brcm2708: update to latest version
[openwrt/staging/wigyori.git] / target / linux / brcm2708 / patches-4.4 / 0227-bcm2835-sdhost-Firmware-manages-the-clock-divisor.patch
1 From 08532d242d7702ae0add95096aa49c5e96e066e2 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 227/232] 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,