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 > Davinci-linux-open-source@linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source