Module Name: src Committed By: jmcneill Date: Sun Aug 2 21:44:36 UTC 2015
Modified Files: src/sys/dev/sdmmc: sdmmc_mem.c sdmmcchip.h sdmmcreg.h sdmmcvar.h Log Message: Add basic UHS-I support. SDR50 and SDR104 are supported, but not DDR50. To generate a diff of this commit: cvs rdiff -u -r1.34 -r1.35 src/sys/dev/sdmmc/sdmmc_mem.c cvs rdiff -u -r1.4 -r1.5 src/sys/dev/sdmmc/sdmmcchip.h cvs rdiff -u -r1.15 -r1.16 src/sys/dev/sdmmc/sdmmcreg.h cvs rdiff -u -r1.16 -r1.17 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/sdmmc_mem.c diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.34 src/sys/dev/sdmmc/sdmmc_mem.c:1.35 --- src/sys/dev/sdmmc/sdmmc_mem.c:1.34 Fri Feb 27 16:08:17 2015 +++ src/sys/dev/sdmmc/sdmmc_mem.c Sun Aug 2 21:44:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_mem.c,v 1.34 2015/02/27 16:08:17 nonaka Exp $ */ +/* $NetBSD: sdmmc_mem.c,v 1.35 2015/08/02 21:44:36 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.34 2015/02/27 16:08:17 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.35 2015/08/02 21:44:36 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -104,6 +104,7 @@ sdmmc_mem_enable(struct sdmmc_softc *sc) { uint32_t host_ocr; uint32_t card_ocr; + uint32_t new_ocr; uint32_t ocr = 0; int error; @@ -184,19 +185,78 @@ mmc_mode: error = sdmmc_mem_send_if_cond(sc, 0x1aa, &card_ocr); if (error == 0 && card_ocr == 0x1aa) SET(ocr, MMC_OCR_HCS); + + if (sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch) & MMC_OCR_S18A) + SET(ocr, MMC_OCR_S18A); } host_ocr |= ocr; /* Send the new OCR value until all cards are ready. */ - error = sdmmc_mem_send_op_cond(sc, host_ocr, NULL); + error = sdmmc_mem_send_op_cond(sc, host_ocr, &new_ocr); if (error) { DPRINTF(("%s: couldn't send memory OCR\n", SDMMCDEVNAME(sc))); goto out; } + if (ISSET(new_ocr, MMC_OCR_S18A) && sc->sc_sct->signal_voltage) { + /* + * Card and host support low voltage mode, begin switch + * sequence. + */ + struct sdmmc_command cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.c_arg = 0; + cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1; + cmd.c_opcode = SD_VOLTAGE_SWITCH; + error = sdmmc_mmc_command(sc, &cmd); + if (error) { + DPRINTF(("%s: voltage switch command failed\n", + SDMMCDEVNAME(sc))); + goto out; + } + + delay(1000); + + /* + * Stop the clock + */ + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, + SDMMC_SDCLK_OFF); + if (error) + goto out; + + delay(1000); + + /* + * Card switch command was successful, update host controller + * signal voltage setting. + */ + error = sdmmc_chip_signal_voltage(sc->sc_sct, + sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180); + if (error) + goto out; + + delay(5000); + + /* + * Switch to SDR12 timing + */ + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000); + if (error) + goto out; + + delay(1000); + + SET(sc->sc_flags, SMF_UHS_MODE); + } + out: SDMMC_UNLOCK(sc); + if (error) + printf("%s: %s failed with error %d\n", SDMMCDEVNAME(sc), + __func__, error); + return error; } @@ -617,23 +677,26 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc 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 }, + 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 }, + 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 }, + { 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 }, + { 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 }, + { 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; sdmmc_bitfield512_t status; /* Switch Function Status */ @@ -684,6 +747,9 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc i < __arraycount(switch_group0_functions); i++, g <<= 1) { if (!(switch_group0_functions[i].v & host_ocr)) continue; + if (switch_group0_functions[i].uhs && + !ISSET(sc->sc_flags, SMF_UHS_MODE)) + break; if (g & support_func) best_func = i; } Index: src/sys/dev/sdmmc/sdmmcchip.h diff -u src/sys/dev/sdmmc/sdmmcchip.h:1.4 src/sys/dev/sdmmc/sdmmcchip.h:1.5 --- src/sys/dev/sdmmc/sdmmcchip.h:1.4 Wed May 18 01:07:17 2011 +++ src/sys/dev/sdmmc/sdmmcchip.h Sun Aug 2 21:44:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcchip.h,v 1.4 2011/05/18 01:07:17 dyoung Exp $ */ +/* $NetBSD: sdmmcchip.h,v 1.5 2015/08/02 21:44:36 jmcneill Exp $ */ /* $OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $ */ /* @@ -57,6 +57,9 @@ struct sdmmc_chip_functions { /* card interrupt */ void (*card_enable_intr)(sdmmc_chipset_handle_t, int); void (*card_intr_ack)(sdmmc_chipset_handle_t); + + /* UHS functions */ + int (*signal_voltage)(sdmmc_chipset_handle_t, int); }; /* host controller reset */ @@ -90,11 +93,18 @@ struct sdmmc_chip_functions { ((tag)->card_enable_intr((handle), (enable))) #define sdmmc_chip_card_intr_ack(tag, handle) \ ((tag)->card_intr_ack((handle))) +/* UHS functions */ +#define sdmmc_chip_signal_voltage(tag, handle, voltage) \ + ((tag)->signal_voltage((handle), (voltage))) /* clock frequencies for sdmmc_chip_bus_clock() */ #define SDMMC_SDCLK_OFF 0 #define SDMMC_SDCLK_400K 400 +/* voltage levels for sdmmc_chip_signal_voltage() */ +#define SDMMC_SIGNAL_VOLTAGE_330 0 +#define SDMMC_SIGNAL_VOLTAGE_180 1 + /* SPI mode */ struct sdmmc_spi_chip_functions { /* card initialize */ Index: src/sys/dev/sdmmc/sdmmcreg.h diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.15 src/sys/dev/sdmmc/sdmmcreg.h:1.16 --- src/sys/dev/sdmmc/sdmmcreg.h:1.15 Sun Dec 7 20:07:25 2014 +++ src/sys/dev/sdmmc/sdmmcreg.h Sun Aug 2 21:44:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcreg.h,v 1.15 2014/12/07 20:07:25 jmcneill Exp $ */ +/* $NetBSD: sdmmcreg.h,v 1.16 2015/08/02 21:44:36 jmcneill Exp $ */ /* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -58,6 +58,7 @@ #define SD_SEND_RELATIVE_ADDR 3 /* R6 */ #define SD_SEND_SWITCH_FUNC 6 /* R1 */ #define SD_SEND_IF_COND 8 /* R7 */ +#define SD_VOLTAGE_SWITCH 11 /* R1 */ /* SD application commands */ /* response type */ #define SD_APP_SET_BUS_WIDTH 6 /* R1 */ @@ -68,6 +69,7 @@ /* OCR bits */ #define MMC_OCR_MEM_READY (1U<<31)/* memory power-up status bit */ #define MMC_OCR_HCS (1<<30) +#define MMC_OCR_S18A (1<<24) #define MMC_OCR_3_5V_3_6V (1<<23) #define MMC_OCR_3_4V_3_5V (1<<22) #define MMC_OCR_3_3V_3_4V (1<<21) Index: src/sys/dev/sdmmc/sdmmcvar.h diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.16 src/sys/dev/sdmmc/sdmmcvar.h:1.17 --- src/sys/dev/sdmmc/sdmmcvar.h:1.16 Fri Feb 27 16:08:17 2015 +++ src/sys/dev/sdmmc/sdmmcvar.h Sun Aug 2 21:44:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcvar.h,v 1.16 2015/02/27 16:08:17 nonaka Exp $ */ +/* $NetBSD: sdmmcvar.h,v 1.17 2015/08/02 21:44:36 jmcneill Exp $ */ /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -216,6 +216,7 @@ struct sdmmc_softc { #define SMF_MEM_MODE 0x0008 /* host in memory mode (SD or MMC) */ #define SMF_CARD_PRESENT 0x4000 /* card presence noticed */ #define SMF_CARD_ATTACHED 0x8000 /* card driver(s) attached */ +#define SMF_UHS_MODE 0x10000 /* host in UHS mode */ uint32_t sc_caps; /* host capability */ #define SMC_CAPS_AUTO_STOP 0x0001 /* send CMD12 automagically by host */