svn commit: r246886 - head/sys/dev/sdhci

Oleksandr Tymoshenko gonzo at FreeBSD.org
Sat Feb 16 23:12:07 UTC 2013


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;


More information about the svn-src-all mailing list