]> git.sur5r.net Git - u-boot/blob - arch/arm/cpu/armv7/sunxi/usb_phy.c
sunxi: Print soc-id from sram controller for sun8i boards
[u-boot] / arch / arm / cpu / armv7 / sunxi / usb_phy.c
1 /*
2  * Sunxi usb-phy code
3  *
4  * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
5  * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
6  *
7  * Based on code from
8  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
9  *
10  * SPDX-License-Identifier:     GPL-2.0+
11  */
12
13 #include <common.h>
14 #include <asm/arch/clock.h>
15 #include <asm/arch/cpu.h>
16 #include <asm/arch/usb_phy.h>
17 #include <asm/gpio.h>
18 #include <asm/io.h>
19 #include <errno.h>
20
21 #define SUNXI_USB_PMU_IRQ_ENABLE        0x800
22 #ifdef CONFIG_MACH_SUN8I_A33
23 #define SUNXI_USB_CSR                   0x410
24 #else
25 #define SUNXI_USB_CSR                   0x404
26 #endif
27 #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
34 #define REG_PHY_UNK_H3                  0x420
35 #define REG_PMU_UNK_H3                  0x810
36
37 static struct sunxi_usb_phy {
38         int usb_rst_mask;
39         int gpio_vbus;
40         int gpio_vbus_det;
41         int gpio_id_det;
42         int id;
43         int init_count;
44         int power_on_count;
45         int base;
46 } sunxi_usb_phy[] = {
47         {
48                 .usb_rst_mask = CCM_USB_CTRL_PHY0_RST | CCM_USB_CTRL_PHY0_CLK,
49                 .id = 0,
50                 .base = SUNXI_USB0_BASE,
51         },
52         {
53                 .usb_rst_mask = CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK,
54                 .id = 1,
55                 .base = SUNXI_USB1_BASE,
56         },
57 #if CONFIG_SUNXI_USB_PHYS >= 3
58         {
59                 .usb_rst_mask = CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK,
60                 .id = 2,
61                 .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,
69         }
70 #endif
71 };
72
73 static int get_vbus_gpio(int index)
74 {
75         switch (index) {
76         case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN);
77         case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN);
78         case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN);
79         case 3: return sunxi_name_to_gpio(CONFIG_USB3_VBUS_PIN);
80         }
81         return -EINVAL;
82 }
83
84 static int get_vbus_detect_gpio(int index)
85 {
86         switch (index) {
87         case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_DET);
88         }
89         return -EINVAL;
90 }
91
92 static int get_id_detect_gpio(int index)
93 {
94         switch (index) {
95         case 0: return sunxi_name_to_gpio(CONFIG_USB0_ID_DET);
96         }
97         return -EINVAL;
98 }
99
100 static void usb_phy_write(struct sunxi_usb_phy *phy, int addr,
101                           int data, int len)
102 {
103         int j = 0, usbc_bit = 0;
104         void *dest = (void *)SUNXI_USB0_BASE + SUNXI_USB_CSR;
105
106 #ifdef CONFIG_MACH_SUN8I_A33
107         /* CSR needs to be explicitly initialized to 0 on A33 */
108         writel(0, dest);
109 #endif
110
111         usbc_bit = 1 << (phy->id * 2);
112         for (j = 0; j < len; j++) {
113                 /* set the bit address to be written */
114                 clrbits_le32(dest, 0xff << 8);
115                 setbits_le32(dest, (addr + j) << 8);
116
117                 clrbits_le32(dest, usbc_bit);
118                 /* set data bit */
119                 if (data & 0x1)
120                         setbits_le32(dest, 1 << 7);
121                 else
122                         clrbits_le32(dest, 1 << 7);
123
124                 setbits_le32(dest, usbc_bit);
125
126                 clrbits_le32(dest, usbc_bit);
127
128                 data >>= 1;
129         }
130 }
131
132 #if defined CONFIG_MACH_SUN8I_H3
133 static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
134 {
135         if (phy->id == 0)
136                 clrbits_le32(SUNXI_USBPHY_BASE + REG_PHY_UNK_H3, 0x01);
137
138         clrbits_le32(phy->base + REG_PMU_UNK_H3, 0x02);
139 }
140 #else
141 static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy)
142 {
143         /* The following comments are machine
144          * translated from Chinese, you have been warned!
145          */
146
147         /* Regulation 45 ohms */
148         if (phy->id == 0)
149                 usb_phy_write(phy, 0x0c, 0x01, 1);
150
151         /* adjust PHY's magnitude and rate */
152         usb_phy_write(phy, 0x20, 0x14, 5);
153
154         /* threshold adjustment disconnect */
155 #if defined CONFIG_MACH_SUN5I || defined CONFIG_MACH_SUN7I
156         usb_phy_write(phy, 0x2a, 2, 2);
157 #else
158         usb_phy_write(phy, 0x2a, 3, 2);
159 #endif
160
161         return;
162 }
163 #endif
164
165 static void sunxi_usb_phy_passby(struct sunxi_usb_phy *phy, int enable)
166 {
167         unsigned long bits = 0;
168         void *addr;
169
170         addr = (void *)phy->base + SUNXI_USB_PMU_IRQ_ENABLE;
171
172         bits = SUNXI_EHCI_AHB_ICHR8_EN |
173                 SUNXI_EHCI_AHB_INCR4_BURST_EN |
174                 SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
175                 SUNXI_EHCI_ULPI_BYPASS_EN;
176
177         if (enable)
178                 setbits_le32(addr, bits);
179         else
180                 clrbits_le32(addr, bits);
181
182         return;
183 }
184
185 void sunxi_usb_phy_enable_squelch_detect(int index, int enable)
186 {
187         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
188
189         usb_phy_write(phy, 0x3c, enable ? 0 : 2, 2);
190 }
191
192 void sunxi_usb_phy_init(int index)
193 {
194         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
195         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
196
197         phy->init_count++;
198         if (phy->init_count != 1)
199                 return;
200
201         setbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask);
202
203         sunxi_usb_phy_config(phy);
204
205         if (phy->id != 0)
206                 sunxi_usb_phy_passby(phy, SUNXI_USB_PASSBY_EN);
207 }
208
209 void sunxi_usb_phy_exit(int index)
210 {
211         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
212         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
213
214         phy->init_count--;
215         if (phy->init_count != 0)
216                 return;
217
218         if (phy->id != 0)
219                 sunxi_usb_phy_passby(phy, !SUNXI_USB_PASSBY_EN);
220
221         clrbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask);
222 }
223
224 void sunxi_usb_phy_power_on(int index)
225 {
226         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
227
228         phy->power_on_count++;
229         if (phy->power_on_count != 1)
230                 return;
231
232         if (phy->gpio_vbus >= 0)
233                 gpio_set_value(phy->gpio_vbus, 1);
234 }
235
236 void sunxi_usb_phy_power_off(int index)
237 {
238         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
239
240         phy->power_on_count--;
241         if (phy->power_on_count != 0)
242                 return;
243
244         if (phy->gpio_vbus >= 0)
245                 gpio_set_value(phy->gpio_vbus, 0);
246 }
247
248 int sunxi_usb_phy_power_is_on(int index)
249 {
250         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
251
252         return phy->power_on_count > 0;
253 }
254
255 int sunxi_usb_phy_vbus_detect(int index)
256 {
257         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
258         int err, retries = 3;
259
260         if (phy->gpio_vbus_det < 0)
261                 return phy->gpio_vbus_det;
262
263         err = gpio_get_value(phy->gpio_vbus_det);
264         /*
265          * Vbus may have been provided by the board and just been turned of
266          * some milliseconds ago on reset, what we're measuring then is a
267          * residual charge on Vbus, sleep a bit and try again.
268          */
269         while (err > 0 && retries--) {
270                 mdelay(100);
271                 err = gpio_get_value(phy->gpio_vbus_det);
272         }
273
274         return err;
275 }
276
277 int sunxi_usb_phy_id_detect(int index)
278 {
279         struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
280
281         if (phy->gpio_id_det < 0)
282                 return phy->gpio_id_det;
283
284         return gpio_get_value(phy->gpio_id_det);
285 }
286
287 int sunxi_usb_phy_probe(void)
288 {
289         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
290         struct sunxi_usb_phy *phy;
291         int i, ret = 0;
292
293         for (i = 0; i < CONFIG_SUNXI_USB_PHYS; i++) {
294                 phy = &sunxi_usb_phy[i];
295
296                 phy->gpio_vbus = get_vbus_gpio(i);
297                 if (phy->gpio_vbus >= 0) {
298                         ret = gpio_request(phy->gpio_vbus, "usb_vbus");
299                         if (ret)
300                                 return ret;
301                         ret = gpio_direction_output(phy->gpio_vbus, 0);
302                         if (ret)
303                                 return ret;
304                 }
305
306                 phy->gpio_vbus_det = get_vbus_detect_gpio(i);
307                 if (phy->gpio_vbus_det >= 0) {
308                         ret = gpio_request(phy->gpio_vbus_det, "usb_vbus_det");
309                         if (ret)
310                                 return ret;
311                         ret = gpio_direction_input(phy->gpio_vbus_det);
312                         if (ret)
313                                 return ret;
314                 }
315
316                 phy->gpio_id_det = get_id_detect_gpio(i);
317                 if (phy->gpio_id_det >= 0) {
318                         ret = gpio_request(phy->gpio_id_det, "usb_id_det");
319                         if (ret)
320                                 return ret;
321                         ret = gpio_direction_input(phy->gpio_id_det);
322                         if (ret)
323                                 return ret;
324                         sunxi_gpio_set_pull(phy->gpio_id_det,
325                                             SUNXI_GPIO_PULL_UP);
326                 }
327         }
328
329         setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
330
331         return 0;
332 }
333
334 int sunxi_usb_phy_remove(void)
335 {
336         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
337         struct sunxi_usb_phy *phy;
338         int i;
339
340         clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
341
342         for (i = 0; i < CONFIG_SUNXI_USB_PHYS; i++) {
343                 phy = &sunxi_usb_phy[i];
344
345                 if (phy->gpio_vbus >= 0)
346                         gpio_free(phy->gpio_vbus);
347
348                 if (phy->gpio_vbus_det >= 0)
349                         gpio_free(phy->gpio_vbus_det);
350
351                 if (phy->gpio_id_det >= 0)
352                         gpio_free(phy->gpio_id_det);
353         }
354
355         return 0;
356 }