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