Blame view

drivers/mmc/sdhci.c 14.1 KB
af62a5578   Lei Wen   MMC: add sdhci ge...
1
2
3
4
  /*
   * Copyright 2011, Marvell Semiconductor Inc.
   * Lei Wen <leiwen@marvell.com>
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
af62a5578   Lei Wen   MMC: add sdhci ge...
6
7
8
9
10
11
12
13
14
   *
   * Back ported to the 8xx platform (from the 8260 platform) by
   * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
   */
  
  #include <common.h>
  #include <malloc.h>
  #include <mmc.h>
  #include <sdhci.h>
492d3223b   Stefan Roese   mmc: sdhci.c: Add...
15
16
17
  #if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
  void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER;
  #else
af62a5578   Lei Wen   MMC: add sdhci ge...
18
  void *aligned_buffer;
492d3223b   Stefan Roese   mmc: sdhci.c: Add...
19
  #endif
af62a5578   Lei Wen   MMC: add sdhci ge...
20
21
22
23
24
25
26
27
28
29
  
  static void sdhci_reset(struct sdhci_host *host, u8 mask)
  {
  	unsigned long timeout;
  
  	/* Wait max 100 ms */
  	timeout = 100;
  	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
  	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
  		if (timeout == 0) {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
30
31
32
  			printf("%s: Reset 0x%x never completed.
  ",
  			       __func__, (int)mask);
af62a5578   Lei Wen   MMC: add sdhci ge...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  			return;
  		}
  		timeout--;
  		udelay(1000);
  	}
  }
  
  static void sdhci_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd)
  {
  	int i;
  	if (cmd->resp_type & MMC_RSP_136) {
  		/* CRC is stripped so we need to do some shifting. */
  		for (i = 0; i < 4; i++) {
  			cmd->response[i] = sdhci_readl(host,
  					SDHCI_RESPONSE + (3-i)*4) << 8;
  			if (i != 3)
  				cmd->response[i] |= sdhci_readb(host,
  						SDHCI_RESPONSE + (3-i)*4-1);
  		}
  	} else {
  		cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE);
  	}
  }
  
  static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
  {
  	int i;
  	char *offs;
  	for (i = 0; i < data->blocksize; i += 4) {
  		offs = data->dest + i;
  		if (data->flags == MMC_DATA_READ)
  			*(u32 *)offs = sdhci_readl(host, SDHCI_BUFFER);
  		else
  			sdhci_writel(host, *(u32 *)offs, SDHCI_BUFFER);
  	}
  }
  
  static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
  				unsigned int start_addr)
  {
a004abde8   Lei Wen   mmc: sdhci: add t...
73
  	unsigned int stat, rdy, mask, timeout, block = 0;
804c7f422   Jaehoon Chung   mmc: sdhci: add t...
74
75
  #ifdef CONFIG_MMC_SDMA
  	unsigned char ctrl;
2c011847c   Juhyun \(Justin\) Oh   Fix wrong sdhci h...
76
  	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
804c7f422   Jaehoon Chung   mmc: sdhci: add t...
77
  	ctrl &= ~SDHCI_CTRL_DMA_MASK;
2c011847c   Juhyun \(Justin\) Oh   Fix wrong sdhci h...
78
  	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
804c7f422   Jaehoon Chung   mmc: sdhci: add t...
79
  #endif
af62a5578   Lei Wen   MMC: add sdhci ge...
80

5d48e4224   Jaehoon Chung   mmc: sdhci: incre...
81
  	timeout = 1000000;
af62a5578   Lei Wen   MMC: add sdhci ge...
82
83
84
85
86
  	rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
  	mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE;
  	do {
  		stat = sdhci_readl(host, SDHCI_INT_STATUS);
  		if (stat & SDHCI_INT_ERROR) {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
87
88
89
  			printf("%s: Error detected in status(0x%X)!
  ",
  			       __func__, stat);
af62a5578   Lei Wen   MMC: add sdhci ge...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  			return -1;
  		}
  		if (stat & rdy) {
  			if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask))
  				continue;
  			sdhci_writel(host, rdy, SDHCI_INT_STATUS);
  			sdhci_transfer_pio(host, data);
  			data->dest += data->blocksize;
  			if (++block >= data->blocks)
  				break;
  		}
  #ifdef CONFIG_MMC_SDMA
  		if (stat & SDHCI_INT_DMA_END) {
  			sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS);
