Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36ba5d52 authored by Thomas Abraham's avatar Thomas Abraham Committed by Kukjin Kim
Browse files

ARM: EXYNOS: add device tree support for MCT controller driver



Allow the MCT controller base address and interrupts to be
obtained from device tree and remove unused static definitions
of these. The non-dt support for Exynos5250 is removed but
retained for Exynos4210 based platforms.

Cc: Changhwan Youn <chaos.youn@samsung.com>
Signed-off-by: default avatarThomas Abraham <thomas.abraham@linaro.org>
Reviewed-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarKukjin Kim <kgene.kim@samsung.com>
parent c371dc60
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
Samsung's Multi Core Timer (MCT)

The Samsung's Multi Core Timer (MCT) module includes two main blocks, the
global timer and CPU local timers. The global timer is a 64-bit free running
up-counter and can generate 4 interrupts when the counter reaches one of the
four preset counter values. The CPU local timers are 32-bit free running
down-counters and generate an interrupt when the counter expires. There is
one CPU local timer instantiated in MCT for every CPU in the system.

Required properties:

- compatible: should be "samsung,exynos4210-mct".
  (a) "samsung,exynos4210-mct", for mct compatible with Exynos4210 mct.
  (b) "samsung,exynos4412-mct", for mct compatible with Exynos4412 mct.

- reg: base address of the mct controller and length of the address space
  it occupies.

- interrupts: the list of interrupts generated by the controller. The following
  should be the order of the interrupts specified. The local timer interrupts
  should be specified after the four global timer interrupts have been
  specified.

	0: Global Timer Interrupt 0
	1: Global Timer Interrupt 1
	2: Global Timer Interrupt 2
	3: Global Timer Interrupt 3
	4: Local Timer Interrupt 0
	5: Local Timer Interrupt 1
	6: ..
	7: ..
	i: Local Timer Interrupt n

Example 1: In this example, the system uses only the first global timer
	   interrupt generated by MCT and the remaining three global timer
	   interrupts are unused. Two local timer interrupts have been
	   specified.

	mct@10050000 {
		compatible = "samsung,exynos4210-mct";
		reg = <0x10050000 0x800>;
		interrupts = <0 57 0>, <0 0 0>, <0 0 0>, <0 0 0>,
			     <0 42 0>, <0 48 0>;
	};

Example 2: In this example, the MCT global and local timer interrupts are
	   connected to two seperate interrupt controllers. Hence, an
	   interrupt-map is created to map the interrupts to the respective
	   interrupt controllers.

	mct@101C0000 {
		compatible = "samsung,exynos4210-mct";
		reg = <0x101C0000 0x800>;
		interrupt-controller;
		#interrups-cells = <2>;
		interrupt-parent = <&mct_map>;
		interrupts = <0 0>, <1 0>, <2 0>, <3 0>,
			     <4 0>, <5 0>;

		mct_map: mct-map {
			#interrupt-cells = <2>;
			#address-cells = <0>;
			#size-cells = <0>;
			interrupt-map = <0x0 0 &combiner 23 3>,
					<0x4 0 &gic 0 120 0>,
					<0x5 0 &gic 0 121 0>;
		};
	};
+0 −6
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@

/* For EXYNOS4 and EXYNOS5 */

#define EXYNOS_IRQ_MCT_LOCALTIMER	IRQ_PPI(12)

#define EXYNOS_IRQ_EINT16_31		IRQ_SPI(32)

/* For EXYNOS4 SoCs */
@@ -323,8 +321,6 @@
#define EXYNOS5_IRQ_CEC			IRQ_SPI(114)
#define EXYNOS5_IRQ_SATA		IRQ_SPI(115)

