brcm2708: update to latest version
[openwrt/staging/wigyori.git] / target / linux / brcm2708 / patches-4.4 / 0217-bcm2835-sdhost-Adjust-to-core-clock-changes.patch
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
5
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.
9
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.
14
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.
17
18 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
19 ---
20 drivers/mmc/host/Kconfig | 1 +
21 drivers/mmc/host/bcm2835-sdhost.c | 140 ++++++++++++++++++++++++++++++++------
22 2 files changed, 119 insertions(+), 22 deletions(-)
23
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
31 help
32 This selects the SDHost controller on BCM2835/6.
33
34 --- a/drivers/mmc/host/bcm2835-sdhost.c
35 +++ b/drivers/mmc/host/bcm2835-sdhost.c
36 @@ -50,6 +50,10 @@
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>
43 +
44
45 #define DRIVER_NAME "sdhost-bcm2835"
46
47 @@ -136,6 +140,8 @@
48
49 #define MHZ 1000000
50
51 +#define RPI_FIRMWARE_CLOCK_CORE 4
52 +
53
54 struct bcm2835_host {
55 spinlock_t lock;
56 @@ -151,7 +157,9 @@ struct bcm2835_host {
57
58 bool slow_card; /* Force 11-bit divisor */
59
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 */
64
65 struct tasklet_struct finish_tasklet; /* Tasklet structures */
66
67 @@ -183,6 +191,7 @@ struct bcm2835_host {
68 unsigned int use_sbc:1; /* Send CMD23 */
69
70 unsigned int debug:1; /* Enable debug output */
71 + unsigned int variable_clock:1; /* The core clock may change */
72
73 /*DMA part*/
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) */
77
78 u32 sectors; /* Cached card size in sectors */
79 +
80 + struct notifier_block cpufreq_nb; /* The cpufreq callback list item */
81 + struct semaphore cpufreq_semaphore; /* Interlock between SD activity and cpufreq changes */
82 };
83
84 #if ENABLE_LOG
85 @@ -227,6 +239,10 @@ static u32 sdhost_log_idx;
86 static spinlock_t log_lock;
87 static void __iomem *timer_base;
88
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);
92 +
93 #define LOG_ENTRIES (256*1)
94 #define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
95
96 @@ -448,20 +464,14 @@ static void bcm2835_sdhost_reset(struct
97
98 static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
99
100 -static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft)
101 +static void bcm2835_sdhost_init(struct bcm2835_host *host)
102 {
103 - pr_debug("bcm2835_sdhost_init(%d)\n", soft);
104 + pr_debug("bcm2835_sdhost_init()\n");
105
106 /* Set interrupt enables */
107 host->hcfg = SDHCFG_BUSY_IRPT_EN;
108
109 bcm2835_sdhost_reset_internal(host);
110 -
111 - if (soft) {
112 - /* force clock reconfiguration */
113 - host->clock = 0;
114 - bcm2835_sdhost_set_ios(host->mmc, &host->mmc->ios);
115 - }
116 }
117
118 static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
119 @@ -1499,10 +1509,10 @@ static irqreturn_t bcm2835_sdhost_irq(in
120 return result;
121 }
122
123 -void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
124 +void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
125 {
126 int div = 0; /* Initialized for compiler warning */
127 - unsigned int input_clock = clock;
128 + unsigned int clock = host->clock;
129
130 if (host->debug)
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
133 return;
134 }
135
136 - div = host->max_clk / clock;
137 + div = host->cur_clk / clock;
138 if (div < 2)
139 div = 2;
140 - if ((host->max_clk / div) > clock)
141 + if ((host->cur_clk / div) > clock)
142 div++;
143 div -= 2;
144
145 if (div > SDCDIV_MAX_CDIV)
146 div = SDCDIV_MAX_CDIV;
147
148 - clock = host->max_clk / (div + 2);
149 + clock = host->cur_clk / (div + 2);
150 host->mmc->actual_clock = clock;
151
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);
156
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);
164
165 if (host->debug)
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);
172 }
173
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);
178
179 + if (host->variable_clock &&
180 + (down_killable(&host->cpufreq_semaphore) != 0)) {
181 + mrq->cmd->error = -EINTR;
182 + mmc_request_done(mmc, mrq);
183 + return;
184 + }
185 +
186 spin_lock_irqsave(&host->lock, flags);
187
188 WARN_ON(host->mrq != NULL);
189 @@ -1687,6 +1704,52 @@ static void bcm2835_sdhost_request(struc
190 spin_unlock_irqrestore(&host->lock, flags);
191 }
192
193 +static int bcm2835_sdhost_cpufreq_callback(struct notifier_block *nb,
194 + unsigned long action, void *data)
195 +{
196 + struct cpufreq_freqs *freq = data;
197 + struct bcm2835_host *host;
198 +
199 + host = container_of(nb, struct bcm2835_host, cpufreq_nb);
200 +
201 + if (freq->cpu == 0) {
202 + switch (action) {
203 + case CPUFREQ_PRECHANGE:
204 + if (down_killable(&host->cpufreq_semaphore) != 0)
205 + return NOTIFY_BAD;
206 + break;
207 + case CPUFREQ_POSTCHANGE:
208 + if (freq->new > freq->old)
209 + host->cur_clk = host->max_clk;
210 + else
211 + host->cur_clk = host->min_clk;
212 + bcm2835_sdhost_set_clock(host);
213 + up(&host->cpufreq_semaphore);
214 + break;
215 + default:
216 + break;
217 + }
218 + }
219 + return NOTIFY_OK;
220 +}
221 +
222 +static unsigned int get_core_clock(unsigned int mode)
223 +{
224 + struct rpi_firmware *fw = rpi_firmware_get(NULL);
225 + struct {
226 + u32 id;
227 + u32 val;
228 + } packet;
229 + int ret;
230 +
231 + packet.id = RPI_FIRMWARE_CLOCK_CORE;
232 + ret = rpi_firmware_property(fw, mode, &packet, sizeof(packet));
233 + if (ret)
234 + return 0;
235 +
236 + return packet.val;
237 +}
238 +
239 static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
240 {
241
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);
245
246 + if (ios->clock && !host->cur_clk)
247 + host->cur_clk = get_core_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
248 +
249 spin_lock_irqsave(&host->lock, flags);
250
251 log_event("IOS<", ios->clock, 0);
252
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);
257 }
258
259 /* set bus width */
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;
268 }
269 @@ -1813,6 +1879,9 @@ static void bcm2835_sdhost_tasklet_finis
270
271 spin_unlock_irqrestore(&host->lock, flags);
272
273 + if (host->variable_clock)
274 + up(&host->cpufreq_semaphore);
275 +
276 if (terminate_chan)
277 {
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);
282
283 - bcm2835_sdhost_init(host, 0);
284 + bcm2835_sdhost_init(host);
285
286 ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
287 - mmc_hostname(mmc), host);
288 + mmc_hostname(mmc), host);
289 if (ret) {
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;
295 const __be32 *addr;
296 + unsigned int max_clk;
297 int ret;
298
299 pr_debug("bcm2835_sdhost_probe\n");
300 @@ -2062,6 +2132,28 @@ static int bcm2835_sdhost_probe(struct p
301 if (ret)
302 goto err;
303
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;
311 + }
312 +
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 */
321 + } else {
322 + host->variable_clock = 0;
323 + host->cur_clk = host->max_clk;
324 + }
325 +
326 platform_set_drvdata(pdev, host);
327
328 pr_debug("bcm2835_sdhost_probe -> OK\n");
329 @@ -2081,6 +2173,10 @@ static int bcm2835_sdhost_remove(struct
330
331 pr_debug("bcm2835_sdhost_remove\n");
332
333 + if (host->variable_clock)
334 + cpufreq_unregister_notifier(&host->cpufreq_nb,
335 + CPUFREQ_TRANSITION_NOTIFIER);
336 +
337 mmc_remove_host(host->mmc);
338
339 bcm2835_sdhost_set_power(host, false);