diff --exclude=CVS --exclude='.#*' --exclude='obj.*' --exclude='makeBuild*' -uNr src.orig/sys/dev/sdmmc/sdhc.c src/sys/dev/sdmmc/sdhc.c --- src.orig/sys/dev/sdmmc/sdhc.c 2011-06-29 15:21:16.000000000 +0900 +++ src/sys/dev/sdmmc/sdhc.c 2012-02-01 12:16:10.000000000 +0900 @@ -64,6 +64,7 @@ struct kmutex host_mtx; + int specver; /* sdhc spec version */ u_int clkbase; /* base clock frequency in KHz */ int maxblklen; /* maximum block length */ uint32_t ocr; /* OCR value from capabilities */ @@ -78,6 +79,7 @@ uint32_t flags; /* flags for this host */ #define SHF_USE_DMA 0x0001 #define SHF_USE_4BIT_MODE 0x0002 +#define SHF_USE_ADMA 0x0004 }; #define HDEVNAME(hp) (device_xname((hp)->sc->sc_dev)) @@ -165,26 +167,29 @@ { struct sdmmcbus_attach_args saa; struct sdhc_host *hp; - uint32_t caps; -#ifdef SDHC_DEBUG + uint32_t caps[2]; 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 "); 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/0x%x\n", SDHC_VENDOR_VERSION(sdhcver)); + break; + + case SDHC_SPEC_VERS_200: + aprint_normal("2.0/0x%x\n", SDHC_VENDOR_VERSION(sdhcver)); break; - case 0x01: - aprint_normal("2.0/%u\n", SDHC_VENDOR_VERSION(sdhcver)); + case SDHC_SPEC_VERS_300: + aprint_normal("3.0/0x%x\n", SDHC_VENDOR_VERSION(sdhcver)); break; default: - aprint_normal(">2.0/%u\n", SDHC_VENDOR_VERSION(sdhcver)); + aprint_normal("unknown(0x%0x)/0x%x\n", + SDHC_SPEC_VERSION(sdhcver), SDHC_VENDOR_VERSION(sdhcver)); break; } -#endif /* Allocate one more host structure. */ hp = malloc(sizeof(struct sdhc_host), M_DEVBUF, M_WAITOK|M_ZERO); @@ -200,6 +205,7 @@ 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); @@ -212,28 +218,36 @@ /* Determine host capabilities. */ mutex_enter(&hp->host_mtx); - caps = HREAD4(hp, SDHC_CAPABILITIES); + caps[0] = HREAD4(hp, SDHC_CAPABILITIES); + caps[1] = (hp->specver >= SDHC_SPEC_VERS_300) ? + HREAD4(hp, SDHC_CAPABILITIES_1) : 0; mutex_exit(&hp->host_mtx); #if notyet /* Use DMA if the host system and the controller support it. */ if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA) || ((ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA) - && ISSET(caps, SDHC_DMA_SUPPORT)))) { + && ISSET(caps[0], SDHC_DMA_SUPPORT)))) SET(hp->flags, SHF_USE_DMA); - aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); - } + if (ISSET(sc->sc_flags, SDHC_FLAG_BROKEN_DMA)) + CLR(hp->flags, SHF_USE_DMA); + + if ((hp->specver >= SDHC_SPEC_VERS_200) + && ISSET(caps[0], SDHC_ADMA2_SUPPORT)) + SET(hp->flags, SHF_USE_ADMA); + if (ISSET(sc->sc_flags, SDHC_FLAG_BROKEN_ADMA)) + CLR(hp->flags, SHF_USE_ADMA); #endif /* * 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[0]); 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; @@ -257,18 +271,18 @@ /* * Determine SD bus voltage levels supported by the controller. */ - if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) + if (ISSET(caps[0], SDHC_VOLTAGE_SUPP_1_8V)) SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V); - if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V)) + if (ISSET(caps[0], SDHC_VOLTAGE_SUPP_3_0V)) SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V); - if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V)) + if (ISSET(caps[0], SDHC_VOLTAGE_SUPP_3_3V)) SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V); /* * Determine the maximum block length supported by the host * controller. (2.2.24) */ - switch((caps >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK) { + switch((caps[0] >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK) { case SDHC_MAX_BLK_LEN_512: hp->maxblklen = 512; break; @@ -293,6 +307,13 @@ device_xname(sc->sc_dev), hp->maxblklen, hp->maxblklen > 1 ? "s" : "")); +#if notyet + if (ISSET(hp->flags, SHF_USE_ADMA)) + aprint_normal_dev(sc->sc_dev, "using ADMA transfer\n"); + else if (ISSET(hp->flags, SHF_USE_DMA)) + aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); +#endif + /* * Attach the generic SD/MMC bus driver. (The bus driver must * not invoke any chipset functions before it is attached.) @@ -308,8 +329,10 @@ saa.saa_clkmin /= 16; saa.saa_caps = SMC_CAPS_4BIT_MODE|SMC_CAPS_AUTO_STOP; #if notyet - if (ISSET(hp->flags, SHF_USE_DMA)) - saa.saa_caps |= SMC_CAPS_DMA; + if (ISSET(hp->flags, SHF_USE_DMA|SHF_USE_ADMA)) + SET(saa.saa_caps, SMC_CAPS_DMA); + if (ISSET(hp->flags, SHF_USE_ADMA)) + SET(saa.saa_caps, SMC_CAPS_MULTI_SEG_DMA); #endif hp->sdmmc = config_found(sc->sc_dev, &saa, NULL); @@ -395,6 +418,48 @@ return true; } +uint8_t +sdhc_read_1(struct sdhc_host *hp, int reg) +{ + + return HREAD1(hp, reg); +} + +uint16_t +sdhc_read_2(struct sdhc_host *hp, int reg) +{ + + return HREAD2(hp, reg); +} + +uint32_t +sdhc_read_4(struct sdhc_host *hp, int reg) +{ + + return HREAD4(hp, reg); +} + +void +sdhc_write_1(struct sdhc_host *hp, int reg, uint8_t val) +{ + + HWRITE1(hp, reg, val); +} + +void +sdhc_write_2(struct sdhc_host *hp, int reg, uint16_t val) +{ + + HWRITE2(hp, reg, val); +} + +void +sdhc_write_4(struct sdhc_host *hp, int reg, uint32_t val) +{ + + HWRITE4(hp, reg, val); +} + /* * Reset the host controller. Called during initialization, when * cards are removed, upon resume, and during error recovery. @@ -609,9 +674,7 @@ int error = 0; #ifdef DIAGNOSTIC int ispresent; -#endif -#ifdef DIAGNOSTIC mutex_enter(&hp->host_mtx); ispresent = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK); mutex_exit(&hp->host_mtx); @@ -1282,6 +1345,8 @@ HREAD2(hp, SDHC_EINTR_SIGNAL_EN)); printf("0x%02x CAPABILITIES: %x\n", SDHC_CAPABILITIES, HREAD4(hp, SDHC_CAPABILITIES)); + printf("0x%02x CAPABILITIES: %x\n", SDHC_CAPABILITIES_1, + HREAD4(hp, SDHC_CAPABILITIES_1)); printf("0x%02x MAX_CAPABILITIES: %x\n", SDHC_MAX_CAPABILITIES, HREAD4(hp, SDHC_MAX_CAPABILITIES)); } diff --exclude=CVS --exclude='.#*' --exclude='obj.*' --exclude='makeBuild*' -uNr src.orig/sys/dev/sdmmc/sdhcreg.h src/sys/dev/sdmmc/sdhcreg.h --- src.orig/sys/dev/sdmmc/sdhcreg.h 2012-02-02 08:02:22.000000000 +0900 +++ src/sys/dev/sdmmc/sdhcreg.h 2012-02-02 08:02:31.000000000 +0900 @@ -72,6 +72,12 @@ #define SDHC_CMD_INHIBIT_CMD (1<<0) #define SDHC_CMD_INHIBIT_MASK 0x0003 #define SDHC_HOST_CTL 0x28 +#define _SDHC_8BIT_MODE (1<<5) +#define SDHC_CTL_DMA_MASK (3<<3) +#define SDHC_CTL_DMA_SDMA (0<<3) +#define SDHC_CTL_DMA_ADMA1 (1<<3) +#define SDHC_CTL_DMA_ADMA2_32 (2<<3) +#define SDHC_CTL_DMA_ADMA2_64 (3<<3) #define SDHC_HIGH_SPEED (1<<2) #define SDHC_8BIT_MODE (1<<2) /* ESDHC */ #define SDHC_4BIT_MODE (1<<1) @@ -136,11 +142,15 @@ #define SDHC_EINTR_SIGNAL_MASK 0x01ff /* excluding vendor signals */ #define SDHC_CMD12_ERROR_STATUS 0x3c #define SDHC_CAPABILITIES 0x40 +#define SDHC_64BIT_SUPPORT (1<<28) #define SDHC_VOLTAGE_SUPP_1_8V (1<<26) #define SDHC_VOLTAGE_SUPP_3_0V (1<<25) #define SDHC_VOLTAGE_SUPP_3_3V (1<<24) #define SDHC_DMA_SUPPORT (1<<22) -#define SDHC_HIGH_SPEED_SUPP (1<<21) +#define SDHC_HIGH_SPEED_SUPPORT (1<<21) +#define SDHC_ADMA1_SUPPORT (1<<20) +#define SDHC_ADMA2_SUPPORT (1<<19) +#define SDHC_8BIT_MODE_SUPPORT (1<<18) #define SDHC_MAX_BLK_LEN_512 0 #define SDHC_MAX_BLK_LEN_1024 1 #define SDHC_MAX_BLK_LEN_2048 2 @@ -149,9 +159,24 @@ #define SDHC_MAX_BLK_LEN_MASK 0x3 #define SDHC_BASE_FREQ_SHIFT 8 #define SDHC_BASE_FREQ_MASK 0x3f +#define SDHC_SPEC300_BASE_FREQ_MASK 0xff #define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */ #define SDHC_TIMEOUT_FREQ_SHIFT 0 #define SDHC_TIMEOUT_FREQ_MASK 0x1f +#define SDHC_CAPABILITIES_1 0x44 +#define SDHC_SDR50_SUPP (1U<<0) +#define SDHC_SDR104_SUPP (1U<<1) +#define SDHC_DDR50_SUPP (1U<<2) +#define SDHC_DRIVER_TYPE_A (1U<<4) +#define SDHC_DRIVER_TYPE_C (1U<<5) +#define SDHC_DRIVER_TYPE_D (1U<<6) +#define SDHC_RET_TIMER_CNT_SHIFT 8 +#define SDHC_RET_TIMER_CNT_MASK 0xf +#define SDHC_USE_SDR50_TUNING (1U<<13) +#define SDHC_RET_MODE_SHIFT 14 +#define SDHC_RET_MODE_MASK 0x3 +#define SDHC_CLOCK_MUL_SHIFT 16 +#define SDHC_CLOCK_MUL_MASK 0xff #define SDHC_MAX_CAPABILITIES 0x48 #define SDHC_HOST_VER 0xFC #define SDHC_VVN_MASK 0x0f @@ -167,9 +192,16 @@ #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) +#define SDHC_SPEC300_BASE_FREQ_KHZ(cap) \ + ((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_SPEC300_BASE_FREQ_MASK) * 1000) #define SDHC_TIMEOUT_FREQ(cap) \ (((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK) #define SDHC_TIMEOUT_FREQ_KHZ(cap) \ @@ -177,6 +209,14 @@ SDHC_TIMEOUT_FREQ(cap) * 1000: \ SDHC_TIMEOUT_FREQ(cap)) +/* SDHC_CAPABILITIES_1 decoding */ +#define SDHC_RET_TIMER_CNT(cap) \ + (((cap) >> SDHC_RET_TIMER_CNT_SHIFT) & SDHC_RET_TIMER_CNT_MASK) +#define SDHC_RET_MODE(cap) \ + (((cap) >> SDHC_RET_MODE_SHIFT) & SDHC_RET_MODE_MASK) +#define SDHC_CLOCK_MUL(cap) \ + (((cap) >> SDHC_CLOCK_MUL_SHIFT) & SDHC_CLOCK_MUL_MASK) + /* SDHC_HOST_CTL_VERSION decoding */ #define SDHC_SPEC_VERSION(hcv) \ (((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK) diff --exclude=CVS --exclude='.#*' --exclude='obj.*' --exclude='makeBuild*' -uNr src.orig/sys/dev/sdmmc/sdhcvar.h src/sys/dev/sdmmc/sdhcvar.h --- src.orig/sys/dev/sdmmc/sdhcvar.h 2012-02-02 08:07:22.000000000 +0900 +++ src/sys/dev/sdmmc/sdhcvar.h 2012-02-02 08:06:43.000000000 +0900 @@ -35,14 +35,18 @@ bus_dma_tag_t sc_dmat; uint32_t sc_flags; -#define SDHC_FLAG_USE_DMA 0x0001 -#define SDHC_FLAG_FORCE_DMA 0x0002 -#define SDHC_FLAG_NO_PWR0 0x0004 /* Freescale ESDHC */ -#define SDHC_FLAG_HAVE_DVS 0x0008 /* Freescale ESDHC */ -#define SDHC_FLAG_32BIT_ACCESS 0x0010 /* Freescale ESDHC */ -#define SDHC_FLAG_ENHANCED 0x0020 /* Freescale ESDHC */ -#define SDHC_FLAG_8BIT_MODE 0x0040 /* MMC 8bit mode is supported */ -#define SDHC_FLAG_HAVE_CGM 0x0080 /* Netlogic XLP */ +#define SDHC_FLAG_USE_DMA 0x0001 +#define SDHC_FLAG_FORCE_DMA 0x0002 +#define SDHC_FLAG_NO_PWR0 0x0004 /* Freescale ESDHC */ +#define SDHC_FLAG_HAVE_DVS 0x0008 /* Freescale ESDHC */ +#define SDHC_FLAG_32BIT_ACCESS 0x0010 /* Freescale ESDHC */ +#define SDHC_FLAG_ENHANCED 0x0020 /* Freescale ESDHC */ +#define SDHC_FLAG_8BIT_MODE 0x0040 /* MMC 8bit mode is supported */ +#define SDHC_FLAG_HAVE_CGM 0x0080 /* Netlogic XLP */ +#define SDHC_FLAG_BROKEN_DMA 0x0100 +#define SDHC_FLAG_BROKEN_ADMA 0x0200 +#define SDHC_FLAG_BROKEN_RO_DETECT 0x0400 + uint32_t sc_clkbase; }; @@ -55,4 +59,11 @@ bool sdhc_resume(device_t, const pmf_qual_t *); bool sdhc_shutdown(device_t, int); +uint8_t sdhc_read_1(struct sdhc_host *, int reg); +uint16_t sdhc_read_2(struct sdhc_host *, int reg); +uint32_t sdhc_read_4(struct sdhc_host *, int reg); +void sdhc_write_1(struct sdhc_host *, int reg, uint8_t); +void sdhc_write_2(struct sdhc_host *, int reg, uint16_t); +void sdhc_write_4(struct sdhc_host *, int reg, uint32_t); + #endif /* _SDHCVAR_H_ */ --- src.orig/sys/dev/pci/sdhc_pci.c 2012-02-02 07:41:02.000000000 +0900 +++ src/sys/dev/pci/sdhc_pci.c 2012-02-02 07:40:03.000000000 +0900 @@ -20,6 +20,8 @@ #include __KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.5 2012/01/30 19:41:23 drochner Exp $"); +#include "opt_sdmmc.h" + #include #include #include @@ -33,9 +35,11 @@ #include #include -/* PCI base address registers */ -#define SDHC_PCI_BAR_START PCI_MAPREG_START -#define SDHC_PCI_BAR_END PCI_MAPREG_END +#ifdef SDHC_DEBUG +#define DPRINTF(s) printf s +#else +#define DPRINTF(s) /**/ +#endif /* PCI interface classes */ #define SDHC_PCI_INTERFACE_NO_DMA 0x00 @@ -50,9 +54,14 @@ #define SDHC_PCI_NUM_SLOTS(info) ((((info) >> 4) & 0x7) + 1) #define SDHC_PCI_FIRST_BAR(info) ((info) & 0x7) +struct sdhc_pci_quirk; struct sdhc_pci_softc { struct sdhc_softc sc; void *sc_ih; + pci_chipset_tag_t sc_pct; + pcitag_t sc_pt; + pcireg_t sc_id; + const struct sdhc_pci_quirk *sc_quirk; }; static int sdhc_pci_match(device_t, cfdata_t, void *); @@ -61,31 +70,64 @@ CFATTACH_DECL_NEW(sdhc_pci, sizeof(struct sdhc_pci_softc), sdhc_pci_match, sdhc_pci_attach, NULL, NULL); -#ifdef SDHC_DEBUG -#define DPRINTF(s) printf s -#else -#define DPRINTF(s) /**/ -#endif +static bool sdhc_pci_suspend(device_t, const pmf_qual_t *); +static bool sdhc_pci_resume(device_t, const pmf_qual_t *); + +static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *, + struct sdhc_pci_softc *); +static void sdhc_pci_quirk_jmicron_hack(struct pci_attach_args *, + struct sdhc_pci_softc *); +static int sdhc_pci_quirk_jmicron_host_add(struct pci_attach_args *, + struct sdhc_pci_softc *); +static void sdhc_pci_quirk_jmicron_host_remove(struct sdhc_pci_softc *); +static bool shdc_pci_quirk_jmicron_suspend(struct sdhc_pci_softc *, + const pmf_qual_t *); +static bool shdc_pci_quirk_jmicron_resume(struct sdhc_pci_softc *, + const pmf_qual_t *); + +struct sdhc_pci_quirk { + uint32_t flags; /* sdhc_softc.sc_flags */ + + int (*match)(struct pci_attach_args *); + void (*hack)(struct pci_attach_args *, struct sdhc_pci_softc *); + int (*host_add)(struct pci_attach_args *, struct sdhc_pci_softc *); + void (*host_remove)(struct sdhc_pci_softc *); + bool (*suspend)(struct sdhc_pci_softc *, const pmf_qual_t *); + bool (*resume)(struct sdhc_pci_softc *, const pmf_qual_t *); +}; + +static struct sdhc_pci_quirk ti_quirk = { + .hack = sdhc_pci_quirk_ti_hack, +}; + +static struct sdhc_pci_quirk ene_quirk = { + .flags = SDHC_FLAG_NO_PWR0, +}; -static const struct sdhc_pci_quirk { +static struct sdhc_pci_quirk jmicron_quirk = { + .hack = sdhc_pci_quirk_jmicron_hack, + .host_add = sdhc_pci_quirk_jmicron_host_add, + .host_remove = sdhc_pci_quirk_jmicron_host_remove, + .suspend = shdc_pci_quirk_jmicron_suspend, + .resume = shdc_pci_quirk_jmicron_resume, +}; + +static const struct sdhc_pci_quirks { pci_vendor_id_t vendor; pci_product_id_t product; pci_vendor_id_t subvendor; pci_product_id_t subproduct; 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) -} sdhc_pci_quirk_table[] = { + const struct sdhc_pci_quirk *quirk; +} sdhc_pci_quirks_table[] = { { PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI72111SD, 0xffff, 0xffff, 4, - SDHC_PCI_QUIRK_TI_HACK + &ti_quirk, }, { @@ -94,7 +136,7 @@ 0xffff, 0xffff, 3, - SDHC_PCI_QUIRK_TI_HACK + &ti_quirk, }, { @@ -103,23 +145,57 @@ 0xffff, 0xffff, 0, - SDHC_PCI_QUIRK_NO_PWR0 + &ene_quirk, + }, + + { + PCI_VENDOR_JMICRON, + PCI_PRODUCT_JMICRON_JMB38X_SD, + 0xffff, + 0xffff, + ~0, + &jmicron_quirk, }, -}; -static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *); + { + PCI_VENDOR_JMICRON, + PCI_PRODUCT_JMICRON_JMB38X_MMC, + 0xffff, + 0xffff, + ~0, + &jmicron_quirk, + }, -static uint32_t -sdhc_pci_lookup_quirk_flags(struct pci_attach_args *pa) + { + PCI_VENDOR_JMICRON, + PCI_PRODUCT_JMICRON_JMB388_SD, + 0xffff, + 0xffff, + ~0, + &jmicron_quirk, + }, + + { + PCI_VENDOR_JMICRON, + PCI_PRODUCT_JMICRON_JMB388_MMC, + 0xffff, + 0xffff, + ~0, + &jmicron_quirk, + }, +}; + +static const struct sdhc_pci_quirk * +sdhc_pci_lookup_quirk(struct pci_attach_args *pa) { - const struct sdhc_pci_quirk *q; + const struct sdhc_pci_quirks *q; pcireg_t id; pci_vendor_id_t vendor; pci_product_id_t product; int i; - for (i = 0; i < __arraycount(sdhc_pci_quirk_table); i++) { - q = &sdhc_pci_quirk_table[i]; + for (i = 0; i < __arraycount(sdhc_pci_quirks_table); i++) { + q = &sdhc_pci_quirks_table[i]; if ((PCI_VENDOR(pa->pa_id) == q->vendor) && (PCI_PRODUCT(pa->pa_id) == q->product)) { @@ -129,7 +205,7 @@ if ((q->subvendor == 0xffff) && (q->subproduct == 0xffff)) - return q->flags; + return q->quirk; id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); @@ -140,30 +216,39 @@ && (q->subproduct != 0xffff)) { if ((vendor == q->subvendor) && (product == q->subproduct)) - return q->flags; + return q->quirk; } else if (q->subvendor != 0xffff) { if (product == q->subproduct) - return q->flags; + return q->quirk; } else { if (vendor == q->subvendor) - return q->flags; + return q->quirk; } } } - return 0; + return NULL; } static int sdhc_pci_match(device_t parent, cfdata_t cf, void *aux) { struct pci_attach_args *pa = aux; + const struct sdhc_pci_quirk *quirk; + int error; - if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM && - PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC) - return 1; + if (PCI_CLASS(pa->pa_class) != PCI_CLASS_SYSTEM || + PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_SYSTEM_SDHC) + return 0; + + quirk = sdhc_pci_lookup_quirk(pa); + if (quirk && quirk->match) { + error = (*quirk->match)(pa); + if (error) + return 0; + } - return 0; + return 1; } static void @@ -177,28 +262,35 @@ pcireg_t csr; pcireg_t slotinfo; char const *intrstr; - int nslots; + int nslots, n; int reg; - int cnt; + int cnt, i; bus_space_tag_t iot; bus_space_handle_t ioh; bus_size_t size; - uint32_t flags; + pcireg_t memtype; + struct { + pcireg_t reg; + pcireg_t type; + } bar[(PCI_MAPREG_END - PCI_MAPREG_START) / sizeof(uint32_t)]; + int maxbar; sc->sc.sc_dev = self; sc->sc.sc_dmat = pa->pa_dmat; sc->sc.sc_host = NULL; + sc->sc_pct = pa->pa_pc; + sc->sc_pt = pa->pa_tag; + sc->sc_id = pa->pa_id; pci_aprint_devinfo(pa, NULL); /* Some controllers needs special treatment. */ - flags = sdhc_pci_lookup_quirk_flags(pa); - if (ISSET(flags, SDHC_PCI_QUIRK_TI_HACK)) - sdhc_pci_quirk_ti_hack(pa); - if (ISSET(flags, SDHC_PCI_QUIRK_FORCE_DMA)) - 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); + sc->sc_quirk = sdhc_pci_lookup_quirk(pa); + if (sc->sc_quirk) { + SET(sc->sc.sc_flags, sc->sc_quirk->flags); + if (sc->sc_quirk->hack) + (*sc->sc_quirk->hack)(pa, sc); + } /* * Map and attach all hosts supported by the host controller. @@ -237,30 +329,50 @@ if ((PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA)) SET(sc->sc.sc_flags, SDHC_FLAG_USE_DMA); - /* XXX: handle 64-bit BARs */ + for (reg = PCI_MAPREG_START, i = 0, n = nslots; + reg < PCI_MAPREG_END && n > 0; i++, --n) { + memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg); + bar[i].reg = reg; + bar[i].type = memtype; + if (memtype == (PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_64BIT)) + reg += sizeof(uint64_t); + else + reg += sizeof(uint32_t); + } + maxbar = i; +#ifdef SDHC_DEBUG + for (i = 0; i < maxbar; i++) { + printf("%s: bar[%d]: reg=0x%x, type=%s\n", + device_xname(self), i, bar[i].reg, + ((PCI_MAPREG_TYPE(bar[i].type) == PCI_MAPREG_TYPE_IO) ? "IO" + : (bar[i].type == + (PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_64BIT)) ? + "MEM64" : "MEM32")); + } +#endif + cnt = 0; - for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) * - sizeof(uint32_t); - reg < SDHC_PCI_BAR_END && nslots > 0; - reg += sizeof(uint32_t), nslots--) { - if (pci_mapreg_map(pa, reg, PCI_MAPREG_TYPE_MEM, 0, - &iot, &ioh, NULL, &size)) { + for (i = SDHC_PCI_FIRST_BAR(slotinfo); + i < maxbar && nslots > 0; i++, --nslots) { + if (PCI_MAPREG_TYPE(bar[i].type) != PCI_MAPREG_TYPE_MEM) + continue; + if (pci_mapreg_map(pa, bar[i].reg, bar[i].type, 0, &iot, &ioh, + NULL, &size)) continue; - } cnt++; - if (sdhc_host_found(&sc->sc, iot, ioh, size) != 0) { - /* XXX: sc->sc_host leak */ + if (sdhc_host_found(&sc->sc, iot, ioh, size)) aprint_error_dev(self, - "couldn't initialize host (0x%x)\n", reg); - } + "couldn't initialize host (0x%x)\n", bar[i].reg); + else if (sc->sc_quirk && sc->sc_quirk->host_add) + (*sc->sc_quirk->host_add)(pa, sc); } if (cnt == 0) { aprint_error_dev(self, "couldn't map register\n"); goto err; } - if (!pmf_device_register1(self, sdhc_suspend, sdhc_resume, + if (!pmf_device_register1(self, sdhc_pci_suspend, sdhc_pci_resume, sdhc_shutdown)) { aprint_error_dev(self, "couldn't establish powerhook\n"); } @@ -272,12 +384,37 @@ free(sc->sc.sc_host, M_DEVBUF); } -/* TI specific register */ +static bool +sdhc_pci_suspend(device_t self, const pmf_qual_t *qual) +{ + struct sdhc_pci_softc *sc = device_private(self); + + if (sc->sc_quirk && sc->sc_quirk->suspend) + (*sc->sc_quirk->suspend)(sc, qual); + + return sdhc_suspend(self, qual); +} + +static bool +sdhc_pci_resume(device_t self, const pmf_qual_t *qual) +{ + struct sdhc_pci_softc *sc = device_private(self); + + if (!sdhc_resume(self, qual)) + return false; + + if (sc->sc_quirk && sc->sc_quirk->resume) + (*sc->sc_quirk->resume)(sc, qual); + + return true; +} + +/* TI specific */ #define SDHC_PCI_GENERAL_CTL 0x4c #define MMC_SD_DIS 0x02 static void -sdhc_pci_quirk_ti_hack(struct pci_attach_args *pa) +sdhc_pci_quirk_ti_hack(struct pci_attach_args *pa, struct sdhc_pci_softc *sc) { pci_chipset_tag_t pc = pa->pa_pc; pcitag_t tag; @@ -302,6 +439,160 @@ * SD host takes over. */ reg = pci_conf_read(pc, tag, SDHC_PCI_GENERAL_CTL); - reg |= MMC_SD_DIS; + SET(reg, MMC_SD_DIS); pci_conf_write(pc, tag, SDHC_PCI_GENERAL_CTL, reg); } + +/* JMicron specific */ +#define JMICRON_PMOS 0xae +#define PMOS_ON (1U << 0) /* Turn PMOS on */ +#define PMOS_DET_2_4V (3U << 1) /* over current detection to 2.4V */ +#define PMOS_DEBOUNCE (1U << 6) /* enable over current debouncing */ + +/* pci_conf_{read,write}() require 4bytes aligned register number */ +#define JMICRON_PMOS_REG (JMICRON_PMOS & ~3) +#define JMICRON_PMOS_SB ((JMICRON_PMOS & 3) * 8) + +static __inline uint8_t +jmicron_pmos_read(pci_chipset_tag_t pct, pcitag_t pt) +{ + pcireg_t reg; + + reg = pci_conf_read(pct, pt, JMICRON_PMOS_REG); + reg >>= JMICRON_PMOS_SB; + + return (uint8_t)reg; +} + +static __inline void +jmicron_pmos_write(pci_chipset_tag_t pct, pcitag_t pt, uint8_t pmos) +{ + pcireg_t reg; + + reg = pci_conf_read(pct, pt, JMICRON_PMOS_REG); + CLR(reg, 0xff << JMICRON_PMOS_SB); + SET(reg, pmos << JMICRON_PMOS_SB); + pci_conf_write(pct, pt, JMICRON_PMOS_REG, reg); +} + +static void +jmicron_pmos(pci_chipset_tag_t pct, pcitag_t pt, int onoff) +{ + uint8_t pmos; + + pmos = jmicron_pmos_read(pct, pt); + if (onoff) + SET(pmos, PMOS_ON | PMOS_DET_2_4V | PMOS_DEBOUNCE); + else + CLR(pmos, PMOS_ON | PMOS_DET_2_4V | PMOS_DEBOUNCE); + jmicron_pmos_write(pct, pt, pmos); +} + +static void +sdhc_pci_quirk_jmicron_hack(struct pci_attach_args *pa, + struct sdhc_pci_softc *sc) +{ + + /* power on */ + jmicron_pmos(sc->sc_pct, sc->sc_pt, 1); + + switch (PCI_PRODUCT(sc->sc_id)) { + case PCI_PRODUCT_JMICRON_JMB38X_SD: + case PCI_PRODUCT_JMICRON_JMB388_SD: + SET(sc->sc.sc_flags, SDHC_FLAG_BROKEN_RO_DETECT); + break; + } +} + +#define JMICRON_MMC_INTR 0xc0 +#define MMC_INTR_EN 0x01 + +static void +jmicron_mmc_enable_intr(struct sdhc_host *hp, int onoff) +{ + uint8_t reg; + + reg = sdhc_read_1(hp, JMICRON_MMC_INTR); + if (onoff) + SET(reg, MMC_INTR_EN); + else + CLR(reg, MMC_INTR_EN); + sdhc_write_1(hp, JMICRON_MMC_INTR, reg); +} + +static int +sdhc_pci_quirk_jmicron_host_add(struct pci_attach_args *pa, + struct sdhc_pci_softc *sc) +{ + struct sdhc_host *hp = sc->sc.sc_host[sc->sc.sc_nhosts - 1]; + uint16_t sdhcver; + + if (PCI_REVISION(pa->pa_class) == 0) { + sdhcver = sdhc_read_2(hp, SDHC_HOST_CTL_VERSION); + if (SDHC_VENDOR_VERSION(sdhcver) < 0xac) + SET(sc->sc.sc_flags, SDHC_FLAG_BROKEN_ADMA); + } + + switch (PCI_PRODUCT(sc->sc_id)) { + case PCI_PRODUCT_JMICRON_JMB38X_MMC: + case PCI_PRODUCT_JMICRON_JMB388_MMC: + jmicron_mmc_enable_intr(hp, 1); + break; + } + return 0; +} + +static void +sdhc_pci_quirk_jmicron_host_remove(struct sdhc_pci_softc *sc) +{ + struct sdhc_host *hp = sc->sc.sc_host[sc->sc.sc_nhosts - 1]; + + switch (PCI_PRODUCT(sc->sc_id)) { + case PCI_PRODUCT_JMICRON_JMB38X_MMC: + case PCI_PRODUCT_JMICRON_JMB388_MMC: + jmicron_mmc_enable_intr(hp, 1); + break; + } +} + +static bool +shdc_pci_quirk_jmicron_suspend(struct sdhc_pci_softc *sc, + const pmf_qual_t *qual) +{ + int i; + + switch (PCI_PRODUCT(sc->sc_id)) { + case PCI_PRODUCT_JMICRON_JMB38X_MMC: + case PCI_PRODUCT_JMICRON_JMB388_MMC: + for (i = 0; i < sc->sc.sc_nhosts; i++) + jmicron_mmc_enable_intr(sc->sc.sc_host[i], 0); + break; + } + +#if 0 + /* power off */ + jmicron_pmos(sc->sc_pct, sc->sc_pt, 0); +#endif + + return true; +} + +static bool +shdc_pci_quirk_jmicron_resume(struct sdhc_pci_softc *sc, + const pmf_qual_t *qual) +{ + int i; + + switch (PCI_PRODUCT(sc->sc_id)) { + case PCI_PRODUCT_JMICRON_JMB38X_MMC: + case PCI_PRODUCT_JMICRON_JMB388_MMC: + for (i = 0; i < sc->sc.sc_nhosts; i++) + jmicron_mmc_enable_intr(sc->sc.sc_host[i], 1); + break; + } + + /* power on */ + jmicron_pmos(sc->sc_pct, sc->sc_pt, 1); + + return true; +} --- src.orig/sys/dev/cardbus/sdhc_cardbus.c 2011-08-01 20:20:28.000000000 +0900 +++ src/sys/dev/cardbus/sdhc_cardbus.c 2012-02-02 07:40:31.000000000 +0900 @@ -28,6 +28,8 @@ #include __KERNEL_RCSID(0, "$NetBSD: sdhc_cardbus.c,v 1.3 2011/08/01 11:20:28 drochner Exp $"); +#include "opt_sdmmc.h" + #include #include #include