📄 full-h1940-2.6.21.patch
字号:
+ host->pio_words, host->pio_ptr);++ }++ if (fifo > host->pio_words)+ fifo = host->pio_words;++ host->pio_words-= fifo;+ host->pio_count+= fifo;++ while(fifo--) {+ writel(*(host->pio_ptr++), to_ptr);+ }+ }++ enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);+}++static void pio_tasklet(unsigned long data)+{+ struct s3cmci_host *host = (struct s3cmci_host *) data;+++ if (host->pio_active == XFER_WRITE)+ do_pio_write(host);++ if (host->pio_active == XFER_READ)+ do_pio_read(host);++ if (host->complete_what == COMPLETION_FINALIZE) {+ clear_imask(host);+ if (host->pio_active != XFER_NONE) {+ dbg(host, dbg_err, "unfinished %s "+ "- pio_count:[%u] pio_words:[%u]\n",+ (host->pio_active == XFER_READ)?"read":"write",+ host->pio_count, host->pio_words);++ host->mrq->data->error = MMC_ERR_DMA;+ }++ disable_irq(host->irq);+ finalize_request(host);+ }+}++/*+ * ISR for SDI Interface IRQ+ * Communication between driver and ISR works as follows:+ * host->mrq points to current request+ * host->complete_what tells the ISR when the request is considered done+ * COMPLETION_CMDSENT when the command was sent+ * COMPLETION_RSPFIN when a response was received+ * COMPLETION_XFERFINISH when the data transfer is finished+ * COMPLETION_XFERFINISH_RSPFIN both of the above.+ * host->complete_request is the completion-object the driver waits for+ *+ * 1) Driver sets up host->mrq and host->complete_what+ * 2) Driver prepares the transfer+ * 3) Driver enables interrupts+ * 4) Driver starts transfer+ * 5) Driver waits for host->complete_rquest+ * 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+ *+ * Note: "->error"-fields are expected to be set to 0 before the request+ * was issued by mmc.c - therefore they are only set, when an error+ * contition comes up+ */++static irqreturn_t s3cmci_irq(int irq, void *dev_id)+{+ struct s3cmci_host *host;+ struct mmc_command *cmd;+ u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;+ u32 mci_cclear, mci_dclear;+ unsigned long iflags;++ host = (struct s3cmci_host *)dev_id;++ spin_lock_irqsave(&host->complete_lock, iflags);++ mci_csta = readl(host->base + S3C2410_SDICMDSTAT);+ mci_dsta = readl(host->base + S3C2410_SDIDSTA);+ mci_dcnt = readl(host->base + S3C2410_SDIDCNT);+ mci_fsta = readl(host->base + S3C2410_SDIFSTA);+ mci_imsk = readl(host->base + host->sdiimsk);+ mci_cclear = 0;+ mci_dclear = 0;++ if ((host->complete_what == COMPLETION_NONE) ||+ (host->complete_what == COMPLETION_FINALIZE)) {+ host->status = "nothing to complete";+ clear_imask(host);+ goto irq_out;+ }++ if (!host->mrq) {+ host->status = "no active mrq";+ clear_imask(host);+ goto irq_out;+ }++ cmd = host->cmd_is_stop?host->mrq->stop:host->mrq->cmd;++ if (!cmd) {+ host->status = "no active cmd";+ clear_imask(host);+ goto irq_out;+ }++ if (!host->dodma) {+ if ((host->pio_active == XFER_WRITE) &&+ (mci_fsta & S3C2410_SDIFSTA_TFDET)) {++ disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);+ tasklet_schedule(&host->pio_tasklet);+ host->status = "pio tx";+ }++ if ((host->pio_active == XFER_READ) &&+ (mci_fsta & S3C2410_SDIFSTA_RFDET)) {++ disable_imask(host,+ S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST);++ tasklet_schedule(&host->pio_tasklet);+ host->status = "pio rx";+ }+ }++ if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {+ cmd->error = MMC_ERR_TIMEOUT;+ host->status = "error: command timeout";+ goto fail_transfer;+ }++ if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {+ if (host->complete_what == COMPLETION_CMDSENT) {+ host->status = "ok: command sent";+ goto close_transfer;+ }++ mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;+ }++ if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {+ if (cmd->flags & MMC_RSP_CRC) {+ if (host->is2440 || !(cmd->flags & MMC_RSP_136)) {+ cmd->error = MMC_ERR_BADCRC;+ host->status = "error: bad command crc";+ goto fail_transfer;+ }+ }+ mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;+ }++ if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) {+ if (host->complete_what == COMPLETION_RSPFIN) {+ host->status = "ok: command response received";+ goto close_transfer;+ }++ if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)+ host->complete_what = COMPLETION_XFERFINISH;++ mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;+ }++ /* errors handled after this point are only relevant+ when a data transfer is in progress */++ if (!cmd->data)+ goto clear_status_bits;++ /* Check for FIFO failure */+ if (host->is2440) {+ if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {+ host->mrq->data->error = MMC_ERR_FIFO;+ host->status = "error: 2440 fifo failure";+ goto fail_transfer;+ }+ } else {+ if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {+ cmd->data->error = MMC_ERR_FIFO;+ host->status = "error: fifo failure";+ goto fail_transfer;+ }+ }++ if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {+ cmd->data->error = MMC_ERR_BADCRC;+ host->status = "error: bad data crc (outgoing)";+ goto fail_transfer;+ }++ if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {+ cmd->data->error = MMC_ERR_BADCRC;+ host->status = "error: bad data crc (incoming)";+ goto fail_transfer;+ }++ if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {+ cmd->data->error = MMC_ERR_TIMEOUT;+ host->status = "error: data timeout";+ goto fail_transfer;+ }++ if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {+ if (host->complete_what == COMPLETION_XFERFINISH) {+ host->status = "ok: data transfer completed";+ goto close_transfer;+ }++ if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {+ host->complete_what = COMPLETION_RSPFIN;+ }++ mci_dclear |= S3C2410_SDIDSTA_XFERFINISH;+ }++clear_status_bits:+ writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);+ writel(mci_dclear, host->base + S3C2410_SDIDSTA);++ goto irq_out;++fail_transfer:+ host->pio_active = XFER_NONE;++close_transfer:+ host->complete_what = COMPLETION_FINALIZE;++ clear_imask(host);+ tasklet_schedule(&host->pio_tasklet);++ goto irq_out;++irq_out:+ dbg(host, dbg_irq, "csta:0x%08x dsta:0x%08x "+ "fsta:0x%08x dcnt:0x%08x status:%s.\n",+ mci_csta, mci_dsta, mci_fsta,+ mci_dcnt, host->status);++ spin_unlock_irqrestore(&host->complete_lock, iflags);+ return IRQ_HANDLED;++}++/*+ * ISR for the CardDetect Pin+*/++static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)+{+ struct s3cmci_host *host = (struct s3cmci_host *)dev_id;++ dbg(host, dbg_irq, "card detect\n");++ mmc_detect_change(host->mmc, 500);++ return IRQ_HANDLED;+}++void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, void *buf_id,+ int size, enum s3c2410_dma_buffresult result)+{+ unsigned long iflags;+ u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;+ struct s3cmci_host *host = (struct s3cmci_host *)buf_id;++ mci_csta = readl(host->base + S3C2410_SDICMDSTAT);+ mci_dsta = readl(host->base + S3C2410_SDIDSTA);+ mci_fsta = readl(host->base + S3C2410_SDIFSTA);+ mci_dcnt = readl(host->base + S3C2410_SDIDCNT);++ if ((!host->mrq) || (!host->mrq) || (!host->mrq->data))+ return;++ if (!host->dmatogo)+ return;++ spin_lock_irqsave(&host->complete_lock, iflags);++ if (result != S3C2410_RES_OK) {+ dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "+ "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",+ mci_csta, mci_dsta, mci_fsta,+ mci_dcnt, result, host->dmatogo);++ goto fail_request;+ }++ host->dmatogo--;+ if (host->dmatogo) {+ dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "+ "DCNT:[%08x] toGo:%u\n",+ size, mci_dsta, mci_dcnt, host->dmatogo);++ goto out;+ }++ dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",+ size, mci_dsta, mci_dcnt);++ host->complete_what = COMPLETION_FINALIZE;++out:+ tasklet_schedule(&host->pio_tasklet);+ spin_unlock_irqrestore(&host->complete_lock, iflags);+ return;+++fail_request:+ host->mrq->data->error = MMC_ERR_DMA;+ host->complete_what = COMPLETION_FINALIZE;+ writel(0, host->base + host->sdiimsk);+ goto out;++}++static void finalize_request(struct s3cmci_host *host)+{+ struct mmc_request *mrq = host->mrq;+ struct mmc_command *cmd = host->cmd_is_stop?mrq->stop:mrq->cmd;+ int debug_as_failure = 0;++ if (host->complete_what != COMPLETION_FINALIZE)+ return;++ if (!mrq)+ return;++ if (cmd->data && (cmd->error == MMC_ERR_NONE) &&+ (cmd->data->error == MMC_ERR_NONE)) {++ if (host->dodma && (!host->dma_complete)) {+ dbg(host, dbg_dma, "DMA Missing!\n");+ return;+ }+ }++ // Read response+ cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);+ cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);+ cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);+ cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);++ // reset clock speed, as it could still be set low for+ writel(host->prescaler, host->base + S3C2410_SDIPRE);++ if (cmd->error)+ debug_as_failure = 1;++ if (cmd->data && cmd->data->error)+ debug_as_failure = 1;++ //if(cmd->flags & MMC_RSP_MAYFAIL) debug_as_failure = 0;++#ifdef CONFIG_MMC_DEBUG+ dbg_dumpcmd(host, cmd, debug_as_failure);+#endif+ //Cleanup controller+ writel(0, host->base + S3C2410_SDICMDARG);+ writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);+ writel(0, host->base + S3C2410_SDICMDCON);+ writel(0, host->base + host->sdiimsk);++ if (cmd->data && cmd->error)+ cmd->data->error = cmd->error;++ if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {+ host->cmd_is_stop = 1;+ s3cmci_send_request(host->mmc);+ return;+ }++ // 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);+ } else {+ mrq->data->bytes_xfered = 0;+ }++ // If we had an error while transfering data we flush the+ // DMA channel and the fifo to clear out any garbage+ if (mrq->data->error != MMC_ERR_NONE) {+ if (host->dodma)+ s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);++ if (host->is2440) {+ //Clear failure register and reset fifo+ writel(S3C2440_SDIFSTA_FIFORESET |+ S3C2440_SDIFSTA_FIFOFAIL,+ host->base + S3C2410_SDIFSTA);+ } else {+ u32 mci_con;++ //reset fifo+ mci_con = readl(host->base + S3C2410_SDICON);+ mci_con|= S3C2410_SDICON_FIFORESET;++ writel(mci_con, host->base + S3C2410_SDICON);+ }+ }++request_done:+ host->complete_what = COMPLETION_NONE;+ host->mrq = NULL;+ mmc_request_done(host->mmc, mrq);+}+++void s3cmci_dma_setup(struct s3cmci_host *host, enum s3c2410_dmasrc source)+{+ static int setup_ok = 0;+ static enum s3c2410_dmasrc last_source = -1;++ if (last_source == source)+ return;++ last_source = source;++ s3c2410_dma_devconfig(host->dma, source, 3,+ host->mem->start + host->sdidata);++ if (!setup_ok) {+ s3c2410_dma_config(host->dma, 4,+ (S3C2410_DCON_HWTRIG | S3C2410_DCON_CH0_SDI));+ s3c2410_dma_set_buffdone_fn(host->dma, s3cmci_dma_done_callback);+ s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);+ setup_ok = 1;+ }+}++static void s3cmci_send_command(struct s3cmci_host *host,+ struct mmc_command *cmd)+{+ u32 ccon, imsk;++ imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |+ S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT |+ S3C2410_SDIIMSK_RESPONSECRC;++ enable_imask(host, imsk);++ if (cmd->data) {+ host->complete_what = COMPLETION_XFERFINISH_RSPFIN;+ } else if (cmd->flags & MMC_RSP_PRESENT) {+ host->complete_what = COMPLETION_RSPFIN;+ } else {+ host->complete_what = COMPLETION_CMDSENT;+ }++ writel(cmd->arg, host->base + S3C2410_SDICMDARG);++ ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX;+ ccon|= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;++ if (cmd->flags & MMC_RSP_PRESENT)+ ccon |= S3C2410_SDICMDCON_WAITRSP;++ if (cmd->flags & MMC_RSP_136)+ ccon|= S3C2410_SDICMDCON_LONGRSP;++ writel(ccon, host->base + S3C2410_SDICMDCON);+}++static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)+{+ u32 dcon, imsk, stoptries=3;++ /* write DCON register */++ if (!data) {+ writel(0, host->base + S3C2410_SDIDCON);+ return 0;+ }++ while(readl(host->base + S3C2410_SDIDSTA) &+ (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {++ dbg(host, dbg_err,+ "mci_setup_data() transfer stillin progress.\n");++ writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);+ s3cmci_reset(host);+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -