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 39722b150eSWenyou.Yang@microchip.com #ifdef CONFIG_DM_MMC 40722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat { 41722b150eSWenyou.Yang@microchip.com struct mmc mmc; 426b75d359SMarek Vasut struct mmc_config cfg; 436b75d359SMarek Vasut struct atmel_mci *mci; 44722b150eSWenyou.Yang@microchip.com }; 45722b150eSWenyou.Yang@microchip.com #endif 46722b150eSWenyou.Yang@microchip.com 47722b150eSWenyou.Yang@microchip.com struct atmel_mci_priv { 48722b150eSWenyou.Yang@microchip.com #ifndef CONFIG_DM_MMC 49722b150eSWenyou.Yang@microchip.com struct mmc_config cfg; 50722b150eSWenyou.Yang@microchip.com struct atmel_mci *mci; 51722b150eSWenyou.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 */ 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 */ 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 77*9b79dbd2SJean-Jacques Hiblot static inline void mci_set_blklen(atmel_mci_t *mci, int blklen) 78*9b79dbd2SJean-Jacques Hiblot { 79*9b79dbd2SJean-Jacques Hiblot unsigned int version = atmel_mci_get_version(mci); 80*9b79dbd2SJean-Jacques Hiblot 81*9b79dbd2SJean-Jacques Hiblot blklen &= 0xfffc; 82*9b79dbd2SJean-Jacques Hiblot 83*9b79dbd2SJean-Jacques Hiblot /* MCI IP version >= 0x200 has blkr */ 84*9b79dbd2SJean-Jacques Hiblot if (version >= 0x200) 85*9b79dbd2SJean-Jacques Hiblot writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)), 86*9b79dbd2SJean-Jacques Hiblot &mci->blkr); 87*9b79dbd2SJean-Jacques Hiblot else 88*9b79dbd2SJean-Jacques Hiblot writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr); 89*9b79dbd2SJean-Jacques Hiblot } 90*9b79dbd2SJean-Jacques Hiblot 911592ef85SReinhard Meyer /* Setup for MCI Clock and Block Size */ 92c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC 93722b150eSWenyou.Yang@microchip.com static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen) 94c86c0155SWenyou Yang { 95722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat *plat = dev_get_platdata(dev); 96722b150eSWenyou.Yang@microchip.com struct atmel_mci_priv *priv = dev_get_priv(dev); 97722b150eSWenyou.Yang@microchip.com struct mmc *mmc = &plat->mmc; 98c86c0155SWenyou Yang u32 bus_hz = priv->bus_clk_rate; 99722b150eSWenyou.Yang@microchip.com atmel_mci_t *mci = plat->mci; 100c86c0155SWenyou Yang #else 1011592ef85SReinhard Meyer static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) 1021592ef85SReinhard Meyer { 1036b75d359SMarek Vasut struct atmel_mci_priv *priv = mmc->priv; 1041592ef85SReinhard Meyer u32 bus_hz = get_mci_clk_rate(); 105722b150eSWenyou.Yang@microchip.com atmel_mci_t *mci = priv->mci; 106c86c0155SWenyou Yang #endif 107c86c0155SWenyou Yang 1081592ef85SReinhard Meyer u32 clkdiv = 255; 109cd60ebd4SBo Shen unsigned int version = atmel_mci_get_version(mci); 110cd60ebd4SBo Shen u32 clkodd = 0; 111cd60ebd4SBo Shen u32 mr; 1121592ef85SReinhard Meyer 1131592ef85SReinhard Meyer debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n", 1141592ef85SReinhard Meyer bus_hz, hz, blklen); 1151592ef85SReinhard Meyer if (hz > 0) { 116cd60ebd4SBo Shen if (version >= 0x500) { 117cd60ebd4SBo Shen clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2; 118cd60ebd4SBo Shen if (clkdiv > 511) 119cd60ebd4SBo Shen clkdiv = 511; 120cd60ebd4SBo Shen 121cd60ebd4SBo Shen clkodd = clkdiv & 1; 122cd60ebd4SBo Shen clkdiv >>= 1; 123cd60ebd4SBo Shen 124b84c9c9aSMarek Vasut debug("mci: setting clock %u Hz, block size %u\n", 125cd60ebd4SBo Shen bus_hz / (clkdiv * 2 + clkodd + 2), blklen); 126cd60ebd4SBo Shen } else { 127cd60ebd4SBo Shen /* find clkdiv yielding a rate <= than requested */ 1281592ef85SReinhard Meyer for (clkdiv = 0; clkdiv < 255; clkdiv++) { 1291592ef85SReinhard Meyer if ((bus_hz / (clkdiv + 1) / 2) <= hz) 1301592ef85SReinhard Meyer break; 1311592ef85SReinhard Meyer } 132b84c9c9aSMarek Vasut debug("mci: setting clock %u Hz, block size %u\n", 1331592ef85SReinhard Meyer (bus_hz / (clkdiv + 1)) / 2, blklen); 1341592ef85SReinhard Meyer 135cd60ebd4SBo Shen } 136cd60ebd4SBo Shen } 137b4670a0cSGregory CLEMENT if (version >= 0x500) 138b4670a0cSGregory CLEMENT priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2); 139b4670a0cSGregory CLEMENT else 140b4670a0cSGregory CLEMENT priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2; 141cd60ebd4SBo Shen 142cd60ebd4SBo Shen mr = MMCI_BF(CLKDIV, clkdiv); 143cd60ebd4SBo Shen 144cd60ebd4SBo Shen /* MCI IP version >= 0x200 has R/WPROOF */ 145cd60ebd4SBo Shen if (version >= 0x200) 146cd60ebd4SBo Shen mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF); 147cd60ebd4SBo Shen 1481db7377aSWu, Josh /* 149cd60ebd4SBo Shen * MCI IP version >= 0x500 use bit 16 as clkodd. 150cd60ebd4SBo Shen * MCI IP version < 0x500 use upper 16 bits for blklen. 1511db7377aSWu, Josh */ 152cd60ebd4SBo Shen if (version >= 0x500) 153cd60ebd4SBo Shen mr |= MMCI_BF(CLKODD, clkodd); 154cd60ebd4SBo Shen 155cd60ebd4SBo Shen writel(mr, &mci->mr); 156cd60ebd4SBo Shen 157*9b79dbd2SJean-Jacques Hiblot mci_set_blklen(mci, blklen); 158cd60ebd4SBo Shen 159da55c66eSBo Shen if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS) 160da55c66eSBo Shen writel(MMCI_BIT(HSMODE), &mci->cfg); 161da55c66eSBo Shen 162877807e1SMarek Vasut priv->initialized = 1; 1631592ef85SReinhard Meyer } 1641592ef85SReinhard Meyer 1651592ef85SReinhard Meyer /* Return the CMDR with flags for a given command and data packet */ 1661592ef85SReinhard Meyer static u32 mci_encode_cmd( 1671592ef85SReinhard Meyer struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags) 1681592ef85SReinhard Meyer { 1691592ef85SReinhard Meyer u32 cmdr = 0; 1701592ef85SReinhard Meyer 1711592ef85SReinhard Meyer /* Default Flags for Errors */ 1721592ef85SReinhard Meyer *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) | 1731592ef85SReinhard Meyer MMCI_BIT(RINDE) | MMCI_BIT(RTOE)); 1741592ef85SReinhard Meyer 1751592ef85SReinhard Meyer /* Default Flags for the Command */ 1761592ef85SReinhard Meyer cmdr |= MMCI_BIT(MAXLAT); 1771592ef85SReinhard Meyer 1781592ef85SReinhard Meyer if (data) { 1791592ef85SReinhard Meyer cmdr |= MMCI_BF(TRCMD, 1); 1801592ef85SReinhard Meyer if (data->blocks > 1) 1811592ef85SReinhard Meyer cmdr |= MMCI_BF(TRTYP, 1); 1821592ef85SReinhard Meyer if (data->flags & MMC_DATA_READ) 1831592ef85SReinhard Meyer cmdr |= MMCI_BIT(TRDIR); 1841592ef85SReinhard Meyer } 1851592ef85SReinhard Meyer 1861592ef85SReinhard Meyer if (cmd->resp_type & MMC_RSP_CRC) 1871592ef85SReinhard Meyer *error_flags |= MMCI_BIT(RCRCE); 1881592ef85SReinhard Meyer if (cmd->resp_type & MMC_RSP_136) 1891592ef85SReinhard Meyer cmdr |= MMCI_BF(RSPTYP, 2); 1901592ef85SReinhard Meyer else if (cmd->resp_type & MMC_RSP_BUSY) 1911592ef85SReinhard Meyer cmdr |= MMCI_BF(RSPTYP, 3); 1921592ef85SReinhard Meyer else if (cmd->resp_type & MMC_RSP_PRESENT) 1931592ef85SReinhard Meyer cmdr |= MMCI_BF(RSPTYP, 1); 1941592ef85SReinhard Meyer 1951592ef85SReinhard Meyer return cmdr | MMCI_BF(CMDNB, cmd->cmdidx); 1961592ef85SReinhard Meyer } 1971592ef85SReinhard Meyer 1981592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */ 1991592ef85SReinhard Meyer static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags) 2001592ef85SReinhard Meyer { 2011592ef85SReinhard Meyer u32 status; 2021592ef85SReinhard Meyer 2031592ef85SReinhard Meyer do { 2041592ef85SReinhard Meyer status = readl(&mci->sr); 2051592ef85SReinhard Meyer if (status & (error_flags | MMCI_BIT(OVRE))) 2061592ef85SReinhard Meyer goto io_fail; 2071592ef85SReinhard Meyer } while (!(status & MMCI_BIT(RXRDY))); 2081592ef85SReinhard Meyer 2091592ef85SReinhard Meyer if (status & MMCI_BIT(RXRDY)) { 2101592ef85SReinhard Meyer *data = readl(&mci->rdr); 2111592ef85SReinhard Meyer status = 0; 2121592ef85SReinhard Meyer } 2131592ef85SReinhard Meyer io_fail: 2141592ef85SReinhard Meyer return status; 2151592ef85SReinhard Meyer } 2161592ef85SReinhard Meyer 2171592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */ 2181592ef85SReinhard Meyer static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags) 2191592ef85SReinhard Meyer { 2201592ef85SReinhard Meyer u32 status; 2211592ef85SReinhard Meyer 2221592ef85SReinhard Meyer do { 2231592ef85SReinhard Meyer status = readl(&mci->sr); 2241592ef85SReinhard Meyer if (status & (error_flags | MMCI_BIT(UNRE))) 2251592ef85SReinhard Meyer goto io_fail; 2261592ef85SReinhard Meyer } while (!(status & MMCI_BIT(TXRDY))); 2271592ef85SReinhard Meyer 2281592ef85SReinhard Meyer if (status & MMCI_BIT(TXRDY)) { 2291592ef85SReinhard Meyer writel(*data, &mci->tdr); 2301592ef85SReinhard Meyer status = 0; 2311592ef85SReinhard Meyer } 2321592ef85SReinhard Meyer io_fail: 2331592ef85SReinhard Meyer return status; 2341592ef85SReinhard Meyer } 2351592ef85SReinhard Meyer 2361592ef85SReinhard Meyer /* 2371592ef85SReinhard Meyer * Entered into mmc structure during driver init 2381592ef85SReinhard Meyer * 2391592ef85SReinhard Meyer * Sends a command out on the bus and deals with the block data. 2401592ef85SReinhard Meyer * Takes the mmc pointer, a command pointer, and an optional data pointer. 2411592ef85SReinhard Meyer */ 242c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC 243c86c0155SWenyou Yang static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, 244c86c0155SWenyou Yang struct mmc_data *data) 245c86c0155SWenyou Yang { 246722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat *plat = dev_get_platdata(dev); 247c86c0155SWenyou Yang struct atmel_mci_priv *priv = dev_get_priv(dev); 248722b150eSWenyou.Yang@microchip.com atmel_mci_t *mci = plat->mci; 249c86c0155SWenyou Yang #else 2501592ef85SReinhard Meyer static int 2511592ef85SReinhard Meyer mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 2521592ef85SReinhard Meyer { 2536b75d359SMarek Vasut struct atmel_mci_priv *priv = mmc->priv; 2546b75d359SMarek Vasut atmel_mci_t *mci = priv->mci; 255722b150eSWenyou.Yang@microchip.com #endif 2561592ef85SReinhard Meyer u32 cmdr; 2571592ef85SReinhard Meyer u32 error_flags = 0; 2581592ef85SReinhard Meyer u32 status; 2591592ef85SReinhard Meyer 260877807e1SMarek Vasut if (!priv->initialized) { 2611592ef85SReinhard Meyer puts ("MCI not initialized!\n"); 262915ffa52SJaehoon Chung return -ECOMM; 2631592ef85SReinhard Meyer } 2641592ef85SReinhard Meyer 2651592ef85SReinhard Meyer /* Figure out the transfer arguments */ 2661592ef85SReinhard Meyer cmdr = mci_encode_cmd(cmd, data, &error_flags); 2671592ef85SReinhard Meyer 268*9b79dbd2SJean-Jacques Hiblot mci_set_blklen(mci, data->blocksize); 269*9b79dbd2SJean-Jacques Hiblot 2701db7377aSWu, Josh /* For multi blocks read/write, set the block register */ 2711db7377aSWu, Josh if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) 2721db7377aSWu, Josh || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) 273*9b79dbd2SJean-Jacques Hiblot writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize), 2741db7377aSWu, Josh &mci->blkr); 2751db7377aSWu, Josh 2761592ef85SReinhard Meyer /* Send the command */ 2771592ef85SReinhard Meyer writel(cmd->cmdarg, &mci->argr); 2781592ef85SReinhard Meyer writel(cmdr, &mci->cmdr); 2791592ef85SReinhard Meyer 2801592ef85SReinhard Meyer #ifdef DEBUG 2811592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG"); 2821592ef85SReinhard Meyer #endif 2831592ef85SReinhard Meyer 2841592ef85SReinhard Meyer /* Wait for the command to complete */ 2851592ef85SReinhard Meyer while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY))); 2861592ef85SReinhard Meyer 28793e3236cSBo Shen if ((status & error_flags) & MMCI_BIT(RTOE)) { 28893e3236cSBo Shen dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out"); 289915ffa52SJaehoon Chung return -ETIMEDOUT; 29093e3236cSBo Shen } else if (status & error_flags) { 2911592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed"); 292915ffa52SJaehoon Chung return -ECOMM; 2931592ef85SReinhard Meyer } 2941592ef85SReinhard Meyer 2951592ef85SReinhard Meyer /* Copy the response to the response buffer */ 2961592ef85SReinhard Meyer if (cmd->resp_type & MMC_RSP_136) { 2971592ef85SReinhard Meyer cmd->response[0] = readl(&mci->rspr); 2981592ef85SReinhard Meyer cmd->response[1] = readl(&mci->rspr1); 2991592ef85SReinhard Meyer cmd->response[2] = readl(&mci->rspr2); 3001592ef85SReinhard Meyer cmd->response[3] = readl(&mci->rspr3); 3011592ef85SReinhard Meyer } else 3021592ef85SReinhard Meyer cmd->response[0] = readl(&mci->rspr); 3031592ef85SReinhard Meyer 3041592ef85SReinhard Meyer /* transfer all of the blocks */ 3051592ef85SReinhard Meyer if (data) { 3061592ef85SReinhard Meyer u32 word_count, block_count; 3071592ef85SReinhard Meyer u32* ioptr; 308*9b79dbd2SJean-Jacques Hiblot u32 i; 3091592ef85SReinhard Meyer u32 (*mci_data_op) 3101592ef85SReinhard Meyer (atmel_mci_t *mci, u32* data, u32 error_flags); 3111592ef85SReinhard Meyer 3121592ef85SReinhard Meyer if (data->flags & MMC_DATA_READ) { 3131592ef85SReinhard Meyer mci_data_op = mci_data_read; 3141592ef85SReinhard Meyer ioptr = (u32*)data->dest; 3151592ef85SReinhard Meyer } else { 3161592ef85SReinhard Meyer mci_data_op = mci_data_write; 3171592ef85SReinhard Meyer ioptr = (u32*)data->src; 3181592ef85SReinhard Meyer } 3191592ef85SReinhard Meyer 3201592ef85SReinhard Meyer status = 0; 3211592ef85SReinhard Meyer for (block_count = 0; 3221592ef85SReinhard Meyer block_count < data->blocks && !status; 3231592ef85SReinhard Meyer block_count++) { 3241592ef85SReinhard Meyer word_count = 0; 3251592ef85SReinhard Meyer do { 3261592ef85SReinhard Meyer status = mci_data_op(mci, ioptr, error_flags); 3271592ef85SReinhard Meyer word_count++; 3281592ef85SReinhard Meyer ioptr++; 3291592ef85SReinhard Meyer } while (!status && word_count < (data->blocksize/4)); 3301592ef85SReinhard Meyer #ifdef DEBUG 3311592ef85SReinhard Meyer if (data->flags & MMC_DATA_READ) 3321592ef85SReinhard Meyer { 3339902c7b6SWu, Josh u32 cnt = word_count * 4; 3341592ef85SReinhard Meyer printf("Read Data:\n"); 3359902c7b6SWu, Josh print_buffer(0, data->dest + cnt * block_count, 3369902c7b6SWu, Josh 1, cnt, 0); 3371592ef85SReinhard Meyer } 3381592ef85SReinhard Meyer #endif 3391592ef85SReinhard Meyer if (status) { 3401592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, 3411592ef85SReinhard Meyer "Data Transfer Failed"); 342915ffa52SJaehoon Chung return -ECOMM; 3431592ef85SReinhard Meyer } 3441592ef85SReinhard Meyer } 3451592ef85SReinhard Meyer 3461592ef85SReinhard Meyer /* Wait for Transfer End */ 3471592ef85SReinhard Meyer i = 0; 3481592ef85SReinhard Meyer do { 3491592ef85SReinhard Meyer status = readl(&mci->sr); 3501592ef85SReinhard Meyer 3511592ef85SReinhard Meyer if (status & error_flags) { 3521592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, 3531592ef85SReinhard Meyer "DTIP Wait Failed"); 354915ffa52SJaehoon Chung return -ECOMM; 3551592ef85SReinhard Meyer } 3561592ef85SReinhard Meyer i++; 3571592ef85SReinhard Meyer } while ((status & MMCI_BIT(DTIP)) && i < 10000); 3581592ef85SReinhard Meyer if (status & MMCI_BIT(DTIP)) { 3591592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, 3601592ef85SReinhard Meyer "XFER DTIP never unset, ignoring"); 3611592ef85SReinhard Meyer } 3621592ef85SReinhard Meyer } 3631592ef85SReinhard Meyer 364b4670a0cSGregory CLEMENT /* 365b4670a0cSGregory CLEMENT * After the switch command, wait for 8 clocks before the next 366b4670a0cSGregory CLEMENT * command 367b4670a0cSGregory CLEMENT */ 368b4670a0cSGregory CLEMENT if (cmd->cmdidx == MMC_CMD_SWITCH) 369b4670a0cSGregory CLEMENT udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */ 370b4670a0cSGregory CLEMENT 3711592ef85SReinhard Meyer return 0; 3721592ef85SReinhard Meyer } 3731592ef85SReinhard Meyer 374c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC 375c86c0155SWenyou Yang static int atmel_mci_set_ios(struct udevice *dev) 376c86c0155SWenyou Yang { 377722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat *plat = dev_get_platdata(dev); 378c86c0155SWenyou Yang struct mmc *mmc = mmc_get_mmc_dev(dev); 379722b150eSWenyou.Yang@microchip.com atmel_mci_t *mci = plat->mci; 380c86c0155SWenyou Yang #else 3811592ef85SReinhard Meyer /* Entered into mmc structure during driver init */ 38207b0b9c0SJaehoon Chung static int mci_set_ios(struct mmc *mmc) 3831592ef85SReinhard Meyer { 3846b75d359SMarek Vasut struct atmel_mci_priv *priv = mmc->priv; 3856b75d359SMarek Vasut atmel_mci_t *mci = priv->mci; 386722b150eSWenyou.Yang@microchip.com #endif 387aac4b69bSBo Shen int bus_width = mmc->bus_width; 388aac4b69bSBo Shen unsigned int version = atmel_mci_get_version(mci); 389aac4b69bSBo Shen int busw; 3901592ef85SReinhard Meyer 3911592ef85SReinhard Meyer /* Set the clock speed */ 392c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC 393722b150eSWenyou.Yang@microchip.com mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN); 394c86c0155SWenyou Yang #else 3951592ef85SReinhard Meyer mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN); 396c86c0155SWenyou Yang #endif 3971592ef85SReinhard Meyer 3981592ef85SReinhard Meyer /* 3991592ef85SReinhard Meyer * set the bus width and select slot for this interface 4001592ef85SReinhard Meyer * there is no capability for multiple slots on the same interface yet 4011592ef85SReinhard Meyer */ 402aac4b69bSBo Shen if ((version & 0xf00) >= 0x300) { 403aac4b69bSBo Shen switch (bus_width) { 404aac4b69bSBo Shen case 8: 405aac4b69bSBo Shen busw = 3; 406aac4b69bSBo Shen break; 407aac4b69bSBo Shen case 4: 408aac4b69bSBo Shen busw = 2; 409aac4b69bSBo Shen break; 410aac4b69bSBo Shen default: 411aac4b69bSBo Shen busw = 0; 412aac4b69bSBo Shen break; 413aac4b69bSBo Shen } 414aac4b69bSBo Shen 415aac4b69bSBo Shen writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); 416aac4b69bSBo Shen } else { 417aac4b69bSBo Shen busw = (bus_width == 4) ? 1 : 0; 418aac4b69bSBo Shen 419aac4b69bSBo Shen writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); 420aac4b69bSBo Shen } 42107b0b9c0SJaehoon Chung 42207b0b9c0SJaehoon Chung return 0; 4231592ef85SReinhard Meyer } 4241592ef85SReinhard Meyer 425c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC 426722b150eSWenyou.Yang@microchip.com static int atmel_mci_hw_init(struct udevice *dev) 427c86c0155SWenyou Yang { 428722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat *plat = dev_get_platdata(dev); 429722b150eSWenyou.Yang@microchip.com atmel_mci_t *mci = plat->mci; 430c86c0155SWenyou Yang #else 4311592ef85SReinhard Meyer /* Entered into mmc structure during driver init */ 4321592ef85SReinhard Meyer static int mci_init(struct mmc *mmc) 4331592ef85SReinhard Meyer { 4346b75d359SMarek Vasut struct atmel_mci_priv *priv = mmc->priv; 4356b75d359SMarek Vasut atmel_mci_t *mci = priv->mci; 436722b150eSWenyou.Yang@microchip.com #endif 4371592ef85SReinhard Meyer 4381592ef85SReinhard Meyer /* Initialize controller */ 4391592ef85SReinhard Meyer writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */ 4401592ef85SReinhard Meyer writel(MMCI_BIT(PWSDIS), &mci->cr); /* disable power save */ 4411592ef85SReinhard Meyer writel(MMCI_BIT(MCIEN), &mci->cr); /* enable mci */ 4422aed9d14SReinhard Meyer writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); /* select port */ 4431592ef85SReinhard Meyer 4449924ca6eSWu, Josh /* This delay can be optimized, but stick with max value */ 4459924ca6eSWu, Josh writel(0x7f, &mci->dtor); 4461592ef85SReinhard Meyer /* Disable Interrupts */ 4471592ef85SReinhard Meyer writel(~0UL, &mci->idr); 4481592ef85SReinhard Meyer 4491592ef85SReinhard Meyer /* Set default clocks and blocklen */ 450c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC 451722b150eSWenyou.Yang@microchip.com mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); 452c86c0155SWenyou Yang #else 4531592ef85SReinhard Meyer mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); 454c86c0155SWenyou Yang #endif 4551592ef85SReinhard Meyer 4561592ef85SReinhard Meyer return 0; 4571592ef85SReinhard Meyer } 4581592ef85SReinhard Meyer 459c86c0155SWenyou Yang #ifndef CONFIG_DM_MMC 460ab769f22SPantelis Antoniou static const struct mmc_ops atmel_mci_ops = { 461ab769f22SPantelis Antoniou .send_cmd = mci_send_cmd, 462ab769f22SPantelis Antoniou .set_ios = mci_set_ios, 463ab769f22SPantelis Antoniou .init = mci_init, 464ab769f22SPantelis Antoniou }; 465ab769f22SPantelis Antoniou 4661592ef85SReinhard Meyer /* 4671592ef85SReinhard Meyer * This is the only exported function 4681592ef85SReinhard Meyer * 4691592ef85SReinhard Meyer * Call it with the MCI register base address 4701592ef85SReinhard Meyer */ 4711592ef85SReinhard Meyer int atmel_mci_init(void *regs) 4721592ef85SReinhard Meyer { 47393bfd616SPantelis Antoniou struct mmc *mmc; 47493bfd616SPantelis Antoniou struct mmc_config *cfg; 4756b75d359SMarek Vasut struct atmel_mci_priv *priv; 476aac4b69bSBo Shen unsigned int version; 4771592ef85SReinhard Meyer 4786b75d359SMarek Vasut priv = calloc(1, sizeof(*priv)); 4796b75d359SMarek Vasut if (!priv) 4806b75d359SMarek Vasut return -ENOMEM; 481aac4b69bSBo Shen 4826b75d359SMarek Vasut cfg = &priv->cfg; 48393bfd616SPantelis Antoniou 48493bfd616SPantelis Antoniou cfg->name = "mci"; 48593bfd616SPantelis Antoniou cfg->ops = &atmel_mci_ops; 4861592ef85SReinhard Meyer 4876b75d359SMarek Vasut priv->mci = (struct atmel_mci *)regs; 488877807e1SMarek Vasut priv->initialized = 0; 4896b75d359SMarek Vasut 4901592ef85SReinhard Meyer /* need to be able to pass these in on a board by board basis */ 49193bfd616SPantelis Antoniou cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 4926b75d359SMarek Vasut version = atmel_mci_get_version(priv->mci); 493da55c66eSBo Shen if ((version & 0xf00) >= 0x300) { 49493bfd616SPantelis Antoniou cfg->host_caps = MMC_MODE_8BIT; 495da55c66eSBo Shen cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; 496da55c66eSBo Shen } 497aac4b69bSBo Shen 49893bfd616SPantelis Antoniou cfg->host_caps |= MMC_MODE_4BIT; 499aac4b69bSBo Shen 5001592ef85SReinhard Meyer /* 5011592ef85SReinhard Meyer * min and max frequencies determined by 5021592ef85SReinhard Meyer * max and min of clock divider 5031592ef85SReinhard Meyer */ 50493bfd616SPantelis Antoniou cfg->f_min = get_mci_clk_rate() / (2*256); 50593bfd616SPantelis Antoniou cfg->f_max = get_mci_clk_rate() / (2*1); 5061592ef85SReinhard Meyer 50793bfd616SPantelis Antoniou cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 5088feafcc4SJohn Rigby 5096b75d359SMarek Vasut mmc = mmc_create(cfg, priv); 51093bfd616SPantelis Antoniou 51193bfd616SPantelis Antoniou if (mmc == NULL) { 5126b75d359SMarek Vasut free(priv); 5136b75d359SMarek Vasut return -ENODEV; 51493bfd616SPantelis Antoniou } 5156b75d359SMarek Vasut /* NOTE: possibly leaking the priv structure */ 5161592ef85SReinhard Meyer 5171592ef85SReinhard Meyer return 0; 5181592ef85SReinhard Meyer } 519c86c0155SWenyou Yang #endif 520c86c0155SWenyou Yang 521c86c0155SWenyou Yang #ifdef CONFIG_DM_MMC 522c86c0155SWenyou Yang static const struct dm_mmc_ops atmel_mci_mmc_ops = { 523c86c0155SWenyou Yang .send_cmd = atmel_mci_send_cmd, 524c86c0155SWenyou Yang .set_ios = atmel_mci_set_ios, 525c86c0155SWenyou Yang }; 526c86c0155SWenyou Yang 527722b150eSWenyou.Yang@microchip.com static void atmel_mci_setup_cfg(struct udevice *dev) 528c86c0155SWenyou Yang { 529722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat *plat = dev_get_platdata(dev); 530722b150eSWenyou.Yang@microchip.com struct atmel_mci_priv *priv = dev_get_priv(dev); 531c86c0155SWenyou Yang struct mmc_config *cfg; 532c86c0155SWenyou Yang u32 version; 533c86c0155SWenyou Yang 534722b150eSWenyou.Yang@microchip.com cfg = &plat->cfg; 535c86c0155SWenyou Yang cfg->name = "Atmel mci"; 536c86c0155SWenyou Yang cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 537c86c0155SWenyou Yang 538c86c0155SWenyou Yang /* 539c86c0155SWenyou Yang * If the version is above 3.0, the capabilities of the 8-bit 540c86c0155SWenyou Yang * bus width and high speed are supported. 541c86c0155SWenyou Yang */ 542722b150eSWenyou.Yang@microchip.com version = atmel_mci_get_version(plat->mci); 543c86c0155SWenyou Yang if ((version & 0xf00) >= 0x300) { 544c86c0155SWenyou Yang cfg->host_caps = MMC_MODE_8BIT | 545c86c0155SWenyou Yang MMC_MODE_HS | MMC_MODE_HS_52MHz; 546c86c0155SWenyou Yang } 547c86c0155SWenyou Yang 548c86c0155SWenyou Yang cfg->host_caps |= MMC_MODE_4BIT; 549c86c0155SWenyou Yang cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 550c86c0155SWenyou Yang cfg->f_min = priv->bus_clk_rate / (2 * 256); 551c86c0155SWenyou Yang cfg->f_max = priv->bus_clk_rate / 2; 552c86c0155SWenyou Yang } 553c86c0155SWenyou Yang 554c86c0155SWenyou Yang static int atmel_mci_enable_clk(struct udevice *dev) 555c86c0155SWenyou Yang { 556c86c0155SWenyou Yang struct atmel_mci_priv *priv = dev_get_priv(dev); 557c86c0155SWenyou Yang struct clk clk; 558c86c0155SWenyou Yang ulong clk_rate; 559c86c0155SWenyou Yang int ret = 0; 560c86c0155SWenyou Yang 561c86c0155SWenyou Yang ret = clk_get_by_index(dev, 0, &clk); 562c86c0155SWenyou Yang if (ret) { 563c86c0155SWenyou Yang ret = -EINVAL; 564c86c0155SWenyou Yang goto failed; 565c86c0155SWenyou Yang } 566c86c0155SWenyou Yang 567c86c0155SWenyou Yang ret = clk_enable(&clk); 568c86c0155SWenyou Yang if (ret) 569c86c0155SWenyou Yang goto failed; 570c86c0155SWenyou Yang 571c86c0155SWenyou Yang clk_rate = clk_get_rate(&clk); 572c86c0155SWenyou Yang if (!clk_rate) { 573c86c0155SWenyou Yang ret = -EINVAL; 574c86c0155SWenyou Yang goto failed; 575c86c0155SWenyou Yang } 576c86c0155SWenyou Yang 577c86c0155SWenyou Yang priv->bus_clk_rate = clk_rate; 578c86c0155SWenyou Yang 579c86c0155SWenyou Yang failed: 580c86c0155SWenyou Yang clk_free(&clk); 581c86c0155SWenyou Yang 582c86c0155SWenyou Yang return ret; 583c86c0155SWenyou Yang } 584c86c0155SWenyou Yang 585c86c0155SWenyou Yang static int atmel_mci_probe(struct udevice *dev) 586c86c0155SWenyou Yang { 587c86c0155SWenyou Yang struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 588722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat *plat = dev_get_platdata(dev); 589c86c0155SWenyou Yang struct mmc *mmc; 590c86c0155SWenyou Yang int ret; 591c86c0155SWenyou Yang 592c86c0155SWenyou Yang ret = atmel_mci_enable_clk(dev); 593c86c0155SWenyou Yang if (ret) 594c86c0155SWenyou Yang return ret; 595c86c0155SWenyou Yang 596722b150eSWenyou.Yang@microchip.com plat->mci = (struct atmel_mci *)devfdt_get_addr_ptr(dev); 597c86c0155SWenyou Yang 598722b150eSWenyou.Yang@microchip.com atmel_mci_setup_cfg(dev); 599c86c0155SWenyou Yang 600722b150eSWenyou.Yang@microchip.com mmc = &plat->mmc; 601722b150eSWenyou.Yang@microchip.com mmc->cfg = &plat->cfg; 602c86c0155SWenyou Yang mmc->dev = dev; 603c86c0155SWenyou Yang upriv->mmc = mmc; 604c86c0155SWenyou Yang 605722b150eSWenyou.Yang@microchip.com atmel_mci_hw_init(dev); 606c86c0155SWenyou Yang 607c86c0155SWenyou Yang return 0; 608c86c0155SWenyou Yang } 609c86c0155SWenyou Yang 610c86c0155SWenyou Yang static int atmel_mci_bind(struct udevice *dev) 611c86c0155SWenyou Yang { 612722b150eSWenyou.Yang@microchip.com struct atmel_mci_plat *plat = dev_get_platdata(dev); 613c86c0155SWenyou Yang 614722b150eSWenyou.Yang@microchip.com return mmc_bind(dev, &plat->mmc, &plat->cfg); 615c86c0155SWenyou Yang } 616c86c0155SWenyou Yang 617c86c0155SWenyou Yang static const struct udevice_id atmel_mci_ids[] = { 618c86c0155SWenyou Yang { .compatible = "atmel,hsmci" }, 619c86c0155SWenyou Yang { } 620c86c0155SWenyou Yang }; 621c86c0155SWenyou Yang 622c86c0155SWenyou Yang U_BOOT_DRIVER(atmel_mci) = { 623c86c0155SWenyou Yang .name = "atmel-mci", 624c86c0155SWenyou Yang .id = UCLASS_MMC, 625c86c0155SWenyou Yang .of_match = atmel_mci_ids, 626c86c0155SWenyou Yang .bind = atmel_mci_bind, 627c86c0155SWenyou Yang .probe = atmel_mci_probe, 628722b150eSWenyou.Yang@microchip.com .platdata_auto_alloc_size = sizeof(struct atmel_mci_plat), 629c86c0155SWenyou Yang .priv_auto_alloc_size = sizeof(struct atmel_mci_priv), 630c86c0155SWenyou Yang .ops = &atmel_mci_mmc_ops, 631c86c0155SWenyou Yang }; 632c86c0155SWenyou Yang #endif 633