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-usb3ss.c (8982B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller
      4 * Copyright 2015-2018 Socionext Inc.
      5 * Author:
      6 *      Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
      7 * Contributors:
      8 *      Motoya Tanigawa <tanigawa.motoya@socionext.com>
      9 *      Masami Hiramatsu <masami.hiramatsu@linaro.org>
     10 */
     11
     12#include <linux/bitfield.h>
     13#include <linux/bitops.h>
     14#include <linux/clk.h>
     15#include <linux/io.h>
     16#include <linux/module.h>
     17#include <linux/of.h>
     18#include <linux/of_platform.h>
     19#include <linux/phy/phy.h>
     20#include <linux/platform_device.h>
     21#include <linux/regulator/consumer.h>
     22#include <linux/reset.h>
     23
     24#define SSPHY_TESTI		0x0
     25#define TESTI_DAT_MASK		GENMASK(13, 6)
     26#define TESTI_ADR_MASK		GENMASK(5, 1)
     27#define TESTI_WR_EN		BIT(0)
     28
     29#define SSPHY_TESTO		0x4
     30#define TESTO_DAT_MASK		GENMASK(7, 0)
     31
     32#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
     33
     34#define CDR_CPD_TRIM	PHY_F(7, 3, 0)	/* RxPLL charge pump current */
     35#define CDR_CPF_TRIM	PHY_F(8, 3, 0)	/* RxPLL charge pump current 2 */
     36#define TX_PLL_TRIM	PHY_F(9, 3, 0)	/* TxPLL charge pump current */
     37#define BGAP_TRIM	PHY_F(11, 3, 0)	/* Bandgap voltage */
     38#define CDR_TRIM	PHY_F(13, 6, 5)	/* Clock Data Recovery setting */
     39#define VCO_CTRL	PHY_F(26, 7, 4)	/* VCO control */
     40#define VCOPLL_CTRL	PHY_F(27, 2, 0)	/* TxPLL VCO tuning */
     41#define VCOPLL_CM	PHY_F(28, 1, 0)	/* TxPLL voltage */
     42
     43#define MAX_PHY_PARAMS	7
     44
     45struct uniphier_u3ssphy_param {
     46	struct {
     47		int reg_no;
     48		int msb;
     49		int lsb;
     50	} field;
     51	u8 value;
     52};
     53
     54struct uniphier_u3ssphy_priv {
     55	struct device *dev;
     56	void __iomem *base;
     57	struct clk *clk, *clk_ext, *clk_parent, *clk_parent_gio;
     58	struct reset_control *rst, *rst_parent, *rst_parent_gio;
     59	struct regulator *vbus;
     60	const struct uniphier_u3ssphy_soc_data *data;
     61};
     62
     63struct uniphier_u3ssphy_soc_data {
     64	bool is_legacy;
     65	int nparams;
     66	const struct uniphier_u3ssphy_param param[MAX_PHY_PARAMS];
     67};
     68
     69static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv *priv,
     70					  u32 data)
     71{
     72	/* need to read TESTO twice after accessing TESTI */
     73	writel(data, priv->base + SSPHY_TESTI);
     74	readl(priv->base + SSPHY_TESTO);
     75	readl(priv->base + SSPHY_TESTO);
     76}
     77
     78static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv *priv,
     79				       const struct uniphier_u3ssphy_param *p)
     80{
     81	u32 val;
     82	u8 field_mask = GENMASK(p->field.msb, p->field.lsb);
     83	u8 data;
     84
     85	/* read previous data */
     86	val  = FIELD_PREP(TESTI_DAT_MASK, 1);
     87	val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
     88	uniphier_u3ssphy_testio_write(priv, val);
     89	val = readl(priv->base + SSPHY_TESTO) & TESTO_DAT_MASK;
     90
     91	/* update value */
     92	val &= ~field_mask;
     93	data = field_mask & (p->value << p->field.lsb);
     94	val  = FIELD_PREP(TESTI_DAT_MASK, data | val);
     95	val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
     96	uniphier_u3ssphy_testio_write(priv, val);
     97	uniphier_u3ssphy_testio_write(priv, val | TESTI_WR_EN);
     98	uniphier_u3ssphy_testio_write(priv, val);
     99
    100	/* read current data as dummy */
    101	val  = FIELD_PREP(TESTI_DAT_MASK, 1);
    102	val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
    103	uniphier_u3ssphy_testio_write(priv, val);
    104	readl(priv->base + SSPHY_TESTO);
    105}
    106
    107static int uniphier_u3ssphy_power_on(struct phy *phy)
    108{
    109	struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
    110	int ret;
    111
    112	ret = clk_prepare_enable(priv->clk_ext);
    113	if (ret)
    114		return ret;
    115
    116	ret = clk_prepare_enable(priv->clk);
    117	if (ret)
    118		goto out_clk_ext_disable;
    119
    120	ret = reset_control_deassert(priv->rst);
    121	if (ret)
    122		goto out_clk_disable;
    123
    124	if (priv->vbus) {
    125		ret = regulator_enable(priv->vbus);
    126		if (ret)
    127			goto out_rst_assert;
    128	}
    129
    130	return 0;
    131
    132out_rst_assert:
    133	reset_control_assert(priv->rst);
    134out_clk_disable:
    135	clk_disable_unprepare(priv->clk);
    136out_clk_ext_disable:
    137	clk_disable_unprepare(priv->clk_ext);
    138
    139	return ret;
    140}
    141
    142static int uniphier_u3ssphy_power_off(struct phy *phy)
    143{
    144	struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
    145
    146	if (priv->vbus)
    147		regulator_disable(priv->vbus);
    148
    149	reset_control_assert(priv->rst);
    150	clk_disable_unprepare(priv->clk);
    151	clk_disable_unprepare(priv->clk_ext);
    152
    153	return 0;
    154}
    155
    156static int uniphier_u3ssphy_init(struct phy *phy)
    157{
    158	struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
    159	int i, ret;
    160
    161	ret = clk_prepare_enable(priv->clk_parent);
    162	if (ret)
    163		return ret;
    164
    165	ret = clk_prepare_enable(priv->clk_parent_gio);
    166	if (ret)
    167		goto out_clk_disable;
    168
    169	ret = reset_control_deassert(priv->rst_parent);
    170	if (ret)
    171		goto out_clk_gio_disable;
    172
    173	ret = reset_control_deassert(priv->rst_parent_gio);
    174	if (ret)
    175		goto out_rst_assert;
    176
    177	if (priv->data->is_legacy)
    178		return 0;
    179
    180	for (i = 0; i < priv->data->nparams; i++)
    181		uniphier_u3ssphy_set_param(priv, &priv->data->param[i]);
    182
    183	return 0;
    184
    185out_rst_assert:
    186	reset_control_assert(priv->rst_parent);
    187out_clk_gio_disable:
    188	clk_disable_unprepare(priv->clk_parent_gio);
    189out_clk_disable:
    190	clk_disable_unprepare(priv->clk_parent);
    191
    192	return ret;
    193}
    194
    195static int uniphier_u3ssphy_exit(struct phy *phy)
    196{
    197	struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
    198
    199	reset_control_assert(priv->rst_parent_gio);
    200	reset_control_assert(priv->rst_parent);
    201	clk_disable_unprepare(priv->clk_parent_gio);
    202	clk_disable_unprepare(priv->clk_parent);
    203
    204	return 0;
    205}
    206
    207static const struct phy_ops uniphier_u3ssphy_ops = {
    208	.init           = uniphier_u3ssphy_init,
    209	.exit           = uniphier_u3ssphy_exit,
    210	.power_on       = uniphier_u3ssphy_power_on,
    211	.power_off      = uniphier_u3ssphy_power_off,
    212	.owner          = THIS_MODULE,
    213};
    214
    215static int uniphier_u3ssphy_probe(struct platform_device *pdev)
    216{
    217	struct device *dev = &pdev->dev;
    218	struct uniphier_u3ssphy_priv *priv;
    219	struct phy_provider *phy_provider;
    220	struct phy *phy;
    221
    222	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    223	if (!priv)
    224		return -ENOMEM;
    225
    226	priv->dev = dev;
    227	priv->data = of_device_get_match_data(dev);
    228	if (WARN_ON(!priv->data ||
    229		    priv->data->nparams > MAX_PHY_PARAMS))
    230		return -EINVAL;
    231
    232	priv->base = devm_platform_ioremap_resource(pdev, 0);
    233	if (IS_ERR(priv->base))
    234		return PTR_ERR(priv->base);
    235
    236	if (!priv->data->is_legacy) {
    237		priv->clk = devm_clk_get(dev, "phy");
    238		if (IS_ERR(priv->clk))
    239			return PTR_ERR(priv->clk);
    240
    241		priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
    242		if (IS_ERR(priv->clk_ext))
    243			return PTR_ERR(priv->clk_ext);
    244
    245		priv->rst = devm_reset_control_get_shared(dev, "phy");
    246		if (IS_ERR(priv->rst))
    247			return PTR_ERR(priv->rst);
    248	} else {
    249		priv->clk_parent_gio = devm_clk_get(dev, "gio");
    250		if (IS_ERR(priv->clk_parent_gio))
    251			return PTR_ERR(priv->clk_parent_gio);
    252
    253		priv->rst_parent_gio =
    254			devm_reset_control_get_shared(dev, "gio");
    255		if (IS_ERR(priv->rst_parent_gio))
    256			return PTR_ERR(priv->rst_parent_gio);
    257	}
    258
    259	priv->clk_parent = devm_clk_get(dev, "link");
    260	if (IS_ERR(priv->clk_parent))
    261		return PTR_ERR(priv->clk_parent);
    262
    263	priv->rst_parent = devm_reset_control_get_shared(dev, "link");
    264	if (IS_ERR(priv->rst_parent))
    265		return PTR_ERR(priv->rst_parent);
    266
    267	priv->vbus = devm_regulator_get_optional(dev, "vbus");
    268	if (IS_ERR(priv->vbus)) {
    269		if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
    270			return PTR_ERR(priv->vbus);
    271		priv->vbus = NULL;
    272	}
    273
    274	phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops);
    275	if (IS_ERR(phy))
    276		return PTR_ERR(phy);
    277
    278	phy_set_drvdata(phy, priv);
    279	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    280
    281	return PTR_ERR_OR_ZERO(phy_provider);
    282}
    283
    284static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = {
    285	.is_legacy = true,
    286};
    287
    288static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = {
    289	.is_legacy = false,
    290	.nparams = 7,
    291	.param = {
    292		{ CDR_CPD_TRIM, 10 },
    293		{ CDR_CPF_TRIM, 3 },
    294		{ TX_PLL_TRIM, 5 },
    295		{ BGAP_TRIM, 9 },
    296		{ CDR_TRIM, 2 },
    297		{ VCOPLL_CTRL, 7 },
    298		{ VCOPLL_CM, 1 },
    299	},
    300};
    301
    302static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = {
    303	.is_legacy = false,
    304	.nparams = 3,
    305	.param = {
    306		{ CDR_CPD_TRIM, 6 },
    307		{ CDR_TRIM, 2 },
    308		{ VCO_CTRL, 5 },
    309	},
    310};
    311
    312static const struct of_device_id uniphier_u3ssphy_match[] = {
    313	{
    314		.compatible = "socionext,uniphier-pro4-usb3-ssphy",
    315		.data = &uniphier_pro4_data,
    316	},
    317	{
    318		.compatible = "socionext,uniphier-pro5-usb3-ssphy",
    319		.data = &uniphier_pro4_data,
    320	},
    321	{
    322		.compatible = "socionext,uniphier-pxs2-usb3-ssphy",
    323		.data = &uniphier_pxs2_data,
    324	},
    325	{
    326		.compatible = "socionext,uniphier-ld20-usb3-ssphy",
    327		.data = &uniphier_ld20_data,
    328	},
    329	{
    330		.compatible = "socionext,uniphier-pxs3-usb3-ssphy",
    331		.data = &uniphier_ld20_data,
    332	},
    333	{
    334		.compatible = "socionext,uniphier-nx1-usb3-ssphy",
    335		.data = &uniphier_ld20_data,
    336	},
    337	{ /* sentinel */ }
    338};
    339MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match);
    340
    341static struct platform_driver uniphier_u3ssphy_driver = {
    342	.probe = uniphier_u3ssphy_probe,
    343	.driver	= {
    344		.name = "uniphier-usb3-ssphy",
    345		.of_match_table	= uniphier_u3ssphy_match,
    346	},
    347};
    348
    349module_platform_driver(uniphier_u3ssphy_driver);
    350
    351MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
    352MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller");
    353MODULE_LICENSE("GPL v2");