📄 x
字号:
--- omap_hsmmc.c 2008-07-04 21:26:18.000000000 +0530+++ /home/khasim/psp_release/linux/kernel_org/2.6_kernel/drivers/mmc/host/omap_hsmmc.c 2008-06-26 15:59:51.000000000 +0530@@ -42,6 +42,7 @@ #include <asm/arch/clock.h> #include <asm/semaphore.h> #include "omap_hsmmc.h"+#include <asm/scatterlist.h> #ifdef CONFIG_PM #include <linux/notifier.h>@@ -87,8 +88,10 @@ #define OMAP_MMC_SYSCONFIG_LVL2 0x2 #endif /* #ifdef AGGR_PM_CAP */ -#if defined(CONFIG_MACH_OMAP_2430SDP) || defined(CONFIG_MACH_OMAP_3430SDP) || \- defined(CONFIG_MACH_OMAP_3430LABRADOR) || defined(CONFIG_MACH_OMAP3_BEAGLE)+#if defined(CONFIG_MACH_OMAP_2430SDP) || \+ defined(CONFIG_MACH_OMAP_3430SDP) || \+ defined(CONFIG_MACH_OMAP_3430LABRADOR) || \+ defined(CONFIG_MACH_OMAP3EVM) extern int enable_mmc_power(int slot); extern int disable_mmc_power(int slot); extern int mask_carddetect_int(int slot);@@ -104,6 +107,9 @@ DEVICE_ATTR(mmc_cover_switch, S_IRUGO, m DEVICE_ATTR(mmc_card_detect, S_IWUSR, NULL, set_mmc_carddetect); #endif +#define MMC_CARD_NONE 4+#define MAX_CRC_RETRY 1+ struct mmc_omap_host *saved_host1, *saved_host2; struct mmc_omap_host {@@ -133,9 +139,29 @@ struct mmc_omap_host { u32 bytesleft; int use_dma, dma_ch; unsigned int dma_len;+ unsigned int sg_dma_len; unsigned int dma_dir;+ int chain_id;+ struct omap_dma_channel_params params;+ u32 chains_requested;/* Number of chains to be requested */+ u32 extra_chain_reqd;/* if there is a need of last chaining*/+ u32 no_of_chain_reqd;/*No of times callback called*/+ u32 current_cb_cnt;+ int brs_received;+ int dma_done;+ int dma_is_read;+ spinlock_t dma_lock;+ unsigned int sg_len;+ int sg_idx;+ u32 buffer_bytes_left;+ u32 total_bytes_left; struct work_struct mmc_carddetect_work; int initstream;+ /*Added for CRC retry*/+ bool card_detected;+ u32 rca, mod_addr, org_addr;+ int is_high_capacity;+ int flag_err, cmd_12,cmd_13, crc_retry; }; #ifdef CONFIG_OMAP34XX_OFFMODE@@ -164,6 +190,12 @@ static int gptfclk_counter; #endif /* #ifdef CONFIG_MMC_OMAP3430 */ static int mmc_clk_counter [NO_OF_MMC_HOSTS];+#define OMAP_MMC_STAT_BRR 1 << 5+#define OMAP_MMC_STAT_BWR 1 << 4+#define NO_OF_DMA_CHAINS_USED 2//This will work with 2 chains currently++static void mmc_chain_dma(struct mmc_omap_host *host, struct mmc_data *data);+static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data); #ifdef AGGR_PM_CAP static int omap_mmc_sysconfig (struct mmc_omap_host *host, int level)@@ -377,6 +409,28 @@ static void send_init_stream(struct mmc_ enable_irq(host->irq); } ++/*+ * Configure the resptype, cmdtype and send the given command to the card+ */+static void+mmc_omap_start_command18(struct mmc_omap_host *host, struct mmc_command *cmd)+{+ int cmdreg = 0, resptype = 0, cmdtype = 0;++ mmc_clk_enable_aggressive(host);+ /* Clear status bits and enable interrupts */+ OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_STAT_CLEAR);++ resptype = 2;+ cmdreg = (MMC_READ_MULTIPLE_BLOCK << 24) | (resptype << 16) | (cmdtype << 22);+ cmdreg |= DP_SELECT | DDIR | MSBS | BCE | DMA_EN;+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);+ OMAP_HSMMC_WRITE(host->base, ARG, host->mod_addr);+ OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);+}+ /* * Configure the resptype, cmdtype and send the given command to the card */@@ -419,6 +473,11 @@ mmc_omap_start_command(struct mmc_omap_h } cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);+ if (cmd->opcode == MMC_SEND_CSD)+ host->rca = cmd->arg;+ if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK)+ host->org_addr = cmd->arg;+ if (cmd->opcode == MMC_READ_SINGLE_BLOCK || cmd->opcode == MMC_READ_MULTIPLE_BLOCK@@ -452,14 +511,14 @@ mmc_omap_start_command(struct mmc_omap_h } if (cmd->arg & OMAP_SDIO_READ) {-#ifdef CONFIG_OMAP_SDIO_NON_DMA_MODE+#ifdef CONFIG_OMAP_SDIO_NON_DMA_MODE cmdreg |= DP_SELECT; #else cmdreg |= DP_SELECT | DMA_EN | BCE | MSBS; #endif cmdreg &= ~(DDIR); } else {-#ifdef CONFIG_OMAP_SDIO_NON_DMA_MODE+#ifdef CONFIG_OMAP_SDIO_NON_DMA_MODE cmdreg |= DP_SELECT | DDIR; #else cmdreg |= DP_SELECT | DDIR | DMA_EN | BCE | MSBS;@@ -556,17 +615,24 @@ sdio_omap_xfer_done(struct mmc_omap_host static void mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) {- host->data = NULL;-- if (host->use_dma && host->dma_ch != -1) {- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,+ if(host->use_dma)+ {+ /* Un-map the memory required for DMA */+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, host->dma_dir); } + /* Reset the variables as transfer is complete */+ host->data = NULL;+ host->sg_len = 0;+ host->sg_dma_len = 0;+ host->datadir = OMAP_MMC_DATADIR_NONE; if (data->error == MMC_ERR_NONE) data->bytes_xfered += data->blocks * (data->blksz);+ else+ data->bytes_xfered = 0; mmc_clk_disable_aggressive(host); @@ -575,10 +641,51 @@ mmc_omap_xfer_done(struct mmc_omap_host mmc_request_done(host->mmc, data->mrq); return; }-+ /* Send the stop command. Remember FCLK is not stopped before this call */ mmc_omap_start_command(host, data->stop); } ++static void+mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)+{+ unsigned long flags;+ int done;++ if (!host->use_dma) {+ mmc_omap_xfer_done(host, data);+ return;+ }+ done = 0;+ spin_lock_irqsave(&host->dma_lock, flags);+ if (host->dma_done)+ done = 1;+ else+ host->brs_received = 1;+ spin_unlock_irqrestore(&host->dma_lock, flags);++ if (done)+ mmc_omap_xfer_done(host, data);+}+++static void+mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data)+{+ unsigned long flags;+ int done;++ done = 0;+ spin_lock_irqsave(&host->dma_lock, flags);+ if (host->brs_received)+ done = 1;+ else+ host->dma_done = 1;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ if (done)+ mmc_omap_xfer_done(host, data);+}+ /* * Notify the core about command completion */@@ -586,7 +693,6 @@ static void mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) { host->cmd = NULL;- if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { /* response type 2 */@@ -599,6 +705,29 @@ mmc_omap_cmd_done(struct mmc_omap_host * cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10); } }+ if(cmd->opcode == SD_APP_OP_COND)+ {+ if(cmd->resp[0] & 0x40000000)+ {+ host->is_high_capacity = 1;+ }+ else+ {+ host->is_high_capacity = 0;+ }+ }+ if(cmd->opcode == MMC_SEND_OP_COND)+ {+ if(cmd->resp[0] & 0x40000000)+ {+ host->is_high_capacity = 1;+ }+ else+ {+ host->is_high_capacity = 0;+ }+ }+ #ifdef CONFIG_OMAP_SDIO if (host->mmc->mode == MMC_MODE_SDIO) { if (host->sdiodata == NULL || cmd->error != MMC_ERR_NONE) {@@ -636,13 +765,27 @@ static void mmc_dma_cleanup(struct mmc_o host->data->error |= MMC_ERR_TIMEOUT; - if (host->use_dma && host->dma_ch != -1) {- dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,- host->dma_dir);- dma_ch = host->dma_ch;- host->dma_ch = -1;- omap_free_dma(dma_ch);- up(&host->sem);+ if(host->mmc->mode == MMC_MODE_SDIO)+ {+ if (host->use_dma && host->dma_ch != -1) {+ dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,+ host->dma_dir);+ dma_ch = host->dma_ch;+ host->dma_ch = -1;+ omap_free_dma(dma_ch);++ }+ }+ else+ {+ if (host->use_dma) {+ omap_stop_dma_chain_transfers(host->chain_id);+ dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->sg_len,+ host->dma_dir);+ omap_free_dma_chain(host->chain_id);+ mmc_omap_dma_done(host, host->data);+ host->chain_id = -1;+ } } host->data = NULL; #ifdef CONFIG_OMAP_SDIO@@ -696,16 +839,277 @@ static void sdio_non_dma_xfer(struct mmc } #endif +/* PIO only */+static void+mmc_omap_sg_to_buf(struct mmc_omap_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->total_bytes_left)+ host->buffer_bytes_left = host->total_bytes_left;+}+++/* PIO only */+static void+mmc_omap_xfer_data(struct mmc_omap_host *host, int write)+{+ int n;++ if (host->buffer_bytes_left == 0) {+ host->sg_idx++;+ BUG_ON(host->sg_idx == host->sg_len);+ mmc_omap_sg_to_buf(host);+ }+ n = 64;+ if (n > host->buffer_bytes_left)+ n = host->buffer_bytes_left;+ host->buffer_bytes_left -= n;+ host->total_bytes_left -= n;+ host->data->bytes_xfered += n;++ if (write) {+ __raw_writesw(host->base + OMAP_HSMMC_DATA, host->buffer, n);+ } else {+ __raw_readsw(host->base + OMAP_HSMMC_DATA, host->buffer, n);+ }+}+++/*+ * Configure the resptype, cmdtype and send the given command to the card+ */+static void+mmc_omap_start_command13(struct mmc_omap_host *host, struct mmc_command *cmd)+{+ int cmdreg = 0, resptype = 0, cmdtype = 0;+ unsigned long flags;++ mmc_clk_enable_aggressive(host);+ /* Clear status bits and enable interrupts */+ OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_STAT_CLEAR);+ resptype = 2;+ cmdreg = (MMC_SEND_STATUS << 24) | (resptype << 16) | (cmdtype << 22);++ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);+ OMAP_HSMMC_WRITE(host->base, ARG, host->rca);+ OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);+ spin_lock_irqsave(&host->dma_lock, flags);+ host->cmd_13 = 1;+ spin_unlock_irqrestore(&host->dma_lock, flags);+}++/*+ * Notify the core about command completion+ */+static void+mmc_omap_err_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)+{+ cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);+ mmc_clk_disable_aggressive(host);+ if(host->cmd_13 == 1)+ {+ if(cmd->resp[0] != 0x900)+ dev_dbg(mmc_dev(host->mmc),+ "%s:CMD response error cmd->resp[0]%x\n",+ mmc_hostname(host->mmc),cmd->resp[0]);+ }+}++++static int+mmc_omap_err_calc(struct mmc_omap_host *host)+{+ unsigned sg_len_remain;+ struct mmc_data *data = host->data;+ unsigned long flags;++ if(unlikely(host == NULL))+ {+ return -1;+ }+ /* Enable DMA */+ host->use_dma = 1;+ spin_lock_irqsave(&host->dma_lock, flags);++ if(host->extra_chain_reqd == 0)+ {+ if(host->data->sg_len <= NO_OF_DMA_CHAINS_USED)+ host->sg_idx = 0;+ else+ host->sg_idx = host->sg_idx-NO_OF_DMA_CHAINS_USED;+ }+ else+ {+ if(host->sg_idx == host->data->sg_len)+ host->sg_idx = host->data->sg_len;+ else+ host->sg_idx = host->sg_idx-NO_OF_DMA_CHAINS_USED;+ }+ if(host->sg_idx == host->data->sg_len)+ sg_len_remain =1;+ else+ sg_len_remain = data->sg_len - host->sg_idx;+ if(sg_len_remain >= NO_OF_DMA_CHAINS_USED)+ {+ host->chains_requested = NO_OF_DMA_CHAINS_USED;+ }+ else+ {+ host->chains_requested = 1;+ }+ if(host->data->sg_len <= NO_OF_DMA_CHAINS_USED)+ {+ host->extra_chain_reqd = 0;+ host->no_of_chain_reqd = 0;+ host->current_cb_cnt = 0;+ }+ else+ {+ host->no_of_chain_reqd = sg_len_remain/NO_OF_DMA_CHAINS_USED;+ host->extra_chain_reqd= sg_len_remain%NO_OF_DMA_CHAINS_USED;+ host->current_cb_cnt = 1;+ }+ spin_unlock_irqrestore(&host->dma_lock, flags);++ return 0;++}++++/*+ * Routine to configure block leangth for MMC/SD/SDIO cards+ * and intiate the transfer.+ */+static int+mmc_omap_err_prepare_data(struct mmc_omap_host *host)+{+ int i;+ unsigned count=0, count1=0;+ struct mmc_data *data = host->data;++ if(unlikely(host == NULL))+ {+ return -1;+ }+ mmc_clk_enable_aggressive(host); + 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;+ }++ for(i = 0 ;i < host->sg_idx; i++)+ {+ count1 += (sg_dma_len(&data->sg[i])/data->blksz);+ }++ for(i = host->sg_idx ;i < (host->chains_requested+host->sg_idx); i++)+ {+ count += (sg_dma_len(&data->sg[i])/data->blksz);+ }++ OMAP_HSMMC_WRITE(host->base, BLK, (host->data->blksz));+ OMAP_HSMMC_WRITE(host->base, BLK,+ OMAP_HSMMC_READ(host->base,+ BLK) | (count << 16));+ host->mod_addr = host->org_addr;+ if(host->is_high_capacity ==1)+ host->mod_addr += count1;//as card is high capacity+ else+ host->mod_addr += (count1*512);//as card is not high capacity+ host->datadir = (host->data->flags & MMC_DATA_WRITE) ?+ OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ;+ if (mmc_omap_get_dma_channel(host, data) == 0)+ {+ enum dma_data_direction dma_data_dir;++ if (data->flags & MMC_DATA_WRITE)+ dma_data_dir = DMA_TO_DEVICE;+ else+ dma_data_dir = DMA_FROM_DEVICE;+ host->total_bytes_left = 0;+ mmc_chain_dma(host, host->data);+ host->brs_received = 0;+ host->dma_done = 0;+ /* Enable DMA */+ host->use_dma = 1;+ }+ mmc_clk_disable_aggressive(host); + return 0;+}++/*+ * Notify the xfer done on MMC/SD cards to the core+ */+static void+mmc_omap_read_err_done(struct mmc_omap_host *host, struct mmc_data *data)+{+ unsigned long flags;++ spin_lock_irqsave(&host->dma_lock, flags);+ host->flag_err = 1;+ host->cmd_12 = 1;+ spin_unlock_irqrestore(&host->dma_lock, flags);+ mmc_clk_disable_aggressive(host);+ mmc_omap_start_command(host, data->stop);+}+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -