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