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 } 240