aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2012-05-14 21:37:04 +0200
committerArnd Bergmann <arnd@arndb.de>2012-05-14 21:37:04 +0200
commit853b20396becfe9425f4d5da74e10ea67811b188 (patch)
tree6cbd5db9ce11677769a34d205a47907a0f2a75a8
parentb335d89cd455ef89c734b9a25de1ab0e745363eb (diff)
parentace1297f7222ec5d6a33f41e792a21e999551924 (diff)
Merge branch 'mmp/dt' into next/pm
The mmp power management changes are based on this branch, so pull it in as a dependency. Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--Documentation/devicetree/bindings/arm/mrvl/intc.txt40
-rw-r--r--Documentation/devicetree/bindings/arm/mrvl/mrvl.txt (renamed from Documentation/devicetree/bindings/arm/mrvl.txt)8
-rw-r--r--Documentation/devicetree/bindings/arm/mrvl/timer.txt13
-rw-r--r--Documentation/devicetree/bindings/gpio/mrvl-gpio.txt18
-rw-r--r--Documentation/devicetree/bindings/i2c/mrvl-i2c.txt15
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/boot/dts/mmp2-brownstone.dts38
-rw-r--r--arch/arm/boot/dts/mmp2.dtsi220
-rw-r--r--arch/arm/boot/dts/pxa168.dtsi67
-rw-r--r--arch/arm/boot/dts/pxa910-dkb.dts38
-rw-r--r--arch/arm/boot/dts/pxa910.dtsi140
-rw-r--r--arch/arm/mach-mmp/Kconfig29
-rw-r--r--arch/arm/mach-mmp/Makefile9
-rw-r--r--arch/arm/mach-mmp/include/mach/entry-macro.S4
-rw-r--r--arch/arm/mach-mmp/include/mach/irqs.h27
-rw-r--r--arch/arm/mach-mmp/irq-mmp2.c158
-rw-r--r--arch/arm/mach-mmp/irq-pxa168.c54
-rw-r--r--arch/arm/mach-mmp/irq.c445
-rw-r--r--arch/arm/mach-mmp/mmp-dt.c66
-rw-r--r--arch/arm/mach-mmp/mmp2-dt.c60
-rw-r--r--arch/arm/mach-mmp/time.c81
-rw-r--r--drivers/gpio/gpio-pxa.c116
22 files changed, 1313 insertions, 334 deletions
diff --git a/Documentation/devicetree/bindings/arm/mrvl/intc.txt b/Documentation/devicetree/bindings/arm/mrvl/intc.txt
new file mode 100644
index 00000000000..80b9a94d9a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/intc.txt
@@ -0,0 +1,40 @@
+* Marvell MMP Interrupt controller
+
+Required properties:
+- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or
+ "mrvl,mmp2-mux-intc"
+- reg : Address and length of the register set of the interrupt controller.
+ If the interrupt controller is intc, address and length means the range
+ of the whold interrupt controller. If the interrupt controller is mux-intc,
+ address and length means one register. Since address of mux-intc is in the
+ range of intc. mux-intc is secondary interrupt controller.
+- reg-names : Name of the register set of the interrupt controller. It's
+ only required in mux-intc interrupt controller.
+- interrupts : Should be the port interrupt shared by mux interrupts. It's
+ only required in mux-intc interrupt controller.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source.
+- mrvl,intc-nr-irqs : Specifies the number of interrupts in the interrupt
+ controller.
+- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge
+ detection first.
+
+Example:
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp2-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ intcmux4@d4282150 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x150 0x4>, <0x168 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
index d8de933e9d8..117d741a2e4 100644
--- a/Documentation/devicetree/bindings/arm/mrvl.txt
+++ b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
@@ -4,3 +4,11 @@ Marvell Platforms Device Tree Bindings
PXA168 Aspenite Board
Required root node properties:
- compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
+
+PXA910 DKB Board
+Required root node properties:
+ - compatible = "mrvl,pxa910-dkb";
+
+MMP2 Brownstone Board
+Required root node properties:
+ - compatible = "mrvl,mmp2-brownstone";
diff --git a/Documentation/devicetree/bindings/arm/mrvl/timer.txt b/Documentation/devicetree/bindings/arm/mrvl/timer.txt
new file mode 100644
index 00000000000..9a6e251462e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/timer.txt
@@ -0,0 +1,13 @@
+* Marvell MMP Timer controller
+
+Required properties:
+- compatible : Should be "mrvl,mmp-timer".
+- reg : Address and length of the register set of timer controller.
+- interrupts : Should be the interrupt number.
+
+Example:
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
index 1e34cfe5ebe..05428f39d9a 100644
--- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
@@ -3,19 +3,25 @@
Required properties:
- compatible : Should be "mrvl,pxa-gpio" or "mrvl,mmp-gpio"
- reg : Address and length of the register set for the device
-- interrupts : Should be the port interrupt shared by all gpio pins, if
-- interrupt-name : Should be the name of irq resource.
- one number.
+- interrupts : Should be the port interrupt shared by all gpio pins.
+ There're three gpio interrupts in arch-pxa, and they're gpio0,
+ gpio1 and gpio_mux. There're only one gpio interrupt in arch-mmp,
+ gpio_mux.
+- interrupt-name : Should be the name of irq resource. Each interrupt
+ binds its interrupt-name.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells: Specifies the number of cells needed to encode an
+ interrupt source.
- gpio-controller : Marks the device node as a gpio controller.
- #gpio-cells : Should be one. It is the pin number.
Example:
gpio: gpio@d4019000 {
- compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+ compatible = "mrvl,mmp-gpio";
reg = <0xd4019000 0x1000>;
- interrupts = <49>, <17>, <18>;
- interrupt-name = "gpio_mux", "gpio0", "gpio1";
+ interrupts = <49>;
+ interrupt-name = "gpio_mux";
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
index 071eb3caae9..b891ee21835 100644
--- a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
@@ -3,34 +3,31 @@
Required properties :
- reg : Offset and length of the register set for the device
- - compatible : should be "mrvl,mmp-twsi" where CHIP is the name of a
+ - compatible : should be "mrvl,mmp-twsi" where mmp is the name of a
compatible processor, e.g. pxa168, pxa910, mmp2, mmp3.
For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required
as shown in the example below.
Recommended properties :
- - interrupts : <a b> where a is the interrupt number and b is a
- field that represents an encoding of the sense and level
- information for the interrupt. This should be encoded based on
- the information in section 2) depending on the type of interrupt
- controller you have.
+ - interrupts : the interrupt number
- interrupt-parent : the phandle for the interrupt controller that
- services interrupts for this device.
+ services interrupts for this device. If the parent is the default
+ interrupt controller in device tree, it could be ignored.
- mrvl,i2c-polling : Disable interrupt of i2c controller. Polling
status register of i2c controller instead.
- mrvl,i2c-fast-mode : Enable fast mode of i2c controller.
Examples:
twsi1: i2c@d4011000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
mrvl,i2c-fast-mode;
};
twsi2: i2c@d4025000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>;
interrupts = <58>;
};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cf006d40342..4cf9d428097 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -632,6 +632,7 @@ config ARCH_MMP
select CLKDEV_LOOKUP
select GENERIC_CLOCKEVENTS
select GPIO_PXA
+ select IRQ_DOMAIN
select TICK_ONESHOT
select PLAT_PXA
select SPARSE_IRQ
diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
new file mode 100644
index 00000000000..153a4b2d12b
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2-brownstone.dts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "mmp2.dtsi"
+
+/ {
+ model = "Marvell MMP2 Aspenite Development Board";
+ compatible = "mrvl,mmp2-brownstone", "mrvl,mmp2";
+
+ chosen {
+ bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+ };
+
+ memory {
+ reg = <0x00000000 0x04000000>;
+ };
+
+ soc {
+ apb@d4000000 {
+ uart3: uart@d4018000 {
+ status = "okay";
+ };
+ twsi1: i2c@d4011000 {
+ status = "okay";
+ };
+ rtc: rtc@d4010000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi
new file mode 100644
index 00000000000..80f74e25640
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2.dtsi
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart1;
+ serial1 = &uart2;
+ serial2 = &uart3;
+ serial3 = &uart4;
+ i2c0 = &twsi1;
+ i2c1 = &twsi2;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ axi@d4200000 { /* AXI */
+ compatible = "mrvl,axi-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4200000 0x00200000>;
+ ranges;
+
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp2-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ intcmux4@d4282150 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x150 0x4>, <0x168 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
+
+ intcmux5: interrupt-controller@d4282154 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <5>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x154 0x4>, <0x16c 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ mrvl,clr-mfp-irq = <1>;
+ };
+
+ intcmux9: interrupt-controller@d4282180 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <9>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x180 0x4>, <0x17c 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <3>;
+ };
+
+ intcmux17: interrupt-controller@d4282158 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <17>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x158 0x4>, <0x170 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <5>;
+ };
+
+ intcmux35: interrupt-controller@d428215c {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <35>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x15c 0x4>, <0x174 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <15>;
+ };
+
+ intcmux51: interrupt-controller@d4282160 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <51>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x160 0x4>, <0x178 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
+
+ intcmux55: interrupt-controller@d4282188 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <55>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x188 0x4>, <0x184 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
+ };
+
+ apb@d4000000 { /* APB */
+ compatible = "mrvl,apb-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4000000 0x00200000>;
+ ranges;
+
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
+
+ uart1: uart@d4030000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4030000 0x1000>;
+ interrupts = <27>;
+ status = "disabled";
+ };
+
+ uart2: uart@d4017000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4017000 0x1000>;
+ interrupts = <28>;
+ status = "disabled";
+ };
+
+ uart3: uart@d4018000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4018000 0x1000>;
+ interrupts = <24>;
+ status = "disabled";
+ };
+
+ uart4: uart@d4016000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4016000 0x1000>;
+ interrupts = <46>;
+ status = "disabled";
+ };
+
+ gpio@d4019000 {
+ compatible = "mrvl,mmp-gpio";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4019000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <49>;
+ interrupt-names = "gpio_mux";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ ranges;
+
+ gcb0: gpio@d4019000 {
+ reg = <0xd4019000 0x4>;
+ };
+
+ gcb1: gpio@d4019004 {
+ reg = <0xd4019004 0x4>;
+ };
+
+ gcb2: gpio@d4019008 {
+ reg = <0xd4019008 0x4>;
+ };
+
+ gcb3: gpio@d4019100 {
+ reg = <0xd4019100 0x4>;
+ };
+
+ gcb4: gpio@d4019104 {
+ reg = <0xd4019104 0x4>;
+ };
+
+ gcb5: gpio@d4019108 {
+ reg = <0xd4019108 0x4>;
+ };
+ };
+
+ twsi1: i2c@d4011000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4011000 0x1000>;
+ interrupts = <7>;
+ mrvl,i2c-fast-mode;
+ status = "disabled";
+ };
+
+ twsi2: i2c@d4025000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4025000 0x1000>;
+ interrupts = <58>;
+ status = "disabled";
+ };
+
+ rtc: rtc@d4010000 {
+ compatible = "mrvl,mmp-rtc";
+ reg = <0xd4010000 0x1000>;
+ interrupts = <1 0>;
+ interrupt-names = "rtc 1Hz", "rtc alarm";
+ interrupt-parent = <&intcmux5>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
index d32d5128f22..31a71869608 100644
--- a/arch/arm/boot/dts/pxa168.dtsi
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -18,13 +18,6 @@
i2c1 = &twsi2;
};
- intc: intc-interrupt-controller@d4282000 {
- compatible = "mrvl,mmp-intc", "mrvl,intc";
- interrupt-controller;
- #interrupt-cells = <1>;
- reg = <0xd4282000 0x1000>;
- };
-
soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -32,6 +25,23 @@
interrupt-parent = <&intc>;
ranges;
+ axi@d4200000 { /* AXI */
+ compatible = "mrvl,axi-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4200000 0x00200000>;
+ ranges;
+
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ };
+
apb@d4000000 { /* APB */
compatible = "mrvl,apb-bus", "simple-bus";
#address-cells = <1>;
@@ -39,40 +49,65 @@
reg = <0xd4000000 0x00200000>;
ranges;
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
+
uart1: uart@d4017000 {
- compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+ compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>;
interrupts = <27>;
status = "disabled";
};
uart2: uart@d4018000 {
- compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+ compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>;
interrupts = <28>;
status = "disabled";
};
uart3: uart@d4026000 {
- compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+ compatible = "mrvl,mmp-uart";
reg = <0xd4026000 0x1000>;
interrupts = <29>;
status = "disabled";
};
- gpio: gpio@d4019000 {
- compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+ gpio@d4019000 {
+ compatible = "mrvl,mmp-gpio";
+ #address-cells = <1>;
+ #size-cells = <1>;
reg = <0xd4019000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
interrupts = <49>;
interrupt-names = "gpio_mux";
- gpio-controller;
- #gpio-cells = <1>;
interrupt-controller;
#interrupt-cells = <1>;
+ ranges;
+
+ gcb0: gpio@d4019000 {
+ reg = <0xd4019000 0x4>;
+ };
+
+ gcb1: gpio@d4019004 {
+ reg = <0xd4019004 0x4>;
+ };
+
+ gcb2: gpio@d4019008 {
+ reg = <0xd4019008 0x4>;
+ };
+
+ gcb3: gpio@d4019100 {
+ reg = <0xd4019100 0x4>;
+ };
};
twsi1: i2c@d4011000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
mrvl,i2c-fast-mode;
@@ -80,7 +115,7 @@
};
twsi2: i2c@d4025000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>;
interrupts = <58>;
status = "disabled";
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
new file mode 100644
index 00000000000..e92be5a474e
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "pxa910.dtsi"
+
+/ {
+ model = "Marvell PXA910 DKB Development Board";
+ compatible = "mrvl,pxa910-dkb", "mrvl,pxa910";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+ };
+
+ memory {
+ reg = <0x00000000 0x10000000>;
+ };
+
+ soc {
+ apb@d4000000 {
+ uart1: uart@d4017000 {
+ status = "okay";
+ };
+ twsi1: i2c@d4011000 {
+ status = "okay";
+ };
+ rtc: rtc@d4010000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
new file mode 100644
index 00000000000..aebf32de73b
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart1;
+ serial1 = &uart2;
+ serial2 = &uart3;
+ i2c0 = &twsi1;
+ i2c1 = &twsi2;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ axi@d4200000 { /* AXI */
+ compatible = "mrvl,axi-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4200000 0x00200000>;
+ ranges;
+
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ };
+
+ apb@d4000000 { /* APB */
+ compatible = "mrvl,apb-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4000000 0x00200000>;
+ ranges;
+
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
+
+ timer1: timer@d4016000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4016000 0x100>;
+ interrupts = <29>;
+ status = "disabled";
+ };
+
+ uart1: uart@d4017000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4017000 0x1000>;
+ interrupts = <27>;
+ status = "disabled";
+ };
+
+ uart2: uart@d4018000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4018000 0x1000>;
+ interrupts = <28>;
+ status = "disabled";
+ };
+
+ uart3: uart@d4036000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4036000 0x1000>;
+ interrupts = <59>;
+ status = "disabled";
+ };
+
+ gpio@d4019000 {
+ compatible = "mrvl,mmp-gpio";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4019000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <49>;
+ interrupt-names = "gpio_mux";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ ranges;
+
+ gcb0: gpio@d4019000 {
+ reg = <0xd4019000 0x4>;
+ };
+
+ gcb1: gpio@d4019004 {
+ reg = <0xd4019004 0x4>;
+ };
+
+ gcb2: gpio@d4019008 {
+ reg = <0xd4019008 0x4>;
+ };
+
+ gcb3: gpio@d4019100 {
+ reg = <0xd4019100 0x4>;
+ };
+ };
+
+ twsi1: i2c@d4011000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4011000 0x1000>;
+ interrupts = <7>;
+ mrvl,i2c-fast-mode;
+ status = "disabled";
+ };
+
+ twsi2: i2c@d4037000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4037000 0x1000>;
+ interrupts = <54>;
+ status = "disabled";
+ };
+
+ rtc: rtc@d4010000 {
+ compatible = "mrvl,mmp-rtc";
+ reg = <0xd4010000 0x1000>;
+ interrupts = <5 6>;
+ interrupt-names = "rtc 1Hz", "rtc alarm";
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 5a90b9a3ab6..ede72162815 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -2,16 +2,6 @@ if ARCH_MMP
menu "Marvell PXA168/910/MMP2 Implmentations"
-config MACH_MMP_DT
- bool "Support MMP2 platforms from device tree"
- select CPU_PXA168
- select CPU_PXA910
- select USE_OF
- help
- Include support for Marvell MMP2 based platforms using
- the device tree. Needn't select any other machine while
- MACH_MMP_DT is enabled.
-
config MACH_ASPENITE
bool "Marvell's PXA168 Aspenite Development Board"
select CPU_PXA168
@@ -94,6 +84,25 @@ config MACH_GPLUGD
Say 'Y' here if you want to support the Marvell PXA168-based
GuruPlug Display (gplugD) Board
+config MACH_MMP_DT
+ bool "Support MMP (ARMv5) platforms from device tree"
+ select CPU_PXA168
+ select CPU_PXA910
+ select USE_OF
+ help
+ Include support for Marvell MMP2 based platforms using
+ the device tree. Needn't select any other machine while
+ MACH_MMP_DT is enabled.
+
+config MACH_MMP2_DT
+ bool "Support MMP2 (ARMv7) platforms from device tree"
+ depends on !CPU_MOHAWK
+ select CPU_MMP2
+ select USE_OF
+ help
+ Include support for Marvell MMP2 based platforms using
+ the device tree.
+
endmenu
config CPU_PXA168
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 4fc0ff5dc96..b920b9bfbdb 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -2,12 +2,12 @@
# Makefile for Marvell's PXA168 processors line
#
-obj-y += common.o clock.o devices.o time.o
+obj-y += common.o clock.o devices.o time.o irq.o
# SoC support
-obj-$(CONFIG_CPU_PXA168) += pxa168.o irq-pxa168.o
-obj-$(CONFIG_CPU_PXA910) += pxa910.o irq-pxa168.o
-obj-$(CONFIG_CPU_MMP2) += mmp2.o irq-mmp2.o sram.o
+obj-$(CONFIG_CPU_PXA168) += pxa168.o
+obj-$(CONFIG_CPU_PXA910) += pxa910.o
+obj-$(CONFIG_CPU_MMP2) += mmp2.o sram.o
# board support
obj-$(CONFIG_MACH_ASPENITE) += aspenite.o
@@ -19,5 +19,6 @@ obj-$(CONFIG_MACH_BROWNSTONE) += brownstone.o
obj-$(CONFIG_MACH_FLINT) += flint.o
obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
obj-$(CONFIG_MACH_MMP_DT) += mmp-dt.o
+obj-$(CONFIG_MACH_MMP2_DT) += mmp2-dt.o
obj-$(CONFIG_MACH_TETON_BGA) += teton_bga.o
obj-$(CONFIG_MACH_GPLUGD) += gplugd.o
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S
index 9cff9e7a2b2..bd152e24e6d 100644
--- a/arch/arm/mach-mmp/include/mach/entry-macro.S
+++ b/arch/arm/mach-mmp/include/mach/entry-macro.S
@@ -6,13 +6,15 @@
* published by the Free Software Foundation.
*/
+#include <asm/irq.h>
#include <mach/regs-icu.h>
.macro get_irqnr_preamble, base, tmp
mrc p15, 0, \tmp, c0, c0, 0 @ CPUID
and \tmp, \tmp, #0xff00
cmp \tmp, #0x5800
- ldr \base, =ICU_VIRT_BASE
+ ldr \base, =mmp_icu_base
+ ldr \base, [\base, #0]
addne \base, \base, #0x10c @ PJ1 AP INT SEL register
addeq \base, \base, #0x104 @ PJ4 IRQ SEL register
.endm
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h
index d0e746626a3..fb492a50a81 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -125,7 +125,7 @@
#define IRQ_MMP2_RTC_MUX 5
#define IRQ_MMP2_TWSI1 7
#define IRQ_MMP2_GPU 8
-#define IRQ_MMP2_KEYPAD 9
+#define IRQ_MMP2_KEYPAD_MUX 9
#define IRQ_MMP2_ROTARY 10
#define IRQ_MMP2_TRACKBALL 11
#define IRQ_MMP2_ONEWIRE 12
@@ -163,11 +163,11 @@
#define IRQ_MMP2_DMA_FIQ 47
#define IRQ_MMP2_DMA_RIQ 48
#define IRQ_MMP2_GPIO 49
-#define IRQ_MMP2_SSP_MUX 51
+#define IRQ_MMP2_MIPI_HSI1_MUX 51
#define IRQ_MMP2_MMC2 52
#define IRQ_MMP2_MMC3 53
#define IRQ_MMP2_MMC4 54
-#define IRQ_MMP2_MIPI_HSI 55
+#define IRQ_MMP2_MIPI_HSI0_MUX 55
#define IRQ_MMP2_MSP 58
#define IRQ_MMP2_MIPI_SLIM_DMA 59
#define IRQ_MMP2_PJ4_FREQ_CHG 60
@@ -186,8 +186,14 @@
#define IRQ_MMP2_RTC_ALARM (IRQ_MMP2_RTC_BASE + 0)
#define IRQ_MMP2_RTC (IRQ_MMP2_RTC_BASE + 1)
+/* secondary interrupt of INT #9 */
+#define IRQ_MMP2_KEYPAD_BASE (IRQ_MMP2_RTC_BASE + 2)
+#define IRQ_MMP2_KPC (IRQ_MMP2_KEYPAD_BASE + 0)
+#define IRQ_MMP2_ROTORY (IRQ_MMP2_KEYPAD_BASE + 1)
+#define IRQ_MMP2_TBALL (IRQ_MMP2_KEYPAD_BASE + 2)
+
/* secondary interrupt of INT #17 */
-#define IRQ_MMP2_TWSI_BASE (IRQ_MMP2_RTC_BASE + 2)
+#define IRQ_MMP2_TWSI_BASE (IRQ_MMP2_KEYPAD_BASE + 3)
#define IRQ_MMP2_TWSI2 (IRQ_MMP2_TWSI_BASE + 0)
#define IRQ_MMP2_TWSI3 (IRQ_MMP2_TWSI_BASE + 1)
#define IRQ_MMP2_TWSI4 (IRQ_MMP2_TWSI_BASE + 2)
@@ -212,11 +218,16 @@
#define IRQ_MMP2_COMMRX (IRQ_MMP2_MISC_BASE + 14)
/* secondary interrupt of INT #51 */
-#define IRQ_MMP2_SSP_BASE (IRQ_MMP2_MISC_BASE + 15)
-#define IRQ_MMP2_SSP1_SRDY (IRQ_MMP2_SSP_BASE + 0)
-#define IRQ_MMP2_SSP3_SRDY (IRQ_MMP2_SSP_BASE + 1)
+#define IRQ_MMP2_MIPI_HSI1_BASE (IRQ_MMP2_MISC_BASE + 15)
+#define IRQ_MMP2_HSI1_CAWAKE (IRQ_MMP2_MIPI_HSI1_BASE + 0)
+#define IRQ_MMP2_MIPI_HSI_INT1 (IRQ_MMP2_MIPI_HSI1_BASE + 1)
+
+/* secondary interrupt of INT #55 */
+#define IRQ_MMP2_MIPI_HSI0_BASE (IRQ_MMP2_MIPI_HSI1_BASE + 2)
+#define IRQ_MMP2_HSI0_CAWAKE (IRQ_MMP2_MIPI_HSI0_BASE + 0)
+#define IRQ_MMP2_MIPI_HSI_INT0 (IRQ_MMP2_MIPI_HSI0_BASE + 1)
-#define IRQ_MMP2_MUX_END (IRQ_MMP2_SSP_BASE + 2)
+#define IRQ_MMP2_MUX_END (IRQ_MMP2_MIPI_HSI0_BASE + 2)
#define IRQ_GPIO_START 128
#define MMP_NR_BUILTIN_GPIO 192
diff --git a/arch/arm/mach-mmp/irq-mmp2.c b/arch/arm/mach-mmp/irq-mmp2.c
deleted file mode 100644
index 7895d277421..00000000000
--- a/arch/arm/mach-mmp/irq-mmp2.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/irq-mmp2.c
- *
- * Generic IRQ handling, GPIO IRQ demultiplexing, etc.
- *
- * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- * Copyright: Marvell International Ltd.
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/irqs.h>
-#include <mach/regs-icu.h>
-#include <mach/mmp2.h>
-
-#include "common.h"
-
-static void icu_mask_irq(struct irq_data *d)
-{
- uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
-
- r &= ~ICU_INT_ROUTE_PJ4_IRQ;
- __raw_writel(r, ICU_INT_CONF(d->irq));
-}
-
-static void icu_unmask_irq(struct irq_data *d)
-{
- uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
-
- r |= ICU_INT_ROUTE_PJ4_IRQ;
- __raw_writel(r, ICU_INT_CONF(d->irq));
-}
-
-static struct irq_chip icu_irq_chip = {
- .name = "icu_irq",
- .irq_mask = icu_mask_irq,
- .irq_mask_ack = icu_mask_irq,
- .irq_unmask = icu_unmask_irq,
-};
-
-static void pmic_irq_ack(struct irq_data *d)
-{
- if (d->irq == IRQ_MMP2_PMIC)
- mmp2_clear_pmic_int();
-}
-
-#define SECOND_IRQ_MASK(_name_, irq_base, prefix) \
-static void _name_##_mask_irq(struct irq_data *d) \
-{ \
- uint32_t r; \
- r = __raw_readl(prefix##_MASK) | (1 << (d->irq - irq_base)); \
- __raw_writel(r, prefix##_MASK); \
-}
-
-#define SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \
-static void _name_##_unmask_irq(struct irq_data *d) \
-{ \
- uint32_t r; \
- r = __raw_readl(prefix##_MASK) & ~(1 << (d->irq - irq_base)); \
- __raw_writel(r, prefix##_MASK); \
-}
-
-#define SECOND_IRQ_DEMUX(_name_, irq_base, prefix) \
-static void _name_##_irq_demux(unsigned int irq, struct irq_desc *desc) \
-{ \
- unsigned long status, mask, n; \
- mask = __raw_readl(prefix##_MASK); \
- while (1) { \
- status = __raw_readl(prefix##_STATUS) & ~mask; \
- if (status == 0) \
- break; \
- n = find_first_bit(&status, BITS_PER_LONG); \
- while (n < BITS_PER_LONG) { \
- generic_handle_irq(irq_base + n); \
- n = find_next_bit(&status, BITS_PER_LONG, n+1); \
- } \
- } \
-}
-
-#define SECOND_IRQ_CHIP(_name_, irq_base, prefix) \
-SECOND_IRQ_MASK(_name_, irq_base, prefix) \
-SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \
-SECOND_IRQ_DEMUX(_name_, irq_base, prefix) \
-static struct irq_chip _name_##_irq_chip = { \
- .name = #_name_, \
- .irq_mask = _name_##_mask_irq, \
- .irq_unmask = _name_##_unmask_irq, \
-}
-
-SECOND_IRQ_CHIP(pmic, IRQ_MMP2_PMIC_BASE, MMP2_ICU_INT4);
-SECOND_IRQ_CHIP(rtc, IRQ_MMP2_RTC_BASE, MMP2_ICU_INT5);
-SECOND_IRQ_CHIP(twsi, IRQ_MMP2_TWSI_BASE, MMP2_ICU_INT17);
-SECOND_IRQ_CHIP(misc, IRQ_MMP2_MISC_BASE, MMP2_ICU_INT35);
-SECOND_IRQ_CHIP(ssp, IRQ_MMP2_SSP_BASE, MMP2_ICU_INT51);
-
-static void init_mux_irq(struct irq_chip *chip, int start, int num)
-{
- int irq;
-
- for (irq = start; num > 0; irq++, num--) {
- struct irq_data *d = irq_get_irq_data(irq);
-
- /* mask and clear the IRQ */
- chip->irq_mask(d);
- if (chip->irq_ack)
- chip->irq_ack(d);
-
- irq_set_chip(irq, chip);
- set_irq_flags(irq, IRQF_VALID);
- irq_set_handler(irq, handle_level_irq);
- }
-}
-
-void __init mmp2_init_icu(void)
-{
- int irq;
-
- for (irq = 0; irq < IRQ_MMP2_MUX_BASE; irq++) {
- icu_mask_irq(irq_get_irq_data(irq));
- irq_set_chip(irq, &icu_irq_chip);
- set_irq_flags(irq, IRQF_VALID);
-
- switch (irq) {
- case IRQ_MMP2_PMIC_MUX:
- case IRQ_MMP2_RTC_MUX:
- case IRQ_MMP2_TWSI_MUX:
- case IRQ_MMP2_MISC_MUX:
- case IRQ_MMP2_SSP_MUX:
- break;
- default:
- irq_set_handler(irq, handle_level_irq);
- break;
- }
- }
-
- /* NOTE: IRQ_MMP2_PMIC requires the PMIC MFPR register
- * to be written to clear the interrupt
- */
- pmic_irq_chip.irq_ack = pmic_irq_ack;
-
- init_mux_irq(&pmic_irq_chip, IRQ_MMP2_PMIC_BASE, 2);
- init_mux_irq(&rtc_irq_chip, IRQ_MMP2_RTC_BASE, 2);
- init_mux_irq(&twsi_irq_chip, IRQ_MMP2_TWSI_BASE, 5);
- init_mux_irq(&misc_irq_chip, IRQ_MMP2_MISC_BASE, 15);
- init_mux_irq(&ssp_irq_chip, IRQ_MMP2_SSP_BASE, 2);
-
- irq_set_chained_handler(IRQ_MMP2_PMIC_MUX, pmic_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_RTC_MUX, rtc_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_TWSI_MUX, twsi_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_MISC_MUX, misc_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_SSP_MUX, ssp_irq_demux);
-}
diff --git a/arch/arm/mach-mmp/irq-pxa168.c b/arch/arm/mach-mmp/irq-pxa168.c
deleted file mode 100644
index 89706a0d08f..00000000000
--- a/arch/arm/mach-mmp/irq-pxa168.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/irq.c
- *
- * Generic IRQ handling, GPIO IRQ demultiplexing, etc.
- *
- * Author: Bin Yang <bin.yang@marvell.com>
- * Created: Sep 30, 2008
- * Copyright: Marvell International Ltd.
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/regs-icu.h>
-
-#include "common.h"
-
-#define IRQ_ROUTE_TO_AP (ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ)
-
-#define PRIORITY_DEFAULT 0x1
-#define PRIORITY_NONE 0x0 /* means IRQ disabled */
-
-static void icu_mask_irq(struct irq_data *d)
-{
- __raw_writel(PRIORITY_NONE, ICU_INT_CONF(d->irq));
-}
-
-static void icu_unmask_irq(struct irq_data *d)
-{
- __raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(d->irq));
-}
-
-static struct irq_chip icu_irq_chip = {
- .name = "icu_irq",
- .irq_ack = icu_mask_irq,
- .irq_mask = icu_mask_irq,
- .irq_unmask = icu_unmask_irq,
-};
-
-void __init icu_init_irq(void)
-{
- int irq;
-
- for (irq = 0; irq < 64; irq++) {
- icu_mask_irq(irq_get_irq_data(irq));
- irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-}
diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c
new file mode 100644
index 00000000000..3705470c9f1
--- /dev/null
+++ b/arch/arm/mach-mmp/irq.c
@@ -0,0 +1,445 @@
+/*
+ * linux/arch/arm/mach-mmp/irq.c
+ *
+ * Generic IRQ handling, GPIO IRQ demultiplexing, etc.
+ * Copyright (C) 2008 - 2012 Marvell Technology Group Ltd.
+ *
+ * Author: Bin Yang <bin.yang@marvell.com>
+ * Haojian Zhuang <haojian.zhuang@gmail.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <mach/irqs.h>
+
+#include "common.h"
+
+#define MAX_ICU_NR 16
+
+struct icu_chip_data {
+ int nr_irqs;
+ unsigned int virq_base;
+ unsigned int cascade_irq;
+ void __iomem *reg_status;
+ void __iomem *reg_mask;
+ unsigned int conf_enable;
+ unsigned int conf_disable;
+ unsigned int conf_mask;
+ unsigned int clr_mfp_irq_base;
+ unsigned int clr_mfp_hwirq;
+ struct irq_domain *domain;
+};
+
+struct mmp_intc_conf {
+ unsigned int conf_enable;
+ unsigned int conf_disable;
+ unsigned int conf_mask;
+};
+
+void __iomem *mmp_icu_base;
+static struct icu_chip_data icu_data[MAX_ICU_NR];
+static int max_icu_nr;
+
+extern void mmp2_clear_pmic_int(void);
+
+static void icu_mask_ack_irq(struct irq_data *d)
+{
+ struct irq_domain *domain = d->domain;
+ struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+ int hwirq;
+ u32 r;
+
+ hwirq = d->irq - data->virq_base;
+ if (data == &icu_data[0]) {
+ r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+ r &= ~data->conf_mask;
+ r |= data->conf_disable;
+ writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+ } else {
+#ifdef CONFIG_CPU_MMP2
+ if ((data->virq_base == data->clr_mfp_irq_base)
+ && (hwirq == data->clr_mfp_hwirq))
+ mmp2_clear_pmic_int();
+#endif
+ r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+ writel_relaxed(r, data->reg_mask);
+ }
+}
+
+static void icu_mask_irq(struct irq_data *d)
+{
+ struct irq_domain *domain = d->domain;
+ struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+ int hwirq;
+ u32 r;
+
+ hwirq = d->irq - data->virq_base;
+ if (data == &icu_data[0]) {
+ r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+ r &= ~data->conf_mask;
+ r |= data->conf_disable;
+ writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+ } else {
+ r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+ writel_relaxed(r, data->reg_mask);
+ }
+}
+
+static void icu_unmask_irq(struct irq_data *d)
+{
+ struct irq_domain *domain = d->domain;
+ struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+ int hwirq;
+ u32 r;
+
+ hwirq = d->irq - data->virq_base;
+ if (data == &icu_data[0]) {
+ r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+ r &= ~data->conf_mask;
+ r |= data->conf_enable;
+ writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+ } else {
+ r = readl_relaxed(data->reg_mask) & ~(1 << hwirq);
+ writel_relaxed(r, data->reg_mask);
+ }
+}
+
+static struct irq_chip icu_irq_chip = {
+ .name = "icu_irq",
+ .irq_mask = icu_mask_irq,
+ .irq_mask_ack = icu_mask_ack_irq,
+ .irq_unmask = icu_unmask_irq,
+};
+
+static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain;
+ struct icu_chip_data *data;
+ int i;
+ unsigned long mask, status, n;
+
+ for (i = 1; i < max_icu_nr; i++) {
+ if (irq == icu_data[i].cascade_irq) {
+ domain = icu_data[i].domain;
+ data = (struct icu_chip_data *)domain->host_data;
+ break;
+ }
+ }
+ if (i >= max_icu_nr) {
+ pr_err("Spurious irq %d in MMP INTC\n", irq);
+ return;
+ }
+
+ mask = readl_relaxed(data->reg_mask);
+ while (1) {
+ status = readl_relaxed(data->reg_status) & ~mask;
+ if (status == 0)
+ break;
+ n = find_first_bit(&status, BITS_PER_LONG);
+ while (n < BITS_PER_LONG) {
+ generic_handle_irq(icu_data[i].virq_base + n);
+ n = find_next_bit(&status, BITS_PER_LONG, n + 1);
+ }
+ }
+}
+
+static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ return 0;
+}
+
+static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ *out_hwirq = intspec[0];
+ return 0;
+}
+
+const struct irq_domain_ops mmp_irq_domain_ops = {
+ .map = mmp_irq_domain_map,
+ .xlate = mmp_irq_domain_xlate,
+};
+
+static struct mmp_intc_conf mmp_conf = {
+ .conf_enable = 0x51,
+ .conf_disable = 0x0,
+ .conf_mask = 0x7f,
+};
+
+static struct mmp_intc_conf mmp2_conf = {
+ .conf_enable = 0x20,
+ .conf_disable = 0x0,
+ .conf_mask = 0x7f,
+};
+
+/* MMP (ARMv5) */
+void __init icu_init_irq(void)
+{
+ int irq;
+
+ max_icu_nr = 1;
+ mmp_icu_base = ioremap(0xd4282000, 0x1000);
+ icu_data[0].conf_enable = mmp_conf.conf_enable;
+ icu_data[0].conf_disable = mmp_conf.conf_disable;
+ icu_data[0].conf_mask = mmp_conf.conf_mask;
+ icu_data[0].nr_irqs = 64;
+ icu_data[0].virq_base = 0;
+ icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+ &irq_domain_simple_ops,
+ &icu_data[0]);
+ for (irq = 0; irq < 64; irq++) {
+ icu_mask_irq(irq_get_irq_data(irq));
+ irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ irq_set_default_host(icu_data[0].domain);
+}
+
+/* MMP2 (ARMv7) */
+void __init mmp2_init_icu(void)
+{
+ int irq;
+
+ max_icu_nr = 8;
+ mmp_icu_base = ioremap(0xd4282000, 0x1000);
+ icu_data[0].conf_enable = mmp2_conf.conf_enable;
+ icu_data[0].conf_disable = mmp2_conf.conf_disable;
+ icu_data[0].conf_mask = mmp2_conf.conf_mask;
+ icu_data[0].nr_irqs = 64;
+ icu_data[0].virq_base = 0;
+ icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+ &irq_domain_simple_ops,
+ &icu_data[0]);
+ icu_data[1].reg_status = mmp_icu_base + 0x150;
+ icu_data[1].reg_mask = mmp_icu_base + 0x168;
+ icu_data[1].clr_mfp_irq_base = IRQ_MMP2_PMIC_BASE;
+ icu_data[1].clr_mfp_hwirq = IRQ_MMP2_PMIC - IRQ_MMP2_PMIC_BASE;
+ icu_data[1].nr_irqs = 2;
+ icu_data[1].virq_base = IRQ_MMP2_PMIC_BASE;
+ icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs,
+ icu_data[1].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[1]);
+ icu_data[2].reg_status = mmp_icu_base + 0x154;
+ icu_data[2].reg_mask = mmp_icu_base + 0x16c;
+ icu_data[2].nr_irqs = 2;
+ icu_data[2].virq_base = IRQ_MMP2_RTC_BASE;
+ icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs,
+ icu_data[2].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[2]);
+ icu_data[3].reg_status = mmp_icu_base + 0x180;
+ icu_data[3].reg_mask = mmp_icu_base + 0x17c;
+ icu_data[3].nr_irqs = 3;
+ icu_data[3].virq_base = IRQ_MMP2_KEYPAD_BASE;
+ icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs,
+ icu_data[3].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[3]);
+ icu_data[4].reg_status = mmp_icu_base + 0x158;
+ icu_data[4].reg_mask = mmp_icu_base + 0x170;
+ icu_data[4].nr_irqs = 5;
+ icu_data[4].virq_base = IRQ_MMP2_TWSI_BASE;
+ icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs,
+ icu_data[4].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[4]);
+ icu_data[5].reg_status = mmp_icu_base + 0x15c;
+ icu_data[5].reg_mask = mmp_icu_base + 0x174;
+ icu_data[5].nr_irqs = 15;
+ icu_data[5].virq_base = IRQ_MMP2_MISC_BASE;
+ icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs,
+ icu_data[5].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[5]);
+ icu_data[6].reg_status = mmp_icu_base + 0x160;
+ icu_data[6].reg_mask = mmp_icu_base + 0x178;
+ icu_data[6].nr_irqs = 2;
+ icu_data[6].virq_base = IRQ_MMP2_MIPI_HSI1_BASE;
+ icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs,
+ icu_data[6].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[6]);
+ icu_data[7].reg_status = mmp_icu_base + 0x188;
+ icu_data[7].reg_mask = mmp_icu_base + 0x184;
+ icu_data[7].nr_irqs = 2;
+ icu_data[7].virq_base = IRQ_MMP2_MIPI_HSI0_BASE;
+ icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs,
+ icu_data[7].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[7]);
+ for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) {
+ icu_mask_irq(irq_get_irq_data(irq));
+ switch (irq) {
+ case IRQ_MMP2_PMIC_MUX:
+ case IRQ_MMP2_RTC_MUX:
+ case IRQ_MMP2_KEYPAD_MUX:
+ case IRQ_MMP2_TWSI_MUX:
+ case IRQ_MMP2_MISC_MUX:
+ case IRQ_MMP2_MIPI_HSI1_MUX:
+ case IRQ_MMP2_MIPI_HSI0_MUX:
+ irq_set_chip(irq, &icu_irq_chip);
+ irq_set_chained_handler(irq, icu_mux_irq_demux);
+ break;
+ default:
+ irq_set_chip_and_handler(irq, &icu_irq_chip,
+ handle_level_irq);
+ break;
+ }
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ irq_set_default_host(icu_data[0].domain);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id intc_ids[] __initconst = {
+ { .compatible = "mrvl,mmp-intc", .data = &mmp_conf },
+ { .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf },
+ {}
+};
+
+static const struct of_device_id mmp_mux_irq_match[] __initconst = {
+ { .compatible = "mrvl,mmp2-mux-intc" },
+ {}
+};
+
+int __init mmp2_mux_init(struct device_node *parent)
+{
+ struct device_node *node;
+ const struct of_device_id *of_id;
+ struct resource res;
+ int i, irq_base, ret, irq;
+ u32 nr_irqs, mfp_irq;
+
+ node = parent;
+ max_icu_nr = 1;
+ for (i = 1; i < MAX_ICU_NR; i++) {
+ node = of_find_matching_node(node, mmp_mux_irq_match);
+ if (!node)
+ break;
+ of_id = of_match_node(&mmp_mux_irq_match[0], node);
+ ret = of_property_read_u32(node, "mrvl,intc-nr-irqs",
+ &nr_irqs);
+ if (ret) {
+ pr_err("Not found mrvl,intc-nr-irqs property\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret < 0) {
+ pr_err("Not found reg property\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ icu_data[i].reg_status = mmp_icu_base + res.start;
+ ret = of_address_to_resource(node, 1, &res);
+ if (ret < 0) {
+ pr_err("Not found reg property\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ icu_data[i].reg_mask = mmp_icu_base + res.start;
+ icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
+ if (!icu_data[i].cascade_irq) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+ if (irq_base < 0) {
+ pr_err("Failed to allocate IRQ numbers for mux intc\n");
+ ret = irq_base;
+ goto err;
+ }
+ if (!of_property_read_u32(node, "mrvl,clr-mfp-irq",
+ &mfp_irq)) {
+ icu_data[i].clr_mfp_irq_base = irq_base;
+ icu_data[i].clr_mfp_hwirq = mfp_irq;
+ }
+ irq_set_chained_handler(icu_data[i].cascade_irq,
+ icu_mux_irq_demux);
+ icu_data[i].nr_irqs = nr_irqs;
+ icu_data[i].virq_base = irq_base;
+ icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs,
+ irq_base, 0,
+ &mmp_irq_domain_ops,
+ &icu_data[i]);
+ for (irq = irq_base; irq < irq_base + nr_irqs; irq++)
+ icu_mask_irq(irq_get_irq_data(irq));
+ }
+ max_icu_nr = i;
+ return 0;
+err:
+ of_node_put(node);
+ max_icu_nr = i;
+ return ret;
+}
+
+void __init mmp_dt_irq_init(void)
+{
+ struct device_node *node;
+ const struct of_device_id *of_id;
+ struct mmp_intc_conf *conf;
+ int nr_irqs, irq_base, ret, irq;
+
+ node = of_find_matching_node(NULL, intc_ids);
+ if (!node) {
+ pr_err("Failed to find interrupt controller in arch-mmp\n");
+ return;
+ }
+ of_id = of_match_node(intc_ids, node);
+ conf = of_id->data;
+
+ ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
+ if (ret) {
+ pr_err("Not found mrvl,intc-nr-irqs property\n");
+ return;
+ }
+
+ mmp_icu_base = of_iomap(node, 0);
+ if (!mmp_icu_base) {
+ pr_err("Failed to get interrupt controller register\n");
+ return;
+ }
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0);
+ if (irq_base < 0) {
+ pr_err("Failed to allocate IRQ numbers\n");
+ goto err;
+ } else if (irq_base != NR_IRQS_LEGACY) {
+ pr_err("ICU's irqbase should be started from 0\n");
+ goto err;
+ }
+ icu_data[0].conf_enable = conf->conf_enable;
+ icu_data[0].conf_disable = conf->conf_disable;
+ icu_data[0].conf_mask = conf->conf_mask;
+ icu_data[0].nr_irqs = nr_irqs;
+ icu_data[0].virq_base = 0;
+ icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0,
+ &mmp_irq_domain_ops,
+ &icu_data[0]);
+ irq_set_default_host(icu_data[0].domain);
+ for (irq = 0; irq < nr_irqs; irq++)
+ icu_mask_irq(irq_get_irq_data(irq));
+ mmp2_mux_init(node);
+ return;
+err:
+ iounmap(mmp_icu_base);
+}
+#endif
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index 67075395e40..033cc31b3c7 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -14,14 +14,19 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
#include <mach/irqs.h>
#include "common.h"
-extern struct sys_timer pxa168_timer;
-extern void __init icu_init_irq(void);
+extern void __init mmp_dt_irq_init(void);
+extern void __init mmp_dt_init_timer(void);
-static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = {
+static struct sys_timer mmp_dt_timer = {
+ .init = mmp_dt_init_timer,
+};
+
+static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
@@ -32,44 +37,47 @@ static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = {
{}
};
-static int __init mmp_intc_add_irq_domain(struct device_node *np,
- struct device_node *parent)
-{
- irq_domain_add_simple(np, 0);
- return 0;
-}
-
-static int __init mmp_gpio_add_irq_domain(struct device_node *np,
- struct device_node *parent)
-{
- irq_domain_add_simple(np, IRQ_GPIO_START);
- return 0;
-}
-
-static const struct of_device_id mmp_irq_match[] __initconst = {
- { .compatible = "mrvl,mmp-intc", .data = mmp_intc_add_irq_domain, },
- { .compatible = "mrvl,mmp-gpio", .data = mmp_gpio_add_irq_domain, },
+static const struct of_dev_auxdata pxa910_auxdata_lookup[] __initconst = {
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4036000, "pxa2xx-uart.2", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4037000, "pxa2xx-i2c.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
{}
};
-static void __init mmp_dt_init(void)
+static void __init pxa168_dt_init(void)
{
+ of_platform_populate(NULL, of_default_bus_match_table,
+ pxa168_auxdata_lookup, NULL);
+}
- of_irq_init(mmp_irq_match);
-
+static void __init pxa910_dt_init(void)
+{
of_platform_populate(NULL, of_default_bus_match_table,
- mmp_auxdata_lookup, NULL);
+ pxa910_auxdata_lookup, NULL);
}
-static const char *pxa168_dt_board_compat[] __initdata = {
+static const char *mmp_dt_board_compat[] __initdata = {
"mrvl,pxa168-aspenite",
+ "mrvl,pxa910-dkb",
NULL,
};
DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
.map_io = mmp_map_io,
- .init_irq = icu_init_irq,
- .timer = &pxa168_timer,
- .init_machine = mmp_dt_init,
- .dt_compat = pxa168_dt_board_compat,
+ .init_irq = mmp_dt_irq_init,
+ .timer = &mmp_dt_timer,
+ .init_machine = pxa168_dt_init,
+ .dt_compat = mmp_dt_board_compat,
+MACHINE_END
+
+DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
+ .map_io = mmp_map_io,
+ .init_irq = mmp_dt_irq_init,
+ .timer = &mmp_dt_timer,
+ .init_machine = pxa910_dt_init,
+ .dt_compat = mmp_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
new file mode 100644
index 00000000000..535a5ed5977
--- /dev/null
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -0,0 +1,60 @@
+/*
+ * linux/arch/arm/mach-mmp/mmp2-dt.c
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/irqs.h>
+#include <mach/regs-apbc.h>
+
+#include "common.h"
+
+extern void __init mmp_dt_irq_init(void);
+extern void __init mmp_dt_init_timer(void);
+
+static struct sys_timer mmp_dt_timer = {
+ .init = mmp_dt_init_timer,
+};
+
+static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.2", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4016000, "pxa2xx-uart.3", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
+ {}
+};
+
+static void __init mmp2_dt_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table,
+ mmp2_auxdata_lookup, NULL);
+}
+
+static const char *mmp2_dt_board_compat[] __initdata = {
+ "mrvl,mmp2-brownstone",
+ NULL,
+};
+
+DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
+ .map_io = mmp_map_io,
+ .init_irq = mmp_dt_irq_init,
+ .timer = &mmp_dt_timer,
+ .init_machine = mmp2_dt_init,
+ .dt_compat = mmp2_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 71fc4ee4602..936447c7097 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -25,6 +25,9 @@
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <asm/sched_clock.h>
#include <mach/addr-map.h>
@@ -41,6 +44,8 @@
#define MAX_DELTA (0xfffffffe)
#define MIN_DELTA (16)
+static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
+
/*
* FIXME: the timer needs some delay to stablize the counter capture
*/
@@ -48,12 +53,12 @@ static inline uint32_t timer_read(void)
{
int delay = 100;
- __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(1));
+ __raw_writel(1, mmp_timer_base + TMR_CVWR(1));
while (delay--)
cpu_relax();
- return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1));
+ return __raw_readl(mmp_timer_base + TMR_CVWR(1));
}
static u32 notrace mmp_read_sched_clock(void)
@@ -68,12 +73,12 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
/*
* Clear pending interrupt status.
*/
- __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
+ __raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
/*
* Disable timer 0.
*/
- __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x02, mmp_timer_base + TMR_CER);
c->event_handler(c);
@@ -90,23 +95,23 @@ static int timer_set_next_event(unsigned long delta,
/*
* Disable timer 0.
*/
- __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x02, mmp_timer_base + TMR_CER);
/*
* Clear and enable timer match 0 interrupt.
*/
- __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
- __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0));
+ __raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
+ __raw_writel(0x01, mmp_timer_base + TMR_IER(0));
/*
* Setup new clockevent timer value.
*/
- __raw_writel(delta - 1, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
+ __raw_writel(delta - 1, mmp_timer_base + TMR_TN_MM(0, 0));
/*
* Enable timer 0.
*/
- __raw_writel(0x03, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x03, mmp_timer_base + TMR_CER);
local_irq_restore(flags);
@@ -124,7 +129,7 @@ static void timer_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* disable the matching interrupt */
- __raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0));
+ __raw_writel(0x00, mmp_timer_base + TMR_IER(0));
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
@@ -157,27 +162,27 @@ static struct clocksource cksrc = {
static void __init timer_config(void)
{
- uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR);
+ uint32_t ccr = __raw_readl(mmp_timer_base + TMR_CCR);
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_CER); /* disable */
+ __raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
(TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
- __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
+ __raw_writel(ccr, mmp_timer_base + TMR_CCR);
/* set timer 0 to periodic mode, and timer 1 to free-running mode */
- __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CMR);
+ __raw_writel(0x2, mmp_timer_base + TMR_CMR);
- __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* periodic */
- __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0)); /* clear status */
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
+ __raw_writel(0x1, mmp_timer_base + TMR_PLCR(0)); /* periodic */
+ __raw_writel(0x7, mmp_timer_base + TMR_ICR(0)); /* clear status */
+ __raw_writel(0x0, mmp_timer_base + TMR_IER(0));
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(1)); /* free-running */
- __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(1)); /* clear status */
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(1));
+ __raw_writel(0x0, mmp_timer_base + TMR_PLCR(1)); /* free-running */
+ __raw_writel(0x7, mmp_timer_base + TMR_ICR(1)); /* clear status */
+ __raw_writel(0x0, mmp_timer_base + TMR_IER(1));
/* enable timer 1 counter */
- __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x2, mmp_timer_base + TMR_CER);
}
static struct irqaction timer_irq = {
@@ -203,3 +208,37 @@ void __init timer_init(int irq)
clocksource_register_hz(&cksrc, CLOCK_TICK_RATE);
clockevents_register_device(&ckevt);
}
+
+#ifdef CONFIG_OF
+static struct of_device_id mmp_timer_dt_ids[] = {
+ { .compatible = "mrvl,mmp-timer", },
+ {}
+};
+
+void __init mmp_dt_init_timer(void)
+{
+ struct device_node *np;
+ int irq, ret;
+
+ np = of_find_matching_node(NULL, mmp_timer_dt_ids);
+ if (!np) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ ret = -EINVAL;
+ goto out;
+ }
+ mmp_timer_base = of_iomap(np, 0);
+ if (!mmp_timer_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ timer_init(irq);
+ return;
+out:
+ pr_err("Failed to get timer from device tree with error:%d\n", ret);
+}
+#endif
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index fc3ace3fd4c..58a6a63a6ec 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -11,13 +11,17 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio-pxa.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <linux/slab.h>
@@ -56,6 +60,10 @@
int pxa_last_gpio;
+#ifdef CONFIG_OF
+static struct irq_domain *domain;
+#endif
+
struct pxa_gpio_chip {
struct gpio_chip chip;
void __iomem *regbase;
@@ -81,7 +89,6 @@ enum {
PXA3XX_GPIO,
PXA93X_GPIO,
MMP_GPIO = 0x10,
- MMP2_GPIO,
};
static DEFINE_SPINLOCK(gpio_lock);
@@ -475,22 +482,92 @@ static int pxa_gpio_nums(void)
gpio_type = MMP_GPIO;
} else if (cpu_is_mmp2()) {
count = 191;
- gpio_type = MMP2_GPIO;
+ gpio_type = MMP_GPIO;
}
#endif /* CONFIG_ARCH_MMP */
return count;
}
+static struct of_device_id pxa_gpio_dt_ids[] = {
+ { .compatible = "mrvl,pxa-gpio" },
+ { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
+ {}
+};
+
+static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ return 0;
+}
+
+const struct irq_domain_ops pxa_irq_domain_ops = {
+ .map = pxa_irq_domain_map,
+};
+
+#ifdef CONFIG_OF
+static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
+{
+ int ret, nr_banks, nr_gpios, irq_base;
+ struct device_node *prev, *next, *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(pxa_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to find gpio controller\n");
+ return -EFAULT;
+ }
+ gpio_type = (int)of_id->data;
+
+ next = of_get_next_child(np, NULL);
+ prev = next;
+ if (!next) {
+ dev_err(&pdev->dev, "Failed to find child gpio node\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ for (nr_banks = 1; ; nr_banks++) {
+ next = of_get_next_child(np, prev);
+ if (!next)
+ break;
+ prev = next;
+ }
+ of_node_put(prev);
+ nr_gpios = nr_banks << 5;
+ pxa_last_gpio = nr_gpios - 1;
+
+ irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
+ if (irq_base < 0) {
+ dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+ goto err;
+ }
+ domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
+ &pxa_irq_domain_ops, NULL);
+ return 0;
+err:
+ iounmap(gpio_reg_base);
+ return ret;
+}
+#else
+#define pxa_gpio_probe_dt(pdev) (-1)
+#endif
+
static int __devinit pxa_gpio_probe(struct platform_device *pdev)
{
struct pxa_gpio_chip *c;
struct resource *res;
struct clk *clk;
struct pxa_gpio_platform_data *info;
- int gpio, irq, ret;
+ int gpio, irq, ret, use_of = 0;
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
- pxa_last_gpio = pxa_gpio_nums();
+ ret = pxa_gpio_probe_dt(pdev);
+ if (ret < 0)
+ pxa_last_gpio = pxa_gpio_nums();
+ else
+ use_of = 1;
if (!pxa_last_gpio)
return -EINVAL;
@@ -545,25 +622,27 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
}
+ if (!use_of) {
#ifdef CONFIG_ARCH_PXA
- irq = gpio_to_irq(0);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
-
- irq = gpio_to_irq(1);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
-#endif
+ irq = gpio_to_irq(0);
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
- for (irq = gpio_to_irq(gpio_offset);
- irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+ irq = gpio_to_irq(1);
irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
+#endif
+
+ for (irq = gpio_to_irq(gpio_offset);
+ irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
}
irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
@@ -574,6 +653,7 @@ static struct platform_driver pxa_gpio_driver = {
.probe = pxa_gpio_probe,
.driver = {
.name = "pxa-gpio",
+ .of_match_table = pxa_gpio_dt_ids,
},
};