Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Oct 2015 04:22:56 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r289359 - head/sys/dev/sdhci
Message-ID:  <201510150422.t9F4MurD037057@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Thu Oct 15 04:22:56 2015
New Revision: 289359
URL: https://svnweb.freebsd.org/changeset/base/289359

Log:
  Add support for the BCM57765 card reader.
  
  This patch adds support for the BCM57765[2] card reader function included in
  Broadcom's BCM57766 ethernet/sd3.0 controller. This controller is commonly
  found in laptops and Apple hardware (MBP, iMac, etc).
  
  The BCM57765 chipset is almost fully compatible with the SD3.0 spec, but
  does not support deriving a frequency below 781KHz from its default base
  clock via the standard SD3.0-configured 10-bit clock divisor.
  
  If such a divisor is set, card identification (which requires a 400KHz
  clock frequency) will time out[1].
  
  As a work-around, I've made use of an undocumented device-specific clock
  control register to switch the controller to a 63MHz clock source when
  targeting clock speeds below 781KHz; the clock source is likewise switched
  back to the 200MHz clock when targeting speeds greater than 781KHz.
  
  Additionally, this patch fixes a small sdhci_pci bug; the
  sdhci_pci_softc->quirks flag was not copied to the sdhci_slot, resulting in
  `quirk` behavior not being applied by sdhci.c.
  
  [1] A number of Linux/FreeBSD users have noted that bringing up the chipsets'
  associated ethernet interface will allow SD cards to enumerate (slowly).
  This is a controller implementation side-effect triggered by the ethernet
  driver's reading of the hardware statistics registers.
  
  [2] This may also fix card detection when using the BCM57785 chipset, but I
  don't have access to the BCM57785 chipset and can't verify.
  
  I actually snagged some BCM57785 hardware recently (2012 Retina MacBook Pro)
  and can confirm that this also fixes card enumeration with the BCM57785
  chipset; with the patch, I can boot off of the internal sdcard reader.
  
  PR:		kern/203385
  Submitted by:	Landon Fuller <landon@landonf.org>

Modified:
  head/sys/dev/sdhci/sdhci.c
  head/sys/dev/sdhci/sdhci.h
  head/sys/dev/sdhci/sdhci_pci.c

Modified: head/sys/dev/sdhci/sdhci.c
==============================================================================
--- head/sys/dev/sdhci/sdhci.c	Thu Oct 15 03:48:03 2015	(r289358)
+++ head/sys/dev/sdhci/sdhci.c	Thu Oct 15 04:22:56 2015	(r289359)
@@ -89,6 +89,19 @@ static void sdhci_card_task(void *, int)
 #define	SDHCI_200_MAX_DIVIDER	256
 #define	SDHCI_300_MAX_DIVIDER	2046
 
+/*
+ * Broadcom BCM577xx Controller Constants
+ */
+#define BCM577XX_DEFAULT_MAX_DIVIDER	256		/* Maximum divider supported by the default clock source. */
+#define BCM577XX_ALT_CLOCK_BASE		63000000	/* Alternative clock's base frequency. */
+
+#define BCM577XX_HOST_CONTROL		0x198
+#define BCM577XX_CTRL_CLKSEL_MASK	0xFFFFCFFF
+#define BCM577XX_CTRL_CLKSEL_SHIFT	12
+#define BCM577XX_CTRL_CLKSEL_DEFAULT	0x0
+#define BCM577XX_CTRL_CLKSEL_64MHZ	0x3
+
+
 static void
 sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
