diff options
author | Peng Fan <Peng.Fan@freescale.com> | 2015-03-10 15:05:10 +0800 |
---|---|---|
committer | Peng Fan <Peng.Fan@freescale.com> | 2015-04-29 15:00:32 +0800 |
commit | eefcd91b30a0ee7ae2f0f3d03d4f4e667374443b (patch) | |
tree | d79e3b140ff257a3da4a39e028e32e7d46c65f52 | |
parent | b7f153c8b55c4ccccf792de9dd63ece243c72435 (diff) | |
download | u-boot-imx-eefcd91b30a0ee7ae2f0f3d03d4f4e667374443b.zip u-boot-imx-eefcd91b30a0ee7ae2f0f3d03d4f4e667374443b.tar.gz u-boot-imx-eefcd91b30a0ee7ae2f0f3d03d4f4e667374443b.tar.bz2 |
MLK-10774-33 imx:mx6 add udc and fastboot support
Add udc and fastboot support
We did not use the upstream way.
Currently use CI_UDC and USB_GAGDET of upstream can make fastboot work,
but lack of flash operation, so we still use our way.
Signed-off-by: Peng Fan <Peng.Fan@freescale.com>
Signed-off-by: Nitin Garg <nitin.garg@freescale.com>
Signed-off-by: Ye.Li <B37916@freescale.com>
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 |