]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - drivers/usb/host/ehci-sunxi.c
Merge branch 'master' of git://git.denx.de/u-boot-sh
[karo-tx-uboot.git] / drivers / usb / host / ehci-sunxi.c
1 /*
2  * Copyright (C) 2014 Roman Byshko
3  *
4  * Roman Byshko <rbyshko@gmail.com>
5  *
6  * Based on code from
7  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
8  *
9  * SPDX-License-Identifier:     GPL-2.0+
10  */
11
12 #include <asm/arch/clock.h>
13 #include <asm/arch/cpu.h>
14 #include <asm/gpio.h>
15 #include <asm/io.h>
16 #include <common.h>
17 #include "ehci.h"
18
19 #define SUNXI_USB_PMU_IRQ_ENABLE        0x800
20 #define SUNXI_USB_CSR                   0x404
21 #define SUNXI_USB_PASSBY_EN             1
22
23 #define SUNXI_EHCI_AHB_ICHR8_EN         (1 << 10)
24 #define SUNXI_EHCI_AHB_INCR4_BURST_EN   (1 << 9)
25 #define SUNXI_EHCI_AHB_INCRX_ALIGN_EN   (1 << 8)
26 #define SUNXI_EHCI_ULPI_BYPASS_EN       (1 << 0)
27
28 static struct sunxi_ehci_hcd {
29         struct usb_hcd *hcd;
30         int usb_rst_mask;
31         int ahb_clk_mask;
32         int gpio_vbus;
33         int irq;
34         int id;
35 } sunxi_echi_hcd[] = {
36         {
37                 .usb_rst_mask = CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK,
38                 .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
39 #ifndef CONFIG_MACH_SUN6I
40                 .irq = 39,
41 #else
42                 .irq = 72,
43 #endif
44                 .id = 1,
45         },
46 #if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1)
47         {
48                 .usb_rst_mask = CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK,
49                 .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1,
50 #ifndef CONFIG_MACH_SUN6I
51                 .irq = 40,
52 #else
53                 .irq = 74,
54 #endif
55                 .id = 2,
56         }
57 #endif
58 };
59
60 static int enabled_hcd_count;
61
62 static void *get_io_base(int hcd_id)
63 {
64         switch (hcd_id) {
65         case 0:
66                 return (void *)SUNXI_USB0_BASE;
67         case 1:
68                 return (void *)SUNXI_USB1_BASE;
69         case 2:
70                 return (void *)SUNXI_USB2_BASE;
71         default:
72                 return NULL;
73         }
74 }
75
76 static int get_vbus_gpio(int hcd_id)
77 {
78         switch (hcd_id) {
79         case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN);
80         case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN);
81         }
82         return -1;
83 }
84
85 static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci, int addr,
86                           int data, int len)
87 {
88         int j = 0, usbc_bit = 0;
89         void *dest = get_io_base(0) + SUNXI_USB_CSR;
90
91         usbc_bit = 1 << (sunxi_ehci->id * 2);
92         for (j = 0; j < len; j++) {
93                 /* set the bit address to be written */
94                 clrbits_le32(dest, 0xff << 8);
95                 setbits_le32(dest, (addr + j) << 8);
96
97                 clrbits_le32(dest, usbc_bit);
98                 /* set data bit */
99                 if (data & 0x1)
100                         setbits_le32(dest, 1 << 7);
101                 else
102                         clrbits_le32(dest, 1 << 7);
103
104                 setbits_le32(dest, usbc_bit);
105
106                 clrbits_le32(dest, usbc_bit);
107
108                 data >>= 1;
109         }
110 }
111
112 static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci)
113 {
114         /* The following comments are machine
115          * translated from Chinese, you have been warned!
116          */
117
118         /* adjust PHY's magnitude and rate */
119         usb_phy_write(sunxi_ehci, 0x20, 0x14, 5);
120
121         /* threshold adjustment disconnect */
122 #if defined CONFIG_MACH_SUN4I || defined CONFIG_MACH_SUN6I
123         usb_phy_write(sunxi_ehci, 0x2a, 3, 2);
124 #else
125         usb_phy_write(sunxi_ehci, 0x2a, 2, 2);
126 #endif
127
128         return;
129 }
130
131 static void sunxi_usb_passby(struct sunxi_ehci_hcd *sunxi_ehci, int enable)
132 {
133         unsigned long bits = 0;
134         void *addr = get_io_base(sunxi_ehci->id) + SUNXI_USB_PMU_IRQ_ENABLE;
135
136         bits = SUNXI_EHCI_AHB_ICHR8_EN |
137                 SUNXI_EHCI_AHB_INCR4_BURST_EN |
138                 SUNXI_EHCI_AHB_INCRX_ALIGN_EN |
139                 SUNXI_EHCI_ULPI_BYPASS_EN;
140
141         if (enable)
142                 setbits_le32(addr, bits);
143         else
144                 clrbits_le32(addr, bits);
145
146         return;
147 }
148
149 static void sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci)
150 {
151         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
152
153         setbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
154         setbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
155 #ifdef CONFIG_MACH_SUN6I
156         setbits_le32(&ccm->ahb_reset0_cfg, sunxi_ehci->ahb_clk_mask);
157 #endif
158
159         sunxi_usb_phy_init(sunxi_ehci);
160
161         sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN);
162
163         if (sunxi_ehci->gpio_vbus != -1)
164                 gpio_direction_output(sunxi_ehci->gpio_vbus, 1);
165 }
166
167 static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci)
168 {
169         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
170
171         if (sunxi_ehci->gpio_vbus != -1)
172                 gpio_direction_output(sunxi_ehci->gpio_vbus, 0);
173
174         sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN);
175
176 #ifdef CONFIG_MACH_SUN6I
177         clrbits_le32(&ccm->ahb_reset0_cfg, sunxi_ehci->ahb_clk_mask);
178 #endif
179         clrbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask);
180         clrbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask);
181 }
182
183 int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
184                 struct ehci_hcor **hcor)
185 {
186         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
187         struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
188         int err;
189
190         sunxi_ehci->gpio_vbus = get_vbus_gpio(sunxi_ehci->id);
191
192         /* enable common PHY only once */
193         if (index == 0)
194                 setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
195
196         if (sunxi_ehci->gpio_vbus != -1) {
197                 err = gpio_request(sunxi_ehci->gpio_vbus, "ehci_vbus");
198                 if (err)
199                         return err;
200         }
201
202         sunxi_ehci_enable(sunxi_ehci);
203
204         *hccr = get_io_base(sunxi_ehci->id);
205
206         *hcor = (struct ehci_hcor *)((uint32_t) *hccr
207                                 + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
208
209         debug("sunxi-ehci: init hccr %x and hcor %x hc_length %d\n",
210               (uint32_t)*hccr, (uint32_t)*hcor,
211               (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
212
213         enabled_hcd_count++;
214
215         return 0;
216 }
217
218 int ehci_hcd_stop(int index)
219 {
220         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
221         struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
222         int err;
223
224         sunxi_ehci_disable(sunxi_ehci);
225
226         if (sunxi_ehci->gpio_vbus != -1) {
227                 err = gpio_free(sunxi_ehci->gpio_vbus);
228                 if (err)
229                         return err;
230         }
231
232         /* disable common PHY only once, for the last enabled hcd */
233         if (enabled_hcd_count == 1)
234                 clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
235
236         enabled_hcd_count--;
237
238         return 0;
239 }