X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/3047c0ecc311fb92179046be48414cc570d75d0b..a0d848ed9dde978ad40ef8b752ff2d651c00091b:/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c index 812e03797..b728c8745 100644 --- a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c +++ b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -32,8 +31,9 @@ #define DRIVER_NAME "glamo-mci" struct glamo_mci_host { - struct platform_device *pdev; struct glamo_mmc_platform_data *pdata; + struct platform_device *pdev; + struct glamo_core *core; struct mmc_host *mmc; struct resource *mmio_mem; struct resource *data_mem; @@ -53,8 +53,10 @@ struct glamo_mci_host { struct timer_list disable_timer; struct work_struct irq_work; + struct work_struct read_work; unsigned clk_enabled : 1; + }; static void glamo_mci_send_request(struct mmc_host *mmc, struct mmc_request* mrq); @@ -74,7 +76,7 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, * for example */ -static int sd_max_clk = 50000000; +static int sd_max_clk = 21000000; module_param(sd_max_clk, int, 0644); /* @@ -139,7 +141,7 @@ static void glamo_reg_set_bit_mask(struct glamo_mci_host *glamo, static void glamo_mci_clock_disable(struct glamo_mci_host *host) { if (host->clk_enabled) { - glamo_engine_div_disable(host->pdata->core, GLAMO_ENGINE_MMC); + glamo_engine_div_disable(host->core, GLAMO_ENGINE_MMC); host->clk_enabled = 0; } } @@ -148,7 +150,7 @@ static void glamo_mci_clock_enable(struct glamo_mci_host *host) { del_timer_sync(&host->disable_timer); if (!host->clk_enabled) { - glamo_engine_div_enable(host->pdata->core, GLAMO_ENGINE_MMC); + glamo_engine_div_enable(host->core, GLAMO_ENGINE_MMC); host->clk_enabled = 1; } } @@ -205,7 +207,7 @@ static int glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq) if (freq) { glamo_mci_clock_enable(host); - real_rate = glamo_engine_reclock(host->pdata->core, GLAMO_ENGINE_MMC, freq); + real_rate = glamo_engine_reclock(host->core, GLAMO_ENGINE_MMC, freq); } else { glamo_mci_clock_disable(host); } @@ -216,7 +218,6 @@ static int glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq) static void glamo_mci_request_done(struct glamo_mci_host *host, struct mmc_request *mrq) { mod_timer(&host->disable_timer, jiffies + HZ / 16); - mmc_request_done(host->mmc, mrq); } @@ -227,12 +228,17 @@ static void glamo_mci_irq_worker(struct work_struct *work) irq_work); struct mmc_command *cmd; uint16_t status; - if (!host->mrq || !host->mrq->cmd) return; cmd = host->mrq->cmd; +#if 0 + if (cmd->data->flags & MMC_DATA_READ) { + return; + } +#endif + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); dev_dbg(&host->pdev->dev, "status = 0x%04x\n", status); @@ -240,20 +246,20 @@ static void glamo_mci_irq_worker(struct work_struct *work) if (status & GLAMO_STAT1_MMC_RB_DRDY) status &= ~GLAMO_STAT1_MMC_DTOUT; - if (status & (GLAMO_STAT1_MMC_RTOUT | - GLAMO_STAT1_MMC_DTOUT)) + if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT)) cmd->error = -ETIMEDOUT; - if (status & (GLAMO_STAT1_MMC_BWERR | - GLAMO_STAT1_MMC_BRERR)) + if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) { cmd->error = -EILSEQ; + } if (cmd->error) { dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status); goto done; } /* issue STOP if we have been given one to use */ - if (host->mrq->stop) + if (host->mrq->stop) { glamo_mci_send_command(host, host->mrq->stop); + } if (cmd->data->flags & MMC_DATA_READ) do_pio_read(host, cmd->data); @@ -263,10 +269,70 @@ done: glamo_mci_request_done(host, cmd->mrq); } +static void glamo_mci_read_worker(struct work_struct *work) +{ + struct glamo_mci_host *host = container_of(work, struct glamo_mci_host, + read_work); + struct mmc_command *cmd; + uint16_t status; + uint16_t blocks_ready; + size_t data_read = 0; + size_t data_ready; + struct scatterlist *sg; + u16 __iomem *from_ptr = host->data_base; + void *sg_pointer; + + + cmd = host->mrq->cmd; + sg = cmd->data->sg; + do { + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); + + if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT)) + cmd->error = -ETIMEDOUT; + if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) + cmd->error = -EILSEQ; + if (cmd->error) { + dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status); + goto done; + } + + blocks_ready = glamo_reg_read(host, GLAMO_REG_MMC_RB_BLKCNT); + data_ready = blocks_ready * cmd->data->blksz; + + if (data_ready == data_read) + yield(); + + while(sg && data_read + sg->length <= data_ready) { + sg_pointer = page_address(sg_page(sg)) + sg->offset; + memcpy(sg_pointer, from_ptr, sg->length); + from_ptr += sg->length >> 1; + + data_read += sg->length; + sg = sg_next(sg); + } + + } while(sg); + cmd->data->bytes_xfered = data_read; + + do { + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); + } while (!(status & GLAMO_STAT1_MMC_IDLE)); + + if (host->mrq->stop) + glamo_mci_send_command(host, host->mrq->stop); + + do { + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); + } while (!(status & GLAMO_STAT1_MMC_IDLE)); +done: + host->mrq = NULL; + glamo_mci_request_done(host, cmd->mrq); +} + static irqreturn_t glamo_mci_irq(int irq, void *devid) { struct glamo_mci_host *host = (struct glamo_mci_host*)devid; - schedule_work(&host->irq_work); return IRQ_HANDLED; @@ -391,7 +457,7 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, break; } - if (triggers_int) + if (cmd->data) host->mrq = cmd->mrq; /* always largest timeout */ @@ -430,8 +496,7 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, GLAMO_STAT1_MMC_DTOUT)) || (timeout == 0)) { cmd->error = -ETIMEDOUT; - } else if (status & (GLAMO_STAT1_MMC_BWERR | - GLAMO_STAT1_MMC_BRERR)) { + } else if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) { cmd->error = -EILSEQ; } @@ -451,6 +516,15 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, ((readw(®_resp[2])) << 24); } } + +#if 0 + /* We'll only get an interrupt when all data has been transfered. + By starting to copy data when it's avaiable we can increase throughput by + up to 30%. */ + if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) + schedule_work(&host->read_work); +#endif + } static int glamo_mci_prepare_pio(struct glamo_mci_host *host, @@ -486,7 +560,7 @@ static int glamo_mci_irq_poll(struct glamo_mci_host *host, * but something insane like suspend problems can mean * we spin here forever, so we timeout after a LONG time */ - while ((!(readw(host->pdata->core->base + + while ((!(readw(host->core->base + GLAMO_REG_IRQ_STATUS) & GLAMO_IRQ_MMC)) && (timeout--)); @@ -497,7 +571,7 @@ static int glamo_mci_irq_poll(struct glamo_mci_host *host, return -ETIMEDOUT; } /* ack this interrupt source */ - writew(GLAMO_IRQ_MMC, host->pdata->core->base + + writew(GLAMO_IRQ_MMC, host->core->base + GLAMO_REG_IRQ_CLEAR); /* yay we are an interrupt controller! -- call the ISR @@ -513,9 +587,11 @@ static void glamo_mci_send_request(struct mmc_host *mmc, struct mmc_request *mrq struct glamo_mci_host *host = mmc_priv(mmc); struct mmc_command *cmd = mrq->cmd; + glamo_mci_clock_enable(host); host->request_counter++; if (cmd->data) { if(glamo_mci_prepare_pio(host, cmd->data)) { + cmd->error = -EIO; cmd->data->error = -EIO; goto done; } @@ -526,7 +602,6 @@ static void glamo_mci_send_request(struct mmc_host *mmc, struct mmc_request *mrq cmd->opcode, cmd->arg, cmd->data, cmd->mrq->stop, cmd->flags); - glamo_mci_clock_enable(host); glamo_mci_send_command(host, cmd); /* @@ -536,7 +611,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc, struct mmc_request *mrq goto done; - if (!host->pdata->core->irq_works) { + if (!host->core->irq_works) { if (glamo_mci_irq_poll(host, mrq->cmd)) goto done; } @@ -572,7 +647,7 @@ static void glamo_mci_set_power_mode(struct glamo_mci_host *host, break; case MMC_POWER_OFF: default: - glamo_engine_disable(host->pdata->core, + glamo_engine_disable(host->core, GLAMO_ENGINE_MMC); ret = regulator_disable(host->regulator); @@ -644,8 +719,9 @@ static struct mmc_host_ops glamo_mci_ops = { static int glamo_mci_probe(struct platform_device *pdev) { - struct mmc_host *mmc; - struct glamo_mci_host *host; + struct mmc_host *mmc; + struct glamo_mci_host *host; + struct glamo_core *core = dev_get_drvdata(pdev->dev.parent); int ret; dev_info(&pdev->dev, "glamo_mci driver (C)2007 Openmoko, Inc\n"); @@ -659,11 +735,14 @@ static int glamo_mci_probe(struct platform_device *pdev) host = mmc_priv(mmc); host->mmc = mmc; host->pdev = pdev; - host->pdata = pdev->dev.platform_data; + if (core->pdata) + host->pdata = core->pdata->mmc_data; host->power_mode = MMC_POWER_OFF; host->clk_enabled = 0; + host->core = core; INIT_WORK(&host->irq_work, glamo_mci_irq_worker); + INIT_WORK(&host->read_work, glamo_mci_read_worker); host->regulator = regulator_get(pdev->dev.parent, "SD_3V3"); if (!host->regulator) { @@ -735,7 +814,7 @@ static int glamo_mci_probe(struct platform_device *pdev) host->vdd = 0; - host->clk_rate = glamo_pll_rate(host->pdata->core, GLAMO_PLL1); + host->clk_rate = glamo_pll_rate(host->core, GLAMO_PLL1); /* explain our host controller capabilities */ mmc->ops = &glamo_mci_ops; @@ -744,7 +823,7 @@ static int glamo_mci_probe(struct platform_device *pdev) MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; mmc->f_min = host->clk_rate / 256; - mmc->f_max = host->clk_rate; + mmc->f_max = sd_max_clk; mmc->max_blk_count = (1 << 16) - 1; /* GLAMO_REG_MMC_RB_BLKCNT */ mmc->max_blk_size = (1 << 12) - 1; /* GLAMO_REG_MMC_RB_BLKLEN */ @@ -761,8 +840,8 @@ static int glamo_mci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mmc); - glamo_engine_enable(host->pdata->core, GLAMO_ENGINE_MMC); - glamo_engine_reset(host->pdata->core, GLAMO_ENGINE_MMC); + glamo_engine_enable(host->core, GLAMO_ENGINE_MMC); + glamo_engine_reset(host->core, GLAMO_ENGINE_MMC); glamo_reg_write(host, GLAMO_REG_MMC_WDATADS1, (u16)(host->data_mem->start)); @@ -820,7 +899,7 @@ static int glamo_mci_remove(struct platform_device *pdev) mmc_free_host(mmc); - glamo_engine_disable(host->pdata->core, GLAMO_ENGINE_MMC); + glamo_engine_disable(host->core, GLAMO_ENGINE_MMC); return 0; } @@ -847,8 +926,8 @@ static int glamo_mci_resume(struct device *dev) struct glamo_mci_host *host = mmc_priv(mmc); int ret; - glamo_engine_enable(host->pdata->core, GLAMO_ENGINE_MMC); - glamo_engine_reset(host->pdata->core, GLAMO_ENGINE_MMC); + glamo_engine_enable(host->core, GLAMO_ENGINE_MMC); + glamo_engine_reset(host->core, GLAMO_ENGINE_MMC); glamo_reg_write(host, GLAMO_REG_MMC_WDATADS1, (u16)(host->data_mem->start));