xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/rpi3/sdhost/rpi3_sdhost.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2019, Linaro Limited
3*54fd6939SJiyong Park  * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <[email protected]>
4*54fd6939SJiyong Park  *
5*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
6*54fd6939SJiyong Park  */
7*54fd6939SJiyong Park 
8*54fd6939SJiyong Park #include <arch.h>
9*54fd6939SJiyong Park #include <arch_helpers.h>
10*54fd6939SJiyong Park #include <assert.h>
11*54fd6939SJiyong Park #include <common/debug.h>
12*54fd6939SJiyong Park #include <lib/mmio.h>
13*54fd6939SJiyong Park #include <drivers/delay_timer.h>
14*54fd6939SJiyong Park #include <drivers/rpi3/sdhost/rpi3_sdhost.h>
15*54fd6939SJiyong Park #include <drivers/mmc.h>
16*54fd6939SJiyong Park #include <drivers/rpi3/gpio/rpi3_gpio.h>
17*54fd6939SJiyong Park #include <errno.h>
18*54fd6939SJiyong Park #include <string.h>
19*54fd6939SJiyong Park 
20*54fd6939SJiyong Park static void rpi3_sdhost_initialize(void);
21*54fd6939SJiyong Park static int rpi3_sdhost_send_cmd(struct mmc_cmd *cmd);
22*54fd6939SJiyong Park static int rpi3_sdhost_set_ios(unsigned int clk, unsigned int width);
23*54fd6939SJiyong Park static int rpi3_sdhost_prepare(int lba, uintptr_t buf, size_t size);
24*54fd6939SJiyong Park static int rpi3_sdhost_read(int lba, uintptr_t buf, size_t size);
25*54fd6939SJiyong Park static int rpi3_sdhost_write(int lba, uintptr_t buf, size_t size);
26*54fd6939SJiyong Park 
27*54fd6939SJiyong Park static const struct mmc_ops rpi3_sdhost_ops = {
28*54fd6939SJiyong Park 	.init		= rpi3_sdhost_initialize,
29*54fd6939SJiyong Park 	.send_cmd	= rpi3_sdhost_send_cmd,
30*54fd6939SJiyong Park 	.set_ios	= rpi3_sdhost_set_ios,
31*54fd6939SJiyong Park 	.prepare	= rpi3_sdhost_prepare,
32*54fd6939SJiyong Park 	.read		= rpi3_sdhost_read,
33*54fd6939SJiyong Park 	.write		= rpi3_sdhost_write,
34*54fd6939SJiyong Park };
35*54fd6939SJiyong Park 
36*54fd6939SJiyong Park static struct rpi3_sdhost_params rpi3_sdhost_params;
37*54fd6939SJiyong Park 
38*54fd6939SJiyong Park /**
39*54fd6939SJiyong Park  * Wait for command being processed.
40*54fd6939SJiyong Park  *
41*54fd6939SJiyong Park  * This function waits the command being processed. It compares
42*54fd6939SJiyong Park  * the ENABLE flag of the HC_COMMAND register. When ENABLE flag disappeared
43*54fd6939SJiyong Park  * it means the command is processed by the SDHOST.
44*54fd6939SJiyong Park  * The timeout is currently 1000*100 us = 100 ms.
45*54fd6939SJiyong Park  *
46*54fd6939SJiyong Park  * @return 0: command finished. 1: command timed out.
47*54fd6939SJiyong Park  */
rpi3_sdhost_waitcommand(void)48*54fd6939SJiyong Park static int rpi3_sdhost_waitcommand(void)
49*54fd6939SJiyong Park {
50*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
51*54fd6939SJiyong Park 
52*54fd6939SJiyong Park 	volatile int timeout = 1000;
53*54fd6939SJiyong Park 
54*54fd6939SJiyong Park 	while ((mmio_read_32(reg_base + HC_COMMAND) & HC_CMD_ENABLE)
55*54fd6939SJiyong Park 	       && (--timeout > 0)) {
56*54fd6939SJiyong Park 		udelay(100);
57*54fd6939SJiyong Park 	}
58*54fd6939SJiyong Park 
59*54fd6939SJiyong Park 	return ((timeout > 0) ? 0 : (-(ETIMEDOUT)));
60*54fd6939SJiyong Park }
61*54fd6939SJiyong Park 
62*54fd6939SJiyong Park /**
63*54fd6939SJiyong Park  * Send the command and argument to the SDHOST
64*54fd6939SJiyong Park  *
65*54fd6939SJiyong Park  * This function will wait for the previous command finished. And then
66*54fd6939SJiyong Park  * clear any error status of previous command. And then
67*54fd6939SJiyong Park  * send out the command and args. The command will be turned on the ENABLE
68*54fd6939SJiyong Park  * flag before sending out.
69*54fd6939SJiyong Park  */
send_command_raw(unsigned int cmd,unsigned int arg)70*54fd6939SJiyong Park static void send_command_raw(unsigned int cmd, unsigned int arg)
71*54fd6939SJiyong Park {
72*54fd6939SJiyong Park 	unsigned int status;
73*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
74*54fd6939SJiyong Park 
75*54fd6939SJiyong Park 	/* wait for previous command finish */
76*54fd6939SJiyong Park 	rpi3_sdhost_waitcommand();
77*54fd6939SJiyong Park 
78*54fd6939SJiyong Park 	/* clean error status */
79*54fd6939SJiyong Park 	status = mmio_read_32(reg_base + HC_HOSTSTATUS);
80*54fd6939SJiyong Park 	if (status & HC_HSTST_MASK_ERROR_ALL)
81*54fd6939SJiyong Park 		mmio_write_32(reg_base + HC_HOSTSTATUS, status);
82*54fd6939SJiyong Park 
83*54fd6939SJiyong Park 	/* recording the command */
84*54fd6939SJiyong Park 	rpi3_sdhost_params.current_cmd = cmd & HC_CMD_COMMAND_MASK;
85*54fd6939SJiyong Park 
86*54fd6939SJiyong Park 	/* send the argument and command */
87*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_ARGUMENT, arg);
88*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_COMMAND, cmd | HC_CMD_ENABLE);
89*54fd6939SJiyong Park }
90*54fd6939SJiyong Park 
91*54fd6939SJiyong Park /**
92*54fd6939SJiyong Park  * Send the command and argument to the SDHOST, decorated with control
93*54fd6939SJiyong Park  * flags.
94*54fd6939SJiyong Park  *
95*54fd6939SJiyong Park  * This function will use send_command_raw to send the commands to SDHOST.
96*54fd6939SJiyong Park  * But before sending it will decorate the command with control flags specific
97*54fd6939SJiyong Park  * to SDHOST.
98*54fd6939SJiyong Park  */
send_command_decorated(unsigned int cmd,unsigned int arg)99*54fd6939SJiyong Park static void send_command_decorated(unsigned int cmd, unsigned int arg)
100*54fd6939SJiyong Park {
101*54fd6939SJiyong Park 	unsigned int cmd_flags = 0;
102*54fd6939SJiyong Park 
103*54fd6939SJiyong Park 	switch (cmd & HC_CMD_COMMAND_MASK) {
104*54fd6939SJiyong Park 	case MMC_CMD(0):
105*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_RESPONSE_NONE;
106*54fd6939SJiyong Park 		break;
107*54fd6939SJiyong Park 	case MMC_ACMD(51):
108*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_READ;
109*54fd6939SJiyong Park 		break;
110*54fd6939SJiyong Park 	case MMC_CMD(8):
111*54fd6939SJiyong Park 	case MMC_CMD(11):
112*54fd6939SJiyong Park 	case MMC_CMD(17):
113*54fd6939SJiyong Park 	case MMC_CMD(18):
114*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_READ;
115*54fd6939SJiyong Park 		break;
116*54fd6939SJiyong Park 	case MMC_CMD(20):
117*54fd6939SJiyong Park 	case MMC_CMD(24):
118*54fd6939SJiyong Park 	case MMC_CMD(25):
119*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_WRITE;
120*54fd6939SJiyong Park 		break;
121*54fd6939SJiyong Park 	case MMC_CMD(12):
122*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_BUSY;
123*54fd6939SJiyong Park 		break;
124*54fd6939SJiyong Park 	default:
125*54fd6939SJiyong Park 		break;
126*54fd6939SJiyong Park 	}
127*54fd6939SJiyong Park 	send_command_raw(cmd | cmd_flags, arg);
128*54fd6939SJiyong Park }
129*54fd6939SJiyong Park 
130*54fd6939SJiyong Park /**
131*54fd6939SJiyong Park  * drains the FIFO on DATA port
132*54fd6939SJiyong Park  *
133*54fd6939SJiyong Park  * This function drains any data left in the DATA port.
134*54fd6939SJiyong Park  */
rpi3_drain_fifo(void)135*54fd6939SJiyong Park static void rpi3_drain_fifo(void)
136*54fd6939SJiyong Park {
137*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
138*54fd6939SJiyong Park 	volatile int timeout = 100000;
139*54fd6939SJiyong Park 
140*54fd6939SJiyong Park 	rpi3_sdhost_waitcommand();
141*54fd6939SJiyong Park 
142*54fd6939SJiyong Park 	while (mmio_read_32(reg_base + HC_HOSTSTATUS) & HC_HSTST_HAVEDATA) {
143*54fd6939SJiyong Park 		mmio_read_32(reg_base + HC_DATAPORT);
144*54fd6939SJiyong Park 		udelay(100);
145*54fd6939SJiyong Park 	}
146*54fd6939SJiyong Park 
147*54fd6939SJiyong Park 	while (1) {
148*54fd6939SJiyong Park 		uint32_t edm, fsm;
149*54fd6939SJiyong Park 
150*54fd6939SJiyong Park 		edm = mmio_read_32(reg_base + HC_DEBUG);
151*54fd6939SJiyong Park 		fsm = edm & HC_DBG_FSM_MASK;
152*54fd6939SJiyong Park 
153*54fd6939SJiyong Park 		if ((fsm == HC_DBG_FSM_IDENTMODE) ||
154*54fd6939SJiyong Park 		    (fsm == HC_DBG_FSM_DATAMODE))
155*54fd6939SJiyong Park 			break;
156*54fd6939SJiyong Park 
157*54fd6939SJiyong Park 		if ((fsm == HC_DBG_FSM_READWAIT) ||
158*54fd6939SJiyong Park 		    (fsm == HC_DBG_FSM_WRITESTART1) ||
159*54fd6939SJiyong Park 		    (fsm == HC_DBG_FSM_READDATA)) {
160*54fd6939SJiyong Park 			mmio_write_32(reg_base + HC_DEBUG,
161*54fd6939SJiyong Park 				      edm | HC_DBG_FORCE_DATA_MODE);
162*54fd6939SJiyong Park 			break;
163*54fd6939SJiyong Park 		}
164*54fd6939SJiyong Park 
165*54fd6939SJiyong Park 		if (--timeout <= 0) {
166*54fd6939SJiyong Park 			ERROR("rpi3_sdhost: %s cannot recover stat\n",
167*54fd6939SJiyong Park 			      __func__);
168*54fd6939SJiyong Park 			return;
169*54fd6939SJiyong Park 		}
170*54fd6939SJiyong Park 	}
171*54fd6939SJiyong Park }
172*54fd6939SJiyong Park 
173*54fd6939SJiyong Park /**
174*54fd6939SJiyong Park  * Dump SDHOST registers
175*54fd6939SJiyong Park  */
rpi3_sdhost_print_regs(void)176*54fd6939SJiyong Park static void rpi3_sdhost_print_regs(void)
177*54fd6939SJiyong Park {
178*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
179*54fd6939SJiyong Park 
180*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_COMMAND:        0x%08x\n",
181*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_COMMAND));
182*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_ARGUMENT:       0x%08x\n",
183*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_ARGUMENT));
184*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_TIMEOUTCOUNTER: 0x%08x\n",
185*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_TIMEOUTCOUNTER));
186*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_CLOCKDIVISOR:   0x%08x\n",
187*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_CLOCKDIVISOR));
188*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_RESPONSE_0:     0x%08x\n",
189*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_RESPONSE_0));
190*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_RESPONSE_1:     0x%08x\n",
191*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_RESPONSE_1));
192*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_RESPONSE_2:     0x%08x\n",
193*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_RESPONSE_2));
194*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_RESPONSE_3:     0x%08x\n",
195*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_RESPONSE_3));
196*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_HOSTSTATUS:     0x%08x\n",
197*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_HOSTSTATUS));
198*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_POWER:          0x%08x\n",
199*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_POWER));
200*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_DEBUG:          0x%08x\n",
201*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_DEBUG));
202*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_HOSTCONFIG:     0x%08x\n",
203*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_HOSTCONFIG));
204*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_BLOCKSIZE:      0x%08x\n",
205*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_BLOCKSIZE));
206*54fd6939SJiyong Park 	INFO("rpi3_sdhost: HC_BLOCKCOUNT:     0x%08x\n",
207*54fd6939SJiyong Park 	     mmio_read_32(reg_base + HC_BLOCKCOUNT));
208*54fd6939SJiyong Park }
209*54fd6939SJiyong Park 
210*54fd6939SJiyong Park /**
211*54fd6939SJiyong Park  * Reset SDHOST
212*54fd6939SJiyong Park  */
rpi3_sdhost_reset(void)213*54fd6939SJiyong Park static void rpi3_sdhost_reset(void)
214*54fd6939SJiyong Park {
215*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
216*54fd6939SJiyong Park 	unsigned int dbg;
217*54fd6939SJiyong Park 	uint32_t tmp1;
218*54fd6939SJiyong Park 
219*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_POWER, 0);
220*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_COMMAND, 0);
221*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_ARGUMENT, 0);
222*54fd6939SJiyong Park 
223*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_TIMEOUTCOUNTER, HC_TIMEOUT_DEFAULT);
224*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_CLOCKDIVISOR, 0);
225*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_HOSTSTATUS, HC_HSTST_RESET);
226*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_HOSTCONFIG, 0);
227*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_BLOCKSIZE, 0);
228*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_BLOCKCOUNT, 0);
229*54fd6939SJiyong Park 
230*54fd6939SJiyong Park 	dbg = mmio_read_32(reg_base + HC_DEBUG);
231*54fd6939SJiyong Park 	dbg &= ~((HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_READ_SHIFT) |
232*54fd6939SJiyong Park 		 (HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_WRITE_SHIFT));
233*54fd6939SJiyong Park 	dbg |= (HC_FIFO_THRESH_READ << HC_DBG_FIFO_THRESH_READ_SHIFT) |
234*54fd6939SJiyong Park 		(HC_FIFO_THRESH_WRITE << HC_DBG_FIFO_THRESH_WRITE_SHIFT);
235*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_DEBUG, dbg);
236*54fd6939SJiyong Park 	mdelay(250);
237*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_POWER, 1);
238*54fd6939SJiyong Park 	mdelay(250);
239*54fd6939SJiyong Park 	rpi3_sdhost_params.clk_rate = 0;
240*54fd6939SJiyong Park 
241*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_MAXVAL);
242*54fd6939SJiyong Park 	tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG);
243*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1 | HC_HSTCF_INT_BUSY);
244*54fd6939SJiyong Park }
245*54fd6939SJiyong Park 
rpi3_sdhost_initialize(void)246*54fd6939SJiyong Park static void rpi3_sdhost_initialize(void)
247*54fd6939SJiyong Park {
248*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
249*54fd6939SJiyong Park 
250*54fd6939SJiyong Park 	assert((rpi3_sdhost_params.reg_base & MMC_BLOCK_MASK) == 0);
251*54fd6939SJiyong Park 
252*54fd6939SJiyong Park 	rpi3_sdhost_reset();
253*54fd6939SJiyong Park 
254*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_PREFERVAL);
255*54fd6939SJiyong Park 	udelay(300);
256*54fd6939SJiyong Park }
257*54fd6939SJiyong Park 
rpi3_sdhost_send_cmd(struct mmc_cmd * cmd)258*54fd6939SJiyong Park static int rpi3_sdhost_send_cmd(struct mmc_cmd *cmd)
259*54fd6939SJiyong Park {
260*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
261*54fd6939SJiyong Park 	int err = 0;
262*54fd6939SJiyong Park 	uint32_t cmd_idx;
263*54fd6939SJiyong Park 	uint32_t cmd_arg;
264*54fd6939SJiyong Park 	uint32_t cmd_flags = 0;
265*54fd6939SJiyong Park 	uint32_t intmask;
266*54fd6939SJiyong Park 
267*54fd6939SJiyong Park 	/* Wait for the command done */
268*54fd6939SJiyong Park 	err = rpi3_sdhost_waitcommand();
269*54fd6939SJiyong Park 	if (err != 0) {
270*54fd6939SJiyong Park 		WARN("previous command not done yet\n");
271*54fd6939SJiyong Park 		return err;
272*54fd6939SJiyong Park 	}
273*54fd6939SJiyong Park 
274*54fd6939SJiyong Park 	cmd_idx = cmd->cmd_idx & HC_CMD_COMMAND_MASK;
275*54fd6939SJiyong Park 
276*54fd6939SJiyong Park 	cmd_arg = cmd->cmd_arg;
277*54fd6939SJiyong Park 	if (cmd_idx == MMC_ACMD(51)) {
278*54fd6939SJiyong Park 		/* if previous cmd send to SDHOST is not MMC_CMD(55).
279*54fd6939SJiyong Park 		 * It means this MMC_ACMD(51) is a resend.
280*54fd6939SJiyong Park 		 * And we must also resend MMC_CMD(55) in this case
281*54fd6939SJiyong Park 		 */
282*54fd6939SJiyong Park 		if (rpi3_sdhost_params.current_cmd != MMC_CMD(55)) {
283*54fd6939SJiyong Park 			send_command_decorated(
284*54fd6939SJiyong Park 				MMC_CMD(55),
285*54fd6939SJiyong Park 				rpi3_sdhost_params.sdcard_rca <<
286*54fd6939SJiyong Park 				RCA_SHIFT_OFFSET);
287*54fd6939SJiyong Park 			rpi3_sdhost_params.mmc_app_cmd = 1;
288*54fd6939SJiyong Park 			rpi3_sdhost_waitcommand();
289*54fd6939SJiyong Park 
290*54fd6939SJiyong Park 			/* Also we need to call prepare to clean the buffer */
291*54fd6939SJiyong Park 			rpi3_sdhost_prepare(0, (uintptr_t)NULL, 8);
292*54fd6939SJiyong Park 		}
293*54fd6939SJiyong Park 	}
294*54fd6939SJiyong Park 
295*54fd6939SJiyong Park 	/* We ignore MMC_CMD(12) sending from the TF-A's MMC driver
296*54fd6939SJiyong Park 	 * because we send MMC_CMD(12) by ourselves.
297*54fd6939SJiyong Park 	 */
298*54fd6939SJiyong Park 	if (cmd_idx == MMC_CMD(12))
299*54fd6939SJiyong Park 		return 0;
300*54fd6939SJiyong Park 
301*54fd6939SJiyong Park 	if ((cmd->resp_type & MMC_RSP_136) &&
302*54fd6939SJiyong Park 	    (cmd->resp_type & MMC_RSP_BUSY)) {
303*54fd6939SJiyong Park 		ERROR("rpi3_sdhost: unsupported response type!\n");
304*54fd6939SJiyong Park 		return -(EOPNOTSUPP);
305*54fd6939SJiyong Park 	}
306*54fd6939SJiyong Park 
307*54fd6939SJiyong Park 	if (cmd->resp_type & MMC_RSP_48 && cmd->resp_type != MMC_RESPONSE_R2) {
308*54fd6939SJiyong Park 		/* 48-bit command
309*54fd6939SJiyong Park 		 * We don't need to set any flags here because it is default.
310*54fd6939SJiyong Park 		 */
311*54fd6939SJiyong Park 	} else if (cmd->resp_type & MMC_RSP_136) {
312*54fd6939SJiyong Park 		/* 136-bit command */
313*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_RESPONSE_LONG;
314*54fd6939SJiyong Park 	} else {
315*54fd6939SJiyong Park 		/* no respond command */
316*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_RESPONSE_NONE;
317*54fd6939SJiyong Park 	}
318*54fd6939SJiyong Park 
319*54fd6939SJiyong Park 	rpi3_sdhost_params.cmdbusy = 0;
320*54fd6939SJiyong Park 	if (cmd->resp_type & MMC_RSP_BUSY) {
321*54fd6939SJiyong Park 		cmd_flags |= HC_CMD_BUSY;
322*54fd6939SJiyong Park 		rpi3_sdhost_params.cmdbusy = 1;
323*54fd6939SJiyong Park 	}
324*54fd6939SJiyong Park 
325*54fd6939SJiyong Park 	if (rpi3_sdhost_params.mmc_app_cmd) {
326*54fd6939SJiyong Park 		switch (cmd_idx) {
327*54fd6939SJiyong Park 		case MMC_ACMD(41):
328*54fd6939SJiyong Park 			if (cmd_arg == OCR_HCS)
329*54fd6939SJiyong Park 				cmd_arg |= OCR_3_3_3_4;
330*54fd6939SJiyong Park 			break;
331*54fd6939SJiyong Park 		default:
332*54fd6939SJiyong Park 			break;
333*54fd6939SJiyong Park 		}
334*54fd6939SJiyong Park 		rpi3_sdhost_params.mmc_app_cmd = 0;
335*54fd6939SJiyong Park 	}
336*54fd6939SJiyong Park 
337*54fd6939SJiyong Park 	if (cmd_idx == MMC_CMD(55))
338*54fd6939SJiyong Park 		rpi3_sdhost_params.mmc_app_cmd = 1;
339*54fd6939SJiyong Park 
340*54fd6939SJiyong Park 	send_command_decorated(cmd_idx | cmd_flags, cmd_arg);
341*54fd6939SJiyong Park 
342*54fd6939SJiyong Park 	intmask = mmio_read_32(reg_base + HC_HOSTSTATUS);
343*54fd6939SJiyong Park 	if (rpi3_sdhost_params.cmdbusy && (intmask & HC_HSTST_INT_BUSY)) {
344*54fd6939SJiyong Park 		mmio_write_32(reg_base + HC_HOSTSTATUS, HC_HSTST_INT_BUSY);
345*54fd6939SJiyong Park 		rpi3_sdhost_params.cmdbusy = 0;
346*54fd6939SJiyong Park 	}
347*54fd6939SJiyong Park 
348*54fd6939SJiyong Park 	if (!(cmd_flags & HC_CMD_RESPONSE_NONE)) {
349*54fd6939SJiyong Park 		err = rpi3_sdhost_waitcommand();
350*54fd6939SJiyong Park 		if (err != 0)
351*54fd6939SJiyong Park 			ERROR("rpi3_sdhost: cmd cannot be finished\n");
352*54fd6939SJiyong Park 	}
353*54fd6939SJiyong Park 
354*54fd6939SJiyong Park 	cmd->resp_data[0] = mmio_read_32(reg_base + HC_RESPONSE_0);
355*54fd6939SJiyong Park 	cmd->resp_data[1] = mmio_read_32(reg_base + HC_RESPONSE_1);
356*54fd6939SJiyong Park 	cmd->resp_data[2] = mmio_read_32(reg_base + HC_RESPONSE_2);
357*54fd6939SJiyong Park 	cmd->resp_data[3] = mmio_read_32(reg_base + HC_RESPONSE_3);
358*54fd6939SJiyong Park 
359*54fd6939SJiyong Park 	if (mmio_read_32(reg_base + HC_COMMAND) & HC_CMD_FAILED) {
360*54fd6939SJiyong Park 		uint32_t sdhsts = mmio_read_32(reg_base + HC_HOSTSTATUS);
361*54fd6939SJiyong Park 
362*54fd6939SJiyong Park 		mmio_write_32(reg_base + HC_HOSTSTATUS,
363*54fd6939SJiyong Park 			      HC_HSTST_MASK_ERROR_ALL);
364*54fd6939SJiyong Park 
365*54fd6939SJiyong Park 		/*
366*54fd6939SJiyong Park 		 * If the command SEND_OP_COND returns with CRC7 error,
367*54fd6939SJiyong Park 		 * it can be considered as having completed successfully.
368*54fd6939SJiyong Park 		 */
369*54fd6939SJiyong Park 		if (!(sdhsts & HC_HSTST_ERROR_CRC7)
370*54fd6939SJiyong Park 		    || (cmd_idx != MMC_CMD(1))) {
371*54fd6939SJiyong Park 			if (sdhsts & HC_HSTST_TIMEOUT_CMD) {
372*54fd6939SJiyong Park 				ERROR("rpi3_sdhost: timeout status 0x%x\n",
373*54fd6939SJiyong Park 				      sdhsts);
374*54fd6939SJiyong Park 				err = -(ETIMEDOUT);
375*54fd6939SJiyong Park 			} else {
376*54fd6939SJiyong Park 				ERROR("rpi3_sdhost: unknown err, cmd = 0x%x\n",
377*54fd6939SJiyong Park 				      mmio_read_32(reg_base + HC_COMMAND));
378*54fd6939SJiyong Park 				ERROR("rpi3_sdhost status: 0x%x\n", sdhsts);
379*54fd6939SJiyong Park 				err = -(EILSEQ);
380*54fd6939SJiyong Park 			}
381*54fd6939SJiyong Park 		}
382*54fd6939SJiyong Park 	}
383*54fd6939SJiyong Park 
384*54fd6939SJiyong Park 	if ((!err) && (cmd_idx == MMC_CMD(3))) {
385*54fd6939SJiyong Park 		/* we keep the RCA in case to send MMC_CMD(55) ourselves */
386*54fd6939SJiyong Park 		rpi3_sdhost_params.sdcard_rca = (cmd->resp_data[0]
387*54fd6939SJiyong Park 						 & 0xFFFF0000U) >> 16;
388*54fd6939SJiyong Park 	}
389*54fd6939SJiyong Park 
390*54fd6939SJiyong Park 	return err;
391*54fd6939SJiyong Park }
392*54fd6939SJiyong Park 
rpi3_sdhost_set_clock(unsigned int clk)393*54fd6939SJiyong Park static int rpi3_sdhost_set_clock(unsigned int clk)
394*54fd6939SJiyong Park {
395*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
396*54fd6939SJiyong Park 	uint32_t max_clk = 250000000;
397*54fd6939SJiyong Park 	uint32_t div;
398*54fd6939SJiyong Park 
399*54fd6939SJiyong Park 	if (clk < 100000) {
400*54fd6939SJiyong Park 		mmio_write_32(reg_base + HC_CLOCKDIVISOR,
401*54fd6939SJiyong Park 			      HC_CLOCKDIVISOR_MAXVAL);
402*54fd6939SJiyong Park 		return 0;
403*54fd6939SJiyong Park 	}
404*54fd6939SJiyong Park 
405*54fd6939SJiyong Park 	div = max_clk / clk;
406*54fd6939SJiyong Park 	if (div < 2)
407*54fd6939SJiyong Park 		div = 2;
408*54fd6939SJiyong Park 
409*54fd6939SJiyong Park 	if ((max_clk / div) > clk)
410*54fd6939SJiyong Park 		div++;
411*54fd6939SJiyong Park 
412*54fd6939SJiyong Park 	div -= 2;
413*54fd6939SJiyong Park 	if (div > HC_CLOCKDIVISOR_MAXVAL)
414*54fd6939SJiyong Park 		div = HC_CLOCKDIVISOR_MAXVAL;
415*54fd6939SJiyong Park 
416*54fd6939SJiyong Park 	rpi3_sdhost_params.clk_rate = max_clk / (div + 2);
417*54fd6939SJiyong Park 	rpi3_sdhost_params.ns_per_fifo_word = (1000000000 /
418*54fd6939SJiyong Park 					       rpi3_sdhost_params.clk_rate)
419*54fd6939SJiyong Park 		* 8;
420*54fd6939SJiyong Park 
421*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_CLOCKDIVISOR, div);
422*54fd6939SJiyong Park 	return 0;
423*54fd6939SJiyong Park }
424*54fd6939SJiyong Park 
rpi3_sdhost_set_ios(unsigned int clk,unsigned int width)425*54fd6939SJiyong Park static int rpi3_sdhost_set_ios(unsigned int clk, unsigned int width)
426*54fd6939SJiyong Park {
427*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
428*54fd6939SJiyong Park 	uint32_t tmp1;
429*54fd6939SJiyong Park 
430*54fd6939SJiyong Park 	rpi3_sdhost_set_clock(clk);
431*54fd6939SJiyong Park 	VERBOSE("rpi3_sdhost: Changing clock to %dHz for data mode\n", clk);
432*54fd6939SJiyong Park 
433*54fd6939SJiyong Park 	if (width != MMC_BUS_WIDTH_4 && width != MMC_BUS_WIDTH_1) {
434*54fd6939SJiyong Park 		ERROR("rpi3_sdhost: width %d not supported\n", width);
435*54fd6939SJiyong Park 		return -(EOPNOTSUPP);
436*54fd6939SJiyong Park 	}
437*54fd6939SJiyong Park 	rpi3_sdhost_params.bus_width = width;
438*54fd6939SJiyong Park 
439*54fd6939SJiyong Park 	tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG);
440*54fd6939SJiyong Park 	tmp1 &= ~(HC_HSTCF_EXTBUS_4BIT);
441*54fd6939SJiyong Park 	if (rpi3_sdhost_params.bus_width == MMC_BUS_WIDTH_4)
442*54fd6939SJiyong Park 		tmp1 |= HC_HSTCF_EXTBUS_4BIT;
443*54fd6939SJiyong Park 
444*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1);
445*54fd6939SJiyong Park 	tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG);
446*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1 |
447*54fd6939SJiyong Park 		      HC_HSTCF_SLOW_CARD | HC_HSTCF_INTBUS_WIDE);
448*54fd6939SJiyong Park 
449*54fd6939SJiyong Park 	return 0;
450*54fd6939SJiyong Park }
451*54fd6939SJiyong Park 
rpi3_sdhost_prepare(int lba,uintptr_t buf,size_t size)452*54fd6939SJiyong Park static int rpi3_sdhost_prepare(int lba, uintptr_t buf, size_t size)
453*54fd6939SJiyong Park {
454*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
455*54fd6939SJiyong Park 	size_t blocks;
456*54fd6939SJiyong Park 	size_t blocksize;
457*54fd6939SJiyong Park 
458*54fd6939SJiyong Park 	if (size < 512) {
459*54fd6939SJiyong Park 		blocksize = size;
460*54fd6939SJiyong Park 		blocks = 1;
461*54fd6939SJiyong Park 	} else {
462*54fd6939SJiyong Park 		blocksize = 512;
463*54fd6939SJiyong Park 		blocks = size / blocksize;
464*54fd6939SJiyong Park 		if (size % blocksize != 0)
465*54fd6939SJiyong Park 			blocks++;
466*54fd6939SJiyong Park 	}
467*54fd6939SJiyong Park 
468*54fd6939SJiyong Park 	rpi3_drain_fifo();
469*54fd6939SJiyong Park 
470*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_BLOCKSIZE, blocksize);
471*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_BLOCKCOUNT, blocks);
472*54fd6939SJiyong Park 	udelay(100);
473*54fd6939SJiyong Park 	return 0;
474*54fd6939SJiyong Park }
475*54fd6939SJiyong Park 
rpi3_sdhost_read(int lba,uintptr_t buf,size_t size)476*54fd6939SJiyong Park static int rpi3_sdhost_read(int lba, uintptr_t buf, size_t size)
477*54fd6939SJiyong Park {
478*54fd6939SJiyong Park 	int err = 0;
479*54fd6939SJiyong Park 	uint32_t *buf1 = ((uint32_t *) buf);
480*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
481*54fd6939SJiyong Park 	int timeout = 100000;
482*54fd6939SJiyong Park 	int remaining_words = 0;
483*54fd6939SJiyong Park 
484*54fd6939SJiyong Park 	for (int i = 0; i < size / 4; i++) {
485*54fd6939SJiyong Park 		volatile int t = timeout;
486*54fd6939SJiyong Park 		uint32_t hsts_err;
487*54fd6939SJiyong Park 
488*54fd6939SJiyong Park 		while ((mmio_read_32(reg_base + HC_HOSTSTATUS)
489*54fd6939SJiyong Park 			& HC_HSTST_HAVEDATA) == 0) {
490*54fd6939SJiyong Park 			if (t == 0) {
491*54fd6939SJiyong Park 				ERROR("rpi3_sdhost: fifo timeout after %dus\n",
492*54fd6939SJiyong Park 				      timeout);
493*54fd6939SJiyong Park 				err = -(ETIMEDOUT);
494*54fd6939SJiyong Park 				break;
495*54fd6939SJiyong Park 			}
496*54fd6939SJiyong Park 			t--;
497*54fd6939SJiyong Park 			udelay(10);
498*54fd6939SJiyong Park 		}
499*54fd6939SJiyong Park 		if (t == 0)
500*54fd6939SJiyong Park 			break;
501*54fd6939SJiyong Park 
502*54fd6939SJiyong Park 		uint32_t data = mmio_read_32(reg_base + HC_DATAPORT);
503*54fd6939SJiyong Park 
504*54fd6939SJiyong Park 		hsts_err = mmio_read_32(reg_base + HC_HOSTSTATUS)
505*54fd6939SJiyong Park 			& HC_HSTST_MASK_ERROR_ALL;
506*54fd6939SJiyong Park 		if (hsts_err) {
507*54fd6939SJiyong Park 			ERROR("rpi3_sdhost: transfer FIFO word %d: 0x%x\n",
508*54fd6939SJiyong Park 			      i,
509*54fd6939SJiyong Park 			      mmio_read_32(reg_base + HC_HOSTSTATUS));
510*54fd6939SJiyong Park 			rpi3_sdhost_print_regs();
511*54fd6939SJiyong Park 
512*54fd6939SJiyong Park 			err = -(EILSEQ);
513*54fd6939SJiyong Park 
514*54fd6939SJiyong Park 			/* clean the error status */
515*54fd6939SJiyong Park 			mmio_write_32(reg_base + HC_HOSTSTATUS, hsts_err);
516*54fd6939SJiyong Park 		}
517*54fd6939SJiyong Park 
518*54fd6939SJiyong Park 		if (buf1)
519*54fd6939SJiyong Park 			buf1[i] = data;
520*54fd6939SJiyong Park 
521*54fd6939SJiyong Park 		/* speeding up if the remaining words are still a lot */
522*54fd6939SJiyong Park 		remaining_words = (mmio_read_32(reg_base + HC_DEBUG) >> 4)
523*54fd6939SJiyong Park 			& HC_DBG_FIFO_THRESH_MASK;
524*54fd6939SJiyong Park 		if (remaining_words >= 7)
525*54fd6939SJiyong Park 			continue;
526*54fd6939SJiyong Park 
527*54fd6939SJiyong Park 		/* delay. slowing down the read process */
528*54fd6939SJiyong Park 		udelay(100);
529*54fd6939SJiyong Park 	}
530*54fd6939SJiyong Park 
531*54fd6939SJiyong Park 	/* We decide to stop by ourselves.
532*54fd6939SJiyong Park 	 * It is because MMC_CMD(18) -> MMC_CMD(13) -> MMC_CMD(12)
533*54fd6939SJiyong Park 	 * doesn't work for RPi3 SDHost.
534*54fd6939SJiyong Park 	 */
535*54fd6939SJiyong Park 	if (rpi3_sdhost_params.current_cmd == MMC_CMD(18))
536*54fd6939SJiyong Park 		send_command_decorated(MMC_CMD(12), 0);
537*54fd6939SJiyong Park 
538*54fd6939SJiyong Park 	return err;
539*54fd6939SJiyong Park }
540*54fd6939SJiyong Park 
rpi3_sdhost_write(int lba,uintptr_t buf,size_t size)541*54fd6939SJiyong Park static int rpi3_sdhost_write(int lba, uintptr_t buf, size_t size)
542*54fd6939SJiyong Park {
543*54fd6939SJiyong Park 	uint32_t *buf1 = ((uint32_t *) buf);
544*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
545*54fd6939SJiyong Park 	int err = 0;
546*54fd6939SJiyong Park 	int remaining_words = 0;
547*54fd6939SJiyong Park 
548*54fd6939SJiyong Park 	for (int i = 0; i < size / 4; i++) {
549*54fd6939SJiyong Park 		uint32_t hsts_err;
550*54fd6939SJiyong Park 		uint32_t data = buf1[i];
551*54fd6939SJiyong Park 		uint32_t dbg;
552*54fd6939SJiyong Park 		uint32_t fsm_state;
553*54fd6939SJiyong Park 
554*54fd6939SJiyong Park 		mmio_write_32(reg_base + HC_DATAPORT, data);
555*54fd6939SJiyong Park 
556*54fd6939SJiyong Park 		dbg = mmio_read_32(reg_base + HC_DEBUG);
557*54fd6939SJiyong Park 		fsm_state = dbg & HC_DBG_FSM_MASK;
558*54fd6939SJiyong Park 		if (fsm_state != HC_DBG_FSM_WRITEDATA
559*54fd6939SJiyong Park 		    && fsm_state != HC_DBG_FSM_WRITESTART1
560*54fd6939SJiyong Park 		    && fsm_state != HC_DBG_FSM_WRITESTART2
561*54fd6939SJiyong Park 		    && fsm_state != HC_DBG_FSM_WRITECRC
562*54fd6939SJiyong Park 		    && fsm_state != HC_DBG_FSM_WRITEWAIT1
563*54fd6939SJiyong Park 		    && fsm_state != HC_DBG_FSM_WRITEWAIT2) {
564*54fd6939SJiyong Park 			hsts_err = mmio_read_32(reg_base + HC_HOSTSTATUS)
565*54fd6939SJiyong Park 				& HC_HSTST_MASK_ERROR_ALL;
566*54fd6939SJiyong Park 			if (hsts_err)
567*54fd6939SJiyong Park 				err = -(EILSEQ);
568*54fd6939SJiyong Park 		}
569*54fd6939SJiyong Park 
570*54fd6939SJiyong Park 		/* speeding up if the remaining words are not many */
571*54fd6939SJiyong Park 		remaining_words = (mmio_read_32(reg_base + HC_DEBUG) >> 4)
572*54fd6939SJiyong Park 			& HC_DBG_FIFO_THRESH_MASK;
573*54fd6939SJiyong Park 		if (remaining_words <= 4)
574*54fd6939SJiyong Park 			continue;
575*54fd6939SJiyong Park 
576*54fd6939SJiyong Park 		udelay(100);
577*54fd6939SJiyong Park 	}
578*54fd6939SJiyong Park 
579*54fd6939SJiyong Park 	/* We decide to stop by ourselves.
580*54fd6939SJiyong Park 	 * It is because MMC_CMD(25) -> MMC_CMD(13) -> MMC_CMD(12)
581*54fd6939SJiyong Park 	 * doesn't work for RPi3 SDHost.
582*54fd6939SJiyong Park 	 */
583*54fd6939SJiyong Park 	if (rpi3_sdhost_params.current_cmd == MMC_CMD(25))
584*54fd6939SJiyong Park 		send_command_decorated(MMC_CMD(12), 0);
585*54fd6939SJiyong Park 
586*54fd6939SJiyong Park 	return err;
587*54fd6939SJiyong Park }
588*54fd6939SJiyong Park 
rpi3_sdhost_init(struct rpi3_sdhost_params * params,struct mmc_device_info * mmc_dev_info)589*54fd6939SJiyong Park void rpi3_sdhost_init(struct rpi3_sdhost_params *params,
590*54fd6939SJiyong Park 		    struct mmc_device_info *mmc_dev_info)
591*54fd6939SJiyong Park {
592*54fd6939SJiyong Park 	assert((params != 0) &&
593*54fd6939SJiyong Park 	       ((params->reg_base & MMC_BLOCK_MASK) == 0));
594*54fd6939SJiyong Park 
595*54fd6939SJiyong Park 	memcpy(&rpi3_sdhost_params, params, sizeof(struct rpi3_sdhost_params));
596*54fd6939SJiyong Park 
597*54fd6939SJiyong Park 	/* backup GPIO 48 to 53 configurations */
598*54fd6939SJiyong Park 	for (int i = 48; i <= 53; i++) {
599*54fd6939SJiyong Park 		rpi3_sdhost_params.gpio48_pinselect[i - 48]
600*54fd6939SJiyong Park 			= rpi3_gpio_get_select(i);
601*54fd6939SJiyong Park 		VERBOSE("rpi3_sdhost: Original GPIO state %d: %d\n",
602*54fd6939SJiyong Park 			i,
603*54fd6939SJiyong Park 			rpi3_sdhost_params.gpio48_pinselect[i - 48]);
604*54fd6939SJiyong Park 	}
605*54fd6939SJiyong Park 
606*54fd6939SJiyong Park 	/* setting pull resistors for 48 to 53.
607*54fd6939SJiyong Park 	 * It is debatable to set SD_CLK to UP or NONE. We massively
608*54fd6939SJiyong Park 	 * tested different brands of SD Cards and found NONE works
609*54fd6939SJiyong Park 	 * most stable.
610*54fd6939SJiyong Park 	 *
611*54fd6939SJiyong Park 	 * GPIO 48 (SD_CLK) to GPIO_PULL_NONE
612*54fd6939SJiyong Park 	 * GPIO 49 (SD_CMD) to GPIO_PULL_UP
613*54fd6939SJiyong Park 	 * GPIO 50 (SD_D0)  to GPIO_PULL_UP
614*54fd6939SJiyong Park 	 * GPIO 51 (SD_D1)  to GPIO_PULL_UP
615*54fd6939SJiyong Park 	 * GPIO 52 (SD_D2)  to GPIO_PULL_UP
616*54fd6939SJiyong Park 	 * GPIO 53 (SD_D3)  to GPIO_PULL_UP
617*54fd6939SJiyong Park 	 */
618*54fd6939SJiyong Park 	gpio_set_pull(48, GPIO_PULL_NONE);
619*54fd6939SJiyong Park 	for (int i = 49; i <= 53; i++)
620*54fd6939SJiyong Park 		gpio_set_pull(i, GPIO_PULL_UP);
621*54fd6939SJiyong Park 
622*54fd6939SJiyong Park 	/* Set pin 48-53 to alt-0. It means route SDHOST to card slot */
623*54fd6939SJiyong Park 	for (int i = 48; i <= 53; i++)
624*54fd6939SJiyong Park 		rpi3_gpio_set_select(i, RPI3_GPIO_FUNC_ALT0);
625*54fd6939SJiyong Park 
626*54fd6939SJiyong Park 	mmc_init(&rpi3_sdhost_ops, params->clk_rate, params->bus_width,
627*54fd6939SJiyong Park 		 params->flags, mmc_dev_info);
628*54fd6939SJiyong Park }
629*54fd6939SJiyong Park 
rpi3_sdhost_stop(void)630*54fd6939SJiyong Park void rpi3_sdhost_stop(void)
631*54fd6939SJiyong Park {
632*54fd6939SJiyong Park 	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
633*54fd6939SJiyong Park 
634*54fd6939SJiyong Park 	VERBOSE("rpi3_sdhost: Shutting down: drain FIFO out\n");
635*54fd6939SJiyong Park 	rpi3_drain_fifo();
636*54fd6939SJiyong Park 
637*54fd6939SJiyong Park 	VERBOSE("rpi3_sdhost: Shutting down: slowing down the clock\n");
638*54fd6939SJiyong Park 	mmio_write_32(reg_base+HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_SLOWVAL);
639*54fd6939SJiyong Park 	udelay(500);
640*54fd6939SJiyong Park 
641*54fd6939SJiyong Park 	VERBOSE("rpi3_sdhost: Shutting down: put SDHost into idle state\n");
642*54fd6939SJiyong Park 	send_command_decorated(MMC_CMD(0), 0);
643*54fd6939SJiyong Park 	udelay(500);
644*54fd6939SJiyong Park 
645*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_COMMAND, 0);
646*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_ARGUMENT, 0);
647*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_TIMEOUTCOUNTER, HC_TIMEOUT_IDLE);
648*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_STOPVAL);
649*54fd6939SJiyong Park 
650*54fd6939SJiyong Park 	udelay(100);
651*54fd6939SJiyong Park 
652*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_POWER, 0);
653*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_HOSTCONFIG, 0);
654*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_BLOCKSIZE, 0x400);
655*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_BLOCKCOUNT, 0);
656*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_HOSTSTATUS, 0x7f8);
657*54fd6939SJiyong Park 
658*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_COMMAND, 0);
659*54fd6939SJiyong Park 	mmio_write_32(reg_base + HC_ARGUMENT, 0);
660*54fd6939SJiyong Park 
661*54fd6939SJiyong Park 	udelay(100);
662*54fd6939SJiyong Park 
663*54fd6939SJiyong Park 	/* Restore the pinmux to original state */
664*54fd6939SJiyong Park 	for (int i = 48; i <= 53; i++) {
665*54fd6939SJiyong Park 		rpi3_gpio_set_select(i,
666*54fd6939SJiyong Park 				     rpi3_sdhost_params.gpio48_pinselect[i-48]);
667*54fd6939SJiyong Park 	}
668*54fd6939SJiyong Park 
669*54fd6939SJiyong Park 	/* Reset the pull resistors before entering BL33.
670*54fd6939SJiyong Park 	 * GPIO 48 (SD_CLK) to GPIO_PULL_UP
671*54fd6939SJiyong Park 	 * GPIO 49 (SD_CMD) to GPIO_PULL_UP
672*54fd6939SJiyong Park 	 * GPIO 50 (SD_D0)  to GPIO_PULL_UP
673*54fd6939SJiyong Park 	 * GPIO 51 (SD_D1)  to GPIO_PULL_UP
674*54fd6939SJiyong Park 	 * GPIO 52 (SD_D2)  to GPIO_PULL_UP
675*54fd6939SJiyong Park 	 * GPIO 53 (SD_D3)  to GPIO_PULL_UP
676*54fd6939SJiyong Park 	 */
677*54fd6939SJiyong Park 	for (int i = 48; i <= 53; i++)
678*54fd6939SJiyong Park 		gpio_set_pull(i, GPIO_PULL_UP);
679*54fd6939SJiyong Park }
680