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
This commit is contained in:
Tom Rini 2017-09-01 10:40:59 -04:00
commit 6aee2ab68c
47 changed files with 1156 additions and 279 deletions

View 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

View 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+
*/
/*

View 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__

View 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__

View 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);

View 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)
{

View 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>

View 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>

View 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

View 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;

View 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();

View 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_ */

View 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;

View 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.

View 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

View 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,

View 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,

View 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

View 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

View 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)) {

View 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 = {

View 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

View 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);

View 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 = {

View 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 = {

View 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 = {

View 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)) {

View 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)) {

View 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

View 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

50
cmd/usb_gadget_sdp.c Normal file
View File

@ -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"
);

View 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

View 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

View 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.

37
common/spl/spl_sdp.c Normal file
View File

@ -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);

View 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

View 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

View 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

100
doc/README.sdp Normal file
View File

@ -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

View 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);
}

View File

@ -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 */ }
};

View 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"

View 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

737
drivers/usb/gadget/f_sdp.c Normal file
View File

@ -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);

View File

@ -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

16
include/sdp.h Normal file
View File

@ -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_ */