diff options
42 files changed, 976 insertions, 39 deletions
diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README index da0151db9964..5a930c1528ad 100644 --- a/Documentation/arm/Marvell/README +++ b/Documentation/arm/Marvell/README @@ -211,6 +211,30 @@ MMP/MMP2 family (communication processor) Linux kernel mach directory: arch/arm/mach-mmp Linux kernel plat directory: arch/arm/plat-pxa +Berlin family (Digital Entertainment) +------------------------------------- + + Flavors: + 88DE3005, Armada 1500-mini + Design name: BG2CD + Core: ARM Cortex-A9, PL310 L2CC + Homepage: http://www.marvell.com/digital-entertainment/armada-1500-mini/ + 88DE3100, Armada 1500 + Design name: BG2 + Core: Marvell PJ4B (ARMv7), Tauros3 L2CC + Homepage: http://www.marvell.com/digital-entertainment/armada-1500/ + Product Brief: http://www.marvell.com/digital-entertainment/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf + 88DE???? + Design name: BG3 + Core: ARM Cortex-A15, CA15 integrated L2CC + + Homepage: http://www.marvell.com/digital-entertainment/ + Directory: arch/arm/mach-berlin + + Comments: + * This line of SoCs is based on Marvell Sheeva or ARM Cortex CPUs + with Synopsys DesignWare (IRQ, GPIO, Timers, ...) and PXA IP (SDHCI, USB, ETH, ...). + Long-term plans --------------- diff --git a/Documentation/devicetree/bindings/arm/marvell,berlin.txt b/Documentation/devicetree/bindings/arm/marvell,berlin.txt new file mode 100644 index 000000000000..737afa5f8148 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/marvell,berlin.txt @@ -0,0 +1,24 @@ +Marvell Berlin SoC Family Device Tree Bindings +--------------------------------------------------------------- + +Boards with a SoC of the Marvell Berlin family, e.g. Armada 1500 +shall have the following properties: + +* Required root node properties: +compatible: must contain "marvell,berlin" + +In addition, the above compatible shall be extended with the specific +SoC and board used. Currently known SoC compatibles are: + "marvell,berlin2" for Marvell Armada 1500 (BG2, 88DE3100), + "marvell,berlin2cd" for Marvell Armada 1500-mini (BG2CD, 88DE3005) + "marvell,berlin2ct" for Marvell Armada ? (BG2CT, 88DE????) + "marvell,berlin3" for Marvell Armada ? (BG3, 88DE????) + +* Example: + +/ { + model = "Sony NSZ-GS7"; + compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin"; + + ... +} diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt new file mode 100644 index 000000000000..492911744ca3 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt @@ -0,0 +1,32 @@ +Synopsys DesignWare APB interrupt controller (dw_apb_ictl) + +Synopsys DesignWare provides interrupt controller IP for APB known as +dw_apb_ictl. The IP is used as secondary interrupt controller in some SoCs with +APB bus, e.g. Marvell Armada 1500. + +Required properties: +- compatible: shall be "snps,dw-apb-ictl" +- reg: physical base address of the controller and length of memory mapped + region starting with ENABLE_LOW register +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: number of cells to encode an interrupt-specifier, shall be 1 +- interrupts: interrupt reference to primary interrupt controller +- interrupt-parent: (optional) reference specific primary interrupt controller + +The interrupt sources map to the corresponding bits in the interrupt +registers, i.e. +- 0 maps to bit 0 of low interrupts, +- 1 maps to bit 1 of low interrupts, +- 32 maps to bit 0 of high interrupts, +- 33 maps to bit 1 of high interrupts, +- (optional) fast interrupts start at 64. + +Example: + aic: interrupt-controller@3000 { + compatible = "snps,dw-apb-ictl"; + reg = <0x3000 0xc00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 1344816c4c06..95648eb610b3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1027,6 +1027,12 @@ L: [email protected] (moderated for non-subscribers) S: Maintained F: arch/arm/mach-mvebu/ +ARM/Marvell Berlin SoC support +M: Sebastian Hesselbarth <[email protected]> +L: [email protected] (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-berlin/ + ARM/Marvell Dove/Kirkwood/MV78xx0/Orion SOC support M: Jason Cooper <[email protected]> M: Andrew Lunn <[email protected]> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6808460a48ba..6a8d80be1c4c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -931,6 +931,8 @@ source "arch/arm/mach-bcm/Kconfig" source "arch/arm/mach-bcm2835/Kconfig" +source "arch/arm/mach-berlin/Kconfig" + source "arch/arm/mach-clps711x/Kconfig" source "arch/arm/mach-cns3xxx/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 5765abf5ce84..257155874bce 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -94,6 +94,14 @@ choice depends on ARCH_BCM2835 select DEBUG_UART_PL01X + config DEBUG_BERLIN_UART + bool "Marvell Berlin SoC Debug UART" + depends on ARCH_BERLIN + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on Marvell Berlin SoC based platforms. + config DEBUG_CLPS711X_UART1 bool "Kernel low-level debugging messages via UART1" depends on ARCH_CLPS711X @@ -1011,6 +1019,7 @@ config DEBUG_UART_PHYS default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE default 0xf1012000 if ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \ ARCH_ORION5X + default 0xf7fc9000 if DEBUG_BERLIN_UART default 0xf8b00000 if DEBUG_HI3716_UART default 0xfcb00000 if DEBUG_HI3620_UART default 0xfe800000 if ARCH_IOP32X @@ -1036,6 +1045,7 @@ config DEBUG_UART_VIRT default 0xf2100000 if DEBUG_PXA_UART1 default 0xf4090000 if ARCH_LPC32XX default 0xf4200000 if ARCH_GEMINI + default 0xf7fc9000 if DEBUG_BERLIN_UART default 0xf8009000 if DEBUG_VEXPRESS_UART0_CA9 default 0xf8090000 if DEBUG_VEXPRESS_UART0_RS1 default 0xfb009000 if DEBUG_REALVIEW_STD_PORT diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 6da9abb30460..b2f8222bb6c4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -148,6 +148,7 @@ textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 machine-$(CONFIG_ARCH_AT91) += at91 machine-$(CONFIG_ARCH_BCM) += bcm machine-$(CONFIG_ARCH_BCM2835) += bcm2835 +machine-$(CONFIG_ARCH_BERLIN) += berlin machine-$(CONFIG_ARCH_CLPS711X) += clps711x machine-$(CONFIG_ARCH_CNS3XXX) += cns3xxx machine-$(CONFIG_ARCH_DAVINCI) += davinci diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index e4a0bea3c767..e1bf28743b98 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -45,6 +45,9 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm11351-brt.dtb \ bcm28155-ap.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb +dtb-$(CONFIG_ARCH_BERLIN) += \ + berlin2-sony-nsz-gs7.dtb \ + berlin2cd-google-chromecast.dtb dtb-$(CONFIG_ARCH_DAVINCI) += da850-enbw-cmc.dtb \ da850-evm.dtb dtb-$(CONFIG_ARCH_DOVE) += dove-cm-a510.dtb \ diff --git a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts new file mode 100644 index 000000000000..c72bfd468d10 --- /dev/null +++ b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts @@ -0,0 +1,29 @@ +/* + * Device Tree file for Sony NSZ-GS7 + * + * Sebastian Hesselbarth <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +#include "berlin2.dtsi" + +/ { + model = "Sony NSZ-GS7"; + compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin"; + + chosen { + bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; /* 1 GB */ + }; +}; + +&uart0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi new file mode 100644 index 000000000000..56a1af2f1052 --- /dev/null +++ b/arch/arm/boot/dts/berlin2.dtsi @@ -0,0 +1,227 @@ +/* + * Device Tree Include file for Marvell Armada 1500 (Berlin BG2) SoC + * + * Sebastian Hesselbarth <[email protected]> + * + * based on GPL'ed 2.6 kernel sources + * (c) Marvell International Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include "skeleton.dtsi" +#include <dt-bindings/interrupt-controller/arm-gic.h> + +/ { + model = "Marvell Armada 1500 (BG2) SoC"; + compatible = "marvell,berlin2", "marvell,berlin"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "marvell,pj4b"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <0>; + }; + + cpu@1 { + compatible = "marvell,pj4b"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <1>; + }; + }; + + clocks { + smclk: sysmgr-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + + cfgclk: cfg-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <400000000>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + ranges = <0 0xf7000000 0x1000000>; + + l2: l2-cache-controller@ac0000 { + compatible = "marvell,tauros3-cache", "arm,pl310-cache"; + reg = <0xac0000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + gic: interrupt-controller@ad1000 { + compatible = "arm,cortex-a9-gic"; + reg = <0xad1000 0x1000>, <0xad0100 0x0100>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + local-timer@ad0600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xad0600 0x20>; + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sysclk>; + }; + + apb@e80000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xe80000 0x10000>; + interrupt-parent = <&aic>; + + timer0: timer@2c00 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c00 0x14>; + interrupts = <8>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "okay"; + }; + + timer1: timer@2c14 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c14 0x14>; + interrupts = <9>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "okay"; + }; + + timer2: timer@2c28 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c28 0x14>; + interrupts = <10>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer3: timer@2c3c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c3c 0x14>; + interrupts = <11>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer4: timer@2c50 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c50 0x14>; + interrupts = <12>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer5: timer@2c64 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c64 0x14>; + interrupts = <13>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer6: timer@2c78 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c78 0x14>; + interrupts = <14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer7: timer@2c8c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c8c 0x14>; + interrupts = <15>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + aic: interrupt-controller@3000 { + compatible = "snps,dw-apb-ictl"; + reg = <0x3000 0xc00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + apb@fc0000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xfc0000 0x10000>; + interrupt-parent = <&sic>; + + uart0: serial@9000 { + compatible = "snps,dw-apb-uart"; + reg = <0x9000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <8>; + clocks = <&smclk>; + status = "disabled"; + }; + + uart1: serial@a000 { + compatible = "snps,dw-apb-uart"; + reg = <0xa000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <9>; + clocks = <&smclk>; + status = "disabled"; + }; + + uart2: serial@b000 { + compatible = "snps,dw-apb-uart"; + reg = <0xb000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <10>; + clocks = <&smclk>; + status = "disabled"; + }; + + sic: interrupt-controller@e000 { + compatible = "snps,dw-apb-ictl"; + reg = <0xe000 0x400>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts new file mode 100644 index 000000000000..bcd81ffc495d --- /dev/null +++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts @@ -0,0 +1,29 @@ +/* + * Device Tree file for Google Chromecast + * + * Sebastian Hesselbarth <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +#include "berlin2cd.dtsi" + +/ { + model = "Google Chromecast"; + compatible = "google,chromecast", "marvell,berlin2cd", "marvell,berlin"; + + chosen { + bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x20000000>; /* 512 MB */ + }; +}; + +&uart0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi new file mode 100644 index 000000000000..094968c27533 --- /dev/null +++ b/arch/arm/boot/dts/berlin2cd.dtsi @@ -0,0 +1,210 @@ +/* + * Device Tree Include file for Marvell Armada 1500-mini (Berlin BG2CD) SoC + * + * Sebastian Hesselbarth <[email protected]> + * + * based on GPL'ed 2.6 kernel sources + * (c) Marvell International Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include "skeleton.dtsi" +#include <dt-bindings/interrupt-controller/arm-gic.h> + +/ { + model = "Marvell Armada 1500-mini (BG2CD) SoC"; + compatible = "marvell,berlin2cd", "marvell,berlin"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <0>; + }; + }; + + clocks { + smclk: sysmgr-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + + cfgclk: cfg-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <75000000>; + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <300000000>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + ranges = <0 0xf7000000 0x1000000>; + + l2: l2-cache-controller@ac0000 { + compatible = "arm,pl310-cache"; + reg = <0xac0000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + gic: interrupt-controller@ad1000 { + compatible = "arm,cortex-a9-gic"; + reg = <0xad1000 0x1000>, <0xad0100 0x0100>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + local-timer@ad0600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xad0600 0x20>; + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sysclk>; + }; + + apb@e80000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xe80000 0x10000>; + interrupt-parent = <&aic>; + + timer0: timer@2c00 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c00 0x14>; + interrupts = <8>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "okay"; + }; + + timer1: timer@2c14 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c14 0x14>; + interrupts = <9>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "okay"; + }; + + timer2: timer@2c28 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c28 0x14>; + interrupts = <10>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer3: timer@2c3c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c3c 0x14>; + interrupts = <11>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer4: timer@2c50 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c50 0x14>; + interrupts = <12>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer5: timer@2c64 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c64 0x14>; + interrupts = <13>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer6: timer@2c78 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c78 0x14>; + interrupts = <14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer7: timer@2c8c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c8c 0x14>; + interrupts = <15>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + aic: interrupt-controller@3000 { + compatible = "snps,dw-apb-ictl"; + reg = <0x3000 0xc00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + apb@fc0000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xfc0000 0x10000>; + interrupt-parent = <&sic>; + + uart0: serial@9000 { + compatible = "snps,dw-apb-uart"; + reg = <0x9000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <8>; + clocks = <&smclk>; + status = "disabled"; + }; + + uart1: serial@a000 { + compatible = "snps,dw-apb-uart"; + reg = <0xa000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <9>; + clocks = <&smclk>; + status = "disabled"; + }; + + sic: interrupt-controller@e000 { + compatible = "snps,dw-apb-ictl"; + reg = <0xe000 0x400>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + }; +}; diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index ce922d0ea7aa..53c6a26b633d 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -66,7 +66,7 @@ static long __init sp804_get_clock_rate(struct clk *clk) static void __iomem *sched_clock_base; -static u32 sp804_read(void) +static u64 notrace sp804_read(void) { return ~readl_relaxed(sched_clock_base + TIMER_VALUE); } @@ -104,7 +104,7 @@ void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, if (use_sched_clock) { sched_clock_base = base; - setup_sched_clock(sp804_read, 32, rate); + sched_clock_register(sp804_read, 32, rate); } } diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index c1df4e9db140..7e3f5cba7cfd 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -7,6 +7,9 @@ CONFIG_MACH_ARMADA_370=y CONFIG_MACH_ARMADA_XP=y CONFIG_ARCH_BCM=y CONFIG_ARCH_BCM_MOBILE=y +CONFIG_ARCH_BERLIN=y +CONFIG_MACH_BERLIN_BG2=y +CONFIG_MACH_BERLIN_BG2CD=y CONFIG_GPIO_PCA953X=y CONFIG_ARCH_HIGHBANK=y CONFIG_ARCH_KEYSTONE=y diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 699b71e7f7ec..44eacdd7468b 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -67,7 +67,7 @@ config SOC_SAMA5D3 select HAVE_AT91_DBGU1 help Select this if you are using one of Atmel's SAMA5D3 family SoC. - This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35. + This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35, SAMA5D36. endif if SOC_SAM_V4_V5 diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h index d3d7b993846b..86c71debab5b 100644 --- a/arch/arm/mach-at91/include/mach/cpu.h +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -53,6 +53,7 @@ #define ARCH_EXID_SAMA5D33 0x00414300 #define ARCH_EXID_SAMA5D34 0x00414301 #define ARCH_EXID_SAMA5D35 0x00584300 +#define ARCH_EXID_SAMA5D36 0x00004301 #define ARCH_FAMILY_AT91X92 0x09200000 #define ARCH_FAMILY_AT91SAM9 0x01900000 @@ -105,7 +106,7 @@ enum at91_soc_subtype { /* SAMA5D3 */ AT91_SOC_SAMA5D31, AT91_SOC_SAMA5D33, AT91_SOC_SAMA5D34, - AT91_SOC_SAMA5D35, + AT91_SOC_SAMA5D35, AT91_SOC_SAMA5D36, /* No subtype for this SoC */ AT91_SOC_SUBTYPE_NONE, diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 094b3459c288..eb6468dc60d5 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -233,6 +233,9 @@ static void __init soc_detect(u32 dbgu_base) case ARCH_EXID_SAMA5D35: at91_soc_initdata.subtype = AT91_SOC_SAMA5D35; break; + case ARCH_EXID_SAMA5D36: + at91_soc_initdata.subtype = AT91_SOC_SAMA5D36; + break; } } } @@ -275,6 +278,7 @@ static const char *soc_subtype_name[] = { [AT91_SOC_SAMA5D33] = "sama5d33", [AT91_SOC_SAMA5D34] = "sama5d34", [AT91_SOC_SAMA5D35] = "sama5d35", + [AT91_SOC_SAMA5D36] = "sama5d36", [AT91_SOC_SUBTYPE_NONE] = "None", [AT91_SOC_SUBTYPE_UNKNOWN] = "Unknown", }; diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig new file mode 100644 index 000000000000..7a02d222c378 --- /dev/null +++ b/arch/arm/mach-berlin/Kconfig @@ -0,0 +1,29 @@ +config ARCH_BERLIN + bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 + select ARM_GIC + select GENERIC_CLOCKEVENTS + select GENERIC_IRQ_CHIP + select COMMON_CLK + select DW_APB_ICTL + select DW_APB_TIMER_OF + +if ARCH_BERLIN + +menu "Marvell Berlin SoC variants" + +config MACH_BERLIN_BG2 + bool "Marvell Armada 1500 (BG2)" + select CACHE_L2X0 + select CPU_PJ4B + select HAVE_ARM_TWD if SMP + select HAVE_SMP + +config MACH_BERLIN_BG2CD + bool "Marvell Armada 1500-mini (BG2CD)" + select CACHE_L2X0 + select CPU_V7 + select HAVE_ARM_TWD if SMP + +endmenu + +endif diff --git a/arch/arm/mach-berlin/Makefile b/arch/arm/mach-berlin/Makefile new file mode 100644 index 000000000000..ab69fe956f49 --- /dev/null +++ b/arch/arm/mach-berlin/Makefile @@ -0,0 +1 @@ +obj-y += berlin.o diff --git a/arch/arm/mach-berlin/berlin.c b/arch/arm/mach-berlin/berlin.c new file mode 100644 index 000000000000..025bcb5473eb --- /dev/null +++ b/arch/arm/mach-berlin/berlin.c @@ -0,0 +1,39 @@ +/* + * Device Tree support for Marvell Berlin SoCs. + * + * Sebastian Hesselbarth <[email protected]> + * + * based on GPL'ed 2.6 kernel sources + * (c) Marvell International Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/of_platform.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/mach/arch.h> + +static void __init berlin_init_machine(void) +{ + /* + * with DT probing for L2CCs, berlin_init_machine can be removed. + * Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc + */ + l2x0_of_init(0x70c00000, 0xfeffffff); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static const char * const berlin_dt_compat[] = { + "marvell,berlin", + NULL, +}; + +DT_MACHINE_START(BERLIN_DT, "Marvell Berlin") + .dt_compat = berlin_dt_compat, + .init_machine = berlin_init_machine, +MACHINE_END diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c index 134641d688bb..a1935911e4f1 100644 --- a/arch/arm/mach-clps711x/common.c +++ b/arch/arm/mach-clps711x/common.c @@ -259,7 +259,7 @@ asmlinkage void __exception_irq_entry clps711x_handle_irq(struct pt_regs *regs) } while (1); } -static u32 notrace clps711x_sched_clock_read(void) +static u64 notrace clps711x_sched_clock_read(void) { return ~readw_relaxed(CLPS711X_VIRT_BASE + TC1D); } @@ -366,7 +366,7 @@ void __init clps711x_timer_init(void) tmp = clps_readl(SYSCON1) & ~(SYSCON1_TC1S | SYSCON1_TC1M); clps_writel(tmp, SYSCON1); - setup_sched_clock(clps711x_sched_clock_read, 16, timl); + sched_clock_register(clps711x_sched_clock_read, 16, timl); clocksource_mmio_init(CLPS711X_VIRT_BASE + TC1D, "clps711x_clocksource", timl, 300, 16, diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index 56c6eb5266ad..24ad30f32ae3 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c @@ -285,7 +285,7 @@ static struct clocksource clocksource_davinci = { /* * Overwrite weak default sched_clock with something more precise */ -static u32 notrace davinci_read_sched_clock(void) +static u64 notrace davinci_read_sched_clock(void) { return timer32_read(&timers[TID_CLOCKSOURCE]); } @@ -391,7 +391,7 @@ void __init davinci_timer_init(void) davinci_clock_tick_rate)) printk(err, clocksource_davinci.name); - setup_sched_clock(davinci_read_sched_clock, 32, + sched_clock_register(davinci_read_sched_clock, 32, davinci_clock_tick_rate); /* setup clockevent */ diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig index 93e54fd4e3d5..bec570ae6494 100644 --- a/arch/arm/mach-ep93xx/Kconfig +++ b/arch/arm/mach-ep93xx/Kconfig @@ -5,6 +5,7 @@ menu "Cirrus EP93xx Implementation Options" config EP93XX_SOC_COMMON bool default y + select SOC_BUS select LEDS_GPIO_REGISTER config CRUNCH diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index d95ee28a616a..157ba88433c9 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -21,6 +21,7 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/dma-mapping.h> +#include <linux/sys_soc.h> #include <linux/timex.h> #include <linux/irq.h> #include <linux/io.h> @@ -44,6 +45,7 @@ #include <linux/platform_data/spi-ep93xx.h> #include <mach/gpio-ep93xx.h> +#include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/time.h> @@ -137,7 +139,7 @@ static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id) static struct irqaction ep93xx_timer_irq = { .name = "ep93xx timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = ep93xx_timer_interrupt, }; @@ -925,8 +927,108 @@ void ep93xx_ide_release_gpio(struct platform_device *pdev) } EXPORT_SYMBOL(ep93xx_ide_release_gpio); -void __init ep93xx_init_devices(void) +/************************************************************************* + * EP93xx Security peripheral + *************************************************************************/ + +/* + * The Maverick Key is 256 bits of micro fuses blown at the factory during + * manufacturing to uniquely identify a part. + * + * See: http://arm.cirrus.com/forum/viewtopic.php?t=486&highlight=maverick+key + */ +#define EP93XX_SECURITY_REG(x) (EP93XX_SECURITY_BASE + (x)) +#define EP93XX_SECURITY_SECFLG EP93XX_SECURITY_REG(0x2400) +#define EP93XX_SECURITY_FUSEFLG EP93XX_SECURITY_REG(0x2410) +#define EP93XX_SECURITY_UNIQID EP93XX_SECURITY_REG(0x2440) +#define EP93XX_SECURITY_UNIQCHK EP93XX_SECURITY_REG(0x2450) +#define EP93XX_SECURITY_UNIQVAL EP93XX_SECURITY_REG(0x2460) +#define EP93XX_SECURITY_SECID1 EP93XX_SECURITY_REG(0x2500) +#define EP93XX_SECURITY_SECID2 EP93XX_SECURITY_REG(0x2504) +#define EP93XX_SECURITY_SECCHK1 EP93XX_SECURITY_REG(0x2520) +#define EP93XX_SECURITY_SECCHK2 EP93XX_SECURITY_REG(0x2524) +#define EP93XX_SECURITY_UNIQID2 EP93XX_SECURITY_REG(0x2700) +#define EP93XX_SECURITY_UNIQID3 EP93XX_SECURITY_REG(0x2704) +#define EP93XX_SECURITY_UNIQID4 EP93XX_SECURITY_REG(0x2708) +#define EP93XX_SECURITY_UNIQID5 EP93XX_SECURITY_REG(0x270c) + +static char ep93xx_soc_id[33]; + +static const char __init *ep93xx_get_soc_id(void) { + unsigned int id, id2, id3, id4, id5; + + if (__raw_readl(EP93XX_SECURITY_UNIQVAL) != 1) + return "bad Hamming code"; + + id = __raw_readl(EP93XX_SECURITY_UNIQID); + id2 = __raw_readl(EP93XX_SECURITY_UNIQID2); + id3 = __raw_readl(EP93XX_SECURITY_UNIQID3); + id4 = __raw_readl(EP93XX_SECURITY_UNIQID4); + id5 = __raw_readl(EP93XX_SECURITY_UNIQID5); + + if (id != id2) + return "invalid"; + + snprintf(ep93xx_soc_id, sizeof(ep93xx_soc_id), + "%08x%08x%08x%08x", id2, id3, id4, id5); + + return ep93xx_soc_id; +} + +static const char __init *ep93xx_get_soc_rev(void) +{ + int rev = ep93xx_chip_revision(); + + switch (rev) { + case EP93XX_CHIP_REV_D0: + return "D0"; + case EP93XX_CHIP_REV_D1: + return "D1"; + case EP93XX_CHIP_REV_E0: + return "E0"; + case EP93XX_CHIP_REV_E1: + return "E1"; + case EP93XX_CHIP_REV_E2: + return "E2"; + default: + return "unknown"; + } +} + +static const char __init *ep93xx_get_machine_name(void) +{ + return kasprintf(GFP_KERNEL,"%s", machine_desc->name); +} + +static struct device __init *ep93xx_init_soc(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return NULL; + + soc_dev_attr->machine = ep93xx_get_machine_name(); + soc_dev_attr->family = "Cirrus Logic EP93xx"; + soc_dev_attr->revision = ep93xx_get_soc_rev(); + soc_dev_attr->soc_id = ep93xx_get_soc_id(); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->machine); + kfree(soc_dev_attr); + return NULL; + } + + return soc_device_to_device(soc_dev); +} + +struct device __init *ep93xx_init_devices(void) +{ + struct device *parent; + /* Disallow access to MaverickCrunch initially */ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA); @@ -937,6 +1039,8 @@ void __init ep93xx_init_devices(void) EP93XX_SYSCON_DEVCFG_GONIDE | EP93XX_SYSCON_DEVCFG_HONIDE); + parent = ep93xx_init_soc(); + /* Get the GPIO working early, other devices need it */ platform_device_register(&ep93xx_gpio_device); @@ -949,6 +1053,8 @@ void __init ep93xx_init_devices(void) platform_device_register(&ep93xx_wdt_device); gpio_led_register_device(-1, &ep93xx_led_data); + + return parent; } void ep93xx_restart(enum reboot_mode mode, const char *cmd) diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index e256e0baec2e..4c0bbd97f741 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h @@ -6,6 +6,7 @@ #include <linux/reboot.h> +struct device; struct i2c_gpio_platform_data; struct i2c_board_info; struct spi_board_info; @@ -54,7 +55,7 @@ void ep93xx_register_ide(void); int ep93xx_ide_acquire_gpio(struct platform_device *pdev); void ep93xx_ide_release_gpio(struct platform_device *pdev); -void ep93xx_init_devices(void); +struct device *ep93xx_init_devices(void); extern void ep93xx_timer_init(void); void ep93xx_restart(enum reboot_mode, const char *); diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index 9b6638aadeaa..1a3a5f615770 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -111,7 +111,7 @@ static void gpt_irq_acknowledge(void) static void __iomem *sched_clock_reg; -static u32 notrace mxc_read_sched_clock(void) +static u64 notrace mxc_read_sched_clock(void) { return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0; } @@ -123,7 +123,7 @@ static int __init mxc_clocksource_init(struct clk *timer_clk) sched_clock_reg = reg; - setup_sched_clock(mxc_read_sched_clock, 32, c); + sched_clock_register(mxc_read_sched_clock, 32, c); return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32, clocksource_mmio_readl_up); } diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index d50dc2dbfd89..473e21b87364 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -277,7 +277,7 @@ struct amba_pl010_data ap_uart_data = { static unsigned long timer_reload; -static u32 notrace integrator_read_sched_clock(void) +static u64 notrace integrator_read_sched_clock(void) { return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); } @@ -298,7 +298,7 @@ static void integrator_clocksource_init(unsigned long inrate, clocksource_mmio_init(base + TIMER_VALUE, "timer2", rate, 200, 16, clocksource_mmio_readl_down); - setup_sched_clock(integrator_read_sched_clock, 16, rate); + sched_clock_register(integrator_read_sched_clock, 16, rate); } static void __iomem * clkevt_base; diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 9edaf4734fa8..bc9d8ec2918e 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -475,7 +475,7 @@ void __init ixp4xx_sys_init(void) /* * sched_clock() */ -static u32 notrace ixp4xx_read_sched_clock(void) +static u64 notrace ixp4xx_read_sched_clock(void) { return *IXP4XX_OSTS; } @@ -493,7 +493,7 @@ unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ; EXPORT_SYMBOL(ixp4xx_timer_freq); static void __init ixp4xx_clocksource_init(void) { - setup_sched_clock(ixp4xx_read_sched_clock, 32, ixp4xx_timer_freq); + sched_clock_register(ixp4xx_read_sched_clock, 32, ixp4xx_timer_freq); clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32, ixp4xx_clocksource_read); diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c index 7ac41e83cfef..024022d91fe3 100644 --- a/arch/arm/mach-mmp/time.c +++ b/arch/arm/mach-mmp/time.c @@ -61,7 +61,7 @@ static inline uint32_t timer_read(void) return __raw_readl(mmp_timer_base + TMR_CVWR(1)); } -static u32 notrace mmp_read_sched_clock(void) +static u64 notrace mmp_read_sched_clock(void) { return timer_read(); } @@ -195,7 +195,7 @@ void __init timer_init(int irq) { timer_config(); - setup_sched_clock(mmp_read_sched_clock, 32, CLOCK_TICK_RATE); + sched_clock_register(mmp_read_sched_clock, 32, CLOCK_TICK_RATE); ckevt.cpumask = cpumask_of(0); diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 1e9c3383daba..fd1644987534 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -187,7 +187,7 @@ static struct notifier_block msm_timer_cpu_nb = { .notifier_call = msm_timer_cpu_notify, }; -static notrace u32 msm_sched_clock_read(void) +static u64 notrace msm_sched_clock_read(void) { return msm_clocksource.read(&msm_clocksource); } @@ -229,7 +229,7 @@ err: res = clocksource_register_hz(cs, dgt_hz); if (res) pr_err("clocksource_register failed\n"); - setup_sched_clock(msm_sched_clock_read, sched_bits, dgt_hz); + sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz); } #ifdef CONFIG_OF diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index 6b5f298d6638..a7588cfd0286 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -181,7 +181,7 @@ static __init void omap_init_mpu_timer(unsigned long rate) * --------------------------------------------------------------------------- */ -static u32 notrace omap_mpu_read_sched_clock(void) +static u64 notrace omap_mpu_read_sched_clock(void) { return ~omap_mpu_timer_read(1); } @@ -193,7 +193,7 @@ static void __init omap_init_clocksource(unsigned long rate) "%s: can't register clocksource!\n"; omap_mpu_timer_start(1, ~0, 1); - setup_sched_clock(omap_mpu_read_sched_clock, 32, rate); + sched_clock_register(omap_mpu_read_sched_clock, 32, rate); if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate, 300, 32, clocksource_mmio_readl_down)) diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 3ca81e0ada5e..ec084d158f64 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -379,7 +379,7 @@ static struct clocksource clocksource_gpt = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static u32 notrace dmtimer_read_sched_clock(void) +static u64 notrace dmtimer_read_sched_clock(void) { if (clksrc.reserved) return __omap_dm_timer_read_counter(&clksrc, @@ -471,7 +471,7 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id, __omap_dm_timer_load_start(&clksrc, OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, OMAP_TIMER_NONPOSTED); - setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); + sched_clock_register(dmtimer_read_sched_clock, 32, clksrc.rate); if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) pr_err("Could not register clocksource %s\n", diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 9aa852a8fab9..d1bfaa73b1c9 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -33,7 +33,7 @@ * calls to sched_clock() which should always be the case in practice. */ -static u32 notrace pxa_read_sched_clock(void) +static u64 notrace pxa_read_sched_clock(void) { return readl_relaxed(OSCR); } @@ -149,7 +149,7 @@ void __init pxa_timer_init(void) writel_relaxed(0, OIER); writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); - setup_sched_clock(pxa_read_sched_clock, 32, clock_tick_rate); + sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate); ckevt_pxa_osmr0.cpumask = cpumask_of(0); diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 713c86cd3d64..6fd4acb8f187 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -20,7 +20,7 @@ #include <mach/hardware.h> #include <mach/irqs.h> -static u32 notrace sa1100_read_sched_clock(void) +static u64 notrace sa1100_read_sched_clock(void) { return readl_relaxed(OSCR); } @@ -122,7 +122,7 @@ void __init sa1100_timer_init(void) writel_relaxed(0, OIER); writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); - setup_sched_clock(sa1100_read_sched_clock, 32, 3686400); + sched_clock_register(sa1100_read_sched_clock, 32, 3686400); ckevt_sa1100_osmr0.cpumask = cpumask_of(0); diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c index 9a5f9fb352ce..9724e4e7cc93 100644 --- a/arch/arm/mach-u300/timer.c +++ b/arch/arm/mach-u300/timer.c @@ -341,7 +341,7 @@ static struct irqaction u300_timer_irq = { * stamp. (Inspired by OMAP implementation.) */ -static u32 notrace u300_read_sched_clock(void) +static u64 notrace u300_read_sched_clock(void) { return readl(u300_timer_base + U300_TIMER_APP_GPT2CC); } @@ -379,7 +379,7 @@ static void __init u300_timer_init_of(struct device_node *np) clk_prepare_enable(clk); rate = clk_get_rate(clk); - setup_sched_clock(u300_read_sched_clock, 32, rate); + sched_clock_register(u300_read_sched_clock, 32, rate); u300_delay_timer.read_current_timer = &u300_read_current_timer; u300_delay_timer.freq = rate; diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c index 29606bd75f3f..d70b73364a3f 100644 --- a/arch/arm/plat-iop/time.c +++ b/arch/arm/plat-iop/time.c @@ -54,7 +54,7 @@ static struct clocksource iop_clocksource = { /* * IOP sched_clock() implementation via its clocksource. */ -static u32 notrace iop_read_sched_clock(void) +static u64 notrace iop_read_sched_clock(void) { return 0xffffffffu - read_tcr1(); } @@ -142,7 +142,7 @@ void __init iop_init_time(unsigned long tick_rate) { u32 timer_ctl; - setup_sched_clock(iop_read_sched_clock, 32, tick_rate); + sched_clock_register(iop_read_sched_clock, 32, tick_rate); ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ); iop_tick_rate = tick_rate; diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index d9bc98eb2a6b..384a776d8eb2 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c @@ -38,7 +38,7 @@ */ static void __iomem *sync32k_cnt_reg; -static u32 notrace omap_32k_read_sched_clock(void) +static u64 notrace omap_32k_read_sched_clock(void) { return sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0; } @@ -115,7 +115,7 @@ int __init omap_init_clocksource_32k(void __iomem *vbase) return ret; } - setup_sched_clock(omap_32k_read_sched_clock, 32, 32768); + sched_clock_register(omap_32k_read_sched_clock, 32, 32768); register_persistent_clock(NULL, omap_read_persistent_clock); pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n"); diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c index 9d2b2ac74938..dade2920e9a6 100644 --- a/arch/arm/plat-orion/time.c +++ b/arch/arm/plat-orion/time.c @@ -60,7 +60,7 @@ static u32 ticks_per_jiffy; * at least 7.5ns (133MHz TCLK). */ -static u32 notrace orion_read_sched_clock(void) +static u64 notrace orion_read_sched_clock(void) { return ~readl(timer_base + TIMER0_VAL_OFF); } @@ -201,7 +201,7 @@ orion_time_init(void __iomem *_bridge_base, u32 _bridge_timer1_clr_mask, /* * Set scale and timer for sched_clock. */ - setup_sched_clock(orion_read_sched_clock, 32, tclk); + sched_clock_register(orion_read_sched_clock, 32, tclk); /* * Setup free-running clocksource timer (interrupts diff --git a/arch/arm/plat-versatile/sched-clock.c b/arch/arm/plat-versatile/sched-clock.c index 51b109e3b6c3..c966ae90f4a0 100644 --- a/arch/arm/plat-versatile/sched-clock.c +++ b/arch/arm/plat-versatile/sched-clock.c @@ -26,7 +26,7 @@ static void __iomem *ctr; -static u32 notrace versatile_read_sched_clock(void) +static u64 notrace versatile_read_sched_clock(void) { if (ctr) return readl(ctr); @@ -37,5 +37,5 @@ static u32 notrace versatile_read_sched_clock(void) void __init versatile_sched_clock_init(void __iomem *reg, unsigned long rate) { ctr = reg; - setup_sched_clock(versatile_read_sched_clock, 32, rate); + sched_clock_register(versatile_read_sched_clock, 32, rate); } diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 3792a1aa52b8..940638ddc982 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -30,6 +30,10 @@ config ARM_VIC_NR The maximum number of VICs available in the system, for power management. +config DW_APB_ICTL + bool + select IRQ_DOMAIN + config IMGPDC_IRQ bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c60b9010b152..6427323af4c3 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_MMP) += irq-mmp.o obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o obj-$(CONFIG_ARCH_MXS) += irq-mxs.o obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o +obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o obj-$(CONFIG_METAG) += irq-metag-ext.o obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c new file mode 100644 index 000000000000..31e231e1f566 --- /dev/null +++ b/drivers/irqchip/irq-dw-apb-ictl.c @@ -0,0 +1,150 @@ +/* + * Synopsys DW APB ICTL irqchip driver. + * + * Sebastian Hesselbarth <[email protected]> + * + * based on GPL'ed 2.6 kernel sources + * (c) Marvell International Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#include "irqchip.h" + +#define APB_INT_ENABLE_L 0x00 +#define APB_INT_ENABLE_H 0x04 +#define APB_INT_MASK_L 0x08 +#define APB_INT_MASK_H 0x0c +#define APB_INT_FINALSTATUS_L 0x30 +#define APB_INT_FINALSTATUS_H 0x34 + +static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip_generic *gc = irq_get_handler_data(irq); + struct irq_domain *d = gc->private; + u32 stat; + int n; + + chained_irq_enter(chip, desc); + + for (n = 0; n < gc->num_ct; n++) { + stat = readl_relaxed(gc->reg_base + + APB_INT_FINALSTATUS_L + 4 * n); + while (stat) { + u32 hwirq = ffs(stat) - 1; + generic_handle_irq(irq_find_mapping(d, + gc->irq_base + hwirq + 32 * n)); + stat &= ~(1 << hwirq); + } + } + + chained_irq_exit(chip, desc); +} + +static int __init dw_apb_ictl_init(struct device_node *np, + struct device_node *parent) +{ + unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; + struct resource r; + struct irq_domain *domain; + struct irq_chip_generic *gc; + void __iomem *iobase; + int ret, nrirqs, irq; + u32 reg; + + /* Map the parent interrupt for the chained handler */ + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_err("%s: unable to parse irq\n", np->full_name); + return -EINVAL; + } + + ret = of_address_to_resource(np, 0, &r); + if (ret) { + pr_err("%s: unable to get resource\n", np->full_name); + return ret; + } + + if (!request_mem_region(r.start, resource_size(&r), np->full_name)) { + pr_err("%s: unable to request mem region\n", np->full_name); + return -ENOMEM; + } + + iobase = ioremap(r.start, resource_size(&r)); + if (!iobase) { + pr_err("%s: unable to map resource\n", np->full_name); + ret = -ENOMEM; + goto err_release; + } + + /* + * DW IP can be configured to allow 2-64 irqs. We can determine + * the number of irqs supported by writing into enable register + * and look for bits not set, as corresponding flip-flops will + * have been removed by sythesis tool. + */ + + /* mask and enable all interrupts */ + writel(~0, iobase + APB_INT_MASK_L); + writel(~0, iobase + APB_INT_MASK_H); + writel(~0, iobase + APB_INT_ENABLE_L); + writel(~0, iobase + APB_INT_ENABLE_H); + + reg = readl(iobase + APB_INT_ENABLE_H); + if (reg) + nrirqs = 32 + fls(reg); + else + nrirqs = fls(readl(iobase + APB_INT_ENABLE_L)); + + domain = irq_domain_add_linear(np, nrirqs, + &irq_generic_chip_ops, NULL); + if (!domain) { + pr_err("%s: unable to add irq domain\n", np->full_name); + ret = -ENOMEM; + goto err_unmap; + } + + ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1, + np->name, handle_level_irq, clr, 0, + IRQ_GC_INIT_MASK_CACHE); + if (ret) { + pr_err("%s: unable to alloc irq domain gc\n", np->full_name); + goto err_unmap; + } + + gc = irq_get_domain_generic_chip(domain, 0); + gc->private = domain; + gc->reg_base = iobase; + + gc->chip_types[0].regs.mask = APB_INT_MASK_L; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; + + if (nrirqs > 32) { + gc->chip_types[1].regs.mask = APB_INT_MASK_H; + gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit; + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit; + } + + irq_set_handler_data(irq, gc); + irq_set_chained_handler(irq, dw_apb_ictl_handler); + + return 0; + +err_unmap: + iounmap(iobase); +err_release: + release_mem_region(r.start, resource_size(&r)); + return ret; +} +IRQCHIP_DECLARE(dw_apb_ictl, + "snps,dw-apb-ictl", dw_apb_ictl_init); |