summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/sdhci/sdhci_pci.c50
1 files changed, 43 insertions, 7 deletions
diff --git a/sys/dev/sdhci/sdhci_pci.c b/sys/dev/sdhci/sdhci_pci.c
index edb65f5..b13a0c9 100644
--- a/sys/dev/sdhci/sdhci_pci.c
+++ b/sys/dev/sdhci/sdhci_pci.c
@@ -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),
OpenPOWER on IntegriCloud