3e81c7724   Lei Wen   mmc: sdhci: fix s...
104
  			start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
af62a5578   Lei Wen   MMC: add sdhci ge...
105
106
107
108
  			start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
  			sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
  		}
  #endif
a004abde8   Lei Wen   mmc: sdhci: add t...
109
110
111
  		if (timeout-- > 0)
  			udelay(10);
  		else {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
112
113
  			printf("%s: Transfer data timeout
  ", __func__);
a004abde8   Lei Wen   mmc: sdhci: add t...
114
115
  			return -1;
  		}
af62a5578   Lei Wen   MMC: add sdhci ge...
116
117
118
  	} while (!(stat & SDHCI_INT_DATA_END));
  	return 0;
  }
56b34bc61   Przemyslaw Marczak   mmc: sdhci: Avoid...
119
120
121
122
123
124
125
126
127
128
129
130
  /*
   * No command will be sent by driver if card is busy, so driver must wait
   * for card ready state.
   * Every time when card is busy after timeout then (last) timeout value will be
   * increased twice but only if it doesn't exceed global defined maximum.
   * Each function call will use last timeout value. Max timeout can be redefined
   * in board config file.
   */
  #ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT
  #define CONFIG_SDHCI_CMD_MAX_TIMEOUT		3200
  #endif
  #define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT	100
6588c78bf   Jeroen Hofstee   sdhci: make local...
131
  static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
af62a5578   Lei Wen   MMC: add sdhci ge...
132
133
  		       struct mmc_data *data)
  {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
134
  	struct sdhci_host *host = mmc->priv;
af62a5578   Lei Wen   MMC: add sdhci ge...
135
136
137
138
  	unsigned int stat = 0;
  	int ret = 0;
  	int trans_bytes = 0, is_aligned = 1;
  	u32 mask, flags, mode;
56b34bc61   Przemyslaw Marczak   mmc: sdhci: Avoid...
139
  	unsigned int time = 0, start_addr = 0;
56b34bc61   Przemyslaw Marczak   mmc: sdhci: Avoid...
140
  	int mmc_dev = mmc->block_dev.dev;
29905a451   Stefan Roese   mmc: sdhci: Use t...
141
  	unsigned start = get_timer(0);
af62a5578   Lei Wen   MMC: add sdhci ge...
142

56b34bc61   Przemyslaw Marczak   mmc: sdhci: Avoid...
143
144
  	/* Timeout unit - ms */
  	static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;
af62a5578   Lei Wen   MMC: add sdhci ge...
145
146
147
148
149
150
151
152
153
154
  
  	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
  	mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
  
  	/* We shouldn't wait for data inihibit for stop commands, even
  	   though they might use busy signaling */
  	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
  		mask &= ~SDHCI_DATA_INHIBIT;
  
  	while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
56b34bc61   Przemyslaw Marczak   mmc: sdhci: Avoid...
155
  		if (time >= cmd_timeout) {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
156
  			printf("%s: MMC: %d busy ", __func__, mmc_dev);
56b34bc61   Przemyslaw Marczak   mmc: sdhci: Avoid...
157
158
159
160
161
162
163
164
165
166
  			if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
  				cmd_timeout += cmd_timeout;
  				printf("timeout increasing to: %u ms.
  ",
  				       cmd_timeout);
  			} else {
  				puts("timeout.
  ");
  				return COMM_ERR;
  			}
af62a5578   Lei Wen   MMC: add sdhci ge...
167
  		}
56b34bc61   Przemyslaw Marczak   mmc: sdhci: Avoid...
168
  		time++;
af62a5578   Lei Wen   MMC: add sdhci ge...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  		udelay(1000);
  	}
  
  	mask = SDHCI_INT_RESPONSE;
  	if (!(cmd->resp_type & MMC_RSP_PRESENT))
  		flags = SDHCI_CMD_RESP_NONE;
  	else if (cmd->resp_type & MMC_RSP_136)
  		flags = SDHCI_CMD_RESP_LONG;
  	else if (cmd->resp_type & MMC_RSP_BUSY) {
  		flags = SDHCI_CMD_RESP_SHORT_BUSY;
  		mask |= SDHCI_INT_DATA_END;
  	} else
  		flags = SDHCI_CMD_RESP_SHORT;
  
  	if (cmd->resp_type & MMC_RSP_CRC)
  		flags |= SDHCI_CMD_CRC;
  	if (cmd->resp_type & MMC_RSP_OPCODE)
  		flags |= SDHCI_CMD_INDEX;
  	if (data)
  		flags |= SDHCI_CMD_DATA;
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
189
  	/* Set Transfer mode regarding to data flag */
