Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 5/5] ARM: dts: OMAP5: Specify nonsecure PPI IRQ for arch timer
From: Santosh Shilimkar @ 2013-01-19 17:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <e76a7048f02560a90f1e9cdc0181fd43@localhost>

On Saturday 19 January 2013 08:16 PM, Marc Zyngier wrote:
> On Sat, 19 Jan 2013 00:21:22 +0530, Santosh Shilimkar
> <santosh.shilimkar@ti.com> wrote:
>> On Friday 18 January 2013 10:38 PM, Marc Zyngier wrote:
>>> On 18/01/13 17:00, Santosh Shilimkar wrote:
>>>> On Friday 18 January 2013 09:32 PM, Marc Zyngier wrote:
>>>>> On 18/01/13 15:32, Santosh Shilimkar wrote:
>>>>>> From: Rajendra Nayak <rnayak@ti.com>
>>>>>>
>>>>>> Specify both secure as well as nonsecure PPI IRQ for arch
>>>>>> timer. This fixes the following errors seen on DT OMAP5 boot..
>>>>>>
>>>>>> [    0.000000] arch_timer: No interrupt available, giving up
>>>>>>
>>>>>> Cc: Benoit Cousson <b-cousson@ti.com>
>>>>>>
>>>>>> Signed-off-by: Rajendra Nayak <rnayak@ti.com>
>>>>>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>>>>> ---
>>>>>>     arch/arm/boot/dts/omap5.dtsi |   16 ++++++++++++----
>>>>>>     1 file changed, 12 insertions(+), 4 deletions(-)
>>>>>>
>>>>>> diff --git a/arch/arm/boot/dts/omap5.dtsi
>>>>>> b/arch/arm/boot/dts/omap5.dtsi
>>>>>> index 790bb2a..7a78d1b 100644
>>>>>> --- a/arch/arm/boot/dts/omap5.dtsi
>>>>>> +++ b/arch/arm/boot/dts/omap5.dtsi
>>>>>> @@ -35,8 +35,12 @@
>>>>>>     			compatible = "arm,cortex-a15";
>>>>>>     			timer {
>>>>>>     				compatible = "arm,armv7-timer";
>>>>>> -				/* 14th PPI IRQ, active low level-sensitive */
>>>>>> -				interrupts = <1 14 0x308>;
>>>>>> +				/*
>>>>>> +				 * PPI secure/nonsecure IRQ,
>>>>>> +				 * active low level-sensitive
>>>>>> +				 */
>>>>>> +				interrupts = <1 13 0x308>,
>>>>>> +					     <1 14 0x308>;
>>>>>
>>>>> Care to add the virtual and HYP timer interrupts? So KVM can get a
>>>>> chance to run on this HW...
>>>>>
>>>> Thanks Marc for spotting it. Will take care of it.
>>>
>>> I just realised something silly... You have one timer node *per cpu*,
>>> and this is not really expected.
>>>
>> This was discussed on the list here [1]
>> Benoit suggested to add per CPU node since arch timer is per
>> CPU and DT should describe the hw the way it is. Did we miss
>> something ?
>
> The current approach is not to duplicate banked resources. We do not have
> duplicated twd-timer nodes on Cortex A9, we do not expose multiple CPU
> interfaces for the GIC...
>
Yes, I have observed that. The arch/twd timer DT extraction code doesn't
expect per CPU DT node and on that basis only, initial patch was
adding single timer node outside cpu node. Benoit comment was that
the DT should describe the way hardware is and probably the DT
extraction code should be updated accordingly.

> And speaking of the GIC: how do you interpret the CPU mask in the
> interrupt field of the timer? The value 0x3xx in the third field is there
> to indicate that CPU0 and CPU1 are getting interrupted by the timer. What
> does it mean when you duplicate it?>          M.
>

>
Here too I have to keep mask for both CPUs because of the current DT
extraction code. I some how forgot to bring that discussion to your
notice. I can update the DT files to go back to the single timer
node if the plan is not to duplicate the per CPU resources.

Benoit,
Whats your take on it ?

Regards
Santosh

^ permalink raw reply

* [PATCH v2] mm: dmapool: use provided gfp flags for all dma_alloc_coherent() calls
From: Andrew Lunn @ 2013-01-19 16:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301172026.45514.arnd@arndb.de>

On Thu, Jan 17, 2013 at 08:26:45PM +0000, Arnd Bergmann wrote:
> On Thursday 17 January 2013, Soeren Moch wrote:
> > On 17.01.2013 11:49, Arnd Bergmann wrote:
> > > On Wednesday 16 January 2013, Soeren Moch wrote:
> > >>>> I will see what I can do here. Is there an easy way to track the buffer
> > >>>> usage without having to wait for complete exhaustion?
> > >>>
> > >>> DMA_API_DEBUG
> > >>
> > >> OK, maybe I can try this.

I tried this. Not what i expected. We have at least one problem with
the ethernet driver:

WARNING: at lib/dma-debug.c:933 check_unmap+0x4b8/0x8a8()
mv643xx_eth_port mv643xx_eth_port.0: DMA-API: device driver failed to check map error[device address=0x000000001f22be00] [size=1536 bytes] [mapped as single]
Modules linked in:
[<c000db10>] (unwind_backtrace+0x0/0xf4) from [<c0016c44>] (warn_slowpath_common+0x4c/0x64)
[<c0016c44>] (warn_slowpath_common+0x4c/0x64) from [<c0016cf0>] (warn_slowpath_fmt+0x30/0x40)
[<c0016cf0>] (warn_slowpath_fmt+0x30/0x40) from [<c01ab540>] (check_unmap+0x4b8/0x8a8)
[<c01ab540>] (check_unmap+0x4b8/0x8a8) from [<c01abbb8>] (debug_dma_unmap_page+0x8c/0x98)
[<c01abbb8>] (debug_dma_unmap_page+0x8c/0x98) from [<c025cb1c>] (mv643xx_eth_poll+0x630/0x800)
[<c025cb1c>] (mv643xx_eth_poll+0x630/0x800) from [<c0331d9c>] (net_rx_action+0xcc/0x1d4)
[<c0331d9c>] (net_rx_action+0xcc/0x1d4) from [<c001e1b0>] (__do_softirq+0xa8/0x170)
[<c001e1b0>] (__do_softirq+0xa8/0x170) from [<c001e3e8>] (do_softirq+0x5c/0x6c)
[<c001e3e8>] (do_softirq+0x5c/0x6c) from [<c001e610>] (local_bh_enable+0xcc/0xdc)
[<c001e610>] (local_bh_enable+0xcc/0xdc) from [<c0359c74>] (ip_finish_output+0x1c8/0x39c)
[<c0359c74>] (ip_finish_output+0x1c8/0x39c) from [<c03571a4>] (ip_local_out+0x28/0x2c)
[<c03571a4>] (ip_local_out+0x28/0x2c) from [<c0359564>] (ip_queue_xmit+0x118/0x338)
[<c0359564>] (ip_queue_xmit+0x118/0x338) from [<c036e58c>] (tcp_transmit_skb+0x3fc/0x8e4)
[<c036e58c>] (tcp_transmit_skb+0x3fc/0x8e4) from [<c0371218>] (tcp_write_xmit+0x228/0xb08)
[<c0371218>] (tcp_write_xmit+0x228/0xb08) from [<c0371b6c>] (__tcp_push_pending_frames+0x30/0x9c)
[<c0371b6c>] (__tcp_push_pending_frames+0x30/0x9c) from [<c0362940>] (tcp_sendmsg+0x158/0xdc4)
[<c0362940>] (tcp_sendmsg+0x158/0xdc4) from [<c0386620>] (inet_sendmsg+0x38/0x74)
[<c0386620>] (inet_sendmsg+0x38/0x74) from [<c031f370>] (sock_aio_write+0x12c/0x138)
[<c031f370>] (sock_aio_write+0x12c/0x138) from [<c00a62f4>] (do_sync_write+0xa0/0xd0)
[<c00a62f4>] (do_sync_write+0xa0/0xd0) from [<c00a6f18>] (vfs_write+0x13c/0x144)
[<c00a6f18>] (vfs_write+0x13c/0x144) from [<c00a6ff0>] (sys_write+0x44/0x70)
[<c00a6ff0>] (sys_write+0x44/0x70) from [<c0008ce0>] (ret_fast_syscall+0x0/0x2c)
---[ end trace b75faa8779652e63 ]---

I'm getting about 4 errors reported a second from the ethernet driver.

Before i look at issues with em28xx i will first try to get the noise
from the ethernet driver sorted out.

     Andrew

^ permalink raw reply

* [PATCH v2] mm: dmapool: use provided gfp flags for all dma_alloc_coherent() calls
From: Soeren Moch @ 2013-01-19 15:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301172026.45514.arnd@arndb.de>

On 17.01.2013 21:26, Arnd Bergmann wrote:
> On Thursday 17 January 2013, Soeren Moch wrote:
>> On 17.01.2013 11:49, Arnd Bergmann wrote:
>>> On Wednesday 16 January 2013, Soeren Moch wrote:
>>>>>> I will see what I can do here. Is there an easy way to track the buffer
>>>>>> usage without having to wait for complete exhaustion?
>>>>>
>>>>> DMA_API_DEBUG
>>>>
>>>> OK, maybe I can try this.
>>>>>
>>>
>>> Any success with this? It should at least tell you if there is a
>>> memory leak in one of the drivers.
>>
>> Not yet, sorry. I have to do all the tests in my limited spare time.
>> Can you tell me what to search for in the debug output?
>
> Actually now that I've looked closer, you can't immediately see
> all the mappings as I thought.
>
> But please try enabling DMA_API_DEBUG in combination with this
> one-line patch:
>
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index 6b2fb87..3df74ac 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -497,6 +497,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
>   		pr_err_once("ERROR: %u KiB atomic DMA coherent pool is too small!\n"
>   			    "Please increase it with coherent_pool= kernel parameter!\n",
>   			    (unsigned)pool->size / 1024);
> +		debug_dma_dump_mappings(NULL);
>   	}
>   	spin_unlock_irqrestore(&pool->lock, flags);
>
> That will show every single allocation that is currently active. This lets
> you see where all the memory went, and if there is a possible leak or
> excessive fragmentation.
>
> 	Arnd
>

Please find attached a debug log generated with your patch.

I used the sata disk and two em28xx dvb sticks, no other usb devices,
no ethernet cable connected, tuners on saa716x-based card not used.

What I can see in the log: a lot of coherent mappings from sata_mv and 
orion_ehci, a few from mv643xx_eth, no other coherent mappings.
All coherent mappings are page aligned, some of them (from orion_ehci)
are not really small (as claimed in __alloc_from_pool).

I don't believe in a memory leak. When I restart vdr (the application
utilizing the dvb sticks) then there is enough dma memory available
again.

Regards,
Soeren


-------------- next part --------------
A non-text attachment was scrubbed...
Name: dma_debug.log
Type: text/x-log
Size: 215198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130119/365a3ec2/attachment-0001.bin>

^ permalink raw reply

* [PATCH 5/5] ARM: dts: OMAP5: Specify nonsecure PPI IRQ for arch timer
From: Marc Zyngier @ 2013-01-19 14:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50F999AA.2020901@ti.com>

On Sat, 19 Jan 2013 00:21:22 +0530, Santosh Shilimkar
<santosh.shilimkar@ti.com> wrote:
> On Friday 18 January 2013 10:38 PM, Marc Zyngier wrote:
>> On 18/01/13 17:00, Santosh Shilimkar wrote:
>>> On Friday 18 January 2013 09:32 PM, Marc Zyngier wrote:
>>>> On 18/01/13 15:32, Santosh Shilimkar wrote:
>>>>> From: Rajendra Nayak <rnayak@ti.com>
>>>>>
>>>>> Specify both secure as well as nonsecure PPI IRQ for arch
>>>>> timer. This fixes the following errors seen on DT OMAP5 boot..
>>>>>
>>>>> [    0.000000] arch_timer: No interrupt available, giving up
>>>>>
>>>>> Cc: Benoit Cousson <b-cousson@ti.com>
>>>>>
>>>>> Signed-off-by: Rajendra Nayak <rnayak@ti.com>
>>>>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>>>> ---
>>>>>    arch/arm/boot/dts/omap5.dtsi |   16 ++++++++++++----
>>>>>    1 file changed, 12 insertions(+), 4 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm/boot/dts/omap5.dtsi
>>>>> b/arch/arm/boot/dts/omap5.dtsi
>>>>> index 790bb2a..7a78d1b 100644
>>>>> --- a/arch/arm/boot/dts/omap5.dtsi
>>>>> +++ b/arch/arm/boot/dts/omap5.dtsi
>>>>> @@ -35,8 +35,12 @@
>>>>>    			compatible = "arm,cortex-a15";
>>>>>    			timer {
>>>>>    				compatible = "arm,armv7-timer";
>>>>> -				/* 14th PPI IRQ, active low level-sensitive */
>>>>> -				interrupts = <1 14 0x308>;
>>>>> +				/*
>>>>> +				 * PPI secure/nonsecure IRQ,
>>>>> +				 * active low level-sensitive
>>>>> +				 */
>>>>> +				interrupts = <1 13 0x308>,
>>>>> +					     <1 14 0x308>;
>>>>
>>>> Care to add the virtual and HYP timer interrupts? So KVM can get a
>>>> chance to run on this HW...
>>>>
>>> Thanks Marc for spotting it. Will take care of it.
>>
>> I just realised something silly... You have one timer node *per cpu*,
>> and this is not really expected.
>>
> This was discussed on the list here [1]
> Benoit suggested to add per CPU node since arch timer is per
> CPU and DT should describe the hw the way it is. Did we miss
> something ?

The current approach is not to duplicate banked resources. We do not have
duplicated twd-timer nodes on Cortex A9, we do not expose multiple CPU
interfaces for the GIC...

And speaking of the GIC: how do you interpret the CPU mask in the
interrupt field of the timer? The value 0x3xx in the third field is there
to indicate that CPU0 and CPU1 are getting interrupted by the timer. What
does it mean when you duplicate it?

        M.
-- 
Fast, cheap, reliable. Pick two.

^ permalink raw reply

* [PATCH v2] video: Kconfig: Specify the SoCs that make use of FB_IMX
From: Fabio Estevam @ 2013-01-19 10:15 UTC (permalink / raw)
  To: linux-arm-kernel

From: Fabio Estevam <fabio.estevam@freescale.com>

FB_IMX is the framebuffer driver used by MX1, MX21, MX25 and MX27 processors.

Pass this information to the Kconfig text to make it clear.

Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
Shawn,

Could you get this one also via your tree?

No response from the fb maintainer for months on this one.

Changes since v1:
- Add mx1/21 to the list.

 drivers/video/Kconfig |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0cff083..f0c53b2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -364,7 +364,7 @@ config FB_SA1100
 	  Y here.
 
 config FB_IMX
-	tristate "Freescale i.MX LCD support"
+	tristate "Freescale i.MX1/21/25/27 LCD support"
 	depends on FB && IMX_HAVE_PLATFORM_IMX_FB
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH] ARM: tegra: DTS: seaboard: remove unnecessarily text
From: Laxman Dewangan @ 2013-01-19  9:37 UTC (permalink / raw)
  To: linux-arm-kernel

There is unnecessarily text in the keymap table. Removing this.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
 arch/arm/boot/dts/tegra20-seaboard.dts |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index 2e87330..d4e4ff2 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -705,7 +705,7 @@
 				0x0E030010	/* KEY_Q */
 				0x0E04003E	/* KEY_F4 */
 				0x0E05003D	/* KEY_F3 */
-				0x0E060002	/* KEY_1 */1
+				0x0E060002	/* KEY_1 */
 				0x0E070041	/* KEY_F7 */
 
 				0x0F000001	/* KEY_ESC */
-- 
1.7.1.1

^ permalink raw reply related

* [PATCH] dts: vt8500: Add initial dts support for WM8850
From: Tony Prisk @ 2013-01-19  6:44 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a soc dtsi for the Wondermedia WM8850.

A board dts file is also included for the W70v2 tablet, with support
for all the drivers currently in mainline.

Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
Hi Olof,

Sorry this is a bit late.

Regards
Tony P

 arch/arm/boot/dts/Makefile         |    3 +-
 arch/arm/boot/dts/wm8850-w70v2.dts |   47 ++++++++
 arch/arm/boot/dts/wm8850.dtsi      |  224 ++++++++++++++++++++++++++++++++++++
 3 files changed, 273 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/wm8850-w70v2.dts
 create mode 100644 arch/arm/boot/dts/wm8850.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 5ebb44f..8a75991 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -151,7 +151,8 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
 	xenvm-4.2.dtb
 dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \
 	wm8505-ref.dtb \
-	wm8650-mid.dtb
+	wm8650-mid.dtb \
+	wm8850-w70v2.dtb
 dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb
 
 targets += dtbs
