Home | History | Annotate | Line # | Download | only in macppc
      1 /*	$NetBSD: pic_ohare.c,v 1.17 2021/03/05 07:15:53 rin Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2007 Michael Lorenz
      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  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: pic_ohare.c,v 1.17 2021/03/05 07:15:53 rin Exp $");
     31 
     32 #include "opt_interrupt.h"
     33 
     34 #include <sys/param.h>
     35 #include <sys/kmem.h>
     36 #include <sys/kernel.h>
     37 
     38 #include <machine/pio.h>
     39 
     40 #include <dev/ofw/openfirm.h>
     41 
     42 #include <machine/autoconf.h>
     43 #include <arch/powerpc/pic/picvar.h>
     44 
     45 static void ohare_enable_irq(struct pic_ops *, int, int);
     46 static void ohare_reenable_irq(struct pic_ops *, int, int);
     47 static void ohare_disable_irq(struct pic_ops *, int);
     48 static int  ohare_get_irq(struct pic_ops *, int);
     49 static void ohare_ack_irq(struct pic_ops *, int);
     50 static void ohare_establish_irq(struct pic_ops *, int, int, int);
     51 
     52 #define OHARE_NIRQ 32
     53 
     54 struct ohare_ops {
     55 	struct pic_ops pic;
     56 	uint32_t pending_events;
     57 	uint32_t enable_mask;
     58 	uint32_t level_mask;
     59 	uint32_t irqs[NIPL];			/* per priority level */
     60 	uint32_t priority_masks[OHARE_NIRQ];	/* per IRQ */
     61 };
     62 
     63 static struct ohare_ops *setup_ohare(uint32_t, int);
     64 static void setup_ohare2(uint32_t, int);
     65 static inline void ohare_read_events(struct ohare_ops *);
     66 
     67 #define INT_STATE_REG	((uint32_t)pic->pic_cookie + 0x20)
     68 #define INT_ENABLE_REG	((uint32_t)pic->pic_cookie + 0x24)
     69 #define INT_CLEAR_REG	((uint32_t)pic->pic_cookie + 0x28)
     70 #define INT_LEVEL_REG	((uint32_t)pic->pic_cookie + 0x2c)
     71 
     72 int init_ohare(void)
     73 {
     74 	uint32_t reg[5];
     75 	uint32_t obio_base;
     76 	uint32_t irq;
     77 	int      ohare, ohare2, is_gc = 0;
     78 
     79 	ohare = OF_finddevice("/bandit/ohare");
     80 	if (ohare == -1) {
     81 		ohare = OF_finddevice("/bandit/gc");
     82 		is_gc = 1;
     83 	}
     84 
     85 
     86 	if (OF_getprop(ohare, "assigned-addresses", reg, sizeof(reg)) != 20)
     87 		return FALSE;
     88 
     89 	obio_base = reg[2];
     90 	aprint_normal("found %s PIC at %08x\n",
     91 	    is_gc ? "Grand Central" : "ohare", obio_base);
     92 	setup_ohare(obio_base, is_gc);
     93 
     94 	/* look for 2nd ohare */
     95 	ohare2 = OF_finddevice("/bandit/pci106b,7");
     96 	if (ohare2 == -1)
     97 		goto done;
     98 
     99 	if (OF_getprop(ohare2, "assigned-addresses", reg, sizeof(reg)) < 20)
    100 		goto done;
    101 
    102 	if (OF_getprop(ohare2, "AAPL,interrupts", &irq, sizeof(irq)) < 4)
    103 		goto done;
    104 
    105 	obio_base = reg[2];
    106 	aprint_normal("found ohare2 PIC at %08x, irq %d\n", obio_base, irq);
    107 	setup_ohare2(obio_base, irq);
    108 done:
    109 	return TRUE;
    110 }
    111 
    112 static struct ohare_ops *
    113 setup_ohare(uint32_t addr, int is_gc)
    114 {
    115 	struct ohare_ops *ohare;
    116 	struct pic_ops *pic;
    117 	int i;
    118 
    119 	ohare = kmem_zalloc(sizeof(struct ohare_ops), KM_SLEEP);
    120 	pic = &ohare->pic;
    121 
    122 	pic->pic_numintrs = OHARE_NIRQ;
    123 	pic->pic_cookie = (void *)addr;
    124 	pic->pic_enable_irq = ohare_enable_irq;
    125 	pic->pic_reenable_irq = ohare_reenable_irq;
    126 	pic->pic_disable_irq = ohare_disable_irq;
    127 	pic->pic_get_irq = ohare_get_irq;
    128 	pic->pic_ack_irq = ohare_ack_irq;
    129 	pic->pic_establish_irq = ohare_establish_irq;
    130 	pic->pic_finish_setup = NULL;
    131 
    132 	if (is_gc) {
    133 
    134 		strcpy(pic->pic_name, "gc");
    135 	} else {
    136 
    137 		strcpy(pic->pic_name, "ohare");
    138 	}
    139 	ohare->level_mask = 0;
    140 
    141 	for (i = 0; i < OHARE_NIRQ; i++)
    142 		ohare->priority_masks[i] = 0;
    143 	for (i = 0; i < NIPL; i++)
    144 		ohare->irqs[i] = 0;
    145 	pic_add(pic);
    146 	ohare->pending_events = 0;
    147 	ohare->enable_mask = 0;
    148 	out32rb(INT_ENABLE_REG, 0);
    149 	out32rb(INT_CLEAR_REG, 0xffffffff);
    150 	return ohare;
    151 }
    152 
    153 static void
    154 setup_ohare2(uint32_t addr, int irq)
    155 {
    156 	struct ohare_ops *pic;
    157 
    158 	pic = setup_ohare(addr, 0);
    159 	strcpy(pic->pic.pic_name, "ohare2");
    160 	intr_establish_xname(irq, IST_LEVEL, IPL_HIGH, pic_handle_intr, pic,
    161 	    "ohara2");
    162 }
    163 
    164 static void
    165 ohare_enable_irq(struct pic_ops *pic, int irq, int type)
    166 {
    167 	struct ohare_ops *ohare = (struct ohare_ops *)pic;
    168 	uint32_t mask = 1 << irq;
    169 
    170 	ohare->enable_mask |= mask;
    171 	out32rb(INT_ENABLE_REG, ohare->enable_mask);
    172 }
    173 
    174 static void
    175 ohare_reenable_irq(struct pic_ops *pic, int irq, int type)
    176 {
    177 	struct ohare_ops *ohare = (struct ohare_ops *)pic;
    178 	uint32_t levels;
    179 	uint32_t mask = 1 << irq;
    180 
    181 	ohare->enable_mask |= mask;
    182 	out32rb(INT_ENABLE_REG, ohare->enable_mask);
    183 	levels = in32rb(INT_STATE_REG);
    184 	if (levels & mask) {
    185 		pic_mark_pending(pic->pic_intrbase + irq);
    186 		out32rb(INT_CLEAR_REG, mask);
    187 	}
    188 }
    189 
    190 static void
    191 ohare_disable_irq(struct pic_ops *pic, int irq)
    192 {
    193 	struct ohare_ops *ohare = (struct ohare_ops *)pic;
    194 	uint32_t mask = 1 << irq;
    195 
    196 	ohare->enable_mask &= ~mask;
    197 	out32rb(INT_ENABLE_REG, ohare->enable_mask);
    198 }
    199 
    200 static inline void
    201 ohare_read_events(struct ohare_ops *ohare)
    202 {
    203 	struct pic_ops *pic = &ohare->pic;
    204 	uint32_t irqs, events, levels;
    205 
    206 	irqs = in32rb(INT_STATE_REG);
    207 	events = irqs & ~ohare->level_mask;
    208 
    209 	levels = in32rb(INT_LEVEL_REG) & ohare->enable_mask;
    210 	events |= levels & ohare->level_mask;
    211 	out32rb(INT_CLEAR_REG, events | irqs);
    212 	ohare->pending_events |= events;
    213 
    214 #if 0
    215 	if (events != 0)
    216 		aprint_error("%s: ev %08x\n", __func__, events);
    217 #endif
    218 }
    219 
    220 static int
    221 ohare_get_irq(struct pic_ops *pic, int mode)
    222 {
    223 	struct ohare_ops *ohare = (struct ohare_ops *)pic;
    224 	uint32_t evt;
    225 	uint16_t prio;
    226 	int bit, mask, lvl;
    227 #ifdef OHARE_DEBUG
    228 	int bail = 0;
    229 #endif
    230 
    231 	if (ohare->pending_events == 0)
    232 		ohare_read_events(ohare);
    233 
    234 	if (ohare->pending_events == 0)
    235 		return 255;
    236 
    237 	bit = 31 - __builtin_clz(ohare->pending_events);
    238 	mask = 1 << bit;
    239 
    240 	if ((ohare->pending_events & ~mask) == 0) {
    241 
    242 		ohare->pending_events = 0;
    243 		return bit;
    244 	}
    245 
    246 	/*
    247 	 * if we get here we have more than one irq pending so return them
    248 	 * according to priority
    249 	 */
    250 
    251 	evt = ohare->pending_events & ~mask;
    252 	prio = ohare->priority_masks[bit];
    253 	while (evt != 0) {
    254 		bit = 31 - __builtin_clz(evt);
    255 		prio |= ohare->priority_masks[bit];
    256 		evt &= ~(1 << bit);
    257 #ifdef OHARE_DEBUG
    258 		bail++;
    259 		if (bail > 31)
    260 			panic("hanging in ohare_get_irq");
    261 #endif
    262 	}
    263 	lvl = 31 - __builtin_clz(prio);
    264 	evt = ohare->pending_events & ohare->irqs[lvl];
    265 
    266 	if (evt == 0) {
    267 #ifdef OHARE_DEBUG
    268 		aprint_verbose("%s: spurious interrupt\n",
    269 		    ohare->pic.pic_name);
    270 		printf("levels: %08x\n", in32rb(INT_LEVEL_REG));
    271 		printf("states: %08x\n", in32rb(INT_STATE_REG));
    272 		printf("enable: %08x\n", in32rb(INT_ENABLE_REG));
    273 		printf("events: %08x\n", ohare->pending_events);
    274 #endif
    275 		evt = ohare->pending_events;
    276 	}
    277 
    278 	bit = 31 - __builtin_clz(evt);
    279 	mask = 1 << bit;
    280 	ohare->pending_events &= ~mask;
    281 	return bit;
    282 }
    283 
    284 static void
    285 ohare_ack_irq(struct pic_ops *pic, int irq)
    286 {
    287 }
    288 
    289 static void
    290 ohare_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
    291 {
    292 	struct ohare_ops *ohare = (struct ohare_ops *)pic;
    293 	uint32_t mask = (1 << irq);
    294 	int realpri = uimin(NIPL, uimax(0, pri)), i;
    295 	uint32_t level = 1 << realpri;
    296 
    297 	KASSERT((irq >= 0) && (irq < OHARE_NIRQ));
    298 
    299 	if (type == IST_LEVEL) {
    300 
    301 		ohare->level_mask |= mask;
    302 	} else {
    303 
    304 		ohare->level_mask &= ~mask;
    305 	}
    306 	aprint_debug("mask: %08x\n", ohare->level_mask);
    307 	ohare->priority_masks[irq] = level;
    308 	for (i = 0; i < NIPL; i++)
    309 		ohare->irqs[i] = 0;
    310 
    311 	for (i = 0; i < OHARE_NIRQ; i++) {
    312 		if (ohare->priority_masks[i] == 0)
    313 			continue;
    314 		level = 31 - __builtin_clz(ohare->priority_masks[i]);
    315 		ohare->irqs[level] |= (1 << i);
    316 	}
    317 }
    318