- 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
This commit is contained in:
Marius Strobl 2014-12-31 16:06:26 +00:00
parent 116c46a407
commit c22626471e

View File

@ -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),