aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2010-12-06 03:24:14 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-12-19 11:01:24 -0500
commitb70a67f938e4a7544ca4dea2856b88f3c47669ff (patch)
tree2ce47d93d20f32215fcac74063947e2d45bf8289 /drivers/mmc
parent34177802001894e064c857cac2759f68119550cd (diff)
ARM: 6526/1: mmci: corrected calculation of clock div for ux500
The Ux500 variant of this block has a different divider. The value used right now is too big and which means a loss in performance. This fix corrects it. Also expand the math comments a bit so it's clear what's happening. Further the Ux500 variant does not like if we use the BYPASS bit, instead we are supposed to set the clock divider to zero. Signed-off-by: Ulf Hansson <ulf.hansson@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/mmci.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 0814b88b44d6..f67fd4f2ab48 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -51,6 +51,7 @@ static unsigned int fmax = 515633;
51 * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when 51 * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when
52 * using DMA. 52 * using DMA.
53 * @sdio: variant supports SDIO 53 * @sdio: variant supports SDIO
54 * @st_clkdiv: true if using a ST-specific clock divider algorithm
54 */ 55 */
55struct variant_data { 56struct variant_data {
56 unsigned int clkreg; 57 unsigned int clkreg;
@@ -61,6 +62,7 @@ struct variant_data {
61 bool broken_blockend; 62 bool broken_blockend;
62 bool broken_blockend_dma; 63 bool broken_blockend_dma;
63 bool sdio; 64 bool sdio;
65 bool st_clkdiv;
64}; 66};
65 67
66static struct variant_data variant_arm = { 68static struct variant_data variant_arm = {
@@ -86,7 +88,9 @@ static struct variant_data variant_ux500 = {
86 .datalength_bits = 24, 88 .datalength_bits = 24,
87 .broken_blockend = true, 89 .broken_blockend = true,
88 .sdio = true, 90 .sdio = true,
91 .st_clkdiv = true,
89}; 92};
93
90/* 94/*
91 * This must be called with host->lock held 95 * This must be called with host->lock held
92 */ 96 */
@@ -97,9 +101,30 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
97 101
98 if (desired) { 102 if (desired) {
99 if (desired >= host->mclk) { 103 if (desired >= host->mclk) {
100 clk = MCI_CLK_BYPASS; 104 /*
105 * The ST clock divider does not like the bypass bit,
106 * even though it's available. Instead the datasheet
107 * recommends setting the divider to zero.
108 */
109 if (!variant->st_clkdiv)
110 clk = MCI_CLK_BYPASS;
101 host->cclk = host->mclk; 111 host->cclk = host->mclk;
112 } else if (variant->st_clkdiv) {
113 /*
114 * DB8500 TRM says f = mclk / (clkdiv + 2)
115 * => clkdiv = (mclk / f) - 2
116 * Round the divider up so we don't exceed the max
117 * frequency
118 */
119 clk = DIV_ROUND_UP(host->mclk, desired) - 2;
120 if (clk >= 256)
121 clk = 255;
122 host->cclk = host->mclk / (clk + 2);
102 } else { 123 } else {
124 /*
125 * PL180 TRM says f = mclk / (2 * (clkdiv + 1))
126 * => clkdiv = mclk / (2 * f) - 1
127 */
103 clk = host->mclk / (2 * desired) - 1; 128 clk = host->mclk / (2 * desired) - 1;
104 if (clk >= 256) 129 if (clk >= 256)
105 clk = 255; 130 clk = 255;