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 */
};