yeeloong_machdep.c revision 1.6
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 69void lemote_device_register(device_t, void *); 70void lemote_reset(void); 71 72void fuloong_powerdown(void); 73void fuloong_setup(void); 74 75void yeeloong_powerdown(void); 76 77void lemote_pci_attach_hook(device_t, device_t, 78 struct pcibus_attach_args *); 79int lemote_intr_map(int, int, int, pci_intr_handle_t *); 80 81void lemote_isa_attach_hook(device_t, device_t, 82 struct isabus_attach_args *); 83void *lemote_isa_intr_establish(void *, int, int, int, 84 int (*)(void *), void *); 85void lemote_isa_intr_disestablish(void *, void *); 86const struct evcnt * lemote_isa_intr_evcnt(void *, int); 87const char * lemote_isa_intr_string(void *, int, char *, size_t); 88 89uint lemote_get_isa_imr(void); 90uint lemote_get_isa_isr(void); 91void lemote_isa_intr(int, vaddr_t, uint32_t); 92 93const 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 107const 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 124const 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 142const 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 161struct 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 171const 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 192const 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 213const 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 239static int stray_intr[BONITO_NISA]; 240#endif 241/* 242 * PCI model specific routines 243 */ 244 245void 246lemote_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 314int 315lemote_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 359void 360lemote_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 367void * 368lemote_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 386void 387lemote_isa_intr_disestablish(void *v, void *ih) 388{ 389 390 evbmips_intr_disestablish(ih); 391} 392 393const struct evcnt * 394lemote_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 403const char * 404lemote_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 */ 424void 425lemote_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 477uint 478lemote_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 489uint 490lemote_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 505void 506fuloong_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 517void 518yeeloong_powerdown(void) 519{ 520 521 REGVAL(BONITO_GPIODATA) &= ~0x00000001; 522 REGVAL(BONITO_GPIOIE) &= ~0x00000001; 523} 524 525void 526lemote_reset(void) 527{ 528 529 wrmsr(GCSC_GLCP_SYS_RST, rdmsr(GCSC_GLCP_SYS_RST) | 1); 530} 531 532void 533fuloong_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 553void 554lemote_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