1 /* $OpenBSD: ht.c,v 1.19 2022/03/13 12:33:01 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Mark Kettenis 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/systm.h> 21 #include <sys/device.h> 22 23 #include <machine/autoconf.h> 24 #include <machine/bus.h> 25 26 #include <dev/pci/pcireg.h> 27 #include <dev/pci/pcivar.h> 28 #include <dev/pci/pcidevs.h> 29 30 #include <dev/ofw/openfirm.h> 31 32 int ht_match(struct device *, void *, void *); 33 void ht_attach(struct device *, struct device *, void *); 34 35 pcireg_t ht_conf_read(void *, pcitag_t, int); 36 void ht_conf_write(void *, pcitag_t, int, pcireg_t); 37 38 int ht_print(void *, const char *); 39 40 struct ht_softc { 41 struct device sc_dev; 42 int sc_maxdevs; 43 struct ppc_bus_space sc_mem_bus_space; 44 struct ppc_bus_space sc_io_bus_space; 45 struct ppc_pci_chipset sc_pc; 46 bus_space_tag_t sc_memt; 47 bus_space_handle_t sc_config0_memh; 48 bus_space_handle_t sc_config1_memh; 49 bus_space_tag_t sc_iot; 50 bus_space_handle_t sc_config0_ioh; 51 }; 52 53 const struct cfattach ht_ca = { 54 sizeof(struct ht_softc), ht_match, ht_attach 55 }; 56 57 struct cfdriver ht_cd = { 58 NULL, "ht", DV_DULL, 59 }; 60 61 int 62 ht_match(struct device *parent, void *cf, void *aux) 63 { 64 struct confargs *ca = aux; 65 66 if (strcmp(ca->ca_name, "ht") == 0) 67 return (1); 68 return (0); 69 } 70 71 void 72 ht_attach(struct device *parent, struct device *self, void *aux) 73 { 74 struct ht_softc *sc = (struct ht_softc *)self; 75 struct confargs *ca = aux; 76 struct pcibus_attach_args pba; 77 u_int32_t regs[6]; 78 char compat[32]; 79 int node, len; 80 81 if (ca->ca_node == 0) { 82 printf(": invalid node on ht config\n"); 83 return; 84 } 85 86 len = OF_getprop(ca->ca_node, "reg", regs, sizeof(regs)); 87 if (len < 0 || len < sizeof(regs)) { 88 printf(": regs lookup failed, node %x\n", ca->ca_node); 89 return; 90 } 91 92 sc->sc_mem_bus_space.bus_base = 0x80000000; 93 sc->sc_mem_bus_space.bus_size = 0; 94 sc->sc_mem_bus_space.bus_io = 0; 95 sc->sc_memt = &sc->sc_mem_bus_space; 96 97 sc->sc_io_bus_space.bus_base = 0x80000000; 98 sc->sc_io_bus_space.bus_size = 0; 99 sc->sc_io_bus_space.bus_io = 1; 100 sc->sc_iot = &sc->sc_io_bus_space; 101 102 sc->sc_maxdevs = 1; 103 for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) 104 sc->sc_maxdevs++; 105 106 if (bus_space_map(sc->sc_memt, regs[1], 107 (1 << 11)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) { 108 printf(": can't map PCI config0 memory\n"); 109 return; 110 } 111 112 if (bus_space_map(sc->sc_memt, regs[1] + 0x01000000, 113 regs[2] - 0x01000000, 0, &sc->sc_config1_memh)) { 114 printf(": can't map PCI config1 memory\n"); 115 return; 116 } 117 118 if (bus_space_map(sc->sc_iot, regs[4], 0x1000, 0, 119 &sc->sc_config0_ioh)) { 120 printf(": can't map PCI config0 io\n"); 121 return; 122 } 123 124 len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat)); 125 if (len <= 0) 126 printf(": unknown"); 127 else 128 printf(": %s", compat); 129 130 sc->sc_pc.pc_conf_v = sc; 131 sc->sc_pc.pc_node = ca->ca_node; 132 sc->sc_pc.pc_conf_read = ht_conf_read; 133 sc->sc_pc.pc_conf_write = ht_conf_write; 134 135 bzero(&pba, sizeof(pba)); 136 pba.pba_busname = "pci"; 137 pba.pba_iot = sc->sc_iot; 138 pba.pba_memt = sc->sc_memt; 139 pba.pba_dmat = &pci_bus_dma_tag; 140 pba.pba_pc = &sc->sc_pc; 141 pba.pba_domain = pci_ndomains++; 142 pba.pba_bus = 0; 143 144 printf(", %d devices\n", sc->sc_maxdevs); 145 146 config_found(self, &pba, ht_print); 147 } 148 149 pcireg_t 150 ht_conf_read(void *cpv, pcitag_t tag, int offset) 151 { 152 struct ht_softc *sc = cpv; 153 int bus, dev, fcn; 154 pcireg_t reg; 155 uint32_t val; 156 157 val = PCITAG_OFFSET(tag); 158 #ifdef DEBUG 159 printf("ht_conf_read: tag=%x, offset=%x\n", val, offset); 160 #endif 161 pci_decompose_tag(NULL, tag, &bus, &dev, &fcn); 162 if (bus == 0 && dev == 0) { 163 val |= (offset << 2); 164 reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val); 165 reg = letoh32(reg); 166 } else if (bus == 0) { 167 /* XXX Why can we only access function 0? */ 168 if (fcn > 0) 169 return ~0; 170 val |= offset; 171 reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val); 172 } else { 173 val |= offset; 174 reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val); 175 } 176 #ifdef DEBUG 177 printf("ht_conf_read: reg=%x\n", reg); 178 #endif 179 return reg; 180 } 181 182 void 183 ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) 184 { 185 struct ht_softc *sc = cpv; 186 int bus, dev, fcn; 187 uint32_t val; 188 189 val = PCITAG_OFFSET(tag); 190 #ifdef DEBUG 191 printf("ht_conf_write: tag=%x, offset=%x, data = %x\n", 192 val, offset, data); 193 #endif 194 pci_decompose_tag(NULL, tag, &bus, &dev, &fcn); 195 if (bus == 0 && dev == 0) { 196 val |= (offset << 2); 197 data = htole32(data); 198 bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, val, data); 199 bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val); 200 } else if (bus == 0) { 201 /* XXX Why can we only access function 0? */ 202 if (fcn > 0) 203 return; 204 val |= offset; 205 bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, val, data); 206 bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val); 207 } else { 208 val |= offset; 209 bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, val, data); 210 bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val); 211 } 212 } 213 214 int 215 ht_print(void *aux, const char *pnp) 216 { 217 struct pcibus_attach_args *pba = aux; 218 219 if (pnp) 220 printf("%s at %s", pba->pba_busname, pnp); 221 printf(" bus %d", pba->pba_bus); 222 return (UNCONF); 223 } 224