xref: /OK3568_Linux_fs/u-boot/drivers/mmc/gen_atmel_mci.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2010
3*4882a593Smuzhiyun  * Rob Emanuele <rob@emanuele.us>
4*4882a593Smuzhiyun  * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Original Driver:
7*4882a593Smuzhiyun  * Copyright (C) 2004-2006 Atmel Corporation
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <common.h>
13*4882a593Smuzhiyun #include <clk.h>
14*4882a593Smuzhiyun #include <dm.h>
15*4882a593Smuzhiyun #include <mmc.h>
16*4882a593Smuzhiyun #include <part.h>
17*4882a593Smuzhiyun #include <malloc.h>
18*4882a593Smuzhiyun #include <asm/io.h>
19*4882a593Smuzhiyun #include <linux/errno.h>
20*4882a593Smuzhiyun #include <asm/byteorder.h>
21*4882a593Smuzhiyun #include <asm/arch/clk.h>
22*4882a593Smuzhiyun #include <asm/arch/hardware.h>
23*4882a593Smuzhiyun #include "atmel_mci.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #ifndef CONFIG_SYS_MMC_CLK_OD
28*4882a593Smuzhiyun # define CONFIG_SYS_MMC_CLK_OD	150000
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define MMC_DEFAULT_BLKLEN	512
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #if defined(CONFIG_ATMEL_MCI_PORTB)
34*4882a593Smuzhiyun # define MCI_BUS 1
35*4882a593Smuzhiyun #else
36*4882a593Smuzhiyun # define MCI_BUS 0
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
40*4882a593Smuzhiyun struct atmel_mci_plat {
41*4882a593Smuzhiyun 	struct mmc		mmc;
42*4882a593Smuzhiyun 	struct mmc_config	cfg;
43*4882a593Smuzhiyun 	struct atmel_mci	*mci;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun #endif
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun struct atmel_mci_priv {
48*4882a593Smuzhiyun #ifndef CONFIG_DM_MMC
49*4882a593Smuzhiyun 	struct mmc_config	cfg;
50*4882a593Smuzhiyun 	struct atmel_mci	*mci;
51*4882a593Smuzhiyun #endif
52*4882a593Smuzhiyun 	unsigned int		initialized:1;
53*4882a593Smuzhiyun 	unsigned int		curr_clk;
54*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
55*4882a593Smuzhiyun 	ulong		bus_clk_rate;
56*4882a593Smuzhiyun #endif
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* Read Atmel MCI IP version */
atmel_mci_get_version(struct atmel_mci * mci)60*4882a593Smuzhiyun static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	return readl(&mci->version) & 0x00000fff;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun  * Print command and status:
67*4882a593Smuzhiyun  *
68*4882a593Smuzhiyun  * - always when DEBUG is defined
69*4882a593Smuzhiyun  * - on command errors
70*4882a593Smuzhiyun  */
dump_cmd(u32 cmdr,u32 arg,u32 status,const char * msg)71*4882a593Smuzhiyun static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
74*4882a593Smuzhiyun 	      cmdr, cmdr & 0x3F, arg, status, msg);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /* Setup for MCI Clock and Block Size */
78*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
mci_set_mode(struct udevice * dev,u32 hz,u32 blklen)79*4882a593Smuzhiyun static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
82*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = dev_get_priv(dev);
83*4882a593Smuzhiyun 	struct mmc *mmc = &plat->mmc;
84*4882a593Smuzhiyun 	u32 bus_hz = priv->bus_clk_rate;
85*4882a593Smuzhiyun 	atmel_mci_t *mci = plat->mci;
86*4882a593Smuzhiyun #else
87*4882a593Smuzhiyun static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = mmc->priv;
90*4882a593Smuzhiyun 	u32 bus_hz = get_mci_clk_rate();
91*4882a593Smuzhiyun 	atmel_mci_t *mci = priv->mci;
92*4882a593Smuzhiyun #endif
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	u32 clkdiv = 255;
95*4882a593Smuzhiyun 	unsigned int version = atmel_mci_get_version(mci);
96*4882a593Smuzhiyun 	u32 clkodd = 0;
97*4882a593Smuzhiyun 	u32 mr;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
100*4882a593Smuzhiyun 		bus_hz, hz, blklen);
101*4882a593Smuzhiyun 	if (hz > 0) {
102*4882a593Smuzhiyun 		if (version >= 0x500) {
103*4882a593Smuzhiyun 			clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
104*4882a593Smuzhiyun 			if (clkdiv > 511)
105*4882a593Smuzhiyun 				clkdiv = 511;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 			clkodd = clkdiv & 1;
108*4882a593Smuzhiyun 			clkdiv >>= 1;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 			debug("mci: setting clock %u Hz, block size %u\n",
111*4882a593Smuzhiyun 			      bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
112*4882a593Smuzhiyun 		} else {
113*4882a593Smuzhiyun 			/* find clkdiv yielding a rate <= than requested */
114*4882a593Smuzhiyun 			for (clkdiv = 0; clkdiv < 255; clkdiv++) {
115*4882a593Smuzhiyun 				if ((bus_hz / (clkdiv + 1) / 2) <= hz)
116*4882a593Smuzhiyun 					break;
117*4882a593Smuzhiyun 			}
118*4882a593Smuzhiyun 			debug("mci: setting clock %u Hz, block size %u\n",
119*4882a593Smuzhiyun 			      (bus_hz / (clkdiv + 1)) / 2, blklen);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 		}
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 	if (version >= 0x500)
124*4882a593Smuzhiyun 		priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
125*4882a593Smuzhiyun 	else
126*4882a593Smuzhiyun 		priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
127*4882a593Smuzhiyun 	blklen &= 0xfffc;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	mr = MMCI_BF(CLKDIV, clkdiv);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* MCI IP version >= 0x200 has R/WPROOF */
132*4882a593Smuzhiyun 	if (version >= 0x200)
133*4882a593Smuzhiyun 		mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/*
136*4882a593Smuzhiyun 	 * MCI IP version >= 0x500 use bit 16 as clkodd.
137*4882a593Smuzhiyun 	 * MCI IP version < 0x500 use upper 16 bits for blklen.
138*4882a593Smuzhiyun 	 */
139*4882a593Smuzhiyun 	if (version >= 0x500)
140*4882a593Smuzhiyun 		mr |= MMCI_BF(CLKODD, clkodd);
141*4882a593Smuzhiyun 	else
142*4882a593Smuzhiyun 		mr |= MMCI_BF(BLKLEN, blklen);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	writel(mr, &mci->mr);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	/* MCI IP version >= 0x200 has blkr */
147*4882a593Smuzhiyun 	if (version >= 0x200)
148*4882a593Smuzhiyun 		writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
151*4882a593Smuzhiyun 		writel(MMCI_BIT(HSMODE), &mci->cfg);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	priv->initialized = 1;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /* Return the CMDR with flags for a given command and data packet */
157*4882a593Smuzhiyun static u32 mci_encode_cmd(
158*4882a593Smuzhiyun 	struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	u32 cmdr = 0;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	/* Default Flags for Errors */
163*4882a593Smuzhiyun 	*error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
164*4882a593Smuzhiyun 		MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	/* Default Flags for the Command */
167*4882a593Smuzhiyun 	cmdr |= MMCI_BIT(MAXLAT);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if (data) {
170*4882a593Smuzhiyun 		cmdr |= MMCI_BF(TRCMD, 1);
171*4882a593Smuzhiyun 		if (data->blocks > 1)
172*4882a593Smuzhiyun 			cmdr |= MMCI_BF(TRTYP, 1);
173*4882a593Smuzhiyun 		if (data->flags & MMC_DATA_READ)
174*4882a593Smuzhiyun 			cmdr |= MMCI_BIT(TRDIR);
175*4882a593Smuzhiyun 	}
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (cmd->resp_type & MMC_RSP_CRC)
178*4882a593Smuzhiyun 		*error_flags |= MMCI_BIT(RCRCE);
179*4882a593Smuzhiyun 	if (cmd->resp_type & MMC_RSP_136)
180*4882a593Smuzhiyun 		cmdr |= MMCI_BF(RSPTYP, 2);
181*4882a593Smuzhiyun 	else if (cmd->resp_type & MMC_RSP_BUSY)
182*4882a593Smuzhiyun 		cmdr |= MMCI_BF(RSPTYP, 3);
183*4882a593Smuzhiyun 	else if (cmd->resp_type & MMC_RSP_PRESENT)
184*4882a593Smuzhiyun 		cmdr |= MMCI_BF(RSPTYP, 1);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun /* Entered into function pointer in mci_send_cmd */
190*4882a593Smuzhiyun static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	u32 status;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	do {
195*4882a593Smuzhiyun 		status = readl(&mci->sr);
196*4882a593Smuzhiyun 		if (status & (error_flags | MMCI_BIT(OVRE)))
197*4882a593Smuzhiyun 			goto io_fail;
198*4882a593Smuzhiyun 	} while (!(status & MMCI_BIT(RXRDY)));
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (status & MMCI_BIT(RXRDY)) {
201*4882a593Smuzhiyun 		*data = readl(&mci->rdr);
202*4882a593Smuzhiyun 		status = 0;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun io_fail:
205*4882a593Smuzhiyun 	return status;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun /* Entered into function pointer in mci_send_cmd */
209*4882a593Smuzhiyun static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	u32 status;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	do {
214*4882a593Smuzhiyun 		status = readl(&mci->sr);
215*4882a593Smuzhiyun 		if (status & (error_flags | MMCI_BIT(UNRE)))
216*4882a593Smuzhiyun 			goto io_fail;
217*4882a593Smuzhiyun 	} while (!(status & MMCI_BIT(TXRDY)));
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	if (status & MMCI_BIT(TXRDY)) {
220*4882a593Smuzhiyun 		writel(*data, &mci->tdr);
221*4882a593Smuzhiyun 		status = 0;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun io_fail:
224*4882a593Smuzhiyun 	return status;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun /*
228*4882a593Smuzhiyun  * Entered into mmc structure during driver init
229*4882a593Smuzhiyun  *
230*4882a593Smuzhiyun  * Sends a command out on the bus and deals with the block data.
231*4882a593Smuzhiyun  * Takes the mmc pointer, a command pointer, and an optional data pointer.
232*4882a593Smuzhiyun  */
233*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
234*4882a593Smuzhiyun static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
235*4882a593Smuzhiyun 			      struct mmc_data *data)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
238*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = dev_get_priv(dev);
239*4882a593Smuzhiyun 	struct mmc *mmc = mmc_get_mmc_dev(dev);
240*4882a593Smuzhiyun 	atmel_mci_t *mci = plat->mci;
241*4882a593Smuzhiyun #else
242*4882a593Smuzhiyun static int
243*4882a593Smuzhiyun mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = mmc->priv;
246*4882a593Smuzhiyun 	atmel_mci_t *mci = priv->mci;
247*4882a593Smuzhiyun #endif
248*4882a593Smuzhiyun 	u32 cmdr;
249*4882a593Smuzhiyun 	u32 error_flags = 0;
250*4882a593Smuzhiyun 	u32 status;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if (!priv->initialized) {
253*4882a593Smuzhiyun 		puts ("MCI not initialized!\n");
254*4882a593Smuzhiyun 		return -ECOMM;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/* Figure out the transfer arguments */
258*4882a593Smuzhiyun 	cmdr = mci_encode_cmd(cmd, data, &error_flags);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/* For multi blocks read/write, set the block register */
261*4882a593Smuzhiyun 	if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
262*4882a593Smuzhiyun 			|| (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
263*4882a593Smuzhiyun 		writel(data->blocks | MMCI_BF(BLKLEN, mmc->read_bl_len),
264*4882a593Smuzhiyun 			&mci->blkr);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	/* Send the command */
267*4882a593Smuzhiyun 	writel(cmd->cmdarg, &mci->argr);
268*4882a593Smuzhiyun 	writel(cmdr, &mci->cmdr);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun #ifdef DEBUG
271*4882a593Smuzhiyun 	dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
272*4882a593Smuzhiyun #endif
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	/* Wait for the command to complete */
275*4882a593Smuzhiyun 	while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if ((status & error_flags) & MMCI_BIT(RTOE)) {
278*4882a593Smuzhiyun 		dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
279*4882a593Smuzhiyun 		return -ETIMEDOUT;
280*4882a593Smuzhiyun 	} else if (status & error_flags) {
281*4882a593Smuzhiyun 		dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
282*4882a593Smuzhiyun 		return -ECOMM;
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* Copy the response to the response buffer */
286*4882a593Smuzhiyun 	if (cmd->resp_type & MMC_RSP_136) {
287*4882a593Smuzhiyun 		cmd->response[0] = readl(&mci->rspr);
288*4882a593Smuzhiyun 		cmd->response[1] = readl(&mci->rspr1);
289*4882a593Smuzhiyun 		cmd->response[2] = readl(&mci->rspr2);
290*4882a593Smuzhiyun 		cmd->response[3] = readl(&mci->rspr3);
291*4882a593Smuzhiyun 	} else
292*4882a593Smuzhiyun 		cmd->response[0] = readl(&mci->rspr);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* transfer all of the blocks */
295*4882a593Smuzhiyun 	if (data) {
296*4882a593Smuzhiyun 		u32 word_count, block_count;
297*4882a593Smuzhiyun 		u32* ioptr;
298*4882a593Smuzhiyun 		u32 sys_blocksize, dummy, i;
299*4882a593Smuzhiyun 		u32 (*mci_data_op)
300*4882a593Smuzhiyun 			(atmel_mci_t *mci, u32* data, u32 error_flags);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 		if (data->flags & MMC_DATA_READ) {
303*4882a593Smuzhiyun 			mci_data_op = mci_data_read;
304*4882a593Smuzhiyun 			sys_blocksize = mmc->read_bl_len;
305*4882a593Smuzhiyun 			ioptr = (u32*)data->dest;
306*4882a593Smuzhiyun 		} else {
307*4882a593Smuzhiyun 			mci_data_op = mci_data_write;
308*4882a593Smuzhiyun 			sys_blocksize = mmc->write_bl_len;
309*4882a593Smuzhiyun 			ioptr = (u32*)data->src;
310*4882a593Smuzhiyun 		}
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 		status = 0;
313*4882a593Smuzhiyun 		for (block_count = 0;
314*4882a593Smuzhiyun 				block_count < data->blocks && !status;
315*4882a593Smuzhiyun 				block_count++) {
316*4882a593Smuzhiyun 			word_count = 0;
317*4882a593Smuzhiyun 			do {
318*4882a593Smuzhiyun 				status = mci_data_op(mci, ioptr, error_flags);
319*4882a593Smuzhiyun 				word_count++;
320*4882a593Smuzhiyun 				ioptr++;
321*4882a593Smuzhiyun 			} while (!status && word_count < (data->blocksize/4));
322*4882a593Smuzhiyun #ifdef DEBUG
323*4882a593Smuzhiyun 			if (data->flags & MMC_DATA_READ)
324*4882a593Smuzhiyun 			{
325*4882a593Smuzhiyun 				u32 cnt = word_count * 4;
326*4882a593Smuzhiyun 				printf("Read Data:\n");
327*4882a593Smuzhiyun 				print_buffer(0, data->dest + cnt * block_count,
328*4882a593Smuzhiyun 					     1, cnt, 0);
329*4882a593Smuzhiyun 			}
330*4882a593Smuzhiyun #endif
331*4882a593Smuzhiyun #ifdef DEBUG
332*4882a593Smuzhiyun 			if (!status && word_count < (sys_blocksize / 4))
333*4882a593Smuzhiyun 				printf("filling rest of block...\n");
334*4882a593Smuzhiyun #endif
335*4882a593Smuzhiyun 			/* fill the rest of a full block */
336*4882a593Smuzhiyun 			while (!status && word_count < (sys_blocksize / 4)) {
337*4882a593Smuzhiyun 				status = mci_data_op(mci, &dummy,
338*4882a593Smuzhiyun 					error_flags);
339*4882a593Smuzhiyun 				word_count++;
340*4882a593Smuzhiyun 			}
341*4882a593Smuzhiyun 			if (status) {
342*4882a593Smuzhiyun 				dump_cmd(cmdr, cmd->cmdarg, status,
343*4882a593Smuzhiyun 					"Data Transfer Failed");
344*4882a593Smuzhiyun 				return -ECOMM;
345*4882a593Smuzhiyun 			}
346*4882a593Smuzhiyun 		}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 		/* Wait for Transfer End */
349*4882a593Smuzhiyun 		i = 0;
350*4882a593Smuzhiyun 		do {
351*4882a593Smuzhiyun 			status = readl(&mci->sr);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 			if (status & error_flags) {
354*4882a593Smuzhiyun 				dump_cmd(cmdr, cmd->cmdarg, status,
355*4882a593Smuzhiyun 					"DTIP Wait Failed");
356*4882a593Smuzhiyun 				return -ECOMM;
357*4882a593Smuzhiyun 			}
358*4882a593Smuzhiyun 			i++;
359*4882a593Smuzhiyun 		} while ((status & MMCI_BIT(DTIP)) && i < 10000);
360*4882a593Smuzhiyun 		if (status & MMCI_BIT(DTIP)) {
361*4882a593Smuzhiyun 			dump_cmd(cmdr, cmd->cmdarg, status,
362*4882a593Smuzhiyun 				"XFER DTIP never unset, ignoring");
363*4882a593Smuzhiyun 		}
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/*
367*4882a593Smuzhiyun 	 * After the switch command, wait for 8 clocks before the next
368*4882a593Smuzhiyun 	 * command
369*4882a593Smuzhiyun 	 */
370*4882a593Smuzhiyun 	if (cmd->cmdidx == MMC_CMD_SWITCH)
371*4882a593Smuzhiyun 		udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	return 0;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
377*4882a593Smuzhiyun static int atmel_mci_set_ios(struct udevice *dev)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
380*4882a593Smuzhiyun 	struct mmc *mmc = mmc_get_mmc_dev(dev);
381*4882a593Smuzhiyun 	atmel_mci_t *mci = plat->mci;
382*4882a593Smuzhiyun #else
383*4882a593Smuzhiyun /* Entered into mmc structure during driver init */
384*4882a593Smuzhiyun static int mci_set_ios(struct mmc *mmc)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = mmc->priv;
387*4882a593Smuzhiyun 	atmel_mci_t *mci = priv->mci;
388*4882a593Smuzhiyun #endif
389*4882a593Smuzhiyun 	int bus_width = mmc->bus_width;
390*4882a593Smuzhiyun 	unsigned int version = atmel_mci_get_version(mci);
391*4882a593Smuzhiyun 	int busw;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/* Set the clock speed */
394*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
395*4882a593Smuzhiyun 	mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
396*4882a593Smuzhiyun #else
397*4882a593Smuzhiyun 	mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
398*4882a593Smuzhiyun #endif
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	/*
401*4882a593Smuzhiyun 	 * set the bus width and select slot for this interface
402*4882a593Smuzhiyun 	 * there is no capability for multiple slots on the same interface yet
403*4882a593Smuzhiyun 	 */
404*4882a593Smuzhiyun 	if ((version & 0xf00) >= 0x300) {
405*4882a593Smuzhiyun 		switch (bus_width) {
406*4882a593Smuzhiyun 		case 8:
407*4882a593Smuzhiyun 			busw = 3;
408*4882a593Smuzhiyun 			break;
409*4882a593Smuzhiyun 		case 4:
410*4882a593Smuzhiyun 			busw = 2;
411*4882a593Smuzhiyun 			break;
412*4882a593Smuzhiyun 		default:
413*4882a593Smuzhiyun 			busw = 0;
414*4882a593Smuzhiyun 			break;
415*4882a593Smuzhiyun 		}
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 		writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
418*4882a593Smuzhiyun 	} else {
419*4882a593Smuzhiyun 		busw = (bus_width == 4) ? 1 : 0;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 		writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	return 0;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
428*4882a593Smuzhiyun static int atmel_mci_hw_init(struct udevice *dev)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
431*4882a593Smuzhiyun 	atmel_mci_t *mci = plat->mci;
432*4882a593Smuzhiyun #else
433*4882a593Smuzhiyun /* Entered into mmc structure during driver init */
434*4882a593Smuzhiyun static int mci_init(struct mmc *mmc)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = mmc->priv;
437*4882a593Smuzhiyun 	atmel_mci_t *mci = priv->mci;
438*4882a593Smuzhiyun #endif
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	/* Initialize controller */
441*4882a593Smuzhiyun 	writel(MMCI_BIT(SWRST), &mci->cr);	/* soft reset */
442*4882a593Smuzhiyun 	writel(MMCI_BIT(PWSDIS), &mci->cr);	/* disable power save */
443*4882a593Smuzhiyun 	writel(MMCI_BIT(MCIEN), &mci->cr);	/* enable mci */
444*4882a593Smuzhiyun 	writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);	/* select port */
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	/* This delay can be optimized, but stick with max value */
447*4882a593Smuzhiyun 	writel(0x7f, &mci->dtor);
448*4882a593Smuzhiyun 	/* Disable Interrupts */
449*4882a593Smuzhiyun 	writel(~0UL, &mci->idr);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	/* Set default clocks and blocklen */
452*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
453*4882a593Smuzhiyun 	mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
454*4882a593Smuzhiyun #else
455*4882a593Smuzhiyun 	mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
456*4882a593Smuzhiyun #endif
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	return 0;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun #ifndef CONFIG_DM_MMC
462*4882a593Smuzhiyun static const struct mmc_ops atmel_mci_ops = {
463*4882a593Smuzhiyun 	.send_cmd	= mci_send_cmd,
464*4882a593Smuzhiyun 	.set_ios	= mci_set_ios,
465*4882a593Smuzhiyun 	.init		= mci_init,
466*4882a593Smuzhiyun };
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun /*
469*4882a593Smuzhiyun  * This is the only exported function
470*4882a593Smuzhiyun  *
471*4882a593Smuzhiyun  * Call it with the MCI register base address
472*4882a593Smuzhiyun  */
473*4882a593Smuzhiyun int atmel_mci_init(void *regs)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct mmc *mmc;
476*4882a593Smuzhiyun 	struct mmc_config *cfg;
477*4882a593Smuzhiyun 	struct atmel_mci_priv *priv;
478*4882a593Smuzhiyun 	unsigned int version;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	priv = calloc(1, sizeof(*priv));
481*4882a593Smuzhiyun 	if (!priv)
482*4882a593Smuzhiyun 		return -ENOMEM;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	cfg = &priv->cfg;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	cfg->name = "mci";
487*4882a593Smuzhiyun 	cfg->ops = &atmel_mci_ops;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	priv->mci = (struct atmel_mci *)regs;
490*4882a593Smuzhiyun 	priv->initialized = 0;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* need to be able to pass these in on a board by board basis */
493*4882a593Smuzhiyun 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
494*4882a593Smuzhiyun 	version = atmel_mci_get_version(priv->mci);
495*4882a593Smuzhiyun 	if ((version & 0xf00) >= 0x300) {
496*4882a593Smuzhiyun 		cfg->host_caps = MMC_MODE_8BIT;
497*4882a593Smuzhiyun 		cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	cfg->host_caps |= MMC_MODE_4BIT;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	/*
503*4882a593Smuzhiyun 	 * min and max frequencies determined by
504*4882a593Smuzhiyun 	 * max and min of clock divider
505*4882a593Smuzhiyun 	 */
506*4882a593Smuzhiyun 	cfg->f_min = get_mci_clk_rate() / (2*256);
507*4882a593Smuzhiyun 	cfg->f_max = get_mci_clk_rate() / (2*1);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	mmc = mmc_create(cfg, priv);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	if (mmc == NULL) {
514*4882a593Smuzhiyun 		free(priv);
515*4882a593Smuzhiyun 		return -ENODEV;
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 	/* NOTE: possibly leaking the priv structure */
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	return 0;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun #endif
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun #ifdef CONFIG_DM_MMC
524*4882a593Smuzhiyun static const struct dm_mmc_ops atmel_mci_mmc_ops = {
525*4882a593Smuzhiyun 	.send_cmd = atmel_mci_send_cmd,
526*4882a593Smuzhiyun 	.set_ios = atmel_mci_set_ios,
527*4882a593Smuzhiyun };
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun static void atmel_mci_setup_cfg(struct udevice *dev)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
532*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = dev_get_priv(dev);
533*4882a593Smuzhiyun 	struct mmc_config *cfg;
534*4882a593Smuzhiyun 	u32 version;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	cfg = &plat->cfg;
537*4882a593Smuzhiyun 	cfg->name = "Atmel mci";
538*4882a593Smuzhiyun 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	/*
541*4882a593Smuzhiyun 	 * If the version is above 3.0, the capabilities of the 8-bit
542*4882a593Smuzhiyun 	 * bus width and high speed are supported.
543*4882a593Smuzhiyun 	 */
544*4882a593Smuzhiyun 	version = atmel_mci_get_version(plat->mci);
545*4882a593Smuzhiyun 	if ((version & 0xf00) >= 0x300) {
546*4882a593Smuzhiyun 		cfg->host_caps = MMC_MODE_8BIT |
547*4882a593Smuzhiyun 				 MMC_MODE_HS | MMC_MODE_HS_52MHz;
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	cfg->host_caps |= MMC_MODE_4BIT;
551*4882a593Smuzhiyun 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
552*4882a593Smuzhiyun 	cfg->f_min = priv->bus_clk_rate / (2 * 256);
553*4882a593Smuzhiyun 	cfg->f_max = priv->bus_clk_rate / 2;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun static int atmel_mci_enable_clk(struct udevice *dev)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	struct atmel_mci_priv *priv = dev_get_priv(dev);
559*4882a593Smuzhiyun 	struct clk clk;
560*4882a593Smuzhiyun 	ulong clk_rate;
561*4882a593Smuzhiyun 	int ret = 0;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	ret = clk_get_by_index(dev, 0, &clk);
564*4882a593Smuzhiyun 	if (ret) {
565*4882a593Smuzhiyun 		ret = -EINVAL;
566*4882a593Smuzhiyun 		goto failed;
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	ret = clk_enable(&clk);
570*4882a593Smuzhiyun 	if (ret)
571*4882a593Smuzhiyun 		goto failed;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	clk_rate = clk_get_rate(&clk);
574*4882a593Smuzhiyun 	if (!clk_rate) {
575*4882a593Smuzhiyun 		ret = -EINVAL;
576*4882a593Smuzhiyun 		goto failed;
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	priv->bus_clk_rate = clk_rate;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun failed:
582*4882a593Smuzhiyun 	clk_free(&clk);
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	return ret;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun static int atmel_mci_probe(struct udevice *dev)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
590*4882a593Smuzhiyun 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
591*4882a593Smuzhiyun 	struct mmc *mmc;
592*4882a593Smuzhiyun 	int ret;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	ret = atmel_mci_enable_clk(dev);
595*4882a593Smuzhiyun 	if (ret)
596*4882a593Smuzhiyun 		return ret;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	plat->mci = (struct atmel_mci *)devfdt_get_addr_ptr(dev);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	atmel_mci_setup_cfg(dev);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	mmc = &plat->mmc;
603*4882a593Smuzhiyun 	mmc->cfg = &plat->cfg;
604*4882a593Smuzhiyun 	mmc->dev = dev;
605*4882a593Smuzhiyun 	upriv->mmc = mmc;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	atmel_mci_hw_init(dev);
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	return 0;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun static int atmel_mci_bind(struct udevice *dev)
613*4882a593Smuzhiyun {
614*4882a593Smuzhiyun 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	return mmc_bind(dev, &plat->mmc, &plat->cfg);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun static const struct udevice_id atmel_mci_ids[] = {
620*4882a593Smuzhiyun 	{ .compatible = "atmel,hsmci" },
621*4882a593Smuzhiyun 	{ }
622*4882a593Smuzhiyun };
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun U_BOOT_DRIVER(atmel_mci) = {
625*4882a593Smuzhiyun 	.name = "atmel-mci",
626*4882a593Smuzhiyun 	.id = UCLASS_MMC,
627*4882a593Smuzhiyun 	.of_match = atmel_mci_ids,
628*4882a593Smuzhiyun 	.bind = atmel_mci_bind,
629*4882a593Smuzhiyun 	.probe = atmel_mci_probe,
630*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct atmel_mci_plat),
631*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct atmel_mci_priv),
632*4882a593Smuzhiyun 	.ops = &atmel_mci_mmc_ops,
633*4882a593Smuzhiyun };
634*4882a593Smuzhiyun #endif
635