1 /* $OpenBSD: htb.c,v 1.3 2017/05/10 15:21:02 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2016 Visa Hankala 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 /* 20 * PCI host bridge driver for Loongson 3A. 21 */ 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/device.h> 26 27 #include <machine/autoconf.h> 28 #include <machine/loongson3.h> 29 30 #include <dev/pci/pcidevs.h> 31 #include <dev/pci/pcireg.h> 32 #include <dev/pci/pcivar.h> 33 #include <dev/pci/ppbreg.h> 34 35 #include <loongson/dev/htbreg.h> 36 #include <loongson/dev/htbvar.h> 37 38 struct htb_softc { 39 struct device sc_dev; 40 struct mips_pci_chipset sc_pc; 41 const struct htb_config *sc_config; 42 }; 43 44 int htb_match(struct device *, void *, void *); 45 void htb_attach(struct device *, struct device *, void *); 46 int htb_print(void *, const char *); 47 48 void htb_attach_hook(struct device *, struct device *, 49 struct pcibus_attach_args *pba); 50 int htb_bus_maxdevs(void *, int); 51 pcitag_t htb_make_tag(void *, int, int, int); 52 void htb_decompose_tag(void *, pcitag_t, int *, int *, int *); 53 int htb_conf_addr(const struct bonito_config *, pcitag_t, int, 54 u_int32_t *, u_int32_t *); 55 int htb_conf_size(void *, pcitag_t); 56 pcireg_t htb_conf_read(void *, pcitag_t, int); 57 void htb_conf_write(void *, pcitag_t, int, pcireg_t); 58 int htb_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 59 const char * 60 htb_pci_intr_string(void *, pci_intr_handle_t); 61 void *htb_pci_intr_establish(void *, pci_intr_handle_t, int, 62 int (*)(void *), void *, char *); 63 void htb_pci_intr_disestablish(void *, void *); 64 65 bus_addr_t htb_pa_to_device(paddr_t); 66 paddr_t htb_device_to_pa(bus_addr_t); 67 68 int htb_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 69 bus_space_handle_t *); 70 int htb_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 71 bus_space_handle_t *); 72 paddr_t htb_mem_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int); 73 74 paddr_t htb_cfg_space_addr(pcitag_t, int); 75 76 pcireg_t htb_conf_read_early(pcitag_t, int); 77 pcitag_t htb_make_tag_early(int, int, int); 78 79 const struct cfattach htb_ca = { 80 sizeof(struct htb_softc), htb_match, htb_attach 81 }; 82 83 struct cfdriver htb_cd = { 84 NULL, "htb", DV_DULL 85 }; 86 87 struct machine_bus_dma_tag htb_bus_dma_tag = { 88 ._dmamap_create = _dmamap_create, 89 ._dmamap_destroy = _dmamap_destroy, 90 ._dmamap_load = _dmamap_load, 91 ._dmamap_load_mbuf = _dmamap_load_mbuf, 92 ._dmamap_load_uio = _dmamap_load_uio, 93 ._dmamap_load_raw = _dmamap_load_raw, 94 ._dmamap_load_buffer = _dmamap_load_buffer, 95 ._dmamap_unload = _dmamap_unload, 96 ._dmamap_sync = _dmamap_sync, 97 ._dmamem_alloc = _dmamem_alloc, 98 ._dmamem_free = _dmamem_free, 99 ._dmamem_map = _dmamem_map, 100 ._dmamem_unmap = _dmamem_unmap, 101 ._dmamem_mmap = _dmamem_mmap, 102 103 ._pa_to_device = htb_pa_to_device, 104 ._device_to_pa = htb_device_to_pa 105 }; 106 107 struct mips_bus_space htb_pci_io_space_tag = { 108 .bus_base = PHYS_TO_XKPHYS(HTB_IO_BASE, CCA_NC), 109 ._space_read_1 = generic_space_read_1, 110 ._space_write_1 = generic_space_write_1, 111 ._space_read_2 = generic_space_read_2, 112 ._space_write_2 = generic_space_write_2, 113 ._space_read_4 = generic_space_read_4, 114 ._space_write_4 = generic_space_write_4, 115 ._space_read_8 = generic_space_read_8, 116 ._space_write_8 = generic_space_write_8, 117 ._space_read_raw_2 = generic_space_read_raw_2, 118 ._space_write_raw_2 = generic_space_write_raw_2, 119 ._space_read_raw_4 = generic_space_read_raw_4, 120 ._space_write_raw_4 = generic_space_write_raw_4, 121 ._space_read_raw_8 = generic_space_read_raw_8, 122 ._space_write_raw_8 = generic_space_write_raw_8, 123 ._space_map = htb_io_map, 124 ._space_unmap = generic_space_unmap, 125 ._space_subregion = generic_space_region, 126 ._space_vaddr = generic_space_vaddr, 127 ._space_mmap = generic_space_mmap 128 }; 129 130 struct mips_bus_space htb_pci_mem_space_tag = { 131 .bus_base = PHYS_TO_XKPHYS(0, CCA_NC), 132 ._space_read_1 = generic_space_read_1, 133 ._space_write_1 = generic_space_write_1, 134 ._space_read_2 = generic_space_read_2, 135 ._space_write_2 = generic_space_write_2, 136 ._space_read_4 = generic_space_read_4, 137 ._space_write_4 = generic_space_write_4, 138 ._space_read_8 = generic_space_read_8, 139 ._space_write_8 = generic_space_write_8, 140 ._space_read_raw_2 = generic_space_read_raw_2, 141 ._space_write_raw_2 = generic_space_write_raw_2, 142 ._space_read_raw_4 = generic_space_read_raw_4, 143 ._space_write_raw_4 = generic_space_write_raw_4, 144 ._space_read_raw_8 = generic_space_read_raw_8, 145 ._space_write_raw_8 = generic_space_write_raw_8, 146 ._space_map = htb_mem_map, 147 ._space_unmap = generic_space_unmap, 148 ._space_subregion = generic_space_region, 149 ._space_vaddr = generic_space_vaddr, 150 ._space_mmap = htb_mem_mmap 151 }; 152 153 int 154 htb_match(struct device *parent, void *match, void *aux) 155 { 156 struct mainbus_attach_args *maa = aux; 157 158 if (loongson_ver != 0x3a && loongson_ver != 0x3b) 159 return 0; 160 161 if (strcmp(maa->maa_name, htb_cd.cd_name) != 0) 162 return 0; 163 164 return 1; 165 } 166 167 void 168 htb_attach(struct device *parent, struct device *self, void *aux) 169 { 170 struct pcibus_attach_args pba; 171 struct htb_softc *sc = (struct htb_softc *)self; 172 pci_chipset_tag_t pc = &sc->sc_pc; 173 174 printf("\n"); 175 176 sc->sc_config = sys_platform->htb_config; 177 178 pc->pc_conf_v = sc; 179 pc->pc_attach_hook = htb_attach_hook; 180 pc->pc_bus_maxdevs = htb_bus_maxdevs; 181 pc->pc_make_tag = htb_make_tag; 182 pc->pc_decompose_tag = htb_decompose_tag; 183 pc->pc_conf_size = htb_conf_size; 184 pc->pc_conf_read = htb_conf_read; 185 pc->pc_conf_write = htb_conf_write; 186 187 pc->pc_intr_v = sc; 188 pc->pc_intr_map = htb_pci_intr_map; 189 pc->pc_intr_string = htb_pci_intr_string; 190 pc->pc_intr_establish = htb_pci_intr_establish; 191 pc->pc_intr_disestablish = htb_pci_intr_disestablish; 192 193 memset(&pba, 0, sizeof(pba)); 194 pba.pba_busname = "pci"; 195 pba.pba_iot = &htb_pci_io_space_tag; 196 pba.pba_memt = &htb_pci_mem_space_tag; 197 pba.pba_dmat = &htb_bus_dma_tag; 198 pba.pba_pc = pc; 199 pba.pba_ioex = extent_create("htb_io", 0, 0xffffffff, M_DEVBUF, 200 NULL, 0, EX_NOWAIT | EX_FILLED); 201 if (pba.pba_ioex != NULL) { 202 extent_free(pba.pba_ioex, 0, HTB_IO_SIZE, EX_NOWAIT); 203 } 204 pba.pba_memex = extent_create("htb_mem", 0, 0xffffffff, M_DEVBUF, 205 NULL, 0, EX_NOWAIT | EX_FILLED); 206 if (pba.pba_memex != NULL) { 207 extent_free(pba.pba_memex, HTB_MEM_BASE, HTB_MEM_SIZE, 208 EX_NOWAIT); 209 } 210 pba.pba_domain = pci_ndomains++; 211 pba.pba_bus = 0; 212 config_found(&sc->sc_dev, &pba, htb_print); 213 } 214 215 int 216 htb_print(void *aux, const char *pnp) 217 { 218 struct pcibus_attach_args *pba = aux; 219 220 if (pnp) 221 printf("%s at %s", pba->pba_busname, pnp); 222 printf(" bus %d", pba->pba_bus); 223 224 return UNCONF; 225 } 226 227 void 228 htb_attach_hook(struct device *parent, struct device *self, 229 struct pcibus_attach_args *pba) 230 { 231 pci_chipset_tag_t pc = pba->pba_pc; 232 struct htb_softc *sc = pc->pc_conf_v; 233 const struct htb_config *hc = sc->sc_config; 234 235 if (pba->pba_bus == 0) 236 hc->hc_attach_hook(pc); 237 } 238 239 int 240 htb_bus_maxdevs(void *v, int busno) 241 { 242 return 32; 243 } 244 245 pcitag_t 246 htb_make_tag(void *unused, int b, int d, int f) 247 { 248 return (b << 16) | (d << 11) | (f << 8); 249 } 250 251 void 252 htb_decompose_tag(void *unused, pcitag_t tag, int *bp, int *dp, int *fp) 253 { 254 if (bp != NULL) 255 *bp = (tag >> 16) & 0xff; 256 if (dp != NULL) 257 *dp = (tag >> 11) & 0x1f; 258 if (fp != NULL) 259 *fp = (tag >> 8) & 0x7; 260 } 261 262 int 263 htb_conf_addr(const struct bonito_config *bc, pcitag_t tag, int offset, 264 u_int32_t *cfgoff, u_int32_t *pcimap_cfg) 265 { 266 return -1; 267 } 268 269 int 270 htb_conf_size(void *v, pcitag_t tag) 271 { 272 return PCIE_CONFIG_SPACE_SIZE; 273 } 274 275 pcireg_t 276 htb_conf_read(void *v, pcitag_t tag, int offset) 277 { 278 return REGVAL(htb_cfg_space_addr(tag, offset)); 279 } 280 281 void 282 htb_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data) 283 { 284 REGVAL(htb_cfg_space_addr(tag, offset)) = data; 285 } 286 287 paddr_t 288 htb_cfg_space_addr(pcitag_t tag, int offset) 289 { 290 paddr_t pa; 291 int bus; 292 293 htb_decompose_tag(NULL, tag, &bus, NULL, NULL); 294 if (bus == 0) 295 pa = HTB_CFG_TYPE0_BASE; 296 else 297 pa = HTB_CFG_TYPE1_BASE; 298 return pa + tag + (offset & 0xfffc); 299 } 300 301 /* 302 * PCI interrupt handling 303 */ 304 305 int 306 htb_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 307 { 308 int dev, pin; 309 310 *ihp = (pci_intr_handle_t)-1; 311 312 if (pa->pa_intrpin == 0) 313 return 1; 314 315 if (pa->pa_intrpin > PCI_INTERRUPT_PIN_MAX) { 316 printf(": bad interrupt pin %d\n", pa->pa_intrpin); 317 return 1; 318 } 319 320 pci_decompose_tag(pa->pa_pc, pa->pa_tag, NULL, &dev, NULL); 321 if (pa->pa_bridgetag != NULL) { 322 pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev); 323 if (pa->pa_bridgeih[pin - 1] != (pci_intr_handle_t)-1) { 324 *ihp = pa->pa_bridgeih[pin - 1]; 325 return 0; 326 } 327 } 328 329 if (pa->pa_intrline != 0) { 330 *ihp = pa->pa_intrline; 331 return 0; 332 } 333 334 return 1; 335 } 336 337 const char * 338 htb_pci_intr_string(void *cookie, pci_intr_handle_t ih) 339 { 340 static char irqstr[16]; 341 342 snprintf(irqstr, sizeof(irqstr), "irq %lu", ih); 343 return irqstr; 344 } 345 346 void * 347 htb_pci_intr_establish(void *cookie, pci_intr_handle_t ih, int level, 348 int (*cb)(void *), void *cbarg, char *name) 349 { 350 return loongson3_ht_intr_establish(ih, level, cb, cbarg, name); 351 } 352 353 void 354 htb_pci_intr_disestablish(void *cookie, void *ihp) 355 { 356 loongson3_ht_intr_disestablish(ihp); 357 } 358 359 bus_addr_t 360 htb_pa_to_device(paddr_t pa) 361 { 362 return pa ^ loongson_dma_base; 363 } 364 365 paddr_t 366 htb_device_to_pa(bus_addr_t addr) 367 { 368 return addr ^ loongson_dma_base; 369 } 370 371 /* 372 * bus_space(9) mapping routines 373 */ 374 375 int 376 htb_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, 377 bus_space_handle_t *bshp) 378 { 379 const struct legacy_io_range *r; 380 bus_addr_t end; 381 382 if (offs >= HTB_IO_SIZE) 383 return EINVAL; 384 385 if (offs < HTB_IO_LEGACY) { 386 end = offs + size - 1; 387 if ((r = sys_platform->legacy_io_ranges) == NULL) 388 return ENXIO; 389 for ( ; r->start != 0; r++) { 390 if (offs >= r->start && end <= r->end) 391 break; 392 } 393 if (r->end == 0) 394 return ENXIO; 395 } 396 397 *bshp = t->bus_base + offs; 398 return 0; 399 } 400 401 int 402 htb_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, 403 bus_space_handle_t *bshp) 404 { 405 if (offs < HTB_MEM_BASE || offs + size > HTB_MEM_BASE + HTB_MEM_SIZE) 406 return EINVAL; 407 408 *bshp = t->bus_base + offs; 409 return 0; 410 } 411 412 paddr_t 413 htb_mem_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off, int prot, 414 int flags) 415 { 416 return addr + off; 417 } 418 419 /* 420 * Functions for system setup 421 */ 422 423 void 424 htb_early_setup(void) 425 { 426 pci_make_tag_early = htb_make_tag_early; 427 pci_conf_read_early = htb_conf_read_early; 428 429 early_mem_t = &htb_pci_mem_space_tag; 430 early_io_t = &htb_pci_io_space_tag; 431 } 432 433 pcitag_t 434 htb_make_tag_early(int b, int d, int f) 435 { 436 return htb_make_tag(NULL, b, d, f); 437 } 438 439 pcireg_t 440 htb_conf_read_early(pcitag_t tag, int reg) 441 { 442 return htb_conf_read(NULL, tag, reg); 443 } 444