• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ufshc_send_uic_cmd(uintptr_t base,uic_cmd_t * cmd)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 
ufshc_dme_get(unsigned int attr,unsigned int idx,unsigned int * val)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 
ufshc_dme_set(unsigned int attr,unsigned int idx,unsigned int val)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 
ufshc_reset(uintptr_t base)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 
ufshc_link_startup(uintptr_t base)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 */
get_empty_slot(int * 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 
get_utrd(utp_utrd_t * utrd)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  */
ufs_prepare_cmd(utp_utrd_t * utrd,uint8_t op,uint8_t lun,int lba,uintptr_t buf,size_t length)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 	}
275 	if (hd->dd == DD_IN)
276 		flush_dcache_range(buf, length);
277 	else if (hd->dd == DD_OUT)
278 		inv_dcache_range(buf, length);
279 	if (length) {
280 		upiu->exp_data_trans_len = htobe32(length);
281 		assert(lba_cnt <= UINT16_MAX);
282 		prdt = (prdt_t *)utrd->prdt;
283 
284 		prdt_size = 0;
285 		while (length > 0) {
286 			prdt->dba = (unsigned int)(buf & UINT32_MAX);
287 			prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX);
288 			/* prdt->dbc counts from 0 */
289 			if (length > MAX_PRDT_SIZE) {
290 				prdt->dbc = MAX_PRDT_SIZE - 1;
291 				length = length - MAX_PRDT_SIZE;
292 			} else {
293 				prdt->dbc = length - 1;
294 				length = 0;
295 			}
296 			buf += MAX_PRDT_SIZE;
297 			prdt++;
298 			prdt_size += sizeof(prdt_t);
299 		}
300 		utrd->size_prdt = ALIGN_8(prdt_size);
301 		hd->prdtl = utrd->size_prdt >> 2;
302 		hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2;
303 	}
304 
305 	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
306 	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
307 	return 0;
308 }
309 
ufs_prepare_query(utp_utrd_t * utrd,uint8_t op,uint8_t idn,uint8_t index,uint8_t sel,uintptr_t buf,size_t length)310 static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn,
311 			     uint8_t index, uint8_t sel,
312 			     uintptr_t buf, size_t length)
313 {
314 	utrd_header_t *hd;
315 	query_upiu_t *query_upiu;
316 
317 
318 	hd = (utrd_header_t *)utrd->header;
319 	query_upiu = (query_upiu_t *)utrd->upiu;
320 
321 	mmio_write_32(ufs_params.reg_base + UTRLBA,
322 		      utrd->header & UINT32_MAX);
323 	mmio_write_32(ufs_params.reg_base + UTRLBAU,
324 		      (utrd->header >> 32) & UINT32_MAX);
325 
326 
327 	hd->i = 1;
328 	hd->ct = CT_UFS_STORAGE;
329 	hd->ocs = OCS_MASK;
330 
331 	query_upiu->trans_type = QUERY_REQUEST_UPIU;
332 	query_upiu->task_tag = utrd->task_tag;
333 	query_upiu->ts.desc.opcode = op;
334 	query_upiu->ts.desc.idn = idn;
335 	query_upiu->ts.desc.index = index;
336 	query_upiu->ts.desc.selector = sel;
337 	switch (op) {
338 	case QUERY_READ_DESC:
339 		query_upiu->query_func = QUERY_FUNC_STD_READ;
340 		query_upiu->ts.desc.length = htobe16(length);
341 		break;
342 	case QUERY_WRITE_DESC:
343 		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
344 		query_upiu->ts.desc.length = htobe16(length);
345 		memcpy((void *)(utrd->upiu + sizeof(query_upiu_t)),
346 		       (void *)buf, length);
347 		break;
348 	case QUERY_READ_ATTR:
349 	case QUERY_READ_FLAG:
350 		query_upiu->query_func = QUERY_FUNC_STD_READ;
351 		break;
352 	case QUERY_CLEAR_FLAG:
353 	case QUERY_SET_FLAG:
354 		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
355 		break;
356 	case QUERY_WRITE_ATTR:
357 		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
358 		memcpy((void *)&query_upiu->ts.attr.value, (void *)buf, length);
359 		break;
360 	default:
361 		assert(0);
362 	}
363 	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
364 	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
365 	return 0;
366 }
367 
ufs_prepare_nop_out(utp_utrd_t * utrd)368 static void ufs_prepare_nop_out(utp_utrd_t *utrd)
369 {
370 	utrd_header_t *hd;
371 	nop_out_upiu_t *nop_out;
372 
373 	mmio_write_32(ufs_params.reg_base + UTRLBA,
374 		      utrd->header & UINT32_MAX);
375 	mmio_write_32(ufs_params.reg_base + UTRLBAU,
376 		      (utrd->header >> 32) & UINT32_MAX);
377 
378 	hd = (utrd_header_t *)utrd->header;
379 	nop_out = (nop_out_upiu_t *)utrd->upiu;
380 
381 	hd->i = 1;
382 	hd->ct = CT_UFS_STORAGE;
383 	hd->ocs = OCS_MASK;
384 
385 	nop_out->trans_type = 0;
386 	nop_out->task_tag = utrd->task_tag;
387 	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
388 	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
389 }
390 
ufs_send_request(int task_tag)391 static void ufs_send_request(int task_tag)
392 {
393 	unsigned int data;
394 	int slot;
395 
396 	slot = task_tag - 1;
397 	/* clear all interrupts */
398 	mmio_write_32(ufs_params.reg_base + IS, ~0);
399 
400 	mmio_write_32(ufs_params.reg_base + UTRLRSR, 1);
401 	do {
402 		data = mmio_read_32(ufs_params.reg_base + UTRLRSR);
403 	} while (data == 0);
404 
405 	data = UTRIACR_IAEN | UTRIACR_CTR | UTRIACR_IACTH(0x1F) |
406 	       UTRIACR_IATOVAL(0xFF);
407 	mmio_write_32(ufs_params.reg_base + UTRIACR, data);
408 	/* send request */
409 	mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot);
410 }
411 
ufs_check_resp(utp_utrd_t * utrd,int trans_type)412 static int ufs_check_resp(utp_utrd_t *utrd, int trans_type)
413 {
414 	utrd_header_t *hd;
415 	resp_upiu_t *resp;
416 	unsigned int data;
417 	int slot;
418 
419 	hd = (utrd_header_t *)utrd->header;
420 	resp = (resp_upiu_t *)utrd->resp_upiu;
421 	inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
422 	inv_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
423 	do {
424 		data = mmio_read_32(ufs_params.reg_base + IS);
425 		if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0)
426 			return -EIO;
427 	} while ((data & UFS_INT_UTRCS) == 0);
428 	slot = utrd->task_tag - 1;
429 
430 	data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
431 	assert((data & (1 << slot)) == 0);
432 	assert(hd->ocs == OCS_SUCCESS);
433 	assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);
434 	(void)resp;
435 	(void)slot;
436 	return 0;
437 }
438 
439 #ifdef UFS_RESP_DEBUG
dump_upiu(utp_utrd_t * utrd)440 static void dump_upiu(utp_utrd_t *utrd)
441 {
442 	utrd_header_t *hd;
443 	int i;
444 
445 	hd = (utrd_header_t *)utrd->header;
446 	INFO("utrd:0x%x, ruo:0x%x, rul:0x%x, ocs:0x%x, UTRLDBR:0x%x\n",
447 		(unsigned int)(uintptr_t)utrd, hd->ruo, hd->rul, hd->ocs,
448 		mmio_read_32(ufs_params.reg_base + UTRLDBR));
449 	for (i = 0; i < sizeof(utrd_header_t); i += 4) {
450 		INFO("[%lx]:0x%x\n",
451 			(uintptr_t)utrd->header + i,
452 			*(unsigned int *)((uintptr_t)utrd->header + i));
453 	}
454 
455 	for (i = 0; i < sizeof(cmd_upiu_t); i += 4) {
456 		INFO("cmd[%lx]:0x%x\n",
457 			utrd->upiu + i,
458 			*(unsigned int *)(utrd->upiu + i));
459 	}
460 	for (i = 0; i < sizeof(resp_upiu_t); i += 4) {
461 		INFO("resp[%lx]:0x%x\n",
462 			utrd->resp_upiu + i,
463 			*(unsigned int *)(utrd->resp_upiu + i));
464 	}
465 	for (i = 0; i < sizeof(prdt_t); i += 4) {
466 		INFO("prdt[%lx]:0x%x\n",
467 			utrd->prdt + i,
468 			*(unsigned int *)(utrd->prdt + i));
469 	}
470 }
471 #endif
472 
ufs_verify_init(void)473 static void ufs_verify_init(void)
474 {
475 	utp_utrd_t utrd;
476 	int result;
477 
478 	get_utrd(&utrd);
479 	ufs_prepare_nop_out(&utrd);
480 	ufs_send_request(utrd.task_tag);
481 	result = ufs_check_resp(&utrd, NOP_IN_UPIU);
482 	assert(result == 0);
483 	(void)result;
484 }
485 
ufs_verify_ready(void)486 static void ufs_verify_ready(void)
487 {
488 	utp_utrd_t utrd;
489 	int result;
490 
491 	get_utrd(&utrd);
492 	ufs_prepare_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0);
493 	ufs_send_request(utrd.task_tag);
494 	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
495 	assert(result == 0);
496 	(void)result;
497 }
498 
ufs_query(uint8_t op,uint8_t idn,uint8_t index,uint8_t sel,uintptr_t buf,size_t size)499 static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
500 		      uintptr_t buf, size_t size)
501 {
502 	utp_utrd_t utrd;
503 	query_resp_upiu_t *resp;
504 	int result;
505 
506 	switch (op) {
507 	case QUERY_READ_FLAG:
508 	case QUERY_READ_ATTR:
509 	case QUERY_READ_DESC:
510 	case QUERY_WRITE_DESC:
511 	case QUERY_WRITE_ATTR:
512 		assert(((buf & 3) == 0) && (size != 0));
513 		break;
514 	}
515 	get_utrd(&utrd);
516 	ufs_prepare_query(&utrd, op, idn, index, sel, buf, size);
517 	ufs_send_request(utrd.task_tag);
518 	result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU);
519 	assert(result == 0);
520 	resp = (query_resp_upiu_t *)utrd.resp_upiu;
521 #ifdef UFS_RESP_DEBUG
522 	dump_upiu(&utrd);
523 #endif
524 	assert(resp->query_resp == QUERY_RESP_SUCCESS);
525 
526 	switch (op) {
527 	case QUERY_READ_FLAG:
528 		*(uint32_t *)buf = (uint32_t)resp->ts.flag.value;
529 		break;
530 	case QUERY_READ_ATTR:
531 	case QUERY_READ_DESC:
532 		memcpy((void *)buf,
533 		       (void *)(utrd.resp_upiu + sizeof(query_resp_upiu_t)),
534 		       size);
535 		break;
536 	}
537 	(void)result;
538 }
539 
ufs_read_attr(int idn)540 unsigned int ufs_read_attr(int idn)
541 {
542 	unsigned int value;
543 
544 	ufs_query(QUERY_READ_ATTR, idn, 0, 0,
545 		  (uintptr_t)&value, sizeof(value));
546 	return value;
547 }
548 
ufs_write_attr(int idn,unsigned int value)549 void ufs_write_attr(int idn, unsigned int value)
550 {
551 	ufs_query(QUERY_WRITE_ATTR, idn, 0, 0,
552 		  (uintptr_t)&value, sizeof(value));
553 }
554 
ufs_read_flag(int idn)555 unsigned int ufs_read_flag(int idn)
556 {
557 	unsigned int value;
558 
559 	ufs_query(QUERY_READ_FLAG, idn, 0, 0,
560 		  (uintptr_t)&value, sizeof(value));
561 	return value;
562 }
563 
ufs_set_flag(int idn)564 void ufs_set_flag(int idn)
565 {
566 	ufs_query(QUERY_SET_FLAG, idn, 0, 0, 0, 0);
567 }
568 
ufs_clear_flag(int idn)569 void ufs_clear_flag(int idn)
570 {
571 	ufs_query(QUERY_CLEAR_FLAG, idn, 0, 0, 0, 0);
572 }
573 
ufs_read_desc(int idn,int index,uintptr_t buf,size_t size)574 void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size)
575 {
576 	ufs_query(QUERY_READ_DESC, idn, index, 0, buf, size);
577 }
578 
ufs_write_desc(int idn,int index,uintptr_t buf,size_t size)579 void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size)
580 {
581 	ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size);
582 }
583 
ufs_read_capacity(int lun,unsigned int * num,unsigned int * size)584 void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
585 {
586 	utp_utrd_t utrd;
587 	resp_upiu_t *resp;
588 	sense_data_t *sense;
589 	unsigned char data[CACHE_WRITEBACK_GRANULE << 1];
590 	uintptr_t buf;
591 	int result;
592 	int retry;
593 
594 	assert((ufs_params.reg_base != 0) &&
595 	       (ufs_params.desc_base != 0) &&
596 	       (ufs_params.desc_size >= UFS_DESC_SIZE) &&
597 	       (num != NULL) && (size != NULL));
598 
599 	/* align buf address */
600 	buf = (uintptr_t)data;
601 	buf = (buf + CACHE_WRITEBACK_GRANULE - 1) &
602 	      ~(CACHE_WRITEBACK_GRANULE - 1);
603 	memset((void *)buf, 0, CACHE_WRITEBACK_GRANULE);
604 	flush_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
605 	do {
606 		get_utrd(&utrd);
607 		ufs_prepare_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0,
608 				buf, READ_CAPACITY_LENGTH);
609 		ufs_send_request(utrd.task_tag);
610 		result = ufs_check_resp(&utrd, RESPONSE_UPIU);
611 		assert(result == 0);
612 #ifdef UFS_RESP_DEBUG
613 		dump_upiu(&utrd);
614 #endif
615 		resp = (resp_upiu_t *)utrd.resp_upiu;
616 		retry = 0;
617 		sense = &resp->sd.sense;
618 		if (sense->resp_code == SENSE_DATA_VALID) {
619 			if ((sense->sense_key == SENSE_KEY_UNIT_ATTENTION) &&
620 			    (sense->asc == 0x29) && (sense->ascq == 0)) {
621 				retry = 1;
622 			}
623 		}
624 		inv_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
625 		/* last logical block address */
626 		*num = be32toh(*(unsigned int *)buf);
627 		if (*num)
628 			*num += 1;
629 		/* logical block length in bytes */
630 		*size = be32toh(*(unsigned int *)(buf + 4));
631 	} while (retry);
632 	(void)result;
633 }
634 
ufs_read_blocks(int lun,int lba,uintptr_t buf,size_t size)635 size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size)
636 {
637 	utp_utrd_t utrd;
638 	resp_upiu_t *resp;
639 	int result;
640 
641 	assert((ufs_params.reg_base != 0) &&
642 	       (ufs_params.desc_base != 0) &&
643 	       (ufs_params.desc_size >= UFS_DESC_SIZE));
644 
645 	memset((void *)buf, 0, size);
646 	get_utrd(&utrd);
647 	ufs_prepare_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
648 	ufs_send_request(utrd.task_tag);
649 	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
650 	assert(result == 0);
651 #ifdef UFS_RESP_DEBUG
652 	dump_upiu(&utrd);
653 #endif
654 	resp = (resp_upiu_t *)utrd.resp_upiu;
655 	(void)result;
656 	return size - resp->res_trans_cnt;
657 }
658 
ufs_write_blocks(int lun,int lba,const uintptr_t buf,size_t size)659 size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size)
660 {
661 	utp_utrd_t utrd;
662 	resp_upiu_t *resp;
663 	int result;
664 
665 	assert((ufs_params.reg_base != 0) &&
666 	       (ufs_params.desc_base != 0) &&
667 	       (ufs_params.desc_size >= UFS_DESC_SIZE));
668 
669 	memset((void *)buf, 0, size);
670 	get_utrd(&utrd);
671 	ufs_prepare_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
672 	ufs_send_request(utrd.task_tag);
673 	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
674 	assert(result == 0);
675 #ifdef UFS_RESP_DEBUG
676 	dump_upiu(&utrd);
677 #endif
678 	resp = (resp_upiu_t *)utrd.resp_upiu;
679 	(void)result;
680 	return size - resp->res_trans_cnt;
681 }
682 
ufs_enum(void)683 static void ufs_enum(void)
684 {
685 	unsigned int blk_num, blk_size;
686 	int i;
687 
688 	/* 0 means 1 slot */
689 	nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;
690 	if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE))
691 		nutrs = ufs_params.desc_size / UFS_DESC_SIZE;
692 
693 	ufs_verify_init();
694 	ufs_verify_ready();
695 
696 	ufs_set_flag(FLAG_DEVICE_INIT);
697 	mdelay(100);
698 	/* dump available LUNs */
699 	for (i = 0; i < UFS_MAX_LUNS; i++) {
700 		ufs_read_capacity(i, &blk_num, &blk_size);
701 		if (blk_num && blk_size) {
702 			INFO("UFS LUN%d contains %d blocks with %d-byte size\n",
703 			     i, blk_num, blk_size);
704 		}
705 	}
706 }
707 
ufs_init(const ufs_ops_t * ops,ufs_params_t * params)708 int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
709 {
710 	int result;
711 	unsigned int data;
712 	uic_cmd_t cmd;
713 
714 	assert((params != NULL) &&
715 	       (params->reg_base != 0) &&
716 	       (params->desc_base != 0) &&
717 	       (params->desc_size >= UFS_DESC_SIZE));
718 
719 	memcpy(&ufs_params, params, sizeof(ufs_params_t));
720 
721 	if (ufs_params.flags & UFS_FLAGS_SKIPINIT) {
722 		result = ufshc_dme_get(0x1571, 0, &data);
723 		assert(result == 0);
724 		result = ufshc_dme_get(0x41, 0, &data);
725 		assert(result == 0);
726 		if (data == 1) {
727 			/* prepare to exit hibernate mode */
728 			memset(&cmd, 0, sizeof(uic_cmd_t));
729 			cmd.op = DME_HIBERNATE_EXIT;
730 			result = ufshc_send_uic_cmd(ufs_params.reg_base,
731 						    &cmd);
732 			assert(result == 0);
733 			data = mmio_read_32(ufs_params.reg_base + UCMDARG2);
734 			assert(data == 0);
735 			do {
736 				data = mmio_read_32(ufs_params.reg_base + IS);
737 			} while ((data & UFS_INT_UHXS) == 0);
738 			mmio_write_32(ufs_params.reg_base + IS, UFS_INT_UHXS);
739 			data = mmio_read_32(ufs_params.reg_base + HCS);
740 			assert((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL);
741 		}
742 		result = ufshc_dme_get(0x1568, 0, &data);
743 		assert(result == 0);
744 		assert((data > 0) && (data <= 3));
745 	} else {
746 		assert((ops != NULL) && (ops->phy_init != NULL) &&
747 		       (ops->phy_set_pwr_mode != NULL));
748 
749 		ufshc_reset(ufs_params.reg_base);
750 		ops->phy_init(&ufs_params);
751 		result = ufshc_link_startup(ufs_params.reg_base);
752 		assert(result == 0);
753 		ops->phy_set_pwr_mode(&ufs_params);
754 	}
755 
756 	ufs_enum();
757 	(void)result;
758 	return 0;
759 }
760