1/* $NetBSD: tc_3000_500.c,v 1.38 2021/05/07 16:58:34 thorpej Exp $ */
2
3/*
4 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Chris G. Demetriou
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22 *  School of Computer Science
23 *  Carnegie Mellon University
24 *  Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
31
32__KERNEL_RCSID(0, "$NetBSD: tc_3000_500.c,v 1.38 2021/05/07 16:58:34 thorpej Exp $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/device.h>
37#include <sys/kmem.h>
38#include <sys/cpu.h>
39
40#include <machine/autoconf.h>
41#include <machine/pte.h>
42#include <machine/rpb.h>
43
44#include <dev/tc/tcvar.h>
45#include <alpha/tc/tc_conf.h>
46#include <alpha/tc/tc_3000_500.h>
47
48#include "wsdisplay.h"
49#include "sfb.h"
50
51#if NSFB > 0
52extern int	sfb_cnattach(tc_addr_t);
53#endif
54
55static int	tc_3000_500_intrnull(void *);
56
57#define C(x)	((void *)(u_long)x)
58#define	KV(x)	(ALPHA_PHYS_TO_K0SEG(x))
59
60const struct tc_slotdesc tc_3000_500_slots[] = {
61	{ KV(0x100000000), C(TC_3000_500_DEV_OPT0), },	/* 0 - opt slot 0 */
62	{ KV(0x120000000), C(TC_3000_500_DEV_OPT1), },	/* 1 - opt slot 1 */
63	{ KV(0x140000000), C(TC_3000_500_DEV_OPT2), },	/* 2 - opt slot 2 */
64	{ KV(0x160000000), C(TC_3000_500_DEV_OPT3), },	/* 3 - opt slot 3 */
65	{ KV(0x180000000), C(TC_3000_500_DEV_OPT4), },	/* 4 - opt slot 4 */
66	{ KV(0x1a0000000), C(TC_3000_500_DEV_OPT5), },	/* 5 - opt slot 5 */
67	{ KV(0x1c0000000), C(TC_3000_500_DEV_BOGUS), },	/* 6 - TCDS ASIC */
68	{ KV(0x1e0000000), C(TC_3000_500_DEV_BOGUS), },	/* 7 - IOCTL ASIC */
69};
70const int tc_3000_500_nslots = __arraycount(tc_3000_500_slots);
71
72const struct tc_builtin tc_3000_500_graphics_builtins[] = {
73	{ "FLAMG-IO",	7, 0x00000000, C(TC_3000_500_DEV_IOASIC),	},
74	{ "PMAGB-BA",	7, 0x02000000, C(TC_3000_500_DEV_CXTURBO),	},
75	{ "PMAZ-DS ",	6, 0x00000000, C(TC_3000_500_DEV_TCDS),		},
76};
77const int tc_3000_500_graphics_nbuiltins =
78    __arraycount(tc_3000_500_graphics_builtins);
79
80const struct tc_builtin tc_3000_500_nographics_builtins[] = {
81	{ "FLAMG-IO",	7, 0x00000000, C(TC_3000_500_DEV_IOASIC),	},
82	{ "PMAZ-DS ",	6, 0x00000000, C(TC_3000_500_DEV_TCDS),		},
83};
84const int tc_3000_500_nographics_nbuiltins =
85    __arraycount(tc_3000_500_nographics_builtins);
86
87static const uint32_t tc_3000_500_intrbits[TC_3000_500_NCOOKIES] = {
88	TC_3000_500_IR_OPT0,
89	TC_3000_500_IR_OPT1,
90	TC_3000_500_IR_OPT2,
91	TC_3000_500_IR_OPT3,
92	TC_3000_500_IR_OPT4,
93	TC_3000_500_IR_OPT5,
94	TC_3000_500_IR_TCDS,
95	TC_3000_500_IR_IOASIC,
96	TC_3000_500_IR_CXTURBO,
97};
98
99static struct tcintr {
100	int	(*tci_func)(void *);
101	void	*tci_arg;
102	struct evcnt tci_evcnt;
103} tc_3000_500_intr[TC_3000_500_NCOOKIES];
104
105static uint32_t tc_3000_500_imask; /* intrs we want to ignore; mirrors IMR. */
106
107void
108tc_3000_500_intr_setup(void)
109{
110	char *cp;
111	u_long i;
112
113	/*
114	 * Disable all slot interrupts.  Note that this cannot
115	 * actually disable CXTurbo, TCDS, and IOASIC interrupts.
116	 */
117	tc_3000_500_imask = *(volatile uint32_t *)TC_3000_500_IMR_READ;
118	for (i = 0; i < TC_3000_500_NCOOKIES; i++)
119		tc_3000_500_imask |= tc_3000_500_intrbits[i];
120	*(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
121	tc_mb();
122
123	/*
124	 * Set up interrupt handlers.
125	 */
126	for (i = 0; i < TC_3000_500_NCOOKIES; i++) {
127		tc_3000_500_intr[i].tci_func = tc_3000_500_intrnull;
128		tc_3000_500_intr[i].tci_arg = (void *)i;
129
130		cp = kmem_asprintf("slot %lu", i);
131		evcnt_attach_dynamic(&tc_3000_500_intr[i].tci_evcnt,
132		    EVCNT_TYPE_INTR, NULL, "tc", cp);
133	}
134}
135
136const struct evcnt *
137tc_3000_500_intr_evcnt(device_t tcadev, void *cookie)
138{
139	u_long dev = (u_long)cookie;
140
141#ifdef DIAGNOSTIC
142	/* XXX bounds-check cookie. */
143#endif
144
145	return (&tc_3000_500_intr[dev].tci_evcnt);
146}
147
148void
149tc_3000_500_intr_establish(device_t tcadev, void *cookie, tc_intrlevel_t level, int (*func)(void *), void *arg)
150{
151	u_long dev = (u_long)cookie;
152
153#ifdef DIAGNOSTIC
154	/* XXX bounds-check cookie. */
155#endif
156
157	if (tc_3000_500_intr[dev].tci_func != tc_3000_500_intrnull)
158		panic("tc_3000_500_intr_establish: cookie %lu twice", dev);
159
160	const int s = splhigh();
161
162	/* All TC systems are uniprocessors. */
163	KASSERT(CPU_IS_PRIMARY(curcpu()));
164	KASSERT(ncpu == 1);
165	curcpu()->ci_nintrhand++;
166
167	tc_3000_500_intr[dev].tci_func = func;
168	tc_3000_500_intr[dev].tci_arg = arg;
169
170	splx(s);
171
172	tc_3000_500_imask &= ~tc_3000_500_intrbits[dev];
173	*(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
174	tc_mb();
175}
176
177void
178tc_3000_500_intr_disestablish(device_t tcadev, void *cookie)
179{
180	u_long dev = (u_long)cookie;
181
182#ifdef DIAGNOSTIC
183	/* XXX bounds-check cookie. */
184#endif
185
186	if (tc_3000_500_intr[dev].tci_func == tc_3000_500_intrnull)
187		panic("tc_3000_500_intr_disestablish: cookie %lu bad intr",
188		    dev);
189
190	tc_3000_500_imask |= tc_3000_500_intrbits[dev];
191	*(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
192	tc_mb();
193
194	const int s = splhigh();
195
196	curcpu()->ci_nintrhand--;
197
198	tc_3000_500_intr[dev].tci_func = tc_3000_500_intrnull;
199	tc_3000_500_intr[dev].tci_arg = (void *)dev;
200
201	splx(s);
202}
203
204static int
205tc_3000_500_intrnull(void *val)
206{
207
208	panic("tc_3000_500_intrnull: uncaught TC intr for cookie %ld",
209	    (u_long)val);
210}
211
212void
213tc_3000_500_iointr(void *arg, unsigned long vec)
214{
215	uint32_t ir;
216	int ifound;
217
218	KERNEL_LOCK(1, NULL);
219
220#ifdef DIAGNOSTIC
221	int s;
222	if (vec != 0x800)
223		panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec);
224	s = splhigh();
225	if (s != ALPHA_PSL_IPL_IO_HI)
226		panic("INVALID ASSUMPTION: IPL %d, not %d", s,
227		    ALPHA_PSL_IPL_IO_HI);
228	splx(s);
229#endif
230
231	do {
232		tc_syncbus();
233		ir = *(volatile uint32_t *)TC_3000_500_IR_CLEAR;
234
235		/* Ignore interrupts that we haven't enabled. */
236		ir &= ~(tc_3000_500_imask & 0x1ff);
237
238		ifound = 0;
239
240#define	INCRINTRCNT(slot)	tc_3000_500_intr[slot].tci_evcnt.ev_count++
241
242#define	CHECKINTR(slot)							\
243		if (ir & tc_3000_500_intrbits[slot]) {			\
244			ifound = 1;					\
245			INCRINTRCNT(slot);				\
246			(*tc_3000_500_intr[slot].tci_func)		\
247			    (tc_3000_500_intr[slot].tci_arg);		\
248		}
249		/* Do them in order of priority; highest slot # first. */
250		CHECKINTR(TC_3000_500_DEV_CXTURBO);
251		CHECKINTR(TC_3000_500_DEV_IOASIC);
252		CHECKINTR(TC_3000_500_DEV_TCDS);
253		CHECKINTR(TC_3000_500_DEV_OPT5);
254		CHECKINTR(TC_3000_500_DEV_OPT4);
255		CHECKINTR(TC_3000_500_DEV_OPT3);
256		CHECKINTR(TC_3000_500_DEV_OPT2);
257		CHECKINTR(TC_3000_500_DEV_OPT1);
258		CHECKINTR(TC_3000_500_DEV_OPT0);
259#undef CHECKINTR
260
261#ifdef DIAGNOSTIC
262#define PRINTINTR(msg, bits)						\
263	if (ir & bits)							\
264		printf(msg);
265		PRINTINTR("Second error occurred\n", TC_3000_500_IR_ERR2);
266		PRINTINTR("DMA buffer error\n", TC_3000_500_IR_DMABE);
267		PRINTINTR("DMA cross 2K boundary\n", TC_3000_500_IR_DMA2K);
268		PRINTINTR("TC reset in progress\n", TC_3000_500_IR_TCRESET);
269		PRINTINTR("TC parity error\n", TC_3000_500_IR_TCPAR);
270		PRINTINTR("DMA tag error\n", TC_3000_500_IR_DMATAG);
271		PRINTINTR("Single-bit error\n", TC_3000_500_IR_DMASBE);
272		PRINTINTR("Double-bit error\n", TC_3000_500_IR_DMADBE);
273		PRINTINTR("TC I/O timeout\n", TC_3000_500_IR_TCTIMEOUT);
274		PRINTINTR("DMA block too long\n", TC_3000_500_IR_DMABLOCK);
275		PRINTINTR("Invalid I/O address\n", TC_3000_500_IR_IOADDR);
276		PRINTINTR("DMA scatter/gather invalid\n", TC_3000_500_IR_DMASG);
277		PRINTINTR("Scatter/gather parity error\n",
278		    TC_3000_500_IR_SGPAR);
279#undef PRINTINTR
280#endif
281	} while (ifound);
282
283	KERNEL_UNLOCK_ONE(NULL);
284}
285
286#if NWSDISPLAY > 0
287/*
288 * tc_3000_500_fb_cnattach --
289 *	Attempt to map the CTB output device to a slot and attach the
290 * framebuffer as the output side of the console.
291 */
292int
293tc_3000_500_fb_cnattach(uint64_t turbo_slot)
294{
295	uint32_t output_slot;
296
297	output_slot = turbo_slot & 0xffffffff;
298
299	if (output_slot >= tc_3000_500_nslots) {
300		return EINVAL;
301	}
302
303	if (hwrpb->rpb_variation & SV_GRAPHICS) {
304		if (output_slot == 0) {
305#if NSFB > 0
306			sfb_cnattach(KV(0x1e0000000) + 0x02000000);
307			return 0;
308#else
309			return ENXIO;
310#endif
311		}
312	} else {
313		/*
314		 * Slots 0-2 in the tc_3000_500_slots array are only
315		 * on the 500 models that also have the CXTurbo
316		 * (500/800/900) and a total of 6 TC slots.  For the
317		 * 400/600/700, slots 0-2 are in table locations 3-5, so
318		 * offset the CTB slot by 3 to get the address in our table.
319		 */
320		output_slot += 3;
321	}
322	return tc_fb_cnattach(tc_3000_500_slots[output_slot-1].tcs_addr);
323}
324#endif /* NWSDISPLAY */
325
326#if 0
327/*
328 * tc_3000_500_ioslot --
329 *	Set the PBS bits for devices on the TC.
330 */
331void
332tc_3000_500_ioslot(uint32_t slot, uint32_t flags, int set)
333{
334	volatile uint32_t *iosp;
335	uint32_t ios;
336	int s;
337
338	iosp = (volatile uint32_t *)TC_3000_500_IOSLOT;
339	ios = *iosp;
340	flags <<= (slot * 3);
341	if (set)
342		ios |= flags;
343	else
344		ios &= ~flags;
345	s = splhigh();
346	*iosp = ios;
347	tc_mb();
348	splx(s);
349}
350#endif
351