1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #include <config.h>
20 #include <asm/io.h>
21
22 uint64_t ufsboot_static_space_address = 0;
23
24 #include "ufs.h"
25 #include "scsi.c"
26
send_uic_command(uint32_t command,uint32_t arg1,uint32_t arg2,uint32_t arg3)27 static int send_uic_command(uint32_t command, uint32_t arg1, uint32_t arg2, uint32_t arg3)
28 {
29 int retry = 10;
30 unsigned int tick;
31 uint32_t reg = 0;
32 unsigned int tick_ready;
33
34 tick_ready = current_time();
35 for (;;) {
36 if (dwc_ufs_read_reg(UFS_HCS_OFF) & UFS_HCS_UCRDY_BIT) {
37 break;
38 }
39 if (time_passed_ms(tick_ready) > UFS_HC_WAIT_UCRDY_TIMEOUT_MS) {
40 break;
41 }
42 }
43
44 do {
45 //debug_printf("send_uic_command: cmd = 0x%x, arg1 = 0x%x, retry = %d\n", command, arg1, retry);
46 dwc_ufs_write_reg(UFS_IS_OFF, 0xFFFFFFFF);
47 dwc_ufs_write_reg(UFS_UICCMDARG1_OFF, arg1);
48 dwc_ufs_write_reg(UFS_UICCMDARG2_OFF, arg2);
49 dwc_ufs_write_reg(UFS_UICCMDARG3_OFF, arg3);
50
51 dwc_ufs_write_reg(UFS_UICCMD_OFF, (command & 0xFF));
52
53 tick = current_time();
54 for (;;) {
55 if (dwc_ufs_read_reg(UFS_IS_OFF) & UFS_IS_UCCS_BIT) {
56 reg = dwc_ufs_read_reg(UFS_UICCMDARG2_OFF) & UFS_UICCMDARG2_RET_MASK;
57 if (!reg) {
58 dwc_ufs_write_reg(UFS_IS_OFF, 0xFFFFFFFF);
59 return UFS_SUCCESS;
60 } else {
61 debug_printf("send_uic_command: get error resp, resp = 0x%x\n", reg);
62 ufs_waitms(1);
63 break;
64 }
65 }
66
67 if (time_passed_ms(tick) > UFS_SEND_UIC_CMD_TIMEOUT_MS) {
68 debug_printf("send_uic_command: wait UCCS int timeout\n");
69 break;
70 }
71 }
72 } while (--retry > 0);
73
74 dwc_ufs_write_reg(UFS_IS_OFF, 0xFFFFFFFF);
75 debug_printf("send_uic_command: return error, ret = -0x%x\n", ((reg & 0xf) + RET_UIC_CONFIG_ERROR_OFF));
76 return -((reg & 0xf) + RET_UIC_CONFIG_ERROR_OFF);
77 }
78
ufs_config_init(void)79 static void ufs_config_init(void)
80 {
81 int i = 0;
82 struct dwc_ufs_utrd *p_utrd = NULL;
83
84 /* Unipro DL_AFC0CreditThreshold */
85 send_uic_command(DME_SET, 0x20440000, 0, 0x0);
86 /* Unipro DL_TC0OutAckThreshold */
87 send_uic_command(DME_SET, 0x20450000, 0, 0x0);
88 /* Unipro DL_TC0TXFCThreshold */
89 send_uic_command(DME_SET, 0x20400000, 0, 0x9);
90
91 ufsboot_static_space_address = UFS_START_WORK_SPACE_START;
92 ufs_memset((void*)ufsboot_static_space_address, 0, UFS_STATIC_WORK_SPACE_SIZE);
93 ufsboot_static_space_address = BYTES_ALIGN_1024(ufsboot_static_space_address);
94 if (!ufsboot_static_space_address) {
95 return ;
96 }
97
98 p_utrd = (struct dwc_ufs_utrd *)UFS_TR_UTP_BASE;
99 /* UTRD init */
100 ufs_memset((void *)UFS_TR_UTP_BASE, 0, MAX_TR_TASK * sizeof(struct dwc_ufs_utrd));
101 writel(0x1, STATIC_UFS_TAG_ADDR);
102
103 dwc_ufs_write_reg(UFS_UTRLBA_OFF, UFS_TR_UTP_BASE);
104 dwc_ufs_write_reg(UFS_UTRLBAU_OFF, 0);
105
106 for (i = 0; i < MAX_TR_TASK; i++) {
107 //debug_printf("init UTRD, p_utrd addr = 0x%x\n", (uint32_t)p_utrd);
108 p_utrd->ucdba = UFS_CMD_UPIU_BASE;
109 p_utrd->ucdbau = 0x0;
110 p_utrd->resp_upiu_offset = (UFS_RESP_UPIU_BASE - UFS_CMD_UPIU_BASE) >> 2;
111 p_utrd->prdt_offset = (UFS_PRDT_BASE - UFS_CMD_UPIU_BASE) >> 2;
112 p_utrd += 1;
113 }
114 /* UTMRD init */
115 ufs_memset((void *)UFS_TMR_UTP_BASE, 0, 20 * 4);
116 dwc_ufs_write_reg(UFS_UTMRLBA_OFF, UFS_TMR_UTP_BASE);
117 dwc_ufs_write_reg(UFS_UTMRLBAU_OFF, 0);
118
119 dwc_ufs_write_reg(UFS_UTRLRSR_OFF, UFS_UTP_RUN_BIT);
120 dwc_ufs_write_reg(UFS_UTMRLRSR_OFF, UFS_UTP_RUN_BIT);
121 return;
122 }
123
wait_for_cmd_completion(uint32_t tag,uint32_t timeout_ms)124 static int wait_for_cmd_completion(uint32_t tag, uint32_t timeout_ms)
125 {
126 unsigned int tick;
127
128 if ((tag < 1) || (tag > MAX_TR_TASK)) {
129 debug_printf("wait_for_cmd_completion: input tag invalid, tag = %d\n", tag);
130 tag = 1;
131 }
132
133 /* Set the doorbell for processing the request */
134 dwc_ufs_write_reg(UFS_UTRLDBR_OFF, 0x1 << (tag - 1));
135
136 tick = current_time();
137 /* Wait for the DoorBell to clear */
138 for (;;) {
139 if((dwc_ufs_read_reg(UFS_UTRLDBR_OFF) & (0x1 << (tag - 1))) == 0) {
140 break;
141 }
142
143 if(time_passed_ms(tick) > timeout_ms) {
144 debug_printf("UTRL DoorBell Not Cleared and Timed Out\n");
145 dwc_ufs_write_reg(UFS_UTRLCLR_OFF, 0);
146 return UFS_UTRD_DOORBELL_TIMEOUT;
147 }
148 }
149
150 return UFS_SUCCESS;
151 }
152
create_nop_out_upiu(uint32_t tag)153 static void create_nop_out_upiu(uint32_t tag)
154 {
155 struct dwc_ufs_nop_req_upiu *cmd_upiu_ptr = NULL;
156 struct dwc_ufs_utrd *utrd_desc = NULL;
157 int i;
158
159 if ((tag < 1) || (tag > MAX_TR_TASK)) {
160 debug_printf("create_nop_out_upiu: input tag invalid, tag = %d\n", tag);
161 tag = 1;
162 }
163
164 cmd_upiu_ptr = (struct dwc_ufs_nop_req_upiu*)UFS_CMD_UPIU_BASE;
165 utrd_desc = (struct dwc_ufs_utrd *)UFS_TR_UTP_BASE;
166 utrd_desc += tag - 1;
167 debug_printf("create_nop_out_upiu: utrd_desc addr 0x%x\n", utrd_desc);
168
169 /* clean response upiu */
170 ufs_memset((void *)UFS_RESP_UPIU_BASE, 0, sizeof(struct dwc_ufs_nop_resp_upiu));
171
172 utrd_desc->ct_and_flags = (uint8_t)(UTP_NO_DATA_TRANSFER | UTP_UFS_STORAGE_COMMAND);
173
174 utrd_desc->resp_upiu_length = to_littleendian16((uint16_t)sizeof(struct dwc_ufs_nop_resp_upiu) >> 2);
175 utrd_desc->prdt_length = 0;
176 utrd_desc->ocs = 0xf;
177
178 cmd_upiu_ptr->trans_type = 0x00;
179 cmd_upiu_ptr->flags = 0x00;
180 cmd_upiu_ptr->reserved_1 = 0x00;
181 cmd_upiu_ptr->task_tag = tag;
182 cmd_upiu_ptr->reserved_2 = 0x0;
183 cmd_upiu_ptr->tot_ehs_len = 0x00;
184 cmd_upiu_ptr->reserved_3 = 0x00;
185 cmd_upiu_ptr->data_seg_len = 0x00;
186 for (i = 0; i < 20; i++) {
187 cmd_upiu_ptr->reserved_4[i] = 0x00;
188 }
189
190 return;
191 }
192
read_nop_rsp(uint32_t tag)193 static int read_nop_rsp(uint32_t tag)
194 {
195 struct dwc_ufs_nop_resp_upiu *resp_upiu = NULL;
196 struct dwc_ufs_utrd *utrd_desc = NULL;
197
198 if ((tag < 1) || (tag > MAX_TR_TASK)) {
199 debug_printf("read_nop_rsp: input tag invalid, tag = %d\n", tag);
200 tag = 1;
201 }
202
203 resp_upiu = (struct dwc_ufs_nop_resp_upiu *)UFS_RESP_UPIU_BASE;
204 utrd_desc = (struct dwc_ufs_utrd *)UFS_TR_UTP_BASE;
205 utrd_desc += tag - 1;
206
207 debug_printf("read_nop_rsp: utrd_desc addr 0x%x\n", utrd_desc);
208
209 if (utrd_desc->ocs != UFS_SUCCESS) {
210 return -((utrd_desc->ocs & 0xf) + RET_UTRD_OCS_ERROR_OFF);
211 }
212
213 if ((resp_upiu->trans_type & 0x3F) != NOP_TRANS_TYPE) {
214 debug_printf("invalid nop in\n");
215 return UFS_INVALID_NOP_IN;
216 }
217
218 if (resp_upiu->response != UFS_SUCCESS) {
219 debug_printf("nop in response error, resp = 0x%x\n", resp_upiu->response);
220 return UFS_NOP_RESP_FAIL;
221 }
222
223 return UFS_SUCCESS;
224 }
225
send_nop_out_cmd(void)226 static int send_nop_out_cmd(void)
227 {
228 int ret;
229 uint32_t tag = 0;
230 int i;
231
232 tag = readl(STATIC_UFS_TAG_ADDR);
233 debug_printf("in send nop out: read tag = %d\n", tag);
234 for (i = 0; i < 3; i++) {
235 if ((tag > MAX_TR_TASK) || (tag < 1)) {
236 tag = 1;
237 }
238 debug_printf("create nop out: tag = %d\n", tag);
239 create_nop_out_upiu(tag);
240 ret = wait_for_cmd_completion(tag, UFS_SEND_NOP_OUT_TIMEOUT_MS);
241 if (ret == UFS_SUCCESS) {
242 ret = read_nop_rsp(tag);
243 }
244
245 if (ret == UFS_SUCCESS) {
246 break;
247 }
248
249 debug_printf("nop out nop in fail, ret = %d, retry = %d\n", ret, i);
250 ufs_waitms(1);
251 if (ret == UFS_UTRD_DOORBELL_TIMEOUT) {
252 tag++;
253 writel(tag, STATIC_UFS_TAG_ADDR);
254 }
255 }
256
257 return ret;
258 }
259
create_cmd_upiu(uint32_t opcode,enum dma_data_direction direction,uint64_t buf_addr,uint32_t rel_addr,uint32_t size,uint32_t tag)260 static int create_cmd_upiu(uint32_t opcode,
261 enum dma_data_direction direction,
262 uint64_t buf_addr, uint32_t rel_addr,
263 uint32_t size, uint32_t tag)
264 {
265 struct dwc_ufs_cmd_upiu *cmd_upiu_ptr = NULL;
266 struct dwc_ufs_utrd *utrd_desc = NULL;
267 struct dwc_ufs_prd *prdt_table = NULL;
268 uint32_t data_direction;
269 uint8_t upiu_flags;
270 uint32_t prdt_buf_size = PRDT_BUFFER_SIZE;
271 uint64_t buf_addr_phy;
272 uint32_t i;
273 int ret;
274
275 if (opcode == UFS_OP_READ_10) {
276 if (rel_addr % LOGICAL_BLK_SIZE) {
277 return UFS_SOFTWARE_ERROR;
278 }
279 if (size % LOGICAL_BLK_SIZE) {
280 return UFS_SOFTWARE_ERROR;
281 }
282 }
283
284 cmd_upiu_ptr = (struct dwc_ufs_cmd_upiu *)UFS_CMD_UPIU_BASE;
285 utrd_desc = (struct dwc_ufs_utrd *)UFS_TR_UTP_BASE;
286 utrd_desc += tag - 1;
287 debug_printf("create_cmd_upiu: utrd_desc addr 0x%x\n", utrd_desc);
288
289 prdt_table = (struct dwc_ufs_prd *)UFS_PRDT_BASE;
290
291 if (direction == DMA_FROM_DEVICE) {
292 data_direction = UTP_DEVICE_TO_HOST;
293 upiu_flags = UPIU_CMD_FLAGS_READ;
294 } else if (direction == DMA_NONE) {
295 data_direction = UTP_NO_DATA_TRANSFER;
296 upiu_flags = UPIU_CMD_FLAGS_NONE;
297 } else {
298 return UFS_SOFTWARE_ERROR;
299 }
300
301 /* clean response upiu */
302 ufs_memset((void *)UFS_RESP_UPIU_BASE, 0, sizeof(struct dwc_ufs_xfer_resp_upiu));
303
304 /* Update cmd_type, flags and response upiu length for transfer requests */
305 utrd_desc->ct_and_flags =
306 (uint8_t)(data_direction | UTP_UFS_STORAGE_COMMAND);
307 utrd_desc->resp_upiu_length = to_littleendian16((uint16_t)
308 (sizeof(struct dwc_ufs_xfer_resp_upiu) >> 2));
309 utrd_desc->ocs = 0xf;
310 utrd_desc->prdt_length = to_littleendian16((uint16_t)
311 ((size + PRDT_BUFFER_SIZE - 1) / PRDT_BUFFER_SIZE));
312
313 cmd_upiu_ptr->trans_type = 0x01;
314 cmd_upiu_ptr->flags = upiu_flags;
315 cmd_upiu_ptr->lun = UFS_BOOT_LUN;
316 cmd_upiu_ptr->task_tag = tag;
317 cmd_upiu_ptr->cmd_set_type = 0x0;
318 cmd_upiu_ptr->reserved_1_0 = 0x0;
319 cmd_upiu_ptr->reserved_1_1 = 0x0;
320 cmd_upiu_ptr->reserved_1_2 = 0x0;
321 cmd_upiu_ptr->tot_ehs_len = 0x0;
322 cmd_upiu_ptr->reserved_2 = 0x0;
323 cmd_upiu_ptr->data_seg_len = 0x0;
324 cmd_upiu_ptr->exp_data_xfer_len = to_bigendian32(size);
325
326 ret = get_cmnd(opcode, (rel_addr / LOGICAL_BLK_SIZE),
327 (size / LOGICAL_BLK_SIZE), cmd_upiu_ptr->cdb);
328 if (ret) {
329 return UFS_SOFTWARE_ERROR;
330 }
331
332 buf_addr_phy =
333 (uint64_t)LPRAM_ADDR_FROM_LPM3_TO_CPU((uint64_t)buf_addr);
334
335 /* Fill PRD Table Info */
336 if (direction != DMA_NONE) {
337 for (i = 0; (size); i++) {
338 prdt_table[i].base_addr =
339 to_littleendian32((uint32_t)
340 (buf_addr_phy & 0xffffffff) +
341 (i * prdt_buf_size));
342 prdt_table[i].upper_addr =
343 to_littleendian32((uint32_t)
344 ((buf_addr_phy >> 32) & 0xffffffff));
345 prdt_table[i].reserved1 = 0x0;
346 prdt_table[i].size = to_littleendian32
347 (((prdt_buf_size < size) ? prdt_buf_size : size) - 1);
348 size -= (prdt_buf_size < size) ? prdt_buf_size : size;
349 }
350 }
351
352 return UFS_SUCCESS;
353 }
354
send_scsi_cmd(uint32_t opcode,enum dma_data_direction direction,uint64_t buf_addr,uint32_t rel_addr,uint32_t size,uint32_t tag)355 static int send_scsi_cmd(uint32_t opcode,
356 enum dma_data_direction direction,
357 uint64_t buf_addr, uint32_t rel_addr,
358 uint32_t size, uint32_t tag)
359 {
360 int ret;
361 uint32_t timeout_ms;
362
363 if (size % 0x4) {
364 return UFS_SOFTWARE_ERROR;
365 }
366 if (size / PRDT_BUFFER_SIZE >= MAX_PRDT_ENTRIES) {
367 return UFS_SOFTWARE_ERROR;
368 }
369
370 if (opcode == UFS_OP_TEST_UNIT_READY) {
371 timeout_ms = 10;
372 } else if (opcode == UFS_OP_READ_10)
373 //timeout_ms = 1000;
374 //debug for reset bug
375 {
376 timeout_ms = 50000;
377 } else {
378 return UFS_SOFTWARE_ERROR;
379 }
380
381 ret = create_cmd_upiu(opcode, direction, buf_addr, rel_addr, size, tag);
382 if (ret != UFS_SUCCESS) {
383 return ret;
384 }
385
386 ret = wait_for_cmd_completion(tag, timeout_ms);
387 return ret;
388 }
389
handle_scsi_completion(uint32_t tag)390 static int handle_scsi_completion(uint32_t tag)
391 {
392 struct dwc_ufs_xfer_resp_upiu *resp_upiu;
393 struct dwc_ufs_utrd *utrd_desc;
394 uint8_t status;
395
396 resp_upiu = (struct dwc_ufs_xfer_resp_upiu *)UFS_RESP_UPIU_BASE;
397 utrd_desc = (struct dwc_ufs_utrd *)UFS_TR_UTP_BASE;
398 utrd_desc += tag - 1;
399 debug_printf("handle_scsi_completion: utrd_desc addr 0x%x\n", utrd_desc);
400
401 if (utrd_desc->ocs == UFS_SUCCESS) {
402 status = resp_upiu->status;
403 if (status == SAM_STAT_GOOD) {
404 return UFS_SUCCESS;
405 }
406
407 if (status == SAM_STAT_CHECK_CONDITION) {
408 return -(RET_SENSE_KEY_OFF + (resp_upiu->sense_data[2] & 0xf));
409 }
410
411 switch (status) {
412 case SAM_STAT_CONDITION_MET:
413 return RESP_STAT_CONDITION_MET;
414 case SAM_STAT_BUSY:
415 return RESP_STAT_BUSY;
416 case SAM_STAT_RESERVATION_CONFLICT:
417 return RESP_STAT_RESERVATION_CONFLICT;
418 case SAM_STAT_TASK_SET_FULL:
419 return RESP_STAT_TASK_SET_FULL;
420 case SAM_STAT_ACA_ACTIVE:
421 return RESP_STAT_ACA_ACTIVE;
422 case SAM_STAT_TASK_ABORTED:
423 return RESP_STAT_TASK_ABORTED;
424 default:
425 return RESP_STAT_UNKNOW;
426 }
427 } else {
428 return -((utrd_desc->ocs & 0xf) + RET_UTRD_OCS_ERROR_OFF);
429 }
430
431 return UFS_SUCCESS;
432 }
433
do_scsi_cmd(uint32_t opcode,enum dma_data_direction direction,uint64_t buf_addr,uint32_t rel_addr,uint32_t size,uint32_t tag)434 static int do_scsi_cmd(uint32_t opcode,
435 enum dma_data_direction direction,
436 uint64_t buf_addr, uint32_t rel_addr,
437 uint32_t size, uint32_t tag)
438 {
439 int ret = 0;
440 if ((tag < 1) || (tag > MAX_TR_TASK)) {
441 debug_printf("do_scsi_cmd: input tag invalid, tag = %d\n", tag);
442 tag = 1;
443 }
444
445 ret = send_scsi_cmd(opcode, direction, buf_addr, rel_addr, size, tag);
446 if (ret != UFS_SUCCESS) {
447 return ret;
448 }
449
450 ret = handle_scsi_completion(tag);
451 if (ret != UFS_SUCCESS) {
452 return ret;
453 }
454 return ret;
455 }
456
test_unit_ready(void)457 static int test_unit_ready(void)
458 {
459 uint32_t tag = 0;
460 int ret;
461 int i;
462
463 tag = readl(STATIC_UFS_TAG_ADDR);
464 debug_printf("test_unit_ready: read tag = %d\n", tag);
465 for (i = 0; i < 4; i++) {
466 if ((tag > MAX_TR_TASK) || (tag < 1)) {
467 tag = 1;
468 }
469 debug_printf("test_unit_ready: tag = %d\n", tag);
470
471 ret = do_scsi_cmd(UFS_OP_TEST_UNIT_READY, DMA_NONE, 0, 0, 0, tag);
472 if (ret == UFS_SUCCESS) {
473 break;
474 }
475 debug_printf("test_unit_ready ret = %d, retry = %d\n", ret, i);
476 ufs_waitms(1);
477 if (ret == UFS_UTRD_DOORBELL_TIMEOUT) {
478 tag++;
479 writel(tag, STATIC_UFS_TAG_ADDR);
480 }
481 }
482
483 return ret;
484 }
485
ufs_start_boot(void)486 static int ufs_start_boot(void)
487 {
488 int ret;
489
490 ret = send_nop_out_cmd();
491 if (ret) {
492 debug_printf("ufs send nop out fail\n");
493 return ret;
494 }
495
496 debug_printf("ufs nop in out OK\n");
497
498 ret = test_unit_ready();
499 if (ret) {
500 debug_printf("ufs test unit ready fail\n");
501 return ret;
502 }
503
504 debug_printf("ufs test unit ready OK\n");
505 return UFS_SUCCESS;
506 }
507
ufs_read_boot_data(uint64_t buf_addr,uint32_t rel_addr,uint32_t size)508 static int ufs_read_boot_data(uint64_t buf_addr,
509 uint32_t rel_addr,
510 uint32_t size)
511 {
512 int ret;
513 int retry = 50;
514 uint32_t tag = 0;
515
516 size = BYTES_ALIGN_4096(size);
517 tag = readl(STATIC_UFS_TAG_ADDR);
518 debug_printf("ufs_read_boot_data: read tag = %d\n", tag);
519 if ((tag > MAX_TR_TASK) || (tag < 1)) {
520 tag = 1;
521 }
522 debug_printf("ufs_read_boot_data: tag = %d\n", tag);
523
524 while (retry > 0) {
525 ret = do_scsi_cmd(UFS_OP_READ_10, DMA_FROM_DEVICE, buf_addr, rel_addr, size, tag);
526 if (ret == UFS_SUCCESS) {
527 debug_printf("ufs read 10 OK\n");
528 return ret;
529 } else if ((ret == RESP_STAT_BUSY)
530 || (ret == RESP_STAT_TASK_SET_FULL)
531 || (ret == NOT_READY)) {
532 ufs_waitms(1);
533 retry--;
534 debug_printf("ufs read 10 retry, ret = %d, retry = %d\n", ret, retry);
535 } else {
536 debug_printf("ufs read 10 FAIL, ret = %d\n", ret);
537 break;
538 }
539 }
540 return ret;
541 }
542
ufs_boot_read(void * ptr,unsigned int size)543 void ufs_boot_read(void *ptr, unsigned int size)
544 {
545 ufs_memset(ptr, 0, size);
546 ufs_config_init();
547 ufs_start_boot();
548 ufs_read_boot_data((uint64_t)ptr, 0, size);
549 }
550
551