]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
Merge git://git.denx.de/u-boot-imx
authorTom Rini <trini@konsulko.com>
Fri, 1 Sep 2017 14:40:59 +0000 (10:40 -0400)
committerTom Rini <trini@konsulko.com>
Fri, 1 Sep 2017 14:40:59 +0000 (10:40 -0400)
Signed-off-by: Tom Rini <trini@konsulko.com>
Conflicts:
configs/imx6qdl_icore_mmc_defconfig
configs/imx6qdl_icore_rqs_defconfig

47 files changed:
arch/arm/include/asm/arch-mx35/mmc_host_def.h
arch/arm/include/asm/arch-mx5/iomux-mx51.h
arch/arm/include/asm/arch-mxs/iomux-mx23.h
arch/arm/include/asm/arch-mxs/iomux-mx28.h
arch/arm/include/asm/mach-imx/sys_proto.h
arch/arm/mach-imx/mx6/soc.c
arch/arm/mach-imx/mx7/psci-mx7.c
arch/arm/mach-imx/mx7/psci.S
arch/arm/mach-imx/spl.c
arch/arm/mach-imx/timer.c
board/bachmann/ot1200/ot1200.c
board/barco/platinum/platinum.h
board/congatec/cgtqmx6eval/cgtqmx6eval.c
board/el/el6x/el6x.c
board/engicam/common/spl.c
board/freescale/mx6sabreauto/mx6sabreauto.c
board/freescale/mx6sabresd/mx6sabresd.c
board/gateworks/gw_ventana/gw_ventana_spl.c
board/kosagi/novena/novena_spl.c
board/liebherr/mccmon6/spl.c
board/phytec/pcm058/pcm058.c
board/phytec/pfla02/Kconfig
board/phytec/pfla02/pfla02.c
board/solidrun/mx6cuboxi/mx6cuboxi.c
board/toradex/apalis_imx6/apalis_imx6.c
board/toradex/colibri_imx6/colibri_imx6.c
board/udoo/udoo_spl.c
board/wandboard/spl.c
cmd/Kconfig
cmd/Makefile
cmd/usb_gadget_sdp.c [new file with mode: 0644]
common/spl/Kconfig
common/spl/Makefile
common/spl/spl.c
common/spl/spl_sdp.c [new file with mode: 0644]
configs/apalis_imx6_defconfig
configs/colibri_imx6_defconfig
configs/imx6qdl_icore_mmc_defconfig
doc/README.sdp [new file with mode: 0644]
drivers/pinctrl/nxp/pinctrl-imx.c
drivers/pinctrl/nxp/pinctrl-imx7ulp.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/f_sdp.c [new file with mode: 0644]
include/configs/imx6-engicam.h
include/imximage.h [moved from tools/imximage.h with 100% similarity]
include/sdp.h [new file with mode: 0644]

index 775b9552cad2ae5e98d9d3c05abdb97196e7a9b3..07755114919fa4fd02a62d706392e01c554588df 100644 (file)
@@ -3,23 +3,7 @@
  * Texas Instruments, <www.ti.com>
  * Syed Mohammed Khasim <khasim@ti.com>
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation's version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
 #ifndef MMC_HOST_DEF_H
index 5c636acc03de69015390460e0280fa42fd9131f4..522512eec3a67bbe507b282ff90bbb41763cb11a 100644 (file)
@@ -3,12 +3,7 @@
  * Copyright (C) 2010 Freescale Semiconductor, Inc.
  * Copyright (C) 2009-2012 Genesi USA, Inc.
  *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 /*
index 7cb5e71688160df26e7677607a52d3f918b10e3d..690929c06a9cf9965b5d1f70e6b9f85c98f4c128 100644 (file)
@@ -2,12 +2,7 @@
  * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
  * Copyright (C) 2010 Freescale Semiconductor, Inc.
  *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #ifndef __MACH_IOMUX_MX23_H__
index b42820de743d1b4cc21ccc5f8764ce18175b26c2..39ea74bc2137a50c827201bf1ece7c104b6fa40f 100644 (file)
@@ -2,12 +2,7 @@
  * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
  * Copyright (C) 2010 Freescale Semiconductor, Inc.
  *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #ifndef __MACH_IOMUX_MX28_H__
index 046df6291a8d0899de2d48ef111fffc4bcd451fa..970c4ca76028bdf3e0c731cde2a8663719d2c0b0 100644 (file)
@@ -69,8 +69,13 @@ enum imx6_bmode_emi {
 
 enum imx6_bmode {
        IMX6_BMODE_EMI,
-       IMX6_BMODE_UART,
+#if defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL)
+       IMX6_BMODE_QSPI,
+       IMX6_BMODE_RESERVED,
+#else
+       IMX6_BMODE_RESERVED,
        IMX6_BMODE_SATA,
+#endif
        IMX6_BMODE_SERIAL_ROM,
        IMX6_BMODE_SD,
        IMX6_BMODE_ESD,
@@ -85,6 +90,8 @@ static inline u8 imx6_is_bmode_from_gpr9(void)
 }
 
 u32 imx6_src_get_boot_mode(void);
+void gpr_init(void);
+
 #endif /* CONFIG_MX6 */
 
 u32 get_nr_cpus(void);
index 9ede1f543527e78186896f378691bc74573f2802..b72466808c0023aab2692abd554a0078299d41b3 100644 (file)
@@ -551,6 +551,7 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
 }
 #endif
 
+#ifndef CONFIG_SPL_BUILD
 /*
  * cfg_val will be used for
  * Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
@@ -577,6 +578,7 @@ const struct boot_mode soc_boot_modes[] = {
        {"esdhc4",      MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
        {NULL,          0},
 };
+#endif
 
 void reset_misc(void)
 {
@@ -681,6 +683,23 @@ void imx_setup_hdmi(void)
 }
 #endif
 
+void gpr_init(void)
+{
+       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
+
+       /* enable AXI cache for VDOA/VPU/IPU */
+       writel(0xF00000CF, &iomux->gpr[4]);
+       if (is_mx6dqp()) {
+               /* set IPU AXI-id1 Qos=0x1 AXI-id0/2/3 Qos=0x7 */
+               writel(0x77177717, &iomux->gpr[6]);
+               writel(0x77177717, &iomux->gpr[7]);
+       } else {
+               /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
+               writel(0x007F007F, &iomux->gpr[6]);
+               writel(0x007F007F, &iomux->gpr[7]);
+       }
+}
+
 #ifdef CONFIG_IMX_BOOTAUX
 int arch_auxiliary_core_up(u32 core_id, u32 boot_private_data)
 {
index 502552d1718fe32a4ddd45d52984805c9039b14a..7f429b0a4332c3d21e15db3c72b434243f7a1384 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
 #include <asm/io.h>
 #include <asm/psci.h>
 #include <asm/secure.h>
index 96e88d6184e40b06a67ade00ac67e309b8f094a7..fc5eb34c8890a20271579953836020dae067884a 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
 #include <config.h>
 #include <linux/linkage.h>
 
index 75698c48ea608afcadbec6b0167a960677a88ec5..258578ac25b4fd6efee695c703f4d81bdb9bbff4 100644 (file)
@@ -15,6 +15,8 @@
 #include <spl.h>
 #include <asm/mach-imx/hab.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 #if defined(CONFIG_MX6)
 /* determine boot device from SRC_SBMR1 (BOOT_CFG[4:1]) or SRC_GPR9 register */
 u32 spl_boot_device(void)
@@ -27,7 +29,7 @@ u32 spl_boot_device(void)
         * BOOT_MODE - see IMX6DQRM Table 8-1
         */
        if (((bmode >> 24) & 0x03) == 0x01) /* Serial Downloader */
-               return BOOT_DEVICE_UART;
+               return BOOT_DEVICE_BOARD;
 
        /* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
        switch ((reg & IMX6_BMODE_MASK) >> IMX6_BMODE_SHIFT) {
@@ -42,11 +44,13 @@ u32 spl_boot_device(void)
                break;
                }
        /* Reserved: Used to force Serial Downloader */
-       case IMX6_BMODE_UART:
-               return BOOT_DEVICE_UART;
+       case IMX6_BMODE_RESERVED:
+               return BOOT_DEVICE_BOARD;
        /* SATA: See 8.5.4, Table 8-20 */
+#if !defined(CONFIG_MX6UL) && !defined(CONFIG_MX6ULL)
        case IMX6_BMODE_SATA:
                return BOOT_DEVICE_SATA;
+#endif
        /* Serial ROM: See 8.5.5.1, Table 8-22 */
        case IMX6_BMODE_SERIAL_ROM:
                /* BOOT_CFG4[2:0] */
@@ -126,3 +130,13 @@ __weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
 }
 
 #endif
