OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From e567a7eb59832a76c36cf531967a56d3ff906584 Mon Sep 17 00:00:00 2001 |
2 | From: gellert <gellert@raspberrypi.org> |
||
3 | Date: Fri, 15 Aug 2014 16:35:06 +0100 |
||
4 | Subject: [PATCH 040/454] MMC: added alternative MMC driver |
||
5 | MIME-Version: 1.0 |
||
6 | Content-Type: text/plain; charset=UTF-8 |
||
7 | Content-Transfer-Encoding: 8bit |
||
8 | |||
9 | mmc: Disable CMD23 transfers on all cards |
||
10 | |||
11 | Pending wire-level investigation of these types of transfers |
||
12 | and associated errors on bcm2835-mmc, disable for now. Fallback of |
||
13 | CMD18/CMD25 transfers will be used automatically by the MMC layer. |
||
14 | |||
15 | Reported/Tested-by: Gellert Weisz <gellert@raspberrypi.org> |
||
16 | |||
17 | mmc: bcm2835-mmc: enable DT support for all architectures |
||
18 | |||
19 | Both ARCH_BCM2835 and ARCH_BCM270x are built with OF now. |
||
20 | Enable Device Tree support for all architectures. |
||
21 | |||
22 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
23 | |||
24 | mmc: bcm2835-mmc: fix probe error handling |
||
25 | |||
26 | Probe error handling is broken in several places. |
||
27 | Simplify error handling by using device managed functions. |
||
28 | Replace pr_{err,info} with dev_{err,info}. |
||
29 | |||
30 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
31 | |||
32 | bcm2835-mmc: Add locks when accessing sdhost registers |
||
33 | |||
34 | bcm2835-mmc: Add range of debug options for slowing things down |
||
35 | |||
36 | bcm2835-mmc: Add option to disable some delays |
||
37 | |||
38 | bcm2835-mmc: Add option to disable MMC_QUIRK_BLK_NO_CMD23 |
||
39 | |||
40 | bcm2835-mmc: Default to disabling MMC_QUIRK_BLK_NO_CMD23 |
||
41 | |||
42 | bcm2835-mmc: Adding overclocking option |
||
43 | |||
44 | Allow a different clock speed to be substitued for a requested 50MHz. |
||
45 | This option is exposed using the "overclock_50" DT parameter. |
||
46 | Note that the mmc interface is restricted to EVEN integer divisions of |
||
47 | 250MHz, and the highest sensible option is 63 (250/4 = 62.5), the |
||
48 | next being 125 (250/2) which is much too high. |
||
49 | |||
50 | Use at your own risk. |
||
51 | |||
52 | bcm2835-mmc: Round up the overclock, so 62 works for 62.5Mhz |
||
53 | |||
54 | Also only warn once for each overclock setting. |
||
55 | |||
56 | mmc: bcm2835-mmc: Make available on ARCH_BCM2835 |
||
57 | |||
58 | Make the bcm2835-mmc driver available for use on ARCH_BCM2835. |
||
59 | |||
60 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
61 | |||
62 | BCM270x_DT: add bcm2835-mmc entry |
||
63 | |||
64 | Add Device Tree entry for bcm2835-mmc. |
||
65 | In non-DT mode, don't add the device in the board file. |
||
66 | |||
67 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
68 | |||
69 | bcm2835-mmc: Don't overwrite MMC capabilities from DT |
||
70 | |||
71 | bcm2835-mmc: Don't override bus width capabilities from devicetree |
||
72 | |||
73 | Take out the force setting of the MMC_CAP_4_BIT_DATA host capability |
||
74 | so that the result read from devicetree via mmc_of_parse() is |
||
75 | preserved. |
||
76 | |||
77 | bcm2835-mmc: Only claim one DMA channel |
||
78 | |||
79 | With both MMC controllers enabled there are few DMA channels left. The |
||
80 | bcm2835-mmc driver only uses DMA in one direction at a time, so it |
||
81 | doesn't need to claim two channels. |
||
82 | |||
83 | See: https://github.com/raspberrypi/linux/issues/1327 |
||
84 | |||
85 | Signed-off-by: Phil Elwell <phil@raspberrypi.org> |
||
86 | --- |
||
87 | drivers/mmc/core/block.c | 28 +- |
||
88 | drivers/mmc/core/core.c | 3 +- |
||
89 | drivers/mmc/core/host.c | 17 +- |
||
90 | drivers/mmc/core/quirks.h | 8 + |
||
91 | drivers/mmc/host/Kconfig | 29 + |
||
92 | drivers/mmc/host/Makefile | 1 + |
||
93 | drivers/mmc/host/bcm2835-mmc.c | 1584 ++++++++++++++++++++++++++++++++ |
||
94 | include/linux/mmc/card.h | 2 + |
||
95 | 8 files changed, 1667 insertions(+), 5 deletions(-) |
||
96 | create mode 100644 drivers/mmc/host/bcm2835-mmc.c |
||
97 | |||
98 | --- a/drivers/mmc/core/block.c |
||
99 | +++ b/drivers/mmc/core/block.c |
||
100 | @@ -131,6 +131,13 @@ static DEFINE_MUTEX(open_lock); |
||
101 | module_param(perdev_minors, int, 0444); |
||
102 | MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); |
||
103 | |||
104 | +/* |
||
105 | + * Allow quirks to be overridden for the current card |
||
106 | + */ |
||
107 | +static char *card_quirks; |
||
108 | +module_param(card_quirks, charp, 0644); |
||
109 | +MODULE_PARM_DESC(card_quirks, "Force the use of the indicated quirks (a bitfield)"); |
||
110 | + |
||
111 | static inline int mmc_blk_part_switch(struct mmc_card *card, |
||
112 | unsigned int part_type); |
||
113 | |||
114 | @@ -2514,6 +2521,7 @@ static int mmc_blk_probe(struct mmc_card |
||
115 | { |
||
116 | struct mmc_blk_data *md, *part_md; |
||
117 | char cap_str[10]; |
||
118 | + char quirk_str[24]; |
||
119 | |||
120 | /* |
||
121 | * Check that the card supports the command class(es) we need. |
||
122 | @@ -2521,7 +2529,16 @@ static int mmc_blk_probe(struct mmc_card |
||
123 | if (!(card->csd.cmdclass & CCC_BLOCK_READ)) |
||
124 | return -ENODEV; |
||
125 | |||
126 | - mmc_fixup_device(card, mmc_blk_fixups); |
||
127 | + if (card_quirks) { |
||
128 | + unsigned long quirks; |
||
129 | + if (kstrtoul(card_quirks, 0, &quirks) == 0) |
||
130 | + card->quirks = (unsigned int)quirks; |
||
131 | + else |
||
132 | + pr_err("mmc_block: Invalid card_quirks parameter '%s'\n", |
||
133 | + card_quirks); |
||
134 | + } |
||
135 | + else |
||
136 | + mmc_fixup_device(card, mmc_blk_fixups); |
||
137 | |||
138 | md = mmc_blk_alloc(card); |
||
139 | if (IS_ERR(md)) |
||
140 | @@ -2529,9 +2546,14 @@ static int mmc_blk_probe(struct mmc_card |
||
141 | |||
142 | string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2, |
||
143 | cap_str, sizeof(cap_str)); |
||
144 | - pr_info("%s: %s %s %s %s\n", |
||
145 | + if (card->quirks) |
||
146 | + snprintf(quirk_str, sizeof(quirk_str), |
||
147 | + " (quirks 0x%08x)", card->quirks); |
||
148 | + else |
||
149 | + quirk_str[0] = '\0'; |
||
150 | + pr_info("%s: %s %s %s%s%s\n", |
||
151 | md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), |
||
152 | - cap_str, md->read_only ? "(ro)" : ""); |
||
153 | + cap_str, md->read_only ? " (ro)" : "", quirk_str); |
||
154 | |||
155 | if (mmc_blk_alloc_parts(card, md)) |
||
156 | goto out; |
||
157 | --- a/drivers/mmc/core/core.c |
||
158 | +++ b/drivers/mmc/core/core.c |
||
159 | @@ -2210,7 +2210,8 @@ EXPORT_SYMBOL(mmc_erase); |
||
160 | int mmc_can_erase(struct mmc_card *card) |
||
161 | { |
||
162 | if ((card->host->caps & MMC_CAP_ERASE) && |
||
163 | - (card->csd.cmdclass & CCC_ERASE) && card->erase_size) |
||
164 | + (card->csd.cmdclass & CCC_ERASE) && card->erase_size && |
||
165 | + !(card->quirks & MMC_QUIRK_ERASE_BROKEN)) |
||
166 | return 1; |
||
167 | return 0; |
||
168 | } |
||
169 | --- a/drivers/mmc/core/host.c |
||
170 | +++ b/drivers/mmc/core/host.c |
||
171 | @@ -350,15 +350,30 @@ struct mmc_host *mmc_alloc_host(int extr |
||
172 | { |
||
173 | int err; |
||
174 | struct mmc_host *host; |
||
175 | + int id; |
||
176 | |||
177 | host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); |
||
178 | if (!host) |
||
179 | return NULL; |
||
180 | |||
181 | + /* If OF aliases exist, start dynamic assignment after highest */ |
||
182 | + id = of_alias_get_highest_id("mmc"); |
||
183 | + id = (id < 0) ? 0 : id + 1; |
||
184 | + |
||
185 | + /* If this devices has OF node, maybe it has an alias */ |
||
186 | + if (dev->of_node) { |
||
187 | + int of_id = of_alias_get_id(dev->of_node, "mmc"); |
||
188 | + |
||
189 | + if (of_id < 0) |
||
190 | + dev_warn(dev, "/aliases ID not available\n"); |
||
191 | + else |
||
192 | + id = of_id; |
||
193 | + } |
||
194 | + |
||
195 | /* scanning will be enabled when we're ready */ |
||
196 | host->rescan_disable = 1; |
||
197 | |||
198 | - err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL); |
||
199 | + err = ida_simple_get(&mmc_host_ida, id, 0, GFP_KERNEL); |
||
200 | if (err < 0) { |
||
201 | kfree(host); |
||
202 | return NULL; |
||
203 | --- a/drivers/mmc/core/quirks.h |
||
204 | +++ b/drivers/mmc/core/quirks.h |
||
205 | @@ -99,6 +99,14 @@ static const struct mmc_fixup mmc_blk_fi |
||
206 | MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, |
||
207 | MMC_QUIRK_TRIM_BROKEN), |
||
208 | |||
209 | + /* |
||
210 | + * On some Kingston SD cards, multiple erases of less than 64 |
||
211 | + * sectors can cause corruption. |
||
212 | + */ |
||
213 | + MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), |
||
214 | + MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), |
||
215 | + MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk, MMC_QUIRK_ERASE_BROKEN), |
||
216 | + |
||
217 | END_FIXUP |
||
218 | }; |
||
219 | |||
220 | --- a/drivers/mmc/host/Kconfig |
||
221 | +++ b/drivers/mmc/host/Kconfig |
||
222 | @@ -4,6 +4,35 @@ |
||
223 | |||
224 | comment "MMC/SD/SDIO Host Controller Drivers" |
||
225 | |||
226 | +config MMC_BCM2835_MMC |
||
227 | + tristate "MMC support on BCM2835" |
||
228 | + depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835 |
||
229 | + help |
||
230 | + This selects the MMC Interface on BCM2835. |
||
231 | + |
||
232 | + If you have a controller with this interface, say Y or M here. |
||
233 | + |
||
234 | + If unsure, say N. |
||
235 | + |
||
236 | +config MMC_BCM2835_DMA |
||
237 | + bool "DMA support on BCM2835 Arasan controller" |
||
238 | + depends on MMC_BCM2835_MMC |
||
239 | + help |
||
240 | + Enable DMA support on the Arasan SDHCI controller in Broadcom 2708 |
||
241 | + based chips. |
||
242 | + |
||
243 | + If unsure, say N. |
||
244 | + |
||
245 | +config MMC_BCM2835_PIO_DMA_BARRIER |
||
246 | + int "Block count limit for PIO transfers" |
||
247 | + depends on MMC_BCM2835_MMC && MMC_BCM2835_DMA |
||
248 | + range 0 256 |
||
249 | + default 2 |
||
250 | + help |
||
251 | + The inclusive limit in bytes under which PIO will be used instead of DMA |
||
252 | + |
||
253 | + If unsure, say 2 here. |
||
254 | + |
||
255 | config MMC_DEBUG |
||
256 | bool "MMC host drivers debugging" |
||
257 | depends on MMC != n |
||
258 | --- a/drivers/mmc/host/Makefile |
||
259 | +++ b/drivers/mmc/host/Makefile |
||
260 | @@ -20,6 +20,7 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c |
||
261 | obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o |
||
262 | obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o |
||
263 | obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o |
||
264 | +obj-$(CONFIG_MMC_BCM2835_MMC) += bcm2835-mmc.o |
||
265 | obj-$(CONFIG_MMC_WBSD) += wbsd.o |
||
266 | obj-$(CONFIG_MMC_AU1X) += au1xmmc.o |
||
267 | obj-$(CONFIG_MMC_MTK) += mtk-sd.o |
||
268 | --- /dev/null |
||
269 | +++ b/drivers/mmc/host/bcm2835-mmc.c |
||
270 | @@ -0,0 +1,1584 @@ |
||
271 | +/* |
||
272 | + * BCM2835 MMC host driver. |
||
273 | + * |
||
274 | + * Author: Gellert Weisz <gellert@raspberrypi.org> |
||
275 | + * Copyright 2014 |
||
276 | + * |
||
277 | + * Based on |
||
278 | + * sdhci-bcm2708.c by Broadcom |
||
279 | + * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko |
||
280 | + * sdhci.c and sdhci-pci.c by Pierre Ossman |
||
281 | + * |
||
282 | + * This program is free software; you can redistribute it and/or modify it |
||
283 | + * under the terms and conditions of the GNU General Public License, |
||
284 | + * version 2, as published by the Free Software Foundation. |
||
285 | + * |
||
286 | + * This program is distributed in the hope it will be useful, but WITHOUT |
||
287 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||
288 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
||
289 | + * more details. |
||
290 | + * |
||
291 | + * You should have received a copy of the GNU General Public License |
||
292 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
293 | + */ |
||
294 | + |
||
295 | +#include <linux/delay.h> |
||
296 | +#include <linux/module.h> |
||
297 | +#include <linux/io.h> |
||
298 | +#include <linux/mmc/mmc.h> |
||
299 | +#include <linux/mmc/host.h> |
||
300 | +#include <linux/mmc/sd.h> |
||
301 | +#include <linux/scatterlist.h> |
||
302 | +#include <linux/of_address.h> |
||
303 | +#include <linux/of_irq.h> |
||
304 | +#include <linux/clk.h> |
||
305 | +#include <linux/platform_device.h> |
||
306 | +#include <linux/err.h> |
||
307 | +#include <linux/blkdev.h> |
||
308 | +#include <linux/dmaengine.h> |
||
309 | +#include <linux/dma-mapping.h> |
||
310 | +#include <linux/of_dma.h> |
||
311 | + |
||
312 | +#include "sdhci.h" |
||
313 | + |
||
314 | + |
||
315 | +#define DRIVER_NAME "mmc-bcm2835" |
||
316 | + |
||
317 | +#define DBG(f, x...) \ |
||
318 | +pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) |
||
319 | + |
||
320 | +#ifndef CONFIG_MMC_BCM2835_DMA |
||
321 | + #define FORCE_PIO |
||
322 | +#endif |
||
323 | + |
||
324 | + |
||
325 | +/* the inclusive limit in bytes under which PIO will be used instead of DMA */ |
||
326 | +#ifdef CONFIG_MMC_BCM2835_PIO_DMA_BARRIER |
||
327 | +#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_PIO_DMA_BARRIER |
||
328 | +#else |
||
329 | +#define PIO_DMA_BARRIER 00 |
||
330 | +#endif |
||
331 | + |
||
332 | +#define MIN_FREQ 400000 |
||
333 | +#define TIMEOUT_VAL 0xE |
||
334 | +#define BCM2835_SDHCI_WRITE_DELAY(f) (((2 * 1000000) / f) + 1) |
||
335 | + |
||
336 | + |
||
337 | +unsigned mmc_debug; |
||
338 | +unsigned mmc_debug2; |
||
339 | + |
||
340 | +struct bcm2835_host { |
||
341 | + spinlock_t lock; |
||
342 | + |
||
343 | + void __iomem *ioaddr; |
||
344 | + u32 bus_addr; |
||
345 | + |
||
346 | + struct mmc_host *mmc; |
||
347 | + |
||
348 | + u32 timeout; |
||
349 | + |
||
350 | + int clock; /* Current clock speed */ |
||
351 | + u8 pwr; /* Current voltage */ |
||
352 | + |
||
353 | + unsigned int max_clk; /* Max possible freq */ |
||
354 | + unsigned int timeout_clk; /* Timeout freq (KHz) */ |
||
355 | + unsigned int clk_mul; /* Clock Muliplier value */ |
||
356 | + |
||
357 | + struct tasklet_struct finish_tasklet; /* Tasklet structures */ |
||
358 | + |
||
359 | + struct timer_list timer; /* Timer for timeouts */ |
||
360 | + |
||
361 | + struct sg_mapping_iter sg_miter; /* SG state for PIO */ |
||
362 | + unsigned int blocks; /* remaining PIO blocks */ |
||
363 | + |
||
364 | + int irq; /* Device IRQ */ |
||
365 | + |
||
366 | + |
||
367 | + u32 ier; /* cached registers */ |
||
368 | + |
||
369 | + struct mmc_request *mrq; /* Current request */ |
||
370 | + struct mmc_command *cmd; /* Current command */ |
||
371 | + struct mmc_data *data; /* Current data request */ |
||
372 | + unsigned int data_early:1; /* Data finished before cmd */ |
||
373 | + |
||
374 | + wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ |
||
375 | + |
||
376 | + u32 thread_isr; |
||
377 | + |
||
378 | + u32 shadow; |
||
379 | + |
||
380 | + /*DMA part*/ |
||
381 | + struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */ |
||
382 | + struct dma_slave_config dma_cfg_rx; |
||
383 | + struct dma_slave_config dma_cfg_tx; |
||
384 | + struct dma_async_tx_descriptor *tx_desc; /* descriptor */ |
||
385 | + |
||
386 | + bool have_dma; |
||
387 | + bool use_dma; |
||
388 | + bool wait_for_dma; |
||
389 | + /*end of DMA part*/ |
||
390 | + |
||
391 | + int max_delay; /* maximum length of time spent waiting */ |
||
392 | + |
||
393 | + int flags; /* Host attributes */ |
||
394 | +#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ |
||
395 | +#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ |
||
396 | +#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ |
||
397 | +#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ |
||
398 | +#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ |
||
399 | + |
||
400 | + u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */ |
||
401 | + u32 max_overclock; /* Highest reported */ |
||
402 | +}; |
||
403 | + |
||
404 | + |
||
405 | +static inline void bcm2835_mmc_writel(struct bcm2835_host *host, u32 val, int reg, int from) |
||
406 | +{ |
||
407 | + unsigned delay; |
||
408 | + lockdep_assert_held_once(&host->lock); |
||
409 | + writel(val, host->ioaddr + reg); |
||
410 | + udelay(BCM2835_SDHCI_WRITE_DELAY(max(host->clock, MIN_FREQ))); |
||
411 | + |
||
412 | + delay = ((mmc_debug >> 16) & 0xf) << ((mmc_debug >> 20) & 0xf); |
||
413 | + if (delay && !((1<<from) & mmc_debug2)) |
||
414 | + udelay(delay); |
||
415 | +} |
||
416 | + |
||
417 | +static inline void mmc_raw_writel(struct bcm2835_host *host, u32 val, int reg) |
||
418 | +{ |
||
419 | + unsigned delay; |
||
420 | + lockdep_assert_held_once(&host->lock); |
||
421 | + writel(val, host->ioaddr + reg); |
||
422 | + |
||
423 | + delay = ((mmc_debug >> 24) & 0xf) << ((mmc_debug >> 28) & 0xf); |
||
424 | + if (delay) |
||
425 | + udelay(delay); |
||
426 | +} |
||
427 | + |
||
428 | +static inline u32 bcm2835_mmc_readl(struct bcm2835_host *host, int reg) |
||
429 | +{ |
||
430 | + lockdep_assert_held_once(&host->lock); |
||
431 | + return readl(host->ioaddr + reg); |
||
432 | +} |
||
433 | + |
||
434 | +static inline void bcm2835_mmc_writew(struct bcm2835_host *host, u16 val, int reg) |
||
435 | +{ |
||
436 | + u32 oldval = (reg == SDHCI_COMMAND) ? host->shadow : |
||
437 | + bcm2835_mmc_readl(host, reg & ~3); |
||
438 | + u32 word_num = (reg >> 1) & 1; |
||
439 | + u32 word_shift = word_num * 16; |
||
440 | + u32 mask = 0xffff << word_shift; |
||
441 | + u32 newval = (oldval & ~mask) | (val << word_shift); |
||
442 | + |
||
443 | + if (reg == SDHCI_TRANSFER_MODE) |
||
444 | + host->shadow = newval; |
||
445 | + else |
||
446 | + bcm2835_mmc_writel(host, newval, reg & ~3, 0); |
||
447 | + |
||
448 | +} |
||
449 | + |
||
450 | +static inline void bcm2835_mmc_writeb(struct bcm2835_host *host, u8 val, int reg) |
||
451 | +{ |
||
452 | + u32 oldval = bcm2835_mmc_readl(host, reg & ~3); |
||
453 | + u32 byte_num = reg & 3; |
||
454 | + u32 byte_shift = byte_num * 8; |
||
455 | + u32 mask = 0xff << byte_shift; |
||
456 | + u32 newval = (oldval & ~mask) | (val << byte_shift); |
||
457 | + |
||
458 | + bcm2835_mmc_writel(host, newval, reg & ~3, 1); |
||
459 | +} |
||
460 | + |
||
461 | + |
||
462 | +static inline u16 bcm2835_mmc_readw(struct bcm2835_host *host, int reg) |
||
463 | +{ |
||
464 | + u32 val = bcm2835_mmc_readl(host, (reg & ~3)); |
||
465 | + u32 word_num = (reg >> 1) & 1; |
||
466 | + u32 word_shift = word_num * 16; |
||
467 | + u32 word = (val >> word_shift) & 0xffff; |
||
468 | + |
||
469 | + return word; |
||
470 | +} |
||
471 | + |
||
472 | +static inline u8 bcm2835_mmc_readb(struct bcm2835_host *host, int reg) |
||
473 | +{ |
||
474 | + u32 val = bcm2835_mmc_readl(host, (reg & ~3)); |
||
475 | + u32 byte_num = reg & 3; |
||
476 | + u32 byte_shift = byte_num * 8; |
||
477 | + u32 byte = (val >> byte_shift) & 0xff; |
||
478 | + |
||
479 | + return byte; |
||
480 | +} |
||
481 | + |
||
482 | +static void bcm2835_mmc_unsignal_irqs(struct bcm2835_host *host, u32 clear) |
||
483 | +{ |
||
484 | + u32 ier; |
||
485 | + |
||
486 | + ier = bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE); |
||
487 | + ier &= ~clear; |
||
488 | + /* change which requests generate IRQs - makes no difference to |
||
489 | + the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */ |
||
490 | + bcm2835_mmc_writel(host, ier, SDHCI_SIGNAL_ENABLE, 2); |
||
491 | +} |
||
492 | + |
||
493 | + |
||
494 | +static void bcm2835_mmc_dumpregs(struct bcm2835_host *host) |
||
495 | +{ |
||
496 | + pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", |
||
497 | + mmc_hostname(host->mmc)); |
||
498 | + |
||
499 | + pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", |
||
500 | + bcm2835_mmc_readl(host, SDHCI_DMA_ADDRESS), |
||
501 | + bcm2835_mmc_readw(host, SDHCI_HOST_VERSION)); |
||
502 | + pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", |
||
503 | + bcm2835_mmc_readw(host, SDHCI_BLOCK_SIZE), |
||
504 | + bcm2835_mmc_readw(host, SDHCI_BLOCK_COUNT)); |
||
505 | + pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", |
||
506 | + bcm2835_mmc_readl(host, SDHCI_ARGUMENT), |
||
507 | + bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE)); |
||
508 | + pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", |
||
509 | + bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE), |
||
510 | + bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL)); |
||
511 | + pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", |
||
512 | + bcm2835_mmc_readb(host, SDHCI_POWER_CONTROL), |
||
513 | + bcm2835_mmc_readb(host, SDHCI_BLOCK_GAP_CONTROL)); |
||
514 | + pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", |
||
515 | + bcm2835_mmc_readb(host, SDHCI_WAKE_UP_CONTROL), |
||
516 | + bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL)); |
||
517 | + pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", |
||
518 | + bcm2835_mmc_readb(host, SDHCI_TIMEOUT_CONTROL), |
||
519 | + bcm2835_mmc_readl(host, SDHCI_INT_STATUS)); |
||
520 | + pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", |
||
521 | + bcm2835_mmc_readl(host, SDHCI_INT_ENABLE), |
||
522 | + bcm2835_mmc_readl(host, SDHCI_SIGNAL_ENABLE)); |
||
523 | + pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", |
||
524 | + bcm2835_mmc_readw(host, SDHCI_ACMD12_ERR), |
||
525 | + bcm2835_mmc_readw(host, SDHCI_SLOT_INT_STATUS)); |
||
526 | + pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", |
||
527 | + bcm2835_mmc_readl(host, SDHCI_CAPABILITIES), |
||
528 | + bcm2835_mmc_readl(host, SDHCI_CAPABILITIES_1)); |
||
529 | + pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", |
||
530 | + bcm2835_mmc_readw(host, SDHCI_COMMAND), |
||
531 | + bcm2835_mmc_readl(host, SDHCI_MAX_CURRENT)); |
||
532 | + pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", |
||
533 | + bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2)); |
||
534 | + |
||
535 | + pr_debug(DRIVER_NAME ": ===========================================\n"); |
||
536 | +} |
||
537 | + |
||
538 | + |
||
539 | +static void bcm2835_mmc_reset(struct bcm2835_host *host, u8 mask) |
||
540 | +{ |
||
541 | + unsigned long timeout; |
||
542 | + unsigned long flags; |
||
543 | + |
||
544 | + spin_lock_irqsave(&host->lock, flags); |
||
545 | + bcm2835_mmc_writeb(host, mask, SDHCI_SOFTWARE_RESET); |
||
546 | + |
||
547 | + if (mask & SDHCI_RESET_ALL) |
||
548 | + host->clock = 0; |
||
549 | + |
||
550 | + /* Wait max 100 ms */ |
||
551 | + timeout = 100; |
||
552 | + |
||
553 | + /* hw clears the bit when it's done */ |
||
554 | + while (bcm2835_mmc_readb(host, SDHCI_SOFTWARE_RESET) & mask) { |
||
555 | + if (timeout == 0) { |
||
556 | + pr_err("%s: Reset 0x%x never completed.\n", |
||
557 | + mmc_hostname(host->mmc), (int)mask); |
||
558 | + bcm2835_mmc_dumpregs(host); |
||
559 | + return; |
||
560 | + } |
||
561 | + timeout--; |
||
562 | + spin_unlock_irqrestore(&host->lock, flags); |
||
563 | + mdelay(1); |
||
564 | + spin_lock_irqsave(&host->lock, flags); |
||
565 | + } |
||
566 | + |
||
567 | + if (100-timeout > 10 && 100-timeout > host->max_delay) { |
||
568 | + host->max_delay = 100-timeout; |
||
569 | + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); |
||
570 | + } |
||
571 | + spin_unlock_irqrestore(&host->lock, flags); |
||
572 | +} |
||
573 | + |
||
574 | +static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); |
||
575 | + |
||
576 | +static void bcm2835_mmc_init(struct bcm2835_host *host, int soft) |
||
577 | +{ |
||
578 | + unsigned long flags; |
||
579 | + if (soft) |
||
580 | + bcm2835_mmc_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); |
||
581 | + else |
||
582 | + bcm2835_mmc_reset(host, SDHCI_RESET_ALL); |
||
583 | + |
||
584 | + host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | |
||
585 | + SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | |
||
586 | + SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | |
||
587 | + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | |
||
588 | + SDHCI_INT_RESPONSE; |
||
589 | + |
||
590 | + spin_lock_irqsave(&host->lock, flags); |
||
591 | + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 3); |
||
592 | + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 3); |
||
593 | + spin_unlock_irqrestore(&host->lock, flags); |
||
594 | + |
||
595 | + if (soft) { |
||
596 | + /* force clock reconfiguration */ |
||
597 | + host->clock = 0; |
||
598 | + bcm2835_mmc_set_ios(host->mmc, &host->mmc->ios); |
||
599 | + } |
||
600 | +} |
||
601 | + |
||
602 | + |
||
603 | + |
||
604 | +static void bcm2835_mmc_finish_data(struct bcm2835_host *host); |
||
605 | + |
||
606 | +static void bcm2835_mmc_dma_complete(void *param) |
||
607 | +{ |
||
608 | + struct bcm2835_host *host = param; |
||
609 | + struct dma_chan *dma_chan; |
||
610 | + unsigned long flags; |
||
611 | + u32 dir_data; |
||
612 | + |
||
613 | + spin_lock_irqsave(&host->lock, flags); |
||
614 | + |
||
615 | + host->use_dma = false; |
||
616 | + |
||
617 | + if (host->data && !(host->data->flags & MMC_DATA_WRITE)) { |
||
618 | + /* otherwise handled in SDHCI IRQ */ |
||
619 | + dma_chan = host->dma_chan_rxtx; |
||
620 | + dir_data = DMA_FROM_DEVICE; |
||
621 | + |
||
622 | + dma_unmap_sg(dma_chan->device->dev, |
||
623 | + host->data->sg, host->data->sg_len, |
||
624 | + dir_data); |
||
625 | + |
||
626 | + bcm2835_mmc_finish_data(host); |
||
627 | + } else if (host->wait_for_dma) { |
||
628 | + host->wait_for_dma = false; |
||
629 | + tasklet_schedule(&host->finish_tasklet); |
||
630 | + } |
||
631 | + |
||
632 | + spin_unlock_irqrestore(&host->lock, flags); |
||
633 | +} |
||
634 | + |
||
635 | +static void bcm2835_bcm2835_mmc_read_block_pio(struct bcm2835_host *host) |
||
636 | +{ |
||
637 | + unsigned long flags; |
||
638 | + size_t blksize, len, chunk; |
||
639 | + |
||
640 | + u32 uninitialized_var(scratch); |
||
641 | + u8 *buf; |
||
642 | + |
||
643 | + blksize = host->data->blksz; |
||
644 | + chunk = 0; |
||
645 | + |
||
646 | + local_irq_save(flags); |
||
647 | + |
||
648 | + while (blksize) { |
||
649 | + if (!sg_miter_next(&host->sg_miter)) |
||
650 | + BUG(); |
||
651 | + |
||
652 | + len = min(host->sg_miter.length, blksize); |
||
653 | + |
||
654 | + blksize -= len; |
||
655 | + host->sg_miter.consumed = len; |
||
656 | + |
||
657 | + buf = host->sg_miter.addr; |
||
658 | + |
||
659 | + while (len) { |
||
660 | + if (chunk == 0) { |
||
661 | + scratch = bcm2835_mmc_readl(host, SDHCI_BUFFER); |
||
662 | + chunk = 4; |
||
663 | + } |
||
664 | + |
||
665 | + *buf = scratch & 0xFF; |
||
666 | + |
||
667 | + buf++; |
||
668 | + scratch >>= 8; |
||
669 | + chunk--; |
||
670 | + len--; |
||
671 | + } |
||
672 | + } |
||
673 | + |
||
674 | + sg_miter_stop(&host->sg_miter); |
||
675 | + |
||
676 | + local_irq_restore(flags); |
||
677 | +} |
||
678 | + |
||
679 | +static void bcm2835_bcm2835_mmc_write_block_pio(struct bcm2835_host *host) |
||
680 | +{ |
||
681 | + unsigned long flags; |
||
682 | + size_t blksize, len, chunk; |
||
683 | + u32 scratch; |
||
684 | + u8 *buf; |
||
685 | + |
||
686 | + blksize = host->data->blksz; |
||
687 | + chunk = 0; |
||
688 | + chunk = 0; |
||
689 | + scratch = 0; |
||
690 | + |
||
691 | + local_irq_save(flags); |
||
692 | + |
||
693 | + while (blksize) { |
||
694 | + if (!sg_miter_next(&host->sg_miter)) |
||
695 | + BUG(); |
||
696 | + |
||
697 | + len = min(host->sg_miter.length, blksize); |
||
698 | + |
||
699 | + blksize -= len; |
||
700 | + host->sg_miter.consumed = len; |
||
701 | + |
||
702 | + buf = host->sg_miter.addr; |
||
703 | + |
||
704 | + while (len) { |
||
705 | + scratch |= (u32)*buf << (chunk * 8); |
||
706 | + |
||
707 | + buf++; |
||
708 | + chunk++; |
||
709 | + len--; |
||
710 | + |
||
711 | + if ((chunk == 4) || ((len == 0) && (blksize == 0))) { |
||
712 | + mmc_raw_writel(host, scratch, SDHCI_BUFFER); |
||
713 | + chunk = 0; |
||
714 | + scratch = 0; |
||
715 | + } |
||
716 | + } |
||
717 | + } |
||
718 | + |
||
719 | + sg_miter_stop(&host->sg_miter); |
||
720 | + |
||
721 | + local_irq_restore(flags); |
||
722 | +} |
||
723 | + |
||
724 | + |
||
725 | +static void bcm2835_mmc_transfer_pio(struct bcm2835_host *host) |
||
726 | +{ |
||
727 | + u32 mask; |
||
728 | + |
||
729 | + BUG_ON(!host->data); |
||
730 | + |
||
731 | + if (host->blocks == 0) |
||
732 | + return; |
||
733 | + |
||
734 | + if (host->data->flags & MMC_DATA_READ) |
||
735 | + mask = SDHCI_DATA_AVAILABLE; |
||
736 | + else |
||
737 | + mask = SDHCI_SPACE_AVAILABLE; |
||
738 | + |
||
739 | + while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) { |
||
740 | + |
||
741 | + if (host->data->flags & MMC_DATA_READ) |
||
742 | + bcm2835_bcm2835_mmc_read_block_pio(host); |
||
743 | + else |
||
744 | + bcm2835_bcm2835_mmc_write_block_pio(host); |
||
745 | + |
||
746 | + host->blocks--; |
||
747 | + |
||
748 | + /* QUIRK used in sdhci.c removes the 'if' */ |
||
749 | + /* but it seems this is unnecessary */ |
||
750 | + if (host->blocks == 0) |
||
751 | + break; |
||
752 | + |
||
753 | + |
||
754 | + } |
||
755 | +} |
||
756 | + |
||
757 | + |
||
758 | +static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host) |
||
759 | +{ |
||
760 | + u32 len, dir_data, dir_slave; |
||
761 | + struct dma_async_tx_descriptor *desc = NULL; |
||
762 | + struct dma_chan *dma_chan; |
||
763 | + |
||
764 | + |
||
765 | + WARN_ON(!host->data); |
||
766 | + |
||
767 | + if (!host->data) |
||
768 | + return; |
||
769 | + |
||
770 | + if (host->blocks == 0) |
||
771 | + return; |
||
772 | + |
||
773 | + dma_chan = host->dma_chan_rxtx; |
||
774 | + if (host->data->flags & MMC_DATA_READ) { |
||
775 | + dir_data = DMA_FROM_DEVICE; |
||
776 | + dir_slave = DMA_DEV_TO_MEM; |
||
777 | + } else { |
||
778 | + dir_data = DMA_TO_DEVICE; |
||
779 | + dir_slave = DMA_MEM_TO_DEV; |
||
780 | + } |
||
781 | + |
||
782 | + /* The parameters have already been validated, so this will not fail */ |
||
783 | + (void)dmaengine_slave_config(dma_chan, |
||
784 | + (dir_data == DMA_FROM_DEVICE) ? |
||
785 | + &host->dma_cfg_rx : |
||
786 | + &host->dma_cfg_tx); |
||
787 | + |
||
788 | + BUG_ON(!dma_chan->device); |
||
789 | + BUG_ON(!dma_chan->device->dev); |
||
790 | + BUG_ON(!host->data->sg); |
||
791 | + |
||
792 | + len = dma_map_sg(dma_chan->device->dev, host->data->sg, |
||
793 | + host->data->sg_len, dir_data); |
||
794 | + if (len > 0) { |
||
795 | + desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg, |
||
796 | + len, dir_slave, |
||
797 | + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
||
798 | + } else { |
||
799 | + dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); |
||
800 | + } |
||
801 | + if (desc) { |
||
802 | + unsigned long flags; |
||
803 | + spin_lock_irqsave(&host->lock, flags); |
||
804 | + bcm2835_mmc_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL | |
||
805 | + SDHCI_INT_SPACE_AVAIL); |
||
806 | + host->tx_desc = desc; |
||
807 | + desc->callback = bcm2835_mmc_dma_complete; |
||
808 | + desc->callback_param = host; |
||
809 | + spin_unlock_irqrestore(&host->lock, flags); |
||
810 | + dmaengine_submit(desc); |
||
811 | + dma_async_issue_pending(dma_chan); |
||
812 | + } |
||
813 | + |
||
814 | +} |
||
815 | + |
||
816 | + |
||
817 | + |
||
818 | +static void bcm2835_mmc_set_transfer_irqs(struct bcm2835_host *host) |
||
819 | +{ |
||
820 | + u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; |
||
821 | + u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR; |
||
822 | + |
||
823 | + if (host->use_dma) |
||
824 | + host->ier = (host->ier & ~pio_irqs) | dma_irqs; |
||
825 | + else |
||
826 | + host->ier = (host->ier & ~dma_irqs) | pio_irqs; |
||
827 | + |
||
828 | + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 4); |
||
829 | + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 4); |
||
830 | +} |
||
831 | + |
||
832 | + |
||
833 | +static void bcm2835_mmc_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd) |
||
834 | +{ |
||
835 | + u8 count; |
||
836 | + struct mmc_data *data = cmd->data; |
||
837 | + |
||
838 | + WARN_ON(host->data); |
||
839 | + |
||
840 | + if (data || (cmd->flags & MMC_RSP_BUSY)) { |
||
841 | + count = TIMEOUT_VAL; |
||
842 | + bcm2835_mmc_writeb(host, count, SDHCI_TIMEOUT_CONTROL); |
||
843 | + } |
||
844 | + |
||
845 | + if (!data) |
||
846 | + return; |
||
847 | + |
||
848 | + /* Sanity checks */ |
||
849 | + BUG_ON(data->blksz * data->blocks > 524288); |
||
850 | + BUG_ON(data->blksz > host->mmc->max_blk_size); |
||
851 | + BUG_ON(data->blocks > 65535); |
||
852 | + |
||
853 | + host->data = data; |
||
854 | + host->data_early = 0; |
||
855 | + host->data->bytes_xfered = 0; |
||
856 | + |
||
857 | + |
||
858 | + if (!(host->flags & SDHCI_REQ_USE_DMA)) { |
||
859 | + int flags; |
||
860 | + |
||
861 | + flags = SG_MITER_ATOMIC; |
||
862 | + if (host->data->flags & MMC_DATA_READ) |
||
863 | + flags |= SG_MITER_TO_SG; |
||
864 | + else |
||
865 | + flags |= SG_MITER_FROM_SG; |
||
866 | + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); |
||
867 | + host->blocks = data->blocks; |
||
868 | + } |
||
869 | + |
||
870 | + host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER; |
||
871 | + |
||
872 | + bcm2835_mmc_set_transfer_irqs(host); |
||
873 | + |
||
874 | + /* Set the DMA boundary value and block size */ |
||
875 | + bcm2835_mmc_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, |
||
876 | + data->blksz), SDHCI_BLOCK_SIZE); |
||
877 | + bcm2835_mmc_writew(host, data->blocks, SDHCI_BLOCK_COUNT); |
||
878 | + |
||
879 | + BUG_ON(!host->data); |
||
880 | +} |
||
881 | + |
||
882 | +static void bcm2835_mmc_set_transfer_mode(struct bcm2835_host *host, |
||
883 | + struct mmc_command *cmd) |
||
884 | +{ |
||
885 | + u16 mode; |
||
886 | + struct mmc_data *data = cmd->data; |
||
887 | + |
||
888 | + if (data == NULL) { |
||
889 | + /* clear Auto CMD settings for no data CMDs */ |
||
890 | + mode = bcm2835_mmc_readw(host, SDHCI_TRANSFER_MODE); |
||
891 | + bcm2835_mmc_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 | |
||
892 | + SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE); |
||
893 | + return; |
||
894 | + } |
||
895 | + |
||
896 | + WARN_ON(!host->data); |
||
897 | + |
||
898 | + mode = SDHCI_TRNS_BLK_CNT_EN; |
||
899 | + |
||
900 | + if ((mmc_op_multi(cmd->opcode) || data->blocks > 1)) { |
||
901 | + mode |= SDHCI_TRNS_MULTI; |
||
902 | + |
||
903 | + /* |
||
904 | + * If we are sending CMD23, CMD12 never gets sent |
||
905 | + * on successful completion (so no Auto-CMD12). |
||
906 | + */ |
||
907 | + if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) |
||
908 | + mode |= SDHCI_TRNS_AUTO_CMD12; |
||
909 | + else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { |
||
910 | + mode |= SDHCI_TRNS_AUTO_CMD23; |
||
911 | + bcm2835_mmc_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2, 5); |
||
912 | + } |
||
913 | + } |
||
914 | + |
||
915 | + if (data->flags & MMC_DATA_READ) |
||
916 | + mode |= SDHCI_TRNS_READ; |
||
917 | + if (host->flags & SDHCI_REQ_USE_DMA) |
||
918 | + mode |= SDHCI_TRNS_DMA; |
||
919 | + |
||
920 | + bcm2835_mmc_writew(host, mode, SDHCI_TRANSFER_MODE); |
||
921 | +} |
||
922 | + |
||
923 | +void bcm2835_mmc_send_command(struct bcm2835_host *host, struct mmc_command *cmd) |
||
924 | +{ |
||
925 | + int flags; |
||
926 | + u32 mask; |
||
927 | + unsigned long timeout; |
||
928 | + |
||
929 | + WARN_ON(host->cmd); |
||
930 | + |
||
931 | + /* Wait max 10 ms */ |
||
932 | + timeout = 1000; |
||
933 | + |
||
934 | + mask = SDHCI_CMD_INHIBIT; |
||
935 | + if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) |
||
936 | + mask |= SDHCI_DATA_INHIBIT; |
||
937 | + |
||
938 | + /* We shouldn't wait for data inihibit for stop commands, even |
||
939 | + though they might use busy signaling */ |
||
940 | + if (host->mrq->data && (cmd == host->mrq->data->stop)) |
||
941 | + mask &= ~SDHCI_DATA_INHIBIT; |
||
942 | + |
||
943 | + while (bcm2835_mmc_readl(host, SDHCI_PRESENT_STATE) & mask) { |
||
944 | + if (timeout == 0) { |
||
945 | + pr_err("%s: Controller never released inhibit bit(s).\n", |
||
946 | + mmc_hostname(host->mmc)); |
||
947 | + bcm2835_mmc_dumpregs(host); |
||
948 | + cmd->error = -EIO; |
||
949 | + tasklet_schedule(&host->finish_tasklet); |
||
950 | + return; |
||
951 | + } |
||
952 | + timeout--; |
||
953 | + udelay(10); |
||
954 | + } |
||
955 | + |
||
956 | + if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) { |
||
957 | + host->max_delay = (1000-timeout)/100; |
||
958 | + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); |
||
959 | + } |
||
960 | + |
||
961 | + timeout = jiffies; |
||
962 | + if (!cmd->data && cmd->busy_timeout > 9000) |
||
963 | + timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; |
||
964 | + else |
||
965 | + timeout += 10 * HZ; |
||
966 | + mod_timer(&host->timer, timeout); |
||
967 | + |
||
968 | + host->cmd = cmd; |
||
969 | + host->use_dma = false; |
||
970 | + |
||
971 | + bcm2835_mmc_prepare_data(host, cmd); |
||
972 | + |
||
973 | + bcm2835_mmc_writel(host, cmd->arg, SDHCI_ARGUMENT, 6); |
||
974 | + |
||
975 | + bcm2835_mmc_set_transfer_mode(host, cmd); |
||
976 | + |
||
977 | + if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { |
||
978 | + pr_err("%s: Unsupported response type!\n", |
||
979 | + mmc_hostname(host->mmc)); |
||
980 | + cmd->error = -EINVAL; |
||
981 | + tasklet_schedule(&host->finish_tasklet); |
||
982 | + return; |
||
983 | + } |
||
984 | + |
||
985 | + if (!(cmd->flags & MMC_RSP_PRESENT)) |
||
986 | + flags = SDHCI_CMD_RESP_NONE; |
||
987 | + else if (cmd->flags & MMC_RSP_136) |
||
988 | + flags = SDHCI_CMD_RESP_LONG; |
||
989 | + else if (cmd->flags & MMC_RSP_BUSY) |
||
990 | + flags = SDHCI_CMD_RESP_SHORT_BUSY; |
||
991 | + else |
||
992 | + flags = SDHCI_CMD_RESP_SHORT; |
||
993 | + |
||
994 | + if (cmd->flags & MMC_RSP_CRC) |
||
995 | + flags |= SDHCI_CMD_CRC; |
||
996 | + if (cmd->flags & MMC_RSP_OPCODE) |
||
997 | + flags |= SDHCI_CMD_INDEX; |
||
998 | + |
||
999 | + if (cmd->data) |
||
1000 | + flags |= SDHCI_CMD_DATA; |
||
1001 | + |
||
1002 | + bcm2835_mmc_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); |
||
1003 | +} |
||
1004 | + |
||
1005 | + |
||
1006 | +static void bcm2835_mmc_finish_data(struct bcm2835_host *host) |
||
1007 | +{ |
||
1008 | + struct mmc_data *data; |
||
1009 | + |
||
1010 | + BUG_ON(!host->data); |
||
1011 | + |
||
1012 | + data = host->data; |
||
1013 | + host->data = NULL; |
||
1014 | + |
||
1015 | + if (data->error) |
||
1016 | + data->bytes_xfered = 0; |
||
1017 | + else |
||
1018 | + data->bytes_xfered = data->blksz * data->blocks; |
||
1019 | + |
||
1020 | + /* |
||
1021 | + * Need to send CMD12 if - |
||
1022 | + * a) open-ended multiblock transfer (no CMD23) |
||
1023 | + * b) error in multiblock transfer |
||
1024 | + */ |
||
1025 | + if (data->stop && |
||
1026 | + (data->error || |
||
1027 | + !host->mrq->sbc)) { |
||
1028 | + |
||
1029 | + /* |
||
1030 | + * The controller needs a reset of internal state machines |
||
1031 | + * upon error conditions. |
||
1032 | + */ |
||
1033 | + if (data->error) { |
||
1034 | + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); |
||
1035 | + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); |
||
1036 | + } |
||
1037 | + |
||
1038 | + bcm2835_mmc_send_command(host, data->stop); |
||
1039 | + } else if (host->use_dma) { |
||
1040 | + host->wait_for_dma = true; |
||
1041 | + } else { |
||
1042 | + tasklet_schedule(&host->finish_tasklet); |
||
1043 | + } |
||
1044 | +} |
||
1045 | + |
||
1046 | +static void bcm2835_mmc_finish_command(struct bcm2835_host *host) |
||
1047 | +{ |
||
1048 | + int i; |
||
1049 | + |
||
1050 | + BUG_ON(host->cmd == NULL); |
||
1051 | + |
||
1052 | + if (host->cmd->flags & MMC_RSP_PRESENT) { |
||
1053 | + if (host->cmd->flags & MMC_RSP_136) { |
||
1054 | + /* CRC is stripped so we need to do some shifting. */ |
||
1055 | + for (i = 0; i < 4; i++) { |
||
1056 | + host->cmd->resp[i] = bcm2835_mmc_readl(host, |
||
1057 | + SDHCI_RESPONSE + (3-i)*4) << 8; |
||
1058 | + if (i != 3) |
||
1059 | + host->cmd->resp[i] |= |
||
1060 | + bcm2835_mmc_readb(host, |
||
1061 | + SDHCI_RESPONSE + (3-i)*4-1); |
||
1062 | + } |
||
1063 | + } else { |
||
1064 | + host->cmd->resp[0] = bcm2835_mmc_readl(host, SDHCI_RESPONSE); |
||
1065 | + } |
||
1066 | + } |
||
1067 | + |
||
1068 | + host->cmd->error = 0; |
||
1069 | + |
||
1070 | + /* Finished CMD23, now send actual command. */ |
||
1071 | + if (host->cmd == host->mrq->sbc) { |
||
1072 | + host->cmd = NULL; |
||
1073 | + bcm2835_mmc_send_command(host, host->mrq->cmd); |
||
1074 | + |
||
1075 | + if (host->mrq->cmd->data && host->use_dma) { |
||
1076 | + /* DMA transfer starts now, PIO starts after interrupt */ |
||
1077 | + bcm2835_mmc_transfer_dma(host); |
||
1078 | + } |
||
1079 | + } else { |
||
1080 | + |
||
1081 | + /* Processed actual command. */ |
||
1082 | + if (host->data && host->data_early) |
||
1083 | + bcm2835_mmc_finish_data(host); |
||
1084 | + |
||
1085 | + if (!host->cmd->data) |
||
1086 | + tasklet_schedule(&host->finish_tasklet); |
||
1087 | + |
||
1088 | + host->cmd = NULL; |
||
1089 | + } |
||
1090 | +} |
||
1091 | + |
||
1092 | + |
||
1093 | +static void bcm2835_mmc_timeout_timer(unsigned long data) |
||
1094 | +{ |
||
1095 | + struct bcm2835_host *host; |
||
1096 | + unsigned long flags; |
||
1097 | + |
||
1098 | + host = (struct bcm2835_host *)data; |
||
1099 | + |
||
1100 | + spin_lock_irqsave(&host->lock, flags); |
||
1101 | + |
||
1102 | + if (host->mrq) { |
||
1103 | + pr_err("%s: Timeout waiting for hardware interrupt.\n", |
||
1104 | + mmc_hostname(host->mmc)); |
||
1105 | + bcm2835_mmc_dumpregs(host); |
||
1106 | + |
||
1107 | + if (host->data) { |
||
1108 | + host->data->error = -ETIMEDOUT; |
||
1109 | + bcm2835_mmc_finish_data(host); |
||
1110 | + } else { |
||
1111 | + if (host->cmd) |
||
1112 | + host->cmd->error = -ETIMEDOUT; |
||
1113 | + else |
||
1114 | + host->mrq->cmd->error = -ETIMEDOUT; |
||
1115 | + |
||
1116 | + tasklet_schedule(&host->finish_tasklet); |
||
1117 | + } |
||
1118 | + } |
||
1119 | + |
||
1120 | + mmiowb(); |
||
1121 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1122 | +} |
||
1123 | + |
||
1124 | + |
||
1125 | +static void bcm2835_mmc_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable) |
||
1126 | +{ |
||
1127 | + if (!(host->flags & SDHCI_DEVICE_DEAD)) { |
||
1128 | + if (enable) |
||
1129 | + host->ier |= SDHCI_INT_CARD_INT; |
||
1130 | + else |
||
1131 | + host->ier &= ~SDHCI_INT_CARD_INT; |
||
1132 | + |
||
1133 | + bcm2835_mmc_writel(host, host->ier, SDHCI_INT_ENABLE, 7); |
||
1134 | + bcm2835_mmc_writel(host, host->ier, SDHCI_SIGNAL_ENABLE, 7); |
||
1135 | + mmiowb(); |
||
1136 | + } |
||
1137 | +} |
||
1138 | + |
||
1139 | +static void bcm2835_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) |
||
1140 | +{ |
||
1141 | + struct bcm2835_host *host = mmc_priv(mmc); |
||
1142 | + unsigned long flags; |
||
1143 | + |
||
1144 | + spin_lock_irqsave(&host->lock, flags); |
||
1145 | + if (enable) |
||
1146 | + host->flags |= SDHCI_SDIO_IRQ_ENABLED; |
||
1147 | + else |
||
1148 | + host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; |
||
1149 | + |
||
1150 | + bcm2835_mmc_enable_sdio_irq_nolock(host, enable); |
||
1151 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1152 | +} |
||
1153 | + |
||
1154 | +static void bcm2835_mmc_cmd_irq(struct bcm2835_host *host, u32 intmask) |
||
1155 | +{ |
||
1156 | + |
||
1157 | + BUG_ON(intmask == 0); |
||
1158 | + |
||
1159 | + if (!host->cmd) { |
||
1160 | + pr_err("%s: Got command interrupt 0x%08x even " |
||
1161 | + "though no command operation was in progress.\n", |
||
1162 | + mmc_hostname(host->mmc), (unsigned)intmask); |
||
1163 | + bcm2835_mmc_dumpregs(host); |
||
1164 | + return; |
||
1165 | + } |
||
1166 | + |
||
1167 | + if (intmask & SDHCI_INT_TIMEOUT) |
||
1168 | + host->cmd->error = -ETIMEDOUT; |
||
1169 | + else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | |
||
1170 | + SDHCI_INT_INDEX)) { |
||
1171 | + host->cmd->error = -EILSEQ; |
||
1172 | + } |
||
1173 | + |
||
1174 | + if (host->cmd->error) { |
||
1175 | + tasklet_schedule(&host->finish_tasklet); |
||
1176 | + return; |
||
1177 | + } |
||
1178 | + |
||
1179 | + if (intmask & SDHCI_INT_RESPONSE) |
||
1180 | + bcm2835_mmc_finish_command(host); |
||
1181 | + |
||
1182 | +} |
||
1183 | + |
||
1184 | +static void bcm2835_mmc_data_irq(struct bcm2835_host *host, u32 intmask) |
||
1185 | +{ |
||
1186 | + struct dma_chan *dma_chan; |
||
1187 | + u32 dir_data; |
||
1188 | + |
||
1189 | + BUG_ON(intmask == 0); |
||
1190 | + |
||
1191 | + if (!host->data) { |
||
1192 | + /* |
||
1193 | + * The "data complete" interrupt is also used to |
||
1194 | + * indicate that a busy state has ended. See comment |
||
1195 | + * above in sdhci_cmd_irq(). |
||
1196 | + */ |
||
1197 | + if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { |
||
1198 | + if (intmask & SDHCI_INT_DATA_END) { |
||
1199 | + bcm2835_mmc_finish_command(host); |
||
1200 | + return; |
||
1201 | + } |
||
1202 | + } |
||
1203 | + |
||
1204 | + pr_debug("%s: Got data interrupt 0x%08x even " |
||
1205 | + "though no data operation was in progress.\n", |
||
1206 | + mmc_hostname(host->mmc), (unsigned)intmask); |
||
1207 | + bcm2835_mmc_dumpregs(host); |
||
1208 | + |
||
1209 | + return; |
||
1210 | + } |
||
1211 | + |
||
1212 | + if (intmask & SDHCI_INT_DATA_TIMEOUT) |
||
1213 | + host->data->error = -ETIMEDOUT; |
||
1214 | + else if (intmask & SDHCI_INT_DATA_END_BIT) |
||
1215 | + host->data->error = -EILSEQ; |
||
1216 | + else if ((intmask & SDHCI_INT_DATA_CRC) && |
||
1217 | + SDHCI_GET_CMD(bcm2835_mmc_readw(host, SDHCI_COMMAND)) |
||
1218 | + != MMC_BUS_TEST_R) |
||
1219 | + host->data->error = -EILSEQ; |
||
1220 | + |
||
1221 | + if (host->use_dma) { |
||
1222 | + if (host->data->flags & MMC_DATA_WRITE) { |
||
1223 | + /* IRQ handled here */ |
||
1224 | + |
||
1225 | + dma_chan = host->dma_chan_rxtx; |
||
1226 | + dir_data = DMA_TO_DEVICE; |
||
1227 | + dma_unmap_sg(dma_chan->device->dev, |
||
1228 | + host->data->sg, host->data->sg_len, |
||
1229 | + dir_data); |
||
1230 | + |
||
1231 | + bcm2835_mmc_finish_data(host); |
||
1232 | + } |
||
1233 | + |
||
1234 | + } else { |
||
1235 | + if (host->data->error) |
||
1236 | + bcm2835_mmc_finish_data(host); |
||
1237 | + else { |
||
1238 | + if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) |
||
1239 | + bcm2835_mmc_transfer_pio(host); |
||
1240 | + |
||
1241 | + if (intmask & SDHCI_INT_DATA_END) { |
||
1242 | + if (host->cmd) { |
||
1243 | + /* |
||
1244 | + * Data managed to finish before the |
||
1245 | + * command completed. Make sure we do |
||
1246 | + * things in the proper order. |
||
1247 | + */ |
||
1248 | + host->data_early = 1; |
||
1249 | + } else { |
||
1250 | + bcm2835_mmc_finish_data(host); |
||
1251 | + } |
||
1252 | + } |
||
1253 | + } |
||
1254 | + } |
||
1255 | +} |
||
1256 | + |
||
1257 | + |
||
1258 | +static irqreturn_t bcm2835_mmc_irq(int irq, void *dev_id) |
||
1259 | +{ |
||
1260 | + irqreturn_t result = IRQ_NONE; |
||
1261 | + struct bcm2835_host *host = dev_id; |
||
1262 | + u32 intmask, mask, unexpected = 0; |
||
1263 | + int max_loops = 16; |
||
1264 | + |
||
1265 | + spin_lock(&host->lock); |
||
1266 | + |
||
1267 | + intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS); |
||
1268 | + |
||
1269 | + if (!intmask || intmask == 0xffffffff) { |
||
1270 | + result = IRQ_NONE; |
||
1271 | + goto out; |
||
1272 | + } |
||
1273 | + |
||
1274 | + do { |
||
1275 | + /* Clear selected interrupts. */ |
||
1276 | + mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | |
||
1277 | + SDHCI_INT_BUS_POWER); |
||
1278 | + bcm2835_mmc_writel(host, mask, SDHCI_INT_STATUS, 8); |
||
1279 | + |
||
1280 | + |
||
1281 | + if (intmask & SDHCI_INT_CMD_MASK) |
||
1282 | + bcm2835_mmc_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); |
||
1283 | + |
||
1284 | + if (intmask & SDHCI_INT_DATA_MASK) |
||
1285 | + bcm2835_mmc_data_irq(host, intmask & SDHCI_INT_DATA_MASK); |
||
1286 | + |
||
1287 | + if (intmask & SDHCI_INT_BUS_POWER) |
||
1288 | + pr_err("%s: Card is consuming too much power!\n", |
||
1289 | + mmc_hostname(host->mmc)); |
||
1290 | + |
||
1291 | + if (intmask & SDHCI_INT_CARD_INT) { |
||
1292 | + bcm2835_mmc_enable_sdio_irq_nolock(host, false); |
||
1293 | + host->thread_isr |= SDHCI_INT_CARD_INT; |
||
1294 | + result = IRQ_WAKE_THREAD; |
||
1295 | + } |
||
1296 | + |
||
1297 | + intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | |
||
1298 | + SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | |
||
1299 | + SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER | |
||
1300 | + SDHCI_INT_CARD_INT); |
||
1301 | + |
||
1302 | + if (intmask) { |
||
1303 | + unexpected |= intmask; |
||
1304 | + bcm2835_mmc_writel(host, intmask, SDHCI_INT_STATUS, 9); |
||
1305 | + } |
||
1306 | + |
||
1307 | + if (result == IRQ_NONE) |
||
1308 | + result = IRQ_HANDLED; |
||
1309 | + |
||
1310 | + intmask = bcm2835_mmc_readl(host, SDHCI_INT_STATUS); |
||
1311 | + } while (intmask && --max_loops); |
||
1312 | +out: |
||
1313 | + spin_unlock(&host->lock); |
||
1314 | + |
||
1315 | + if (unexpected) { |
||
1316 | + pr_err("%s: Unexpected interrupt 0x%08x.\n", |
||
1317 | + mmc_hostname(host->mmc), unexpected); |
||
1318 | + bcm2835_mmc_dumpregs(host); |
||
1319 | + } |
||
1320 | + |
||
1321 | + return result; |
||
1322 | +} |
||
1323 | + |
||
1324 | +static irqreturn_t bcm2835_mmc_thread_irq(int irq, void *dev_id) |
||
1325 | +{ |
||
1326 | + struct bcm2835_host *host = dev_id; |
||
1327 | + unsigned long flags; |
||
1328 | + u32 isr; |
||
1329 | + |
||
1330 | + spin_lock_irqsave(&host->lock, flags); |
||
1331 | + isr = host->thread_isr; |
||
1332 | + host->thread_isr = 0; |
||
1333 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1334 | + |
||
1335 | + if (isr & SDHCI_INT_CARD_INT) { |
||
1336 | + sdio_run_irqs(host->mmc); |
||
1337 | + |
||
1338 | + spin_lock_irqsave(&host->lock, flags); |
||
1339 | + if (host->flags & SDHCI_SDIO_IRQ_ENABLED) |
||
1340 | + bcm2835_mmc_enable_sdio_irq_nolock(host, true); |
||
1341 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1342 | + } |
||
1343 | + |
||
1344 | + return isr ? IRQ_HANDLED : IRQ_NONE; |
||
1345 | +} |
||
1346 | + |
||
1347 | + |
||
1348 | + |
||
1349 | +void bcm2835_mmc_set_clock(struct bcm2835_host *host, unsigned int clock) |
||
1350 | +{ |
||
1351 | + int div = 0; /* Initialized for compiler warning */ |
||
1352 | + int real_div = div, clk_mul = 1; |
||
1353 | + u16 clk = 0; |
||
1354 | + unsigned long timeout; |
||
1355 | + unsigned int input_clock = clock; |
||
1356 | + |
||
1357 | + if (host->overclock_50 && (clock == 50000000)) |
||
1358 | + clock = host->overclock_50 * 1000000 + 999999; |
||
1359 | + |
||
1360 | + host->mmc->actual_clock = 0; |
||
1361 | + |
||
1362 | + bcm2835_mmc_writew(host, 0, SDHCI_CLOCK_CONTROL); |
||
1363 | + |
||
1364 | + if (clock == 0) |
||
1365 | + return; |
||
1366 | + |
||
1367 | + /* Version 3.00 divisors must be a multiple of 2. */ |
||
1368 | + if (host->max_clk <= clock) |
||
1369 | + div = 1; |
||
1370 | + else { |
||
1371 | + for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; |
||
1372 | + div += 2) { |
||
1373 | + if ((host->max_clk / div) <= clock) |
||
1374 | + break; |
||
1375 | + } |
||
1376 | + } |
||
1377 | + |
||
1378 | + real_div = div; |
||
1379 | + div >>= 1; |
||
1380 | + |
||
1381 | + if (real_div) |
||
1382 | + clock = (host->max_clk * clk_mul) / real_div; |
||
1383 | + host->mmc->actual_clock = clock; |
||
1384 | + |
||
1385 | + if ((clock > input_clock) && (clock > host->max_overclock)) { |
||
1386 | + pr_warn("%s: Overclocking to %dHz\n", |
||
1387 | + mmc_hostname(host->mmc), clock); |
||
1388 | + host->max_overclock = clock; |
||
1389 | + } |
||
1390 | + |
||
1391 | + clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; |
||
1392 | + clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) |
||
1393 | + << SDHCI_DIVIDER_HI_SHIFT; |
||
1394 | + clk |= SDHCI_CLOCK_INT_EN; |
||
1395 | + bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL); |
||
1396 | + |
||
1397 | + /* Wait max 20 ms */ |
||
1398 | + timeout = 20; |
||
1399 | + while (!((clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL)) |
||
1400 | + & SDHCI_CLOCK_INT_STABLE)) { |
||
1401 | + if (timeout == 0) { |
||
1402 | + pr_err("%s: Internal clock never " |
||
1403 | + "stabilised.\n", mmc_hostname(host->mmc)); |
||
1404 | + bcm2835_mmc_dumpregs(host); |
||
1405 | + return; |
||
1406 | + } |
||
1407 | + timeout--; |
||
1408 | + mdelay(1); |
||
1409 | + } |
||
1410 | + |
||
1411 | + if (20-timeout > 10 && 20-timeout > host->max_delay) { |
||
1412 | + host->max_delay = 20-timeout; |
||
1413 | + pr_warning("Warning: MMC controller hung for %d ms\n", host->max_delay); |
||
1414 | + } |
||
1415 | + |
||
1416 | + clk |= SDHCI_CLOCK_CARD_EN; |
||
1417 | + bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL); |
||
1418 | +} |
||
1419 | + |
||
1420 | +static void bcm2835_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) |
||
1421 | +{ |
||
1422 | + struct bcm2835_host *host; |
||
1423 | + unsigned long flags; |
||
1424 | + |
||
1425 | + host = mmc_priv(mmc); |
||
1426 | + |
||
1427 | + spin_lock_irqsave(&host->lock, flags); |
||
1428 | + |
||
1429 | + WARN_ON(host->mrq != NULL); |
||
1430 | + |
||
1431 | + host->mrq = mrq; |
||
1432 | + |
||
1433 | + if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) |
||
1434 | + bcm2835_mmc_send_command(host, mrq->sbc); |
||
1435 | + else |
||
1436 | + bcm2835_mmc_send_command(host, mrq->cmd); |
||
1437 | + |
||
1438 | + mmiowb(); |
||
1439 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1440 | + |
||
1441 | + if (!(mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) && mrq->cmd->data && host->use_dma) { |
||
1442 | + /* DMA transfer starts now, PIO starts after interrupt */ |
||
1443 | + bcm2835_mmc_transfer_dma(host); |
||
1444 | + } |
||
1445 | +} |
||
1446 | + |
||
1447 | + |
||
1448 | +static void bcm2835_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
||
1449 | +{ |
||
1450 | + |
||
1451 | + struct bcm2835_host *host = mmc_priv(mmc); |
||
1452 | + unsigned long flags; |
||
1453 | + u8 ctrl; |
||
1454 | + u16 clk, ctrl_2; |
||
1455 | + |
||
1456 | + pr_debug("bcm2835_mmc_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n", |
||
1457 | + ios->clock, ios->power_mode, ios->bus_width, |
||
1458 | + ios->timing, ios->signal_voltage, ios->drv_type); |
||
1459 | + |
||
1460 | + spin_lock_irqsave(&host->lock, flags); |
||
1461 | + |
||
1462 | + if (!ios->clock || ios->clock != host->clock) { |
||
1463 | + bcm2835_mmc_set_clock(host, ios->clock); |
||
1464 | + host->clock = ios->clock; |
||
1465 | + } |
||
1466 | + |
||
1467 | + if (host->pwr != SDHCI_POWER_330) { |
||
1468 | + host->pwr = SDHCI_POWER_330; |
||
1469 | + bcm2835_mmc_writeb(host, SDHCI_POWER_330 | SDHCI_POWER_ON, SDHCI_POWER_CONTROL); |
||
1470 | + } |
||
1471 | + |
||
1472 | + ctrl = bcm2835_mmc_readb(host, SDHCI_HOST_CONTROL); |
||
1473 | + |
||
1474 | + /* set bus width */ |
||
1475 | + ctrl &= ~SDHCI_CTRL_8BITBUS; |
||
1476 | + if (ios->bus_width == MMC_BUS_WIDTH_4) |
||
1477 | + ctrl |= SDHCI_CTRL_4BITBUS; |
||
1478 | + else |
||
1479 | + ctrl &= ~SDHCI_CTRL_4BITBUS; |
||
1480 | + |
||
1481 | + ctrl &= ~SDHCI_CTRL_HISPD; /* NO_HISPD_BIT */ |
||
1482 | + |
||
1483 | + |
||
1484 | + bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); |
||
1485 | + /* |
||
1486 | + * We only need to set Driver Strength if the |
||
1487 | + * preset value enable is not set. |
||
1488 | + */ |
||
1489 | + ctrl_2 = bcm2835_mmc_readw(host, SDHCI_HOST_CONTROL2); |
||
1490 | + ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK; |
||
1491 | + if (ios->drv_type == MMC_SET_DRIVER_TYPE_A) |
||
1492 | + ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A; |
||
1493 | + else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C) |
||
1494 | + ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C; |
||
1495 | + |
||
1496 | + bcm2835_mmc_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); |
||
1497 | + |
||
1498 | + /* Reset SD Clock Enable */ |
||
1499 | + clk = bcm2835_mmc_readw(host, SDHCI_CLOCK_CONTROL); |
||
1500 | + clk &= ~SDHCI_CLOCK_CARD_EN; |
||
1501 | + bcm2835_mmc_writew(host, clk, SDHCI_CLOCK_CONTROL); |
||
1502 | + |
||
1503 | + /* Re-enable SD Clock */ |
||
1504 | + bcm2835_mmc_set_clock(host, host->clock); |
||
1505 | + bcm2835_mmc_writeb(host, ctrl, SDHCI_HOST_CONTROL); |
||
1506 | + |
||
1507 | + mmiowb(); |
||
1508 | + |
||
1509 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1510 | +} |
||
1511 | + |
||
1512 | + |
||
1513 | +static struct mmc_host_ops bcm2835_ops = { |
||
1514 | + .request = bcm2835_mmc_request, |
||
1515 | + .set_ios = bcm2835_mmc_set_ios, |
||
1516 | + .enable_sdio_irq = bcm2835_mmc_enable_sdio_irq, |
||
1517 | +}; |
||
1518 | + |
||
1519 | + |
||
1520 | +static void bcm2835_mmc_tasklet_finish(unsigned long param) |
||
1521 | +{ |
||
1522 | + struct bcm2835_host *host; |
||
1523 | + unsigned long flags; |
||
1524 | + struct mmc_request *mrq; |
||
1525 | + |
||
1526 | + host = (struct bcm2835_host *)param; |
||
1527 | + |
||
1528 | + spin_lock_irqsave(&host->lock, flags); |
||
1529 | + |
||
1530 | + /* |
||
1531 | + * If this tasklet gets rescheduled while running, it will |
||
1532 | + * be run again afterwards but without any active request. |
||
1533 | + */ |
||
1534 | + if (!host->mrq) { |
||
1535 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1536 | + return; |
||
1537 | + } |
||
1538 | + |
||
1539 | + del_timer(&host->timer); |
||
1540 | + |
||
1541 | + mrq = host->mrq; |
||
1542 | + |
||
1543 | + /* |
||
1544 | + * The controller needs a reset of internal state machines |
||
1545 | + * upon error conditions. |
||
1546 | + */ |
||
1547 | + if (!(host->flags & SDHCI_DEVICE_DEAD) && |
||
1548 | + ((mrq->cmd && mrq->cmd->error) || |
||
1549 | + (mrq->data && (mrq->data->error || |
||
1550 | + (mrq->data->stop && mrq->data->stop->error))))) { |
||
1551 | + |
||
1552 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1553 | + bcm2835_mmc_reset(host, SDHCI_RESET_CMD); |
||
1554 | + bcm2835_mmc_reset(host, SDHCI_RESET_DATA); |
||
1555 | + spin_lock_irqsave(&host->lock, flags); |
||
1556 | + } |
||
1557 | + |
||
1558 | + host->mrq = NULL; |
||
1559 | + host->cmd = NULL; |
||
1560 | + host->data = NULL; |
||
1561 | + |
||
1562 | + mmiowb(); |
||
1563 | + |
||
1564 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1565 | + mmc_request_done(host->mmc, mrq); |
||
1566 | +} |
||
1567 | + |
||
1568 | + |
||
1569 | + |
||
1570 | +static int bcm2835_mmc_add_host(struct bcm2835_host *host) |
||
1571 | +{ |
||
1572 | + struct mmc_host *mmc = host->mmc; |
||
1573 | + struct device *dev = mmc->parent; |
||
1574 | +#ifndef FORCE_PIO |
||
1575 | + struct dma_slave_config cfg; |
||
1576 | +#endif |
||
1577 | + int ret; |
||
1578 | + |
||
1579 | + bcm2835_mmc_reset(host, SDHCI_RESET_ALL); |
||
1580 | + |
||
1581 | + host->clk_mul = 0; |
||
1582 | + |
||
1583 | + mmc->f_max = host->max_clk; |
||
1584 | + mmc->f_max = host->max_clk; |
||
1585 | + mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; |
||
1586 | + |
||
1587 | + /* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */ |
||
1588 | + host->timeout_clk = mmc->f_max / 1000; |
||
1589 | + mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; |
||
1590 | + |
||
1591 | + /* host controller capabilities */ |
||
1592 | + mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_ERASE | MMC_CAP_NEEDS_POLL | |
||
1593 | + MMC_CAP_SDIO_IRQ | MMC_CAP_SD_HIGHSPEED | |
||
1594 | + MMC_CAP_MMC_HIGHSPEED; |
||
1595 | + |
||
1596 | + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; |
||
1597 | + |
||
1598 | + host->flags = SDHCI_AUTO_CMD23; |
||
1599 | + |
||
1600 | + dev_info(dev, "mmc_debug:%x mmc_debug2:%x\n", mmc_debug, mmc_debug2); |
||
1601 | +#ifdef FORCE_PIO |
||
1602 | + dev_info(dev, "Forcing PIO mode\n"); |
||
1603 | + host->have_dma = false; |
||
1604 | +#else |
||
1605 | + if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) { |
||
1606 | + dev_err(dev, "%s: Unable to initialise DMA channel. Falling back to PIO\n", |
||
1607 | + DRIVER_NAME); |
||
1608 | + host->have_dma = false; |
||
1609 | + } else { |
||
1610 | + dev_info(dev, "DMA channel allocated"); |
||
1611 | + |
||
1612 | + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
||
1613 | + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
||
1614 | + cfg.slave_id = 11; /* DREQ channel */ |
||
1615 | + |
||
1616 | + /* Validate the slave configurations */ |
||
1617 | + |
||
1618 | + cfg.direction = DMA_MEM_TO_DEV; |
||
1619 | + cfg.src_addr = 0; |
||
1620 | + cfg.dst_addr = host->bus_addr + SDHCI_BUFFER; |
||
1621 | + |
||
1622 | + ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg); |
||
1623 | + |
||
1624 | + if (ret == 0) { |
||
1625 | + host->dma_cfg_tx = cfg; |
||
1626 | + |
||
1627 | + cfg.direction = DMA_DEV_TO_MEM; |
||
1628 | + cfg.src_addr = host->bus_addr + SDHCI_BUFFER; |
||
1629 | + cfg.dst_addr = 0; |
||
1630 | + |
||
1631 | + ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg); |
||
1632 | + } |
||
1633 | + |
||
1634 | + if (ret == 0) { |
||
1635 | + host->dma_cfg_rx = cfg; |
||
1636 | + |
||
1637 | + host->have_dma = true; |
||
1638 | + } else { |
||
1639 | + pr_err("%s: unable to configure DMA channel. " |
||
1640 | + "Falling back to PIO\n", |
||
1641 | + mmc_hostname(mmc)); |
||
1642 | + dma_release_channel(host->dma_chan_rxtx); |
||
1643 | + host->dma_chan_rxtx = NULL; |
||
1644 | + host->have_dma = false; |
||
1645 | + } |
||
1646 | + } |
||
1647 | +#endif |
||
1648 | + mmc->max_segs = 128; |
||
1649 | + mmc->max_req_size = 524288; |
||
1650 | + mmc->max_seg_size = mmc->max_req_size; |
||
1651 | + mmc->max_blk_size = 512; |
||
1652 | + mmc->max_blk_count = 65535; |
||
1653 | + |
||
1654 | + /* report supported voltage ranges */ |
||
1655 | + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; |
||
1656 | + |
||
1657 | + tasklet_init(&host->finish_tasklet, |
||
1658 | + bcm2835_mmc_tasklet_finish, (unsigned long)host); |
||
1659 | + |
||
1660 | + setup_timer(&host->timer, bcm2835_mmc_timeout_timer, (unsigned long)host); |
||
1661 | + init_waitqueue_head(&host->buf_ready_int); |
||
1662 | + |
||
1663 | + bcm2835_mmc_init(host, 0); |
||
1664 | + ret = devm_request_threaded_irq(dev, host->irq, bcm2835_mmc_irq, |
||
1665 | + bcm2835_mmc_thread_irq, IRQF_SHARED, |
||
1666 | + mmc_hostname(mmc), host); |
||
1667 | + if (ret) { |
||
1668 | + dev_err(dev, "Failed to request IRQ %d: %d\n", host->irq, ret); |
||
1669 | + goto untasklet; |
||
1670 | + } |
||
1671 | + |
||
1672 | + mmiowb(); |
||
1673 | + mmc_add_host(mmc); |
||
1674 | + |
||
1675 | + return 0; |
||
1676 | + |
||
1677 | +untasklet: |
||
1678 | + tasklet_kill(&host->finish_tasklet); |
||
1679 | + |
||
1680 | + return ret; |
||
1681 | +} |
||
1682 | + |
||
1683 | +static int bcm2835_mmc_probe(struct platform_device *pdev) |
||
1684 | +{ |
||
1685 | + struct device *dev = &pdev->dev; |
||
1686 | + struct device_node *node = dev->of_node; |
||
1687 | + struct clk *clk; |
||
1688 | + struct resource *iomem; |
||
1689 | + struct bcm2835_host *host; |
||
1690 | + struct mmc_host *mmc; |
||
1691 | + const __be32 *addr; |
||
1692 | + int ret; |
||
1693 | + |
||
1694 | + mmc = mmc_alloc_host(sizeof(*host), dev); |
||
1695 | + if (!mmc) |
||
1696 | + return -ENOMEM; |
||
1697 | + |
||
1698 | + mmc->ops = &bcm2835_ops; |
||
1699 | + host = mmc_priv(mmc); |
||
1700 | + host->mmc = mmc; |
||
1701 | + host->timeout = msecs_to_jiffies(1000); |
||
1702 | + spin_lock_init(&host->lock); |
||
1703 | + |
||
1704 | + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
1705 | + host->ioaddr = devm_ioremap_resource(dev, iomem); |
||
1706 | + if (IS_ERR(host->ioaddr)) { |
||
1707 | + ret = PTR_ERR(host->ioaddr); |
||
1708 | + goto err; |
||
1709 | + } |
||
1710 | + |
||
1711 | + addr = of_get_address(node, 0, NULL, NULL); |
||
1712 | + if (!addr) { |
||
1713 | + dev_err(dev, "could not get DMA-register address\n"); |
||
1714 | + return -ENODEV; |
||
1715 | + } |
||
1716 | + host->bus_addr = be32_to_cpup(addr); |
||
1717 | + pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n", |
||
1718 | + (unsigned long)host->ioaddr, |
||
1719 | + (unsigned long)iomem->start, |
||
1720 | + (unsigned long)host->bus_addr); |
||
1721 | + |
||
1722 | +#ifndef FORCE_PIO |
||
1723 | + if (node) { |
||
1724 | + host->dma_chan_rxtx = dma_request_slave_channel(dev, "rx-tx"); |
||
1725 | + if (!host->dma_chan_rxtx) |
||
1726 | + host->dma_chan_rxtx = |
||
1727 | + dma_request_slave_channel(dev, "tx"); |
||
1728 | + if (!host->dma_chan_rxtx) |
||
1729 | + host->dma_chan_rxtx = |
||
1730 | + dma_request_slave_channel(dev, "rx"); |
||
1731 | + } else { |
||
1732 | + dma_cap_mask_t mask; |
||
1733 | + |
||
1734 | + dma_cap_zero(mask); |
||
1735 | + /* we don't care about the channel, any would work */ |
||
1736 | + dma_cap_set(DMA_SLAVE, mask); |
||
1737 | + host->dma_chan_rxtx = dma_request_channel(mask, NULL, NULL); |
||
1738 | + } |
||
1739 | +#endif |
||
1740 | + clk = devm_clk_get(dev, NULL); |
||
1741 | + if (IS_ERR(clk)) { |
||
1742 | + ret = PTR_ERR(clk); |
||
1743 | + if (ret == -EPROBE_DEFER) |
||
1744 | + dev_info(dev, "could not get clk, deferring probe\n"); |
||
1745 | + else |
||
1746 | + dev_err(dev, "could not get clk\n"); |
||
1747 | + goto err; |
||
1748 | + } |
||
1749 | + |
||
1750 | + host->max_clk = clk_get_rate(clk); |
||
1751 | + |
||
1752 | + host->irq = platform_get_irq(pdev, 0); |
||
1753 | + if (host->irq <= 0) { |
||
1754 | + dev_err(dev, "get IRQ failed\n"); |
||
1755 | + ret = -EINVAL; |
||
1756 | + goto err; |
||
1757 | + } |
||
1758 | + |
||
1759 | + if (node) { |
||
1760 | + mmc_of_parse(mmc); |
||
1761 | + |
||
1762 | + /* Read any custom properties */ |
||
1763 | + of_property_read_u32(node, |
||
1764 | + "brcm,overclock-50", |
||
1765 | + &host->overclock_50); |
||
1766 | + } else { |
||
1767 | + mmc->caps |= MMC_CAP_4_BIT_DATA; |
||
1768 | + } |
||
1769 | + |
||
1770 | + ret = bcm2835_mmc_add_host(host); |
||
1771 | + if (ret) |
||
1772 | + goto err; |
||
1773 | + |
||
1774 | + platform_set_drvdata(pdev, host); |
||
1775 | + |
||
1776 | + return 0; |
||
1777 | +err: |
||
1778 | + mmc_free_host(mmc); |
||
1779 | + |
||
1780 | + return ret; |
||
1781 | +} |
||
1782 | + |
||
1783 | +static int bcm2835_mmc_remove(struct platform_device *pdev) |
||
1784 | +{ |
||
1785 | + struct bcm2835_host *host = platform_get_drvdata(pdev); |
||
1786 | + unsigned long flags; |
||
1787 | + int dead; |
||
1788 | + u32 scratch; |
||
1789 | + |
||
1790 | + dead = 0; |
||
1791 | + scratch = bcm2835_mmc_readl(host, SDHCI_INT_STATUS); |
||
1792 | + if (scratch == (u32)-1) |
||
1793 | + dead = 1; |
||
1794 | + |
||
1795 | + |
||
1796 | + if (dead) { |
||
1797 | + spin_lock_irqsave(&host->lock, flags); |
||
1798 | + |
||
1799 | + host->flags |= SDHCI_DEVICE_DEAD; |
||
1800 | + |
||
1801 | + if (host->mrq) { |
||
1802 | + pr_err("%s: Controller removed during " |
||
1803 | + " transfer!\n", mmc_hostname(host->mmc)); |
||
1804 | + |
||
1805 | + host->mrq->cmd->error = -ENOMEDIUM; |
||
1806 | + tasklet_schedule(&host->finish_tasklet); |
||
1807 | + } |
||
1808 | + |
||
1809 | + spin_unlock_irqrestore(&host->lock, flags); |
||
1810 | + } |
||
1811 | + |
||
1812 | + mmc_remove_host(host->mmc); |
||
1813 | + |
||
1814 | + if (!dead) |
||
1815 | + bcm2835_mmc_reset(host, SDHCI_RESET_ALL); |
||
1816 | + |
||
1817 | + free_irq(host->irq, host); |
||
1818 | + |
||
1819 | + del_timer_sync(&host->timer); |
||
1820 | + |
||
1821 | + tasklet_kill(&host->finish_tasklet); |
||
1822 | + |
||
1823 | + mmc_free_host(host->mmc); |
||
1824 | + platform_set_drvdata(pdev, NULL); |
||
1825 | + |
||
1826 | + return 0; |
||
1827 | +} |
||
1828 | + |
||
1829 | + |
||
1830 | +static const struct of_device_id bcm2835_mmc_match[] = { |
||
1831 | + { .compatible = "brcm,bcm2835-mmc" }, |
||
1832 | + { } |
||
1833 | +}; |
||
1834 | +MODULE_DEVICE_TABLE(of, bcm2835_mmc_match); |
||
1835 | + |
||
1836 | + |
||
1837 | + |
||
1838 | +static struct platform_driver bcm2835_mmc_driver = { |
||
1839 | + .probe = bcm2835_mmc_probe, |
||
1840 | + .remove = bcm2835_mmc_remove, |
||
1841 | + .driver = { |
||
1842 | + .name = DRIVER_NAME, |
||
1843 | + .owner = THIS_MODULE, |
||
1844 | + .of_match_table = bcm2835_mmc_match, |
||
1845 | + }, |
||
1846 | +}; |
||
1847 | +module_platform_driver(bcm2835_mmc_driver); |
||
1848 | + |
||
1849 | +module_param(mmc_debug, uint, 0644); |
||
1850 | +module_param(mmc_debug2, uint, 0644); |
||
1851 | +MODULE_ALIAS("platform:mmc-bcm2835"); |
||
1852 | +MODULE_DESCRIPTION("BCM2835 SDHCI driver"); |
||
1853 | +MODULE_LICENSE("GPL v2"); |
||
1854 | +MODULE_AUTHOR("Gellert Weisz"); |
||
1855 | --- a/include/linux/mmc/card.h |
||
1856 | +++ b/include/linux/mmc/card.h |
||
1857 | @@ -269,6 +269,8 @@ struct mmc_card { |
||
1858 | #define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */ |
||
1859 | #define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */ |
||
1860 | |||
1861 | +#define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */ |
||
1862 | + |
||
1863 | bool reenable_cmdq; /* Re-enable Command Queue */ |
||
1864 | |||
1865 | unsigned int erase_size; /* erase size in sectors */ |