#define EXYNOS5_IRQ_MCT_L0		IRQ_SPI(120)
#define EXYNOS5_IRQ_MCT_L1		IRQ_SPI(121)
#define EXYNOS5_IRQ_MMC44		IRQ_SPI(123)
#define EXYNOS5_IRQ_MDMA1		IRQ_SPI(124)
#define EXYNOS5_IRQ_FIMC_LITE0		IRQ_SPI(125)
@@ -419,8 +415,6 @@
#define EXYNOS5_IRQ_PMU_CPU1		COMBINER_IRQ(22, 4)

#define EXYNOS5_IRQ_EINT0		COMBINER_IRQ(23, 0)
#define EXYNOS5_IRQ_MCT_G0		COMBINER_IRQ(23, 3)
#define EXYNOS5_IRQ_MCT_G1		COMBINER_IRQ(23, 4)

#define EXYNOS5_IRQ_EINT1		COMBINER_IRQ(24, 0)
#define EXYNOS5_IRQ_SYSMMU_LITE1_0	COMBINER_IRQ(24, 1)
+37 −12
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <linux/delay.h>
#include <linux/percpu.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>

#include <asm/arch_timer.h>
#include <asm/localtimer.h>
@@ -474,14 +476,16 @@ static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
};
#endif /* CONFIG_LOCAL_TIMERS */

static void __init exynos4_timer_resources(void)
static void __init exynos4_timer_resources(struct device_node *np)
{
	struct clk *mct_clk;
	mct_clk = clk_get(NULL, "xtal");

	clk_rate = clk_get_rate(mct_clk);

	reg_base = S5P_VA_SYSTIMER;
	reg_base = np ? of_iomap(np, 0) : S5P_VA_SYSTIMER;
	if (!reg_base)
		panic("%s: unable to ioremap mct address space\n", __func__);

#ifdef CONFIG_LOCAL_TIMERS
	if (mct_int_type == MCT_INT_PPI) {
@@ -498,30 +502,51 @@ static void __init exynos4_timer_resources(void)
#endif /* CONFIG_LOCAL_TIMERS */
}

static const struct of_device_id exynos_mct_ids[] = {
	{ .compatible = "samsung,exynos4210-mct", .data = (void *)MCT_INT_SPI },
	{ .compatible = "samsung,exynos4412-mct", .data = (void *)MCT_INT_PPI },
};

void __init exynos4_timer_init(void)
{
	struct device_node *np = NULL;
	const struct of_device_id *match;
	u32 nr_irqs, i;

	if (soc_is_exynos5440()) {
		arch_timer_of_register();
		return;
	}

	if (soc_is_exynos4210()) {
#ifdef CONFIG_OF
	np = of_find_matching_node_and_match(NULL, exynos_mct_ids, &match);
#endif
	if (np) {
		mct_int_type = (u32)(match->data);

		/* This driver uses only one global timer interrupt */
		mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);

		/*
		 * Find out the number of local irqs specified. The local
		 * timer irqs are specified after the four global timer
		 * irqs are specified.
		 */
#ifdef CONFIG_OF
		nr_irqs = of_irq_count(np);
#endif
		for (i = MCT_L0_IRQ; i < nr_irqs; i++)
			mct_irqs[i] = irq_of_parse_and_map(np, i);
	} else if (soc_is_exynos4210()) {
		mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0;
		mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0;
		mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1;
		mct_int_type = MCT_INT_SPI;
	} else if (soc_is_exynos5250()) {
		mct_irqs[MCT_G0_IRQ] = EXYNOS5_IRQ_MCT_G0;
		mct_irqs[MCT_L0_IRQ] = EXYNOS5_IRQ_MCT_L0;
		mct_irqs[MCT_L1_IRQ] = EXYNOS5_IRQ_MCT_L1;
		mct_int_type = MCT_INT_SPI;
	} else {
		mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0;
		mct_irqs[MCT_L0_IRQ] = EXYNOS_IRQ_MCT_LOCALTIMER;
		mct_int_type = MCT_INT_PPI;
		panic("unable to determine mct controller type\n");
	}

	exynos4_timer_resources();
	exynos4_timer_resources(np);
	exynos4_clocksource_init();
	exynos4_clockevent_init();
}