diff options
Diffstat (limited to 'drivers/mmc/mxcmmc.c')
-rw-r--r-- | drivers/mmc/mxcmmc.c | 523 |
1 files changed, 0 insertions, 523 deletions
diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c deleted file mode 100644 index 1acea6f820b..00000000000 --- a/drivers/mmc/mxcmmc.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * This is a driver for the SDHC controller found in Freescale MX2/MX3 - * SoCs. It is basically the same hardware as found on MX1 (imxmmc.c). - * Unlike the hardware found on MX1, this hardware just works and does - * not need all the quirks found in imxmmc.c, hence the seperate driver. - * - * Copyright (C) 2009 Ilya Yanok, <yanok@emcraft.com> - * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> - * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> - * - * derived from pxamci.c by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <config.h> -#include <command.h> -#include <mmc.h> -#include <part.h> -#include <malloc.h> -#include <mmc.h> -#include <time.h> -#include <linux/errno.h> -#include <asm/io.h> -#include <asm/arch/clock.h> - -#define DRIVER_NAME "mxc-mmc" - -struct mxcmci_regs { - u32 str_stp_clk; - u32 status; - u32 clk_rate; - u32 cmd_dat_cont; - u32 res_to; - u32 read_to; - u32 blk_len; - u32 nob; - u32 rev_no; - u32 int_cntr; - u32 cmd; - u32 arg; - u32 pad; - u32 res_fifo; - u32 buffer_access; -}; - -#define STR_STP_CLK_RESET (1 << 3) -#define STR_STP_CLK_START_CLK (1 << 1) -#define STR_STP_CLK_STOP_CLK (1 << 0) - -#define STATUS_CARD_INSERTION (1 << 31) -#define STATUS_CARD_REMOVAL (1 << 30) -#define STATUS_YBUF_EMPTY (1 << 29) -#define STATUS_XBUF_EMPTY (1 << 28) -#define STATUS_YBUF_FULL (1 << 27) -#define STATUS_XBUF_FULL (1 << 26) -#define STATUS_BUF_UND_RUN (1 << 25) -#define STATUS_BUF_OVFL (1 << 24) -#define STATUS_SDIO_INT_ACTIVE (1 << 14) -#define STATUS_END_CMD_RESP (1 << 13) -#define STATUS_WRITE_OP_DONE (1 << 12) -#define STATUS_DATA_TRANS_DONE (1 << 11) -#define STATUS_READ_OP_DONE (1 << 11) -#define STATUS_WR_CRC_ERROR_CODE_MASK (3 << 10) -#define STATUS_CARD_BUS_CLK_RUN (1 << 8) -#define STATUS_BUF_READ_RDY (1 << 7) -#define STATUS_BUF_WRITE_RDY (1 << 6) -#define STATUS_RESP_CRC_ERR (1 << 5) -#define STATUS_CRC_READ_ERR (1 << 3) -#define STATUS_CRC_WRITE_ERR (1 << 2) -#define STATUS_TIME_OUT_RESP (1 << 1) -#define STATUS_TIME_OUT_READ (1 << 0) -#define STATUS_ERR_MASK 0x2f - -#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1 << 12) -#define CMD_DAT_CONT_STOP_READWAIT (1 << 11) -#define CMD_DAT_CONT_START_READWAIT (1 << 10) -#define CMD_DAT_CONT_BUS_WIDTH_4 (2 << 8) -#define CMD_DAT_CONT_INIT (1 << 7) -#define CMD_DAT_CONT_WRITE (1 << 4) -#define CMD_DAT_CONT_DATA_ENABLE (1 << 3) -#define CMD_DAT_CONT_RESPONSE_48BIT_CRC (1 << 0) -#define CMD_DAT_CONT_RESPONSE_136BIT (2 << 0) -#define CMD_DAT_CONT_RESPONSE_48BIT (3 << 0) - -#define INT_SDIO_INT_WKP_EN (1 << 18) -#define INT_CARD_INSERTION_WKP_EN (1 << 17) -#define INT_CARD_REMOVAL_WKP_EN (1 << 16) -#define INT_CARD_INSERTION_EN (1 << 15) -#define INT_CARD_REMOVAL_EN (1 << 14) -#define INT_SDIO_IRQ_EN (1 << 13) -#define INT_DAT0_EN (1 << 12) -#define INT_BUF_READ_EN (1 << 4) -#define INT_BUF_WRITE_EN (1 << 3) -#define INT_END_CMD_RES_EN (1 << 2) -#define INT_WRITE_OP_DONE_EN (1 << 1) -#define INT_READ_OP_EN (1 << 0) - -struct mxcmci_host { - struct mmc *mmc; - struct mxcmci_regs *base; - int irq; - int detect_irq; - int dma; - int do_dma; - unsigned int power_mode; - - struct mmc_cmd *cmd; - struct mmc_data *data; - - unsigned int dma_nents; - unsigned int datasize; - unsigned int dma_dir; - - u16 rev_no; - unsigned int cmdat; - - int clock; -}; - -static struct mxcmci_host mxcmci_host; - -/* maintainer note: do we really want to have a global host pointer? */ -static struct mxcmci_host *host = &mxcmci_host; - -static inline int mxcmci_use_dma(struct mxcmci_host *host) -{ - return host->do_dma; -} - -static void mxcmci_softreset(struct mxcmci_host *host) -{ - int i; - - /* reset sequence */ - writel(STR_STP_CLK_RESET, &host->base->str_stp_clk); - writel(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, - &host->base->str_stp_clk); - - for (i = 0; i < 8; i++) - writel(STR_STP_CLK_START_CLK, &host->base->str_stp_clk); - - writel(0xff, &host->base->res_to); -} - -static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned int blksz = data->blocksize; - unsigned int datasize = nob * blksz; - - host->data = data; - - writel(nob, &host->base->nob); - writel(blksz, &host->base->blk_len); - host->datasize = datasize; -} - -static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_cmd *cmd, - unsigned int cmdat) -{ - if (host->cmd != NULL) - printf("mxcmci: error!\n"); - host->cmd = cmd; - - switch (cmd->resp_type) { - case MMC_RSP_R1: /* short CRC, OPCODE */ - case MMC_RSP_R1b:/* short CRC, OPCODE, BUSY */ - cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC; - break; - case MMC_RSP_R2: /* long 136 bit + CRC */ - cmdat |= CMD_DAT_CONT_RESPONSE_136BIT; - break; - case MMC_RSP_R3: /* short */ - cmdat |= CMD_DAT_CONT_RESPONSE_48BIT; - break; - case MMC_RSP_NONE: - break; - default: - printf("mxcmci: unhandled response type 0x%x\n", - cmd->resp_type); - return -EINVAL; - } - - writel(cmd->cmdidx, &host->base->cmd); - writel(cmd->cmdarg, &host->base->arg); - writel(cmdat, &host->base->cmd_dat_cont); - - return 0; -} - -static void mxcmci_finish_request(struct mxcmci_host *host, - struct mmc_cmd *cmd, struct mmc_data *data) -{ - host->cmd = NULL; - host->data = NULL; -} - -static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) -{ - int data_error = 0; - - if (stat & STATUS_ERR_MASK) { - printf("request failed. status: 0x%08x\n", - stat); - if (stat & STATUS_CRC_READ_ERR) { - data_error = -EILSEQ; - } else if (stat & STATUS_CRC_WRITE_ERR) { - u32 err_code = (stat >> 9) & 0x3; - if (err_code == 2) /* No CRC response */ - data_error = -ETIMEDOUT; - else - data_error = -EILSEQ; - } else if (stat & STATUS_TIME_OUT_READ) { - data_error = -ETIMEDOUT; - } else { - data_error = -EIO; - } - } - - host->data = NULL; - - return data_error; -} - -static int mxcmci_read_response(struct mxcmci_host *host, unsigned int stat) -{ - struct mmc_cmd *cmd = host->cmd; - int i; - u32 a, b, c; - u32 *resp = (u32 *)cmd->response; - - if (!cmd) - return 0; - - if (stat & STATUS_TIME_OUT_RESP) { - printf("CMD TIMEOUT\n"); - return -ETIMEDOUT; - } else if (stat & STATUS_RESP_CRC_ERR && cmd->resp_type & MMC_RSP_CRC) { - printf("cmd crc error\n"); - return -EILSEQ; - } - - if (cmd->resp_type & MMC_RSP_PRESENT) { - if (cmd->resp_type & MMC_RSP_136) { - for (i = 0; i < 4; i++) { - a = readl(&host->base->res_fifo) & 0xFFFF; - b = readl(&host->base->res_fifo) & 0xFFFF; - resp[i] = a << 16 | b; - } - } else { - a = readl(&host->base->res_fifo) & 0xFFFF; - b = readl(&host->base->res_fifo) & 0xFFFF; - c = readl(&host->base->res_fifo) & 0xFFFF; - resp[0] = a << 24 | b << 8 | c >> 8; - } - } - return 0; -} - -static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask) -{ - u32 stat; - unsigned long timeout = get_ticks() + CONFIG_SYS_HZ; - - do { - stat = readl(&host->base->status); - if (stat & STATUS_ERR_MASK) - return stat; - if (timeout < get_ticks()) - return STATUS_TIME_OUT_READ; - if (stat & mask) - return 0; - } while (1); -} - -static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) -{ - unsigned int stat; - u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, - STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); - if (stat) - return stat; - *buf++ = readl(&host->base->buffer_access); - bytes -= 4; - } - - if (bytes) { - u8 *b = (u8 *)buf; - u32 tmp; - - stat = mxcmci_poll_status(host, - STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); - if (stat) - return stat; - tmp = readl(&host->base->buffer_access); - memcpy(b, &tmp, bytes); - } - - return 0; -} - -static int mxcmci_push(struct mxcmci_host *host, const void *_buf, int bytes) -{ - unsigned int stat; - const u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - writel(*buf++, &host->base->buffer_access); - bytes -= 4; - } - - if (bytes) { - const u8 *b = (u8 *)buf; - u32 tmp; - - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - - memcpy(&tmp, b, bytes); - writel(tmp, &host->base->buffer_access); - } - - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - - return 0; -} - -static int mxcmci_transfer_data(struct mxcmci_host *host) -{ - struct mmc_data *data = host->data; - int stat; - unsigned long length; - - length = data->blocks * data->blocksize; - host->datasize = 0; - - if (data->flags & MMC_DATA_READ) { - stat = mxcmci_pull(host, data->dest, length); - if (stat) - return stat; - host->datasize += length; - } else { - stat = mxcmci_push(host, (const void *)(data->src), length); - if (stat) - return stat; - host->datasize += length; - stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE); - if (stat) - return stat; - } - return 0; -} - -static int mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) -{ - int datastat; - int ret; - - ret = mxcmci_read_response(host, stat); - - if (ret) { - mxcmci_finish_request(host, host->cmd, host->data); - return ret; - } - - if (!host->data) { - mxcmci_finish_request(host, host->cmd, host->data); - return 0; - } - - datastat = mxcmci_transfer_data(host); - ret = mxcmci_finish_data(host, datastat); - mxcmci_finish_request(host, host->cmd, host->data); - return ret; -} - -static int mxcmci_request(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - struct mxcmci_host *host = mmc->priv; - unsigned int cmdat = host->cmdat; - u32 stat; - int ret; - - host->cmdat &= ~CMD_DAT_CONT_INIT; - if (data) { - mxcmci_setup_data(host, data); - - cmdat |= CMD_DAT_CONT_DATA_ENABLE; - - if (data->flags & MMC_DATA_WRITE) - cmdat |= CMD_DAT_CONT_WRITE; - } - - if ((ret = mxcmci_start_cmd(host, cmd, cmdat))) { - mxcmci_finish_request(host, cmd, data); - return ret; - } - - do { - stat = readl(&host->base->status); - writel(stat, &host->base->status); - } while (!(stat & STATUS_END_CMD_RESP)); - - return mxcmci_cmd_done(host, stat); -} - -static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) -{ - unsigned int divider; - int prescaler = 0; - unsigned long clk_in = mxc_get_clock(MXC_ESDHC_CLK); - - while (prescaler <= 0x800) { - for (divider = 1; divider <= 0xF; divider++) { - int x; - - x = (clk_in / (divider + 1)); - - if (prescaler) - x /= (prescaler * 2); - - if (x <= clk_ios) - break; - } - if (divider < 0x10) - break; - - if (prescaler == 0) - prescaler = 1; - else - prescaler <<= 1; - } - - writel((prescaler << 4) | divider, &host->base->clk_rate); -} - -static int mxcmci_set_ios(struct mmc *mmc) -{ - struct mxcmci_host *host = mmc->priv; - if (mmc->bus_width == 4) - host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; - else - host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; - - if (mmc->clock) { - mxcmci_set_clk_rate(host, mmc->clock); - writel(STR_STP_CLK_START_CLK, &host->base->str_stp_clk); - } else { - writel(STR_STP_CLK_STOP_CLK, &host->base->str_stp_clk); - } - - host->clock = mmc->clock; - - return 0; -} - -static int mxcmci_init(struct mmc *mmc) -{ - struct mxcmci_host *host = mmc->priv; - - mxcmci_softreset(host); - - host->rev_no = readl(&host->base->rev_no); - if (host->rev_no != 0x400) { - printf("wrong rev.no. 0x%08x. aborting.\n", - host->rev_no); - return -ENODEV; - } - - /* recommended in data sheet */ - writel(0x2db4, &host->base->read_to); - - writel(0, &host->base->int_cntr); - - return 0; -} - -static const struct mmc_ops mxcmci_ops = { - .send_cmd = mxcmci_request, - .set_ios = mxcmci_set_ios, - .init = mxcmci_init, -}; - -static struct mmc_config mxcmci_cfg = { - .name = "MXC MCI", - .ops = &mxcmci_ops, - .host_caps = MMC_MODE_4BIT, - .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, - .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, -}; - -static int mxcmci_initialize(struct bd_info *bis) -{ - host->base = (struct mxcmci_regs *)CONFIG_MXC_MCI_REGS_BASE; - - mxcmci_cfg.f_min = mxc_get_clock(MXC_ESDHC_CLK) >> 7; - mxcmci_cfg.f_max = mxc_get_clock(MXC_ESDHC_CLK) >> 1; - - host->mmc = mmc_create(&mxcmci_cfg, host); - if (host->mmc == NULL) - return -1; - - return 0; -} - -int mxc_mmc_init(struct bd_info *bis) -{ - return mxcmci_initialize(bis); -} |