af62a5578   Lei Wen   MMC: add sdhci ge...
190
191
192
193
194
195
196
197
198
199
200
201
  	if (data != 0) {
  		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
  		mode = SDHCI_TRNS_BLK_CNT_EN;
  		trans_bytes = data->blocks * data->blocksize;
  		if (data->blocks > 1)
  			mode |= SDHCI_TRNS_MULTI;
  
  		if (data->flags == MMC_DATA_READ)
  			mode |= SDHCI_TRNS_READ;
  
  #ifdef CONFIG_MMC_SDMA
  		if (data->flags == MMC_DATA_READ)
3c1fcb770   Rob Herring   sdhci: fix warnin...
202
  			start_addr = (unsigned long)data->dest;
af62a5578   Lei Wen   MMC: add sdhci ge...
203
  		else
3c1fcb770   Rob Herring   sdhci: fix warnin...
204
  			start_addr = (unsigned long)data->src;
af62a5578   Lei Wen   MMC: add sdhci ge...
205
206
207
  		if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
  				(start_addr & 0x7) != 0x0) {
  			is_aligned = 0;
3c1fcb770   Rob Herring   sdhci: fix warnin...
208
  			start_addr = (unsigned long)aligned_buffer;
af62a5578   Lei Wen   MMC: add sdhci ge...
209
210
211
  			if (data->flags != MMC_DATA_READ)
  				memcpy(aligned_buffer, data->src, trans_bytes);
  		}
492d3223b   Stefan Roese   mmc: sdhci.c: Add...
212
213
214
215
216
217
218
219
220
221
  #if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
  		/*
  		 * Always use this bounce-buffer when
  		 * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined
  		 */
  		is_aligned = 0;
  		start_addr = (unsigned long)aligned_buffer;
  		if (data->flags != MMC_DATA_READ)
  			memcpy(aligned_buffer, data->src, trans_bytes);
  #endif
af62a5578   Lei Wen   MMC: add sdhci ge...
222
223
224
225
226
227
228
229
  		sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
  		mode |= SDHCI_TRNS_DMA;
  #endif
  		sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
  				data->blocksize),
  				SDHCI_BLOCK_SIZE);
  		sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
  		sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
5e1c23cd3   Kevin Liu   mmc: sdhci: add t...
230
231
  	} else if (cmd->resp_type & MMC_RSP_BUSY) {
  		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
af62a5578   Lei Wen   MMC: add sdhci ge...
232
233
234
235
  	}
  
  	sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
  #ifdef CONFIG_MMC_SDMA
2c2ec4c96   Lei Wen   mmc: sdhci: fix c...
236
  	flush_cache(start_addr, trans_bytes);
af62a5578   Lei Wen   MMC: add sdhci ge...
237
238
  #endif
  	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
29905a451   Stefan Roese   mmc: sdhci: Use t...
239
  	start = get_timer(0);
