Add support for DDR50 transfer modes.diff -r1.75 -r1.76 src/sys/dev/sdmmc/sdhc.c
(jmcneill)
--- src/sys/dev/sdmmc/sdhc.c 2015/08/03 05:24:37 1.75
+++ src/sys/dev/sdmmc/sdhc.c 2015/08/03 10:08:51 1.76
@@ -1,39 +1,39 @@ | @@ -1,39 +1,39 @@ | |||
1 | /* $NetBSD: sdhc.c,v 1.75 2015/08/03 05:24:37 mlelstv Exp $ */ | 1 | /* $NetBSD: sdhc.c,v 1.76 2015/08/03 10:08:51 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.75 2015/08/03 05:24:37 mlelstv Exp $"); | 26 | __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.76 2015/08/03 10:08:51 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/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 | 39 | |||
@@ -164,27 +164,27 @@ hwrite2(struct sdhc_host *hp, bus_size_t | @@ -164,27 +164,27 @@ hwrite2(struct sdhc_host *hp, bus_size_t | |||
164 | do if (bits) HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits)); while (0) | 164 | do if (bits) HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits)); while (0) | |
165 | #define HSET2(hp, reg, bits) \ | 165 | #define HSET2(hp, reg, bits) \ | |
166 | do if (bits) HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits)); while (0) | 166 | do if (bits) HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits)); while (0) | |
167 | #define HSET4(hp, reg, bits) \ | 167 | #define HSET4(hp, reg, bits) \ | |
168 | do if (bits) HWRITE4((hp), (reg), HREAD4((hp), (reg)) | (bits)); while (0) | 168 | do if (bits) HWRITE4((hp), (reg), HREAD4((hp), (reg)) | (bits)); while (0) | |
169 | 169 | |||
170 | static int sdhc_host_reset(sdmmc_chipset_handle_t); | 170 | static int sdhc_host_reset(sdmmc_chipset_handle_t); | |
171 | static int sdhc_host_reset1(sdmmc_chipset_handle_t); | 171 | static int sdhc_host_reset1(sdmmc_chipset_handle_t); | |
172 | static uint32_t sdhc_host_ocr(sdmmc_chipset_handle_t); | 172 | static uint32_t sdhc_host_ocr(sdmmc_chipset_handle_t); | |
173 | static int sdhc_host_maxblklen(sdmmc_chipset_handle_t); | 173 | static int sdhc_host_maxblklen(sdmmc_chipset_handle_t); | |
174 | static int sdhc_card_detect(sdmmc_chipset_handle_t); | 174 | static int sdhc_card_detect(sdmmc_chipset_handle_t); | |
175 | static int sdhc_write_protect(sdmmc_chipset_handle_t); | 175 | static int sdhc_write_protect(sdmmc_chipset_handle_t); | |
176 | static int sdhc_bus_power(sdmmc_chipset_handle_t, uint32_t); | 176 | static int sdhc_bus_power(sdmmc_chipset_handle_t, uint32_t); | |
177 | static int sdhc_bus_clock(sdmmc_chipset_handle_t, int); | 177 | static int sdhc_bus_clock_ddr(sdmmc_chipset_handle_t, int, bool); | |
178 | static int sdhc_bus_width(sdmmc_chipset_handle_t, int); | 178 | static int sdhc_bus_width(sdmmc_chipset_handle_t, int); | |
179 | static int sdhc_bus_rod(sdmmc_chipset_handle_t, int); | 179 | static int sdhc_bus_rod(sdmmc_chipset_handle_t, int); | |
180 | static void sdhc_card_enable_intr(sdmmc_chipset_handle_t, int); | 180 | static void sdhc_card_enable_intr(sdmmc_chipset_handle_t, int); | |
181 | static void sdhc_card_intr_ack(sdmmc_chipset_handle_t); | 181 | static void sdhc_card_intr_ack(sdmmc_chipset_handle_t); | |
182 | static void sdhc_exec_command(sdmmc_chipset_handle_t, | 182 | static void sdhc_exec_command(sdmmc_chipset_handle_t, | |
183 | struct sdmmc_command *); | 183 | struct sdmmc_command *); | |
184 | static int sdhc_signal_voltage(sdmmc_chipset_handle_t, int); | 184 | static int sdhc_signal_voltage(sdmmc_chipset_handle_t, int); | |
185 | static int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); | 185 | static int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); | |
186 | static int sdhc_wait_state(struct sdhc_host *, uint32_t, uint32_t); | 186 | static int sdhc_wait_state(struct sdhc_host *, uint32_t, uint32_t); | |
187 | static int sdhc_soft_reset(struct sdhc_host *, int); | 187 | static int sdhc_soft_reset(struct sdhc_host *, int); | |
188 | static int sdhc_wait_intr(struct sdhc_host *, int, int); | 188 | static int sdhc_wait_intr(struct sdhc_host *, int, int); | |
189 | static void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *); | 189 | static void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *); | |
190 | static int sdhc_transfer_data_dma(struct sdhc_host *, struct sdmmc_command *); | 190 | static int sdhc_transfer_data_dma(struct sdhc_host *, struct sdmmc_command *); | |
@@ -200,39 +200,40 @@ static struct sdmmc_chip_functions sdhc_ | @@ -200,39 +200,40 @@ static struct sdmmc_chip_functions sdhc_ | |||
200 | 200 | |||
201 | /* host controller capabilities */ | 201 | /* host controller capabilities */ | |
202 | .host_ocr = sdhc_host_ocr, | 202 | .host_ocr = sdhc_host_ocr, | |
203 | .host_maxblklen = sdhc_host_maxblklen, | 203 | .host_maxblklen = sdhc_host_maxblklen, | |
204 | 204 | |||
205 | /* card detection */ | 205 | /* card detection */ | |
206 | .card_detect = sdhc_card_detect, | 206 | .card_detect = sdhc_card_detect, | |
207 | 207 | |||
208 | /* write protect */ | 208 | /* write protect */ | |
209 | .write_protect = sdhc_write_protect, | 209 | .write_protect = sdhc_write_protect, | |
210 | 210 | |||
211 | /* bus power, clock frequency, width and ROD(OpenDrain/PushPull) */ | 211 | /* bus power, clock frequency, width and ROD(OpenDrain/PushPull) */ | |
212 | .bus_power = sdhc_bus_power, | 212 | .bus_power = sdhc_bus_power, | |
213 | .bus_clock = sdhc_bus_clock, | 213 | .bus_clock = NULL, /* see sdhc_bus_clock_ddr */ | |
214 | .bus_width = sdhc_bus_width, | 214 | .bus_width = sdhc_bus_width, | |
215 | .bus_rod = sdhc_bus_rod, | 215 | .bus_rod = sdhc_bus_rod, | |
216 | 216 | |||
217 | /* command execution */ | 217 | /* command execution */ | |
218 | .exec_command = sdhc_exec_command, | 218 | .exec_command = sdhc_exec_command, | |
219 | 219 | |||
220 | /* card interrupt */ | 220 | /* card interrupt */ | |
221 | .card_enable_intr = sdhc_card_enable_intr, | 221 | .card_enable_intr = sdhc_card_enable_intr, | |
222 | .card_intr_ack = sdhc_card_intr_ack, | 222 | .card_intr_ack = sdhc_card_intr_ack, | |
223 | 223 | |||
224 | /* UHS functions */ | 224 | /* UHS functions */ | |
225 | .signal_voltage = sdhc_signal_voltage, | 225 | .signal_voltage = sdhc_signal_voltage, | |
226 | .bus_clock_ddr = sdhc_bus_clock_ddr, | |||
226 | }; | 227 | }; | |
227 | 228 | |||
228 | static int | 229 | static int | |
229 | sdhc_cfprint(void *aux, const char *pnp) | 230 | sdhc_cfprint(void *aux, const char *pnp) | |
230 | { | 231 | { | |
231 | const struct sdmmcbus_attach_args * const saa = aux; | 232 | const struct sdmmcbus_attach_args * const saa = aux; | |
232 | const struct sdhc_host * const hp = saa->saa_sch; | 233 | const struct sdhc_host * const hp = saa->saa_sch; | |
233 | 234 | |||
234 | if (pnp) { | 235 | if (pnp) { | |
235 | aprint_normal("sdmmc at %s", pnp); | 236 | aprint_normal("sdmmc at %s", pnp); | |
236 | } | 237 | } | |
237 | for (size_t host = 0; host < hp->sc->sc_nhosts; host++) { | 238 | for (size_t host = 0; host < hp->sc->sc_nhosts; host++) { | |
238 | if (hp->sc->sc_host[host] == hp) { | 239 | if (hp->sc->sc_host[host] == hp) { | |
@@ -408,34 +409,34 @@ sdhc_host_found(struct sdhc_softc *sc, b | @@ -408,34 +409,34 @@ sdhc_host_found(struct sdhc_softc *sc, b | |||
408 | 409 | |||
409 | /* | 410 | /* | |
410 | * Determine SD bus voltage levels supported by the controller. | 411 | * Determine SD bus voltage levels supported by the controller. | |
411 | */ | 412 | */ | |
412 | aprint_normal(","); | 413 | aprint_normal(","); | |
413 | if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) { | 414 | if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) { | |
414 | SET(hp->ocr, MMC_OCR_HCS); | 415 | SET(hp->ocr, MMC_OCR_HCS); | |
415 | aprint_normal(" HS"); | 416 | aprint_normal(" HS"); | |
416 | } | 417 | } | |
417 | if (ISSET(caps2, SDHC_SDR50_SUPP)) { | 418 | if (ISSET(caps2, SDHC_SDR50_SUPP)) { | |
418 | SET(hp->ocr, MMC_OCR_S18A); | 419 | SET(hp->ocr, MMC_OCR_S18A); | |
419 | aprint_normal(" SDR50"); | 420 | aprint_normal(" SDR50"); | |
420 | } | 421 | } | |
421 | if (ISSET(caps2, SDHC_SDR104_SUPP)) { | |||
422 | SET(hp->ocr, MMC_OCR_S18A); | |||
423 | aprint_normal(" SDR104"); | |||
424 | } | |||
425 | if (ISSET(caps2, SDHC_DDR50_SUPP)) { | 422 | if (ISSET(caps2, SDHC_DDR50_SUPP)) { | |
426 | SET(hp->ocr, MMC_OCR_S18A); | 423 | SET(hp->ocr, MMC_OCR_S18A); | |
427 | aprint_normal(" DDR50"); | 424 | aprint_normal(" DDR50"); | |
428 | } | 425 | } | |
426 | if (ISSET(caps2, SDHC_SDR104_SUPP)) { | |||
427 | SET(hp->ocr, MMC_OCR_S18A); | |||
428 | aprint_normal(" SDR104 HS200"); | |||
429 | } | |||
429 | if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) { | 430 | if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) { | |
430 | SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V); | 431 | SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V); | |
431 | aprint_normal(" 1.8V"); | 432 | aprint_normal(" 1.8V"); | |
432 | } | 433 | } | |
433 | if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V)) { | 434 | if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V)) { | |
434 | SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V); | 435 | SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V); | |
435 | aprint_normal(" 3.0V"); | 436 | aprint_normal(" 3.0V"); | |
436 | } | 437 | } | |
437 | if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V)) { | 438 | if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V)) { | |
438 | SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V); | 439 | SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V); | |
439 | aprint_normal(" 3.3V"); | 440 | aprint_normal(" 3.3V"); | |
440 | } | 441 | } | |
441 | 442 | |||
@@ -524,26 +525,34 @@ adma_done: | @@ -524,26 +525,34 @@ adma_done: | |||
524 | saa.saa_clkmin = hp->clkbase / 256 / 16; | 525 | saa.saa_clkmin = hp->clkbase / 256 / 16; | |
525 | else if (hp->sc->sc_clkmsk != 0) | 526 | else if (hp->sc->sc_clkmsk != 0) | |
526 | saa.saa_clkmin = hp->clkbase / (hp->sc->sc_clkmsk >> | 527 | saa.saa_clkmin = hp->clkbase / (hp->sc->sc_clkmsk >> | |
527 | (ffs(hp->sc->sc_clkmsk) - 1)); | 528 | (ffs(hp->sc->sc_clkmsk) - 1)); | |
528 | else if (hp->specver >= SDHC_SPEC_VERS_300) | 529 | else if (hp->specver >= SDHC_SPEC_VERS_300) | |
529 | saa.saa_clkmin = hp->clkbase / 0x3ff; | 530 | saa.saa_clkmin = hp->clkbase / 0x3ff; | |
530 | else | 531 | else | |
531 | saa.saa_clkmin = hp->clkbase / 256; | 532 | saa.saa_clkmin = hp->clkbase / 256; | |
532 | saa.saa_caps = SMC_CAPS_4BIT_MODE|SMC_CAPS_AUTO_STOP; | 533 | saa.saa_caps = SMC_CAPS_4BIT_MODE|SMC_CAPS_AUTO_STOP; | |
533 | if (ISSET(sc->sc_flags, SDHC_FLAG_8BIT_MODE)) | 534 | if (ISSET(sc->sc_flags, SDHC_FLAG_8BIT_MODE)) | |
534 | saa.saa_caps |= SMC_CAPS_8BIT_MODE; | 535 | saa.saa_caps |= SMC_CAPS_8BIT_MODE; | |
535 | if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) | 536 | if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) | |
536 | saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED; | 537 | saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED; | |
538 | if (ISSET(caps2, SDHC_SDR104_SUPP)) | |||
539 | saa.saa_caps |= SMC_CAPS_UHS_SDR104 | | |||
540 | SMC_CAPS_UHS_SDR50 | | |||
541 | SMC_CAPS_MMC_HS200; | |||
542 | if (ISSET(caps2, SDHC_SDR50_SUPP)) | |||
543 | saa.saa_caps |= SMC_CAPS_UHS_SDR50; | |||
544 | if (ISSET(caps2, SDHC_DDR50_SUPP)) | |||
545 | saa.saa_caps |= SMC_CAPS_UHS_DDR50; | |||
537 | if (ISSET(hp->flags, SHF_USE_DMA)) { | 546 | if (ISSET(hp->flags, SHF_USE_DMA)) { | |
538 | saa.saa_caps |= SMC_CAPS_DMA; | 547 | saa.saa_caps |= SMC_CAPS_DMA; | |
539 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) | 548 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) | |
540 | saa.saa_caps |= SMC_CAPS_MULTI_SEG_DMA; | 549 | saa.saa_caps |= SMC_CAPS_MULTI_SEG_DMA; | |
541 | } | 550 | } | |
542 | if (ISSET(sc->sc_flags, SDHC_FLAG_SINGLE_ONLY)) | 551 | if (ISSET(sc->sc_flags, SDHC_FLAG_SINGLE_ONLY)) | |
543 | saa.saa_caps |= SMC_CAPS_SINGLE_ONLY; | 552 | saa.saa_caps |= SMC_CAPS_SINGLE_ONLY; | |
544 | hp->sdmmc = config_found(sc->sc_dev, &saa, sdhc_cfprint); | 553 | hp->sdmmc = config_found(sc->sc_dev, &saa, sdhc_cfprint); | |
545 | 554 | |||
546 | return 0; | 555 | return 0; | |
547 | 556 | |||
548 | err: | 557 | err: | |
549 | cv_destroy(&hp->intr_cv); | 558 | cv_destroy(&hp->intr_cv); | |
@@ -954,27 +963,27 @@ sdhc_clock_divisor(struct sdhc_host *hp, | @@ -954,27 +963,27 @@ sdhc_clock_divisor(struct sdhc_host *hp, | |||
954 | } | 963 | } | |
955 | /* No divisor found. */ | 964 | /* No divisor found. */ | |
956 | return false; | 965 | return false; | |
957 | } | 966 | } | |
958 | /* No divisor found. */ | 967 | /* No divisor found. */ | |
959 | return false; | 968 | return false; | |
960 | } | 969 | } | |
961 | 970 | |||
962 | /* | 971 | /* | |
963 | * Set or change SDCLK frequency or disable the SD clock. | 972 | * Set or change SDCLK frequency or disable the SD clock. | |
964 | * Return zero on success. | 973 | * Return zero on success. | |
965 | */ | 974 | */ | |
966 | static int | 975 | static int | |
967 | sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) | 976 | sdhc_bus_clock_ddr(sdmmc_chipset_handle_t sch, int freq, bool ddr) | |
968 | { | 977 | { | |
969 | struct sdhc_host *hp = (struct sdhc_host *)sch; | 978 | struct sdhc_host *hp = (struct sdhc_host *)sch; | |
970 | u_int div; | 979 | u_int div; | |
971 | u_int timo; | 980 | u_int timo; | |
972 | int16_t reg; | 981 | int16_t reg; | |
973 | int error = 0; | 982 | int error = 0; | |
974 | bool present __diagused; | 983 | bool present __diagused; | |
975 | 984 | |||
976 | mutex_enter(&hp->intr_lock); | 985 | mutex_enter(&hp->intr_lock); | |
977 | 986 | |||
978 | #ifdef DIAGNOSTIC | 987 | #ifdef DIAGNOSTIC | |
979 | present = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK); | 988 | present = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK); | |
980 | 989 | |||
@@ -997,34 +1006,39 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc | @@ -997,34 +1006,39 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc | |||
997 | if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { | 1006 | if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { | |
998 | HCLR4(hp, SDHC_CLOCK_CTL, 0xfff8); | 1007 | HCLR4(hp, SDHC_CLOCK_CTL, 0xfff8); | |
999 | if (freq == SDMMC_SDCLK_OFF) { | 1008 | if (freq == SDMMC_SDCLK_OFF) { | |
1000 | HSET4(hp, SDHC_CLOCK_CTL, 0x80f0); | 1009 | HSET4(hp, SDHC_CLOCK_CTL, 0x80f0); | |
1001 | goto out; | 1010 | goto out; | |
1002 | } | 1011 | } | |
1003 | } else { | 1012 | } else { | |
1004 | HCLR2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE); | 1013 | HCLR2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE); | |
1005 | if (freq == SDMMC_SDCLK_OFF) | 1014 | if (freq == SDMMC_SDCLK_OFF) | |
1006 | goto out; | 1015 | goto out; | |
1007 | } | 1016 | } | |
1008 | 1017 | |||
1009 | if (hp->specver >= SDHC_SPEC_VERS_300) { | 1018 | if (hp->specver >= SDHC_SPEC_VERS_300) { | |
1010 | /* XXX DDR */ | |||
1011 | HCLR2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_MASK); | 1019 | HCLR2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_MASK); | |
1012 | if (freq > 100000) { | 1020 | if (freq > 100000) { | |
1013 | HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR104); | 1021 | HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR104); | |
1014 | } else if (freq > 50000) { | 1022 | } else if (freq > 50000) { | |
1015 | HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR50); | 1023 | HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR50); | |
1016 | } else if (freq > 25000) { | 1024 | } else if (freq > 25000) { | |
1017 | HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR25); | 1025 | if (ddr) { | |
1026 | HSET2(hp, SDHC_HOST_CTL2, | |||
1027 | SDHC_UHS_MODE_SELECT_DDR50); | |||
1028 | } else { | |||
1029 | HSET2(hp, SDHC_HOST_CTL2, | |||
1030 | SDHC_UHS_MODE_SELECT_SDR25); | |||
1031 | } | |||
1018 | } else if (freq > 400) { | 1032 | } else if (freq > 400) { | |
1019 | HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12); | 1033 | HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12); | |
1020 | } | 1034 | } | |
1021 | } | 1035 | } | |
1022 | 1036 | |||
1023 | /* | 1037 | /* | |
1024 | * Set the minimum base clock frequency divisor. | 1038 | * Set the minimum base clock frequency divisor. | |
1025 | */ | 1039 | */ | |
1026 | if (!sdhc_clock_divisor(hp, freq, &div)) { | 1040 | if (!sdhc_clock_divisor(hp, freq, &div)) { | |
1027 | /* Invalid base clock frequency or `freq' value. */ | 1041 | /* Invalid base clock frequency or `freq' value. */ | |
1028 | aprint_error_dev(hp->sc->sc_dev, | 1042 | aprint_error_dev(hp->sc->sc_dev, | |
1029 | "Invalid bus clock %d kHz\n", freq); | 1043 | "Invalid bus clock %d kHz\n", freq); | |
1030 | error = EINVAL; | 1044 | error = EINVAL; |
--- src/sys/dev/sdmmc/sdmmc.c 2015/08/03 05:32:50 1.28
+++ src/sys/dev/sdmmc/sdmmc.c 2015/08/03 10:08:51 1.29
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sdmmc.c,v 1.28 2015/08/03 05:32:50 mlelstv Exp $ */ | 1 | /* $NetBSD: sdmmc.c,v 1.29 2015/08/03 10:08:51 jmcneill Exp $ */ | |
2 | /* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */ | 2 | /* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg 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 | |
@@ -39,27 +39,27 @@ | @@ -39,27 +39,27 @@ | |||
39 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 39 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
40 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 40 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
42 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 42 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
43 | */ | 43 | */ | |
44 | 44 | |||
45 | /* | 45 | /* | |
46 | * Host controller independent SD/MMC bus driver based on information | 46 | * Host controller independent SD/MMC bus driver based on information | |
47 | * from SanDisk SD Card Product Manual Revision 2.2 (SanDisk), SDIO | 47 | * from SanDisk SD Card Product Manual Revision 2.2 (SanDisk), SDIO | |
48 | * Simple Specification Version 1.0 (SDIO) and the Linux "mmc" driver. | 48 | * Simple Specification Version 1.0 (SDIO) and the Linux "mmc" driver. | |
49 | */ | 49 | */ | |
50 | 50 | |||
51 | #include <sys/cdefs.h> | 51 | #include <sys/cdefs.h> | |
52 | __KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.28 2015/08/03 05:32:50 mlelstv Exp $"); | 52 | __KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.29 2015/08/03 10:08:51 jmcneill Exp $"); | |
53 | 53 | |||
54 | #ifdef _KERNEL_OPT | 54 | #ifdef _KERNEL_OPT | |
55 | #include "opt_sdmmc.h" | 55 | #include "opt_sdmmc.h" | |
56 | #endif | 56 | #endif | |
57 | 57 | |||
58 | #include <sys/param.h> | 58 | #include <sys/param.h> | |
59 | #include <sys/device.h> | 59 | #include <sys/device.h> | |
60 | #include <sys/kernel.h> | 60 | #include <sys/kernel.h> | |
61 | #include <sys/kthread.h> | 61 | #include <sys/kthread.h> | |
62 | #include <sys/malloc.h> | 62 | #include <sys/malloc.h> | |
63 | #include <sys/proc.h> | 63 | #include <sys/proc.h> | |
64 | #include <sys/systm.h> | 64 | #include <sys/systm.h> | |
65 | #include <sys/callout.h> | 65 | #include <sys/callout.h> | |
@@ -513,27 +513,28 @@ sdmmc_enable(struct sdmmc_softc *sc) | @@ -513,27 +513,28 @@ sdmmc_enable(struct sdmmc_softc *sc) | |||
513 | * Calculate the equivalent of the card OCR from the host | 513 | * Calculate the equivalent of the card OCR from the host | |
514 | * capabilities and select the maximum supported bus voltage. | 514 | * capabilities and select the maximum supported bus voltage. | |
515 | */ | 515 | */ | |
516 | error = sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, | 516 | error = sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, | |
517 | sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch)); | 517 | sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch)); | |
518 | if (error) { | 518 | if (error) { | |
519 | aprint_error_dev(sc->sc_dev, "couldn't supply bus power\n"); | 519 | aprint_error_dev(sc->sc_dev, "couldn't supply bus power\n"); | |
520 | goto out; | 520 | goto out; | |
521 | } | 521 | } | |
522 | 522 | |||
523 | /* | 523 | /* | |
524 | * Select the minimum clock frequency. | 524 | * Select the minimum clock frequency. | |
525 | */ | 525 | */ | |
526 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_400K); | 526 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_400K, | |
527 | false); | |||
527 | if (error) { | 528 | if (error) { | |
528 | aprint_error_dev(sc->sc_dev, "couldn't supply clock\n"); | 529 | aprint_error_dev(sc->sc_dev, "couldn't supply clock\n"); | |
529 | goto out; | 530 | goto out; | |
530 | } | 531 | } | |
531 | 532 | |||
532 | /* XXX wait for card to power up */ | 533 | /* XXX wait for card to power up */ | |
533 | sdmmc_delay(100000); | 534 | sdmmc_delay(100000); | |
534 | 535 | |||
535 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { | 536 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { | |
536 | /* Initialize SD I/O card function(s). */ | 537 | /* Initialize SD I/O card function(s). */ | |
537 | error = sdmmc_io_enable(sc); | 538 | error = sdmmc_io_enable(sc); | |
538 | if (error) { | 539 | if (error) { | |
539 | DPRINTF(1, ("%s: sdmmc_io_enable failed %d\n", DEVNAME(sc), error)); | 540 | DPRINTF(1, ("%s: sdmmc_io_enable failed %d\n", DEVNAME(sc), error)); | |
@@ -559,27 +560,28 @@ out: | @@ -559,27 +560,28 @@ out: | |||
559 | 560 | |||
560 | static void | 561 | static void | |
561 | sdmmc_disable(struct sdmmc_softc *sc) | 562 | sdmmc_disable(struct sdmmc_softc *sc) | |
562 | { | 563 | { | |
563 | /* XXX complete commands if card is still present. */ | 564 | /* XXX complete commands if card is still present. */ | |
564 | 565 | |||
565 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { | 566 | if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) { | |
566 | /* Make sure no card is still selected. */ | 567 | /* Make sure no card is still selected. */ | |
567 | (void)sdmmc_select_card(sc, NULL); | 568 | (void)sdmmc_select_card(sc, NULL); | |
568 | } | 569 | } | |
569 | 570 | |||
570 | /* Turn off bus power and clock. */ | 571 | /* Turn off bus power and clock. */ | |
571 | (void)sdmmc_chip_bus_width(sc->sc_sct, sc->sc_sch, 1); | 572 | (void)sdmmc_chip_bus_width(sc->sc_sct, sc->sc_sch, 1); | |
572 | (void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_OFF); | 573 | (void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_OFF, | |
574 | false); | |||
573 | (void)sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, 0); | 575 | (void)sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, 0); | |
574 | sc->sc_busclk = sc->sc_clkmax; | 576 | sc->sc_busclk = sc->sc_clkmax; | |
575 | } | 577 | } | |
576 | 578 | |||
577 | /* | 579 | /* | |
578 | * Set the lowest bus voltage supported by the card and the host. | 580 | * Set the lowest bus voltage supported by the card and the host. | |
579 | */ | 581 | */ | |
580 | int | 582 | int | |
581 | sdmmc_set_bus_power(struct sdmmc_softc *sc, uint32_t host_ocr, | 583 | sdmmc_set_bus_power(struct sdmmc_softc *sc, uint32_t host_ocr, | |
582 | uint32_t card_ocr) | 584 | uint32_t card_ocr) | |
583 | { | 585 | { | |
584 | uint32_t bit; | 586 | uint32_t bit; | |
585 | 587 |
--- src/sys/dev/sdmmc/sdmmc_io.c 2015/08/03 05:32:50 1.9
+++ src/sys/dev/sdmmc/sdmmc_io.c 2015/08/03 10:08:51 1.10
@@ -1,36 +1,36 @@ | @@ -1,36 +1,36 @@ | |||
1 | /* $NetBSD: sdmmc_io.c,v 1.9 2015/08/03 05:32:50 mlelstv Exp $ */ | 1 | /* $NetBSD: sdmmc_io.c,v 1.10 2015/08/03 10:08:51 jmcneill Exp $ */ | |
2 | /* $OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $ */ | 2 | /* $OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw 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 | /* Routines for SD I/O cards. */ | 20 | /* Routines for SD I/O cards. */ | |
21 | 21 | |||
22 | #include <sys/cdefs.h> | 22 | #include <sys/cdefs.h> | |
23 | __KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.9 2015/08/03 05:32:50 mlelstv Exp $"); | 23 | __KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.10 2015/08/03 10:08:51 jmcneill Exp $"); | |
24 | 24 | |||
25 | #ifdef _KERNEL_OPT | 25 | #ifdef _KERNEL_OPT | |
26 | #include "opt_sdmmc.h" | 26 | #include "opt_sdmmc.h" | |
27 | #endif | 27 | #endif | |
28 | 28 | |||
29 | #include <sys/param.h> | 29 | #include <sys/param.h> | |
30 | #include <sys/kernel.h> | 30 | #include <sys/kernel.h> | |
31 | #include <sys/malloc.h> | 31 | #include <sys/malloc.h> | |
32 | #include <sys/proc.h> | 32 | #include <sys/proc.h> | |
33 | #include <sys/systm.h> | 33 | #include <sys/systm.h> | |
34 | 34 | |||
35 | #include <dev/sdmmc/sdmmc_ioreg.h> | 35 | #include <dev/sdmmc/sdmmc_ioreg.h> | |
36 | #include <dev/sdmmc/sdmmcchip.h> | 36 | #include <dev/sdmmc/sdmmcchip.h> | |
@@ -221,27 +221,28 @@ sdmmc_io_init(struct sdmmc_softc *sc, st | @@ -221,27 +221,28 @@ sdmmc_io_init(struct sdmmc_softc *sc, st | |||
221 | 221 | |||
222 | reg = sdmmc_io_read_1(sf, SD_IO_CCCR_HIGH_SPEED); | 222 | reg = sdmmc_io_read_1(sf, SD_IO_CCCR_HIGH_SPEED); | |
223 | if (reg & CCCR_HIGH_SPEED_SHS) { | 223 | if (reg & CCCR_HIGH_SPEED_SHS) { | |
224 | reg |= CCCR_HIGH_SPEED_EHS; | 224 | reg |= CCCR_HIGH_SPEED_EHS; | |
225 | sdmmc_io_write_1(sf, SD_IO_CCCR_HIGH_SPEED, reg); | 225 | sdmmc_io_write_1(sf, SD_IO_CCCR_HIGH_SPEED, reg); | |
226 | sf->csd.tran_speed = 50000; /* 50MHz */ | 226 | sf->csd.tran_speed = 50000; /* 50MHz */ | |
227 | 227 | |||
228 | /* Wait 400KHz x 8 clock */ | 228 | /* Wait 400KHz x 8 clock */ | |
229 | delay(1); | 229 | delay(1); | |
230 | } | 230 | } | |
231 | if (sc->sc_busclk > sf->csd.tran_speed) | 231 | if (sc->sc_busclk > sf->csd.tran_speed) | |
232 | sc->sc_busclk = sf->csd.tran_speed; | 232 | sc->sc_busclk = sf->csd.tran_speed; | |
233 | error = | 233 | error = | |
234 | sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk); | 234 | sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk, | |
235 | false); | |||
235 | if (error) | 236 | if (error) | |
236 | aprint_error_dev(sc->sc_dev, | 237 | aprint_error_dev(sc->sc_dev, | |
237 | "can't change bus clock\n"); | 238 | "can't change bus clock\n"); | |
238 | } else { | 239 | } else { | |
239 | reg = sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x000); | 240 | reg = sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x000); | |
240 | sf->interface = FBR_STD_FUNC_IF_CODE(reg); | 241 | sf->interface = FBR_STD_FUNC_IF_CODE(reg); | |
241 | if (sf->interface == 0x0f) | 242 | if (sf->interface == 0x0f) | |
242 | sf->interface = | 243 | sf->interface = | |
243 | sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x001); | 244 | sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x001); | |
244 | error = sdmmc_read_cis(sf, &sf->cis); | 245 | error = sdmmc_read_cis(sf, &sf->cis); | |
245 | if (error) { | 246 | if (error) { | |
246 | aprint_error_dev(sc->sc_dev, "couldn't read CIS\n"); | 247 | aprint_error_dev(sc->sc_dev, "couldn't read CIS\n"); | |
247 | SET(sf->flags, SFF_ERROR); | 248 | SET(sf->flags, SFF_ERROR); |
--- src/sys/dev/sdmmc/sdmmc_mem.c 2015/08/03 05:32:50 1.38
+++ src/sys/dev/sdmmc/sdmmc_mem.c 2015/08/03 10:08:51 1.39
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sdmmc_mem.c,v 1.38 2015/08/03 05:32:50 mlelstv Exp $ */ | 1 | /* $NetBSD: sdmmc_mem.c,v 1.39 2015/08/03 10:08:51 jmcneill Exp $ */ | |
2 | /* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */ | 2 | /* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg 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 | |
@@ -35,27 +35,27 @@ | @@ -35,27 +35,27 @@ | |||
35 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 35 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
36 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 36 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
37 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 37 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
38 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 38 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
39 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 39 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
40 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 40 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 41 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
42 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 42 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
43 | */ | 43 | */ | |
44 | 44 | |||
45 | /* Routines for SD/MMC memory cards. */ | 45 | /* Routines for SD/MMC memory cards. */ | |
46 | 46 | |||
47 | #include <sys/cdefs.h> | 47 | #include <sys/cdefs.h> | |
48 | __KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.38 2015/08/03 05:32:50 mlelstv Exp $"); | 48 | __KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.39 2015/08/03 10:08:51 jmcneill Exp $"); | |
49 | 49 | |||
50 | #ifdef _KERNEL_OPT | 50 | #ifdef _KERNEL_OPT | |
51 | #include "opt_sdmmc.h" | 51 | #include "opt_sdmmc.h" | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | #include <sys/param.h> | 54 | #include <sys/param.h> | |
55 | #include <sys/kernel.h> | 55 | #include <sys/kernel.h> | |
56 | #include <sys/malloc.h> | 56 | #include <sys/malloc.h> | |
57 | #include <sys/systm.h> | 57 | #include <sys/systm.h> | |
58 | #include <sys/device.h> | 58 | #include <sys/device.h> | |
59 | 59 | |||
60 | #include <dev/sdmmc/sdmmcchip.h> | 60 | #include <dev/sdmmc/sdmmcchip.h> | |
61 | #include <dev/sdmmc/sdmmcreg.h> | 61 | #include <dev/sdmmc/sdmmcreg.h> | |
@@ -86,26 +86,47 @@ static int sdmmc_mem_spi_read_ocr(struct | @@ -86,26 +86,47 @@ static int sdmmc_mem_spi_read_ocr(struct | |||
86 | static int sdmmc_mem_single_read_block(struct sdmmc_function *, uint32_t, | 86 | static int sdmmc_mem_single_read_block(struct sdmmc_function *, uint32_t, | |
87 | u_char *, size_t); | 87 | u_char *, size_t); | |
88 | static int sdmmc_mem_single_write_block(struct sdmmc_function *, uint32_t, | 88 | static int sdmmc_mem_single_write_block(struct sdmmc_function *, uint32_t, | |
89 | u_char *, size_t); | 89 | u_char *, size_t); | |
90 | static int sdmmc_mem_single_segment_dma_read_block(struct sdmmc_function *, | 90 | static int sdmmc_mem_single_segment_dma_read_block(struct sdmmc_function *, | |
91 | uint32_t, u_char *, size_t); | 91 | uint32_t, u_char *, size_t); | |
92 | static int sdmmc_mem_single_segment_dma_write_block(struct sdmmc_function *, | 92 | static int sdmmc_mem_single_segment_dma_write_block(struct sdmmc_function *, | |
93 | uint32_t, u_char *, size_t); | 93 | uint32_t, u_char *, size_t); | |
94 | static int sdmmc_mem_read_block_subr(struct sdmmc_function *, bus_dmamap_t, | 94 | static int sdmmc_mem_read_block_subr(struct sdmmc_function *, bus_dmamap_t, | |
95 | uint32_t, u_char *, size_t); | 95 | uint32_t, u_char *, size_t); | |
96 | static int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t, | 96 | static int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t, | |
97 | uint32_t, u_char *, size_t); | 97 | uint32_t, u_char *, size_t); | |
98 | 98 | |||
99 | static const struct { | |||
100 | const char *name; | |||
101 | int v; | |||
102 | int freq; | |||
103 | } switch_group0_functions[] = { | |||
104 | /* Default/SDR12 */ | |||
105 | { "Default/SDR12", 0, 25000 }, | |||
106 | ||||
107 | /* High-Speed/SDR25 */ | |||
108 | { "High-Speed/SDR25", SMC_CAPS_SD_HIGHSPEED, 50000 }, | |||
109 | ||||
110 | /* SDR50 */ | |||
111 | { "SDR50", SMC_CAPS_UHS_SDR50, 100000 }, | |||
112 | ||||
113 | /* SDR104 */ | |||
114 | { "SDR104", SMC_CAPS_UHS_SDR104, 208000 }, | |||
115 | ||||
116 | /* DDR50 */ | |||
117 | { "DDR50", SMC_CAPS_UHS_DDR50, 50000 }, | |||
118 | }; | |||
119 | ||||
99 | /* | 120 | /* | |
100 | * Initialize SD/MMC memory cards and memory in SDIO "combo" cards. | 121 | * Initialize SD/MMC memory cards and memory in SDIO "combo" cards. | |
101 | */ | 122 | */ | |
102 | int | 123 | int | |
103 | sdmmc_mem_enable(struct sdmmc_softc *sc) | 124 | sdmmc_mem_enable(struct sdmmc_softc *sc) | |
104 | { | 125 | { | |
105 | uint32_t host_ocr; | 126 | uint32_t host_ocr; | |
106 | uint32_t card_ocr; | 127 | uint32_t card_ocr; | |
107 | uint32_t new_ocr; | 128 | uint32_t new_ocr; | |
108 | uint32_t ocr = 0; | 129 | uint32_t ocr = 0; | |
109 | int error; | 130 | int error; | |
110 | 131 | |||
111 | SDMMC_LOCK(sc); | 132 | SDMMC_LOCK(sc); | |
@@ -211,47 +232,48 @@ mmc_mode: | @@ -211,47 +232,48 @@ mmc_mode: | |||
211 | error = sdmmc_mmc_command(sc, &cmd); | 232 | error = sdmmc_mmc_command(sc, &cmd); | |
212 | if (error) { | 233 | if (error) { | |
213 | DPRINTF(("%s: voltage switch command failed\n", | 234 | DPRINTF(("%s: voltage switch command failed\n", | |
214 | SDMMCDEVNAME(sc))); | 235 | SDMMCDEVNAME(sc))); | |
215 | goto out; | 236 | goto out; | |
216 | } | 237 | } | |
217 | 238 | |||
218 | delay(1000); | 239 | delay(1000); | |
219 | 240 | |||
220 | /* | 241 | /* | |
221 | * Stop the clock | 242 | * Stop the clock | |
222 | */ | 243 | */ | |
223 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, | 244 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, | |
224 | SDMMC_SDCLK_OFF); | 245 | SDMMC_SDCLK_OFF, false); | |
225 | if (error) | 246 | if (error) | |
226 | goto out; | 247 | goto out; | |
227 | 248 | |||
228 | delay(1000); | 249 | delay(1000); | |
229 | 250 | |||
230 | /* | 251 | /* | |
231 | * Card switch command was successful, update host controller | 252 | * Card switch command was successful, update host controller | |
232 | * signal voltage setting. | 253 | * signal voltage setting. | |
233 | */ | 254 | */ | |
234 | error = sdmmc_chip_signal_voltage(sc->sc_sct, | 255 | error = sdmmc_chip_signal_voltage(sc->sc_sct, | |
235 | sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180); | 256 | sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180); | |
236 | if (error) | 257 | if (error) | |
237 | goto out; | 258 | goto out; | |
238 | 259 | |||
239 | delay(5000); | 260 | delay(5000); | |
240 | 261 | |||
241 | /* | 262 | /* | |
242 | * Switch to SDR12 timing | 263 | * Switch to SDR12 timing | |
243 | */ | 264 | */ | |
244 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000); | 265 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000, | |
266 | false); | |||
245 | if (error) | 267 | if (error) | |
246 | goto out; | 268 | goto out; | |
247 | 269 | |||
248 | delay(1000); | 270 | delay(1000); | |
249 | 271 | |||
250 | SET(sc->sc_flags, SMF_UHS_MODE); | 272 | SET(sc->sc_flags, SMF_UHS_MODE); | |
251 | } | 273 | } | |
252 | 274 | |||
253 | out: | 275 | out: | |
254 | SDMMC_UNLOCK(sc); | 276 | SDMMC_UNLOCK(sc); | |
255 | 277 | |||
256 | if (error) | 278 | if (error) | |
257 | printf("%s: %s failed with error %d\n", SDMMCDEVNAME(sc), | 279 | printf("%s: %s failed with error %d\n", SDMMCDEVNAME(sc), | |
@@ -662,214 +684,258 @@ static void | @@ -662,214 +684,258 @@ static void | |||
662 | sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *buf) { | 684 | sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *buf) { | |
663 | size_t i; | 685 | size_t i; | |
664 | uint32_t tmp0, tmp1; | 686 | uint32_t tmp0, tmp1; | |
665 | const size_t bitswords = __arraycount(buf->_bits); | 687 | const size_t bitswords = __arraycount(buf->_bits); | |
666 | for (i = 0; i < bitswords/2; i++) { | 688 | for (i = 0; i < bitswords/2; i++) { | |
667 | tmp0 = buf->_bits[i]; | 689 | tmp0 = buf->_bits[i]; | |
668 | tmp1 = buf->_bits[bitswords - 1 - i]; | 690 | tmp1 = buf->_bits[bitswords - 1 - i]; | |
669 | buf->_bits[i] = be32toh(tmp1); | 691 | buf->_bits[i] = be32toh(tmp1); | |
670 | buf->_bits[bitswords - 1 - i] = be32toh(tmp0); | 692 | buf->_bits[bitswords - 1 - i] = be32toh(tmp0); | |
671 | } | 693 | } | |
672 | } | 694 | } | |
673 | 695 | |||
674 | static int | 696 | static int | |
697 | sdmmc_mem_select_transfer_mode(struct sdmmc_softc *sc, int support_func) | |||
698 | { | |||
699 | if (ISSET(sc->sc_flags, SMF_UHS_MODE)) { | |||
700 | if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR104) && | |||
701 | ISSET(support_func, SD_ACCESS_MODE_SDR104)) { | |||
702 | return SD_ACCESS_MODE_SDR104; | |||
703 | } | |||
704 | if (ISSET(sc->sc_caps, SMC_CAPS_UHS_DDR50) && | |||
705 | ISSET(support_func, SD_ACCESS_MODE_DDR50)) { | |||
706 | return SD_ACCESS_MODE_DDR50; | |||
707 | } | |||
708 | if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR50) && | |||
709 | ISSET(support_func, SD_ACCESS_MODE_SDR50)) { | |||
710 | return SD_ACCESS_MODE_SDR50; | |||
711 | } | |||
712 | } | |||
713 | if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) && | |||
714 | ISSET(support_func, SD_ACCESS_MODE_SDR25)) { | |||
715 | return SD_ACCESS_MODE_SDR25; | |||
716 | } | |||
717 | return SD_ACCESS_MODE_SDR12; | |||
718 | } | |||
719 | ||||
720 | static int | |||
675 | sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) | 721 | sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) | |
676 | { | 722 | { | |
677 | static const struct { | 723 | int support_func, best_func, bus_clock, error, i; | |
678 | int v; | |||
679 | int freq; | |||
680 | int uhs; | |||
681 | } switch_group0_functions[] = { | |||
682 | /* Default/SDR12 */ | |||
683 | { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V | | |||
684 | MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V, 25000, 0 }, | |||
685 | ||||
686 | /* High-Speed/SDR25 */ | |||
687 | { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V | | |||
688 | MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V, 50000, 0 }, | |||
689 | ||||
690 | /* SDR50 */ | |||
691 | { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 100000, 1 }, | |||
692 | ||||
693 | /* SDR104 */ | |||
694 | { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 208000, 1 }, | |||
695 | ||||
696 | #if notyet | |||
697 | /* DDR50 */ | |||
698 | { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 50000, 1 }, | |||
699 | #endif | |||
700 | }; | |||
701 | int host_ocr, support_func, best_func, bus_clock, error, g, i; | |||
702 | sdmmc_bitfield512_t status; /* Switch Function Status */ | 724 | sdmmc_bitfield512_t status; /* Switch Function Status */ | |
725 | bool ddr = false; | |||
703 | 726 | |||
704 | /* change bus clock */ | 727 | /* change bus clock */ | |
705 | bus_clock = min(sc->sc_busclk, sf->csd.tran_speed); | 728 | bus_clock = min(sc->sc_busclk, sf->csd.tran_speed); | |
706 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock); | 729 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock, false); | |
707 | if (error) { | 730 | if (error) { | |
708 | aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); | 731 | aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); | |
709 | return error; | 732 | return error; | |
710 | } | 733 | } | |
711 | 734 | |||
712 | error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr); | 735 | error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr); | |
713 | if (error) { | 736 | if (error) { | |
714 | aprint_error_dev(sc->sc_dev, "SD_SEND_SCR send failed.\n"); | 737 | aprint_error_dev(sc->sc_dev, "SD_SEND_SCR send failed.\n"); | |
715 | return error; | 738 | return error; | |
716 | } | 739 | } | |
717 | error = sdmmc_mem_decode_scr(sc, sf); | 740 | error = sdmmc_mem_decode_scr(sc, sf); | |
718 | if (error) | 741 | if (error) | |
719 | return error; | 742 | return error; | |
720 | 743 | |||
721 | if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE) && | 744 | if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE) && | |
722 | ISSET(sf->scr.bus_width, SCR_SD_BUS_WIDTHS_4BIT)) { | 745 | ISSET(sf->scr.bus_width, SCR_SD_BUS_WIDTHS_4BIT)) { | |
723 | DPRINTF(("%s: change bus width\n", SDMMCDEVNAME(sc))); | 746 | DPRINTF(("%s: change bus width\n", SDMMCDEVNAME(sc))); | |
724 | error = sdmmc_set_bus_width(sf, 4); | 747 | error = sdmmc_set_bus_width(sf, 4); | |
725 | if (error) { | 748 | if (error) { | |
726 | aprint_error_dev(sc->sc_dev, | 749 | aprint_error_dev(sc->sc_dev, | |
727 | "can't change bus width (%d bit)\n", 4); | 750 | "can't change bus width (%d bit)\n", 4); | |
728 | return error; | 751 | return error; | |
729 | } | 752 | } | |
730 | sf->width = 4; | 753 | sf->width = 4; | |
731 | } | 754 | } | |
732 | 755 | |||
756 | best_func = 0; | |||
733 | if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 && | 757 | if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 && | |
734 | ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) { | 758 | ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) { | |
735 | DPRINTF(("%s: switch func mode 0\n", SDMMCDEVNAME(sc))); | 759 | DPRINTF(("%s: switch func mode 0\n", SDMMCDEVNAME(sc))); | |
736 | error = sdmmc_mem_sd_switch(sf, 0, 1, 0, &status); | 760 | error = sdmmc_mem_sd_switch(sf, 0, 1, 0, &status); | |
737 | if (error) { | 761 | if (error) { | |
738 | aprint_error_dev(sc->sc_dev, | 762 | aprint_error_dev(sc->sc_dev, | |
739 | "switch func mode 0 failed\n"); | 763 | "switch func mode 0 failed\n"); | |
740 | return error; | 764 | return error; | |
741 | } | 765 | } | |
742 | 766 | |||
743 | host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch); | |||
744 | support_func = SFUNC_STATUS_GROUP(&status, 1); | 767 | support_func = SFUNC_STATUS_GROUP(&status, 1); | |
745 | DPRINTF(("%s: support_func %#x\n", SDMMCDEVNAME(sc), support_func)); | 768 | ||
746 | best_func = 0; | 769 | for (i = 0; i < __arraycount(switch_group0_functions); i++) { | |
747 | for (i = 0, g = 1; | 770 | if (!(support_func & (1 << i))) | |
748 | i < __arraycount(switch_group0_functions); i++, g <<= 1) { | |||
749 | if (!(switch_group0_functions[i].v & host_ocr)) | |||
750 | continue; | 771 | continue; | |
751 | if (switch_group0_functions[i].uhs && | 772 | DPRINTF(("%s: card supports mode %s\n", | |
752 | !ISSET(sc->sc_flags, SMF_UHS_MODE)) | 773 | SDMMCDEVNAME(sc), | |
753 | break; | 774 | switch_group0_functions[i].name)); | |
754 | if (g & support_func) | |||
755 | best_func = i; | |||
756 | } | 775 | } | |
757 | if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) && | 776 | ||
758 | best_func != 0) { | 777 | best_func = sdmmc_mem_select_transfer_mode(sc, support_func); | |
778 | ||||
779 | DPRINTF(("%s: using mode %s\n", SDMMCDEVNAME(sc), | |||
780 | switch_group0_functions[best_func].name)); | |||
781 | ||||
782 | if (best_func != 0) { | |||
759 | DPRINTF(("%s: switch func mode 1(func=%d)\n", | 783 | DPRINTF(("%s: switch func mode 1(func=%d)\n", | |
760 | SDMMCDEVNAME(sc), best_func)); | 784 | SDMMCDEVNAME(sc), best_func)); | |
761 | error = | 785 | error = | |
762 | sdmmc_mem_sd_switch(sf, 1, 1, best_func, &status); | 786 | sdmmc_mem_sd_switch(sf, 1, 1, best_func, &status); | |
763 | if (error) { | 787 | if (error) { | |
764 | aprint_error_dev(sc->sc_dev, | 788 | aprint_error_dev(sc->sc_dev, | |
765 | "switch func mode 1 failed:" | 789 | "switch func mode 1 failed:" | |
766 | " group 1 function %d(0x%2x)\n", | 790 | " group 1 function %d(0x%2x)\n", | |
767 | best_func, support_func); | 791 | best_func, support_func); | |
768 | return error; | 792 | return error; | |
769 | } | 793 | } | |
770 | sf->csd.tran_speed = | 794 | sf->csd.tran_speed = | |
771 | switch_group0_functions[best_func].freq; | 795 | switch_group0_functions[best_func].freq; | |
772 | 796 | |||
797 | if (best_func == SD_ACCESS_MODE_DDR50) | |||
798 | ddr = true; | |||
799 | ||||
773 | /* Wait 400KHz x 8 clock (2.5us * 8 + slop) */ | 800 | /* Wait 400KHz x 8 clock (2.5us * 8 + slop) */ | |
774 | delay(25); | 801 | delay(25); | |
775 | } | 802 | } | |
776 | } | 803 | } | |
777 | 804 | |||
778 | /* update bus clock */ | 805 | /* update bus clock */ | |
779 | if (sc->sc_busclk > sf->csd.tran_speed) | 806 | if (sc->sc_busclk > sf->csd.tran_speed) | |
780 | sc->sc_busclk = sf->csd.tran_speed; | 807 | sc->sc_busclk = sf->csd.tran_speed; | |
781 | if (sc->sc_busclk == bus_clock) | 808 | if (sc->sc_busclk == bus_clock && sc->sc_busddr == ddr) | |
782 | return 0; | 809 | return 0; | |
783 | 810 | |||
784 | /* change bus clock */ | 811 | /* change bus clock */ | |
785 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk); | 812 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk, | |
813 | ddr); | |||
786 | if (error) { | 814 | if (error) { | |
787 | aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); | 815 | aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); | |
788 | return error; | 816 | return error; | |
789 | } | 817 | } | |
790 | 818 | |||
819 | sc->sc_transfer_mode = switch_group0_functions[best_func].name; | |||
820 | sc->sc_busddr = ddr; | |||
821 | ||||
791 | return 0; | 822 | return 0; | |
792 | } | 823 | } | |
793 | 824 | |||
794 | static int | 825 | static int | |
795 | sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) | 826 | sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) | |
796 | { | 827 | { | |
797 | int width, value, hs_timing, bus_clock, error; | 828 | int width, value, hs_timing, bus_clock, error; | |
798 | char ext_csd[512]; | 829 | char ext_csd[512]; | |
799 | uint32_t sectors = 0; | 830 | uint32_t sectors = 0; | |
800 | int host_ocr; | 831 | ||
832 | sc->sc_transfer_mode = NULL; | |||
801 | 833 | |||
802 | /* change bus clock */ | 834 | /* change bus clock */ | |
803 | bus_clock = min(sc->sc_busclk, sf->csd.tran_speed); | 835 | bus_clock = min(sc->sc_busclk, sf->csd.tran_speed); | |
804 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock); | 836 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock, false); | |
805 | if (error) { | 837 | if (error) { | |
806 | aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); | 838 | aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); | |
807 | return error; | 839 | return error; | |
808 | } | 840 | } | |
809 | 841 | |||
810 | host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch); | |||
811 | ||||
812 | if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) { | 842 | if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) { | |
813 | error = sdmmc_mem_send_cxd_data(sc, | 843 | error = sdmmc_mem_send_cxd_data(sc, | |
814 | MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd)); | 844 | MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd)); | |
815 | if (error) { | 845 | if (error) { | |
816 | aprint_error_dev(sc->sc_dev, | 846 | aprint_error_dev(sc->sc_dev, | |
817 | "can't read EXT_CSD (error=%d)\n", error); | 847 | "can't read EXT_CSD (error=%d)\n", error); | |
818 | return error; | 848 | return error; | |
819 | } | 849 | } | |
820 | if ((sf->csd.csdver == MMC_CSD_CSDVER_EXT_CSD) && | 850 | if ((sf->csd.csdver == MMC_CSD_CSDVER_EXT_CSD) && | |
821 | (ext_csd[EXT_CSD_STRUCTURE] > EXT_CSD_STRUCTURE_VER_1_2)) { | 851 | (ext_csd[EXT_CSD_STRUCTURE] > EXT_CSD_STRUCTURE_VER_1_2)) { | |
822 | aprint_error_dev(sc->sc_dev, | 852 | aprint_error_dev(sc->sc_dev, | |
823 | "unrecognised future version (%d)\n", | 853 | "unrecognised future version (%d)\n", | |
824 | ext_csd[EXT_CSD_STRUCTURE]); | 854 | ext_csd[EXT_CSD_STRUCTURE]); | |
825 | return ENOTSUP; | 855 | return ENOTSUP; | |
826 | } | 856 | } | |
827 | 857 | |||
828 | if (ISSET(host_ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V) && | 858 | sc->sc_transfer_mode = NULL; | |
859 | if (ISSET(sc->sc_caps, SMC_CAPS_MMC_HS200) && | |||
829 | ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_HS200_1_8V) { | 860 | ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_HS200_1_8V) { | |
830 | sf->csd.tran_speed = 200000; /* 200MHz SDR */ | 861 | sf->csd.tran_speed = 200000; /* 200MHz SDR */ | |
831 | hs_timing = 2; | 862 | hs_timing = 2; | |
832 | } else if (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_52M) { | 863 | } else if (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_52M) { | |
833 | sf->csd.tran_speed = 52000; /* 52MHz */ | 864 | sf->csd.tran_speed = 52000; /* 52MHz */ | |
834 | hs_timing = 1; | 865 | hs_timing = 1; | |
835 | } else if (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_26M) { | 866 | } else if (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_26M) { | |
836 | sf->csd.tran_speed = 26000; /* 26MHz */ | 867 | sf->csd.tran_speed = 26000; /* 26MHz */ | |
837 | hs_timing = 0; | 868 | hs_timing = 0; | |
838 | } else { | 869 | } else { | |
839 | aprint_error_dev(sc->sc_dev, | 870 | aprint_error_dev(sc->sc_dev, | |
840 | "unknown CARD_TYPE: 0x%x\n", | 871 | "unknown CARD_TYPE: 0x%x\n", | |
841 | ext_csd[EXT_CSD_CARD_TYPE]); | 872 | ext_csd[EXT_CSD_CARD_TYPE]); | |
842 | return ENOTSUP; | 873 | return ENOTSUP; | |
843 | } | 874 | } | |
844 | 875 | |||
845 | if (!ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) { | 876 | if (hs_timing == 2) { | |
877 | error = sdmmc_chip_signal_voltage(sc->sc_sct, | |||
878 | sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180); | |||
879 | if (error) | |||
880 | hs_timing = 1; | |||
881 | } | |||
882 | ||||
883 | if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) { | |||
884 | width = 8; | |||
885 | value = EXT_CSD_BUS_WIDTH_8; | |||
886 | } else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) { | |||
887 | width = 4; | |||
888 | value = EXT_CSD_BUS_WIDTH_4; | |||
889 | } else { | |||
890 | width = 1; | |||
891 | value = EXT_CSD_BUS_WIDTH_1; | |||
892 | } | |||
893 | ||||
894 | if (width != 1) { | |||
895 | error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, | |||
896 | EXT_CSD_BUS_WIDTH, value); | |||
897 | if (error == 0) | |||
898 | error = sdmmc_chip_bus_width(sc->sc_sct, | |||
899 | sc->sc_sch, width); | |||
900 | else { | |||
901 | DPRINTF(("%s: can't change bus width" | |||
902 | " (%d bit)\n", SDMMCDEVNAME(sc), width)); | |||
903 | return error; | |||
904 | } | |||
905 | ||||
906 | /* XXXX: need bus test? (using by CMD14 & CMD19) */ | |||
907 | } | |||
908 | sf->width = width; | |||
909 | ||||
910 | if (hs_timing == 1 && | |||
911 | !ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) { | |||
846 | hs_timing = 0; | 912 | hs_timing = 0; | |
847 | } | 913 | } | |
848 | if (hs_timing) { | 914 | if (hs_timing) { | |
849 | error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, | 915 | error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, | |
850 | EXT_CSD_HS_TIMING, hs_timing); | 916 | EXT_CSD_HS_TIMING, hs_timing); | |
851 | if (error) { | 917 | if (error) { | |
852 | aprint_error_dev(sc->sc_dev, | 918 | aprint_error_dev(sc->sc_dev, | |
853 | "can't change high speed\n"); | 919 | "can't change high speed\n"); | |
854 | return error; | 920 | return error; | |
855 | } | 921 | } | |
856 | } | 922 | } | |
857 | 923 | |||
858 | if (sc->sc_busclk > sf->csd.tran_speed) | 924 | if (sc->sc_busclk > sf->csd.tran_speed) | |
859 | sc->sc_busclk = sf->csd.tran_speed; | 925 | sc->sc_busclk = sf->csd.tran_speed; | |
860 | if (sc->sc_busclk != bus_clock) { | 926 | if (sc->sc_busclk != bus_clock) { | |
861 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, | 927 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, | |
862 | sc->sc_busclk); | 928 | sc->sc_busclk, false); | |
863 | if (error) { | 929 | if (error) { | |
864 | aprint_error_dev(sc->sc_dev, | 930 | aprint_error_dev(sc->sc_dev, | |
865 | "can't change bus clock\n"); | 931 | "can't change bus clock\n"); | |
866 | return error; | 932 | return error; | |
867 | } | 933 | } | |
868 | } | 934 | } | |
869 | 935 | |||
870 | if (hs_timing) { | 936 | if (hs_timing) { | |
871 | error = sdmmc_mem_send_cxd_data(sc, | 937 | error = sdmmc_mem_send_cxd_data(sc, | |
872 | MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd)); | 938 | MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd)); | |
873 | if (error) { | 939 | if (error) { | |
874 | aprint_error_dev(sc->sc_dev, | 940 | aprint_error_dev(sc->sc_dev, | |
875 | "can't re-read EXT_CSD\n"); | 941 | "can't re-read EXT_CSD\n"); | |
@@ -881,58 +947,37 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s | @@ -881,58 +947,37 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s | |||
881 | return EINVAL; | 947 | return EINVAL; | |
882 | } | 948 | } | |
883 | } | 949 | } | |
884 | 950 | |||
885 | sectors = ext_csd[EXT_CSD_SEC_COUNT + 0] << 0 | | 951 | sectors = ext_csd[EXT_CSD_SEC_COUNT + 0] << 0 | | |
886 | ext_csd[EXT_CSD_SEC_COUNT + 1] << 8 | | 952 | ext_csd[EXT_CSD_SEC_COUNT + 1] << 8 | | |
887 | ext_csd[EXT_CSD_SEC_COUNT + 2] << 16 | | 953 | ext_csd[EXT_CSD_SEC_COUNT + 2] << 16 | | |
888 | ext_csd[EXT_CSD_SEC_COUNT + 3] << 24; | 954 | ext_csd[EXT_CSD_SEC_COUNT + 3] << 24; | |
889 | if (sectors > (2u * 1024 * 1024 * 1024) / 512) { | 955 | if (sectors > (2u * 1024 * 1024 * 1024) / 512) { | |
890 | SET(sf->flags, SFF_SDHC); | 956 | SET(sf->flags, SFF_SDHC); | |
891 | sf->csd.capacity = sectors; | 957 | sf->csd.capacity = sectors; | |
892 | } | 958 | } | |
893 | 959 | |||
894 | if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) { | 960 | if (hs_timing == 2) { | |
895 | width = 8; | 961 | sc->sc_transfer_mode = "HS200"; | |
896 | value = EXT_CSD_BUS_WIDTH_8; | |||
897 | } else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) { | |||
898 | width = 4; | |||
899 | value = EXT_CSD_BUS_WIDTH_4; | |||
900 | } else { | 962 | } else { | |
901 | width = 1; | 963 | sc->sc_transfer_mode = NULL; | |
902 | value = EXT_CSD_BUS_WIDTH_1; | |||
903 | } | 964 | } | |
904 | ||||
905 | if (width != 1) { | |||
906 | error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, | |||
907 | EXT_CSD_BUS_WIDTH, value); | |||
908 | if (error == 0) | |||
909 | error = sdmmc_chip_bus_width(sc->sc_sct, | |||
910 | sc->sc_sch, width); | |||
911 | else { | |||
912 | DPRINTF(("%s: can't change bus width" | |||
913 | " (%d bit)\n", SDMMCDEVNAME(sc), width)); | |||
914 | return error; | |||
915 | } | |||
916 | ||||
917 | /* XXXX: need bus test? (using by CMD14 & CMD19) */ | |||
918 | } | |||
919 | sf->width = width; | |||
920 | } else { | 965 | } else { | |
921 | if (sc->sc_busclk > sf->csd.tran_speed) | 966 | if (sc->sc_busclk > sf->csd.tran_speed) | |
922 | sc->sc_busclk = sf->csd.tran_speed; | 967 | sc->sc_busclk = sf->csd.tran_speed; | |
923 | if (sc->sc_busclk != bus_clock) { | 968 | if (sc->sc_busclk != bus_clock) { | |
924 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, | 969 | error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, | |
925 | sc->sc_busclk); | 970 | sc->sc_busclk, false); | |
926 | if (error) { | 971 | if (error) { | |
927 | aprint_error_dev(sc->sc_dev, | 972 | aprint_error_dev(sc->sc_dev, | |
928 | "can't change bus clock\n"); | 973 | "can't change bus clock\n"); | |
929 | return error; | 974 | return error; | |
930 | } | 975 | } | |
931 | } | 976 | } | |
932 | } | 977 | } | |
933 | 978 | |||
934 | return 0; | 979 | return 0; | |
935 | } | 980 | } | |
936 | 981 | |||
937 | static int | 982 | static int | |
938 | sdmmc_mem_send_cid(struct sdmmc_softc *sc, sdmmc_response *resp) | 983 | sdmmc_mem_send_cid(struct sdmmc_softc *sc, sdmmc_response *resp) | |
@@ -1073,31 +1118,31 @@ sdmmc_mem_decode_scr(struct sdmmc_softc | @@ -1073,31 +1118,31 @@ sdmmc_mem_decode_scr(struct sdmmc_softc | |||
1073 | memset(resp, 0, sizeof(resp)); | 1118 | memset(resp, 0, sizeof(resp)); | |
1074 | /* | 1119 | /* | |
1075 | * Change the raw-scr received from the DMA stream to resp. | 1120 | * Change the raw-scr received from the DMA stream to resp. | |
1076 | */ | 1121 | */ | |
1077 | resp[0] = be32toh(sf->raw_scr[1]) >> 8; // LSW | 1122 | resp[0] = be32toh(sf->raw_scr[1]) >> 8; // LSW | |
1078 | resp[1] = be32toh(sf->raw_scr[0]); // MSW | 1123 | resp[1] = be32toh(sf->raw_scr[0]); // MSW | |
1079 | resp[0] |= (resp[1] & 0xff) << 24; | 1124 | resp[0] |= (resp[1] & 0xff) << 24; | |
1080 | resp[1] >>= 8; | 1125 | resp[1] >>= 8; | |
1081 | 1126 | |||
1082 | ver = SCR_STRUCTURE(resp); | 1127 | ver = SCR_STRUCTURE(resp); | |
1083 | sf->scr.sd_spec = SCR_SD_SPEC(resp); | 1128 | sf->scr.sd_spec = SCR_SD_SPEC(resp); | |
1084 | sf->scr.bus_width = SCR_SD_BUS_WIDTHS(resp); | 1129 | sf->scr.bus_width = SCR_SD_BUS_WIDTHS(resp); | |
1085 | 1130 | |||
1086 | DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x spec=%d, bus width=%d\n", | 1131 | DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x ver=%d, spec=%d, bus width=%d, spec3=%d\n", | |
1087 | SDMMCDEVNAME(sc), resp[1], resp[0], | 1132 | SDMMCDEVNAME(sc), resp[1], resp[0], | |
1088 | sf->scr.sd_spec, sf->scr.bus_width)); | 1133 | ver, sf->scr.sd_spec, sf->scr.bus_width, sf->scr.sd_spec3)); | |
1089 | 1134 | |||
1090 | if (ver != 0) { | 1135 | if (ver != 0 && ver != 1) { | |
1091 | DPRINTF(("%s: unknown structure version: %d\n", | 1136 | DPRINTF(("%s: unknown structure version: %d\n", | |
1092 | SDMMCDEVNAME(sc), ver)); | 1137 | SDMMCDEVNAME(sc), ver)); | |
1093 | return EINVAL; | 1138 | return EINVAL; | |
1094 | } | 1139 | } | |
1095 | return 0; | 1140 | return 0; | |
1096 | } | 1141 | } | |
1097 | 1142 | |||
1098 | static int | 1143 | static int | |
1099 | sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int opcode, void *data, | 1144 | sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int opcode, void *data, | |
1100 | size_t datalen) | 1145 | size_t datalen) | |
1101 | { | 1146 | { | |
1102 | struct sdmmc_command cmd; | 1147 | struct sdmmc_command cmd; | |
1103 | bus_dma_segment_t ds[1]; | 1148 | bus_dma_segment_t ds[1]; |
--- src/sys/dev/sdmmc/sdmmcchip.h 2015/08/02 21:44:36 1.5
+++ src/sys/dev/sdmmc/sdmmcchip.h 2015/08/03 10:08:51 1.6
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sdmmcchip.h,v 1.5 2015/08/02 21:44:36 jmcneill Exp $ */ | 1 | /* $NetBSD: sdmmcchip.h,v 1.6 2015/08/03 10:08:51 jmcneill Exp $ */ | |
2 | /* $OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $ */ | 2 | /* $OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe 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 | |
@@ -50,47 +50,48 @@ struct sdmmc_chip_functions { | @@ -50,47 +50,48 @@ struct sdmmc_chip_functions { | |||
50 | int (*bus_width)(sdmmc_chipset_handle_t, int); | 50 | int (*bus_width)(sdmmc_chipset_handle_t, int); | |
51 | int (*bus_rod)(sdmmc_chipset_handle_t, int); | 51 | int (*bus_rod)(sdmmc_chipset_handle_t, int); | |
52 | 52 | |||
53 | /* command execution */ | 53 | /* command execution */ | |
54 | void (*exec_command)(sdmmc_chipset_handle_t, | 54 | void (*exec_command)(sdmmc_chipset_handle_t, | |
55 | struct sdmmc_command *); | 55 | struct sdmmc_command *); | |
56 | 56 | |||
57 | /* card interrupt */ | 57 | /* card interrupt */ | |
58 | void (*card_enable_intr)(sdmmc_chipset_handle_t, int); | 58 | void (*card_enable_intr)(sdmmc_chipset_handle_t, int); | |
59 | void (*card_intr_ack)(sdmmc_chipset_handle_t); | 59 | void (*card_intr_ack)(sdmmc_chipset_handle_t); | |
60 | 60 | |||
61 | /* UHS functions */ | 61 | /* UHS functions */ | |
62 | int (*signal_voltage)(sdmmc_chipset_handle_t, int); | 62 | int (*signal_voltage)(sdmmc_chipset_handle_t, int); | |
63 | int (*bus_clock_ddr)(sdmmc_chipset_handle_t, int, bool); | |||
63 | }; | 64 | }; | |
64 | 65 | |||
65 | /* host controller reset */ | 66 | /* host controller reset */ | |
66 | #define sdmmc_chip_host_reset(tag, handle) \ | 67 | #define sdmmc_chip_host_reset(tag, handle) \ | |
67 | ((tag)->host_reset((handle))) | 68 | ((tag)->host_reset((handle))) | |
68 | /* host capabilities */ | 69 | /* host capabilities */ | |
69 | #define sdmmc_chip_host_ocr(tag, handle) \ | 70 | #define sdmmc_chip_host_ocr(tag, handle) \ | |
70 | ((tag)->host_ocr((handle))) | 71 | ((tag)->host_ocr((handle))) | |
71 | #define sdmmc_chip_host_maxblklen(tag, handle) \ | 72 | #define sdmmc_chip_host_maxblklen(tag, handle) \ | |
72 | ((tag)->host_maxblklen((handle))) | 73 | ((tag)->host_maxblklen((handle))) | |
73 | /* card detection */ | 74 | /* card detection */ | |
74 | #define sdmmc_chip_card_detect(tag, handle) \ | 75 | #define sdmmc_chip_card_detect(tag, handle) \ | |
75 | ((tag)->card_detect((handle))) | 76 | ((tag)->card_detect((handle))) | |
76 | /* write protect */ | 77 | /* write protect */ | |
77 | #define sdmmc_chip_write_protect(tag, handle) \ | 78 | #define sdmmc_chip_write_protect(tag, handle) \ | |
78 | ((tag)->write_protect((handle))) | 79 | ((tag)->write_protect((handle))) | |
79 | /* bus power, clock frequency, width and rod */ | 80 | /* bus power, clock frequency, width and rod */ | |
80 | #define sdmmc_chip_bus_power(tag, handle, ocr) \ | 81 | #define sdmmc_chip_bus_power(tag, handle, ocr) \ | |
81 | ((tag)->bus_power((handle), (ocr))) | 82 | ((tag)->bus_power((handle), (ocr))) | |
82 | #define sdmmc_chip_bus_clock(tag, handle, freq) \ | 83 | #define sdmmc_chip_bus_clock(tag, handle, freq, ddr) \ | |
83 | ((tag)->bus_clock((handle), (freq))) | 84 | ((tag)->bus_clock_ddr ? (tag)->bus_clock_ddr((handle), (freq), (ddr)) : ((ddr) ? EINVAL : ((tag)->bus_clock((handle), (freq))))) | |
84 | #define sdmmc_chip_bus_width(tag, handle, width) \ | 85 | #define sdmmc_chip_bus_width(tag, handle, width) \ | |
85 | ((tag)->bus_width((handle), (width))) | 86 | ((tag)->bus_width((handle), (width))) | |
86 | #define sdmmc_chip_bus_rod(tag, handle, width) \ | 87 | #define sdmmc_chip_bus_rod(tag, handle, width) \ | |
87 | ((tag)->bus_rod((handle), (width))) | 88 | ((tag)->bus_rod((handle), (width))) | |
88 | /* command execution */ | 89 | /* command execution */ | |
89 | #define sdmmc_chip_exec_command(tag, handle, cmdp) \ | 90 | #define sdmmc_chip_exec_command(tag, handle, cmdp) \ | |
90 | ((tag)->exec_command((handle), (cmdp))) | 91 | ((tag)->exec_command((handle), (cmdp))) | |
91 | /* card interrupt */ | 92 | /* card interrupt */ | |
92 | #define sdmmc_chip_card_enable_intr(tag, handle, enable) \ | 93 | #define sdmmc_chip_card_enable_intr(tag, handle, enable) \ | |
93 | ((tag)->card_enable_intr((handle), (enable))) | 94 | ((tag)->card_enable_intr((handle), (enable))) | |
94 | #define sdmmc_chip_card_intr_ack(tag, handle) \ | 95 | #define sdmmc_chip_card_intr_ack(tag, handle) \ | |
95 | ((tag)->card_intr_ack((handle))) | 96 | ((tag)->card_intr_ack((handle))) | |
96 | /* UHS functions */ | 97 | /* UHS functions */ |
--- src/sys/dev/sdmmc/sdmmcreg.h 2015/08/02 22:47:05 1.17
+++ src/sys/dev/sdmmc/sdmmcreg.h 2015/08/03 10:08:51 1.18
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sdmmcreg.h,v 1.17 2015/08/02 22:47:05 jmcneill Exp $ */ | 1 | /* $NetBSD: sdmmcreg.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $ */ | |
2 | /* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ | 2 | /* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg 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 | |
@@ -324,26 +324,32 @@ | @@ -324,26 +324,32 @@ | |||
324 | #define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */ | 324 | #define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */ | |
325 | #define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */ | 325 | #define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */ | |
326 | #define SCR_SD_SPEC3(scr) MMC_RSP_BITS((scr), 47, 1) | 326 | #define SCR_SD_SPEC3(scr) MMC_RSP_BITS((scr), 47, 1) | |
327 | #define SCR_EX_SECURITY(scr) MMC_RSP_BITS((scr), 43, 4) | 327 | #define SCR_EX_SECURITY(scr) MMC_RSP_BITS((scr), 43, 4) | |
328 | #define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 34, 9) | 328 | #define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 34, 9) | |
329 | #define SCR_CMD_SUPPORT_CMD23(scr) MMC_RSP_BITS((scr), 33, 1) | 329 | #define SCR_CMD_SUPPORT_CMD23(scr) MMC_RSP_BITS((scr), 33, 1) | |
330 | #define SCR_CMD_SUPPORT_CMD20(scr) MMC_RSP_BITS((scr), 32, 1) | 330 | #define SCR_CMD_SUPPORT_CMD20(scr) MMC_RSP_BITS((scr), 32, 1) | |
331 | #define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32) | 331 | #define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32) | |
332 | 332 | |||
333 | /* Status of Switch Function */ | 333 | /* Status of Switch Function */ | |
334 | #define SFUNC_STATUS_GROUP(status, group) \ | 334 | #define SFUNC_STATUS_GROUP(status, group) \ | |
335 | (__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16)) | 335 | (__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16)) | |
336 | 336 | |||
337 | #define SD_ACCESS_MODE_SDR12 0 | |||
338 | #define SD_ACCESS_MODE_SDR25 1 | |||
339 | #define SD_ACCESS_MODE_SDR50 2 | |||
340 | #define SD_ACCESS_MODE_SDR104 3 | |||
341 | #define SD_ACCESS_MODE_DDR50 4 | |||
342 | ||||
337 | /* This assumes the response fields are in host byte order in 32-bit units. */ | 343 | /* This assumes the response fields are in host byte order in 32-bit units. */ | |
338 | #define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len)) | 344 | #define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len)) | |
339 | static inline uint32_t | 345 | static inline uint32_t | |
340 | __bitfield(const uint32_t *src, size_t start, size_t len) | 346 | __bitfield(const uint32_t *src, size_t start, size_t len) | |
341 | { | 347 | { | |
342 | if (start + len > 512 || len == 0 || len > 32) | 348 | if (start + len > 512 || len == 0 || len > 32) | |
343 | return 0; | 349 | return 0; | |
344 | 350 | |||
345 | src += start / 32; | 351 | src += start / 32; | |
346 | start %= 32; | 352 | start %= 32; | |
347 | 353 | |||
348 | uint32_t dst = src[0] >> start; | 354 | uint32_t dst = src[0] >> start; | |
349 | 355 |
--- src/sys/dev/sdmmc/sdmmcvar.h 2015/08/02 21:44:36 1.17
+++ src/sys/dev/sdmmc/sdmmcvar.h 2015/08/03 10:08:51 1.18
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sdmmcvar.h,v 1.17 2015/08/02 21:44:36 jmcneill Exp $ */ | 1 | /* $NetBSD: sdmmcvar.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $ */ | |
2 | /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ | 2 | /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg 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 | |
@@ -219,52 +219,59 @@ struct sdmmc_softc { | @@ -219,52 +219,59 @@ struct sdmmc_softc { | |||
219 | #define SMF_UHS_MODE 0x10000 /* host in UHS mode */ | 219 | #define SMF_UHS_MODE 0x10000 /* host in UHS mode */ | |
220 | 220 | |||
221 | uint32_t sc_caps; /* host capability */ | 221 | uint32_t sc_caps; /* host capability */ | |
222 | #define SMC_CAPS_AUTO_STOP 0x0001 /* send CMD12 automagically by host */ | 222 | #define SMC_CAPS_AUTO_STOP 0x0001 /* send CMD12 automagically by host */ | |
223 | #define SMC_CAPS_4BIT_MODE 0x0002 /* 4-bits data bus width */ | 223 | #define SMC_CAPS_4BIT_MODE 0x0002 /* 4-bits data bus width */ | |
224 | #define SMC_CAPS_DMA 0x0004 /* DMA transfer */ | 224 | #define SMC_CAPS_DMA 0x0004 /* DMA transfer */ | |
225 | #define SMC_CAPS_SPI_MODE 0x0008 /* SPI mode */ | 225 | #define SMC_CAPS_SPI_MODE 0x0008 /* SPI mode */ | |
226 | #define SMC_CAPS_POLL_CARD_DET 0x0010 /* Polling card detect */ | 226 | #define SMC_CAPS_POLL_CARD_DET 0x0010 /* Polling card detect */ | |
227 | #define SMC_CAPS_SINGLE_ONLY 0x0020 /* only single read/write */ | 227 | #define SMC_CAPS_SINGLE_ONLY 0x0020 /* only single read/write */ | |
228 | #define SMC_CAPS_8BIT_MODE 0x0040 /* 8-bits data bus width */ | 228 | #define SMC_CAPS_8BIT_MODE 0x0040 /* 8-bits data bus width */ | |
229 | #define SMC_CAPS_MULTI_SEG_DMA 0x0080 /* multiple segment DMA transfer */ | 229 | #define SMC_CAPS_MULTI_SEG_DMA 0x0080 /* multiple segment DMA transfer */ | |
230 | #define SMC_CAPS_SD_HIGHSPEED 0x0100 /* SD high-speed timing */ | 230 | #define SMC_CAPS_SD_HIGHSPEED 0x0100 /* SD high-speed timing */ | |
231 | #define SMC_CAPS_MMC_HIGHSPEED 0x0200 /* MMC high-speed timing */ | 231 | #define SMC_CAPS_MMC_HIGHSPEED 0x0200 /* MMC high-speed timing */ | |
232 | #define SMC_CAPS_UHS_SDR50 0x1000 /* UHS SDR50 timing */ | |||
233 | #define SMC_CAPS_UHS_SDR104 0x2000 /* UHS SDR104 timing */ | |||
234 | #define SMC_CAPS_UHS_DDR50 0x4000 /* UHS DDR50 timing */ | |||
235 | #define SMC_CAPS_UHS_MASK 0x7000 | |||
236 | #define SMC_CAPS_MMC_HS200 0x8000 /* eMMC HS200 timing */ | |||
232 | 237 | |||
233 | /* function */ | 238 | /* function */ | |
234 | int sc_function_count; /* number of I/O functions (SDIO) */ | 239 | int sc_function_count; /* number of I/O functions (SDIO) */ | |
235 | struct sdmmc_function *sc_card; /* selected card */ | 240 | struct sdmmc_function *sc_card; /* selected card */ | |
236 | struct sdmmc_function *sc_fn0; /* function 0, the card itself */ | 241 | struct sdmmc_function *sc_fn0; /* function 0, the card itself */ | |
237 | SIMPLEQ_HEAD(, sdmmc_function) sf_head; /* list of card functions */ | 242 | SIMPLEQ_HEAD(, sdmmc_function) sf_head; /* list of card functions */ | |
238 | 243 | |||
239 | /* task queue */ | 244 | /* task queue */ | |
240 | struct lwp *sc_tskq_lwp; /* asynchronous tasks */ | 245 | struct lwp *sc_tskq_lwp; /* asynchronous tasks */ | |
241 | TAILQ_HEAD(, sdmmc_task) sc_tskq; /* task thread work queue */ | 246 | TAILQ_HEAD(, sdmmc_task) sc_tskq; /* task thread work queue */ | |
242 | struct kmutex sc_tskq_mtx; | 247 | struct kmutex sc_tskq_mtx; | |
243 | struct kcondvar sc_tskq_cv; | 248 | struct kcondvar sc_tskq_cv; | |
244 | 249 | |||
245 | /* discover task */ | 250 | /* discover task */ | |
246 | struct sdmmc_task sc_discover_task; /* card attach/detach task */ | 251 | struct sdmmc_task sc_discover_task; /* card attach/detach task */ | |
247 | struct kmutex sc_discover_task_mtx; | 252 | struct kmutex sc_discover_task_mtx; | |
248 | 253 | |||
249 | /* interrupt task */ | 254 | /* interrupt task */ | |
250 | struct sdmmc_task sc_intr_task; /* card interrupt task */ | 255 | struct sdmmc_task sc_intr_task; /* card interrupt task */ | |
251 | struct kmutex sc_intr_task_mtx; | 256 | struct kmutex sc_intr_task_mtx; | |
252 | TAILQ_HEAD(, sdmmc_intr_handler) sc_intrq; /* interrupt handlers */ | 257 | TAILQ_HEAD(, sdmmc_intr_handler) sc_intrq; /* interrupt handlers */ | |
253 | 258 | |||
254 | u_int sc_clkmin; /* host min bus clock */ | 259 | u_int sc_clkmin; /* host min bus clock */ | |
255 | u_int sc_clkmax; /* host max bus clock */ | 260 | u_int sc_clkmax; /* host max bus clock */ | |
256 | u_int sc_busclk; /* host bus clock */ | 261 | u_int sc_busclk; /* host bus clock */ | |
262 | bool sc_busddr; /* host bus clock is in DDR mode */ | |||
257 | int sc_buswidth; /* host bus width */ | 263 | int sc_buswidth; /* host bus width */ | |
264 | const char *sc_transfer_mode; /* current transfer mode */ | |||
258 | 265 | |||
259 | callout_t sc_card_detect_ch; /* polling card insert/remove */ | 266 | callout_t sc_card_detect_ch; /* polling card insert/remove */ | |
260 | }; | 267 | }; | |
261 | 268 | |||
262 | /* | 269 | /* | |
263 | * Attach devices at the sdmmc bus. | 270 | * Attach devices at the sdmmc bus. | |
264 | */ | 271 | */ | |
265 | struct sdmmc_attach_args { | 272 | struct sdmmc_attach_args { | |
266 | uint16_t manufacturer; | 273 | uint16_t manufacturer; | |
267 | uint16_t product; | 274 | uint16_t product; | |
268 | int interface; | 275 | int interface; | |
269 | struct sdmmc_function *sf; | 276 | struct sdmmc_function *sf; | |
270 | }; | 277 | }; |