summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2020-08-14 14:49:04 +0000
committerkettenis <kettenis@openbsd.org>2020-08-14 14:49:04 +0000
commita62fc20a112dc2cec994ce46422c87e62e6d4cae (patch)
treeeacf1bb59ee4206b2a43b13713189b07f61684a7
parentDon't build double-double functions since long double is the same as double (diff)
downloadwireguard-openbsd-a62fc20a112dc2cec994ce46422c87e62e6d4cae.tar.xz
wireguard-openbsd-a62fc20a112dc2cec994ce46422c87e62e6d4cae.zip
Add support for eMMC HS200 mode. Loosely based on code from NetBSD.
ok patrick@
-rw-r--r--sys/dev/sdmmc/sdhc.c34
-rw-r--r--sys/dev/sdmmc/sdmmc_mem.c161
-rw-r--r--sys/dev/sdmmc/sdmmcchip.h12
-rw-r--r--sys/dev/sdmmc/sdmmcreg.h17
-rw-r--r--sys/dev/sdmmc/sdmmcvar.h12
5 files changed, 164 insertions, 72 deletions
diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c
index 591762af459..b07eb273184 100644
--- a/sys/dev/sdmmc/sdhc.c
+++ b/sys/dev/sdmmc/sdhc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhc.c,v 1.68 2020/06/14 18:37:16 patrick Exp $ */
+/* $OpenBSD: sdhc.c,v 1.69 2020/08/14 14:49:04 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -121,26 +121,18 @@ void sdhc_dump_regs(struct sdhc_host *);
#endif
struct sdmmc_chip_functions sdhc_functions = {
- /* host controller reset */
- sdhc_host_reset,
- /* host controller capabilities */
- sdhc_host_ocr,
- sdhc_host_maxblklen,
- /* card detection */
- sdhc_card_detect,
- /* bus power and clock frequency */
- sdhc_bus_power,
- sdhc_bus_clock,
- sdhc_bus_width,
- /* command execution */
- sdhc_exec_command,
- /* card interrupt */
- sdhc_card_intr_mask,
- sdhc_card_intr_ack,
- /* UHS functions */
- sdhc_signal_voltage,
- /* hibernate */
- sdhc_hibernate_init,
+ .host_reset = sdhc_host_reset,
+ .host_ocr = sdhc_host_ocr,
+ .host_maxblklen = sdhc_host_maxblklen,
+ .card_detect = sdhc_card_detect,
+ .bus_power = sdhc_bus_power,
+ .bus_clock = sdhc_bus_clock,
+ .bus_width = sdhc_bus_width,
+ .exec_command = sdhc_exec_command,
+ .card_intr_mask = sdhc_card_intr_mask,
+ .card_intr_ack = sdhc_card_intr_ack,
+ .signal_voltage = sdhc_signal_voltage,
+ .hibernate_init = sdhc_hibernate_init,
};
struct cfdriver sdhc_cd = {
diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c
index 9412593de04..fcbc2349c51 100644
--- a/sys/dev/sdmmc/sdmmc_mem.c
+++ b/sys/dev/sdmmc/sdmmc_mem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmc_mem.c,v 1.33 2018/06/04 13:33:10 patrick Exp $ */
+/* $OpenBSD: sdmmc_mem.c,v 1.34 2020/08/14 14:49:04 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -70,6 +70,34 @@ int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t,
#define DPRINTF(s) /**/
#endif
+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 },
+};
+
+const int sdmmc_mmc_timings[] = {
+ [SDMMC_TIMING_LEGACY] = 26000,
+ [SDMMC_TIMING_HIGHSPEED] = 52000,
+ [SDMMC_TIMING_MMC_DDR52] = 52000,
+ [SDMMC_TIMING_MMC_HS200] = 200000
+};
+
/*
* Initialize SD/MMC memory cards and memory in SDIO "combo" cards.
*/
@@ -581,6 +609,41 @@ sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *buf) {
}
int
+sdmmc_mem_execute_tuning(struct sdmmc_softc *sc, struct sdmmc_function *sf)
+{
+ int timing = -1;
+
+ if (ISSET(sc->sc_flags, SMF_SD_MODE)) {
+ if (!ISSET(sc->sc_flags, SMF_UHS_MODE))
+ return 0;
+
+ switch (sf->csd.tran_speed) {
+ case 100000:
+ timing = SDMMC_TIMING_UHS_SDR50;
+ break;
+ case 208000:
+ timing = SDMMC_TIMING_UHS_SDR104;
+ break;
+ default:
+ return 0;
+ }
+ } else {
+ switch (sf->csd.tran_speed) {
+ case 200000:
+ timing = SDMMC_TIMING_MMC_HS200;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ DPRINTF(("%s: execute tuning for timing %d\n", SDMMCDEVNAME(sc),
+ timing));
+
+ return sdmmc_chip_execute_tuning(sc->sct, sc->sch, timing);
+}
+
+int
sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
{
int support_func, best_func, error;
@@ -647,6 +710,8 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
DEVNAME(sc), best_func, support_func);
return error;
}
+ sf->csd.tran_speed =
+ switch_group0_functions[best_func].freq;
/* Wait 400KHz x 8 clock (2.5us * 8 + slop) */
delay(25);
@@ -692,7 +757,11 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
card_type = ext_csd[EXT_CSD_CARD_TYPE];
- if (card_type & EXT_CSD_CARD_TYPE_F_52M_1_8V &&
+ if (card_type & EXT_CSD_CARD_TYPE_F_HS200_1_8V &&
+ ISSET(sc->sc_caps, SMC_CAPS_MMC_HS200)) {
+ speed = 200000;
+ timing = SDMMC_TIMING_MMC_HS200;
+ } else if (card_type & EXT_CSD_CARD_TYPE_F_DDR52_1_8V &&
ISSET(sc->sc_caps, SMC_CAPS_MMC_DDR52)) {
speed = 52000;
timing = SDMMC_TIMING_MMC_DDR52;
@@ -707,39 +776,6 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
ext_csd[EXT_CSD_CARD_TYPE]);
}
- if (timing != SDMMC_TIMING_LEGACY) {
- /* switch to high speed timing */
- error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HS_TIMING, EXT_CSD_HS_TIMING_HS);
- if (error != 0) {
- printf("%s: can't change high speed\n",
- DEVNAME(sc));
- return error;
- }
-
- sdmmc_delay(10000);
- }
-
- error = sdmmc_chip_bus_clock(sc->sct, sc->sch, speed, SDMMC_TIMING_HIGHSPEED);
- if (error != 0) {
- printf("%s: can't change bus clock\n", DEVNAME(sc));
- return error;
- }
-
- if (timing != SDMMC_TIMING_LEGACY) {
- /* read EXT_CSD again */
- error = sdmmc_mem_send_cxd_data(sc,
- MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd));
- if (error != 0) {
- printf("%s: can't re-read EXT_CSD\n", DEVNAME(sc));
- return error;
- }
- if (ext_csd[EXT_CSD_HS_TIMING] != EXT_CSD_HS_TIMING_HS) {
- printf("%s, HS_TIMING set failed\n", DEVNAME(sc));
- return EINVAL;
- }
- }
-
if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) {
width = 8;
value = EXT_CSD_BUS_WIDTH_8;
@@ -767,6 +803,52 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
sdmmc_delay(10000);
}
+ if (timing != SDMMC_TIMING_LEGACY) {
+ switch (timing) {
+ case SDMMC_TIMING_MMC_HS200:
+ value = EXT_CSD_HS_TIMING_HS200;
+ break;
+ case SDMMC_TIMING_MMC_DDR52:
+ case SDMMC_TIMING_HIGHSPEED:
+ value = EXT_CSD_HS_TIMING_HS;
+ break;
+ }
+
+ /* switch to high speed timing */
+ error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, value);
+ if (error != 0) {
+ printf("%s: can't change timing\n",
+ DEVNAME(sc));
+ return error;
+ }
+
+ sdmmc_delay(10000);
+ }
+
+ KASSERT(timing < nitems(sdmmc_mmc_timings));
+ sf->csd.tran_speed = sdmmc_mmc_timings[timing];
+
+ if (timing != SDMMC_TIMING_LEGACY) {
+ /* read EXT_CSD again */
+ error = sdmmc_mem_send_cxd_data(sc,
+ MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd));
+ if (error != 0) {
+ printf("%s: can't re-read EXT_CSD\n", DEVNAME(sc));
+ return error;
+ }
+ if (ext_csd[EXT_CSD_HS_TIMING] != value) {
+ printf("%s, HS_TIMING set failed\n", DEVNAME(sc));
+ return EINVAL;
+ }
+ }
+
+ error = sdmmc_chip_bus_clock(sc->sct, sc->sch, speed, SDMMC_TIMING_HIGHSPEED);
+ if (error != 0) {
+ printf("%s: can't change bus clock\n", DEVNAME(sc));
+ return error;
+ }
+
if (timing == SDMMC_TIMING_MMC_DDR52) {
switch (width) {
case 4:
@@ -813,6 +895,15 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
sf->flags |= SFF_SDHC;
sf->csd.capacity = sectors;
}
+
+ if (timing == SDMMC_TIMING_MMC_HS200) {
+ /* execute tuning (HS200) */
+ error = sdmmc_mem_execute_tuning(sc, sf);
+ if (error) {
+ printf("%s: can't execute MMC tuning\n", DEVNAME(sc));
+ return error;
+ }
+ }
}
return error;
diff --git a/sys/dev/sdmmc/sdmmcchip.h b/sys/dev/sdmmc/sdmmcchip.h
index 14e2568c021..042f6993f45 100644
--- a/sys/dev/sdmmc/sdmmcchip.h
+++ b/sys/dev/sdmmc/sdmmcchip.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmcchip.h,v 1.13 2018/12/29 11:37:30 patrick Exp $ */
+/* $OpenBSD: sdmmcchip.h,v 1.14 2020/08/14 14:49:04 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -45,7 +45,8 @@ struct sdmmc_chip_functions {
void (*card_intr_mask)(sdmmc_chipset_handle_t, int);
void (*card_intr_ack)(sdmmc_chipset_handle_t);
/* UHS functions */
- int (*signal_voltage)(sdmmc_chipset_handle_t, int);
+ int (*signal_voltage)(sdmmc_chipset_handle_t, int);
+ int (*execute_tuning)(sdmmc_chipset_handle_t, int);
/* hibernate */
int (*hibernate_init)(sdmmc_chipset_handle_t, void *);
};
@@ -79,6 +80,8 @@ struct sdmmc_chip_functions {
/* UHS functions */
#define sdmmc_chip_signal_voltage(tag, handle, voltage) \
((tag)->signal_voltage((handle), (voltage)))
+#define sdmmc_chip_execute_tuning(tag, handle, timing) \
+ ((tag)->execute_tuning((handle), (timing)))
/* clock frequencies for sdmmc_chip_bus_clock() */
#define SDMMC_SDCLK_OFF 0
@@ -92,7 +95,10 @@ struct sdmmc_chip_functions {
#define SDMMC_TIMING_LEGACY 0
#define SDMMC_TIMING_HIGHSPEED 1
-#define SDMMC_TIMING_MMC_DDR52 2
+#define SDMMC_TIMING_UHS_SDR50 2
+#define SDMMC_TIMING_UHS_SDR104 3
+#define SDMMC_TIMING_MMC_DDR52 4
+#define SDMMC_TIMING_MMC_HS200 5
#define SDMMC_MAX_FUNCTIONS 8
diff --git a/sys/dev/sdmmc/sdmmcreg.h b/sys/dev/sdmmc/sdmmcreg.h
index c984afc9f78..a9f12fe3af6 100644
--- a/sys/dev/sdmmc/sdmmcreg.h
+++ b/sys/dev/sdmmc/sdmmcreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmcreg.h,v 1.11 2016/05/05 11:01:08 kettenis Exp $ */
+/* $OpenBSD: sdmmcreg.h,v 1.12 2020/08/14 14:49:04 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -33,6 +33,8 @@
#define MMC_SET_BLOCKLEN 16 /* R1 */
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
+#define MMC_SEND_TUNING_BLOCK 19 /* R1 */
+#define MMC_SEND_TUNING_BLOCK_HS200 21 /* R1 */
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
@@ -122,13 +124,12 @@
* 0x0B and 0x0F. */
#define EXT_CSD_CARD_TYPE_F_26M (1 << 0)
#define EXT_CSD_CARD_TYPE_F_52M (1 << 1)
-#define EXT_CSD_CARD_TYPE_F_52M_1_8V (1 << 2)
-#define EXT_CSD_CARD_TYPE_F_52M_1_2V (1 << 3)
-#define EXT_CSD_CARD_TYPE_26M 0x01
-#define EXT_CSD_CARD_TYPE_52M 0x03
-#define EXT_CSD_CARD_TYPE_52M_V18 0x07
-#define EXT_CSD_CARD_TYPE_52M_V12 0x0b
-#define EXT_CSD_CARD_TYPE_52M_V12_18 0x0f
+#define EXT_CSD_CARD_TYPE_F_DDR52_1_8V (1 << 2)
+#define EXT_CSD_CARD_TYPE_F_DDR52_1_2V (1 << 3)
+#define EXT_CSD_CARD_TYPE_F_HS200_1_8V (1 << 4)
+#define EXT_CSD_CARD_TYPE_F_HS200_1_2V (1 << 5)
+#define EXT_CSD_CARD_TYPE_F_HS400_1_8V (1 << 6)
+#define EXT_CSD_CARD_TYPE_F_HS400_1_2V (1 << 7)
/* MMC_SWITCH access mode */
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h
index 61dc0dad74d..4ef6d87c678 100644
--- a/sys/dev/sdmmc/sdmmcvar.h
+++ b/sys/dev/sdmmc/sdmmcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmcvar.h,v 1.33 2020/07/03 13:31:47 krw Exp $ */
+/* $OpenBSD: sdmmcvar.h,v 1.34 2020/08/14 14:49:04 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -36,6 +36,7 @@ struct sdmmc_csd {
int capacity; /* total number of sectors */
int sector_size; /* sector size in bytes */
int read_bl_len; /* block length for reads */
+ int tran_speed; /* transfer speed (kbit/s) */
int ccc; /* Card Command Class for SD */
/* ... */
};
@@ -177,10 +178,11 @@ struct sdmmc_softc {
#define SMF_SD_MODE 0x0001 /* host in SD mode (MMC otherwise) */
#define SMF_IO_MODE 0x0002 /* host in I/O mode (SD mode only) */
#define SMF_MEM_MODE 0x0004 /* host in memory mode (SD or MMC) */
-#define SMF_CARD_PRESENT 0x0010 /* card presence noticed */
-#define SMF_CARD_ATTACHED 0x0020 /* card driver(s) attached */
-#define SMF_STOP_AFTER_MULTIPLE 0x0040 /* send a stop after a multiple cmd */
-#define SMF_CONFIG_PENDING 0x0080 /* config_pending_incr() called */
+#define SMF_UHS_MODE 0x0010 /* host in UHS mode */
+#define SMF_CARD_PRESENT 0x0020 /* card presence noticed */
+#define SMF_CARD_ATTACHED 0x0040 /* card driver(s) attached */
+#define SMF_STOP_AFTER_MULTIPLE 0x0080 /* send a stop after a multiple cmd */
+#define SMF_CONFIG_PENDING 0x0100 /* config_pending_incr() called */
uint32_t sc_caps; /* host capability */
#define SMC_CAPS_AUTO_STOP 0x0001 /* send CMD12 automagically by host */