Blame view

drivers/mmc/gen_atmel_mci.c 14.1 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
2
3
4
5
6
7
8
  /*
   * Copyright (C) 2010
   * Rob Emanuele <rob@emanuele.us>
   * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
   *
   * Original Driver:
   * Copyright (C) 2004-2006 Atmel Corporation
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
9
10
11
   */
  
  #include <common.h>
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
12
  #include <clk.h>
9d922450a   Simon Glass   dm: Use dm.h head...
13
  #include <dm.h>
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
14
15
16
17
  #include <mmc.h>
  #include <part.h>
  #include <malloc.h>
  #include <asm/io.h>
1221ce459   Masahiro Yamada   treewide: replace...
18
  #include <linux/errno.h>
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
19
20
  #include <asm/byteorder.h>
  #include <asm/arch/clk.h>
329f0f52f   Reinhard Meyer   ATMEL: fix relate...
21
  #include <asm/arch/hardware.h>
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
22
23
24
25
26
27
28
29
30
31
32
33
34
  #include "atmel_mci.h"
  
  #ifndef CONFIG_SYS_MMC_CLK_OD
  # define CONFIG_SYS_MMC_CLK_OD	150000
  #endif
  
  #define MMC_DEFAULT_BLKLEN	512
  
  #if defined(CONFIG_ATMEL_MCI_PORTB)
  # define MCI_BUS 1
  #else
  # define MCI_BUS 0
  #endif
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
35
36
37
38
39
40
41
  #ifdef CONFIG_DM_MMC
  struct atmel_mci_plat {
  	struct mmc		mmc;
  	struct mmc_config	cfg;
  	struct atmel_mci	*mci;
  };
  #endif
6b75d3594   Marek Vasut   mmc: atmel: Imple...
42
  struct atmel_mci_priv {
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
43
  #ifndef CONFIG_DM_MMC
6b75d3594   Marek Vasut   mmc: atmel: Imple...
44
45
  	struct mmc_config	cfg;
  	struct atmel_mci	*mci;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
46
  #endif
877807e19   Marek Vasut   mmc: atmel: Zap g...
47
  	unsigned int		initialized:1;
b4670a0c2   Gregory CLEMENT   mmc: atmel: Prope...
48
  	unsigned int		curr_clk;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
49
  #ifdef CONFIG_DM_MMC
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
50
51
  	ulong		bus_clk_rate;
  #endif
6b75d3594   Marek Vasut   mmc: atmel: Imple...
52
  };
aac4b69b2   Bo Shen   mmc: atmel_mci: u...
53
54
55
56
57
  /* Read Atmel MCI IP version */
  static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
  {
  	return readl(&mci->version) & 0x00000fff;
  }
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
58
59
60
61
62
63
64
65
  /*
   * Print command and status:
   *
   * - always when DEBUG is defined
   * - on command errors
   */
  static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
  {
b84c9c9a9   Marek Vasut   mmc: atmel: Silen...
66
67
68
  	debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s
  ",
  	      cmdr, cmdr & 0x3F, arg, status, msg);
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
69
  }
9b79dbd20   Jean-Jacques Hiblot   mmc: atmel: when ...
70
71
72
73
74
75
76
77
78
79
80
81
82
  static inline void mci_set_blklen(atmel_mci_t *mci, int blklen)
  {
  	unsigned int version = atmel_mci_get_version(mci);
  
  	blklen &= 0xfffc;
  
  	/* MCI IP version >= 0x200 has blkr */
  	if (version >= 0x200)
  		writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)),
  		       &mci->blkr);
  	else
  		writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr);
  }
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
83
  /* Setup for MCI Clock and Block Size */
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
84
  #ifdef CONFIG_DM_MMC
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
85
  static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
