📄 full.patch
字号:
+ * 6) ISR checks for request status (errors and success)+ * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error+ * 7) ISR completes host->complete_request+ * 8) ISR disables interrupts+ * 9) Driver wakes up and takes care of the request+*/++static irqreturn_t s3c2410sdi_irq(int irq, void *dev_id, struct pt_regs *regs)+{+ struct s3c2410sdi_host *host;+ u32 sdi_csta, sdi_dsta, sdi_dcnt;+ u32 sdi_cclear, sdi_dclear;+ unsigned long iflags;++ host = (struct s3c2410sdi_host *)dev_id;++ //Check for things not supposed to happen+ if(!host) return IRQ_HANDLED;+ + sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);+ sdi_dsta = readl(host->base + S3C2410_SDIDSTA);+ sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);+ + DBG(PFX "IRQ csta=0x%08x dsta=0x%08x dcnt:0x%08x\n", sdi_csta, sdi_dsta, sdi_dcnt);+ + spin_lock_irqsave( &host->complete_lock, iflags);+ + if( host->complete_what==COMPLETION_NONE ) {+ goto clear_imask;+ }+ + if(!host->mrq) { + goto clear_imask;+ }++ + sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);+ sdi_dsta = readl(host->base + S3C2410_SDIDSTA);+ sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);+ sdi_cclear = 0;+ sdi_dclear = 0;+ + + if(sdi_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {+ host->mrq->cmd->error = MMC_ERR_TIMEOUT;+ goto transfer_closed;+ }++ if(sdi_csta & S3C2410_SDICMDSTAT_CMDSENT) {+ if(host->complete_what == COMPLETION_CMDSENT) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ goto transfer_closed;+ }++ sdi_cclear |= S3C2410_SDICMDSTAT_CMDSENT;+ }++ if(sdi_csta & S3C2410_SDICMDSTAT_CRCFAIL) {+ if(host->mrq->cmd->flags & MMC_RSP_CRC) {+ host->mrq->cmd->error = MMC_ERR_BADCRC;+ goto transfer_closed;+ }++ sdi_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;+ }++ if(sdi_csta & S3C2410_SDICMDSTAT_RSPFIN) {+ if(host->complete_what == COMPLETION_RSPFIN) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ goto transfer_closed;+ }++ if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ host->complete_what = COMPLETION_XFERFINISH;+ }++ sdi_cclear |= S3C2410_SDICMDSTAT_RSPFIN;+ }++ if(sdi_dsta & S3C2410_SDIDSTA_FIFOFAIL) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ host->mrq->data->error = MMC_ERR_FIFO;+ goto transfer_closed;+ }++ if(sdi_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ host->mrq->data->error = MMC_ERR_BADCRC;+ goto transfer_closed;+ }++ if(sdi_dsta & S3C2410_SDIDSTA_CRCFAIL) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ host->mrq->data->error = MMC_ERR_BADCRC;+ goto transfer_closed;+ }++ if(sdi_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ host->mrq->data->error = MMC_ERR_TIMEOUT;+ goto transfer_closed;+ }++ if(sdi_dsta & S3C2410_SDIDSTA_XFERFINISH) {+ if(host->complete_what == COMPLETION_XFERFINISH) {+ host->mrq->cmd->error = MMC_ERR_NONE;+ host->mrq->data->error = MMC_ERR_NONE;+ goto transfer_closed;+ }++ if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {+ host->mrq->data->error = MMC_ERR_NONE;+ host->complete_what = COMPLETION_RSPFIN;+ }++ sdi_dclear |= S3C2410_SDIDSTA_XFERFINISH;+ }++ writel(sdi_cclear, host->base + S3C2410_SDICMDSTAT);+ writel(sdi_dclear, host->base + S3C2410_SDIDSTA);++ spin_unlock_irqrestore( &host->complete_lock, iflags);+ DBG(PFX "IRQ still waiting.\n");+ return IRQ_HANDLED;+++transfer_closed:+ host->complete_what = COMPLETION_NONE;+ complete(&host->complete_request);+ writel(0, host->base + S3C2410_SDIIMSK);+ spin_unlock_irqrestore( &host->complete_lock, iflags);+ DBG(PFX "IRQ transfer closed.\n");+ return IRQ_HANDLED;+ +clear_imask:+ writel(0, host->base + S3C2410_SDIIMSK);+ spin_unlock_irqrestore( &host->complete_lock, iflags);+ DBG(PFX "IRQ clear imask.\n");+ return IRQ_HANDLED;++}+++/*+ * ISR for the CardDetect Pin+*/++static irqreturn_t s3c2410sdi_irq_cd(int irq, void *dev_id, struct pt_regs *regs)+{+ struct s3c2410sdi_host *host = (struct s3c2410sdi_host *)dev_id;+ mmc_detect_change(host->mmc);++ return IRQ_HANDLED;+}++++void s3c2410sdi_dma_done_callback(s3c2410_dma_chan_t *dma_ch, void *buf_id,+ int size, s3c2410_dma_buffresult_t result)+{ unsigned long iflags;+ u32 sdi_csta, sdi_dsta,sdi_dcnt;+ struct s3c2410sdi_host *host = (struct s3c2410sdi_host *)buf_id;+ + sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);+ sdi_dsta = readl(host->base + S3C2410_SDIDSTA);+ sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);+ + DBG(PFX "DMAD csta=0x%08x dsta=0x%08x dcnt:0x%08x result:0x%08x\n", sdi_csta, sdi_dsta, sdi_dcnt, result);+ + spin_lock_irqsave( &host->complete_lock, iflags);+ + if(!host->mrq) goto out;+ if(!host->mrq->data) goto out;+ + + sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);+ sdi_dsta = readl(host->base + S3C2410_SDIDSTA);+ sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);+ + if( result!=S3C2410_RES_OK ) {+ goto fail_request;+ }+ + + if(host->mrq->data->flags & MMC_DATA_READ) {+ if( sdi_dcnt>0 ) {+ goto fail_request;+ }+ }+ +out: + complete(&host->complete_dma);+ spin_unlock_irqrestore( &host->complete_lock, iflags);+ return;+++fail_request:+ host->mrq->data->error = MMC_ERR_DMA;+ host->complete_what = COMPLETION_NONE;+ complete(&host->complete_dma);+ complete(&host->complete_request);+ writel(0, host->base + S3C2410_SDIIMSK);+ goto out;++}+++void s3c2410sdi_dma_setup(struct s3c2410sdi_host *host, eDMAPurpose_t purpose) {+ s3c2410_dmasrc_t source;++ switch(purpose) {+ default:+ case DMAP_READ:+ source = S3C2410_DMASRC_HW;+ break;++ case DMAP_WRITE:+ source = S3C2410_DMASRC_MEM;+ break;+ }++ s3c2410_dma_devconfig(host->dma, source, 3, host->mem->start + S3C2410_SDIDATA);+ s3c2410_dma_config(host->dma, 4, (1<<23) | (2<<24));+ s3c2410_dma_set_buffdone_fn(host->dma, s3c2410sdi_dma_done_callback);+ s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);+}++static void s3c2410sdi_request(struct mmc_host *mmc, struct mmc_request *mrq) {+ struct s3c2410sdi_host *host = mmc_priv(mmc);+ u32 sdi_carg, sdi_ccon, sdi_timer;+ u32 sdi_bsize, sdi_dcon, sdi_imsk;++ DBG(KERN_DEBUG PFX "request: [CMD] opcode:0x%02x arg:0x%08x flags:%x retries:%u\n",+ mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags, mrq->cmd->retries);+++ sdi_ccon = mrq->cmd->opcode & S3C2410_SDICMDCON_INDEX;+ sdi_ccon|= S3C2410_SDICMDCON_SENDERHOST;+ sdi_ccon|= S3C2410_SDICMDCON_CMDSTART;++ sdi_carg = mrq->cmd->arg;++ //FIXME: Timer value ?!+ sdi_timer= 0xF000;++ sdi_bsize= 0;+ sdi_dcon = 0;+ sdi_imsk = 0;++ //enable interrupts for transmission errors+ sdi_imsk |= S3C2410_SDIIMSK_RESPONSEND;+ sdi_imsk |= S3C2410_SDIIMSK_CRCSTATUS;+++ host->complete_what = COMPLETION_CMDSENT;++ if (mrq->cmd->flags & MMC_RSP_MASK) {+ host->complete_what = COMPLETION_RSPFIN;++ sdi_ccon |= S3C2410_SDICMDCON_WAITRSP;+ sdi_imsk |= S3C2410_SDIIMSK_CMDTIMEOUT;++ } else {+ //We need the CMDSENT-Interrupt only if we want are not waiting+ //for a response+ sdi_imsk |= S3C2410_SDIIMSK_CMDSENT;+ }++ if(mrq->cmd->flags & MMC_RSP_LONG) {+ sdi_ccon|= S3C2410_SDICMDCON_LONGRSP;+ }++ if(mrq->cmd->flags & MMC_RSP_CRC) {+ sdi_imsk |= S3C2410_SDIIMSK_RESPONSECRC;+ }+++ if (mrq->data) {+ host->complete_what = COMPLETION_XFERFINISH_RSPFIN;++++ sdi_bsize = (1 << mrq->data->blksz_bits);++ sdi_dcon = (mrq->data->blocks & S3C2410_SDIDCON_BLKNUM_MASK);+ sdi_dcon |= S3C2410_SDIDCON_DMAEN;++ sdi_imsk |= S3C2410_SDIIMSK_FIFOFAIL;+ sdi_imsk |= S3C2410_SDIIMSK_DATACRC;+ sdi_imsk |= S3C2410_SDIIMSK_DATATIMEOUT;+ sdi_imsk |= S3C2410_SDIIMSK_DATAFINISH;+ sdi_imsk |= 0xFFFFFFE0;++ DBG(PFX "request: [DAT] bsize:%u blocks:%u bytes:%u\n",+ sdi_bsize, mrq->data->blocks, mrq->data->blocks * sdi_bsize);++ if(mrq->data->flags & MMC_DATA_WIDE) {+ sdi_dcon |= S3C2410_SDIDCON_WIDEBUS;+ }++ if(!(mrq->data->flags & MMC_DATA_STREAM)) {+ sdi_dcon |= S3C2410_SDIDCON_BLOCKMODE;+ }++ if(mrq->data->flags & MMC_DATA_WRITE) {+ sdi_dcon |= S3C2410_SDIDCON_TXAFTERRESP;+ sdi_dcon |= S3C2410_SDIDCON_XFER_TXSTART;+ s3c2410sdi_dma_setup(host, DMAP_WRITE);+#ifdef S3C2410SDI_DMA_BACKBUF + memcpy(host->dmabuf_log, mrq->data->req->buffer, mrq->data->blocks * sdi_bsize);+#endif+ }++ if(mrq->data->flags & MMC_DATA_READ) {+ sdi_dcon |= S3C2410_SDIDCON_RXAFTERCMD;+ sdi_dcon |= S3C2410_SDIDCON_XFER_RXSTART;+ s3c2410sdi_dma_setup(host, DMAP_READ);+ }+ + ++ //start DMA+#ifdef S3C2410SDI_DMA_BACKBUF+ s3c2410_dma_enqueue(host->dma, (void *) host,+ host->dmabuf_phys,+ (mrq->data->blocks << mrq->data->blksz_bits) );+#else+ s3c2410_dma_enqueue(host->dma, (void *) host,+ virt_to_phys(mrq->data->req->buffer),+ (mrq->data->blocks << mrq->data->blksz_bits) );+#endif+ }++ host->mrq = mrq;++ init_completion(&host->complete_request);+ init_completion(&host->complete_dma);++ //Clear command and data status registers+ writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);+ writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);++ // Setup SDI controller+ writel(sdi_bsize,host->base + S3C2410_SDIBSIZE);+ writel(sdi_timer,host->base + S3C2410_SDITIMER);+ writel(sdi_imsk,host->base + S3C2410_SDIIMSK);++ // Setup SDI command argument and data control+ writel(sdi_carg, host->base + S3C2410_SDICMDARG);+ writel(sdi_dcon, host->base + S3C2410_SDIDCON);++ // This initiates transfer+ writel(sdi_ccon, host->base + S3C2410_SDICMDCON);++ // Wait for transfer to complete+ wait_for_completion(&host->complete_request);+ DBG("[CMD] request complete.\n");+ if(mrq->data) {+ wait_for_completion(&host->complete_dma);+ DBG("[DAT] DMA complete.\n");+ }+ + // Wait for DMA to complete+// if(mrq->data) wait_for_completion(&host->complete_dma);++ //Cleanup controller+ writel(0, host->base + S3C2410_SDICMDARG);+ writel(0, host->base + S3C2410_SDIDCON);+ writel(0, host->base + S3C2410_SDICMDCON);+ writel(0, host->base + S3C2410_SDIIMSK);++ // Read response+ mrq->cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);+ mrq->cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);+ mrq->cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);+ mrq->cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);++ host->mrq = NULL;++ DBG(PFX "request done.\n");++ // If we have no data transfer we are finished here+ if (!mrq->data) goto request_done;++ // Calulate the amout of bytes transfer, but only if there was+ // no error+ if(mrq->data->error == MMC_ERR_NONE) {+ mrq->data->bytes_xfered = (mrq->data->blocks << mrq->data->blksz_bits);+ if(mrq->data->flags & MMC_DATA_READ);+#ifdef S3C2410SDI_DMA_BACKBUF+ memcpy(mrq->data->req->buffer, host->dmabuf_log, mrq->data->bytes_xfered);+#endif+ } else {+ mrq->data->bytes_xfered = 0;+ }++ // If we had an error while transfering data we flush the+ // DMA channel to clear out any garbage+ if(mrq->data->error != MMC_ERR_NONE) {+ s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);+ DBG(PFX "flushing DMA.\n"); + }+ // Issue stop command+ if(mrq->data->stop) mmc_wait_for_cmd(mmc, mrq->data->stop, 3);+++request_done:++ mrq->done(mrq);+}++static void s3c2410sdi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) {+ struct s3c2410sdi_host *host = mmc_priv(mmc);+ u32 sdi_psc, sdi_con;++ //Set power+ sdi_con = readl(host->base + S3C2410_SDICON);+ switch(ios->power_mode) {+ case MMC_POWER_ON:+ case MMC_POWER_UP:+ s3c2410_gpio_setpin(S3C2410_GPA17, 1); // card power on++ s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK);+ s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD);+ s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0);+ s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);+ s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2);+ s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3);++ sdi_con|= S3C2410_SDICON_FIFORESET;+ break;++ case MMC_POWER_OFF:+ default:+ s3c2410_gpio_setpin(S3C2410_GPA17, 0); // card power off++ s3c2410_gpio_setpin(S3C2410_GPE5, 0);+ s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);+ break;+ }++ //Set clock+ for(sdi_psc=0;sdi_psc<255;sdi_psc++) {+ if( (clk_get_rate(host->clk) / (2*(sdi_psc+1))) <= ios->clock) break;+ }++ if(sdi_psc > 255) sdi_psc = 255;+ writel(sdi_psc, host->base + S3C2410_SDIPRE);++ //Set CLO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -