xref: /netbsd-src/sys/arch/alpha/tc/tc_3000_300.c (revision b7b2b8a3d89bfee25ca9324638c59a92666e2e4e)
1*b7b2b8a3Sthorpej /* $NetBSD: tc_3000_300.c,v 1.39 2021/05/07 16:58:34 thorpej Exp $ */
2dd5a5290Scgd 
3dd5a5290Scgd /*
4576c7693Scgd  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
5dd5a5290Scgd  * All rights reserved.
6dd5a5290Scgd  *
7dd5a5290Scgd  * Author: Chris G. Demetriou
8dd5a5290Scgd  *
9dd5a5290Scgd  * Permission to use, copy, modify and distribute this software and
10dd5a5290Scgd  * its documentation is hereby granted, provided that both the copyright
11dd5a5290Scgd  * notice and this permission notice appear in all copies of the
12dd5a5290Scgd  * software, derivative works or modified versions, and any portions
13dd5a5290Scgd  * thereof, and that both notices appear in supporting documentation.
14dd5a5290Scgd  *
15dd5a5290Scgd  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16dd5a5290Scgd  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17dd5a5290Scgd  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18dd5a5290Scgd  *
19dd5a5290Scgd  * Carnegie Mellon requests users of this software to return to
20dd5a5290Scgd  *
21dd5a5290Scgd  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22dd5a5290Scgd  *  School of Computer Science
23dd5a5290Scgd  *  Carnegie Mellon University
24dd5a5290Scgd  *  Pittsburgh PA 15213-3890
25dd5a5290Scgd  *
26dd5a5290Scgd  * any improvements or extensions that they make and grant Carnegie the
27dd5a5290Scgd  * rights to redistribute these changes.
28dd5a5290Scgd  */
29dd5a5290Scgd 
3090789b53Scgd #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
3190789b53Scgd 
32*b7b2b8a3Sthorpej __KERNEL_RCSID(0, "$NetBSD: tc_3000_300.c,v 1.39 2021/05/07 16:58:34 thorpej Exp $");
33059aaeddScgd 
34dd5a5290Scgd #include <sys/param.h>
350cefc7efScgd #include <sys/systm.h>
36dd5a5290Scgd #include <sys/device.h>
376f97a7c1Sthorpej #include <sys/kmem.h>
38d15aec95Sthorpej #include <sys/cpu.h>
39dd5a5290Scgd 
40dd5a5290Scgd #include <machine/autoconf.h>
41dd5a5290Scgd #include <machine/pte.h>
42dd5a5290Scgd 
43a5c74353Scgd #include <dev/tc/tcvar.h>
44c6641d91Snisimura #include <dev/tc/ioasicreg.h>
45a5c74353Scgd #include <alpha/tc/tc_conf.h>
46dd5a5290Scgd #include <alpha/tc/tc_3000_300.h>
4767be755fSbriggs 
4831a77e61Sdrochner #include "wsdisplay.h"
4967be755fSbriggs #include "sfb.h"
5067be755fSbriggs 
5167be755fSbriggs #if NSFB > 0
5202cdf4d2Sdsl extern int	sfb_cnattach(tc_addr_t);
5367be755fSbriggs #endif
54dd5a5290Scgd 
55*b7b2b8a3Sthorpej static int	tc_3000_300_intrnull(void *);
56dd5a5290Scgd 
57a5c74353Scgd #define	C(x)	((void *)(u_long)x)
580cefc7efScgd #define	KV(x)	(ALPHA_PHYS_TO_K0SEG(x))
59a5c74353Scgd 
60ba87ccc4Scgd /*
61ba87ccc4Scgd  * We have to read and modify the IOASIC registers directly, because
62ba87ccc4Scgd  * the TC option slot interrupt request and mask bits are stored there,
63ba87ccc4Scgd  * and the ioasic code isn't initted when we need to frob some interrupt
64ba87ccc4Scgd  * bits.
65ba87ccc4Scgd  */
66ba87ccc4Scgd #define	DEC_3000_300_IOASIC_ADDR	KV(0x1a0000000)
67ba87ccc4Scgd 
68*b7b2b8a3Sthorpej const struct tc_slotdesc tc_3000_300_slots[] = {
69a5c74353Scgd 	{ KV(0x100000000), C(TC_3000_300_DEV_OPT0), },	/* 0 - opt slot 0 */
70a5c74353Scgd 	{ KV(0x120000000), C(TC_3000_300_DEV_OPT1), },	/* 1 - opt slot 1 */
718bf44847Snisimura 	{ KV(0x140000000), C(TC_3000_300_DEV_BOGUS), }, /* 2 - unused */
728bf44847Snisimura 	{ KV(0x160000000), C(TC_3000_300_DEV_BOGUS), }, /* 3 - unused */
738bf44847Snisimura 	{ KV(0x180000000), C(TC_3000_300_DEV_BOGUS), },	/* 4 - TCDS ASIC */
748bf44847Snisimura 	{ KV(0x1a0000000), C(TC_3000_300_DEV_BOGUS), }, /* 5 - IOCTL ASIC */
758bf44847Snisimura 	{ KV(0x1c0000000), C(TC_3000_300_DEV_BOGUS), }, /* 6 - CXTurbo */
76dd5a5290Scgd };
77*b7b2b8a3Sthorpej const int tc_3000_300_nslots = __arraycount(tc_3000_300_slots);
78dd5a5290Scgd 
79*b7b2b8a3Sthorpej const struct tc_builtin tc_3000_300_builtins[] = {
808bf44847Snisimura 	{ "PMAGB-BA",	6, 0x02000000, C(TC_3000_300_DEV_CXTURBO),	},
818bf44847Snisimura 	{ "FLAMG-IO",	5, 0x00000000, C(TC_3000_300_DEV_IOASIC),	},
828bf44847Snisimura 	{ "PMAZ-DS ",	4, 0x00000000, C(TC_3000_300_DEV_TCDS),		},
83dd5a5290Scgd };
84*b7b2b8a3Sthorpej const int tc_3000_300_nbuiltins = __arraycount(tc_3000_300_builtins);
85dd5a5290Scgd 
86*b7b2b8a3Sthorpej static struct tcintr {
8702cdf4d2Sdsl 	int	(*tci_func)(void *);
88a5c74353Scgd 	void	*tci_arg;
89b0ce38fdSthorpej 	struct evcnt tci_evcnt;
90a5c74353Scgd } tc_3000_300_intr[TC_3000_300_NCOOKIES];
91dd5a5290Scgd 
92dd5a5290Scgd void
tc_3000_300_intr_setup(void)93eacc5f97Smatt tc_3000_300_intr_setup(void)
94dd5a5290Scgd {
95eacc5f97Smatt 	volatile uint32_t *imskp;
96b0ce38fdSthorpej 	char *cp;
97a5c74353Scgd 	u_long i;
98dd5a5290Scgd 
99a5c74353Scgd 	/*
100ba87ccc4Scgd 	 * Disable all interrupts that we can (can't disable builtins).
101a5c74353Scgd 	 */
102eacc5f97Smatt 	imskp = (volatile uint32_t *)(DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK);
103ba87ccc4Scgd 	*imskp &= ~(IOASIC_INTR_300_OPT0 | IOASIC_INTR_300_OPT1);
104a5c74353Scgd 
105a5c74353Scgd 	/*
106a5c74353Scgd 	 * Set up interrupt handlers.
107a5c74353Scgd 	 */
108a5c74353Scgd 	for (i = 0; i < TC_3000_300_NCOOKIES; i++) {
109a5c74353Scgd 	        tc_3000_300_intr[i].tci_func = tc_3000_300_intrnull;
110a5c74353Scgd 	        tc_3000_300_intr[i].tci_arg = (void *)i;
111b0ce38fdSthorpej 
1126f97a7c1Sthorpej 		cp = kmem_asprintf("slot %lu", i);
113b0ce38fdSthorpej 		evcnt_attach_dynamic(&tc_3000_300_intr[i].tci_evcnt,
114b0ce38fdSthorpej 		    EVCNT_TYPE_INTR, NULL, "tc", cp);
115dd5a5290Scgd 	}
116dd5a5290Scgd }
117dd5a5290Scgd 
118cffb5808Scgd const struct evcnt *
tc_3000_300_intr_evcnt(device_t tcadev,void * cookie)11950feb1fbSmatt tc_3000_300_intr_evcnt(device_t tcadev, void *cookie)
120cffb5808Scgd {
121b0ce38fdSthorpej 	u_long dev = (u_long)cookie;
122cffb5808Scgd 
123b0ce38fdSthorpej #ifdef DIAGNOSTIC
124b0ce38fdSthorpej 	/* XXX bounds-check cookie. */
125b0ce38fdSthorpej #endif
126b0ce38fdSthorpej 
127b0ce38fdSthorpej 	return (&tc_3000_300_intr[dev].tci_evcnt);
128cffb5808Scgd }
129cffb5808Scgd 
130dd5a5290Scgd void
tc_3000_300_intr_establish(device_t tcadev,void * cookie,tc_intrlevel_t level,int (* func)(void *),void * arg)13150feb1fbSmatt tc_3000_300_intr_establish(device_t tcadev, void *cookie, tc_intrlevel_t level, int (*func)(void *), void *arg)
132dd5a5290Scgd {
133eacc5f97Smatt 	volatile uint32_t *imskp;
134a5c74353Scgd 	u_long dev = (u_long)cookie;
135dd5a5290Scgd 
136dd5a5290Scgd #ifdef DIAGNOSTIC
137a5c74353Scgd 	/* XXX bounds-check cookie. */
138dd5a5290Scgd #endif
139dd5a5290Scgd 
140a5c74353Scgd 	if (tc_3000_300_intr[dev].tci_func != tc_3000_300_intrnull)
1415194c207Sthorpej 		panic("tc_3000_300_intr_establish: cookie %lu twice", dev);
142dd5a5290Scgd 
143d15aec95Sthorpej 	const int s = splhigh();
144d15aec95Sthorpej 
145d15aec95Sthorpej 	/* All TC systems are uniprocessors. */
146d15aec95Sthorpej 	KASSERT(CPU_IS_PRIMARY(curcpu()));
147d15aec95Sthorpej 	KASSERT(ncpu == 1);
148d15aec95Sthorpej 	curcpu()->ci_nintrhand++;
149d15aec95Sthorpej 
150a5c74353Scgd 	tc_3000_300_intr[dev].tci_func = func;
151a5c74353Scgd 	tc_3000_300_intr[dev].tci_arg = arg;
152dd5a5290Scgd 
153d15aec95Sthorpej 	splx(s);
154d15aec95Sthorpej 
155eacc5f97Smatt 	imskp = (volatile uint32_t *)(DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK);
156a5c74353Scgd 	switch (dev) {
157a5c74353Scgd 	case TC_3000_300_DEV_OPT0:
158ba87ccc4Scgd 		*imskp |= IOASIC_INTR_300_OPT0;
159a5c74353Scgd 		break;
160a5c74353Scgd 	case TC_3000_300_DEV_OPT1:
161ba87ccc4Scgd 		*imskp |= IOASIC_INTR_300_OPT1;
162a5c74353Scgd 		break;
163a5c74353Scgd 	default:
164a5c74353Scgd 		/* interrupts for builtins always enabled */
165a5c74353Scgd 		break;
166a5c74353Scgd 	}
167dd5a5290Scgd }
168dd5a5290Scgd 
169dd5a5290Scgd void
tc_3000_300_intr_disestablish(device_t tcadev,void * cookie)17050feb1fbSmatt tc_3000_300_intr_disestablish(device_t tcadev, void *cookie)
171dd5a5290Scgd {
172eacc5f97Smatt 	volatile uint32_t *imskp;
173a5c74353Scgd 	u_long dev = (u_long)cookie;
174dd5a5290Scgd 
175dd5a5290Scgd #ifdef DIAGNOSTIC
176a5c74353Scgd 	/* XXX bounds-check cookie. */
177dd5a5290Scgd #endif
178dd5a5290Scgd 
179a5c74353Scgd 	if (tc_3000_300_intr[dev].tci_func == tc_3000_300_intrnull)
1805194c207Sthorpej 		panic("tc_3000_300_intr_disestablish: cookie %lu bad intr",
181dd5a5290Scgd 		    dev);
182dd5a5290Scgd 
183eacc5f97Smatt 	imskp = (volatile uint32_t *)(DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK);
184a5c74353Scgd 	switch (dev) {
185a5c74353Scgd 	case TC_3000_300_DEV_OPT0:
186ba87ccc4Scgd 		*imskp &= ~IOASIC_INTR_300_OPT0;
187a5c74353Scgd 		break;
188a5c74353Scgd 	case TC_3000_300_DEV_OPT1:
189ba87ccc4Scgd 		*imskp &= ~IOASIC_INTR_300_OPT1;
190a5c74353Scgd 		break;
191a5c74353Scgd 	default:
192a5c74353Scgd 		/* interrupts for builtins always enabled */
193a5c74353Scgd 		break;
194a5c74353Scgd 	}
195dd5a5290Scgd 
196d15aec95Sthorpej 	const int s = splhigh();
197d15aec95Sthorpej 
198d15aec95Sthorpej 	curcpu()->ci_nintrhand--;
199d15aec95Sthorpej 
200a5c74353Scgd 	tc_3000_300_intr[dev].tci_func = tc_3000_300_intrnull;
201a5c74353Scgd 	tc_3000_300_intr[dev].tci_arg = (void *)dev;
202d15aec95Sthorpej 
203d15aec95Sthorpej 	splx(s);
204a5c74353Scgd }
205a5c74353Scgd 
206*b7b2b8a3Sthorpej static int
tc_3000_300_intrnull(void * val)207454af1c0Sdsl tc_3000_300_intrnull(void *val)
208a5c74353Scgd {
209a5c74353Scgd 
2100f09ed48Sprovos 	panic("tc_3000_300_intrnull: uncaught TC intr for cookie %ld",
211a5c74353Scgd 	    (u_long)val);
212dd5a5290Scgd }
213dd5a5290Scgd 
214dd5a5290Scgd void
tc_3000_300_iointr(void * arg,unsigned long vec)215454af1c0Sdsl tc_3000_300_iointr(void *arg, unsigned long vec)
216dd5a5290Scgd {
217eacc5f97Smatt 	uint32_t tcir, ioasicir, ioasicimr;
2180cefc7efScgd 	int ifound;
219dd5a5290Scgd 
2201099504eSthorpej 	KERNEL_LOCK(1, NULL);
2211099504eSthorpej 
222dd5a5290Scgd #ifdef DIAGNOSTIC
223dd5a5290Scgd 	int s;
224dd5a5290Scgd 	if (vec != 0x800)
2259905bce8Scgd 		panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec);
226dd5a5290Scgd 	s = splhigh();
2272871f8c0Sthorpej 	if (s != ALPHA_PSL_IPL_IO_HI)
2280cefc7efScgd 		panic("INVALID ASSUMPTION: IPL %d, not %d", s,
2292871f8c0Sthorpej 		    ALPHA_PSL_IPL_IO_HI);
230dd5a5290Scgd 	splx(s);
231dd5a5290Scgd #endif
232dd5a5290Scgd 
233dd5a5290Scgd 	do {
234a5c74353Scgd 		tc_syncbus();
235dd5a5290Scgd 
23693d789f4Scgd 		/* find out what interrupts/errors occurred */
237eacc5f97Smatt 		tcir = *(volatile uint32_t *)TC_3000_300_IR;
238eacc5f97Smatt 		ioasicir = *(volatile uint32_t *)
239c6641d91Snisimura 		    (DEC_3000_300_IOASIC_ADDR + IOASIC_INTR);
240eacc5f97Smatt 		ioasicimr = *(volatile uint32_t *)
241c6641d91Snisimura 		    (DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK);
242a5c74353Scgd 		tc_mb();
24393d789f4Scgd 
244cb0eb158Scgd 		/* Ignore interrupts that aren't enabled out. */
245cb0eb158Scgd 		ioasicir &= ioasicimr;
246cb0eb158Scgd 
24793d789f4Scgd 		/* clear the interrupts/errors we found. */
248eacc5f97Smatt 		*(volatile uint32_t *)TC_3000_300_IR = tcir;
249a5c74353Scgd 		/* XXX can't clear TC option slot interrupts here? */
250a5c74353Scgd 		tc_wmb();
25193d789f4Scgd 
252dd5a5290Scgd 		ifound = 0;
253666c7f6fScgd 
254b0ce38fdSthorpej #define	INCRINTRCNT(slot)	tc_3000_300_intr[slot].tci_evcnt.ev_count++
255666c7f6fScgd 
256a5c74353Scgd #define	CHECKINTR(slot, flag)						\
257a5c74353Scgd 		if (flag) {						\
258dd5a5290Scgd 			ifound = 1;					\
259666c7f6fScgd 			INCRINTRCNT(slot);				\
260a5c74353Scgd 			(*tc_3000_300_intr[slot].tci_func)		\
261a5c74353Scgd 			    (tc_3000_300_intr[slot].tci_arg);		\
262dd5a5290Scgd 		}
263dd5a5290Scgd 		/* Do them in order of priority; highest slot # first. */
264ba87ccc4Scgd 		CHECKINTR(TC_3000_300_DEV_CXTURBO,
265ba87ccc4Scgd 		    tcir & TC_3000_300_IR_CXTURBO);
266666c7f6fScgd 		CHECKINTR(TC_3000_300_DEV_IOASIC,
267666c7f6fScgd 		    (tcir & TC_3000_300_IR_IOASIC) &&
268666c7f6fScgd 	            (ioasicir & ~(IOASIC_INTR_300_OPT1|IOASIC_INTR_300_OPT0)));
269ba87ccc4Scgd 		CHECKINTR(TC_3000_300_DEV_TCDS, tcir & TC_3000_300_IR_TCDS);
270ba87ccc4Scgd 		CHECKINTR(TC_3000_300_DEV_OPT1,
271ba87ccc4Scgd 		    ioasicir & IOASIC_INTR_300_OPT1);
272cb0eb158Scgd 		CHECKINTR(TC_3000_300_DEV_OPT0,
273cb0eb158Scgd 		    ioasicir & IOASIC_INTR_300_OPT0);
274dd5a5290Scgd #undef CHECKINTR
275dd5a5290Scgd 
276dd5a5290Scgd #ifdef DIAGNOSTIC
277dd5a5290Scgd #define PRINTINTR(msg, bits)						\
278ba87ccc4Scgd 	if (tcir & bits)						\
2798d9699acSchristos 		printf(msg);
280dd5a5290Scgd 		PRINTINTR("BCache tag parity error\n",
281dd5a5290Scgd 		    TC_3000_300_IR_BCTAGPARITY);
282dd5a5290Scgd 		PRINTINTR("TC overrun error\n", TC_3000_300_IR_TCOVERRUN);
283dd5a5290Scgd 		PRINTINTR("TC I/O timeout\n", TC_3000_300_IR_TCTIMEOUT);
284dd5a5290Scgd 		PRINTINTR("Bcache parity error\n",
285dd5a5290Scgd 		    TC_3000_300_IR_BCACHEPARITY);
286dd5a5290Scgd 		PRINTINTR("Memory parity error\n", TC_3000_300_IR_MEMPARITY);
287dd5a5290Scgd #undef PRINTINTR
288dd5a5290Scgd #endif
289dd5a5290Scgd 	} while (ifound);
2901099504eSthorpej 
2911099504eSthorpej 	KERNEL_UNLOCK_ONE(NULL);
292dd5a5290Scgd }
293ab947090Sbriggs 
29431a77e61Sdrochner #if NWSDISPLAY > 0
295ab947090Sbriggs /*
296ab947090Sbriggs  * tc_3000_300_fb_cnattach --
297ab947090Sbriggs  *	Attempt to map the CTB output device to a slot and attach the
298ab947090Sbriggs  * framebuffer as the output side of the console.
299ab947090Sbriggs  */
300ab947090Sbriggs int
tc_3000_300_fb_cnattach(uint64_t turbo_slot)301eacc5f97Smatt tc_3000_300_fb_cnattach(uint64_t turbo_slot)
302ab947090Sbriggs {
303eacc5f97Smatt 	uint32_t output_slot;
304ab947090Sbriggs 
305ab947090Sbriggs 	output_slot = turbo_slot & 0xffffffff;
306ab947090Sbriggs 
307ab947090Sbriggs 	if (output_slot >= tc_3000_300_nslots) {
308f6f48ed7Sdrochner 		return EINVAL;
309ab947090Sbriggs 	}
310ab947090Sbriggs 
311ab947090Sbriggs 	if (output_slot == 0) {
31267be755fSbriggs #if NSFB > 0
313ab947090Sbriggs 		sfb_cnattach(KV(0x1c0000000) + 0x02000000);
31467be755fSbriggs 		return 0;
315f6f48ed7Sdrochner #else
316f6f48ed7Sdrochner 		return ENXIO;
31767be755fSbriggs #endif
318ab947090Sbriggs 	}
319ab947090Sbriggs 
320ab947090Sbriggs 	return tc_fb_cnattach(tc_3000_300_slots[output_slot-1].tcs_addr);
321ab947090Sbriggs }
32231a77e61Sdrochner #endif /* NWSDISPLAY */
323