+
+#if defined(CONFIG_MX6) && defined(CONFIG_SPL_OS_BOOT)
+int dram_init_banksize(void)
+{
+       gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+       gd->bd->bi_dram[0].size = imx_ddr_size();
+
+       return 0;
+}
+#endif
index 9b011147d66861ccc8c9d2188a8de9536522901b..69dbf3c2cebf6bccc45c401394381709b49b9151 100644 (file)
@@ -74,8 +74,7 @@ int timer_init(void)
        __raw_writel(GPTCR_SWR, &cur_gpt->control);
 
        /* We have no udelay by now */
-       for (i = 0; i < 100; i++)
-               __raw_writel(0, &cur_gpt->control);
+       __raw_writel(0, &cur_gpt->control);
 
        i = __raw_readl(&cur_gpt->control);
        i &= ~GPTCR_CLKSOURCE_MASK;
index df10d6a0d0406c1b36a764979832da11ae1952b3..9465cea72f2ce37e8e264a77d0d9d19f81ada20a 100644 (file)
@@ -169,17 +169,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 int board_early_init_f(void)
 {
        ccgr_init();
index d3ea8bda731f2b13962900b1a891ad09afae639a..3013ed9078aa4c469cbef7cc09c47b2a34dcca5c 100644 (file)
@@ -75,15 +75,4 @@ static inline void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static inline void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 #endif /* _PLATINUM_H_ */
index 8cd0090887a82ef2f1be2ecea52ff7bfda426e4f..2ed66d3ba34aebc39318fbcd94c37090eb123c0c 100644 (file)
@@ -955,17 +955,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 /* Define a minimal structure so that the part number can be read via SPL */
 struct mfgdata {
        unsigned char tsize;
index 6b98b5c3ebda90c4788d57ef939c3d70930a09f7..fb128f5d4cb85b03f295d54bb5baab53d8be9521 100644 (file)
@@ -570,17 +570,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 /*
  * This section requires the differentiation between iMX6 Sabre boards, but
  * for now, it will configure only for the mx6q variant.
index a8a7cf317e8790446aa23d3a11a7729fa642fe3c..6964c131d90dd660bb6ef0d5f56c86b4cb319877 100644 (file)
@@ -39,6 +39,17 @@ static iomux_v3_cfg_t const uart_pads[] = {
 #endif
 };
 
+#ifdef CONFIG_SPL_OS_BOOT
+int spl_start_uboot(void)
+{
+       /* break into full u-boot on 'c' */
+       if (serial_tstc() && serial_getc() == 'c')
+               return 1;
+
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_MX6QDL
 /*
  * Driving strength:
@@ -332,17 +343,6 @@ static void ccgr_init(void)
 #endif
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 static void spl_dram_init(void)
 {
 #ifdef CONFIG_MX6QDL
index f8f77f616cf1ae887ea7726a14d7f4840ee5405b..15ca0294f5051bd1bf479a082342f70d7c550984 100644 (file)
@@ -798,23 +798,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       if (is_mx6dqp()) {
-               /* set IPU AXI-id1 Qos=0x1 AXI-id0/2/3 Qos=0x7 */
-               writel(0x77177717, &iomux->gpr[6]);
-               writel(0x77177717, &iomux->gpr[7]);
-       } else {
-               /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-               writel(0x007F007F, &iomux->gpr[6]);
-               writel(0x007F007F, &iomux->gpr[7]);
-       }
-}
-
 static int mx6q_dcd_table[] = {
        0x020e0798, 0x000C0000,
        0x020e0758, 0x00000000,
index 9a562b3424da0d7754e9a0dfcf807c83b2e9fbb7..5b50bc815f4396a1e7270049fe6ae5abfe885845 100644 (file)
@@ -747,23 +747,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       if (is_mx6dqp()) {
-               /* set IPU AXI-id1 Qos=0x1 AXI-id0/2/3 Qos=0x7 */
-               writel(0x77177717, &iomux->gpr[6]);
-               writel(0x77177717, &iomux->gpr[7]);
-       } else {
-               /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-               writel(0x007F007F, &iomux->gpr[6]);
-               writel(0x007F007F, &iomux->gpr[7]);
-       }
-}
-
 static int mx6q_dcd_table[] = {
        0x020e0798, 0x000C0000,
        0x020e0758, 0x00000000,
index 9524da7daf392166f55b9d7f5b49d526e858ccb9..c2e370ba0be7dc48f43c9a6eb370d324651c884a 100644 (file)
@@ -583,17 +583,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 /*
  * called from C runtime startup code (arch/arm/lib/crt0.S:_main)
  * - we have a stack and a place to store GD, both in SRAM
index 3645b75cb29bfa07222eec8f673862b5e3e1e1bb..512f06da76b6565fd9d6ddea0db11fa9a0f08188 100644 (file)
@@ -550,17 +550,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 /*
  * called from C runtime startup code (arch/arm/lib/crt0.S:_main)
  * - we have a stack and a place to store GD, both in SRAM
index 15844ef437b7b76c7e790c12c44c400619ac7daf..a2f804db8fee1f70a0468ae155f8c0177b5b21b9 100644 (file)
@@ -260,17 +260,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 static void spl_dram_init(void)
 {
        if (is_cpu_type(MXC_CPU_MX6SOLO)) {
index 4257fbcb68b471fd64277ee2f7746ac4d497c100..1538158987aef400557c77c340c82a1658e7a777 100644 (file)
@@ -487,18 +487,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
-
 static void spl_dram_init(void)
 {
        struct mx6_ddr_sysinfo sysinfo = {
index 142a1222fc69275cf2aa4d8ae7baaae1c96c6f01..f4da68b5ba9512be1ae8f870a88eeca437f25647 100644 (file)
@@ -9,4 +9,10 @@ config SYS_VENDOR
 config SYS_CONFIG_NAME
        default "pfla02"
 
+config SPL_DRAM_1_BANK
+       bool "DRAM on just one bank"
+       help
+         activate, if the module has just one bank
+         of RAM
+
 endif
index 8d2ce63e06bbe06bc23b7ff1626a8bf0e48c6641..136f1d5e7068721201edec0ca70c559f23a831c9 100644 (file)
@@ -485,9 +485,9 @@ static const struct mx6_mmdc_calibration mx6_mmcd_calib = {
 
 /* Index in RAM Chip array */
 enum {
-       RAM_1GB,
-       RAM_2GB,
-       RAM_4GB
+       RAM_MT64K,
+       RAM_MT128K,
+       RAM_MT256K
 };
 
 static struct mx6_ddr3_cfg mt41k_xx[] = {
@@ -550,42 +550,11 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
+static void spl_dram_init(struct mx6_ddr_sysinfo *sysinfo,
+                               struct mx6_ddr3_cfg *mem_ddr)
 {
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
-static void spl_dram_init(struct mx6_ddr3_cfg *mem_ddr)
-{
-       struct mx6_ddr_sysinfo sysinfo = {
-               /* width of data bus:0=16,1=32,2=64 */
-               .dsize = 2,
-               /* config for full 4GB range so that get_mem_size() works */
-               .cs_density = 32, /* 32Gb per CS */
-               /* single chip select */
-               .ncs = 2,
-               .cs1_mirror = 0,
-               .rtt_wr = 1 /*DDR3_RTT_60_OHM*/,        /* RTT_Wr = RZQ/4 */
-               .rtt_nom = 1 /*DDR3_RTT_60_OHM*/,       /* RTT_Nom = RZQ/4 */
-               .walat = 1,     /* Write additional latency */
-               .ralat = 5,     /* Read additional latency */
-               .mif3_mode = 3, /* Command prediction working mode */
-               .bi_on = 1,     /* Bank interleaving enabled */
-               .sde_to_rst = 0x10,     /* 14 cycles, 200us (JEDEC default) */
-               .rst_to_cke = 0x23,     /* 33 cycles, 500us (JEDEC default) */
-               .ddr_type = DDR_TYPE_DDR3,
-               .refsel = 1,    /* Refresh cycles at 32KHz */
-               .refr = 7,      /* 8 refresh commands per refresh cycle */
-       };
-
        mx6dq_dram_iocfg(64, &mx6_ddr_ioregs, &mx6_grp_ioregs);
-       mx6_dram_cfg(&sysinfo, &mx6_mmcd_calib, mem_ddr);
+       mx6_dram_cfg(sysinfo, &mx6_mmcd_calib, mem_ddr);
 }
 
 int board_mmc_init(bd_t *bis)
@@ -627,10 +596,12 @@ void board_boot_order(u32 *spl_boot_list)
  * Function checks for mirrors in the first CS
  */
 #define RAM_TEST_PATTERN       0xaa5555aa
-static unsigned int pfla02_detect_ramsize(void)
+#define MIN_BANK_SIZE          (512 * 1024 * 1024)
+
+static unsigned int pfla02_detect_chiptype(void)
 {
        u32 *p, *p1;
-       unsigned int offset = 512 * 1024 * 1024;
+       unsigned int offset = MIN_BANK_SIZE;
        int i;
 
        for (i = 0; i < 2; i++) {
@@ -649,12 +620,38 @@ static unsigned int pfla02_detect_ramsize(void)
                if (*p == *p1)
                        return i;
        }
-       return RAM_4GB;
+       return RAM_MT256K;
 }
 
 void board_init_f(ulong dummy)
 {
        unsigned int ramchip;
+
+       struct mx6_ddr_sysinfo sysinfo = {
+               /* width of data bus:0=16,1=32,2=64 */
+               .dsize = 2,
+               /* config for full 4GB range so that get_mem_size() works */
+               .cs_density = 32, /* 512 MB */
+               /* single chip select */
+#if IS_ENABLED(CONFIG_SPL_DRAM_1_BANK)
+               .ncs = 1,
+#else
+               .ncs = 2,
+#endif
+               .cs1_mirror = 1,
+               .rtt_wr = 1 /*DDR3_RTT_60_OHM*/,        /* RTT_Wr = RZQ/4 */
+               .rtt_nom = 1 /*DDR3_RTT_60_OHM*/,       /* RTT_Nom = RZQ/4 */
+               .walat = 1,     /* Write additional latency */
+               .ralat = 5,     /* Read additional latency */
+               .mif3_mode = 3, /* Command prediction working mode */
+               .bi_on = 1,     /* Bank interleaving enabled */
+               .sde_to_rst = 0x10,     /* 14 cycles, 200us (JEDEC default) */
+               .rst_to_cke = 0x23,     /* 33 cycles, 500us (JEDEC default) */
+               .ddr_type = DDR_TYPE_DDR3,
+               .refsel = 1,    /* Refresh cycles at 32KHz */
+               .refr = 7,      /* 8 refresh commands per refresh cycle */
+       };
+
 #ifdef CONFIG_CMD_NAND
        /* Enable NAND */
        setup_gpmi_nand();
@@ -682,10 +679,23 @@ void board_init_f(ulong dummy)
        setup_gpios();
 
        /* DDR initialization */
-       spl_dram_init(&mt41k_xx[RAM_4GB]);
-       ramchip = pfla02_detect_ramsize();
-       if (ramchip != RAM_4GB)
-               spl_dram_init(&mt41k_xx[ramchip]);
+       spl_dram_init(&sysinfo, &mt41k_xx[RAM_MT256K]);
+       ramchip = pfla02_detect_chiptype();
+       debug("Detected chip %d\n", ramchip);
+#if !IS_ENABLED(CONFIG_SPL_DRAM_1_BANK)
+       switch (ramchip) {
+               case RAM_MT64K:
+                       sysinfo.cs_density = 6;
+                       break;
+               case RAM_MT128K:
+                       sysinfo.cs_density = 10;
+                       break;
+               case RAM_MT256K:
+                       sysinfo.cs_density = 18;
+                       break;
+       }
+#endif
+       spl_dram_init(&sysinfo, &mt41k_xx[ramchip]);
 
        /* Clear the BSS. */
        memset(__bss_start, 0, __bss_end - __bss_start);
index 7e59fb259e118fd99400261453088d0ab7231da4..986abc57720bc15327d0d5e6d2f64a1194618d71 100644 (file)
@@ -581,17 +581,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 static void spl_dram_init(int width)
 {
        struct mx6_ddr_sysinfo sysinfo = {
index 7a3e493faf168a908f73463501d434f8cb9da1a1..ebc6c12cbcbd2143e428f68090168ae611285f57 100644 (file)
@@ -29,6 +29,7 @@
 #include <dm/platform_data/serial_mxc.h>
 #include <dm/platdata.h>
 #include <fsl_esdhc.h>
+#include <g_dnl.h>
 #include <i2c.h>
 #include <imx_thermal.h>
 #include <linux/errno.h>
@@ -1159,17 +1160,6 @@ static void ccgr_init(void)
        writel(0x000000FB, &ccm->ccosr);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 static void ddr_init(int *table, int size)
 {
        int i;
@@ -1234,6 +1224,18 @@ void reset_cpu(ulong addr)
 {
 }
 
+#ifdef CONFIG_SPL_USB_GADGET_SUPPORT
+int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
+{
+       unsigned short usb_pid;
+
+       usb_pid = TORADEX_USB_PRODUCT_NUM_OFFSET + 0xfff;
+       put_unaligned(usb_pid, &dev->idProduct);
+
+       return 0;
+}
+#endif
+
 #endif
 
 static struct mxc_serial_platdata mxc_serial_plat = {
index dbcd2337829dbfb62231b34d5055c0927eea0d37..669d9123ca295bd3283d98b27edab4da89e857ae 100644 (file)
@@ -28,6 +28,7 @@
 #include <dm/platform_data/serial_mxc.h>
 #include <dm/platdata.h>
 #include <fsl_esdhc.h>
+#include <g_dnl.h>
 #include <i2c.h>
 #include <imx_thermal.h>
 #include <linux/errno.h>
@@ -1036,17 +1037,6 @@ static void ccgr_init(void)
        writel(0x000000FB, &ccm->ccosr);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 static void ddr_init(int *table, int size)
 {
        int i;
@@ -1118,6 +1108,18 @@ void reset_cpu(ulong addr)
 {
 }
 
+#ifdef CONFIG_SPL_USB_GADGET_SUPPORT
+int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
+{
+       unsigned short usb_pid;
+
+       usb_pid = TORADEX_USB_PRODUCT_NUM_OFFSET + 0xfff;
+       put_unaligned(usb_pid, &dev->idProduct);
+
+       return 0;
+}
+#endif
+
 #endif
 
 static struct mxc_serial_platdata mxc_serial_plat = {
index e83e7c3a1b2208e0652e79bf9c95c7a0d5e0e56e..3645969e4341ecf348611496a08a97d23c96ebb3 100644 (file)
@@ -211,17 +211,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000FF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 static void spl_dram_init(void)
 {
        if (is_cpu_type(MXC_CPU_MX6DL)) {
index 47082a88d5ec45812ad079b1660a386a56e8a293..99a02865ecf63ffacab74bef188e8b50a60d0c2a 100644 (file)
@@ -266,17 +266,6 @@ static void ccgr_init(void)
        writel(0x000003FF, &ccm->CCGR6);
 }
 
-static void gpr_init(void)
-{
-       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       /* enable AXI cache for VDOA/VPU/IPU */
-       writel(0xF00000CF, &iomux->gpr[4]);
-       /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
-       writel(0x007F007F, &iomux->gpr[6]);
-       writel(0x007F007F, &iomux->gpr[7]);
-}
-
 static void spl_dram_init(void)
 {
        if (is_cpu_type(MXC_CPU_MX6SOLO)) {
index 42d955c96aee9520bd68462b09ed01ff47b03f82..d6d130edfa917c7f6af938be710e0f4e581d8276 100644 (file)
@@ -895,6 +895,13 @@ config CMD_USB
        help
          USB support.
 
+config CMD_USB_SDP
+       bool "sdp"
+       select USB_FUNCTION_SDP
+       help
+         Enables the command "sdp" which is used to have U-Boot emulating the
+         Serial Download Protocol (SDP) via USB.
+
 config CMD_USB_MASS_STORAGE
        bool "UMS usb mass storage"
        help
index 4a865bd7d7540e6769d7c287071a6b062c8b2f85..2a5b8ce82577528c4195adb1d887c94e01f7a416 100644 (file)
@@ -132,6 +132,7 @@ obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o
 obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
 
 obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o
+obj-$(CONFIG_CMD_USB_SDP) += usb_gadget_sdp.o
 obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o
 obj-$(CONFIG_CMD_XIMG) += ximg.o
 obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o
diff --git a/cmd/usb_gadget_sdp.c b/cmd/usb_gadget_sdp.c
new file mode 100644 (file)
index 0000000..b1d8b28
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * cmd_sdp.c -- sdp command
+ *
+ * Copyright (C) 2016 Toradex
+ * Author: Stefan Agner <stefan.agner@toradex.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <g_dnl.h>
+#include <sdp.h>
+#include <usb.h>
+
+static int do_sdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int ret = CMD_RET_FAILURE;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       char *usb_controller = argv[1];
+       int controller_index = simple_strtoul(usb_controller, NULL, 0);
+       board_usb_init(controller_index, USB_INIT_DEVICE);
+
+       g_dnl_clear_detach();
+       g_dnl_register("usb_dnl_sdp");
+
+       ret = sdp_init(controller_index);
+       if (ret) {
+               error("SDP init failed: %d", ret);
+               goto exit;
+       }
+
+       /* This command typically does not return but jumps to an image */
+       sdp_handle(controller_index);
+       error("SDP ended");
+
+exit:
+       g_dnl_unregister();
+       board_usb_cleanup(controller_index, USB_INIT_DEVICE);
+
+       return ret;
+}
+
+U_BOOT_CMD(sdp, 2, 1, do_sdp,
+       "Serial Downloader Protocol",
+       "<USB_controller>\n"
+       "  - serial downloader protocol via <USB_controller>\n"
+);
index 582b685dad36b9cea6298481d49ceb214e8a5926..9446cd9b42e45fb3be13f1c27a1dafbbac31cc4f 100644 (file)
@@ -668,6 +668,12 @@ config SPL_DFU_RAM
 
 endchoice
 
+config SPL_USB_SDP_SUPPORT
+       bool "Support SDP (Serial Download Protocol)"
+       help
+         Enable Serial Download Protocol (SDP) device support in SPL. This
+         allows to download images into memory and execute (jump to) them
+         using the same protocol as implemented by the i.MX family's boot ROM.
 endif
 
 config SPL_WATCHDOG_SUPPORT
index fde0d09a5a9b151090464294ec04534b32e058f5..e229947b53b535259c86631b805a5a7ece37245a 100644 (file)
@@ -30,4 +30,5 @@ obj-$(CONFIG_$(SPL_TPL_)SATA_SUPPORT) += spl_sata.o
 obj-$(CONFIG_$(SPL_TPL_)DFU_SUPPORT) += spl_dfu.o
 obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o
 obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o
+obj-$(CONFIG_$(SPL_TPL_)USB_SDP_SUPPORT) += spl_sdp.o
 endif
index d245cfc0d14d905586dd37fd1ac969dd5d6853fa..8b219ba6908d3ac58688ce483295944372b5f077 100644 (file)
@@ -379,7 +379,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
                if (spl_init())
                        hang();
        }
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MX6)
        /*
         * timer_init() does not exist on PPC systems. The timer is initialized
         * and enabled (decrementer) in interrupt_init() here.
diff --git a/common/spl/spl_sdp.c b/common/spl/spl_sdp.c
new file mode 100644 (file)
index 0000000..350bcdb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * (C) Copyright 2016 Toradex
+ * Author: Stefan Agner <stefan.agner@toradex.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <usb.h>
+#include <g_dnl.h>
+#include <sdp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int spl_sdp_load_image(struct spl_image_info *spl_image,
+                             struct spl_boot_device *bootdev)
+{
+       int ret;
+       const int controller_index = 0;
+
+       g_dnl_clear_detach();
+       g_dnl_register("usb_dnl_sdp");
+
+       ret = sdp_init(controller_index);
+       if (ret) {
+               error("SDP init failed: %d", ret);
+               return -ENODEV;
+       }
+
+       /* This command typically does not return but jumps to an image */
+       sdp_handle(controller_index);
+       error("SDP ended");
+
+       return -EINVAL;
+}
+SPL_LOAD_IMAGE_METHOD("USB SDP", 0, BOOT_DEVICE_BOARD, spl_sdp_load_image);
index 89b6670a4760966083144d6b84935c99a89821f7..ba906c6f3df070aad89484cddc7f6f87b822e047 100644 (file)
@@ -16,6 +16,9 @@ CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_SPL=y
 CONFIG_SPL_DMA_SUPPORT=y
 CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_USB_HOST_SUPPORT=y
+CONFIG_SPL_USB_GADGET_SUPPORT=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="Apalis iMX6 # "
 CONFIG_CMD_BOOTZ=y
@@ -32,6 +35,7 @@ CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
+CONFIG_CMD_USB_SDP=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
index 35e881b00961e628941ce360819140585ab937a3..063738373b50927550f9e433ccd42acf05588949 100644 (file)
@@ -16,6 +16,9 @@ CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_SPL=y
 CONFIG_SPL_DMA_SUPPORT=y
 CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_USB_HOST_SUPPORT=y
+CONFIG_SPL_USB_GADGET_SUPPORT=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="Colibri iMX6 # "
 CONFIG_CMD_BOOTZ=y
@@ -32,6 +35,7 @@ CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
+CONFIG_CMD_USB_SDP=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
index 2a0679f6ff26ba3d447aaddf9910defc25966098..5a84c6366e3d09d9ebdb495de0df06b1956d715f 100644 (file)
@@ -49,3 +49,4 @@ CONFIG_DEBUG_UART_CLOCK=24000000
 CONFIG_MXC_UART=y
 CONFIG_IMX_THERMAL=y
 CONFIG_VIDEO_IPUV3=y
+CONFIG_SPL_OS_BOOT=y
diff --git a/doc/README.sdp b/doc/README.sdp
new file mode 100644 (file)
index 0000000..9b438c0
--- /dev/null
@@ -0,0 +1,100 @@
+-------------
+SDP in U-Boot
+-------------
+
+SDP stands for serial download protocol. It is the protocol used in NXP's
+i.MX SoCs ROM Serial Downloader and provides means to download a program
+image to the chip over USB and UART serial connection.
+
+The implementation in U-Boot uses the USB Downloader Gadget (g_dnl) to
+provide a SDP implementation over USB. This allows to download program
+images to the target in SPL/U-Boot using the same protocol/tooling the
+SoC's recovery mechanism is using.
+
+The SDP protocol over USB is a USB HID class protocol. USB HID class
+protocols allow to access a USB device without OS specific drivers. The
+U-Boot implementation has primarly been tested using the open source
+imx_loader utility (https://github.com/toradex/imx_loader).
+
+The host side utilities are typically capable to interpret the i.MX
+specific image header (see doc/README.imximage). There are extensions
+for imx_loader's imx_usb utility which allow to interpret the U-Boot
+specific legacy image format (see mkimage(1)). Also the U-Boot side
+support beside the i.MX specific header the U-Boot legacy header.
+
+Usage
+-----
+
+This implementation can be started in U-Boot using the sdp command
+(CONFIG_CMD_USB_SDP) or in SPL if Serial Downloader boot mode has been
+detected (CONFIG_SPL_USB_SDP_SUPPORT).
+
+A typical use case is downloading full U-Boot after SPL has been
+downloaded through the boot ROM's Serial Downloader. Using boot mode
+detection the SPL will run the SDP implementation automatically in
+this case:
+
+  # imx_usb SPL
+
+Targets Serial Console:
+
+  Trying to boot from USB SDP
+  SDP: initialize...
+  SDP: handle requests...
+
+At this point the SPL reenumerated as a new HID device and emulating
+the boot ROM's SDP protocol. The USB VID/PID will depend on standard
+U-Boot configurations CONFIG_G_DNL_(VENDOR|PRODUCT)_NUM. Make sure
+imx_usb is aware of the USB VID/PID for your device by adding a
+configuration entry in imx_usb.conf:
+
+  0x1b67:0x4fff, mx6_usb_sdp_spl.conf
+
+And the device specific configuration file mx6_usb_sdp_spl.conf:
+
+  mx6_spl_sdp
+  hid,uboot_header,1024,0x910000,0x10000000,1G,0x00900000,0x40000
+
+This allows to download the regular U-Boot with legacy image headers
+(u-boot.img) using a second invocation of imx_usb:
+
+  # imx_usb u-boot.img
+
+Furthermore, when U-Boot is running the sdp command can be used to
+download and run scripts:
+
+  # imx_usb script.scr
+
+imx_usb configuration files can be also used to download multiple
+files and of arbitrary types, e.g.
+
+  mx6_usb_sdp_uboot
+  hid,1024,0x10000000,1G,0x00907000,0x31000
+  full.itb:load 0x12100000
+  boot.scr:load 0x12000000,jump 0x12000000
+
+There is also a batch mode which allows imx_usb to handle multiple
+consecutive reenumerations by adding multiple VID/PID specifications
+in imx_usb.conf:
+
+  0x15a2:0x0061, mx6_usb_rom.conf, 0x1b67:0x4fff, mx6_usb_sdp_spl.conf
+
+In this mode the file to download (imx_usb job) needs to be specified
+in the configuration files.
+
+mx6_usb_rom.conf:
+
+  mx6_qsb
+  hid,1024,0x910000,0x10000000,1G,0x00900000,0x40000
+  SPL:jump header2
+
+mx6_usb_sdp_spl.conf:
+
+  mx6_spl_sdp
+  hid,uboot_header,1024,0x10000000,1G,0x00907000,0x31000
+  u-boot.img:jump header2
+
+With that SPL and U-Boot can be downloaded with a single invocation
+of imx_usb without arguments:
+
+  # imx_usb
index 1b6107fae600f64ece0fd11eddf09aee00839de5..32cbac963f7bb43826737cb9a1f2695d0a0b09fc 100644 (file)
@@ -158,7 +158,7 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
                if (!(config_val & IMX_NO_PAD_CTL)) {
                        if (info->flags & SHARE_MUX_CONF_REG) {
                                clrsetbits_le32(info->base + conf_reg,
-                                               info->mux_mask, config_val);
+                                               ~info->mux_mask, config_val);
                        } else {
                                writel(config_val, info->base + conf_reg);
                        }
index 4a893e5a65f7dbfbddf3d968208175a55a8499e8..618ce6a0e103c3c5c2576740b553064c784685fb 100644 (file)
 
 #include "pinctrl-imx.h"
 
-static struct imx_pinctrl_soc_info imx7ulp_pinctrl_soc_info = {
+static struct imx_pinctrl_soc_info imx7ulp_pinctrl_soc_info0 = {
+       .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CONFIG_IBE_OBE,
+};
+
+static struct imx_pinctrl_soc_info imx7ulp_pinctrl_soc_info1 = {
        .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CONFIG_IBE_OBE,
 };
 
@@ -25,8 +29,8 @@ static int imx7ulp_pinctrl_probe(struct udevice *dev)
 }
 
 static const struct udevice_id imx7ulp_pinctrl_match[] = {
-       { .compatible = "fsl,imx7ulp-iomuxc-0", .data = (ulong)&imx7ulp_pinctrl_soc_info },
-       { .compatible = "fsl,imx7ulp-iomuxc-1", .data = (ulong)&imx7ulp_pinctrl_soc_info },
+       { .compatible = "fsl,imx7ulp-iomuxc-0", .data = (ulong)&imx7ulp_pinctrl_soc_info0 },
+       { .compatible = "fsl,imx7ulp-iomuxc-1", .data = (ulong)&imx7ulp_pinctrl_soc_info1 },
        { /* sentinel */ }
 };
 
index 261ed128acd882c996c11114f9d51eb963e435b5..225b66bc95ff3492dfff8b340d5130dc86d06b76 100644 (file)
@@ -103,6 +103,13 @@ config USB_GADGET_DOWNLOAD
 
 if USB_GADGET_DOWNLOAD
 
+config USB_FUNCTION_SDP
+       bool "Enable USB SDP (Serial Download Protocol)"
+       help
+         Enable Serial Download Protocol (SDP) device support in U-Boot. This
+         allows to download images into memory and execute (jump to) them
+         using the same protocol as implemented by the i.MX family's boot ROM.
+
 config G_DNL_MANUFACTURER
        string "Vendor name of USB device"
 
index 5e316a7cff956db270ccfb0ca211c06e05c80633..7258099c1cf5f930831a6cf7a4473804b98ff120 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += g_dnl.o
 obj-$(CONFIG_SPL_DFU_SUPPORT) += f_dfu.o
+obj-$(CONFIG_SPL_USB_SDP_SUPPORT) += f_sdp.o
 endif
 
 # new USB gadget layer dependencies
@@ -28,6 +29,7 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o
 obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o
 obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o
 obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o
+obj-$(CONFIG_USB_FUNCTION_SDP) += f_sdp.o
 endif
 endif
 ifdef CONFIG_USB_ETHER
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
new file mode 100644 (file)
index 0000000..0fae66b
--- /dev/null
@@ -0,0 +1,737 @@
+/*
+ * f_sdp.c -- USB HID Serial Download Protocol
+ *
+ * Copyright (C) 2017 Toradex
+ * Author: Stefan Agner <stefan.agner@toradex.com>
+ *
+ * This file implements the Serial Download Protocol (SDP) as specified in
+ * the i.MX 6 Reference Manual. The SDP is a USB HID based protocol and
+ * allows to download images directly to memory. The implementation
+ * works with the imx_loader (imx_usb) USB client software on host side.
+ *
+ * Not all commands are implemented, e.g. WRITE_REGISTER, DCD_WRITE and
+ * SKIP_DCD_HEADER are only stubs.
+ *
+ * Parts of the implementation are based on f_dfu and f_thor.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <errno.h>
+#include <common.h>
+#include <console.h>
+#include <malloc.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+
+#include <asm/io.h>
+#include <g_dnl.h>
+#include <sdp.h>
+#include <spl.h>
+#include <image.h>
+#include <imximage.h>
+
+#define HID_REPORT_ID_MASK     0x000000ff
+
+/*
+ * HID class requests
+ */
+#define HID_REQ_GET_REPORT             0x01
+#define HID_REQ_GET_IDLE               0x02
+#define HID_REQ_GET_PROTOCOL           0x03
+#define HID_REQ_SET_REPORT             0x09
+#define HID_REQ_SET_IDLE               0x0A
+#define HID_REQ_SET_PROTOCOL           0x0B
+
+#define HID_USAGE_PAGE_LEN             76
+
+struct hid_report {
+       u8 usage_page[HID_USAGE_PAGE_LEN];
+} __packed;
+
+#define SDP_READ_REGISTER      0x0101
+#define SDP_WRITE_REGISTER     0x0202
+#define SDP_WRITE_FILE         0x0404
+#define SDP_ERROR_STATUS       0x0505
+#define SDP_DCD_WRITE          0x0a0a
+#define SDP_JUMP_ADDRESS       0x0b0b
+#define SDP_SKIP_DCD_HEADER    0x0c0c
+
+#define SDP_SECURITY_CLOSED            0x12343412
+#define SDP_SECURITY_OPEN              0x56787856
+
+#define SDP_WRITE_FILE_COMPLETE                0x88888888
+#define SDP_WRITE_REGISTER_COMPLETE    0x128A8A12
+#define SDP_SKIP_DCD_HEADER_COMPLETE   0x900DD009
+#define SDP_ERROR_IMXHEADER            0x000a0533
+
+#define SDP_COMMAND_LEN                16
+
+struct sdp_command {
+       u16 cmd;
+       u32 addr;
+       u8 format;
+       u32 cnt;
+       u32 data;
+       u8 rsvd;
+} __packed;
+
+enum sdp_state {
+       SDP_STATE_IDLE,
+       SDP_STATE_RX_DCD_DATA,
+       SDP_STATE_RX_FILE_DATA,
+       SDP_STATE_TX_SEC_CONF,
+       SDP_STATE_TX_SEC_CONF_BUSY,
+       SDP_STATE_TX_REGISTER,
+       SDP_STATE_TX_REGISTER_BUSY,
+       SDP_STATE_TX_STATUS,
+       SDP_STATE_TX_STATUS_BUSY,
+       SDP_STATE_JUMP,
+};
+
+struct f_sdp {
+       struct usb_function             usb_function;
+
+       struct usb_descriptor_header    **function;
+
+       u8                              altsetting;
+       enum sdp_state                  state;
+       enum sdp_state                  next_state;
+       u32                             dnl_address;
+       u32                             dnl_bytes_remaining;
+       u32                             jmp_address;
+       bool                            always_send_status;
+       u32                             error_status;
+
+       /* EP0 request */
+       struct usb_request              *req;
+
+       /* EP1 IN */
+       struct usb_ep                   *in_ep;
+       struct usb_request              *in_req;
+
+       bool                            configuration_done;
+};
+
+static struct f_sdp *sdp_func;
+
+static inline struct f_sdp *func_to_sdp(struct usb_function *f)
+{
+       return container_of(f, struct f_sdp, usb_function);
+}
+
+static struct usb_interface_descriptor sdp_intf_runtime = {
+       .bLength =              sizeof(sdp_intf_runtime),
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bAlternateSetting =    0,
+       .bNumEndpoints =        1,
+       .bInterfaceClass =      USB_CLASS_HID,
+       .bInterfaceSubClass =   0,
+       .bInterfaceProtocol =   0,
+       /* .iInterface = DYNAMIC */
+};
+
+/* HID configuration */
+static struct usb_class_hid_descriptor sdp_hid_desc = {
+       .bLength =              sizeof(sdp_hid_desc),
+       .bDescriptorType =      USB_DT_CS_DEVICE,
+
+       .bcdCDC =               __constant_cpu_to_le16(0x0110),
+       .bCountryCode =         0,
+       .bNumDescriptors =      1,
+
+       .bDescriptorType0       = USB_DT_HID_REPORT,
+       .wDescriptorLength0     = HID_USAGE_PAGE_LEN,
+};
+
+static struct usb_endpoint_descriptor in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
+
+       .bEndpointAddress =     1 | USB_DIR_IN,
+       .bmAttributes = USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       64,
+       .bInterval =            1,
+};
+
+static struct usb_descriptor_header *sdp_runtime_descs[] = {
+       (struct usb_descriptor_header *)&sdp_intf_runtime,
+       (struct usb_descriptor_header *)&sdp_hid_desc,
+       (struct usb_descriptor_header *)&in_desc,
+       NULL,
+};
+
+/* This is synchronized with what the SoC implementation reports */
+static struct hid_report sdp_hid_report = {
+       .usage_page = {
+               0x06, 0x00, 0xff, /* Usage Page */
+               0x09, 0x01, /* Usage (Pointer?) */
+               0xa1, 0x01, /* Collection */
+
+               0x85, 0x01, /* Report ID */
+               0x19, 0x01, /* Usage Minimum */
+               0x29, 0x01, /* Usage Maximum */
+               0x15, 0x00, /* Local Minimum */
+               0x26, 0xFF, 0x00, /* Local Maximum? */
+               0x75, 0x08, /* Report Size */
+               0x95, 0x10, /* Report Count */
+               0x91, 0x02, /* Output Data */
+
+               0x85, 0x02, /* Report ID */
+               0x19, 0x01, /* Usage Minimum */
+               0x29, 0x01, /* Usage Maximum */
+               0x15, 0x00, /* Local Minimum */
+               0x26, 0xFF, 0x00, /* Local Maximum? */
+               0x75, 0x80, /* Report Size 128 */
+               0x95, 0x40, /* Report Count */
+               0x91, 0x02, /* Output Data */
+
+               0x85, 0x03, /* Report ID */
+               0x19, 0x01, /* Usage Minimum */
+               0x29, 0x01, /* Usage Maximum */
+               0x15, 0x00, /* Local Minimum */
+               0x26, 0xFF, 0x00, /* Local Maximum? */
+               0x75, 0x08, /* Report Size 8 */
+               0x95, 0x04, /* Report Count */
+               0x81, 0x02, /* Input Data */
+
+               0x85, 0x04, /* Report ID */
+               0x19, 0x01, /* Usage Minimum */
+               0x29, 0x01, /* Usage Maximum */
+               0x15, 0x00, /* Local Minimum */
+               0x26, 0xFF, 0x00, /* Local Maximum? */
+               0x75, 0x08, /* Report Size 8 */
+               0x95, 0x40, /* Report Count */
+               0x81, 0x02, /* Input Data */
+               0xc0
+       },
+};
+
+static const char sdp_name[] = "Serial Downloader Protocol";
+
+/*
+ * static strings, in UTF-8
+ */
+static struct usb_string strings_sdp_generic[] = {
+       [0].s = sdp_name,
+       {  }                    /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_sdp_generic = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_sdp_generic,
+};
+
+static struct usb_gadget_strings *sdp_generic_strings[] = {
+       &stringtab_sdp_generic,
+       NULL,
+};
+
+static void sdp_rx_command_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_sdp *sdp = req->context;
+       int status = req->status;
+       u8 *data = req->buf;
+       u8 report = data[0];
+
+       if (status != 0) {
+               error("Status: %d", status);
+               return;
+       }
+
+       if (report != 1) {
+               error("Unexpected report %d", report);
+               return;
+       }
+
+       struct sdp_command *cmd = req->buf + 1;
+
+       debug("%s: command: %04x, addr: %08x, cnt: %u\n",
+             __func__, be16_to_cpu(cmd->cmd),
+             be32_to_cpu(cmd->addr), be32_to_cpu(cmd->cnt));
+
+       switch (be16_to_cpu(cmd->cmd)) {
+       case SDP_READ_REGISTER:
+               sdp->always_send_status = false;
+               sdp->error_status = 0x0;
+
+               sdp->state = SDP_STATE_TX_SEC_CONF;
+               sdp->dnl_address = be32_to_cpu(cmd->addr);
+               sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
+               sdp->next_state = SDP_STATE_TX_REGISTER;
+               printf("Reading %d registers at 0x%08x... ",
+                      sdp->dnl_bytes_remaining, sdp->dnl_address);
+               break;
+       case SDP_WRITE_FILE:
+               sdp->always_send_status = true;
+               sdp->error_status = SDP_WRITE_FILE_COMPLETE;
+
+               sdp->state = SDP_STATE_RX_FILE_DATA;
+               sdp->dnl_address = be32_to_cpu(cmd->addr);
+               sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
+               sdp->next_state = SDP_STATE_IDLE;
+
+               printf("Downloading file of size %d to 0x%08x... ",
+                      sdp->dnl_bytes_remaining, sdp->dnl_address);
+
+               break;
+       case SDP_ERROR_STATUS:
+               sdp->always_send_status = true;
+               sdp->error_status = 0;
+
+               sdp->state = SDP_STATE_TX_SEC_CONF;
+               sdp->next_state = SDP_STATE_IDLE;
+               break;
+       case SDP_DCD_WRITE:
+               sdp->always_send_status = true;
+               sdp->error_status = SDP_WRITE_REGISTER_COMPLETE;
+
+               sdp->state = SDP_STATE_RX_DCD_DATA;
+               sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
+               sdp->next_state = SDP_STATE_IDLE;
+               break;
+       case SDP_JUMP_ADDRESS:
+               sdp->always_send_status = false;
+               sdp->error_status = 0;
+
+               sdp->jmp_address = be32_to_cpu(cmd->addr);
+               sdp->state = SDP_STATE_TX_SEC_CONF;
+               sdp->next_state = SDP_STATE_JUMP;
+               break;
+       case SDP_SKIP_DCD_HEADER:
+               sdp->always_send_status = true;
+               sdp->error_status = SDP_SKIP_DCD_HEADER_COMPLETE;
+
+               /* Ignore command, DCD not supported anyway */
+               sdp->state = SDP_STATE_TX_SEC_CONF;
+               sdp->next_state = SDP_STATE_IDLE;
+               break;
+       default:
+               error("Unknown command: %04x\n", be16_to_cpu(cmd->cmd));
+       }
+}
+
+static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_sdp *sdp = req->context;
+       int status = req->status;
+       u8 *data = req->buf;
+       u8 report = data[0];
+       int datalen = req->length - 1;
+
+       if (status != 0) {
+               error("Status: %d", status);
+               return;
+       }
+
+       if (report != 2) {
+               error("Unexpected report %d", report);
+               return;
+       }
+
+       if (sdp->dnl_bytes_remaining < datalen) {
+               /*
+                * Some USB stacks require to send a complete buffer as
+                * specified in the HID descriptor. This leads to longer
+                * transfers than the file length, no problem for us.
+                */
+               sdp->dnl_bytes_remaining = 0;
+       } else {
+               sdp->dnl_bytes_remaining -= datalen;
+       }
+
+       if (sdp->state == SDP_STATE_RX_FILE_DATA) {
+               memcpy((void *)sdp->dnl_address, req->buf + 1, datalen);
+               sdp->dnl_address += datalen;
+       }
+
+       if (sdp->dnl_bytes_remaining)
+               return;
+
+       printf("done\n");
+
+       switch (sdp->state) {
+       case SDP_STATE_RX_FILE_DATA:
+               sdp->state = SDP_STATE_TX_SEC_CONF;
+               break;
+       case SDP_STATE_RX_DCD_DATA:
+               sdp->state = SDP_STATE_TX_SEC_CONF;
+               break;
+       default:
+               error("Invalid state: %d", sdp->state);
+       }
+}
+
+static void sdp_tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_sdp *sdp = req->context;
+       int status = req->status;
+
+       if (status != 0) {
+               error("Status: %d", status);
+               return;
+       }
+
+       switch (sdp->state) {
+       case SDP_STATE_TX_SEC_CONF_BUSY:
+               /* Not all commands require status report */
+               if (sdp->always_send_status || sdp->error_status)
+                       sdp->state = SDP_STATE_TX_STATUS;
+               else
+                       sdp->state = sdp->next_state;
+
+               break;
+       case SDP_STATE_TX_STATUS_BUSY:
+               sdp->state = sdp->next_state;
+               break;
+       case SDP_STATE_TX_REGISTER_BUSY:
+               if (sdp->dnl_bytes_remaining)
+                       sdp->state = SDP_STATE_TX_REGISTER;
+               else
+                       sdp->state = SDP_STATE_IDLE;
+               break;
+       default:
+               error("Wrong State: %d", sdp->state);
+               sdp->state = SDP_STATE_IDLE;
+               break;
+       }
+       debug("%s complete --> %d, %d/%d\n", ep->name,
+             status, req->actual, req->length);
+}
+
+static int sdp_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_gadget *gadget = f->config->cdev->gadget;
+       struct usb_request *req = f->config->cdev->req;
+       struct f_sdp *sdp = f->config->cdev->req->context;
+       u16 len = le16_to_cpu(ctrl->wLength);
+       u16 w_value = le16_to_cpu(ctrl->wValue);
+       int value = 0;
+       u8 req_type = ctrl->bRequestType & USB_TYPE_MASK;
+
+       debug("w_value: 0x%04x len: 0x%04x\n", w_value, len);
+       debug("req_type: 0x%02x ctrl->bRequest: 0x%02x sdp->state: %d\n",
+             req_type, ctrl->bRequest, sdp->state);
+
+       if (req_type == USB_TYPE_STANDARD) {
+               if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR) {
+                       /* Send HID report descriptor */
+                       value = min(len, (u16) sizeof(sdp_hid_report));
+                       memcpy(req->buf, &sdp_hid_report, value);
+                       sdp->configuration_done = true;
+               }
+       }
+
+       if (req_type == USB_TYPE_CLASS) {
+               int report = w_value & HID_REPORT_ID_MASK;
+
+               /* HID (SDP) request */
+               switch (ctrl->bRequest) {
+               case HID_REQ_SET_REPORT:
+                       switch (report) {
+                       case 1:
+                               value = SDP_COMMAND_LEN + 1;
+                               req->complete = sdp_rx_command_complete;
+                               break;
+                       case 2:
+                               value = len;
+                               req->complete = sdp_rx_data_complete;
+                               break;
+                       }
+               }
+       }
+
+       if (value >= 0) {
+               req->length = value;
+               req->zero = value < len;
+               value = usb_ep_queue(gadget->ep0, req, 0);
+               if (value < 0) {
+                       debug("ep_queue --> %d\n", value);
+                       req->status = 0;
+               }
+       }
+
+       return value;
+}
+
+static int sdp_bind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct usb_gadget *gadget = c->cdev->gadget;
+       struct usb_composite_dev *cdev = c->cdev;
+       struct f_sdp *sdp = func_to_sdp(f);
+       int rv = 0, id;
+
+       id = usb_interface_id(c, f);
+       if (id < 0)
+               return id;
+       sdp_intf_runtime.bInterfaceNumber = id;
+
+       struct usb_ep *ep;
+
+       /* allocate instance-specific endpoints */
+       ep = usb_ep_autoconfig(gadget, &in_desc);
+       if (!ep) {
+               rv = -ENODEV;
+               goto error;
+       }
+
+       sdp->in_ep = ep; /* Store IN EP for enabling @ setup */
+
+       cdev->req->context = sdp;
+
+error:
+       return rv;
+}
+
+static void sdp_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       free(sdp_func);
+       sdp_func = NULL;
+}
+
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
+{
+       struct usb_request *req;
+
+       req = usb_ep_alloc_request(ep, 0);
+       if (!req)
+               return req;
+
+       req->length = length;
+       req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length);
+       if (!req->buf) {
+               usb_ep_free_request(ep, req);
+               req = NULL;
+       }
+
+       return req;
+}
+
+
+static struct usb_request *sdp_start_ep(struct usb_ep *ep)
+{
+       struct usb_request *req;
+
+       req = alloc_ep_req(ep, 64);
+       debug("%s: ep:%p req:%p\n", __func__, ep, req);
+
+       if (!req)
+               return NULL;
+
+       memset(req->buf, 0, req->length);
+       req->complete = sdp_tx_complete;
+
+       return req;
+}
+static int sdp_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+       struct f_sdp *sdp = func_to_sdp(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       int result;
+
+       debug("%s: intf: %d alt: %d\n", __func__, intf, alt);
+
+       result = usb_ep_enable(sdp->in_ep, &in_desc);
+       if (result)
+               return result;
+       sdp->in_req = sdp_start_ep(sdp->in_ep);
+       sdp->in_req->context = sdp;
+
+       sdp->in_ep->driver_data = cdev; /* claim */
+
+       sdp->altsetting = alt;
+       sdp->state = SDP_STATE_IDLE;
+
+       return 0;
+}
+
+static int sdp_get_alt(struct usb_function *f, unsigned intf)
+{
+       struct f_sdp *sdp = func_to_sdp(f);
+
+       return sdp->altsetting;
+}
+
+static void sdp_disable(struct usb_function *f)
+{
+       struct f_sdp *sdp = func_to_sdp(f);
+
+       usb_ep_disable(sdp->in_ep);
+
+       if (sdp->in_req) {
+               free(sdp->in_req);
+               sdp->in_req = NULL;
+       }
+}
+
+static int sdp_bind_config(struct usb_configuration *c)
+{
+       int status;
+
+       if (!sdp_func) {
+               sdp_func = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*sdp_func));
+               if (!sdp_func)
+                       return -ENOMEM;
+       }
+
+       memset(sdp_func, 0, sizeof(*sdp_func));
+
+       sdp_func->usb_function.name = "sdp";
+       sdp_func->usb_function.hs_descriptors = sdp_runtime_descs;
+       sdp_func->usb_function.descriptors = sdp_runtime_descs;
+       sdp_func->usb_function.bind = sdp_bind;
+       sdp_func->usb_function.unbind = sdp_unbind;
+       sdp_func->usb_function.set_alt = sdp_set_alt;
+       sdp_func->usb_function.get_alt = sdp_get_alt;
+       sdp_func->usb_function.disable = sdp_disable;
+       sdp_func->usb_function.strings = sdp_generic_strings;
+       sdp_func->usb_function.setup = sdp_setup;
+
+       status = usb_add_function(c, &sdp_func->usb_function);
+
+       return status;
+}
+
+int sdp_init(int controller_index)
+{
+       printf("SDP: initialize...\n");
+       while (!sdp_func->configuration_done) {
+               if (ctrlc()) {
+                       puts("\rCTRL+C - Operation aborted.\n");
+                       return 1;
+               }
+               usb_gadget_handle_interrupts(controller_index);
+       }
+
+       return 0;
+}
+
+static u32 sdp_jump_imxheader(void *address)
+{
+       flash_header_v2_t *headerv2 = address;
+       ulong (*entry)(void);
+
+       if (headerv2->header.tag != IVT_HEADER_TAG) {
+               printf("Header Tag is not an IMX image\n");
+               return SDP_ERROR_IMXHEADER;
+       }
+
+       printf("Jumping to 0x%08x\n", headerv2->entry);
+       entry = (void *)headerv2->entry;
+       entry();
+
+       /* The image probably never returns hence we won't reach that point */
+       return 0;
+}
+
+static void sdp_handle_in_ep(void)
+{
+       u8 *data = sdp_func->in_req->buf;
+       u32 status;
+       int datalen;
+
+       switch (sdp_func->state) {
+       case SDP_STATE_TX_SEC_CONF:
+               debug("Report 3: HAB security\n");
+               data[0] = 3;
+
+               status = SDP_SECURITY_OPEN;
+               memcpy(&data[1], &status, 4);
+               sdp_func->in_req->length = 5;
+               usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0);
+               sdp_func->state = SDP_STATE_TX_SEC_CONF_BUSY;
+               break;
+
+       case SDP_STATE_TX_STATUS:
+               debug("Report 4: Status\n");
+               data[0] = 4;
+
+               memcpy(&data[1], &sdp_func->error_status, 4);
+               sdp_func->in_req->length = 65;
+               usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0);
+               sdp_func->state = SDP_STATE_TX_STATUS_BUSY;
+               break;
+       case SDP_STATE_TX_REGISTER:
+               debug("Report 4: Register Values\n");
+               data[0] = 4;
+
+               datalen = sdp_func->dnl_bytes_remaining;
+
+               if (datalen > 64)
+                       datalen = 64;
+
+               memcpy(&data[1], (void *)sdp_func->dnl_address, datalen);
+               sdp_func->in_req->length = 65;
+
+               sdp_func->dnl_bytes_remaining -= datalen;
+               sdp_func->dnl_address += datalen;
+
+               usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0);
+               sdp_func->state = SDP_STATE_TX_REGISTER_BUSY;
+               break;
+       case SDP_STATE_JUMP:
+               printf("Jumping to header at 0x%08x\n", sdp_func->jmp_address);
+               status = sdp_jump_imxheader((void *)sdp_func->jmp_address);
+
+               /* If imx header fails, try some U-Boot specific headers */
+               if (status) {
+#ifdef CONFIG_SPL_BUILD
+                       /* In SPL, allow jumps to U-Boot images */
+                       struct spl_image_info spl_image = {};
+                       spl_parse_image_header(&spl_image,
+                               (struct image_header *)sdp_func->jmp_address);
+                       jump_to_image_no_args(&spl_image);
+#else
+                       /* In U-Boot, allow jumps to scripts */
+                       source(sdp_func->jmp_address, "script@1");
+#endif
+               }
+
+               sdp_func->next_state = SDP_STATE_IDLE;
+               sdp_func->error_status = status;
+
+               /* Only send Report 4 if there was an error */
+               if (status)
+                       sdp_func->state = SDP_STATE_TX_STATUS;
+               else
+                       sdp_func->state = SDP_STATE_IDLE;
+               break;
+       default:
+               break;
+       };
+}
+
+void sdp_handle(int controller_index)
+{
+       printf("SDP: handle requests...\n");
+       while (1) {
+               if (ctrlc()) {
+                       puts("\rCTRL+C - Operation aborted.\n");
+                       return;
+               }
+
+               usb_gadget_handle_interrupts(controller_index);
+
+               sdp_handle_in_ep();
+       }
+}
+
+int sdp_add(struct usb_configuration *c)
+{
+       int id;
+
+       id = usb_string_id(c->cdev);
+       if (id < 0)
+               return id;
+       strings_sdp_generic[0].id = id;
+       sdp_intf_runtime.iInterface = id;
+
+       debug("%s: cdev: %p gadget: %p gadget->ep0: %p\n", __func__,
+             c->cdev, c->cdev->gadget, c->cdev->gadget->ep0);
+
+       return sdp_bind_config(c);
+}
+
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_sdp, sdp_add);
index e0bdb656b2676c202df63a7938fa2573965a7d64..a1b70361560f2b5b174b7d98d28291c24631a7eb 100644 (file)
 # define CONFIG_MII
 #endif
 
