1/*	$NetBSD: ka780.c,v 1.35 2024/02/04 18:47:27 andvar Exp $ */
2/*-
3 * Copyright (c) 1982, 1986, 1988 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 *	@(#)ka780.c	7.4 (Berkeley) 5/9/91
31 */
32
33/*
34 * 780-specific code.
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: ka780.c,v 1.35 2024/02/04 18:47:27 andvar Exp $");
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/bus.h>
43#include <sys/cpu.h>
44#include <sys/device.h>
45
46#include <machine/nexus.h>
47#include <machine/sid.h>
48#include <machine/clock.h>
49
50#include "ioconf.h"
51#include "locators.h"
52
53static	void ka780_memerr(void);
54static	int ka780_mchk(void *);
55static	void ka780_conf(void);
56static	void ka780_attach_cpu(device_t);
57static	int getsort(int type);
58
59static	int mem_sbi_match(device_t, cfdata_t, void *);
60static	void mem_sbi_attach(device_t, device_t, void *);
61
62CFATTACH_DECL_NEW(mem_sbi, sizeof(struct mem_softc),
63    mem_sbi_match, mem_sbi_attach, NULL, NULL);
64
65int
66mem_sbi_match(device_t parent, cfdata_t cf, void *aux)
67{
68	struct sbi_attach_args * const sa = aux;
69
70	if (cf->cf_loc[SBICF_TR] != sa->sa_nexnum &&
71	    cf->cf_loc[SBICF_TR] != SBICF_TR_DEFAULT)
72		return 0;
73
74	return getsort(sa->sa_type);
75}
76
77int
78getsort(int type)
79{
80	switch (type) {
81	case NEX_MEM4:
82	case NEX_MEM4I:
83	case NEX_MEM16:
84	case NEX_MEM16I:
85		return M780C;
86
87	case NEX_MEM64I:
88	case NEX_MEM64L:
89	case NEX_MEM64LI:
90	case NEX_MEM256I:
91	case NEX_MEM256L:
92	case NEX_MEM256LI:
93		return M780EL;
94
95	case NEX_MEM64U:
96	case NEX_MEM64UI:
97	case NEX_MEM256U:
98	case NEX_MEM256UI:
99		return M780EU;
100
101	default:
102		return M_NONE;
103	}
104}
105
106static const char * const ka780_devs[] = { "cpu", "sbi", NULL };
107
108/*
109 * Declaration of 780-specific calls.
110 */
111const struct cpu_dep ka780_calls = {
112	.cpu_mchk	= ka780_mchk,
113	.cpu_memerr	= ka780_memerr,
114	.cpu_conf	= ka780_conf,
115	.cpu_gettime	= generic_gettime,
116	.cpu_settime	= generic_settime,
117	.cpu_vups	= 2,	/* ~VUPS */
118	.cpu_scbsz	= 5,	/* SCB pages */
119	.cpu_devs	= ka780_devs,
120	.cpu_attach_cpu	= ka780_attach_cpu,
121};
122
123/*
124 * Memory controller register usage varies per controller.
125 */
126struct mcr780 {
127	int	mc_reg[4];
128};
129
130#define M780_ICRD	0x40000000	/* inhibit crd interrupts, in [2] */
131#define M780_HIER	0x20000000	/* high error rate, in reg[2] */
132#define M780_ERLOG	0x10000000	/* error log request, in reg[2] */
133/* on a 780, memory crd's occur only when bit 15 is set in the SBIER */
134/* register; bit 14 there is an error bit which we also clear */
135/* these bits are in the back of the ``red book'' (or in the VMS code) */
136
137#define M780C_INH(mcr)	\
138	((mcr)->mc_reg[2] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
139	    mtpr(0, PR_SBIER);
140#define M780C_ENA(mcr)	\
141	((mcr)->mc_reg[2] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
142#define M780C_ERR(mcr)	\
143	((mcr)->mc_reg[2] & (M780_ERLOG))
144
145#define M780C_SYN(mcr)	((mcr)->mc_reg[2] & 0xff)
146#define M780C_ADDR(mcr) (((mcr)->mc_reg[2] >> 8) & 0xfffff)
147
148#define M780EL_INH(mcr) \
149	((mcr)->mc_reg[2] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
150	    mtpr(0, PR_SBIER);
151#define M780EL_ENA(mcr) \
152	((mcr)->mc_reg[2] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
153#define M780EL_ERR(mcr) \
154	((mcr)->mc_reg[2] & (M780_ERLOG))
155
156#define M780EL_SYN(mcr)		((mcr)->mc_reg[2] & 0x7f)
157#define M780EL_ADDR(mcr)	(((mcr)->mc_reg[2] >> 11) & 0x1ffff)
158
159#define M780EU_INH(mcr) \
160	((mcr)->mc_reg[3] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
161	    mtpr(0, PR_SBIER);
162#define M780EU_ENA(mcr) \
163	((mcr)->mc_reg[3] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
164#define M780EU_ERR(mcr) \
165	((mcr)->mc_reg[3] & (M780_ERLOG))
166
167#define M780EU_SYN(mcr)		((mcr)->mc_reg[3] & 0x7f)
168#define M780EU_ADDR(mcr)	(((mcr)->mc_reg[3] >> 11) & 0x1ffff)
169
170/* enable crd interrupts */
171void
172mem_sbi_attach(device_t parent, device_t self, void *aux)
173{
174	struct sbi_attach_args * const sa = (struct sbi_attach_args *)aux;
175	struct mem_softc * const sc = device_private(self);
176	struct mcr780 * const mcr = (void *)sa->sa_ioh; /* XXX */
177
178	sc->sc_dev = self;
179	sc->sc_memaddr = (void *)sa->sa_ioh; /* XXX */
180	sc->sc_memtype = getsort(sa->sa_type);
181	sc->sc_memnr = sa->sa_type;
182
183	switch (sc->sc_memtype) {
184	case M780C:
185		aprint_normal(": standard");
186		M780C_ENA(mcr);
187		break;
188
189	case M780EL:
190		aprint_normal(": (el) ");
191		M780EL_ENA(mcr);
192		if (sc->sc_memnr != NEX_MEM64I && sc->sc_memnr != NEX_MEM256I)
193			break;
194
195	case M780EU:
196		aprint_normal(": (eu)");
197		M780EU_ENA(mcr);
198		break;
199	}
200	printf("\n");
201}
202
203#ifdef TRENDATA
204/*
205 * Figure out what chip to replace on Trendata boards.
206 * Assumes all your memory is Trendata or the non-Trendata
207 * memory never fails..
208 */
209const struct {
210	u_char	m_syndrome;
211	char	m_chip[4];
212} memlogtab[] = {
213	{0x01,	"C00"},	{0x02,	"C01"},	{0x04,	"C02"},	{0x08,	"C03"},
214	{0x10,	"C04"},	{0x19,	"L01"},	{0x1A,	"L02"},	{0x1C,	"L04"},
215	{0x1F,	"L07"},	{0x20,	"C05"},	{0x38,	"L00"},	{0x3B,	"L03"},
216	{0x3D,	"L05"},	{0x3E,	"L06"},	{0x40,	"C06"},	{0x49,	"L09"},
217	{0x4A,	"L10"},	{0x4c,	"L12"},	{0x4F,	"L15"},	{0x51,	"L17"},
218	{0x52,	"L18"},	{0x54,	"L20"},	{0x57,	"L23"},	{0x58,	"L24"},
219	{0x5B,	"L27"},	{0x5D,	"L29"},	{0x5E,	"L30"},	{0x68,	"L08"},
220	{0x6B,	"L11"},	{0x6D,	"L13"},	{0x6E,	"L14"},	{0x70,	"L16"},
221	{0x73,	"L19"},	{0x75,	"L21"},	{0x76,	"L22"},	{0x79,	"L25"},
222	{0x7A,	"L26"},	{0x7C,	"L28"},	{0x7F,	"L31"},	{0x80,	"C07"},
223	{0x89,	"U01"},	{0x8A,	"U02"},	{0x8C,	"U04"},	{0x8F,	"U07"},
224	{0x91,	"U09"},	{0x92,	"U10"},	{0x94,	"U12"},	{0x97,	"U15"},
225	{0x98,	"U16"},	{0x9B,	"U19"},	{0x9D,	"U21"},	{0x9E,	"U22"},
226	{0xA8,	"U00"},	{0xAB,	"U03"},	{0xAD,	"U05"},	{0xAE,	"U06"},
227	{0xB0,	"U08"},	{0xB3,	"U11"},	{0xB5,	"U13"},	{0xB6,	"U14"},
228	{0xB9,	"U17"},	{0xBA,	"U18"},	{0xBC,	"U20"},	{0xBF,	"U23"},
229	{0xC1,	"U25"},	{0xC2,	"U26"},	{0xC4,	"U28"},	{0xC7,	"U31"},
230	{0xE0,	"U24"},	{0xE3,	"U27"},	{0xE5,	"U29"},	{0xE6,	"U30"}
231};
232
233static void
234memlog(int m, struct mcr780 *mcr)
235{
236	int i;
237
238	for (i = 0; i < __arraycount(memlogtab); i++)
239		if ((u_char)(M780C_SYN(mcr)) == memlogtab[i].m_syndrome) {
240			printf(
241			    "mcr%d: replace %s chip in %s bank of memory"
242			    " board %d (0-15)\n",
243			    m, memlogtab[i].m_chip,
244			    (M780C_ADDR(mcr) & 0x8000) ? "upper" : "lower",
245			    (M780C_ADDR(mcr) >> 16));
246			return;
247		}
248	printf("mcr%d: multiple errors, not traceable\n", m);
249}
250#endif /* TRENDATA */
251
252/* log crd errors */
253void
254ka780_memerr(void)
255{
256	struct mem_softc *sc;
257	struct mcr780 *mcr;
258	int m;
259
260	for (m = 0; m < mem_cd.cd_ndevs; m++) {
261		sc = device_lookup_private(&mem_cd, m);
262		if (sc == NULL)
263			continue;
264		mcr = (struct mcr780 *)sc->sc_memaddr;
265		switch (sc->sc_memtype) {
266
267		case M780C:
268			if (M780C_ERR(mcr)) {
269				aprint_error_dev(sc->sc_dev,
270				    "soft ecc addr %x syn %x\n",
271				    M780C_ADDR(mcr), M780C_SYN(mcr));
272#ifdef TRENDATA
273				memlog(m, mcr);
274#endif
275				M780C_INH(mcr);
276			}
277			break;
278
279		case M780EL:
280			if (M780EL_ERR(mcr)) {
281				aprint_error_dev(sc->sc_dev,
282				    "soft ecc addr %x syn %x\n",
283				    M780EL_ADDR(mcr), M780EL_SYN(mcr));
284				M780EL_INH(mcr);
285			}
286			if (sc->sc_memnr != NEX_MEM64I &&
287			    sc->sc_memnr != NEX_MEM256I)
288				break;
289
290		case M780EU:
291			if (M780EU_ERR(mcr)) {
292				aprint_error_dev(sc->sc_dev,
293				    "soft ecc addr %x syn %x\n",
294				    M780EU_ADDR(mcr), M780EU_SYN(mcr));
295				M780EU_INH(mcr);
296			}
297			break;
298		}
299	}
300}
301
302const char mc780[][3] = {
303	"0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"
304};
305
306struct mc780frame {
307	int	mc8_bcnt;		/* byte count == 0x28 */
308	int	mc8_summary;		/* summary parameter (as above) */
309	int	mc8_cpues;		/* cpu error status */
310	int	mc8_upc;		/* micro pc */
311	int	mc8_vaviba;		/* va/viba register */
312	int	mc8_dreg;		/* d register */
313	int	mc8_tber0;		/* tbuf error reg 0 */
314	int	mc8_tber1;		/* tbuf error reg 1 */
315	int	mc8_timo;		/* timeout address divided by 4 */
316	int	mc8_parity;		/* parity */
317	int	mc8_sbier;		/* sbi error register */
318	int	mc8_pc;			/* trapped pc */
319	int	mc8_psl;		/* trapped psl */
320};
321
322int
323ka780_mchk(void *cmcf)
324{
325	struct mc780frame * const mcf = (struct mc780frame *)cmcf;
326	int type = mcf->mc8_summary;
327	int sbifs;
328
329	printf("machine check %x: %s%s\n", type, mc780[type&0xf],
330	    (type&0xf0) ? " abort" : " fault");
331	printf("\tcpues %x upc %x va/viba %x dreg %x tber %x %x\n",
332	   mcf->mc8_cpues, mcf->mc8_upc, mcf->mc8_vaviba,
333	   mcf->mc8_dreg, mcf->mc8_tber0, mcf->mc8_tber1);
334	sbifs = mfpr(PR_SBIFS);
335	printf("\ttimo %x parity %x sbier %x pc %x psl %x sbifs %x\n",
336	   mcf->mc8_timo*4, mcf->mc8_parity, mcf->mc8_sbier,
337	   mcf->mc8_pc, mcf->mc8_psl, sbifs);
338	/* THE FUNNY BITS IN THE FOLLOWING ARE FROM THE ``BLACK BOOK'' */
339	/* AND SHOULD BE PUT IN AN ``sbi.h'' */
340	mtpr(sbifs &~ 0x2000000, PR_SBIFS);
341	mtpr(mfpr(PR_SBIER) | 0x70c0, PR_SBIER);
342	return (MCHK_PANIC);
343}
344
345struct ka78x {
346	unsigned snr:12,
347		 plant:3,
348		 eco:8,
349		 v785:1,
350		 type:8;
351};
352
353void
354ka780_conf(void)
355{
356	/* Enable cache */
357	mtpr(0x200000, PR_SBIMT);
358
359}
360
361void
362ka780_attach_cpu(device_t self)
363{
364	struct ka78x * const ka78 = (void *)&vax_cpudata;
365
366	aprint_normal(": KA%s, S/N %d(%d), hardware ECO level %d(%d)\n",
367	    cpu_getmodel() + 7, ka78->snr, ka78->plant, ka78->eco >> 4, ka78->eco);
368	aprint_normal_dev(self, "4KB L1 cache");
369	if (mfpr(PR_ACCS) & 255) {
370		aprint_normal(", FPA present\n");
371		mtpr(0x8000, PR_ACCS);
372	} else
373		aprint_normal(", no FPA\n");
374
375}
376