diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2010-05-22 02:36:56 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-05-22 02:36:56 -0400 |
commit | cf9b59e9d3e008591d1f54830f570982bb307a0d (patch) | |
tree | 113478ce8fd8c832ba726ffdf59b82cb46356476 /drivers/mmc | |
parent | 44504b2bebf8b5823c59484e73096a7d6574471d (diff) | |
parent | f4b87dee923342505e1ddba8d34ce9de33e75050 (diff) |
Merge remote branch 'origin' into secretlab/next-devicetree
Merging in current state of Linus' tree to deal with merge conflicts and
build failures in vio.c after merge.
Conflicts:
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-mpc.c
drivers/net/gianfar.c
Also fixed up one line in arch/powerpc/kernel/vio.c to use the
correct node pointer.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/at91_mci.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 20 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.c | 19 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 6 | ||||
-rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 472 | ||||
-rw-r--r-- | drivers/mmc/host/msm_sdcc.h | 15 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.c | 2 |
7 files changed, 334 insertions, 202 deletions
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index a6dd7da37357..336d9f553f3e 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c | |||
@@ -314,8 +314,8 @@ static void at91_mci_post_dma_read(struct at91mci_host *host) | |||
314 | dmabuf = (unsigned *)tmpv; | 314 | dmabuf = (unsigned *)tmpv; |
315 | } | 315 | } |
316 | 316 | ||
317 | flush_kernel_dcache_page(sg_page(sg)); | ||
317 | kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); | 318 | kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); |
318 | dmac_flush_range((void *)sgbuffer, ((void *)sgbuffer) + amount); | ||
319 | data->bytes_xfered += amount; | 319 | data->bytes_xfered += amount; |
320 | if (size == 0) | 320 | if (size == 0) |
321 | break; | 321 | break; |
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 88be37d9e9a5..df0e8a88d85f 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
@@ -266,7 +266,7 @@ static int atmci_req_show(struct seq_file *s, void *v) | |||
266 | "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", | 266 | "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", |
267 | cmd->opcode, cmd->arg, cmd->flags, | 267 | cmd->opcode, cmd->arg, cmd->flags, |
268 | cmd->resp[0], cmd->resp[1], cmd->resp[2], | 268 | cmd->resp[0], cmd->resp[1], cmd->resp[2], |
269 | cmd->resp[2], cmd->error); | 269 | cmd->resp[3], cmd->error); |
270 | if (data) | 270 | if (data) |
271 | seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", | 271 | seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", |
272 | data->bytes_xfered, data->blocks, | 272 | data->bytes_xfered, data->blocks, |
@@ -276,7 +276,7 @@ static int atmci_req_show(struct seq_file *s, void *v) | |||
276 | "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", | 276 | "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", |
277 | stop->opcode, stop->arg, stop->flags, | 277 | stop->opcode, stop->arg, stop->flags, |
278 | stop->resp[0], stop->resp[1], stop->resp[2], | 278 | stop->resp[0], stop->resp[1], stop->resp[2], |
279 | stop->resp[2], stop->error); | 279 | stop->resp[3], stop->error); |
280 | } | 280 | } |
281 | 281 | ||
282 | spin_unlock_bh(&slot->host->lock); | 282 | spin_unlock_bh(&slot->host->lock); |
@@ -569,9 +569,10 @@ static void atmci_dma_cleanup(struct atmel_mci *host) | |||
569 | { | 569 | { |
570 | struct mmc_data *data = host->data; | 570 | struct mmc_data *data = host->data; |
571 | 571 | ||
572 | dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, | 572 | if (data) |
573 | ((data->flags & MMC_DATA_WRITE) | 573 | dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, |
574 | ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); | 574 | ((data->flags & MMC_DATA_WRITE) |
575 | ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); | ||
575 | } | 576 | } |
576 | 577 | ||
577 | static void atmci_stop_dma(struct atmel_mci *host) | 578 | static void atmci_stop_dma(struct atmel_mci *host) |
@@ -579,7 +580,7 @@ static void atmci_stop_dma(struct atmel_mci *host) | |||
579 | struct dma_chan *chan = host->data_chan; | 580 | struct dma_chan *chan = host->data_chan; |
580 | 581 | ||
581 | if (chan) { | 582 | if (chan) { |
582 | chan->device->device_terminate_all(chan); | 583 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); |
583 | atmci_dma_cleanup(host); | 584 | atmci_dma_cleanup(host); |
584 | } else { | 585 | } else { |
585 | /* Data transfer was stopped by the interrupt handler */ | 586 | /* Data transfer was stopped by the interrupt handler */ |
@@ -1099,8 +1100,8 @@ static void atmci_command_complete(struct atmel_mci *host, | |||
1099 | "command error: status=0x%08x\n", status); | 1100 | "command error: status=0x%08x\n", status); |
1100 | 1101 | ||
1101 | if (cmd->data) { | 1102 | if (cmd->data) { |
1102 | host->data = NULL; | ||
1103 | atmci_stop_dma(host); | 1103 | atmci_stop_dma(host); |
1104 | host->data = NULL; | ||
1104 | mci_writel(host, IDR, MCI_NOTBUSY | 1105 | mci_writel(host, IDR, MCI_NOTBUSY |
1105 | | MCI_TXRDY | MCI_RXRDY | 1106 | | MCI_TXRDY | MCI_RXRDY |
1106 | | ATMCI_DATA_ERROR_FLAGS); | 1107 | | ATMCI_DATA_ERROR_FLAGS); |
@@ -1293,6 +1294,7 @@ static void atmci_tasklet_func(unsigned long priv) | |||
1293 | } else { | 1294 | } else { |
1294 | data->bytes_xfered = data->blocks * data->blksz; | 1295 | data->bytes_xfered = data->blocks * data->blksz; |
1295 | data->error = 0; | 1296 | data->error = 0; |
1297 | mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS); | ||
1296 | } | 1298 | } |
1297 | 1299 | ||
1298 | if (!data->stop) { | 1300 | if (!data->stop) { |
@@ -1751,13 +1753,13 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
1751 | ret = -ENODEV; | 1753 | ret = -ENODEV; |
1752 | if (pdata->slot[0].bus_width) { | 1754 | if (pdata->slot[0].bus_width) { |
1753 | ret = atmci_init_slot(host, &pdata->slot[0], | 1755 | ret = atmci_init_slot(host, &pdata->slot[0], |
1754 | MCI_SDCSEL_SLOT_A, 0); | 1756 | 0, MCI_SDCSEL_SLOT_A); |
1755 | if (!ret) | 1757 | if (!ret) |
1756 | nr_slots++; | 1758 | nr_slots++; |
1757 | } | 1759 | } |
1758 | if (pdata->slot[1].bus_width) { | 1760 | if (pdata->slot[1].bus_width) { |
1759 | ret = atmci_init_slot(host, &pdata->slot[1], | 1761 | ret = atmci_init_slot(host, &pdata->slot[1], |
1760 | MCI_SDCSEL_SLOT_B, 1); | 1762 | 1, MCI_SDCSEL_SLOT_B); |
1761 | if (!ret) | 1763 | if (!ret) |
1762 | nr_slots++; | 1764 | nr_slots++; |
1763 | } | 1765 | } |
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 84c103a7ee13..ff115d920888 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
@@ -55,14 +55,16 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) | |||
55 | host->cclk = host->mclk / (2 * (clk + 1)); | 55 | host->cclk = host->mclk / (2 * (clk + 1)); |
56 | } | 56 | } |
57 | if (host->hw_designer == AMBA_VENDOR_ST) | 57 | if (host->hw_designer == AMBA_VENDOR_ST) |
58 | clk |= MCI_FCEN; /* Bug fix in ST IP block */ | 58 | clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */ |
59 | clk |= MCI_CLK_ENABLE; | 59 | clk |= MCI_CLK_ENABLE; |
60 | /* This hasn't proven to be worthwhile */ | 60 | /* This hasn't proven to be worthwhile */ |
61 | /* clk |= MCI_CLK_PWRSAVE; */ | 61 | /* clk |= MCI_CLK_PWRSAVE; */ |
62 | } | 62 | } |
63 | 63 | ||
64 | if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) | 64 | if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) |
65 | clk |= MCI_WIDE_BUS; | 65 | clk |= MCI_4BIT_BUS; |
66 | if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) | ||
67 | clk |= MCI_ST_8BIT_BUS; | ||
66 | 68 | ||
67 | writel(clk, host->base + MMCICLOCK); | 69 | writel(clk, host->base + MMCICLOCK); |
68 | } | 70 | } |
@@ -629,7 +631,18 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
629 | 631 | ||
630 | mmc->ops = &mmci_ops; | 632 | mmc->ops = &mmci_ops; |
631 | mmc->f_min = (host->mclk + 511) / 512; | 633 | mmc->f_min = (host->mclk + 511) / 512; |
632 | mmc->f_max = min(host->mclk, fmax); | 634 | /* |
635 | * If the platform data supplies a maximum operating | ||
636 | * frequency, this takes precedence. Else, we fall back | ||
637 | * to using the module parameter, which has a (low) | ||
638 | * default value in case it is not specified. Either | ||
639 | * value must not exceed the clock rate into the block, | ||
640 | * of course. | ||
641 | */ | ||
642 | if (plat->f_max) | ||
643 | mmc->f_max = min(host->mclk, plat->f_max); | ||
644 | else | ||
645 | mmc->f_max = min(host->mclk, fmax); | ||
633 | dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); | 646 | dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); |
634 | 647 | ||
635 | #ifdef CONFIG_REGULATOR | 648 | #ifdef CONFIG_REGULATOR |
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 1ceb9a90f59b..d77062e5e3af 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h | |||
@@ -25,9 +25,11 @@ | |||
25 | #define MCI_CLK_ENABLE (1 << 8) | 25 | #define MCI_CLK_ENABLE (1 << 8) |
26 | #define MCI_CLK_PWRSAVE (1 << 9) | 26 | #define MCI_CLK_PWRSAVE (1 << 9) |
27 | #define MCI_CLK_BYPASS (1 << 10) | 27 | #define MCI_CLK_BYPASS (1 << 10) |
28 | #define MCI_WIDE_BUS (1 << 11) | 28 | #define MCI_4BIT_BUS (1 << 11) |
29 | /* 8bit wide buses supported in ST Micro versions */ | ||
30 | #define MCI_ST_8BIT_BUS (1 << 12) | ||
29 | /* HW flow control on the ST Micro version */ | 31 | /* HW flow control on the ST Micro version */ |
30 | #define MCI_FCEN (1 << 13) | 32 | #define MCI_ST_FCEN (1 << 13) |
31 | 33 | ||
32 | #define MMCIARGUMENT 0x008 | 34 | #define MMCIARGUMENT 0x008 |
33 | #define MMCICOMMAND 0x00c | 35 | #define MMCICOMMAND 0x00c |
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 04ae884383f6..61f1d27fed3f 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2007 Google Inc, | 4 | * Copyright (C) 2007 Google Inc, |
5 | * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. | 5 | * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. |
6 | * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -26,6 +27,7 @@ | |||
26 | #include <linux/log2.h> | 27 | #include <linux/log2.h> |
27 | #include <linux/mmc/host.h> | 28 | #include <linux/mmc/host.h> |
28 | #include <linux/mmc/card.h> | 29 | #include <linux/mmc/card.h> |
30 | #include <linux/mmc/sdio.h> | ||
29 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
30 | #include <linux/scatterlist.h> | 32 | #include <linux/scatterlist.h> |
31 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
@@ -47,6 +49,8 @@ | |||
47 | 49 | ||
48 | #define DRIVER_NAME "msm-sdcc" | 50 | #define DRIVER_NAME "msm-sdcc" |
49 | 51 | ||
52 | #define BUSCLK_PWRSAVE 1 | ||
53 | #define BUSCLK_TIMEOUT (HZ) | ||
50 | static unsigned int msmsdcc_fmin = 144000; | 54 | static unsigned int msmsdcc_fmin = 144000; |
51 | static unsigned int msmsdcc_fmax = 50000000; | 55 | static unsigned int msmsdcc_fmax = 50000000; |
52 | static unsigned int msmsdcc_4bit = 1; | 56 | static unsigned int msmsdcc_4bit = 1; |
@@ -57,6 +61,67 @@ static unsigned int msmsdcc_sdioirq; | |||
57 | #define PIO_SPINMAX 30 | 61 | #define PIO_SPINMAX 30 |
58 | #define CMD_SPINMAX 20 | 62 | #define CMD_SPINMAX 20 |
59 | 63 | ||
64 | |||
65 | static inline void | ||
66 | msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) | ||
67 | { | ||
68 | WARN_ON(!host->clks_on); | ||
69 | |||
70 | BUG_ON(host->curr.mrq); | ||
71 | |||
72 | if (deferr) { | ||
73 | mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); | ||
74 | } else { | ||
75 | del_timer_sync(&host->busclk_timer); | ||
76 | /* Need to check clks_on again in case the busclk | ||
77 | * timer fired | ||
78 | */ | ||
79 | if (host->clks_on) { | ||
80 | clk_disable(host->clk); | ||
81 | clk_disable(host->pclk); | ||
82 | host->clks_on = 0; | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
87 | static inline int | ||
88 | msmsdcc_enable_clocks(struct msmsdcc_host *host) | ||
89 | { | ||
90 | int rc; | ||
91 | |||
92 | del_timer_sync(&host->busclk_timer); | ||
93 | |||
94 | if (!host->clks_on) { | ||
95 | rc = clk_enable(host->pclk); | ||
96 | if (rc) | ||
97 | return rc; | ||
98 | rc = clk_enable(host->clk); | ||
99 | if (rc) { | ||
100 | clk_disable(host->pclk); | ||
101 | return rc; | ||
102 | } | ||
103 | udelay(1 + ((3 * USEC_PER_SEC) / | ||
104 | (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); | ||
105 | host->clks_on = 1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static inline unsigned int | ||
111 | msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) | ||
112 | { | ||
113 | return readl(host->base + reg); | ||
114 | } | ||
115 | |||
116 | static inline void | ||
117 | msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) | ||
118 | { | ||
119 | writel(data, host->base + reg); | ||
120 | /* 3 clk delay required! */ | ||
121 | udelay(1 + ((3 * USEC_PER_SEC) / | ||
122 | (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); | ||
123 | } | ||
124 | |||
60 | static void | 125 | static void |
61 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, | 126 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, |
62 | u32 c); | 127 | u32 c); |
@@ -64,8 +129,6 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, | |||
64 | static void | 129 | static void |
65 | msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | 130 | msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) |
66 | { | 131 | { |
67 | writel(0, host->base + MMCICOMMAND); | ||
68 | |||
69 | BUG_ON(host->curr.data); | 132 | BUG_ON(host->curr.data); |
70 | 133 | ||
71 | host->curr.mrq = NULL; | 134 | host->curr.mrq = NULL; |
@@ -76,6 +139,9 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | |||
76 | if (mrq->cmd->error == -ETIMEDOUT) | 139 | if (mrq->cmd->error == -ETIMEDOUT) |
77 | mdelay(5); | 140 | mdelay(5); |
78 | 141 | ||
142 | #if BUSCLK_PWRSAVE | ||
143 | msmsdcc_disable_clocks(host, 1); | ||
144 | #endif | ||
79 | /* | 145 | /* |
80 | * Need to drop the host lock here; mmc_request_done may call | 146 | * Need to drop the host lock here; mmc_request_done may call |
81 | * back into the driver... | 147 | * back into the driver... |
@@ -88,7 +154,6 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | |||
88 | static void | 154 | static void |
89 | msmsdcc_stop_data(struct msmsdcc_host *host) | 155 | msmsdcc_stop_data(struct msmsdcc_host *host) |
90 | { | 156 | { |
91 | writel(0, host->base + MMCIDATACTRL); | ||
92 | host->curr.data = NULL; | 157 | host->curr.data = NULL; |
93 | host->curr.got_dataend = host->curr.got_datablkend = 0; | 158 | host->curr.got_dataend = host->curr.got_datablkend = 0; |
94 | } | 159 | } |
@@ -109,6 +174,31 @@ uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) | |||
109 | return 0; | 174 | return 0; |
110 | } | 175 | } |
111 | 176 | ||
177 | static inline void | ||
178 | msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { | ||
179 | msmsdcc_writel(host, arg, MMCIARGUMENT); | ||
180 | msmsdcc_writel(host, c, MMCICOMMAND); | ||
181 | } | ||
182 | |||
183 | static void | ||
184 | msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) | ||
185 | { | ||
186 | struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; | ||
187 | |||
188 | msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); | ||
189 | msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, | ||
190 | MMCIDATALENGTH); | ||
191 | msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); | ||
192 | msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); | ||
193 | |||
194 | if (host->cmd_cmd) { | ||
195 | msmsdcc_start_command_exec(host, | ||
196 | (u32) host->cmd_cmd->arg, | ||
197 | (u32) host->cmd_c); | ||
198 | } | ||
199 | host->dma.active = 1; | ||
200 | } | ||
201 | |||
112 | static void | 202 | static void |
113 | msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | 203 | msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, |
114 | unsigned int result, | 204 | unsigned int result, |
@@ -121,8 +211,11 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
121 | struct mmc_request *mrq; | 211 | struct mmc_request *mrq; |
122 | 212 | ||
123 | spin_lock_irqsave(&host->lock, flags); | 213 | spin_lock_irqsave(&host->lock, flags); |
214 | host->dma.active = 0; | ||
215 | |||
124 | mrq = host->curr.mrq; | 216 | mrq = host->curr.mrq; |
125 | BUG_ON(!mrq); | 217 | BUG_ON(!mrq); |
218 | WARN_ON(!mrq->data); | ||
126 | 219 | ||
127 | if (!(result & DMOV_RSLT_VALID)) { | 220 | if (!(result & DMOV_RSLT_VALID)) { |
128 | pr_err("msmsdcc: Invalid DataMover result\n"); | 221 | pr_err("msmsdcc: Invalid DataMover result\n"); |
@@ -146,7 +239,6 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
146 | if (!mrq->data->error) | 239 | if (!mrq->data->error) |
147 | mrq->data->error = -EIO; | 240 | mrq->data->error = -EIO; |
148 | } | 241 | } |
149 | host->dma.busy = 0; | ||
150 | dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, | 242 | dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, |
151 | host->dma.dir); | 243 | host->dma.dir); |
152 | 244 | ||
@@ -159,6 +251,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
159 | } | 251 | } |
160 | 252 | ||
161 | host->dma.sg = NULL; | 253 | host->dma.sg = NULL; |
254 | host->dma.busy = 0; | ||
162 | 255 | ||
163 | if ((host->curr.got_dataend && host->curr.got_datablkend) | 256 | if ((host->curr.got_dataend && host->curr.got_datablkend) |
164 | || mrq->data->error) { | 257 | || mrq->data->error) { |
@@ -172,12 +265,14 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | |||
172 | if (!mrq->data->error) | 265 | if (!mrq->data->error) |
173 | host->curr.data_xfered = host->curr.xfer_size; | 266 | host->curr.data_xfered = host->curr.xfer_size; |
174 | if (!mrq->data->stop || mrq->cmd->error) { | 267 | if (!mrq->data->stop || mrq->cmd->error) { |
175 | writel(0, host->base + MMCICOMMAND); | ||
176 | host->curr.mrq = NULL; | 268 | host->curr.mrq = NULL; |
177 | host->curr.cmd = NULL; | 269 | host->curr.cmd = NULL; |
178 | mrq->data->bytes_xfered = host->curr.data_xfered; | 270 | mrq->data->bytes_xfered = host->curr.data_xfered; |
179 | 271 | ||
180 | spin_unlock_irqrestore(&host->lock, flags); | 272 | spin_unlock_irqrestore(&host->lock, flags); |
273 | #if BUSCLK_PWRSAVE | ||
274 | msmsdcc_disable_clocks(host, 1); | ||
275 | #endif | ||
181 | mmc_request_done(host->mmc, mrq); | 276 | mmc_request_done(host->mmc, mrq); |
182 | return; | 277 | return; |
183 | } else | 278 | } else |
@@ -218,6 +313,8 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
218 | host->dma.sg = data->sg; | 313 | host->dma.sg = data->sg; |
219 | host->dma.num_ents = data->sg_len; | 314 | host->dma.num_ents = data->sg_len; |
220 | 315 | ||
316 | BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ | ||
317 | |||
221 | nc = host->dma.nc; | 318 | nc = host->dma.nc; |
222 | 319 | ||
223 | switch (host->pdev_id) { | 320 | switch (host->pdev_id) { |
@@ -246,22 +343,15 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
246 | 343 | ||
247 | host->curr.user_pages = 0; | 344 | host->curr.user_pages = 0; |
248 | 345 | ||
249 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | ||
250 | host->dma.num_ents, host->dma.dir); | ||
251 | |||
252 | if (n != host->dma.num_ents) { | ||
253 | pr_err("%s: Unable to map in all sg elements\n", | ||
254 | mmc_hostname(host->mmc)); | ||
255 | host->dma.sg = NULL; | ||
256 | host->dma.num_ents = 0; | ||
257 | return -ENOMEM; | ||
258 | } | ||
259 | |||
260 | box = &nc->cmd[0]; | 346 | box = &nc->cmd[0]; |
261 | for (i = 0; i < host->dma.num_ents; i++) { | 347 | for (i = 0; i < host->dma.num_ents; i++) { |
262 | box->cmd = CMD_MODE_BOX; | 348 | box->cmd = CMD_MODE_BOX; |
263 | 349 | ||
264 | if (i == (host->dma.num_ents - 1)) | 350 | /* Initialize sg dma address */ |
351 | sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) | ||
352 | + sg->offset; | ||
353 | |||
354 | if (i == (host->dma.num_ents - 1)) | ||
265 | box->cmd |= CMD_LC; | 355 | box->cmd |= CMD_LC; |
266 | rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? | 356 | rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? |
267 | (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : | 357 | (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : |
@@ -300,15 +390,70 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
300 | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); | 390 | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); |
301 | host->dma.hdr.complete_func = msmsdcc_dma_complete_func; | 391 | host->dma.hdr.complete_func = msmsdcc_dma_complete_func; |
302 | 392 | ||
393 | n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | ||
394 | host->dma.num_ents, host->dma.dir); | ||
395 | /* dsb inside dma_map_sg will write nc out to mem as well */ | ||
396 | |||
397 | if (n != host->dma.num_ents) { | ||
398 | printk(KERN_ERR "%s: Unable to map in all sg elements\n", | ||
399 | mmc_hostname(host->mmc)); | ||
400 | host->dma.sg = NULL; | ||
401 | host->dma.num_ents = 0; | ||
402 | return -ENOMEM; | ||
403 | } | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int | ||
409 | snoop_cccr_abort(struct mmc_command *cmd) | ||
410 | { | ||
411 | if ((cmd->opcode == 52) && | ||
412 | (cmd->arg & 0x80000000) && | ||
413 | (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) | ||
414 | return 1; | ||
303 | return 0; | 415 | return 0; |
304 | } | 416 | } |
305 | 417 | ||
306 | static void | 418 | static void |
307 | msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | 419 | msmsdcc_start_command_deferred(struct msmsdcc_host *host, |
420 | struct mmc_command *cmd, u32 *c) | ||
421 | { | ||
422 | *c |= (cmd->opcode | MCI_CPSM_ENABLE); | ||
423 | |||
424 | if (cmd->flags & MMC_RSP_PRESENT) { | ||
425 | if (cmd->flags & MMC_RSP_136) | ||
426 | *c |= MCI_CPSM_LONGRSP; | ||
427 | *c |= MCI_CPSM_RESPONSE; | ||
428 | } | ||
429 | |||
430 | if (/*interrupt*/0) | ||
431 | *c |= MCI_CPSM_INTERRUPT; | ||
432 | |||
433 | if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || | ||
434 | ((cmd->opcode == 24) || (cmd->opcode == 25))) || | ||
435 | (cmd->opcode == 53)) | ||
436 | *c |= MCI_CSPM_DATCMD; | ||
437 | |||
438 | if (cmd == cmd->mrq->stop) | ||
439 | *c |= MCI_CSPM_MCIABORT; | ||
440 | |||
441 | if (snoop_cccr_abort(cmd)) | ||
442 | *c |= MCI_CSPM_MCIABORT; | ||
443 | |||
444 | if (host->curr.cmd != NULL) { | ||
445 | printk(KERN_ERR "%s: Overlapping command requests\n", | ||
446 | mmc_hostname(host->mmc)); | ||
447 | } | ||
448 | host->curr.cmd = cmd; | ||
449 | } | ||
450 | |||
451 | static void | ||
452 | msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, | ||
453 | struct mmc_command *cmd, u32 c) | ||
308 | { | 454 | { |
309 | unsigned int datactrl, timeout; | 455 | unsigned int datactrl, timeout; |
310 | unsigned long long clks; | 456 | unsigned long long clks; |
311 | void __iomem *base = host->base; | ||
312 | unsigned int pio_irqmask = 0; | 457 | unsigned int pio_irqmask = 0; |
313 | 458 | ||
314 | host->curr.data = data; | 459 | host->curr.data = data; |
@@ -320,13 +465,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | |||
320 | 465 | ||
321 | memset(&host->pio, 0, sizeof(host->pio)); | 466 | memset(&host->pio, 0, sizeof(host->pio)); |
322 | 467 | ||
323 | clks = (unsigned long long)data->timeout_ns * host->clk_rate; | ||
324 | do_div(clks, NSEC_PER_SEC); | ||
325 | timeout = data->timeout_clks + (unsigned int)clks; | ||
326 | writel(timeout, base + MMCIDATATIMER); | ||
327 | |||
328 | writel(host->curr.xfer_size, base + MMCIDATALENGTH); | ||
329 | |||
330 | datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); | 468 | datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); |
331 | 469 | ||
332 | if (!msmsdcc_config_dma(host, data)) | 470 | if (!msmsdcc_config_dma(host, data)) |
@@ -347,47 +485,51 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | |||
347 | if (data->flags & MMC_DATA_READ) | 485 | if (data->flags & MMC_DATA_READ) |
348 | datactrl |= MCI_DPSM_DIRECTION; | 486 | datactrl |= MCI_DPSM_DIRECTION; |
349 | 487 | ||
350 | writel(pio_irqmask, base + MMCIMASK1); | 488 | clks = (unsigned long long)data->timeout_ns * host->clk_rate; |
351 | writel(datactrl, base + MMCIDATACTRL); | 489 | do_div(clks, NSEC_PER_SEC); |
490 | timeout = data->timeout_clks + (unsigned int)clks*2 ; | ||
352 | 491 | ||
353 | if (datactrl & MCI_DPSM_DMAENABLE) { | 492 | if (datactrl & MCI_DPSM_DMAENABLE) { |
493 | /* Save parameters for the exec function */ | ||
494 | host->cmd_timeout = timeout; | ||
495 | host->cmd_pio_irqmask = pio_irqmask; | ||
496 | host->cmd_datactrl = datactrl; | ||
497 | host->cmd_cmd = cmd; | ||
498 | |||
499 | host->dma.hdr.execute_func = msmsdcc_dma_exec_func; | ||
500 | host->dma.hdr.data = (void *)host; | ||
354 | host->dma.busy = 1; | 501 | host->dma.busy = 1; |
502 | |||
503 | if (cmd) { | ||
504 | msmsdcc_start_command_deferred(host, cmd, &c); | ||
505 | host->cmd_c = c; | ||
506 | } | ||
355 | msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); | 507 | msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); |
508 | } else { | ||
509 | msmsdcc_writel(host, timeout, MMCIDATATIMER); | ||
510 | |||
511 | msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); | ||
512 | |||
513 | msmsdcc_writel(host, pio_irqmask, MMCIMASK1); | ||
514 | msmsdcc_writel(host, datactrl, MMCIDATACTRL); | ||
515 | |||
516 | if (cmd) { | ||
517 | /* Daisy-chain the command if requested */ | ||
518 | msmsdcc_start_command(host, cmd, c); | ||
519 | } | ||
356 | } | 520 | } |
357 | } | 521 | } |
358 | 522 | ||
359 | static void | 523 | static void |
360 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) | 524 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) |
361 | { | 525 | { |
362 | void __iomem *base = host->base; | ||
363 | |||
364 | if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { | ||
365 | writel(0, base + MMCICOMMAND); | ||
366 | udelay(2 + ((5 * 1000000) / host->clk_rate)); | ||
367 | } | ||
368 | |||
369 | c |= cmd->opcode | MCI_CPSM_ENABLE; | ||
370 | |||
371 | if (cmd->flags & MMC_RSP_PRESENT) { | ||
372 | if (cmd->flags & MMC_RSP_136) | ||
373 | c |= MCI_CPSM_LONGRSP; | ||
374 | c |= MCI_CPSM_RESPONSE; | ||
375 | } | ||
376 | |||
377 | if (cmd->opcode == 17 || cmd->opcode == 18 || | ||
378 | cmd->opcode == 24 || cmd->opcode == 25 || | ||
379 | cmd->opcode == 53) | ||
380 | c |= MCI_CSPM_DATCMD; | ||
381 | |||
382 | if (cmd == cmd->mrq->stop) | 526 | if (cmd == cmd->mrq->stop) |
383 | c |= MCI_CSPM_MCIABORT; | 527 | c |= MCI_CSPM_MCIABORT; |
384 | 528 | ||
385 | host->curr.cmd = cmd; | ||
386 | |||
387 | host->stats.cmds++; | 529 | host->stats.cmds++; |
388 | 530 | ||
389 | writel(cmd->arg, base + MMCIARGUMENT); | 531 | msmsdcc_start_command_deferred(host, cmd, &c); |
390 | writel(c, base + MMCICOMMAND); | 532 | msmsdcc_start_command_exec(host, cmd->arg, c); |
391 | } | 533 | } |
392 | 534 | ||
393 | static void | 535 | static void |
@@ -421,13 +563,11 @@ msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, | |||
421 | static int | 563 | static int |
422 | msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) | 564 | msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) |
423 | { | 565 | { |
424 | void __iomem *base = host->base; | ||
425 | uint32_t *ptr = (uint32_t *) buffer; | 566 | uint32_t *ptr = (uint32_t *) buffer; |
426 | int count = 0; | 567 | int count = 0; |
427 | 568 | ||
428 | while (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) { | 569 | while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { |
429 | 570 | *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); | |
430 | *ptr = readl(base + MMCIFIFO + (count % MCI_FIFOSIZE)); | ||
431 | ptr++; | 571 | ptr++; |
432 | count += sizeof(uint32_t); | 572 | count += sizeof(uint32_t); |
433 | 573 | ||
@@ -459,7 +599,7 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, | |||
459 | if (remain == 0) | 599 | if (remain == 0) |
460 | break; | 600 | break; |
461 | 601 | ||
462 | status = readl(base + MMCISTATUS); | 602 | status = msmsdcc_readl(host, MMCISTATUS); |
463 | } while (status & MCI_TXFIFOHALFEMPTY); | 603 | } while (status & MCI_TXFIFOHALFEMPTY); |
464 | 604 | ||
465 | return ptr - buffer; | 605 | return ptr - buffer; |
@@ -469,7 +609,7 @@ static int | |||
469 | msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) | 609 | msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) |
470 | { | 610 | { |
471 | while (maxspin) { | 611 | while (maxspin) { |
472 | if ((readl(host->base + MMCISTATUS) & mask)) | 612 | if ((msmsdcc_readl(host, MMCISTATUS) & mask)) |
473 | return 0; | 613 | return 0; |
474 | udelay(1); | 614 | udelay(1); |
475 | --maxspin; | 615 | --maxspin; |
@@ -477,14 +617,13 @@ msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) | |||
477 | return -ETIMEDOUT; | 617 | return -ETIMEDOUT; |
478 | } | 618 | } |
479 | 619 | ||
480 | static int | 620 | static irqreturn_t |
481 | msmsdcc_pio_irq(int irq, void *dev_id) | 621 | msmsdcc_pio_irq(int irq, void *dev_id) |
482 | { | 622 | { |
483 | struct msmsdcc_host *host = dev_id; | 623 | struct msmsdcc_host *host = dev_id; |
484 | void __iomem *base = host->base; | ||
485 | uint32_t status; | 624 | uint32_t status; |
486 | 625 | ||
487 | status = readl(base + MMCISTATUS); | 626 | status = msmsdcc_readl(host, MMCISTATUS); |
488 | 627 | ||
489 | do { | 628 | do { |
490 | unsigned long flags; | 629 | unsigned long flags; |
@@ -539,14 +678,14 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
539 | host->pio.sg_off = 0; | 678 | host->pio.sg_off = 0; |
540 | } | 679 | } |
541 | 680 | ||
542 | status = readl(base + MMCISTATUS); | 681 | status = msmsdcc_readl(host, MMCISTATUS); |
543 | } while (1); | 682 | } while (1); |
544 | 683 | ||
545 | if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) | 684 | if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) |
546 | writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); | 685 | msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); |
547 | 686 | ||
548 | if (!host->curr.xfer_remain) | 687 | if (!host->curr.xfer_remain) |
549 | writel(0, base + MMCIMASK1); | 688 | msmsdcc_writel(host, 0, MMCIMASK1); |
550 | 689 | ||
551 | return IRQ_HANDLED; | 690 | return IRQ_HANDLED; |
552 | } | 691 | } |
@@ -554,15 +693,13 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
554 | static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) | 693 | static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) |
555 | { | 694 | { |
556 | struct mmc_command *cmd = host->curr.cmd; | 695 | struct mmc_command *cmd = host->curr.cmd; |
557 | void __iomem *base = host->base; | ||
558 | 696 | ||
559 | host->curr.cmd = NULL; | 697 | host->curr.cmd = NULL; |
560 | cmd->resp[0] = readl(base + MMCIRESPONSE0); | 698 | cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); |
561 | cmd->resp[1] = readl(base + MMCIRESPONSE1); | 699 | cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); |
562 | cmd->resp[2] = readl(base + MMCIRESPONSE2); | 700 | cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); |
563 | cmd->resp[3] = readl(base + MMCIRESPONSE3); | 701 | cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); |
564 | 702 | ||
565 | del_timer(&host->command_timer); | ||
566 | if (status & MCI_CMDTIMEOUT) { | 703 | if (status & MCI_CMDTIMEOUT) { |
567 | cmd->error = -ETIMEDOUT; | 704 | cmd->error = -ETIMEDOUT; |
568 | } else if (status & MCI_CMDCRCFAIL && | 705 | } else if (status & MCI_CMDCRCFAIL && |
@@ -580,8 +717,10 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) | |||
580 | msmsdcc_request_end(host, cmd->mrq); | 717 | msmsdcc_request_end(host, cmd->mrq); |
581 | } else /* host->data == NULL */ | 718 | } else /* host->data == NULL */ |
582 | msmsdcc_request_end(host, cmd->mrq); | 719 | msmsdcc_request_end(host, cmd->mrq); |
583 | } else if (!(cmd->data->flags & MMC_DATA_READ)) | 720 | } else if (cmd->data) |
584 | msmsdcc_start_data(host, cmd->data); | 721 | if (!(cmd->data->flags & MMC_DATA_READ)) |
722 | msmsdcc_start_data(host, cmd->data, | ||
723 | NULL, 0); | ||
585 | } | 724 | } |
586 | 725 | ||
587 | static void | 726 | static void |
@@ -590,6 +729,11 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, | |||
590 | { | 729 | { |
591 | struct mmc_data *data = host->curr.data; | 730 | struct mmc_data *data = host->curr.data; |
592 | 731 | ||
732 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | | ||
733 | MCI_CMDTIMEOUT) && host->curr.cmd) { | ||
734 | msmsdcc_do_cmdirq(host, status); | ||
735 | } | ||
736 | |||
593 | if (!data) | 737 | if (!data) |
594 | return; | 738 | return; |
595 | 739 | ||
@@ -602,7 +746,8 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, | |||
602 | msm_dmov_stop_cmd(host->dma.channel, | 746 | msm_dmov_stop_cmd(host->dma.channel, |
603 | &host->dma.hdr, 0); | 747 | &host->dma.hdr, 0); |
604 | else { | 748 | else { |
605 | msmsdcc_stop_data(host); | 749 | if (host->curr.data) |
750 | msmsdcc_stop_data(host); | ||
606 | if (!data->stop) | 751 | if (!data->stop) |
607 | msmsdcc_request_end(host, data->mrq); | 752 | msmsdcc_request_end(host, data->mrq); |
608 | else | 753 | else |
@@ -657,17 +802,18 @@ msmsdcc_irq(int irq, void *dev_id) | |||
657 | spin_lock(&host->lock); | 802 | spin_lock(&host->lock); |
658 | 803 | ||
659 | do { | 804 | do { |
660 | status = readl(base + MMCISTATUS); | 805 | status = msmsdcc_readl(host, MMCISTATUS); |
806 | status &= (msmsdcc_readl(host, MMCIMASK0) | | ||
807 | MCI_DATABLOCKENDMASK); | ||
808 | msmsdcc_writel(host, status, MMCICLEAR); | ||
661 | 809 | ||
662 | status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); | 810 | if (status & MCI_SDIOINTR) |
663 | writel(status, base + MMCICLEAR); | 811 | status &= ~MCI_SDIOINTR; |
664 | 812 | ||
665 | msmsdcc_handle_irq_data(host, status, base); | 813 | if (!status) |
814 | break; | ||
666 | 815 | ||
667 | if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | | 816 | msmsdcc_handle_irq_data(host, status, base); |
668 | MCI_CMDTIMEOUT) && host->curr.cmd) { | ||
669 | msmsdcc_do_cmdirq(host, status); | ||
670 | } | ||
671 | 817 | ||
672 | if (status & MCI_SDIOINTOPER) { | 818 | if (status & MCI_SDIOINTOPER) { |
673 | cardint = 1; | 819 | cardint = 1; |
@@ -714,24 +860,27 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
714 | return; | 860 | return; |
715 | } | 861 | } |
716 | 862 | ||
863 | msmsdcc_enable_clocks(host); | ||
864 | |||
717 | host->curr.mrq = mrq; | 865 | host->curr.mrq = mrq; |
718 | 866 | ||
719 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) | 867 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) |
720 | msmsdcc_start_data(host, mrq->data); | 868 | /* Queue/read data, daisy-chain command when data starts */ |
721 | 869 | msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); | |
722 | msmsdcc_start_command(host, mrq->cmd, 0); | 870 | else |
871 | msmsdcc_start_command(host, mrq->cmd, 0); | ||
723 | 872 | ||
724 | if (host->cmdpoll && !msmsdcc_spin_on_status(host, | 873 | if (host->cmdpoll && !msmsdcc_spin_on_status(host, |
725 | MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, | 874 | MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, |
726 | CMD_SPINMAX)) { | 875 | CMD_SPINMAX)) { |
727 | uint32_t status = readl(host->base + MMCISTATUS); | 876 | uint32_t status = msmsdcc_readl(host, MMCISTATUS); |
728 | msmsdcc_do_cmdirq(host, status); | 877 | msmsdcc_do_cmdirq(host, status); |
729 | writel(MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, | 878 | msmsdcc_writel(host, |
730 | host->base + MMCICLEAR); | 879 | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, |
880 | MMCICLEAR); | ||
731 | host->stats.cmdpoll_hits++; | 881 | host->stats.cmdpoll_hits++; |
732 | } else { | 882 | } else { |
733 | host->stats.cmdpoll_misses++; | 883 | host->stats.cmdpoll_misses++; |
734 | mod_timer(&host->command_timer, jiffies + HZ); | ||
735 | } | 884 | } |
736 | spin_unlock_irqrestore(&host->lock, flags); | 885 | spin_unlock_irqrestore(&host->lock, flags); |
737 | } | 886 | } |
@@ -742,14 +891,13 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
742 | struct msmsdcc_host *host = mmc_priv(mmc); | 891 | struct msmsdcc_host *host = mmc_priv(mmc); |
743 | u32 clk = 0, pwr = 0; | 892 | u32 clk = 0, pwr = 0; |
744 | int rc; | 893 | int rc; |
894 | unsigned long flags; | ||
745 | 895 | ||
746 | if (ios->clock) { | 896 | spin_lock_irqsave(&host->lock, flags); |
747 | 897 | ||
748 | if (!host->clks_on) { | 898 | msmsdcc_enable_clocks(host); |
749 | clk_enable(host->pclk); | 899 | |
750 | clk_enable(host->clk); | 900 | if (ios->clock) { |
751 | host->clks_on = 1; | ||
752 | } | ||
753 | if (ios->clock != host->clk_rate) { | 901 | if (ios->clock != host->clk_rate) { |
754 | rc = clk_set_rate(host->clk, ios->clock); | 902 | rc = clk_set_rate(host->clk, ios->clock); |
755 | if (rc < 0) | 903 | if (rc < 0) |
@@ -787,18 +935,16 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
787 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) | 935 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) |
788 | pwr |= MCI_OD; | 936 | pwr |= MCI_OD; |
789 | 937 | ||
790 | writel(clk, host->base + MMCICLOCK); | 938 | msmsdcc_writel(host, clk, MMCICLOCK); |
791 | 939 | ||
792 | if (host->pwr != pwr) { | 940 | if (host->pwr != pwr) { |
793 | host->pwr = pwr; | 941 | host->pwr = pwr; |
794 | writel(pwr, host->base + MMCIPOWER); | 942 | msmsdcc_writel(host, pwr, MMCIPOWER); |
795 | } | ||
796 | |||
797 | if (!(clk & MCI_CLK_ENABLE) && host->clks_on) { | ||
798 | clk_disable(host->clk); | ||
799 | clk_disable(host->pclk); | ||
800 | host->clks_on = 0; | ||
801 | } | 943 | } |
944 | #if BUSCLK_PWRSAVE | ||
945 | msmsdcc_disable_clocks(host, 1); | ||
946 | #endif | ||
947 | spin_unlock_irqrestore(&host->lock, flags); | ||
802 | } | 948 | } |
803 | 949 | ||
804 | static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) | 950 | static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) |
@@ -809,13 +955,13 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) | |||
809 | 955 | ||
810 | spin_lock_irqsave(&host->lock, flags); | 956 | spin_lock_irqsave(&host->lock, flags); |
811 | if (msmsdcc_sdioirq == 1) { | 957 | if (msmsdcc_sdioirq == 1) { |
812 | status = readl(host->base + MMCIMASK0); | 958 | status = msmsdcc_readl(host, MMCIMASK0); |
813 | if (enable) | 959 | if (enable) |
814 | status |= MCI_SDIOINTOPERMASK; | 960 | status |= MCI_SDIOINTOPERMASK; |
815 | else | 961 | else |
816 | status &= ~MCI_SDIOINTOPERMASK; | 962 | status &= ~MCI_SDIOINTOPERMASK; |
817 | host->saved_irq0mask = status; | 963 | host->saved_irq0mask = status; |
818 | writel(status, host->base + MMCIMASK0); | 964 | msmsdcc_writel(host, status, MMCIMASK0); |
819 | } | 965 | } |
820 | spin_unlock_irqrestore(&host->lock, flags); | 966 | spin_unlock_irqrestore(&host->lock, flags); |
821 | } | 967 | } |
@@ -875,42 +1021,13 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) | |||
875 | msmsdcc_check_status((unsigned long) host); | 1021 | msmsdcc_check_status((unsigned long) host); |
876 | } | 1022 | } |
877 | 1023 | ||
878 | /* | ||
879 | * called when a command expires. | ||
880 | * Dump some debugging, and then error | ||
881 | * out the transaction. | ||
882 | */ | ||
883 | static void | 1024 | static void |
884 | msmsdcc_command_expired(unsigned long _data) | 1025 | msmsdcc_busclk_expired(unsigned long _data) |
885 | { | 1026 | { |
886 | struct msmsdcc_host *host = (struct msmsdcc_host *) _data; | 1027 | struct msmsdcc_host *host = (struct msmsdcc_host *) _data; |
887 | struct mmc_request *mrq; | ||
888 | unsigned long flags; | ||
889 | |||
890 | spin_lock_irqsave(&host->lock, flags); | ||
891 | mrq = host->curr.mrq; | ||
892 | |||
893 | if (!mrq) { | ||
894 | pr_info("%s: Command expiry misfire\n", | ||
895 | mmc_hostname(host->mmc)); | ||
896 | spin_unlock_irqrestore(&host->lock, flags); | ||
897 | return; | ||
898 | } | ||
899 | |||
900 | pr_err("%s: Command timeout (%p %p %p %p)\n", | ||
901 | mmc_hostname(host->mmc), mrq, mrq->cmd, | ||
902 | mrq->data, host->dma.sg); | ||
903 | |||
904 | mrq->cmd->error = -ETIMEDOUT; | ||
905 | msmsdcc_stop_data(host); | ||
906 | 1028 | ||
907 | writel(0, host->base + MMCICOMMAND); | 1029 | if (host->clks_on) |
908 | 1030 | msmsdcc_disable_clocks(host, 0); | |
909 | host->curr.mrq = NULL; | ||
910 | host->curr.cmd = NULL; | ||
911 | |||
912 | spin_unlock_irqrestore(&host->lock, flags); | ||
913 | mmc_request_done(host->mmc, mrq); | ||
914 | } | 1031 | } |
915 | 1032 | ||
916 | static int | 1033 | static int |
@@ -1012,6 +1129,7 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1012 | host->pdev_id = pdev->id; | 1129 | host->pdev_id = pdev->id; |
1013 | host->plat = plat; | 1130 | host->plat = plat; |
1014 | host->mmc = mmc; | 1131 | host->mmc = mmc; |
1132 | host->curr.cmd = NULL; | ||
1015 | 1133 | ||
1016 | host->cmdpoll = 1; | 1134 | host->cmdpoll = 1; |
1017 | 1135 | ||
@@ -1027,36 +1145,35 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1027 | host->dmares = dmares; | 1145 | host->dmares = dmares; |
1028 | spin_lock_init(&host->lock); | 1146 | spin_lock_init(&host->lock); |
1029 | 1147 | ||
1148 | #ifdef CONFIG_MMC_EMBEDDED_SDIO | ||
1149 | if (plat->embedded_sdio) | ||
1150 | mmc_set_embedded_sdio_data(mmc, | ||
1151 | &plat->embedded_sdio->cis, | ||
1152 | &plat->embedded_sdio->cccr, | ||
1153 | plat->embedded_sdio->funcs, | ||
1154 | plat->embedded_sdio->num_funcs); | ||
1155 | #endif | ||
1156 | |||
1030 | /* | 1157 | /* |
1031 | * Setup DMA | 1158 | * Setup DMA |
1032 | */ | 1159 | */ |
1033 | msmsdcc_init_dma(host); | 1160 | msmsdcc_init_dma(host); |
1034 | 1161 | ||
1035 | /* | 1162 | /* Get our clocks */ |
1036 | * Setup main peripheral bus clock | ||
1037 | */ | ||
1038 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); | 1163 | host->pclk = clk_get(&pdev->dev, "sdc_pclk"); |
1039 | if (IS_ERR(host->pclk)) { | 1164 | if (IS_ERR(host->pclk)) { |
1040 | ret = PTR_ERR(host->pclk); | 1165 | ret = PTR_ERR(host->pclk); |
1041 | goto host_free; | 1166 | goto host_free; |
1042 | } | 1167 | } |
1043 | 1168 | ||
1044 | ret = clk_enable(host->pclk); | ||
1045 | if (ret) | ||
1046 | goto pclk_put; | ||
1047 | |||
1048 | host->pclk_rate = clk_get_rate(host->pclk); | ||
1049 | |||
1050 | /* | ||
1051 | * Setup SDC MMC clock | ||
1052 | */ | ||
1053 | host->clk = clk_get(&pdev->dev, "sdc_clk"); | 1169 | host->clk = clk_get(&pdev->dev, "sdc_clk"); |
1054 | if (IS_ERR(host->clk)) { | 1170 | if (IS_ERR(host->clk)) { |
1055 | ret = PTR_ERR(host->clk); | 1171 | ret = PTR_ERR(host->clk); |
1056 | goto pclk_disable; | 1172 | goto pclk_put; |
1057 | } | 1173 | } |
1058 | 1174 | ||
1059 | ret = clk_enable(host->clk); | 1175 | /* Enable clocks */ |
1176 | ret = msmsdcc_enable_clocks(host); | ||
1060 | if (ret) | 1177 | if (ret) |
1061 | goto clk_put; | 1178 | goto clk_put; |
1062 | 1179 | ||
@@ -1066,10 +1183,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1066 | goto clk_disable; | 1183 | goto clk_disable; |
1067 | } | 1184 | } |
1068 | 1185 | ||
1186 | host->pclk_rate = clk_get_rate(host->pclk); | ||
1069 | host->clk_rate = clk_get_rate(host->clk); | 1187 | host->clk_rate = clk_get_rate(host->clk); |
1070 | 1188 | ||
1071 | host->clks_on = 1; | ||
1072 | |||
1073 | /* | 1189 | /* |
1074 | * Setup MMC host structure | 1190 | * Setup MMC host structure |
1075 | */ | 1191 | */ |
@@ -1092,10 +1208,10 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1092 | mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ | 1208 | mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ |
1093 | mmc->max_seg_size = mmc->max_req_size; | 1209 | mmc->max_seg_size = mmc->max_req_size; |
1094 | 1210 | ||
1095 | writel(0, host->base + MMCIMASK0); | 1211 | msmsdcc_writel(host, 0, MMCIMASK0); |
1096 | writel(0x5e007ff, host->base + MMCICLEAR); /* Add: 1 << 25 */ | 1212 | msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); |
1097 | 1213 | ||
1098 | writel(MCI_IRQENABLE, host->base + MMCIMASK0); | 1214 | msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); |
1099 | host->saved_irq0mask = MCI_IRQENABLE; | 1215 | host->saved_irq0mask = MCI_IRQENABLE; |
1100 | 1216 | ||
1101 | /* | 1217 | /* |
@@ -1137,13 +1253,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1137 | host->eject = !host->oldstat; | 1253 | host->eject = !host->oldstat; |
1138 | } | 1254 | } |
1139 | 1255 | ||
1140 | /* | 1256 | init_timer(&host->busclk_timer); |
1141 | * Setup a command timer. We currently need this due to | 1257 | host->busclk_timer.data = (unsigned long) host; |
1142 | * some 'strange' timeout / error handling situations. | 1258 | host->busclk_timer.function = msmsdcc_busclk_expired; |
1143 | */ | ||
1144 | init_timer(&host->command_timer); | ||
1145 | host->command_timer.data = (unsigned long) host; | ||
1146 | host->command_timer.function = msmsdcc_command_expired; | ||
1147 | 1259 | ||
1148 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, | 1260 | ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, |
1149 | DRIVER_NAME " (cmd)", host); | 1261 | DRIVER_NAME " (cmd)", host); |
@@ -1181,6 +1293,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1181 | if (host->timer.function) | 1293 | if (host->timer.function) |
1182 | pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); | 1294 | pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); |
1183 | 1295 | ||
1296 | #if BUSCLK_PWRSAVE | ||
1297 | msmsdcc_disable_clocks(host, 1); | ||
1298 | #endif | ||
1184 | return 0; | 1299 | return 0; |
1185 | cmd_irq_free: | 1300 | cmd_irq_free: |
1186 | free_irq(cmd_irqres->start, host); | 1301 | free_irq(cmd_irqres->start, host); |
@@ -1188,11 +1303,9 @@ msmsdcc_probe(struct platform_device *pdev) | |||
1188 | if (host->stat_irq) | 1303 | if (host->stat_irq) |
1189 | free_irq(host->stat_irq, host); | 1304 | free_irq(host->stat_irq, host); |
1190 | clk_disable: | 1305 | clk_disable: |
1191 | clk_disable(host->clk); | 1306 | msmsdcc_disable_clocks(host, 0); |
1192 | clk_put: | 1307 | clk_put: |
1193 | clk_put(host->clk); | 1308 | clk_put(host->clk); |
1194 | pclk_disable: | ||
1195 | clk_disable(host->pclk); | ||
1196 | pclk_put: | 1309 | pclk_put: |
1197 | clk_put(host->pclk); | 1310 | clk_put(host->pclk); |
1198 | host_free: | 1311 | host_free: |
@@ -1215,15 +1328,10 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) | |||
1215 | 1328 | ||
1216 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) | 1329 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) |
1217 | rc = mmc_suspend_host(mmc, state); | 1330 | rc = mmc_suspend_host(mmc, state); |
1218 | if (!rc) { | 1331 | if (!rc) |
1219 | writel(0, host->base + MMCIMASK0); | 1332 | msmsdcc_writel(host, 0, MMCIMASK0); |
1220 | 1333 | if (host->clks_on) | |
1221 | if (host->clks_on) { | 1334 | msmsdcc_disable_clocks(host, 0); |
1222 | clk_disable(host->clk); | ||
1223 | clk_disable(host->pclk); | ||
1224 | host->clks_on = 0; | ||
1225 | } | ||
1226 | } | ||
1227 | } | 1335 | } |
1228 | return rc; | 1336 | return rc; |
1229 | } | 1337 | } |
@@ -1232,27 +1340,21 @@ static int | |||
1232 | msmsdcc_resume(struct platform_device *dev) | 1340 | msmsdcc_resume(struct platform_device *dev) |
1233 | { | 1341 | { |
1234 | struct mmc_host *mmc = mmc_get_drvdata(dev); | 1342 | struct mmc_host *mmc = mmc_get_drvdata(dev); |
1235 | unsigned long flags; | ||
1236 | 1343 | ||
1237 | if (mmc) { | 1344 | if (mmc) { |
1238 | struct msmsdcc_host *host = mmc_priv(mmc); | 1345 | struct msmsdcc_host *host = mmc_priv(mmc); |
1239 | 1346 | ||
1240 | spin_lock_irqsave(&host->lock, flags); | 1347 | msmsdcc_enable_clocks(host); |
1241 | 1348 | ||
1242 | if (!host->clks_on) { | 1349 | msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); |
1243 | clk_enable(host->pclk); | ||
1244 | clk_enable(host->clk); | ||
1245 | host->clks_on = 1; | ||
1246 | } | ||
1247 | |||
1248 | writel(host->saved_irq0mask, host->base + MMCIMASK0); | ||
1249 | |||
1250 | spin_unlock_irqrestore(&host->lock, flags); | ||
1251 | 1350 | ||
1252 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) | 1351 | if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) |
1253 | mmc_resume_host(mmc); | 1352 | mmc_resume_host(mmc); |
1254 | if (host->stat_irq) | 1353 | if (host->stat_irq) |
1255 | enable_irq(host->stat_irq); | 1354 | enable_irq(host->stat_irq); |
1355 | #if BUSCLK_PWRSAVE | ||
1356 | msmsdcc_disable_clocks(host, 1); | ||
1357 | #endif | ||
1256 | } | 1358 | } |
1257 | return 0; | 1359 | return 0; |
1258 | } | 1360 | } |
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 8c8448469811..da0039c9285e 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h | |||
@@ -171,6 +171,7 @@ struct msmsdcc_dma_data { | |||
171 | int channel; | 171 | int channel; |
172 | struct msmsdcc_host *host; | 172 | struct msmsdcc_host *host; |
173 | int busy; /* Set if DM is busy */ | 173 | int busy; /* Set if DM is busy */ |
174 | int active; | ||
174 | }; | 175 | }; |
175 | 176 | ||
176 | struct msmsdcc_pio_data { | 177 | struct msmsdcc_pio_data { |
@@ -213,7 +214,7 @@ struct msmsdcc_host { | |||
213 | struct clk *clk; /* main MMC bus clock */ | 214 | struct clk *clk; /* main MMC bus clock */ |
214 | struct clk *pclk; /* SDCC peripheral bus clock */ | 215 | struct clk *pclk; /* SDCC peripheral bus clock */ |
215 | unsigned int clks_on; /* set if clocks are enabled */ | 216 | unsigned int clks_on; /* set if clocks are enabled */ |
216 | struct timer_list command_timer; | 217 | struct timer_list busclk_timer; |
217 | 218 | ||
218 | unsigned int eject; /* eject state */ | 219 | unsigned int eject; /* eject state */ |
219 | 220 | ||
@@ -233,6 +234,18 @@ struct msmsdcc_host { | |||
233 | struct msmsdcc_pio_data pio; | 234 | struct msmsdcc_pio_data pio; |
234 | int cmdpoll; | 235 | int cmdpoll; |
235 | struct msmsdcc_stats stats; | 236 | struct msmsdcc_stats stats; |
237 | |||
238 | #ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ | ||
239 | struct work_struct resume_task; | ||
240 | #endif | ||
241 | |||
242 | /* Command parameters */ | ||
243 | unsigned int cmd_timeout; | ||
244 | unsigned int cmd_pio_irqmask; | ||
245 | unsigned int cmd_datactrl; | ||
246 | struct mmc_command *cmd_cmd; | ||
247 | u32 cmd_c; | ||
248 | |||
236 | }; | 249 | }; |
237 | 250 | ||
238 | #endif | 251 | #endif |
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 0ed48959b590..e4f00e70a749 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
@@ -544,7 +544,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid) | |||
544 | { | 544 | { |
545 | struct pxamci_host *host = mmc_priv(devid); | 545 | struct pxamci_host *host = mmc_priv(devid); |
546 | 546 | ||
547 | mmc_detect_change(devid, host->pdata->detect_delay); | 547 | mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms)); |
548 | return IRQ_HANDLED; | 548 | return IRQ_HANDLED; |
549 | } | 549 | } |
550 | 550 | ||