/* * 2nd - OMAP "second stage" tt-loader * * Copyright (C) 2008 Guillaume Bougard * Copyright (C) 2005 Luis Recuerda * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include "usb.h" #define _LSR_ ((volatile u8 *) 0xfffb0014) #define _THR_ ((volatile u8 *) 0xfffb0000) #define _RHR_ ((volatile u8 *) 0xfffb0000) #define MEM_READ_SIZE 32 static char *usb_hdr = "TIS" ; static char usb_outbuffer[64]; // limited strcpy static u32 strcpy ( char *dest, char *src ) { u32 count = 0 ; char *tmp = dest, *s = src; while ( ++count < 256 && *s != '\0' ) *tmp++ = *s++ ; *tmp = '\0' ; return count ; } static u32 memcpy ( char *dest, char *src, u32 count ) { char *tmp = dest, *s = src; u32 step = count ; while (step--) *tmp++ = *s++; return count ; } static void bsend (char ch) { while (!((*_LSR_) & 0x20)); *_THR_= ch; } static inline int check_serial (void) { return (*_LSR_) & 0x01; } static char brecv (void) { while (!((*_LSR_) & 0x01)); return *_RHR_; } char crecv (void) { return brecv (); } void csend (char ch) { if (ch == '\n') bsend ('\r'); bsend (ch); } void tsend (const char *text) { while (*text) csend (*text++); } void xsend (unsigned value) { if (value < 10) bsend (value + '0'); else bsend (value + ('A'-10)); } void x8send (u8 value) { xsend (value >> 4); xsend (value & 0xf); } void x16send (u16 value) { int i; for (i= 0; i < 4; ++i) { xsend (value >> 12); value<<= 4; } } void x32send (u32 value) { int i; for (i= 0; i < 8; ++i) { xsend (value >> 28); value<<= 4; } } static void usb_msg (const char cmd, const char *msg) { u32 len = strcpy(usb_outbuffer,usb_hdr); usb_outbuffer[len-1] = cmd ; len += strcpy(&usb_outbuffer[len], msg ? (char *)msg : "" ); usb_send ( usb_outbuffer, len); while (!usb_sent ()); } static u32 usb_code (char cmd, u32 code) { u32 len = strcpy(usb_outbuffer,usb_hdr); usb_outbuffer[len-1] = cmd ; (*(u32 *)(usb_outbuffer+len)) = code ; len += sizeof(u32); usb_send ( usb_outbuffer, len ); while (!usb_sent ()); return code ; } static void usb_blk (const char cmd, char *mem, u32 size) { u32 len = strcpy(usb_outbuffer,usb_hdr); usb_outbuffer[len-1] = cmd ; len += memcpy(usb_outbuffer+len,mem,size); usb_send ( usb_outbuffer, len ); while (!usb_sent ()); } // Code from linux-2.6.24.3/arch/arm/mach-omap1/id.c source static u16 omap_get_jtag_id(void) { u32 prod_id, jtag_id; prod_id = omap_readl(OMAP_PRODUCTION_ID_1); jtag_id = omap_readl(OMAP32_ID_1); /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */ if (((prod_id >> 20) == 0) || (prod_id == jtag_id)) prod_id = 0; else prod_id &= 0xffff; if (prod_id) return prod_id; /* Use OMAP32_ID_1 as fallback */ prod_id = ((jtag_id >> 12) & 0xffff); return prod_id; } u32 _main (void) { u32 address = CFG_LOADADDR ; usb_msg ('m', "In omap plateform"); u16 prod_id = omap_get_jtag_id(); switch (prod_id) { case 0xb55f: usb_msg ('m', "Found supported omap730"); break; default: usb_msg ('m', "Unsupported plateform found"); usb_code ('v', (u32) prod_id); break; } // Ready to manage requests usb_msg ('r', "Waiting first request"); for (;;) { u32 total, cmd, index = 0 ; u8 usb_inbuffer[64]; usb_recv (usb_inbuffer, sizeof (usb_inbuffer)); while (!usb_rcvd ()); // Check we are knowing the provided header while ( usb_inbuffer[index] == (u8) usb_hdr[index] && usb_hdr[index] != '\0' ) index++ ; if ( usb_hdr[index] != '\0' ) continue ; cmd = usb_inbuffer[index++] ; if ((char)cmd == 's') // Ask size to upload { total= *(u32 *) &usb_inbuffer[index]; u32 size = 0; usb_code ('n', total); while (size < total) { u32 r; usb_recv ((u8 *)address, sizeof (usb_inbuffer)); while ((r= usb_rcvd ()) == 0); address += r ; size += r ; } usb_code ('o', size); } else if ((char)cmd == 'f') // load file ACK { usb_msg ('f', (const char *)&usb_inbuffer[index]); } else if ((char)cmd == 'M') // dump memory command { usb_blk ('M', (char *)address, MEM_READ_SIZE); address += MEM_READ_SIZE ; } else if ((char)cmd == 'a') // set address command { address = *(u32 *) &usb_inbuffer[index]; usb_code ('i', address); } else if ((char)cmd == 'c') // call command { index = ((u32_fnc_t *)address)(); usb_code ('i', index); } else if ((char)cmd == 'b') // boot command { usb_code ('b', address ); // Just return the address where is store the branch to do u32 bootaddress = (u32) &address ; // Convert/cast address just to avoid gcc warning return bootaddress ; } } }