diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c | 104 |
1 files changed, 89 insertions, 15 deletions
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..fdf292f8e 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 <linux/irq.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/crc7.h> #include <linux/scatterlist.h> @@ -53,6 +52,7 @@ struct glamo_mci_host { struct timer_list disable_timer; struct work_struct irq_work; + struct work_struct read_work; unsigned clk_enabled : 1; }; @@ -74,7 +74,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); /* @@ -216,7 +216,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 +226,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 +244,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 +267,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 +455,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 +494,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 +514,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, @@ -513,9 +585,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 +600,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); /* @@ -664,6 +737,7 @@ static int glamo_mci_probe(struct platform_device *pdev) host->clk_enabled = 0; 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) { @@ -744,7 +818,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 */ |