1 /* $OpenBSD: sdhc_pci.c,v 1.20 2016/04/30 11:32:23 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/device.h> 21 #include <sys/systm.h> 22 #include <sys/malloc.h> 23 24 #include <dev/pci/pcivar.h> 25 #include <dev/pci/pcidevs.h> 26 #include <dev/sdmmc/sdhcreg.h> 27 #include <dev/sdmmc/sdhcvar.h> 28 #include <dev/sdmmc/sdmmcvar.h> 29 30 /* 31 * 8-bit PCI configuration register that tells us how many slots there 32 * are and which BAR entry corresponds to the first slot. 33 */ 34 #define SDHC_PCI_CONF_SLOT_INFO 0x40 35 #define SDHC_PCI_NUM_SLOTS(info) ((((info) >> 4) & 0x7) + 1) 36 #define SDHC_PCI_FIRST_BAR(info) ((info) & 0x7) 37 38 /* TI specific register */ 39 #define SDHC_PCI_GENERAL_CTL 0x4c 40 #define MMC_SD_DIS 0x02 41 42 /* RICOH specific registers */ 43 #define SDHC_PCI_MODE_KEY 0xf9 44 #define SDHC_PCI_MODE 0x150 45 #define SDHC_PCI_MODE_SD20 0x10 46 #define SDHC_PCI_BASE_FREQ_KEY 0xfc 47 #define SDHC_PCI_BASE_FREQ 0xe1 48 49 struct sdhc_pci_softc { 50 struct sdhc_softc sc; 51 pci_chipset_tag_t sc_pc; 52 pcitag_t sc_tag; 53 pcireg_t sc_id; 54 void *sc_ih; 55 }; 56 57 int sdhc_pci_match(struct device *, void *, void *); 58 void sdhc_pci_attach(struct device *, struct device *, void *); 59 int sdhc_pci_activate(struct device *, int); 60 61 void sdhc_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, uint8_t); 62 void sdhc_takecontroller(struct pci_attach_args *); 63 void sdhc_ricohfix(struct sdhc_pci_softc *); 64 65 struct cfattach sdhc_pci_ca = { 66 sizeof(struct sdhc_pci_softc), sdhc_pci_match, sdhc_pci_attach, 67 NULL, sdhc_pci_activate 68 }; 69 70 int 71 sdhc_pci_match(struct device *parent, void *match, void *aux) 72 { 73 struct pci_attach_args *pa = aux; 74 75 /* 76 * The Realtek RTS5209 is supported by rtsx(4). Usually the device 77 * class for these is UNDEFINED but there are RTS5209 devices which 78 * are advertising an SYSTEM/SDHC device class in addition to a 79 * separate device advertising the UNDEFINED class. Such devices are 80 * not compatible with sdhc(4), so ignore them. 81 */ 82 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_REALTEK && 83 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_REALTEK_RTS5209) 84 return 0; 85 86 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM && 87 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC) 88 return 1; 89 90 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RICOH && 91 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U822 || 92 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U823)) 93 return 1; 94 95 return 0; 96 } 97 98 void 99 sdhc_pci_attach(struct device *parent, struct device *self, void *aux) 100 { 101 struct sdhc_pci_softc *sc = (struct sdhc_pci_softc *)self; 102 struct pci_attach_args *pa = aux; 103 pci_intr_handle_t ih; 104 char const *intrstr; 105 int slotinfo; 106 int nslots; 107 int usedma; 108 int reg; 109 pcireg_t type; 110 bus_space_tag_t iot; 111 bus_space_handle_t ioh; 112 bus_size_t size; 113 u_int32_t caps = 0; 114 115 sc->sc_pc = pa->pa_pc; 116 sc->sc_tag = pa->pa_tag; 117 sc->sc_id = pa->pa_id; 118 119 /* Some TI controllers needs special treatment. */ 120 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI && 121 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TI_PCI7XX1_SD && 122 pa->pa_function == 4) 123 sdhc_takecontroller(pa); 124 125 /* ENE controllers break if set to 0V bus power. */ 126 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ENE && 127 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENE_SDCARD) 128 sc->sc.sc_flags |= SDHC_F_NOPWR0; 129 130 /* Some RICOH controllers need to be bumped into the right mode. */ 131 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RICOH && 132 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U822 || 133 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U823)) 134 sdhc_ricohfix(sc); 135 136 if (pci_intr_map(pa, &ih)) { 137 printf(": can't map interrupt\n"); 138 return; 139 } 140 141 intrstr = pci_intr_string(pa->pa_pc, ih); 142 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SDMMC, 143 sdhc_intr, sc, sc->sc.sc_dev.dv_xname); 144 if (sc->sc_ih == NULL) { 145 printf(": can't establish interrupt\n"); 146 return; 147 } 148 printf(": %s\n", intrstr); 149 150 /* Enable use of DMA if supported by the interface. */ 151 usedma = PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA; 152 sc->sc.sc_dmat = pa->pa_dmat; 153 154 /* 155 * Map and attach all hosts supported by the host controller. 156 */ 157 slotinfo = pci_conf_read(pa->pa_pc, pa->pa_tag, 158 SDHC_PCI_CONF_SLOT_INFO); 159 nslots = SDHC_PCI_NUM_SLOTS(slotinfo); 160 161 /* Allocate an array big enough to hold all the possible hosts */ 162 sc->sc.sc_host = mallocarray(nslots, sizeof(struct sdhc_host *), 163 M_DEVBUF, M_WAITOK); 164 165 for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) * 4; 166 reg < SDHC_PCI_BAR_END && nslots > 0; 167 reg += 4, nslots--) { 168 if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, reg, &type)) 169 break; 170 171 if (type == PCI_MAPREG_TYPE_IO || pci_mapreg_map(pa, reg, 172 type, 0, &iot, &ioh, NULL, &size, 0)) { 173 printf("%s at 0x%x: can't map registers\n", 174 sc->sc.sc_dev.dv_xname, reg); 175 break; 176 } 177 178 if (sdhc_host_found(&sc->sc, iot, ioh, size, usedma, caps) != 0) 179 printf("%s at 0x%x: can't initialize host\n", 180 sc->sc.sc_dev.dv_xname, reg); 181 182 if (type & PCI_MAPREG_MEM_TYPE_64BIT) 183 reg += 4; 184 } 185 } 186 187 int 188 sdhc_pci_activate(struct device *self, int act) 189 { 190 struct sdhc_pci_softc *sc = (struct sdhc_pci_softc *)self; 191 int rv; 192 193 switch (act) { 194 case DVACT_SUSPEND: 195 rv = sdhc_activate(self, act); 196 break; 197 case DVACT_RESUME: 198 /* Some RICOH controllers need to be bumped into the right mode. */ 199 if (PCI_VENDOR(sc->sc_id) == PCI_VENDOR_RICOH && 200 (PCI_PRODUCT(sc->sc_id) == PCI_PRODUCT_RICOH_R5U822 || 201 PCI_PRODUCT(sc->sc_id) == PCI_PRODUCT_RICOH_R5U823)) 202 sdhc_ricohfix(sc); 203 rv = sdhc_activate(self, act); 204 break; 205 default: 206 rv = sdhc_activate(self, act); 207 break; 208 } 209 return (rv); 210 } 211 212 void 213 sdhc_takecontroller(struct pci_attach_args *pa) 214 { 215 pcitag_t tag; 216 pcireg_t id, reg; 217 218 /* Look at func 3 for the flash device */ 219 tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 3); 220 id = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG); 221 if (PCI_PRODUCT(id) != PCI_PRODUCT_TI_PCI7XX1_FLASH) 222 return; 223 224 /* 225 * Disable MMC/SD on the flash media controller so the 226 * SD host takes over. 227 */ 228 reg = pci_conf_read(pa->pa_pc, tag, SDHC_PCI_GENERAL_CTL); 229 reg |= MMC_SD_DIS; 230 pci_conf_write(pa->pa_pc, tag, SDHC_PCI_GENERAL_CTL, reg); 231 } 232 233 void 234 sdhc_ricohfix(struct sdhc_pci_softc *sc) 235 { 236 /* Enable SD2.0 mode. */ 237 sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_MODE_KEY, 0xfc); 238 sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20); 239 sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_MODE_KEY, 0x00); 240 241 /* 242 * Some SD/MMC cards don't work with the default base 243 * clock frequency of 200MHz. Lower it to 50Hz. 244 */ 245 sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_BASE_FREQ_KEY, 0x01); 246 sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_BASE_FREQ, 50); 247 sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_BASE_FREQ_KEY, 0x00); 248 } 249 250 void 251 sdhc_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, uint8_t val) 252 { 253 pcireg_t tmp; 254 255 tmp = pci_conf_read(pc, tag, reg & ~0x3); 256 tmp &= ~(0xff << ((reg & 0x3) * 8)); 257 tmp |= (val << ((reg & 0x3) * 8)); 258 pci_conf_write(pc, tag, reg & ~0x3, tmp); 259 } 260