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 */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to