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