📄 atheros_2_0_hcd.patch
字号:
+ req->BlockCount * req->BlockLen);++ req->DataRemaining = 0;+ status = SDIO_STATUS_SUCCESS;++ } else if (context->complete == S3C24XX_HCD_DATA_WRITE) {+ /* DMA WRITE completion */+ if (context->latest_xfer_size != req->DataRemaining) {+ DBG_PRINT(SDDBG_ERROR, ("Unexpected write xfer size: %d <-> %d\n",+ context->latest_xfer_size, req->DataRemaining));+ status = SDIO_STATUS_BUS_WRITE_ERROR;+ }++ dsta = readl(context->base + S3C2410_SDIDSTA);+ counter = 0;+ while (!(dsta & S3C2410_SDIDSTA_XFERFINISH)) {+ if (counter > 500) {+ printk("write xfer timed out\n");+ status = SDIO_STATUS_BUS_WRITE_ERROR;+ goto out;+ }+ dsta = readl(context->base + S3C2410_SDIDSTA);+ counter++;+ mdelay(1);+ };++ writel(S3C2410_SDIDSTA_XFERFINISH, context->base + S3C2410_SDIDSTA);+ req->DataRemaining = 0;+ status = SDIO_STATUS_SUCCESS;+ }++ out:+ req->Status = status;+}++static void s3c24xx_hcd_pio_complete(struct s3c24xx_hcd_context * context)+{+ u32 fsta, counter;+ u8 *ptr;+ int fifo_count;+ PSDREQUEST req;+ SDIO_STATUS status = SDIO_STATUS_ERROR;++ req = GET_CURRENT_REQUEST(&context->hcd);+ if (req == NULL) {+ DBG_PRINT(SDDBG_ERROR, ("%s(): No current request\n", __FUNCTION__));+ return;+ }++ ptr = req->pDataBuffer;++ if (context->complete == S3C24XX_HCD_DATA_READ) {+ counter = 0;+ DBG_PRINT(SDDBG_TRACE, ("Data read..."));+ do {+ counter++;+ fsta = readl(context->base + S3C2410_SDIFSTA);+ mdelay(1);+ if (counter > 1000) {+ DBG_PRINT(SDDBG_ERROR, ("DATA read timeout\n"));+ status = SDIO_STATUS_BUS_READ_TIMEOUT;+ s3c24xx_dump_regs(context);+ goto out;+ }+ } while(!(fsta & S3C2410_SDIFSTA_RFDET));+ DBG_PRINT(SDDBG_TRACE, ("RX detected\n"));++ while (1) {+ counter = 0;+ fifo_count = (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK);+ while (!fifo_count) {+ counter++;+ mdelay(1);+ if (counter > 500) {+ s3c24xx_dump_regs(context);+ DBG_PRINT(SDDBG_ERROR, ("No more bytes in FIFO\n"));+ goto out;+ }+ fifo_count = (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK);+ }++ if (fifo_count > req->DataRemaining) {+ DBG_PRINT(SDDBG_ERROR, ("DATA read, fifo_count %d > expected %d\n", fifo_count, req->DataRemaining));+ fifo_count = req->DataRemaining;+ }++ req->DataRemaining -= fifo_count;+ while (fifo_count > 0) {+ if (context->data_size == 4)+ *(ptr) = readl(context->base + S3C2440_SDIDATA);+ else if (context->data_size == 2)+ *(ptr) = readw(context->base + S3C2440_SDIDATA);+ else+ *(ptr) = readb(context->base + S3C2440_SDIDATA);++ ptr += context->data_size;+ fifo_count -= context->data_size;++ }++ if (!req->DataRemaining) {+ /* We poll for xfer finish */+ counter = 0;+ while (!(readl(context->base + S3C2410_SDIDSTA)+ & S3C2410_SDIDSTA_XFERFINISH)) {+ counter++;+ mdelay(1);+ if (counter > 500) {+ DBG_PRINT(SDDBG_ERROR, ("RX XFERFINISH missing\n"));+ s3c24xx_dump_regs(context);+ break;+ }+ }++ status = SDIO_STATUS_SUCCESS;+ goto out;+ }+ }++ } else if (context->complete == S3C24XX_HCD_DATA_WRITE) {+ counter = 0;+ DBG_PRINT(SDDBG_TRACE, ("Data write..."));+ do {+ counter++;+ fsta = readl(context->base + S3C2410_SDIFSTA);+ mdelay(1);+ if (counter > 1000) {+ DBG_PRINT(SDDBG_ERROR, ("DATA write timeout\n"));+ status = SDIO_STATUS_BUS_WRITE_ERROR;+ goto out;+ break;+ }++ } while(!(fsta & S3C2410_SDIFSTA_TFDET));+ DBG_PRINT(SDDBG_TRACE, ("TX detected\n"));++ while (1) {+ counter = 0;+ fifo_count = 63 - (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK);+ while (!fifo_count) {+ counter++;+ mdelay(1);+ if (counter > 500) {+ s3c24xx_dump_regs(context);+ DBG_PRINT(SDDBG_ERROR, ("No more space in FIFO\n"));+ goto out;+ }+ fifo_count = 63 - (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK);+ }++ if (fifo_count > req->DataRemaining)+ fifo_count = req->DataRemaining;++ req->DataRemaining -= fifo_count;++ while (fifo_count > 0) {+ if (context->data_size == 4)+ writel(*(ptr), context->base + S3C2440_SDIDATA);+ else if (context->data_size == 2)+ writew(*(ptr), context->base + S3C2440_SDIDATA);+ else+ writeb(*(ptr), context->base + S3C2440_SDIDATA);++ ptr += context->data_size;+ fifo_count -= context->data_size;+ }++ if (!req->DataRemaining) {+ /* We poll for xfer finish */+ counter = 0;+ while (!(readl(context->base + S3C2410_SDIDSTA)+ & S3C2410_SDIDSTA_XFERFINISH)) {+ counter++;+ mdelay(1);+ if (counter > 500) {+ DBG_PRINT(SDDBG_ERROR, ("RX XFERFINISH missing\n"));+ s3c24xx_dump_regs(context);+ break;+ }+ }++ status = SDIO_STATUS_SUCCESS;+ goto out;+ }+ }++ } else {+ DBG_PRINT(SDDBG_ERROR, ("Wrong context: %d\n", context->complete));+ }++ out:+ req->Status = status;+}++static void s3c24xx_hcd_io_work(struct work_struct *work)+{+ PSDREQUEST req;+ SDIO_STATUS status = SDIO_STATUS_SUCCESS;+ struct s3c24xx_hcd_context * context =+ container_of(work, struct s3c24xx_hcd_context, io_work);++ req = GET_CURRENT_REQUEST(&context->hcd);+ if (req == NULL) {+ DBG_PRINT(SDDBG_ERROR, ("%s(): No current request\n", __FUNCTION__));+ return;+ }++ if (req->Status == SDIO_STATUS_BUS_RESP_TIMEOUT) {+ DBG_PRINT(SDDBG_ERROR, ("### TIMEOUT ###\n"));+ s3c24xx_dump_regs(context);+ goto out;+ }++ if (context->complete == S3C24XX_HCD_NO_RESPONSE &&+ req->Status == SDIO_STATUS_SUCCESS) {+ DBG_PRINT(SDDBG_TRACE, ("CMD done, Status: %d\n", req->Status));+ printk("CMD done, Status: %d\n", req->Status);+ goto out;+ }++ if ((context->complete == S3C24XX_HCD_RESPONSE_SHORT ||+ context->complete == S3C24XX_HCD_RESPONSE_LONG ||+ context->complete == S3C24XX_HCD_DATA_READ ||+ context->complete == S3C24XX_HCD_DATA_WRITE) &&+ req->Status == SDIO_STATUS_SUCCESS) {+ u32 resp[4];++ /* We need to copy the response data and send it over */+ resp[0] = readl(context->base + S3C2410_SDIRSP0);+ resp[1] = readl(context->base + S3C2410_SDIRSP1);+ resp[2] = readl(context->base + S3C2410_SDIRSP2);+ resp[3] = readl(context->base + S3C2410_SDIRSP3);++ if (GET_SDREQ_RESP_TYPE(req->Flags) != SDREQ_FLAGS_RESP_R2) {+ DBG_PRINT(SDDBG_TRACE, ("SHORT response: 0x%08x\n", resp[0]));+ memcpy(&req->Response[1], (u8*)resp, 4);+ req->Response[5] = (readl(context->base + S3C2410_SDICMDSTAT) & 0xff);+ } else {+ printk("LONG response: 0x%08x\n", resp[0]);+ DBG_PRINT(SDDBG_TRACE, ("LONG response: 0x%08x\n", resp[0]));+ memcpy(&req->Response[1], (u8*)resp, 16);+ //req->Response[17] = (readl(context->base + S3C2410_SDICMDSTAT) & 0xff);+ }++ /* There is a data stage */+ if (context->complete == S3C24XX_HCD_DATA_READ ||+ context->complete == S3C24XX_HCD_DATA_WRITE) {+ status = SDIO_CheckResponse(&context->hcd, req,+ SDHCD_CHECK_DATA_TRANS_OK);++ if (!SDIO_SUCCESS(status)) {+ DBG_PRINT(SDDBG_ERROR,+ ("Target not ready for data xfer\n"));+ return;+ }++ if (context->dma_en) {+ dma_sync_single(NULL, context->io_buffer_dma,+ req->BlockCount * req->BlockLen, DMA_BIDIRECTIONAL);++ s3c2410_dma_ctrl(context->dma_channel, S3C2410_DMAOP_START);++ wait_for_completion(&context->dma_complete);++ s3c24xx_hcd_dma_complete(context);+ } else {+ s3c24xx_hcd_pio_complete(context);+ }+ }+ }++ out:+ s3c24xx_hcd_clear_sta(context);+ s3c24xx_hcd_clear_imask(context);++ writel(0, context->base + S3C2410_SDICMDARG);+ writel(0, context->base + S3C2410_SDICMDCON);++ SDIO_HandleHcdEvent(&context->hcd, EVENT_HCD_TRANSFER_DONE);+}++static void s3c24xx_hcd_irq_work(struct work_struct *work)+{+ struct s3c24xx_hcd_context * context =+ container_of(work, struct s3c24xx_hcd_context, irq_work);++ disable_irq(context->io_irq);++ writel(S3C2410_SDIDSTA_SDIOIRQDETECT, context->base + S3C2410_SDIDSTA);++ SDIO_HandleHcdEvent(&context->hcd, EVENT_HCD_SDIO_IRQ_PENDING);++ enable_irq(context->io_irq);+}++void s3c24xx_hcd_dma_done(struct s3c2410_dma_chan *dma_ch, void *buf_id,+ int size, enum s3c2410_dma_buffresult result)+{+ struct s3c24xx_hcd_context * context =+ (struct s3c24xx_hcd_context *) buf_id;++ if (result != S3C2410_RES_OK) {+ DBG_PRINT(SDDBG_ERROR, ("%s(): DMA xfer failed: %d\n", __FUNCTION__, result));+ s3c24xx_dump_regs(context);+ }++ context->latest_xfer_size = size;+ complete(&context->dma_complete);+}++static int s3c24xx_hcd_prepare_dma(struct s3c24xx_hcd_context * context)+{+ PSDREQUEST req;+ SDIO_STATUS status = SDIO_STATUS_SUCCESS;+ int read = 0, hwcfg = S3C2410_DISRCC_INC | S3C2410_DISRCC_APB;+ enum s3c2410_dmasrc source = S3C2410_DMASRC_MEM;++ req = GET_CURRENT_REQUEST(&context->hcd);+ if (req == NULL) {+ DBG_PRINT(SDDBG_ERROR, ("%s(): No current request\n", __FUNCTION__));+ status = SDIO_STATUS_ERROR;+ }++ if (!context->dma_en) {+ DBG_PRINT(SDDBG_ERROR, ("%s(): DMA is disabled\n", __FUNCTION__));+ status = SDIO_STATUS_ERROR;+ }++ if (!IS_SDREQ_DATA_TRANS(req->Flags)) {+ DBG_PRINT(SDDBG_ERROR, ("%s(): No data to transfer\n", __FUNCTION__));+ status = SDIO_STATUS_ERROR;+ }++ if(!IS_SDREQ_WRITE_DATA(req->Flags)) {+ read = 1;+ source = S3C2410_DMASRC_HW;+ hwcfg = S3C2410_DISRCC_APB | 1;+ } else {+ memcpy(context->io_buffer, req->pDataBuffer, req->DataRemaining);+ dma_sync_single(NULL, context->io_buffer_dma,+ req->BlockCount * req->BlockLen, DMA_BIDIRECTIONAL);++ }++ s3c2410_dma_devconfig(context->dma_channel, source, hwcfg,+ (unsigned long)context->mem->start + S3C2440_SDIDATA);++ s3c2410_dma_config(context->dma_channel, context->data_size,+ S3C2410_DCON_CH0_SDI);+ //(S3C2410_DCON_HWTRIG | S3C2410_DCON_CH0_SDI));++ s3c2410_dma_set_buffdone_fn(context->dma_channel, s3c24xx_hcd_dma_done);++// s3c2410_dma_setflags(context->dma_channel, S3C2410_DMAF_AUTOSTART);++ s3c2410_dma_ctrl(context->dma_channel, S3C2410_DMAOP_FLUSH);++ s3c2410_dma_enqueue(context->dma_channel, context,+ context->io_buffer_dma,+ req->DataRemaining);++ return 0;+}+++static irqreturn_t s3c24xx_hcd_irq(int irq, void *dev_id)+{+ u32 cmdsta, dsta, fsta;+ unsigned long flags, trace = 0;+ PSDREQUEST req;+ struct s3c24xx_hcd_context * context =+ (struct s3c24xx_hcd_context *)dev_id;++ spin_lock_irqsave(&context->lock, flags);++ s3c24xx_hcd_clear_imask(context);++ cmdsta = readl(context->base + S3C2410_SDICMDSTAT);+ dsta = readl(context->base + S3C2410_SDIDSTA);+ fsta = readl(context->base + S3C2410_SDIFSTA);++ context->cmdsta = cmdsta;+ context->dsta = dsta;+ context->fsta = fsta;++ s3c24xx_hcd_clear_csta(context);++ if (dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {+ writel(S3C2410_SDIDSTA_SDIOIRQDETECT, context->base + S3C2410_SDIDSTA);++ if (context->int_sdio) {+ u32 imask;++ context->int_sdio = 0;++ imask = readl(context->base + S3C2440_SDIIMSK);+ imask &= ~S3C2410_SDIIMSK_SDIOIRQ;+ writel(imask, context->base + S3C2440_SDIIMSK);+ schedule_work(&context->irq_work);+ }+ }++ req = GET_CURRENT_REQUEST(&context->hcd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -