1 /* 2 * Copyright 2017 Rockchip Electronics Co., Ltd 3 * Frank Wang <frank.wang@rock-chips.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <errno.h> 9 #include <common.h> 10 #include <command.h> 11 #include <console.h> 12 #include <g_dnl.h> 13 #include <part.h> 14 #include <usb.h> 15 #include <usb_mass_storage.h> 16 #include <rockusb.h> 17 18 static struct rockusb rkusb; 19 static struct rockusb *g_rkusb; 20 21 static int rkusb_read_sector(struct ums *ums_dev, 22 ulong start, lbaint_t blkcnt, void *buf) 23 { 24 struct blk_desc *block_dev = &ums_dev->block_dev; 25 lbaint_t blkstart = start + ums_dev->start_sector; 26 int ret; 27 28 if ((blkstart + blkcnt) > RKUSB_READ_LIMIT_ADDR) { 29 memset(buf, 0xcc, blkcnt * SECTOR_SIZE); 30 return blkcnt; 31 } else { 32 ret = blk_dread(block_dev, blkstart, blkcnt, buf); 33 if (!ret) 34 ret = -EIO; 35 return ret; 36 } 37 } 38 39 static int rkusb_write_sector(struct ums *ums_dev, 40 ulong start, lbaint_t blkcnt, const void *buf) 41 { 42 struct blk_desc *block_dev = &ums_dev->block_dev; 43 lbaint_t blkstart = start + ums_dev->start_sector; 44 int ret; 45 46 if (block_dev->if_type == IF_TYPE_MTD) 47 block_dev->op_flag |= BLK_MTD_CONT_WRITE; 48 49 ret = blk_dwrite(block_dev, blkstart, blkcnt, buf); 50 if (!ret) 51 ret = -EIO; 52 53 if (block_dev->if_type == IF_TYPE_MTD) 54 block_dev->op_flag &= ~(BLK_MTD_CONT_WRITE); 55 return ret; 56 } 57 58 static int rkusb_erase_sector(struct ums *ums_dev, 59 ulong start, lbaint_t blkcnt) 60 { 61 struct blk_desc *block_dev = &ums_dev->block_dev; 62 lbaint_t blkstart = start + ums_dev->start_sector; 63 64 return blk_derase(block_dev, blkstart, blkcnt); 65 } 66 67 static void rkusb_fini(void) 68 { 69 int i; 70 71 for (i = 0; i < g_rkusb->ums_cnt; i++) 72 free((void *)g_rkusb->ums[i].name); 73 free(g_rkusb->ums); 74 g_rkusb->ums = NULL; 75 g_rkusb->ums_cnt = 0; 76 g_rkusb = NULL; 77 } 78 79 #define RKUSB_NAME_LEN 16 80 81 static int rkusb_init(const char *devtype, const char *devnums_part_str) 82 { 83 char *s, *t, *devnum_part_str, *name; 84 struct blk_desc *block_dev; 85 disk_partition_t info; 86 int partnum, cnt; 87 int ret = -1; 88 struct ums *ums_new; 89 90 s = strdup(devnums_part_str); 91 if (!s) 92 return -1; 93 94 t = s; 95 g_rkusb->ums_cnt = 0; 96 97 for (;;) { 98 devnum_part_str = strsep(&t, ","); 99 if (!devnum_part_str) 100 break; 101 102 partnum = blk_get_device_part_str(devtype, devnum_part_str, 103 &block_dev, &info, 1); 104 if (partnum < 0) 105 goto cleanup; 106 107 /* f_mass_storage.c assumes SECTOR_SIZE sectors */ 108 if (block_dev->blksz != SECTOR_SIZE) 109 goto cleanup; 110 111 ums_new = realloc(g_rkusb->ums, (g_rkusb->ums_cnt + 1) * 112 sizeof(*g_rkusb->ums)); 113 if (!ums_new) 114 goto cleanup; 115 g_rkusb->ums = ums_new; 116 cnt = g_rkusb->ums_cnt; 117 118 /* Expose all partitions for rockusb command */ 119 g_rkusb->ums[cnt].start_sector = 0; 120 g_rkusb->ums[cnt].num_sectors = block_dev->lba; 121 122 g_rkusb->ums[cnt].read_sector = rkusb_read_sector; 123 g_rkusb->ums[cnt].write_sector = rkusb_write_sector; 124 g_rkusb->ums[cnt].erase_sector = rkusb_erase_sector; 125 126 name = malloc(RKUSB_NAME_LEN); 127 if (!name) 128 goto cleanup; 129 snprintf(name, RKUSB_NAME_LEN, "rkusb disk %d", cnt); 130 g_rkusb->ums[cnt].name = name; 131 g_rkusb->ums[cnt].block_dev = *block_dev; 132 133 printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 134 g_rkusb->ums_cnt, 135 g_rkusb->ums[cnt].block_dev.devnum, 136 g_rkusb->ums[cnt].block_dev.hwpart, 137 g_rkusb->ums[cnt].start_sector, 138 g_rkusb->ums[cnt].num_sectors); 139 140 g_rkusb->ums_cnt++; 141 } 142 143 if (g_rkusb->ums_cnt) 144 ret = 0; 145 146 cleanup: 147 free(s); 148 if (ret < 0) 149 rkusb_fini(); 150 151 return ret; 152 } 153 154 void rkusb_force_to_usb2(bool enable) 155 { 156 if (g_rkusb) 157 g_rkusb->force_usb2 = enable; 158 } 159 160 bool rkusb_force_usb2_enabled(void) 161 { 162 if (!g_rkusb) 163 return true; 164 165 return g_rkusb->force_usb2; 166 } 167 168 void rkusb_switch_to_usb3_enable(bool enable) 169 { 170 if (g_rkusb) 171 g_rkusb->switch_usb3 = enable; 172 } 173 174 bool rkusb_switch_usb3_enabled(void) 175 { 176 if (!g_rkusb) 177 return false; 178 179 return g_rkusb->switch_usb3; 180 } 181 182 static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 183 { 184 const char *usb_controller; 185 const char *devtype; 186 const char *devnum; 187 unsigned int controller_index; 188 int rc; 189 int cable_ready_timeout __maybe_unused; 190 const char *s; 191 192 if (argc != 4) 193 return CMD_RET_USAGE; 194 195 re_enumerate: 196 usb_controller = argv[1]; 197 devtype = argv[2]; 198 devnum = argv[3]; 199 200 if (!strcmp(devtype, "mmc") && !strcmp(devnum, "1")) { 201 pr_err("Forbid to flash mmc 1(sdcard)\n"); 202 return CMD_RET_FAILURE; 203 } else if ((!strcmp(devtype, "nvme") || !strcmp(devtype, "scsi")) && !strcmp(devnum, "0")) { 204 /* 205 * Add partnum ":0" to active 'allow_whole_dev' partition 206 * search mechanism on multi storage, where there maybe not 207 * valid partition table. 208 */ 209 devnum = "0:0"; 210 } 211 212 g_rkusb = &rkusb; 213 rc = rkusb_init(devtype, devnum); 214 if (rc < 0) 215 return CMD_RET_FAILURE; 216 217 if (g_rkusb->ums[0].block_dev.if_type == IF_TYPE_MTD && 218 g_rkusb->ums[0].block_dev.devnum == BLK_MTD_NAND) { 219 #ifdef CONFIG_CMD_GO 220 pr_err("Enter bootrom rockusb...\n"); 221 flushc(); 222 run_command("rbrom", 0); 223 #else 224 pr_err("rockusb: count not support loader upgrade!\n"); 225 #endif 226 } 227 228 controller_index = (unsigned int)(simple_strtoul( 229 usb_controller, NULL, 0)); 230 rc = usb_gadget_initialize(controller_index); 231 if (rc) { 232 pr_err("Couldn't init USB controller."); 233 rc = CMD_RET_FAILURE; 234 goto cleanup_rkusb; 235 } 236 237 rc = fsg_init(g_rkusb->ums, g_rkusb->ums_cnt); 238 if (rc) { 239 pr_err("fsg_init failed"); 240 rc = CMD_RET_FAILURE; 241 goto cleanup_board; 242 } 243 244 if (rkusb_switch_usb3_enabled()) { 245 /* Maskrom usb3 serialnumber get from upgrade tool */ 246 rkusb_switch_to_usb3_enable(false); 247 } else { 248 s = env_get("serial#"); 249 if (s) { 250 char *sn = (char *)calloc(strlen(s) + 1, sizeof(char)); 251 char *sn_p = sn; 252 253 if (!sn) 254 goto cleanup_board; 255 256 memcpy(sn, s, strlen(s)); 257 while (*sn_p) { 258 if (*sn_p == '\\' || *sn_p == '/') 259 *sn_p = '_'; 260 sn_p++; 261 } 262 263 g_dnl_set_serialnumber(sn); 264 free(sn); 265 #if defined(CONFIG_SUPPORT_USBPLUG) 266 } else { 267 char sn[9] = "Rockchip"; 268 269 g_dnl_set_serialnumber(sn); 270 #endif 271 } 272 } 273 274 rc = g_dnl_register("rkusb_ums_dnl"); 275 if (rc) { 276 pr_err("g_dnl_register failed"); 277 rc = CMD_RET_FAILURE; 278 goto cleanup_board; 279 } 280 281 /* Timeout unit: seconds */ 282 cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 283 284 if (!g_dnl_board_usb_cable_connected()) { 285 puts("Please connect USB cable.\n"); 286 287 while (!g_dnl_board_usb_cable_connected()) { 288 if (ctrlc()) { 289 puts("\rCTRL+C - Operation aborted.\n"); 290 rc = CMD_RET_SUCCESS; 291 goto cleanup_register; 292 } 293 if (!cable_ready_timeout) { 294 puts("\rUSB cable not detected.\nCommand exit.\n"); 295 rc = CMD_RET_SUCCESS; 296 goto cleanup_register; 297 } 298 299 printf("\rAuto exit in: %.2d s.", cable_ready_timeout); 300 mdelay(1000); 301 cable_ready_timeout--; 302 } 303 puts("\r\n"); 304 } 305 306 while (1) { 307 usb_gadget_handle_interrupts(controller_index); 308 309 rc = fsg_main_thread(NULL); 310 if (rc) { 311 if (rc == -ENODEV && rkusb_usb3_capable() && 312 !rkusb_force_usb2_enabled()) { 313 printf("wait for usb3 connect timeout\n"); 314 rkusb_force_to_usb2(true); 315 g_dnl_unregister(); 316 usb_gadget_release(controller_index); 317 rkusb_fini(); 318 goto re_enumerate; 319 } 320 321 /* Check I/O error */ 322 if (rc == -EIO) 323 printf("\rCheck USB cable connection\n"); 324 325 /* Check CTRL+C */ 326 if (rc == -EPIPE) 327 printf("\rCTRL+C - Operation aborted\n"); 328 329 rc = CMD_RET_SUCCESS; 330 goto cleanup_register; 331 } 332 333 if (rkusb_switch_usb3_enabled()) { 334 printf("rockusb switch to usb3\n"); 335 g_dnl_unregister(); 336 usb_gadget_release(controller_index); 337 rkusb_fini(); 338 goto re_enumerate; 339 } 340 } 341 342 cleanup_register: 343 g_dnl_unregister(); 344 cleanup_board: 345 usb_gadget_release(controller_index); 346 cleanup_rkusb: 347 rkusb_fini(); 348 349 return rc; 350 } 351 352 U_BOOT_CMD_ALWAYS(rockusb, 4, 1, do_rkusb, 353 "Use the rockusb Protocol", 354 "<USB_controller> <devtype> <dev[:part]> e.g. rockusb 0 mmc 0\n" 355 ); 356