af62a5578   Lei Wen   MMC: add sdhci ge...
240
241
242
243
  	do {
  		stat = sdhci_readl(host, SDHCI_INT_STATUS);
  		if (stat & SDHCI_INT_ERROR)
  			break;
29905a451   Stefan Roese   mmc: sdhci: Use t...
244
245
  	} while (((stat & mask) != mask) &&
  		 (get_timer(start) < CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT));
af62a5578   Lei Wen   MMC: add sdhci ge...
246

29905a451   Stefan Roese   mmc: sdhci: Use t...
247
  	if (get_timer(start) >= CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT) {
3a6383207   Jaehoon Chung   mmc: sdhci: add t...
248
249
250
  		if (host->quirks & SDHCI_QUIRK_BROKEN_R1B)
  			return 0;
  		else {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
251
252
  			printf("%s: Timeout for status update!
  ", __func__);
3a6383207   Jaehoon Chung   mmc: sdhci: add t...
253
254
255
  			return TIMEOUT;
  		}
  	}
af62a5578   Lei Wen   MMC: add sdhci ge...
256
257
258
259
260
261
262
263
  	if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
  		sdhci_cmd_done(host, cmd);
  		sdhci_writel(host, mask, SDHCI_INT_STATUS);
  	} else
  		ret = -1;
  
  	if (!ret && data)
  		ret = sdhci_transfer_data(host, data, start_addr);
13243f2ea   Tushar Behera   mmc: sdhci: Add a...
264
265
  	if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD)
  		udelay(1000);
af62a5578   Lei Wen   MMC: add sdhci ge...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  	stat = sdhci_readl(host, SDHCI_INT_STATUS);
  	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
  	if (!ret) {
  		if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
  				!is_aligned && (data->flags == MMC_DATA_READ))
  			memcpy(data->dest, aligned_buffer, trans_bytes);
  		return 0;
  	}
  
  	sdhci_reset(host, SDHCI_RESET_CMD);
  	sdhci_reset(host, SDHCI_RESET_DATA);
  	if (stat & SDHCI_INT_TIMEOUT)
  		return TIMEOUT;
  	else
  		return COMM_ERR;
  }
  
  static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
  {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
285
  	struct sdhci_host *host = mmc->priv;
79667b7b7   Wenyou Yang   mmc: sdhci: Fix t...
286
  	unsigned int div, clk, timeout, reg;
af62a5578   Lei Wen   MMC: add sdhci ge...
287

79667b7b7   Wenyou Yang   mmc: sdhci: Fix t...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  	/* Wait max 20 ms */
  	timeout = 200;
  	while (sdhci_readl(host, SDHCI_PRESENT_STATE) &
  			   (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) {
  		if (timeout == 0) {
  			printf("%s: Timeout to wait cmd & data inhibit
  ",
  			       __func__);
  			return -1;
  		}
  
  		timeout--;
  		udelay(100);
  	}
  
  	reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
  	reg &= ~SDHCI_CLOCK_CARD_EN;
  	sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
af62a5578   Lei Wen   MMC: add sdhci ge...
306
307
308
  
  	if (clock == 0)
  		return 0;
113e5dfcd   Jaehoon Chung   mmc: sdhci: use t...
309
  	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
af62a5578   Lei Wen   MMC: add sdhci ge...
310
  		/* Version 3.00 divisors must be a multiple of 2. */
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
311
  		if (mmc->cfg->f_max <= clock)
af62a5578   Lei Wen   MMC: add sdhci ge...
312
313
314
  			div = 1;
  		else {
  			for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
315
  				if ((mmc->cfg->f_max / div) <= clock)
af62a5578   Lei Wen   MMC: add sdhci ge...
316
317
318
319
320
321
  					break;
  			}
  		}
  	} else {
  		/* Version 2.00 divisors must be a power of 2. */
  		for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
322
  			if ((mmc->cfg->f_max / div) <= clock)
af62a5578   Lei Wen   MMC: add sdhci ge...
323
324
325
326
  				break;
  		}
  	}
  	div >>= 1;
