From 2636bc3f11c953c24b3af7334082811737bf475b Mon Sep 17 00:00:00 2001 From: Paolo Sabatino Date: Sat, 19 Mar 2022 21:41:38 +0000 Subject: [PATCH] rk3288: tinkerboard: add UMS mode when USB host is connected to OTG port during boot --- arch/arm/include/asm/arch-rockchip/gpio.h | 22 ++++ arch/arm/mach-rockchip/board.c | 115 +++++++++++++++++++++ arch/arm/mach-rockchip/spl.c | 23 ++++- cmd/usb_mass_storage.c | 9 +- common/autoboot.c | 22 ++++ common/board_r.c | 1 + drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 1 + drivers/usb/gadget/f_mass_storage.c | 10 +- include/init.h | 1 + include/linux/usb/gadget.h | 3 + 10 files changed, 203 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/arch-rockchip/gpio.h b/arch/arm/include/asm/arch-rockchip/gpio.h index 1aaec5fae..135688d3b 100644 --- a/arch/arm/include/asm/arch-rockchip/gpio.h +++ b/arch/arm/include/asm/arch-rockchip/gpio.h @@ -24,6 +24,28 @@ struct rockchip_gpio_regs { }; check_member(rockchip_gpio_regs, ls_sync, 0x60); +/* + * RK3288 IO memory map: + * + */ +#define RKIO_GPIO0_PHYS 0xFF750000 +#define RKIO_GRF_PHYS 0xFF770000 +#define RKIO_GPIO1_PHYS 0xFF780000 +#define RKIO_GPIO2_PHYS 0xFF790000 +#define RKIO_GPIO3_PHYS 0xFF7A0000 +#define RKIO_GPIO4_PHYS 0xFF7B0000 +#define RKIO_GPIO5_PHYS 0xFF7C0000 +#define RKIO_GPIO6_PHYS 0xFF7D0000 + +/* gpio power down/up control */ +#define GRF_GPIO2A_P 0x150 +#define GRF_GPIO6A_P 0x190 + +/* gpio input/output control */ +#define GPIO_SWPORT_DR 0x00 +#define GPIO_SWPORT_DDR 0x04 +#define GPIO_EXT_PORT 0x50 + enum gpio_pu_pd { GPIO_PULL_NORMAL = 0, GPIO_PULL_UP, diff --git a/arch/arm/mach-rockchip/board.c b/arch/arm/mach-rockchip/board.c index ba4da72b3..5ae2c7f8f 100644 --- a/arch/arm/mach-rockchip/board.c +++ b/arch/arm/mach-rockchip/board.c @@ -17,10 +17,26 @@ #include #include #include +#include +#include #include DECLARE_GLOBAL_DATA_PTR; +enum project_id { + TinkerBoardS = 0, + TinkerBoard = 7, +}; + +enum pcb_id { + SR, + ER, + PR, +}; + +extern bool force_ums; + + __weak int rk_board_late_init(void) { return 0; @@ -33,6 +49,105 @@ int board_late_init(void) return rk_board_late_init(); } +/* +* +* usb current limit : GPIO6_A6 (H:unlock, L:lock) +* +*/ +void usb_current_limit_ctrl(bool unlock_current) +{ + int tmp; + + printf("%s: unlock_current = %d\n", __func__, unlock_current); + tmp = readl(RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + if(unlock_current == true) + writel(tmp | 0x40, RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + else + writel(tmp & ~0x40, RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + + tmp = readl(RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); + writel(tmp | 0x40, RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); +} + +/* +* +* eMMC maskrom mode : GPIO6_A7 (H:disable maskrom, L:enable maskrom) +* +*/ +void rk3288_maskrom_ctrl(bool enable_emmc) +{ + int tmp; + + printf("%s: enable_emmc = %d\n", __func__, enable_emmc); + tmp = readl(RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + if(enable_emmc == true) + writel(tmp | 0x80, RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + else + writel(tmp & ~0x80, RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + + tmp = readl(RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); + writel(tmp | 0x80, RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); + mdelay(10); +} + +/* +* +* project id : GPIO2_A3 GPIO2_A2 GPIO2_A1 +* pcb id : GPIO2_B2 GPIO2_B1 GPIO2_B0 +* SDP/CDP : GPIO6_A5 (H:SDP, L:CDP) +* usb current limit : GPIO6_A6 (H:unlock, L:lock) +* eMMC maskrom mode : GPIO6_A7 (H:disable maskrom, L:enable maskrom) +* +* Please check TRM V1.2 part1 page 152 for the following register settings +* +*/ +int check_force_enter_ums_mode(void) +{ + int tmp; + enum pcb_id pcbid; + enum project_id projectid; + + // GPIO2_A3/GPIO2_A2/GPIO2_A1 pull up enable + tmp = readl(RKIO_GRF_PHYS + GRF_GPIO2A_P); + writel((tmp&~(0x03F<<2)) | 0x3F<<(16 + 2) | 0x15<<2, RKIO_GRF_PHYS + GRF_GPIO2A_P); + + // GPIO2_A3/GPIO2_A2/GPIO2_A1/GPIO2_B2/GPIO2_B1/GPIO2_B0 set to input + tmp = readl(RKIO_GPIO2_PHYS + GPIO_SWPORT_DDR); + writel(tmp & ~(0x70E), RKIO_GPIO2_PHYS + GPIO_SWPORT_DDR); + + // GPIO6_A5 pull up/down disable + tmp = readl(RKIO_GRF_PHYS + GRF_GPIO6A_P); + writel((tmp&~(0x03<<10)) | 0x03<<(16 + 10), RKIO_GRF_PHYS + GRF_GPIO6A_P); + + // GPIO6_A5 set to input + tmp = readl(RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); + writel(tmp & ~(0x20), RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); + + mdelay(10); + + // read GPIO2_A3/GPIO2_A2/GPIO2_A1 value + projectid = (readl(RKIO_GPIO2_PHYS + GPIO_EXT_PORT) & 0x0E) >>1; + + // read GPIO2_B2/GPIO2_B1/GPIO2_B0 value + pcbid = (readl(RKIO_GPIO2_PHYS + GPIO_EXT_PORT) & 0x700) >> 8; + + // only Tinker Board S and the PR stage PCB has this function + if(projectid!=TinkerBoard && pcbid >= ER){ + printf("PC event = 0x%x\n", readl(RKIO_GPIO6_PHYS + GPIO_EXT_PORT)&0x20); + if((readl(RKIO_GPIO6_PHYS + GPIO_EXT_PORT)&0x20)==0x20) { + // SDP detected, enable EMMC and unlock usb current limit + printf("usb connected to SDP, force enter ums mode\n"); + force_ums = true; + rk3288_maskrom_ctrl(true); + usb_current_limit_ctrl(true); + } else { + usb_current_limit_ctrl(false); + } + } + return 0; +} + + int board_init(void) { int ret; diff --git a/arch/arm/mach-rockchip/spl.c b/arch/arm/mach-rockchip/spl.c index f148d48b6..59daff438 100644 --- a/arch/arm/mach-rockchip/spl.c +++ b/arch/arm/mach-rockchip/spl.c @@ -106,6 +106,27 @@ __weak int arch_cpu_init(void) return 0; } +/* +* +* usb current limit : GPIO6_A6 (H:unlock, L:lock) +* +*/ +void usb_current_limit_ctrl(bool unlock_current) +{ + int tmp; + +#include + + tmp = readl(RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + if(unlock_current == true) + writel(tmp | 0x40, RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + else + writel(tmp & ~0x40, RKIO_GPIO6_PHYS + GPIO_SWPORT_DR); + + tmp = readl(RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); + writel(tmp | 0x40, RKIO_GPIO6_PHYS + GPIO_SWPORT_DDR); +} + void board_init_f(ulong dummy) { int ret; @@ -122,7 +143,7 @@ void board_init_f(ulong dummy) debug_uart_init(); debug("\nspl:debug uart enabled in %s\n", __func__); #endif - + usb_current_limit_ctrl(true); board_early_init_f(); ret = spl_early_init(); diff --git a/cmd/usb_mass_storage.c b/cmd/usb_mass_storage.c index cf2f55994..d406ea453 100644 --- a/cmd/usb_mass_storage.c +++ b/cmd/usb_mass_storage.c @@ -111,7 +111,7 @@ static int ums_init(const char *devtype, const char *devnums_part_str) name = malloc(UMS_NAME_LEN); if (!name) goto cleanup; - snprintf(name, UMS_NAME_LEN, "UMS disk %d", ums_count); + snprintf(name, UMS_NAME_LEN, "Armbian UMS disk %d", ums_count); ums[ums_count].name = name; ums[ums_count].block_dev = *block_dev; @@ -136,7 +136,7 @@ cleanup: return ret; } -static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag, +int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { const char *usb_controller; @@ -218,6 +218,11 @@ static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag, usb_gadget_handle_interrupts(controller_index); rc = fsg_main_thread(NULL); + + if (rc == -ETIMEDOUT) { + goto cleanup_register; + } + if (rc) { /* Check I/O error */ if (rc == -EIO) diff --git a/common/autoboot.c b/common/autoboot.c index e628baffb..eefaa28d4 100644 --- a/common/autoboot.c +++ b/common/autoboot.c @@ -40,6 +40,9 @@ DECLARE_GLOBAL_DATA_PTR; static int stored_bootdelay; static int menukey; +bool force_ums = false; +bool getdescriptor = false; + #if !defined(CONFIG_AUTOBOOT_STOP_STR_CRYPT) #define CONFIG_AUTOBOOT_STOP_STR_CRYPT "" #endif @@ -49,6 +52,10 @@ static int menukey; #define AUTOBOOT_MENUKEY 0 #endif +extern int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]); +void usb_current_limit_ctrl(bool unlock_current); +void rk3288_maskrom_ctrl(bool enable_emmc); + /* * Use a "constant-length" time compare function for this * hash compare: @@ -363,6 +370,21 @@ void autoboot_command(const char *s) { debug("### main_loop: bootcmd=\"%s\"\n", s ? s : ""); + if (force_ums) { + // force to enter ums mode + char *local_args[4]; + char str1[]="ums", str2[]="1", str3[]="mmc", str4[]="0"; + + local_args[0]=str1; + local_args[1]=str2; + local_args[2]=str3; + local_args[3]=str4; + if (do_usb_mass_storage(NULL, 0, 4, local_args) == -ETIMEDOUT) { + rk3288_maskrom_ctrl(false); + usb_current_limit_ctrl(false); + } + } + if (s && (stored_bootdelay == -2 || (stored_bootdelay != -1 && !abortboot(stored_bootdelay)))) { bool lock; diff --git a/common/board_r.c b/common/board_r.c index 29dd7d26d..5b952d00c 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -797,6 +797,7 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_MMC initr_mmc, #endif + check_force_enter_ums_mode, #ifdef CONFIG_XEN initr_xen, #endif diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index f17009a29..b85b3f825 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -1393,6 +1393,7 @@ static void dwc2_ep0_setup(struct dwc2_udc *dev) debug_cond(DEBUG_SETUP != 0, "%s: *** USB_REQ_GET_DESCRIPTOR\n", __func__); + getdescriptor = true; break; case USB_REQ_SET_INTERFACE: diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 45f0504b6..80706d41b 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -655,7 +655,7 @@ static void busy_indicator(void) static int sleep_thread(struct fsg_common *common) { int rc = 0; - int i = 0, k = 0; + int i = 0, k = 0, j = 0; /* Wait until a signal arrives or we are woken up */ for (;;) { @@ -666,6 +666,7 @@ static int sleep_thread(struct fsg_common *common) busy_indicator(); i = 0; k++; + j++; } if (k == 10) { @@ -680,6 +681,13 @@ static int sleep_thread(struct fsg_common *common) k = 0; } + if (j == 300) { //about 3 seconds + if(force_ums && !getdescriptor) { + printf("wait for usb get descriptor cmd timeout\n"); + return -ETIMEDOUT; + } + } + usb_gadget_handle_interrupts(controller_index); } common->thread_wakeup_needed = 0; diff --git a/include/init.h b/include/init.h index 0f48ccb57..bae1cb88e 100644 --- a/include/init.h +++ b/include/init.h @@ -261,6 +261,7 @@ int board_early_init_f(void); /* manipulate the U-Boot fdt before its relocation */ int board_fix_fdt(void *rw_fdt_blob); int board_late_init(void); +int check_force_enter_ums_mode (void); int board_postclk_init(void); /* after clocks/timebase, before env/serial */ int board_early_init_r(void); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 06292ddeb..48709f3b0 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -25,6 +25,9 @@ struct usb_ep; +extern bool force_ums; +extern bool getdescriptor; + /** * struct usb_request - describes one i/o request * @buf: Buffer used for data. Always provide this; some controllers -- 2.30.2