target/loader: disable bootrom mapping
[osmocom-bb.git] / src / target / firmware / apps / loader / main.c
1 /* boot loader for Calypso phones */
2
3 /* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <debug.h>
28 #include <memory.h>
29 #include <delay.h>
30 #include <rffe.h>
31 #include <keypad.h>
32 #include <board.h>
33 #include <console.h>
34 #include <manifest.h>
35
36 #include <osmocore/crc16.h>
37
38 #include <abb/twl3025.h>
39 #include <rf/trf6151.h>
40
41 #include <comm/sercomm.h>
42
43 #include <calypso/clock.h>
44 #include <calypso/tpu.h>
45 #include <calypso/tsp.h>
46 #include <calypso/irq.h>
47 #include <calypso/misc.h>
48 #include <calypso/uart.h>
49 #include <calypso/timer.h>
50
51 #include <flash/cfi_flash.h>
52
53 #include "protocol.h"
54
55 /* Main Program */
56 const char *hr =
57     "======================================================================\n";
58
59 static void key_handler(enum key_codes code, enum key_states state);
60 static void cmd_handler(uint8_t dlci, struct msgb *msg);
61
62 int flag = 0;
63
64 static void flush_uart(void)
65 {
66         unsigned i;
67         for (i = 0; i < 500; i++) {
68                 uart_poll(SERCOMM_UART_NR);
69                 delay_ms(1);
70         }
71 }
72
73 static void device_poweroff(void)
74 {
75         flush_uart();
76         twl3025_power_off();
77 }
78
79 static void device_reset(void)
80 {
81         flush_uart();
82         wdog_reset();
83 }
84
85 static void device_enter_loader(unsigned char bootrom)
86 {
87         flush_uart();
88
89         calypso_bootrom(bootrom);
90         void (*entry) (void) = (void (*)(void))0;
91         entry();
92 }
93
94 static void device_jump(void *entry)
95 {
96         flush_uart();
97
98         void (*f) (void) = (void (*)(void))entry;
99         f();
100 }
101
102 static void loader_send_simple(struct msgb *msg, uint8_t dlci, uint8_t command)
103 {
104         msgb_put_u8(msg, command);
105         sercomm_sendmsg(dlci, msg);
106 }
107
108 extern unsigned char _start;
109
110 static void loader_send_init(uint8_t dlci)
111 {
112         struct msgb *msg = sercomm_alloc_msgb(9);
113         msgb_put_u8(msg, LOADER_INIT);
114         msgb_put_u32(msg, 0);
115         msgb_put_u32(msg, &_start);
116         sercomm_sendmsg(dlci, msg);
117 }
118
119 flash_t the_flash;
120
121 extern void putchar_asm(uint32_t c);
122
123 static const uint8_t phone_ack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
124
125 int main(void)
126 {
127         /* Simulate a compal loader saying "ACK" */
128         int i = 0;
129         for (i = 0; i < sizeof(phone_ack); i++) {
130                 putchar_asm(phone_ack[i]);
131         }
132
133         /* Always disable wdt (some platforms enable it on boot) */
134         wdog_enable(0);
135
136         /* Disable the bootrom mapping */
137         calypso_bootrom(0);
138
139         /* Initialize TWL3025 for power control */
140         twl3025_init();
141
142         /* Backlight */
143         bl_mode_pwl(1);
144         bl_level(50);
145
146         /* Initialize UART without interrupts */
147         uart_init(SERCOMM_UART_NR, 0);
148         uart_baudrate(SERCOMM_UART_NR, UART_115200);
149
150         /* Initialize HDLC subsystem */
151         sercomm_init();
152
153         /* Say hi */
154         puts("\n\nOSMOCOM Loader (revision " GIT_REVISION ")\n");
155         puts(hr);
156
157         /* Identify environment */
158         printf("Running on %s in environment %s\n", manifest_board,
159                manifest_environment);
160
161         /* Initialize flash driver */
162         if (flash_init(&the_flash, 0)) {
163                 puts("Failed to initialize flash!\n");
164         } else {
165                 printf("Found flash of %d bytes at 0x%x with %d regions\n",
166                        the_flash.f_size, the_flash.f_base,
167                        the_flash.f_nregions);
168
169                 int i;
170                 for (i = 0; i < the_flash.f_nregions; i++) {
171                         printf("  Region %d of %d pages with %d bytes each.\n",
172                                i,
173                                the_flash.f_regions[i].fr_bnum,
174                                the_flash.f_regions[i].fr_bsize);
175                 }
176
177         }
178
179         /* Set up a key handler for powering off */
180         keypad_set_handler(&key_handler);
181
182         /* Set up loader communications */
183         sercomm_register_rx_cb(SC_DLCI_LOADER, &cmd_handler);
184
185         /* Notify any running osmoload about our startup */
186         loader_send_init(SC_DLCI_LOADER);
187
188         /* Wait for events */
189         while (1) {
190                 keypad_poll();
191                 uart_poll(SERCOMM_UART_NR);
192         }
193
194         /* NOT REACHED */
195
196         twl3025_power_off();
197 }
198
199 static void cmd_handler(uint8_t dlci, struct msgb *msg)
200 {
201         if (msg->data_len < 1) {
202                 return;
203         }
204
205         uint8_t command = msgb_get_u8(msg);
206
207         int res;
208
209         flash_lock_t lock;
210
211         void *data;
212
213         uint8_t chip;
214         uint8_t nbytes;
215         uint16_t crc, mycrc;
216         uint32_t address;
217
218         struct msgb *reply = sercomm_alloc_msgb(256);   // XXX
219
220         if (!reply) {
221                 printf("Failed to allocate reply buffer!\n");
222                 goto out;
223         }
224
225         switch (command) {
226
227         case LOADER_PING:
228                 loader_send_simple(reply, dlci, LOADER_PING);
229                 break;
230
231         case LOADER_RESET:
232                 loader_send_simple(reply, dlci, LOADER_RESET);
233                 device_reset();
234                 break;
235
236         case LOADER_POWEROFF:
237                 loader_send_simple(reply, dlci, LOADER_POWEROFF);
238                 device_poweroff();
239                 break;
240
241         case LOADER_ENTER_ROM_LOADER:
242                 loader_send_simple(reply, dlci, LOADER_ENTER_ROM_LOADER);
243                 device_enter_loader(1);
244                 break;
245
246         case LOADER_ENTER_FLASH_LOADER:
247                 loader_send_simple(reply, dlci, LOADER_ENTER_FLASH_LOADER);
248                 device_enter_loader(0);
249                 break;
250
251         case LOADER_MEM_READ:
252
253                 nbytes = msgb_get_u8(msg);
254                 address = msgb_get_u32(msg);
255
256                 crc = crc16(0, (void *)address, nbytes);
257
258                 msgb_put_u8(reply, LOADER_MEM_READ);
259                 msgb_put_u8(reply, nbytes);
260                 msgb_put_u16(reply, crc);
261                 msgb_put_u32(reply, address);
262
263                 memcpy(msgb_put(reply, nbytes), (void *)address, nbytes);
264
265                 sercomm_sendmsg(dlci, reply);
266
267                 break;
268
269         case LOADER_MEM_WRITE:
270
271                 nbytes = msgb_get_u8(msg);
272                 crc = msgb_get_u16(msg);
273                 address = msgb_get_u32(msg);
274
275                 data = msgb_get(msg, nbytes);
276
277                 mycrc = crc16(0, data, nbytes);
278
279                 if (mycrc == crc) {
280                         memcpy((void *)address, data, nbytes);
281                 }
282
283                 msgb_put_u8(reply, LOADER_MEM_WRITE);
284                 msgb_put_u8(reply, nbytes);
285                 msgb_put_u16(reply, mycrc);
286                 msgb_put_u32(reply, address);
287
288                 sercomm_sendmsg(dlci, reply);
289
290                 break;
291
292         case LOADER_JUMP:
293
294                 address = msgb_get_u32(msg);
295
296                 msgb_put_u8(reply, LOADER_JUMP);
297                 msgb_put_u32(reply, address);
298
299                 sercomm_sendmsg(dlci, reply);
300
301                 device_jump((void *)address);
302
303                 break;
304
305         case LOADER_FLASH_INFO:
306
307                 msgb_put_u8(reply, LOADER_FLASH_INFO);
308                 msgb_put_u8(reply, 1);  // nchips
309
310                 // chip 1
311                 msgb_put_u32(reply, the_flash.f_base);
312                 msgb_put_u32(reply, the_flash.f_size);
313                 msgb_put_u8(reply, the_flash.f_nregions);
314
315                 int i;
316                 for (i = 0; i < the_flash.f_nregions; i++) {
317                         msgb_put_u32(reply, the_flash.f_regions[i].fr_bnum);
318                         msgb_put_u32(reply, the_flash.f_regions[i].fr_bsize);
319                 }
320
321                 sercomm_sendmsg(dlci, reply);
322
323                 break;
324
325         case LOADER_FLASH_ERASE:
326         case LOADER_FLASH_UNLOCK:
327         case LOADER_FLASH_LOCK:
328         case LOADER_FLASH_LOCKDOWN:
329
330                 chip = msgb_get_u8(msg);
331                 address = msgb_get_u32(msg);
332
333                 if (command == LOADER_FLASH_ERASE) {
334                         res = flash_block_erase(&the_flash, address);
335                 }
336                 if (command == LOADER_FLASH_UNLOCK) {
337                         res = flash_block_unlock(&the_flash, address);
338                 }
339                 if (command == LOADER_FLASH_LOCK) {
340                         res = flash_block_lock(&the_flash, address);
341                 }
342                 if (command == LOADER_FLASH_LOCKDOWN) {
343                         res = flash_block_lockdown(&the_flash, address);
344                 }
345
346                 msgb_put_u8(reply, command);
347                 msgb_put_u8(reply, chip);
348                 msgb_put_u32(reply, address);
349                 msgb_put_u32(reply, (res != 0));
350
351                 sercomm_sendmsg(dlci, reply);
352
353                 break;
354
355         case LOADER_FLASH_GETLOCK:
356
357                 chip = msgb_get_u8(msg);
358                 address = msgb_get_u32(msg);
359
360                 lock = flash_block_getlock(&the_flash, address);
361
362                 msgb_put_u8(reply, command);
363                 msgb_put_u8(reply, chip);
364                 msgb_put_u32(reply, address);
365
366                 switch (lock) {
367                 case FLASH_UNLOCKED:
368                         msgb_put_u32(reply, LOADER_FLASH_UNLOCKED);
369                         break;
370                 case FLASH_LOCKED:
371                         msgb_put_u32(reply, LOADER_FLASH_LOCKED);
372                         break;
373                 case FLASH_LOCKED_DOWN:
374                         msgb_put_u32(reply, LOADER_FLASH_LOCKED_DOWN);
375                         break;
376                 default:
377                         msgb_put_u32(reply, 0xFFFFFFFF);
378                         break;
379                 }
380
381                 sercomm_sendmsg(dlci, reply);
382
383                 break;
384
385         case LOADER_FLASH_PROGRAM:
386
387                 nbytes = msgb_get_u8(msg);
388                 crc = msgb_get_u16(msg);
389                 msgb_get_u8(msg);       // XXX align
390                 chip = msgb_get_u8(msg);
391                 address = msgb_get_u32(msg);
392
393                 data = msgb_get(msg, nbytes);
394
395                 mycrc = crc16(0, data, nbytes);
396
397                 if (mycrc == crc) {
398                         res = flash_program(&the_flash, address, data, nbytes);
399                 }
400
401                 msgb_put_u8(reply, LOADER_FLASH_PROGRAM);
402                 msgb_put_u8(reply, nbytes);
403                 msgb_put_u16(reply, mycrc);
404                 msgb_put_u8(reply, 0);  // XXX align
405                 msgb_put_u8(reply, chip);
406                 msgb_put_u32(reply, address);
407
408                 msgb_put_u32(reply, (uint32_t) res);    // XXX
409
410                 sercomm_sendmsg(dlci, reply);
411
412                 break;
413
414         default:
415                 printf("unknown command %d\n", command);
416
417                 msgb_free(reply);
418
419                 break;
420         }
421
422  out:
423
424         msgb_free(msg);
425 }
426
427 static void key_handler(enum key_codes code, enum key_states state)
428 {
429         if (state != PRESSED)
430                 return;
431
432         switch (code) {
433         case KEY_POWER:
434                 puts("Powering off due to keypress.\n");
435                 device_poweroff();
436                 break;
437         case KEY_OK:
438                 puts("Resetting due to keypress.\n");
439                 device_reset();
440                 break;
441         default:
442                 break;
443         }
444 }