• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /**
3  * ufs.c - UFS specific U-boot commands
4  *
5  * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
6  *
7  */
8 #include <common.h>
9 #include <command.h>
10 #include <ufs.h>
11 
12 #ifndef CONFIG_UFS
do_ufs(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])13 static int do_ufs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
14 {
15 	int dev, ret;
16 
17 	if (argc >= 2) {
18 		if (!strcmp(argv[1], "init")) {
19 			if (argc == 3) {
20 				dev = simple_strtoul(argv[2], NULL, 10);
21 				ret = ufs_probe_dev(dev);
22 				if (ret)
23 					return CMD_RET_FAILURE;
24 			} else {
25 				ufs_probe();
26 			}
27 
28 			return CMD_RET_SUCCESS;
29 		}
30 	}
31 
32 	return CMD_RET_USAGE;
33 }
34 
35 U_BOOT_CMD(ufs, 3, 1, do_ufs,
36 	   "UFS  sub system",
37 	   "init [dev] - init UFS subsystem\n"
38 );
39 #else
40 
41 #define UFS_BLKSIZE_SHIFT 12
42 #define b2m(a) (((a) >> 10) / 1000)
43 #define b2k(a) (((a) >> 10) % 1000)
44 static int curr_device = 0;
45 
do_ufs_read(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])46 static int do_ufs_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
47 {
48 	u32 blk, cnt;
49 	u64 addr;
50 	unsigned long long start_ticks, end_ticks;
51 	unsigned long long size, speed;
52 
53 	if (argc != 5) /* 5 arg */
54 		return CMD_RET_USAGE;
55 
56 	addr = (u64)simple_strtoul(argv[2], NULL, 16); /* arg 2: ddr addr, 16 in hex */
57 	blk = simple_strtoul(argv[3], NULL, 16);       /* arg 3: start block, 16 in hex */
58 	cnt = simple_strtoul(argv[4], NULL, 16);       /* arg 4: block count, 16 in hex */
59 
60 	printf("\nUFS read: dev # %d, block # %d, count %d ... ", curr_device, blk, cnt);
61 
62 	ufs_storage_init();
63 	start_ticks = get_ticks();
64 	if (ufs_read_storage(addr, (u64)blk << UFS_BLKSIZE_SHIFT, cnt << UFS_BLKSIZE_SHIFT)) {
65 		printf("0 blocks read: ERROR\n");
66 		return CMD_RET_FAILURE;
67 	}
68 	end_ticks = get_ticks();
69 	printf("%d blocks read: OK\n", cnt);
70 
71 	size = cnt << UFS_BLKSIZE_SHIFT;
72 	speed = (size * CONFIG_SYS_TIMER_RATE) / (end_ticks - start_ticks);
73 	printf("%llu.%03llu MB/s\n", b2m(speed), b2k(speed));
74 
75 	return CMD_RET_SUCCESS;
76 }
77 
do_ufs_write(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])78 static int do_ufs_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
79 {
80 	u32 blk, cnt;
81 	u64 addr;
82 	unsigned long long start_ticks, end_ticks;
83 	unsigned long long size, speed;
84 
85 	if (argc != 5) /* 5 arg */
86 		return CMD_RET_USAGE;
87 
88 	addr = (u64)simple_strtoul(argv[2], NULL, 16); /* arg 2: ddr addr, 16 in hex */
89 	blk = simple_strtoul(argv[3], NULL, 16);       /* arg 3: start block, 16 in hex */
90 	cnt = simple_strtoul(argv[4], NULL, 16);       /* arg 4: block count, 16 in hex */
91 
92 	if (strncmp(argv[0], "write.ext4sp", sizeof("write.ext4sp")) == 0) {
93 #ifdef CONFIG_EXT4_SPARSE
94 		printf("\nUFS write ext4 sparse: dev # %d, block # %d, count %d ...\n",
95 		       curr_device, blk, cnt);
96 
97 		return ufs_ext4_unsparse((void *)(uintptr_t)addr, blk, cnt);
98 #else
99 		printf("Not support.\n");
100 		return CMD_RET_SUCCESS;
101 #endif
102 	}
103 
104 	printf("\nUFS write: dev # %d, block # %d, count %d ... ", curr_device, blk, cnt);
105 
106 	ufs_storage_init();
107 	start_ticks = get_ticks();
108 	if (ufs_write_storage(addr, (u64)blk << UFS_BLKSIZE_SHIFT, cnt << UFS_BLKSIZE_SHIFT)) {
109 		printf("0 blocks write: ERROR\n");
110 		return CMD_RET_FAILURE;
111 	}
112 	end_ticks = get_ticks();
113 	printf("%d blocks written: OK\n", cnt);
114 
115 	size = cnt << UFS_BLKSIZE_SHIFT;
116 	speed = (size * CONFIG_SYS_TIMER_RATE) / (end_ticks - start_ticks);
117 	printf("%llu.%03llu MB/s\n", b2m(speed), b2k(speed));
118 
119 	/* must write boot data to boot lun due to bootup demand,
120 	 * start from block 0, no longer than 0x400 blocks(4M).
121 	 */
122 	if ((blk == 0) && (cnt <= 0x400)) {
123 		/* write boot data */
124 		if (ufs_write_boot_storage(addr, (u64)blk << UFS_BLKSIZE_SHIFT,
125 				cnt << UFS_BLKSIZE_SHIFT)) {
126 			printf("boot write: ERROR\n");
127 			return CMD_RET_FAILURE;
128 		}
129 	}
130 
131 	return CMD_RET_SUCCESS;
132 }
133 
do_ufs_bootread(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])134 static int do_ufs_bootread(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
135 {
136 	u32 blk, cnt;
137 	u64 addr;
138 
139 	if (argc != 5) /* 5 arg */
140 		return CMD_RET_USAGE;
141 
142 	addr = (u64)simple_strtoul(argv[2], NULL, 16); /* arg 2: ddr addr, 16 in hex */
143 	blk = simple_strtoul(argv[3], NULL, 16);       /* arg 3: start block, 16 in hex */
144 	cnt = simple_strtoul(argv[4], NULL, 16);       /* arg 4: block count, 16 in hex */
145 
146 	printf("\nUFS read: dev # %d, block # %d, count %d ... ", curr_device, blk, cnt);
147 
148 	ufs_storage_init();
149 	if (ufs_read_boot_storage(addr, (u64)blk << UFS_BLKSIZE_SHIFT,
150 			cnt << UFS_BLKSIZE_SHIFT)) {
151 		printf("boot read: ERROR\n");
152 		return CMD_RET_FAILURE;
153 	}
154 	printf("%d blocks read: OK\n", cnt);
155 
156 	return CMD_RET_SUCCESS;
157 }
158 
do_ufs_bootwrite(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])159 static int do_ufs_bootwrite(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
160 {
161 	u32 blk, cnt;
162 	u64 addr;
163 
164 	if (argc != 5) /* 5 arg */
165 		return CMD_RET_USAGE;
166 
167 	addr = (u64)simple_strtoul(argv[2], NULL, 16); /* arg 2: ddr addr, 16 in hex */
168 	blk = simple_strtoul(argv[3], NULL, 16);       /* arg 3: start block, 16 in hex */
169 	cnt = simple_strtoul(argv[4], NULL, 16);       /* arg 4: block count, 16 in hex */
170 
171 	printf("\nUFS write: dev # %d, block # %d, count %d ... ", curr_device, blk, cnt);
172 
173 	ufs_storage_init();
174 	if (ufs_write_boot_storage(addr, (u64)blk << UFS_BLKSIZE_SHIFT,
175 			cnt << UFS_BLKSIZE_SHIFT)) {
176 		printf("boot write: ERROR\n");
177 		return CMD_RET_FAILURE;
178 	}
179 	printf("%d blocks write: OK\n", cnt);
180 
181 	return CMD_RET_SUCCESS;
182 }
183 
do_ufs_reinit(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])184 static int do_ufs_reinit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
185 {
186 	if (argc != 2) /* 2 arg */
187 		return CMD_RET_USAGE;
188 
189 	ufs_reinit();
190 
191 	return CMD_RET_SUCCESS;
192 }
193 
do_ufs_reg(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])194 static int do_ufs_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
195 {
196 	if (argc != 2) /* 2 arg */
197 		return CMD_RET_USAGE;
198 
199 	ufs_reg_dump();
200 
201 	return CMD_RET_SUCCESS;
202 }
203 
do_ufs_setlun(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])204 static int do_ufs_setlun(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
205 {
206 	u32 lun_num;
207 
208 	if (argc != 2) /* 2 arg */
209 		return CMD_RET_USAGE;
210 
211 	lun_num = simple_strtoul(argv[1], NULL, 16); /* arg 1: lun, 16 in hex */
212 	ufs_set_active_lun(lun_num);
213 
214 	return CMD_RET_SUCCESS;
215 }
216 
do_ufs_bootlun(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])217 static int do_ufs_bootlun(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
218 {
219 	u32 lun_num;
220 
221 	if (argc != 2) /* 2 arg */
222 		return CMD_RET_USAGE;
223 
224 	lun_num = simple_strtoul(argv[1], NULL, 16); /* arg 1: lun, 16 in hex */
225 	ufs_set_bootlun(lun_num);
226 
227 	return CMD_RET_SUCCESS;
228 }
229 
do_ufs_hi(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])230 static int do_ufs_hi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
231 {
232 	int ret;
233 
234 	if (argc != 2) /* 2 arg */
235 		return CMD_RET_USAGE;
236 
237 	ret = ufs_hibernate_enter();
238 	if (ret)
239 		return CMD_RET_FAILURE;
240 	printf("hibernate in ok\n");
241 	return CMD_RET_SUCCESS;
242 }
243 
do_ufs_ho(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])244 static int do_ufs_ho(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
245 {
246 	int ret;
247 
248 	if (argc != 2) /* 2 arg */
249 		return CMD_RET_USAGE;
250 
251 	ret = ufs_hibernate_exit();
252 	if (ret)
253 		return CMD_RET_FAILURE;
254 	printf("hibernate out ok\n");
255 	return CMD_RET_SUCCESS;
256 }
257 
do_ufs_mode(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])258 static int do_ufs_mode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
259 {
260 	struct pwr_mode_params pmp;
261 	uint32_t mode, gear, rate, lane;
262 
263 	if (argc != 5) /* 5 arg */
264 		return CMD_RET_USAGE;
265 
266 	mode = simple_strtoul(argv[1], NULL, 16); /* arg 1: mode, 16 in hex */
267 	gear = simple_strtoul(argv[2], NULL, 16); /* arg 2: gear, 16 in hex */
268 	rate = simple_strtoul(argv[3], NULL, 16); /* arg 3: rate, 16 in hex */
269 	lane = simple_strtoul(argv[4], NULL, 16); /* arg 4: lane, 16 in hex */
270 	mode = (mode << 4) | mode; /* rx shift 4 */
271 
272 	pmp.pwr_mode = mode;
273 	pmp.tx_gear = gear;
274 	pmp.rx_gear = gear;
275 	pmp.hs_series = rate;
276 	pmp.tx_lanes = lane;
277 	pmp.rx_lanes = lane;
278 
279 	printf("UFS %s Gear-%d Rate-%c Lane-%d\n",
280 		 ((mode == SLOW_MODE) ? "Slow" :
281 		 ((mode == SLOWAUTO_MODE) ? "SlowAuto" :
282 		 ((mode == FAST_MODE) ? "Fast" : "FastAuto"))),
283 		 gear, (rate == 1) ? 'A' : 'B', lane);
284 
285 	if (do_mode_change(&pmp)) {
286 		printf("power mode change fail\n");
287 		return CMD_RET_FAILURE;
288 	} else {
289 		printf("power mode change ok\n");
290 	}
291 	return CMD_RET_SUCCESS;
292 }
293 
294 static cmd_tbl_t cmd_ufs[] = {
295 	U_BOOT_CMD_MKENT(read, 5, 0, do_ufs_read, "", ""),
296 	U_BOOT_CMD_MKENT(write, 5, 0, do_ufs_write, "", ""),
297 	U_BOOT_CMD_MKENT(bootread, 5, 0, do_ufs_bootread, "", ""),
298 	U_BOOT_CMD_MKENT(bootwrite, 5, 0, do_ufs_bootwrite, "", ""),
299 	U_BOOT_CMD_MKENT(reinit, 2, 0, do_ufs_reinit, "", ""),
300 	U_BOOT_CMD_MKENT(reg, 2, 0, do_ufs_reg, "", ""),
301 	U_BOOT_CMD_MKENT(setlun, 2, 0, do_ufs_setlun, "", ""),
302 	U_BOOT_CMD_MKENT(bootlun, 2, 0, do_ufs_bootlun, "", ""),
303 	U_BOOT_CMD_MKENT(hi, 2, 0, do_ufs_hi, "", ""),
304 	U_BOOT_CMD_MKENT(ho, 2, 0, do_ufs_ho, "", ""),
305 	U_BOOT_CMD_MKENT(mode, 5, 0, do_ufs_mode, "", ""),
306 };
307 
do_ufsops(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])308 static int do_ufsops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
309 {
310 	cmd_tbl_t *cp = NULL;
311 
312 	if (argc == 1) {
313 		cmd_usage(cmdtp);
314 		return CMD_RET_SUCCESS;
315 	}
316 
317 	cp = find_cmd_tbl(argv[1], cmd_ufs, ARRAY_SIZE(cmd_ufs));
318 
319 	/* Drop the ufs command */
320 	argc--;
321 	argv++;
322 
323 	if (cp == NULL || argc > cp->maxargs)
324 		return CMD_RET_USAGE;
325 
326 	return cp->cmd(cmdtp, flag, argc, argv);
327 }
328 
329 U_BOOT_CMD(
330 	ufs, 6, 0, do_ufsops,
331 	"UFS sub system",
332 	"read <device num> addr blk# cnt\n"
333 	"ufs write <device num> addr blk# cnt\n"
334 	"ufs write.ext4sp <device num> addr blk# cnt\n"
335 	"ufs bootread <device num> addr blk# cnt\n"
336 	"ufs bootwrite <device num> addr blk# cnt\n"
337 	"ufs reinit <device num>\n"
338 	"ufs reg <device num>\n"
339 );
340 
do_ufsinfo(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])341 static int do_ufsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
342 {
343 	u32 type;
344 
345 	switch (argc) {
346 	case 0: /* 0 arg */
347 	case 1: /* 1 arg */
348 		ufs_show_desc_info(0xF);
349 		break;
350 	case 2: /* 2 arg */
351 		if (strncmp(argv[1], "-h", sizeof("-h")) == 0) {
352 			cmd_usage(cmdtp);
353 			break;
354 		}
355 
356 		type = simple_strtoul(argv[1], NULL, 16); /* arg 1: type, 16 in hex */
357 		ufs_show_desc_info(type);
358 		break;
359 	default:
360 		return CMD_RET_USAGE;
361 	}
362 
363 	return CMD_RET_SUCCESS;
364 }
365 
366 U_BOOT_CMD(
367 	ufsinfo, 2, 0, do_ufsinfo,
368 	"display UFS info",
369 	"<idn>\n"
370 	"    idn :0x0  -- device descriptor\n"
371 	"    idn :0x1  -- configuration descriptor\n"
372 	"    idn :0x2  -- unit descriptor\n"
373 	"    idn :0x4  -- interconnect descriptor\n"
374 	"    idn :0x5  -- string descriptor\n"
375 	"    idn :0x7  -- geometry descriptor\n"
376 	"    idn :0x9  -- health descriptor\n"
377 	"    idn :0xE  -- show all info\n"
378 	"    idn :0xF  -- show basic info\n"
379 );
380 #endif
381