diff --git a/arch/arm/boot/dts/wm8850-w70v2.dts b/arch/arm/boot/dts/wm8850-w70v2.dts
new file mode 100644
index 0000000..fcc660c
--- /dev/null
+++ b/arch/arm/boot/dts/wm8850-w70v2.dts
@@ -0,0 +1,47 @@
+/*
+ * wm8850-w70v2.dts
+ *  - Device tree file for Wondermedia WM8850 Tablet
+ *  - 'W70-V2' mainboard
+ *  - HongLianYing 'HLY070ML268-21A' 7" LCD panel
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * Licensed under GPLv2 or later
+ */
+
+/dts-v1/;
+/include/ "wm8850.dtsi"
+
+/ {
+	model = "Wondermedia WM8850-W70v2 Tablet";
+
+	/*
+	 * Display node is based on Sascha Hauer's patch on dri-devel.
+	 * Added a bpp property to calculate the size of the framebuffer
+	 * until the binding is formalized.
+	 */
+	display: display at 0 {
+		modes {
+			mode0: mode at 0 {
+				hactive = <800>;
+				vactive = <480>;
+				hback-porch = <88>;
+				hfront-porch = <40>;
+				hsync-len = <0>;
+				vback-porch = <32>;
+				vfront-porch = <11>;
+				vsync-len = <1>;
+				clock = <0>;	/* unused but required */
+				bpp = <16>;	/* non-standard but required */
+			};
+		};
+	};
+
+	backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 0 50000 1>;	/* duty inverted */
+
+		brightness-levels = <0 40 60 80 100 130 190 255>;
+		default-brightness-level = <5>;
+	};
+};
diff --git a/arch/arm/boot/dts/wm8850.dtsi b/arch/arm/boot/dts/wm8850.dtsi
new file mode 100644
index 0000000..2dbc39c
--- /dev/null
+++ b/arch/arm/boot/dts/wm8850.dtsi
@@ -0,0 +1,224 @@
+/*
+ * wm8850.dtsi - Device tree file for Wondermedia WM8850 SoC
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * Licensed under GPLv2 or later
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	compatible = "wm,wm8850";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges;
+		interrupt-parent = <&intc0>;
+
+		intc0: interrupt-controller at d8140000 {
+			compatible = "via,vt8500-intc";
+			interrupt-controller;
+			reg = <0xd8140000 0x10000>;
+			#interrupt-cells = <1>;
+		};
+
+		/* Secondary IC cascaded to intc0 */
+		intc1: interrupt-controller at d8150000 {
+			compatible = "via,vt8500-intc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			reg = <0xD8150000 0x10000>;
+			interrupts = <56 57 58 59 60 61 62 63>;
+		};
+
+		gpio: gpio-controller at d8110000 {
+			compatible = "wm,wm8650-gpio";
+			gpio-controller;
+			reg = <0xd8110000 0x10000>;
+			#gpio-cells = <3>;
+		};
+
+		pmc at d8130000 {
+			compatible = "via,vt8500-pmc";
+			reg = <0xd8130000 0x1000>;
+
+			clocks {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				ref25: ref25M {
+					#clock-cells = <0>;
+					compatible = "fixed-clock";
+					clock-frequency = <25000000>;
+				};
+
+				ref24: ref24M {
+					#clock-cells = <0>;
+					compatible = "fixed-clock";
+					clock-frequency = <24000000>;
+				};
+
+				plla: plla {
+					#clock-cells = <0>;
+					compatible = "wm,wm8750-pll-clock";
+					clocks = <&ref25>;
+					reg = <0x200>;
+				};
+
+				pllb: pllb {
+					#clock-cells = <0>;
+					compatible = "wm,wm8750-pll-clock";
+					clocks = <&ref25>;
+					reg = <0x204>;
+				};
+
+				clkuart0: uart0 {
+					#clock-cells = <0>;
+					compatible = "via,vt8500-device-clock";
+					clocks = <&ref24>;
+					enable-reg = <0x254>;
+					enable-bit = <24>;
+				};
+
+				clkuart1: uart1 {
+					#clock-cells = <0>;
+					compatible = "via,vt8500-device-clock";
+					clocks = <&ref24>;
+					enable-reg = <0x254>;
+					enable-bit = <25>;
+				};
+
+                                clkuart2: uart2 {
+                                        #clock-cells = <0>;
+                                        compatible = "via,vt8500-device-clock";
+                                        clocks = <&ref24>;
+                                        enable-reg = <0x254>;
+                                        enable-bit = <26>;
+                                };
+
+                                clkuart3: uart3 {
+                                        #clock-cells = <0>;
+                                        compatible = "via,vt8500-device-clock";
+                                        clocks = <&ref24>;
+                                        enable-reg = <0x254>;
+                                        enable-bit = <27>;
+                                };
+
+				clkpwm: pwm {
+ 					#clock-cells = <0>;
+ 					compatible = "via,vt8500-device-clock";
+					clocks = <&pllb>;
+					divisor-reg = <0x350>;
+					enable-reg = <0x250>;
+					enable-bit = <17>;
+ 				};
+
+				clksdhc: sdhc {
+					#clock-cells = <0>;
+					compatible = "via,vt8500-device-clock";
+					clocks = <&pllb>;
+					divisor-reg = <0x330>;
+					divisor-mask = <0x3f>;
+					enable-reg = <0x250>;
+					enable-bit = <0>;
+				};
+			};
+		};
+
+		fb at d8051700 {
+			compatible = "wm,wm8505-fb";
+			reg = <0xd8051700 0x200>;
+			display = <&display>;
+			default-mode = <&mode0>;
+		};
+
+		ge_rops at d8050400 {
+			compatible = "wm,prizm-ge-rops";
+			reg = <0xd8050400 0x100>;
+		};
+
+		pwm: pwm at d8220000 {
+			#pwm-cells = <3>;
+			compatible = "via,vt8500-pwm";
+			reg = <0xd8220000 0x100>;
+			clocks = <&clkpwm>;
+		};
+
+		timer at d8130100 {
+			compatible = "via,vt8500-timer";
+			reg = <0xd8130100 0x28>;
+			interrupts = <36>;
+		};
+
+		ehci at d8007900 {
+			compatible = "via,vt8500-ehci";
+			reg = <0xd8007900 0x200>;
+			interrupts = <26>;
+		};
+
+		uhci at d8007b00 {
+			compatible = "platform-uhci";
+			reg = <0xd8007b00 0x200>;
+			interrupts = <26>;
+		};
+
+		uhci at d8008d00 {
+			compatible = "platform-uhci";
+			reg = <0xd8008d00 0x200>;
+			interrupts = <26>;
+		};
+
+		uart0: uart at d8200000 {
+			compatible = "via,vt8500-uart";
+			reg = <0xd8200000 0x1040>;
+			interrupts = <32>;
+			clocks = <&clkuart0>;
+		};
+
+		uart1: uart at d82b0000 {
+			compatible = "via,vt8500-uart";
+			reg = <0xd82b0000 0x1040>;
+			interrupts = <33>;
+			clocks = <&clkuart1>;
+		};
+
+                uart2: uart at d8210000 {
+                        compatible = "via,vt8500-uart";
+                        reg = <0xd8210000 0x1040>;
+                        interrupts = <47>;
+                        clocks = <&clkuart2>;
+                };
+
+                uart3: uart at d82c0000 {
+                        compatible = "via,vt8500-uart";
+                        reg = <0xd82c0000 0x1040>;
+                        interrupts = <50>;
+                        clocks = <&clkuart3>;
+                };
+
+		rtc at d8100000 {
+			compatible = "via,vt8500-rtc";
+			reg = <0xd8100000 0x10000>;
+			interrupts = <48>;
+		};
+
+		sdhc at d800a000 {
+			compatible = "wm,wm8505-sdhc";
+			reg = <0xd800a000 0x1000>;
+			interrupts = <20 21>;
+			clocks = <&clksdhc>;
+			bus-width = <4>;
+			sdon-inverted;
+		};
+	};
+};
-- 
1.7.9.5

^ permalink raw reply related

* ARM: ux500:mach-ux500/cpuidle.c spinlock dis-matching
From: Steve zhan @ 2013-01-19  6:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Daniel,Linus Walleij.
	Using MUTT resubmit this for 
http://lists.infradead.org/pipermail/linux-arm-kernel/2013-January/139893.html

---
Steve

commit 99d0a05d163bd070eba7caab7e772206edbcbbc9
Author: steve zhan <zhanzhenbo@gmail.com>
Date:   Mon Jan 7 18:19:14 2013 +0800

    ARM: ux500: add spin_unlock(&master_lock).
    
    Add the missing spin_unlock statement to unlock
    master_lock when prcmu_gic_decouple() return TRUE
    
    Signed-off-by: steve zhan <zhanzhenbo@gmail.com>

diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
index b54884bd..ce91493 100644
--- a/arch/arm/mach-ux500/cpuidle.c
+++ b/arch/arm/mach-ux500/cpuidle.c
@@ -40,8 +40,10 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev,
 			goto wfi;
 
 		/* decouple the gic from the A9 cores */
-		if (prcmu_gic_decouple())
+		if (prcmu_gic_decouple()) {
+			spin_unlock(&master_lock);
 			goto out;
+		}
 
 		/* If an error occur, we will have to recouple the gic
 		 * manually */




2013/1/7 Daniel Lezcano <daniel.lezcano@linaro.org>:
> On 01/07/2013 06:50 AM, steve.zhan wrote:
>> Hi Daniel,
>>
>>     Happy new year, Thank you for reply.
>> Sorry for that i have refer the old patch email.
>> I have updated the patch, Pls check the URL:
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-December/138939.html
>> Now i am using gmail GUI tools to send mail, i will switch email tool
>> to MUTT to commit the other patchs in the future.
>
> Ok.
>
> Please do not introduce a new variable which is at the end pointless and
> add more complexity.
>
> You can simply remove the if statement for prcmu_gic_decouple(), or
> unlock if it fails.
>
> Thanks
>   -- Daniel
>
>> --------------
>> steve.zhan
>>
>> 2013/1/7, Daniel Lezcano <daniel.lezcano@linaro.org>:
>>> On 12/28/2012 08:06 AM, steve.zhan wrote:
>>>> Hi Daniel,
>>>
>>> Hi Steve,
>>>
>>> sorry I missed your email.
>>>
>>>>
>>>>        I think we must unlock the master spinlock even
>>>> prcmu_gic_decouple function now always return 0.
>>>>        Could you give some infos about this?
>>>
>>> I agree, that would be cleaner.
>>>
>>> AFAICS, your patch does not solve the problem because 'recouple' will be
>>> false if prcmu_gic_decouple fails, so the lock will never be release.
>>>
>>> That will be simpler to do:
>>>
>>> if (prcmu_gic_decouple()) {
>>>      spin_unlock(&master);
>>>      goto out;
>>> }
>>>
>>> no ?
>>>
>>>> Thanks.
>>>>
>>>> diff --git a/arch/arm/mach-ux500/cpuidle.c
>>>> b/arch/arm/mach-ux500/cpuidle.c
>>>> index b54884bd..b0759ce 100644
>>>> --- a/arch/arm/mach-ux500/cpuidle.c
>>>> +++ b/arch/arm/mach-ux500/cpuidle.c
>>>> @@ -29,6 +29,7 @@ static inline int ux500_enter_idle(struct cpuidle_device
>>>> *dev,
>>>>  {
>>>>         int this_cpu = smp_processor_id();
>>>>         bool recouple = false;
>>>> +       bool locked = false;
>>>>
>>>>         clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu);
>>>>
>>>> @@ -39,6 +40,8 @@ static inline int ux500_enter_idle(struct cpuidle_device
>>>> *dev,
>>>>                 if (!spin_trylock(&master_lock))
>>>>                         goto wfi;
>>>>
>>>> +               locked = true;
>>>> +
>>>>                 /* decouple the gic from the A9 cores */
>>>>                 if (prcmu_gic_decouple())
>>>>                         goto out;
>>>> @@ -76,7 +79,7 @@ static inline int ux500_enter_idle(struct cpuidle_device
>>>> *dev,
>>>>                 /* When we switch to retention, the prcmu is in charge
>>>>                  * of recoupling the gic automatically */
>>>>                 recouple = false;
>>>> -
>>>> +               locked = false;
>>>>                 spin_unlock(&master_lock);
>>>>         }
>>>>  wfi:
>>>> @@ -86,7 +89,8 @@ out:
>>>>
>>>>         if (recouple) {
>>>>                 prcmu_gic_recouple();
>>>> -               spin_unlock(&master_lock);
>>>> +               if (locked)
>>>> +                       spin_unlock(&master_lock);
>>>>         }
>>>>
>>>>         clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu);
>>>>
>>>>
>>>>
>>>> Steve Zhan
>>>>
>>>
>>>
>>> --
>>>  <http://www.linaro.org/> Linaro.org ?? Open source software for ARM SoCs
>>>
>>> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
>>> <http://twitter.com/#!/linaroorg> Twitter |
>>> <http://www.linaro.org/linaro-blog/> Blog
>>>
>>>
>>
>>
>
>
> --
>  <http://www.linaro.org/> Linaro.org ?? Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

^ permalink raw reply related

* [PATCH] rtc: vt8500: Fix year field in vt8500_rtc_set_time
From: Tony Prisk @ 2013-01-19  6:23 UTC (permalink / raw)
  To: linux-arm-kernel

year field is incorrectly masked when setting the date. If the year
is beyond 2099, the year field will be incorrectly updated in hardware.

This patch masks the year field correctly.

Signed-off-by: Edgar Toernig <froese@gmx.de>
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
Hi Andrew,

This patch has been floating around since -rc1, but looks like it may have been
missed. I have rebased it onto -rc4 to make applying it easier. Trivial fix.

Regards
Tony P

 drivers/rtc/rtc-vt8500.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
index 00c930f..2730533 100644
--- a/drivers/rtc/rtc-vt8500.c
+++ b/drivers/rtc/rtc-vt8500.c
@@ -137,7 +137,7 @@ static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
 		return -EINVAL;
 	}
 
-	writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S)
+	writel((bin2bcd(tm->tm_year % 100) << DATE_YEAR_S)
 		| (bin2bcd(tm->tm_mon + 1) << DATE_MONTH_S)
 		| (bin2bcd(tm->tm_mday))
 		| ((tm->tm_year >= 200) << DATE_CENTURY_S),
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 4/4] video: vt8500: Update descriptions in video/Kconfig
From: Tony Prisk @ 2013-01-19  6:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358575377-26364-1-git-send-email-linux@prisktech.co.nz>

This patch updates the descriptions for the VIA VT8500 and
Wondermedia WM8xxx-series framebuffer drivers to correctly reflect
which hardware they support.

Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
 drivers/video/Kconfig |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6678daf..3bbb3c1 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1767,7 +1767,7 @@ config FB_AU1200
 	  option au1200fb:panel=<name>.
 
 config FB_VT8500
-	bool "VT8500 LCD Driver"
+	bool "VIA VT8500 Framebuffer Driver"
 	depends on (FB = y) && ARM && ARCH_VT8500
 	select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
 	select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
@@ -1777,14 +1777,15 @@ config FB_VT8500
 	  controller.
 
 config FB_WM8505
-	bool "WM8505 frame buffer support"
+	bool "Wondermedia WM8xxx-series framebuffer support"
 	depends on (FB = y) && ARM && ARCH_VT8500
 	select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
 	select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
 	select FB_SYS_IMAGEBLIT
 	help
-	  This is the framebuffer driver for WonderMedia WM8505/WM8650
-	  integrated LCD controller.
+	  This is the framebuffer driver for WonderMedia WM8xxx-series
+	  integrated LCD controller. This driver covers the WM8505, WM8650
+	  and WM8850 SoCs.
 
 config FB_WMT_GE_ROPS
 	bool "VT8500/WM8xxx accelerated raster ops support"
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 3/4] video: vt8500: Remove unused platform_data/video-vt8500lcdfb.h
From: Tony Prisk @ 2013-01-19  6:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358575377-26364-1-git-send-email-linux@prisktech.co.nz>

With the conversion to devicetree only for arch-vt8500, this
header is no longer required. This patch removes the #include
from the two framebuffer drivers that used it, and the header file.

Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
 drivers/video/vt8500lcdfb.c                     |    2 --
 drivers/video/wm8505fb.c                        |    2 --
 include/linux/platform_data/video-vt8500lcdfb.h |   31 -----------------------
 3 files changed, 35 deletions(-)
 delete mode 100644 include/linux/platform_data/video-vt8500lcdfb.h

diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c
index d8cc1f6..1c34821 100644
--- a/drivers/video/vt8500lcdfb.c
+++ b/drivers/video/vt8500lcdfb.c
@@ -30,8 +30,6 @@
 #include <linux/platform_device.h>
 #include <linux/wait.h>
 
-#include <linux/platform_data/video-vt8500lcdfb.h>
-
 #include "vt8500lcdfb.h"
 
 #ifdef CONFIG_FB_WMT_GE_ROPS
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c
index dd28c26..8c8c129 100644
--- a/drivers/video/wm8505fb.c
+++ b/drivers/video/wm8505fb.c
@@ -32,8 +32,6 @@
 #include <linux/of_fdt.h>
 #include <linux/memblock.h>
 
-#include <linux/platform_data/video-vt8500lcdfb.h>
-
 #include "wm8505fb_regs.h"
 
 #ifdef CONFIG_FB_WMT_GE_ROPS
