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