Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Oct 2012 17:21:58 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r242320 - head/sys/dev/sdhci
Message-ID:  <201210291721.q9THLw0W006873@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201210291721.q9THLw0W006873>