diff options
author | Tom Rini <trini@konsulko.com> | 2017-09-01 10:40:59 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2017-09-01 10:40:59 -0400 |
commit | 6aee2ab68c362ace5a59f89a63abed82e0bf19e5 (patch) | |
tree | 0b76045a178e9c0ed61e141bd8dfb3e34e4e86a9 | |
parent | 4109d702934c361b2ae2a5ad34f4dfee708cc214 (diff) | |
parent | 63af4b0ad0666e0797306593813b6272e1995bde (diff) |
Merge git://git.denx.de/u-boot-imx
Signed-off-by: Tom Rini <trini@konsulko.com>
Conflicts:
configs/imx6qdl_icore_mmc_defconfig
configs/imx6qdl_icore_rqs_defconfig
47 files changed, 1156 insertions, 279 deletions
diff --git a/arch/arm/include/asm/arch-mx35/mmc_host_def.h b/arch/arm/include/asm/arch-mx35/mmc_host_def.h index 775b9552cad..07755114919 100644 --- a/arch/arm/include/asm/arch-mx35/mmc_host_def.h +++ b/arch/arm/include/asm/arch-mx35/mmc_host_def.h @@ -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 diff --git a/arch/arm/include/asm/arch-mx5/iomux-mx51.h b/arch/arm/include/asm/arch-mx5/iomux-mx51.h index 5c636acc03d..522512eec3a 100644 --- a/arch/arm/include/asm/arch-mx5/iomux-mx51.h +++ b/arch/arm/include/asm/arch-mx5/iomux-mx51.h @@ -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+ */ /* diff --git a/arch/arm/include/asm/arch-mxs/iomux-mx23.h b/arch/arm/include/asm/arch-mxs/iomux-mx23.h index 7cb5e716881..690929c06a9 100644 --- a/arch/arm/include/asm/arch-mxs/iomux-mx23.h +++ b/arch/arm/include/asm/arch-mxs/iomux-mx23.h @@ -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__ diff --git a/arch/arm/include/asm/arch-mxs/iomux-mx28.h b/arch/arm/include/asm/arch-mxs/iomux-mx28.h index b42820de743..39ea74bc213 100644 --- a/arch/arm/include/asm/arch-mxs/iomux-mx28.h +++ b/arch/arm/include/asm/arch-mxs/iomux-mx28.h @@ -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__ diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h index 046df6291a8..970c4ca7602 100644 --- a/arch/arm/include/asm/mach-imx/sys_proto.h +++ b/arch/arm/include/asm/mach-imx/sys_proto.h @@ -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); diff --git a/arch/arm/mach-imx/mx6/soc.c b/arch/arm/mach-imx/mx6/soc.c index 9ede1f54352..b72466808c0 100644 --- a/arch/arm/mach-imx/mx6/soc.c +++ b/arch/arm/mach-imx/mx6/soc.c @@ -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) { diff --git a/arch/arm/mach-imx/mx7/psci-mx7.c b/arch/arm/mach-imx/mx7/psci-mx7.c index 502552d1718..7f429b0a433 100644 --- a/arch/arm/mach-imx/mx7/psci-mx7.c +++ b/arch/arm/mach-imx/mx7/psci-mx7.c @@ -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> diff --git a/arch/arm/mach-imx/mx7/psci.S b/arch/arm/mach-imx/mx7/psci.S index 96e88d6184e..fc5eb34c889 100644 --- a/arch/arm/mach-imx/mx7/psci.S +++ b/arch/arm/mach-imx/mx7/psci.S @@ -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> diff --git a/arch/arm/mach-imx/spl.c b/arch/arm/mach-imx/spl.c index 75698c48ea6..258578ac25b 100644 --- a/arch/arm/mach-imx/spl.c +++ b/arch/arm/mach-imx/spl.c @@ -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 diff --git a/arch/arm/mach-imx/timer.c b/arch/arm/mach-imx/timer.c index 9b011147d66..69dbf3c2ceb 100644 --- a/arch/arm/mach-imx/timer.c +++ b/arch/arm/mach-imx/timer.c @@ -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; diff --git a/board/bachmann/ot1200/ot1200.c b/board/bachmann/ot1200/ot1200.c index df10d6a0d04..9465cea72f2 100644 --- a/board/bachmann/ot1200/ot1200.c +++ b/board/bachmann/ot1200/ot1200.c @@ -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(); diff --git a/board/barco/platinum/platinum.h b/board/barco/platinum/platinum.h index d3ea8bda731..3013ed9078a 100644 --- a/board/barco/platinum/platinum.h +++ b/board/barco/platinum/platinum.h @@ -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_ */ diff --git a/board/congatec/cgtqmx6eval/cgtqmx6eval.c b/board/congatec/cgtqmx6eval/cgtqmx6eval.c index 8cd0090887a..2ed66d3ba34 100644 --- a/board/congatec/cgtqmx6eval/cgtqmx6eval.c +++ b/board/congatec/cgtqmx6eval/cgtqmx6eval.c @@ -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; diff --git a/board/el/el6x/el6x.c b/board/el/el6x/el6x.c index 6b98b5c3ebd..fb128f5d4cb 100644 --- a/board/el/el6x/el6x.c +++ b/board/el/el6x/el6x.c @@ -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. diff --git a/board/engicam/common/spl.c b/board/engicam/common/spl.c index a8a7cf317e8..6964c131d90 100644 --- a/board/engicam/common/spl.c +++ b/board/engicam/common/spl.c @@ -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 diff --git a/board/freescale/mx6sabreauto/mx6sabreauto.c b/board/freescale/mx6sabreauto/mx6sabreauto.c index f8f77f616cf..15ca0294f50 100644 --- a/board/freescale/mx6sabreauto/mx6sabreauto.c +++ b/board/freescale/mx6sabreauto/mx6sabreauto.c @@ -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, diff --git a/board/freescale/mx6sabresd/mx6sabresd.c b/board/freescale/mx6sabresd/mx6sabresd.c index 9a562b3424d..5b50bc815f4 100644 --- a/board/freescale/mx6sabresd/mx6sabresd.c +++ b/board/freescale/mx6sabresd/mx6sabresd.c @@ -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, diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.c b/board/gateworks/gw_ventana/gw_ventana_spl.c index 9524da7daf3..c2e370ba0be 100644 --- a/board/gateworks/gw_ventana/gw_ventana_spl.c +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -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 diff --git a/board/kosagi/novena/novena_spl.c b/board/kosagi/novena/novena_spl.c index 3645b75cb29..512f06da76b 100644 --- a/board/kosagi/novena/novena_spl.c +++ b/board/kosagi/novena/novena_spl.c @@ -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 diff --git a/board/liebherr/mccmon6/spl.c b/board/liebherr/mccmon6/spl.c index 15844ef437b..a2f804db8fe 100644 --- a/board/liebherr/mccmon6/spl.c +++ b/board/liebherr/mccmon6/spl.c @@ -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)) { diff --git a/board/phytec/pcm058/pcm058.c b/board/phytec/pcm058/pcm058.c index 4257fbcb68b..1538158987a 100644 --- a/board/phytec/pcm058/pcm058.c +++ b/board/phytec/pcm058/pcm058.c @@ -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 = { diff --git a/board/phytec/pfla02/Kconfig b/board/phytec/pfla02/Kconfig index 142a1222fc6..f4da68b5ba9 100644 --- a/board/phytec/pfla02/Kconfig +++ b/board/phytec/pfla02/Kconfig @@ -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 diff --git a/board/phytec/pfla02/pfla02.c b/board/phytec/pfla02/pfla02.c index 8d2ce63e06b..136f1d5e706 100644 --- a/board/phytec/pfla02/pfla02.c +++ b/board/phytec/pfla02/pfla02.c @@ -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); diff --git a/board/solidrun/mx6cuboxi/mx6cuboxi.c b/board/solidrun/mx6cuboxi/mx6cuboxi.c index 7e59fb259e1..986abc57720 100644 --- a/board/solidrun/mx6cuboxi/mx6cuboxi.c +++ b/board/solidrun/mx6cuboxi/mx6cuboxi.c @@ -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 = { diff --git a/board/toradex/apalis_imx6/apalis_imx6.c b/board/toradex/apalis_imx6/apalis_imx6.c index 7a3e493faf1..ebc6c12cbcb 100644 --- a/board/toradex/apalis_imx6/apalis_imx6.c +++ b/board/toradex/apalis_imx6/apalis_imx6.c @@ -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 = { diff --git a/board/toradex/colibri_imx6/colibri_imx6.c b/board/toradex/colibri_imx6/colibri_imx6.c index dbcd2337829..669d9123ca2 100644 --- a/board/toradex/colibri_imx6/colibri_imx6.c +++ b/board/toradex/colibri_imx6/colibri_imx6.c @@ -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 = { diff --git a/board/udoo/udoo_spl.c b/board/udoo/udoo_spl.c index e83e7c3a1b2..3645969e434 100644 --- a/board/udoo/udoo_spl.c +++ b/board/udoo/udoo_spl.c @@ -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)) { diff --git a/board/wandboard/spl.c b/board/wandboard/spl.c index 47082a88d5e..99a02865ecf 100644 --- a/board/wandboard/spl.c +++ b/board/wandboard/spl.c @@ -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)) { diff --git a/cmd/Kconfig b/cmd/Kconfig index 42d955c96ae..d6d130edfa9 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -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 diff --git a/cmd/Makefile b/cmd/Makefile index 4a865bd7d75..2a5b8ce8257 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -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 index 00000000000..b1d8b2858e1 --- /dev/null +++ b/cmd/usb_gadget_sdp.c @@ -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" +); diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 582b685dad3..9446cd9b42e 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -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 diff --git a/common/spl/Makefile b/common/spl/Makefile index fde0d09a5a9..e229947b53b 100644 --- a/common/spl/Makefile +++ b/common/spl/Makefile @@ -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 diff --git a/common/spl/spl.c b/common/spl/spl.c index d245cfc0d14..8b219ba6908 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -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 index 00000000000..350bcdb0569 --- /dev/null +++ b/common/spl/spl_sdp.c @@ -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); diff --git a/configs/apalis_imx6_defconfig b/configs/apalis_imx6_defconfig index 89b6670a476..ba906c6f3df 100644 --- a/configs/apalis_imx6_defconfig +++ b/configs/apalis_imx6_defconfig @@ -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 diff --git a/configs/colibri_imx6_defconfig b/configs/colibri_imx6_defconfig index 35e881b0096..063738373b5 100644 --- a/configs/colibri_imx6_defconfig +++ b/configs/colibri_imx6_defconfig @@ -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 diff --git a/configs/imx6qdl_icore_mmc_defconfig b/configs/imx6qdl_icore_mmc_defconfig index 2a0679f6ff2..5a84c6366e3 100644 --- a/configs/imx6qdl_icore_mmc_defconfig +++ b/configs/imx6qdl_icore_mmc_defconfig @@ -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 index 00000000000..9b438c0746c --- /dev/null +++ b/doc/README.sdp @@ -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 diff --git a/drivers/pinctrl/nxp/pinctrl-imx.c b/drivers/pinctrl/nxp/pinctrl-imx.c index 1b6107fae60..32cbac963f7 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx.c +++ b/drivers/pinctrl/nxp/pinctrl-imx.c @@ -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); } diff --git a/drivers/pinctrl/nxp/pinctrl-imx7ulp.c b/drivers/pinctrl/nxp/pinctrl-imx7ulp.c index 4a893e5a65f..618ce6a0e10 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx7ulp.c +++ b/drivers/pinctrl/nxp/pinctrl-imx7ulp.c @@ -12,7 +12,11 @@ #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 */ } }; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 261ed128acd..225b66bc95f 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -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" diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 5e316a7cff9..7258099c1cf 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -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 index 00000000000..0fae66beaba --- /dev/null +++ b/drivers/usb/gadget/f_sdp.c @@ -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); diff --git a/include/configs/imx6-engicam.h b/include/configs/imx6-engicam.h index e0bdb656b26..a1b70361560 100644 --- a/include/configs/imx6-engicam.h +++ b/include/configs/imx6-engicam.h @@ -183,6 +183,20 @@ # 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 diff --git a/tools/imximage.h b/include/imximage.h index de1ea8ff147..de1ea8ff147 100644 --- a/tools/imximage.h +++ b/include/imximage.h diff --git a/include/sdp.h b/include/sdp.h new file mode 100644 index 00000000000..f476bab8f10 --- /dev/null +++ b/include/sdp.h @@ -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_ */ |