Home | History | Annotate | Download | only in ufs
      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 	}
    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 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    564 void ufs_set_flag(int idn)
    565 {
    566 	ufs_query(QUERY_SET_FLAG, idn, 0, 0, 0, 0);
    567 }
    568 
    569 void ufs_clear_flag(int idn)
    570 {
    571 	ufs_query(QUERY_CLEAR_FLAG, idn, 0, 0, 0, 0);
    572 }
    573 
    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 
    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 
    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 
    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 
    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 
    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 
    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