Merge tag 'linux-watchdog-6.7-rc1' of git://www.linux-watchdog.org/linux-watchdog
[linux-2.6-microblaze.git] / drivers / phy / broadcom / phy-bcm-ns-usb3.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Broadcom Northstar USB 3.0 PHY Driver
4  *
5  * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
6  * Copyright (C) 2016 Broadcom
7  *
8  * All magic values used for initialization (and related comments) were obtained
9  * from Broadcom's SDK:
10  * Copyright (c) Broadcom Corp, 2012
11  */
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   0x1f
27 #define BCM_NS_USB3_PHY_PLL30_BLOCK     0x8000
28 #define BCM_NS_USB3_PHY_TX_PMD_BLOCK    0x8040
29 #define BCM_NS_USB3_PHY_PIPE_BLOCK      0x8060
30
31 /* Registers of PLL30 block */
32 #define BCM_NS_USB3_PLL_CONTROL         0x01
33 #define BCM_NS_USB3_PLLA_CONTROL0       0x0a
34 #define BCM_NS_USB3_PLLA_CONTROL1       0x0b
35
36 /* Registers of TX PMD block */
37 #define BCM_NS_USB3_TX_PMD_CONTROL1     0x01
38
39 /* Registers of PIPE block */
40 #define BCM_NS_USB3_LFPS_CMP            0x02
41 #define BCM_NS_USB3_LFPS_DEGLITCH       0x03
42
43 enum bcm_ns_family {
44         BCM_NS_UNKNOWN,
45         BCM_NS_AX,
46         BCM_NS_BX,
47 };
48
49 struct 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
57 static 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
69 static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg,
70                                       u16 value);
71
72 static 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
120 static 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
150 static 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
173 static const struct phy_ops ops = {
174         .init           = bcm_ns_usb3_phy_init,
175         .owner          = THIS_MODULE,
176 };
177
178 /**************************************************
179  * MDIO driver code
180  **************************************************/
181
182 static 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
190 static 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
231 static 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
241 mdio_module_driver(bcm_ns_usb3_mdio_driver);
242
243 MODULE_LICENSE("GPL v2");
244 MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table);