86
  {
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
87
88
89
  	struct atmel_mci_plat *plat = dev_get_platdata(dev);
  	struct atmel_mci_priv *priv = dev_get_priv(dev);
  	struct mmc *mmc = &plat->mmc;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
90
  	u32 bus_hz = priv->bus_clk_rate;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
91
  	atmel_mci_t *mci = plat->mci;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
92
  #else
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
93
94
  static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
  {
6b75d3594   Marek Vasut   mmc: atmel: Imple...
95
  	struct atmel_mci_priv *priv = mmc->priv;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
96
  	u32 bus_hz = get_mci_clk_rate();
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
97
  	atmel_mci_t *mci = priv->mci;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
98
  #endif
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
99
  	u32 clkdiv = 255;
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
100
101
102
  	unsigned int version = atmel_mci_get_version(mci);
  	u32 clkodd = 0;
  	u32 mr;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
103
104
105
106
107
  
  	debug("mci: bus_hz is %u, setting clock %u Hz, block size %u
  ",
  		bus_hz, hz, blklen);
  	if (hz > 0) {
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
108
109
110
111
112
113
114
  		if (version >= 0x500) {
  			clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
  			if (clkdiv > 511)
  				clkdiv = 511;
  
  			clkodd = clkdiv & 1;
  			clkdiv >>= 1;
b84c9c9a9   Marek Vasut   mmc: atmel: Silen...
115
116
117
  			debug("mci: setting clock %u Hz, block size %u
  ",
  			      bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
118
119
120
121
122
123
  		} else {
  			/* find clkdiv yielding a rate <= than requested */
  			for (clkdiv = 0; clkdiv < 255; clkdiv++) {
  				if ((bus_hz / (clkdiv + 1) / 2) <= hz)
  					break;
  			}
b84c9c9a9   Marek Vasut   mmc: atmel: Silen...
124
125
126
  			debug("mci: setting clock %u Hz, block size %u
  ",
  			      (bus_hz / (clkdiv + 1)) / 2, blklen);
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
127

1592ef859   Reinhard Meyer   AT91: MCI: add SD...
128
129
  		}
  	}
b4670a0c2   Gregory CLEMENT   mmc: atmel: Prope...
130
131
132
133
  	if (version >= 0x500)
  		priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
  	else
  		priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
134
135
136
137
138
139
  
  	mr = MMCI_BF(CLKDIV, clkdiv);
  
  	/* MCI IP version >= 0x200 has R/WPROOF */
  	if (version >= 0x200)
  		mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
1db7377a7   Wu, Josh   mmc: at91: add mu...
140
  	/*
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
141
142
  	 * MCI IP version >= 0x500 use bit 16 as clkodd.
  	 * MCI IP version < 0x500 use upper 16 bits for blklen.
1db7377a7   Wu, Josh   mmc: at91: add mu...
143
  	 */
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
144
145
  	if (version >= 0x500)
  		mr |= MMCI_BF(CLKODD, clkodd);
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
146
147
  
  	writel(mr, &mci->mr);
9b79dbd20   Jean-Jacques Hiblot   mmc: atmel: when ...
148
  	mci_set_blklen(mci, blklen);
cd60ebd43   Bo Shen   MMC: atmel_mci: r...
149

da55c66ec   Bo Shen   MMC: atmel_mci: e...
150
151
  	if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
  		writel(MMCI_BIT(HSMODE), &mci->cfg);
877807e19   Marek Vasut   mmc: atmel: Zap g...
152
  	priv->initialized = 1;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  }
  
  /* Return the CMDR with flags for a given command and data packet */
  static u32 mci_encode_cmd(
  	struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
  {
  	u32 cmdr = 0;
  
  	/* Default Flags for Errors */
  	*error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
  		MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
  
  	/* Default Flags for the Command */
  	cmdr |= MMCI_BIT(MAXLAT);
  
  	if (data) {
  		cmdr |= MMCI_BF(TRCMD, 1);
  		if (data->blocks > 1)
  			cmdr |= MMCI_BF(TRTYP, 1);
  		if (data->flags & MMC_DATA_READ)
  			cmdr |= MMCI_BIT(TRDIR);
  	}
  
  	if (cmd->resp_type & MMC_RSP_CRC)
  		*error_flags |= MMCI_BIT(RCRCE);
  	if (cmd->resp_type & MMC_RSP_136)
  		cmdr |= MMCI_BF(RSPTYP, 2);
  	else if (cmd->resp_type & MMC_RSP_BUSY)
  		cmdr |= MMCI_BF(RSPTYP, 3);
  	else if (cmd->resp_type & MMC_RSP_PRESENT)
  		cmdr |= MMCI_BF(RSPTYP, 1);
  
  	return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
  }
  
  /* Entered into function pointer in mci_send_cmd */
  static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
  {
  	u32 status;
  
  	do {
  		status = readl(&mci->sr);
  		if (status & (error_flags | MMCI_BIT(OVRE)))
  			goto io_fail;
  	} while (!(status & MMCI_BIT(RXRDY)));
  
  	if (status & MMCI_BIT(RXRDY)) {
  		*data = readl(&mci->rdr);
  		status = 0;
  	}
  io_fail:
  	return status;
  }
  
  /* Entered into function pointer in mci_send_cmd */
  static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
  {
  	u32 status;
  
  	do {
  		status = readl(&mci->sr);
  		if (status & (error_flags | MMCI_BIT(UNRE)))
  			goto io_fail;
  	} while (!(status & MMCI_BIT(TXRDY)));
  
  	if (status & MMCI_BIT(TXRDY)) {
  		writel(*data, &mci->tdr);
  		status = 0;
  	}
  io_fail:
  	return status;
  }
  
  /*
   * Entered into mmc structure during driver init
   *
   * Sends a command out on the bus and deals with the block data.
   * Takes the mmc pointer, a command pointer, and an optional data pointer.
   */
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
232
233
234
235
  #ifdef CONFIG_DM_MMC
  static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
  			      struct mmc_data *data)
  {
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
236
  	struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
237
  	struct atmel_mci_priv *priv = dev_get_priv(dev);
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
238
  	atmel_mci_t *mci = plat->mci;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
239
  #else
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
240
241
242
  static int
  mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
  {
6b75d3594   Marek Vasut   mmc: atmel: Imple...
243
244
  	struct atmel_mci_priv *priv = mmc->priv;
  	atmel_mci_t *mci = priv->mci;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
245
  #endif
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
246
247
248
  	u32 cmdr;
  	u32 error_flags = 0;
  	u32 status;
877807e19   Marek Vasut   mmc: atmel: Zap g...
249
  	if (!priv->initialized) {
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
250
251
  		puts ("MCI not initialized!
  ");
915ffa521   Jaehoon Chung   mmc: use the gene...
252
  		return -ECOMM;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
253
254
255
256
  	}
  
  	/* Figure out the transfer arguments */
  	cmdr = mci_encode_cmd(cmd, data, &error_flags);
9b79dbd20   Jean-Jacques Hiblot   mmc: atmel: when ...
257
  	mci_set_blklen(mci, data->blocksize);
1db7377a7   Wu, Josh   mmc: at91: add mu...
258
259
260
  	/* For multi blocks read/write, set the block register */
  	if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
  			|| (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
9b79dbd20   Jean-Jacques Hiblot   mmc: atmel: when ...
261
262
  		writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize),
  		       &mci->blkr);
1db7377a7   Wu, Josh   mmc: at91: add mu...
263

1592ef859   Reinhard Meyer   AT91: MCI: add SD...
264
265
266
267
268
269
270
271
272
273
  	/* Send the command */
  	writel(cmd->cmdarg, &mci->argr);
  	writel(cmdr, &mci->cmdr);
  
  #ifdef DEBUG
  	dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
  #endif
  
  	/* Wait for the command to complete */
  	while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
93e3236cc   Bo Shen   mmc: atmel_mci: a...
274
275
  	if ((status & error_flags) & MMCI_BIT(RTOE)) {
  		dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
915ffa521   Jaehoon Chung   mmc: use the gene...
276
  		return -ETIMEDOUT;
93e3236cc   Bo Shen   mmc: atmel_mci: a...
277
  	} else if (status & error_flags) {
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
278
  		dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
915ffa521   Jaehoon Chung   mmc: use the gene...
279
  		return -ECOMM;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  	}
  
  	/* Copy the response to the response buffer */
  	if (cmd->resp_type & MMC_RSP_136) {
  		cmd->response[0] = readl(&mci->rspr);
  		cmd->response[1] = readl(&mci->rspr1);
  		cmd->response[2] = readl(&mci->rspr2);
  		cmd->response[3] = readl(&mci->rspr3);
  	} else
  		cmd->response[0] = readl(&mci->rspr);
  
  	/* transfer all of the blocks */
  	if (data) {
  		u32 word_count, block_count;
  		u32* ioptr;
9b79dbd20   Jean-Jacques Hiblot   mmc: atmel: when ...
295
  		u32 i;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
296
297
298
299
300
  		u32 (*mci_data_op)
  			(atmel_mci_t *mci, u32* data, u32 error_flags);
  
  		if (data->flags & MMC_DATA_READ) {
  			mci_data_op = mci_data_read;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
301
302
303
  			ioptr = (u32*)data->dest;
  		} else {
  			mci_data_op = mci_data_write;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  			ioptr = (u32*)data->src;
  		}
  
  		status = 0;
  		for (block_count = 0;
  				block_count < data->blocks && !status;
  				block_count++) {
  			word_count = 0;
  			do {
  				status = mci_data_op(mci, ioptr, error_flags);
  				word_count++;
  				ioptr++;
  			} while (!status && word_count < (data->blocksize/4));
  #ifdef DEBUG
  			if (data->flags & MMC_DATA_READ)
  			{
9902c7b6f   Wu, Josh   mmc: atmel_mci: f...
320
  				u32 cnt = word_count * 4;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
321
322
  				printf("Read Data:
  ");
9902c7b6f   Wu, Josh   mmc: atmel_mci: f...
323
324
  				print_buffer(0, data->dest + cnt * block_count,
  					     1, cnt, 0);
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
325
326
  			}
  #endif
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
327
328
329
  			if (status) {
  				dump_cmd(cmdr, cmd->cmdarg, status,
  					"Data Transfer Failed");
915ffa521   Jaehoon Chung   mmc: use the gene...
330
  				return -ECOMM;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
331
332
333
334
335
336
337
338
339
340
341
  			}
  		}
  
  		/* Wait for Transfer End */
  		i = 0;
  		do {
  			status = readl(&mci->sr);
  
  			if (status & error_flags) {
  				dump_cmd(cmdr, cmd->cmdarg, status,
  					"DTIP Wait Failed");
915ffa521   Jaehoon Chung   mmc: use the gene...
342
  				return -ECOMM;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
343
344
345
346
347
348
349
350
  			}
  			i++;
  		} while ((status & MMCI_BIT(DTIP)) && i < 10000);
  		if (status & MMCI_BIT(DTIP)) {
  			dump_cmd(cmdr, cmd->cmdarg, status,
  				"XFER DTIP never unset, ignoring");
  		}
  	}
b4670a0c2   Gregory CLEMENT   mmc: atmel: Prope...
351
352
353
354
355
356
  	/*
  	 * After the switch command, wait for 8 clocks before the next
  	 * command
  	 */
  	if (cmd->cmdidx == MMC_CMD_SWITCH)
  		udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
357
358
  	return 0;
  }
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
359
360
361
  #ifdef CONFIG_DM_MMC
  static int atmel_mci_set_ios(struct udevice *dev)
  {
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
362
  	struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
363
  	struct mmc *mmc = mmc_get_mmc_dev(dev);
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
364
  	atmel_mci_t *mci = plat->mci;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
365
  #else
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
366
  /* Entered into mmc structure during driver init */
07b0b9c00   Jaehoon Chung   mmc: change the s...
367
  static int mci_set_ios(struct mmc *mmc)
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
368
  {
6b75d3594   Marek Vasut   mmc: atmel: Imple...
369
370
  	struct atmel_mci_priv *priv = mmc->priv;
  	atmel_mci_t *mci = priv->mci;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
371
  #endif
aac4b69b2   Bo Shen   mmc: atmel_mci: u...
372
373
374
  	int bus_width = mmc->bus_width;
  	unsigned int version = atmel_mci_get_version(mci);
  	int busw;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
375
376
  
  	/* Set the clock speed */
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
377
  #ifdef CONFIG_DM_MMC
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
378
  	mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
379
  #else
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
380
  	mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
381
  #endif
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
382
383
384
385
  
  	/*
  	 * set the bus width and select slot for this interface
  	 * there is no capability for multiple slots on the same interface yet
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
386
  	 */
aac4b69b2   Bo Shen   mmc: atmel_mci: u...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  	if ((version & 0xf00) >= 0x300) {
  		switch (bus_width) {
  		case 8:
  			busw = 3;
  			break;
  		case 4:
  			busw = 2;
  			break;
  		default:
  			busw = 0;
  			break;
  		}
  
  		writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
  	} else {
  		busw = (bus_width == 4) ? 1 : 0;
  
  		writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
  	}
07b0b9c00   Jaehoon Chung   mmc: change the s...
406
407
  
  	return 0;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
408
  }
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
409
  #ifdef CONFIG_DM_MMC
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
410
  static int atmel_mci_hw_init(struct udevice *dev)
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
411
  {
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
412
413
  	struct atmel_mci_plat *plat = dev_get_platdata(dev);
  	atmel_mci_t *mci = plat->mci;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
414
  #else
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
415
416
417
  /* Entered into mmc structure during driver init */
  static int mci_init(struct mmc *mmc)
  {
6b75d3594   Marek Vasut   mmc: atmel: Imple...
418
419
  	struct atmel_mci_priv *priv = mmc->priv;
  	atmel_mci_t *mci = priv->mci;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
420
  #endif
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
421
422
423
424
425
  
  	/* Initialize controller */
  	writel(MMCI_BIT(SWRST), &mci->cr);	/* soft reset */
  	writel(MMCI_BIT(PWSDIS), &mci->cr);	/* disable power save */
  	writel(MMCI_BIT(MCIEN), &mci->cr);	/* enable mci */
2aed9d14c   Reinhard Meyer   AT91: gen_atmel_m...
426
  	writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);	/* select port */
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
427

9924ca6e9   Wu, Josh   mmc: at91: use ma...
428
429
  	/* This delay can be optimized, but stick with max value */
  	writel(0x7f, &mci->dtor);
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
430
431
432
433
  	/* Disable Interrupts */
  	writel(~0UL, &mci->idr);
  
  	/* Set default clocks and blocklen */
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
434
  #ifdef CONFIG_DM_MMC
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
435
  	mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
436
  #else
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
437
  	mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
438
  #endif
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
439
440
441
  
  	return 0;
  }
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
442
  #ifndef CONFIG_DM_MMC
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
443
444
445
446
447
  static const struct mmc_ops atmel_mci_ops = {
  	.send_cmd	= mci_send_cmd,
  	.set_ios	= mci_set_ios,
  	.init		= mci_init,
  };
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
448
449
450
451
452
453
454
  /*
   * This is the only exported function
   *
   * Call it with the MCI register base address
   */
  int atmel_mci_init(void *regs)
  {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
455
456
  	struct mmc *mmc;
  	struct mmc_config *cfg;
6b75d3594   Marek Vasut   mmc: atmel: Imple...
457
  	struct atmel_mci_priv *priv;
aac4b69b2   Bo Shen   mmc: atmel_mci: u...
458
  	unsigned int version;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
459

6b75d3594   Marek Vasut   mmc: atmel: Imple...
460
461
462
  	priv = calloc(1, sizeof(*priv));
  	if (!priv)
  		return -ENOMEM;
aac4b69b2   Bo Shen   mmc: atmel_mci: u...
463

6b75d3594   Marek Vasut   mmc: atmel: Imple...
464
  	cfg = &priv->cfg;
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
465
466
467
  
  	cfg->name = "mci";
  	cfg->ops = &atmel_mci_ops;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
468

6b75d3594   Marek Vasut   mmc: atmel: Imple...
469
  	priv->mci = (struct atmel_mci *)regs;
877807e19   Marek Vasut   mmc: atmel: Zap g...
470
  	priv->initialized = 0;
6b75d3594   Marek Vasut   mmc: atmel: Imple...
471

1592ef859   Reinhard Meyer   AT91: MCI: add SD...
472
  	/* need to be able to pass these in on a board by board basis */
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
473
  	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
6b75d3594   Marek Vasut   mmc: atmel: Imple...
474
  	version = atmel_mci_get_version(priv->mci);
da55c66ec   Bo Shen   MMC: atmel_mci: e...
475
  	if ((version & 0xf00) >= 0x300) {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
476
  		cfg->host_caps = MMC_MODE_8BIT;
da55c66ec   Bo Shen   MMC: atmel_mci: e...
477
478
  		cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
  	}
aac4b69b2   Bo Shen   mmc: atmel_mci: u...
479

93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
480
  	cfg->host_caps |= MMC_MODE_4BIT;
aac4b69b2   Bo Shen   mmc: atmel_mci: u...
481

1592ef859   Reinhard Meyer   AT91: MCI: add SD...
482
483
484
485
  	/*
  	 * min and max frequencies determined by
  	 * max and min of clock divider
  	 */
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
486
487
488
489
  	cfg->f_min = get_mci_clk_rate() / (2*256);
  	cfg->f_max = get_mci_clk_rate() / (2*1);
  
  	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
490

6b75d3594   Marek Vasut   mmc: atmel: Imple...
491
  	mmc = mmc_create(cfg, priv);
8feafcc49   John Rigby   MMC: make b_max u...
492

93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
493
  	if (mmc == NULL) {
6b75d3594   Marek Vasut   mmc: atmel: Imple...
494
495
  		free(priv);
  		return -ENODEV;
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
496
  	}
6b75d3594   Marek Vasut   mmc: atmel: Imple...
497
  	/* NOTE: possibly leaking the priv structure */
1592ef859   Reinhard Meyer   AT91: MCI: add SD...
498
499
500
  
  	return 0;
  }
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
501
502
503
504
505
506
507
  #endif
  
  #ifdef CONFIG_DM_MMC
  static const struct dm_mmc_ops atmel_mci_mmc_ops = {
  	.send_cmd = atmel_mci_send_cmd,
  	.set_ios = atmel_mci_set_ios,
  };
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
508
  static void atmel_mci_setup_cfg(struct udevice *dev)
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
509
  {
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
510
511
  	struct atmel_mci_plat *plat = dev_get_platdata(dev);
  	struct atmel_mci_priv *priv = dev_get_priv(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
512
513
  	struct mmc_config *cfg;
  	u32 version;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
514
  	cfg = &plat->cfg;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
515
516
517
518
519
520
521
  	cfg->name = "Atmel mci";
  	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
  
  	/*
  	 * If the version is above 3.0, the capabilities of the 8-bit
  	 * bus width and high speed are supported.
  	 */
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
522
  	version = atmel_mci_get_version(plat->mci);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  	if ((version & 0xf00) >= 0x300) {
  		cfg->host_caps = MMC_MODE_8BIT |
  				 MMC_MODE_HS | MMC_MODE_HS_52MHz;
  	}
  
  	cfg->host_caps |= MMC_MODE_4BIT;
  	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
  	cfg->f_min = priv->bus_clk_rate / (2 * 256);
  	cfg->f_max = priv->bus_clk_rate / 2;
  }
  
  static int atmel_mci_enable_clk(struct udevice *dev)
  {
  	struct atmel_mci_priv *priv = dev_get_priv(dev);
  	struct clk clk;
  	ulong clk_rate;
  	int ret = 0;
  
  	ret = clk_get_by_index(dev, 0, &clk);
  	if (ret) {
  		ret = -EINVAL;
  		goto failed;
  	}
  
  	ret = clk_enable(&clk);
  	if (ret)
  		goto failed;
  
  	clk_rate = clk_get_rate(&clk);
  	if (!clk_rate) {
  		ret = -EINVAL;
  		goto failed;
  	}
  
  	priv->bus_clk_rate = clk_rate;
  
  failed:
  	clk_free(&clk);
  
  	return ret;
  }
  
  static int atmel_mci_probe(struct udevice *dev)
  {
  	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
568
  	struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
569
570
571
572
573
574
  	struct mmc *mmc;
  	int ret;
  
  	ret = atmel_mci_enable_clk(dev);
  	if (ret)
  		return ret;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
575
  	plat->mci = (struct atmel_mci *)devfdt_get_addr_ptr(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
576

722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
577
  	atmel_mci_setup_cfg(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
578

722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
579
580
  	mmc = &plat->mmc;
  	mmc->cfg = &plat->cfg;
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
581
582
  	mmc->dev = dev;
  	upriv->mmc = mmc;
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
583
  	atmel_mci_hw_init(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
584
585
586
587
588
589
  
  	return 0;
  }
  
  static int atmel_mci_bind(struct udevice *dev)
  {
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
590
  	struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
591

722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
592
  	return mmc_bind(dev, &plat->mmc, &plat->cfg);
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
593
594
595
596
597
598
599
600
601
602
603
604
605
  }
  
  static const struct udevice_id atmel_mci_ids[] = {
  	{ .compatible = "atmel,hsmci" },
  	{ }
  };
  
  U_BOOT_DRIVER(atmel_mci) = {
  	.name = "atmel-mci",
  	.id = UCLASS_MMC,
  	.of_match = atmel_mci_ids,
  	.bind = atmel_mci_bind,
  	.probe = atmel_mci_probe,
722b150e6   Wenyou.Yang@microchip.com   mmc: gen_atmel_mc...
606
  	.platdata_auto_alloc_size = sizeof(struct atmel_mci_plat),
c86c0155d   Wenyou Yang   mmc: gen_atmel_mc...
607
608
609
610
  	.priv_auto_alloc_size = sizeof(struct atmel_mci_priv),
  	.ops = &atmel_mci_mmc_ops,
  };
  #endif