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