+/* Falcon Mode */
+#ifdef CONFIG_SPL_OS_BOOT
+# define CONFIG_SPL_FS_LOAD_ARGS_NAME  "args"
+# define CONFIG_SPL_FS_LOAD_KERNEL_NAME        "uImage"
+# define CONFIG_CMD_SPL
+# define CONFIG_SYS_SPL_ARGS_ADDR      0x18000000
+# define CONFIG_CMD_SPL_WRITE_SIZE     (128 * SZ_1K)
+
+/* MMC support: args@1MB kernel@2MB */
+# define CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR         0x800   /* 1MB */
+# define CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS                (CONFIG_CMD_SPL_WRITE_SIZE / 512)
+# define CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR       0x1000  /* 2MB */
+#endif
+
 /* Framebuffer */
 #ifdef CONFIG_VIDEO_IPUV3
 # define CONFIG_IPUV3_CLK              260000000
similarity index 100%
rename from tools/imximage.h
rename to include/imximage.h
diff --git a/include/sdp.h b/include/sdp.h
new file mode 100644 (file)
index 0000000..f476bab
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * sdp.h - Serial Download Protocol
+ *
+ * Copyright (C) 2017 Toradex
+ * Author: Stefan Agner <stefan.agner@toradex.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __SDP_H_
+#define __SDP_H_
+
+int sdp_init(int controller_index);
+void sdp_handle(int controller_index);
+
+#endif /* __SDP_H_ */