Bernard Blackham wrote:
> This is actually a forward port of the SD/MMC driver from the latest
> LSP, melded into linux-2.6.23-git. I've tried to keep the style
> updates that were merged recently. I fixed the exit code (in
> davinci_mmcsd_exit) to release clocks, and some failure paths in
> davinci_mmcsd_init.
>
> This is probably not quite what David and Dirk were wanting, as it's
> probably further from being merged upstream than previously.
> However, it works for me (have tried reading/writing an SD card
> successfully, reading at about ~6MB/s and writing at ~1MB/s). It
> hasn't been put under particularly strenuous testing either, so
> beware.
At this point, I'm willing to take something that works, but needs
rework/cleanup as it's better than what is there today.
Also, there's a whole new MMC/SD/SDIO framework headed for mailine, so
it will probably need some rework for that as well. But with a couple
minor cleanups as mentioned below, I'll merge it.
Please add a Signed-off-by: line as well.
>
> davinci_mmc.c | 748
> ++++++++++++++++++++++++++++++++++++++--------------------
> davinci_mmc.h | 23 +
> 2 files changed, 520 insertions(+), 251 deletions(-)
>
> diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
> index 5d8e79f..3a635d0 100644
> --- a/drivers/mmc/host/davinci_mmc.c
> +++ b/drivers/mmc/host/davinci_mmc.c
> @@ -24,13 +24,17 @@
> Modifications:
> ver. 1.0: Oct 2005, Purushotam Kumar Initial version
> ver 1.1: Nov 2005, Purushotam Kumar Solved bugs
> - ver 1.2: Jan 2066, Purushotam Kumar Added card remove insert support
> + ver 1.2: Jan 2006, Purushotam Kumar Added card remove insert support
What, you don't think he could've done this update in the future? ;)
> -
> */
>
> #include <linux/module.h>
> +#include <linux/version.h>
> +/* DEBUG check shall be made before kernel.h or device.h is included */
> +#ifdef CONFIG_MMC_DEBUG
> +#define DEBUG
> +#endif
You don't need this, as the equivalent is already done by the Makefile.
> #include <linux/tty.h>
> #include <linux/ioport.h>
> #include <linux/init.h>
> @@ -41,35 +45,25 @@ #include <linux/clk.h>
> #include <linux/mmc/host.h>
> #include <linux/mmc/card.h>
> #include <linux/mmc/mmc.h>
> -
> #include <asm/io.h>
> #include <asm/irq.h>
> #include <asm/hardware.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> #include <asm/arch/irqs.h>
> #include <asm/arch/hardware.h>
>
> #include "davinci_mmc.h"
> #include <asm/arch/edma.h>
>
> -/* FIXME: old defines from old mmc.h */
> -/* #define MMC_RSP_NONE (0 << 0) */
> -/* #define MMC_RSP_SHORT (1 << 0) */
> -/* #define MMC_RSP_LONG (2 << 0) */
> -/* #define MMC_RSP_MASK (3 << 0) */
> -/* #define MMC_RSP_CRC (1 << 3) /\* expect valid crc
> *\/ */
> -/* #define MMC_RSP_BUSY (1 << 4) /\* card may send busy
> *\/ */
> -#define MMC_RSP_SHORT MMC_RSP_PRESENT
> -#define MMC_RSP_LONG MMC_RSP_136
> -#define MMC_RSP_MASK (MMC_RSP_PRESENT | MMC_RSP_136)
> -
> extern void davinci_clean_channel(int ch_no);
>
> /* MMCSD Init clock in Hz in opendain mode */
> -#define MMCSD_INIT_CLOCK 200000
> -#define DRIVER_NAME "mmc0"
> -#define MMCINT_INTERRUPT IRQ_MMCINT
> -#define MMCSD_REGS_BASE_ADDR DAVINCI_MMC_SD_BASE
> -#define TCINTEN (0x1<<20)
> +#define MMCSD_INIT_CLOCK 200000
> +#define DRIVER_NAME "mmc0"
> +#define MMCINT_INTERRUPT IRQ_MMCINT
> +#define MMCSD_REGS_BASE_ADDR DAVINCI_MMC_SD_BASE
> +#define TCINTEN (0x1<<20)
>
> /* This macro could not be defined to 0 (ZERO) or -ve value.
> * This value is multiplied to "HZ"
> @@ -83,6 +77,8 @@ mmcsd_config_def mmcsd_cfg = {
> /* read write thresholds (in bytes) can be any power of 2 from 2 to 64 */
> 32,
> /* To use the DMA or not-- 1- Use DMA, 0-Interrupt mode */
> + 1,
> +/* flag Indicates 1bit/4bit mode */
> 1
> };
>
> @@ -107,54 +103,71 @@ static struct mmc_request *que_mmc_reque
> /* tells whether card is initizlzed or not */
> static unsigned int is_card_initialized = 0;
> static unsigned int new_card_state = 0; /* tells current state of card
> */
> +static unsigned int is_card_removed = 0;
>
> static DEFINE_SPINLOCK(mmc_lock);
>
> +#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
> +#define MMCST1_BUSY (1 << 0)
> +
> +static inline void wait_on_data(void)
> +{
> + int cnt = 900000;
> + while (((mmcsd_regs->mmc_st1) & MMCST1_BUSY) && cnt) {
> + cnt--;
> + udelay(1);
> + }
> + if (!cnt) {
> + dev_warn(&mmc_dev, "ERROR: TOUT waiting for BUSY\n");
> + }
> +}
> +
> static void mmc_davinci_start_command(struct mmc_davinci_host *host,
> struct mmc_command *cmd)
> {
> u32 cmd_reg = 0;
> u32 resp_type = 0;
> u32 cmd_type = 0;
> - int byte_cnt = 0, i = 0;
> unsigned long flags;
>
> +#ifdef CONFIG_MMC_DEBUG
> dev_dbg(&mmc_dev, "\nMMCSD : CMD%d, argument 0x%08x",
> cmd->opcode, cmd->arg);
> - if (cmd->flags & MMC_RSP_SHORT)
> - dev_dbg(&mmc_dev, ", 32-bit response");
> - if (cmd->flags & MMC_RSP_LONG)
> - dev_dbg(&mmc_dev, ", 128-bit response");
> - if (cmd->flags & MMC_RSP_CRC)
> - dev_dbg(&mmc_dev, ", CRC");
> - if (cmd->flags & MMC_RSP_BUSY)
> - dev_dbg(&mmc_dev, ", busy notification");
> - else
> - dev_dbg(&mmc_dev, ", No busy notification");
> + switch (RSP_TYPE(mmc_resp_type(cmd))) {
> + case RSP_TYPE(MMC_RSP_R1):
> + dev_dbg(&mmc_dev, ", R1/R1b response");
> + break;
> + case RSP_TYPE(MMC_RSP_R2):
> + dev_dbg(&mmc_dev, ", R2 response");
> + break;
> + case RSP_TYPE(MMC_RSP_R3):
> + dev_dbg(&mmc_dev, ", R3 response");
> + break;
> + default:
> + break;
> + }
> dev_dbg(&mmc_dev, "\n");
> +#endif
> host->cmd = cmd;
>
> /* Protocol layer does not provide response type,
> * but our hardware needs to know exact type, not just size!
> */
> - switch (cmd->flags & MMC_RSP_MASK) {
> + switch (RSP_TYPE(mmc_resp_type(cmd))) {
> case MMC_RSP_NONE:
> /* resp 0 */
> break;
> - case MMC_RSP_SHORT:
> - /* resp 1, resp 1b */
> - /* OR resp 3!! (assume this if bus is set opendrain) */
> - if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) {
> - resp_type = 3;
> - if (cmd->opcode == 3)
> - resp_type = 1;
> - } else
> - resp_type = 1;
> + case RSP_TYPE(MMC_RSP_R1):
> + resp_type = 1;
> break;
> - case MMC_RSP_LONG:
> - /* resp 2 */
> + case RSP_TYPE(MMC_RSP_R2):
> resp_type = 2;
> break;
> + case RSP_TYPE(MMC_RSP_R3):
> + resp_type = 3;
> + break;
> + default:
> + break;
> }
>
> /* Protocol layer does not provide command type, but our hardware
> @@ -171,11 +184,11 @@ static void mmc_davinci_start_command(st
> * rest are ac, except if opendrain
> */
>
> - if (host->data_dir)
> + if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
> cmd_type = DAVINCI_MMC_CMDTYPE_ADTC;
> - else if (resp_type == 0 && cmd->opcode != 15)
> + else if (mmc_cmd_type(cmd) == MMC_CMD_BC)
> cmd_type = DAVINCI_MMC_CMDTYPE_BC;
> - else if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
> + else if (mmc_cmd_type(cmd) == MMC_CMD_BCR)
> cmd_type = DAVINCI_MMC_CMDTYPE_BCR;
> else
> cmd_type = DAVINCI_MMC_CMDTYPE_AC;
> @@ -198,10 +211,9 @@ static void mmc_davinci_start_command(st
> cmd_reg = cmd_reg | (1 << 14);
>
> /* Set for generating DMA Xfer event */
> - if ((host->use_dma == 1) && (host->data != NULL)
> - && ((cmd->opcode == 18) || (cmd->opcode == 25)
> - || (cmd->opcode == 24)
> - || (cmd->opcode == 17)))
> + if ((host->do_dma == 1) && (host->data != NULL)
> + && ((cmd->opcode == 18) || (cmd->opcode == 25)
> + || (cmd->opcode == 24) || (cmd->opcode == 17)))
> cmd_reg = cmd_reg | (1 << 16);
>
> /* Setting whether command involves data transfer or not */
> @@ -227,7 +239,7 @@ static void mmc_davinci_start_command(st
>
> /* Enable interrupt */
> if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
> - if (host->use_dma != 1)
> + if (host->do_dma != 1)
> mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
> | MMCSD_EVENT_WRITE
> | MMCSD_EVENT_ERROR_CMDCRC
> @@ -243,7 +255,7 @@ static void mmc_davinci_start_command(st
> | MMCSD_EVENT_ERROR_DATATIMEOUT
> | MMCSD_EVENT_BLOCK_XFERRED;
> } else if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
> - if (host->use_dma != 1)
> + if (host->do_dma != 1)
> mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
> | MMCSD_EVENT_READ
> | MMCSD_EVENT_ERROR_CMDCRC
> @@ -271,25 +283,22 @@ static void mmc_davinci_start_command(st
> */
> if ((host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
> && (cmd_type == DAVINCI_MMC_CMDTYPE_ADTC)
> - && (host->use_dma != 1)) {
> - byte_cnt = mmcsd_cfg.rw_threshold;
> - host->bytes_left -= mmcsd_cfg.rw_threshold;
> - for (i = 0; i < (byte_cnt / 4); i++) {
> - mmcsd_regs->mmc_dxr = *host->buffer;
> - host->buffer++;
> - }
> - }
> + && (host->do_dma != 1))
> + /* Fill the FIFO for Tx */
> + davinci_fifo_data_trans(host);
>
> if (cmd->opcode == 7) {
> spin_lock_irqsave(&mmc_lock, flags);
> + is_card_removed = 0;
> new_card_state = 1;
> is_card_initialized = 1;
> host->old_card_state = new_card_state;
> is_init_progress = 0;
> spin_unlock_irqrestore(&mmc_lock, flags);
> }
> - if (cmd->opcode == 1) {
> + if (cmd->opcode == 1 || cmd->opcode == 41) {
> spin_lock_irqsave(&mmc_lock, flags);
> + is_card_initialized = 0;
> is_init_progress = 1;
> spin_unlock_irqrestore(&mmc_lock, flags);
> }
> @@ -302,47 +311,178 @@ static void mmc_davinci_start_command(st
>
> static void mmc_davinci_dma_cb(int lch, u16 ch_status, void *data)
> {
> - int sync_dev = 0;
> - struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
> + if (DMA_COMPLETE != ch_status) {
> + struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
> + dev_warn(&mmc_dev, "[DMA FAILED]");
> + davinci_abort_dma(host);
> + }
> +}
>
> - if (DMA_COMPLETE == ch_status) {
> +static void davinci_fifo_data_trans(struct mmc_davinci_host *host)
> +{
> + int n, i;
>
> - if (host->cmd == NULL && host->data == NULL) {
> - if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
> - sync_dev = DAVINCI_DMA_MMCTXEVT;
> - } else {
> - sync_dev = DAVINCI_DMA_MMCRXEVT;
> - }
> - dev_dbg(&mmc_dev,
> - "Interrupt from DMA when no request has been
> made\n");
> - davinci_stop_dma(sync_dev);
> - return;
> - }
> + if (host->buffer_bytes_left == 0) {
> + host->sg_idx++;
> + BUG_ON(host->sg_idx == host->sg_len);
> + mmc_davinci_sg_to_buf(host);
> + }
>
> - if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
> - sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
> - } else {
> - sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
> + n = mmcsd_cfg.rw_threshold;
> + if (n > host->buffer_bytes_left)
> + n = host->buffer_bytes_left;
> + host->buffer_bytes_left -= n;
> + host->bytes_left -= n;
> +
> + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
> + for (i = 0; i < (n / 4); i++) {
> + mmcsd_regs->mmc_dxr = *host->buffer;
> + host->buffer++;
> }
> - davinci_stop_dma(sync_dev);
> } else {
> - /* Handing of Event missed interreupt from DMA */
> - dev_dbg(&mmc_dev,
> - "Event miss interrupt has been generated by DMA\n");
> - if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
> - sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
> - } else {
> - sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
> + for (i = 0; i < (n / 4); i++) {
> + *host->buffer = mmcsd_regs->mmc_drr;
> + host->buffer++;
> }
> - davinci_clean_channel(sync_dev);
> }
> }
>
> +static void davinci_reinit_chan(void)
> +{
> + int sync_dev;
> +
> + sync_dev = DAVINCI_DMA_MMCTXEVT;
> + davinci_stop_dma(sync_dev);
> + davinci_clean_channel(sync_dev);
> +
> + sync_dev = DAVINCI_DMA_MMCRXEVT;
> + davinci_stop_dma(sync_dev);
> + davinci_clean_channel(sync_dev);
> +}
> +
> +static void davinci_abort_dma(struct mmc_davinci_host *host)
> +{
> + int sync_dev = 0;
> +
> + if (host->data_dir == DAVINCI_MMC_DATADIR_READ)
> + sync_dev = DAVINCI_DMA_MMCTXEVT;
> + else
> + sync_dev = DAVINCI_DMA_MMCRXEVT;
> +
> + davinci_stop_dma(sync_dev);
> + davinci_clean_channel(sync_dev);
> +
> +}
> +
> static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
> struct mmc_request *req)
> {
> - const char *dev_name;
> - int sync_dev, r, edma_ch = 0, tcc = 0;
> + int use_dma = 1, i;
> + struct mmc_data *data = host->data;
> + int block_size = data->blksz;
> +
> + host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
> + ((data->flags & MMC_DATA_WRITE)
> + ? DMA_TO_DEVICE
> + : DMA_FROM_DEVICE));
> +
> + /* Decide if we can use DMA */
> + for (i = 0; i < host->sg_len; i++) {
> + if ((data->sg[i].length % block_size) != 0) {
> + use_dma = 0;
> + break;
> + }
> + }
> +
> + if (!use_dma) {
> + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
> + (data->flags & MMC_DATA_WRITE)
> + ? DMA_TO_DEVICE
> + : DMA_FROM_DEVICE);
> + return -1;
> + }
> +
> + host->do_dma = 1;
> +
> + host->dma_state = 0;
> +
> + mmc_davinci_send_dma_request(host, req);
> +
> + return 0;
> +
> +}
> +
> +static int davinci_release_dma_channels(struct mmc_davinci_host *host)
> +{
> + davinci_free_dma(DAVINCI_DMA_MMCTXEVT);
> + davinci_free_dma(DAVINCI_DMA_MMCRXEVT);
> +
> + if (host->edma_ch_details.cnt_chanel) {
> + davinci_free_dma(host->edma_ch_details.chanel_num[0]);
> + host->edma_ch_details.cnt_chanel = 0;
> + }
> +
> + return 0;
> +}
> +
> +static int davinci_acquire_dma_channels(struct mmc_davinci_host *host)
> +{
> + int edma_chan_num, tcc = 0, r, sync_dev;
> + enum dma_event_q queue_no = EVENTQ_0;
> +
> + /* Acquire master DMA write channel */
> + if ((r = davinci_request_dma(DAVINCI_DMA_MMCTXEVT, "MMC_WRITE",
> + mmc_davinci_dma_cb, host, &edma_chan_num, &tcc,
> + queue_no)) != 0) {
> + dev_warn(&mmc_dev,
> + "MMC: davinci_request_dma() failed with %d\n",
> + r);
> + return r;
> + }
> +
> + /* Acquire master DMA read channel */
> + if ((r = davinci_request_dma(DAVINCI_DMA_MMCRXEVT, "MMC_READ",
> + mmc_davinci_dma_cb, host, &edma_chan_num, &tcc,
> + queue_no)) != 0) {
> + dev_warn(&mmc_dev,
> + "MMC: davinci_request_dma() failed with %d\n",
> + r);
> + goto free_master_write;
> + }
> +
> + host->edma_ch_details.cnt_chanel = 0;
> +
> + /* currently data Writes are done using single block mode,
> + * so no DMA slave write channel is required for now */
> +
> + /* Create a DMA slave read channel
> + * (assuming max segments handled is 2) */
> + sync_dev = DAVINCI_DMA_MMCRXEVT;
> + if ((r = davinci_request_dma(DAVINCI_EDMA_PARAM_ANY, "LINK",
> + NULL, NULL, &edma_chan_num, &sync_dev,
> + queue_no)) != 0) {
> + dev_warn(&mmc_dev,
> + "MMC: davinci_request_dma() failed with %d\n", r);
> + goto free_master_read;
> + }
> +
> + host->edma_ch_details.cnt_chanel++;
> + host->edma_ch_details.chanel_num[0] = edma_chan_num;
> +
> + return 0;
> +
> +free_master_read:
> + davinci_free_dma(DAVINCI_DMA_MMCRXEVT);
> +free_master_write:
> + davinci_free_dma(DAVINCI_DMA_MMCTXEVT);
> +
> + return r;
> +}
> +
> +static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
> + struct mmc_request *req)
> +{
> + int sync_dev;
> unsigned char i, j;
> unsigned short acnt, bcnt, ccnt;
> unsigned int src_port, dst_port, temp_ccnt;
> @@ -353,69 +493,50 @@ static int mmc_davinci_start_dma_transfe
> unsigned short bcntrld;
> enum sync_dimension sync_mode;
> edmacc_paramentry_regs temp;
> - enum dma_event_q queue_no = EVENTQ_0;
> int edma_chan_num;
> - unsigned int num_eight_words = (req->data->blocks * 512) / 32;
> static unsigned int option_read = 0;
> static unsigned int option_write = 0;
> - static unsigned char dma_read_req = 1;
> - static unsigned char dma_write_req = 1;
> + struct mmc_data *data = host->data;
> + struct scatterlist *sg = &data->sg[0];
> + unsigned int count;
> + int num_frames, frame;
>
> #define MAX_C_CNT 64000
>
> - if ((req->data->flags & MMC_DATA_WRITE)) {
> - sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
> - dev_name = "MMC_WRITE";
> + frame = data->blksz;
> + count = sg_dma_len(sg);
>
> - if (dma_write_req) {
> - r = davinci_request_dma(sync_dev, dev_name,
> - mmc_davinci_dma_cb, host,
> - &edma_ch, &tcc, queue_no);
> - if (r != 0) {
> - dev_dbg(&mmc_dev,
> - "MMC: davinci_request_dma() failed with
> %d\n",
> -r);
> - return r;
> - }
> - dma_write_req = 0;
> - }
> - } else {
> - sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
> - dev_name = "MMC_READ";
> - if (dma_read_req) {
> - r = davinci_request_dma(sync_dev, dev_name,
> - mmc_davinci_dma_cb, host,
> - &edma_ch, &tcc, queue_no);
> - if (r != 0) {
> - dev_dbg(&mmc_dev,
> - "MMC: davinci_request_dma() failed with
> %d\n",
> - r);
> - return r;
> - }
> - dma_read_req = 0;
> - }
> + if ((data->blocks == 1) && (count > data->blksz)) {
> + count = frame;
> }
>
> - if ((req->data->flags & MMC_DATA_WRITE)) {
> - /* AB Sync Transfer */
> - /* Acnt =32, Bcnt= , Cnt=1 */
> -
> - sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
> + if (count % 32 == 0) {
> acnt = 4;
> bcnt = 8;
> - if (num_eight_words > MAX_C_CNT) {
> - temp_ccnt = MAX_C_CNT;
> - ccnt = temp_ccnt;
> - } else {
> - ccnt = num_eight_words;
> - temp_ccnt = ccnt;
> - }
> + num_frames = count / 32;
> + } else {
> + acnt = count;
> + bcnt = 1;
> + num_frames = 1;
> + }
> +
> + if (num_frames > MAX_C_CNT) {
> + temp_ccnt = MAX_C_CNT;
> + ccnt = temp_ccnt;
> + } else {
> + ccnt = num_frames;
> + temp_ccnt = ccnt;
> + }
> +
> + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
> + /*AB Sync Transfer */
> + sync_dev = DAVINCI_DMA_MMCTXEVT;
>
> - src_port = (unsigned int)virt_to_phys(req->data->mrq->buffer);
> + src_port = (unsigned int)sg_dma_address(sg);
> mode_src = INCR;
> fifo_width_src = W8BIT; /* It's not cared as modeDsr is INCR */
> - src_bidx = 4;
> - src_cidx = 32;
> + src_bidx = acnt;
> + src_cidx = acnt * bcnt;
> dst_port = MMCSD_REGS_BASE_ADDR + 0x2C;
> mode_dst = INCR;
> fifo_width_dst = W8BIT; /* It's not cared as modeDsr is INCR */
> @@ -425,27 +546,18 @@ r);
> sync_mode = ABSYNC;
>
> } else {
> - sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
> - acnt = 4;
> - bcnt = 8;
> - if (num_eight_words > MAX_C_CNT) {
> - temp_ccnt = MAX_C_CNT;
> - ccnt = temp_ccnt;
> - } else {
> - ccnt = num_eight_words;
> - temp_ccnt = ccnt;
> - }
> + sync_dev = DAVINCI_DMA_MMCRXEVT;
>
> src_port = MMCSD_REGS_BASE_ADDR + 0x28;
> mode_src = INCR;
> fifo_width_src = W8BIT;
> src_bidx = 0;
> src_cidx = 0;
> - dst_port = (unsigned int)virt_to_phys(req->data->mrq->buffer);
> + dst_port = (unsigned int)sg_dma_address(sg);
> mode_dst = INCR;
> fifo_width_dst = W8BIT; /* It's not cared as modeDsr is INCR */
> - dst_bidx = 4;
> - dst_cidx = 32;
> + dst_bidx = acnt;
> + dst_cidx = acnt * bcnt;
> bcntrld = 8;
> sync_mode = ABSYNC;
> }
> @@ -459,7 +571,6 @@ r);
> davinci_set_dma_transfer_params(sync_dev, acnt, bcnt, ccnt, bcntrld,
> sync_mode);
>
> - host->edma_ch_details.cnt_chanel = 0;
> davinci_get_dma_params(sync_dev, &temp);
> if (sync_dev == DAVINCI_DMA_MMCTXEVT) {
> if (option_write == 0) {
> @@ -478,12 +589,15 @@ r);
> }
> }
>
> - if (num_eight_words > MAX_C_CNT) { /* Linking will be performed */
> + if (host->sg_len > 1) {
> davinci_get_dma_params(sync_dev, &temp);
> temp.opt &= ~TCINTEN;
> davinci_set_dma_params(sync_dev, &temp);
>
> - for (i = 0; i < EDMA_MAX_LOGICAL_CHA_ALLOWED; i++) {
> + for (i = 0; i < host->sg_len - 1; i++) {
> +
> + sg = &data->sg[i + 1];
> +
> if (i != 0) {
> j = i - 1;
> davinci_get_dma_params(
> @@ -495,30 +609,24 @@ r);
> &temp);
> }
>
> - host->edma_ch_details.cnt_chanel++;
> - davinci_request_dma(DAVINCI_EDMA_PARAM_ANY, "LINK",
> - NULL, NULL, &edma_chan_num,
> - &sync_dev, queue_no);
> - host->edma_ch_details.chanel_num[i] = edma_chan_num;
> - ccnt = temp.ccnt & 0x0000FFFF;
> - if (sync_dev == DAVINCI_DMA_MMCTXEVT) {
> - temp.src = temp.src + (acnt * bcnt * ccnt);
> - } else {
> - temp.dst = temp.dst + (acnt * bcnt * ccnt);
> - }
> + edma_chan_num = host->edma_ch_details.chanel_num[0];
> +
> + frame = data->blksz;
> + count = sg_dma_len(sg);
> +
> + if ((data->blocks == 1) && (count > data->blksz))
> + count = frame;
> +
> + ccnt = count / 32;
> +
> + if (sync_dev == DAVINCI_DMA_MMCTXEVT)
> + temp.src = (unsigned int)sg_dma_address(sg);
> + else
> + temp.dst = (unsigned int)sg_dma_address(sg);
> temp.opt |= TCINTEN;
>
> - if ((num_eight_words - temp_ccnt) > MAX_C_CNT) {
> - temp.ccnt = (temp.ccnt & 0xFFFF0000)
> - | MAX_C_CNT;
> - ccnt = temp.ccnt & 0x0000FFFF;
> - temp_ccnt = temp_ccnt + ccnt;
> - } else {
> - temp.ccnt = (temp.ccnt & 0xFFFF0000)
> - | (num_eight_words -temp_ccnt);
> - ccnt = temp.ccnt & 0x0000FFFF;
> - temp_ccnt = temp_ccnt + ccnt;
> - }
> + temp.ccnt = (temp.ccnt & 0xFFFF0000) | (ccnt);
> +
> davinci_set_dma_params(edma_chan_num, &temp);
> if (i != 0) {
> j = i - 1;
> @@ -526,8 +634,6 @@ r);
> chanel_num[j],
> edma_chan_num);
> }
> - if (temp_ccnt == num_eight_words)
> - break;
> }
> davinci_dma_link_lch(sync_dev,
> host->edma_ch_details.chanel_num[0]);
> @@ -540,8 +646,7 @@ r);
> static void
> mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request
> *req)
> {
> - int timeout;
> -
> + int timeout, sg_len;
> host->data = req->data;
> if (req->data == NULL) {
> host->data_dir = DAVINCI_MMC_DATADIR_NONE;
> @@ -549,6 +654,9 @@ mmc_davinci_prepare_data(struct mmc_davi
> mmcsd_regs->mmc_nblk = 0;
> return;
> }
> + /* Init idx */
> + host->sg_idx = 0;
> +
> dev_dbg(&mmc_dev,
> "MMCSD : Data xfer (%s %s), "
> "DTO %d cycles + %d ns, %d blocks of %d bytes\r\n",
> @@ -589,15 +697,33 @@ mmc_davinci_prepare_data(struct mmc_davi
> break;
> }
>
> - if ((host->use_dma == 1)
> - && (mmc_davinci_start_dma_transfer(host, req) == 0)) {
> + sg_len = (req->data->blocks == 1) ? 1 : req->data->sg_len;
> + host->sg_len = sg_len;
> +
> + host->bytes_left = req->data->blocks * req->data->blksz;
> +
> + if ((host->use_dma == 1) && (host->bytes_left % 32 == 0)
> + && (mmc_davinci_start_dma_transfer(host, req) == 0)) {
> host->buffer = NULL;
> host->bytes_left = 0;
> } else {
> /* Revert to CPU Copy */
> - host->buffer = (u32 *) (req->data->mrq->buffer);
> - host->bytes_left = req->data->blocks * req->data->blksz;
> - host->use_dma = 0;
> +
> + host->do_dma = 0;
> + mmc_davinci_sg_to_buf(host);
> + }
> +}
> +
> +/* PIO only */
> +static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
> +{
> + struct scatterlist *sg;
> +
> + sg = host->data->sg + host->sg_idx;
> + host->buffer_bytes_left = sg->length;
> + host->buffer = page_address(sg->page) + sg->offset;
> + if (host->buffer_bytes_left > host->bytes_left) {
> + host->buffer_bytes_left = host->bytes_left;
> }
> }
>
> @@ -606,14 +732,27 @@ static void mmc_davinci_request(struct m
> struct mmc_davinci_host *host = mmc_priv(mmc);
> unsigned long flags;
>
> + if (is_card_removed) {
> + if (req->cmd) {
> + req->cmd->error |= MMC_ERR_TIMEOUT;
> + mmc_request_done(mmc, req);
> + }
> + dev_dbg(&mmc_dev,
> + "From code segment excuted when card removed\n");
> + return;
> + }
> +
> + wait_on_data();
> +
> if (!is_card_detect_progress) {
> spin_lock_irqsave(&mmc_lock, flags);
> is_card_busy = 1;
> spin_unlock_irqrestore(&mmc_lock, flags);
> + host->do_dma = 0;
> mmc_davinci_prepare_data(host, req);
> mmc_davinci_start_command(host, req->cmd);
> } else {
> - /* Queu up the request as card dectection is being excuted */
> + /* Queue up the request as card dectection is being excuted */
> que_mmc_host = mmc;
> que_mmc_request = req;
> spin_lock_irqsave(&mmc_lock, flags);
> @@ -652,6 +791,13 @@ static void mmc_davinci_set_ios(struct m
> dev_dbg(&mmc_dev, "clock %dHz busmode %d powermode %d Vdd %d.%02d\r\n",
> ios->clock, ios->bus_mode, ios->power_mode,
> ios->vdd / 100, ios->vdd % 100);
> + if (ios->bus_width == MMC_BUS_WIDTH_4) {
> + dev_dbg(&mmc_dev, "\nEnabling 4 bit mode\n");
> + mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | (1 << 2);
> + } else {
> + dev_dbg(&mmc_dev, "Disabling 4 bit mode\n");
> + mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(1 << 2);
> + }
>
> if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
> open_drain_freq = ((unsigned int)cpu_arm_clk
> @@ -660,8 +806,12 @@ static void mmc_davinci_set_ios(struct m
> | open_drain_freq;
> } else {
> mmc_push_pull_freq = calculate_freq_for_card(ios->clock);
> + mmcsd_regs->mmc_clk &= ~(0x100);
> + udelay(10);
> mmcsd_regs->mmc_clk = (mmcsd_regs->mmc_clk & ~(0xFF))
> | mmc_push_pull_freq;
> + mmcsd_regs->mmc_clk |= 0x100;
> + udelay(10);
> }
> host->bus_mode = ios->bus_mode;
> if (ios->power_mode == MMC_POWER_UP) {
> @@ -685,6 +835,15 @@ mmc_davinci_xfer_done(struct mmc_davinci
> if (data->error == MMC_ERR_NONE)
> data->bytes_xfered += data->blocks * data->blksz;
>
> + if (host->do_dma) {
> + davinci_abort_dma(host);
> +
> + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
> + (data->
> + flags & MMC_DATA_WRITE) ? DMA_TO_DEVICE :
> + DMA_FROM_DEVICE);
> + }
> +
> if (data->error == MMC_ERR_TIMEOUT) {
> spin_lock_irqsave(&mmc_lock, flags);
> is_card_busy = 0;
> @@ -708,25 +867,24 @@ static void mmc_davinci_cmd_done(struct
> struct mmc_command *cmd)
> {
> unsigned long flags;
> -
> host->cmd = NULL;
> - switch (cmd->flags & MMC_RSP_MASK) {
> - case MMC_RSP_NONE:
> - /* resp 0 */
> - break;
>
> - case MMC_RSP_SHORT:
> - /* response types 1, 1b, 3, 4, 5, 6 */
> - cmd->resp[0] = mmcsd_regs->mmc_rsp67;
> - break;
> + if (!cmd) {
> + dev_warn(&mmc_dev, "%s(): No cmd ptr\n", __FUNCTION__);
> + return;
> + }
>
> - case MMC_RSP_LONG:
> - /* response type 2 */
> - cmd->resp[3] = mmcsd_regs->mmc_rsp01;
> - cmd->resp[2] = mmcsd_regs->mmc_rsp23;
> - cmd->resp[1] = mmcsd_regs->mmc_rsp45;
> - cmd->resp[0] = mmcsd_regs->mmc_rsp67;
> - break;
> + if (cmd->flags & MMC_RSP_PRESENT) {
> + if (cmd->flags & MMC_RSP_136) {
> + /* response type 2 */
> + cmd->resp[3] = mmcsd_regs->mmc_rsp01;
> + cmd->resp[2] = mmcsd_regs->mmc_rsp23;
> + cmd->resp[1] = mmcsd_regs->mmc_rsp45;
> + cmd->resp[0] = mmcsd_regs->mmc_rsp67;
> + } else {
> + /* response types 1, 1b, 3, 4, 5, 6 */
> + cmd->resp[0] = mmcsd_regs->mmc_rsp67;
> + }
> }
>
> if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
> @@ -746,7 +904,6 @@ static irqreturn_t mmc_davinci_irq(int i
> u16 status;
> int end_command;
> int end_transfer;
> - int byte_cnt = 0, i = 0;
> unsigned long flags;
>
> if (host->is_core_command) {
> @@ -783,44 +940,36 @@ static irqreturn_t mmc_davinci_irq(int i
> if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
> if (status & MMCSD_EVENT_WRITE) {
> /* Buffer almost empty */
> - if (host->bytes_left > 0) {
> - byte_cnt =
> - mmcsd_cfg.rw_threshold;
> - host->bytes_left -=
> - mmcsd_cfg.rw_threshold;
> - for (i = 0; i < (byte_cnt / 4);
> - i++) {
> - mmcsd_regs->mmc_dxr =
> - *host->buffer;
> - host->buffer++;
> - }
> - }
> + if (host->bytes_left > 0)
> + davinci_fifo_data_trans(host);
> }
> }
>
> if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
> if (status & MMCSD_EVENT_READ) {
> /* Buffer almost empty */
> - if (host->bytes_left > 0) {
> - byte_cnt =
> - mmcsd_cfg.rw_threshold;
> - host->bytes_left -=
> - mmcsd_cfg.rw_threshold;
> - for (i = 0; i < (byte_cnt / 4);
> - i++) {
> - *host->buffer =
> - mmcsd_regs->
> - mmc_drr;
> - host->buffer++;
> - }
> - }
> + if (host->bytes_left > 0)
> + davinci_fifo_data_trans(host);
> }
> }
>
> if (status & MMCSD_EVENT_BLOCK_XFERRED) {
> /* Block sent/received */
> if (host->data != NULL) {
> - end_transfer = 1;
> +
> + if (host->do_dma == 1) {
> + end_transfer = 1;
> + } else {
> + /* if datasize<32 no RX ints
> are generated */
> + if (host->bytes_left > 0) {
> + davinci_fifo_data_trans
> + (host);
> + }
> + end_transfer = 1;
> + }
> + } else {
> + dev_warn(&mmc_dev,
> + "TC:host->data is NULL\n");
> }
> }
>
> @@ -829,6 +978,7 @@ static irqreturn_t mmc_davinci_irq(int i
> if ((host->data) && (new_card_state != 0)) {
> host->data->error |= MMC_ERR_TIMEOUT;
> spin_lock_irqsave(&mmc_lock, flags);
> + is_card_removed = 1;
> new_card_state = 0;
> is_card_initialized = 0;
> spin_unlock_irqrestore(&mmc_lock,
> @@ -836,15 +986,23 @@ static irqreturn_t mmc_davinci_irq(int i
> dev_dbg(&mmc_dev,
> "MMCSD: Data timeout, CMD%d and
> status is %x\r\n",
> host->cmd->opcode, status);
> +
> + if (host->cmd) {
> + host->cmd->error |=
> + MMC_ERR_TIMEOUT;
> + }
> end_transfer = 1;
> - host->cmd->error |= MMC_ERR_TIMEOUT;
> }
> - dev_dbg(&mmc_dev,
> - "MMCSD: Data timeout, CMD%d and status
> is %x\r\n",
> - host->cmd->opcode, status);
> }
>
> if (status & MMCSD_EVENT_ERROR_DATACRC) {
> + /* DAT line portion is diabled and in reset
> state */
> + mmcsd_regs->mmc_ctl =
> + mmcsd_regs->mmc_ctl | (1 << 1);
> + udelay(10);
> + mmcsd_regs->mmc_ctl =
> + mmcsd_regs->mmc_ctl & ~(1 << 1);
> +
> /* Data CRC error */
> if (host->data) {
> host->data->error |= MMC_ERR_BADCRC;
> @@ -859,6 +1017,10 @@ static irqreturn_t mmc_davinci_irq(int i
> }
>
> if (status & MMCSD_EVENT_ERROR_CMDTIMEOUT) {
> + if (host->do_dma)
> + /* abort DMA transfer */
> + davinci_abort_dma(host);
> +
> /* Command timeout */
> if (host->cmd) {
> /* Timeouts are normal in case of
> @@ -888,7 +1050,11 @@ static irqreturn_t mmc_davinci_irq(int i
> /* Command CRC error */
> dev_dbg(&mmc_dev, "Command CRC error\r\n");
> if (host->cmd) {
> - host->cmd->error |= MMC_ERR_BADCRC;
> + /* Ignore CMD CRC errors during high
> speed operation */
> + if (host->mmc->ios.clock <= 25000000) {
> + host->cmd->error |=
> + MMC_ERR_BADCRC;
> + }
> end_command = 1;
> }
> }
> @@ -926,6 +1092,7 @@ static irqreturn_t mmc_davinci_irq(int i
>
> } else {
> spin_lock_irqsave(&mmc_lock, flags);
> + is_card_removed = 1;
> new_card_state = 0;
> is_card_initialized = 0;
> spin_unlock_irqrestore(&mmc_lock, flags);
> @@ -945,15 +1112,17 @@ static irqreturn_t mmc_davinci_irq(int i
>
> }
>
> - if (host->cmd_code == 1) {
> + if (host->cmd_code == 1 || host->cmd_code == 55) {
> if (status & MMCSD_EVENT_EOFCMD) {
> spin_lock_irqsave(&mmc_lock, flags);
> + is_card_removed = 0;
> new_card_state = 1;
> is_card_initialized = 0;
> spin_unlock_irqrestore(&mmc_lock, flags);
> } else {
>
> spin_lock_irqsave(&mmc_lock, flags);
> + is_card_removed = 1;
> new_card_state = 0;
> is_card_initialized = 0;
> spin_unlock_irqrestore(&mmc_lock, flags);
> @@ -970,19 +1139,31 @@ static irqreturn_t mmc_davinci_irq(int i
> is_req_queued_up = 0;
> spin_unlock_irqrestore(&mmc_lock, flags);
> }
> -
> }
>
> if (host->cmd_code == 0) {
> if (status & MMCSD_EVENT_EOFCMD) {
> + static int flag_sd_mmc;
> host->is_core_command = 0;
> - host->cmd_code = 1;
> - dev_dbg(&mmc_dev,
> - "MMC-Probing mmc with cmd1\n");
> - /* Issue cmd1 */
> - mmcsd_regs->mmc_arghl = 0x80300000;
> - mmcsd_regs->mmc_cmd = 0x00000601;
>
> + if (flag_sd_mmc) {
> + flag_sd_mmc = 0;
> + host->cmd_code = 1;
> + /* Issue cmd1 */
> + mmcsd_regs->mmc_arghl = 0x80300000;
> + mmcsd_regs->mmc_cmd = 0x00000601;
> + } else {
> + flag_sd_mmc = 1;
> + host->cmd_code = 55;
> + /* Issue cmd55 */
> + mmcsd_regs->mmc_arghl = 0x0;
> + mmcsd_regs->mmc_cmd =
> + ((0x0 | (1 << 9) | 55));
> + }
> +
> + dev_dbg(&mmc_dev,
> + "MMC-Probing mmc with cmd%d\n",
> + host->cmd_code);
> } else {
> spin_lock_irqsave(&mmc_lock, flags);
> new_card_state = 0;
> @@ -999,12 +1180,22 @@ static irqreturn_t mmc_davinci_irq(int i
> static struct mmc_host_ops mmc_davinci_ops = {
> .request = mmc_davinci_request,
> .set_ios = mmc_davinci_set_ios,
> + .get_ro = mmc_davinci_get_ro
> };
>
> +static int mmc_davinci_get_ro(struct mmc_host *mmc)
> +{
> + return 0;
> +}
> +
> void mmc_check_card(unsigned long data)
> {
> struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
> unsigned long flags;
> + struct mmc_card *card = NULL;
> +
> + if (host->mmc && host->mmc->card)
> + card = host->mmc->card;
>
> if ((!is_card_detect_progress) || (!is_init_progress)) {
> if (is_card_initialized) {
> @@ -1014,7 +1205,9 @@ void mmc_check_card(unsigned long data)
> is_card_detect_progress = 1;
> spin_unlock_irqrestore(&mmc_lock, flags);
> /* Issue cmd13 */
> - mmcsd_regs->mmc_arghl = 0x10000;
> + mmcsd_regs->mmc_arghl = (card
> + && mmc_card_sd(card))
> + ? (card->rca << 16) : 0x10000;
> mmcsd_regs->mmc_cmd = 0x0000028D;
> } else {
> host->is_core_command = 0;
> @@ -1041,6 +1234,8 @@ static void davinci_mmc_check_status(uns
>
> if (!is_card_busy) {
> if (host->old_card_state ^ new_card_state) {
> + davinci_reinit_chan();
> + init_mmcsd_host();
> mmc_detect_change(host->mmc, 0);
> spin_lock_irqsave(&mmc_lock, flags);
> host->old_card_state = new_card_state;
> @@ -1057,6 +1252,7 @@ static void init_mmcsd_host(void)
> mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | 0x1;
> /* DAT line portion is diabled and in reset state */
> mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | (1 << 1);
> + udelay(10);
>
> mmcsd_regs->mmc_clk = 0x0;
> mmcsd_regs->mmc_clk = mmcsd_regs->mmc_clk | (1 << 8);
> @@ -1066,13 +1262,14 @@ static void init_mmcsd_host(void)
>
> mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(0x1);
> mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(1 << 1);
> + udelay(10);
> }
>
> static int davinci_mmcsd_probe(struct platform_device *pdev)
> {
> struct mmc_davinci_host *host;
> struct mmc_host *mmc;
> - int ret;
> + int ret = 0;
>
> mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev);
> if (!mmc) {
> @@ -1085,14 +1282,44 @@ static int davinci_mmcsd_probe(struct pl
>
> init_mmcsd_host();
>
> + if (mmcsd_cfg.use_4bit_mode) {
> + dev_warn(&mmc_dev, "Supporting 4-bit mode\n");
> + mmc->caps |= MMC_CAP_4_BIT_DATA;
> + } else
> + dev_warn(&mmc_dev, "Not Supporting 4-bit mode\n");
> +
> mmc->ops = &mmc_davinci_ops;
> mmc->f_min = 312500;
> - mmc->f_max = 20000000;
> +#ifdef CONFIG_MMC_HIGHSPEED
> + mmc->f_max = 50000000;
> +#else
> + mmc->f_max = 25000000;
> +#endif
> mmc->ocr_avail = MMC_VDD_32_33;
>
> + mmc->max_phys_segs = 2;
> + mmc->max_hw_segs = 2;
> + mmc->max_blk_size = 4095; /* BLEN is 11 bits */
> + mmc->max_blk_count = 65535; /* NBLK is 16 bits */
> + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
> + mmc->max_seg_size = mmc->max_req_size;
> +
> + dev_dbg(&mmc_dev, "max_phys_segs=%d\n", mmc->max_phys_segs);
> + dev_dbg(&mmc_dev, "max_hw_segs=%d\n", mmc->max_hw_segs);
> + dev_dbg(&mmc_dev, "max_blk_size=%d\n", mmc->max_blk_size);
> + dev_dbg(&mmc_dev, "max_req_size=%d\n", mmc->max_req_size);
> + dev_dbg(&mmc_dev, "max_seg_size=%d\n", mmc->max_seg_size);
> +
> host = mmc_priv(mmc);
> host->mmc = mmc; /* Important */
>
> + if (mmcsd_cfg.use_dma) {
> + dev_dbg(&mmc_dev, "Using DMA mode\n");
> + if (davinci_acquire_dma_channels(host) != 0)
> + goto out;
> + } else
> + dev_dbg(&mmc_dev, "Not Using DMA mode\n");
> +
> host->use_dma = mmcsd_cfg.use_dma;
> host->irq = MMCINT_INTERRUPT;
> host->sd_support = 1;
> @@ -1122,13 +1349,20 @@ out:
> static int davinci_mmcsd_remove(struct platform_device *pdev)
> {
> struct mmc_davinci_host *host = platform_get_drvdata(pdev);
> + unsigned long flags;
>
> platform_set_drvdata(pdev, NULL);
> - mmc_remove_host(host->mmc);
> - free_irq(host->irq, host);
> - del_timer(&host->timer);
> - davinci_free_dma(DAVINCI_DMA_MMCTXEVT);
> - davinci_free_dma(DAVINCI_DMA_MMCRXEVT);
> + if (host) {
> + mmc_remove_host(host->mmc);
> + free_irq(host->irq, host);
> +
> + spin_lock_irqsave(&mmc_lock, flags);
> + del_timer(&host->timer);
> + spin_unlock_irqrestore(&mmc_lock, flags);
> +
> + davinci_release_dma_channels(host);
> + }
> +
> return 0;
>
> }
> @@ -1222,14 +1456,26 @@ free1:
> platform_device_unregister(&mmc_davinci_device);
> }
>
> + if (clkp) {
> + mmc_clkp = NULL;
> + clk_put(clkp);
> + }
> +
> return -ENODEV;
> }
>
> static void __exit davinci_mmcsd_exit(void)
> {
> + struct clk *clkp;
> +
> platform_driver_unregister(&davinci_mmcsd_driver);
> platform_device_unregister(&mmc_davinci_device);
> - clk_disable(mmc_clkp);
> +
> + clkp = mmc_clkp;
> + mmc_clkp = NULL;
> +
> + clk_disable(clkp);
> + clk_put(clkp);
> }
>
> module_init(davinci_mmcsd_init);
> diff --git a/drivers/mmc/host/davinci_mmc.h b/drivers/mmc/host/davinci_mmc.h
> index a6c4557..5840ccf 100644
> --- a/drivers/mmc/host/davinci_mmc.h
> +++ b/drivers/mmc/host/davinci_mmc.h
> @@ -132,6 +132,7 @@ #define DAVINCI_MMC_DATADIR_WRITE 2
> int power_pin;
>
> int use_dma;
> + int do_dma;
> struct completion dma_completion;
>
> struct timer_list timer;
> @@ -143,10 +144,16 @@ #define DAVINCI_MMC_DATADIR_WRITE 2
>
> edma_ch_mmcsd edma_ch_details;
>
> + unsigned int sg_len;
> + int sg_idx;
> + unsigned int buffer_bytes_left;
> + unsigned int dma_len;
> + int dma_state;
> };
> typedef struct {
> unsigned short rw_threshold;
> unsigned short use_dma;
> + unsigned short use_4bit_mode;
> } mmcsd_config_def;
>
> typedef enum {
> @@ -168,4 +175,20 @@ #define MMCSD_EVENT_CRC_ERROR \
> #define MMCSD_EVENT_ERROR \
> (MMCSD_EVENT_TIMEOUT_ERROR | MMCSD_EVENT_CRC_ERROR)
>
> +static void init_mmcsd_host(void);
> +
> +static void davinci_fifo_data_trans(struct mmc_davinci_host *host);
> +
> +static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host);
> +
> +static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
> + struct mmc_request *req);
> +
> +static void mmc_davinci_xfer_done(struct mmc_davinci_host *host,
> + struct mmc_data *data);
> +
> +static int mmc_davinci_get_ro(struct mmc_host *mmc);
> +
> +static void davinci_abort_dma(struct mmc_davinci_host *host);
> +
> #endif /* DAVINCI_MMC_H_ */
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source