void sdhc_acpi_attach(struct device *parent, struct device *self, void *aux) { struct acpi_attach_args *aaa = aux; struct sdhc_acpi_softc *sc = (struct sdhc_acpi_softc *)self; struct aml_value res; sc->sc_acpi = (struct acpi_softc *)parent; sc->sc_node = aaa->aaa_node; printf(": %s", sc->sc_node->name); if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { printf(", can't find registers\n"); return; } aml_parse_resource(&res, sdhc_acpi_parse_resources, sc); printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); if (sc->sc_addr == 0 || sc->sc_size == 0) { printf("\n"); return; } printf(" irq %d", sc->sc_irq); sc->sc_memt = aaa->aaa_memt; if (bus_space_map(sc->sc_memt, sc->sc_addr, sc->sc_size, 0, &sc->sc_memh)) { printf(", can't map registers\n"); return; } sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_BIO, sdhc_intr, sc, sc->sc.sc_dev.dv_xname); if (sc->sc_ih == NULL) { printf(", can't establish interrupt\n"); return; } printf("\n"); sc->sc.sc_host = &sc->sc_host; sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, sc->sc_size, 0, 0); }
static void bcmemmc_attach_i(device_t self) { struct bcmemmc_softc * const sc = device_private(self); int error; error = sdhc_host_found(&sc->sc, sc->sc_iot, sc->sc_ioh, sc->sc_ios); if (error != 0) { aprint_error_dev(self, "couldn't initialize host, error=%d\n", error); goto fail; } return; fail: /* XXX add bus_dma failure cleanup */ if (sc->sc_ih) { intr_disestablish(sc->sc_ih); sc->sc_ih = NULL; } bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); }
static void sdhc_attach(device_t parent, device_t self, void *aux) { struct sdhc_axi_softc *sc = device_private(self); struct axi_attach_args *aa = aux; bus_space_tag_t iot = aa->aa_iot; bus_space_handle_t ioh; u_int perclk = 0, v; sc->sc_sdhc.sc_dev = self; sc->sc_sdhc.sc_dmat = aa->aa_dmat; if (bus_space_map(iot, aa->aa_addr, AIPS2_USDHC_SIZE, 0, &ioh)) { aprint_error_dev(self, "can't map\n"); return; } aprint_normal(": Ultra Secured Digial Host Controller\n"); aprint_naive("\n"); sc->sc_sdhc.sc_host = sc->sc_hosts; switch (aa->aa_addr) { case IMX6_AIPS2_BASE + AIPS2_USDHC1_BASE: v = imx6_ccm_read(CCM_CCGR6); imx6_ccm_write(CCM_CCGR6, v | CCM_CCGR6_USDHC1_CLK_ENABLE(3)); perclk = imx6_get_clock(IMX6CLK_USDHC1); sdhc_set_gpio_cd(sc, "usdhc1-cd-gpio"); break; case IMX6_AIPS2_BASE + AIPS2_USDHC2_BASE: v = imx6_ccm_read(CCM_CCGR6); imx6_ccm_write(CCM_CCGR6, v | CCM_CCGR6_USDHC2_CLK_ENABLE(3)); perclk = imx6_get_clock(IMX6CLK_USDHC2); sdhc_set_gpio_cd(sc, "usdhc2-cd-gpio"); break; case IMX6_AIPS2_BASE + AIPS2_USDHC3_BASE: v = imx6_ccm_read(CCM_CCGR6); imx6_ccm_write(CCM_CCGR6, v | CCM_CCGR6_USDHC3_CLK_ENABLE(3)); perclk = imx6_get_clock(IMX6CLK_USDHC3); sdhc_set_gpio_cd(sc, "usdhc3-cd-gpio"); break; case IMX6_AIPS2_BASE + AIPS2_USDHC4_BASE: v = imx6_ccm_read(CCM_CCGR6); imx6_ccm_write(CCM_CCGR6, v | CCM_CCGR6_USDHC4_CLK_ENABLE(3)); perclk = imx6_get_clock(IMX6CLK_USDHC4); sdhc_set_gpio_cd(sc, "usdhc4-cd-gpio"); break; } sc->sc_sdhc.sc_clkbase = perclk / 1000; sc->sc_sdhc.sc_flags |= SDHC_FLAG_USE_DMA | SDHC_FLAG_NO_PWR0 | SDHC_FLAG_HAVE_DVS | SDHC_FLAG_32BIT_ACCESS | SDHC_FLAG_8BIT_MODE | SDHC_FLAG_USE_ADMA2 | SDHC_FLAG_POLL_CARD_DET | SDHC_FLAG_USDHC; sc->sc_ih = intr_establish(aa->aa_irq, IPL_SDMMC, IST_LEVEL, sdhc_intr, &sc->sc_sdhc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "can't establish interrupt\n"); return; } sc->sc_sdhc.sc_vendor_card_detect = imx6_sdhc_card_detect; if (sdhc_host_found(&sc->sc_sdhc, iot, ioh, AIPS2_USDHC_SIZE)) { aprint_error_dev(self, "can't initialize host\n"); return; } if (!pmf_device_register1(self, sdhc_suspend, sdhc_resume, sdhc_shutdown)) { aprint_error_dev(self, "can't establish power hook\n"); } }
static void sdhc_pci_attach(device_t parent, device_t self, void *aux) { struct sdhc_pci_softc *sc = device_private(self); struct pci_attach_args *pa = (struct pci_attach_args *)aux; pci_chipset_tag_t pc = pa->pa_pc; pcitag_t tag = pa->pa_tag; pci_intr_handle_t ih; pcireg_t csr; pcireg_t slotinfo; char const *intrstr; int nslots; int reg; int cnt; bus_space_tag_t iot; bus_space_handle_t ioh; bus_size_t size; uint32_t flags; char intrbuf[PCI_INTRSTR_LEN]; sc->sc.sc_dev = self; sc->sc.sc_dmat = pa->pa_dmat; sc->sc.sc_host = NULL; sc->sc_pc = pc; 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); 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. */ slotinfo = pci_conf_read(pc, tag, SDHC_PCI_CONF_SLOT_INFO); nslots = SDHC_PCI_NUM_SLOTS(slotinfo); /* Allocate an array big enough to hold all the possible hosts */ sc->sc.sc_host = malloc(sizeof(struct sdhc_host *) * nslots, M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc.sc_host == NULL) { aprint_error_dev(self, "couldn't alloc memory\n"); goto err; } /* Enable the device. */ csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr | PCI_COMMAND_MASTER_ENABLE); /* Map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { aprint_error_dev(self, "couldn't map interrupt\n"); goto err; } intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); sc->sc_ih = pci_intr_establish(pc, ih, IPL_SDMMC, sdhc_intr, &sc->sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt\n"); goto err; } aprint_normal_dev(self, "interrupting at %s\n", intrstr); /* Enable use of DMA if supported by the interface. */ if ((PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA)) SET(sc->sc.sc_flags, SDHC_FLAG_USE_DMA); /* XXX: handle 64-bit BARs */ 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)) { continue; } cnt++; if (sdhc_host_found(&sc->sc, iot, ioh, size) != 0) { /* XXX: sc->sc_host leak */ aprint_error_dev(self, "couldn't initialize host (0x%x)\n", reg); } } if (cnt == 0) { aprint_error_dev(self, "couldn't map register\n"); goto err; } if (!pmf_device_register1(self, sdhc_suspend, sdhc_resume, sdhc_shutdown)) { aprint_error_dev(self, "couldn't establish powerhook\n"); } return; err: if (sc->sc.sc_host != NULL) { free(sc->sc.sc_host, M_DEVBUF); sc->sc.sc_host = NULL; } }
static void obiosdhc_attach(device_t parent, device_t self, void *aux) { struct obiosdhc_softc * const sc = device_private(self); struct obio_attach_args * const oa = aux; prop_dictionary_t prop = device_properties(self); uint32_t clkd, stat; int error, timo, clksft, n; bool support8bit = false; const char *transfer_mode = "PIO"; #ifdef TI_AM335X size_t i; #endif prop_dictionary_get_bool(prop, "8bit", &support8bit); sc->sc.sc_dmat = oa->obio_dmat; sc->sc.sc_dev = self; sc->sc.sc_flags |= SDHC_FLAG_32BIT_ACCESS; sc->sc.sc_flags |= SDHC_FLAG_NO_LED_ON; sc->sc.sc_flags |= SDHC_FLAG_RSP136_CRC; sc->sc.sc_flags |= SDHC_FLAG_SINGLE_ONLY; if (support8bit) sc->sc.sc_flags |= SDHC_FLAG_8BIT_MODE; #ifdef TI_AM335X sc->sc.sc_flags |= SDHC_FLAG_WAIT_RESET; sc->sc.sc_flags &= ~SDHC_FLAG_SINGLE_ONLY; #endif #if defined(OMAP_3530) sc->sc.sc_flags &= ~SDHC_FLAG_SINGLE_ONLY; #endif sc->sc.sc_host = sc->sc_hosts; sc->sc.sc_clkbase = 96000; /* 96MHZ */ if (!prop_dictionary_get_uint32(prop, "clkmask", &sc->sc.sc_clkmsk)) sc->sc.sc_clkmsk = 0x0000ffc0; sc->sc.sc_vendor_rod = obiosdhc_rod; sc->sc.sc_vendor_write_protect = obiosdhc_write_protect; sc->sc.sc_vendor_card_detect = obiosdhc_card_detect; sc->sc.sc_vendor_bus_clock = obiosdhc_bus_clock; sc->sc_bst = oa->obio_iot; clksft = ffs(sc->sc.sc_clkmsk) - 1; error = bus_space_map(sc->sc_bst, oa->obio_addr, oa->obio_size, 0, &sc->sc_bsh); if (error) { aprint_error_dev(self, "can't map registers: %d\n", error); return; } bus_space_subregion(sc->sc_bst, sc->sc_bsh, OMAP3_SDMMC_SDHC_OFFSET, OMAP3_SDMMC_SDHC_SIZE, &sc->sc_sdhc_bsh); #if NEDMA > 0 if (oa->obio_edmabase != -1) { cv_init(&sc->sc_edma_cv, "sdhcedma"); sc->sc_edma_fifo = oa->obio_addr + OMAP3_SDMMC_SDHC_OFFSET + SDHC_DATA; obiosdhc_edma_init(sc, oa->obio_edmabase); sc->sc.sc_flags |= SDHC_FLAG_USE_DMA; sc->sc.sc_flags |= SDHC_FLAG_EXTERNAL_DMA; sc->sc.sc_flags |= SDHC_FLAG_EXTDMA_DMAEN; sc->sc.sc_flags &= ~SDHC_FLAG_SINGLE_ONLY; sc->sc.sc_vendor_transfer_data_dma = obiosdhc_edma_xfer_data; transfer_mode = "EDMA"; } #endif aprint_naive("\n"); aprint_normal(": SDHC controller (%s)\n", transfer_mode); #ifdef TI_AM335X /* XXX Not really AM335X-specific. */ for (i = 0; i < __arraycount(am335x_sdhc); i++) if ((oa->obio_addr == am335x_sdhc[i].as_base_addr) && (oa->obio_intr == am335x_sdhc[i].as_intr)) { prcm_module_enable(&am335x_sdhc[i].as_module); break; } KASSERT(i < __arraycount(am335x_sdhc)); #endif /* XXXXXX: Turn-on regulator via I2C. */ /* XXXXXX: And enable ICLOCK/FCLOCK. */ /* MMCHS Soft reset */ bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSCONFIG, SYSCONFIG_SOFTRESET); timo = 3000000; /* XXXX 3 sec. */ while (timo--) { if (bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSSTATUS) & SYSSTATUS_RESETDONE) break; delay(1); } if (timo == 0) aprint_error_dev(self, "Soft reset timeout\n"); bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSCONFIG, SYSCONFIG_ENAWAKEUP | SYSCONFIG_AUTOIDLE | SYSCONFIG_SIDLEMODE_AUTO | SYSCONFIG_CLOCKACTIVITY_FCLK | SYSCONFIG_CLOCKACTIVITY_ICLK); sc->sc_ih = intr_establish(oa->obio_intr, IPL_VM, IST_LEVEL, sdhc_intr, &sc->sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "failed to establish interrupt %d\n", oa->obio_intr); goto fail; } error = sdhc_host_found(&sc->sc, sc->sc_bst, sc->sc_sdhc_bsh, oa->obio_size - OMAP3_SDMMC_SDHC_OFFSET); if (error != 0) { aprint_error_dev(self, "couldn't initialize host, error=%d\n", error); goto fail; } /* Set SDVS 1.8v and DTW 1bit mode */ SDHC_WRITE(sc, SDHC_HOST_CTL, SDHC_VOLTAGE_1_8V << (SDHC_VOLTAGE_SHIFT + 8)); bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON, bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) | CON_OD); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_INTCLK_ENABLE | SDHC_SDCLK_ENABLE); SDHC_WRITE(sc, SDHC_HOST_CTL, SDHC_READ(sc, SDHC_HOST_CTL) | SDHC_BUS_POWER << 8); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) | CLKD(150) << clksft); /* * 22.6.1.3.1.5 MMCHS Controller INIT Procedure Start * from 'OMAP35x Applications Processor Technical Reference Manual'. * * During the INIT procedure, the MMCHS controller generates 80 clock * periods. In order to keep the 1ms gap, the MMCHS controller should * be configured to generate a clock whose frequency is smaller or * equal to 80 KHz. */ SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) & ~SDHC_SDCLK_ENABLE); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) & ~sc->sc.sc_clkmsk); clkd = CLKD(80); n = 1; while (clkd & ~(sc->sc.sc_clkmsk >> clksft)) { clkd >>= 1; n <<= 1; } SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) | (clkd << clksft)); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_SDCLK_ENABLE); bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON, bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) | CON_INIT); for (; n > 0; n--) { SDHC_WRITE(sc, SDHC_TRANSFER_MODE, 0x00000000); timo = 3000000; /* XXXX 3 sec. */ stat = 0; while (!(stat & SDHC_COMMAND_COMPLETE)) { stat = SDHC_READ(sc, SDHC_NINTR_STATUS); if (--timo == 0) break; delay(1); } if (timo == 0) { aprint_error_dev(self, "INIT Procedure timeout\n"); break; } SDHC_WRITE(sc, SDHC_NINTR_STATUS, stat); } bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON, bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) & ~CON_INIT); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) & ~SDHC_SDCLK_ENABLE); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) & ~sc->sc.sc_clkmsk); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) | CLKD(150) << clksft); SDHC_WRITE(sc, SDHC_CLOCK_CTL, SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_SDCLK_ENABLE); return; fail: if (sc->sc_ih) { intr_disestablish(sc->sc_ih); sc->sc_ih = NULL; } bus_space_unmap(sc->sc_bst, sc->sc_bsh, oa->obio_size); }
void sdhc_pci_attach(struct device *parent, struct device *self, void *aux) { struct sdhc_pci_softc *sc = (struct sdhc_pci_softc *)self; struct pci_attach_args *pa = aux; pci_intr_handle_t ih; char const *intrstr; int slotinfo; int nslots; int usedma; int reg; bus_space_tag_t iot; bus_space_handle_t ioh; bus_size_t size; u_int32_t caps = 0; /* Some TI controllers needs special treatment. */ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI && PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TI_PCI7XX1_SD && pa->pa_function == 4) sdhc_takecontroller(pa); /* ENE controllers break if set to 0V bus power. */ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ENE && PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENE_SDCARD) sc->sc.sc_flags |= SDHC_F_NOPWR0; /* Some RICOH controllers need to be bumped into the right mode. */ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RICOH && PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U823) { /* 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); } if (pci_intr_map(pa, &ih)) { printf(": can't map interrupt\n"); return; } intrstr = pci_intr_string(pa->pa_pc, ih); sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SDMMC, sdhc_intr, sc, sc->sc.sc_dev.dv_xname); if (sc->sc_ih == NULL) { printf(": can't establish interrupt\n"); return; } printf(": %s\n", intrstr); /* Enable use of DMA if supported by the interface. */ usedma = PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA; /* * Map and attach all hosts supported by the host controller. */ slotinfo = pci_conf_read(pa->pa_pc, pa->pa_tag, SDHC_PCI_CONF_SLOT_INFO); nslots = SDHC_PCI_NUM_SLOTS(slotinfo); /* Allocate an array big enough to hold all the possible hosts */ sc->sc.sc_host = malloc(sizeof(struct sdhc_host *) * nslots, M_DEVBUF, M_WAITOK); /* XXX: handle 64-bit BARs */ for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) * sizeof(u_int32_t); reg < SDHC_PCI_BAR_END && nslots > 0; reg += sizeof(u_int32_t), nslots--) { if (pci_mem_find(pa->pa_pc, pa->pa_tag, reg, NULL, NULL, NULL) != 0) continue; if (pci_mapreg_map(pa, reg, PCI_MAPREG_TYPE_MEM, 0, &iot, &ioh, NULL, &size, 0)) { printf("%s at 0x%x: can't map registers\n", sc->sc.sc_dev.dv_xname, reg); continue; } if (sdhc_host_found(&sc->sc, iot, ioh, size, usedma, caps) != 0) /* XXX: sc->sc_host leak */ printf("%s at 0x%x: can't initialize host\n", sc->sc.sc_dev.dv_xname, reg); } }