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