Home | History | Annotate | Line # | Download | only in macppc
      1 /*	$NetBSD: pic_heathrow.c,v 1.12 2021/01/26 14:49:41 thorpej 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_heathrow.c,v 1.12 2021/01/26 14:49:41 thorpej 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 heathrow_enable_irq(struct pic_ops *, int, int);
     46 static void heathrow_reenable_irq(struct pic_ops *, int, int);
     47 static void heathrow_disable_irq(struct pic_ops *, int);
     48 static int  heathrow_get_irq(struct pic_ops *, int);
     49 static void heathrow_ack_irq(struct pic_ops *, int);
     50 static void heathrow_establish_irq(struct pic_ops *, int, int, int);
     51 
     52 struct heathrow_ops {
     53 	struct pic_ops pic;
     54 	uint32_t pending_events_h;
     55 	uint32_t pending_events_l;
     56 	uint32_t enable_mask_h;
     57 	uint32_t enable_mask_l;
     58 	uint32_t level_mask_h;
     59 	uint32_t level_mask_l;
     60 };
     61 
     62 static struct heathrow_ops *setup_heathrow(uint32_t);
     63 static inline void heathrow_read_events(struct heathrow_ops *);
     64 
     65 #define INT_STATE_REG_H		((uint32_t)pic->pic_cookie + 0x10)
     66 #define INT_ENABLE_REG_H	((uint32_t)pic->pic_cookie + 0x14)
     67 #define INT_CLEAR_REG_H		((uint32_t)pic->pic_cookie + 0x18)
     68 #define INT_LEVEL_REG_H		((uint32_t)pic->pic_cookie + 0x1c)
     69 #define INT_STATE_REG_L		((uint32_t)pic->pic_cookie + 0x20)
     70 #define INT_ENABLE_REG_L	((uint32_t)pic->pic_cookie + 0x24)
     71 #define INT_CLEAR_REG_L		((uint32_t)pic->pic_cookie + 0x28)
     72 #define INT_LEVEL_REG_L		((uint32_t)pic->pic_cookie + 0x2c)
     73 
     74 static const char *compat[] = {
     75 	"heathrow",
     76 	NULL
     77 };
     78 
     79 int init_heathrow(void)
     80 {
     81 	uint32_t reg[5];
     82 	uint32_t obio_base;
     83 	int      heathrow;
     84 
     85 	heathrow = OF_finddevice("/pci/mac-io");
     86 	if (heathrow == -1)
     87 		heathrow = OF_finddevice("mac-io");
     88 	if (heathrow == -1)
     89 		return FALSE;
     90 
     91 	if (! of_compatible(heathrow, compat))
     92 		return FALSE;
     93 
     94 	if (OF_getprop(heathrow, "assigned-addresses", reg, sizeof(reg)) != 20)
     95 		return FALSE;
     96 
     97 	obio_base = reg[2];
     98 	aprint_normal("found heathrow PIC at %08x\n", obio_base);
     99 	setup_heathrow(obio_base);
    100 	/* TODO: look for 2nd Heathrow */
    101 	return TRUE;
    102 }
    103 
    104 static struct heathrow_ops *
    105 setup_heathrow(uint32_t addr)
    106 {
    107 	struct heathrow_ops *heathrow;
    108 	struct pic_ops *pic;
    109 
    110 	heathrow = kmem_zalloc(sizeof(struct heathrow_ops), KM_SLEEP);
    111 	pic = &heathrow->pic;
    112 
    113 	pic->pic_numintrs = 64;
    114 	pic->pic_cookie = (void *)addr;
    115 	pic->pic_enable_irq = heathrow_enable_irq;
    116 	pic->pic_reenable_irq = heathrow_reenable_irq;
    117 	pic->pic_disable_irq = heathrow_disable_irq;
    118 	pic->pic_get_irq = heathrow_get_irq;
    119 	pic->pic_ack_irq = heathrow_ack_irq;
    120 	pic->pic_establish_irq = heathrow_establish_irq;
    121 	pic->pic_finish_setup = NULL;
    122 
    123 	strcpy(pic->pic_name, "heathrow");
    124 	pic_add(pic);
    125 	heathrow->pending_events_l = 0;
    126 	heathrow->enable_mask_l = 0;
    127 	heathrow->level_mask_l = 0;
    128 	heathrow->pending_events_h = 0;
    129 	heathrow->enable_mask_h = 0;
    130 	heathrow->level_mask_h = 0;
    131 	out32rb(INT_ENABLE_REG_L, 0);
    132 	out32rb(INT_CLEAR_REG_L, 0xffffffff);
    133 	out32rb(INT_ENABLE_REG_H, 0);
    134 	out32rb(INT_CLEAR_REG_H, 0xffffffff);
    135 	return heathrow;
    136 }
    137 
    138 static void
    139 heathrow_enable_irq(struct pic_ops *pic, int irq, int type)
    140 {
    141 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
    142 	uint32_t mask = 1 << (irq & 0x1f);
    143 
    144 	if (irq & 0x20) {
    145 		heathrow->enable_mask_h |= mask;
    146 		out32rb(INT_ENABLE_REG_H, heathrow->enable_mask_h);
    147 	} else {
    148 		heathrow->enable_mask_l |= mask;
    149 		out32rb(INT_ENABLE_REG_L, heathrow->enable_mask_l);
    150 	}
    151 }
    152 
    153 static void
    154 heathrow_reenable_irq(struct pic_ops *pic, int irq, int type)
    155 {
    156 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
    157 	uint32_t levels;
    158 	uint32_t mask = 1 << (irq  & 0x1f);
    159 
    160 	if (irq & 0x20) {
    161 		heathrow->enable_mask_h |= mask;
    162 		out32rb(INT_ENABLE_REG_H, heathrow->enable_mask_h);
    163 		levels = in32rb(INT_STATE_REG_H);
    164 		if (levels & mask) {
    165 			pic_mark_pending(pic->pic_intrbase + irq);
    166 			out32rb(INT_CLEAR_REG_H, mask);
    167 		}
    168 	} else {
    169 		heathrow->enable_mask_l |= mask;
    170 		out32rb(INT_ENABLE_REG_L, heathrow->enable_mask_l);
    171 		levels = in32rb(INT_STATE_REG_L);
    172 		if (levels & mask) {
    173 			pic_mark_pending(pic->pic_intrbase + irq);
    174 			out32rb(INT_CLEAR_REG_L, mask);
    175 		}
    176 	}
    177 }
    178 
    179 static void
    180 heathrow_disable_irq(struct pic_ops *pic, int irq)
    181 {
    182 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
    183 	uint32_t mask = 1 << (irq & 0x1f);
    184 
    185 	if (irq & 0x20) {
    186 		heathrow->enable_mask_h &= ~mask;
    187 		out32rb(INT_ENABLE_REG_H, heathrow->enable_mask_h);
    188 	} else {
    189 		heathrow->enable_mask_l &= ~mask;
    190 		out32rb(INT_ENABLE_REG_L, heathrow->enable_mask_l);
    191 	}
    192 }
    193 
    194 static inline void
    195 heathrow_read_events(struct heathrow_ops *heathrow)
    196 {
    197 	struct pic_ops *pic = &heathrow->pic;
    198 	uint32_t irqs, events, levels;
    199 
    200 	/* first the low 32 IRQs */
    201 	irqs = in32rb(INT_STATE_REG_L);
    202 	events = irqs & ~heathrow->level_mask_l;
    203 
    204 	levels = in32rb(INT_LEVEL_REG_L) & heathrow->enable_mask_l;
    205 	events |= levels & heathrow->level_mask_l;
    206 	out32rb(INT_CLEAR_REG_L, events | irqs);
    207 	heathrow->pending_events_l |= events;
    208 
    209 	/* then the upper 32 */
    210 	irqs = in32rb(INT_STATE_REG_H);
    211 	events = irqs & ~heathrow->level_mask_h;
    212 	levels = in32rb(INT_LEVEL_REG_L) & heathrow->enable_mask_h;
    213 	events |= levels & heathrow->level_mask_h;
    214 	out32rb(INT_CLEAR_REG_H, events);
    215 	heathrow->pending_events_h |= events;
    216 }
    217 
    218 static int
    219 heathrow_get_irq(struct pic_ops *pic, int mode)
    220 {
    221 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
    222 	int bit, mask;
    223 
    224 	if ((heathrow->pending_events_h == 0) &&
    225 	    (heathrow->pending_events_l == 0))
    226 		heathrow_read_events(heathrow);
    227 
    228 	if ((heathrow->pending_events_h == 0) &&
    229 	    (heathrow->pending_events_l == 0))
    230 		return 255;
    231 
    232 	if (heathrow->pending_events_l != 0) {
    233 		bit = 31 - __builtin_clz(heathrow->pending_events_l);
    234 		mask = 1 << bit;
    235 		heathrow->pending_events_l &= ~mask;
    236 		return bit;
    237 	}
    238 
    239 	if (heathrow->pending_events_h != 0) {
    240 		bit = 31 - __builtin_clz(heathrow->pending_events_h);
    241 		mask = 1 << bit;
    242 		heathrow->pending_events_h &= ~mask;
    243 		return bit + 32;
    244 	}
    245 	/* we should never get here */
    246 	return 255;
    247 }
    248 
    249 static void
    250 heathrow_ack_irq(struct pic_ops *pic, int irq)
    251 {
    252 }
    253 
    254 static void
    255 heathrow_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
    256 {
    257 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
    258 	uint32_t mask;
    259 
    260 	KASSERT((irq >= 0) && (irq < 64));
    261 
    262 	mask = 1 << (irq & 0x1f);
    263 	if (irq & 0x20) {
    264 		if (type == IST_LEVEL) {
    265 
    266 			heathrow->level_mask_h |= mask;
    267 		} else {
    268 
    269 			heathrow->level_mask_h &= ~mask;
    270 		}
    271 	} else {
    272 		if (type == IST_LEVEL) {
    273 
    274 			heathrow->level_mask_l |= mask;
    275 		} else {
    276 
    277 			heathrow->level_mask_l &= ~mask;
    278 		}
    279 	}
    280 	aprint_debug("mask: %08x %08x\n", heathrow->level_mask_h,
    281 	    heathrow->level_mask_l);
    282 }
    283