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-hi3660-usb3.c (5794B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Phy provider for USB 3.0 controller on HiSilicon 3660 platform
      4 *
      5 * Copyright (C) 2017-2018 Hilisicon Electronics Co., Ltd.
      6 *		http://www.huawei.com
      7 *
      8 * Authors: Yu Chen <chenyu56@huawei.com>
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/mfd/syscon.h>
     13#include <linux/module.h>
     14#include <linux/phy/phy.h>
     15#include <linux/platform_device.h>
     16#include <linux/regmap.h>
     17
     18#define PERI_CRG_CLK_EN4			0x40
     19#define PERI_CRG_CLK_DIS4			0x44
     20#define GT_CLK_USB3OTG_REF			BIT(0)
     21#define GT_ACLK_USB3OTG				BIT(1)
     22
     23#define PERI_CRG_RSTEN4				0x90
     24#define PERI_CRG_RSTDIS4			0x94
     25#define IP_RST_USB3OTGPHY_POR			BIT(3)
     26#define IP_RST_USB3OTG				BIT(5)
     27
     28#define PERI_CRG_ISODIS				0x148
     29#define USB_REFCLK_ISO_EN			BIT(25)
     30
     31#define PCTRL_PERI_CTRL3			0x10
     32#define PCTRL_PERI_CTRL3_MSK_START		16
     33#define USB_TCXO_EN				BIT(1)
     34
     35#define PCTRL_PERI_CTRL24			0x64
     36#define SC_CLK_USB3PHY_3MUX1_SEL		BIT(25)
     37
     38#define USBOTG3_CTRL0				0x00
     39#define SC_USB3PHY_ABB_GT_EN			BIT(15)
     40
     41#define USBOTG3_CTRL2				0x08
     42#define USBOTG3CTRL2_POWERDOWN_HSP		BIT(0)
     43#define USBOTG3CTRL2_POWERDOWN_SSP		BIT(1)
     44
     45#define USBOTG3_CTRL3				0x0C
     46#define USBOTG3_CTRL3_VBUSVLDEXT		BIT(6)
     47#define USBOTG3_CTRL3_VBUSVLDEXTSEL		BIT(5)
     48
     49#define USBOTG3_CTRL4				0x10
     50
     51#define USBOTG3_CTRL7				0x1c
     52#define REF_SSP_EN				BIT(16)
     53
     54/* This value config the default txtune parameter of the usb 2.0 phy */
     55#define HI3660_USB_DEFAULT_PHY_PARAM		0x1c466e3
     56
     57struct hi3660_priv {
     58	struct device *dev;
     59	struct regmap *peri_crg;
     60	struct regmap *pctrl;
     61	struct regmap *otg_bc;
     62	u32 eye_diagram_param;
     63};
     64
     65static int hi3660_phy_init(struct phy *phy)
     66{
     67	struct hi3660_priv *priv = phy_get_drvdata(phy);
     68	u32 val, mask;
     69	int ret;
     70
     71	/* usb refclk iso disable */
     72	ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS, USB_REFCLK_ISO_EN);
     73	if (ret)
     74		goto out;
     75
     76	/* enable usb_tcxo_en */
     77	val = USB_TCXO_EN | (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
     78	ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, val);
     79	if (ret)
     80		goto out;
     81
     82	/* assert phy */
     83	val = IP_RST_USB3OTGPHY_POR | IP_RST_USB3OTG;
     84	ret = regmap_write(priv->peri_crg, PERI_CRG_RSTEN4, val);
     85	if (ret)
     86		goto out;
     87
     88	/* enable phy ref clk */
     89	val = SC_USB3PHY_ABB_GT_EN;
     90	mask = val;
     91	ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL0, mask, val);
     92	if (ret)
     93		goto out;
     94
     95	val = REF_SSP_EN;
     96	mask = val;
     97	ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL7, mask, val);
     98	if (ret)
     99		goto out;
    100
    101	/* exit from IDDQ mode */
    102	mask = USBOTG3CTRL2_POWERDOWN_HSP | USBOTG3CTRL2_POWERDOWN_SSP;
    103	ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL2, mask, 0);
    104	if (ret)
    105		goto out;
    106
    107	/* delay for exit from IDDQ mode */
    108	usleep_range(100, 120);
    109
    110	/* deassert phy */
    111	val = IP_RST_USB3OTGPHY_POR | IP_RST_USB3OTG;
    112	ret = regmap_write(priv->peri_crg, PERI_CRG_RSTDIS4, val);
    113	if (ret)
    114		goto out;
    115
    116	/* delay for phy deasserted */
    117	usleep_range(10000, 15000);
    118
    119	/* fake vbus valid signal */
    120	val = USBOTG3_CTRL3_VBUSVLDEXT | USBOTG3_CTRL3_VBUSVLDEXTSEL;
    121	mask = val;
    122	ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL3, mask, val);
    123	if (ret)
    124		goto out;
    125
    126	/* delay for vbus valid */
    127	usleep_range(100, 120);
    128
    129	ret = regmap_write(priv->otg_bc, USBOTG3_CTRL4,
    130			priv->eye_diagram_param);
    131	if (ret)
    132		goto out;
    133
    134	return 0;
    135out:
    136	dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
    137	return ret;
    138}
    139
    140static int hi3660_phy_exit(struct phy *phy)
    141{
    142	struct hi3660_priv *priv = phy_get_drvdata(phy);
    143	u32 val;
    144	int ret;
    145
    146	/* assert phy */
    147	val = IP_RST_USB3OTGPHY_POR;
    148	ret = regmap_write(priv->peri_crg, PERI_CRG_RSTEN4, val);
    149	if (ret)
    150		goto out;
    151
    152	/* disable usb_tcxo_en */
    153	val = USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START;
    154	ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, val);
    155	if (ret)
    156		goto out;
    157
    158	return 0;
    159out:
    160	dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
    161	return ret;
    162}
    163
    164static const struct phy_ops hi3660_phy_ops = {
    165	.init		= hi3660_phy_init,
    166	.exit		= hi3660_phy_exit,
    167	.owner		= THIS_MODULE,
    168};
    169
    170static int hi3660_phy_probe(struct platform_device *pdev)
    171{
    172	struct phy_provider *phy_provider;
    173	struct device *dev = &pdev->dev;
    174	struct phy *phy;
    175	struct hi3660_priv *priv;
    176
    177	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    178	if (!priv)
    179		return -ENOMEM;
    180
    181	priv->dev = dev;
    182	priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
    183					"hisilicon,pericrg-syscon");
    184	if (IS_ERR(priv->peri_crg)) {
    185		dev_err(dev, "no hisilicon,pericrg-syscon\n");
    186		return PTR_ERR(priv->peri_crg);
    187	}
    188
    189	priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
    190					"hisilicon,pctrl-syscon");
    191	if (IS_ERR(priv->pctrl)) {
    192		dev_err(dev, "no hisilicon,pctrl-syscon\n");
    193		return PTR_ERR(priv->pctrl);
    194	}
    195
    196	/* node of hi3660 phy is a sub-node of usb3_otg_bc */
    197	priv->otg_bc = syscon_node_to_regmap(dev->parent->of_node);
    198	if (IS_ERR(priv->otg_bc)) {
    199		dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
    200		return PTR_ERR(priv->otg_bc);
    201	}
    202
    203	if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
    204		&(priv->eye_diagram_param)))
    205		priv->eye_diagram_param = HI3660_USB_DEFAULT_PHY_PARAM;
    206
    207	phy = devm_phy_create(dev, NULL, &hi3660_phy_ops);
    208	if (IS_ERR(phy))
    209		return PTR_ERR(phy);
    210
    211	phy_set_drvdata(phy, priv);
    212	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    213	return PTR_ERR_OR_ZERO(phy_provider);
    214}
    215
    216static const struct of_device_id hi3660_phy_of_match[] = {
    217	{.compatible = "hisilicon,hi3660-usb-phy",},
    218	{ }
    219};
    220MODULE_DEVICE_TABLE(of, hi3660_phy_of_match);
    221
    222static struct platform_driver hi3660_phy_driver = {
    223	.probe	= hi3660_phy_probe,
    224	.driver = {
    225		.name	= "hi3660-usb-phy",
    226		.of_match_table	= hi3660_phy_of_match,
    227	}
    228};
    229module_platform_driver(hi3660_phy_driver);
    230
    231MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
    232MODULE_LICENSE("GPL v2");
    233MODULE_DESCRIPTION("Hilisicon Hi3660 USB3 PHY Driver");