1 From 4b89d07fd299a0f4e25321920cb74416ba2e638e Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.org>
3 Date: Wed, 30 Mar 2016 16:33:09 +0100
4 Subject: [PATCH 217/232] bcm2835-sdhost: Adjust to core clock changes
6 The SDHOST block uses the core clock, so previously it has been
7 necessary to prevent the core clock from changing in order to maintain
8 performance and prevent accidental SD bus overclocking.
10 With this patch the sdhost driver is notified of clock changes, allowing
11 it to delay them while an SD access is outstanding and to delay new SD
12 accesses while the clock is changing. This feature is disabled in the
13 case where the core frequency can never change.
15 Now that the driver copes with changes to the core clock, it is safe
16 to disable the io_is_busy feature of the on-demand governor.
18 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
20 drivers/mmc/host/Kconfig | 1 +
21 drivers/mmc/host/bcm2835-sdhost.c | 140 ++++++++++++++++++++++++++++++++------
22 2 files changed, 119 insertions(+), 22 deletions(-)
24 --- a/drivers/mmc/host/Kconfig
25 +++ b/drivers/mmc/host/Kconfig
26 @@ -36,6 +36,7 @@ config MMC_BCM2835_PIO_DMA_BARRIER
27 config MMC_BCM2835_SDHOST
28 tristate "Support for the SDHost controller on BCM2708/9"
29 depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
30 + depends on RASPBERRYPI_FIRMWARE
32 This selects the SDHost controller on BCM2835/6.
34 --- a/drivers/mmc/host/bcm2835-sdhost.c
35 +++ b/drivers/mmc/host/bcm2835-sdhost.c
37 #include <linux/of_dma.h>
38 #include <linux/time.h>
39 #include <linux/workqueue.h>
40 +#include <linux/cpufreq.h>
41 +#include <linux/semaphore.h>
42 +#include <soc/bcm2835/raspberrypi-firmware.h>
45 #define DRIVER_NAME "sdhost-bcm2835"
51 +#define RPI_FIRMWARE_CLOCK_CORE 4
56 @@ -151,7 +157,9 @@ struct bcm2835_host {
58 bool slow_card; /* Force 11-bit divisor */
60 - unsigned int max_clk; /* Max possible freq */
61 + unsigned int max_clk; /* Max src clock freq */
62 + unsigned int min_clk; /* Min src clock freq */
63 + unsigned int cur_clk; /* Current src clock freq */
65 struct tasklet_struct finish_tasklet; /* Tasklet structures */
67 @@ -183,6 +191,7 @@ struct bcm2835_host {
68 unsigned int use_sbc:1; /* Send CMD23 */
70 unsigned int debug:1; /* Enable debug output */
71 + unsigned int variable_clock:1; /* The core clock may change */
74 struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
75 @@ -208,6 +217,9 @@ struct bcm2835_host {
76 u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */
78 u32 sectors; /* Cached card size in sectors */
80 + struct notifier_block cpufreq_nb; /* The cpufreq callback list item */
81 + struct semaphore cpufreq_semaphore; /* Interlock between SD activity and cpufreq changes */
85 @@ -227,6 +239,10 @@ static u32 sdhost_log_idx;
86 static spinlock_t log_lock;
87 static void __iomem *timer_base;
89 +static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
90 + unsigned long action, void *data);
91 +static unsigned int get_core_clock(unsigned int mode);
93 #define LOG_ENTRIES (256*1)
94 #define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
96 @@ -448,20 +464,14 @@ static void bcm2835_sdhost_reset(struct
98 static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
100 -static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft)
101 +static void bcm2835_sdhost_init(struct bcm2835_host *host)
103 - pr_debug("bcm2835_sdhost_init(%d)\n", soft);
104 + pr_debug("bcm2835_sdhost_init()\n");
106 /* Set interrupt enables */
107 host->hcfg = SDHCFG_BUSY_IRPT_EN;
109 bcm2835_sdhost_reset_internal(host);
112 - /* force clock reconfiguration */
114 - bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios);
118 static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
119 @@ -1499,10 +1509,10 @@ static irqreturn_t bcm2835_sdhost_irq(in
123 -void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
124 +void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
126 int div = 0; /* Initialized for compiler warning */
127 - unsigned int input_clock = clock;
128 + unsigned int clock = host->clock;
131 pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
132 @@ -1543,17 +1553,17 @@ void bcm2835_sdhost_set_clock(struct bcm
136 - div = host->max_clk / clock;
137 + div = host->cur_clk / clock;
140 - if ((host->max_clk / div) > clock)
141 + if ((host->cur_clk / div) > clock)
145 if (div > SDCDIV_MAX_CDIV)
146 div = SDCDIV_MAX_CDIV;
148 - clock = host->max_clk / (div + 2);
149 + clock = host->cur_clk / (div + 2);
150 host->mmc->actual_clock = clock;
152 /* Calibrate some delays */
153 @@ -1561,7 +1571,7 @@ void bcm2835_sdhost_set_clock(struct bcm
154 host->ns_per_fifo_word = (1000000000/clock) *
155 ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
157 - if (clock > input_clock) {
158 + if (clock > host->clock) {
159 /* Save the closest value, to make it easier
160 to reduce in the event of error */
161 host->overclock_50 = (clock/MHZ);
162 @@ -1587,9 +1597,9 @@ void bcm2835_sdhost_set_clock(struct bcm
163 bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
166 - pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
167 - mmc_hostname(host->mmc), input_clock,
168 - host->max_clk, host->cdiv, host->mmc->actual_clock);
169 + pr_info("%s: clock=%d -> cur_clk=%d, cdiv=%x (actual clock %d)\n",
170 + mmc_hostname(host->mmc), host->clock,
171 + host->cur_clk, host->cdiv, host->mmc->actual_clock);
174 static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
175 @@ -1638,6 +1648,13 @@ static void bcm2835_sdhost_request(struc
176 (mrq->data->blocks > host->pio_limit))
177 bcm2835_sdhost_prepare_dma(host, mrq->data);
179 + if (host->variable_clock &&
180 + (down_killable(&host->cpufreq_semaphore) != 0)) {
181 + mrq->cmd->error = -EINTR;
182 + mmc_request_done(mmc, mrq);
186 spin_lock_irqsave(&host->lock, flags);
188 WARN_ON(host->mrq != NULL);
189 @@ -1687,6 +1704,52 @@ static void bcm2835_sdhost_request(struc
190 spin_unlock_irqrestore(&host->lock, flags);
193 +static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
194 + unsigned long action, void *data)
196 + struct cpufreq_freqs *freq = data;
197 + struct bcm2835_host *host;
199 + host = container_of(nb, struct bcm2835_host, cpufreq_nb);
201 + if (freq->cpu == 0) {
203 + case CPUFREQ_PRECHANGE:
204 + if (down_killable(&host->cpufreq_semaphore) != 0)
207 + case CPUFREQ_POSTCHANGE:
208 + if (freq->new > freq->old)
209 + host->cur_clk = host->max_clk;
211 + host->cur_clk = host->min_clk;
212 + bcm2835_sdhost_set_clock(host);
213 + up(&host->cpufreq_semaphore);
222 +static unsigned int get_core_clock(unsigned int mode)
224 + struct rpi_firmware *fw = rpi_firmware_get(NULL);
231 + packet.id = RPI_FIRMWARE_CLOCK_CORE;
232 + ret = rpi_firmware_property(fw, mode, &packet, sizeof(packet));
239 static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
242 @@ -1700,13 +1763,16 @@ static void bcm2835_sdhost_set_ios(struc
243 ios->clock, ios->power_mode, ios->bus_width,
244 ios->timing, ios->signal_voltage, ios->drv_type);
246 + if (ios->clock && !host->cur_clk)
247 + host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
249 spin_lock_irqsave(&host->lock, flags);
251 log_event("IOS<", ios->clock, 0);
253 if (!ios->clock || ios->clock != host->clock) {
254 - bcm2835_sdhost_set_clock(host, ios->clock);
255 host->clock = ios->clock;
256 + bcm2835_sdhost_set_clock(host);
260 @@ -1795,7 +1861,7 @@ static void bcm2835_sdhost_tasklet_finis
261 host->overclock_50--;
262 pr_warn("%s: reducing overclock due to errors\n",
263 mmc_hostname(host->mmc));
264 - bcm2835_sdhost_set_clock(host,50*MHZ);
265 + bcm2835_sdhost_set_clock(host);
266 mrq->cmd->error = -EILSEQ;
267 mrq->cmd->retries = 1;
269 @@ -1813,6 +1879,9 @@ static void bcm2835_sdhost_tasklet_finis
271 spin_unlock_irqrestore(&host->lock, flags);
273 + if (host->variable_clock)
274 + up(&host->cpufreq_semaphore);
278 int err = dmaengine_terminate_all(terminate_chan);
279 @@ -1915,10 +1984,10 @@ int bcm2835_sdhost_add_host(struct bcm28
280 setup_timer(&host->timer, bcm2835_sdhost_timeout,
281 (unsigned long)host);
283 - bcm2835_sdhost_init(host, 0);
284 + bcm2835_sdhost_init(host);
286 ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
287 - mmc_hostname(mmc), host);
288 + mmc_hostname(mmc), host);
290 pr_err("%s: failed to request IRQ %d: %d\n",
291 mmc_hostname(mmc), host->irq, ret);
292 @@ -1953,6 +2022,7 @@ static int bcm2835_sdhost_probe(struct p
293 struct bcm2835_host *host;
294 struct mmc_host *mmc;
296 + unsigned int max_clk;
299 pr_debug("bcm2835_sdhost_probe\n");
300 @@ -2062,6 +2132,28 @@ static int bcm2835_sdhost_probe(struct p
304 + /* Query the core clock frequencies */
305 + host->min_clk = get_core_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
306 + max_clk = get_core_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
307 + if (max_clk != host->max_clk) {
308 + pr_warn("%s: Expected max clock %d, found %d\n",
309 + mmc_hostname(mmc), host->max_clk, max_clk);
310 + host->max_clk = max_clk;
313 + if (host->min_clk != host->max_clk) {
314 + host->cpufreq_nb.notifier_call =
315 + bcm2835_sdhost_cpufreq_callback;
316 + sema_init(&host->cpufreq_semaphore, 1);
317 + cpufreq_register_notifier(&host->cpufreq_nb,
318 + CPUFREQ_TRANSITION_NOTIFIER);
319 + host->variable_clock = 1;
320 + host->cur_clk = 0; /* Get this later */
322 + host->variable_clock = 0;
323 + host->cur_clk = host->max_clk;
326 platform_set_drvdata(pdev, host);
328 pr_debug("bcm2835_sdhost_probe -> OK\n");
329 @@ -2081,6 +2173,10 @@ static int bcm2835_sdhost_remove(struct
331 pr_debug("bcm2835_sdhost_remove\n");
333 + if (host->variable_clock)
334 + cpufreq_unregister_notifier(&host->cpufreq_nb,
335 + CPUFREQ_TRANSITION_NOTIFIER);
337 mmc_remove_host(host->mmc);
339 bcm2835_sdhost_set_power(host, false);