| 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 | * |
|---|
| 7 | * ARM kernel loader. Adapt from qemu-neo1973 |
|---|
| 8 | * Copyright (c) 2006-2007 CodeSourcery. |
|---|
| 9 | * Written by Paul Brook |
|---|
| 10 | * |
|---|
| 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 | |
|---|
| 30 | extern u32 crc32( u32 crc, char* buf, u32 len, crc_cb_fnc_t* cb); |
|---|
| 31 | |
|---|
| 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 |
|---|
| 38 | |
|---|
| 39 | static char *usb_hdr = "TIS" ; |
|---|
| 40 | static char usb_outbuffer[MEM_READ_SIZE+4]; |
|---|
| 41 | |
|---|
| 42 | static u32 strcpy ( char *dest, char *src ) |
|---|
| 43 | { |
|---|
| 44 | u32 count = 0 ; |
|---|
| 45 | char *tmp = dest, *s = src; |
|---|
| 46 | |
|---|
| 47 | while ( ++count < MEM_READ_SIZE && *s != '\0' ) |
|---|
| 48 | *tmp++ = *s++ ; |
|---|
| 49 | |
|---|
| 50 | *tmp = '\0' ; |
|---|
| 51 | |
|---|
| 52 | return count ; |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 216 | u32 _main (void) |
|---|
| 217 | { |
|---|
| 218 | u32 params = CFG_PARAMADDR ; |
|---|
| 219 | u32 address = CFG_LOADADDR ; |
|---|
| 220 | u32 crc = 0 ; |
|---|
| 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 | |
|---|
| 242 | u8 usb_inbuffer[CHUNK_SIZE]; |
|---|
| 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 |
|---|
| 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 |
|---|
| 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 |
|---|
| 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 |
|---|
| 354 | if ((char)cmd == 'c') // call command |
|---|
| 355 | { |
|---|
| 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 | ); |
|---|
| 365 | usb_code ('i', index); |
|---|
| 366 | |
|---|
| 367 | } else |
|---|
| 368 | if ((char)cmd == 'b') // boot command |
|---|
| 369 | { |
|---|
| 370 | usb_code ('b', address ); |
|---|
| 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 | |
|---|
| 409 | } |
|---|
| 410 | } |
|---|
| 411 | } |
|---|