b09ed6e4f   Jaehoon Chung   mmc: s5p_sdhci: a...
327
328
  	if (host->set_clock)
  		host->set_clock(host->index, div);
af62a5578   Lei Wen   MMC: add sdhci ge...
329
330
331
332
333
334
335
336
337
338
339
  	clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
  	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
  		<< SDHCI_DIVIDER_HI_SHIFT;
  	clk |= SDHCI_CLOCK_INT_EN;
  	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
  
  	/* Wait max 20 ms */
  	timeout = 20;
  	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
  		& SDHCI_CLOCK_INT_STABLE)) {
  		if (timeout == 0) {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
340
341
342
  			printf("%s: Internal clock never stabilised.
  ",
  			       __func__);
af62a5578   Lei Wen   MMC: add sdhci ge...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  			return -1;
  		}
  		timeout--;
  		udelay(1000);
  	}
  
  	clk |= SDHCI_CLOCK_CARD_EN;
  	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
  	return 0;
  }
  
  static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
  {
  	u8 pwr = 0;
  
  	if (power != (unsigned short)-1) {
  		switch (1 << power) {
  		case MMC_VDD_165_195:
  			pwr = SDHCI_POWER_180;
  			break;
  		case MMC_VDD_29_30:
  		case MMC_VDD_30_31:
  			pwr = SDHCI_POWER_300;
  			break;
  		case MMC_VDD_32_33:
  		case MMC_VDD_33_34:
  			pwr = SDHCI_POWER_330;
  			break;
  		}
  	}
  
  	if (pwr == 0) {
  		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
  		return;
  	}
688c2d140   Mela Custodio   mmc: add no simul...
378
379
  	if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
  		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
af62a5578   Lei Wen   MMC: add sdhci ge...
380
381
382
383
  	pwr |= SDHCI_POWER_ON;
  
  	sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
  }
6588c78bf   Jeroen Hofstee   sdhci: make local...
384
  static void sdhci_set_ios(struct mmc *mmc)
af62a5578   Lei Wen   MMC: add sdhci ge...
385
386
  {
  	u32 ctrl;
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
387
  	struct sdhci_host *host = mmc->priv;
af62a5578   Lei Wen   MMC: add sdhci ge...
388

236bfecff   Jaehoon Chung   mmc: add the quir...
389
390
  	if (host->set_control_reg)
  		host->set_control_reg(host);
af62a5578   Lei Wen   MMC: add sdhci ge...
391
392
393
394
395
396
397
  	if (mmc->clock != host->clock)
  		sdhci_set_clock(mmc, mmc->clock);
  
  	/* Set bus width */
  	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
  	if (mmc->bus_width == 8) {
  		ctrl &= ~SDHCI_CTRL_4BITBUS;
113e5dfcd   Jaehoon Chung   mmc: sdhci: use t...
398
399
  		if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
  				(host->quirks & SDHCI_QUIRK_USE_WIDE8))
af62a5578   Lei Wen   MMC: add sdhci ge...
400
401
  			ctrl |= SDHCI_CTRL_8BITBUS;
  	} else {
f88a429f1   Matt Reimer   mmc: sdhci: fix b...
402
403
  		if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
  				(host->quirks & SDHCI_QUIRK_USE_WIDE8))
af62a5578   Lei Wen   MMC: add sdhci ge...
404
405
406
407
408
409
410
411
412
413
414
  			ctrl &= ~SDHCI_CTRL_8BITBUS;
  		if (mmc->bus_width == 4)
  			ctrl |= SDHCI_CTRL_4BITBUS;
  		else
  			ctrl &= ~SDHCI_CTRL_4BITBUS;
  	}
  
  	if (mmc->clock > 26000000)
  		ctrl |= SDHCI_CTRL_HISPD;
  	else
  		ctrl &= ~SDHCI_CTRL_HISPD;
236bfecff   Jaehoon Chung   mmc: add the quir...
415
416
  	if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
  		ctrl &= ~SDHCI_CTRL_HISPD;
