Bladeren bron

Merge tag 'integrator-for-v3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator into next/drivers

From Linus Walleij:
Some Integrator patches that matured for v3.14:

- Use PATCH_PHYS_TO_VIRT and AUTO_ZRELADDR.
- Support cascaded interrupts on the SIC.
- Complete clock implementation for the IM-PD1.

* tag 'integrator-for-v3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator:
  clk: versatile: fixup IM-PD1 clock implementation
  clk: versatile: pass a name to ICST clock provider
  ARM: integrator: pass parent IRQ to the SIC
  irqchip: versatile FPGA: support cascaded interrupts from DT
  ARM: integrator: Default enable ARM_PATCH_PHYS_VIRT, AUTO_ZRELADDR

Signed-off-by: Olof Johansson <olof@lixom.net>
Olof Johansson 11 jaren geleden
bovenliggende
commit
3d7e0207ce

+ 5 - 0
Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt

@@ -29,3 +29,8 @@ pic: pic@14000000 {
         clear-mask = <0xffffffff>;
         valid-mask = <0x003fffff>;
 };
+
+Optional properties:
+- interrupts: if the FPGA IRQ controller is cascaded, i.e. if its IRQ
+  output is simply connected to the input of another IRQ controller,
+  then the parent IRQ shall be specified in this property.

+ 2 - 0
arch/arm/Kconfig

@@ -313,6 +313,8 @@ config ARCH_INTEGRATOR
 	bool "ARM Ltd. Integrator family"
 	select ARCH_HAS_CPUFREQ
 	select ARM_AMBA
+	select ARM_PATCH_PHYS_VIRT
+	select AUTO_ZRELADDR
 	select COMMON_CLK
 	select COMMON_CLK_VERSATILE
 	select GENERIC_CLOCKEVENTS

+ 3 - 0
arch/arm/boot/dts/integratorcp.dts

@@ -47,8 +47,11 @@
 		valid-mask = <0x00000007>;
 	};
 
