#include <stdio.h>
#include <string.h>
-#include <gsm.h>
#include <debug.h>
#include <memory.h>
+#include <delay.h>
#include <rffe.h>
#include <keypad.h>
#include <board.h>
#include <console.h>
+#include <manifest.h>
+
+#include <osmocore/crc16.h>
#include <abb/twl3025.h>
-#include <display/st7558.h>
#include <rf/trf6151.h>
#include <comm/sercomm.h>
#include <calypso/uart.h>
#include <calypso/timer.h>
-#include <layer1/sync.h>
-#include <layer1/tpu_window.h>
-
-#include <machine/endian.h>
+#include <cfi_flash.h>
#include "protocol.h"
-struct loader_mem_read {
- uint8_t cmd;
- uint8_t nbytes;
- uint32_t address;
- uint8_t data[0];
-} __attribute__((__packed__));
-
-uint32_t htonl(uint32_t hostlong) {
-#if BYTE_ORDER==LITTLE_ENDIAN
- return (hostlong>>24) | ((hostlong&0xff0000)>>8) |
- ((hostlong&0xff00)<<8) | (hostlong<<24);
-#else
- return hostlong;
-#endif
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+static void key_handler(enum key_codes code, enum key_states state);
+static void cmd_handler(uint8_t dlci, struct msgb *msg);
+
+int flag = 0;
+
+static void flush_uart(void) {
+ unsigned i;
+ for(i = 0; i < 500; i++) {
+ uart_poll(SERCOMM_UART_NR);
+ delay_ms(1);
+ }
}
-uint32_t ntohl(uint32_t hostlong) __attribute__((weak,alias("htonl")));
+static void device_poweroff(void) {
+ flush_uart();
+ twl3025_power_off();
+}
-uint16_t htons(uint16_t hostshort) {
-#if BYTE_ORDER==LITTLE_ENDIAN
- return ((hostshort>>8)&0xff) | (hostshort<<8);
-#else
- return hostshort;
-#endif
+static void device_reset(void) {
+ flush_uart();
+ wdog_reset();
}
-uint16_t ntohs(uint16_t hostshort) __attribute__((weak,alias("htons")));
+static void device_enter_loader(unsigned char bootrom) {
+ flush_uart();
-#define SCAN
+ calypso_bootrom(bootrom);
+ void (*entry)( void ) = (void (*)(void))0;
+ entry();
+}
-#ifdef SCAN
-/* if scanning is enabled, scan from 0 ... 124 */
-#define BASE_ARFCN 0
-#else
-/* fixed ARFCN in GSM1800 at which Harald has his GSM test license */
-#define BASE_ARFCN 871
-#endif
+static void device_jump(void *entry) {
+ flush_uart();
-/* FIXME: We need proper calibrated delay loops at some point! */
-void delay_us(unsigned int us)
-{
- volatile unsigned int i;
+ void (*f)( void ) = (void (*)(void))entry;
+ f();
+}
- for (i= 0; i < us*4; i++) { i; }
+static void
+loader_send_simple(struct msgb *msg, uint8_t dlci, uint8_t command) {
+ msgb_put_u8(msg, command);
+ sercomm_sendmsg(dlci, msg);
}
-void delay_ms(unsigned int ms)
-{
- volatile unsigned int i;
+extern unsigned char _start;
- for (i= 0; i < ms*1300; i++) { i; }
+static void
+loader_send_init(uint8_t dlci) {
+ struct msgb *msg = sercomm_alloc_msgb(9);
+ msgb_put_u8(msg, LOADER_INIT);
+ msgb_put_u32(msg, 0);
+ msgb_put_u32(msg, &_start);
+ sercomm_sendmsg(dlci, msg);
}
-/* Main Program */
-const char *hr = "======================================================================\n";
+flash_t the_flash;
-static void key_handler(enum key_codes code, enum key_states state);
-static void cmd_handler(uint8_t dlci, struct msgb *msg);
+extern void puts_asm(char *s);
+extern void putchar_asm(uint32_t c);
-int flag = 0;
-
-void poweroff(void) {
- unsigned i;
- for(i = 0; i < 10; i++) {
- uart_poll(SERCOMM_UART_NR);
- delay_ms(10);
- }
- twl3025_power_off();
-}
+static const uint8_t phone_ack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
int main(void)
{
+ int i = 0;
+ for(i = 0; i < sizeof(phone_ack); i++) {
+ putchar_asm(phone_ack[i]);
+ }
+
/* Always disable wdt (some platforms enable it on boot) */
wdog_enable(0);
/* Initialize TWL3025 for power control */
twl3025_init();
+ /* Backlight */
+ bl_mode_pwl(1);
+ bl_level(50);
+
/* Initialize UART without interrupts */
uart_init(SERCOMM_UART_NR, 0);
uart_baudrate(SERCOMM_UART_NR, UART_115200);
sercomm_init();
/* Say hi */
- puts("\n\nOSMOCOM Calypso loader\n");
+ puts("\n\nOSMOCOM Calypso loader (revision " GIT_REVISION ")\n");
puts(hr);
+ /* Initialize flash driver */
+ if(flash_init(&the_flash, 0)) {
+ puts("Failed to initialize flash!\n");
+ }
+
+ /* Identify environment */
+ printf("Running on %s in environment %s\n", manifest_board, manifest_environment);
+
/* Set up a key handler for powering off */
keypad_set_handler(&key_handler);
/* Set up loader communications */
sercomm_register_rx_cb(SC_DLCI_LOADER, &cmd_handler);
+ /* Notify any running osmoload about our startup */
+ loader_send_init(SC_DLCI_LOADER);
+
/* Wait for events */
while (1) {
keypad_poll();
return;
}
- uint8_t command = 0; //= msgb_get_u8(msg);
+ uint8_t command = msgb_get_u8(msg);
- printf("command %u\n", command);
+ int res;
- msgb_free(msg);
+ flash_lock_t lock;
- return;
+ void *data;
+ uint8_t chip;
uint8_t nbytes;
+ uint16_t crc, mycrc;
uint32_t address;
- struct msgb *reply;
+ struct msgb *reply = sercomm_alloc_msgb(256); // XXX
+
+ if(!reply) {
+ printf("Failed to allocate reply buffer!\n");
+ goto out;
+ }
switch(command) {
case LOADER_PING:
+ loader_send_simple(reply, dlci, LOADER_PING);
+ break;
- printf("ping\n");
+ case LOADER_RESET:
+ loader_send_simple(reply, dlci, LOADER_RESET);
+ device_reset();
+ break;
- //sercomm_sendmsg(dlci, msg);
- //msg = NULL;
+ case LOADER_POWEROFF:
+ loader_send_simple(reply, dlci, LOADER_POWEROFF);
+ device_poweroff();
+ break;
+
+ case LOADER_ENTER_ROM_LOADER:
+ loader_send_simple(reply, dlci, LOADER_ENTER_ROM_LOADER);
+ device_enter_loader(1);
+ break;
+ case LOADER_ENTER_FLASH_LOADER:
+ loader_send_simple(reply, dlci, LOADER_ENTER_FLASH_LOADER);
+ device_enter_loader(0);
break;
case LOADER_MEM_READ:
nbytes = msgb_get_u8(msg);
address = msgb_get_u32(msg);
- printf("mem read %u @ %p\n", nbytes, (void*)address);
-
- reply = sercomm_alloc_msgb(6 + nbytes);
+ crc = crc16(0, (void*)address, nbytes);
msgb_put_u8(reply, LOADER_MEM_READ);
msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, crc);
msgb_put_u32(reply, address);
memcpy(msgb_put(reply, nbytes), (void*)address, nbytes);
break;
- }
+ case LOADER_MEM_WRITE:
+
+ nbytes = msgb_get_u8(msg);
+ crc = msgb_get_u16(msg);
+ address = msgb_get_u32(msg);
+
+ data = msgb_get(msg, nbytes);
+
+ mycrc = crc16(0, data, nbytes);
+
+ if(mycrc == crc) {
+ memcpy((void*)address, data, nbytes);
+ }
+
+ msgb_put_u8(reply, LOADER_MEM_WRITE);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, mycrc);
+ msgb_put_u32(reply, address);
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
- if(msg) {
- msgb_free(msg);
+ case LOADER_JUMP:
+
+ address = msgb_get_u32(msg);
+
+ msgb_put_u8(reply, LOADER_JUMP);
+ msgb_put_u32(reply, address);
+
+ sercomm_sendmsg(dlci, reply);
+
+ device_jump((void*)address);
+
+ break;
+
+ case LOADER_FLASH_INFO:
+
+ msgb_put_u8(reply, LOADER_FLASH_INFO);
+ msgb_put_u8(reply, 1); // nchips
+
+ // chip 1
+ msgb_put_u32(reply, the_flash.f_base);
+ msgb_put_u32(reply, the_flash.f_size);
+ msgb_put_u8(reply, the_flash.f_nregions);
+
+ int i;
+ for(i = 0; i < the_flash.f_nregions; i++) {
+ msgb_put_u32(reply, the_flash.f_regions[i].fr_bnum);
+ msgb_put_u32(reply, the_flash.f_regions[i].fr_bsize);
+ }
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_ERASE:
+ case LOADER_FLASH_UNLOCK:
+ case LOADER_FLASH_LOCK:
+ case LOADER_FLASH_LOCKDOWN:
+
+ chip = msgb_get_u8(msg);
+ address = msgb_get_u32(msg);
+
+ if(command == LOADER_FLASH_ERASE) {
+ res = flash_block_erase(&the_flash, address);
+ }
+ if(command == LOADER_FLASH_UNLOCK) {
+ res = flash_block_unlock(&the_flash, address);
+ }
+ if(command == LOADER_FLASH_LOCK) {
+ res = flash_block_lock(&the_flash, address);
+ }
+ if(command == LOADER_FLASH_LOCKDOWN) {
+ res = flash_block_lockdown(&the_flash, address);
+ }
+
+ msgb_put_u8(reply, command);
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+ msgb_put_u32(reply, (res != 0));
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_GETLOCK:
+
+ chip = msgb_get_u8(msg);
+ address = msgb_get_u32(msg);
+
+ lock = flash_block_getlock(&the_flash, address);
+
+ msgb_put_u8(reply, command);
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+
+ switch(lock) {
+ case FLASH_UNLOCKED:
+ msgb_put_u32(reply, LOADER_FLASH_UNLOCKED);
+ break;
+ case FLASH_LOCKED:
+ msgb_put_u32(reply, LOADER_FLASH_LOCKED);
+ break;
+ case FLASH_LOCKED_DOWN:
+ msgb_put_u32(reply, LOADER_FLASH_LOCKED_DOWN);
+ break;
+ default:
+ msgb_put_u32(reply, 0xFFFFFFFF);
+ break;
+ }
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_PROGRAM:
+
+ nbytes = msgb_get_u8(msg);
+ crc = msgb_get_u16(msg);
+ msgb_get_u8(msg); // XXX align
+ chip = msgb_get_u8(msg);
+ address = msgb_get_u32(msg);
+
+ data = msgb_get(msg, nbytes);
+
+ mycrc = crc16(0, data, nbytes);
+
+ if(mycrc == crc) {
+ res = flash_program(&the_flash, address, data, nbytes);
+ }
+
+ msgb_put_u8(reply, LOADER_FLASH_PROGRAM);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, mycrc);
+ msgb_put_u8(reply, 0); // XXX align
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+
+ msgb_put_u32(reply, (uint32_t)res); // XXX
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ default:
+ printf("unknown command %d\n", command);
+
+ msgb_free(reply);
+
+ break;
}
+
+ out:
+
+ msgb_free(msg);
}
static void key_handler(enum key_codes code, enum key_states state)
switch (code) {
case KEY_POWER:
- poweroff();
+ puts("Powering off due to keypress.\n");
+ device_poweroff();
+ break;
+ case KEY_OK:
+ puts("Resetting due to keypress.\n");
+ device_reset();
break;
default:
break;