[11] | 1 | /* |
---|
| 2 | * 2nd - OMAP "second stage" tt-loader |
---|
| 3 | * |
---|
| 4 | * Copyright (C) 2008 Guillaume Bougard <gbougard@pkg.fr> |
---|
| 5 | * Copyright (C) 2005 Luis Recuerda <lrec@helios.homeip.net> |
---|
| 6 | * |
---|
[12] | 7 | * ARM kernel loader. Adapt from qemu-neo1973 |
---|
| 8 | * Copyright (c) 2006-2007 CodeSourcery. |
---|
| 9 | * Written by Paul Brook |
---|
| 10 | * |
---|
[11] | 11 | * This program is free software; you can redistribute it and/or |
---|
| 12 | * modify it under the terms of the GNU General Public License |
---|
| 13 | * as published by the Free Software Foundation; either version 2 |
---|
| 14 | * of the License, or (at your option) any later version. |
---|
| 15 | * |
---|
| 16 | * This program is distributed in the hope that it will be useful, |
---|
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 19 | * GNU General Public License for more details. |
---|
| 20 | * |
---|
| 21 | * You should have received a copy of the GNU General Public License |
---|
| 22 | * along with this program; if not, write to the Free Software |
---|
| 23 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
| 24 | * |
---|
| 25 | */ |
---|
| 26 | |
---|
| 27 | #include "config.h" |
---|
| 28 | #include "usb.h" |
---|
| 29 | |
---|
[12] | 30 | extern u32 crc32( u32 crc, char* buf, u32 len, crc_cb_fnc_t* cb); |
---|
[11] | 31 | |
---|
[12] | 32 | /* |
---|
| 33 | * Length of memory dump done by 2nd.bin, must be a multiple of DUMP_LINE_SIZE from host main.c |
---|
| 34 | * Must also be sufficient to output lines of text, let's say 128 bytes |
---|
| 35 | */ |
---|
| 36 | #define MEM_READ_SIZE 128*32 |
---|
| 37 | #define CHUNK_SIZE 8192 |
---|
[11] | 38 | |
---|
| 39 | static char *usb_hdr = "TIS" ; |
---|
[12] | 40 | static char usb_outbuffer[MEM_READ_SIZE+4]; |
---|
[11] | 41 | |
---|
| 42 | static u32 strcpy ( char *dest, char *src ) |
---|
| 43 | { |
---|
| 44 | u32 count = 0 ; |
---|
| 45 | char *tmp = dest, *s = src; |
---|
| 46 | |
---|
[12] | 47 | while ( ++count < MEM_READ_SIZE && *s != '\0' ) |
---|
[11] | 48 | *tmp++ = *s++ ; |
---|
| 49 | |
---|
| 50 | *tmp = '\0' ; |
---|
| 51 | |
---|
| 52 | return count ; |
---|
| 53 | } |
---|
| 54 | |
---|
[12] | 55 | static u32 strlen ( char *src ) |
---|
| 56 | { |
---|
| 57 | u32 len = 0 ; |
---|
| 58 | |
---|
| 59 | while ( *src != '\0' ) { |
---|
| 60 | src++ ; |
---|
| 61 | len ++ ; |
---|
| 62 | } |
---|
| 63 | |
---|
| 64 | return len ; |
---|
| 65 | } |
---|
| 66 | |
---|
[11] | 67 | static u32 memcpy ( char *dest, char *src, u32 count ) |
---|
| 68 | { |
---|
| 69 | char *tmp = dest, *s = src; |
---|
| 70 | u32 step = count ; |
---|
| 71 | |
---|
| 72 | while (step--) |
---|
| 73 | *tmp++ = *s++; |
---|
| 74 | |
---|
| 75 | return count ; |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | static void usb_msg (const char cmd, const char *msg) |
---|
| 79 | { |
---|
| 80 | u32 len = strcpy(usb_outbuffer,usb_hdr); |
---|
| 81 | usb_outbuffer[len-1] = cmd ; |
---|
| 82 | |
---|
| 83 | len += strcpy(&usb_outbuffer[len], msg ? (char *)msg : "" ); |
---|
| 84 | |
---|
| 85 | usb_send ( usb_outbuffer, len); |
---|
| 86 | while (!usb_sent ()); |
---|
| 87 | } |
---|
| 88 | |
---|
| 89 | static u32 usb_code (char cmd, u32 code) |
---|
| 90 | { |
---|
| 91 | u32 len = strcpy(usb_outbuffer,usb_hdr); |
---|
| 92 | usb_outbuffer[len-1] = cmd ; |
---|
| 93 | (*(u32 *)(usb_outbuffer+len)) = code ; |
---|
| 94 | len += sizeof(u32); |
---|
| 95 | |
---|
| 96 | usb_send ( usb_outbuffer, len ); |
---|
| 97 | while (!usb_sent ()); |
---|
| 98 | return code ; |
---|
| 99 | } |
---|
| 100 | |
---|
| 101 | static void usb_blk (const char cmd, char *mem, u32 size) |
---|
| 102 | { |
---|
| 103 | u32 len = strcpy(usb_outbuffer,usb_hdr); |
---|
| 104 | usb_outbuffer[len-1] = cmd ; |
---|
| 105 | |
---|
| 106 | len += memcpy(usb_outbuffer+len,mem,size); |
---|
| 107 | |
---|
| 108 | usb_send ( usb_outbuffer, len ); |
---|
| 109 | while (!usb_sent ()); |
---|
| 110 | } |
---|
| 111 | |
---|
| 112 | // Code from linux-2.6.24.3/arch/arm/mach-omap1/id.c source |
---|
| 113 | static u16 omap_get_jtag_id(void) |
---|
| 114 | { |
---|
| 115 | u32 prod_id, jtag_id; |
---|
| 116 | |
---|
| 117 | prod_id = omap_readl(OMAP_PRODUCTION_ID_1); |
---|
| 118 | jtag_id = omap_readl(OMAP32_ID_1); |
---|
| 119 | |
---|
| 120 | /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */ |
---|
| 121 | if (((prod_id >> 20) == 0) || (prod_id == jtag_id)) |
---|
| 122 | prod_id = 0; |
---|
| 123 | else |
---|
| 124 | prod_id &= 0xffff; |
---|
| 125 | |
---|
| 126 | if (prod_id) |
---|
| 127 | return prod_id; |
---|
| 128 | |
---|
| 129 | /* Use OMAP32_ID_1 as fallback */ |
---|
| 130 | prod_id = ((jtag_id >> 12) & 0xffff); |
---|
| 131 | |
---|
| 132 | return prod_id; |
---|
| 133 | } |
---|
| 134 | |
---|
[12] | 135 | // stl_raw is qemu related |
---|
| 136 | #define stl_raw(x,v) *(u32 *)(x) = v |
---|
| 137 | static void set_kernel_args(u32 ram_size, int initrd_size, const char *kernel_cmdline, u32 ram_start) |
---|
| 138 | { |
---|
| 139 | u32 *p; |
---|
| 140 | |
---|
| 141 | // Set pointer to kernel params |
---|
| 142 | p = (u32 *)(CFG_PARAMADDR); |
---|
| 143 | |
---|
| 144 | /* ATAG_CORE */ |
---|
| 145 | stl_raw(p++, 5); |
---|
| 146 | stl_raw(p++, 0x54410001); |
---|
| 147 | stl_raw(p++, 0); // 0 = ro ; 1= rw |
---|
| 148 | stl_raw(p++, 0x1000); // Page size |
---|
| 149 | stl_raw(p++, 0); // root device overrided by cmdline |
---|
| 150 | /* ATAG_MEM */ |
---|
| 151 | stl_raw(p++, 4); |
---|
| 152 | stl_raw(p++, 0x54410002); |
---|
| 153 | stl_raw(p++, ram_size); |
---|
| 154 | stl_raw(p++, ram_start); |
---|
| 155 | if (initrd_size) { |
---|
| 156 | /* ATAG_INITRD2 */ |
---|
| 157 | stl_raw(p++, 4); |
---|
| 158 | stl_raw(p++, 0x54420005); |
---|
| 159 | stl_raw(p++, ram_start + INITRD_LOAD_ADDR); |
---|
| 160 | stl_raw(p++, initrd_size); |
---|
| 161 | } |
---|
| 162 | if (kernel_cmdline && *kernel_cmdline) { |
---|
| 163 | /* ATAG_CMDLINE */ |
---|
| 164 | int cmdline_size; |
---|
| 165 | |
---|
| 166 | cmdline_size = strlen((char *)kernel_cmdline); |
---|
| 167 | memcpy ((char *)p + 2, (char *)kernel_cmdline, cmdline_size + 1); |
---|
| 168 | cmdline_size = (cmdline_size >> 2) + 1; |
---|
| 169 | stl_raw(p++, cmdline_size + 2); |
---|
| 170 | stl_raw(p++, 0x54410009); |
---|
| 171 | p += cmdline_size; |
---|
| 172 | } |
---|
| 173 | /* ATAG_END */ |
---|
| 174 | stl_raw(p++, 0); |
---|
| 175 | stl_raw(p++, 0); |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | #define C1_DC (1<<2) /* dcache off/on */ |
---|
| 179 | #define C1_IC (1<<12) /* icache off/on */ |
---|
| 180 | |
---|
| 181 | void cleanup_before_linux (void) |
---|
| 182 | { |
---|
| 183 | /* |
---|
| 184 | * this function is called just before we call linux |
---|
| 185 | * it prepares the processor for linux |
---|
| 186 | * |
---|
| 187 | * we turn off caches etc ... |
---|
| 188 | */ |
---|
| 189 | |
---|
| 190 | unsigned long i; |
---|
| 191 | |
---|
| 192 | /* turn off I/D-cache */ |
---|
| 193 | asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); |
---|
| 194 | i &= ~(C1_DC | C1_IC); |
---|
| 195 | asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); |
---|
| 196 | |
---|
| 197 | /* flush I/D-cache */ |
---|
| 198 | i = 0; |
---|
| 199 | asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | void usb_crc32_pos( u32 pos, u32 total, u32 crc ) |
---|
| 203 | { |
---|
| 204 | u32 len = strcpy(usb_outbuffer,usb_hdr); |
---|
| 205 | usb_outbuffer[len-1] = 'x' ; |
---|
| 206 | (*(u32 *)(usb_outbuffer+len)) = pos ; |
---|
| 207 | len += sizeof(u32); |
---|
| 208 | (*(u32 *)(usb_outbuffer+len)) = total ; |
---|
| 209 | len += sizeof(u32); |
---|
| 210 | (*(u32 *)(usb_outbuffer+len)) = crc ; |
---|
| 211 | len += sizeof(u32); |
---|
| 212 | usb_send ( usb_outbuffer, len ); |
---|
| 213 | while (!usb_sent ()); |
---|
| 214 | } |
---|
| 215 | |
---|
[11] | 216 | u32 _main (void) |
---|
| 217 | { |
---|
[12] | 218 | u32 params = CFG_PARAMADDR ; |
---|
[11] | 219 | u32 address = CFG_LOADADDR ; |
---|
[12] | 220 | u32 crc = 0 ; |
---|
[11] | 221 | usb_msg ('m', "In omap plateform"); |
---|
| 222 | |
---|
| 223 | u16 prod_id = omap_get_jtag_id(); |
---|
| 224 | switch (prod_id) |
---|
| 225 | { |
---|
| 226 | case 0xb55f: |
---|
| 227 | usb_msg ('m', "Found supported omap730"); |
---|
| 228 | break; |
---|
| 229 | default: |
---|
| 230 | usb_msg ('m', "Unsupported plateform found"); |
---|
| 231 | usb_code ('v', (u32) prod_id); |
---|
| 232 | break; |
---|
| 233 | } |
---|
| 234 | |
---|
| 235 | // Ready to manage requests |
---|
| 236 | usb_msg ('r', "Waiting first request"); |
---|
| 237 | |
---|
| 238 | for (;;) |
---|
| 239 | { |
---|
| 240 | u32 total, cmd, index = 0 ; |
---|
| 241 | |
---|
[12] | 242 | u8 usb_inbuffer[CHUNK_SIZE]; |
---|
[11] | 243 | usb_recv (usb_inbuffer, sizeof (usb_inbuffer)); |
---|
| 244 | while (!usb_rcvd ()); |
---|
| 245 | |
---|
| 246 | // Check we are knowing the provided header |
---|
| 247 | while ( usb_inbuffer[index] == (u8) usb_hdr[index] && usb_hdr[index] != '\0' ) |
---|
| 248 | index++ ; |
---|
| 249 | |
---|
| 250 | if ( usb_hdr[index] != '\0' ) |
---|
| 251 | continue ; |
---|
| 252 | |
---|
| 253 | cmd = usb_inbuffer[index++] ; |
---|
| 254 | |
---|
| 255 | if ((char)cmd == 's') // Ask size to upload |
---|
| 256 | { |
---|
| 257 | total= *(u32 *) &usb_inbuffer[index]; |
---|
| 258 | u32 size = 0; |
---|
| 259 | |
---|
| 260 | usb_code ('n', total); |
---|
| 261 | |
---|
| 262 | while (size < total) |
---|
| 263 | { |
---|
| 264 | u32 r; |
---|
| 265 | |
---|
| 266 | usb_recv ((u8 *)address, sizeof (usb_inbuffer)); |
---|
| 267 | while ((r= usb_rcvd ()) == 0); |
---|
| 268 | |
---|
| 269 | address += r ; |
---|
| 270 | size += r ; |
---|
| 271 | } |
---|
| 272 | |
---|
| 273 | usb_code ('o', size); |
---|
| 274 | |
---|
| 275 | } else |
---|
[12] | 276 | if ((char)cmd == 'C') // set crc32 value for next download |
---|
| 277 | { |
---|
| 278 | crc = *(u32 *) &usb_inbuffer[index]; |
---|
| 279 | usb_code ('i', crc); |
---|
| 280 | |
---|
| 281 | } else |
---|
| 282 | if ((char)cmd == 'm') // Download size from memory |
---|
| 283 | { |
---|
| 284 | total= *(u32 *) &usb_inbuffer[index]; |
---|
| 285 | u32 size = 0; |
---|
| 286 | |
---|
| 287 | usb_code ('I', total); |
---|
| 288 | |
---|
| 289 | // Check crc32 if it has been set |
---|
| 290 | if (total && crc) |
---|
| 291 | { |
---|
| 292 | crc_cb_fnc_t* cb = NULL ; |
---|
| 293 | if (total>1024*1024) |
---|
| 294 | cb = &usb_crc32_pos ; |
---|
| 295 | u32 foundcrc = crc32(0, (char *)address,total,cb) ; |
---|
| 296 | usb_code ('C', foundcrc); |
---|
| 297 | // Skip download on crc match |
---|
| 298 | if (foundcrc == crc) |
---|
| 299 | total = 0 ; |
---|
| 300 | } |
---|
| 301 | |
---|
| 302 | if (total == 0) |
---|
| 303 | usb_blk ('D', (char *)address, 0); |
---|
| 304 | |
---|
| 305 | while (size < total) |
---|
| 306 | { |
---|
| 307 | u32 bs = MEM_READ_SIZE ; |
---|
| 308 | if ( total - size < MEM_READ_SIZE) |
---|
| 309 | bs = total - size ; |
---|
| 310 | usb_blk ('D', (char *)address, bs); |
---|
| 311 | address += bs ; |
---|
| 312 | size += bs ; |
---|
| 313 | } |
---|
| 314 | |
---|
| 315 | // reset crc for next download anyway |
---|
| 316 | crc = 0 ; |
---|
| 317 | |
---|
| 318 | } else |
---|
| 319 | if ((char)cmd == 'e') // End, just loop |
---|
| 320 | { |
---|
| 321 | usb_reset(); |
---|
| 322 | |
---|
| 323 | } else |
---|
[11] | 324 | if ((char)cmd == 'f') // load file ACK |
---|
| 325 | { |
---|
| 326 | usb_msg ('f', (const char *)&usb_inbuffer[index]); |
---|
| 327 | |
---|
| 328 | } else |
---|
| 329 | if ((char)cmd == 'M') // dump memory command |
---|
| 330 | { |
---|
| 331 | usb_blk ('M', (char *)address, MEM_READ_SIZE); |
---|
| 332 | address += MEM_READ_SIZE ; |
---|
| 333 | |
---|
| 334 | } else |
---|
| 335 | if ((char)cmd == 'a') // set address command |
---|
| 336 | { |
---|
| 337 | address = *(u32 *) &usb_inbuffer[index]; |
---|
| 338 | usb_code ('i', address); |
---|
| 339 | |
---|
| 340 | } else |
---|
[12] | 341 | if ((char)cmd == 'p') // do a poke on address |
---|
| 342 | { |
---|
| 343 | u32 size = memcpy( (char *) address, (char *) &usb_inbuffer[index], 4); |
---|
| 344 | address += size ; |
---|
| 345 | usb_code ('i', address ); |
---|
| 346 | |
---|
| 347 | } else |
---|
| 348 | if ((char)cmd == 'P') // do a peek on address |
---|
| 349 | { |
---|
| 350 | usb_code ('i', *(u32 *) address ); |
---|
| 351 | address += 4 ; |
---|
| 352 | |
---|
| 353 | } else |
---|
[11] | 354 | if ((char)cmd == 'c') // call command |
---|
| 355 | { |
---|
[12] | 356 | __asm__ __volatile__ ( |
---|
| 357 | "mov r0, #0 ;" |
---|
| 358 | "mov r1, #0 ;" |
---|
| 359 | "mov r2, #0 ;" |
---|
| 360 | "ldr r3, %1 ;" |
---|
| 361 | "blx r3 ;" |
---|
| 362 | "mov %0, r0 ;" |
---|
| 363 | : "=r"(index) : "m"(address) : "r0", "r1", "r2", "r3" |
---|
| 364 | ); |
---|
[11] | 365 | usb_code ('i', index); |
---|
| 366 | |
---|
| 367 | } else |
---|
| 368 | if ((char)cmd == 'b') // boot command |
---|
| 369 | { |
---|
| 370 | usb_code ('b', address ); |
---|
[12] | 371 | usb_reset(); |
---|
| 372 | __asm__ __volatile__ ( |
---|
| 373 | "ldr r0, %0 ;" |
---|
| 374 | "mov pc, r0 ;" |
---|
| 375 | : : "m"(address) |
---|
| 376 | ); |
---|
| 377 | |
---|
| 378 | } else |
---|
| 379 | if ((char)cmd == 'k') // boot kernel command |
---|
| 380 | { |
---|
| 381 | int machid = * (int *) &usb_inbuffer[index]; |
---|
| 382 | usb_code ('I', machid); |
---|
| 383 | set_kernel_args( RAM_SIZE, INITRD_SIZE, KERNEL_CMDLINE, CFG_BASESDRAM ); |
---|
| 384 | usb_code ('b', address ); |
---|
| 385 | usb_reset(); |
---|
| 386 | cleanup_before_linux(); |
---|
| 387 | __asm__ __volatile__ ( |
---|
| 388 | "mov r0, #0 ;" |
---|
| 389 | "ldr r1, %0 ;" |
---|
| 390 | "ldr r2, %1 ;" |
---|
| 391 | "mov r3, #0 ;" |
---|
| 392 | "mov r4, #0 ;" |
---|
| 393 | "ldr r5, %2 ;" |
---|
| 394 | "mov pc, r5 ;" |
---|
| 395 | : : "m" (machid), "m"(params), "m"(address) |
---|
| 396 | ); |
---|
| 397 | } else |
---|
| 398 | if ((char)cmd == 'S') // Stack command |
---|
| 399 | { |
---|
| 400 | __asm__ __volatile__ ( |
---|
| 401 | "ldr fp, %0 ;" |
---|
| 402 | "sub fp, #4 ;" |
---|
| 403 | "mov sp, fp ;" |
---|
| 404 | "sub sp, #256 ;" |
---|
| 405 | : : "m"(address) |
---|
| 406 | ); |
---|
| 407 | usb_code ('i', address); |
---|
| 408 | |
---|
[11] | 409 | } |
---|
| 410 | } |
---|
| 411 | } |
---|