1 /* mbed USBHost Library
2 * Copyright (c) 2006-2013 ARM Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #if defined(TARGET_RZ_A1H)
20 #include "USBHALHost.h"
23 #include "ohci_wrapp_RZ_A1.h"
26 #define HCCA_SIZE sizeof(HCCA)
27 #define ED_SIZE sizeof(HCED)
28 #define TD_SIZE sizeof(HCTD)
30 #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
31 #define ALIGNE_MSK (0x0000000F)
33 static volatile uint8_t usb_buf[TOTAL_SIZE + ALIGNE_MSK]; //16 bytes aligned!
35 USBHALHost * USBHALHost::instHost;
37 USBHALHost::USBHALHost() {
40 memset((void*)usb_hcca, 0, HCCA_SIZE);
41 for (int i = 0; i < MAX_ENDPOINT; i++) {
42 edBufAlloc[i] = false;
44 for (int i = 0; i < MAX_TD; i++) {
45 tdBufAlloc[i] = false;
49 void USBHALHost::init() {
50 ohciwrapp_init(&_usbisr);
52 ohciwrapp_reg_w(OHCI_REG_CONTROL, 1); // HARDWARE RESET
53 ohciwrapp_reg_w(OHCI_REG_CONTROLHEADED, 0); // Initialize Control list head to Zero
54 ohciwrapp_reg_w(OHCI_REG_BULKHEADED, 0); // Initialize Bulk list head to Zero
56 // Wait 100 ms before apply reset
60 ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_HCR);
62 // Write Fm Interval and Largest Data Packet Counter
63 ohciwrapp_reg_w(OHCI_REG_FMINTERVAL, DEFAULT_FMINTERVAL);
64 ohciwrapp_reg_w(OHCI_REG_PERIODICSTART, FI * 90 / 100);
66 // Put HC in operational state
67 ohciwrapp_reg_w(OHCI_REG_CONTROL, (ohciwrapp_reg_r(OHCI_REG_CONTROL) & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER);
69 ohciwrapp_reg_w(OHCI_REG_RHSTATUS, OR_RH_STATUS_LPSC);
71 ohciwrapp_reg_w(OHCI_REG_HCCA, (uint32_t)(usb_hcca));
73 // Clear Interrrupt Status
74 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS));
76 ohciwrapp_reg_w(OHCI_REG_INTERRUPTENABLE, OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC);
78 // Enable the USB Interrupt
79 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_CSC);
80 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
82 // Check for any connected devices
83 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
86 USB_DBG("Device connected (%08x)\n\r", ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1));
87 deviceConnected(0, 1, ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_LSDA);
91 uint32_t USBHALHost::controlHeadED() {
92 return ohciwrapp_reg_r(OHCI_REG_CONTROLHEADED);
95 uint32_t USBHALHost::bulkHeadED() {
96 return ohciwrapp_reg_r(OHCI_REG_BULKHEADED);
99 uint32_t USBHALHost::interruptHeadED() {
100 return usb_hcca->IntTable[0];
103 void USBHALHost::updateBulkHeadED(uint32_t addr) {
104 ohciwrapp_reg_w(OHCI_REG_BULKHEADED, addr);
108 void USBHALHost::updateControlHeadED(uint32_t addr) {
109 ohciwrapp_reg_w(OHCI_REG_CONTROLHEADED, addr);
112 void USBHALHost::updateInterruptHeadED(uint32_t addr) {
113 usb_hcca->IntTable[0] = addr;
117 void USBHALHost::enableList(ENDPOINT_TYPE type) {
121 case CONTROL_ENDPOINT:
122 ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_CLF);
123 wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_CLE);
124 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
126 case ISOCHRONOUS_ENDPOINT:
129 ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_BLF);
130 wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_BLE);
131 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
133 case INTERRUPT_ENDPOINT:
134 wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_PLE);
135 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
141 bool USBHALHost::disableList(ENDPOINT_TYPE type) {
145 case CONTROL_ENDPOINT:
146 wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
147 if(wk_data & OR_CONTROL_CLE) {
148 wk_data &= ~OR_CONTROL_CLE;
149 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
153 case ISOCHRONOUS_ENDPOINT:
156 wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
157 if(wk_data & OR_CONTROL_BLE) {
158 wk_data &= ~OR_CONTROL_BLE;
159 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
163 case INTERRUPT_ENDPOINT:
164 wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
165 if(wk_data & OR_CONTROL_PLE) {
166 wk_data &= ~OR_CONTROL_PLE;
167 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
176 void USBHALHost::memInit() {
177 volatile uint8_t *p_wk_buf = (uint8_t *)(((uint32_t)usb_buf + ALIGNE_MSK) & ~ALIGNE_MSK);
179 usb_hcca = (volatile HCCA *)p_wk_buf;
180 usb_edBuf = (volatile uint8_t *)(p_wk_buf + HCCA_SIZE);
181 usb_tdBuf = (volatile uint8_t *)(p_wk_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE));
184 volatile uint8_t * USBHALHost::getED() {
185 for (int i = 0; i < MAX_ENDPOINT; i++) {
186 if ( !edBufAlloc[i] ) {
187 edBufAlloc[i] = true;
188 return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
191 perror("Could not allocate ED\r\n");
192 return NULL; //Could not alloc ED
195 volatile uint8_t * USBHALHost::getTD() {
197 for (i = 0; i < MAX_TD; i++) {
198 if ( !tdBufAlloc[i] ) {
199 tdBufAlloc[i] = true;
200 return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
203 perror("Could not allocate TD\r\n");
204 return NULL; //Could not alloc TD
208 void USBHALHost::freeED(volatile uint8_t * ed) {
210 i = (ed - usb_edBuf) / ED_SIZE;
211 edBufAlloc[i] = false;
214 void USBHALHost::freeTD(volatile uint8_t * td) {
216 i = (td - usb_tdBuf) / TD_SIZE;
217 tdBufAlloc[i] = false;
221 void USBHALHost::resetRootHub() {
222 // Initiate port reset
223 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRS);
225 while (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRS);
227 // ...and clear port reset signal
228 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
232 void USBHALHost::_usbisr(void) {
234 instHost->UsbIrqhandler();
238 void USBHALHost::UsbIrqhandler() {
239 uint32_t int_status = ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS) & ohciwrapp_reg_r(OHCI_REG_INTERRUPTENABLE);
242 if (int_status != 0) { //Is there something to actually process?
243 // Root hub status change interrupt
244 if (int_status & OR_INTR_STATUS_RHSC) {
245 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CSC) {
246 if (ohciwrapp_reg_r(OHCI_REG_RHSTATUS) & OR_RH_STATUS_DRWE) {
247 // When DRWE is on, Connect Status Change
248 // means a remote wakeup event.
251 //Root device connected
252 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
254 // wait 150ms to avoid bounce
257 //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
258 data = ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_LSDA;
259 deviceConnected(0, 1, data);
262 //Root device disconnected
265 if (!(int_status & OR_INTR_STATUS_WDH)) {
266 usb_hcca->DoneHead = 0;
269 deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
271 if (int_status & OR_INTR_STATUS_WDH) {
272 usb_hcca->DoneHead = 0;
273 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_WDH);
277 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_CSC);
279 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRSC) {
280 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
282 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_RHSC);
285 // Writeback Done Head interrupt
286 if (int_status & OR_INTR_STATUS_WDH) {
287 transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
288 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_WDH);