| @@ -1,39 +1,39 @@ | | | @@ -1,39 +1,39 @@ |
1 | /* $NetBSD: sdhc.c,v 1.55 2015/04/14 18:34:29 bouyer Exp $ */ | | 1 | /* $NetBSD: sdhc.c,v 1.56 2015/05/02 12:10:24 jmcneill Exp $ */ |
2 | /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ | | 2 | /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> | | 5 | * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 18 | */ |
19 | | | 19 | |
20 | /* | | 20 | /* |
21 | * SD Host Controller driver based on the SD Host Controller Standard | | 21 | * SD Host Controller driver based on the SD Host Controller Standard |
22 | * Simplified Specification Version 1.00 (www.sdcard.com). | | 22 | * Simplified Specification Version 1.00 (www.sdcard.com). |
23 | */ | | 23 | */ |
24 | | | 24 | |
25 | #include <sys/cdefs.h> | | 25 | #include <sys/cdefs.h> |
26 | __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.55 2015/04/14 18:34:29 bouyer Exp $"); | | 26 | __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.56 2015/05/02 12:10:24 jmcneill Exp $"); |
27 | | | 27 | |
28 | #ifdef _KERNEL_OPT | | 28 | #ifdef _KERNEL_OPT |
29 | #include "opt_sdmmc.h" | | 29 | #include "opt_sdmmc.h" |
30 | #endif | | 30 | #endif |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/device.h> | | 33 | #include <sys/device.h> |
34 | #include <sys/kernel.h> | | 34 | #include <sys/kernel.h> |
35 | #include <sys/kthread.h> | | 35 | #include <sys/kthread.h> |
36 | #include <sys/malloc.h> | | 36 | #include <sys/malloc.h> |
37 | #include <sys/systm.h> | | 37 | #include <sys/systm.h> |
38 | #include <sys/mutex.h> | | 38 | #include <sys/mutex.h> |
39 | #include <sys/condvar.h> | | 39 | #include <sys/condvar.h> |
| @@ -279,26 +279,30 @@ sdhc_host_found(struct sdhc_softc *sc, b | | | @@ -279,26 +279,30 @@ sdhc_host_found(struct sdhc_softc *sc, b |
279 | switch (SDHC_SPEC_VERSION(sdhcver)) { | | 279 | switch (SDHC_SPEC_VERSION(sdhcver)) { |
280 | case SDHC_SPEC_VERS_100: | | 280 | case SDHC_SPEC_VERS_100: |
281 | aprint_normal("1.0"); | | 281 | aprint_normal("1.0"); |
282 | break; | | 282 | break; |
283 | | | 283 | |
284 | case SDHC_SPEC_VERS_200: | | 284 | case SDHC_SPEC_VERS_200: |
285 | aprint_normal("2.0"); | | 285 | aprint_normal("2.0"); |
286 | break; | | 286 | break; |
287 | | | 287 | |
288 | case SDHC_SPEC_VERS_300: | | 288 | case SDHC_SPEC_VERS_300: |
289 | aprint_normal("3.0"); | | 289 | aprint_normal("3.0"); |
290 | break; | | 290 | break; |
291 | | | 291 | |
| | | 292 | case SDHC_SPEC_VERS_400: |
| | | 293 | aprint_normal("4.0"); |
| | | 294 | break; |
| | | 295 | |
292 | default: | | 296 | default: |
293 | aprint_normal("unknown version(0x%x)", | | 297 | aprint_normal("unknown version(0x%x)", |
294 | SDHC_SPEC_VERSION(sdhcver)); | | 298 | SDHC_SPEC_VERSION(sdhcver)); |
295 | break; | | 299 | break; |
296 | } | | 300 | } |
297 | aprint_normal(", rev.%u\n", SDHC_VENDOR_VERSION(sdhcver)); | | 301 | aprint_normal(", rev.%u\n", SDHC_VENDOR_VERSION(sdhcver)); |
298 | | | 302 | |
299 | /* | | 303 | /* |
300 | * Reset the host controller and enable interrupts. | | 304 | * Reset the host controller and enable interrupts. |
301 | */ | | 305 | */ |
302 | (void)sdhc_host_reset(hp); | | 306 | (void)sdhc_host_reset(hp); |
303 | | | 307 | |
304 | /* Determine host capabilities. */ | | 308 | /* Determine host capabilities. */ |
| @@ -319,32 +323,33 @@ sdhc_host_found(struct sdhc_softc *sc, b | | | @@ -319,32 +323,33 @@ sdhc_host_found(struct sdhc_softc *sc, b |
319 | (ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA && | | 323 | (ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA && |
320 | ISSET(caps, SDHC_DMA_SUPPORT)))) { | | 324 | ISSET(caps, SDHC_DMA_SUPPORT)))) { |
321 | SET(hp->flags, SHF_USE_DMA); | | 325 | SET(hp->flags, SHF_USE_DMA); |
322 | if (!ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA) || | | 326 | if (!ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA) || |
323 | ISSET(sc->sc_flags, SDHC_FLAG_EXTDMA_DMAEN)) | | 327 | ISSET(sc->sc_flags, SDHC_FLAG_EXTDMA_DMAEN)) |
324 | SET(hp->flags, SHF_MODE_DMAEN); | | 328 | SET(hp->flags, SHF_MODE_DMAEN); |
325 | | | 329 | |
326 | aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); | | 330 | aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); |
327 | } | | 331 | } |
328 | | | 332 | |
329 | /* | | 333 | /* |
330 | * Determine the base clock frequency. (2.2.24) | | 334 | * Determine the base clock frequency. (2.2.24) |
331 | */ | | 335 | */ |
332 | if (hp->specver == SDHC_SPEC_VERS_300) { | | 336 | if (hp->specver >= SDHC_SPEC_VERS_300) { |
333 | hp->clkbase = SDHC_BASE_V3_FREQ_KHZ(caps); | | 337 | hp->clkbase = SDHC_BASE_V3_FREQ_KHZ(caps); |
334 | } else { | | 338 | } else { |
335 | hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); | | 339 | hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); |
336 | } | | 340 | } |
337 | if (hp->clkbase == 0) { | | 341 | if (hp->clkbase == 0 || |
| | | 342 | ISSET(sc->sc_flags, SDHC_FLAG_NO_CLKBASE)) { |
338 | if (sc->sc_clkbase == 0) { | | 343 | if (sc->sc_clkbase == 0) { |
339 | /* The attachment driver must tell us. */ | | 344 | /* The attachment driver must tell us. */ |
340 | aprint_error_dev(sc->sc_dev, | | 345 | aprint_error_dev(sc->sc_dev, |
341 | "unknown base clock frequency\n"); | | 346 | "unknown base clock frequency\n"); |
342 | goto err; | | 347 | goto err; |
343 | } | | 348 | } |
344 | hp->clkbase = sc->sc_clkbase; | | 349 | hp->clkbase = sc->sc_clkbase; |
345 | } | | 350 | } |
346 | if (hp->clkbase < 10000 || hp->clkbase > 10000 * 256) { | | 351 | if (hp->clkbase < 10000 || hp->clkbase > 10000 * 256) { |
347 | /* SDHC 1.0 supports only 10-63 MHz. */ | | 352 | /* SDHC 1.0 supports only 10-63 MHz. */ |
348 | aprint_error_dev(sc->sc_dev, | | 353 | aprint_error_dev(sc->sc_dev, |
349 | "base clock frequency out of range: %u MHz\n", | | 354 | "base clock frequency out of range: %u MHz\n", |
350 | hp->clkbase / 1000); | | 355 | hp->clkbase / 1000); |
| @@ -414,27 +419,27 @@ sdhc_host_found(struct sdhc_softc *sc, b | | | @@ -414,27 +419,27 @@ sdhc_host_found(struct sdhc_softc *sc, b |
414 | memset(&saa, 0, sizeof(saa)); | | 419 | memset(&saa, 0, sizeof(saa)); |
415 | saa.saa_busname = "sdmmc"; | | 420 | saa.saa_busname = "sdmmc"; |
416 | saa.saa_sct = &sdhc_functions; | | 421 | saa.saa_sct = &sdhc_functions; |
417 | saa.saa_sch = hp; | | 422 | saa.saa_sch = hp; |
418 | saa.saa_dmat = hp->dmat; | | 423 | saa.saa_dmat = hp->dmat; |
419 | saa.saa_clkmax = hp->clkbase; | | 424 | saa.saa_clkmax = hp->clkbase; |
420 | if (ISSET(sc->sc_flags, SDHC_FLAG_HAVE_CGM)) | | 425 | if (ISSET(sc->sc_flags, SDHC_FLAG_HAVE_CGM)) |
421 | saa.saa_clkmin = hp->clkbase / 256 / 2046; | | 426 | saa.saa_clkmin = hp->clkbase / 256 / 2046; |
422 | else if (ISSET(sc->sc_flags, SDHC_FLAG_HAVE_DVS)) | | 427 | else if (ISSET(sc->sc_flags, SDHC_FLAG_HAVE_DVS)) |
423 | saa.saa_clkmin = hp->clkbase / 256 / 16; | | 428 | saa.saa_clkmin = hp->clkbase / 256 / 16; |
424 | else if (hp->sc->sc_clkmsk != 0) | | 429 | else if (hp->sc->sc_clkmsk != 0) |
425 | saa.saa_clkmin = hp->clkbase / (hp->sc->sc_clkmsk >> | | 430 | saa.saa_clkmin = hp->clkbase / (hp->sc->sc_clkmsk >> |
426 | (ffs(hp->sc->sc_clkmsk) - 1)); | | 431 | (ffs(hp->sc->sc_clkmsk) - 1)); |
427 | else if (hp->specver == SDHC_SPEC_VERS_300) | | 432 | else if (hp->specver >= SDHC_SPEC_VERS_300) |
428 | saa.saa_clkmin = hp->clkbase / 0x3ff; | | 433 | saa.saa_clkmin = hp->clkbase / 0x3ff; |
429 | else | | 434 | else |
430 | saa.saa_clkmin = hp->clkbase / 256; | | 435 | saa.saa_clkmin = hp->clkbase / 256; |
431 | saa.saa_caps = SMC_CAPS_4BIT_MODE|SMC_CAPS_AUTO_STOP; | | 436 | saa.saa_caps = SMC_CAPS_4BIT_MODE|SMC_CAPS_AUTO_STOP; |
432 | if (ISSET(sc->sc_flags, SDHC_FLAG_8BIT_MODE)) | | 437 | if (ISSET(sc->sc_flags, SDHC_FLAG_8BIT_MODE)) |
433 | saa.saa_caps |= SMC_CAPS_8BIT_MODE; | | 438 | saa.saa_caps |= SMC_CAPS_8BIT_MODE; |
434 | if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) | | 439 | if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) |
435 | saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED; | | 440 | saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED; |
436 | if (ISSET(hp->flags, SHF_USE_DMA)) { | | 441 | if (ISSET(hp->flags, SHF_USE_DMA)) { |
437 | saa.saa_caps |= SMC_CAPS_DMA; | | 442 | saa.saa_caps |= SMC_CAPS_DMA; |
438 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) | | 443 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) |
439 | saa.saa_caps |= SMC_CAPS_MULTI_SEG_DMA; | | 444 | saa.saa_caps |= SMC_CAPS_MULTI_SEG_DMA; |
440 | } | | 445 | } |
| @@ -817,27 +822,27 @@ sdhc_clock_divisor(struct sdhc_host *hp, | | | @@ -817,27 +822,27 @@ sdhc_clock_divisor(struct sdhc_host *hp, |
817 | roundup |= dvs & 1; | | 822 | roundup |= dvs & 1; |
818 | } | | 823 | } |
819 | /* No divisor found. */ | | 824 | /* No divisor found. */ |
820 | return false; | | 825 | return false; |
821 | } | | 826 | } |
822 | if (hp->sc->sc_clkmsk != 0) { | | 827 | if (hp->sc->sc_clkmsk != 0) { |
823 | div = howmany(hp->clkbase, freq); | | 828 | div = howmany(hp->clkbase, freq); |
824 | if (div > (hp->sc->sc_clkmsk >> (ffs(hp->sc->sc_clkmsk) - 1))) | | 829 | if (div > (hp->sc->sc_clkmsk >> (ffs(hp->sc->sc_clkmsk) - 1))) |
825 | return false; | | 830 | return false; |
826 | *divp = div << (ffs(hp->sc->sc_clkmsk) - 1); | | 831 | *divp = div << (ffs(hp->sc->sc_clkmsk) - 1); |
827 | //freq = hp->clkbase / div; | | 832 | //freq = hp->clkbase / div; |
828 | return true; | | 833 | return true; |
829 | } | | 834 | } |
830 | if (hp->specver == SDHC_SPEC_VERS_300) { | | 835 | if (hp->specver >= SDHC_SPEC_VERS_300) { |
831 | div = howmany(hp->clkbase, freq); | | 836 | div = howmany(hp->clkbase, freq); |
832 | div = div > 1 ? howmany(div, 2) : 0; | | 837 | div = div > 1 ? howmany(div, 2) : 0; |
833 | if (div > 0x3ff) | | 838 | if (div > 0x3ff) |
834 | return false; | | 839 | return false; |
835 | *divp = (((div >> 8) & SDHC_SDCLK_XDIV_MASK) | | 840 | *divp = (((div >> 8) & SDHC_SDCLK_XDIV_MASK) |
836 | << SDHC_SDCLK_XDIV_SHIFT) | | | 841 | << SDHC_SDCLK_XDIV_SHIFT) | |
837 | (((div >> 0) & SDHC_SDCLK_DIV_MASK) | | 842 | (((div >> 0) & SDHC_SDCLK_DIV_MASK) |
838 | << SDHC_SDCLK_DIV_SHIFT); | | 843 | << SDHC_SDCLK_DIV_SHIFT); |
839 | //freq = hp->clkbase / div; | | 844 | //freq = hp->clkbase / div; |
840 | return true; | | 845 | return true; |
841 | } else { | | 846 | } else { |
842 | for (div = 1; div <= 256; div *= 2) { | | 847 | for (div = 1; div <= 256; div *= 2) { |
843 | if ((hp->clkbase / div) <= freq) { | | 848 | if ((hp->clkbase / div) <= freq) { |