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
47 changed files with 1156 additions and 279 deletions
|
@ -3,23 +3,7 @@
|
||||||
* Texas Instruments, <www.ti.com>
|
* Texas Instruments, <www.ti.com>
|
||||||
* Syed Mohammed Khasim <khasim@ti.com>
|
* Syed Mohammed Khasim <khasim@ti.com>
|
||||||
*
|
*
|
||||||
* See file CREDITS for list of people who contributed to this
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MMC_HOST_DEF_H
|
#ifndef MMC_HOST_DEF_H
|
||||||
|
|
|
@ -3,12 +3,7 @@
|
||||||
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
||||||
* Copyright (C) 2009-2012 Genesi USA, Inc.
|
* Copyright (C) 2009-2012 Genesi USA, Inc.
|
||||||
*
|
*
|
||||||
* The code contained herein is licensed under the GNU General Public
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2,12 +2,7 @@
|
||||||
* Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
|
* Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
|
||||||
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
||||||
*
|
*
|
||||||
* The code contained herein is licensed under the GNU General Public
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MACH_IOMUX_MX23_H__
|
#ifndef __MACH_IOMUX_MX23_H__
|
||||||
|
|
|
@ -2,12 +2,7 @@
|
||||||
* Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
|
* Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
|
||||||
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
||||||
*
|
*
|
||||||
* The code contained herein is licensed under the GNU General Public
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MACH_IOMUX_MX28_H__
|
#ifndef __MACH_IOMUX_MX28_H__
|
||||||
|
|
|
@ -69,8 +69,13 @@ enum imx6_bmode_emi {
|
||||||
|
|
||||||
enum imx6_bmode {
|
enum imx6_bmode {
|
||||||
IMX6_BMODE_EMI,
|
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,
|
IMX6_BMODE_SATA,
|
||||||
|
#endif
|
||||||
IMX6_BMODE_SERIAL_ROM,
|
IMX6_BMODE_SERIAL_ROM,
|
||||||
IMX6_BMODE_SD,
|
IMX6_BMODE_SD,
|
||||||
IMX6_BMODE_ESD,
|
IMX6_BMODE_ESD,
|
||||||
|
@ -85,6 +90,8 @@ static inline u8 imx6_is_bmode_from_gpr9(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 imx6_src_get_boot_mode(void);
|
u32 imx6_src_get_boot_mode(void);
|
||||||
|
void gpr_init(void);
|
||||||
|
|
||||||
#endif /* CONFIG_MX6 */
|
#endif /* CONFIG_MX6 */
|
||||||
|
|
||||||
u32 get_nr_cpus(void);
|
u32 get_nr_cpus(void);
|
||||||
|
|
|
@ -551,6 +551,7 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_SPL_BUILD
|
||||||
/*
|
/*
|
||||||
* cfg_val will be used for
|
* cfg_val will be used for
|
||||||
* Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
|
* 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)},
|
{"esdhc4", MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
|
||||||
{NULL, 0},
|
{NULL, 0},
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
void reset_misc(void)
|
void reset_misc(void)
|
||||||
{
|
{
|
||||||
|
@ -681,6 +683,23 @@ void imx_setup_hdmi(void)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef CONFIG_IMX_BOOTAUX
|
||||||
int arch_auxiliary_core_up(u32 core_id, u32 boot_private_data)
|
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/io.h>
|
||||||
#include <asm/psci.h>
|
#include <asm/psci.h>
|
||||||
#include <asm/secure.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 <config.h>
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <spl.h>
|
#include <spl.h>
|
||||||
#include <asm/mach-imx/hab.h>
|
#include <asm/mach-imx/hab.h>
|
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
#if defined(CONFIG_MX6)
|
#if defined(CONFIG_MX6)
|
||||||
/* determine boot device from SRC_SBMR1 (BOOT_CFG[4:1]) or SRC_GPR9 register */
|
/* determine boot device from SRC_SBMR1 (BOOT_CFG[4:1]) or SRC_GPR9 register */
|
||||||
u32 spl_boot_device(void)
|
u32 spl_boot_device(void)
|
||||||
|
@ -27,7 +29,7 @@ u32 spl_boot_device(void)
|
||||||
* BOOT_MODE - see IMX6DQRM Table 8-1
|
* BOOT_MODE - see IMX6DQRM Table 8-1
|
||||||
*/
|
*/
|
||||||
if (((bmode >> 24) & 0x03) == 0x01) /* Serial Downloader */
|
if (((bmode >> 24) & 0x03) == 0x01) /* Serial Downloader */
|
||||||
return BOOT_DEVICE_UART;
|
return BOOT_DEVICE_BOARD;
|
||||||
|
|
||||||
/* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
|
/* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
|
||||||
switch ((reg & IMX6_BMODE_MASK) >> IMX6_BMODE_SHIFT) {
|
switch ((reg & IMX6_BMODE_MASK) >> IMX6_BMODE_SHIFT) {
|
||||||
|
@ -42,11 +44,13 @@ u32 spl_boot_device(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Reserved: Used to force Serial Downloader */
|
/* Reserved: Used to force Serial Downloader */
|
||||||
case IMX6_BMODE_UART:
|
case IMX6_BMODE_RESERVED:
|
||||||
return BOOT_DEVICE_UART;
|
return BOOT_DEVICE_BOARD;
|
||||||
/* SATA: See 8.5.4, Table 8-20 */
|
/* SATA: See 8.5.4, Table 8-20 */
|
||||||
|
#if !defined(CONFIG_MX6UL) && !defined(CONFIG_MX6ULL)
|
||||||
case IMX6_BMODE_SATA:
|
case IMX6_BMODE_SATA:
|
||||||
return BOOT_DEVICE_SATA;
|
return BOOT_DEVICE_SATA;
|
||||||
|
#endif
|
||||||
/* Serial ROM: See 8.5.5.1, Table 8-22 */
|
/* Serial ROM: See 8.5.5.1, Table 8-22 */
|
||||||
case IMX6_BMODE_SERIAL_ROM:
|
case IMX6_BMODE_SERIAL_ROM:
|
||||||
/* BOOT_CFG4[2:0] */
|
/* BOOT_CFG4[2:0] */
|
||||||
|
@ -126,3 +130,13 @@ __weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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,7 +74,6 @@ int timer_init(void)
|
||||||
__raw_writel(GPTCR_SWR, &cur_gpt->control);
|
__raw_writel(GPTCR_SWR, &cur_gpt->control);
|
||||||
|
|
||||||
/* We have no udelay by now */
|
/* 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 = __raw_readl(&cur_gpt->control);
|
||||||
|
|
|
@ -169,17 +169,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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)
|
int board_early_init_f(void)
|
||||||
{
|
{
|
||||||
ccgr_init();
|
ccgr_init();
|
||||||
|
|
|
@ -75,15 +75,4 @@ static inline void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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_ */
|
#endif /* _PLATINUM_H_ */
|
||||||
|
|
|
@ -955,17 +955,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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 */
|
/* Define a minimal structure so that the part number can be read via SPL */
|
||||||
struct mfgdata {
|
struct mfgdata {
|
||||||
unsigned char tsize;
|
unsigned char tsize;
|
||||||
|
|
|
@ -570,17 +570,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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
|
* This section requires the differentiation between iMX6 Sabre boards, but
|
||||||
* for now, it will configure only for the mx6q variant.
|
* for now, it will configure only for the mx6q variant.
|
||||||
|
|
|
@ -39,6 +39,17 @@ static iomux_v3_cfg_t const uart_pads[] = {
|
||||||
#endif
|
#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
|
#ifdef CONFIG_MX6QDL
|
||||||
/*
|
/*
|
||||||
* Driving strength:
|
* Driving strength:
|
||||||
|
@ -332,17 +343,6 @@ static void ccgr_init(void)
|
||||||
#endif
|
#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)
|
static void spl_dram_init(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_MX6QDL
|
#ifdef CONFIG_MX6QDL
|
||||||
|
|
|
@ -798,23 +798,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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[] = {
|
static int mx6q_dcd_table[] = {
|
||||||
0x020e0798, 0x000C0000,
|
0x020e0798, 0x000C0000,
|
||||||
0x020e0758, 0x00000000,
|
0x020e0758, 0x00000000,
|
||||||
|
|
|
@ -747,23 +747,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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[] = {
|
static int mx6q_dcd_table[] = {
|
||||||
0x020e0798, 0x000C0000,
|
0x020e0798, 0x000C0000,
|
||||||
0x020e0758, 0x00000000,
|
0x020e0758, 0x00000000,
|
||||||
|
|
|
@ -583,17 +583,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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)
|
* 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
|
* - 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);
|
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)
|
* 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
|
* - 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);
|
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)
|
static void spl_dram_init(void)
|
||||||
{
|
{
|
||||||
if (is_cpu_type(MXC_CPU_MX6SOLO)) {
|
if (is_cpu_type(MXC_CPU_MX6SOLO)) {
|
||||||
|
|
|
@ -487,18 +487,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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)
|
static void spl_dram_init(void)
|
||||||
{
|
{
|
||||||
struct mx6_ddr_sysinfo sysinfo = {
|
struct mx6_ddr_sysinfo sysinfo = {
|
||||||
|
|
|
@ -9,4 +9,10 @@ config SYS_VENDOR
|
||||||
config SYS_CONFIG_NAME
|
config SYS_CONFIG_NAME
|
||||||
default "pfla02"
|
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
|
endif
|
||||||
|
|
|
@ -485,9 +485,9 @@ static const struct mx6_mmdc_calibration mx6_mmcd_calib = {
|
||||||
|
|
||||||
/* Index in RAM Chip array */
|
/* Index in RAM Chip array */
|
||||||
enum {
|
enum {
|
||||||
RAM_1GB,
|
RAM_MT64K,
|
||||||
RAM_2GB,
|
RAM_MT128K,
|
||||||
RAM_4GB
|
RAM_MT256K
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mx6_ddr3_cfg mt41k_xx[] = {
|
static struct mx6_ddr3_cfg mt41k_xx[] = {
|
||||||
|
@ -550,42 +550,11 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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);
|
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)
|
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
|
* Function checks for mirrors in the first CS
|
||||||
*/
|
*/
|
||||||
#define RAM_TEST_PATTERN 0xaa5555aa
|
#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;
|
u32 *p, *p1;
|
||||||
unsigned int offset = 512 * 1024 * 1024;
|
unsigned int offset = MIN_BANK_SIZE;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
|
@ -649,12 +620,38 @@ static unsigned int pfla02_detect_ramsize(void)
|
||||||
if (*p == *p1)
|
if (*p == *p1)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return RAM_4GB;
|
return RAM_MT256K;
|
||||||
}
|
}
|
||||||
|
|
||||||
void board_init_f(ulong dummy)
|
void board_init_f(ulong dummy)
|
||||||
{
|
{
|
||||||
unsigned int ramchip;
|
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
|
#ifdef CONFIG_CMD_NAND
|
||||||
/* Enable NAND */
|
/* Enable NAND */
|
||||||
setup_gpmi_nand();
|
setup_gpmi_nand();
|
||||||
|
@ -682,10 +679,23 @@ void board_init_f(ulong dummy)
|
||||||
setup_gpios();
|
setup_gpios();
|
||||||
|
|
||||||
/* DDR initialization */
|
/* DDR initialization */
|
||||||
spl_dram_init(&mt41k_xx[RAM_4GB]);
|
spl_dram_init(&sysinfo, &mt41k_xx[RAM_MT256K]);
|
||||||
ramchip = pfla02_detect_ramsize();
|
ramchip = pfla02_detect_chiptype();
|
||||||
if (ramchip != RAM_4GB)
|
debug("Detected chip %d\n", ramchip);
|
||||||
spl_dram_init(&mt41k_xx[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. */
|
/* Clear the BSS. */
|
||||||
memset(__bss_start, 0, __bss_end - __bss_start);
|
memset(__bss_start, 0, __bss_end - __bss_start);
|
||||||
|
|
|
@ -581,17 +581,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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)
|
static void spl_dram_init(int width)
|
||||||
{
|
{
|
||||||
struct mx6_ddr_sysinfo sysinfo = {
|
struct mx6_ddr_sysinfo sysinfo = {
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <dm/platform_data/serial_mxc.h>
|
#include <dm/platform_data/serial_mxc.h>
|
||||||
#include <dm/platdata.h>
|
#include <dm/platdata.h>
|
||||||
#include <fsl_esdhc.h>
|
#include <fsl_esdhc.h>
|
||||||
|
#include <g_dnl.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
#include <imx_thermal.h>
|
#include <imx_thermal.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
@ -1159,17 +1160,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000000FB, &ccm->ccosr);
|
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)
|
static void ddr_init(int *table, int size)
|
||||||
{
|
{
|
||||||
int i;
|
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
|
#endif
|
||||||
|
|
||||||
static struct mxc_serial_platdata mxc_serial_plat = {
|
static struct mxc_serial_platdata mxc_serial_plat = {
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <dm/platform_data/serial_mxc.h>
|
#include <dm/platform_data/serial_mxc.h>
|
||||||
#include <dm/platdata.h>
|
#include <dm/platdata.h>
|
||||||
#include <fsl_esdhc.h>
|
#include <fsl_esdhc.h>
|
||||||
|
#include <g_dnl.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
#include <imx_thermal.h>
|
#include <imx_thermal.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
@ -1036,17 +1037,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000000FB, &ccm->ccosr);
|
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)
|
static void ddr_init(int *table, int size)
|
||||||
{
|
{
|
||||||
int i;
|
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
|
#endif
|
||||||
|
|
||||||
static struct mxc_serial_platdata mxc_serial_plat = {
|
static struct mxc_serial_platdata mxc_serial_plat = {
|
||||||
|
|
|
@ -211,17 +211,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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)
|
static void spl_dram_init(void)
|
||||||
{
|
{
|
||||||
if (is_cpu_type(MXC_CPU_MX6DL)) {
|
if (is_cpu_type(MXC_CPU_MX6DL)) {
|
||||||
|
|
|
@ -266,17 +266,6 @@ static void ccgr_init(void)
|
||||||
writel(0x000003FF, &ccm->CCGR6);
|
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)
|
static void spl_dram_init(void)
|
||||||
{
|
{
|
||||||
if (is_cpu_type(MXC_CPU_MX6SOLO)) {
|
if (is_cpu_type(MXC_CPU_MX6SOLO)) {
|
||||||
|
|
|
@ -895,6 +895,13 @@ config CMD_USB
|
||||||
help
|
help
|
||||||
USB support.
|
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
|
config CMD_USB_MASS_STORAGE
|
||||||
bool "UMS usb mass storage"
|
bool "UMS usb mass storage"
|
||||||
help
|
help
|
||||||
|
|
|
@ -132,6 +132,7 @@ obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o
|
||||||
obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
|
obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
|
||||||
|
|
||||||
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.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_THOR_DOWNLOAD) += thordown.o
|
||||||
obj-$(CONFIG_CMD_XIMG) += ximg.o
|
obj-$(CONFIG_CMD_XIMG) += ximg.o
|
||||||
obj-$(CONFIG_CMD_YAFFS2) += yaffs2.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
|
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
|
endif
|
||||||
|
|
||||||
config SPL_WATCHDOG_SUPPORT
|
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_)DFU_SUPPORT) += spl_dfu.o
|
||||||
obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o
|
obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o
|
||||||
obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o
|
obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o
|
||||||
|
obj-$(CONFIG_$(SPL_TPL_)USB_SDP_SUPPORT) += spl_sdp.o
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -379,7 +379,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||||
if (spl_init())
|
if (spl_init())
|
||||||
hang();
|
hang();
|
||||||
}
|
}
|
||||||
#ifndef CONFIG_PPC
|
#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MX6)
|
||||||
/*
|
/*
|
||||||
* timer_init() does not exist on PPC systems. The timer is initialized
|
* timer_init() does not exist on PPC systems. The timer is initialized
|
||||||
* and enabled (decrementer) in interrupt_init() here.
|
* 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=y
|
||||||
CONFIG_SPL_DMA_SUPPORT=y
|
CONFIG_SPL_DMA_SUPPORT=y
|
||||||
CONFIG_SPL_I2C_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_HUSH_PARSER=y
|
||||||
CONFIG_SYS_PROMPT="Apalis iMX6 # "
|
CONFIG_SYS_PROMPT="Apalis iMX6 # "
|
||||||
CONFIG_CMD_BOOTZ=y
|
CONFIG_CMD_BOOTZ=y
|
||||||
|
@ -32,6 +35,7 @@ CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_I2C=y
|
CONFIG_CMD_I2C=y
|
||||||
CONFIG_CMD_MMC=y
|
CONFIG_CMD_MMC=y
|
||||||
CONFIG_CMD_USB=y
|
CONFIG_CMD_USB=y
|
||||||
|
CONFIG_CMD_USB_SDP=y
|
||||||
CONFIG_CMD_USB_MASS_STORAGE=y
|
CONFIG_CMD_USB_MASS_STORAGE=y
|
||||||
CONFIG_CMD_DHCP=y
|
CONFIG_CMD_DHCP=y
|
||||||
CONFIG_CMD_MII=y
|
CONFIG_CMD_MII=y
|
||||||
|
|
|
@ -16,6 +16,9 @@ CONFIG_BOARD_EARLY_INIT_F=y
|
||||||
CONFIG_SPL=y
|
CONFIG_SPL=y
|
||||||
CONFIG_SPL_DMA_SUPPORT=y
|
CONFIG_SPL_DMA_SUPPORT=y
|
||||||
CONFIG_SPL_I2C_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_HUSH_PARSER=y
|
||||||
CONFIG_SYS_PROMPT="Colibri iMX6 # "
|
CONFIG_SYS_PROMPT="Colibri iMX6 # "
|
||||||
CONFIG_CMD_BOOTZ=y
|
CONFIG_CMD_BOOTZ=y
|
||||||
|
@ -32,6 +35,7 @@ CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_I2C=y
|
CONFIG_CMD_I2C=y
|
||||||
CONFIG_CMD_MMC=y
|
CONFIG_CMD_MMC=y
|
||||||
CONFIG_CMD_USB=y
|
CONFIG_CMD_USB=y
|
||||||
|
CONFIG_CMD_USB_SDP=y
|
||||||
CONFIG_CMD_USB_MASS_STORAGE=y
|
CONFIG_CMD_USB_MASS_STORAGE=y
|
||||||
CONFIG_CMD_DHCP=y
|
CONFIG_CMD_DHCP=y
|
||||||
CONFIG_CMD_MII=y
|
CONFIG_CMD_MII=y
|
||||||
|
|
|
@ -49,3 +49,4 @@ CONFIG_DEBUG_UART_CLOCK=24000000
|
||||||
CONFIG_MXC_UART=y
|
CONFIG_MXC_UART=y
|
||||||
CONFIG_IMX_THERMAL=y
|
CONFIG_IMX_THERMAL=y
|
||||||
CONFIG_VIDEO_IPUV3=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 (!(config_val & IMX_NO_PAD_CTL)) {
|
||||||
if (info->flags & SHARE_MUX_CONF_REG) {
|
if (info->flags & SHARE_MUX_CONF_REG) {
|
||||||
clrsetbits_le32(info->base + conf_reg,
|
clrsetbits_le32(info->base + conf_reg,
|
||||||
info->mux_mask, config_val);
|
~info->mux_mask, config_val);
|
||||||
} else {
|
} else {
|
||||||
writel(config_val, info->base + conf_reg);
|
writel(config_val, info->base + conf_reg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,11 @@
|
||||||
|
|
||||||
#include "pinctrl-imx.h"
|
#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,
|
.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[] = {
|
static const struct udevice_id imx7ulp_pinctrl_match[] = {
|
||||||
{ .compatible = "fsl,imx7ulp-iomuxc-0", .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_info },
|
{ .compatible = "fsl,imx7ulp-iomuxc-1", .data = (ulong)&imx7ulp_pinctrl_soc_info1 },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,13 @@ config USB_GADGET_DOWNLOAD
|
||||||
|
|
||||||
if 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
|
config G_DNL_MANUFACTURER
|
||||||
string "Vendor name of USB device"
|
string "Vendor name of USB device"
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o
|
||||||
ifdef CONFIG_SPL_BUILD
|
ifdef CONFIG_SPL_BUILD
|
||||||
obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += g_dnl.o
|
obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += g_dnl.o
|
||||||
obj-$(CONFIG_SPL_DFU_SUPPORT) += f_dfu.o
|
obj-$(CONFIG_SPL_DFU_SUPPORT) += f_dfu.o
|
||||||
|
obj-$(CONFIG_SPL_USB_SDP_SUPPORT) += f_sdp.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# new USB gadget layer dependencies
|
# 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_DFU) += f_dfu.o
|
||||||
obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o
|
obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o
|
||||||
obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o
|
obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o
|
||||||
|
obj-$(CONFIG_USB_FUNCTION_SDP) += f_sdp.o
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
ifdef CONFIG_USB_ETHER
|
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
|
# define CONFIG_MII
|
||||||
#endif
|
#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 */
|
/* Framebuffer */
|
||||||
#ifdef CONFIG_VIDEO_IPUV3
|
#ifdef CONFIG_VIDEO_IPUV3
|
||||||
# define CONFIG_IPUV3_CLK 260000000
|
# 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 a new issue