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