summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/cpu/armv7/mx6/soc.c103
-rw-r--r--arch/arm/include/asm/arch-mx6/mx6_usbphy.h480
-rw-r--r--arch/arm/include/asm/imx-common/boot_mode.h24
-rw-r--r--arch/arm/lib/board.c12
-rw-r--r--board/freescale/common/Makefile3
-rw-r--r--board/freescale/common/recovery.c78
-rw-r--r--board/freescale/mx6qsabreauto/mx6qsabreauto.c134
-rw-r--r--board/freescale/mx6sabresd/mx6sabresd.c131
-rw-r--r--board/freescale/mx6slevk/mx6slevk.c99
-rw-r--r--board/freescale/mx6sxsabreauto/mx6sxsabreauto.c107
-rw-r--r--board/freescale/mx6sxsabresd/mx6sxsabresd.c116
-rw-r--r--common/board_r.c23
-rw-r--r--common/cmd_bootm.c2
-rw-r--r--common/cmd_fastboot.c1834
-rw-r--r--configs/mx6dlsabreautoandroid_defconfig7
-rw-r--r--configs/mx6dlsabreautoandroid_nand_defconfig7
-rw-r--r--configs/mx6dlsabresdandroid_defconfig7
-rw-r--r--configs/mx6qsabreautoandroid_defconfig7
-rw-r--r--configs/mx6qsabreautoandroid_nand_defconfig7
-rw-r--r--configs/mx6qsabresdandroid_defconfig7
-rw-r--r--configs/mx6slevkandroid_defconfig7
-rw-r--r--configs/mx6solosabreautoandroid_defconfig7
-rw-r--r--configs/mx6solosabreautoandroid_nand_defconfig7
-rw-r--r--configs/mx6solosabresdandroid_defconfig7
-rw-r--r--configs/mx6sxsabreautoandroid_defconfig7
-rw-r--r--configs/mx6sxsabreautoandroid_nand_defconfig7
-rw-r--r--configs/mx6sxsabresdandroid_defconfig7
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/fastboot/Makefile8
-rw-r--r--drivers/fastboot/fastboot.c1127
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/imx_udc.c1190
-rw-r--r--include/configs/mx6sabre_common.h6
-rw-r--r--include/configs/mx6sabreandroid_common.h62
-rw-r--r--include/configs/mx6slevk.h4
-rw-r--r--include/configs/mx6slevkandroid.h77
-rw-r--r--include/configs/mx6sxsabreautoandroid.h61
-rw-r--r--include/configs/mx6sxsabresdandroid.h53
-rw-r--r--include/fastboot.h376
-rw-r--r--include/recovery.h20
-rw-r--r--include/usb/imx_udc.h573
41 files changed, 6767 insertions, 29 deletions
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c
index 7bd2118..d81dd1a 100644
--- a/arch/arm/cpu/armv7/mx6/soc.c
+++ b/arch/arm/cpu/armv7/mx6/soc.c
@@ -24,6 +24,15 @@
#include <asm/arch/crm_regs.h>
#include <dm.h>
#include <imx_thermal.h>
+#ifdef CONFIG_FASTBOOT
+#ifdef CONFIG_ANDROID_RECOVERY
+#include <recovery.h>
+#endif
+#endif
+#ifdef CONFIG_IMX_UDC
+#include <asm/arch/mx6_usbphy.h>
+#include <usb/imx_udc.h>
+#endif
enum ldo_reg {
LDO_ARM,
@@ -977,3 +986,97 @@ void v7_outer_cache_disable(void)
clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN);
}
#endif /* !CONFIG_SYS_L2CACHE_OFF */
+
+#ifdef CONFIG_FASTBOOT
+
+#ifdef CONFIG_ANDROID_RECOVERY
+#define ANDROID_RECOVERY_BOOT (1 << 7)
+/* check if the recovery bit is set by kernel, it can be set by kernel
+ * issue a command '# reboot recovery' */
+int recovery_check_and_clean_flag(void)
+{
+ int flag_set = 0;
+ u32 reg;
+ reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR);
+
+ flag_set = !!(reg & ANDROID_RECOVERY_BOOT);
+ printf("check_and_clean: reg %x, flag_set %d\n", reg, flag_set);
+ /* clean it in case looping infinite here.... */
+ if (flag_set) {
+ reg &= ~ANDROID_RECOVERY_BOOT;
+ writel(reg, SNVS_BASE_ADDR + SNVS_LPGPR);
+ }
+
+ return flag_set;
+}
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#define ANDROID_FASTBOOT_BOOT (1 << 8)
+/* check if the recovery bit is set by kernel, it can be set by kernel
+ * issue a command '# reboot fastboot' */
+int fastboot_check_and_clean_flag(void)
+{
+ int flag_set = 0;
+ u32 reg;
+
+ reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR);
+
+ flag_set = !!(reg & ANDROID_FASTBOOT_BOOT);
+
+ /* clean it in case looping infinite here.... */
+ if (flag_set) {
+ reg &= ~ANDROID_FASTBOOT_BOOT;
+ writel(reg, SNVS_BASE_ADDR + SNVS_LPGPR);
+ }
+
+ return flag_set;
+}
+#endif /*CONFIG_FASTBOOT*/
+
+#ifdef CONFIG_IMX_UDC
+void set_usboh3_clk(void)
+{
+ udc_pins_setting();
+}
+
+void set_usb_phy1_clk(void)
+{
+ /* make sure pll3 is enable here */
+ struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+
+ writel((BM_ANADIG_USB1_CHRG_DETECT_EN_B |
+ BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B),
+ &ccm_regs->usb1_chrg_detect_set);
+
+ writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS,
+ &ccm_regs->analog_usb1_pll_480_ctrl_set);
+}
+void enable_usb_phy1_clk(unsigned char enable)
+{
+ if (enable)
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL_CLR);
+ else
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL_SET);
+}
+
+void reset_usb_phy1(void)
+{
+ /* Reset USBPHY module */
+ u32 temp;
+ temp = readl(USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL);
+ temp |= BM_USBPHY_CTRL_SFTRST;
+ writel(temp, USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL);
+ udelay(10);
+
+ /* Remove CLKGATE and SFTRST */
+ temp = readl(USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL);
+ temp &= ~(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST);
+ writel(temp, USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL);
+ udelay(10);
+
+ /* Power up the PHY */
+ writel(0, USB_PHY0_BASE_ADDR + HW_USBPHY_PWD);
+}
+#endif
diff --git a/arch/arm/include/asm/arch-mx6/mx6_usbphy.h b/arch/arm/include/asm/arch-mx6/mx6_usbphy.h
new file mode 100644
index 0000000..0d9a4f5
--- /dev/null
+++ b/arch/arm/include/asm/arch-mx6/mx6_usbphy.h
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2008-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_MX6_MX6_USBPHY_H__
+#define __ASM_ARCH_MX6_MX6_USBPHY_H__
+
+#define HW_USBPHY_PWD (0x00000000)
+#define HW_USBPHY_PWD_SET (0x00000004)
+#define HW_USBPHY_PWD_CLR (0x00000008)
+#define HW_USBPHY_PWD_TOG (0x0000000c)
+
+#define BP_USBPHY_PWD_RSVD2 21
+#define BM_USBPHY_PWD_RSVD2 0xFFE00000
+#define BF_USBPHY_PWD_RSVD2(v) \
+ (((v) << 21) & BM_USBPHY_PWD_RSVD2)
+#define BM_USBPHY_PWD_RXPWDRX 0x00100000
+#define BM_USBPHY_PWD_RXPWDDIFF 0x00080000
+#define BM_USBPHY_PWD_RXPWD1PT1 0x00040000
+#define BM_USBPHY_PWD_RXPWDENV 0x00020000
+#define BP_USBPHY_PWD_RSVD1 13
+#define BM_USBPHY_PWD_RSVD1 0x0001E000
+#define BF_USBPHY_PWD_RSVD1(v) \
+ (((v) << 13) & BM_USBPHY_PWD_RSVD1)
+#define BM_USBPHY_PWD_TXPWDV2I 0x00001000
+#define BM_USBPHY_PWD_TXPWDIBIAS 0x00000800
+#define BM_USBPHY_PWD_TXPWDFS 0x00000400
+#define BP_USBPHY_PWD_RSVD0 0
+#define BM_USBPHY_PWD_RSVD0 0x000003FF
+#define BF_USBPHY_PWD_RSVD0(v) \
+ (((v) << 0) & BM_USBPHY_PWD_RSVD0)
+
+#define HW_USBPHY_TX (0x00000010)
+#define HW_USBPHY_TX_SET (0x00000014)
+#define HW_USBPHY_TX_CLR (0x00000018)
+#define HW_USBPHY_TX_TOG (0x0000001c)
+
+#define BP_USBPHY_TX_RSVD5 29
+#define BM_USBPHY_TX_RSVD5 0xE0000000
+#define BF_USBPHY_TX_RSVD5(v) \
+ (((v) << 29) & BM_USBPHY_TX_RSVD5)
+#define BP_USBPHY_TX_USBPHY_TX_EDGECTRL 26
+#define BM_USBPHY_TX_USBPHY_TX_EDGECTRL 0x1C000000
+#define BF_USBPHY_TX_USBPHY_TX_EDGECTRL(v) \
+ (((v) << 26) & BM_USBPHY_TX_USBPHY_TX_EDGECTRL)
+#define BM_USBPHY_TX_USBPHY_TX_SYNC_INVERT 0x02000000
+#define BM_USBPHY_TX_USBPHY_TX_SYNC_MUX 0x01000000
+#define BP_USBPHY_TX_RSVD4 22
+#define BM_USBPHY_TX_RSVD4 0x00C00000
+#define BF_USBPHY_TX_RSVD4(v) \
+ (((v) << 22) & BM_USBPHY_TX_RSVD4)
+#define BM_USBPHY_TX_TXENCAL45DP 0x00200000
+#define BM_USBPHY_TX_RSVD3 0x00100000
+#define BP_USBPHY_TX_TXCAL45DP 16
+#define BM_USBPHY_TX_TXCAL45DP 0x000F0000
+#define BF_USBPHY_TX_TXCAL45DP(v) \
+ (((v) << 16) & BM_USBPHY_TX_TXCAL45DP)
+#define BP_USBPHY_TX_RSVD2 14
+#define BM_USBPHY_TX_RSVD2 0x0000C000
+#define BF_USBPHY_TX_RSVD2(v) \
+ (((v) << 14) & BM_USBPHY_TX_RSVD2)
+#define BM_USBPHY_TX_TXENCAL45DN 0x00002000
+#define BM_USBPHY_TX_RSVD1 0x00001000
+#define BP_USBPHY_TX_TXCAL45DN 8
+#define BM_USBPHY_TX_TXCAL45DN 0x00000F00
+#define BF_USBPHY_TX_TXCAL45DN(v) \
+ (((v) << 8) & BM_USBPHY_TX_TXCAL45DN)
+#define BP_USBPHY_TX_RSVD0 4
+#define BM_USBPHY_TX_RSVD0 0x000000F0
+#define BF_USBPHY_TX_RSVD0(v) \
+ (((v) << 4) & BM_USBPHY_TX_RSVD0)
+#define BP_USBPHY_TX_D_CAL 0
+#define BM_USBPHY_TX_D_CAL 0x0000000F
+#define BF_USBPHY_TX_D_CAL(v) \
+ (((v) << 0) & BM_USBPHY_TX_D_CAL)
+
+#define HW_USBPHY_RX (0x00000020)
+#define HW_USBPHY_RX_SET (0x00000024)
+#define HW_USBPHY_RX_CLR (0x00000028)
+#define HW_USBPHY_RX_TOG (0x0000002c)
+
+#define BP_USBPHY_RX_RSVD2 23
+#define BM_USBPHY_RX_RSVD2 0xFF800000
+#define BF_USBPHY_RX_RSVD2(v) \
+ (((v) << 23) & BM_USBPHY_RX_RSVD2)
+#define BM_USBPHY_RX_RXDBYPASS 0x00400000
+#define BP_USBPHY_RX_RSVD1 7
+#define BM_USBPHY_RX_RSVD1 0x003FFF80
+#define BF_USBPHY_RX_RSVD1(v) \
+ (((v) << 7) & BM_USBPHY_RX_RSVD1)
+#define BP_USBPHY_RX_DISCONADJ 4
+#define BM_USBPHY_RX_DISCONADJ 0x00000070
+#define BF_USBPHY_RX_DISCONADJ(v) \
+ (((v) << 4) & BM_USBPHY_RX_DISCONADJ)
+#define BM_USBPHY_RX_RSVD0 0x00000008
+#define BP_USBPHY_RX_ENVADJ 0
+#define BM_USBPHY_RX_ENVADJ 0x00000007
+#define BF_USBPHY_RX_ENVADJ(v) \
+ (((v) << 0) & BM_USBPHY_RX_ENVADJ)
+
+#define HW_USBPHY_CTRL (0x00000030)
+#define HW_USBPHY_CTRL_SET (0x00000034)
+#define HW_USBPHY_CTRL_CLR (0x00000038)
+#define HW_USBPHY_CTRL_TOG (0x0000003c)
+
+#define BM_USBPHY_CTRL_SFTRST 0x80000000
+#define BM_USBPHY_CTRL_CLKGATE 0x40000000
+#define BM_USBPHY_CTRL_UTMI_SUSPENDM 0x20000000
+#define BM_USBPHY_CTRL_HOST_FORCE_LS_SE0 0x10000000
+#define BM_USBPHY_CTRL_OTG_ID_VALUE 0x08000000
+#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS 0x04000000
+#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE 0x02000000
+#define BM_USBPHY_CTRL_FSDLL_RST_EN 0x01000000
+#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP 0x00800000
+#define BM_USBPHY_CTRL_ENIDCHG_WKUP 0x00400000
+#define BM_USBPHY_CTRL_ENDPDMCHG_WKUP 0x00200000
+#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD 0x00100000
+#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE 0x00080000
+#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL 0x00040000
+#define BM_USBPHY_CTRL_WAKEUP_IRQ 0x00020000
+#define BM_USBPHY_CTRL_ENIRQWAKEUP 0x00010000
+#define BM_USBPHY_CTRL_ENUTMILEVEL3 0x00008000
+#define BM_USBPHY_CTRL_ENUTMILEVEL2 0x00004000
+#define BM_USBPHY_CTRL_DATA_ON_LRADC 0x00002000
+#define BM_USBPHY_CTRL_DEVPLUGIN_IRQ 0x00001000
+#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN 0x00000800
+#define BM_USBPHY_CTRL_RESUME_IRQ 0x00000400
+#define BM_USBPHY_CTRL_ENIRQRESUMEDETECT 0x00000200
+#define BM_USBPHY_CTRL_RESUMEIRQSTICKY 0x00000100
+#define BM_USBPHY_CTRL_ENOTGIDDETECT 0x00000080
+#define BM_USBPHY_CTRL_OTG_ID_CHG_IRQ 0x00000040
+#define BM_USBPHY_CTRL_DEVPLUGIN_POLARITY 0x00000020
+#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT 0x00000010
+#define BM_USBPHY_CTRL_HOSTDISCONDETECT_IRQ 0x00000008
+#define BM_USBPHY_CTRL_ENIRQHOSTDISCON 0x00000004
+#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT 0x00000002
+#define BM_USBPHY_CTRL_ENOTG_ID_CHG_IRQ 0x00000001
+
+#define HW_USBPHY_STATUS (0x00000040)
+
+#define BP_USBPHY_STATUS_RSVD4 11
+#define BM_USBPHY_STATUS_RSVD4 0xFFFFF800
+#define BF_USBPHY_STATUS_RSVD4(v) \
+ (((v) << 11) & BM_USBPHY_STATUS_RSVD4)
+#define BM_USBPHY_STATUS_RESUME_STATUS 0x00000400
+#define BM_USBPHY_STATUS_RSVD3 0x00000200
+#define BM_USBPHY_STATUS_OTGID_STATUS 0x00000100
+#define BM_USBPHY_STATUS_RSVD2 0x00000080
+#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS 0x00000040
+#define BP_USBPHY_STATUS_RSVD1 4
+#define BM_USBPHY_STATUS_RSVD1 0x00000030
+#define BF_USBPHY_STATUS_RSVD1(v) \
+ (((v) << 4) & BM_USBPHY_STATUS_RSVD1)
+#define BM_USBPHY_STATUS_HOSTDISCONDETECT_STATUS 0x00000008
+#define BP_USBPHY_STATUS_RSVD0 0
+#define BM_USBPHY_STATUS_RSVD0 0x00000007
+#define BF_USBPHY_STATUS_RSVD0(v) \
+ (((v) << 0) & BM_USBPHY_STATUS_RSVD0)
+
+#define HW_USBPHY_DEBUG (0x00000050)
+#define HW_USBPHY_DEBUG_SET (0x00000054)
+#define HW_USBPHY_DEBUG_CLR (0x00000058)
+#define HW_USBPHY_DEBUG_TOG (0x0000005c)
+
+#define BM_USBPHY_DEBUG_RSVD3 0x80000000
+#define BM_USBPHY_DEBUG_CLKGATE 0x40000000
+#define BM_USBPHY_DEBUG_HOST_RESUME_DEBUG 0x20000000
+#define BP_USBPHY_DEBUG_SQUELCHRESETLENGTH 25
+#define BM_USBPHY_DEBUG_SQUELCHRESETLENGTH 0x1E000000
+#define BF_USBPHY_DEBUG_SQUELCHRESETLENGTH(v) \
+ (((v) << 25) & BM_USBPHY_DEBUG_SQUELCHRESETLENGTH)
+#define BM_USBPHY_DEBUG_ENSQUELCHRESET 0x01000000
+#define BP_USBPHY_DEBUG_RSVD2 21
+#define BM_USBPHY_DEBUG_RSVD2 0x00E00000
+#define BF_USBPHY_DEBUG_RSVD2(v) \
+ (((v) << 21) & BM_USBPHY_DEBUG_RSVD2)
+#define BP_USBPHY_DEBUG_SQUELCHRESETCOUNT 16
+#define BM_USBPHY_DEBUG_SQUELCHRESETCOUNT 0x001F0000
+#define BF_USBPHY_DEBUG_SQUELCHRESETCOUNT(v) \
+ (((v) << 16) & BM_USBPHY_DEBUG_SQUELCHRESETCOUNT)
+#define BP_USBPHY_DEBUG_RSVD1 13
+#define BM_USBPHY_DEBUG_RSVD1 0x0000E000
+#define BF_USBPHY_DEBUG_RSVD1(v) \
+ (((v) << 13) & BM_USBPHY_DEBUG_RSVD1)
+#define BM_USBPHY_DEBUG_ENTX2RXCOUNT 0x00001000
+#define BP_USBPHY_DEBUG_TX2RXCOUNT 8
+#define BM_USBPHY_DEBUG_TX2RXCOUNT 0x00000F00
+#define BF_USBPHY_DEBUG_TX2RXCOUNT(v) \
+ (((v) << 8) & BM_USBPHY_DEBUG_TX2RXCOUNT)
+#define BP_USBPHY_DEBUG_RSVD0 6
+#define BM_USBPHY_DEBUG_RSVD0 0x000000C0
+#define BF_USBPHY_DEBUG_RSVD0(v) \
+ (((v) << 6) & BM_USBPHY_DEBUG_RSVD0)
+#define BP_USBPHY_DEBUG_ENHSTPULLDOWN 4
+#define BM_USBPHY_DEBUG_ENHSTPULLDOWN 0x00000030
+#define BF_USBPHY_DEBUG_ENHSTPULLDOWN(v) \
+ (((v) << 4) & BM_USBPHY_DEBUG_ENHSTPULLDOWN)
+#define BP_USBPHY_DEBUG_HSTPULLDOWN 2
+#define BM_USBPHY_DEBUG_HSTPULLDOWN 0x0000000C
+#define BF_USBPHY_DEBUG_HSTPULLDOWN(v) \
+ (((v) << 2) & BM_USBPHY_DEBUG_HSTPULLDOWN)
+#define BM_USBPHY_DEBUG_DEBUG_INTERFACE_HOLD 0x00000002
+#define BM_USBPHY_DEBUG_OTGIDPIOLOCK 0x00000001
+
+#define HW_USBPHY_DEBUG0_STATUS (0x00000060)
+
+#define BP_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 26
+#define BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 0xFC000000
+#define BF_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT(v) \
+ (((v) << 26) & BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT)
+#define BP_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 16
+#define BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 0x03FF0000
+#define BF_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT(v) \
+ (((v) << 16) & BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT)
+#define BP_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0
+#define BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0x0000FFFF
+#define BF_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT(v) \
+ (((v) << 0) & BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT)
+
+#define HW_USBPHY_DEBUG1 (0x00000070)
+#define HW_USBPHY_DEBUG1_SET (0x00000074)
+#define HW_USBPHY_DEBUG1_CLR (0x00000078)
+#define HW_USBPHY_DEBUG1_TOG (0x0000007c)
+
+#define BP_USBPHY_DEBUG1_RSVD1 15
+#define BM_USBPHY_DEBUG1_RSVD1 0xFFFF8000
+#define BF_USBPHY_DEBUG1_RSVD1(v) \
+ (((v) << 15) & BM_USBPHY_DEBUG1_RSVD1)
+#define BP_USBPHY_DEBUG1_ENTAILADJVD 13
+#define BM_USBPHY_DEBUG1_ENTAILADJVD 0x00006000
+#define BF_USBPHY_DEBUG1_ENTAILADJVD(v) \
+ (((v) << 13) & BM_USBPHY_DEBUG1_ENTAILADJVD)
+#define BM_USBPHY_DEBUG1_ENTX2TX 0x00001000
+#define BP_USBPHY_DEBUG1_RSVD0 4
+#define BM_USBPHY_DEBUG1_RSVD0 0x00000FF0
+#define BF_USBPHY_DEBUG1_RSVD0(v) \
+ (((v) << 4) & BM_USBPHY_DEBUG1_RSVD0)
+#define BP_USBPHY_DEBUG1_DBG_ADDRESS 0
+#define BM_USBPHY_DEBUG1_DBG_ADDRESS 0x0000000F
+#define BF_USBPHY_DEBUG1_DBG_ADDRESS(v) \
+ (((v) << 0) & BM_USBPHY_DEBUG1_DBG_ADDRESS)
+
+#define HW_USBPHY_VERSION (0x00000080)
+
+#define BP_USBPHY_VERSION_MAJOR 24
+#define BM_USBPHY_VERSION_MAJOR 0xFF000000
+#define BF_USBPHY_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_USBPHY_VERSION_MAJOR)
+#define BP_USBPHY_VERSION_MINOR 16
+#define BM_USBPHY_VERSION_MINOR 0x00FF0000
+#define BF_USBPHY_VERSION_MINOR(v) \
+ (((v) << 16) & BM_USBPHY_VERSION_MINOR)
+#define BP_USBPHY_VERSION_STEP 0
+#define BM_USBPHY_VERSION_STEP 0x0000FFFF
+#define BF_USBPHY_VERSION_STEP(v) \
+ (((v) << 0) & BM_USBPHY_VERSION_STEP)
+
+#define HW_USBPHY_IP (0x00000090)
+#define HW_USBPHY_IP_SET (0x00000094)
+#define HW_USBPHY_IP_CLR (0x00000098)
+#define HW_USBPHY_IP_TOG (0x0000009c)
+
+#define BP_USBPHY_IP_RSVD1 25
+#define BM_USBPHY_IP_RSVD1 0xFE000000
+#define BF_USBPHY_IP_RSVD1(v) \
+ (((v) << 25) & BM_USBPHY_IP_RSVD1)
+#define BP_USBPHY_IP_DIV_SEL 23
+#define BM_USBPHY_IP_DIV_SEL 0x01800000
+#define BF_USBPHY_IP_DIV_SEL(v) \
+ (((v) << 23) & BM_USBPHY_IP_DIV_SEL)
+#define BV_USBPHY_IP_DIV_SEL__DEFAULT 0x0
+#define BV_USBPHY_IP_DIV_SEL__LOWER 0x1
+#define BV_USBPHY_IP_DIV_SEL__LOWEST 0x2
+#define BV_USBPHY_IP_DIV_SEL__UNDEFINED 0x3
+#define BP_USBPHY_IP_LFR_SEL 21
+#define BM_USBPHY_IP_LFR_SEL 0x00600000
+#define BF_USBPHY_IP_LFR_SEL(v) \
+ (((v) << 21) & BM_USBPHY_IP_LFR_SEL)
+#define BV_USBPHY_IP_LFR_SEL__DEFAULT 0x0
+#define BV_USBPHY_IP_LFR_SEL__TIMES_2 0x1
+#define BV_USBPHY_IP_LFR_SEL__TIMES_05 0x2
+#define BV_USBPHY_IP_LFR_SEL__UNDEFINED 0x3
+#define BP_USBPHY_IP_CP_SEL 19
+#define BM_USBPHY_IP_CP_SEL 0x00180000
+#define BF_USBPHY_IP_CP_SEL(v) \
+ (((v) << 19) & BM_USBPHY_IP_CP_SEL)
+#define BV_USBPHY_IP_CP_SEL__DEFAULT 0x0
+#define BV_USBPHY_IP_CP_SEL__TIMES_2 0x1
+#define BV_USBPHY_IP_CP_SEL__TIMES_05 0x2
+#define BV_USBPHY_IP_CP_SEL__UNDEFINED 0x3
+#define BM_USBPHY_IP_TSTI_TX_DP 0x00040000
+#define BM_USBPHY_IP_TSTI_TX_DM 0x00020000
+#define BM_USBPHY_IP_ANALOG_TESTMODE 0x00010000
+#define BP_USBPHY_IP_RSVD0 3
+#define BM_USBPHY_IP_RSVD0 0x0000FFF8
+#define BF_USBPHY_IP_RSVD0(v) \
+ (((v) << 3) & BM_USBPHY_IP_RSVD0)
+#define BM_USBPHY_IP_EN_USB_CLKS 0x00000004
+#define BM_USBPHY_IP_PLL_LOCKED 0x00000002
+#define BM_USBPHY_IP_PLL_POWER 0x00000001
+
+/* The register definition for usbphy which includes at usb core's register set
+ * (from USB_CORE_BASE + 0x800)
+ */
+#define USB_CTRL USBOTHER_REG(0x00) /* USB OTG Control register */
+#define USB_H1_CTRL USBOTHER_REG(0x04) /* USB H1 Control register */
+#define USB_H2_CTRL USBOTHER_REG(0x08) /* USB H2 Control register */
+#define USB_H3_CTRL USBOTHER_REG(0x0c) /* USB H3 Control register */
+
+/* USB Host2 HSIC Control Register */
+#define USB_UH2_HSIC_CTRL USBOTHER_REG(0x10)
+
+/* USB Host3 HSIC Control Register */
+#define USB_UH3_HSIC_CTRL USBOTHER_REG(0x14)
+
+/* OTG UTMI PHY Control 0 Register */
+#define USB_OTG_PHY_CTRL_0 USBOTHER_REG(0x18)
+
+/* OTG UTMI PHY Control 1 Register */
+#define USB_H1_PHY_CTRL_0 USBOTHER_REG(0x1c)
+
+/* USB Host2 HSIC DLL Configuration Register 1 */
+#define USB_UH2_HSIC_DLL_CFG1 USBOTHER_REG(0x20)
+
+/* USB Host2 HSIC DLL Configuration Register 2 */
+#define USB_UH2_HSIC_DLL_CFG2 USBOTHER_REG(0x24)
+
+/* USB Host2 HSIC DLL Configuration Register 3 */
+#define USB_UH2_HSIC_DLL_CFG3 USBOTHER_REG(0x28)
+
+/* USB Host3 HSIC DLL Configuration Register 1 */
+#define USB_UH3_HSIC_DLL_CFG1 USBOTHER_REG(0x30)
+
+/* USB Host3 HSIC DLL Configuration Register 2 */
+#define USB_UH3_HSIC_DLL_CFG2 USBOTHER_REG(0x34)
+
+/* USB Host3 HSIC DLL Configuration Register 3 */
+#define USB_UH3_HSIC_DLL_CFG3 USBOTHER_REG(0x38)
+
+/*
+ * register bits
+ */
+
+/* USBCTRL */
+#define UCTRL_OSIC_MASK (3 << 29) /* OTG Serial Interface Config: */
+#define UCTRL_OSIC_DU6 (0 << 29) /* Differential/unidirectional 6 wire */
+#define UCTRL_OSIC_DB4 (1 << 29) /* Differential/bidirectional 4 wire */
+#define UCTRL_OSIC_SU6 (2 << 29) /* single-ended/unidirectional 6 wire */
+#define UCTRL_OSIC_SB3 (3 << 29) /* single-ended/bidirectional 3 wire */
+#define UCTRL_OUIE (1 << 28) /* OTG ULPI intr enable */
+#define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */
+#define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */
+#define UCTRL_OPM (1 << 24) /* OTG power mask */
+#define UCTRL_O_PWR_POL (1 << 24) /* OTG power pin polarity */
+#define UCTRL_H2WIR (1 << 17) /* HOST2 wakeup intr request received */
+#define UCTRL_H2SIC_MASK (3 << 21) /* HOST2 Serial Interface Config: */
+#define UCTRL_H2SIC_DU6 (0 << 21) /* Differential/unidirectional 6 wire */
+#define UCTRL_H2SIC_DB4 (1 << 21) /* Differential/bidirectional 4 wire */
+#define UCTRL_H2SIC_SU6 (2 << 21) /* single-ended/unidirectional 6 wire */
+#define UCTRL_H2SIC_SB3 (3 << 21) /* single-ended/bidirectional 3 wire */
+#define UCTRL_H2UIE (1 << 8) /* HOST2 ULPI intr enable */
+#define UCTRL_H2WIE (1 << 7) /* HOST2 wakeup intr enable */
+#define UCTRL_H2PP 0 /* Power Polarity for uh2 */
+#define UCTRL_H2PM (1 << 4) /* HOST2 power mask */
+#define UCTRL_H2OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */
+#define UCTRL_H2OIDWK_EN (1 << 5) /* OTG ID Wakeup Enable */
+
+#define UCTRL_H1WIR (1 << 15) /* HOST1 wakeup intr request received */
+#define UCTRL_H1SIC_MASK (3 << 13) /* HOST1 Serial Interface Config: */
+#define UCTRL_H1SIC_DU6 (0 << 13) /* Differential/unidirectional 6 wire */
+#define UCTRL_H1SIC_DB4 (1 << 13) /* Differential/bidirectional 4 wire */
+#define UCTRL_H1SIC_SU6 (2 << 13) /* single-ended/unidirectional 6 wire */
+#define UCTRL_H1SIC_SB3 (3 << 13) /* single-ended/bidirectional 3 wire */
+#define UCTRL_OLOCKD (1 << 13) /* otg lock disable */
+#define UCTRL_H2LOCKD (1 << 12) /* HOST2 lock disable */
+#define UCTRL_H1UIE (1 << 12) /* Host1 ULPI interrupt enable */
+
+#define UCTRL_PP (1 << 11) /* power polarity bit */
+#define UCTRL_H1WIE (1 << 11) /* HOST1 wakeup intr enable */
+#define UCTRL_H1BPVAL_RXDP (1 << 10) /* HOST1 RxDp status in bypass mode */
+#define UCTRL_XCSO (1 << 10) /* Xcvr Clock Select for OTG port */
+#define UCTRL_H1BPVAL_RXDM (1 << 9) /* HOST1 RxDm status in bypass mode */
+#define UCTRL_XCSH2 (1 << 9) /* Xcvr Clock Select for Host port */
+#define UCTRL_H1PM (1 << 8) /* HOST1 power mask */
+#define UCTRL_IP_PULIDP (1 << 8) /* Ipp_Puimpel_Pullup_Dp */
+
+#define UCTRL_IP_PUE_UP (1 << 7) /* ipp_pue_pullup_dp */
+#define UCTRL_IP_PUE_DOWN (1 << 6) /* ipp_pue_pulldwn_dpdm */
+#define UCTRL_H2DT (1 << 5) /* HOST2 TLL disabled */
+#define UCTRL_H1DT (1 << 4) /* HOST1 TLL disabled */
+#define UCTRL_USBTE (1 << 4) /* USBT Transceiver enable */
+#define UCTRL_OCPOL (1 << 3) /* OverCurrent Polarity */
+#define UCTRL_OCE (1 << 2) /* OverCurrent Enable */
+#define UCTRL_H2OCPOL (1 << 2) /* OverCurrent Polarity of Host2 */
+#define UCTRL_H2OCS (1 << 1) /* Host OverCurrent State */
+#define UCTRL_BPE (1 << 0) /* bypass mode enable */
+#define UCTRL_OTD (1 << 0) /* OTG TLL Disable */
+#define UCTRL_OOCS (1 << 0) /* OTG OverCurrent State */
+
+/* OTG_MIRROR */
+#define OTGM_SESEND (1 << 4) /* B device session end */
+#define OTGM_VBUSVAL (1 << 3) /* Vbus valid */
+#define OTGM_BSESVLD (1 << 2) /* B session Valid */
+#define OTGM_ASESVLD (1 << 1) /* A session Valid */
+#define OTGM_IDIDG (1 << 0) /* OTG ID pin status */
+ /* 1=high: Operate as B-device */
+ /* 0=low : Operate as A-device */
+
+/* USB_PHY_CTRL_FUNC */
+/* PHY control0 Register Bit Masks */
+#define USB_UTMI_PHYCTRL_CONF2 (1 << 26)
+
+#define USB_UTMI_PHYCTRL_UTMI_ENABLE (1 << 24)
+#define USB_UTMI_PHYCTRL_CHGRDETEN (1 << 24) /* Enable Charger Detector */
+#define USB_UTMI_PHYCTRL_CHGRDETON (1 << 23) /* Charger Detector Power On Control */
+#define USB_UTMI_PHYCTRL_OC_POL (1 << 9) /* OTG Polarity of Overcurrent */
+#define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */
+#define USB_UH1_OC_DIS (1 << 5) /* UH1 Disable Overcurrent Event */
+#define USB_UH1_OC_POL (1 << 6) /* UH1 Polarity of OC,Low active */
+/* USB_PHY_CTRL_FUNC2*/
+#define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3
+#define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0
+#define USB_UTMI_PHYCTRL2_HSDEVSEL_MASK 0x3
+#define USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT 19
+
+/* USB_CTRL_1 */
+#define USB_CTRL_UH1_EXT_CLK_EN (1 << 25)
+#define USB_CTRL_UH2_EXT_CLK_EN (1 << 26)
+#define USB_CTRL_UH2_CLK_FROM_ULPI_PHY (1 << 2)
+/* ULPIVIEW register bits */
+#define ULPIVW_OFF (0x170)
+#define ULPIVW_WU (1 << 31) /* Wakeup */
+#define ULPIVW_RUN (1 << 30) /* read/write run */
+#define ULPIVW_WRITE (1 << 29) /* 0=read 1=write */
+#define ULPIVW_SS (1 << 27) /* SyncState */
+#define ULPIVW_PORT_MASK 0x07 /* Port field */
+#define ULPIVW_PORT_SHIFT 24
+#define ULPIVW_ADDR_MASK 0xFF /* data address field */
+#define ULPIVW_ADDR_SHIFT 16
+#define ULPIVW_RDATA_MASK 0xFF /* read data field */
+#define ULPIVW_RDATA_SHIFT 8
+#define ULPIVW_WDATA_MASK 0xFF /* write data field */
+#define ULPIVW_WDATA_SHIFT 0
+
+/* USB Clock on/off Control Register */
+#define OTG_AHBCLK_OFF (0x1<<17) /* 1: OFF */
+#define H1_AHBCLK_OFF (0x1<<18) /* 1: OFF */
+
+/* mx6q's register bit begins*/
+
+/* OTG CTRL - H3 CTRL */
+#define UCTRL_OWIR (1 << 31) /* OTG wakeup intr request received */
+/* bit 18 - bit 30 is reserved at mx6q */
+#define UCTRL_WKUP_VBUS_EN (1 << 17) /* OTG wake-up on VBUS change enable */
+#define UCTRL_WKUP_ID_EN (1 << 16) /* OTG wake-up on ID change enable */
+#define UCTRL_WKUP_SW (1 << 15) /* OTG Software Wake-up */
+#define UCTRL_WKUP_SW_EN (1 << 14) /* OTG Software Wake-up enable */
+#define UCTRL_UTMI_ON_CLOCK (1 << 13) /* Force OTG UTMI PHY clock output on
+ even if suspend mode */
+#define UCTRL_SUSPENDM (1 << 12) /* Force OTG UTMI PHY Suspend */
+#define UCTRL_RESET (1 << 11) /* Force OTG UTMI PHY Reset */
+#define UCTRL_OWIE (1 << 10) /* OTG wakeup intr request received */
+#define UCTRL_PM (1 << 9) /* OTG Power Mask */
+#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
+/* bit 0 - bit 6 is reserved at mx6q */
+
+/* Host2/3 HSIC Ctrl */
+#define CLK_VLD (1 << 31) /* Indicating whether HSIC clock is valid */
+#define HSIC_EN (1 << 12) /* HSIC enable */
+#define HSIC_CLK_ON (1 << 11) /* Force HSIC module 480M clock on,
+ * even when in Host is in suspend mode
+ */
+/* OTG/HOST1 Phy Ctrl */
+#define PHY_UTMI_CLK_VLD (1 << 31) /* Indicating whether OTG UTMI PHY Clock Valid */
+
+#define NOP_XCVR (0xffffffff) /* Indicate it is no usb phy */
+#endif /* __ARCH_ARM___USBPHY_H */
diff --git a/arch/arm/include/asm/imx-common/boot_mode.h b/arch/arm/include/asm/imx-common/boot_mode.h
index de0205c..a098761 100644
--- a/arch/arm/include/asm/imx-common/boot_mode.h
+++ b/arch/arm/include/asm/imx-common/boot_mode.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Boundary Devices Inc.
+ * Copyright (C) 2012-2015 Boundary Devices Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -9,6 +9,27 @@
#define MAKE_CFGVAL(cfg1, cfg2, cfg3, cfg4) \
((cfg4) << 24) | ((cfg3) << 16) | ((cfg2) << 8) | (cfg1)
+enum boot_device {
+ WEIM_NOR_BOOT,
+ ONE_NAND_BOOT,
+ PATA_BOOT,
+ SATA_BOOT,
+ I2C_BOOT,
+ SPI_NOR_BOOT,
+ SD1_BOOT,
+ SD2_BOOT,
+ SD3_BOOT,
+ SD4_BOOT,
+ MMC1_BOOT,
+ MMC2_BOOT,
+ MMC3_BOOT,
+ MMC4_BOOT,
+ NAND_BOOT,
+ QSPI_BOOT,
+ UNKNOWN_BOOT,
+ BOOT_DEV_NUM = UNKNOWN_BOOT,
+};
+
struct boot_mode {
const char *name;
unsigned cfg_val;
@@ -16,5 +37,6 @@ struct boot_mode {
void add_board_boot_modes(const struct boot_mode *p);
void boot_mode_apply(unsigned cfg_val);
+enum boot_device get_boot_device(void);
extern const struct boot_mode soc_boot_modes[];
#endif
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index f606255..8045c9d 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -45,6 +45,10 @@
#include <miiphy.h>
#endif
+#ifdef CONFIG_FASTBOOT
+#include <fastboot.h>
+#endif
+
DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len;
@@ -639,6 +643,10 @@ void board_init_r(gd_t *id, ulong dest_addr)
board_late_init();
#endif
+#ifdef CONFIG_FASTBOOT
+ fastboot_setup();
+#endif
+
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
@@ -678,6 +686,10 @@ void board_init_r(gd_t *id, ulong dest_addr)
}
#endif
+#ifdef CONFIG_FASTBOOT
+ check_fastboot();
+#endif
+
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop();
diff --git a/board/freescale/common/Makefile b/board/freescale/common/Makefile
index 7181cac..c9d4250 100644
--- a/board/freescale/common/Makefile
+++ b/board/freescale/common/Makefile
@@ -61,6 +61,9 @@ obj-$(CONFIG_VSC_CROSSBAR) += vsc3316_3308.o
obj-$(CONFIG_IDT8T49N222A) += idt8t49n222a_serdes_clk.o
obj-$(CONFIG_ZM7300) += zm7300.o
obj-$(CONFIG_POWER_PFUZE100) += pfuze.o
+ifdef CONFIG_FASTBOOT
+obj-${CONFIG_ANDROID_RECOVERY} += recovery.o
+endif
obj-$(CONFIG_LS102XA_STREAM_ID) += ls102xa_stream_id.o
diff --git a/board/freescale/common/recovery.c b/board/freescale/common/recovery.c
new file mode 100644
index 0000000..e6f2137
--- /dev/null
+++ b/board/freescale/common/recovery.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <malloc.h>
+#include <recovery.h>
+#ifdef CONFIG_MXC_KPD
+#include <mxc_keyb.h>
+#endif
+#include <asm/imx-common/boot_mode.h>
+
+#ifdef CONFIG_MXC_KPD
+#define PRESSED_VOL_DOWN 0x01
+#define PRESSED_POWER 0x02
+#define RECOVERY_KEY_MASK (PRESSED_VOL_DOWN | PRESSED_POWER)
+
+inline int test_key(int value, struct kpp_key_info *ki)
+{
+ return (ki->val == value) && (ki->evt == KDepress);
+}
+
+int check_key_pressing(void)
+{
+ struct kpp_key_info *key_info = NULL;
+ int state = 0, keys, i;
+
+ int ret = 0;
+
+ mxc_kpp_init();
+ /* due to glitch suppression circuit,
+ wait sometime to let all keys scanned. */
+ udelay(1000);
+ keys = mxc_kpp_getc(&key_info);
+
+ printf("Detecting VOL_DOWN+POWER key for recovery(%d:%d) ...\n",
+ keys, keys ? key_info->val : 0);
+ if (keys > 1) {
+ for (i = 0; i < keys; i++) {
+ if (test_key(CONFIG_POWER_KEY, &key_info[i]))
+ state |= PRESSED_POWER;
+ else if (test_key(CONFIG_VOL_DOWN_KEY, &key_info[i]))
+ state |= PRESSED_VOL_DOWN;
+ }
+ }
+ if ((state & RECOVERY_KEY_MASK) == RECOVERY_KEY_MASK)
+ ret = 1;
+ if (key_info)
+ free(key_info);
+ return ret;
+}
+#else
+/* If not using mxc keypad, currently we will detect power key on board */
+int check_key_pressing(void)
+{
+ return 0;
+}
+#endif
+
+void setup_recovery_env(void)
+{
+ board_recovery_setup();
+}
+
+/* export to lib_arm/board.c */
+void check_recovery_mode(void)
+{
+ if (check_key_pressing()) {
+ puts("Fastboot: Recovery key pressing got!\n");
+ setup_recovery_env();
+ } else if (check_recovery_cmd_file()) {
+ puts("Fastboot: Recovery command file found!\n");
+ setup_recovery_env();
+ } else {
+ puts("Fastboot: Normal\n");
+ }
+}
diff --git a/board/freescale/mx6qsabreauto/mx6qsabreauto.c b/board/freescale/mx6qsabreauto/mx6qsabreauto.c
index 27f3087..e9b4fe0 100644
--- a/board/freescale/mx6qsabreauto/mx6qsabreauto.c
+++ b/board/freescale/mx6qsabreauto/mx6qsabreauto.c
@@ -810,3 +810,137 @@ int board_ehci_power(int port, int on)
return 0;
}
#endif
+
+#ifdef CONFIG_FASTBOOT
+
+void board_fastboot_setup(void)
+{
+ switch (get_boot_device()) {
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+ case SATA_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "sata");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti sata");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD1_BOOT:
+ case MMC1_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc0");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc0");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc1");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc1");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ case NAND_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "nand");
+ if (!getenv("fbparts"))
+ setenv("fbparts", ANDROID_FASTBOOT_NAND_PARTS);
+ if (!getenv("bootcmd"))
+ setenv("bootcmd",
+ "nand read ${loadaddr} ${boot_nand_offset} "
+ "${boot_nand_size};booti ${loadaddr}");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/
+ default:
+ printf("unsupported boot devices\n");
+ break;
+ }
+}
+
+#ifdef CONFIG_ANDROID_RECOVERY
+
+#define GPIO_VOL_DN_KEY IMX_GPIO_NR(5, 14)
+iomux_v3_cfg_t const recovery_key_pads[] = {
+ (MX6_PAD_DISP0_DAT20__GPIO5_IO14 | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+
+int check_recovery_cmd_file(void)
+{
+ int button_pressed = 0;
+ int recovery_mode = 0;
+
+ recovery_mode = recovery_check_and_clean_flag();
+
+ /* Check Recovery Combo Button press or not. */
+ imx_iomux_v3_setup_multiple_pads(recovery_key_pads,
+ ARRAY_SIZE(recovery_key_pads));
+
+ gpio_direction_input(GPIO_VOL_DN_KEY);
+
+ if (gpio_get_value(GPIO_VOL_DN_KEY) == 0) { /* VOL_DN key is low assert */
+ button_pressed = 1;
+ printf("Recovery key pressed\n");
+ }
+
+ return recovery_mode || button_pressed;
+}
+
+void board_recovery_setup(void)
+{
+ int bootdev = get_boot_device();
+
+ switch (bootdev) {
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+ case SATA_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti sata recovery");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD1_BOOT:
+ case MMC1_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti mmc0 recovery");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti mmc1 recovery");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ case NAND_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "nand read ${loadaddr} ${recovery_nand_offset} "
+ "${recovery_nand_size};booti ${loadaddr}");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/
+ default:
+ printf("Unsupported bootup device for recovery: dev: %d\n",
+ bootdev);
+ return;
+ }
+
+ printf("setup env for recovery..\n");
+ setenv("bootcmd", "run bootcmd_android_recovery");
+}
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#endif /*CONFIG_FASTBOOT*/
+
+#ifdef CONFIG_IMX_UDC
+iomux_v3_cfg_t const otg_udc_pads[] = {
+ (MX6_PAD_ENET_RX_ER__USB_OTG_ID | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+void udc_pins_setting(void)
+{
+ imx_iomux_v3_setup_multiple_pads(otg_udc_pads,
+ ARRAY_SIZE(otg_udc_pads));
+
+ /*set daisy chain for otg_pin_id on 6q. for 6dl, this bit is reserved*/
+ imx_iomux_set_gpr_register(1, 13, 1, 0);
+}
+
+#endif /*CONFIG_IMX_UDC*/
diff --git a/board/freescale/mx6sabresd/mx6sabresd.c b/board/freescale/mx6sabresd/mx6sabresd.c
index 0a6c29e..c3d8408 100644
--- a/board/freescale/mx6sabresd/mx6sabresd.c
+++ b/board/freescale/mx6sabresd/mx6sabresd.c
@@ -45,6 +45,12 @@
#ifdef CONFIG_CMD_SATA
#include <asm/imx-common/sata.h>
#endif
+#ifdef CONFIG_FASTBOOT
+#include <fastboot.h>
+#ifdef CONFIG_ANDROID_RECOVERY
+#include <recovery.h>
+#endif
+#endif /*CONFIG_FASTBOOT*/
DECLARE_GLOBAL_DATA_PTR;
@@ -1185,11 +1191,134 @@ int checkboard(void)
return 0;
}
+#ifdef CONFIG_FASTBOOT
+
+void board_fastboot_setup(void)
+{
+ switch (get_boot_device()) {
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+ case SATA_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "sata");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti sata");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD2_BOOT:
+ case MMC2_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc0");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc0");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc1");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc1");
+ break;
+ case MMC4_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc2");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc2");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+ default:
+ printf("unsupported boot devices\n");
+ break;
+ }
+
+}
+
+#ifdef CONFIG_ANDROID_RECOVERY
+
+#define GPIO_VOL_DN_KEY IMX_GPIO_NR(1, 5)
+iomux_v3_cfg_t const recovery_key_pads[] = {
+ (MX6_PAD_GPIO_5__GPIO1_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+
+int check_recovery_cmd_file(void)
+{
+ int button_pressed = 0;
+ int recovery_mode = 0;
+
+ recovery_mode = recovery_check_and_clean_flag();
+
+ /* Check Recovery Combo Button press or not. */
+ imx_iomux_v3_setup_multiple_pads(recovery_key_pads,
+ ARRAY_SIZE(recovery_key_pads));
+
+ gpio_direction_input(GPIO_VOL_DN_KEY);
+
+ if (gpio_get_value(GPIO_VOL_DN_KEY) == 0) { /* VOL_DN key is low assert */
+ button_pressed = 1;
+ printf("Recovery key pressed\n");
+ }
+
+ return recovery_mode || button_pressed;
+}
+
+void board_recovery_setup(void)
+{
+ int bootdev = get_boot_device();
+
+ switch (bootdev) {
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+ case SATA_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "booti sata recovery");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD2_BOOT:
+ case MMC2_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "booti mmc0 recovery");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "booti mmc1 recovery");
+ break;
+ case MMC4_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "booti mmc2 recovery");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+ default:
+ printf("Unsupported bootup device for recovery: dev: %d\n",
+ bootdev);
+ return;
+ }
+
+ printf("setup env for recovery..\n");
+ setenv("bootcmd", "run bootcmd_android_recovery");
+}
+
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#endif /*CONFIG_FASTBOOT*/
+
#ifdef CONFIG_IMX_UDC
iomux_v3_cfg_t const otg_udc_pads[] = {
(MX6_PAD_ENET_RX_ER__USB_OTG_ID | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
-#endif
+void udc_pins_setting(void)
+{
+ imx_iomux_v3_setup_multiple_pads(otg_udc_pads,
+ ARRAY_SIZE(otg_udc_pads));
+
+ /*set daisy chain for otg_pin_id on 6q. for 6dl, this bit is reserved*/
+ imx_iomux_set_gpr_register(1, 13, 1, 0);
+}
+#endif /*CONFIG_IMX_UDC*/
#ifdef CONFIG_SPL_BUILD
#include <spl.h>
diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c
index 137fae3..3d3c55d 100644
--- a/board/freescale/mx6slevk/mx6slevk.c
+++ b/board/freescale/mx6slevk/mx6slevk.c
@@ -13,6 +13,7 @@
#include <asm/arch/mx6-pins.h>
#include <asm/arch/sys_proto.h>
#include <asm/gpio.h>
+#include <asm/imx-common/boot_mode.h>
#include <asm/imx-common/iomux-v3.h>
#include <asm/imx-common/mxc_i2c.h>
#include <asm/imx-common/spi.h>
@@ -32,6 +33,12 @@
#include <lcd.h>
#include <mxc_epdc_fb.h>
#endif
+#ifdef CONFIG_FASTBOOT
+#include <fastboot.h>
+#ifdef CONFIG_ANDROID_RECOVERY
+#include <recovery.h>
+#endif
+#endif /*CONFIG_FASTBOOT*/
DECLARE_GLOBAL_DATA_PTR;
@@ -870,3 +877,95 @@ int setup_mxc_kpd(void)
return 0;
}
#endif /*CONFIG_MXC_KPD*/
+
+#ifdef CONFIG_FASTBOOT
+
+void board_fastboot_setup(void)
+{
+ switch (get_boot_device()) {
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD1_BOOT:
+ case MMC1_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc0");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc0");
+ break;
+ case SD2_BOOT:
+ case MMC2_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc1");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc1");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc2");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc2");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+ default:
+ printf("unsupported boot devices\n");
+ break;
+ }
+
+}
+
+#ifdef CONFIG_ANDROID_RECOVERY
+int check_recovery_cmd_file(void)
+{
+ return recovery_check_and_clean_flag();
+}
+
+void board_recovery_setup(void)
+{
+ int bootdev = get_boot_device();
+
+ /*current uboot BSP only supports USDHC2*/
+ switch (bootdev) {
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD1_BOOT:
+ case MMC1_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "booti mmc0 recovery");
+ break;
+ case SD2_BOOT:
+ case MMC2_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "booti mmc1 recovery");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "booti mmc2 recovery");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+ default:
+ printf("Unsupported bootup device for recovery: dev: %d\n",
+ bootdev);
+ return;
+ }
+
+ printf("setup env for recovery..\n");
+ setenv("bootcmd", "run bootcmd_android_recovery");
+}
+
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#endif /*CONFIG_FASTBOOT*/
+
+#ifdef CONFIG_IMX_UDC
+iomux_v3_cfg_t const otg_udc_pads[] = {
+ (MX6_PAD_EPDC_PWRCOM__ANATOP_USBOTG1_ID | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+void udc_pins_setting(void)
+{
+ imx_iomux_v3_setup_multiple_pads(otg_udc_pads,
+ ARRAY_SIZE(otg_udc_pads));
+}
+#endif /*CONFIG_IMX_UDC*/
diff --git a/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c b/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c
index e39e236..589922f 100644
--- a/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c
+++ b/board/freescale/mx6sxsabreauto/mx6sxsabreauto.c
@@ -44,6 +44,13 @@
#include <gpio_exp.h>
#endif
+#ifdef CONFIG_FASTBOOT
+#include <fastboot.h>
+#ifdef CONFIG_ANDROID_RECOVERY
+#include <recovery.h>
+#endif
+#endif /*CONFIG_FASTBOOT*/
+
DECLARE_GLOBAL_DATA_PTR;
#define UART_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
@@ -805,3 +812,103 @@ int checkboard(void)
return 0;
}
+
+#ifdef CONFIG_FASTBOOT
+
+void board_fastboot_setup(void)
+{
+ switch (get_boot_device()) {
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc0");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc0");
+ break;
+ case SD4_BOOT:
+ case MMC4_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc1");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc1");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ case NAND_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "nand");
+ if (!getenv("fbparts"))
+ setenv("fbparts", ANDROID_FASTBOOT_NAND_PARTS);
+ if (!getenv("bootcmd"))
+ setenv("bootcmd",
+ "nand read ${loadaddr} ${boot_nand_offset} "
+ "${boot_nand_size};booti ${loadaddr}");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/
+
+ default:
+ printf("unsupported boot devices\n");
+ break;
+ }
+}
+
+#ifdef CONFIG_ANDROID_RECOVERY
+int check_recovery_cmd_file(void)
+{
+ int recovery_mode = 0;
+
+ recovery_mode = recovery_check_and_clean_flag();
+
+ return recovery_mode;
+}
+
+void board_recovery_setup(void)
+{
+ int bootdev = get_boot_device();
+
+ switch (bootdev) {
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti mmc0 recovery");
+ break;
+ case SD4_BOOT:
+ case MMC4_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti mmc1 recovery");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ case NAND_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery",
+ "nand read ${loadaddr} ${recovery_nand_offset} "
+ "${recovery_nand_size};booti ${loadaddr}");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/
+ default:
+ printf("Unsupported bootup device for recovery: dev: %d\n",
+ bootdev);
+ return;
+ }
+
+ printf("setup env for recovery..\n");
+ setenv("bootcmd", "run bootcmd_android_recovery");
+}
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#endif /*CONFIG_FASTBOOT*/
+
+#ifdef CONFIG_IMX_UDC
+iomux_v3_cfg_t const otg_udc_pads[] = {
+ (MX6_PAD_GPIO1_IO10__ANATOP_OTG1_ID | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+void udc_pins_setting(void)
+{
+ imx_iomux_v3_setup_multiple_pads(otg_udc_pads,
+ ARRAY_SIZE(otg_udc_pads));
+}
+
+#endif /*CONFIG_IMX_UDC*/
diff --git a/board/freescale/mx6sxsabresd/mx6sxsabresd.c b/board/freescale/mx6sxsabresd/mx6sxsabresd.c
index 67e334b..a632d35 100644
--- a/board/freescale/mx6sxsabresd/mx6sxsabresd.c
+++ b/board/freescale/mx6sxsabresd/mx6sxsabresd.c
@@ -40,6 +40,13 @@
#include <mxsfb.h>
#endif
+#ifdef CONFIG_FASTBOOT
+#include <fastboot.h>
+#ifdef CONFIG_ANDROID_RECOVERY
+#include <recovery.h>
+#endif
+#endif /*CONFIG_FASTBOOT*/
+
DECLARE_GLOBAL_DATA_PTR;
#define UART_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
@@ -888,6 +895,115 @@ int checkboard(void)
return 0;
}
+#ifdef CONFIG_FASTBOOT
+
+void board_fastboot_setup(void)
+{
+ switch (get_boot_device()) {
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD2_BOOT:
+ case MMC2_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc0");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc0");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc1");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc1");
+ break;
+ case SD4_BOOT:
+ case MMC4_BOOT:
+ if (!getenv("fastboot_dev"))
+ setenv("fastboot_dev", "mmc2");
+ if (!getenv("bootcmd"))
+ setenv("bootcmd", "booti mmc2");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+ default:
+ printf("unsupported boot devices\n");
+ break;
+ }
+}
+
+#ifdef CONFIG_ANDROID_RECOVERY
+
+#define GPIO_VOL_DN_KEY IMX_GPIO_NR(1, 19)
+iomux_v3_cfg_t const recovery_key_pads[] = {
+ (MX6_PAD_CSI_DATA05__GPIO1_IO_19 | MUX_PAD_CTRL(BUTTON_PAD_CTRL)),
+};
+
+int check_recovery_cmd_file(void)
+{
+ int button_pressed = 0;
+ int recovery_mode = 0;
+
+ recovery_mode = recovery_check_and_clean_flag();
+
+ /* Check Recovery Combo Button press or not. */
+ imx_iomux_v3_setup_multiple_pads(recovery_key_pads,
+ ARRAY_SIZE(recovery_key_pads));
+
+ gpio_direction_input(GPIO_VOL_DN_KEY);
+
+ if (gpio_get_value(GPIO_VOL_DN_KEY) == 0) { /* VOL_DN key is low assert */
+ button_pressed = 1;
+ printf("Recovery key pressed\n");
+ }
+
+ return recovery_mode || button_pressed;
+}
+
+void board_recovery_setup(void)
+{
+ int bootdev = get_boot_device();
+
+ switch (bootdev) {
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case SD2_BOOT:
+ case MMC2_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti mmc0 recovery");
+ break;
+ case SD3_BOOT:
+ case MMC3_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti mmc1 recovery");
+ break;
+ case SD4_BOOT:
+ case MMC4_BOOT:
+ if (!getenv("bootcmd_android_recovery"))
+ setenv("bootcmd_android_recovery", "booti mmc2 recovery");
+ break;
+#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/
+ default:
+ printf("Unsupported bootup device for recovery: dev: %d\n",
+ bootdev);
+ return;
+ }
+
+ printf("setup env for recovery..\n");
+ setenv("bootcmd", "run bootcmd_android_recovery");
+}
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#endif /*CONFIG_FASTBOOT*/
+
+#ifdef CONFIG_IMX_UDC
+iomux_v3_cfg_t const otg_udc_pads[] = {
+ (MX6_PAD_GPIO1_IO10__ANATOP_OTG1_ID | MUX_PAD_CTRL(NO_PAD_CTRL)),
+};
+void udc_pins_setting(void)
+{
+ imx_iomux_v3_setup_multiple_pads(otg_udc_pads,
+ ARRAY_SIZE(otg_udc_pads));
+}
+
+#endif /*CONFIG_IMX_UDC*/
+
#ifdef CONFIG_SPL_BUILD
#include <libfdt.h>
#include <spl.h>
diff --git a/common/board_r.c b/common/board_r.c
index 0335f6b..ceccb80 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -58,6 +58,9 @@
#ifdef CONFIG_AVR32
#include <asm/arch/mmu.h>
#endif
+#ifdef CONFIG_FASTBOOT
+#include <fastboot.h>
+#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -673,6 +676,20 @@ static int initr_kbd(void)
}
#endif
+#ifdef CONFIG_FASTBOOT
+static int initr_fastboot_setup(void)
+{
+ fastboot_setup();
+ return 0;
+}
+
+static int initr_check_fastboot(void)
+{
+ check_fastboot();
+ return 0;
+}
+#endif
+
static int run_main_loop(void)
{
#ifdef CONFIG_SANDBOX
@@ -848,6 +865,9 @@ init_fnc_t init_sequence_r[] = {
#ifdef CONFIG_BOARD_LATE_INIT
board_late_init,
#endif
+#ifdef CONFIG_FASTBOOT
+ initr_fastboot_setup,
+#endif
#ifdef CONFIG_CMD_SCSI
INIT_FUNC_WATCHDOG_RESET
initr_scsi,
@@ -891,6 +911,9 @@ init_fnc_t init_sequence_r[] = {
#ifdef CONFIG_PS2KBD
initr_kbd,
#endif
+#ifdef CONFIG_FASTBOOT
+ initr_check_fastboot,
+#endif
run_main_loop,
};
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 6c5b600..c4e8d58 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -651,6 +651,7 @@ U_BOOT_CMD(
);
#endif /* CONFIG_CMD_BOOTZ */
+#if 0
#ifdef CONFIG_CMD_BOOTI
/* See Documentation/arm64/booting.txt in the Linux kernel */
struct Image_header {
@@ -799,3 +800,4 @@ U_BOOT_CMD(
"boot arm64 Linux Image image from memory", booti_help_text
);
#endif /* CONFIG_CMD_BOOTI */
+#endif
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
index 346ab80..c84877e 100644
--- a/common/cmd_fastboot.c
+++ b/common/cmd_fastboot.c
@@ -1,47 +1,1827 @@
/*
- * Copyright 2008 - 2009 Windriver, <www.windriver.com>
- * Author: Tom Rix <Tom.Rix@windriver.com>
+ * Copyright 2008 - 2009 (C) Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
*
- * (C) Copyright 2014 Linaro, Ltd.
- * Rob Herring <robh@kernel.org>
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ *
+ * Part of the rx_handler were copied from the Android project.
+ * Specifically rx command parsing in the usb_rx_data_complete
+ * function of the file bootable/bootloader/legacy/usbloader/usbloader.c
+ *
+ * The logical naming of flash comes from the Android project
+ * Thse structures and functions that look like fastboot_flash_*
+ * They come from bootable/bootloader/legacy/libboot/flash.c
+ *
+ * This is their Copyright:
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
+#include <asm/byteorder.h>
#include <common.h>
#include <command.h>
-#include <g_dnl.h>
+#include <nand.h>
+#include <fastboot.h>
+#include <environment.h>
+#include <mmc.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+#include <asm/bootm.h>
+
+#ifdef CONFIG_FASTBOOT
+
+int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+extern int do_bootm_linux(int flag, int argc,
+ char *argv[], bootm_headers_t *images);
+
+/* Forward decl */
+static int tx_handler(void);
+static int rx_handler(const unsigned char *buffer, unsigned int buffer_size);
+static void reset_handler(void);
+
+static struct cmd_fastboot_interface interface = {
+ .rx_handler = rx_handler,
+ .reset_handler = reset_handler,
+ .product_name = NULL,
+ .serial_no = NULL,
+ .nand_block_size = 0,
+ .transfer_buffer = (unsigned char *)0xffffffff,
+ .transfer_buffer_size = 0,
+};
+
+static unsigned int download_size;
+static unsigned int download_bytes;
+static unsigned int download_bytes_unpadded;
+static unsigned int download_error;
+static unsigned int continue_booting;
+static unsigned int upload_size;
+static unsigned int upload_bytes;
+static unsigned int upload_error;
+
+#define MMC_SATA_BLOCK_SIZE 512
+
+#ifdef CONFIG_FASTBOOT_STORAGE_NAND
+static void save_env(struct fastboot_ptentry *ptn,
+ char *var, char *val)
+{
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ char lock[128], unlock[128];
+#endif
+
+ setenv(var, val);
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ sprintf(lock, "nand lock 0x%x 0x%x", ptn->start, ptn->length);
+ sprintf(unlock, "nand unlock 0x%x 0x%x", ptn->start, ptn->length);
+
+ /* This could be a problem is there is an outstanding lock */
+ run_command(unlock, 0);
+#endif
+ saveenv();
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ run_command(lock, 0);
+#endif
+}
+
+void save_parts_values(struct fastboot_ptentry *ptn,
+ unsigned int offset,
+ unsigned int size)
+{
+ char var[64], val[32];
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ char lock[128], unlock[128];
+ struct fastboot_ptentry *env_ptn;
+#endif
+
+ printf("saving it..\n");
+
+
+ sprintf(var, "%s_nand_offset", ptn->name);
+ sprintf(val, "0x%x", offset);
+
+ printf("setenv %s %s\n", var, val);
+
+ setenv(var, val);
+
+ sprintf(var, "%s_nand_size", ptn->name);
+ sprintf(val, "0x%x", size);
+
+ printf("setenv %s %s\n", var, val);
+
+ setenv(var, val);
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ /* Warning :
+ The environment is assumed to be in a partition named 'enviroment'.
+ It is very possible that your board stores the enviroment
+ someplace else. */
+ env_ptn = fastboot_flash_find_ptn("environment");
+
+ if (env_ptn) {
+ sprintf(lock, "nand lock 0x%x 0x%x",
+ env_ptn->start, env_ptn->length);
+ sprintf(unlock, "nand unlock 0x%x 0x%x",
+ env_ptn->start, env_ptn->length);
+
+ run_command(unlock, 0);
+ }
+#endif
+ saveenv();
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ if (env_ptn)
+ run_command(lock, 0);
+#endif
+}
+
+int check_parts_values(struct fastboot_ptentry *ptn)
+{
+ char var[64];
+
+ sprintf(var, "%s_nand_offset", ptn->name);
+ if (!getenv(var))
+ return 1;
+
+ sprintf(var, "%s_nand_size", ptn->name);
+ if (!getenv(var))
+ return 1;
+
+ return 0;
+}
-static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+static int write_to_ptn(struct fastboot_ptentry *ptn)
{
- int ret;
+ int ret = 1;
+ char length[32];
+ char write_type[32];
+ int repeat, repeat_max;
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ char lock[128];
+ char unlock[128];
+#endif
+ char write[128];
+ char erase[128];
+
+ printf("flashing '%s'\n", ptn->name);
- g_dnl_clear_detach();
- ret = g_dnl_register("usb_dnl_fastboot");
- if (ret)
- return ret;
+ /* Which flavor of write to use */
+ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_I)
+ sprintf(write_type, "write.i");
+#ifdef CONFIG_CMD_NAND_TRIMFFS
+ else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS)
+ sprintf(write_type, "write.trimffs");
+#endif
+ else
+ sprintf(write_type, "write");
- if (!g_dnl_board_usb_cable_connected()) {
- puts("\rUSB cable not detected.\n" \
- "Command exit.\n");
- return CMD_RET_FAILURE;
+ /* Some flashing requires writing the same data in multiple,
+ consecutive flash partitions */
+ repeat_max = 1;
+ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) {
+ if (ptn->flags &
+ FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) {
+ printf("Warning can not do both 'contiguous block' "
+ "and 'repeat' writes for for partition '%s'\n", ptn->name);
+ printf("Ignoring repeat flag\n");
+ } else {
+ repeat_max = ptn->flags &
+ FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;
+ }
}
- while (1) {
- if (g_dnl_detach())
+ /* Unlock the whole partition instead of trying to
+ manage special cases */
+ sprintf(length, "0x%x", ptn->length * repeat_max);
+
+ for (repeat = 0; repeat < repeat_max; repeat++) {
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ sprintf(lock, "nand lock 0x%x %s",
+ ptn->start + (repeat * ptn->length), length);
+ sprintf(unlock, "nand unlock 0x%x %s",
+ ptn->start + (repeat * ptn->length), length);
+#endif
+ sprintf(erase, "nand erase 0x%x %s",
+ ptn->start + (repeat * ptn->length), length);
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ run_command(unlock, 0);
+#endif
+ run_command(erase, 0);
+
+ if ((ptn->flags &
+ FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) &&
+ (ptn->flags &
+ FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK)) {
+ /* Both can not be true */
+ printf("Warning can not do 'next good block' and \
+ 'contiguous block' for partition '%s'\n",
+ ptn->name);
+ printf("Ignoring these flags\n");
+ } else if (ptn->flags &
+ FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) {
+ /* Keep writing until you get a good block
+ transfer_buffer should already be aligned */
+ if (interface.nand_block_size) {
+ unsigned int blocks = download_bytes /
+ interface.nand_block_size;
+ unsigned int i = 0;
+ unsigned int offset = 0;
+
+ while (i < blocks) {
+ /* Check for overflow */
+ if (offset >= ptn->length)
+ break;
+
+ /* download's address only advance
+ if last write was successful */
+
+ /* nand's address always advances */
+ sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type,
+ interface.transfer_buffer +
+ (i * interface.nand_block_size),
+ ptn->start + (repeat * ptn->length) + offset,
+ interface.nand_block_size);
+
+ ret = run_command(write, 0);
+ if (ret)
+ break;
+ else
+ i++;
+
+ /* Go to next nand block */
+ offset += interface.nand_block_size;
+ }
+ } else {
+ printf("Warning nand block size can not be 0 \
+ when using 'next good block' for \
+ partition '%s'\n", ptn->name);
+ printf("Ignoring write request\n");
+ }
+ } else if (ptn->flags &
+ FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) {
+ /* Keep writing until you get a good block
+ transfer_buffer should already be aligned */
+ if (interface.nand_block_size) {
+ if (0 == nand_curr_device) {
+ nand_info_t *nand;
+ unsigned long off;
+ unsigned int ok_start;
+
+ nand = &nand_info[nand_curr_device];
+
+ printf("\nDevice %d bad blocks:\n",
+ nand_curr_device);
+
+ /* Initialize the ok_start to the
+ start of the partition
+ Then try to find a block large
+ enough for the download */
+ ok_start = ptn->start;
+
+ /* It is assumed that the start and
+ length are multiples of block size */
+ for (off = ptn->start;
+ off < ptn->start + ptn->length;
+ off += nand->erasesize) {
+ if (nand_block_isbad(nand, off)) {
+ /* Reset the ok_start
+ to the next block */
+ ok_start = off +
+ nand->erasesize;
+ }
+
+ /* Check if we have enough
+ blocks */
+ if ((ok_start - off) >=
+ download_bytes)
+ break;
+ }
+
+ /* Check if there is enough space */
+ if (ok_start + download_bytes <=
+ ptn->start + ptn->length) {
+
+ sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type,
+ interface.transfer_buffer,
+ ok_start,
+ download_bytes);
+
+ ret = run_command(write, 0);
+
+ /* Save the results into an
+ environment variable on the
+ format
+ ptn_name + 'offset'
+ ptn_name + 'size' */
+ if (ret) {
+ /* failed */
+ save_parts_values(ptn, ptn->start, 0);
+ } else {
+ /* success */
+ save_parts_values(ptn, ok_start, download_bytes);
+ }
+ } else {
+ printf("Error could not find enough contiguous space "
+ "in partition '%s'\n", ptn->name);
+ printf("Ignoring write request\n");
+ }
+ } else {
+ /* TBD : Generalize flash handling */
+ printf("Error only handling 1 NAND per board");
+ printf("Ignoring write request\n");
+ }
+ } else {
+ printf("Warning nand block size can not be 0 \
+ when using 'continuous block' for \
+ partition '%s'\n", ptn->name);
+ printf("Ignoring write request\n");
+ }
+ } else {
+ /* Normal case */
+ sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type,
+ interface.transfer_buffer,
+ ptn->start + (repeat * ptn->length),
+ download_bytes);
+#ifdef CONFIG_CMD_NAND_TRIMFFS
+ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS) {
+ sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type,
+ interface.transfer_buffer,
+ ptn->start + (repeat * ptn->length),
+ download_bytes_unpadded);
+ }
+#endif
+
+ ret = run_command(write, 0);
+
+ if (0 == repeat) {
+ if (ret) /* failed */
+ save_parts_values(ptn, ptn->start, 0);
+ else /* success */
+ save_parts_values(ptn, ptn->start,
+ download_bytes);
+ }
+ }
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ run_command(lock, 0);
+#endif
+
+ if (ret)
break;
- if (ctrlc())
+ }
+
+ return ret;
+}
+#else
+static void save_env(struct fastboot_ptentry *ptn,
+ char *var, char *val)
+{
+ setenv(var, val);
+ saveenv();
+}
+#endif
+
+/* When save = 0, just parse. The input is unchanged
+ When save = 1, parse and do the save. The input is changed */
+static int parse_env(void *ptn, char *err_string, int save, int debug)
+{
+ int ret = 1;
+ unsigned int sets = 0;
+ unsigned int comment_start = 0;
+ char *var = NULL;
+ char *var_end = NULL;
+ char *val = NULL;
+ char *val_end = NULL;
+ unsigned int i;
+
+ char *buff = (char *)interface.transfer_buffer;
+ unsigned int size = download_bytes_unpadded;
+
+ /* The input does not have to be null terminated.
+ This will cause a problem in the corner case
+ where the last line does not have a new line.
+ Put a null after the end of the input.
+
+ WARNING : Input buffer is assumed to be bigger
+ than the size of the input */
+ if (save)
+ buff[size] = 0;
+
+ for (i = 0; i < size; i++) {
+
+ if (NULL == var) {
+
+ /*
+ * Check for comments, comment ok only on
+ * mostly empty lines
+ */
+ if (buff[i] == '#')
+ comment_start = 1;
+
+ if (comment_start) {
+ if ((buff[i] == '\r') ||
+ (buff[i] == '\n')) {
+ comment_start = 0;
+ }
+ } else {
+ if (!((buff[i] == ' ') ||
+ (buff[i] == '\t') ||
+ (buff[i] == '\r') ||
+ (buff[i] == '\n'))) {
+ /*
+ * Normal whitespace before the
+ * variable
+ */
+ var = &buff[i];
+ }
+ }
+
+ } else if (((NULL == var_end) || (NULL == val)) &&
+ ((buff[i] == '\r') || (buff[i] == '\n'))) {
+
+ /* This is the case when a variable
+ is unset. */
+
+ if (save) {
+ /* Set the var end to null so the
+ normal string routines will work
+
+ WARNING : This changes the input */
+ buff[i] = '\0';
+
+ save_env(ptn, var, val);
+
+ if (debug)
+ printf("Unsetting %s\n", var);
+ }
+
+ /* Clear the variable so state is parse is back
+ to initial. */
+ var = NULL;
+ var_end = NULL;
+ sets++;
+ } else if (NULL == var_end) {
+ if ((buff[i] == ' ') ||
+ (buff[i] == '\t'))
+ var_end = &buff[i];
+ } else if (NULL == val) {
+ if (!((buff[i] == ' ') ||
+ (buff[i] == '\t')))
+ val = &buff[i];
+ } else if (NULL == val_end) {
+ if ((buff[i] == '\r') ||
+ (buff[i] == '\n')) {
+ /* look for escaped cr or ln */
+ if ('\\' == buff[i - 1]) {
+ /* check for dos */
+ if ((buff[i] == '\r') &&
+ (buff[i+1] == '\n'))
+ buff[i + 1] = ' ';
+ buff[i - 1] = buff[i] = ' ';
+ } else {
+ val_end = &buff[i];
+ }
+ }
+ } else {
+ sprintf(err_string, "Internal Error");
+
+ if (debug)
+ printf("Internal error at %s %d\n",
+ __FILE__, __LINE__);
+ return 1;
+ }
+ /* Check if a var / val pair is ready */
+ if (NULL != val_end) {
+ if (save) {
+ /* Set the end's with nulls so
+ normal string routines will
+ work.
+
+ WARNING : This changes the input */
+ *var_end = '\0';
+ *val_end = '\0';
+
+ save_env(ptn, var, val);
+
+ if (debug)
+ printf("Setting %s %s\n", var, val);
+ }
+
+ /* Clear the variable so state is parse is back
+ to initial. */
+ var = NULL;
+ var_end = NULL;
+ val = NULL;
+ val_end = NULL;
+
+ sets++;
+ }
+ }
+
+ /* Corner case
+ Check for the case that no newline at end of the input */
+ if ((NULL != var) &&
+ (NULL == val_end)) {
+ if (save) {
+ /* case of val / val pair */
+ if (var_end)
+ *var_end = '\0';
+ /* else case handled by setting 0 past
+ the end of buffer.
+ Similar for val_end being null */
+ save_env(ptn, var, val);
+
+ if (debug) {
+ if (var_end)
+ printf("Trailing Setting %s %s\n", var, val);
+ else
+ printf("Trailing Unsetting %s\n", var);
+ }
+ }
+ sets++;
+ }
+ /* Did we set anything ? */
+ if (0 == sets)
+ sprintf(err_string, "No variables set");
+ else
+ ret = 0;
+
+ return ret;
+}
+
+static int saveenv_to_ptn(struct fastboot_ptentry *ptn, char *err_string)
+{
+ int ret = 1;
+ int save = 0;
+ int debug = 0;
+
+ /* err_string is only 32 bytes
+ Initialize with a generic error message. */
+ sprintf(err_string, "%s", "Unknown Error");
+
+ /* Parse the input twice.
+ Only save to the enviroment if the entire input if correct */
+ save = 0;
+ if (0 == parse_env(ptn, err_string, save, debug)) {
+ save = 1;
+ ret = parse_env(ptn, err_string, save, debug);
+ }
+ return ret;
+}
+
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+
+static void process_flash_nand(const char *cmdbuf, char *response)
+{
+ if (download_bytes) {
+ struct fastboot_ptentry *ptn;
+
+ ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+ if (ptn == 0) {
+ sprintf(response, "FAILpartition does not exist");
+ } else if ((download_bytes > ptn->length) &&
+ !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+ sprintf(response, "FAILimage too large for partition");
+ /* TODO : Improve check for yaffs write */
+ } else {
+ /* Check if this is not really a flash write
+ but rather a saveenv */
+ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+ /* Since the response can only be 64 bytes,
+ there is no point in having a large error message. */
+ char err_string[32];
+ if (saveenv_to_ptn(ptn, &err_string[0])) {
+ printf("savenv '%s' failed : %s\n",
+ ptn->name, err_string);
+ sprintf(response, "FAIL%s", err_string);
+ } else {
+ printf("partition '%s' saveenv-ed\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ } else {
+ /* Normal case */
+ if (write_to_ptn(ptn)) {
+ printf("flashing '%s' failed\n", ptn->name);
+ sprintf(response, "FAILfailed to flash partition");
+ } else {
+ printf("partition '%s' flashed\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ }
+ }
+ } else {
+ sprintf(response, "FAILno image downloaded");
+ }
+
+}
+#endif
+
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+static void process_flash_sata(const char *cmdbuf, char *response)
+{
+ if (download_bytes) {
+ struct fastboot_ptentry *ptn;
+
+ /* Next is the partition name */
+ ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+ if (ptn == 0) {
+ printf("Partition:'%s' does not exist\n", ptn->name);
+ sprintf(response, "FAILpartition does not exist");
+ } else if ((download_bytes >
+ ptn->length * MMC_SATA_BLOCK_SIZE) &&
+ !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+ printf("Image too large for the partition\n");
+ sprintf(response, "FAILimage too large for partition");
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+ /* Since the response can only be 64 bytes,
+ there is no point in having a large error message. */
+ char err_string[32];
+ if (saveenv_to_ptn(ptn, &err_string[0])) {
+ printf("savenv '%s' failed : %s\n", ptn->name, err_string);
+ sprintf(response, "FAIL%s", err_string);
+ } else {
+ printf("partition '%s' saveenv-ed\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ } else {
+ unsigned int temp;
+ char sata_write[128];
+
+ /* block count */
+ temp = (download_bytes +
+ MMC_SATA_BLOCK_SIZE - 1) /
+ MMC_SATA_BLOCK_SIZE;
+
+ sprintf(sata_write, "sata write 0x%x 0x%x 0x%x",
+ (unsigned int)interface.transfer_buffer,
+ ptn->start,
+ temp)
+
+ if (run_command(sata_write, 0)) {
+ printf("Writing '%s' FAILED!\n",
+ ptn->name);
+ sprintf(response,
+ "FAIL: Write partition");
+ } else {
+ printf("Writing '%s' DONE!\n",
+ ptn->name);
+ sprintf(response, "OKAY");
+ }
+ }
+ } else {
+ sprintf(response, "FAILno image downloaded");
+ }
+
+}
+#endif
+
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+static void process_flash_mmc(const char *cmdbuf, char *response)
+{
+ if (download_bytes) {
+ struct fastboot_ptentry *ptn;
+
+ /* Next is the partition name */
+ ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+ if (ptn == 0) {
+ printf("Partition:'%s' does not exist\n", ptn->name);
+ sprintf(response, "FAILpartition does not exist");
+ } else if ((download_bytes >
+ ptn->length * MMC_SATA_BLOCK_SIZE) &&
+ !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+ printf("Image too large for the partition\n");
+ sprintf(response, "FAILimage too large for partition");
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+ /* Since the response can only be 64 bytes,
+ there is no point in having a large error message. */
+ char err_string[32];
+ if (saveenv_to_ptn(ptn, &err_string[0])) {
+ printf("savenv '%s' failed : %s\n", ptn->name, err_string);
+ sprintf(response, "FAIL%s", err_string);
+ } else {
+ printf("partition '%s' saveenv-ed\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ } else {
+ unsigned int temp;
+
+ char mmc_dev[128];
+ char mmc_write[128];
+ int mmcret;
+
+ printf("writing to partition '%s'\n", ptn->name);
+
+ if (ptn->partition_id != FASTBOOT_MMC_NONE_PARTITION_ID)
+ sprintf(mmc_dev, "mmc dev %x %x",
+ fastboot_devinfo.dev_id, /*slot no*/
+ ptn->partition_id /*part no*/);
+ else
+ sprintf(mmc_dev, "mmc dev %x",
+ fastboot_devinfo.dev_id /*slot no*/);
+
+ /* block count */
+ temp = (download_bytes +
+ MMC_SATA_BLOCK_SIZE - 1) /
+ MMC_SATA_BLOCK_SIZE;
+
+ sprintf(mmc_write, "mmc write 0x%x 0x%x 0x%x",
+ (unsigned int)interface.transfer_buffer, /*source*/
+ ptn->start, /*dest*/
+ temp /*length*/);
+
+ printf("Initializing '%s'\n", ptn->name);
+
+ mmcret = run_command(mmc_dev, 0);
+ if (mmcret)
+ sprintf(response, "FAIL:Init of MMC card");
+ else
+ sprintf(response, "OKAY");
+
+ printf("Writing '%s'\n", ptn->name);
+ if (run_command(mmc_write, 0)) {
+ printf("Writing '%s' FAILED!\n", ptn->name);
+ sprintf(response, "FAIL: Write partition");
+ } else {
+ printf("Writing '%s' DONE!\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ }
+ } else {
+ sprintf(response, "FAILno image downloaded");
+ }
+}
+
+#endif
+
+static void reset_handler ()
+{
+ /* If there was a download going on, bail */
+ download_size = 0;
+ download_bytes = 0;
+ download_bytes_unpadded = 0;
+ download_error = 0;
+ continue_booting = 0;
+ upload_size = 0;
+ upload_bytes = 0;
+ upload_error = 0;
+}
+
+static void rx_process_getvar(const char *cmdbuf, char *response)
+{
+ int temp_len = 0;
+
+ strcpy(response, "OKAY");
+
+ temp_len = strlen("getvar:");
+ if (!strcmp(cmdbuf + temp_len, "version")) {
+ strcpy(response + 4, FASTBOOT_VERSION);
+ } else if (!strcmp(cmdbuf + temp_len,
+ "product")) {
+ if (interface.product_name)
+ strcpy(response + 4, interface.product_name);
+
+ } else if (!strcmp(cmdbuf + temp_len,
+ "serialno")) {
+ if (interface.serial_no)
+ strcpy(response + 4, interface.serial_no);
+
+ } else if (!strcmp(cmdbuf + temp_len,
+ "downloadsize")) {
+ if (interface.transfer_buffer_size)
+ sprintf(response + 4, "0x%x",
+ interface.transfer_buffer_size);
+ } else {
+ fastboot_getvar(cmdbuf + 7, response + 4);
+ }
+}
+
+static void rx_process_reboot(const char *cmdbuf, char *response)
+{
+ sprintf(response, "OKAY");
+ fastboot_tx_status(response, strlen(response));
+ udelay(1000000); /* 1 sec */
+
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static int rx_process_erase(const char *cmdbuf, char *response)
+{
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ struct fastboot_ptentry *ptn;
+
+ ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+ if (ptn == 0) {
+ sprintf(response, "FAILpartition does not exist");
+ } else {
+ int status, repeat, repeat_max;
+
+ printf("erasing '%s'\n", ptn->name);
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ char lock[128];
+ char unlock[128];
+#endif
+ char erase[128];
+
+ repeat_max = 1;
+ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK)
+ repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;
+
+ for (repeat = 0; repeat < repeat_max;
+ repeat++) {
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ sprintf(lock, "nand lock 0x%x 0x%x",
+ ptn->start + (repeat * ptn->length),
+ ptn->length);
+ sprintf(unlock, "nand unlock 0x%x 0x%x",
+ ptn->start + (repeat * ptn->length),
+ ptn->length);
+#endif
+ sprintf(erase, "nand erase 0x%x 0x%x",
+ ptn->start + (repeat * ptn->length),
+ ptn->length);
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ run_command(unlock, 0);
+#endif
+ status = run_command(erase, 0);
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ run_command(lock, 0);
+#endif
+
+ if (status)
+ break;
+ }
+
+ if (status) {
+ sprintf(response,
+ "FAILfailed to erase partition");
+ } else {
+ printf("partition '%s' erased\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ }
+ return 0;
+#else
+ printf("Not support erase command for EMMC\n");
+ return -1;
+#endif
+
+}
+
+static void rx_process_flash(const char *cmdbuf, char *response)
+{
+ switch (fastboot_devinfo.type) {
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+ case DEV_SATA:
+ process_flash_sata(cmdbuf, response);
+ break;
+#endif
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case DEV_MMC:
+ process_flash_mmc(cmdbuf, response);
+ break;
+#endif
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ case DEV_NAND:
+ process_flash_nand(cmdbuf, response);
+ break;
+#endif
+ default:
+ printf("Not support flash command for current device %d\n",
+ fastboot_devinfo.type);
+ sprintf(response,
+ "FAILfailed to flash device");
+ break;
+ }
+}
+
+static void rx_process_boot(const char *cmdbuf, char *response)
+{
+ if ((download_bytes) &&
+ (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE <
+ download_bytes)) {
+ char start[32];
+ char *booti_args[4] = {"booti", NULL, "boot", NULL};
+
+ /*
+ * Use this later to determine if a command line was passed
+ * for the kernel.
+ */
+ /* struct fastboot_boot_img_hdr *fb_hdr = */
+ /* (struct fastboot_boot_img_hdr *) interface.transfer_buffer; */
+
+ /* Skip the mkbootimage header */
+ /* image_header_t *hdr = */
+ /* (image_header_t *) */
+ /* &interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE]; */
+
+ booti_args[1] = start;
+ sprintf(start, "0x%x", (unsigned int)interface.transfer_buffer);
+
+ /* Execution should jump to kernel so send the response
+ now and wait a bit. */
+ sprintf(response, "OKAY");
+ fastboot_tx_status(response, strlen(response));
+
+ printf("Booting kernel...\n");
+
+
+ /* Reserve for further use, this can
+ * be more convient for developer. */
+ /* if (strlen ((char *) &fb_hdr->cmdline[0])) */
+ /* set_env("bootargs", (char *) &fb_hdr->cmdline[0]); */
+
+ /* boot the boot.img */
+ do_booti(NULL, 0, 3, booti_args);
+
+
+ }
+ sprintf(response, "FAILinvalid boot image");
+}
+
+static void rx_process_upload(const char *cmdbuf, char *response)
+{
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ unsigned int adv, delim_index, len;
+ struct fastboot_ptentry *ptn;
+ unsigned int is_raw = 0;
+
+ /* Is this a raw read ? */
+ if (memcmp(cmdbuf, "uploadraw:", 10) == 0) {
+ is_raw = 1;
+ adv = 10;
+ } else {
+ adv = 7;
+ }
+
+ /* Scan to the next ':' to find when the size starts */
+ len = strlen(cmdbuf);
+ for (delim_index = adv;
+ delim_index < len; delim_index++) {
+ if (cmdbuf[delim_index] == ':') {
+ /* WARNING, cmdbuf is being modified. */
+ *((char *) &cmdbuf[delim_index]) = 0;
break;
- usb_gadget_handle_interrupts();
+ }
+ }
+
+ ptn = fastboot_flash_find_ptn(cmdbuf + adv);
+ if (ptn == 0) {
+ sprintf(response,
+ "FAILpartition does not exist");
+ } else {
+ /* This is how much the user is expecting */
+ unsigned int user_size;
+ /*
+ * This is the maximum size needed for
+ * this partition
+ */
+ unsigned int size;
+ /* This is the length of the data */
+ unsigned int length;
+ /*
+ * Used to check previous write of
+ * the parition
+ */
+ char env_ptn_length_var[128];
+ char *env_ptn_length_val;
+
+ user_size = 0;
+ if (delim_index < len)
+ user_size =
+ simple_strtoul(cmdbuf + delim_index + 1,
+ NULL, 16);
+
+ /* Make sure output is padded to block size */
+ length = ptn->length;
+ sprintf(env_ptn_length_var,
+ "%s_nand_size", ptn->name);
+ env_ptn_length_val = getenv(env_ptn_length_var);
+ if (env_ptn_length_val) {
+ length =
+ simple_strtoul(env_ptn_length_val,
+ NULL, 16);
+ /* Catch possible problems */
+ if (!length)
+ length = ptn->length;
+ }
+
+ size = length / interface.nand_block_size;
+ size *= interface.nand_block_size;
+ if (length % interface.nand_block_size)
+ size += interface.nand_block_size;
+
+ if (is_raw)
+ size += (size /
+ interface.nand_block_size) *
+ interface.nand_oob_size;
+
+ if (size > interface.transfer_buffer_size) {
+
+ sprintf(response, "FAILdata too large");
+
+ } else if (user_size == 0) {
+
+ /* Send the data response */
+ sprintf(response, "DATA%08x", size);
+
+ } else if (user_size != size) {
+ /* This is the wrong size */
+ sprintf(response, "FAIL");
+ } else {
+ /*
+ * This is where the transfer
+ * buffer is populated
+ */
+ unsigned char *buf =
+ interface.transfer_buffer;
+ char read[128];
+
+ /*
+ * Setting upload_size causes
+ * transfer to happen in main loop
+ */
+ upload_size = size;
+ upload_bytes = 0;
+ upload_error = 0;
+
+ /*
+ * Poison the transfer buffer, 0xff
+ * is erase value of nand
+ */
+ memset(buf, 0xff, upload_size);
+
+ /* Which flavor of read to use */
+ if (is_raw)
+ sprintf(read, "nand read.raw 0x%x 0x%x 0x%x",
+ (unsigned int)(interface.transfer_buffer),
+ ptn->start,
+ upload_size);
+ else
+ sprintf(read, "nand read.i 0x%x 0x%x 0x%x",
+ (unsigned int)(interface.transfer_buffer),
+ ptn->start,
+ upload_size);
+
+ run_command(read, 0);
+
+ /* Send the data response */
+ sprintf(response, "DATA%08x", size);
+ }
+ }
+#endif
+
+}
+
+static int tx_handler(void)
+{
+ if (upload_size) {
+
+ int bytes_written;
+ bytes_written = fastboot_tx(interface.transfer_buffer +
+ upload_bytes, upload_size -
+ upload_bytes);
+ if (bytes_written > 0) {
+
+ upload_bytes += bytes_written;
+ /* Check if this is the last */
+ if (upload_bytes == upload_size) {
+
+ /* Reset upload */
+ upload_size = 0;
+ upload_bytes = 0;
+ upload_error = 0;
+ }
+ }
+ }
+ return upload_error;
+}
+
+static int rx_handler (const unsigned char *buffer, unsigned int buffer_size)
+{
+ int ret = 1;
+
+ /*response buffer, Use 65 instead of 64
+ null gets dropped. strcpy's need the extra byte */
+ char response[FASTBOOT_RESPONSE_SIZE];
+
+ if (download_size) {
+ /* Something to download */
+
+ if (buffer_size) {
+ /* Handle possible overflow */
+ unsigned int transfer_size =
+ download_size - download_bytes;
+
+ if (buffer_size < transfer_size)
+ transfer_size = buffer_size;
+
+ /* Save the data to the transfer buffer */
+ memcpy(interface.transfer_buffer + download_bytes,
+ buffer, transfer_size);
+
+ download_bytes += transfer_size;
+
+ /* Check if transfer is done */
+ if (download_bytes >= download_size) {
+ /* Reset global transfer variable,
+ Keep download_bytes because it will be
+ used in the next possible flashing command */
+ download_size = 0;
+
+ if (download_error) {
+ /* There was an earlier error */
+ sprintf(response, "ERROR");
+ } else {
+ /* Everything has transferred,
+ send the OK response */
+ sprintf(response, "OKAY");
+ }
+ fastboot_tx_status(response, strlen(response));
+
+ printf("\ndownloading of %d bytes finished\n",
+ download_bytes);
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ /* Pad to block length
+ In most cases, padding the download to be
+ block aligned is correct. The exception is
+ when the following flash writes to the oob
+ area. This happens when the image is a
+ YAFFS image. Since we do not know what
+ the download is until it is flashed,
+ go ahead and pad it, but save the true
+ size in case if should have
+ been unpadded */
+ download_bytes_unpadded = download_bytes;
+ if (interface.nand_block_size) {
+ if (download_bytes %
+ interface.nand_block_size) {
+ unsigned int pad =
+ interface.nand_block_size -
+ (download_bytes % interface.nand_block_size);
+ unsigned int i;
+
+ for (i = 0; i < pad; i++) {
+ if (download_bytes >=
+ interface.transfer_buffer_size)
+ break;
+
+ interface.transfer_buffer[download_bytes] = 0;
+ download_bytes++;
+ }
+ }
+ }
+#endif
+ }
+
+ /* Provide some feedback */
+ if (download_bytes &&
+ 0 == (download_bytes %
+ (16 * interface.nand_block_size))) {
+ /* Some feeback that the
+ download is happening */
+ if (download_error)
+ printf("X");
+ else
+ printf(".");
+ if (0 == (download_bytes %
+ (80 * 16 *
+ interface.nand_block_size)))
+ printf("\n");
+
+ }
+ } else {
+ /* Ignore empty buffers */
+ printf("Warning empty download buffer\n");
+ printf("Ignoring\n");
+ }
+ ret = 0;
+ } else {
+ /* A command */
+
+ /* Cast to make compiler happy with string functions */
+ const char *cmdbuf = (char *) buffer;
+ printf("cmdbuf: %s\n", cmdbuf);
+
+ /* Generic failed response */
+ sprintf(response, "FAIL");
+
+ /* reboot
+ Reboot the board. */
+ if (memcmp(cmdbuf, "reboot", 6) == 0) {
+ rx_process_reboot(cmdbuf, response);
+ /* This code is unreachable,
+ leave it to make the compiler happy */
+ return 0;
+ }
+
+ /* getvar
+ Get common fastboot variables
+ Board has a chance to handle other variables */
+ if (memcmp(cmdbuf, "getvar:", 7) == 0) {
+ rx_process_getvar(cmdbuf, response);
+ ret = 0;
+ }
+
+ /* erase
+ Erase a register flash partition
+ Board has to set up flash partitions */
+ if (memcmp(cmdbuf, "erase:", 6) == 0)
+ ret = rx_process_erase(cmdbuf, response);
+
+ /* download
+ download something ..
+ What happens to it depends on the next command after data */
+
+ if (memcmp(cmdbuf, "download:", 9) == 0) {
+
+ /* save the size */
+ download_size = simple_strtoul(cmdbuf + 9, NULL, 16);
+ /* Reset the bytes count, now it is safe */
+ download_bytes = 0;
+ /* Reset error */
+ download_error = 0;
+
+ printf("Starting download of %d bytes\n",
+ download_size);
+
+ if (0 == download_size) {
+ /* bad user input */
+ sprintf(response, "FAILdata invalid size");
+ } else if (download_size >
+ interface.transfer_buffer_size) {
+ /* set download_size to 0 because this is an error */
+ download_size = 0;
+ sprintf(response, "FAILdata too large");
+ } else {
+ /* The default case, the transfer fits
+ completely in the interface buffer */
+ sprintf(response, "DATA%08x", download_size);
+ }
+ ret = 0;
+ }
+
+ /* boot
+ boot what was downloaded
+
+ WARNING WARNING WARNING
+
+ This is not what you expect.
+ The fastboot client does its own packaging of the
+ kernel. The layout is defined in the android header
+ file bootimage.h. This layeout is copiedlooks like this,
+
+ **
+ ** +-----------------+
+ ** | boot header | 1 page
+ ** +-----------------+
+ ** | kernel | n pages
+ ** +-----------------+
+ ** | ramdisk | m pages
+ ** +-----------------+
+ ** | second stage | o pages
+ ** +-----------------+
+ **
+
+ We only care about the kernel.
+ So we have to jump past a page.
+
+ What is a page size ?
+ The fastboot client uses 2048
+
+ The is the default value of
+
+ CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
+
+ */
+
+ if (memcmp(cmdbuf, "boot", 4) == 0) {
+ rx_process_boot(cmdbuf, response);
+ ret = 0;
+ }
+
+ /* flash
+ Flash what was downloaded */
+ if (memcmp(cmdbuf, "flash:", 6) == 0) {
+ rx_process_flash(cmdbuf, response);
+ ret = 0;
+ }
+
+ /* continue
+ Stop doing fastboot */
+ if (memcmp(cmdbuf, "continue", 8) == 0) {
+ sprintf(response, "OKAY");
+ continue_booting = 1;
+ ret = 0;
+ }
+
+ /* upload
+ Upload just the data in a partition */
+ if ((memcmp(cmdbuf, "upload:", 7) == 0) ||
+ (memcmp(cmdbuf, "uploadraw:", 10) == 0)) {
+ rx_process_upload(cmdbuf, response);
+ ret = 0;
+ }
+
+ fastboot_tx_status(response, strlen(response));
+
+ } /* End of command */
+
+ return ret;
+}
+
+int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int ret = 1;
+ int check_timeout = 0;
+ uint64_t timeout_endtime = 0;
+ uint64_t timeout_ticks = 1000;
+ int continue_from_disconnect = 0;
+
+ do {
+ continue_from_disconnect = 0;
+
+ /* Initialize the board specific support */
+ if (0 == fastboot_init(&interface)) {
+
+ int poll_status;
+
+ /* If we got this far, we are a success */
+ ret = 0;
+ printf("fastboot initialized\n");
+
+ timeout_endtime = get_timer(0);
+ timeout_endtime += timeout_ticks;
+
+ while (1) {
+ uint64_t current_time = 0;
+ poll_status = fastboot_poll();
+
+ if (1 == check_timeout)
+ current_time = get_timer(0);
+
+ if (FASTBOOT_ERROR == poll_status) {
+ /* Error */
+ break;
+ } else if (FASTBOOT_DISCONNECT == poll_status) {
+ /* beak, cleanup and re-init */
+ printf("Fastboot disconnect detected\n");
+ continue_from_disconnect = 1;
+ break;
+ } else if ((1 == check_timeout) &&
+ (FASTBOOT_INACTIVE == poll_status)) {
+
+ /* No activity */
+ if (current_time >= timeout_endtime) {
+ printf("Fastboot inactivity detected\n");
+ break;
+ }
+ } else {
+ /* Something happened */
+ if (1 == check_timeout) {
+ /* Update the timeout endtime */
+ timeout_endtime = current_time;
+ timeout_endtime += timeout_ticks;
+ }
+ }
+
+ /* Check if the user wanted to terminate with ^C */
+ if ((FASTBOOT_INACTIVE == poll_status) &&
+ (ctrlc())) {
+ printf("Fastboot ended by user\n");
+ break;
+ }
+
+ /*
+ * Check if the fastboot client wanted to
+ * continue booting
+ */
+ if (continue_booting) {
+ printf("Fastboot ended by client\n");
+ break;
+ }
+
+ /* Check if there is something to upload */
+ tx_handler();
+ }
+ }
+
+ /* Reset the board specific support */
+ fastboot_shutdown();
+
+ /* restart the loop if a disconnect was detected */
+ } while (continue_from_disconnect);
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ fastboot, 2, 1, do_fastboot,
+ "fastboot- use USB Fastboot protocol\n",
+ "[inactive timeout]\n"
+ " - Run as a fastboot usb device.\n"
+ " - The optional inactive timeout is the decimal seconds before\n"
+ " - the normal console resumes\n"
+);
+
+
+#ifdef CONFIG_CMD_BOOTI
+ /* Section for Android bootimage format support
+ * Refer:
+ * http://android.git.kernel.org/?p=platform/system/core.git;a=blob;
+ * f=mkbootimg/bootimg.h
+ */
+
+void
+bootimg_print_image_hdr(struct fastboot_boot_img_hdr *hdr)
+{
+#ifdef DEBUG
+ int i;
+ printf(" Image magic: %s\n", hdr->magic);
+
+ printf(" kernel_size: 0x%x\n", hdr->kernel_size);
+ printf(" kernel_addr: 0x%x\n", hdr->kernel_addr);
+
+ printf(" rdisk_size: 0x%x\n", hdr->ramdisk_size);
+ printf(" rdisk_addr: 0x%x\n", hdr->ramdisk_addr);
+
+ printf(" second_size: 0x%x\n", hdr->second_size);
+ printf(" second_addr: 0x%x\n", hdr->second_addr);
+
+ printf(" tags_addr: 0x%x\n", hdr->tags_addr);
+ printf(" page_size: 0x%x\n", hdr->page_size);
+
+ printf(" name: %s\n", hdr->name);
+ printf(" cmdline: %s%x\n", hdr->cmdline);
+
+ for (i = 0; i < 8; i++)
+ printf(" id[%d]: 0x%x\n", i, hdr->id[i]);
+#endif
+}
+
+static struct fastboot_boot_img_hdr boothdr __aligned(ARCH_DMA_MINALIGN);
+
+#define ALIGN_SECTOR(n, pagesz) ((n + (pagesz - 1)) & (~(pagesz - 1)))
+
+#ifdef CONFIG_LMB
+static void boot_start_lmb(bootm_headers_t *images)
+{
+ ulong mem_start;
+ phys_size_t mem_size;
+
+ lmb_init(&images->lmb);
+
+ mem_start = getenv_bootm_low();
+ mem_size = getenv_bootm_size();
+
+ lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size);
+
+ arch_lmb_reserve(&images->lmb);
+ board_lmb_reserve(&images->lmb);
+}
+#else
+#define lmb_reserve(lmb, base, size)
+static inline void boot_start_lmb(bootm_headers_t *images) { }
+#endif
+
+/* Allow for arch specific config before we boot */
+static void __arch_preboot_os(void)
+{
+ /* please define platform specific arch_preboot_os() */
+}
+void arch_preboot_os(void) __attribute__((weak, alias("__arch_preboot_os")));
+
+/* booti <addr> [ mmc0 | mmc1 [ <partition> ] ] */
+int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned addr = 0;
+ char *ptn = "boot";
+ int mmcc = -1;
+ struct fastboot_boot_img_hdr *hdr = &boothdr;
+#ifdef CONFIG_SECURE_BOOT
+ u_int32_t load_addr;
+ uint32_t image_size;
+#endif
+ int i = 0;
+ bootm_headers_t images;
+
+ for (i = 0; i < argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+
+ if (argc < 2)
+ return -1;
+
+ if (!strncmp(argv[1], "mmc", 3))
+ mmcc = simple_strtoul(argv[1]+3, NULL, 10);
+ else
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ if (argc > 2)
+ ptn = argv[2];
+
+ if (mmcc != -1) {
+#ifdef CONFIG_MMC
+ struct fastboot_ptentry *pte;
+ struct mmc *mmc;
+ disk_partition_t info;
+ block_dev_desc_t *dev_desc = NULL;
+ unsigned sector;
+
+ memset((void *)&info, 0 , sizeof(disk_partition_t));
+ /* i.MX use MBR as partition table, so this will have
+ to find the start block and length for the
+ partition name and register the fastboot pte we
+ define the partition number of each partition in
+ config file
+ */
+ mmc = find_mmc_device(mmcc);
+ if (!mmc) {
+ printf("booti: cannot find '%d' mmc device\n", mmcc);
+ goto fail;
+ }
+ dev_desc = get_dev("mmc", mmcc);
+ if (NULL == dev_desc) {
+ printf("** Block device MMC %d not supported\n", mmcc);
+ goto fail;
+ }
+
+ /* below was i.MX mmc operation code */
+ if (mmc_init(mmc)) {
+ printf("mmc%d init failed\n", mmcc);
+ goto fail;
+ }
+
+ pte = fastboot_flash_find_ptn(ptn);
+ if (!pte) {
+ printf("booti: cannot find '%s' partition\n", ptn);
+ goto fail;
+ }
+
+ if (mmc->block_dev.block_read(mmcc, pte->start,
+ 1, (void *)hdr) < 0) {
+ printf("booti: mmc failed to read bootimg header\n");
+ goto fail;
+ }
+
+ if (memcmp(hdr->magic, FASTBOOT_BOOT_MAGIC, 8)) {
+ printf("booti: bad boot image magic\n");
+ goto fail;
+ }
+
+ sector = pte->start + (hdr->page_size / 512);
+
+ if (mmc->block_dev.block_read(mmcc, sector,
+ (hdr->kernel_size / 512) + 1,
+ (void *)hdr->kernel_addr) < 0) {
+ printf("booti: mmc failed to read kernel\n");
+ goto fail;
+ }
+ /* flush cache after read */
+ flush_cache((ulong)hdr->kernel_addr, hdr->kernel_size); /* FIXME */
+ sector += ALIGN_SECTOR(hdr->kernel_size, hdr->page_size) / 512;
+ if (mmc->block_dev.block_read(mmcc, sector,
+ (hdr->ramdisk_size / 512) + 1,
+ (void *)hdr->ramdisk_addr) < 0) {
+ printf("booti: mmc failed to read ramdisk\n");
+ goto fail;
+ }
+ /* flush cache after read */
+ flush_cache((ulong)hdr->ramdisk_addr, hdr->ramdisk_size); /* FIXME */
+
+#ifdef CONFIG_OF_LIBFDT
+ /* load the dtb file */
+ if (hdr->second_size && hdr->second_addr) {
+ sector += ALIGN_SECTOR(hdr->ramdisk_size, hdr->page_size) / 512;
+ if (mmc->block_dev.block_read(mmcc, sector,
+ (hdr->second_size / 512) + 1,
+ (void *)hdr->second_addr) < 0) {
+ printf("booti: mmc failed to dtb\n");
+ goto fail;
+ }
+ /* flush cache after read */
+ flush_cache((ulong)hdr->second_addr, hdr->second_size); /* FIXME */
+ }
+#endif /*CONFIG_OF_LIBFDT*/
+
+#else /*! CONFIG_MMC*/
+ return -1;
+#endif /*! CONFIG_MMC*/
+ } else {
+ unsigned kaddr, raddr, end;
+#ifdef CONFIG_OF_LIBFDT
+ unsigned fdtaddr = 0;
+#endif
+
+ /* set this aside somewhere safe */
+ memcpy(hdr, (void *) addr, sizeof(*hdr));
+
+ if (memcmp(hdr->magic, FASTBOOT_BOOT_MAGIC, 8)) {
+ printf("booti: bad boot image magic\n");
+ return 1;
+ }
+
+ bootimg_print_image_hdr(hdr);
+
+ kaddr = addr + hdr->page_size;
+ raddr = kaddr + ALIGN_SECTOR(hdr->kernel_size, hdr->page_size);
+ end = raddr + hdr->ramdisk_size;
+#ifdef CONFIG_OF_LIBFDT
+ if (hdr->second_size) {
+ fdtaddr = raddr + ALIGN_SECTOR(hdr->ramdisk_size, hdr->page_size);
+ end = fdtaddr + hdr->second_size;
+ }
+#endif /*CONFIG_OF_LIBFDT*/
+ if (kaddr != hdr->kernel_addr) {
+ /*check overlap*/
+ if (((hdr->kernel_addr >= addr) &&
+ (hdr->kernel_addr <= end)) ||
+ ((addr >= hdr->kernel_addr) &&
+ (addr <= hdr->kernel_addr + hdr->kernel_size))) {
+ printf("Fail: booti address overlap with kernel address\n");
+ return 1;
+ }
+ memmove((void *) hdr->kernel_addr,
+ (void *)kaddr, hdr->kernel_size);
+ }
+ if (raddr != hdr->ramdisk_addr) {
+ /*check overlap*/
+ if (((hdr->ramdisk_addr >= addr) &&
+ (hdr->ramdisk_addr <= end)) ||
+ ((addr >= hdr->ramdisk_addr) &&
+ (addr <= hdr->ramdisk_addr + hdr->ramdisk_size))) {
+ printf("Fail: booti address overlap with ramdisk address\n");
+ return 1;
+ }
+ memmove((void *) hdr->ramdisk_addr,
+ (void *)raddr, hdr->ramdisk_size);
+ }
+
+#ifdef CONFIG_OF_LIBFDT
+ if (hdr->second_size && fdtaddr != hdr->second_addr) {
+ /*check overlap*/
+ if (((hdr->second_addr >= addr) &&
+ (hdr->second_addr <= end)) ||
+ ((addr >= hdr->second_addr) &&
+ (addr <= hdr->second_addr + hdr->second_size))) {
+ printf("Fail: booti address overlap with FDT address\n");
+ return 1;
+ }
+ memmove((void *) hdr->second_addr,
+ (void *)fdtaddr, hdr->second_size);
+ }
+#endif /*CONFIG_OF_LIBFDT*/
+ }
+
+ printf("kernel @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size);
+ printf("ramdisk @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size);
+#ifdef CONFIG_OF_LIBFDT
+ if (hdr->second_size)
+ printf("fdt @ %08x (%d)\n", hdr->second_addr, hdr->second_size);
+#endif /*CONFIG_OF_LIBFDT*/
+
+#ifdef CONFIG_SECURE_BOOT
+#define IVT_SIZE 0x20
+#define CSF_PAD_SIZE 0x2000
+ extern uint32_t authenticate_image(uint32_t ddr_start,
+ uint32_t image_size);
+
+ image_size = hdr->ramdisk_addr + hdr->ramdisk_size - hdr->kernel_addr -
+ IVT_SIZE - CSF_PAD_SIZE;
+
+ if (authenticate_image(hdr->kernel_addr, image_size)) {
+ printf("Authenticate OK\n");
+ } else {
+ printf("Authenticate image Fail, Please check\n\n");
+ return 1;
+ }
+#endif /*CONFIG_SECURE_BOOT*/
+
+#ifdef CONFIG_CMDLINE_TAG
+ char *commandline = getenv("bootargs");
+
+ /* If no bootargs env, just use hdr command line */
+ if (!commandline) {
+ commandline = (char *)hdr->cmdline;
+#ifdef CONFIG_SERIAL_TAG
+ char appended_cmd_line[FASTBOOT_BOOT_ARGS_SIZE];
+ struct tag_serialnr serialnr;
+ get_board_serial(&serialnr);
+ if (strlen((char *)hdr->cmdline) +
+ strlen("androidboot.serialno") + 17 < FASTBOOT_BOOT_ARGS_SIZE) {
+ sprintf(appended_cmd_line,
+ "%s androidboot.serialno=%08x%08x",
+ (char *)hdr->cmdline,
+ serialnr.high,
+ serialnr.low);
+ commandline = appended_cmd_line;
+ } else {
+ printf("Cannot append androidboot.serialno\n");
+ }
+
+ setenv("bootargs", commandline);
+#endif
}
- g_dnl_unregister();
- g_dnl_clear_detach();
- return CMD_RET_SUCCESS;
+ /* XXX: in production, you should always use boot.img 's cmdline !!! */
+ printf("kernel cmdline:\n");
+ printf("\tuse boot.img ");
+ printf("command line:\n\t%s\n", commandline);
+#endif /*CONFIG_CMDLINE_TAG*/
+
+ memset(&images, 0, sizeof(images));
+
+ /*Setup lmb for memory reserve*/
+ boot_start_lmb(&images);
+
+ images.ep = hdr->kernel_addr;
+ images.rd_start = hdr->ramdisk_addr;
+ images.rd_end = hdr->ramdisk_addr + hdr->ramdisk_size;
+
+ /*Reserve memory for kernel image*/
+ lmb_reserve(&images.lmb, images.ep, hdr->kernel_size);
+
+#ifdef CONFIG_OF_LIBFDT
+ /*use secondary fields for fdt, second_size= fdt size, second_addr= fdt addr*/
+ images.ft_addr = (char *)(hdr->second_addr);
+ images.ft_len = (ulong)(hdr->second_size);
+ set_working_fdt_addr((ulong)(images.ft_addr));
+#endif /*CONFIG_OF_LIBFDT*/
+
+ arch_preboot_os();
+
+ do_bootm_linux(0, 0, NULL, &images);
+
+ puts("booti: Control returned to monitor - resetting...\n");
+ do_reset(cmdtp, flag, argc, argv);
+ return 1;
+
+fail:
+#ifdef CONFIG_FASTBOOT
+ return do_fastboot(NULL, 0, 0, NULL);
+#else /*! CONFIG_FASTBOOT*/
+ return -1;
+#endif /*! CONFIG_FASTBOOT*/
}
U_BOOT_CMD(
- fastboot, 1, 0, do_fastboot,
- "use USB Fastboot protocol",
- "\n"
- " - run as a fastboot usb device"
+ booti, 3, 1, do_booti,
+ "booti - boot android bootimg from memory\n",
+ "[<addr> | mmc0 | mmc1 | mmc2 | mmcX] [<partition>]\n "
+ "- boot application image stored in memory or mmc\n"
+ "\t'addr' should be the address of boot image "
+ "which is zImage+ramdisk.img\n"
+ "\t'mmcX' is the mmc device you store your boot.img, "
+ "which will read the boot.img from 1M offset('/boot' partition)\n"
+ "\t 'partition' (optional) is the partition id of your device, "
+ "if no partition give, will going to 'boot' partition\n"
);
+#endif /* CONFIG_CMD_BOOTI */
+
+#endif /* CONFIG_FASTBOOT */
diff --git a/configs/mx6dlsabreautoandroid_defconfig b/configs/mx6dlsabreautoandroid_defconfig
new file mode 100644
index 0000000..2a2d0ac
--- /dev/null
+++ b/configs/mx6dlsabreautoandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6qsabreauto/mx6dl.cfg,MX6DL,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6QSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6dlsabreautoandroid_nand_defconfig b/configs/mx6dlsabreautoandroid_nand_defconfig
new file mode 100644
index 0000000..30b170f
--- /dev/null
+++ b/configs/mx6dlsabreautoandroid_nand_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6qsabreauto/mx6dl.cfg,MX6DL,SYS_BOOT_NAND,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6QSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6dlsabresdandroid_defconfig b/configs/mx6dlsabresdandroid_defconfig
new file mode 100644
index 0000000..fc3843b
--- /dev/null
+++ b/configs/mx6dlsabresdandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6sabresd/mx6dlsabresd.cfg,MX6DL,SYS_USE_SPINOR,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6SABRESD=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6qsabreautoandroid_defconfig b/configs/mx6qsabreautoandroid_defconfig
new file mode 100644
index 0000000..03989eb
--- /dev/null
+++ b/configs/mx6qsabreautoandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6qsabreauto/imximage.cfg,MX6Q,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6QSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6qsabreautoandroid_nand_defconfig b/configs/mx6qsabreautoandroid_nand_defconfig
new file mode 100644
index 0000000..2659bc9
--- /dev/null
+++ b/configs/mx6qsabreautoandroid_nand_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6qsabreauto/imximage.cfg,MX6Q,SYS_BOOT_NAND,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6QSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6qsabresdandroid_defconfig b/configs/mx6qsabresdandroid_defconfig
new file mode 100644
index 0000000..fe5d3ab
--- /dev/null
+++ b/configs/mx6qsabresdandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6sabresd/mx6q_4x_mt41j128.cfg,MX6Q,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6SABRESD=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6slevkandroid_defconfig b/configs/mx6slevkandroid_defconfig
new file mode 100644
index 0000000..abde409
--- /dev/null
+++ b/configs/mx6slevkandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6slevk/imximage.cfg,MX6SL,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6SLEVK=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6solosabreautoandroid_defconfig b/configs/mx6solosabreautoandroid_defconfig
new file mode 100644
index 0000000..c09c52b
--- /dev/null
+++ b/configs/mx6solosabreautoandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,SYS_NOSMP="nosmp",ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6QSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6solosabreautoandroid_nand_defconfig b/configs/mx6solosabreautoandroid_nand_defconfig
new file mode 100644
index 0000000..8641e5f
--- /dev/null
+++ b/configs/mx6solosabreautoandroid_nand_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,SYS_NOSMP="nosmp",SYS_BOOT_NAND,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6QSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6solosabresdandroid_defconfig b/configs/mx6solosabresdandroid_defconfig
new file mode 100644
index 0000000..7fb3135
--- /dev/null
+++ b/configs/mx6solosabresdandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6sabresd/mx6solo_4x_mt41j128.cfg,MX6SOLO,SYS_USE_SPINOR,SYS_NOSMP="nosmp",ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6SABRESD=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6sxsabreautoandroid_defconfig b/configs/mx6sxsabreautoandroid_defconfig
new file mode 100644
index 0000000..d283ea8
--- /dev/null
+++ b/configs/mx6sxsabreautoandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6sxsabreauto/imximage.cfg,MX6SX,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6SXSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6sxsabreautoandroid_nand_defconfig b/configs/mx6sxsabreautoandroid_nand_defconfig
new file mode 100644
index 0000000..c3ae52e
--- /dev/null
+++ b/configs/mx6sxsabreautoandroid_nand_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6sxsabreauto/imximage.cfg,MX6SX,SYS_BOOT_NAND,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6SXSABREAUTO=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/configs/mx6sxsabresdandroid_defconfig b/configs/mx6sxsabresdandroid_defconfig
new file mode 100644
index 0000000..d2ab71e
--- /dev/null
+++ b/configs/mx6sxsabresdandroid_defconfig
@@ -0,0 +1,7 @@
+CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6sxsabresd/imximage.cfg,MX6SX,ANDROID_SUPPORT"
+CONFIG_ARM=y
+CONFIG_TARGET_MX6SXSABRESD=y
+CONFIG_SYS_MALLOC_F=y
+CONFIG_SYS_MALLOC_F_LEN=0x400
+CONFIG_DM=y
+CONFIG_DM_THERMAL=y
diff --git a/drivers/Makefile b/drivers/Makefile
index 5ef58c0..2350a9a 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -23,3 +23,4 @@ obj-y += input/
# SOC specific infrastructure drivers.
obj-y += soc/
obj-y += thermal/
+obj-y += fastboot/
diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile
new file mode 100644
index 0000000..251120d
--- /dev/null
+++ b/drivers/fastboot/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_FASTBOOT) += fastboot.o
diff --git a/drivers/fastboot/fastboot.c b/drivers/fastboot/fastboot.c
new file mode 100644
index 0000000..0b5bebb
--- /dev/null
+++ b/drivers/fastboot/fastboot.c
@@ -0,0 +1,1127 @@
+/*
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <config.h>
+#include <malloc.h>
+#include <fastboot.h>
+#include <usb/imx_udc.h>
+#include <asm/io.h>
+#include <usbdevice.h>
+#include <mmc.h>
+#include <sata.h>
+#ifdef CONFIG_ANDROID_RECOVERY
+#include <recovery.h>
+#endif
+
+/*
+ * Defines
+ */
+#define NUM_ENDPOINTS 2
+
+#define CONFIG_USBD_OUT_PKTSIZE 0x200
+#define CONFIG_USBD_IN_PKTSIZE 0x200
+#define MAX_BUFFER_SIZE 0x200
+
+/*
+ * imx family android layout
+ * mbr - 0 ~ 0x3FF byte
+ * bootloader - 0x400 ~ 0xFFFFF byte
+ * kernel - 0x100000 ~ 5FFFFF byte
+ * uramedisk - 0x600000 ~ 0x6FFFFF supposing 1M temporarily
+ * SYSTEM partition - /dev/mmcblk0p2 or /dev/sda2
+ * RECOVERY parittion - dev/mmcblk0p4 or /dev/sda4
+ */
+#define ANDROID_MBR_OFFSET 0
+#define ANDROID_MBR_SIZE 0x200
+#define ANDROID_BOOTLOADER_OFFSET 0x400
+#define ANDROID_BOOTLOADER_SIZE 0xFFC00
+#define ANDROID_KERNEL_OFFSET 0x100000
+#define ANDROID_KERNEL_SIZE 0x500000
+#define ANDROID_URAMDISK_OFFSET 0x600000
+#define ANDROID_URAMDISK_SIZE 0x100000
+
+#define STR_LANG_INDEX 0x00
+#define STR_MANUFACTURER_INDEX 0x01
+#define STR_PRODUCT_INDEX 0x02
+#define STR_SERIAL_INDEX 0x03
+#define STR_CONFIG_INDEX 0x04
+#define STR_DATA_INTERFACE_INDEX 0x05
+#define STR_CTRL_INTERFACE_INDEX 0x06
+#define STR_COUNT 0x07
+
+#define FASTBOOT_FBPARTS_ENV_MAX_LEN 1024
+/* To support the Android-style naming of flash */
+#define MAX_PTN 16
+
+
+/*pentry index internally*/
+enum {
+ PTN_MBR_INDEX = 0,
+ PTN_BOOTLOADER_INDEX,
+ PTN_KERNEL_INDEX,
+ PTN_URAMDISK_INDEX,
+ PTN_SYSTEM_INDEX,
+ PTN_RECOVERY_INDEX
+};
+
+struct fastboot_device_info fastboot_devinfo;
+
+/* defined and used by gadget/ep0.c */
+extern struct usb_string_descriptor **usb_strings;
+
+static struct usb_device_instance device_instance[1];
+static struct usb_bus_instance bus_instance[1];
+static struct usb_configuration_instance config_instance[1];
+static struct usb_interface_instance interface_instance[1];
+static struct usb_alternate_instance alternate_instance[1];
+/* one extra for control endpoint */
+static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];
+
+static struct cmd_fastboot_interface *fastboot_interface;
+static int fastboot_configured_flag;
+static int usb_disconnected;
+
+/* Indicies, References */
+static u8 rx_endpoint;
+static u8 tx_endpoint;
+static struct usb_string_descriptor *fastboot_string_table[STR_COUNT];
+
+/* USB Descriptor Strings */
+static u8 wstrLang[4] = {4, USB_DT_STRING, 0x9, 0x4};
+static u8 wstrManufacturer[2 * (sizeof(CONFIG_FASTBOOT_MANUFACTURER_STR))];
+static u8 wstrProduct[2 * (sizeof(CONFIG_FASTBOOT_PRODUCT_NAME_STR))];
+static u8 wstrSerial[2*(sizeof(CONFIG_FASTBOOT_SERIAL_NUM))];
+static u8 wstrConfiguration[2 * (sizeof(CONFIG_FASTBOOT_CONFIGURATION_STR))];
+static u8 wstrDataInterface[2 * (sizeof(CONFIG_FASTBOOT_INTERFACE_STR))];
+
+/* Standard USB Data Structures */
+static struct usb_interface_descriptor interface_descriptors[1];
+static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
+static struct usb_configuration_descriptor *configuration_descriptor;
+static struct usb_device_descriptor device_descriptor = {
+ .bLength = sizeof(struct usb_device_descriptor),
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = cpu_to_le16(USB_BCD_VERSION),
+ .bDeviceClass = 0xff,
+ .bDeviceSubClass = 0xff,
+ .bDeviceProtocol = 0xff,
+ .bMaxPacketSize0 = 0x40,
+ .idVendor = cpu_to_le16(CONFIG_FASTBOOT_VENDOR_ID),
+ .idProduct = cpu_to_le16(CONFIG_FASTBOOT_PRODUCT_ID),
+ .bcdDevice = cpu_to_le16(CONFIG_FASTBOOT_BCD_DEVICE),
+ .iManufacturer = STR_MANUFACTURER_INDEX,
+ .iProduct = STR_PRODUCT_INDEX,
+ .iSerialNumber = STR_SERIAL_INDEX,
+ .bNumConfigurations = 1
+};
+
+/*
+ * Static Generic Serial specific data
+ */
+
+struct fastboot_config_desc {
+ struct usb_configuration_descriptor configuration_desc;
+ struct usb_interface_descriptor interface_desc[1];
+ struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS];
+};
+
+static struct fastboot_config_desc
+fastboot_configuration_descriptors[1] = {
+ {
+ .configuration_desc = {
+ .bLength = sizeof(struct usb_configuration_descriptor),
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength =
+ cpu_to_le16(sizeof(struct fastboot_config_desc)),
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_INDEX,
+ .bmAttributes =
+ BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+ .bMaxPower = 0x32
+ },
+ .interface_desc = {
+ {
+ .bLength =
+ sizeof(struct usb_interface_descriptor),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = NUM_ENDPOINTS,
+ .bInterfaceClass =
+ FASTBOOT_INTERFACE_CLASS,
+ .bInterfaceSubClass =
+ FASTBOOT_INTERFACE_SUB_CLASS,
+ .bInterfaceProtocol =
+ FASTBOOT_INTERFACE_PROTOCOL,
+ .iInterface = STR_DATA_INTERFACE_INDEX
+ },
+ },
+ .data_endpoints = {
+ {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = UDC_OUT_ENDPOINT |
+ USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize =
+ cpu_to_le16(CONFIG_USBD_OUT_PKTSIZE),
+ .bInterval = 0x00,
+ },
+ {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = UDC_IN_ENDPOINT |
+ USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize =
+ cpu_to_le16(CONFIG_USBD_IN_PKTSIZE),
+ .bInterval = 0x00,
+ },
+ },
+ },
+};
+
+
+
+static struct fastboot_ptentry ptable[MAX_PTN];
+static unsigned int pcount;
+
+
+/* Static Function Prototypes */
+static void _fastboot_init_strings(void);
+static void _fastboot_init_instances(void);
+static void _fastboot_init_endpoints(void);
+static void _fastboot_event_handler(struct usb_device_instance *device,
+ usb_device_event_t event, int data);
+static int _fastboot_cdc_setup(struct usb_device_request *request,
+ struct urb *urb);
+static int _fastboot_usb_configured(void);
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \
+ || defined(CONFIG_FASTBOOT_STORAGE_MMC)
+static int _fastboot_parts_load_from_ptable(void);
+#endif
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+static int _fastboot_parts_load_from_env(void);
+#endif
+static int _fastboot_setup_dev(void);
+static void _fastboot_load_partitions(void);
+
+/* utility function for converting char* to wide string used by USB */
+static void str2wide(char *str, u16 * wide)
+{
+ int i;
+ for (i = 0; i < strlen(str) && str[i]; i++) {
+ #if defined(__LITTLE_ENDIAN)
+ wide[i] = (u16) str[i];
+ #elif defined(__BIG_ENDIAN)
+ wide[i] = ((u16)(str[i])<<8);
+ #else
+ #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined"
+ #endif
+ }
+}
+
+/*
+ Get mmc control number from passed string, eg, "mmc1" mean device 1. Only
+ support "mmc0" to "mmc9" currently. It will be treated as device 0 for
+ other string.
+*/
+static int _fastboot_get_mmc_no(char *env_str)
+{
+ int digit = 0;
+ unsigned char a;
+
+ if (env_str && (strlen(env_str) >= 4) &&
+ !strncmp(env_str, "mmc", 3)) {
+ a = env_str[3];
+ if (a >= '0' && a <= '9')
+ digit = a - '0';
+ }
+
+ return digit;
+}
+
+static int _fastboot_setup_dev(void)
+{
+ char *fastboot_env;
+ fastboot_env = getenv("fastboot_dev");
+
+ if (fastboot_env) {
+ if (!strcmp(fastboot_env, "sata")) {
+ fastboot_devinfo.type = DEV_SATA;
+ fastboot_devinfo.dev_id = 0;
+ } else if (!strcmp(fastboot_env, "nand")) {
+ fastboot_devinfo.type = DEV_NAND;
+ fastboot_devinfo.dev_id = 0;
+ } else if (!strncmp(fastboot_env, "mmc", 3)) {
+ fastboot_devinfo.type = DEV_MMC;
+ fastboot_devinfo.dev_id = _fastboot_get_mmc_no(fastboot_env);
+ }
+ } else {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Initialize fastboot
+ */
+int fastboot_init(struct cmd_fastboot_interface *interface)
+{
+ printf("fastboot is in init......");
+
+ fastboot_interface = interface;
+ fastboot_interface->product_name = CONFIG_FASTBOOT_PRODUCT_NAME_STR;
+ fastboot_interface->serial_no = CONFIG_FASTBOOT_SERIAL_NUM;
+ fastboot_interface->nand_block_size = 4096;
+ fastboot_interface->transfer_buffer =
+ (unsigned char *)CONFIG_FASTBOOT_TRANSFER_BUF;
+ fastboot_interface->transfer_buffer_size =
+ CONFIG_FASTBOOT_TRANSFER_BUF_SIZE;
+
+ _fastboot_init_strings();
+ /* Basic USB initialization */
+ udc_init();
+
+ _fastboot_init_instances();
+
+ udc_startup_events(device_instance);
+ udc_connect(); /* Enable pullup for host detection */
+
+ return 0;
+}
+
+static void _fastboot_init_strings(void)
+{
+ struct usb_string_descriptor *string;
+
+ fastboot_string_table[STR_LANG_INDEX] =
+ (struct usb_string_descriptor *)wstrLang;
+
+ string = (struct usb_string_descriptor *)wstrManufacturer;
+ string->bLength = sizeof(wstrManufacturer);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_FASTBOOT_MANUFACTURER_STR, string->wData);
+ fastboot_string_table[STR_MANUFACTURER_INDEX] = string;
+
+ string = (struct usb_string_descriptor *)wstrProduct;
+ string->bLength = sizeof(wstrProduct);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_FASTBOOT_PRODUCT_NAME_STR, string->wData);
+ fastboot_string_table[STR_PRODUCT_INDEX] = string;
+
+ string = (struct usb_string_descriptor *)wstrSerial;
+ string->bLength = sizeof(wstrSerial);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_FASTBOOT_SERIAL_NUM, string->wData);
+ fastboot_string_table[STR_SERIAL_INDEX] = string;
+
+ string = (struct usb_string_descriptor *)wstrConfiguration;
+ string->bLength = sizeof(wstrConfiguration);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_FASTBOOT_CONFIGURATION_STR, string->wData);
+ fastboot_string_table[STR_CONFIG_INDEX] = string;
+
+ string = (struct usb_string_descriptor *) wstrDataInterface;
+ string->bLength = sizeof(wstrDataInterface);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_FASTBOOT_INTERFACE_STR, string->wData);
+ fastboot_string_table[STR_DATA_INTERFACE_INDEX] = string;
+
+ /* Now, initialize the string table for ep0 handling */
+ usb_strings = fastboot_string_table;
+}
+
+static void _fastboot_init_instances(void)
+{
+ int i;
+ u16 temp;
+
+ /* Assign endpoint descriptors */
+ ep_descriptor_ptrs[0] =
+ &fastboot_configuration_descriptors[0].data_endpoints[0];
+ ep_descriptor_ptrs[1] =
+ &fastboot_configuration_descriptors[0].data_endpoints[1];
+
+ /* Configuration Descriptor */
+ configuration_descriptor =
+ (struct usb_configuration_descriptor *)
+ &fastboot_configuration_descriptors;
+
+ fastboot_configured_flag = 0;
+
+ /* initialize device instance */
+ memset(device_instance, 0, sizeof(struct usb_device_instance));
+ device_instance->device_state = STATE_INIT;
+ device_instance->device_descriptor = &device_descriptor;
+ device_instance->event = _fastboot_event_handler;
+ device_instance->cdc_recv_setup = _fastboot_cdc_setup;
+ device_instance->bus = bus_instance;
+ device_instance->configurations = 1;
+ device_instance->configuration_instance_array = config_instance;
+
+ /* initialize bus instance */
+ memset(bus_instance, 0, sizeof(struct usb_bus_instance));
+ bus_instance->device = device_instance;
+ bus_instance->endpoint_array = endpoint_instance;
+ bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
+ bus_instance->maxpacketsize = 0xFF;
+ bus_instance->serial_number_str = CONFIG_FASTBOOT_SERIAL_NUM;
+
+ /* configuration instance */
+ memset(config_instance, 0,
+ sizeof(struct usb_configuration_instance));
+ config_instance->interfaces = 1;
+ config_instance->configuration_descriptor = configuration_descriptor;
+ config_instance->interface_instance_array = interface_instance;
+
+ /* interface instance */
+ memset(interface_instance, 0,
+ sizeof(struct usb_interface_instance));
+ interface_instance->alternates = 1;
+ interface_instance->alternates_instance_array = alternate_instance;
+
+ /* alternates instance */
+ memset(alternate_instance, 0,
+ sizeof(struct usb_alternate_instance));
+ alternate_instance->interface_descriptor = interface_descriptors;
+ alternate_instance->endpoints = NUM_ENDPOINTS;
+ alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs;
+
+ /* endpoint instances */
+ memset(&endpoint_instance[0], 0,
+ sizeof(struct usb_endpoint_instance));
+ endpoint_instance[0].endpoint_address = 0;
+ endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE;
+ endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL;
+ endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE;
+ endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL;
+ udc_setup_ep(device_instance, 0, &endpoint_instance[0]);
+
+ for (i = 1; i <= NUM_ENDPOINTS; i++) {
+ memset(&endpoint_instance[i], 0,
+ sizeof(struct usb_endpoint_instance));
+
+ endpoint_instance[i].endpoint_address =
+ ep_descriptor_ptrs[i - 1]->bEndpointAddress;
+
+ endpoint_instance[i].rcv_attributes =
+ ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+ /*fix the abort caused by unalignment*/
+ temp = *(u8 *)&ep_descriptor_ptrs[i - 1]->wMaxPacketSize;
+ temp |=
+ (*(((u8 *)&ep_descriptor_ptrs[i - 1]->wMaxPacketSize) + 1) << 8);
+
+ endpoint_instance[i].rcv_packetSize =
+ le16_to_cpu(temp);
+
+ endpoint_instance[i].tx_attributes =
+ ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+ endpoint_instance[i].tx_packetSize =
+ le16_to_cpu(temp);
+
+ endpoint_instance[i].tx_attributes =
+ ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+ urb_link_init(&endpoint_instance[i].rcv);
+ urb_link_init(&endpoint_instance[i].rdy);
+ urb_link_init(&endpoint_instance[i].tx);
+ urb_link_init(&endpoint_instance[i].done);
+
+ if (endpoint_instance[i].endpoint_address & USB_DIR_IN) {
+ tx_endpoint = i;
+ endpoint_instance[i].tx_urb =
+ usbd_alloc_urb(device_instance,
+ &endpoint_instance[i]);
+ } else {
+ rx_endpoint = i;
+ endpoint_instance[i].rcv_urb =
+ usbd_alloc_urb(device_instance,
+ &endpoint_instance[i]);
+ }
+ }
+}
+
+static void _fastboot_init_endpoints(void)
+{
+ int i;
+
+ bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
+ for (i = 1; i <= NUM_ENDPOINTS; i++)
+ udc_setup_ep(device_instance, i, &endpoint_instance[i]);
+}
+
+static void _fastboot_destroy_endpoints(void)
+{
+ int i;
+ struct urb *tx_urb;
+
+ for (i = 1; i <= NUM_ENDPOINTS; i++) {
+ /*dealloc urb*/
+ if (endpoint_instance[i].endpoint_address & USB_DIR_IN) {
+ if (endpoint_instance[i].tx_urb)
+ usbd_dealloc_urb(endpoint_instance[i].tx_urb);
+
+ while (endpoint_instance[i].tx_queue) {
+ tx_urb = first_urb_detached(&endpoint_instance[i].tx);
+ if (tx_urb) {
+ usbd_dealloc_urb(tx_urb);
+ endpoint_instance[i].tx_queue--;
+ } else {
+ break;
+ }
+ }
+ endpoint_instance[i].tx_queue = 0;
+
+ do {
+ tx_urb = first_urb_detached(&endpoint_instance[i].done);
+ if (tx_urb)
+ usbd_dealloc_urb(tx_urb);
+ } while (tx_urb);
+
+ } else {
+ if (endpoint_instance[i].rcv_urb)
+ usbd_dealloc_urb(endpoint_instance[i].rcv_urb);
+ }
+
+ udc_destroy_ep(device_instance, &endpoint_instance[i]);
+ }
+}
+
+
+static int _fill_buffer(u8 *buf)
+{
+ struct usb_endpoint_instance *endpoint =
+ &endpoint_instance[rx_endpoint];
+
+ if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
+ unsigned int nb = 0;
+ char *src = (char *)endpoint->rcv_urb->buffer;
+ unsigned int rx_avail = MAX_BUFFER_SIZE;
+
+ if (rx_avail >= endpoint->rcv_urb->actual_length) {
+ nb = endpoint->rcv_urb->actual_length;
+ memcpy(buf, src, nb);
+ endpoint->rcv_urb->actual_length = 0;
+ }
+ return nb;
+ }
+ return 0;
+}
+
+static struct urb *_next_urb(struct usb_device_instance *device,
+ struct usb_endpoint_instance *endpoint)
+{
+ struct urb *current_urb = NULL;
+ int space;
+
+ /* If there's a queue, then we should add to the last urb */
+ if (!endpoint->tx_queue)
+ current_urb = endpoint->tx_urb;
+ else
+ /* Last urb from tx chain */
+ current_urb =
+ p2surround(struct urb, link, endpoint->tx.prev);
+
+ /* Make sure this one has enough room */
+ space = current_urb->buffer_length - current_urb->actual_length;
+ if (space > 0)
+ return current_urb;
+ else { /* No space here */
+ /* First look at done list */
+ current_urb = first_urb_detached(&endpoint->done);
+ if (!current_urb)
+ current_urb = usbd_alloc_urb(device, endpoint);
+
+ urb_append(&endpoint->tx, current_urb);
+ endpoint->tx_queue++;
+ }
+ return current_urb;
+}
+
+static int _fastboot_usb_configured(void)
+{
+ return fastboot_configured_flag;
+}
+
+static void _fastboot_event_handler(struct usb_device_instance *device,
+ usb_device_event_t event, int data)
+{
+ switch (event) {
+ case DEVICE_RESET:
+ case DEVICE_BUS_INACTIVE:
+ fastboot_configured_flag = 0;
+ break;
+ case DEVICE_CONFIGURED:
+ fastboot_configured_flag = 1;
+ _fastboot_init_endpoints();
+ break;
+ case DEVICE_ADDRESS_ASSIGNED:
+ default:
+ break;
+ }
+}
+
+static int _fastboot_cdc_setup(struct usb_device_request *request,
+ struct urb *urb)
+{
+ return 0;
+}
+
+
+/*!
+ * Function to receive data from host through channel
+ *
+ * @buf buffer to fill in
+ * @count read data size
+ *
+ * @return 0
+ */
+int fastboot_usb_recv(u8 *buf, int count)
+{
+ int len = 0;
+
+ while (!_fastboot_usb_configured())
+ udc_irq();
+
+ /* update rxqueue to wait new data */
+ mxc_udc_rxqueue_update(2, count);
+
+ while (!len) {
+ if (is_usb_disconnected()) {
+ /*it will not unconfigure when disconnect
+ from host, so here needs manual unconfigure
+ anyway, it's just a workaround*/
+ fastboot_configured_flag = 0;
+ usb_disconnected = 1;
+ return 0;
+ }
+ udc_irq();
+ if (_fastboot_usb_configured())
+ len = _fill_buffer(buf);
+ }
+ return len;
+}
+
+int fastboot_getvar(const char *rx_buffer, char *tx_buffer)
+{
+ /* Place board specific variables here */
+ return 0;
+}
+
+int fastboot_poll()
+{
+ u8 buffer[MAX_BUFFER_SIZE];
+ int length = 0;
+
+ memset(buffer, 0, MAX_BUFFER_SIZE);
+
+ length = fastboot_usb_recv(buffer, MAX_BUFFER_SIZE);
+
+ /* If usb disconnected, blocked here to wait */
+ if (usb_disconnected) {
+ udc_disconnect();
+ udc_connect();
+ /*the udc_connect will be blocked until connect to host
+ so, the usb_disconnect should be 0 after udc_connect,
+ and should be set manually. Anyway, it's just a workaround*/
+ usb_disconnected = 0;
+ }
+
+ if (!length)
+ return FASTBOOT_INACTIVE;
+
+ /* Pass this up to the interface's handler */
+ if (fastboot_interface && fastboot_interface->rx_handler) {
+ if (!fastboot_interface->rx_handler(buffer, length))
+ return FASTBOOT_OK;
+ }
+ return FASTBOOT_OK;
+}
+
+int fastboot_tx(unsigned char *buffer, unsigned int buffer_size)
+{
+ /* Not realized yet */
+ return 0;
+}
+
+static int _fastboot_write_buffer(const char *buffer,
+ unsigned int buffer_size)
+{
+ struct usb_endpoint_instance *endpoint =
+ (struct usb_endpoint_instance *)&endpoint_instance[tx_endpoint];
+ struct urb *current_urb = NULL;
+
+ if (!_fastboot_usb_configured())
+ return 0;
+
+ current_urb = _next_urb(device_instance, endpoint);
+ if (buffer_size) {
+ char *dest;
+ int space_avail, popnum, count, total = 0;
+
+ /* Break buffer into urb sized pieces,
+ * and link each to the endpoint
+ */
+ count = buffer_size;
+ while (count > 0) {
+ if (!current_urb) {
+ printf("current_urb is NULL, buffer_size %d\n",
+ buffer_size);
+ return total;
+ }
+
+ dest = (char *)current_urb->buffer +
+ current_urb->actual_length;
+
+ space_avail = current_urb->buffer_length -
+ current_urb->actual_length;
+ popnum = min(space_avail, count);
+ if (popnum == 0)
+ break;
+
+ memcpy(dest, buffer + total, popnum);
+ printf("send: %s\n", (char *)buffer);
+
+ current_urb->actual_length += popnum;
+ total += popnum;
+
+ if (udc_endpoint_write(endpoint))
+ /* Write pre-empted by RX */
+ return 0;
+ count -= popnum;
+ } /* end while */
+ return total;
+ }
+ return 0;
+}
+
+int fastboot_tx_status(const char *buffer, unsigned int buffer_size)
+{
+ int len = 0;
+
+ while (buffer_size > 0) {
+ len = _fastboot_write_buffer(buffer + len, buffer_size);
+ buffer_size -= len;
+
+ udc_irq();
+ }
+ udc_irq();
+
+ return 0;
+}
+
+void fastboot_shutdown(void)
+{
+ usb_shutdown();
+
+ /* Reset interface*/
+ if (fastboot_interface &&
+ fastboot_interface->reset_handler) {
+ fastboot_interface->reset_handler();
+ }
+
+ /* Reset some globals */
+ _fastboot_destroy_endpoints();
+ fastboot_interface = NULL;
+ fastboot_configured_flag = 0;
+ usb_disconnected = 0;
+
+ /*free memory*/
+ udc_destroy();
+}
+
+/*
+ * CPU and board-specific fastboot initializations. Aliased function
+ * signals caller to move on
+ */
+static void __def_fastboot_setup(void)
+{
+ /*do nothing here*/
+}
+void board_fastboot_setup(void) \
+ __attribute__((weak, alias("__def_fastboot_setup")));
+
+
+void fastboot_setup(void)
+{
+ /*execute board relevant initilizations for preparing fastboot */
+ board_fastboot_setup();
+
+ /*get the fastboot dev*/
+ _fastboot_setup_dev();
+
+ /*check if we need to setup recovery*/
+#ifdef CONFIG_ANDROID_RECOVERY
+ check_recovery_mode();
+#endif
+
+ /*load partitions information for the fastboot dev*/
+ _fastboot_load_partitions();
+}
+
+/* export to lib_arm/board.c */
+void check_fastboot(void)
+{
+ if (fastboot_check_and_clean_flag())
+ do_fastboot(NULL, 0, 0, 0);
+}
+
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \
+ || defined(CONFIG_FASTBOOT_STORAGE_MMC)
+/**
+ @mmc_dos_partition_index: the partition index in mbr.
+ @mmc_partition_index: the boot partition or user partition index,
+ not related to the partition table.
+ */
+static int _fastboot_parts_add_ptable_entry(int ptable_index,
+ int mmc_dos_partition_index,
+ int mmc_partition_index,
+ const char *name,
+ block_dev_desc_t *dev_desc,
+ struct fastboot_ptentry *ptable)
+{
+ disk_partition_t info;
+ strcpy(ptable[ptable_index].name, name);
+
+ if (get_partition_info(dev_desc,
+ mmc_dos_partition_index, &info)) {
+ printf("Bad partition index:%d for partition:%s\n",
+ mmc_dos_partition_index, name);
+ return -1;
+ } else {
+ ptable[ptable_index].start = info.start;
+ ptable[ptable_index].length = info.size;
+ ptable[ptable_index].partition_id = mmc_partition_index;
+ }
+ return 0;
+}
+
+static int _fastboot_parts_load_from_ptable(void)
+{
+ int i;
+#ifdef CONFIG_CMD_SATA
+ int sata_device_no;
+#endif
+
+ /* mmc boot partition: -1 means no partition, 0 user part., 1 boot part.
+ * default is no partition, for emmc default user part, except emmc*/
+ int boot_partition = FASTBOOT_MMC_NONE_PARTITION_ID;
+ int user_partition = FASTBOOT_MMC_NONE_PARTITION_ID;
+
+ struct mmc *mmc;
+ block_dev_desc_t *dev_desc;
+ struct fastboot_ptentry ptable[PTN_RECOVERY_INDEX + 1];
+
+ /* sata case in env */
+ if (fastboot_devinfo.type == DEV_SATA) {
+#ifdef CONFIG_CMD_SATA
+ puts("flash target is SATA\n");
+ if (sata_initialize())
+ return -1;
+ sata_device_no = CONFIG_FASTBOOT_SATA_NO;
+ if (sata_device_no >= CONFIG_SYS_SATA_MAX_DEVICE) {
+ printf("Unknown SATA(%d) device for fastboot\n",
+ sata_device_no);
+ return -1;
+ }
+ dev_desc = sata_get_dev(sata_device_no);
+#else /*! CONFIG_CMD_SATA*/
+ puts("SATA isn't buildin\n");
+ return -1;
+#endif /*! CONFIG_CMD_SATA*/
+ } else if (fastboot_devinfo.type == DEV_MMC) {
+ int mmc_no = 0;
+ mmc_no = fastboot_devinfo.dev_id;
+
+ printf("flash target is MMC:%d\n", mmc_no);
+ mmc = find_mmc_device(mmc_no);
+ if (mmc && mmc_init(mmc))
+ printf("MMC card init failed!\n");
+
+ dev_desc = get_dev("mmc", mmc_no);
+ if (NULL == dev_desc) {
+ printf("** Block device MMC %d not supported\n",
+ mmc_no);
+ return -1;
+ }
+
+ /* multiple boot paritions for eMMC 4.3 later */
+ if (mmc->part_config != MMCPART_NOAVAILABLE) {
+ boot_partition = FASTBOOT_MMC_BOOT_PARTITION_ID;
+ user_partition = FASTBOOT_MMC_USER_PARTITION_ID;
+ }
+ } else {
+ printf("Can't setup partition table on this device %d\n",
+ fastboot_devinfo.type);
+ return -1;
+ }
+
+ memset((char *)ptable, 0,
+ sizeof(struct fastboot_ptentry) * (PTN_RECOVERY_INDEX + 1));
+ /* MBR */
+ strcpy(ptable[PTN_MBR_INDEX].name, "mbr");
+ ptable[PTN_MBR_INDEX].start = ANDROID_MBR_OFFSET / dev_desc->blksz;
+ ptable[PTN_MBR_INDEX].length = ANDROID_MBR_SIZE / dev_desc->blksz;
+ ptable[PTN_MBR_INDEX].partition_id = user_partition;
+ /* Bootloader */
+ strcpy(ptable[PTN_BOOTLOADER_INDEX].name, "bootloader");
+ ptable[PTN_BOOTLOADER_INDEX].start =
+ ANDROID_BOOTLOADER_OFFSET / dev_desc->blksz;
+ ptable[PTN_BOOTLOADER_INDEX].length =
+ ANDROID_BOOTLOADER_SIZE / dev_desc->blksz;
+ ptable[PTN_BOOTLOADER_INDEX].partition_id = boot_partition;
+
+ _fastboot_parts_add_ptable_entry(PTN_KERNEL_INDEX,
+ CONFIG_ANDROID_BOOT_PARTITION_MMC,
+ user_partition, "boot", dev_desc, ptable);
+ _fastboot_parts_add_ptable_entry(PTN_RECOVERY_INDEX,
+ CONFIG_ANDROID_RECOVERY_PARTITION_MMC,
+ user_partition,
+ "recovery", dev_desc, ptable);
+ _fastboot_parts_add_ptable_entry(PTN_SYSTEM_INDEX,
+ CONFIG_ANDROID_SYSTEM_PARTITION_MMC,
+ user_partition,
+ "system", dev_desc, ptable);
+
+ for (i = 0; i <= PTN_RECOVERY_INDEX; i++)
+ fastboot_flash_add_ptn(&ptable[i]);
+
+ return 0;
+}
+#endif /*CONFIG_FASTBOOT_STORAGE_SATA || CONFIG_FASTBOOT_STORAGE_MMC*/
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+static unsigned long long _memparse(char *ptr, char **retptr)
+{
+ char *endptr; /* local pointer to end of parsed string */
+
+ unsigned long ret = simple_strtoul(ptr, &endptr, 0);
+
+ switch (*endptr) {
+ case 'M':
+ case 'm':
+ ret <<= 10;
+ case 'K':
+ case 'k':
+ ret <<= 10;
+ endptr++;
+ default:
+ break;
+ }
+
+ if (retptr)
+ *retptr = endptr;
+
+ return ret;
+}
+
+static int _fastboot_parts_add_env_entry(char *s, char **retptr)
+{
+ unsigned long size;
+ unsigned long offset = 0;
+ char *name;
+ int name_len;
+ int delim;
+ unsigned int flags;
+ struct fastboot_ptentry part;
+
+ size = _memparse(s, &s);
+ if (0 == size) {
+ printf("Error:FASTBOOT size of parition is 0\n");
+ return 1;
+ }
+
+ /* fetch partition name and flags */
+ flags = 0; /* this is going to be a regular partition */
+ delim = 0;
+ /* check for offset */
+ if (*s == '@') {
+ s++;
+ offset = _memparse(s, &s);
+ } else {
+ printf("Error:FASTBOOT offset of parition is not given\n");
+ return 1;
+ }
+
+ /* now look for name */
+ if (*s == '(')
+ delim = ')';
+
+ if (delim) {
+ char *p;
+
+ name = ++s;
+ p = strchr((const char *)name, delim);
+ if (!p) {
+ printf("Error:FASTBOOT no closing %c found in partition name\n",
+ delim);
+ return 1;
+ }
+ name_len = p - name;
+ s = p + 1;
+ } else {
+ printf("Error:FASTBOOT no partition name for \'%s\'\n", s);
+ return 1;
+ }
+
+ /* check for options */
+ while (1) {
+ if (strncmp(s, "i", 1) == 0) {
+ flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_I;
+ s += 1;
+ } else if (strncmp(s, "ubifs", 5) == 0) {
+ /* ubifs */
+ flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS;
+ s += 5;
+ } else {
+ break;
+ }
+ if (strncmp(s, "|", 1) == 0)
+ s += 1;
+ }
+
+ /* enter this partition (offset will be calculated later if it is zero at this point) */
+ part.length = size;
+ part.start = offset;
+ part.flags = flags;
+
+ if (name) {
+ if (name_len >= sizeof(part.name)) {
+ printf("Error:FASTBOOT partition name is too long\n");
+ return 1;
+ }
+ strncpy(&part.name[0], name, name_len);
+ /* name is not null terminated */
+ part.name[name_len] = '\0';
+ } else {
+ printf("Error:FASTBOOT no name\n");
+ return 1;
+ }
+
+ fastboot_flash_add_ptn(&part);
+
+ /*if the nand partitions envs are not initialized, try to init them*/
+ if (check_parts_values(&part))
+ save_parts_values(&part, part.start, part.length);
+
+ /* return (updated) pointer command line string */
+ *retptr = s;
+
+ /* return partition table */
+ return 0;
+}
+
+static int _fastboot_parts_load_from_env(void)
+{
+ char fbparts[FASTBOOT_FBPARTS_ENV_MAX_LEN], *env;
+
+ env = getenv("fbparts");
+ if (env) {
+ unsigned int len;
+ len = strlen(env);
+ if (len && len < FASTBOOT_FBPARTS_ENV_MAX_LEN) {
+ char *s, *e;
+
+ memcpy(&fbparts[0], env, len + 1);
+ printf("Fastboot: Adding partitions from environment\n");
+ s = &fbparts[0];
+ e = s + len;
+ while (s < e) {
+ if (_fastboot_parts_add_env_entry(s, &s)) {
+ printf("Error:Fastboot: Abort adding partitions\n");
+ pcount = 0;
+ return 1;
+ }
+ /* Skip a bunch of delimiters */
+ while (s < e) {
+ if ((' ' == *s) ||
+ ('\t' == *s) ||
+ ('\n' == *s) ||
+ ('\r' == *s) ||
+ (',' == *s)) {
+ s++;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/
+
+static void _fastboot_load_partitions(void)
+{
+ pcount = 0;
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ _fastboot_parts_load_from_env();
+#elif defined(CONFIG_FASTBOOT_STORAGE_SATA) \
+ || defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ _fastboot_parts_load_from_ptable();
+#endif
+}
+
+/*
+ * Android style flash utilties */
+void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn)
+{
+ if (pcount < MAX_PTN) {
+ memcpy(ptable + pcount, ptn, sizeof(struct fastboot_ptentry));
+ pcount++;
+ }
+}
+
+void fastboot_flash_dump_ptn(void)
+{
+ unsigned int n;
+ for (n = 0; n < pcount; n++) {
+ struct fastboot_ptentry *ptn = ptable + n;
+ printf("ptn %d name='%s' start=%d len=%d\n",
+ n, ptn->name, ptn->start, ptn->length);
+ }
+}
+
+
+struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name)
+{
+ unsigned int n;
+
+ for (n = 0; n < pcount; n++) {
+ /* Make sure a substring is not accepted */
+ if (strlen(name) == strlen(ptable[n].name)) {
+ if (0 == strcmp(ptable[n].name, name))
+ return ptable + n;
+ }
+ }
+
+ printf("can't find partition: %s, dump the partition table\n", name);
+ fastboot_flash_dump_ptn();
+ return 0;
+}
+
+struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n)
+{
+ if (n < pcount)
+ return ptable + n;
+ else
+ return 0;
+}
+
+unsigned int fastboot_flash_get_ptn_count(void)
+{
+ return pcount;
+}
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 70bb550..4869867 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -34,5 +34,6 @@ obj-y += ep0.o
obj-$(CONFIG_DW_UDC) += designware_udc.o
obj-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o
obj-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o
+obj-$(CONFIG_IMX_UDC) += imx_udc.o
endif
endif
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
new file mode 100644
index 0000000..9371ef5
--- /dev/null
+++ b/drivers/usb/gadget/imx_udc.c
@@ -0,0 +1,1190 @@
+/*
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <malloc.h>
+#include <command.h>
+#include <asm/errno.h>
+#include <usbdevice.h>
+#include <usb/imx_udc.h>
+
+#include "ep0.h"
+
+#ifdef DEBUG
+#define DBG(x...) printf(x)
+#else
+#define DBG(x...) do {} while (0)
+#endif
+
+#define mdelay(n) udelay((n)*1000)
+
+#define EP_TQ_ITEM_SIZE 16
+
+#define inc_index(x) (x = ((x+1) % EP_TQ_ITEM_SIZE))
+
+#define ep_is_in(e, tx) ((e == 0) ? (mxc_udc.ep0_dir == USB_DIR_IN) : tx)
+
+#define USB_RECIP_MASK 0x03
+#define USB_TYPE_MASK (0x03 << 5)
+#define USB_MEM_ALIGN_BYTE 4096
+#define USB_DEV_DQH_ALIGN 64
+#define USB_DEV_DTD_ALIGN 64
+
+/*fixed the dtd buffer to 4096 bytes, even it could be 20KB*/
+#define USB_DEV_DTD_MAX_BUFFER_SIZE 4096
+
+#define CACHE_ALIGNED_END(start, length) \
+ (ALIGN((uint32_t)start + length, ARCH_DMA_MINALIGN))
+
+struct mxc_ep_t{
+ int epnum;
+ int dir;
+ /* change from int to u32 to make `min` happy */
+ u32 max_pkt_size;
+ struct usb_endpoint_instance *epi;
+ struct ep_queue_item *ep_dtd[EP_TQ_ITEM_SIZE];
+ int index; /* to index the free tx tqi */
+ int done; /* to index the complete rx tqi */
+ struct ep_queue_item *tail; /* last item in the dtd chain */
+ struct ep_queue_head *ep_qh;
+} ;
+
+struct mxc_udc_ctrl{
+ int max_ep;
+ int ep0_dir;
+ int setaddr;
+ struct ep_queue_head *ep_qh;
+ struct mxc_ep_t *mxc_ep;
+ u32 qh_unaligned;
+};
+
+static int usb_highspeed;
+static int usb_inited;
+static struct mxc_udc_ctrl mxc_udc;
+static struct usb_device_instance *udc_device;
+static struct urb *ep0_urb;
+/*
+ * malloc an aligned memory
+ * unaligned_addr: return a unaligned address for memory free
+ * size : memory size
+ * align : alignment for this memroy
+ * return : aligned address(NULL when malloc failt)
+*/
+static void *malloc_aligned_buffer(u32 *unaligned_addr,
+ int size, int align)
+{
+ int msize = (size + align - 1);
+ u32 vir, vir_align;
+
+ /* force the allocated memory size to be aligned with min cache operation unit.
+ * So it is safe to flush/invalidate the cache.
+ */
+ msize = (msize + ARCH_DMA_MINALIGN - 1) / ARCH_DMA_MINALIGN;
+ msize = msize * ARCH_DMA_MINALIGN;
+
+ vir = (u32)malloc(msize);
+ memset((void *)vir, 0, msize);
+ vir_align = (vir + align - 1) & (~(align - 1));
+ *unaligned_addr = vir;
+
+ DBG("alloc aligned vir addr %x\n", vir_align);
+ return (void *)vir_align;
+}
+
+int is_usb_disconnected()
+{
+ int ret = 0;
+
+ ret = readl(USB_OTGSC) & OTGSC_B_SESSION_VALID ? 0 : 1;
+ return ret;
+}
+
+static int mxc_init_usb_qh(void)
+{
+ int size;
+ memset(&mxc_udc, 0, sizeof(mxc_udc));
+ mxc_udc.max_ep = (readl(USB_DCCPARAMS) & DCCPARAMS_DEN_MASK) * 2;
+ DBG("udc max ep = %d\n", mxc_udc.max_ep);
+ size = mxc_udc.max_ep * sizeof(struct ep_queue_head);
+ mxc_udc.ep_qh = malloc_aligned_buffer(&mxc_udc.qh_unaligned,
+ size, USB_MEM_ALIGN_BYTE);
+ if (!mxc_udc.ep_qh) {
+ printf("malloc ep qh dma buffer failure\n");
+ return -1;
+ }
+ memset(mxc_udc.ep_qh, 0, size);
+
+ /*flush cache to physical memory*/
+ flush_dcache_range((unsigned long)mxc_udc.ep_qh,
+ CACHE_ALIGNED_END(mxc_udc.ep_qh, size));
+
+ writel(virt_to_phys(mxc_udc.ep_qh) & 0xfffff800, USB_ENDPOINTLISTADDR);
+ return 0;
+}
+
+static int mxc_destroy_usb_qh(void)
+{
+ if (mxc_udc.ep_qh && mxc_udc.qh_unaligned) {
+ free((void *)mxc_udc.qh_unaligned);
+ mxc_udc.ep_qh = 0;
+ mxc_udc.qh_unaligned = 0;
+ mxc_udc.max_ep = 0;
+ }
+
+ return 0;
+}
+
+static int mxc_init_ep_struct(void)
+{
+ int i;
+
+ DBG("init mxc ep\n");
+ mxc_udc.mxc_ep = malloc(mxc_udc.max_ep * sizeof(struct mxc_ep_t));
+ if (!mxc_udc.mxc_ep) {
+ printf("malloc ep struct failure\n");
+ return -1;
+ }
+ memset((void *)mxc_udc.mxc_ep, 0,
+ sizeof(struct mxc_ep_t) * mxc_udc.max_ep);
+ for (i = 0; i < mxc_udc.max_ep / 2; i++) {
+ struct mxc_ep_t *ep;
+ ep = mxc_udc.mxc_ep + i * 2;
+ ep->epnum = i;
+ ep->index = ep->done = 0;
+ ep->dir = USB_RECV; /* data from host to device */
+ ep->ep_qh = &mxc_udc.ep_qh[i * 2];
+
+ ep = mxc_udc.mxc_ep + (i * 2 + 1);
+ ep->epnum = i;
+ ep->index = ep->done = 0;
+ ep->dir = USB_SEND; /* data to host from device */
+ ep->ep_qh = &mxc_udc.ep_qh[(i * 2 + 1)];
+ }
+ return 0;
+}
+
+static int mxc_destroy_ep_struct(void)
+{
+ if (mxc_udc.mxc_ep) {
+ free(mxc_udc.mxc_ep);
+ mxc_udc.mxc_ep = 0;
+ }
+ return 0;
+}
+
+static int mxc_init_ep_dtd(u8 index)
+{
+ struct mxc_ep_t *ep;
+ u32 unaligned_addr;
+ int i;
+
+ if (index >= mxc_udc.max_ep)
+ DBG("%s ep %d is not valid\n", __func__, index);
+
+ ep = mxc_udc.mxc_ep + index;
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ ep->ep_dtd[i] = malloc_aligned_buffer(&unaligned_addr,
+ sizeof(struct ep_queue_item), USB_DEV_DTD_ALIGN);
+ ep->ep_dtd[i]->item_unaligned_addr = unaligned_addr;
+
+ if (NULL == ep->ep_dtd[i]) {
+ printf("%s malloc tq item failure\n", __func__);
+
+ /*free other already allocated dtd*/
+ while (i) {
+ i--;
+ free((void *)(ep->ep_dtd[i]->item_unaligned_addr));
+ ep->ep_dtd[i] = 0;
+ }
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int mxc_destroy_ep_dtd(u8 index)
+{
+ struct mxc_ep_t *ep;
+ int i;
+
+ if (index >= mxc_udc.max_ep)
+ DBG("%s ep %d is not valid\n", __func__, index);
+
+ ep = mxc_udc.mxc_ep + index;
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ if (ep->ep_dtd[i]) {
+ free((void *)(ep->ep_dtd[i]->item_unaligned_addr));
+ ep->ep_dtd[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+static void mxc_ep_qh_setup(u8 ep_num, u8 dir, u8 ep_type,
+ u32 max_pkt_len, u32 zlt, u8 mult)
+{
+ struct ep_queue_head *p_qh = mxc_udc.ep_qh + (2 * ep_num + dir);
+ u32 tmp = 0;
+
+ tmp = max_pkt_len << 16;
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ tmp |= (1 << 15);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ tmp |= (mult << 30);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ break;
+ default:
+ DBG("error ep type is %d\n", ep_type);
+ return;
+ }
+ if (zlt)
+ tmp |= (1<<29);
+
+ p_qh->config = tmp;
+
+ /*flush qh's config field to physical memory*/
+ flush_dcache_range((unsigned long)p_qh,
+ CACHE_ALIGNED_END(p_qh, sizeof(struct ep_queue_head)));
+}
+
+static void mxc_ep_setup(u8 ep_num, u8 dir, u8 ep_type)
+{
+ u32 epctrl = 0;
+ epctrl = readl(USB_ENDPTCTRL(ep_num));
+ if (dir) {
+ if (ep_num)
+ epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ epctrl |= EPCTRL_TX_ENABLE;
+ epctrl |= ((u32)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT);
+ } else {
+ if (ep_num)
+ epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ epctrl |= EPCTRL_RX_ENABLE;
+ epctrl |= ((u32)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+ writel(epctrl, USB_ENDPTCTRL(ep_num));
+}
+
+static void mxc_ep_destroy(u8 ep_num, u8 dir)
+{
+ u32 epctrl = 0;
+ epctrl = readl(USB_ENDPTCTRL(ep_num));
+ if (dir)
+ epctrl &= ~EPCTRL_TX_ENABLE;
+ else
+ epctrl &= ~EPCTRL_RX_ENABLE;
+
+ writel(epctrl, USB_ENDPTCTRL(ep_num));
+}
+
+
+static void mxc_tqi_init_page(struct ep_queue_item *tqi)
+{
+ tqi->page0 = virt_to_phys((void *)(tqi->page_vir));
+ tqi->page1 = tqi->page0 + 0x1000;
+ tqi->page2 = tqi->page1 + 0x1000;
+ tqi->page3 = tqi->page2 + 0x1000;
+ tqi->page4 = tqi->page3 + 0x1000;
+}
+
+static int mxc_malloc_ep0_ptr(struct mxc_ep_t *ep)
+{
+ int i;
+ struct ep_queue_item *tqi;
+ int max_pkt_size = USB_MAX_CTRL_PAYLOAD;
+
+ ep->max_pkt_size = max_pkt_size;
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ tqi = ep->ep_dtd[i];
+ tqi->page_vir = (u32)malloc_aligned_buffer(&tqi->page_unaligned,
+ max_pkt_size,
+ USB_MEM_ALIGN_BYTE);
+ if ((void *)tqi->page_vir == NULL) {
+ printf("malloc ep's dtd bufer failure, i=%d\n", i);
+ return -1;
+ }
+ mxc_tqi_init_page(tqi);
+
+ /*flush dtd's config field to physical memory*/
+ flush_dcache_range((unsigned long)tqi,
+ CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item)));
+ }
+ return 0;
+}
+
+static int mxc_free_ep0_ptr(struct mxc_ep_t *ep)
+{
+ int i;
+ struct ep_queue_item *tqi;
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ tqi = ep->ep_dtd[i];
+ if (tqi->page_vir) {
+ free((void *)(tqi->page_unaligned));
+ tqi->page_vir = 0;
+ tqi->page_unaligned = 0;
+ tqi->page0 = 0;
+ tqi->page1 = 0;
+ tqi->page2 = 0;
+ tqi->page3 = 0;
+ tqi->page4 = 0;
+
+ /*flush dtd's config field to physical memory*/
+ flush_dcache_range((unsigned long)tqi,
+ CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item)));
+ }
+ }
+
+ return 0;
+}
+
+static void ep0_setup(void)
+{
+ mxc_ep_qh_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 0, 0);
+ mxc_ep_qh_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 0, 0);
+ mxc_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+ mxc_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+ mxc_init_ep_dtd(0 * 2 + USB_RECV);
+ mxc_init_ep_dtd(0 * 2 + USB_SEND);
+ mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_RECV));
+ mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_SEND));
+}
+
+static void ep0_destroy(void)
+{
+ mxc_ep_destroy(0, USB_RECV);
+ mxc_ep_destroy(0, USB_SEND);
+ mxc_free_ep0_ptr(mxc_udc.mxc_ep + (USB_RECV));
+ mxc_free_ep0_ptr(mxc_udc.mxc_ep + (USB_SEND));
+ mxc_destroy_ep_dtd(0 * 2 + USB_RECV);
+ mxc_destroy_ep_dtd(0 * 2 + USB_SEND);
+}
+
+static int mxc_tqi_is_busy(struct ep_queue_item *tqi)
+{
+ /* bit 7 is set by software when send, clear by controller
+ when finish */
+ /*Invalidate cache to gain dtd content from physical memory*/
+ invalidate_dcache_range((unsigned long)tqi,
+ CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item)));
+ return tqi->info & (1 << 7);
+}
+
+static int mxc_ep_xfer_is_working(struct mxc_ep_t *ep, u32 in)
+{
+ /* in: means device -> host */
+ u32 bitmask = 1 << (ep->epnum + in * 16);
+ u32 temp, prime, tstat;
+
+ prime = (bitmask & readl(USB_ENDPTPRIME));
+ if (prime)
+ return 1;
+ do {
+ temp = readl(USB_USBCMD);
+ writel(temp|USB_CMD_ATDTW, USB_USBCMD);
+ tstat = readl(USB_ENDPTSTAT) & bitmask;
+ } while (!(readl(USB_USBCMD) & USB_CMD_ATDTW));
+ writel(temp & (~USB_CMD_ATDTW), USB_USBCMD);
+
+ if (tstat)
+ return 1;
+ return 0;
+}
+
+static void mxc_update_qh(struct mxc_ep_t *ep,
+ struct ep_queue_item *tqi, u32 in)
+{
+ /* in: means device -> host */
+ struct ep_queue_head *qh = ep->ep_qh;
+ u32 bitmask = 1 << (ep->epnum + in * 16);
+ DBG("%s, line %d, epnum=%d, in=%d\n", __func__,
+ __LINE__, ep->epnum, in);
+ qh->next_queue_item = virt_to_phys(tqi);
+ qh->info = 0;
+
+ /*flush qh''s config field to physical memory*/
+ flush_dcache_range((unsigned long)qh,
+ CACHE_ALIGNED_END(qh, sizeof(struct ep_queue_head)));
+
+ writel(bitmask, USB_ENDPTPRIME);
+}
+
+static void _dump_buf(u8 *buf, u32 len)
+{
+#ifdef DEBUG
+ char *data = (char *)buf;
+ int i;
+ for (i = 0; i < len; i++) {
+ printf("0x%02x ", data[i]);
+ if (i%16 == 15)
+ printf("\n");
+ }
+ printf("\n");
+#endif
+}
+
+static void mxc_udc_queue_update(u8 epnum,
+ u8 *data, u32 len, u32 tx)
+{
+ struct mxc_ep_t *ep;
+ struct ep_queue_item *tqi, *head, *last;
+ int send = 0;
+ int in;
+
+ head = last = NULL;
+ in = ep_is_in(epnum, tx);
+ ep = mxc_udc.mxc_ep + (epnum * 2 + in);
+ DBG("epnum = %d, in = %d\n", epnum, in);
+ do {
+ tqi = ep->ep_dtd[ep->index];
+ DBG("%s, index = %d, tqi = %p\n", __func__, ep->index, tqi);
+ while (mxc_tqi_is_busy(tqi))
+ ;
+ mxc_tqi_init_page(tqi);
+ DBG("%s, line = %d, len = %d\n", __func__, __LINE__, len);
+ inc_index(ep->index);
+ send = min(len, ep->max_pkt_size);
+ if (data) {
+ memcpy((void *)tqi->page_vir, (void *)data, send);
+ _dump_buf((u8 *)(tqi->page_vir), send);
+
+ flush_dcache_range((unsigned long)(tqi->page_vir),
+ CACHE_ALIGNED_END(tqi->page_vir, send));
+ }
+ if (!head)
+ last = head = tqi;
+ else {
+ last->next_item_ptr = virt_to_phys(tqi);
+ last->next_item_vir = tqi;
+ last = tqi;
+ }
+ if (!tx)
+ tqi->reserved[0] = send;
+ /* we set IOC for every dtd */
+ tqi->info = ((send << 16) | (1 << 15) | (1 << 7));
+ data += send;
+ len -= send;
+
+ flush_dcache_range((unsigned long)tqi,
+ CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item)));
+ } while (len);
+
+ last->next_item_ptr = 0x1; /* end */
+ flush_dcache_range((unsigned long)last,
+ CACHE_ALIGNED_END(last, sizeof(struct ep_queue_item)));
+
+ if (ep->tail) {
+ ep->tail->next_item_ptr = virt_to_phys(head);
+ ep->tail->next_item_vir = head;
+ flush_dcache_range((unsigned long)(ep->tail),
+ CACHE_ALIGNED_END(ep->tail, sizeof(struct ep_queue_item)));
+
+ if (mxc_ep_xfer_is_working(ep, in)) {
+ DBG("ep is working\n");
+ goto out;
+ }
+ }
+ mxc_update_qh(ep, head, in);
+out:
+ ep->tail = last;
+}
+
+static void mxc_udc_txqueue_update(u8 ep, u8 *data, u32 len)
+{
+ printf("[SEND DATA] EP= %d, Len = 0x%x\n", ep, len);
+ _dump_buf(data, len);
+ mxc_udc_queue_update(ep, data, len, 1);
+}
+
+void mxc_udc_rxqueue_update(u8 ep, u32 len)
+{
+ mxc_udc_queue_update(ep, NULL, len, 0);
+}
+
+static void mxc_ep0_stall(void)
+{
+ u32 temp;
+ temp = readl(USB_ENDPTCTRL(0));
+ temp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+ writel(temp, USB_ENDPTCTRL(0));
+}
+
+static void mxc_usb_run(void)
+{
+ unsigned int temp = 0;
+
+ /* Enable DR irq reg */
+ temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+ | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+ | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+ writel(temp, USB_USBINTR);
+
+ /* Set controller to Run */
+ temp = readl(USB_USBCMD);
+ temp |= USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+}
+
+static void mxc_usb_stop(void)
+{
+ unsigned int temp = 0;
+
+ writel(temp, USB_USBINTR);
+
+ /* Set controller to Stop */
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+}
+
+static void usb_phy_init(void)
+{
+ u32 temp;
+ /* select 24M clk */
+ temp = readl(USB_PHY1_CTRL);
+ temp &= ~3;
+ temp |= 1;
+ writel(temp, USB_PHY1_CTRL);
+ /* Config PHY interface */
+ temp = readl(USB_PORTSC1);
+ temp &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+ temp |= PORTSCX_PTW_16BIT;
+ writel(temp, USB_PORTSC1);
+ DBG("Config PHY END\n");
+}
+
+static void usb_set_mode_device(void)
+{
+ u32 temp;
+
+ /* Set controller to stop */
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+
+ while (readl(USB_USBCMD) & USB_CMD_RUN_STOP)
+ ;
+ /* Do core reset */
+ temp = readl(USB_USBCMD);
+ temp |= USB_CMD_CTRL_RESET;
+ writel(temp, USB_USBCMD);
+ while (readl(USB_USBCMD) & USB_CMD_CTRL_RESET)
+ ;
+ DBG("DOORE RESET END\n");
+
+#if defined(CONFIG_MX6)
+ reset_usb_phy1();
+#endif
+ DBG("init core to device mode\n");
+ temp = readl(USB_USBMODE);
+ temp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
+ temp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ temp |= USB_MODE_SETUP_LOCK_OFF;
+ writel(temp, USB_USBMODE);
+
+ temp = readl(USB_OTGSC);
+ temp |= (1<<3);
+ writel(temp, USB_OTGSC);
+ DBG("init core to device mode end\n");
+}
+
+static void usb_init_eps(void)
+{
+ u32 temp;
+ DBG("Flush begin\n");
+ temp = readl(USB_ENDPTNAKEN);
+ temp |= 0x10001; /* clear mode bits */
+ writel(temp, USB_ENDPTNAKEN);
+ writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+ writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+ writel(0xffffffff, USB_ENDPTFLUSH);
+ DBG("FLUSH END\n");
+}
+
+static void usb_udc_init(void)
+{
+ DBG("\n************************\n");
+ DBG(" usb init start\n");
+ DBG("\n************************\n");
+
+ usb_phy_init();
+ usb_set_mode_device();
+ mxc_init_usb_qh();
+ usb_init_eps();
+ mxc_init_ep_struct();
+ ep0_setup();
+ usb_inited = 1;
+}
+
+static void usb_udc_destroy(void)
+{
+ usb_set_mode_device();
+
+ usb_inited = 0;
+
+ ep0_destroy();
+ mxc_destroy_ep_struct();
+ mxc_destroy_usb_qh();
+}
+
+void usb_shutdown(void)
+{
+ u32 temp;
+ /* disable pullup */
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+ mdelay(2);
+}
+
+static void ch9getstatus(u8 request_type,
+ u16 value, u16 index, u16 length)
+{
+ u16 tmp;
+
+ if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ tmp = 1 << 0; /* self powerd */
+ tmp |= 0 << 1; /* not remote wakeup able */
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+ tmp = 0;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+ tmp = 0;
+ }
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, (u8 *)&tmp, 2, 0xffffffff);
+}
+
+static void mxc_udc_read_setup_pkt(struct usb_device_request *s)
+{
+ u32 temp;
+ temp = readl(USB_ENDPTSETUPSTAT);
+ writel(temp, USB_ENDPTSETUPSTAT);
+ DBG("setup stat %x\n", temp);
+ do {
+ temp = readl(USB_USBCMD);
+ temp |= USB_CMD_SUTW;
+ writel(temp, USB_USBCMD);
+
+ invalidate_dcache_range((unsigned long)(mxc_udc.mxc_ep[0].ep_qh),
+ CACHE_ALIGNED_END((mxc_udc.mxc_ep[0].ep_qh),
+ sizeof(struct ep_queue_head)));
+
+ memcpy((void *)s,
+ (void *)mxc_udc.mxc_ep[0].ep_qh->setup_data, 8);
+ } while (!(readl(USB_USBCMD) & USB_CMD_SUTW));
+
+ DBG("handle_setup s.type=%x req=%x len=%x\n",
+ s->bmRequestType, s->bRequest, s->wLength);
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_SUTW;
+ writel(temp, USB_USBCMD);
+
+ DBG("[SETUP] type=%x req=%x val=%x index=%x len=%x\n",
+ s->bmRequestType, s->bRequest,
+ s->wValue, s->wIndex,
+ s->wLength);
+}
+
+static void mxc_udc_recv_setup(void)
+{
+ struct usb_device_request *s = &ep0_urb->device_request;
+
+ mxc_udc_read_setup_pkt(s);
+ if (s->wLength) {
+ /* If has a data phase,
+ * then prime a dtd for status stage which has zero length DATA0.
+ * The direction of status stage should oppsite to direction of data phase.
+ */
+ mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
+ USB_DIR_OUT : USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ }
+ if (ep0_recv_setup(ep0_urb)) {
+ mxc_ep0_stall();
+ return;
+ }
+ switch (s->bRequest) {
+ case USB_REQ_GET_STATUS:
+ if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) !=
+ (USB_DIR_IN | USB_TYPE_STANDARD))
+ break;
+ ch9getstatus(s->bmRequestType, s->wValue,
+ s->wIndex, s->wLength);
+
+ DBG("[SETUP] REQ_GET_STATUS\n");
+ return;
+ case USB_REQ_SET_ADDRESS:
+ if (s->bmRequestType != (USB_DIR_OUT |
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+ break;
+ mxc_udc.setaddr = 1;
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+ DBG("[SETUP] REQ_SET_ADDRESS\n");
+ return;
+ case USB_REQ_SET_CONFIGURATION:
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ DBG("[SETUP] REQ_SET_CONFIGURATION\n");
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ {
+ int rc = -1;
+ if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+ (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD))
+ rc = 0;
+ else if ((s->bmRequestType &
+ (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+ (USB_RECIP_DEVICE | USB_TYPE_STANDARD))
+ rc = 0;
+ else
+ break;
+ if (rc == 0) {
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ }
+ return;
+ }
+ default:
+ break;
+ }
+ if (s->wLength) {
+ mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
+ USB_DIR_IN : USB_DIR_OUT;
+ mxc_udc_queue_update(0, ep0_urb->buffer,
+ ep0_urb->actual_length, 0xffffffff);
+ ep0_urb->actual_length = 0;
+ } else {
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ }
+}
+
+static int mxc_udc_tqi_empty(struct ep_queue_item *tqi)
+{
+ int ret;
+
+ invalidate_dcache_range((unsigned long)tqi,
+ CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item)));
+
+ ret = tqi->info & (1 << 7);
+ return ret;
+}
+
+static struct usb_endpoint_instance *mxc_get_epi(u8 epnum)
+{
+ int i;
+ for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+ if ((udc_device->bus->endpoint_array[i].endpoint_address &
+ USB_ENDPOINT_NUMBER_MASK) == epnum)
+ return &udc_device->bus->endpoint_array[i];
+ }
+ return NULL;
+}
+
+static u32 _mxc_ep_recv_data(u8 epnum, struct ep_queue_item *tqi)
+{
+ struct usb_endpoint_instance *epi = mxc_get_epi(epnum);
+ struct urb *urb;
+ u32 len = 0;
+
+ if (!epi)
+ return 0;
+
+ invalidate_dcache_range((unsigned long)tqi,
+ CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item)));
+
+ urb = epi->rcv_urb;
+ if (urb) {
+ u8 *data = urb->buffer + urb->actual_length;
+ int remain_len = (tqi->info >> 16) & (0xefff);
+ len = tqi->reserved[0] - remain_len;
+ DBG("recv len %d-%d-%d\n", len, tqi->reserved[0], remain_len);
+
+
+ invalidate_dcache_range((unsigned long)tqi->page_vir,
+ CACHE_ALIGNED_END(tqi->page_vir, len));
+ memcpy(data, (void *)tqi->page_vir, len);
+
+ _dump_buf(data, len);
+ }
+ return len;
+}
+
+static void mxc_udc_ep_recv(u8 epnum)
+{
+ struct mxc_ep_t *ep = mxc_udc.mxc_ep + (epnum * 2 + USB_RECV);
+ struct ep_queue_item *tqi;
+ while (1) {
+ u32 nbytes;
+ tqi = ep->ep_dtd[ep->done];
+ if (mxc_udc_tqi_empty(tqi))
+ break;
+ nbytes = _mxc_ep_recv_data(epnum, tqi);
+ usbd_rcv_complete(ep->epi, nbytes, 0);
+ inc_index(ep->done);
+ if (ep->done == ep->index)
+ break;
+ }
+}
+
+static void mxc_udc_handle_xfer_complete(void)
+{
+ int i;
+ u32 bitpos = readl(USB_ENDPTCOMPLETE);
+
+ writel(bitpos, USB_ENDPTCOMPLETE);
+
+ for (i = 0; i < mxc_udc.max_ep; i++) {
+ int epnum = i >> 1;
+ int dir = i % 2;
+ u32 bitmask = 1 << (epnum + 16 * dir);
+ if (!(bitmask & bitpos))
+ continue;
+ DBG("ep %d, dir %d, complete\n", epnum, dir);
+ if (!epnum) {
+ if (mxc_udc.setaddr) {
+ writel(udc_device->address << 25,
+ USB_DEVICEADDR);
+ mxc_udc.setaddr = 0;
+ }
+ continue;
+ }
+ DBG("############### dir = %d ***************\n", dir);
+ if (dir == USB_SEND)
+ continue;
+ mxc_udc_ep_recv(epnum);
+ }
+}
+
+static void usb_dev_hand_usbint(void)
+{
+ if (readl(USB_ENDPTSETUPSTAT)) {
+ DBG("recv one setup packet\n");
+ mxc_udc_recv_setup();
+ }
+ if (readl(USB_ENDPTCOMPLETE)) {
+ DBG("Dtd complete irq\n");
+ mxc_udc_handle_xfer_complete();
+ }
+}
+
+static void usb_dev_hand_reset(void)
+{
+ u32 temp;
+ temp = readl(USB_DEVICEADDR);
+ temp &= ~0xfe000000;
+ writel(temp, USB_DEVICEADDR);
+ writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+ writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+ while (readl(USB_ENDPTPRIME))
+ ;
+ writel(0xffffffff, USB_ENDPTFLUSH);
+ DBG("reset-PORTSC=%x\n", readl(USB_PORTSC1));
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+}
+
+void usb_dev_hand_pci(void)
+{
+ u32 speed;
+ while (readl(USB_PORTSC1) & PORTSCX_PORT_RESET)
+ ;
+ speed = readl(USB_PORTSC1) & PORTSCX_PORT_SPEED_MASK;
+ switch (speed) {
+ case PORTSCX_PORT_SPEED_HIGH:
+ usb_highspeed = 2;
+ break;
+ case PORTSCX_PORT_SPEED_FULL:
+ usb_highspeed = 1;
+ break;
+ case PORTSCX_PORT_SPEED_LOW:
+ usb_highspeed = 0;
+ break;
+ default:
+ break;
+ }
+ DBG("portspeed=%d, speed = %x, PORTSC = %x\n",
+ usb_highspeed, speed, readl(USB_PORTSC1));
+}
+
+void usb_dev_hand_suspend(void)
+{
+}
+
+void mxc_irq_poll(void)
+{
+ unsigned irq_src = readl(USB_USBSTS) & readl(USB_USBINTR);
+ writel(irq_src, USB_USBSTS);
+
+ if (irq_src == 0)
+ return;
+
+ if (irq_src & USB_STS_INT)
+ usb_dev_hand_usbint();
+
+ if (irq_src & USB_STS_RESET) {
+ printf("USB_RESET\n");
+ usb_dev_hand_reset();
+ }
+ if (irq_src & USB_STS_PORT_CHANGE) {
+ printf("USB_PORT_CHANGE 0x%x\n", irq_src);
+ usb_dev_hand_pci();
+ }
+ if (irq_src & USB_STS_SUSPEND)
+ printf("USB_SUSPEND\n");
+ if (irq_src & USB_STS_ERR)
+ printf("USB_ERR\n");
+}
+
+void mxc_udc_wait_cable_insert(void)
+{
+ u32 temp;
+ int cable_connect = 1;
+
+ do {
+ udelay(50);
+
+ temp = readl(USB_OTGSC);
+ if (temp & (OTGSC_B_SESSION_VALID)) {
+ printf("USB Mini b cable Connected!\n");
+ break;
+ } else if (cable_connect == 1) {
+ printf("wait usb cable into the connector!\n");
+ cable_connect = 0;
+ }
+ } while (1);
+}
+
+void udc_disable_over_current(void)
+{
+ u32 temp;
+ temp = readl(USB_OTG_CTRL);
+ temp |= (UCTRL_OVER_CUR_POL);
+ writel(temp, USB_OTG_CTRL);
+}
+
+/*
+ * mxc_udc_init function
+ */
+int mxc_udc_init(void)
+{
+ udc_pins_setting();
+ set_usb_phy1_clk();
+ enable_usboh3_clk(1);
+#if defined(CONFIG_MX6)
+ udc_disable_over_current();
+#endif
+ enable_usb_phy1_clk(1);
+ usb_udc_init();
+
+ return 0;
+}
+
+/*
+ * mxc_udc_init function
+ */
+int mxc_udc_destroy(void)
+{
+ usb_udc_destroy();
+ enable_usboh3_clk(0);
+ enable_usb_phy1_clk(0);
+
+ return 0;
+}
+
+void mxc_udc_poll(void)
+{
+ mxc_irq_poll();
+}
+
+/*
+ * Functions for gadget APIs
+ */
+int udc_init(void)
+{
+ mxc_udc_init();
+ return 0;
+}
+
+int udc_destroy(void)
+{
+ udc_disable();
+ mxc_udc_destroy();
+ return 0;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, u32 index,
+ struct usb_endpoint_instance *epi)
+{
+ u8 dir, epnum, zlt, mult;
+ u8 ep_type;
+ u32 max_pkt_size;
+ int ep_addr;
+ struct mxc_ep_t *ep;
+
+ if (epi) {
+ zlt = 1;
+ mult = 0;
+ ep_addr = epi->endpoint_address;
+ epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+ DBG("setup ep %d\n", epnum);
+ if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ dir = USB_SEND;
+ ep_type = epi->tx_attributes;
+ max_pkt_size = epi->tx_packetSize;
+ } else {
+ dir = USB_RECV;
+ ep_type = epi->rcv_attributes;
+ max_pkt_size = epi->rcv_packetSize;
+ }
+ if (ep_type == USB_ENDPOINT_XFER_ISOC) {
+ mult = (u32)(1 + ((max_pkt_size >> 11) & 0x03));
+ max_pkt_size = max_pkt_size & 0x7ff;
+ DBG("mult = %d\n", mult);
+ }
+ ep = mxc_udc.mxc_ep + (epnum * 2 + dir);
+ ep->epi = epi;
+ if (epnum) {
+ struct ep_queue_item *tqi;
+ int i;
+
+ mxc_ep_qh_setup(epnum, dir, ep_type,
+ max_pkt_size, zlt, mult);
+ mxc_ep_setup(epnum, dir, ep_type);
+ mxc_init_ep_dtd(epnum * 2 + dir);
+
+ /* malloc endpoint's dtd's data buffer*/
+ ep->max_pkt_size = max_pkt_size;
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ tqi = ep->ep_dtd[i];
+ tqi->page_vir = (u32)malloc_aligned_buffer(
+ &tqi->page_unaligned, max_pkt_size,
+ USB_MEM_ALIGN_BYTE);
+ if ((void *)tqi->page_vir == NULL) {
+ printf("malloc dtd bufer failure\n");
+ return;
+ }
+ mxc_tqi_init_page(tqi);
+
+ flush_dcache_range((unsigned long)tqi,
+ CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item)));
+ }
+ }
+ }
+}
+
+void udc_destroy_ep(struct usb_device_instance *device,
+ struct usb_endpoint_instance *epi)
+{
+ struct mxc_ep_t *ep;
+ int ep_addr;
+ u8 dir, epnum;
+
+ if (epi) {
+ ep_addr = epi->endpoint_address;
+ epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+ if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+ dir = USB_SEND;
+ else
+ dir = USB_RECV;
+
+ ep = mxc_udc.mxc_ep + (epnum * 2 + dir);
+ ep->epi = 0;
+
+ if (epnum) {
+ struct ep_queue_item *tqi;
+ int i;
+
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ tqi = ep->ep_dtd[i];
+ if (tqi->page_vir) {
+ free((void *)(tqi->page_unaligned));
+ tqi->page_unaligned = 0;
+ tqi->page_vir = 0;
+ tqi->page0 = 0;
+ tqi->page1 = 0;
+ tqi->page2 = 0;
+ tqi->page3 = 0;
+ tqi->page4 = 0;
+ }
+ }
+
+ mxc_destroy_ep_dtd(epnum * 2 + dir);
+ mxc_ep_destroy(epnum, dir);
+ }
+ }
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *epi)
+{
+ struct urb *urb = epi->tx_urb;
+ int ep_num = epi->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+ u8 *data = (u8 *)urb->buffer + epi->sent;
+ int n = urb->actual_length - epi->sent;
+ mxc_udc_txqueue_update(ep_num, data, n);
+ epi->last = n;
+
+ /* usbd_tx_complete will take care of updating 'sent' */
+ usbd_tx_complete(epi);
+ return 0;
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+ udc_device = device;
+ ep0_urb = usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array);
+}
+
+void udc_disable(void)
+{
+ usbd_dealloc_urb(ep0_urb);
+ udc_device = NULL;
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+ usbd_device_event_irq(device, DEVICE_INIT, 0);
+ usbd_device_event_irq(device, DEVICE_CREATE, 0);
+ udc_enable(device);
+}
+
+void udc_irq(void)
+{
+ mxc_irq_poll();
+}
+
+void udc_connect(void)
+{
+ mxc_usb_run();
+ mxc_udc_wait_cable_insert();
+}
+
+void udc_disconnect(void)
+{
+ /* imx6 will hang if access usb register without init oh3
+ * clock, so not access it if not init. */
+ if (usb_inited)
+ mxc_usb_stop();
+}
+
+void udc_set_nak(int epid)
+{
+}
+
+void udc_unset_nak(int epid)
+{
+}
diff --git a/include/configs/mx6sabre_common.h b/include/configs/mx6sabre_common.h
index 1425229..c8fffb4 100644
--- a/include/configs/mx6sabre_common.h
+++ b/include/configs/mx6sabre_common.h
@@ -439,6 +439,11 @@
#define CONFIG_IMX_VIDEO_SKIP
#ifndef CONFIG_SPL
+/*
+ * USE our legacy UDC driver, but not CI_UDC
+ * USE our legacy fastboot way, but not gnl
+ */
+#if 0
#define CONFIG_CI_UDC
#define CONFIG_USBD_HS
#define CONFIG_USB_GADGET_DUALSPEED
@@ -453,6 +458,7 @@
#define CONFIG_G_DNL_PRODUCT_NUM 0xa4a5
#define CONFIG_G_DNL_MANUFACTURER "FSL"
#endif
+#endif
#if defined(CONFIG_ANDROID_SUPPORT)
#include "mx6sabreandroid_common.h"
diff --git a/include/configs/mx6sabreandroid_common.h b/include/configs/mx6sabreandroid_common.h
new file mode 100644
index 0000000..dec4148
--- /dev/null
+++ b/include/configs/mx6sabreandroid_common.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef MX6_SABRE_ANDROID_COMMON_H
+#define MX6_SABRE_ANDROID_COMMON_H
+
+#define CONFIG_SERIAL_TAG
+
+#define CONFIG_USB_DEVICE
+#define CONFIG_IMX_UDC 1
+
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_FASTBOOT 1
+#define CONFIG_FASTBOOT_VENDOR_ID 0x18d1
+#define CONFIG_FASTBOOT_PRODUCT_ID 0x0d02
+#define CONFIG_FASTBOOT_BCD_DEVICE 0x311
+#define CONFIG_FASTBOOT_MANUFACTURER_STR "Freescale"
+#define CONFIG_FASTBOOT_PRODUCT_NAME_STR "i.mx6 Sabre Board"
+#define CONFIG_FASTBOOT_INTERFACE_STR "Android fastboot"
+#define CONFIG_FASTBOOT_CONFIGURATION_STR "Android fastboot"
+#define CONFIG_FASTBOOT_SERIAL_NUM "12345"
+#define CONFIG_FASTBOOT_SATA_NO 0
+
+#if defined CONFIG_SYS_BOOT_NAND
+#define CONFIG_FASTBOOT_STORAGE_NAND
+#elif defined CONFIG_SYS_BOOT_SATA
+#define CONFIG_FASTBOOT_STORAGE_SATA
+#else
+#define CONFIG_FASTBOOT_STORAGE_MMC
+#endif
+
+/* For system.img growing up more than 256MB, more buffer needs
+* to receive the system.img*/
+#define CONFIG_FASTBOOT_TRANSFER_BUF 0x2c000000
+#define CONFIG_FASTBOOT_TRANSFER_BUF_SIZE 0x19000000 /* 400M byte */
+
+
+#define CONFIG_CMD_BOOTI
+#define CONFIG_ANDROID_RECOVERY
+/* which mmc bus is your main storage ? */
+#define CONFIG_ANDROID_MAIN_MMC_BUS 2
+#define CONFIG_ANDROID_BOOT_PARTITION_MMC 1
+#define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5
+#define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2
+#define CONFIG_ANDROID_CACHE_PARTITION_MMC 6
+
+#undef CONFIG_EXTRA_ENV_SETTINGS
+#undef CONFIG_BOOTCOMMAND
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "splashpos=m,m\0" \
+ "fdt_high=0xffffffff\0" \
+ "initrd_high=0xffffffff\0" \
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+#define ANDROID_FASTBOOT_NAND_PARTS "16m@64m(boot) 16m@80m(recovery) 810m@96m(android_root)ubifs"
+#endif
+
+#endif /* MX6_SABRE_ANDROID_COMMON_H */
diff --git a/include/configs/mx6slevk.h b/include/configs/mx6slevk.h
index 631e6dd..8d770b1 100644
--- a/include/configs/mx6slevk.h
+++ b/include/configs/mx6slevk.h
@@ -319,4 +319,8 @@
#endif
#endif /* CONFIG_SPLASH_SCREEN */
+#if defined(CONFIG_ANDROID_SUPPORT)
+#include "mx6slevkandroid.h"
+#endif
+
#endif /* __CONFIG_H */
diff --git a/include/configs/mx6slevkandroid.h b/include/configs/mx6slevkandroid.h
new file mode 100644
index 0000000..e5e7be7
--- /dev/null
+++ b/include/configs/mx6slevkandroid.h
@@ -0,0 +1,77 @@
+
+/*
+ * Copyright (C) 2013-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef MX6SL_EVK_ANDROID_H
+#define MX6SL_EVK_ANDROID_H
+
+#include <asm/imx-common/mxc_key_defs.h>
+
+#define CONFIG_SERIAL_TAG
+
+#define CONFIG_USB_DEVICE
+#define CONFIG_IMX_UDC 1
+
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_FASTBOOT 1
+#define CONFIG_FASTBOOT_VENDOR_ID 0x18d1
+#define CONFIG_FASTBOOT_PRODUCT_ID 0x0d02
+#define CONFIG_FASTBOOT_BCD_DEVICE 0x311
+#define CONFIG_FASTBOOT_MANUFACTURER_STR "Freescale"
+#define CONFIG_FASTBOOT_PRODUCT_NAME_STR "i.mx6sl EVK Board"
+#define CONFIG_FASTBOOT_INTERFACE_STR "Android fastboot"
+#define CONFIG_FASTBOOT_CONFIGURATION_STR "Android fastboot"
+#define CONFIG_FASTBOOT_SERIAL_NUM "12345"
+#define CONFIG_FASTBOOT_SATA_NO 0
+
+#if defined CONFIG_SYS_BOOT_NAND
+#define CONFIG_FASTBOOT_STORAGE_NAND
+#elif defined CONFIG_SYS_BOOT_SATA
+#define CONFIG_FASTBOOT_STORAGE_SATA
+#else
+#define CONFIG_FASTBOOT_STORAGE_MMC
+#endif
+
+/* For system.img growing up more than 256MB, more buffer needs
+* to receive the system.img*/
+#define CONFIG_FASTBOOT_TRANSFER_BUF 0x8c000000
+#define CONFIG_FASTBOOT_TRANSFER_BUF_SIZE 0x19000000 /* 400M byte */
+
+
+#define CONFIG_CMD_BOOTI
+#define CONFIG_ANDROID_RECOVERY
+/* which mmc bus is your main storage ? */
+#define CONFIG_ANDROID_MAIN_MMC_BUS 2
+#define CONFIG_ANDROID_BOOT_PARTITION_MMC 1
+#define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5
+#define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2
+#define CONFIG_ANDROID_CACHE_PARTITION_MMC 6
+
+/*keyboard mapping*/
+#define CONFIG_VOL_DOWN_KEY KEY_BACK
+#define CONFIG_POWER_KEY KEY_5
+
+#define CONFIG_MXC_KPD
+#define CONFIG_MXC_KEYMAPPING \
+ { \
+ KEY_SELECT, KEY_BACK, KEY_1, KEY_2, \
+ KEY_3, KEY_4, KEY_5, KEY_MENU, \
+ KEY_6, KEY_7, KEY_8, KEY_9, \
+ KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_DOWN, \
+ }
+#define CONFIG_MXC_KPD_COLMAX 4
+#define CONFIG_MXC_KPD_ROWMAX 4
+
+
+#undef CONFIG_EXTRA_ENV_SETTINGS
+#undef CONFIG_BOOTCOMMAND
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "splashpos=m,m\0" \
+ "fdt_high=0xffffffff\0" \
+ "initrd_high=0xffffffff\0" \
+
+#endif
diff --git a/include/configs/mx6sxsabreautoandroid.h b/include/configs/mx6sxsabreautoandroid.h
new file mode 100644
index 0000000..6501592
--- /dev/null
+++ b/include/configs/mx6sxsabreautoandroid.h
@@ -0,0 +1,61 @@
+
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MX6SX_SABREAUTO_ANDROID_H
+#define __MX6SX_SABREAUTO_ANDROID_H
+
+#define CONFIG_SERIAL_TAG
+
+#define CONFIG_USB_DEVICE
+#define CONFIG_IMX_UDC 1
+
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_FASTBOOT 1
+#define CONFIG_FASTBOOT_VENDOR_ID 0x18d1
+#define CONFIG_FASTBOOT_PRODUCT_ID 0x0d02
+#define CONFIG_FASTBOOT_BCD_DEVICE 0x311
+#define CONFIG_FASTBOOT_MANUFACTURER_STR "Freescale"
+#define CONFIG_FASTBOOT_PRODUCT_NAME_STR "i.mx6sx SABRE-AUTO Board"
+#define CONFIG_FASTBOOT_INTERFACE_STR "Android fastboot"
+#define CONFIG_FASTBOOT_CONFIGURATION_STR "Android fastboot"
+#define CONFIG_FASTBOOT_SERIAL_NUM "12345"
+#define CONFIG_FASTBOOT_SATA_NO 0
+
+#if defined CONFIG_SYS_BOOT_NAND
+#define CONFIG_FASTBOOT_STORAGE_NAND
+#else
+#define CONFIG_FASTBOOT_STORAGE_MMC
+#endif
+
+/* For system.img growing up more than 256MB, more buffer needs
+* to receive the system.img*/
+#define CONFIG_FASTBOOT_TRANSFER_BUF 0x8c000000
+#define CONFIG_FASTBOOT_TRANSFER_BUF_SIZE 0x19000000 /* 400M byte */
+
+
+#define CONFIG_CMD_BOOTI
+#define CONFIG_ANDROID_RECOVERY
+/* which mmc bus is your main storage ? */
+#define CONFIG_ANDROID_MAIN_MMC_BUS 2
+#define CONFIG_ANDROID_BOOT_PARTITION_MMC 1
+#define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5
+#define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2
+#define CONFIG_ANDROID_CACHE_PARTITION_MMC 6
+
+#undef CONFIG_EXTRA_ENV_SETTINGS
+#undef CONFIG_BOOTCOMMAND
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "splashpos=m,m\0" \
+ "fdt_high=0xffffffff\0" \
+ "initrd_high=0xffffffff\0" \
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+#define ANDROID_FASTBOOT_NAND_PARTS "16m@64m(boot) 16m@80m(recovery) 810m@96m(android_root)ubifs"
+#endif
+
+#endif
diff --git a/include/configs/mx6sxsabresdandroid.h b/include/configs/mx6sxsabresdandroid.h
new file mode 100644
index 0000000..83a2a38
--- /dev/null
+++ b/include/configs/mx6sxsabresdandroid.h
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MX6SX_SABRESD_ANDROID_H
+#define __MX6SX_SABRESD_ANDROID_H
+
+#define CONFIG_SERIAL_TAG
+
+#define CONFIG_USB_DEVICE
+#define CONFIG_IMX_UDC 1
+
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_FASTBOOT 1
+#define CONFIG_FASTBOOT_VENDOR_ID 0x18d1
+#define CONFIG_FASTBOOT_PRODUCT_ID 0x0d02
+#define CONFIG_FASTBOOT_BCD_DEVICE 0x311
+#define CONFIG_FASTBOOT_MANUFACTURER_STR "Freescale"
+#define CONFIG_FASTBOOT_PRODUCT_NAME_STR "i.mx6sx SABRESD Board"
+#define CONFIG_FASTBOOT_INTERFACE_STR "Android fastboot"
+#define CONFIG_FASTBOOT_CONFIGURATION_STR "Android fastboot"
+#define CONFIG_FASTBOOT_SERIAL_NUM "12345"
+#define CONFIG_FASTBOOT_SATA_NO 0
+
+#define CONFIG_FASTBOOT_STORAGE_MMC
+
+/* For system.img growing up more than 256MB, more buffer needs
+* to receive the system.img*/
+#define CONFIG_FASTBOOT_TRANSFER_BUF 0x8c000000
+#define CONFIG_FASTBOOT_TRANSFER_BUF_SIZE 0x19000000 /* 400M byte */
+
+
+#define CONFIG_CMD_BOOTI
+#define CONFIG_ANDROID_RECOVERY
+/* which mmc bus is your main storage ? */
+#define CONFIG_ANDROID_MAIN_MMC_BUS 2
+#define CONFIG_ANDROID_BOOT_PARTITION_MMC 1
+#define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5
+#define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2
+#define CONFIG_ANDROID_CACHE_PARTITION_MMC 6
+
+#undef CONFIG_EXTRA_ENV_SETTINGS
+#undef CONFIG_BOOTCOMMAND
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "splashpos=m,m\0" \
+ "fdt_high=0xffffffff\0" \
+ "initrd_high=0xffffffff\0" \
+
+#endif
diff --git a/include/fastboot.h b/include/fastboot.h
new file mode 100644
index 0000000..c81abcf
--- /dev/null
+++ b/include/fastboot.h
@@ -0,0 +1,376 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ *
+ * The logical naming of flash comes from the Android project
+ * Thse structures and functions that look like fastboot_flash_*
+ * They come from bootloader/legacy/include/boot/flash.h
+ *
+ * The boot_img_hdr structure and associated magic numbers also
+ * come from the Android project. They are from
+ * system/core/mkbootimg/bootimg.h
+ *
+ * Here are their copyrights
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef FASTBOOT_H
+#define FASTBOOT_H
+
+#include <common.h>
+#include <command.h>
+
+/* This is the interface file between the common cmd_fastboot.c and
+ the board specific support.
+
+ To use this interface, define CONFIG_FASTBOOT in your board config file.
+ An example is include/configs/mx6slevkandroid.h
+ ...
+ #define CONFIG_FASTBOOT 1 / * Using fastboot interface * /
+ ...
+
+*/
+
+/* From fastboot client.. */
+#define FASTBOOT_INTERFACE_CLASS 0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
+#define FASTBOOT_INTERFACE_PROTOCOL 0x03
+
+#define FASTBOOT_VERSION "0.5"
+
+/* Max size of responses from us to host */
+#define FASTBOOT_RESPONSE_SIZE 65
+
+/* The fastboot client uses a value of 2048 for the
+ page size of it boot.img file format.
+ Reset this in your board config file as needed. */
+#ifndef CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
+#define CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE 2048
+#endif
+
+/* Lower byte shows if the read/write/erase operation in
+ repeated. The base address is incremented.
+ Either 0 or 1 is ok for a default */
+
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT(n) (n & 0x0f)
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK 0x0000000F
+
+/* Writes happen a block at a time.
+ If the write fails, go to next block
+ NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK 0x00000010
+
+/* Find a contiguous block big enough for a the whole file
+ NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK 0x00000020
+
+/* Write the file with write.i */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_I 0x00000100
+
+/* Write the file with write.trimffs */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS 0x00000200
+
+/* Write the file as a series of variable/value pairs
+ using the setenv and saveenv commands */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV 0x00000400
+
+/* Status values */
+#define FASTBOOT_OK 0
+#define FASTBOOT_ERROR -1
+#define FASTBOOT_DISCONNECT 1
+#define FASTBOOT_INACTIVE 2
+
+/* Android bootimage file format */
+#define FASTBOOT_BOOT_MAGIC "ANDROID!"
+#define FASTBOOT_BOOT_MAGIC_SIZE 8
+#define FASTBOOT_BOOT_NAME_SIZE 16
+#define FASTBOOT_BOOT_ARGS_SIZE 512
+
+#define FASTBOOT_MMC_BOOT_PARTITION_ID 1
+#define FASTBOOT_MMC_USER_PARTITION_ID 0
+#define FASTBOOT_MMC_NONE_PARTITION_ID -1
+
+enum {
+ DEV_SATA,
+ DEV_MMC,
+ DEV_NAND
+};
+
+struct cmd_fastboot_interface {
+ /* This function is called when a buffer has been
+ recieved from the client app.
+ The buffer is a supplied by the board layer and must be unmodified.
+ The buffer_size is how much data is passed in.
+ Returns 0 on success
+ Returns 1 on failure
+
+ Set by cmd_fastboot */
+ int (*rx_handler)(const unsigned char *buffer,
+ unsigned int buffer_size);
+
+ /* This function is called when an exception has
+ occurred in the device code and the state
+ off fastboot needs to be reset
+
+ Set by cmd_fastboot */
+ void (*reset_handler)(void);
+
+ /* A getvar string for the product name
+ It can have a maximum of 60 characters
+
+ Set by board */
+ char *product_name;
+
+ /* A getvar string for the serial number
+ It can have a maximum of 60 characters
+
+ Set by board */
+ char *serial_no;
+
+ /* Nand block size
+ Supports the write option WRITE_NEXT_GOOD_BLOCK
+
+ Set by board */
+ unsigned int nand_block_size;
+
+ /* Nand oob size
+ Set by board */
+ unsigned int nand_oob_size;
+
+ /* Transfer buffer, for handling flash updates
+ Should be multiple of the nand_block_size
+ Care should be take so it does not overrun bootloader memory
+ Controlled by the configure variable CFG_FASTBOOT_TRANSFER_BUFFER
+
+ Set by board */
+ unsigned char *transfer_buffer;
+
+ /* How big is the transfer buffer
+ Controlled by the configure variable
+ CFG_FASTBOOT_TRANSFER_BUFFER_SIZE
+
+ Set by board */
+ unsigned int transfer_buffer_size;
+
+};
+
+/* flash partitions are defined in terms of blocks
+** (flash erase units)
+*/
+struct fastboot_ptentry {
+ /* The logical name for this partition, null terminated */
+ char name[16];
+ /* The start wrt the nand part, must be multiple of nand block size */
+ unsigned int start;
+ /* The length of the partition, must be multiple of nand block size */
+ unsigned int length;
+ /* Controls the details of how operations are done on the partition
+ See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */
+ unsigned int flags;
+ /* partition id: 0 - normal partition; 1 - boot partition */
+ unsigned int partition_id;
+};
+
+struct fastboot_device_info {
+ unsigned char type;
+ unsigned char dev_id;
+};
+
+/* Boot img hdr structure comes from the Android project
+ * See it in: system/core/mkbootimg/bootimg.h
+ */
+struct fastboot_boot_img_hdr {
+ unsigned char magic[FASTBOOT_BOOT_MAGIC_SIZE];
+
+ unsigned kernel_size; /* size in bytes */
+ unsigned kernel_addr; /* physical load addr */
+
+ unsigned ramdisk_size; /* size in bytes */
+ unsigned ramdisk_addr; /* physical load addr */
+
+ unsigned second_size; /* size in bytes */
+ unsigned second_addr; /* physical load addr */
+
+ unsigned tags_addr; /* physical addr for kernel tags */
+ unsigned page_size; /* flash page size we assume */
+ unsigned unused[2]; /* future expansion: should be 0 */
+
+ unsigned char name[FASTBOOT_BOOT_NAME_SIZE]; /* asciiz product name */
+
+ unsigned char cmdline[FASTBOOT_BOOT_ARGS_SIZE];
+
+ unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+#ifdef CONFIG_FASTBOOT
+
+extern struct fastboot_device_info fastboot_devinfo;
+
+/* Prepare the fastboot environments,
+ * should be executed before "fastboot" cmd
+ */
+void fastboot_setup(void);
+
+/* Initizes the board specific fastboot
+ * Returns 0 on success
+ * Returns 1 on failure
+ */
+int fastboot_init(struct cmd_fastboot_interface *interface);
+
+/* Cleans up the board specific fastboot */
+void fastboot_shutdown(void);
+
+/*
+ * Handles board specific usb protocol exchanges
+ * Returns 0 on success
+ * Returns 1 on disconnects, break out of loop
+ * Returns 2 if no USB activity detected
+ * Returns -1 on failure, unhandled usb requests and other error conditions
+*/
+int fastboot_poll(void);
+
+/* Is this high speed (2.0) or full speed (1.1) ?
+ * Returns 0 on full speed
+ * Returns 1 on high speed
+ */
+int fastboot_is_highspeed(void);
+
+/* Return the size of the fifo */
+int fastboot_fifo_size(void);
+
+/* Send a status reply to the client app
+ * buffer does not have to be null terminated.
+ * buffer_size must be not be larger than what is returned by
+ * fastboot_fifo_size
+ * Returns 0 on success
+ * Returns 1 on failure
+ */
+int fastboot_tx_status(const char *buffer, unsigned int buffer_size);
+
+/*
+ * Send some data to the client app
+ * buffer does not have to be null terminated.
+ * buffer_size can be larger than what is returned by
+ * fastboot_fifo_size
+ * Returns number of bytes written
+ */
+int fastboot_tx(unsigned char *buffer, unsigned int buffer_size);
+
+/* A board specific variable handler.
+ * The size of the buffers is governed by the fastboot spec.
+ * rx_buffer is at most 57 bytes
+ * tx_buffer is at most 60 bytes
+ * Returns 0 on success
+ * Returns 1 on failure
+ */
+int fastboot_getvar(const char *rx_buffer, char *tx_buffer);
+
+/* The Android-style flash handling */
+
+/* tools to populate and query the partition table */
+void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn);
+struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
+unsigned int fastboot_flash_get_ptn_count(void);
+void fastboot_flash_dump_ptn(void);
+
+
+/* Check the board special boot mode reboot to fastboot mode. */
+int fastboot_check_and_clean_flag(void);
+
+/*fastboot command handling function*/
+int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+/*check if fastboot mode is requested by user*/
+void check_fastboot(void);
+
+/*Setup board-relative fastboot environment */
+void board_fastboot_setup(void);
+
+#ifdef CONFIG_FASTBOOT_STORAGE_NAND
+/*Save parameters for NAND storage partitions */
+void save_parts_values(struct fastboot_ptentry *ptn,
+ unsigned int offset, unsigned int size);
+
+/* Checks parameters for NAND storage partitions
+ * Return 1 if the parameter is not set
+ * Return 0 if the parameter has been set
+ */
+int check_parts_values(struct fastboot_ptentry *ptn);
+#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/
+
+#else /*! CONFIG_FASTBOOT*/
+
+/* Stubs for when CONFIG_FASTBOOT is not defined */
+#define fastboot_setup() 0
+#define fastboot_init(a) 1
+#define fastboot_shutdown()
+#define fastboot_poll() 1
+#define fastboot_is_highspeed() 0
+#define fastboot_fifo_size() 0
+#define fastboot_tx_status(a, b) 1
+#define fastboot_getvar(a, b) 1
+#define fastboot_tx(a, b) 1
+
+#define fastboot_flash_add_ptn(a)
+#define fastboot_flash_find_ptn(a) NULL
+#define fastboot_flash_get_ptn(a) NULL
+#define fastboot_flash_get_ptn_count() 0
+#define fastboot_flash_dump_ptn()
+#define do_fastboot(a, b, c, d) 0
+
+#define fastboot_quick(a) 0
+#define fastboot_get_ep_num(a, b) 0
+#define fastboot_dump_memory(a, b) 0
+#define DBG_ALWS(x...)
+#define DBG_ERR(x...)
+#define DBG_DEBUG(x...)
+#define DBG_INFO(x...)
+
+
+#endif /*! CONFIG_FASTBOOT*/
+#endif /* FASTBOOT_H */
diff --git a/include/recovery.h b/include/recovery.h
new file mode 100644
index 0000000..1e0492a
--- /dev/null
+++ b/include/recovery.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __RECOVERY_H_
+#define __RECOVERY_H_
+
+struct reco_envs {
+ char *cmd;
+ char *args;
+};
+
+void check_recovery_mode(void);
+int recovery_check_and_clean_flag(void);
+int check_recovery_cmd_file(void);
+void board_recovery_setup(void);
+
+#endif
diff --git a/include/usb/imx_udc.h b/include/usb/imx_udc.h
new file mode 100644
index 0000000..51e33d7
--- /dev/null
+++ b/include/usb/imx_udc.h
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _IMX_UDC_H_
+#define _IMX_UDC_H_
+
+#include <usbdevice.h>
+
+#define USB_OTGREGS_BASE (OTG_BASE_ADDR + 0x000)
+#define USB_H1REGS_BASE (OTG_BASE_ADDR + 0x200)
+#define USB_H2REGS_BASE (OTG_BASE_ADDR + 0x400)
+#if (defined CONFIG_MX51 || defined CONFIG_MX50 || defined CONFIG_MX6Q \
+ || defined CONFIG_MX53 || defined CONFIG_MX6DL || defined CONFIG_MX6SL)
+#define USB_H3REGS_BASE (OTG_BASE_ADDR + 0x600)
+#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x800)
+#else
+#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x600)
+#endif
+
+#define USBOTG_REG32(offset) (USB_OTGREGS_BASE + (offset))
+#define USBOTG_REG16(offset) (USB_OTGREGS_BASE + (offset))
+#define USBOTHER_REG(offset) (USB_OTHERREGS_BASE + (offset))
+
+#define USB_ID (OTG_BASE_ADDR + 0x0000)
+#define USB_HWGENERAL (OTG_BASE_ADDR + 0x0004)
+#define USB_HWHOST (OTG_BASE_ADDR + 0x0008)
+#define USB_HWDEVICE (OTG_BASE_ADDR + 0x000C)
+#define USB_HWTXBUF (OTG_BASE_ADDR + 0x0010)
+#define USB_HWRXBUF (OTG_BASE_ADDR + 0x0014)
+#define USB_SBUSCFG (OTG_BASE_ADDR + 0x0090)
+
+#define USB_CAPLENGTH (OTG_BASE_ADDR + 0x0100) /* 8 bit */
+#define USB_HCIVERSION (OTG_BASE_ADDR + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS (OTG_BASE_ADDR + 0x0104)
+#define USB_HCCPARAMS (OTG_BASE_ADDR + 0x0108)
+#define USB_DCIVERSION (OTG_BASE_ADDR + 0x0120) /* 16 bit */
+#define USB_DCCPARAMS (OTG_BASE_ADDR + 0x0124)
+#define USB_USBCMD (OTG_BASE_ADDR + 0x0140)
+#define USB_USBSTS (OTG_BASE_ADDR + 0x0144)
+#define USB_USBINTR (OTG_BASE_ADDR + 0x0148)
+#define USB_FRINDEX (OTG_BASE_ADDR + 0x014C)
+#define USB_DEVICEADDR (OTG_BASE_ADDR + 0x0154)
+#define USB_ENDPOINTLISTADDR (OTG_BASE_ADDR + 0x0158)
+#define USB_BURSTSIZE (OTG_BASE_ADDR + 0x0160)
+#define USB_TXFILLTUNING (OTG_BASE_ADDR + 0x0164)
+#define USB_ULPI_VIEWPORT (OTG_BASE_ADDR + 0x0170)
+#define USB_ENDPTNAK (OTG_BASE_ADDR + 0x0178)
+#define USB_ENDPTNAKEN (OTG_BASE_ADDR + 0x017C)
+#define USB_PORTSC1 (OTG_BASE_ADDR + 0x0184)
+#define USB_OTGSC (OTG_BASE_ADDR + 0x01A4)
+#define USB_USBMODE (OTG_BASE_ADDR + 0x01A8)
+#define USB_ENDPTSETUPSTAT (OTG_BASE_ADDR + 0x01AC)
+#define USB_ENDPTPRIME (OTG_BASE_ADDR + 0x01B0)
+#define USB_ENDPTFLUSH (OTG_BASE_ADDR + 0x01B4)
+#define USB_ENDPTSTAT (OTG_BASE_ADDR + 0x01B8)
+#define USB_ENDPTCOMPLETE (OTG_BASE_ADDR + 0x01BC)
+#define USB_ENDPTCTRL(n) (OTG_BASE_ADDR + 0x01C0 + (4 * (n)))
+
+/*
+ * other regs (not part of ARC core)
+ */
+/* USB Control register */
+#define USBCTRL USBOTHER_REG(0x00)
+
+/* USB OTG mirror register */
+#define USB_OTG_MIRROR USBOTHER_REG(0x04)
+
+/* OTG UTMI PHY Function Control register */
+#define USB_PHY_CTR_FUNC USBOTHER_REG(0x08)
+
+/* OTG UTMI PHY Function Control register */
+#define USB_PHY_CTR_FUNC2 USBOTHER_REG(0x0c)
+
+#define USB_CTRL_1 USBOTHER_REG(0x10)
+#define USBCTRL_HOST2 USBOTHER_REG(0x14) /* USB Cotrol Register 1*/
+#define USBCTRL_HOST3 USBOTHER_REG(0x18) /* USB Cotrol Register 1*/
+#define USBH1_PHY_CTRL0 USBOTHER_REG(0x1c) /* USB Cotrol Register 1*/
+#define USBH1_PHY_CTRL1 USBOTHER_REG(0x20) /* USB Cotrol Register 1*/
+
+/* USB Clock on/off Control Register */
+#define USB_CLKONOFF_CTRL USBOTHER_REG(0x24)
+
+/* mx6x other regs */
+/* USB OTG Control register */
+#define USB_OTG_CTRL USBOTHER_REG(0x00)
+
+/* USB H1 Control register */
+#define USB_H1_CTRL USBOTHER_REG(0x04)
+
+/* USB H2 Control register */
+#define USB_H2_CTRL USBOTHER_REG(0x08)
+
+/* USB H3 Control register */
+#define USB_H3_CTRL USBOTHER_REG(0x0c)
+
+/* USB Host2 HSIC Control Register */
+#define USB_UH2_HSIC_CTRL USBOTHER_REG(0x10)
+
+/* USB Host3 HSIC Control Register */
+#define USB_UH3_HSIC_CTRL USBOTHER_REG(0x14)
+
+/* OTG UTMI PHY Control 0 Register */
+#define USB_OTG_PHY_CTRL_0 USBOTHER_REG(0x18)
+
+/* OTG UTMI PHY Control 1 Register */
+#define USB_H1_PHY_CTRL_0 USBOTHER_REG(0x1c)
+
+/* USB Host2 HSIC DLL Configuration Register 1 */
+#define USB_UH2_HSIC_DLL_CFG1 USBOTHER_REG(0x20)
+
+/* USB Host2 HSIC DLL Configuration Register 2 */
+#define USB_UH2_HSIC_DLL_CFG2 USBOTHER_REG(0x24)
+
+/* USB Host2 HSIC DLL Configuration Register 3 */
+#define USB_UH2_HSIC_DLL_CFG3 USBOTHER_REG(0x28)
+
+/* USB Host3 HSIC DLL Configuration Register 1 */
+#define USB_UH3_HSIC_DLL_CFG1 USBOTHER_REG(0x30)
+
+/* USB Host3 HSIC DLL Configuration Register 2 */
+#define USB_UH3_HSIC_DLL_CFG2 USBOTHER_REG(0x34)
+
+/* USB Host3 HSIC DLL Configuration Register 3 */
+#define USB_UH3_HSIC_DLL_CFG3 USBOTHER_REG(0x38)
+
+
+#define USB_PHY1_CTRL (OTG_BASE_ADDR + 0x80C)
+#define USBCMD_RESET 2
+#define USBCMD_ATTACH 1
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST 3
+
+struct ep_queue_head {
+ volatile unsigned int config;
+ volatile unsigned int current; /* read-only */
+
+ volatile unsigned int next_queue_item;
+ volatile unsigned int info;
+ volatile unsigned int page0;
+ volatile unsigned int page1;
+ volatile unsigned int page2;
+ volatile unsigned int page3;
+ volatile unsigned int page4;
+ volatile unsigned int reserved_0;
+
+ volatile unsigned char setup_data[8];
+ volatile unsigned int reserved[4];
+};
+
+#define CONFIG_MAX_PKT(n) ((n) << 16)
+#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */
+#define CONFIG_IOS (1 << 15) /* IRQ on setup */
+
+struct ep_queue_item {
+ volatile unsigned int next_item_ptr;
+ volatile unsigned int info;
+ volatile unsigned int page0;
+ volatile unsigned int page1;
+ volatile unsigned int page2;
+ volatile unsigned int page3;
+ volatile unsigned int page4;
+ unsigned int item_unaligned_addr;
+ unsigned int page_vir;
+ unsigned int page_unaligned;
+ struct ep_queue_item *next_item_vir;
+ volatile unsigned int reserved[5];
+};
+
+#define TERMINATE 1
+
+#define INFO_BYTES(n) ((n) << 16)
+#define INFO_IOC (1 << 15)
+#define INFO_ACTIVE (1 << 7)
+#define INFO_HALTED (1 << 6)
+#define INFO_BUFFER_ERROR (1 << 5)
+#define INFO_TX_ERROR (1 << 3)
+
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_DC 0x00000080
+#define DCCPARAMS_DEN_MASK 0x0000001f
+
+/* Frame Index Register Bit Masks */
+#define USB_FRINDEX_MASKS (0x3fff)
+/* USB CMD Register Bit Masks */
+#define USB_CMD_RUN_STOP (0x00000001)
+#define USB_CMD_CTRL_RESET (0x00000002)
+#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010)
+#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020)
+#define USB_CMD_INT_AA_DOORBELL (0x00000040)
+#define USB_CMD_ASP (0x00000300)
+#define USB_CMD_ASYNC_SCH_PARK_EN (0x00000800)
+#define USB_CMD_SUTW (0x00002000)
+#define USB_CMD_ATDTW (0x00004000)
+#define USB_CMD_ITC (0x00FF0000)
+
+/* bit 15,3,2 are frame list size */
+#define USB_CMD_FRAME_SIZE_1024 (0x00000000)
+#define USB_CMD_FRAME_SIZE_512 (0x00000004)
+#define USB_CMD_FRAME_SIZE_256 (0x00000008)
+#define USB_CMD_FRAME_SIZE_128 (0x0000000C)
+#define USB_CMD_FRAME_SIZE_64 (0x00008000)
+#define USB_CMD_FRAME_SIZE_32 (0x00008004)
+#define USB_CMD_FRAME_SIZE_16 (0x00008008)
+#define USB_CMD_FRAME_SIZE_8 (0x0000800C)
+
+/* bit 9-8 are async schedule park mode count */
+#define USB_CMD_ASP_00 (0x00000000)
+#define USB_CMD_ASP_01 (0x00000100)
+#define USB_CMD_ASP_10 (0x00000200)
+#define USB_CMD_ASP_11 (0x00000300)
+#define USB_CMD_ASP_BIT_POS (8)
+
+/* bit 23-16 are interrupt threshold control */
+#define USB_CMD_ITC_NO_THRESHOLD (0x00000000)
+#define USB_CMD_ITC_1_MICRO_FRM (0x00010000)
+#define USB_CMD_ITC_2_MICRO_FRM (0x00020000)
+#define USB_CMD_ITC_4_MICRO_FRM (0x00040000)
+#define USB_CMD_ITC_8_MICRO_FRM (0x00080000)
+#define USB_CMD_ITC_16_MICRO_FRM (0x00100000)
+#define USB_CMD_ITC_32_MICRO_FRM (0x00200000)
+#define USB_CMD_ITC_64_MICRO_FRM (0x00400000)
+#define USB_CMD_ITC_BIT_POS (16)
+
+/* USB STS Register Bit Masks */
+#define USB_STS_INT (0x00000001)
+#define USB_STS_ERR (0x00000002)
+#define USB_STS_PORT_CHANGE (0x00000004)
+#define USB_STS_FRM_LST_ROLL (0x00000008)
+#define USB_STS_SYS_ERR (0x00000010)
+#define USB_STS_IAA (0x00000020)
+#define USB_STS_RESET (0x00000040)
+#define USB_STS_SOF (0x00000080)
+#define USB_STS_SUSPEND (0x00000100)
+#define USB_STS_HC_HALTED (0x00001000)
+#define USB_STS_RCL (0x00002000)
+#define USB_STS_PERIODIC_SCHEDULE (0x00004000)
+#define USB_STS_ASYNC_SCHEDULE (0x00008000)
+
+/* USB INTR Register Bit Masks */
+#define USB_INTR_INT_EN (0x00000001)
+#define USB_INTR_ERR_INT_EN (0x00000002)
+#define USB_INTR_PTC_DETECT_EN (0x00000004)
+#define USB_INTR_FRM_LST_ROLL_EN (0x00000008)
+#define USB_INTR_SYS_ERR_EN (0x00000010)
+#define USB_INTR_ASYN_ADV_EN (0x00000020)
+#define USB_INTR_RESET_EN (0x00000040)
+#define USB_INTR_SOF_EN (0x00000080)
+#define USB_INTR_DEVICE_SUSPEND (0x00000100)
+
+/* Device Address bit masks */
+#define USB_DEVICE_ADDRESS_MASK (0xFE000000)
+#define USB_DEVICE_ADDRESS_BIT_POS (25)
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK (0xfffff800)
+
+/* PORTSCX Register Bit Masks */
+#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001)
+#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002)
+#define PORTSCX_PORT_ENABLE (0x00000004)
+#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008)
+#define PORTSCX_OVER_CURRENT_ACT (0x00000010)
+#define PORTSCX_OVER_CURRENT_CHG (0x00000020)
+#define PORTSCX_PORT_FORCE_RESUME (0x00000040)
+#define PORTSCX_PORT_SUSPEND (0x00000080)
+#define PORTSCX_PORT_RESET (0x00000100)
+#define PORTSCX_LINE_STATUS_BITS (0x00000C00)
+#define PORTSCX_PORT_POWER (0x00001000)
+#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000)
+#define PORTSCX_PORT_TEST_CTRL (0x000F0000)
+#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000)
+#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000)
+#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000)
+#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000)
+#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000)
+#define PORTSCX_PORT_SPEED_MASK (0x0C000000)
+#define PORTSCX_PORT_WIDTH (0x10000000)
+#define PORTSCX_PHY_TYPE_SEL (0xC0000000)
+
+/* bit 11-10 are line status */
+#define PORTSCX_LINE_STATUS_SE0 (0x00000000)
+#define PORTSCX_LINE_STATUS_JSTATE (0x00000400)
+#define PORTSCX_LINE_STATUS_KSTATE (0x00000800)
+#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00)
+#define PORTSCX_LINE_STATUS_BIT_POS (10)
+
+/* bit 15-14 are port indicator control */
+#define PORTSCX_PIC_OFF (0x00000000)
+#define PORTSCX_PIC_AMBER (0x00004000)
+#define PORTSCX_PIC_GREEN (0x00008000)
+#define PORTSCX_PIC_UNDEF (0x0000C000)
+#define PORTSCX_PIC_BIT_POS (14)
+
+/* bit 19-16 are port test control */
+#define PORTSCX_PTC_DISABLE (0x00000000)
+#define PORTSCX_PTC_JSTATE (0x00010000)
+#define PORTSCX_PTC_KSTATE (0x00020000)
+#define PORTSCX_PTC_SEQNAK (0x00030000)
+#define PORTSCX_PTC_PACKET (0x00040000)
+#define PORTSCX_PTC_FORCE_EN (0x00050000)
+#define PORTSCX_PTC_BIT_POS (16)
+
+/* bit 27-26 are port speed */
+#define PORTSCX_PORT_SPEED_FULL (0x00000000)
+#define PORTSCX_PORT_SPEED_LOW (0x04000000)
+#define PORTSCX_PORT_SPEED_HIGH (0x08000000)
+#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000)
+#define PORTSCX_SPEED_BIT_POS (26)
+
+/* OTGSC Register Bit Masks */
+#define OTGSC_B_SESSION_VALID_IRQ_EN (1 << 27)
+#define OTGSC_B_SESSION_VALID_IRQ_STS (1 << 19)
+#define OTGSC_B_SESSION_VALID (1 << 11)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define PORTSCX_PTW (0x10000000)
+#define PORTSCX_PTW_8BIT (0x00000000)
+#define PORTSCX_PTW_16BIT (0x10000000)
+
+/* bit 31-30 are port transceiver select */
+#define PORTSCX_PTS_UTMI (0x00000000)
+#define PORTSCX_PTS_ULPI (0x80000000)
+#define PORTSCX_PTS_FSLS (0xC0000000)
+#define PORTSCX_PTS_BIT_POS (30)
+
+/* USB MODE Register Bit Masks */
+#define USB_MODE_CTRL_MODE_IDLE (0x00000000)
+#define USB_MODE_CTRL_MODE_DEVICE (0x00000002)
+#define USB_MODE_CTRL_MODE_HOST (0x00000003)
+#define USB_MODE_CTRL_MODE_MASK 0x00000003
+#define USB_MODE_CTRL_MODE_RSV (0x00000001)
+#define USB_MODE_ES 0x00000004 /* (big) Endian Sel */
+#define USB_MODE_SETUP_LOCK_OFF (0x00000008)
+#define USB_MODE_STREAM_DISABLE (0x00000010)
+/* Endpoint Flush Register */
+#define EPFLUSH_TX_OFFSET (0x00010000)
+#define EPFLUSH_RX_OFFSET (0x00000000)
+
+/* Endpoint Setup Status bit masks */
+#define EP_SETUP_STATUS_MASK (0x0000003F)
+#define EP_SETUP_STATUS_EP0 (0x00000001)
+
+/* ENDPOINTCTRLx Register Bit Masks */
+#define EPCTRL_TX_ENABLE (0x00800000)
+#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */
+#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */
+#define EPCTRL_TX_TYPE (0x000C0000)
+#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */
+#define EPCTRL_TX_EP_STALL (0x00010000)
+#define EPCTRL_RX_ENABLE (0x00000080)
+#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */
+#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */
+#define EPCTRL_RX_TYPE (0x0000000C)
+#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */
+#define EPCTRL_RX_EP_STALL (0x00000001)
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define EPCTRL_EP_TYPE_CONTROL (0)
+#define EPCTRL_EP_TYPE_ISO (1)
+#define EPCTRL_EP_TYPE_BULK (2)
+#define EPCTRL_EP_TYPE_INTERRUPT (3)
+#define EPCTRL_TX_EP_TYPE_SHIFT (18)
+#define EPCTRL_RX_EP_TYPE_SHIFT (2)
+
+/* SNOOPn Register Bit Masks */
+#define SNOOP_ADDRESS_MASK (0xFFFFF000)
+#define SNOOP_SIZE_ZERO (0x00) /* snooping disable */
+#define SNOOP_SIZE_4KB (0x0B) /* 4KB snoop size */
+#define SNOOP_SIZE_8KB (0x0C)
+#define SNOOP_SIZE_16KB (0x0D)
+#define SNOOP_SIZE_32KB (0x0E)
+#define SNOOP_SIZE_64KB (0x0F)
+#define SNOOP_SIZE_128KB (0x10)
+#define SNOOP_SIZE_256KB (0x11)
+#define SNOOP_SIZE_512KB (0x12)
+#define SNOOP_SIZE_1MB (0x13)
+#define SNOOP_SIZE_2MB (0x14)
+#define SNOOP_SIZE_4MB (0x15)
+#define SNOOP_SIZE_8MB (0x16)
+#define SNOOP_SIZE_16MB (0x17)
+#define SNOOP_SIZE_32MB (0x18)
+#define SNOOP_SIZE_64MB (0x19)
+#define SNOOP_SIZE_128MB (0x1A)
+#define SNOOP_SIZE_256MB (0x1B)
+#define SNOOP_SIZE_512MB (0x1C)
+#define SNOOP_SIZE_1GB (0x1D)
+#define SNOOP_SIZE_2GB (0x1E) /* 2GB snoop size */
+
+/* pri_ctrl Register Bit Masks */
+#define PRI_CTRL_PRI_LVL1 (0x0000000C)
+#define PRI_CTRL_PRI_LVL0 (0x00000003)
+
+/* si_ctrl Register Bit Masks */
+#define SI_CTRL_ERR_DISABLE (0x00000010)
+#define SI_CTRL_IDRC_DISABLE (0x00000008)
+#define SI_CTRL_RD_SAFE_EN (0x00000004)
+#define SI_CTRL_RD_PREFETCH_DISABLE (0x00000002)
+#define SI_CTRL_RD_PREFEFETCH_VAL (0x00000001)
+
+/* control Register Bit Masks */
+#define USB_CTRL_IOENB (0x00000004)
+#define USB_CTRL_ULPI_INT0EN (0x00000001)
+#define USB_CTRL_OTG_WUIR (0x80000000)
+#define USB_CTRL_OTG_WUIE (0x08000000)
+#define USB_CTRL_OTG_VWUE (0x00001000)
+#define USB_CTRL_OTG_IWUE (0x00100000)
+
+
+
+#define INTR_UE (1 << 0)
+#define INTR_UEE (1 << 1)
+#define INTR_PCE (1 << 2)
+#define INTR_SEE (1 << 4)
+#define INTR_URE (1 << 6)
+#define INTR_SRE (1 << 7)
+#define INTR_SLE (1 << 8)
+
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+
+#define CTRL_TXE (1 << 23)
+#define CTRL_TXR (1 << 22)
+#define CTRL_TXI (1 << 21)
+#define CTRL_TXD (1 << 17)
+#define CTRL_TXS (1 << 16)
+#define CTRL_RXE (1 << 7)
+#define CTRL_RXR (1 << 6)
+#define CTRL_RXI (1 << 5)
+#define CTRL_RXD (1 << 1)
+#define CTRL_RXS (1 << 0)
+
+#define CTRL_TXT_CTRL (0 << 18)
+#define CTRL_TXT_ISOCH (1 << 18)
+#define CTRL_TXT_BULK (2 << 18)
+#define CTRL_TXT_INT (3 << 18)
+
+#define CTRL_RXT_CTRL (0 << 2)
+#define CTRL_RXT_ISOCH (1 << 2)
+#define CTRL_RXT_BULK (2 << 2)
+#define CTRL_RXT_INT (3 << 2)
+
+#define USB_RECV 0
+#define USB_SEND 1
+#define USB_MAX_CTRL_PAYLOAD 64
+
+/* UDC device defines */
+#define EP0_MAX_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_OUT_ENDPOINT 0x02
+#define UDC_OUT_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_IN_ENDPOINT 0x03
+#define UDC_IN_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_INT_ENDPOINT 0x01
+#define UDC_INT_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_BULK_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+
+/* mx6q's register bit begins*/
+
+/* OTG CTRL - H3 CTRL */
+#define UCTRL_OWIR (1 << 31) /* OTG wakeup intr request received */
+/* bit 18 - bit 30 is reserved at mx6q */
+#define UCTRL_WKUP_VBUS_EN (1 << 17) /* OTG wake-up on VBUS change enable */
+#define UCTRL_WKUP_ID_EN (1 << 16) /* OTG wake-up on ID change enable */
+#define UCTRL_WKUP_SW (1 << 15) /* OTG Software Wake-up */
+#define UCTRL_WKUP_SW_EN (1 << 14) /* OTG Software Wake-up enable */
+#define UCTRL_UTMI_ON_CLOCK (1 << 13) /* Force OTG UTMI PHY clock output
+ on even if suspend mode */
+#define UCTRL_SUSPENDM (1 << 12) /* Force OTG UTMI PHY Suspend */
+#define UCTRL_RESET (1 << 11) /* Force OTG UTMI PHY Reset */
+#define UCTRL_OWIE (1 << 10) /* OTG wakeup intr request received */
+#define UCTRL_PM (1 << 9) /* OTG Power Mask */
+#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
+/* bit 0 - bit 6 is reserved at mx6q */
+
+/* Host2/3 HSIC Ctrl */
+#define CLK_VLD (1 << 31) /* Indicating whether HSIC clock is valid */
+#define HSIC_EN (1 << 12) /* HSIC enable */
+#define HSIC_CLK_ON (1 << 11) /* Force HSIC module 480M clock on,
+ * even when in Host is in suspend mode
+ */
+/* OTG/HOST1 Phy Ctrl */
+#define PHY_UTMI_CLK_VLD (1 << 31)/* Indicating whether OTG UTMI PHY Clock Valid*/
+
+int udc_init(void);
+
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+
+void udc_connect(void);
+void udc_disconnect(void);
+
+void udc_startup_events(struct usb_device_instance *device);
+void udc_setup_ep(struct usb_device_instance *device,
+ unsigned int ep, struct usb_endpoint_instance *endpoint);
+int udc_endpoint_write(struct usb_endpoint_instance *epi);
+void udc_irq(void);
+void usb_shutdown(void);
+void mxc_udc_rxqueue_update(u8 ep, u32 len);
+int is_usb_disconnected(void);
+void reset_usb_phy1(void);
+void set_usboh3_clk(void);
+void set_usb_phy1_clk(void);
+void enable_usb_phy1_clk(unsigned char enable);
+void enable_usboh3_clk(unsigned char enable);
+void udc_pins_setting(void);
+
+/*destroy functions*/
+void udc_destroy_ep(struct usb_device_instance *device,
+ struct usb_endpoint_instance *epi);
+int udc_destroy(void);
+
+
+#ifdef CONFIG_FASTBOOT
+
+#define EP0_OUT_INDEX 0
+#define EP0_IN_INDEX 16
+#define EP1_OUT_INDEX 1
+#define EP1_IN_INDEX 17
+#define EP2_OUT_INDEX 2
+#define EP2_IN_INDEX 18
+#define EP3_OUT_INDEX 3
+#define EP3_IN_INDEX 19
+#define EP4_OUT_INDEX 4
+#define EP4_IN_INDEX 20
+#define EP5_OUT_INDEX 5
+#define EP5_IN_INDEX 21
+#define EP6_OUT_INDEX 6
+#define EP6_IN_INDEX 22
+#define EP7_OUT_INDEX 7
+#define EP7_IN_INDEX 23
+#define EP8_OUT_INDEX 8
+#define EP8_IN_INDEX 24
+#define EP9_OUT_INDEX 9
+#define EP9_IN_INDEX 25
+#define EP10_OUT_INDEX 10
+#define EP10_IN_INDEX 26
+#define EP11_OUT_INDEX 11
+#define EP11_IN_INDEX 27
+#define EP12_OUT_INDEX 12
+#define EP12_IN_INDEX 28
+#define EP13_OUT_INDEX 13
+#define EP13_IN_INDEX 29
+#define EP14_OUT_INDEX 14
+#define EP14_IN_INDEX 30
+#define EP15_OUT_INDEX 15
+#define EP15_IN_INDEX 31
+
+#define MAX_PAKET_LEN 512
+typedef void (*EP_HANDLER_P)(u32 index, u8 *buf);
+
+int udc_irq_handler(void);
+void udc_hal_data_init(void);
+void udc_wait_connect(void);
+void udc_run(void);
+int udc_recv_data(u32 index, u8 *recvbuf, u32 recvlen, EP_HANDLER_P cb);
+int udc_send_data(u32 index, u8 *buf, u32 sendlen, EP_HANDLER_P cb);
+void udc_qh_dtd_init(u32 index);
+void udc_dtd_setup(u32 index, u8 ep_type);
+void udc_qh_setup(u32 index, u8 ep_type, u32 max_pkt_len, u32 zlt, u8 mult);
+u8 *udc_get_descriptor(u8 type, u8 *plen);
+void udc_set_addr(u8 addr);
+void udc_set_configure(u8 config);
+
+#endif /* CONFIG_FASTBOOT */
+
+#endif