1/*	$NetBSD: imc.c,v 1.31 2011/06/30 20:09:35 wiz Exp $	*/
2
3/*
4 * Copyright (c) 2001 Rafal K. Boni
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__KERNEL_RCSID(0, "$NetBSD: imc.c,v 1.31 2011/06/30 20:09:35 wiz Exp $");
32
33#include <sys/param.h>
34#include <sys/device.h>
35#include <sys/systm.h>
36
37#include <machine/cpu.h>
38#include <machine/locore.h>
39#include <machine/autoconf.h>
40#include <sys/bus.h>
41#include <machine/machtype.h>
42#include <machine/sysconf.h>
43
44#include <sgimips/dev/imcreg.h>
45#include <sgimips/dev/imcvar.h>
46
47#include <sgimips/gio/giovar.h>
48
49#include "locators.h"
50
51struct imc_softc {
52	struct device sc_dev;
53
54	bus_space_tag_t iot;
55	bus_space_handle_t ioh;
56
57	int eisa_present;
58};
59
60static int	imc_match(struct device *, struct cfdata *, void *);
61static void	imc_attach(struct device *, struct device *, void *);
62static int	imc_print(void *, const char *);
63static void	imc_bus_reset(void);
64static void	imc_bus_error(vaddr_t, uint32_t, uint32_t);
65static void	imc_watchdog_reset(void);
66static void	imc_watchdog_disable(void);
67static void	imc_watchdog_enable(void);
68
69CFATTACH_DECL(imc, sizeof(struct imc_softc),
70    imc_match, imc_attach, NULL, NULL);
71
72struct imc_attach_args {
73	const char* iaa_name;
74
75	bus_space_tag_t iaa_st;
76	bus_space_handle_t iaa_sh;
77
78/* ? */
79	long	iaa_offset;
80	int	iaa_intr;
81#if 0
82	int	iaa_stride;
83#endif
84};
85
86int imc_gio64_arb_config(int, uint32_t);
87
88struct imc_softc isc;
89
90static int
91imc_match(struct device *parent, struct cfdata *match, void *aux)
92{
93
94	if ((mach_type == MACH_SGI_IP22) || (mach_type == MACH_SGI_IP20))
95		return 1;
96
97	return 0;
98}
99
100static void
101imc_attach(struct device *parent, struct device *self, void *aux)
102{
103	uint32_t reg;
104	struct imc_attach_args iaa;
105	struct mainbus_attach_args *ma = aux;
106	uint32_t sysid;
107
108	isc.iot = SGIMIPS_BUS_SPACE_HPC;
109	if (bus_space_map(isc.iot, ma->ma_addr, 0,
110	    BUS_SPACE_MAP_LINEAR, &isc.ioh))
111		panic("imc_attach: could not allocate memory\n");
112
113	platform.bus_reset = imc_bus_reset;
114	platform.watchdog_reset = imc_watchdog_reset;
115	platform.watchdog_disable = imc_watchdog_disable;
116	platform.watchdog_enable = imc_watchdog_enable;
117
118	sysid = bus_space_read_4(isc.iot, isc.ioh, IMC_SYSID);
119
120	/* EISA exists on IP22 only */
121	if (mach_subtype == MACH_SGI_IP22_FULLHOUSE)
122		isc.eisa_present = (sysid & IMC_SYSID_HAVEISA);
123	else
124		isc.eisa_present = 0;
125
126	printf(": revision %d", (sysid & IMC_SYSID_REVMASK));
127
128	if (isc.eisa_present)
129		printf(", EISA bus present");
130
131	printf("\n");
132
133	/* Clear CPU/GIO error status registers to clear any leftover bits. */
134	imc_bus_reset();
135
136	/* Hook the bus error handler into the ISR */
137	platform.intr4 = imc_bus_error;
138
139	/*
140	 * Enable parity reporting on GIO/main memory transactions.
141	 * Disable parity checking on CPU bus transactions (as turning
142	 * it on seems to cause spurious bus errors), but enable parity
143	 * checking on CPU reads from main memory (note that this bit
144	 * has the opposite sense... Turning it on turns the checks off!).
145	 * Finally, turn on interrupt writes to the CPU from the MC.
146	 */
147	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0);
148	reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
149	reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA);
150	bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg);
151
152	/* Setup the MC write buffer depth */
153	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL1);
154	reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13;
155
156	/*
157	 * Force endianness on the onboard HPC and both slots.
158	 * This should be safe for Fullhouse, but leave it conditional
159	 * for now.
160	 */
161	if (mach_type == MACH_SGI_IP20 || (mach_type == MACH_SGI_IP22 &&
162	    mach_subtype == MACH_SGI_IP22_GUINNESS)) {
163		reg |=  IMC_CPUCTRL1_HPCFX;
164		reg |=  IMC_CPUCTRL1_EXP0FX;
165		reg |=  IMC_CPUCTRL1_EXP1FX;
166		reg &= ~IMC_CPUCTRL1_HPCLITTLE;
167		reg &= ~IMC_CPUCTRL1_EXP0LITTLE;
168		reg &= ~IMC_CPUCTRL1_EXP1LITTLE;
169	}
170	bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL1, reg);
171
172
173	/*
174	 * Set GIO64 arbitrator configuration register:
175	 *
176	 * Preserve PROM-set graphics-related bits, as they seem to depend
177	 * on the graphics variant present and I'm not sure how to figure
178	 * that out or 100% sure what the correct settings are for each.
179	 */
180	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_GIO64ARB);
181	reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST);
182
183	/* Rest of settings are machine/board dependent */
184	if (mach_type == MACH_SGI_IP20) {
185		reg |=   IMC_GIO64ARB_ONEGIO;
186	        reg |=  (IMC_GIO64ARB_EXP0RT	| IMC_GIO64ARB_EXP1RT);
187		reg |=  (IMC_GIO64ARB_EXP0MST	| IMC_GIO64ARB_EXP1MST);
188		reg &= ~(IMC_GIO64ARB_HPC64	|
189			 IMC_GIO64ARB_HPCEXP64	| IMC_GIO64ARB_EISA64 |
190			 IMC_GIO64ARB_EXP064	| IMC_GIO64ARB_EXP164 |
191			 IMC_GIO64ARB_EXP0PIPE	| IMC_GIO64ARB_EXP1PIPE);
192	} else {
193		/*
194		 * GIO64 invariant for all IP22 platforms: one GIO bus,
195		 * HPC1 @ 64
196		 */
197		reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64;
198
199		switch (mach_subtype) {
200		case MACH_SGI_IP22_GUINNESS:
201			/* XXX is MST mutually exclusive? */
202	        	reg |=  (IMC_GIO64ARB_EXP0RT	| IMC_GIO64ARB_EXP1RT);
203			reg |=  (IMC_GIO64ARB_EXP0MST	| IMC_GIO64ARB_EXP1MST);
204
205			/* EISA can bus-master, is 64-bit */
206			reg |= (IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64);
207			break;
208
209		case MACH_SGI_IP22_FULLHOUSE:
210		/*
211		 * All Fullhouse boards have a 64-bit HPC2 and pipelined
212		 * EXP0 slot.
213		 */
214			reg |= (IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE);
215
216			if (mach_boardrev < 2) {
217			/* EXP0 realtime, EXP1 can master */
218				reg |= (IMC_GIO64ARB_EXP0RT |
219				    IMC_GIO64ARB_EXP1MST);
220			} else {
221				/* EXP1 pipelined as well, EISA masters */
222				reg |= (IMC_GIO64ARB_EXP1PIPE |
223				    IMC_GIO64ARB_EISAMST);
224			}
225			break;
226		}
227	}
228
229	bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg);
230
231	if (isc.eisa_present) {
232#if notyet
233		memset(&iaa, 0, sizeof(iaa));
234
235		config_found_ia(self, "eisabus", (void*)&iaa, eisabusprint);
236#endif
237	}
238
239	memset(&iaa, 0, sizeof(iaa));
240
241	config_found_ia(self, "giobus", (void*)&iaa, imc_print);
242
243	imc_watchdog_enable();
244}
245
246
247static int
248imc_print(void *aux, const char *name)
249{
250
251	if (name)
252		aprint_normal("gio at %s", name);
253
254	return UNCONF;
255}
256
257static void
258imc_bus_reset(void)
259{
260
261	bus_space_write_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT, 0);
262	bus_space_write_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT, 0);
263}
264
265static void
266imc_bus_error(vaddr_t pc, uint32_t status, uint32_t ipending)
267{
268
269	printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n",
270			bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT),
271			bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRADDR),
272			bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT),
273			bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRADDR) );
274	imc_bus_reset();
275}
276
277static void
278imc_watchdog_reset(void)
279{
280
281	bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0);
282}
283
284static void
285imc_watchdog_disable(void)
286{
287	uint32_t reg;
288
289	bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0);
290	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0);
291	reg &= ~(IMC_CPUCTRL0_WDOG);
292	bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg);
293}
294
295static void
296imc_watchdog_enable(void)
297{
298	uint32_t reg;
299
300	/* enable watchdog and clear it */
301	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0);
302	reg |= IMC_CPUCTRL0_WDOG;
303	bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg);
304	imc_watchdog_reset();
305}
306
307/* intended to be called from gio/gio.c only */
308int
309imc_gio64_arb_config(int slot, uint32_t flags)
310{
311	uint32_t reg;
312
313	/* GIO_SLOT_EXP1 is unusable on Fullhouse */
314	if (slot == GIO_SLOT_EXP1 && mach_subtype == MACH_SGI_IP22_FULLHOUSE)
315		return EINVAL;
316
317	/* GIO_SLOT_GFX is only usable on Fullhouse */
318	if (slot == GIO_SLOT_GFX && mach_subtype != MACH_SGI_IP22_FULLHOUSE)
319		return EINVAL;
320
321	/* GIO_SLOT_GFX is always pipelined */
322	if (slot == GIO_SLOT_GFX && (flags & GIO_ARB_NOPIPE))
323		return EINVAL;
324
325	/* IP20 does not support pipelining (XXX what about Indy?) */
326	if (((flags & GIO_ARB_PIPE) || (flags & GIO_ARB_NOPIPE)) &&
327	    mach_type == MACH_SGI_IP20)
328		return EINVAL;
329
330	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_GIO64ARB);
331
332	if (flags & GIO_ARB_RT) {
333		if (slot == GIO_SLOT_EXP0)
334			reg |= IMC_GIO64ARB_EXP0RT;
335		else if (slot == GIO_SLOT_EXP1)
336			reg |= IMC_GIO64ARB_EXP1RT;
337		else if (slot == GIO_SLOT_GFX)
338			reg |= IMC_GIO64ARB_GRXRT;
339	}
340
341	if (flags & GIO_ARB_MST) {
342		if (slot == GIO_SLOT_EXP0)
343			reg |= IMC_GIO64ARB_EXP0MST;
344		else if (slot == GIO_SLOT_EXP1)
345			reg |= IMC_GIO64ARB_EXP1MST;
346		else if (slot == GIO_SLOT_GFX)
347			reg |= IMC_GIO64ARB_GRXMST;
348	}
349
350	if (flags & GIO_ARB_PIPE) {
351		if (slot == GIO_SLOT_EXP0)
352			reg |= IMC_GIO64ARB_EXP0PIPE;
353		else if (slot == GIO_SLOT_EXP1)
354			reg |= IMC_GIO64ARB_EXP1PIPE;
355	}
356
357	if (flags & GIO_ARB_LB) {
358		if (slot == GIO_SLOT_EXP0)
359			reg &= ~IMC_GIO64ARB_EXP0RT;
360		else if (slot == GIO_SLOT_EXP1)
361			reg &= ~IMC_GIO64ARB_EXP1RT;
362		else if (slot == GIO_SLOT_GFX)
363			reg &= ~IMC_GIO64ARB_GRXRT;
364	}
365
366	if (flags & GIO_ARB_SLV) {
367		if (slot == GIO_SLOT_EXP0)
368			reg &= ~IMC_GIO64ARB_EXP0MST;
369		else if (slot == GIO_SLOT_EXP1)
370			reg &= ~IMC_GIO64ARB_EXP1MST;
371		else if (slot == GIO_SLOT_GFX)
372			reg &= ~IMC_GIO64ARB_GRXMST;
373	}
374
375	if (flags & GIO_ARB_NOPIPE) {
376		if (slot == GIO_SLOT_EXP0)
377			reg &= ~IMC_GIO64ARB_EXP0PIPE;
378		else if (slot == GIO_SLOT_EXP1)
379			reg &= ~IMC_GIO64ARB_EXP1PIPE;
380	}
381
382	if (flags & GIO_ARB_32BIT) {
383		if (slot == GIO_SLOT_EXP0)
384			reg &= ~IMC_GIO64ARB_EXP064;
385		else if (slot == GIO_SLOT_EXP1)
386			reg &= ~IMC_GIO64ARB_EXP164;
387	}
388
389	if (flags & GIO_ARB_64BIT) {
390		if (slot == GIO_SLOT_EXP0)
391			reg |= IMC_GIO64ARB_EXP064;
392		else if (slot == GIO_SLOT_EXP1)
393			reg |= IMC_GIO64ARB_EXP164;
394	}
395
396	if (flags & GIO_ARB_HPC2_32BIT)
397		reg &= ~IMC_GIO64ARB_HPCEXP64;
398
399	if (flags & GIO_ARB_HPC2_64BIT)
400		reg |= IMC_GIO64ARB_HPCEXP64;
401
402	bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg);
403
404	return 0;
405}
406
407/*
408 * According to chapter 19 of the "IRIX Device Driver Programmer's Guide",
409 * some GIO devices, which do not drive all data lines, may cause false
410 * memory read parity errors on the SysAD bus. The workaround is to disable
411 * parity checking.
412 */
413void
414imc_disable_sysad_parity(void)
415{
416	uint32_t reg;
417
418	if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22)
419		return;
420
421	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0);
422	reg |= IMC_CPUCTRL0_NCHKMEMPAR;
423	bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg);
424}
425
426void
427imc_enable_sysad_parity(void)
428{
429	uint32_t reg;
430
431	if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22)
432		return;
433
434	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0);
435	reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
436	bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg);
437}
438
439int
440imc_is_sysad_parity_enabled(void)
441{
442	uint32_t reg;
443
444	if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22)
445		return 0;
446
447	reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0);
448
449	return reg & IMC_CPUCTRL0_NCHKMEMPAR;
450}
451