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

Commit 6d49d535 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge branch 'next/devel-exynos5250-1' of...

Merge branch 'next/devel-exynos5250-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/soc2

* 'next/devel-exynos5250-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung

:
  ARM: EXYNOS: Add AUXDATA for i2c controllers
  ARM: dts: Update device tree source files for EXYNOS5250
  ARM: EXYNOS: Add device tree support for interrupt combiner
  ARM: EXYNOS: Add irq_domain support for interrupt combiner
  ARM: EXYNOS: Remove a new bus_type instance for EXYNOS5
  ARM: EXYNOS: update irqs for EXYNOS5250 SoC
  ARM: EXYNOS: Add pre-divider and fout mux clocks for bpll and mpll
  ARM: EXYNOS: add GPC4 bank instance
  ARM: EXYNOS: Redefine IRQ_MCT_L0,1 definition
  ARM: EXYNOS: Modify the GIC physical address for static io-mapping
  ARM: EXYNOS: Add watchdog timer clock instance

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents a551204b 380c3a54
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
* Samsung Exynos Interrupt Combiner Controller

Samsung's Exynos4 architecture includes a interrupt combiner controller which
can combine interrupt sources as a group and provide a single interrupt request
for the group. The interrupt request from each group are connected to a parent
interrupt controller, such as GIC in case of Exynos4210.

The interrupt combiner controller consists of multiple combiners. Upto eight
interrupt sources can be connected to a combiner. The combiner outputs one
combined interrupt for its eight interrupt sources. The combined interrupt
is usually connected to a parent interrupt controller.

A single node in the device tree is used to describe the interrupt combiner
controller module (which includes multiple combiners). A combiner in the
interrupt controller module shares config/control registers with other
combiners. For example, a 32-bit interrupt enable/disable config register
can accommodate upto 4 interrupt combiners (with each combiner supporting
upto 8 interrupt sources).

Required properties:
- compatible: should be "samsung,exynos4210-combiner".
- interrupt-controller: Identifies the node as an interrupt controller.
- #interrupt-cells: should be <2>. The meaning of the cells are
	* First Cell: Combiner Group Number.
	* Second Cell: Interrupt number within the group.
- reg: Base address and size of interrupt combiner registers.
- interrupts: The list of interrupts generated by the combiners which are then
    connected to a parent interrupt controller. The format of the interrupt
    specifier depends in the interrupt parent controller.

Optional properties:
- samsung,combiner-nr: The number of interrupt combiners supported. If this
  property is not specified, the default number of combiners is assumed
  to be 16.
- interrupt-parent: pHandle of the parent interrupt controller, if not
  inherited from the parent node.


Example:

	The following is a an example from the Exynos4210 SoC dtsi file.

	combiner:interrupt-controller@10440000 {
		compatible = "samsung,exynos4210-combiner";
		interrupt-controller;
		#interrupt-cells = <2>;
		reg = <0x10440000 0x1000>;
		interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
			     <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
			     <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
			     <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
	};
