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