1 /* $NetBSD: imx51_tzic.c,v 1.2 2010/12/20 00:25:28 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 SHIMIZU Ryo <ryo@nerv.org> 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: imx51_tzic.c,v 1.2 2010/12/20 00:25:28 matt Exp $"); 30 31 #define _INTR_PRIVATE /* for arm/pic/picvar.h */ 32 33 #include "locators.h" 34 35 #include <sys/param.h> 36 #include <sys/evcnt.h> 37 #include <sys/device.h> 38 #include <sys/atomic.h> 39 40 #include <machine/intr.h> 41 #include <machine/bus.h> 42 43 #include <uvm/uvm_extern.h> 44 45 #include <arm/cpu.h> 46 #include <arm/armreg.h> 47 #include <arm/cpufunc.h> 48 49 #include <machine/autoconf.h> 50 #include <machine/bus.h> 51 52 #include <arm/imx/imx51reg.h> 53 #include <arm/imx/imx51var.h> 54 #include <arm/imx/imx51_tzicreg.h> 55 56 static int tzic_match(device_t, cfdata_t, void *); 57 static void tzic_attach(device_t, device_t, void *); 58 59 /* for arm/pic */ 60 static void tzic_unblock_irqs(struct pic_softc *, size_t, uint32_t); 61 static void tzic_block_irqs(struct pic_softc *, size_t, uint32_t); 62 static void tzic_establish_irq(struct pic_softc *, struct intrsource *); 63 static void tzic_source_name(struct pic_softc *, int, char *, size_t); 64 65 struct tzic_softc { 66 device_t sc_dev; 67 struct pic_softc sc_pic; 68 bus_space_tag_t sc_iot; 69 bus_space_handle_t sc_ioh; 70 uint32_t sc_enabled_mask[4]; 71 }; 72 73 const struct pic_ops tzic_pic_ops = { 74 .pic_unblock_irqs = tzic_unblock_irqs, 75 .pic_block_irqs = tzic_block_irqs, 76 .pic_establish_irq = tzic_establish_irq, 77 .pic_source_name = tzic_source_name 78 }; 79 80 static void tzic_intr_init(struct tzic_softc * const); 81 82 static const char * const tzic_intr_source_names[] = TZIC_INTR_SOURCE_NAMES; 83 84 extern struct cfdriver tzic_cd; 85 86 #define PIC_TO_SOFTC(pic) \ 87 ((struct tzic_softc *)((char *)(pic) - \ 88 offsetof(struct tzic_softc, sc_pic))) 89 90 #define INTC_READ(tzic, reg) \ 91 bus_space_read_4((tzic)->sc_iot, (tzic)->sc_ioh, (reg)) 92 #define INTC_WRITE(tzic, reg, val) \ 93 bus_space_write_4((tzic)->sc_iot, (tzic)->sc_ioh, (reg), (val)) 94 95 /* use [7:4] of interrupt priority. 96 * 0 is the highest priority. 97 */ 98 #define HW_TO_SW_IPL(ipl) (IPL_HIGH - ((ipl) >> 3)) 99 #define SW_TO_HW_IPL(ipl) ((IPL_HIGH - (ipl)) << 3) 100 101 CFATTACH_DECL_NEW(tzic, sizeof(struct tzic_softc), 102 tzic_match, tzic_attach, NULL, NULL); 103 104 struct tzic_softc *tzic_softc; 105 106 int 107 tzic_match(device_t parent, cfdata_t self, void *aux) 108 { 109 struct axi_attach_args *aa; 110 111 aa = aux; 112 113 if (aa->aa_addr != TZIC_BASE) 114 return 0; 115 116 return 1; 117 } 118 119 void 120 tzic_attach(device_t parent, device_t self, void *aux) 121 { 122 struct tzic_softc *tzic = device_private(self); 123 struct axi_attach_args * const aa = aux; 124 int error; 125 126 KASSERT(aa->aa_irqbase != AXICF_IRQBASE_DEFAULT); 127 KASSERT(self->dv_unit == 0); 128 129 aprint_normal(": TrustZone Interrupt Controller\n"); 130 aprint_naive("\n"); 131 132 tzic->sc_dev = self; 133 tzic->sc_iot = aa->aa_iot; 134 135 tzic_softc = tzic; 136 137 if (aa->aa_size == AXICF_SIZE_DEFAULT) 138 aa->aa_size = TZIC_SIZE; 139 140 error = bus_space_map(tzic->sc_iot, aa->aa_addr, aa->aa_size, 0, &tzic->sc_ioh); 141 142 if (error) { 143 panic("tzic_attach: failed to map register %#x-%#x: %d", 144 (uint32_t)aa->aa_addr, 145 (uint32_t)(aa->aa_addr + aa->aa_size - 1), 146 error); 147 } 148 149 tzic_intr_init(tzic); 150 151 tzic->sc_pic.pic_ops = &tzic_pic_ops; 152 tzic->sc_pic.pic_maxsources = TZIC_INTNUM; 153 strlcpy(tzic->sc_pic.pic_name, device_xname(self), 154 sizeof(tzic->sc_pic.pic_name)); 155 156 pic_add(&tzic->sc_pic, aa->aa_irqbase); 157 158 aprint_normal_dev(tzic->sc_dev, "interrupts %d..%d register VA:%p\n", 159 aa->aa_irqbase, aa->aa_irqbase + TZIC_INTNUM, 160 (void *)tzic->sc_ioh); 161 162 /* Everything is all set. Enable the interrupts. */ 163 enable_interrupts(I32_bit|F32_bit); 164 } 165 166 167 void 168 tzic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) 169 { 170 struct tzic_softc * const tzic = PIC_TO_SOFTC(pic); 171 const size_t group = irq_base / 32; 172 173 KASSERT((irq_mask & tzic->sc_enabled_mask[group]) == 0); 174 175 tzic->sc_enabled_mask[group] |= irq_mask; 176 INTC_WRITE(tzic, TZIC_ENSET(group), irq_mask); 177 } 178 179 void 180 tzic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) 181 { 182 struct tzic_softc * const tzic = PIC_TO_SOFTC(pic); 183 const size_t group = irq_base / 32; 184 185 tzic->sc_enabled_mask[group] &= ~irq_mask; 186 187 INTC_WRITE(tzic, TZIC_ENCLEAR(group), irq_mask); 188 } 189 190 /* 191 * Called with interrupts disabled 192 */ 193 static int 194 find_pending_irqs(struct tzic_softc *tzic, size_t group) 195 { 196 uint32_t pending = 0; 197 198 KASSERT( group <= 3 ); 199 200 pending = INTC_READ(tzic, TZIC_PND(group)); 201 202 KASSERT((tzic->sc_enabled_mask[group] & pending) == pending); 203 204 if (pending == 0) 205 return 0; 206 207 return pic_mark_pending_sources(&tzic->sc_pic, group * 32, pending); 208 } 209 210 void 211 tzic_establish_irq(struct pic_softc *pic, struct intrsource *is) 212 { 213 struct tzic_softc * const tzic = PIC_TO_SOFTC(pic); 214 int priority_shift; 215 int priority_offset; 216 uint32_t reg; 217 218 KASSERT(is->is_irq < 128); 219 KASSERT(is->is_ipl < 16); 220 KASSERT(is->is_type == IST_LEVEL); 221 222 priority_shift = (is->is_irq % 4) * 8; 223 priority_offset = (is->is_irq / 4); 224 reg = INTC_READ(tzic, TZIC_PRIORITY(priority_offset)); 225 reg &= ~(0xff << priority_shift); 226 reg |= SW_TO_HW_IPL(is->is_ipl) << priority_shift; 227 INTC_WRITE(tzic, TZIC_PRIORITY(priority_offset), reg); 228 } 229 230 void 231 tzic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len) 232 { 233 strlcpy(buf, tzic_intr_source_names[irq], len); 234 } 235 236 void 237 imx51_irq_handler(void *frame) 238 { 239 struct cpu_info * const ci = curcpu(); 240 const int oldipl = ci->ci_cpl; 241 const uint32_t oldipl_mask = __BIT(oldipl); 242 int ipl_mask = 0; 243 244 ci->ci_data.cpu_nintr++; 245 246 if (tzic_softc->sc_enabled_mask[0]) 247 ipl_mask |= find_pending_irqs(tzic_softc, 0); 248 if (tzic_softc->sc_enabled_mask[1]) 249 ipl_mask |= find_pending_irqs(tzic_softc, 1); 250 if (tzic_softc->sc_enabled_mask[2]) 251 ipl_mask |= find_pending_irqs(tzic_softc, 2); 252 if (tzic_softc->sc_enabled_mask[3]) 253 ipl_mask |= find_pending_irqs(tzic_softc, 3); 254 255 if ((ipl_mask & ~oldipl_mask) > oldipl_mask) 256 pic_do_pending_ints(I32_bit, oldipl, frame); 257 } 258 259 static void 260 tzic_intr_init(struct tzic_softc * const tzic) 261 { 262 uint32_t reg; 263 int i; 264 265 disable_interrupts(I32_bit|F32_bit); 266 267 reg = INTC_READ(tzic, TZIC_INTCNTL); 268 INTC_WRITE(tzic, TZIC_INTCNTL, INTCNTL_NSEN_MASK|INTCNTL_NSEN|INTCNTL_EN); 269 reg = INTC_READ(tzic, TZIC_INTCNTL); 270 INTC_WRITE(tzic, TZIC_PRIOMASK, SW_TO_HW_IPL(IPL_NONE)); 271 reg = INTC_READ(tzic, TZIC_PRIOMASK); 272 273 INTC_WRITE(tzic, TZIC_SYNCCTRL, 0x00); 274 reg = INTC_READ(tzic, TZIC_SYNCCTRL); 275 276 /* route all interrupts to IRQ. secure interrupts are for FIQ */ 277 for (i = 0; i < 4; i++) 278 INTC_WRITE(tzic, TZIC_INTSEC(i), 0xffffffff); 279 280 /* disable all interrupts */ 281 for (i = 0; i < 4; i++) 282 INTC_WRITE(tzic, TZIC_ENCLEAR(i), 0xffffffff); 283 284 } 285