1 1.23 thorpej /* $NetBSD: gemini_pci.c,v 1.23 2020/11/20 18:10:07 thorpej Exp $ */ 2 1.1 matt 3 1.1 matt /* adapted from: 4 1.1 matt * NetBSD: i80312_pci.c,v 1.9 2005/12/11 12:16:51 christos Exp 5 1.1 matt */ 6 1.1 matt 7 1.1 matt /* 8 1.1 matt * Copyright (c) 2001 Wasabi Systems, Inc. 9 1.1 matt * All rights reserved. 10 1.1 matt * 11 1.1 matt * Written by Jason R. Thorpe for Wasabi Systems, Inc. 12 1.1 matt * 13 1.1 matt * Redistribution and use in source and binary forms, with or without 14 1.1 matt * modification, are permitted provided that the following conditions 15 1.1 matt * are met: 16 1.1 matt * 1. Redistributions of source code must retain the above copyright 17 1.1 matt * notice, this list of conditions and the following disclaimer. 18 1.1 matt * 2. Redistributions in binary form must reproduce the above copyright 19 1.1 matt * notice, this list of conditions and the following disclaimer in the 20 1.1 matt * documentation and/or other materials provided with the distribution. 21 1.1 matt * 3. All advertising materials mentioning features or use of this software 22 1.1 matt * must display the following acknowledgement: 23 1.1 matt * This product includes software developed for the NetBSD Project by 24 1.1 matt * Wasabi Systems, Inc. 25 1.1 matt * 4. The name of Wasabi Systems, Inc. may not be used to endorse 26 1.1 matt * or promote products derived from this software without specific prior 27 1.1 matt * written permission. 28 1.1 matt * 29 1.1 matt * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 30 1.1 matt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31 1.1 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32 1.1 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 33 1.1 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34 1.1 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35 1.1 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36 1.1 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37 1.1 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 1.1 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39 1.1 matt * POSSIBILITY OF SUCH DAMAGE. 40 1.1 matt */ 41 1.1 matt 42 1.1 matt /* 43 1.1 matt * PCI configuration support for i80312 Companion I/O chip. 44 1.1 matt */ 45 1.1 matt 46 1.1 matt #include <sys/cdefs.h> 47 1.23 thorpej __KERNEL_RCSID(0, "$NetBSD: gemini_pci.c,v 1.23 2020/11/20 18:10:07 thorpej Exp $"); 48 1.1 matt 49 1.15 matt #include "opt_gemini.h" 50 1.15 matt #include "opt_pci.h" 51 1.15 matt #include "pci.h" 52 1.1 matt 53 1.1 matt #include <sys/param.h> 54 1.1 matt #include <sys/systm.h> 55 1.1 matt #include <sys/device.h> 56 1.23 thorpej #include <sys/kmem.h> 57 1.15 matt #include <sys/bus.h> 58 1.15 matt #include <sys/intr.h> 59 1.1 matt 60 1.1 matt #include <uvm/uvm_extern.h> 61 1.1 matt 62 1.15 matt #include <dev/pci/pcivar.h> 63 1.15 matt #include <dev/pci/pcidevs.h> 64 1.15 matt #include <dev/pci/pciconf.h> 65 1.15 matt 66 1.15 matt #include <arm/locore.h> 67 1.1 matt 68 1.1 matt #include <arm/pic/picvar.h> 69 1.1 matt 70 1.1 matt #include <arm/gemini/gemini_reg.h> 71 1.1 matt #include <arm/gemini/gemini_pcivar.h> 72 1.1 matt #include <arm/gemini/gemini_obiovar.h> 73 1.1 matt 74 1.14 chs void gemini_pci_attach_hook(device_t, device_t, 75 1.1 matt struct pcibus_attach_args *); 76 1.1 matt int gemini_pci_bus_maxdevs(void *, int); 77 1.1 matt pcitag_t gemini_pci_make_tag(void *, int, int, int); 78 1.1 matt void gemini_pci_decompose_tag(void *, pcitag_t, int *, int *, 79 1.1 matt int *); 80 1.1 matt pcireg_t gemini_pci_conf_read(void *, pcitag_t, int); 81 1.1 matt void gemini_pci_conf_write(void *, pcitag_t, int, pcireg_t); 82 1.12 matt int gemini_pci_conf_hook(void *, int, int, int, pcireg_t); 83 1.13 matt void gemini_pci_conf_interrupt(void *, int, int, int, int, int *); 84 1.1 matt 85 1.9 dyoung int gemini_pci_intr_map(const struct pci_attach_args *, 86 1.1 matt pci_intr_handle_t *); 87 1.17 christos const char *gemini_pci_intr_string(void *, pci_intr_handle_t, 88 1.17 christos char *, size_t); 89 1.1 matt const struct evcnt *gemini_pci_intr_evcnt(void *, pci_intr_handle_t); 90 1.1 matt void *gemini_pci_intr_establish(void *, pci_intr_handle_t, 91 1.19 jmcneill int, int (*)(void *), void *, const char *); 92 1.1 matt void gemini_pci_intr_disestablish(void *, void *); 93 1.1 matt int gemini_pci_intr_handler(void *v); 94 1.1 matt 95 1.1 matt #define PCI_CONF_LOCK(s) (s) = disable_interrupts(I32_bit) 96 1.1 matt #define PCI_CONF_UNLOCK(s) restore_interrupts((s)) 97 1.1 matt 98 1.1 matt struct gemini_pci_intrq { 99 1.1 matt SIMPLEQ_ENTRY(gemini_pci_intrq) iq_q; 100 1.1 matt int (*iq_func)(void *); 101 1.1 matt void *iq_arg; 102 1.1 matt void *iq_ih; 103 1.1 matt }; 104 1.1 matt 105 1.1 matt static SIMPLEQ_HEAD(, gemini_pci_intrq) gemini_pci_intrq = 106 1.1 matt SIMPLEQ_HEAD_INITIALIZER(gemini_pci_intrq); 107 1.1 matt 108 1.1 matt static inline int 109 1.1 matt gemini_pci_intrq_empty(void) 110 1.1 matt { 111 1.1 matt return SIMPLEQ_EMPTY(&gemini_pci_intrq); 112 1.1 matt } 113 1.1 matt 114 1.1 matt static inline void * 115 1.1 matt gemini_pci_intrq_insert(void *ih, int (*func)(void *), void *arg) 116 1.1 matt { 117 1.1 matt struct gemini_pci_intrq *iqp; 118 1.1 matt 119 1.23 thorpej iqp = kmem_zalloc(sizeof(*iqp), KM_SLEEP); 120 1.1 matt iqp->iq_func = func; 121 1.1 matt iqp->iq_arg = arg; 122 1.1 matt iqp->iq_ih = ih; 123 1.1 matt SIMPLEQ_INSERT_TAIL(&gemini_pci_intrq, iqp, iq_q); 124 1.1 matt 125 1.1 matt return (void *)iqp; 126 1.1 matt } 127 1.1 matt 128 1.1 matt static inline void 129 1.1 matt gemini_pci_intrq_remove(void *cookie) 130 1.1 matt { 131 1.1 matt struct gemini_pci_intrq *iqp; 132 1.1 matt 133 1.1 matt SIMPLEQ_FOREACH(iqp, &gemini_pci_intrq, iq_q) { 134 1.1 matt if ((void *)iqp == cookie) { 135 1.1 matt SIMPLEQ_REMOVE(&gemini_pci_intrq, 136 1.1 matt iqp, gemini_pci_intrq, iq_q); 137 1.23 thorpej kmem_free(iqp, sizeof(*iqp)); 138 1.1 matt return; 139 1.1 matt } 140 1.1 matt } 141 1.1 matt } 142 1.1 matt 143 1.1 matt static inline int 144 1.1 matt gemini_pci_intrq_dispatch(void) 145 1.1 matt { 146 1.1 matt struct gemini_pci_intrq *iqp; 147 1.1 matt 148 1.1 matt SIMPLEQ_FOREACH(iqp, &gemini_pci_intrq, iq_q) { 149 1.1 matt (*iqp->iq_func)(iqp->iq_arg); 150 1.1 matt } 151 1.1 matt 152 1.1 matt return 1; 153 1.1 matt } 154 1.1 matt 155 1.1 matt void 156 1.1 matt gemini_pci_init(pci_chipset_tag_t pc, void *cookie) 157 1.1 matt { 158 1.1 matt struct obio_softc *sc = cookie; 159 1.1 matt 160 1.1 matt pc->pc_conf_v = cookie; 161 1.1 matt pc->pc_attach_hook = gemini_pci_attach_hook; 162 1.1 matt pc->pc_bus_maxdevs = gemini_pci_bus_maxdevs; 163 1.1 matt pc->pc_make_tag = gemini_pci_make_tag; 164 1.1 matt pc->pc_decompose_tag = gemini_pci_decompose_tag; 165 1.1 matt pc->pc_conf_read = gemini_pci_conf_read; 166 1.1 matt pc->pc_conf_write = gemini_pci_conf_write; 167 1.1 matt 168 1.1 matt pc->pc_intr_v = cookie; 169 1.1 matt pc->pc_intr_map = gemini_pci_intr_map; 170 1.1 matt pc->pc_intr_string = gemini_pci_intr_string; 171 1.1 matt pc->pc_intr_evcnt = gemini_pci_intr_evcnt; 172 1.1 matt pc->pc_intr_establish = gemini_pci_intr_establish; 173 1.1 matt pc->pc_intr_disestablish = gemini_pci_intr_disestablish; 174 1.1 matt 175 1.1 matt pc->pc_conf_hook = gemini_pci_conf_hook; 176 1.12 matt pc->pc_conf_interrupt = gemini_pci_conf_interrupt; 177 1.1 matt 178 1.1 matt /* 179 1.1 matt * initialize copy of CFG_CMD 180 1.1 matt */ 181 1.1 matt sc->sc_pci_chipset.pc_cfg_cmd = 182 1.1 matt gemini_pci_conf_read(sc, 0, GEMINI_PCI_CFG_CMD); 183 1.1 matt 184 1.1 matt #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE) 185 1.1 matt /* 186 1.1 matt * Configure the PCI bus. 187 1.1 matt * 188 1.1 matt * XXX We need to revisit this. We only configure the Secondary 189 1.1 matt * bus (and its children). The bus configure code needs changes 190 1.1 matt * to support how the busses are arranged on this chip. We also 191 1.1 matt * need to only configure devices in the private device space on 192 1.1 matt * the Secondary bus. 193 1.1 matt */ 194 1.1 matt 195 1.1 matt aprint_normal("%s: configuring Secondary PCI bus\n", 196 1.6 cliff device_xname(sc->sc_dev)); 197 1.1 matt 198 1.22 thorpej struct pciconf_resources *pcires = pciconf_resource_init(); 199 1.22 thorpej 200 1.1 matt /* 201 1.2 cliff * XXX PCI IO addr should be inherited ? 202 1.1 matt */ 203 1.22 thorpej pciconf_resource_add(pcires, PCICONF_RESOURCE_IO, 204 1.22 thorpej GEMINI_PCIIO_BASE, GEMINI_PCIIO_SIZE); 205 1.1 matt 206 1.1 matt /* 207 1.1 matt * XXX PCI mem addr should be inherited ? 208 1.1 matt */ 209 1.22 thorpej pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM, 210 1.22 thorpej GEMINI_PCIMEM_BASE, GEMINI_PCIMEM_SIZE); 211 1.1 matt 212 1.22 thorpej pci_configure_bus(pc, pcires, 0, arm_dcache_align); 213 1.1 matt 214 1.4 cliff gemini_pci_conf_write(sc, 0, GEMINI_PCI_CFG_REG_MEM1, 215 1.5 cliff PCI_CFG_REG_MEM_BASE((GEMINI_DRAM_BASE + (GEMINI_BUSBASE * 1024 * 1024))) 216 1.5 cliff | gemini_pci_cfg_reg_mem_size(MEMSIZE * 1024 * 1024)); 217 1.1 matt 218 1.22 thorpej pciconf_resource_fini(pcires); 219 1.1 matt #endif 220 1.1 matt } 221 1.1 matt 222 1.1 matt void 223 1.12 matt gemini_pci_conf_interrupt(void *v, int a, int b, int c, int d, int *p) 224 1.1 matt { 225 1.1 matt } 226 1.1 matt 227 1.1 matt int 228 1.12 matt gemini_pci_conf_hook(void *v, int bus, int device, int function, pcireg_t id) 229 1.1 matt { 230 1.1 matt int rv; 231 1.1 matt 232 1.1 matt rv = PCI_CONF_ALL; 233 1.1 matt 234 1.1 matt return rv; 235 1.1 matt } 236 1.1 matt 237 1.1 matt void 238 1.14 chs gemini_pci_attach_hook(device_t parent, device_t self, 239 1.1 matt struct pcibus_attach_args *pba) 240 1.1 matt { 241 1.1 matt /* Nothing to do. */ 242 1.1 matt } 243 1.1 matt 244 1.1 matt int 245 1.1 matt gemini_pci_bus_maxdevs(void *v, int busno) 246 1.1 matt { 247 1.1 matt return (32); 248 1.1 matt } 249 1.1 matt 250 1.1 matt pcitag_t 251 1.1 matt gemini_pci_make_tag(void *v, int b, int d, int f) 252 1.1 matt { 253 1.1 matt return ((b << 16) | (d << 11) | (f << 8)); 254 1.1 matt } 255 1.1 matt 256 1.1 matt void 257 1.1 matt gemini_pci_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) 258 1.1 matt { 259 1.1 matt if (bp != NULL) 260 1.1 matt *bp = (tag >> 16) & 0xff; 261 1.1 matt if (dp != NULL) 262 1.1 matt *dp = (tag >> 11) & 0x1f; 263 1.1 matt if (fp != NULL) 264 1.1 matt *fp = (tag >> 8) & 0x7; 265 1.1 matt } 266 1.1 matt 267 1.1 matt struct pciconf_state { 268 1.1 matt uint32_t ps_addr_val; 269 1.1 matt int ps_b, ps_d, ps_f; 270 1.1 matt }; 271 1.1 matt 272 1.1 matt static int 273 1.1 matt gemini_pci_conf_setup(struct obio_softc *sc, pcitag_t tag, int offset, 274 1.1 matt struct pciconf_state *ps) 275 1.1 matt { 276 1.18 msaitoh 277 1.18 msaitoh if ((unsigned int)offset >= PCI_CONF_SIZE) 278 1.18 msaitoh return (1); 279 1.18 msaitoh 280 1.1 matt gemini_pci_decompose_tag(sc, tag, &ps->ps_b, &ps->ps_d, &ps->ps_f); 281 1.1 matt 282 1.1 matt ps->ps_addr_val = 283 1.1 matt PCI_CFG_CMD_ENB 284 1.1 matt | PCI_CFG_CMD_BUSn(ps->ps_b) 285 1.1 matt | PCI_CFG_CMD_DEVn(ps->ps_d) 286 1.1 matt | PCI_CFG_CMD_FUNCn(ps->ps_f) 287 1.1 matt | PCI_CFG_CMD_REGn(offset); 288 1.1 matt 289 1.1 matt return (0); 290 1.1 matt } 291 1.1 matt 292 1.1 matt pcireg_t 293 1.1 matt gemini_pci_conf_read(void *v, pcitag_t tag, int offset) 294 1.1 matt { 295 1.1 matt struct obio_softc *sc = v; 296 1.1 matt struct pciconf_state ps; 297 1.1 matt vaddr_t va; 298 1.1 matt pcireg_t rv; 299 1.1 matt u_int s; 300 1.1 matt 301 1.1 matt if (gemini_pci_conf_setup(sc, tag, offset, &ps)) 302 1.1 matt return ((pcireg_t) -1); 303 1.1 matt 304 1.1 matt PCI_CONF_LOCK(s); 305 1.1 matt 306 1.1 matt if (sc->sc_pci_chipset.pc_cfg_cmd != ps.ps_addr_val) { 307 1.1 matt sc->sc_pci_chipset.pc_cfg_cmd = ps.ps_addr_val; 308 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_pcicfg_ioh, 309 1.1 matt GEMINI_PCI_CFG_CMD, ps.ps_addr_val); 310 1.1 matt } 311 1.1 matt 312 1.1 matt va = (vaddr_t) bus_space_vaddr(sc->sc_iot, sc->sc_pcicfg_ioh); 313 1.1 matt if (badaddr_read((void *) (va + GEMINI_PCI_CFG_DATA), sizeof(rv), &rv)) { 314 1.1 matt /* 315 1.1 matt * XXX Clear the Master Abort 316 1.1 matt */ 317 1.1 matt #if 1 318 1.1 matt printf("conf_read: %d/%d/%d bad address\n", 319 1.1 matt ps.ps_b, ps.ps_d, ps.ps_f); 320 1.1 matt #endif 321 1.1 matt rv = (pcireg_t) -1; 322 1.1 matt } 323 1.1 matt 324 1.1 matt PCI_CONF_UNLOCK(s); 325 1.1 matt 326 1.1 matt return (rv); 327 1.1 matt } 328 1.1 matt 329 1.1 matt void 330 1.1 matt gemini_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val) 331 1.1 matt { 332 1.1 matt struct obio_softc *sc = v; 333 1.1 matt struct pciconf_state ps; 334 1.1 matt u_int s; 335 1.1 matt 336 1.1 matt if (gemini_pci_conf_setup(sc, tag, offset, &ps)) 337 1.1 matt return; 338 1.1 matt 339 1.1 matt PCI_CONF_LOCK(s); 340 1.1 matt 341 1.1 matt if (sc->sc_pci_chipset.pc_cfg_cmd != ps.ps_addr_val) { 342 1.1 matt sc->sc_pci_chipset.pc_cfg_cmd = ps.ps_addr_val; 343 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_pcicfg_ioh, 344 1.1 matt GEMINI_PCI_CFG_CMD, ps.ps_addr_val); 345 1.1 matt } 346 1.1 matt 347 1.1 matt bus_space_write_4(sc->sc_iot, sc->sc_pcicfg_ioh, 348 1.1 matt GEMINI_PCI_CFG_DATA, val); 349 1.1 matt 350 1.1 matt PCI_CONF_UNLOCK(s); 351 1.1 matt } 352 1.1 matt 353 1.1 matt int 354 1.9 dyoung gemini_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 355 1.1 matt { 356 1.1 matt int irq; 357 1.1 matt 358 1.1 matt irq = 8; 359 1.1 matt 360 1.1 matt *ihp = irq; 361 1.1 matt return 0; 362 1.1 matt } 363 1.1 matt 364 1.1 matt const char * 365 1.16 christos gemini_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len) 366 1.1 matt { 367 1.16 christos strlcpy(buf, "pci", len); 368 1.16 christos return buf; 369 1.1 matt } 370 1.1 matt 371 1.1 matt const struct evcnt * 372 1.1 matt gemini_pci_intr_evcnt(void *v, pci_intr_handle_t ih) 373 1.1 matt { 374 1.1 matt return NULL; 375 1.1 matt } 376 1.1 matt 377 1.1 matt void * 378 1.1 matt gemini_pci_intr_establish(void *v, pci_intr_handle_t pci_ih, int ipl, 379 1.19 jmcneill int (*func)(void *), void *arg, const char *xname) 380 1.1 matt { 381 1.1 matt pcireg_t r; 382 1.1 matt void *ih=NULL; 383 1.1 matt int irq; 384 1.1 matt void *cookie; 385 1.1 matt 386 1.1 matt irq = (int)pci_ih; 387 1.1 matt 388 1.1 matt r = gemini_pci_conf_read(v, 0, GEMINI_PCI_CFG_REG_CTL2); 389 1.1 matt r |= CFG_REG_CTL2_INTMASK_INT_ABCD; 390 1.1 matt gemini_pci_conf_write(v, 0, GEMINI_PCI_CFG_REG_CTL2, r); 391 1.1 matt 392 1.1 matt if (gemini_pci_intrq_empty()) 393 1.19 jmcneill ih = intr_establish_xname(irq, ipl, IST_LEVEL_HIGH, 394 1.19 jmcneill gemini_pci_intr_handler, v, xname); 395 1.1 matt 396 1.1 matt cookie = gemini_pci_intrq_insert(ih, func, arg); 397 1.1 matt return cookie; 398 1.1 matt } 399 1.1 matt 400 1.1 matt void 401 1.1 matt gemini_pci_intr_disestablish(void *v, void *cookie) 402 1.1 matt { 403 1.1 matt pcireg_t r; 404 1.8 mbalmer struct gemini_pci_intrq *iqp = (struct gemini_pci_intrq *)cookie; 405 1.1 matt void *ih = iqp->iq_ih; 406 1.1 matt 407 1.1 matt gemini_pci_intrq_remove(cookie); 408 1.1 matt if (gemini_pci_intrq_empty()) { 409 1.1 matt r = gemini_pci_conf_read(v, 0, GEMINI_PCI_CFG_REG_CTL2); 410 1.1 matt r &= ~CFG_REG_CTL2_INTMASK_INT_ABCD; 411 1.1 matt gemini_pci_conf_write(v, 0, GEMINI_PCI_CFG_REG_CTL2, r); 412 1.1 matt intr_disestablish(ih); 413 1.1 matt } 414 1.1 matt } 415 1.1 matt 416 1.1 matt int 417 1.1 matt gemini_pci_intr_handler(void *v) 418 1.1 matt { 419 1.1 matt pcireg_t r; 420 1.1 matt int rv; 421 1.1 matt 422 1.1 matt /* 423 1.1 matt * dispatch PCI device interrupt handlers 424 1.1 matt */ 425 1.1 matt rv = gemini_pci_intrq_dispatch(); 426 1.1 matt 427 1.1 matt /* 428 1.1 matt * ack Gemini PCI interrupts 429 1.1 matt */ 430 1.1 matt r = gemini_pci_conf_read(v, 0, GEMINI_PCI_CFG_REG_CTL2); 431 1.1 matt gemini_pci_conf_write(v, 0, GEMINI_PCI_CFG_REG_CTL2, r); 432 1.1 matt 433 1.1 matt return rv; 434 1.1 matt } 435