svn commit: r242320 - head/sys/dev/sdhci
Oleksandr Tymoshenko
gonzo at FreeBSD.org
Mon Oct 29 17:21:59 UTC 2012
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 */
More information about the svn-src-all
mailing list