1 /* $NetBSD: pic_amiga.c,v 1.5 2020/11/20 17:48:25 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2008,2009,2010 Frank Wille. 5 * All rights reserved. 6 * 7 * Written by Frank Wille for The NetBSD Project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: pic_amiga.c,v 1.5 2020/11/20 17:48:25 thorpej Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/kmem.h> 36 #include <sys/kernel.h> 37 38 #include <uvm/uvm_extern.h> 39 40 #include <arch/powerpc/pic/picvar.h> 41 #include <amiga/amiga/custom.h> 42 #include <amigappc/amigappc/p5reg.h> 43 44 static void amiga_enable_irq(struct pic_ops *, int, int); 45 static void amiga_disable_irq(struct pic_ops *, int); 46 static int amiga_get_irq(struct pic_ops *, int); 47 static void amiga_ack_irq(struct pic_ops *, int); 48 struct pic_ops *setup_amiga_intr(void); 49 50 /* 51 * Number of amigappc hardware interrupts, based on 68000 IPL mask. 52 * In reality 6, because level 0 means no interrupt and level 7 (NMI) 53 * should not happen. 54 */ 55 #define MAXIPL 7 56 57 struct amiga_ops { 58 struct pic_ops pic; 59 int disablemask; 60 }; 61 62 struct pic_ops * 63 setup_amiga_intr(void) 64 { 65 struct amiga_ops *amipic; 66 struct pic_ops *pic; 67 68 amipic = kmem_alloc(sizeof(struct amiga_ops), KM_SLEEP); 69 pic = &amipic->pic; 70 71 pic->pic_numintrs = MAXIPL; 72 pic->pic_cookie = (void *)NULL; 73 pic->pic_enable_irq = amiga_enable_irq; 74 pic->pic_reenable_irq = amiga_enable_irq; 75 pic->pic_disable_irq = amiga_disable_irq; 76 pic->pic_get_irq = amiga_get_irq; 77 pic->pic_ack_irq = amiga_ack_irq; 78 pic->pic_establish_irq = dummy_pic_establish_intr; 79 strcpy(pic->pic_name, "amiga"); 80 81 /* Set PPC IPL to 7, disabling all interrupts */ 82 amipic->disablemask = (1 << MAXIPL) - 1; 83 P5write(P5_IPL_EMU, P5_DISABLE_INT | 7); 84 85 pic_add(pic); 86 87 return pic; 88 } 89 90 static void 91 amiga_enable_irq(struct pic_ops *pic, int ipl, int type) 92 { 93 struct amiga_ops *amipic = (struct amiga_ops *)pic; 94 int iplmask, dmask, newipl; 95 96 iplmask = 1 << ipl; 97 dmask = amipic->disablemask; 98 99 if ((dmask & iplmask)) { 100 101 dmask &= ~iplmask; 102 amipic->disablemask = dmask; 103 if (!(dmask & ~(iplmask - 1))) { 104 105 /* Lower the emulated PPC IPL to the next highest */ 106 newipl = 31 - __builtin_clz(dmask); 107 P5write(P5_IPL_EMU, P5_SET_CLEAR | P5_DISABLE_INT | 108 (newipl ^ P5_IPL_MASK)); 109 P5write(P5_IPL_EMU, P5_DISABLE_INT | newipl); 110 } 111 } 112 } 113 114 static void 115 amiga_disable_irq(struct pic_ops *pic, int ipl) 116 { 117 struct amiga_ops *amipic = (struct amiga_ops *)pic; 118 int iplmask, dmask; 119 120 iplmask = 1 << ipl; 121 dmask = amipic->disablemask; 122 123 if (!(dmask & iplmask)) { 124 125 if (!(dmask & ~(iplmask - 1))) { 126 127 /* Raise the emulated PPC IPL to the new ipl */ 128 P5write(P5_IPL_EMU, P5_SET_CLEAR | P5_DISABLE_INT | 129 (ipl ^ P5_IPL_MASK)); 130 P5write(P5_IPL_EMU, P5_DISABLE_INT | ipl); 131 } 132 amipic->disablemask |= iplmask; 133 } 134 } 135 136 static int 137 amiga_get_irq(struct pic_ops *pic, int mode) 138 { 139 unsigned char ipl; 140 141 if (mode == PIC_GET_RECHECK) 142 return 255; 143 144 /* Get the interrupt's 68k IPL - the bits are active low */ 145 P5read(P5_IPL_EMU, ipl); 146 ipl = ~(ipl >> 3) & P5_IPL_MASK; 147 148 return ipl == 0 ? 255 : ipl; 149 } 150 151 static void 152 amiga_ack_irq(struct pic_ops *pic, int ipl) 153 { 154 } 155