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