Commit b5feaefb authored by Olof Johansson's avatar Olof Johansson

Merge tag 'integrator-for-v3.15-1' of...

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

Merge "Integrator/Versatile base patch stack for the v3.15 series"
from Linus Walleij:

"this is a set of patches I have sent for review and failed to get ACKs
from the proper subsystem maintainers after repeated pings. However I
now need to have this rotated in linux-next as a base for multiplatform,
so please pull it in, it is all ARM drivers anyway. Russell pointed out
some things and these have been fixed and iterated in this series."

- Move integrator clock definitions to the device tree, alter
  clock and timer drivers accordingly.

- Alter the VIC irqchip driver to support cascaded VICs off
  a parent IRQ controller.

- Update the IM-PD1 plugin code to use managed resources.

- Register the VIC on the IM-PD1.

- Select the PL061 GPIO block for the IM-PD1 on the
  Integrator/AP.

* tag 'integrator-for-v3.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator:
  ARM: integrator: select GPIO block
  ARM: integrator: register the IM-PD1 VIC
  ARM: integrator: use managed resources for the IM-PD1
  irqchip: support cascaded VICs
  irqchip: vic: update the base IRQ member correctly
  clk: versatile: respect parent rate in ICST clock
  clk: versatile: pass a parent to the ICST clock
  ARM: integrator: switch to fetch clocks from device tree
  ARM: SP804: make Integrator/CP timer pick clock from DT
  ARM: integrator: define clocks in the device trees
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 58035fcc 29525484
Clock bindings for ARM Integrator Core Module clocks
Auxilary Oscillator Clock
This is a configurable clock fed from a 24 MHz chrystal,
used for generating e.g. video clocks. It is located on the
core module and there is only one of these.
This clock node *must* be a subnode of the core module, since
it obtains the base address for it's address range from its
parent node.
Required properties:
- compatible: must be "arm,integrator-cm-auxosc"
- #clock-cells: must be <0>
Optional properties:
- clocks: parent clock(s)
Example:
core-module@10000000 {
xtal24mhz: xtal24mhz@24M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
};
auxosc: cm_aux_osc@25M {
#clock-cells = <0>;
compatible = "arm,integrator-cm-auxosc";
clocks = <&xtal24mhz>;
};
};
...@@ -18,6 +18,28 @@ chosen { ...@@ -18,6 +18,28 @@ chosen {
bootargs = "root=/dev/ram0 console=ttyAM0,38400n8 earlyprintk"; bootargs = "root=/dev/ram0 console=ttyAM0,38400n8 earlyprintk";
}; };
/* 24 MHz chrystal on the core module */
xtal24mhz: xtal24mhz@24M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
};
pclk: pclk@0 {
#clock-cells = <0>;
compatible = "fixed-factor-clock";
clock-div = <1>;
clock-mult = <1>;
clocks = <&xtal24mhz>;
};
/* The UART clock is 14.74 MHz divided by an ICS525 */
uartclk: uartclk@14.74M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <14745600>;
};
syscon { syscon {
compatible = "arm,integrator-ap-syscon"; compatible = "arm,integrator-ap-syscon";
reg = <0x11000000 0x100>; reg = <0x11000000 0x100>;
...@@ -28,14 +50,17 @@ syscon { ...@@ -28,14 +50,17 @@ syscon {
timer0: timer@13000000 { timer0: timer@13000000 {
compatible = "arm,integrator-timer"; compatible = "arm,integrator-timer";
clocks = <&xtal24mhz>;
}; };
timer1: timer@13000100 { timer1: timer@13000100 {
compatible = "arm,integrator-timer"; compatible = "arm,integrator-timer";
clocks = <&xtal24mhz>;
}; };
timer2: timer@13000200 { timer2: timer@13000200 {
compatible = "arm,integrator-timer"; compatible = "arm,integrator-timer";
clocks = <&xtal24mhz>;
}; };
pic: pic@14000000 { pic: pic@14000000 {
...@@ -92,26 +117,36 @@ fpga { ...@@ -92,26 +117,36 @@ fpga {
rtc: rtc@15000000 { rtc: rtc@15000000 {
compatible = "arm,pl030", "arm,primecell"; compatible = "arm,pl030", "arm,primecell";
arm,primecell-periphid = <0x00041030>; arm,primecell-periphid = <0x00041030>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
uart0: uart@16000000 { uart0: uart@16000000 {
compatible = "arm,pl010", "arm,primecell"; compatible = "arm,pl010", "arm,primecell";
arm,primecell-periphid = <0x00041010>; arm,primecell-periphid = <0x00041010>;
clocks = <&uartclk>, <&pclk>;
clock-names = "uartclk", "apb_pclk";
}; };
uart1: uart@17000000 { uart1: uart@17000000 {
compatible = "arm,pl010", "arm,primecell"; compatible = "arm,pl010", "arm,primecell";
arm,primecell-periphid = <0x00041010>; arm,primecell-periphid = <0x00041010>;
clocks = <&uartclk>, <&pclk>;
clock-names = "uartclk", "apb_pclk";
}; };
kmi0: kmi@18000000 { kmi0: kmi@18000000 {
compatible = "arm,pl050", "arm,primecell"; compatible = "arm,pl050", "arm,primecell";
arm,primecell-periphid = <0x00041050>; arm,primecell-periphid = <0x00041050>;
clocks = <&xtal24mhz>, <&pclk>;
clock-names = "KMIREFCLK", "apb_pclk";
}; };
kmi1: kmi@19000000 { kmi1: kmi@19000000 {
compatible = "arm,pl050", "arm,primecell"; compatible = "arm,pl050", "arm,primecell";
arm,primecell-periphid = <0x00041050>; arm,primecell-periphid = <0x00041050>;
clocks = <&xtal24mhz>, <&pclk>;
clock-names = "KMIREFCLK", "apb_pclk";
}; };
}; };
}; };
...@@ -13,25 +13,107 @@ chosen { ...@@ -13,25 +13,107 @@ chosen {
bootargs = "root=/dev/ram0 console=ttyAMA0,38400n8 earlyprintk"; bootargs = "root=/dev/ram0 console=ttyAMA0,38400n8 earlyprintk";
}; };
/*
* The Integrator/CP overall clocking architecture can be found in
* ARM DUI 0184B page 7-28 "Integrator/CP922T system clocks" which
* appear to illustrate the layout used in most configurations.
*/
/* The codec chrystal operates at 24.576 MHz */
xtal_codec: xtal24.576@24.576M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24576000>;
};
/* The chrystal is divided by 2 by the codec for the AACI bit clock */
aaci_bitclk: aaci_bitclk@12.288M {
#clock-cells = <0>;
compatible = "fixed-factor-clock";
clock-div = <2>;
clock-mult = <1>;
clocks = <&xtal_codec>;
};
/* This is a 25MHz chrystal on the base board */
xtal25mhz: xtal25mhz@25M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <25000000>;
};
/* The UART clock is 14.74 MHz divided from 25MHz by an ICS525 */
uartclk: uartclk@14.74M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <14745600>;
};
/* Actually sysclk I think */
pclk: pclk@0 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <0>;
};
core-module@10000000 {
/* 24 MHz chrystal on the core module */
xtal24mhz: xtal24mhz@24M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
};
/*
* External oscillator on the core module, usually used
* to drive video circuitry. Driven from the 24MHz clock.
*/
auxosc: cm_aux_osc@25M {
#clock-cells = <0>;
compatible = "arm,integrator-cm-auxosc";
clocks = <&xtal24mhz>;
};
/* The KMI clock is the 24 MHz oscillator divided to 8MHz */
kmiclk: kmiclk@1M {
#clock-cells = <0>;
compatible = "fixed-factor-clock";
clock-div = <3>;
clock-mult = <1>;
clocks = <&xtal24mhz>;
};
/* The timer clock is the 24 MHz oscillator divided to 1MHz */
timclk: timclk@1M {
#clock-cells = <0>;
compatible = "fixed-factor-clock";
clock-div = <24>;
clock-mult = <1>;
clocks = <&xtal24mhz>;
};
};
syscon { syscon {
compatible = "arm,integrator-cp-syscon"; compatible = "arm,integrator-cp-syscon";
reg = <0xcb000000 0x100>; reg = <0xcb000000 0x100>;
}; };
timer0: timer@13000000 { timer0: timer@13000000 {
/* TIMER0 runs @ 25MHz */ /* TIMER0 runs directly on the 25MHz chrystal */
compatible = "arm,integrator-cp-timer"; compatible = "arm,integrator-cp-timer";
status = "disabled"; clocks = <&xtal25mhz>;
}; };
timer1: timer@13000100 { timer1: timer@13000100 {
/* TIMER1 runs @ 1MHz */ /* TIMER1 runs @ 1MHz */
compatible = "arm,integrator-cp-timer"; compatible = "arm,integrator-cp-timer";
clocks = <&timclk>;
}; };
timer2: timer@13000200 { timer2: timer@13000200 {
/* TIMER2 runs @ 1MHz */ /* TIMER2 runs @ 1MHz */
compatible = "arm,integrator-cp-timer"; compatible = "arm,integrator-cp-timer";
clocks = <&timclk>;
}; };
pic: pic@14000000 { pic: pic@14000000 {
...@@ -74,22 +156,32 @@ fpga { ...@@ -74,22 +156,32 @@ fpga {
*/ */
rtc@15000000 { rtc@15000000 {
compatible = "arm,pl031", "arm,primecell"; compatible = "arm,pl031", "arm,primecell";
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
uart@16000000 { uart@16000000 {
compatible = "arm,pl011", "arm,primecell"; compatible = "arm,pl011", "arm,primecell";
clocks = <&uartclk>, <&pclk>;
clock-names = "uartclk", "apb_pclk";
}; };
uart@17000000 { uart@17000000 {
compatible = "arm,pl011", "arm,primecell"; compatible = "arm,pl011", "arm,primecell";
clocks = <&uartclk>, <&pclk>;
clock-names = "uartclk", "apb_pclk";
}; };
kmi@18000000 { kmi@18000000 {
compatible = "arm,pl050", "arm,primecell"; compatible = "arm,pl050", "arm,primecell";
clocks = <&kmiclk>, <&pclk>;
clock-names = "KMIREFCLK", "apb_pclk";
}; };
kmi@19000000 { kmi@19000000 {
compatible = "arm,pl050", "arm,primecell"; compatible = "arm,pl050", "arm,primecell";
clocks = <&kmiclk>, <&pclk>;
clock-names = "KMIREFCLK", "apb_pclk";
}; };
/* /*
...@@ -100,18 +192,24 @@ mmc@1c000000 { ...@@ -100,18 +192,24 @@ mmc@1c000000 {
reg = <0x1c000000 0x1000>; reg = <0x1c000000 0x1000>;
interrupts = <23 24>; interrupts = <23 24>;
max-frequency = <515633>; max-frequency = <515633>;
clocks = <&uartclk>, <&pclk>;
clock-names = "mclk", "apb_pclk";
}; };
aaci@1d000000 { aaci@1d000000 {
compatible = "arm,pl041", "arm,primecell"; compatible = "arm,pl041", "arm,primecell";
reg = <0x1d000000 0x1000>; reg = <0x1d000000 0x1000>;
interrupts = <25>; interrupts = <25>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
clcd@c0000000 { clcd@c0000000 {
compatible = "arm,pl110", "arm,primecell"; compatible = "arm,pl110", "arm,primecell";
reg = <0xC0000000 0x1000>; reg = <0xC0000000 0x1000>;
interrupts = <22>; interrupts = <22>;
clocks = <&auxosc>, <&pclk>;
clock-names = "clcd", "apb_pclk";
}; };
}; };
}; };
...@@ -271,10 +271,14 @@ static void __init integrator_cp_of_init(struct device_node *np) ...@@ -271,10 +271,14 @@ static void __init integrator_cp_of_init(struct device_node *np)
void __iomem *base; void __iomem *base;
int irq; int irq;
const char *name = of_get_property(np, "compatible", NULL); const char *name = of_get_property(np, "compatible", NULL);
struct clk *clk;
base = of_iomap(np, 0); base = of_iomap(np, 0);
if (WARN_ON(!base)) if (WARN_ON(!base))
return; return;
clk = of_clk_get(np, 0);
if (WARN_ON(IS_ERR(clk)))
return;
/* Ensure timer is disabled */ /* Ensure timer is disabled */
writel(0, base + TIMER_CTRL); writel(0, base + TIMER_CTRL);
...@@ -283,13 +287,13 @@ static void __init integrator_cp_of_init(struct device_node *np) ...@@ -283,13 +287,13 @@ static void __init integrator_cp_of_init(struct device_node *np)
goto err; goto err;
if (!init_count) if (!init_count)
sp804_clocksource_init(base, name); __sp804_clocksource_and_sched_clock_init(base, name, clk, 0);
else { else {
irq = irq_of_parse_and_map(np, 0); irq = irq_of_parse_and_map(np, 0);
if (irq <= 0) if (irq <= 0)
goto err; goto err;
sp804_clockevents_init(base, irq, name); __sp804_clockevents_init(base, irq, clk, name);
} }
init_count++; init_count++;
......
...@@ -30,6 +30,9 @@ config ARCH_CINTEGRATOR ...@@ -30,6 +30,9 @@ config ARCH_CINTEGRATOR
config INTEGRATOR_IMPD1 config INTEGRATOR_IMPD1
tristate "Include support for Integrator/IM-PD1" tristate "Include support for Integrator/IM-PD1"
depends on ARCH_INTEGRATOR_AP depends on ARCH_INTEGRATOR_AP
select ARCH_REQUIRE_GPIOLIB
select ARM_VIC
select GPIO_PL061 if GPIOLIB
help help
The IM-PD1 is an add-on logic module for the Integrator which The IM-PD1 is an add-on logic module for the Integrator which
allows ARM(R) Ltd PrimeCells to be developed and evaluated. allows ARM(R) Ltd PrimeCells to be developed and evaluated.
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_data/clk-integrator.h> #include <linux/platform_data/clk-integrator.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/irqchip/arm-vic.h>
#include <mach/lm.h> #include <mach/lm.h>
#include <mach/impd1.h> #include <mach/impd1.h>
...@@ -35,6 +36,7 @@ MODULE_PARM_DESC(lmid, "logic module stack position"); ...@@ -35,6 +36,7 @@ MODULE_PARM_DESC(lmid, "logic module stack position");
struct impd1_module { struct impd1_module {
void __iomem *base; void __iomem *base;
void __iomem *vic_base;
}; };
void impd1_tweak_control(struct device *dev, u32 mask, u32 val) void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
...@@ -262,9 +264,6 @@ struct impd1_device { ...@@ -262,9 +264,6 @@ struct impd1_device {
static struct impd1_device impd1_devs[] = { static struct impd1_device impd1_devs[] = {
{ {
.offset = 0x03000000,
.id = 0x00041190,
}, {
.offset = 0x00100000, .offset = 0x00100000,
.irq = { 1 }, .irq = { 1 },
.id = 0x00141011, .id = 0x00141011,
...@@ -304,46 +303,72 @@ static struct impd1_device impd1_devs[] = { ...@@ -304,46 +303,72 @@ static struct impd1_device impd1_devs[] = {
} }
}; };
static int impd1_probe(struct lm_device *dev) /*
* Valid IRQs: 0 thru 9 and 11, 10 unused.
*/
#define IMPD1_VALID_IRQS 0x00000bffU
static int __init impd1_probe(struct lm_device *dev)
{ {
struct impd1_module *impd1; struct impd1_module *impd1;
int i, ret; int irq_base;
int i;
if (dev->id != module_id) if (dev->id != module_id)
return -EINVAL; return -EINVAL;
if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers")) if (!devm_request_mem_region(&dev->dev, dev->resource.start,
SZ_4K, "LM registers"))
return -EBUSY; return -EBUSY;
impd1 = kzalloc(sizeof(struct impd1_module), GFP_KERNEL); impd1 = devm_kzalloc(&dev->dev, sizeof(struct impd1_module),
if (!impd1) { GFP_KERNEL);
ret = -ENOMEM; if (!impd1)
goto release_lm; return -ENOMEM;
}
impd1->base = ioremap(dev->resource.start, SZ_4K); impd1->base = devm_ioremap(&dev->dev, dev->resource.start, SZ_4K);
if (!impd1->base) { if (!impd1->base)
ret = -ENOMEM; return -ENOMEM;
goto free_impd1;
}
lm_set_drvdata(dev, impd1); integrator_impd1_clk_init(impd1->base, dev->id);
printk("IM-PD1 found at 0x%08lx\n", if (!devm_request_mem_region(&dev->dev,
(unsigned long)dev->resource.start); dev->resource.start + 0x03000000,
SZ_4K, "VIC"))
return -EBUSY;
integrator_impd1_clk_init(impd1->base, dev->id); impd1->vic_base = devm_ioremap(&dev->dev,
dev->resource.start + 0x03000000,
SZ_4K);
if (!impd1->vic_base)
return -ENOMEM;
irq_base = vic_init_cascaded(impd1->vic_base, dev->irq,
IMPD1_VALID_IRQS, 0);
lm_set_drvdata(dev, impd1);
dev_info(&dev->dev, "IM-PD1 found at 0x%08lx\n",
(unsigned long)dev->resource.start);
for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
struct impd1_device *idev = impd1_devs + i; struct impd1_device *idev = impd1_devs + i;
struct amba_device *d; struct amba_device *d;
unsigned long pc_base; unsigned long pc_base;
char devname[32]; char devname[32];
int irq1 = idev->irq[0];
int irq2 = idev->irq[1];
/* Translate IRQs to IM-PD1 local numberspace */
if (irq1)
irq1 += irq_base;
if (irq2)
irq2 += irq_base;
pc_base = dev->resource.start + idev->offset; pc_base = dev->resource.start + idev->offset;
snprintf(devname, 32, "lm%x:%5.5lx", dev->id, idev->offset >> 12); snprintf(devname, 32, "lm%x:%5.5lx", dev->id, idev->offset >> 12);
d = amba_ahb_device_add_res(&dev->dev, devname, pc_base, SZ_4K, d = amba_ahb_device_add_res(&dev->dev, devname, pc_base, SZ_4K,
dev->irq, dev->irq, irq1, irq2,
idev->platform_data, idev->id, idev->platform_data, idev->id,
&dev->resource); &dev->resource);
if (IS_ERR(d)) { if (IS_ERR(d)) {
...@@ -353,14 +378,6 @@ static int impd1_probe(struct lm_device *dev) ...@@ -353,14 +378,6 @@ static int impd1_probe(struct lm_device *dev)
} }
return 0; return 0;
free_impd1:
if (impd1 && impd1->base)
iounmap(impd1->base);
kfree(impd1);
release_lm:
release_mem_region(dev->resource.start, SZ_4K);
return ret;
} }
static int impd1_remove_one(struct device *dev, void *data) static int impd1_remove_one(struct device *dev, void *data)
...@@ -371,16 +388,10 @@ static int impd1_remove_one(struct device *dev, void *data) ...@@ -371,16 +388,10 @@ static int impd1_remove_one(struct device *dev, void *data)
static void impd1_remove(struct lm_device *dev) static void impd1_remove(struct lm_device *dev)
{ {
struct impd1_module *impd1 = lm_get_drvdata(dev);
device_for_each_child(&dev->dev, NULL, impd1_remove_one); device_for_each_child(&dev->dev, NULL, impd1_remove_one);
integrator_impd1_clk_exit(dev->id); integrator_impd1_clk_exit(dev->id);
lm_set_drvdata(dev, NULL); lm_set_drvdata(dev, NULL);
iounmap(impd1->base);
kfree(impd1);
release_mem_region(dev->resource.start, SZ_4K);
} }
static struct lm_driver impd1_driver = { static struct lm_driver impd1_driver = {
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
#include <linux/termios.h> #include <linux/termios.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
#include <linux/clk-provider.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/platform.h> #include <mach/platform.h>
...@@ -402,10 +403,7 @@ static void __init ap_of_timer_init(void) ...@@ -402,10 +403,7 @@ static void __init ap_of_timer_init(void)
struct clk *clk; struct clk *clk;
unsigned long rate; unsigned long rate;
clk = clk_get_sys("ap_timer", NULL); of_clk_init(NULL);
BUG_ON(IS_ERR(clk));
clk_prepare_enable(clk);
rate = clk_get_rate(clk);
err = of_property_read_string(of_aliases, err = of_property_read_string(of_aliases,
"arm,timer-primary", &path); "arm,timer-primary", &path);
...@@ -415,6 +413,12 @@ static void __init ap_of_timer_init(void) ...@@ -415,6 +413,12 @@ static void __init ap_of_timer_init(void)
base = of_iomap(node, 0); base = of_iomap(node, 0);
if (WARN_ON(!base)) if (WARN_ON(!base))
return; return;
clk = of_clk_get(node, 0);
BUG_ON(IS_ERR(clk));
clk_prepare_enable(clk);
rate = clk_get_rate(clk);
writel(0, base + TIMER_CTRL); writel(0, base + TIMER_CTRL);
integrator_clocksource_init(rate, base); integrator_clocksource_init(rate, base);
...@@ -427,6 +431,12 @@ static void __init ap_of_timer_init(void) ...@@ -427,6 +431,12 @@ static void __init ap_of_timer_init(void)
if (WARN_ON(!base)) if (WARN_ON(!base))
return; return;
irq = irq_of_parse_and_map(node, 0); irq = irq_of_parse_and_map(node, 0);
clk = of_clk_get(node, 0);
BUG_ON(IS_ERR(clk));
clk_prepare_enable(clk);
rate = clk_get_rate(clk);
writel(0, base + TIMER_CTRL); writel(0, base + TIMER_CTRL);
integrator_clockevent_init(rate, base, irq); integrator_clockevent_init(rate, base, irq);
} }
...@@ -440,7 +450,6 @@ static void __init ap_init_irq_of(void) ...@@ -440,7 +450,6 @@ static void __init ap_init_irq_of(void)
{ {
cm_init(); cm_init();
of_irq_init(fpga_irq_of_match); of_irq_init(fpga_irq_of_match);
integrator_clk_init(false);
} }
/* For the Device Tree, add in the UART callbacks as AUXDATA */ /* For the Device Tree, add in the UART callbacks as AUXDATA */
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/irqchip/versatile-fpga.h> #include <linux/irqchip/versatile-fpga.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/platform_data/clk-integrator.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
...@@ -33,8 +32,6 @@ ...@@ -33,8 +32,6 @@
#include <mach/platform.h> #include <mach/platform.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst.h>
#include <mach/lm.h> #include <mach/lm.h>
...@@ -43,8 +40,6 @@ ...@@ -43,8 +40,6 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/hardware/timer-sp.h>
#include <plat/clcd.h> #include <plat/clcd.h>
#include <plat/sched_clock.h> #include <plat/sched_clock.h>
...@@ -250,7 +245,6 @@ static void __init intcp_init_irq_of(void) ...@@ -250,7 +245,6 @@ static void __init intcp_init_irq_of(void)
{ {
cm_init(); cm_init();
of_irq_init(fpga_irq_of_match); of_irq_init(fpga_irq_of_match);
integrator_clk_init(true);
} }
/* /*
......
...@@ -108,7 +108,7 @@ void __init versatile_init_irq(void) ...@@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
np = of_find_matching_node_by_address(NULL, vic_of_match, np = of_find_matching_node_by_address(NULL, vic_of_match,
VERSATILE_VIC_BASE); VERSATILE_VIC_BASE);
__vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np); __vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
......
...@@ -33,7 +33,7 @@ struct clk_icst { ...@@ -33,7 +33,7 @@ struct clk_icst {
struct clk_hw hw; struct clk_hw hw;
void __iomem *vcoreg; void __iomem *vcoreg;
void __iomem *lockreg; void __iomem *lockreg;
const struct icst_params *params; struct icst_params *params;
unsigned long rate; unsigned long rate;
}; };
...@@ -84,6 +84,8 @@ static unsigned long icst_recalc_rate(struct clk_hw *hw, ...@@ -84,6 +84,8 @@ static unsigned long icst_recalc_rate(struct clk_hw *hw,
struct clk_icst *icst = to_icst(hw); struct clk_icst *icst = to_icst(hw);
struct icst_vco vco; struct icst_vco vco;
if (parent_rate)
icst->params->ref = parent_rate;
vco = vco_get(icst->vcoreg); vco = vco_get(icst->vcoreg);
icst->rate = icst_hz(icst->params, vco); icst->rate = icst_hz(icst->params, vco);
return icst->rate; return icst->rate;
...@@ -105,6 +107,8 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -105,6 +107,8 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_icst *icst = to_icst(hw); struct clk_icst *icst = to_icst(hw);
struct icst_vco vco; struct icst_vco vco;
if (parent_rate)
icst->params->ref = parent_rate;
vco = icst_hz_to_vco(icst->params, rate); vco = icst_hz_to_vco(icst->params, rate);
icst->rate = icst_hz(icst->params, vco); icst->rate = icst_hz(icst->params, vco);
vco_set(icst->lockreg, icst->vcoreg, vco); vco_set(icst->lockreg, icst->vcoreg, vco);
...@@ -120,24 +124,33 @@ static const struct clk_ops icst_ops = { ...@@ -120,24 +124,33 @@ static const struct clk_ops icst_ops = {
struct clk *icst_clk_register(struct device *dev, struct clk *icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc, const struct clk_icst_desc *desc,
const char *name, const char *name,
const char *parent_name,
void __iomem *base) void __iomem *base)
{ {
struct clk *clk; struct clk *clk;
struct clk_icst *icst; struct clk_icst *icst;
struct clk_init_data init; struct clk_init_data init;
struct icst_params *pclone;
icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL); icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL);
if (!icst) { if (!icst) {
pr_err("could not allocate ICST clock!\n"); pr_err("could not allocate ICST clock!\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL);
if (!pclone) {
pr_err("could not clone ICST params\n");
return ERR_PTR(-ENOMEM);
}
init.name = name; init.name = name;
init.ops = &icst_ops; init.ops = &icst_ops;
init.flags = CLK_IS_ROOT; init.flags = CLK_IS_ROOT;
init.parent_names = NULL; init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = 0; init.num_parents = (parent_name ? 1 : 0);
icst->hw.init = &init; icst->hw.init = &init;
icst->params = desc->params; icst->params = pclone;
icst->vcoreg = base + desc->vco_offset; icst->vcoreg = base + desc->vco_offset;
icst->lockreg = base + desc->lock_offset; icst->lockreg = base + desc->lock_offset;
......
...@@ -16,4 +16,5 @@ struct clk_icst_desc { ...@@ -16,4 +16,5 @@ struct clk_icst_desc {
struct clk *icst_clk_register(struct device *dev, struct clk *icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc, const struct clk_icst_desc *desc,
const char *name, const char *name,
const char *parent_name,
void __iomem *base); void __iomem *base);
...@@ -93,13 +93,15 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id) ...@@ -93,13 +93,15 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
imc = &impd1_clks[id]; imc = &impd1_clks[id];
imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id); imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id);
clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, base); clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL,
base);
imc->vco1clk = clk; imc->vco1clk = clk;
imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id); imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
/* VCO2 is also called "CLK2" */ /* VCO2 is also called "CLK2" */
imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id); imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id);
clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, base); clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, NULL,
base);
imc->vco2clk = clk; imc->vco2clk = clk;
/* MMCI uses CLK2 right off */ /* MMCI uses CLK2 right off */
......
...@@ -10,21 +10,17 @@ ...@@ -10,21 +10,17 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_data/clk-integrator.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <mach/hardware.h>
#include <mach/platform.h>
#include "clk-icst.h" #include "clk-icst.h"
/* #define INTEGRATOR_HDR_LOCK_OFFSET 0x14
* Implementation of the ARM Integrator/AP and Integrator/CP clock tree.
* Inspired by portions of:
* plat-versatile/clock.c and plat-versatile/include/plat/clock.h
*/
static const struct icst_params cp_auxvco_params = { /* Base offset for the core module */
.ref = 24000000, static void __iomem *cm_base;
static const struct icst_params cp_auxosc_params = {
.vco_max = ICST525_VCO_MAX_5V, .vco_max = ICST525_VCO_MAX_5V,
.vco_min = ICST525_VCO_MIN, .vco_min = ICST525_VCO_MIN,
.vd_min = 8, .vd_min = 8,
...@@ -35,50 +31,39 @@ static const struct icst_params cp_auxvco_params = { ...@@ -35,50 +31,39 @@ static const struct icst_params cp_auxvco_params = {
.idx2s = icst525_idx2s, .idx2s = icst525_idx2s,
}; };
static const struct clk_icst_desc __initdata cp_icst_desc = { static const struct clk_icst_desc __initdata cm_auxosc_desc = {
.params = &cp_auxvco_params, .params = &cp_auxosc_params,
.vco_offset = 0x1c, .vco_offset = 0x1c,
.lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
}; };
/* static void __init of_integrator_cm_osc_setup(struct device_node *np)
* integrator_clk_init() - set up the integrator clock tree
* @is_cp: pass true if it's the Integrator/CP else AP is assumed
*/
void __init integrator_clk_init(bool is_cp)
{ {
struct clk *clk; struct clk *clk = ERR_PTR(-EINVAL);
const char *clk_name = np->name;
/* APB clock dummy */ const struct clk_icst_desc *desc = &cm_auxosc_desc;
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); const char *parent_name;
clk_register_clkdev(clk, "apb_pclk", NULL);
/* UART reference clock */
clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
14745600);
clk_register_clkdev(clk, NULL, "uart0");
clk_register_clkdev(clk, NULL, "uart1");
if (is_cp)
clk_register_clkdev(clk, NULL, "mmci");
/* 24 MHz clock */
clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT,
24000000);
clk_register_clkdev(clk, NULL, "kmi0");
clk_register_clkdev(clk, NULL, "kmi1");
if (!is_cp)
clk_register_clkdev(clk, NULL, "ap_timer");
if (!is_cp) if (!cm_base) {
return; /* Remap the core module base if not done yet */
struct device_node *parent;
/* 1 MHz clock */ parent = of_get_parent(np);
clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT, if (!np) {
1000000); pr_err("no parent on core module clock\n");
clk_register_clkdev(clk, NULL, "sp804"); return;
}
cm_base = of_iomap(parent, 0);
if (!cm_base) {
pr_err("could not remap core module base\n");
return;
}
}
/* ICST VCO clock used on the Integrator/CP CLCD */ parent_name = of_clk_get_parent_name(np, 0);
clk = icst_clk_register(NULL, &cp_icst_desc, "icst", clk = icst_clk_register(NULL, desc, clk_name, parent_name, cm_base);
__io_address(INTEGRATOR_HDR_BASE)); if (!IS_ERR(clk))
clk_register_clkdev(clk, NULL, "clcd"); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
CLK_OF_DECLARE(integrator_cm_auxosc_clk,
"arm,integrator-cm-auxosc", of_integrator_cm_osc_setup);
...@@ -85,10 +85,10 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) ...@@ -85,10 +85,10 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
/* ICST VCO clock */ /* ICST VCO clock */
if (is_pb1176) if (is_pb1176)
clk = icst_clk_register(NULL, &realview_osc0_desc, clk = icst_clk_register(NULL, &realview_osc0_desc,
"osc0", sysbase); "osc0", NULL, sysbase);
else else
clk = icst_clk_register(NULL, &realview_osc4_desc, clk = icst_clk_register(NULL, &realview_osc4_desc,
"osc4", sysbase); "osc4", NULL, sysbase);
clk_register_clkdev(clk, NULL, "dev:clcd"); clk_register_clkdev(clk, NULL, "dev:clcd");
clk_register_clkdev(clk, NULL, "issp:clcd"); clk_register_clkdev(clk, NULL, "issp:clcd");
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
/** /**
* struct vic_device - VIC PM device * struct vic_device - VIC PM device
* @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
* @irq: The IRQ number for the base of the VIC. * @irq: The IRQ number for the base of the VIC.
* @base: The register base for the VIC. * @base: The register base for the VIC.
* @valid_sources: A bitmask of valid interrupts * @valid_sources: A bitmask of valid interrupts
...@@ -224,6 +225,17 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) ...@@ -224,6 +225,17 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
return handled; return handled;
} }
static void vic_handle_irq_cascaded(unsigned int irq, struct irq_desc *desc)
{
u32 stat, hwirq;
struct vic_device *vic = irq_desc_get_handler_data(desc);
while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
hwirq = ffs(stat) - 1;
generic_handle_irq(irq_find_mapping(vic->domain, hwirq));
}
}
/* /*
* Keep iterating over all registered VIC's until there are no pending * Keep iterating over all registered VIC's until there are no pending
* interrupts. * interrupts.
...@@ -246,6 +258,7 @@ static struct irq_domain_ops vic_irqdomain_ops = { ...@@ -246,6 +258,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
/** /**
* vic_register() - Register a VIC. * vic_register() - Register a VIC.
* @base: The base address of the VIC. * @base: The base address of the VIC.
* @parent_irq: The parent IRQ if cascaded, else 0.
* @irq: The base IRQ for the VIC. * @irq: The base IRQ for the VIC.
* @valid_sources: bitmask of valid interrupts * @valid_sources: bitmask of valid interrupts
* @resume_sources: bitmask of interrupts allowed for resume sources. * @resume_sources: bitmask of interrupts allowed for resume sources.
...@@ -257,7 +270,8 @@ static struct irq_domain_ops vic_irqdomain_ops = { ...@@ -257,7 +270,8 @@ static struct irq_domain_ops vic_irqdomain_ops = {
* *
* This also configures the IRQ domain for the VIC. * This also configures the IRQ domain for the VIC.
*/ */
static void __init vic_register(void __iomem *base, unsigned int irq, static void __init vic_register(void __iomem *base, unsigned int parent_irq,
unsigned int irq,
u32 valid_sources, u32 resume_sources, u32 valid_sources, u32 resume_sources,
struct device_node *node) struct device_node *node)
{ {
...@@ -273,15 +287,25 @@ static void __init vic_register(void __iomem *base, unsigned int irq, ...@@ -273,15 +287,25 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
v->base = base; v->base = base;
v->valid_sources = valid_sources; v->valid_sources = valid_sources;
v->resume_sources = resume_sources; v->resume_sources = resume_sources;
v->irq = irq;
set_handle_irq(vic_handle_irq); set_handle_irq(vic_handle_irq);
vic_id++; vic_id++;
if (parent_irq) {
irq_set_handler_data(parent_irq, v);
irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded);
}
v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
&vic_irqdomain_ops, v); &vic_irqdomain_ops, v);
/* create an IRQ mapping for each valid IRQ */ /* create an IRQ mapping for each valid IRQ */
for (i = 0; i < fls(valid_sources); i++) for (i = 0; i < fls(valid_sources); i++)
if (valid_sources & (1 << i)) if (valid_sources & (1 << i))
irq_create_mapping(v->domain, i); irq_create_mapping(v->domain, i);
/* If no base IRQ was passed, figure out our allocated base */
if (irq)
v->irq = irq;
else
v->irq = irq_find_mapping(v->domain, 0);
} }
static void vic_ack_irq(struct irq_data *d) static void vic_ack_irq(struct irq_data *d)
...@@ -409,10 +433,10 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, ...@@ -409,10 +433,10 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
writel(32, base + VIC_PL190_DEF_VECT_ADDR); writel(32, base + VIC_PL190_DEF_VECT_ADDR);
} }
vic_register(base, irq_start, vic_sources, 0, node); vic_register(base, 0, irq_start, vic_sources, 0, node);
} }
void __init __vic_init(void __iomem *base, int irq_start, void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
u32 vic_sources, u32 resume_sources, u32 vic_sources, u32 resume_sources,
struct device_node *node) struct device_node *node)
{ {
...@@ -449,7 +473,7 @@ void __init __vic_init(void __iomem *base, int irq_start, ...@@ -449,7 +473,7 @@ void __init __vic_init(void __iomem *base, int irq_start,
vic_init2(base); vic_init2(base);
vic_register(base, irq_start, vic_sources, resume_sources, node); vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
} }
/** /**
...@@ -462,7 +486,28 @@ void __init __vic_init(void __iomem *base, int irq_start, ...@@ -462,7 +486,28 @@ void __init __vic_init(void __iomem *base, int irq_start,
void __init vic_init(void __iomem *base, unsigned int irq_start, void __init vic_init(void __iomem *base, unsigned int irq_start,
u32 vic_sources, u32 resume_sources) u32 vic_sources, u32 resume_sources)
{ {
__vic_init(base, irq_start, vic_sources, resume_sources, NULL); __vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
}
/**
* vic_init_cascaded() - initialise a cascaded vectored interrupt controller
* @base: iomem base address
* @parent_irq: the parent IRQ we're cascaded off
* @irq_start: starting interrupt number, must be muliple of 32
* @vic_sources: bitmask of interrupt sources to allow
* @resume_sources: bitmask of interrupt sources to allow for resume
*
* This returns the base for the new interrupts or negative on error.
*/
int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
u32 vic_sources, u32 resume_sources)
{
struct vic_device *v;
v = &vic_devices[vic_id];
__vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
/* Return out acquired base */
return v->irq;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -485,7 +530,7 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent) ...@@ -485,7 +530,7 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
/* /*
* Passing 0 as first IRQ makes the simple domain allocate descriptors * Passing 0 as first IRQ makes the simple domain allocate descriptors
*/ */
__vic_init(regs, 0, interrupt_mask, wakeup_mask, node); __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
return 0; return 0;
} }
......
...@@ -29,8 +29,10 @@ ...@@ -29,8 +29,10 @@
struct device_node; struct device_node;
struct pt_regs; struct pt_regs;
void __vic_init(void __iomem *base, int irq_start, u32 vic_sources, void __vic_init(void __iomem *base, int parent_irq, int irq_start,
u32 resume_sources, struct device_node *node); u32 vic_sources, u32 resume_sources, struct device_node *node);
void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
u32 vic_sources, u32 resume_sources);
#endif #endif
void integrator_clk_init(bool is_cp);
void integrator_impd1_clk_init(void __iomem *base, unsigned int id); void integrator_impd1_clk_init(void __iomem *base, unsigned int id);
void integrator_impd1_clk_exit(unsigned int id); void integrator_impd1_clk_exit(unsigned int id);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment