Module Name: src Committed By: nonaka Date: Fri Feb 17 10:51:48 UTC 2017
Modified Files: src/sys/dev/acpi: sdhc_acpi.c src/sys/dev/pci: sdhc_pci.c src/sys/dev/sdmmc: sdhc.c sdhcvar.h sdmmc.c sdmmc_mem.c sdmmcchip.h sdmmcreg.h sdmmcvar.h Log Message: sdhc(4): hardware reset support for Intel eMMC controller To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/dev/acpi/sdhc_acpi.c cvs rdiff -u -r1.12 -r1.13 src/sys/dev/pci/sdhc_pci.c cvs rdiff -u -r1.98 -r1.99 src/sys/dev/sdmmc/sdhc.c cvs rdiff -u -r1.27 -r1.28 src/sys/dev/sdmmc/sdhcvar.h cvs rdiff -u -r1.33 -r1.34 src/sys/dev/sdmmc/sdmmc.c cvs rdiff -u -r1.54 -r1.55 src/sys/dev/sdmmc/sdmmc_mem.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/sdmmc/sdmmcchip.h cvs rdiff -u -r1.28 -r1.29 src/sys/dev/sdmmc/sdmmcreg.h cvs rdiff -u -r1.22 -r1.23 src/sys/dev/sdmmc/sdmmcvar.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/acpi/sdhc_acpi.c diff -u src/sys/dev/acpi/sdhc_acpi.c:1.3 src/sys/dev/acpi/sdhc_acpi.c:1.4 --- src/sys/dev/acpi/sdhc_acpi.c:1.3 Thu Aug 11 01:54:30 2016 +++ src/sys/dev/acpi/sdhc_acpi.c Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc_acpi.c,v 1.3 2016/08/11 01:54:30 nonaka Exp $ */ +/* $NetBSD: sdhc_acpi.c,v 1.4 2017/02/17 10:51:48 nonaka Exp $ */ /* * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc_acpi.c,v 1.3 2016/08/11 01:54:30 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc_acpi.c,v 1.4 2017/02/17 10:51:48 nonaka Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -50,6 +50,9 @@ static bool sdhc_acpi_resume(device_t, c struct sdhc_acpi_softc { struct sdhc_softc sc; + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + bus_size_t sc_memsize; int sc_irq; ACPI_HANDLE sc_crs, sc_srs; @@ -59,14 +62,58 @@ struct sdhc_acpi_softc { CFATTACH_DECL_NEW(sdhc_acpi, sizeof(struct sdhc_acpi_softc), sdhc_acpi_match, sdhc_acpi_attach, sdhc_acpi_detach, NULL); -static uint32_t sdhc_acpi_intr(void *); - -static const char * const sdhc_acpi_ids[] = { - "80860F14", - "80860F16", - NULL +static uint32_t sdhc_acpi_intr(void *); +static void sdhc_acpi_intel_emmc_hw_reset(struct sdhc_softc *, + struct sdhc_host *); + +static const struct sdhc_acpi_slot { + const char *hid; + const char *uid; + int type; +#define SLOT_TYPE_SD 0 /* SD or SDIO */ +#define SLOT_TYPE_EMMC 1 /* eMMC */ +} sdhc_acpi_slot_map[] = { + { "80865ACA", NULL, SLOT_TYPE_SD }, + { "80865ACC", NULL, SLOT_TYPE_EMMC }, + { "80865AD0", NULL, SLOT_TYPE_SD }, + { "80860F14", "1", SLOT_TYPE_EMMC }, + { "80860F14", "3", SLOT_TYPE_SD }, + { "80860F16", NULL, SLOT_TYPE_SD }, + { "INT33BB", "2", SLOT_TYPE_SD }, + { "INT33BB", "3", SLOT_TYPE_SD }, + { "INT33C6", NULL, SLOT_TYPE_SD }, + { "INT3436", NULL, SLOT_TYPE_SD }, + { "INT344D", NULL, SLOT_TYPE_SD }, + { "PNP0D40", NULL, SLOT_TYPE_SD }, + { "PNP0FFF", "3", SLOT_TYPE_SD }, }; +static const struct sdhc_acpi_slot * +sdhc_acpi_find_slot(ACPI_DEVICE_INFO *ad) +{ + const struct sdhc_acpi_slot *slot; + const char *hid, *uid; + size_t i; + + hid = ad->HardwareId.String; + uid = ad->UniqueId.String; + + if (!(ad->Valid & ACPI_VALID_HID) || hid == NULL) + return NULL; + + for (i = 0; i < __arraycount(sdhc_acpi_slot_map); i++) { + slot = &sdhc_acpi_slot_map[i]; + if (strcmp(hid, slot->hid) == 0) { + if (slot->uid == NULL || + ((ad->Valid & ACPI_VALID_UID) != 0 && + uid != NULL && + strcmp(uid, slot->uid) == 0)) + return slot; + } + } + return NULL; +} + static int sdhc_acpi_match(device_t parent, cfdata_t match, void *opaque) { @@ -75,7 +122,7 @@ sdhc_acpi_match(device_t parent, cfdata_ if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) return 0; - return acpi_match_hid(aa->aa_node->ad_devinfo, sdhc_acpi_ids); + return sdhc_acpi_find_slot(aa->aa_node->ad_devinfo) != NULL; } static void @@ -83,17 +130,22 @@ sdhc_acpi_attach(device_t parent, device { struct sdhc_acpi_softc *sc = device_private(self); struct acpi_attach_args *aa = opaque; + const struct sdhc_acpi_slot *slot; struct acpi_resources res; struct acpi_mem *mem; struct acpi_irq *irq; - bus_space_handle_t memh; ACPI_STATUS rv; sc->sc.sc_dev = self; sc->sc.sc_dmat = aa->aa_dmat; sc->sc.sc_host = NULL; + sc->sc_memt = aa->aa_memt; sc->sc_irq = -1; + slot = sdhc_acpi_find_slot(aa->aa_node->ad_devinfo); + if (slot->type == SLOT_TYPE_EMMC) + sc->sc.sc_vendor_hw_reset = sdhc_acpi_intel_emmc_hw_reset; + rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res, &acpi_resource_parse_ops_default); if (ACPI_FAILURE(rv)) @@ -116,9 +168,10 @@ sdhc_acpi_attach(device_t parent, device aprint_error_dev(self, "incomplete resources\n"); goto cleanup; } + sc->sc_memsize = mem->ar_length; - if (bus_space_map(aa->aa_memt, mem->ar_base, mem->ar_length, 0, - &memh)) { + if (bus_space_map(sc->sc_memt, mem->ar_base, sc->sc_memsize, 0, + &sc->sc_memh)) { aprint_error_dev(self, "couldn't map registers\n"); goto cleanup; } @@ -128,22 +181,23 @@ sdhc_acpi_attach(device_t parent, device if (ACPI_FAILURE(rv)) { aprint_error_dev(self, "couldn't establish interrupt handler\n"); - goto cleanup; + goto unmap; } sc->sc_irq = irq->ar_irq; sc->sc.sc_host = kmem_zalloc(sizeof(struct sdhc_host *), KM_NOSLEEP); if (sc->sc.sc_host == NULL) { aprint_error_dev(self, "couldn't alloc memory\n"); - goto cleanup; + goto intr_disestablish; } /* Enable DMA transfer */ sc->sc.sc_flags |= SDHC_FLAG_USE_DMA; - if (sdhc_host_found(&sc->sc, aa->aa_memt, memh, mem->ar_length) != 0) { + if (sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, + sc->sc_memsize) != 0) { aprint_error_dev(self, "couldn't initialize host\n"); - goto cleanup; + goto fail; } if (!pmf_device_register1(self, sdhc_suspend, sdhc_acpi_resume, @@ -154,15 +208,23 @@ sdhc_acpi_attach(device_t parent, device acpi_resource_cleanup(&res); return; -cleanup: - acpi_resource_cleanup(&res); - if (sc->sc_crs_buffer.Pointer) - ACPI_FREE(sc->sc_crs_buffer.Pointer); +fail: + if (sc->sc.sc_host != NULL) + kmem_free(sc->sc.sc_host, sizeof(struct sdhc_host *)); + sc->sc.sc_host = NULL; +intr_disestablish: if (sc->sc_irq >= 0) /* XXX acpi_intr_disestablish? */ AcpiOsRemoveInterruptHandler(sc->sc_irq, sdhc_acpi_intr); - if (sc->sc.sc_host != NULL) - kmem_free(sc->sc.sc_host, sizeof(struct sdhc_host *)); + sc->sc_irq = -1; +unmap: + bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize); + sc->sc_memsize = 0; +cleanup: + if (sc->sc_crs_buffer.Pointer) + ACPI_FREE(sc->sc_crs_buffer.Pointer); + sc->sc_crs_buffer.Pointer = NULL; + acpi_resource_cleanup(&res); } static int @@ -173,9 +235,6 @@ sdhc_acpi_detach(device_t self, int flag pmf_device_deregister(self); - if (sc->sc_crs_buffer.Pointer) - ACPI_FREE(sc->sc_crs_buffer.Pointer); - rv = sdhc_detach(&sc->sc, flags); if (rv) return rv; @@ -187,6 +246,12 @@ sdhc_acpi_detach(device_t self, int flag if (sc->sc.sc_host != NULL) kmem_free(sc->sc.sc_host, sizeof(struct sdhc_host *)); + if (sc->sc_memsize > 0) + bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize); + + if (sc->sc_crs_buffer.Pointer) + ACPI_FREE(sc->sc_crs_buffer.Pointer); + return 0; } @@ -215,3 +280,25 @@ sdhc_acpi_intr(void *context) return ACPI_INTERRUPT_NOT_HANDLED; return ACPI_INTERRUPT_HANDLED; } + +static void +sdhc_acpi_intel_emmc_hw_reset(struct sdhc_softc *sc, struct sdhc_host *hp) +{ + kmutex_t *plock = sdhc_host_lock(hp); + uint8_t reg; + + mutex_enter(plock); + + reg = sdhc_host_read_1(hp, SDHC_POWER_CTL); + reg |= 0x10; + sdhc_host_write_1(hp, SDHC_POWER_CTL, reg); + + sdmmc_delay(10); + + reg &= ~0x10; + sdhc_host_write_1(hp, SDHC_POWER_CTL, reg); + + sdmmc_delay(1000); + + mutex_exit(plock); +} Index: src/sys/dev/pci/sdhc_pci.c diff -u src/sys/dev/pci/sdhc_pci.c:1.12 src/sys/dev/pci/sdhc_pci.c:1.13 --- src/sys/dev/pci/sdhc_pci.c:1.12 Sun Aug 9 13:27:48 2015 +++ src/sys/dev/pci/sdhc_pci.c Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc_pci.c,v 1.12 2015/08/09 13:27:48 mlelstv Exp $ */ +/* $NetBSD: sdhc_pci.c,v 1.13 2017/02/17 10:51:48 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.12 2015/08/09 13:27:48 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.13 2017/02/17 10:51:48 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -81,11 +81,12 @@ 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_RICOH_LOWER_FREQ_HACK (1U << 3) -#define SDHC_PCI_QUIRK_RICOH_SLOW_SDR50_HACK (1U << 4) +#define SDHC_PCI_QUIRK_FORCE_DMA __BIT(0) +#define SDHC_PCI_QUIRK_TI_HACK __BIT(1) +#define SDHC_PCI_QUIRK_NO_PWR0 __BIT(2) +#define SDHC_PCI_QUIRK_RICOH_LOWER_FREQ_HACK __BIT(3) +#define SDHC_PCI_QUIRK_RICOH_SLOW_SDR50_HACK __BIT(4) +#define SDHC_PCI_QUIRK_INTEL_EMMC_HW_RESET __BIT(5) } sdhc_pci_quirk_table[] = { { PCI_VENDOR_TI, @@ -138,10 +139,39 @@ static const struct sdhc_pci_quirk { ~0, SDHC_PCI_QUIRK_FORCE_DMA }, + + { + PCI_VENDOR_INTEL, + PCI_PRODUCT_INTEL_BAYTRAIL_SCC_MMC, + 0xffff, + 0xffff, + ~0, + SDHC_PCI_QUIRK_INTEL_EMMC_HW_RESET + }, + + { + PCI_VENDOR_INTEL, + PCI_PRODUCT_INTEL_BSW_SSC_MMC, + 0xffff, + 0xffff, + ~0, + SDHC_PCI_QUIRK_INTEL_EMMC_HW_RESET + }, + + { + PCI_VENDOR_INTEL, + PCI_PRODUCT_INTEL_100SERIES_LP_EMMC, + 0xffff, + 0xffff, + ~0, + SDHC_PCI_QUIRK_INTEL_EMMC_HW_RESET + }, }; 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 void sdhc_pci_intel_emmc_hw_reset(struct sdhc_softc *, + struct sdhc_host *); static uint32_t sdhc_pci_lookup_quirk_flags(struct pci_attach_args *pa) @@ -242,6 +272,8 @@ sdhc_pci_attach(device_t parent, device_ sdhc_pci_quirk_ricoh_lower_freq_hack(pa); if (ISSET(flags, SDHC_PCI_QUIRK_RICOH_SLOW_SDR50_HACK)) SET(sc->sc.sc_flags, SDHC_FLAG_SLOW_SDR50); + if (ISSET(flags, SDHC_PCI_QUIRK_INTEL_EMMC_HW_RESET)) + sc->sc.sc_vendor_hw_reset = sdhc_pci_intel_emmc_hw_reset; /* * Map and attach all hosts supported by the host controller. @@ -410,3 +442,25 @@ sdhc_pci_quirk_ricoh_lower_freq_hack(str sdhc_pci_conf_write(pa, SDHC_PCI_BASE_FREQ_KEY, 0x00); printf("quirked\n"); } + +static void +sdhc_pci_intel_emmc_hw_reset(struct sdhc_softc *sc, struct sdhc_host *hp) +{ + kmutex_t *plock = sdhc_host_lock(hp); + uint8_t reg; + + mutex_enter(plock); + + reg = sdhc_host_read_1(hp, SDHC_POWER_CTL); + reg |= 0x10; + sdhc_host_write_1(hp, SDHC_POWER_CTL, reg); + + sdmmc_delay(10); + + reg &= ~0x10; + sdhc_host_write_1(hp, SDHC_POWER_CTL, reg); + + sdmmc_delay(1000); + + mutex_exit(plock); +} Index: src/sys/dev/sdmmc/sdhc.c diff -u src/sys/dev/sdmmc/sdhc.c:1.98 src/sys/dev/sdmmc/sdhc.c:1.99 --- src/sys/dev/sdmmc/sdhc.c:1.98 Fri Feb 17 10:50:43 2017 +++ src/sys/dev/sdmmc/sdhc.c Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.98 2017/02/17 10:50:43 nonaka Exp $ */ +/* $NetBSD: sdhc.c,v 1.99 2017/02/17 10:51:48 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.98 2017/02/17 10:50:43 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.99 2017/02/17 10:51:48 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -192,6 +192,7 @@ static int sdhc_signal_voltage(sdmmc_chi static int sdhc_execute_tuning1(struct sdhc_host *, int); static int sdhc_execute_tuning(sdmmc_chipset_handle_t, int); static void sdhc_tuning_timer(void *); +static void sdhc_hw_reset(sdmmc_chipset_handle_t); static int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); static int sdhc_wait_state(struct sdhc_host *, uint32_t, uint32_t); static int sdhc_soft_reset(struct sdhc_host *, int); @@ -235,6 +236,7 @@ static struct sdmmc_chip_functions sdhc_ .signal_voltage = sdhc_signal_voltage, .bus_clock_ddr = sdhc_bus_clock_ddr, .execute_tuning = sdhc_execute_tuning, + .hw_reset = sdhc_hw_reset, }; static int @@ -1479,6 +1481,16 @@ sdhc_tuning_timer(void *arg) atomic_swap_uint(&hp->tuning_timer_pending, 1); } +static void +sdhc_hw_reset(sdmmc_chipset_handle_t sch) +{ + struct sdhc_host *hp = (struct sdhc_host *)sch; + struct sdhc_softc *sc = hp->sc; + + if (sc->sc_vendor_hw_reset != NULL) + sc->sc_vendor_hw_reset(sc, hp); +} + static int sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value) { @@ -2402,6 +2414,42 @@ sdhc_host_lock(struct sdhc_host *hp) return &hp->intr_lock; } +uint8_t +sdhc_host_read_1(struct sdhc_host *hp, int reg) +{ + return HREAD1(hp, reg); +} + +uint16_t +sdhc_host_read_2(struct sdhc_host *hp, int reg) +{ + return HREAD2(hp, reg); +} + +uint32_t +sdhc_host_read_4(struct sdhc_host *hp, int reg) +{ + return HREAD4(hp, reg); +} + +void +sdhc_host_write_1(struct sdhc_host *hp, int reg, uint8_t val) +{ + HWRITE1(hp, reg, val); +} + +void +sdhc_host_write_2(struct sdhc_host *hp, int reg, uint16_t val) +{ + HWRITE2(hp, reg, val); +} + +void +sdhc_host_write_4(struct sdhc_host *hp, int reg, uint32_t val) +{ + HWRITE4(hp, reg, val); +} + #ifdef SDHC_DEBUG void sdhc_dump_regs(struct sdhc_host *hp) Index: src/sys/dev/sdmmc/sdhcvar.h diff -u src/sys/dev/sdmmc/sdhcvar.h:1.27 src/sys/dev/sdmmc/sdhcvar.h:1.28 --- src/sys/dev/sdmmc/sdhcvar.h:1.27 Sat Jan 7 15:05:08 2017 +++ src/sys/dev/sdmmc/sdhcvar.h Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhcvar.h,v 1.27 2017/01/07 15:05:08 kiyohara Exp $ */ +/* $NetBSD: sdhcvar.h,v 1.28 2017/02/17 10:51:48 nonaka Exp $ */ /* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */ /* @@ -73,6 +73,7 @@ struct sdhc_softc { int (*sc_vendor_bus_width)(struct sdhc_softc *, int); int (*sc_vendor_bus_clock)(struct sdhc_softc *, int); int (*sc_vendor_transfer_data_dma)(struct sdhc_softc *, struct sdmmc_command *); + void (*sc_vendor_hw_reset)(struct sdhc_softc *, struct sdhc_host *); }; /* Host controller functions called by the attachment driver. */ @@ -84,5 +85,11 @@ bool sdhc_suspend(device_t, const pmf_qu bool sdhc_resume(device_t, const pmf_qual_t *); bool sdhc_shutdown(device_t, int); kmutex_t *sdhc_host_lock(struct sdhc_host *); +uint8_t sdhc_host_read_1(struct sdhc_host *, int); +uint16_t sdhc_host_read_2(struct sdhc_host *, int); +uint32_t sdhc_host_read_4(struct sdhc_host *, int); +void sdhc_host_write_1(struct sdhc_host *, int, uint8_t); +void sdhc_host_write_2(struct sdhc_host *, int, uint16_t); +void sdhc_host_write_4(struct sdhc_host *, int, uint32_t); #endif /* _SDHCVAR_H_ */ Index: src/sys/dev/sdmmc/sdmmc.c diff -u src/sys/dev/sdmmc/sdmmc.c:1.33 src/sys/dev/sdmmc/sdmmc.c:1.34 --- src/sys/dev/sdmmc/sdmmc.c:1.33 Tue Dec 22 09:55:38 2015 +++ src/sys/dev/sdmmc/sdmmc.c Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc.c,v 1.33 2015/12/22 09:55:38 mlelstv Exp $ */ +/* $NetBSD: sdmmc.c,v 1.34 2017/02/17 10:51:48 nonaka Exp $ */ /* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */ /* @@ -49,7 +49,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.33 2015/12/22 09:55:38 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.34 2017/02/17 10:51:48 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -400,6 +400,8 @@ sdmmc_card_attach(struct sdmmc_softc *sc CLR(sc->sc_flags, SMF_CARD_ATTACHED); + sdmmc_chip_hw_reset(sc->sc_sct, sc->sc_sch); + /* * Power up the card (or card stack). */ Index: src/sys/dev/sdmmc/sdmmc_mem.c diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.54 src/sys/dev/sdmmc/sdmmc_mem.c:1.55 --- src/sys/dev/sdmmc/sdmmc_mem.c:1.54 Fri Feb 17 10:50:43 2017 +++ src/sys/dev/sdmmc/sdmmc_mem.c Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_mem.c,v 1.54 2017/02/17 10:50:43 nonaka Exp $ */ +/* $NetBSD: sdmmc_mem.c,v 1.55 2017/02/17 10:51:48 nonaka Exp $ */ /* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -45,7 +45,7 @@ /* Routines for SD/MMC memory cards. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.54 2017/02/17 10:50:43 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.55 2017/02/17 10:51:48 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -934,6 +934,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s ext_csd[EXT_CSD_STRUCTURE]); return ENOTSUP; } + sf->ext_csd.rev = ext_csd[EXT_CSD_REV]; if (ISSET(sc->sc_caps, SMC_CAPS_MMC_HS200) && ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_HS200_1_8V) { @@ -1088,6 +1089,11 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s return error; } } + + if (sf->ext_csd.rev >= 5) { + sf->ext_csd.rst_n_function = + ext_csd[EXT_CSD_RST_N_FUNCTION]; + } } else { if (sc->sc_busclk > sf->csd.tran_speed) sc->sc_busclk = sf->csd.tran_speed; Index: src/sys/dev/sdmmc/sdmmcchip.h diff -u src/sys/dev/sdmmc/sdmmcchip.h:1.8 src/sys/dev/sdmmc/sdmmcchip.h:1.9 --- src/sys/dev/sdmmc/sdmmcchip.h:1.8 Fri Feb 17 10:50:43 2017 +++ src/sys/dev/sdmmc/sdmmcchip.h Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcchip.h,v 1.8 2017/02/17 10:50:43 nonaka Exp $ */ +/* $NetBSD: sdmmcchip.h,v 1.9 2017/02/17 10:51:48 nonaka Exp $ */ /* $OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $ */ /* @@ -62,6 +62,9 @@ struct sdmmc_chip_functions { int (*signal_voltage)(sdmmc_chipset_handle_t, int); int (*bus_clock_ddr)(sdmmc_chipset_handle_t, int, bool); int (*execute_tuning)(sdmmc_chipset_handle_t, int); + + /* hardware reset */ + void (*hw_reset)(sdmmc_chipset_handle_t); }; /* host controller reset */ @@ -100,6 +103,9 @@ struct sdmmc_chip_functions { ((tag)->signal_voltage ? (tag)->signal_voltage((handle), (voltage)) : EINVAL) #define sdmmc_chip_execute_tuning(tag, handle, timing) \ ((tag)->execute_tuning ? (tag)->execute_tuning((handle), (timing)) : EINVAL) +/* hardware reset */ +#define sdmmc_chip_hw_reset(tag, handle) \ + ((tag)->hw_reset ? (tag)->hw_reset((handle)) : /*CONSTCOND*/0) /* clock frequencies for sdmmc_chip_bus_clock() */ #define SDMMC_SDCLK_OFF 0 Index: src/sys/dev/sdmmc/sdmmcreg.h diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.28 src/sys/dev/sdmmc/sdmmcreg.h:1.29 --- src/sys/dev/sdmmc/sdmmcreg.h:1.28 Fri Feb 17 10:47:09 2017 +++ src/sys/dev/sdmmc/sdmmcreg.h Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcreg.h,v 1.28 2017/02/17 10:47:09 nonaka Exp $ */ +/* $NetBSD: sdmmcreg.h,v 1.29 2017/02/17 10:51:48 nonaka Exp $ */ /* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -115,6 +115,7 @@ #define SD_ARG_BUS_WIDTH_4 2 /* EXT_CSD fields */ +#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ #define EXT_CSD_BUS_WIDTH 183 /* W/E_P */ #define EXT_CSD_HS_TIMING 185 /* R/W/E_P */ #define EXT_CSD_REV 192 /* R */ @@ -155,6 +156,12 @@ #define EXT_CSD_CARD_TYPE_F_HS400_1_8V (1 << 6) /* HS400 DDR 200 MHz 1.8V */ #define EXT_CSD_CARD_TYPE_F_HS400_1_2V (1 << 7) /* HS400 DDR 200 MHz 1.2V */ +/* EXT_CSD_RST_N_FUNCTION */ +#define EXT_CSD_RST_N_TMP_DISABLED 0x00 +#define EXT_CSD_RST_N_PERM_ENABLED 0x01 +#define EXT_CSD_RST_N_PERM_DISABLED 0x02 +#define EXT_CSD_RST_N_MASK 0x03 + /* MMC_SWITCH access mode */ #define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in value */ Index: src/sys/dev/sdmmc/sdmmcvar.h diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.22 src/sys/dev/sdmmc/sdmmcvar.h:1.23 --- src/sys/dev/sdmmc/sdmmcvar.h:1.22 Fri Feb 17 10:49:47 2017 +++ src/sys/dev/sdmmc/sdmmcvar.h Fri Feb 17 10:51:48 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcvar.h,v 1.22 2017/02/17 10:49:47 nonaka Exp $ */ +/* $NetBSD: sdmmcvar.h,v 1.23 2017/02/17 10:51:48 nonaka Exp $ */ /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -49,6 +49,11 @@ struct sdmmc_csd { /* ... */ }; +struct sdmmc_ext_csd { + uint8_t rev; + uint8_t rst_n_function; /* RST_n_FUNCTION */ +}; + struct sdmmc_cid { int mid; /* manufacturer identification number */ int oid; /* OEM/product identification number */ @@ -185,6 +190,7 @@ struct sdmmc_function { struct sdmmc_cis cis; /* decoded CIS */ /* SD/MMC memory card members */ struct sdmmc_csd csd; /* decoded CSD value */ + struct sdmmc_ext_csd ext_csd; /* decoded EXT_CSD value */ struct sdmmc_cid cid; /* decoded CID value */ sdmmc_response raw_cid; /* temp. storage for decoding */ uint32_t raw_scr[2];