From 1d7c8ec1431aec1c75c79dc17ecad0ab80435311 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 24 Jun 2015 14:25:10 +0200 Subject: ARM: OMAP: Add omap3 USB loader tool 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 --- arch/arm/mach-omap/Kconfig | 15 ++ arch/arm/mach-omap/Makefile | 2 + arch/arm/mach-omap/include/mach/omap3-generic.h | 2 + arch/arm/mach-omap/omap3_xload_usb.c | 185 ++++++++++++++++++++++++ arch/arm/mach-omap/xload.c | 8 +- 5 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-omap/omap3_xload_usb.c (limited to 'arch') diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig index c86542370d..abf204a63d 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -120,6 +120,21 @@ config OMAP4_USBBOOT You need the utility program omap4_usbboot to boot from USB. Please read omap4_usb_booting.txt for more information. +config OMAP3_USBBOOT + bool "enable booting from USB" + depends on ARCH_OMAP3 + help + Say Y here if you want to be able to boot the 2nd stage via USB. This + works by transferring the 2nd stage image using the MUSB controller + which is already initialized by the ROM code. Use the omap3-usb-loader + tool selectable below to upload images. + +config OMAP3_USB_LOADER + bool "enable omap3 USB loader host tool" + depends on ARCH_OMAP3 + help + Say Y here to build the omap3 usb loader tool. + config OMAP_SERIALBOOT bool "enable booting from serial" select XYMODEM diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile index fcc2727713..65072b91e4 100644 --- a/arch/arm/mach-omap/Makefile +++ b/arch/arm/mach-omap/Makefile @@ -31,6 +31,8 @@ obj-$(CONFIG_OMAP_GPMC) += gpmc.o devices-gpmc-nand.o obj-$(CONFIG_SHELL_NONE) += xload.o obj-$(CONFIG_MFD_TWL6030) += omap4_twl6030_mmc.o obj-$(CONFIG_OMAP4_USBBOOT) += omap4_rom_usb.o +obj-$(CONFIG_OMAP3_USBBOOT) += omap3_xload_usb.o +pbl-$(CONFIG_OMAP3_USBBOOT) += omap3_xload_usb.o obj-$(CONFIG_CMD_BOOT_ORDER) += boot_order.o obj-$(CONFIG_BAREBOX_UPDATE_AM33XX_SPI_NOR_MLO) += am33xx_bbu_spi_mlo.o obj-$(CONFIG_BAREBOX_UPDATE_AM33XX_NAND) += am33xx_bbu_nand.o diff --git a/arch/arm/mach-omap/include/mach/omap3-generic.h b/arch/arm/mach-omap/include/mach/omap3-generic.h index 7db0838a5f..ab53b98971 100644 --- a/arch/arm/mach-omap/include/mach/omap3-generic.h +++ b/arch/arm/mach-omap/include/mach/omap3-generic.h @@ -29,4 +29,6 @@ void __noreturn omap3_reset_cpu(unsigned long addr); int omap3_init(void); int omap3_devices_init(void); +void *omap3_xload_boot_usb(void); + #endif /* __MACH_OMAP3_GENERIC_H */ diff --git a/arch/arm/mach-omap/omap3_xload_usb.c b/arch/arm/mach-omap/omap3_xload_usb.c new file mode 100644 index 0000000000..e7dc21e4a7 --- /dev/null +++ b/arch/arm/mach-omap/omap3_xload_usb.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015 Sascha Hauer , 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 +#include +#include +#include +#include + +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; +} diff --git a/arch/arm/mach-omap/xload.c b/arch/arm/mach-omap/xload.c index 85c9120ccf..4a0714ed93 100644 --- a/arch/arm/mach-omap/xload.c +++ b/arch/arm/mach-omap/xload.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -284,13 +285,16 @@ static __noreturn int omap_xload(void) func = omap_xload_boot_mmc(); break; case BOOTSOURCE_USB: - if (IS_ENABLED(CONFIG_FS_OMAP4_USBBOOT)) { + if (IS_ENABLED(CONFIG_OMAP3_USBBOOT) && cpu_is_omap3()) { + printf("booting from USB\n"); + func = omap3_xload_boot_usb(); + } else if (IS_ENABLED(CONFIG_FS_OMAP4_USBBOOT)) { printf("booting from USB\n"); func = omap4_xload_boot_usb(); - break; } else { printf("booting from USB not enabled\n"); } + break; case BOOTSOURCE_NAND: printf("booting from NAND\n"); func = omap_xload_boot_nand(barebox_part->nand_offset, -- cgit v1.2.3