Date: Mon, 29 Oct 2012 17:21:58 +0000 (UTC) From: Oleksandr Tymoshenko <gonzo@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r242320 - head/sys/dev/sdhci Message-ID: <201210291721.q9THLw0W006873@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: gonzo Date: Mon Oct 29 17:21:58 2012 New Revision: 242320 URL: http://svn.freebsd.org/changeset/base/242320 Log: Add new quirks: - Data timeout is broken - Data timeout uses SD clock - Capabilities register is unavailable Add calculations for clock divisor for SDHCI 3.0 Modified: head/sys/dev/sdhci/sdhci.c head/sys/dev/sdhci/sdhci.h Modified: head/sys/dev/sdhci/sdhci.c ============================================================================== --- head/sys/dev/sdhci/sdhci.c Mon Oct 29 17:19:43 2012 (r242319) +++ head/sys/dev/sdhci/sdhci.c Mon Oct 29 17:21:58 2012 (r242320) @@ -221,6 +221,7 @@ sdhci_set_clock(struct sdhci_slot *slot, { uint32_t res; uint16_t clk; + uint16_t div; int timeout; if (clock == slot->clock) @@ -232,17 +233,39 @@ sdhci_set_clock(struct sdhci_slot *slot, /* If no clock requested - left it so. */ if (clock == 0) return; - /* Looking for highest freq <= clock. */ - res = slot->max_clk; - for (clk = 1; clk < 256; clk <<= 1) { - if (res <= clock) - break; - res >>= 1; + if (slot->version < SDHCI_SPEC_300) { + /* Looking for highest freq <= clock. */ + res = slot->max_clk; + for (div = 1; div < 256; div <<= 1) { + if (res <= clock) + break; + res >>= 1; + } + /* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */ + div >>= 1; + } + else { + /* Version 3.0 divisors are multiples of two up to 1023*2 */ + if (clock > slot->max_clk) + div = 2; + else { + for (div = 2; div < 1023*2; div += 2) { + if ((slot->max_clk / div) <= clock) + break; + } + } + div >>= 1; } - /* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */ - clk >>= 1; + + if (bootverbose || sdhci_debug) + slot_printf(slot, "Divider %d for freq %d (max %d)\n", + div, clock, slot->max_clk); + /* Now we have got divider, set it. */ - clk <<= SDHCI_DIVIDER_SHIFT; + clk = (div & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT; + clk |= ((div >> SDHCI_DIVIDER_MASK_LEN) & SDHCI_DIVIDER_HI_MASK) + << SDHCI_DIVIDER_HI_SHIFT; + WR2(slot, SDHCI_CLOCK_CONTROL, clk); /* Enable clock. */ clk |= SDHCI_CLOCK_INT_EN; @@ -488,7 +511,10 @@ sdhci_init_slot(device_t dev, struct sdh sdhci_init(slot); slot->version = (RD2(slot, SDHCI_HOST_VERSION) >> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK; - caps = RD4(slot, SDHCI_CAPABILITIES); + if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS) + caps = slot->caps; + else + caps = RD4(slot, SDHCI_CAPABILITIES); /* Calculate base clock frequency. */ slot->max_clk = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; @@ -499,14 +525,19 @@ sdhci_init_slot(device_t dev, struct sdh } slot->max_clk *= 1000000; /* Calculate timeout clock frequency. */ - slot->timeout_clk = - (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; + if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) { + slot->timeout_clk = slot->max_clk / 1000; + } else { + slot->timeout_clk = + (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; + if (caps & SDHCI_TIMEOUT_CLK_UNIT) + slot->timeout_clk *= 1000; + } + if (slot->timeout_clk == 0) { device_printf(dev, "Hardware doesn't specify timeout clock " "frequency.\n"); } - if (caps & SDHCI_TIMEOUT_CLK_UNIT) - slot->timeout_clk *= 1000; slot->host.f_min = slot->max_clk / 256; slot->host.f_max = slot->max_clk; @@ -815,6 +846,8 @@ sdhci_start_data(struct sdhci_slot *slot slot_printf(slot, "Timeout too large!\n"); div = 0xE; } + if (slot->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) + div = 0xE; WR1(slot, SDHCI_TIMEOUT_CONTROL, div); if (data == NULL) Modified: head/sys/dev/sdhci/sdhci.h ============================================================================== --- head/sys/dev/sdhci/sdhci.h Mon Oct 29 17:19:43 2012 (r242319) +++ head/sys/dev/sdhci/sdhci.h Mon Oct 29 17:21:58 2012 (r242320) @@ -51,12 +51,16 @@ #define SDHCI_QUIRK_BROKEN_TIMINGS (1<<8) /* Controller needs lowered frequency */ #define SDHCI_QUIRK_LOWER_FREQUENCY (1<<9) - +/* Data timeout is invalid, should use SD clock */ +#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<10) +/* Timeout value is invalid, should be overriden */ +#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<11) +/* SDHCI_CAPABILITIES is invalid */ +#define SDHCI_QUIRK_MISSING_CAPS (1<<12) /* * Controller registers */ - #define SDHCI_DMA_ADDRESS 0x00 #define SDHCI_BLOCK_SIZE 0x04 @@ -130,7 +134,11 @@ #define SDHCI_WAKE_UP_CONTROL 0x2B #define SDHCI_CLOCK_CONTROL 0x2C +#define SDHCI_DIVIDER_MASK 0xff +#define SDHCI_DIVIDER_MASK_LEN 8 #define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_DIVIDER_HI_MASK 3 +#define SDHCI_DIVIDER_HI_SHIFT 6 #define SDHCI_CLOCK_CARD_EN 0x0004 #define SDHCI_CLOCK_INT_STABLE 0x0002 #define SDHCI_CLOCK_INT_EN 0x0001 @@ -204,9 +212,13 @@ #define SDHCI_VENDOR_VER_SHIFT 8 #define SDHCI_SPEC_VER_MASK 0x00FF #define SDHCI_SPEC_VER_SHIFT 0 +#define SDHCI_SPEC_100 0 +#define SDHCI_SPEC_200 1 +#define SDHCI_SPEC_300 2 struct sdhci_slot { u_int quirks; /* Chip specific quirks */ + u_int caps; /* Override SDHCI_CAPABILITIES */ device_t bus; /* Bus device */ device_t dev; /* Slot device */ u_char num; /* Slot number */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201210291721.q9THLw0W006873>