Commit 55be7f8d authored by Russell King's avatar Russell King

[MMC] MMCI optimisations.

Optimise register accesses; dereferencing "host" each time introduces
extra loads.

No need to check MCI_TXFIFOEMPTY when checking if we have a data IRQ.

Since we support clock bypass mode, the maximum clock rate is the
MCLK rate itself.
parent c1ea6029
...@@ -63,6 +63,7 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) ...@@ -63,6 +63,7 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
{ {
unsigned int datactrl, timeout, irqmask; unsigned int datactrl, timeout, irqmask;
void *base;
DBG(host, "blksz %04x blks %04x flags %08x\n", DBG(host, "blksz %04x blks %04x flags %08x\n",
1 << data->blksz_bits, data->blocks, data->flags); 1 << data->blksz_bits, data->blocks, data->flags);
...@@ -76,8 +77,9 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) ...@@ -76,8 +77,9 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
((unsigned long long)data->timeout_ns * host->cclk) / ((unsigned long long)data->timeout_ns * host->cclk) /
1000000000ULL; 1000000000ULL;
writel(timeout, host->base + MMCIDATATIMER); base = host->base;
writel(host->size, host->base + MMCIDATALENGTH); writel(timeout, base + MMCIDATATIMER);
writel(host->size, base + MMCIDATALENGTH);
datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4; datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
if (data->flags & MMC_DATA_READ) { if (data->flags & MMC_DATA_READ) {
...@@ -91,18 +93,20 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) ...@@ -91,18 +93,20 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
irqmask = MCI_TXFIFOHALFEMPTYMASK; irqmask = MCI_TXFIFOHALFEMPTYMASK;
} }
writel(datactrl, host->base + MMCIDATACTRL); writel(datactrl, base + MMCIDATACTRL);
writel(irqmask, host->base + MMCIMASK1); writel(irqmask, base + MMCIMASK1);
} }
static void static void
mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
{ {
void *base = host->base;
DBG(host, "op %02x arg %08x flags %08x\n", DBG(host, "op %02x arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags); cmd->opcode, cmd->arg, cmd->flags);
if (readl(host->base + MMCICOMMAND) & MCI_CPSM_ENABLE) { if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
writel(0, host->base + MMCICOMMAND); writel(0, base + MMCICOMMAND);
udelay(1); udelay(1);
} }
...@@ -122,8 +126,8 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) ...@@ -122,8 +126,8 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
host->cmd = cmd; host->cmd = cmd;
writel(cmd->arg, host->base + MMCIARGUMENT); writel(cmd->arg, base + MMCIARGUMENT);
writel(c, host->base + MMCICOMMAND); writel(c, base + MMCICOMMAND);
} }
static void static void
...@@ -146,7 +150,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, ...@@ -146,7 +150,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
host->data = NULL; host->data = NULL;
if (!data->stop) { if (!data->stop) {
mmci_request_end(host, data->mrq); mmci_request_end(host, data->mrq);
} else /*if (readl(host->base + MMCIDATACNT) > 6)*/ { } else {
mmci_start_command(host, data->stop, 0); mmci_start_command(host, data->stop, 0);
} }
} }
...@@ -156,12 +160,14 @@ static void ...@@ -156,12 +160,14 @@ static void
mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
unsigned int status) unsigned int status)
{ {
void *base = host->base;
host->cmd = NULL; host->cmd = NULL;
cmd->resp[0] = readl(host->base + MMCIRESPONSE0); cmd->resp[0] = readl(base + MMCIRESPONSE0);
cmd->resp[1] = readl(host->base + MMCIRESPONSE1); cmd->resp[1] = readl(base + MMCIRESPONSE1);
cmd->resp[2] = readl(host->base + MMCIRESPONSE2); cmd->resp[2] = readl(base + MMCIRESPONSE2);
cmd->resp[3] = readl(host->base + MMCIRESPONSE3); cmd->resp[3] = readl(base + MMCIRESPONSE3);
if (status & MCI_CMDTIMEOUT) { if (status & MCI_CMDTIMEOUT) {
cmd->error = MMC_ERR_TIMEOUT; cmd->error = MMC_ERR_TIMEOUT;
...@@ -176,27 +182,31 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ...@@ -176,27 +182,31 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
} }
} }
/*
* PIO data transfer IRQ handler.
*/
static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct mmci_host *host = dev_id; struct mmci_host *host = dev_id;
void *base = host->base;
u32 status; u32 status;
int ret = 0; int ret = 0;
do { do {
status = readl(host->base + MMCISTATUS); status = readl(base + MMCISTATUS);
if (!(status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL| if (!(status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL|
MCI_TXFIFOEMPTY|MCI_TXFIFOHALFEMPTY))) MCI_TXFIFOHALFEMPTY)))
break; break;
DBG(host, "irq1 %08x\n", status); DBG(host, "irq1 %08x\n", status);
if (status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL)) { if (status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL)) {
int count = host->size - (readl(host->base + MMCIFIFOCNT) << 2); unsigned int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
if (count < 0) if (count < 0)
count = 0; count = 0;
if (count && host->buffer) { if (count && host->buffer) {
readsl(host->base + MMCIFIFO, host->buffer, count >> 2); readsl(base + MMCIFIFO, host->buffer, count >> 2);
host->buffer += count; host->buffer += count;
host->size -= count; host->size -= count;
if (host->size == 0) if (host->size == 0)
...@@ -207,7 +217,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -207,7 +217,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
first = 0; first = 0;
printk(KERN_ERR "MMCI: sinking excessive data\n"); printk(KERN_ERR "MMCI: sinking excessive data\n");
} }
readl(host->base + MMCIFIFO); readl(base + MMCIFIFO);
} }
} }
...@@ -221,7 +231,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -221,7 +231,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
MCI_FIFOSIZE : MCI_FIFOHALFSIZE; MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
unsigned int count = min(host->size, maxcnt); unsigned int count = min(host->size, maxcnt);
writesl(host->base + MMCIFIFO, host->buffer, count >> 2); writesl(base + MMCIFIFO, host->buffer, count >> 2);
host->buffer += count; host->buffer += count;
host->size -= count; host->size -= count;
...@@ -242,6 +252,9 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -242,6 +252,9 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_RETVAL(ret); return IRQ_RETVAL(ret);
} }
/*
* Handle completion of command and data transfers.
*/
static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct mmci_host *host = dev_id; struct mmci_host *host = dev_id;
...@@ -411,7 +424,7 @@ static int mmci_probe(struct amba_device *dev, void *id) ...@@ -411,7 +424,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
mmc->ops = &mmci_ops; mmc->ops = &mmci_ops;
mmc->f_min = (host->mclk + 511) / 512; mmc->f_min = (host->mclk + 511) / 512;
mmc->f_max = min(host->mclk / 2, fmax); mmc->f_max = min(host->mclk, fmax);
mmc->ocr_avail = plat->ocr_mask; mmc->ocr_avail = plat->ocr_mask;
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment