Module Name: src Committed By: jmcneill Date: Sun Aug 2 21:45:12 UTC 2015
Modified Files: src/sys/dev/sdmmc: sdhc.c sdhcreg.h Log Message: add support for UHS-I modes on capable 3.0+ controllers To generate a diff of this commit: cvs rdiff -u -r1.70 -r1.71 src/sys/dev/sdmmc/sdhc.c cvs rdiff -u -r1.14 -r1.15 src/sys/dev/sdmmc/sdhcreg.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.70 src/sys/dev/sdmmc/sdhc.c:1.71 --- src/sys/dev/sdmmc/sdhc.c:1.70 Sun Aug 2 11:28:01 2015 +++ src/sys/dev/sdmmc/sdhc.c Sun Aug 2 21:45:12 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.70 2015/08/02 11:28:01 jmcneill Exp $ */ +/* $NetBSD: sdhc.c,v 1.71 2015/08/02 21:45:12 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.70 2015/08/02 11:28:01 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.71 2015/08/02 21:45:12 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -181,6 +181,7 @@ static void sdhc_card_enable_intr(sdmmc_ static void sdhc_card_intr_ack(sdmmc_chipset_handle_t); static void sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); +static int sdhc_signal_voltage(sdmmc_chipset_handle_t, int); static int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); static int sdhc_wait_state(struct sdhc_host *, uint32_t, uint32_t); static int sdhc_soft_reset(struct sdhc_host *, int); @@ -218,7 +219,10 @@ static struct sdmmc_chip_functions sdhc_ /* card interrupt */ .card_enable_intr = sdhc_card_enable_intr, - .card_intr_ack = sdhc_card_intr_ack + .card_intr_ack = sdhc_card_intr_ack, + + /* UHS functions */ + .signal_voltage = sdhc_signal_voltage, }; static int @@ -249,7 +253,7 @@ sdhc_host_found(struct sdhc_softc *sc, b { struct sdmmcbus_attach_args saa; struct sdhc_host *hp; - uint32_t caps; + uint32_t caps, caps2; uint16_t sdhcver; int error; @@ -314,6 +318,11 @@ sdhc_host_found(struct sdhc_softc *sc, b } else { caps = HREAD4(hp, SDHC_CAPABILITIES); } + if (hp->specver >= SDHC_SPEC_VERS_300) { + caps2 = HREAD4(hp, SDHC_CAPABILITIES2); + } else { + caps2 = 0; + } /* * Use DMA if the host system and the controller support it. @@ -402,11 +411,21 @@ sdhc_host_found(struct sdhc_softc *sc, b aprint_normal(","); if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) { SET(hp->ocr, MMC_OCR_HCS); - aprint_normal(" High-Speed"); + aprint_normal(" HS"); + } + if (ISSET(caps2, SDHC_SDR50_SUPP)) { + 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(caps, SDHC_VOLTAGE_SUPP_1_8V) && - (hp->specver < SDHC_SPEC_VERS_300 || - ISSET(caps, SDHC_EMBEDDED_SLOT))) { + 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"); } @@ -812,7 +831,7 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc * Select the lowest voltage according to capabilities. */ ocr &= hp->ocr; - if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V)) { + if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V|MMC_OCR_S18A)) { vdd = SDHC_VOLTAGE_1_8V; } else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V)) { vdd = SDHC_VOLTAGE_3_0V; @@ -986,6 +1005,20 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc goto out; } + 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); + } else { + HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12); + } + } + /* * Set the minimum base clock frequency divisor. */ @@ -1155,6 +1188,25 @@ sdhc_card_intr_ack(sdmmc_chipset_handle_ } static int +sdhc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage) +{ + struct sdhc_host *hp = (struct sdhc_host *)sch; + + switch (signal_voltage) { + case SDMMC_SIGNAL_VOLTAGE_180: + HSET2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN); + break; + case SDMMC_SIGNAL_VOLTAGE_330: + HCLR2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN); + break; + default: + return EINVAL; + } + + return 0; +} + +static int sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value) { uint32_t state; Index: src/sys/dev/sdmmc/sdhcreg.h diff -u src/sys/dev/sdmmc/sdhcreg.h:1.14 src/sys/dev/sdmmc/sdhcreg.h:1.15 --- src/sys/dev/sdmmc/sdhcreg.h:1.14 Wed Jul 29 12:11:14 2015 +++ src/sys/dev/sdmmc/sdhcreg.h Sun Aug 2 21:45:12 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhcreg.h,v 1.14 2015/07/29 12:11:14 jmcneill Exp $ */ +/* $NetBSD: sdhcreg.h,v 1.15 2015/08/02 21:45:12 jmcneill Exp $ */ /* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */ /* @@ -142,6 +142,15 @@ #define SDHC_EINTR_SIGNAL_EN 0x3a #define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */ #define SDHC_CMD12_ERROR_STATUS 0x3c +#define SDHC_HOST_CTL2 0x3e +#define SDHC_1_8V_SIGNAL_EN (1<<3) +#define SDHC_UHS_MODE_SELECT_SHIFT 0 +#define SDHC_UHS_MODE_SELECT_MASK 0x7 +#define SDHC_UHS_MODE_SELECT_SDR12 0 +#define SDHC_UHS_MODE_SELECT_SDR25 1 +#define SDHC_UHS_MODE_SELECT_SDR50 2 +#define SDHC_UHS_MODE_SELECT_SDR104 3 +#define SDHC_UHS_MODE_SELECT_DDR50 4 #define SDHC_CAPABILITIES 0x40 #define SDHC_SHARED_BUS_SLOT (1<<31) #define SDHC_EMBEDDED_SLOT (1<<30) @@ -167,6 +176,20 @@ #define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */ #define SDHC_TIMEOUT_FREQ_SHIFT 0 #define SDHC_TIMEOUT_FREQ_MASK 0x1f +#define SDHC_CAPABILITIES2 0x44 +#define SDHC_SDR50_SUPP (1<<0) +#define SDHC_SDR104_SUPP (1<<1) +#define SDHC_DDR50_SUPP (1<<2) +#define SDHC_DRIVER_TYPE_A (1<<4) +#define SDHC_DRIVER_TYPE_C (1<<5) +#define SDHC_DRIVER_TYPE_D (1<<6) +#define SDHC_TIMER_COUNT_SHIFT 8 +#define SDHC_TIMER_COUNT_MASK 0xf +#define SDHC_TUNING_SDR50 (1<<13) +#define SDHC_RETUNING_MODES_SHIFT 14 +#define SDHC_RETUNING_MODES_MASK 0x3 +#define SDHC_CLOCK_MULTIPLIER_SHIFT 16 +#define SDHC_CLOCK_MULTIPLIER_MASK 0xff #define SDHC_ADMA_ERROR_STATUS 0x54 #define SDHC_ADMA_LENGTH_MISMATCH (1<<2) #define SDHC_ADMA_ERROR_STATE (3<<0)