forked from Minki/linux
Integrator/Versatile base patch stack for the v3.15 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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJS/J2oAAoJEEEQszewGV1zkTYP/RCvXqFHsMONrQLtIVCcf0Yp Hzr4+hsfXZBTAGR5kvsxCeu/BNbyEEdm85Nqe6S1ehcGyZ5RWieqN1NgA7sCHZCu rJzBC6cJXRa+8r5i+IdjmpVhftV9d1DP6aTM2Z0GpNyhuefQTUskNA2w4ltVEfLz mJ7xwoRURXGVY/vmlyBTnDaPv8J7jFGdxUyYoQtH/MRWsuiBCuiSUXYn0FmHEjeC KG8ETTjQbZxjl2ewDrbv8S+U2Xu0DLn1iKTZbwpSyfYlIQM+FoBvJ8RHIAVTz3AK bWYSq+C0yghupejiZ9JUoqWL7c2Lq8ijaX5yzwhV6EKuVvD4tem23jO/SIObmIgp 3ruobAwE5VWq2PPDD/FWL6WYbWulE9MhLAzIZuWowIMQpGezey9CPt4E9HLAhQTM akaX3nbFVkpp10ptcYm4p3DIEZklusf/1wC78b5p+kOOlqNI2uip7vI+caWJmyVJ wdyCaB2QXu45B7Eil7iZwkZqzoVO3+jVcINrhh3sG/BeyKXQYmTEZ73CSboik9uT kI9RWPSHrLVogSnBAHVnXsEvFnH1shzYTsv4xozRll4Zy7kVTl3Kdm4Od/GY+hSl SSLKXaVUePjbPokpiuUZbrQHZU53qCFgsATJWFngekIwI7FL/oRohKiSSgFD7CkF OfUKlAimgolxDi0inHJ2 =a4vs -----END PGP SIGNATURE----- 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: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
b5feaefb45
34
Documentation/devicetree/bindings/clock/arm-integrator.txt
Normal file
34
Documentation/devicetree/bindings/clock/arm-integrator.txt
Normal file
@ -0,0 +1,34 @@
|
||||
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 @@
|
||||
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 {
|
||||
compatible = "arm,integrator-ap-syscon";
|
||||
reg = <0x11000000 0x100>;
|
||||
@ -28,14 +50,17 @@
|
||||
|
||||
timer0: timer@13000000 {
|
||||
compatible = "arm,integrator-timer";
|
||||
clocks = <&xtal24mhz>;
|
||||
};
|
||||
|
||||
timer1: timer@13000100 {
|
||||
compatible = "arm,integrator-timer";
|
||||
clocks = <&xtal24mhz>;
|
||||
};
|
||||
|
||||
timer2: timer@13000200 {
|
||||
compatible = "arm,integrator-timer";
|
||||
clocks = <&xtal24mhz>;
|
||||
};
|
||||
|
||||
pic: pic@14000000 {
|
||||
@ -92,26 +117,36 @@
|
||||
rtc: rtc@15000000 {
|
||||
compatible = "arm,pl030", "arm,primecell";
|
||||
arm,primecell-periphid = <0x00041030>;
|
||||
clocks = <&pclk>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
uart0: uart@16000000 {
|
||||
compatible = "arm,pl010", "arm,primecell";
|
||||
arm,primecell-periphid = <0x00041010>;
|
||||
clocks = <&uartclk>, <&pclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
uart1: uart@17000000 {
|
||||
compatible = "arm,pl010", "arm,primecell";
|
||||
arm,primecell-periphid = <0x00041010>;
|
||||
clocks = <&uartclk>, <&pclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi0: kmi@18000000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
arm,primecell-periphid = <0x00041050>;
|
||||
clocks = <&xtal24mhz>, <&pclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi1: kmi@19000000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
arm,primecell-periphid = <0x00041050>;
|
||||
clocks = <&xtal24mhz>, <&pclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -13,25 +13,107 @@
|
||||
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 {
|
||||
compatible = "arm,integrator-cp-syscon";
|
||||
reg = <0xcb000000 0x100>;
|
||||
};
|
||||
|
||||
timer0: timer@13000000 {
|
||||
/* TIMER0 runs @ 25MHz */
|
||||
/* TIMER0 runs directly on the 25MHz chrystal */
|
||||
compatible = "arm,integrator-cp-timer";
|
||||
status = "disabled";
|
||||
clocks = <&xtal25mhz>;
|
||||
};
|
||||
|
||||
timer1: timer@13000100 {
|
||||
/* TIMER1 runs @ 1MHz */
|
||||
compatible = "arm,integrator-cp-timer";
|
||||
clocks = <&timclk>;
|
||||
};
|
||||
|
||||
timer2: timer@13000200 {
|
||||
/* TIMER2 runs @ 1MHz */
|
||||
compatible = "arm,integrator-cp-timer";
|
||||
clocks = <&timclk>;
|
||||
};
|
||||
|
||||
pic: pic@14000000 {
|
||||
@ -74,22 +156,32 @@
|
||||
*/
|
||||
rtc@15000000 {
|
||||
compatible = "arm,pl031", "arm,primecell";
|
||||
clocks = <&pclk>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
uart@16000000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
clocks = <&uartclk>, <&pclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
uart@17000000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
clocks = <&uartclk>, <&pclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi@18000000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
clocks = <&kmiclk>, <&pclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi@19000000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
clocks = <&kmiclk>, <&pclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
|
||||
/*
|
||||
@ -100,18 +192,24 @@
|
||||
reg = <0x1c000000 0x1000>;
|
||||
interrupts = <23 24>;
|
||||
max-frequency = <515633>;
|
||||
clocks = <&uartclk>, <&pclk>;
|
||||
clock-names = "mclk", "apb_pclk";
|
||||
};
|
||||
|
||||
aaci@1d000000 {
|
||||
compatible = "arm,pl041", "arm,primecell";
|
||||
reg = <0x1d000000 0x1000>;
|
||||
interrupts = <25>;
|
||||
clocks = <&pclk>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
clcd@c0000000 {
|
||||
compatible = "arm,pl110", "arm,primecell";
|
||||
reg = <0xC0000000 0x1000>;
|
||||
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)
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
const char *name = of_get_property(np, "compatible", NULL);
|
||||
struct clk *clk;
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
clk = of_clk_get(np, 0);
|
||||
if (WARN_ON(IS_ERR(clk)))
|
||||
return;
|
||||
|
||||
/* Ensure timer is disabled */
|
||||
writel(0, base + TIMER_CTRL);
|
||||
@ -283,13 +287,13 @@ static void __init integrator_cp_of_init(struct device_node *np)
|
||||
goto err;
|
||||
|
||||
if (!init_count)
|
||||
sp804_clocksource_init(base, name);
|
||||
__sp804_clocksource_and_sched_clock_init(base, name, clk, 0);
|
||||
else {
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (irq <= 0)
|
||||
goto err;
|
||||
|
||||
sp804_clockevents_init(base, irq, name);
|
||||
__sp804_clockevents_init(base, irq, clk, name);
|
||||
}
|
||||
|
||||
init_count++;
|
||||
|
@ -30,6 +30,9 @@ config ARCH_CINTEGRATOR
|
||||
config INTEGRATOR_IMPD1
|
||||
tristate "Include support for Integrator/IM-PD1"
|
||||
depends on ARCH_INTEGRATOR_AP
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select ARM_VIC
|
||||
select GPIO_PL061 if GPIOLIB
|
||||
help
|
||||
The IM-PD1 is an add-on logic module for the Integrator which
|
||||
allows ARM(R) Ltd PrimeCells to be developed and evaluated.
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/clk-integrator.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irqchip/arm-vic.h>
|
||||
|
||||
#include <mach/lm.h>
|
||||
#include <mach/impd1.h>
|
||||
@ -35,6 +36,7 @@ MODULE_PARM_DESC(lmid, "logic module stack position");
|
||||
|
||||
struct impd1_module {
|
||||
void __iomem *base;
|
||||
void __iomem *vic_base;
|
||||
};
|
||||
|
||||
void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
|
||||
@ -262,9 +264,6 @@ struct impd1_device {
|
||||
|
||||
static struct impd1_device impd1_devs[] = {
|
||||
{
|
||||
.offset = 0x03000000,
|
||||
.id = 0x00041190,
|
||||
}, {
|
||||
.offset = 0x00100000,
|
||||
.irq = { 1 },
|
||||
.id = 0x00141011,
|
||||
@ -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;
|
||||
int i, ret;
|
||||
int irq_base;
|
||||
int i;
|
||||
|
||||
if (dev->id != module_id)
|
||||
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;
|
||||
|
||||
impd1 = kzalloc(sizeof(struct impd1_module), GFP_KERNEL);
|
||||
if (!impd1) {
|
||||
ret = -ENOMEM;
|
||||
goto release_lm;
|
||||
}
|
||||
impd1 = devm_kzalloc(&dev->dev, sizeof(struct impd1_module),
|
||||
GFP_KERNEL);
|
||||
if (!impd1)
|
||||
return -ENOMEM;
|
||||
|
||||
impd1->base = ioremap(dev->resource.start, SZ_4K);
|
||||
if (!impd1->base) {
|
||||
ret = -ENOMEM;
|
||||
goto free_impd1;
|
||||
}
|
||||
impd1->base = devm_ioremap(&dev->dev, dev->resource.start, SZ_4K);
|
||||
if (!impd1->base)
|
||||
return -ENOMEM;
|
||||
|
||||
integrator_impd1_clk_init(impd1->base, dev->id);
|
||||
|
||||
if (!devm_request_mem_region(&dev->dev,
|
||||
dev->resource.start + 0x03000000,
|
||||
SZ_4K, "VIC"))
|
||||
return -EBUSY;
|
||||
|
||||
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);
|
||||
|
||||
printk("IM-PD1 found at 0x%08lx\n",
|
||||
(unsigned long)dev->resource.start);
|
||||
|
||||
integrator_impd1_clk_init(impd1->base, dev->id);
|
||||
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++) {
|
||||
struct impd1_device *idev = impd1_devs + i;
|
||||
struct amba_device *d;
|
||||
unsigned long pc_base;
|
||||
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;
|
||||
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,
|
||||
dev->irq, dev->irq,
|
||||
irq1, irq2,
|
||||
idev->platform_data, idev->id,
|
||||
&dev->resource);
|
||||
if (IS_ERR(d)) {
|
||||
@ -353,14 +378,6 @@ static int impd1_probe(struct lm_device *dev)
|
||||
}
|
||||
|
||||
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)
|
||||
@ -371,16 +388,10 @@ static int impd1_remove_one(struct device *dev, void *data)
|
||||
|
||||
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);
|
||||
integrator_impd1_clk_exit(dev->id);
|
||||
|
||||
lm_set_drvdata(dev, NULL);
|
||||
|
||||
iounmap(impd1->base);
|
||||
kfree(impd1);
|
||||
release_mem_region(dev->resource.start, SZ_4K);
|
||||
}
|
||||
|
||||
static struct lm_driver impd1_driver = {
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/platform.h>
|
||||
@ -402,10 +403,7 @@ static void __init ap_of_timer_init(void)
|
||||
struct clk *clk;
|
||||
unsigned long rate;
|
||||
|
||||
clk = clk_get_sys("ap_timer", NULL);
|
||||
BUG_ON(IS_ERR(clk));
|
||||
clk_prepare_enable(clk);
|
||||
rate = clk_get_rate(clk);
|
||||
of_clk_init(NULL);
|
||||
|
||||
err = of_property_read_string(of_aliases,
|
||||
"arm,timer-primary", &path);
|
||||
@ -415,6 +413,12 @@ static void __init ap_of_timer_init(void)
|
||||
base = of_iomap(node, 0);
|
||||
if (WARN_ON(!base))
|
||||
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);
|
||||
integrator_clocksource_init(rate, base);
|
||||
|
||||
@ -427,6 +431,12 @@ static void __init ap_of_timer_init(void)
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
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);
|
||||
integrator_clockevent_init(rate, base, irq);
|
||||
}
|
||||
@ -440,7 +450,6 @@ static void __init ap_init_irq_of(void)
|
||||
{
|
||||
cm_init();
|
||||
of_irq_init(fpga_irq_of_match);
|
||||
integrator_clk_init(false);
|
||||
}
|
||||
|
||||
/* For the Device Tree, add in the UART callbacks as AUXDATA */
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <linux/irqchip/versatile-fpga.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/platform_data/clk-integrator.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
@ -33,8 +32,6 @@
|
||||
#include <mach/platform.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/hardware/arm_timer.h>
|
||||
#include <asm/hardware/icst.h>
|
||||
|
||||
#include <mach/lm.h>
|
||||
|
||||
@ -43,8 +40,6 @@
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
#include <asm/hardware/timer-sp.h>
|
||||
|
||||
#include <plat/clcd.h>
|
||||
#include <plat/sched_clock.h>
|
||||
|
||||
@ -250,7 +245,6 @@ static void __init intcp_init_irq_of(void)
|
||||
{
|
||||
cm_init();
|
||||
of_irq_init(fpga_irq_of_match);
|
||||
integrator_clk_init(true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -108,7 +108,7 @@ void __init versatile_init_irq(void)
|
||||
|
||||
np = of_find_matching_node_by_address(NULL, vic_of_match,
|
||||
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);
|
||||
|
||||
|
@ -33,7 +33,7 @@ struct clk_icst {
|
||||
struct clk_hw hw;
|
||||
void __iomem *vcoreg;
|
||||
void __iomem *lockreg;
|
||||
const struct icst_params *params;
|
||||
struct icst_params *params;
|
||||
unsigned long rate;
|
||||
};
|
||||
|
||||
@ -84,6 +84,8 @@ static unsigned long icst_recalc_rate(struct clk_hw *hw,
|
||||
struct clk_icst *icst = to_icst(hw);
|
||||
struct icst_vco vco;
|
||||
|
||||
if (parent_rate)
|
||||
icst->params->ref = parent_rate;
|
||||
vco = vco_get(icst->vcoreg);
|
||||
icst->rate = icst_hz(icst->params, vco);
|
||||
return icst->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 icst_vco vco;
|
||||
|
||||
if (parent_rate)
|
||||
icst->params->ref = parent_rate;
|
||||
vco = icst_hz_to_vco(icst->params, rate);
|
||||
icst->rate = icst_hz(icst->params, vco);
|
||||
vco_set(icst->lockreg, icst->vcoreg, vco);
|
||||
@ -120,24 +124,33 @@ static const struct clk_ops icst_ops = {
|
||||
struct clk *icst_clk_register(struct device *dev,
|
||||
const struct clk_icst_desc *desc,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_icst *icst;
|
||||
struct clk_init_data init;
|
||||
struct icst_params *pclone;
|
||||
|
||||
icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL);
|
||||
if (!icst) {
|
||||
pr_err("could not allocate ICST clock!\n");
|
||||
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.ops = &icst_ops;
|
||||
init.flags = CLK_IS_ROOT;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
icst->hw.init = &init;
|
||||
icst->params = desc->params;
|
||||
icst->params = pclone;
|
||||
icst->vcoreg = base + desc->vco_offset;
|
||||
icst->lockreg = base + desc->lock_offset;
|
||||
|
||||
|
@ -16,4 +16,5 @@ struct clk_icst_desc {
|
||||
struct clk *icst_clk_register(struct device *dev,
|
||||
const struct clk_icst_desc *desc,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
void __iomem *base);
|
||||
|
@ -93,13 +93,15 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
|
||||
imc = &impd1_clks[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->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
|
||||
|
||||
/* 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);
|
||||
clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, NULL,
|
||||
base);
|
||||
imc->vco2clk = clk;
|
||||
|
||||
/* MMCI uses CLK2 right off */
|
||||
|
@ -10,21 +10,17 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_data/clk-integrator.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/platform.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include "clk-icst.h"
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
#define INTEGRATOR_HDR_LOCK_OFFSET 0x14
|
||||
|
||||
static const struct icst_params cp_auxvco_params = {
|
||||
.ref = 24000000,
|
||||
/* Base offset for the core module */
|
||||
static void __iomem *cm_base;
|
||||
|
||||
static const struct icst_params cp_auxosc_params = {
|
||||
.vco_max = ICST525_VCO_MAX_5V,
|
||||
.vco_min = ICST525_VCO_MIN,
|
||||
.vd_min = 8,
|
||||
@ -35,50 +31,39 @@ static const struct icst_params cp_auxvco_params = {
|
||||
.idx2s = icst525_idx2s,
|
||||
};
|
||||
|
||||
static const struct clk_icst_desc __initdata cp_icst_desc = {
|
||||
.params = &cp_auxvco_params,
|
||||
static const struct clk_icst_desc __initdata cm_auxosc_desc = {
|
||||
.params = &cp_auxosc_params,
|
||||
.vco_offset = 0x1c,
|
||||
.lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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)
|
||||
static void __init of_integrator_cm_osc_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk *clk = ERR_PTR(-EINVAL);
|
||||
const char *clk_name = np->name;
|
||||
const struct clk_icst_desc *desc = &cm_auxosc_desc;
|
||||
const char *parent_name;
|
||||
|
||||
/* APB clock dummy */
|
||||
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
|
||||
clk_register_clkdev(clk, "apb_pclk", NULL);
|
||||
if (!cm_base) {
|
||||
/* Remap the core module base if not done yet */
|
||||
struct device_node *parent;
|
||||
|
||||
/* 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");
|
||||
parent = of_get_parent(np);
|
||||
if (!np) {
|
||||
pr_err("no parent on core module clock\n");
|
||||
return;
|
||||
}
|
||||
cm_base = of_iomap(parent, 0);
|
||||
if (!cm_base) {
|
||||
pr_err("could not remap core module base\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
return;
|
||||
|
||||
/* 1 MHz clock */
|
||||
clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT,
|
||||
1000000);
|
||||
clk_register_clkdev(clk, NULL, "sp804");
|
||||
|
||||
/* ICST VCO clock used on the Integrator/CP CLCD */
|
||||
clk = icst_clk_register(NULL, &cp_icst_desc, "icst",
|
||||
__io_address(INTEGRATOR_HDR_BASE));
|
||||
clk_register_clkdev(clk, NULL, "clcd");
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
clk = icst_clk_register(NULL, desc, clk_name, parent_name, cm_base);
|
||||
if (!IS_ERR(clk))
|
||||
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)
|
||||
/* ICST VCO clock */
|
||||
if (is_pb1176)
|
||||
clk = icst_clk_register(NULL, &realview_osc0_desc,
|
||||
"osc0", sysbase);
|
||||
"osc0", NULL, sysbase);
|
||||
else
|
||||
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, "issp:clcd");
|
||||
|
@ -57,6 +57,7 @@
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @base: The register base for the VIC.
|
||||
* @valid_sources: A bitmask of valid interrupts
|
||||
@ -224,6 +225,17 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
|
||||
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
|
||||
* interrupts.
|
||||
@ -246,6 +258,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
|
||||
/**
|
||||
* vic_register() - Register a VIC.
|
||||
* @base: The base address of the VIC.
|
||||
* @parent_irq: The parent IRQ if cascaded, else 0.
|
||||
* @irq: The base IRQ for the VIC.
|
||||
* @valid_sources: bitmask of valid interrupts
|
||||
* @resume_sources: bitmask of interrupts allowed for resume sources.
|
||||
@ -257,7 +270,8 @@ static struct irq_domain_ops vic_irqdomain_ops = {
|
||||
*
|
||||
* 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,
|
||||
struct device_node *node)
|
||||
{
|
||||
@ -273,15 +287,25 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
|
||||
v->base = base;
|
||||
v->valid_sources = valid_sources;
|
||||
v->resume_sources = resume_sources;
|
||||
v->irq = irq;
|
||||
set_handle_irq(vic_handle_irq);
|
||||
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,
|
||||
&vic_irqdomain_ops, v);
|
||||
/* create an IRQ mapping for each valid IRQ */
|
||||
for (i = 0; i < fls(valid_sources); i++)
|
||||
if (valid_sources & (1 << 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)
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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,
|
||||
struct device_node *node)
|
||||
{
|
||||
@ -449,7 +473,7 @@ void __init __vic_init(void __iomem *base, int irq_start,
|
||||
|
||||
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,
|
||||
void __init vic_init(void __iomem *base, unsigned int irq_start,
|
||||
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
|
||||
@ -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
|
||||
*/
|
||||
__vic_init(regs, 0, interrupt_mask, wakeup_mask, node);
|
||||
__vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,8 +29,10 @@
|
||||
struct device_node;
|
||||
struct pt_regs;
|
||||
|
||||
void __vic_init(void __iomem *base, int irq_start, u32 vic_sources,
|
||||
u32 resume_sources, struct device_node *node);
|
||||
void __vic_init(void __iomem *base, int parent_irq, int irq_start,
|
||||
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);
|
||||
int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
|
||||
u32 vic_sources, u32 resume_sources);
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,2 @@
|
||||
void integrator_clk_init(bool is_cp);
|
||||
void integrator_impd1_clk_init(void __iomem *base, unsigned int id);
|
||||
void integrator_impd1_clk_exit(unsigned int id);
|
||||
|
Loading…
Reference in New Issue
Block a user