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