diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-01-11 06:54:54 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-01-11 06:54:54 +0000 |
commit | 67bd1cddd3db45698dfa321681211045786b7374 (patch) | |
tree | daf2f0521c0b3565ac8f1c3343af47bd4bb502b3 /sys/dev/sdmmc | |
parent | 0a2177d95505019241dc20999f31057f910edd93 (diff) |
Add (limited) support for controllers that implement version 3.0 of the
SD host controller standard. Support the larger base clock and larger
clock divisors.
ok jsg@
Diffstat (limited to 'sys/dev/sdmmc')
-rw-r--r-- | sys/dev/sdmmc/sdhc.c | 36 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdhcreg.h | 18 |
2 files changed, 46 insertions, 8 deletions
diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c index 0fbb05f7ef0..dd810c0eec3 100644 --- a/sys/dev/sdmmc/sdhc.c +++ b/sys/dev/sdmmc/sdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhc.c,v 1.40 2016/01/10 14:11:43 kettenis Exp $ */ +/* $OpenBSD: sdhc.c,v 1.41 2016/01/11 06:54:53 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -42,6 +42,7 @@ struct sdhc_host { struct device *sdmmc; /* generic SD/MMC device */ bus_space_tag_t iot; /* host register set tag */ bus_space_handle_t ioh; /* host register set handle */ + u_int16_t version; /* specification version */ u_int clkbase; /* base clock frequency in KHz */ int maxblklen; /* maximum block length */ int flags; /* flags for this host */ @@ -133,6 +134,7 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, struct sdmmcbus_attach_args saa; struct sdhc_host *hp; int error = 1; + int max_clock; #ifdef SDHC_DEBUG u_int16_t version; @@ -159,6 +161,9 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, hp->iot = iot; hp->ioh = ioh; + /* Store specification version. */ + hp->version = bus_space_read_2(iot, ioh, SDHC_HOST_CTL_VERSION); + /* * Reset the host controller and enable interrupts. */ @@ -175,15 +180,23 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, /* * Determine the base clock frequency. (2.2.24) */ - if (SDHC_BASE_FREQ_KHZ(caps) != 0) - hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); + if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) { + /* SDHC 3.0 supports 10-255 MHz. */ + max_clock = 255000; + if (SDHC_BASE_FREQ_KHZ_V3(caps) != 0) + hp->clkbase = SDHC_BASE_FREQ_KHZ_V3(caps); + } else { + /* SDHC 1.0/2.0 supports only 10-63 MHz. */ + max_clock = 63000; + if (SDHC_BASE_FREQ_KHZ(caps) != 0) + hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); + } if (hp->clkbase == 0) { /* The attachment driver must tell us. */ printf("%s: base clock frequency unknown\n", sc->sc_dev.dv_xname); goto err; - } else if (hp->clkbase < 10000 || hp->clkbase > 63000) { - /* SDHC 1.0 supports only 10-63 MHz. */ + } else if (hp->clkbase < 10000 || hp->clkbase > max_clock) { printf("%s: base clock frequency out of range: %u MHz\n", sc->sc_dev.dv_xname, hp->clkbase / 1000); goto err; @@ -443,9 +456,13 @@ sdhc_bus_power(sdmmc_chipset_handle_t sch, u_int32_t ocr) static int sdhc_clock_divisor(struct sdhc_host *hp, u_int freq) { + int max_div = 256; int div; - for (div = 1; div <= 256; div *= 2) + if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) + max_div = 2046; + + for (div = 1; div <= max_div; div *= 2) if ((hp->clkbase / div) <= freq) return (div / 2); /* No divisor found. */ @@ -462,6 +479,7 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) struct sdhc_host *hp = sch; int s; int div; + int sdclk; int timo; int error = 0; @@ -489,7 +507,11 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) error = EINVAL; goto ret; } - HWRITE2(hp, SDHC_CLOCK_CTL, div << SDHC_SDCLK_DIV_SHIFT); + if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) + sdclk = SDHC_SDCLK_DIV_V3(div); + else + sdclk = SDHC_SDCLK_DIV(div); + HWRITE2(hp, SDHC_CLOCK_CTL, sdclk); /* * Start internal clock. Wait 10ms for stabilization. diff --git a/sys/dev/sdmmc/sdhcreg.h b/sys/dev/sdmmc/sdhcreg.h index 56d72dcd24a..c7e9bc85764 100644 --- a/sys/dev/sdmmc/sdhcreg.h +++ b/sys/dev/sdmmc/sdhcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */ +/* $OpenBSD: sdhcreg.h,v 1.5 2016/01/11 06:54:53 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -95,6 +95,8 @@ #define SDHC_CLOCK_CTL 0x2c #define SDHC_SDCLK_DIV_SHIFT 8 #define SDHC_SDCLK_DIV_MASK 0xff +#define SDHC_SDCLK_DIV_RSHIFT_V3 2 +#define SDHC_SDCLK_DIV_MASK_V3 0x300 #define SDHC_SDCLK_ENABLE (1<<2) #define SDHC_INTCLK_STABLE (1<<1) #define SDHC_INTCLK_ENABLE (1<<0) @@ -148,9 +150,11 @@ #define SDHC_MAX_BLK_LEN_MASK 0x3 #define SDHC_BASE_FREQ_SHIFT 8 #define SDHC_BASE_FREQ_MASK 0x3f +#define SDHC_BASE_FREQ_MASK_V3 0xff #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_CAPABILITIES_1 0x44 #define SDHC_MAX_CAPABILITIES 0x48 #define SDHC_SLOT_INTR_STATUS 0xfc #define SDHC_HOST_CTL_VERSION 0xfe @@ -158,10 +162,22 @@ #define SDHC_SPEC_VERS_MASK 0xff #define SDHC_VENDOR_VERS_SHIFT 8 #define SDHC_VENDOR_VERS_MASK 0xff +#define SDHC_SPEC_V1 0 +#define SDHC_SPEC_V2 1 +#define SDHC_SPEC_V3 2 + +/* SDHC_CLOCK_CTL encoding */ +#define SDHC_SDCLK_DIV(div) \ + (((div) & SDHC_SDCLK_DIV_MASK) << SDHC_SDCLK_DIV_SHIFT) +#define SDHC_SDCLK_DIV_V3(div) \ + (SDHC_SDCLK_DIV(div) | \ + (((div) & SDHC_SDCLK_DIV_MASK_V3) >> SDHC_SDCLK_DIV_RSHIFT_V3)) /* SDHC_CAPABILITIES decoding */ #define SDHC_BASE_FREQ_KHZ(cap) \ ((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000) +#define SDHC_BASE_FREQ_KHZ_V3(cap) \ + ((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK_V3) * 1000) #define SDHC_TIMEOUT_FREQ(cap) \ (((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK) #define SDHC_TIMEOUT_FREQ_KHZ(cap) \ |