xref: /rk3399_ARM-atf/drivers/ufs/ufs.c (revision 61f72a34250d063da67f4fc2b0eb8c3fda3376be)
1 /*
2  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <arch_helpers.h>
8 #include <assert.h>
9 #include <debug.h>
10 #include <delay_timer.h>
11 #include <endian.h>
12 #include <errno.h>
13 #include <mmio.h>
14 #include <platform_def.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <ufs.h>
18 
19 #define CDB_ADDR_MASK			127
20 #define ALIGN_CDB(x)			(((x) + CDB_ADDR_MASK) & ~CDB_ADDR_MASK)
21 #define ALIGN_8(x)			(((x) + 7) & ~7)
22 
23 #define UFS_DESC_SIZE			0x400
24 #define MAX_UFS_DESC_SIZE		0x8000		/* 32 descriptors */
25 
26 #define MAX_PRDT_SIZE			0x40000		/* 256KB */
27 
28 static ufs_params_t ufs_params;
29 static int nutrs;	/* Number of UTP Transfer Request Slots */
30 
31 int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd)
32 {
33 	unsigned int data;
34 
35 	data = mmio_read_32(base + HCS);
36 	if ((data & HCS_UCRDY) == 0)
37 		return -EBUSY;
38 	mmio_write_32(base + IS, ~0);
39 	mmio_write_32(base + UCMDARG1, cmd->arg1);
40 	mmio_write_32(base + UCMDARG2, cmd->arg2);
41 	mmio_write_32(base + UCMDARG3, cmd->arg3);
42 	mmio_write_32(base + UICCMD, cmd->op);
43 
44 	do {
45 		data = mmio_read_32(base + IS);
46 	} while ((data & UFS_INT_UCCS) == 0);
47 	mmio_write_32(base + IS, UFS_INT_UCCS);
48 	return mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
49 }
50 
51 int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
52 {
53 	uintptr_t base;
54 	unsigned int data;
55 	int retries;
56 
57 	assert((ufs_params.reg_base != 0) && (val != NULL));
58 
59 	base = ufs_params.reg_base;
60 	for (retries = 0; retries < 100; retries++) {
61 		data = mmio_read_32(base + HCS);
62 		if ((data & HCS_UCRDY) != 0)
63 			break;
64 		mdelay(1);
65 	}
66 	if (retries >= 100)
67 		return -EBUSY;
68 
69 	mmio_write_32(base + IS, ~0);
70 	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
71 	mmio_write_32(base + UCMDARG2, 0);
72 	mmio_write_32(base + UCMDARG3, 0);
73 	mmio_write_32(base + UICCMD, DME_GET);
74 	do {
75 		data = mmio_read_32(base + IS);
76 		if (data & UFS_INT_UE)
77 			return -EINVAL;
78 	} while ((data & UFS_INT_UCCS) == 0);
79 	mmio_write_32(base + IS, UFS_INT_UCCS);
80 	data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
81 	assert(data == 0);
82 
83 	*val = mmio_read_32(base + UCMDARG3);
84 	return 0;
85 }
86 
87 int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val)
88 {
89 	uintptr_t base;
90 	unsigned int data;
91 
92 	assert((ufs_params.reg_base != 0));
93 
94 	base = ufs_params.reg_base;
95 	data = mmio_read_32(base + HCS);
96 	if ((data & HCS_UCRDY) == 0)
97 		return -EBUSY;
98 	mmio_write_32(base + IS, ~0);
99 	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
100 	mmio_write_32(base + UCMDARG2, 0);
101 	mmio_write_32(base + UCMDARG3, val);
102 	mmio_write_32(base + UICCMD, DME_SET);
103 	do {
104 		data = mmio_read_32(base + IS);
105 		if (data & UFS_INT_UE)
106 			return -EINVAL;
107 	} while ((data & UFS_INT_UCCS) == 0);
108 	mmio_write_32(base + IS, UFS_INT_UCCS);
109 	data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
110 	assert(data == 0);
111 	return 0;
112 }
113 
114 static void ufshc_reset(uintptr_t base)
115 {
116 	unsigned int data;
117 
118 	/* Enable Host Controller */
119 	mmio_write_32(base + HCE, HCE_ENABLE);
120 	/* Wait until basic initialization sequence completed */
121 	do {
122 		data = mmio_read_32(base + HCE);
123 	} while ((data & HCE_ENABLE) == 0);
124 
125 	/* Enable Interrupts */
126 	data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES |
127 	       UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES;
128 	mmio_write_32(base + IE, data);
129 }
130 
131 static int ufshc_link_startup(uintptr_t base)
132 {
133 	uic_cmd_t cmd;
134 	int data, result;
135 	int retries;
136 
137 	for (retries = 10; retries > 0; retries--) {
138 		memset(&cmd, 0, sizeof(cmd));
139 		cmd.op = DME_LINKSTARTUP;
140 		result = ufshc_send_uic_cmd(base, &cmd);
141 		if (result != 0)
142 			continue;
143 		while ((mmio_read_32(base + HCS) & HCS_DP) == 0)
144 			;
145 		data = mmio_read_32(base + IS);
146 		if (data & UFS_INT_ULSS)
147 			mmio_write_32(base + IS, UFS_INT_ULSS);
148 		return 0;
149 	}
150 	return -EIO;
151 }
152 
153 /* Check Door Bell register to get an empty slot */
154 static int get_empty_slot(int *slot)
155 {
156 	unsigned int data;
157 	int i;
158 
159 	data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
160 	for (i = 0; i < nutrs; i++) {
161 		if ((data & 1) == 0)
162 			break;
163 		data = data >> 1;
164 	}
165 	if (i >= nutrs)
166 		return -EBUSY;
167 	*slot = i;
168 	return 0;
169 }
170 
171 static void get_utrd(utp_utrd_t *utrd)
172 {
173 	uintptr_t base;
174 	int slot = 0, result;
175 	utrd_header_t *hd;
176 
177 	assert(utrd != NULL);
178 	result = get_empty_slot(&slot);
179 	assert(result == 0);
180 
181 	/* clear utrd */
182 	memset((void *)utrd, 0, sizeof(utp_utrd_t));
183 	base = ufs_params.desc_base + (slot * UFS_DESC_SIZE);
184 	/* clear the descriptor */
185 	memset((void *)base, 0, UFS_DESC_SIZE);
186 
187 	utrd->header = base;
188 	utrd->task_tag = slot + 1;
189 	/* CDB address should be aligned with 128 bytes */
190 	utrd->upiu = ALIGN_CDB(utrd->header + sizeof(utrd_header_t));
191 	utrd->resp_upiu = ALIGN_8(utrd->upiu + sizeof(cmd_upiu_t));
192 	utrd->size_upiu = utrd->resp_upiu - utrd->upiu;
193 	utrd->size_resp_upiu = ALIGN_8(sizeof(resp_upiu_t));
194 	utrd->prdt = utrd->resp_upiu + utrd->size_resp_upiu;
195 
196 	hd = (utrd_header_t *)utrd->header;
197 	hd->ucdba = utrd->upiu & UINT32_MAX;
198 	hd->ucdbau = (utrd->upiu >> 32) & UINT32_MAX;
199 	/* Both RUL and RUO is based on DWORD */
200 	hd->rul = utrd->size_resp_upiu >> 2;
201 	hd->ruo = utrd->size_upiu >> 2;
202 	(void)result;
203 }
204 
205 /*
206  * Prepare UTRD, Command UPIU, Response UPIU.
207  */
208 static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
209 			   int lba, uintptr_t buf, size_t length)
210 {
211 	utrd_header_t *hd;
212 	cmd_upiu_t *upiu;
213 	prdt_t *prdt;
214 	unsigned int ulba;
215 	unsigned int lba_cnt;
216 	int prdt_size;
217 
218 
219 	mmio_write_32(ufs_params.reg_base + UTRLBA,
220 		      utrd->header & UINT32_MAX);
221 	mmio_write_32(ufs_params.reg_base + UTRLBAU,
222 		      (utrd->upiu >> 32) & UINT32_MAX);
223 
224 	hd = (utrd_header_t *)utrd->header;
225 	upiu = (cmd_upiu_t *)utrd->upiu;
226 
227 	hd->i = 1;
228 	hd->ct = CT_UFS_STORAGE;
229 	hd->ocs = OCS_MASK;
230 
231 	upiu->trans_type = CMD_UPIU;
232 	upiu->task_tag = utrd->task_tag;
233 	upiu->cdb[0] = op;
234 	ulba = (unsigned int)lba;
235 	lba_cnt = (unsigned int)(length >> UFS_BLOCK_SHIFT);
236 	switch (op) {
237 	case CDBCMD_TEST_UNIT_READY:
238 		break;
239 	case CDBCMD_READ_CAPACITY_10:
240 		hd->dd = DD_OUT;
241 		upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;
242 		upiu->lun = lun;
243 		break;
244 	case CDBCMD_READ_10:
245 		hd->dd = DD_OUT;
246 		upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;
247 		upiu->lun = lun;
248 		upiu->cdb[1] = RW_WITHOUT_CACHE;
249 		/* set logical block address */
250 		upiu->cdb[2] = (ulba >> 24) & 0xff;
251 		upiu->cdb[3] = (ulba >> 16) & 0xff;
252 		upiu->cdb[4] = (ulba >> 8) & 0xff;
253 		upiu->cdb[5] = ulba & 0xff;
254 		/* set transfer length */
255 		upiu->cdb[7] = (lba_cnt >> 8) & 0xff;
256 		upiu->cdb[8] = lba_cnt & 0xff;
257 		break;
258 	case CDBCMD_WRITE_10:
259 		hd->dd = DD_IN;
260 		upiu->flags = UPIU_FLAGS_W | UPIU_FLAGS_ATTR_S;
261 		upiu->lun = lun;
262 		upiu->cdb[1] = RW_WITHOUT_CACHE;
263 		/* set logical block address */
264 		upiu->cdb[2] = (ulba >> 24) & 0xff;
265 		upiu->cdb[3] = (ulba >> 16) & 0xff;
266 		upiu->cdb[4] = (ulba >> 8) & 0xff;
267 		upiu->cdb[5] = ulba & 0xff;
268 		/* set transfer length */
269 		upiu->cdb[7] = (lba_cnt >> 8) & 0xff;
270 		upiu->cdb[8] = lba_cnt & 0xff;
271 		break;
272 	default:
273 		assert(0);
274 		break;
275 	}
276 	if (hd->dd == DD_IN)
277 		flush_dcache_range(buf, length);
278 	else if (hd->dd == DD_OUT)
279 		inv_dcache_range(buf, length);
280 	if (length) {
281 		upiu->exp_data_trans_len = htobe32(length);
282 		assert(lba_cnt <= UINT16_MAX);
283 		prdt = (prdt_t *)utrd->prdt;
284 
285 		prdt_size = 0;
286 		while (length > 0) {
287 			prdt->dba = (unsigned int)(buf & UINT32_MAX);
288 			prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX);
289 			/* prdt->dbc counts from 0 */
290 			if (length > MAX_PRDT_SIZE) {
291 				prdt->dbc = MAX_PRDT_SIZE - 1;
292 				length = length - MAX_PRDT_SIZE;
293 			} else {
294 				prdt->dbc = length - 1;
295 				length = 0;
296 			}
297 			buf += MAX_PRDT_SIZE;
298 			prdt++;
299 			prdt_size += sizeof(prdt_t);
300 		}
301 		utrd->size_prdt = ALIGN_8(prdt_size);
302 		hd->prdtl = utrd->size_prdt >> 2;
303 		hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2;
304 	}
305 
306 	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
307 	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
308 	return 0;
309 }
310 
311 static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn,
312 			     uint8_t index, uint8_t sel,
313 			     uintptr_t buf, size_t length)
314 {
315 	utrd_header_t *hd;
316 	query_upiu_t *query_upiu;
317 
318 
319 	hd = (utrd_header_t *)utrd->header;
320 	query_upiu = (query_upiu_t *)utrd->upiu;
321 
322 	mmio_write_32(ufs_params.reg_base + UTRLBA,
323 		      utrd->header & UINT32_MAX);
324 	mmio_write_32(ufs_params.reg_base + UTRLBAU,
325 		      (utrd->header >> 32) & UINT32_MAX);
326 
327 
328 	hd->i = 1;
329 	hd->ct = CT_UFS_STORAGE;
330 	hd->ocs = OCS_MASK;
331 
332 	query_upiu->trans_type = QUERY_REQUEST_UPIU;
333 	query_upiu->task_tag = utrd->task_tag;
334 	query_upiu->ts.desc.opcode = op;
335 	query_upiu->ts.desc.idn = idn;
336 	query_upiu->ts.desc.index = index;
337 	query_upiu->ts.desc.selector = sel;
338 	switch (op) {
339 	case QUERY_READ_DESC:
340 		query_upiu->query_func = QUERY_FUNC_STD_READ;
341 		query_upiu->ts.desc.length = htobe16(length);
342 		break;
343 	case QUERY_WRITE_DESC:
344 		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
345 		query_upiu->ts.desc.length = htobe16(length);
346 		memcpy((void *)(utrd->upiu + sizeof(query_upiu_t)),
347 		       (void *)buf, length);
348 		break;
349 	case QUERY_READ_ATTR:
350 	case QUERY_READ_FLAG:
351 		query_upiu->query_func = QUERY_FUNC_STD_READ;
352 		break;
353 	case QUERY_CLEAR_FLAG:
354 	case QUERY_SET_FLAG:
355 		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
356 		break;
357 	case QUERY_WRITE_ATTR:
358 		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
359 		memcpy((void *)&query_upiu->ts.attr.value, (void *)buf, length);
360 		break;
361 	default:
362 		assert(0);
363 		break;
364 	}
365 	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
366 	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
367 	return 0;
368 }
369 
370 static void ufs_prepare_nop_out(utp_utrd_t *utrd)
371 {
372 	utrd_header_t *hd;
373 	nop_out_upiu_t *nop_out;
374 
375 	mmio_write_32(ufs_params.reg_base + UTRLBA,
376 		      utrd->header & UINT32_MAX);
377 	mmio_write_32(ufs_params.reg_base + UTRLBAU,
378 		      (utrd->header >> 32) & UINT32_MAX);
379 
380 	hd = (utrd_header_t *)utrd->header;
381 	nop_out = (nop_out_upiu_t *)utrd->upiu;
382 
383 	hd->i = 1;
384 	hd->ct = CT_UFS_STORAGE;
385 	hd->ocs = OCS_MASK;
386 
387 	nop_out->trans_type = 0;
388 	nop_out->task_tag = utrd->task_tag;
389 	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
390 	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
391 }
392 
393 static void ufs_send_request(int task_tag)
394 {
395 	unsigned int data;
396 	int slot;
397 
398 	slot = task_tag - 1;
399 	/* clear all interrupts */
400 	mmio_write_32(ufs_params.reg_base + IS, ~0);
401 
402 	mmio_write_32(ufs_params.reg_base + UTRLRSR, 1);
403 	do {
404 		data = mmio_read_32(ufs_params.reg_base + UTRLRSR);
405 	} while (data == 0);
406 
407 	data = UTRIACR_IAEN | UTRIACR_CTR | UTRIACR_IACTH(0x1F) |
408 	       UTRIACR_IATOVAL(0xFF);
409 	mmio_write_32(ufs_params.reg_base + UTRIACR, data);
410 	/* send request */
411 	mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot);
412 }
413 
414 static int ufs_check_resp(utp_utrd_t *utrd, int trans_type)
415 {
416 	utrd_header_t *hd;
417 	resp_upiu_t *resp;
418 	unsigned int data;
419 	int slot;
420 
421 	hd = (utrd_header_t *)utrd->header;
422 	resp = (resp_upiu_t *)utrd->resp_upiu;
423 	inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
424 	inv_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
425 	do {
426 		data = mmio_read_32(ufs_params.reg_base + IS);
427 		if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0)
428 			return -EIO;
429 	} while ((data & UFS_INT_UTRCS) == 0);
430 	slot = utrd->task_tag - 1;
431 
432 	data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
433 	assert((data & (1 << slot)) == 0);
434 	assert(hd->ocs == OCS_SUCCESS);
435 	assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);
436 	(void)resp;
437 	(void)slot;
438 	return 0;
439 }
440 
441 #ifdef UFS_RESP_DEBUG
442 static void dump_upiu(utp_utrd_t *utrd)
443 {
444 	utrd_header_t *hd;
445 	int i;
446 
447 	hd = (utrd_header_t *)utrd->header;
448 	INFO("utrd:0x%x, ruo:0x%x, rul:0x%x, ocs:0x%x, UTRLDBR:0x%x\n",
449 		(unsigned int)(uintptr_t)utrd, hd->ruo, hd->rul, hd->ocs,
450 		mmio_read_32(ufs_params.reg_base + UTRLDBR));
451 	for (i = 0; i < sizeof(utrd_header_t); i += 4) {
452 		INFO("[%lx]:0x%x\n",
453 			(uintptr_t)utrd->header + i,
454 			*(unsigned int *)((uintptr_t)utrd->header + i));
455 	}
456 
457 	for (i = 0; i < sizeof(cmd_upiu_t); i += 4) {
458 		INFO("cmd[%lx]:0x%x\n",
459 			utrd->upiu + i,
460 			*(unsigned int *)(utrd->upiu + i));
461 	}
462 	for (i = 0; i < sizeof(resp_upiu_t); i += 4) {
463 		INFO("resp[%lx]:0x%x\n",
464 			utrd->resp_upiu + i,
465 			*(unsigned int *)(utrd->resp_upiu + i));
466 	}
467 	for (i = 0; i < sizeof(prdt_t); i += 4) {
468 		INFO("prdt[%lx]:0x%x\n",
469 			utrd->prdt + i,
470 			*(unsigned int *)(utrd->prdt + i));
471 	}
472 }
473 #endif
474 
475 static void ufs_verify_init(void)
476 {
477 	utp_utrd_t utrd;
478 	int result;
479 
480 	get_utrd(&utrd);
481 	ufs_prepare_nop_out(&utrd);
482 	ufs_send_request(utrd.task_tag);
483 	result = ufs_check_resp(&utrd, NOP_IN_UPIU);
484 	assert(result == 0);
485 	(void)result;
486 }
487 
488 static void ufs_verify_ready(void)
489 {
490 	utp_utrd_t utrd;
491 	int result;
492 
493 	get_utrd(&utrd);
494 	ufs_prepare_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0);
495 	ufs_send_request(utrd.task_tag);
496 	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
497 	assert(result == 0);
498 	(void)result;
499 }
500 
501 static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
502 		      uintptr_t buf, size_t size)
503 {
504 	utp_utrd_t utrd;
505 	query_resp_upiu_t *resp;
506 	int result;
507 
508 	switch (op) {
509 	case QUERY_READ_FLAG:
510 	case QUERY_READ_ATTR:
511 	case QUERY_READ_DESC:
512 	case QUERY_WRITE_DESC:
513 	case QUERY_WRITE_ATTR:
514 		assert(((buf & 3) == 0) && (size != 0));
515 		break;
516 	default:
517 		/* Do nothing in default case */
518 		break;
519 	}
520 	get_utrd(&utrd);
521 	ufs_prepare_query(&utrd, op, idn, index, sel, buf, size);
522 	ufs_send_request(utrd.task_tag);
523 	result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU);
524 	assert(result == 0);
525 	resp = (query_resp_upiu_t *)utrd.resp_upiu;
526 #ifdef UFS_RESP_DEBUG
527 	dump_upiu(&utrd);
528 #endif
529 	assert(resp->query_resp == QUERY_RESP_SUCCESS);
530 
531 	switch (op) {
532 	case QUERY_READ_FLAG:
533 		*(uint32_t *)buf = (uint32_t)resp->ts.flag.value;
534 		break;
535 	case QUERY_READ_ATTR:
536 	case QUERY_READ_DESC:
537 		memcpy((void *)buf,
538 		       (void *)(utrd.resp_upiu + sizeof(query_resp_upiu_t)),
539 		       size);
540 		break;
541 	default:
542 		/* Do nothing in default case */
543 		break;
544 	}
545 	(void)result;
546 }
547 
548 unsigned int ufs_read_attr(int idn)
549 {
550 	unsigned int value;
551 
552 	ufs_query(QUERY_READ_ATTR, idn, 0, 0,
553 		  (uintptr_t)&value, sizeof(value));
554 	return value;
555 }
556 
557 void ufs_write_attr(int idn, unsigned int value)
558 {
559 	ufs_query(QUERY_WRITE_ATTR, idn, 0, 0,
560 		  (uintptr_t)&value, sizeof(value));
561 }
562 
563 unsigned int ufs_read_flag(int idn)
564 {
565 	unsigned int value;
566 
567 	ufs_query(QUERY_READ_FLAG, idn, 0, 0,
568 		  (uintptr_t)&value, sizeof(value));
569 	return value;
570 }
571 
572 void ufs_set_flag(int idn)
573 {
574 	ufs_query(QUERY_SET_FLAG, idn, 0, 0, 0, 0);
575 }
576 
577 void ufs_clear_flag(int idn)
578 {
579 	ufs_query(QUERY_CLEAR_FLAG, idn, 0, 0, 0, 0);
580 }
581 
582 void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size)
583 {
584 	ufs_query(QUERY_READ_DESC, idn, index, 0, buf, size);
585 }
586 
587 void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size)
588 {
589 	ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size);
590 }
591 
592 void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
593 {
594 	utp_utrd_t utrd;
595 	resp_upiu_t *resp;
596 	sense_data_t *sense;
597 	unsigned char data[CACHE_WRITEBACK_GRANULE << 1];
598 	uintptr_t buf;
599 	int result;
600 	int retry;
601 
602 	assert((ufs_params.reg_base != 0) &&
603 	       (ufs_params.desc_base != 0) &&
604 	       (ufs_params.desc_size >= UFS_DESC_SIZE) &&
605 	       (num != NULL) && (size != NULL));
606 
607 	/* align buf address */
608 	buf = (uintptr_t)data;
609 	buf = (buf + CACHE_WRITEBACK_GRANULE - 1) &
610 	      ~(CACHE_WRITEBACK_GRANULE - 1);
611 	memset((void *)buf, 0, CACHE_WRITEBACK_GRANULE);
612 	flush_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
613 	do {
614 		get_utrd(&utrd);
615 		ufs_prepare_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0,
616 				buf, READ_CAPACITY_LENGTH);
617 		ufs_send_request(utrd.task_tag);
618 		result = ufs_check_resp(&utrd, RESPONSE_UPIU);
619 		assert(result == 0);
620 #ifdef UFS_RESP_DEBUG
621 		dump_upiu(&utrd);
622 #endif
623 		resp = (resp_upiu_t *)utrd.resp_upiu;
624 		retry = 0;
625 		sense = &resp->sd.sense;
626 		if (sense->resp_code == SENSE_DATA_VALID) {
627 			if ((sense->sense_key == SENSE_KEY_UNIT_ATTENTION) &&
628 			    (sense->asc == 0x29) && (sense->ascq == 0)) {
629 				retry = 1;
630 			}
631 		}
632 		inv_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
633 		/* last logical block address */
634 		*num = be32toh(*(unsigned int *)buf);
635 		if (*num)
636 			*num += 1;
637 		/* logical block length in bytes */
638 		*size = be32toh(*(unsigned int *)(buf + 4));
639 	} while (retry);
640 	(void)result;
641 }
642 
643 size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size)
644 {
645 	utp_utrd_t utrd;
646 	resp_upiu_t *resp;
647 	int result;
648 
649 	assert((ufs_params.reg_base != 0) &&
650 	       (ufs_params.desc_base != 0) &&
651 	       (ufs_params.desc_size >= UFS_DESC_SIZE));
652 
653 	memset((void *)buf, 0, size);
654 	get_utrd(&utrd);
655 	ufs_prepare_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
656 	ufs_send_request(utrd.task_tag);
657 	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
658 	assert(result == 0);
659 #ifdef UFS_RESP_DEBUG
660 	dump_upiu(&utrd);
661 #endif
662 	resp = (resp_upiu_t *)utrd.resp_upiu;
663 	(void)result;
664 	return size - resp->res_trans_cnt;
665 }
666 
667 size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size)
668 {
669 	utp_utrd_t utrd;
670 	resp_upiu_t *resp;
671 	int result;
672 
673 	assert((ufs_params.reg_base != 0) &&
674 	       (ufs_params.desc_base != 0) &&
675 	       (ufs_params.desc_size >= UFS_DESC_SIZE));
676 
677 	memset((void *)buf, 0, size);
678 	get_utrd(&utrd);
679 	ufs_prepare_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
680 	ufs_send_request(utrd.task_tag);
681 	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
682 	assert(result == 0);
683 #ifdef UFS_RESP_DEBUG
684 	dump_upiu(&utrd);
685 #endif
686 	resp = (resp_upiu_t *)utrd.resp_upiu;
687 	(void)result;
688 	return size - resp->res_trans_cnt;
689 }
690 
691 static void ufs_enum(void)
692 {
693 	unsigned int blk_num, blk_size;
694 	int i;
695 
696 	/* 0 means 1 slot */
697 	nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;
698 	if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE))
699 		nutrs = ufs_params.desc_size / UFS_DESC_SIZE;
700 
701 	ufs_verify_init();
702 	ufs_verify_ready();
703 
704 	ufs_set_flag(FLAG_DEVICE_INIT);
705 	mdelay(100);
706 	/* dump available LUNs */
707 	for (i = 0; i < UFS_MAX_LUNS; i++) {
708 		ufs_read_capacity(i, &blk_num, &blk_size);
709 		if (blk_num && blk_size) {
710 			INFO("UFS LUN%d contains %d blocks with %d-byte size\n",
711 			     i, blk_num, blk_size);
712 		}
713 	}
714 }
715 
716 static void ufs_get_device_info(struct ufs_dev_desc *card_data)
717 {
718 	uint8_t desc_buf[DESC_DEVICE_MAX_SIZE];
719 
720 	ufs_query(QUERY_READ_DESC, DESC_TYPE_DEVICE, 0, 0,
721 				(uintptr_t)desc_buf, DESC_DEVICE_MAX_SIZE);
722 
723 	/*
724 	 * getting vendor (manufacturerID) and Bank Index in big endian
725 	 * format
726 	 */
727 	card_data->wmanufacturerid = (uint16_t)((desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8) |
728 				     (desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]));
729 }
730 
731 int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
732 {
733 	int result;
734 	unsigned int data;
735 	uic_cmd_t cmd;
736 	struct ufs_dev_desc card = {0};
737 
738 	assert((params != NULL) &&
739 	       (params->reg_base != 0) &&
740 	       (params->desc_base != 0) &&
741 	       (params->desc_size >= UFS_DESC_SIZE));
742 
743 	memcpy(&ufs_params, params, sizeof(ufs_params_t));
744 
745 	if (ufs_params.flags & UFS_FLAGS_SKIPINIT) {
746 		result = ufshc_dme_get(0x1571, 0, &data);
747 		assert(result == 0);
748 		result = ufshc_dme_get(0x41, 0, &data);
749 		assert(result == 0);
750 		if (data == 1) {
751 			/* prepare to exit hibernate mode */
752 			memset(&cmd, 0, sizeof(uic_cmd_t));
753 			cmd.op = DME_HIBERNATE_EXIT;
754 			result = ufshc_send_uic_cmd(ufs_params.reg_base,
755 						    &cmd);
756 			assert(result == 0);
757 			data = mmio_read_32(ufs_params.reg_base + UCMDARG2);
758 			assert(data == 0);
759 			do {
760 				data = mmio_read_32(ufs_params.reg_base + IS);
761 			} while ((data & UFS_INT_UHXS) == 0);
762 			mmio_write_32(ufs_params.reg_base + IS, UFS_INT_UHXS);
763 			data = mmio_read_32(ufs_params.reg_base + HCS);
764 			assert((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL);
765 		}
766 		result = ufshc_dme_get(0x1568, 0, &data);
767 		assert(result == 0);
768 		assert((data > 0) && (data <= 3));
769 	} else {
770 		assert((ops != NULL) && (ops->phy_init != NULL) &&
771 		       (ops->phy_set_pwr_mode != NULL));
772 
773 		ufshc_reset(ufs_params.reg_base);
774 		ops->phy_init(&ufs_params);
775 		result = ufshc_link_startup(ufs_params.reg_base);
776 		assert(result == 0);
777 
778 		ufs_enum();
779 
780 		ufs_get_device_info(&card);
781 		if (card.wmanufacturerid == UFS_VENDOR_SKHYNIX) {
782 			ufs_params.flags |= UFS_FLAGS_VENDOR_SKHYNIX;
783 		}
784 
785 		ops->phy_set_pwr_mode(&ufs_params);
786 	}
787 
788 	(void)result;
789 	return 0;
790 }
791