diff mbox

[1/3] ARM: CSR: Adding CSR SiRFprimaII board support

Message ID 1309945678-18813-2-git-send-email-bs14@csr.com
State New
Headers show

Commit Message

Barry Song July 6, 2011, 9:47 a.m. UTC
From: Binghua Duan <binghua.duan@csr.com>

SiRFprimaII is the latest generation application processor from CSR’s
Multifunction SoC product family. Designed around an ARM cortex A9 core,
high-speed memory bus, advanced 3D accelerator and full-HD multi-format
video decoder, SiRFprimaII is able to meet the needs of complicated
applications for modern multifunction devices that require heavy concurrent
applications and fluid user experience. Integrated with GPS baseband,
analog and PMU, this new platform is designed to provide a cost effective
solution for Automotive and Consumer markets.

This patch adds the basic support for this SoC and EVB board based on device
tree. It is following the ZYNQ of Grant Likely in some degree.

Signed-off-by: Binghua Duan <Binghua.Duan@csr.com>
Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com>
Signed-off-by: Yuping Luo <Yuping.Luo@csr.com>
Signed-off-by: Bin Shi <Bin.Shi@csr.com>
Signed-off-by: Huayi Li <Huayi.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
---
 Documentation/devicetree/bindings/arm/sirf.txt  |    3 +
 arch/arm/Kconfig                                |   13 +
 arch/arm/Makefile                               |    1 +
 arch/arm/boot/dts/prima2-cb.dts                 |  423 +++++++++++++++++++
 arch/arm/mach-prima2/Makefile                   |    5 +
 arch/arm/mach-prima2/Makefile.boot              |    3 +
 arch/arm/mach-prima2/clock.c                    |  509 +++++++++++++++++++++++
 arch/arm/mach-prima2/common.h                   |   26 ++
 arch/arm/mach-prima2/include/mach/clkdev.h      |   15 +
 arch/arm/mach-prima2/include/mach/debug-macro.S |   29 ++
 arch/arm/mach-prima2/include/mach/entry-macro.S |   29 ++
 arch/arm/mach-prima2/include/mach/hardware.h    |   15 +
 arch/arm/mach-prima2/include/mach/io.h          |   21 +
 arch/arm/mach-prima2/include/mach/irqs.h        |   17 +
 arch/arm/mach-prima2/include/mach/map.h         |   16 +
 arch/arm/mach-prima2/include/mach/memory.h      |   21 +
 arch/arm/mach-prima2/include/mach/system.h      |   29 ++
 arch/arm/mach-prima2/include/mach/timex.h       |   14 +
 arch/arm/mach-prima2/include/mach/uart.h        |   23 +
 arch/arm/mach-prima2/include/mach/uncompress.h  |   40 ++
 arch/arm/mach-prima2/include/mach/vmalloc.h     |   14 +
 arch/arm/mach-prima2/irq.c                      |   71 ++++
 arch/arm/mach-prima2/prima2.c                   |   40 ++
 arch/arm/mach-prima2/rstc.c                     |   69 +++
 arch/arm/mach-prima2/timer.c                    |  219 ++++++++++
 arch/arm/mm/Kconfig                             |    2 +-
 26 files changed, 1666 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/sirf.txt
 create mode 100644 arch/arm/boot/dts/prima2-cb.dts
 create mode 100644 arch/arm/mach-prima2/Makefile
 create mode 100644 arch/arm/mach-prima2/Makefile.boot
 create mode 100644 arch/arm/mach-prima2/clock.c
 create mode 100644 arch/arm/mach-prima2/common.h
 create mode 100644 arch/arm/mach-prima2/include/mach/clkdev.h
 create mode 100644 arch/arm/mach-prima2/include/mach/debug-macro.S
 create mode 100644 arch/arm/mach-prima2/include/mach/entry-macro.S
 create mode 100644 arch/arm/mach-prima2/include/mach/hardware.h
 create mode 100644 arch/arm/mach-prima2/include/mach/io.h
 create mode 100644 arch/arm/mach-prima2/include/mach/irqs.h
 create mode 100644 arch/arm/mach-prima2/include/mach/map.h
 create mode 100644 arch/arm/mach-prima2/include/mach/memory.h
 create mode 100644 arch/arm/mach-prima2/include/mach/system.h
 create mode 100644 arch/arm/mach-prima2/include/mach/timex.h
 create mode 100644 arch/arm/mach-prima2/include/mach/uart.h
 create mode 100644 arch/arm/mach-prima2/include/mach/uncompress.h
 create mode 100644 arch/arm/mach-prima2/include/mach/vmalloc.h
 create mode 100644 arch/arm/mach-prima2/irq.c
 create mode 100644 arch/arm/mach-prima2/prima2.c
 create mode 100644 arch/arm/mach-prima2/rstc.c
 create mode 100644 arch/arm/mach-prima2/timer.c

Comments

Russell King - ARM Linux July 6, 2011, 11:04 a.m. UTC | #1
On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote:
> +static int sirfsoc_timer_set_next_event(unsigned long delta,
> +	struct clock_event_device *ce)
> +{
> +	unsigned long now, next;
> +
> +	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
> +	now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
> +	do {
> +		next = now + delta;
> +		writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
> +		writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
> +		now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
> +	} while ((next - now) > delta);
> +
> +	return 0;
> +}

Please have a look at any of the callsites of clockevents_program_event()
in kernel/time/.  You'll notice that they loop in some fashion should your
set_next_event() return -ETIME.

As there is the possibility that if you can't program the event (because
it has already passed) then it is likely that there is some work which
needs to be done before the next event is set.  So the repeat logic should
stay in the common code and not be duplicated in each platform.
Arnd Bergmann July 6, 2011, 11:41 a.m. UTC | #2
On Wednesday 06 July 2011, Barry Song wrote:
> From: Binghua Duan <binghua.duan@csr.com>
> 
> SiRFprimaII is the latest generation application processor from CSR’s
> Multifunction SoC product family. Designed around an ARM cortex A9 core,
> high-speed memory bus, advanced 3D accelerator and full-HD multi-format
> video decoder, SiRFprimaII is able to meet the needs of complicated
> applications for modern multifunction devices that require heavy concurrent
> applications and fluid user experience. Integrated with GPS baseband,
> analog and PMU, this new platform is designed to provide a cost effective
> solution for Automotive and Consumer markets.
> 
> This patch adds the basic support for this SoC and EVB board based on device
> tree. It is following the ZYNQ of Grant Likely in some degree.
> 
> Signed-off-by: Binghua Duan <Binghua.Duan@csr.com>
> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
> Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com>
> Signed-off-by: Yuping Luo <Yuping.Luo@csr.com>
> Signed-off-by: Bin Shi <Bin.Shi@csr.com>
> Signed-off-by: Huayi Li <Huayi.Li@csr.com>
> Signed-off-by: Barry Song <Baohua.Song@csr.com>

Reviewed-by: Arnd Bergmann <arnd@arndb.de>

I think this is good for 3.1, but there are still a few things about
the device tree file could be improved.

> +	axi {
> +		compatible = "simple-bus";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges = <0x40000000 0x40000000 0x80000000>;
> +
> +		sirfsoc-iobus {
> +			compatible = "simple-bus";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges = <0x40000000 0x40000000 0x80000000>;
> +
> +			l2-cache-controller@0x80040000 {
> +				compatible = "arm,pl310-cache";
> +				reg = <0x80040000 0x1000>;
> +				interrupts = <59>;
> +			};
> +
> +			intc: interrupt-controller@0x80020000 {
> +				#interrupt-cells = <1>;
> +				interrupt-controller;
> +				compatible = "sirf,prima2-intc";
> +				reg = <0x80020000 0x1000>;
> +			};
> +
> +                     sys-iobg {
> +                             compatible = "simple-bus";
> +                             #address-cells = <1>;
> +                             #size-cells = <1>;
> +                             ranges = <0x88000000 0x88000000 0x40000>;
> +
> +                             clock-controller@0x88000000 {
> +                                     compatible = "sirf,prima2-clkc";
> +                                     reg = <0x88000000 0x1000>;
> +                                     interrupts = <3>;
> +                             };


The axi bus and the sirfsoc-iobus seem to be identical in their scope,
so it's probably enough to model one of them.

I would normally recommend defining the ranges so that addresses are local
to the respective bus, like

	axi {
		ranges = <0 0x40000000 0x80000000>;

		sys-iobg {
			ranges = <0 0x48000000 0x40000>;
                        clock-controller@0x88000000 {
                               compatible = "sirf,prima2-clkc";
                               reg = <0 0x1000>;
			}

                        reset-controller@0x88010000 {
                               compatible = "sirf,prima2-rstc";
                               reg = <0x10000 0x1000>;
                        };
		}
	}


> +			disp-iobg {
> +				compatible = "simple-bus";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				ranges = <0x90010000 0x90010000 0x30000>;
> +
> +				display@0x90010000 {
> +					compatible = "sirf,prima2-lcd";
> +					reg = <0x90010000 0x20000>;
> +					interrupts = <30>;
> +				};
> +
> +				vpp@0x90020000 {
> +					compatible = "sirf,prima2-vpp";
> +					reg = <0x90020000 0x10000>;
> +					interrupts = <31>;
> +				};
> +			};
> +
> +			graphics-iobg {
> +				compatible = "simple-bus";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				ranges = <0x98000000 0x98000000 0x8000000>;
> +
> +				graphics@0x98000000 {
> +					compatible = "sirf,prima2-graphics";
> +					reg = <0x98000000 0x8000000>;
> +					interrupts = <6>;
> +				};
> +			};

Are the display and graphics units CSR developments? If the GPU is
in fact licensed from someone else (powervr, arm, ...), you should
probably list the actual name of the device.

> +			multimedia-iobg {
> +				compatible = "simple-bus";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				ranges = <0xa0000000 0xa0000000 0x8000000>;
> +
> +				multimedia@0xa0000000 {
> +					compatible = "sirf,prima2-multimedia";
> +					reg = <0xa0000000 0x8000000>;
> +					interrupts = <5>;
> +				};
> +			};

"multimedia" sounds like a too generic term. What does this do?

> +				uart0: uart@0xb0050000 {
> +					cell-index = <0>;
> +					compatible = "sirf,prima2-uart";
> +					reg = <0xb0050000 0x10000>;
> +					interrupts = <17>;
> +				};
> +
> +	 			uart1: uart@0xb0060000 {
> +					cell-index = <1>;
> +					compatible = "sirf,prima2-uart";
> +					reg = <0xb0060000 0x10000>;
> +					interrupts = <18>;
> +				};
> +
> +	 			uart2: uart@0xb0070000 {
> +					cell-index = <2>;
> +					compatible = "sirf,prima2-uart";
> +					reg = <0xb0070000 0x10000>;
> +					interrupts = <19>;
> +				};

Are these proprietary uarts, or are they compatible to 8250 and the
like? You might want to set a clock-frequency property as of_serial.c
uses.

> +			rtc-iobg {
> +				compatible = "sirf,prima2-rtciobg", "simple-bus";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				reg = <0x80030000 0x10000>;
> +
> +				gpsrtc@0x1000 {
> +					compatible = "sirf,prima2-gpsrtc";
> +					reg = <0x1000 0x1000>;
> +					interrupts = <55 56 57>;
> +				};
> +
> +				sysrtc@0x2000 {
> +					compatible = "sirf,prima2-sysrtc";
> +					reg = <0x2000 0x1000>;
> +					interrupts = <52 53 54>;
> +				};
> +
> +				pwrc@0x3000 {
> +					compatible = "sirf,prima2-pwrc";
> +					reg = <0x3000 0x1000>;
> +					interrupts = <32>;
> +				};
> +			};

Are these rtc implementations related? From the register layout, I would
guess that they are supposed to be used by the same driver, so it's
probably a good idea to add a "compatible" property with a common name
for all three.

> +			uus-iobg {
> +				compatible = "simple-bus";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				ranges = <0xb8000000 0xb8000000 0x40000>;
> +
> +	 			usb0: usb@0xb00E0000 {
> +					compatible = "sirf,prima2-usb";
> +					reg = <0xb8000000 0x10000>;
> +					interrupts = <10>;
> +				};
> +
> +	 			usb1: usb@0xb00f0000 {
> +					compatible = "sirf,prima2-usb";
> +					reg = <0xb8010000 0x10000>;
> +					interrupts = <11>;
> +				};

Is the usb implementation compatible to an existing one? Many SoCs
use one of ehci, ohci or musb. If that's the case, you should look
at the respective bindings.

> +				sata@0xb00f0000 {
> +					compatible = "sirf,prima2-sata";
> +					reg = <0xb8020000 0x10000>;
> +					interrupts = <37>;
> +				};

Same thing here. Most sata controllers are compatible to some
standard implementation.

> +				security@0xb00f0000 {
> +					compatible = "sirf,prima2-security";
> +					reg = <0xb8030000 0x10000>;
> +					interrupts = <42>;
> +				};
> +			};
> +		};
> +	};
> +};

	Arnd
Barry Song July 6, 2011, 12:22 p.m. UTC | #3
Hi Arnd,
thanks.

2011/7/6 Arnd Bergmann <arnd@arndb.de>:
> On Wednesday 06 July 2011, Barry Song wrote:
>> From: Binghua Duan <binghua.duan@csr.com>
>>
>> SiRFprimaII is the latest generation application processor from CSR’s
>> Multifunction SoC product family. Designed around an ARM cortex A9 core,
>> high-speed memory bus, advanced 3D accelerator and full-HD multi-format
>> video decoder, SiRFprimaII is able to meet the needs of complicated
>> applications for modern multifunction devices that require heavy concurrent
>> applications and fluid user experience. Integrated with GPS baseband,
>> analog and PMU, this new platform is designed to provide a cost effective
>> solution for Automotive and Consumer markets.
>>
>> This patch adds the basic support for this SoC and EVB board based on device
>> tree. It is following the ZYNQ of Grant Likely in some degree.
>>
>> Signed-off-by: Binghua Duan <Binghua.Duan@csr.com>
>> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
>> Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com>
>> Signed-off-by: Yuping Luo <Yuping.Luo@csr.com>
>> Signed-off-by: Bin Shi <Bin.Shi@csr.com>
>> Signed-off-by: Huayi Li <Huayi.Li@csr.com>
>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
>
> Reviewed-by: Arnd Bergmann <arnd@arndb.de>
>
> I think this is good for 3.1, but there are still a few things about
> the device tree file could be improved.
>
>> +     axi {
>> +             compatible = "simple-bus";
>> +             #address-cells = <1>;
>> +             #size-cells = <1>;
>> +             ranges = <0x40000000 0x40000000 0x80000000>;
>> +
>> +             sirfsoc-iobus {
>> +                     compatible = "simple-bus";
>> +                     #address-cells = <1>;
>> +                     #size-cells = <1>;
>> +                     ranges = <0x40000000 0x40000000 0x80000000>;
>> +
>> +                     l2-cache-controller@0x80040000 {
>> +                             compatible = "arm,pl310-cache";
>> +                             reg = <0x80040000 0x1000>;
>> +                             interrupts = <59>;
>> +                     };
>> +
>> +                     intc: interrupt-controller@0x80020000 {
>> +                             #interrupt-cells = <1>;
>> +                             interrupt-controller;
>> +                             compatible = "sirf,prima2-intc";
>> +                             reg = <0x80020000 0x1000>;
>> +                     };
>> +
>> +                     sys-iobg {
>> +                             compatible = "simple-bus";
>> +                             #address-cells = <1>;
>> +                             #size-cells = <1>;
>> +                             ranges = <0x88000000 0x88000000 0x40000>;
>> +
>> +                             clock-controller@0x88000000 {
>> +                                     compatible = "sirf,prima2-clkc";
>> +                                     reg = <0x88000000 0x1000>;
>> +                                     interrupts = <3>;
>> +                             };
>
>
> The axi bus and the sirfsoc-iobus seem to be identical in their scope,
> so it's probably enough to model one of them.

ok.

>
> I would normally recommend defining the ranges so that addresses are local
> to the respective bus, like
>
>        axi {
>                ranges = <0 0x40000000 0x80000000>;
>
>                sys-iobg {
>                        ranges = <0 0x48000000 0x40000>;
>                        clock-controller@0x88000000 {
>                               compatible = "sirf,prima2-clkc";
>                               reg = <0 0x1000>;
>                        }
>
>                        reset-controller@0x88010000 {
>                               compatible = "sirf,prima2-rstc";
>                               reg = <0x10000 0x1000>;
>                        };
>                }
>        }

i am not sure whether it make us a little more difficult to know the
real address at first glance.we will need to calculate.
all addresses are 1:1 mapped in this chip. bus map can work even
though we only give "ranges;" without real "ranges = <0x....>;".

i also find i missed grant's comment about deleting "0x" after "@" in
this patch.

>
>
>> +                     disp-iobg {
>> +                             compatible = "simple-bus";
>> +                             #address-cells = <1>;
>> +                             #size-cells = <1>;
>> +                             ranges = <0x90010000 0x90010000 0x30000>;
>> +
>> +                             display@0x90010000 {
>> +                                     compatible = "sirf,prima2-lcd";
>> +                                     reg = <0x90010000 0x20000>;
>> +                                     interrupts = <30>;
>> +                             };
>> +
>> +                             vpp@0x90020000 {
>> +                                     compatible = "sirf,prima2-vpp";
>> +                                     reg = <0x90020000 0x10000>;
>> +                                     interrupts = <31>;
>> +                             };
>> +                     };
>> +
>> +                     graphics-iobg {
>> +                             compatible = "simple-bus";
>> +                             #address-cells = <1>;
>> +                             #size-cells = <1>;
>> +                             ranges = <0x98000000 0x98000000 0x8000000>;
>> +
>> +                             graphics@0x98000000 {
>> +                                     compatible = "sirf,prima2-graphics";
>> +                                     reg = <0x98000000 0x8000000>;
>> +                                     interrupts = <6>;
>> +                             };
>> +                     };
>
> Are the display and graphics units CSR developments? If the GPU is
> in fact licensed from someone else (powervr, arm, ...), you should
> probably list the actual name of the device.

GPU is powervr sgx 531, so could we define compatible as "powervr,sgx531"?

>
>> +                     multimedia-iobg {
>> +                             compatible = "simple-bus";
>> +                             #address-cells = <1>;
>> +                             #size-cells = <1>;
>> +                             ranges = <0xa0000000 0xa0000000 0x8000000>;
>> +
>> +                             multimedia@0xa0000000 {
>> +                                     compatible = "sirf,prima2-multimedia";
>> +                                     reg = <0xa0000000 0x8000000>;
>> +                                     interrupts = <5>;
>> +                             };
>> +                     };
>
> "multimedia" sounds like a too generic term. What does this do?

 video decoding.

>
>> +                             uart0: uart@0xb0050000 {
>> +                                     cell-index = <0>;
>> +                                     compatible = "sirf,prima2-uart";
>> +                                     reg = <0xb0050000 0x10000>;
>> +                                     interrupts = <17>;
>> +                             };
>> +
>> +                             uart1: uart@0xb0060000 {
>> +                                     cell-index = <1>;
>> +                                     compatible = "sirf,prima2-uart";
>> +                                     reg = <0xb0060000 0x10000>;
>> +                                     interrupts = <18>;
>> +                             };
>> +
>> +                             uart2: uart@0xb0070000 {
>> +                                     cell-index = <2>;
>> +                                     compatible = "sirf,prima2-uart";
>> +                                     reg = <0xb0070000 0x10000>;
>> +                                     interrupts = <19>;
>> +                             };
>
> Are these proprietary uarts, or are they compatible to 8250 and the
> like? You might want to set a clock-frequency property as of_serial.c
> uses.

it is not compatible with 8250 .

>
>> +                     rtc-iobg {
>> +                             compatible = "sirf,prima2-rtciobg", "simple-bus";
>> +                             #address-cells = <1>;
>> +                             #size-cells = <1>;
>> +                             reg = <0x80030000 0x10000>;
>> +
>> +                             gpsrtc@0x1000 {
>> +                                     compatible = "sirf,prima2-gpsrtc";
>> +                                     reg = <0x1000 0x1000>;
>> +                                     interrupts = <55 56 57>;
>> +                             };
>> +
>> +                             sysrtc@0x2000 {
>> +                                     compatible = "sirf,prima2-sysrtc";
>> +                                     reg = <0x2000 0x1000>;
>> +                                     interrupts = <52 53 54>;
>> +                             };
>> +
>> +                             pwrc@0x3000 {
>> +                                     compatible = "sirf,prima2-pwrc";
>> +                                     reg = <0x3000 0x1000>;
>> +                                     interrupts = <32>;
>> +                             };
>> +                     };
>
> Are these rtc implementations related? From the register layout, I would
> guess that they are supposed to be used by the same driver, so it's
> probably a good idea to add a "compatible" property with a common name
> for all three.

in fact, because they are slow, they can't be accessed by mapped
address directly, the only common point they have is we need to access
them through mapped address in rtc-iobg indirectly just like we access
i2c/spi/nand devices.

they are three different devices with different purpose and register
layout in fact.

>
>> +                     uus-iobg {
>> +                             compatible = "simple-bus";
>> +                             #address-cells = <1>;
>> +                             #size-cells = <1>;
>> +                             ranges = <0xb8000000 0xb8000000 0x40000>;
>> +
>> +                             usb0: usb@0xb00E0000 {
>> +                                     compatible = "sirf,prima2-usb";
>> +                                     reg = <0xb8000000 0x10000>;
>> +                                     interrupts = <10>;
>> +                             };
>> +
>> +                             usb1: usb@0xb00f0000 {
>> +                                     compatible = "sirf,prima2-usb";
>> +                                     reg = <0xb8010000 0x10000>;
>> +                                     interrupts = <11>;
>> +                             };
>
> Is the usb implementation compatible to an existing one? Many SoCs
> use one of ehci, ohci or musb. If that's the case, you should look
> at the respective bindings.
>
>> +                             sata@0xb00f0000 {
>> +                                     compatible = "sirf,prima2-sata";
>> +                                     reg = <0xb8020000 0x10000>;
>> +                                     interrupts = <37>;
>> +                             };
>
> Same thing here. Most sata controllers are compatible to some
> standard implementation.

ok. i see :-). let me have some check with ic guys and send v4 with these fixes.

>
>> +                             security@0xb00f0000 {
>> +                                     compatible = "sirf,prima2-security";
>> +                                     reg = <0xb8030000 0x10000>;
>> +                                     interrupts = <42>;
>> +                             };
>> +                     };
>> +             };
>> +     };
>> +};
>
>        Arnd
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>
Thanks
barry
Russell King - ARM Linux July 6, 2011, 12:25 p.m. UTC | #4
On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote:
> diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h
> new file mode 100644
> index 0000000..fc54f16
> --- /dev/null
> +++ b/arch/arm/mach-prima2/include/mach/io.h
> @@ -0,0 +1,21 @@
> +/*
> + * arch/arm/mach-prima2/include/mach/io.h
> + *
> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2 or later.
> + */
> +
> +#ifndef __MACH_PRIMA2_IO_H
> +#define __MACH_PRIMA2_IO_H
> +
> +#define IO_SPACE_LIMIT 0xffffffff

Can folk please start putting comments in their io.h file explaining their
choice for this definition?  Looking through the existing files, it is
almost impossible to infer the reason the value was picked, which makes
future maintanence a headache.

IO_SPACE_LIMIT sets the upper bound for the PCI/ISA style IO accessor
macros (inb, et.al.)

My guidance is:

1. If you have no support for ISA/PCI/PC card drivers, then set this to
   zero to prevent ISA/PCI drivers reserving IO port space.  You should
   be able to leave __io() set to __typesafe_io() without risking any
   ISA driver stamping on memory as those drivers should no longer
   successfully initialize with this set to zero.

2. If you have MMIO-mapped IO space (eg, a PCI bridge which forwards
   MMIO accesses in a window to PCI IO space) or equivalent, then set
   this to the size of the window, or 64K-1.  Explain this.

3. If you have MMIO-mapped IO space which is scattered (eg, multiple
   PC cards with their IO space individually mapped as separate 64K
   blocks) then explain this and set it to 0xffffffff for the time
   being.

In any case, having the chosen value documented, and if it is for
specific devices on the board, documenting that too, would really
help.

I shall be making this change to asm/io.h shortly:

 #include <mach/io.h>

+/*
+ * This is the limit of PCI/ISA/PC card IO space, which is by default
+ * 64K if we have PC card, PCI or ISA support.  Otherwise, default to
+ * zero to prevent ISA/PCI drivers claiming IO space (and potentially
+ * oopsing.)
+ *
+ * Only set this larger if you really need inb() et.al. to operate over
+ * a larger address space (eg, for multiple MMIO-mapped PC card sockets
+ * as found on SA11x0 and PXA.)
+ */
+#ifndef IO_SPACE_LIMIT
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
+#define IO_SPACE_LIMIT ((resource_size_t)0xffff)
+#else
+#define IO_SPACE_LIMIT ((resource_size_t)0)
+#endif
+#endif

Thanks.
Arnd Bergmann July 6, 2011, 12:42 p.m. UTC | #5
On Wednesday 06 July 2011, Russell King - ARM Linux wrote:
> On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote:
> > diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-
> > +
> > +#ifndef __MACH_PRIMA2_IO_H
> > +#define __MACH_PRIMA2_IO_H
> > +
> > +#define IO_SPACE_LIMIT 0xffffffff
> 
> Can folk please start putting comments in their io.h file explaining their
> choice for this definition?  Looking through the existing files, it is
> almost impossible to infer the reason the value was picked, which makes
> future maintanence a headache.

I had the same comment for one of the earlier versions of the patch
set, but we agreed that I'd come up with a way to remove this at a
later stage for all platforms that don't have PC-style PIO.

Right now, the only platforms that use a value other than 0xffffffff
are ones that actually have PCI and set it to 0xffff.

> IO_SPACE_LIMIT sets the upper bound for the PCI/ISA style IO accessor
> macros (inb, et.al.)
> 
> My guidance is:
> 
> 1. If you have no support for ISA/PCI/PC card drivers, then set this to
>    zero to prevent ISA/PCI drivers reserving IO port space.  You should
>    be able to leave __io() set to __typesafe_io() without risking any
>    ISA driver stamping on memory as those drivers should no longer
>    successfully initialize with this set to zero.
> 
> 2. If you have MMIO-mapped IO space (eg, a PCI bridge which forwards
>    MMIO accesses in a window to PCI IO space) or equivalent, then set
>    this to the size of the window, or 64K-1.  Explain this.
> 
> 3. If you have MMIO-mapped IO space which is scattered (eg, multiple
>    PC cards with their IO space individually mapped as separate 64K
>    blocks) then explain this and set it to 0xffffffff for the time
>    being.

Sounds good.

> I shall be making this change to asm/io.h shortly:
> 
>  #include <mach/io.h>
> 
> +/*
> + * This is the limit of PCI/ISA/PC card IO space, which is by default
> + * 64K if we have PC card, PCI or ISA support.  Otherwise, default to
> + * zero to prevent ISA/PCI drivers claiming IO space (and potentially
> + * oopsing.)
> + *
> + * Only set this larger if you really need inb() et.al. to operate over
> + * a larger address space (eg, for multiple MMIO-mapped PC card sockets
> + * as found on SA11x0 and PXA.)
> + */
> +#ifndef IO_SPACE_LIMIT
> +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
> +#define IO_SPACE_LIMIT ((resource_size_t)0xffff)
> +#else
> +#define IO_SPACE_LIMIT ((resource_size_t)0)
> +#endif
> +#endif

Good idea. The related change that I want to do is to conditionalize
all drivers that require PC-style I/O on the respective bus they
use, so we can also remove the __io macro for platforms that don't
need it and catch all drivers using inb/outb at compile time.

To do that, I'm working on a patch set that splits the 8250
driver into separate parts for platform drivers (mostly MMIO)
and ISA drivers (mostly PIO), since that seems to be the only
driver that we need on non-PIO platforms that uses inb/outb
directly.

	Arnd
Russell King - ARM Linux July 6, 2011, 1:09 p.m. UTC | #6
On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote:
> Good idea. The related change that I want to do is to conditionalize
> all drivers that require PC-style I/O on the respective bus they
> use, so we can also remove the __io macro for platforms that don't
> need it and catch all drivers using inb/outb at compile time.

And what about those which use ioport_map() and ioread/write ?

The approach of setting IO_SPACE_LIMIT to zero makes those harmless
even if inb/outb are provided.

> To do that, I'm working on a patch set that splits the 8250
> driver into separate parts for platform drivers (mostly MMIO)
> and ISA drivers (mostly PIO), since that seems to be the only
> driver that we need on non-PIO platforms that uses inb/outb
> directly.

I don't really see the point of that given the ioread/iowrite et.al.
semantics.

And note that ioread/iowrite are unsupportable on some ARM platforms
with ISA because of weird addressing techniques (and that renders
PATA unsupportable on those platforms, while the old IDE stuff can
continue to work with CF cards.)
Russell King - ARM Linux July 6, 2011, 1:29 p.m. UTC | #7
On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote:
> I had the same comment for one of the earlier versions of the patch
> set, but we agreed that I'd come up with a way to remove this at a
> later stage for all platforms that don't have PC-style PIO.
> 
> Right now, the only platforms that use a value other than 0xffffffff
> are ones that actually have PCI and set it to 0xffff.

As I point out, you can't use that as a reason to work out why the macro
is being set.  Various platforms have it set to 0xffffffff, and use the
PCI/ISA IO accessor with virtual memory addresses provided by (eg) the
PCMCIA subsystem - SA11x0 and PXA come to mind on that.

The problem there is that we can't just change the thing because there is
that constant thorn known as cs89x0.c, which also uses these macros, and
that driver has never been properly updated (it contains _lots_ of platform
specific hacks in it.)  Changing the base address for the PCI/ISA IO
accessor on those platforms is likely to completely break at least this
driver.

Plus there are is at least one platform which sets it to 0xffff yet
doesn't appear to have PCI selected (VT8500).  So I don't think we can
even use the 64K-1 value to infer anything about the platform.

This is why we need the reasoning behind the value for this macro
documented.
Arnd Bergmann July 6, 2011, 1:44 p.m. UTC | #8
On Wednesday 06 July 2011, Barry Song wrote:

> > I would normally recommend defining the ranges so that addresses are local
> > to the respective bus, like
> >
> >        axi {
> >                ranges = <0 0x40000000 0x80000000>;
> >
> >                sys-iobg {
> >                        ranges = <0 0x48000000 0x40000>;
> >                        clock-controller@0x88000000 {
> >                               compatible = "sirf,prima2-clkc";
> >                               reg = <0 0x1000>;
> >                        }
> >
> >                        reset-controller@0x88010000 {
> >                               compatible = "sirf,prima2-rstc";
> >                               reg = <0x10000 0x1000>;
> >                        };
> >                }
> >        }
> 
> i am not sure whether it make us a little more difficult to know the
> real address at first glance.we will need to calculate.
> all addresses are 1:1 mapped in this chip. bus map can work even
> though we only give "ranges;" without real "ranges = <0x....>;".

So each iobg still passes down the entire 32-bit address?

Note that you never have to do the calculation in the driver
source, of_iomap and the resource logic both take care of this.

There are multiple ways to handle this, and an empty ranges property
usually works fine, but I find that less readable.

Another way to handle these is to have a separate range for
each child bus, as in arch/powerpc/boot/dts/gef_ppc9a.dts

To stay in the example, this would mean doing something like

        axi {
		#address-cells = <2>;
                #size-cells = <1>;

                ranges = <0 0 0x80000000 0x08000000 // axi devices
			  1 0 0x88000000 0x08000000 // sys-iobg
			  2 0 0x90000000 0x00010000 // mem-iobg
			  3 0 0x90010000 0x07fe0000 // disp-iobg
                          ... >;

                l2-cache-controller@80040000 {
                        compatible = "arm,pl310-cache";
                        reg = <0 0x40000 0x1000>;
                        interrupts = <59>;
                };

                sys-iobg {
			#address-cells = <1>;
        	        #size-cells = <1>;
                        ranges = <1 0 0 0x40000>;
                        clock-controller@88000000 {
                               compatible = "sirf,prima2-clkc";
                               reg = <0 0x1000>;
                        }

                        reset-controller@88010000 {
                               compatible = "sirf,prima2-rstc";
                               reg = <0x10000 0x1000>;
                        };
                }
        }



