Module Name: src Committed By: nonaka Date: Fri Mar 2 18:20:34 UTC 2012
Modified Files: src/sys/dev/pci: sdhc_pci.c src/sys/dev/sdmmc: sdhc.c sdhcreg.h Log Message: Added Ricoh 5U822/5U823 SD/MMC Controller support. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/dev/pci/sdhc_pci.c cvs rdiff -u -r1.11 -r1.12 src/sys/dev/sdmmc/sdhc.c cvs rdiff -u -r1.5 -r1.6 src/sys/dev/sdmmc/sdhcreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/sdhc_pci.c diff -u src/sys/dev/pci/sdhc_pci.c:1.6 src/sys/dev/pci/sdhc_pci.c:1.7 --- src/sys/dev/pci/sdhc_pci.c:1.6 Thu Feb 2 22:49:17 2012 +++ src/sys/dev/pci/sdhc_pci.c Fri Mar 2 18:20:33 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc_pci.c,v 1.6 2012/02/02 22:49:17 nonaka Exp $ */ +/* $NetBSD: sdhc_pci.c,v 1.7 2012/03/02 18:20:33 nonaka Exp $ */ /* $OpenBSD: sdhc_pci.c,v 1.7 2007/10/30 18:13:45 chl Exp $ */ /* @@ -18,7 +18,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.6 2012/02/02 22:49:17 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.7 2012/03/02 18:20:33 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -79,9 +79,10 @@ static const struct sdhc_pci_quirk { u_int function; uint32_t flags; -#define SDHC_PCI_QUIRK_FORCE_DMA (1U << 0) -#define SDHC_PCI_QUIRK_TI_HACK (1U << 1) -#define SDHC_PCI_QUIRK_NO_PWR0 (1U << 2) +#define SDHC_PCI_QUIRK_FORCE_DMA (1U << 0) +#define SDHC_PCI_QUIRK_TI_HACK (1U << 1) +#define SDHC_PCI_QUIRK_NO_PWR0 (1U << 2) +#define SDHC_PCI_QUIRK_RICOH_LOWER_FREQ_HACK (1U << 3) } sdhc_pci_quirk_table[] = { { PCI_VENDOR_TI, @@ -109,9 +110,19 @@ static const struct sdhc_pci_quirk { 0, SDHC_PCI_QUIRK_NO_PWR0 }, + + { + PCI_VENDOR_RICOH, + PCI_PRODUCT_RICOH_Rx5U823, + 0xffff, + 0xffff, + 0, + SDHC_PCI_QUIRK_RICOH_LOWER_FREQ_HACK + }, }; static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *); +static void sdhc_pci_quirk_ricoh_lower_freq_hack(struct pci_attach_args *); static uint32_t sdhc_pci_lookup_quirk_flags(struct pci_attach_args *pa) @@ -133,7 +144,7 @@ sdhc_pci_lookup_quirk_flags(struct pci_a if ((q->subvendor == 0xffff) && (q->subproduct == 0xffff)) - return q->flags; + return (q->flags); id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); @@ -144,18 +155,17 @@ sdhc_pci_lookup_quirk_flags(struct pci_a && (q->subproduct != 0xffff)) { if ((vendor == q->subvendor) && (product == q->subproduct)) - return q->flags; + return (q->flags); } else if (q->subvendor != 0xffff) { if (product == q->subproduct) - return q->flags; + return (q->flags); } else { if (vendor == q->subvendor) - return q->flags; + return (q->flags); } } } - - return 0; + return (0); } static int @@ -165,9 +175,12 @@ sdhc_pci_match(device_t parent, cfdata_t if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM && PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC) - return 1; - - return 0; + return (1); + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RICOH && + (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_Rx5U822 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_Rx5U823)) + return (1); + return (0); } static void @@ -203,6 +216,8 @@ sdhc_pci_attach(device_t parent, device_ SET(sc->sc.sc_flags, SDHC_FLAG_FORCE_DMA); if (ISSET(flags, SDHC_PCI_QUIRK_NO_PWR0)) SET(sc->sc.sc_flags, SDHC_FLAG_NO_PWR0); + if (ISSET(flags, SDHC_PCI_QUIRK_RICOH_LOWER_FREQ_HACK)) + sdhc_pci_quirk_ricoh_lower_freq_hack(pa); /* * Map and attach all hosts supported by the host controller. @@ -276,6 +291,17 @@ err: free(sc->sc.sc_host, M_DEVBUF); } +static void +sdhc_pci_conf_write(struct pci_attach_args *pa, int reg, uint8_t val) +{ + pcireg_t r; + + r = pci_conf_read(pa->pa_pc, pa->pa_tag, reg & ~0x3); + r &= ~(0xff << ((reg & 0x3) * 8)); + r |= (val << ((reg & 0x3) * 8)); + pci_conf_write(pa->pa_pc, pa->pa_tag, reg & ~0x3, r); +} + /* TI specific register */ #define SDHC_PCI_GENERAL_CTL 0x4c #define MMC_SD_DIS 0x02 @@ -309,3 +335,29 @@ sdhc_pci_quirk_ti_hack(struct pci_attach reg |= MMC_SD_DIS; pci_conf_write(pc, tag, SDHC_PCI_GENERAL_CTL, reg); } + +/* Ricoh specific register */ +#define SDHC_PCI_MODE_KEY 0xf9 +#define SDHC_PCI_MODE 0x150 +#define SDHC_PCI_MODE_SD20 0x10 +#define SDHC_PCI_BASE_FREQ_KEY 0xfc +#define SDHC_PCI_BASE_FREQ 0xe1 + +/* Some RICOH controllers need to be bumped into the right mode. */ +static void +sdhc_pci_quirk_ricoh_lower_freq_hack(struct pci_attach_args *pa) +{ + + /* Enable SD2.0 mode. */ + sdhc_pci_conf_write(pa, SDHC_PCI_MODE_KEY, 0xfc); + sdhc_pci_conf_write(pa, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20); + sdhc_pci_conf_write(pa, SDHC_PCI_MODE_KEY, 0x00); + + /* + * Some SD/MMC cards don't work with the default base + * clock frequency of 200MHz. Lower it to 50Hz. + */ + sdhc_pci_conf_write(pa, SDHC_PCI_BASE_FREQ_KEY, 0x01); + sdhc_pci_conf_write(pa, SDHC_PCI_BASE_FREQ, 50); + sdhc_pci_conf_write(pa, SDHC_PCI_BASE_FREQ_KEY, 0x00); +} Index: src/sys/dev/sdmmc/sdhc.c diff -u src/sys/dev/sdmmc/sdhc.c:1.11 src/sys/dev/sdmmc/sdhc.c:1.12 --- src/sys/dev/sdmmc/sdhc.c:1.11 Thu Feb 23 21:06:21 2012 +++ src/sys/dev/sdmmc/sdhc.c Fri Mar 2 18:20:33 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.11 2012/02/23 21:06:21 matt Exp $ */ +/* $NetBSD: sdhc.c,v 1.12 2012/03/02 18:20:33 nonaka Exp $ */ /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ /* @@ -23,7 +23,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.11 2012/02/23 21:06:21 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.12 2012/03/02 18:20:33 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -79,6 +79,8 @@ struct sdhc_host { struct kmutex intr_mtx; struct kcondvar intr_cv; + int specver; /* spec. version */ + uint32_t flags; /* flags for this host */ #define SHF_USE_DMA 0x0001 #define SHF_USE_4BIT_MODE 0x0002 @@ -90,18 +92,18 @@ struct sdhc_host { static uint8_t hread1(struct sdhc_host *hp, bus_size_t reg) { + if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) return bus_space_read_1(hp->iot, hp->ioh, reg); - return bus_space_read_4(hp->iot, hp->ioh, reg & -4) >> (8 * (reg & 3)); } static uint16_t hread2(struct sdhc_host *hp, bus_size_t reg) { + if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) return bus_space_read_2(hp->iot, hp->ioh, reg); - return bus_space_read_4(hp->iot, hp->ioh, reg & -4) >> (8 * (reg & 2)); } @@ -114,6 +116,7 @@ hread2(struct sdhc_host *hp, bus_size_t static void hwrite1(struct sdhc_host *hp, bus_size_t o, uint8_t val) { + if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { bus_space_write_1(hp->iot, hp->ioh, o, val); } else { @@ -128,6 +131,7 @@ hwrite1(struct sdhc_host *hp, bus_size_t static void hwrite2(struct sdhc_host *hp, bus_size_t o, uint16_t val) { + if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { bus_space_write_2(hp->iot, hp->ioh, o, val); } else { @@ -223,25 +227,29 @@ sdhc_host_found(struct sdhc_softc *sc, b struct sdmmcbus_attach_args saa; struct sdhc_host *hp; uint32_t caps; -#ifdef SDHC_DEBUG uint16_t sdhcver; sdhcver = bus_space_read_2(iot, ioh, SDHC_HOST_CTL_VERSION); - aprint_normal_dev(sc->sc_dev, "SD Host Specification/Vendor Version "); + aprint_normal_dev(sc->sc_dev, "SD Host Specification "); switch (SDHC_SPEC_VERSION(sdhcver)) { - case 0x00: - aprint_normal("1.0/%u\n", SDHC_VENDOR_VERSION(sdhcver)); + case SDHC_SPEC_VERS_100: + aprint_normal("1.0"); + break; + + case SDHC_SPEC_VERS_200: + aprint_normal("2.0"); break; - case 0x01: - aprint_normal("2.0/%u\n", SDHC_VENDOR_VERSION(sdhcver)); + case SDHC_SPEC_VERS_300: + aprint_normal("3.0"); break; default: - aprint_normal(">2.0/%u\n", SDHC_VENDOR_VERSION(sdhcver)); + aprint_normal("unknown version(0x%x)", + SDHC_SPEC_VERSION(sdhcver)); break; } -#endif + aprint_normal(", rev.%u\n", SDHC_VENDOR_VERSION(sdhcver)); /* Allocate one more host structure. */ hp = malloc(sizeof(struct sdhc_host), M_DEVBUF, M_WAITOK|M_ZERO); @@ -257,6 +265,7 @@ sdhc_host_found(struct sdhc_softc *sc, b hp->iot = iot; hp->ioh = ioh; hp->dmat = sc->sc_dmat; + hp->specver = SDHC_SPEC_VERSION(sdhcver); mutex_init(&hp->host_mtx, MUTEX_DEFAULT, IPL_SDMMC); mutex_init(&hp->intr_mtx, MUTEX_DEFAULT, IPL_SDMMC); @@ -285,12 +294,12 @@ sdhc_host_found(struct sdhc_softc *sc, b /* * Determine the base clock frequency. (2.2.24) */ - if (SDHC_BASE_FREQ_KHZ(caps) != 0) - hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); + hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); if (hp->clkbase == 0) { if (sc->sc_clkbase == 0) { /* The attachment driver must tell us. */ - aprint_error_dev(sc->sc_dev,"unknown base clock frequency\n"); + aprint_error_dev(sc->sc_dev, + "unknown base clock frequency\n"); goto err; } hp->clkbase = sc->sc_clkbase; @@ -419,6 +428,7 @@ sdhc_suspend(device_t dev, const pmf_qua { struct sdhc_softc *sc = device_private(dev); struct sdhc_host *hp; + size_t i; /* XXX poll for command completion or suspend command * in progress */ @@ -427,15 +437,15 @@ sdhc_suspend(device_t dev, const pmf_qua for (size_t n = 0; n < sc->sc_nhosts; n++) { hp = sc->sc_host[n]; if (ISSET(sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { - for (size_t i = 0; i < sizeof hp->regs; i += 4) { + for (i = 0; i < sizeof hp->regs; i += 4) { uint32_t v = HREAD4(hp, i); - hp->regs[i+0] = (v >> 0); - hp->regs[i+1] = (v >> 8); - hp->regs[i+2] = (v >> 16); - hp->regs[i+3] = (v >> 24); + hp->regs[i + 0] = (v >> 0); + hp->regs[i + 1] = (v >> 8); + hp->regs[i + 2] = (v >> 16); + hp->regs[i + 3] = (v >> 24); } } else { - for (size_t i = 0; i < sizeof hp->regs; i++) { + for (i = 0; i < sizeof hp->regs; i++) { hp->regs[i] = HREAD1(hp, i); } } @@ -448,21 +458,22 @@ sdhc_resume(device_t dev, const pmf_qual { struct sdhc_softc *sc = device_private(dev); struct sdhc_host *hp; + size_t i; /* Restore the host controller state. */ for (size_t n = 0; n < sc->sc_nhosts; n++) { hp = sc->sc_host[n]; (void)sdhc_host_reset(hp); if (ISSET(sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { - for (size_t i = 0; i < sizeof hp->regs; i += 4) { + for (i = 0; i < sizeof hp->regs; i += 4) { HWRITE4(hp, i, - (hp->regs[i+0] << 0) - |(hp->regs[i+1] << 8) - |(hp->regs[i+2] << 16) - |(hp->regs[i+3] << 24)); + (hp->regs[i + 0] << 0) + | (hp->regs[i + 1] << 8) + | (hp->regs[i + 2] << 16) + | (hp->regs[i + 3] << 24)); } } else { - for (size_t i = 0; i < sizeof hp->regs; i++) { + for (i = 0; i < sizeof hp->regs; i++) { HWRITE1(hp, i, hp->regs[i]); } } @@ -601,9 +612,7 @@ sdhc_write_protect(sdmmc_chipset_handle_ r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_WRITE_PROTECT_SWITCH); mutex_exit(&hp->host_mtx); - if (!r) - return 1; - return 0; + return r ? 0 : 1; } /* @@ -722,7 +731,6 @@ sdhc_clock_divisor(struct sdhc_host *hp, } } } - /* No divisor found. */ return false; } @@ -739,18 +747,17 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc u_int timo; int error = 0; #ifdef DIAGNOSTIC - bool ispresent; -#endif + bool present; -#ifdef DIAGNOSTIC mutex_enter(&hp->host_mtx); - ispresent = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK); + present = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK); mutex_exit(&hp->host_mtx); /* Must not stop the clock if commands are in progress. */ - if (ispresent && sdhc_card_detect(hp)) + if (present && sdhc_card_detect(hp)) { printf("%s: sdhc_sdclk_frequency_select: command in progress\n", device_xname(hp->sc->sc_dev)); + } #endif mutex_enter(&hp->host_mtx); @@ -790,11 +797,13 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc */ if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { sdmmc_delay(10000); - HSET4(hp, SDHC_CLOCK_CTL, 8|SDHC_INTCLK_ENABLE|SDHC_INTCLK_STABLE); + HSET4(hp, SDHC_CLOCK_CTL, + 8 | SDHC_INTCLK_ENABLE | SDHC_INTCLK_STABLE); } else { HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE); for (timo = 1000; timo > 0; timo--) { - if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE)) + if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), + SDHC_INTCLK_STABLE)) break; sdmmc_delay(10); } @@ -819,6 +828,7 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc sdmmc_delay(10); } DPRINTF(2,("%s: %u init spins\n", __func__, 10 - timo)); + /* * Enable SD clock. */ @@ -865,11 +875,11 @@ sdhc_bus_width(sdmmc_chipset_handle_t sc mutex_enter(&hp->host_mtx); reg = HREAD1(hp, SDHC_HOST_CTL); if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { - reg &= ~(SDHC_4BIT_MODE|SDHC_8BIT_MODE); + reg &= ~(SDHC_4BIT_MODE|SDHC_ESDHC_8BIT_MODE); if (width == 4) reg |= SDHC_4BIT_MODE; else if (width == 8) - reg |= SDHC_8BIT_MODE; + reg |= SDHC_ESDHC_8BIT_MODE; } else { reg &= ~SDHC_4BIT_MODE; if (width == 4) @@ -1086,8 +1096,7 @@ sdhc_start_command(struct sdhc_host *hp, /* * Prepare command register value. (2.2.6) */ - command = - (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) << SDHC_COMMAND_INDEX_SHIFT; + command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) << SDHC_COMMAND_INDEX_SHIFT; if (ISSET(cmd->c_flags, SCF_RSP_CRC)) command |= SDHC_CRC_CHECK_ENABLE; @@ -1224,11 +1233,11 @@ static int sdhc_transfer_data_pio(struct sdhc_host *hp, struct sdmmc_command *cmd) { uint8_t *data = cmd->c_data; + void (*pio_func)(struct sdhc_host *, uint8_t *, u_int); u_int len, datalen; u_int imask; u_int pmask; int error = 0; - void (*pio_func)(struct sdhc_host *, uint8_t *, u_int); if (ISSET(cmd->c_flags, SCF_CMD_READ)) { imask = SDHC_BUFFER_READ_READY; @@ -1366,22 +1375,22 @@ sdhc_write_data_pio(struct sdhc_host *hp } } - static void esdhc_read_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen) { uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS); + uint32_t v; + while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { - uint32_t v = HREAD4(hp, SDHC_DATA); + v = HREAD4(hp, SDHC_DATA); v = le32toh(v); *(uint32_t *)data = v; data += 4; datalen -= 4; status = HREAD2(hp, SDHC_NINTR_STATUS); } - if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { - uint32_t v = HREAD4(hp, SDHC_DATA); + v = HREAD4(hp, SDHC_DATA); v = le32toh(v); do { *data++ = v; @@ -1394,8 +1403,10 @@ static void esdhc_write_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen) { uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS); + uint32_t v; + while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { - uint32_t v = *(uint32_t *)data; + v = *(uint32_t *)data; v = htole32(v); HWRITE4(hp, SDHC_DATA, v); data += 4; @@ -1403,7 +1414,7 @@ esdhc_write_data_pio(struct sdhc_host *h status = HREAD2(hp, SDHC_NINTR_STATUS); } if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { - uint32_t v = *(uint32_t *)data; + v = *(uint32_t *)data; v = htole32(v); HWRITE4(hp, SDHC_DATA, v); } Index: src/sys/dev/sdmmc/sdhcreg.h diff -u src/sys/dev/sdmmc/sdhcreg.h:1.5 src/sys/dev/sdmmc/sdhcreg.h:1.6 --- src/sys/dev/sdmmc/sdhcreg.h:1.5 Wed Feb 1 22:53:19 2012 +++ src/sys/dev/sdmmc/sdhcreg.h Fri Mar 2 18:20:34 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhcreg.h,v 1.5 2012/02/01 22:53:19 matt Exp $ */ +/* $NetBSD: sdhcreg.h,v 1.6 2012/03/02 18:20:34 nonaka Exp $ */ /* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */ /* @@ -73,7 +73,7 @@ #define SDHC_CMD_INHIBIT_MASK 0x0003 #define SDHC_HOST_CTL 0x28 #define SDHC_HIGH_SPEED (1<<2) -#define SDHC_8BIT_MODE (1<<2) /* ESDHC */ +#define SDHC_ESDHC_8BIT_MODE (1<<2) /* eSDHC */ #define SDHC_4BIT_MODE (1<<1) #define SDHC_LED_ON (1<<0) #define SDHC_POWER_CTL 0x29 @@ -167,6 +167,11 @@ #define SDHC_DMA_CTL 0x40c /* eSDHC */ #define SDHC_DMA_SNOOP 0x40 +/* SDHC_SPEC_VERS */ +#define SDHC_SPEC_VERS_100 0x00 +#define SDHC_SPEC_VERS_200 0x01 +#define SDHC_SPEC_VERS_300 0x02 + /* SDHC_CAPABILITIES decoding */ #define SDHC_BASE_FREQ_KHZ(cap) \ ((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000)