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