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 27 if ((blkstart + blkcnt) > RKUSB_READ_LIMIT_ADDR) { 28 memset(buf, 0xcc, blkcnt * SECTOR_SIZE); 29 return blkcnt; 30 } else { 31 return blk_dread(block_dev, blkstart, blkcnt, buf); 32 } 33 } 34 35 static int rkusb_write_sector(struct ums *ums_dev, 36 ulong start, lbaint_t blkcnt, const void *buf) 37 { 38 struct blk_desc *block_dev = &ums_dev->block_dev; 39 lbaint_t blkstart = start + ums_dev->start_sector; 40 int ret; 41 42 if (block_dev->if_type == IF_TYPE_MTD) 43 block_dev->op_flag |= BLK_MTD_CONT_WRITE; 44 ret = blk_dwrite(block_dev, blkstart, blkcnt, buf); 45 if (block_dev->if_type == IF_TYPE_MTD) 46 block_dev->op_flag &= ~(BLK_MTD_CONT_WRITE); 47 return ret; 48 } 49 50 static int rkusb_erase_sector(struct ums *ums_dev, 51 ulong start, lbaint_t blkcnt) 52 { 53 struct blk_desc *block_dev = &ums_dev->block_dev; 54 lbaint_t blkstart = start + ums_dev->start_sector; 55 56 return blk_derase(block_dev, blkstart, blkcnt); 57 } 58 59 static void rkusb_fini(void) 60 { 61 int i; 62 63 for (i = 0; i < g_rkusb->ums_cnt; i++) 64 free((void *)g_rkusb->ums[i].name); 65 free(g_rkusb->ums); 66 g_rkusb->ums = NULL; 67 g_rkusb = NULL; 68 g_rkusb->ums_cnt = 0; 69 } 70 71 #define RKUSB_NAME_LEN 16 72 73 static int rkusb_init(const char *devtype, const char *devnums_part_str) 74 { 75 char *s, *t, *devnum_part_str, *name; 76 struct blk_desc *block_dev; 77 disk_partition_t info; 78 int partnum, cnt; 79 int ret = -1; 80 struct ums *ums_new; 81 82 s = strdup(devnums_part_str); 83 if (!s) 84 return -1; 85 86 t = s; 87 g_rkusb->ums_cnt = 0; 88 89 for (;;) { 90 devnum_part_str = strsep(&t, ","); 91 if (!devnum_part_str) 92 break; 93 94 partnum = blk_get_device_part_str(devtype, devnum_part_str, 95 &block_dev, &info, 1); 96 if (partnum < 0) 97 goto cleanup; 98 99 /* f_mass_storage.c assumes SECTOR_SIZE sectors */ 100 if (block_dev->blksz != SECTOR_SIZE) 101 goto cleanup; 102 103 ums_new = realloc(g_rkusb->ums, (g_rkusb->ums_cnt + 1) * 104 sizeof(*g_rkusb->ums)); 105 if (!ums_new) 106 goto cleanup; 107 g_rkusb->ums = ums_new; 108 cnt = g_rkusb->ums_cnt; 109 110 /* Expose all partitions for rockusb command */ 111 g_rkusb->ums[cnt].start_sector = 0; 112 g_rkusb->ums[cnt].num_sectors = block_dev->lba; 113 114 g_rkusb->ums[cnt].read_sector = rkusb_read_sector; 115 g_rkusb->ums[cnt].write_sector = rkusb_write_sector; 116 g_rkusb->ums[cnt].erase_sector = rkusb_erase_sector; 117 118 name = malloc(RKUSB_NAME_LEN); 119 if (!name) 120 goto cleanup; 121 snprintf(name, RKUSB_NAME_LEN, "rkusb disk %d", cnt); 122 g_rkusb->ums[cnt].name = name; 123 g_rkusb->ums[cnt].block_dev = *block_dev; 124 125 printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 126 g_rkusb->ums_cnt, 127 g_rkusb->ums[cnt].block_dev.devnum, 128 g_rkusb->ums[cnt].block_dev.hwpart, 129 g_rkusb->ums[cnt].start_sector, 130 g_rkusb->ums[cnt].num_sectors); 131 132 g_rkusb->ums_cnt++; 133 } 134 135 if (g_rkusb->ums_cnt) 136 ret = 0; 137 138 cleanup: 139 free(s); 140 if (ret < 0) 141 rkusb_fini(); 142 143 return ret; 144 } 145 146 static int do_rkusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 147 { 148 const char *usb_controller; 149 const char *devtype; 150 const char *devnum; 151 unsigned int controller_index; 152 int rc; 153 int cable_ready_timeout __maybe_unused; 154 const char *s; 155 156 if (argc != 4) 157 return CMD_RET_USAGE; 158 159 usb_controller = argv[1]; 160 devtype = argv[2]; 161 devnum = argv[3]; 162 163 if (!strcmp(devtype, "mmc") && !strcmp(devnum, "1")) { 164 pr_err("Forbid to flash mmc 1(sdcard)\n"); 165 return CMD_RET_FAILURE; 166 } 167 168 g_rkusb = &rkusb; 169 rc = rkusb_init(devtype, devnum); 170 if (rc < 0) 171 return CMD_RET_FAILURE; 172 173 if (g_rkusb->ums[0].block_dev.if_type == IF_TYPE_MTD && 174 g_rkusb->ums[0].block_dev.devnum == BLK_MTD_NAND) { 175 #ifdef CONFIG_CMD_GO 176 pr_err("Enter bootrom rockusb...\n"); 177 flushc(); 178 run_command("rbrom", 0); 179 #else 180 pr_err("rockusb: count not support loader upgrade!\n"); 181 #endif 182 } 183 184 controller_index = (unsigned int)(simple_strtoul( 185 usb_controller, NULL, 0)); 186 rc = usb_gadget_initialize(controller_index); 187 if (rc) { 188 pr_err("Couldn't init USB controller."); 189 rc = CMD_RET_FAILURE; 190 goto cleanup_rkusb; 191 } 192 193 rc = fsg_init(g_rkusb->ums, g_rkusb->ums_cnt); 194 if (rc) { 195 pr_err("fsg_init failed"); 196 rc = CMD_RET_FAILURE; 197 goto cleanup_board; 198 } 199 200 s = env_get("serial#"); 201 if (s) { 202 char *sn = (char *)calloc(strlen(s) + 1, sizeof(char)); 203 char *sn_p = sn; 204 205 if (!sn) 206 goto cleanup_board; 207 208 memcpy(sn, s, strlen(s)); 209 while (*sn_p) { 210 if (*sn_p == '\\' || *sn_p == '/') 211 *sn_p = '_'; 212 sn_p++; 213 } 214 215 g_dnl_set_serialnumber(sn); 216 free(sn); 217 } 218 219 rc = g_dnl_register("rkusb_ums_dnl"); 220 if (rc) { 221 pr_err("g_dnl_register failed"); 222 rc = CMD_RET_FAILURE; 223 goto cleanup_board; 224 } 225 226 /* Timeout unit: seconds */ 227 cable_ready_timeout = UMS_CABLE_READY_TIMEOUT; 228 229 if (!g_dnl_board_usb_cable_connected()) { 230 puts("Please connect USB cable.\n"); 231 232 while (!g_dnl_board_usb_cable_connected()) { 233 if (ctrlc()) { 234 puts("\rCTRL+C - Operation aborted.\n"); 235 rc = CMD_RET_SUCCESS; 236 goto cleanup_register; 237 } 238 if (!cable_ready_timeout) { 239 puts("\rUSB cable not detected.\nCommand exit.\n"); 240 rc = CMD_RET_SUCCESS; 241 goto cleanup_register; 242 } 243 244 printf("\rAuto exit in: %.2d s.", cable_ready_timeout); 245 mdelay(1000); 246 cable_ready_timeout--; 247 } 248 puts("\r\n"); 249 } 250 251 while (1) { 252 usb_gadget_handle_interrupts(controller_index); 253 254 rc = fsg_main_thread(NULL); 255 if (rc) { 256 /* Check I/O error */ 257 if (rc == -EIO) 258 printf("\rCheck USB cable connection\n"); 259 260 /* Check CTRL+C */ 261 if (rc == -EPIPE) 262 printf("\rCTRL+C - Operation aborted\n"); 263 264 rc = CMD_RET_SUCCESS; 265 goto cleanup_register; 266 } 267 } 268 269 cleanup_register: 270 g_dnl_unregister(); 271 cleanup_board: 272 usb_gadget_release(controller_index); 273 cleanup_rkusb: 274 rkusb_fini(); 275 276 return rc; 277 } 278 279 U_BOOT_CMD_ALWAYS(rockusb, 4, 1, do_rkusb, 280 "Use the rockusb Protocol", 281 "<USB_controller> <devtype> <dev[:part]> e.g. rockusb 0 mmc 0\n" 282 ); 283