+	/* The SIC is cascaded off IRQ 26 on the PIC */
 	sic: sic@ca000000 {
 		compatible = "arm,versatile-fpga-irq";
+		interrupt-parent = <&pic>;
+		interrupts = <26>;
 		#interrupt-cells = <1>;
 		interrupt-controller;
 		reg = <0xca000000 0x100>;

+ 2 - 1
drivers/clk/versatile/clk-icst.c

@@ -119,6 +119,7 @@ static const struct clk_ops icst_ops = {
 
 struct clk *icst_clk_register(struct device *dev,
 			const struct clk_icst_desc *desc,
+			const char *name,
 			void __iomem *base)
 {
 	struct clk *clk;
@@ -130,7 +131,7 @@ struct clk *icst_clk_register(struct device *dev,
 		pr_err("could not allocate ICST clock!\n");
 		return ERR_PTR(-ENOMEM);
 	}
-	init.name = "icst";
+	init.name = name;
 	init.ops = &icst_ops;
 	init.flags = CLK_IS_ROOT;
 	init.parent_names = NULL;

+ 1 - 0
drivers/clk/versatile/clk-icst.h

@@ -15,4 +15,5 @@ struct clk_icst_desc {
 
 struct clk *icst_clk_register(struct device *dev,
 			      const struct clk_icst_desc *desc,
+			      const char *name,
 			      void __iomem *base);

+ 72 - 16
drivers/clk/versatile/clk-impd1.c

@@ -1,6 +1,6 @@
 /*
  * Clock driver for the ARM Integrator/IM-PD1 board
- * Copyright (C) 2012 Linus Walleij
+ * Copyright (C) 2012-2013 Linus Walleij
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,20 +18,28 @@
 #include "clk-icst.h"
 
 struct impd1_clk {
-	struct clk *vcoclk;
+	char *vco1name;
+	struct clk *vco1clk;
+	char *vco2name;
+	struct clk *vco2clk;
+	struct clk *mmciclk;
+	char *uartname;
 	struct clk *uartclk;
-	struct clk_lookup *clks[3];
+	char *spiname;
+	struct clk *spiclk;
+	char *scname;
+	struct clk *scclk;
+	struct clk_lookup *clks[6];
 };
 
+/* One entry for each connected IM-PD1 LM */
 static struct impd1_clk impd1_clks[4];
 
 /*
- * There are two VCO's on the IM-PD1 but only one is used by the
- * kernel, that is why we are only implementing the control of
- * IMPD1_OSC1 here.
+ * There are two VCO's on the IM-PD1
  */
 
-static const struct icst_params impd1_vco_params = {
+static const struct icst_params impd1_vco1_params = {
 	.ref		= 24000000,	/* 24 MHz */
 	.vco_max	= ICST525_VCO_MAX_3V,
 	.vco_min	= ICST525_VCO_MIN,
@@ -44,11 +52,29 @@ static const struct icst_params impd1_vco_params = {
 };
 
 static const struct clk_icst_desc impd1_icst1_desc = {
-	.params = &impd1_vco_params,
+	.params = &impd1_vco1_params,
 	.vco_offset = IMPD1_OSC1,
 	.lock_offset = IMPD1_LOCK,
 };
 
+static const struct icst_params impd1_vco2_params = {
+	.ref		= 24000000,	/* 24 MHz */
+	.vco_max	= ICST525_VCO_MAX_3V,
+	.vco_min	= ICST525_VCO_MIN,
+	.vd_min		= 12,
+	.vd_max		= 519,
+	.rd_min		= 3,
+	.rd_max		= 120,
+	.s2div		= icst525_s2div,
+	.idx2s		= icst525_idx2s,
+};
+
+static const struct clk_icst_desc impd1_icst2_desc = {
+	.params = &impd1_vco2_params,
+	.vco_offset = IMPD1_OSC2,
+	.lock_offset = IMPD1_LOCK,
+};
+
 /**
  * integrator_impd1_clk_init() - set up the integrator clock tree
  * @base: base address of the logic module (LM)
@@ -66,16 +92,39 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
 	}
 	imc = &impd1_clks[id];
 
-	clk = icst_clk_register(NULL, &impd1_icst1_desc, base);
-	imc->vcoclk = clk;
+	imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id);
+	clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, base);
+	imc->vco1clk = clk;
 	imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
 
-	/* UART reference clock */
-	clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
-				14745600);
+	/* VCO2 is also called "CLK2" */
+	imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id);
+	clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, base);
+	imc->vco2clk = clk;
+
+	/* MMCI uses CLK2 right off */
+	imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00700", id);
+
+	/* UART reference clock divides CLK2 by a fixed factor 4 */
+	imc->uartname = kasprintf(GFP_KERNEL, "lm%x-uartclk", id);
+	clk = clk_register_fixed_factor(NULL, imc->uartname, imc->vco2name,
+				   CLK_IGNORE_UNUSED, 1, 4);
 	imc->uartclk = clk;
-	imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
-	imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
+	imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
+	imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
+
+	/* SPI PL022 clock divides CLK2 by a fixed factor 64 */
+	imc->spiname = kasprintf(GFP_KERNEL, "lm%x-spiclk", id);
+	clk = clk_register_fixed_factor(NULL, imc->spiname, imc->vco2name,
+				   CLK_IGNORE_UNUSED, 1, 64);
+	imc->clks[4] = clkdev_alloc(clk, NULL, "lm%x:00300", id);
+
+	/* Smart Card clock divides CLK2 by a fixed factor 4 */
+	imc->scname = kasprintf(GFP_KERNEL, "lm%x-scclk", id);
+	clk = clk_register_fixed_factor(NULL, imc->scname, imc->vco2name,
+				   CLK_IGNORE_UNUSED, 1, 4);
+	imc->scclk = clk;
+	imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00600", id);
 
 	for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
 		clkdev_add(imc->clks[i]);
@@ -92,6 +141,13 @@ void integrator_impd1_clk_exit(unsigned int id)
 
 	for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
 		clkdev_drop(imc->clks[i]);
+	clk_unregister(imc->spiclk);
 	clk_unregister(imc->uartclk);
-	clk_unregister(imc->vcoclk);
+	clk_unregister(imc->vco2clk);
+	clk_unregister(imc->vco1clk);
+	kfree(imc->scname);
+	kfree(imc->spiname);
+	kfree(imc->uartname);
+	kfree(imc->vco2name);
+	kfree(imc->vco1name);
 }

+ 1 - 1
drivers/clk/versatile/clk-integrator.c

@@ -78,7 +78,7 @@ void __init integrator_clk_init(bool is_cp)
 	clk_register_clkdev(clk, NULL, "sp804");
 
 	/* ICST VCO clock used on the Integrator/CP CLCD */
-	clk = icst_clk_register(NULL, &cp_icst_desc,
+	clk = icst_clk_register(NULL, &cp_icst_desc, "icst",
 				__io_address(INTEGRATOR_HDR_BASE));
 	clk_register_clkdev(clk, NULL, "clcd");
 }

+ 4 - 2
drivers/clk/versatile/clk-realview.c

@@ -84,9 +84,11 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
 
 	/* ICST VCO clock */
 	if (is_pb1176)
-		clk = icst_clk_register(NULL, &realview_osc0_desc, sysbase);
+		clk = icst_clk_register(NULL, &realview_osc0_desc,
+					"osc0", sysbase);
 	else
-		clk = icst_clk_register(NULL, &realview_osc4_desc, sysbase);
+		clk = icst_clk_register(NULL, &realview_osc4_desc,
+					"osc4", sysbase);
 
 	clk_register_clkdev(clk, NULL, "dev:clcd");
 	clk_register_clkdev(clk, NULL, "issp:clcd");

+ 13 - 2
drivers/irqchip/irq-versatile-fpga.c

@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/exception.h>
 #include <asm/mach/irq.h>
@@ -167,8 +168,12 @@ void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
 			f->used_irqs++;
 		}
 
-	pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n",
+	pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs",
 		fpga_irq_id, name, base, f->used_irqs);
+	if (parent_irq != -1)
+		pr_cont(", parent IRQ: %d\n", parent_irq);
+	else
+		pr_cont("\n");
 
 	fpga_irq_id++;
 }
@@ -180,6 +185,7 @@ int __init fpga_irq_of_init(struct device_node *node,
 	void __iomem *base;
 	u32 clear_mask;
 	u32 valid_mask;
+	int parent_irq;
 
 	if (WARN_ON(!node))
 		return -ENODEV;
@@ -193,7 +199,12 @@ int __init fpga_irq_of_init(struct device_node *node,
 	if (of_property_read_u32(node, "valid-mask", &valid_mask))
 		valid_mask = 0;
 
-	fpga_irq_init(base, node->name, 0, -1, valid_mask, node);
+	/* Some chips are cascaded from a parent IRQ */
+	parent_irq = irq_of_parse_and_map(node, 0);
+	if (!parent_irq)
+		parent_irq = -1;
+
+	fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node);
 
 	writel(clear_mask, base + IRQ_ENABLE_CLEAR);
 	writel(clear_mask, base + FIQ_ENABLE_CLEAR);