> >> +
> >> +                     graphics-iobg {
> >> +                             compatible = "simple-bus";
> >> +                             #address-cells = <1>;
> >> +                             #size-cells = <1>;
> >> +                             ranges = <0x98000000 0x98000000 0x8000000>;
> >> +
> >> +                             graphics@0x98000000 {
> >> +                                     compatible = "sirf,prima2-graphics";
> >> +                                     reg = <0x98000000 0x8000000>;
> >> +                                     interrupts = <6>;
> >> +                             };
> >> +                     };
> >
> > Are the display and graphics units CSR developments? If the GPU is
> > in fact licensed from someone else (powervr, arm, ...), you should
> > probably list the actual name of the device.
> 
> GPU is powervr sgx 531, so could we define compatible as "powervr,sgx531"?

Probably yes. You should have a look if there are already bindings for
this that define other attributes. Also, if there is any customization
inside of the chip, you should have another more specific identifier
that makes it possible that this is the version that csr has modified.

> >> +                     multimedia-iobg {
> >> +                             compatible = "simple-bus";
> >> +                             #address-cells = <1>;
> >> +                             #size-cells = <1>;
> >> +                             ranges = <0xa0000000 0xa0000000 0x8000000>;
> >> +
> >> +                             multimedia@0xa0000000 {
> >> +                                     compatible = "sirf,prima2-multimedia";
> >> +                                     reg = <0xa0000000 0x8000000>;
> >> +                                     interrupts = <5>;
> >> +                             };
> >> +                     };
> >
> > "multimedia" sounds like a too generic term. What does this do?
> 
>  video decoding.

sirf,prima2-video-codec is probably better than, but if anyone has other
suggestions, you could use something else.

> > Are these proprietary uarts, or are they compatible to 8250 and the
> > like? You might want to set a clock-frequency property as of_serial.c
> > uses.
> 
> it is not compatible with 8250 .

ok

> > Are these rtc implementations related? From the register layout, I would
> > guess that they are supposed to be used by the same driver, so it's
> > probably a good idea to add a "compatible" property with a common name
> > for all three.
> 
> in fact, because they are slow, they can't be accessed by mapped
> address directly, the only common point they have is we need to access
> them through mapped address in rtc-iobg indirectly just like we access
> i2c/spi/nand devices.
> 
> they are three different devices with different purpose and register
> layout in fact.

Ok.

	Arnd
Arnd Bergmann July 6, 2011, 2:41 p.m. UTC | #9
On Wednesday 06 July 2011, Russell King - ARM Linux wrote:
> On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote:
> > Good idea. The related change that I want to do is to conditionalize
> > all drivers that require PC-style I/O on the respective bus they
> > use, so we can also remove the __io macro for platforms that don't
> > need it and catch all drivers using inb/outb at compile time.
> 
> And what about those which use ioport_map() and ioread/write ?

ioport_map should return an error if IO_SPACE_LIMIT is zero.
I also tried just forcing a link error by not providing any
ioport_map in that case, which didn't cause major problems
in my tests. If that works for the general case, I'd prefer that
option.

If we have no drivers using ioport_map, ioread/iowrite automatically
becomes a non-issue.

> The approach of setting IO_SPACE_LIMIT to zero makes those harmless
> even if inb/outb are provided.

I'm not arguing against setting IO_SPACE_LIMIT to zero, I just want
to do more on top of that. There are numerous drivers that we are
able to enable on non-PIO machines that clearly cannot work because
they depend on a bus that's not there. This includes stuff like
gameport, pcmcia, or various rtc.

> > To do that, I'm working on a patch set that splits the 8250
> > driver into separate parts for platform drivers (mostly MMIO)
> > and ISA drivers (mostly PIO), since that seems to be the only
> > driver that we need on non-PIO platforms that uses inb/outb
> > directly.
> 
> I don't really see the point of that given the ioread/iowrite et.al.
> semantics.
> 
> And note that ioread/iowrite are unsupportable on some ARM platforms
> with ISA because of weird addressing techniques (and that renders
> PATA unsupportable on those platforms, while the old IDE stuff can
> continue to work with CF cards.)

Different issue, but I'm sure that they are supportable. What we ended
up doing on the PCIe bus in one of the Cell blades was to encode
special regions in the __iomem token returned from pci_iomap that
would trigger indirect access in iowrite32. For the simple case where
all buses use the same weird addressing, the regular CONFIG_GENERIC_IOMAP
support should be enough already.

	Arnd
Russell King - ARM Linux July 6, 2011, 2:51 p.m. UTC | #10
On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote:
> Right now, the only platforms that use a value other than 0xffffffff
> are ones that actually have PCI and set it to 0xffff.

Note that those platforms using soc_common need to have their inb() et.al.
defined to be compatible with readb() et.al. as soc_common ioremaps the
IO resource and passes that into the PCMCIA layer as the per-socket IO
offset.

The alternative is to rip that out, and use fixed mappings and fixed
per-SoC IO offsets.

So, I think as part of this idea, we should - for the time being -
default IO_SPACE_LIMIT to 0xffffffff if PCMCIA_SOC_COMMON is enabled in
any way.  The plus side is that we get that condition documented, and
so can do something about it later.
Arnd Bergmann July 6, 2011, 3:03 p.m. UTC | #11
On Wednesday 06 July 2011, Russell King - ARM Linux wrote:
> On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote:
> > Right now, the only platforms that use a value other than 0xffffffff
> > are ones that actually have PCI and set it to 0xffff.
> 
> Note that those platforms using soc_common need to have their inb() et.al.
> defined to be compatible with readb() et.al. as soc_common ioremaps the
> IO resource and passes that into the PCMCIA layer as the per-socket IO
> offset.
> 
> The alternative is to rip that out, and use fixed mappings and fixed
> per-SoC IO offsets.
> 
> So, I think as part of this idea, we should - for the time being -
> default IO_SPACE_LIMIT to 0xffffffff if PCMCIA_SOC_COMMON is enabled in
> any way.  The plus side is that we get that condition documented, and
> so can do something about it later.

Ok, sounds good.

	Arnd
Barry Song July 6, 2011, 3:16 p.m. UTC | #12
2011/7/6 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote:
>> +static int sirfsoc_timer_set_next_event(unsigned long delta,
>> +     struct clock_event_device *ce)
>> +{
>> +     unsigned long now, next;
>> +
>> +     writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
>> +     now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
>> +     do {
>> +             next = now + delta;
>> +             writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
>> +             writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
>> +             now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
>> +     } while ((next - now) > delta);
>> +
>> +     return 0;
>> +}
>
> Please have a look at any of the callsites of clockevents_program_event()
> in kernel/time/.  You'll notice that they loop in some fashion should your
> set_next_event() return -ETIME.

ok. looks like the function can be fixed to:

static int sirfsoc_timer_set_next_event(unsigned long delta,
                struct clock_event_device *ce)
{
        unsigned long now, next;

        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base +
SIRFSOC_TIMER_LATCH);
        now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);

        next = now + delta;
        writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base +
SIRFSOC_TIMER_LATCH);
        now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);

        return next - now > delta ? -ETIME : 0;
}


>
> As there is the possibility that if you can't program the event (because
> it has already passed) then it is likely that there is some work which
> needs to be done before the next event is set.  So the repeat logic should
> stay in the common code and not be duplicated in each platform.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Russell King - ARM Linux July 6, 2011, 3:25 p.m. UTC | #13
On Wed, Jul 06, 2011 at 04:41:05PM +0200, Arnd Bergmann wrote:
> On Wednesday 06 July 2011, Russell King - ARM Linux wrote:
> > And note that ioread/iowrite are unsupportable on some ARM platforms
> > with ISA because of weird addressing techniques (and that renders
> > PATA unsupportable on those platforms, while the old IDE stuff can
> > continue to work with CF cards.)
> 
> Different issue, but I'm sure that they are supportable.

Ha, you've no idea what kind of messed up ideas hardware people come up
with then.  Take this - this is real hardware which I've had Linux
running on continuously for the last 13 years.  Here is the /proc/ioports:

0000-000f : pcmcia_socket0
  0000-000f : pcmcia0.0
    0000-0007 : ide-cs
    000e-000e : ide-cs
0220-0238 : am79c961
  0220-0237 : eth0
0278-027f : reserved
02f8-02ff : serial
0300-030f : pcmcia_socket1
  0300-030f : pcmcia1.0
0378-037a : parport0
03bc-03be : reserved
03e0-03e1 : i82365
03f8-03ff : serial

ISA devices have either 8 data lines or 16 data lines.
1) If the device has 8 data lines, then it is accessible on physical
   addresses ISA_BASE + (ioport << 2).

2) If the device has 16 data lines, then:
   a) for an ISA device which transfers 8-bit accesses on the low byte
      lane, registers are accessible at ISA_BASE + ((ioport & ~1) << 1).
      For even ioports, use a byte access.  For odd ioports, use a word
      access.

   b) for an ISA Device which transfers even 8-bit accesses on the low
      byte lane and odd 8-bit accesses on the high byte lane, registers
      are accessible at ISA_BASE + ((ioport & ~1) << 1) + (ioport & 1).

(PCs sort this out via the IOCS16 signal, which is not connected in this
example.)

   c) for 16-bit accesses, these are always naturally aligned, so these
      registers are accessible at ISA_BASE + ((ioport & ~1) << 1).

So, let's look at some examples.  Serial ports (standard 16550A) at ISA
bus address 0x2f8 and 0x3f8.  So, the translation from ISA address to
bus offset is:
	0x2f8 => 0xbe0	0x3f8 => 0xfe0
	0x2f9 => 0xbe4	0x3f9 => 0xfe4
	0x2fa => 0xbe8	0x3fa => 0xfe8 etc.

The PCMCIA controller is a standard i82365 at the standard ISA address
of 0x3e0.  This has the following translation:
	0x3e0 => 0x7c0(b)
	0x3e1 => 0x7c0(w)

An inserted PCMCIA card may require:
	0x100 => 0x200(b)
	0x101 => 0x200(w) or 0x201(b)
	0x102 => 0x204(b)
	0x103 => 0x204(w) or 0x205(b)

So, if you do an ioport_map() to convert from the ISA address to a bus
specific address, and _then_ add the device specific offset, you end up
with information lost, and you no longer know how to manipulate the
cookie into the correct bus address and access type.

The alternative is you keep the returned ioport cookie the same as the
ISA address, and do all the conversion in ioread/iowrite - that's even
more horrible than how it's already doing because then you need to know
if its real MMIO or IO, and whether it's an 8 bit IO device, 16-bit
low byte lane IO device, or a 16-bit both byte lane IO device.  Plus
whether the MMIO is in the broken PCMCIA controller IO space (CPU
address bit 11 missing and CPU address bit 19 mapped to two bus
address bits...)
Barry Song July 6, 2011, 4:09 p.m. UTC | #14
2011/7/6 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote:
>> diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h
>> new file mode 100644
>> index 0000000..fc54f16
>> --- /dev/null
>> +++ b/arch/arm/mach-prima2/include/mach/io.h
>> @@ -0,0 +1,21 @@
>> +/*
>> + * arch/arm/mach-prima2/include/mach/io.h
>> + *
>> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *
>> + * Licensed under GPLv2 or later.
>> + */
>> +
>> +#ifndef __MACH_PRIMA2_IO_H
>> +#define __MACH_PRIMA2_IO_H
>> +
>> +#define IO_SPACE_LIMIT 0xffffffff
>
> Can folk please start putting comments in their io.h file explaining their
> choice for this definition?  Looking through the existing files, it is
> almost impossible to infer the reason the value was picked, which makes
> future maintanence a headache.
>
> IO_SPACE_LIMIT sets the upper bound for the PCI/ISA style IO accessor
> macros (inb, et.al.)
>
> My guidance is:
>
> 1. If you have no support for ISA/PCI/PC card drivers, then set this to
>   zero to prevent ISA/PCI drivers reserving IO port space.  You should
>   be able to leave __io() set to __typesafe_io() without risking any
>   ISA driver stamping on memory as those drivers should no longer
>   successfully initialize with this set to zero.
>
> 2. If you have MMIO-mapped IO space (eg, a PCI bridge which forwards
>   MMIO accesses in a window to PCI IO space) or equivalent, then set
>   this to the size of the window, or 64K-1.  Explain this.
>
> 3. If you have MMIO-mapped IO space which is scattered (eg, multiple
>   PC cards with their IO space individually mapped as separate 64K
>   blocks) then explain this and set it to 0xffffffff for the time
>   being.
>
> In any case, having the chosen value documented, and if it is for
> specific devices on the board, documenting that too, would really
> help.
>
> I shall be making this change to asm/io.h shortly:
>
>  #include <mach/io.h>
>
> +/*
> + * This is the limit of PCI/ISA/PC card IO space, which is by default
> + * 64K if we have PC card, PCI or ISA support.  Otherwise, default to
> + * zero to prevent ISA/PCI drivers claiming IO space (and potentially
> + * oopsing.)
> + *
> + * Only set this larger if you really need inb() et.al. to operate over
> + * a larger address space (eg, for multiple MMIO-mapped PC card sockets
> + * as found on SA11x0 and PXA.)
> + */
> +#ifndef IO_SPACE_LIMIT
> +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
> +#define IO_SPACE_LIMIT ((resource_size_t)0xffff)
> +#else
> +#define IO_SPACE_LIMIT ((resource_size_t)0)
> +#endif
> +#endif

if you define that in asm/io.h as you said:

#ifndef IO_SPACE_LIMIT
#if defined(PCMCIA_SOC_COMMON)
#define  IO_SPACE_LIMIT ((resource_size_t)0xffffffff)
#else
#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
#define IO_SPACE_LIMIT ((resource_size_t)0xffff)
#else
#define IO_SPACE_LIMIT ((resource_size_t)0)
#endif
#endif
#endif

i'd like to delete IO_SPACE_LIMIT in my io.h.

otherwise, i'd like to try "#define IO_SPACE_LIMIT
((resource_size_t)0)" in my io.h since i have no real
CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON.

>
> Thanks.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Arnd Bergmann July 6, 2011, 4:13 p.m. UTC | #15
On Wednesday 06 July 2011, Russell King - ARM Linux wrote:
> Ha, you've no idea what kind of messed up ideas hardware people come up
> with then.  Take this - this is real hardware which I've had Linux
> running on continuously for the last 13 years.  Here is the /proc/ioports:
> 
< skipped lots of interesting information about how messed up the hardware can be>

> So, if you do an ioport_map() to convert from the ISA address to a bus
> specific address, and then add the device specific offset, you end up
> with information lost, and you no longer know how to manipulate the
> cookie into the correct bus address and access type.
> 
> The alternative is you keep the returned ioport cookie the same as the
> ISA address, and do all the conversion in ioread/iowrite - that's even
> more horrible than how it's already doing because then you need to know
> if its real MMIO or IO, and whether it's an 8 bit IO device, 16-bit
> low byte lane IO device, or a 16-bit both byte lane IO device.  Plus
> whether the MMIO is in the broken PCMCIA controller IO space (CPU
> address bit 11 missing and CPU address bit 19 mapped to two bus
> address bits...)

Well, first of all, I never suggested converting drivers to use
iowrite, you brought that up. So as long as the 16-bit ISA driver
keep using inb/outb, an iowrite implementation would not need to
bother about this specific problem and don't even need a private
iowrite implementation but instead move that platform over to use
CONFIG_GENERIC_IOMAP.

What lib/iomap.c does is indeed to look at the address, by default
it assumes that __iomem tokens below 0x10000 are IO ports, while
larger values are MMIO addresses. This appears to work fine on x86,
and AFAICT, it should still work with both the botched PIO mapping
(minus the 16-bit devices) and the botched MMIO mapping, since both
will just end up calling the fixups in arch/arm/mach-ebsa110/io.c.

