blob: 1a1ddd744d06b1f2e1513f6c83c3ffb1076e740b [file] [log] [blame]
/*
* USB bootloader
*
* Copyright (C) 2011 Rick Bronson
*
* 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 <common.h>
#include <malloc.h>
#include <asm/arch/cpu.h> /* get chip and board defs */
#include "usb.h"
extern void udelay (unsigned long usecs);
typedef int boot_os_fn (void);
/* send a buffer via USB */
int usb_send(unsigned char *buffer, unsigned int buffer_size)
{
int ret = 0;
if (!(*peri_txcsr & MUSB_TXCSR_TXPKTRDY))
{
unsigned int cntr;
for (cntr = 0; cntr < buffer_size; cntr++)
*bulk_fifo = buffer[cntr];
*peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
ret = buffer_size;
}
return ret;
}
////////////////////
static int usb_recv (u8 *buffer, int size)
{
int cntr;
u16 count = 0;
if (*peri_rxcsr & MUSB_RXCSR_RXPKTRDY)
{
count = *rxcount;
for (cntr = 0; cntr < count; cntr++)
{
*buffer++ = *bulk_fifo;
}
/* Clear the RXPKTRDY bit */
*peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
}
return count; /* FIXME */
}
static unsigned char usb_outbuffer[64];
static void usb_msg (unsigned int cmd, const char *msg)
{
unsigned char *p_char = usb_outbuffer;
* (int *) p_char = cmd;
p_char += sizeof (cmd);
if (msg)
{
while (*msg)
*p_char++= *msg++;
*p_char++= 0;
}
usb_send (usb_outbuffer, p_char - usb_outbuffer);
}
static void usb_code (unsigned int cmd, u32 code)
{
unsigned int *p_int = (unsigned int *) usb_outbuffer;
*p_int++ = cmd;
*p_int++ = code;
usb_send (usb_outbuffer, ((unsigned char *) p_int) - usb_outbuffer);
}
void do_usb (void)
{
boot_os_fn *boot_fn;
int res;
u32 usb_inbuffer[512];
u32 total;
u8 *addr;
u32 bytes;
int size;
int cntr = 0;
usb_msg (USBLOAD_CMD_FILE_REQ, "file req");
while(++cntr < 200000) /* try for 1 second then bail out */
{
res = usb_recv ((u8 *) usb_inbuffer, sizeof (usb_inbuffer));
switch (usb_inbuffer[0])
{
case USBLOAD_CMD_FILE:
printf ("USBLOAD_CMD_FILE total = %d cmd = %c%c%c%c val = 0x%x val = 0x%x\n",
res,
((char*)&usb_inbuffer[0])[0], ((char*)&usb_inbuffer[0])[1], ((char*)&usb_inbuffer[0])[2], ((char*)&usb_inbuffer[0])[3],
usb_inbuffer[1],
usb_inbuffer[2]);
total = usb_inbuffer[1]; /* get size and address */
addr = (u8 *) usb_inbuffer[2];
usb_code (USBLOAD_CMD_ECHO_SZ, total);
bytes = 0;
while (bytes < total)
{
size = usb_recv ((u8 *) usb_inbuffer, sizeof (usb_inbuffer));
memcpy(addr, usb_inbuffer, size);
addr += size;
bytes += size;
}
usb_code (USBLOAD_CMD_REPORT_SZ, total); /* tell him we got this many bytes */
printf ("got file addr = 0x%x counter = %d\n", addr, cntr);
usb_msg (USBLOAD_CMD_FILE_REQ, "file req"); /* see if they have another file for us */
cntr = 0;
break;
case USBLOAD_CMD_JUMP:
printf ("USBLOAD_CMD_JUMP total = %d addr = 0x%x val = 0x%x\n", res, usb_inbuffer[0], usb_inbuffer[1]);
boot_fn = (boot_os_fn *) usb_inbuffer[1];
boot_fn(); /* go to u-boot and maybe kernel */
break;
default:
break;
}
udelay(10); /* delay 10 us */
}
printf("USB done\n");
hang();
}