xref: /netbsd-src/sys/arch/sgimips/dev/crime.c (revision 0151967ca65acd1f5e6e6f25d2d06af42f49415d)
1*0151967cSmrg /*	$NetBSD: crime.c,v 1.39 2021/04/26 17:07:17 mrg Exp $	*/
24a45886cSsoren 
34a45886cSsoren /*
423020fc3Ssekiya  * Copyright (c) 2004 Christopher SEKIYA
54a45886cSsoren  * Copyright (c) 2000 Soren S. Jorvang
64a45886cSsoren  * All rights reserved.
74a45886cSsoren  *
84a45886cSsoren  * Redistribution and use in source and binary forms, with or without
94a45886cSsoren  * modification, are permitted provided that the following conditions
104a45886cSsoren  * are met:
114a45886cSsoren  * 1. Redistributions of source code must retain the above copyright
124a45886cSsoren  *    notice, this list of conditions and the following disclaimer.
134a45886cSsoren  * 2. Redistributions in binary form must reproduce the above copyright
144a45886cSsoren  *    notice, this list of conditions and the following disclaimer in the
154a45886cSsoren  *    documentation and/or other materials provided with the distribution.
164a45886cSsoren  * 3. All advertising materials mentioning features or use of this software
174a45886cSsoren  *    must display the following acknowledgement:
184a45886cSsoren  *          This product includes software developed for the
1907147999Skeihan  *          NetBSD Project.  See http://www.NetBSD.org/ for
204a45886cSsoren  *          information about NetBSD.
214a45886cSsoren  * 4. The name of the author may not be used to endorse or promote products
224a45886cSsoren  *    derived from this software without specific prior written permission.
234a45886cSsoren  *
244a45886cSsoren  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
254a45886cSsoren  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
264a45886cSsoren  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
274a45886cSsoren  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
284a45886cSsoren  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
294a45886cSsoren  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
304a45886cSsoren  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
314a45886cSsoren  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
324a45886cSsoren  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
334a45886cSsoren  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
344a45886cSsoren  */
354a45886cSsoren 
364a45886cSsoren /*
374a45886cSsoren  * O2 CRIME
384a45886cSsoren  */
394a45886cSsoren 
40ed517291Slukem #include <sys/cdefs.h>
41*0151967cSmrg __KERNEL_RCSID(0, "$NetBSD: crime.c,v 1.39 2021/04/26 17:07:17 mrg Exp $");
42*0151967cSmrg 
43*0151967cSmrg #include "opt_ddb.h"
44ed517291Slukem 
454a45886cSsoren #include <sys/param.h>
464a45886cSsoren #include <sys/device.h>
474a45886cSsoren #include <sys/systm.h>
4823020fc3Ssekiya #include <sys/kernel.h>
49f0301095Syamt #include <sys/cpu.h>
504a45886cSsoren 
514a45886cSsoren #include <machine/locore.h>
524a45886cSsoren #include <machine/autoconf.h>
53cf10107dSdyoung #include <sys/bus.h>
5441ba2b7cSsoren #include <machine/intr.h>
55af0e157bSthorpej #include <machine/machtype.h>
5658a060c7Ssekiya #include <machine/sysconf.h>
574a45886cSsoren 
58b0cd3c80Stsutsui #include <sgimips/dev/crimevar.h>
594a45886cSsoren #include <sgimips/dev/crimereg.h>
6063b59c4dSsekiya #include <sgimips/mace/macevar.h>
614a45886cSsoren 
62*0151967cSmrg #if defined(DDB)
63*0151967cSmrg #include <machine/db_machdep.h>
64*0151967cSmrg #endif
65*0151967cSmrg 
664a45886cSsoren #include "locators.h"
674a45886cSsoren 
68e1beb9f8Stsutsui #define DISABLE_CRIME_WATCHDOG
6969a102c0Sjmcneill 
70f0b7a070Smacallan static int	crime_match(device_t, struct cfdata *, void *);
71f0b7a070Smacallan static void	crime_attach(device_t, device_t, void *);
7225bb3b0eSmrg static void	crime_mem_reset(void);
7325bb3b0eSmrg static void	crime_cpu_reset(void);
7425bb3b0eSmrg static void	crime_bus_reset(void);
7523020fc3Ssekiya void		crime_watchdog_reset(void);
7623020fc3Ssekiya void		crime_watchdog_disable(void);
7723347d39Smatt void		crime_intr(vaddr_t, uint32_t, uint32_t);
7823020fc3Ssekiya void		*crime_intr_establish(int, int, int (*)(void *), void *);
794a45886cSsoren 
8023020fc3Ssekiya static bus_space_tag_t crm_iot;
8123020fc3Ssekiya static bus_space_handle_t crm_ioh;
82b0cd3c80Stsutsui 
83f0b7a070Smacallan CFATTACH_DECL_NEW(crime, sizeof(struct crime_softc),
8489bf5a8fSthorpej     crime_match, crime_attach, NULL, NULL);
854a45886cSsoren 
86c21021e6Srafal #define CRIME_NINTR 32 	/* XXX */
87c21021e6Srafal 
88c21021e6Srafal struct {
89c21021e6Srafal 	int	(*func)(void *);
90c21021e6Srafal 	void	*arg;
91c21021e6Srafal } crime[CRIME_NINTR];
92c21021e6Srafal 
934a45886cSsoren static int
crime_match(device_t parent,struct cfdata * match,void * aux)94f0b7a070Smacallan crime_match(device_t parent, struct cfdata *match, void *aux)
954a45886cSsoren {
964a45886cSsoren 
974a45886cSsoren 	/*
984a45886cSsoren 	 * The CRIME is in the O2.
994a45886cSsoren 	 */
100af0e157bSthorpej 	if (mach_type == MACH_SGI_IP32)
1014578c8e4Stsutsui 		return 1;
102af0e157bSthorpej 
1034578c8e4Stsutsui 	return 0;
1044a45886cSsoren }
1054a45886cSsoren 
1064a45886cSsoren static void
crime_attach(device_t parent,device_t self,void * aux)107f0b7a070Smacallan crime_attach(device_t parent, device_t self, void *aux)
1084a45886cSsoren {
1094a45886cSsoren 	struct mainbus_attach_args *ma = aux;
11023347d39Smatt 	struct cpu_info * const ci = curcpu();
111f0b7a070Smacallan 	struct crime_softc *sc = device_private(self);
1124578c8e4Stsutsui 	uint64_t crm_id;
1134578c8e4Stsutsui 	uint64_t baseline, endline;
1144578c8e4Stsutsui 	uint32_t startctr, endctr, cps;
1154a45886cSsoren 
116*0151967cSmrg #if defined(DDB)
117*0151967cSmrg 	cpu_reset_address = crime_reboot;
118*0151967cSmrg #endif
119*0151967cSmrg 
120f0b7a070Smacallan 	sc->sc_dev = self;
121eb488f67Smacallan 	crm_iot = normal_memt;
122b0cd3c80Stsutsui 
123eb488f67Smacallan 	if (bus_space_map(crm_iot, ma->ma_addr, 0x1000,
12423020fc3Ssekiya 	    BUS_SPACE_MAP_LINEAR, &crm_ioh))
1254578c8e4Stsutsui 		panic("%s: can't map I/O space", __func__);
126b0cd3c80Stsutsui 
12723020fc3Ssekiya 	crm_id = bus_space_read_8(crm_iot, crm_ioh, CRIME_REV);
1284a45886cSsoren 
129c21021e6Srafal 	aprint_naive(": system ASIC");
130c21021e6Srafal 
13130d29f64Srafal 	switch ((crm_id & CRIME_ID_IDBITS) >> CRIME_ID_IDSHIFT) {
1320cff9e28Srafal 	case 0x0b:
1330cff9e28Srafal 		aprint_normal(": rev 1.5");
1340cff9e28Srafal 		break;
1350cff9e28Srafal 
1360cff9e28Srafal 	case 0x0a:
1370cff9e28Srafal 		if ((crm_id >> 32) == 0)
1380cff9e28Srafal 			aprint_normal(": rev 1.1");
1390cff9e28Srafal 		else if ((crm_id >> 32) == 1)
1400cff9e28Srafal 			aprint_normal(": rev 1.3");
1414a45886cSsoren 		else
1420cff9e28Srafal 			aprint_normal(": rev 1.4");
1430cff9e28Srafal 		break;
1444a45886cSsoren 
1450cff9e28Srafal 	case 0x00:
1460cff9e28Srafal 		aprint_normal(": Petty CRIME");
1470cff9e28Srafal 		break;
1480cff9e28Srafal 
1490cff9e28Srafal 	default:
1500cff9e28Srafal 		aprint_normal(": Unknown CRIME");
1510cff9e28Srafal 		break;
1520cff9e28Srafal 	}
1530cff9e28Srafal 
1544578c8e4Stsutsui 	aprint_normal(" (CRIME_ID: %" PRIu64 ")\n", crm_id);
155c21021e6Srafal 
15623020fc3Ssekiya 	/* reset CRIME CPU & memory error registers */
15725bb3b0eSmrg 	crime_mem_reset();
15825bb3b0eSmrg 	crime_cpu_reset();
15923020fc3Ssekiya 
160a311d7b2Stsutsui 	crime_watchdog_disable();
161a36263cdStsutsui 
16284857998Stsutsui #define CRIME_TIMER_FREQ	66666666	/* crime clock is 66.7MHz */
16323020fc3Ssekiya 
16484857998Stsutsui 	baseline = bus_space_read_8(crm_iot, crm_ioh, CRIME_TIME)
16584857998Stsutsui 	    & CRIME_TIME_MASK;
16684857998Stsutsui 	startctr = mips3_cp0_count_read();
16723020fc3Ssekiya 
16884857998Stsutsui 	/* read both cp0 and crime counters for 100ms */
16984857998Stsutsui 	do {
17084857998Stsutsui 		endline = bus_space_read_8(crm_iot, crm_ioh, CRIME_TIME)
17184857998Stsutsui 		    & CRIME_TIME_MASK;
17284857998Stsutsui 		endctr = mips3_cp0_count_read();
17384857998Stsutsui 	} while (endline - baseline < (CRIME_TIMER_FREQ / 10));
17484857998Stsutsui 
17584857998Stsutsui 	cps = (endctr - startctr) * 10;
17623347d39Smatt 	ci->ci_cpu_freq = cps;
17723347d39Smatt 	ci->ci_cctr_freq = cps;
17823347d39Smatt 	if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
17923347d39Smatt 		ci->ci_cpu_freq *= 2;
18023347d39Smatt 	ci->ci_cycles_per_hz = (cps + (hz / 2)) / hz;
18123347d39Smatt 	ci->ci_divisor_delay = (cps + (1000000 / 2)) / 1000000;
18223020fc3Ssekiya 
183b0cd3c80Stsutsui 	/* Turn on memory error and crime error interrupts.
184b0cd3c80Stsutsui 	   All others turned on as devices are registered. */
18523020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK,
186b0cd3c80Stsutsui 	    CRIME_INT_MEMERR |
187b0cd3c80Stsutsui 	    CRIME_INT_CRMERR |
188b0cd3c80Stsutsui 	    CRIME_INT_VICE |
189b0cd3c80Stsutsui 	    CRIME_INT_VID_OUT |
190b0cd3c80Stsutsui 	    CRIME_INT_VID_IN2 |
191b0cd3c80Stsutsui 	    CRIME_INT_VID_IN1);
19223020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTSTAT, 0);
19323020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_SOFTINT, 0);
19423020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_HARDINT, 0);
19558a060c7Ssekiya 
19623020fc3Ssekiya 	platform.bus_reset = crime_bus_reset;
19723020fc3Ssekiya 	platform.watchdog_reset = crime_watchdog_reset;
19823020fc3Ssekiya 	platform.watchdog_disable = crime_watchdog_disable;
19923020fc3Ssekiya 	platform.watchdog_enable = crime_watchdog_reset;
20023020fc3Ssekiya 	platform.intr_establish = crime_intr_establish;
20123020fc3Ssekiya 	platform.intr0 = crime_intr;
2024a45886cSsoren }
20341ba2b7cSsoren 
20441ba2b7cSsoren /*
205c21021e6Srafal  * XXX: sharing interrupts?
20641ba2b7cSsoren  */
20741ba2b7cSsoren 
20841ba2b7cSsoren void *
crime_intr_establish(int irq,int level,int (* func)(void *),void * arg)20923020fc3Ssekiya crime_intr_establish(int irq, int level, int (*func)(void *), void *arg)
21041ba2b7cSsoren {
2114578c8e4Stsutsui 
2128590eac4Ssekiya 	if (irq < 16)
21363b59c4dSsekiya 		return mace_intr_establish(irq, level, func, arg);
21463b59c4dSsekiya 
215c21021e6Srafal 	if (crime[irq].func != NULL)
216c21021e6Srafal 		return NULL;	/* panic("Cannot share CRIME interrupts!"); */
21741ba2b7cSsoren 
218c21021e6Srafal 	crime[irq].func = func;
219c21021e6Srafal 	crime[irq].arg = arg;
22041ba2b7cSsoren 
221b0cd3c80Stsutsui 	crime_intr_mask(irq);
222b0cd3c80Stsutsui 
223c21021e6Srafal 	return (void *)&crime[irq];
22441ba2b7cSsoren }
22541ba2b7cSsoren 
2260cff9e28Srafal void
crime_intr(vaddr_t pc,uint32_t status,uint32_t ipending)22723347d39Smatt crime_intr(vaddr_t pc, uint32_t status, uint32_t ipending)
22841ba2b7cSsoren {
2294578c8e4Stsutsui 	uint64_t crime_intmask;
2304578c8e4Stsutsui 	uint64_t crime_intstat;
2314578c8e4Stsutsui 	uint64_t crime_ipending;
2324578c8e4Stsutsui 	uint64_t address, stat;
23341ba2b7cSsoren 	int i;
23441ba2b7cSsoren 
23523020fc3Ssekiya 	crime_intmask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
23623020fc3Ssekiya 	crime_intstat = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTSTAT);
23723020fc3Ssekiya 	crime_ipending = (crime_intstat & crime_intmask);
23823020fc3Ssekiya 
2398590eac4Ssekiya 	if (crime_ipending & 0xffff)
2408590eac4Ssekiya 		mace_intr(crime_ipending & 0xffff);
24123020fc3Ssekiya 
24223020fc3Ssekiya 	if (crime_ipending & 0xffff0000) {
24323020fc3Ssekiya 	/*
24423020fc3Ssekiya 	 * CRIME interrupts for CPU and memory errors
24523020fc3Ssekiya 	 */
24623020fc3Ssekiya 		if (crime_ipending & CRIME_INT_MEMERR) {
2474578c8e4Stsutsui 			address = bus_space_read_8(crm_iot, crm_ioh,
2484578c8e4Stsutsui 			    CRIME_MEM_ERROR_ADDR);
2494578c8e4Stsutsui 			stat = bus_space_read_8(crm_iot, crm_ioh,
2504578c8e4Stsutsui 			    CRIME_MEM_ERROR_STAT);
2514578c8e4Stsutsui 			printf("crime: memory error address %" PRIu64
2524578c8e4Stsutsui 			    " status %" PRIu64 "\n", address << 2, stat);
25325bb3b0eSmrg 			crime_mem_reset();
25423020fc3Ssekiya 		}
25523020fc3Ssekiya 
25623020fc3Ssekiya 		if (crime_ipending & CRIME_INT_CRMERR) {
2574578c8e4Stsutsui 			stat = bus_space_read_8(crm_iot, crm_ioh,
2584578c8e4Stsutsui 			    CRIME_CPU_ERROR_STAT);
25925bb3b0eSmrg 			address = bus_space_read_8(crm_iot, crm_ioh,
26025bb3b0eSmrg 			    CRIME_CPU_ERROR_ADDR) << 2;
26125bb3b0eSmrg 			printf("crime: cpu error %" PRIu64 " at address %"
26225bb3b0eSmrg 			       PRIu64 "\n", stat, address);
26325bb3b0eSmrg 			crime_cpu_reset();
26423020fc3Ssekiya 		}
26523020fc3Ssekiya 	}
26623020fc3Ssekiya 
2671fcc2e99Sjmcneill 	crime_ipending &= ~0xffff;
26823020fc3Ssekiya 
2694578c8e4Stsutsui 	if (crime_ipending) {
2701fcc2e99Sjmcneill 		for (i = 16; i < CRIME_NINTR; i++) {
2714578c8e4Stsutsui 			if ((crime_ipending & (1 << i)) &&
2724578c8e4Stsutsui 			    crime[i].func != NULL)
27341ba2b7cSsoren 				(*crime[i].func)(crime[i].arg);
2740cff9e28Srafal 		}
27541ba2b7cSsoren 	}
2764578c8e4Stsutsui }
27741ba2b7cSsoren 
278b0cd3c80Stsutsui void
crime_intr_mask(unsigned int intr)279b0cd3c80Stsutsui crime_intr_mask(unsigned int intr)
280b0cd3c80Stsutsui {
2814578c8e4Stsutsui 	uint64_t mask;
282b0cd3c80Stsutsui 
28323020fc3Ssekiya 	mask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
284b0cd3c80Stsutsui 	mask |= (1 << intr);
28523020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK, mask);
286b0cd3c80Stsutsui }
28758a060c7Ssekiya 
28858a060c7Ssekiya void
crime_intr_unmask(unsigned int intr)2898590eac4Ssekiya crime_intr_unmask(unsigned int intr)
2908590eac4Ssekiya {
2914578c8e4Stsutsui 	uint64_t mask;
2928590eac4Ssekiya 
2938590eac4Ssekiya 	mask = bus_space_read_8(crm_iot, crm_ioh, CRIME_INTMASK);
2948590eac4Ssekiya 	mask &= ~(1 << intr);
2958590eac4Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_INTMASK, mask);
2968590eac4Ssekiya }
2978590eac4Ssekiya 
2988590eac4Ssekiya void
crime_mem_reset(void)29925bb3b0eSmrg crime_mem_reset(void)
30025bb3b0eSmrg {
30125bb3b0eSmrg 
30225bb3b0eSmrg 	bus_space_write_8(crm_iot, crm_ioh, CRIME_MEM_ERROR_STAT, 0);
30325bb3b0eSmrg }
30425bb3b0eSmrg 
30525bb3b0eSmrg void
crime_cpu_reset(void)30625bb3b0eSmrg crime_cpu_reset(void)
30758a060c7Ssekiya {
3084578c8e4Stsutsui 
30923020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_CPU_ERROR_STAT, 0);
31025bb3b0eSmrg }
31125bb3b0eSmrg 
31225bb3b0eSmrg void
crime_bus_reset(void)31325bb3b0eSmrg crime_bus_reset(void)
31425bb3b0eSmrg {
31525bb3b0eSmrg 
31625bb3b0eSmrg 	crime_mem_reset();
31725bb3b0eSmrg 	crime_cpu_reset();
31858a060c7Ssekiya }
31958a060c7Ssekiya 
32023020fc3Ssekiya void
crime_watchdog_reset(void)32123020fc3Ssekiya crime_watchdog_reset(void)
32223020fc3Ssekiya {
3234578c8e4Stsutsui 
324e1beb9f8Stsutsui #ifdef DISABLE_CRIME_WATCHDOG
32569a102c0Sjmcneill 	bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
32669a102c0Sjmcneill #else
32723020fc3Ssekiya 	/* enable watchdog timer, clear it */
32823020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh,
32923020fc3Ssekiya 		CRIME_CONTROL, CRIME_CONTROL_DOG_ENABLE);
33023020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
33169a102c0Sjmcneill #endif
33223020fc3Ssekiya }
33323020fc3Ssekiya 
33423020fc3Ssekiya void
crime_watchdog_disable(void)33523020fc3Ssekiya crime_watchdog_disable(void)
33623020fc3Ssekiya {
3374578c8e4Stsutsui 	uint64_t reg;
33823020fc3Ssekiya 
33923020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_WATCHDOG, 0);
34023020fc3Ssekiya 	reg = bus_space_read_8(crm_iot, crm_ioh, CRIME_CONTROL)
34123020fc3Ssekiya 	    & ~CRIME_CONTROL_DOG_ENABLE;
34223020fc3Ssekiya 	bus_space_write_8(crm_iot, crm_ioh, CRIME_CONTROL, reg);
34323020fc3Ssekiya }
344c65071e6Smacallan 
345c65071e6Smacallan void
crime_reboot(void)3464578c8e4Stsutsui crime_reboot(void)
347c65071e6Smacallan {
348c65071e6Smacallan 
349c65071e6Smacallan 	bus_space_write_8(crm_iot, crm_ioh,  CRIME_CONTROL,
350c65071e6Smacallan 	    CRIME_CONTROL_HARD_RESET);
3514578c8e4Stsutsui 	for (;;)
3524578c8e4Stsutsui 		;
353c65071e6Smacallan }
354