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
This commit is contained in:
Oleksandr Tymoshenko 2012-10-29 17:21:58 +00:00
parent 29e575503c
commit 8f3b7d5616
2 changed files with 61 additions and 16 deletions

View File

@ -221,6 +221,7 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock)
{
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, uint32_t clock)
/* 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;
}
/* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */
clk >>= 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;
}
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 sdhci_slot *slot, int num)
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 sdhci_slot *slot, int num)
}
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, struct mmc_data *data)
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)

View File

@ -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 */