1 From d2b23892c9f7b04b68280889bea7823ba555b325 Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.org>
3 Date: Thu, 31 Mar 2016 15:44:53 +0100
4 Subject: [PATCH 222/304] bcm2835-sdhost: Precalc divisors and overclocks
6 Recalculating the clock divisors when the core clock changes is wasteful
7 and makes it harder to manage the overclock settings. Instead,
8 precalculate them and only report significant changes.
10 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
12 drivers/mmc/host/bcm2835-sdhost.c | 152 ++++++++++++++++++++++----------------
13 1 file changed, 88 insertions(+), 64 deletions(-)
15 --- a/drivers/mmc/host/bcm2835-sdhost.c
16 +++ b/drivers/mmc/host/bcm2835-sdhost.c
17 @@ -154,12 +154,15 @@ struct bcm2835_host {
18 u32 pio_timeout; /* In jiffies */
20 int clock; /* Current clock speed */
23 bool slow_card; /* Force 11-bit divisor */
25 unsigned int max_clk; /* Max src clock freq */
26 - unsigned int min_clk; /* Min src clock freq */
27 - unsigned int cur_clk; /* Current src clock freq */
28 + unsigned int src_clks[2]; /* Min/max src clock freqs */
29 + unsigned int cur_clk_idx; /* Index of current clock */
30 + unsigned int next_clk_idx; /* Next clock index */
31 + unsigned int cdivs[2];
33 struct tasklet_struct finish_tasklet; /* Tasklet structures */
35 @@ -213,7 +216,7 @@ struct bcm2835_host {
36 u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */
37 u32 delay_after_this_stop; /* minimum time between this stop and subsequent data transfer */
38 u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */
39 - u32 overclock; /* Current frequency if overclocked, else zero */
40 + u32 prev_overclock_50;
41 u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
43 u32 sectors; /* Cached card size in sectors */
44 @@ -1509,10 +1512,35 @@ static irqreturn_t bcm2835_sdhost_irq(in
48 +static void bcm2835_sdhost_select_clock(struct bcm2835_host *host, int idx)
50 + unsigned int clock = host->clocks[idx];
51 + unsigned int cdiv = host->cdivs[idx];
53 + host->mmc->actual_clock = clock;
54 + host->ns_per_fifo_word = (1000000000/clock) *
55 + ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
58 + bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
60 + /* Set the timeout to 500ms */
61 + bcm2835_sdhost_write(host, clock/2, SDTOUT);
63 + host->cur_clk_idx = host->next_clk_idx = idx;
66 + pr_info("%s: clock=%d -> src_clk=%d, cdiv=%x (actual %d)\n",
67 + mmc_hostname(host->mmc), host->clock,
68 + host->src_clks[idx], host->cdiv,
69 + host->mmc->actual_clock);
72 void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
74 int div = 0; /* Initialized for compiler warning */
75 unsigned int clock = host->clock;
79 pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
80 @@ -1553,53 +1581,45 @@ void bcm2835_sdhost_set_clock(struct bcm
84 - div = host->cur_clk / clock;
87 - if ((host->cur_clk / div) > clock)
91 - if (div > SDCDIV_MAX_CDIV)
92 - div = SDCDIV_MAX_CDIV;
94 - clock = host->cur_clk / (div + 2);
95 - host->mmc->actual_clock = clock;
97 - /* Calibrate some delays */
99 - host->ns_per_fifo_word = (1000000000/clock) *
100 - ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
101 + /* Calculate the clock divisors */
102 + for (clk_idx = 0; clk_idx <= host->variable_clock; clk_idx++)
104 + unsigned int cur_clk = host->src_clks[clk_idx];
105 + unsigned int actual_clock;
107 - if (clock > host->clock) {
108 - /* Save the closest value, to make it easier
109 - to reduce in the event of error */
110 - host->overclock_50 = (clock/MHZ);
112 - if (clock != host->overclock) {
113 - pr_warn("%s: overclocking to %dHz\n",
114 - mmc_hostname(host->mmc), clock);
115 - host->overclock = clock;
116 + div = cur_clk / clock;
119 + if ((cur_clk / div) > clock)
123 + if (div > SDCDIV_MAX_CDIV)
124 + div = SDCDIV_MAX_CDIV;
125 + actual_clock = cur_clk / (div + 2);
127 + host->cdivs[clk_idx] = div;
128 + host->clocks[clk_idx] = actual_clock;
130 + if (host->overclock_50 != host->prev_overclock_50) {
131 + const char *clk_name = "";
132 + if (host->variable_clock)
133 + clk_name = clk_idx ? " (turbo)" : " (normal)";
134 + if (actual_clock > host->clock)
135 + pr_info("%s: overclocking to %dHz%s\n",
136 + mmc_hostname(host->mmc),
137 + actual_clock, clk_name);
138 + else if ((host->overclock_50 < 50) && (clk_idx == 0))
139 + pr_info("%s: cancelling overclock%s\n",
140 + mmc_hostname(host->mmc),
141 + host->variable_clock ? "s" : "");
144 - else if (host->overclock)
146 - host->overclock = 0;
147 - if (clock == 50 * MHZ)
148 - pr_warn("%s: cancelling overclock\n",
149 - mmc_hostname(host->mmc));
153 - bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
154 + if (host->clock == 50*MHZ)
155 + host->prev_overclock_50 = host->overclock_50;
157 - /* Set the timeout to 500ms */
158 - bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
161 - pr_info("%s: clock=%d -> cur_clk=%d, cdiv=%x (actual clock %d)\n",
162 - mmc_hostname(host->mmc), host->clock,
163 - host->cur_clk, host->cdiv, host->mmc->actual_clock);
164 + bcm2835_sdhost_select_clock(host, host->cur_clk_idx);
167 static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
168 @@ -1657,6 +1677,9 @@ static void bcm2835_sdhost_request(struc
170 spin_lock_irqsave(&host->lock, flags);
172 + if (host->next_clk_idx != host->cur_clk_idx)
173 + bcm2835_sdhost_select_clock(host, host->next_clk_idx);
175 WARN_ON(host->mrq != NULL);
178 @@ -1719,11 +1742,7 @@ static int bcm2835_sdhost_cpufreq_callba
181 case CPUFREQ_POSTCHANGE:
182 - if (freq->new > freq->old)
183 - host->cur_clk = host->max_clk;
185 - host->cur_clk = host->min_clk;
186 - bcm2835_sdhost_set_clock(host);
187 + host->next_clk_idx = (freq->new > freq->old);
188 up(&host->cpufreq_semaphore);
191 @@ -1763,8 +1782,11 @@ static void bcm2835_sdhost_set_ios(struc
192 ios->clock, ios->power_mode, ios->bus_width,
193 ios->timing, ios->signal_voltage, ios->drv_type);
195 - if (ios->clock && !host->cur_clk)
196 - host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
197 + if (ios->clock && (host->cur_clk_idx == -1)) {
198 + unsigned int cur_clk =
199 + get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
200 + host->cur_clk_idx = (cur_clk == host->src_clks[0]) ? 0 : 1;
203 spin_lock_irqsave(&host->lock, flags);
205 @@ -1854,11 +1876,12 @@ static void bcm2835_sdhost_tasklet_finis
207 /* Drop the overclock after any data corruption, or after any
209 - if (host->overclock) {
210 + if (host->clock > 50*MHZ) {
211 if ((mrq->cmd && mrq->cmd->error) ||
212 (mrq->data && mrq->data->error) ||
213 (mrq->stop && mrq->stop->error)) {
214 - host->overclock_50--;
215 + host->overclock_50 = (host->clock/MHZ) - 1;
217 pr_warn("%s: reducing overclock due to errors\n",
218 mmc_hostname(host->mmc));
219 bcm2835_sdhost_set_clock(host);
220 @@ -2022,7 +2045,7 @@ static int bcm2835_sdhost_probe(struct p
221 struct bcm2835_host *host;
222 struct mmc_host *mmc;
224 - unsigned int max_clk;
225 + unsigned int max_clk, min_clk;
228 pr_debug("bcm2835_sdhost_probe\n");
229 @@ -2128,12 +2151,8 @@ static int bcm2835_sdhost_probe(struct p
231 mmc->caps |= MMC_CAP_4_BIT_DATA;
233 - ret = bcm2835_sdhost_add_host(host);
237 /* Query the core clock frequencies */
238 - host->min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
239 + min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
240 max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
241 if (max_clk != host->max_clk) {
242 pr_warn("%s: Expected max clock %d, found %d\n",
243 @@ -2141,19 +2160,24 @@ static int bcm2835_sdhost_probe(struct p
244 host->max_clk = max_clk;
247 - if (host->min_clk != host->max_clk) {
248 + host->src_clks[0] = min_clk;
249 + host->cur_clk_idx = -1;
250 + if (max_clk != min_clk) {
251 + host->src_clks[1] = max_clk;
252 host->cpufreq_nb.notifier_call =
253 bcm2835_sdhost_cpufreq_callback;
254 sema_init(&host->cpufreq_semaphore, 1);
255 cpufreq_register_notifier(&host->cpufreq_nb,
256 CPUFREQ_TRANSITION_NOTIFIER);
257 host->variable_clock = 1;
258 - host->cur_clk = 0; /* Get this later */
260 host->variable_clock = 0;
261 - host->cur_clk = host->max_clk;
264 + ret = bcm2835_sdhost_add_host(host);
268 platform_set_drvdata(pdev, host);
270 pr_debug("bcm2835_sdhost_probe -> OK\n");