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