@@ -228,6 +241,8 @@ sdhci_init(struct sdhci_slot *slot)
 static void
 sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock)
 {
+	uint32_t clk_base;
+	uint32_t clk_sel;
 	uint32_t res;
 	uint16_t clk;
 	uint16_t div;
@@ -243,6 +258,22 @@ sdhci_set_clock(struct sdhci_slot *slot,
 	/* If no clock requested - left it so. */
 	if (clock == 0)
 		return;
+	
+	/* Determine the clock base frequency */
+	clk_base = slot->max_clk;
+	if (slot->quirks & SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC) {
+		clk_sel = RD2(slot, BCM577XX_HOST_CONTROL) & BCM577XX_CTRL_CLKSEL_MASK;
+
+		/* Select clock source appropriate for the requested frequency. */
+		if ((clk_base / BCM577XX_DEFAULT_MAX_DIVIDER) > clock) {
+			clk_base = BCM577XX_ALT_CLOCK_BASE;
+			clk_sel |= (BCM577XX_CTRL_CLKSEL_64MHZ << BCM577XX_CTRL_CLKSEL_SHIFT);
+		} else {
+			clk_sel |= (BCM577XX_CTRL_CLKSEL_DEFAULT << BCM577XX_CTRL_CLKSEL_SHIFT);
+		}
+		
+		WR2(slot, BCM577XX_HOST_CONTROL, clk_sel);
+	}
 
 	/* Recalculate timeout clock frequency based on the new sd clock. */
 	if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
@@ -250,7 +281,7 @@ sdhci_set_clock(struct sdhci_slot *slot,
 
 	if (slot->version < SDHCI_SPEC_300) {
 		/* Looking for highest freq <= clock. */
-		res = slot->max_clk;
+		res = clk_base;
 		for (div = 1; div < SDHCI_200_MAX_DIVIDER; div <<= 1) {
 			if (res <= clock)
 				break;
@@ -261,11 +292,11 @@ 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)
+		if (clock >= clk_base)
 			div = 0;
 		else {
 			for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) { 
-				if ((slot->max_clk / div) <= clock) 
+				if ((clk_base / div) <= clock) 
 					break;
 			}
 		}
@@ -273,8 +304,8 @@ sdhci_set_clock(struct sdhci_slot *slot,
 	}
 
 	if (bootverbose || sdhci_debug)
-		slot_printf(slot, "Divider %d for freq %d (max %d)\n", 
-			div, clock, slot->max_clk);
+		slot_printf(slot, "Divider %d for freq %d (base %d)\n", 
+			div, clock, clk_base);
 
 	/* Now we have got divider, set it. */
 	clk = (div & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT;

Modified: head/sys/dev/sdhci/sdhci.h
==============================================================================
--- head/sys/dev/sdhci/sdhci.h	Thu Oct 15 03:48:03 2015	(r289358)
+++ head/sys/dev/sdhci/sdhci.h	Thu Oct 15 04:22:56 2015	(r289359)
@@ -63,6 +63,8 @@
 #define	SDHCI_QUIRK_WAITFOR_RESET_ASSERTED		(1<<14)
 /* Leave controller in standard mode when putting card in HS mode. */
 #define	SDHCI_QUIRK_DONT_SET_HISPD_BIT			(1<<15)
+/* Alternate clock source is required when supplying a 400 KHz clock. */
+#define	SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC		(1<<16)
 
 /*
  * Controller registers

Modified: head/sys/dev/sdhci/sdhci_pci.c
==============================================================================
--- head/sys/dev/sdhci/sdhci_pci.c	Thu Oct 15 03:48:03 2015	(r289358)
+++ head/sys/dev/sdhci/sdhci_pci.c	Thu Oct 15 04:22:56 2015	(r289359)
@@ -105,6 +105,8 @@ static const struct sdhci_device {
 	{ 0x2381197B, 	0xffff,	"JMicron JMB38X SD",
 	    SDHCI_QUIRK_32BIT_DMA_SIZE |
 	    SDHCI_QUIRK_RESET_AFTER_REQUEST },
+	{ 0x16bc14e4,	0xffff,	"Broadcom BCM577xx SDXC/MMC Card Reader",
+	    SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC },
 	{ 0,		0xffff,	NULL,
 	    0 }
 };
@@ -334,6 +336,8 @@ sdhci_pci_attach(device_t dev)
 			device_printf(dev, "Can't allocate memory for slot %d\n", i);
 			continue;
 		}
+		
+		slot->quirks = sc->quirks;
 
 		if (sdhci_init_slot(dev, slot, i) != 0)
 			continue;



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