+48 −0
Original line number Diff line number Diff line
@@ -23,4 +23,52 @@
	chosen {
		bootargs = "root=/dev/ram0 rw ramdisk=8192 console=ttySAC1,115200";
	};

	i2c@12C60000 {
		samsung,i2c-sda-delay = <100>;
		samsung,i2c-max-bus-freq = <20000>;
		gpios = <&gpb3 0 2 3 0>,
			<&gpb3 1 2 3 0>;

		eeprom@50 {
			compatible = "samsung,s524ad0xd1";
			reg = <0x50>;
		};
	};

	i2c@12C70000 {
		samsung,i2c-sda-delay = <100>;
		samsung,i2c-max-bus-freq = <20000>;
		gpios = <&gpb3 2 2 3 0>,
			<&gpb3 3 2 3 0>;

		eeprom@51 {
			compatible = "samsung,s524ad0xd1";
			reg = <0x51>;
		};
	};

	i2c@12C80000 {
		status = "disabled";
	};

	i2c@12C90000 {
		status = "disabled";
	};

	i2c@12CA0000 {
		status = "disabled";
	};

	i2c@12CB0000 {
		status = "disabled";
	};

	i2c@12CC0000 {
		status = "disabled";
	};

	i2c@12CD0000 {
		status = "disabled";
	};
};
+29 −31
Original line number Diff line number Diff line
@@ -23,11 +23,11 @@
	compatible = "samsung,exynos5250";
	interrupt-parent = <&gic>;

	gic:interrupt-controller@10490000 {
	gic:interrupt-controller@10481000 {
		compatible = "arm,cortex-a9-gic";
		#interrupt-cells = <3>;
		interrupt-controller;
		reg = <0x10490000 0x1000>, <0x10480000 0x100>;
		reg = <0x10481000 0x1000>, <0x10482000 0x2000>;
	};

	watchdog {
@@ -42,30 +42,6 @@
		interrupts = <0 43 0>, <0 44 0>;
	};

	sdhci@12200000 {
		compatible = "samsung,exynos4210-sdhci";
		reg = <0x12200000 0x100>;
		interrupts = <0 75 0>;
	};

	sdhci@12210000 {
		compatible = "samsung,exynos4210-sdhci";
		reg = <0x12210000 0x100>;
		interrupts = <0 76 0>;
	};

	sdhci@12220000 {
		compatible = "samsung,exynos4210-sdhci";
		reg = <0x12220000 0x100>;
		interrupts = <0 77 0>;
	};

	sdhci@12230000 {
		compatible = "samsung,exynos4210-sdhci";
		reg = <0x12230000 0x100>;
		interrupts = <0 78 0>;
	};

	serial@12C00000 {
		compatible = "samsung,exynos4210-uart";
		reg = <0x12C00000 0x100>;
@@ -94,48 +70,64 @@
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12C60000 0x100>;
		interrupts = <0 56 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c@12C70000 {
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12C70000 0x100>;
		interrupts = <0 57 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c@12C80000 {
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12C80000 0x100>;
		interrupts = <0 58 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c@12C90000 {
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12C90000 0x100>;
		interrupts = <0 59 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c@12CA0000 {
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12CA0000 0x100>;
		interrupts = <0 60 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c@12CB0000 {
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12CB0000 0x100>;
		interrupts = <0 61 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c@12CC0000 {
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12CC0000 0x100>;
		interrupts = <0 62 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c@12CD0000 {
		compatible = "samsung,s3c2440-i2c";
		reg = <0x12CD0000 0x100>;
		interrupts = <0 63 0>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	amba {
@@ -157,13 +149,13 @@
			interrupts = <0 35 0>;
		};

		mdma0: pdma@10800000 {
		mdma0: mdma@10800000 {
			compatible = "arm,pl330", "arm,primecell";
			reg = <0x10800000 0x1000>;
			interrupts = <0 33 0>;
		};

		mdma1: pdma@11C10000 {
		mdma1: mdma@11C10000 {
			compatible = "arm,pl330", "arm,primecell";
			reg = <0x11C10000 0x1000>;
			interrupts = <0 124 0>;
@@ -242,6 +234,12 @@
			#gpio-cells = <4>;
		};

		gpc4: gpio-controller@114002E0 {
			compatible = "samsung,exynos4-gpio";
			reg = <0x114002E0 0x20>;
			#gpio-cells = <4>;
		};

		gpd0: gpio-controller@11400160 {
			compatible = "samsung,exynos4-gpio";
			reg = <0x11400160 0x20>;
@@ -388,19 +386,19 @@

		gpv2: gpio-controller@10D10040 {
			compatible = "samsung,exynos4-gpio";
			reg = <0x10D10040 0x20>;
			reg = <0x10D10060 0x20>;
			#gpio-cells = <4>;
		};

		gpv3: gpio-controller@10D10060 {
			compatible = "samsung,exynos4-gpio";
			reg = <0x10D10060 0x20>;
			reg = <0x10D10080 0x20>;
			#gpio-cells = <4>;
		};

		gpv4: gpio-controller@10D10080 {
			compatible = "samsung,exynos4-gpio";
			reg = <0x10D10080 0x20>;
			reg = <0x10D100C0 0x20>;
			#gpio-cells = <4>;
		};

+49 −2
Original line number Diff line number Diff line
@@ -165,11 +165,29 @@ static struct clksrc_clk exynos5_clk_sclk_apll = {
	.reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 24, .size = 3 },
};

static struct clksrc_clk exynos5_clk_mout_bpll_fout = {
	.clk	= {
		.name		= "mout_bpll_fout",
	},
	.sources = &clk_src_bpll_fout,
	.reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 0, .size = 1 },
};

static struct clk *exynos5_clk_src_bpll_list[] = {
	[0] = &clk_fin_bpll,
	[1] = &exynos5_clk_mout_bpll_fout.clk,
};

static struct clksrc_sources exynos5_clk_src_bpll = {
	.sources	= exynos5_clk_src_bpll_list,
	.nr_sources	= ARRAY_SIZE(exynos5_clk_src_bpll_list),
};

static struct clksrc_clk exynos5_clk_mout_bpll = {
	.clk	= {
		.name		= "mout_bpll",
	},
	.sources = &clk_src_bpll,
	.sources = &exynos5_clk_src_bpll,
	.reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 0, .size = 1 },
};

@@ -207,11 +225,29 @@ static struct clksrc_clk exynos5_clk_mout_epll = {
	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 12, .size = 1 },
};

static struct clksrc_clk exynos5_clk_mout_mpll_fout = {
	.clk	= {
		.name		= "mout_mpll_fout",
	},
	.sources = &clk_src_mpll_fout,
	.reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 4, .size = 1 },
};

static struct clk *exynos5_clk_src_mpll_list[] = {
	[0] = &clk_fin_mpll,
	[1] = &exynos5_clk_mout_mpll_fout.clk,
};

static struct clksrc_sources exynos5_clk_src_mpll = {
	.sources	= exynos5_clk_src_mpll_list,
	.nr_sources	= ARRAY_SIZE(exynos5_clk_src_mpll_list),
};

struct clksrc_clk exynos5_clk_mout_mpll = {
	.clk = {
		.name		= "mout_mpll",
	},
	.sources = &clk_src_mpll,
	.sources = &exynos5_clk_src_mpll,
	.reg_src = { .reg = EXYNOS5_CLKSRC_CORE1, .shift = 8, .size = 1 },
};

@@ -473,6 +509,11 @@ static struct clk exynos5_init_clocks_off[] = {
		.parent		= &exynos5_clk_aclk_66.clk,
		.enable		= exynos5_clk_ip_peris_ctrl,
		.ctrlbit	= (1 << 20),
	}, {
		.name		= "watchdog",
		.parent		= &exynos5_clk_aclk_66.clk,
		.enable		= exynos5_clk_ip_peris_ctrl,
		.ctrlbit	= (1 << 19),
	}, {
		.name		= "hsmmc",
		.devname	= "exynos4-sdhci.0",
@@ -1031,10 +1072,12 @@ static struct clksrc_clk *exynos5_sysclks[] = {
	&exynos5_clk_mout_apll,
	&exynos5_clk_sclk_apll,
	&exynos5_clk_mout_bpll,
	&exynos5_clk_mout_bpll_fout,
	&exynos5_clk_mout_bpll_user,
	&exynos5_clk_mout_cpll,
	&exynos5_clk_mout_epll,
	&exynos5_clk_mout_mpll,
	&exynos5_clk_mout_mpll_fout,
	&exynos5_clk_mout_mpll_user,
	&exynos5_clk_vpllsrc,
	&exynos5_clk_sclk_vpll,
@@ -1098,7 +1141,9 @@ static struct clk *exynos5_clks[] __initdata = {
	&exynos5_clk_sclk_hdmi27m,
	&exynos5_clk_sclk_hdmiphy,
	&clk_fout_bpll,
	&clk_fout_bpll_div2,
	&clk_fout_cpll,
	&clk_fout_mpll_div2,
	&exynos5_clk_armclk,
};

@@ -1263,8 +1308,10 @@ void __init_or_cpufreq exynos5_setup_clocks(void)

	clk_fout_apll.ops = &exynos5_fout_apll_ops;
	clk_fout_bpll.rate = bpll;
	clk_fout_bpll_div2.rate = bpll >> 1;
	clk_fout_cpll.rate = cpll;
	clk_fout_mpll.rate = mpll;
	clk_fout_mpll_div2.rate = mpll >> 1;
	clk_fout_epll.rate = epll;
	clk_fout_vpll.rate = vpll;

+116 −62
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@
#include <linux/serial_core.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/export.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>

#include <asm/proc-fns.h>
#include <asm/exception.h>
@@ -265,12 +268,12 @@ static struct map_desc exynos5_iodesc[] __initdata = {
	}, {
		.virtual	= (unsigned long)S5P_VA_GIC_CPU,
		.pfn		= __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
		.length		= SZ_64K,
		.length		= SZ_8K,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long)S5P_VA_GIC_DIST,
		.pfn		= __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
		.length		= SZ_64K,
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
};
@@ -399,6 +402,7 @@ struct combiner_chip_data {
	void __iomem *base;
};

static struct irq_domain *combiner_irq_domain;
static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];

static inline void __iomem *combiner_base(struct irq_data *data)
@@ -411,14 +415,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)

static void combiner_mask_irq(struct irq_data *data)
{
	u32 mask = 1 << (data->irq % 32);
	u32 mask = 1 << (data->hwirq % 32);

	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
}

static void combiner_unmask_irq(struct irq_data *data)
{
	u32 mask = 1 << (data->irq % 32);
	u32 mask = 1 << (data->hwirq % 32);

	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
}
@@ -474,49 +478,127 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
	irq_set_chained_handler(irq, combiner_handle_cascade_irq);
}

static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
			  unsigned int irq_start)
static void __init combiner_init_one(unsigned int combiner_nr,
				     void __iomem *base)
{
	unsigned int i;
	unsigned int max_nr;

	if (soc_is_exynos5250())
		max_nr = EXYNOS5_MAX_COMBINER_NR;
	else
		max_nr = EXYNOS4_MAX_COMBINER_NR;

	if (combiner_nr >= max_nr)
		BUG();

	combiner_data[combiner_nr].base = base;
	combiner_data[combiner_nr].irq_offset = irq_start;
	combiner_data[combiner_nr].irq_offset = irq_find_mapping(
		combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
	combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);

	/* Disable all interrupts */

	__raw_writel(combiner_data[combiner_nr].irq_mask,
		     base + COMBINER_ENABLE_CLEAR);
}

#ifdef CONFIG_OF
static int combiner_irq_domain_xlate(struct irq_domain *d,
				     struct device_node *controller,
				     const u32 *intspec, unsigned int intsize,
				     unsigned long *out_hwirq,
				     unsigned int *out_type)
{
	if (d->of_node != controller)
		return -EINVAL;

	/* Setup the Linux IRQ subsystem */
	if (intsize < 2)
		return -EINVAL;

	for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
				+ MAX_IRQ_IN_COMBINER; i++) {
		irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
		irq_set_chip_data(i, &combiner_data[combiner_nr]);
		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
	*out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
	*out_type = 0;

	return 0;
}
#else
static int combiner_irq_domain_xlate(struct irq_domain *d,
				     struct device_node *controller,
				     const u32 *intspec, unsigned int intsize,
				     unsigned long *out_hwirq,
				     unsigned int *out_type)
{
	return -EINVAL;
}
#endif

static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
				   irq_hw_number_t hw)
{
	irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
	irq_set_chip_data(irq, &combiner_data[hw >> 3]);
	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);

	return 0;
}

static struct irq_domain_ops combiner_irq_domain_ops = {
	.xlate	= combiner_irq_domain_xlate,
	.map	= combiner_irq_domain_map,
};

void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
{
	int i, irq, irq_base;
	unsigned int max_nr, nr_irq;

	if (np) {
		if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
			pr_warning("%s: number of combiners not specified, "
				"setting default as %d.\n",
				__func__, EXYNOS4_MAX_COMBINER_NR);
			max_nr = EXYNOS4_MAX_COMBINER_NR;
		}
	} else {
		max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
						EXYNOS4_MAX_COMBINER_NR;
	}
	nr_irq = max_nr * MAX_IRQ_IN_COMBINER;

	irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
	if (IS_ERR_VALUE(irq_base)) {
		irq_base = COMBINER_IRQ(0, 0);
		pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
	}

	combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
				&combiner_irq_domain_ops, &combiner_data);
	if (WARN_ON(!combiner_irq_domain)) {
		pr_warning("%s: irq domain init failed\n", __func__);
		return;
	}

	for (i = 0; i < max_nr; i++) {
		combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
		irq = np ? irq_of_parse_and_map(np, i) : IRQ_SPI(i);
		combiner_cascade_irq(i, irq);
	}
}

#ifdef CONFIG_OF
int __init combiner_of_init(struct device_node *np, struct device_node *parent)
{
	void __iomem *combiner_base;

	combiner_base = of_iomap(np, 0);
	if (!combiner_base) {
		pr_err("%s: failed to map combiner registers\n", __func__);
		return -ENXIO;
	}

	combiner_init(combiner_base, np);

	return 0;
}

static const struct of_device_id exynos4_dt_irq_match[] = {
	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
	{ .compatible = "samsung,exynos4210-combiner",
			.data = combiner_of_init, },
	{},
};
#endif

void __init exynos4_init_irq(void)
{
	int irq;
	unsigned int gic_bank_offset;

	gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
@@ -528,12 +610,8 @@ void __init exynos4_init_irq(void)
		of_irq_init(exynos4_dt_irq_match);
#endif

	for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) {

		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
				COMBINER_IRQ(irq, 0));
		combiner_cascade_irq(irq, IRQ_SPI(irq));
	}
	if (!of_have_populated_dt())
		combiner_init(S5P_VA_COMBINER_BASE, NULL);

	/*
	 * The parameters of s5p_init_irq() are for VIC init.
@@ -545,18 +623,9 @@ void __init exynos4_init_irq(void)

void __init exynos5_init_irq(void)
{
	int irq;

#ifdef CONFIG_OF
	of_irq_init(exynos4_dt_irq_match);
#endif

	for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
				COMBINER_IRQ(irq, 0));
		combiner_cascade_irq(irq, IRQ_SPI(irq));
	}

	/*
	 * The parameters of s5p_init_irq() are for VIC init.
	 * Theses parameters should be NULL and 0 because EXYNOS4
@@ -565,30 +634,18 @@ void __init exynos5_init_irq(void)
	s5p_init_irq(NULL, 0);
}

struct bus_type exynos4_subsys = {
	.name		= "exynos4-core",
	.dev_name	= "exynos4-core",
};

struct bus_type exynos5_subsys = {
	.name		= "exynos5-core",
	.dev_name	= "exynos5-core",
struct bus_type exynos_subsys = {
	.name		= "exynos-core",
	.dev_name	= "exynos-core",
};

static struct device exynos4_dev = {
	.bus	= &exynos4_subsys,
};

static struct device exynos5_dev = {
	.bus	= &exynos5_subsys,
	.bus	= &exynos_subsys,
};

static int __init exynos_core_init(void)
{
	if (soc_is_exynos5250())
		return subsys_system_register(&exynos5_subsys, NULL);
	else
		return subsys_system_register(&exynos4_subsys, NULL);
	return subsys_system_register(&exynos_subsys, NULL);
}
core_initcall(exynos_core_init);

@@ -675,9 +732,6 @@ static int __init exynos_init(void)
{
	printk(KERN_INFO "EXYNOS: Initializing architecture\n");

	if (soc_is_exynos5250())
		return device_register(&exynos5_dev);
	else
	return device_register(&exynos4_dev);
}

Loading