brcm2708: update linux 4.4 patches to latest version
[lede.git] / target / linux / brcm2708 / patches-4.4 / 0222-bcm2835-sdhost-Precalc-divisors-and-overclocks.patch
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
5
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.
9
10 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
11 ---
12  drivers/mmc/host/bcm2835-sdhost.c | 152 ++++++++++++++++++++++----------------
13  1 file changed, 88 insertions(+), 64 deletions(-)
14
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 */
19  
20         int                     clock;          /* Current clock speed */
21 +       int                     clocks[2];
22  
23         bool                    slow_card;      /* Force 11-bit divisor */
24  
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];
32  
33         struct tasklet_struct   finish_tasklet; /* Tasklet structures */
34  
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) */
42  
43         u32                             sectors;        /* Cached card size in sectors */
44 @@ -1509,10 +1512,35 @@ static irqreturn_t bcm2835_sdhost_irq(in
45         return result;
46  }
47  
48 +static void bcm2835_sdhost_select_clock(struct bcm2835_host *host, int idx)
49 +{
50 +       unsigned int clock = host->clocks[idx];
51 +       unsigned int cdiv = host->cdivs[idx];
52 +
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);
56 +
57 +       host->cdiv = cdiv;
58 +       bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
59 +
60 +       /* Set the timeout to 500ms */
61 +       bcm2835_sdhost_write(host, clock/2, SDTOUT);
62 +
63 +       host->cur_clk_idx = host->next_clk_idx = idx;
64 +
65 +       if (host->debug)
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);
70 +}
71 +
72  void bcm2835_sdhost_set_clock(struct bcm2835_host *host)
73  {
74         int div = 0; /* Initialized for compiler warning */
75         unsigned int clock = host->clock;
76 +       int clk_idx;
77  
78         if (host->debug)
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
81             return;
82         }
83  
84 -       div = host->cur_clk / clock;
85 -       if (div < 2)
86 -               div = 2;
87 -       if ((host->cur_clk / div) > clock)
88 -               div++;
89 -       div -= 2;
90 -
91 -       if (div > SDCDIV_MAX_CDIV)
92 -           div = SDCDIV_MAX_CDIV;
93 -
94 -       clock = host->cur_clk / (div + 2);
95 -       host->mmc->actual_clock = clock;
96 -
97 -       /* Calibrate some delays */
98 -
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++)
103 +       {
104 +               unsigned int cur_clk = host->src_clks[clk_idx];
105 +               unsigned int actual_clock;
106  
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);
111 -
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;
117 +               if (div < 2)
118 +                       div = 2;
119 +               if ((cur_clk / div) > clock)
120 +                       div++;
121 +               div -= 2;
122 +
123 +               if (div > SDCDIV_MAX_CDIV)
124 +                       div = SDCDIV_MAX_CDIV;
125 +               actual_clock = cur_clk / (div + 2);
126 +
127 +               host->cdivs[clk_idx] = div;
128 +               host->clocks[clk_idx] = actual_clock;
129 +
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" : "");
142                 }
143         }
144 -       else if (host->overclock)
145 -       {
146 -               host->overclock = 0;
147 -               if (clock == 50 * MHZ)
148 -                       pr_warn("%s: cancelling overclock\n",
149 -                               mmc_hostname(host->mmc));
150 -       }
151  
152 -       host->cdiv = div;
153 -       bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
154 +       if (host->clock == 50*MHZ)
155 +               host->prev_overclock_50 = host->overclock_50;
156  
157 -       /* Set the timeout to 500ms */
158 -       bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
159 -
160 -       if (host->debug)
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);
165  }
166  
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
169  
170         spin_lock_irqsave(&host->lock, flags);
171  
172 +       if (host->next_clk_idx != host->cur_clk_idx)
173 +               bcm2835_sdhost_select_clock(host, host->next_clk_idx);
174 +
175         WARN_ON(host->mrq != NULL);
176         host->mrq = mrq;
177  
178 @@ -1719,11 +1742,7 @@ static int bcm2835_sdhost_cpufreq_callba
179                                 return NOTIFY_BAD;
180                         break;
181                 case CPUFREQ_POSTCHANGE:
182 -                       if (freq->new > freq->old)
183 -                               host->cur_clk = host->max_clk;
184 -                       else
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);
189                         break;
190                 default:
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);
194  
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;
201 +       }
202  
203         spin_lock_irqsave(&host->lock, flags);
204  
205 @@ -1854,11 +1876,12 @@ static void bcm2835_sdhost_tasklet_finis
206  
207         /* Drop the overclock after any data corruption, or after any
208            error overclocked */
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;
216 +
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;
223         const __be32 *addr;
224 -       unsigned int max_clk;
225 +       unsigned int max_clk, min_clk;
226         int ret;
227  
228         pr_debug("bcm2835_sdhost_probe\n");
229 @@ -2128,12 +2151,8 @@ static int bcm2835_sdhost_probe(struct p
230         else
231                 mmc->caps |= MMC_CAP_4_BIT_DATA;
232  
233 -       ret = bcm2835_sdhost_add_host(host);
234 -       if (ret)
235 -               goto err;
236 -
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;
245         }
246  
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 */
259         } else {
260                 host->variable_clock = 0;
261 -               host->cur_clk = host->max_clk;
262         }
263  
264 +       ret = bcm2835_sdhost_add_host(host);
265 +       if (ret)
266 +               goto err;
267 +
268         platform_set_drvdata(pdev, host);
269  
270         pr_debug("bcm2835_sdhost_probe -> OK\n");