svn commit: r278535 - stable/10/sys/dev/sdhci
Marius Strobl
marius at FreeBSD.org
Tue Feb 10 21:44:29 UTC 2015
Author: marius
Date: Tue Feb 10 21:44:28 2015
New Revision: 278535
URL: https://svnweb.freebsd.org/changeset/base/278535
Log:
MFC: r276469
- 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.
Modified:
stable/10/sys/dev/sdhci/sdhci_pci.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/dev/sdhci/sdhci_pci.c
==============================================================================
--- stable/10/sys/dev/sdhci/sdhci_pci.c Tue Feb 10 21:41:56 2015 (r278534)
+++ stable/10/sys/dev/sdhci/sdhci_pci.c Tue Feb 10 21:44:28 2015 (r278535)
@@ -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;
@@ -207,21 +209,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)
{
@@ -263,7 +287,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);
@@ -353,6 +376,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);
}
@@ -398,6 +433,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),
More information about the svn-src-stable-10
mailing list