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