1 /* $NetBSD: news4000.c,v 1.2 2024/06/02 13:28:44 andvar Exp $ */ 2 3 /*- 4 * Copyright (C) 2000 NONAKA Kimihiro. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #define __INTR_PRIVATE 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/timetc.h> 34 #include <sys/intr.h> 35 36 #include <machine/adrsmap.h> 37 #include <machine/cpu.h> 38 39 #include <mips/locore.h> 40 41 #include <newsmips/apbus/apbusvar.h> 42 #include <newsmips/newsmips/machid.h> 43 44 static void news4000_level0_intr(void); 45 static void news4000_level1_intr(void); 46 47 static void news4000_enable_intr(void); 48 static void news4000_disable_intr(void); 49 static void news4000_enable_timer(void); 50 static void news4000_readidrom(uint8_t *); 51 52 /* 53 * This is a mask of bits of to clear in the SR when we go to a 54 * given interrupt priority level. 55 */ 56 static const struct ipl_sr_map news4000_ipl_sr_map = { 57 .sr_bits = { 58 [IPL_NONE] = 0, 59 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 60 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 61 [IPL_VM] = MIPS_SOFT_INT_MASK 62 | MIPS_INT_MASK_0 63 | MIPS_INT_MASK_1, 64 [IPL_SCHED] = MIPS_SOFT_INT_MASK 65 | MIPS_INT_MASK_0 66 | MIPS_INT_MASK_1 67 | MIPS_INT_MASK_2, 68 [IPL_DDB] = MIPS_INT_MASK, 69 [IPL_HIGH] = MIPS_INT_MASK, 70 }, 71 }; 72 73 /* 74 * Handle news4000 interrupts. 75 */ 76 void 77 news4000_intr(int ppl, vaddr_t pc, uint32_t status) 78 { 79 uint32_t ipending; 80 int ipl; 81 82 while (ppl < (ipl = splintr(&ipending))) { 83 if (ipending & MIPS_INT_MASK_2) { 84 uint32_t int2stat; 85 86 int2stat = *(volatile uint32_t *)NEWS4000_INTST2; 87 88 if (int2stat & NEWS4000_INT2_TIMER) { 89 struct clockframe cf = { 90 .pc = pc, 91 .sr = status, 92 .intr = (curcpu()->ci_idepth > 1), 93 }; 94 *(volatile uint32_t *)NEWS4000_TIMER = 1; 95 96 hardclock(&cf); 97 intrcnt[HARDCLOCK_INTR]++; 98 } 99 100 apbus_wbflush(); 101 } 102 103 if (ipending & MIPS_INT_MASK_5) { 104 uint32_t int5stat = 105 *(volatile uint32_t *)NEWS4000_INTST5; 106 printf("level5 interrupt: status = %04x\n", int5stat); 107 apbus_wbflush(); 108 } 109 110 if (ipending & MIPS_INT_MASK_4) { 111 uint32_t int4stat = 112 *(volatile uint32_t *)NEWS4000_INTST4; 113 printf("level4 interrupt: status = %04x\n", int4stat); 114 apbus_wbflush(); 115 } 116 117 if (ipending & MIPS_INT_MASK_3) { 118 printf("level3 interrupt\n"); 119 apbus_wbflush(); 120 } 121 122 if (ipending & MIPS_INT_MASK_1) { 123 news4000_level1_intr(); 124 apbus_wbflush(); 125 } 126 127 if (ipending & MIPS_INT_MASK_0) { 128 news4000_level0_intr(); 129 apbus_wbflush(); 130 } 131 } 132 } 133 134 static void 135 news4000_level1_intr(void) 136 { 137 uint32_t int1stat; 138 139 int1stat = *(volatile uint32_t *)NEWS4000_INTST1; 140 141 #if 0 142 *(volatile uint32_t *)NEWS4000_LED = 0xe; /* XXX */ 143 #endif 144 145 printf("level1_intr stat = 0x%x\n", int1stat); 146 147 if (int1stat) { 148 if (apbus_intr_dispatch(1, int1stat) == 0) 149 printf("level1_intr: no handler (mask 0x%04x)\n", 150 int1stat); 151 } else 152 printf("level1 stray interrupt?\n"); 153 } 154 155 static void 156 news4000_level0_intr(void) 157 { 158 uint32_t int0stat; 159 160 int0stat = *(volatile uint32_t *)NEWS4000_INTST0; 161 162 if (int0stat) { 163 if (apbus_intr_dispatch(0, int0stat) == 0) 164 printf("level0_intr: no handler (mask 0x%04x)\n", 165 int0stat); 166 } else 167 printf("level0 stray interrupt?\n"); 168 } 169 170 static void 171 news4000_enable_intr(void) 172 { 173 174 *(volatile uint32_t *)NEWS4000_INTEN0 = 0xffffffff; 175 *(volatile uint32_t *)NEWS4000_INTEN1 = 0xffffffff; 176 *(volatile uint32_t *)NEWS4000_INTEN2 = 1; 177 *(volatile uint32_t *)NEWS4000_INTEN3 = 0; 178 *(volatile uint32_t *)NEWS4000_INTEN4 = 0; /* 3 */ 179 *(volatile uint32_t *)NEWS4000_INTEN5 = 0; /* 3 */ 180 } 181 182 static void 183 news4000_disable_intr(void) 184 { 185 186 *(volatile uint32_t *)NEWS4000_INTEN0 = 0; 187 *(volatile uint32_t *)NEWS4000_INTEN1 = 0; 188 *(volatile uint32_t *)NEWS4000_INTEN2 = 0; 189 *(volatile uint32_t *)NEWS4000_INTEN3 = 0; 190 *(volatile uint32_t *)NEWS4000_INTEN4 = 0; 191 *(volatile uint32_t *)NEWS4000_INTEN5 = 0; 192 } 193 194 static void 195 news4000_enable_timer(void) 196 { 197 198 #if 0 199 news4000_tc_init(); 200 #endif 201 202 /* enable timer interrupt */ 203 *(volatile uint32_t *)NEWS4000_TIMERCTL = 1; 204 } 205 206 extern struct idrom idrom; 207 208 static void 209 news4000_readidrom(uint8_t *rom) 210 { 211 volatile uint32_t *status_port = (uint32_t *)NEWS4000_IDROM_STATUS; 212 volatile uint32_t *data_port = (uint32_t *)NEWS4000_IDROM_DATA; 213 int offset; 214 215 while ((*status_port & 1) == 0) 216 continue; 217 218 for (offset = 0; offset < sizeof(struct idrom); offset++, rom++) { 219 *data_port = offset; 220 221 while ((*status_port & 1) == 0) 222 continue; 223 224 *rom = (uint8_t)(*data_port & 0xff); 225 } 226 } 227 228 void 229 news4000_init(void) 230 { 231 232 ipl_sr_map = news4000_ipl_sr_map; 233 234 enable_intr = news4000_enable_intr; 235 disable_intr = news4000_disable_intr; 236 enable_timer = news4000_enable_timer; 237 238 news_wbflush = (uint32_t *)NEWS4000_WBFLUSH; 239 240 news4000_readidrom((uint8_t *)&idrom); 241 hostid = idrom.id_serial; 242 } 243