Home | History | Annotate | Line # | Download | only in ingenic
intr.c revision 1.1
      1 /*	$NetBSD: intr.c,v 1.1 2014/12/06 14:26:40 macallan Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2014 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: intr.c,v 1.1 2014/12/06 14:26:40 macallan Exp $");
     31 
     32 #define __INTR_PRIVATE
     33 
     34 #include <sys/param.h>
     35 #include <sys/cpu.h>
     36 #include <sys/device.h>
     37 #include <sys/kernel.h>
     38 #include <sys/systm.h>
     39 #include <sys/timetc.h>
     40 
     41 #include <mips/locore.h>
     42 #include <machine/intr.h>
     43 
     44 #include <mips/ingenic/ingenic_regs.h>
     45 
     46 extern void ingenic_clockintr(uint32_t);
     47 extern void ingenic_puts(const char *);
     48 
     49 /*
     50  * This is a mask of bits to clear in the SR when we go to a
     51  * given hardware interrupt priority level.
     52  */
     53 static const struct ipl_sr_map ingenic_ipl_sr_map = {
     54     .sr_bits = {
     55 	[IPL_NONE] =		0,
     56 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
     57 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1,
     58 	[IPL_VM] =
     59 	    MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
     60 	    MIPS_INT_MASK_0 |
     61 	    MIPS_INT_MASK_3 |
     62 	    MIPS_INT_MASK_4 |
     63 	    MIPS_INT_MASK_5,
     64 	[IPL_SCHED] =
     65 	    MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
     66 	    MIPS_INT_MASK_0 |
     67 	    MIPS_INT_MASK_1 |
     68 	    MIPS_INT_MASK_2 |
     69 	    MIPS_INT_MASK_3 |
     70 	    MIPS_INT_MASK_4 |
     71 	    MIPS_INT_MASK_5,
     72 	[IPL_DDB] =		MIPS_INT_MASK,
     73 	[IPL_HIGH] =            MIPS_INT_MASK,
     74     },
     75 };
     76 
     77 //#define INGENIC_DEBUG
     78 void
     79 evbmips_intr_init(void)
     80 {
     81 	uint32_t reg;
     82 
     83 	ipl_sr_map = ingenic_ipl_sr_map;
     84 
     85 	/* mask all peripheral IRQs */
     86 	writereg(JZ_ICMR0, 0xffffffff);
     87 	writereg(JZ_ICMR1, 0xffffffff);
     88 
     89 	/* allow mailbox and peripheral interrupts to core 0 only */
     90 	reg = MFC0(12, 4);	/* reset entry and interrupts */
     91 	reg &= 0xffff0000;
     92 	reg |= REIM_IRQ0_M | REIM_MIRQ0_M | REIM_MIRQ1_M;
     93 	MTC0(reg, 12, 4);
     94 }
     95 
     96 void
     97 evbmips_iointr(int ipl, vaddr_t pc, uint32_t ipending)
     98 {
     99 	uint32_t id;
    100 #ifdef INGENIC_DEBUG
    101 	char buffer[256];
    102 
    103 	snprintf(buffer, 256, "pending: %08x CR %08x\n", ipending, MFC0(MIPS_COP_0_CAUSE, 0));
    104 	ingenic_puts(buffer);
    105 #endif
    106 	/* see which core we're on */
    107 	id = MFC0(15, 1) & 7;
    108 
    109 	/*
    110 	 * XXX
    111 	 * the manual counts the softint bits as INT0 and INT1, out headers
    112 	 * don't so everything here looks off by two
    113 	 */
    114 	if (ipending & MIPS_INT_MASK_1) {
    115 		/*
    116 		 * this is a mailbox interrupt / IPI
    117 		 * for now just print the message and clear it
    118 		 */
    119 		uint32_t reg;
    120 
    121 		/* read pending IPIs */
    122 		reg = MFC0(12, 3);
    123 		if (id == 0) {
    124 			if (reg & CS_MIRQ0_P) {
    125 
    126 #ifdef INGENIC_DEBUG
    127 				snprintf(buffer, 256, "IPI for core 0, msg %08x\n",
    128 				    MFC0(CP0_CORE_MBOX, 0));
    129 				ingenic_puts(buffer);
    130 #endif
    131 				reg &= (~CS_MIRQ0_P);
    132 				/* clear it */
    133 				MTC0(reg, 12, 3);
    134 			}
    135 		} else if (id == 1) {
    136 			if (reg & CS_MIRQ1_P) {
    137 #ifdef INGENIC_DEBUG
    138 				snprintf(buffer, 256, "IPI for core 1, msg %08x\n",
    139 				    MFC0(CP0_CORE_MBOX, 1));
    140 				ingenic_puts(buffer);
    141 #endif
    142 				reg &= ( 7 - CS_MIRQ1_P);
    143 				/* clear it */
    144 				MTC0(reg, 12, 3);
    145 			}
    146 		}
    147 	}
    148 	if (ipending & MIPS_INT_MASK_2) {
    149 		/* this is a timer interrupt */
    150 		ingenic_clockintr(id);
    151 		ingenic_puts("INT2\n");
    152 	}
    153 	if (ipending & MIPS_INT_MASK_0) {
    154 		/* peripheral interrupt */
    155 
    156 		/*
    157 		 * XXX
    158 		 * OS timer interrupts are supposed to show up as INT2 as well
    159 		 * but I haven't seen them there so for now we just weed them
    160 		 * out right here.
    161 		 * The idea is to allow peripheral interrupts on both cores but
    162 		 * block INT0 on core1 so it would see only timer interrupts
    163 		 * and IPIs. If that doesn't work we'll have to send an IPI to
    164 		 * core1 for each timer tick.
    165 		 */
    166 		if (readreg(JZ_ICPR0) & 0x08000000)
    167 			ingenic_clockintr(id);
    168 		KASSERT(id == 0);
    169 	}
    170 }
    171