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; } }
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); } }