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 <cfi_flash.h>
56 const char *hr = "======================================================================\n";
58 static void key_handler(enum key_codes code, enum key_states state);
59 static void cmd_handler(uint8_t dlci, struct msgb *msg);
63 static void flush_uart(void) {
65 for(i = 0; i < 500; i++) {
66 uart_poll(SERCOMM_UART_NR);
71 static void device_poweroff(void) {
76 static void device_reset(void) {
81 static void device_enter_loader(unsigned char bootrom) {
84 calypso_bootrom(bootrom);
85 void (*entry)( void ) = (void (*)(void))0;
89 static void device_jump(void *entry) {
92 void (*f)( void ) = (void (*)(void))entry;
97 loader_send_simple(struct msgb *msg, uint8_t dlci, uint8_t command) {
98 msgb_put_u8(msg, command);
99 sercomm_sendmsg(dlci, msg);
102 extern unsigned char _start;
105 loader_send_init(uint8_t dlci) {
106 struct msgb *msg = sercomm_alloc_msgb(9);
107 msgb_put_u8(msg, LOADER_INIT);
108 msgb_put_u32(msg, 0);
109 msgb_put_u32(msg, &_start);
110 sercomm_sendmsg(dlci, msg);
115 extern void puts_asm(char *s);
116 extern void putchar_asm(uint32_t c);
118 static const uint8_t phone_ack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
123 for(i = 0; i < sizeof(phone_ack); i++) {
124 putchar_asm(phone_ack[i]);
127 /* Always disable wdt (some platforms enable it on boot) */
130 /* Initialize TWL3025 for power control */
137 /* Initialize UART without interrupts */
138 uart_init(SERCOMM_UART_NR, 0);
139 uart_baudrate(SERCOMM_UART_NR, UART_115200);
141 /* Initialize HDLC subsystem */
145 puts("\n\nOSMOCOM Calypso loader (revision " GIT_REVISION ")\n");
148 /* Initialize flash driver */
149 if(flash_init(&the_flash, 0)) {
150 puts("Failed to initialize flash!\n");
153 /* Identify environment */
154 printf("Running on %s in environment %s\n", manifest_board, manifest_environment);
156 /* Set up a key handler for powering off */
157 keypad_set_handler(&key_handler);
159 /* Set up loader communications */
160 sercomm_register_rx_cb(SC_DLCI_LOADER, &cmd_handler);
162 /* Notify any running osmoload about our startup */
163 loader_send_init(SC_DLCI_LOADER);
165 /* Wait for events */
168 uart_poll(SERCOMM_UART_NR);
176 static void cmd_handler(uint8_t dlci, struct msgb *msg) {
177 if(msg->data_len < 1) {
181 uint8_t command = msgb_get_u8(msg);
194 struct msgb *reply = sercomm_alloc_msgb(256); // XXX
197 printf("Failed to allocate reply buffer!\n");
204 loader_send_simple(reply, dlci, LOADER_PING);
208 loader_send_simple(reply, dlci, LOADER_RESET);
212 case LOADER_POWEROFF:
213 loader_send_simple(reply, dlci, LOADER_POWEROFF);
217 case LOADER_ENTER_ROM_LOADER:
218 loader_send_simple(reply, dlci, LOADER_ENTER_ROM_LOADER);
219 device_enter_loader(1);
222 case LOADER_ENTER_FLASH_LOADER:
223 loader_send_simple(reply, dlci, LOADER_ENTER_FLASH_LOADER);
224 device_enter_loader(0);
227 case LOADER_MEM_READ:
229 nbytes = msgb_get_u8(msg);
230 address = msgb_get_u32(msg);
232 crc = crc16(0, (void*)address, nbytes);
234 msgb_put_u8(reply, LOADER_MEM_READ);
235 msgb_put_u8(reply, nbytes);
236 msgb_put_u16(reply, crc);
237 msgb_put_u32(reply, address);
239 memcpy(msgb_put(reply, nbytes), (void*)address, nbytes);
241 sercomm_sendmsg(dlci, reply);
245 case LOADER_MEM_WRITE:
247 nbytes = msgb_get_u8(msg);
248 crc = msgb_get_u16(msg);
249 address = msgb_get_u32(msg);
251 data = msgb_get(msg, nbytes);
253 mycrc = crc16(0, data, nbytes);
256 memcpy((void*)address, data, nbytes);
259 msgb_put_u8(reply, LOADER_MEM_WRITE);
260 msgb_put_u8(reply, nbytes);
261 msgb_put_u16(reply, mycrc);
262 msgb_put_u32(reply, address);
264 sercomm_sendmsg(dlci, reply);
270 address = msgb_get_u32(msg);
272 msgb_put_u8(reply, LOADER_JUMP);
273 msgb_put_u32(reply, address);
275 sercomm_sendmsg(dlci, reply);
277 device_jump((void*)address);
281 case LOADER_FLASH_INFO:
283 msgb_put_u8(reply, LOADER_FLASH_INFO);
284 msgb_put_u8(reply, 1); // nchips
287 msgb_put_u32(reply, the_flash.f_base);
288 msgb_put_u32(reply, the_flash.f_size);
289 msgb_put_u8(reply, the_flash.f_nregions);
292 for(i = 0; i < the_flash.f_nregions; i++) {
293 msgb_put_u32(reply, the_flash.f_regions[i].fr_bnum);
294 msgb_put_u32(reply, the_flash.f_regions[i].fr_bsize);
297 sercomm_sendmsg(dlci, reply);
301 case LOADER_FLASH_ERASE:
302 case LOADER_FLASH_UNLOCK:
303 case LOADER_FLASH_LOCK:
304 case LOADER_FLASH_LOCKDOWN:
306 chip = msgb_get_u8(msg);
307 address = msgb_get_u32(msg);
309 if(command == LOADER_FLASH_ERASE) {
310 res = flash_block_erase(&the_flash, address);
312 if(command == LOADER_FLASH_UNLOCK) {
313 res = flash_block_unlock(&the_flash, address);
315 if(command == LOADER_FLASH_LOCK) {
316 res = flash_block_lock(&the_flash, address);
318 if(command == LOADER_FLASH_LOCKDOWN) {
319 res = flash_block_lockdown(&the_flash, address);
322 msgb_put_u8(reply, command);
323 msgb_put_u8(reply, chip);
324 msgb_put_u32(reply, address);
325 msgb_put_u32(reply, (res != 0));
327 sercomm_sendmsg(dlci, reply);
331 case LOADER_FLASH_GETLOCK:
333 chip = msgb_get_u8(msg);
334 address = msgb_get_u32(msg);
336 lock = flash_block_getlock(&the_flash, address);
338 msgb_put_u8(reply, command);
339 msgb_put_u8(reply, chip);
340 msgb_put_u32(reply, address);
344 msgb_put_u32(reply, LOADER_FLASH_UNLOCKED);
347 msgb_put_u32(reply, LOADER_FLASH_LOCKED);
349 case FLASH_LOCKED_DOWN:
350 msgb_put_u32(reply, LOADER_FLASH_LOCKED_DOWN);
353 msgb_put_u32(reply, 0xFFFFFFFF);
357 sercomm_sendmsg(dlci, reply);
361 case LOADER_FLASH_PROGRAM:
363 nbytes = msgb_get_u8(msg);
364 crc = msgb_get_u16(msg);
365 msgb_get_u8(msg); // XXX align
366 chip = msgb_get_u8(msg);
367 address = msgb_get_u32(msg);
369 data = msgb_get(msg, nbytes);
371 mycrc = crc16(0, data, nbytes);
374 res = flash_program(&the_flash, address, data, nbytes);
377 msgb_put_u8(reply, LOADER_FLASH_PROGRAM);
378 msgb_put_u8(reply, nbytes);
379 msgb_put_u16(reply, mycrc);
380 msgb_put_u8(reply, 0); // XXX align
381 msgb_put_u8(reply, chip);
382 msgb_put_u32(reply, address);
384 msgb_put_u32(reply, (uint32_t)res); // XXX
386 sercomm_sendmsg(dlci, reply);
391 printf("unknown command %d\n", command);
403 static void key_handler(enum key_codes code, enum key_states state)
405 if (state != PRESSED)
410 puts("Powering off due to keypress.\n");
414 puts("Resetting due to keypress.\n");