yeeloong_machdep.c revision 1.7
1/* $NetBSD: yeeloong_machdep.c,v 1.7 2015/06/09 16:29:01 macallan 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.7 2015/06/09 16:29:01 macallan 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 70void lemote_device_register(device_t, void *); 71void lemote_reset(void); 72 73void fuloong_powerdown(void); 74void fuloong_setup(void); 75 76void yeeloong_powerdown(void); 77 78void lemote_pci_attach_hook(device_t, device_t, 79 struct pcibus_attach_args *); 80int lemote_intr_map(int, int, int, pci_intr_handle_t *); 81 82void lemote_isa_attach_hook(device_t, device_t, 83 struct isabus_attach_args *); 84void *lemote_isa_intr_establish(void *, int, int, int, 85 int (*)(void *), void *); 86void lemote_isa_intr_disestablish(void *, void *); 87const struct evcnt * lemote_isa_intr_evcnt(void *, int); 88const char * lemote_isa_intr_string(void *, int, char *, size_t); 89 90uint lemote_get_isa_imr(void); 91uint lemote_get_isa_isr(void); 92void lemote_isa_intr(int, vaddr_t, uint32_t); 93 94const 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 108const 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 125const 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 143const 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 162struct 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 172const 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 193const 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 214const 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 240static int stray_intr[BONITO_NISA]; 241#endif 242/* 243 * PCI model specific routines 244 */ 245 246void 247lemote_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 315int 316lemote_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 360void 361lemote_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 368void * 369lemote_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 387void 388lemote_isa_intr_disestablish(void *v, void *ih) 389{ 390 391 evbmips_intr_disestablish(ih); 392} 393 394const struct evcnt * 395lemote_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 404const char * 405lemote_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 */ 425void 426lemote_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 478uint 479lemote_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 490uint 491lemote_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 506void 507fuloong_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 518void 519yeeloong_powerdown(void) 520{ 521 522 REGVAL(BONITO_GPIODATA) &= ~0x00000001; 523 REGVAL(BONITO_GPIOIE) &= ~0x00000001; 524} 525 526void 527lemote_reset(void) 528{ 529 530 wrmsr(GCSC_GLCP_SYS_RST, rdmsr(GCSC_GLCP_SYS_RST) | 1); 531} 532 533void 534fuloong_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 554void 555lemote_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 /* 563 * The device numbering must match. There's no way 564 * pmon tells us more info. Depending on the usb slot 565 * and hubs used you may be lucky. Also, assume umass/sd for usb 566 * attached devices. 567 */ 568 switch (bootdev_class) { 569 case DV_DISK: 570 if (device_is_a(dev, "wd") && strcmp(name, bootdev) == 0) { 571 if (booted_device == NULL) 572 booted_device = dev; 573 } else { 574 /* XXX this really only works safely for usb0... */ 575 if ((device_is_a(dev, "sd") || 576 device_is_a(dev, "cd") == 0) && 577 strncmp(bootdev, "usb", 3) == 0 && 578 strcmp(name + 2, bootdev + 3) == 0) { 579 if (booted_device == NULL) 580 booted_device = dev; 581 } 582 } 583 break; 584 case DV_IFNET: 585 /* 586 * This relies on the onboard Ethernet interface being 587 * attached before any other (usb) interface. 588 */ 589 if (booted_device == NULL) 590 booted_device = dev; 591 break; 592 default: 593 break; 594 } 595} 596