📄 bvd_mmc.c
字号:
/* Setup DMA if necessary */ switch (request->cmd) { case MMC_READ_SINGLE_BLOCK: case MMC_READ_MULTIPLE_BLOCK: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_DATA_DONE | MMC_EVENT_RX_DMA_DONE | MMC_EVENT_CLK_OFF); bvd_mmc_dma_rx_start(&bvd_mmc_data); break; case MMC_WRITE_BLOCK: case MMC_WRITE_MULTIPLE_BLOCK: case MMC_PROGRAM_CID: case MMC_PROGRAM_CSD: case MMC_SEND_WRITE_PROT: case MMC_GEN_CMD: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_DATA_DONE | MMC_EVENT_TX_DMA_DONE | MMC_EVENT_PROG_DONE | MMC_EVENT_CLK_OFF); bvd_mmc_dma_tx_start(&bvd_mmc_data); break; case MMC_LOCK_UNLOCK: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_DATA_DONE | MMC_EVENT_PROG_DONE | MMC_EVENT_CLK_OFF); break; case MMC_WRITE_DAT_UNTIL_STOP: case MMC_READ_DAT_UNTIL_STOP: printk(KERN_ERR "Unsupported MMC data transfer command: %d\n", request->cmd); bvd_mmc_wait_for(0); break; case SEND_SCR: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_DATA_DONE | MMC_EVENT_CLK_OFF); break; case MMC_STOP_TRANSMISSION: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_DATA_DONE | MMC_EVENT_PROG_DONE | MMC_EVENT_CLK_OFF); break; default: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_CLK_OFF); break; } bvd_mmc_data.timeout.expires = jiffies + MMC_COMMAND_TIMEOUT; add_timer(&bvd_mmc_data.timeout); barrier(); bvd_mmc_start_clock(); return MMC_NO_ERROR;}/* Start the command execution */void bvd_mmc_send_command(struct mmc_request *request){ int retval; DEBUG(2, "send command [%d %x]\n", request->cmd, request->arg); /* Sanity check */ if (bvd_mmc_data.request != NULL) { printk(KERN_ERR "MMC command sent while another command " " in processing\n"); request->result = MMC_ERROR_DRIVER_FAILURE; mmc_cmd_complete(request); } /* CRC error check. add by w20598 */ if (mmc_crc_error) { /* prevent continuous CRC error interrupt after an CRC error happens */ /* this will make for IRQ23(Memory to Memeory DMA) diable */ disable_irq(IRQ_MMC); mmc_crc_error = 0; bvd_mmc_request_complete(&bvd_mmc_data, MMC_ERROR_CRC); } /* Save current request for the future processing */ bvd_mmc_data.request = request; /* Indicate we have no result yet */ request->result = MMC_NO_RESPONSE; if (request->cmd == MMC_CIM_RESET) { /* On reset, 1-bit bus width */ bvd_mmc_data.use_4bit = 0; /* On reset, drop MMC clock down */ retval = bvd_mmc_set_clock(MMC_CLOCK_SLOW); if (retval) { bvd_mmc_request_complete(&bvd_mmc_data, retval); return; } } if (request->cmd == SD_SEND_OP_COND) { DEBUG(3, "Have an SD card\n"); bvd_mmc_data.sd = 1; } if (request->cmd == MMC_SEND_OP_COND) { DEBUG(3, "Have an MMC card\n"); bvd_mmc_data.sd = 0; /* always use 1bit for MMC */ bvd_mmc_data.use_4bit = 0; } if (request->cmd == SET_BUS_WIDTH) { if (request->arg == 0x2) { DEBUG(2, "Use 4-bit bus width\n"); bvd_mmc_data.use_4bit = 1; } else { DEBUG(2, "Use 1-bit bus width\n"); bvd_mmc_data.use_4bit = 0; } } retval = bvd_mmc_exec_command(request); if (retval) { bvd_mmc_request_complete(&bvd_mmc_data, retval); }}/* Fetch response data from the response FIFO */static void bvd_mmc_fetch_response(u8 *buf, int len){ while (len-- > 0) { u16 rdata = MMC_RES; *buf++ = (rdata >> 8) & 0xff; if (len-- > 0) *buf++ = rdata & 0xff; }}/* Obtain response to the command and store it to response buffer */static void bvd_mmc_get_response(struct mmc_request *request){ u8 *buf; if (!request) { DEBUG(1, "Oops - fetch response for zero request ?\n"); return; } buf = request->response; DEBUG(2, "fetch response for request %d, cmd %d\n", request->rtype, request->cmd); request->result = MMC_NO_ERROR; switch (request->rtype) { case RESPONSE_R1: case RESPONSE_R1B: case RESPONSE_R6: case RESPONSE_R3: case RESPONSE_R4: case RESPONSE_R5: bvd_mmc_fetch_response(buf, 5); DEBUG(3, "request %d, response [%02x %02x %02x %02x %02x]\n", request->rtype, buf[0], buf[1], buf[2], buf[3], buf[4]); break; case RESPONSE_R2_CID: case RESPONSE_R2_CSD: bvd_mmc_fetch_response(buf, 17); DEBUG(3, "request %d, response [", request->rtype);#if CONFIG_MMC_DEBUG_VERBOSE > 2 if (g_mmc_debug >= 3) { int n; for (n = 0; n < 17; n++) printk("%02x ", buf[n]); printk("]\n"); }#endif break; case RESPONSE_NONE: bvd_mmc_fetch_response(buf, 0); DEBUG(3, "No response\n"); break; default: bvd_mmc_fetch_response(buf, 0); DEBUG(3, "unhandled response type for request %d\n", request->rtype); break; }}/* SD card returns SCR register as data. MMC core expect it in the response buffer, after normal response. */static void bvd_mmc_get_extra_response(struct mmc_request *request){ u8 *buf = request->response; if (request->cmd == SEND_SCR) { int i; DEBUG(3, "extra response: ["); for (i = 0; i < 8; i+=4) *((u32*)(buf + i + 5)) = MMC_RXFIFO;#if CONFIG_MMC_DEBUG_VERBOSE > 2 for (i = 0; i < 8; i++) { if (g_mmc_debug >= 3) printk(" %02x", buf[i + 5]); } printk(" ]\n");#endif }}/* Program I/O mode data transfer */static void bvd_mmc_tx(struct mmc_request *request){ int i, count; DEBUG(2, "\n"); if (!request->cnt) return; count = (request->cnt < 32) ? request->cnt : 32; for (i=0; i < count; i+=4) MMC_TXFIFO = *((u32*)(request->buffer+i)); if (count < 32) MMC_PRTBUF = 0x1; request->buffer += count; request->cnt -= count;}/* Card service IRQ handler */static void bvd_mmc_int(int irq, void *dev, struct pt_regs *regs){ int status, irqtype; bvd_mmc_data_t *mmc = (bvd_mmc_data_t *)dev; status = MMC_STAT; irqtype = MMC_I_REG; DEBUG(3, "MMC service IRQ [MMC_STAT %x, MMC_I_REG %x, MMC_I_MASK %x], CD %p, request %p\n", status, irqtype, MMC_I_MASK, mmc, mmc->request); /* Checking for data or response timeout */ if ((status & (MMC_STAT_TIME_OUT_READ | MMC_STAT_TIME_OUT_RES)) || (irqtype & MMC_I_TINT)) { DEBUG(1, "MMC/SD timeout, MMC_STAT 0x%x\n", status); bvd_mmc_request_complete(mmc, MMC_ERROR_TIMEOUT); return; } /* Checking for CRC error */ if ((status & (MMC_STAT_CRC_RD_ERR | MMC_STAT_CRC_WR_ERR | MMC_STAT_RES_CRC_ERR)) || (irqtype & (MMC_I_RES_ERR | MMC_I_DAT_ERR))) { DEBUG(1, "MMC/CD CRC error, MMC_STAT 0x%x\n", status); if (!mmc_crc_error) { switch (mmc->request->cmd) { /* FIXME: workaround for sighting #55580 */ case MMC_ALL_SEND_CID: case MMC_SEND_CSD: case MMC_SEND_CID: /* ignore CRC error for these commands */ break; /* FIXME: workaround for sighting #59136 */ case MMC_SEND_STATUS: if ((MMC_CLKRT & 0x7) == MMC_CLKRT_FREQ_19_5MHZ) { struct mmc_request *req = mmc->request; bvd_mmc_set_clock(9750000); del_timer(&mmc->timeout); bvd_mmc_wait_for(0); mmc->request = NULL; bvd_mmc_send_command(req); return; } /* FIXME: multi-block CRC issue */ case MMC_READ_SINGLE_BLOCK: case MMC_READ_MULTIPLE_BLOCK: mmc_crc_error = 1; bvd_mmc_wait_for(MMC_EVENT_RX_DMA_DONE); return; case MMC_WRITE_BLOCK: case MMC_WRITE_MULTIPLE_BLOCK: mmc_crc_error = 1; bvd_mmc_wait_for(MMC_EVENT_TX_DMA_DONE); return; /* else fall-through */ default: bvd_mmc_request_complete(mmc, MMC_ERROR_CRC); return; } } /* if (! mmc_crc_error) */ } /* If the command and response sequence has completed, get the response */ if ((mmc->event_mask & MMC_EVENT_RESPONSE) && (irqtype & MMC_I_END_CMD_RES)) { bvd_mmc_get_response(mmc->request); bvd_mmc_event(MMC_EVENT_RESPONSE); } /* Transfer data in program I/O mode */ if ((mmc->event_mask & MMC_EVENT_DATA_DONE) && (irqtype & MMC_I_TXFIFO_WR_REQ)) { bvd_mmc_tx(mmc->request); } /* Handle data transfer done event */ if ((mmc->event_mask & MMC_EVENT_DATA_DONE) && (irqtype & MMC_I_DATA_TRAN_DONE)) { bvd_mmc_get_extra_response(mmc->request); bvd_mmc_event(MMC_EVENT_DATA_DONE); } /* Handle programming done event */ if ((mmc->event_mask & MMC_EVENT_PROG_DONE) && (irqtype & MMC_I_PRG_DONE)) { bvd_mmc_event(MMC_EVENT_PROG_DONE); } /* Handle clock off event */ if ((mmc->event_mask == MMC_EVENT_CLK_OFF) && (MMC_I_REG & MMC_I_CLK_IS_OFF)) { bvd_mmc_event(MMC_EVENT_CLK_OFF); }}/* Timeout handler */static void bvd_mmc_timeout(unsigned long data){ struct bvd_mmc_data *mmc = (struct bvd_mmc_data *)data; printk(KERN_ERR "MMC timeout: waiting events 0x%02x\n", mmc->event_mask); if (!mmc_crc_error) bvd_mmc_request_complete(mmc, MMC_ERROR_TIMEOUT);}#ifdef CONFIG_PM/* * Standard PM functions, if CONFIG_PM is used *//* Suspend the MMC slot */static int bvd_mmc_suspend(void){ DEBUG(1, "suspend mmc slot\n"); /*set GPIO output high to save power*/ CKEN &= ~CKEN12_MMC; set_GPIO(GPIO_MMC_CLK); set_GPIO_mode(GPIO_MMC_CLK | GPIO_OUT); set_GPIO(GPIO_MMC_CMD); set_GPIO_mode(GPIO_MMC_CMD | GPIO_OUT); set_GPIO(GPIO_MMC_DATA0); set_GPIO_mode(GPIO_MMC_DATA0 | GPIO_OUT); set_GPIO(GPIO_MMC_DATA1); set_GPIO_mode(GPIO_MMC_DATA1 | GPIO_OUT); set_GPIO(GPIO_MMC_DATA2); set_GPIO_mode(GPIO_MMC_DATA2 | GPIO_OUT);#ifdef CONFIG_ARCH_EZXBASE set_GPIO(GPIO_MMC_DATA3); set_GPIO_mode(GPIO_MMC_DATA3 | GPIO_IN);#endif return 0;}/* Resume the MMC slot */static void bvd_mmc_resume(void){ DEBUG(1, "resume mmc slot\n"); #ifdef CONFIG_ARCH_EZXBASE #ifndef CONFIG_ARCH_EZX_HAINAN if( GPLR(GPIO_MMC_DETECT) & GPIO_bit(GPIO_MMC_DETECT) )#else if(ezx_mmc_get_slot_state())#endif#else if( GPLR(GPIO_MMC_DATA3) & GPIO_bit(GPIO_MMC_DATA3) )#endif { CKEN |= CKEN12_MMC; set_GPIO_mode(GPIO_MMC_CLK | GPIO_ALT_FN_2_OUT); set_GPIO_mode(GPIO_MMC_CMD | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT); set_GPIO_mode(GPIO_MMC_DATA0 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);#ifdef CONFIG_ARCH_EZXBASE set_GPIO_mode(GPIO_MMC_DATA1 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT); set_GPIO_mode(GPIO_MMC_DATA2 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT); set_GPIO_mode(GPIO_MMC_DATA3 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);#endif } }static int bvd_mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ switch(req) { case PM_SUSPEND: bvd_mmc_suspend(); break; case PM_RESUME:#ifdef CONFIG_ARCH_EZX_E680 e680_reconfig_gpio();#else bvd_mmc_resume();#endif break; default: printk(KERN_ERR "MMC/SD: invalid PM request %d\n", req); break; } return 0;}#endif /* CONFIG_PM *//* Initialize the slot and prepare software layer to operate with it */int bvd_mmc_slot_init(void){ int retval; int channel; /* Request basic card servicing IRQ */ retval = request_irq(IRQ_MMC, bvd_mmc_int, SA_INTERRUPT | SA_SAMPLE_RANDOM, "MMC/SD", &bvd_mmc_data); if (retval) { printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n"); return retval; } /* Request MMC Rx DMA channel */ channel = pxa_request_dma("MMC Rx", DMA_PRIO_MEDIUM, bvd_mmc_dma_rx_callback, &bvd_mmc_data); if (channel < 0) { printk(KERN_ERR "pxa_request_dma failed for MMC Rx\n"); goto err1; } bvd_mmc_data.dma_rx_ch = channel; /* Request MMC Tx DMA channel */ channel = pxa_request_dma("MMC Tx", DMA_PRIO_MEDIUM, bvd_mmc_dma_tx_callback, &bvd_mmc_data); if (channel < 0) { printk(KERN_ERR "pxa_request_dma failed for MMC Tx\n"); goto err2; } bvd_mmc_data.dma_tx_ch = channel; /* Use 1-bit by default */ bvd_mmc_data.use_4bit = 0; init_timer(&bvd_mmc_data.timeout); bvd_mmc_data.timeout.function = bvd_mmc_timeout; bvd_mmc_data.timeout.data = (unsigned long)&bvd_mmc_data; #ifdef CONFIG_PM /* Register MMC slot as as power-managed device */ pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, bvd_mmc_pm_callback);#endif DEBUG(2, "MMC initialized with code %d\n", retval); return retval;err2: pxa_free_dma(bvd_mmc_data.dma_rx_ch);err1: free_irq(IRQ_MMC, &bvd_mmc_data); return -1;}/* Shut down the slot and relax software about MMC slot */void bvd_mmc_slot_cleanup(void){ long flags; DEBUG(2, "Bye, MMC\n"); local_irq_save(flags); /* Shut down the slot */ bvd_mmc_slot_down(); /* Free DMA channels */ pxa_free_dma(bvd_mmc_data.dma_rx_ch); pxa_free_dma(bvd_mmc_data.dma_tx_ch); /* Free both IRQs */ free_irq(IRQ_MMC, &bvd_mmc_data); local_irq_restore(flags);}MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -