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-bcm-sr-usb.c (7332B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2016-2018 Broadcom
      4 */
      5
      6#include <linux/delay.h>
      7#include <linux/io.h>
      8#include <linux/iopoll.h>
      9#include <linux/module.h>
     10#include <linux/of.h>
     11#include <linux/phy/phy.h>
     12#include <linux/platform_device.h>
     13
     14enum bcm_usb_phy_version {
     15	BCM_SR_USB_COMBO_PHY,
     16	BCM_SR_USB_HS_PHY,
     17};
     18
     19enum bcm_usb_phy_reg {
     20	PLL_CTRL,
     21	PHY_CTRL,
     22	PHY_PLL_CTRL,
     23};
     24
     25/* USB PHY registers */
     26
     27static const u8 bcm_usb_combo_phy_ss[] = {
     28	[PLL_CTRL]		= 0x18,
     29	[PHY_CTRL]		= 0x14,
     30};
     31
     32static const u8 bcm_usb_combo_phy_hs[] = {
     33	[PLL_CTRL]	= 0x0c,
     34	[PHY_CTRL]	= 0x10,
     35};
     36
     37static const u8 bcm_usb_hs_phy[] = {
     38	[PLL_CTRL]	= 0x8,
     39	[PHY_CTRL]	= 0xc,
     40};
     41
     42enum pll_ctrl_bits {
     43	PLL_RESETB,
     44	SSPLL_SUSPEND_EN,
     45	PLL_SEQ_START,
     46	PLL_LOCK,
     47};
     48
     49static const u8 u3pll_ctrl[] = {
     50	[PLL_RESETB]		= 0,
     51	[SSPLL_SUSPEND_EN]	= 1,
     52	[PLL_SEQ_START]		= 2,
     53	[PLL_LOCK]		= 3,
     54};
     55
     56#define HSPLL_PDIV_MASK		0xF
     57#define HSPLL_PDIV_VAL		0x1
     58
     59static const u8 u2pll_ctrl[] = {
     60	[PLL_RESETB]	= 5,
     61	[PLL_LOCK]	= 6,
     62};
     63
     64enum bcm_usb_phy_ctrl_bits {
     65	CORERDY,
     66	PHY_RESETB,
     67	PHY_PCTL,
     68};
     69
     70#define PHY_PCTL_MASK	0xffff
     71#define SSPHY_PCTL_VAL	0x0006
     72
     73static const u8 u3phy_ctrl[] = {
     74	[PHY_RESETB]	= 1,
     75	[PHY_PCTL]	= 2,
     76};
     77
     78static const u8 u2phy_ctrl[] = {
     79	[CORERDY]		= 0,
     80	[PHY_RESETB]		= 5,
     81	[PHY_PCTL]		= 6,
     82};
     83
     84struct bcm_usb_phy_cfg {
     85	uint32_t type;
     86	uint32_t version;
     87	void __iomem *regs;
     88	struct phy *phy;
     89	const u8 *offset;
     90};
     91
     92#define PLL_LOCK_RETRY_COUNT	1000
     93
     94enum bcm_usb_phy_type {
     95	USB_HS_PHY,
     96	USB_SS_PHY,
     97};
     98
     99#define NUM_BCM_SR_USB_COMBO_PHYS	2
    100
    101static inline void bcm_usb_reg32_clrbits(void __iomem *addr, uint32_t clear)
    102{
    103	writel(readl(addr) & ~clear, addr);
    104}
    105
    106static inline void bcm_usb_reg32_setbits(void __iomem *addr, uint32_t set)
    107{
    108	writel(readl(addr) | set, addr);
    109}
    110
    111static int bcm_usb_pll_lock_check(void __iomem *addr, u32 bit)
    112{
    113	u32 data;
    114	int ret;
    115
    116	ret = readl_poll_timeout_atomic(addr, data, (data & bit), 1,
    117					PLL_LOCK_RETRY_COUNT);
    118	if (ret)
    119		pr_err("%s: FAIL\n", __func__);
    120
    121	return ret;
    122}
    123
    124static int bcm_usb_ss_phy_init(struct bcm_usb_phy_cfg *phy_cfg)
    125{
    126	int ret = 0;
    127	void __iomem *regs = phy_cfg->regs;
    128	const u8 *offset;
    129	u32 rd_data;
    130
    131	offset = phy_cfg->offset;
    132
    133	/* Set pctl with mode and soft reset */
    134	rd_data = readl(regs + offset[PHY_CTRL]);
    135	rd_data &= ~(PHY_PCTL_MASK << u3phy_ctrl[PHY_PCTL]);
    136	rd_data |= (SSPHY_PCTL_VAL << u3phy_ctrl[PHY_PCTL]);
    137	writel(rd_data, regs + offset[PHY_CTRL]);
    138
    139	bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL],
    140			      BIT(u3pll_ctrl[SSPLL_SUSPEND_EN]));
    141	bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
    142			      BIT(u3pll_ctrl[PLL_SEQ_START]));
    143	bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
    144			      BIT(u3pll_ctrl[PLL_RESETB]));
    145
    146	/* Maximum timeout for PLL reset done */
    147	msleep(30);
    148
    149	ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL],
    150				     BIT(u3pll_ctrl[PLL_LOCK]));
    151
    152	return ret;
    153}
    154
    155static int bcm_usb_hs_phy_init(struct bcm_usb_phy_cfg *phy_cfg)
    156{
    157	int ret = 0;
    158	void __iomem *regs = phy_cfg->regs;
    159	const u8 *offset;
    160
    161	offset = phy_cfg->offset;
    162
    163	bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL],
    164			      BIT(u2pll_ctrl[PLL_RESETB]));
    165	bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
    166			      BIT(u2pll_ctrl[PLL_RESETB]));
    167
    168	ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL],
    169				     BIT(u2pll_ctrl[PLL_LOCK]));
    170
    171	return ret;
    172}
    173
    174static int bcm_usb_phy_reset(struct phy *phy)
    175{
    176	struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy);
    177	void __iomem *regs = phy_cfg->regs;
    178	const u8 *offset;
    179
    180	offset = phy_cfg->offset;
    181
    182	if (phy_cfg->type == USB_HS_PHY) {
    183		bcm_usb_reg32_clrbits(regs + offset[PHY_CTRL],
    184				      BIT(u2phy_ctrl[CORERDY]));
    185		bcm_usb_reg32_setbits(regs + offset[PHY_CTRL],
    186				      BIT(u2phy_ctrl[CORERDY]));
    187	}
    188
    189	return 0;
    190}
    191
    192static int bcm_usb_phy_init(struct phy *phy)
    193{
    194	struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy);
    195	int ret = -EINVAL;
    196
    197	if (phy_cfg->type == USB_SS_PHY)
    198		ret = bcm_usb_ss_phy_init(phy_cfg);
    199	else if (phy_cfg->type == USB_HS_PHY)
    200		ret = bcm_usb_hs_phy_init(phy_cfg);
    201
    202	return ret;
    203}
    204
    205static const struct phy_ops sr_phy_ops = {
    206	.init		= bcm_usb_phy_init,
    207	.reset		= bcm_usb_phy_reset,
    208	.owner		= THIS_MODULE,
    209};
    210
    211static struct phy *bcm_usb_phy_xlate(struct device *dev,
    212				     struct of_phandle_args *args)
    213{
    214	struct bcm_usb_phy_cfg *phy_cfg;
    215	int phy_idx;
    216
    217	phy_cfg = dev_get_drvdata(dev);
    218	if (!phy_cfg)
    219		return ERR_PTR(-EINVAL);
    220
    221	if (phy_cfg->version == BCM_SR_USB_COMBO_PHY) {
    222		phy_idx = args->args[0];
    223
    224		if (WARN_ON(phy_idx > 1))
    225			return ERR_PTR(-ENODEV);
    226
    227		return phy_cfg[phy_idx].phy;
    228	} else
    229		return phy_cfg->phy;
    230}
    231
    232static int bcm_usb_phy_create(struct device *dev, struct device_node *node,
    233			      void __iomem *regs, uint32_t version)
    234{
    235	struct bcm_usb_phy_cfg *phy_cfg;
    236	int idx;
    237
    238	if (version == BCM_SR_USB_COMBO_PHY) {
    239		phy_cfg = devm_kzalloc(dev, NUM_BCM_SR_USB_COMBO_PHYS *
    240				       sizeof(struct bcm_usb_phy_cfg),
    241				       GFP_KERNEL);
    242		if (!phy_cfg)
    243			return -ENOMEM;
    244
    245		for (idx = 0; idx < NUM_BCM_SR_USB_COMBO_PHYS; idx++) {
    246			phy_cfg[idx].regs = regs;
    247			phy_cfg[idx].version = version;
    248			if (idx == 0) {
    249				phy_cfg[idx].offset = bcm_usb_combo_phy_hs;
    250				phy_cfg[idx].type = USB_HS_PHY;
    251			} else {
    252				phy_cfg[idx].offset = bcm_usb_combo_phy_ss;
    253				phy_cfg[idx].type = USB_SS_PHY;
    254			}
    255			phy_cfg[idx].phy = devm_phy_create(dev, node,
    256							   &sr_phy_ops);
    257			if (IS_ERR(phy_cfg[idx].phy))
    258				return PTR_ERR(phy_cfg[idx].phy);
    259
    260			phy_set_drvdata(phy_cfg[idx].phy, &phy_cfg[idx]);
    261		}
    262	} else if (version == BCM_SR_USB_HS_PHY) {
    263		phy_cfg = devm_kzalloc(dev, sizeof(struct bcm_usb_phy_cfg),
    264				       GFP_KERNEL);
    265		if (!phy_cfg)
    266			return -ENOMEM;
    267
    268		phy_cfg->regs = regs;
    269		phy_cfg->version = version;
    270		phy_cfg->offset = bcm_usb_hs_phy;
    271		phy_cfg->type = USB_HS_PHY;
    272		phy_cfg->phy = devm_phy_create(dev, node, &sr_phy_ops);
    273		if (IS_ERR(phy_cfg->phy))
    274			return PTR_ERR(phy_cfg->phy);
    275
    276		phy_set_drvdata(phy_cfg->phy, phy_cfg);
    277	} else
    278		return -ENODEV;
    279
    280	dev_set_drvdata(dev, phy_cfg);
    281
    282	return 0;
    283}
    284
    285static const struct of_device_id bcm_usb_phy_of_match[] = {
    286	{
    287		.compatible = "brcm,sr-usb-combo-phy",
    288		.data = (void *)BCM_SR_USB_COMBO_PHY,
    289	},
    290	{
    291		.compatible = "brcm,sr-usb-hs-phy",
    292		.data = (void *)BCM_SR_USB_HS_PHY,
    293	},
    294	{ /* sentinel */ },
    295};
    296MODULE_DEVICE_TABLE(of, bcm_usb_phy_of_match);
    297
    298static int bcm_usb_phy_probe(struct platform_device *pdev)
    299{
    300	struct device *dev = &pdev->dev;
    301	struct device_node *dn = dev->of_node;
    302	const struct of_device_id *of_id;
    303	void __iomem *regs;
    304	int ret;
    305	enum bcm_usb_phy_version version;
    306	struct phy_provider *phy_provider;
    307
    308	regs = devm_platform_ioremap_resource(pdev, 0);
    309	if (IS_ERR(regs))
    310		return PTR_ERR(regs);
    311
    312	of_id = of_match_node(bcm_usb_phy_of_match, dn);
    313	if (of_id)
    314		version = (enum bcm_usb_phy_version)of_id->data;
    315	else
    316		return -ENODEV;
    317
    318	ret = bcm_usb_phy_create(dev, dn, regs, version);
    319	if (ret)
    320		return ret;
    321
    322	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
    323
    324	return PTR_ERR_OR_ZERO(phy_provider);
    325}
    326
    327static struct platform_driver bcm_usb_phy_driver = {
    328	.driver = {
    329		.name = "phy-bcm-sr-usb",
    330		.of_match_table = bcm_usb_phy_of_match,
    331	},
    332	.probe = bcm_usb_phy_probe,
    333};
    334module_platform_driver(bcm_usb_phy_driver);
    335
    336MODULE_AUTHOR("Broadcom");
    337MODULE_DESCRIPTION("Broadcom stingray USB Phy driver");
    338MODULE_LICENSE("GPL v2");