blob: fcd0593767db6d4ed7b50b638c52ec30aca3e9b2 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2015 Brian Swetland
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#include <app.h>
25#include <err.h>
26#include <debug.h>
27#include <string.h>
28#include <stdlib.h>
29#include <printf.h>
30#include <dev/udc.h>
31
32#include <platform.h>
33#include <arch/arm.h>
34#include <kernel/thread.h>
35#include <kernel/event.h>
36#include <kernel/timer.h>
37
38#include <platform/lpc43xx-gpio.h>
39
40#define PIN_LED PIN(1,1)
41#define GPIO_LED GPIO(0,8)
42
43void spifi_init(void);
44void spifi_page_program(u32 addr, u32 *ptr, u32 count);
45void spifi_sector_erase(u32 addr);
46int spifi_verify_erased(u32 addr, u32 count);
47int spifi_verify_page(u32 addr, u32 *ptr);
48
49static event_t txevt = EVENT_INITIAL_VALUE(txevt, 0, 0);
50static event_t rxevt = EVENT_INITIAL_VALUE(rxevt, 0, 0);
51
52static udc_request_t *txreq;
53static udc_request_t *rxreq;
54static udc_endpoint_t *txept;
55static udc_endpoint_t *rxept;
56
57static volatile int online;
58static volatile int txstatus;
59static volatile int rxstatus;
60static volatile unsigned rxactual;
61
62static void lpcboot_notify(udc_gadget_t *gadget, unsigned event) {
63 if (event == UDC_EVENT_ONLINE) {
64 online = 1;
65 } else {
66 online = 0;
67 }
68}
69
70static void rx_complete(udc_request_t *req, unsigned actual, int status) {
71 rxactual = actual;
72 rxstatus = status;
73 event_signal(&rxevt, 0);
74}
75
76static void tx_complete(udc_request_t *req, unsigned actual, int status) {
77 txstatus = status;
78 event_signal(&txevt, 0);
79}
80
81void usb_xmit(void *data, unsigned len) {
82 event_unsignal(&txevt);
83 txreq->buffer = data;
84 txreq->length = len;
85 txstatus = 1;
86 udc_request_queue(txept, txreq);
87 event_wait(&txevt);
88}
89
90int usb_recv(void *data, unsigned len, lk_time_t timeout) {
91 event_unsignal(&rxevt);
92 rxreq->buffer = data;
93 rxreq->length = len;
94 rxstatus = 1;
95 udc_request_queue(rxept, rxreq);
96 if (event_wait_timeout(&rxevt, timeout)) {
97 return ERR_TIMED_OUT;
98 }
99 return rxactual;
100}
101
102static udc_device_t lpcboot_device = {
103 .vendor_id = 0x1209,
104 .product_id = 0x5039,
105 .version_id = 0x0100,
106};
107
108static udc_endpoint_t *lpcboot_endpoints[2];
109
110static udc_gadget_t lpcboot_gadget = {
111 .notify = lpcboot_notify,
112 .ifc_class = 0xFF,
113 .ifc_subclass = 0xFF,
114 .ifc_protocol = 0xFF,
115 .ifc_endpoints = 2,
116 .ept = lpcboot_endpoints,
117};
118
119static void lpcboot_init(const struct app_descriptor *app)
120{
121 udc_init(&lpcboot_device);
122 lpcboot_endpoints[0] = txept = udc_endpoint_alloc(UDC_BULK_IN, 512);
123 lpcboot_endpoints[1] = rxept = udc_endpoint_alloc(UDC_BULK_OUT, 512);
124 txreq = udc_request_alloc();
125 rxreq = udc_request_alloc();
126 rxreq->complete = rx_complete;
127 txreq->complete = tx_complete;
128 udc_register_gadget(&lpcboot_gadget);
129}
130
131#define RAM_BASE 0x10000000
132#define RAM_SIZE (128 * 1024)
133
134#define BOOT_BASE 0
135#define BOOT_SIZE (32 * 1024)
136
137#define ROM_BASE (32 * 1024)
138#define ROM_SIZE (128 * 1024)
139
140struct device_info {
141 u8 part[16];
142 u8 board[16];
143 u32 version;
144 u32 ram_base;
145 u32 ram_size;
146 u32 rom_base;
147 u32 rom_size;
148 u32 unused0;
149 u32 unused1;
150 u32 unused2;
151};
152
153struct device_info DEVICE = {
154 .part = "LPC43xx",
155 .board = TARGET,
156 .version = 0x0001000,
157 .ram_base = RAM_BASE,
158 .ram_size = RAM_SIZE,
159 .rom_base = ROM_BASE,
160 .rom_size = ROM_SIZE,
161};
162
163
164#define MAGIC1 0xAA113377
165#define MAGIC2 0xAA773311
166#define MAGIC1_ADDR 0x20003FF8
167#define MAGIC2_ADDR 0x20003FFC
168
169void boot_app(void) {
170 writel(MAGIC1, MAGIC1_ADDR);
171 writel(MAGIC2, MAGIC2_ADDR);
172}
173
174int erase_page(u32 addr) {
175 spifi_sector_erase(addr);
176 return spifi_verify_erased(addr, 0x1000/4);
177}
178
179int write_page(u32 addr, void *ptr) {
180 unsigned n;
181 u32 *x = ptr;
182 for (n = 0; n < 16; n++) {
183 spifi_page_program(addr, x, 256 / 4);
184 if (spifi_verify_page(addr, x)) return -1;
185 addr += 256;
186 x += (256 / 4);
187 }
188 return 0;
189}
190
191static uint32_t ram[4096/4];
192
193void handle(u32 magic, u32 cmd, u32 arg) {
194 u32 reply[2];
195 u32 addr, xfer;
196 int err = 0;
197
198 if (magic != 0xDB00A5A5)
199 return;
200
201 reply[0] = magic;
202 reply[1] = -1;
203
204 switch (cmd) {
205 case 'E':
206 reply[1] = erase_page(ROM_BASE);
207 break;
208 case 'W':
209 case 'w':
210 if (cmd == 'W') {
211 if (arg > ROM_SIZE)
212 break;
213 addr = ROM_BASE;
214 } else {
215 if (arg > BOOT_SIZE)
216 break;
217 addr = BOOT_BASE;
218 }
219 reply[1] = 0;
220 usb_xmit(reply, 8);
221 while (arg > 0) {
222 xfer = (arg > 4096) ? 4096 : arg;
223 usb_recv(ram, xfer, INFINITE_TIME);
224 if (!err) err = erase_page(addr);
225 if (!err) err = write_page(addr, ram);
226 addr += 4096;
227 arg -= xfer;
228 }
229 printf("flash %s\n", err ? "ERROR" : "OK");
230 reply[1] = err;
231 break;
232#if WITH_BOOT_TO_RAM
233 case 'X':
234 if (arg > RAM_SIZE)
235 break;
236 reply[1] = 0;
237 usb_xmit(reply, 8);
238 usb_recv(ram, arg);
239 usb_xmit(reply, 8);
240
241 /* let last txn clear */
242 usb_recv_timeout(buf, 64, 10);
243
244 boot_image(ram);
245 break;
246#endif
247 case 'Q':
248 reply[1] = 0;
249 usb_xmit(reply, 8);
250 usb_xmit(&DEVICE, sizeof(DEVICE));
251 return;
252 case 'A':
253 boot_app();
254 case 'R':
255 /* reboot "normally" */
256 reply[1] = 0;
257 usb_xmit(reply, 8);
258 udc_stop();
259 platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
260 default:
261 break;
262 }
263 usb_xmit(reply, 8);
264}
265
266static short led_idx = 0;
267static short led_delay[] = { 500, 100, 100, 100, };
268static short led_state[] = { 1, 0, 1, 0, };
269static timer_t led_timer = TIMER_INITIAL_VALUE(led_timer);
270
271static enum handler_return led_timer_cb(timer_t *timer, lk_time_t now, void *arg) {
272 gpio_set(GPIO_LED, led_state[led_idx]);
273 timer_set_oneshot(timer, led_delay[led_idx], led_timer_cb, NULL);
274 led_idx++;
275 if (led_idx == (sizeof(led_state)/sizeof(led_state[0]))) {
276 led_idx = 0;
277 }
278 return 0;
279}
280
281static void lpcboot_entry(const struct app_descriptor *app, void *args)
282{
283 lk_time_t timeout;
284 int r;
285 u32 buf[64/4];
286
287#if 0
288 timeout = INFINITE_TIME;
289#else
290 if (readl(32768) != 0) {
291 timeout = 3000;
292 } else {
293 timeout = INFINITE_TIME;
294 }
295#endif
296
297 pin_config(PIN_LED, PIN_MODE(0) | PIN_PLAIN);
298 gpio_config(GPIO_LED, GPIO_OUTPUT);
299 led_timer_cb(&led_timer, 0, NULL);
300
301 udc_start();
302 spifi_init();
303 for (;;) {
304 if (!online) {
305 thread_yield();
306 continue;
307 }
308 r = usb_recv(buf, 64, timeout);
309 if (r == ERR_TIMED_OUT) {
310 boot_app();
311 platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
312 }
313 if (r == 12) {
314 handle(buf[0], buf[1], buf[2]);
315 timeout = INFINITE_TIME;
316 }
317 }
318}
319
320APP_START(usbtest)
321 .init = lpcboot_init,
322 .entry = lpcboot_entry,
323APP_END
324
325