Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * BCM6328 USBH PHY Controller Driver
0004  *
0005  * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
0006  * Copyright (C) 2015 Simon Arlott
0007  *
0008  * Derived from bcm963xx_4.12L.06B_consumer/kernel/linux/arch/mips/bcm963xx/setup.c:
0009  * Copyright (C) 2002 Broadcom Corporation
0010  *
0011  * Derived from OpenWrt patches:
0012  * Copyright (C) 2013 Jonas Gorski <jonas.gorski@gmail.com>
0013  * Copyright (C) 2013 Florian Fainelli <f.fainelli@gmail.com>
0014  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
0015  */
0016 
0017 #include <linux/clk.h>
0018 #include <linux/io.h>
0019 #include <linux/module.h>
0020 #include <linux/phy/phy.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/reset.h>
0023 
0024 /* USBH control register offsets */
0025 enum usbh_regs {
0026     USBH_BRT_CONTROL1 = 0,
0027     USBH_BRT_CONTROL2,
0028     USBH_BRT_STATUS1,
0029     USBH_BRT_STATUS2,
0030     USBH_UTMI_CONTROL1,
0031 #define   USBH_UC1_DEV_MODE_SEL     BIT(0)
0032     USBH_TEST_PORT_CONTROL,
0033     USBH_PLL_CONTROL1,
0034 #define   USBH_PLLC_REFCLKSEL_SHIFT 0
0035 #define   USBH_PLLC_REFCLKSEL_MASK  (0x3 << USBH_PLLC_REFCLKSEL_SHIFT)
0036 #define   USBH_PLLC_CLKSEL_SHIFT    2
0037 #define   USBH_PLLC_CLKSEL_MASK     (0x3 << USBH_PLLC_CLKSEL_MASK)
0038 #define   USBH_PLLC_XTAL_PWRDWNB    BIT(4)
0039 #define   USBH_PLLC_PLL_PWRDWNB     BIT(5)
0040 #define   USBH_PLLC_PLL_CALEN       BIT(6)
0041 #define   USBH_PLLC_PHYPLL_BYP      BIT(7)
0042 #define   USBH_PLLC_PLL_RESET       BIT(8)
0043 #define   USBH_PLLC_PLL_IDDQ_PWRDN  BIT(9)
0044 #define   USBH_PLLC_PLL_PWRDN_DELAY BIT(10)
0045 #define   USBH_6318_PLLC_PLL_SUSPEND_EN BIT(27)
0046 #define   USBH_6318_PLLC_PHYPLL_BYP BIT(29)
0047 #define   USBH_6318_PLLC_PLL_RESET  BIT(30)
0048 #define   USBH_6318_PLLC_PLL_IDDQ_PWRDN BIT(31)
0049     USBH_SWAP_CONTROL,
0050 #define   USBH_SC_OHCI_DATA_SWAP    BIT(0)
0051 #define   USBH_SC_OHCI_ENDIAN_SWAP  BIT(1)
0052 #define   USBH_SC_OHCI_LOGICAL_ADDR_EN  BIT(2)
0053 #define   USBH_SC_EHCI_DATA_SWAP    BIT(3)
0054 #define   USBH_SC_EHCI_ENDIAN_SWAP  BIT(4)
0055 #define   USBH_SC_EHCI_LOGICAL_ADDR_EN  BIT(5)
0056 #define   USBH_SC_USB_DEVICE_SEL    BIT(6)
0057     USBH_GENERIC_CONTROL,
0058 #define   USBH_GC_PLL_SUSPEND_EN    BIT(1)
0059     USBH_FRAME_ADJUST_VALUE,
0060     USBH_SETUP,
0061 #define   USBH_S_IOC            BIT(4)
0062 #define   USBH_S_IPP            BIT(5)
0063     USBH_MDIO,
0064     USBH_MDIO32,
0065     USBH_USB_SIM_CONTROL,
0066 #define   USBH_USC_LADDR_SEL        BIT(5)
0067 
0068     __USBH_ENUM_SIZE
0069 };
0070 
0071 struct bcm63xx_usbh_phy_variant {
0072     /* Registers */
0073     long regs[__USBH_ENUM_SIZE];
0074 
0075     /* PLLC bits to set/clear for power on */
0076     u32 power_pllc_clr;
0077     u32 power_pllc_set;
0078 
0079     /* Setup bits to set/clear for power on */
0080     u32 setup_clr;
0081     u32 setup_set;
0082 
0083     /* Swap Control bits to set */
0084     u32 swapctl_dev_set;
0085 
0086     /* Test Port Control value to set if non-zero */
0087     u32 tpc_val;
0088 
0089     /* USB Sim Control bits to set */
0090     u32 usc_set;
0091 
0092     /* UTMI Control 1 bits to set */
0093     u32 utmictl1_dev_set;
0094 };
0095 
0096 struct bcm63xx_usbh_phy {
0097     void __iomem *base;
0098     struct clk *usbh_clk;
0099     struct clk *usb_ref_clk;
0100     struct reset_control *reset;
0101     const struct bcm63xx_usbh_phy_variant *variant;
0102     bool device_mode;
0103 };
0104 
0105 static const struct bcm63xx_usbh_phy_variant usbh_bcm6318 = {
0106     .regs = {
0107         [USBH_BRT_CONTROL1] = -1,
0108         [USBH_BRT_CONTROL2] = -1,
0109         [USBH_BRT_STATUS1] = -1,
0110         [USBH_BRT_STATUS2] = -1,
0111         [USBH_UTMI_CONTROL1] = 0x2c,
0112         [USBH_TEST_PORT_CONTROL] = 0x1c,
0113         [USBH_PLL_CONTROL1] = 0x04,
0114         [USBH_SWAP_CONTROL] = 0x0c,
0115         [USBH_GENERIC_CONTROL] = -1,
0116         [USBH_FRAME_ADJUST_VALUE] = 0x08,
0117         [USBH_SETUP] = 0x00,
0118         [USBH_MDIO] = 0x14,
0119         [USBH_MDIO32] = 0x18,
0120         [USBH_USB_SIM_CONTROL] = 0x20,
0121     },
0122     .power_pllc_clr = USBH_6318_PLLC_PLL_IDDQ_PWRDN,
0123     .power_pllc_set = USBH_6318_PLLC_PLL_SUSPEND_EN,
0124     .setup_set = USBH_S_IOC,
0125     .swapctl_dev_set = USBH_SC_USB_DEVICE_SEL,
0126     .usc_set = USBH_USC_LADDR_SEL,
0127     .utmictl1_dev_set = USBH_UC1_DEV_MODE_SEL,
0128 };
0129 
0130 static const struct bcm63xx_usbh_phy_variant usbh_bcm6328 = {
0131     .regs = {
0132         [USBH_BRT_CONTROL1] = 0x00,
0133         [USBH_BRT_CONTROL2] = 0x04,
0134         [USBH_BRT_STATUS1] = 0x08,
0135         [USBH_BRT_STATUS2] = 0x0c,
0136         [USBH_UTMI_CONTROL1] = 0x10,
0137         [USBH_TEST_PORT_CONTROL] = 0x14,
0138         [USBH_PLL_CONTROL1] = 0x18,
0139         [USBH_SWAP_CONTROL] = 0x1c,
0140         [USBH_GENERIC_CONTROL] = 0x20,
0141         [USBH_FRAME_ADJUST_VALUE] = 0x24,
0142         [USBH_SETUP] = 0x28,
0143         [USBH_MDIO] = 0x2c,
0144         [USBH_MDIO32] = 0x30,
0145         [USBH_USB_SIM_CONTROL] = 0x34,
0146     },
0147     .setup_set = USBH_S_IOC,
0148     .swapctl_dev_set = USBH_SC_USB_DEVICE_SEL,
0149     .utmictl1_dev_set = USBH_UC1_DEV_MODE_SEL,
0150 };
0151 
0152 static const struct bcm63xx_usbh_phy_variant usbh_bcm6358 = {
0153     .regs = {
0154         [USBH_BRT_CONTROL1] = -1,
0155         [USBH_BRT_CONTROL2] = -1,
0156         [USBH_BRT_STATUS1] = -1,
0157         [USBH_BRT_STATUS2] = -1,
0158         [USBH_UTMI_CONTROL1] = -1,
0159         [USBH_TEST_PORT_CONTROL] = 0x24,
0160         [USBH_PLL_CONTROL1] = -1,
0161         [USBH_SWAP_CONTROL] = 0x00,
0162         [USBH_GENERIC_CONTROL] = -1,
0163         [USBH_FRAME_ADJUST_VALUE] = -1,
0164         [USBH_SETUP] = -1,
0165         [USBH_MDIO] = -1,
0166         [USBH_MDIO32] = -1,
0167         [USBH_USB_SIM_CONTROL] = -1,
0168     },
0169     /*
0170      * The magic value comes for the original vendor BSP
0171      * and is needed for USB to work. Datasheet does not
0172      * help, so the magic value is used as-is.
0173      */
0174     .tpc_val = 0x1c0020,
0175 };
0176 
0177 static const struct bcm63xx_usbh_phy_variant usbh_bcm6368 = {
0178     .regs = {
0179         [USBH_BRT_CONTROL1] = 0x00,
0180         [USBH_BRT_CONTROL2] = 0x04,
0181         [USBH_BRT_STATUS1] = 0x08,
0182         [USBH_BRT_STATUS2] = 0x0c,
0183         [USBH_UTMI_CONTROL1] = 0x10,
0184         [USBH_TEST_PORT_CONTROL] = 0x14,
0185         [USBH_PLL_CONTROL1] = 0x18,
0186         [USBH_SWAP_CONTROL] = 0x1c,
0187         [USBH_GENERIC_CONTROL] = -1,
0188         [USBH_FRAME_ADJUST_VALUE] = 0x24,
0189         [USBH_SETUP] = 0x28,
0190         [USBH_MDIO] = 0x2c,
0191         [USBH_MDIO32] = 0x30,
0192         [USBH_USB_SIM_CONTROL] = 0x34,
0193     },
0194     .power_pllc_clr = USBH_PLLC_PLL_IDDQ_PWRDN | USBH_PLLC_PLL_PWRDN_DELAY,
0195     .setup_set = USBH_S_IOC,
0196     .swapctl_dev_set = USBH_SC_USB_DEVICE_SEL,
0197     .utmictl1_dev_set = USBH_UC1_DEV_MODE_SEL,
0198 };
0199 
0200 static const struct bcm63xx_usbh_phy_variant usbh_bcm63268 = {
0201     .regs = {
0202         [USBH_BRT_CONTROL1] = 0x00,
0203         [USBH_BRT_CONTROL2] = 0x04,
0204         [USBH_BRT_STATUS1] = 0x08,
0205         [USBH_BRT_STATUS2] = 0x0c,
0206         [USBH_UTMI_CONTROL1] = 0x10,
0207         [USBH_TEST_PORT_CONTROL] = 0x14,
0208         [USBH_PLL_CONTROL1] = 0x18,
0209         [USBH_SWAP_CONTROL] = 0x1c,
0210         [USBH_GENERIC_CONTROL] = 0x20,
0211         [USBH_FRAME_ADJUST_VALUE] = 0x24,
0212         [USBH_SETUP] = 0x28,
0213         [USBH_MDIO] = 0x2c,
0214         [USBH_MDIO32] = 0x30,
0215         [USBH_USB_SIM_CONTROL] = 0x34,
0216     },
0217     .power_pllc_clr = USBH_PLLC_PLL_IDDQ_PWRDN | USBH_PLLC_PLL_PWRDN_DELAY,
0218     .setup_clr = USBH_S_IPP,
0219     .setup_set = USBH_S_IOC,
0220     .swapctl_dev_set = USBH_SC_USB_DEVICE_SEL,
0221     .utmictl1_dev_set = USBH_UC1_DEV_MODE_SEL,
0222 };
0223 
0224 static inline bool usbh_has_reg(struct bcm63xx_usbh_phy *usbh, int reg)
0225 {
0226     return (usbh->variant->regs[reg] >= 0);
0227 }
0228 
0229 static inline u32 usbh_readl(struct bcm63xx_usbh_phy *usbh, int reg)
0230 {
0231     return __raw_readl(usbh->base + usbh->variant->regs[reg]);
0232 }
0233 
0234 static inline void usbh_writel(struct bcm63xx_usbh_phy *usbh, int reg,
0235                    u32 value)
0236 {
0237     __raw_writel(value, usbh->base + usbh->variant->regs[reg]);
0238 }
0239 
0240 static int bcm63xx_usbh_phy_init(struct phy *phy)
0241 {
0242     struct bcm63xx_usbh_phy *usbh = phy_get_drvdata(phy);
0243     int ret;
0244 
0245     ret = clk_prepare_enable(usbh->usbh_clk);
0246     if (ret) {
0247         dev_err(&phy->dev, "unable to enable usbh clock: %d\n", ret);
0248         return ret;
0249     }
0250 
0251     ret = clk_prepare_enable(usbh->usb_ref_clk);
0252     if (ret) {
0253         dev_err(&phy->dev, "unable to enable usb_ref clock: %d\n", ret);
0254         clk_disable_unprepare(usbh->usbh_clk);
0255         return ret;
0256     }
0257 
0258     ret = reset_control_reset(usbh->reset);
0259     if (ret) {
0260         dev_err(&phy->dev, "unable to reset device: %d\n", ret);
0261         clk_disable_unprepare(usbh->usb_ref_clk);
0262         clk_disable_unprepare(usbh->usbh_clk);
0263         return ret;
0264     }
0265 
0266     /* Configure to work in native CPU endian */
0267     if (usbh_has_reg(usbh, USBH_SWAP_CONTROL)) {
0268         u32 val = usbh_readl(usbh, USBH_SWAP_CONTROL);
0269 
0270         val |= USBH_SC_EHCI_DATA_SWAP;
0271         val &= ~USBH_SC_EHCI_ENDIAN_SWAP;
0272 
0273         val |= USBH_SC_OHCI_DATA_SWAP;
0274         val &= ~USBH_SC_OHCI_ENDIAN_SWAP;
0275 
0276         if (usbh->device_mode && usbh->variant->swapctl_dev_set)
0277             val |= usbh->variant->swapctl_dev_set;
0278 
0279         usbh_writel(usbh, USBH_SWAP_CONTROL, val);
0280     }
0281 
0282     if (usbh_has_reg(usbh, USBH_SETUP)) {
0283         u32 val = usbh_readl(usbh, USBH_SETUP);
0284 
0285         val |= usbh->variant->setup_set;
0286         val &= ~usbh->variant->setup_clr;
0287 
0288         usbh_writel(usbh, USBH_SETUP, val);
0289     }
0290 
0291     if (usbh_has_reg(usbh, USBH_USB_SIM_CONTROL)) {
0292         u32 val = usbh_readl(usbh, USBH_USB_SIM_CONTROL);
0293 
0294         val |= usbh->variant->usc_set;
0295 
0296         usbh_writel(usbh, USBH_USB_SIM_CONTROL, val);
0297     }
0298 
0299     if (usbh->variant->tpc_val &&
0300         usbh_has_reg(usbh, USBH_TEST_PORT_CONTROL))
0301         usbh_writel(usbh, USBH_TEST_PORT_CONTROL,
0302                 usbh->variant->tpc_val);
0303 
0304     if (usbh->device_mode &&
0305         usbh_has_reg(usbh, USBH_UTMI_CONTROL1) &&
0306         usbh->variant->utmictl1_dev_set) {
0307         u32 val = usbh_readl(usbh, USBH_UTMI_CONTROL1);
0308 
0309         val |= usbh->variant->utmictl1_dev_set;
0310 
0311         usbh_writel(usbh, USBH_UTMI_CONTROL1, val);
0312     }
0313 
0314     return 0;
0315 }
0316 
0317 static int bcm63xx_usbh_phy_power_on(struct phy *phy)
0318 {
0319     struct bcm63xx_usbh_phy *usbh = phy_get_drvdata(phy);
0320 
0321     if (usbh_has_reg(usbh, USBH_PLL_CONTROL1)) {
0322         u32 val = usbh_readl(usbh, USBH_PLL_CONTROL1);
0323 
0324         val |= usbh->variant->power_pllc_set;
0325         val &= ~usbh->variant->power_pllc_clr;
0326 
0327         usbh_writel(usbh, USBH_PLL_CONTROL1, val);
0328     }
0329 
0330     return 0;
0331 }
0332 
0333 static int bcm63xx_usbh_phy_power_off(struct phy *phy)
0334 {
0335     struct bcm63xx_usbh_phy *usbh = phy_get_drvdata(phy);
0336 
0337     if (usbh_has_reg(usbh, USBH_PLL_CONTROL1)) {
0338         u32 val = usbh_readl(usbh, USBH_PLL_CONTROL1);
0339 
0340         val &= ~usbh->variant->power_pllc_set;
0341         val |= usbh->variant->power_pllc_clr;
0342 
0343         usbh_writel(usbh, USBH_PLL_CONTROL1, val);
0344     }
0345 
0346     return 0;
0347 }
0348 
0349 static int bcm63xx_usbh_phy_exit(struct phy *phy)
0350 {
0351     struct bcm63xx_usbh_phy *usbh = phy_get_drvdata(phy);
0352 
0353     clk_disable_unprepare(usbh->usbh_clk);
0354     clk_disable_unprepare(usbh->usb_ref_clk);
0355 
0356     return 0;
0357 }
0358 
0359 static const struct phy_ops bcm63xx_usbh_phy_ops = {
0360     .exit = bcm63xx_usbh_phy_exit,
0361     .init = bcm63xx_usbh_phy_init,
0362     .power_off = bcm63xx_usbh_phy_power_off,
0363     .power_on = bcm63xx_usbh_phy_power_on,
0364     .owner = THIS_MODULE,
0365 };
0366 
0367 static struct phy *bcm63xx_usbh_phy_xlate(struct device *dev,
0368                       struct of_phandle_args *args)
0369 {
0370     struct bcm63xx_usbh_phy *usbh = dev_get_drvdata(dev);
0371 
0372     usbh->device_mode = !!args->args[0];
0373 
0374     return of_phy_simple_xlate(dev, args);
0375 }
0376 
0377 static int __init bcm63xx_usbh_phy_probe(struct platform_device *pdev)
0378 {
0379     struct device *dev = &pdev->dev;
0380     struct bcm63xx_usbh_phy *usbh;
0381     const struct bcm63xx_usbh_phy_variant *variant;
0382     struct phy *phy;
0383     struct phy_provider *phy_provider;
0384 
0385     usbh = devm_kzalloc(dev, sizeof(*usbh), GFP_KERNEL);
0386     if (!usbh)
0387         return -ENOMEM;
0388 
0389     variant = device_get_match_data(dev);
0390     if (!variant)
0391         return -EINVAL;
0392     usbh->variant = variant;
0393 
0394     usbh->base = devm_platform_ioremap_resource(pdev, 0);
0395     if (IS_ERR(usbh->base))
0396         return PTR_ERR(usbh->base);
0397 
0398     usbh->reset = devm_reset_control_get_exclusive(dev, NULL);
0399     if (IS_ERR(usbh->reset)) {
0400         if (PTR_ERR(usbh->reset) != -EPROBE_DEFER)
0401             dev_err(dev, "failed to get reset\n");
0402         return PTR_ERR(usbh->reset);
0403     }
0404 
0405     usbh->usbh_clk = devm_clk_get_optional(dev, "usbh");
0406     if (IS_ERR(usbh->usbh_clk))
0407         return PTR_ERR(usbh->usbh_clk);
0408 
0409     usbh->usb_ref_clk = devm_clk_get_optional(dev, "usb_ref");
0410     if (IS_ERR(usbh->usb_ref_clk))
0411         return PTR_ERR(usbh->usb_ref_clk);
0412 
0413     phy = devm_phy_create(dev, NULL, &bcm63xx_usbh_phy_ops);
0414     if (IS_ERR(phy)) {
0415         dev_err(dev, "failed to create PHY\n");
0416         return PTR_ERR(phy);
0417     }
0418 
0419     platform_set_drvdata(pdev, usbh);
0420     phy_set_drvdata(phy, usbh);
0421 
0422     phy_provider = devm_of_phy_provider_register(dev,
0423                              bcm63xx_usbh_phy_xlate);
0424     if (IS_ERR(phy_provider)) {
0425         dev_err(dev, "failed to register PHY provider\n");
0426         return PTR_ERR(phy_provider);
0427     }
0428 
0429     dev_dbg(dev, "Registered BCM63xx USB PHY driver\n");
0430 
0431     return 0;
0432 }
0433 
0434 static const struct of_device_id bcm63xx_usbh_phy_ids[] __initconst = {
0435     { .compatible = "brcm,bcm6318-usbh-phy", .data = &usbh_bcm6318 },
0436     { .compatible = "brcm,bcm6328-usbh-phy", .data = &usbh_bcm6328 },
0437     { .compatible = "brcm,bcm6358-usbh-phy", .data = &usbh_bcm6358 },
0438     { .compatible = "brcm,bcm6362-usbh-phy", .data = &usbh_bcm6368 },
0439     { .compatible = "brcm,bcm6368-usbh-phy", .data = &usbh_bcm6368 },
0440     { .compatible = "brcm,bcm63268-usbh-phy", .data = &usbh_bcm63268 },
0441     { /* sentinel */ }
0442 };
0443 MODULE_DEVICE_TABLE(of, bcm63xx_usbh_phy_ids);
0444 
0445 static struct platform_driver bcm63xx_usbh_phy_driver __refdata = {
0446     .driver = {
0447         .name = "bcm63xx-usbh-phy",
0448         .of_match_table = bcm63xx_usbh_phy_ids,
0449     },
0450     .probe  = bcm63xx_usbh_phy_probe,
0451 };
0452 module_platform_driver(bcm63xx_usbh_phy_driver);
0453 
0454 MODULE_DESCRIPTION("BCM63xx USBH PHY driver");
0455 MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>");
0456 MODULE_AUTHOR("Simon Arlott");
0457 MODULE_LICENSE("GPL");