xref: /arm-trusted-firmware/drivers/brcm/emmc/emmc_csl_sdcmd.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2016 - 2020, Broadcom
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <stdlib.h>
8*91f16700Schasinglulu #include <stddef.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include "bcm_emmc.h"
11*91f16700Schasinglulu #include "emmc_chal_types.h"
12*91f16700Schasinglulu #include "emmc_chal_sd.h"
13*91f16700Schasinglulu #include "emmc_csl_sdprot.h"
14*91f16700Schasinglulu #include "emmc_csl_sdcmd.h"
15*91f16700Schasinglulu #include "emmc_csl_sd.h"
16*91f16700Schasinglulu #include "emmc_chal_sd.h"
17*91f16700Schasinglulu #include "emmc_pboot_hal_memory_drv.h"
18*91f16700Schasinglulu 
19*91f16700Schasinglulu int sd_cmd0(struct sd_handle *handle)
20*91f16700Schasinglulu {
21*91f16700Schasinglulu 	int res;
22*91f16700Schasinglulu 	uint32_t argument = 0x0; /* Go to IDLE state. */
23*91f16700Schasinglulu 
24*91f16700Schasinglulu 	/* send cmd and parse result */
25*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_GO_IDLE_STATE, argument, 0, NULL);
26*91f16700Schasinglulu 
27*91f16700Schasinglulu 	if (res == SD_OK) {
28*91f16700Schasinglulu 		/* Clear all other interrupts */
29*91f16700Schasinglulu 		chal_sd_clear_irq((void *)handle->device, 0xffffffff);
30*91f16700Schasinglulu 	}
31*91f16700Schasinglulu 
32*91f16700Schasinglulu 	return res;
33*91f16700Schasinglulu }
34*91f16700Schasinglulu 
35*91f16700Schasinglulu int sd_cmd1(struct sd_handle *handle, uint32_t ocr, uint32_t *ocr_output)
36*91f16700Schasinglulu {
37*91f16700Schasinglulu 	int res;
38*91f16700Schasinglulu 	uint32_t options;
39*91f16700Schasinglulu 	struct sd_resp resp;
40*91f16700Schasinglulu 
41*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R3_4 << SD_CMDR_RSP_TYPE_S;
42*91f16700Schasinglulu 
43*91f16700Schasinglulu 	if (ocr_output == NULL) {
44*91f16700Schasinglulu 		EMMC_TRACE("Invalid args\n");
45*91f16700Schasinglulu 		return SD_FAIL;
46*91f16700Schasinglulu 	}
47*91f16700Schasinglulu 
48*91f16700Schasinglulu 	/* send cmd and parse result */
49*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_SEND_OPCOND, ocr, options, &resp);
50*91f16700Schasinglulu 
51*91f16700Schasinglulu 	if (res == SD_OK)
52*91f16700Schasinglulu 		*ocr_output = resp.data.r3.ocr;
53*91f16700Schasinglulu 
54*91f16700Schasinglulu 	return res;
55*91f16700Schasinglulu }
56*91f16700Schasinglulu 
57*91f16700Schasinglulu int sd_cmd2(struct sd_handle *handle)
58*91f16700Schasinglulu {
59*91f16700Schasinglulu 	uint32_t options;
60*91f16700Schasinglulu 	struct sd_resp resp;
61*91f16700Schasinglulu 
62*91f16700Schasinglulu 	/* send cmd and parse result */
63*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R2 << SD_CMDR_RSP_TYPE_S;
64*91f16700Schasinglulu 
65*91f16700Schasinglulu 	return send_cmd(handle, SD_CMD_ALL_SEND_CID, 0, options, &resp);
66*91f16700Schasinglulu }
67*91f16700Schasinglulu 
68*91f16700Schasinglulu int sd_cmd3(struct sd_handle *handle)
69*91f16700Schasinglulu {
70*91f16700Schasinglulu 	int res;
71*91f16700Schasinglulu 	uint32_t options = 0;
72*91f16700Schasinglulu 	uint32_t argument;
73*91f16700Schasinglulu 	struct sd_resp resp;
74*91f16700Schasinglulu 
75*91f16700Schasinglulu 	/* use non zero and non 0x1 value for rca */
76*91f16700Schasinglulu 	handle->device->ctrl.rca = 0x5;
77*91f16700Schasinglulu 	argument = handle->device->ctrl.rca << SD_CMD7_ARG_RCA_SHIFT;
78*91f16700Schasinglulu 
79*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
80*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
81*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK;
82*91f16700Schasinglulu 
83*91f16700Schasinglulu 	/* send cmd and parse result */
84*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_MMC_SET_RCA, argument, options, &resp);
85*91f16700Schasinglulu 
86*91f16700Schasinglulu 	if (res != SD_OK)
87*91f16700Schasinglulu 		handle->device->ctrl.rca = 0;
88*91f16700Schasinglulu 
89*91f16700Schasinglulu 	return res;
90*91f16700Schasinglulu }
91*91f16700Schasinglulu 
92*91f16700Schasinglulu int sd_cmd7(struct sd_handle *handle, uint32_t rca)
93*91f16700Schasinglulu {
94*91f16700Schasinglulu 	int res;
95*91f16700Schasinglulu 	uint32_t argument, options;
96*91f16700Schasinglulu 	struct sd_resp resp;
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	argument = (rca << SD_CMD7_ARG_RCA_SHIFT);
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 	/*
101*91f16700Schasinglulu 	 * Response to CMD7 is:
102*91f16700Schasinglulu 	 * R1 while selectiing from Stand-By State to Transfer State
103*91f16700Schasinglulu 	 * R1b while selecting from Disconnected State to Programming State.
104*91f16700Schasinglulu 	 *
105*91f16700Schasinglulu 	 * In this driver, we only issue a CMD7 once, to go to transfer mode
106*91f16700Schasinglulu 	 * during init_mmc_card().
107*91f16700Schasinglulu 	 */
108*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
109*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
110*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK;
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	/* send cmd and parse result */
113*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_SELECT_DESELECT_CARD, argument, options,
114*91f16700Schasinglulu 		       &resp);
115*91f16700Schasinglulu 
116*91f16700Schasinglulu 	if (res == SD_OK)
117*91f16700Schasinglulu 		/* Clear all other interrupts */
118*91f16700Schasinglulu 		chal_sd_clear_irq((void *)handle->device, 0xffffffff);
119*91f16700Schasinglulu 
120*91f16700Schasinglulu 	return res;
121*91f16700Schasinglulu }
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 
124*91f16700Schasinglulu /*
125*91f16700Schasinglulu  * CMD8 Get CSD_EXT
126*91f16700Schasinglulu  */
127*91f16700Schasinglulu int mmc_cmd8(struct sd_handle *handle, uint8_t *extCsdReg)
128*91f16700Schasinglulu {
129*91f16700Schasinglulu 	uint32_t res, options;
130*91f16700Schasinglulu 	struct sd_resp resp;
131*91f16700Schasinglulu 
132*91f16700Schasinglulu 	data_xfer_setup(handle, extCsdReg, CEATA_EXT_CSDBLOCK_SIZE,
133*91f16700Schasinglulu 			    SD_XFER_CARD_TO_HOST);
134*91f16700Schasinglulu 
135*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
136*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_DTDS_MASK |
137*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK;
138*91f16700Schasinglulu 
139*91f16700Schasinglulu 	/* send cmd and parse result */
140*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_READ_EXT_CSD, 0, options, &resp);
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	if (res == SD_OK)
143*91f16700Schasinglulu 		res = process_data_xfer(handle, extCsdReg, 0,
144*91f16700Schasinglulu 					CEATA_EXT_CSDBLOCK_SIZE,
145*91f16700Schasinglulu 					SD_XFER_CARD_TO_HOST);
146*91f16700Schasinglulu 
147*91f16700Schasinglulu 	return res;
148*91f16700Schasinglulu }
149*91f16700Schasinglulu 
150*91f16700Schasinglulu int sd_cmd9(struct sd_handle *handle, struct sd_card_data *card)
151*91f16700Schasinglulu {
152*91f16700Schasinglulu 	int res;
153*91f16700Schasinglulu 	uint32_t argument, options, iBlkNum, multiFactor = 1;
154*91f16700Schasinglulu 	uint32_t maxReadBlockLen = 1, maxWriteBlockLen = 1;
155*91f16700Schasinglulu 	struct sd_resp resp;
156*91f16700Schasinglulu 
157*91f16700Schasinglulu 	argument = handle->device->ctrl.rca << SD_CMD7_ARG_RCA_SHIFT;
158*91f16700Schasinglulu 
159*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R2 << SD_CMDR_RSP_TYPE_S |
160*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK;
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	/* send cmd and parse result */
163*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_SEND_CSD, argument, options, &resp);
164*91f16700Schasinglulu 
165*91f16700Schasinglulu 	if (res != SD_OK)
166*91f16700Schasinglulu 		return res;
167*91f16700Schasinglulu 
168*91f16700Schasinglulu 	if (handle->card->type == SD_CARD_MMC) {
169*91f16700Schasinglulu 		card->csd.mmc.structure = (resp.data.r2.rsp4 >> 22) & 0x3;
170*91f16700Schasinglulu 		card->csd.mmc.csdSpecVer = (resp.data.r2.rsp4 >> 18) & 0x0f;
171*91f16700Schasinglulu 		card->csd.mmc.taac = (resp.data.r2.rsp4 >> 8) & 0xff;
172*91f16700Schasinglulu 		card->csd.mmc.nsac = resp.data.r2.rsp4 & 0xff;
173*91f16700Schasinglulu 		card->csd.mmc.speed = resp.data.r2.rsp3 >> 24;
174*91f16700Schasinglulu 		card->csd.mmc.classes = (resp.data.r2.rsp3 >> 12) & 0xfff;
175*91f16700Schasinglulu 		card->csd.mmc.rdBlkLen = (resp.data.r2.rsp3 >> 8) & 0xf;
176*91f16700Schasinglulu 		card->csd.mmc.rdBlkPartial = (resp.data.r2.rsp3 >> 7) & 0x01;
177*91f16700Schasinglulu 		card->csd.mmc.wrBlkMisalign = (resp.data.r2.rsp3 >> 6) & 0x1;
178*91f16700Schasinglulu 		card->csd.mmc.rdBlkMisalign = (resp.data.r2.rsp3 >> 5) & 0x1;
179*91f16700Schasinglulu 		card->csd.mmc.dsr = (resp.data.r2.rsp2 >> 4) & 0x01;
180*91f16700Schasinglulu 		card->csd.mmc.size =
181*91f16700Schasinglulu 		    ((resp.data.r2.rsp3 & 0x3) << 10) +
182*91f16700Schasinglulu 		    ((resp.data.r2.rsp2 >> 22) & 0x3ff);
183*91f16700Schasinglulu 		card->csd.mmc.vddRdCurrMin = (resp.data.r2.rsp2 >> 19) & 0x7;
184*91f16700Schasinglulu 		card->csd.mmc.vddRdCurrMax = (resp.data.r2.rsp2 >> 16) & 0x7;
185*91f16700Schasinglulu 		card->csd.mmc.vddWrCurrMin = (resp.data.r2.rsp2 >> 13) & 0x7;
186*91f16700Schasinglulu 		card->csd.mmc.vddWrCurrMax = (resp.data.r2.rsp2 >> 10) & 0x7;
187*91f16700Schasinglulu 		card->csd.mmc.devSizeMulti = (resp.data.r2.rsp2 >> 7) & 0x7;
188*91f16700Schasinglulu 		card->csd.mmc.eraseGrpSize = (resp.data.r2.rsp2 >> 2) & 0x1f;
189*91f16700Schasinglulu 		card->csd.mmc.eraseGrpSizeMulti =
190*91f16700Schasinglulu 		    ((resp.data.r2.rsp2 & 0x3) << 3) +
191*91f16700Schasinglulu 		    ((resp.data.r2.rsp1 >> 29) & 0x7);
192*91f16700Schasinglulu 		card->csd.mmc.wrProtGroupSize =
193*91f16700Schasinglulu 		    ((resp.data.r2.rsp1 >> 24) & 0x1f);
194*91f16700Schasinglulu 		card->csd.mmc.wrProtGroupEnable =
195*91f16700Schasinglulu 		    (resp.data.r2.rsp1 >> 23) & 0x1;
196*91f16700Schasinglulu 		card->csd.mmc.manuDefEcc = (resp.data.r2.rsp1 >> 21) & 0x3;
197*91f16700Schasinglulu 		card->csd.mmc.wrSpeedFactor = (resp.data.r2.rsp1 >> 18) & 0x7;
198*91f16700Schasinglulu 		card->csd.mmc.wrBlkLen = (resp.data.r2.rsp1 >> 14) & 0xf;
199*91f16700Schasinglulu 		card->csd.mmc.wrBlkPartial = (resp.data.r2.rsp1 >> 13) & 0x1;
200*91f16700Schasinglulu 		card->csd.mmc.protAppl = (resp.data.r2.rsp1 >> 8) & 0x1;
201*91f16700Schasinglulu 		card->csd.mmc.copyFlag = (resp.data.r2.rsp1 >> 7) & 0x1;
202*91f16700Schasinglulu 		card->csd.mmc.permWrProt = (resp.data.r2.rsp1 >> 6) & 0x1;
203*91f16700Schasinglulu 		card->csd.mmc.tmpWrProt = (resp.data.r2.rsp1 >> 5) & 0x1;
204*91f16700Schasinglulu 		card->csd.mmc.fileFormat = (resp.data.r2.rsp1 >> 4) & 0x03;
205*91f16700Schasinglulu 		card->csd.mmc.eccCode = resp.data.r2.rsp1 & 0x03;
206*91f16700Schasinglulu 		maxReadBlockLen <<= card->csd.mmc.rdBlkLen;
207*91f16700Schasinglulu 		maxWriteBlockLen <<= card->csd.mmc.wrBlkLen;
208*91f16700Schasinglulu 
209*91f16700Schasinglulu 		iBlkNum = card->csd.mmc.size + 1;
210*91f16700Schasinglulu 		multiFactor = (1 << (card->csd.mmc.devSizeMulti + 2));
211*91f16700Schasinglulu 
212*91f16700Schasinglulu 		handle->card->size =
213*91f16700Schasinglulu 		    iBlkNum * multiFactor * (1 << card->csd.mmc.rdBlkLen);
214*91f16700Schasinglulu 	}
215*91f16700Schasinglulu 
216*91f16700Schasinglulu 	handle->card->maxRdBlkLen = maxReadBlockLen;
217*91f16700Schasinglulu 	handle->card->maxWtBlkLen = maxWriteBlockLen;
218*91f16700Schasinglulu 
219*91f16700Schasinglulu 	if (handle->card->size < 0xA00000) {
220*91f16700Schasinglulu 		/*
221*91f16700Schasinglulu 		 * 10MB Too small size mean, cmd9 response is wrong,
222*91f16700Schasinglulu 		 * Use default value 1G
223*91f16700Schasinglulu 		 */
224*91f16700Schasinglulu 		handle->card->size = 0x40000000;
225*91f16700Schasinglulu 		handle->card->maxRdBlkLen = 512;
226*91f16700Schasinglulu 		handle->card->maxWtBlkLen = 512;
227*91f16700Schasinglulu 	}
228*91f16700Schasinglulu 
229*91f16700Schasinglulu 	if ((handle->card->maxRdBlkLen > 512) ||
230*91f16700Schasinglulu 	    (handle->card->maxWtBlkLen > 512)) {
231*91f16700Schasinglulu 		handle->card->maxRdBlkLen = 512;
232*91f16700Schasinglulu 		handle->card->maxWtBlkLen = 512;
233*91f16700Schasinglulu 	} else if ((handle->card->maxRdBlkLen == 0) ||
234*91f16700Schasinglulu 		   (handle->card->maxWtBlkLen == 0)) {
235*91f16700Schasinglulu 		handle->card->maxRdBlkLen = 512;
236*91f16700Schasinglulu 		handle->card->maxWtBlkLen = 512;
237*91f16700Schasinglulu 	}
238*91f16700Schasinglulu 
239*91f16700Schasinglulu 	handle->device->cfg.blockSize = handle->card->maxRdBlkLen;
240*91f16700Schasinglulu 
241*91f16700Schasinglulu 	return res;
242*91f16700Schasinglulu }
243*91f16700Schasinglulu 
244*91f16700Schasinglulu int sd_cmd13(struct sd_handle *handle, uint32_t *status)
245*91f16700Schasinglulu {
246*91f16700Schasinglulu 	int res;
247*91f16700Schasinglulu 	uint32_t argument, options;
248*91f16700Schasinglulu 	struct sd_resp resp;
249*91f16700Schasinglulu 
250*91f16700Schasinglulu 	argument = handle->device->ctrl.rca << SD_CMD7_ARG_RCA_SHIFT;
251*91f16700Schasinglulu 
252*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
253*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
254*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK;
255*91f16700Schasinglulu 
256*91f16700Schasinglulu 	/* send cmd and parse result */
257*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_SEND_STATUS, argument, options, &resp);
258*91f16700Schasinglulu 
259*91f16700Schasinglulu 	if (res == SD_OK) {
260*91f16700Schasinglulu 		*status = resp.cardStatus;
261*91f16700Schasinglulu 	}
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 	return res;
264*91f16700Schasinglulu }
265*91f16700Schasinglulu 
266*91f16700Schasinglulu int sd_cmd16(struct sd_handle *handle, uint32_t length)
267*91f16700Schasinglulu {
268*91f16700Schasinglulu 	int res;
269*91f16700Schasinglulu 	uint32_t argument, options, ntry;
270*91f16700Schasinglulu 	struct sd_resp resp;
271*91f16700Schasinglulu 
272*91f16700Schasinglulu 	argument = length;
273*91f16700Schasinglulu 
274*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
275*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK |
276*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
277*91f16700Schasinglulu 
278*91f16700Schasinglulu 	ntry = 0;
279*91f16700Schasinglulu 	do {
280*91f16700Schasinglulu 		res = sd_cmd13(handle, &resp.cardStatus);
281*91f16700Schasinglulu 		if (res != SD_OK) {
282*91f16700Schasinglulu 			EMMC_TRACE(
283*91f16700Schasinglulu 				"cmd13 failed before cmd16: rca 0x%0x, return %d, response 0x%0x\n",
284*91f16700Schasinglulu 				handle->device->ctrl.rca, res, resp.cardStatus);
285*91f16700Schasinglulu 			return res;
286*91f16700Schasinglulu 		}
287*91f16700Schasinglulu 
288*91f16700Schasinglulu 		if (resp.cardStatus & 0x100)
289*91f16700Schasinglulu 			break;
290*91f16700Schasinglulu 
291*91f16700Schasinglulu 		EMMC_TRACE("cmd13 rsp:0x%08x before cmd16\n", resp.cardStatus);
292*91f16700Schasinglulu 
293*91f16700Schasinglulu 		if (ntry > handle->device->cfg.retryLimit) {
294*91f16700Schasinglulu 			EMMC_TRACE("cmd13 retry reach limit %d\n",
295*91f16700Schasinglulu 				   handle->device->cfg.retryLimit);
296*91f16700Schasinglulu 			return SD_CMD_TIMEOUT;
297*91f16700Schasinglulu 		}
298*91f16700Schasinglulu 
299*91f16700Schasinglulu 		ntry++;
300*91f16700Schasinglulu 		EMMC_TRACE("cmd13 retry %d\n", ntry);
301*91f16700Schasinglulu 
302*91f16700Schasinglulu 		SD_US_DELAY(1000);
303*91f16700Schasinglulu 
304*91f16700Schasinglulu 	} while (1);
305*91f16700Schasinglulu 
306*91f16700Schasinglulu 	/* send cmd and parse result */
307*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_SET_BLOCKLEN, argument, options, &resp);
308*91f16700Schasinglulu 
309*91f16700Schasinglulu 	return res;
310*91f16700Schasinglulu }
311*91f16700Schasinglulu 
312*91f16700Schasinglulu int sd_cmd17(struct sd_handle *handle,
313*91f16700Schasinglulu 	     uint32_t addr, uint32_t len, uint8_t *buffer)
314*91f16700Schasinglulu {
315*91f16700Schasinglulu 	int res;
316*91f16700Schasinglulu 	uint32_t argument, options, ntry;
317*91f16700Schasinglulu 	struct sd_resp resp;
318*91f16700Schasinglulu 
319*91f16700Schasinglulu 	ntry = 0;
320*91f16700Schasinglulu 	do {
321*91f16700Schasinglulu 		res = sd_cmd13(handle, &resp.cardStatus);
322*91f16700Schasinglulu 		if (res != SD_OK) {
323*91f16700Schasinglulu 			EMMC_TRACE(
324*91f16700Schasinglulu 				"cmd 13 failed before cmd17: rca 0x%0x, return %d, response 0x%0x\n",
325*91f16700Schasinglulu 				handle->device->ctrl.rca, res, resp.cardStatus);
326*91f16700Schasinglulu 			return res;
327*91f16700Schasinglulu 		}
328*91f16700Schasinglulu 
329*91f16700Schasinglulu 		if (resp.cardStatus & 0x100)
330*91f16700Schasinglulu 			break;
331*91f16700Schasinglulu 
332*91f16700Schasinglulu 		EMMC_TRACE("cmd13 rsp:0x%08x before cmd17\n", resp.cardStatus);
333*91f16700Schasinglulu 
334*91f16700Schasinglulu 		if (ntry > handle->device->cfg.retryLimit) {
335*91f16700Schasinglulu 			EMMC_TRACE("cmd13 retry reach limit %d\n",
336*91f16700Schasinglulu 				   handle->device->cfg.retryLimit);
337*91f16700Schasinglulu 			return SD_CMD_TIMEOUT;
338*91f16700Schasinglulu 		}
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 		ntry++;
341*91f16700Schasinglulu 		EMMC_TRACE("cmd13 retry %d\n", ntry);
342*91f16700Schasinglulu 
343*91f16700Schasinglulu 		SD_US_DELAY(1000);
344*91f16700Schasinglulu 
345*91f16700Schasinglulu 	} while (1);
346*91f16700Schasinglulu 
347*91f16700Schasinglulu 	data_xfer_setup(handle, buffer, len, SD_XFER_CARD_TO_HOST);
348*91f16700Schasinglulu 
349*91f16700Schasinglulu 	/* send cmd and parse result */
350*91f16700Schasinglulu 	argument = addr;
351*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
352*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_DTDS_MASK |
353*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK | SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
354*91f16700Schasinglulu 
355*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_READ_SINGLE_BLOCK, argument, options,
356*91f16700Schasinglulu 		       &resp);
357*91f16700Schasinglulu 
358*91f16700Schasinglulu 	if (res != SD_OK)
359*91f16700Schasinglulu 		return res;
360*91f16700Schasinglulu 
361*91f16700Schasinglulu 	res = process_data_xfer(handle, buffer, addr, len, SD_XFER_CARD_TO_HOST);
362*91f16700Schasinglulu 
363*91f16700Schasinglulu 	return res;
364*91f16700Schasinglulu }
365*91f16700Schasinglulu 
366*91f16700Schasinglulu int sd_cmd18(struct sd_handle *handle,
367*91f16700Schasinglulu 	     uint32_t addr, uint32_t len, uint8_t *buffer)
368*91f16700Schasinglulu {
369*91f16700Schasinglulu 	int res;
370*91f16700Schasinglulu 	uint32_t argument, options, ntry;
371*91f16700Schasinglulu 	struct sd_resp resp;
372*91f16700Schasinglulu 
373*91f16700Schasinglulu 	ntry = 0;
374*91f16700Schasinglulu 	do {
375*91f16700Schasinglulu 		res = sd_cmd13(handle, &resp.cardStatus);
376*91f16700Schasinglulu 		if (res != SD_OK) {
377*91f16700Schasinglulu 			EMMC_TRACE(
378*91f16700Schasinglulu 				"cmd 13 failed before cmd18: rca 0x%0x, return %d, response 0x%0x\n",
379*91f16700Schasinglulu 				handle->device->ctrl.rca, res, resp.cardStatus);
380*91f16700Schasinglulu 			return res;
381*91f16700Schasinglulu 		}
382*91f16700Schasinglulu 
383*91f16700Schasinglulu 		if (resp.cardStatus & 0x100)
384*91f16700Schasinglulu 			break;
385*91f16700Schasinglulu 
386*91f16700Schasinglulu 		EMMC_TRACE("cmd13 rsp:0x%08x before cmd18\n", resp.cardStatus);
387*91f16700Schasinglulu 
388*91f16700Schasinglulu 		if (ntry > handle->device->cfg.retryLimit) {
389*91f16700Schasinglulu 			EMMC_TRACE("cmd13 retry reach limit %d\n",
390*91f16700Schasinglulu 				   handle->device->cfg.retryLimit);
391*91f16700Schasinglulu 			return SD_CMD_TIMEOUT;
392*91f16700Schasinglulu 		}
393*91f16700Schasinglulu 
394*91f16700Schasinglulu 		ntry++;
395*91f16700Schasinglulu 		EMMC_TRACE("cmd13 retry %d\n", ntry);
396*91f16700Schasinglulu 
397*91f16700Schasinglulu 		SD_US_DELAY(1000);
398*91f16700Schasinglulu 	} while (1);
399*91f16700Schasinglulu 
400*91f16700Schasinglulu 	data_xfer_setup(handle, buffer, len, SD_XFER_CARD_TO_HOST);
401*91f16700Schasinglulu 
402*91f16700Schasinglulu 	argument = addr;
403*91f16700Schasinglulu 
404*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
405*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_DTDS_MASK |
406*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_MSBS_MASK | SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
407*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_BCEN_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK |
408*91f16700Schasinglulu 		  BIT(SD4_EMMC_TOP_CMD_ACMDEN_SHIFT);
409*91f16700Schasinglulu 
410*91f16700Schasinglulu 	/* send cmd and parse result */
411*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_READ_MULTIPLE_BLOCK, argument, options,
412*91f16700Schasinglulu 		       &resp);
413*91f16700Schasinglulu 
414*91f16700Schasinglulu 	if (res != SD_OK)
415*91f16700Schasinglulu 		return res;
416*91f16700Schasinglulu 
417*91f16700Schasinglulu 	res = process_data_xfer(handle, buffer, addr, len, SD_XFER_CARD_TO_HOST);
418*91f16700Schasinglulu 
419*91f16700Schasinglulu 	return res;
420*91f16700Schasinglulu }
421*91f16700Schasinglulu 
422*91f16700Schasinglulu #ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
423*91f16700Schasinglulu static int card_sts_resp(struct sd_handle *handle, uint32_t *status)
424*91f16700Schasinglulu {
425*91f16700Schasinglulu 	int res;
426*91f16700Schasinglulu 	uint32_t ntry = 0;
427*91f16700Schasinglulu 
428*91f16700Schasinglulu 	do {
429*91f16700Schasinglulu 		res = sd_cmd13(handle, status);
430*91f16700Schasinglulu 		if (res != SD_OK) {
431*91f16700Schasinglulu 			EMMC_TRACE(
432*91f16700Schasinglulu 				"cmd 13 failed before cmd35: rca 0x%0x, return %d\n",
433*91f16700Schasinglulu 				handle->device->ctrl.rca, res);
434*91f16700Schasinglulu 			return res;
435*91f16700Schasinglulu 		}
436*91f16700Schasinglulu 
437*91f16700Schasinglulu 		if (*status & 0x100)
438*91f16700Schasinglulu 			break;
439*91f16700Schasinglulu 
440*91f16700Schasinglulu 		EMMC_TRACE("cmd13 rsp:0x%08x before cmd35\n", resp.cardStatus);
441*91f16700Schasinglulu 
442*91f16700Schasinglulu 		if (ntry > handle->device->cfg.retryLimit) {
443*91f16700Schasinglulu 			EMMC_TRACE("cmd13 retry reach limit %d\n",
444*91f16700Schasinglulu 				   handle->device->cfg.retryLimit);
445*91f16700Schasinglulu 			return SD_CMD_TIMEOUT;
446*91f16700Schasinglulu 		}
447*91f16700Schasinglulu 
448*91f16700Schasinglulu 		ntry++;
449*91f16700Schasinglulu 		EMMC_TRACE("cmd13 retry %d\n", ntry);
450*91f16700Schasinglulu 
451*91f16700Schasinglulu 		SD_US_DELAY(1000);
452*91f16700Schasinglulu 	} while (1);
453*91f16700Schasinglulu 
454*91f16700Schasinglulu 	return SD_OK;
455*91f16700Schasinglulu }
456*91f16700Schasinglulu 
457*91f16700Schasinglulu int sd_cmd35(struct sd_handle *handle, uint32_t start)
458*91f16700Schasinglulu {
459*91f16700Schasinglulu 	int res;
460*91f16700Schasinglulu 	uint32_t argument, options;
461*91f16700Schasinglulu 	struct sd_resp resp;
462*91f16700Schasinglulu 
463*91f16700Schasinglulu 	res = card_sts_resp(handle, &resp.cardStatus);
464*91f16700Schasinglulu 	if (res != SD_OK)
465*91f16700Schasinglulu 		return res;
466*91f16700Schasinglulu 
467*91f16700Schasinglulu 	argument = start;
468*91f16700Schasinglulu 
469*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
470*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK |
471*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
472*91f16700Schasinglulu 
473*91f16700Schasinglulu 	/* send cmd and parse result */
474*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_ERASE_GROUP_START,
475*91f16700Schasinglulu 		       argument, options, &resp);
476*91f16700Schasinglulu 
477*91f16700Schasinglulu 	if (res != SD_OK)
478*91f16700Schasinglulu 		return res;
479*91f16700Schasinglulu 
480*91f16700Schasinglulu 	return res;
481*91f16700Schasinglulu }
482*91f16700Schasinglulu 
483*91f16700Schasinglulu int sd_cmd36(struct sd_handle *handle, uint32_t end)
484*91f16700Schasinglulu {
485*91f16700Schasinglulu 	int res;
486*91f16700Schasinglulu 	uint32_t argument, options;
487*91f16700Schasinglulu 	struct sd_resp resp;
488*91f16700Schasinglulu 
489*91f16700Schasinglulu 	res = card_sts_resp(handle, &resp.cardStatus);
490*91f16700Schasinglulu 	if (res != SD_OK)
491*91f16700Schasinglulu 		return res;
492*91f16700Schasinglulu 
493*91f16700Schasinglulu 	argument = end;
494*91f16700Schasinglulu 
495*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
496*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK |
497*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
498*91f16700Schasinglulu 
499*91f16700Schasinglulu 	/* send cmd and parse result */
500*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_ERASE_GROUP_END,
501*91f16700Schasinglulu 		       argument, options, &resp);
502*91f16700Schasinglulu 
503*91f16700Schasinglulu 	if (res != SD_OK)
504*91f16700Schasinglulu 		return res;
505*91f16700Schasinglulu 
506*91f16700Schasinglulu 	return res;
507*91f16700Schasinglulu }
508*91f16700Schasinglulu 
509*91f16700Schasinglulu int sd_cmd38(struct sd_handle *handle)
510*91f16700Schasinglulu {
511*91f16700Schasinglulu 	int res;
512*91f16700Schasinglulu 	uint32_t argument, options;
513*91f16700Schasinglulu 	struct sd_resp resp;
514*91f16700Schasinglulu 
515*91f16700Schasinglulu 	res = card_sts_resp(handle, &resp.cardStatus);
516*91f16700Schasinglulu 	if (res != SD_OK)
517*91f16700Schasinglulu 		return res;
518*91f16700Schasinglulu 
519*91f16700Schasinglulu 	argument = 0;
520*91f16700Schasinglulu 
521*91f16700Schasinglulu 	options = (SD_CMDR_RSP_TYPE_R1b_5b << SD_CMDR_RSP_TYPE_S) |
522*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK |
523*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
524*91f16700Schasinglulu 
525*91f16700Schasinglulu 	/* send cmd and parse result */
526*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_ERASE, argument, options, &resp);
527*91f16700Schasinglulu 
528*91f16700Schasinglulu 	if (res != SD_OK)
529*91f16700Schasinglulu 		return res;
530*91f16700Schasinglulu 
531*91f16700Schasinglulu 	return res;
532*91f16700Schasinglulu }
533*91f16700Schasinglulu #endif
534*91f16700Schasinglulu 
535*91f16700Schasinglulu #ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
536*91f16700Schasinglulu 
537*91f16700Schasinglulu int sd_cmd24(struct sd_handle *handle,
538*91f16700Schasinglulu 	     uint32_t addr, uint32_t len, uint8_t *buffer)
539*91f16700Schasinglulu {
540*91f16700Schasinglulu 	int res;
541*91f16700Schasinglulu 	uint32_t argument, options, ntry;
542*91f16700Schasinglulu 	struct sd_resp resp;
543*91f16700Schasinglulu 
544*91f16700Schasinglulu 	ntry = 0;
545*91f16700Schasinglulu 	do {
546*91f16700Schasinglulu 		res = sd_cmd13(handle, &resp.cardStatus);
547*91f16700Schasinglulu 		if (res != SD_OK) {
548*91f16700Schasinglulu 			EMMC_TRACE(
549*91f16700Schasinglulu 				"cmd 13 failed before cmd24: rca 0x%0x, return %d, response 0x%0x\n",
550*91f16700Schasinglulu 				handle->device->ctrl.rca, res, &resp.cardStatus);
551*91f16700Schasinglulu 			return res;
552*91f16700Schasinglulu 		}
553*91f16700Schasinglulu 
554*91f16700Schasinglulu 		if (resp.cardStatus & 0x100)
555*91f16700Schasinglulu 			break;
556*91f16700Schasinglulu 
557*91f16700Schasinglulu 		EMMC_TRACE("cmd13 rsp:0x%08x before cmd24\n", resp.cardStatus);
558*91f16700Schasinglulu 
559*91f16700Schasinglulu 		if (ntry > handle->device->cfg.retryLimit) {
560*91f16700Schasinglulu 			EMMC_TRACE("cmd13 retry reach limit %d\n",
561*91f16700Schasinglulu 				   handle->device->cfg.retryLimit);
562*91f16700Schasinglulu 			return SD_CMD_TIMEOUT;
563*91f16700Schasinglulu 		}
564*91f16700Schasinglulu 
565*91f16700Schasinglulu 		ntry++;
566*91f16700Schasinglulu 		EMMC_TRACE("cmd13 retry %d\n", ntry);
567*91f16700Schasinglulu 
568*91f16700Schasinglulu 		SD_US_DELAY(1000);
569*91f16700Schasinglulu 
570*91f16700Schasinglulu 	} while (1);
571*91f16700Schasinglulu 
572*91f16700Schasinglulu 	data_xfer_setup(handle, buffer, len, SD_XFER_HOST_TO_CARD);
573*91f16700Schasinglulu 
574*91f16700Schasinglulu 	argument = addr;
575*91f16700Schasinglulu 
576*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
577*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK |
578*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
579*91f16700Schasinglulu 
580*91f16700Schasinglulu 	/* send cmd and parse result */
581*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_WRITE_BLOCK, argument, options, &resp);
582*91f16700Schasinglulu 
583*91f16700Schasinglulu 	if (res != SD_OK)
584*91f16700Schasinglulu 		return res;
585*91f16700Schasinglulu 
586*91f16700Schasinglulu 	res = process_data_xfer(handle, buffer, addr, len, SD_XFER_HOST_TO_CARD);
587*91f16700Schasinglulu 
588*91f16700Schasinglulu 	return res;
589*91f16700Schasinglulu }
590*91f16700Schasinglulu 
591*91f16700Schasinglulu int sd_cmd25(struct sd_handle *handle,
592*91f16700Schasinglulu 	     uint32_t addr, uint32_t len, uint8_t *buffer)
593*91f16700Schasinglulu {
594*91f16700Schasinglulu 	int res = SD_OK;
595*91f16700Schasinglulu 	uint32_t argument, options, ntry;
596*91f16700Schasinglulu 	struct sd_resp resp;
597*91f16700Schasinglulu 
598*91f16700Schasinglulu 	ntry = 0;
599*91f16700Schasinglulu 	do {
600*91f16700Schasinglulu 		res = sd_cmd13(handle, &resp.cardStatus);
601*91f16700Schasinglulu 		if (res != SD_OK) {
602*91f16700Schasinglulu 			EMMC_TRACE(
603*91f16700Schasinglulu 				"cmd 13 failed before cmd25: rca 0x%0x, return %d, response 0x%0x\n",
604*91f16700Schasinglulu 				handle->device->ctrl.rca, res, &resp.cardStatus);
605*91f16700Schasinglulu 			return res;
606*91f16700Schasinglulu 		}
607*91f16700Schasinglulu 
608*91f16700Schasinglulu 		if (resp.cardStatus & 0x100)
609*91f16700Schasinglulu 			break;
610*91f16700Schasinglulu 
611*91f16700Schasinglulu 		EMMC_TRACE("cmd13 rsp:0x%08x before cmd25\n", resp.cardStatus);
612*91f16700Schasinglulu 
613*91f16700Schasinglulu 		if (ntry > handle->device->cfg.retryLimit) {
614*91f16700Schasinglulu 			EMMC_TRACE("cmd13 retry reach limit %d\n",
615*91f16700Schasinglulu 				   handle->device->cfg.retryLimit);
616*91f16700Schasinglulu 			return SD_CMD_TIMEOUT;
617*91f16700Schasinglulu 		}
618*91f16700Schasinglulu 
619*91f16700Schasinglulu 		ntry++;
620*91f16700Schasinglulu 		EMMC_TRACE("cmd13 retry %d\n", ntry);
621*91f16700Schasinglulu 
622*91f16700Schasinglulu 		SD_US_DELAY(1000);
623*91f16700Schasinglulu 	} while (1);
624*91f16700Schasinglulu 
625*91f16700Schasinglulu 	data_xfer_setup(handle, buffer, len, SD_XFER_HOST_TO_CARD);
626*91f16700Schasinglulu 
627*91f16700Schasinglulu 	argument = addr;
628*91f16700Schasinglulu 
629*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
630*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_MSBS_MASK |
631*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK | SD4_EMMC_TOP_CMD_BCEN_MASK |
632*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CRC_EN_MASK |
633*91f16700Schasinglulu 		  BIT(SD4_EMMC_TOP_CMD_ACMDEN_SHIFT);
634*91f16700Schasinglulu 
635*91f16700Schasinglulu 	/* send cmd and parse result */
636*91f16700Schasinglulu 	res = send_cmd(handle, SD_CMD_WRITE_MULTIPLE_BLOCK,
637*91f16700Schasinglulu 		       argument, options, &resp);
638*91f16700Schasinglulu 
639*91f16700Schasinglulu 	if (res != SD_OK)
640*91f16700Schasinglulu 		return res;
641*91f16700Schasinglulu 
642*91f16700Schasinglulu 	res = process_data_xfer(handle, buffer, addr, len, SD_XFER_HOST_TO_CARD);
643*91f16700Schasinglulu 
644*91f16700Schasinglulu 	return res;
645*91f16700Schasinglulu }
646*91f16700Schasinglulu #endif /* INCLUDE_EMMC_DRIVER_WRITE_CODE */
647*91f16700Schasinglulu 
648*91f16700Schasinglulu int mmc_cmd6(struct sd_handle *handle, uint32_t argument)
649*91f16700Schasinglulu {
650*91f16700Schasinglulu 	int res;
651*91f16700Schasinglulu 	uint32_t options;
652*91f16700Schasinglulu 	struct sd_resp resp;
653*91f16700Schasinglulu 
654*91f16700Schasinglulu 	options = SD_CMDR_RSP_TYPE_R1b_5b << SD_CMDR_RSP_TYPE_S |
655*91f16700Schasinglulu 		  SD4_EMMC_TOP_CMD_CCHK_EN_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK;
656*91f16700Schasinglulu 
657*91f16700Schasinglulu 	EMMC_TRACE("Sending CMD6 with argument 0x%X\n", argument);
658*91f16700Schasinglulu 
659*91f16700Schasinglulu 	/* send cmd and parse result */
660*91f16700Schasinglulu 	res = send_cmd(handle, SD_ACMD_SET_BUS_WIDTH, argument, options, &resp);
661*91f16700Schasinglulu 
662*91f16700Schasinglulu 	/*
663*91f16700Schasinglulu 	 * For R1b type response:
664*91f16700Schasinglulu 	 * controller issues a COMMAND COMPLETE interrupt when the R1
665*91f16700Schasinglulu 	 * response is received,
666*91f16700Schasinglulu 	 * then controller monitors DAT0 for busy status,
667*91f16700Schasinglulu 	 * controller issues a TRANSFER COMPLETE interrupt when busy signal
668*91f16700Schasinglulu 	 * clears.
669*91f16700Schasinglulu 	 */
670*91f16700Schasinglulu 	wait_for_event(handle,
671*91f16700Schasinglulu 		       SD4_EMMC_TOP_INTR_TXDONE_MASK | SD_ERR_INTERRUPTS,
672*91f16700Schasinglulu 		       handle->device->cfg.wfe_retry);
673*91f16700Schasinglulu 
674*91f16700Schasinglulu 	if (res == SD_OK) {
675*91f16700Schasinglulu 		/* Check result of Cmd6 using Cmd13 to check card status */
676*91f16700Schasinglulu 
677*91f16700Schasinglulu 		/* Check status using Cmd13 */
678*91f16700Schasinglulu 		res = sd_cmd13(handle, &resp.cardStatus);
679*91f16700Schasinglulu 
680*91f16700Schasinglulu 		if (res == SD_OK) {
681*91f16700Schasinglulu 			/* Check bit 7 (SWITCH_ERROR) in card status */
682*91f16700Schasinglulu 			if ((resp.cardStatus & 0x80) != 0) {
683*91f16700Schasinglulu 				EMMC_TRACE("cmd6 failed: SWITCH_ERROR\n");
684*91f16700Schasinglulu 				res = SD_FAIL;
685*91f16700Schasinglulu 			}
686*91f16700Schasinglulu 		} else {
687*91f16700Schasinglulu 			EMMC_TRACE("cmd13 failed after cmd6: ");
688*91f16700Schasinglulu 			EMMC_TRACE("rca 0x%0x, return %d, response 0x%0x\n",
689*91f16700Schasinglulu 				handle->device->ctrl.rca, res, resp.cardStatus);
690*91f16700Schasinglulu 		}
691*91f16700Schasinglulu 	}
692*91f16700Schasinglulu 
693*91f16700Schasinglulu 	return res;
694*91f16700Schasinglulu }
695*91f16700Schasinglulu 
696*91f16700Schasinglulu 
697*91f16700Schasinglulu #define SD_BUSY_CHECK		0x00203000
698*91f16700Schasinglulu #define DAT0_LEVEL_MASK		0x100000	/* bit20 in PSTATE */
699*91f16700Schasinglulu #define DEV_BUSY_TIMEOUT	600000		/* 60 Sec : 600000 * 100us */
700*91f16700Schasinglulu 
701*91f16700Schasinglulu int send_cmd(struct sd_handle *handle, uint32_t cmdIndex, uint32_t argument,
702*91f16700Schasinglulu 	     uint32_t options, struct sd_resp *resp)
703*91f16700Schasinglulu {
704*91f16700Schasinglulu 	int status = SD_OK;
705*91f16700Schasinglulu 	uint32_t event = 0, present, timeout = 0, retry = 0, mask = 3;
706*91f16700Schasinglulu 	uint32_t temp_resp[4];
707*91f16700Schasinglulu 
708*91f16700Schasinglulu 	if (handle == NULL) {
709*91f16700Schasinglulu 		EMMC_TRACE("Invalid handle for cmd%d\n", cmdIndex);
710*91f16700Schasinglulu 		return SD_INVALID_HANDLE;
711*91f16700Schasinglulu 	}
712*91f16700Schasinglulu 
713*91f16700Schasinglulu 	mask = (SD_BUSY_CHECK & options) ? 3 : 1;
714*91f16700Schasinglulu 
715*91f16700Schasinglulu RETRY_WRITE_CMD:
716*91f16700Schasinglulu 	do {
717*91f16700Schasinglulu 		/* Make sure it is ok to send command */
718*91f16700Schasinglulu 		present =
719*91f16700Schasinglulu 		    chal_sd_get_present_status((CHAL_HANDLE *) handle->device);
720*91f16700Schasinglulu 		timeout++;
721*91f16700Schasinglulu 
722*91f16700Schasinglulu 		if (present & mask)
723*91f16700Schasinglulu 			SD_US_DELAY(1000);
724*91f16700Schasinglulu 		else
725*91f16700Schasinglulu 			break;
726*91f16700Schasinglulu 
727*91f16700Schasinglulu 	} while (timeout < EMMC_BUSY_CMD_TIMEOUT_MS);
728*91f16700Schasinglulu 
729*91f16700Schasinglulu 	if (timeout >= EMMC_BUSY_CMD_TIMEOUT_MS) {
730*91f16700Schasinglulu 		status = SD_CMD_MISSING;
731*91f16700Schasinglulu 		EMMC_TRACE("cmd%d timedout %dms\n", cmdIndex, timeout);
732*91f16700Schasinglulu 	}
733*91f16700Schasinglulu 
734*91f16700Schasinglulu 	/* Reset both DAT and CMD line if only of them are stuck */
735*91f16700Schasinglulu 	if (present & mask)
736*91f16700Schasinglulu 		check_error(handle, SD4_EMMC_TOP_INTR_CMDERROR_MASK);
737*91f16700Schasinglulu 
738*91f16700Schasinglulu 	handle->device->ctrl.argReg = argument;
739*91f16700Schasinglulu 	chal_sd_send_cmd((CHAL_HANDLE *) handle->device, cmdIndex,
740*91f16700Schasinglulu 			 handle->device->ctrl.argReg, options);
741*91f16700Schasinglulu 
742*91f16700Schasinglulu 	handle->device->ctrl.cmdIndex = cmdIndex;
743*91f16700Schasinglulu 
744*91f16700Schasinglulu 	event = wait_for_event(handle,
745*91f16700Schasinglulu 			       (SD4_EMMC_TOP_INTR_CMDDONE_MASK |
746*91f16700Schasinglulu 				SD_ERR_INTERRUPTS),
747*91f16700Schasinglulu 			       handle->device->cfg.wfe_retry);
748*91f16700Schasinglulu 
749*91f16700Schasinglulu 	if (handle->device->ctrl.cmdStatus == SD_CMD_MISSING) {
750*91f16700Schasinglulu 		retry++;
751*91f16700Schasinglulu 
752*91f16700Schasinglulu 		if (retry >= handle->device->cfg.retryLimit) {
753*91f16700Schasinglulu 			status = SD_CMD_MISSING;
754*91f16700Schasinglulu 			EMMC_TRACE("cmd%d retry reaches the limit %d\n",
755*91f16700Schasinglulu 				   cmdIndex, retry);
756*91f16700Schasinglulu 		} else {
757*91f16700Schasinglulu 			/* reset both DAT & CMD line if one of them is stuck */
758*91f16700Schasinglulu 			present = chal_sd_get_present_status((CHAL_HANDLE *)
759*91f16700Schasinglulu 							     handle->device);
760*91f16700Schasinglulu 
761*91f16700Schasinglulu 			if (present & mask)
762*91f16700Schasinglulu 				check_error(handle,
763*91f16700Schasinglulu 					    SD4_EMMC_TOP_INTR_CMDERROR_MASK);
764*91f16700Schasinglulu 
765*91f16700Schasinglulu 			EMMC_TRACE("cmd%d retry %d PSTATE[0x%08x]\n",
766*91f16700Schasinglulu 				   cmdIndex, retry,
767*91f16700Schasinglulu 				   chal_sd_get_present_status((CHAL_HANDLE *)
768*91f16700Schasinglulu 							      handle->device));
769*91f16700Schasinglulu 			goto RETRY_WRITE_CMD;
770*91f16700Schasinglulu 		}
771*91f16700Schasinglulu 	}
772*91f16700Schasinglulu 
773*91f16700Schasinglulu 	if (handle->device->ctrl.cmdStatus == SD_OK) {
774*91f16700Schasinglulu 		if (resp != NULL) {
775*91f16700Schasinglulu 			status =
776*91f16700Schasinglulu 			    chal_sd_get_response((CHAL_HANDLE *) handle->device,
777*91f16700Schasinglulu 						 temp_resp);
778*91f16700Schasinglulu 			process_cmd_response(handle,
779*91f16700Schasinglulu 					     handle->device->ctrl.cmdIndex,
780*91f16700Schasinglulu 					     temp_resp[0], temp_resp[1],
781*91f16700Schasinglulu 					     temp_resp[2], temp_resp[3], resp);
782*91f16700Schasinglulu 		}
783*91f16700Schasinglulu 
784*91f16700Schasinglulu 		/* Check Device busy after CMD */
785*91f16700Schasinglulu 		if ((cmdIndex == 5) || (cmdIndex == 6) || (cmdIndex == 7) ||
786*91f16700Schasinglulu 		    (cmdIndex == 28) || (cmdIndex == 29) || (cmdIndex == 38)) {
787*91f16700Schasinglulu 
788*91f16700Schasinglulu 			timeout = 0;
789*91f16700Schasinglulu 			do {
790*91f16700Schasinglulu 				present =
791*91f16700Schasinglulu 				    chal_sd_get_present_status((CHAL_HANDLE *)
792*91f16700Schasinglulu 							       handle->device);
793*91f16700Schasinglulu 
794*91f16700Schasinglulu 				timeout++;
795*91f16700Schasinglulu 
796*91f16700Schasinglulu 				/* Dat[0]:bit20 low means device busy */
797*91f16700Schasinglulu 				if ((present & DAT0_LEVEL_MASK) == 0) {
798*91f16700Schasinglulu 					EMMC_TRACE("Device busy: ");
799*91f16700Schasinglulu 					EMMC_TRACE(
800*91f16700Schasinglulu 					  "cmd%d arg:0x%08x: PSTATE[0x%08x]\n",
801*91f16700Schasinglulu 					  cmdIndex, argument, present);
802*91f16700Schasinglulu 					SD_US_DELAY(100);
803*91f16700Schasinglulu 				} else {
804*91f16700Schasinglulu 					break;
805*91f16700Schasinglulu 				}
806*91f16700Schasinglulu 			} while (timeout < DEV_BUSY_TIMEOUT);
807*91f16700Schasinglulu 		}
808*91f16700Schasinglulu 	} else if (handle->device->ctrl.cmdStatus &&
809*91f16700Schasinglulu 		   handle->device->ctrl.cmdStatus != SD_CMD_MISSING) {
810*91f16700Schasinglulu 		retry++;
811*91f16700Schasinglulu 		status = check_error(handle, handle->device->ctrl.cmdStatus);
812*91f16700Schasinglulu 
813*91f16700Schasinglulu 		EMMC_TRACE(
814*91f16700Schasinglulu 			"cmd%d error: cmdStatus:0x%08x error_status:0x%08x\n",
815*91f16700Schasinglulu 			cmdIndex, handle->device->ctrl.cmdStatus, status);
816*91f16700Schasinglulu 
817*91f16700Schasinglulu 		if ((handle->device->ctrl.cmdIndex == 1) ||
818*91f16700Schasinglulu 		    (handle->device->ctrl.cmdIndex == 5)) {
819*91f16700Schasinglulu 			status = event;
820*91f16700Schasinglulu 		} else if ((handle->device->ctrl.cmdIndex == 7) ||
821*91f16700Schasinglulu 			   (handle->device->ctrl.cmdIndex == 41)) {
822*91f16700Schasinglulu 			status = event;
823*91f16700Schasinglulu 		} else if ((status == SD_ERROR_RECOVERABLE) &&
824*91f16700Schasinglulu 			   (retry < handle->device->cfg.retryLimit)) {
825*91f16700Schasinglulu 			EMMC_TRACE("cmd%d recoverable error ", cmdIndex);
826*91f16700Schasinglulu 			EMMC_TRACE("retry %d PSTATE[0x%08x].\n", retry,
827*91f16700Schasinglulu 				   chal_sd_get_present_status((CHAL_HANDLE *)
828*91f16700Schasinglulu 							      handle->device));
829*91f16700Schasinglulu 			goto RETRY_WRITE_CMD;
830*91f16700Schasinglulu 		} else {
831*91f16700Schasinglulu 			EMMC_TRACE("cmd%d retry reaches the limit %d\n",
832*91f16700Schasinglulu 				   cmdIndex, retry);
833*91f16700Schasinglulu 			status = event;
834*91f16700Schasinglulu 		}
835*91f16700Schasinglulu 	}
836*91f16700Schasinglulu 
837*91f16700Schasinglulu 	handle->device->ctrl.blkReg = 0;
838*91f16700Schasinglulu 	/* clear error status for next command */
839*91f16700Schasinglulu 	handle->device->ctrl.cmdStatus = 0;
840*91f16700Schasinglulu 
841*91f16700Schasinglulu 	return status;
842*91f16700Schasinglulu }
843