1 /* $NetBSD: yeeloong_machdep.c,v 1.8 2016/07/10 00:14:36 jmcneill Exp $ */ 2 /* $OpenBSD: yeeloong_machdep.c,v 1.16 2011/04/15 20:40:06 deraadt Exp $ */ 3 4 /* 5 * Copyright (c) 2009, 2010 Miodrag Vallat. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * Lemote {Fu,Lyn,Yee}loong specific code and configuration data. 22 * (this file really ought to be named lemote_machdep.c by now) 23 */ 24 25 #include <sys/cdefs.h> 26 __KERNEL_RCSID(0, "$NetBSD: yeeloong_machdep.c,v 1.8 2016/07/10 00:14:36 jmcneill Exp $"); 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/device.h> 31 #include <sys/types.h> 32 33 #include <mips/cpuregs.h> 34 #include <evbmips/loongson/autoconf.h> 35 #include <mips/pmon/pmon.h> 36 #include <evbmips/loongson/loongson_intr.h> 37 #include <evbmips/loongson/loongson_bus_defs.h> 38 #include <evbmips/loongson/loongson_isa.h> 39 40 #include <dev/isa/isareg.h> 41 #include <dev/isa/isavar.h> 42 #include <dev/ic/i8259reg.h> 43 44 #include <dev/pci/pcireg.h> 45 #include <dev/pci/pcivar.h> 46 #include <dev/pci/pcidevs.h> 47 48 #include <mips/bonito/bonitoreg.h> 49 #include <mips/bonito/bonitovar.h> 50 51 #include <evbmips/loongson/dev/kb3310var.h> 52 #include <evbmips/loongson/dev/glxreg.h> 53 #include <evbmips/loongson/dev/glxvar.h> 54 55 #include "com.h" 56 #include "isa.h" 57 #include "ykbec.h" 58 59 #if NCOM > 0 60 #include <sys/termios.h> 61 #include <dev/ic/comvar.h> 62 #endif 63 64 #ifdef LOW_DEBUG 65 #define DPRINTF(x) printf x 66 #else 67 #define DPRINTF(x) 68 #endif 69 70 void lemote_device_register(device_t, void *); 71 void lemote_reset(void); 72 73 void fuloong_powerdown(void); 74 void fuloong_setup(void); 75 76 void yeeloong_powerdown(void); 77 78 void lemote_pci_attach_hook(device_t, device_t, 79 struct pcibus_attach_args *); 80 int lemote_intr_map(int, int, int, pci_intr_handle_t *); 81 82 void lemote_isa_attach_hook(device_t, device_t, 83 struct isabus_attach_args *); 84 void *lemote_isa_intr_establish(void *, int, int, int, 85 int (*)(void *), void *); 86 void lemote_isa_intr_disestablish(void *, void *); 87 const struct evcnt * lemote_isa_intr_evcnt(void *, int); 88 const char * lemote_isa_intr_string(void *, int, char *, size_t); 89 90 uint lemote_get_isa_imr(void); 91 uint lemote_get_isa_isr(void); 92 void lemote_isa_intr(int, vaddr_t, uint32_t); 93 94 const struct bonito_config lemote_bonito = { 95 .bc_adbase = 11, 96 97 .bc_gpioIE = LOONGSON_INTRMASK_GPIO, 98 .bc_intEdge = LOONGSON_INTRMASK_PCI_SYSERR | 99 LOONGSON_INTRMASK_PCI_PARERR, 100 .bc_intSteer = 0, 101 .bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR | 102 LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR | 103 LOONGSON_INTRMASK_INT0 | LOONGSON_INTRMASK_INT1, 104 105 .bc_attach_hook = lemote_pci_attach_hook, 106 }; 107 108 const struct legacy_io_range fuloong_legacy_ranges[] = { 109 /* isa */ 110 { IO_DMAPG + 4, IO_DMAPG + 4 }, 111 /* mcclock */ 112 { IO_RTC, IO_RTC + 1 }, 113 /* pciide */ 114 { 0x170, 0x170 + 7 }, 115 { 0x1f0, 0x1f0 + 7 }, 116 { 0x376, 0x376 }, 117 { 0x3f6, 0x3f6 }, 118 /* com */ 119 { IO_COM1, IO_COM1 + 8 }, /* IR port */ 120 { IO_COM2, IO_COM2 + 8 }, /* serial port */ 121 122 { 0 } 123 }; 124 125 const struct legacy_io_range lynloong_legacy_ranges[] = { 126 /* isa */ 127 { IO_DMAPG + 4, IO_DMAPG + 4 }, 128 /* mcclock */ 129 { IO_RTC, IO_RTC + 1 }, 130 /* pciide */ 131 { 0x170, 0x170 + 7 }, 132 { 0x1f0, 0x1f0 + 7 }, 133 { 0x376, 0x376 }, 134 { 0x3f6, 0x3f6 }, 135 #if 0 /* no external connector */ 136 /* com */ 137 { IO_COM2, IO_COM2 + 8 }, 138 #endif 139 140 { 0 } 141 }; 142 143 const struct legacy_io_range yeeloong_legacy_ranges[] = { 144 /* isa */ 145 { IO_DMAPG + 4, IO_DMAPG + 4 }, 146 /* pckbc */ 147 { IO_KBD, IO_KBD }, 148 { IO_KBD + 4, IO_KBD + 4 }, 149 /* mcclock */ 150 { IO_RTC, IO_RTC + 1 }, 151 /* pciide */ 152 { 0x170, 0x170 + 7 }, 153 { 0x1f0, 0x1f0 + 7 }, 154 { 0x376, 0x376 }, 155 { 0x3f6, 0x3f6 }, 156 /* kb3110b embedded controller */ 157 { 0x381, 0x383 }, 158 159 { 0 } 160 }; 161 162 struct mips_isa_chipset lemote_isa_chipset = { 163 .ic_v = NULL, 164 165 .ic_attach_hook = lemote_isa_attach_hook, 166 .ic_intr_establish = lemote_isa_intr_establish, 167 .ic_intr_disestablish = lemote_isa_intr_disestablish, 168 .ic_intr_evcnt = lemote_isa_intr_evcnt, 169 .ic_intr_string = lemote_isa_intr_string, 170 }; 171 172 const struct platform fuloong_platform = { 173 .system_type = LOONGSON_FULOONG, 174 .vendor = "Lemote", 175 .product = "Fuloong", 176 177 .bonito_config = &lemote_bonito, 178 .isa_chipset = &lemote_isa_chipset, 179 .legacy_io_ranges = fuloong_legacy_ranges, 180 .bonito_mips_intr = MIPS_INT_MASK_4, 181 .isa_mips_intr = MIPS_INT_MASK_0, 182 .isa_intr = lemote_isa_intr, 183 .p_pci_intr_map = lemote_intr_map, 184 .irq_map =loongson2f_irqmap, 185 186 .setup = fuloong_setup, 187 .device_register = lemote_device_register, 188 189 .powerdown = fuloong_powerdown, 190 .reset = lemote_reset 191 }; 192 193 const struct platform lynloong_platform = { 194 .system_type = LOONGSON_LYNLOONG, 195 .vendor = "Lemote", 196 .product = "Lynloong", 197 198 .bonito_config = &lemote_bonito, 199 .isa_chipset = &lemote_isa_chipset, 200 .legacy_io_ranges = lynloong_legacy_ranges, 201 .bonito_mips_intr = MIPS_INT_MASK_4, 202 .isa_mips_intr = MIPS_INT_MASK_0, 203 .isa_intr = lemote_isa_intr, 204 .p_pci_intr_map = lemote_intr_map, 205 .irq_map =loongson2f_irqmap, 206 207 .setup = fuloong_setup, 208 .device_register = lemote_device_register, 209 210 .powerdown = fuloong_powerdown, 211 .reset = lemote_reset 212 }; 213 214 const struct platform yeeloong_platform = { 215 .system_type = LOONGSON_YEELOONG, 216 .vendor = "Lemote", 217 .product = "Yeeloong", 218 219 .bonito_config = &lemote_bonito, 220 .isa_chipset = &lemote_isa_chipset, 221 .legacy_io_ranges = yeeloong_legacy_ranges, 222 .bonito_mips_intr = MIPS_INT_MASK_4, 223 .isa_mips_intr = MIPS_INT_MASK_0, 224 .isa_intr = lemote_isa_intr, 225 .p_pci_intr_map = lemote_intr_map, 226 .irq_map =loongson2f_irqmap, 227 228 .setup = NULL, 229 .device_register = lemote_device_register, 230 231 .powerdown = yeeloong_powerdown, 232 .reset = lemote_reset, 233 #if NYKBEC > 0 234 .suspend = ykbec_suspend, 235 .resume = ykbec_resume 236 #endif 237 }; 238 239 #if NISA > 0 240 static int stray_intr[BONITO_NISA]; 241 #endif 242 /* 243 * PCI model specific routines 244 */ 245 246 void 247 lemote_pci_attach_hook(device_t parent, device_t self, 248 struct pcibus_attach_args *pba) 249 { 250 pci_chipset_tag_t pc = pba->pba_pc; 251 pcitag_t tag; 252 pcireg_t id; 253 int dev, i; 254 255 if (pba->pba_bus != 0) 256 return; 257 258 /* 259 * Check for an AMD CS5536 chip; if one is found, register 260 * the proper PCI configuration space hooks. 261 */ 262 263 for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) { 264 tag = pci_make_tag(pc, 0, dev, 0); 265 id = pci_conf_read(pc, tag, PCI_ID_REG); 266 DPRINTF(("lemote_pci_attach_hook id 0x%x\n", id)); 267 if (id == PCI_ID_CODE(PCI_VENDOR_AMD, 268 PCI_PRODUCT_AMD_CS5536_PCISB)) { 269 glx_init(pc, tag, dev); 270 break; 271 } 272 } 273 274 wrmsr(GCSC_PIC_SHDW, 0); 275 DPRINTF(("PMON setup picregs:")); 276 for (i = 0; i < 12; i++) { 277 if (i == 6) 278 DPRINTF((" | ")); 279 DPRINTF((" 0x%x", (uint32_t)(rdmsr(GCSC_PIC_SHDW) & 0xff))); 280 } 281 DPRINTF(("\n")); 282 DPRINTF(("intsel 0x%x 0x%x\n", REGVAL8(BONITO_PCIIO_BASE + 0x4d0), 283 REGVAL8(BONITO_PCIIO_BASE + 0x4d1))); 284 285 /* setup legacy interrupt controller */ 286 REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW1) = 0xff; 287 REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW1) = 288 ICW1_SELECT | ICW1_IC4; 289 REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW2) = ICW2_VECTOR(0); 290 REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW3) = ICW3_CASCADE(2); 291 REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW4) = ICW4_8086; 292 delay(100); 293 /* mask all interrupts */ 294 REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW1) = 0xff; 295 296 /* read ISR by default. */ 297 REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) = OCW3_SELECT | OCW3_RR; 298 (void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3); 299 300 /* reset; program device, four bytes */ 301 REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW1) = 0xff; 302 REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW1) = 303 ICW1_SELECT | ICW1_IC4; 304 REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW2) = ICW2_VECTOR(8); 305 REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW3) = ICW3_SIC(2); 306 REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW4) = ICW4_8086; 307 delay(100); 308 /* leave interrupts masked */ 309 REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW1) = 0xff; 310 /* read ISR by default. */ 311 REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) = OCW3_SELECT | OCW3_RR; 312 (void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3); 313 } 314 315 int 316 lemote_intr_map(int dev, int fn, int pin, pci_intr_handle_t *ihp) 317 { 318 switch (dev) { 319 /* onboard devices, only pin A is wired */ 320 case 6: 321 case 7: 322 case 8: 323 case 9: 324 if (pin == PCI_INTERRUPT_PIN_A) { 325 *ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA + 326 (dev - 6)); 327 return (0); 328 } 329 break; 330 /* PCI slot */ 331 case 10: 332 *ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA + 333 (pin - PCI_INTERRUPT_PIN_A)); 334 return (0); 335 /* Geode chip */ 336 case 14: 337 switch (fn) { 338 case 1: /* Flash */ 339 *ihp = BONITO_ISA_IRQ(6); 340 return (0); 341 case 3: /* AC97 */ 342 *ihp = BONITO_ISA_IRQ(9); 343 return (0); 344 case 4: /* OHCI */ 345 case 5: /* EHCI */ 346 *ihp = BONITO_ISA_IRQ(11); 347 return (0); 348 } 349 break; 350 default: 351 break; 352 } 353 return (1); 354 } 355 356 /* 357 * ISA model specific routines 358 */ 359 #if NISA > 0 360 void 361 lemote_isa_attach_hook(device_t parent, device_t self, 362 struct isabus_attach_args *iba) 363 { 364 365 loongson_set_isa_imr(loongson_isaimr); 366 } 367 368 void * 369 lemote_isa_intr_establish(void *v, int irq, int type, int level, 370 int (*handler)(void *), void *arg) 371 { 372 void *ih; 373 uint imr; 374 375 ih = evbmips_intr_establish(BONITO_ISA_IRQ(irq), handler, arg); 376 if (ih == NULL) 377 return (NULL); 378 379 /* enable interrupt */ 380 imr = lemote_get_isa_imr(); 381 imr |= (1 << irq); 382 DPRINTF(("lemote_isa_intr_establish: enable irq %d 0x%x\n", irq, imr)); 383 loongson_set_isa_imr(imr); 384 return (ih); 385 } 386 387 void 388 lemote_isa_intr_disestablish(void *v, void *ih) 389 { 390 391 evbmips_intr_disestablish(ih); 392 } 393 394 const struct evcnt * 395 lemote_isa_intr_evcnt(void *v, int irq) 396 { 397 398 if (irq == 0 || irq >= BONITO_NISA || irq == 2) 399 panic("lemote_isa_intr_evcnt: bogus isa irq 0x%x", irq); 400 401 return (&bonito_intrhead[BONITO_ISA_IRQ(irq)].intr_count); 402 } 403 404 const char * 405 lemote_isa_intr_string(void *v, int irq, char *buf, size_t len) 406 { 407 if (irq == 0 || irq >= BONITO_NISA || irq == 2) 408 panic("lemote_isa_intr_string: bogus isa irq 0x%x", irq); 409 410 return loongson_intr_string(&lemote_bonito, BONITO_ISA_IRQ(irq), buf, 411 len); 412 } 413 #endif 414 /* 415 * Legacy (ISA) interrupt handling 416 */ 417 418 /* 419 * Process legacy interrupts. 420 * 421 * XXX On 2F, ISA interrupts only occur on LOONGSON_INTR_INT0, but since 422 * XXX the other LOONGSON_INTR_INT# are unmaskable, bad things will happen 423 * XXX if they ever are triggered... 424 */ 425 void 426 lemote_isa_intr(int ipl, vaddr_t pc, uint32_t ipending) 427 { 428 #if NISA > 0 429 struct evbmips_intrhand *ih; 430 uint32_t isr, imr, mask; 431 int bitno; 432 int rc; 433 434 imr = lemote_get_isa_imr(); 435 isr = lemote_get_isa_isr() & imr; 436 if (isr == 0) 437 return; 438 439 /* 440 * Now process allowed interrupts. 441 */ 442 /* Service higher level interrupts first */ 443 for (bitno = BONITO_NISA - 1, mask = 1UL << bitno; 444 mask != 0; 445 bitno--, mask >>= 1) { 446 if ((isr & mask) == 0) 447 continue; 448 449 loongson_isa_specific_eoi(bitno); 450 451 rc = 0; 452 LIST_FOREACH(ih, 453 &bonito_intrhead[BONITO_ISA_IRQ(bitno)].intrhand_head, 454 ih_q) { 455 if ((*ih->ih_func)(ih->ih_arg) != 0) { 456 rc = 1; 457 bonito_intrhead[BONITO_ISA_IRQ(bitno)].intr_count.ev_count++; 458 } 459 } 460 if (rc == 0) { 461 if (stray_intr[bitno]++ & 0x10000) { 462 printf("spurious isa interrupt %d\n", bitno); 463 stray_intr[bitno] = 0; 464 } 465 } 466 467 if ((isr ^= mask) == 0) 468 break; 469 } 470 471 /* 472 * Reenable interrupts which have been serviced. 473 */ 474 loongson_set_isa_imr(imr); 475 #endif 476 } 477 478 uint 479 lemote_get_isa_imr(void) 480 { 481 uint imr1, imr2; 482 483 imr1 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW1); 484 imr1 &= ~(1 << 2); /* hide cascade */ 485 imr2 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW1); 486 487 return ((imr2 << 8) | imr1); 488 } 489 490 uint 491 lemote_get_isa_isr(void) 492 { 493 uint isr1, isr2; 494 495 isr1 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU1); 496 isr1 &= ~(1 << 2); 497 isr2 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU2); 498 499 return ((isr2 << 8) | isr1); 500 } 501 502 /* 503 * Other model specific routines 504 */ 505 506 void 507 fuloong_powerdown(void) 508 { 509 vaddr_t gpiobase; 510 511 gpiobase = BONITO_PCIIO_BASE + (rdmsr(GCSC_DIVIL_LBAR_GPIO) & 0xff00); 512 /* enable GPIO 13 */ 513 REGVAL(gpiobase + GCSC_GPIOL_OUT_EN) = GCSC_GPIO_ATOMIC_VALUE(13, 1); 514 /* set GPIO13 value to zero */ 515 REGVAL(gpiobase + GCSC_GPIOL_OUT_VAL) = GCSC_GPIO_ATOMIC_VALUE(13, 0); 516 } 517 518 void 519 yeeloong_powerdown(void) 520 { 521 522 REGVAL(BONITO_GPIODATA) &= ~0x00000001; 523 REGVAL(BONITO_GPIOIE) &= ~0x00000001; 524 } 525 526 void 527 lemote_reset(void) 528 { 529 530 wrmsr(GCSC_GLCP_SYS_RST, rdmsr(GCSC_GLCP_SYS_RST) | 1); 531 } 532 533 void 534 fuloong_setup(void) 535 { 536 #if NCOM > 0 537 const char *envvar; 538 int serial; 539 540 envvar = pmon_getenv("nokbd"); 541 serial = envvar != NULL; 542 envvar = pmon_getenv("novga"); 543 serial = serial && envvar != NULL; 544 545 //serial = 1; /* XXXXXX */ 546 if (serial) { 547 comconsiot = &bonito_iot; 548 comconsaddr = 0x2f8; 549 comconsrate = 115200; /* default PMON console speed */ 550 } 551 #endif 552 } 553 554 void 555 lemote_device_register(device_t dev, void *aux) 556 { 557 const char *name = device_xname(dev); 558 559 if (device_class(dev) != bootdev_class) 560 return; 561 562 /* OHCI memory space access may not be enabled by the BIOS */ 563 if (device_is_a(dev, "ohci")) { 564 struct pci_attach_args *pa = aux; 565 pcireg_t csr = pci_conf_read(pa->pa_pc, pa->pa_tag, 566 PCI_COMMAND_STATUS_REG); 567 if ((csr & PCI_COMMAND_MEM_ENABLE) == 0) { 568 csr |= PCI_COMMAND_MEM_ENABLE; 569 pci_conf_write(pa->pa_pc, pa->pa_tag, 570 PCI_COMMAND_STATUS_REG, csr); 571 } 572 } 573 574 /* 575 * The device numbering must match. There's no way 576 * pmon tells us more info. Depending on the usb slot 577 * and hubs used you may be lucky. Also, assume umass/sd for usb 578 * attached devices. 579 */ 580 switch (bootdev_class) { 581 case DV_DISK: 582 if (device_is_a(dev, "wd") && strcmp(name, bootdev) == 0) { 583 if (booted_device == NULL) 584 booted_device = dev; 585 } else { 586 /* XXX this really only works safely for usb0... */ 587 if ((device_is_a(dev, "sd") || 588 device_is_a(dev, "cd") == 0) && 589 strncmp(bootdev, "usb", 3) == 0 && 590 strcmp(name + 2, bootdev + 3) == 0) { 591 if (booted_device == NULL) 592 booted_device = dev; 593 } 594 } 595 break; 596 case DV_IFNET: 597 /* 598 * This relies on the onboard Ethernet interface being 599 * attached before any other (usb) interface. 600 */ 601 if (booted_device == NULL) 602 booted_device = dev; 603 break; 604 default: 605 break; 606 } 607 } 608