root/drivers/phy/broadcom/phy-bcm-sr-usb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcm_usb_reg32_clrbits
  2. bcm_usb_reg32_setbits
  3. bcm_usb_pll_lock_check
  4. bcm_usb_ss_phy_init
  5. bcm_usb_hs_phy_init
  6. bcm_usb_phy_reset
  7. bcm_usb_phy_init
  8. bcm_usb_phy_xlate
  9. bcm_usb_phy_create
  10. bcm_usb_phy_probe

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

/* [<][>][^][v][top][bottom][index][help] */