1 /* $NetBSD: pic_amiga.c,v 1.2 2010/02/02 19:15:33 phx 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.2 2010/02/02 19:15:33 phx Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/malloc.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 = malloc(sizeof(struct amiga_ops), M_DEVBUF, M_NOWAIT); 69 KASSERT(amipic != NULL); 70 pic = &amipic->pic; 71 72 pic->pic_numintrs = MAXIPL; 73 pic->pic_cookie = (void *)NULL; 74 pic->pic_enable_irq = amiga_enable_irq; 75 pic->pic_reenable_irq = amiga_enable_irq; 76 pic->pic_disable_irq = amiga_disable_irq; 77 pic->pic_get_irq = amiga_get_irq; 78 pic->pic_ack_irq = amiga_ack_irq; 79 pic->pic_establish_irq = dummy_pic_establish_intr; 80 strcpy(pic->pic_name, "amiga"); 81 82 /* Set PPC IPL to 7, disabling all interrupts */ 83 amipic->disablemask = (1 << MAXIPL) - 1; 84 P5write(P5_IPL_EMU, P5_DISABLE_INT | 7); 85 86 pic_add(pic); 87 88 return pic; 89 } 90 91 static void 92 amiga_enable_irq(struct pic_ops *pic, int ipl, int type) 93 { 94 struct amiga_ops *amipic = (struct amiga_ops *)pic; 95 int iplmask, dmask, newipl; 96 97 iplmask = 1 << ipl; 98 dmask = amipic->disablemask; 99 100 if ((dmask & iplmask)) { 101 102 dmask &= ~iplmask; 103 amipic->disablemask = dmask; 104 if (!(dmask & ~(iplmask - 1))) { 105 106 /* Lower the emulated PPC IPL to the next highest */ 107 newipl = 31 - cntlzw(dmask); 108 P5write(P5_IPL_EMU, P5_SET_CLEAR | P5_DISABLE_INT | 109 (newipl ^ P5_IPL_MASK)); 110 P5write(P5_IPL_EMU, P5_DISABLE_INT | newipl); 111 } 112 } 113 } 114 115 static void 116 amiga_disable_irq(struct pic_ops *pic, int ipl) 117 { 118 struct amiga_ops *amipic = (struct amiga_ops *)pic; 119 int iplmask, dmask; 120 121 iplmask = 1 << ipl; 122 dmask = amipic->disablemask; 123 124 if (!(dmask & iplmask)) { 125 126 if (!(dmask & ~(iplmask - 1))) { 127 128 /* Raise the emulated PPC IPL to the new ipl */ 129 P5write(P5_IPL_EMU, P5_SET_CLEAR | P5_DISABLE_INT | 130 (ipl ^ P5_IPL_MASK)); 131 P5write(P5_IPL_EMU, P5_DISABLE_INT | ipl); 132 } 133 amipic->disablemask |= iplmask; 134 } 135 } 136 137 static int 138 amiga_get_irq(struct pic_ops *pic, int mode) 139 { 140 unsigned char ipl; 141 142 if (mode == PIC_GET_RECHECK) 143 return 255; 144 145 /* Get the interrupt's 68k IPL - the bits are active low */ 146 P5read(P5_IPL_EMU, ipl); 147 ipl = ~(ipl >> 3) & P5_IPL_MASK; 148 149 return ipl == 0 ? 255 : ipl; 150 } 151 152 static void 153 amiga_ack_irq(struct pic_ops *pic, int ipl) 154 { 155 } 156