af62a5578   Lei Wen   MMC: add sdhci ge...
417
418
  	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
  }
6588c78bf   Jeroen Hofstee   sdhci: make local...
419
  static int sdhci_init(struct mmc *mmc)
af62a5578   Lei Wen   MMC: add sdhci ge...
420
  {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
421
  	struct sdhci_host *host = mmc->priv;
af62a5578   Lei Wen   MMC: add sdhci ge...
422
423
424
425
  
  	if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) {
  		aligned_buffer = memalign(8, 512*1024);
  		if (!aligned_buffer) {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
426
427
428
  			printf("%s: Aligned buffer alloc failed!!!
  ",
  			       __func__);
af62a5578   Lei Wen   MMC: add sdhci ge...
429
430
431
  			return -1;
  		}
  	}
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
432
  	sdhci_set_power(host, fls(mmc->cfg->voltages) - 1);
470dcc751   Joe Hershberger   mmc: Add a SDHCI ...
433
434
  
  	if (host->quirks & SDHCI_QUIRK_NO_CD) {
102142c9e   Andrei Pistirica   drivers: mmc: add...
435
436
437
438
439
440
  #if defined(CONFIG_PIC32_SDHCI)
  		/* PIC32 SDHCI CD errata:
  		 * - set CD_TEST and clear CD_TEST_INS bit
  		 */
  		sdhci_writeb(host, SDHCI_CTRL_CD_TEST, SDHCI_HOST_CONTROL);
  #else
470dcc751   Joe Hershberger   mmc: Add a SDHCI ...
441
  		unsigned int status;
e113fe3c0   Matt Reimer   mmc: sdhci: don't...
442
  		sdhci_writeb(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST,
470dcc751   Joe Hershberger   mmc: Add a SDHCI ...
443
444
445
446
447
448
449
  			SDHCI_HOST_CONTROL);
  
  		status = sdhci_readl(host, SDHCI_PRESENT_STATE);
  		while ((!(status & SDHCI_CARD_PRESENT)) ||
  		    (!(status & SDHCI_CARD_STATE_STABLE)) ||
  		    (!(status & SDHCI_CARD_DETECT_PIN_LEVEL)))
  			status = sdhci_readl(host, SDHCI_PRESENT_STATE);
102142c9e   Andrei Pistirica   drivers: mmc: add...
450
  #endif
470dcc751   Joe Hershberger   mmc: Add a SDHCI ...
451
  	}
ce0c1bc13   Łukasz Majewski   mmc:sdhci:fix: Ch...
452
  	/* Enable only interrupts served by the SD controller */
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
453
454
  	sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
  		     SDHCI_INT_ENABLE);
ce0c1bc13   Łukasz Majewski   mmc:sdhci:fix: Ch...
455
456
  	/* Mask all sdhci interrupt sources */
  	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
af62a5578   Lei Wen   MMC: add sdhci ge...
457

af62a5578   Lei Wen   MMC: add sdhci ge...
458
459
  	return 0;
  }
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
460
461
462
463
464
465
  
  static const struct mmc_ops sdhci_ops = {
  	.send_cmd	= sdhci_send_command,
  	.set_ios	= sdhci_set_ios,
  	.init		= sdhci_init,
  };
