Home | History | Annotate | Line # | Download | only in amigappc
      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