📄 x
字号:
+ //host->params.ie =+ host->params.read_prio = DMA_CH_PRIO_HIGH;+ host->params.src_ei = 0;+ host->params.src_fi = 0;+ host->params.src_port = 0;+ host->params.sync_mode = OMAP_DMA_SYNC_FRAME;+ host->params.write_prio = DMA_CH_PRIO_HIGH;+ if (!(data->flags & MMC_DATA_WRITE)) { host->dma_dir = DMA_FROM_DEVICE;@@ -1233,42 +1843,102 @@ mmc_omap_start_dma_transfer(struct mmc_o sync_dev = OMAP24XX_DMA_MMC1_RX; else sync_dev = OMAP24XX_DMA_MMC2_RX;++ host->params.dst_amode = OMAP_DMA_AMODE_POST_INC;+ host->params.dst_start = sg_dma_address(&data->sg[host->sg_idx]);++ host->params.frame_count = count;++ host->params.src_amode = OMAP_DMA_AMODE_CONSTANT;+ host->params.src_or_dst_synch = OMAP_DMA_SRC_SYNC;+ host->params.src_start = (dma_addr_t) (host->mapbase +OMAP_HSMMC_DATA);++ host->params.trigger = sync_dev; } else { host->dma_dir = DMA_TO_DEVICE; if (host->id == OMAP_MMC1_DEVID) sync_dev = OMAP24XX_DMA_MMC1_TX; else sync_dev = OMAP24XX_DMA_MMC2_TX;++ host->params.dst_amode = OMAP_DMA_AMODE_CONSTANT;+ host->params.dst_start = (dma_addr_t) (host->mapbase + OMAP_HSMMC_DATA);++ host->params.frame_count = count;++ host->params.src_amode = OMAP_DMA_AMODE_POST_INC;+ host->params.src_or_dst_synch = OMAP_DMA_DST_SYNC;+ host->params.src_start = sg_dma_address(&data->sg[host->sg_idx]);++ host->params.trigger = sync_dev; } - ret = omap_request_dma(sync_dev, "MMC/SD", mmc_omap_dma_cb, host,- &dma_ch);+ /* Request a DMA chain for transfer+ * A chain is requested before each transfer to avoid+ * locking of DMA resources+ */+ ret = omap_request_dma_chain(sync_dev, "MMC/SD", mmc_omap_dma_cb,+ &dma_chid, host->chains_requested,+ OMAP_DMA_DYNAMIC_CHAIN, host->params); if (ret != 0) { dev_dbg(mmc_dev(host->mmc),- "%s: omap_request_dma() failed with %d\n",+ "%s: omap_request_dma_chain() failed with %d\n", mmc_hostname(host->mmc), ret); return ret; }+ else+ {+ if(host->chains_requested > 1)+ omap_dma_set_interrupt_ch(dma_chid, OMAP_DMA_DROP_IRQ |+ OMAP2_DMA_MISALIGNED_ERR_IRQ |+ OMAP2_DMA_TRANS_ERR_IRQ,+ OMAP_DMA_DROP_IRQ |+ OMAP_DMA_BLOCK_IRQ |+ OMAP2_DMA_MISALIGNED_ERR_IRQ |+ OMAP2_DMA_TRANS_ERR_IRQ);+ }+ host->chain_id = dma_chid;+ return 0;+} - host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,- host->dma_dir);- host->dma_ch = dma_ch; - if (!(data->flags & MMC_DATA_WRITE)) {- sync_dir = OMAP_DMA_SRC_SYNC;- mmc_omap_config_dma_param(sync_dir, host, data);- } else {- sync_dir = OMAP_DMA_DST_SYNC;- mmc_omap_config_dma_param(sync_dir, host, data);+static void mmc_chain_dma(struct mmc_omap_host *host, struct mmc_data *data)+{+ u16 frame;+ u32 count,i,dma_chain_status, sg_idx = host->sg_idx;+ struct scatterlist *sg;++ frame = data->blksz;+ for(i = host->sg_idx ;i < (host->chains_requested + sg_idx); i++)+ {+ sg = &data->sg[i];+ count = sg_dma_len(sg)/frame;+ host->sg_dma_len += (frame * count);+ if(!(data->flags & MMC_DATA_WRITE))+ {+ dma_chain_status = omap_dma_chain_a_transfer(host->chain_id,+ (dma_addr_t) (host->mapbase +OMAP_HSMMC_DATA),+ sg_dma_address(&data->sg[i]), (data->blksz / 4),+ count, host);+ if(dma_chain_status != 0)+ dev_dbg(mmc_dev(host->mmc),+ "%s: omap_dma_chain_a_transfer() failed during read with %d\n",+ mmc_hostname(host->mmc), dma_chain_status);+ }+ else+ {+ dma_chain_status = omap_dma_chain_a_transfer(host->chain_id,+ sg_dma_address(&data->sg[i]),+ (dma_addr_t) (host->mapbase + OMAP_HSMMC_DATA),+ (data->blksz / 4) ,count ,host);+ if(dma_chain_status != 0)+ dev_dbg(mmc_dev(host->mmc),+ "%s: omap_dma_chain_a_transfer() failed during write with %d\n",+ mmc_hostname(host->mmc), dma_chain_status);+ }+ host->sg_idx++; } - omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,- (data->blksz / 4), data->blocks,- OMAP_DMA_SYNC_FRAME, sync_dev,- sync_dir);-- omap_start_dma(dma_ch);- return 0; } /*@@ -1278,11 +1948,23 @@ mmc_omap_start_dma_transfer(struct mmc_o static int mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) {- int ret = 0;+ int use_dma;+ int i, block_size;+ unsigned sg_len;+ struct mmc_data *data = req->data;+ unsigned long flags;+ #ifdef CONFIG_OMAP_SDIO int byte_count = 0, func = 0;+ int ret = 0; #endif + if(unlikely(host == NULL))+ {+ return -1;+ }++ /* Store the pointer for request */ host->data = req->data; #ifdef CONFIG_OMAP_SDIO@@ -1313,7 +1995,7 @@ mmc_omap_prepare_data(struct mmc_omap_ho | (1 << 16)); } -#ifdef CONFIG_OMAP_SDIO_NON_DMA_MODE+#ifdef CONFIG_OMAP_SDIO_NON_DMA_MODE host->buffer = (u32 *) req->data->sdio_buffer_virt; #else if (polling_mode == 0) {@@ -1333,9 +2015,13 @@ mmc_omap_prepare_data(struct mmc_omap_ho return 0; } #endif /* ifdef CONFIG_OMAP_SDIO */+ /* Enable DMA */+ host->use_dma = 1; if (req->data == NULL) { host->datadir = OMAP_MMC_DATADIR_NONE; OMAP_HSMMC_WRITE(host->base, BLK, BLK_CLEAR);+ /* Since there is nothing to DMA, clear the flag */+ host->use_dma = 0; return 0; } @@ -1343,17 +2029,69 @@ mmc_omap_prepare_data(struct mmc_omap_ho OMAP_HSMMC_WRITE(host->base, BLK, OMAP_HSMMC_READ(host->base, BLK) | (req->data->blocks << 16));+++ /* Copy the Block Size information */+ block_size = data->blksz;++ /* Cope with calling layer confusion; it issues "single+ * block" writes using multi-block scatterlists.+ */+ sg_len = (data->blocks == 1) ? 1 : data->sg_len;++ spin_lock_irqsave(&host->dma_lock, flags);+ if(sg_len > NO_OF_DMA_CHAINS_USED)+ {+ host->extra_chain_reqd = sg_len % NO_OF_DMA_CHAINS_USED;+ host->no_of_chain_reqd = sg_len / NO_OF_DMA_CHAINS_USED;+ host->chains_requested = NO_OF_DMA_CHAINS_USED;+ host->current_cb_cnt = 1;+ }+ else+ {+ host->extra_chain_reqd = 0;+ host->no_of_chain_reqd = 0;+ host->chains_requested = data->sg_len;+ host->current_cb_cnt = 0;+ }+ spin_unlock_irqrestore(&host->dma_lock, flags);++ /* Only do DMA for entire blocks */+ use_dma = host->use_dma;+ if (use_dma) {+ for (i = 0; i < sg_len; i++) {+ if ((data->sg[i].length % block_size) != 0) {+ use_dma = 0;+ break;+ }+ }+ } host->datadir = (req->data-> flags & MMC_DATA_WRITE) ? OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ;+ /* Initialize the internal scatter list count */+ host->sg_idx = 0;+ if (use_dma) {+ if (mmc_omap_get_dma_channel(host, data) == 0) {+ enum dma_data_direction dma_data_dir; - if (host->use_dma) {- ret = mmc_omap_start_dma_transfer(host, req);- if (ret != 0) {- dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");- return ret;- } else {- host->buffer = NULL;- host->bytesleft = 0;+ if (data->flags & MMC_DATA_WRITE)+ dma_data_dir = DMA_TO_DEVICE;+ else+ dma_data_dir = DMA_FROM_DEVICE;++ host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,+ sg_len, dma_data_dir);+ host->total_bytes_left = 0;+ mmc_chain_dma(host, req->data);+ host->brs_received = 0;+ host->dma_done = 0;++ /* Enable DMA */+ host->use_dma = 1;+ }+ else+ {+ host->use_dma = 0; } } else { /* Revert to CPU copy */@@ -1362,6 +2100,7 @@ mmc_omap_prepare_data(struct mmc_omap_ho req->data->sg->offset); host->bytesleft = req->data->blocks * (req->data->blksz); host->dma_ch = -1;+ host->use_dma = 0; } return 0;@@ -1395,6 +2134,36 @@ static void omap_mmc_request(struct mmc_ "MMC host %s failed to initiate data transfer\n", mmc_hostname(host->mmc)); + /* Start the DMA if DMA is needed */+ if (host->use_dma && (host->mmc->mode == MMC_MODE_MMC+ || host->mmc->mode == MMC_MODE_SD))+ {+ omap_start_dma_chain_transfers(host->chain_id);+ }+ if(host->card_detected == 1)+ {+ if (host->mmc->mode == MMC_MODE_MMC ||+ host->mmc->mode == MMC_MODE_SD)+ {+ host->mmc->max_hw_segs = 128;+ host->mmc->max_phys_segs = 128;+ host->mmc->max_blk_size = 512;+ host->mmc->max_blk_count = 0xFFFF;+ host->mmc->max_req_size = host->mmc->max_blk_size * host->mmc->max_blk_count;+ host->mmc->max_seg_size = host->mmc->max_req_size;+ host->card_detected = 0;+ }+ else if(host->mmc->mode == MMC_MODE_SDIO)+ {+ host->mmc->max_hw_segs = 1;+ host->mmc->max_phys_segs = 1;+ host->mmc->max_seg_size = 1<<12;+ host->mmc->max_req_size = 1<<12;+ host->mmc->max_blk_size = 512;+ host->mmc->max_blk_count = 1<<12 / 512;+ host->card_detected = 0;+ }+ } mmc_clk_disable_aggressive(host); mmc_omap_start_command(host, req->cmd);@@ -1451,19 +2220,16 @@ static void omap_mmc_set_ios(struct mmc_ switch (mmc->ios.bus_width) { case MMC_BUS_WIDTH_8:- printk("MMC: Operating in 8 bit mode\n");- OMAP_HSMMC_WRITE(host->base, CON,+ OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_READ(host->base,CON) | EIGHT_BIT); break; case MMC_BUS_WIDTH_4:- printk("MMC: Operating in 4 bit mode\n"); OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base,HCTL) | FOUR_BIT); break; case MMC_BUS_WIDTH_1:- printk("MMC: Operating in 1 bit mode\n"); OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_READ(host->base,CON) & ~EIGHT_BIT); OMAP_HSMMC_WRITE(host->base, HCTL,@@ -1475,10 +2241,10 @@ static void omap_mmc_set_ios(struct mmc_ if ((cpu_is_omap34xx() && is_sil_rev_less_than(OMAP3430_REV_ES2_0)) || (cpu_is_omap2430() && omap2_cpu_rev() == 2)) { if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&- ((ios->vdd == 7) || (ios->vdd == 8))) {+ ((ios->vdd == 7) || (ios->vdd == 8))) { if (omap_mmc_switch_opcond(host, 0) != 0) dev_dbg(mmc_dev(host->mmc),- "omap_mmc_set_ios:"+ "omap_mmc_set_ios:" "switch operation failed\n"); host->initstream = 0; }@@ -1529,7 +2295,7 @@ static struct mmc_host_ops mmc_omap_ops */ static ssize_t sdio_polling_switch(struct device *dev, struct device_attribute *attr,- const char *buf, size_t count)+ const char *buf, size_t count) { char cmd[25]; int i = 0;@@ -1611,9 +2377,20 @@ static int __init omap_mmc_probe(struct mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; mmc->f_max = 52000000;+ mmc->mode = MMC_CARD_NONE;+ host->card_detected = 1;+ host->is_high_capacity = 0;+ host->flag_err = 0;+ host->cmd_12 = 0;+ host->cmd_13 = 0;+ host->crc_retry = 0;+ #ifdef CONFIG_OMAP_SDIO host->sdio_card_intr = 0; #endif+ spin_lock_init(&host->dma_lock);+ host->chain_id = -1;+ host->sg_dma_len = 0; if (cpu_is_omap2430()) { if (host->id == OMAP_MMC1_DEVID) {@@ -1660,7 +2437,7 @@ static int __init omap_mmc_probe(struct */ if (IS_ERR(host->dbclk)) dev_dbg(mmc_dev(host->mmc),- "Failed to get"+ "Failed to get" "debounce clock for MMC2\n"); } }@@ -1703,9 +2480,6 @@ static int __init omap_mmc_probe(struct dev_dbg(mmc_dev(host->mmc), "Failed to enable debounce clock for MMC%d\n", host->id);- }-- if (cpu_is_omap2430()) { omap_writel(omap_readl(OMAP2_CONTROL_DEVCONF1) | MMC1_ACTIVE_OVERWRITE, OMAP2_CONTROL_DEVCONF1); if (minfo->wire4)@@ -1728,10 +2502,8 @@ static int __init omap_mmc_probe(struct if (cpu_is_omap3410()) { mmc->caps = MMC_CAP_4_BIT_DATA; }- else {+ else mmc->caps = MMC_CAP_8_BIT_DATA;- printk("\n Configuring for 8 BIT DATA -------------- \n");- } } OMAP_HSMMC_WRITE(host->base, HCTL,@@ -1765,6 +2537,23 @@ static int __init omap_mmc_probe(struct HCTL) | SDVS18); } + /* Use scatterlist DMA to reduce per-transfer costs.+ * NOTE max_seg_size assumption that small blocks aren't+ * normally used (except e.g. for reading SD registers).+ */+ mmc->max_phys_segs = 128; /* Largest sized scatter list+ * the driver could handle. Since this is+ * managed by us in software, we can tune+ * this value */+ mmc->max_hw_segs = 128; /* Largest number of address/length+ * pairs the host adapter can actually+ * give at once to the device. This value+ * should be kept same as scatter list */+ mmc->max_blk_size = 512; /* Block Length at max can be 1024 */+ mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;+ mmc->max_seg_size = mmc->max_req_size;+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; OMAP_HSMMC_WRITE(host->base, CAPA,OMAP_HSMMC_READ(host->base,@@ -1780,8 +2569,10 @@ static int __init omap_mmc_probe(struct OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) | SDBP); - if (machine_is_omap_2430sdp() || machine_is_omap_3430sdp()- || machine_is_omap_3430labrador() || machine_is_omap3_beagle() ) {+ if (machine_is_omap_2430sdp() ||+ machine_is_omap_3430sdp() ||+ machine_is_omap_3430labrador() ||+ machine_is_omap3evm()) { /* * Create sysfs entries for enabling/disabling hotplug * support for MMC cards@@ -1789,7 +2580,7 @@ static int __init omap_mmc_probe(struct if (device_create_file(&pdev->dev, &dev_attr_mmc_cover_switch) < 0) { dev_dbg(mmc_dev(host->mmc),- "Unable to create sysfs"+ "Unable to create sysfs" "attribute for MMC1 cover switch\n"); } if (device_create_file(&pdev->dev,@@ -1818,8 +2609,10 @@ static int __init omap_mmc_probe(struct host->card_detect_irq = minfo->switch_pin; if (minfo->switch_pin >= 0) {- if (machine_is_omap_2430sdp() || machine_is_omap_3430sdp()- || machine_is_omap_3430labrador() || machine_is_omap3_beagle()) {+ if (machine_is_omap_2430sdp() ||+ machine_is_omap_3430sdp() ||+ machine_is_omap_3430labrador() ||+ machine_is_omap3evm()) { host->card_detect_irq = TWL4030_GPIO_IRQ_NO(minfo->switch_pin); INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);@@ -1943,8 +2736,10 @@ static int omap_mmc_suspend(struct platf /* Temporarily enabling the clocks for configuration */ mmc_clk_enable_aggressive(host); - if (machine_is_omap_2430sdp() || machine_is_omap_3430sdp()- || machine_is_omap_3430labrador() || machine_is_omap3_beagle() ) {+ if (machine_is_omap_2430sdp() ||+ machine_is_omap_3430sdp() ||+ machine_is_omap_3430labrador() ||+ machine_is_omap3evm()) { disable_irq(host->card_detect_irq); ret = mask_carddetect_int(host->id); if (ret)@@ -1974,7 +2769,7 @@ static int omap_mmc_suspend(struct platf /* Clearing the STAT register*/ status = OMAP_HSMMC_READ(host->base, STAT);- OMAP_HSMMC_WRITE(host->base, STAT, status);+ OMAP_HSMMC_WRITE(host->base, STAT, status); /* disable clks for MMC1 */ mmc_clk_disable(host); @@ -2024,7 +2819,7 @@ static int omap_mmc_resume(struct platfo ret = mmc_omap_power(host,1); if (ret != 0) { dev_dbg(mmc_dev(host->mmc),- "Unable to enable power to MMC1\n");+ "Unable to enable power to MMC1\n"); return ret; } @@ -2035,12 +2830,14 @@ static int omap_mmc_resume(struct platfo if (cpu_is_omap2430()) { if (clk_enable(host->dbclk) != 0) dev_dbg(mmc_dev(host->mmc),- "Unable to enable debounce"+ "Unable to enable debounce" "clock for MMC1\n"); } - if (machine_is_omap_2430sdp() || machine_is_omap_3430sdp()- || machine_is_omap_3430labrador() || machine_is_omap3_beagle() ) {+ if (machine_is_omap_2430sdp() ||+ machine_is_omap_3430sdp() ||+ machine_is_omap_3430labrador() ||+ machine_is_omap3evm()) { enable_irq(host->card_detect_irq); ret = unmask_carddetect_int(host->id); if (ret)@@ -2101,7 +2898,7 @@ omap_mmc_pre_scale(int slot, struct noti static int omap_mmc_post_scale(int slot, struct notifier_block *op, unsigned long level,- void *ptr)+ void *ptr) { struct mmc_omap_host *host = (slot == MMC1) ? saved_host1 : saved_host2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -