xref: /rk3399_rockchip-uboot/drivers/mmc/sdhci.c (revision 29905a451b7ecf86785a4404e926fb14a8daced3)
1af62a557SLei Wen /*
2af62a557SLei Wen  * Copyright 2011, Marvell Semiconductor Inc.
3af62a557SLei Wen  * Lei Wen <leiwen@marvell.com>
4af62a557SLei Wen  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6af62a557SLei Wen  *
7af62a557SLei Wen  * Back ported to the 8xx platform (from the 8260 platform) by
8af62a557SLei Wen  * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
9af62a557SLei Wen  */
10af62a557SLei Wen 
11af62a557SLei Wen #include <common.h>
12af62a557SLei Wen #include <malloc.h>
13af62a557SLei Wen #include <mmc.h>
14af62a557SLei Wen #include <sdhci.h>
15af62a557SLei Wen 
16af62a557SLei Wen void *aligned_buffer;
17af62a557SLei Wen 
18af62a557SLei Wen static void sdhci_reset(struct sdhci_host *host, u8 mask)
19af62a557SLei Wen {
20af62a557SLei Wen 	unsigned long timeout;
21af62a557SLei Wen 
22af62a557SLei Wen 	/* Wait max 100 ms */
23af62a557SLei Wen 	timeout = 100;
24af62a557SLei Wen 	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
25af62a557SLei Wen 	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
26af62a557SLei Wen 		if (timeout == 0) {
2730e6d979SDarwin Rambo 			printf("%s: Reset 0x%x never completed.\n",
2830e6d979SDarwin Rambo 			       __func__, (int)mask);
29af62a557SLei Wen 			return;
30af62a557SLei Wen 		}
31af62a557SLei Wen 		timeout--;
32af62a557SLei Wen 		udelay(1000);
33af62a557SLei Wen 	}
34af62a557SLei Wen }
35af62a557SLei Wen 
36af62a557SLei Wen static void sdhci_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd)
37af62a557SLei Wen {
38af62a557SLei Wen 	int i;
39af62a557SLei Wen 	if (cmd->resp_type & MMC_RSP_136) {
40af62a557SLei Wen 		/* CRC is stripped so we need to do some shifting. */
41af62a557SLei Wen 		for (i = 0; i < 4; i++) {
42af62a557SLei Wen 			cmd->response[i] = sdhci_readl(host,
43af62a557SLei Wen 					SDHCI_RESPONSE + (3-i)*4) << 8;
44af62a557SLei Wen 			if (i != 3)
45af62a557SLei Wen 				cmd->response[i] |= sdhci_readb(host,
46af62a557SLei Wen 						SDHCI_RESPONSE + (3-i)*4-1);
47af62a557SLei Wen 		}
48af62a557SLei Wen 	} else {
49af62a557SLei Wen 		cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE);
50af62a557SLei Wen 	}
51af62a557SLei Wen }
52af62a557SLei Wen 
53af62a557SLei Wen static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
54af62a557SLei Wen {
55af62a557SLei Wen 	int i;
56af62a557SLei Wen 	char *offs;
57af62a557SLei Wen 	for (i = 0; i < data->blocksize; i += 4) {
58af62a557SLei Wen 		offs = data->dest + i;
59af62a557SLei Wen 		if (data->flags == MMC_DATA_READ)
60af62a557SLei Wen 			*(u32 *)offs = sdhci_readl(host, SDHCI_BUFFER);
61af62a557SLei Wen 		else
62af62a557SLei Wen 			sdhci_writel(host, *(u32 *)offs, SDHCI_BUFFER);
63af62a557SLei Wen 	}
64af62a557SLei Wen }
65af62a557SLei Wen 
66af62a557SLei Wen static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
67af62a557SLei Wen 				unsigned int start_addr)
68af62a557SLei Wen {
69a004abdeSLei Wen 	unsigned int stat, rdy, mask, timeout, block = 0;
70804c7f42SJaehoon Chung #ifdef CONFIG_MMC_SDMA
71804c7f42SJaehoon Chung 	unsigned char ctrl;
722c011847SJuhyun \(Justin\) Oh 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
73804c7f42SJaehoon Chung 	ctrl &= ~SDHCI_CTRL_DMA_MASK;
742c011847SJuhyun \(Justin\) Oh 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
75804c7f42SJaehoon Chung #endif
76af62a557SLei Wen 
775d48e422SJaehoon Chung 	timeout = 1000000;
78af62a557SLei Wen 	rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
79af62a557SLei Wen 	mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE;
80af62a557SLei Wen 	do {
81af62a557SLei Wen 		stat = sdhci_readl(host, SDHCI_INT_STATUS);
82af62a557SLei Wen 		if (stat & SDHCI_INT_ERROR) {
8330e6d979SDarwin Rambo 			printf("%s: Error detected in status(0x%X)!\n",
8430e6d979SDarwin Rambo 			       __func__, stat);
85af62a557SLei Wen 			return -1;
86af62a557SLei Wen 		}
87af62a557SLei Wen 		if (stat & rdy) {
88af62a557SLei Wen 			if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask))
89af62a557SLei Wen 				continue;
90af62a557SLei Wen 			sdhci_writel(host, rdy, SDHCI_INT_STATUS);
91af62a557SLei Wen 			sdhci_transfer_pio(host, data);
92af62a557SLei Wen 			data->dest += data->blocksize;
93af62a557SLei Wen 			if (++block >= data->blocks)
94af62a557SLei Wen 				break;
95af62a557SLei Wen 		}
96af62a557SLei Wen #ifdef CONFIG_MMC_SDMA
97af62a557SLei Wen 		if (stat & SDHCI_INT_DMA_END) {
98af62a557SLei Wen 			sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS);
993e81c772SLei Wen 			start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
100af62a557SLei Wen 			start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
101af62a557SLei Wen 			sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
102af62a557SLei Wen 		}
103af62a557SLei Wen #endif
104a004abdeSLei Wen 		if (timeout-- > 0)
105a004abdeSLei Wen 			udelay(10);
106a004abdeSLei Wen 		else {
10730e6d979SDarwin Rambo 			printf("%s: Transfer data timeout\n", __func__);
108a004abdeSLei Wen 			return -1;
109a004abdeSLei Wen 		}
110af62a557SLei Wen 	} while (!(stat & SDHCI_INT_DATA_END));
111af62a557SLei Wen 	return 0;
112af62a557SLei Wen }
113af62a557SLei Wen 
11456b34bc6SPrzemyslaw Marczak /*
11556b34bc6SPrzemyslaw Marczak  * No command will be sent by driver if card is busy, so driver must wait
11656b34bc6SPrzemyslaw Marczak  * for card ready state.
11756b34bc6SPrzemyslaw Marczak  * Every time when card is busy after timeout then (last) timeout value will be
11856b34bc6SPrzemyslaw Marczak  * increased twice but only if it doesn't exceed global defined maximum.
11956b34bc6SPrzemyslaw Marczak  * Each function call will use last timeout value. Max timeout can be redefined
12056b34bc6SPrzemyslaw Marczak  * in board config file.
12156b34bc6SPrzemyslaw Marczak  */
12256b34bc6SPrzemyslaw Marczak #ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT
12356b34bc6SPrzemyslaw Marczak #define CONFIG_SDHCI_CMD_MAX_TIMEOUT		3200
12456b34bc6SPrzemyslaw Marczak #endif
12556b34bc6SPrzemyslaw Marczak #define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT	100
12656b34bc6SPrzemyslaw Marczak 
1276588c78bSJeroen Hofstee static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
128af62a557SLei Wen 		       struct mmc_data *data)
129af62a557SLei Wen {
13093bfd616SPantelis Antoniou 	struct sdhci_host *host = mmc->priv;
131af62a557SLei Wen 	unsigned int stat = 0;
132af62a557SLei Wen 	int ret = 0;
133af62a557SLei Wen 	int trans_bytes = 0, is_aligned = 1;
134af62a557SLei Wen 	u32 mask, flags, mode;
13556b34bc6SPrzemyslaw Marczak 	unsigned int time = 0, start_addr = 0;
13656b34bc6SPrzemyslaw Marczak 	int mmc_dev = mmc->block_dev.dev;
137*29905a45SStefan Roese 	unsigned start = get_timer(0);
138af62a557SLei Wen 
13956b34bc6SPrzemyslaw Marczak 	/* Timeout unit - ms */
14056b34bc6SPrzemyslaw Marczak 	static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;
141af62a557SLei Wen 
142af62a557SLei Wen 	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
143af62a557SLei Wen 	mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
144af62a557SLei Wen 
145af62a557SLei Wen 	/* We shouldn't wait for data inihibit for stop commands, even
146af62a557SLei Wen 	   though they might use busy signaling */
147af62a557SLei Wen 	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
148af62a557SLei Wen 		mask &= ~SDHCI_DATA_INHIBIT;
149af62a557SLei Wen 
150af62a557SLei Wen 	while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
15156b34bc6SPrzemyslaw Marczak 		if (time >= cmd_timeout) {
15230e6d979SDarwin Rambo 			printf("%s: MMC: %d busy ", __func__, mmc_dev);
15356b34bc6SPrzemyslaw Marczak 			if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
15456b34bc6SPrzemyslaw Marczak 				cmd_timeout += cmd_timeout;
15556b34bc6SPrzemyslaw Marczak 				printf("timeout increasing to: %u ms.\n",
15656b34bc6SPrzemyslaw Marczak 				       cmd_timeout);
15756b34bc6SPrzemyslaw Marczak 			} else {
15856b34bc6SPrzemyslaw Marczak 				puts("timeout.\n");
159af62a557SLei Wen 				return COMM_ERR;
160af62a557SLei Wen 			}
16156b34bc6SPrzemyslaw Marczak 		}
16256b34bc6SPrzemyslaw Marczak 		time++;
163af62a557SLei Wen 		udelay(1000);
164af62a557SLei Wen 	}
165af62a557SLei Wen 
166af62a557SLei Wen 	mask = SDHCI_INT_RESPONSE;
167af62a557SLei Wen 	if (!(cmd->resp_type & MMC_RSP_PRESENT))
168af62a557SLei Wen 		flags = SDHCI_CMD_RESP_NONE;
169af62a557SLei Wen 	else if (cmd->resp_type & MMC_RSP_136)
170af62a557SLei Wen 		flags = SDHCI_CMD_RESP_LONG;
171af62a557SLei Wen 	else if (cmd->resp_type & MMC_RSP_BUSY) {
172af62a557SLei Wen 		flags = SDHCI_CMD_RESP_SHORT_BUSY;
173af62a557SLei Wen 		mask |= SDHCI_INT_DATA_END;
174af62a557SLei Wen 	} else
175af62a557SLei Wen 		flags = SDHCI_CMD_RESP_SHORT;
176af62a557SLei Wen 
177af62a557SLei Wen 	if (cmd->resp_type & MMC_RSP_CRC)
178af62a557SLei Wen 		flags |= SDHCI_CMD_CRC;
179af62a557SLei Wen 	if (cmd->resp_type & MMC_RSP_OPCODE)
180af62a557SLei Wen 		flags |= SDHCI_CMD_INDEX;
181af62a557SLei Wen 	if (data)
182af62a557SLei Wen 		flags |= SDHCI_CMD_DATA;
183af62a557SLei Wen 
184af62a557SLei Wen 	/* Set Transfer mode regarding to data flag */
185af62a557SLei Wen 	if (data != 0) {
186af62a557SLei Wen 		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
187af62a557SLei Wen 		mode = SDHCI_TRNS_BLK_CNT_EN;
188af62a557SLei Wen 		trans_bytes = data->blocks * data->blocksize;
189af62a557SLei Wen 		if (data->blocks > 1)
190af62a557SLei Wen 			mode |= SDHCI_TRNS_MULTI;
191af62a557SLei Wen 
192af62a557SLei Wen 		if (data->flags == MMC_DATA_READ)
193af62a557SLei Wen 			mode |= SDHCI_TRNS_READ;
194af62a557SLei Wen 
195af62a557SLei Wen #ifdef CONFIG_MMC_SDMA
196af62a557SLei Wen 		if (data->flags == MMC_DATA_READ)
1973c1fcb77SRob Herring 			start_addr = (unsigned long)data->dest;
198af62a557SLei Wen 		else
1993c1fcb77SRob Herring 			start_addr = (unsigned long)data->src;
200af62a557SLei Wen 		if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
201af62a557SLei Wen 				(start_addr & 0x7) != 0x0) {
202af62a557SLei Wen 			is_aligned = 0;
2033c1fcb77SRob Herring 			start_addr = (unsigned long)aligned_buffer;
204af62a557SLei Wen 			if (data->flags != MMC_DATA_READ)
205af62a557SLei Wen 				memcpy(aligned_buffer, data->src, trans_bytes);
206af62a557SLei Wen 		}
207af62a557SLei Wen 
208af62a557SLei Wen 		sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
209af62a557SLei Wen 		mode |= SDHCI_TRNS_DMA;
210af62a557SLei Wen #endif
211af62a557SLei Wen 		sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
212af62a557SLei Wen 				data->blocksize),
213af62a557SLei Wen 				SDHCI_BLOCK_SIZE);
214af62a557SLei Wen 		sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
215af62a557SLei Wen 		sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
2165e1c23cdSKevin Liu 	} else if (cmd->resp_type & MMC_RSP_BUSY) {
2175e1c23cdSKevin Liu 		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
218af62a557SLei Wen 	}
219af62a557SLei Wen 
220af62a557SLei Wen 	sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
221af62a557SLei Wen #ifdef CONFIG_MMC_SDMA
2222c2ec4c9SLei Wen 	flush_cache(start_addr, trans_bytes);
223af62a557SLei Wen #endif
224af62a557SLei Wen 	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
225*29905a45SStefan Roese 	start = get_timer(0);
226af62a557SLei Wen 	do {
227af62a557SLei Wen 		stat = sdhci_readl(host, SDHCI_INT_STATUS);
228af62a557SLei Wen 		if (stat & SDHCI_INT_ERROR)
229af62a557SLei Wen 			break;
230*29905a45SStefan Roese 	} while (((stat & mask) != mask) &&
231*29905a45SStefan Roese 		 (get_timer(start) < CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT));
232af62a557SLei Wen 
233*29905a45SStefan Roese 	if (get_timer(start) >= CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT) {
2343a638320SJaehoon Chung 		if (host->quirks & SDHCI_QUIRK_BROKEN_R1B)
2353a638320SJaehoon Chung 			return 0;
2363a638320SJaehoon Chung 		else {
23730e6d979SDarwin Rambo 			printf("%s: Timeout for status update!\n", __func__);
2383a638320SJaehoon Chung 			return TIMEOUT;
2393a638320SJaehoon Chung 		}
2403a638320SJaehoon Chung 	}
2413a638320SJaehoon Chung 
242af62a557SLei Wen 	if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
243af62a557SLei Wen 		sdhci_cmd_done(host, cmd);
244af62a557SLei Wen 		sdhci_writel(host, mask, SDHCI_INT_STATUS);
245af62a557SLei Wen 	} else
246af62a557SLei Wen 		ret = -1;
247af62a557SLei Wen 
248af62a557SLei Wen 	if (!ret && data)
249af62a557SLei Wen 		ret = sdhci_transfer_data(host, data, start_addr);
250af62a557SLei Wen 
25113243f2eSTushar Behera 	if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD)
25213243f2eSTushar Behera 		udelay(1000);
25313243f2eSTushar Behera 
254af62a557SLei Wen 	stat = sdhci_readl(host, SDHCI_INT_STATUS);
255af62a557SLei Wen 	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
256af62a557SLei Wen 	if (!ret) {
257af62a557SLei Wen 		if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
258af62a557SLei Wen 				!is_aligned && (data->flags == MMC_DATA_READ))
259af62a557SLei Wen 			memcpy(data->dest, aligned_buffer, trans_bytes);
260af62a557SLei Wen 		return 0;
261af62a557SLei Wen 	}
262af62a557SLei Wen 
263af62a557SLei Wen 	sdhci_reset(host, SDHCI_RESET_CMD);
264af62a557SLei Wen 	sdhci_reset(host, SDHCI_RESET_DATA);
265af62a557SLei Wen 	if (stat & SDHCI_INT_TIMEOUT)
266af62a557SLei Wen 		return TIMEOUT;
267af62a557SLei Wen 	else
268af62a557SLei Wen 		return COMM_ERR;
269af62a557SLei Wen }
270af62a557SLei Wen 
271af62a557SLei Wen static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
272af62a557SLei Wen {
27393bfd616SPantelis Antoniou 	struct sdhci_host *host = mmc->priv;
274af62a557SLei Wen 	unsigned int div, clk, timeout;
275af62a557SLei Wen 
276af62a557SLei Wen 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
277af62a557SLei Wen 
278af62a557SLei Wen 	if (clock == 0)
279af62a557SLei Wen 		return 0;
280af62a557SLei Wen 
281113e5dfcSJaehoon Chung 	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
282af62a557SLei Wen 		/* Version 3.00 divisors must be a multiple of 2. */
28393bfd616SPantelis Antoniou 		if (mmc->cfg->f_max <= clock)
284af62a557SLei Wen 			div = 1;
285af62a557SLei Wen 		else {
286af62a557SLei Wen 			for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
28793bfd616SPantelis Antoniou 				if ((mmc->cfg->f_max / div) <= clock)
288af62a557SLei Wen 					break;
289af62a557SLei Wen 			}
290af62a557SLei Wen 		}
291af62a557SLei Wen 	} else {
292af62a557SLei Wen 		/* Version 2.00 divisors must be a power of 2. */
293af62a557SLei Wen 		for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
29493bfd616SPantelis Antoniou 			if ((mmc->cfg->f_max / div) <= clock)
295af62a557SLei Wen 				break;
296af62a557SLei Wen 		}
297af62a557SLei Wen 	}
298af62a557SLei Wen 	div >>= 1;
299af62a557SLei Wen 
300b09ed6e4SJaehoon Chung 	if (host->set_clock)
301b09ed6e4SJaehoon Chung 		host->set_clock(host->index, div);
302b09ed6e4SJaehoon Chung 
303af62a557SLei Wen 	clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
304af62a557SLei Wen 	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
305af62a557SLei Wen 		<< SDHCI_DIVIDER_HI_SHIFT;
306af62a557SLei Wen 	clk |= SDHCI_CLOCK_INT_EN;
307af62a557SLei Wen 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
308af62a557SLei Wen 
309af62a557SLei Wen 	/* Wait max 20 ms */
310af62a557SLei Wen 	timeout = 20;
311af62a557SLei Wen 	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
312af62a557SLei Wen 		& SDHCI_CLOCK_INT_STABLE)) {
313af62a557SLei Wen 		if (timeout == 0) {
31430e6d979SDarwin Rambo 			printf("%s: Internal clock never stabilised.\n",
31530e6d979SDarwin Rambo 			       __func__);
316af62a557SLei Wen 			return -1;
317af62a557SLei Wen 		}
318af62a557SLei Wen 		timeout--;
319af62a557SLei Wen 		udelay(1000);
320af62a557SLei Wen 	}
321af62a557SLei Wen 
322af62a557SLei Wen 	clk |= SDHCI_CLOCK_CARD_EN;
323af62a557SLei Wen 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
324af62a557SLei Wen 	return 0;
325af62a557SLei Wen }
326af62a557SLei Wen 
327af62a557SLei Wen static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
328af62a557SLei Wen {
329af62a557SLei Wen 	u8 pwr = 0;
330af62a557SLei Wen 
331af62a557SLei Wen 	if (power != (unsigned short)-1) {
332af62a557SLei Wen 		switch (1 << power) {
333af62a557SLei Wen 		case MMC_VDD_165_195:
334af62a557SLei Wen 			pwr = SDHCI_POWER_180;
335af62a557SLei Wen 			break;
336af62a557SLei Wen 		case MMC_VDD_29_30:
337af62a557SLei Wen 		case MMC_VDD_30_31:
338af62a557SLei Wen 			pwr = SDHCI_POWER_300;
339af62a557SLei Wen 			break;
340af62a557SLei Wen 		case MMC_VDD_32_33:
341af62a557SLei Wen 		case MMC_VDD_33_34:
342af62a557SLei Wen 			pwr = SDHCI_POWER_330;
343af62a557SLei Wen 			break;
344af62a557SLei Wen 		}
345af62a557SLei Wen 	}
346af62a557SLei Wen 
347af62a557SLei Wen 	if (pwr == 0) {
348af62a557SLei Wen 		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
349af62a557SLei Wen 		return;
350af62a557SLei Wen 	}
351af62a557SLei Wen 
352688c2d14SMela Custodio 	if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
353688c2d14SMela Custodio 		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
354688c2d14SMela Custodio 
355af62a557SLei Wen 	pwr |= SDHCI_POWER_ON;
356af62a557SLei Wen 
357af62a557SLei Wen 	sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
358af62a557SLei Wen }
359af62a557SLei Wen 
3606588c78bSJeroen Hofstee static void sdhci_set_ios(struct mmc *mmc)
361af62a557SLei Wen {
362af62a557SLei Wen 	u32 ctrl;
36393bfd616SPantelis Antoniou 	struct sdhci_host *host = mmc->priv;
364af62a557SLei Wen 
365236bfecfSJaehoon Chung 	if (host->set_control_reg)
366236bfecfSJaehoon Chung 		host->set_control_reg(host);
367236bfecfSJaehoon Chung 
368af62a557SLei Wen 	if (mmc->clock != host->clock)
369af62a557SLei Wen 		sdhci_set_clock(mmc, mmc->clock);
370af62a557SLei Wen 
371af62a557SLei Wen 	/* Set bus width */
372af62a557SLei Wen 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
373af62a557SLei Wen 	if (mmc->bus_width == 8) {
374af62a557SLei Wen 		ctrl &= ~SDHCI_CTRL_4BITBUS;
375113e5dfcSJaehoon Chung 		if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
376113e5dfcSJaehoon Chung 				(host->quirks & SDHCI_QUIRK_USE_WIDE8))
377af62a557SLei Wen 			ctrl |= SDHCI_CTRL_8BITBUS;
378af62a557SLei Wen 	} else {
379f88a429fSMatt Reimer 		if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
380f88a429fSMatt Reimer 				(host->quirks & SDHCI_QUIRK_USE_WIDE8))
381af62a557SLei Wen 			ctrl &= ~SDHCI_CTRL_8BITBUS;
382af62a557SLei Wen 		if (mmc->bus_width == 4)
383af62a557SLei Wen 			ctrl |= SDHCI_CTRL_4BITBUS;
384af62a557SLei Wen 		else
385af62a557SLei Wen 			ctrl &= ~SDHCI_CTRL_4BITBUS;
386af62a557SLei Wen 	}
387af62a557SLei Wen 
388af62a557SLei Wen 	if (mmc->clock > 26000000)
389af62a557SLei Wen 		ctrl |= SDHCI_CTRL_HISPD;
390af62a557SLei Wen 	else
391af62a557SLei Wen 		ctrl &= ~SDHCI_CTRL_HISPD;
392af62a557SLei Wen 
393236bfecfSJaehoon Chung 	if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
394236bfecfSJaehoon Chung 		ctrl &= ~SDHCI_CTRL_HISPD;
395236bfecfSJaehoon Chung 
396af62a557SLei Wen 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
397af62a557SLei Wen }
398af62a557SLei Wen 
3996588c78bSJeroen Hofstee static int sdhci_init(struct mmc *mmc)
400af62a557SLei Wen {
40193bfd616SPantelis Antoniou 	struct sdhci_host *host = mmc->priv;
402af62a557SLei Wen 
403af62a557SLei Wen 	if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) {
404af62a557SLei Wen 		aligned_buffer = memalign(8, 512*1024);
405af62a557SLei Wen 		if (!aligned_buffer) {
40630e6d979SDarwin Rambo 			printf("%s: Aligned buffer alloc failed!!!\n",
40730e6d979SDarwin Rambo 			       __func__);
408af62a557SLei Wen 			return -1;
409af62a557SLei Wen 		}
410af62a557SLei Wen 	}
411af62a557SLei Wen 
41293bfd616SPantelis Antoniou 	sdhci_set_power(host, fls(mmc->cfg->voltages) - 1);
413470dcc75SJoe Hershberger 
414470dcc75SJoe Hershberger 	if (host->quirks & SDHCI_QUIRK_NO_CD) {
415470dcc75SJoe Hershberger 		unsigned int status;
416470dcc75SJoe Hershberger 
417e113fe3cSMatt Reimer 		sdhci_writeb(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST,
418470dcc75SJoe Hershberger 			SDHCI_HOST_CONTROL);
419470dcc75SJoe Hershberger 
420470dcc75SJoe Hershberger 		status = sdhci_readl(host, SDHCI_PRESENT_STATE);
421470dcc75SJoe Hershberger 		while ((!(status & SDHCI_CARD_PRESENT)) ||
422470dcc75SJoe Hershberger 		    (!(status & SDHCI_CARD_STATE_STABLE)) ||
423470dcc75SJoe Hershberger 		    (!(status & SDHCI_CARD_DETECT_PIN_LEVEL)))
424470dcc75SJoe Hershberger 			status = sdhci_readl(host, SDHCI_PRESENT_STATE);
425470dcc75SJoe Hershberger 	}
426470dcc75SJoe Hershberger 
427ce0c1bc1SŁukasz Majewski 	/* Enable only interrupts served by the SD controller */
42830e6d979SDarwin Rambo 	sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
42930e6d979SDarwin Rambo 		     SDHCI_INT_ENABLE);
430ce0c1bc1SŁukasz Majewski 	/* Mask all sdhci interrupt sources */
431ce0c1bc1SŁukasz Majewski 	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
432af62a557SLei Wen 
433af62a557SLei Wen 	return 0;
434af62a557SLei Wen }
435af62a557SLei Wen 
436ab769f22SPantelis Antoniou 
437ab769f22SPantelis Antoniou static const struct mmc_ops sdhci_ops = {
438ab769f22SPantelis Antoniou 	.send_cmd	= sdhci_send_command,
439ab769f22SPantelis Antoniou 	.set_ios	= sdhci_set_ios,
440ab769f22SPantelis Antoniou 	.init		= sdhci_init,
441ab769f22SPantelis Antoniou };
442ab769f22SPantelis Antoniou 
443af62a557SLei Wen int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
444af62a557SLei Wen {
445af62a557SLei Wen 	unsigned int caps;
446af62a557SLei Wen 
44793bfd616SPantelis Antoniou 	host->cfg.name = host->name;
44893bfd616SPantelis Antoniou 	host->cfg.ops = &sdhci_ops;
449af62a557SLei Wen 
450af62a557SLei Wen 	caps = sdhci_readl(host, SDHCI_CAPABILITIES);
451af62a557SLei Wen #ifdef CONFIG_MMC_SDMA
452af62a557SLei Wen 	if (!(caps & SDHCI_CAN_DO_SDMA)) {
45330e6d979SDarwin Rambo 		printf("%s: Your controller doesn't support SDMA!!\n",
45430e6d979SDarwin Rambo 		       __func__);
455af62a557SLei Wen 		return -1;
456af62a557SLei Wen 	}
457af62a557SLei Wen #endif
458af62a557SLei Wen 
459af62a557SLei Wen 	if (max_clk)
46093bfd616SPantelis Antoniou 		host->cfg.f_max = max_clk;
461af62a557SLei Wen 	else {
462113e5dfcSJaehoon Chung 		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
46393bfd616SPantelis Antoniou 			host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
464af62a557SLei Wen 				>> SDHCI_CLOCK_BASE_SHIFT;
465af62a557SLei Wen 		else
46693bfd616SPantelis Antoniou 			host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK)
467af62a557SLei Wen 				>> SDHCI_CLOCK_BASE_SHIFT;
46893bfd616SPantelis Antoniou 		host->cfg.f_max *= 1000000;
469af62a557SLei Wen 	}
47093bfd616SPantelis Antoniou 	if (host->cfg.f_max == 0) {
47130e6d979SDarwin Rambo 		printf("%s: Hardware doesn't specify base clock frequency\n",
47230e6d979SDarwin Rambo 		       __func__);
473af62a557SLei Wen 		return -1;
474af62a557SLei Wen 	}
475af62a557SLei Wen 	if (min_clk)
47693bfd616SPantelis Antoniou 		host->cfg.f_min = min_clk;
477af62a557SLei Wen 	else {
478113e5dfcSJaehoon Chung 		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
47993bfd616SPantelis Antoniou 			host->cfg.f_min = host->cfg.f_max /
48093bfd616SPantelis Antoniou 				SDHCI_MAX_DIV_SPEC_300;
481af62a557SLei Wen 		else
48293bfd616SPantelis Antoniou 			host->cfg.f_min = host->cfg.f_max /
48393bfd616SPantelis Antoniou 				SDHCI_MAX_DIV_SPEC_200;
484af62a557SLei Wen 	}
485af62a557SLei Wen 
48693bfd616SPantelis Antoniou 	host->cfg.voltages = 0;
487af62a557SLei Wen 	if (caps & SDHCI_CAN_VDD_330)
48893bfd616SPantelis Antoniou 		host->cfg.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
489af62a557SLei Wen 	if (caps & SDHCI_CAN_VDD_300)
49093bfd616SPantelis Antoniou 		host->cfg.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
491af62a557SLei Wen 	if (caps & SDHCI_CAN_VDD_180)
49293bfd616SPantelis Antoniou 		host->cfg.voltages |= MMC_VDD_165_195;
493236bfecfSJaehoon Chung 
494236bfecfSJaehoon Chung 	if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
49593bfd616SPantelis Antoniou 		host->cfg.voltages |= host->voltages;
496236bfecfSJaehoon Chung 
49793bfd616SPantelis Antoniou 	host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
498113e5dfcSJaehoon Chung 	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
499af62a557SLei Wen 		if (caps & SDHCI_CAN_DO_8BIT)
50093bfd616SPantelis Antoniou 			host->cfg.host_caps |= MMC_MODE_8BIT;
5011695b29aSJagannadha Sutradharudu Teki 	}
502236bfecfSJaehoon Chung 	if (host->host_caps)
50393bfd616SPantelis Antoniou 		host->cfg.host_caps |= host->host_caps;
50493bfd616SPantelis Antoniou 
50593bfd616SPantelis Antoniou 	host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
506af62a557SLei Wen 
507af62a557SLei Wen 	sdhci_reset(host, SDHCI_RESET_ALL);
50893bfd616SPantelis Antoniou 
50993bfd616SPantelis Antoniou 	host->mmc = mmc_create(&host->cfg, host);
51093bfd616SPantelis Antoniou 	if (host->mmc == NULL) {
51193bfd616SPantelis Antoniou 		printf("%s: mmc create fail!\n", __func__);
51293bfd616SPantelis Antoniou 		return -1;
51393bfd616SPantelis Antoniou 	}
514af62a557SLei Wen 
515af62a557SLei Wen 	return 0;
516af62a557SLei Wen }
517