]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/sunxi/usbc.c
7b883fbcec0c7beb11c5a4fd741b64503d5f9711
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / sunxi / usbc.c
1 /*
2  * Sunxi usb-controller code shared between the ehci and musb controllers
3  *
4  * Copyright (C) 2014 Roman Byshko
5  *
6  * Roman Byshko <rbyshko@gmail.com>
7  *
8  * Based on code from
9  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
10  *
11  * SPDX-License-Identifier:     GPL-2.0+
12  */
13
14 #include <asm/arch/clock.h>
15 #include <asm/arch/cpu.h>
16 #include <asm/arch/usbc.h>
17 #include <asm/gpio.h>
18 #include <asm/io.h>
19 #include <common.h>
20 #ifdef CONFIG_AXP152_POWER
21 #include <axp152.h>
22 #endif
23 #ifdef CONFIG_AXP209_POWER
24 #include <axp209.h>
25 #endif
26 #ifdef CONFIG_AXP221_POWER
27 #include <axp221.h>
28 #endif
29
30 #define SUNXI_USB_PMU_IRQ_ENABLE        0x800
31 #ifdef CONFIG_MACH_SUN8I_A33
32 #define SUNXI_USB_CSR                   0x410
33 #else
34 #define SUNXI_USB_CSR                   0x404
35 #endif
36 #define SUNXI_USB_PASSBY_EN             1
37
38 #define SUNXI_EHCI_AHB_ICHR8_EN         (1 << 10)
39 #define SUNXI_EHCI_AHB_INCR4_BURST_EN   (1 << 9)
40 #define SUNXI_EHCI_AHB_INCRX_ALIGN_EN   (1 << 8)
41 #define SUNXI_EHCI_ULPI_BYPASS_EN       (1 << 0)
42
43 static struct sunxi_usbc_hcd {
44         struct usb_hcd *hcd;
45         int usb_rst_mask;
46         int ahb_clk_mask;
47         int gpio_vbus;
48         int gpio_vbus_det;
49         int id;
50 } sunxi_usbc_hcd[] = {
51         {
52                 .usb_rst_mask = CCM_USB_CTRL_PHY0_RST | CCM_USB_CTRL_PHY0_CLK,
53                 .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB0,
54                 .id = 0,
55         },
56         {
57                 .usb_rst_mask = CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK,
58                 .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
59                 .id = 1,
60         },
61 #if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1)
62         {
63                 .usb_rst_mask = CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK,
64                 .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1,
65                 .id = 2,
66         }
67 #endif
68 };
69
70 static int enabled_hcd_count;
71
72 void *sunxi_usbc_get_io_base(int index)
73 {
74         switch (index) {
75         case 0:
76                 return (void *)SUNXI_USB0_BASE;
77         case 1:
78                 return (void *)SUNXI_USB1_BASE;
79         case 2:
80                 return (void *)SUNXI_USB2_BASE;
81         default:
82                 return NULL;
83         }
84 }
85
86 static int get_vbus_gpio(int index)
87 {
88         switch (index) {
89         case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN);
90         case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN);
91         case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN);
92         }
93         return -1;
94 }
95
96 static int get_vbus_detect_gpio(int index)
97 {
98         switch (index) {
99         case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_DET);
100         }
101         return -1;
102 }
103
104 static void usb_phy_write(struct sunxi_usbc_hcd *sunxi_usbc, int addr,
105                           int data, int len)
106 {
107         int j = 0, usbc_bit = 0;
108         void *dest = sunxi_usbc_get_io_base(0) + SUNXI_USB_CSR;
109
110 #ifdef CONFIG_MACH_SUN8I_A33
111         /* CSR needs to be explicitly initialized to 0 on A33 */
112         writel(0, dest);
113 #endif
114
115         usbc_bit = 1 << (sunxi_usbc->id * 2);
116         for (j = 0; j < len; j++) {
117                 /* set the bit address to be written */
118                 clrbits_le32(dest, 0xff << 8);
119                 setbits_le32(dest, (addr + j) << 8);
120
121                 clrbits_le32(dest, usbc_bit);
122                 /* set data bit */
123                 if (data & 0x1)
124                         setbits_le32(dest, 1 << 7);
125                 else
126                         clrbits_le32(dest, 1 << 7);
127
128                 setbits_le32(dest, usbc_bit);
129
130                 clrbits_le32(dest, usbc_bit);
131
132                 data >>= 1;
133         }
134 }
135
136 static void sunxi_usb_phy_init(struct sunxi_usbc_hcd *sunxi_usbc)
137 {
138         /* The following comments are machine
139          * translated from Chinese, you have been warned!
140          */
141
142         /* Regulation 45 ohms */
143         if (sunxi_usbc->id == 0)
144                 usb_phy_write(sunxi_usbc, 0x0c, 0x01, 1);
145
146         /* adjust PHY's magnitude and rate */
147         usb_phy_write(sunxi_usbc, 0x20, 0x14, 5);
148
149         /* threshold adjustment disconnect */
150 #if defined CONFIG_MACH_SUN4I || defined CONFIG_MACH_SUN6I
151         usb_phy_write(sunxi_usbc, 0x2a, 3, 2);
152 #else
153         usb_phy_write(sunxi_usbc, 0x2a, 2, 2);
154 #endif
155
156         return;
157 }
158
159 static void sunxi_usb_passby(struct sunxi_usbc_hcd *sunxi_usbc, int enable)
160 {
161         unsigned long bits = 0;
162         void *addr = sunxi_usbc_get_io_base(sunxi_usbc->id) +
163                      SUNXI_USB_PMU_IRQ_ENABLE;
164
165         bits = SUNXI_EHCI_AHB_ICHR8_EN |
166                 SUNXI_EHCI_AHB_INCR4_BURST_EN |
167                 SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
168                 SUNXI_EHCI_ULPI_BYPASS_EN;
169
170         if (enable)
171                 setbits_le32(addr, bits);
172         else
173                 clrbits_le32(addr, bits);
174
175         return;
176 }
177
178 void sunxi_usbc_enable_squelch_detect(int index, int enable)
179 {
180         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
181
182         usb_phy_write(sunxi_usbc, 0x3c, enable ? 0 : 2, 2);
183 }
184
185 int sunxi_usbc_request_resources(int index)
186 {
187         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
188         int ret = 0;
189
190         sunxi_usbc->gpio_vbus = get_vbus_gpio(index);
191         if (sunxi_usbc->gpio_vbus != -1) {
192                 ret |= gpio_request(sunxi_usbc->gpio_vbus, "usbc_vbus");
193                 ret |= gpio_direction_output(sunxi_usbc->gpio_vbus, 0);
194         }
195
196         sunxi_usbc->gpio_vbus_det = get_vbus_detect_gpio(index);
197         if (sunxi_usbc->gpio_vbus_det != -1) {
198                 ret |= gpio_request(sunxi_usbc->gpio_vbus_det, "usbc_vbus_det");
199                 ret |= gpio_direction_input(sunxi_usbc->gpio_vbus_det);
200         }
201
202         return ret;
203 }
204
205 int sunxi_usbc_free_resources(int index)
206 {
207         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
208         int ret = 0;
209
210         if (sunxi_usbc->gpio_vbus != -1)
211                 ret |= gpio_free(sunxi_usbc->gpio_vbus);
212
213         if (sunxi_usbc->gpio_vbus_det != -1)
214                 ret |= gpio_free(sunxi_usbc->gpio_vbus_det);
215
216         return ret;
217 }
218
219 void sunxi_usbc_enable(int index)
220 {
221         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
222         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
223
224         /* enable common PHY only once */
225         if (enabled_hcd_count == 0)
226                 setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
227
228         setbits_le32(&ccm->usb_clk_cfg, sunxi_usbc->usb_rst_mask);
229         setbits_le32(&ccm->ahb_gate0, sunxi_usbc->ahb_clk_mask);
230 #ifdef CONFIG_SUNXI_GEN_SUN6I
231         setbits_le32(&ccm->ahb_reset0_cfg, sunxi_usbc->ahb_clk_mask);
232 #endif
233
234         sunxi_usb_phy_init(sunxi_usbc);
235
236         if (sunxi_usbc->id != 0)
237                 sunxi_usb_passby(sunxi_usbc, SUNXI_USB_PASSBY_EN);
238
239         enabled_hcd_count++;
240 }
241
242 void sunxi_usbc_disable(int index)
243 {
244         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
245         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
246
247         if (sunxi_usbc->id != 0)
248                 sunxi_usb_passby(sunxi_usbc, !SUNXI_USB_PASSBY_EN);
249
250 #ifdef CONFIG_SUNXI_GEN_SUN6I
251         clrbits_le32(&ccm->ahb_reset0_cfg, sunxi_usbc->ahb_clk_mask);
252 #endif
253         clrbits_le32(&ccm->ahb_gate0, sunxi_usbc->ahb_clk_mask);
254         clrbits_le32(&ccm->usb_clk_cfg, sunxi_usbc->usb_rst_mask);
255
256         /* disable common PHY only once, for the last enabled hcd */
257         if (enabled_hcd_count == 1)
258                 clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
259
260         enabled_hcd_count--;
261 }
262
263 void sunxi_usbc_vbus_enable(int index)
264 {
265         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
266
267         if (sunxi_usbc->gpio_vbus != -1)
268                 gpio_set_value(sunxi_usbc->gpio_vbus, 1);
269 }
270
271 void sunxi_usbc_vbus_disable(int index)
272 {
273         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
274
275         if (sunxi_usbc->gpio_vbus != -1)
276                 gpio_set_value(sunxi_usbc->gpio_vbus, 0);
277 }
278
279 int sunxi_usbc_vbus_detect(int index)
280 {
281         struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
282         int err, retries = 3;
283
284         if (sunxi_usbc->gpio_vbus_det == -1) {
285                 eprintf("Error: invalid vbus detection pin\n");
286                 return -1;
287         }
288
289         err = gpio_get_value(sunxi_usbc->gpio_vbus_det);
290         /*
291          * Vbus may have been provided by the board and just been turned of
292          * some milliseconds ago on reset, what we're measuring then is a
293          * residual charge on Vbus, sleep a bit and try again.
294          */
295         while (err > 0 && retries--) {
296                 mdelay(100);
297                 err = gpio_get_value(sunxi_usbc->gpio_vbus_det);
298         }
299
300         return err;
301 }