Author: gonzo
Date: Sat Feb 16 23:12:06 2013
New Revision: 246886
URL: http://svnweb.freebsd.org/changeset/base/246886

Log:
  Various timing-related fixes:
  
  - Replace divisor numbers with more descirptive names
  - Properly calculate minimum frequency for SDHCI 3.0
  - Properly calculate frequency for SDHCI 3.0 in mmcbr_set_clock
  - Add min_freq method to sdhci_if.m and provide default
    implementation.  By re-implementing this method hardware
    drivers can control frequency controller operates when
    executing initialization sequence

Modified:
  head/sys/dev/sdhci/sdhci.c
  head/sys/dev/sdhci/sdhci.h
  head/sys/dev/sdhci/sdhci_if.m

Modified: head/sys/dev/sdhci/sdhci.c
==============================================================================
--- head/sys/dev/sdhci/sdhci.c  Sat Feb 16 22:44:02 2013        (r246885)
+++ head/sys/dev/sdhci/sdhci.c  Sat Feb 16 23:12:06 2013        (r246886)
@@ -65,7 +65,7 @@ struct sdhci_softc {
 
 static SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver");
 
-int    sdhci_debug = 0;
+int    sdhci_debug = 1;
 TUNABLE_INT("hw.sdhci.debug", &sdhci_debug);
 SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RW, &sdhci_debug, 0, "Debug 
level");
 
@@ -98,6 +98,9 @@ static void sdhci_card_task(void *, int)
 
 #define        SDHCI_DEFAULT_MAX_FREQ  50
 
+#define        SDHCI_200_MAX_DIVIDER   256
+#define        SDHCI_300_MAX_DIVIDER   2046
+
 static void
 sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
@@ -238,7 +241,7 @@ sdhci_set_clock(struct sdhci_slot *slot,
        if (slot->version < SDHCI_SPEC_300) {
                /* Looking for highest freq <= clock. */
                res = slot->max_clk;
-               for (div = 1; div < 256; div <<= 1) {
+               for (div = 1; div < SDHCI_200_MAX_DIVIDER; div <<= 1) {
                        if (res <= clock)
                                break;
                        res >>= 1;
@@ -248,10 +251,10 @@ sdhci_set_clock(struct sdhci_slot *slot,
        }
        else {
                /* Version 3.0 divisors are multiples of two up to 1023*2 */
-               if (clock > slot->max_clk)
-                       div = 2;
+               if (clock >= slot->max_clk)
+                       div = 0;
                else {
-                       for (div = 2; div < 1023*2; div += 2) {
+                       for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) { 
                                if ((slot->max_clk / div) <= clock) 
                                        break;
                        }
@@ -545,7 +548,7 @@ sdhci_init_slot(device_t dev, struct sdh
                    "frequency.\n");
        }
 
-       slot->host.f_min = slot->max_clk / 256;
+       slot->host.f_min = SDHCI_MIN_FREQ(slot->bus, slot);
        slot->host.f_max = slot->max_clk;
        slot->host.host_ocr = 0;
        if (caps & SDHCI_CAN_VDD_330)
@@ -635,6 +638,15 @@ sdhci_generic_resume(struct sdhci_slot *
        return (0);
 }
 
+uint32_t
+sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot)
+{
+       if (slot->version >= SDHCI_SPEC_300)
+               return (slot->max_clk / SDHCI_300_MAX_DIVIDER);
+       else
+               return (slot->max_clk / SDHCI_200_MAX_DIVIDER);
+}
+
 int
 sdhci_generic_update_ios(device_t brdev, device_t reqdev)
 {
@@ -1078,8 +1090,12 @@ sdhci_data_irq(struct sdhci_slot *slot, 
        }
        if (intmask & SDHCI_INT_DATA_TIMEOUT)
                slot->curcmd->error = MMC_ERR_TIMEOUT;
-       else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
+       else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) {
+               if (intmask & SDHCI_INT_DATA_CRC) {
+                       panic("DATA CRC error\n");
+               }
                slot->curcmd->error = MMC_ERR_BADCRC;
+       }
        if (slot->curcmd->data == NULL &&
            (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
            SDHCI_INT_DMA_END))) {
@@ -1299,14 +1315,30 @@ sdhci_generic_write_ivar(device_t bus, d
                break;
        case MMCBR_IVAR_CLOCK:
                if (value > 0) {
-                       uint32_t clock = slot->max_clk;
+                       uint32_t max_clock;
+                       uint32_t clock;
                        int i;
 
-                       for (i = 0; i < 8; i++) {
-                               if (clock <= value)
-                                       break;
-                               clock >>= 1;
+                       max_clock = slot->max_clk;
+                       clock = max_clock;
+
+                       if (slot->version < SDHCI_SPEC_300) {
+                               for (i = 0; i < SDHCI_200_MAX_DIVIDER;
+                                   i <<= 1) {
+                                       if (clock <= value)
+                                               break;
+                                       clock >>= 1;
+                               }
+                       }
+                       else {
+                               for (i = 0; i < SDHCI_300_MAX_DIVIDER;
+                                   i += 2) {
+                                       if (clock <= value)
+                                               break;
+                                       clock = max_clock / (i + 2);
+                               }
                        }
+
                        slot->host.ios.clock = clock;
                } else
                        slot->host.ios.clock = 0;

Modified: head/sys/dev/sdhci/sdhci.h
==============================================================================
--- head/sys/dev/sdhci/sdhci.h  Sat Feb 16 22:44:02 2013        (r246885)
+++ head/sys/dev/sdhci/sdhci.h  Sat Feb 16 23:12:06 2013        (r246886)
@@ -266,5 +266,6 @@ int sdhci_generic_get_ro(device_t brdev,
 int sdhci_generic_acquire_host(device_t brdev, device_t reqdev);
 int sdhci_generic_release_host(device_t brdev, device_t reqdev);
 void sdhci_generic_intr(struct sdhci_slot *slot);
+uint32_t sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot);
 
 #endif /* __SDHCI_H__ */

Modified: head/sys/dev/sdhci/sdhci_if.m
==============================================================================
--- head/sys/dev/sdhci/sdhci_if.m       Sat Feb 16 22:44:02 2013        
(r246885)
+++ head/sys/dev/sdhci/sdhci_if.m       Sat Feb 16 23:12:06 2013        
(r246886)
@@ -58,7 +58,18 @@
 # that mmc/sd card drivers call to make requests.
 #
 
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
+
 #include <machine/bus.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/sdhci/sdhci.h>
+
 CODE {
        struct sdhci_slot;
 }
@@ -119,3 +130,8 @@ METHOD void write_multi_4 {
        uint32_t                *data;
        bus_size_t              count;
 }
+
+METHOD uint32_t min_freq {
+       device_t                brdev;
+       struct sdhci_slot       *slot;
+} DEFAULT sdhci_generic_min_freq;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to