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:
parent
29e575503c
commit
8f3b7d5616
@ -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)
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user