📄 mhn_controller.c
字号:
pxa_host->data = llreq->data; pxa_host->llreq = llreq; cmd = pxa_host->cmd; dbg("Read to send CMD :0x%x, cmd flag 0x%x", cmd->opcode, cmd->flags); if (cmd->flags & MSS_CMD_INIT) cmd_dat |= MMC_CMDAT_INIT; if (cmd->flags & MSS_CMD_STOP) cmd_dat |= MMC_CMDAT_STOP; if (cmd->flags & MSS_CMD_SDIO_EN || host->sdio_int) cmd_dat |= MMC_CMDAT_SDIO_INT; if (llreq->data) { dbg("data flags 0x%x", llreq->data->flags); if (llreq->data->flags & MSS_DATA_WRITE) cmd_dat |= MMC_CMDAT_WRITE; pxa_host_setup_data(pxa_host, llreq->data); cmd_dat |= (MMC_CMDAT_DATA | MMC_CMDAT_DMA); cmd_dat &= ~MMC_CMDAT_BUSY; dbg("data nob %d, block_len %d", llreq->data->blocks, llreq->data->blksz); if (llreq->data->flags & MSS_DATA_STREAM) cmd_dat |= MMC_CMDAT_STREAM; } else { writel(0, pxa_host->base + MMC_NUMBLK); writel(0, pxa_host->base + MMC_BLKLEN); } dbg("cmd rtype %d", cmd->rtype); switch (cmd->rtype) { case MSS_RESPONSE_NONE: cmd_dat |= MMC_CMDAT_RESP_FMT_NONE; break; case MSS_RESPONSE_R1B: cmd_dat |= MMC_CMDAT_BUSY; // Fall through case MSS_RESPONSE_R1: case MSS_RESPONSE_R4: case MSS_RESPONSE_R5: case MSS_RESPONSE_R6: case MSS_RESPONSE_R7: cmd_dat |= MMC_CMDAT_RESP_FMT_R1; break; case MSS_RESPONSE_R2_CID: case MSS_RESPONSE_R2_CSD: cmd_dat |= MMC_CMDAT_RESP_FMT_R2; break; case MSS_RESPONSE_R3: cmd_dat |= MMC_CMDAT_RESP_FMT_R3; break; } dbg("card bus width %d", card->bus_width); if (card->bus_width == MSS_BUSWIDTH_4BIT) cmd_dat |= MMC_CMDAT_4DAT; writel(cmd->opcode, pxa_host->base + MMC_CMD); writel(cmd->arg >> 16, pxa_host->base + MMC_ARGH); writel(cmd->arg & 0xffff, pxa_host->base + MMC_ARGL); writel(cmd_dat, pxa_host->base + MMC_CMDAT); dbg("Read out MMC_CMD 0x%x",readl(pxa_host->base+MMC_CMD)); dbg("Read out MMC_ARGH 0x%x",readl(pxa_host->base+MMC_ARGH)); dbg("Read out MMC_ARGL 0x%x",readl(pxa_host->base+MMC_ARGL)); dbg("Read out MMC_CMDAT 0x%x",readl(pxa_host->base+MMC_CMDAT)); dbg("Read out MMC_CLKRT 0x%x",readl(pxa_host->base+MMC_CLKRT)); dbg("Read out MMC_NUMBLK 0x%x",readl(pxa_host->base+MMC_NUMBLK)); dbg("Read out MMC_BLKSZ 0x%x",readl(pxa_host->base+MMC_BLKLEN)); if (llreq->data && llreq->data->sg_len) { pxa_host->dma_run = 1; DDADR(pxa_host->dma) = pxa_host->sg_dma; /* start DMA */ DCSR(pxa_host->dma) |= DCSR_RUN; dbg("enable dma %d, DDADR: 0x%x, DCSR: 0x%x", pxa_host->dma, DDADR(pxa_host->dma), DCSR(pxa_host->dma)); } pxa_host_enable_int(pxa_host, MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR); }static void pxa_mss_enable_sdio_int(struct mss_host *host, int enable){ unsigned long flags; struct pxa_mss_host *pxa_host = host->private; local_irq_save(flags); if (enable) { host->sdio_int = MSS_SDIO_INT_EN; pxa_host_enable_int(pxa_host, MMC_I_MASK_SDIO_INT); } else { host->sdio_int = MSS_SDIO_INT_DIS; pxa_host_disable_int(pxa_host, MMC_I_MASK_SDIO_INT); } local_irq_restore(flags);}/* * DMA irq handler. devid represent pxa_mss_controller_device for dma interrupt * is to pxa_controller */static void pxa_host_dma_irq(int dma, void *devid, struct pt_regs *regs){ unsigned int dcsr; struct pxa_mss_host *pxa_host; struct mss_card *card; struct mss_cmd *cmd; struct mss_data *data; dbg("DMA IRQ"); pxa_host = (struct pxa_mss_host *)devid; card = pxa_host->host->active_card; data = pxa_host->data; if (!card) { printk(KERN_ERR "Can not find card\n"); BUG(); } cmd = pxa_host->cmd; dcsr = DCSR(dma); DCSR(dma) &= ~DCSR_STOPIRQEN; dbg("dma int dcsr:0x%x, DSADR:0x%x, DCMD:0x%x", dcsr, DSADR(dma), DCMD(dma)); if (dcsr & DCSR_BUSERR) { /* dbg("DCSR_BUSEER"); */ cmd->error = MSS_ERROR_DMA; data->bytes_xfered = 0; pxa_host_disable_int(pxa_host, MMC_I_MASK_DATA_TRAN_DONE | MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT); pxa_host->llreq->done(pxa_host->llreq); } else if (dcsr & DCSR_STOPSTATE) { if (data && (data->flags & MSS_DATA_WRITE)) writel(BUF_PART_FULL, pxa_host->base + MMC_PRTBUF); if (data && (data->flags & MSS_DATA_WRITE) && cmd->rtype == MSS_RESPONSE_R1B) pxa_host_enable_int(pxa_host, MMC_I_REG_PRG_DONE); /* dbg("sg index:%d, dma_len:%d", pxa_host->sg_idx, pxa_host->dma_len); */ else if (data && (data->flags & (MSS_DATA_WRITE | MSS_DATA_READ))) { pxa_host_enable_int(pxa_host, MMC_I_MASK_DATA_TRAN_DONE | MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT); } else { printk(KERN_ERR "ERROR in SLOT_DMA_IRQ, neither WRITE" " nor READ or sg_idx exceed dma_len"); dump_stack(); } } pxa_host->dma_run = 0; return; }/* * slot INT routine for commands with R1B response type */static int pxa_host_r1b_irq(struct pxa_mss_host *pxa_host, u32 ireg, u32 stat, u32 mask){ struct mss_host *host; struct mss_cmd *cmd; /* dbg("host%d, I_REG: 0x%x, STAT: 0x%x, MASK: 0x%x\n", pxa_host->host->id, (u32)ireg, (u32)stat, (u32)mask); */ host = pxa_host->host; cmd = pxa_host->cmd; if ((ireg & MMC_I_REG_END_CMD_RES) && (!(mask & MMC_I_MASK_END_CMD_RES)) ) { pxa_host_disable_int(pxa_host, MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR); pxa_host_get_response(pxa_host, cmd); if (ireg & MMC_I_REG_RES_ERR) { pxa_host_set_error(cmd, stat); /* dbg("in RES_ERROR, prepare to cmd_complete");*/ pxa_host->llreq->done(pxa_host->llreq); return 1; } pxa_host_enable_int(pxa_host, MMC_I_MASK_PRG_DONE); return 1; } if ((ireg & MMC_I_REG_PRG_DONE) && (!(mask & MMC_I_MASK_PRG_DONE)) ) { pxa_host_disable_int(pxa_host, MMC_I_MASK_PRG_DONE); /* dbg("in PRG_DONE, prepare to cmd_complete\n"); */ pxa_host->llreq->done(pxa_host->llreq); } return 1;}/* * slot INT routine for write commands with data buffer */static int pxa_host_write_irq(struct pxa_mss_host *pxa_host, u32 ireg, u32 stat, u32 mask){ struct mss_host *host; struct mss_cmd *cmd; host = pxa_host->host; cmd = pxa_host->cmd; if ((ireg & MMC_I_REG_END_CMD_RES) && \ (!(mask & MMC_I_MASK_END_CMD_RES))) { pxa_host_disable_int(pxa_host, MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR); if (ireg & MMC_I_REG_RES_ERR) { pxa_host_set_error(cmd, stat); /* dbg("in RES_ERROR, prepare to cmd_complete"); */ pxa_host->llreq->done(pxa_host->llreq); return 1; } pxa_host_get_response(pxa_host, cmd); return 1; } if ((ireg & (MMC_I_REG_DAT_ERR | MMC_I_REG_TINT)) && (!(mask & (MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT)))) { stat = readl(pxa_host->base + MMC_STAT); pxa_host_disable_int(pxa_host, MMC_I_MASK_DATA_TRAN_DONE | \ MMC_I_MASK_DAT_ERR | \ MMC_I_MASK_TINT); pxa_host_set_error(cmd, stat); /* dbg("DATA/TIMEOUT error. I_REG: 0x%x, STAT: 0x%x, I_MASK: 0x%x. prepare to cmd_complete", MMC_I_REG, MMC_STAT, MMC_I_MASK); */ pxa_host->llreq->done(pxa_host->llreq); return 1; } /* wait for DMA interrupt, DATA WRITE done once DATA_TRAN_DONE * interrupt occurred */ if ((ireg & MMC_I_REG_DATA_TRAN_DONE) && (!(mask & MMC_I_MASK_DATA_TRAN_DONE)) ) { /* Note: must not disable DATA_ERROR interrupt, * for it may be occured again!!! */ pxa_host_disable_int(pxa_host, MMC_I_MASK_DATA_TRAN_DONE | MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT); pxa_host_enable_int(pxa_host, MMC_I_MASK_PRG_DONE); return 1; } if ((ireg & MMC_I_REG_PRG_DONE) && (!(mask & MMC_I_MASK_PRG_DONE)) ) { //pxa_host_get_response(pxa_host, cmd); pxa_host_disable_int(pxa_host, MMC_I_MASK_PRG_DONE); /* dbg("in PRG_DONE, prepare to cmd_complete"); */ pxa_host->llreq->done(pxa_host->llreq); } return 1;}/** * pxa_slot_read_irq * @card: mss_card_device * @ireg: value of MMCx_I_REG * @stat: value of MMCx_STAT * @mask: value of MMCx_I_MASK * * slot INT routine for read commands with data buffer */static int pxa_host_read_irq(struct pxa_mss_host *pxa_host, u32 ireg, u32 stat, u32 mask){ struct mss_host *host; struct mss_cmd *cmd; host = pxa_host->host; cmd = pxa_host->cmd; if ((ireg & MMC_I_REG_END_CMD_RES) && (!(mask & MMC_I_MASK_END_CMD_RES))) { pxa_host_disable_int(pxa_host, MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR); if (ireg & MMC_I_REG_RES_ERR) { pxa_host_set_error(cmd, stat); pxa_host->llreq->done(pxa_host->llreq); return 1; } pxa_host_get_response(pxa_host, cmd); /* DATA_TRAN_DONE is not enabled now */ pxa_host_enable_int(pxa_host, MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT); return 1; } if ((ireg & (MMC_I_REG_DAT_ERR | MMC_I_REG_TINT)) && \ (!(mask & (MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT)))) { stat = readl(pxa_host->base + MMC_STAT); pxa_host_disable_int(pxa_host, MMC_I_MASK_DATA_TRAN_DONE | \ MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT); pxa_host_set_error(cmd, stat); /* dbg("DATA/TIMEOUT error. I_REG: 0x%x, STAT: 0x%x, I_MASK: 0x%x. prepare to cmd_complete", readl(pxa_host->base + MMC_I_REG), readl(pxa_host->base + MMC_STAT), readl(pxa_host->base + MMC_I_MASK)); */ pxa_host->llreq->done(pxa_host->llreq); } /* wait for DMA interrupt, DATA READ done * once DATA_TRAN_DONE interrupt occurred */ if ((ireg & MMC_I_REG_DATA_TRAN_DONE) && \ (!(mask & MMC_I_MASK_DATA_TRAN_DONE))) { pxa_host_disable_int(pxa_host, \ MMC_I_MASK_DATA_TRAN_DONE | \ MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT); /* dbg("in DATA_TRAN_DONE, prepare to cmd_complete");*/ pxa_host->llreq->done(pxa_host->llreq); return 1; } return 1;}/** * pxa_slot_other_irq * @card: mss_card_device * @ireg: value of MMCx_I_REG * @stat: value of MMCx_STAT * @mask: value of MMCx_I_MASK * * slot INT routine for commands other than R1B, write and read commands */static int pxa_host_other_irq(struct pxa_mss_host *pxa_host, u32 ireg, u32 stat, u32 mask){ struct mss_cmd *cmd = pxa_host->cmd; if ((ireg & MMC_I_REG_RES_ERR) && (!(mask & MMC_I_MASK_RES_ERR))){ dbg("pxa_host_other_irq:1 branch \n"); pxa_host_disable_int(pxa_host, MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR); pxa_host_get_response(pxa_host, cmd); pxa_host_set_error(cmd, stat); /* dbg("in RES_ERROR, prepare to cmd_complete\n"); */ pxa_host->llreq->done(pxa_host->llreq); return 1; } else if((ireg & MMC_I_REG_END_CMD_RES) && \ (!(mask & MMC_I_MASK_END_CMD_RES))) { dbg("pxa_host_other_irq:2 branch \n"); pxa_host_disable_int(pxa_host, MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR); pxa_host_get_response(pxa_host, cmd); pxa_host->llreq->done(pxa_host->llreq); } return 1;}/** * pxa_slot_irq * @irq: IRQ number * @devid: pointer to pxa_mss_controller_device * @regs: interrupt context * * response interrupt and sdio interrupt handler. * devid represent pxa_mss_controller_device because * interrupt is to pxa_controller */static irqreturn_t pxa_host_irq(int irq, void *devid, struct pt_regs *regs){ struct pxa_mss_host *pxa_host; struct mss_cmd *cmd; struct mss_data *data; struct mss_driver *drv; struct mss_card *card; u32 ireg, stat, mask; pxa_host = (struct pxa_mss_host *)devid; cmd = pxa_host->cmd; data = pxa_host->data; card = pxa_host->host->active_card; ireg = readl(pxa_host->base + MMC_I_REG); stat = readl(pxa_host->base + MMC_STAT); mask = readl(pxa_host->base + MMC_I_MASK); dbg("host%d irq, I_REG:0x%x, STAT:0x%x, I_MASK:0x%x, CLKRT:0x%x," "RESTO:0x%x, RDTO:0x%x\n", pxa_host->host->id, ireg, stat, mask, readl(pxa_host->base + MMC_CLKRT), readl(pxa_host->base + MMC_RESTO), readl(pxa_host->base + MMC_RDTO)); if (data) { if (data->flags & MSS_DATA_WRITE) { pxa_host_write_irq(pxa_host, ireg, stat, mask); } if (data->flags & MSS_DATA_READ) { pxa_host_read_irq(pxa_host, ireg, stat, mask); } } else if ((cmd->rtype == MSS_RESPONSE_R1B) && (!data || !data->sg_len)) pxa_host_r1b_irq(pxa_host, ireg, stat, mask); else pxa_host_other_irq(pxa_host, ireg, stat, mask); /* handle sdio interrupt, wakeup sdio int IRQ handler thread */ if ((ireg & MMC_I_REG_SDIO_INT) && (!(mask & MMC_I_MASK_SDIO_INT))) { struct pxa_slot *pxa_slot = pxa_host->active_slot->private; dbg("SDIO interrupt ocurred\n"); pxa_host_disable_int(pxa_host, MMC_I_MASK_SDIO_INT); pxa_host->host->sdio_int = MSS_SDIO_INT_DIS; if (!pxa_host->active_slot->card || !pxa_host->active_slot->card->dev.driver) return IRQ_HANDLED; drv = container_of(pxa_host->active_slot->card->dev.driver, struct mss_driver, driver); INIT_WORK(&pxa_slot->sdio_int, (void (*)(void *))drv->sdio_int_handler, pxa_host->active_slot->card); queue_work(pxa_host->sdio_work_queue, &pxa_slot->sdio_int); } return IRQ_HANDLED;}/** * pxa_slot_gpio_irq * @irq: IRQ number * @devid: pointer to mss_slot * @regs: interrupt context * * hot-plug interrupt handler. devid represent slot * because hot-plug is slot-specific. */static irqreturn_t pxa_slot_gpio_irq(int irq, void *devid, struct pt_regs *regs){ struct mss_slot *slot = (struct mss_slot *)devid; struct pxa_slot *pxa_slot = slot->private; struct pxa_mss_host *pxa_host = slot->host->private; dbg("Slot :%d, inttrupt", slot->id); queue_delayed_work(pxa_host->work_queue, &pxa_slot->card_change, 20); return IRQ_HANDLED; }#if 0static int pxa_slot_work_thread(void *data){ struct mss_slot *slot = data; struct pxa_slot *pxa_slot = slot->private; DECLARE_WAITQUEUE(wait, current); current->flags |= PF_MEMALLOC; daemonize("pxaslot%d.%d", slot->host->id, slot->id); complete(&pxa_slot->thread_complete); down(&pxa_slot->thread_sem); add_wait_queue(&pxa_slot->thread_wq, &wait); do { try_to_freeze(); if (pxa_slot->flags & PXA_SLOT_SCAN) { pxa_slot->flags &= ~PXA_SLOT_SCAN; mss_scan_slot(slot); } set_current_state(TASK_INTERRUPTIBLE); if (pxa_slot->flags & PXA_SLOT_EXIT) break; up(&pxa_slot->thread_sem); schedule(); down(&pxa_slot->thread_sem); set_current_state(TASK_RUNNING); } while(1); remove_wait_queue(&pxa_slot->thread_wq, &wait); up(&pxa_slot->thread_sem); complete_and_exit(&pxa_slot->thread_complete, 0);}#endifvoid pxa_slot_card_change(struct mss_slot *slot){ /* struct pxa_mss_host *pxa_host = slot->host->private; */ struct mss_card *card = slot->card; while (card && card->state == MSS_CARD_SUSPENDED) schedule_timeout(20); /* if (pxa_host->suspend) { set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&pxa_host->suspend_wq, &wait); schedule(); set_current_state(TASK_RUNNING); }*/ mss_scan_slot(slot);}/* init slot, request IRQ for slot, register mss_slot to core, initialize card * if inserted */static int pxa_slot_init(struct pxa_mss_host *pxa_host, int slotid){ struct mss_slot *slot; struct pxa_slot *pxa_slot;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -