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