1 /* $NetBSD: kirkwood.c,v 1.2 2010/10/30 06:37:49 kiyohara Exp $ */ 2 /* 3 * Copyright (c) 2010 KIYOHARA Takashi 4 * 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: kirkwood.c,v 1.2 2010/10/30 06:37:49 kiyohara Exp $"); 30 31 #define _INTR_PRIVATE 32 33 #include "mvsocgpp.h" 34 35 #include <sys/param.h> 36 #include <sys/bus.h> 37 38 #include <machine/intr.h> 39 40 #include <arm/pic/picvar.h> 41 #include <arm/pic/picvar.h> 42 43 #include <arm/marvell/mvsocreg.h> 44 #include <arm/marvell/mvsocvar.h> 45 #include <arm/marvell/kirkwoodreg.h> 46 47 #include <dev/marvell/marvellreg.h> 48 49 50 static void kirkwood_intr_init(void); 51 52 static void kirkwood_pic_unblock_low_irqs(struct pic_softc *, size_t, uint32_t); 53 static void kirkwood_pic_unblock_high_irqs(struct pic_softc *, size_t, 54 uint32_t); 55 static void kirkwood_pic_block_low_irqs(struct pic_softc *, size_t, uint32_t); 56 static void kirkwood_pic_block_high_irqs(struct pic_softc *, size_t, uint32_t); 57 static int kirkwood_pic_find_pending_high_irqs(struct pic_softc *); 58 static void kirkwood_pic_establish_irq(struct pic_softc *, struct intrsource *); 59 static void kirkwood_pic_source_name(struct pic_softc *, int, char *, size_t); 60 61 static int kirkwood_find_pending_irqs(void); 62 63 static const char * const sources[64] = { 64 "MainHighSum(0)", "Bridge(1)", "Host2CPU DB(2)", "CPU2Host DB(3)", 65 "Reserved_4(4)", "Xor0Chan0(5)", "Xor0Chan1(6)", "Xor1Chan0(7)", 66 "Xor1Chan1(8)", "PEX0INT(9)", "Reserved(10)", "GbE0Sum(11)", 67 "GbE0Rx(12)", "GbE0Tx(13)", "GbE0Misc(14)", "GbE1Sum(15)", 68 "GbE1Rx(16)", "GbE1Tx(17)", "GbE1Misc(18)", "USB0Cnt(19)", 69 "Reserved(20)", "Sata(21)", "SecurityInt(22)", "SPIInt(23)", 70 "AudioINT(24)", "Reserved(25)", "TS0Int(26)", "Reserved(27)", 71 "SDIOInt(28)", "TWSI(29)", "AVBInt(30)", "TDMInt(31)" 72 73 "Reserved(32)", "Uart0Int(33)", "Uart1Int(34)", "GPIOLo7_0(35)" 74 "GPIOLo8_15(36)", "GPIOLo16_23(37)", "GPIOLo24_31(38)", "GPIOHi7_0(39)" 75 "GPIOHi8_15(40)", "GPIOHi16_23(41)", "XOR0Err(42)", "XOR1Err(43)" 76 "PEX0Err(44)", "Reserved(45)", "GbE0Err(46)", "GbE1Err(47)" 77 "USBErr(48)", "SecurityErr(49)", "AudioErr(50)", "Reserved(51)" 78 "Reserved(52)", "RTCInt(53)", "Reserved(54)", "Reserved(55)" 79 "Reserved(56)", "Reserved(57)", "Reserved(58)", "Reserved(59)" 80 "Reserved(60)", "Reserved(61)", "Reserved(62)", "Reserved(63)" 81 }; 82 83 static struct pic_ops kirkwood_picops_low = { 84 .pic_unblock_irqs = kirkwood_pic_unblock_low_irqs, 85 .pic_block_irqs = kirkwood_pic_block_low_irqs, 86 .pic_establish_irq = kirkwood_pic_establish_irq, 87 .pic_source_name = kirkwood_pic_source_name, 88 }; 89 static struct pic_ops kirkwood_picops_high = { 90 .pic_unblock_irqs = kirkwood_pic_unblock_high_irqs, 91 .pic_block_irqs = kirkwood_pic_block_high_irqs, 92 .pic_find_pending_irqs = kirkwood_pic_find_pending_high_irqs, 93 .pic_establish_irq = kirkwood_pic_establish_irq, 94 .pic_source_name = kirkwood_pic_source_name, 95 }; 96 static struct pic_softc kirkwood_pic_low = { 97 .pic_ops = &kirkwood_picops_low, 98 .pic_maxsources = 32, 99 .pic_name = "kirkwood_low", 100 }; 101 static struct pic_softc kirkwood_pic_high = { 102 .pic_ops = &kirkwood_picops_high, 103 .pic_maxsources = 32, 104 .pic_name = "kirkwood_high", 105 }; 106 107 108 /* 109 * kirkwood_intr_bootstrap: 110 * 111 * Initialize the rest of the interrupt subsystem, making it 112 * ready to handle interrupts from devices. 113 */ 114 void 115 kirkwood_intr_bootstrap(void) 116 { 117 extern void (*mvsoc_intr_init)(void); 118 119 /* disable all interrupts */ 120 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 0); 121 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 0); 122 123 /* disable all bridge interrupts */ 124 write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0); 125 126 mvsoc_intr_init = kirkwood_intr_init; 127 128 #if NMVSOCGPP > 0 129 switch (mvsoc_model()) { 130 case MARVELL_KIRKWOOD_88F6180: gpp_npins = 30; break; 131 case MARVELL_KIRKWOOD_88F6192: gpp_npins = 36; break; 132 case MARVELL_KIRKWOOD_88F6281: gpp_npins = 50; break; 133 } 134 gpp_irqbase = 96; /* Main Low(32) + High(32) + Bridge(32) */ 135 #endif 136 } 137 138 static void 139 kirkwood_intr_init(void) 140 { 141 extern struct pic_softc mvsoc_bridge_pic; 142 void *ih; 143 144 pic_add(&kirkwood_pic_low, 0); 145 146 pic_add(&kirkwood_pic_high, 32); 147 ih = intr_establish(KIRKWOOD_IRQ_HIGH, IPL_HIGH, IST_LEVEL_HIGH, 148 pic_handle_intr, &kirkwood_pic_high); 149 KASSERT(ih != NULL); 150 151 pic_add(&mvsoc_bridge_pic, 64); 152 ih = intr_establish(KIRKWOOD_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH, 153 pic_handle_intr, &mvsoc_bridge_pic); 154 KASSERT(ih != NULL); 155 156 find_pending_irqs = kirkwood_find_pending_irqs; 157 } 158 159 /* ARGSUSED */ 160 static void 161 kirkwood_pic_unblock_low_irqs(struct pic_softc *pic, size_t irqbase, 162 uint32_t irq_mask) 163 { 164 165 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 166 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) | irq_mask); 167 } 168 169 /* ARGSUSED */ 170 static void 171 kirkwood_pic_unblock_high_irqs(struct pic_softc *pic, size_t irqbase, 172 uint32_t irq_mask) 173 { 174 175 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 176 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) | irq_mask); 177 } 178 179 /* ARGSUSED */ 180 static void 181 kirkwood_pic_block_low_irqs(struct pic_softc *pic, size_t irqbase, 182 uint32_t irq_mask) 183 { 184 185 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 186 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) & ~irq_mask); 187 } 188 189 /* ARGSUSED */ 190 static void 191 kirkwood_pic_block_high_irqs(struct pic_softc *pic, size_t irqbase, 192 uint32_t irq_mask) 193 { 194 195 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 196 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) & ~irq_mask); 197 } 198 199 static int 200 kirkwood_pic_find_pending_high_irqs(struct pic_softc *pic) 201 { 202 uint32_t pending; 203 204 pending = read_mlmbreg(KIRKWOOD_MLMB_MICHR) & 205 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR); 206 if (pending == 0) 207 return 0; 208 pic_mark_pending_sources(pic, 0, pending); 209 return 1; 210 } 211 212 /* ARGSUSED */ 213 static void 214 kirkwood_pic_establish_irq(struct pic_softc *pic, struct intrsource *is) 215 { 216 /* Nothing */ 217 } 218 219 static void 220 kirkwood_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len) 221 { 222 223 strlcpy(buf, sources[pic->pic_irqbase + irq], len); 224 } 225 226 /* 227 * Called with interrupts disabled 228 */ 229 static int 230 kirkwood_find_pending_irqs(void) 231 { 232 uint32_t pending; 233 234 pending = read_mlmbreg(KIRKWOOD_MLMB_MICLR) & 235 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR); 236 if (pending == 0) 237 return 0; 238 239 return pic_mark_pending_sources(&kirkwood_pic_low, 0, pending); 240 } 241 242 /* 243 * Clock functions 244 */ 245 246 void 247 kirkwood_getclks(bus_addr_t iobase) 248 { 249 uint32_t reg; 250 uint16_t model; 251 252 #define MHz * 1000 * 1000 253 254 model = mvsoc_model(); 255 if (model == MARVELL_KIRKWOOD_88F6281) 256 mvTclk = 200 MHz; 257 else /* 166MHz */ 258 mvTclk = 166666667; 259 260 reg = *(volatile uint32_t *)(iobase + KIRKWOOD_MPP_BASE + 261 KIRKWOOD_MPP_SAMPLE_AT_RESET); 262 if (model == MARVELL_KIRKWOOD_88F6180) { 263 switch (reg & 0x0000001c) { 264 case 0x00000014: mvPclk = 600 MHz; break; 265 case 0x00000018: mvPclk = 800 MHz; break; 266 default: 267 panic("unknown mvPclk\n"); 268 } 269 mvSysclk = 200 MHz; 270 } else { 271 switch (reg & 0x0040001a) { 272 case 0x00000008: mvPclk = 600 MHz; break; 273 case 0x00400008: mvPclk = 800 MHz; break; 274 case 0x0040000a: mvPclk = 1000 MHz; break; 275 case 0x00000012: mvPclk = 1200 MHz; break; 276 case 0x00000018: mvPclk = 1200 MHz; break; 277 default: 278 panic("unknown mvPclk\n"); 279 } 280 281 switch (reg & 0x000001e0) { 282 case 0x00000060: mvSysclk = mvPclk * 2 / 5; break; 283 case 0x00000080: mvSysclk = mvPclk * 1 / 3; break; 284 case 0x000000c0: mvSysclk = mvPclk * 1 / 4; break; 285 default: 286 panic("unknown mvSysclk\n"); 287 } 288 } 289 290 #undef MHz 291 292 } 293