1aa9b1b59SFrank Wang /* 2aa9b1b59SFrank Wang * Copyright 2017 Rockchip Electronics Co., Ltd 3aa9b1b59SFrank Wang * Frank Wang <frank.wang@rock-chips.com> 4aa9b1b59SFrank Wang * 5aa9b1b59SFrank Wang * SPDX-License-Identifier: GPL-2.0+ 6aa9b1b59SFrank Wang */ 7aa9b1b59SFrank Wang 8aa9b1b59SFrank Wang #include <errno.h> 9aa9b1b59SFrank Wang #include <common.h> 10aa9b1b59SFrank Wang #include <command.h> 11aa9b1b59SFrank Wang #include <console.h> 12aa9b1b59SFrank Wang #include <g_dnl.h> 13aa9b1b59SFrank Wang #include <part.h> 14aa9b1b59SFrank Wang #include <usb.h> 15aa9b1b59SFrank Wang #include <usb_mass_storage.h> 16aa9b1b59SFrank Wang #include <rockusb.h> 17aa9b1b59SFrank Wang 18aa9b1b59SFrank Wang static struct rockusb rkusb; 19aa9b1b59SFrank Wang static struct rockusb *g_rkusb; 20aa9b1b59SFrank Wang 21aa9b1b59SFrank Wang static int rkusb_read_sector(struct ums *ums_dev, 22aa9b1b59SFrank Wang ulong start, lbaint_t blkcnt, void *buf) 23aa9b1b59SFrank Wang { 24aa9b1b59SFrank Wang struct blk_desc *block_dev = &ums_dev->block_dev; 25aa9b1b59SFrank Wang lbaint_t blkstart = start + ums_dev->start_sector; 26aa9b1b59SFrank Wang 27957c1cf2SShunqian Zheng if ((blkstart + blkcnt) > RKUSB_READ_LIMIT_ADDR) { 28628c8271SJason Zhu memset(buf, 0xcc, blkcnt * SECTOR_SIZE); 29628c8271SJason Zhu return blkcnt; 30628c8271SJason Zhu } else { 31aa9b1b59SFrank Wang return blk_dread(block_dev, blkstart, blkcnt, buf); 32aa9b1b59SFrank Wang } 33628c8271SJason Zhu } 34aa9b1b59SFrank Wang 35aa9b1b59SFrank Wang static int rkusb_write_sector(struct ums *ums_dev, 36aa9b1b59SFrank Wang ulong start, lbaint_t blkcnt, const void *buf) 37aa9b1b59SFrank Wang { 38aa9b1b59SFrank Wang struct blk_desc *block_dev = &ums_dev->block_dev; 39aa9b1b59SFrank Wang lbaint_t blkstart = start + ums_dev->start_sector; 40177c8736SJon Lin int ret; 41aa9b1b59SFrank Wang 42177c8736SJon Lin if (block_dev->if_type == IF_TYPE_MTD) 43177c8736SJon Lin block_dev->op_flag |= BLK_MTD_CONT_WRITE; 44177c8736SJon Lin ret = blk_dwrite(block_dev, blkstart, blkcnt, buf); 45177c8736SJon Lin if (block_dev->if_type == IF_TYPE_MTD) 46177c8736SJon Lin block_dev->op_flag &= ~(BLK_MTD_CONT_WRITE); 47177c8736SJon Lin return ret; 48aa9b1b59SFrank Wang } 49aa9b1b59SFrank Wang 50aa9b1b59SFrank Wang static int rkusb_erase_sector(struct ums *ums_dev, 51aa9b1b59SFrank Wang ulong start, lbaint_t blkcnt) 52aa9b1b59SFrank Wang { 53aa9b1b59SFrank Wang struct blk_desc *block_dev = &ums_dev->block_dev; 54aa9b1b59SFrank Wang lbaint_t blkstart = start + ums_dev->start_sector; 55aa9b1b59SFrank Wang 56aa9b1b59SFrank Wang return blk_derase(block_dev, blkstart, blkcnt); 57aa9b1b59SFrank Wang } 58aa9b1b59SFrank Wang 59aa9b1b59SFrank Wang static void rkusb_fini(void) 60aa9b1b59SFrank Wang { 61aa9b1b59SFrank Wang int i; 62aa9b1b59SFrank Wang 63aa9b1b59SFrank Wang for (i = 0; i < g_rkusb->ums_cnt; i++) 64aa9b1b59SFrank Wang free((void *)g_rkusb->ums[i].name); 65aa9b1b59SFrank Wang free(g_rkusb->ums); 66aa9b1b59SFrank Wang g_rkusb->ums = NULL; 67aa9b1b59SFrank Wang g_rkusb = NULL; 68aa9b1b59SFrank Wang g_rkusb->ums_cnt = 0; 69aa9b1b59SFrank Wang } 70aa9b1b59SFrank Wang 71aa9b1b59SFrank Wang #define RKUSB_NAME_LEN 16 72aa9b1b59SFrank Wang 73aa9b1b59SFrank Wang static int rkusb_init(const char *devtype, const char *devnums_part_str) 74aa9b1b59SFrank Wang { 75aa9b1b59SFrank Wang char *s, *t, *devnum_part_str, *name; 76aa9b1b59SFrank Wang struct blk_desc *block_dev; 77aa9b1b59SFrank Wang disk_partition_t info; 78aa9b1b59SFrank Wang int partnum, cnt; 79aa9b1b59SFrank Wang int ret = -1; 80aa9b1b59SFrank Wang struct ums *ums_new; 81aa9b1b59SFrank Wang 82aa9b1b59SFrank Wang s = strdup(devnums_part_str); 83aa9b1b59SFrank Wang if (!s) 84aa9b1b59SFrank Wang return -1; 85aa9b1b59SFrank Wang 86aa9b1b59SFrank Wang t = s; 87aa9b1b59SFrank Wang g_rkusb->ums_cnt = 0; 88aa9b1b59SFrank Wang 89aa9b1b59SFrank Wang for (;;) { 90aa9b1b59SFrank Wang devnum_part_str = strsep(&t, ","); 91aa9b1b59SFrank Wang if (!devnum_part_str) 92aa9b1b59SFrank Wang break; 93aa9b1b59SFrank Wang 94aa9b1b59SFrank Wang partnum = blk_get_device_part_str(devtype, devnum_part_str, 95aa9b1b59SFrank Wang &block_dev, &info, 1); 96aa9b1b59SFrank Wang if (partnum < 0) 97aa9b1b59SFrank Wang goto cleanup; 98aa9b1b59SFrank Wang 99aa9b1b59SFrank Wang /* f_mass_storage.c assumes SECTOR_SIZE sectors */ 100aa9b1b59SFrank Wang if (block_dev->blksz != SECTOR_SIZE) 101aa9b1b59SFrank Wang goto cleanup; 102aa9b1b59SFrank Wang 103aa9b1b59SFrank Wang ums_new = realloc(g_rkusb->ums, (g_rkusb->ums_cnt + 1) * 104aa9b1b59SFrank Wang sizeof(*g_rkusb->ums)); 105aa9b1b59SFrank Wang if (!ums_new) 106aa9b1b59SFrank Wang goto cleanup; 107aa9b1b59SFrank Wang g_rkusb->ums = ums_new; 108aa9b1b59SFrank Wang cnt = g_rkusb->ums_cnt; 109aa9b1b59SFrank Wang 110dd31eefeSFrank Wang /* Expose all partitions for rockusb command */ 111aa9b1b59SFrank Wang g_rkusb->ums[cnt].start_sector = 0; 112aa9b1b59SFrank Wang g_rkusb->ums[cnt].num_sectors = block_dev->lba; 113aa9b1b59SFrank Wang 114aa9b1b59SFrank Wang g_rkusb->ums[cnt].read_sector = rkusb_read_sector; 115aa9b1b59SFrank Wang g_rkusb->ums[cnt].write_sector = rkusb_write_sector; 116aa9b1b59SFrank Wang g_rkusb->ums[cnt].erase_sector = rkusb_erase_sector; 117aa9b1b59SFrank Wang 118aa9b1b59SFrank Wang name = malloc(RKUSB_NAME_LEN); 119aa9b1b59SFrank Wang if (!name) 120aa9b1b59SFrank Wang goto cleanup; 121aa9b1b59SFrank Wang snprintf(name, RKUSB_NAME_LEN, "rkusb disk %d", cnt); 122aa9b1b59SFrank Wang g_rkusb->ums[cnt].name = name; 123aa9b1b59SFrank Wang g_rkusb->ums[cnt].block_dev = *block_dev; 124aa9b1b59SFrank Wang 125aa9b1b59SFrank Wang printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 126aa9b1b59SFrank Wang g_rkusb->ums_cnt, 127aa9b1b59SFrank Wang g_rkusb->ums[cnt].block_dev.devnum, 128aa9b1b59SFrank Wang g_rkusb->ums[cnt].block_dev.hwpart, 129aa9b1b59SFrank Wang g_rkusb->ums[cnt].start_sector, 130aa9b1b59SFrank Wang g_rkusb->ums[cnt].num_sectors); 131aa9b1b59SFrank Wang 132aa9b1b59SFrank Wang g_rkusb->ums_cnt++; 133aa9b1b59SFrank Wang } 134aa9b1b59SFrank Wang 135aa9b1b59SFrank Wang if (g_rkusb->ums_cnt) 136aa9b1b59SFrank Wang ret = 0; 137aa9b1b59SFrank Wang 138aa9b1b59SFrank Wang cleanup: 139aa9b1b59SFrank Wang free(s); 140aa9b1b59SFrank Wang if (ret < 0) 141aa9b1b59SFrank Wang rkusb_fini(); 142aa9b1b59SFrank Wang 143aa9b1b59SFrank Wang return ret; 144aa9b1b59SFrank Wang } 145aa9b1b59SFrank Wang 146aa9b1b59SFrank Wang static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 147aa9b1b59SFrank Wang { 148aa9b1b59SFrank Wang const char *usb_controller; 149aa9b1b59SFrank Wang const char *devtype; 150aa9b1b59SFrank Wang const char *devnum; 151aa9b1b59SFrank Wang unsigned int controller_index; 152aa9b1b59SFrank Wang int rc; 153aa9b1b59SFrank Wang int cable_ready_timeout __maybe_unused; 154fc1a5563SJason Zhu const char *s; 155aa9b1b59SFrank Wang 156aa9b1b59SFrank Wang if (argc != 4) 157aa9b1b59SFrank Wang return CMD_RET_USAGE; 158aa9b1b59SFrank Wang 159aa9b1b59SFrank Wang usb_controller = argv[1]; 160aa9b1b59SFrank Wang devtype = argv[2]; 161aa9b1b59SFrank Wang devnum = argv[3]; 162aa9b1b59SFrank Wang 163535b44c0SJoseph Chen if (!strcmp(devtype, "mmc") && !strcmp(devnum, "1")) { 164535b44c0SJoseph Chen pr_err("Forbid to flash mmc 1(sdcard)\n"); 165535b44c0SJoseph Chen return CMD_RET_FAILURE; 166535b44c0SJoseph Chen } 167535b44c0SJoseph Chen 168aa9b1b59SFrank Wang g_rkusb = &rkusb; 169aa9b1b59SFrank Wang rc = rkusb_init(devtype, devnum); 170aa9b1b59SFrank Wang if (rc < 0) 171aa9b1b59SFrank Wang return CMD_RET_FAILURE; 172aa9b1b59SFrank Wang 173*1b01cf55SYifeng Zhao if (g_rkusb->ums[0].block_dev.if_type == IF_TYPE_MTD && 174*1b01cf55SYifeng Zhao g_rkusb->ums[0].block_dev.devnum == BLK_MTD_NAND) { 175*1b01cf55SYifeng Zhao #ifdef CONFIG_CMD_GO 176*1b01cf55SYifeng Zhao pr_err("Enter bootrom rockusb...\n"); 177*1b01cf55SYifeng Zhao flushc(); 178*1b01cf55SYifeng Zhao run_command("rbrom", 0); 179*1b01cf55SYifeng Zhao #else 180*1b01cf55SYifeng Zhao pr_err("rockusb: count not support loader upgrade!\n"); 181*1b01cf55SYifeng Zhao #endif 182*1b01cf55SYifeng Zhao } 183*1b01cf55SYifeng Zhao 184aa9b1b59SFrank Wang controller_index = (unsigned int)(simple_strtoul( 185aa9b1b59SFrank Wang usb_controller, NULL, 0)); 186b95d4446SJean-Jacques Hiblot rc = usb_gadget_initialize(controller_index); 187b95d4446SJean-Jacques Hiblot if (rc) { 18890aa625cSMasahiro Yamada pr_err("Couldn't init USB controller."); 189aa9b1b59SFrank Wang rc = CMD_RET_FAILURE; 190aa9b1b59SFrank Wang goto cleanup_rkusb; 191aa9b1b59SFrank Wang } 192aa9b1b59SFrank Wang 193aa9b1b59SFrank Wang rc = fsg_init(g_rkusb->ums, g_rkusb->ums_cnt); 194aa9b1b59SFrank Wang if (rc) { 19590aa625cSMasahiro Yamada pr_err("fsg_init failed"); 196aa9b1b59SFrank Wang rc = CMD_RET_FAILURE; 197aa9b1b59SFrank Wang goto cleanup_board; 198aa9b1b59SFrank Wang } 199aa9b1b59SFrank Wang 200fc1a5563SJason Zhu s = env_get("serial#"); 20106c1e1b3SJason Zhu if (s) { 20206c1e1b3SJason Zhu char *sn = (char *)calloc(strlen(s) + 1, sizeof(char)); 20306c1e1b3SJason Zhu char *sn_p = sn; 20406c1e1b3SJason Zhu 20506c1e1b3SJason Zhu if (!sn) 20606c1e1b3SJason Zhu goto cleanup_board; 20706c1e1b3SJason Zhu 20806c1e1b3SJason Zhu memcpy(sn, s, strlen(s)); 20906c1e1b3SJason Zhu while (*sn_p) { 21006c1e1b3SJason Zhu if (*sn_p == '\\' || *sn_p == '/') 21106c1e1b3SJason Zhu *sn_p = '_'; 21206c1e1b3SJason Zhu sn_p++; 21306c1e1b3SJason Zhu } 21406c1e1b3SJason Zhu 21506c1e1b3SJason Zhu g_dnl_set_serialnumber(sn); 21606c1e1b3SJason Zhu free(sn); 21706c1e1b3SJason Zhu } 218fc1a5563SJason Zhu 219aa9b1b59SFrank Wang rc = g_dnl_register("rkusb_ums_dnl"); 220aa9b1b59SFrank Wang if (rc) { 22190aa625cSMasahiro Yamada pr_err("g_dnl_register failed"); 222aa9b1b59SFrank Wang rc = CMD_RET_FAILURE; 223aa9b1b59SFrank Wang goto cleanup_board; 224aa9b1b59SFrank Wang } 225aa9b1b59SFrank Wang 226aa9b1b59SFrank Wang /* Timeout unit: seconds */ 227aa9b1b59SFrank Wang cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 228aa9b1b59SFrank Wang 229aa9b1b59SFrank Wang if (!g_dnl_board_usb_cable_connected()) { 230aa9b1b59SFrank Wang puts("Please connect USB cable.\n"); 231aa9b1b59SFrank Wang 232aa9b1b59SFrank Wang while (!g_dnl_board_usb_cable_connected()) { 233aa9b1b59SFrank Wang if (ctrlc()) { 234aa9b1b59SFrank Wang puts("\rCTRL+C - Operation aborted.\n"); 235aa9b1b59SFrank Wang rc = CMD_RET_SUCCESS; 236aa9b1b59SFrank Wang goto cleanup_register; 237aa9b1b59SFrank Wang } 238aa9b1b59SFrank Wang if (!cable_ready_timeout) { 239aa9b1b59SFrank Wang puts("\rUSB cable not detected.\nCommand exit.\n"); 240aa9b1b59SFrank Wang rc = CMD_RET_SUCCESS; 241aa9b1b59SFrank Wang goto cleanup_register; 242aa9b1b59SFrank Wang } 243aa9b1b59SFrank Wang 244aa9b1b59SFrank Wang printf("\rAuto exit in: %.2d s.", cable_ready_timeout); 245aa9b1b59SFrank Wang mdelay(1000); 246aa9b1b59SFrank Wang cable_ready_timeout--; 247aa9b1b59SFrank Wang } 248aa9b1b59SFrank Wang puts("\r\n"); 249aa9b1b59SFrank Wang } 250aa9b1b59SFrank Wang 251aa9b1b59SFrank Wang while (1) { 252aa9b1b59SFrank Wang usb_gadget_handle_interrupts(controller_index); 253aa9b1b59SFrank Wang 254aa9b1b59SFrank Wang rc = fsg_main_thread(NULL); 255aa9b1b59SFrank Wang if (rc) { 256aa9b1b59SFrank Wang /* Check I/O error */ 257aa9b1b59SFrank Wang if (rc == -EIO) 258aa9b1b59SFrank Wang printf("\rCheck USB cable connection\n"); 259aa9b1b59SFrank Wang 260aa9b1b59SFrank Wang /* Check CTRL+C */ 261aa9b1b59SFrank Wang if (rc == -EPIPE) 262aa9b1b59SFrank Wang printf("\rCTRL+C - Operation aborted\n"); 263aa9b1b59SFrank Wang 264aa9b1b59SFrank Wang rc = CMD_RET_SUCCESS; 265aa9b1b59SFrank Wang goto cleanup_register; 266aa9b1b59SFrank Wang } 267aa9b1b59SFrank Wang } 268aa9b1b59SFrank Wang 269aa9b1b59SFrank Wang cleanup_register: 270aa9b1b59SFrank Wang g_dnl_unregister(); 271aa9b1b59SFrank Wang cleanup_board: 272b95d4446SJean-Jacques Hiblot usb_gadget_release(controller_index); 273aa9b1b59SFrank Wang cleanup_rkusb: 274aa9b1b59SFrank Wang rkusb_fini(); 275aa9b1b59SFrank Wang 276aa9b1b59SFrank Wang return rc; 277aa9b1b59SFrank Wang } 278aa9b1b59SFrank Wang 279f6aff21fSJoseph Chen U_BOOT_CMD_ALWAYS(rockusb, 4, 1, do_rkusb, 280aa9b1b59SFrank Wang "Use the rockusb Protocol", 281aa9b1b59SFrank Wang "<USB_controller> <devtype> <dev[:part]> e.g. rockusb 0 mmc 0\n" 282aa9b1b59SFrank Wang ); 283