xref: /rk3399_rockchip-uboot/drivers/mmc/gen_atmel_mci.c (revision c86c0155dcfbb02ce92c4d7245ffdf6fa904fbee)
11592ef85SReinhard Meyer /*
21592ef85SReinhard Meyer  * Copyright (C) 2010
31592ef85SReinhard Meyer  * Rob Emanuele <rob@emanuele.us>
41592ef85SReinhard Meyer  * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
51592ef85SReinhard Meyer  *
61592ef85SReinhard Meyer  * Original Driver:
71592ef85SReinhard Meyer  * Copyright (C) 2004-2006 Atmel Corporation
81592ef85SReinhard Meyer  *
91a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
101592ef85SReinhard Meyer  */
111592ef85SReinhard Meyer 
121592ef85SReinhard Meyer #include <common.h>
13*c86c0155SWenyou Yang #include <clk.h>
141592ef85SReinhard Meyer #include <mmc.h>
151592ef85SReinhard Meyer #include <part.h>
161592ef85SReinhard Meyer #include <malloc.h>
171592ef85SReinhard Meyer #include <asm/io.h>
181221ce45SMasahiro Yamada #include <linux/errno.h>
191592ef85SReinhard Meyer #include <asm/byteorder.h>
201592ef85SReinhard Meyer #include <asm/arch/clk.h>
21329f0f52SReinhard Meyer #include <asm/arch/hardware.h>
22*c86c0155SWenyou Yang #include <dm/device.h>
231592ef85SReinhard Meyer #include "atmel_mci.h"
241592ef85SReinhard Meyer 
25*c86c0155SWenyou Yang DECLARE_GLOBAL_DATA_PTR;
26*c86c0155SWenyou Yang 
271592ef85SReinhard Meyer #ifndef CONFIG_SYS_MMC_CLK_OD
281592ef85SReinhard Meyer # define CONFIG_SYS_MMC_CLK_OD	150000
291592ef85SReinhard Meyer #endif
301592ef85SReinhard Meyer 
311592ef85SReinhard Meyer #define MMC_DEFAULT_BLKLEN	512
321592ef85SReinhard Meyer 
331592ef85SReinhard Meyer #if defined(CONFIG_ATMEL_MCI_PORTB)
341592ef85SReinhard Meyer # define MCI_BUS 1
351592ef85SReinhard Meyer #else
361592ef85SReinhard Meyer # define MCI_BUS 0
371592ef85SReinhard Meyer #endif
381592ef85SReinhard Meyer 
396b75d359SMarek Vasut struct atmel_mci_priv {
406b75d359SMarek Vasut 	struct mmc_config	cfg;
416b75d359SMarek Vasut 	struct atmel_mci	*mci;
42877807e1SMarek Vasut 	unsigned int		initialized:1;
43b4670a0cSGregory CLEMENT 	unsigned int		curr_clk;
44*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
45*c86c0155SWenyou Yang 	struct mmc	mmc;
46*c86c0155SWenyou Yang 	ulong		bus_clk_rate;
47*c86c0155SWenyou Yang #endif
486b75d359SMarek Vasut };
496b75d359SMarek Vasut 
50aac4b69bSBo Shen /* Read Atmel MCI IP version */
51aac4b69bSBo Shen static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
52aac4b69bSBo Shen {
53aac4b69bSBo Shen 	return readl(&mci->version) & 0x00000fff;
54aac4b69bSBo Shen }
55aac4b69bSBo Shen 
561592ef85SReinhard Meyer /*
571592ef85SReinhard Meyer  * Print command and status:
581592ef85SReinhard Meyer  *
591592ef85SReinhard Meyer  * - always when DEBUG is defined
601592ef85SReinhard Meyer  * - on command errors
611592ef85SReinhard Meyer  */
621592ef85SReinhard Meyer static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
631592ef85SReinhard Meyer {
64b84c9c9aSMarek Vasut 	debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
651592ef85SReinhard Meyer 	      cmdr, cmdr & 0x3F, arg, status, msg);
661592ef85SReinhard Meyer }
671592ef85SReinhard Meyer 
681592ef85SReinhard Meyer /* Setup for MCI Clock and Block Size */
69*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
70*c86c0155SWenyou Yang static void mci_set_mode(struct atmel_mci_priv *priv, u32 hz, u32 blklen)
71*c86c0155SWenyou Yang {
72*c86c0155SWenyou Yang 	struct mmc *mmc = &priv->mmc;
73*c86c0155SWenyou Yang 	u32 bus_hz = priv->bus_clk_rate;
74*c86c0155SWenyou Yang #else
751592ef85SReinhard Meyer static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
761592ef85SReinhard Meyer {
776b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
781592ef85SReinhard Meyer 	u32 bus_hz = get_mci_clk_rate();
79*c86c0155SWenyou Yang #endif
80*c86c0155SWenyou Yang 
81*c86c0155SWenyou Yang 	atmel_mci_t *mci = priv->mci;
821592ef85SReinhard Meyer 	u32 clkdiv = 255;
83cd60ebd4SBo Shen 	unsigned int version = atmel_mci_get_version(mci);
84cd60ebd4SBo Shen 	u32 clkodd = 0;
85cd60ebd4SBo Shen 	u32 mr;
861592ef85SReinhard Meyer 
871592ef85SReinhard Meyer 	debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
881592ef85SReinhard Meyer 		bus_hz, hz, blklen);
891592ef85SReinhard Meyer 	if (hz > 0) {
90cd60ebd4SBo Shen 		if (version >= 0x500) {
91cd60ebd4SBo Shen 			clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
92cd60ebd4SBo Shen 			if (clkdiv > 511)
93cd60ebd4SBo Shen 				clkdiv = 511;
94cd60ebd4SBo Shen 
95cd60ebd4SBo Shen 			clkodd = clkdiv & 1;
96cd60ebd4SBo Shen 			clkdiv >>= 1;
97cd60ebd4SBo Shen 
98b84c9c9aSMarek Vasut 			debug("mci: setting clock %u Hz, block size %u\n",
99cd60ebd4SBo Shen 			      bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
100cd60ebd4SBo Shen 		} else {
101cd60ebd4SBo Shen 			/* find clkdiv yielding a rate <= than requested */
1021592ef85SReinhard Meyer 			for (clkdiv = 0; clkdiv < 255; clkdiv++) {
1031592ef85SReinhard Meyer 				if ((bus_hz / (clkdiv + 1) / 2) <= hz)
1041592ef85SReinhard Meyer 					break;
1051592ef85SReinhard Meyer 			}
106b84c9c9aSMarek Vasut 			debug("mci: setting clock %u Hz, block size %u\n",
1071592ef85SReinhard Meyer 			      (bus_hz / (clkdiv + 1)) / 2, blklen);
1081592ef85SReinhard Meyer 
109cd60ebd4SBo Shen 		}
110cd60ebd4SBo Shen 	}
111b4670a0cSGregory CLEMENT 	if (version >= 0x500)
112b4670a0cSGregory CLEMENT 		priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
113b4670a0cSGregory CLEMENT 	else
114b4670a0cSGregory CLEMENT 		priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
1151592ef85SReinhard Meyer 	blklen &= 0xfffc;
116cd60ebd4SBo Shen 
117cd60ebd4SBo Shen 	mr = MMCI_BF(CLKDIV, clkdiv);
118cd60ebd4SBo Shen 
119cd60ebd4SBo Shen 	/* MCI IP version >= 0x200 has R/WPROOF */
120cd60ebd4SBo Shen 	if (version >= 0x200)
121cd60ebd4SBo Shen 		mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
122cd60ebd4SBo Shen 
1231db7377aSWu, Josh 	/*
124cd60ebd4SBo Shen 	 * MCI IP version >= 0x500 use bit 16 as clkodd.
125cd60ebd4SBo Shen 	 * MCI IP version < 0x500 use upper 16 bits for blklen.
1261db7377aSWu, Josh 	 */
127cd60ebd4SBo Shen 	if (version >= 0x500)
128cd60ebd4SBo Shen 		mr |= MMCI_BF(CLKODD, clkodd);
129cd60ebd4SBo Shen 	else
130cd60ebd4SBo Shen 		mr |= MMCI_BF(BLKLEN, blklen);
131cd60ebd4SBo Shen 
132cd60ebd4SBo Shen 	writel(mr, &mci->mr);
133cd60ebd4SBo Shen 
134cd60ebd4SBo Shen 	/* MCI IP version >= 0x200 has blkr */
135cd60ebd4SBo Shen 	if (version >= 0x200)
1361db7377aSWu, Josh 		writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
137cd60ebd4SBo Shen 
138da55c66eSBo Shen 	if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
139da55c66eSBo Shen 		writel(MMCI_BIT(HSMODE), &mci->cfg);
140da55c66eSBo Shen 
141877807e1SMarek Vasut 	priv->initialized = 1;
1421592ef85SReinhard Meyer }
1431592ef85SReinhard Meyer 
1441592ef85SReinhard Meyer /* Return the CMDR with flags for a given command and data packet */
1451592ef85SReinhard Meyer static u32 mci_encode_cmd(
1461592ef85SReinhard Meyer 	struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
1471592ef85SReinhard Meyer {
1481592ef85SReinhard Meyer 	u32 cmdr = 0;
1491592ef85SReinhard Meyer 
1501592ef85SReinhard Meyer 	/* Default Flags for Errors */
1511592ef85SReinhard Meyer 	*error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
1521592ef85SReinhard Meyer 		MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
1531592ef85SReinhard Meyer 
1541592ef85SReinhard Meyer 	/* Default Flags for the Command */
1551592ef85SReinhard Meyer 	cmdr |= MMCI_BIT(MAXLAT);
1561592ef85SReinhard Meyer 
1571592ef85SReinhard Meyer 	if (data) {
1581592ef85SReinhard Meyer 		cmdr |= MMCI_BF(TRCMD, 1);
1591592ef85SReinhard Meyer 		if (data->blocks > 1)
1601592ef85SReinhard Meyer 			cmdr |= MMCI_BF(TRTYP, 1);
1611592ef85SReinhard Meyer 		if (data->flags & MMC_DATA_READ)
1621592ef85SReinhard Meyer 			cmdr |= MMCI_BIT(TRDIR);
1631592ef85SReinhard Meyer 	}
1641592ef85SReinhard Meyer 
1651592ef85SReinhard Meyer 	if (cmd->resp_type & MMC_RSP_CRC)
1661592ef85SReinhard Meyer 		*error_flags |= MMCI_BIT(RCRCE);
1671592ef85SReinhard Meyer 	if (cmd->resp_type & MMC_RSP_136)
1681592ef85SReinhard Meyer 		cmdr |= MMCI_BF(RSPTYP, 2);
1691592ef85SReinhard Meyer 	else if (cmd->resp_type & MMC_RSP_BUSY)
1701592ef85SReinhard Meyer 		cmdr |= MMCI_BF(RSPTYP, 3);
1711592ef85SReinhard Meyer 	else if (cmd->resp_type & MMC_RSP_PRESENT)
1721592ef85SReinhard Meyer 		cmdr |= MMCI_BF(RSPTYP, 1);
1731592ef85SReinhard Meyer 
1741592ef85SReinhard Meyer 	return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
1751592ef85SReinhard Meyer }
1761592ef85SReinhard Meyer 
1771592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */
1781592ef85SReinhard Meyer static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
1791592ef85SReinhard Meyer {
1801592ef85SReinhard Meyer 	u32 status;
1811592ef85SReinhard Meyer 
1821592ef85SReinhard Meyer 	do {
1831592ef85SReinhard Meyer 		status = readl(&mci->sr);
1841592ef85SReinhard Meyer 		if (status & (error_flags | MMCI_BIT(OVRE)))
1851592ef85SReinhard Meyer 			goto io_fail;
1861592ef85SReinhard Meyer 	} while (!(status & MMCI_BIT(RXRDY)));
1871592ef85SReinhard Meyer 
1881592ef85SReinhard Meyer 	if (status & MMCI_BIT(RXRDY)) {
1891592ef85SReinhard Meyer 		*data = readl(&mci->rdr);
1901592ef85SReinhard Meyer 		status = 0;
1911592ef85SReinhard Meyer 	}
1921592ef85SReinhard Meyer io_fail:
1931592ef85SReinhard Meyer 	return status;
1941592ef85SReinhard Meyer }
1951592ef85SReinhard Meyer 
1961592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */
1971592ef85SReinhard Meyer static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
1981592ef85SReinhard Meyer {
1991592ef85SReinhard Meyer 	u32 status;
2001592ef85SReinhard Meyer 
2011592ef85SReinhard Meyer 	do {
2021592ef85SReinhard Meyer 		status = readl(&mci->sr);
2031592ef85SReinhard Meyer 		if (status & (error_flags | MMCI_BIT(UNRE)))
2041592ef85SReinhard Meyer 			goto io_fail;
2051592ef85SReinhard Meyer 	} while (!(status & MMCI_BIT(TXRDY)));
2061592ef85SReinhard Meyer 
2071592ef85SReinhard Meyer 	if (status & MMCI_BIT(TXRDY)) {
2081592ef85SReinhard Meyer 		writel(*data, &mci->tdr);
2091592ef85SReinhard Meyer 		status = 0;
2101592ef85SReinhard Meyer 	}
2111592ef85SReinhard Meyer io_fail:
2121592ef85SReinhard Meyer 	return status;
2131592ef85SReinhard Meyer }
2141592ef85SReinhard Meyer 
2151592ef85SReinhard Meyer /*
2161592ef85SReinhard Meyer  * Entered into mmc structure during driver init
2171592ef85SReinhard Meyer  *
2181592ef85SReinhard Meyer  * Sends a command out on the bus and deals with the block data.
2191592ef85SReinhard Meyer  * Takes the mmc pointer, a command pointer, and an optional data pointer.
2201592ef85SReinhard Meyer  */
221*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
222*c86c0155SWenyou Yang static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
223*c86c0155SWenyou Yang 			      struct mmc_data *data)
224*c86c0155SWenyou Yang {
225*c86c0155SWenyou Yang 	struct atmel_mci_priv *priv = dev_get_priv(dev);
226*c86c0155SWenyou Yang 	struct mmc *mmc = mmc_get_mmc_dev(dev);
227*c86c0155SWenyou Yang #else
2281592ef85SReinhard Meyer static int
2291592ef85SReinhard Meyer mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
2301592ef85SReinhard Meyer {
2316b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
232*c86c0155SWenyou Yang #endif
2336b75d359SMarek Vasut 	atmel_mci_t *mci = priv->mci;
2341592ef85SReinhard Meyer 	u32 cmdr;
2351592ef85SReinhard Meyer 	u32 error_flags = 0;
2361592ef85SReinhard Meyer 	u32 status;
2371592ef85SReinhard Meyer 
238877807e1SMarek Vasut 	if (!priv->initialized) {
2391592ef85SReinhard Meyer 		puts ("MCI not initialized!\n");
240915ffa52SJaehoon Chung 		return -ECOMM;
2411592ef85SReinhard Meyer 	}
2421592ef85SReinhard Meyer 
2431592ef85SReinhard Meyer 	/* Figure out the transfer arguments */
2441592ef85SReinhard Meyer 	cmdr = mci_encode_cmd(cmd, data, &error_flags);
2451592ef85SReinhard Meyer 
2461db7377aSWu, Josh 	/* For multi blocks read/write, set the block register */
2471db7377aSWu, Josh 	if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
2481db7377aSWu, Josh 			|| (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
2491db7377aSWu, Josh 		writel(data->blocks | MMCI_BF(BLKLEN, mmc->read_bl_len),
2501db7377aSWu, Josh 			&mci->blkr);
2511db7377aSWu, Josh 
2521592ef85SReinhard Meyer 	/* Send the command */
2531592ef85SReinhard Meyer 	writel(cmd->cmdarg, &mci->argr);
2541592ef85SReinhard Meyer 	writel(cmdr, &mci->cmdr);
2551592ef85SReinhard Meyer 
2561592ef85SReinhard Meyer #ifdef DEBUG
2571592ef85SReinhard Meyer 	dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
2581592ef85SReinhard Meyer #endif
2591592ef85SReinhard Meyer 
2601592ef85SReinhard Meyer 	/* Wait for the command to complete */
2611592ef85SReinhard Meyer 	while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
2621592ef85SReinhard Meyer 
26393e3236cSBo Shen 	if ((status & error_flags) & MMCI_BIT(RTOE)) {
26493e3236cSBo Shen 		dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
265915ffa52SJaehoon Chung 		return -ETIMEDOUT;
26693e3236cSBo Shen 	} else if (status & error_flags) {
2671592ef85SReinhard Meyer 		dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
268915ffa52SJaehoon Chung 		return -ECOMM;
2691592ef85SReinhard Meyer 	}
2701592ef85SReinhard Meyer 
2711592ef85SReinhard Meyer 	/* Copy the response to the response buffer */
2721592ef85SReinhard Meyer 	if (cmd->resp_type & MMC_RSP_136) {
2731592ef85SReinhard Meyer 		cmd->response[0] = readl(&mci->rspr);
2741592ef85SReinhard Meyer 		cmd->response[1] = readl(&mci->rspr1);
2751592ef85SReinhard Meyer 		cmd->response[2] = readl(&mci->rspr2);
2761592ef85SReinhard Meyer 		cmd->response[3] = readl(&mci->rspr3);
2771592ef85SReinhard Meyer 	} else
2781592ef85SReinhard Meyer 		cmd->response[0] = readl(&mci->rspr);
2791592ef85SReinhard Meyer 
2801592ef85SReinhard Meyer 	/* transfer all of the blocks */
2811592ef85SReinhard Meyer 	if (data) {
2821592ef85SReinhard Meyer 		u32 word_count, block_count;
2831592ef85SReinhard Meyer 		u32* ioptr;
2841592ef85SReinhard Meyer 		u32 sys_blocksize, dummy, i;
2851592ef85SReinhard Meyer 		u32 (*mci_data_op)
2861592ef85SReinhard Meyer 			(atmel_mci_t *mci, u32* data, u32 error_flags);
2871592ef85SReinhard Meyer 
2881592ef85SReinhard Meyer 		if (data->flags & MMC_DATA_READ) {
2891592ef85SReinhard Meyer 			mci_data_op = mci_data_read;
2901592ef85SReinhard Meyer 			sys_blocksize = mmc->read_bl_len;
2911592ef85SReinhard Meyer 			ioptr = (u32*)data->dest;
2921592ef85SReinhard Meyer 		} else {
2931592ef85SReinhard Meyer 			mci_data_op = mci_data_write;
2941592ef85SReinhard Meyer 			sys_blocksize = mmc->write_bl_len;
2951592ef85SReinhard Meyer 			ioptr = (u32*)data->src;
2961592ef85SReinhard Meyer 		}
2971592ef85SReinhard Meyer 
2981592ef85SReinhard Meyer 		status = 0;
2991592ef85SReinhard Meyer 		for (block_count = 0;
3001592ef85SReinhard Meyer 				block_count < data->blocks && !status;
3011592ef85SReinhard Meyer 				block_count++) {
3021592ef85SReinhard Meyer 			word_count = 0;
3031592ef85SReinhard Meyer 			do {
3041592ef85SReinhard Meyer 				status = mci_data_op(mci, ioptr, error_flags);
3051592ef85SReinhard Meyer 				word_count++;
3061592ef85SReinhard Meyer 				ioptr++;
3071592ef85SReinhard Meyer 			} while (!status && word_count < (data->blocksize/4));
3081592ef85SReinhard Meyer #ifdef DEBUG
3091592ef85SReinhard Meyer 			if (data->flags & MMC_DATA_READ)
3101592ef85SReinhard Meyer 			{
3119902c7b6SWu, Josh 				u32 cnt = word_count * 4;
3121592ef85SReinhard Meyer 				printf("Read Data:\n");
3139902c7b6SWu, Josh 				print_buffer(0, data->dest + cnt * block_count,
3149902c7b6SWu, Josh 					     1, cnt, 0);
3151592ef85SReinhard Meyer 			}
3161592ef85SReinhard Meyer #endif
3171592ef85SReinhard Meyer #ifdef DEBUG
3181592ef85SReinhard Meyer 			if (!status && word_count < (sys_blocksize / 4))
3191592ef85SReinhard Meyer 				printf("filling rest of block...\n");
3201592ef85SReinhard Meyer #endif
3211592ef85SReinhard Meyer 			/* fill the rest of a full block */
3221592ef85SReinhard Meyer 			while (!status && word_count < (sys_blocksize / 4)) {
3231592ef85SReinhard Meyer 				status = mci_data_op(mci, &dummy,
3241592ef85SReinhard Meyer 					error_flags);
3251592ef85SReinhard Meyer 				word_count++;
3261592ef85SReinhard Meyer 			}
3271592ef85SReinhard Meyer 			if (status) {
3281592ef85SReinhard Meyer 				dump_cmd(cmdr, cmd->cmdarg, status,
3291592ef85SReinhard Meyer 					"Data Transfer Failed");
330915ffa52SJaehoon Chung 				return -ECOMM;
3311592ef85SReinhard Meyer 			}
3321592ef85SReinhard Meyer 		}
3331592ef85SReinhard Meyer 
3341592ef85SReinhard Meyer 		/* Wait for Transfer End */
3351592ef85SReinhard Meyer 		i = 0;
3361592ef85SReinhard Meyer 		do {
3371592ef85SReinhard Meyer 			status = readl(&mci->sr);
3381592ef85SReinhard Meyer 
3391592ef85SReinhard Meyer 			if (status & error_flags) {
3401592ef85SReinhard Meyer 				dump_cmd(cmdr, cmd->cmdarg, status,
3411592ef85SReinhard Meyer 					"DTIP Wait Failed");
342915ffa52SJaehoon Chung 				return -ECOMM;
3431592ef85SReinhard Meyer 			}
3441592ef85SReinhard Meyer 			i++;
3451592ef85SReinhard Meyer 		} while ((status & MMCI_BIT(DTIP)) && i < 10000);
3461592ef85SReinhard Meyer 		if (status & MMCI_BIT(DTIP)) {
3471592ef85SReinhard Meyer 			dump_cmd(cmdr, cmd->cmdarg, status,
3481592ef85SReinhard Meyer 				"XFER DTIP never unset, ignoring");
3491592ef85SReinhard Meyer 		}
3501592ef85SReinhard Meyer 	}
3511592ef85SReinhard Meyer 
352b4670a0cSGregory CLEMENT 	/*
353b4670a0cSGregory CLEMENT 	 * After the switch command, wait for 8 clocks before the next
354b4670a0cSGregory CLEMENT 	 * command
355b4670a0cSGregory CLEMENT 	 */
356b4670a0cSGregory CLEMENT 	if (cmd->cmdidx == MMC_CMD_SWITCH)
357b4670a0cSGregory CLEMENT 		udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
358b4670a0cSGregory CLEMENT 
3591592ef85SReinhard Meyer 	return 0;
3601592ef85SReinhard Meyer }
3611592ef85SReinhard Meyer 
362*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
363*c86c0155SWenyou Yang static int atmel_mci_set_ios(struct udevice *dev)
364*c86c0155SWenyou Yang {
365*c86c0155SWenyou Yang 	struct atmel_mci_priv *priv = dev_get_priv(dev);
366*c86c0155SWenyou Yang 	struct mmc *mmc = mmc_get_mmc_dev(dev);
367*c86c0155SWenyou Yang #else
3681592ef85SReinhard Meyer /* Entered into mmc structure during driver init */
36907b0b9c0SJaehoon Chung static int mci_set_ios(struct mmc *mmc)
3701592ef85SReinhard Meyer {
3716b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
372*c86c0155SWenyou Yang #endif
3736b75d359SMarek Vasut 	atmel_mci_t *mci = priv->mci;
374aac4b69bSBo Shen 	int bus_width = mmc->bus_width;
375aac4b69bSBo Shen 	unsigned int version = atmel_mci_get_version(mci);
376aac4b69bSBo Shen 	int busw;
3771592ef85SReinhard Meyer 
3781592ef85SReinhard Meyer 	/* Set the clock speed */
379*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
380*c86c0155SWenyou Yang 	mci_set_mode(priv, mmc->clock, MMC_DEFAULT_BLKLEN);
381*c86c0155SWenyou Yang #else
3821592ef85SReinhard Meyer 	mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
383*c86c0155SWenyou Yang #endif
3841592ef85SReinhard Meyer 
3851592ef85SReinhard Meyer 	/*
3861592ef85SReinhard Meyer 	 * set the bus width and select slot for this interface
3871592ef85SReinhard Meyer 	 * there is no capability for multiple slots on the same interface yet
3881592ef85SReinhard Meyer 	 */
389aac4b69bSBo Shen 	if ((version & 0xf00) >= 0x300) {
390aac4b69bSBo Shen 		switch (bus_width) {
391aac4b69bSBo Shen 		case 8:
392aac4b69bSBo Shen 			busw = 3;
393aac4b69bSBo Shen 			break;
394aac4b69bSBo Shen 		case 4:
395aac4b69bSBo Shen 			busw = 2;
396aac4b69bSBo Shen 			break;
397aac4b69bSBo Shen 		default:
398aac4b69bSBo Shen 			busw = 0;
399aac4b69bSBo Shen 			break;
400aac4b69bSBo Shen 		}
401aac4b69bSBo Shen 
402aac4b69bSBo Shen 		writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
403aac4b69bSBo Shen 	} else {
404aac4b69bSBo Shen 		busw = (bus_width == 4) ? 1 : 0;
405aac4b69bSBo Shen 
406aac4b69bSBo Shen 		writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
407aac4b69bSBo Shen 	}
40807b0b9c0SJaehoon Chung 
40907b0b9c0SJaehoon Chung 	return 0;
4101592ef85SReinhard Meyer }
4111592ef85SReinhard Meyer 
412*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
413*c86c0155SWenyou Yang static int atmel_mci_hw_init(struct atmel_mci_priv *priv)
414*c86c0155SWenyou Yang {
415*c86c0155SWenyou Yang #else
4161592ef85SReinhard Meyer /* Entered into mmc structure during driver init */
4171592ef85SReinhard Meyer static int mci_init(struct mmc *mmc)
4181592ef85SReinhard Meyer {
4196b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
420*c86c0155SWenyou Yang #endif
4216b75d359SMarek Vasut 	atmel_mci_t *mci = priv->mci;
4221592ef85SReinhard Meyer 
4231592ef85SReinhard Meyer 	/* Initialize controller */
4241592ef85SReinhard Meyer 	writel(MMCI_BIT(SWRST), &mci->cr);	/* soft reset */
4251592ef85SReinhard Meyer 	writel(MMCI_BIT(PWSDIS), &mci->cr);	/* disable power save */
4261592ef85SReinhard Meyer 	writel(MMCI_BIT(MCIEN), &mci->cr);	/* enable mci */
4272aed9d14SReinhard Meyer 	writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);	/* select port */
4281592ef85SReinhard Meyer 
4299924ca6eSWu, Josh 	/* This delay can be optimized, but stick with max value */
4309924ca6eSWu, Josh 	writel(0x7f, &mci->dtor);
4311592ef85SReinhard Meyer 	/* Disable Interrupts */
4321592ef85SReinhard Meyer 	writel(~0UL, &mci->idr);
4331592ef85SReinhard Meyer 
4341592ef85SReinhard Meyer 	/* Set default clocks and blocklen */
435*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
436*c86c0155SWenyou Yang 	mci_set_mode(priv, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
437*c86c0155SWenyou Yang #else
4381592ef85SReinhard Meyer 	mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
439*c86c0155SWenyou Yang #endif
4401592ef85SReinhard Meyer 
4411592ef85SReinhard Meyer 	return 0;
4421592ef85SReinhard Meyer }
4431592ef85SReinhard Meyer 
444*c86c0155SWenyou Yang #ifndef CONFIG_DM_MMC
445ab769f22SPantelis Antoniou static const struct mmc_ops atmel_mci_ops = {
446ab769f22SPantelis Antoniou 	.send_cmd	= mci_send_cmd,
447ab769f22SPantelis Antoniou 	.set_ios	= mci_set_ios,
448ab769f22SPantelis Antoniou 	.init		= mci_init,
449ab769f22SPantelis Antoniou };
450ab769f22SPantelis Antoniou 
4511592ef85SReinhard Meyer /*
4521592ef85SReinhard Meyer  * This is the only exported function
4531592ef85SReinhard Meyer  *
4541592ef85SReinhard Meyer  * Call it with the MCI register base address
4551592ef85SReinhard Meyer  */
4561592ef85SReinhard Meyer int atmel_mci_init(void *regs)
4571592ef85SReinhard Meyer {
45893bfd616SPantelis Antoniou 	struct mmc *mmc;
45993bfd616SPantelis Antoniou 	struct mmc_config *cfg;
4606b75d359SMarek Vasut 	struct atmel_mci_priv *priv;
461aac4b69bSBo Shen 	unsigned int version;
4621592ef85SReinhard Meyer 
4636b75d359SMarek Vasut 	priv = calloc(1, sizeof(*priv));
4646b75d359SMarek Vasut 	if (!priv)
4656b75d359SMarek Vasut 		return -ENOMEM;
466aac4b69bSBo Shen 
4676b75d359SMarek Vasut 	cfg = &priv->cfg;
46893bfd616SPantelis Antoniou 
46993bfd616SPantelis Antoniou 	cfg->name = "mci";
47093bfd616SPantelis Antoniou 	cfg->ops = &atmel_mci_ops;
4711592ef85SReinhard Meyer 
4726b75d359SMarek Vasut 	priv->mci = (struct atmel_mci *)regs;
473877807e1SMarek Vasut 	priv->initialized = 0;
4746b75d359SMarek Vasut 
4751592ef85SReinhard Meyer 	/* need to be able to pass these in on a board by board basis */
47693bfd616SPantelis Antoniou 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
4776b75d359SMarek Vasut 	version = atmel_mci_get_version(priv->mci);
478da55c66eSBo Shen 	if ((version & 0xf00) >= 0x300) {
47993bfd616SPantelis Antoniou 		cfg->host_caps = MMC_MODE_8BIT;
480da55c66eSBo Shen 		cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
481da55c66eSBo Shen 	}
482aac4b69bSBo Shen 
48393bfd616SPantelis Antoniou 	cfg->host_caps |= MMC_MODE_4BIT;
484aac4b69bSBo Shen 
4851592ef85SReinhard Meyer 	/*
4861592ef85SReinhard Meyer 	 * min and max frequencies determined by
4871592ef85SReinhard Meyer 	 * max and min of clock divider
4881592ef85SReinhard Meyer 	 */
48993bfd616SPantelis Antoniou 	cfg->f_min = get_mci_clk_rate() / (2*256);
49093bfd616SPantelis Antoniou 	cfg->f_max = get_mci_clk_rate() / (2*1);
4911592ef85SReinhard Meyer 
49293bfd616SPantelis Antoniou 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
4938feafcc4SJohn Rigby 
4946b75d359SMarek Vasut 	mmc = mmc_create(cfg, priv);
49593bfd616SPantelis Antoniou 
49693bfd616SPantelis Antoniou 	if (mmc == NULL) {
4976b75d359SMarek Vasut 		free(priv);
4986b75d359SMarek Vasut 		return -ENODEV;
49993bfd616SPantelis Antoniou 	}
5006b75d359SMarek Vasut 	/* NOTE: possibly leaking the priv structure */
5011592ef85SReinhard Meyer 
5021592ef85SReinhard Meyer 	return 0;
5031592ef85SReinhard Meyer }
504*c86c0155SWenyou Yang #endif
505*c86c0155SWenyou Yang 
506*c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
507*c86c0155SWenyou Yang static const struct dm_mmc_ops atmel_mci_mmc_ops = {
508*c86c0155SWenyou Yang 	.send_cmd = atmel_mci_send_cmd,
509*c86c0155SWenyou Yang 	.set_ios = atmel_mci_set_ios,
510*c86c0155SWenyou Yang };
511*c86c0155SWenyou Yang 
512*c86c0155SWenyou Yang static void atmel_mci_setup_cfg(struct atmel_mci_priv *priv)
513*c86c0155SWenyou Yang {
514*c86c0155SWenyou Yang 	struct mmc_config *cfg;
515*c86c0155SWenyou Yang 	u32 version;
516*c86c0155SWenyou Yang 
517*c86c0155SWenyou Yang 	cfg = &priv->cfg;
518*c86c0155SWenyou Yang 	cfg->name = "Atmel mci";
519*c86c0155SWenyou Yang 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
520*c86c0155SWenyou Yang 
521*c86c0155SWenyou Yang 	/*
522*c86c0155SWenyou Yang 	 * If the version is above 3.0, the capabilities of the 8-bit
523*c86c0155SWenyou Yang 	 * bus width and high speed are supported.
524*c86c0155SWenyou Yang 	 */
525*c86c0155SWenyou Yang 	version = atmel_mci_get_version(priv->mci);
526*c86c0155SWenyou Yang 	if ((version & 0xf00) >= 0x300) {
527*c86c0155SWenyou Yang 		cfg->host_caps = MMC_MODE_8BIT |
528*c86c0155SWenyou Yang 				 MMC_MODE_HS | MMC_MODE_HS_52MHz;
529*c86c0155SWenyou Yang 	}
530*c86c0155SWenyou Yang 
531*c86c0155SWenyou Yang 	cfg->host_caps |= MMC_MODE_4BIT;
532*c86c0155SWenyou Yang 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
533*c86c0155SWenyou Yang 	cfg->f_min = priv->bus_clk_rate / (2 * 256);
534*c86c0155SWenyou Yang 	cfg->f_max = priv->bus_clk_rate / 2;
535*c86c0155SWenyou Yang }
536*c86c0155SWenyou Yang 
537*c86c0155SWenyou Yang static int atmel_mci_enable_clk(struct udevice *dev)
538*c86c0155SWenyou Yang {
539*c86c0155SWenyou Yang 	struct atmel_mci_priv *priv = dev_get_priv(dev);
540*c86c0155SWenyou Yang 	struct clk clk;
541*c86c0155SWenyou Yang 	ulong clk_rate;
542*c86c0155SWenyou Yang 	int ret = 0;
543*c86c0155SWenyou Yang 
544*c86c0155SWenyou Yang 	ret = clk_get_by_index(dev, 0, &clk);
545*c86c0155SWenyou Yang 	if (ret) {
546*c86c0155SWenyou Yang 		ret = -EINVAL;
547*c86c0155SWenyou Yang 		goto failed;
548*c86c0155SWenyou Yang 	}
549*c86c0155SWenyou Yang 
550*c86c0155SWenyou Yang 	ret = clk_enable(&clk);
551*c86c0155SWenyou Yang 	if (ret)
552*c86c0155SWenyou Yang 		goto failed;
553*c86c0155SWenyou Yang 
554*c86c0155SWenyou Yang 	clk_rate = clk_get_rate(&clk);
555*c86c0155SWenyou Yang 	if (!clk_rate) {
556*c86c0155SWenyou Yang 		ret = -EINVAL;
557*c86c0155SWenyou Yang 		goto failed;
558*c86c0155SWenyou Yang 	}
559*c86c0155SWenyou Yang 
560*c86c0155SWenyou Yang 	priv->bus_clk_rate = clk_rate;
561*c86c0155SWenyou Yang 
562*c86c0155SWenyou Yang failed:
563*c86c0155SWenyou Yang 	clk_free(&clk);
564*c86c0155SWenyou Yang 
565*c86c0155SWenyou Yang 	return ret;
566*c86c0155SWenyou Yang }
567*c86c0155SWenyou Yang 
568*c86c0155SWenyou Yang static int atmel_mci_probe(struct udevice *dev)
569*c86c0155SWenyou Yang {
570*c86c0155SWenyou Yang 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
571*c86c0155SWenyou Yang 	struct atmel_mci_priv *priv = dev_get_priv(dev);
572*c86c0155SWenyou Yang 	struct mmc *mmc;
573*c86c0155SWenyou Yang 	int ret;
574*c86c0155SWenyou Yang 
575*c86c0155SWenyou Yang 	ret = atmel_mci_enable_clk(dev);
576*c86c0155SWenyou Yang 	if (ret)
577*c86c0155SWenyou Yang 		return ret;
578*c86c0155SWenyou Yang 
579*c86c0155SWenyou Yang 	priv->mci = (struct atmel_mci *)dev_get_addr_ptr(dev);
580*c86c0155SWenyou Yang 
581*c86c0155SWenyou Yang 	atmel_mci_setup_cfg(priv);
582*c86c0155SWenyou Yang 
583*c86c0155SWenyou Yang 	mmc = &priv->mmc;
584*c86c0155SWenyou Yang 	mmc->cfg = &priv->cfg;
585*c86c0155SWenyou Yang 	mmc->dev = dev;
586*c86c0155SWenyou Yang 	upriv->mmc = mmc;
587*c86c0155SWenyou Yang 
588*c86c0155SWenyou Yang 	atmel_mci_hw_init(priv);
589*c86c0155SWenyou Yang 
590*c86c0155SWenyou Yang 	return 0;
591*c86c0155SWenyou Yang }
592*c86c0155SWenyou Yang 
593*c86c0155SWenyou Yang static int atmel_mci_bind(struct udevice *dev)
594*c86c0155SWenyou Yang {
595*c86c0155SWenyou Yang 	struct atmel_mci_priv *priv = dev_get_priv(dev);
596*c86c0155SWenyou Yang 
597*c86c0155SWenyou Yang 	return mmc_bind(dev, &priv->mmc, &priv->cfg);
598*c86c0155SWenyou Yang }
599*c86c0155SWenyou Yang 
600*c86c0155SWenyou Yang static const struct udevice_id atmel_mci_ids[] = {
601*c86c0155SWenyou Yang 	{ .compatible = "atmel,hsmci" },
602*c86c0155SWenyou Yang 	{ }
603*c86c0155SWenyou Yang };
604*c86c0155SWenyou Yang 
605*c86c0155SWenyou Yang U_BOOT_DRIVER(atmel_mci) = {
606*c86c0155SWenyou Yang 	.name = "atmel-mci",
607*c86c0155SWenyou Yang 	.id = UCLASS_MMC,
608*c86c0155SWenyou Yang 	.of_match = atmel_mci_ids,
609*c86c0155SWenyou Yang 	.bind = atmel_mci_bind,
610*c86c0155SWenyou Yang 	.probe = atmel_mci_probe,
611*c86c0155SWenyou Yang 	.priv_auto_alloc_size = sizeof(struct atmel_mci_priv),
612*c86c0155SWenyou Yang 	.ops = &atmel_mci_mmc_ops,
613*c86c0155SWenyou Yang };
614*c86c0155SWenyou Yang #endif
615