1 /* boot loader for Calypso phones */
3 /* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
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.
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.
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.
36 #include <osmocore/crc16.h>
38 #include <abb/twl3025.h>
39 #include <rf/trf6151.h>
41 #include <comm/sercomm.h>
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>
51 #include <flash/cfi_flash.h>
57 "======================================================================\n";
59 static void key_handler(enum key_codes code, enum key_states state);
60 static void cmd_handler(uint8_t dlci, struct msgb *msg);
64 static void flush_uart(void)
67 for (i = 0; i < 500; i++) {
68 uart_poll(SERCOMM_UART_NR);
73 static void device_poweroff(void)
79 static void device_reset(void)
85 static void device_enter_loader(unsigned char bootrom)
89 calypso_bootrom(bootrom);
90 void (*entry) (void) = (void (*)(void))0;
94 static void device_jump(void *entry)
98 void (*f) (void) = (void (*)(void))entry;
102 static void loader_send_simple(struct msgb *msg, uint8_t dlci, uint8_t command)
104 msgb_put_u8(msg, command);
105 sercomm_sendmsg(dlci, msg);
108 extern unsigned char _start;
110 static void loader_send_init(uint8_t dlci)
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);
121 extern void putchar_asm(uint32_t c);
123 static const uint8_t phone_ack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
127 /* Simulate a compal loader saying "ACK" */
129 for (i = 0; i < sizeof(phone_ack); i++) {
130 putchar_asm(phone_ack[i]);
133 /* Always disable wdt (some platforms enable it on boot) */
136 /* Disable the bootrom mapping */
139 /* Initialize TWL3025 for power control */
146 /* Initialize UART without interrupts */
147 uart_init(SERCOMM_UART_NR, 0);
148 uart_baudrate(SERCOMM_UART_NR, UART_115200);
150 /* Initialize HDLC subsystem */
154 puts("\n\nOSMOCOM Loader (revision " GIT_REVISION ")\n");
157 /* Identify environment */
158 printf("Running on %s in environment %s\n", manifest_board,
159 manifest_environment);
161 /* Initialize flash driver */
162 if (flash_init(&the_flash, 0)) {
163 puts("Failed to initialize flash!\n");
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);
170 for (i = 0; i < the_flash.f_nregions; i++) {
171 printf(" Region %d of %d pages with %d bytes each.\n",
173 the_flash.f_regions[i].fr_bnum,
174 the_flash.f_regions[i].fr_bsize);
179 /* Set up a key handler for powering off */
180 keypad_set_handler(&key_handler);
182 /* Set up loader communications */
183 sercomm_register_rx_cb(SC_DLCI_LOADER, &cmd_handler);
185 /* Notify any running osmoload about our startup */
186 loader_send_init(SC_DLCI_LOADER);
188 /* Wait for events */
191 uart_poll(SERCOMM_UART_NR);
199 static void cmd_handler(uint8_t dlci, struct msgb *msg)
201 if (msg->data_len < 1) {
205 uint8_t command = msgb_get_u8(msg);
218 struct msgb *reply = sercomm_alloc_msgb(256); // XXX
221 printf("Failed to allocate reply buffer!\n");
228 loader_send_simple(reply, dlci, LOADER_PING);
232 loader_send_simple(reply, dlci, LOADER_RESET);
236 case LOADER_POWEROFF:
237 loader_send_simple(reply, dlci, LOADER_POWEROFF);
241 case LOADER_ENTER_ROM_LOADER:
242 loader_send_simple(reply, dlci, LOADER_ENTER_ROM_LOADER);
243 device_enter_loader(1);
246 case LOADER_ENTER_FLASH_LOADER:
247 loader_send_simple(reply, dlci, LOADER_ENTER_FLASH_LOADER);
248 device_enter_loader(0);
251 case LOADER_MEM_READ:
253 nbytes = msgb_get_u8(msg);
254 address = msgb_get_u32(msg);
256 crc = crc16(0, (void *)address, nbytes);
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);
263 memcpy(msgb_put(reply, nbytes), (void *)address, nbytes);
265 sercomm_sendmsg(dlci, reply);
269 case LOADER_MEM_WRITE:
271 nbytes = msgb_get_u8(msg);
272 crc = msgb_get_u16(msg);
273 address = msgb_get_u32(msg);
275 data = msgb_get(msg, nbytes);
277 mycrc = crc16(0, data, nbytes);
280 memcpy((void *)address, data, nbytes);
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);
288 sercomm_sendmsg(dlci, reply);
294 address = msgb_get_u32(msg);
296 msgb_put_u8(reply, LOADER_JUMP);
297 msgb_put_u32(reply, address);
299 sercomm_sendmsg(dlci, reply);
301 device_jump((void *)address);
305 case LOADER_FLASH_INFO:
307 msgb_put_u8(reply, LOADER_FLASH_INFO);
308 msgb_put_u8(reply, 1); // nchips
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);
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);
321 sercomm_sendmsg(dlci, reply);
325 case LOADER_FLASH_ERASE:
326 case LOADER_FLASH_UNLOCK:
327 case LOADER_FLASH_LOCK:
328 case LOADER_FLASH_LOCKDOWN:
330 chip = msgb_get_u8(msg);
331 address = msgb_get_u32(msg);
333 if (command == LOADER_FLASH_ERASE) {
334 res = flash_block_erase(&the_flash, address);
336 if (command == LOADER_FLASH_UNLOCK) {
337 res = flash_block_unlock(&the_flash, address);
339 if (command == LOADER_FLASH_LOCK) {
340 res = flash_block_lock(&the_flash, address);
342 if (command == LOADER_FLASH_LOCKDOWN) {
343 res = flash_block_lockdown(&the_flash, address);
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));
351 sercomm_sendmsg(dlci, reply);
355 case LOADER_FLASH_GETLOCK:
357 chip = msgb_get_u8(msg);
358 address = msgb_get_u32(msg);
360 lock = flash_block_getlock(&the_flash, address);
362 msgb_put_u8(reply, command);
363 msgb_put_u8(reply, chip);
364 msgb_put_u32(reply, address);
368 msgb_put_u32(reply, LOADER_FLASH_UNLOCKED);
371 msgb_put_u32(reply, LOADER_FLASH_LOCKED);
373 case FLASH_LOCKED_DOWN:
374 msgb_put_u32(reply, LOADER_FLASH_LOCKED_DOWN);
377 msgb_put_u32(reply, 0xFFFFFFFF);
381 sercomm_sendmsg(dlci, reply);
385 case LOADER_FLASH_PROGRAM:
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);
393 data = msgb_get(msg, nbytes);
395 mycrc = crc16(0, data, nbytes);
398 res = flash_program(&the_flash, address, data, nbytes);
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);
408 msgb_put_u32(reply, (uint32_t) res); // XXX
410 sercomm_sendmsg(dlci, reply);
415 printf("unknown command %d\n", command);
427 static void key_handler(enum key_codes code, enum key_states state)
429 if (state != PRESSED)
434 puts("Powering off due to keypress.\n");
438 puts("Resetting due to keypress.\n");