1d7c8ec143
The OMAP3 supports uploading the first stage bootloader via USB. The ROM leaves the MUSB controller enabled and it can then be used to upload a 2nd stage image. This patch adds the omap3-usb-loader tool and the necessary barebox support to upload the 2nd stage image. The omap usb loader tool is downloaded from https://github.com/grant-h/omap_loader and changed to also accept CHSETTINGS images. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
186 lines
4.6 KiB
C
186 lines
4.6 KiB
C
/*
|
|
* Copyright (c) 2015 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
|
|
*
|
|
* Based on a patch by:
|
|
*
|
|
* Copyright (C) 2011 Rick Bronson
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <io.h>
|
|
#include <malloc.h>
|
|
#include <mach/omap3-silicon.h>
|
|
#include <mach/omap3-generic.h>
|
|
|
|
static void __iomem *omap3_usb_base = (void __iomem *)OMAP3_MUSB0_BASE;
|
|
|
|
#define OMAP34XX_USB_EP(n) (omap3_usb_base + 0x100 + 0x10 * (n))
|
|
|
|
#define MUSB_RXCSR 0x06
|
|
#define MUSB_RXCOUNT 0x08
|
|
#define MUSB_TXCSR 0x02
|
|
#define MUSB_FIFOSIZE 0x0F
|
|
#define OMAP34XX_USB_RXCSR(n) (OMAP34XX_USB_EP(n) + MUSB_RXCSR)
|
|
#define OMAP34XX_USB_RXCOUNT(n) (OMAP34XX_USB_EP(n) + MUSB_RXCOUNT)
|
|
#define OMAP34XX_USB_TXCSR(n) (OMAP34XX_USB_EP(n) + MUSB_TXCSR)
|
|
#define OMAP34XX_USB_FIFOSIZE(n) (OMAP34XX_USB_EP(n) + MUSB_FIFOSIZE)
|
|
#define OMAP34XX_USB_FIFO(n) (omap3_usb_base + 0x20 + ((n) * 4))
|
|
|
|
/* memory mapped registers */
|
|
#define BULK_ENDPOINT 1
|
|
#define MUSB_RXCSR_RXPKTRDY 0x0001
|
|
#define MUSB_TXCSR_TXPKTRDY 0x0001
|
|
|
|
#define PACK4(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a))
|
|
#define USBLOAD_CMD_FILE PACK4('U', 'S', 'B', 's') /* send file size */
|
|
#define USBLOAD_CMD_JUMP PACK4('U', 'S', 'B', 'j') /* go where I tell you */
|
|
#define USBLOAD_CMD_FILE_REQ PACK4('U', 'S', 'B', 'f') /* file request */
|
|
#define USBLOAD_CMD_ECHO_SZ PACK4('U', 'S', 'B', 'n') /* echo file size */
|
|
#define USBLOAD_CMD_REPORT_SZ PACK4('U', 'S', 'B', 'o') /* report file size */
|
|
#define USBLOAD_CMD_MESSAGE PACK4('U', 'S', 'B', 'm') /* message for debug */
|
|
|
|
static int usb_send(unsigned char *buffer, unsigned int buffer_size)
|
|
{
|
|
unsigned int cntr;
|
|
u16 txcsr;
|
|
void __iomem *reg = (void *)OMAP34XX_USB_TXCSR(BULK_ENDPOINT);
|
|
void __iomem *bulk_fifo = (void *)OMAP34XX_USB_FIFO(BULK_ENDPOINT);
|
|
|
|
txcsr = readw(reg);
|
|
|
|
if (txcsr & MUSB_TXCSR_TXPKTRDY)
|
|
return 0;
|
|
|
|
for (cntr = 0; cntr < buffer_size; cntr++)
|
|
writeb(buffer[cntr], bulk_fifo);
|
|
|
|
txcsr = readw(reg);
|
|
txcsr |= MUSB_TXCSR_TXPKTRDY;
|
|
writew(txcsr, reg);
|
|
|
|
return buffer_size;
|
|
}
|
|
|
|
static int usb_recv(u8 *buffer)
|
|
{
|
|
int cntr;
|
|
u16 count = 0;
|
|
u16 rxcsr;
|
|
void __iomem *reg = (void *)OMAP34XX_USB_RXCSR(BULK_ENDPOINT);
|
|
void __iomem *bulk_fifo = (void *)OMAP34XX_USB_FIFO(BULK_ENDPOINT);
|
|
|
|
rxcsr = readw(reg);
|
|
|
|
if (!(rxcsr & MUSB_RXCSR_RXPKTRDY))
|
|
return 0;
|
|
|
|
count = readw((void *)OMAP34XX_USB_RXCOUNT(BULK_ENDPOINT));
|
|
for (cntr = 0; cntr < count; cntr++)
|
|
*buffer++ = readb(bulk_fifo);
|
|
|
|
/* Clear the RXPKTRDY bit */
|
|
rxcsr = readw(reg);
|
|
rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
|
|
writew(rxcsr, reg);
|
|
|
|
return count;
|
|
}
|
|
|
|
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 *omap3_xload_boot_usb(void)
|
|
{
|
|
int res;
|
|
void *buf;
|
|
u32 *buf32;
|
|
u32 total;
|
|
void *addr;
|
|
u32 bytes;
|
|
int size;
|
|
int cntr;
|
|
void *fn;
|
|
u8 __buf[512];
|
|
|
|
buf32 = buf = __buf;
|
|
|
|
usb_msg (USBLOAD_CMD_FILE_REQ, "file req");
|
|
for (cntr = 0; cntr < 10000000; cntr++) {
|
|
size = usb_recv(buf);
|
|
if (!size)
|
|
continue;
|
|
|
|
switch (buf32[0]) {
|
|
case USBLOAD_CMD_FILE:
|
|
pr_debug ("USBLOAD_CMD_FILE total = %d size = 0x%x addr = 0x%x\n",
|
|
res, buf32[1], buf32[2]);
|
|
total = buf32[1]; /* get size and address */
|
|
addr = (void *)buf32[2];
|
|
usb_code(USBLOAD_CMD_ECHO_SZ, total);
|
|
|
|
bytes = 0;
|
|
|
|
while (bytes < total) {
|
|
size = usb_recv(buf);
|
|
memcpy(addr, buf, size);
|
|
addr += size;
|
|
bytes += size;
|
|
}
|
|
|
|
usb_code(USBLOAD_CMD_REPORT_SZ, total); /* tell him we got this many bytes */
|
|
usb_msg (USBLOAD_CMD_FILE_REQ, "file req"); /* see if they have another file for us */
|
|
break;
|
|
case USBLOAD_CMD_JUMP:
|
|
pr_debug("USBLOAD_CMD_JUMP total = %d addr = 0x%x val = 0x%x\n",
|
|
res, buf32[0], buf32[1]);
|
|
fn = (void *)buf32[1];
|
|
goto out;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
fn = NULL;
|
|
out:
|
|
|
|
return fn;
|
|
}
|