| @@ -1,39 +1,39 @@ | | | @@ -1,39 +1,39 @@ |
1 | /* $NetBSD: sdhc.c,v 1.107 2020/07/15 15:57:52 msaitoh Exp $ */ | | 1 | /* $NetBSD: sdhc.c,v 1.108 2021/03/13 23:26:47 mlelstv 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.107 2020/07/15 15:57:52 msaitoh Exp $"); | | 26 | __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.108 2021/03/13 23:26:47 mlelstv 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/malloc.h> | | 35 | #include <sys/malloc.h> |
36 | #include <sys/systm.h> | | 36 | #include <sys/systm.h> |
37 | #include <sys/mutex.h> | | 37 | #include <sys/mutex.h> |
38 | #include <sys/condvar.h> | | 38 | #include <sys/condvar.h> |
39 | #include <sys/atomic.h> | | 39 | #include <sys/atomic.h> |
| @@ -379,26 +379,28 @@ sdhc_host_found(struct sdhc_softc *sc, b | | | @@ -379,26 +379,28 @@ sdhc_host_found(struct sdhc_softc *sc, b |
379 | caps |= SDHC_ADMA2_SUPP; | | 379 | caps |= SDHC_ADMA2_SUPP; |
380 | sc->sc_caps = caps; | | 380 | sc->sc_caps = caps; |
381 | /* uSDHC has no SDHC_CAPABILITIES2 register */ | | 381 | /* uSDHC has no SDHC_CAPABILITIES2 register */ |
382 | caps2 = sc->sc_caps2 = SDHC_SDR50_SUPP | SDHC_DDR50_SUPP; | | 382 | caps2 = sc->sc_caps2 = SDHC_SDR50_SUPP | SDHC_DDR50_SUPP; |
383 | } else { | | 383 | } else { |
384 | caps = sc->sc_caps = HREAD4(hp, SDHC_CAPABILITIES); | | 384 | caps = sc->sc_caps = HREAD4(hp, SDHC_CAPABILITIES); |
385 | if (hp->specver >= SDHC_SPEC_VERS_300) { | | 385 | if (hp->specver >= SDHC_SPEC_VERS_300) { |
386 | caps2 = sc->sc_caps2 = HREAD4(hp, SDHC_CAPABILITIES2); | | 386 | caps2 = sc->sc_caps2 = HREAD4(hp, SDHC_CAPABILITIES2); |
387 | } else { | | 387 | } else { |
388 | caps2 = sc->sc_caps2 = 0; | | 388 | caps2 = sc->sc_caps2 = 0; |
389 | } | | 389 | } |
390 | } | | 390 | } |
391 | | | 391 | |
| | | 392 | aprint_verbose(", caps <%08x/%08x>", caps, caps2); |
| | | 393 | |
392 | const u_int retuning_mode = (caps2 >> SDHC_RETUNING_MODES_SHIFT) & | | 394 | const u_int retuning_mode = (caps2 >> SDHC_RETUNING_MODES_SHIFT) & |
393 | SDHC_RETUNING_MODES_MASK; | | 395 | SDHC_RETUNING_MODES_MASK; |
394 | if (retuning_mode == SDHC_RETUNING_MODE_1) { | | 396 | if (retuning_mode == SDHC_RETUNING_MODE_1) { |
395 | hp->tuning_timer_count = (caps2 >> SDHC_TIMER_COUNT_SHIFT) & | | 397 | hp->tuning_timer_count = (caps2 >> SDHC_TIMER_COUNT_SHIFT) & |
396 | SDHC_TIMER_COUNT_MASK; | | 398 | SDHC_TIMER_COUNT_MASK; |
397 | if (hp->tuning_timer_count == 0xf) | | 399 | if (hp->tuning_timer_count == 0xf) |
398 | hp->tuning_timer_count = 0; | | 400 | hp->tuning_timer_count = 0; |
399 | if (hp->tuning_timer_count) | | 401 | if (hp->tuning_timer_count) |
400 | hp->tuning_timer_count = | | 402 | hp->tuning_timer_count = |
401 | 1 << (hp->tuning_timer_count - 1); | | 403 | 1 << (hp->tuning_timer_count - 1); |
402 | } | | 404 | } |
403 | | | 405 | |
404 | /* | | 406 | /* |
| @@ -1714,34 +1716,37 @@ sdhc_start_command(struct sdhc_host *hp, | | | @@ -1714,34 +1716,37 @@ sdhc_start_command(struct sdhc_host *hp, |
1714 | aprint_error_dev(sc->sc_dev, | | 1716 | aprint_error_dev(sc->sc_dev, |
1715 | "data not a multiple of %u bytes\n", blksize); | | 1717 | "data not a multiple of %u bytes\n", blksize); |
1716 | return EINVAL; | | 1718 | return EINVAL; |
1717 | } | | 1719 | } |
1718 | } | | 1720 | } |
1719 | | | 1721 | |
1720 | /* Check limit imposed by 9-bit block count. (1.7.2) */ | | 1722 | /* Check limit imposed by 9-bit block count. (1.7.2) */ |
1721 | if (blkcount > SDHC_BLOCK_COUNT_MAX) { | | 1723 | if (blkcount > SDHC_BLOCK_COUNT_MAX) { |
1722 | aprint_error_dev(sc->sc_dev, "too much data\n"); | | 1724 | aprint_error_dev(sc->sc_dev, "too much data\n"); |
1723 | return EINVAL; | | 1725 | return EINVAL; |
1724 | } | | 1726 | } |
1725 | | | 1727 | |
1726 | /* Prepare transfer mode register value. (2.2.5) */ | | 1728 | /* Prepare transfer mode register value. (2.2.5) */ |
1727 | mode = SDHC_BLOCK_COUNT_ENABLE; | | 1729 | mode = 0; |
1728 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) | | 1730 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) |
1729 | mode |= SDHC_READ_MODE; | | 1731 | mode |= SDHC_READ_MODE; |
1730 | if (blkcount > 1) { | | 1732 | if (blkcount > 0) { |
1731 | mode |= SDHC_MULTI_BLOCK_MODE; | | 1733 | mode |= SDHC_BLOCK_COUNT_ENABLE; |
1732 | /* XXX only for memory commands? */ | | 1734 | if (blkcount > 1) { |
1733 | if (!ISSET(sc->sc_flags, SDHC_FLAG_NO_AUTO_STOP)) | | 1735 | mode |= SDHC_MULTI_BLOCK_MODE; |
1734 | mode |= SDHC_AUTO_CMD12_ENABLE; | | 1736 | if (!ISSET(sc->sc_flags, SDHC_FLAG_NO_AUTO_STOP) |
| | | 1737 | && !ISSET(cmd->c_flags, SCF_NO_STOP)) |
| | | 1738 | mode |= SDHC_AUTO_CMD12_ENABLE; |
| | | 1739 | } |
1735 | } | | 1740 | } |
1736 | if (cmd->c_dmamap != NULL && cmd->c_datalen > 0 && | | 1741 | if (cmd->c_dmamap != NULL && cmd->c_datalen > 0 && |
1737 | ISSET(hp->flags, SHF_MODE_DMAEN)) { | | 1742 | ISSET(hp->flags, SHF_MODE_DMAEN)) { |
1738 | mode |= SDHC_DMA_ENABLE; | | 1743 | mode |= SDHC_DMA_ENABLE; |
1739 | } | | 1744 | } |
1740 | | | 1745 | |
1741 | /* | | 1746 | /* |
1742 | * Prepare command register value. (2.2.6) | | 1747 | * Prepare command register value. (2.2.6) |
1743 | */ | | 1748 | */ |
1744 | command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) << SDHC_COMMAND_INDEX_SHIFT; | | 1749 | command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) << SDHC_COMMAND_INDEX_SHIFT; |
1745 | | | 1750 | |
1746 | if (ISSET(cmd->c_flags, SCF_RSP_CRC)) | | 1751 | if (ISSET(cmd->c_flags, SCF_RSP_CRC)) |
1747 | command |= SDHC_CRC_CHECK_ENABLE; | | 1752 | command |= SDHC_CRC_CHECK_ENABLE; |