summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--README45
-rw-r--r--arch/arm/cpu/armv7/zynq/cpu.c13
-rw-r--r--arch/arm/cpu/armv7/zynq/ddrc.c5
-rw-r--r--arch/arm/cpu/armv7/zynq/slcr.c87
-rw-r--r--arch/arm/cpu/armv7/zynq/spl.c15
-rw-r--r--arch/arm/dts/zynq-7000.dtsi194
-rw-r--r--arch/arm/dts/zynq-microzed.dts9
-rw-r--r--arch/arm/dts/zynq-zc702.dts9
-rw-r--r--arch/arm/dts/zynq-zc706.dts9
-rw-r--r--arch/arm/dts/zynq-zc770-xm010.dts9
-rw-r--r--arch/arm/dts/zynq-zc770-xm012.dts9
-rw-r--r--arch/arm/dts/zynq-zc770-xm013.dts9
-rw-r--r--arch/arm/dts/zynq-zed.dts9
-rw-r--r--arch/arm/include/asm/arch-tegra/usb.h2
-rw-r--r--arch/arm/include/asm/arch-zynq/hardware.h13
-rw-r--r--arch/arm/include/asm/arch-zynq/sys_proto.h2
-rw-r--r--board/BuR/common/common.c7
-rw-r--r--board/matrix_vision/common/mv_common.c2
-rw-r--r--board/samsung/common/Makefile1
-rw-r--r--board/samsung/common/ums.c74
-rw-r--r--board/xilinx/zynq/.gitignore1
-rw-r--r--board/xilinx/zynq/Makefile5
-rw-r--r--board/xilinx/zynq/board.c25
-rw-r--r--board/xilinx/zynq/ps7_init.c12
-rw-r--r--board/xilinx/zynq/xil_io.h13
-rw-r--r--common/Makefile3
-rw-r--r--common/cmd_bootm.c23
-rw-r--r--common/cmd_fastboot.c36
-rw-r--r--common/cmd_fpga.c91
-rw-r--r--common/cmd_fuse.c11
-rw-r--r--common/cmd_mmc.c799
-rw-r--r--common/cmd_nand.c16
-rw-r--r--common/cmd_otp.c18
-rw-r--r--common/cmd_part.c2
-rw-r--r--common/cmd_usb_mass_storage.c91
-rw-r--r--common/console.c28
-rw-r--r--common/image-android.c84
-rw-r--r--common/image.c20
-rw-r--r--disk/part.c80
-rw-r--r--doc/README.android-fastboot91
-rw-r--r--doc/README.android-fastboot-protocol170
-rw-r--r--drivers/dfu/dfu.c4
-rw-r--r--drivers/dfu/dfu_mmc.c46
-rw-r--r--drivers/dfu/dfu_nand.c13
-rw-r--r--drivers/fpga/fpga.c36
-rw-r--r--drivers/fpga/spartan2.c3
-rw-r--r--drivers/fpga/spartan3.c3
-rw-r--r--drivers/fpga/virtex2.c3
-rw-r--r--drivers/fpga/xilinx.c26
-rw-r--r--drivers/fpga/zynqpl.c105
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/fsl_esdhc.c26
-rw-r--r--drivers/mmc/mmc.c35
-rw-r--r--drivers/mmc/rpmb.c323
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/ci_udc.c182
-rw-r--r--drivers/usb/gadget/ci_udc.h17
-rw-r--r--drivers/usb/gadget/f_dfu.c10
-rw-r--r--drivers/usb/gadget/f_fastboot.c513
-rw-r--r--drivers/usb/gadget/f_thor.c12
-rw-r--r--drivers/usb/gadget/storage_common.c4
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-tegra.c165
-rw-r--r--drivers/usb/host/ehci-zynq.c104
-rw-r--r--drivers/usb/musb-new/musb_gadget_ep0.c8
-rw-r--r--include/android_image.h69
-rw-r--r--include/common.h2
-rw-r--r--include/configs/GEN860T.h1
-rw-r--r--include/configs/MVBC_P.h1
-rw-r--r--include/configs/MVBLM7.h1
-rw-r--r--include/configs/MVSMR.h1
-rw-r--r--include/configs/alpr.h1
-rw-r--r--include/configs/astro_mcf5373l.h1
-rw-r--r--include/configs/balloon3.h1
-rw-r--r--include/configs/coreboot.h1
-rw-r--r--include/configs/grsim.h1
-rw-r--r--include/configs/grsim_leon2.h1
-rw-r--r--include/configs/iocon.h3
-rw-r--r--include/configs/kwb.h2
-rw-r--r--include/configs/mt_ventoux.h1
-rw-r--r--include/configs/omap3_beagle.h10
-rw-r--r--include/configs/omap3_mvblx.h1
-rw-r--r--include/configs/tseries.h2
-rw-r--r--include/configs/x600.h1
-rw-r--r--include/configs/zynq-common.h56
-rw-r--r--include/configs/zynq_zc70x.h1
-rw-r--r--include/configs/zynq_zed.h1
-rw-r--r--include/dfu.h4
-rw-r--r--include/fpga.h20
-rw-r--r--include/image.h13
-rw-r--r--include/mmc.h12
-rw-r--r--include/part.h2
-rw-r--r--include/usb_mass_storage.h13
-rw-r--r--include/xilinx.h8
-rw-r--r--lib/Makefile1
96 files changed, 3334 insertions, 689 deletions
diff --git a/Makefile b/Makefile
index 176ce10..1f56e85 100644
--- a/Makefile
+++ b/Makefile
@@ -752,6 +752,9 @@ ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin
ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.img
ALL-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb u-boot-dtb.bin
+ifeq ($(CONFIG_SPL_FRAMEWORK),y)
+ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img
+endif
ALL-$(CONFIG_OF_HOSTFILE) += u-boot.dtb
ifneq ($(CONFIG_SPL_TARGET),)
ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%)
@@ -854,6 +857,11 @@ MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \
u-boot.img u-boot.kwb u-boot.pbl: u-boot.bin FORCE
$(call if_changed,mkimage)
+MKIMAGEFLAGS_u-boot-dtb.img = $(MKIMAGEFLAGS_u-boot.img)
+
+u-boot-dtb.img: u-boot-dtb.bin FORCE
+ $(call if_changed,mkimage)
+
u-boot.sha1: u-boot.bin
tools/ubsha1 u-boot.bin
diff --git a/README b/README
index 5f89552..a280435 100644
--- a/README
+++ b/README
@@ -1534,6 +1534,16 @@ The following options need to be configured:
CONFIG_SH_MMCIF_CLK
Define the clock frequency for MMCIF
+ CONFIG_GENERIC_MMC
+ Enable the generic MMC driver
+
+ CONFIG_SUPPORT_EMMC_BOOT
+ Enable some additional features of the eMMC boot partitions.
+
+ CONFIG_SUPPORT_EMMC_RPMB
+ Enable the commands for reading, writing and programming the
+ key for the Replay Protection Memory Block partition in eMMC.
+
- USB Device Firmware Update (DFU) class support:
CONFIG_DFU_FUNCTION
This enables the USB portion of the DFU USB class
@@ -1579,6 +1589,28 @@ The following options need to be configured:
entering dfuMANIFEST state. Host waits this timeout, before
sending again an USB request to the device.
+- USB Device Android Fastboot support:
+ CONFIG_CMD_FASTBOOT
+ This enables the command "fastboot" which enables the Android
+ fastboot mode for the platform's USB device. Fastboot is a USB
+ protocol for downloading images, flashing and device control
+ used on Android devices.
+ See doc/README.android-fastboot for more information.
+
+ CONFIG_ANDROID_BOOT_IMAGE
+ This enables support for booting images which use the Android
+ image format header.
+
+ CONFIG_USB_FASTBOOT_BUF_ADDR
+ The fastboot protocol requires a large memory buffer for
+ downloads. Define this to the starting RAM address to use for
+ downloaded images.
+
+ CONFIG_USB_FASTBOOT_BUF_SIZE
+ The fastboot protocol requires a large memory buffer for
+ downloads. This buffer should be as large as possible for a
+ platform. Define this to the size available RAM for fastboot.
+
- Journaling Flash filesystem support:
CONFIG_JFFS2_NAND, CONFIG_JFFS2_NAND_OFF, CONFIG_JFFS2_NAND_SIZE,
CONFIG_JFFS2_NAND_DEV
@@ -2550,6 +2582,19 @@ CBFS (Coreboot Filesystem) support
Specify the number of FPGA devices to support.
+ CONFIG_CMD_FPGA_LOADMK
+
+ Enable support for fpga loadmk command
+
+ CONFIG_CMD_FPGA_LOADP
+
+ Enable support for fpga loadp command - load partial bitstream
+
+ CONFIG_CMD_FPGA_LOADBP
+
+ Enable support for fpga loadbp command - load partial bitstream
+ (Xilinx only)
+
CONFIG_SYS_FPGA_PROG_FEEDBACK
Enable printing of hash marks during FPGA configuration.
diff --git a/arch/arm/cpu/armv7/zynq/cpu.c b/arch/arm/cpu/armv7/zynq/cpu.c
index 7626b5c..816d0c5 100644
--- a/arch/arm/cpu/armv7/zynq/cpu.c
+++ b/arch/arm/cpu/armv7/zynq/cpu.c
@@ -14,6 +14,9 @@ void lowlevel_init(void)
{
}
+#define ZYNQ_SILICON_VER_MASK 0xF0000000
+#define ZYNQ_SILICON_VER_SHIFT 28
+
int arch_cpu_init(void)
{
zynq_slcr_unlock();
@@ -42,6 +45,16 @@ int arch_cpu_init(void)
return 0;
}
+unsigned int zynq_get_silicon_version(void)
+{
+ unsigned int ver;
+
+ ver = (readl(&devcfg_base->mctrl) &
+ ZYNQ_SILICON_VER_MASK) >> ZYNQ_SILICON_VER_SHIFT;
+
+ return ver;
+}
+
void reset_cpu(ulong addr)
{
zynq_slcr_cpu_reset();
diff --git a/arch/arm/cpu/armv7/zynq/ddrc.c b/arch/arm/cpu/armv7/zynq/ddrc.c
index ba6a6ae..e0ed3bf 100644
--- a/arch/arm/cpu/armv7/zynq/ddrc.c
+++ b/arch/arm/cpu/armv7/zynq/ddrc.c
@@ -40,11 +40,8 @@ void zynq_ddrc_init(void)
* first stage bootloader. To get ECC to work all memory has
* been initialized by writing any value.
*/
- memset(0, 0, 1 * 1024 * 1024);
+ memset((void *)0, 0, 1 * 1024 * 1024);
} else {
puts("Memory: ECC disabled\n");
}
-
- if (width == ZYNQ_DDRC_CTRLREG_BUSWIDTH_16BIT)
- gd->ram_size /= 2;
}
diff --git a/arch/arm/cpu/armv7/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c
index d7c1882..934ccc3 100644
--- a/arch/arm/cpu/armv7/zynq/slcr.c
+++ b/arch/arm/cpu/armv7/zynq/slcr.c
@@ -8,26 +8,75 @@
#include <asm/io.h>
#include <malloc.h>
#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
#include <asm/arch/clk.h>
#define SLCR_LOCK_MAGIC 0x767B
#define SLCR_UNLOCK_MAGIC 0xDF0D
+#define SLCR_USB_L1_SEL 0x04
+
#define SLCR_IDCODE_MASK 0x1F000
#define SLCR_IDCODE_SHIFT 12
+/*
+ * zynq_slcr_mio_get_status - Get the status of MIO peripheral.
+ *
+ * @peri_name: Name of the peripheral for checking MIO status
+ * @get_pins: Pointer to array of get pin for this peripheral
+ * @num_pins: Number of pins for this peripheral
+ * @mask: Mask value
+ * @check_val: Required check value to get the status of periph
+ */
+struct zynq_slcr_mio_get_status {
+ const char *peri_name;
+ const int *get_pins;
+ int num_pins;
+ u32 mask;
+ u32 check_val;
+};
+
+static const int usb0_pins[] = {
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
+};
+
+static const int usb1_pins[] = {
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+};
+
+static const struct zynq_slcr_mio_get_status mio_periphs[] = {
+ {
+ "usb0",
+ usb0_pins,
+ ARRAY_SIZE(usb0_pins),
+ SLCR_USB_L1_SEL,
+ SLCR_USB_L1_SEL,
+ },
+ {
+ "usb1",
+ usb1_pins,
+ ARRAY_SIZE(usb1_pins),
+ SLCR_USB_L1_SEL,
+ SLCR_USB_L1_SEL,
+ },
+};
+
static int slcr_lock = 1; /* 1 means locked, 0 means unlocked */
void zynq_slcr_lock(void)
{
- if (!slcr_lock)
+ if (!slcr_lock) {
writel(SLCR_LOCK_MAGIC, &slcr_base->slcr_lock);
+ slcr_lock = 1;
+ }
}
void zynq_slcr_unlock(void)
{
- if (slcr_lock)
+ if (slcr_lock) {
writel(SLCR_UNLOCK_MAGIC, &slcr_base->slcr_unlock);
+ slcr_lock = 0;
+ }
}
/* Reset the entire system */
@@ -82,7 +131,7 @@ void zynq_slcr_devcfg_disable(void)
{
zynq_slcr_unlock();
- /* Disable AXI interface */
+ /* Disable AXI interface by asserting FPGA resets */
writel(0xFFFFFFFF, &slcr_base->fpga_rst_ctrl);
/* Set Level Shifters DT618760 */
@@ -98,7 +147,7 @@ void zynq_slcr_devcfg_enable(void)
/* Set Level Shifters DT618760 */
writel(0xF, &slcr_base->lvl_shftr_en);
- /* Disable AXI interface */
+ /* Enable AXI interface by de-asserting FPGA resets */
writel(0x0, &slcr_base->fpga_rst_ctrl);
zynq_slcr_lock();
@@ -115,3 +164,33 @@ u32 zynq_slcr_get_idcode(void)
return (readl(&slcr_base->pss_idcode) & SLCR_IDCODE_MASK) >>
SLCR_IDCODE_SHIFT;
}
+
+/*
+ * zynq_slcr_get_mio_pin_status - Get the MIO pin status of peripheral.
+ *
+ * @periph: Name of the peripheral
+ *
+ * Returns count to indicate the number of pins configured for the
+ * given @periph.
+ */
+int zynq_slcr_get_mio_pin_status(const char *periph)
+{
+ const struct zynq_slcr_mio_get_status *mio_ptr;
+ int val, i, j;
+ int mio = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mio_periphs); i++) {
+ if (strcmp(periph, mio_periphs[i].peri_name) == 0) {
+ mio_ptr = &mio_periphs[i];
+ for (j = 0; j < mio_ptr->num_pins; j++) {
+ val = readl(&slcr_base->mio_pin
+ [mio_ptr->get_pins[j]]);
+ if ((val & mio_ptr->mask) == mio_ptr->check_val)
+ mio++;
+ }
+ break;
+ }
+ }
+
+ return mio;
+}
diff --git a/arch/arm/cpu/armv7/zynq/spl.c b/arch/arm/cpu/armv7/zynq/spl.c
index fcad762..d73e5cb 100644
--- a/arch/arm/cpu/armv7/zynq/spl.c
+++ b/arch/arm/cpu/armv7/zynq/spl.c
@@ -28,6 +28,13 @@ void board_init_f(ulong dummy)
board_init_r(NULL, 0);
}
+#ifdef CONFIG_SPL_BOARD_INIT
+void spl_board_init(void)
+{
+ board_init();
+}
+#endif
+
u32 spl_boot_device(void)
{
u32 mode;
@@ -67,3 +74,11 @@ int spl_start_uboot(void)
return 0;
}
#endif
+
+__weak void ps7_init(void)
+{
+ /*
+ * This function is overridden by the one in
+ * board/xilinx/zynq/ps7_init.c, if it exists.
+ */
+}
diff --git a/arch/arm/dts/zynq-7000.dtsi b/arch/arm/dts/zynq-7000.dtsi
index f20b8bd..2d076f1 100644
--- a/arch/arm/dts/zynq-7000.dtsi
+++ b/arch/arm/dts/zynq-7000.dtsi
@@ -10,4 +10,198 @@
/ {
compatible = "xlnx,zynq-7000";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <0>;
+ clocks = <&clkc 3>;
+ clock-latency = <1000>;
+ operating-points = <
+ /* kHz uV */
+ 666667 1000000
+ 333334 1000000
+ 222223 1000000
+ >;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <1>;
+ clocks = <&clkc 3>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,cortex-a9-pmu";
+ interrupts = <0 5 4>, <0 6 4>;
+ interrupt-parent = <&intc>;
+ reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >;
+ };
+
+ amba {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+ ranges;
+
+ i2c0: zynq-i2c@e0004000 {
+ compatible = "cdns,i2c-r1p10";
+ status = "disabled";
+ clocks = <&clkc 38>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 25 4>;
+ reg = <0xe0004000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: zynq-i2c@e0005000 {
+ compatible = "cdns,i2c-r1p10";
+ status = "disabled";
+ clocks = <&clkc 39>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 48 4>;
+ reg = <0xe0005000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ intc: interrupt-controller@f8f01000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0xF8F01000 0x1000>,
+ <0xF8F00100 0x100>;
+ };
+
+ L2: cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0xF8F02000 0x1000>;
+ arm,data-latency = <3 2 2>;
+ arm,tag-latency = <2 2 2>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ uart0: uart@e0000000 {
+ compatible = "xlnx,xuartps";
+ status = "disabled";
+ clocks = <&clkc 23>, <&clkc 40>;
+ clock-names = "ref_clk", "aper_clk";
+ reg = <0xE0000000 0x1000>;
+ interrupts = <0 27 4>;
+ };
+
+ uart1: uart@e0001000 {
+ compatible = "xlnx,xuartps";
+ status = "disabled";
+ clocks = <&clkc 24>, <&clkc 41>;
+ clock-names = "ref_clk", "aper_clk";
+ reg = <0xE0001000 0x1000>;
+ interrupts = <0 50 4>;
+ };
+
+ gem0: ethernet@e000b000 {
+ compatible = "cdns,gem";
+ reg = <0xe000b000 0x4000>;
+ status = "disabled";
+ interrupts = <0 22 4>;
+ clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;
+ clock-names = "pclk", "hclk", "tx_clk";
+ };
+
+ gem1: ethernet@e000c000 {
+ compatible = "cdns,gem";
+ reg = <0xe000c000 0x4000>;
+ status = "disabled";
+ interrupts = <0 45 4>;
+ clocks = <&clkc 31>, <&clkc 31>, <&clkc 14>;
+ clock-names = "pclk", "hclk", "tx_clk";
+ };
+
+ sdhci0: ps7-sdhci@e0100000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "disabled";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <&clkc 21>, <&clkc 32>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 24 4>;
+ reg = <0xe0100000 0x1000>;
+ } ;
+
+ sdhci1: ps7-sdhci@e0101000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "disabled";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <&clkc 22>, <&clkc 33>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 47 4>;
+ reg = <0xe0101000 0x1000>;
+ } ;
+
+ slcr: slcr@f8000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "xlnx,zynq-slcr", "syscon";
+ reg = <0xF8000000 0x1000>;
+ ranges;
+ clkc: clkc@100 {
+ #clock-cells = <1>;
+ compatible = "xlnx,ps7-clkc";
+ ps-clk-frequency = <33333333>;
+ fclk-enable = <0>;
+ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
+ "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
+ "dci", "lqspi", "smc", "pcap", "gem0", "gem1",
+ "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
+ "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
+ "dma", "usb0_aper", "usb1_aper", "gem0_aper",
+ "gem1_aper", "sdio0_aper", "sdio1_aper",
+ "spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
+ "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
+ "gpio_aper", "lqspi_aper", "smc_aper", "swdt",
+ "dbg_trc", "dbg_apb";
+ reg = <0x100 0x100>;
+ };
+ };
+
+ global_timer: timer@f8f00200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0xf8f00200 0x20>;
+ interrupts = <1 11 0x301>;
+ interrupt-parent = <&intc>;
+ clocks = <&clkc 4>;
+ };
+
+ ttc0: ttc0@f8001000 {
+ interrupt-parent = <&intc>;
+ interrupts = < 0 10 4 0 11 4 0 12 4 >;
+ compatible = "cdns,ttc";
+ clocks = <&clkc 6>;
+ reg = <0xF8001000 0x1000>;
+ };
+
+ ttc1: ttc1@f8002000 {
+ interrupt-parent = <&intc>;
+ interrupts = < 0 37 4 0 38 4 0 39 4 >;
+ compatible = "cdns,ttc";
+ clocks = <&clkc 6>;
+ reg = <0xF8002000 0x1000>;
+ };
+ scutimer: scutimer@f8f00600 {
+ interrupt-parent = <&intc>;
+ interrupts = < 1 13 0x301 >;
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = < 0xf8f00600 0x20 >;
+ clocks = <&clkc 4>;
+ } ;
+ };
};
diff --git a/arch/arm/dts/zynq-microzed.dts b/arch/arm/dts/zynq-microzed.dts
index 6da71c1..c373a2c 100644
--- a/arch/arm/dts/zynq-microzed.dts
+++ b/arch/arm/dts/zynq-microzed.dts
@@ -11,4 +11,13 @@
/ {
model = "Zynq MicroZED Board";
compatible = "xlnx,zynq-microzed", "xlnx,zynq-7000";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x40000000>;
+ };
};
diff --git a/arch/arm/dts/zynq-zc702.dts b/arch/arm/dts/zynq-zc702.dts
index 667dc28..4fa0b00 100644
--- a/arch/arm/dts/zynq-zc702.dts
+++ b/arch/arm/dts/zynq-zc702.dts
@@ -11,4 +11,13 @@
/ {
model = "Zynq ZC702 Board";
compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x40000000>;
+ };
};
diff --git a/arch/arm/dts/zynq-zc706.dts b/arch/arm/dts/zynq-zc706.dts
index 526fc88..2a80195 100644
--- a/arch/arm/dts/zynq-zc706.dts
+++ b/arch/arm/dts/zynq-zc706.dts
@@ -11,4 +11,13 @@
/ {
model = "Zynq ZC706 Board";
compatible = "xlnx,zynq-zc706", "xlnx,zynq-7000";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x40000000>;
+ };
};
diff --git a/arch/arm/dts/zynq-zc770-xm010.dts b/arch/arm/dts/zynq-zc770-xm010.dts
index 8b542a1..5e661749 100644
--- a/arch/arm/dts/zynq-zc770-xm010.dts
+++ b/arch/arm/dts/zynq-zc770-xm010.dts
@@ -11,4 +11,13 @@
/ {
model = "Zynq ZC770 XM010 Board";
compatible = "xlnx,zynq-zc770-xm010", "xlnx,zynq-7000";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x40000000>;
+ };
};
diff --git a/arch/arm/dts/zynq-zc770-xm012.dts b/arch/arm/dts/zynq-zc770-xm012.dts
index 0379a07..127a661 100644
--- a/arch/arm/dts/zynq-zc770-xm012.dts
+++ b/arch/arm/dts/zynq-zc770-xm012.dts
@@ -11,4 +11,13 @@
/ {
model = "Zynq ZC770 XM012 Board";
compatible = "xlnx,zynq-zc770-xm012", "xlnx,zynq-7000";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x40000000>;
+ };
};
diff --git a/arch/arm/dts/zynq-zc770-xm013.dts b/arch/arm/dts/zynq-zc770-xm013.dts
index a4f9e05..c61c7e7 100644
--- a/arch/arm/dts/zynq-zc770-xm013.dts
+++ b/arch/arm/dts/zynq-zc770-xm013.dts
@@ -11,4 +11,13 @@
/ {
model = "Zynq ZC770 XM013 Board";
compatible = "xlnx,zynq-zc770-xm013", "xlnx,zynq-7000";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x40000000>;
+ };
};
diff --git a/arch/arm/dts/zynq-zed.dts b/arch/arm/dts/zynq-zed.dts
index 91a5deb..70cc8a6 100644
--- a/arch/arm/dts/zynq-zed.dts
+++ b/arch/arm/dts/zynq-zed.dts
@@ -11,4 +11,13 @@
/ {
model = "Zynq ZED Board";
compatible = "xlnx,zynq-zed", "xlnx,zynq-7000";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x20000000>;
+ };
};
diff --git a/arch/arm/include/asm/arch-tegra/usb.h b/arch/arm/include/asm/arch-tegra/usb.h
index ceb7bcd..c817088 100644
--- a/arch/arm/include/asm/arch-tegra/usb.h
+++ b/arch/arm/include/asm/arch-tegra/usb.h
@@ -349,6 +349,8 @@ struct usb_ctlr {
/* USB3_IF_USB_PHY_VBUS_SENSORS_0 */
#define VBUS_VLD_STS (1 << 26)
+#define VBUS_B_SESS_VLD_SW_VALUE (1 << 12)
+#define VBUS_B_SESS_VLD_SW_EN (1 << 11)
/* Setup USB on the board */
int usb_process_devicetree(const void *blob);
diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h
index 39184da..2aede0c 100644
--- a/arch/arm/include/asm/arch-zynq/hardware.h
+++ b/arch/arm/include/asm/arch-zynq/hardware.h
@@ -22,9 +22,12 @@
#define ZYNQ_SPI_BASEADDR0 0xE0006000
#define ZYNQ_SPI_BASEADDR1 0xE0007000
#define ZYNQ_DDRC_BASEADDR 0xF8006000
+#define ZYNQ_EFUSE_BASEADDR 0xF800D000
+#define ZYNQ_USB_BASEADDR0 0xE0002000
+#define ZYNQ_USB_BASEADDR1 0xE0003000
/* Bootmode setting values */
-#define ZYNQ_BM_MASK 0xF
+#define ZYNQ_BM_MASK 0x7
#define ZYNQ_BM_NOR 0x2
#define ZYNQ_BM_SD 0x5
#define ZYNQ_BM_JTAG 0x0
@@ -130,4 +133,12 @@ struct ddrc_regs {
};
#define ddrc_base ((struct ddrc_regs *)ZYNQ_DDRC_BASEADDR)
+struct efuse_reg {
+ u32 reserved1[4];
+ u32 status;
+ u32 reserved2[3];
+};
+
+#define efuse_base ((struct efuse_reg *)ZYNQ_EFUSE_BASEADDR)
+
#endif /* _ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/include/asm/arch-zynq/sys_proto.h b/arch/arm/include/asm/arch-zynq/sys_proto.h
index a68e1b3..53c30ec 100644
--- a/arch/arm/include/asm/arch-zynq/sys_proto.h
+++ b/arch/arm/include/asm/arch-zynq/sys_proto.h
@@ -15,7 +15,9 @@ extern void zynq_slcr_devcfg_disable(void);
extern void zynq_slcr_devcfg_enable(void);
extern u32 zynq_slcr_get_boot_mode(void);
extern u32 zynq_slcr_get_idcode(void);
+extern int zynq_slcr_get_mio_pin_status(const char *periph);
extern void zynq_ddrc_init(void);
+extern unsigned int zynq_get_silicon_version(void);
/* Driver extern functions */
extern int zynq_sdhci_init(u32 regbase);
diff --git a/board/BuR/common/common.c b/board/BuR/common/common.c
index 4c926ce..25cbe62 100644
--- a/board/BuR/common/common.c
+++ b/board/BuR/common/common.c
@@ -19,6 +19,7 @@
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/arch/sys_proto.h>
+#include <asm/arch/mmc_host_def.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <i2c.h>
@@ -214,3 +215,9 @@ int board_eth_init(bd_t *bis)
return rv;
}
#endif /* CONFIG_DRIVER_TI_CPSW */
+#if defined(CONFIG_GENERIC_MMC) && !defined(CONFIG_SPL_BUILD)
+int board_mmc_init(bd_t *bis)
+{
+ return omap_mmc_init(1, 0, 0, -1, -1);
+}
+#endif
diff --git a/board/matrix_vision/common/mv_common.c b/board/matrix_vision/common/mv_common.c
index 70133b5..1be5aba 100644
--- a/board/matrix_vision/common/mv_common.c
+++ b/board/matrix_vision/common/mv_common.c
@@ -77,7 +77,7 @@ int mv_load_fpga(void)
return -1;
}
- result = fpga_load(0, fpga_data, data_size);
+ result = fpga_load(0, fpga_data, data_size, BIT_FULL);
if (!result)
bootstage_mark(BOOTSTAGE_ID_START);
diff --git a/board/samsung/common/Makefile b/board/samsung/common/Makefile
index 7d2bb8c..41d0cc3 100644
--- a/board/samsung/common/Makefile
+++ b/board/samsung/common/Makefile
@@ -7,7 +7,6 @@
obj-$(CONFIG_SOFT_I2C_MULTI_BUS) += multi_i2c.o
obj-$(CONFIG_THOR_FUNCTION) += thor.o
-obj-$(CONFIG_CMD_USB_MASS_STORAGE) += ums.o
obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD
diff --git a/board/samsung/common/ums.c b/board/samsung/common/ums.c
deleted file mode 100644
index cebabe9..0000000
--- a/board/samsung/common/ums.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 Samsung Electronics
- * Lukasz Majewski <l.majewski@samsung.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <usb_mass_storage.h>
-#include <part.h>
-
-static int ums_read_sector(struct ums *ums_dev,
- ulong start, lbaint_t blkcnt, void *buf)
-{
- block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
- lbaint_t blkstart = start + ums_dev->start_sector;
- int dev_num = block_dev->dev;
-
- return block_dev->block_read(dev_num, blkstart, blkcnt, buf);
-}
-
-static int ums_write_sector(struct ums *ums_dev,
- ulong start, lbaint_t blkcnt, const void *buf)
-{
- block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
- lbaint_t blkstart = start + ums_dev->start_sector;
- int dev_num = block_dev->dev;
-
- return block_dev->block_write(dev_num, blkstart, blkcnt, buf);
-}
-
-static struct ums ums_dev = {
- .read_sector = ums_read_sector,
- .write_sector = ums_write_sector,
- .name = "UMS disk",
-};
-
-static struct ums *ums_disk_init(struct mmc *mmc)
-{
- uint64_t mmc_end_sector = mmc->capacity / SECTOR_SIZE;
- uint64_t ums_end_sector = UMS_NUM_SECTORS + UMS_START_SECTOR;
-
- if (!mmc_end_sector) {
- error("MMC capacity is not valid");
- return NULL;
- }
-
- ums_dev.mmc = mmc;
-
- if (ums_end_sector <= mmc_end_sector) {
- ums_dev.start_sector = UMS_START_SECTOR;
- if (UMS_NUM_SECTORS)
- ums_dev.num_sectors = UMS_NUM_SECTORS;
- else
- ums_dev.num_sectors = mmc_end_sector - UMS_START_SECTOR;
- } else {
- ums_dev.num_sectors = mmc_end_sector;
- puts("UMS: defined bad disk parameters. Using default.\n");
- }
-
- printf("UMS: disk start sector: %#x, count: %#x\n",
- ums_dev.start_sector, ums_dev.num_sectors);
-
- return &ums_dev;
-}
-
-struct ums *ums_init(unsigned int dev_num)
-{
- struct mmc *mmc = find_mmc_device(dev_num);
-
- if (!mmc || mmc_init(mmc))
- return NULL;
- return ums_disk_init(mmc);
-}
diff --git a/board/xilinx/zynq/.gitignore b/board/xilinx/zynq/.gitignore
new file mode 100644
index 0000000..68b8edd
--- /dev/null
+++ b/board/xilinx/zynq/.gitignore
@@ -0,0 +1 @@
+ps7_init.[ch]
diff --git a/board/xilinx/zynq/Makefile b/board/xilinx/zynq/Makefile
index 3f19a1c..fd93f63 100644
--- a/board/xilinx/zynq/Makefile
+++ b/board/xilinx/zynq/Makefile
@@ -6,4 +6,7 @@
#
obj-y := board.o
-obj-$(CONFIG_SPL_BUILD) += ps7_init.o
+
+# Please copy ps7_init.c/h from hw project to this directory
+obj-$(CONFIG_SPL_BUILD) += \
+ $(if $(wildcard $(srctree)/$(src)/ps7_init.c), ps7_init.o)
diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c
index c8cc2bc..258632e 100644
--- a/board/xilinx/zynq/board.c
+++ b/board/xilinx/zynq/board.c
@@ -6,6 +6,8 @@
#include <common.h>
#include <fdtdec.h>
+#include <fpga.h>
+#include <mmc.h>
#include <netdev.h>
#include <zynqpl.h>
#include <asm/arch/hardware.h>
@@ -13,21 +15,23 @@
DECLARE_GLOBAL_DATA_PTR;
-#ifdef CONFIG_FPGA
-xilinx_desc fpga;
+#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \
+ (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD))
+static xilinx_desc fpga;
/* It can be done differently */
-xilinx_desc fpga010 = XILINX_XC7Z010_DESC(0x10);
-xilinx_desc fpga015 = XILINX_XC7Z015_DESC(0x15);
-xilinx_desc fpga020 = XILINX_XC7Z020_DESC(0x20);
-xilinx_desc fpga030 = XILINX_XC7Z030_DESC(0x30);
-xilinx_desc fpga045 = XILINX_XC7Z045_DESC(0x45);
-xilinx_desc fpga100 = XILINX_XC7Z100_DESC(0x100);
+static xilinx_desc fpga010 = XILINX_XC7Z010_DESC(0x10);
+static xilinx_desc fpga015 = XILINX_XC7Z015_DESC(0x15);
+static xilinx_desc fpga020 = XILINX_XC7Z020_DESC(0x20);
+static xilinx_desc fpga030 = XILINX_XC7Z030_DESC(0x30);
+static xilinx_desc fpga045 = XILINX_XC7Z045_DESC(0x45);
+static xilinx_desc fpga100 = XILINX_XC7Z100_DESC(0x100);
#endif
int board_init(void)
{
-#ifdef CONFIG_FPGA
+#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \
+ (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD))
u32 idcode;
idcode = zynq_slcr_get_idcode();
@@ -54,7 +58,8 @@ int board_init(void)
}
#endif
-#ifdef CONFIG_FPGA
+#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \
+ (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD))
fpga_init();
fpga_add(fpga_xilinx, &fpga);
#endif
diff --git a/board/xilinx/zynq/ps7_init.c b/board/xilinx/zynq/ps7_init.c
deleted file mode 100644
index c47da09..0000000
--- a/board/xilinx/zynq/ps7_init.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * (C) Copyright 2014 Xilinx, Inc. Michal Simek
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-#include <common.h>
-#include <asm/arch/spl.h>
-
-__weak void ps7_init(void)
-{
- puts("Please copy ps7_init.c/h from hw project\n");
-}
diff --git a/board/xilinx/zynq/xil_io.h b/board/xilinx/zynq/xil_io.h
new file mode 100644
index 0000000..e59a977
--- /dev/null
+++ b/board/xilinx/zynq/xil_io.h
@@ -0,0 +1,13 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef XIL_IO_H /* prevent circular inclusions */
+#define XIL_IO_H
+
+/*
+ * This empty file is here because ps7_init.c exported by hw project
+ * has #include "xil_io.h" line.
+ */
+
+#endif /* XIL_IO_H */
diff --git a/common/Makefile b/common/Makefile
index 7c853ae..219cb51 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -168,6 +168,8 @@ obj-y += cmd_usb.o
obj-y += usb.o usb_hub.o
obj-$(CONFIG_USB_STORAGE) += usb_storage.o
endif
+obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
+
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
@@ -237,6 +239,7 @@ obj-y += console.o
obj-$(CONFIG_CROS_EC) += cros_ec.o
obj-y += dlmalloc.o
obj-y += image.o
+obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
obj-$(CONFIG_FIT) += image-fit.o
obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index e683af3..34b4b58 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -222,6 +222,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
const void *os_hdr;
+ bool ep_found = false;
/* get kernel image header, start address and length */
os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
@@ -274,6 +275,18 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
}
break;
#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ case IMAGE_FORMAT_ANDROID:
+ images.os.type = IH_TYPE_KERNEL;
+ images.os.comp = IH_COMP_NONE;
+ images.os.os = IH_OS_LINUX;
+ images.ep = images.os.load;
+ ep_found = true;
+
+ images.os.end = android_image_get_end(os_hdr);
+ images.os.load = android_image_get_kload(os_hdr);
+ break;
+#endif
default:
puts("ERROR: unknown image format type!\n");
return 1;
@@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
return 1;
}
#endif
- } else {
+ } else if (!ep_found) {
puts("Could not find kernel entry point!\n");
return 1;
}
@@ -1002,6 +1015,14 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
images->fit_noffset_os = os_noffset;
break;
#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ case IMAGE_FORMAT_ANDROID:
+ printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
+ if (android_image_get_kernel((void *)img_addr, images->verify,
+ os_data, os_len))
+ return NULL;
+ break;
+#endif
default:
printf("Wrong Image Format for %s command\n", cmdtp->name);
bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
new file mode 100644
index 0000000..83fa7bd
--- /dev/null
+++ b/common/cmd_fastboot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 - 2009 Windriver, <www.windriver.com>
+ * Author: Tom Rix <Tom.Rix@windriver.com>
+ *
+ * (C) Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <command.h>
+#include <g_dnl.h>
+
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ int ret;
+
+ ret = g_dnl_register("usb_dnl_fastboot");
+ if (ret)
+ return ret;
+
+ while (1) {
+ if (ctrlc())
+ break;
+ usb_gadget_handle_interrupts();
+ }
+
+ g_dnl_unregister();
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+ fastboot, 1, 1, do_fastboot,
+ "fastboot - enter USB Fastboot protocol",
+ ""
+);
diff --git a/common/cmd_fpga.c b/common/cmd_fpga.c
index 010cd24..bda5c8f 100644
--- a/common/cmd_fpga.c
+++ b/common/cmd_fpga.c
@@ -11,6 +11,7 @@
#include <common.h>
#include <command.h>
#include <fpga.h>
+#include <fs.h>
#include <malloc.h>
/* Local functions */
@@ -23,6 +24,9 @@ static int fpga_get_op(char *opstr);
#define FPGA_LOADB 2
#define FPGA_DUMP 3
#define FPGA_LOADMK 4
+#define FPGA_LOADP 5
+#define FPGA_LOADBP 6
+#define FPGA_LOADFS 7
/* ------------------------------------------------------------------------- */
/* command form:
@@ -45,6 +49,10 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
const char *fit_uname = NULL;
ulong fit_addr;
#endif
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ fpga_fs_info fpga_fsinfo;
+ fpga_fsinfo.fstype = FS_TYPE_ANY;
+#endif
if (devstr)
dev = (int) simple_strtoul(devstr, NULL, 16);
@@ -52,6 +60,14 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
fpga_data = (void *)simple_strtoul(datastr, NULL, 16);
switch (argc) {
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ case 9:
+ fpga_fsinfo.blocksize = (unsigned int)
+ simple_strtoul(argv[5], NULL, 16);
+ fpga_fsinfo.interface = argv[6];
+ fpga_fsinfo.dev_part = argv[7];
+ fpga_fsinfo.filename = argv[8];
+#endif
case 5: /* fpga <op> <dev> <data> <datasize> */
data_size = simple_strtoul(argv[4], NULL, 16);
@@ -120,16 +136,27 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
case FPGA_NONE:
case FPGA_INFO:
break;
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ case FPGA_LOADFS:
+ /* Blocksize can be zero */
+ if (!fpga_fsinfo.interface || !fpga_fsinfo.dev_part ||
+ !fpga_fsinfo.filename)
+ wrong_parms = 1;
+#endif
case FPGA_LOAD:
+ case FPGA_LOADP:
case FPGA_LOADB:
+ case FPGA_LOADBP:
case FPGA_DUMP:
if (!fpga_data || !data_size)
wrong_parms = 1;
break;
+#if defined(CONFIG_CMD_FPGA_LOADMK)
case FPGA_LOADMK:
if (!fpga_data)
wrong_parms = 1;
break;
+#endif
}
if (wrong_parms) {
@@ -146,13 +173,32 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
break;
case FPGA_LOAD:
- rc = fpga_load(dev, fpga_data, data_size);
+ rc = fpga_load(dev, fpga_data, data_size, BIT_FULL);
+ break;
+
+#if defined(CONFIG_CMD_FPGA_LOADP)
+ case FPGA_LOADP:
+ rc = fpga_load(dev, fpga_data, data_size, BIT_PARTIAL);
break;
+#endif
case FPGA_LOADB:
- rc = fpga_loadbitstream(dev, fpga_data, data_size);
+ rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_FULL);
+ break;
+
+#if defined(CONFIG_CMD_FPGA_LOADBP)
+ case FPGA_LOADBP:
+ rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_PARTIAL);
+ break;
+#endif
+
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ case FPGA_LOADFS:
+ rc = fpga_fsload(dev, fpga_data, data_size, &fpga_fsinfo);
break;
+#endif
+#if defined(CONFIG_CMD_FPGA_LOADMK)
case FPGA_LOADMK:
switch (genimg_get_format(fpga_data)) {
case IMAGE_FORMAT_LEGACY:
@@ -179,7 +225,8 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
data = (ulong)image_get_data(hdr);
data_size = image_get_data_size(hdr);
}
- rc = fpga_load(dev, (void *)data, data_size);
+ rc = fpga_load(dev, (void *)data, data_size,
+ BIT_FULL);
}
break;
#if defined(CONFIG_FIT)
@@ -221,7 +268,8 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
return 1;
}
- rc = fpga_load(dev, fit_data, data_size);
+ rc = fpga_load(dev, fit_data, data_size,
+ BIT_FULL);
}
break;
#endif
@@ -231,6 +279,7 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
break;
}
break;
+#endif
case FPGA_DUMP:
rc = fpga_dump(dev, fpga_data, data_size);
@@ -257,8 +306,22 @@ static int fpga_get_op(char *opstr)
op = FPGA_LOADB;
else if (!strcmp("load", opstr))
op = FPGA_LOAD;
+#if defined(CONFIG_CMD_FPGA_LOADP)
+ else if (!strcmp("loadp", opstr))
+ op = FPGA_LOADP;
+#endif
+#if defined(CONFIG_CMD_FPGA_LOADBP)
+ else if (!strcmp("loadbp", opstr))
+ op = FPGA_LOADBP;
+#endif
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ else if (!strcmp("loadfs", opstr))
+ op = FPGA_LOADFS;
+#endif
+#if defined(CONFIG_CMD_FPGA_LOADMK)
else if (!strcmp("loadmk", opstr))
op = FPGA_LOADMK;
+#endif
else if (!strcmp("dump", opstr))
op = FPGA_DUMP;
@@ -268,19 +331,39 @@ static int fpga_get_op(char *opstr)
return op;
}
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+U_BOOT_CMD(fpga, 9, 1, do_fpga,
+#else
U_BOOT_CMD(fpga, 6, 1, do_fpga,
+#endif
"loadable FPGA image support",
"[operation type] [device number] [image address] [image size]\n"
"fpga operations:\n"
" dump\t[dev]\t\t\tLoad device to memory buffer\n"
" info\t[dev]\t\t\tlist known device information\n"
" load\t[dev] [address] [size]\tLoad device from memory buffer\n"
+#if defined(CONFIG_CMD_FPGA_LOADP)
+ " loadp\t[dev] [address] [size]\t"
+ "Load device from memory buffer with partial bitstream\n"
+#endif
" loadb\t[dev] [address] [size]\t"
"Load device from bitstream buffer (Xilinx only)\n"
+#if defined(CONFIG_CMD_FPGA_LOADBP)
+ " loadbp\t[dev] [address] [size]\t"
+ "Load device from bitstream buffer with partial bitstream"
+ "(Xilinx only)\n"
+#endif
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ "Load device from filesystem (FAT by default) (Xilinx only)\n"
+ " loadfs [dev] [address] [image size] [blocksize] <interface>\n"
+ " [<dev[:part]>] <filename>\n"
+#endif
+#if defined(CONFIG_CMD_FPGA_LOADMK)
" loadmk [dev] [address]\tLoad device generated with mkimage"
#if defined(CONFIG_FIT)
"\n"
"\tFor loadmk operating on FIT format uImage address must include\n"
"\tsubimage unit name in the form of addr:<subimg_uname>"
#endif
+#endif
);
diff --git a/common/cmd_fuse.c b/common/cmd_fuse.c
index 0df57db..abab978 100644
--- a/common/cmd_fuse.c
+++ b/common/cmd_fuse.c
@@ -33,15 +33,8 @@ static int confirm_prog(void)
"what you are doing!\n"
"\nReally perform this fuse programming? <y/N>\n");
- if (getc() == 'y') {
- int c;
-
- putc('y');
- c = getc();
- putc('\n');
- if (c == '\r')
- return 1;
- }
+ if (confirm_yesno())
+ return 1;
puts("Fuse programming aborted\n");
return 0;
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
index c1916c9..eea3375 100644
--- a/common/cmd_mmc.c
+++ b/common/cmd_mmc.c
@@ -71,12 +71,6 @@ U_BOOT_CMD(
);
#else /* !CONFIG_GENERIC_MMC */
-enum mmc_state {
- MMC_INVALID,
- MMC_READ,
- MMC_WRITE,
- MMC_ERASE,
-};
static void print_mmcinfo(struct mmc *mmc)
{
printf("Device: %s\n", mmc->cfg->name);
@@ -98,7 +92,18 @@ static void print_mmcinfo(struct mmc *mmc)
printf("Bus Width: %d-bit\n", mmc->bus_width);
}
-
+static struct mmc *init_mmc_device(int dev)
+{
+ struct mmc *mmc;
+ mmc = find_mmc_device(dev);
+ if (!mmc) {
+ printf("no mmc device at slot %x\n", dev);
+ return NULL;
+ }
+ if (mmc_init(mmc))
+ return NULL;
+ return mmc;
+}
static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct mmc *mmc;
@@ -112,351 +117,537 @@ static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
}
- mmc = find_mmc_device(curr_device);
+ mmc = init_mmc_device(curr_device);
+ if (!mmc)
+ return CMD_RET_FAILURE;
- if (mmc) {
- mmc_init(mmc);
+ print_mmcinfo(mmc);
+ return CMD_RET_SUCCESS;
+}
- print_mmcinfo(mmc);
- return 0;
- } else {
- printf("no mmc device at slot %x\n", curr_device);
+#ifdef CONFIG_SUPPORT_EMMC_RPMB
+static int confirm_key_prog(void)
+{
+ puts("Warning: Programming authentication key can be done only once !\n"
+ " Use this command only if you are sure of what you are doing,\n"
+ "Really perform the key programming? <y/N> ");
+ if (confirm_yesno())
return 1;
+
+ puts("Authentication key programming aborted\n");
+ return 0;
+}
+static int do_mmcrpmb_key(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ void *key_addr;
+ struct mmc *mmc = find_mmc_device(curr_device);
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ key_addr = (void *)simple_strtoul(argv[1], NULL, 16);
+ if (!confirm_key_prog())
+ return CMD_RET_FAILURE;
+ if (mmc_rpmb_set_key(mmc, key_addr)) {
+ printf("ERROR - Key already programmed ?\n");
+ return CMD_RET_FAILURE;
}
+ return CMD_RET_SUCCESS;
}
+static int do_mmcrpmb_read(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ u16 blk, cnt;
+ void *addr;
+ int n;
+ void *key_addr = NULL;
+ struct mmc *mmc = find_mmc_device(curr_device);
-U_BOOT_CMD(
- mmcinfo, 1, 0, do_mmcinfo,
- "display MMC info",
- "- display info of the current MMC device"
-);
+ if (argc < 4)
+ return CMD_RET_USAGE;
-static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ addr = (void *)simple_strtoul(argv[1], NULL, 16);
+ blk = simple_strtoul(argv[2], NULL, 16);
+ cnt = simple_strtoul(argv[3], NULL, 16);
+
+ if (argc == 5)
+ key_addr = (void *)simple_strtoul(argv[4], NULL, 16);
+
+ printf("\nMMC RPMB read: dev # %d, block # %d, count %d ... ",
+ curr_device, blk, cnt);
+ n = mmc_rpmb_read(mmc, addr, blk, cnt, key_addr);
+
+ printf("%d RPMB blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
+ if (n != cnt)
+ return CMD_RET_FAILURE;
+ return CMD_RET_SUCCESS;
+}
+static int do_mmcrpmb_write(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
{
- enum mmc_state state;
+ u16 blk, cnt;
+ void *addr;
+ int n;
+ void *key_addr;
+ struct mmc *mmc = find_mmc_device(curr_device);
- if (argc < 2)
+ if (argc != 5)
return CMD_RET_USAGE;
- if (curr_device < 0) {
- if (get_mmc_num() > 0)
- curr_device = 0;
- else {
- puts("No MMC device available\n");
- return 1;
- }
+ addr = (void *)simple_strtoul(argv[1], NULL, 16);
+ blk = simple_strtoul(argv[2], NULL, 16);
+ cnt = simple_strtoul(argv[3], NULL, 16);
+ key_addr = (void *)simple_strtoul(argv[4], NULL, 16);
+
+ printf("\nMMC RPMB write: dev # %d, block # %d, count %d ... ",
+ curr_device, blk, cnt);
+ n = mmc_rpmb_write(mmc, addr, blk, cnt, key_addr);
+
+ printf("%d RPMB blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
+ if (n != cnt)
+ return CMD_RET_FAILURE;
+ return CMD_RET_SUCCESS;
+}
+static int do_mmcrpmb_counter(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ unsigned long counter;
+ struct mmc *mmc = find_mmc_device(curr_device);
+
+ if (mmc_rpmb_get_counter(mmc, &counter))
+ return CMD_RET_FAILURE;
+ printf("RPMB Write counter= %lx\n", counter);
+ return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t cmd_rpmb[] = {
+ U_BOOT_CMD_MKENT(key, 2, 0, do_mmcrpmb_key, "", ""),
+ U_BOOT_CMD_MKENT(read, 5, 1, do_mmcrpmb_read, "", ""),
+ U_BOOT_CMD_MKENT(write, 5, 0, do_mmcrpmb_write, "", ""),
+ U_BOOT_CMD_MKENT(counter, 1, 1, do_mmcrpmb_counter, "", ""),
+};
+
+static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ cmd_tbl_t *cp;
+ struct mmc *mmc;
+ char original_part;
+ int ret;
+
+ cp = find_cmd_tbl(argv[1], cmd_rpmb, ARRAY_SIZE(cmd_rpmb));
+
+ /* Drop the rpmb subcommand */
+ argc--;
+ argv++;
+
+ if (cp == NULL || argc > cp->maxargs)
+ return CMD_RET_USAGE;
+ if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
+ return CMD_RET_SUCCESS;
+
+ mmc = init_mmc_device(curr_device);
+ if (!mmc)
+ return CMD_RET_FAILURE;
+
+ if (!(mmc->version & MMC_VERSION_MMC)) {
+ printf("It is not a EMMC device\n");
+ return CMD_RET_FAILURE;
+ }
+ if (mmc->version < MMC_VERSION_4_41) {
+ printf("RPMB not supported before version 4.41\n");
+ return CMD_RET_FAILURE;
+ }
+ /* Switch to the RPMB partition */
+ original_part = mmc->part_num;
+ if (mmc->part_num != MMC_PART_RPMB) {
+ if (mmc_switch_part(curr_device, MMC_PART_RPMB) != 0)
+ return CMD_RET_FAILURE;
+ mmc->part_num = MMC_PART_RPMB;
}
+ ret = cp->cmd(cmdtp, flag, argc, argv);
- if (strcmp(argv[1], "rescan") == 0) {
- struct mmc *mmc;
+ /* Return to original partition */
+ if (mmc->part_num != original_part) {
+ if (mmc_switch_part(curr_device, original_part) != 0)
+ return CMD_RET_FAILURE;
+ mmc->part_num = original_part;
+ }
+ return ret;
+}
+#endif
- if (argc != 2)
- return CMD_RET_USAGE;
+static int do_mmc_read(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct mmc *mmc;
+ u32 blk, cnt, n;
+ void *addr;
- mmc = find_mmc_device(curr_device);
- if (!mmc) {
- printf("no mmc device at slot %x\n", curr_device);
- return 1;
- }
+ if (argc != 4)
+ return CMD_RET_USAGE;
- mmc->has_init = 0;
+ addr = (void *)simple_strtoul(argv[1], NULL, 16);
+ blk = simple_strtoul(argv[2], NULL, 16);
+ cnt = simple_strtoul(argv[3], NULL, 16);
- if (mmc_init(mmc))
- return 1;
- else
- return 0;
- } else if (strcmp(argv[1], "part") == 0) {
- block_dev_desc_t *mmc_dev;
- struct mmc *mmc;
+ mmc = init_mmc_device(curr_device);
+ if (!mmc)
+ return CMD_RET_FAILURE;
- if (argc != 2)
- return CMD_RET_USAGE;
+ printf("\nMMC read: dev # %d, block # %d, count %d ... ",
+ curr_device, blk, cnt);
- mmc = find_mmc_device(curr_device);
- if (!mmc) {
- printf("no mmc device at slot %x\n", curr_device);
- return 1;
- }
- mmc_init(mmc);
- mmc_dev = mmc_get_dev(curr_device);
- if (mmc_dev != NULL &&
- mmc_dev->type != DEV_TYPE_UNKNOWN) {
- print_part(mmc_dev);
- return 0;
- }
+ n = mmc->block_dev.block_read(curr_device, blk, cnt, addr);
+ /* flush cache after read */
+ flush_cache((ulong)addr, cnt * 512); /* FIXME */
+ printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
- puts("get mmc type error!\n");
- return 1;
- } else if (strcmp(argv[1], "list") == 0) {
- if (argc != 2)
- return CMD_RET_USAGE;
- print_mmc_devices('\n');
- return 0;
- } else if (strcmp(argv[1], "dev") == 0) {
- int dev, part = -1;
- struct mmc *mmc;
-
- if (argc == 2)
- dev = curr_device;
- else if (argc == 3)
- dev = simple_strtoul(argv[2], NULL, 10);
- else if (argc == 4) {
- dev = (int)simple_strtoul(argv[2], NULL, 10);
- part = (int)simple_strtoul(argv[3], NULL, 10);
- if (part > PART_ACCESS_MASK) {
- printf("#part_num shouldn't be larger"
- " than %d\n", PART_ACCESS_MASK);
- return 1;
- }
- } else
- return CMD_RET_USAGE;
+ return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+static int do_mmc_write(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct mmc *mmc;
+ u32 blk, cnt, n;
+ void *addr;
- mmc = find_mmc_device(dev);
- if (!mmc) {
- printf("no mmc device at slot %x\n", dev);
- return 1;
- }
+ if (argc != 4)
+ return CMD_RET_USAGE;
- mmc_init(mmc);
- if (part != -1) {
- int ret;
- if (mmc->part_config == MMCPART_NOAVAILABLE) {
- printf("Card doesn't support part_switch\n");
- return 1;
- }
+ addr = (void *)simple_strtoul(argv[1], NULL, 16);
+ blk = simple_strtoul(argv[2], NULL, 16);
+ cnt = simple_strtoul(argv[3], NULL, 16);
- if (part != mmc->part_num) {
- ret = mmc_switch_part(dev, part);
- if (!ret)
- mmc->part_num = part;
+ mmc = init_mmc_device(curr_device);
+ if (!mmc)
+ return CMD_RET_FAILURE;
- printf("switch to partitions #%d, %s\n",
- part, (!ret) ? "OK" : "ERROR");
- }
- }
- curr_device = dev;
- if (mmc->part_config == MMCPART_NOAVAILABLE)
- printf("mmc%d is current device\n", curr_device);
- else
- printf("mmc%d(part %d) is current device\n",
- curr_device, mmc->part_num);
+ printf("\nMMC write: dev # %d, block # %d, count %d ... ",
+ curr_device, blk, cnt);
- return 0;
-#ifdef CONFIG_SUPPORT_EMMC_BOOT
- } else if (strcmp(argv[1], "partconf") == 0) {
- int dev;
- struct mmc *mmc;
- u8 ack, part_num, access;
-
- if (argc == 6) {
- dev = simple_strtoul(argv[2], NULL, 10);
- ack = simple_strtoul(argv[3], NULL, 10);
- part_num = simple_strtoul(argv[4], NULL, 10);
- access = simple_strtoul(argv[5], NULL, 10);
- } else {
- return CMD_RET_USAGE;
- }
+ if (mmc_getwp(mmc) == 1) {
+ printf("Error: card is write protected!\n");
+ return CMD_RET_FAILURE;
+ }
+ n = mmc->block_dev.block_write(curr_device, blk, cnt, addr);
+ printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
- mmc = find_mmc_device(dev);
- if (!mmc) {
- printf("no mmc device at slot %x\n", dev);
- return 1;
- }
+ return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+static int do_mmc_erase(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct mmc *mmc;
+ u32 blk, cnt, n;
- if (IS_SD(mmc)) {
- puts("PARTITION_CONFIG only exists on eMMC\n");
- return 1;
- }
+ if (argc != 3)
+ return CMD_RET_USAGE;
- /* acknowledge to be sent during boot operation */
- return mmc_set_part_conf(mmc, ack, part_num, access);
- } else if (strcmp(argv[1], "bootbus") == 0) {
- int dev;
- struct mmc *mmc;
- u8 width, reset, mode;
-
- if (argc == 6) {
- dev = simple_strtoul(argv[2], NULL, 10);
- width = simple_strtoul(argv[3], NULL, 10);
- reset = simple_strtoul(argv[4], NULL, 10);
- mode = simple_strtoul(argv[5], NULL, 10);
- } else {
- return CMD_RET_USAGE;
- }
+ blk = simple_strtoul(argv[1], NULL, 16);
+ cnt = simple_strtoul(argv[2], NULL, 16);
- mmc = find_mmc_device(dev);
- if (!mmc) {
- printf("no mmc device at slot %x\n", dev);
- return 1;
- }
+ mmc = init_mmc_device(curr_device);
+ if (!mmc)
+ return CMD_RET_FAILURE;
- if (IS_SD(mmc)) {
- puts("BOOT_BUS_WIDTH only exists on eMMC\n");
- return 1;
- }
+ printf("\nMMC erase: dev # %d, block # %d, count %d ... ",
+ curr_device, blk, cnt);
- /* acknowledge to be sent during boot operation */
- return mmc_set_boot_bus_width(mmc, width, reset, mode);
- } else if (strcmp(argv[1], "bootpart-resize") == 0) {
- int dev;
- struct mmc *mmc;
- u32 bootsize, rpmbsize;
-
- if (argc == 5) {
- dev = simple_strtoul(argv[2], NULL, 10);
- bootsize = simple_strtoul(argv[3], NULL, 10);
- rpmbsize = simple_strtoul(argv[4], NULL, 10);
- } else {
- return CMD_RET_USAGE;
- }
+ if (mmc_getwp(mmc) == 1) {
+ printf("Error: card is write protected!\n");
+ return CMD_RET_FAILURE;
+ }
+ n = mmc->block_dev.block_erase(curr_device, blk, cnt);
+ printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR");
- mmc = find_mmc_device(dev);
- if (!mmc) {
- printf("no mmc device at slot %x\n", dev);
- return 1;
- }
+ return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+static int do_mmc_rescan(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct mmc *mmc;
- if (IS_SD(mmc)) {
- printf("It is not a EMMC device\n");
- return 1;
- }
+ mmc = find_mmc_device(curr_device);
+ if (!mmc) {
+ printf("no mmc device at slot %x\n", curr_device);
+ return CMD_RET_FAILURE;
+ }
- if (0 == mmc_boot_partition_size_change(mmc,
- bootsize, rpmbsize)) {
- printf("EMMC boot partition Size %d MB\n", bootsize);
- printf("EMMC RPMB partition Size %d MB\n", rpmbsize);
- return 0;
- } else {
- printf("EMMC boot partition Size change Failed.\n");
- return 1;
- }
- } else if (strcmp(argv[1], "rst-function") == 0) {
- /*
- * Set the RST_n_ENABLE bit of RST_n_FUNCTION
- * The only valid values are 0x0, 0x1 and 0x2 and writing
- * a value of 0x1 or 0x2 sets the value permanently.
- */
- int dev;
- struct mmc *mmc;
- u8 enable;
-
- if (argc == 4) {
- dev = simple_strtoul(argv[2], NULL, 10);
- enable = simple_strtoul(argv[3], NULL, 10);
- } else {
- return CMD_RET_USAGE;
- }
+ mmc->has_init = 0;
- if (enable > 2 || enable < 0) {
- puts("Invalid RST_n_ENABLE value\n");
- return CMD_RET_USAGE;
- }
+ if (mmc_init(mmc))
+ return CMD_RET_FAILURE;
+ return CMD_RET_SUCCESS;
+}
+static int do_mmc_part(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ block_dev_desc_t *mmc_dev;
+ struct mmc *mmc;
- mmc = find_mmc_device(dev);
- if (!mmc) {
- printf("no mmc device at slot %x\n", dev);
- return 1;
+ mmc = init_mmc_device(curr_device);
+ if (!mmc)
+ return CMD_RET_FAILURE;
+
+ mmc_dev = mmc_get_dev(curr_device);
+ if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) {
+ print_part(mmc_dev);
+ return CMD_RET_SUCCESS;
+ }
+
+ puts("get mmc type error!\n");
+ return CMD_RET_FAILURE;
+}
+static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ int dev, part = -1, ret;
+ struct mmc *mmc;
+
+ if (argc == 1) {
+ dev = curr_device;
+ } else if (argc == 2) {
+ dev = simple_strtoul(argv[1], NULL, 10);
+ } else if (argc == 3) {
+ dev = (int)simple_strtoul(argv[1], NULL, 10);
+ part = (int)simple_strtoul(argv[2], NULL, 10);
+ if (part > PART_ACCESS_MASK) {
+ printf("#part_num shouldn't be larger than %d\n",
+ PART_ACCESS_MASK);
+ return CMD_RET_FAILURE;
}
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ mmc = init_mmc_device(dev);
+ if (!mmc)
+ return CMD_RET_FAILURE;
- if (IS_SD(mmc)) {
- puts("RST_n_FUNCTION only exists on eMMC\n");
+ if (part != -1) {
+ ret = mmc_select_hwpart(dev, part);
+ printf("switch to partitions #%d, %s\n",
+ part, (!ret) ? "OK" : "ERROR");
+ if (ret)
return 1;
- }
+ }
+ curr_device = dev;
+ if (mmc->part_config == MMCPART_NOAVAILABLE)
+ printf("mmc%d is current device\n", curr_device);
+ else
+ printf("mmc%d(part %d) is current device\n",
+ curr_device, mmc->part_num);
- return mmc_set_rst_n_function(mmc, enable);
-#endif /* CONFIG_SUPPORT_EMMC_BOOT */
+ return CMD_RET_SUCCESS;
+}
+static int do_mmc_list(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ print_mmc_devices('\n');
+ return CMD_RET_SUCCESS;
+}
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+static int do_mmc_bootbus(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ int dev;
+ struct mmc *mmc;
+ u8 width, reset, mode;
+
+ if (argc != 5)
+ return CMD_RET_USAGE;
+ dev = simple_strtoul(argv[1], NULL, 10);
+ width = simple_strtoul(argv[2], NULL, 10);
+ reset = simple_strtoul(argv[3], NULL, 10);
+ mode = simple_strtoul(argv[4], NULL, 10);
+
+ mmc = init_mmc_device(dev);
+ if (!mmc)
+ return CMD_RET_FAILURE;
+
+ if (IS_SD(mmc)) {
+ puts("BOOT_BUS_WIDTH only exists on eMMC\n");
+ return CMD_RET_FAILURE;
}
- else if (argc == 3 && strcmp(argv[1], "setdsr") == 0) {
- struct mmc *mmc = find_mmc_device(curr_device);
- u32 val = simple_strtoul(argv[2], NULL, 16);
- int ret;
+ /* acknowledge to be sent during boot operation */
+ return mmc_set_boot_bus_width(mmc, width, reset, mode);
+}
+static int do_mmc_boot_resize(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ int dev;
+ struct mmc *mmc;
+ u32 bootsize, rpmbsize;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+ dev = simple_strtoul(argv[1], NULL, 10);
+ bootsize = simple_strtoul(argv[2], NULL, 10);
+ rpmbsize = simple_strtoul(argv[3], NULL, 10);
- if (!mmc) {
- printf("no mmc device at slot %x\n", curr_device);
- return 1;
- }
- ret = mmc_set_dsr(mmc, val);
- printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
- if (!ret) {
- mmc->has_init = 0;
- if (mmc_init(mmc))
- return 1;
- else
- return 0;
- }
- return ret;
+ mmc = init_mmc_device(dev);
+ if (!mmc)
+ return CMD_RET_FAILURE;
+
+ if (IS_SD(mmc)) {
+ printf("It is not a EMMC device\n");
+ return CMD_RET_FAILURE;
}
- state = MMC_INVALID;
- if (argc == 5 && strcmp(argv[1], "read") == 0)
- state = MMC_READ;
- else if (argc == 5 && strcmp(argv[1], "write") == 0)
- state = MMC_WRITE;
- else if (argc == 4 && strcmp(argv[1], "erase") == 0)
- state = MMC_ERASE;
-
- if (state != MMC_INVALID) {
- struct mmc *mmc = find_mmc_device(curr_device);
- int idx = 2;
- u32 blk, cnt, n;
- void *addr;
-
- if (state != MMC_ERASE) {
- addr = (void *)simple_strtoul(argv[idx], NULL, 16);
- ++idx;
- } else
- addr = NULL;
- blk = simple_strtoul(argv[idx], NULL, 16);
- cnt = simple_strtoul(argv[idx + 1], NULL, 16);
-
- if (!mmc) {
- printf("no mmc device at slot %x\n", curr_device);
- return 1;
- }
+ if (mmc_boot_partition_size_change(mmc, bootsize, rpmbsize)) {
+ printf("EMMC boot partition Size change Failed.\n");
+ return CMD_RET_FAILURE;
+ }
+
+ printf("EMMC boot partition Size %d MB\n", bootsize);
+ printf("EMMC RPMB partition Size %d MB\n", rpmbsize);
+ return CMD_RET_SUCCESS;
+}
+static int do_mmc_partconf(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ int dev;
+ struct mmc *mmc;
+ u8 ack, part_num, access;
- printf("\nMMC %s: dev # %d, block # %d, count %d ... ",
- argv[1], curr_device, blk, cnt);
+ if (argc != 5)
+ return CMD_RET_USAGE;
- mmc_init(mmc);
+ dev = simple_strtoul(argv[1], NULL, 10);
+ ack = simple_strtoul(argv[2], NULL, 10);
+ part_num = simple_strtoul(argv[3], NULL, 10);
+ access = simple_strtoul(argv[4], NULL, 10);
- if ((state == MMC_WRITE || state == MMC_ERASE)) {
- if (mmc_getwp(mmc) == 1) {
- printf("Error: card is write protected!\n");
- return 1;
- }
- }
+ mmc = init_mmc_device(dev);
+ if (!mmc)
+ return CMD_RET_FAILURE;
- switch (state) {
- case MMC_READ:
- n = mmc->block_dev.block_read(curr_device, blk,
- cnt, addr);
- /* flush cache after read */
- flush_cache((ulong)addr, cnt * 512); /* FIXME */
- break;
- case MMC_WRITE:
- n = mmc->block_dev.block_write(curr_device, blk,
- cnt, addr);
- break;
- case MMC_ERASE:
- n = mmc->block_dev.block_erase(curr_device, blk, cnt);
- break;
- default:
- BUG();
- }
+ if (IS_SD(mmc)) {
+ puts("PARTITION_CONFIG only exists on eMMC\n");
+ return CMD_RET_FAILURE;
+ }
+
+ /* acknowledge to be sent during boot operation */
+ return mmc_set_part_conf(mmc, ack, part_num, access);
+}
+static int do_mmc_rst_func(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ int dev;
+ struct mmc *mmc;
+ u8 enable;
+
+ /*
+ * Set the RST_n_ENABLE bit of RST_n_FUNCTION
+ * The only valid values are 0x0, 0x1 and 0x2 and writing
+ * a value of 0x1 or 0x2 sets the value permanently.
+ */
+ if (argc != 3)
+ return CMD_RET_USAGE;
+
+ dev = simple_strtoul(argv[1], NULL, 10);
+ enable = simple_strtoul(argv[2], NULL, 10);
+
+ if (enable > 2 || enable < 0) {
+ puts("Invalid RST_n_ENABLE value\n");
+ return CMD_RET_USAGE;
+ }
+
+ mmc = init_mmc_device(dev);
+ if (!mmc)
+ return CMD_RET_FAILURE;
+
+ if (IS_SD(mmc)) {
+ puts("RST_n_FUNCTION only exists on eMMC\n");
+ return CMD_RET_FAILURE;
+ }
- printf("%d blocks %s: %s\n",
- n, argv[1], (n == cnt) ? "OK" : "ERROR");
- return (n == cnt) ? 0 : 1;
+ return mmc_set_rst_n_function(mmc, enable);
+}
+#endif
+static int do_mmc_setdsr(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct mmc *mmc;
+ u32 val;
+ int ret;
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+ val = simple_strtoul(argv[2], NULL, 16);
+
+ mmc = find_mmc_device(curr_device);
+ if (!mmc) {
+ printf("no mmc device at slot %x\n", curr_device);
+ return CMD_RET_FAILURE;
+ }
+ ret = mmc_set_dsr(mmc, val);
+ printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
+ if (!ret) {
+ mmc->has_init = 0;
+ if (mmc_init(mmc))
+ return CMD_RET_FAILURE;
+ else
+ return CMD_RET_SUCCESS;
}
+ return ret;
+}
+
+static cmd_tbl_t cmd_mmc[] = {
+ U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""),
+ U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""),
+ U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
+ U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""),
+ U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""),
+ U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
+ U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
+ U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+ U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
+ U_BOOT_CMD_MKENT(bootpart-resize, 3, 0, do_mmc_boot_resize, "", ""),
+ U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""),
+ U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""),
+#endif
+#ifdef CONFIG_SUPPORT_EMMC_RPMB
+ U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""),
+#endif
+ U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
+};
+
+static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *cp;
+
+ cp = find_cmd_tbl(argv[1], cmd_mmc, ARRAY_SIZE(cmd_mmc));
+
+ /* Drop the mmc command */
+ argc--;
+ argv++;
+
+ if (cp == NULL || argc > cp->maxargs)
+ return CMD_RET_USAGE;
+ if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
+ return CMD_RET_SUCCESS;
- return CMD_RET_USAGE;
+ if (curr_device < 0) {
+ if (get_mmc_num() > 0) {
+ curr_device = 0;
+ } else {
+ puts("No MMC device available\n");
+ return CMD_RET_FAILURE;
+ }
+ }
+ return cp->cmd(cmdtp, flag, argc, argv);
}
U_BOOT_CMD(
- mmc, 6, 1, do_mmcops,
+ mmc, 7, 1, do_mmcops,
"MMC sub system",
- "read addr blk# cnt\n"
+ "info - display info of the current MMC device\n"
+ "mmc read addr blk# cnt\n"
"mmc write addr blk# cnt\n"
"mmc erase blk# cnt\n"
"mmc rescan\n"
@@ -474,6 +665,20 @@ U_BOOT_CMD(
" - Change the RST_n_FUNCTION field of the specified device\n"
" WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n"
#endif
- "mmc setdsr - set DSR register value\n"
+#ifdef CONFIG_SUPPORT_EMMC_RPMB
+ "mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n"
+ "mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n"
+ "mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n"
+ "mmc rpmb counter - read the value of the write counter\n"
+#endif
+ "mmc setdsr <value> - set DSR register value\n"
);
+
+/* Old command kept for compatibility. Same as 'mmc info' */
+U_BOOT_CMD(
+ mmcinfo, 1, 0, do_mmcinfo,
+ "display MMC info",
+ "- display info of the current MMC device"
+);
+
#endif /* !CONFIG_GENERIC_MMC */
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 04ab0f1..a84f7dc 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -605,22 +605,16 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
opts.spread = spread;
if (scrub) {
- if (!scrub_yes)
- puts(scrub_warn);
-
- if (scrub_yes)
+ if (scrub_yes) {
opts.scrub = 1;
- else if (getc() == 'y') {
- puts("y");
- if (getc() == '\r')
+ } else {
+ puts(scrub_warn);
+ if (confirm_yesno()) {
opts.scrub = 1;
- else {
+ } else {
puts("scrub aborted\n");
return 1;
}
- } else {
- puts("scrub aborted\n");
- return 1;
}
}
ret = nand_erase_opts(nand, &opts);
diff --git a/common/cmd_otp.c b/common/cmd_otp.c
index 67808aa..593bb8c 100644
--- a/common/cmd_otp.c
+++ b/common/cmd_otp.c
@@ -158,21 +158,9 @@ int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
lowup(half + count - 1), page + (half + count - 1) / 2,
half + count
);
-
- i = 0;
- while (1) {
- if (tstc()) {
- const char exp_ans[] = "YES\r";
- char c;
- putc(c = getc());
- if (exp_ans[i++] != c) {
- printf(" Aborting\n");
- return 1;
- } else if (!exp_ans[i]) {
- puts("\n");
- break;
- }
- }
+ if (!confirm_yesno()) {
+ printf(" Aborting\n");
+ return 1;
}
}
diff --git a/common/cmd_part.c b/common/cmd_part.c
index 1424854..c84bc27 100644
--- a/common/cmd_part.c
+++ b/common/cmd_part.c
@@ -82,7 +82,7 @@ int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
U_BOOT_CMD(
part, 5, 1, do_part,
"disk partition related commands",
- "uuid <interface> <dev>:<part>\n"
+ "part uuid <interface> <dev>:<part>\n"
" - print partition UUID\n"
"part uuid <interface> <dev>:<part> <varname>\n"
" - set environment variable to partition UUID\n"
diff --git a/common/cmd_usb_mass_storage.c b/common/cmd_usb_mass_storage.c
index d8d9efd..2c879ea 100644
--- a/common/cmd_usb_mass_storage.c
+++ b/common/cmd_usb_mass_storage.c
@@ -9,41 +9,107 @@
#include <common.h>
#include <command.h>
#include <g_dnl.h>
+#include <part.h>
#include <usb.h>
#include <usb_mass_storage.h>
+static int ums_read_sector(struct ums *ums_dev,
+ ulong start, lbaint_t blkcnt, void *buf)
+{
+ block_dev_desc_t *block_dev = ums_dev->block_dev;
+ lbaint_t blkstart = start + ums_dev->start_sector;
+ int dev_num = block_dev->dev;
+
+ return block_dev->block_read(dev_num, blkstart, blkcnt, buf);
+}
+
+static int ums_write_sector(struct ums *ums_dev,
+ ulong start, lbaint_t blkcnt, const void *buf)
+{
+ block_dev_desc_t *block_dev = ums_dev->block_dev;
+ lbaint_t blkstart = start + ums_dev->start_sector;
+ int dev_num = block_dev->dev;
+
+ return block_dev->block_write(dev_num, blkstart, blkcnt, buf);
+}
+
+static struct ums ums_dev = {
+ .read_sector = ums_read_sector,
+ .write_sector = ums_write_sector,
+ .name = "UMS disk",
+};
+
+struct ums *ums_init(const char *devtype, const char *devnum)
+{
+ block_dev_desc_t *block_dev;
+ int ret;
+
+ ret = get_device(devtype, devnum, &block_dev);
+ if (ret < 0)
+ return NULL;
+
+ /* f_mass_storage.c assumes SECTOR_SIZE sectors */
+ if (block_dev->blksz != SECTOR_SIZE)
+ return NULL;
+
+ ums_dev.block_dev = block_dev;
+ ums_dev.start_sector = 0;
+ ums_dev.num_sectors = block_dev->lba;
+
+ printf("UMS: disk start sector: %#x, count: %#x\n",
+ ums_dev.start_sector, ums_dev.num_sectors);
+
+ return &ums_dev;
+}
+
int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
+ const char *usb_controller;
+ const char *devtype;
+ const char *devnum;
+ struct ums *ums;
+ unsigned int controller_index;
+ int rc;
+ int cable_ready_timeout __maybe_unused;
+
if (argc < 3)
return CMD_RET_USAGE;
- const char *usb_controller = argv[1];
- const char *mmc_devstring = argv[2];
-
- unsigned int dev_num = simple_strtoul(mmc_devstring, NULL, 0);
+ usb_controller = argv[1];
+ if (argc >= 4) {
+ devtype = argv[2];
+ devnum = argv[3];
+ } else {
+ devtype = "mmc";
+ devnum = argv[2];
+ }
- struct ums *ums = ums_init(dev_num);
+ ums = ums_init(devtype, devnum);
if (!ums)
return CMD_RET_FAILURE;
- unsigned int controller_index = (unsigned int)(simple_strtoul(
- usb_controller, NULL, 0));
+ controller_index = (unsigned int)(simple_strtoul(
+ usb_controller, NULL, 0));
if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
error("Couldn't init USB controller.");
return CMD_RET_FAILURE;
}
- int rc = fsg_init(ums);
+ rc = fsg_init(ums);
if (rc) {
error("fsg_init failed");
return CMD_RET_FAILURE;
}
- g_dnl_register("usb_dnl_ums");
+ rc = g_dnl_register("usb_dnl_ums");
+ if (rc) {
+ error("g_dnl_register failed");
+ return CMD_RET_FAILURE;
+ }
/* Timeout unit: seconds */
- int cable_ready_timeout = UMS_CABLE_READY_TIMEOUT;
+ cable_ready_timeout = UMS_CABLE_READY_TIMEOUT;
if (!g_dnl_board_usb_cable_connected()) {
/*
@@ -91,7 +157,8 @@ exit:
return CMD_RET_SUCCESS;
}
-U_BOOT_CMD(ums, CONFIG_SYS_MAXARGS, 1, do_usb_mass_storage,
+U_BOOT_CMD(ums, 4, 1, do_usb_mass_storage,
"Use the UMS [User Mass Storage]",
- "ums <USB_controller> <mmc_dev> e.g. ums 0 0"
+ "ums <USB_controller> [<devtype>] <devnum> e.g. ums 0 mmc 0\n"
+ " devtype defaults to mmc"
);
diff --git a/common/console.c b/common/console.c
index 2dfb788..5453726 100644
--- a/common/console.c
+++ b/common/console.c
@@ -537,7 +537,33 @@ int ctrlc(void)
}
return 0;
}
-
+/* Reads user's confirmation.
+ Returns 1 if user's input is "y", "Y", "yes" or "YES"
+*/
+int confirm_yesno(void)
+{
+ int i;
+ char str_input[5];
+
+ /* Flush input */
+ while (tstc())
+ getc();
+ i = 0;
+ while (i < sizeof(str_input)) {
+ str_input[i] = getc();
+ putc(str_input[i]);
+ if (str_input[i] == '\r')
+ break;
+ i++;
+ }
+ putc('\n');
+ if (strncmp(str_input, "y\r", 2) == 0 ||
+ strncmp(str_input, "Y\r", 2) == 0 ||
+ strncmp(str_input, "yes\r", 4) == 0 ||
+ strncmp(str_input, "YES\r", 4) == 0)
+ return 1;
+ return 0;
+}
/* pass 1 to disable ctrlc() checking, 0 to enable.
* returns previous state
*/
diff --git a/common/image-android.c b/common/image-android.c
new file mode 100644
index 0000000..6ded7e2
--- /dev/null
+++ b/common/image-android.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <image.h>
+#include <android_image.h>
+
+static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
+
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+ ulong *os_data, ulong *os_len)
+{
+ /*
+ * Not all Android tools use the id field for signing the image with
+ * sha1 (or anything) so we don't check it. It is not obvious that the
+ * string is null terminated so we take care of this.
+ */
+ strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
+ andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
+ if (strlen(andr_tmp_str))
+ printf("Android's image name: %s\n", andr_tmp_str);
+
+ printf("Kernel load addr 0x%08x size %u KiB\n",
+ hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
+ strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
+ andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
+ if (strlen(andr_tmp_str)) {
+ printf("Kernel command line: %s\n", andr_tmp_str);
+ setenv("bootargs", andr_tmp_str);
+ }
+ if (hdr->ramdisk_size)
+ printf("RAM disk load addr 0x%08x size %u KiB\n",
+ hdr->ramdisk_addr,
+ DIV_ROUND_UP(hdr->ramdisk_size, 1024));
+
+ if (os_data) {
+ *os_data = (ulong)hdr;
+ *os_data += hdr->page_size;
+ }
+ if (os_len)
+ *os_len = hdr->kernel_size;
+ return 0;
+}
+
+int android_image_check_header(const struct andr_img_hdr *hdr)
+{
+ return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
+}
+
+ulong android_image_get_end(const struct andr_img_hdr *hdr)
+{
+ u32 size = 0;
+ /*
+ * The header takes a full page, the remaining components are aligned
+ * on page boundary
+ */
+ size += hdr->page_size;
+ size += ALIGN(hdr->kernel_size, hdr->page_size);
+ size += ALIGN(hdr->ramdisk_size, hdr->page_size);
+ size += ALIGN(hdr->second_size, hdr->page_size);
+
+ return size;
+}
+
+ulong android_image_get_kload(const struct andr_img_hdr *hdr)
+{
+ return hdr->kernel_addr;
+}
+
+int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
+ ulong *rd_data, ulong *rd_len)
+{
+ if (!hdr->ramdisk_size)
+ return -1;
+ *rd_data = (unsigned long)hdr;
+ *rd_data += hdr->page_size;
+ *rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
+
+ *rd_len = hdr->ramdisk_size;
+ return 0;
+}
diff --git a/common/image.c b/common/image.c
index fcc5a9c..fa4864d 100644
--- a/common/image.c
+++ b/common/image.c
@@ -660,10 +660,12 @@ int genimg_get_format(const void *img_addr)
if (image_check_magic(hdr))
format = IMAGE_FORMAT_LEGACY;
#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
- else {
- if (fdt_check_header(img_addr) == 0)
- format = IMAGE_FORMAT_FIT;
- }
+ else if (fdt_check_header(img_addr) == 0)
+ format = IMAGE_FORMAT_FIT;
+#endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ else if (android_image_check_header(img_addr) == 0)
+ format = IMAGE_FORMAT_ANDROID;
#endif
return format;
@@ -933,7 +935,15 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
(ulong)images->legacy_hdr_os);
image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
- } else {
+ }
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
+ (!android_image_get_ramdisk((void *)images->os.start,
+ &rd_data, &rd_len))) {
+ /* empty */
+ }
+#endif
+ else {
/*
* no initrd image
*/
diff --git a/disk/part.c b/disk/part.c
index b8c6aac..2827089 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -22,6 +22,7 @@
struct block_drvr {
char *name;
block_dev_desc_t* (*get_dev)(int dev);
+ int (*select_hwpart)(int dev_num, int hwpart);
};
static const struct block_drvr block_drvr[] = {
@@ -38,7 +39,11 @@ static const struct block_drvr block_drvr[] = {
{ .name = "usb", .get_dev = usb_stor_get_dev, },
#endif
#if defined(CONFIG_MMC)
- { .name = "mmc", .get_dev = mmc_get_dev, },
+ {
+ .name = "mmc",
+ .get_dev = mmc_get_dev,
+ .select_hwpart = mmc_select_hwpart,
+ },
#endif
#if defined(CONFIG_SYSTEMACE)
{ .name = "ace", .get_dev = systemace_get_dev, },
@@ -52,11 +57,13 @@ static const struct block_drvr block_drvr[] = {
DECLARE_GLOBAL_DATA_PTR;
#ifdef HAVE_BLOCK_DEVICE
-block_dev_desc_t *get_dev(const char *ifname, int dev)
+block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
{
const struct block_drvr *drvr = block_drvr;
block_dev_desc_t* (*reloc_get_dev)(int dev);
+ int (*select_hwpart)(int dev_num, int hwpart);
char *name;
+ int ret;
if (!ifname)
return NULL;
@@ -68,17 +75,41 @@ block_dev_desc_t *get_dev(const char *ifname, int dev)
while (drvr->name) {
name = drvr->name;
reloc_get_dev = drvr->get_dev;
+ select_hwpart = drvr->select_hwpart;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
name += gd->reloc_off;
reloc_get_dev += gd->reloc_off;
-#endif
- if (strncmp(ifname, name, strlen(name)) == 0)
- return reloc_get_dev(dev);
+ if (select_hwpart)
+ select_hwpart += gd->reloc_off;
+#endif
+ if (strncmp(ifname, name, strlen(name)) == 0) {
+ block_dev_desc_t *dev_desc = reloc_get_dev(dev);
+ if (!dev_desc)
+ return NULL;
+ if (hwpart == -1)
+ return dev_desc;
+ if (!select_hwpart)
+ return NULL;
+ ret = select_hwpart(dev_desc->dev, hwpart);
+ if (ret < 0)
+ return NULL;
+ return dev_desc;
+ }
drvr++;
}
return NULL;
}
+
+block_dev_desc_t *get_dev(const char *ifname, int dev)
+{
+ return get_dev_hwpart(ifname, dev, -1);
+}
#else
+block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
+{
+ return NULL;
+}
+
block_dev_desc_t *get_dev(const char *ifname, int dev)
{
return NULL;
@@ -413,25 +444,52 @@ int get_partition_info(block_dev_desc_t *dev_desc, int part
return -1;
}
-int get_device(const char *ifname, const char *dev_str,
+int get_device(const char *ifname, const char *dev_hwpart_str,
block_dev_desc_t **dev_desc)
{
char *ep;
- int dev;
+ char *dup_str = NULL;
+ const char *dev_str, *hwpart_str;
+ int dev, hwpart;
+
+ hwpart_str = strchr(dev_hwpart_str, '.');
+ if (hwpart_str) {
+ dup_str = strdup(dev_hwpart_str);
+ dup_str[hwpart_str - dev_hwpart_str] = 0;
+ dev_str = dup_str;
+ hwpart_str++;
+ } else {
+ dev_str = dev_hwpart_str;
+ hwpart = -1;
+ }
dev = simple_strtoul(dev_str, &ep, 16);
if (*ep) {
printf("** Bad device specification %s %s **\n",
ifname, dev_str);
- return -1;
+ dev = -1;
+ goto cleanup;
+ }
+
+ if (hwpart_str) {
+ hwpart = simple_strtoul(hwpart_str, &ep, 16);
+ if (*ep) {
+ printf("** Bad HW partition specification %s %s **\n",
+ ifname, hwpart_str);
+ dev = -1;
+ goto cleanup;
+ }
}
- *dev_desc = get_dev(ifname, dev);
+ *dev_desc = get_dev_hwpart(ifname, dev, hwpart);
if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
- printf("** Bad device %s %s **\n", ifname, dev_str);
- return -1;
+ printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
+ dev = -1;
+ goto cleanup;
}
+cleanup:
+ free(dup_str);
return dev;
}
diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
new file mode 100644
index 0000000..f1d128c
--- /dev/null
+++ b/doc/README.android-fastboot
@@ -0,0 +1,91 @@
+Android Fastboot
+~~~~~~~~~~~~~~~~
+
+Overview
+========
+The protocol that is used over USB is described in
+README.android-fastboot-protocol in same directory.
+
+The current implementation does not yet support the flash and erase
+commands.
+
+Client installation
+===================
+The counterpart to this gadget is the fastboot client which can
+be found in Android's platform/system/core repository in the fastboot
+folder. It runs on Windows, Linux and even OSX. Linux user are lucky since
+they only need libusb.
+Windows users need to bring some time until they have Android SDK (currently
+http://dl.google.com/android/installer_r12-windows.exe) installed. You
+need to install ADB package which contains the required glue libraries for
+accessing USB. Also you need "Google USB driver package" and "SDK platform
+tools". Once installed the usb driver is placed in your SDK folder under
+extras\google\usb_driver. The android_winusb.inf needs a line like
+
+ %SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022
+
+either in the [Google.NTx86] section for 32bit Windows or [Google.NTamd64]
+for 64bit Windows. VID and PID should match whatever the fastboot is
+advertising.
+
+Board specific
+==============
+The fastboot gadget relies on the USB download gadget, so the following
+options must be configured:
+
+CONFIG_USBDOWNLOAD_GADGET
+CONFIG_G_DNL_VENDOR_NUM
+CONFIG_G_DNL_PRODUCT_NUM
+CONFIG_G_DNL_MANUFACTURER
+
+The fastboot function is enabled by defining CONFIG_CMD_FASTBOOT and
+CONFIG_ANDROID_BOOT_IMAGE.
+
+The fastboot protocol requires a large memory buffer for downloads. This
+buffer should be as large as possible for a platform. The location of the
+buffer and size are set with CONFIG_USB_FASTBOOT_BUF_ADDR and
+CONFIG_USB_FASTBOOT_BUF_SIZE.
+
+In Action
+=========
+Enter into fastboot by executing the fastboot command in u-boot and you
+should see:
+|GADGET DRIVER: usb_dnl_fastboot
+
+On the client side you can fetch the bootloader version for instance:
+|>fastboot getvar bootloader-version
+|bootloader-version: U-Boot 2014.04-00005-gd24cabc
+|finished. total time: 0.000s
+
+or initiate a reboot:
+|>fastboot reboot
+
+and once the client comes back, the board should reset.
+
+You can also specify a kernel image to boot. You have to either specify
+the an image in Android format _or_ pass a binary kernel and let the
+fastboot client wrap the Android suite around it. On OMAP for instance you
+take zImage kernel and pass it to the fastboot client:
+
+|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0
+| mem=128M" boot zImage
+|creating boot image...
+|creating boot image - 1847296 bytes
+|downloading 'boot.img'...
+|OKAY [ 2.766s]
+|booting...
+|OKAY [ -0.000s]
+|finished. total time: 2.766s
+
+and on the gadget side you should see:
+|Starting download of 1847296 bytes
+|........................................................
+|downloading of 1847296 bytes finished
+|Booting kernel..
+|## Booting Android Image at 0x81000000 ...
+|Kernel load addr 0x80008000 size 1801 KiB
+|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M
+| Loading Kernel Image ... OK
+|OK
+|
+|Starting kernel ...
diff --git a/doc/README.android-fastboot-protocol b/doc/README.android-fastboot-protocol
new file mode 100644
index 0000000..e9e7166
--- /dev/null
+++ b/doc/README.android-fastboot-protocol
@@ -0,0 +1,170 @@
+FastBoot Version 0.4
+----------------------
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB. It is designed to be very straightforward to implement, to
+allow it to be used across a wide range of devices and from hosts running
+Linux, Windows, or OSX.
+
+
+Basic Requirements
+------------------
+
+* Two bulk endpoints (in, out) are required
+* Max packet size must be 64 bytes for full-speed and 512 bytes for
+ high-speed USB
+* The protocol is entirely host-driven and synchronous (unlike the
+ multi-channel, bi-directional, asynchronous ADB protocol)
+
+
+Transport and Framing
+---------------------
+
+1. Host sends a command, which is an ascii string in a single
+ packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+ The first four bytes of the response are "OKAY", "FAIL", "DATA",
+ or "INFO". Additional bytes may contain an (ascii) informative
+ message.
+
+ a. INFO -> the remaining 60 bytes are an informative message
+ (providing progress or diagnostic messages). They should
+ be displayed and then step #2 repeats
+
+ b. FAIL -> the requested command failed. The remaining 60 bytes
+ of the response (if present) provide a textual failure message
+ to present to the user. Stop.
+
+ c. OKAY -> the requested command completed successfully. Go to #5
+
+ d. DATA -> the requested command is ready for the data phase.
+ A DATA response packet will be 12 bytes long, in the form of
+ DATA00000000 where the 8 digit hexidecimal number represents
+ the total data size to transfer.
+
+3. Data phase. Depending on the command, the host or client will
+ send the indicated amount of data. Short packets are always
+ acceptable and zero-length packets are ignored. This phase continues
+ until the client has sent or received the number of bytes indicated
+ in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.
+ The first four bytes of the response are "OKAY", "FAIL", or "INFO".
+ Similar to #2:
+
+ a. INFO -> display the remaining 60 bytes and return to #4
+
+ b. FAIL -> display the remaining 60 bytes (if present) as a failure
+ reason and consider the command failed. Stop.
+
+ c. OKAY -> success. Go to #5
+
+5. Success. Stop.
+
+
+Example Session
+---------------
+
+Host: "getvar:version" request version variable
+
+Client: "OKAY0.4" return version "0.4"
+
+Host: "getvar:nonexistant" request some undefined variable
+
+Client: "OKAY" return value ""
+
+Host: "download:00001234" request to send 0x1234 bytes of data
+
+Client: "DATA00001234" ready to accept data
+
+Host: < 0x1234 bytes > send data
+
+Client: "OKAY" success
+
+Host: "flash:bootloader" request to flash the data to the bootloader
+
+Client: "INFOerasing flash" indicate status / progress
+ "INFOwriting flash"
+ "OKAY" indicate success
+
+Host: "powerdown" send a command
+
+Client: "FAILunknown command" indicate failure
+
+
+Command Reference
+-----------------
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+ for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+ specification. OEM-specific commands should not begin with a
+ lowercase letter, to prevent incompatibilities with future specs.
+
+ "getvar:%s" Read a config/version variable from the bootloader.
+ The variable contents will be returned after the
+ OKAY response.
+
+ "download:%08x" Write data to memory which will be later used
+ by "boot", "ramdisk", "flash", etc. The client
+ will reply with "DATA%08x" if it has enough
+ space in RAM or "FAIL" if not. The size of
+ the download is remembered.
+
+ "verify:%08x" Send a digital signature to verify the downloaded
+ data. Required if the bootloader is "secure"
+ otherwise "flash" and "boot" will be ignored.
+
+ "flash:%s" Write the previously downloaded image to the
+ named partition (if possible).
+
+ "erase:%s" Erase the indicated partition (clear to 0xFFs)
+
+ "boot" The previously downloaded data is a boot.img
+ and should be booted according to the normal
+ procedure for a boot.img
+
+ "continue" Continue booting as normal (if possible)
+
+ "reboot" Reboot the device.
+
+ "reboot-bootloader" Reboot back into the bootloader.
+ Useful for upgrade processes that require upgrading
+ the bootloader and then upgrading other partitions
+ using the new bootloader.
+
+ "powerdown" Power off the device.
+
+
+
+Client Variables
+----------------
+
+The "getvar:%s" command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are:
+
+ version Version of FastBoot protocol supported.
+ It should be "0.3" for this document.
+
+ version-bootloader Version string for the Bootloader.
+
+ version-baseband Version string of the Baseband Software
+
+ product Name of the product
+
+ serialno Product serial number
+
+ secure If the value is "yes", this is a secure
+ bootloader requiring a signature before
+ it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification. OEM-specific names should not start with lowercase
+characters.
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index 51b1026..a938109 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -131,6 +131,10 @@ int dfu_flush(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
{
int ret = 0;
+ ret = dfu_write_buffer_drain(dfu);
+ if (ret)
+ return ret;
+
if (dfu->flush_medium)
ret = dfu->flush_medium(dfu);
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 5e10ea7..63cc876 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -18,11 +18,29 @@ static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE];
static long dfu_file_buf_len;
+static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part)
+{
+ int ret;
+
+ if (part == mmc->part_num)
+ return 0;
+
+ ret = mmc_switch_part(dfu->dev_num, part);
+ if (ret) {
+ error("Cannot switch to partition %d\n", part);
+ return ret;
+ }
+ mmc->part_num = part;
+
+ return 0;
+}
+
static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
{
struct mmc *mmc = find_mmc_device(dfu->dev_num);
u32 blk_start, blk_count, n = 0;
+ int ret, part_num_bkp = 0;
/*
* We must ensure that we work in lba_blk_size chunks, so ALIGN
@@ -39,6 +57,13 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
return -EINVAL;
}
+ if (dfu->data.mmc.hw_partition >= 0) {
+ part_num_bkp = mmc->part_num;
+ ret = mmc_access_part(dfu, mmc, dfu->data.mmc.hw_partition);
+ if (ret)
+ return ret;
+ }
+
debug("%s: %s dev: %d start: %d cnt: %d buf: 0x%p\n", __func__,
op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", dfu->dev_num,
blk_start, blk_count, buf);
@@ -57,9 +82,17 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
if (n != blk_count) {
error("MMC operation failed");
+ if (dfu->data.mmc.hw_partition >= 0)
+ mmc_access_part(dfu, mmc, part_num_bkp);
return -EIO;
}
+ if (dfu->data.mmc.hw_partition >= 0) {
+ ret = mmc_access_part(dfu, mmc, part_num_bkp);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -194,6 +227,8 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf,
* 2nd and 3rd:
* lba_start and lba_size, for raw write
* mmc_dev and mmc_part, for filesystems and part
+ * 4th (optional):
+ * mmcpart <num> (access to HW eMMC partitions)
*/
int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
{
@@ -233,11 +268,22 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
return -ENODEV;
}
+ dfu->data.mmc.hw_partition = -EINVAL;
if (!strcmp(entity_type, "raw")) {
dfu->layout = DFU_RAW_ADDR;
dfu->data.mmc.lba_start = second_arg;
dfu->data.mmc.lba_size = third_arg;
dfu->data.mmc.lba_blk_size = mmc->read_bl_len;
+
+ /*
+ * Check for an extra entry at dfu_alt_info env variable
+ * specifying the mmc HW defined partition number
+ */
+ if (s)
+ if (!strcmp(strsep(&s, " "), "mmcpart"))
+ dfu->data.mmc.hw_partition =
+ simple_strtoul(s, NULL, 0);
+
} else if (!strcmp(entity_type, "part")) {
disk_partition_t partinfo;
block_dev_desc_t *blk_dev = &mmc->block_dev;
diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c
index 2d07097..ccdbef6 100644
--- a/drivers/dfu/dfu_nand.c
+++ b/drivers/dfu/dfu_nand.c
@@ -163,6 +163,18 @@ static int dfu_flush_medium_nand(struct dfu_entity *dfu)
return ret;
}
+unsigned int dfu_polltimeout_nand(struct dfu_entity *dfu)
+{
+ /*
+ * Currently, Poll Timeout != 0 is only needed on nand
+ * ubi partition, as the not used sectors need an erase
+ */
+ if (dfu->data.nand.ubi)
+ return DFU_MANIFEST_POLL_TIMEOUT;
+
+ return DFU_DEFAULT_POLL_TIMEOUT;
+}
+
int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
{
char *st;
@@ -211,6 +223,7 @@ int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
dfu->read_medium = dfu_read_medium_nand;
dfu->write_medium = dfu_write_medium_nand;
dfu->flush_medium = dfu_flush_medium_nand;
+ dfu->poll_timeout = dfu_polltimeout_nand;
/* initial state */
dfu->inited = 0;
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
index b940d9b..37946d5 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -173,16 +173,45 @@ int fpga_add(fpga_type devtype, void *desc)
/*
* Convert bitstream data and load into the fpga
*/
-int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size)
+int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
{
printf("Bitstream support not implemented for this FPGA device\n");
return FPGA_FAIL;
}
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int fpga_fsload(int devnum, const void *buf, size_t size,
+ fpga_fs_info *fpga_fsinfo)
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ const fpga_desc *desc = fpga_validate(devnum, buf, size,
+ (char *)__func__);
+
+ if (desc) {
+ switch (desc->devtype) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_loadfs(desc->devdesc, buf, size,
+ fpga_fsinfo);
+#else
+ fpga_no_sup((char *)__func__, "Xilinx devices");
+#endif
+ break;
+ default:
+ printf("%s: Invalid or unsupported device type %d\n",
+ __func__, desc->devtype);
+ }
+ }
+
+ return ret_val;
+}
+#endif
+
/*
* Generic multiplexing code
*/
-int fpga_load(int devnum, const void *buf, size_t bsize)
+int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype)
{
int ret_val = FPGA_FAIL; /* assume failure */
const fpga_desc *desc = fpga_validate(devnum, buf, bsize,
@@ -192,7 +221,8 @@ int fpga_load(int devnum, const void *buf, size_t bsize)
switch (desc->devtype) {
case fpga_xilinx:
#if defined(CONFIG_FPGA_XILINX)
- ret_val = xilinx_load(desc->devdesc, buf, bsize);
+ ret_val = xilinx_load(desc->devdesc, buf, bsize,
+ bstype);
#else
fpga_no_sup((char *)__func__, "Xilinx devices");
#endif
diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c
index 7054056..859fb3c 100644
--- a/drivers/fpga/spartan2.c
+++ b/drivers/fpga/spartan2.c
@@ -41,7 +41,8 @@ static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* ------------------------------------------------------------------------- */
/* Spartan-II Generic Implementation */
-static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
diff --git a/drivers/fpga/spartan3.c b/drivers/fpga/spartan3.c
index 5c9412c..b0213e6 100644
--- a/drivers/fpga/spartan3.c
+++ b/drivers/fpga/spartan3.c
@@ -45,7 +45,8 @@ static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* ------------------------------------------------------------------------- */
/* Spartan-II Generic Implementation */
-static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c
index e092147..0d2d9a4 100644
--- a/drivers/fpga/virtex2.c
+++ b/drivers/fpga/virtex2.c
@@ -90,7 +90,8 @@ static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
-static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c
index 8837f5c..3795c1a 100644
--- a/drivers/fpga/xilinx.c
+++ b/drivers/fpga/xilinx.c
@@ -24,7 +24,8 @@ static int xilinx_validate(xilinx_desc *desc, char *fn);
/* ------------------------------------------------------------------------- */
-int fpga_loadbitstream(int devnum, char *fpgadata, size_t size)
+int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
{
unsigned int length;
unsigned int swapsize;
@@ -127,19 +128,36 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size)
dataptr += 4;
printf(" bytes in bitstream = %d\n", swapsize);
- return fpga_load(devnum, dataptr, swapsize);
+ return fpga_load(devnum, dataptr, swapsize, bstype);
}
-int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize)
+int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
printf ("%s: Invalid device descriptor\n", __FUNCTION__);
return FPGA_FAIL;
}
- return desc->operations->load(desc, buf, bsize);
+ return desc->operations->load(desc, buf, bsize, bstype);
}
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+ fpga_fs_info *fpga_fsinfo)
+{
+ if (!xilinx_validate(desc, (char *)__func__)) {
+ printf("%s: Invalid device descriptor\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ if (!desc->operations->loadfs)
+ return FPGA_FAIL;
+
+ return desc->operations->loadfs(desc, buf, bsize, fpga_fsinfo);
+}
+#endif
+
int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index c066f21..68fe0f3 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <asm/io.h>
+#include <fs.h>
#include <zynqpl.h>
#include <linux/sizes.h>
#include <asm/arch/hardware.h>
@@ -194,7 +195,7 @@ static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen)
return FPGA_SUCCESS;
}
-static int zynq_dma_xfer_init(u32 partialbit)
+static int zynq_dma_xfer_init(bitstream_type bstype)
{
u32 status, control, isr_status;
unsigned long ts;
@@ -202,7 +203,7 @@ static int zynq_dma_xfer_init(u32 partialbit)
/* Clear loopback bit */
clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK);
- if (!partialbit) {
+ if (bstype != BIT_PARTIAL) {
zynq_slcr_devcfg_disable();
/* Setting PCFG_PROG_B signal to high */
@@ -322,16 +323,11 @@ static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
size_t bsize, u32 blocksize, u32 *swap,
- u32 *partialbit)
+ bitstream_type *bstype)
{
u32 *buf_start;
u32 diff;
- /* Detect if we are going working with partial or full bitstream */
- if (bsize != desc->size) {
- printf("%s: Working with partial bitstream\n", __func__);
- *partialbit = 1;
- }
buf_start = check_data((u8 *)buf, blocksize, swap);
if (!buf_start)
@@ -351,17 +347,16 @@ static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
return FPGA_FAIL;
}
- if (zynq_dma_xfer_init(*partialbit))
+ if (zynq_dma_xfer_init(*bstype))
return FPGA_FAIL;
return 0;
}
-
-static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
unsigned long ts; /* Timestamp */
- u32 partialbit = 0;
u32 isr_status, swap;
/*
@@ -369,7 +364,7 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
* in chunks
*/
if (zynq_validate_bitstream(desc, buf, bsize, bsize, &swap,
- &partialbit))
+ &bstype))
return FPGA_FAIL;
buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap);
@@ -398,11 +393,92 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
debug("%s: FPGA config done\n", __func__);
+ if (bstype != BIT_PARTIAL)
+ zynq_slcr_devcfg_enable();
+
+ return FPGA_SUCCESS;
+}
+
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+ fpga_fs_info *fsinfo)
+{
+ unsigned long ts; /* Timestamp */
+ u32 isr_status, swap;
+ u32 partialbit = 0;
+ u32 blocksize;
+ u32 pos = 0;
+ int fstype;
+ char *interface, *dev_part, *filename;
+
+ blocksize = fsinfo->blocksize;
+ interface = fsinfo->interface;
+ dev_part = fsinfo->dev_part;
+ filename = fsinfo->filename;
+ fstype = fsinfo->fstype;
+
+ if (fs_set_blk_dev(interface, dev_part, fstype))
+ return FPGA_FAIL;
+
+ if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+ return FPGA_FAIL;
+
+ if (zynq_validate_bitstream(desc, buf, bsize, blocksize, &swap,
+ &partialbit))
+ return FPGA_FAIL;
+
+ dcache_disable();
+
+ do {
+ buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+ if (zynq_dma_transfer((u32)buf | 1, blocksize >> 2,
+ 0xffffffff, 0))
+ return FPGA_FAIL;
+
+ bsize -= blocksize;
+ pos += blocksize;
+
+ if (fs_set_blk_dev(interface, dev_part, fstype))
+ return FPGA_FAIL;
+
+ if (bsize > blocksize) {
+ if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+ return FPGA_FAIL;
+ } else {
+ if (fs_read(filename, (u32) buf, pos, bsize) < 0)
+ return FPGA_FAIL;
+ }
+ } while (bsize > blocksize);
+
+ buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+ if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
+ return FPGA_FAIL;
+
+ dcache_enable();
+
+ isr_status = readl(&devcfg_base->int_sts);
+
+ /* Check FPGA configuration completion */
+ ts = get_timer(0);
+ while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
+ if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for FPGA to config\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ isr_status = readl(&devcfg_base->int_sts);
+ }
+
+ debug("%s: FPGA config done\n", __func__);
+
if (!partialbit)
zynq_slcr_devcfg_enable();
return FPGA_SUCCESS;
}
+#endif
static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
@@ -411,6 +487,9 @@ static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
struct xilinx_fpga_op zynq_op = {
.load = zynq_load,
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ .loadfs = zynq_loadfs,
+#endif
.dump = zynq_dump,
.info = zynq_info,
};
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 931922b..4c6ab9e 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_DWMMC) += dw_mmc.o
obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
+obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
else
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 50cba64..5541613 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -174,7 +174,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
int timeout;
struct fsl_esdhc_cfg *cfg = mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
-#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+
uint wml_value;
wml_value = data->blocksize/4;
@@ -184,12 +184,15 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
wml_value = WML_RD_WML_MAX_VAL;
esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
esdhc_write32(&regs->dsaddr, (u32)data->dest);
+#endif
} else {
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
flush_dcache_range((ulong)data->src,
(ulong)data->src+data->blocks
*data->blocksize);
-
+#endif
if (wml_value > WML_WR_WML_MAX)
wml_value = WML_WR_WML_MAX_VAL;
if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
@@ -199,19 +202,10 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
wml_value << 16);
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
esdhc_write32(&regs->dsaddr, (u32)data->src);
+#endif
}
-#else /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
- if (!(data->flags & MMC_DATA_READ)) {
- if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
- printf("\nThe SD card is locked. "
- "Can not write to a locked card.\n\n");
- return TIMEOUT;
- }
- esdhc_write32(&regs->dsaddr, (u32)data->src);
- } else
- esdhc_write32(&regs->dsaddr, (u32)data->dest);
-#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
@@ -252,6 +246,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
return 0;
}
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
static void check_and_invalidate_dcache_range
(struct mmc_cmd *cmd,
struct mmc_data *data) {
@@ -261,6 +256,8 @@ static void check_and_invalidate_dcache_range
unsigned end = start+size ;
invalidate_dcache_range(start, end);
}
+#endif
+
/*
* Sends a command out on the bus. Takes the mmc pointer,
* a command pointer, and an optional data pointer.
@@ -388,9 +385,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
goto out;
}
} while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE);
-#endif
+
if (data->flags & MMC_DATA_READ)
check_and_invalidate_dcache_range(cmd, data);
+#endif
}
out:
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 16051e5..8b53ead 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -150,6 +150,8 @@ int mmc_send_status(struct mmc *mmc, int timeout)
#endif
return TIMEOUT;
}
+ if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
+ return SWITCH_ERR;
return 0;
}
@@ -501,7 +503,7 @@ static int mmc_change_freq(struct mmc *mmc)
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
if (err)
- return err;
+ return err == SWITCH_ERR ? 0 : err;
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, ext_csd);
@@ -550,6 +552,32 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
return 0;
}
+int mmc_select_hwpart(int dev_num, int hwpart)
+{
+ struct mmc *mmc = find_mmc_device(dev_num);
+ int ret;
+
+ if (!mmc)
+ return -1;
+
+ if (mmc->part_num == hwpart)
+ return 0;
+
+ if (mmc->part_config == MMCPART_NOAVAILABLE) {
+ printf("Card doesn't support part_switch\n");
+ return -1;
+ }
+
+ ret = mmc_switch_part(dev_num, hwpart);
+ if (ret)
+ return -1;
+
+ mmc->part_num = hwpart;
+
+ return 0;
+}
+
+
int mmc_switch_part(int dev_num, unsigned int part_num)
{
struct mmc *mmc = find_mmc_device(dev_num);
@@ -1310,10 +1338,13 @@ static int mmc_complete_init(struct mmc *mmc)
int mmc_init(struct mmc *mmc)
{
int err = IN_PROGRESS;
- unsigned start = get_timer(0);
+ unsigned start;
if (mmc->has_init)
return 0;
+
+ start = get_timer(0);
+
if (!mmc->init_in_progress)
err = mmc_start_init(mmc);
diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c
new file mode 100644
index 0000000..05936f5
--- /dev/null
+++ b/drivers/mmc/rpmb.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2014, Staubli Faverges
+ * Pierre Aubert
+ *
+ * eMMC- Replay Protected Memory Block
+ * According to JEDEC Standard No. 84-A441
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <mmc.h>
+#include <sha256.h>
+#include "mmc_private.h"
+
+/* Request codes */
+#define RPMB_REQ_KEY 1
+#define RPMB_REQ_WCOUNTER 2
+#define RPMB_REQ_WRITE_DATA 3
+#define RPMB_REQ_READ_DATA 4
+#define RPMB_REQ_STATUS 5
+
+/* Response code */
+#define RPMB_RESP_KEY 0x0100
+#define RPMB_RESP_WCOUNTER 0x0200
+#define RPMB_RESP_WRITE_DATA 0x0300
+#define RPMB_RESP_READ_DATA 0x0400
+
+/* Error codes */
+#define RPMB_OK 0
+#define RPMB_ERR_GENERAL 1
+#define RPMB_ERR_AUTH 2
+#define RPMB_ERR_COUNTER 3
+#define RPMB_ERR_ADDRESS 4
+#define RPMB_ERR_WRITE 5
+#define RPMB_ERR_READ 6
+#define RPMB_ERR_KEY 7
+#define RPMB_ERR_CNT_EXPIRED 0x80
+#define RPMB_ERR_MSK 0x7
+
+/* Sizes of RPMB data frame */
+#define RPMB_SZ_STUFF 196
+#define RPMB_SZ_MAC 32
+#define RPMB_SZ_DATA 256
+#define RPMB_SZ_NONCE 16
+
+#define SHA256_BLOCK_SIZE 64
+
+/* Error messages */
+static const char * const rpmb_err_msg[] = {
+ "",
+ "General failure",
+ "Authentication failure",
+ "Counter failure",
+ "Address failure",
+ "Write failure",
+ "Read failure",
+ "Authentication key not yet programmed",
+};
+
+
+/* Structure of RPMB data frame. */
+struct s_rpmb {
+ unsigned char stuff[RPMB_SZ_STUFF];
+ unsigned char mac[RPMB_SZ_MAC];
+ unsigned char data[RPMB_SZ_DATA];
+ unsigned char nonce[RPMB_SZ_NONCE];
+ unsigned long write_counter;
+ unsigned short address;
+ unsigned short block_count;
+ unsigned short result;
+ unsigned short request;
+};
+
+static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
+ bool is_rel_write)
+{
+ struct mmc_cmd cmd = {0};
+
+ cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
+ cmd.cmdarg = blockcount & 0x0000FFFF;
+ if (is_rel_write)
+ cmd.cmdarg |= 1 << 31;
+ cmd.resp_type = MMC_RSP_R1;
+
+ return mmc_send_cmd(mmc, &cmd, NULL);
+}
+static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
+ unsigned int count, bool is_rel_write)
+{
+ struct mmc_cmd cmd = {0};
+ struct mmc_data data;
+ int ret;
+
+ ret = mmc_set_blockcount(mmc, count, is_rel_write);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
+#endif
+ return 1;
+ }
+
+ cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1b;
+
+ data.src = (const char *)s;
+ data.blocks = 1;
+ data.blocksize = MMC_MAX_BLOCK_LEN;
+ data.flags = MMC_DATA_WRITE;
+
+ ret = mmc_send_cmd(mmc, &cmd, &data);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
+#endif
+ return 1;
+ }
+ return 0;
+}
+static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
+ unsigned short expected)
+{
+ struct mmc_cmd cmd = {0};
+ struct mmc_data data;
+ int ret;
+
+ ret = mmc_set_blockcount(mmc, 1, false);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
+#endif
+ return -1;
+ }
+ cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
+
+ data.dest = (char *)s;
+ data.blocks = 1;
+ data.blocksize = MMC_MAX_BLOCK_LEN;
+ data.flags = MMC_DATA_READ;
+
+ ret = mmc_send_cmd(mmc, &cmd, &data);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
+#endif
+ return -1;
+ }
+ /* Check the response and the status */
+ if (be16_to_cpu(s->request) != expected) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:response= %x\n", __func__,
+ be16_to_cpu(s->request));
+#endif
+ return -1;
+ }
+ ret = be16_to_cpu(s->result);
+ if (ret) {
+ printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
+ (ret & RPMB_ERR_CNT_EXPIRED) ?
+ "Write counter has expired" : "");
+ }
+
+ /* Return the status of the command */
+ return ret;
+}
+static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
+ return -1;
+
+ /* Read the result */
+ return mmc_rpmb_response(mmc, rpmb_frame, expected);
+}
+static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
+ unsigned char *output)
+{
+ sha256_context ctx;
+ int i;
+ unsigned char k_ipad[SHA256_BLOCK_SIZE];
+ unsigned char k_opad[SHA256_BLOCK_SIZE];
+
+ sha256_starts(&ctx);
+
+ /* According to RFC 4634, the HMAC transform looks like:
+ SHA(K XOR opad, SHA(K XOR ipad, text))
+
+ where K is an n byte key.
+ ipad is the byte 0x36 repeated blocksize times
+ opad is the byte 0x5c repeated blocksize times
+ and text is the data being protected.
+ */
+
+ for (i = 0; i < RPMB_SZ_MAC; i++) {
+ k_ipad[i] = key[i] ^ 0x36;
+ k_opad[i] = key[i] ^ 0x5c;
+ }
+ /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
+ for ( ; i < SHA256_BLOCK_SIZE; i++) {
+ k_ipad[i] = 0x36;
+ k_opad[i] = 0x5c;
+ }
+ sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
+ sha256_update(&ctx, buff, len);
+ sha256_finish(&ctx, output);
+
+ /* Init context for second pass */
+ sha256_starts(&ctx);
+
+ /* start with outer pad */
+ sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
+
+ /* then results of 1st hash */
+ sha256_update(&ctx, output, RPMB_SZ_MAC);
+
+ /* finish up 2nd pass */
+ sha256_finish(&ctx, output);
+}
+int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
+{
+ int ret;
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
+ return -1;
+
+ /* Read the result */
+ ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
+ if (ret)
+ return ret;
+
+ *pcounter = be32_to_cpu(rpmb_frame->write_counter);
+ return 0;
+}
+int mmc_rpmb_set_key(struct mmc *mmc, void *key)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
+ memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
+
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
+ return -1;
+
+ /* read the operation status */
+ return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
+}
+int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
+ unsigned short cnt, unsigned char *key)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->address = cpu_to_be16(blk + i);
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
+ break;
+
+ /* Read the result */
+ if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
+ break;
+
+ /* Check the HMAC if key is provided */
+ if (key) {
+ unsigned char ret_hmac[RPMB_SZ_MAC];
+
+ rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
+ if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
+ printf("MAC error on block #%d\n", i);
+ break;
+ }
+ }
+ /* Copy data */
+ memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
+ }
+ return i;
+}
+int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
+ unsigned short cnt, unsigned char *key)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+ unsigned long wcount;
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ if (mmc_rpmb_get_counter(mmc, &wcount)) {
+ printf("Cannot read RPMB write counter\n");
+ break;
+ }
+
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
+ rpmb_frame->address = cpu_to_be16(blk + i);
+ rpmb_frame->block_count = cpu_to_be16(1);
+ rpmb_frame->write_counter = cpu_to_be32(wcount);
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
+ /* Computes HMAC */
+ rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
+
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
+ break;
+
+ /* Get status */
+ if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
+ break;
+ }
+ return i;
+}
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 896c8d4..66becdc 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
+obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o
endif
ifdef CONFIG_USB_ETHER
obj-y += ether.o
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 02d3fda..9cd0036 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -205,13 +205,26 @@ static void ci_invalidate_qtd(int ep_num)
static struct usb_request *
ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
{
- struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
- return &ci_ep->req;
+ struct ci_req *ci_req;
+
+ ci_req = memalign(ARCH_DMA_MINALIGN, sizeof(*ci_req));
+ if (!ci_req)
+ return NULL;
+
+ INIT_LIST_HEAD(&ci_req->queue);
+ ci_req->b_buf = 0;
+
+ return &ci_req->req;
}
-static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
+static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *req)
{
- return;
+ struct ci_req *ci_req;
+
+ ci_req = container_of(req, struct ci_req, req);
+ if (ci_req->b_buf)
+ free(ci_req->b_buf);
+ free(ci_req);
}
static void ep_enable(int num, int in, int maxpacket)
@@ -267,99 +280,102 @@ static int ci_ep_disable(struct usb_ep *ep)
return 0;
}
-static int ci_bounce(struct ci_ep *ep, int in)
+static int ci_bounce(struct ci_req *ci_req, int in)
{
- uint32_t addr = (uint32_t)ep->req.buf;
- uint32_t ba;
+ struct usb_request *req = &ci_req->req;
+ uint32_t addr = (uint32_t)req->buf;
+ uint32_t hwaddr;
+ uint32_t aligned_used_len;
/* Input buffer address is not aligned. */
if (addr & (ARCH_DMA_MINALIGN - 1))
goto align;
/* Input buffer length is not aligned. */
- if (ep->req.length & (ARCH_DMA_MINALIGN - 1))
+ if (req->length & (ARCH_DMA_MINALIGN - 1))
goto align;
/* The buffer is well aligned, only flush cache. */
- ep->b_len = ep->req.length;
- ep->b_buf = ep->req.buf;
+ ci_req->hw_len = req->length;
+ ci_req->hw_buf = req->buf;
goto flush;
align:
- /* Use internal buffer for small payloads. */
- if (ep->req.length <= 64) {
- ep->b_len = 64;
- ep->b_buf = ep->b_fast;
- } else {
- ep->b_len = roundup(ep->req.length, ARCH_DMA_MINALIGN);
- ep->b_buf = memalign(ARCH_DMA_MINALIGN, ep->b_len);
- if (!ep->b_buf)
+ if (ci_req->b_buf && req->length > ci_req->b_len) {
+ free(ci_req->b_buf);
+ ci_req->b_buf = 0;
+ }
+ if (!ci_req->b_buf) {
+ ci_req->b_len = roundup(req->length, ARCH_DMA_MINALIGN);
+ ci_req->b_buf = memalign(ARCH_DMA_MINALIGN, ci_req->b_len);
+ if (!ci_req->b_buf)
return -ENOMEM;
}
+ ci_req->hw_len = ci_req->b_len;
+ ci_req->hw_buf = ci_req->b_buf;
+
if (in)
- memcpy(ep->b_buf, ep->req.buf, ep->req.length);
+ memcpy(ci_req->hw_buf, req->buf, req->length);
flush:
- ba = (uint32_t)ep->b_buf;
- flush_dcache_range(ba, ba + ep->b_len);
+ hwaddr = (uint32_t)ci_req->hw_buf;
+ aligned_used_len = roundup(req->length, ARCH_DMA_MINALIGN);
+ flush_dcache_range(hwaddr, hwaddr + aligned_used_len);
return 0;
}
-static void ci_debounce(struct ci_ep *ep, int in)
+static void ci_debounce(struct ci_req *ci_req, int in)
{
- uint32_t addr = (uint32_t)ep->req.buf;
- uint32_t ba = (uint32_t)ep->b_buf;
+ struct usb_request *req = &ci_req->req;
+ uint32_t addr = (uint32_t)req->buf;
+ uint32_t hwaddr = (uint32_t)ci_req->hw_buf;
+ uint32_t aligned_used_len;
- if (in) {
- if (addr == ba)
- return; /* not a bounce */
- goto free;
- }
- invalidate_dcache_range(ba, ba + ep->b_len);
+ if (in)
+ return;
+
+ aligned_used_len = roundup(req->actual, ARCH_DMA_MINALIGN);
+ invalidate_dcache_range(hwaddr, hwaddr + aligned_used_len);
- if (addr == ba)
- return; /* not a bounce */
+ if (addr == hwaddr)
+ return; /* not a bounce */
- memcpy(ep->req.buf, ep->b_buf, ep->req.actual);
-free:
- /* Large payloads use allocated buffer, free it. */
- if (ep->b_buf != ep->b_fast)
- free(ep->b_buf);
+ memcpy(req->buf, ci_req->hw_buf, req->actual);
}
-static int ci_ep_queue(struct usb_ep *ep,
- struct usb_request *req, gfp_t gfp_flags)
+static void ci_ep_submit_next_request(struct ci_ep *ci_ep)
{
- struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
struct ept_queue_item *item;
struct ept_queue_head *head;
- int bit, num, len, in, ret;
+ int bit, num, len, in;
+ struct ci_req *ci_req;
+
+ ci_ep->req_primed = true;
+
num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
item = ci_get_qtd(num, in);
head = ci_get_qh(num, in);
- len = req->length;
- ret = ci_bounce(ci_ep, in);
- if (ret)
- return ret;
+ ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
+ len = ci_req->req.length;
item->next = TERMINATE;
item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
- item->page0 = (uint32_t)ci_ep->b_buf;
- item->page1 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x1000;
- item->page2 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x2000;
- item->page3 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x3000;
- item->page4 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x4000;
+ item->page0 = (uint32_t)ci_req->hw_buf;
+ item->page1 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x1000;
+ item->page2 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x2000;
+ item->page3 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x3000;
+ item->page4 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x4000;
ci_flush_qtd(num);
head->next = (unsigned) item;
head->info = 0;
- DBG("ept%d %s queue len %x, buffer %p\n",
- num, in ? "in" : "out", len, ci_ep->b_buf);
+ DBG("ept%d %s queue len %x, req %p, buffer %p\n",
+ num, in ? "in" : "out", len, ci_req, ci_req->hw_buf);
ci_flush_qh(num);
if (in)
@@ -368,6 +384,29 @@ static int ci_ep_queue(struct usb_ep *ep,
bit = EPT_RX(num);
writel(bit, &udc->epprime);
+}
+
+static int ci_ep_queue(struct usb_ep *ep,
+ struct usb_request *req, gfp_t gfp_flags)
+{
+ struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+ struct ci_req *ci_req = container_of(req, struct ci_req, req);
+ int in, ret;
+ int __maybe_unused num;
+
+ num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+
+ ret = ci_bounce(ci_req, in);
+ if (ret)
+ return ret;
+
+ DBG("ept%d %s pre-queue req %p, buffer %p\n",
+ num, in ? "in" : "out", ci_req, ci_req->hw_buf);
+ list_add_tail(&ci_req->queue, &ci_ep->queue);
+
+ if (!ci_ep->req_primed)
+ ci_ep_submit_next_request(ci_ep);
return 0;
}
@@ -376,6 +415,8 @@ static void handle_ep_complete(struct ci_ep *ep)
{
struct ept_queue_item *item;
int num, in, len;
+ struct ci_req *ci_req;
+
num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
if (num == 0)
@@ -383,20 +424,27 @@ static void handle_ep_complete(struct ci_ep *ep)
item = ci_get_qtd(num, in);
ci_invalidate_qtd(num);
+ len = (item->info >> 16) & 0x7fff;
if (item->info & 0xff)
printf("EP%d/%s FAIL info=%x pg0=%x\n",
num, in ? "in" : "out", item->info, item->page0);
- len = (item->info >> 16) & 0x7fff;
- ep->req.actual = ep->req.length - len;
- ci_debounce(ep, in);
+ ci_req = list_first_entry(&ep->queue, struct ci_req, queue);
+ list_del_init(&ci_req->queue);
+ ep->req_primed = false;
+
+ if (!list_empty(&ep->queue))
+ ci_ep_submit_next_request(ep);
+
+ ci_req->req.actual = ci_req->req.length - len;
+ ci_debounce(ci_req, in);
- DBG("ept%d %s complete %x\n",
- num, in ? "in" : "out", len);
- ep->req.complete(&ep->ep, &ep->req);
+ DBG("ept%d %s req %p, complete %x\n",
+ num, in ? "in" : "out", ci_req, len);
+ ci_req->req.complete(&ep->ep, &ci_req->req);
if (num == 0) {
- ep->req.length = 0;
- usb_ep_queue(&ep->ep, &ep->req, 0);
+ ci_req->req.length = 0;
+ usb_ep_queue(&ep->ep, &ci_req->req, 0);
ep->desc = &ep0_in_desc;
}
}
@@ -405,13 +453,18 @@ static void handle_ep_complete(struct ci_ep *ep)
static void handle_setup(void)
{
- struct usb_request *req = &controller.ep[0].req;
+ struct ci_ep *ci_ep = &controller.ep[0];
+ struct ci_req *ci_req;
+ struct usb_request *req;
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
struct ept_queue_head *head;
struct usb_ctrlrequest r;
int status = 0;
int num, in, _num, _in, i;
char *buf;
+
+ ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
+ req = &ci_req->req;
head = ci_get_qh(0, 0); /* EP0 OUT */
ci_invalidate_qh(0);
@@ -424,6 +477,9 @@ static void handle_setup(void)
DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest),
r.bRequestType, r.bRequest, r.wIndex, r.wValue);
+ list_del_init(&ci_req->queue);
+ ci_ep->req_primed = false;
+
switch (SETUP(r.bRequestType, r.bRequest)) {
case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
_num = r.wIndex & 15;
@@ -701,6 +757,8 @@ static int ci_udc_probe(void)
/* Init EP 0 */
memcpy(&controller.ep[0].ep, &ci_ep_init[0], sizeof(*ci_ep_init));
controller.ep[0].desc = &ep0_in_desc;
+ INIT_LIST_HEAD(&controller.ep[0].queue);
+ controller.ep[0].req_primed = false;
controller.gadget.ep0 = &controller.ep[0].ep;
INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
@@ -708,6 +766,8 @@ static int ci_udc_probe(void)
for (i = 1; i < NUM_ENDPOINTS; i++) {
memcpy(&controller.ep[i].ep, &ci_ep_init[1],
sizeof(*ci_ep_init));
+ INIT_LIST_HEAD(&controller.ep[i].queue);
+ controller.ep[i].req_primed = false;
list_add_tail(&controller.ep[i].ep.ep_list,
&controller.gadget.ep_list);
}
diff --git a/drivers/usb/gadget/ci_udc.h b/drivers/usb/gadget/ci_udc.h
index 4425fd9..23cff56 100644
--- a/drivers/usb/gadget/ci_udc.h
+++ b/drivers/usb/gadget/ci_udc.h
@@ -77,15 +77,22 @@ struct ci_udc {
#define CTRL_TXT_BULK (2 << 18)
#define CTRL_RXT_BULK (2 << 2)
+struct ci_req {
+ struct usb_request req;
+ struct list_head queue;
+ /* Bounce buffer allocated if needed to align the transfer */
+ uint8_t *b_buf;
+ uint32_t b_len;
+ /* Buffer for the current transfer. Either req.buf/len or b_buf/len */
+ uint8_t *hw_buf;
+ uint32_t hw_len;
+};
+
struct ci_ep {
struct usb_ep ep;
struct list_head queue;
+ bool req_primed;
const struct usb_endpoint_descriptor *desc;
-
- struct usb_request req;
- uint8_t *b_buf;
- uint32_t b_len;
- uint8_t b_fast[64] __aligned(ARCH_DMA_MINALIGN);
};
struct ci_drv {
diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c
index 1b1e179..859fe82 100644
--- a/drivers/usb/gadget/f_dfu.c
+++ b/drivers/usb/gadget/f_dfu.c
@@ -175,10 +175,17 @@ static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req)
req->length, f_dfu->blk_seq_num);
}
+static inline int dfu_get_manifest_timeout(struct dfu_entity *dfu)
+{
+ return dfu->poll_timeout ? dfu->poll_timeout(dfu) :
+ DFU_MANIFEST_POLL_TIMEOUT;
+}
+
static void handle_getstatus(struct usb_request *req)
{
struct dfu_status *dstat = (struct dfu_status *)req->buf;
struct f_dfu *f_dfu = req->context;
+ struct dfu_entity *dfu = dfu_get_entity(f_dfu->altsetting);
dfu_set_poll_timeout(dstat, 0);
@@ -191,7 +198,8 @@ static void handle_getstatus(struct usb_request *req)
f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
break;
case DFU_STATE_dfuMANIFEST:
- dfu_set_poll_timeout(dstat, DFU_MANIFEST_POLL_TIMEOUT);
+ dfu_set_poll_timeout(dstat, dfu_get_manifest_timeout(dfu));
+ break;
default:
break;
}
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
new file mode 100644
index 0000000..9dd85b6
--- /dev/null
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -0,0 +1,513 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/compiler.h>
+#include <version.h>
+#include <g_dnl.h>
+
+#define FASTBOOT_VERSION "0.4"
+
+#define FASTBOOT_INTERFACE_CLASS 0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
+#define FASTBOOT_INTERFACE_PROTOCOL 0x03
+
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+
+/* The 64 defined bytes plus \0 */
+#define RESPONSE_LEN (64 + 1)
+
+#define EP_BUFFER_SIZE 4096
+
+struct f_fastboot {
+ struct usb_function usb_function;
+
+ /* IN/OUT EP's and correspoinding requests */
+ struct usb_ep *in_ep, *out_ep;
+ struct usb_request *in_req, *out_req;
+};
+
+static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
+{
+ return container_of(f, struct f_fastboot, usb_function);
+}
+
+static struct f_fastboot *fastboot_func;
+static unsigned int download_size;
+static unsigned int download_bytes;
+
+static struct usb_endpoint_descriptor fs_ep_in = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+ .bInterval = 0x00,
+};
+
+static struct usb_endpoint_descriptor fs_ep_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
+ .bInterval = 0x00,
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
+ .bInterval = 0x00,
+};
+
+static struct usb_interface_descriptor interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x02,
+ .bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
+ .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
+ .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
+};
+
+static struct usb_descriptor_header *fb_runtime_descs[] = {
+ (struct usb_descriptor_header *)&interface_desc,
+ (struct usb_descriptor_header *)&fs_ep_in,
+ (struct usb_descriptor_header *)&hs_ep_out,
+ NULL,
+};
+
+/*
+ * static strings, in UTF-8
+ */
+static const char fastboot_name[] = "Android Fastboot";
+
+static struct usb_string fastboot_string_defs[] = {
+ [0].s = fastboot_name,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_fastboot = {
+ .language = 0x0409, /* en-us */
+ .strings = fastboot_string_defs,
+};
+
+static struct usb_gadget_strings *fastboot_strings[] = {
+ &stringtab_fastboot,
+ NULL,
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+
+static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ int status = req->status;
+ if (!status)
+ return;
+ printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+}
+
+static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ int id;
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct f_fastboot *f_fb = func_to_fastboot(f);
+
+ /* DYNAMIC interface numbers assignments */
+ id = usb_interface_id(c, f);
+ if (id < 0)
+ return id;
+ interface_desc.bInterfaceNumber = id;
+
+ id = usb_string_id(c->cdev);
+ if (id < 0)
+ return id;
+ fastboot_string_defs[0].id = id;
+ interface_desc.iInterface = id;
+
+ f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
+ if (!f_fb->in_ep)
+ return -ENODEV;
+ f_fb->in_ep->driver_data = c->cdev;
+
+ f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
+ if (!f_fb->out_ep)
+ return -ENODEV;
+ f_fb->out_ep->driver_data = c->cdev;
+
+ hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+
+ return 0;
+}
+
+static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ memset(fastboot_func, 0, sizeof(*fastboot_func));
+}
+
+static void fastboot_disable(struct usb_function *f)
+{
+ struct f_fastboot *f_fb = func_to_fastboot(f);
+
+ usb_ep_disable(f_fb->out_ep);
+ usb_ep_disable(f_fb->in_ep);
+
+ if (f_fb->out_req) {
+ free(f_fb->out_req->buf);
+ usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
+ f_fb->out_req = NULL;
+ }
+ if (f_fb->in_req) {
+ free(f_fb->in_req->buf);
+ usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
+ f_fb->in_req = NULL;
+ }
+}
+
+static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, 0);
+ if (!req)
+ return NULL;
+
+ req->length = EP_BUFFER_SIZE;
+ req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+
+ memset(req->buf, 0, req->length);
+ return req;
+}
+
+static int fastboot_set_alt(struct usb_function *f,
+ unsigned interface, unsigned alt)
+{
+ int ret;
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
+ struct f_fastboot *f_fb = func_to_fastboot(f);
+
+ debug("%s: func: %s intf: %d alt: %d\n",
+ __func__, f->name, interface, alt);
+
+ /* make sure we don't enable the ep twice */
+ if (gadget->speed == USB_SPEED_HIGH)
+ ret = usb_ep_enable(f_fb->out_ep, &hs_ep_out);
+ else
+ ret = usb_ep_enable(f_fb->out_ep, &fs_ep_out);
+ if (ret) {
+ puts("failed to enable out ep\n");
+ return ret;
+ }
+
+ f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
+ if (!f_fb->out_req) {
+ puts("failed to alloc out req\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ f_fb->out_req->complete = rx_handler_command;
+
+ ret = usb_ep_enable(f_fb->in_ep, &fs_ep_in);
+ if (ret) {
+ puts("failed to enable in ep\n");
+ goto err;
+ }
+
+ f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
+ if (!f_fb->in_req) {
+ puts("failed alloc req in\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ f_fb->in_req->complete = fastboot_complete;
+
+ ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ fastboot_disable(f);
+ return ret;
+}
+
+static int fastboot_add(struct usb_configuration *c)
+{
+ struct f_fastboot *f_fb = fastboot_func;
+ int status;
+
+ debug("%s: cdev: 0x%p\n", __func__, c->cdev);
+
+ if (!f_fb) {
+ f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
+ if (!f_fb)
+ return -ENOMEM;
+
+ fastboot_func = f_fb;
+ memset(f_fb, 0, sizeof(*f_fb));
+ }
+
+ f_fb->usb_function.name = "f_fastboot";
+ f_fb->usb_function.hs_descriptors = fb_runtime_descs;
+ f_fb->usb_function.bind = fastboot_bind;
+ f_fb->usb_function.unbind = fastboot_unbind;
+ f_fb->usb_function.set_alt = fastboot_set_alt;
+ f_fb->usb_function.disable = fastboot_disable;
+ f_fb->usb_function.strings = fastboot_strings;
+
+ status = usb_add_function(c, &f_fb->usb_function);
+ if (status) {
+ free(f_fb);
+ fastboot_func = f_fb;
+ }
+
+ return status;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+ struct usb_request *in_req = fastboot_func->in_req;
+ int ret;
+
+ memcpy(in_req->buf, buffer, buffer_size);
+ in_req->length = buffer_size;
+ ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
+ if (ret)
+ printf("Error %d on queue\n", ret);
+ return 0;
+}
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+ return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+ fastboot_func->in_req->complete = compl_do_reset;
+ fastboot_tx_write_str("OKAY");
+}
+
+static int strcmp_l1(const char *s1, const char *s2)
+{
+ if (!s1 || !s2)
+ return -1;
+ return strncmp(s1, s2, strlen(s1));
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+ char response[RESPONSE_LEN];
+ const char *s;
+
+ strcpy(response, "OKAY");
+ strsep(&cmd, ":");
+ if (!cmd) {
+ fastboot_tx_write_str("FAILmissing var");
+ return;
+ }
+
+ if (!strcmp_l1("version", cmd)) {
+ strncat(response, FASTBOOT_VERSION, sizeof(response));
+ } else if (!strcmp_l1("bootloader-version", cmd)) {
+ strncat(response, U_BOOT_VERSION, sizeof(response));
+ } else if (!strcmp_l1("downloadsize", cmd)) {
+ char str_num[12];
+
+ sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
+ strncat(response, str_num, sizeof(response));
+ } else if (!strcmp_l1("serialno", cmd)) {
+ s = getenv("serial#");
+ if (s)
+ strncat(response, s, sizeof(response));
+ else
+ strcpy(response, "FAILValue not set");
+ } else {
+ strcpy(response, "FAILVariable not implemented");
+ }
+ fastboot_tx_write_str(response);
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+ int rx_remain = download_size - download_bytes;
+ if (rx_remain < 0)
+ return 0;
+ if (rx_remain > EP_BUFFER_SIZE)
+ return EP_BUFFER_SIZE;
+ return rx_remain;
+}
+
+#define BYTES_PER_DOT 0x20000
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+ char response[RESPONSE_LEN];
+ unsigned int transfer_size = download_size - download_bytes;
+ const unsigned char *buffer = req->buf;
+ unsigned int buffer_size = req->actual;
+
+ if (req->status != 0) {
+ printf("Bad status: %d\n", req->status);
+ return;
+ }
+
+ if (buffer_size < transfer_size)
+ transfer_size = buffer_size;
+
+ memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
+ buffer, transfer_size);
+
+ download_bytes += transfer_size;
+
+ /* Check if transfer is done */
+ if (download_bytes >= download_size) {
+ /*
+ * Reset global transfer variable, keep download_bytes because
+ * it will be used in the next possible flashing command
+ */
+ download_size = 0;
+ req->complete = rx_handler_command;
+ req->length = EP_BUFFER_SIZE;
+
+ sprintf(response, "OKAY");
+ fastboot_tx_write_str(response);
+
+ printf("\ndownloading of %d bytes finished\n", download_bytes);
+ } else {
+ req->length = rx_bytes_expected();
+ if (req->length < ep->maxpacket)
+ req->length = ep->maxpacket;
+ }
+
+ if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
+ putc('.');
+ if (!(download_bytes % (74 * BYTES_PER_DOT)))
+ putc('\n');
+ }
+ req->actual = 0;
+ usb_ep_queue(ep, req, 0);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+ char response[RESPONSE_LEN];
+
+ strsep(&cmd, ":");
+ download_size = simple_strtoul(cmd, NULL, 16);
+ download_bytes = 0;
+
+ printf("Starting download of %d bytes\n", download_size);
+
+ if (0 == download_size) {
+ sprintf(response, "FAILdata invalid size");
+ } else if (download_size > CONFIG_USB_FASTBOOT_BUF_SIZE) {
+ download_size = 0;
+ sprintf(response, "FAILdata too large");
+ } else {
+ sprintf(response, "DATA%08x", download_size);
+ req->complete = rx_handler_dl_image;
+ req->length = rx_bytes_expected();
+ if (req->length < ep->maxpacket)
+ req->length = ep->maxpacket;
+ }
+ fastboot_tx_write_str(response);
+}
+
+static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ char boot_addr_start[12];
+ char *bootm_args[] = { "bootm", boot_addr_start, NULL };
+
+ puts("Booting kernel..\n");
+
+ sprintf(boot_addr_start, "0x%lx", load_addr);
+ do_bootm(NULL, 0, 2, bootm_args);
+
+ /* This only happens if image is somehow faulty so we start over */
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+ fastboot_func->in_req->complete = do_bootm_on_complete;
+ fastboot_tx_write_str("OKAY");
+}
+
+struct cmd_dispatch_info {
+ char *cmd;
+ void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
+ {
+ .cmd = "reboot",
+ .cb = cb_reboot,
+ }, {
+ .cmd = "getvar:",
+ .cb = cb_getvar,
+ }, {
+ .cmd = "download:",
+ .cb = cb_download,
+ }, {
+ .cmd = "boot",
+ .cb = cb_boot,
+ },
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmdbuf = req->buf;
+ void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+ if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
+ func_cb = cmd_dispatch_info[i].cb;
+ break;
+ }
+ }
+
+ if (!func_cb)
+ fastboot_tx_write_str("FAILunknown command");
+ else
+ func_cb(ep, req);
+
+ if (req->status == 0) {
+ *cmdbuf = '\0';
+ req->actual = 0;
+ usb_ep_queue(ep, req, 0);
+ }
+}
diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c
index feef9e4..28f215e 100644
--- a/drivers/usb/gadget/f_thor.c
+++ b/drivers/usb/gadget/f_thor.c
@@ -219,21 +219,15 @@ static int download_tail(long long int left, int cnt)
}
/*
- * To store last "packet" DFU storage backend requires dfu_write with
- * size parameter equal to 0
+ * To store last "packet" or write file from buffer to filesystem
+ * DFU storage backend requires dfu_flush
*
* This also frees memory malloc'ed by dfu_get_buf(), so no explicit
* need fo call dfu_free_buf() is needed.
*/
- ret = dfu_write(dfu_entity, transfer_buffer, 0, cnt);
- if (ret)
- error("DFU write failed [%d] cnt: %d", ret, cnt);
-
ret = dfu_flush(dfu_entity, transfer_buffer, 0, cnt);
- if (ret) {
+ if (ret)
error("DFU flush failed!");
- return ret;
- }
return ret;
}
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 7430074..02803df 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -311,11 +311,7 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
/* Number of buffers we will use. 2 is enough for double-buffering */
-#ifndef CONFIG_CI_UDC
#define FSG_NUM_BUFFERS 2
-#else
-#define FSG_NUM_BUFFERS 1 /* ci_udc only allows 1 req per ep at present */
-#endif
/* Default size of buffer length. */
#define FSG_BUFLEN ((u32)16384)
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index b301e28..7211c6a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
+obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
# xhci
obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 38db18e..33e5ea9 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -69,6 +69,7 @@ struct fdt_usb {
unsigned enabled:1; /* 1 to enable, 0 to disable */
unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */
unsigned initialized:1; /* has this port already been initialized? */
+ enum usb_init_type init_type;
enum dr_mode dr_mode; /* dual role mode */
enum periph_id periph_id;/* peripheral id */
struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */
@@ -237,29 +238,31 @@ int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
return PORTSC_PSPD(reg);
}
-/* Put the port into host mode */
-static void set_host_mode(struct fdt_usb *config)
+/* Set up VBUS for host/device mode */
+static void set_up_vbus(struct fdt_usb *config, enum usb_init_type init)
{
/*
- * If we are an OTG port, check if remote host is driving VBus and
- * bail out in this case.
+ * If we are an OTG port initializing in host mode,
+ * check if remote host is driving VBus and bail out in this case.
*/
- if (config->dr_mode == DR_MODE_OTG &&
- (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS))
+ if (init == USB_INIT_HOST &&
+ config->dr_mode == DR_MODE_OTG &&
+ (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS)) {
+ printf("tegrausb: VBUS input active; not enabling as host\n");
return;
+ }
- /*
- * If not driving, we set the GPIO to enable VBUS. We assume
- * that the pinmux is set up correctly for this.
- */
if (fdt_gpio_isvalid(&config->vbus_gpio)) {
+ int vbus_value;
+
fdtdec_setup_gpio(&config->vbus_gpio);
- gpio_direction_output(config->vbus_gpio.gpio,
- (config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW) ?
- 0 : 1);
- debug("set_host_mode: GPIO %d %s\n", config->vbus_gpio.gpio,
- (config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW) ?
- "low" : "high");
+
+ vbus_value = (init == USB_INIT_HOST) ^
+ !!(config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW);
+ gpio_direction_output(config->vbus_gpio.gpio, vbus_value);
+
+ debug("set_up_vbus: GPIO %d %d\n", config->vbus_gpio.gpio,
+ vbus_value);
}
}
@@ -293,10 +296,44 @@ static const unsigned *get_pll_timing(void)
return timing;
}
+/* select the PHY to use with a USB controller */
+static void init_phy_mux(struct fdt_usb *config, uint pts,
+ enum usb_init_type init)
+{
+ struct usb_ctlr *usbctlr = config->reg;
+
+#if defined(CONFIG_TEGRA20)
+ if (config->periph_id == PERIPH_ID_USBD) {
+ clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK,
+ PTS_UTMI << PTS1_SHIFT);
+ clrbits_le32(&usbctlr->port_sc1, STS1);
+ } else {
+ clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
+ PTS_UTMI << PTS_SHIFT);
+ clrbits_le32(&usbctlr->port_sc1, STS);
+ }
+#else
+ /* Set to Host mode (if applicable) after Controller Reset was done */
+ clrsetbits_le32(&usbctlr->usb_mode, USBMODE_CM_HC,
+ (init == USB_INIT_HOST) ? USBMODE_CM_HC : 0);
+ /*
+ * Select PHY interface after setting host mode.
+ * For device mode, the ordering requirement is not an issue, since
+ * only the first USB controller supports device mode, and that USB
+ * controller can only talk to a UTMI PHY, so the PHY selection is
+ * already made at reset time, so this write is a no-op.
+ */
+ clrsetbits_le32(&usbctlr->hostpc1_devlc, PTS_MASK,
+ pts << PTS_SHIFT);
+ clrbits_le32(&usbctlr->hostpc1_devlc, STS);
+#endif
+}
+
/* set up the UTMI USB controller with the parameters provided */
-static int init_utmi_usb_controller(struct fdt_usb *config)
+static int init_utmi_usb_controller(struct fdt_usb *config,
+ enum usb_init_type init)
{
- u32 val;
+ u32 b_sess_valid_mask, val;
int loop_count;
const unsigned *timing;
struct usb_ctlr *usbctlr = config->reg;
@@ -314,6 +351,10 @@ static int init_utmi_usb_controller(struct fdt_usb *config)
/* Follow the crystal clock disable by >100ns delay */
udelay(1);
+ b_sess_valid_mask = (VBUS_B_SESS_VLD_SW_VALUE | VBUS_B_SESS_VLD_SW_EN);
+ clrsetbits_le32(&usbctlr->phy_vbus_sensors, b_sess_valid_mask,
+ (init == USB_INIT_DEVICE) ? b_sess_valid_mask : 0);
+
/*
* To Use the A Session Valid for cable detection logic, VBUS_WAKEUP
* mux must be switched to actually use a_sess_vld threshold.
@@ -485,21 +526,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config)
clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
/* Select UTMI parallel interface */
-#if defined(CONFIG_TEGRA20)
- if (config->periph_id == PERIPH_ID_USBD) {
- clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK,
- PTS_UTMI << PTS1_SHIFT);
- clrbits_le32(&usbctlr->port_sc1, STS1);
- } else {
- clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
- PTS_UTMI << PTS_SHIFT);
- clrbits_le32(&usbctlr->port_sc1, STS);
- }
-#else
- clrsetbits_le32(&usbctlr->hostpc1_devlc, PTS_MASK,
- PTS_UTMI << PTS_SHIFT);
- clrbits_le32(&usbctlr->hostpc1_devlc, STS);
-#endif
+ init_phy_mux(config, PTS_UTMI, init);
/* Deassert power down state */
clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_FORCE_PD_POWERDOWN |
@@ -529,7 +556,8 @@ static int init_utmi_usb_controller(struct fdt_usb *config)
#endif
/* set up the ULPI USB controller with the parameters provided */
-static int init_ulpi_usb_controller(struct fdt_usb *config)
+static int init_ulpi_usb_controller(struct fdt_usb *config,
+ enum usb_init_type init)
{
u32 val;
int loop_count;
@@ -557,13 +585,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config)
ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP);
/* Select ULPI parallel interface */
-#if defined(CONFIG_TEGRA20)
- clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
- PTS_ULPI << PTS_SHIFT);
-#else
- clrsetbits_le32(&usbctlr->hostpc1_devlc, PTS_MASK,
- PTS_ULPI << PTS_SHIFT);
-#endif
+ init_phy_mux(config, PTS_ULPI, init);
/* enable ULPI transceiver */
setbits_le32(&usbctlr->susp_ctrl, ULPI_PHY_ENB);
@@ -612,7 +634,8 @@ static int init_ulpi_usb_controller(struct fdt_usb *config)
return 0;
}
#else
-static int init_ulpi_usb_controller(struct fdt_usb *config)
+static int init_ulpi_usb_controller(struct fdt_usb *config,
+ enum usb_init_type init)
{
printf("No code to set up ULPI controller, please enable"
"CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT");
@@ -765,42 +788,66 @@ int ehci_hcd_init(int index, enum usb_init_type init,
config = &port[index];
+ switch (init) {
+ case USB_INIT_HOST:
+ switch (config->dr_mode) {
+ case DR_MODE_HOST:
+ case DR_MODE_OTG:
+ break;
+ default:
+ printf("tegrausb: Invalid dr_mode %d for host mode\n",
+ config->dr_mode);
+ return -1;
+ }
+ break;
+ case USB_INIT_DEVICE:
+ if (config->periph_id != PERIPH_ID_USBD) {
+ printf("tegrausb: Device mode only supported on first USB controller\n");
+ return -1;
+ }
+ if (!config->utmi) {
+ printf("tegrausb: Device mode only supported with UTMI PHY\n");
+ return -1;
+ }
+ switch (config->dr_mode) {
+ case DR_MODE_DEVICE:
+ case DR_MODE_OTG:
+ break;
+ default:
+ printf("tegrausb: Invalid dr_mode %d for device mode\n",
+ config->dr_mode);
+ return -1;
+ }
+ break;
+ default:
+ printf("tegrausb: Unknown USB_INIT_* %d\n", init);
+ return -1;
+ }
+
/* skip init, if the port is already initialized */
- if (config->initialized)
+ if (config->initialized && config->init_type == init)
goto success;
- if (config->utmi && init_utmi_usb_controller(config)) {
+ if (config->utmi && init_utmi_usb_controller(config, init)) {
printf("tegrausb: Cannot init port %d\n", index);
return -1;
}
- if (config->ulpi && init_ulpi_usb_controller(config)) {
+ if (config->ulpi && init_ulpi_usb_controller(config, init)) {
printf("tegrausb: Cannot init port %d\n", index);
return -1;
}
- set_host_mode(config);
+ set_up_vbus(config, init);
config->initialized = 1;
+ config->init_type = init;
success:
usbctlr = config->reg;
*hccr = (struct ehci_hccr *)&usbctlr->cap_length;
*hcor = (struct ehci_hcor *)&usbctlr->usb_cmd;
- if (controller->has_hostpc) {
- /* Set to Host mode after Controller Reset was done */
- clrsetbits_le32(&usbctlr->usb_mode, USBMODE_CM_HC,
- USBMODE_CM_HC);
- /* Select UTMI parallel interface after setting host mode */
- if (config->utmi) {
- clrsetbits_le32((char *)&usbctlr->usb_cmd +
- HOSTPC1_DEVLC, PTS_MASK,
- PTS_UTMI << PTS_SHIFT);
- clrbits_le32((char *)&usbctlr->usb_cmd +
- HOSTPC1_DEVLC, STS);
- }
- }
return 0;
}
diff --git a/drivers/usb/host/ehci-zynq.c b/drivers/usb/host/ehci-zynq.c
new file mode 100644
index 0000000..7770d05
--- /dev/null
+++ b/drivers/usb/host/ehci-zynq.c
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2014, Xilinx, Inc
+ *
+ * USB Low level initialization(Specific to zynq)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/ehci-fsl.h>
+#include <usb/ulpi.h>
+
+#include "ehci.h"
+
+#define ZYNQ_USB_USBCMD_RST 0x0000002
+#define ZYNQ_USB_USBCMD_STOP 0x0000000
+#define ZYNQ_USB_NUM_MIO 12
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
+ struct ehci_hcor **hcor)
+{
+ struct usb_ehci *ehci;
+ struct ulpi_viewport ulpi_vp;
+ int ret, mio_usb;
+ /* Used for writing the ULPI data address */
+ struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+ if (!index) {
+ mio_usb = zynq_slcr_get_mio_pin_status("usb0");
+ if (mio_usb != ZYNQ_USB_NUM_MIO) {
+ printf("usb0 wrong num MIO: %d, Index %d\n", mio_usb,
+ index);
+ return -1;
+ }
+ ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR0;
+ } else {
+ mio_usb = zynq_slcr_get_mio_pin_status("usb1");
+ if (mio_usb != ZYNQ_USB_NUM_MIO) {
+ printf("usb1 wrong num MIO: %d, Index %d\n", mio_usb,
+ index);
+ return -1;
+ }
+ ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR1;
+ }
+
+ *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+ *hcor = (struct ehci_hcor *)((uint32_t) *hccr +
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+ ulpi_vp.viewport_addr = (u32)&ehci->ulpi_viewpoint;
+ ulpi_vp.port_num = 0;
+
+ ret = ulpi_init(&ulpi_vp);
+ if (ret) {
+ puts("zynq ULPI viewport init failed\n");
+ return -1;
+ }
+
+ /* ULPI set flags */
+ ulpi_write(&ulpi_vp, &ulpi->otg_ctrl,
+ ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN |
+ ULPI_OTG_EXTVBUSIND);
+ ulpi_write(&ulpi_vp, &ulpi->function_ctrl,
+ ULPI_FC_FULL_SPEED | ULPI_FC_OPMODE_NORMAL |
+ ULPI_FC_SUSPENDM);
+ ulpi_write(&ulpi_vp, &ulpi->iface_ctrl, 0);
+
+ /* Set VBus */
+ ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set,
+ ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+ struct usb_ehci *ehci;
+
+ if (!index)
+ ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR0;
+ else
+ ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR1;
+
+ /* Stop controller */
+ writel(ZYNQ_USB_USBCMD_STOP, &ehci->usbcmd);
+ udelay(1000);
+
+ /* Initiate controller reset */
+ writel(ZYNQ_USB_USBCMD_RST, &ehci->usbcmd);
+
+ return 0;
+}
diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c
index 6599d38..8c3b0a1 100644
--- a/drivers/usb/musb-new/musb_gadget_ep0.c
+++ b/drivers/usb/musb-new/musb_gadget_ep0.c
@@ -576,6 +576,10 @@ static void ep0_txstate(struct musb *musb)
} else
request = NULL;
+ /* send it out, triggering a "txpktrdy cleared" irq */
+ musb_ep_select(musb->mregs, 0);
+ musb_writew(regs, MUSB_CSR0, csr);
+
/* report completions as soon as the fifo's loaded; there's no
* win in waiting till this last packet gets acked. (other than
* very precise fault reporting, needed by USB TMC; possible with
@@ -588,10 +592,6 @@ static void ep0_txstate(struct musb *musb)
return;
musb->ackpend = 0;
}
-
- /* send it out, triggering a "txpktrdy cleared" irq */
- musb_ep_select(musb->mregs, 0);
- musb_writew(regs, MUSB_CSR0, csr);
}
/*
diff --git a/include/android_image.h b/include/android_image.h
new file mode 100644
index 0000000..094d60a
--- /dev/null
+++ b/include/android_image.h
@@ -0,0 +1,69 @@
+/*
+ * This is from the Android Project,
+ * Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
+ * File: include/boot/bootimg.h
+ * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _ANDROID_IMAGE_H_
+#define _ANDROID_IMAGE_H_
+
+#define ANDR_BOOT_MAGIC "ANDROID!"
+#define ANDR_BOOT_MAGIC_SIZE 8
+#define ANDR_BOOT_NAME_SIZE 16
+#define ANDR_BOOT_ARGS_SIZE 512
+
+struct andr_img_hdr {
+ char magic[ANDR_BOOT_MAGIC_SIZE];
+
+ u32 kernel_size; /* size in bytes */
+ u32 kernel_addr; /* physical load addr */
+
+ u32 ramdisk_size; /* size in bytes */
+ u32 ramdisk_addr; /* physical load addr */
+
+ u32 second_size; /* size in bytes */
+ u32 second_addr; /* physical load addr */
+
+ u32 tags_addr; /* physical addr for kernel tags */
+ u32 page_size; /* flash page size we assume */
+ u32 unused[2]; /* future expansion: should be 0 */
+
+ char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
+
+ char cmdline[ANDR_BOOT_ARGS_SIZE];
+
+ u32 id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+/*
+ * +-----------------+
+ * | boot header | 1 page
+ * +-----------------+
+ * | kernel | n pages
+ * +-----------------+
+ * | ramdisk | m pages
+ * +-----------------+
+ * | second stage | o pages
+ * +-----------------+
+ *
+ * n = (kernel_size + page_size - 1) / page_size
+ * m = (ramdisk_size + page_size - 1) / page_size
+ * o = (second_size + page_size - 1) / page_size
+ *
+ * 0. all entities are page_size aligned in flash
+ * 1. kernel and ramdisk are required (size != 0)
+ * 2. second is optional (second_size == 0 -> no second)
+ * 3. load each element (kernel, ramdisk, second) at
+ * the specified physical address (kernel_addr, etc)
+ * 4. prepare tags at tag_addr. kernel_args[] is
+ * appended to the kernel commandline in the tags.
+ * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+ * 6. if second_size != 0: jump to second_addr
+ * else: jump to kernel_addr
+ */
+#endif
diff --git a/include/common.h b/include/common.h
index 13e5dc7..232136c 100644
--- a/include/common.h
+++ b/include/common.h
@@ -836,7 +836,7 @@ int ctrlc (void);
int had_ctrlc (void); /* have we had a Control-C since last clear? */
void clear_ctrlc (void); /* clear the Control-C condition */
int disable_ctrlc (int); /* 1 to disable, 0 to enable Control-C detect */
-
+int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */
/*
* STDIO based functions (can always be used)
*/
diff --git a/include/configs/GEN860T.h b/include/configs/GEN860T.h
index 2822a08..fd6c976 100644
--- a/include/configs/GEN860T.h
+++ b/include/configs/GEN860T.h
@@ -219,6 +219,7 @@
#define CONFIG_CMD_ELF
#define CONFIG_CMD_DATE
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_MII
#define CONFIG_CMD_BEDBUG
diff --git a/include/configs/MVBC_P.h b/include/configs/MVBC_P.h
index 036396c..1ab2b3d 100644
--- a/include/configs/MVBC_P.h
+++ b/include/configs/MVBC_P.h
@@ -89,6 +89,7 @@
#define CONFIG_CMD_SDRAM
#define CONFIG_CMD_PCI
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_I2C
#undef CONFIG_WATCHDOG
diff --git a/include/configs/MVBLM7.h b/include/configs/MVBLM7.h
index 27c2fa0..1ee4d7c 100644
--- a/include/configs/MVBLM7.h
+++ b/include/configs/MVBLM7.h
@@ -267,6 +267,7 @@
#define CONFIG_CMD_PCI
#define CONFIG_CMD_I2C
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_USB
#define CONFIG_DOS_PARTITION
diff --git a/include/configs/MVSMR.h b/include/configs/MVSMR.h
index ad15506..27f730d 100644
--- a/include/configs/MVSMR.h
+++ b/include/configs/MVSMR.h
@@ -74,6 +74,7 @@
#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_I2C
#define CONFIG_CMD_MII
#define CONFIG_CMD_NET
diff --git a/include/configs/alpr.h b/include/configs/alpr.h
index 7849b22..2782e55 100644
--- a/include/configs/alpr.h
+++ b/include/configs/alpr.h
@@ -222,6 +222,7 @@
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_EEPROM
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_I2C
#undef CONFIG_CMD_LOADB
#undef CONFIG_CMD_LOADS
diff --git a/include/configs/astro_mcf5373l.h b/include/configs/astro_mcf5373l.h
index d875753..fa64a68 100644
--- a/include/configs/astro_mcf5373l.h
+++ b/include/configs/astro_mcf5373l.h
@@ -88,6 +88,7 @@
#define CONFIG_CMD_LOADS
#define CONFIG_CMD_LOADB
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMDLINE_EDITING
#define CONFIG_SYS_HUSH_PARSER
diff --git a/include/configs/balloon3.h b/include/configs/balloon3.h
index 5228ba6..2f5a660 100644
--- a/include/configs/balloon3.h
+++ b/include/configs/balloon3.h
@@ -54,6 +54,7 @@
#undef CONFIG_CMD_IMLS
#define CONFIG_CMD_USB
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#undef CONFIG_LCD
/*
diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h
index d1d732f..a1a63a0 100644
--- a/include/configs/coreboot.h
+++ b/include/configs/coreboot.h
@@ -167,6 +167,7 @@
#define CONFIG_CMD_ECHO
#undef CONFIG_CMD_FLASH
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_GPIO
#define CONFIG_CMD_IMI
#undef CONFIG_CMD_IMLS
diff --git a/include/configs/grsim.h b/include/configs/grsim.h
index 556c749..1e089a9 100644
--- a/include/configs/grsim.h
+++ b/include/configs/grsim.h
@@ -53,6 +53,7 @@
#define CONFIG_CMD_DIAG
#define CONFIG_CMD_ECHO /* echo arguments */
#define CONFIG_CMD_FPGA /* FPGA configuration Support */
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_IRQ
#define CONFIG_CMD_ITEST /* Integer (and string) test */
#define CONFIG_CMD_LOADB /* loadb */
diff --git a/include/configs/grsim_leon2.h b/include/configs/grsim_leon2.h
index 8be9898..66194a8 100644
--- a/include/configs/grsim_leon2.h
+++ b/include/configs/grsim_leon2.h
@@ -51,6 +51,7 @@
#define CONFIG_CMD_DIAG
#define CONFIG_CMD_ECHO /* echo arguments */
#define CONFIG_CMD_FPGA /* FPGA configuration Support */
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_IRQ
#define CONFIG_CMD_ITEST /* Integer (and string) test */
#define CONFIG_CMD_LOADB /* loadb */
diff --git a/include/configs/iocon.h b/include/configs/iocon.h
index f36c2a3..79c4736 100644
--- a/include/configs/iocon.h
+++ b/include/configs/iocon.h
@@ -62,7 +62,8 @@
* Commands additional to the ones defined in amcc-common.h
*/
#define CONFIG_CMD_CACHE
-#define CONFIG_CMD_FPGAD
+#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#undef CONFIG_CMD_EEPROM
/*
diff --git a/include/configs/kwb.h b/include/configs/kwb.h
index 0f631c0..0860434 100644
--- a/include/configs/kwb.h
+++ b/include/configs/kwb.h
@@ -109,7 +109,7 @@
#undef CONFIG_ENV_IS_NOWHERE
#define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_SYS_MMC_ENV_DEV 1
+#define CONFIG_SYS_MMC_ENV_DEV 0
#define CONFIG_SYS_MMC_ENV_PART 2
#define CONFIG_ENV_OFFSET 0x40000 /* TODO: Adresse definieren */
#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
diff --git a/include/configs/mt_ventoux.h b/include/configs/mt_ventoux.h
index e7afd07..01e395a 100644
--- a/include/configs/mt_ventoux.h
+++ b/include/configs/mt_ventoux.h
@@ -49,6 +49,7 @@
* FPGA
*/
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_FPGA
#define CONFIG_FPGA_XILINX
#define CONFIG_FPGA_SPARTAN3
diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h
index d07e52d..0a7df60 100644
--- a/include/configs/omap3_beagle.h
+++ b/include/configs/omap3_beagle.h
@@ -66,6 +66,16 @@
#define CONFIG_TWL4030_USB 1
#define CONFIG_USB_ETHER
#define CONFIG_USB_ETHER_RNDIS
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_VBUS_DRAW 0
+#define CONFIG_USBDOWNLOAD_GADGET
+#define CONFIG_G_DNL_VENDOR_NUM 0x0451
+#define CONFIG_G_DNL_PRODUCT_NUM 0xd022
+#define CONFIG_G_DNL_MANUFACTURER "TI"
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_ANDROID_BOOT_IMAGE
+#define CONFIG_USB_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR
+#define CONFIG_USB_FASTBOOT_BUF_SIZE 0x07000000
/* USB EHCI */
#define CONFIG_CMD_USB
diff --git a/include/configs/omap3_mvblx.h b/include/configs/omap3_mvblx.h
index 8d11010..a3dcb15 100644
--- a/include/configs/omap3_mvblx.h
+++ b/include/configs/omap3_mvblx.h
@@ -127,6 +127,7 @@
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_PING
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_SYS_I2C
#define CONFIG_SYS_OMAP24_I2C_SPEED 100000
diff --git a/include/configs/tseries.h b/include/configs/tseries.h
index 8fb87ac..e550afa 100644
--- a/include/configs/tseries.h
+++ b/include/configs/tseries.h
@@ -237,7 +237,7 @@
#elif defined(CONFIG_EMMC_BOOT)
#undef CONFIG_ENV_IS_NOWHERE
#define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_SYS_MMC_ENV_DEV 1
+#define CONFIG_SYS_MMC_ENV_DEV 0
#define CONFIG_SYS_MMC_ENV_PART 2
#define CONFIG_ENV_OFFSET 0x40000 /* TODO: Adresse definieren */
#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
diff --git a/include/configs/x600.h b/include/configs/x600.h
index 7405419..eae85d6 100644
--- a/include/configs/x600.h
+++ b/include/configs/x600.h
@@ -107,6 +107,7 @@
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_ENV
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
#define CONFIG_CMD_GPIO
#define CONFIG_CMD_I2C
#define CONFIG_CMD_MEMORY
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h
index 731e69b..dc5bc22 100644
--- a/include/configs/zynq-common.h
+++ b/include/configs/zynq-common.h
@@ -83,10 +83,27 @@
# define CONFIG_SDHCI
# define CONFIG_ZYNQ_SDHCI
# define CONFIG_CMD_MMC
-# define CONFIG_CMD_FAT
+#endif
+
+#ifdef CONFIG_ZYNQ_USB
+# define CONFIG_USB_EHCI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+# define CONFIG_USB_EHCI_ZYNQ
+# define CONFIG_USB_ULPI_VIEWPORT
+# define CONFIG_USB_ULPI
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_USB_MAX_CONTROLLER_COUNT 2
+#endif
+
+#if defined(CONFIG_ZYNQ_SDHCI) || defined(CONFIG_ZYNQ_USB)
# define CONFIG_SUPPORT_VFAT
+# define CONFIG_CMD_FAT
# define CONFIG_CMD_EXT2
+# define CONFIG_FAT_WRITE
# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_EXT4
+# define CONFIG_CMD_EXT4_WRITE
#endif
#define CONFIG_SYS_I2C_ZYNQ
@@ -150,7 +167,13 @@
"bootm ${load_addr}\0" \
"jtagboot=echo TFTPing FIT to RAM... && " \
"tftpboot ${load_addr} ${fit_image} && " \
- "bootm ${load_addr}\0"
+ "bootm ${load_addr}\0" \
+ "usbboot=if usb start; then " \
+ "echo Copying FIT from USB to RAM... && " \
+ "fatload usb 0 ${load_addr} ${fit_image} && " \
+ "bootm ${load_addr}\0" \
+ "fi\0"
+
#define CONFIG_BOOTCOMMAND "run $modeboot"
#define CONFIG_BOOTDELAY 3 /* -1 to Disable autoboot */
#define CONFIG_SYS_LOAD_ADDR 0 /* default? */
@@ -165,7 +188,7 @@
#define CONFIG_SYS_LONGHELP
#define CONFIG_CLOCKS
#define CONFIG_CMD_CLK
-#define CONFIG_SYS_MAXARGS 15 /* max number of command args */
+#define CONFIG_SYS_MAXARGS 32 /* max number of command args */
#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */
#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
sizeof(CONFIG_SYS_PROMPT) + 16)
@@ -191,6 +214,10 @@
#define CONFIG_FPGA_XILINX
#define CONFIG_FPGA_ZYNQPL
#define CONFIG_CMD_FPGA
+#define CONFIG_CMD_FPGA_LOADMK
+#define CONFIG_CMD_FPGA_LOADP
+#define CONFIG_CMD_FPGA_LOADBP
+#define CONFIG_CMD_FPGA_LOADFS
/* Open Firmware flat tree */
#define CONFIG_OF_LIBFDT
@@ -209,7 +236,7 @@
#define CONFIG_RSA
/* Extend size of kernel image for uncompression */
-#define CONFIG_SYS_BOOTM_LEN (20 * 1024 * 1024)
+#define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024)
/* Boot FreeBSD/vxWorks from an ELF image */
#if defined(CONFIG_ZYNQ_BOOT_FREEBSD)
@@ -235,16 +262,10 @@
#define CONFIG_SPL_LIBCOMMON_SUPPORT
#define CONFIG_SPL_LIBGENERIC_SUPPORT
#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_BOARD_INIT
#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/zynq/u-boot-spl.lds"
-/* Disable dcache for SPL just for sure */
-#ifdef CONFIG_SPL_BUILD
-#define CONFIG_SYS_DCACHE_OFF
-#undef CONFIG_FPGA
-#undef CONFIG_OF_CONTROL
-#endif
-
/* MMC support */
#ifdef CONFIG_ZYNQ_SDHCI0
#define CONFIG_SPL_MMC_SUPPORT
@@ -253,7 +274,18 @@
#define CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION 1
#define CONFIG_SPL_LIBDISK_SUPPORT
#define CONFIG_SPL_FAT_SUPPORT
-#define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot.img"
+#if defined(CONFIG_OF_CONTROL) && defined(CONFIG_OF_SEPARATE)
+# define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot-dtb.img"
+#else
+# define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot.img"
+#endif
+#endif
+
+/* Disable dcache for SPL just for sure */
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_SYS_DCACHE_OFF
+#undef CONFIG_FPGA
+#undef CONFIG_OF_CONTROL
#endif
/* Address in RAM where the parameters must be copied by SPL. */
diff --git a/include/configs/zynq_zc70x.h b/include/configs/zynq_zc70x.h
index de0e241..291a5fe 100644
--- a/include/configs/zynq_zc70x.h
+++ b/include/configs/zynq_zc70x.h
@@ -19,6 +19,7 @@
#define CONFIG_SYS_NO_FLASH
#define CONFIG_ZYNQ_SDHCI0
+#define CONFIG_ZYNQ_USB
#define CONFIG_ZYNQ_I2C0
#define CONFIG_ZYNQ_EEPROM
#define CONFIG_ZYNQ_BOOT_FREEBSD
diff --git a/include/configs/zynq_zed.h b/include/configs/zynq_zed.h
index 274140c..ce17d40 100644
--- a/include/configs/zynq_zed.h
+++ b/include/configs/zynq_zed.h
@@ -18,6 +18,7 @@
#define CONFIG_SYS_NO_FLASH
+#define CONFIG_ZYNQ_USB
#define CONFIG_ZYNQ_SDHCI0
#define CONFIG_ZYNQ_BOOT_FREEBSD
#define CONFIG_DEFAULT_DEVICE_TREE zynq-zed
diff --git a/include/dfu.h b/include/dfu.h
index 2409168..26ffbc8 100644
--- a/include/dfu.h
+++ b/include/dfu.h
@@ -43,6 +43,9 @@ struct mmc_internal_data {
unsigned int lba_size;
unsigned int lba_blk_size;
+ /* eMMC HW partition access */
+ int hw_partition;
+
/* FAT/EXT */
unsigned int dev;
unsigned int part;
@@ -100,6 +103,7 @@ struct dfu_entity {
u64 offset, void *buf, long *len);
int (*flush_medium)(struct dfu_entity *dfu);
+ unsigned int (*poll_timeout)(struct dfu_entity *dfu);
struct list_head list;
diff --git a/include/fpga.h b/include/fpga.h
index 15e603a..914024c 100644
--- a/include/fpga.h
+++ b/include/fpga.h
@@ -35,13 +35,29 @@ typedef struct { /* typedef fpga_desc */
void *devdesc; /* real device descriptor */
} fpga_desc; /* end, typedef fpga_desc */
+typedef struct { /* typedef fpga_desc */
+ unsigned int blocksize;
+ char *interface;
+ char *dev_part;
+ char *filename;
+ int fstype;
+} fpga_fs_info;
+
+typedef enum {
+ BIT_FULL = 0,
+ BIT_PARTIAL,
+} bitstream_type;
/* root function definitions */
extern void fpga_init(void);
extern int fpga_add(fpga_type devtype, void *desc);
extern int fpga_count(void);
-extern int fpga_load(int devnum, const void *buf, size_t bsize);
-extern int fpga_loadbitstream(int devnum, char *fpgadata, size_t size);
+extern int fpga_load(int devnum, const void *buf, size_t bsize,
+ bitstream_type bstype);
+extern int fpga_fsload(int devnum, const void *buf, size_t size,
+ fpga_fs_info *fpga_fsinfo);
+extern int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype);
extern int fpga_dump(int devnum, const void *buf, size_t bsize);
extern int fpga_info(int devnum);
extern const fpga_desc *const fpga_validate(int devnum, const void *buf,
diff --git a/include/image.h b/include/image.h
index b278778..1886168 100644
--- a/include/image.h
+++ b/include/image.h
@@ -413,6 +413,7 @@ enum fit_load_op {
#define IMAGE_FORMAT_INVALID 0x00
#define IMAGE_FORMAT_LEGACY 0x01 /* legacy image_header based format */
#define IMAGE_FORMAT_FIT 0x02 /* new, libfdt based format */
+#define IMAGE_FORMAT_ANDROID 0x03 /* Android boot image */
int genimg_get_format(const void *img_addr);
int genimg_has_config(bootm_headers_t *images);
@@ -1031,4 +1032,16 @@ static inline int fit_image_check_target_arch(const void *fdt, int node)
#endif /* CONFIG_FIT_VERBOSE */
#endif /* CONFIG_FIT */
+#if defined(CONFIG_ANDROID_BOOT_IMAGE)
+struct andr_img_hdr;
+int android_image_check_header(const struct andr_img_hdr *hdr);
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+ ulong *os_data, ulong *os_len);
+int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
+ ulong *rd_data, ulong *rd_len);
+ulong android_image_get_end(const struct andr_img_hdr *hdr);
+ulong android_image_get_kload(const struct andr_img_hdr *hdr);
+
+#endif /* CONFIG_ANDROID_BOOT_IMAGE */
+
#endif /* __IMAGE_H__ */
diff --git a/include/mmc.h b/include/mmc.h
index bc11f45..a3a100b 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -54,6 +54,7 @@
#define COMM_ERR -18 /* Communications Error */
#define TIMEOUT -19
#define IN_PROGRESS -20 /* operation is in progress */
+#define SWITCH_ERR -21 /* Card reports failure to switch mode */
#define MMC_CMD_GO_IDLE_STATE 0
#define MMC_CMD_SEND_OP_COND 1
@@ -70,6 +71,7 @@
#define MMC_CMD_SET_BLOCKLEN 16
#define MMC_CMD_READ_SINGLE_BLOCK 17
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
+#define MMC_CMD_SET_BLOCK_COUNT 23
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
#define MMC_CMD_ERASE_GROUP_START 35
@@ -109,6 +111,7 @@
#define SECURE_ERASE 0x80000000
#define MMC_STATUS_MASK (~0x0206BF7F)
+#define MMC_STATUS_SWITCH_ERROR (1 << 7)
#define MMC_STATUS_RDY_FOR_DATA (1 << 8)
#define MMC_STATUS_CURR_STATE (0xf << 9)
#define MMC_STATUS_ERROR (1 << 19)
@@ -225,6 +228,7 @@
* boot partitions (2), general purpose partitions (4) in MMC v4.4.
*/
#define MMC_NUM_BOOT_PARTITION 2
+#define MMC_PART_RPMB 3 /* RPMB partition number */
struct mmc_cid {
unsigned long psn;
@@ -336,7 +340,13 @@ int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access);
int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode);
/* Function to modify the RST_n_FUNCTION field of EXT_CSD */
int mmc_set_rst_n_function(struct mmc *mmc, u8 enable);
-
+/* Functions to read / write the RPMB partition */
+int mmc_rpmb_set_key(struct mmc *mmc, void *key);
+int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *counter);
+int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
+ unsigned short cnt, unsigned char *key);
+int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
+ unsigned short cnt, unsigned char *key);
/**
* Start device initialization and return immediately; it does not block on
* polling OCR (operation condition register) status. Then you should call
diff --git a/include/part.h b/include/part.h
index 53532dc..f2c8c64 100644
--- a/include/part.h
+++ b/include/part.h
@@ -103,6 +103,7 @@ block_dev_desc_t* sata_get_dev(int dev);
block_dev_desc_t* scsi_get_dev(int dev);
block_dev_desc_t* usb_stor_get_dev(int dev);
block_dev_desc_t* mmc_get_dev(int dev);
+int mmc_select_hwpart(int dev_num, int hwpart);
block_dev_desc_t* systemace_get_dev(int dev);
block_dev_desc_t* mg_disk_get_dev(int dev);
block_dev_desc_t *host_get_dev(int dev);
@@ -126,6 +127,7 @@ static inline block_dev_desc_t* sata_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* scsi_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* usb_stor_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* mmc_get_dev(int dev) { return NULL; }
+static inline int mmc_select_hwpart(int dev_num, int hwpart) { return -1; }
static inline block_dev_desc_t* systemace_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* mg_disk_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t *host_get_dev(int dev) { return NULL; }
diff --git a/include/usb_mass_storage.h b/include/usb_mass_storage.h
index ed46064..69b80cd 100644
--- a/include/usb_mass_storage.h
+++ b/include/usb_mass_storage.h
@@ -9,17 +9,9 @@
#define __USB_MASS_STORAGE_H__
#define SECTOR_SIZE 0x200
-#include <mmc.h>
+#include <part.h>
#include <linux/usb/composite.h>
-#ifndef UMS_START_SECTOR
-#define UMS_START_SECTOR 0
-#endif
-
-#ifndef UMS_NUM_SECTORS
-#define UMS_NUM_SECTORS 0
-#endif
-
/* Wait at maximum 60 seconds for cable connection */
#define UMS_CABLE_READY_TIMEOUT 60
@@ -31,14 +23,13 @@ struct ums {
unsigned int start_sector;
unsigned int num_sectors;
const char *name;
- struct mmc *mmc;
+ block_dev_desc_t *block_dev;
};
extern struct ums *ums;
int fsg_init(struct ums *);
void fsg_cleanup(void);
-struct ums *ums_init(unsigned int);
int fsg_main_thread(void *);
int fsg_add(struct usb_configuration *c);
#endif /* __USB_MASS_STORAGE_H__ */
diff --git a/include/xilinx.h b/include/xilinx.h
index 9801267..aebcb3b 100644
--- a/include/xilinx.h
+++ b/include/xilinx.h
@@ -45,16 +45,20 @@ typedef struct { /* typedef xilinx_desc */
} xilinx_desc; /* end, typedef xilinx_desc */
struct xilinx_fpga_op {
- int (*load)(xilinx_desc *, const void *, size_t);
+ int (*load)(xilinx_desc *, const void *, size_t, bitstream_type);
+ int (*loadfs)(xilinx_desc *, const void *, size_t, fpga_fs_info *);
int (*dump)(xilinx_desc *, const void *, size_t);
int (*info)(xilinx_desc *);
};
/* Generic Xilinx Functions
*********************************************************************/
-int xilinx_load(xilinx_desc *desc, const void *image, size_t size);
+int xilinx_load(xilinx_desc *desc, const void *image, size_t size,
+ bitstream_type bstype);
int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize);
int xilinx_info(xilinx_desc *desc);
+int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+ fpga_fs_info *fpga_fsinfo);
/* Board specific implementation specific function types
*********************************************************************/
diff --git a/lib/Makefile b/lib/Makefile
index 27e4f78..377ab13 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -35,6 +35,7 @@ obj-y += net_utils.o
obj-$(CONFIG_PHYSMEM) += physmem.o
obj-y += qsort.o
obj-$(CONFIG_SHA1) += sha1.o
+obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o
obj-$(CONFIG_SHA256) += sha256.o
obj-y += strmhz.o
obj-$(CONFIG_TPM) += tpm.o