The only problem you will hit is when there are ISA devices with
MMIO addresses below 0x40000, which is impossible on PCs but
perhaps not on arbitrarily incompatible ISA buses.

	Arnd
Nicolas Pitre July 6, 2011, 4:35 p.m. UTC | #16
On Wed, 6 Jul 2011, Arnd Bergmann wrote:
> On Wednesday 06 July 2011, Russell King - ARM Linux wrote:
> > I shall be making this change to asm/io.h shortly:
> > 
> >  #include <mach/io.h>
> > 
> > +/*
> > + * This is the limit of PCI/ISA/PC card IO space, which is by default
> > + * 64K if we have PC card, PCI or ISA support.  Otherwise, default to
> > + * zero to prevent ISA/PCI drivers claiming IO space (and potentially
> > + * oopsing.)
> > + *
> > + * Only set this larger if you really need inb() et.al. to operate over
> > + * a larger address space (eg, for multiple MMIO-mapped PC card sockets
> > + * as found on SA11x0 and PXA.)
> > + */
> > +#ifndef IO_SPACE_LIMIT
> > +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
> > +#define IO_SPACE_LIMIT ((resource_size_t)0xffff)
> > +#else
> > +#define IO_SPACE_LIMIT ((resource_size_t)0)
> > +#endif
> > +#endif
> 
> Good idea. The related change that I want to do is to conditionalize
> all drivers that require PC-style I/O on the respective bus they
> use, so we can also remove the __io macro for platforms that don't
> need it and catch all drivers using inb/outb at compile time.

In the spirit of removing as much machine specific and globally used 
defines (see my patch series removing a bunch of mach/memory.h 
instances), I'd like to see a solution that would make IO_SPACE_LIMIT 
into a variable, or having the same definition with a fixed mapping, for 
as many SOCs as possible.


Nicolas
Russell King - ARM Linux July 6, 2011, 5:42 p.m. UTC | #17
On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote:
> In the spirit of removing as much machine specific and globally used 
> defines (see my patch series removing a bunch of mach/memory.h 
> instances), I'd like to see a solution that would make IO_SPACE_LIMIT 
> into a variable, or having the same definition with a fixed mapping, for 
> as many SOCs as possible.

In theory it should be possible to have it defined as 64K across
everything.  ISTR that you were against that with SA1100 platforms
because of the PCMCIA problem though...
Arnd Bergmann July 6, 2011, 5:59 p.m. UTC | #18
On Wednesday 06 July 2011 19:42:48 Russell King - ARM Linux wrote:
> On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote:
> > In the spirit of removing as much machine specific and globally used 
> > defines (see my patch series removing a bunch of mach/memory.h 
> > instances), I'd like to see a solution that would make IO_SPACE_LIMIT 
> > into a variable, or having the same definition with a fixed mapping, for 
> > as many SOCs as possible.
> 
> In theory it should be possible to have it defined as 64K across
> everything.  ISTR that you were against that with SA1100 platforms
> because of the PCMCIA problem though...

If the problem is only with a few platforms, my preference would be
to hardcode this to 64k or 0, and leave the platforms that require
something else out of the common zImage for now.

For all platforms that only need the 64k window and don't have any
of other special needs, I would also like to hardcode the virtual
address window eventually, so that inb/outb can still be a single
instruction.

	Arnd
Nicolas Pitre July 6, 2011, 6:09 p.m. UTC | #19
On Wed, 6 Jul 2011, Russell King - ARM Linux wrote:

> On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote:
> > In the spirit of removing as much machine specific and globally used 
> > defines (see my patch series removing a bunch of mach/memory.h 
> > instances), I'd like to see a solution that would make IO_SPACE_LIMIT 
> > into a variable, or having the same definition with a fixed mapping, for 
> > as many SOCs as possible.
> 
> In theory it should be possible to have it defined as 64K across
> everything.  ISTR that you were against that with SA1100 platforms
> because of the PCMCIA problem though...

To be honest, if I was against it, the reasons have long been swapped 
out of my brain.  And since those machines with pretenses of ISA-type 
buses are fading away in terms of actual users, I don't really mind if 
they are not consolidated.  As long as those machines with PCI or none 
of it can rely on shared definitions that should be good enough.


Nicolas
Nicolas Pitre July 6, 2011, 6:11 p.m. UTC | #20
On Wed, 6 Jul 2011, Arnd Bergmann wrote:

> On Wednesday 06 July 2011 19:42:48 Russell King - ARM Linux wrote:
> > On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote:
> > > In the spirit of removing as much machine specific and globally used 
> > > defines (see my patch series removing a bunch of mach/memory.h 
> > > instances), I'd like to see a solution that would make IO_SPACE_LIMIT 
> > > into a variable, or having the same definition with a fixed mapping, for 
> > > as many SOCs as possible.
> > 
> > In theory it should be possible to have it defined as 64K across
> > everything.  ISTR that you were against that with SA1100 platforms
> > because of the PCMCIA problem though...
> 
> If the problem is only with a few platforms, my preference would be
> to hardcode this to 64k or 0, and leave the platforms that require
> something else out of the common zImage for now.
> 
> For all platforms that only need the 64k window and don't have any
> of other special needs, I would also like to hardcode the virtual
> address window eventually, so that inb/outb can still be a single
> instruction.

I would say that hardcoding the virtual mapping is probably the first 
thing to do.  That would certainly simplify the rest of the kernel.


Nicolas
Russell King - ARM Linux July 6, 2011, 6:15 p.m. UTC | #21
On Wed, Jul 06, 2011 at 02:11:29PM -0400, Nicolas Pitre wrote:
> On Wed, 6 Jul 2011, Arnd Bergmann wrote:
> > If the problem is only with a few platforms, my preference would be
> > to hardcode this to 64k or 0, and leave the platforms that require
> > something else out of the common zImage for now.
> > 
> > For all platforms that only need the 64k window and don't have any
> > of other special needs, I would also like to hardcode the virtual
> > address window eventually, so that inb/outb can still be a single
> > instruction.
> 
> I would say that hardcoding the virtual mapping is probably the first 
> thing to do.  That would certainly simplify the rest of the kernel.

We _used_ to hard-code that mapping, but it became painful to supply
that information into soc_common, which isn't supposed to be ARM
specific.

So going back to hard-coded mappings is a backwards step - essentially
reintroducing one problem which was already solved to resolve a different
problem.

That isn't progress, that's merely changing one resolution for another.
Nicolas Pitre July 6, 2011, 6:35 p.m. UTC | #22
On Wed, 6 Jul 2011, Russell King - ARM Linux wrote:

> On Wed, Jul 06, 2011 at 02:11:29PM -0400, Nicolas Pitre wrote:
> > On Wed, 6 Jul 2011, Arnd Bergmann wrote:
> > > If the problem is only with a few platforms, my preference would be
> > > to hardcode this to 64k or 0, and leave the platforms that require
> > > something else out of the common zImage for now.
> > > 
> > > For all platforms that only need the 64k window and don't have any
> > > of other special needs, I would also like to hardcode the virtual
> > > address window eventually, so that inb/outb can still be a single
> > > instruction.
> > 
> > I would say that hardcoding the virtual mapping is probably the first 
> > thing to do.  That would certainly simplify the rest of the kernel.
> 
> We _used_ to hard-code that mapping, but it became painful to supply
> that information into soc_common, which isn't supposed to be ARM
> specific.
> 
> So going back to hard-coded mappings is a backwards step - essentially
> reintroducing one problem which was already solved to resolve a different
> problem.
> 
> That isn't progress, that's merely changing one resolution for another.

Let's simply let the problematic cases RIP then.  Maybe those
PCMCIA equipped ARM board will get out of commission eventually.


Nicolas
Russell King - ARM Linux July 6, 2011, 7:10 p.m. UTC | #23
On Thu, Jul 07, 2011 at 12:09:24AM +0800, Barry Song wrote:
> if you define that in asm/io.h as you said:
> 
> #ifndef IO_SPACE_LIMIT
> #if defined(PCMCIA_SOC_COMMON)
> #define  IO_SPACE_LIMIT ((resource_size_t)0xffffffff)
> #else
> #if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
> #define IO_SPACE_LIMIT ((resource_size_t)0xffff)
> #else
> #define IO_SPACE_LIMIT ((resource_size_t)0)
> #endif
> #endif
> #endif
> 
> i'd like to delete IO_SPACE_LIMIT in my io.h.
>
> otherwise, i'd like to try "#define IO_SPACE_LIMIT
> ((resource_size_t)0)" in my io.h since i have no real
> CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON.

Thanks - stopping the 0xffffffff madness in new platforms is great.

If you also omit the definition for __io() and set NO_IOPORT in your
Kconfig, you should also end up with inb() et.al. undefined by asm/io.h,
which should cause build-time failures if an ISA/PCI/PCMCIA driver
attempts to build.
Arnd Bergmann July 6, 2011, 8:31 p.m. UTC | #24
On Wednesday 06 July 2011 21:10:00 Russell King - ARM Linux wrote:
> On Thu, Jul 07, 2011 at 12:09:24AM +0800, Barry Song wrote:
> > if you define that in asm/io.h as you said:
> > 
> > #ifndef IO_SPACE_LIMIT
> > #if defined(PCMCIA_SOC_COMMON)
> > #define  IO_SPACE_LIMIT ((resource_size_t)0xffffffff)
> > #else
> > #if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
> > #define IO_SPACE_LIMIT ((resource_size_t)0xffff)
> > #else
> > #define IO_SPACE_LIMIT ((resource_size_t)0)
> > #endif
> > #endif
> > #endif
> > 
> > i'd like to delete IO_SPACE_LIMIT in my io.h.
> >
> > otherwise, i'd like to try "#define IO_SPACE_LIMIT
> > ((resource_size_t)0)" in my io.h since i have no real
> > CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON.
> 
> Thanks - stopping the 0xffffffff madness in new platforms is great.

FWIW, I've double-checked the Xilinx zynq platform that I've already queued
up for 3.1: this one defines IO_SPACE_LIMIT to 0xffff because PCI support
will get merged later, so that's fine.

> If you also omit the definition for __io() and set NO_IOPORT in your
> Kconfig, you should also end up with inb() et.al. undefined by asm/io.h,
> which should cause build-time failures if an ISA/PCI/PCMCIA driver
> attempts to build.

Just as a follow-up, this is what I was referring to in the other
sub-thread. Setting NO_IOPORT and removing __io does work for a lot
of things today, but breaks randconfig builds left and right. I want
to clean that up by adding 'depends on HAS_IOPORT' at the correct places
and then switch all platforms that don't need it to remove __io.

	Arnd
Russell King - ARM Linux July 6, 2011, 8:50 p.m. UTC | #25
On Wed, Jul 06, 2011 at 10:31:50PM +0200, Arnd Bergmann wrote:
> Just as a follow-up, this is what I was referring to in the other
> sub-thread. Setting NO_IOPORT and removing __io does work for a lot
> of things today, but breaks randconfig builds left and right. I want
> to clean that up by adding 'depends on HAS_IOPORT' at the correct places
> and then switch all platforms that don't need it to remove __io.

It's not that easy.  NO_IOPORT was brought in by Viro to work around
various platforms which broke - such as RiscPC.  Viro was well aware
of that platform, and we had a discussion about it.

The conclusion (I think) was that NO_IOPORT was to prevent ioport_map()
et.al. on platforms which couldn't provide a sane definition - eg:

(11 Feb 2007)...
19:50 < rmk> inb(port) | inb(port + 1) << 8 is not identical to addr = ioport_map(port); readb(addr) | readb(addr + 1)
19:51 < rmk> inb(port) | inb(port + 1) << 8 _is_ identical to addr = ioport_map(port); readb(addr) | readb(addr + (1 << 2))
19:53 < rmk> inw(port) | inw(port + 2) equates to addr = ioport_map(port); readw(addr) | readw(addr + (2 << 2))

So, while the above referred to platform uses inb etc, it sets
NO_IOPORT to stop the devres breakage, which in turn disables
HAS_IOPORT.

So, HAS_IOPORT does not mean the ISA/PCI accessors are not provided.
It means there will be no devres support for it and ioport_map() is
probably missing.

I've added Viro to this thread in case he'd like to correct me (if he
remembers the background to HAS_IOPORT/NO_IOPORT etc.)
Arnd Bergmann July 6, 2011, 9:21 p.m. UTC | #26
On Wednesday 06 July 2011 22:50:59 Russell King - ARM Linux wrote:
> On Wed, Jul 06, 2011 at 10:31:50PM +0200, Arnd Bergmann wrote:
> > Just as a follow-up, this is what I was referring to in the other
> > sub-thread. Setting NO_IOPORT and removing __io does work for a lot
> > of things today, but breaks randconfig builds left and right. I want
> > to clean that up by adding 'depends on HAS_IOPORT' at the correct places
> > and then switch all platforms that don't need it to remove __io.
> 
> It's not that easy.  NO_IOPORT was brought in by Viro to work around
> various platforms which broke - such as RiscPC.  Viro was well aware
> of that platform, and we had a discussion about it.
> 
> The conclusion (I think) was that NO_IOPORT was to prevent ioport_map()
> et.al. on platforms which couldn't provide a sane definition - eg:
> 
> (11 Feb 2007)...
> 19:50 < rmk> inb(port) | inb(port + 1) << 8 is not identical to addr = ioport_map(port); readb(addr) | readb(addr + 1)
> 19:51 < rmk> inb(port) | inb(port + 1) << 8 is identical to addr = ioport_map(port); readb(addr) | readb(addr + (1 << 2))
> 19:53 < rmk> inw(port) | inw(port + 2) equates to addr = ioport_map(port); readw(addr) | readw(addr + (2 << 2))
> 
> So, while the above referred to platform uses inb etc, it sets
> NO_IOPORT to stop the devres breakage, which in turn disables
> HAS_IOPORT.
> 
> So, HAS_IOPORT does not mean the ISA/PCI accessors are not provided.
> It means there will be no devres support for it and ioport_map() is
> probably missing.
> 
> I've added Viro to this thread in case he'd like to correct me (if he
> remembers the background to HAS_IOPORT/NO_IOPORT etc.)

Thanks for the exact reference. You've mentioned this before and I tried
to find the discussion but couldn't.

I understand that the original meaning of NO_IOPORT/HAS_IOPORT is very
limited, and I would like to extend it in a way to allow both the
scenario with inb/outb but without ioport_map and the case where you
have no PIO space at all.

CONFIG_HAS_IOPORT is nice in that it mirrors CONFIG_HAS_IOMEM for
readl/writel, so my preferred solution would be to repurpose that
symbol to mean that inb/outb are available, while introducing a
new symbol to mean that ioport_map is also available, e.g.
CONFIG_HAS_IOPORT_MAP for the cases where we now use CONFIG_HAS_IOPORT.

	Arnd
Barry Song July 7, 2011, 1:20 a.m. UTC | #27
2011/7/7 Arnd Bergmann <arnd@arndb.de>:
> On Wednesday 06 July 2011 21:10:00 Russell King - ARM Linux wrote:
>> On Thu, Jul 07, 2011 at 12:09:24AM +0800, Barry Song wrote:
>> > if you define that in asm/io.h as you said:
>> >
>> > #ifndef IO_SPACE_LIMIT
>> > #if defined(PCMCIA_SOC_COMMON)
>> > #define  IO_SPACE_LIMIT ((resource_size_t)0xffffffff)
>> > #else
>> > #if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
>> > #define IO_SPACE_LIMIT ((resource_size_t)0xffff)
>> > #else
>> > #define IO_SPACE_LIMIT ((resource_size_t)0)
>> > #endif
>> > #endif
>> > #endif
>> >
>> > i'd like to delete IO_SPACE_LIMIT in my io.h.
>> >
>> > otherwise, i'd like to try "#define IO_SPACE_LIMIT
>> > ((resource_size_t)0)" in my io.h since i have no real
>> > CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON.
>>
>> Thanks - stopping the 0xffffffff madness in new platforms is great.
>
> FWIW, I've double-checked the Xilinx zynq platform that I've already queued
> up for 3.1: this one defines IO_SPACE_LIMIT to 0xffff because PCI support
> will get merged later, so that's fine.

