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
lemote_pci_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)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
lemote_intr_map(int dev,int fn,int pin,pci_intr_handle_t * ihp)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
lemote_isa_attach_hook(device_t parent,device_t self,struct isabus_attach_args * iba)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 *
lemote_isa_intr_establish(void * v,int irq,int type,int level,int (* handler)(void *),void * arg)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
lemote_isa_intr_disestablish(void * v,void * ih)388 lemote_isa_intr_disestablish(void *v, void *ih)
389 {
390
391 evbmips_intr_disestablish(ih);
392 }
393
394 const struct evcnt *
lemote_isa_intr_evcnt(void * v,int irq)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 *
lemote_isa_intr_string(void * v,int irq,char * buf,size_t len)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
lemote_isa_intr(int ipl,vaddr_t pc,uint32_t ipending)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
lemote_get_isa_imr(void)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
lemote_get_isa_isr(void)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
fuloong_powerdown(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
yeeloong_powerdown(void)519 yeeloong_powerdown(void)
520 {
521
522 REGVAL(BONITO_GPIODATA) &= ~0x00000001;
523 REGVAL(BONITO_GPIOIE) &= ~0x00000001;
524 }
525
526 void
lemote_reset(void)527 lemote_reset(void)
528 {
529
530 wrmsr(GCSC_GLCP_SYS_RST, rdmsr(GCSC_GLCP_SYS_RST) | 1);
531 }
532
533 void
fuloong_setup(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
lemote_device_register(device_t dev,void * aux)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