af62a5578   Lei Wen   MMC: add sdhci ge...
466
467
  int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
  {
af62a5578   Lei Wen   MMC: add sdhci ge...
468
  	unsigned int caps;
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
469
470
  	host->cfg.name = host->name;
  	host->cfg.ops = &sdhci_ops;
af62a5578   Lei Wen   MMC: add sdhci ge...
471
472
473
474
  
  	caps = sdhci_readl(host, SDHCI_CAPABILITIES);
  #ifdef CONFIG_MMC_SDMA
  	if (!(caps & SDHCI_CAN_DO_SDMA)) {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
475
476
477
  		printf("%s: Your controller doesn't support SDMA!!
  ",
  		       __func__);
af62a5578   Lei Wen   MMC: add sdhci ge...
478
479
480
481
482
  		return -1;
  	}
  #endif
  
  	if (max_clk)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
483
  		host->cfg.f_max = max_clk;
af62a5578   Lei Wen   MMC: add sdhci ge...
484
  	else {
113e5dfcd   Jaehoon Chung   mmc: sdhci: use t...
485
  		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
486
  			host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
af62a5578   Lei Wen   MMC: add sdhci ge...
487
488
  				>> SDHCI_CLOCK_BASE_SHIFT;
  		else
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
489
  			host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK)
af62a5578   Lei Wen   MMC: add sdhci ge...
490
  				>> SDHCI_CLOCK_BASE_SHIFT;
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
491
  		host->cfg.f_max *= 1000000;
af62a5578   Lei Wen   MMC: add sdhci ge...
492
  	}
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
493
  	if (host->cfg.f_max == 0) {
30e6d979f   Darwin Rambo   mmc: Minor cleanu...
494
495
496
  		printf("%s: Hardware doesn't specify base clock frequency
  ",
  		       __func__);
af62a5578   Lei Wen   MMC: add sdhci ge...
497
498
499
  		return -1;
  	}
  	if (min_clk)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
500
  		host->cfg.f_min = min_clk;
af62a5578   Lei Wen   MMC: add sdhci ge...
501
  	else {
113e5dfcd   Jaehoon Chung   mmc: sdhci: use t...
502
  		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
503
504
  			host->cfg.f_min = host->cfg.f_max /
  				SDHCI_MAX_DIV_SPEC_300;
af62a5578   Lei Wen   MMC: add sdhci ge...
505
  		else
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
506
507
  			host->cfg.f_min = host->cfg.f_max /
  				SDHCI_MAX_DIV_SPEC_200;
af62a5578   Lei Wen   MMC: add sdhci ge...
508
  	}
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
509
  	host->cfg.voltages = 0;
af62a5578   Lei Wen   MMC: add sdhci ge...
510
  	if (caps & SDHCI_CAN_VDD_330)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
511
  		host->cfg.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
af62a5578   Lei Wen   MMC: add sdhci ge...
512
  	if (caps & SDHCI_CAN_VDD_300)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
513
  		host->cfg.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
af62a5578   Lei Wen   MMC: add sdhci ge...
514
  	if (caps & SDHCI_CAN_VDD_180)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
515
  		host->cfg.voltages |= MMC_VDD_165_195;
236bfecff   Jaehoon Chung   mmc: add the quir...
516
517
  
  	if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
518
  		host->cfg.voltages |= host->voltages;
236bfecff   Jaehoon Chung   mmc: add the quir...
519

93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
520
  	host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
113e5dfcd   Jaehoon Chung   mmc: sdhci: use t...
521
  	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
1695b29a5   Jagannadha Sutradharudu Teki   mmc: sdhci: Enabl...
522
  		if (caps & SDHCI_CAN_DO_8BIT)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
523
  			host->cfg.host_caps |= MMC_MODE_8BIT;
1695b29a5   Jagannadha Sutradharudu Teki   mmc: sdhci: Enabl...
524
  	}
429790026   Siva Durga Prasad Paladugu   mmc: sdhci: Clear...
525
526
527
  
  	if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
  		host->cfg.host_caps &= ~(MMC_MODE_HS | MMC_MODE_HS_52MHz);
236bfecff   Jaehoon Chung   mmc: add the quir...
528
  	if (host->host_caps)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
529
530
531
  		host->cfg.host_caps |= host->host_caps;
  
  	host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
af62a5578   Lei Wen   MMC: add sdhci ge...
532
533
  
  	sdhci_reset(host, SDHCI_RESET_ALL);
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
534
535
536
537
538
539
540
  
  	host->mmc = mmc_create(&host->cfg, host);
  	if (host->mmc == NULL) {
  		printf("%s: mmc create fail!
  ", __func__);
  		return -1;
  	}
af62a5578   Lei Wen   MMC: add sdhci ge...
541
542
543
  
  	return 0;
  }