1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> |
---|
5 | * Copyright (c) 2011 Ben Gray <ben.r.gray@gmail.com>. |
---|
6 | * All rights reserved. |
---|
7 | * |
---|
8 | * Redistribution and use in source and binary forms, with or without |
---|
9 | * modification, are permitted provided that the following conditions |
---|
10 | * are met: |
---|
11 | * 1. Redistributions of source code must retain the above copyright |
---|
12 | * notice, this list of conditions and the following disclaimer. |
---|
13 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
14 | * notice, this list of conditions and the following disclaimer in the |
---|
15 | * documentation and/or other materials provided with the distribution. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
---|
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
---|
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
27 | * SUCH DAMAGE. |
---|
28 | * |
---|
29 | */ |
---|
30 | #include <sys/cdefs.h> |
---|
31 | __FBSDID("$FreeBSD$"); |
---|
32 | |
---|
33 | #include <sys/param.h> |
---|
34 | #include <sys/systm.h> |
---|
35 | #include <sys/bus.h> |
---|
36 | #include <sys/gpio.h> |
---|
37 | #include <sys/kernel.h> |
---|
38 | #include <sys/malloc.h> |
---|
39 | #include <sys/module.h> |
---|
40 | #include <rtems/bsd/sys/resource.h> |
---|
41 | #include <sys/rman.h> |
---|
42 | #include <sys/sysctl.h> |
---|
43 | #include <sys/taskqueue.h> |
---|
44 | |
---|
45 | #include <machine/bus.h> |
---|
46 | #include <machine/resource.h> |
---|
47 | #include <machine/intr.h> |
---|
48 | |
---|
49 | #include <dev/ofw/ofw_bus.h> |
---|
50 | #include <dev/ofw/ofw_bus_subr.h> |
---|
51 | |
---|
52 | #include <dev/mmc/bridge.h> |
---|
53 | #include <dev/mmc/mmcreg.h> |
---|
54 | #include <dev/mmc/mmcbrvar.h> |
---|
55 | |
---|
56 | #include <dev/sdhci/sdhci.h> |
---|
57 | #include <dev/sdhci/sdhci_fdt_gpio.h> |
---|
58 | #include <rtems/bsd/local/sdhci_if.h> |
---|
59 | |
---|
60 | #include <arm/ti/ti_cpuid.h> |
---|
61 | #include <arm/ti/ti_prcm.h> |
---|
62 | #include <arm/ti/ti_hwmods.h> |
---|
63 | #include <rtems/bsd/local/gpio_if.h> |
---|
64 | |
---|
65 | struct ti_sdhci_softc { |
---|
66 | device_t dev; |
---|
67 | struct sdhci_fdt_gpio * gpio; |
---|
68 | struct resource * mem_res; |
---|
69 | struct resource * irq_res; |
---|
70 | void * intr_cookie; |
---|
71 | struct sdhci_slot slot; |
---|
72 | clk_ident_t mmchs_clk_id; |
---|
73 | uint32_t mmchs_reg_off; |
---|
74 | uint32_t sdhci_reg_off; |
---|
75 | uint32_t baseclk_hz; |
---|
76 | uint32_t cmd_and_mode; |
---|
77 | uint32_t sdhci_clkdiv; |
---|
78 | boolean_t disable_highspeed; |
---|
79 | boolean_t force_card_present; |
---|
80 | boolean_t disable_readonly; |
---|
81 | }; |
---|
82 | |
---|
83 | /* |
---|
84 | * Table of supported FDT compat strings. |
---|
85 | * |
---|
86 | * Note that "ti,mmchs" is our own invention, and should be phased out in favor |
---|
87 | * of the documented names. |
---|
88 | * |
---|
89 | * Note that vendor Beaglebone dtsi files use "ti,omap3-hsmmc" for the am335x. |
---|
90 | */ |
---|
91 | static struct ofw_compat_data compat_data[] = { |
---|
92 | {"ti,omap3-hsmmc", 1}, |
---|
93 | {"ti,omap4-hsmmc", 1}, |
---|
94 | {"ti,mmchs", 1}, |
---|
95 | {NULL, 0}, |
---|
96 | }; |
---|
97 | |
---|
98 | /* |
---|
99 | * The MMCHS hardware has a few control and status registers at the beginning of |
---|
100 | * the device's memory map, followed by the standard sdhci register block. |
---|
101 | * Different SoCs have the register blocks at different offsets from the |
---|
102 | * beginning of the device. Define some constants to map out the registers we |
---|
103 | * access, and the various per-SoC offsets. The SDHCI_REG_OFFSET is how far |
---|
104 | * beyond the MMCHS block the SDHCI block is found; it's the same on all SoCs. |
---|
105 | */ |
---|
106 | #define OMAP3_MMCHS_REG_OFFSET 0x000 |
---|
107 | #define OMAP4_MMCHS_REG_OFFSET 0x100 |
---|
108 | #define AM335X_MMCHS_REG_OFFSET 0x100 |
---|
109 | #define SDHCI_REG_OFFSET 0x100 |
---|
110 | |
---|
111 | #define MMCHS_SYSCONFIG 0x010 |
---|
112 | #define MMCHS_SYSCONFIG_RESET (1 << 1) |
---|
113 | #define MMCHS_SYSSTATUS 0x014 |
---|
114 | #define MMCHS_SYSSTATUS_RESETDONE (1 << 0) |
---|
115 | #define MMCHS_CON 0x02C |
---|
116 | #define MMCHS_CON_DW8 (1 << 5) |
---|
117 | #define MMCHS_CON_DVAL_8_4MS (3 << 9) |
---|
118 | #define MMCHS_CON_OD (1 << 0) |
---|
119 | #define MMCHS_SYSCTL 0x12C |
---|
120 | #define MMCHS_SYSCTL_CLKD_MASK 0x3FF |
---|
121 | #define MMCHS_SYSCTL_CLKD_SHIFT 6 |
---|
122 | #define MMCHS_SD_CAPA 0x140 |
---|
123 | #define MMCHS_SD_CAPA_VS18 (1 << 26) |
---|
124 | #define MMCHS_SD_CAPA_VS30 (1 << 25) |
---|
125 | #define MMCHS_SD_CAPA_VS33 (1 << 24) |
---|
126 | |
---|
127 | static inline uint32_t |
---|
128 | ti_mmchs_read_4(struct ti_sdhci_softc *sc, bus_size_t off) |
---|
129 | { |
---|
130 | |
---|
131 | return (bus_read_4(sc->mem_res, off + sc->mmchs_reg_off)); |
---|
132 | } |
---|
133 | |
---|
134 | static inline void |
---|
135 | ti_mmchs_write_4(struct ti_sdhci_softc *sc, bus_size_t off, uint32_t val) |
---|
136 | { |
---|
137 | |
---|
138 | bus_write_4(sc->mem_res, off + sc->mmchs_reg_off, val); |
---|
139 | } |
---|
140 | |
---|
141 | static inline uint32_t |
---|
142 | RD4(struct ti_sdhci_softc *sc, bus_size_t off) |
---|
143 | { |
---|
144 | |
---|
145 | return (bus_read_4(sc->mem_res, off + sc->sdhci_reg_off)); |
---|
146 | } |
---|
147 | |
---|
148 | static inline void |
---|
149 | WR4(struct ti_sdhci_softc *sc, bus_size_t off, uint32_t val) |
---|
150 | { |
---|
151 | |
---|
152 | bus_write_4(sc->mem_res, off + sc->sdhci_reg_off, val); |
---|
153 | } |
---|
154 | |
---|
155 | static uint8_t |
---|
156 | ti_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) |
---|
157 | { |
---|
158 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
159 | |
---|
160 | return ((RD4(sc, off & ~3) >> (off & 3) * 8) & 0xff); |
---|
161 | } |
---|
162 | |
---|
163 | static uint16_t |
---|
164 | ti_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) |
---|
165 | { |
---|
166 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
167 | uint32_t clkdiv, val32; |
---|
168 | |
---|
169 | /* |
---|
170 | * The MMCHS hardware has a non-standard interpretation of the sdclock |
---|
171 | * divisor bits. It uses the same bit positions as SDHCI 3.0 (15..6) |
---|
172 | * but doesn't split them into low:high fields. Instead they're a |
---|
173 | * single number in the range 0..1023 and the number is exactly the |
---|
174 | * clock divisor (with 0 and 1 both meaning divide by 1). The SDHCI |
---|
175 | * driver code expects a v2.0 or v3.0 divisor. The shifting and masking |
---|
176 | * here extracts the MMCHS representation from the hardware word, cleans |
---|
177 | * those bits out, applies the 2N adjustment, and plugs the result into |
---|
178 | * the bit positions for the 2.0 or 3.0 divisor in the returned register |
---|
179 | * value. The ti_sdhci_write_2() routine performs the opposite |
---|
180 | * transformation when the SDHCI driver writes to the register. |
---|
181 | */ |
---|
182 | if (off == SDHCI_CLOCK_CONTROL) { |
---|
183 | val32 = RD4(sc, SDHCI_CLOCK_CONTROL); |
---|
184 | clkdiv = ((val32 >> MMCHS_SYSCTL_CLKD_SHIFT) & |
---|
185 | MMCHS_SYSCTL_CLKD_MASK) / 2; |
---|
186 | val32 &= ~(MMCHS_SYSCTL_CLKD_MASK << MMCHS_SYSCTL_CLKD_SHIFT); |
---|
187 | val32 |= (clkdiv & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT; |
---|
188 | if (slot->version >= SDHCI_SPEC_300) |
---|
189 | val32 |= ((clkdiv >> SDHCI_DIVIDER_MASK_LEN) & |
---|
190 | SDHCI_DIVIDER_HI_MASK) << SDHCI_DIVIDER_HI_SHIFT; |
---|
191 | return (val32 & 0xffff); |
---|
192 | } |
---|
193 | |
---|
194 | /* |
---|
195 | * Standard 32-bit handling of command and transfer mode. |
---|
196 | */ |
---|
197 | if (off == SDHCI_TRANSFER_MODE) { |
---|
198 | return (sc->cmd_and_mode >> 16); |
---|
199 | } else if (off == SDHCI_COMMAND_FLAGS) { |
---|
200 | return (sc->cmd_and_mode & 0x0000ffff); |
---|
201 | } |
---|
202 | |
---|
203 | return ((RD4(sc, off & ~3) >> (off & 3) * 8) & 0xffff); |
---|
204 | } |
---|
205 | |
---|
206 | static uint32_t |
---|
207 | ti_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) |
---|
208 | { |
---|
209 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
210 | uint32_t val32; |
---|
211 | |
---|
212 | val32 = RD4(sc, off); |
---|
213 | |
---|
214 | /* |
---|
215 | * If we need to disallow highspeed mode due to the OMAP4 erratum, strip |
---|
216 | * that flag from the returned capabilities. |
---|
217 | */ |
---|
218 | if (off == SDHCI_CAPABILITIES && sc->disable_highspeed) |
---|
219 | val32 &= ~SDHCI_CAN_DO_HISPD; |
---|
220 | |
---|
221 | /* |
---|
222 | * Force the card-present state if necessary. |
---|
223 | */ |
---|
224 | if (off == SDHCI_PRESENT_STATE && sc->force_card_present) |
---|
225 | val32 |= SDHCI_CARD_PRESENT; |
---|
226 | |
---|
227 | return (val32); |
---|
228 | } |
---|
229 | |
---|
230 | static void |
---|
231 | ti_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, |
---|
232 | uint32_t *data, bus_size_t count) |
---|
233 | { |
---|
234 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
235 | |
---|
236 | bus_read_multi_4(sc->mem_res, off + sc->sdhci_reg_off, data, count); |
---|
237 | } |
---|
238 | |
---|
239 | static void |
---|
240 | ti_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, |
---|
241 | uint8_t val) |
---|
242 | { |
---|
243 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
244 | uint32_t val32; |
---|
245 | |
---|
246 | val32 = RD4(sc, off & ~3); |
---|
247 | val32 &= ~(0xff << (off & 3) * 8); |
---|
248 | val32 |= (val << (off & 3) * 8); |
---|
249 | |
---|
250 | WR4(sc, off & ~3, val32); |
---|
251 | } |
---|
252 | |
---|
253 | static void |
---|
254 | ti_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, |
---|
255 | uint16_t val) |
---|
256 | { |
---|
257 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
258 | uint32_t clkdiv, val32; |
---|
259 | |
---|
260 | /* |
---|
261 | * Translate between the hardware and SDHCI 2.0 or 3.0 representations |
---|
262 | * of the clock divisor. See the comments in ti_sdhci_read_2() for |
---|
263 | * details. |
---|
264 | */ |
---|
265 | if (off == SDHCI_CLOCK_CONTROL) { |
---|
266 | clkdiv = (val >> SDHCI_DIVIDER_SHIFT) & SDHCI_DIVIDER_MASK; |
---|
267 | if (slot->version >= SDHCI_SPEC_300) |
---|
268 | clkdiv |= ((val >> SDHCI_DIVIDER_HI_SHIFT) & |
---|
269 | SDHCI_DIVIDER_HI_MASK) << SDHCI_DIVIDER_MASK_LEN; |
---|
270 | clkdiv *= 2; |
---|
271 | if (clkdiv > MMCHS_SYSCTL_CLKD_MASK) |
---|
272 | clkdiv = MMCHS_SYSCTL_CLKD_MASK; |
---|
273 | val32 = RD4(sc, SDHCI_CLOCK_CONTROL); |
---|
274 | val32 &= 0xffff0000; |
---|
275 | val32 |= val & ~(MMCHS_SYSCTL_CLKD_MASK << |
---|
276 | MMCHS_SYSCTL_CLKD_SHIFT); |
---|
277 | val32 |= clkdiv << MMCHS_SYSCTL_CLKD_SHIFT; |
---|
278 | WR4(sc, SDHCI_CLOCK_CONTROL, val32); |
---|
279 | return; |
---|
280 | } |
---|
281 | |
---|
282 | /* |
---|
283 | * Standard 32-bit handling of command and transfer mode. |
---|
284 | */ |
---|
285 | if (off == SDHCI_TRANSFER_MODE) { |
---|
286 | sc->cmd_and_mode = (sc->cmd_and_mode & 0xffff0000) | |
---|
287 | ((uint32_t)val & 0x0000ffff); |
---|
288 | return; |
---|
289 | } else if (off == SDHCI_COMMAND_FLAGS) { |
---|
290 | sc->cmd_and_mode = (sc->cmd_and_mode & 0x0000ffff) | |
---|
291 | ((uint32_t)val << 16); |
---|
292 | WR4(sc, SDHCI_TRANSFER_MODE, sc->cmd_and_mode); |
---|
293 | return; |
---|
294 | } |
---|
295 | |
---|
296 | val32 = RD4(sc, off & ~3); |
---|
297 | val32 &= ~(0xffff << (off & 3) * 8); |
---|
298 | val32 |= ((val & 0xffff) << (off & 3) * 8); |
---|
299 | WR4(sc, off & ~3, val32); |
---|
300 | } |
---|
301 | |
---|
302 | static void |
---|
303 | ti_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, |
---|
304 | uint32_t val) |
---|
305 | { |
---|
306 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
307 | |
---|
308 | WR4(sc, off, val); |
---|
309 | } |
---|
310 | |
---|
311 | static void |
---|
312 | ti_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, |
---|
313 | uint32_t *data, bus_size_t count) |
---|
314 | { |
---|
315 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
316 | |
---|
317 | bus_write_multi_4(sc->mem_res, off + sc->sdhci_reg_off, data, count); |
---|
318 | } |
---|
319 | |
---|
320 | static void |
---|
321 | ti_sdhci_intr(void *arg) |
---|
322 | { |
---|
323 | struct ti_sdhci_softc *sc = arg; |
---|
324 | |
---|
325 | sdhci_generic_intr(&sc->slot); |
---|
326 | } |
---|
327 | |
---|
328 | static int |
---|
329 | ti_sdhci_update_ios(device_t brdev, device_t reqdev) |
---|
330 | { |
---|
331 | struct ti_sdhci_softc *sc = device_get_softc(brdev); |
---|
332 | struct sdhci_slot *slot; |
---|
333 | struct mmc_ios *ios; |
---|
334 | uint32_t val32, newval32; |
---|
335 | |
---|
336 | slot = device_get_ivars(reqdev); |
---|
337 | ios = &slot->host.ios; |
---|
338 | |
---|
339 | /* |
---|
340 | * There is an 8-bit-bus bit in the MMCHS control register which, when |
---|
341 | * set, overrides the 1 vs 4 bit setting in the standard SDHCI |
---|
342 | * registers. Set that bit first according to whether an 8-bit bus is |
---|
343 | * requested, then let the standard driver handle everything else. |
---|
344 | */ |
---|
345 | val32 = ti_mmchs_read_4(sc, MMCHS_CON); |
---|
346 | newval32 = val32; |
---|
347 | |
---|
348 | if (ios->bus_width == bus_width_8) |
---|
349 | newval32 |= MMCHS_CON_DW8; |
---|
350 | else |
---|
351 | newval32 &= ~MMCHS_CON_DW8; |
---|
352 | |
---|
353 | if (ios->bus_mode == opendrain) |
---|
354 | newval32 |= MMCHS_CON_OD; |
---|
355 | else /* if (ios->bus_mode == pushpull) */ |
---|
356 | newval32 &= ~MMCHS_CON_OD; |
---|
357 | |
---|
358 | if (newval32 != val32) |
---|
359 | ti_mmchs_write_4(sc, MMCHS_CON, newval32); |
---|
360 | |
---|
361 | return (sdhci_generic_update_ios(brdev, reqdev)); |
---|
362 | } |
---|
363 | |
---|
364 | static int |
---|
365 | ti_sdhci_get_ro(device_t brdev, device_t reqdev) |
---|
366 | { |
---|
367 | struct ti_sdhci_softc *sc = device_get_softc(brdev); |
---|
368 | |
---|
369 | if (sc->disable_readonly) |
---|
370 | return (0); |
---|
371 | |
---|
372 | return (sdhci_fdt_gpio_get_readonly(sc->gpio)); |
---|
373 | } |
---|
374 | |
---|
375 | static bool |
---|
376 | ti_sdhci_get_card_present(device_t dev, struct sdhci_slot *slot) |
---|
377 | { |
---|
378 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
379 | |
---|
380 | return (sdhci_fdt_gpio_get_present(sc->gpio)); |
---|
381 | } |
---|
382 | |
---|
383 | static int |
---|
384 | ti_sdhci_detach(device_t dev) |
---|
385 | { |
---|
386 | |
---|
387 | /* sdhci_fdt_gpio_teardown(sc->gpio); */ |
---|
388 | |
---|
389 | return (EBUSY); |
---|
390 | } |
---|
391 | |
---|
392 | static void |
---|
393 | ti_sdhci_hw_init(device_t dev) |
---|
394 | { |
---|
395 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
396 | uint32_t regval; |
---|
397 | unsigned long timeout; |
---|
398 | |
---|
399 | /* Enable the controller and interface/functional clocks */ |
---|
400 | if (ti_prcm_clk_enable(sc->mmchs_clk_id) != 0) { |
---|
401 | device_printf(dev, "Error: failed to enable MMC clock\n"); |
---|
402 | return; |
---|
403 | } |
---|
404 | |
---|
405 | /* Get the frequency of the source clock */ |
---|
406 | if (ti_prcm_clk_get_source_freq(sc->mmchs_clk_id, |
---|
407 | &sc->baseclk_hz) != 0) { |
---|
408 | device_printf(dev, "Error: failed to get source clock freq\n"); |
---|
409 | return; |
---|
410 | } |
---|
411 | |
---|
412 | /* Issue a softreset to the controller */ |
---|
413 | ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, MMCHS_SYSCONFIG_RESET); |
---|
414 | timeout = 1000; |
---|
415 | while (!(ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & |
---|
416 | MMCHS_SYSSTATUS_RESETDONE)) { |
---|
417 | if (--timeout == 0) { |
---|
418 | device_printf(dev, |
---|
419 | "Error: Controller reset operation timed out\n"); |
---|
420 | break; |
---|
421 | } |
---|
422 | DELAY(100); |
---|
423 | } |
---|
424 | |
---|
425 | /* |
---|
426 | * Reset the command and data state machines and also other aspects of |
---|
427 | * the controller such as bus clock and power. |
---|
428 | * |
---|
429 | * If we read the software reset register too fast after writing it we |
---|
430 | * can get back a zero that means the reset hasn't started yet rather |
---|
431 | * than that the reset is complete. Per TI recommendations, work around |
---|
432 | * it by reading until we see the reset bit asserted, then read until |
---|
433 | * it's clear. We also set the SDHCI_QUIRK_WAITFOR_RESET_ASSERTED quirk |
---|
434 | * so that the main sdhci driver uses this same logic in its resets. |
---|
435 | */ |
---|
436 | ti_sdhci_write_1(dev, NULL, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL); |
---|
437 | timeout = 10000; |
---|
438 | while ((ti_sdhci_read_1(dev, NULL, SDHCI_SOFTWARE_RESET) & |
---|
439 | SDHCI_RESET_ALL) != SDHCI_RESET_ALL) { |
---|
440 | if (--timeout == 0) { |
---|
441 | break; |
---|
442 | } |
---|
443 | DELAY(1); |
---|
444 | } |
---|
445 | timeout = 10000; |
---|
446 | while ((ti_sdhci_read_1(dev, NULL, SDHCI_SOFTWARE_RESET) & |
---|
447 | SDHCI_RESET_ALL)) { |
---|
448 | if (--timeout == 0) { |
---|
449 | device_printf(dev, |
---|
450 | "Error: Software reset operation timed out\n"); |
---|
451 | break; |
---|
452 | } |
---|
453 | DELAY(100); |
---|
454 | } |
---|
455 | |
---|
456 | /* |
---|
457 | * The attach() routine has examined fdt data and set flags in |
---|
458 | * slot.host.caps to reflect what voltages we can handle. Set those |
---|
459 | * values in the CAPA register. The manual says that these values can |
---|
460 | * only be set once, "before initialization" whatever that means, and |
---|
461 | * that they survive a reset. So maybe doing this will be a no-op if |
---|
462 | * u-boot has already initialized the hardware. |
---|
463 | */ |
---|
464 | regval = ti_mmchs_read_4(sc, MMCHS_SD_CAPA); |
---|
465 | if (sc->slot.host.caps & MMC_OCR_LOW_VOLTAGE) |
---|
466 | regval |= MMCHS_SD_CAPA_VS18; |
---|
467 | if (sc->slot.host.caps & (MMC_OCR_290_300 | MMC_OCR_300_310)) |
---|
468 | regval |= MMCHS_SD_CAPA_VS30; |
---|
469 | ti_mmchs_write_4(sc, MMCHS_SD_CAPA, regval); |
---|
470 | |
---|
471 | /* Set initial host configuration (1-bit, std speed, pwr off). */ |
---|
472 | ti_sdhci_write_1(dev, NULL, SDHCI_HOST_CONTROL, 0); |
---|
473 | ti_sdhci_write_1(dev, NULL, SDHCI_POWER_CONTROL, 0); |
---|
474 | |
---|
475 | /* Set the initial controller configuration. */ |
---|
476 | ti_mmchs_write_4(sc, MMCHS_CON, MMCHS_CON_DVAL_8_4MS); |
---|
477 | } |
---|
478 | |
---|
479 | static int |
---|
480 | ti_sdhci_attach(device_t dev) |
---|
481 | { |
---|
482 | struct ti_sdhci_softc *sc = device_get_softc(dev); |
---|
483 | int rid, err; |
---|
484 | pcell_t prop; |
---|
485 | phandle_t node; |
---|
486 | |
---|
487 | sc->dev = dev; |
---|
488 | |
---|
489 | /* |
---|
490 | * Get the MMCHS device id from FDT. If it's not there use the newbus |
---|
491 | * unit number (which will work as long as the devices are in order and |
---|
492 | * none are skipped in the fdt). Note that this is a property we made |
---|
493 | * up and added in freebsd, it doesn't exist in the published bindings. |
---|
494 | */ |
---|
495 | node = ofw_bus_get_node(dev); |
---|
496 | sc->mmchs_clk_id = ti_hwmods_get_clock(dev); |
---|
497 | if (sc->mmchs_clk_id == INVALID_CLK_IDENT) { |
---|
498 | device_printf(dev, "failed to get clock based on hwmods property\n"); |
---|
499 | } |
---|
500 | |
---|
501 | /* |
---|
502 | * The hardware can inherently do dual-voltage (1p8v, 3p0v) on the first |
---|
503 | * device, and only 1p8v on other devices unless an external transceiver |
---|
504 | * is used. The only way we could know about a transceiver is fdt data. |
---|
505 | * Note that we have to do this before calling ti_sdhci_hw_init() so |
---|
506 | * that it can set the right values in the CAPA register, which can only |
---|
507 | * be done once and never reset. |
---|
508 | */ |
---|
509 | sc->slot.host.caps |= MMC_OCR_LOW_VOLTAGE; |
---|
510 | if (sc->mmchs_clk_id == MMC1_CLK || OF_hasprop(node, "ti,dual-volt")) { |
---|
511 | sc->slot.host.caps |= MMC_OCR_290_300 | MMC_OCR_300_310; |
---|
512 | } |
---|
513 | |
---|
514 | /* |
---|
515 | * Set the offset from the device's memory start to the MMCHS registers. |
---|
516 | * Also for OMAP4 disable high speed mode due to erratum ID i626. |
---|
517 | */ |
---|
518 | switch (ti_chip()) { |
---|
519 | #ifdef SOC_OMAP4 |
---|
520 | case CHIP_OMAP_4: |
---|
521 | sc->mmchs_reg_off = OMAP4_MMCHS_REG_OFFSET; |
---|
522 | sc->disable_highspeed = true; |
---|
523 | break; |
---|
524 | #endif |
---|
525 | #ifdef SOC_TI_AM335X |
---|
526 | case CHIP_AM335X: |
---|
527 | sc->mmchs_reg_off = AM335X_MMCHS_REG_OFFSET; |
---|
528 | break; |
---|
529 | #endif |
---|
530 | default: |
---|
531 | panic("Unknown OMAP device\n"); |
---|
532 | } |
---|
533 | |
---|
534 | /* |
---|
535 | * The standard SDHCI registers are at a fixed offset (the same on all |
---|
536 | * SoCs) beyond the MMCHS registers. |
---|
537 | */ |
---|
538 | sc->sdhci_reg_off = sc->mmchs_reg_off + SDHCI_REG_OFFSET; |
---|
539 | |
---|
540 | /* Resource setup. */ |
---|
541 | rid = 0; |
---|
542 | sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, |
---|
543 | RF_ACTIVE); |
---|
544 | if (!sc->mem_res) { |
---|
545 | device_printf(dev, "cannot allocate memory window\n"); |
---|
546 | err = ENXIO; |
---|
547 | goto fail; |
---|
548 | } |
---|
549 | |
---|
550 | rid = 0; |
---|
551 | sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, |
---|
552 | RF_ACTIVE); |
---|
553 | if (!sc->irq_res) { |
---|
554 | device_printf(dev, "cannot allocate interrupt\n"); |
---|
555 | err = ENXIO; |
---|
556 | goto fail; |
---|
557 | } |
---|
558 | |
---|
559 | if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE, |
---|
560 | NULL, ti_sdhci_intr, sc, &sc->intr_cookie)) { |
---|
561 | device_printf(dev, "cannot setup interrupt handler\n"); |
---|
562 | err = ENXIO; |
---|
563 | goto fail; |
---|
564 | } |
---|
565 | |
---|
566 | /* |
---|
567 | * Set up handling of card-detect and write-protect gpio lines. |
---|
568 | * |
---|
569 | * If there is no write protect info in the fdt data, fall back to the |
---|
570 | * historical practice of assuming that the card is writable. This |
---|
571 | * works around bad fdt data from the upstream source. The alternative |
---|
572 | * would be to trust the sdhci controller's PRESENT_STATE register WP |
---|
573 | * bit, but it may say write protect is in effect when it's not if the |
---|
574 | * pinmux setup doesn't route the WP signal into the sdchi block. |
---|
575 | */ |
---|
576 | sc->gpio = sdhci_fdt_gpio_setup(sc->dev, &sc->slot); |
---|
577 | |
---|
578 | if (!OF_hasprop(node, "wp-gpios") && !OF_hasprop(node, "wp-disable")) |
---|
579 | sc->disable_readonly = true; |
---|
580 | |
---|
581 | /* Initialise the MMCHS hardware. */ |
---|
582 | ti_sdhci_hw_init(dev); |
---|
583 | |
---|
584 | /* |
---|
585 | * The capabilities register can only express base clock frequencies in |
---|
586 | * the range of 0-63MHz for a v2.0 controller. Since our clock runs |
---|
587 | * faster than that, the hardware sets the frequency to zero in the |
---|
588 | * register. When the register contains zero, the sdhci driver expects |
---|
589 | * slot.max_clk to already have the right value in it. |
---|
590 | */ |
---|
591 | sc->slot.max_clk = sc->baseclk_hz; |
---|
592 | |
---|
593 | /* |
---|
594 | * The MMCHS timeout counter is based on the output sdclock. Tell the |
---|
595 | * sdhci driver to recalculate the timeout clock whenever the output |
---|
596 | * sdclock frequency changes. |
---|
597 | */ |
---|
598 | sc->slot.quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; |
---|
599 | |
---|
600 | /* |
---|
601 | * The MMCHS hardware shifts the 136-bit response data (in violation of |
---|
602 | * the spec), so tell the sdhci driver not to do the same in software. |
---|
603 | */ |
---|
604 | sc->slot.quirks |= SDHCI_QUIRK_DONT_SHIFT_RESPONSE; |
---|
605 | |
---|
606 | /* |
---|
607 | * Reset bits are broken, have to wait to see the bits asserted |
---|
608 | * before waiting to see them de-asserted. |
---|
609 | */ |
---|
610 | sc->slot.quirks |= SDHCI_QUIRK_WAITFOR_RESET_ASSERTED; |
---|
611 | |
---|
612 | /* |
---|
613 | * The controller waits for busy responses. |
---|
614 | */ |
---|
615 | sc->slot.quirks |= SDHCI_QUIRK_WAIT_WHILE_BUSY; |
---|
616 | |
---|
617 | /* |
---|
618 | * DMA is not really broken, I just haven't implemented it yet. |
---|
619 | */ |
---|
620 | sc->slot.quirks |= SDHCI_QUIRK_BROKEN_DMA; |
---|
621 | |
---|
622 | /* |
---|
623 | * Set up the hardware and go. Note that this sets many of the |
---|
624 | * slot.host.* fields, so we have to do this before overriding any of |
---|
625 | * those values based on fdt data, below. |
---|
626 | */ |
---|
627 | sdhci_init_slot(dev, &sc->slot, 0); |
---|
628 | |
---|
629 | /* |
---|
630 | * The SDHCI controller doesn't realize it, but we can support 8-bit |
---|
631 | * even though we're not a v3.0 controller. If there's an fdt bus-width |
---|
632 | * property, honor it. |
---|
633 | */ |
---|
634 | if (OF_getencprop(node, "bus-width", &prop, sizeof(prop)) > 0) { |
---|
635 | sc->slot.host.caps &= ~(MMC_CAP_4_BIT_DATA | |
---|
636 | MMC_CAP_8_BIT_DATA); |
---|
637 | switch (prop) { |
---|
638 | case 8: |
---|
639 | sc->slot.host.caps |= MMC_CAP_8_BIT_DATA; |
---|
640 | /* FALLTHROUGH */ |
---|
641 | case 4: |
---|
642 | sc->slot.host.caps |= MMC_CAP_4_BIT_DATA; |
---|
643 | break; |
---|
644 | case 1: |
---|
645 | break; |
---|
646 | default: |
---|
647 | device_printf(dev, "Bad bus-width value %u\n", prop); |
---|
648 | break; |
---|
649 | } |
---|
650 | } |
---|
651 | |
---|
652 | /* |
---|
653 | * If the slot is flagged with the non-removable property, set our flag |
---|
654 | * to always force the SDHCI_CARD_PRESENT bit on. |
---|
655 | */ |
---|
656 | node = ofw_bus_get_node(dev); |
---|
657 | if (OF_hasprop(node, "non-removable")) |
---|
658 | sc->force_card_present = true; |
---|
659 | |
---|
660 | bus_generic_probe(dev); |
---|
661 | bus_generic_attach(dev); |
---|
662 | |
---|
663 | sdhci_start_slot(&sc->slot); |
---|
664 | |
---|
665 | return (0); |
---|
666 | |
---|
667 | fail: |
---|
668 | if (sc->intr_cookie) |
---|
669 | bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie); |
---|
670 | if (sc->irq_res) |
---|
671 | bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); |
---|
672 | if (sc->mem_res) |
---|
673 | bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); |
---|
674 | |
---|
675 | return (err); |
---|
676 | } |
---|
677 | |
---|
678 | static int |
---|
679 | ti_sdhci_probe(device_t dev) |
---|
680 | { |
---|
681 | |
---|
682 | if (!ofw_bus_status_okay(dev)) |
---|
683 | return (ENXIO); |
---|
684 | |
---|
685 | if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { |
---|
686 | device_set_desc(dev, "TI MMCHS (SDHCI 2.0)"); |
---|
687 | return (BUS_PROBE_DEFAULT); |
---|
688 | } |
---|
689 | |
---|
690 | return (ENXIO); |
---|
691 | } |
---|
692 | |
---|
693 | static device_method_t ti_sdhci_methods[] = { |
---|
694 | /* Device interface */ |
---|
695 | DEVMETHOD(device_probe, ti_sdhci_probe), |
---|
696 | DEVMETHOD(device_attach, ti_sdhci_attach), |
---|
697 | DEVMETHOD(device_detach, ti_sdhci_detach), |
---|
698 | |
---|
699 | /* Bus interface */ |
---|
700 | DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), |
---|
701 | DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), |
---|
702 | |
---|
703 | /* MMC bridge interface */ |
---|
704 | DEVMETHOD(mmcbr_update_ios, ti_sdhci_update_ios), |
---|
705 | DEVMETHOD(mmcbr_request, sdhci_generic_request), |
---|
706 | DEVMETHOD(mmcbr_get_ro, ti_sdhci_get_ro), |
---|
707 | DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), |
---|
708 | DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), |
---|
709 | |
---|
710 | /* SDHCI registers accessors */ |
---|
711 | DEVMETHOD(sdhci_read_1, ti_sdhci_read_1), |
---|
712 | DEVMETHOD(sdhci_read_2, ti_sdhci_read_2), |
---|
713 | DEVMETHOD(sdhci_read_4, ti_sdhci_read_4), |
---|
714 | DEVMETHOD(sdhci_read_multi_4, ti_sdhci_read_multi_4), |
---|
715 | DEVMETHOD(sdhci_write_1, ti_sdhci_write_1), |
---|
716 | DEVMETHOD(sdhci_write_2, ti_sdhci_write_2), |
---|
717 | DEVMETHOD(sdhci_write_4, ti_sdhci_write_4), |
---|
718 | DEVMETHOD(sdhci_write_multi_4, ti_sdhci_write_multi_4), |
---|
719 | DEVMETHOD(sdhci_get_card_present, ti_sdhci_get_card_present), |
---|
720 | |
---|
721 | DEVMETHOD_END |
---|
722 | }; |
---|
723 | |
---|
724 | static devclass_t ti_sdhci_devclass; |
---|
725 | |
---|
726 | static driver_t ti_sdhci_driver = { |
---|
727 | "sdhci_ti", |
---|
728 | ti_sdhci_methods, |
---|
729 | sizeof(struct ti_sdhci_softc), |
---|
730 | }; |
---|
731 | |
---|
732 | DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, NULL, |
---|
733 | NULL); |
---|
734 | MODULE_DEPEND(sdhci_ti, sdhci, 1, 1, 1); |
---|
735 | MMC_DECLARE_BRIDGE(sdhci_ti); |
---|