cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-uniphier-ahci.c (13382B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * phy-uniphier-ahci.c - PHY driver for UniPhier AHCI controller
      4 * Copyright 2016-2020, Socionext Inc.
      5 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
      6 */
      7
      8#include <linux/bitfield.h>
      9#include <linux/bitops.h>
     10#include <linux/clk.h>
     11#include <linux/iopoll.h>
     12#include <linux/module.h>
     13#include <linux/of.h>
     14#include <linux/of_platform.h>
     15#include <linux/phy/phy.h>
     16#include <linux/platform_device.h>
     17#include <linux/reset.h>
     18
     19struct uniphier_ahciphy_priv {
     20	struct device *dev;
     21	void __iomem  *base;
     22	struct clk *clk, *clk_parent, *clk_parent_gio;
     23	struct reset_control *rst, *rst_parent, *rst_parent_gio;
     24	struct reset_control *rst_pm, *rst_tx, *rst_rx;
     25	const struct uniphier_ahciphy_soc_data *data;
     26};
     27
     28struct uniphier_ahciphy_soc_data {
     29	int (*init)(struct uniphier_ahciphy_priv *priv);
     30	int (*power_on)(struct uniphier_ahciphy_priv *priv);
     31	int (*power_off)(struct uniphier_ahciphy_priv *priv);
     32	bool is_legacy;
     33	bool is_ready_high;
     34	bool is_phy_clk;
     35};
     36
     37/* for Pro4 */
     38#define CKCTRL0				0x0
     39#define CKCTRL0_CK_OFF			BIT(9)
     40#define CKCTRL0_NCY_MASK		GENMASK(8, 4)
     41#define CKCTRL0_NCY5_MASK		GENMASK(3, 2)
     42#define CKCTRL0_PRESCALE_MASK		GENMASK(1, 0)
     43#define CKCTRL1				0x4
     44#define CKCTRL1_LOS_LVL_MASK		GENMASK(20, 16)
     45#define CKCTRL1_TX_LVL_MASK		GENMASK(12, 8)
     46#define RXTXCTRL			0x8
     47#define RXTXCTRL_RX_EQ_VALL_MASK	GENMASK(31, 29)
     48#define RXTXCTRL_RX_DPLL_MODE_MASK	GENMASK(28, 26)
     49#define RXTXCTRL_TX_ATTEN_MASK		GENMASK(14, 12)
     50#define RXTXCTRL_TX_BOOST_MASK		GENMASK(11, 8)
     51#define RXTXCTRL_TX_EDGERATE_MASK	GENMASK(3, 2)
     52#define RXTXCTRL_TX_CKO_EN		BIT(0)
     53#define RSTPWR				0x30
     54#define RSTPWR_RX_EN_VAL		BIT(18)
     55
     56/* for PXs2/PXs3 */
     57#define CKCTRL				0x0
     58#define CKCTRL_P0_READY			BIT(15)
     59#define CKCTRL_P0_RESET			BIT(10)
     60#define CKCTRL_REF_SSP_EN		BIT(9)
     61#define TXCTRL0				0x4
     62#define TXCTRL0_AMP_G3_MASK		GENMASK(22, 16)
     63#define TXCTRL0_AMP_G2_MASK		GENMASK(14, 8)
     64#define TXCTRL0_AMP_G1_MASK		GENMASK(6, 0)
     65#define TXCTRL1				0x8
     66#define TXCTRL1_DEEMPH_G3_MASK		GENMASK(21, 16)
     67#define TXCTRL1_DEEMPH_G2_MASK		GENMASK(13, 8)
     68#define TXCTRL1_DEEMPH_G1_MASK		GENMASK(5, 0)
     69#define RXCTRL				0xc
     70#define RXCTRL_LOS_LVL_MASK		GENMASK(20, 16)
     71#define RXCTRL_LOS_BIAS_MASK		GENMASK(10, 8)
     72#define RXCTRL_RX_EQ_MASK		GENMASK(2, 0)
     73
     74static int uniphier_ahciphy_pro4_init(struct uniphier_ahciphy_priv *priv)
     75{
     76	u32 val;
     77
     78	/* set phy MPLL parameters */
     79	val = readl(priv->base + CKCTRL0);
     80	val &= ~CKCTRL0_NCY_MASK;
     81	val |= FIELD_PREP(CKCTRL0_NCY_MASK, 0x6);
     82	val &= ~CKCTRL0_NCY5_MASK;
     83	val |= FIELD_PREP(CKCTRL0_NCY5_MASK, 0x2);
     84	val &= ~CKCTRL0_PRESCALE_MASK;
     85	val |= FIELD_PREP(CKCTRL0_PRESCALE_MASK, 0x1);
     86	writel(val, priv->base + CKCTRL0);
     87
     88	/* setup phy control parameters */
     89	val = readl(priv->base + CKCTRL1);
     90	val &= ~CKCTRL1_LOS_LVL_MASK;
     91	val |= FIELD_PREP(CKCTRL1_LOS_LVL_MASK, 0x10);
     92	val &= ~CKCTRL1_TX_LVL_MASK;
     93	val |= FIELD_PREP(CKCTRL1_TX_LVL_MASK, 0x06);
     94	writel(val, priv->base + CKCTRL1);
     95
     96	val = readl(priv->base + RXTXCTRL);
     97	val &= ~RXTXCTRL_RX_EQ_VALL_MASK;
     98	val |= FIELD_PREP(RXTXCTRL_RX_EQ_VALL_MASK, 0x6);
     99	val &= ~RXTXCTRL_RX_DPLL_MODE_MASK;
    100	val |= FIELD_PREP(RXTXCTRL_RX_DPLL_MODE_MASK, 0x3);
    101	val &= ~RXTXCTRL_TX_ATTEN_MASK;
    102	val |= FIELD_PREP(RXTXCTRL_TX_ATTEN_MASK, 0x3);
    103	val &= ~RXTXCTRL_TX_BOOST_MASK;
    104	val |= FIELD_PREP(RXTXCTRL_TX_BOOST_MASK, 0x5);
    105	val &= ~RXTXCTRL_TX_EDGERATE_MASK;
    106	val |= FIELD_PREP(RXTXCTRL_TX_EDGERATE_MASK, 0x0);
    107	writel(val, priv->base + RXTXCTRL);
    108
    109	return 0;
    110}
    111
    112static int uniphier_ahciphy_pro4_power_on(struct uniphier_ahciphy_priv *priv)
    113{
    114	u32 val;
    115	int ret;
    116
    117	/* enable reference clock for phy */
    118	val = readl(priv->base + CKCTRL0);
    119	val &= ~CKCTRL0_CK_OFF;
    120	writel(val, priv->base + CKCTRL0);
    121
    122	/* enable TX clock */
    123	val = readl(priv->base + RXTXCTRL);
    124	val |= RXTXCTRL_TX_CKO_EN;
    125	writel(val, priv->base + RXTXCTRL);
    126
    127	/* wait until RX is ready */
    128	ret = readl_poll_timeout(priv->base + RSTPWR, val,
    129				 !(val & RSTPWR_RX_EN_VAL), 200, 2000);
    130	if (ret) {
    131		dev_err(priv->dev, "Failed to check whether Rx is ready\n");
    132		goto out_disable_clock;
    133	}
    134
    135	/* release all reset */
    136	ret = reset_control_deassert(priv->rst_pm);
    137	if (ret) {
    138		dev_err(priv->dev, "Failed to release PM reset\n");
    139		goto out_disable_clock;
    140	}
    141
    142	ret = reset_control_deassert(priv->rst_tx);
    143	if (ret) {
    144		dev_err(priv->dev, "Failed to release Tx reset\n");
    145		goto out_reset_pm_assert;
    146	}
    147
    148	ret = reset_control_deassert(priv->rst_rx);
    149	if (ret) {
    150		dev_err(priv->dev, "Failed to release Rx reset\n");
    151		goto out_reset_tx_assert;
    152	}
    153
    154	return 0;
    155
    156out_reset_tx_assert:
    157	reset_control_assert(priv->rst_tx);
    158out_reset_pm_assert:
    159	reset_control_assert(priv->rst_pm);
    160
    161out_disable_clock:
    162	/* disable TX clock */
    163	val = readl(priv->base + RXTXCTRL);
    164	val &= ~RXTXCTRL_TX_CKO_EN;
    165	writel(val, priv->base + RXTXCTRL);
    166
    167	/* disable reference clock for phy */
    168	val = readl(priv->base + CKCTRL0);
    169	val |= CKCTRL0_CK_OFF;
    170	writel(val, priv->base + CKCTRL0);
    171
    172	return ret;
    173}
    174
    175static int uniphier_ahciphy_pro4_power_off(struct uniphier_ahciphy_priv *priv)
    176{
    177	u32 val;
    178
    179	reset_control_assert(priv->rst_rx);
    180	reset_control_assert(priv->rst_tx);
    181	reset_control_assert(priv->rst_pm);
    182
    183	/* disable TX clock */
    184	val = readl(priv->base + RXTXCTRL);
    185	val &= ~RXTXCTRL_TX_CKO_EN;
    186	writel(val, priv->base + RXTXCTRL);
    187
    188	/* disable reference clock for phy */
    189	val = readl(priv->base + CKCTRL0);
    190	val |= CKCTRL0_CK_OFF;
    191	writel(val, priv->base + CKCTRL0);
    192
    193	return 0;
    194}
    195
    196static void uniphier_ahciphy_pxs2_enable(struct uniphier_ahciphy_priv *priv,
    197					 bool enable)
    198{
    199	u32 val;
    200
    201	val = readl(priv->base + CKCTRL);
    202
    203	if (enable) {
    204		val |= CKCTRL_REF_SSP_EN;
    205		writel(val, priv->base + CKCTRL);
    206		val &= ~CKCTRL_P0_RESET;
    207		writel(val, priv->base + CKCTRL);
    208	} else {
    209		val |= CKCTRL_P0_RESET;
    210		writel(val, priv->base + CKCTRL);
    211		val &= ~CKCTRL_REF_SSP_EN;
    212		writel(val, priv->base + CKCTRL);
    213	}
    214}
    215
    216static int uniphier_ahciphy_pxs2_power_on(struct uniphier_ahciphy_priv *priv)
    217{
    218	int ret;
    219	u32 val;
    220
    221	uniphier_ahciphy_pxs2_enable(priv, true);
    222
    223	/* wait until PLL is ready */
    224	if (priv->data->is_ready_high)
    225		ret = readl_poll_timeout(priv->base + CKCTRL, val,
    226					 (val & CKCTRL_P0_READY), 200, 400);
    227	else
    228		ret = readl_poll_timeout(priv->base + CKCTRL, val,
    229					 !(val & CKCTRL_P0_READY), 200, 400);
    230	if (ret) {
    231		dev_err(priv->dev, "Failed to check whether PHY PLL is ready\n");
    232		uniphier_ahciphy_pxs2_enable(priv, false);
    233	}
    234
    235	return ret;
    236}
    237
    238static int uniphier_ahciphy_pxs2_power_off(struct uniphier_ahciphy_priv *priv)
    239{
    240	uniphier_ahciphy_pxs2_enable(priv, false);
    241
    242	return 0;
    243}
    244
    245static int uniphier_ahciphy_pxs3_init(struct uniphier_ahciphy_priv *priv)
    246{
    247	int i;
    248	u32 val;
    249
    250	/* setup port parameter */
    251	val = readl(priv->base + TXCTRL0);
    252	val &= ~TXCTRL0_AMP_G3_MASK;
    253	val |= FIELD_PREP(TXCTRL0_AMP_G3_MASK, 0x73);
    254	val &= ~TXCTRL0_AMP_G2_MASK;
    255	val |= FIELD_PREP(TXCTRL0_AMP_G2_MASK, 0x46);
    256	val &= ~TXCTRL0_AMP_G1_MASK;
    257	val |= FIELD_PREP(TXCTRL0_AMP_G1_MASK, 0x42);
    258	writel(val, priv->base + TXCTRL0);
    259
    260	val = readl(priv->base + TXCTRL1);
    261	val &= ~TXCTRL1_DEEMPH_G3_MASK;
    262	val |= FIELD_PREP(TXCTRL1_DEEMPH_G3_MASK, 0x23);
    263	val &= ~TXCTRL1_DEEMPH_G2_MASK;
    264	val |= FIELD_PREP(TXCTRL1_DEEMPH_G2_MASK, 0x05);
    265	val &= ~TXCTRL1_DEEMPH_G1_MASK;
    266	val |= FIELD_PREP(TXCTRL1_DEEMPH_G1_MASK, 0x05);
    267
    268	val = readl(priv->base + RXCTRL);
    269	val &= ~RXCTRL_LOS_LVL_MASK;
    270	val |= FIELD_PREP(RXCTRL_LOS_LVL_MASK, 0x9);
    271	val &= ~RXCTRL_LOS_BIAS_MASK;
    272	val |= FIELD_PREP(RXCTRL_LOS_BIAS_MASK, 0x2);
    273	val &= ~RXCTRL_RX_EQ_MASK;
    274	val |= FIELD_PREP(RXCTRL_RX_EQ_MASK, 0x1);
    275
    276	/* dummy read 25 times to make a wait time for the phy to stabilize */
    277	for (i = 0; i < 25; i++)
    278		readl(priv->base + CKCTRL);
    279
    280	return 0;
    281}
    282
    283static int uniphier_ahciphy_init(struct phy *phy)
    284{
    285	struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
    286	int ret;
    287
    288	ret = clk_prepare_enable(priv->clk_parent_gio);
    289	if (ret)
    290		return ret;
    291
    292	ret = clk_prepare_enable(priv->clk_parent);
    293	if (ret)
    294		goto out_clk_gio_disable;
    295
    296	ret = reset_control_deassert(priv->rst_parent_gio);
    297	if (ret)
    298		goto out_clk_disable;
    299
    300	ret = reset_control_deassert(priv->rst_parent);
    301	if (ret)
    302		goto out_rst_gio_assert;
    303
    304	if (priv->data->init) {
    305		ret = priv->data->init(priv);
    306		if (ret)
    307			goto out_rst_assert;
    308	}
    309
    310	return 0;
    311
    312out_rst_assert:
    313	reset_control_assert(priv->rst_parent);
    314out_rst_gio_assert:
    315	reset_control_assert(priv->rst_parent_gio);
    316out_clk_disable:
    317	clk_disable_unprepare(priv->clk_parent);
    318out_clk_gio_disable:
    319	clk_disable_unprepare(priv->clk_parent_gio);
    320
    321	return ret;
    322}
    323
    324static int uniphier_ahciphy_exit(struct phy *phy)
    325{
    326	struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
    327
    328	reset_control_assert(priv->rst_parent);
    329	reset_control_assert(priv->rst_parent_gio);
    330	clk_disable_unprepare(priv->clk_parent);
    331	clk_disable_unprepare(priv->clk_parent_gio);
    332
    333	return 0;
    334}
    335
    336static int uniphier_ahciphy_power_on(struct phy *phy)
    337{
    338	struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
    339	int ret = 0;
    340
    341	ret = clk_prepare_enable(priv->clk);
    342	if (ret)
    343		return ret;
    344
    345	ret = reset_control_deassert(priv->rst);
    346	if (ret)
    347		goto out_clk_disable;
    348
    349	if (priv->data->power_on) {
    350		ret = priv->data->power_on(priv);
    351		if (ret)
    352			goto out_reset_assert;
    353	}
    354
    355	return 0;
    356
    357out_reset_assert:
    358	reset_control_assert(priv->rst);
    359out_clk_disable:
    360	clk_disable_unprepare(priv->clk);
    361
    362	return ret;
    363}
    364
    365static int uniphier_ahciphy_power_off(struct phy *phy)
    366{
    367	struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
    368	int ret = 0;
    369
    370	if (priv->data->power_off)
    371		ret = priv->data->power_off(priv);
    372
    373	reset_control_assert(priv->rst);
    374	clk_disable_unprepare(priv->clk);
    375
    376	return ret;
    377}
    378
    379static const struct phy_ops uniphier_ahciphy_ops = {
    380	.init  = uniphier_ahciphy_init,
    381	.exit  = uniphier_ahciphy_exit,
    382	.power_on  = uniphier_ahciphy_power_on,
    383	.power_off = uniphier_ahciphy_power_off,
    384	.owner = THIS_MODULE,
    385};
    386
    387static int uniphier_ahciphy_probe(struct platform_device *pdev)
    388{
    389	struct device *dev = &pdev->dev;
    390	struct uniphier_ahciphy_priv *priv;
    391	struct phy *phy;
    392	struct phy_provider *phy_provider;
    393
    394	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    395	if (!priv)
    396		return -ENOMEM;
    397
    398	priv->dev = dev;
    399	priv->data = of_device_get_match_data(dev);
    400	if (WARN_ON(!priv->data))
    401		return -EINVAL;
    402
    403	priv->base = devm_platform_ioremap_resource(pdev, 0);
    404	if (IS_ERR(priv->base))
    405		return PTR_ERR(priv->base);
    406
    407	priv->clk_parent = devm_clk_get(dev, "link");
    408	if (IS_ERR(priv->clk_parent))
    409		return PTR_ERR(priv->clk_parent);
    410
    411	if (priv->data->is_phy_clk) {
    412		priv->clk = devm_clk_get(dev, "phy");
    413		if (IS_ERR(priv->clk))
    414			return PTR_ERR(priv->clk);
    415	}
    416
    417	priv->rst_parent = devm_reset_control_get_shared(dev, "link");
    418	if (IS_ERR(priv->rst_parent))
    419		return PTR_ERR(priv->rst_parent);
    420
    421	priv->rst = devm_reset_control_get_shared(dev, "phy");
    422	if (IS_ERR(priv->rst))
    423		return PTR_ERR(priv->rst);
    424
    425	if (priv->data->is_legacy) {
    426		priv->clk_parent_gio = devm_clk_get(dev, "gio");
    427		if (IS_ERR(priv->clk_parent_gio))
    428			return PTR_ERR(priv->clk_parent_gio);
    429		priv->rst_parent_gio =
    430			devm_reset_control_get_shared(dev, "gio");
    431		if (IS_ERR(priv->rst_parent_gio))
    432			return PTR_ERR(priv->rst_parent_gio);
    433
    434		priv->rst_pm = devm_reset_control_get_shared(dev, "pm");
    435		if (IS_ERR(priv->rst_pm))
    436			return PTR_ERR(priv->rst_pm);
    437
    438		priv->rst_tx = devm_reset_control_get_shared(dev, "tx");
    439		if (IS_ERR(priv->rst_tx))
    440			return PTR_ERR(priv->rst_tx);
    441
    442		priv->rst_rx = devm_reset_control_get_shared(dev, "rx");
    443		if (IS_ERR(priv->rst_rx))
    444			return PTR_ERR(priv->rst_rx);
    445	}
    446
    447	phy = devm_phy_create(dev, dev->of_node, &uniphier_ahciphy_ops);
    448	if (IS_ERR(phy)) {
    449		dev_err(dev, "failed to create phy\n");
    450		return PTR_ERR(phy);
    451	}
    452
    453	phy_set_drvdata(phy, priv);
    454	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    455	if (IS_ERR(phy_provider))
    456		return PTR_ERR(phy_provider);
    457
    458	return 0;
    459}
    460
    461static const struct uniphier_ahciphy_soc_data uniphier_pro4_data = {
    462	.init = uniphier_ahciphy_pro4_init,
    463	.power_on  = uniphier_ahciphy_pro4_power_on,
    464	.power_off = uniphier_ahciphy_pro4_power_off,
    465	.is_legacy = true,
    466	.is_phy_clk = false,
    467};
    468
    469static const struct uniphier_ahciphy_soc_data uniphier_pxs2_data = {
    470	.power_on  = uniphier_ahciphy_pxs2_power_on,
    471	.power_off = uniphier_ahciphy_pxs2_power_off,
    472	.is_legacy = false,
    473	.is_ready_high = false,
    474	.is_phy_clk = false,
    475};
    476
    477static const struct uniphier_ahciphy_soc_data uniphier_pxs3_data = {
    478	.init      = uniphier_ahciphy_pxs3_init,
    479	.power_on  = uniphier_ahciphy_pxs2_power_on,
    480	.power_off = uniphier_ahciphy_pxs2_power_off,
    481	.is_legacy = false,
    482	.is_ready_high = true,
    483	.is_phy_clk = true,
    484};
    485
    486static const struct of_device_id uniphier_ahciphy_match[] = {
    487	{
    488		.compatible = "socionext,uniphier-pro4-ahci-phy",
    489		.data = &uniphier_pro4_data,
    490	},
    491	{
    492		.compatible = "socionext,uniphier-pxs2-ahci-phy",
    493		.data = &uniphier_pxs2_data,
    494	},
    495	{
    496		.compatible = "socionext,uniphier-pxs3-ahci-phy",
    497		.data = &uniphier_pxs3_data,
    498	},
    499	{ /* Sentinel */ },
    500};
    501MODULE_DEVICE_TABLE(of, uniphier_ahciphy_match);
    502
    503static struct platform_driver uniphier_ahciphy_driver = {
    504	.probe = uniphier_ahciphy_probe,
    505	.driver = {
    506		.name = "uniphier-ahci-phy",
    507		.of_match_table = uniphier_ahciphy_match,
    508	},
    509};
    510module_platform_driver(uniphier_ahciphy_driver);
    511
    512MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
    513MODULE_DESCRIPTION("UniPhier PHY driver for AHCI controller");
    514MODULE_LICENSE("GPL v2");