]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/USBHost/USBHost/USBHALHost_RZ_A1.cpp
Merge commit '5a0132f1c1c9a14fd2941f0a5e29bbf5e31da20c' into master-core-pull
[max/tmk_keyboard.git] / tmk_core / tool / mbed / mbed-sdk / libraries / USBHost / USBHost / USBHALHost_RZ_A1.cpp
1 /* mbed USBHost Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #if defined(TARGET_RZ_A1H)
18
19 #include "mbed.h"
20 #include "USBHALHost.h"
21 #include "dbg.h"
22
23 #include "ohci_wrapp_RZ_A1.h"
24
25
26 #define HCCA_SIZE sizeof(HCCA)
27 #define ED_SIZE sizeof(HCED)
28 #define TD_SIZE sizeof(HCTD)
29
30 #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
31 #define ALIGNE_MSK (0x0000000F)
32
33 static volatile uint8_t usb_buf[TOTAL_SIZE + ALIGNE_MSK];  //16 bytes aligned!
34
35 USBHALHost * USBHALHost::instHost;
36
37 USBHALHost::USBHALHost() {
38     instHost = this;
39     memInit();
40     memset((void*)usb_hcca, 0, HCCA_SIZE);
41     for (int i = 0; i < MAX_ENDPOINT; i++) {
42         edBufAlloc[i] = false;
43     }
44     for (int i = 0; i < MAX_TD; i++) {
45         tdBufAlloc[i] = false;
46     }
47 }
48
49 void USBHALHost::init() {
50     ohciwrapp_init(&_usbisr);
51
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
55
56     // Wait 100 ms before apply reset
57     wait_ms(100);
58
59     // software reset
60     ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_HCR);
61
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);
65
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);
68     // Set Global Power
69     ohciwrapp_reg_w(OHCI_REG_RHSTATUS, OR_RH_STATUS_LPSC);
70
71     ohciwrapp_reg_w(OHCI_REG_HCCA, (uint32_t)(usb_hcca));
72
73     // Clear Interrrupt Status
74     ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS));
75
76     ohciwrapp_reg_w(OHCI_REG_INTERRUPTENABLE, OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC);
77
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);
81
82     // Check for any connected devices
83     if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
84         //Device connected
85         wait_ms(150);
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);
88     }
89 }
90
91 uint32_t USBHALHost::controlHeadED() {
92     return ohciwrapp_reg_r(OHCI_REG_CONTROLHEADED);
93 }
94
95 uint32_t USBHALHost::bulkHeadED() {
96     return ohciwrapp_reg_r(OHCI_REG_BULKHEADED);
97 }
98
99 uint32_t USBHALHost::interruptHeadED() {
100     return usb_hcca->IntTable[0];
101 }
102
103 void USBHALHost::updateBulkHeadED(uint32_t addr) {
104     ohciwrapp_reg_w(OHCI_REG_BULKHEADED, addr);
105 }
106
107
108 void USBHALHost::updateControlHeadED(uint32_t addr) {
109     ohciwrapp_reg_w(OHCI_REG_CONTROLHEADED, addr);
110 }
111
112 void USBHALHost::updateInterruptHeadED(uint32_t addr) {
113     usb_hcca->IntTable[0] = addr;
114 }
115
116
117 void USBHALHost::enableList(ENDPOINT_TYPE type) {
118     uint32_t wk_data;
119
120     switch(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);
125             break;
126         case ISOCHRONOUS_ENDPOINT:
127             break;
128         case BULK_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);
132             break;
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);
136             break;
137     }
138 }
139
140
141 bool USBHALHost::disableList(ENDPOINT_TYPE type) {
142     uint32_t wk_data;
143
144     switch(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);
150                 return true;
151             }
152             return false;
153         case ISOCHRONOUS_ENDPOINT:
154             return false;
155         case BULK_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);
160                 return true;
161             }
162             return false;
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);
168                 return true;
169             }
170             return false;
171     }
172     return false;
173 }
174
175
176 void USBHALHost::memInit() {
177     volatile uint8_t *p_wk_buf = (uint8_t *)(((uint32_t)usb_buf + ALIGNE_MSK) & ~ALIGNE_MSK);
178
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));
182 }
183
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);
189         }
190     }
191     perror("Could not allocate ED\r\n");
192     return NULL; //Could not alloc ED
193 }
194
195 volatile uint8_t * USBHALHost::getTD() {
196     int i;
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);
201         }
202     }
203     perror("Could not allocate TD\r\n");
204     return NULL; //Could not alloc TD
205 }
206
207
208 void USBHALHost::freeED(volatile uint8_t * ed) {
209     int i;
210     i = (ed - usb_edBuf) / ED_SIZE;
211     edBufAlloc[i] = false;
212 }
213
214 void USBHALHost::freeTD(volatile uint8_t * td) {
215     int i;
216     i = (td - usb_tdBuf) / TD_SIZE;
217     tdBufAlloc[i] = false;
218 }
219
220
221 void USBHALHost::resetRootHub() {
222     // Initiate port reset
223     ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRS);
224
225     while (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRS);
226
227     // ...and clear port reset signal
228     ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
229 }
230
231
232 void USBHALHost::_usbisr(void) {
233     if (instHost) {
234         instHost->UsbIrqhandler();
235     }
236 }
237
238 void USBHALHost::UsbIrqhandler() {
239     uint32_t int_status = ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS) & ohciwrapp_reg_r(OHCI_REG_INTERRUPTENABLE);
240     uint32_t data;
241
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.
249                 } else {
250
251                     //Root device connected
252                     if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
253
254                         // wait 150ms to avoid bounce
255                         wait_ms(150);
256
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);
260                     }
261
262                     //Root device disconnected
263                     else {
264
265                         if (!(int_status & OR_INTR_STATUS_WDH)) {
266                             usb_hcca->DoneHead = 0;
267                         }
268
269                         deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
270
271                         if (int_status & OR_INTR_STATUS_WDH) {
272                             usb_hcca->DoneHead = 0;
273                             ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_WDH);
274                         }
275                     }
276                 }
277                 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_CSC);
278             }
279             if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRSC) {
280                 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
281             }
282             ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_RHSC);
283         }
284
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);
289         }
290     }
291 }
292 #endif