diff options
author | 2020-08-14 14:49:04 +0000 | |
---|---|---|
committer | 2020-08-14 14:49:04 +0000 | |
commit | a62fc20a112dc2cec994ce46422c87e62e6d4cae (patch) | |
tree | eacf1bb59ee4206b2a43b13713189b07f61684a7 | |
parent | Don't build double-double functions since long double is the same as double (diff) | |
download | wireguard-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.c | 34 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_mem.c | 161 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcchip.h | 12 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcreg.h | 17 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcvar.h | 12 |
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 */ |