blob: 993f036b7877f9dfd77cbdafeb2950b94a2ce662 [file] [log] [blame]
Jagan Tekid3c38282018-05-07 13:03:26 +05301/*
2 * Allwinner sun4i USB PHY driver
3 *
4 * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
5 * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
6 * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
7 *
8 * Modelled arch/arm/mach-sunxi/usb_phy.c to compatible with generic-phy.
9 *
10 * SPDX-License-Identifier: GPL-2.0+
11 */
12
13#include <common.h>
14#include <dm.h>
15#include <dm/device.h>
16#include <generic-phy.h>
Jagan Teki21fc42d2018-05-07 13:03:27 +053017#include <phy-sun4i-usb.h>
Jagan Tekid3c38282018-05-07 13:03:26 +053018#include <asm/gpio.h>
19#include <asm/io.h>
20#include <asm/arch/clock.h>
21#include <asm/arch/cpu.h>
22
23#define REG_ISCR 0x00
24#define REG_PHYCTL_A10 0x04
25#define REG_PHYBIST 0x08
26#define REG_PHYTUNE 0x0c
27#define REG_PHYCTL_A33 0x10
28#define REG_PHY_OTGCTL 0x20
29#define REG_PMU_UNK1 0x10
30
31/* Common Control Bits for Both PHYs */
32#define PHY_PLL_BW 0x03
33#define PHY_RES45_CAL_EN 0x0c
34
35/* Private Control Bits for Each PHY */
36#define PHY_TX_AMPLITUDE_TUNE 0x20
37#define PHY_TX_SLEWRATE_TUNE 0x22
38#define PHY_DISCON_TH_SEL 0x2a
39
40#define PHYCTL_DATA BIT(7)
41#define OTGCTL_ROUTE_MUSB BIT(0)
42
43#define PHY_TX_RATE BIT(4)
44#define PHY_TX_MAGNITUDE BIT(2)
45#define PHY_TX_AMPLITUDE_LEN 5
46
47#define PHY_RES45_CAL_DATA BIT(0)
48#define PHY_RES45_CAL_LEN 1
49#define PHY_DISCON_TH_LEN 2
50
51#define SUNXI_AHB_ICHR8_EN BIT(10)
52#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
53#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
54#define SUNXI_ULPI_BYPASS_EN BIT(0)
55
56#define MAX_PHYS 4
57
58enum sun4i_usb_phy_type {
Jagan Tekic1b0e5a2018-05-07 13:03:28 +053059 sun8i_h3_phy,
Jagan Tekid3c38282018-05-07 13:03:26 +053060 sun50i_a64_phy,
61};
62
63struct sun4i_usb_phy_cfg {
64 int num_phys;
65 enum sun4i_usb_phy_type type;
66 u32 disc_thresh;
67 u8 phyctl_offset;
68 bool enable_pmu_unk1;
69 bool phy0_dual_route;
70};
71
72struct sun4i_usb_phy_info {
73 const char *gpio_vbus;
74 const char *gpio_vbus_det;
75 const char *gpio_id_det;
76 int rst_mask;
77} phy_info[] = {
78 {
79 .gpio_vbus = CONFIG_USB0_VBUS_PIN,
80 .gpio_vbus_det = CONFIG_USB0_VBUS_DET,
81 .gpio_id_det = CONFIG_USB0_ID_DET,
82 .rst_mask = (CCM_USB_CTRL_PHY0_RST | CCM_USB_CTRL_PHY0_CLK),
83 },
84 {
85 .gpio_vbus = CONFIG_USB1_VBUS_PIN,
86 .gpio_vbus_det = NULL,
87 .gpio_id_det = NULL,
88 .rst_mask = (CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK),
89 },
90 {
91 .gpio_vbus = CONFIG_USB2_VBUS_PIN,
92 .gpio_vbus_det = NULL,
93 .gpio_id_det = NULL,
94 .rst_mask = (CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK),
95 },
96 {
97 .gpio_vbus = CONFIG_USB3_VBUS_PIN,
98 .gpio_vbus_det = NULL,
99 .gpio_id_det = NULL,
100 .rst_mask = (CCM_USB_CTRL_PHY3_RST | CCM_USB_CTRL_PHY3_CLK),
101 },
102};
103
104struct sun4i_usb_phy_plat {
105 void __iomem *pmu;
106 int power_on_count;
107 int gpio_vbus;
108 int gpio_vbus_det;
109 int gpio_id_det;
110 int rst_mask;
111 int id;
112};
113
114struct sun4i_usb_phy_data {
115 void __iomem *base;
116 struct sunxi_ccm_reg *ccm;
117 const struct sun4i_usb_phy_cfg *cfg;
118 struct sun4i_usb_phy_plat *usb_phy;
119};
120
121static int initial_usb_scan_delay = CONFIG_INITIAL_USB_SCAN_DELAY;
122
123static void sun4i_usb_phy_write(struct phy *phy, u32 addr, u32 data, int len)
124{
125 struct sun4i_usb_phy_data *phy_data = dev_get_priv(phy->dev);
126 struct sun4i_usb_phy_plat *usb_phy = &phy_data->usb_phy[phy->id];
127 u32 temp, usbc_bit = BIT(usb_phy->id * 2);
128 void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset;
129 int i;
130
131 if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) {
132 /* SoCs newer than A33 need us to set phyctl to 0 explicitly */
133 writel(0, phyctl);
134 }
135
136 for (i = 0; i < len; i++) {
137 temp = readl(phyctl);
138
139 /* clear the address portion */
140 temp &= ~(0xff << 8);
141
142 /* set the address */
143 temp |= ((addr + i) << 8);
144 writel(temp, phyctl);
145
146 /* set the data bit and clear usbc bit*/
147 temp = readb(phyctl);
148 if (data & 0x1)
149 temp |= PHYCTL_DATA;
150 else
151 temp &= ~PHYCTL_DATA;
152 temp &= ~usbc_bit;
153 writeb(temp, phyctl);
154
155 /* pulse usbc_bit */
156 temp = readb(phyctl);
157 temp |= usbc_bit;
158 writeb(temp, phyctl);
159
160 temp = readb(phyctl);
161 temp &= ~usbc_bit;
162 writeb(temp, phyctl);
163
164 data >>= 1;
165 }
166}
167
168static void sun4i_usb_phy_passby(struct sun4i_usb_phy_plat *usb_phy,
169 bool enable)
170{
171 u32 bits, reg_value;
172
173 if (!usb_phy->pmu)
174 return;
175
176 bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
177 SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
178 reg_value = readl(usb_phy->pmu);
179
180 if (enable)
181 reg_value |= bits;
182 else
183 reg_value &= ~bits;
184
185 writel(reg_value, usb_phy->pmu);
186}
187
188static int sun4i_usb_phy_power_on(struct phy *phy)
189{
190 struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
191 struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
192
193 if (initial_usb_scan_delay) {
194 mdelay(initial_usb_scan_delay);
195 initial_usb_scan_delay = 0;
196 }
197
198 usb_phy->power_on_count++;
199 if (usb_phy->power_on_count != 1)
200 return 0;
201
202 if (usb_phy->gpio_vbus >= 0)
203 gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_UP);
204
205 return 0;
206}
207
208static int sun4i_usb_phy_power_off(struct phy *phy)
209{
210 struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
211 struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
212
213 usb_phy->power_on_count--;
214 if (usb_phy->power_on_count != 0)
215 return 0;
216
217 if (usb_phy->gpio_vbus >= 0)
218 gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_DISABLE);
219
220 return 0;
221}
222
223static void sun4i_usb_phy0_reroute(struct sun4i_usb_phy_data *data, bool id_det)
224{
225 u32 regval;
226
227 regval = readl(data->base + REG_PHY_OTGCTL);
228 if (!id_det) {
229 /* Host mode. Route phy0 to EHCI/OHCI */
230 regval &= ~OTGCTL_ROUTE_MUSB;
231 } else {
232 /* Peripheral mode. Route phy0 to MUSB */
233 regval |= OTGCTL_ROUTE_MUSB;
234 }
235 writel(regval, data->base + REG_PHY_OTGCTL);
236}
237
238static int sun4i_usb_phy_init(struct phy *phy)
239{
240 struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
241 struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
242 u32 val;
243
244 setbits_le32(&data->ccm->usb_clk_cfg, usb_phy->rst_mask);
245
246 if (usb_phy->pmu && data->cfg->enable_pmu_unk1) {
247 val = readl(usb_phy->pmu + REG_PMU_UNK1);
248 writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1);
249 }
250
251 if (usb_phy->id == 0)
252 sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, PHY_RES45_CAL_DATA,
253 PHY_RES45_CAL_LEN);
254
255 /* Adjust PHY's magnitude and rate */
256 sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, PHY_TX_MAGNITUDE |
257 PHY_TX_RATE, PHY_TX_AMPLITUDE_LEN);
258
259 /* Disconnect threshold adjustment */
260 sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->cfg->disc_thresh,
261 PHY_DISCON_TH_LEN);
262
263 if (usb_phy->id != 0)
264 sun4i_usb_phy_passby(usb_phy, true);
265
266 sun4i_usb_phy0_reroute(data, true);
267
268 return 0;
269}
270
271static int sun4i_usb_phy_exit(struct phy *phy)
272{
273 struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
274 struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
275
276 sun4i_usb_phy_passby(usb_phy, false);
277
278 clrbits_le32(&data->ccm->usb_clk_cfg, usb_phy->rst_mask);
279
280 return 0;
281}
282
283static int sun4i_usb_phy_xlate(struct phy *phy,
284 struct ofnode_phandle_args *args)
285{
286 struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
287
288 if (args->args_count >= data->cfg->num_phys)
289 return -EINVAL;
290
291 if (args->args_count)
292 phy->id = args->args[0];
293 else
294 phy->id = 0;
295
296 debug("%s: phy_id = %ld\n", __func__, phy->id);
297 return 0;
298}
299
Jagan Teki21fc42d2018-05-07 13:03:27 +0530300int sun4i_usb_phy_vbus_detect(struct phy *phy)
301{
302 struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
303 struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
304 int err, retries = 3;
305
306 debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
307
308 if (usb_phy->gpio_vbus_det < 0)
309 return usb_phy->gpio_vbus_det;
310
311 err = gpio_get_value(usb_phy->gpio_vbus_det);
312 /*
313 * Vbus may have been provided by the board and just been turned of
314 * some milliseconds ago on reset, what we're measuring then is a
315 * residual charge on Vbus, sleep a bit and try again.
316 */
317 while (err > 0 && retries--) {
318 mdelay(100);
319 err = gpio_get_value(usb_phy->gpio_vbus_det);
320 }
321
322 return err;
323}
324
325int sun4i_usb_phy_id_detect(struct phy *phy)
326{
327 struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
328 struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
329
330 debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
331
332 if (usb_phy->gpio_id_det < 0)
333 return usb_phy->gpio_id_det;
334
335 return gpio_get_value(usb_phy->gpio_id_det);
336}
337
Jagan Tekid3c38282018-05-07 13:03:26 +0530338static struct phy_ops sun4i_usb_phy_ops = {
339 .of_xlate = sun4i_usb_phy_xlate,
340 .init = sun4i_usb_phy_init,
341 .power_on = sun4i_usb_phy_power_on,
342 .power_off = sun4i_usb_phy_power_off,
343 .exit = sun4i_usb_phy_exit,
344};
345
346static int sun4i_usb_phy_probe(struct udevice *dev)
347{
348 struct sun4i_usb_phy_plat *plat = dev_get_platdata(dev);
349 struct sun4i_usb_phy_data *data = dev_get_priv(dev);
350 int i, ret;
351
352 data->cfg = (const struct sun4i_usb_phy_cfg *)dev_get_driver_data(dev);
353 if (!data->cfg)
354 return -EINVAL;
355
356 data->base = (void __iomem *)devfdt_get_addr_name(dev, "phy_ctrl");
357 if (IS_ERR(data->base))
358 return PTR_ERR(data->base);
359
360 data->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
361 if (IS_ERR(data->ccm))
362 return PTR_ERR(data->ccm);
363
364 data->usb_phy = plat;
365 for (i = 0; i < data->cfg->num_phys; i++) {
366 struct sun4i_usb_phy_plat *phy = &plat[i];
367 struct sun4i_usb_phy_info *info = &phy_info[i];
368 char name[16];
369
370 phy->gpio_vbus = sunxi_name_to_gpio(info->gpio_vbus);
371 if (phy->gpio_vbus >= 0) {
372 ret = gpio_request(phy->gpio_vbus, "usb_vbus");
373 if (ret)
374 return ret;
375 ret = gpio_direction_output(phy->gpio_vbus, 0);
376 if (ret)
377 return ret;
378 }
379
380 phy->gpio_vbus_det = sunxi_name_to_gpio(info->gpio_vbus_det);
381 if (phy->gpio_vbus_det >= 0) {
382 ret = gpio_request(phy->gpio_vbus_det, "usb_vbus_det");
383 if (ret)
384 return ret;
385 ret = gpio_direction_input(phy->gpio_vbus_det);
386 if (ret)
387 return ret;
388 }
389
390 phy->gpio_id_det = sunxi_name_to_gpio(info->gpio_id_det);
391 if (phy->gpio_id_det >= 0) {
392 ret = gpio_request(phy->gpio_id_det, "usb_id_det");
393 if (ret)
394 return ret;
395 ret = gpio_direction_input(phy->gpio_id_det);
396 if (ret)
397 return ret;
398 sunxi_gpio_set_pull(phy->gpio_id_det, SUNXI_GPIO_PULL_UP);
399 }
400
401 if (i || data->cfg->phy0_dual_route) {
402 snprintf(name, sizeof(name), "pmu%d", i);
403 phy->pmu = (void __iomem *)devfdt_get_addr_name(dev, name);
404 if (IS_ERR(phy->pmu))
405 return PTR_ERR(phy->pmu);
406 }
407
408 phy->id = i;
409 phy->rst_mask = info->rst_mask;
410 };
411
412 setbits_le32(&data->ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
413
414 debug("Allwinner Sun4I USB PHY driver loaded\n");
415 return 0;
416}
417
Jagan Tekic1b0e5a2018-05-07 13:03:28 +0530418static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
419 .num_phys = 4,
420 .type = sun8i_h3_phy,
421 .disc_thresh = 3,
422 .phyctl_offset = REG_PHYCTL_A33,
423 .enable_pmu_unk1 = true,
424 .phy0_dual_route = true,
425};
426
Jagan Tekid3c38282018-05-07 13:03:26 +0530427static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
428 .num_phys = 2,
429 .type = sun50i_a64_phy,
430 .disc_thresh = 3,
431 .phyctl_offset = REG_PHYCTL_A33,
432 .enable_pmu_unk1 = true,
433 .phy0_dual_route = true,
434};
435
436static const struct udevice_id sun4i_usb_phy_ids[] = {
Jagan Tekic1b0e5a2018-05-07 13:03:28 +0530437 { .compatible = "allwinner,sun8i-h3-usb-phy", .data = (ulong)&sun8i_h3_cfg },
Jagan Tekid3c38282018-05-07 13:03:26 +0530438 { .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg},
439 { }
440};
441
442U_BOOT_DRIVER(sun4i_usb_phy) = {
443 .name = "sun4i_usb_phy",
444 .id = UCLASS_PHY,
445 .of_match = sun4i_usb_phy_ids,
446 .ops = &sun4i_usb_phy_ops,
447 .probe = sun4i_usb_phy_probe,
448 .platdata_auto_alloc_size = sizeof(struct sun4i_usb_phy_plat[MAX_PHYS]),
449 .priv_auto_alloc_size = sizeof(struct sun4i_usb_phy_data),
450};