Module Name: src Committed By: jmcneill Date: Mon Aug 3 10:08:51 UTC 2015
Modified Files: src/sys/dev/sdmmc: sdhc.c sdmmc.c sdmmc_io.c sdmmc_mem.c sdmmcchip.h sdmmcreg.h sdmmcvar.h Log Message: Add support for DDR50 transfer modes. To generate a diff of this commit: cvs rdiff -u -r1.75 -r1.76 src/sys/dev/sdmmc/sdhc.c cvs rdiff -u -r1.28 -r1.29 src/sys/dev/sdmmc/sdmmc.c cvs rdiff -u -r1.9 -r1.10 src/sys/dev/sdmmc/sdmmc_io.c cvs rdiff -u -r1.38 -r1.39 src/sys/dev/sdmmc/sdmmc_mem.c cvs rdiff -u -r1.5 -r1.6 src/sys/dev/sdmmc/sdmmcchip.h cvs rdiff -u -r1.17 -r1.18 src/sys/dev/sdmmc/sdmmcreg.h \ src/sys/dev/sdmmc/sdmmcvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/sdmmc/sdhc.c diff -u src/sys/dev/sdmmc/sdhc.c:1.75 src/sys/dev/sdmmc/sdhc.c:1.76 --- src/sys/dev/sdmmc/sdhc.c:1.75 Mon Aug 3 05:24:37 2015 +++ src/sys/dev/sdmmc/sdhc.c Mon Aug 3 10:08:51 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.75 2015/08/03 05:24:37 mlelstv Exp $ */ +/* $NetBSD: sdhc.c,v 1.76 2015/08/03 10:08:51 jmcneill Exp $ */ /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ /* @@ -23,7 +23,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.75 2015/08/03 05:24:37 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.76 2015/08/03 10:08:51 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -174,7 +174,7 @@ static int sdhc_host_maxblklen(sdmmc_chi static int sdhc_card_detect(sdmmc_chipset_handle_t); static int sdhc_write_protect(sdmmc_chipset_handle_t); static int sdhc_bus_power(sdmmc_chipset_handle_t, uint32_t); -static int sdhc_bus_clock(sdmmc_chipset_handle_t, int); +static int sdhc_bus_clock_ddr(sdmmc_chipset_handle_t, int, bool); static int sdhc_bus_width(sdmmc_chipset_handle_t, int); static int sdhc_bus_rod(sdmmc_chipset_handle_t, int); static void sdhc_card_enable_intr(sdmmc_chipset_handle_t, int); @@ -210,7 +210,7 @@ static struct sdmmc_chip_functions sdhc_ /* bus power, clock frequency, width and ROD(OpenDrain/PushPull) */ .bus_power = sdhc_bus_power, - .bus_clock = sdhc_bus_clock, + .bus_clock = NULL, /* see sdhc_bus_clock_ddr */ .bus_width = sdhc_bus_width, .bus_rod = sdhc_bus_rod, @@ -223,6 +223,7 @@ static struct sdmmc_chip_functions sdhc_ /* UHS functions */ .signal_voltage = sdhc_signal_voltage, + .bus_clock_ddr = sdhc_bus_clock_ddr, }; static int @@ -418,14 +419,14 @@ sdhc_host_found(struct sdhc_softc *sc, b SET(hp->ocr, MMC_OCR_S18A); aprint_normal(" SDR50"); } - if (ISSET(caps2, SDHC_SDR104_SUPP)) { - SET(hp->ocr, MMC_OCR_S18A); - aprint_normal(" SDR104"); - } if (ISSET(caps2, SDHC_DDR50_SUPP)) { SET(hp->ocr, MMC_OCR_S18A); aprint_normal(" DDR50"); } + if (ISSET(caps2, SDHC_SDR104_SUPP)) { + SET(hp->ocr, MMC_OCR_S18A); + aprint_normal(" SDR104 HS200"); + } if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) { SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V); aprint_normal(" 1.8V"); @@ -534,6 +535,14 @@ adma_done: saa.saa_caps |= SMC_CAPS_8BIT_MODE; if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED; + if (ISSET(caps2, SDHC_SDR104_SUPP)) + saa.saa_caps |= SMC_CAPS_UHS_SDR104 | + SMC_CAPS_UHS_SDR50 | + SMC_CAPS_MMC_HS200; + if (ISSET(caps2, SDHC_SDR50_SUPP)) + saa.saa_caps |= SMC_CAPS_UHS_SDR50; + if (ISSET(caps2, SDHC_DDR50_SUPP)) + saa.saa_caps |= SMC_CAPS_UHS_DDR50; if (ISSET(hp->flags, SHF_USE_DMA)) { saa.saa_caps |= SMC_CAPS_DMA; if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) @@ -964,7 +973,7 @@ sdhc_clock_divisor(struct sdhc_host *hp, * Return zero on success. */ static int -sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +sdhc_bus_clock_ddr(sdmmc_chipset_handle_t sch, int freq, bool ddr) { struct sdhc_host *hp = (struct sdhc_host *)sch; u_int div; @@ -1007,14 +1016,19 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc } if (hp->specver >= SDHC_SPEC_VERS_300) { - /* XXX DDR */ HCLR2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_MASK); if (freq > 100000) { HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR104); } else if (freq > 50000) { HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR50); } else if (freq > 25000) { - HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR25); + if (ddr) { + HSET2(hp, SDHC_HOST_CTL2, + SDHC_UHS_MODE_SELECT_DDR50); + } else { + HSET2(hp, SDHC_HOST_CTL2, + SDHC_UHS_MODE_SELECT_SDR25); + } } else if (freq > 400) { HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12); } Index: src/sys/dev/sdmmc/sdmmc.c diff -u src/sys/dev/sdmmc/sdmmc.c:1.28 src/sys/dev/sdmmc/sdmmc.c:1.29 --- src/sys/dev/sdmmc/sdmmc.c:1.28 Mon Aug 3 05:32:50 2015 +++ src/sys/dev/sdmmc/sdmmc.c Mon Aug 3 10:08:51 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc.c,v 1.28 2015/08/03 05:32:50 mlelstv Exp $ */ +/* $NetBSD: sdmmc.c,v 1.29 2015/08/03 10:08:51 jmcneill Exp $ */ /* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */ /* @@ -49,7 +49,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.28 2015/08/03 05:32:50 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.29 2015/08/03 10:08:51 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -523,7 +523,8 @@ sdmmc_enable(struct sdmmc_softc *sc) /* * Select the minimum clock frequency. */ - error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_400K); + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_400K, + false); if (error) { aprint_error_dev(sc->sc_dev, "couldn't supply clock\n"); goto out; @@ -569,7 +570,8 @@ sdmmc_disable(struct sdmmc_softc *sc) /* Turn off bus power and clock. */ (void)sdmmc_chip_bus_width(sc->sc_sct, sc->sc_sch, 1); - (void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_OFF); + (void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_OFF, + false); (void)sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, 0); sc->sc_busclk = sc->sc_clkmax; } Index: src/sys/dev/sdmmc/sdmmc_io.c diff -u src/sys/dev/sdmmc/sdmmc_io.c:1.9 src/sys/dev/sdmmc/sdmmc_io.c:1.10 --- src/sys/dev/sdmmc/sdmmc_io.c:1.9 Mon Aug 3 05:32:50 2015 +++ src/sys/dev/sdmmc/sdmmc_io.c Mon Aug 3 10:08:51 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_io.c,v 1.9 2015/08/03 05:32:50 mlelstv Exp $ */ +/* $NetBSD: sdmmc_io.c,v 1.10 2015/08/03 10:08:51 jmcneill Exp $ */ /* $OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $ */ /* @@ -20,7 +20,7 @@ /* Routines for SD I/O cards. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.9 2015/08/03 05:32:50 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.10 2015/08/03 10:08:51 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -231,7 +231,8 @@ sdmmc_io_init(struct sdmmc_softc *sc, st if (sc->sc_busclk > sf->csd.tran_speed) sc->sc_busclk = sf->csd.tran_speed; error = - sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk); + sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk, + false); if (error) aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); Index: src/sys/dev/sdmmc/sdmmc_mem.c diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.38 src/sys/dev/sdmmc/sdmmc_mem.c:1.39 --- src/sys/dev/sdmmc/sdmmc_mem.c:1.38 Mon Aug 3 05:32:50 2015 +++ src/sys/dev/sdmmc/sdmmc_mem.c Mon Aug 3 10:08:51 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_mem.c,v 1.38 2015/08/03 05:32:50 mlelstv Exp $ */ +/* $NetBSD: sdmmc_mem.c,v 1.39 2015/08/03 10:08:51 jmcneill Exp $ */ /* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -45,7 +45,7 @@ /* Routines for SD/MMC memory cards. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.38 2015/08/03 05:32:50 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.39 2015/08/03 10:08:51 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -96,6 +96,27 @@ static int sdmmc_mem_read_block_subr(str static int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t, uint32_t, u_char *, size_t); +static const struct { + const char *name; + int v; + int freq; +} switch_group0_functions[] = { + /* Default/SDR12 */ + { "Default/SDR12", 0, 25000 }, + + /* High-Speed/SDR25 */ + { "High-Speed/SDR25", SMC_CAPS_SD_HIGHSPEED, 50000 }, + + /* SDR50 */ + { "SDR50", SMC_CAPS_UHS_SDR50, 100000 }, + + /* SDR104 */ + { "SDR104", SMC_CAPS_UHS_SDR104, 208000 }, + + /* DDR50 */ + { "DDR50", SMC_CAPS_UHS_DDR50, 50000 }, +}; + /* * Initialize SD/MMC memory cards and memory in SDIO "combo" cards. */ @@ -221,7 +242,7 @@ mmc_mode: * Stop the clock */ error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, - SDMMC_SDCLK_OFF); + SDMMC_SDCLK_OFF, false); if (error) goto out; @@ -241,7 +262,8 @@ mmc_mode: /* * Switch to SDR12 timing */ - error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000); + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000, + false); if (error) goto out; @@ -672,38 +694,39 @@ sdmmc_be512_to_bitfield512(sdmmc_bitfiel } static int +sdmmc_mem_select_transfer_mode(struct sdmmc_softc *sc, int support_func) +{ + if (ISSET(sc->sc_flags, SMF_UHS_MODE)) { + if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR104) && + ISSET(support_func, SD_ACCESS_MODE_SDR104)) { + return SD_ACCESS_MODE_SDR104; + } + if (ISSET(sc->sc_caps, SMC_CAPS_UHS_DDR50) && + ISSET(support_func, SD_ACCESS_MODE_DDR50)) { + return SD_ACCESS_MODE_DDR50; + } + if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR50) && + ISSET(support_func, SD_ACCESS_MODE_SDR50)) { + return SD_ACCESS_MODE_SDR50; + } + } + if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) && + ISSET(support_func, SD_ACCESS_MODE_SDR25)) { + return SD_ACCESS_MODE_SDR25; + } + return SD_ACCESS_MODE_SDR12; +} + +static int sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) { - static const struct { - int v; - int freq; - int uhs; - } switch_group0_functions[] = { - /* Default/SDR12 */ - { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V | - MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V, 25000, 0 }, - - /* High-Speed/SDR25 */ - { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V | - MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V, 50000, 0 }, - - /* SDR50 */ - { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 100000, 1 }, - - /* SDR104 */ - { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 208000, 1 }, - -#if notyet - /* DDR50 */ - { MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V, 50000, 1 }, -#endif - }; - int host_ocr, support_func, best_func, bus_clock, error, g, i; + int support_func, best_func, bus_clock, error, i; sdmmc_bitfield512_t status; /* Switch Function Status */ + bool ddr = false; /* change bus clock */ bus_clock = min(sc->sc_busclk, sf->csd.tran_speed); - error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock); + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock, false); if (error) { aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); return error; @@ -730,6 +753,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc sf->width = 4; } + best_func = 0; if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 && ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) { DPRINTF(("%s: switch func mode 0\n", SDMMCDEVNAME(sc))); @@ -740,22 +764,22 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc return error; } - host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch); support_func = SFUNC_STATUS_GROUP(&status, 1); - DPRINTF(("%s: support_func %#x\n", SDMMCDEVNAME(sc), support_func)); - best_func = 0; - for (i = 0, g = 1; - i < __arraycount(switch_group0_functions); i++, g <<= 1) { - if (!(switch_group0_functions[i].v & host_ocr)) + + for (i = 0; i < __arraycount(switch_group0_functions); i++) { + if (!(support_func & (1 << i))) continue; - if (switch_group0_functions[i].uhs && - !ISSET(sc->sc_flags, SMF_UHS_MODE)) - break; - if (g & support_func) - best_func = i; + DPRINTF(("%s: card supports mode %s\n", + SDMMCDEVNAME(sc), + switch_group0_functions[i].name)); } - if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) && - best_func != 0) { + + best_func = sdmmc_mem_select_transfer_mode(sc, support_func); + + DPRINTF(("%s: using mode %s\n", SDMMCDEVNAME(sc), + switch_group0_functions[best_func].name)); + + if (best_func != 0) { DPRINTF(("%s: switch func mode 1(func=%d)\n", SDMMCDEVNAME(sc), best_func)); error = @@ -770,6 +794,9 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc sf->csd.tran_speed = switch_group0_functions[best_func].freq; + if (best_func == SD_ACCESS_MODE_DDR50) + ddr = true; + /* Wait 400KHz x 8 clock (2.5us * 8 + slop) */ delay(25); } @@ -778,16 +805,20 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc /* update bus clock */ if (sc->sc_busclk > sf->csd.tran_speed) sc->sc_busclk = sf->csd.tran_speed; - if (sc->sc_busclk == bus_clock) + if (sc->sc_busclk == bus_clock && sc->sc_busddr == ddr) return 0; /* change bus clock */ - error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk); + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk, + ddr); if (error) { aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); return error; } + sc->sc_transfer_mode = switch_group0_functions[best_func].name; + sc->sc_busddr = ddr; + return 0; } @@ -797,18 +828,17 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s int width, value, hs_timing, bus_clock, error; char ext_csd[512]; uint32_t sectors = 0; - int host_ocr; + + sc->sc_transfer_mode = NULL; /* change bus clock */ bus_clock = min(sc->sc_busclk, sf->csd.tran_speed); - error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock); + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock, false); if (error) { aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); return error; } - host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch); - if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) { error = sdmmc_mem_send_cxd_data(sc, MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd)); @@ -825,7 +855,8 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s return ENOTSUP; } - if (ISSET(host_ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V) && + sc->sc_transfer_mode = NULL; + if (ISSET(sc->sc_caps, SMC_CAPS_MMC_HS200) && ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_HS200_1_8V) { sf->csd.tran_speed = 200000; /* 200MHz SDR */ hs_timing = 2; @@ -842,7 +873,42 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s return ENOTSUP; } - if (!ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) { + if (hs_timing == 2) { + error = sdmmc_chip_signal_voltage(sc->sc_sct, + sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180); + if (error) + hs_timing = 1; + } + + if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) { + width = 8; + value = EXT_CSD_BUS_WIDTH_8; + } else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) { + width = 4; + value = EXT_CSD_BUS_WIDTH_4; + } else { + width = 1; + value = EXT_CSD_BUS_WIDTH_1; + } + + if (width != 1) { + error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, value); + if (error == 0) + error = sdmmc_chip_bus_width(sc->sc_sct, + sc->sc_sch, width); + else { + DPRINTF(("%s: can't change bus width" + " (%d bit)\n", SDMMCDEVNAME(sc), width)); + return error; + } + + /* XXXX: need bus test? (using by CMD14 & CMD19) */ + } + sf->width = width; + + if (hs_timing == 1 && + !ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) { hs_timing = 0; } if (hs_timing) { @@ -859,7 +925,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s sc->sc_busclk = sf->csd.tran_speed; if (sc->sc_busclk != bus_clock) { error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, - sc->sc_busclk); + sc->sc_busclk, false); if (error) { aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); @@ -891,38 +957,17 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s sf->csd.capacity = sectors; } - if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) { - width = 8; - value = EXT_CSD_BUS_WIDTH_8; - } else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) { - width = 4; - value = EXT_CSD_BUS_WIDTH_4; + if (hs_timing == 2) { + sc->sc_transfer_mode = "HS200"; } else { - width = 1; - value = EXT_CSD_BUS_WIDTH_1; + sc->sc_transfer_mode = NULL; } - - if (width != 1) { - error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, value); - if (error == 0) - error = sdmmc_chip_bus_width(sc->sc_sct, - sc->sc_sch, width); - else { - DPRINTF(("%s: can't change bus width" - " (%d bit)\n", SDMMCDEVNAME(sc), width)); - return error; - } - - /* XXXX: need bus test? (using by CMD14 & CMD19) */ - } - sf->width = width; } else { if (sc->sc_busclk > sf->csd.tran_speed) sc->sc_busclk = sf->csd.tran_speed; if (sc->sc_busclk != bus_clock) { error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, - sc->sc_busclk); + sc->sc_busclk, false); if (error) { aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); @@ -1083,11 +1128,11 @@ sdmmc_mem_decode_scr(struct sdmmc_softc sf->scr.sd_spec = SCR_SD_SPEC(resp); sf->scr.bus_width = SCR_SD_BUS_WIDTHS(resp); - DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x spec=%d, bus width=%d\n", + DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x ver=%d, spec=%d, bus width=%d, spec3=%d\n", SDMMCDEVNAME(sc), resp[1], resp[0], - sf->scr.sd_spec, sf->scr.bus_width)); + ver, sf->scr.sd_spec, sf->scr.bus_width, sf->scr.sd_spec3)); - if (ver != 0) { + if (ver != 0 && ver != 1) { DPRINTF(("%s: unknown structure version: %d\n", SDMMCDEVNAME(sc), ver)); return EINVAL; Index: src/sys/dev/sdmmc/sdmmcchip.h diff -u src/sys/dev/sdmmc/sdmmcchip.h:1.5 src/sys/dev/sdmmc/sdmmcchip.h:1.6 --- src/sys/dev/sdmmc/sdmmcchip.h:1.5 Sun Aug 2 21:44:36 2015 +++ src/sys/dev/sdmmc/sdmmcchip.h Mon Aug 3 10:08:51 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcchip.h,v 1.5 2015/08/02 21:44:36 jmcneill Exp $ */ +/* $NetBSD: sdmmcchip.h,v 1.6 2015/08/03 10:08:51 jmcneill Exp $ */ /* $OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $ */ /* @@ -60,6 +60,7 @@ struct sdmmc_chip_functions { /* UHS functions */ int (*signal_voltage)(sdmmc_chipset_handle_t, int); + int (*bus_clock_ddr)(sdmmc_chipset_handle_t, int, bool); }; /* host controller reset */ @@ -79,8 +80,8 @@ struct sdmmc_chip_functions { /* bus power, clock frequency, width and rod */ #define sdmmc_chip_bus_power(tag, handle, ocr) \ ((tag)->bus_power((handle), (ocr))) -#define sdmmc_chip_bus_clock(tag, handle, freq) \ - ((tag)->bus_clock((handle), (freq))) +#define sdmmc_chip_bus_clock(tag, handle, freq, ddr) \ + ((tag)->bus_clock_ddr ? (tag)->bus_clock_ddr((handle), (freq), (ddr)) : ((ddr) ? EINVAL : ((tag)->bus_clock((handle), (freq))))) #define sdmmc_chip_bus_width(tag, handle, width) \ ((tag)->bus_width((handle), (width))) #define sdmmc_chip_bus_rod(tag, handle, width) \ Index: src/sys/dev/sdmmc/sdmmcreg.h diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.17 src/sys/dev/sdmmc/sdmmcreg.h:1.18 --- src/sys/dev/sdmmc/sdmmcreg.h:1.17 Sun Aug 2 22:47:05 2015 +++ src/sys/dev/sdmmc/sdmmcreg.h Mon Aug 3 10:08:51 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcreg.h,v 1.17 2015/08/02 22:47:05 jmcneill Exp $ */ +/* $NetBSD: sdmmcreg.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $ */ /* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -334,6 +334,12 @@ #define SFUNC_STATUS_GROUP(status, group) \ (__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16)) +#define SD_ACCESS_MODE_SDR12 0 +#define SD_ACCESS_MODE_SDR25 1 +#define SD_ACCESS_MODE_SDR50 2 +#define SD_ACCESS_MODE_SDR104 3 +#define SD_ACCESS_MODE_DDR50 4 + /* This assumes the response fields are in host byte order in 32-bit units. */ #define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len)) static inline uint32_t Index: src/sys/dev/sdmmc/sdmmcvar.h diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.17 src/sys/dev/sdmmc/sdmmcvar.h:1.18 --- src/sys/dev/sdmmc/sdmmcvar.h:1.17 Sun Aug 2 21:44:36 2015 +++ src/sys/dev/sdmmc/sdmmcvar.h Mon Aug 3 10:08:51 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcvar.h,v 1.17 2015/08/02 21:44:36 jmcneill Exp $ */ +/* $NetBSD: sdmmcvar.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $ */ /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -229,6 +229,11 @@ struct sdmmc_softc { #define SMC_CAPS_MULTI_SEG_DMA 0x0080 /* multiple segment DMA transfer */ #define SMC_CAPS_SD_HIGHSPEED 0x0100 /* SD high-speed timing */ #define SMC_CAPS_MMC_HIGHSPEED 0x0200 /* MMC high-speed timing */ +#define SMC_CAPS_UHS_SDR50 0x1000 /* UHS SDR50 timing */ +#define SMC_CAPS_UHS_SDR104 0x2000 /* UHS SDR104 timing */ +#define SMC_CAPS_UHS_DDR50 0x4000 /* UHS DDR50 timing */ +#define SMC_CAPS_UHS_MASK 0x7000 +#define SMC_CAPS_MMC_HS200 0x8000 /* eMMC HS200 timing */ /* function */ int sc_function_count; /* number of I/O functions (SDIO) */ @@ -254,7 +259,9 @@ struct sdmmc_softc { u_int sc_clkmin; /* host min bus clock */ u_int sc_clkmax; /* host max bus clock */ u_int sc_busclk; /* host bus clock */ + bool sc_busddr; /* host bus clock is in DDR mode */ int sc_buswidth; /* host bus width */ + const char *sc_transfer_mode; /* current transfer mode */ callout_t sc_card_detect_ch; /* polling card insert/remove */ };