diff --git a/arch/arm/boards/beagle/Makefile b/arch/arm/boards/beagle/Makefile index 01c7a25..3bee9a2 100644 --- a/arch/arm/boards/beagle/Makefile +++ b/arch/arm/boards/beagle/Makefile @@ -1,2 +1,3 @@ obj-y += board.o lwl-y += lowlevel.o +bbenv-y += defaultenv-beagle diff --git a/arch/arm/boards/beagle/board.c b/arch/arm/boards/beagle/board.c index c56205e..4ac9517 100644 --- a/arch/arm/boards/beagle/board.c +++ b/arch/arm/boards/beagle/board.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #ifdef CONFIG_DRIVER_SERIAL_NS16550 @@ -44,6 +46,9 @@ */ static int beagle_console_init(void) { + if (barebox_arm_machine() != MACH_TYPE_OMAP3_BEAGLE) + return 0; + barebox_set_model("Texas Instruments beagle"); barebox_set_hostname("beagle"); @@ -84,6 +89,9 @@ static int beagle_mem_init(void) { + if (barebox_arm_machine() != MACH_TYPE_OMAP3_BEAGLE) + return 0; + omap_add_ram0(SZ_128M); return 0; @@ -92,6 +100,9 @@ static int beagle_devices_init(void) { + if (barebox_arm_machine() != MACH_TYPE_OMAP3_BEAGLE) + return 0; + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); omap3_add_i2c1(NULL); @@ -114,6 +125,8 @@ bbu_register_std_file_update("nand", 0, "/dev/nand0.barebox.bb", filetype_arm_barebox); + defaultenv_append_directory(defaultenv_beagle); + return 0; } device_initcall(beagle_devices_init); diff --git a/arch/arm/boards/beagle/defaultenv-beagle/boot/mmc b/arch/arm/boards/beagle/defaultenv-beagle/boot/mmc new file mode 100644 index 0000000..db638f8 --- /dev/null +++ b/arch/arm/boards/beagle/defaultenv-beagle/boot/mmc @@ -0,0 +1,5 @@ +#!/bin/sh + +global.bootm.image="/boot/zImage" +#global.bootm.oftree="/boot/oftree" +global.linux.bootargs.dyn.root="root=mmcblk0p2 rootfstype=ext3 rootwait" diff --git a/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi new file mode 100644 index 0000000..e0ef904 --- /dev/null +++ b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi @@ -0,0 +1,4 @@ +#!/bin/sh + +global.bootm.image="/dev/nand0.kernel.bb" +global.linux.bootargs.dyn.root="root=ubi0:root ubi.mtd=nand0.root rootfstype=ubifs" diff --git a/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi-dt b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi-dt new file mode 100644 index 0000000..5fc0a6c --- /dev/null +++ b/arch/arm/boards/beagle/defaultenv-beagle/boot/nand-ubi-dt @@ -0,0 +1,5 @@ +#!/bin/sh + +global.bootm.image="/dev/nand0.kernel.bb" +global.bootm.oftree="/dev/nand0.oftree.bb" +global.linux.bootargs.dyn.root="root=ubi0:root ubi.mtd=nand0.root rootfstype=ubifs" diff --git a/arch/arm/boards/beagle/defaultenv-beagle/init/mtdparts-nand b/arch/arm/boards/beagle/defaultenv-beagle/init/mtdparts-nand new file mode 100644 index 0000000..9335bb1 --- /dev/null +++ b/arch/arm/boards/beagle/defaultenv-beagle/init/mtdparts-nand @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ "$1" = menu ]; then + init-menu-add-entry "$0" "NAND partitions" + exit +fi + +mtdparts="128k(nand0.xload),256k(nand0.barebox)ro,128k(nand0.bareboxenv),128k(nand0.oftree),4M(nand0.kernel),120M(nand0.rootfs),-(nand0.data)" +kernelname="omap2-nand" + +mtdparts-add -b -d nand0 -k ${kernelname} -p ${mtdparts} diff --git a/arch/arm/boards/beagle/defaultenv-beagle/network/eth0-discover b/arch/arm/boards/beagle/defaultenv-beagle/network/eth0-discover new file mode 100644 index 0000000..86d13f5 --- /dev/null +++ b/arch/arm/boards/beagle/defaultenv-beagle/network/eth0-discover @@ -0,0 +1,5 @@ +#!/bin/sh + +# The beagle board supports a network adapter on USB + +usb diff --git a/arch/arm/boards/beagle/env/boot/mmc b/arch/arm/boards/beagle/env/boot/mmc deleted file mode 100644 index db638f8..0000000 --- a/arch/arm/boards/beagle/env/boot/mmc +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -global.bootm.image="/boot/zImage" -#global.bootm.oftree="/boot/oftree" -global.linux.bootargs.dyn.root="root=mmcblk0p2 rootfstype=ext3 rootwait" diff --git a/arch/arm/boards/beagle/env/boot/nand-ubi b/arch/arm/boards/beagle/env/boot/nand-ubi deleted file mode 100644 index e0ef904..0000000 --- a/arch/arm/boards/beagle/env/boot/nand-ubi +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -global.bootm.image="/dev/nand0.kernel.bb" -global.linux.bootargs.dyn.root="root=ubi0:root ubi.mtd=nand0.root rootfstype=ubifs" diff --git a/arch/arm/boards/beagle/env/boot/nand-ubi-dt b/arch/arm/boards/beagle/env/boot/nand-ubi-dt deleted file mode 100644 index 5fc0a6c..0000000 --- a/arch/arm/boards/beagle/env/boot/nand-ubi-dt +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -global.bootm.image="/dev/nand0.kernel.bb" -global.bootm.oftree="/dev/nand0.oftree.bb" -global.linux.bootargs.dyn.root="root=ubi0:root ubi.mtd=nand0.root rootfstype=ubifs" diff --git a/arch/arm/boards/beagle/env/init/mtdparts-nand b/arch/arm/boards/beagle/env/init/mtdparts-nand deleted file mode 100644 index 9335bb1..0000000 --- a/arch/arm/boards/beagle/env/init/mtdparts-nand +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -if [ "$1" = menu ]; then - init-menu-add-entry "$0" "NAND partitions" - exit -fi - -mtdparts="128k(nand0.xload),256k(nand0.barebox)ro,128k(nand0.bareboxenv),128k(nand0.oftree),4M(nand0.kernel),120M(nand0.rootfs),-(nand0.data)" -kernelname="omap2-nand" - -mtdparts-add -b -d nand0 -k ${kernelname} -p ${mtdparts} diff --git a/arch/arm/boards/beagle/env/network/eth0-discover b/arch/arm/boards/beagle/env/network/eth0-discover deleted file mode 100644 index 86d13f5..0000000 --- a/arch/arm/boards/beagle/env/network/eth0-discover +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -# The beagle board supports a network adapter on USB - -usb diff --git a/arch/arm/boards/beagle/lowlevel.c b/arch/arm/boards/beagle/lowlevel.c index d6e6b9f..30cc1f2 100644 --- a/arch/arm/boards/beagle/lowlevel.c +++ b/arch/arm/boards/beagle/lowlevel.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include /** * @brief Do the pin muxing required for Board operation. @@ -157,6 +159,22 @@ return; } +static noinline int beagle_board_init_sdram(void) +{ + struct barebox_arm_boarddata *bd = (void *)OMAP3_SRAM_SCRATCH_SPACE + 0x10; + + boarddata_create(bd, MACH_TYPE_OMAP3_BEAGLE); + + barebox_arm_entry(0x80000000, SZ_128M, bd); +} + +ENTRY_FUNCTION(start_omap3_beagleboard_sdram, bootinfo, r1, r2) +{ + omap3_save_bootinfo((void *)bootinfo); + + beagle_board_init_sdram(); +} + /** * @brief The basic entry point for board initialization. * @@ -166,28 +184,37 @@ * * @return void */ -static int beagle_board_init(void) +static noinline int beagle_board_init(void) { int in_sdram = omap3_running_in_sdram(); + struct barebox_arm_boarddata bd; if (!in_sdram) omap3_core_init(); mux_config(); + + omap_uart_lowlevel_init((void *)OMAP3_UART3_BASE); + /* Dont reconfigure SDRAM while running in SDRAM! */ if (!in_sdram) sdrc_init(); - return 0; + boarddata_create(&bd, MACH_TYPE_OMAP3_BEAGLE); + + barebox_arm_entry(0x80000000, SZ_128M, &bd); } -void __naked __bare_init barebox_arm_reset_vector(uint32_t *data) +ENTRY_FUNCTION(start_omap3_beagleboard_sram, bootinfo, r1, r2) { - omap3_save_bootinfo(data); + omap3_save_bootinfo((void *)bootinfo); arm_cpu_lowlevel_init(); - beagle_board_init(); + omap3_gp_romcode_call(OMAP3_GP_ROMCODE_API_L2_INVAL, 0); - barebox_arm_entry(0x80000000, SZ_128M, NULL); + relocate_to_current_adr(); + setup_c(); + + beagle_board_init(); } diff --git a/arch/arm/configs/omap3530_beagle_defconfig b/arch/arm/configs/omap3530_beagle_defconfig index 3068fbb..070f156 100644 --- a/arch/arm/configs/omap3530_beagle_defconfig +++ b/arch/arm/configs/omap3530_beagle_defconfig @@ -1,67 +1,79 @@ CONFIG_ARCH_OMAP=y +CONFIG_OMAP_MULTI_BOARDS=y CONFIG_MACH_BEAGLE=y CONFIG_THUMB2_BAREBOX=y -CONFIG_CMD_ARM_MMUINFO=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y -CONFIG_PBL_IMAGE=y CONFIG_MMU=y -CONFIG_TEXT_BASE=0x87e00000 -CONFIG_MALLOC_SIZE=0x2000000 +CONFIG_TEXT_BASE=0x0 +CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y +CONFIG_RELOCATABLE=y CONFIG_PROMPT="barebox> " -CONFIG_LONGHELP=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +CONFIG_BLSPEC=y +CONFIG_IMD_TARGET=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/beagle/env" -CONFIG_CMD_EDIT=y -CONFIG_CMD_SLEEP=y -CONFIG_CMD_MSLEEP=y -CONFIG_CMD_SAVEENV=y -CONFIG_CMD_EXPORT=y -CONFIG_CMD_PRINTENV=y -CONFIG_CMD_READLINE=y -CONFIG_CMD_MENU=y -CONFIG_CMD_MENU_MANAGEMENT=y -CONFIG_CMD_TIME=y -CONFIG_CMD_DIRNAME=y -CONFIG_CMD_LN=y -CONFIG_CMD_READLINK=y -CONFIG_CMD_TFTP=y -CONFIG_CMD_ECHO_E=y -CONFIG_CMD_LOADB=y -CONFIG_CMD_MEMINFO=y +CONFIG_RESET_SOURCE=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_OMAP_UART_PORT=3 +CONFIG_DEBUG_INITCALLS=y +CONFIG_CMD_DMESG=y +CONFIG_LONGHELP=y CONFIG_CMD_IOMEM=y -CONFIG_CMD_CRC=y -CONFIG_CMD_CRC_CMP=y -CONFIG_CMD_MD5SUM=y -CONFIG_CMD_FLASH=y +CONFIG_CMD_IMD=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_ARM_MMUINFO=y CONFIG_CMD_BOOTM_SHOW_TYPE=y CONFIG_CMD_BOOTM_VERBOSE=y CONFIG_CMD_BOOTM_INITRD=y CONFIG_CMD_BOOTM_OFTREE=y CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y # CONFIG_CMD_BOOTU is not set -CONFIG_CMD_RESET=y CONFIG_CMD_GO=y -CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_RESET=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_DEFAULTENV=y +CONFIG_CMD_PRINTENV=y CONFIG_CMD_MAGICVAR=y CONFIG_CMD_MAGICVAR_HELP=y -CONFIG_CMD_GPIO=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_FILETYPE=y +CONFIG_CMD_LN=y +CONFIG_CMD_MD5SUM=y CONFIG_CMD_UNCOMPRESS=y -CONFIG_CMD_I2C=y -CONFIG_CMD_MIITOOL=y -CONFIG_NET=y +CONFIG_CMD_MSLEEP=y +CONFIG_CMD_READF=y +CONFIG_CMD_SLEEP=y CONFIG_CMD_DHCP=y -CONFIG_NET_NFS=y +CONFIG_CMD_HOST=y +CONFIG_CMD_MIITOOL=y CONFIG_CMD_PING=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_MENU=y +CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_MENUTREE=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_CRC=y +CONFIG_CMD_CRC_CMP=y +CONFIG_CMD_DETECT=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_BAREBOX_UPDATE=y +CONFIG_CMD_TIME=y +CONFIG_NET=y +CONFIG_NET_NFS=y CONFIG_NET_NETCONSOLE=y -CONFIG_NET_RESOLV=y CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y CONFIG_NET_USB=y @@ -81,6 +93,7 @@ CONFIG_MCI_STARTUP=y CONFIG_MCI_OMAP_HSMMC=y CONFIG_MFD_TWL4030=y +CONFIG_FS_EXT4=y CONFIG_FS_TFTP=y CONFIG_FS_NFS=y CONFIG_FS_FAT=y diff --git a/arch/arm/configs/omap3530_beagle_xload_defconfig b/arch/arm/configs/omap3530_beagle_xload_defconfig index 585ee0f..074cc21 100644 --- a/arch/arm/configs/omap3530_beagle_xload_defconfig +++ b/arch/arm/configs/omap3530_beagle_xload_defconfig @@ -1,21 +1,25 @@ CONFIG_ARCH_OMAP=y CONFIG_OMAP_BUILD_IFT=y +CONFIG_OMAP3_USBBOOT=y +CONFIG_OMAP3_USB_LOADER=y +CONFIG_OMAP_MULTI_BOARDS=y CONFIG_MACH_BEAGLE=y CONFIG_THUMB2_BAREBOX=y -# CONFIG_CMD_ARM_CPUINFO is not set -# CONFIG_ARM_EXCEPTIONS is not set -CONFIG_TEXT_BASE=0x40200000 -CONFIG_MEMORY_LAYOUT_FIXED=y -CONFIG_STACK_BASE=0x4020F000 +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_ARM_UNWIND=y +CONFIG_MMU=y +CONFIG_TEXT_BASE=0x0 CONFIG_STACK_SIZE=0xc00 -CONFIG_MALLOC_BASE=0x87BFFF10 +CONFIG_MALLOC_SIZE=0x0 CONFIG_MALLOC_DUMMY=y +CONFIG_RELOCATABLE=y CONFIG_PROMPT="X-load Beagle>" CONFIG_SHELL_NONE=y # CONFIG_ERRNO_MESSAGES is not set # CONFIG_TIMESTAMP is not set CONFIG_CONSOLE_SIMPLE=y # CONFIG_DEFAULT_ENVIRONMENT is not set +CONFIG_OFDEVICE=y CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y # CONFIG_SPI is not set @@ -33,6 +37,7 @@ CONFIG_MCI_STARTUP=y # CONFIG_MCI_WRITE is not set CONFIG_MCI_OMAP_HSMMC=y +# CONFIG_PINCTRL is not set # CONFIG_FS_RAMFS is not set # CONFIG_FS_DEVFS is not set CONFIG_FS_FAT=y diff --git a/arch/arm/configs/phytec-phycard-omap3_defconfig b/arch/arm/configs/phytec-phycard-omap3_defconfig index a2564d4..5865ebd 100644 --- a/arch/arm/configs/phytec-phycard-omap3_defconfig +++ b/arch/arm/configs/phytec-phycard-omap3_defconfig @@ -7,7 +7,6 @@ CONFIG_CPU_32v7=y CONFIG_ARCH_OMAP3=y CONFIG_OMAP_CLOCK_SOURCE_S32K=y -CONFIG_OMAP3_CLOCK_CONFIG=y CONFIG_OMAP3_COPY_CLOCK_SRAM=n CONFIG_OMAP_GPMC=y CONFIG_MACH_PCAAL1=y diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c index 91fd9b9..8e5097b 100644 --- a/arch/arm/cpu/start.c +++ b/arch/arm/cpu/start.c @@ -28,17 +28,22 @@ #include #include +#include #include "mmu-early.h" unsigned long arm_stack_top; static void *barebox_boarddata; -/* - * return the boarddata variable passed to barebox_arm_entry - */ -void *barebox_arm_boarddata(void) +u32 barebox_arm_machine(void) { - return barebox_boarddata; + struct barebox_arm_boarddata *bd; + + if (!barebox_boarddata) + return 0; + + bd = barebox_boarddata; + + return bd->machine; } static void *barebox_boot_dtb; @@ -83,17 +88,23 @@ } } - /* - * If boarddata is a pointer inside valid memory and contains a - * FDT magic then use it as later to probe devices - */ - if (boarddata && get_unaligned_be32(boarddata) == FDT_MAGIC) { - uint32_t totalsize = get_unaligned_be32(boarddata + 4); - endmem -= ALIGN(totalsize, 64); - barebox_boot_dtb = (void *)endmem; - pr_debug("found DTB in boarddata, copying to 0x%p\n", - barebox_boot_dtb); - memcpy(barebox_boot_dtb, boarddata, totalsize); + if (boarddata) { + if (get_unaligned_be32(boarddata) == FDT_MAGIC) { + uint32_t totalsize = get_unaligned_be32(boarddata + 4); + endmem -= ALIGN(totalsize, 64); + barebox_boot_dtb = (void *)endmem; + pr_debug("found DTB in boarddata, copying to 0x%p\n", + barebox_boot_dtb); + memcpy(barebox_boot_dtb, boarddata, totalsize); + } else if (((struct barebox_arm_boarddata *)boarddata)->magic == + BAREBOX_ARM_BOARDDATA_MAGIC) { + endmem -= ALIGN(sizeof(struct barebox_arm_boarddata), 64); + barebox_boarddata = (void *)endmem; + pr_debug("found machine type in boarddata, copying to 0x%p\n", + barebox_boarddata); + memcpy(barebox_boarddata, boarddata, + sizeof(struct barebox_arm_boarddata)); + } } if ((unsigned long)_text > membase + memsize || diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h index dbc8aaa..0b8acb8 100644 --- a/arch/arm/include/asm/barebox-arm.h +++ b/arch/arm/include/asm/barebox-arm.h @@ -48,7 +48,32 @@ void relocate_to_current_adr(void); void relocate_to_adr(unsigned long target); void __noreturn barebox_arm_entry(unsigned long membase, unsigned long memsize, void *boarddata); -void *barebox_arm_boarddata(void); + +struct barebox_arm_boarddata { +#define BAREBOX_ARM_BOARDDATA_MAGIC 0xabe742c3 + u32 magic; + u32 machine; /* machine number to pass to barebox. This may or may + * not be a ARM machine number registered on arm.linux.org.uk. + * It must only be unique across barebox. Please use a number + * that do not potientially clashes with registered machines, + * i.e. use a number > 0x10000. + */ +}; + +/* + * Create a boarddata struct at given address. Suitable to be passed + * as boarddata to barebox_arm_entry(). The machine can be retrieved + * later with barebox_arm_machine(). + */ +static inline void boarddata_create(void *adr, u32 machine) +{ + struct barebox_arm_boarddata *bd = adr; + + bd->magic = BAREBOX_ARM_BOARDDATA_MAGIC; + bd->machine = machine; +} + +u32 barebox_arm_machine(void); #if defined(CONFIG_RELOCATABLE) && defined(CONFIG_ARM_EXCEPTIONS) void arm_fixup_vectors(void); diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig index bc00d5b..af35975 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -54,14 +54,6 @@ config OMAP_CLOCK_SOURCE_DMTIMER0 bool -config OMAP3_CLOCK_CONFIG - prompt "Clock Configuration" - bool - depends on ARCH_OMAP3 - default y - help - Say Y here if you like to have OMAP3 Clock configuration done. - config OMAP_GPMC prompt "Support for GPMC configuration" bool @@ -128,6 +120,21 @@ 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 @@ -150,6 +157,13 @@ help Say Y here if you are using afis GF +config MACH_BEAGLE + bool "Texas Instrument's Beagle Board" + select HAVE_DEFAULT_ENVIRONMENT_NEW + select ARCH_OMAP3 + help + Say Y here if you are using Beagle Board + config MACH_BEAGLEBONE bool "Texas Instrument's Beagle Bone" select ARCH_AM33XX @@ -173,13 +187,6 @@ help Say Y here if you are using SDP343x platform -config MACH_BEAGLE - bool "Texas Instrument's Beagle Board" - select HAVE_DEFAULT_ENVIRONMENT_NEW - select ARCH_OMAP3 - help - Say Y here if you are using Beagle Board - config MACH_OMAP3EVM bool "Texas Instrument's OMAP3 EVM" select ARCH_OMAP3 diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile index bef1d05..65072b9 100644 --- a/arch/arm/mach-omap/Makefile +++ b/arch/arm/mach-omap/Makefile @@ -25,12 +25,14 @@ pbl-$(CONFIG_ARCH_OMAP4) += omap4_generic.o omap4_clock.o obj-pbl-$(CONFIG_ARCH_AM33XX) += am33xx_generic.o am33xx_clock.o am33xx_mux.o obj-$(CONFIG_ARCH_AM33XX) += am33xx_scrm.o -obj-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock.o -pbl-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock.o +obj-$(CONFIG_ARCH_OMAP3) += omap3_clock.o +pbl-$(CONFIG_ARCH_OMAP3) += omap3_clock.o 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-clock.h b/arch/arm/mach-omap/include/mach/omap3-clock.h index 1ef46aa..7c52da7 100644 --- a/arch/arm/mach-omap/include/mach/omap3-clock.h +++ b/arch/arm/mach-omap/include/mach/omap3-clock.h @@ -107,7 +107,7 @@ /* PER DPLL */ #define PER_M6X2 3 /* 288MHz: CM_CLKSEL1_EMU */ #define PER_M5X2 4 /* 216MHz: CM_CLKSEL_CAM */ -#define PER_M4X2 9 /* 96MHz : CM_CLKSEL_DSS-dss1 */ +#define PER_M4X2 2 /* 432MHz: CM_CLKSEL_DSS-dss1 */ #define PER_M3X2 16 /* 54MHz : CM_CLKSEL_DSS-tv */ #define CLSEL1_EMU_VAL ((CORE_M3X2 << 16) | (PER_M6X2 << 24) | (0x0a50)) diff --git a/arch/arm/mach-omap/include/mach/omap3-generic.h b/arch/arm/mach-omap/include/mach/omap3-generic.h index 7db0838..ab53b98 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 @@ 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_generic.c b/arch/arm/mach-omap/omap3_generic.c index dbb0b5f..0f2e9ce 100644 --- a/arch/arm/mach-omap/omap3_generic.c +++ b/arch/arm/mach-omap/omap3_generic.c @@ -435,9 +435,6 @@ * Does early system init of disabling the watchdog, enable * memory and configuring the clocks. * - * prcm_init is called only if CONFIG_OMAP3_CLOCK_CONFIG is defined. - * We depend on link time clean up to remove a_init if no caller exists. - * * @warning Called path is with SRAM stack * * @return void @@ -459,9 +456,7 @@ sdelay(100); -#ifdef CONFIG_OMAP3_CLOCK_CONFIG prcm_init(); -#endif } #define OMAP3_TRACING_VECTOR1 0x4020ffb4 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 0000000..e7dc21e --- /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 85c9120..4a0714e 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 @@ 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, diff --git a/drivers/bus/omap-gpmc.c b/drivers/bus/omap-gpmc.c index 6752c42..8ae909a 100644 --- a/drivers/bus/omap-gpmc.c +++ b/drivers/bus/omap-gpmc.c @@ -24,6 +24,14 @@ #define GPMC_CS_NUM 8 #define GPMC_NR_WAITPINS 4 +#define GPMC_BURST_4 4 /* 4 word burst */ +#define GPMC_BURST_8 8 /* 8 word burst */ +#define GPMC_BURST_16 16 /* 16 word burst */ +#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */ +#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */ +#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */ +#define GPMC_MUX_AD 2 /* Addr-Data multiplex */ + #define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31) #define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30) #define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29) @@ -55,6 +63,9 @@ #define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN (1 << 7) #define GPMC_CONFIG7_CSVALID (1 << 6) +#define GPMC_DEVICETYPE_NOR 0 +#define GPMC_DEVICETYPE_NAND 2 + static unsigned int gpmc_cs_num = GPMC_CS_NUM; static unsigned int gpmc_nr_waitpins; static unsigned long gpmc_l3_clk = 100000000; /* This should be a proper clock */ @@ -149,7 +160,7 @@ if (p->oe_extra_delay) gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY; if (p->we_extra_delay) - gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY; + gpmc_config->cfg[3] |= GPMC_CONFIG4_WEEXTRADELAY; if (p->cycle2cyclesamecsen) gpmc_config->cfg[5] |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN; if (p->cycle2cyclediffcsen) @@ -220,6 +231,8 @@ if (div < 0) return div; + gpmc_config->cfg[0] |= div - 1; + ret |= set_cfg(gpmc_config, 0, 18, 19, t->wait_monitoring); ret |= set_cfg(gpmc_config, 0, 25, 26, t->clk_activation); @@ -255,6 +268,60 @@ return 0; } +static int gpmc_settings_to_config(struct gpmc_config *gpmc_config, + struct gpmc_settings *p) +{ + u32 config1 = gpmc_config->cfg[0]; + + /* Page/burst mode supports lengths of 4, 8 and 16 bytes */ + if (p->burst_read || p->burst_write) { + switch (p->burst_len) { + case GPMC_BURST_4: + case GPMC_BURST_8: + case GPMC_BURST_16: + break; + default: + pr_err("%s: invalid page/burst-length (%d)\n", + __func__, p->burst_len); + return -EINVAL; + } + } + + if (p->wait_pin > gpmc_nr_waitpins) { + pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin); + return -EINVAL; + } + + config1 |= GPMC_CONFIG1_DEVICESIZE((p->device_width - 1)); + + if (p->sync_read) + config1 |= GPMC_CONFIG1_READTYPE_SYNC; + if (p->sync_write) + config1 |= GPMC_CONFIG1_WRITETYPE_SYNC; + if (p->wait_on_read) + config1 |= GPMC_CONFIG1_WAIT_READ_MON; + if (p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_WRITE_MON; + if (p->wait_on_read || p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin); + if (p->device_nand) + config1 |= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND); + if (p->mux_add_data) + config1 |= GPMC_CONFIG1_MUXTYPE(p->mux_add_data); + if (p->burst_read) + config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP; + if (p->burst_write) + config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP; + if (p->burst_read || p->burst_write) { + config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3); + config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0; + } + + gpmc_config->cfg[0] = config1; + + return 0; +} + /** * gpmc_read_settings_dt - read gpmc settings from device-tree * @np: pointer to device-tree node for a gpmc child device @@ -464,6 +531,77 @@ return 0; } +/** + * gpmc_probe_generic_child - configures the gpmc for a child device + * @pdev: pointer to gpmc platform device + * @child: pointer to device-tree node for child device + * + * Allocates and configures a GPMC chip-select for a child device. + * Returns 0 on success and appropriate negative error code on failure. + */ +static int gpmc_probe_generic_child(struct device_d *dev, + struct device_node *child) +{ + struct gpmc_settings gpmc_s = {}; + struct gpmc_timings gpmc_t = {}; + struct resource res; + int ret, cs; + struct gpmc_config cfg = {}; + resource_size_t size; + + if (of_property_read_u32(child, "reg", &cs) < 0) { + dev_err(dev, "%s has no 'reg' property\n", + child->full_name); + return -ENODEV; + } + + if (of_address_to_resource(child, 0, &res) < 0) { + dev_err(dev, "%s has malformed 'reg' property\n", + child->full_name); + return -ENODEV; + } + + gpmc_read_settings_dt(child, &gpmc_s); + gpmc_read_timings_dt(child, &gpmc_t); + + ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width); + if (ret < 0) + goto err; + + gpmc_timings_to_config(&cfg, &gpmc_t); + + cfg.base = res.start; + + size = resource_size(&res); + if (size > SZ_64M) + cfg.size = GPMC_SIZE_128M; + else if (size > SZ_32M) + cfg.size = GPMC_SIZE_64M; + else if (size > SZ_16M) + cfg.size = GPMC_SIZE_32M; + else + cfg.size = GPMC_SIZE_16M; + + gpmc_settings_to_config(&cfg, &gpmc_s); + + gpmc_cs_config(cs, &cfg); + + /* create platform device, NULL on error or when disabled */ + if (of_get_property(child, "compatible", NULL) && !of_platform_device_create(child, dev)) + goto err_child_fail; + + return 0; + +err_child_fail: + + dev_err(dev, "failed to create gpmc child %s\n", child->name); + ret = -ENODEV; + +err: + + return ret; +} + static int gpmc_probe(struct device_d *dev) { struct device_node *child, *node = dev->device_node; @@ -488,6 +626,10 @@ if (!strncmp(child->name, "nand", 4)) ret = gpmc_probe_nand_child(dev, child); + else if (strncmp(child->name, "ethernet", 8) == 0 || + strncmp(child->name, "nor", 3) == 0 || + strncmp(child->name, "uart", 4) == 0) + ret = gpmc_probe_generic_child(dev, child); else dev_warn(dev, "unhandled child %s\n", child->name); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index ab3ccab..2c075db 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -118,7 +118,7 @@ * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ -static struct device_d *of_platform_device_create(struct device_node *np, +struct device_d *of_platform_device_create(struct device_node *np, struct device_d *parent) { struct device_d *dev; diff --git a/images/Makefile b/images/Makefile index 6ee1dcc..a5f589b 100644 --- a/images/Makefile +++ b/images/Makefile @@ -107,6 +107,7 @@ include $(srctree)/images/Makefile.imxhabv4 include $(srctree)/images/Makefile.mvebu include $(srctree)/images/Makefile.mxs +include $(srctree)/images/Makefile.omap3 include $(srctree)/images/Makefile.rockchip include $(srctree)/images/Makefile.socfpga include $(srctree)/images/Makefile.tegra diff --git a/images/Makefile.omap3 b/images/Makefile.omap3 new file mode 100644 index 0000000..694ec30 --- /dev/null +++ b/images/Makefile.omap3 @@ -0,0 +1,19 @@ +# %.mlo - convert into mlo image +# ---------------------------------------------------------------- +quiet_cmd_omap3_mlo_image = MLO $@ + cmd_omap3_mlo_image = scripts/omap_signGP -o $@ -l 0x40200000 -c $< + +$(obj)/%.omap3_mlo: $(obj)/% FORCE + $(call if_changed,omap3_mlo_image) + +pblx-$(CONFIG_MACH_BEAGLE) += start_omap3_beagleboard_sdram start_omap3_beagleboard_sram +FILE_barebox-beagleboard.img = start_omap3_beagleboard_sdram.pblx +omap3-barebox-$(CONFIG_MACH_BEAGLE) += barebox-beagleboard.img +FILE_barebox-beagleboard-mlo.img = start_omap3_beagleboard_sram.pblx.omap3_mlo +omap3-mlo-$(CONFIG_MACH_BEAGLE) += barebox-beagleboard-mlo.img + +ifdef CONFIG_OMAP_BUILD_IFT +image-y += $(omap3-mlo-y) +else +image-y += $(omap3-barebox-y) +endif diff --git a/include/of.h b/include/of.h index c02f5f4..1db210b 100644 --- a/include/of.h +++ b/include/of.h @@ -224,6 +224,8 @@ extern struct device_node *of_get_root_node(void); extern int of_set_root_node(struct device_node *node); +extern struct device_d *of_platform_device_create(struct device_node *np, + struct device_d *parent); extern int of_platform_populate(struct device_node *root, const struct of_device_id *matches, struct device_d *parent); diff --git a/scripts/Makefile b/scripts/Makefile index 74c2213..a3f6222 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -24,6 +24,9 @@ HOSTCFLAGS_mxs-usb-loader.o = `pkg-config --cflags libusb-1.0` HOSTLOADLIBES_mxs-usb-loader = `pkg-config --libs libusb-1.0` hostprogs-$(CONFIG_ARCH_MXS_USBLOADER) += mxs-usb-loader +HOSTCFLAGS_omap3-usb-loader.o = `pkg-config --cflags libusb-1.0` +HOSTLOADLIBES_omap3-usb-loader = `pkg-config --libs libusb-1.0` +hostprogs-$(CONFIG_OMAP3_USB_LOADER) += omap3-usb-loader subdir-y += mod subdir-$(CONFIG_OMAP4_USBBOOT) += omap4_usbboot diff --git a/scripts/omap3-usb-loader.c b/scripts/omap3-usb-loader.c new file mode 100644 index 0000000..edf6043 --- /dev/null +++ b/scripts/omap3-usb-loader.c @@ -0,0 +1,921 @@ +/* + * OMAP Loader, a USB uploader application targeted at OMAP3 processors + * Copyright (C) 2008 Martin Mueller + * Copyright (C) 2014 Grant Hernandez + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Reasons for the name change: this is a complete rewrite of + * the unversioned omap3_usbload so to lower ambiguity the name was changed. + * The GPLv2 license specifies rewrites as derived work. + */ +#define PROG_NAME "OMAP Loader" +#define VERSION "1.0.0" + +#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define OMAP_IS_BIG_ENDIAN +#endif + +#ifdef OMAP_IS_BIG_ENDIAN +#include +#endif + +#include /* for usleep and friends */ +#include +#include +#include /* for basename */ + +#include /* the main event */ + +/* Device specific defines (OMAP) + * Primary source: http://www.ti.com/lit/pdf/sprugn4 + * Section 26.4.5 "Peripheral Booting" + */ +#define OMAP_BASE_ADDRESS 0x40200000 +#define OMAP_PERIPH_BOOT 0xF0030002 +#define OMAP_VENDOR_ID 0x0451 +#define OMAP_PRODUCT_ID 0xD00E +/* TODO: dynamically discover these endpoints */ +#define OMAP_USB_BULK_IN 0x81 +#define OMAP_USB_BULK_OUT 0x01 +#define OMAP_ASIC_ID_LEN 69 + +#ifdef OMAP_IS_BIG_ENDIAN +#define cpu_to_le32(v) (((v & 0xff) << 24) | ((v & 0xff00) << 8) | \ + ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24)) +#define le32_to_cpu(v) cpu_to_le32(v) +#else +#define cpu_to_le32(v) (v) +#define le32_to_cpu(v) (v) +#endif + +/* + * taken from x-loader/drivers/usb/usb.c + * All credit to Martin Mueller + */ +#define PACK4(a,b,c,d) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)) +#define USBLOAD_CMD_FILE PACK4('U','S','B','s') /* file size request */ +#define USBLOAD_CMD_FILE_REQ PACK4('U','S','B','f') /* file size resp */ +#define USBLOAD_CMD_JUMP PACK4('U','S','B','j') /* execute code here */ +#define USBLOAD_CMD_ECHO_SZ PACK4('U','S','B','n') /* file size confirm to */ +#define USBLOAD_CMD_REPORT_SZ PACK4('U','S','B','o') /* confirm full file */ +#define USBLOAD_CMD_MESSAGE PACK4('U','S','B','m') /* debug message */ + +/* USB transfer characteristics */ +#define USB_MAX_WAIT 5000 +#define USB_TIMEOUT 1000 +#define USB_MAX_TIMEOUTS (USB_MAX_WAIT/USB_TIMEOUT) + +/* stores the data and attributes of a file to upload in to memory */ +struct file_upload { + size_t size; + void *data; + uint32_t addr; + char *path; + char *basename; +}; + +/* stores all of the arguments read in by getopt in main() */ +struct arg_state { + struct file_upload **files; + int numfiles; + uint32_t jumptarget; + uint16_t vendor, product; +}; + +static int g_verbose = 0; + +static void log_error(char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + fprintf(stdout, "[-] "); + vfprintf(stdout, fmt, va); + va_end(va); +} + +static void log_info(char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + fprintf(stdout, "[+] "); + vfprintf(stdout, fmt, va); + va_end(va); +} + +static bool omap_usb_read(libusb_device_handle *handle, unsigned char *data, + int length, int *actuallength) +{ + int ret = 0; + int iter = 0; + int sizeleft = length; + + if (!actuallength) + return false; + + while (sizeleft > 0) { + int actualread = 0; + int readamt = sizeleft; + + ret = libusb_bulk_transfer(handle, OMAP_USB_BULK_IN, data + iter, + readamt, &actualread, USB_TIMEOUT); + + if (ret == LIBUSB_ERROR_TIMEOUT) { + sizeleft -= actualread; + iter += actualread; + + /* we got some data, lets cut our losses and stop here */ + if (iter > 0) + break; + + log_error("device timed out while transfering in %d bytes (got %d)\n", + length, iter); + + return false; + } else if (ret == LIBUSB_SUCCESS) { + /* we cant trust actualRead on anything but a timeout or success */ + sizeleft -= actualread; + iter += actualread; + + /* stop at the first sign of data */ + if (iter > 0) + break; + } else { + log_error("fatal transfer error (BULK_IN) for %d bytes (got %d): %s\n", + length, iter, libusb_error_name(ret)); + return false; + } + } + + *actuallength = iter; + + return true; +} + +static bool omap_usb_write(libusb_device_handle *handle, void *data, int length) +{ + int ret = 0; + int numtimeouts = 0; + int iter = 0; + int sizeleft = length; + + while (sizeleft > 0) { + int actualwrite = 0; + int writeamt = sizeleft > 512 ? 512 : sizeleft; + + ret = libusb_bulk_transfer(handle, OMAP_USB_BULK_OUT, data + iter, + writeamt, &actualwrite, USB_TIMEOUT); + + if (ret == LIBUSB_ERROR_TIMEOUT) { + numtimeouts++; + sizeleft -= actualwrite; + iter += actualwrite; + + /* build in some reliablity */ + if (numtimeouts > USB_MAX_TIMEOUTS) { + log_error("device timed out while transfering out %d bytes (%d made it)\n", + length, iter); + return false; + } + } else if (ret == LIBUSB_SUCCESS) { + /* we cant trust actualWrite on anything but a timeout or success */ + sizeleft -= actualwrite; + iter += actualwrite; + } else { + log_error("fatal transfer error (BULK_OUT) for %d bytes (%d made it): %s\n", + length, iter, libusb_error_name(ret)); + return false; + } + } + + return true; +} + +static unsigned char *omap_usb_get_string(libusb_device_handle *handle, uint8_t idx) +{ + unsigned char *data = NULL; + int len = 0; + int ret = 0; + + if (!handle) + return NULL; + + while (true) { + if (!len || ret < 0) { + len += 256; + data = realloc(data, len); + + if (!data) + return NULL; + } + + ret = libusb_get_string_descriptor_ascii(handle, idx, data, len); + + /* we can still recover... */ + if (ret < 0) { + if (ret == LIBUSB_ERROR_INVALID_PARAM) + continue; /* try again with an increased size */ + + log_error("failed to lookup string index %hhu: %s\n", + idx, libusb_error_name(ret)); + + /* unrecoverable */ + free(data); + return NULL; + } else { + /* we got something! */ + break; + } + } + + return data; +} + +uint16_t omap_products[] = { + 0xd009, + 0xd00f, +}; + +static libusb_device_handle *omap_usb_open(libusb_context *ctx, uint16_t vendor, uint16_t product) +{ + libusb_device **devlist; + libusb_device_handle *handle; + struct libusb_device_descriptor desc; + ssize_t count, i; + int ret; + + log_info("scanning for USB device matching %04hx:%04hx...\n", + vendor, product); + + while (1) { + if ((count = libusb_get_device_list(ctx, &devlist)) < 0) { + log_error("failed to gather USB device list: %s\n", + libusb_error_name(count)); + return NULL; + } + + for (i = 0; i < count; i++) { + ret = libusb_get_device_descriptor(devlist[i], &desc); + if (ret < 0) { + log_error("failed to get USB device descriptor: %s\n", + libusb_error_name(ret)); + libusb_free_device_list(devlist, 1); + return NULL; + } + + if (desc.idVendor != vendor) + continue; + + if (product) { + if (desc.idProduct != product) + continue; + goto found; + } + + for (i = 0; i < sizeof(omap_products) / sizeof(uint16_t); i++) + if (desc.idProduct == omap_products[i]) { + product = desc.idProduct; + goto found; + } + } + + libusb_free_device_list(devlist, 1); + + /* nothing found yet. have a 10ms nap */ + usleep(10000); + } +found: + ret = libusb_open(devlist[i], &handle); + if (ret < 0) { + log_error("failed to open USB device %04hx:%04hx: %s\n", + vendor, product, libusb_error_name(ret)); + libusb_free_device_list(devlist, 1); + return NULL; + } + + ret = libusb_claim_interface(handle, 0); + if (ret) { + printf("Claim failed\n"); + return NULL; + } + + /* grab the manufacturer and product strings for printing */ + unsigned char *mfgstr = omap_usb_get_string(handle, desc.iManufacturer); + unsigned char *prodstr = omap_usb_get_string(handle, desc.iProduct); + + log_info("successfully opened %04hx:%04hx (", vendor, product); + + if (mfgstr) { + fprintf(stdout, prodstr ? "%s " : "%s", mfgstr); + free(mfgstr); + } + + if (prodstr) { + fprintf(stdout, "%s", prodstr); + free(prodstr); + } + + fprintf(stdout, ")\n"); + + return handle; +} + +static unsigned char *read_file(char *path, size_t *readamt) +{ + FILE *fp = fopen(path, "rb"); + + if (!fp) { + log_error("failed to open file \'%s\': %s\n", path, + strerror(errno)); + return NULL; + } + + unsigned char *data = NULL; + size_t allocsize = 0; + size_t iter = 0; + + while (1) { + if (iter >= iter) { + allocsize += 1024; + data = realloc(data, allocsize); + if (!data) + return NULL; + } + + size_t readsize = allocsize - iter; + size_t ret = fread(data + iter, sizeof (unsigned char), readsize, fp); + + iter += ret; + + if (ret != readsize) { + if (feof(fp)) { + break; + } else if (ferror(fp)) { + log_error("error file reading file \'%s\': %s\n", + path, strerror(errno)); + free(data); + return NULL; + } + } + } + + /* trim the allocation down to size */ + data = realloc(data, iter); + *readamt = iter; + + return data; +} + +static int transfer_first_stage(libusb_device_handle * handle, struct arg_state *args) +{ + unsigned char *buffer = NULL; + uint32_t cmd = 0; + uint32_t filelen = 0; + int bufsize = 0x200; + int transLen = 0; + int i; + void *data; + uint32_t *dbuf; + + struct file_upload *file = args->files[0]; + + /* TODO determine buffer size based on endpoint */ + buffer = calloc(bufsize, sizeof (unsigned char)); + filelen = cpu_to_le32(file->size); + + data = file->data; + dbuf = data; + + if (le32toh(dbuf[5]) == 0x45534843) { + int chsettingssize = 512 + 2 * sizeof(uint32_t); + + log_info("CHSETTINGS image detected. Skipping header\n"); + + data += chsettingssize; + filelen -= chsettingssize; + } + + /* read the ASIC ID */ + if (!omap_usb_read(handle, buffer, bufsize, &transLen)) { + log_error("failed to read ASIC ID from USB connection. " + "Check your USB device!\n"); + goto fail; + } + + if (transLen != OMAP_ASIC_ID_LEN) { + log_error("got some ASIC ID, but it's not the right length, %d " + "(expected %d)\n", transLen, OMAP_ASIC_ID_LEN); + goto fail; + } + + /* optionally, print some ASIC ID info */ + if (g_verbose) { + char *fields[] = + { "Num Subblocks", "Device ID Info", "Reserved", + "Ident Data", "Reserved", "CRC (4 bytes)" + }; + int fieldLen[] = { 1, 7, 4, 23, 23, 11 }; + int field = 0; + int nextSep = 0; + + log_info("got ASIC ID - "); + + for (i = 0; i < transLen; i++) { + if (i == nextSep) { + fprintf(stdout, "%s%s ", + (field > 0) ? ", " : "", fields[field]); + nextSep += fieldLen[field]; + field++; + + fprintf(stdout, "["); + } + + fprintf(stdout, "%02x", buffer[i]); + + if (i + 1 == nextSep) + fprintf(stdout, "]"); + } + + fprintf(stdout, "\n"); + } + + /* send the peripheral boot command */ + cmd = cpu_to_le32(OMAP_PERIPH_BOOT); + + if (!omap_usb_write(handle, (unsigned char *) &cmd, sizeof (cmd))) { + log_error("failed to send the peripheral boot command 0x%08x\n", + OMAP_PERIPH_BOOT); + goto fail; + } + + /* send the length of the first file (little endian) */ + if (!omap_usb_write + (handle, (unsigned char *) &filelen, sizeof (filelen))) { + log_error("failed to length specifier of %u to OMAP BootROM\n", + filelen); + goto fail; + } + + /* send the file! */ + if (!omap_usb_write(handle, data, filelen)) { + log_error("failed to send file \'%s\' (size %u)\n", + file->basename, filelen); + goto fail; + } + + free(buffer); + return 1; + + fail: + free(buffer); + return 0; +} + +static int transfer_other_files(libusb_device_handle *handle, struct arg_state *args) +{ + uint32_t *buffer = NULL; + int bufsize = 128 * sizeof (*buffer); + int numfailures = 0; /* build in some reliablity */ + int maxfailures = 3; + int transLen = 0; + int curfile = 1; /* skip the first file */ + size_t len; + + buffer = calloc(bufsize, sizeof(unsigned char)); + + /* handle the state machine for the X-Loader */ + while (curfile < args->numfiles) { + uint32_t opcode = 0; + uint8_t *extra = NULL; + struct file_upload *f = args->files[curfile]; + + /* read the opcode from xloader ID */ + if (!omap_usb_read + (handle, (unsigned char *) buffer, bufsize, &transLen)) { + numfailures++; + + if (numfailures >= maxfailures) { + log_error("failed to read command from X-Loader\n"); + goto fail; + } + + /* sleep a bit */ + usleep(2000 * 1000); /* 2s */ + continue; /* try the opcode read again */ + } + + if (transLen < 8) { + log_error("failed to recieve enough data for the opcode\n"); + goto fail; + } + + /* extract the opcode and extra data pointer */ + opcode = le32_to_cpu(buffer[0]); + extra = (uint8_t *)buffer; + + switch (opcode) { + case USBLOAD_CMD_FILE_REQ: + /* X-loader is requesting a file to be sent */ + /* send the opcode, size, and addr */ + buffer[0] = cpu_to_le32(USBLOAD_CMD_FILE); + buffer[1] = cpu_to_le32(f->size); + buffer[2] = cpu_to_le32(f->addr); + + if (!omap_usb_write(handle, (unsigned char *)buffer, sizeof(*buffer) * 3)) { + log_error("failed to send load file command to the X-loader\n"); + goto fail; + } + + if (g_verbose) { + log_info("uploading \'%s\' (size %zu) to 0x%08x\n", + f->basename, f->size, f->addr); + } + + break; + case USBLOAD_CMD_ECHO_SZ: + /* X-loader confirms the size to recieve */ + if (buffer[1] != f->size) { + log_error + ("X-loader failed to recieve the right file size for " + "file \'%s\' (got %u, expected %zu)\n", + f->basename, buffer[1], f->size); + goto fail; + } + + /* upload the raw file data */ + if (!omap_usb_write(handle, f->data, f->size)) { + log_error + ("failed to send file \'%s\' to the X-loader\n", + f->basename); + goto fail; + } + + break; + case USBLOAD_CMD_REPORT_SZ: + /* X-loader confirms the amount of data it recieved */ + if (buffer[1] != f->size) { + log_error + ("X-loader failed to recieve the right amount of data for " + "file \'%s\' (got %u, expected %zu)\n", + f->basename, buffer[1], f->size); + goto fail; + } + + curfile++; /* move on to the next file */ + break; + case USBLOAD_CMD_MESSAGE: + /* X-loader debug message */ + len = strlen((char *)extra); + + if (len > (bufsize - sizeof (opcode) - 1)) + log_error("X-loader debug message not NUL terminated (size %zu)\n", + len); + else + fprintf(stdout, "X-loader Debug: %s\n", extra); + break; + default: + log_error("unknown X-Loader opcode 0x%08X (%c%c%c%c)\n", + opcode, extra[0], extra[1], extra[2], + extra[3]); + goto fail; + } + } + + /* we're done uploading files to X-loader send the jump command */ + buffer[0] = cpu_to_le32(USBLOAD_CMD_JUMP); + buffer[1] = cpu_to_le32(args->jumptarget); + + if (!omap_usb_write + (handle, (unsigned char *) buffer, sizeof (*buffer) * 2)) { + log_error + ("failed to send the final jump command to the X-loader. " + "Target was 0x%08x\n", args->jumptarget); + goto fail; + } + + if (g_verbose) + log_info("jumping to address 0x%08x\n", args->jumptarget); + + free(buffer); + return 1; + + fail: + free(buffer); + return 0; +} + +static int process_args(struct arg_state *args) +{ + int i; + + /* For each file, load it in to memory + * TODO: defer this until transfer time (save memory and pipeline IO) + */ + + for (i = 0; i < args->numfiles; i++) { + struct file_upload *f = args->files[i]; + + f->data = read_file(f->path, &f->size); + + if (!f->data) { + return 1; + } + } + + if (g_verbose > 0) { + for (i = 0; i < args->numfiles; i++) { + struct file_upload *f = args->files[i]; + + printf("File \'%s\' at 0x%08x, size %zu\n", + f->basename, f->addr, f->size); + } + } + + libusb_context *ctx; + libusb_device_handle *dev; + int ret; + + if ((ret = libusb_init(&ctx)) < 0) { + log_error("failed to initialize libusb context: %s\n", + libusb_error_name(ret)); + return ret; + } + + dev = omap_usb_open(ctx, args->vendor, args->product); + + if (!dev) { + libusb_exit(ctx); + return 1; + } + + /* Communicate with the TI BootROM directly + * - retrieve ASIC ID + * - start peripheral boot + * - upload first file + * - execute first file + */ + if (!transfer_first_stage(dev, args)) { + log_error("failed to transfer the first stage file \'%s\'\n", + args->files[0]->basename); + goto fail; + } + + /* Note: this is a race between the target's processor getting X-loader + * running and our processor. If we fail to communicate with the X-loader, + * it's possible that it hasn't been fully initialized. I'm not going to put + * some stupid, arbitrary sleep value here. The transfer_other_files function + * should be robust enough to handle some errors. + */ + + /* If we are passed one file, assume that the user just wants to + * upload some initial code with no X-loader chaining + */ + if (args->numfiles > 1) { + if (!transfer_other_files(dev, args)) { + log_error + ("failed to transfer the additional files in to memory\n"); + goto fail; + } + } + + log_info("successfully transfered %d %s\n", args->numfiles, + (args->numfiles > 1) ? "files" : "file"); + + /* safely close our USB handle and context */ + libusb_close(dev); + libusb_exit(ctx); + return 0; + +fail: + libusb_close(dev); + libusb_exit(ctx); + + return 1; +} + +/* getopt configuration */ +static int do_version = 0; +static const char *const short_opt = "f:a:j:i:p:vh"; +static const struct option long_opt[] = { + {"file", 1, NULL, 'f'}, + {"addr", 1, NULL, 'a'}, + {"jump", 1, NULL, 'j'}, + {"vendor", 1, NULL, 'i'}, + {"product", 1, NULL, 'p'}, + {"verbose", 0, NULL, 'v'}, + {"help", 0, NULL, 'h'}, + {"version", 0, &do_version, 1}, + {NULL, 0, NULL, 0} +}; + +static void usage(char *exe) +{ + printf( +"Usage: %s [options] -f first-stage [-f file -a addr]...\n" +"Options:\n" +" -f, --file Provide the filename of a binary file to be\n" +" uploaded. The first file specified is uploaded to\n" +" the fixed address 0x%08x as defined by the manual.\n" +" Additional files must be followed by an address\n" +" argument (-a).\n" +" -a, --addr The address to load the prior file at.\n" +" -j, --jump Specify the address to jump to after loading all\n" +" of the files in to memory.\n" +" -i, --vendor Override the default vendor ID to poll for\n" +" (default 0x%04x).\n" +" -p, --product Poll for specific product id. Default: All known OMAP chips\n" +" -h, --help Display this message.\n" +" -v, --verbose Enable verbose output.\n" +"\n" +"Description:\n" +" %s's basic usage is to upload an arbitrary file in to the memory\n" +" of a TI OMAP3 compatible processor. This program directly\n" +" communicates with the TI BootROM in order to upload a first stage\n" +" payload, in most cases, TI's X-Loader. Using a compatible X-Loader\n" +" will enable the upload of any file to any part in device memory.\n" +"\n" +"Examples:\n" +" Uploading a compatible X-Loader, U-Boot, Kernel, and RAMDisk, then jumping\n" +" to the U-Boot image for further bootloading:\n" +" %s -f x-load.bin -f u-boot.bin -a 0x80200000 -f uImage -a 0x80800000 \\\n" +" -f uRamdisk -a 0x81000000 -j 0x80200000\n" +" Uploading arbitrary code to be executed (doesn't have to be X-loader):\n" +" %s -f exec_me.bin\n" +" Trying to debug an upload issue using verbose output:\n" +" %s -v -f exec_me.bin -f file1.bin -a 0xdeadbeef -j 0xabad1dea\n" +"\n" +"Authors:\n" +" Grant Hernandez - rewrite of omap3_usbload to\n" +" use the newer libusb 1.0\n" +" Martin Mueller - initial code (omap3_usbload)\n" +" and X-Loader patch\n", + exe, OMAP_BASE_ADDRESS, OMAP_VENDOR_ID, PROG_NAME, exe, exe, exe + ); +} + +static void license(void) +{ + printf( +"Copyright (C) 2008 Martin Mueller \n" +"Copyright (C) 2014 Grant Hernandez \n" +"License GPLv2: GNU GPL version 2 or later .\n" +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n" + ); +} + +int main(int argc, char *argv[]) +{ + int opt; + bool gotfile = false; + bool gotjump = false; + int filecount = 0; + char *exe = NULL; + + /* temporary local file object */ + struct file_upload file; + /* total arg state */ + struct arg_state *args = calloc(1, sizeof (*args)); + + if (argc < 1) { + log_error("invalid arguments (no argv[0])\n"); + return 1; + } + + exe = argv[0]; + + fprintf(stdout, "%s %s\n", PROG_NAME, VERSION); + + /* set the default vendor and product */ + args->vendor = OMAP_VENDOR_ID; + args->product = 0; + + while ((opt = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) { + switch (opt) { + case 0: + if (do_version) { + license(); + return 0; + } + break; + case 'f': + if (gotfile) { + log_error("missing address argument (-a) for file \'%s\'\n", + file.path); + usage(exe); + return 1; + } + + file.path = strdup(optarg); + + /* necessary to be sure that we own all the memory + and that the path input can be modified */ + char *tmpPath = strdup(file.path); + file.basename = strdup(basename(tmpPath)); + free(tmpPath); + + filecount++; + + /* the first file gets uploaded to a fixed address + as specified by the technical reference manual */ + if (filecount == 1) { + file.addr = OMAP_BASE_ADDRESS; + + /* commit the file object with the processor specified base address */ + args->files = realloc(args->files, filecount); + args->numfiles = filecount; + args->files[filecount - 1] = malloc(sizeof (file)); + memcpy(args->files[filecount - 1], &file, sizeof (file)); + } else { + /* commit only after an address is specified */ + gotfile = true; + } + break; + case 'a': + if (!gotfile) { + log_error + ("missing file argument (-f) before address \'%s\'\n", + optarg); + usage(exe); + return 1; + } + + /* passing 0 to strtoul enables detection of the 0x prefix with + base-10 fallback if missing */ + file.addr = strtoul(optarg, NULL, 0); + + /* commit the file object */ + args->files = realloc(args->files, filecount); + args->numfiles = filecount; + args->files[filecount - 1] = malloc(sizeof(file)); + memcpy(args->files[filecount - 1], &file, sizeof(file)); + + gotfile = false; + break; + case 'j': + args->jumptarget = strtoul(optarg, NULL, 0); + gotjump = true; + break; + case 'i': + args->vendor = (uint16_t)strtoul(optarg, NULL, 0); + break; + case 'p': + args->product = (uint16_t)strtoul(optarg, NULL, 0); + break; + case 'v': + g_verbose++; + break; + case 'h': + usage(exe); + return 0; + default: + usage(exe); + return 1; + } + } + + if (gotfile) { + log_error("got file \'%s\', but no address!\n", file.path); + usage(exe); + return 1; + } + + if (args->numfiles <= 0) { + log_error("at least one file needs to be specified\n"); + usage(exe); + return 1; + } + + if (args->numfiles == 1 && gotjump) { + log_info + ("WARNING: jump target 0x%08x specified, but will never be taken " + "(more than one file required)\n", args->jumptarget); + } else if (args->numfiles > 1 && !gotjump) { + log_info + ("WARNING: no jump target specified. Defaulting to the first " + "file's (\'%s\') address 0x%08x\n", + args->files[1]->basename, args->files[1]->addr); + args->jumptarget = args->files[1]->addr; + } + + return process_args(args); +}