brcm2708: update linux 4.4 patches to latest version
[librecmc/librecmc.git] / target / linux / brcm2708 / patches-4.4 / 0216-bcm2835-sdhost-Adjust-to-core-clock-changes.patch
1 From 13a986c782983be4fcc2c780dd73bfd428cc82b3 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 216/304] 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);