exynos5_combiner.c revision 285830
11449Stomee/*- 21449Stomee * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 31449Stomee * All rights reserved. 41449Stomee * 51449Stomee * Redistribution and use in source and binary forms, with or without 61449Stomee * modification, are permitted provided that the following conditions 71449Stomee * are met: 81449Stomee * 1. Redistributions of source code must retain the above copyright 91449Stomee * notice, this list of conditions and the following disclaimer. 101449Stomee * 2. Redistributions in binary form must reproduce the above copyright 111449Stomee * notice, this list of conditions and the following disclaimer in the 121449Stomee * documentation and/or other materials provided with the distribution. 131449Stomee * 141449Stomee * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151449Stomee * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161449Stomee * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171449Stomee * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181449Stomee * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191449Stomee * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201449Stomee * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211449Stomee * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221449Stomee * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236136Stomee * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241449Stomee * SUCH DAMAGE. 251449Stomee */ 261449Stomee 271449Stomee/* 281449Stomee * Samsung Exynos 5 Interrupt Combiner 291449Stomee * Chapter 7, Exynos 5 Dual User's Manual Public Rev 1.00 301449Stomee */ 311449Stomee 321449Stomee#include <sys/cdefs.h> 331449Stomee__FBSDID("$FreeBSD: releng/10.2/sys/arm/samsung/exynos/exynos5_combiner.c 266341 2014-05-17 19:37:04Z ian $"); 341449Stomee 351449Stomee#include <sys/param.h> 361449Stomee#include <sys/systm.h> 371449Stomee#include <sys/bus.h> 381449Stomee#include <sys/kernel.h> 391449Stomee#include <sys/module.h> 401449Stomee#include <sys/malloc.h> 411449Stomee#include <sys/rman.h> 421449Stomee#include <sys/timeet.h> 436136Stomee#include <sys/timetc.h> 441449Stomee#include <sys/watchdog.h> 451449Stomee 461449Stomee#include <dev/fdt/fdt_common.h> 471449Stomee#include <dev/ofw/openfirm.h> 481449Stomee#include <dev/ofw/ofw_bus.h> 491449Stomee#include <dev/ofw/ofw_bus_subr.h> 506136Stomee 511449Stomee#include <machine/bus.h> 521449Stomee#include <machine/fdt.h> 531449Stomee#include <machine/cpu.h> 541449Stomee#include <machine/intr.h> 551449Stomee 561449Stomee#include <arm/samsung/exynos/exynos5_common.h> 571449Stomee#include <arm/samsung/exynos/exynos5_combiner.h> 581449Stomee 591449Stomee#define NGRP 32 601449Stomee#define ITABLE_LEN 24 611449Stomee 621449Stomee#define IESR(n) (0x10 * n + 0x0) /* Interrupt enable set */ 631449Stomee#define IECR(n) (0x10 * n + 0x4) /* Interrupt enable clear */ 641449Stomee#define ISTR(n) (0x10 * n + 0x8) /* Interrupt status */ 651449Stomee#define IMSR(n) (0x10 * n + 0xC) /* Interrupt masked status */ 661449Stomee#define CIPSR 0x100 /* Combined interrupt pending */ 671449Stomee 681449Stomeestruct combiner_softc { 691449Stomee struct resource *res[1 + NGRP]; 701449Stomee bus_space_tag_t bst; 711449Stomee bus_space_handle_t bsh; 721449Stomee void *ih[NGRP]; 731449Stomee device_t dev; 741449Stomee}; 751449Stomee 761449Stomeestruct combiner_softc *combiner_sc; 771449Stomee 786136Stomeestatic struct resource_spec combiner_spec[] = { 796136Stomee { SYS_RES_MEMORY, 0, RF_ACTIVE }, 806136Stomee { SYS_RES_IRQ, 0, RF_ACTIVE }, 811449Stomee { SYS_RES_IRQ, 1, RF_ACTIVE }, 821449Stomee { SYS_RES_IRQ, 2, RF_ACTIVE }, 831449Stomee { SYS_RES_IRQ, 3, RF_ACTIVE }, 841449Stomee { SYS_RES_IRQ, 4, RF_ACTIVE }, 851449Stomee { SYS_RES_IRQ, 5, RF_ACTIVE }, 866136Stomee { SYS_RES_IRQ, 6, RF_ACTIVE }, 876136Stomee { SYS_RES_IRQ, 7, RF_ACTIVE }, 886136Stomee { SYS_RES_IRQ, 8, RF_ACTIVE }, 896136Stomee { SYS_RES_IRQ, 9, RF_ACTIVE }, 906136Stomee { SYS_RES_IRQ, 10, RF_ACTIVE }, 916136Stomee { SYS_RES_IRQ, 11, RF_ACTIVE }, 926136Stomee { SYS_RES_IRQ, 12, RF_ACTIVE }, 936136Stomee { SYS_RES_IRQ, 13, RF_ACTIVE }, 946136Stomee { SYS_RES_IRQ, 14, RF_ACTIVE }, 956136Stomee { SYS_RES_IRQ, 15, RF_ACTIVE }, 966136Stomee { SYS_RES_IRQ, 16, RF_ACTIVE }, 976136Stomee { SYS_RES_IRQ, 17, RF_ACTIVE }, 986136Stomee { SYS_RES_IRQ, 18, RF_ACTIVE }, 996136Stomee { SYS_RES_IRQ, 19, RF_ACTIVE }, 1006136Stomee { SYS_RES_IRQ, 20, RF_ACTIVE }, 1016136Stomee { SYS_RES_IRQ, 21, RF_ACTIVE }, 1026136Stomee { SYS_RES_IRQ, 22, RF_ACTIVE }, 1036136Stomee { SYS_RES_IRQ, 23, RF_ACTIVE }, 1046136Stomee { SYS_RES_IRQ, 24, RF_ACTIVE }, 1051449Stomee { SYS_RES_IRQ, 25, RF_ACTIVE }, 1061449Stomee { SYS_RES_IRQ, 26, RF_ACTIVE }, 1071449Stomee { SYS_RES_IRQ, 27, RF_ACTIVE }, 1081449Stomee { SYS_RES_IRQ, 28, RF_ACTIVE }, 1091449Stomee { SYS_RES_IRQ, 29, RF_ACTIVE }, 1101449Stomee { SYS_RES_IRQ, 30, RF_ACTIVE }, 1116136Stomee { SYS_RES_IRQ, 31, RF_ACTIVE }, 1126136Stomee { -1, 0 } 1131449Stomee}; 1141449Stomee 1156136Stomeestruct combiner_entry { 1161449Stomee int combiner_id; 1171449Stomee int bit; 1186136Stomee char *source_name; 1191449Stomee}; 1201449Stomee 1211449Stomeestatic struct combiner_entry interrupt_table[ITABLE_LEN] = { 1226136Stomee { 63, 1, "EINT[15]" }, 1231449Stomee { 63, 0, "EINT[14]" }, 1241449Stomee { 62, 1, "EINT[13]" }, 1251449Stomee { 62, 0, "EINT[12]" }, 1263483Stomee { 61, 1, "EINT[11]" }, 1271449Stomee { 61, 0, "EINT[10]" }, 1281449Stomee { 60, 1, "EINT[9]" }, 1291449Stomee { 60, 0, "EINT[8]" }, 1301449Stomee { 59, 1, "EINT[7]" }, 1311449Stomee { 59, 0, "EINT[6]" }, 1321449Stomee { 58, 1, "EINT[5]" }, 1331449Stomee { 58, 0, "EINT[4]" }, 1341449Stomee { 57, 3, "MCT_G3" }, 1356136Stomee { 57, 2, "MCT_G2" }, 1366136Stomee { 57, 1, "EINT[3]" }, 1376136Stomee { 57, 0, "EINT[2]" }, 1381449Stomee { 56, 6, "SYSMMU_G2D[1]" }, 1391449Stomee { 56, 5, "SYSMMU_G2D[0]" }, 1401449Stomee { 56, 2, "SYSMMU_FIMC_LITE1[1]" }, 1411449Stomee { 56, 1, "SYSMMU_FIMC_LITE1[0]" }, 1421449Stomee { 56, 0, "EINT[1]" }, 1431449Stomee { 55, 4, "MCT_G1" }, 1441449Stomee { 55, 3, "MCT_G0" }, 1451449Stomee { 55, 0, "EINT[0]" }, 1461449Stomee 1471449Stomee /* TODO: add groups 54-32 */ 1481449Stomee}; 1491449Stomee 1501449Stomeestruct combined_intr { 1511449Stomee uint32_t enabled; 1521449Stomee void (*ih) (void *); 1531449Stomee void *ih_user; 1541449Stomee}; 1551449Stomee 1561449Stomeestatic struct combined_intr intr_map[32][8]; 1571449Stomee 1581449Stomeestatic void 1591449Stomeecombiner_intr(void *arg) 1601449Stomee{ 1611449Stomee struct combiner_softc *sc; 1621449Stomee void (*ih) (void *); 1631449Stomee void *ih_user; 1641449Stomee int enabled; 1651449Stomee int intrs; 1661449Stomee int shift; 1671449Stomee int cirq; 1681449Stomee int grp; 1691449Stomee int i,n; 1706136Stomee 1716136Stomee sc = arg; 1726136Stomee 1736136Stomee intrs = READ4(sc, CIPSR); 1746136Stomee for (grp = 0; grp < 32; grp++) { 1756136Stomee if (intrs & (1 << grp)) { 1766136Stomee n = (grp / 4); 1776136Stomee shift = (grp % 4) * 8; 1786136Stomee 1796136Stomee cirq = READ4(sc, ISTR(n)); 1806136Stomee for (i = 0; i < 8; i++) { 1816136Stomee if (cirq & (1 << (i + shift))) { 1826136Stomee ih = intr_map[grp][i].ih; 1836136Stomee ih_user = intr_map[grp][i].ih_user; 1846136Stomee enabled = intr_map[grp][i].enabled; 1856136Stomee if (enabled && (ih != NULL)) { 1866136Stomee ih(ih_user); 1876136Stomee } 1886136Stomee } 1896136Stomee } 1906136Stomee } 1916136Stomee } 1926136Stomee} 1936136Stomee 1946136Stomeevoid 1956136Stomeecombiner_setup_intr(char *source_name, void (*ih)(void *), void *ih_user) 1966136Stomee{ 1976136Stomee struct combiner_entry *entry; 1986136Stomee struct combined_intr *cirq; 1996136Stomee struct combiner_softc *sc; 2006136Stomee int shift; 2016136Stomee int reg; 2021449Stomee int grp; 2031449Stomee int n; 2041449Stomee int i; 2051449Stomee 2061449Stomee sc = combiner_sc; 2071449Stomee 2081449Stomee if (sc == NULL) { 2091449Stomee device_printf(sc->dev, "Error: combiner is not attached\n"); 2101449Stomee return; 2111449Stomee } 2121449Stomee 2131449Stomee entry = NULL; 2141449Stomee 2151449Stomee for (i = 0; i < ITABLE_LEN; i++) { 2161449Stomee if (strcmp(interrupt_table[i].source_name, source_name) == 0) { 2171449Stomee entry = &interrupt_table[i]; 2181449Stomee } 2191449Stomee } 2201449Stomee 2211449Stomee if (entry == NULL) { 2221449Stomee device_printf(sc->dev, "Can't find interrupt name %s\n", 2231449Stomee source_name); 2241449Stomee return; 2251449Stomee } 2261449Stomee 2271449Stomee#if 0 2281449Stomee device_printf(sc->dev, "Setting up interrupt %s\n", source_name); 2291449Stomee#endif 2301449Stomee 2311449Stomee grp = entry->combiner_id - 32; 2321449Stomee 2331449Stomee cirq = &intr_map[grp][entry->bit]; 2341449Stomee cirq->enabled = 1; 2351449Stomee cirq->ih = ih; 2361449Stomee cirq->ih_user = ih_user; 2371449Stomee 2381449Stomee n = grp / 4; 2391449Stomee shift = (grp % 4) * 8 + entry->bit; 2401449Stomee 2411449Stomee reg = (1 << shift); 2421449Stomee WRITE4(sc, IESR(n), reg); 2433645Stomee} 2443645Stomee 2453645Stomeestatic int 2463645Stomeecombiner_probe(device_t dev) 2471449Stomee{ 2481449Stomee 2491449Stomee if (!ofw_bus_is_compatible(dev, "exynos,combiner")) 2501449Stomee return (ENXIO); 2511449Stomee 2521449Stomee device_set_desc(dev, "Samsung Exynos 5 Interrupt Combiner"); 2531449Stomee return (BUS_PROBE_DEFAULT); 2541449Stomee} 2551449Stomee 2561449Stomeestatic int 2571449Stomeecombiner_attach(device_t dev) 2581449Stomee{ 2591449Stomee struct combiner_softc *sc; 2601449Stomee int err; 2611449Stomee int i; 2621449Stomee 2633645Stomee sc = device_get_softc(dev); 2641449Stomee sc->dev = dev; 2651449Stomee 2661449Stomee if (bus_alloc_resources(dev, combiner_spec, sc->res)) { 2671449Stomee device_printf(dev, "could not allocate resources\n"); 2681449Stomee return (ENXIO); 2691449Stomee } 2701449Stomee 2711449Stomee /* Memory interface */ 2721449Stomee sc->bst = rman_get_bustag(sc->res[0]); 273 sc->bsh = rman_get_bushandle(sc->res[0]); 274 275 combiner_sc = sc; 276 277 /* Setup interrupt handler */ 278 for (i = 0; i < NGRP; i++) { 279 err = bus_setup_intr(dev, sc->res[1+i], INTR_TYPE_BIO | \ 280 INTR_MPSAFE, NULL, combiner_intr, sc, &sc->ih[i]); 281 if (err) { 282 device_printf(dev, "Unable to alloc int resource.\n"); 283 return (ENXIO); 284 } 285 } 286 287 return (0); 288} 289 290static device_method_t combiner_methods[] = { 291 DEVMETHOD(device_probe, combiner_probe), 292 DEVMETHOD(device_attach, combiner_attach), 293 { 0, 0 } 294}; 295 296static driver_t combiner_driver = { 297 "combiner", 298 combiner_methods, 299 sizeof(struct combiner_softc), 300}; 301 302static devclass_t combiner_devclass; 303 304DRIVER_MODULE(combiner, simplebus, combiner_driver, combiner_devclass, 0, 0); 305