diff --git a/include/linux/platform_data/video-vt8500lcdfb.h b/include/linux/platform_data/video-vt8500lcdfb.h
deleted file mode 100644
index 7f399c3..0000000
--- a/include/linux/platform_data/video-vt8500lcdfb.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *  VT8500/WM8505 Frame Buffer platform data definitions
- *
- *  Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef _VT8500FB_H
-#define _VT8500FB_H
-
-#include <linux/fb.h>
-
-struct vt8500fb_platform_data {
-	struct fb_videomode	mode;
-	u32			xres_virtual;
-	u32			yres_virtual;
-	u32			bpp;
-	unsigned long		video_mem_phys;
-	void			*video_mem_virt;
-	unsigned long		video_mem_len;
-};
-
-#endif /* _VT8500FB_H */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 2/4] video: vt8500: Make wmt_ge_rops optional
From: Tony Prisk @ 2013-01-19  6:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358575377-26364-1-git-send-email-linux@prisktech.co.nz>

At the moment, accelerated raster ops are always enabled on VT8500
and WM8xxx series SoCs. This patch makes them optional.

Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
 drivers/video/Kconfig       |   23 +++++++++++++----------
 drivers/video/vt8500lcdfb.c |   15 +++++++++++++++
 drivers/video/wm8505fb.c    |   15 +++++++++++++++
 3 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e7068c5..6678daf 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -190,14 +190,6 @@ config FB_SYS_FOPS
        depends on FB
        default n
 
-config FB_WMT_GE_ROPS
-	tristate
-	depends on FB
-	default n
-	---help---
-	  Include functions for accelerated rectangle filling and area
-	  copying using WonderMedia Graphics Engine operations.
-
 config FB_DEFERRED_IO
 	bool
 	depends on FB
@@ -1777,7 +1769,8 @@ config FB_AU1200
 config FB_VT8500
 	bool "VT8500 LCD Driver"
 	depends on (FB = y) && ARM && ARCH_VT8500
-	select FB_WMT_GE_ROPS
+	select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
+	select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
 	select FB_SYS_IMAGEBLIT
 	help
 	  This is the framebuffer driver for VIA VT8500 integrated LCD
@@ -1786,12 +1779,22 @@ config FB_VT8500
 config FB_WM8505
 	bool "WM8505 frame buffer support"
 	depends on (FB = y) && ARM && ARCH_VT8500
-	select FB_WMT_GE_ROPS
+	select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
+	select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
 	select FB_SYS_IMAGEBLIT
 	help
 	  This is the framebuffer driver for WonderMedia WM8505/WM8650
 	  integrated LCD controller.
 
+config FB_WMT_GE_ROPS
+	bool "VT8500/WM8xxx accelerated raster ops support"
+	depends on (FB = y) && (FB_VT8500 || FB_WM8505)
+	default n
+	help
+	  This adds support for accelerated raster operations on the
+	  VIA VT8500 and Wondermedia 8xxx series SoCs.
+
+
 source "drivers/video/geode/Kconfig"
 
 config FB_HIT
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c
index aa2579c..d8cc1f6 100644
--- a/drivers/video/vt8500lcdfb.c
+++ b/drivers/video/vt8500lcdfb.c
@@ -33,7 +33,10 @@
 #include <linux/platform_data/video-vt8500lcdfb.h>
 
 #include "vt8500lcdfb.h"
+
+#ifdef CONFIG_FB_WMT_GE_ROPS
 #include "wmt_ge_rops.h"
+#endif
 
 #ifdef CONFIG_OF
 #include <linux/of.h>
@@ -249,12 +252,24 @@ static int vt8500lcd_blank(int blank, struct fb_info *info)
 	return 0;
 }
 
+#ifndef CONFIG_FB_WMT_GE_ROPS
+static int wmt_ge_sync(struct fb_info *p)
+{
+	return 0;
+}
+#endif
+
 static struct fb_ops vt8500lcd_ops = {
 	.owner		= THIS_MODULE,
 	.fb_set_par	= vt8500lcd_set_par,
 	.fb_setcolreg	= vt8500lcd_setcolreg,
+#ifdef CONFIG_FB_WMT_GE_ROPS
 	.fb_fillrect	= wmt_ge_fillrect,
 	.fb_copyarea	= wmt_ge_copyarea,
+#else
+	.fb_fillrect	= sys_fillrect,
+	.fb_copyarea	= sys_copyarea,
+#endif
 	.fb_imageblit	= sys_imageblit,
 	.fb_sync	= wmt_ge_sync,
 	.fb_ioctl	= vt8500lcd_ioctl,
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c
index ddf78fc..dd28c26 100644
--- a/drivers/video/wm8505fb.c
+++ b/drivers/video/wm8505fb.c
@@ -35,7 +35,10 @@
 #include <linux/platform_data/video-vt8500lcdfb.h>
 
 #include "wm8505fb_regs.h"
+
+#ifdef CONFIG_FB_WMT_GE_ROPS
 #include "wmt_ge_rops.h"
+#endif
 
 #define DRIVER_NAME "wm8505-fb"
 
@@ -248,12 +251,24 @@ static int wm8505fb_blank(int blank, struct fb_info *info)
 	return 0;
 }
 
+#ifndef CONFIG_FB_WMT_GE_ROPS
+static int wmt_ge_sync(struct fb_info *p)
+{
+	return 0;
+}
+#endif
+
 static struct fb_ops wm8505fb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_set_par	= wm8505fb_set_par,
 	.fb_setcolreg	= wm8505fb_setcolreg,
+#ifdef CONFIG_FB_WMT_GE_ROPS
 	.fb_fillrect	= wmt_ge_fillrect,
 	.fb_copyarea	= wmt_ge_copyarea,
+#else
+	.fb_fillrect	= sys_fillrect,
+	.fb_copyarea	= sys_copyarea,
+#endif
 	.fb_imageblit	= sys_imageblit,
 	.fb_sync	= wmt_ge_sync,
 	.fb_pan_display	= wm8505fb_pan_display,
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 1/4] drivers/video/wm8505fb.c: use devm_ functions
From: Tony Prisk @ 2013-01-19  6:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358575377-26364-1-git-send-email-linux@prisktech.co.nz>

From: Julia Lawall <Julia.Lawall@lip6.fr>

The various devm_ functions allocate memory that is released when a driver
detaches.  This patch uses these functions for data that is allocated in
the probe function of a platform device and is only freed in the remove
function.

The patch makes some other cleanups.  First, the original code used
devm_kzalloc, but kfree.  This would lead to a double free.  The problem
was found using the following semantic match (http://coccinelle.lip6.fr/):

// <smpl>
@@
expression x,e;
@@
x = devm_kzalloc(...)
... when != x = e
?-kfree(x,...);
// </smpl>

The error-handing code of devm_request_and_ioremap does not print any
warning message, because devm_request_and_ioremap does this.

The call to dma_alloc_coherent is converted to its devm equivalent,
dmam_alloc_coherent.  This implicitly introduces a call to
dmam_free_coherent, which was completly missing in the original code.

A semicolon is removed at the end of the error-handling code for the call
to dma_alloc_coherent.

The block of code calling fb_alloc_cmap is moved below the block of code
calling wm8505fb_set_par, so that the error-handing code of the call to
wm8505fb_set_par can just return ret.  This way there is only one block of
error-handling code that needs to call fb_dealloc_cmap, and so this is
moved up to the place where it is needed, eliminating the need for all
gotos and labels in the function.  This was suggested by Tony Prisk.

The initializations of fbi and ret at the beginning of the function are not
necessary and are removed.  The call platform_set_drvdata(pdev, NULL); at
the end of the function is also removed.

Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
 drivers/video/wm8505fb.c |   78 +++++++++++-----------------------------------
 1 file changed, 19 insertions(+), 59 deletions(-)

diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c
index 4dd0580..ddf78fc 100644
--- a/drivers/video/wm8505fb.c
+++ b/drivers/video/wm8505fb.c
@@ -274,15 +274,11 @@ static int wm8505fb_probe(struct platform_device *pdev)
 	unsigned long fb_mem_len;
 	void *fb_mem_virt;
 
-	ret = -ENOMEM;
-	fbi = NULL;
-
 	fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) +
 			sizeof(u32) * 16, GFP_KERNEL);
 	if (!fbi) {
 		dev_err(&pdev->dev, "Failed to initialize framebuffer device\n");
-		ret = -ENOMEM;
-		goto failed;
+		return -ENOMEM;
 	}
 
 	strcpy(fbi->fb.fix.id, DRIVER_NAME);
@@ -308,31 +304,15 @@ static int wm8505fb_probe(struct platform_device *pdev)
 	fbi->fb.pseudo_palette	= addr;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "no I/O memory resource defined\n");
-		ret = -ENODEV;
-		goto failed_fbi;
-	}
-
-	res = request_mem_region(res->start, resource_size(res), DRIVER_NAME);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "failed to request I/O memory\n");
-		ret = -EBUSY;
-		goto failed_fbi;
-	}
 
-	fbi->regbase = ioremap(res->start, resource_size(res));
-	if (fbi->regbase == NULL) {
-		dev_err(&pdev->dev, "failed to map I/O memory\n");
-		ret = -EBUSY;
-		goto failed_free_res;
-	}
+	fbi->regbase = devm_request_and_ioremap(&pdev->dev, res);
+	if (fbi->regbase == NULL)
+		return -EBUSY;
 
 	np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0);
 	if (!np) {
 		pr_err("%s: No display description in Device Tree\n", __func__);
-		ret = -EINVAL;
-		goto failed_free_res;
+		return -EINVAL;
 	}
 
 	/*
@@ -351,7 +331,7 @@ static int wm8505fb_probe(struct platform_device *pdev)
 	ret |= of_property_read_u32(np, "bpp", &bpp);
 	if (ret) {
 		pr_err("%s: Unable to read display properties\n", __func__);
-		goto failed_free_res;
+		return ret;
 	}
 
 	of_mode.vmode = FB_VMODE_NONINTERLACED;
@@ -365,12 +345,12 @@ static int wm8505fb_probe(struct platform_device *pdev)
 
 	/* try allocating the framebuffer */
 	fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8);
-	fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys,
+	fb_mem_virt = dmam_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys,
 				GFP_KERNEL);
 	if (!fb_mem_virt) {
 		pr_err("%s: Failed to allocate framebuffer\n", __func__);
 		return -ENOMEM;
-	};
+	}
 
 	fbi->fb.var.xres_virtual	= of_mode.xres;
 	fbi->fb.var.yres_virtual	= of_mode.yres * 2;
@@ -381,28 +361,29 @@ static int wm8505fb_probe(struct platform_device *pdev)
 	fbi->fb.screen_base		= fb_mem_virt;
 	fbi->fb.screen_size		= fb_mem_len;
 
-	if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
-		dev_err(&pdev->dev, "Failed to allocate color map\n");
-		ret = -ENOMEM;
-		goto failed_free_io;
-	}
-
-	wm8505fb_init_hw(&fbi->fb);
-
 	fbi->contrast = 0x80;
 	ret = wm8505fb_set_par(&fbi->fb);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to set parameters\n");
-		goto failed_free_cmap;
+		return ret;
 	}
 
+	if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
+		dev_err(&pdev->dev, "Failed to allocate color map\n");
+		return -ENOMEM;
+	}
+
+	wm8505fb_init_hw(&fbi->fb);
+
 	platform_set_drvdata(pdev, fbi);
 
 	ret = register_framebuffer(&fbi->fb);
 	if (ret < 0) {
 		dev_err(&pdev->dev,
 			"Failed to register framebuffer device: %d\n", ret);
-		goto failed_free_cmap;
+		if (fbi->fb.cmap.len)
+			fb_dealloc_cmap(&fbi->fb.cmap);
+		return ret;
 	}
 
 	ret = device_create_file(&pdev->dev, &dev_attr_contrast);
@@ -416,25 +397,11 @@ static int wm8505fb_probe(struct platform_device *pdev)
 	       fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1);
 
 	return 0;
-
-failed_free_cmap:
-	if (fbi->fb.cmap.len)
-		fb_dealloc_cmap(&fbi->fb.cmap);
-failed_free_io:
-	iounmap(fbi->regbase);
-failed_free_res:
-	release_mem_region(res->start, resource_size(res));
-failed_fbi:
-	platform_set_drvdata(pdev, NULL);
-	kfree(fbi);
-failed:
-	return ret;
 }
 
 static int wm8505fb_remove(struct platform_device *pdev)
 {
 	struct wm8505fb_info *fbi = platform_get_drvdata(pdev);
-	struct resource *res;
 
 	device_remove_file(&pdev->dev, &dev_attr_contrast);
 
@@ -445,13 +412,6 @@ static int wm8505fb_remove(struct platform_device *pdev)
 	if (fbi->fb.cmap.len)
 		fb_dealloc_cmap(&fbi->fb.cmap);
 
-	iounmap(fbi->regbase);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-
-	kfree(fbi);
-
 	return 0;
 }
 
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL] video: vt8500: Cleanup for 3.9
From: Tony Prisk @ 2013-01-19  6:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Florian,

This is a series of patches for the vt8500 framebuffer driver. Mostly
cleanup stuff.

Non-cleanup:
video: vt8500: Make wmt_ge_rops optional - This patch makes hardware accelerated
raster ops optional as it doesn't work on the newly added WM8850 (yet).

Regards
Tony Prisk


The following changes since commit 7d1f9aeff1ee4a20b1aeb377dd0f579fe9647619:

  Linux 3.8-rc4 (2013-01-17 19:25:45 -0800)

are available in the git repository at:

  git://server.prisktech.co.nz/git/linuxwmt.git tags/vt8500/video-3.9

for you to fetch changes up to 9167fe967de331a9457e1b4d4fc211857ba3b6ab:

  video: vt8500: Update descriptions in video/Kconfig (2013-01-19 18:52:28 +1300)

----------------------------------------------------------------
video: vt8500: Cleanup for 3.9

----------------------------------------------------------------
Julia Lawall (1):
      drivers/video/wm8505fb.c: use devm_ functions

Tony Prisk (3):
      video: vt8500: Make wmt_ge_rops optional
      video: vt8500: Remove unused platform_data/video-vt8500lcdfb.h
      video: vt8500: Update descriptions in video/Kconfig

 drivers/video/Kconfig                           |   32 ++++----
 drivers/video/vt8500lcdfb.c                     |   17 +++-
 drivers/video/wm8505fb.c                        |   95 ++++++++---------------
 include/linux/platform_data/video-vt8500lcdfb.h |   31 --------
 4 files changed, 67 insertions(+), 108 deletions(-)
 delete mode 100644 include/linux/platform_data/video-vt8500lcdfb.h

^ permalink raw reply

* Compilation problem with drivers/staging/zsmalloc when !SMP on ARM
From: Konrad Rzeszutek Wilk @ 2013-01-19  4:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKGA1bmJ6c4LC=NAD4MU_rBZ2hZjf6qH=C+dqMCf0eP+2vSFdA@mail.gmail.com>

On Fri, Jan 18, 2013 at 07:11:32PM -0600, Matt Sealey wrote:
> On Fri, Jan 18, 2013 at 3:08 PM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Fri, Jan 18, 2013 at 02:24:15PM -0600, Matt Sealey wrote:
> >> Hello all,
> >>
> >> I wonder if anyone can shed some light on this linking problem I have
> >> right now. If I configure my kernel without SMP support (it is a very
> >> lean config for i.MX51 with device tree support only) I hit this error
> >> on linking:
> >
> > Yes, I looked at this, and I've decided that I will _not_ fix this export,
> > neither will I accept a patch to add an export.
> 
> Understood..
> 
> > As far as I can see, this code is buggy in a SMP environment.  There's
> > apparantly no guarantee that:
> >
> > 1. the mapping will be created on a particular CPU.
> > 2. the mapping will then be used only on this specific CPU.
> > 3. no guarantee that another CPU won't speculatively prefetch from this
> >    region.
> > 4. when the mapping is torn down, no guarantee that it's the same CPU that
> >    used the happing.
> >
> > So, the use of the local TLB flush leaves all the other CPUs potentially
> > containing TLB entries for this mapping.
> 
> I'm gonna put this out to the maintainers (Konrad, and Seth since he
> committed it) that if this code is buggy it gets taken back out, even
> if it makes zsmalloc "slow" on ARM, for the following reasons:

Just to make sure I understand, you mean don't use page table
mapping but instead use copying?

> 
> * It's buggy on SMP as Russell describes above
> * It might not be buggy on UP (opposite to Russell's description above
> as the restrictions he states do not exist), but that would imply an
> export for a really core internal MM function nobody should be using
> anyway
> * By that assessment, using that core internal MM function on SMP is
> also bad voodoo that zsmalloc should not be doing

 'local_tlb_flush' is bad voodoo?

> 
> It also either smacks of a lack of comprehensive testing or defiance
> of logic that nobody ever built the code without CONFIG_SMP, which
> means it was only tested on a bunch of SMP ARM systems (I'm guessing..
> Pandaboard? :) or UP systems with SMP/SMP_ON_UP enabled (to expand on
> that guess, maybe Beagleboard in some multiplatform Beagle/Panda
> hybrid kernel). I am sure I was reading the mailing lists when that
> patch was discussed, coded and committed and my guess is correct. In
> this case, what we have here anyway is code which when PROPERLY
> configured as so..

The initial patch were done on x86. Then Seth did the work to make sure
it worked on PPC. Munchin looked on ARM and that is it.

If you have an ARM server that you would be willing to part with I would
be thrilled to look at it.

