main.c (4901B)
1 /* main.c 2 * 3 * Copyright 2011 Brian Swetland <swetland@frotz.net> 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <fw/types.h> 19 #include <fw/lib.h> 20 #include <fw/io.h> 21 #include <fw/string.h> 22 23 #include <arch/hardware.h> 24 25 extern u8 board_name[]; 26 27 #define RAM_BASE 0x10000000 28 #define RAM_SIZE (7 * 1024) 29 30 #define ROM_BASE 0x00001000 31 #define ROM_SIZE (28 * 1024) 32 33 void (*romcall)(u32 *in, u32 *out) = (void*) 0x1fff1ff1; 34 35 /* { PREPARE, startpage, endpage } */ 36 #define OP_PREPARE 50 37 /* { WRITE, dstaddr, srcaddr, bytes, sysclk_khz } */ 38 #define OP_WRITE 51 39 /* { ERASE, startpage, endpage, sysclk_khz } */ 40 #define OP_ERASE 52 41 42 struct device_info { 43 u8 part[16]; 44 u8 board[16]; 45 u32 version; 46 u32 ram_base; 47 u32 ram_size; 48 u32 rom_base; 49 u32 rom_size; 50 u32 unused0; 51 u32 unused1; 52 u32 unused2; 53 }; 54 55 struct device_info DEVICE = { 56 .part = "LPC1343", 57 .version = 0x0001000, 58 .ram_base = RAM_BASE, 59 .ram_size = RAM_SIZE, 60 .rom_base = ROM_BASE, 61 .rom_size = ROM_SIZE, 62 }; 63 64 void iap_erase_page(unsigned addr) { 65 u32 in[4]; 66 u32 out[5]; 67 in[0] = OP_PREPARE; 68 in[1] = (addr >> 12) & 0xF; 69 in[2] = (addr >> 12) & 0xF; 70 romcall(in, out); 71 in[0] = OP_ERASE; 72 in[1] = (addr >> 12) & 0xF; 73 in[2] = (addr >> 12) & 0xF; 74 in[3] = 48000; 75 romcall(in, out); 76 } 77 78 void iap_write_page(unsigned addr, void *src) { 79 u32 in[5]; 80 u32 out[5]; 81 in[0] = OP_PREPARE; 82 in[1] = (addr >> 12) & 0xF; 83 in[2] = (addr >> 12) & 0xF; 84 romcall(in, out); 85 in[0] = OP_WRITE; 86 in[1] = addr; 87 in[2] = (u32) src; 88 in[3] = 0x1000; 89 in[4] = 48000; 90 romcall(in, out); 91 } 92 93 static u32 buf[64]; 94 95 void start_image(u32 pc, u32 sp); 96 97 void _boot_image(void *img) { 98 start_image(((u32*)img)[1], ((u32*)img)[0]); 99 } 100 101 void boot_image(void *img) { 102 board_debug_led(0); 103 usb_stop(); 104 105 /* TODO: shut down various peripherals */ 106 _boot_image(img); 107 } 108 109 void handle(u32 magic, u32 cmd, u32 arg) { 110 u32 reply[2]; 111 u32 addr, xfer; 112 void *ram = (void*) RAM_BASE; 113 114 if (magic != 0xDB00A5A5) 115 return; 116 117 reply[0] = magic; 118 reply[1] = -1; 119 120 switch (cmd) { 121 case 'E': 122 iap_erase_page(0x1000); 123 reply[1] = 0; 124 break; 125 case 'W': 126 if (arg > ROM_SIZE) 127 break; 128 reply[1] = 0; 129 usb_xmit(reply, 8); 130 addr = ROM_BASE; 131 while (arg > 0) { 132 xfer = (arg > 4096) ? 4096 : arg; 133 usb_recv(ram, xfer); 134 iap_erase_page(addr); 135 iap_write_page(addr, ram); 136 addr += 4096; 137 arg -= xfer; 138 } 139 break; 140 case 'X': 141 if (arg > RAM_SIZE) 142 break; 143 reply[1] = 0; 144 usb_xmit(reply, 8); 145 usb_recv(ram, arg); 146 usb_xmit(reply, 8); 147 148 /* let last txn clear */ 149 usb_recv_timeout(buf, 64, 10); 150 151 boot_image(ram); 152 break; 153 case 'Q': 154 reply[1] = 0; 155 usb_xmit(reply, 8); 156 usb_xmit(&DEVICE, sizeof(DEVICE)); 157 return; 158 case 'A': 159 /* reboot-into-app -- signal to bootloader via GPREGn */ 160 writel(0x12345678, GPREG0); 161 writel(0xA5A50001, GPREG1); 162 case 'R': 163 /* reboot "normally" */ 164 reply[1] = 0; 165 usb_xmit(reply, 8); 166 usb_recv_timeout(buf, 64, 10); 167 reboot(); 168 default: 169 break; 170 } 171 usb_xmit(reply, 8); 172 } 173 174 int main() { 175 int n, x, timeout; 176 u32 tmp; 177 u32 gpr0,gpr1; 178 179 /* sample GPREG and clear */ 180 gpr0 = readl(GPREG0); 181 gpr1 = readl(GPREG1); 182 writel(0xBBBBBBBB, GPREG0); 183 writel(0xBBBBBBBB, GPREG1); 184 185 /* request to boot directly into the "app" image */ 186 if ((gpr0 == 0x12345678) && (gpr1 == 0xA5A50001)) 187 _boot_image((void*) 0x1000); 188 189 board_init(); 190 191 usb_init(0x18d1, 0xdb00, "m3dev", "m3boot"); 192 193 /* check for an app image and set a 3s timeout if it exists */ 194 tmp = *((u32*) 0x1000); 195 if ((tmp != 0) && (tmp != 0xFFFFFFFF)) 196 timeout = 30; 197 else 198 timeout = 0; 199 200 /* request to stay in the bootloader forever? */ 201 if ((gpr0 == 0x12345678) && (gpr1 == 0xA5A50000)) 202 timeout = 0; 203 204 strcpy((char*) DEVICE.board, (char*) board_name); 205 206 if (timeout) { 207 /* wait up to 1s to enumerate */ 208 writel(readl(SYS_CLK_CTRL) | SYS_CLK_CT32B0, SYS_CLK_CTRL); 209 writel(48, TM32B0PR); 210 writel(TM32TCR_ENABLE, TM32B0TCR); 211 while (!usb_online() && (readl(TM32B0TC) < 2000000)) ; 212 writel(readl(SYS_CLK_CTRL) & (~SYS_CLK_CT32B0), SYS_CLK_CTRL); 213 if (!usb_online()) 214 goto start_app; 215 } 216 217 x = 0; 218 for (;;) { 219 board_debug_led(x & 1); 220 x++; 221 n = usb_recv_timeout(buf, 64, 100); 222 223 if ((n == -ETIMEOUT) && timeout) { 224 timeout--; 225 if (timeout == 0) 226 break; 227 } 228 229 if (n == 12) { 230 timeout = 0; 231 handle(buf[0], buf[1], buf[2]); 232 } 233 } 234 235 start_app: 236 /* warm reset into the app */ 237 writel(0x12345678, GPREG0); 238 writel(0xA5A50001, GPREG1); 239 reboot(); 240 241 return 0; 242 } 243