📄 x
字号:
++/*+ * Notify the xfer done on MMC/SD cards to the core+ */+static void+mmc_omap_err_done(struct mmc_omap_host *host, struct mmc_data *data)+{+ host->data = NULL;+ if (host->use_dma && host->chain_id != -1) {+ omap_stop_dma_chain_transfers(host->chain_id);+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,+ host->dma_dir);+ omap_free_dma_chain(host->chain_id);+ host->chain_id = -1;+ }++ host->datadir = OMAP_MMC_DATADIR_NONE;+ host->sg_dma_len = 0;++ mmc_clk_disable_aggressive(host);++ if (!data->stop) {+ host->mrq = NULL;+ mmc_request_done(host->mmc, data->mrq);+ return;+ }+ mmc_omap_start_command(host, data->stop);+}+++ /* * The MMC controller IRQ handler */ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) { struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;- int end_command, end_transfer, status;+ int end_command, end_transfer, status, read_crc =0;+ unsigned long flags; typeof(jiffies) timeout; - if (host->cmd == NULL && host->data == NULL) {+ if (unlikely(host == NULL))+ {+ return IRQ_HANDLED;+ }++ if(unlikely(host->cmd == NULL && host->data == NULL)) { status = OMAP_HSMMC_READ(host->base, STAT); if (status != 0) { OMAP_HSMMC_WRITE(host->base, STAT, status);@@ -732,6 +1136,17 @@ static irqreturn_t mmc_omap_irq(int irq, status = OMAP_HSMMC_READ(host->base, STAT); dev_dbg(mmc_dev(host->mmc), "Status in IRQ %x\n", status); + if(unlikely(host->use_dma == 0))+ {+ if (host->total_bytes_left != 0) {+ if ((status & OMAP_MMC_STAT_BRR) ||+ (status & TC))+ mmc_omap_xfer_data(host, 0);+ if (status & OMAP_MMC_STAT_BWR)+ mmc_omap_xfer_data(host, 1);+ }+ }+ if (status & (OMAP_HSMMC_ERR)) { if (status & (OMAP_HSMMC_CMD_TIMEOUT) || status & (OMAP_HSMMC_CMD_CRC)) {@@ -741,6 +1156,7 @@ static irqreturn_t mmc_omap_irq(int irq, * Timeouts are normal in case of * MMC_SEND_STATUS */+ if (host->cmd->opcode != MMC_ALL_SEND_CID) dev_dbg(mmc_dev(host->mmc),@@ -770,7 +1186,31 @@ static irqreturn_t mmc_omap_irq(int irq, mmc_hostname(host->mmc)); mmc_dma_cleanup(host); } else {- host->data->error |= MMC_ERR_BADCRC;+ if(host->data->flags & MMC_DATA_READ)+ {+ read_crc = 1;+ if(host->flag_err == 1)+ {+ dev_dbg(mmc_dev(host->mmc),+ "%s:Data CRC for the second time\n",+ mmc_hostname(host->mmc));+ spin_lock_irqsave(&host->dma_lock, flags);+ host->crc_retry++;+ host->flag_err = 0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ if(host->crc_retry == MAX_CRC_RETRY)+ {+ spin_lock_irqsave(&host->dma_lock, flags);+ host->mod_addr = host->org_addr = 0;+ host->flag_err = host->cmd_12 = host->cmd_13 = 0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ host->data->error |= MMC_ERR_BADCRC;+ mmc_omap_err_done(host, host->data);+ }+ }+ }+ else+ host->data->error |= MMC_ERR_BADCRC; dev_dbg(mmc_dev(host->mmc), "%s: Data CRC error," " bytes left %d\n",@@ -802,15 +1242,15 @@ static irqreturn_t mmc_omap_irq(int irq, dev_dbg(mmc_dev(host->mmc), "MMC%d: SDIO CARD interrupt status %x\n", host->id, status);- OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK & + OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK & (~OMAP_HSMMC_CARD_INT)); host->sdio_card_intr = 0;- /* + /* * SDIO Card interrupt notifier code should go here, * it should clear the source of interrupt and then * call again the interrupt enable API. */- return IRQ_HANDLED; + return IRQ_HANDLED; } } #endif@@ -820,20 +1260,59 @@ static irqreturn_t mmc_omap_irq(int irq, #endif /* ifdef CONFIG_OMAP_SDIO */ OMAP_HSMMC_WRITE(host->base, STAT, status);+ if(host->flag_err == 1)+ {+ if(host->cmd_12 == 1)+ {+ if (status & CC) {+ mmc_omap_err_cmd_done(host, host->cmd);+ spin_lock_irqsave(&host->dma_lock, flags);+ host->cmd_12 =0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ mmc_omap_start_command13(host, host->cmd);+ return IRQ_HANDLED;+ }+ }+ if(host->cmd_13 == 1)+ {+ if (status & CC) {+ mmc_omap_err_cmd_done(host, host->cmd);+ spin_lock_irqsave(&host->dma_lock, flags);+ host->cmd_13 =0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ mmc_omap_err_prepare_data(host);+ omap_start_dma_chain_transfers(host->chain_id);+ mmc_omap_start_command18(host, host->cmd);+ return IRQ_HANDLED;+ }+ }+ return IRQ_HANDLED;+ } if (end_command || (status & CC)) { mmc_omap_cmd_done(host, host->cmd); } - if (end_transfer || (status & TC)) {- if (host->mmc->mode == MMC_MODE_MMC- || host->mmc->mode == MMC_MODE_SD)- mmc_omap_xfer_done(host, host->data);+ if (host->mmc->mode == MMC_MODE_MMC+ || host->mmc->mode == MMC_MODE_SD){+ if (end_transfer){+ if(read_crc)+ {+ mmc_omap_err_calc(host);+ mmc_omap_read_err_done(host, host->data);+ }+ else+ mmc_omap_err_done(host, host->data);+ }+ else if (status & TC)+ mmc_omap_end_of_data(host, host->data);+ } #ifdef CONFIG_OMAP_SDIO- else if (host->mmc->mode == MMC_MODE_SDIO)+ if(host->mmc->mode == MMC_MODE_SDIO){+ if (end_transfer || (status & TC)) sdio_omap_xfer_done(host, host->sdiodata);-#endif /* ifdef CONFIG_OMAP_SDIO */ }+#endif /* ifdef CONFIG_OMAP_SDIO */ return IRQ_HANDLED; }@@ -843,7 +1322,7 @@ static irqreturn_t mmc_omap_irq(int irq, * Function for polling mode read write for SDIO cards */ static void mmc_omap_polling_command(struct mmc_omap_host *host,- struct mmc_command *cmd, u32 cmdreg)+ struct mmc_command *cmd, u32 cmdreg) { int i, readCnt, bytec, status = 0; typeof(jiffies) timeout;@@ -927,12 +1406,18 @@ static int mmc_omap_power(struct mmc_oma int ret = 0; if (on){- 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())+ ret = enable_mmc_power(host->id); } else {- 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())+ ret = disable_mmc_power(host->id); } @@ -957,8 +1442,11 @@ static int omap_mmc_switch_opcond(struct if (ret != 0) dev_dbg(mmc_dev(host->mmc),"Unable to disable power to 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()) {+ if (switch_power_mode(power_mode)) dev_dbg(mmc_dev(host->mmc), "Unable to switch operating" "voltage to the card\n");@@ -1024,10 +1512,22 @@ static void mmc_omap_detect(struct work_ static irqreturn_t mmc_omap_irq_cd(int irq, void *dev_id) { struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;+ unsigned long flags; - 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())+ {+ spin_lock_irqsave(&host->dma_lock, flags);+ host->card_detected = 1;+ host->mmc->mode = MMC_CARD_NONE;+ host->rca = host->mod_addr = host->org_addr = 0;+ host->is_high_capacity = 0;+ host->flag_err = host->cmd_12 = host->cmd_13 = 0;+ spin_unlock_irqrestore(&host->dma_lock, flags); schedule_work(&host->mmc_carddetect_work);+ } else dev_dbg(mmc_dev(host->mmc), "Place to implement MMC hotplug" "implementation based on what the other"@@ -1038,52 +1538,158 @@ static irqreturn_t mmc_omap_irq_cd(int i /* * DMA call back function+ lch is chain id in case of chaining */ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) { struct mmc_omap_host *host = (struct mmc_omap_host *)data;+ int chainid = host->chain_id; int dma_ch;+ unsigned long flags; - /*- * Only report the error for the time being, until the error handling- * for these type of errors is supported from the core- */- if (ch_status & (1 << 11))- dev_dbg(mmc_dev(host->mmc), " %s :MISALIGNED_ADRS_ERR\n",- mmc_hostname(host->mmc));+ if(host->flag_err)+ {+ spin_lock_irqsave(&host->dma_lock, flags);+ host->crc_retry =0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ if(host->no_of_chain_reqd > host->current_cb_cnt)+ {+ spin_lock_irqsave(&host->dma_lock, flags);+ host->current_cb_cnt++;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ mmc_omap_read_err_done(host, host->data);+ }+ else if(host->no_of_chain_reqd == host->current_cb_cnt)+ {+ if(host->extra_chain_reqd == 0)+ {+ /*cleanup and go away*/+ spin_lock_irqsave(&host->dma_lock, flags);+ host->flag_err = 0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ omap_stop_dma_chain_transfers(chainid);+ omap_free_dma_chain(chainid);+ mmc_omap_dma_done(host, host->data);+ host->chain_id = -1; - if (host->dma_ch < 0) {- dev_dbg(mmc_dev(host->mmc), "%s:"- "DMA callback while DMA not enabled?\n",- mmc_hostname(host->mmc));+ }+ else+ {+ /*do the last transfer*/+ spin_lock_irqsave(&host->dma_lock, flags);+ host->chains_requested = host->extra_chain_reqd;+ host->extra_chain_reqd = 0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ mmc_omap_read_err_done(host, host->data);+ }+ } return; }+ if(host->mmc->mode == MMC_MODE_SDIO)+ {+ /*+ * Only report the error for the time being, until the error handling+ * for these type of errors is supported from the core+ */+ if (ch_status & (1 << 11))+ dev_dbg(mmc_dev(host->mmc), " %s :MISALIGNED_ADRS_ERR\n",+ mmc_hostname(host->mmc));++ if (host->dma_ch < 0) {+ dev_dbg(mmc_dev(host->mmc), "%s:"+ "DMA callback while DMA not enabled?\n",+ mmc_hostname(host->mmc));+ return;+ } - dma_ch = host->dma_ch;- host->dma_ch = -1;- omap_free_dma(dma_ch);- up(&host->sem);+ dma_ch = host->dma_ch;+ host->dma_ch = -1;+ omap_free_dma(dma_ch);+ }+ else+ {+ /* If we are at the last transfer, Shut down the reciever */+ if (omap_dma_chain_status(chainid) == OMAP_DMA_CHAIN_INACTIVE) {+ if(host->no_of_chain_reqd > host->current_cb_cnt)+ {+ mmc_chain_dma(host, host->data);+ omap_dma_set_interrupt_ch(host->chain_id, 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);+ omap_start_dma_chain_transfers(host->chain_id);+ spin_lock_irqsave(&host->dma_lock, flags);+ host->current_cb_cnt++;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ }+ else if(host->no_of_chain_reqd == host->current_cb_cnt)+ {+ if(host->extra_chain_reqd == 0)+ {+ omap_stop_dma_chain_transfers(chainid);+ omap_free_dma_chain(chainid);+ mmc_omap_dma_done(host, host->data);+ host->chain_id = -1;+ }+ else+ {+ omap_stop_dma_chain_transfers(chainid);+ omap_free_dma_chain(chainid);+ host->chain_id = -1;+ spin_lock_irqsave(&host->dma_lock, flags);+ host->chains_requested = host->extra_chain_reqd;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ mmc_omap_get_dma_channel(host, host->data);+ mmc_chain_dma(host, host->data);+ omap_start_dma_chain_transfers(host->chain_id);+ spin_lock_irqsave(&host->dma_lock, flags);+ host->extra_chain_reqd = 0;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ }+ }+ else+ {+ dev_dbg(mmc_dev(host->mmc), "%s:"+ "DMA callback ERROR\n",+ mmc_hostname(host->mmc));+ }+ }+ else+ {+ dev_dbg(mmc_dev(host->mmc), "%s:"+ "DMA callback Channel active?\n",+ mmc_hostname(host->mmc));+ }+ } }+++#ifdef CONFIG_OMAP_SDIO+#ifndef CONFIG_OMAP_SDIO_NON_DMA_MODE+ /* * Configure dma src and destination parameters */ static int mmc_omap_config_dma_param(int sync_dir, struct mmc_omap_host *host,- struct mmc_data *data)+ struct mmc_data *data) { if (sync_dir == OMAP_DMA_DST_SYNC) { omap_set_dma_dest_params(host->dma_ch, 0, // dest_port required only for OMAP1 OMAP_DMA_AMODE_CONSTANT,- (dma_addr_t) (host-> mapbase + OMAP_HSMMC_DATA),0, 0);+ (dma_addr_t) (host-> mapbase + OMAP_HSMMC_DATA),0, 0); omap_set_dma_src_params(host->dma_ch, 0, // src_port required only for OMAP1 OMAP_DMA_AMODE_POST_INC,- sg_dma_address(&data-> sg[0]), 0, 0);+ sg_dma_address(&data-> sg[0]), 0, 0); } else { omap_set_dma_src_params(host->dma_ch, 0, // src_port required only for OMAP1 OMAP_DMA_AMODE_CONSTANT,- (dma_addr_t) (host->mapbase +OMAP_HSMMC_DATA),0, 0);+ (dma_addr_t) (host->mapbase +OMAP_HSMMC_DATA),0, 0); omap_set_dma_dest_params(host->dma_ch, 0, // dest_port required only for OMAP1 OMAP_DMA_AMODE_POST_INC,@@ -1092,14 +1698,12 @@ static int mmc_omap_config_dma_param(int return 0; } -#ifdef CONFIG_OMAP_SDIO-#ifndef CONFIG_OMAP_SDIO_NON_DMA_MODE /* * Routine to configure and start dma for SDIO card */ static int sdio_omap_start_dma_transfer(struct mmc_omap_host *host,- struct mmc_request *req)+ struct mmc_request *req) { int sync_dev, sync_dir, dma_ch, ret, readCnt, bytecount; int nob = 1, func = 0;@@ -1196,36 +1800,42 @@ sdio_omap_start_dma_transfer(struct mmc_ #endif #endif /* ifdef CONFIG_OMAP_SDIO */ -/*- * Rotine to configure and start DMA for the MMC card- */-static int-mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req)+static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data) {- int sync_dev, sync_dir, dma_ch, ret;- struct mmc_data *data = req->data;+ int ret = 0;+ int dma_chid;+ u16 frame;+ u32 count;+ struct scatterlist *sg = &data->sg[host->sg_idx];+ int sync_dev = 0;++ frame = data->blksz;/*blk size*/+ count = sg_dma_len(sg)/frame;/*No of blocks*/ /* * If for some reason the DMA transfer is still active, * we wait for timeout period and free the dma */- if (host->dma_ch != -1) {- set_current_state(TASK_INTERRUPTIBLE);- schedule_timeout(100);- if (down_trylock(&host->sem)) {- dma_ch = host->dma_ch;- host->dma_ch = -1;- omap_free_dma(dma_ch);- up(&host->sem);- return 1;- }- } else {- if (down_trylock(&host->sem)) {- dev_dbg(mmc_dev(host->mmc),- "Semaphore was not initialized \n");- BUG();- }- }+ if(host->chain_id != -1)+ dev_dbg(mmc_dev(host->mmc),+ "%s: chain is not free\n",+ mmc_hostname(host->mmc));++ /*Common params*/+ //host->params.burst_mode =+ host->params.data_type = OMAP_DMA_DATA_TYPE_S32;+ host->params.dst_ei = 0;+ host->params.dst_fi = 0;+ host->params.dst_port = 0;+ host->params.elem_count = (data->blksz / 4);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -