exynos5_combiner.c revision 269178
1263936Sbr/*- 2263936Sbr * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3263936Sbr * All rights reserved. 4263936Sbr * 5263936Sbr * Redistribution and use in source and binary forms, with or without 6263936Sbr * modification, are permitted provided that the following conditions 7263936Sbr * are met: 8263936Sbr * 1. Redistributions of source code must retain the above copyright 9263936Sbr * notice, this list of conditions and the following disclaimer. 10263936Sbr * 2. Redistributions in binary form must reproduce the above copyright 11263936Sbr * notice, this list of conditions and the following disclaimer in the 12263936Sbr * documentation and/or other materials provided with the distribution. 13263936Sbr * 14263936Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15263936Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16263936Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17263936Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18263936Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19263936Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20263936Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21263936Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22263936Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23263936Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24263936Sbr * SUCH DAMAGE. 25263936Sbr */ 26263936Sbr 27263936Sbr/* 28263936Sbr * Samsung Exynos 5 Interrupt Combiner 29263936Sbr * Chapter 7, Exynos 5 Dual User's Manual Public Rev 1.00 30263936Sbr */ 31263936Sbr 32263936Sbr#include <sys/cdefs.h> 33263936Sbr__FBSDID("$FreeBSD: head/sys/arm/samsung/exynos/exynos5_combiner.c 269178 2014-07-28 05:37:10Z br $"); 34263936Sbr 35263936Sbr#include <sys/param.h> 36263936Sbr#include <sys/systm.h> 37263936Sbr#include <sys/bus.h> 38263936Sbr#include <sys/kernel.h> 39263936Sbr#include <sys/module.h> 40263936Sbr#include <sys/malloc.h> 41263936Sbr#include <sys/rman.h> 42263936Sbr#include <sys/timeet.h> 43263936Sbr#include <sys/timetc.h> 44263936Sbr#include <sys/watchdog.h> 45263936Sbr 46263936Sbr#include <dev/fdt/fdt_common.h> 47263936Sbr#include <dev/ofw/openfirm.h> 48263936Sbr#include <dev/ofw/ofw_bus.h> 49263936Sbr#include <dev/ofw/ofw_bus_subr.h> 50263936Sbr 51263936Sbr#include <machine/bus.h> 52263936Sbr#include <machine/fdt.h> 53263936Sbr#include <machine/cpu.h> 54263936Sbr#include <machine/intr.h> 55263936Sbr 56263936Sbr#include <arm/samsung/exynos/exynos5_common.h> 57263936Sbr#include <arm/samsung/exynos/exynos5_combiner.h> 58263936Sbr 59263936Sbr#define NGRP 32 60263936Sbr 61263936Sbr#define IESR(n) (0x10 * n + 0x0) /* Interrupt enable set */ 62263936Sbr#define IECR(n) (0x10 * n + 0x4) /* Interrupt enable clear */ 63263936Sbr#define ISTR(n) (0x10 * n + 0x8) /* Interrupt status */ 64263936Sbr#define IMSR(n) (0x10 * n + 0xC) /* Interrupt masked status */ 65263936Sbr#define CIPSR 0x100 /* Combined interrupt pending */ 66263936Sbr 67263936Sbrstruct combiner_softc { 68263936Sbr struct resource *res[1 + NGRP]; 69263936Sbr bus_space_tag_t bst; 70263936Sbr bus_space_handle_t bsh; 71263936Sbr void *ih[NGRP]; 72263936Sbr device_t dev; 73263936Sbr}; 74263936Sbr 75263936Sbrstruct combiner_softc *combiner_sc; 76263936Sbr 77263936Sbrstatic struct resource_spec combiner_spec[] = { 78263936Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 79263936Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, 80263936Sbr { SYS_RES_IRQ, 1, RF_ACTIVE }, 81263936Sbr { SYS_RES_IRQ, 2, RF_ACTIVE }, 82263936Sbr { SYS_RES_IRQ, 3, RF_ACTIVE }, 83263936Sbr { SYS_RES_IRQ, 4, RF_ACTIVE }, 84263936Sbr { SYS_RES_IRQ, 5, RF_ACTIVE }, 85263936Sbr { SYS_RES_IRQ, 6, RF_ACTIVE }, 86263936Sbr { SYS_RES_IRQ, 7, RF_ACTIVE }, 87263936Sbr { SYS_RES_IRQ, 8, RF_ACTIVE }, 88263936Sbr { SYS_RES_IRQ, 9, RF_ACTIVE }, 89263936Sbr { SYS_RES_IRQ, 10, RF_ACTIVE }, 90263936Sbr { SYS_RES_IRQ, 11, RF_ACTIVE }, 91263936Sbr { SYS_RES_IRQ, 12, RF_ACTIVE }, 92263936Sbr { SYS_RES_IRQ, 13, RF_ACTIVE }, 93263936Sbr { SYS_RES_IRQ, 14, RF_ACTIVE }, 94263936Sbr { SYS_RES_IRQ, 15, RF_ACTIVE }, 95263936Sbr { SYS_RES_IRQ, 16, RF_ACTIVE }, 96263936Sbr { SYS_RES_IRQ, 17, RF_ACTIVE }, 97263936Sbr { SYS_RES_IRQ, 18, RF_ACTIVE }, 98263936Sbr { SYS_RES_IRQ, 19, RF_ACTIVE }, 99263936Sbr { SYS_RES_IRQ, 20, RF_ACTIVE }, 100263936Sbr { SYS_RES_IRQ, 21, RF_ACTIVE }, 101263936Sbr { SYS_RES_IRQ, 22, RF_ACTIVE }, 102263936Sbr { SYS_RES_IRQ, 23, RF_ACTIVE }, 103263936Sbr { SYS_RES_IRQ, 24, RF_ACTIVE }, 104263936Sbr { SYS_RES_IRQ, 25, RF_ACTIVE }, 105263936Sbr { SYS_RES_IRQ, 26, RF_ACTIVE }, 106263936Sbr { SYS_RES_IRQ, 27, RF_ACTIVE }, 107263936Sbr { SYS_RES_IRQ, 28, RF_ACTIVE }, 108263936Sbr { SYS_RES_IRQ, 29, RF_ACTIVE }, 109263936Sbr { SYS_RES_IRQ, 30, RF_ACTIVE }, 110263936Sbr { SYS_RES_IRQ, 31, RF_ACTIVE }, 111263936Sbr { -1, 0 } 112263936Sbr}; 113263936Sbr 114263936Sbrstruct combiner_entry { 115263936Sbr int combiner_id; 116263936Sbr int bit; 117263936Sbr char *source_name; 118263936Sbr}; 119263936Sbr 120269178Sbrstatic struct combiner_entry interrupt_table[] = { 121263936Sbr { 63, 1, "EINT[15]" }, 122263936Sbr { 63, 0, "EINT[14]" }, 123263936Sbr { 62, 1, "EINT[13]" }, 124263936Sbr { 62, 0, "EINT[12]" }, 125263936Sbr { 61, 1, "EINT[11]" }, 126263936Sbr { 61, 0, "EINT[10]" }, 127263936Sbr { 60, 1, "EINT[9]" }, 128263936Sbr { 60, 0, "EINT[8]" }, 129263936Sbr { 59, 1, "EINT[7]" }, 130263936Sbr { 59, 0, "EINT[6]" }, 131263936Sbr { 58, 1, "EINT[5]" }, 132263936Sbr { 58, 0, "EINT[4]" }, 133263936Sbr { 57, 3, "MCT_G3" }, 134263936Sbr { 57, 2, "MCT_G2" }, 135263936Sbr { 57, 1, "EINT[3]" }, 136263936Sbr { 57, 0, "EINT[2]" }, 137263936Sbr { 56, 6, "SYSMMU_G2D[1]" }, 138263936Sbr { 56, 5, "SYSMMU_G2D[0]" }, 139263936Sbr { 56, 2, "SYSMMU_FIMC_LITE1[1]" }, 140263936Sbr { 56, 1, "SYSMMU_FIMC_LITE1[0]" }, 141263936Sbr { 56, 0, "EINT[1]" }, 142263936Sbr { 55, 4, "MCT_G1" }, 143263936Sbr { 55, 3, "MCT_G0" }, 144263936Sbr { 55, 0, "EINT[0]" }, 145269178Sbr { 54, 7, "CPU_nCNTVIRQ[1]" }, 146269178Sbr { 54, 6, "CPU_nCTIIRQ[1]" }, 147269178Sbr { 54, 5, "CPU_nCNTPSIRQ[1]" }, 148269178Sbr { 54, 4, "CPU_nPMUIRQ[1]" }, 149269178Sbr { 54, 3, "CPU_nCNTPNSIRQ[1]" }, 150269178Sbr { 54, 2, "CPU_PARITYFAILSCU[1]" }, 151269178Sbr { 54, 1, "CPU_nCNTHPIRQ[1]" }, 152269178Sbr { 54, 0, "PARITYFAIL[1]" }, 153269178Sbr { 53, 1, "CPU_nIRQ[1]" }, 154269178Sbr { 52, 0, "CPU_nIRQ[0]" }, 155269178Sbr { 51, 7, "CPU_nRAMERRIRQ" }, 156269178Sbr { 51, 6, "CPU_nAXIERRIRQ" }, 157269178Sbr { 51, 4, "INT_COMB_ISP_GIC" }, 158269178Sbr { 51, 3, "INT_COMB_IOP_GIC" }, 159269178Sbr { 51, 2, "CCI_nERRORIRQ" }, 160269178Sbr { 51, 1, "INT_COMB_ARMISP_GIC" }, 161269178Sbr { 51, 0, "INT_COMB_ARMIOP_GIC" }, 162269178Sbr { 50, 7, "DISP1[3]" }, 163269178Sbr { 50, 6, "DISP1[2]" }, 164269178Sbr { 50, 5, "DISP1[1]" }, 165269178Sbr { 50, 4, "DISP1[0]" }, 166269178Sbr { 49, 3, "SSCM_PULSE_IRQ_C2CIF[1]" }, 167269178Sbr { 49, 2, "SSCM_PULSE_IRQ_C2CIF[0]" }, 168269178Sbr { 49, 1, "SSCM_IRQ_C2CIF[1]" }, 169269178Sbr { 49, 0, "SSCM_IRQ_C2CIF[0]" }, 170269178Sbr { 48, 3, "PEREV_M1_CDREX" }, 171269178Sbr { 48, 2, "PEREV_M0_CDREX" }, 172269178Sbr { 48, 1, "PEREV_A1_CDREX" }, 173269178Sbr { 48, 0, "PEREV_A0_CDREX" }, 174269178Sbr { 47, 3, "MDMA0_ABORT" }, 175269178Sbr /* 46 is fully reserved */ 176269178Sbr { 45, 1, "MDMA1_ABORT" }, 177269178Sbr /* 44 is fully reserved */ 178269178Sbr { 43, 7, "SYSMMU_DRCISP[1]" }, 179269178Sbr { 43, 6, "SYSMMU_DRCISP[0]" }, 180269178Sbr { 43, 1, "SYSMMU_ODC[1]" }, 181269178Sbr { 43, 0, "SYSMMU_ODC[0]" }, 182269178Sbr { 42, 7, "SYSMMU_ISP[1]" }, 183269178Sbr { 42, 6, "SYSMMU_ISP[0]" }, 184269178Sbr { 42, 5, "SYSMMU_DIS0[1]" }, 185269178Sbr { 42, 4, "SYSMMU_DIS0[0]" }, 186269178Sbr { 42, 3, "DP1" }, 187269178Sbr { 41, 5, "SYSMMU_DIS1[1]" }, 188269178Sbr { 41, 4, "SYSMMU_DIS1[0]" }, 189269178Sbr { 40, 6, "SYSMMU_MFCL[1]" }, 190269178Sbr { 40, 5, "SYSMMU_MFCL[0]" }, 191269178Sbr { 39, 5, "SYSMMU_TV_M0[1]" }, 192269178Sbr { 39, 4, "SYSMMU_TV_M0[0]" }, 193269178Sbr { 39, 3, "SYSMMU_MDMA1[1]" }, 194269178Sbr { 39, 2, "SYSMMU_MDMA1[0]" }, 195269178Sbr { 39, 1, "SYSMMU_MDMA0[1]" }, 196269178Sbr { 39, 0, "SYSMMU_MDMA0[0]" }, 197269178Sbr { 38, 7, "SYSMMU_SSS[1]" }, 198269178Sbr { 38, 6, "SYSMMU_SSS[0]" }, 199269178Sbr { 38, 5, "SYSMMU_RTIC[1]" }, 200269178Sbr { 38, 4, "SYSMMU_RTIC[0]" }, 201269178Sbr { 38, 3, "SYSMMU_MFCR[1]" }, 202269178Sbr { 38, 2, "SYSMMU_MFCR[0]" }, 203269178Sbr { 38, 1, "SYSMMU_ARM[1]" }, 204269178Sbr { 38, 0, "SYSMMU_ARM[0]" }, 205269178Sbr { 37, 7, "SYSMMU_3DNR[1]" }, 206269178Sbr { 37, 6, "SYSMMU_3DNR[0]" }, 207269178Sbr { 37, 5, "SYSMMU_MCUISP[1]" }, 208269178Sbr { 37, 4, "SYSMMU_MCUISP[0]" }, 209269178Sbr { 37, 3, "SYSMMU_SCALERCISP[1]" }, 210269178Sbr { 37, 2, "SYSMMU_SCALERCISP[0]" }, 211269178Sbr { 37, 1, "SYSMMU_FDISP[1]" }, 212269178Sbr { 37, 0, "SYSMMU_FDISP[0]" }, 213269178Sbr { 36, 7, "MCUIOP_CTIIRQ" }, 214269178Sbr { 36, 6, "MCUIOP_PMUIRQ" }, 215269178Sbr { 36, 5, "MCUISP_CTIIRQ" }, 216269178Sbr { 36, 4, "MCUISP_PMUIRQ" }, 217269178Sbr { 36, 3, "SYSMMU_JPEGX[1]" }, 218269178Sbr { 36, 2, "SYSMMU_JPEGX[0]" }, 219269178Sbr { 36, 1, "SYSMMU_ROTATOR[1]" }, 220269178Sbr { 36, 0, "SYSMMU_ROTATOR[0]" }, 221269178Sbr { 35, 7, "SYSMMU_SCALERPISP[1]" }, 222269178Sbr { 35, 6, "SYSMMU_SCALERPISP[0]" }, 223269178Sbr { 35, 5, "SYSMMU_FIMC_LITE0[1]" }, 224269178Sbr { 35, 4, "SYSMMU_FIMC_LITE0[0]" }, 225269178Sbr { 35, 3, "SYSMMU_DISP1_M0[1]" }, 226269178Sbr { 35, 2, "SYSMMU_DISP1_M0[0]" }, 227269178Sbr { 35, 1, "SYSMMU_FIMC_LITE2[1]" }, 228269178Sbr { 35, 0, "SYSMMU_FIMC_LITE2[0]" }, 229269178Sbr { 34, 7, "SYSMMU_GSCL3[1]" }, 230269178Sbr { 34, 6, "SYSMMU_GSCL3[0]" }, 231269178Sbr { 34, 5, "SYSMMU_GSCL2[1]" }, 232269178Sbr { 34, 4, "SYSMMU_GSCL2[0]" }, 233269178Sbr { 34, 3, "SYSMMU_GSCL1[1]" }, 234269178Sbr { 34, 2, "SYSMMU_GSCL1[0]" }, 235269178Sbr { 34, 1, "SYSMMU_GSCL0[1]" }, 236269178Sbr { 34, 0, "SYSMMU_GSCL0[0]" }, 237269178Sbr { 33, 7, "CPU_nCNTVIRQ[0]" }, 238269178Sbr { 33, 6, "CPU_nCNTPSIRQ[0]" }, 239269178Sbr { 33, 5, "CPU_nCNTPSNIRQ[0]" }, 240269178Sbr { 33, 4, "CPU_nCNTHPIRQ[0]" }, 241269178Sbr { 33, 3, "CPU_nCTIIRQ[0]" }, 242269178Sbr { 33, 2, "CPU_nPMUIRQ[0]" }, 243269178Sbr { 33, 1, "CPU_PARITYFAILSCU[0]" }, 244269178Sbr { 33, 0, "CPU_PARITYFAIL0" }, 245269178Sbr { 32, 7, "TZASC_XR1BXW" }, 246269178Sbr { 32, 6, "TZASC_XR1BXR" }, 247269178Sbr { 32, 5, "TZASC_XLBXW" }, 248269178Sbr { 32, 4, "TZASC_XLBXR" }, 249269178Sbr { 32, 3, "TZASC_DRBXW" }, 250269178Sbr { 32, 2, "TZASC_DRBXR" }, 251269178Sbr { 32, 1, "TZASC_CBXW" }, 252269178Sbr { 32, 0, "TZASC_CBXR" }, 253263936Sbr 254269178Sbr { -1, -1, NULL }, 255263936Sbr}; 256263936Sbr 257263936Sbrstruct combined_intr { 258263936Sbr uint32_t enabled; 259263936Sbr void (*ih) (void *); 260263936Sbr void *ih_user; 261263936Sbr}; 262263936Sbr 263263936Sbrstatic struct combined_intr intr_map[32][8]; 264263936Sbr 265263936Sbrstatic void 266263936Sbrcombiner_intr(void *arg) 267263936Sbr{ 268263936Sbr struct combiner_softc *sc; 269263936Sbr void (*ih) (void *); 270263936Sbr void *ih_user; 271263936Sbr int enabled; 272263936Sbr int intrs; 273263936Sbr int shift; 274263936Sbr int cirq; 275263936Sbr int grp; 276263936Sbr int i,n; 277263936Sbr 278263936Sbr sc = arg; 279263936Sbr 280263936Sbr intrs = READ4(sc, CIPSR); 281263936Sbr for (grp = 0; grp < 32; grp++) { 282263936Sbr if (intrs & (1 << grp)) { 283263936Sbr n = (grp / 4); 284263936Sbr shift = (grp % 4) * 8; 285263936Sbr 286263936Sbr cirq = READ4(sc, ISTR(n)); 287263936Sbr for (i = 0; i < 8; i++) { 288263936Sbr if (cirq & (1 << (i + shift))) { 289263936Sbr ih = intr_map[grp][i].ih; 290263936Sbr ih_user = intr_map[grp][i].ih_user; 291263936Sbr enabled = intr_map[grp][i].enabled; 292263936Sbr if (enabled && (ih != NULL)) { 293263936Sbr ih(ih_user); 294263936Sbr } 295263936Sbr } 296263936Sbr } 297263936Sbr } 298263936Sbr } 299263936Sbr} 300263936Sbr 301263936Sbrvoid 302263936Sbrcombiner_setup_intr(char *source_name, void (*ih)(void *), void *ih_user) 303263936Sbr{ 304263936Sbr struct combiner_entry *entry; 305263936Sbr struct combined_intr *cirq; 306263936Sbr struct combiner_softc *sc; 307263936Sbr int shift; 308263936Sbr int reg; 309263936Sbr int grp; 310263936Sbr int n; 311263936Sbr int i; 312263936Sbr 313263936Sbr sc = combiner_sc; 314263936Sbr 315263936Sbr if (sc == NULL) { 316263936Sbr device_printf(sc->dev, "Error: combiner is not attached\n"); 317263936Sbr return; 318263936Sbr } 319263936Sbr 320263936Sbr entry = NULL; 321263936Sbr 322269178Sbr for (i = 0; i < NGRP && interrupt_table[i].bit != -1; i++) { 323263936Sbr if (strcmp(interrupt_table[i].source_name, source_name) == 0) { 324263936Sbr entry = &interrupt_table[i]; 325263936Sbr } 326263936Sbr } 327263936Sbr 328263936Sbr if (entry == NULL) { 329263936Sbr device_printf(sc->dev, "Can't find interrupt name %s\n", 330263936Sbr source_name); 331263936Sbr return; 332263936Sbr } 333263936Sbr 334263936Sbr#if 0 335263936Sbr device_printf(sc->dev, "Setting up interrupt %s\n", source_name); 336263936Sbr#endif 337263936Sbr 338263936Sbr grp = entry->combiner_id - 32; 339263936Sbr 340263936Sbr cirq = &intr_map[grp][entry->bit]; 341263936Sbr cirq->enabled = 1; 342263936Sbr cirq->ih = ih; 343263936Sbr cirq->ih_user = ih_user; 344263936Sbr 345263936Sbr n = grp / 4; 346263936Sbr shift = (grp % 4) * 8 + entry->bit; 347263936Sbr 348263936Sbr reg = (1 << shift); 349263936Sbr WRITE4(sc, IESR(n), reg); 350263936Sbr} 351263936Sbr 352263936Sbrstatic int 353263936Sbrcombiner_probe(device_t dev) 354263936Sbr{ 355263936Sbr 356263936Sbr if (!ofw_bus_is_compatible(dev, "exynos,combiner")) 357263936Sbr return (ENXIO); 358263936Sbr 359263936Sbr device_set_desc(dev, "Samsung Exynos 5 Interrupt Combiner"); 360263936Sbr return (BUS_PROBE_DEFAULT); 361263936Sbr} 362263936Sbr 363263936Sbrstatic int 364263936Sbrcombiner_attach(device_t dev) 365263936Sbr{ 366263936Sbr struct combiner_softc *sc; 367263936Sbr int err; 368263936Sbr int i; 369263936Sbr 370263936Sbr sc = device_get_softc(dev); 371263936Sbr sc->dev = dev; 372263936Sbr 373263936Sbr if (bus_alloc_resources(dev, combiner_spec, sc->res)) { 374263936Sbr device_printf(dev, "could not allocate resources\n"); 375263936Sbr return (ENXIO); 376263936Sbr } 377263936Sbr 378263936Sbr /* Memory interface */ 379263936Sbr sc->bst = rman_get_bustag(sc->res[0]); 380263936Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 381263936Sbr 382263936Sbr combiner_sc = sc; 383263936Sbr 384263936Sbr /* Setup interrupt handler */ 385263936Sbr for (i = 0; i < NGRP; i++) { 386263936Sbr err = bus_setup_intr(dev, sc->res[1+i], INTR_TYPE_BIO | \ 387263936Sbr INTR_MPSAFE, NULL, combiner_intr, sc, &sc->ih[i]); 388263936Sbr if (err) { 389263936Sbr device_printf(dev, "Unable to alloc int resource.\n"); 390263936Sbr return (ENXIO); 391263936Sbr } 392263936Sbr } 393263936Sbr 394263936Sbr return (0); 395263936Sbr} 396263936Sbr 397263936Sbrstatic device_method_t combiner_methods[] = { 398263936Sbr DEVMETHOD(device_probe, combiner_probe), 399263936Sbr DEVMETHOD(device_attach, combiner_attach), 400263936Sbr { 0, 0 } 401263936Sbr}; 402263936Sbr 403263936Sbrstatic driver_t combiner_driver = { 404263936Sbr "combiner", 405263936Sbr combiner_methods, 406263936Sbr sizeof(struct combiner_softc), 407263936Sbr}; 408263936Sbr 409263936Sbrstatic devclass_t combiner_devclass; 410263936Sbr 411263936SbrDRIVER_MODULE(combiner, simplebus, combiner_driver, combiner_devclass, 0, 0); 412