Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 31 Dec 2014 16:06:27 +0000 (UTC)
From:      Marius Strobl <marius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r276469 - head/sys/dev/sdhci
Message-ID:  <201412311606.sBVG6RCj020578@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marius
Date: Wed Dec 31 16:06:26 2014
New Revision: 276469
URL: https://svnweb.freebsd.org/changeset/base/276469

Log:
  - Switching the mode of Ricoh R5CE823 to SD2.0 causes their PCI device ID
    to change to 0xe822, which may be persistent across reboots and, thus,
    confuse other OSes. Therefore, restore the original mode and frequency
    setting on detach and shutdown.
  - Report Ricoh R5CE822 as such.
  - According to Linux, Ricoh R5CE822 also need SDHCI_QUIRK_LOWER_FREQUENCY.
  - Nuke an unused softc member.
  
  MFC after:	3 days

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

Modified: head/sys/dev/sdhci/sdhci_pci.c
==============================================================================
--- head/sys/dev/sdhci/sdhci_pci.c	Wed Dec 31 10:08:17 2014	(r276468)
+++ head/sys/dev/sdhci/sdhci_pci.c	Wed Dec 31 16:06:26 2014	(r276469)
@@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$");
  */
 #define	SDHC_PCI_MODE_KEY		0xf9
 #define	SDHC_PCI_MODE			0x150
-#define	SDHC_PCI_MODE_SD20		0x10
+#define	 SDHC_PCI_MODE_SD20		0x10
 #define	SDHC_PCI_BASE_FREQ_KEY		0xfc
 #define	SDHC_PCI_BASE_FREQ		0xe1
 
@@ -83,8 +83,9 @@ static const struct sdhci_device {
 } sdhci_devices[] = {
 	{ 0x08221180, 	0xffff,	"RICOH R5C822 SD",
 	    SDHCI_QUIRK_FORCE_DMA },
-	{ 0xe8221180, 	0xffff,	"RICOH SD",
-	    SDHCI_QUIRK_FORCE_DMA },
+	{ 0xe8221180, 	0xffff,	"RICOH R5CE822 SD",
+	    SDHCI_QUIRK_FORCE_DMA |
+	    SDHCI_QUIRK_LOWER_FREQUENCY },
 	{ 0xe8231180, 	0xffff,	"RICOH R5CE823 SD",
 	    SDHCI_QUIRK_LOWER_FREQUENCY },
 	{ 0x8034104c, 	0xffff, "TI XX21/XX11 SD",
@@ -109,7 +110,6 @@ static const struct sdhci_device {
 };
 
 struct sdhci_pci_softc {
-	device_t	dev;		/* Controller device */
 	u_int		quirks;		/* Chip specific quirks */
 	struct resource *irq_res;	/* IRQ resource */
 	void 		*intrhand;	/* Interrupt handle */
@@ -117,6 +117,8 @@ struct sdhci_pci_softc {
 	int		num_slots;	/* Number of slots on this controller */
 	struct sdhci_slot slots[6];
 	struct resource	*mem_res[6];	/* Memory resource */
+	uint8_t		cfg_freq;	/* Saved mode */
+	uint8_t		cfg_mode;	/* Saved frequency */
 };
 
 static int sdhci_enable_msi = 1;
@@ -206,21 +208,43 @@ static void sdhci_pci_intr(void *arg);
 static void
 sdhci_lower_frequency(device_t dev)
 {
+	struct sdhci_pci_softc *sc = device_get_softc(dev);
 
-	/* Enable SD2.0 mode. */
+	/*
+	 * Enable SD2.0 mode.
+	 * NB: for RICOH R5CE823, this changes the PCI device ID to 0xe822.
+	 */
 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1);
+	sc->cfg_mode = pci_read_config(dev, SDHC_PCI_MODE, 1);
 	pci_write_config(dev, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20, 1);
 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1);
 
 	/*
 	 * Some SD/MMC cards don't work with the default base
-	 * clock frequency of 200MHz.  Lower it to 50Hz.
+	 * clock frequency of 200 MHz.  Lower it to 50 MHz.
 	 */
 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1);
+	sc->cfg_freq = pci_read_config(dev, SDHC_PCI_BASE_FREQ, 1);
 	pci_write_config(dev, SDHC_PCI_BASE_FREQ, 50, 1);
 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1);
 }
 
+static void
+sdhci_restore_frequency(device_t dev)
+{
+	struct sdhci_pci_softc *sc = device_get_softc(dev);
+
+	/* Restore mode. */
+	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1);
+	pci_write_config(dev, SDHC_PCI_MODE, sc->cfg_mode, 1);
+	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1);
+
+	/* Restore frequency. */
+	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1);
+	pci_write_config(dev, SDHC_PCI_BASE_FREQ, sc->cfg_freq, 1);
+	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1);
+}
+
 static int
 sdhci_pci_probe(device_t dev)
 {
@@ -262,7 +286,6 @@ sdhci_pci_attach(device_t dev)
 	uint16_t subvendor;
 	int bar, err, rid, slots, i;
 
-	sc->dev = dev;
 	model = (uint32_t)pci_get_device(dev) << 16;
 	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
 	subvendor = pci_get_subvendor(dev);
@@ -352,6 +375,18 @@ sdhci_pci_detach(device_t dev)
 		bus_release_resource(dev, SYS_RES_MEMORY,
 		    rman_get_rid(sc->mem_res[i]), sc->mem_res[i]);
 	}
+	if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
+		sdhci_restore_frequency(dev);
+	return (0);
+}
+
+static int
+sdhci_pci_shutdown(device_t dev)
+{
+	struct sdhci_pci_softc *sc = device_get_softc(dev);
+
+	if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
+		sdhci_restore_frequency(dev);
 	return (0);
 }
 
@@ -397,6 +432,7 @@ static device_method_t sdhci_methods[] =
 	DEVMETHOD(device_probe, sdhci_pci_probe),
 	DEVMETHOD(device_attach, sdhci_pci_attach),
 	DEVMETHOD(device_detach, sdhci_pci_detach),
+	DEVMETHOD(device_shutdown, sdhci_pci_shutdown),
 	DEVMETHOD(device_suspend, sdhci_pci_suspend),
 	DEVMETHOD(device_resume, sdhci_pci_resume),
 



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