246 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Broadcom Northstar USB 3.0 PHY Driver4 *5 * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>6 * Copyright (C) 2016 Broadcom7 *8 * All magic values used for initialization (and related comments) were obtained9 * from Broadcom's SDK:10 * Copyright (c) Broadcom Corp, 201211 */12 13#include <linux/bcma/bcma.h>14#include <linux/delay.h>15#include <linux/err.h>16#include <linux/iopoll.h>17#include <linux/mdio.h>18#include <linux/module.h>19#include <linux/of.h>20#include <linux/of_address.h>21#include <linux/platform_device.h>22#include <linux/phy/phy.h>23#include <linux/property.h>24#include <linux/slab.h>25 26#define BCM_NS_USB3_PHY_BASE_ADDR_REG 0x1f27#define BCM_NS_USB3_PHY_PLL30_BLOCK 0x800028#define BCM_NS_USB3_PHY_TX_PMD_BLOCK 0x804029#define BCM_NS_USB3_PHY_PIPE_BLOCK 0x806030 31/* Registers of PLL30 block */32#define BCM_NS_USB3_PLL_CONTROL 0x0133#define BCM_NS_USB3_PLLA_CONTROL0 0x0a34#define BCM_NS_USB3_PLLA_CONTROL1 0x0b35 36/* Registers of TX PMD block */37#define BCM_NS_USB3_TX_PMD_CONTROL1 0x0138 39/* Registers of PIPE block */40#define BCM_NS_USB3_LFPS_CMP 0x0241#define BCM_NS_USB3_LFPS_DEGLITCH 0x0342 43enum bcm_ns_family {44 BCM_NS_UNKNOWN,45 BCM_NS_AX,46 BCM_NS_BX,47};48 49struct bcm_ns_usb3 {50 struct device *dev;51 enum bcm_ns_family family;52 void __iomem *dmp;53 struct mdio_device *mdiodev;54 struct phy *phy;55};56 57static const struct of_device_id bcm_ns_usb3_id_table[] = {58 {59 .compatible = "brcm,ns-ax-usb3-phy",60 .data = (int *)BCM_NS_AX,61 },62 {63 .compatible = "brcm,ns-bx-usb3-phy",64 .data = (int *)BCM_NS_BX,65 },66 {},67};68 69static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg,70 u16 value);71 72static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)73{74 int err;75 76 /* USB3 PLL Block */77 err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,78 BCM_NS_USB3_PHY_PLL30_BLOCK);79 if (err < 0)80 return err;81 82 /* Assert Ana_Pllseq start */83 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x1000);84 85 /* Assert CML Divider ratio to 26 */86 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400);87 88 /* Asserting PLL Reset */89 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0xc000);90 91 /* Deaaserting PLL Reset */92 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0x8000);93 94 /* Deasserting USB3 system reset */95 writel(0, usb3->dmp + BCMA_RESET_CTL);96 97 /* PLL frequency monitor enable */98 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x9000);99 100 /* PIPE Block */101 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,102 BCM_NS_USB3_PHY_PIPE_BLOCK);103 104 /* CMPMAX & CMPMINTH setting */105 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_CMP, 0xf30d);106 107 /* DEGLITCH MIN & MAX setting */108 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_DEGLITCH, 0x6302);109 110 /* TXPMD block */111 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,112 BCM_NS_USB3_PHY_TX_PMD_BLOCK);113 114 /* Enabling SSC */115 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003);116 117 return 0;118}119 120static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3)121{122 int err;123 124 /* PLL30 block */125 err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,126 BCM_NS_USB3_PHY_PLL30_BLOCK);127 if (err < 0)128 return err;129 130 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400);131 132 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 0x80e0);133 134 bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x009c);135 136 /* Enable SSC */137 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,138 BCM_NS_USB3_PHY_TX_PMD_BLOCK);139 140 bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x21d3);141 142 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003);143 144 /* Deasserting USB3 system reset */145 writel(0, usb3->dmp + BCMA_RESET_CTL);146 147 return 0;148}149 150static int bcm_ns_usb3_phy_init(struct phy *phy)151{152 struct bcm_ns_usb3 *usb3 = phy_get_drvdata(phy);153 int err;154 155 /* Perform USB3 system soft reset */156 writel(BCMA_RESET_CTL_RESET, usb3->dmp + BCMA_RESET_CTL);157 158 switch (usb3->family) {159 case BCM_NS_AX:160 err = bcm_ns_usb3_phy_init_ns_ax(usb3);161 break;162 case BCM_NS_BX:163 err = bcm_ns_usb3_phy_init_ns_bx(usb3);164 break;165 default:166 WARN_ON(1);167 err = -ENOTSUPP;168 }169 170 return err;171}172 173static const struct phy_ops ops = {174 .init = bcm_ns_usb3_phy_init,175 .owner = THIS_MODULE,176};177 178/**************************************************179 * MDIO driver code180 **************************************************/181 182static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg,183 u16 value)184{185 struct mdio_device *mdiodev = usb3->mdiodev;186 187 return mdiodev_write(mdiodev, reg, value);188}189 190static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev)191{192 struct device *dev = &mdiodev->dev;193 struct phy_provider *phy_provider;194 struct device_node *syscon_np;195 struct bcm_ns_usb3 *usb3;196 struct resource res;197 int err;198 199 usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL);200 if (!usb3)201 return -ENOMEM;202 203 usb3->dev = dev;204 usb3->mdiodev = mdiodev;205 206 usb3->family = (enum bcm_ns_family)device_get_match_data(dev);207 208 syscon_np = of_parse_phandle(dev->of_node, "usb3-dmp-syscon", 0);209 err = of_address_to_resource(syscon_np, 0, &res);210 of_node_put(syscon_np);211 if (err)212 return err;213 214 usb3->dmp = devm_ioremap_resource(dev, &res);215 if (IS_ERR(usb3->dmp))216 return PTR_ERR(usb3->dmp);217 218 usb3->phy = devm_phy_create(dev, NULL, &ops);219 if (IS_ERR(usb3->phy)) {220 dev_err(dev, "Failed to create PHY\n");221 return PTR_ERR(usb3->phy);222 }223 224 phy_set_drvdata(usb3->phy, usb3);225 226 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);227 228 return PTR_ERR_OR_ZERO(phy_provider);229}230 231static struct mdio_driver bcm_ns_usb3_mdio_driver = {232 .mdiodrv = {233 .driver = {234 .name = "bcm_ns_mdio_usb3",235 .of_match_table = bcm_ns_usb3_id_table,236 },237 },238 .probe = bcm_ns_usb3_mdio_probe,239};240 241mdio_module_driver(bcm_ns_usb3_mdio_driver);242 243MODULE_DESCRIPTION("Broadcom Northstar USB 3.0 PHY Driver");244MODULE_LICENSE("GPL v2");245MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table);246