--- /home/moogle/Desktop/lf1000_mmc.c 2010-03-26 19:04:37.000000000 -0400 +++ lf1000_mmc.c 2010-07-26 16:52:19.094732302 -0400 @@ -13,7 +13,8 @@ * - SD memory card spec 2.0 * - SDIO card spec 1.10 * - 1-bit and 4-bit data bus modes - * - PIO and DMA + * - PIO and DMA (PIO not implemented) + * - up to 50MHz bus clock */ #include @@ -41,13 +42,21 @@ #include "lf1000_mmc.h" +#if !defined(CONFIG_MMC_LF1000_CHANNEL0) && \ + !defined(CONFIG_MMC_LF1000_CHANNEL1) +#warning "No host controllers enabled. Enable at least one." +#endif + #define RESSIZE(res) (((res)->end - (res)->start)+1) #define MAX_CHANNELS 2 #define COMPLETION_TIMEOUT (2*1000) -#define SDIO_CLK_HZ (25*1000*1000) #define DRIVER_NAME "lf1000-sdio" +#define SDIO_CLK_SRC PLL1 +#define SDIO_CLK_DIV 3 +#define LF1000_SDIO_DIV_400KHZ 62 /* divider for 400KHz */ +#define LF1000_SDIO_DIV 0 /* divider for full speed */ #define SDIO_GPIO_PORT GPIO_PORT_B #define SDIO_GPIO_FUNC GPIO_ALT1 @@ -86,23 +95,24 @@ int dma_id; struct lf1000_dma_desc dma_desc; bool dma_active; + enum dma_data_direction dma_dir; + int dma_nents; u8 irq; int div; u32 clock_hz; u8 bus_width; + unsigned char power_mode; + bool sdio_irq_en; struct mmc_request *mrq; + struct mmc_data *data; struct completion dma_transfer; - struct completion complete_request; -#ifdef CONFIG_MMC_DEBUG + /* debugging */ struct dentry *debug; -#endif }; -#ifdef CONFIG_MMC_DEBUG - static void lf1000_regs_show_reg(struct seq_file *s, const char *nm, u32 reg) { struct lf1000_sdio_host *host = s->private; @@ -153,7 +163,6 @@ { struct lf1000_sdio_host *host = s->private; u32 status = readl(host->base + SDI_STATUS); - u8 fsm = (status>>CMDFSM) & 0xF; lf1000_status_show_bit(s, "DMAREQ", status & (1<>CMDFSM) & 0xF); lf1000_status_show_bit(s, "FIFOFULL", status & (1<base + SDI_CTRL) & (1< 8 ? (8-1) : (2-1); u32 tmp = readl(host->base + SDI_FIFOTH) & ~((0xF<base + SDI_FIFOTH); } @@ -338,7 +301,7 @@ static void lf1000_sdio_interrupt_enable(struct lf1000_sdio_host *host) { u32 tmp = readl(host->base + SDI_CTRL); - tmp |= (1<base + SDI_CTRL); } @@ -360,7 +323,10 @@ } if (irqm & (1<pdev->dev, "response timeout\n"); + /* This happens when the stack probes for different types of + * cards and is expected. For example, an SD card will time + * out when probed as an SDIO card. */ + dev_dbg(&host->pdev->dev, "response timeout\n"); return -ETIMEDOUT; } @@ -388,9 +354,13 @@ * output will be enabled later by the MMC subsystem. */ writel(0, host->base + SDI_CLKENA); - /* use PLL1 */ - writel((2<base + SDI_CLKGEN); + /* use PLL1/3, 147MHz/3 = 49MHz */ + writel((2<base + SDI_CLKGEN); writel((1<base + SDI_SYSCLKENB); + /* set SDIO clock to "detect" rate, ~400KHz: + * 49MHz/(62*2) = ~400KHz */ + writel(62, host->base + SDI_CLKDIV); lf1000_sdio_interrupt_enable(host); @@ -398,17 +368,17 @@ lf1000_sdio_reset_dma(host); lf1000_sdio_reset_fifo(host); - lf1000_sdio_set_dma(host, 0); + lf1000_sdio_set_dma(host, 1); lf1000_sdio_set_width(host, MMC_BUS_WIDTH_1); /* Set host data and response timeouts. */ writel((0xFFFFFF<base + SDI_TMOUT); - /* Set block size: 512B is typical for MMC/SD cards. */ + /* Set a defult block size: 512B is typical for MMC/SD cards. */ writel(512, host->base + SDI_BLKSIZ); - lf1000_sdio_set_fifo_th(host, 0); + lf1000_sdio_set_fifo_th(host); /* Disable interrupts and clear any pending. */ writel(0, host->base + SDI_INTMASK); @@ -427,12 +397,8 @@ static void lf1000_sdio_enable_irq(struct mmc_host *mmc, int enable) { struct lf1000_sdio_host *host = mmc_priv(mmc); - u32 tmp = readl(host->base + SDI_INTMASK); - if (enable) - writel(tmp | (1<base + SDI_INTMASK); - else - writel(tmp & ~(1<base + SDI_INTMASK); + host->sdio_irq_en = enable; } /* @@ -447,6 +413,10 @@ static int lf1000_sdio_command_complete(struct lf1000_sdio_host *host) { struct mmc_request *mrq = host->mrq; + bool is_stop = 0; + + if (mrq->stop || (mrq->data && mrq->data->stop)) + is_stop = 1; if (mrq->cmd->flags & MMC_RSP_PRESENT) { if (mrq->cmd->flags & MMC_RSP_136) { @@ -460,7 +430,9 @@ if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) { dev_dbg(&host->pdev->dev, "launching DMA TX\n"); - lf1000_dma_launch(host->dma_channel, &host->dma_desc); + lf1000_dma_int_en(host->dma_channel); + WARN_ON(lf1000_dma_launch(host->dma_channel, + &host->dma_desc)); } if (mrq->cmd->error || !mrq->data) { @@ -473,6 +445,16 @@ return 0; } +static void lf1000_sdio_dma_done(struct lf1000_sdio_host *host) +{ + lf1000_dma_int_dis(host->dma_channel); + host->dma_active = 0; + dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_nents, + host->dma_dir); + host->data = NULL; + complete(&host->dma_transfer); +} + static void lf1000_sdio_transfer_complete(struct lf1000_sdio_host *host) { struct mmc_data *data = host->mrq->data; @@ -484,13 +466,12 @@ if (data->error) { dev_err(&host->pdev->dev, "data error\n"); - /* TODO: abort DMA transfer */ + if (host->dma_active) + lf1000_sdio_dma_done(host); } else { data->bytes_xfered = data->blocks * data->blksz; } - //lf1000_sdio_reset_fifo(host); - /* Complete the command now that the data transfer portion has * finished. */ host->mrq = NULL; @@ -506,55 +487,49 @@ WARN_ON(channel != host->dma_channel); WARN_ON(!host->dma_active); + WARN_ON(pending != 0); if (host->dma_active && channel == host->dma_channel) { dev_dbg(&host->pdev->dev, "DMA transfer completed\n"); - lf1000_sdio_set_dma(host, 0); - lf1000_dma_int_dis(host->dma_channel); - host->dma_active = 0; - complete(&host->dma_transfer); + lf1000_sdio_dma_done(host); } } static irqreturn_t lf1000_sdio_irq(int irq, void *dev_id) { - u32 irqm, irqs; struct lf1000_sdio_host *host = (struct lf1000_sdio_host *)dev_id; + u32 irqm = readl(host->base + SDI_MINTSTS); - irqs = readl(host->base + SDI_RINTSTS); - irqm = readl(host->base + SDI_INTMASK); + dev_dbg(&host->pdev->dev, "IRQ: 0x%08X\n", irqm); - dev_dbg(&host->pdev->dev, "IRQ: 0x%08X\n", irqs & irqm); + if (host->mrq) { + host->mrq->cmd->error = check_command_error(host, irqm); + if (host->mrq->cmd->error) { + dev_dbg(&host->pdev->dev, "command error\n"); + lf1000_sdio_command_complete(host); + goto out_req; + } - /* We will handle all interrupts here, so we can clear any pending - * status right now. */ - irqm = (irqs & irqm); - writel(irqm, host->base + SDI_RINTSTS); + if (irqm & (1<pdev->dev, "command done\n"); + if (lf1000_sdio_command_complete(host)) + goto out_req; + } + if (host->mrq->data && (irqm & (1<pdev->dev, "data transfer over\n"); + host->mrq->data->error = check_data_error(host, irqm); + lf1000_sdio_transfer_complete(host); + } + } + +out_req: if (irqm & (1<pdev->dev, "SDIO interrupt occured\n"); mmc_signal_sdio_irq(host->mmc); } - host->mrq->cmd->error = check_command_error(host, irqm); - if (host->mrq->cmd->error) { - dev_dbg(&host->pdev->dev, "command error\n"); - lf1000_sdio_command_complete(host); - return IRQ_HANDLED; - } - - if (irqm & (1<pdev->dev, "command done\n"); - if (lf1000_sdio_command_complete(host)) - return IRQ_HANDLED; - } - - if (host->mrq->data && (irqm & (1<pdev->dev, "data transfer over\n"); - host->mrq->data->error = check_data_error(host, irqm); - lf1000_sdio_transfer_complete(host); - } - + writel(irqm, host->base + SDI_RINTSTS); return IRQ_HANDLED; } @@ -575,14 +550,20 @@ lf1000_dma_initdesc(desc); - desc->src = (dma_addr_t)(host->phys + SDI_DAT); + host->dma_dir = DMA_FROM_DEVICE; + host->dma_nents = dma_map_sg(mmc_dev(host->mmc), host->mrq->data->sg, + host->mrq->data->sg_len, host->dma_dir); + + desc->src = (dma_addr_t)(host->mem->start); desc->dst = (dma_addr_t)virt_to_phys(buffer); desc->len = sg_dma_len(sg); desc->flags = (DMA_SRC_IO|DMA_DST_MEM|DMA_SRC_32BIT|DMA_DST_32BIT| DMA_SRC_NOINC); desc->id = host->dma_id; - lf1000_dma_launch(host->dma_channel, desc); + lf1000_dma_int_en(host->dma_channel); + + WARN_ON(lf1000_dma_launch(host->dma_channel, desc)); } /* Set up a transfer from memory to the controller. The transfer will be @@ -603,10 +584,12 @@ lf1000_dma_initdesc(desc); + host->dma_dir = DMA_TO_DEVICE; + host->dma_nents = dma_map_sg(mmc_dev(host->mmc), host->mrq->data->sg, + host->mrq->data->sg_len, host->dma_dir); + desc->src = (dma_addr_t)virt_to_phys(buffer); - dev_dbg(&host->pdev->dev, "SRC 0x%X\n", desc->src); - desc->dst = (dma_addr_t)(host->phys + SDI_DAT); - dev_dbg(&host->pdev->dev, "DST 0x%X\n", desc->dst); + desc->dst = (dma_addr_t)(host->mem->start); desc->len = sg_dma_len(sg); desc->flags = (DMA_SRC_MEM|DMA_DST_IO|DMA_SRC_32BIT|DMA_DST_32BIT| DMA_DST_NOINC); @@ -650,21 +633,21 @@ irqm |= (1<base + SDI_INTMASK) & (1<sdio_irq_en<data) { u32 length = mrq->data->blocks * mrq->data->blksz; dev_dbg(&host->pdev->dev, "transferring %d bytes\n", length); - lf1000_sdio_set_fifo_th(host, length); - lf1000_sdio_set_dma(host, 1); + host->data = mrq->data; if (mrq->data->blocks > 1 && (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK || mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)) { dev_dbg(&host->pdev->dev, "setting autostop\n"); flags |= (1<data->blksz, host->base + SDI_BLKSIZ); @@ -673,20 +656,22 @@ irqm |= (1<data->flags & MMC_DATA_STREAM) + if (mrq->data->flags & MMC_DATA_STREAM) { + dev_dbg(&host->pdev->dev, "data stream requested\n"); flags |= (1<data->flags & MMC_DATA_READ) { irqm |= (1<data->flags & MMC_DATA_WRITE) { + + if (mrq->data->flags & MMC_DATA_WRITE) { flags |= (1<stop) { + flags |= (1<pdev->dev, "submitting cmd: 0x%04X irqm: 0x%04X\n", @@ -705,6 +690,11 @@ return -ENOSYS; } +static void lf1000_sdio_set_clock_out(struct lf1000_sdio_host *host, bool en) +{ + writel((1<base + SDI_CLKENA); +} + static int lf1000_sdio_update_clock(struct lf1000_sdio_host *host) { u32 tout, tmp; @@ -733,21 +723,24 @@ static int lf1000_sdio_set_clock_hz(struct lf1000_sdio_host *host, u32 hz) { - u32 tmp; - int div = lf1000_CalcDivider(get_pll_freq(PCLK_PLL)/2, hz); - - if (div < 0) - return 1; - if (div >= 64) - div = 63; + int div; + if (hz == 400000) + div = LF1000_SDIO_DIV_400KHZ; + else if (hz == host->mmc->f_max) + div = LF1000_SDIO_DIV; + else { + u32 clk_hz = get_pll_freq(SDIO_CLK_SRC)/SDIO_CLK_DIV; + div = lf1000_CalcDivider(clk_hz, hz); + if (div < 0) + return 1; + div >>= 1; + } dev_dbg(&host->pdev->dev, "setting DIV=%d\n", div); /* disable the SDIO clock and set the divider */ - writel(0<base + SDI_CLKENA); - tmp = readl(host->base + SDI_CLKGEN); - tmp &= ~(0x7<base + SDI_CLKGEN); + lf1000_sdio_set_clock_out(host, 0); + writel(div & 0xFF, host->base + SDI_CLKDIV); host->div = div; if (lf1000_sdio_update_clock(host)) { @@ -755,8 +748,7 @@ return 1; } - /* turn the SDIO clock back on */ - writel((1<base + SDI_CLKENA); + lf1000_sdio_set_clock_out(host, 1); if (lf1000_sdio_update_clock(host)) { dev_err(&host->pdev->dev, "can't set clock\n"); @@ -789,6 +781,29 @@ } else lf1000_sdio_clock_disable(host); } + + if (ios->power_mode != host->power_mode) { + switch (ios->power_mode) { + case MMC_POWER_OFF: + lf1000_sdio_set_clock_out(host, 0); + break; + + case MMC_POWER_ON: + lf1000_sdio_set_clock_out(host, 1); + lf1000_sdio_reset_dma(host); + lf1000_sdio_reset_fifo(host); + mdelay(5); + break; + + case MMC_POWER_UP: + mdelay(5); + break; + + default: + break; + } + host->power_mode = ios->power_mode; + } } static struct mmc_host_ops lf1000_sdio_ops = { @@ -838,13 +853,14 @@ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; - mmc->f_min = 400*1000; - mmc->f_max = SDIO_CLK_HZ; + mmc->f_min = 400000; + mmc->f_max = get_pll_freq(SDIO_CLK_SRC)/SDIO_CLK_DIV; mmc->ocr_avail = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_SDIO_IRQ; + MMC_CAP_SDIO_IRQ | MMC_CAP_NONREMOVABLE; res = request_mem_region(res->start, RESSIZE(res), DRIVER_NAME); if (!res) { @@ -864,6 +880,7 @@ host->dma_id = channel == 0 ? DMA_SD0RW : DMA_SD1RW; host->dma_active = 0; host->bus_width = MMC_BUS_WIDTH_1; + host->sdio_irq_en = 0; snprintf(host->name, sizeof(host->name), "sdio%1d", host->channel); @@ -888,24 +905,21 @@ goto out_irq; } - host->dma_channel = lf1000_dma_request(host->name, DMA_PRIO_MEDIUM, + host->dma_channel = lf1000_dma_request(host->name, DMA_PRIO_HIGH, lf1000_sdio_dma, (void *)host); if (host->dma_channel < 0) { dev_err(&pdev->dev, "can't get DMA channel\n"); goto out_dma; } - lf1000_dma_int_en(host->dma_channel); - /* prepare the hardware */ lf1000_sdio_setup_pins(host); lf1000_sdio_setup_controller(host); platform_set_drvdata(pdev, mmc); -#ifdef CONFIG_MMC_DEBUG lf1000_sdio_init_debugfs(host); -#endif + mmc_add_host(mmc); dev_dbg(&host->pdev->dev, "\"%s\" probe complete\n", host->name); @@ -924,13 +938,21 @@ return ret; } -/* TODO: loop through channels, fix up channel 1 resources */ static int lf1000_sdio_probe(struct platform_device *pdev) { - return lf1000_sdio_probe_channel(pdev, 0); + int ret; + +#ifdef CONFIG_MMC_LF1000_CHANNEL0 + ret = lf1000_sdio_probe_channel(pdev, 0); + if (ret) + return ret; +#endif +#ifdef CONFIG_MMC_LF1000_CHANNEL1 + ret = lf1000_sdio_probe_channel(pdev, 1); +#endif + return ret; } -/* TODO: remove multiple channels */ static int lf1000_sdio_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); @@ -939,21 +961,21 @@ if (mmc) { host = mmc_priv(mmc); -#ifdef CONFIG_MMC_DEBUG if (host->debug) debugfs_remove_recursive(host->debug); -#endif + mmc_remove_host(mmc); lf1000_sdio_clock_disable(host); + writel(0, host->base + SDI_INTMASK); + lf1000_sdio_clear_int_status(host); free_irq(host->irq, host); lf1000_dma_int_dis(host->dma_channel); lf1000_dma_free(host->dma_channel); - complete(&host->complete_request); + if (host->dma_active) + complete(&host->dma_transfer); iounmap(host->base); release_mem_region(host->mem->start, RESSIZE(host->mem)); release_resource(host->mem); - - mmc_free_host(mmc); } return 0;