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 * 91592ef85SReinhard Meyer * See file CREDITS for list of people who contributed to this 101592ef85SReinhard Meyer * project. 111592ef85SReinhard Meyer * 121592ef85SReinhard Meyer * This program is free software; you can redistribute it and/or 131592ef85SReinhard Meyer * modify it under the terms of the GNU General Public License as 141592ef85SReinhard Meyer * published by the Free Software Foundation; either version 2 of 151592ef85SReinhard Meyer * the License, or (at your option) any later version. 161592ef85SReinhard Meyer * 171592ef85SReinhard Meyer * This program is distributed in the hope that it will be useful, 181592ef85SReinhard Meyer * but WITHOUT ANY WARRANTY; without even the implied warranty of 191592ef85SReinhard Meyer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 201592ef85SReinhard Meyer * GNU General Public License for more details. 211592ef85SReinhard Meyer * 221592ef85SReinhard Meyer * You should have received a copy of the GNU General Public License 231592ef85SReinhard Meyer * along with this program; if not, write to the Free Software 241592ef85SReinhard Meyer * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 251592ef85SReinhard Meyer * MA 02111-1307 USA 261592ef85SReinhard Meyer */ 271592ef85SReinhard Meyer 281592ef85SReinhard Meyer #include <common.h> 291592ef85SReinhard Meyer #include <mmc.h> 301592ef85SReinhard Meyer #include <part.h> 311592ef85SReinhard Meyer #include <malloc.h> 321592ef85SReinhard Meyer #include <asm/io.h> 331592ef85SReinhard Meyer #include <asm/errno.h> 341592ef85SReinhard Meyer #include <asm/byteorder.h> 351592ef85SReinhard Meyer #include <asm/arch/clk.h> 36*329f0f52SReinhard Meyer #include <asm/arch/hardware.h> 371592ef85SReinhard Meyer #include "atmel_mci.h" 381592ef85SReinhard Meyer 391592ef85SReinhard Meyer #ifndef CONFIG_SYS_MMC_CLK_OD 401592ef85SReinhard Meyer # define CONFIG_SYS_MMC_CLK_OD 150000 411592ef85SReinhard Meyer #endif 421592ef85SReinhard Meyer 431592ef85SReinhard Meyer #define MMC_DEFAULT_BLKLEN 512 441592ef85SReinhard Meyer 451592ef85SReinhard Meyer #if defined(CONFIG_ATMEL_MCI_PORTB) 461592ef85SReinhard Meyer # define MCI_BUS 1 471592ef85SReinhard Meyer #else 481592ef85SReinhard Meyer # define MCI_BUS 0 491592ef85SReinhard Meyer #endif 501592ef85SReinhard Meyer 511592ef85SReinhard Meyer static int initialized = 0; 521592ef85SReinhard Meyer 531592ef85SReinhard Meyer /* 541592ef85SReinhard Meyer * Print command and status: 551592ef85SReinhard Meyer * 561592ef85SReinhard Meyer * - always when DEBUG is defined 571592ef85SReinhard Meyer * - on command errors 581592ef85SReinhard Meyer */ 591592ef85SReinhard Meyer static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg) 601592ef85SReinhard Meyer { 611592ef85SReinhard Meyer printf("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n", 621592ef85SReinhard Meyer cmdr, cmdr&0x3F, arg, status, msg); 631592ef85SReinhard Meyer } 641592ef85SReinhard Meyer 651592ef85SReinhard Meyer /* Setup for MCI Clock and Block Size */ 661592ef85SReinhard Meyer static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) 671592ef85SReinhard Meyer { 681592ef85SReinhard Meyer atmel_mci_t *mci = (atmel_mci_t *)mmc->priv; 691592ef85SReinhard Meyer u32 bus_hz = get_mci_clk_rate(); 701592ef85SReinhard Meyer u32 clkdiv = 255; 711592ef85SReinhard Meyer 721592ef85SReinhard Meyer debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n", 731592ef85SReinhard Meyer bus_hz, hz, blklen); 741592ef85SReinhard Meyer if (hz > 0) { 751592ef85SReinhard Meyer /* find lowest clkdiv yielding a rate <= than requested */ 761592ef85SReinhard Meyer for (clkdiv=0; clkdiv<255; clkdiv++) { 771592ef85SReinhard Meyer if ((bus_hz / (clkdiv+1) / 2) <= hz) 781592ef85SReinhard Meyer break; 791592ef85SReinhard Meyer } 801592ef85SReinhard Meyer } 811592ef85SReinhard Meyer printf("mci: setting clock %u Hz, block size %u\n", 821592ef85SReinhard Meyer (bus_hz / (clkdiv+1)) / 2, blklen); 831592ef85SReinhard Meyer 841592ef85SReinhard Meyer blklen &= 0xfffc; 851592ef85SReinhard Meyer /* On some platforms RDPROOF and WRPROOF are ignored */ 861592ef85SReinhard Meyer writel((MMCI_BF(CLKDIV, clkdiv) 871592ef85SReinhard Meyer | MMCI_BF(BLKLEN, blklen) 881592ef85SReinhard Meyer | MMCI_BIT(RDPROOF) 891592ef85SReinhard Meyer | MMCI_BIT(WRPROOF)), &mci->mr); 901592ef85SReinhard Meyer initialized = 1; 911592ef85SReinhard Meyer } 921592ef85SReinhard Meyer 931592ef85SReinhard Meyer /* Return the CMDR with flags for a given command and data packet */ 941592ef85SReinhard Meyer static u32 mci_encode_cmd( 951592ef85SReinhard Meyer struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags) 961592ef85SReinhard Meyer { 971592ef85SReinhard Meyer u32 cmdr = 0; 981592ef85SReinhard Meyer 991592ef85SReinhard Meyer /* Default Flags for Errors */ 1001592ef85SReinhard Meyer *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) | 1011592ef85SReinhard Meyer MMCI_BIT(RINDE) | MMCI_BIT(RTOE)); 1021592ef85SReinhard Meyer 1031592ef85SReinhard Meyer /* Default Flags for the Command */ 1041592ef85SReinhard Meyer cmdr |= MMCI_BIT(MAXLAT); 1051592ef85SReinhard Meyer 1061592ef85SReinhard Meyer if (data) { 1071592ef85SReinhard Meyer cmdr |= MMCI_BF(TRCMD, 1); 1081592ef85SReinhard Meyer if (data->blocks > 1) 1091592ef85SReinhard Meyer cmdr |= MMCI_BF(TRTYP, 1); 1101592ef85SReinhard Meyer if (data->flags & MMC_DATA_READ) 1111592ef85SReinhard Meyer cmdr |= MMCI_BIT(TRDIR); 1121592ef85SReinhard Meyer } 1131592ef85SReinhard Meyer 1141592ef85SReinhard Meyer if (cmd->resp_type & MMC_RSP_CRC) 1151592ef85SReinhard Meyer *error_flags |= MMCI_BIT(RCRCE); 1161592ef85SReinhard Meyer if (cmd->resp_type & MMC_RSP_136) 1171592ef85SReinhard Meyer cmdr |= MMCI_BF(RSPTYP, 2); 1181592ef85SReinhard Meyer else if (cmd->resp_type & MMC_RSP_BUSY) 1191592ef85SReinhard Meyer cmdr |= MMCI_BF(RSPTYP, 3); 1201592ef85SReinhard Meyer else if (cmd->resp_type & MMC_RSP_PRESENT) 1211592ef85SReinhard Meyer cmdr |= MMCI_BF(RSPTYP, 1); 1221592ef85SReinhard Meyer 1231592ef85SReinhard Meyer return cmdr | MMCI_BF(CMDNB, cmd->cmdidx); 1241592ef85SReinhard Meyer } 1251592ef85SReinhard Meyer 1261592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */ 1271592ef85SReinhard Meyer static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags) 1281592ef85SReinhard Meyer { 1291592ef85SReinhard Meyer u32 status; 1301592ef85SReinhard Meyer 1311592ef85SReinhard Meyer do { 1321592ef85SReinhard Meyer status = readl(&mci->sr); 1331592ef85SReinhard Meyer if (status & (error_flags | MMCI_BIT(OVRE))) 1341592ef85SReinhard Meyer goto io_fail; 1351592ef85SReinhard Meyer } while (!(status & MMCI_BIT(RXRDY))); 1361592ef85SReinhard Meyer 1371592ef85SReinhard Meyer if (status & MMCI_BIT(RXRDY)) { 1381592ef85SReinhard Meyer *data = readl(&mci->rdr); 1391592ef85SReinhard Meyer status = 0; 1401592ef85SReinhard Meyer } 1411592ef85SReinhard Meyer io_fail: 1421592ef85SReinhard Meyer return status; 1431592ef85SReinhard Meyer } 1441592ef85SReinhard Meyer 1451592ef85SReinhard Meyer /* Entered into function pointer in mci_send_cmd */ 1461592ef85SReinhard Meyer static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags) 1471592ef85SReinhard Meyer { 1481592ef85SReinhard Meyer u32 status; 1491592ef85SReinhard Meyer 1501592ef85SReinhard Meyer do { 1511592ef85SReinhard Meyer status = readl(&mci->sr); 1521592ef85SReinhard Meyer if (status & (error_flags | MMCI_BIT(UNRE))) 1531592ef85SReinhard Meyer goto io_fail; 1541592ef85SReinhard Meyer } while (!(status & MMCI_BIT(TXRDY))); 1551592ef85SReinhard Meyer 1561592ef85SReinhard Meyer if (status & MMCI_BIT(TXRDY)) { 1571592ef85SReinhard Meyer writel(*data, &mci->tdr); 1581592ef85SReinhard Meyer status = 0; 1591592ef85SReinhard Meyer } 1601592ef85SReinhard Meyer io_fail: 1611592ef85SReinhard Meyer return status; 1621592ef85SReinhard Meyer } 1631592ef85SReinhard Meyer 1641592ef85SReinhard Meyer /* 1651592ef85SReinhard Meyer * Entered into mmc structure during driver init 1661592ef85SReinhard Meyer * 1671592ef85SReinhard Meyer * Sends a command out on the bus and deals with the block data. 1681592ef85SReinhard Meyer * Takes the mmc pointer, a command pointer, and an optional data pointer. 1691592ef85SReinhard Meyer */ 1701592ef85SReinhard Meyer static int 1711592ef85SReinhard Meyer mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 1721592ef85SReinhard Meyer { 1731592ef85SReinhard Meyer atmel_mci_t *mci = (atmel_mci_t *)mmc->priv; 1741592ef85SReinhard Meyer u32 cmdr; 1751592ef85SReinhard Meyer u32 error_flags = 0; 1761592ef85SReinhard Meyer u32 status; 1771592ef85SReinhard Meyer 1781592ef85SReinhard Meyer if (!initialized) { 1791592ef85SReinhard Meyer puts ("MCI not initialized!\n"); 1801592ef85SReinhard Meyer return COMM_ERR; 1811592ef85SReinhard Meyer } 1821592ef85SReinhard Meyer 1831592ef85SReinhard Meyer /* Figure out the transfer arguments */ 1841592ef85SReinhard Meyer cmdr = mci_encode_cmd(cmd, data, &error_flags); 1851592ef85SReinhard Meyer 1861592ef85SReinhard Meyer /* Send the command */ 1871592ef85SReinhard Meyer writel(cmd->cmdarg, &mci->argr); 1881592ef85SReinhard Meyer writel(cmdr, &mci->cmdr); 1891592ef85SReinhard Meyer 1901592ef85SReinhard Meyer #ifdef DEBUG 1911592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG"); 1921592ef85SReinhard Meyer #endif 1931592ef85SReinhard Meyer 1941592ef85SReinhard Meyer /* Wait for the command to complete */ 1951592ef85SReinhard Meyer while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY))); 1961592ef85SReinhard Meyer 1971592ef85SReinhard Meyer if (status & error_flags) { 1981592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed"); 1991592ef85SReinhard Meyer return COMM_ERR; 2001592ef85SReinhard Meyer } 2011592ef85SReinhard Meyer 2021592ef85SReinhard Meyer /* Copy the response to the response buffer */ 2031592ef85SReinhard Meyer if (cmd->resp_type & MMC_RSP_136) { 2041592ef85SReinhard Meyer cmd->response[0] = readl(&mci->rspr); 2051592ef85SReinhard Meyer cmd->response[1] = readl(&mci->rspr1); 2061592ef85SReinhard Meyer cmd->response[2] = readl(&mci->rspr2); 2071592ef85SReinhard Meyer cmd->response[3] = readl(&mci->rspr3); 2081592ef85SReinhard Meyer } else 2091592ef85SReinhard Meyer cmd->response[0] = readl(&mci->rspr); 2101592ef85SReinhard Meyer 2111592ef85SReinhard Meyer /* transfer all of the blocks */ 2121592ef85SReinhard Meyer if (data) { 2131592ef85SReinhard Meyer u32 word_count, block_count; 2141592ef85SReinhard Meyer u32* ioptr; 2151592ef85SReinhard Meyer u32 sys_blocksize, dummy, i; 2161592ef85SReinhard Meyer u32 (*mci_data_op) 2171592ef85SReinhard Meyer (atmel_mci_t *mci, u32* data, u32 error_flags); 2181592ef85SReinhard Meyer 2191592ef85SReinhard Meyer if (data->flags & MMC_DATA_READ) { 2201592ef85SReinhard Meyer mci_data_op = mci_data_read; 2211592ef85SReinhard Meyer sys_blocksize = mmc->read_bl_len; 2221592ef85SReinhard Meyer ioptr = (u32*)data->dest; 2231592ef85SReinhard Meyer } else { 2241592ef85SReinhard Meyer mci_data_op = mci_data_write; 2251592ef85SReinhard Meyer sys_blocksize = mmc->write_bl_len; 2261592ef85SReinhard Meyer ioptr = (u32*)data->src; 2271592ef85SReinhard Meyer } 2281592ef85SReinhard Meyer 2291592ef85SReinhard Meyer status = 0; 2301592ef85SReinhard Meyer for (block_count = 0; 2311592ef85SReinhard Meyer block_count < data->blocks && !status; 2321592ef85SReinhard Meyer block_count++) { 2331592ef85SReinhard Meyer word_count = 0; 2341592ef85SReinhard Meyer do { 2351592ef85SReinhard Meyer status = mci_data_op(mci, ioptr, error_flags); 2361592ef85SReinhard Meyer word_count++; 2371592ef85SReinhard Meyer ioptr++; 2381592ef85SReinhard Meyer } while (!status && word_count < (data->blocksize/4)); 2391592ef85SReinhard Meyer #ifdef DEBUG 2401592ef85SReinhard Meyer if (data->flags & MMC_DATA_READ) 2411592ef85SReinhard Meyer { 2421592ef85SReinhard Meyer printf("Read Data:\n"); 2431592ef85SReinhard Meyer print_buffer(0, data->dest, 1, 2441592ef85SReinhard Meyer word_count*4, 0); 2451592ef85SReinhard Meyer } 2461592ef85SReinhard Meyer #endif 2471592ef85SReinhard Meyer #ifdef DEBUG 2481592ef85SReinhard Meyer if (!status && word_count < (sys_blocksize / 4)) 2491592ef85SReinhard Meyer printf("filling rest of block...\n"); 2501592ef85SReinhard Meyer #endif 2511592ef85SReinhard Meyer /* fill the rest of a full block */ 2521592ef85SReinhard Meyer while (!status && word_count < (sys_blocksize / 4)) { 2531592ef85SReinhard Meyer status = mci_data_op(mci, &dummy, 2541592ef85SReinhard Meyer error_flags); 2551592ef85SReinhard Meyer word_count++; 2561592ef85SReinhard Meyer } 2571592ef85SReinhard Meyer if (status) { 2581592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, 2591592ef85SReinhard Meyer "Data Transfer Failed"); 2601592ef85SReinhard Meyer return COMM_ERR; 2611592ef85SReinhard Meyer } 2621592ef85SReinhard Meyer } 2631592ef85SReinhard Meyer 2641592ef85SReinhard Meyer /* Wait for Transfer End */ 2651592ef85SReinhard Meyer i = 0; 2661592ef85SReinhard Meyer do { 2671592ef85SReinhard Meyer status = readl(&mci->sr); 2681592ef85SReinhard Meyer 2691592ef85SReinhard Meyer if (status & error_flags) { 2701592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, 2711592ef85SReinhard Meyer "DTIP Wait Failed"); 2721592ef85SReinhard Meyer return COMM_ERR; 2731592ef85SReinhard Meyer } 2741592ef85SReinhard Meyer i++; 2751592ef85SReinhard Meyer } while ((status & MMCI_BIT(DTIP)) && i < 10000); 2761592ef85SReinhard Meyer if (status & MMCI_BIT(DTIP)) { 2771592ef85SReinhard Meyer dump_cmd(cmdr, cmd->cmdarg, status, 2781592ef85SReinhard Meyer "XFER DTIP never unset, ignoring"); 2791592ef85SReinhard Meyer } 2801592ef85SReinhard Meyer } 2811592ef85SReinhard Meyer 2821592ef85SReinhard Meyer return 0; 2831592ef85SReinhard Meyer } 2841592ef85SReinhard Meyer 2851592ef85SReinhard Meyer /* Entered into mmc structure during driver init */ 2861592ef85SReinhard Meyer static void mci_set_ios(struct mmc *mmc) 2871592ef85SReinhard Meyer { 2881592ef85SReinhard Meyer atmel_mci_t *mci = (atmel_mci_t *)mmc->priv; 2891592ef85SReinhard Meyer int busw = (mmc->bus_width == 4) ? 1 : 0; 2901592ef85SReinhard Meyer 2911592ef85SReinhard Meyer /* Set the clock speed */ 2921592ef85SReinhard Meyer mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN); 2931592ef85SReinhard Meyer 2941592ef85SReinhard Meyer /* 2951592ef85SReinhard Meyer * set the bus width and select slot for this interface 2961592ef85SReinhard Meyer * there is no capability for multiple slots on the same interface yet 2971592ef85SReinhard Meyer * Bitfield SCDBUS needs to be expanded to 2 bits for 8-bit buses 2981592ef85SReinhard Meyer */ 2991592ef85SReinhard Meyer writel(MMCI_BF(SCDBUS, busw) | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); 3001592ef85SReinhard Meyer } 3011592ef85SReinhard Meyer 3021592ef85SReinhard Meyer /* Entered into mmc structure during driver init */ 3031592ef85SReinhard Meyer static int mci_init(struct mmc *mmc) 3041592ef85SReinhard Meyer { 3051592ef85SReinhard Meyer atmel_mci_t *mci = (atmel_mci_t *)mmc->priv; 3061592ef85SReinhard Meyer 3071592ef85SReinhard Meyer /* Initialize controller */ 3081592ef85SReinhard Meyer writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */ 3091592ef85SReinhard Meyer writel(MMCI_BIT(PWSDIS), &mci->cr); /* disable power save */ 3101592ef85SReinhard Meyer writel(MMCI_BIT(MCIEN), &mci->cr); /* enable mci */ 3112aed9d14SReinhard Meyer writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); /* select port */ 3121592ef85SReinhard Meyer 3131592ef85SReinhard Meyer /* Initial Time-outs */ 3141592ef85SReinhard Meyer writel(0x5f, &mci->dtor); 3151592ef85SReinhard Meyer /* Disable Interrupts */ 3161592ef85SReinhard Meyer writel(~0UL, &mci->idr); 3171592ef85SReinhard Meyer 3181592ef85SReinhard Meyer /* Set default clocks and blocklen */ 3191592ef85SReinhard Meyer mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); 3201592ef85SReinhard Meyer 3211592ef85SReinhard Meyer return 0; 3221592ef85SReinhard Meyer } 3231592ef85SReinhard Meyer 3241592ef85SReinhard Meyer /* 3251592ef85SReinhard Meyer * This is the only exported function 3261592ef85SReinhard Meyer * 3271592ef85SReinhard Meyer * Call it with the MCI register base address 3281592ef85SReinhard Meyer */ 3291592ef85SReinhard Meyer int atmel_mci_init(void *regs) 3301592ef85SReinhard Meyer { 3311592ef85SReinhard Meyer struct mmc *mmc = malloc(sizeof(struct mmc)); 3321592ef85SReinhard Meyer 3331592ef85SReinhard Meyer if (!mmc) 3341592ef85SReinhard Meyer return -1; 3351592ef85SReinhard Meyer strcpy(mmc->name, "mci"); 3361592ef85SReinhard Meyer mmc->priv = regs; 3371592ef85SReinhard Meyer mmc->send_cmd = mci_send_cmd; 3381592ef85SReinhard Meyer mmc->set_ios = mci_set_ios; 3391592ef85SReinhard Meyer mmc->init = mci_init; 3401592ef85SReinhard Meyer 3411592ef85SReinhard Meyer /* need to be able to pass these in on a board by board basis */ 3421592ef85SReinhard Meyer mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 3431592ef85SReinhard Meyer mmc->host_caps = MMC_MODE_4BIT; 3441592ef85SReinhard Meyer /* 3451592ef85SReinhard Meyer * min and max frequencies determined by 3461592ef85SReinhard Meyer * max and min of clock divider 3471592ef85SReinhard Meyer */ 3481592ef85SReinhard Meyer mmc->f_min = get_mci_clk_rate() / (2*256); 3491592ef85SReinhard Meyer mmc->f_max = get_mci_clk_rate() / (2*1); 3501592ef85SReinhard Meyer 3518feafcc4SJohn Rigby mmc->b_max = 0; 3528feafcc4SJohn Rigby 3531592ef85SReinhard Meyer mmc_register(mmc); 3541592ef85SReinhard Meyer 3551592ef85SReinhard Meyer return 0; 3561592ef85SReinhard Meyer } 357