diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2013-07-13 17:35:53 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2013-07-13 17:47:01 +0200 |
commit | 140783ef66eef379feedcfef5403c5729d38936a (patch) | |
tree | 0185a6a6ef80ab134150454674a1d7e1333b8757 /utils/hwstub/stmp/main.c | |
parent | 3dd5e983db8d83113cc76ee0f5c02e158380606a (diff) | |
download | rockbox-140783ef66eef379feedcfef5403c5729d38936a.tar.gz rockbox-140783ef66eef379feedcfef5403c5729d38936a.zip |
hwstub: split target specific code from the common part
Completely rewrite the Mafile, properly put the usb driver in its
own file and the target specific files in a subdirectory.
Change-Id: Iaeee0128e021d5dad76b4d6035a63e33e2d946c1
Diffstat (limited to 'utils/hwstub/stmp/main.c')
-rw-r--r-- | utils/hwstub/stmp/main.c | 1105 |
1 files changed, 0 insertions, 1105 deletions
diff --git a/utils/hwstub/stmp/main.c b/utils/hwstub/stmp/main.c deleted file mode 100644 index 845f3842ea..0000000000 --- a/utils/hwstub/stmp/main.c +++ /dev/null | |||
@@ -1,1105 +0,0 @@ | |||
1 | #include "stddef.h" | ||
2 | #include "protocol.h" | ||
3 | #include "logf.h" | ||
4 | #include "usb_ch9.h" | ||
5 | |||
6 | extern unsigned char oc_codestart[]; | ||
7 | extern unsigned char oc_codeend[]; | ||
8 | extern unsigned char oc_stackstart[]; | ||
9 | extern unsigned char oc_stackend[]; | ||
10 | extern unsigned char oc_bufferstart[]; | ||
11 | extern unsigned char oc_bufferend[]; | ||
12 | |||
13 | #define oc_codesize ((size_t)(oc_codeend - oc_codestart)) | ||
14 | #define oc_stacksize ((size_t)(oc_stackend - oc_stackstart)) | ||
15 | #define oc_buffersize ((size_t)(oc_bufferend - oc_bufferstart)) | ||
16 | |||
17 | /** | ||
18 | * | ||
19 | * Common | ||
20 | * | ||
21 | */ | ||
22 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | ||
23 | |||
24 | #define __REG_SET(reg) (*((volatile uint32_t *)(® + 1))) | ||
25 | #define __REG_CLR(reg) (*((volatile uint32_t *)(® + 2))) | ||
26 | #define __REG_TOG(reg) (*((volatile uint32_t *)(® + 3))) | ||
27 | |||
28 | #define __BLOCK_SFTRST (1 << 31) | ||
29 | #define __BLOCK_CLKGATE (1 << 30) | ||
30 | |||
31 | #define __XTRACT(reg, field) ((reg & reg##__##field##_BM) >> reg##__##field##_BP) | ||
32 | #define __XTRACT_EX(val, field) (((val) & field##_BM) >> field##_BP) | ||
33 | #define __FIELD_SET(reg, field, val) reg = (reg & ~reg##__##field##_BM) | (val << reg##__##field##_BP) | ||
34 | |||
35 | /** | ||
36 | * | ||
37 | * Global | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | enum stmp_family_t | ||
42 | { | ||
43 | UNKNOWN, | ||
44 | STMP3600, | ||
45 | STMP3700, | ||
46 | STMP3770, | ||
47 | STMP3780 | ||
48 | }; | ||
49 | |||
50 | enum stmp_family_t g_stmp_family = UNKNOWN; | ||
51 | |||
52 | /** | ||
53 | * | ||
54 | * USB subsystem | ||
55 | * | ||
56 | */ | ||
57 | |||
58 | #define USB_BASE 0x80080000 | ||
59 | #define USB_NUM_ENDPOINTS 2 | ||
60 | #define MAX_PKT_SIZE 1024 | ||
61 | #define MAX_PKT_SIZE_EP0 64 | ||
62 | |||
63 | /* USB device mode registers (Little Endian) */ | ||
64 | #define REG_USBCMD (*(volatile unsigned int *)(USB_BASE+0x140)) | ||
65 | #define REG_DEVICEADDR (*(volatile unsigned int *)(USB_BASE+0x154)) | ||
66 | #define REG_ENDPOINTLISTADDR (*(volatile unsigned int *)(USB_BASE+0x158)) | ||
67 | #define REG_PORTSC1 (*(volatile unsigned int *)(USB_BASE+0x184)) | ||
68 | #define REG_USBMODE (*(volatile unsigned int *)(USB_BASE+0x1a8)) | ||
69 | #define REG_ENDPTSETUPSTAT (*(volatile unsigned int *)(USB_BASE+0x1ac)) | ||
70 | #define REG_ENDPTPRIME (*(volatile unsigned int *)(USB_BASE+0x1b0)) | ||
71 | #define REG_ENDPTSTATUS (*(volatile unsigned int *)(USB_BASE+0x1b8)) | ||
72 | #define REG_ENDPTCOMPLETE (*(volatile unsigned int *)(USB_BASE+0x1bc)) | ||
73 | #define REG_ENDPTCTRL0 (*(volatile unsigned int *)(USB_BASE+0x1c0)) | ||
74 | #define REG_ENDPTCTRL1 (*(volatile unsigned int *)(USB_BASE+0x1c4)) | ||
75 | #define REG_ENDPTCTRL2 (*(volatile unsigned int *)(USB_BASE+0x1c8)) | ||
76 | #define REG_ENDPTCTRL(_x_) (*(volatile unsigned int *)(USB_BASE+0x1c0+4*(_x_))) | ||
77 | |||
78 | /* USB CMD Register Bit Masks */ | ||
79 | #define USBCMD_RUN (0x00000001) | ||
80 | #define USBCMD_CTRL_RESET (0x00000002) | ||
81 | #define USBCMD_PERIODIC_SCHEDULE_EN (0x00000010) | ||
82 | #define USBCMD_ASYNC_SCHEDULE_EN (0x00000020) | ||
83 | #define USBCMD_INT_AA_DOORBELL (0x00000040) | ||
84 | #define USBCMD_ASP (0x00000300) | ||
85 | #define USBCMD_ASYNC_SCH_PARK_EN (0x00000800) | ||
86 | #define USBCMD_SUTW (0x00002000) | ||
87 | #define USBCMD_ATDTW (0x00004000) | ||
88 | #define USBCMD_ITC (0x00FF0000) | ||
89 | |||
90 | /* Device Address bit masks */ | ||
91 | #define USBDEVICEADDRESS_MASK (0xFE000000) | ||
92 | #define USBDEVICEADDRESS_BIT_POS (25) | ||
93 | |||
94 | /* Endpoint Setup Status bit masks */ | ||
95 | #define EPSETUP_STATUS_EP0 (0x00000001) | ||
96 | |||
97 | /* PORTSCX Register Bit Masks */ | ||
98 | #define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001) | ||
99 | #define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002) | ||
100 | #define PORTSCX_PORT_ENABLE (0x00000004) | ||
101 | #define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008) | ||
102 | #define PORTSCX_OVER_CURRENT_ACT (0x00000010) | ||
103 | #define PORTSCX_OVER_CURRENT_CHG (0x00000020) | ||
104 | #define PORTSCX_PORT_FORCE_RESUME (0x00000040) | ||
105 | #define PORTSCX_PORT_SUSPEND (0x00000080) | ||
106 | #define PORTSCX_PORT_RESET (0x00000100) | ||
107 | #define PORTSCX_LINE_STATUS_BITS (0x00000C00) | ||
108 | #define PORTSCX_PORT_POWER (0x00001000) | ||
109 | #define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000) | ||
110 | #define PORTSCX_PORT_TEST_CTRL (0x000F0000) | ||
111 | #define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000) | ||
112 | #define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000) | ||
113 | #define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000) | ||
114 | #define PORTSCX_PHY_LOW_POWER_SPD (0x00800000) | ||
115 | #define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000) | ||
116 | #define PORTSCX_PORT_SPEED_MASK (0x0C000000) | ||
117 | #define PORTSCX_PORT_WIDTH (0x10000000) | ||
118 | #define PORTSCX_PHY_TYPE_SEL (0xC0000000) | ||
119 | |||
120 | /* bit 11-10 are line status */ | ||
121 | #define PORTSCX_LINE_STATUS_SE0 (0x00000000) | ||
122 | #define PORTSCX_LINE_STATUS_JSTATE (0x00000400) | ||
123 | #define PORTSCX_LINE_STATUS_KSTATE (0x00000800) | ||
124 | #define PORTSCX_LINE_STATUS_UNDEF (0x00000C00) | ||
125 | #define PORTSCX_LINE_STATUS_BIT_POS (10) | ||
126 | |||
127 | /* bit 15-14 are port indicator control */ | ||
128 | #define PORTSCX_PIC_OFF (0x00000000) | ||
129 | #define PORTSCX_PIC_AMBER (0x00004000) | ||
130 | #define PORTSCX_PIC_GREEN (0x00008000) | ||
131 | #define PORTSCX_PIC_UNDEF (0x0000C000) | ||
132 | #define PORTSCX_PIC_BIT_POS (14) | ||
133 | |||
134 | /* bit 19-16 are port test control */ | ||
135 | #define PORTSCX_PTC_DISABLE (0x00000000) | ||
136 | #define PORTSCX_PTC_JSTATE (0x00010000) | ||
137 | #define PORTSCX_PTC_KSTATE (0x00020000) | ||
138 | #define PORTSCX_PTC_SE0NAK (0x00030000) | ||
139 | #define PORTSCX_PTC_PACKET (0x00040000) | ||
140 | #define PORTSCX_PTC_FORCE_EN (0x00050000) | ||
141 | #define PORTSCX_PTC_BIT_POS (16) | ||
142 | |||
143 | /* bit 27-26 are port speed */ | ||
144 | #define PORTSCX_PORT_SPEED_FULL (0x00000000) | ||
145 | #define PORTSCX_PORT_SPEED_LOW (0x04000000) | ||
146 | #define PORTSCX_PORT_SPEED_HIGH (0x08000000) | ||
147 | #define PORTSCX_PORT_SPEED_UNDEF (0x0C000000) | ||
148 | #define PORTSCX_SPEED_BIT_POS (26) | ||
149 | |||
150 | /* bit 28 is parallel transceiver width for UTMI interface */ | ||
151 | #define PORTSCX_PTW (0x10000000) | ||
152 | #define PORTSCX_PTW_8BIT (0x00000000) | ||
153 | #define PORTSCX_PTW_16BIT (0x10000000) | ||
154 | |||
155 | /* bit 31-30 are port transceiver select */ | ||
156 | #define PORTSCX_PTS_UTMI (0x00000000) | ||
157 | #define PORTSCX_PTS_CLASSIC (0x40000000) | ||
158 | #define PORTSCX_PTS_ULPI (0x80000000) | ||
159 | #define PORTSCX_PTS_FSLS (0xC0000000) | ||
160 | #define PORTSCX_PTS_BIT_POS (30) | ||
161 | |||
162 | /* USB MODE Register Bit Masks */ | ||
163 | #define USBMODE_CTRL_MODE_IDLE (0x00000000) | ||
164 | #define USBMODE_CTRL_MODE_DEVICE (0x00000002) | ||
165 | #define USBMODE_CTRL_MODE_HOST (0x00000003) | ||
166 | #define USBMODE_CTRL_MODE_RSV (0x00000001) | ||
167 | #define USBMODE_SETUP_LOCK_OFF (0x00000008) | ||
168 | #define USBMODE_STREAM_DISABLE (0x00000010) | ||
169 | |||
170 | /* ENDPOINTCTRLx Register Bit Masks */ | ||
171 | #define EPCTRL_TX_ENABLE (0x00800000) | ||
172 | #define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */ | ||
173 | #define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */ | ||
174 | #define EPCTRL_TX_TYPE (0x000C0000) | ||
175 | #define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */ | ||
176 | #define EPCTRL_TX_EP_STALL (0x00010000) | ||
177 | #define EPCTRL_RX_ENABLE (0x00000080) | ||
178 | #define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */ | ||
179 | #define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */ | ||
180 | #define EPCTRL_RX_TYPE (0x0000000C) | ||
181 | #define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */ | ||
182 | #define EPCTRL_RX_EP_STALL (0x00000001) | ||
183 | |||
184 | /* bit 19-18 and 3-2 are endpoint type */ | ||
185 | #define EPCTRL_TX_EP_TYPE_SHIFT (18) | ||
186 | #define EPCTRL_RX_EP_TYPE_SHIFT (2) | ||
187 | |||
188 | #define QH_MULT_POS (30) | ||
189 | #define QH_ZLT_SEL (0x20000000) | ||
190 | #define QH_MAX_PKT_LEN_POS (16) | ||
191 | #define QH_IOS (0x00008000) | ||
192 | #define QH_NEXT_TERMINATE (0x00000001) | ||
193 | #define QH_IOC (0x00008000) | ||
194 | #define QH_MULTO (0x00000C00) | ||
195 | #define QH_STATUS_HALT (0x00000040) | ||
196 | #define QH_STATUS_ACTIVE (0x00000080) | ||
197 | #define EP_QUEUE_CURRENT_OFFSET_MASK (0x00000FFF) | ||
198 | #define EP_QUEUE_HEAD_NEXT_POINTER_MASK (0xFFFFFFE0) | ||
199 | #define EP_QUEUE_FRINDEX_MASK (0x000007FF) | ||
200 | #define EP_MAX_LENGTH_TRANSFER (0x4000) | ||
201 | |||
202 | #define DTD_NEXT_TERMINATE (0x00000001) | ||
203 | #define DTD_IOC (0x00008000) | ||
204 | #define DTD_STATUS_ACTIVE (0x00000080) | ||
205 | #define DTD_STATUS_HALTED (0x00000040) | ||
206 | #define DTD_STATUS_DATA_BUFF_ERR (0x00000020) | ||
207 | #define DTD_STATUS_TRANSACTION_ERR (0x00000008) | ||
208 | #define DTD_RESERVED_FIELDS (0x80007300) | ||
209 | #define DTD_ADDR_MASK (0xFFFFFFE0) | ||
210 | #define DTD_PACKET_SIZE (0x7FFF0000) | ||
211 | #define DTD_LENGTH_BIT_POS (16) | ||
212 | #define DTD_ERROR_MASK (DTD_STATUS_HALTED | \ | ||
213 | DTD_STATUS_DATA_BUFF_ERR | \ | ||
214 | DTD_STATUS_TRANSACTION_ERR) | ||
215 | /*-------------------------------------------------------------------------*/ | ||
216 | /* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */ | ||
217 | struct transfer_descriptor { | ||
218 | unsigned int next_td_ptr; /* Next TD pointer(31-5), T(0) set | ||
219 | indicate invalid */ | ||
220 | unsigned int size_ioc_sts; /* Total bytes (30-16), IOC (15), | ||
221 | MultO(11-10), STS (7-0) */ | ||
222 | unsigned int buff_ptr0; /* Buffer pointer Page 0 */ | ||
223 | unsigned int buff_ptr1; /* Buffer pointer Page 1 */ | ||
224 | unsigned int buff_ptr2; /* Buffer pointer Page 2 */ | ||
225 | unsigned int buff_ptr3; /* Buffer pointer Page 3 */ | ||
226 | unsigned int buff_ptr4; /* Buffer pointer Page 4 */ | ||
227 | unsigned int reserved; | ||
228 | } __attribute__ ((packed)); | ||
229 | |||
230 | static struct transfer_descriptor td_array[USB_NUM_ENDPOINTS*2] | ||
231 | __attribute__((aligned(32))); | ||
232 | |||
233 | /* manual: 32.13.1 Endpoint Queue Head (dQH) */ | ||
234 | struct queue_head { | ||
235 | unsigned int max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len | ||
236 | and IOS(15) */ | ||
237 | unsigned int curr_dtd_ptr; /* Current dTD Pointer(31-5) */ | ||
238 | struct transfer_descriptor dtd; /* dTD overlay */ | ||
239 | unsigned int setup_buffer[2]; /* Setup data 8 bytes */ | ||
240 | unsigned int reserved; /* for software use, pointer to the first TD */ | ||
241 | unsigned int status; /* for software use, status of chain in progress */ | ||
242 | unsigned int length; /* for software use, transfered bytes of chain in progress */ | ||
243 | unsigned int wait; /* for softwate use, indicates if the transfer is blocking */ | ||
244 | } __attribute__((packed)); | ||
245 | |||
246 | static struct queue_head qh_array[USB_NUM_ENDPOINTS*2] __attribute__((aligned(2048))); | ||
247 | |||
248 | static const unsigned int pipe2mask[] = { | ||
249 | 0x01, 0x010000, | ||
250 | 0x02, 0x020000, | ||
251 | 0x04, 0x040000, | ||
252 | 0x08, 0x080000, | ||
253 | 0x10, 0x100000, | ||
254 | }; | ||
255 | |||
256 | /* return transfered size if wait=true */ | ||
257 | static int prime_transfer(int ep_num, void *ptr, int len, bool send, bool wait) | ||
258 | { | ||
259 | int pipe = ep_num * 2 + (send ? 1 : 0); | ||
260 | unsigned mask = pipe2mask[pipe]; | ||
261 | struct transfer_descriptor *td = &td_array[pipe]; | ||
262 | struct queue_head* qh = &qh_array[pipe]; | ||
263 | |||
264 | /* prepare TD */ | ||
265 | td->next_td_ptr = DTD_NEXT_TERMINATE; | ||
266 | td->size_ioc_sts = (len<< DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE; | ||
267 | td->buff_ptr0 = (unsigned int)ptr; | ||
268 | td->buff_ptr1 = ((unsigned int)ptr & 0xfffff000) + 0x1000; | ||
269 | td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; | ||
270 | td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; | ||
271 | td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; | ||
272 | td->reserved = 0; | ||
273 | /* prime */ | ||
274 | qh->dtd.next_td_ptr = (unsigned int)td; | ||
275 | qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); | ||
276 | REG_ENDPTPRIME |= mask; | ||
277 | /* wait for priming to be taken into account */ | ||
278 | while(!(REG_ENDPTSTATUS & mask)); | ||
279 | /* wait for completion */ | ||
280 | if(wait) | ||
281 | { | ||
282 | while(!(REG_ENDPTCOMPLETE & mask)); | ||
283 | REG_ENDPTCOMPLETE = mask; | ||
284 | /* memory barrier */ | ||
285 | asm volatile("":::"memory"); | ||
286 | /* return transfered size */ | ||
287 | return len - (td->size_ioc_sts >> DTD_LENGTH_BIT_POS); | ||
288 | } | ||
289 | else | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | void usb_drv_set_address(int address) | ||
294 | { | ||
295 | REG_DEVICEADDR = address << USBDEVICEADDRESS_BIT_POS; | ||
296 | } | ||
297 | |||
298 | /* endpoints */ | ||
299 | #define EP_CONTROL 0 | ||
300 | |||
301 | #define DIR_OUT 0 | ||
302 | #define DIR_IN 1 | ||
303 | |||
304 | #define EP_DIR(ep) (((ep) & USB_ENDPOINT_DIR_MASK) ? DIR_IN : DIR_OUT) | ||
305 | #define EP_NUM(ep) ((ep) & USB_ENDPOINT_NUMBER_MASK) | ||
306 | |||
307 | static int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) | ||
308 | { | ||
309 | return prime_transfer(EP_NUM(endpoint), ptr, length, true, false); | ||
310 | } | ||
311 | |||
312 | static int usb_drv_send(int endpoint, void* ptr, int length) | ||
313 | { | ||
314 | return prime_transfer(EP_NUM(endpoint), ptr, length, true, true); | ||
315 | } | ||
316 | |||
317 | static int usb_drv_recv(int endpoint, void* ptr, int length) | ||
318 | { | ||
319 | return prime_transfer(EP_NUM(endpoint), ptr, length, false, true); | ||
320 | } | ||
321 | |||
322 | static int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length) | ||
323 | { | ||
324 | return prime_transfer(EP_NUM(endpoint), ptr, length, false, false); | ||
325 | } | ||
326 | |||
327 | static int usb_drv_port_speed(void) | ||
328 | { | ||
329 | return (REG_PORTSC1 & 0x08000000) ? 1 : 0; | ||
330 | } | ||
331 | |||
332 | static void usb_drv_stall(int endpoint, bool stall, bool in) | ||
333 | { | ||
334 | int ep_num = EP_NUM(endpoint); | ||
335 | |||
336 | if(in) | ||
337 | { | ||
338 | if(stall) | ||
339 | REG_ENDPTCTRL(ep_num) |= EPCTRL_TX_EP_STALL; | ||
340 | else | ||
341 | REG_ENDPTCTRL(ep_num) &= ~EPCTRL_TX_EP_STALL; | ||
342 | } | ||
343 | else | ||
344 | { | ||
345 | if (stall) | ||
346 | REG_ENDPTCTRL(ep_num) |= EPCTRL_RX_EP_STALL; | ||
347 | else | ||
348 | REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_EP_STALL; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | static void usb_drv_configure_endpoint(int ep_num, int type) | ||
353 | { | ||
354 | REG_ENDPTCTRL(ep_num) = | ||
355 | EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | | ||
356 | EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | | ||
357 | (type << EPCTRL_RX_EP_TYPE_SHIFT) | | ||
358 | (type << EPCTRL_TX_EP_TYPE_SHIFT); | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * | ||
363 | * Clkctrl | ||
364 | * | ||
365 | */ | ||
366 | |||
367 | #define HW_CLKCTRL_BASE 0x80040000 | ||
368 | |||
369 | #define HW_CLKCTRL_PLLCTRL0 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x0)) | ||
370 | #define HW_CLKCTRL_PLLCTRL0__BYPASS (1 << 17) /* STMP3600 only */ | ||
371 | #define HW_CLKCTRL_PLLCTRL0__POWER (1 << 16) | ||
372 | #define HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS (1 << 18) | ||
373 | |||
374 | #define HW_CLKCTRL_PLLCTRL1 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x10)) | ||
375 | #define HW_CLKCTRL_PLLCTRL1__LOCK (1 << 31) | ||
376 | |||
377 | /* STMP3600 only */ | ||
378 | #define HW_CLKCTRL_CPUCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x20)) | ||
379 | #define HW_CLKCTRL_CPUCLKCTRL__DIV_BP 0 | ||
380 | #define HW_CLKCTRL_CPUCLKCTRL__DIV_BM 0x3ff | ||
381 | #define HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK (1 << 30) | ||
382 | |||
383 | /* STMP3600 */ | ||
384 | #define HW_CLKCTRL_HBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x30)) | ||
385 | |||
386 | /* STMP3600 only */ | ||
387 | #define HW_CLKCTRL_XBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x40)) | ||
388 | #define HW_CLKCTRL_XBUSCLKCTRL__DIV_BP 0 | ||
389 | #define HW_CLKCTRL_XBUSCLKCTRL__DIV_BM 0x3ff | ||
390 | |||
391 | /* STMP3600 only */ | ||
392 | #define HW_CLKCTRL_UTMICLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x70)) | ||
393 | #define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE (1 << 30) | ||
394 | #define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE (1 << 31) | ||
395 | |||
396 | /** | ||
397 | * | ||
398 | * Digctl | ||
399 | * | ||
400 | */ | ||
401 | |||
402 | /* Digital control */ | ||
403 | #define HW_DIGCTL_BASE 0x8001C000 | ||
404 | #define HW_DIGCTL_CTRL (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0)) | ||
405 | #define HW_DIGCTL_CTRL__USB_CLKGATE (1 << 2) | ||
406 | |||
407 | #define HW_DIGCTL_MICROSECONDS (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0xC0)) | ||
408 | |||
409 | #define HW_DIGCTL_CHIPID (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0x310)) | ||
410 | #define HW_DIGCTL_CHIPID__PRODUCT_CODE_BP 16 | ||
411 | #define HW_DIGCTL_CHIPID__PRODUCT_CODE_BM 0xffff0000 | ||
412 | #define HW_DIGCTL_CHIPID__REVISION_BP 0 | ||
413 | #define HW_DIGCTL_CHIPID__REVISION_BM 0xff | ||
414 | |||
415 | static bool imx233_us_elapsed(uint32_t ref, unsigned us_delay) | ||
416 | { | ||
417 | uint32_t cur = HW_DIGCTL_MICROSECONDS; | ||
418 | if(ref + us_delay <= ref) | ||
419 | return !(cur > ref) && !(cur < (ref + us_delay)); | ||
420 | else | ||
421 | return (cur < ref) || cur >= (ref + us_delay); | ||
422 | } | ||
423 | |||
424 | static void udelay(unsigned us) | ||
425 | { | ||
426 | uint32_t ref = HW_DIGCTL_MICROSECONDS; | ||
427 | while(!imx233_us_elapsed(ref, us)); | ||
428 | } | ||
429 | |||
430 | #define HZ 1000000 | ||
431 | |||
432 | /** | ||
433 | * | ||
434 | * USB PHY | ||
435 | * | ||
436 | */ | ||
437 | /* USB Phy */ | ||
438 | #define HW_USBPHY_BASE 0x8007C000 | ||
439 | #define HW_USBPHY_PWD (*(volatile uint32_t *)(HW_USBPHY_BASE + 0)) | ||
440 | |||
441 | #define HW_USBPHY_CTRL (*(volatile uint32_t *)(HW_USBPHY_BASE + 0x30)) | ||
442 | |||
443 | /** | ||
444 | * | ||
445 | * DCP | ||
446 | * | ||
447 | */ | ||
448 | #define HW_DCP_BASE 0x80028000 | ||
449 | |||
450 | #define HW_DCP_CTRL (*(volatile unsigned long *)(HW_DCP_BASE + 0x0)) | ||
451 | |||
452 | #define HW_DCP_STAT (*(volatile unsigned long *)(HW_DCP_BASE + 0x10)) | ||
453 | #define HW_DCP_STAT__IRQ(x) (1 << (x)) | ||
454 | |||
455 | #define HW_DCP_CHANNELCTRL (*(volatile unsigned long *)(HW_DCP_BASE + 0x20)) | ||
456 | #define HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(x) (1 << (x)) | ||
457 | |||
458 | #define HW_DCP_CH0CMDPTR (*(volatile unsigned long *)(HW_DCP_BASE + 0x100)) | ||
459 | |||
460 | #define HW_DCP_CH0SEMA (*(volatile unsigned long *)(HW_DCP_BASE + 0x110)) | ||
461 | #define HW_DCP_CH0SEMA__INCREMENT(x) (x) | ||
462 | #define HW_DCP_CH0SEMA__VALUE_BP 16 | ||
463 | #define HW_DCP_CH0SEMA__VALUE_BM (0xff << 16) | ||
464 | #define HW_DCP_CH0STAT (*(volatile unsigned long *)(HW_DCP_BASE + 0x120)) | ||
465 | |||
466 | #define HW_DCP_CTRL0__INTERRUPT_ENABLE (1 << 0) | ||
467 | #define HW_DCP_CTRL0__DECR_SEMAPHORE (1 << 1) | ||
468 | #define HW_DCP_CTRL0__ENABLE_MEMCOPY (1 << 4) | ||
469 | #define HW_DCP_CTRL0__ENABLE_CIPHER (1 << 5) | ||
470 | #define HW_DCP_CTRL0__ENABLE_HASH (1 << 6) | ||
471 | #define HW_DCP_CTRL0__CIPHER_ENCRYPT (1 << 8) | ||
472 | #define HW_DCP_CTRL0__CIPHER_INIT (1 << 9) | ||
473 | #define HW_DCP_CTRL0__OTP_KEY (1 << 10) | ||
474 | #define HW_DCP_CTRL0__HASH_INIT (1 << 12) | ||
475 | #define HW_DCP_CTRL0__HASH_TERM (1 << 13) | ||
476 | #define HW_DCP_CTRL0__HASH_OUTPUT (1 << 15) | ||
477 | |||
478 | #define HW_DCP_CTRL1__CIPHER_SELECT_BP 0 | ||
479 | #define HW_DCP_CTRL1__CIPHER_SELECT_BM 0xf | ||
480 | #define HW_DCP_CTRL1__CIPHER_SELECT__AES128 0 | ||
481 | #define HW_DCP_CTRL1__CIPHER_MODE_BP 4 | ||
482 | #define HW_DCP_CTRL1__CIPHER_MODE_BM 0xf0 | ||
483 | #define HW_DCP_CTRL1__CIPHER_MODE__CBC (1 << 4) | ||
484 | #define HW_DCP_CTRL1__HASH_SELECT_BP 4 | ||
485 | #define HW_DCP_CTRL1__HASH_SELECT_BM 0xf00 | ||
486 | |||
487 | struct dcp_packet_t | ||
488 | { | ||
489 | unsigned long next; | ||
490 | unsigned long ctrl0; | ||
491 | unsigned long ctrl1; | ||
492 | unsigned long src_buf; | ||
493 | unsigned long dst_buf; | ||
494 | unsigned long buf_sz; | ||
495 | unsigned long payload_ptr; | ||
496 | unsigned long status; | ||
497 | } __attribute__((packed)); | ||
498 | |||
499 | /** | ||
500 | * | ||
501 | * Misc | ||
502 | * | ||
503 | */ | ||
504 | |||
505 | void memcpy(void *dest, const void *src, size_t n); | ||
506 | void memmove(void *dest, const void *src, size_t n); | ||
507 | void memset(void *dst, int value, size_t n); | ||
508 | |||
509 | /** | ||
510 | * | ||
511 | * USB stack | ||
512 | * | ||
513 | */ | ||
514 | |||
515 | static struct usb_device_descriptor __attribute__((aligned(2))) | ||
516 | device_descriptor= | ||
517 | { | ||
518 | .bLength = sizeof(struct usb_device_descriptor), | ||
519 | .bDescriptorType = USB_DT_DEVICE, | ||
520 | .bcdUSB = 0x0200, | ||
521 | .bDeviceClass = USB_CLASS_PER_INTERFACE, | ||
522 | .bDeviceSubClass = 0, | ||
523 | .bDeviceProtocol = 0, | ||
524 | .bMaxPacketSize0 = 64, | ||
525 | .idVendor = HWSTUB_USB_VID, | ||
526 | .idProduct = HWSTUB_USB_PID, | ||
527 | .bcdDevice = HWSTUB_VERSION_MAJOR << 8 | HWSTUB_VERSION_MINOR, | ||
528 | .iManufacturer = 1, | ||
529 | .iProduct = 2, | ||
530 | .iSerialNumber = 3, | ||
531 | .bNumConfigurations = 1 | ||
532 | }; | ||
533 | |||
534 | #define USB_MAX_CURRENT 200 | ||
535 | |||
536 | static struct usb_config_descriptor __attribute__((aligned(2))) | ||
537 | config_descriptor = | ||
538 | { | ||
539 | .bLength = sizeof(struct usb_config_descriptor), | ||
540 | .bDescriptorType = USB_DT_CONFIG, | ||
541 | .wTotalLength = 0, /* will be filled in later */ | ||
542 | .bNumInterfaces = 1, | ||
543 | .bConfigurationValue = 1, | ||
544 | .iConfiguration = 0, | ||
545 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
546 | .bMaxPower = (USB_MAX_CURRENT + 1) / 2, /* In 2mA units */ | ||
547 | }; | ||
548 | |||
549 | /* main interface */ | ||
550 | static struct usb_interface_descriptor __attribute__((aligned(2))) | ||
551 | interface_descriptor = | ||
552 | { | ||
553 | .bLength = sizeof(struct usb_interface_descriptor), | ||
554 | .bDescriptorType = USB_DT_INTERFACE, | ||
555 | .bInterfaceNumber = 0, | ||
556 | .bAlternateSetting = 0, | ||
557 | .bNumEndpoints = 3, | ||
558 | .bInterfaceClass = HWSTUB_CLASS, | ||
559 | .bInterfaceSubClass = HWSTUB_SUBCLASS, | ||
560 | .bInterfaceProtocol = HWSTUB_PROTOCOL, | ||
561 | .iInterface = 4 | ||
562 | }; | ||
563 | |||
564 | |||
565 | static struct usb_endpoint_descriptor __attribute__((aligned(2))) | ||
566 | endpoint_descriptor = | ||
567 | { | ||
568 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
569 | .bDescriptorType = USB_DT_ENDPOINT, | ||
570 | .bEndpointAddress = 0, | ||
571 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
572 | .wMaxPacketSize = 0, | ||
573 | .bInterval = 0 | ||
574 | }; | ||
575 | |||
576 | static const struct usb_string_descriptor __attribute__((aligned(2))) | ||
577 | usb_string_iManufacturer = | ||
578 | { | ||
579 | 24, | ||
580 | USB_DT_STRING, | ||
581 | {'R', 'o', 'c', 'k', 'b', 'o', 'x', '.', 'o', 'r', 'g'} | ||
582 | }; | ||
583 | |||
584 | static const struct usb_string_descriptor __attribute__((aligned(2))) | ||
585 | usb_string_iProduct = | ||
586 | { | ||
587 | 52, | ||
588 | USB_DT_STRING, | ||
589 | {'R', 'o', 'c', 'k', 'b', 'o', 'x', ' ', | ||
590 | 'h', 'a', 'r', 'd', 'w', 'a', 'r', 'e', ' ', | ||
591 | 'e', 'm', 'u', 'l', 'a', 't', 'e', 'r'} | ||
592 | }; | ||
593 | |||
594 | static struct usb_string_descriptor __attribute__((aligned(2))) | ||
595 | usb_string_iSerial = | ||
596 | { | ||
597 | 84, | ||
598 | USB_DT_STRING, | ||
599 | {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', | ||
600 | '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', | ||
601 | '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', | ||
602 | '0', '0', '0', '0', '0', '0', '0', '0'} | ||
603 | }; | ||
604 | |||
605 | static struct usb_string_descriptor __attribute__((aligned(2))) | ||
606 | usb_string_iInterface = | ||
607 | { | ||
608 | 28, | ||
609 | USB_DT_STRING, | ||
610 | {'A', 'c', 'i', 'd', ' ', | ||
611 | '0' + (HWSTUB_VERSION_MAJOR >> 4), '0' + (HWSTUB_VERSION_MAJOR & 0xf), '.', | ||
612 | '0' + (HWSTUB_VERSION_MINOR >> 4), '0' + (HWSTUB_VERSION_MINOR & 0xf), '.', | ||
613 | '0' + (HWSTUB_VERSION_REV >> 4), '0' + (HWSTUB_VERSION_REV & 0xf) } | ||
614 | }; | ||
615 | |||
616 | /* this is stringid #0: languages supported */ | ||
617 | static const struct usb_string_descriptor __attribute__((aligned(2))) | ||
618 | lang_descriptor = | ||
619 | { | ||
620 | 4, | ||
621 | USB_DT_STRING, | ||
622 | {0x0409} /* LANGID US English */ | ||
623 | }; | ||
624 | |||
625 | #define USB_NUM_STRINGS 5 | ||
626 | |||
627 | static const struct usb_string_descriptor* const usb_strings[USB_NUM_STRINGS] = | ||
628 | { | ||
629 | &lang_descriptor, | ||
630 | &usb_string_iManufacturer, | ||
631 | &usb_string_iProduct, | ||
632 | &usb_string_iSerial, | ||
633 | &usb_string_iInterface | ||
634 | }; | ||
635 | |||
636 | uint8_t *usb_buffer = oc_bufferstart; | ||
637 | uint32_t usb_buffer_size = 0; | ||
638 | |||
639 | #define EP_BULK 1 | ||
640 | #define EP_INT 2 | ||
641 | |||
642 | static void set_config(void) | ||
643 | { | ||
644 | usb_drv_configure_endpoint(EP_BULK, USB_ENDPOINT_XFER_BULK); | ||
645 | usb_drv_configure_endpoint(EP_INT, USB_ENDPOINT_XFER_INT); | ||
646 | } | ||
647 | |||
648 | static void handle_std_dev_desc(struct usb_ctrlrequest *req) | ||
649 | { | ||
650 | int size; | ||
651 | const void* ptr = NULL; | ||
652 | unsigned index = req->wValue & 0xff; | ||
653 | |||
654 | switch(req->wValue >> 8) | ||
655 | { | ||
656 | case USB_DT_DEVICE: | ||
657 | ptr = &device_descriptor; | ||
658 | size = sizeof(struct usb_device_descriptor); | ||
659 | break; | ||
660 | case USB_DT_OTHER_SPEED_CONFIG: | ||
661 | case USB_DT_CONFIG: | ||
662 | { | ||
663 | int max_packet_size; | ||
664 | |||
665 | /* config desc */ | ||
666 | if((req->wValue >> 8) ==USB_DT_CONFIG) | ||
667 | { | ||
668 | max_packet_size = (usb_drv_port_speed() ? 512 : 64); | ||
669 | config_descriptor.bDescriptorType = USB_DT_CONFIG; | ||
670 | } | ||
671 | else | ||
672 | { | ||
673 | max_packet_size=(usb_drv_port_speed() ? 64 : 512); | ||
674 | config_descriptor.bDescriptorType = USB_DT_OTHER_SPEED_CONFIG; | ||
675 | } | ||
676 | size = sizeof(struct usb_config_descriptor); | ||
677 | |||
678 | /* interface */ | ||
679 | memcpy(usb_buffer + size, (void *)&interface_descriptor, | ||
680 | sizeof(interface_descriptor)); | ||
681 | size += sizeof(interface_descriptor); | ||
682 | /* endpoint 1: bulk out */ | ||
683 | endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_OUT; | ||
684 | endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK; | ||
685 | endpoint_descriptor.wMaxPacketSize = 512; | ||
686 | memcpy(usb_buffer + size, (void *)&endpoint_descriptor, | ||
687 | sizeof(endpoint_descriptor)); | ||
688 | size += sizeof(endpoint_descriptor); | ||
689 | /* endpoint 2: bulk in */ | ||
690 | endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_IN; | ||
691 | endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK; | ||
692 | endpoint_descriptor.wMaxPacketSize = 512; | ||
693 | memcpy(usb_buffer + size, (void *)&endpoint_descriptor, | ||
694 | sizeof(endpoint_descriptor)); | ||
695 | size += sizeof(endpoint_descriptor); | ||
696 | /* endpoint 3: int in */ | ||
697 | endpoint_descriptor.bEndpointAddress = EP_INT | USB_DIR_IN; | ||
698 | endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_INT; | ||
699 | endpoint_descriptor.wMaxPacketSize = 1024; | ||
700 | memcpy(usb_buffer + size, (void *)&endpoint_descriptor, | ||
701 | sizeof(endpoint_descriptor)); | ||
702 | size += sizeof(endpoint_descriptor); | ||
703 | |||
704 | /* fix config descriptor */ | ||
705 | config_descriptor.bNumInterfaces = 1; | ||
706 | config_descriptor.wTotalLength = size; | ||
707 | memcpy(usb_buffer, (void *)&config_descriptor, sizeof(config_descriptor)); | ||
708 | |||
709 | ptr = usb_buffer; | ||
710 | break; | ||
711 | } | ||
712 | case USB_DT_STRING: | ||
713 | if(index < USB_NUM_STRINGS) | ||
714 | { | ||
715 | size = usb_strings[index]->bLength; | ||
716 | ptr = usb_strings[index]; | ||
717 | } | ||
718 | else | ||
719 | usb_drv_stall(EP_CONTROL, true, true); | ||
720 | break; | ||
721 | default: | ||
722 | break; | ||
723 | } | ||
724 | |||
725 | if(ptr) | ||
726 | { | ||
727 | int length = MIN(size, req->wLength); | ||
728 | |||
729 | if(ptr != usb_buffer) | ||
730 | memcpy(usb_buffer, ptr, length); | ||
731 | |||
732 | usb_drv_send(EP_CONTROL, usb_buffer, length); | ||
733 | usb_drv_recv(EP_CONTROL, NULL, 0); | ||
734 | } | ||
735 | else | ||
736 | usb_drv_stall(EP_CONTROL, true, true); | ||
737 | } | ||
738 | |||
739 | static void handle_std_dev_req(struct usb_ctrlrequest *req) | ||
740 | { | ||
741 | switch(req->bRequest) | ||
742 | { | ||
743 | case USB_REQ_GET_CONFIGURATION: | ||
744 | usb_buffer[0] = 1; | ||
745 | usb_drv_send(EP_CONTROL, usb_buffer, 1); | ||
746 | usb_drv_recv(EP_CONTROL, NULL, 0); | ||
747 | break; | ||
748 | case USB_REQ_SET_CONFIGURATION: | ||
749 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
750 | set_config(); | ||
751 | break; | ||
752 | case USB_REQ_GET_DESCRIPTOR: | ||
753 | handle_std_dev_desc(req); | ||
754 | break; | ||
755 | case USB_REQ_SET_ADDRESS: | ||
756 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
757 | usb_drv_set_address(req->wValue); | ||
758 | break; | ||
759 | case USB_REQ_GET_STATUS: | ||
760 | usb_buffer[0] = 0; | ||
761 | usb_buffer[1] = 0; | ||
762 | usb_drv_send(EP_CONTROL, usb_buffer, 2); | ||
763 | usb_drv_recv(EP_CONTROL, NULL, 0); | ||
764 | break; | ||
765 | default: | ||
766 | usb_drv_stall(EP_CONTROL, true, true); | ||
767 | } | ||
768 | } | ||
769 | |||
770 | static void handle_std_req(struct usb_ctrlrequest *req) | ||
771 | { | ||
772 | switch(req->bRequestType & USB_RECIP_MASK) | ||
773 | { | ||
774 | case USB_RECIP_DEVICE: | ||
775 | return handle_std_dev_req(req); | ||
776 | default: | ||
777 | usb_drv_stall(EP_CONTROL, true, true); | ||
778 | } | ||
779 | } | ||
780 | |||
781 | struct usb_resp_info_version_t g_version = | ||
782 | { | ||
783 | .major = HWSTUB_VERSION_MAJOR, | ||
784 | .minor = HWSTUB_VERSION_MINOR, | ||
785 | .revision = HWSTUB_VERSION_REV | ||
786 | }; | ||
787 | |||
788 | struct usb_resp_info_layout_t g_layout; | ||
789 | |||
790 | struct usb_resp_info_stmp_t g_stmp; | ||
791 | |||
792 | struct usb_resp_info_features_t g_features = | ||
793 | { | ||
794 | .feature_mask = HWSTUB_FEATURE_LOG | HWSTUB_FEATURE_MEM | | ||
795 | HWSTUB_FEATURE_CALL | HWSTUB_FEATURE_JUMP | HWSTUB_FEATURE_AES_OTP | ||
796 | }; | ||
797 | |||
798 | static void fill_layout_info(void) | ||
799 | { | ||
800 | g_layout.oc_code_start = (uint32_t)oc_codestart; | ||
801 | g_layout.oc_code_size = oc_codesize; | ||
802 | g_layout.oc_stack_start = (uint32_t)oc_stackstart; | ||
803 | g_layout.oc_stack_size = oc_stacksize; | ||
804 | g_layout.oc_buffer_start = (uint32_t)oc_bufferstart; | ||
805 | g_layout.oc_buffer_size = oc_buffersize; | ||
806 | } | ||
807 | |||
808 | static void fill_stmp_info(void) | ||
809 | { | ||
810 | g_stmp.chipid = __XTRACT(HW_DIGCTL_CHIPID, PRODUCT_CODE); | ||
811 | g_stmp.rev = __XTRACT(HW_DIGCTL_CHIPID, REVISION); | ||
812 | g_stmp.is_supported = g_stmp.chipid == 0x3780 || g_stmp.chipid == 0x3700 || | ||
813 | g_stmp.chipid == 0x3b00; | ||
814 | } | ||
815 | |||
816 | static void handle_get_info(struct usb_ctrlrequest *req) | ||
817 | { | ||
818 | void *ptr = NULL; | ||
819 | int size = 0; | ||
820 | switch(req->wIndex) | ||
821 | { | ||
822 | case HWSTUB_INFO_VERSION: | ||
823 | ptr = &g_version; | ||
824 | size = sizeof(g_version); | ||
825 | break; | ||
826 | case HWSTUB_INFO_LAYOUT: | ||
827 | fill_layout_info(); | ||
828 | ptr = &g_layout; | ||
829 | size = sizeof(g_layout); | ||
830 | break; | ||
831 | case HWSTUB_INFO_STMP: | ||
832 | fill_stmp_info(); | ||
833 | ptr = &g_stmp; | ||
834 | size = sizeof(g_stmp); | ||
835 | break; | ||
836 | case HWSTUB_INFO_FEATURES: | ||
837 | ptr = &g_features; | ||
838 | size = sizeof(g_features); | ||
839 | break; | ||
840 | default: | ||
841 | usb_drv_stall(EP_CONTROL, true, true); | ||
842 | } | ||
843 | |||
844 | if(ptr) | ||
845 | { | ||
846 | int length = MIN(size, req->wLength); | ||
847 | |||
848 | if(ptr != usb_buffer) | ||
849 | memcpy(usb_buffer, ptr, length); | ||
850 | usb_drv_send(EP_CONTROL, usb_buffer, length); | ||
851 | usb_drv_recv(EP_CONTROL, NULL, 0); | ||
852 | } | ||
853 | } | ||
854 | |||
855 | static void handle_get_log(struct usb_ctrlrequest *req) | ||
856 | { | ||
857 | enable_logf(false); | ||
858 | int length = logf_readback(usb_buffer, MIN(req->wLength, usb_buffer_size)); | ||
859 | usb_drv_send(EP_CONTROL, usb_buffer, length); | ||
860 | usb_drv_recv(EP_CONTROL, NULL, 0); | ||
861 | enable_logf(true); | ||
862 | } | ||
863 | |||
864 | static void handle_rw_mem(struct usb_ctrlrequest *req) | ||
865 | { | ||
866 | uint32_t addr = req->wValue | req->wIndex << 16; | ||
867 | uint16_t length = req->wLength; | ||
868 | |||
869 | if(req->bRequestType & USB_DIR_IN) | ||
870 | { | ||
871 | memcpy(usb_buffer, (void *)addr, length); | ||
872 | asm volatile("nop" : : : "memory"); | ||
873 | usb_drv_send(EP_CONTROL, usb_buffer, length); | ||
874 | usb_drv_recv(EP_CONTROL, NULL, 0); | ||
875 | } | ||
876 | else | ||
877 | { | ||
878 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, length); | ||
879 | asm volatile("nop" : : : "memory"); | ||
880 | if(size != length) | ||
881 | usb_drv_stall(EP_CONTROL, true, true); | ||
882 | else | ||
883 | { | ||
884 | memcpy((void *)addr, usb_buffer, length); | ||
885 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
886 | } | ||
887 | } | ||
888 | } | ||
889 | |||
890 | static void handle_call_jump(struct usb_ctrlrequest *req) | ||
891 | { | ||
892 | uint32_t addr = req->wValue | req->wIndex << 16; | ||
893 | |||
894 | if(req->bRequest == HWSTUB_CALL) | ||
895 | ((void (*)(void))addr)(); | ||
896 | else | ||
897 | { | ||
898 | /* disconnect to make sure usb/dma won't interfere */ | ||
899 | REG_USBCMD &= ~USBCMD_RUN; | ||
900 | REG_USBCMD |= USBCMD_CTRL_RESET; | ||
901 | asm volatile("bx %0\n" : : "r" (addr) : "memory"); | ||
902 | } | ||
903 | } | ||
904 | |||
905 | static void do_aes_otp(void *buffer, unsigned length, unsigned params) | ||
906 | { | ||
907 | static struct dcp_packet_t dcp_packet; | ||
908 | |||
909 | bool encrypt = !!(params & HWSTUB_AES_OTP_ENCRYPT); | ||
910 | /* reset DCP */ | ||
911 | __REG_SET(HW_DCP_CTRL) = 0x80000000; | ||
912 | /* clear clock gate */ | ||
913 | __REG_CLR(HW_DCP_CTRL) = 0xc0000000; | ||
914 | /* enable dma for channel 0 */ | ||
915 | __REG_SET(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(0); | ||
916 | /* prepare packet */ | ||
917 | dcp_packet.next = 0; | ||
918 | |||
919 | dcp_packet.ctrl0 = HW_DCP_CTRL0__INTERRUPT_ENABLE | | ||
920 | HW_DCP_CTRL0__DECR_SEMAPHORE | HW_DCP_CTRL0__CIPHER_INIT | | ||
921 | HW_DCP_CTRL0__ENABLE_CIPHER | HW_DCP_CTRL0__OTP_KEY | | ||
922 | (encrypt ? HW_DCP_CTRL0__CIPHER_ENCRYPT : 0); | ||
923 | dcp_packet.ctrl1 = HW_DCP_CTRL1__CIPHER_SELECT__AES128 | | ||
924 | HW_DCP_CTRL1__CIPHER_MODE__CBC; | ||
925 | dcp_packet.src_buf = (unsigned long)buffer + 16; | ||
926 | dcp_packet.dst_buf = (unsigned long)buffer + 16; | ||
927 | dcp_packet.buf_sz = length - 16; | ||
928 | dcp_packet.payload_ptr = (unsigned long)buffer; | ||
929 | dcp_packet.status = 0; | ||
930 | |||
931 | asm volatile("":::"memory"); | ||
932 | /* kick */ | ||
933 | HW_DCP_CH0CMDPTR = (unsigned long)&dcp_packet; | ||
934 | HW_DCP_CH0SEMA = HW_DCP_CH0SEMA__INCREMENT(1); | ||
935 | /* wait */ | ||
936 | while(!(HW_DCP_STAT & HW_DCP_STAT__IRQ(0))); | ||
937 | |||
938 | usb_drv_send_nonblocking(EP_INT, buffer, length); | ||
939 | } | ||
940 | |||
941 | static void handle_aes_otp(struct usb_ctrlrequest *req) | ||
942 | { | ||
943 | uint16_t length = req->wLength; | ||
944 | |||
945 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, length); | ||
946 | if(size != length) | ||
947 | usb_drv_stall(EP_CONTROL, true, true); | ||
948 | else | ||
949 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
950 | do_aes_otp(usb_buffer, length, req->wValue); | ||
951 | } | ||
952 | |||
953 | static void handle_class_dev_req(struct usb_ctrlrequest *req) | ||
954 | { | ||
955 | switch(req->bRequest) | ||
956 | { | ||
957 | case HWSTUB_GET_INFO: | ||
958 | handle_get_info(req); | ||
959 | break; | ||
960 | case HWSTUB_GET_LOG: | ||
961 | handle_get_log(req); | ||
962 | break; | ||
963 | case HWSTUB_RW_MEM: | ||
964 | handle_rw_mem(req); | ||
965 | break; | ||
966 | case HWSTUB_CALL: | ||
967 | case HWSTUB_JUMP: | ||
968 | handle_call_jump(req); | ||
969 | break; | ||
970 | case HWSTUB_AES_OTP: | ||
971 | handle_aes_otp(req); | ||
972 | break; | ||
973 | default: | ||
974 | usb_drv_stall(EP_CONTROL, true, true); | ||
975 | } | ||
976 | } | ||
977 | |||
978 | static void handle_class_req(struct usb_ctrlrequest *req) | ||
979 | { | ||
980 | switch(req->bRequestType & USB_RECIP_MASK) | ||
981 | { | ||
982 | case USB_RECIP_DEVICE: | ||
983 | return handle_class_dev_req(req); | ||
984 | default: | ||
985 | usb_drv_stall(EP_CONTROL, true, true); | ||
986 | } | ||
987 | } | ||
988 | |||
989 | /** | ||
990 | * | ||
991 | * Main | ||
992 | * | ||
993 | */ | ||
994 | |||
995 | void main(uint32_t arg) | ||
996 | { | ||
997 | usb_buffer_size = oc_buffersize; | ||
998 | |||
999 | logf("hwstub %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, | ||
1000 | HWSTUB_VERSION_REV); | ||
1001 | logf("argument: 0x%08x\n", arg); | ||
1002 | |||
1003 | /* detect family */ | ||
1004 | uint16_t product_code = __XTRACT(HW_DIGCTL_CHIPID, PRODUCT_CODE); | ||
1005 | if(product_code >= 0x3600 && product_code < 0x3700) | ||
1006 | { | ||
1007 | logf("identified STMP3600 family\n"); | ||
1008 | g_stmp_family = STMP3600; | ||
1009 | } | ||
1010 | else if(product_code == 0x3700) | ||
1011 | { | ||
1012 | logf("identified STMP3700 family\n"); | ||
1013 | g_stmp_family = STMP3700; | ||
1014 | } | ||
1015 | else if(product_code == 0x37b0) | ||
1016 | { | ||
1017 | logf("identified STMP3770 family\n"); | ||
1018 | g_stmp_family = STMP3770; | ||
1019 | } | ||
1020 | else if(product_code == 0x3780) | ||
1021 | { | ||
1022 | logf("identified STMP3780 family\n"); | ||
1023 | g_stmp_family = STMP3780; | ||
1024 | } | ||
1025 | else | ||
1026 | logf("cannot identify family: 0x%x\n", product_code); | ||
1027 | |||
1028 | /* we don't know if USB was connected or not. In USB recovery mode it will | ||
1029 | * but in other cases it might not be. In doubt, disconnect */ | ||
1030 | REG_USBCMD &= ~USBCMD_RUN; | ||
1031 | if(g_stmp_family == STMP3600) | ||
1032 | { | ||
1033 | /* CPU clock is always derived from PLL, if we switch to PLL, cpu will | ||
1034 | * run at 480 MHz unprepared ! That's bad so prepare to run at slow sleed | ||
1035 | * (1.2MHz) for a safe transition */ | ||
1036 | HW_CLKCTRL_CPUCLKCTRL = HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK | 400; | ||
1037 | /* We need to ensure that XBUS < HBUS but HBUS will be 1.2 MHz after the | ||
1038 | * switch so lower XBUS too */ | ||
1039 | HW_CLKCTRL_XBUSCLKCTRL = 20; | ||
1040 | /* Power PLL */ | ||
1041 | __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER; | ||
1042 | HW_CLKCTRL_PLLCTRL0 = (HW_CLKCTRL_PLLCTRL0 & ~0x3ff) | 480; | ||
1043 | /* Wait lock */ | ||
1044 | while(!(HW_CLKCTRL_PLLCTRL1 & HW_CLKCTRL_PLLCTRL1__LOCK)); | ||
1045 | /* Switch to PLL source */ | ||
1046 | __REG_CLR(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__BYPASS; | ||
1047 | /* Get back XBUS = 24 MHz and CPU = HBUS = 64MHz */ | ||
1048 | HW_CLKCTRL_CPUCLKCTRL = 7; | ||
1049 | HW_CLKCTRL_HBUSCLKCTRL = 7; | ||
1050 | HW_CLKCTRL_XBUSCLKCTRL = 1; | ||
1051 | __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE; | ||
1052 | __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE; | ||
1053 | } | ||
1054 | else | ||
1055 | __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER; | ||
1056 | /* enable USB PHY PLL */ | ||
1057 | __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS; | ||
1058 | /* power up USB PHY */ | ||
1059 | __REG_CLR(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST; | ||
1060 | HW_USBPHY_PWD = 0; | ||
1061 | /* enable USB controller */ | ||
1062 | __REG_CLR(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE; | ||
1063 | /* reset the controller */ | ||
1064 | REG_USBCMD |= USBCMD_CTRL_RESET; | ||
1065 | while (REG_USBCMD & USBCMD_CTRL_RESET); | ||
1066 | /* put it in device mode */ | ||
1067 | REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; | ||
1068 | /* reset address */ | ||
1069 | REG_DEVICEADDR = 0; | ||
1070 | /* prepare qh array */ | ||
1071 | qh_array[0].max_pkt_length = 1 << 29 | MAX_PKT_SIZE_EP0 << 16; | ||
1072 | qh_array[1].max_pkt_length = 1 << 29 | MAX_PKT_SIZE_EP0 << 16; | ||
1073 | qh_array[2].max_pkt_length = 1 << 29 | MAX_PKT_SIZE << 16; | ||
1074 | qh_array[3].max_pkt_length = 1 << 29 | MAX_PKT_SIZE << 16; | ||
1075 | /* setup qh */ | ||
1076 | REG_ENDPOINTLISTADDR = (unsigned int)qh_array; | ||
1077 | /* clear setup status */ | ||
1078 | REG_ENDPTSETUPSTAT = EPSETUP_STATUS_EP0; | ||
1079 | /* run! */ | ||
1080 | REG_USBCMD |= USBCMD_RUN; | ||
1081 | |||
1082 | while(1) | ||
1083 | { | ||
1084 | /* wait for setup */ | ||
1085 | while(!(REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0)) | ||
1086 | ; | ||
1087 | /* clear setup status */ | ||
1088 | REG_ENDPTSETUPSTAT = EPSETUP_STATUS_EP0; | ||
1089 | /* check request */ | ||
1090 | asm volatile("":::"memory"); | ||
1091 | struct usb_ctrlrequest *req = (void *)&qh_array[0].setup_buffer[0]; | ||
1092 | |||
1093 | switch(req->bRequestType & USB_TYPE_MASK) | ||
1094 | { | ||
1095 | case USB_TYPE_STANDARD: | ||
1096 | handle_std_req(req); | ||
1097 | break; | ||
1098 | case USB_TYPE_CLASS: | ||
1099 | handle_class_req(req); | ||
1100 | break; | ||
1101 | default: | ||
1102 | usb_drv_stall(EP_CONTROL, true, true); | ||
1103 | } | ||
1104 | } | ||
1105 | } | ||