blob: 6ac96ccf86269283d16138748336a5b4dd2b8ad8 [file] [log] [blame]
Hans de Goedea1441982015-01-07 15:08:43 +01001/*
Hans de Goede86979092015-04-27 14:54:47 +02002 * Sunxi usb-phy code
Hans de Goedea1441982015-01-07 15:08:43 +01003 *
Hans de Goede86979092015-04-27 14:54:47 +02004 * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
5 * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
Hans de Goedea1441982015-01-07 15:08:43 +01006 *
7 * Based on code from
8 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0+
11 */
12
Hans de Goede7e5aabd2015-04-27 11:44:22 +020013#include <common.h>
Hans de Goedea1441982015-01-07 15:08:43 +010014#include <asm/arch/clock.h>
15#include <asm/arch/cpu.h>
Hans de Goede26a90052015-04-27 15:05:10 +020016#include <asm/arch/usb_phy.h>
Hans de Goedea1441982015-01-07 15:08:43 +010017#include <asm/gpio.h>
18#include <asm/io.h>
Hans de Goede494f5d02015-04-22 17:39:59 +020019#include <errno.h>
Hans de Goedea1441982015-01-07 15:08:43 +010020
21#define SUNXI_USB_PMU_IRQ_ENABLE 0x800
Vishnu Patekar3702f142015-03-01 23:47:48 +053022#ifdef CONFIG_MACH_SUN8I_A33
23#define SUNXI_USB_CSR 0x410
24#else
Hans de Goedea1441982015-01-07 15:08:43 +010025#define SUNXI_USB_CSR 0x404
Vishnu Patekar3702f142015-03-01 23:47:48 +053026#endif
Hans de Goedea1441982015-01-07 15:08:43 +010027#define SUNXI_USB_PASSBY_EN 1
28
29#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
30#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
31#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
32#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
33
Jelle van der Waaa1f5d112016-02-09 23:59:33 +010034#define REG_PHY_UNK_H3 0x420
35#define REG_PMU_UNK_H3 0x810
36
Hans de Goede86979092015-04-27 14:54:47 +020037static struct sunxi_usb_phy {
Hans de Goedea1441982015-01-07 15:08:43 +010038 int usb_rst_mask;
Hans de Goedea1441982015-01-07 15:08:43 +010039 int gpio_vbus;
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +010040 int gpio_vbus_det;
Hans de Goedeaadd97f2015-06-14 17:29:53 +020041 int gpio_id_det;
Hans de Goedea1441982015-01-07 15:08:43 +010042 int id;
Hans de Goedee8204022015-04-27 16:57:54 +020043 int init_count;
44 int power_on_count;
Jelle van der Waaa1f5d112016-02-09 23:59:33 +010045 int base;
Hans de Goede86979092015-04-27 14:54:47 +020046} sunxi_usb_phy[] = {
Hans de Goedea1441982015-01-07 15:08:43 +010047 {
Hans de Goedee7b852a2015-01-07 15:26:06 +010048 .usb_rst_mask = CCM_USB_CTRL_PHY0_RST | CCM_USB_CTRL_PHY0_CLK,
Hans de Goedee7b852a2015-01-07 15:26:06 +010049 .id = 0,
Jelle van der Waaa1f5d112016-02-09 23:59:33 +010050 .base = SUNXI_USB0_BASE,
Hans de Goedee7b852a2015-01-07 15:26:06 +010051 },
52 {
Hans de Goedea1441982015-01-07 15:08:43 +010053 .usb_rst_mask = CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK,
Hans de Goedea1441982015-01-07 15:08:43 +010054 .id = 1,
Jelle van der Waaa1f5d112016-02-09 23:59:33 +010055 .base = SUNXI_USB1_BASE,
Hans de Goedea1441982015-01-07 15:08:43 +010056 },
Hans de Goede1168e092015-04-27 16:50:04 +020057#if CONFIG_SUNXI_USB_PHYS >= 3
Hans de Goedea1441982015-01-07 15:08:43 +010058 {
59 .usb_rst_mask = CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK,
Hans de Goedea1441982015-01-07 15:08:43 +010060 .id = 2,
Jelle van der Waaa1f5d112016-02-09 23:59:33 +010061 .base = SUNXI_USB2_BASE,
62 },
63#endif
64#if CONFIG_SUNXI_USB_PHYS >= 4
65 {
66 .usb_rst_mask = CCM_USB_CTRL_PHY3_RST | CCM_USB_CTRL_PHY3_CLK,
67 .id = 3,
68 .base = SUNXI_USB3_BASE,
Hans de Goedea1441982015-01-07 15:08:43 +010069 }
70#endif
71};
72
Hans de Goedea1441982015-01-07 15:08:43 +010073static int get_vbus_gpio(int index)
74{
75 switch (index) {
Hans de Goedee7b852a2015-01-07 15:26:06 +010076 case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN);
Hans de Goedea1441982015-01-07 15:08:43 +010077 case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN);
78 case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN);
79 }
Hans de Goede494f5d02015-04-22 17:39:59 +020080 return -EINVAL;
Hans de Goedea1441982015-01-07 15:08:43 +010081}
82
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +010083static int get_vbus_detect_gpio(int index)
84{
85 switch (index) {
86 case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_DET);
87 }
Hans de Goede494f5d02015-04-22 17:39:59 +020088 return -EINVAL;
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +010089}
90
Hans de Goedeaadd97f2015-06-14 17:29:53 +020091static int get_id_detect_gpio(int index)
92{
93 switch (index) {
94 case 0: return sunxi_name_to_gpio(CONFIG_USB0_ID_DET);
95 }
96 return -EINVAL;
97}
98
Hans de Goede86979092015-04-27 14:54:47 +020099static void usb_phy_write(struct sunxi_usb_phy *phy, int addr,
Hans de Goedea1441982015-01-07 15:08:43 +0100100 int data, int len)
101{
102 int j = 0, usbc_bit = 0;
Hans de Goede1f4e1d12015-04-27 14:36:23 +0200103 void *dest = (void *)SUNXI_USB0_BASE + SUNXI_USB_CSR;
Hans de Goedea1441982015-01-07 15:08:43 +0100104
Vishnu Patekar3702f142015-03-01 23:47:48 +0530105#ifdef CONFIG_MACH_SUN8I_A33
106 /* CSR needs to be explicitly initialized to 0 on A33 */
107 writel(0, dest);
108#endif
109
Hans de Goede86979092015-04-27 14:54:47 +0200110 usbc_bit = 1 << (phy->id * 2);
Hans de Goedea1441982015-01-07 15:08:43 +0100111 for (j = 0; j < len; j++) {
112 /* set the bit address to be written */
113 clrbits_le32(dest, 0xff << 8);
114 setbits_le32(dest, (addr + j) << 8);
115
116 clrbits_le32(dest, usbc_bit);
117 /* set data bit */
118 if (data & 0x1)
119 setbits_le32(dest, 1 << 7);
120 else
121 clrbits_le32(dest, 1 << 7);
122
123 setbits_le32(dest, usbc_bit);
124
125 clrbits_le32(dest, usbc_bit);
126
127 data >>= 1;
128 }
129}
130
Jelle van der Waaa1f5d112016-02-09 23:59:33 +0100131#if defined CONFIG_MACH_SUN8I_H3
132static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
133{
134 if (phy->id == 0)
135 clrbits_le32(SUNXI_USBPHY_BASE + REG_PHY_UNK_H3, 0x01);
136
137 clrbits_le32(phy->base + REG_PMU_UNK_H3, 0x02);
138}
139#else
Hans de Goede86979092015-04-27 14:54:47 +0200140static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
Hans de Goedea1441982015-01-07 15:08:43 +0100141{
142 /* The following comments are machine
143 * translated from Chinese, you have been warned!
144 */
145
Hans de Goedee7b852a2015-01-07 15:26:06 +0100146 /* Regulation 45 ohms */
Hans de Goede86979092015-04-27 14:54:47 +0200147 if (phy->id == 0)
148 usb_phy_write(phy, 0x0c, 0x01, 1);
Hans de Goedee7b852a2015-01-07 15:26:06 +0100149
Hans de Goedea1441982015-01-07 15:08:43 +0100150 /* adjust PHY's magnitude and rate */
Hans de Goede86979092015-04-27 14:54:47 +0200151 usb_phy_write(phy, 0x20, 0x14, 5);
Hans de Goedea1441982015-01-07 15:08:43 +0100152
153 /* threshold adjustment disconnect */
Hans de Goede9395a0e2015-05-31 19:26:54 +0200154#if defined CONFIG_MACH_SUN5I || defined CONFIG_MACH_SUN7I
Hans de Goede86979092015-04-27 14:54:47 +0200155 usb_phy_write(phy, 0x2a, 2, 2);
Hans de Goede9395a0e2015-05-31 19:26:54 +0200156#else
157 usb_phy_write(phy, 0x2a, 3, 2);
Hans de Goedea1441982015-01-07 15:08:43 +0100158#endif
159
160 return;
161}
Jelle van der Waaa1f5d112016-02-09 23:59:33 +0100162#endif
Hans de Goedea1441982015-01-07 15:08:43 +0100163
Jelle van der Waaa1f5d112016-02-09 23:59:33 +0100164static void sunxi_usb_phy_passby(struct sunxi_usb_phy *phy, int enable)
Hans de Goedea1441982015-01-07 15:08:43 +0100165{
166 unsigned long bits = 0;
Hans de Goede1f4e1d12015-04-27 14:36:23 +0200167 void *addr;
168
Jelle van der Waaa1f5d112016-02-09 23:59:33 +0100169 addr = (void *)phy->base + SUNXI_USB_PMU_IRQ_ENABLE;
Hans de Goedea1441982015-01-07 15:08:43 +0100170
171 bits = SUNXI_EHCI_AHB_ICHR8_EN |
172 SUNXI_EHCI_AHB_INCR4_BURST_EN |
173 SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
174 SUNXI_EHCI_ULPI_BYPASS_EN;
175
176 if (enable)
177 setbits_le32(addr, bits);
178 else
179 clrbits_le32(addr, bits);
180
181 return;
182}
183
Hans de Goede86979092015-04-27 14:54:47 +0200184void sunxi_usb_phy_enable_squelch_detect(int index, int enable)
Hans de Goedeab721ad2015-03-27 20:54:25 +0100185{
Hans de Goede86979092015-04-27 14:54:47 +0200186 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
Hans de Goedeab721ad2015-03-27 20:54:25 +0100187
Hans de Goede86979092015-04-27 14:54:47 +0200188 usb_phy_write(phy, 0x3c, enable ? 0 : 2, 2);
Hans de Goedeab721ad2015-03-27 20:54:25 +0100189}
190
Hans de Goede86979092015-04-27 14:54:47 +0200191void sunxi_usb_phy_init(int index)
Hans de Goedea1441982015-01-07 15:08:43 +0100192{
Hans de Goede86979092015-04-27 14:54:47 +0200193 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
Hans de Goedea1441982015-01-07 15:08:43 +0100194 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
195
Hans de Goedee8204022015-04-27 16:57:54 +0200196 phy->init_count++;
197 if (phy->init_count != 1)
198 return;
199
Hans de Goede86979092015-04-27 14:54:47 +0200200 setbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask);
Hans de Goedea1441982015-01-07 15:08:43 +0100201
Hans de Goede86979092015-04-27 14:54:47 +0200202 sunxi_usb_phy_config(phy);
Hans de Goedea1441982015-01-07 15:08:43 +0100203
Hans de Goede86979092015-04-27 14:54:47 +0200204 if (phy->id != 0)
Jelle van der Waaa1f5d112016-02-09 23:59:33 +0100205 sunxi_usb_phy_passby(phy, SUNXI_USB_PASSBY_EN);
Hans de Goedea1441982015-01-07 15:08:43 +0100206}
207
Hans de Goede86979092015-04-27 14:54:47 +0200208void sunxi_usb_phy_exit(int index)
Hans de Goedea1441982015-01-07 15:08:43 +0100209{
Hans de Goede86979092015-04-27 14:54:47 +0200210 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
Hans de Goedea1441982015-01-07 15:08:43 +0100211 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
212
Hans de Goedee8204022015-04-27 16:57:54 +0200213 phy->init_count--;
214 if (phy->init_count != 0)
215 return;
216
Hans de Goede86979092015-04-27 14:54:47 +0200217 if (phy->id != 0)
Jelle van der Waaa1f5d112016-02-09 23:59:33 +0100218 sunxi_usb_phy_passby(phy, !SUNXI_USB_PASSBY_EN);
Hans de Goedea1441982015-01-07 15:08:43 +0100219
Hans de Goede86979092015-04-27 14:54:47 +0200220 clrbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask);
Hans de Goedea1441982015-01-07 15:08:43 +0100221}
222
Hans de Goede86979092015-04-27 14:54:47 +0200223void sunxi_usb_phy_power_on(int index)
Hans de Goedea1441982015-01-07 15:08:43 +0100224{
Hans de Goede86979092015-04-27 14:54:47 +0200225 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
Hans de Goedea1441982015-01-07 15:08:43 +0100226
Hans de Goedee8204022015-04-27 16:57:54 +0200227 phy->power_on_count++;
228 if (phy->power_on_count != 1)
229 return;
230
Hans de Goede86979092015-04-27 14:54:47 +0200231 if (phy->gpio_vbus >= 0)
232 gpio_set_value(phy->gpio_vbus, 1);
Hans de Goedea1441982015-01-07 15:08:43 +0100233}
234
Hans de Goede86979092015-04-27 14:54:47 +0200235void sunxi_usb_phy_power_off(int index)
Hans de Goedea1441982015-01-07 15:08:43 +0100236{
Hans de Goede86979092015-04-27 14:54:47 +0200237 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
Hans de Goedea1441982015-01-07 15:08:43 +0100238
Hans de Goedee8204022015-04-27 16:57:54 +0200239 phy->power_on_count--;
240 if (phy->power_on_count != 0)
241 return;
242
Hans de Goede86979092015-04-27 14:54:47 +0200243 if (phy->gpio_vbus >= 0)
244 gpio_set_value(phy->gpio_vbus, 0);
Hans de Goedea1441982015-01-07 15:08:43 +0100245}
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +0100246
Hans de Goede39c119d2015-07-08 16:44:22 +0200247int sunxi_usb_phy_power_is_on(int index)
248{
249 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
250
251 return phy->power_on_count > 0;
252}
253
Hans de Goede86979092015-04-27 14:54:47 +0200254int sunxi_usb_phy_vbus_detect(int index)
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +0100255{
Hans de Goede86979092015-04-27 14:54:47 +0200256 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
Hans de Goede444af392015-03-27 21:46:00 +0100257 int err, retries = 3;
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +0100258
Hans de Goede78c2e642015-06-18 18:21:33 +0200259 if (phy->gpio_vbus_det < 0)
Hans de Goede86979092015-04-27 14:54:47 +0200260 return phy->gpio_vbus_det;
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +0100261
Hans de Goede86979092015-04-27 14:54:47 +0200262 err = gpio_get_value(phy->gpio_vbus_det);
Hans de Goede444af392015-03-27 21:46:00 +0100263 /*
264 * Vbus may have been provided by the board and just been turned of
265 * some milliseconds ago on reset, what we're measuring then is a
266 * residual charge on Vbus, sleep a bit and try again.
267 */
268 while (err > 0 && retries--) {
269 mdelay(100);
Hans de Goede86979092015-04-27 14:54:47 +0200270 err = gpio_get_value(phy->gpio_vbus_det);
Hans de Goede444af392015-03-27 21:46:00 +0100271 }
272
273 return err;
Paul Kocialkowski7e9b7de2015-03-22 18:07:12 +0100274}
Hans de Goede1168e092015-04-27 16:50:04 +0200275
Hans de Goedeaadd97f2015-06-14 17:29:53 +0200276int sunxi_usb_phy_id_detect(int index)
277{
278 struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
279
280 if (phy->gpio_id_det < 0)
281 return phy->gpio_id_det;
282
283 return gpio_get_value(phy->gpio_id_det);
284}
285
Hans de Goede1168e092015-04-27 16:50:04 +0200286int sunxi_usb_phy_probe(void)
287{
288 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
289 struct sunxi_usb_phy *phy;
290 int i, ret = 0;
291
292 for (i = 0; i < CONFIG_SUNXI_USB_PHYS; i++) {
293 phy = &sunxi_usb_phy[i];
294
295 phy->gpio_vbus = get_vbus_gpio(i);
296 if (phy->gpio_vbus >= 0) {
297 ret = gpio_request(phy->gpio_vbus, "usb_vbus");
298 if (ret)
299 return ret;
300 ret = gpio_direction_output(phy->gpio_vbus, 0);
301 if (ret)
302 return ret;
303 }
304
305 phy->gpio_vbus_det = get_vbus_detect_gpio(i);
306 if (phy->gpio_vbus_det >= 0) {
307 ret = gpio_request(phy->gpio_vbus_det, "usb_vbus_det");
308 if (ret)
309 return ret;
310 ret = gpio_direction_input(phy->gpio_vbus_det);
311 if (ret)
312 return ret;
313 }
Hans de Goedeaadd97f2015-06-14 17:29:53 +0200314
315 phy->gpio_id_det = get_id_detect_gpio(i);
316 if (phy->gpio_id_det >= 0) {
317 ret = gpio_request(phy->gpio_id_det, "usb_id_det");
318 if (ret)
319 return ret;
320 ret = gpio_direction_input(phy->gpio_id_det);
321 if (ret)
322 return ret;
323 sunxi_gpio_set_pull(phy->gpio_id_det,
324 SUNXI_GPIO_PULL_UP);
325 }
Hans de Goede1168e092015-04-27 16:50:04 +0200326 }
327
328 setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
329
330 return 0;
331}
332
333int sunxi_usb_phy_remove(void)
334{
335 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
336 struct sunxi_usb_phy *phy;
337 int i;
338
339 clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
340
341 for (i = 0; i < CONFIG_SUNXI_USB_PHYS; i++) {
342 phy = &sunxi_usb_phy[i];
343
344 if (phy->gpio_vbus >= 0)
345 gpio_free(phy->gpio_vbus);
346
347 if (phy->gpio_vbus_det >= 0)
348 gpio_free(phy->gpio_vbus_det);
Hans de Goedeaadd97f2015-06-14 17:29:53 +0200349
350 if (phy->gpio_id_det >= 0)
351 gpio_free(phy->gpio_id_det);
Hans de Goede1168e092015-04-27 16:50:04 +0200352 }
353
354 return 0;
355}