> 
> diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c
> b/drivers/staging/zsmalloc/zsmalloc-main.c
> index 09a9d35..ecf75fb 100644
	> --- a/drivers/staging/zsmalloc/zsmalloc-main.c
> +++ b/drivers/staging/zsmalloc/zsmalloc-main.c
> @@ -228,7 +228,7 @@ struct zs_pool {
>   * mapping rather than copying
>   * for object mapping.
>  */
> -#if defined(CONFIG_ARM)
> +#if defined(CONFIG_ARM) && defined(CONFIG_SMP)
>  #define USE_PGTABLE_MAPPING
>  #endif
> 
> .. such that it even compiles in both "guess" configurations, the
> slower Cortex-A8 600MHz single core system gets to use the slow copy
> path and the dual-core 1GHz+ Cortex-A9 (with twice the RAM..) gets to
> use the fast mapping path. Essentially all the patch does is "improve
> performance" on the fastest, best-configured, large-amounts-of-RAM,
> lots-of-CPU-performance ARM systems (OMAP4+, Snapdragon, Exynos4+,
> marvell armada, i.MX6..) while introducing the problems Russell
> describes, and leave performance exactly the same and potentially far
> more stable on the slower, memory-limited ARM machines.

Any ideas on how to detect that?
> 
> Given the purpose of zsmalloc, zram, zcache etc. this somewhat defies
> logic. If it's not making the memory-limited, slow ARM systems run
> better, what's the point?
> 
> So in summary I suggest "we" (Greg? or is it Seth's responsibility?)
> should just back out that whole USE_PGTABLE_MAPPING chunk of code
> introduced with f553646. Then Russell can carry on randconfiging and I
> can build for SMP and UP and get the same code.. with less bugs.

I get that you want to have this fixed right now. I think having it
fixed the right way is a better choice. Lets discuss that first
before we start tossing patches to disable parts of it.

^ permalink raw reply

* Compilation problem with drivers/staging/zsmalloc when !SMP on ARM
From: Konrad Rzeszutek Wilk @ 2013-01-19  4:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130118214527.GA913@kroah.com>

On Fri, Jan 18, 2013 at 01:45:27PM -0800, Greg Kroah-Hartman wrote:
> On Fri, Jan 18, 2013 at 09:08:59PM +0000, Russell King - ARM Linux wrote:
> > On Fri, Jan 18, 2013 at 02:24:15PM -0600, Matt Sealey wrote:
> > > Hello all,
> > > 
> > > I wonder if anyone can shed some light on this linking problem I have
> > > right now. If I configure my kernel without SMP support (it is a very
> > > lean config for i.MX51 with device tree support only) I hit this error
> > > on linking:
> > 
> > Yes, I looked at this, and I've decided that I will _not_ fix this export,
> > neither will I accept a patch to add an export.
> > 
> > As far as I can see, this code is buggy in a SMP environment.  There's
> > apparantly no guarantee that:
> > 
> > 1. the mapping will be created on a particular CPU.
> > 2. the mapping will then be used only on this specific CPU.
> > 3. no guarantee that another CPU won't speculatively prefetch from this
> >    region.

I thought the code had per_cpu for it - so that you wouldn't do that unless
you really went out the way to do it.

> > 4. when the mapping is torn down, no guarantee that it's the same CPU that
> >    used the happing.

With per_cpu that actually would be the case.
> > 
> > So, the use of the local TLB flush leaves all the other CPUs potentially
> > containing TLB entries for this mapping.

Right. That is the point of a local TLB flush.
> > 
> > Finally, there is no TODO file for this driver, which I believe is a
> > requirement for anything to be in stable.  So as far as I can see, it
> > should be deleted or a TODO file added.  I'm not sure why Greg decided
> > to add it without a TODO file.

A TODO file can certainly be added and it is welcome.
> 
> I don't know, I'm cursing the day I took the whole zsmalloc, zcache,
> zram mess that we have in the staging tree now.  People are working to
> get them out of staging, which is good, but the churn involved is
> driving me crazy.

Oh oh.

^ permalink raw reply

* [PATCH v2 3/9] ARM: PRIMA2: initialize l2x0 according to mach from DT
From: Barry Song @ 2013-01-19  4:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130116120318.GD10218@e106331-lin.cambridge.arm.com>

Hi Mark,

2013/1/16 Mark Rutland <mark.rutland@arm.com>:
> On Wed, Jan 16, 2013 at 05:53:29AM +0000, Barry Song wrote:
>> From: Barry Song <Baohua.Song@csr.com>
>>
>> prima2 and marco have diffetent l2 cache configuration, so
>> we initialize l2x0 cache based on dtb given to kernel.
>>
>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> ---
>>  arch/arm/mach-prima2/l2x0.c |   29 ++++++++++++++++++++++++-----
>>  1 files changed, 24 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c
>> index c998377..e41ecd2 100644
>> --- a/arch/arm/mach-prima2/l2x0.c
>> +++ b/arch/arm/mach-prima2/l2x0.c
>> @@ -11,19 +11,38 @@
>>  #include <linux/of.h>
>>  #include <asm/hardware/cache-l2x0.h>
>>
>> -static struct of_device_id prima2_l2x0_ids[]  = {
>> -     { .compatible = "sirf,prima2-pl310-cache" },
>> +struct l2x0_aux
>> +{
>> +     u32 val;
>> +     u32 mask;
>> +};
>> +
>> +static struct l2x0_aux prima2_l2x0_aux __initconst = {
>> +     0x40000,
>> +     0,
>> +};
>
> That 0x40000 is a bit opaque. Now would be a good time to make it a bit more
> legible. Am I right in saying that's (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) ?
>
> It'd also be nice if you used designated initializers:
>
> static struct l2x0_aux prima2_l2x0_aux __initconst = {
>         .val    = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT),
>         .mask   = 0,
> };

good. and make prima2 have consistent style with marco.

>
>> +
>> +static struct l2x0_aux marco_l2x0_aux __initconst = {
>> +     (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
>> +             (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT),
>> +     L2X0_AUX_CTRL_MASK,
>> +};
>
> And here too:
>
> static struct l2x0_aux marco_l2x0_aux __initconst = {
>         .val    = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
>                         (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT),
>         .mask   = L2X0_AUX_CTRL_MASK,
> };
>
>> +
>> +static struct of_device_id sirf_l2x0_ids[] __initconst = {
>> +     { .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, },
>> +     { .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, },
>>       {},
>>  };
>
> I took a look at of_match_node, and it seems that the first match found in an
> of_match_table will be returned first, rather than finding the match earliest
> in a device node's compatible list. This is somewhat counter-intuitive.
>
> Therefore, the marco variant should be listed first, or it will get initialised
> with the prima2 configuration values.

sorry. i don't get it.  do you mean .data(prima2_l2x0_aux) will be
returned for marco?

here l2 node in matco.dts  without "sirf,prima2-pl310-cache"  will
only have "sirf,marco-pl310-cache" and l2 node in prima2.dts without
"sirf,marco-pl310-cache" will only have "sirf,prima2-pl310-cache"

>
>>
>>  static int __init sirfsoc_l2x0_init(void)
>>  {
>>       struct device_node *np;
>> +     const struct l2x0_aux *aux;
>>
>> -     np = of_find_matching_node(NULL, prima2_l2x0_ids);
>> +     np = of_find_matching_node(NULL, sirf_l2x0_ids);
>>       if (np) {
>> -             pr_info("Initializing prima2 L2 cache\n");
>> -             return l2x0_of_init(0x40000, 0);
>> +             aux = of_match_node(sirf_l2x0_ids, np)->data;
>> +             return l2x0_of_init(aux->val, aux->mask);
>>       }
>>
>>       return 0;
>> --
>> 1.7.5.4
>>
>>
>
> With those changes:
>
> Reviewed-by: Mark Rutland <mark.rutland@arm.com>
>
> Thanks,
> Mark.

-barry

^ permalink raw reply

* [PATCH v2 8/9] ARM: PRIMA2: add new SiRFmarco SMP SoC infrastructures
From: Barry Song @ 2013-01-19  4:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130116153739.GE10218@e106331-lin.cambridge.arm.com>

Hi Mark,
Thanks very much for reviewing.

2013/1/16 Mark Rutland <mark.rutland@arm.com>:
> Hello,
>
> On Wed, Jan 16, 2013 at 05:56:23AM +0000, Barry Song wrote:
>> From: Barry Song <Baohua.Song@csr.com>
>>
>> this patch adds tick timer, smp entries and generic DT machine
>> for SiRFmarco dual-core SMP chips.
>>
>> with the added marco, we change the defconfig, using the same
>> defconfig, we get a zImage which can work on both prima2 and
>> marco.
>>
>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
>> ---
>>  arch/arm/boot/dts/Makefile         |    1 +
>>  arch/arm/configs/prima2_defconfig  |    3 +
>>  arch/arm/mach-prima2/Kconfig       |   10 +
>>  arch/arm/mach-prima2/Makefile      |    3 +
>>  arch/arm/mach-prima2/common.c      |   40 ++++-
>>  arch/arm/mach-prima2/common.h      |   11 +
>>  arch/arm/mach-prima2/headsmp.S     |   79 ++++++++
>>  arch/arm/mach-prima2/hotplug.c     |   41 ++++
>>  arch/arm/mach-prima2/platsmp.c     |  170 +++++++++++++++++
>>  arch/arm/mach-prima2/timer-marco.c |  355 ++++++++++++++++++++++++++++++++++++
>>  10 files changed, 712 insertions(+), 1 deletions(-)
>>  create mode 100644 arch/arm/mach-prima2/headsmp.S
>>  create mode 100644 arch/arm/mach-prima2/hotplug.c
>>  create mode 100644 arch/arm/mach-prima2/platsmp.c
>>  create mode 100644 arch/arm/mach-prima2/timer-marco.c
>>
>> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
>> index e44da40..6af9901 100644
>> --- a/arch/arm/boot/dts/Makefile
>> +++ b/arch/arm/boot/dts/Makefile
>> @@ -73,6 +73,7 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-dns320.dtb \
>>         kirkwood-ts219-6281.dtb \
>>         kirkwood-ts219-6282.dtb \
>>         kirkwood-openblocks_a6.dtb
>> +dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb
>>  dtb-$(CONFIG_ARCH_MSM) += msm8660-surf.dtb \
>>         msm8960-cdp.dtb
>>  dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \
>> diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig
>> index 6a936c7..002a1ce 100644
>> --- a/arch/arm/configs/prima2_defconfig
>> +++ b/arch/arm/configs/prima2_defconfig
>> @@ -11,6 +11,9 @@ CONFIG_PARTITION_ADVANCED=y
>>  CONFIG_BSD_DISKLABEL=y
>>  CONFIG_SOLARIS_X86_PARTITION=y
>>  CONFIG_ARCH_SIRF=y
>> +# CONFIG_SWP_EMULATE is not set
>> +CONFIG_SMP=y
>> +CONFIG_SCHED_MC=y
>>  CONFIG_PREEMPT=y
>>  CONFIG_AEABI=y
>>  CONFIG_KEXEC=y
>> diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig
>> index 558ccfb..4f7379f 100644
>> --- a/arch/arm/mach-prima2/Kconfig
>> +++ b/arch/arm/mach-prima2/Kconfig
>> @@ -11,6 +11,16 @@ config ARCH_PRIMA2
>>         help
>>            Support for CSR SiRFSoC ARM Cortex A9 Platform
>>
>> +config ARCH_MARCO
>> +       bool "CSR SiRFSoC MARCO ARM Cortex A9 Platform"
>> +       default y
>> +       select ARM_GIC
>> +       select CPU_V7
>> +       select HAVE_SMP
>> +       select SMP_ON_UP
>> +       help
>> +          Support for CSR SiRFSoC ARM Cortex A9 Platform
>> +
>>  endmenu
>>
>>  config SIRF_IRQ
>> diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
>> index 0007a6e..bfe360c 100644
>> --- a/arch/arm/mach-prima2/Makefile
>> +++ b/arch/arm/mach-prima2/Makefile
>> @@ -5,4 +5,7 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o
>>  obj-$(CONFIG_CACHE_L2X0) += l2x0.o
>>  obj-$(CONFIG_SUSPEND) += pm.o sleep.o
>>  obj-$(CONFIG_SIRF_IRQ) += irq.o
>> +obj-$(CONFIG_SMP) += platsmp.o headsmp.o
>> +obj-$(CONFIG_HOTPLUG_CPU)  += hotplug.o
>>  obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
>> +obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
>> diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
>> index 99f9c7e..00a6564 100644
>> --- a/arch/arm/mach-prima2/common.c
>> +++ b/arch/arm/mach-prima2/common.c
>> @@ -8,9 +8,11 @@
>>
>>  #include <linux/init.h>
>>  #include <linux/kernel.h>
>> +#include <linux/of_irq.h>
>>  #include <asm/sizes.h>
>>  #include <asm/mach-types.h>
>>  #include <asm/mach/arch.h>
>> +#include <asm/hardware/gic.h>
>>  #include <linux/of.h>
>>  #include <linux/of_platform.h>
>>  #include "common.h"
>> @@ -30,6 +32,12 @@ void __init sirfsoc_init_late(void)
>>         sirfsoc_pm_init();
>>  }
>>
>> +static __init void sirfsoc_map_io(void)
>> +{
>> +       sirfsoc_map_lluart();
>> +       sirfsoc_map_scu();
>> +}
>> +
>>  #ifdef CONFIG_ARCH_PRIMA2
>>  static const char *prima2_dt_match[] __initdata = {
>>         "sirf,prima2",
>> @@ -38,7 +46,7 @@ static const char *prima2_dt_match[] __initdata = {
>>
>>  DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
>>         /* Maintainer: Barry Song <baohua.song@csr.com> */
>> -       .map_io         = sirfsoc_map_lluart,
>> +       .map_io         = sirfsoc_map_io,
>>         .init_irq       = sirfsoc_of_irq_init,
>>         .init_time      = sirfsoc_prima2_timer_init,
>>  #ifdef CONFIG_MULTI_IRQ_HANDLER
>> @@ -51,3 +59,33 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
>>         .restart        = sirfsoc_restart,
>>  MACHINE_END
>>  #endif
>> +
>> +#ifdef CONFIG_ARCH_MARCO
>> +static const struct of_device_id marco_irq_match[] __initconst = {
>> +       { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
>> +       { /* sentinel */ }
>> +};
>> +
>> +static void __init marco_init_irq(void)
>> +{
>> +       of_irq_init(marco_irq_match);
>> +}
>> +
>> +static const char *marco_dt_match[] __initdata = {
>> +       "sirf,marco",
>> +       NULL
>> +};
>> +
>> +DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)")
>> +       /* Maintainer: Barry Song <baohua.song@csr.com> */
>> +       .smp            = smp_ops(sirfsoc_smp_ops),
>> +       .map_io         = sirfsoc_map_io,
>> +       .init_irq       = marco_init_irq,
>> +       .init_time      = sirfsoc_marco_timer_init,
>> +       .handle_irq     = gic_handle_irq,
>> +       .init_machine   = sirfsoc_mach_init,
>> +       .init_late      = sirfsoc_init_late,
>> +       .dt_compat      = marco_dt_match,
>> +       .restart        = sirfsoc_restart,
>> +MACHINE_END
>> +#endif
>> diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
>> index a4f91a6..b7c26b6 100644
>> --- a/arch/arm/mach-prima2/common.h
>> +++ b/arch/arm/mach-prima2/common.h
>> @@ -14,6 +14,11 @@
>>  #include <asm/exception.h>
>>
>>  extern void sirfsoc_prima2_timer_init(void);
>> +extern void sirfsoc_marco_timer_init(void);
>> +
>> +extern struct smp_operations   sirfsoc_smp_ops;
>> +extern void sirfsoc_secondary_startup(void);
>> +extern void sirfsoc_cpu_die(unsigned int cpu);
>>
>>  extern void __init sirfsoc_of_irq_init(void);
>>  extern void __init sirfsoc_of_clk_init(void);
>> @@ -26,6 +31,12 @@ static inline void sirfsoc_map_lluart(void)  {}
>>  extern void __init sirfsoc_map_lluart(void);
>>  #endif
>>
>> +#ifndef CONFIG_SMP
>> +static inline void sirfsoc_map_scu(void) {}
>> +#else
>> +extern void sirfsoc_map_scu(void);
>> +#endif
>> +
>>  #ifdef CONFIG_SUSPEND
>>  extern int sirfsoc_pm_init(void);
>>  #else
>> diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S
>> new file mode 100644
>> index 0000000..6ec19d5
>> --- /dev/null
>> +++ b/arch/arm/mach-prima2/headsmp.S
>> @@ -0,0 +1,79 @@
>> +/*
>> + * Entry of the second core for CSR Marco dual-core SMP SoCs
>> + *
>> + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *
>> + * Licensed under GPLv2 or later.
>> + */
>> +
>> +#include <linux/linkage.h>
>> +#include <linux/init.h>
>> +
>> +       __INIT
>> +/*
>> + * Cold boot and hardware reset show different behaviour,
>> + * system will be always panic if we warm-reset the board
>> + * Here we invalidate L1 of CPU1 to make sure there isn't
>> + * uninitialized data written into memory later
>> + */
>> +ENTRY(v7_invalidate_l1)
>> +       mov     r0, #0
>> +       mcr     p15, 0, r0, c7, c5, 0   @ invalidate I cache
>> +       mcr     p15, 2, r0, c0, c0, 0
>> +       mrc     p15, 1, r0, c0, c0, 0
>> +
>> +       ldr     r1, =0x7fff
>> +       and     r2, r1, r0, lsr #13
>> +
>> +       ldr     r1, =0x3ff
>> +
>> +       and     r3, r1, r0, lsr #3      @ NumWays - 1
>> +       add     r2, r2, #1              @ NumSets
>> +
>> +       and     r0, r0, #0x7
>> +       add     r0, r0, #4      @ SetShift
>> +
>> +       clz     r1, r3          @ WayShift
>> +       add     r4, r3, #1      @ NumWays
>> +1:     sub     r2, r2, #1      @ NumSets--
>> +       mov     r3, r4          @ Temp = NumWays
>> +2:     subs    r3, r3, #1      @ Temp--
>> +       mov     r5, r3, lsl r1
>> +       mov     r6, r2, lsl r0
>> +       orr     r5, r5, r6      @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
>> +       mcr     p15, 0, r5, c7, c6, 2
>> +       bgt     2b
>> +       cmp     r2, #0
>> +       bgt     1b
>> +       dsb
>> +       isb
>> +       mov     pc, lr
>> +ENDPROC(v7_invalidate_l1)
>> +
>> +/*
>> + * SIRFSOC specific entry point for secondary CPUs.  This provides
>> + * a "holding pen" into which all secondary cores are held until we're
>> + * ready for them to initialise.
>> + */
>> +ENTRY(sirfsoc_secondary_startup)
>> +       bl v7_invalidate_l1
>> +        mrc     p15, 0, r0, c0, c0, 5
>> +        and     r0, r0, #15
>> +        adr     r4, 1f
>> +        ldmia   r4, {r5, r6}
>> +        sub     r4, r4, r5
>> +        add     r6, r6, r4
>> +pen:    ldr     r7, [r6]
>> +        cmp     r7, r0
>> +        bne     pen
>> +
>> +        /*
>> +         * we've been released from the holding pen: secondary_stack
>> +         * should now contain the SVC stack for this core
>> +         */
>> +        b       secondary_startup
>> +ENDPROC(sirfsoc_secondary_startup)
>> +
>> +        .align
>> +1:      .long   .
>> +        .long   pen_release
>> diff --git a/arch/arm/mach-prima2/hotplug.c b/arch/arm/mach-prima2/hotplug.c
>> new file mode 100644
>> index 0000000..97c1ee5
>> --- /dev/null
>> +++ b/arch/arm/mach-prima2/hotplug.c
>> @@ -0,0 +1,41 @@
>> +/*
>> + * CPU hotplug support for CSR Marco dual-core SMP SoCs
>> + *
>> + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *
>> + * Licensed under GPLv2 or later.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/errno.h>
>> +#include <linux/smp.h>
>> +
>> +#include <asm/cacheflush.h>
>> +#include <asm/smp_plat.h>
>> +
>> +static inline void platform_do_lowpower(unsigned int cpu)
>> +{
>> +       flush_cache_all();
>> +
>> +       /* we put the platform to just WFI */
>> +       for (;;) {
>> +               __asm__ __volatile__("dsb\n\t" "wfi\n\t"
>> +                       : : : "memory");
>> +               if (pen_release == cpu_logical_map(cpu)) {
>> +                       /*
>> +                        * OK, proper wakeup, we're done
>> +                        */
>> +                       break;
>> +               }
>> +       }
>> +}
>> +
>> +/*
>> + * platform-specific code to shutdown a CPU
>> + *
>> + * Called with IRQs disabled
>> + */
>> +void sirfsoc_cpu_die(unsigned int cpu)
>> +{
>> +       platform_do_lowpower(cpu);
>> +}
>> diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c
>> new file mode 100644
>> index 0000000..b939e9b4
>> --- /dev/null
>> +++ b/arch/arm/mach-prima2/platsmp.c
>> @@ -0,0 +1,170 @@
>> +/*
>> + * plat smp support for CSR Marco dual-core SMP SoCs
>> + *
>> + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *
>> + * Licensed under GPLv2 or later.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/smp.h>
>> +#include <linux/delay.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <asm/page.h>
>> +#include <asm/mach/map.h>
>> +#include <asm/smp_plat.h>
>> +#include <asm/smp_scu.h>
>> +#include <asm/cacheflush.h>
>> +#include <asm/cputype.h>
>> +#include <asm/hardware/gic.h>
>> +#include <mach/map.h>
>> +
>> +#include "common.h"
>> +
>> +static void __iomem *scu_base;
>> +static void __iomem *rsc_base;
>> +
>> +static DEFINE_SPINLOCK(boot_lock);
>> +
>> +static struct map_desc scu_io_desc __initdata = {
>> +       .length         = SZ_4K,
>> +       .type           = MT_DEVICE,
>> +};
>> +
>> +void __init sirfsoc_map_scu(void)
>> +{
>> +       unsigned long base;
>> +
>> +       /* Get SCU base */
>> +       asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
>> +
>> +       scu_io_desc.virtual = SIRFSOC_VA(base);
>> +       scu_io_desc.pfn = __phys_to_pfn(base);
>> +       iotable_init(&scu_io_desc, 1);
>> +
>> +       scu_base = (void __iomem *)SIRFSOC_VA(base);
>> +}
>> +
>> +static void __cpuinit sirfsoc_secondary_init(unsigned int cpu)
>> +{
>> +       /*
>> +        * if any interrupts are already enabled for the primary
>> +        * core (e.g. timer irq), then they will not have been enabled
>> +        * for us: do so
>> +        */
>> +       gic_secondary_init(0);
>> +
>> +       /*
>> +        * let the primary processor know we're out of the
>> +        * pen, then head off into the C entry point
>> +        */
>> +       pen_release = -1;
>> +       smp_wmb();
>> +
>> +       /*
>> +        * Synchronise with the boot thread.
>> +        */
>> +       spin_lock(&boot_lock);
>> +       spin_unlock(&boot_lock);
>> +}
>> +
>> +static struct of_device_id rsc_ids[]  = {
>> +       { .compatible = "sirf,marco-rsc" },
>> +       {},
>> +};
>> +
>> +static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
>> +{
>> +       unsigned long timeout;
>> +       struct device_node *np;
>> +
>> +       np = of_find_matching_node(NULL, rsc_ids);
>> +       if (!np)
>> +               return -ENODEV;
>> +
>> +       rsc_base = of_iomap(np, 0);
>> +       if (!rsc_base)
>> +               return -ENOMEM;
>> +
>> +       /*
>> +        * write the address of secondary startup into the sram register
>> +        * at offset 0x2C, then write the magic number 0x3CAF5D62 to the
>> +        * RSC register at offset 0x28, which is what boot rom code is
>> +        * waiting for. This would wake up the secondary core from WFE
>> +        */
>> +#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C
>> +       __raw_writel(virt_to_phys(sirfsoc_secondary_startup),
>> +               rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
>> +
>> +#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28
>> +       __raw_writel(0x3CAF5D62,
>> +               rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
>> +
>> +       /* make sure write buffer is drained */
>> +       mb();
>> +
>> +       spin_lock(&boot_lock);
>> +
>> +       /*
>> +        * The secondary processor is waiting to be released from
>> +        * the holding pen - release it, then wait for it to flag
>> +        * that it has been released by resetting pen_release.
>> +        *
>> +        * Note that "pen_release" is the hardware CPU ID, whereas
>> +        * "cpu" is Linux's internal ID.
>> +        */
>> +       pen_release = cpu_logical_map(cpu);
>> +       __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
>> +       outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
>> +
>> +       /*
>> +        * Send the secondary CPU SEV, thereby causing the boot monitor to read
>> +        * the JUMPADDR and WAKEMAGIC, and branch to the address found there.
>> +        */
>> +       dsb_sev();
>> +
>> +       timeout = jiffies + (1 * HZ);
>> +       while (time_before(jiffies, timeout)) {
>> +               smp_rmb();
>> +               if (pen_release == -1)
>> +                       break;
>> +
>> +               udelay(10);
>> +       }
>> +
>> +       /*
>> +        * now the secondary core is starting up let it run its
>> +        * calibrations, then wait for it to finish
>> +        */
>> +       spin_unlock(&boot_lock);
>> +
>> +       return pen_release != -1 ? -ENOSYS : 0;
>> +}
>> +
>> +static void __init sirfsoc_smp_init_cpus(void)
>> +{
>> +       int i, ncores;
>> +
>> +       ncores = scu_get_core_count(scu_base);
>> +
>> +       for (i = 0; i < ncores; i++)
>> +               set_cpu_possible(i, true);
>> +
>> +       set_smp_cross_call(gic_raise_softirq);
>> +}
>
> You don't need to use scu_get_core_count to figure out which cpus to set
> possible. It duplicates work already done by arm_dt_init_cpu_maps, and doesn't
> initialise the logical map (as arm_dt_init_cpu_maps does).
>
> You're already relying on the arm_dt_init_cpu_maps to set up the logical map
> for the holding pen release, so you may as well rely on it to set_cpu_possible
> for each of the cpus described in the dt.
>
> Tegra is already on its way to doing this:
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-December/138319.html
> http://lists.infradead.org/pipermail/linux-arm-kernel/2013-January/140219.html
> http://lists.infradead.org/pipermail/linux-arm-kernel/2013-January/141596.html
>
what if there are 4 nodes in dts but there are actually only one core
in soc? for example, using qemu to run vexpress without --smp=4?
SiRFmarco will have 2 versions, one is UP, the other one is dual core.
if using dt, i might need to take cpus node out of marco.dtsi

>> +
>> +static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus)
>> +{
>> +       scu_enable(scu_base);
>> +}
>> +
>> +struct smp_operations sirfsoc_smp_ops __initdata = {
>> +        .smp_init_cpus          = sirfsoc_smp_init_cpus,
>> +        .smp_prepare_cpus       = sirfsoc_smp_prepare_cpus,
>> +        .smp_secondary_init     = sirfsoc_secondary_init,
>> +        .smp_boot_secondary     = sirfsoc_boot_secondary,
>> +#ifdef CONFIG_HOTPLUG_CPU
>> +       .cpu_die                = sirfsoc_cpu_die,
>> +#endif
>> +};
>
> The timer below is a big chunk of code, it'd be nicer if it had a patch to
> itself.
ok.

>
>> diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c
>> new file mode 100644
>> index 0000000..07b3a6b
>> --- /dev/null
>> +++ b/arch/arm/mach-prima2/timer-marco.c
>> @@ -0,0 +1,355 @@
>> +/*
>> + * System timer for CSR SiRFprimaII
>> + *
>> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *
>> + * Licensed under GPLv2 or later.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/clockchips.h>
>> +#include <linux/clocksource.h>
>> +#include <linux/bitops.h>
>> +#include <linux/irq.h>
>> +#include <linux/clk.h>
>> +#include <linux/slab.h>
>> +#include <linux/of.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of_address.h>
>> +#include <asm/sched_clock.h>
>> +#include <asm/localtimer.h>
>> +#include <asm/mach/time.h>
>> +
>> +#include "common.h"
>> +
>> +#define SIRFSOC_TIMER_32COUNTER_0_CTRL                 0x0000
>> +#define SIRFSOC_TIMER_32COUNTER_1_CTRL                 0x0004
>> +#define SIRFSOC_TIMER_MATCH_0                          0x0018
>> +#define SIRFSOC_TIMER_MATCH_1                          0x001c
>> +#define SIRFSOC_TIMER_COUNTER_0                                0x0048
>> +#define SIRFSOC_TIMER_COUNTER_1                                0x004c
>> +#define SIRFSOC_TIMER_INTR_STATUS                      0x0060
>> +#define SIRFSOC_TIMER_WATCHDOG_EN                      0x0064
>> +#define SIRFSOC_TIMER_64COUNTER_CTRL                   0x0068
>> +#define SIRFSOC_TIMER_64COUNTER_LO                     0x006c
>> +#define SIRFSOC_TIMER_64COUNTER_HI                     0x0070
>> +#define SIRFSOC_TIMER_64COUNTER_LOAD_LO                        0x0074
>> +#define SIRFSOC_TIMER_64COUNTER_LOAD_HI                        0x0078
>> +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO            0x007c
>> +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI            0x0080
>> +
>> +#define SIRFSOC_TIMER_REG_CNT 6
>> +
>> +static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
>> +       SIRFSOC_TIMER_WATCHDOG_EN,
>> +       SIRFSOC_TIMER_32COUNTER_0_CTRL,
>> +       SIRFSOC_TIMER_32COUNTER_1_CTRL,
>> +       SIRFSOC_TIMER_64COUNTER_CTRL,
>> +       SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
>> +       SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
>> +};
>> +
>> +static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
>> +
>> +static void __iomem *sirfsoc_timer_base;
>> +static void __init sirfsoc_of_timer_map(void);
>> +
>> +/* disable count and interrupt */
>> +static inline void sirfsoc_timer_count_disable(int idx)
>> +{
>> +       writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
>> +               sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
>> +}
>> +
>> +/* enable count and interrupt */
>> +static inline void sirfsoc_timer_count_enable(int idx)
>> +{
>> +       writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x7,
>> +               sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
>> +}
>> +
>> +/* timer0 interrupt handler */
>> +static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
>> +{
>> +       struct clock_event_device *ce = dev_id;
>> +
>> +       /* clear timer0 interrupt */
>> +       writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
>> +
>> +       if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
>> +               sirfsoc_timer_count_disable(0);
>> +
>> +       ce->event_handler(ce);
>> +
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +/* read 64-bit timer counter */
>> +static cycle_t sirfsoc_timer_read(struct clocksource *cs)
>> +{
>> +       u64 cycles;
>> +
>> +       writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
>> +                       BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
>> +
>> +       cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
>> +       cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
>> +
>> +       return cycles;
>> +}
>> +
>> +static int sirfsoc_timer_set_next_event(unsigned long delta,
>> +       struct clock_event_device *ce)
>> +{
>> +
>> +       writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
>> +       writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
>> +
>> +       /* enable the tick */
>> +       sirfsoc_timer_count_enable(0);
>> +
>> +       return 0;
>> +}
>> +
>> +static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
>> +       struct clock_event_device *ce)
>> +{
>> +       switch (mode) {
>> +       case CLOCK_EVT_MODE_ONESHOT:
>> +               /* enable in set_next_event */
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +
>> +       sirfsoc_timer_count_disable(0);
>> +}
>> +
>> +static void sirfsoc_clocksource_suspend(struct clocksource *cs)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
>> +               sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
>> +}
>> +
>> +static void sirfsoc_clocksource_resume(struct clocksource *cs)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
>> +               writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
>> +
>> +       writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
>> +               sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
>> +       writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
>> +               sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
>> +
>> +       writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
>> +               BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
>> +}
>> +
>> +static struct clock_event_device sirfsoc_clockevent = {
>> +       .name = "sirfsoc_clockevent",
>> +       .rating = 200,
>> +       .features = CLOCK_EVT_FEAT_ONESHOT,
>> +       .set_mode = sirfsoc_timer_set_mode,
>> +       .set_next_event = sirfsoc_timer_set_next_event,
>> +};
>> +
>> +static struct clocksource sirfsoc_clocksource = {
>> +       .name = "sirfsoc_clocksource",
>> +       .rating = 200,
>> +       .mask = CLOCKSOURCE_MASK(64),
>> +       .flags = CLOCK_SOURCE_IS_CONTINUOUS,
>> +       .read = sirfsoc_timer_read,
>> +       .suspend = sirfsoc_clocksource_suspend,
>> +       .resume = sirfsoc_clocksource_resume,
>> +};
>> +
>> +static struct irqaction sirfsoc_timer_irq = {
>> +       .name = "sirfsoc_timer0",
>> +       .flags = IRQF_TIMER | IRQF_NOBALANCING,
>> +       .handler = sirfsoc_timer_interrupt,
>> +       .dev_id = &sirfsoc_clockevent,
>> +};
>> +
>> +#ifdef CONFIG_LOCAL_TIMERS
>> +
>> +/* timer1 interrupt handler */
>> +static irqreturn_t sirfsoc_timer1_interrupt(int irq, void *dev_id)
>> +{
>> +       struct clock_event_device *ce = dev_id;
>> +
>> +       /* clear timer1 interrupt */
>> +       writel_relaxed(BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
>> +
>> +       if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
>> +               sirfsoc_timer_count_disable(1);
>> +
>> +       ce->event_handler(ce);
>> +
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static struct irqaction sirfsoc_timer1_irq = {
>> +       .name = "sirfsoc_timer1",
>> +       .flags = IRQF_TIMER | IRQF_NOBALANCING,
>> +       .handler = sirfsoc_timer1_interrupt,
>> +};
>> +
>> +static int sirfsoc_timer1_set_next_event(unsigned long delta,
>> +       struct clock_event_device *ce)
>> +{
>> +       writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
>> +       writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_1);
>> +
>> +       /* enable the tick */
>> +       sirfsoc_timer_count_enable(1);
>> +
>> +       return 0;
>> +}
>> +
>> +static void sirfsoc_timer1_set_mode(enum clock_event_mode mode,
>> +       struct clock_event_device *ce)
>> +{
>> +       switch (mode) {
>> +       case CLOCK_EVT_MODE_ONESHOT:
>> +               /* enable in set_next_event */
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +
>> +       sirfsoc_timer_count_disable(1);
>> +}
>> +
>> +static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce)
>> +{
>> +       /* Use existing clock_event for cpu 0 */
>> +       if (!smp_processor_id())
>> +               return 0;
>
> This seems a little scary. Does the timer only exist for 1 core, or is it not
> actually a local timer?

there are multiple timers, everyone can be avaliable to all cores.
here we actually use timer0 as cpu0's tick, timer1 as cpu1's tick.
each one uses a seperate timers.

>
>> +
>> +       ce->irq = sirfsoc_timer1_irq.irq;
>> +       ce->name = "local_timer";
>> +       ce->features = sirfsoc_clockevent.features;
>> +       ce->rating = sirfsoc_clockevent.rating;
>> +       ce->cpumask = cpumask_of(1);
>
> The local_timer api sets the cpumask, and you've already rejected setups from
> cpu0, so this isn't technically necessary.

right.
>
>> +       ce->set_mode = sirfsoc_timer1_set_mode;
>> +       ce->set_next_event = sirfsoc_timer1_set_next_event;
>> +       ce->shift = sirfsoc_clockevent.shift;
>> +       ce->mult = sirfsoc_clockevent.mult;
>> +       ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns;
>> +       ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns;
>> +
>> +       sirfsoc_timer1_irq.dev_id = ce;
>> +       BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq));
>> +       irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1));
>> +
>> +       clockevents_register_device(ce);
>> +       return 0;
>> +}
>> +
>> +static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
>> +{
>> +       sirfsoc_timer_count_disable(1);
>> +
>> +       remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
>> +}
>
> Presumably you need to balance what you've done in sirfsoc_local_timer_setup,
> and return early for cpu0.
>
>> +
>> +static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = {
>> +       .setup  = sirfsoc_local_timer_setup,
>> +       .stop   = sirfsoc_local_timer_stop,
>> +};
>> +#endif /* CONFIG_LOCAL_TIMERS */
>> +
>> +static void __init sirfsoc_clockevent_init(void)
>> +{
>> +       clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
>> +
>> +       sirfsoc_clockevent.max_delta_ns =
>> +               clockevent_delta2ns(-2, &sirfsoc_clockevent);
>
> I assume this is a typo. For one thing, clockevent_delta2ns takes an unsigned
> long.

grep and get:
http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git&a=search&h=HEAD&st=grep&s=clockevent_delta2ns
almost all platforms don't really take it seriously if we think -2 is
very big unsigned long and number like 0xfffffffe is almost not
unsigned long without UL.

>
>> +       sirfsoc_clockevent.min_delta_ns =
>> +               clockevent_delta2ns(2, &sirfsoc_clockevent);
>> +
>> +       sirfsoc_clockevent.cpumask = cpumask_of(0);
>> +       clockevents_register_device(&sirfsoc_clockevent);
>> +#ifdef CONFIG_LOCAL_TIMERS
>> +       local_timer_register(&sirfsoc_local_timer_ops);
>> +#endif
>> +}
>> +
>> +/* initialize the kernel jiffy timer source */
>> +void __init sirfsoc_marco_timer_init(void)
>> +{
>> +       unsigned long rate;
>> +       u32 timer_div;
>> +       struct clk *clk;
>> +
>> +       /* initialize clocking early, we want to set the OS timer */
>> +       sirfsoc_of_clk_init();
>> +
>> +       /* timer's input clock is io clock */
>> +       clk = clk_get_sys("io", NULL);
>> +
>> +       BUG_ON(IS_ERR(clk));
>> +       rate = clk_get_rate(clk);
>> +
>> +       BUG_ON(rate < CLOCK_TICK_RATE);
>> +       BUG_ON(rate % CLOCK_TICK_RATE);
>> +
>> +       sirfsoc_of_timer_map();
>> +
>> +       /* Initialize the timer dividers */
>> +       timer_div = rate / CLOCK_TICK_RATE / 2 - 1;
>> +       writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
>> +       writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
>> +       writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
>> +
>> +       /* Initialize timer counters to 0 */
>> +       writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
>> +       writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
>> +       writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
>> +               BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
>> +       writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
>> +       writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
>> +
>> +       /* Clear all interrupts */
>> +       writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
>> +
>> +       BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
>> +
>> +       BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
>> +
>> +       sirfsoc_clockevent_init();
>> +}
>> +
>> +static struct of_device_id timer_ids[] = {
>> +       { .compatible = "sirf,marco-tick" },
>> +       {},
>> +};
>> +
>> +static void __init sirfsoc_of_timer_map(void)
>> +{
>> +       struct device_node *np;
>> +
>> +       np = of_find_matching_node(NULL, timer_ids);
>> +       if (!np)
>> +               return;
>> +       sirfsoc_timer_base = of_iomap(np, 0);
>> +       if (!sirfsoc_timer_base)
>> +               panic("unable to map timer cpu registers\n");
>> +
>> +       sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
>> +       if (!sirfsoc_timer_irq.irq)
>> +               panic("No irq passed for timer0 via DT\n");
>> +
>> +#ifdef CONFIG_LOCAL_TIMERS
>> +       sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
>> +       if (!sirfsoc_timer1_irq.irq)
>> +               panic("No irq passed for timer1 via DT\n");
>> +#endif
>> +
>> +       of_node_put(np);
>> +}
>> --
>> 1.7.5.4