as far as i know, zynq still has some static mapping tables and board
file board_dt.c. as you have reviewed csr platform very carefully, i
guess those can get fixed in zynq later too :-)
xilinx zynq and csr prima2 should be the pioneering two new SoCs to
move to DT in arm for the moment. at least, these two things can try
to get same.

>
>> If you also omit the definition for __io() and set NO_IOPORT in your
>> Kconfig, you should also end up with inb() et.al. undefined by asm/io.h,
>> which should cause build-time failures if an ISA/PCI/PCMCIA driver
>> attempts to build.
>
> Just as a follow-up, this is what I was referring to in the other
> sub-thread. Setting NO_IOPORT and removing __io does work for a lot
> of things today, but breaks randconfig builds left and right. I want
> to clean that up by adding 'depends on HAS_IOPORT' at the correct places
> and then switch all platforms that don't need it to remove __io.
>
>        Arnd
>
Barry Song July 7, 2011, 2:26 a.m. UTC | #28
2011/7/6 Arnd Bergmann <arnd@arndb.de>:
> On Wednesday 06 July 2011, Barry Song wrote:
>
>> > I would normally recommend defining the ranges so that addresses are local
>> > to the respective bus, like
>> >
>> >        axi {
>> >                ranges = <0 0x40000000 0x80000000>;
>> >
>> >                sys-iobg {
>> >                        ranges = <0 0x48000000 0x40000>;
>> >                        clock-controller@0x88000000 {
>> >                               compatible = "sirf,prima2-clkc";
>> >                               reg = <0 0x1000>;
>> >                        }
>> >
>> >                        reset-controller@0x88010000 {
>> >                               compatible = "sirf,prima2-rstc";
>> >                               reg = <0x10000 0x1000>;
>> >                        };
>> >                }
>> >        }
>>
>> i am not sure whether it make us a little more difficult to know the
>> real address at first glance.we will need to calculate.
>> all addresses are 1:1 mapped in this chip. bus map can work even
>> though we only give "ranges;" without real "ranges = <0x....>;".
>
> So each iobg still passes down the entire 32-bit address?

yes. each iobg is basically transparent for address transferring.
ranges = <0x40000000 0x40000000 0x80000000>; should be ok.

>
> Note that you never have to do the calculation in the driver
> source, of_iomap and the resource logic both take care of this.
>
> There are multiple ways to handle this, and an empty ranges property
> usually works fine, but I find that less readable.
>
> Another way to handle these is to have a separate range for
> each child bus, as in arch/powerpc/boot/dts/gef_ppc9a.dts
>
> To stay in the example, this would mean doing something like
>
>        axi {
>                #address-cells = <2>;
>                #size-cells = <1>;
>
>                ranges = <0 0 0x80000000 0x08000000 // axi devices
>                          1 0 0x88000000 0x08000000 // sys-iobg
>                          2 0 0x90000000 0x00010000 // mem-iobg
>                          3 0 0x90010000 0x07fe0000 // disp-iobg
>                          ... >;
>
>                l2-cache-controller@80040000 {
>                        compatible = "arm,pl310-cache";
>                        reg = <0 0x40000 0x1000>;
>                        interrupts = <59>;
>                };
>
>                sys-iobg {
>                        #address-cells = <1>;
>                        #size-cells = <1>;
>                        ranges = <1 0 0 0x40000>;
>                        clock-controller@88000000 {
>                               compatible = "sirf,prima2-clkc";
>                               reg = <0 0x1000>;
>                        }
>
>                        reset-controller@88010000 {
>                               compatible = "sirf,prima2-rstc";
>                               reg = <0x10000 0x1000>;
>                        };
>                }
>        }
>
>
>
>> >> +
>> >> +                     graphics-iobg {
>> >> +                             compatible = "simple-bus";
>> >> +                             #address-cells = <1>;
>> >> +                             #size-cells = <1>;
>> >> +                             ranges = <0x98000000 0x98000000 0x8000000>;
>> >> +
>> >> +                             graphics@0x98000000 {
>> >> +                                     compatible = "sirf,prima2-graphics";
>> >> +                                     reg = <0x98000000 0x8000000>;
>> >> +                                     interrupts = <6>;
>> >> +                             };
>> >> +                     };
>> >
>> > Are the display and graphics units CSR developments? If the GPU is
>> > in fact licensed from someone else (powervr, arm, ...), you should
>> > probably list the actual name of the device.
>>
>> GPU is powervr sgx 531, so could we define compatible as "powervr,sgx531"?
>
> Probably yes. You should have a look if there are already bindings for
> this that define other attributes. Also, if there is any customization
> inside of the chip, you should have another more specific identifier
> that makes it possible that this is the version that csr has modified.
>
>> >> +                     multimedia-iobg {
>> >> +                             compatible = "simple-bus";
>> >> +                             #address-cells = <1>;
>> >> +                             #size-cells = <1>;
>> >> +                             ranges = <0xa0000000 0xa0000000 0x8000000>;
>> >> +
>> >> +                             multimedia@0xa0000000 {
>> >> +                                     compatible = "sirf,prima2-multimedia";
>> >> +                                     reg = <0xa0000000 0x8000000>;
>> >> +                                     interrupts = <5>;
>> >> +                             };
>> >> +                     };
>> >
>> > "multimedia" sounds like a too generic term. What does this do?
>>
>>  video decoding.
>
> sirf,prima2-video-codec is probably better than, but if anyone has other
> suggestions, you could use something else.
>
>> > Are these proprietary uarts, or are they compatible to 8250 and the
>> > like? You might want to set a clock-frequency property as of_serial.c
>> > uses.
>>
>> it is not compatible with 8250 .
>
> ok
>
>> > Are these rtc implementations related? From the register layout, I would
>> > guess that they are supposed to be used by the same driver, so it's
>> > probably a good idea to add a "compatible" property with a common name
>> > for all three.
>>
>> in fact, because they are slow, they can't be accessed by mapped
>> address directly, the only common point they have is we need to access
>> them through mapped address in rtc-iobg indirectly just like we access
>> i2c/spi/nand devices.
>>
>> they are three different devices with different purpose and register
>> layout in fact.
>
> Ok.
>
>        Arnd
>
Arnd Bergmann July 7, 2011, 11:23 a.m. UTC | #29
On Wednesday 06 July 2011, Nicolas Pitre wrote:
> > Good idea. The related change that I want to do is to conditionalize
> > all drivers that require PC-style I/O on the respective bus they
> > use, so we can also remove the __io macro for platforms that don't
> > need it and catch all drivers using inb/outb at compile time.
> 
> In the spirit of removing as much machine specific and globally used 
> defines (see my patch series removing a bunch of mach/memory.h 
> instances), I'd like to see a solution that would make IO_SPACE_LIMIT 
> into a variable, or having the same definition with a fixed mapping, for 
> as many SOCs as possible.

I think we don't need to make it a variable as long as we don't need to
support all platforms together in one kernel. Any combinations of recent
platforms should be fine the way that Russell suggested (0xffff if
PCI/ISA/PCMCIA is enabled at compile-time, 0 otherwise).

	Arnd
Russell King - ARM Linux July 7, 2011, 12:37 p.m. UTC | #30
On Thu, Jul 07, 2011 at 01:43:03PM +0200, Arnd Bergmann wrote:
> On Thursday 07 July 2011, Barry Song wrote:
> > > FWIW, I've double-checked the Xilinx zynq platform that I've already queued
> > > up for 3.1: this one defines IO_SPACE_LIMIT to 0xffff because PCI support
> > > will get merged later, so that's fine.
> > 
> > as far as i know, zynq still has some static mapping tables and board
> > file board_dt.c. as you have reviewed csr platform very carefully, i
> > guess those can get fixed in zynq later too :-)
> > xilinx zynq and csr prima2 should be the pioneering two new SoCs to
> > move to DT in arm for the moment. at least, these two things can try
> > to get same.
> 
> Good point. I'm not planning to change the initial xilinx code, since
> it's already in the tree, but I'd like to apply the patch below
> to make it do the same as prima2 in this regard.
> John, can you ack this patch?

How similar are prima2 and zynq after this patch and a diff between
their two subdirectories?  Are there any differences which can be
eliminated?  Is there any commonality which can be factored out from
the two?  Should the two be occupying separate mach directories?

I think this is something we need to pay attention to now.
Russell King - ARM Linux July 7, 2011, 2:12 p.m. UTC | #31
On Thu, Jul 07, 2011 at 03:21:06PM +0200, Arnd Bergmann wrote:
> What's left then are basically the headers. There is significant
> room for consolidation there, and I think most of them have been
> looked at by people before or are currently being worked on.
> Below is the complete diff between the headers of the two platforms
> as they are being proposed now.

Thanks for that.  diff -w might be a good idea on these to eliminate
changes due to whitespace differences.  It has found one thing which
should be fixed...

> diff -urN arch/arm/mach-prima2/include/mach/vmalloc.h arch/arm/mach-zynq/include/mach/vmalloc.h
> --- arch/arm/mach-prima2/include/mach/vmalloc.h	2011-07-07 13:21:41.000000000 +0000
> +++ arch/arm/mach-zynq/include/mach/vmalloc.h	2011-07-07 13:22:07.000000000 +0000
> @@ -1,14 +1,20 @@
> -/*
> - * arch/arm/ach-prima2/include/mach/vmalloc.h
> +/* arch/arm/mach-zynq/include/mach/vmalloc.h
>   *
> - * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *  Copyright (C) 2011 Xilinx
>   *
> - * Licensed under GPLv2 or later.
> + * 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 __MACH_VMALLOC_H
> -#define __MACH_VMALLOC_H
> +#ifndef __MACH_VMALLOC_H__
> +#define __MACH_VMALLOC_H__
>  
> -#define VMALLOC_END	0xFEC00000
> +#define VMALLOC_END       0xE0000000UL

Prima2 should add a UL suffix to VMALLOC_END to ensure that it is
properly typed.
Barry Song July 8, 2011, 2:18 a.m. UTC | #32
2011/7/7 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Thu, Jul 07, 2011 at 03:21:06PM +0200, Arnd Bergmann wrote:
>> What's left then are basically the headers. There is significant
>> room for consolidation there, and I think most of them have been
>> looked at by people before or are currently being worked on.
>> Below is the complete diff between the headers of the two platforms
>> as they are being proposed now.
>
> Thanks for that.  diff -w might be a good idea on these to eliminate
> changes due to whitespace differences.  It has found one thing which
> should be fixed...
>
>> diff -urN arch/arm/mach-prima2/include/mach/vmalloc.h arch/arm/mach-zynq/include/mach/vmalloc.h
>> --- arch/arm/mach-prima2/include/mach/vmalloc.h       2011-07-07 13:21:41.000000000 +0000
>> +++ arch/arm/mach-zynq/include/mach/vmalloc.h 2011-07-07 13:22:07.000000000 +0000
>> @@ -1,14 +1,20 @@
>> -/*
>> - * arch/arm/ach-prima2/include/mach/vmalloc.h
>> +/* arch/arm/mach-zynq/include/mach/vmalloc.h
>>   *
>> - * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *  Copyright (C) 2011 Xilinx
>>   *
>> - * Licensed under GPLv2 or later.
>> + * 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 __MACH_VMALLOC_H
>> -#define __MACH_VMALLOC_H
>> +#ifndef __MACH_VMALLOC_H__
>> +#define __MACH_VMALLOC_H__
>>
>> -#define VMALLOC_END  0xFEC00000
>> +#define VMALLOC_END       0xE0000000UL
>
> Prima2 should add a UL suffix to VMALLOC_END to ensure that it is
> properly typed.

simply adding a UL suffix will make compiling fail since
arch/arm/kernel/debug.S will refer to the macro calculating virtual
address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm.

samsung has one way to handle this:

plat-samsung/include/plat/map-base.h

#define S3C_ADDR_BASE   0xF6000000

#ifndef __ASSEMBLY__
#define S3C_ADDR(x)     ((void __iomem __force *)S3C_ADDR_BASE + (x))
#else
#define S3C_ADDR(x)     (S3C_ADDR_BASE + (x))
#endif

#define S3C_VA_UART     S3C_ADDR(0x01000000)    /* UART */

mach-s5pc100/include/mach/debug-macro.S:
        .macro addruart, rp, rv
                ldr     \rp, = S3C_PA_UART
                ldr     \rv, = S3C_VA_UART
#if CONFIG_DEBUG_S3C_UART != 0
                add     \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
                add     \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
#endif
        .endm

Samsung hasn't UL for S3C_ADDR_BASE in asm context, so its
arch/arm/kernel/debug.S can compile. in C context, "(void __iomem
__force *)" works to force the right type.

To fix my problem, i might simply give the direct address to
SIRFSOC_UART1_VA_BASE:

#define SIRFSOC_UART1_VA_BASE 0xFEC60000

instead of

#define SIRFSOC_UART1_VA_BASE          SIRFSOC_VA(0x060000)
>
Russell King - ARM Linux July 8, 2011, 9:03 a.m. UTC | #33
On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote:
> simply adding a UL suffix will make compiling fail since
> arch/arm/kernel/debug.S will refer to the macro calculating virtual
> address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm.

A solution for VMALLOC_END would be to include linux/const.h and use
_AC(value, UL).  I think you're the only one who bases their IO
addressing off VMALLOC_END.
Nicolas Pitre July 8, 2011, 1:38 p.m. UTC | #34
On Fri, 8 Jul 2011, Russell King - ARM Linux wrote:

> On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote:
> > simply adding a UL suffix will make compiling fail since
> > arch/arm/kernel/debug.S will refer to the macro calculating virtual
> > address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm.
> 
> A solution for VMALLOC_END would be to include linux/const.h and use
> _AC(value, UL).  I think you're the only one who bases their IO
> addressing off VMALLOC_END.

This is also a bad idea to use VMALLOC_END like that since this is 
another per-architecture constant which is targetted for a global 
removal.


Nicolas
Russell King - ARM Linux July 8, 2011, 4:27 p.m. UTC | #35
On Fri, Jul 08, 2011 at 09:38:56AM -0400, Nicolas Pitre wrote:
> On Fri, 8 Jul 2011, Russell King - ARM Linux wrote:
> 
> > On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote:
> > > simply adding a UL suffix will make compiling fail since
> > > arch/arm/kernel/debug.S will refer to the macro calculating virtual
> > > address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm.
> > 
> > A solution for VMALLOC_END would be to include linux/const.h and use
> > _AC(value, UL).  I think you're the only one who bases their IO
> > addressing off VMALLOC_END.
> 
> This is also a bad idea to use VMALLOC_END like that since this is 
> another per-architecture constant which is targetted for a global 
> removal.

Let's get the story straight and avoid confusion...

Using _AC(value, UL) is not a bad idea, nor is adding UL as a suffix for
VMALLOC_END.  Basing IO addresses off VMALLOC_END is questionable, but
we have to have some value for this.

Rather than trying to convert everything to a variable, I think some
effort needs to be spent trying to keep this as a constant.  We've
grown too much to have lots of variances in the kernel memory layout
and we really should be trying to standardize on this stuff.

Part of that is helped with your patch for the StrongARM cache flushing.
We just need to take that further.
Nicolas Pitre July 8, 2011, 6:09 p.m. UTC | #36
On Fri, 8 Jul 2011, Russell King - ARM Linux wrote:

> On Fri, Jul 08, 2011 at 09:38:56AM -0400, Nicolas Pitre wrote:
> > On Fri, 8 Jul 2011, Russell King - ARM Linux wrote:
> > 
> > > On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote:
> > > > simply adding a UL suffix will make compiling fail since
> > > > arch/arm/kernel/debug.S will refer to the macro calculating virtual
> > > > address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm.
> > > 
> > > A solution for VMALLOC_END would be to include linux/const.h and use
> > > _AC(value, UL).  I think you're the only one who bases their IO
> > > addressing off VMALLOC_END.
> > 
> > This is also a bad idea to use VMALLOC_END like that since this is 
> > another per-architecture constant which is targetted for a global 
> > removal.
> 
> Let's get the story straight and avoid confusion...
> 
> Using _AC(value, UL) is not a bad idea, nor is adding UL as a suffix for
> VMALLOC_END. 

