aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2014-06-02 05:10:04 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2014-07-09 05:25:57 -0400
commit9c34b73deec147a042c4bd871a373f76af70e38c (patch)
tree2649ee4b956c0d8fedfce41e9a59406909566b07
parent3f4e6f7b9175e2914b82134c4a6a02825f4766db (diff)
mmc: mmci: Add Qcom specific rx_fifocnt logic.
MCIFIFOCNT register behaviour on Qcom chips is very different than the other pl180 integrations. MCIFIFOCNT register contains the number of words that are still waiting to be transferred through the FIFO. It keeps decrementing once the host CPU reads the MCIFIFO. With the existing logic and the MCIFIFOCNT behaviour, mmci_pio_read will loop forever, as the FIFOCNT register will always return transfer size before reading the FIFO. Also the data sheet states that "This register is only useful for debug purposes and should not be used for normal operation since it does not reflect data which may or may not be in the pipeline". This patch implements a qcom specific get_rx_fifocnt function which is implemented based on status register flags. Based on qcom_fifo flag in variant data structure, the corresponding get_rx_fifocnt function is selected. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/host/mmci.c30
-rw-r--r--drivers/mmc/host/mmci.h1
2 files changed, 29 insertions, 2 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 2e6075fdce46..063136d89b42 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -73,6 +73,7 @@ static unsigned int fmax = 515633;
73 * @busy_detect: true if busy detection on dat0 is supported 73 * @busy_detect: true if busy detection on dat0 is supported
74 * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply 74 * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
75 * @explicit_mclk_control: enable explicit mclk control in driver. 75 * @explicit_mclk_control: enable explicit mclk control in driver.
76 * @qcom_fifo: enables qcom specific fifo pio read logic.
76 */ 77 */
77struct variant_data { 78struct variant_data {
78 unsigned int clkreg; 79 unsigned int clkreg;
@@ -95,6 +96,7 @@ struct variant_data {
95 bool busy_detect; 96 bool busy_detect;
96 bool pwrreg_nopower; 97 bool pwrreg_nopower;
97 bool explicit_mclk_control; 98 bool explicit_mclk_control;
99 bool qcom_fifo;
98}; 100};
99 101
100static struct variant_data variant_arm = { 102static struct variant_data variant_arm = {
@@ -992,15 +994,34 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
992 } 994 }
993} 995}
994 996
997static int mmci_get_rx_fifocnt(struct mmci_host *host, u32 status, int remain)
998{
999 return remain - (readl(host->base + MMCIFIFOCNT) << 2);
1000}
1001
1002static int mmci_qcom_get_rx_fifocnt(struct mmci_host *host, u32 status, int r)
1003{
1004 /*
1005 * on qcom SDCC4 only 8 words are used in each burst so only 8 addresses
1006 * from the fifo range should be used
1007 */
1008 if (status & MCI_RXFIFOHALFFULL)
1009 return host->variant->fifohalfsize;
1010 else if (status & MCI_RXDATAAVLBL)
1011 return 4;
1012
1013 return 0;
1014}
1015
995static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) 1016static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
996{ 1017{
997 void __iomem *base = host->base; 1018 void __iomem *base = host->base;
998 char *ptr = buffer; 1019 char *ptr = buffer;
999 u32 status; 1020 u32 status = readl(host->base + MMCISTATUS);
1000 int host_remain = host->size; 1021 int host_remain = host->size;
1001 1022
1002 do { 1023 do {
1003 int count = host_remain - (readl(base + MMCIFIFOCNT) << 2); 1024 int count = host->get_rx_fifocnt(host, status, host_remain);
1004 1025
1005 if (count > remain) 1026 if (count > remain)
1006 count = remain; 1027 count = remain;
@@ -1489,6 +1510,11 @@ static int mmci_probe(struct amba_device *dev,
1489 if (ret) 1510 if (ret)
1490 goto host_free; 1511 goto host_free;
1491 1512
1513 if (variant->qcom_fifo)
1514 host->get_rx_fifocnt = mmci_qcom_get_rx_fifocnt;
1515 else
1516 host->get_rx_fifocnt = mmci_get_rx_fifocnt;
1517
1492 host->plat = plat; 1518 host->plat = plat;
1493 host->variant = variant; 1519 host->variant = variant;
1494 host->mclk = clk_get_rate(host->clk); 1520 host->mclk = clk_get_rate(host->clk);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index ef346170b241..a1f5e4f49e2a 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -229,6 +229,7 @@ struct mmci_host {
229 /* pio stuff */ 229 /* pio stuff */
230 struct sg_mapping_iter sg_miter; 230 struct sg_mapping_iter sg_miter;
231 unsigned int size; 231 unsigned int size;
232 int (*get_rx_fifocnt)(struct mmci_host *h, u32 status, int remain);
232 233
233#ifdef CONFIG_DMA_ENGINE 234#ifdef CONFIG_DMA_ENGINE
234 /* DMA stuff */ 235 /* DMA stuff */