> Thanks,
> Mark.

-barry

^ permalink raw reply

* [PATCH v3 9/9] ARM: S3C24XX: transform s3c2443 subirqs into new structure
From: Heiko Stübner @ 2013-01-19  3:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301190403.50317.heiko@sntech.de>

Share the common irq code by simply defining a correct mapping declaration
for the s3c2443.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-s3c24xx/irq.c |  289 +++++++++++--------------------------------
 1 files changed, 75 insertions(+), 214 deletions(-)

diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 4cf3c13..969426b 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -732,230 +732,91 @@ void __init s3c2416_init_irq(void)
 #endif
 
 #ifdef CONFIG_CPU_S3C2443
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
-{
-	unsigned int subsrc, submsk;
-	unsigned int end;
-
-	/* read the current pending interrupts, and the mask
-	 * for what it is available */
-
-	subsrc = __raw_readl(S3C2410_SUBSRCPND);
-	submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-	subsrc  &= ~submsk;
-	subsrc >>= (irq - S3C2410_IRQSUB(0));
-	subsrc  &= (1 << len)-1;
-
-	end = len + irq;
-
-	for (; irq < end && subsrc; irq++) {
-		if (subsrc & 1)
-			generic_handle_irq(irq);
-
-		subsrc >>= 1;
-	}
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97	(1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97	INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2443_irq_wdtac97 = {
-	.irq_mask	= s3c2443_irq_wdtac97_mask,
-	.irq_unmask	= s3c2443_irq_wdtac97_unmask,
-	.irq_ack	= s3c2443_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD	(1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD	INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2443_irq_lcd_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2443_irq_lcd = {
-	.irq_mask	= s3c2443_irq_lcd_mask,
-	.irq_unmask	= s3c2443_irq_lcd_unmask,
-	.irq_ack	= s3c2443_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA	(1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA	INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-static void s3c2443_irq_dma_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2443_irq_dma_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2443_irq_dma_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2443_irq_dma = {
-	.irq_mask	= s3c2443_irq_dma_mask,
-	.irq_unmask	= s3c2443_irq_dma_unmask,
-	.irq_ack	= s3c2443_irq_dma_ack,
-};
-
-/* UART3 sub interrupts */
-
-static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2443_irq_uart3_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2443_irq_uart3 = {
-	.irq_mask	= s3c2443_irq_uart3_mask,
-	.irq_unmask	= s3c2443_irq_uart3_unmask,
-	.irq_ack	= s3c2443_irq_uart3_ack,
+static struct s3c_irq_data init_s3c2443base[32] = {
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* CFON */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* NAND */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
 };
 
-/* CAM sub interrupts */
 
-static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
-}
-
-#define INTMSK_CAM	(1UL << (IRQ_CAM - IRQ_EINT0))
-#define SUBMSK_CAM	INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
-
-static void s3c2443_irq_cam_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static void s3c2443_irq_cam_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_CAM);
-}
-
-static void s3c2443_irq_cam_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static struct irq_chip s3c2443_irq_cam = {
-	.irq_mask	= s3c2443_irq_cam_mask,
-	.irq_unmask	= s3c2443_irq_cam_unmask,
-	.irq_ack	= s3c2443_irq_cam_ack,
+static struct s3c_irq_data init_s3c2443subint[32] = {
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+	{ .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+	{ .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
+	{ .type = S3C_IRQTYPE_NONE }, /* reserved */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
 };
 
-/* IRQ initialisation code */
-
-static int s3c2443_add_sub(unsigned int base,
-				   void (*demux)(unsigned int,
-						 struct irq_desc *),
-				   struct irq_chip *chip,
-				   unsigned int start, unsigned int end)
-{
-	unsigned int irqno;
-
-	irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
-	irq_set_chained_handler(base, demux);
-
-	for (irqno = start; irqno <= end; irqno++) {
-		irq_set_chip_and_handler(irqno, chip, handle_level_irq);
-		set_irq_flags(irqno, IRQF_VALID);
-	}
-
-	return 0;
-}
-
 void __init s3c2443_init_irq(void)
 {
-	pr_info("S3C2443: IRQ Support\n");
-
-	s3c24xx_init_irq();
-
-	s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
-			IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
+	struct s3c_irq_intc *main_intc;
 
-	s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
-			IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
+	pr_info("S3C2443: IRQ Support\n");
 
-	s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
-			&s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
+#ifdef CONFIG_FIQ
+	init_FIQ(FIQ_START);
+#endif
 
-	s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
-			&s3c2443_irq_uart3,
-			IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
+	main_intc = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, 0x4a000000);
+	if (IS_ERR(main_intc)) {
+		pr_err("irq: could not create main interrupt controller\n");
+		return;
+	}
 
-	s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
-			&s3c2443_irq_wdtac97,
-			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
+	s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
+	s3c24xx_init_intc(NULL, &init_s3c2443subint[0], main_intc, 0x4a000018);
 }
 #endif
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v3 8/9] ARM: S3C24XX: modify s3c2443 irq init to initialize all irqs
From: Heiko Stübner @ 2013-01-19  3:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301190403.50317.heiko@sntech.de>

Previously the irq init used s3c24xx_init_irq and an additional
arch_initcall to add the cpu specific irqs.

To be able to simplyfy the irq init later, create a new function
s3c2443_init_irq, which then calls s3c24xx_init_irq but also adds
the cpu specific irqs.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-s3c24xx/mach-smdk2443.c        |    2 +-
 arch/arm/plat-s3c24xx/irq.c                  |   22 ++++------------------
 arch/arm/plat-samsung/include/plat/s3c2443.h |    2 ++
 3 files changed, 7 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c
index c6d1a03..8b65a54 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2443.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2443.c
@@ -140,7 +140,7 @@ MACHINE_START(SMDK2443, "SMDK2443")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
 	.atag_offset	= 0x100,
 
-	.init_irq	= s3c24xx_init_irq,
+	.init_irq	= s3c2443_init_irq,
 	.map_io		= smdk2443_map_io,
 	.init_machine	= smdk2443_machine_init,
 	.timer		= &s3c24xx_timer,
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 0a051eb..4cf3c13 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -935,10 +935,11 @@ static int s3c2443_add_sub(unsigned int base,
 	return 0;
 }
 
-static int s3c2443_irq_add(struct device *dev,
-				  struct subsys_interface *sif)
+void __init s3c2443_init_irq(void)
 {
-	printk("S3C2443: IRQ Support\n");
+	pr_info("S3C2443: IRQ Support\n");
+
+	s3c24xx_init_irq();
 
 	s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
 			IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
@@ -956,20 +957,5 @@ static int s3c2443_irq_add(struct device *dev,
 	s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
 			&s3c2443_irq_wdtac97,
 			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
-
-	return 0;
 }
-
-static struct subsys_interface s3c2443_irq_interface = {
-	.name		= "s3c2443_irq",
-	.subsys		= &s3c2443_subsys,
-	.add_dev	= s3c2443_irq_add,
-};
-
-static int __init s3c2443_irq_init(void)
-{
-	return subsys_interface_register(&s3c2443_irq_interface);
-}
-
-arch_initcall(s3c2443_irq_init);
 #endif
diff --git a/arch/arm/plat-samsung/include/plat/s3c2443.h b/arch/arm/plat-samsung/include/plat/s3c2443.h
index a5b794f..71b88ec 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2443.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2443.h
@@ -25,6 +25,8 @@ extern void s3c2443_init_clocks(int xtal);
 extern  int s3c2443_baseclk_add(void);
 
 extern void s3c2443_restart(char mode, const char *cmd);
+
+extern void s3c2443_init_irq(void);
 #else
 #define s3c2443_init_clocks NULL
 #define s3c2443_init_uarts NULL
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v3 7/9] ARM: S3C24XX: move s3c2443 irq code to irq.c
From: Heiko Stübner @ 2013-01-19  3:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301190403.50317.heiko@sntech.de>

Prequisite for further optimizations.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-s3c24xx/Makefile      |    2 +-
 arch/arm/mach-s3c24xx/irq-s3c2443.c |  281 -----------------------------------
 arch/arm/plat-s3c24xx/irq.c         |  243 ++++++++++++++++++++++++++++++
 3 files changed, 244 insertions(+), 282 deletions(-)
 delete mode 100644 arch/arm/mach-s3c24xx/irq-s3c2443.c

diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
index 4d512cb..1072b63 100644
--- a/arch/arm/mach-s3c24xx/Makefile
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -33,7 +33,7 @@ obj-$(CONFIG_CPU_S3C2442)	+= s3c2442.o
 obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o irq-s3c244x.o clock-s3c244x.o
 obj-$(CONFIG_S3C2440_DMA)	+= dma-s3c2440.o
 
-obj-$(CONFIG_CPU_S3C2443)	+= s3c2443.o irq-s3c2443.o clock-s3c2443.o
+obj-$(CONFIG_CPU_S3C2443)	+= s3c2443.o clock-s3c2443.o
 
 # PM
 
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2443.c b/arch/arm/mach-s3c24xx/irq-s3c2443.c
deleted file mode 100644
index 5e69109..0000000
--- a/arch/arm/mach-s3c24xx/irq-s3c2443.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/irq.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
-{
-	unsigned int subsrc, submsk;
-	unsigned int end;
-
-	/* read the current pending interrupts, and the mask
-	 * for what it is available */
-
-	subsrc = __raw_readl(S3C2410_SUBSRCPND);
-	submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-	subsrc  &= ~submsk;
-	subsrc >>= (irq - S3C2410_IRQSUB(0));
-	subsrc  &= (1 << len)-1;
-
-	end = len + irq;
-
-	for (; irq < end && subsrc; irq++) {
-		if (subsrc & 1)
-			generic_handle_irq(irq);
-
-		subsrc >>= 1;
-	}
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97	(1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97	INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2443_irq_wdtac97 = {
-	.irq_mask	= s3c2443_irq_wdtac97_mask,
-	.irq_unmask	= s3c2443_irq_wdtac97_unmask,
-	.irq_ack	= s3c2443_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD	(1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD	INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2443_irq_lcd_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2443_irq_lcd = {
-	.irq_mask	= s3c2443_irq_lcd_mask,
-	.irq_unmask	= s3c2443_irq_lcd_unmask,
-	.irq_ack	= s3c2443_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA	(1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA	INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-static void s3c2443_irq_dma_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2443_irq_dma_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2443_irq_dma_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2443_irq_dma = {
-	.irq_mask	= s3c2443_irq_dma_mask,
-	.irq_unmask	= s3c2443_irq_dma_unmask,
-	.irq_ack	= s3c2443_irq_dma_ack,
-};
-
-/* UART3 sub interrupts */
-
-static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2443_irq_uart3_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2443_irq_uart3 = {
-	.irq_mask	= s3c2443_irq_uart3_mask,
-	.irq_unmask	= s3c2443_irq_uart3_unmask,
-	.irq_ack	= s3c2443_irq_uart3_ack,
-};
-
-/* CAM sub interrupts */
-
-static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
-}
-
-#define INTMSK_CAM	(1UL << (IRQ_CAM - IRQ_EINT0))
-#define SUBMSK_CAM	INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
-
-static void s3c2443_irq_cam_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static void s3c2443_irq_cam_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_CAM);
-}
-
-static void s3c2443_irq_cam_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static struct irq_chip s3c2443_irq_cam = {
-	.irq_mask	= s3c2443_irq_cam_mask,
-	.irq_unmask	= s3c2443_irq_cam_unmask,
-	.irq_ack	= s3c2443_irq_cam_ack,
-};
-
-/* IRQ initialisation code */
-
-static int s3c2443_add_sub(unsigned int base,
-				   void (*demux)(unsigned int,
-						 struct irq_desc *),
-				   struct irq_chip *chip,
-				   unsigned int start, unsigned int end)
-{
-	unsigned int irqno;
-
-	irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
-	irq_set_chained_handler(base, demux);
-
-	for (irqno = start; irqno <= end; irqno++) {
-		irq_set_chip_and_handler(irqno, chip, handle_level_irq);
-		set_irq_flags(irqno, IRQF_VALID);
-	}
-
-	return 0;
-}
-
-static int s3c2443_irq_add(struct device *dev,
-				  struct subsys_interface *sif)
-{
-	printk("S3C2443: IRQ Support\n");
-
-	s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
-			IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
-
-	s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
-			IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
-
-	s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
-			&s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
-
-	s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
-			&s3c2443_irq_uart3,
-			IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
-
-	s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
-			&s3c2443_irq_wdtac97,
-			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
-
-	return 0;
-}
-
-static struct subsys_interface s3c2443_irq_interface = {
-	.name		= "s3c2443_irq",
-	.subsys		= &s3c2443_subsys,
-	.add_dev	= s3c2443_irq_add,
-};
-
-static int __init s3c2443_irq_init(void)
-{
-	return subsys_interface_register(&s3c2443_irq_interface);
-}
-
-arch_initcall(s3c2443_irq_init);
-
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index c6d0d57..0a051eb 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -730,3 +730,246 @@ void __init s3c2416_init_irq(void)
 }
 
 #endif
+
+#ifdef CONFIG_CPU_S3C2443
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+
+static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
+{
+	unsigned int subsrc, submsk;
+	unsigned int end;
+
+	/* read the current pending interrupts, and the mask
+	 * for what it is available */
+
+	subsrc = __raw_readl(S3C2410_SUBSRCPND);
+	submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+	subsrc  &= ~submsk;
+	subsrc >>= (irq - S3C2410_IRQSUB(0));
+	subsrc  &= (1 << len)-1;
+
+	end = len + irq;
+
+	for (; irq < end && subsrc; irq++) {
+		if (subsrc & 1)
+			generic_handle_irq(irq);
+
+		subsrc >>= 1;
+	}
+}
+
+/* WDT/AC97 sub interrupts */
+
+static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
+}
+
+#define INTMSK_WDTAC97	(1UL << (IRQ_WDT - IRQ_EINT0))
+#define SUBMSK_WDTAC97	INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
+
+static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
+}
+
+static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static struct irq_chip s3c2443_irq_wdtac97 = {
+	.irq_mask	= s3c2443_irq_wdtac97_mask,
+	.irq_unmask	= s3c2443_irq_wdtac97_unmask,
+	.irq_ack	= s3c2443_irq_wdtac97_ack,
+};
+
+/* LCD sub interrupts */
+
+static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
+}
+
+#define INTMSK_LCD	(1UL << (IRQ_LCD - IRQ_EINT0))
+#define SUBMSK_LCD	INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
+
+static void s3c2443_irq_lcd_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static void s3c2443_irq_lcd_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_LCD);
+}
+
+static void s3c2443_irq_lcd_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static struct irq_chip s3c2443_irq_lcd = {
+	.irq_mask	= s3c2443_irq_lcd_mask,
+	.irq_unmask	= s3c2443_irq_lcd_unmask,
+	.irq_ack	= s3c2443_irq_lcd_ack,
+};
+
+/* DMA sub interrupts */
+
+static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6);
+}
+
+#define INTMSK_DMA	(1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
+#define SUBMSK_DMA	INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
+
+static void s3c2443_irq_dma_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static void s3c2443_irq_dma_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_DMA);
+}
+
+static void s3c2443_irq_dma_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static struct irq_chip s3c2443_irq_dma = {
+	.irq_mask	= s3c2443_irq_dma_mask,
+	.irq_unmask	= s3c2443_irq_dma_unmask,
+	.irq_ack	= s3c2443_irq_dma_ack,
+};
+
+/* UART3 sub interrupts */
+
+static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
+}
+
+#define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
+#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
+
+static void s3c2443_irq_uart3_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static void s3c2443_irq_uart3_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_UART3);
+}
+
+static void s3c2443_irq_uart3_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static struct irq_chip s3c2443_irq_uart3 = {
+	.irq_mask	= s3c2443_irq_uart3_mask,
+	.irq_unmask	= s3c2443_irq_uart3_unmask,
+	.irq_ack	= s3c2443_irq_uart3_ack,
+};
+
+/* CAM sub interrupts */
+
+static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
+}
+
+#define INTMSK_CAM	(1UL << (IRQ_CAM - IRQ_EINT0))
+#define SUBMSK_CAM	INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
+
+static void s3c2443_irq_cam_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
+}
+
+static void s3c2443_irq_cam_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_CAM);
+}
+
+static void s3c2443_irq_cam_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
+}
+
+static struct irq_chip s3c2443_irq_cam = {
+	.irq_mask	= s3c2443_irq_cam_mask,
+	.irq_unmask	= s3c2443_irq_cam_unmask,
+	.irq_ack	= s3c2443_irq_cam_ack,
+};
+
+/* IRQ initialisation code */
+
+static int s3c2443_add_sub(unsigned int base,
+				   void (*demux)(unsigned int,
+						 struct irq_desc *),
+				   struct irq_chip *chip,
+				   unsigned int start, unsigned int end)
+{
+	unsigned int irqno;
+
+	irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
+	irq_set_chained_handler(base, demux);
+
+	for (irqno = start; irqno <= end; irqno++) {
+		irq_set_chip_and_handler(irqno, chip, handle_level_irq);
+		set_irq_flags(irqno, IRQF_VALID);
+	}
+
+	return 0;
+}
+
+static int s3c2443_irq_add(struct device *dev,
+				  struct subsys_interface *sif)
+{
+	printk("S3C2443: IRQ Support\n");
+
+	s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
+			IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
+
+	s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
+			IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
+
+	s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
+			&s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
+
+	s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
+			&s3c2443_irq_uart3,
+			IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
+
+	s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
+			&s3c2443_irq_wdtac97,
+			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
+
+	return 0;
+}
+
+static struct subsys_interface s3c2443_irq_interface = {
+	.name		= "s3c2443_irq",
+	.subsys		= &s3c2443_subsys,
+	.add_dev	= s3c2443_irq_add,
+};
+
+static int __init s3c2443_irq_init(void)
+{
+	return subsys_interface_register(&s3c2443_irq_interface);
+}
+
+arch_initcall(s3c2443_irq_init);
+#endif
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v3 6/9] ARM: S3C24XX: transform s3c2416 irqs into new structure
From: Heiko Stübner @ 2013-01-19  3:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301190403.50317.heiko@sntech.de>