Absolutely.

> Basing IO addresses off VMALLOC_END is questionable, but we have to 
> have some value for this.

Exact.  I just wouldn't want to see VMALLOC_END even more entangled into 
SOC specific mappings.

> Rather than trying to convert everything to a variable, I think some
> effort needs to be spent trying to keep this as a constant.  We've
> grown too much to have lots of variances in the kernel memory layout
> and we really should be trying to standardize on this stuff.

Indeed.  The VMALLOC_END case is possibly different as we were trying to 
find a way to adjust it automatically at run time which would be one 
thing less for platforms to care about.  Having a globally fixed value 
for it would also solve the multiple definition problem.  But some 
machines have a large set of IO mappings while some others have a 
small one, so having a one size fits all solution here might be 
suboptimal.


Nicolas
Arnd Bergmann July 8, 2011, 9:37 p.m. UTC | #37
On Friday 08 July 2011 20:09:29 Nicolas Pitre wrote:
> Indeed.  The VMALLOC_END case is possibly different as we were trying to 
> find a way to adjust it automatically at run time which would be one 
> thing less for platforms to care about.  Having a globally fixed value 
> for it would also solve the multiple definition problem.  But some 
> machines have a large set of IO mappings while some others have a 
> small one, so having a one size fits all solution here might be 
> suboptimal.

Is everything between VMALLOC_END and 0xfeffffff guaranteed to come
from iotable_init? If so, we could perhaps turn it into a variable
that gets initialized to 0xfeffffff and decreased by iotable_init
to be just below the lowest address that has actually been mapped.

Obviously, anything that derives values from VMALLOC_END at compile
time would need to change, too.

	Arnd
Nicolas Pitre July 21, 2011, 12:03 a.m. UTC | #38
On Fri, 8 Jul 2011, Arnd Bergmann wrote:

> On Friday 08 July 2011 20:09:29 Nicolas Pitre wrote:
> > Indeed.  The VMALLOC_END case is possibly different as we were trying to 
> > find a way to adjust it automatically at run time which would be one 
> > thing less for platforms to care about.  Having a globally fixed value 
> > for it would also solve the multiple definition problem.  But some 
> > machines have a large set of IO mappings while some others have a 
> > small one, so having a one size fits all solution here might be 
> > suboptimal.
> 
> Is everything between VMALLOC_END and 0xfeffffff guaranteed to come
> from iotable_init? If so, we could perhaps turn it into a variable
> that gets initialized to 0xfeffffff and decreased by iotable_init
> to be just below the lowest address that has actually been mapped.
> 
> Obviously, anything that derives values from VMALLOC_END at compile
> time would need to change, too.

You then have a catch22 situation, because one thing that gets derived 
from VMALLOC_END is the highmem threshold, and that has to be determined 
before iotable_init can be used.  And having a fixed highmem threshold 
is not any better than a globally fixed VMALLOC_END of course.


Nicolas
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt
new file mode 100644
index 0000000..6b07f65
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sirf.txt
@@ -0,0 +1,3 @@ 
+prima2 "cb" evalutation board
+Required root node properties:
+    - compatible = "sirf,prima2-cb", "sirf,prima2";
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9adc278..06ee145 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -879,6 +879,19 @@  config ARCH_VT8500
 	select HAVE_PWM
 	help
 	  Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip.
+
+config ARCH_PRIMA2
+	bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform"
+	select CPU_V7
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select CLKDEV_LOOKUP
+	select GENERIC_IRQ_CHIP
+	select USE_OF
+	select ZONE_DMA
+	help
+          Support for CSR SiRFSoC ARM Cortex A9 Platform
+
 endchoice
 
 #
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index f5b2b39..1d693d0 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -169,6 +169,7 @@  machine-$(CONFIG_ARCH_OMAP3)		:= omap2
 machine-$(CONFIG_ARCH_OMAP4)		:= omap2
 machine-$(CONFIG_ARCH_ORION5X)		:= orion5x
 machine-$(CONFIG_ARCH_PNX4008)		:= pnx4008
+machine-$(CONFIG_ARCH_PRIMA2)		:= prima2
 machine-$(CONFIG_ARCH_PXA)		:= pxa
 machine-$(CONFIG_ARCH_REALVIEW)		:= realview
 machine-$(CONFIG_ARCH_RPC)		:= rpc
