firmware: removed flash safety hack
[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 <cfi_flash.h>
52
53 #include "protocol.h"
54
55 /* Main Program */
56 const char *hr = "======================================================================\n";
57
58 static void key_handler(enum key_codes code, enum key_states state);
59 static void cmd_handler(uint8_t dlci, struct msgb *msg);
60
61 int flag = 0;
62
63 static void flush_uart(void) {
64         unsigned i;
65         for(i = 0; i < 500; i++) {
66                 uart_poll(SERCOMM_UART_NR);
67                 delay_ms(1);
68         }
69 }
70
71 static void device_poweroff(void) {
72         flush_uart();
73         twl3025_power_off();
74 }
75
76 static void device_reset(void) {
77         flush_uart();
78         wdog_reset();
79 }
80
81 static void device_enter_loader(unsigned char bootrom) {
82         flush_uart();
83
84         calypso_bootrom(bootrom);
85         void (*entry)( void ) = (void (*)(void))0;
86         entry();
87 }
88
89 static void device_jump(void *entry) {
90         flush_uart();
91
92         void (*f)( void ) = (void (*)(void))entry;
93         f();
94 }
95
96 static void
97 loader_send_simple(struct msgb *msg, uint8_t dlci, uint8_t command) {
98         msgb_put_u8(msg, command);
99         sercomm_sendmsg(dlci, msg);
100 }
101
102 extern unsigned char _start;
103
104 static void
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);
111 }
112
113 flash_t the_flash;
114
115 extern void puts_asm(char *s);
116 extern void putchar_asm(uint32_t c);
117
118 static const uint8_t phone_ack[]     = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
119
120 int main(void)
121 {
122         int i = 0;
123         for(i = 0; i < sizeof(phone_ack); i++) {
124                 putchar_asm(phone_ack[i]);
125         }
126
127         /* Always disable wdt (some platforms enable it on boot) */
128         wdog_enable(0);
129
130         /* Initialize TWL3025 for power control */
131         twl3025_init();
132
133         /* Backlight */
134         bl_mode_pwl(1);
135         bl_level(50);
136
137         /* Initialize UART without interrupts */
138         uart_init(SERCOMM_UART_NR, 0);
139         uart_baudrate(SERCOMM_UART_NR, UART_115200);
140
141         /* Initialize HDLC subsystem */
142         sercomm_init();
143
144         /* Say hi */
145         puts("\n\nOSMOCOM Calypso loader (revision " GIT_REVISION ")\n");
146         puts(hr);
147
148         /* Initialize flash driver */
149         if(flash_init(&the_flash, 0)) {
150                 puts("Failed to initialize flash!\n");
151         }
152
153         /* Identify environment */
154         printf("Running on %s in environment %s\n", manifest_board, manifest_environment);
155
156         /* Set up a key handler for powering off */
157         keypad_set_handler(&key_handler);
158
159         /* Set up loader communications */
160         sercomm_register_rx_cb(SC_DLCI_LOADER, &cmd_handler);
161
162         /* Notify any running osmoload about our startup */
163         loader_send_init(SC_DLCI_LOADER);
164
165         /* Wait for events */
166         while (1) {
167                 keypad_poll();
168                 uart_poll(SERCOMM_UART_NR);
169         }
170
171         /* NOT REACHED */
172
173         twl3025_power_off();
174 }
175
176 static void cmd_handler(uint8_t dlci, struct msgb *msg) {
177         if(msg->data_len < 1) {
178                 return;
179         }
180
181         uint8_t command = msgb_get_u8(msg);
182
183         int res;
184
185         flash_lock_t lock;
186
187         void *data;
188
189         uint8_t  chip;
190         uint8_t  nbytes;
191         uint16_t crc, mycrc;
192         uint32_t address;
193
194         struct msgb *reply = sercomm_alloc_msgb(256); // XXX
195
196         if(!reply) {
197                 printf("Failed to allocate reply buffer!\n");
198                 goto out;
199         }
200
201         switch(command) {
202
203         case LOADER_PING:
204                 loader_send_simple(reply, dlci, LOADER_PING);
205                 break;
206
207         case LOADER_RESET:
208                 loader_send_simple(reply, dlci, LOADER_RESET);
209                 device_reset();
210                 break;
211
212         case LOADER_POWEROFF:
213                 loader_send_simple(reply, dlci, LOADER_POWEROFF);
214                 device_poweroff();
215                 break;
216
217         case LOADER_ENTER_ROM_LOADER:
218                 loader_send_simple(reply, dlci, LOADER_ENTER_ROM_LOADER);
219                 device_enter_loader(1);
220                 break;
221
222         case LOADER_ENTER_FLASH_LOADER:
223                 loader_send_simple(reply, dlci, LOADER_ENTER_FLASH_LOADER);
224                 device_enter_loader(0);
225                 break;
226
227         case LOADER_MEM_READ:
228
229                 nbytes = msgb_get_u8(msg);
230                 address = msgb_get_u32(msg);
231
232                 crc = crc16(0, (void*)address, nbytes);
233
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);
238
239                 memcpy(msgb_put(reply, nbytes), (void*)address, nbytes);
240
241                 sercomm_sendmsg(dlci, reply);
242
243                 break;
244
245         case LOADER_MEM_WRITE:
246
247                 nbytes = msgb_get_u8(msg);
248                 crc = msgb_get_u16(msg);
249                 address = msgb_get_u32(msg);
250
251                 data = msgb_get(msg, nbytes);
252
253                 mycrc = crc16(0, data, nbytes);
254
255                 if(mycrc == crc) {
256                         memcpy((void*)address, data, nbytes);
257                 }
258
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);
263
264                 sercomm_sendmsg(dlci, reply);
265
266                 break;
267
268         case LOADER_JUMP:
269
270                 address = msgb_get_u32(msg);
271
272                 msgb_put_u8(reply, LOADER_JUMP);
273                 msgb_put_u32(reply, address);
274
275                 sercomm_sendmsg(dlci, reply);
276
277                 device_jump((void*)address);
278
279                 break;
280
281         case LOADER_FLASH_INFO:
282
283                 msgb_put_u8(reply, LOADER_FLASH_INFO);
284                 msgb_put_u8(reply, 1); // nchips
285
286                 // chip 1
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);
290
291                 int i;
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);
295                 }
296
297                 sercomm_sendmsg(dlci, reply);
298
299                 break;
300
301         case LOADER_FLASH_ERASE:
302         case LOADER_FLASH_UNLOCK:
303         case LOADER_FLASH_LOCK:
304         case LOADER_FLASH_LOCKDOWN:
305
306                 chip = msgb_get_u8(msg);
307                 address = msgb_get_u32(msg);
308
309                 if(command == LOADER_FLASH_ERASE) {
310                         res = flash_block_erase(&the_flash, address);
311                 }
312                 if(command == LOADER_FLASH_UNLOCK) {
313                         res = flash_block_unlock(&the_flash, address);
314                 }
315                 if(command == LOADER_FLASH_LOCK) {
316                         res = flash_block_lock(&the_flash, address);
317                 }
318                 if(command == LOADER_FLASH_LOCKDOWN) {
319                         res = flash_block_lockdown(&the_flash, address);
320                 }
321
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));
326
327                 sercomm_sendmsg(dlci, reply);
328
329                 break;
330
331         case LOADER_FLASH_GETLOCK:
332
333                 chip = msgb_get_u8(msg);
334                 address = msgb_get_u32(msg);
335
336                 lock = flash_block_getlock(&the_flash, address);
337
338                 msgb_put_u8(reply, command);
339                 msgb_put_u8(reply, chip);
340                 msgb_put_u32(reply, address);
341
342                 switch(lock) {
343                 case FLASH_UNLOCKED:
344                         msgb_put_u32(reply, LOADER_FLASH_UNLOCKED);
345                         break;
346                 case FLASH_LOCKED:
347                         msgb_put_u32(reply, LOADER_FLASH_LOCKED);
348                         break;
349                 case FLASH_LOCKED_DOWN:
350                         msgb_put_u32(reply, LOADER_FLASH_LOCKED_DOWN);
351                         break;
352                 default:
353                         msgb_put_u32(reply, 0xFFFFFFFF);
354                         break;
355                 }
356
357                 sercomm_sendmsg(dlci, reply);
358
359                 break;
360
361         case LOADER_FLASH_PROGRAM:
362
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);
368
369                 data = msgb_get(msg, nbytes);
370
371                 mycrc = crc16(0, data, nbytes);
372
373                 if(mycrc == crc) {
374                         res = flash_program(&the_flash, address, data, nbytes);
375                 }
376
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);
383
384                 msgb_put_u32(reply, (uint32_t)res); // XXX
385
386                 sercomm_sendmsg(dlci, reply);
387
388                 break;
389
390         default:
391                 printf("unknown command %d\n", command);
392
393                 msgb_free(reply);
394
395                 break;
396         }
397
398  out:
399
400         msgb_free(msg);
401 }
402
403 static void key_handler(enum key_codes code, enum key_states state)
404 {
405         if (state != PRESSED)
406                 return;
407
408         switch (code) {
409         case KEY_POWER:
410                 puts("Powering off due to keypress.\n");
411                 device_poweroff();
412                 break;
413         case KEY_OK:
414                 puts("Resetting due to keypress.\n");
415                 device_reset();
416                 break;
417         default:
418                 break;
419         }
420 }