Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2016-2018 Broadcom
0004  */
0005 
0006 #include <linux/delay.h>
0007 #include <linux/io.h>
0008 #include <linux/iopoll.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/phy/phy.h>
0012 #include <linux/platform_device.h>
0013 
0014 enum bcm_usb_phy_version {
0015     BCM_SR_USB_COMBO_PHY,
0016     BCM_SR_USB_HS_PHY,
0017 };
0018 
0019 enum bcm_usb_phy_reg {
0020     PLL_CTRL,
0021     PHY_CTRL,
0022     PHY_PLL_CTRL,
0023 };
0024 
0025 /* USB PHY registers */
0026 
0027 static const u8 bcm_usb_combo_phy_ss[] = {
0028     [PLL_CTRL]      = 0x18,
0029     [PHY_CTRL]      = 0x14,
0030 };
0031 
0032 static const u8 bcm_usb_combo_phy_hs[] = {
0033     [PLL_CTRL]  = 0x0c,
0034     [PHY_CTRL]  = 0x10,
0035 };
0036 
0037 static const u8 bcm_usb_hs_phy[] = {
0038     [PLL_CTRL]  = 0x8,
0039     [PHY_CTRL]  = 0xc,
0040 };
0041 
0042 enum pll_ctrl_bits {
0043     PLL_RESETB,
0044     SSPLL_SUSPEND_EN,
0045     PLL_SEQ_START,
0046     PLL_LOCK,
0047 };
0048 
0049 static const u8 u3pll_ctrl[] = {
0050     [PLL_RESETB]        = 0,
0051     [SSPLL_SUSPEND_EN]  = 1,
0052     [PLL_SEQ_START]     = 2,
0053     [PLL_LOCK]      = 3,
0054 };
0055 
0056 #define HSPLL_PDIV_MASK     0xF
0057 #define HSPLL_PDIV_VAL      0x1
0058 
0059 static const u8 u2pll_ctrl[] = {
0060     [PLL_RESETB]    = 5,
0061     [PLL_LOCK]  = 6,
0062 };
0063 
0064 enum bcm_usb_phy_ctrl_bits {
0065     CORERDY,
0066     PHY_RESETB,
0067     PHY_PCTL,
0068 };
0069 
0070 #define PHY_PCTL_MASK   0xffff
0071 #define SSPHY_PCTL_VAL  0x0006
0072 
0073 static const u8 u3phy_ctrl[] = {
0074     [PHY_RESETB]    = 1,
0075     [PHY_PCTL]  = 2,
0076 };
0077 
0078 static const u8 u2phy_ctrl[] = {
0079     [CORERDY]       = 0,
0080     [PHY_RESETB]        = 5,
0081     [PHY_PCTL]      = 6,
0082 };
0083 
0084 struct bcm_usb_phy_cfg {
0085     uint32_t type;
0086     uint32_t version;
0087     void __iomem *regs;
0088     struct phy *phy;
0089     const u8 *offset;
0090 };
0091 
0092 #define PLL_LOCK_RETRY_COUNT    1000
0093 
0094 enum bcm_usb_phy_type {
0095     USB_HS_PHY,
0096     USB_SS_PHY,
0097 };
0098 
0099 #define NUM_BCM_SR_USB_COMBO_PHYS   2
0100 
0101 static inline void bcm_usb_reg32_clrbits(void __iomem *addr, uint32_t clear)
0102 {
0103     writel(readl(addr) & ~clear, addr);
0104 }
0105 
0106 static inline void bcm_usb_reg32_setbits(void __iomem *addr, uint32_t set)
0107 {
0108     writel(readl(addr) | set, addr);
0109 }
0110 
0111 static int bcm_usb_pll_lock_check(void __iomem *addr, u32 bit)
0112 {
0113     u32 data;
0114     int ret;
0115 
0116     ret = readl_poll_timeout_atomic(addr, data, (data & bit), 1,
0117                     PLL_LOCK_RETRY_COUNT);
0118     if (ret)
0119         pr_err("%s: FAIL\n", __func__);
0120 
0121     return ret;
0122 }
0123 
0124 static int bcm_usb_ss_phy_init(struct bcm_usb_phy_cfg *phy_cfg)
0125 {
0126     int ret = 0;
0127     void __iomem *regs = phy_cfg->regs;
0128     const u8 *offset;
0129     u32 rd_data;
0130 
0131     offset = phy_cfg->offset;
0132 
0133     /* Set pctl with mode and soft reset */
0134     rd_data = readl(regs + offset[PHY_CTRL]);
0135     rd_data &= ~(PHY_PCTL_MASK << u3phy_ctrl[PHY_PCTL]);
0136     rd_data |= (SSPHY_PCTL_VAL << u3phy_ctrl[PHY_PCTL]);
0137     writel(rd_data, regs + offset[PHY_CTRL]);
0138 
0139     bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL],
0140                   BIT(u3pll_ctrl[SSPLL_SUSPEND_EN]));
0141     bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
0142                   BIT(u3pll_ctrl[PLL_SEQ_START]));
0143     bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
0144                   BIT(u3pll_ctrl[PLL_RESETB]));
0145 
0146     /* Maximum timeout for PLL reset done */
0147     msleep(30);
0148 
0149     ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL],
0150                      BIT(u3pll_ctrl[PLL_LOCK]));
0151 
0152     return ret;
0153 }
0154 
0155 static int bcm_usb_hs_phy_init(struct bcm_usb_phy_cfg *phy_cfg)
0156 {
0157     int ret = 0;
0158     void __iomem *regs = phy_cfg->regs;
0159     const u8 *offset;
0160 
0161     offset = phy_cfg->offset;
0162 
0163     bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL],
0164                   BIT(u2pll_ctrl[PLL_RESETB]));
0165     bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
0166                   BIT(u2pll_ctrl[PLL_RESETB]));
0167 
0168     ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL],
0169                      BIT(u2pll_ctrl[PLL_LOCK]));
0170 
0171     return ret;
0172 }
0173 
0174 static int bcm_usb_phy_reset(struct phy *phy)
0175 {
0176     struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy);
0177     void __iomem *regs = phy_cfg->regs;
0178     const u8 *offset;
0179 
0180     offset = phy_cfg->offset;
0181 
0182     if (phy_cfg->type == USB_HS_PHY) {
0183         bcm_usb_reg32_clrbits(regs + offset[PHY_CTRL],
0184                       BIT(u2phy_ctrl[CORERDY]));
0185         bcm_usb_reg32_setbits(regs + offset[PHY_CTRL],
0186                       BIT(u2phy_ctrl[CORERDY]));
0187     }
0188 
0189     return 0;
0190 }
0191 
0192 static int bcm_usb_phy_init(struct phy *phy)
0193 {
0194     struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy);
0195     int ret = -EINVAL;
0196 
0197     if (phy_cfg->type == USB_SS_PHY)
0198         ret = bcm_usb_ss_phy_init(phy_cfg);
0199     else if (phy_cfg->type == USB_HS_PHY)
0200         ret = bcm_usb_hs_phy_init(phy_cfg);
0201 
0202     return ret;
0203 }
0204 
0205 static const struct phy_ops sr_phy_ops = {
0206     .init       = bcm_usb_phy_init,
0207     .reset      = bcm_usb_phy_reset,
0208     .owner      = THIS_MODULE,
0209 };
0210 
0211 static struct phy *bcm_usb_phy_xlate(struct device *dev,
0212                      struct of_phandle_args *args)
0213 {
0214     struct bcm_usb_phy_cfg *phy_cfg;
0215     int phy_idx;
0216 
0217     phy_cfg = dev_get_drvdata(dev);
0218     if (!phy_cfg)
0219         return ERR_PTR(-EINVAL);
0220 
0221     if (phy_cfg->version == BCM_SR_USB_COMBO_PHY) {
0222         phy_idx = args->args[0];
0223 
0224         if (WARN_ON(phy_idx > 1))
0225             return ERR_PTR(-ENODEV);
0226 
0227         return phy_cfg[phy_idx].phy;
0228     } else
0229         return phy_cfg->phy;
0230 }
0231 
0232 static int bcm_usb_phy_create(struct device *dev, struct device_node *node,
0233                   void __iomem *regs, uint32_t version)
0234 {
0235     struct bcm_usb_phy_cfg *phy_cfg;
0236     int idx;
0237 
0238     if (version == BCM_SR_USB_COMBO_PHY) {
0239         phy_cfg = devm_kzalloc(dev, NUM_BCM_SR_USB_COMBO_PHYS *
0240                        sizeof(struct bcm_usb_phy_cfg),
0241                        GFP_KERNEL);
0242         if (!phy_cfg)
0243             return -ENOMEM;
0244 
0245         for (idx = 0; idx < NUM_BCM_SR_USB_COMBO_PHYS; idx++) {
0246             phy_cfg[idx].regs = regs;
0247             phy_cfg[idx].version = version;
0248             if (idx == 0) {
0249                 phy_cfg[idx].offset = bcm_usb_combo_phy_hs;
0250                 phy_cfg[idx].type = USB_HS_PHY;
0251             } else {
0252                 phy_cfg[idx].offset = bcm_usb_combo_phy_ss;
0253                 phy_cfg[idx].type = USB_SS_PHY;
0254             }
0255             phy_cfg[idx].phy = devm_phy_create(dev, node,
0256                                &sr_phy_ops);
0257             if (IS_ERR(phy_cfg[idx].phy))
0258                 return PTR_ERR(phy_cfg[idx].phy);
0259 
0260             phy_set_drvdata(phy_cfg[idx].phy, &phy_cfg[idx]);
0261         }
0262     } else if (version == BCM_SR_USB_HS_PHY) {
0263         phy_cfg = devm_kzalloc(dev, sizeof(struct bcm_usb_phy_cfg),
0264                        GFP_KERNEL);
0265         if (!phy_cfg)
0266             return -ENOMEM;
0267 
0268         phy_cfg->regs = regs;
0269         phy_cfg->version = version;
0270         phy_cfg->offset = bcm_usb_hs_phy;
0271         phy_cfg->type = USB_HS_PHY;
0272         phy_cfg->phy = devm_phy_create(dev, node, &sr_phy_ops);
0273         if (IS_ERR(phy_cfg->phy))
0274             return PTR_ERR(phy_cfg->phy);
0275 
0276         phy_set_drvdata(phy_cfg->phy, phy_cfg);
0277     } else
0278         return -ENODEV;
0279 
0280     dev_set_drvdata(dev, phy_cfg);
0281 
0282     return 0;
0283 }
0284 
0285 static const struct of_device_id bcm_usb_phy_of_match[] = {
0286     {
0287         .compatible = "brcm,sr-usb-combo-phy",
0288         .data = (void *)BCM_SR_USB_COMBO_PHY,
0289     },
0290     {
0291         .compatible = "brcm,sr-usb-hs-phy",
0292         .data = (void *)BCM_SR_USB_HS_PHY,
0293     },
0294     { /* sentinel */ },
0295 };
0296 MODULE_DEVICE_TABLE(of, bcm_usb_phy_of_match);
0297 
0298 static int bcm_usb_phy_probe(struct platform_device *pdev)
0299 {
0300     struct device *dev = &pdev->dev;
0301     struct device_node *dn = dev->of_node;
0302     const struct of_device_id *of_id;
0303     void __iomem *regs;
0304     int ret;
0305     enum bcm_usb_phy_version version;
0306     struct phy_provider *phy_provider;
0307 
0308     regs = devm_platform_ioremap_resource(pdev, 0);
0309     if (IS_ERR(regs))
0310         return PTR_ERR(regs);
0311 
0312     of_id = of_match_node(bcm_usb_phy_of_match, dn);
0313     if (of_id)
0314         version = (enum bcm_usb_phy_version)of_id->data;
0315     else
0316         return -ENODEV;
0317 
0318     ret = bcm_usb_phy_create(dev, dn, regs, version);
0319     if (ret)
0320         return ret;
0321 
0322     phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
0323 
0324     return PTR_ERR_OR_ZERO(phy_provider);
0325 }
0326 
0327 static struct platform_driver bcm_usb_phy_driver = {
0328     .driver = {
0329         .name = "phy-bcm-sr-usb",
0330         .of_match_table = bcm_usb_phy_of_match,
0331     },
0332     .probe = bcm_usb_phy_probe,
0333 };
0334 module_platform_driver(bcm_usb_phy_driver);
0335 
0336 MODULE_AUTHOR("Broadcom");
0337 MODULE_DESCRIPTION("Broadcom stingray USB Phy driver");
0338 MODULE_LICENSE("GPL v2");