diff --git a/arch/arm/boot/dts/prima2-cb.dts b/arch/arm/boot/dts/prima2-cb.dts
new file mode 100644
index 0000000..182717e
--- /dev/null
+++ b/arch/arm/boot/dts/prima2-cb.dts
@@ -0,0 +1,423 @@ 
+/dts-v1/;
+/ {
+	model = "SiRF Prima2 EVB";
+	compatible = "sirf,prima2-cb", "sirf,prima2";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	interrupt-parent = <&intc>;
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	chosen {
+		bootargs = "mem=512M real_root=/dev/mmcblk0p2 console=ttyS0 panel=1 bootsplash=true bpp=16 androidboot.console=ttyS1";
+		linux,stdout-path = &uart1;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			reg = <0x0>;
+			d-cache-line-size = <32>;
+			i-cache-line-size = <32>;
+			d-cache-size = <32768>;
+			i-cache-size = <32768>;
+			/* from bootloader */
+			timebase-frequency = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+		};
+	};
+
+	axi {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x40000000 0x40000000 0x80000000>;
+
+		sirfsoc-iobus {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x40000000 0x40000000 0x80000000>;
+
+			l2-cache-controller@0x80040000 {
+				compatible = "arm,pl310-cache";
+				reg = <0x80040000 0x1000>;
+				interrupts = <59>;
+			};
+
+			intc: interrupt-controller@0x80020000 {
+				#interrupt-cells = <1>;
+				interrupt-controller;
+				compatible = "sirf,prima2-intc";
+				reg = <0x80020000 0x1000>;
+			};
+
+			sys-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0x88000000 0x88000000 0x40000>;
+
+				clock-controller@0x88000000 {
+					compatible = "sirf,prima2-clkc";
+					reg = <0x88000000 0x1000>;
+					interrupts = <3>;
+				};
+
+				reset-controller@0x88010000 {
+					compatible = "sirf,prima2-rstc";
+					reg = <0x88010000 0x1000>;
+				};
+			};
+
+			mem-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0x90000000 0x90000000 0x10000>;
+
+				memory-controller@0x90000000 {
+					compatible = "sirf,prima2-memc";
+					reg = <0x90000000 0x10000>;
+					interrupts = <27>;
+				};
+			};
+
+			disp-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0x90010000 0x90010000 0x30000>;
+
+				display@0x90010000 {
+					compatible = "sirf,prima2-lcd";
+					reg = <0x90010000 0x20000>;
+					interrupts = <30>;
+				};
+
+				vpp@0x90020000 {
+					compatible = "sirf,prima2-vpp";
+					reg = <0x90020000 0x10000>;
+					interrupts = <31>;
+				};
+			};
+
+			graphics-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0x98000000 0x98000000 0x8000000>;
+
+				graphics@0x98000000 {
+					compatible = "sirf,prima2-graphics";
+					reg = <0x98000000 0x8000000>;
+					interrupts = <6>;
+				};
+			};
+
+			multimedia-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0xa0000000 0xa0000000 0x8000000>;
+
+				multimedia@0xa0000000 {
+					compatible = "sirf,prima2-multimedia";
+					reg = <0xa0000000 0x8000000>;
+					interrupts = <5>;
+				};
+			};
+
+			dsp-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0xa8000000 0xa8000000 0x2000000>;
+
+				dspif@0xa8000000 {
+					compatible = "sirf,prima2-dspif";
+					reg = <0xa8000000 0x10000>;
+					interrupts = <9>;
+				};
+
+				gps@0xa8010000 {
+					compatible = "sirf,prima2-gps";
+					reg = <0xa8010000 0x10000>;
+					interrupts = <7>;
+				};
+
+				dsp@0xa9000000 {
+					compatible = "sirf,prima2-dsp";
+					reg = <0xa9000000 0x1000000>;
+					interrupts = <8>;
+				};
+			};
+
+			peri-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0xb0000000 0xb0000000 0x180000>;
+
+				timer@0xb0020000 {
+					compatible = "sirf,prima2-tick";
+					reg = <0xb0020000 0x1000>;
+					interrupts = <0>;
+				};
+
+				nand@0xb0030000 {
+					compatible = "sirf,prima2-nand";
+					reg = <0xb0030000 0x10000>;
+					interrupts = <41>;
+				};
+
+				audio@0xb0040000 {
+					compatible = "sirf,prima2-audio";
+					reg = <0xb0040000 0x10000>;
+					interrupts = <35>;
+				};
+
+				uart0: uart@0xb0050000 {
+					cell-index = <0>;
+					compatible = "sirf,prima2-uart";
+					reg = <0xb0050000 0x10000>;
+					interrupts = <17>;
+				};
+
+	 			uart1: uart@0xb0060000 {
+					cell-index = <1>;
+					compatible = "sirf,prima2-uart";
+					reg = <0xb0060000 0x10000>;
+					interrupts = <18>;
+				};
+
+	 			uart2: uart@0xb0070000 {
+					cell-index = <2>;
+					compatible = "sirf,prima2-uart";
+					reg = <0xb0070000 0x10000>;
+					interrupts = <19>;
+				};
+
+	 			usp0: usp@0xb0080000 {
+					cell-index = <0>;
+					compatible = "sirf,prima2-usp";
+					reg = <0xb0080000 0x10000>;
+					interrupts = <20>;
+				};
+
+	 			usp1: usp@0xb0090000 {
+					cell-index = <1>;
+					compatible = "sirf,prima2-usp";
+					reg = <0xb0090000 0x10000>;
+					interrupts = <21>;
+				};
+
+	 			usp2: usp@0xb00a0000 {
+					cell-index = <2>;
+					compatible = "sirf,prima2-usp";
+					reg = <0xb00a0000 0x10000>;
+					interrupts = <22>;
+				};
+
+	 			dmac0: dma-controller@0xb00b0000 {
+					cell-index = <0>;
+					compatible = "sirf,prima2-dmac";
+					reg = <0xb00b0000 0x10000>;
+					interrupts = <12>;
+				};
+
+	 			dmac1: dma-controller@0xb0160000 {
+					cell-index = <1>;
+					compatible = "sirf,prima2-dmac";
+					reg = <0xb0160000 0x10000>;
+					interrupts = <13>;
+				};
+
+				vip@0xb00C0000 {
+					compatible = "sirf,prima2-vip";
+					reg = <0xb00C0000 0x10000>;
+				};
+
+	 			spi0: spi@0xb00D0000 {
+					cell-index = <0>;
+					compatible = "sirf,prima2-spi";
+					reg = <0xb00D0000 0x10000>;
+					interrupts = <15>;
+				};
+
+	 			spi1: spi@0xb0170000 {
+					cell-index = <1>;
+					compatible = "sirf,prima2-spi";
+					reg = <0xb0170000 0x10000>;
+					interrupts = <16>;
+				};
+
+	 			i2c0: i2c@0xb00E0000 {
+					cell-index = <0>;
+					compatible = "sirf,prima2-i2c";
+					reg = <0xb00E0000 0x10000>;
+					interrupts = <24>;
+				};
+
+	 			i2c1: i2c@0xb00f0000 {
+					cell-index = <1>;
+					compatible = "sirf,prima2-i2c";
+					reg = <0xb00f0000 0x10000>;
+					interrupts = <25>;
+				};
+
+				tsc@0xb0110000 {
+					compatible = "sirf,prima2-tsc";
+					reg = <0xb0110000 0x10000>;
+					interrupts = <33>;
+				};
+
+				gpio: gpio-controller@0xb0120000 {
+					#gpio-cells = <2>;
+					#interrupt-cells = <2>;
+					compatible = "sirf,prima2-gpio";
+					reg = <0xb0120000 0x10000>;
+					gpio-controller;
+					interrupt-controller;
+				};
+
+				pwm@0xb0130000 {
+					compatible = "sirf,prima2-pwm";
+					reg = <0xb0130000 0x10000>;
+				};
+
+				efusesys@0xb0140000 {
+					compatible = "sirf,prima2-efuse";
+					reg = <0xb0140000 0x10000>;
+				};
+
+				pulsec@0xb0150000 {
+					compatible = "sirf,prima2-pulsec";
+					reg = <0xb0150000 0x10000>;
+					interrupts = <48>;
+				};
+
+				pci-iobg {
+					compatible = "sirf,prima2-pciiobg", "simple-bus";
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges = <0x56000000 0x56000000 0x1b00000>;
+
+					sd0: sdhci@0x56000000 {
+						cell-index = <0>;
+						compatible = "sirf,prima2-sdhc";
+						reg = <0x56000000 0x100000>;
+						interrupts = <38>;
+					};
+
+					sd1: sdhci@0x56100000 {
+						cell-index = <1>;
+						compatible = "sirf,prima2-sdhc";
+						reg = <0x56100000 0x100000>;
+						interrupts = <38>;
+					};
+
+					sd2: sdhci@0x56200000 {
+						cell-index = <2>;
+						compatible = "sirf,prima2-sdhc";
+						reg = <0x56200000 0x100000>;
+						interrupts = <23>;
+					};
+
+					sd3: sdhci@0x56300000 {
+						cell-index = <3>;
+						compatible = "sirf,prima2-sdhc";
+						reg = <0x56300000 0x100000>;
+						interrupts = <23>;
+					};
+
+					sd4: sdhci@0x56400000 {
+						cell-index = <4>;
+						compatible = "sirf,prima2-sdhc";
+						reg = <0x56400000 0x100000>;
+						interrupts = <39>;
+					};
+
+					sd5: sdhci@0x56500000 {
+						cell-index = <5>;
+						compatible = "sirf,prima2-sdhc";
+						reg = <0x56500000 0x100000>;
+						interrupts = <39>;
+					};
+
+					pci-copy@0x57900000 {
+						compatible = "sirf,prima2-pcicp";
+						reg = <0x57900000 0x100000>;
+						interrupts = <40>;
+					};
+
+					rom-interface@0x57a00000 {
+						compatible = "sirf,prima2-romif";
+						reg = <0x57a00000 0x100000>;
+					};
+				};
+			};
+
+			rtc-iobg {
+				compatible = "sirf,prima2-rtciobg", "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x80030000 0x10000>;
+
+				gpsrtc@0x1000 {
+					compatible = "sirf,prima2-gpsrtc";
+					reg = <0x1000 0x1000>;
+					interrupts = <55 56 57>;
+				};
+
+				sysrtc@0x2000 {
+					compatible = "sirf,prima2-sysrtc";
+					reg = <0x2000 0x1000>;
+					interrupts = <52 53 54>;
+				};
+
+				pwrc@0x3000 {
+					compatible = "sirf,prima2-pwrc";
+					reg = <0x3000 0x1000>;
+					interrupts = <32>;
+				};
+			};
+
+			uus-iobg {
+				compatible = "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0xb8000000 0xb8000000 0x40000>;
+
+	 			usb0: usb@0xb00E0000 {
+					compatible = "sirf,prima2-usb";
+					reg = <0xb8000000 0x10000>;
+					interrupts = <10>;
+				};
+
+	 			usb1: usb@0xb00f0000 {
+					compatible = "sirf,prima2-usb";
+					reg = <0xb8010000 0x10000>;
+					interrupts = <11>;
+				};
+
+				sata@0xb00f0000 {
+					compatible = "sirf,prima2-sata";
+					reg = <0xb8020000 0x10000>;
+					interrupts = <37>;
+				};
+
+				security@0xb00f0000 {
+					compatible = "sirf,prima2-security";
+					reg = <0xb8030000 0x10000>;
+					interrupts = <42>;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
new file mode 100644
index 0000000..d44f7ae
--- /dev/null
+++ b/arch/arm/mach-prima2/Makefile
@@ -0,0 +1,5 @@ 
+obj-y := timer.o
+obj-y += irq.o
+obj-y += clock.o
+obj-y += rstc.o
+obj-y += prima2.o
diff --git a/arch/arm/mach-prima2/Makefile.boot b/arch/arm/mach-prima2/Makefile.boot
new file mode 100644
index 0000000..d023db3
--- /dev/null
+++ b/arch/arm/mach-prima2/Makefile.boot
@@ -0,0 +1,3 @@ 
+zreladdr-y		:= 0x00008000
+params_phys-y		:= 0x00000100
+initrd_phys-y		:= 0x00800000
diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c
new file mode 100644
index 0000000..f9a2aaf
--- /dev/null
+++ b/arch/arm/mach-prima2/clock.c
@@ -0,0 +1,509 @@ 
+/*
+ * Clock tree for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <asm/mach/map.h>
+#include <mach/map.h>
+
+#define SIRFSOC_CLKC_CLK_EN0    0x0000
+#define SIRFSOC_CLKC_CLK_EN1    0x0004
+#define SIRFSOC_CLKC_REF_CFG    0x0014
+#define SIRFSOC_CLKC_CPU_CFG    0x0018
+#define SIRFSOC_CLKC_MEM_CFG    0x001c
+#define SIRFSOC_CLKC_SYS_CFG    0x0020
+#define SIRFSOC_CLKC_IO_CFG     0x0024
+#define SIRFSOC_CLKC_DSP_CFG    0x0028
+#define SIRFSOC_CLKC_GFX_CFG    0x002c
+#define SIRFSOC_CLKC_MM_CFG     0x0030
+#define SIRFSOC_LKC_LCD_CFG     0x0034
+#define SIRFSOC_CLKC_MMC_CFG    0x0038
+#define SIRFSOC_CLKC_PLL1_CFG0  0x0040
+#define SIRFSOC_CLKC_PLL2_CFG0  0x0044
+#define SIRFSOC_CLKC_PLL3_CFG0  0x0048
+#define SIRFSOC_CLKC_PLL1_CFG1  0x004c
+#define SIRFSOC_CLKC_PLL2_CFG1  0x0050
+#define SIRFSOC_CLKC_PLL3_CFG1  0x0054
+#define SIRFSOC_CLKC_PLL1_CFG2  0x0058
+#define SIRFSOC_CLKC_PLL2_CFG2  0x005c
+#define SIRFSOC_CLKC_PLL3_CFG2  0x0060
+
+#define SIRFSOC_CLOCK_VA_BASE		SIRFSOC_VA(0x005000)
+
+#define KHZ     1000
+#define MHZ     (KHZ * KHZ)
+
+struct clk_ops {
+	unsigned long (*get_rate)(struct clk *clk);
+	long (*round_rate)(struct clk *clk, unsigned long rate);
+	int (*set_rate)(struct clk *clk, unsigned long rate);
+	int (*enable)(struct clk *clk);
+	int (*disable)(struct clk *clk);
+	struct clk *(*get_parent)(struct clk *clk);
+	int (*set_parent)(struct clk *clk, struct clk *parent);
+};
+
+struct clk {
+	struct clk *parent;     /* parent clk */
+	unsigned long rate;     /* clock rate in Hz */
+	signed char usage;      /* clock enable count */
+	signed char enable_bit; /* enable bit: 0 ~ 63 */
+	unsigned short regofs;  /* register offset */
+	struct clk_ops *ops;    /* clock operation */
+};
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+static inline unsigned long clkc_readl(unsigned reg)
+{
+	return readl(SIRFSOC_CLOCK_VA_BASE + reg);
+}
+
+static inline void clkc_writel(u32 val, unsigned reg)
+{
+	writel(val, SIRFSOC_CLOCK_VA_BASE + reg);
+}
+
+/*
+ * osc_rtc - real time oscillator - 32.768KHz
+ * osc_sys - high speed oscillator - 26MHz
+ */
+
+static struct clk clk_rtc = {
+	.rate = 32768,
+};
+
+static struct clk clk_osc = {
+	.rate = 26 * MHZ,
+};
+
+/*
+ * std pll
+ */
+static unsigned long std_pll_get_rate(struct clk *clk)
+{
+	unsigned long fin = clk_get_rate(clk->parent);
+	u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 -
+		SIRFSOC_CLKC_PLL1_CFG0;
+
+	if (clkc_readl(regcfg2) & BIT(2)) {
+		/* pll bypass mode */
+		clk->rate = fin;
+	} else {
+		/* fout = fin * nf / nr / od */
+		u32 cfg0 = clkc_readl(clk->regofs);
+		u32 nf = (cfg0 & (BIT(13) - 1)) + 1;
+		u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1;
+		u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1;
+		WARN_ON(fin % MHZ);
+		clk->rate = fin / MHZ * nf / nr / od * MHZ;
+	}
+
+	return clk->rate;
+}
+
+static int std_pll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long fin, nf, nr, od, reg;
+
+	/*
+	 * fout = fin * nf / (nr * od);
+	 * set od = 1, nr = fin/MHz, so fout = nf * MHz
+	 */
+
+	nf = rate / MHZ;
+	if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1))
+		return -EINVAL;
+
+	fin = clk_get_rate(clk->parent);
+	BUG_ON(fin < MHZ);
+
+	nr = fin / MHZ;
+	BUG_ON((fin % MHZ) || nr > BIT(6));
+
+	od = 1;
+
+	reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19);
+	clkc_writel(reg, clk->regofs);
+
+	reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0;
+	clkc_writel((nf >> 1) - 1, reg);
+
+	reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0;
+	while (!(clkc_readl(reg) & BIT(6)))
+		cpu_relax();
+
+	clk->rate = 0; /* set to zero will force recalculation */
+	return 0;
+}
+
+static struct clk_ops std_pll_ops = {
+	.get_rate = std_pll_get_rate,
+	.set_rate = std_pll_set_rate,
+};
+
+static struct clk clk_pll1 = {
+	.parent = &clk_osc,
+	.regofs = SIRFSOC_CLKC_PLL1_CFG0,
+	.ops = &std_pll_ops,
+};
+
+static struct clk clk_pll2 = {
+	.parent = &clk_osc,
+	.regofs = SIRFSOC_CLKC_PLL2_CFG0,
+	.ops = &std_pll_ops,
+};
+
+static struct clk clk_pll3 = {
+	.parent = &clk_osc,
+	.regofs = SIRFSOC_CLKC_PLL3_CFG0,
+	.ops = &std_pll_ops,
+};
+
+/*
+ * clock domains - cpu, mem, sys/io
+ */
+
+static struct clk clk_mem;
+
+static struct clk *dmn_get_parent(struct clk *clk)
+{
+	struct clk *clks[] = {
+		&clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
+	};
+	u32 cfg = clkc_readl(clk->regofs);
+	WARN_ON((cfg & (BIT(3) - 1)) > 4);
+	return clks[cfg & (BIT(3) - 1)];
+}
+
+static int dmn_set_parent(struct clk *clk, struct clk *parent)
+{
+	const struct clk *clks[] = {
+		&clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
+	};
+	u32 cfg = clkc_readl(clk->regofs);
+	int i;
+	for (i = 0; i < ARRAY_SIZE(clks); i++) {
+		if (clks[i] == parent) {
+			cfg &= ~(BIT(3) - 1);
+			clkc_writel(cfg | i, clk->regofs);
+			/* BIT(3) - switching status: 1 - busy, 0 - done */
+			while (clkc_readl(clk->regofs) & BIT(3))
+				cpu_relax();
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static unsigned long dmn_get_rate(struct clk *clk)
+{
+	unsigned long fin = clk_get_rate(clk->parent);
+	u32 cfg = clkc_readl(clk->regofs);
+	if (cfg & BIT(24)) {
+		/* fcd bypass mode */
+		clk->rate = fin;
+	} else {
+		/*
+		 * wait count: bit[19:16], hold count: bit[23:20]
+		 */
+		u32 wait = (cfg >> 16) & (BIT(4) - 1);
+		u32 hold = (cfg >> 20) & (BIT(4) - 1);
+
+		clk->rate = fin / (wait + hold + 2);
+	}
+
+	return clk->rate;
+}
+
+static int dmn_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long fin;
+	unsigned ratio, wait, hold, reg;
+	unsigned bits = (clk == &clk_mem) ? 3 : 4;
+
+	fin = clk_get_rate(clk->parent);
+	ratio = fin / rate;
+
+	if (unlikely(ratio < 2 || ratio > BIT(bits + 1)))
+		return -EINVAL;
+
+	WARN_ON(fin % rate);
+
+	wait = (ratio >> 1) - 1;
+	hold = ratio - wait - 2;
+
+	reg = clkc_readl(clk->regofs);
+	reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20));
+	reg |= (wait << 16) | (hold << 20) | BIT(25);
+	clkc_writel(reg, clk->regofs);
+
+	/* waiting FCD been effective */
+	while (clkc_readl(clk->regofs) & BIT(25))
+		cpu_relax();
+
+	clk->rate = 0; /* set to zero will force recalculation */
+
+	return 0;
+}
+
+/*
+ * cpu clock has no FCD register in Prima2, can only change pll
+ */
+static int cpu_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret1, ret2;
+	struct clk *cur_parent, *tmp_parent;
+
+	cur_parent = dmn_get_parent(clk);
+	BUG_ON(cur_parent == NULL || cur_parent->usage > 1);
+
+	/* switch to tmp pll before setting parent clock's rate */
+	tmp_parent = cur_parent == &clk_pll1 ? &clk_pll2 : &clk_pll1;
+	ret1 = dmn_set_parent(clk, tmp_parent);
+	BUG_ON(ret1);
+
+	ret2 = clk_set_rate(cur_parent, rate);
+
+	ret1 = dmn_set_parent(clk, cur_parent);
+
+	clk->rate = 0; /* set to zero will force recalculation */
+
+	return ret2 ? ret2 : ret1;
+}
+
+static struct clk_ops cpu_ops = {
+	.get_parent = dmn_get_parent,
+	.set_parent = dmn_set_parent,
+	.set_rate = cpu_set_rate,
+};
+
+static struct clk clk_cpu = {
+	.parent = &clk_pll1,
+	.regofs = SIRFSOC_CLKC_CPU_CFG,
+	.ops = &cpu_ops,
+};
+
+
+static struct clk_ops msi_ops = {
+	.set_rate = dmn_set_rate,
+	.get_rate = dmn_get_rate,
+	.set_parent = dmn_set_parent,
+	.get_parent = dmn_get_parent,
+};
+
+static struct clk clk_mem = {
+	.parent = &clk_pll2,
+	.regofs = SIRFSOC_CLKC_MEM_CFG,
+	.ops = &msi_ops,
+};
+
+static struct clk clk_sys = {
+	.parent = &clk_pll3,
+	.regofs = SIRFSOC_CLKC_SYS_CFG,
+	.ops = &msi_ops,
+};
+
+static struct clk clk_io = {
+	.parent = &clk_pll3,
+	.regofs = SIRFSOC_CLKC_IO_CFG,
+	.ops = &msi_ops,
+};
+
+/*
+ * on-chip clock sets
+ */
+static struct clk_lookup onchip_clks[] = {
+	{
+		.dev_id = "rtc",
+		.clk = &clk_rtc,
+	}, {
+		.dev_id = "osc",
+		.clk = &clk_osc,
+	}, {
+		.dev_id = "pll1",
+		.clk = &clk_pll1,
+	}, {
+		.dev_id = "pll2",
+		.clk = &clk_pll2,
+	}, {
+		.dev_id = "pll3",
+		.clk = &clk_pll3,
+	}, {
+		.dev_id = "cpu",
+		.clk = &clk_cpu,
+	}, {
+		.dev_id = "mem",
+		.clk = &clk_mem,
+	}, {
+		.dev_id = "sys",
+			.clk = &clk_sys,
+	}, {
+		.dev_id = "io",
+			.clk = &clk_io,
+	},
+};
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+
+	if (unlikely(IS_ERR_OR_NULL(clk)))
+		return -EINVAL;
+
+	if (clk->parent)
+		clk_enable(clk->parent);
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	if (!clk->usage++ && clk->ops && clk->ops->enable)
+		clk->ops->enable(clk);
+	spin_unlock_irqrestore(&clocks_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	if (unlikely(IS_ERR_OR_NULL(clk)))
+		return;
+
+	WARN_ON(!clk->usage);
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	if (--clk->usage == 0 && clk->ops && clk->ops->disable)
+		clk->ops->disable(clk);
+	spin_unlock_irqrestore(&clocks_lock, flags);
+
+	if (clk->parent)
+		clk_disable(clk->parent);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (unlikely(IS_ERR_OR_NULL(clk)))
+		return 0;
+
+	if (clk->rate)
+		return clk->rate;
+
+	if (clk->ops && clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+
+	return clk_get_rate(clk->parent);
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (unlikely(IS_ERR_OR_NULL(clk)))
+		return 0;
+
+	if (clk->ops && clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (unlikely(IS_ERR_OR_NULL(clk)))
+		return -EINVAL;
+
+	if (!clk->ops || !clk->ops->set_rate)
+		return -EINVAL;
+
+	return clk->ops->set_rate(clk, rate);
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret;
+	unsigned long flags;
+
+	if (unlikely(IS_ERR_OR_NULL(clk)))
+		return -EINVAL;
+
+	if (!clk->ops || !clk->ops->set_parent)
+		return -EINVAL;
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	ret = clk->ops->set_parent(clk, parent);
+	if (!ret) {
+		parent->usage += clk->usage;
+		clk->parent->usage -= clk->usage;
+		BUG_ON(clk->parent->usage < 0);
+		clk->parent = parent;
+	}
+	spin_unlock_irqrestore(&clocks_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	unsigned long flags;
+
+	if (unlikely(IS_ERR_OR_NULL(clk)))
+		return NULL;
+
+	if (!clk->ops || !clk->ops->get_parent)
+		return clk->parent;
+
+	spin_lock_irqsave(&clocks_lock, flags);
+	clk->parent = clk->ops->get_parent(clk);
+	spin_unlock_irqrestore(&clocks_lock, flags);
+	return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+static void __init sirfsoc_clk_init(void)
+{
+	clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks));
+}
+
+static struct of_device_id clkc_ids[] = {
+	{ .compatible = "sirf,prima2-clkc" },
+};
+
+void __init sirfsoc_of_clk_init(void)
+{
+	struct device_node *np;
+	struct resource res;
+	struct map_desc sirfsoc_clkc_iodesc = {
+		.virtual = SIRFSOC_CLOCK_VA_BASE,
+		.type    = MT_DEVICE,
+	};
+
+	np = of_find_matching_node(NULL, clkc_ids);
+	if (!np)
+		panic("unable to find compatible clkc node in dtb\n");
+
+	if (of_address_to_resource(np, 0, &res))
+		panic("unable to find clkc range in dtb");
+	of_node_put(np);
+
+	sirfsoc_clkc_iodesc.pfn = __phys_to_pfn(res.start);
+	sirfsoc_clkc_iodesc.length = 1 + res.end - res.start;
+
+	iotable_init(&sirfsoc_clkc_iodesc, 1);
+
+	sirfsoc_clk_init();
+}
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
new file mode 100644
index 0000000..83e5d21
--- /dev/null
+++ b/arch/arm/mach-prima2/common.h
@@ -0,0 +1,26 @@ 
+/*
+ * This file contains common function prototypes to avoid externs in the c files.
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_PRIMA2_COMMON_H__
+#define __MACH_PRIMA2_COMMON_H__
+
+#include <linux/init.h>
+#include <asm/mach/time.h>
+
+extern struct sys_timer sirfsoc_timer;
+
+extern void __init sirfsoc_of_irq_init(void);
+extern void __init sirfsoc_of_clk_init(void);
+
+#ifndef CONFIG_DEBUG_LL
+static inline void sirfsoc_map_lluart(void)  {}
+#else
+extern void __init sirfsoc_map_lluart(void);
+#endif
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/clkdev.h b/arch/arm/mach-prima2/include/mach/clkdev.h
new file mode 100644
index 0000000..6693251
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/clkdev.h
@@ -0,0 +1,15 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/clkdev.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_CLKDEV_H
+#define __MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/debug-macro.S b/arch/arm/mach-prima2/include/mach/debug-macro.S
new file mode 100644
index 0000000..bf75106
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/debug-macro.S
@@ -0,0 +1,29 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/debug-macro.S
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <mach/hardware.h>
+#include <mach/uart.h>
+
+	.macro	addruart, rp, rv
+	ldr	\rp, =SIRFSOC_UART1_PA_BASE		@ physical
+	ldr	\rv, =SIRFSOC_UART1_VA_BASE		@ virtual
+	.endm
+
+	.macro	senduart,rd,rx
+	str	\rd, [\rx, #SIRFSOC_UART_TXFIFO_DATA]
+	.endm
+
+	.macro	busyuart,rd,rx
+	.endm
+
+	.macro	waituart,rd,rx
+1001:	ldr	\rd, [\rx, #SIRFSOC_UART_TXFIFO_STATUS]
+	tst	\rd, #SIRFSOC_UART1_TXFIFO_EMPTY
+	beq	1001b
+	.endm
+
diff --git a/arch/arm/mach-prima2/include/mach/entry-macro.S b/arch/arm/mach-prima2/include/mach/entry-macro.S
new file mode 100644
index 0000000..1c8a50f
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/entry-macro.S
@@ -0,0 +1,29 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/entry-macro.S
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <mach/hardware.h>
+
+#define SIRFSOC_INT_ID 0x38
+
+	.macro  get_irqnr_preamble, base, tmp
+	ldr     \base, =sirfsoc_intc_base
+	ldr     \base, [\base]
+	.endm
+
+	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+	ldr \irqnr, [\base, #SIRFSOC_INT_ID]	@ Get the highest priority irq
+	cmp \irqnr, #0x40			@ the irq num can't be larger than 0x3f
+	movges \irqnr, #0
+	.endm
+
+	.macro  disable_fiq
+	.endm
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
diff --git a/arch/arm/mach-prima2/include/mach/hardware.h b/arch/arm/mach-prima2/include/mach/hardware.h
new file mode 100644
index 0000000..105b969
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/hardware.h
@@ -0,0 +1,15 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/hardware.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_HARDWARE_H__
+#define __MACH_HARDWARE_H__
+
+#include <asm/sizes.h>
+#include <mach/map.h>
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h
new file mode 100644
index 0000000..fc54f16
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/io.h
@@ -0,0 +1,21 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/io.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_PRIMA2_IO_H
+#define __MACH_PRIMA2_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)                 __typesafe_io(a)
+#define __mem_pci(a)            (a)
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h
new file mode 100644
index 0000000..bb354f9
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/irqs.h
@@ -0,0 +1,17 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/irqs.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+#define SIRFSOC_INTENAL_IRQ_START  0
+#define SIRFSOC_INTENAL_IRQ_END    59
+
+#define NR_IRQS	220
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/map.h b/arch/arm/mach-prima2/include/mach/map.h
new file mode 100644
index 0000000..66b1ae2
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/map.h
@@ -0,0 +1,16 @@ 
+/*
+ * memory & I/O static mapping definitions for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_PRIMA2_MAP_H__
+#define __MACH_PRIMA2_MAP_H__
+
+#include <mach/vmalloc.h>
+
+#define SIRFSOC_VA(x)			(VMALLOC_END + ((x) & 0x00FFF000))
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/memory.h b/arch/arm/mach-prima2/include/mach/memory.h
new file mode 100644
index 0000000..368cd5a
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/memory.h
@@ -0,0 +1,21 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/memory.h
+ *
+ * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PLAT_PHYS_OFFSET        UL(0x00000000)
+
+/*
+ * Restrict DMA-able region to workaround silicon limitation.
+ * The limitation restricts buffers available for DMA to SD/MMC
+ * hardware to be below 256MB
+ */
+#define ARM_DMA_ZONE_SIZE	(SZ_256M)
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/system.h b/arch/arm/mach-prima2/include/mach/system.h
new file mode 100644
index 0000000..0dbd257
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/system.h
@@ -0,0 +1,29 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/system.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_SYSTEM_H__
+#define __MACH_SYSTEM_H__
+
+#include <linux/bitops.h>
+#include <mach/hardware.h>
+
+#define SIRFSOC_SYS_RST_BIT  BIT(31)
+
+extern void __iomem *sirfsoc_rstc_base;
+
+static inline void arch_idle(void)
+{
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base);
+}
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/timex.h b/arch/arm/mach-prima2/include/mach/timex.h
new file mode 100644
index 0000000..d6f98a7
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/timex.h
@@ -0,0 +1,14 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/timex.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_TIMEX_H__
+#define __MACH_TIMEX_H__
+
+#define CLOCK_TICK_RATE  1000000
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h
new file mode 100644
index 0000000..de2fc2b
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/uart.h
@@ -0,0 +1,23 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/uart.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_PRIMA2_SIRFSOC_UART_H
+#define __MACH_PRIMA2_SIRFSOC_UART_H
+
+/* UART-1: used as serial debug port */
+#define SIRFSOC_UART1_PA_BASE		0xb0060000
+#define SIRFSOC_UART1_VA_BASE		SIRFSOC_VA(0x060000)
+#define SIRFSOC_UART1_SIZE		SZ_4K
+
+#define SIRFSOC_UART_TXFIFO_STATUS	0x0114
+#define SIRFSOC_UART_TXFIFO_DATA	0x0118
+
+#define SIRFSOC_UART1_TXFIFO_FULL                       (1 << 5)
+#define SIRFSOC_UART1_TXFIFO_EMPTY			(1 << 6)
+
+#endif
diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h
new file mode 100644
index 0000000..83125c6
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/uncompress.h
@@ -0,0 +1,40 @@ 
+/*
+ * arch/arm/mach-prima2/include/mach/uncompress.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/uart.h>
+
+void arch_decomp_setup(void)
+{
+}
+
+#define arch_decomp_wdog()
+
+static __inline__ void putc(char c)
+{
+	/*
+	 * during kernel decompression, all mappings are flat:
+	 *  virt_addr == phys_addr
+	 */
+	while (__raw_readl(SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS)
+		& SIRFSOC_UART1_TXFIFO_FULL)
+		barrier();
+
+	__raw_writel(c, SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_DATA);
+}
+
+static inline void flush(void)
+{
+}
+
+#endif
+
diff --git a/arch/arm/mach-prima2/include/mach/vmalloc.h b/arch/arm/mach-prima2/include/mach/vmalloc.h
new file mode 100644
index 0000000..116d0a5
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/vmalloc.h
@@ -0,0 +1,14 @@ 
+/*
+ * arch/arm/ach-prima2/include/mach/vmalloc.h
+ *
+ * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __MACH_VMALLOC_H
+#define __MACH_VMALLOC_H
+
+#define VMALLOC_END	0xFEC00000
+
+#endif
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
new file mode 100644
index 0000000..c3404cb
--- /dev/null
+++ b/arch/arm/mach-prima2/irq.c
@@ -0,0 +1,71 @@ 
+/*
+ * interrupt controller support for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <mach/hardware.h>
+#include <asm/mach/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define SIRFSOC_INT_RISC_MASK0          0x0018
+#define SIRFSOC_INT_RISC_MASK1          0x001C
+#define SIRFSOC_INT_RISC_LEVEL0         0x0020
+#define SIRFSOC_INT_RISC_LEVEL1         0x0024
+
+void __iomem *sirfsoc_intc_base;
+
+static __init void
+sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
+{
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+
+	gc = irq_alloc_generic_chip("SIRFINTC", 1, irq_start, base, handle_level_irq);
+	ct = gc->chip_types;
+
+	ct->chip.irq_mask = irq_gc_mask_clr_bit;
+	ct->chip.irq_unmask = irq_gc_mask_set_bit;
+	ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
+
+	irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0);
+}
+
+static __init void sirfsoc_irq_init(void)
+{
+	sirfsoc_alloc_gc(sirfsoc_intc_base, 0, 32);
+	sirfsoc_alloc_gc(sirfsoc_intc_base + 4, 32, SIRFSOC_INTENAL_IRQ_END - 32);
+
+	writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL0);
+	writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL1);
+
+	writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK0);
+	writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1);
+}
+
+static struct of_device_id intc_ids[]  = {
+	{ .compatible = "sirf,prima2-intc" },
+};
+
+void __init sirfsoc_of_irq_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, intc_ids);
+	if (!np)
+		panic("unable to find compatible intc node in dtb\n");
+
+	sirfsoc_intc_base = of_iomap(np, 0);
+	if (!sirfsoc_intc_base)
+		panic("unable to map intc cpu registers\n");
+
+	of_node_put(np);
+
+	sirfsoc_irq_init();
+}
diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c
new file mode 100644
index 0000000..f6b04a1
--- /dev/null
+++ b/arch/arm/mach-prima2/prima2.c
@@ -0,0 +1,40 @@ 
+/*
+ * Defines machines for CSR SiRFprimaII 
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include "common.h"
+
+static struct of_device_id sirfsoc_of_bus_ids[] __initdata = {
+	{ .compatible = "simple-bus", },
+	{},
+};
+
+void __init sirfsoc_mach_init(void)
+{
+	of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL);
+}
+
+static const char *prima2cb_dt_match[] __initdata = {
+       "sirf,prima2-cb",
+       NULL
+};
+
+MACHINE_START(PRIMA2_EVB, "prima2cb")
+	.boot_params	= 0x00000100,
+	.init_early     = sirfsoc_of_clk_init,
+	.map_io		= sirfsoc_map_lluart,
+	.init_irq	= sirfsoc_of_irq_init,
+	.timer		= &sirfsoc_timer,
+	.init_machine	= sirfsoc_mach_init,
+	.dt_compat      = prima2cb_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c
new file mode 100644
index 0000000..d074786
--- /dev/null
+++ b/arch/arm/mach-prima2/rstc.c
@@ -0,0 +1,69 @@ 
+/*
+ * reset controller 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/mutex.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+void __iomem *sirfsoc_rstc_base;
+static DEFINE_MUTEX(rstc_lock);
+
+static struct of_device_id rstc_ids[]  = {
+	{ .compatible = "sirf,prima2-rstc" },
+};
+
+static int __init sirfsoc_of_rstc_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, rstc_ids);
+	if (!np)
+		panic("unable to find compatible rstc node in dtb\n");
+
+	sirfsoc_rstc_base = of_iomap(np, 0);
+	if (!sirfsoc_rstc_base)
+		panic("unable to map rstc cpu registers\n");
+
+	of_node_put(np);
+
+	return 0;
+}
+early_initcall(sirfsoc_of_rstc_init);
+
+int sirfsoc_reset_device(struct device *dev)
+{
+	const unsigned int *prop = of_get_property(dev->of_node, "reset-bit", NULL);
+	unsigned int reset_bit;
+
+	if (!prop)
+		return -ENODEV;
+
+	reset_bit = be32_to_cpup(prop);
+
+	mutex_lock(&rstc_lock);
+
+	/*
+	 * Writing 1 to this bit resets corresponding block. Writing 0 to this
+	 * bit de-asserts reset signal of the corresponding block.
+	 * datasheet doesn't require explicit delay between the set and clear
+	 * of reset bit. it could be shorter if tests pass.
+	 */
+	writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit,
+		sirfsoc_rstc_base + (reset_bit / 32) * 4);
+	msleep(10);
+	writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit,
+		sirfsoc_rstc_base + (reset_bit / 32) * 4);
+
+	mutex_unlock(&rstc_lock);
+
+	return 0;
+}
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c
new file mode 100644
index 0000000..cc30bc6
--- /dev/null
+++ b/arch/arm/mach-prima2/timer.c
@@ -0,0 +1,219 @@ 
+/*
+ * 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/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <mach/map.h>
+#include <asm/mach/time.h>
+
+#define SIRFSOC_TIMER_COUNTER_LO	0x0000
+#define SIRFSOC_TIMER_COUNTER_HI	0x0004
+#define SIRFSOC_TIMER_MATCH_0		0x0008
+#define SIRFSOC_TIMER_MATCH_1		0x000C
+#define SIRFSOC_TIMER_MATCH_2		0x0010
+#define SIRFSOC_TIMER_MATCH_3		0x0014
+#define SIRFSOC_TIMER_MATCH_4		0x0018
+#define SIRFSOC_TIMER_MATCH_5		0x001C
+#define SIRFSOC_TIMER_STATUS		0x0020
+#define SIRFSOC_TIMER_INT_EN		0x0024
+#define SIRFSOC_TIMER_WATCHDOG_EN	0x0028
+#define SIRFSOC_TIMER_DIV		0x002C
+#define SIRFSOC_TIMER_LATCH		0x0030
+#define SIRFSOC_TIMER_LATCHED_LO	0x0034
+#define SIRFSOC_TIMER_LATCHED_HI	0x0038
+
+#define SIRFSOC_TIMER_WDT_INDEX		5
+
+#define SIRFSOC_TIMER_LATCH_BIT	 BIT(0)
+
+static void __iomem *sirfsoc_timer_base;
+static void __init sirfsoc_of_timer_map(void);
+
+/* timer0 interrupt handler */
+static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ce = dev_id;
+
+	WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0)));
+
+	/* clear timer0 interrupt */
+	writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
+
+	ce->event_handler(ce);
+
+	return IRQ_HANDLED;
+}
+
+/* read 64-bit timer counter */
+static cycle_t sirfsoc_timer_read(struct clocksource *cs)
+{
+	u64 cycles;
+
+	/* latch the 64-bit timer counter */
+	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
+	cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
+	cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
+
+	return cycles;
+}
+
+static int sirfsoc_timer_set_next_event(unsigned long delta,
+	struct clock_event_device *ce)
+{
+	unsigned long now, next;
+
+	writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
+	now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
+	do {
+		next = now + delta;
+		writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
+		writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
+		now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
+	} while ((next - now) > delta);
+
+	return 0;
+}
+
+static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
+	struct clock_event_device *ce)
+{
+	u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		WARN_ON(1);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+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,
+};
+
+static struct irqaction sirfsoc_timer_irq = {
+	.name = "sirfsoc_timer0",
+	.flags = IRQF_TIMER,
+	.irq = 0,
+	.handler = sirfsoc_timer_interrupt,
+	.dev_id = &sirfsoc_clockevent,
+};
+
+/* Overwrite weak default sched_clock with more precise one */
+unsigned long long notrace sched_clock(void)
+{
+	static int is_mapped = 0;
+
+	/*
+	 * sched_clock is called earlier than .init of sys_timer
+	 * if we map timer memory in .init of sys_timer, system
+	 * will panic due to illegal memory access
+	 */
+	if(!is_mapped) {
+		sirfsoc_of_timer_map();
+		is_mapped = 1;
+	}
+
+	return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE);
+}
+
+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);
+	sirfsoc_clockevent.min_delta_ns =
+		clockevent_delta2ns(2, &sirfsoc_clockevent);
+
+	sirfsoc_clockevent.cpumask = cpumask_of(0);
+	clockevents_register_device(&sirfsoc_clockevent);
+}
+
+/* initialize the kernel jiffy timer source */
+static void __init sirfsoc_timer_init(void)
+{
+	unsigned long rate;
+
+	/* timer's input clock is io clock */
+	struct clk *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);
+
+	writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
+	writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_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,prima2-tick" },
+};
+
+static void __init sirfsoc_of_timer_map(void)
+{
+	struct device_node *np;
+	const unsigned int *intspec;
+
+	np = of_find_matching_node(NULL, timer_ids);
+	if (!np)
+		panic("unable to find compatible timer node in dtb\n");
+	sirfsoc_timer_base = of_iomap(np, 0);
+	if (!sirfsoc_timer_base)
+		panic("unable to map timer cpu registers\n");
+
+	/* Get the interrupts property */
+	intspec = of_get_property(np, "interrupts", NULL);
+	BUG_ON(!intspec);
+	sirfsoc_timer_irq.irq = be32_to_cpup(intspec);
+
+	of_node_put(np);
+}
+
+struct sys_timer sirfsoc_timer = {
+	.init = sirfsoc_timer_init,
+};
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 0074b8d..edf0681 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -821,7 +821,7 @@  config CACHE_L2X0
 	depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
 		   REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \
 		   ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \
-		   ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE
+		   ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || ARCH_PRIMA2
 	default y
 	select OUTER_CACHE
 	select OUTER_CACHE_SYNC