Share the common irq code by simply defining a correct mapping declaration
for the s3c2416.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-s3c24xx/irq.c |  342 +++++++++++--------------------------------
 1 files changed, 87 insertions(+), 255 deletions(-)

diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index fe6d278..c6d0d57 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -352,7 +352,8 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
 						 handle_edge_irq);
 		break;
 	case S3C_IRQTYPE_EDGE:
-		if (irq_data->parent_irq)
+		if (irq_data->parent_irq ||
+		    intc->reg_pending == S3C2416_SRCPND2)
 			irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
 						 handle_edge_irq);
 		else
@@ -628,273 +629,104 @@ void __init s3c24xx_init_irq(void)
 }
 
 #ifdef CONFIG_CPU_S3C2416
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
-{
-	unsigned int subsrc, submsk;
-	unsigned int end;
-
-	/* read the current pending interrupts, and the mask
-	 * for what it is available */
-
-	subsrc = __raw_readl(S3C2410_SUBSRCPND);
-	submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-	subsrc  &= ~submsk;
-	subsrc >>= (irq - S3C2410_IRQSUB(0));
-	subsrc  &= (1 << len)-1;
-
-	end = len + irq;
-
-	for (; irq < end && subsrc; irq++) {
-		if (subsrc & 1)
-			generic_handle_irq(irq);
-
-		subsrc >>= 1;
-	}
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97	(1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97	INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2416_irq_wdtac97 = {
-	.irq_mask	= s3c2416_irq_wdtac97_mask,
-	.irq_unmask	= s3c2416_irq_wdtac97_unmask,
-	.irq_ack	= s3c2416_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD	(1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD	INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2416_irq_lcd_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2416_irq_lcd = {
-	.irq_mask	= s3c2416_irq_lcd_mask,
-	.irq_unmask	= s3c2416_irq_lcd_unmask,
-	.irq_ack	= s3c2416_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA	(1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA	INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-
-static void s3c2416_irq_dma_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2416_irq_dma_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2416_irq_dma_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2416_irq_dma = {
-	.irq_mask	= s3c2416_irq_dma_mask,
-	.irq_unmask	= s3c2416_irq_dma_unmask,
-	.irq_ack	= s3c2416_irq_dma_ack,
+static struct s3c_irq_data init_s3c2416base[32] = {
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+	{ .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+	{ .type = S3C_IRQTYPE_NONE, }, /* reserved */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
+	{ .type = S3C_IRQTYPE_NONE, }, /* reserved */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* NAND */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+	{ .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+	{ .type = S3C_IRQTYPE_NONE, },
+	{ .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+	{ .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
 };
 
-/* UART3 sub interrupts */
-
-static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2416_irq_uart3_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2416_irq_uart3 = {
-	.irq_mask	= s3c2416_irq_uart3_mask,
-	.irq_unmask	= s3c2416_irq_uart3_unmask,
-	.irq_ack	= s3c2416_irq_uart3_ack,
+static struct s3c_irq_data init_s3c2416subint[32] = {
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+	{ .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+	{ .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+	{ .type = S3C_IRQTYPE_NONE }, /* reserved */
+	{ .type = S3C_IRQTYPE_NONE }, /* reserved */
+	{ .type = S3C_IRQTYPE_NONE }, /* reserved */
+	{ .type = S3C_IRQTYPE_NONE }, /* reserved */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
+	{ .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
 };
 
-/* second interrupt register */
-
-static inline void s3c2416_irq_ack_second(struct irq_data *data)
-{
-	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
-
-	__raw_writel(bitval, S3C2416_SRCPND2);
-	__raw_writel(bitval, S3C2416_INTPND2);
-}
-
-static void s3c2416_irq_mask_second(struct irq_data *data)
-{
-	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
-	unsigned long mask;
-
-	mask = __raw_readl(S3C2416_INTMSK2);
-	mask |= bitval;
-	__raw_writel(mask, S3C2416_INTMSK2);
-}
-
-static void s3c2416_irq_unmask_second(struct irq_data *data)
-{
-	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
-	unsigned long mask;
-
-	mask = __raw_readl(S3C2416_INTMSK2);
-	mask &= ~bitval;
-	__raw_writel(mask, S3C2416_INTMSK2);
-}
-
-static struct irq_chip s3c2416_irq_second = {
-	.irq_ack	= s3c2416_irq_ack_second,
-	.irq_mask	= s3c2416_irq_mask_second,
-	.irq_unmask	= s3c2416_irq_unmask_second,
+static struct s3c_irq_data init_s3c2416_second[32] = {
+	{ .type = S3C_IRQTYPE_EDGE }, /* 2D */
+	{ .type = S3C_IRQTYPE_EDGE }, /* IIC1 */
+	{ .type = S3C_IRQTYPE_NONE }, /* reserved */
+	{ .type = S3C_IRQTYPE_NONE }, /* reserved */
+	{ .type = S3C_IRQTYPE_EDGE }, /* PCM0 */
+	{ .type = S3C_IRQTYPE_EDGE }, /* PCM1 */
+	{ .type = S3C_IRQTYPE_EDGE }, /* I2S0 */
+	{ .type = S3C_IRQTYPE_EDGE }, /* I2S1 */
 };
 
-
-/* IRQ initialisation code */
-
-static int s3c2416_add_sub(unsigned int base,
-				   void (*demux)(unsigned int,
-						 struct irq_desc *),
-				   struct irq_chip *chip,
-				   unsigned int start, unsigned int end)
-{
-	unsigned int irqno;
-
-	irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
-	irq_set_chained_handler(base, demux);
-
-	for (irqno = start; irqno <= end; irqno++) {
-		irq_set_chip_and_handler(irqno, chip, handle_level_irq);
-		set_irq_flags(irqno, IRQF_VALID);
-	}
-
-	return 0;
-}
-
-static void s3c2416_irq_add_second(void)
-{
-	unsigned long pend;
-	unsigned long last;
-	int irqno;
-	int i;
-
-	/* first, clear all interrupts pending... */
-	last = 0;
-	for (i = 0; i < 4; i++) {
-		pend = __raw_readl(S3C2416_INTPND2);
-
-		if (pend == 0 || pend == last)
-			break;
-
-		__raw_writel(pend, S3C2416_SRCPND2);
-		__raw_writel(pend, S3C2416_INTPND2);
-		printk(KERN_INFO "irq: clearing pending status %08x\n",
-		       (int)pend);
-		last = pend;
-	}
-
-	for (irqno = IRQ_S3C2416_2D; irqno <= IRQ_S3C2416_I2S1; irqno++) {
-		switch (irqno) {
-		case IRQ_S3C2416_RESERVED2:
-		case IRQ_S3C2416_RESERVED3:
-			/* no IRQ here */
-			break;
-		default:
-			irq_set_chip_and_handler(irqno, &s3c2416_irq_second,
-						 handle_edge_irq);
-			set_irq_flags(irqno, IRQF_VALID);
-		}
-	}
-}
-
 void __init s3c2416_init_irq(void)
 {
-	pr_info("S3C2416: IRQ Support\n");
-
-	s3c24xx_init_irq();
+	struct s3c_irq_intc *main_intc;
 
-	s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
-			IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
+	pr_info("S3C2416: IRQ Support\n");
 
-	s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
-			&s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
+#ifdef CONFIG_FIQ
+	init_FIQ(FIQ_START);
+#endif
 
-	s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
-			&s3c2416_irq_uart3,
-			IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
+	main_intc = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, 0x4a000000);
+	if (IS_ERR(main_intc)) {
+		pr_err("irq: could not create main interrupt controller\n");
+		return;
+	}
 
-	s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
-			&s3c2416_irq_wdtac97,
-			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
+	s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
+	s3c24xx_init_intc(NULL, &init_s3c2416subint[0], main_intc, 0x4a000018);
 
-	s3c2416_irq_add_second();
+	s3c24xx_init_intc(NULL, &init_s3c2416_second[0], NULL, 0x4a000040);
 }
 
 #endif
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v3 5/9] ARM: S3C24XX: modify s3c2416 irq init to initialize all irqs
From: Heiko Stübner @ 2013-01-19  3:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301190403.50317.heiko@sntech.de>

Previously the irq init used s3c24xx_init_irq and an additional
arch_initcall to add the cpu specific irqs.

To be able to simplyfy the irq init later, create a new function
s3c416_init_irq, which then calls s3c24xx_init_irq but also adds
the cpu specific irqs.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-s3c24xx/mach-smdk2416.c        |    2 +-
 arch/arm/plat-s3c24xx/irq.c                  |   22 ++++------------------
 arch/arm/plat-samsung/include/plat/s3c2416.h |    1 +
 3 files changed, 6 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
index 7de4120..2abb66f 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2416.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
@@ -250,7 +250,7 @@ MACHINE_START(SMDK2416, "SMDK2416")
 	/* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
 	.atag_offset	= 0x100,
 
-	.init_irq	= s3c24xx_init_irq,
+	.init_irq	= s3c2416_init_irq,
 	.map_io		= smdk2416_map_io,
 	.init_machine	= smdk2416_machine_init,
 	.timer		= &s3c24xx_timer,
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 137dc16..fe6d278 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -874,10 +874,11 @@ static void s3c2416_irq_add_second(void)
 	}
 }
 
-static int s3c2416_irq_add(struct device *dev,
-				  struct subsys_interface *sif)
+void __init s3c2416_init_irq(void)
 {
-	printk(KERN_INFO "S3C2416: IRQ Support\n");
+	pr_info("S3C2416: IRQ Support\n");
+
+	s3c24xx_init_irq();
 
 	s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
 			IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
@@ -894,21 +895,6 @@ static int s3c2416_irq_add(struct device *dev,
 			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
 
 	s3c2416_irq_add_second();
-
-	return 0;
 }
 
-static struct subsys_interface s3c2416_irq_interface = {
-	.name		= "s3c2416_irq",
-	.subsys		= &s3c2416_subsys,
-	.add_dev	= s3c2416_irq_add,
-};
-
-static int __init s3c2416_irq_init(void)
-{
-	return subsys_interface_register(&s3c2416_irq_interface);
-}
-
-arch_initcall(s3c2416_irq_init);
-
 #endif
diff --git a/arch/arm/plat-samsung/include/plat/s3c2416.h b/arch/arm/plat-samsung/include/plat/s3c2416.h
index 7178e33..f27399a 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2416.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2416.h
@@ -25,6 +25,7 @@ extern  int s3c2416_baseclk_add(void);
 
 extern void s3c2416_restart(char mode, const char *cmd);
 
+extern void s3c2416_init_irq(void);
 extern struct syscore_ops s3c2416_irq_syscore_ops;
 
 #else
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v3 4/9] ARM: S3C24XX: move s3c2416 irq init to common irq code
From: Heiko Stübner @ 2013-01-19  3:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301190403.50317.heiko@sntech.de>

This is needed to further clean up the irq init.
The only change made during the move is the renaming of the
conflicting irq_save to s3c2416_irq_save

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-s3c24xx/Makefile      |    2 +-
 arch/arm/mach-s3c24xx/irq-pm.c      |   23 +++
 arch/arm/mach-s3c24xx/irq-s3c2416.c |  348 -----------------------------------
 arch/arm/plat-s3c24xx/irq.c         |  286 ++++++++++++++++++++++++++++
 4 files changed, 310 insertions(+), 349 deletions(-)
 delete mode 100644 arch/arm/mach-s3c24xx/irq-s3c2416.c

diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
index 0ab6ab1..4d512cb 100644
--- a/arch/arm/mach-s3c24xx/Makefile
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_S3C2412_DMA)	+= dma-s3c2412.o
 obj-$(CONFIG_S3C2412_PM)	+= pm-s3c2412.o
 obj-$(CONFIG_S3C2412_PM_SLEEP)	+= sleep-s3c2412.o
 
-obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o irq-s3c2416.o clock-s3c2416.o
+obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o clock-s3c2416.o
 obj-$(CONFIG_S3C2416_PM)	+= pm-s3c2416.o
 
 obj-$(CONFIG_CPU_S3C2440)	+= s3c2440.o irq-s3c2440.o clock-s3c2440.o
diff --git a/arch/arm/mach-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c
index 640ec91..e119959 100644
--- a/arch/arm/mach-s3c24xx/irq-pm.c
+++ b/arch/arm/mach-s3c24xx/irq-pm.c
@@ -99,3 +99,26 @@ struct syscore_ops s3c24xx_irq_syscore_ops = {
 	.suspend	= s3c24xx_irq_suspend,
 	.resume		= s3c24xx_irq_resume,
 };
+
+#ifdef CONFIG_CPU_S3C2416
+static struct sleep_save s3c2416_irq_save[] = {
+	SAVE_ITEM(S3C2416_INTMSK2),
+};
+
+static int s3c2416_irq_suspend(void)
+{
+	s3c_pm_do_save(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save));
+
+	return 0;
+}
+
+static void s3c2416_irq_resume(void)
+{
+	s3c_pm_do_restore(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save));
+}
+
+struct syscore_ops s3c2416_irq_syscore_ops = {
+	.suspend	= s3c2416_irq_suspend,
+	.resume		= s3c2416_irq_resume,
+};
+#endif
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2416.c b/arch/arm/mach-s3c24xx/irq-s3c2416.c
deleted file mode 100644
index ff141b0..0000000
--- a/arch/arm/mach-s3c24xx/irq-s3c2416.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/irq.c
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *	as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/syscore_ops.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
-{
-	unsigned int subsrc, submsk;
-	unsigned int end;
-
-	/* read the current pending interrupts, and the mask
-	 * for what it is available */
-
-	subsrc = __raw_readl(S3C2410_SUBSRCPND);
-	submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-	subsrc  &= ~submsk;
-	subsrc >>= (irq - S3C2410_IRQSUB(0));
-	subsrc  &= (1 << len)-1;
-
-	end = len + irq;
-
-	for (; irq < end && subsrc; irq++) {
-		if (subsrc & 1)
-			generic_handle_irq(irq);
-
-		subsrc >>= 1;
-	}
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97	(1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97	INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2416_irq_wdtac97 = {
-	.irq_mask	= s3c2416_irq_wdtac97_mask,
-	.irq_unmask	= s3c2416_irq_wdtac97_unmask,
-	.irq_ack	= s3c2416_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD	(1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD	INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2416_irq_lcd_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2416_irq_lcd = {
-	.irq_mask	= s3c2416_irq_lcd_mask,
-	.irq_unmask	= s3c2416_irq_lcd_unmask,
-	.irq_ack	= s3c2416_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA	(1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA	INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-
-static void s3c2416_irq_dma_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2416_irq_dma_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2416_irq_dma_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2416_irq_dma = {
-	.irq_mask	= s3c2416_irq_dma_mask,
-	.irq_unmask	= s3c2416_irq_dma_unmask,
-	.irq_ack	= s3c2416_irq_dma_ack,
-};
-
-/* UART3 sub interrupts */
-
-static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
-	s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2416_irq_uart3_mask(struct irq_data *data)
-{
-	s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_unmask(struct irq_data *data)
-{
-	s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_ack(struct irq_data *data)
-{
-	s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2416_irq_uart3 = {
-	.irq_mask	= s3c2416_irq_uart3_mask,
-	.irq_unmask	= s3c2416_irq_uart3_unmask,
-	.irq_ack	= s3c2416_irq_uart3_ack,
-};
-
-/* second interrupt register */
-
-static inline void s3c2416_irq_ack_second(struct irq_data *data)
-{
-	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
-
-	__raw_writel(bitval, S3C2416_SRCPND2);
-	__raw_writel(bitval, S3C2416_INTPND2);
-}
-
-static void s3c2416_irq_mask_second(struct irq_data *data)
-{
-	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
-	unsigned long mask;
-
-	mask = __raw_readl(S3C2416_INTMSK2);
-	mask |= bitval;
-	__raw_writel(mask, S3C2416_INTMSK2);
-}
-
-static void s3c2416_irq_unmask_second(struct irq_data *data)
-{
-	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
-	unsigned long mask;
-
-	mask = __raw_readl(S3C2416_INTMSK2);
-	mask &= ~bitval;
-	__raw_writel(mask, S3C2416_INTMSK2);
-}
-
-static struct irq_chip s3c2416_irq_second = {
-	.irq_ack	= s3c2416_irq_ack_second,
-	.irq_mask	= s3c2416_irq_mask_second,
-	.irq_unmask	= s3c2416_irq_unmask_second,
-};
-
-
-/* IRQ initialisation code */
-
-static int s3c2416_add_sub(unsigned int base,
-				   void (*demux)(unsigned int,
-						 struct irq_desc *),
-				   struct irq_chip *chip,
-				   unsigned int start, unsigned int end)
-{
-	unsigned int irqno;
-
-	irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
-	irq_set_chained_handler(base, demux);
-
-	for (irqno = start; irqno <= end; irqno++) {
-		irq_set_chip_and_handler(irqno, chip, handle_level_irq);
-		set_irq_flags(irqno, IRQF_VALID);
-	}
-
-	return 0;
-}
-
-static void s3c2416_irq_add_second(void)
-{
-	unsigned long pend;
-	unsigned long last;
-	int irqno;
-	int i;
-
-	/* first, clear all interrupts pending... */
-	last = 0;
-	for (i = 0; i < 4; i++) {
-		pend = __raw_readl(S3C2416_INTPND2);
-
-		if (pend == 0 || pend == last)
-			break;
-
-		__raw_writel(pend, S3C2416_SRCPND2);
-		__raw_writel(pend, S3C2416_INTPND2);
-		printk(KERN_INFO "irq: clearing pending status %08x\n",
-		       (int)pend);
-		last = pend;
-	}
-
-	for (irqno = IRQ_S3C2416_2D; irqno <= IRQ_S3C2416_I2S1; irqno++) {
-		switch (irqno) {
-		case IRQ_S3C2416_RESERVED2:
-		case IRQ_S3C2416_RESERVED3:
-			/* no IRQ here */
-			break;
-		default:
-			irq_set_chip_and_handler(irqno, &s3c2416_irq_second,
-						 handle_edge_irq);
-			set_irq_flags(irqno, IRQF_VALID);
-		}
-	}
-}
-
-static int s3c2416_irq_add(struct device *dev,
-				  struct subsys_interface *sif)
-{
-	printk(KERN_INFO "S3C2416: IRQ Support\n");
-
-	s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
-			IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
-
-	s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
-			&s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
-
-	s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
-			&s3c2416_irq_uart3,
-			IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
-
-	s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
-			&s3c2416_irq_wdtac97,
-			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
-
-	s3c2416_irq_add_second();
-
-	return 0;
-}
-
-static struct subsys_interface s3c2416_irq_interface = {
-	.name		= "s3c2416_irq",
-	.subsys		= &s3c2416_subsys,
-	.add_dev	= s3c2416_irq_add,
-};
-
-static int __init s3c2416_irq_init(void)
-{
-	return subsys_interface_register(&s3c2416_irq_interface);
-}
-
-arch_initcall(s3c2416_irq_init);
-
-#ifdef CONFIG_PM
-static struct sleep_save irq_save[] = {
-	SAVE_ITEM(S3C2416_INTMSK2),
-};
-
-static int s3c2416_irq_suspend(void)
-{
-	s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
-
-	return 0;
-}
-
-static void s3c2416_irq_resume(void)
-{
-	s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
-}
-
-struct syscore_ops s3c2416_irq_syscore_ops = {
-	.suspend	= s3c2416_irq_suspend,
-	.resume		= s3c2416_irq_resume,
-};
-#endif
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index adb4358..137dc16 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -626,3 +626,289 @@ void __init s3c24xx_init_irq(void)
 	s3c24xx_init_intc(NULL, &init_subint[0], main_intc, 0x4a000018);
 	s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
 }
+
+#ifdef CONFIG_CPU_S3C2416
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+
+static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
+{
+	unsigned int subsrc, submsk;
+	unsigned int end;
+
+	/* read the current pending interrupts, and the mask
+	 * for what it is available */
+
+	subsrc = __raw_readl(S3C2410_SUBSRCPND);
+	submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+	subsrc  &= ~submsk;
+	subsrc >>= (irq - S3C2410_IRQSUB(0));
+	subsrc  &= (1 << len)-1;
+
+	end = len + irq;
+
+	for (; irq < end && subsrc; irq++) {
+		if (subsrc & 1)
+			generic_handle_irq(irq);
+
+		subsrc >>= 1;
+	}
+}
+
+/* WDT/AC97 sub interrupts */
+
+static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
+}
+
+#define INTMSK_WDTAC97	(1UL << (IRQ_WDT - IRQ_EINT0))
+#define SUBMSK_WDTAC97	INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
+
+static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
+}
+
+static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static struct irq_chip s3c2416_irq_wdtac97 = {
+	.irq_mask	= s3c2416_irq_wdtac97_mask,
+	.irq_unmask	= s3c2416_irq_wdtac97_unmask,
+	.irq_ack	= s3c2416_irq_wdtac97_ack,
+};
+
+/* LCD sub interrupts */
+
+static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
+}
+
+#define INTMSK_LCD	(1UL << (IRQ_LCD - IRQ_EINT0))
+#define SUBMSK_LCD	INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
+
+static void s3c2416_irq_lcd_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static void s3c2416_irq_lcd_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_LCD);
+}
+
+static void s3c2416_irq_lcd_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static struct irq_chip s3c2416_irq_lcd = {
+	.irq_mask	= s3c2416_irq_lcd_mask,
+	.irq_unmask	= s3c2416_irq_lcd_unmask,
+	.irq_ack	= s3c2416_irq_lcd_ack,
+};
+
+/* DMA sub interrupts */
+
+static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
+}
+
+#define INTMSK_DMA	(1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
+#define SUBMSK_DMA	INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
+
+
+static void s3c2416_irq_dma_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static void s3c2416_irq_dma_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_DMA);
+}
+
+static void s3c2416_irq_dma_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static struct irq_chip s3c2416_irq_dma = {
+	.irq_mask	= s3c2416_irq_dma_mask,
+	.irq_unmask	= s3c2416_irq_dma_unmask,
+	.irq_ack	= s3c2416_irq_dma_ack,
+};
+
+/* UART3 sub interrupts */
+
+static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
+{
+	s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
+}
+
+#define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
+#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
+
+static void s3c2416_irq_uart3_mask(struct irq_data *data)
+{
+	s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static void s3c2416_irq_uart3_unmask(struct irq_data *data)
+{
+	s3c_irqsub_unmask(data->irq, INTMSK_UART3);
+}
+
+static void s3c2416_irq_uart3_ack(struct irq_data *data)
+{
+	s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static struct irq_chip s3c2416_irq_uart3 = {
+	.irq_mask	= s3c2416_irq_uart3_mask,
+	.irq_unmask	= s3c2416_irq_uart3_unmask,
+	.irq_ack	= s3c2416_irq_uart3_ack,
+};
+
+/* second interrupt register */
+
+static inline void s3c2416_irq_ack_second(struct irq_data *data)
+{
+	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
+
+	__raw_writel(bitval, S3C2416_SRCPND2);
+	__raw_writel(bitval, S3C2416_INTPND2);
+}
+
+static void s3c2416_irq_mask_second(struct irq_data *data)
+{
+	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
+	unsigned long mask;
+
+	mask = __raw_readl(S3C2416_INTMSK2);
+	mask |= bitval;
+	__raw_writel(mask, S3C2416_INTMSK2);
+}
+
+static void s3c2416_irq_unmask_second(struct irq_data *data)
+{
+	unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
+	unsigned long mask;
+
+	mask = __raw_readl(S3C2416_INTMSK2);
+	mask &= ~bitval;
+	__raw_writel(mask, S3C2416_INTMSK2);
+}
+
+static struct irq_chip s3c2416_irq_second = {
+	.irq_ack	= s3c2416_irq_ack_second,
+	.irq_mask	= s3c2416_irq_mask_second,
+	.irq_unmask	= s3c2416_irq_unmask_second,
+};
+
+
+/* IRQ initialisation code */
+
+static int s3c2416_add_sub(unsigned int base,
+				   void (*demux)(unsigned int,
+						 struct irq_desc *),
+				   struct irq_chip *chip,
+				   unsigned int start, unsigned int end)
+{
+	unsigned int irqno;
+
+	irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
+	irq_set_chained_handler(base, demux);
+
+	for (irqno = start; irqno <= end; irqno++) {
+		irq_set_chip_and_handler(irqno, chip, handle_level_irq);
+		set_irq_flags(irqno, IRQF_VALID);
+	}
+
+	return 0;
+}
+
+static void s3c2416_irq_add_second(void)
+{
+	unsigned long pend;
+	unsigned long last;
+	int irqno;
+	int i;
+
+	/* first, clear all interrupts pending... */
+	last = 0;
+	for (i = 0; i < 4; i++) {
+		pend = __raw_readl(S3C2416_INTPND2);
+
+		if (pend == 0 || pend == last)
+			break;
+
+		__raw_writel(pend, S3C2416_SRCPND2);
+		__raw_writel(pend, S3C2416_INTPND2);
+		printk(KERN_INFO "irq: clearing pending status %08x\n",
+		       (int)pend);
+		last = pend;
+	}
+
+	for (irqno = IRQ_S3C2416_2D; irqno <= IRQ_S3C2416_I2S1; irqno++) {
+		switch (irqno) {
+		case IRQ_S3C2416_RESERVED2:
+		case IRQ_S3C2416_RESERVED3:
+			/* no IRQ here */
+			break;
+		default:
+			irq_set_chip_and_handler(irqno, &s3c2416_irq_second,
+						 handle_edge_irq);
+			set_irq_flags(irqno, IRQF_VALID);
+		}
+	}
+}
+
+static int s3c2416_irq_add(struct device *dev,
+				  struct subsys_interface *sif)
+{
+	printk(KERN_INFO "S3C2416: IRQ Support\n");
+
+	s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
+			IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
+
+	s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
+			&s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
+
+	s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
+			&s3c2416_irq_uart3,
+			IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
+
+	s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
+			&s3c2416_irq_wdtac97,
+			IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
+
+	s3c2416_irq_add_second();
+
+	return 0;
+}
+
+static struct subsys_interface s3c2416_irq_interface = {
+	.name		= "s3c2416_irq",
+	.subsys		= &s3c2416_subsys,
+	.add_dev	= s3c2416_irq_add,
+};
+
+static int __init s3c2416_irq_init(void)
+{
+	return subsys_interface_register(&s3c2416_irq_interface);
+}
+
+arch_initcall(s3c2416_irq_init);
+
+#endif
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v3 3/9] ARM: S3C24XX: Modify s3c_irq_wake to use the hwirq property
From: Heiko Stübner @ 2013-01-19  3:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301190403.50317.heiko@sntech.de>

This gets rid of the use of static irq mappings there.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/mach-s3c24xx/irq-pm.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c
index d48126d..640ec91 100644
--- a/arch/arm/mach-s3c24xx/irq-pm.c
+++ b/arch/arm/mach-s3c24xx/irq-pm.c
@@ -30,18 +30,18 @@
  * set bit to 1 in allow bitfield to enable the wakeup settings on it
 */
 
-unsigned long s3c_irqwake_intallow	= 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
+unsigned long s3c_irqwake_intallow	= 1L << 30 | 0xfL;
 unsigned long s3c_irqwake_eintallow	= 0x0000fff0L;
 
 int s3c_irq_wake(struct irq_data *data, unsigned int state)
 {
-	unsigned long irqbit = 1 << (data->irq - IRQ_EINT0);
+	unsigned long irqbit = 1 << data->hwirq;
 
 	if (!(s3c_irqwake_intallow & irqbit))
 		return -ENOENT;
 
-	printk(KERN_INFO "wake %s for irq %d\n",
-	       state ? "enabled" : "disabled", data->irq);
+	pr_info("wake %s for hwirq %lu\n",
+		state ? "enabled" : "disabled", data->hwirq);
 
 	if (!state)
 		s3c_irqwake_intmask |= irqbit;
-- 
1.7.2.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox