mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-24 04:34:22 +08:00
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:
commit
6aee2ab68c
@ -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
|
||||
|
@ -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+
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -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__
|
||||
|
@ -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__
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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)) {
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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
50
cmd/usb_gadget_sdp.c
Normal 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"
|
||||
);
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
37
common/spl/spl_sdp.c
Normal 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);
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
100
doc/README.sdp
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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 */ }
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
737
drivers/usb/gadget/f_sdp.c
Normal 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);
|
@ -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
16
include/sdp.h
Normal 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_ */
|
Loading…
Reference in New Issue
Block a user