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