xref: /rk3399_rockchip-uboot/drivers/mmc/gen_atmel_mci.c (revision 1fdafb2e3dfecdc4129a8062ad25b1adb32b0efb)
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>
13c86c0155SWenyou Yang #include <clk.h>
149d922450SSimon Glass #include <dm.h>
151592ef85SReinhard Meyer #include <mmc.h>
161592ef85SReinhard Meyer #include <part.h>
171592ef85SReinhard Meyer #include <malloc.h>
181592ef85SReinhard Meyer #include <asm/io.h>
191221ce45SMasahiro Yamada #include <linux/errno.h>
201592ef85SReinhard Meyer #include <asm/byteorder.h>
211592ef85SReinhard Meyer #include <asm/arch/clk.h>
22329f0f52SReinhard Meyer #include <asm/arch/hardware.h>
231592ef85SReinhard Meyer #include "atmel_mci.h"
241592ef85SReinhard Meyer 
25c86c0155SWenyou Yang DECLARE_GLOBAL_DATA_PTR;
26c86c0155SWenyou 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 
39*722b150eSWenyou.Yang@microchip.com #ifdef CONFIG_DM_MMC
40*722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat {
41*722b150eSWenyou.Yang@microchip.com 	struct mmc		mmc;
426b75d359SMarek Vasut 	struct mmc_config	cfg;
436b75d359SMarek Vasut 	struct atmel_mci	*mci;
44*722b150eSWenyou.Yang@microchip.com };
45*722b150eSWenyou.Yang@microchip.com #endif
46*722b150eSWenyou.Yang@microchip.com 
47*722b150eSWenyou.Yang@microchip.com struct atmel_mci_priv {
48*722b150eSWenyou.Yang@microchip.com #ifndef CONFIG_DM_MMC
49*722b150eSWenyou.Yang@microchip.com 	struct mmc_config	cfg;
50*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci	*mci;
51*722b150eSWenyou.Yang@microchip.com #endif
52877807e1SMarek Vasut 	unsigned int		initialized:1;
53b4670a0cSGregory CLEMENT 	unsigned int		curr_clk;
54c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
55c86c0155SWenyou Yang 	ulong		bus_clk_rate;
56c86c0155SWenyou Yang #endif
576b75d359SMarek Vasut };
586b75d359SMarek Vasut 
59aac4b69bSBo Shen /* Read Atmel MCI IP version */
atmel_mci_get_version(struct atmel_mci * mci)60aac4b69bSBo Shen static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
61aac4b69bSBo Shen {
62aac4b69bSBo Shen 	return readl(&mci->version) & 0x00000fff;
63aac4b69bSBo Shen }
64aac4b69bSBo Shen 
651592ef85SReinhard Meyer /*
661592ef85SReinhard Meyer  * Print command and status:
671592ef85SReinhard Meyer  *
681592ef85SReinhard Meyer  * - always when DEBUG is defined
691592ef85SReinhard Meyer  * - on command errors
701592ef85SReinhard Meyer  */
dump_cmd(u32 cmdr,u32 arg,u32 status,const char * msg)711592ef85SReinhard Meyer static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
721592ef85SReinhard Meyer {
73b84c9c9aSMarek Vasut 	debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
741592ef85SReinhard Meyer 	      cmdr, cmdr & 0x3F, arg, status, msg);
751592ef85SReinhard Meyer }
761592ef85SReinhard Meyer 
771592ef85SReinhard Meyer /* Setup for MCI Clock and Block Size */
78c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
mci_set_mode(struct udevice * dev,u32 hz,u32 blklen)79*722b150eSWenyou.Yang@microchip.com static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
80c86c0155SWenyou Yang {
81*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
82*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_priv *priv = dev_get_priv(dev);
83*722b150eSWenyou.Yang@microchip.com 	struct mmc *mmc = &plat->mmc;
84c86c0155SWenyou Yang 	u32 bus_hz = priv->bus_clk_rate;
85*722b150eSWenyou.Yang@microchip.com 	atmel_mci_t *mci = plat->mci;
86c86c0155SWenyou Yang #else
871592ef85SReinhard Meyer static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
881592ef85SReinhard Meyer {
896b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
901592ef85SReinhard Meyer 	u32 bus_hz = get_mci_clk_rate();
91*722b150eSWenyou.Yang@microchip.com 	atmel_mci_t *mci = priv->mci;
92c86c0155SWenyou Yang #endif
93c86c0155SWenyou Yang 
941592ef85SReinhard Meyer 	u32 clkdiv = 255;
95cd60ebd4SBo Shen 	unsigned int version = atmel_mci_get_version(mci);
96cd60ebd4SBo Shen 	u32 clkodd = 0;
97cd60ebd4SBo Shen 	u32 mr;
981592ef85SReinhard Meyer 
991592ef85SReinhard Meyer 	debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
1001592ef85SReinhard Meyer 		bus_hz, hz, blklen);
1011592ef85SReinhard Meyer 	if (hz > 0) {
102cd60ebd4SBo Shen 		if (version >= 0x500) {
103cd60ebd4SBo Shen 			clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
104cd60ebd4SBo Shen 			if (clkdiv > 511)
105cd60ebd4SBo Shen 				clkdiv = 511;
106cd60ebd4SBo Shen 
107cd60ebd4SBo Shen 			clkodd = clkdiv & 1;
108cd60ebd4SBo Shen 			clkdiv >>= 1;
109cd60ebd4SBo Shen 
110b84c9c9aSMarek Vasut 			debug("mci: setting clock %u Hz, block size %u\n",
111cd60ebd4SBo Shen 			      bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
112cd60ebd4SBo Shen 		} else {
113cd60ebd4SBo Shen 			/* find clkdiv yielding a rate <= than requested */
1141592ef85SReinhard Meyer 			for (clkdiv = 0; clkdiv < 255; clkdiv++) {
1151592ef85SReinhard Meyer 				if ((bus_hz / (clkdiv + 1) / 2) <= hz)
1161592ef85SReinhard Meyer 					break;
1171592ef85SReinhard Meyer 			}
118b84c9c9aSMarek Vasut 			debug("mci: setting clock %u Hz, block size %u\n",
1191592ef85SReinhard Meyer 			      (bus_hz / (clkdiv + 1)) / 2, blklen);
1201592ef85SReinhard Meyer 
121cd60ebd4SBo Shen 		}
122cd60ebd4SBo Shen 	}
123b4670a0cSGregory CLEMENT 	if (version >= 0x500)
124b4670a0cSGregory CLEMENT 		priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
125b4670a0cSGregory CLEMENT 	else
126b4670a0cSGregory CLEMENT 		priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
1271592ef85SReinhard Meyer 	blklen &= 0xfffc;
128cd60ebd4SBo Shen 
129cd60ebd4SBo Shen 	mr = MMCI_BF(CLKDIV, clkdiv);
130cd60ebd4SBo Shen 
131cd60ebd4SBo Shen 	/* MCI IP version >= 0x200 has R/WPROOF */
132cd60ebd4SBo Shen 	if (version >= 0x200)
133cd60ebd4SBo Shen 		mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
134cd60ebd4SBo Shen 
1351db7377aSWu, Josh 	/*
136cd60ebd4SBo Shen 	 * MCI IP version >= 0x500 use bit 16 as clkodd.
137cd60ebd4SBo Shen 	 * MCI IP version < 0x500 use upper 16 bits for blklen.
1381db7377aSWu, Josh 	 */
139cd60ebd4SBo Shen 	if (version >= 0x500)
140cd60ebd4SBo Shen 		mr |= MMCI_BF(CLKODD, clkodd);
141cd60ebd4SBo Shen 	else
142cd60ebd4SBo Shen 		mr |= MMCI_BF(BLKLEN, blklen);
143cd60ebd4SBo Shen 
144cd60ebd4SBo Shen 	writel(mr, &mci->mr);
145cd60ebd4SBo Shen 
146cd60ebd4SBo Shen 	/* MCI IP version >= 0x200 has blkr */
147cd60ebd4SBo Shen 	if (version >= 0x200)
1481db7377aSWu, Josh 		writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
149cd60ebd4SBo Shen 
150da55c66eSBo Shen 	if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
151da55c66eSBo Shen 		writel(MMCI_BIT(HSMODE), &mci->cfg);
152da55c66eSBo Shen 
153877807e1SMarek Vasut 	priv->initialized = 1;
1541592ef85SReinhard Meyer }
1551592ef85SReinhard Meyer 
1561592ef85SReinhard Meyer /* Return the CMDR with flags for a given command and data packet */
1571592ef85SReinhard Meyer static u32 mci_encode_cmd(
1581592ef85SReinhard Meyer 	struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
1591592ef85SReinhard Meyer {
1601592ef85SReinhard Meyer 	u32 cmdr = 0;
1611592ef85SReinhard Meyer 
1621592ef85SReinhard Meyer 	/* Default Flags for Errors */
1631592ef85SReinhard Meyer 	*error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
1641592ef85SReinhard Meyer 		MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
1651592ef85SReinhard Meyer 
1661592ef85SReinhard Meyer 	/* Default Flags for the Command */
1671592ef85SReinhard Meyer 	cmdr |= MMCI_BIT(MAXLAT);
1681592ef85SReinhard Meyer 
1691592ef85SReinhard Meyer 	if (data) {
1701592ef85SReinhard Meyer 		cmdr |= MMCI_BF(TRCMD, 1);
1711592ef85SReinhard Meyer 		if (data->blocks > 1)
1721592ef85SReinhard Meyer 			cmdr |= MMCI_BF(TRTYP, 1);
1731592ef85SReinhard Meyer 		if (data->flags & MMC_DATA_READ)
1741592ef85SReinhard Meyer 			cmdr |= MMCI_BIT(TRDIR);
1751592ef85SReinhard Meyer 	}
1761592ef85SReinhard Meyer 
1771592ef85SReinhard Meyer 	if (cmd->resp_type & MMC_RSP_CRC)
1781592ef85SReinhard Meyer 		*error_flags |= MMCI_BIT(RCRCE);
1791592ef85SReinhard Meyer 	if (cmd->resp_type & MMC_RSP_136)
1801592ef85SReinhard Meyer 		cmdr |= MMCI_BF(RSPTYP, 2);
1811592ef85SReinhard Meyer 	else if (cmd->resp_type & MMC_RSP_BUSY)
1821592ef85SReinhard Meyer 		cmdr |= MMCI_BF(RSPTYP, 3);
1831592ef85SReinhard Meyer 	else if (cmd->resp_type & MMC_RSP_PRESENT)
1841592ef85SReinhard Meyer 		cmdr |= MMCI_BF(RSPTYP, 1);
1851592ef85SReinhard Meyer 
1861592ef85SReinhard Meyer 	return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
1871592ef85SReinhard Meyer }
1881592ef85SReinhard Meyer 
1891592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */
1901592ef85SReinhard Meyer static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
1911592ef85SReinhard Meyer {
1921592ef85SReinhard Meyer 	u32 status;
1931592ef85SReinhard Meyer 
1941592ef85SReinhard Meyer 	do {
1951592ef85SReinhard Meyer 		status = readl(&mci->sr);
1961592ef85SReinhard Meyer 		if (status & (error_flags | MMCI_BIT(OVRE)))
1971592ef85SReinhard Meyer 			goto io_fail;
1981592ef85SReinhard Meyer 	} while (!(status & MMCI_BIT(RXRDY)));
1991592ef85SReinhard Meyer 
2001592ef85SReinhard Meyer 	if (status & MMCI_BIT(RXRDY)) {
2011592ef85SReinhard Meyer 		*data = readl(&mci->rdr);
2021592ef85SReinhard Meyer 		status = 0;
2031592ef85SReinhard Meyer 	}
2041592ef85SReinhard Meyer io_fail:
2051592ef85SReinhard Meyer 	return status;
2061592ef85SReinhard Meyer }
2071592ef85SReinhard Meyer 
2081592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */
2091592ef85SReinhard Meyer static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
2101592ef85SReinhard Meyer {
2111592ef85SReinhard Meyer 	u32 status;
2121592ef85SReinhard Meyer 
2131592ef85SReinhard Meyer 	do {
2141592ef85SReinhard Meyer 		status = readl(&mci->sr);
2151592ef85SReinhard Meyer 		if (status & (error_flags | MMCI_BIT(UNRE)))
2161592ef85SReinhard Meyer 			goto io_fail;
2171592ef85SReinhard Meyer 	} while (!(status & MMCI_BIT(TXRDY)));
2181592ef85SReinhard Meyer 
2191592ef85SReinhard Meyer 	if (status & MMCI_BIT(TXRDY)) {
2201592ef85SReinhard Meyer 		writel(*data, &mci->tdr);
2211592ef85SReinhard Meyer 		status = 0;
2221592ef85SReinhard Meyer 	}
2231592ef85SReinhard Meyer io_fail:
2241592ef85SReinhard Meyer 	return status;
2251592ef85SReinhard Meyer }
2261592ef85SReinhard Meyer 
2271592ef85SReinhard Meyer /*
2281592ef85SReinhard Meyer  * Entered into mmc structure during driver init
2291592ef85SReinhard Meyer  *
2301592ef85SReinhard Meyer  * Sends a command out on the bus and deals with the block data.
2311592ef85SReinhard Meyer  * Takes the mmc pointer, a command pointer, and an optional data pointer.
2321592ef85SReinhard Meyer  */
233c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
234c86c0155SWenyou Yang static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
235c86c0155SWenyou Yang 			      struct mmc_data *data)
236c86c0155SWenyou Yang {
237*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
238c86c0155SWenyou Yang 	struct atmel_mci_priv *priv = dev_get_priv(dev);
239c86c0155SWenyou Yang 	struct mmc *mmc = mmc_get_mmc_dev(dev);
240*722b150eSWenyou.Yang@microchip.com 	atmel_mci_t *mci = plat->mci;
241c86c0155SWenyou Yang #else
2421592ef85SReinhard Meyer static int
2431592ef85SReinhard Meyer mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
2441592ef85SReinhard Meyer {
2456b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
2466b75d359SMarek Vasut 	atmel_mci_t *mci = priv->mci;
247*722b150eSWenyou.Yang@microchip.com #endif
2481592ef85SReinhard Meyer 	u32 cmdr;
2491592ef85SReinhard Meyer 	u32 error_flags = 0;
2501592ef85SReinhard Meyer 	u32 status;
2511592ef85SReinhard Meyer 
252877807e1SMarek Vasut 	if (!priv->initialized) {
2531592ef85SReinhard Meyer 		puts ("MCI not initialized!\n");
254915ffa52SJaehoon Chung 		return -ECOMM;
2551592ef85SReinhard Meyer 	}
2561592ef85SReinhard Meyer 
2571592ef85SReinhard Meyer 	/* Figure out the transfer arguments */
2581592ef85SReinhard Meyer 	cmdr = mci_encode_cmd(cmd, data, &error_flags);
2591592ef85SReinhard Meyer 
2601db7377aSWu, Josh 	/* For multi blocks read/write, set the block register */
2611db7377aSWu, Josh 	if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
2621db7377aSWu, Josh 			|| (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
2631db7377aSWu, Josh 		writel(data->blocks | MMCI_BF(BLKLEN, mmc->read_bl_len),
2641db7377aSWu, Josh 			&mci->blkr);
2651db7377aSWu, Josh 
2661592ef85SReinhard Meyer 	/* Send the command */
2671592ef85SReinhard Meyer 	writel(cmd->cmdarg, &mci->argr);
2681592ef85SReinhard Meyer 	writel(cmdr, &mci->cmdr);
2691592ef85SReinhard Meyer 
2701592ef85SReinhard Meyer #ifdef DEBUG
2711592ef85SReinhard Meyer 	dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
2721592ef85SReinhard Meyer #endif
2731592ef85SReinhard Meyer 
2741592ef85SReinhard Meyer 	/* Wait for the command to complete */
2751592ef85SReinhard Meyer 	while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
2761592ef85SReinhard Meyer 
27793e3236cSBo Shen 	if ((status & error_flags) & MMCI_BIT(RTOE)) {
27893e3236cSBo Shen 		dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
279915ffa52SJaehoon Chung 		return -ETIMEDOUT;
28093e3236cSBo Shen 	} else if (status & error_flags) {
2811592ef85SReinhard Meyer 		dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
282915ffa52SJaehoon Chung 		return -ECOMM;
2831592ef85SReinhard Meyer 	}
2841592ef85SReinhard Meyer 
2851592ef85SReinhard Meyer 	/* Copy the response to the response buffer */
2861592ef85SReinhard Meyer 	if (cmd->resp_type & MMC_RSP_136) {
2871592ef85SReinhard Meyer 		cmd->response[0] = readl(&mci->rspr);
2881592ef85SReinhard Meyer 		cmd->response[1] = readl(&mci->rspr1);
2891592ef85SReinhard Meyer 		cmd->response[2] = readl(&mci->rspr2);
2901592ef85SReinhard Meyer 		cmd->response[3] = readl(&mci->rspr3);
2911592ef85SReinhard Meyer 	} else
2921592ef85SReinhard Meyer 		cmd->response[0] = readl(&mci->rspr);
2931592ef85SReinhard Meyer 
2941592ef85SReinhard Meyer 	/* transfer all of the blocks */
2951592ef85SReinhard Meyer 	if (data) {
2961592ef85SReinhard Meyer 		u32 word_count, block_count;
2971592ef85SReinhard Meyer 		u32* ioptr;
2981592ef85SReinhard Meyer 		u32 sys_blocksize, dummy, i;
2991592ef85SReinhard Meyer 		u32 (*mci_data_op)
3001592ef85SReinhard Meyer 			(atmel_mci_t *mci, u32* data, u32 error_flags);
3011592ef85SReinhard Meyer 
3021592ef85SReinhard Meyer 		if (data->flags & MMC_DATA_READ) {
3031592ef85SReinhard Meyer 			mci_data_op = mci_data_read;
3041592ef85SReinhard Meyer 			sys_blocksize = mmc->read_bl_len;
3051592ef85SReinhard Meyer 			ioptr = (u32*)data->dest;
3061592ef85SReinhard Meyer 		} else {
3071592ef85SReinhard Meyer 			mci_data_op = mci_data_write;
3081592ef85SReinhard Meyer 			sys_blocksize = mmc->write_bl_len;
3091592ef85SReinhard Meyer 			ioptr = (u32*)data->src;
3101592ef85SReinhard Meyer 		}
3111592ef85SReinhard Meyer 
3121592ef85SReinhard Meyer 		status = 0;
3131592ef85SReinhard Meyer 		for (block_count = 0;
3141592ef85SReinhard Meyer 				block_count < data->blocks && !status;
3151592ef85SReinhard Meyer 				block_count++) {
3161592ef85SReinhard Meyer 			word_count = 0;
3171592ef85SReinhard Meyer 			do {
3181592ef85SReinhard Meyer 				status = mci_data_op(mci, ioptr, error_flags);
3191592ef85SReinhard Meyer 				word_count++;
3201592ef85SReinhard Meyer 				ioptr++;
3211592ef85SReinhard Meyer 			} while (!status && word_count < (data->blocksize/4));
3221592ef85SReinhard Meyer #ifdef DEBUG
3231592ef85SReinhard Meyer 			if (data->flags & MMC_DATA_READ)
3241592ef85SReinhard Meyer 			{
3259902c7b6SWu, Josh 				u32 cnt = word_count * 4;
3261592ef85SReinhard Meyer 				printf("Read Data:\n");
3279902c7b6SWu, Josh 				print_buffer(0, data->dest + cnt * block_count,
3289902c7b6SWu, Josh 					     1, cnt, 0);
3291592ef85SReinhard Meyer 			}
3301592ef85SReinhard Meyer #endif
3311592ef85SReinhard Meyer #ifdef DEBUG
3321592ef85SReinhard Meyer 			if (!status && word_count < (sys_blocksize / 4))
3331592ef85SReinhard Meyer 				printf("filling rest of block...\n");
3341592ef85SReinhard Meyer #endif
3351592ef85SReinhard Meyer 			/* fill the rest of a full block */
3361592ef85SReinhard Meyer 			while (!status && word_count < (sys_blocksize / 4)) {
3371592ef85SReinhard Meyer 				status = mci_data_op(mci, &dummy,
3381592ef85SReinhard Meyer 					error_flags);
3391592ef85SReinhard Meyer 				word_count++;
3401592ef85SReinhard Meyer 			}
3411592ef85SReinhard Meyer 			if (status) {
3421592ef85SReinhard Meyer 				dump_cmd(cmdr, cmd->cmdarg, status,
3431592ef85SReinhard Meyer 					"Data Transfer Failed");
344915ffa52SJaehoon Chung 				return -ECOMM;
3451592ef85SReinhard Meyer 			}
3461592ef85SReinhard Meyer 		}
3471592ef85SReinhard Meyer 
3481592ef85SReinhard Meyer 		/* Wait for Transfer End */
3491592ef85SReinhard Meyer 		i = 0;
3501592ef85SReinhard Meyer 		do {
3511592ef85SReinhard Meyer 			status = readl(&mci->sr);
3521592ef85SReinhard Meyer 
3531592ef85SReinhard Meyer 			if (status & error_flags) {
3541592ef85SReinhard Meyer 				dump_cmd(cmdr, cmd->cmdarg, status,
3551592ef85SReinhard Meyer 					"DTIP Wait Failed");
356915ffa52SJaehoon Chung 				return -ECOMM;
3571592ef85SReinhard Meyer 			}
3581592ef85SReinhard Meyer 			i++;
3591592ef85SReinhard Meyer 		} while ((status & MMCI_BIT(DTIP)) && i < 10000);
3601592ef85SReinhard Meyer 		if (status & MMCI_BIT(DTIP)) {
3611592ef85SReinhard Meyer 			dump_cmd(cmdr, cmd->cmdarg, status,
3621592ef85SReinhard Meyer 				"XFER DTIP never unset, ignoring");
3631592ef85SReinhard Meyer 		}
3641592ef85SReinhard Meyer 	}
3651592ef85SReinhard Meyer 
366b4670a0cSGregory CLEMENT 	/*
367b4670a0cSGregory CLEMENT 	 * After the switch command, wait for 8 clocks before the next
368b4670a0cSGregory CLEMENT 	 * command
369b4670a0cSGregory CLEMENT 	 */
370b4670a0cSGregory CLEMENT 	if (cmd->cmdidx == MMC_CMD_SWITCH)
371b4670a0cSGregory CLEMENT 		udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
372b4670a0cSGregory CLEMENT 
3731592ef85SReinhard Meyer 	return 0;
3741592ef85SReinhard Meyer }
3751592ef85SReinhard Meyer 
376c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
377c86c0155SWenyou Yang static int atmel_mci_set_ios(struct udevice *dev)
378c86c0155SWenyou Yang {
379*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
380c86c0155SWenyou Yang 	struct mmc *mmc = mmc_get_mmc_dev(dev);
381*722b150eSWenyou.Yang@microchip.com 	atmel_mci_t *mci = plat->mci;
382c86c0155SWenyou Yang #else
3831592ef85SReinhard Meyer /* Entered into mmc structure during driver init */
38407b0b9c0SJaehoon Chung static int mci_set_ios(struct mmc *mmc)
3851592ef85SReinhard Meyer {
3866b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
3876b75d359SMarek Vasut 	atmel_mci_t *mci = priv->mci;
388*722b150eSWenyou.Yang@microchip.com #endif
389aac4b69bSBo Shen 	int bus_width = mmc->bus_width;
390aac4b69bSBo Shen 	unsigned int version = atmel_mci_get_version(mci);
391aac4b69bSBo Shen 	int busw;
3921592ef85SReinhard Meyer 
3931592ef85SReinhard Meyer 	/* Set the clock speed */
394c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
395*722b150eSWenyou.Yang@microchip.com 	mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
396c86c0155SWenyou Yang #else
3971592ef85SReinhard Meyer 	mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
398c86c0155SWenyou Yang #endif
3991592ef85SReinhard Meyer 
4001592ef85SReinhard Meyer 	/*
4011592ef85SReinhard Meyer 	 * set the bus width and select slot for this interface
4021592ef85SReinhard Meyer 	 * there is no capability for multiple slots on the same interface yet
4031592ef85SReinhard Meyer 	 */
404aac4b69bSBo Shen 	if ((version & 0xf00) >= 0x300) {
405aac4b69bSBo Shen 		switch (bus_width) {
406aac4b69bSBo Shen 		case 8:
407aac4b69bSBo Shen 			busw = 3;
408aac4b69bSBo Shen 			break;
409aac4b69bSBo Shen 		case 4:
410aac4b69bSBo Shen 			busw = 2;
411aac4b69bSBo Shen 			break;
412aac4b69bSBo Shen 		default:
413aac4b69bSBo Shen 			busw = 0;
414aac4b69bSBo Shen 			break;
415aac4b69bSBo Shen 		}
416aac4b69bSBo Shen 
417aac4b69bSBo Shen 		writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
418aac4b69bSBo Shen 	} else {
419aac4b69bSBo Shen 		busw = (bus_width == 4) ? 1 : 0;
420aac4b69bSBo Shen 
421aac4b69bSBo Shen 		writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
422aac4b69bSBo Shen 	}
42307b0b9c0SJaehoon Chung 
42407b0b9c0SJaehoon Chung 	return 0;
4251592ef85SReinhard Meyer }
4261592ef85SReinhard Meyer 
427c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
428*722b150eSWenyou.Yang@microchip.com static int atmel_mci_hw_init(struct udevice *dev)
429c86c0155SWenyou Yang {
430*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
431*722b150eSWenyou.Yang@microchip.com 	atmel_mci_t *mci = plat->mci;
432c86c0155SWenyou Yang #else
4331592ef85SReinhard Meyer /* Entered into mmc structure during driver init */
4341592ef85SReinhard Meyer static int mci_init(struct mmc *mmc)
4351592ef85SReinhard Meyer {
4366b75d359SMarek Vasut 	struct atmel_mci_priv *priv = mmc->priv;
4376b75d359SMarek Vasut 	atmel_mci_t *mci = priv->mci;
438*722b150eSWenyou.Yang@microchip.com #endif
4391592ef85SReinhard Meyer 
4401592ef85SReinhard Meyer 	/* Initialize controller */
4411592ef85SReinhard Meyer 	writel(MMCI_BIT(SWRST), &mci->cr);	/* soft reset */
4421592ef85SReinhard Meyer 	writel(MMCI_BIT(PWSDIS), &mci->cr);	/* disable power save */
4431592ef85SReinhard Meyer 	writel(MMCI_BIT(MCIEN), &mci->cr);	/* enable mci */
4442aed9d14SReinhard Meyer 	writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);	/* select port */
4451592ef85SReinhard Meyer 
4469924ca6eSWu, Josh 	/* This delay can be optimized, but stick with max value */
4479924ca6eSWu, Josh 	writel(0x7f, &mci->dtor);
4481592ef85SReinhard Meyer 	/* Disable Interrupts */
4491592ef85SReinhard Meyer 	writel(~0UL, &mci->idr);
4501592ef85SReinhard Meyer 
4511592ef85SReinhard Meyer 	/* Set default clocks and blocklen */
452c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
453*722b150eSWenyou.Yang@microchip.com 	mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
454c86c0155SWenyou Yang #else
4551592ef85SReinhard Meyer 	mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
456c86c0155SWenyou Yang #endif
4571592ef85SReinhard Meyer 
4581592ef85SReinhard Meyer 	return 0;
4591592ef85SReinhard Meyer }
4601592ef85SReinhard Meyer 
461c86c0155SWenyou Yang #ifndef CONFIG_DM_MMC
462ab769f22SPantelis Antoniou static const struct mmc_ops atmel_mci_ops = {
463ab769f22SPantelis Antoniou 	.send_cmd	= mci_send_cmd,
464ab769f22SPantelis Antoniou 	.set_ios	= mci_set_ios,
465ab769f22SPantelis Antoniou 	.init		= mci_init,
466ab769f22SPantelis Antoniou };
467ab769f22SPantelis Antoniou 
4681592ef85SReinhard Meyer /*
4691592ef85SReinhard Meyer  * This is the only exported function
4701592ef85SReinhard Meyer  *
4711592ef85SReinhard Meyer  * Call it with the MCI register base address
4721592ef85SReinhard Meyer  */
4731592ef85SReinhard Meyer int atmel_mci_init(void *regs)
4741592ef85SReinhard Meyer {
47593bfd616SPantelis Antoniou 	struct mmc *mmc;
47693bfd616SPantelis Antoniou 	struct mmc_config *cfg;
4776b75d359SMarek Vasut 	struct atmel_mci_priv *priv;
478aac4b69bSBo Shen 	unsigned int version;
4791592ef85SReinhard Meyer 
4806b75d359SMarek Vasut 	priv = calloc(1, sizeof(*priv));
4816b75d359SMarek Vasut 	if (!priv)
4826b75d359SMarek Vasut 		return -ENOMEM;
483aac4b69bSBo Shen 
4846b75d359SMarek Vasut 	cfg = &priv->cfg;
48593bfd616SPantelis Antoniou 
48693bfd616SPantelis Antoniou 	cfg->name = "mci";
48793bfd616SPantelis Antoniou 	cfg->ops = &atmel_mci_ops;
4881592ef85SReinhard Meyer 
4896b75d359SMarek Vasut 	priv->mci = (struct atmel_mci *)regs;
490877807e1SMarek Vasut 	priv->initialized = 0;
4916b75d359SMarek Vasut 
4921592ef85SReinhard Meyer 	/* need to be able to pass these in on a board by board basis */
49393bfd616SPantelis Antoniou 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
4946b75d359SMarek Vasut 	version = atmel_mci_get_version(priv->mci);
495da55c66eSBo Shen 	if ((version & 0xf00) >= 0x300) {
49693bfd616SPantelis Antoniou 		cfg->host_caps = MMC_MODE_8BIT;
497da55c66eSBo Shen 		cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
498da55c66eSBo Shen 	}
499aac4b69bSBo Shen 
50093bfd616SPantelis Antoniou 	cfg->host_caps |= MMC_MODE_4BIT;
501aac4b69bSBo Shen 
5021592ef85SReinhard Meyer 	/*
5031592ef85SReinhard Meyer 	 * min and max frequencies determined by
5041592ef85SReinhard Meyer 	 * max and min of clock divider
5051592ef85SReinhard Meyer 	 */
50693bfd616SPantelis Antoniou 	cfg->f_min = get_mci_clk_rate() / (2*256);
50793bfd616SPantelis Antoniou 	cfg->f_max = get_mci_clk_rate() / (2*1);
5081592ef85SReinhard Meyer 
50993bfd616SPantelis Antoniou 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
5108feafcc4SJohn Rigby 
5116b75d359SMarek Vasut 	mmc = mmc_create(cfg, priv);
51293bfd616SPantelis Antoniou 
51393bfd616SPantelis Antoniou 	if (mmc == NULL) {
5146b75d359SMarek Vasut 		free(priv);
5156b75d359SMarek Vasut 		return -ENODEV;
51693bfd616SPantelis Antoniou 	}
5176b75d359SMarek Vasut 	/* NOTE: possibly leaking the priv structure */
5181592ef85SReinhard Meyer 
5191592ef85SReinhard Meyer 	return 0;
5201592ef85SReinhard Meyer }
521c86c0155SWenyou Yang #endif
522c86c0155SWenyou Yang 
523c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC
524c86c0155SWenyou Yang static const struct dm_mmc_ops atmel_mci_mmc_ops = {
525c86c0155SWenyou Yang 	.send_cmd = atmel_mci_send_cmd,
526c86c0155SWenyou Yang 	.set_ios = atmel_mci_set_ios,
527c86c0155SWenyou Yang };
528c86c0155SWenyou Yang 
529*722b150eSWenyou.Yang@microchip.com static void atmel_mci_setup_cfg(struct udevice *dev)
530c86c0155SWenyou Yang {
531*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
532*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_priv *priv = dev_get_priv(dev);
533c86c0155SWenyou Yang 	struct mmc_config *cfg;
534c86c0155SWenyou Yang 	u32 version;
535c86c0155SWenyou Yang 
536*722b150eSWenyou.Yang@microchip.com 	cfg = &plat->cfg;
537c86c0155SWenyou Yang 	cfg->name = "Atmel mci";
538c86c0155SWenyou Yang 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
539c86c0155SWenyou Yang 
540c86c0155SWenyou Yang 	/*
541c86c0155SWenyou Yang 	 * If the version is above 3.0, the capabilities of the 8-bit
542c86c0155SWenyou Yang 	 * bus width and high speed are supported.
543c86c0155SWenyou Yang 	 */
544*722b150eSWenyou.Yang@microchip.com 	version = atmel_mci_get_version(plat->mci);
545c86c0155SWenyou Yang 	if ((version & 0xf00) >= 0x300) {
546c86c0155SWenyou Yang 		cfg->host_caps = MMC_MODE_8BIT |
547c86c0155SWenyou Yang 				 MMC_MODE_HS | MMC_MODE_HS_52MHz;
548c86c0155SWenyou Yang 	}
549c86c0155SWenyou Yang 
550c86c0155SWenyou Yang 	cfg->host_caps |= MMC_MODE_4BIT;
551c86c0155SWenyou Yang 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
552c86c0155SWenyou Yang 	cfg->f_min = priv->bus_clk_rate / (2 * 256);
553c86c0155SWenyou Yang 	cfg->f_max = priv->bus_clk_rate / 2;
554c86c0155SWenyou Yang }
555c86c0155SWenyou Yang 
556c86c0155SWenyou Yang static int atmel_mci_enable_clk(struct udevice *dev)
557c86c0155SWenyou Yang {
558c86c0155SWenyou Yang 	struct atmel_mci_priv *priv = dev_get_priv(dev);
559c86c0155SWenyou Yang 	struct clk clk;
560c86c0155SWenyou Yang 	ulong clk_rate;
561c86c0155SWenyou Yang 	int ret = 0;
562c86c0155SWenyou Yang 
563c86c0155SWenyou Yang 	ret = clk_get_by_index(dev, 0, &clk);
564c86c0155SWenyou Yang 	if (ret) {
565c86c0155SWenyou Yang 		ret = -EINVAL;
566c86c0155SWenyou Yang 		goto failed;
567c86c0155SWenyou Yang 	}
568c86c0155SWenyou Yang 
569c86c0155SWenyou Yang 	ret = clk_enable(&clk);
570c86c0155SWenyou Yang 	if (ret)
571c86c0155SWenyou Yang 		goto failed;
572c86c0155SWenyou Yang 
573c86c0155SWenyou Yang 	clk_rate = clk_get_rate(&clk);
574c86c0155SWenyou Yang 	if (!clk_rate) {
575c86c0155SWenyou Yang 		ret = -EINVAL;
576c86c0155SWenyou Yang 		goto failed;
577c86c0155SWenyou Yang 	}
578c86c0155SWenyou Yang 
579c86c0155SWenyou Yang 	priv->bus_clk_rate = clk_rate;
580c86c0155SWenyou Yang 
581c86c0155SWenyou Yang failed:
582c86c0155SWenyou Yang 	clk_free(&clk);
583c86c0155SWenyou Yang 
584c86c0155SWenyou Yang 	return ret;
585c86c0155SWenyou Yang }
586c86c0155SWenyou Yang 
587c86c0155SWenyou Yang static int atmel_mci_probe(struct udevice *dev)
588c86c0155SWenyou Yang {
589c86c0155SWenyou Yang 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
590*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
591c86c0155SWenyou Yang 	struct mmc *mmc;
592c86c0155SWenyou Yang 	int ret;
593c86c0155SWenyou Yang 
594c86c0155SWenyou Yang 	ret = atmel_mci_enable_clk(dev);
595c86c0155SWenyou Yang 	if (ret)
596c86c0155SWenyou Yang 		return ret;
597c86c0155SWenyou Yang 
598*722b150eSWenyou.Yang@microchip.com 	plat->mci = (struct atmel_mci *)devfdt_get_addr_ptr(dev);
599c86c0155SWenyou Yang 
600*722b150eSWenyou.Yang@microchip.com 	atmel_mci_setup_cfg(dev);
601c86c0155SWenyou Yang 
602*722b150eSWenyou.Yang@microchip.com 	mmc = &plat->mmc;
603*722b150eSWenyou.Yang@microchip.com 	mmc->cfg = &plat->cfg;
604c86c0155SWenyou Yang 	mmc->dev = dev;
605c86c0155SWenyou Yang 	upriv->mmc = mmc;
606c86c0155SWenyou Yang 
607*722b150eSWenyou.Yang@microchip.com 	atmel_mci_hw_init(dev);
608c86c0155SWenyou Yang 
609c86c0155SWenyou Yang 	return 0;
610c86c0155SWenyou Yang }
611c86c0155SWenyou Yang 
612c86c0155SWenyou Yang static int atmel_mci_bind(struct udevice *dev)
613c86c0155SWenyou Yang {
614*722b150eSWenyou.Yang@microchip.com 	struct atmel_mci_plat *plat = dev_get_platdata(dev);
615c86c0155SWenyou Yang 
616*722b150eSWenyou.Yang@microchip.com 	return mmc_bind(dev, &plat->mmc, &plat->cfg);
617c86c0155SWenyou Yang }
618c86c0155SWenyou Yang 
619c86c0155SWenyou Yang static const struct udevice_id atmel_mci_ids[] = {
620c86c0155SWenyou Yang 	{ .compatible = "atmel,hsmci" },
621c86c0155SWenyou Yang 	{ }
622c86c0155SWenyou Yang };
623c86c0155SWenyou Yang 
624c86c0155SWenyou Yang U_BOOT_DRIVER(atmel_mci) = {
625c86c0155SWenyou Yang 	.name = "atmel-mci",
626c86c0155SWenyou Yang 	.id = UCLASS_MMC,
627c86c0155SWenyou Yang 	.of_match = atmel_mci_ids,
628c86c0155SWenyou Yang 	.bind = atmel_mci_bind,
629c86c0155SWenyou Yang 	.probe = atmel_mci_probe,
630*722b150eSWenyou.Yang@microchip.com 	.platdata_auto_alloc_size = sizeof(struct atmel_mci_plat),
631c86c0155SWenyou Yang 	.priv_auto_alloc_size = sizeof(struct atmel_mci_priv),
632c86c0155SWenyou Yang 	.ops = &atmel_mci_mmc_ops,
633c86c0155SWenyou Yang };
634c86c0155SWenyou Yang #endif
635