brcm2708: update linux 4.4 patches to latest version
[lede.git] / target / linux / brcm2708 / patches-4.4 / 0225-bcm2835-sdhost-Firmware-manages-the-clock-divisor.patch
1 From c249254c1a0195566538a15dbfe2459da2f16643 Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.org>
3 Date: Mon, 4 Apr 2016 16:03:18 +0100
4 Subject: [PATCH 225/304] bcm2835-sdhost: Firmware manages the clock divisor
5
6 The bcm2835-sdhost driver hands control of the CDIV clock divisor
7 register to matching firmware, allowing it to adjust to a changing
8 core clock. This removes the need to use the performance governor or
9 to enable io_is_busy on the on-demand governor in order to get the
10 best SD performance.
11
12 N.B. As SD clocks must be an integer divisor of the core clock, it is
13 possible that the SD clock for "turbo" mode can be different (even
14 lower) than "normal" mode.
15
16 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
17 ---
18  drivers/mmc/host/bcm2835-sdhost.c          | 120 ++++++++++++++++++-----------
19  include/soc/bcm2835/raspberrypi-firmware.h |   1 +
20  2 files changed, 74 insertions(+), 47 deletions(-)
21
22 --- a/drivers/mmc/host/bcm2835-sdhost.c
23 +++ b/drivers/mmc/host/bcm2835-sdhost.c
24 @@ -50,6 +50,7 @@
25  #include <linux/of_dma.h>
26  #include <linux/time.h>
27  #include <linux/workqueue.h>
28 +#include <soc/bcm2835/raspberrypi-firmware.h>
29  
30  #define DRIVER_NAME "sdhost-bcm2835"
31  
32 @@ -183,6 +184,7 @@ struct bcm2835_host {
33         unsigned int                    use_sbc:1;              /* Send CMD23 */
34  
35         unsigned int                    debug:1;                /* Enable debug output */
36 +       unsigned int                    firmware_sets_cdiv:1;   /* Let the firmware manage the clock */
37  
38         /*DMA part*/
39         struct dma_chan                 *dma_chan_rxtx;         /* DMA channel for reads and writes */
40 @@ -430,7 +432,7 @@ static void bcm2835_sdhost_reset_interna
41         host->clock = 0;
42         host->sectors = 0;
43         bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
44 -       bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
45 +       bcm2835_sdhost_write(host, SDCDIV_MAX_CDIV, SDCDIV);
46         mmiowb();
47  }
48  
49 @@ -1534,62 +1536,75 @@ void bcm2835_sdhost_set_clock(struct bcm
50  
51         host->mmc->actual_clock = 0;
52  
53 -       if (clock < 100000) {
54 -           /* Can't stop the clock, but make it as slow as possible
55 -            * to show willing
56 -            */
57 -           host->cdiv = SDCDIV_MAX_CDIV;
58 -           bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
59 -           return;
60 -       }
61 -
62 -       div = host->max_clk / clock;
63 -       if (div < 2)
64 -               div = 2;
65 -       if ((host->max_clk / div) > clock)
66 -               div++;
67 -       div -= 2;
68 +       if (host->firmware_sets_cdiv) {
69 +               u32 msg[3] = { clock, 0, 0 };
70  
71 -       if (div > SDCDIV_MAX_CDIV)
72 -           div = SDCDIV_MAX_CDIV;
73 +               rpi_firmware_property(rpi_firmware_get(NULL),
74 +                                     RPI_FIRMWARE_SET_SDHOST_CLOCK,
75 +                                     &msg, sizeof(msg));
76  
77 -       clock = host->max_clk / (div + 2);
78 -       host->mmc->actual_clock = clock;
79 +               clock = max(msg[1], msg[2]);
80 +       } else {
81 +               if (clock < 100000) {
82 +                       /* Can't stop the clock, but make it as slow as
83 +                        * possible to show willing
84 +                        */
85 +                       host->cdiv = SDCDIV_MAX_CDIV;
86 +                       bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
87 +                       return;
88 +               }
89 +
90 +               div = host->max_clk / clock;
91 +               if (div < 2)
92 +                       div = 2;
93 +               if ((host->max_clk / div) > clock)
94 +                       div++;
95 +               div -= 2;
96 +
97 +               if (div > SDCDIV_MAX_CDIV)
98 +                       div = SDCDIV_MAX_CDIV;
99 +
100 +               clock = host->max_clk / (div + 2);
101 +
102 +               host->cdiv = div;
103 +               bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
104 +
105 +               if (host->debug)
106 +                       pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x "
107 +                               "(actual clock %d)\n",
108 +                               mmc_hostname(host->mmc), input_clock,
109 +                               host->max_clk, host->cdiv,
110 +                               clock);
111 +       }
112  
113         /* Calibrate some delays */
114  
115         host->ns_per_fifo_word = (1000000000/clock) *
116                 ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
117  
118 -       if (clock > input_clock) {
119 -               /* Save the closest value, to make it easier
120 -                  to reduce in the event of error */
121 -               host->overclock_50 = (clock/MHZ);
122 -
123 -               if (clock != host->overclock) {
124 -                       pr_warn("%s: overclocking to %dHz\n",
125 -                               mmc_hostname(host->mmc), clock);
126 -                       host->overclock = clock;
127 +       if (input_clock == 50 * MHZ) {
128 +               if (clock > input_clock) {
129 +                       /* Save the closest value, to make it easier
130 +                          to reduce in the event of error */
131 +                       host->overclock_50 = (clock/MHZ);
132 +
133 +                       if (clock != host->overclock) {
134 +                               pr_warn("%s: overclocking to %dHz\n",
135 +                                       mmc_hostname(host->mmc), clock);
136 +                               host->overclock = clock;
137 +                       }
138 +               } else if (host->overclock) {
139 +                       host->overclock = 0;
140 +                       if (clock == 50 * MHZ)
141 +                               pr_warn("%s: cancelling overclock\n",
142 +                                       mmc_hostname(host->mmc));
143                 }
144         }
145 -       else if (host->overclock)
146 -       {
147 -               host->overclock = 0;
148 -               if (clock == 50 * MHZ)
149 -                       pr_warn("%s: cancelling overclock\n",
150 -                               mmc_hostname(host->mmc));
151 -       }
152 -
153 -       host->cdiv = div;
154 -       bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
155  
156         /* Set the timeout to 500ms */
157 -       bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT);
158 +       bcm2835_sdhost_write(host, clock/2, SDTOUT);
159  
160 -       if (host->debug)
161 -               pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n",
162 -                       mmc_hostname(host->mmc), input_clock,
163 -                       host->max_clk, host->cdiv, host->mmc->actual_clock);
164 +       host->mmc->actual_clock = clock;
165  }
166  
167  static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq)
168 @@ -1704,11 +1719,6 @@ static void bcm2835_sdhost_set_ios(struc
169  
170         log_event("IOS<", ios->clock, 0);
171  
172 -       if (!ios->clock || ios->clock != host->clock) {
173 -               bcm2835_sdhost_set_clock(host, ios->clock);
174 -               host->clock = ios->clock;
175 -       }
176 -
177         /* set bus width */
178         host->hcfg &= ~SDHCFG_WIDE_EXT_BUS;
179         if (ios->bus_width == MMC_BUS_WIDTH_4)
180 @@ -1721,6 +1731,11 @@ static void bcm2835_sdhost_set_ios(struc
181  
182         bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
183  
184 +       if (!ios->clock || ios->clock != host->clock) {
185 +               bcm2835_sdhost_set_clock(host, ios->clock);
186 +               host->clock = ios->clock;
187 +       }
188 +
189         mmiowb();
190  
191         spin_unlock_irqrestore(&host->lock, flags);
192 @@ -1953,6 +1968,7 @@ static int bcm2835_sdhost_probe(struct p
193         struct bcm2835_host *host;
194         struct mmc_host *mmc;
195         const __be32 *addr;
196 +       u32 msg[3];
197         int ret;
198  
199         pr_debug("bcm2835_sdhost_probe\n");
200 @@ -2058,6 +2074,16 @@ static int bcm2835_sdhost_probe(struct p
201         else
202                 mmc->caps |= MMC_CAP_4_BIT_DATA;
203  
204 +       msg[0] = 0;
205 +       msg[1] = ~0;
206 +       msg[2] = ~0;
207 +
208 +       rpi_firmware_property(rpi_firmware_get(NULL),
209 +                             RPI_FIRMWARE_SET_SDHOST_CLOCK,
210 +                             &msg, sizeof(msg));
211 +
212 +       host->firmware_sets_cdiv = (msg[1] != ~0);
213 +
214         ret = bcm2835_sdhost_add_host(host);
215         if (ret)
216                 goto err;
217 --- a/include/soc/bcm2835/raspberrypi-firmware.h
218 +++ b/include/soc/bcm2835/raspberrypi-firmware.h
219 @@ -79,6 +79,7 @@ enum rpi_firmware_property_tag {
220         RPI_FIRMWARE_SET_VOLTAGE =                            0x00038003,
221         RPI_FIRMWARE_SET_TURBO =                              0x00038009,
222         RPI_FIRMWARE_SET_CUSTOMER_OTP =                       0x00038021,
223 +       RPI_FIRMWARE_SET_SDHOST_CLOCK =                       0x00038042,
224  
225         /* Dispmanx TAGS */
226         RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE =                   0x00040001,