aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/arm/sunxi/README19
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt104
-rw-r--r--Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt17
-rw-r--r--MAINTAINERS6
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/Kconfig.debug8
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/boot/dts/Makefile1
-rw-r--r--arch/arm/boot/dts/sun5i-olinuxino.dts26
-rw-r--r--arch/arm/boot/dts/sun5i.dtsi74
-rw-r--r--arch/arm/include/debug/sunxi.S24
-rw-r--r--arch/arm/mach-sunxi/Kconfig9
-rw-r--r--arch/arm/mach-sunxi/Makefile1
-rw-r--r--arch/arm/mach-sunxi/Makefile.boot1
-rw-r--r--arch/arm/mach-sunxi/sunxi.c60
-rw-r--r--arch/arm/mach-sunxi/sunxi.h20
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-sunxi.c30
-rw-r--r--drivers/clocksource/Kconfig3
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/sunxi_timer.c170
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-sunxi.c150
-rw-r--r--include/linux/clk/sunxi.h22
-rw-r--r--include/linux/irqchip/sunxi.h27
-rw-r--r--include/linux/sunxi_timer.h24
26 files changed, 802 insertions, 0 deletions
diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README
new file mode 100644
index 000000000000..87a1e8fb6242
--- /dev/null
+++ b/Documentation/arm/sunxi/README
@@ -0,0 +1,19 @@
1ARM Allwinner SoCs
2==================
3
4This document lists all the ARM Allwinner SoCs that are currently
5supported in mainline by the Linux kernel. This document will also
6provide links to documentation and or datasheet for these SoCs.
7
8SunXi family
9------------
10
11 Flavors:
12 Allwinner A10 (sun4i)
13 Datasheet : http://dl.linux-sunxi.org/A10/A10%20Datasheet%20-%20v1.21%20%282012-04-06%29.pdf
14
15 Allwinner A13 (sun5i)
16 Datasheet : http://dl.linux-sunxi.org/A13/A13%20Datasheet%20-%20v1.12%20%282012-03-29%29.pdf
17
18 Core: Cortex A8
19 Linux kernel mach directory: arch/arm/mach-sunxi \ No newline at end of file
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt
new file mode 100644
index 000000000000..7f9fb85f5456
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt
@@ -0,0 +1,104 @@
1Allwinner Sunxi Interrupt Controller
2
3Required properties:
4
5- compatible : should be "allwinner,sunxi-ic"
6- reg : Specifies base physical address and size of the registers.
7- interrupt-controller : Identifies the node as an interrupt controller
8- #interrupt-cells : Specifies the number of cells needed to encode an
9 interrupt source. The value shall be 1.
10
11The interrupt sources are as follows:
12
130: ENMI
141: UART0
152: UART1
163: UART2
174: UART3
185: IR0
196: IR1
207: I2C0
218: I2C1
229: I2C2
2310: SPI0
2411: SPI1
2512: SPI2
2613: SPDIF
2714: AC97
2815: TS
2916: I2S
3017: UART4
3118: UART5
3219: UART6
3320: UART7
3421: KEYPAD
3522: TIMER0
3623: TIMER1
3724: TIMER2
3825: TIMER3
3926: CAN
4027: DMA
4128: PIO
4229: TOUCH_PANEL
4330: AUDIO_CODEC
4431: LRADC
4532: SDMC0
4633: SDMC1
4734: SDMC2
4835: SDMC3
4936: MEMSTICK
5037: NAND
5138: USB0
5239: USB1
5340: USB2
5441: SCR
5542: CSI0
5643: CSI1
5744: LCDCTRL0
5845: LCDCTRL1
5946: MP
6047: DEFEBE0
6148: DEFEBE1
6249: PMU
6350: SPI3
6451: TZASC
6552: PATA
6653: VE
6754: SS
6855: EMAC
6956: SATA
7057: GPS
7158: HDMI
7259: TVE
7360: ACE
7461: TVD
7562: PS2_0
7663: PS2_1
7764: USB3
7865: USB4
7966: PLE_PFM
8067: TIMER4
8168: TIMER5
8269: GPU_GP
8370: GPU_GPMMU
8471: GPU_PP0
8572: GPU_PPMMU0
8673: GPU_PMU
8774: GPU_RSV0
8875: GPU_RSV1
8976: GPU_RSV2
9077: GPU_RSV3
9178: GPU_RSV4
9279: GPU_RSV5
9380: GPU_RSV6
9482: SYNC_TIMER0
9583: SYNC_TIMER1
96
97Example:
98
99intc: interrupt-controller {
100 compatible = "allwinner,sunxi-ic";
101 reg = <0x01c20400 0x400>;
102 interrupt-controller;
103 #interrupt-cells = <2>;
104};
diff --git a/Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt b/Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt
new file mode 100644
index 000000000000..0c7b64e95a61
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt
@@ -0,0 +1,17 @@
1Allwinner A1X SoCs Timer Controller
2
3Required properties:
4
5- compatible : should be "allwinner,sunxi-timer"
6- reg : Specifies base physical address and size of the registers.
7- interrupts : The interrupt of the first timer
8- clocks: phandle to the source clock (usually a 24 MHz fixed clock)
9
10Example:
11
12timer {
13 compatible = "allwinner,sunxi-timer";
14 reg = <0x01c20c00 0x400>;
15 interrupts = <22>;
16 clocks = <&osc>;
17};
diff --git a/MAINTAINERS b/MAINTAINERS
index 99199e63f349..12bd27e452e5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -685,6 +685,12 @@ M: Lennert Buytenhek <kernel@wantstofly.org>
685L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 685L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
686S: Maintained 686S: Maintained
687 687
688ARM/Allwinner A1X SoC support
689M: Maxime Ripard <maxime.ripard@free-electrons.com>
690L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
691S: Maintained
692F: arch/arm/mach-sunxi/
693
688ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES 694ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
689M: Andrew Victor <linux@maxim.org.za> 695M: Andrew Victor <linux@maxim.org.za>
690M: Nicolas Ferre <nicolas.ferre@atmel.com> 696M: Nicolas Ferre <nicolas.ferre@atmel.com>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c1cc4f79e4fe..6c1d0198553d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1102,6 +1102,8 @@ source "arch/arm/mach-exynos/Kconfig"
1102 1102
1103source "arch/arm/mach-shmobile/Kconfig" 1103source "arch/arm/mach-shmobile/Kconfig"
1104 1104
1105source "arch/arm/mach-sunxi/Kconfig"
1106
1105source "arch/arm/mach-prima2/Kconfig" 1107source "arch/arm/mach-prima2/Kconfig"
1106 1108
1107source "arch/arm/mach-tegra/Kconfig" 1109source "arch/arm/mach-tegra/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 5566520686a5..4c336c3c4d7e 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -345,6 +345,13 @@ choice
345 Say Y here if you want kernel low-level debugging support 345 Say Y here if you want kernel low-level debugging support
346 on SOCFPGA based platforms. 346 on SOCFPGA based platforms.
347 347
348 config DEBUG_SUNXI_UART1
349 bool "Kernel low-level debugging messages via sunXi UART1"
350 depends on ARCH_SUNXI
351 help
352 Say Y here if you want kernel low-level debugging support
353 on Allwinner A1X based platforms on the UART1.
354
348 config DEBUG_VEXPRESS_UART0_DETECT 355 config DEBUG_VEXPRESS_UART0_DETECT
349 bool "Autodetect UART0 on Versatile Express Cortex-A core tiles" 356 bool "Autodetect UART0 on Versatile Express Cortex-A core tiles"
350 depends on ARCH_VEXPRESS && CPU_CP15_MMU 357 depends on ARCH_VEXPRESS && CPU_CP15_MMU
@@ -424,6 +431,7 @@ config DEBUG_LL_INCLUDE
424 default "debug/mvebu.S" if DEBUG_MVEBU_UART 431 default "debug/mvebu.S" if DEBUG_MVEBU_UART
425 default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART 432 default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
426 default "debug/socfpga.S" if DEBUG_SOCFPGA_UART 433 default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
434 default "debug/sunxi.S" if DEBUG_SUNXI_UART1
427 default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \ 435 default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \
428 DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1 436 DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1
429 default "mach/debug-macro.S" 437 default "mach/debug-macro.S"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 208912167823..58afa0dfcf7c 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -194,6 +194,7 @@ machine-$(CONFIG_ARCH_SPEAR13XX) += spear13xx
194machine-$(CONFIG_ARCH_SPEAR3XX) += spear3xx 194machine-$(CONFIG_ARCH_SPEAR3XX) += spear3xx
195machine-$(CONFIG_MACH_SPEAR600) += spear6xx 195machine-$(CONFIG_MACH_SPEAR600) += spear6xx
196machine-$(CONFIG_ARCH_ZYNQ) += zynq 196machine-$(CONFIG_ARCH_ZYNQ) += zynq
197machine-$(CONFIG_ARCH_SUNXI) += sunxi
197 198
198# Platform directory name. This list is sorted alphanumerically 199# Platform directory name. This list is sorted alphanumerically
199# by CONFIG_* macro name. 200# by CONFIG_* macro name.
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index cc803c92a72c..22e4ac9a4e7d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -86,6 +86,7 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
86 spear310-evb.dtb \ 86 spear310-evb.dtb \
87 spear320-evb.dtb 87 spear320-evb.dtb
88dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb 88dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
89dtb-$(CONFIG_ARCH_SUNXI) += sun5i-olinuxino.dtb
89dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ 90dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
90 tegra20-medcom-wide.dtb \ 91 tegra20-medcom-wide.dtb \
91 tegra20-paz00.dtb \ 92 tegra20-paz00.dtb \
diff --git a/arch/arm/boot/dts/sun5i-olinuxino.dts b/arch/arm/boot/dts/sun5i-olinuxino.dts
new file mode 100644
index 000000000000..3b1cce3af7cb
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-olinuxino.dts
@@ -0,0 +1,26 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * The code contained herein is licensed under the GNU General Public
7 * License. You may obtain a copy of the GNU General Public License
8 * Version 2 or later at the following locations:
9 *
10 * http://www.opensource.org/licenses/gpl-license.html
11 * http://www.gnu.org/copyleft/gpl.html
12 */
13
14/dts-v1/;
15/include/ "sun5i.dtsi"
16
17/ {
18 model = "Olimex A13-Olinuxino";
19 compatible = "olimex,a13-olinuxino", "allwinner,sun5i";
20
21 soc {
22 duart: uart@01c28400 {
23 status = "okay";
24 };
25 };
26};
diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
new file mode 100644
index 000000000000..4bedf3e826e8
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -0,0 +1,74 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * The code contained herein is licensed under the GNU General Public
7 * License. You may obtain a copy of the GNU General Public License
8 * Version 2 or later at the following locations:
9 *
10 * http://www.opensource.org/licenses/gpl-license.html
11 * http://www.gnu.org/copyleft/gpl.html
12 */
13
14/include/ "skeleton.dtsi"
15
16/ {
17 interrupt-parent = <&intc>;
18
19 cpus {
20 cpu@0 {
21 compatible = "arm,cortex-a8";
22 };
23 };
24
25 chosen {
26 bootargs = "earlyprintk console=ttyS0,115200";
27 };
28
29 memory {
30 reg = <0x40000000 0x20000000>;
31 };
32
33 clocks {
34 #address-cells = <1>;
35 #size-cells = <0>;
36
37 osc: oscillator {
38 #clock-cells = <0>;
39 compatible = "fixed-clock";
40 clock-frequency = <24000000>;
41 };
42 };
43
44 soc {
45 compatible = "simple-bus";
46 #address-cells = <1>;
47 #size-cells = <1>;
48 reg = <0x01c20000 0x300000>;
49 ranges;
50
51 timer@01c20c00 {
52 compatible = "allwinner,sunxi-timer";
53 reg = <0x01c20c00 0x400>;
54 interrupts = <22>;
55 clocks = <&osc>;
56 };
57
58 intc: interrupt-controller@01c20400 {
59 compatible = "allwinner,sunxi-ic";
60 reg = <0x01c20400 0x400>;
61 interrupt-controller;
62 #interrupt-cells = <1>;
63 };
64
65 uart1: uart@01c28400 {
66 compatible = "ns8250";
67 reg = <0x01c28400 0x400>;
68 interrupts = <2>;
69 reg-shift = <2>;
70 clock-frequency = <24000000>;
71 status = "disabled";
72 };
73 };
74};
diff --git a/arch/arm/include/debug/sunxi.S b/arch/arm/include/debug/sunxi.S
new file mode 100644
index 000000000000..3bf61ca0df75
--- /dev/null
+++ b/arch/arm/include/debug/sunxi.S
@@ -0,0 +1,24 @@
1/*
2 * Early serial output macro for Allwinner A1X SoCs
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifdef CONFIG_DEBUG_SUNXI_UART1
14#define SUNXI_UART_DEBUG_PHYS_BASE 0x01c28400
15#define SUNXI_UART_DEBUG_VIRT_BASE 0xf1c28400
16#endif
17
18 .macro addruart, rp, rv, tmp
19 ldr \rp, =SUNXI_UART_DEBUG_PHYS_BASE
20 ldr \rv, =SUNXI_UART_DEBUG_VIRT_BASE
21 .endm
22
23#define UART_SHIFT 2
24#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
new file mode 100644
index 000000000000..3fdd0085e306
--- /dev/null
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -0,0 +1,9 @@
1config ARCH_SUNXI
2 bool "Allwinner A1X SOCs" if ARCH_MULTI_V7
3 select CLKSRC_MMIO
4 select COMMON_CLK
5 select GENERIC_CLOCKEVENTS
6 select GENERIC_IRQ_CHIP
7 select PINCTRL
8 select SPARSE_IRQ
9 select SUNXI_TIMER
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
new file mode 100644
index 000000000000..93bebfc3ff9f
--- /dev/null
+++ b/arch/arm/mach-sunxi/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_ARCH_SUNXI) += sunxi.o
diff --git a/arch/arm/mach-sunxi/Makefile.boot b/arch/arm/mach-sunxi/Makefile.boot
new file mode 100644
index 000000000000..46d4cf0841c0
--- /dev/null
+++ b/arch/arm/mach-sunxi/Makefile.boot
@@ -0,0 +1 @@
zreladdr-$(CONFIG_ARCH_SUNXI) += 0x40008000
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
new file mode 100644
index 000000000000..8f42df8af1da
--- /dev/null
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -0,0 +1,60 @@
1/*
2 * Device Tree support for Allwinner A1X SoCs
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/of_irq.h>
16#include <linux/of_platform.h>
17#include <linux/io.h>
18#include <linux/sunxi_timer.h>
19
20#include <linux/irqchip/sunxi.h>
21
22#include <asm/hardware/vic.h>
23
24#include <asm/mach/arch.h>
25#include <asm/mach/map.h>
26
27#include "sunxi.h"
28
29static struct map_desc sunxi_io_desc[] __initdata = {
30 {
31 .virtual = (unsigned long) SUNXI_REGS_VIRT_BASE,
32 .pfn = __phys_to_pfn(SUNXI_REGS_PHYS_BASE),
33 .length = SUNXI_REGS_SIZE,
34 .type = MT_DEVICE,
35 },
36};
37
38void __init sunxi_map_io(void)
39{
40 iotable_init(sunxi_io_desc, ARRAY_SIZE(sunxi_io_desc));
41}
42
43static void __init sunxi_dt_init(void)
44{
45 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
46}
47
48static const char * const sunxi_board_dt_compat[] = {
49 "allwinner,sun5i",
50 NULL,
51};
52
53DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
54 .init_machine = sunxi_dt_init,
55 .map_io = sunxi_map_io,
56 .init_irq = sunxi_init_irq,
57 .handle_irq = sunxi_handle_irq,
58 .timer = &sunxi_timer,
59 .dt_compat = sunxi_board_dt_compat,
60MACHINE_END
diff --git a/arch/arm/mach-sunxi/sunxi.h b/arch/arm/mach-sunxi/sunxi.h
new file mode 100644
index 000000000000..33b58712adea
--- /dev/null
+++ b/arch/arm/mach-sunxi/sunxi.h
@@ -0,0 +1,20 @@
1/*
2 * Generic definitions for Allwinner SunXi SoCs
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#ifndef __MACH_SUNXI_H
14#define __MACH_SUNXI_H
15
16#define SUNXI_REGS_PHYS_BASE 0x01c00000
17#define SUNXI_REGS_VIRT_BASE IOMEM(0xf1c00000)
18#define SUNXI_REGS_SIZE (SZ_2M + SZ_1M)
19
20#endif /* __MACH_SUNXI_H */
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 71a25b91de00..9c300a828ede 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -19,6 +19,7 @@ endif
19obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o 19obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
20obj-$(CONFIG_ARCH_U8500) += ux500/ 20obj-$(CONFIG_ARCH_U8500) += ux500/
21obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o 21obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
22obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o
22 23
23# Chip specific 24# Chip specific
24obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o 25obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
diff --git a/drivers/clk/clk-sunxi.c b/drivers/clk/clk-sunxi.c
new file mode 100644
index 000000000000..0e831b584ba7
--- /dev/null
+++ b/drivers/clk/clk-sunxi.c
@@ -0,0 +1,30 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/clk-provider.h>
18#include <linux/clkdev.h>
19#include <linux/clk/sunxi.h>
20#include <linux/of.h>
21
22static const __initconst struct of_device_id clk_match[] = {
23 { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
24 {}
25};
26
27void __init sunxi_init_clocks(void)
28{
29 of_clk_init(clk_match);
30}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 6a78073c3808..a0985732f1e2 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -22,6 +22,9 @@ config DW_APB_TIMER_OF
22config ARMADA_370_XP_TIMER 22config ARMADA_370_XP_TIMER
23 bool 23 bool
24 24
25config SUNXI_TIMER
26 bool
27
25config CLKSRC_DBX500_PRCMU 28config CLKSRC_DBX500_PRCMU
26 bool "Clocksource PRCMU Timer" 29 bool "Clocksource PRCMU Timer"
27 depends on UX500_SOC_DB8500 30 depends on UX500_SOC_DB8500
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 603be366f762..36f06de4c5ab 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
14obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o 14obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
15obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o 15obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
16obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o 16obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
17obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
17 18
18obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o 19obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c
new file mode 100644
index 000000000000..3c46434b64cb
--- /dev/null
+++ b/drivers/clocksource/sunxi_timer.c
@@ -0,0 +1,170 @@
1/*
2 * Allwinner A1X SoCs timer handling.
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * Based on code from
9 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
10 * Benn Huang <benn@allwinnertech.com>
11 *
12 * This file is licensed under the terms of the GNU General Public
13 * License version 2. This program is licensed "as is" without any
14 * warranty of any kind, whether express or implied.
15 */
16
17#include <linux/clk.h>
18#include <linux/clockchips.h>
19#include <linux/interrupt.h>
20#include <linux/irq.h>
21#include <linux/irqreturn.h>
22#include <linux/of.h>
23#include <linux/of_address.h>
24#include <linux/of_irq.h>
25#include <linux/sunxi_timer.h>
26#include <linux/clk/sunxi.h>
27
28#define TIMER_CTL_REG 0x00
29#define TIMER_CTL_ENABLE (1 << 0)
30#define TIMER_IRQ_ST_REG 0x04
31#define TIMER0_CTL_REG 0x10
32#define TIMER0_CTL_ENABLE (1 << 0)
33#define TIMER0_CTL_AUTORELOAD (1 << 1)
34#define TIMER0_CTL_ONESHOT (1 << 7)
35#define TIMER0_INTVAL_REG 0x14
36#define TIMER0_CNTVAL_REG 0x18
37
38#define TIMER_SCAL 16
39
40static void __iomem *timer_base;
41
42static void sunxi_clkevt_mode(enum clock_event_mode mode,
43 struct clock_event_device *clk)
44{
45 u32 u = readl(timer_base + TIMER0_CTL_REG);
46
47 switch (mode) {
48 case CLOCK_EVT_MODE_PERIODIC:
49 u &= ~(TIMER0_CTL_ONESHOT);
50 writel(u | TIMER0_CTL_ENABLE, timer_base + TIMER0_CTL_REG);
51 break;
52
53 case CLOCK_EVT_MODE_ONESHOT:
54 writel(u | TIMER0_CTL_ONESHOT, timer_base + TIMER0_CTL_REG);
55 break;
56 case CLOCK_EVT_MODE_UNUSED:
57 case CLOCK_EVT_MODE_SHUTDOWN:
58 default:
59 writel(u & ~(TIMER0_CTL_ENABLE), timer_base + TIMER0_CTL_REG);
60 break;
61 }
62}
63
64static int sunxi_clkevt_next_event(unsigned long evt,
65 struct clock_event_device *unused)
66{
67 u32 u = readl(timer_base + TIMER0_CTL_REG);
68 writel(evt, timer_base + TIMER0_CNTVAL_REG);
69 writel(u | TIMER0_CTL_ENABLE | TIMER0_CTL_AUTORELOAD,
70 timer_base + TIMER0_CTL_REG);
71
72 return 0;
73}
74
75static struct clock_event_device sunxi_clockevent = {
76 .name = "sunxi_tick",
77 .shift = 32,
78 .rating = 300,
79 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
80 .set_mode = sunxi_clkevt_mode,
81 .set_next_event = sunxi_clkevt_next_event,
82};
83
84
85static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id)
86{
87 struct clock_event_device *evt = (struct clock_event_device *)dev_id;
88
89 writel(0x1, timer_base + TIMER_IRQ_ST_REG);
90 evt->event_handler(evt);
91
92 return IRQ_HANDLED;
93}
94
95static struct irqaction sunxi_timer_irq = {
96 .name = "sunxi_timer0",
97 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
98 .handler = sunxi_timer_interrupt,
99 .dev_id = &sunxi_clockevent,
100};
101
102static struct of_device_id sunxi_timer_dt_ids[] = {
103 { .compatible = "allwinner,sunxi-timer" },
104};
105
106static void __init sunxi_timer_init(void)
107{
108 struct device_node *node;
109 unsigned long rate = 0;
110 struct clk *clk;
111 int ret, irq;
112 u32 val;
113
114 node = of_find_matching_node(NULL, sunxi_timer_dt_ids);
115 if (!node)
116 panic("No sunxi timer node");
117
118 timer_base = of_iomap(node, 0);
119 if (!timer_base)
120 panic("Can't map registers");
121
122 irq = irq_of_parse_and_map(node, 0);
123 if (irq <= 0)
124 panic("Can't parse IRQ");
125
126 sunxi_init_clocks();
127
128 clk = of_clk_get(node, 0);
129 if (IS_ERR(clk))
130 panic("Can't get timer clock");
131
132 rate = clk_get_rate(clk);
133
134 writel(rate / (TIMER_SCAL * HZ),
135 timer_base + TIMER0_INTVAL_REG);
136
137 /* set clock source to HOSC, 16 pre-division */
138 val = readl(timer_base + TIMER0_CTL_REG);
139 val &= ~(0x07 << 4);
140 val &= ~(0x03 << 2);
141 val |= (4 << 4) | (1 << 2);
142 writel(val, timer_base + TIMER0_CTL_REG);
143
144 /* set mode to auto reload */
145 val = readl(timer_base + TIMER0_CTL_REG);
146 writel(val | TIMER0_CTL_AUTORELOAD, timer_base + TIMER0_CTL_REG);
147
148 ret = setup_irq(irq, &sunxi_timer_irq);
149 if (ret)
150 pr_warn("failed to setup irq %d\n", irq);
151
152 /* Enable timer0 interrupt */
153 val = readl(timer_base + TIMER_CTL_REG);
154 writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG);
155
156 sunxi_clockevent.mult = div_sc(rate / TIMER_SCAL,
157 NSEC_PER_SEC,
158 sunxi_clockevent.shift);
159 sunxi_clockevent.max_delta_ns = clockevent_delta2ns(0xff,
160 &sunxi_clockevent);
161 sunxi_clockevent.min_delta_ns = clockevent_delta2ns(0x1,
162 &sunxi_clockevent);
163 sunxi_clockevent.cpumask = cpumask_of(0);
164
165 clockevents_register_device(&sunxi_clockevent);
166}
167
168struct sys_timer sunxi_timer = {
169 .init = sunxi_timer_init,
170};
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e2e6eb5d32f4..02bd37a6187f 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o 1obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
2obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o
2obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o 3obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
diff --git a/drivers/irqchip/irq-sunxi.c b/drivers/irqchip/irq-sunxi.c
new file mode 100644
index 000000000000..eef41a49acae
--- /dev/null
+++ b/drivers/irqchip/irq-sunxi.c
@@ -0,0 +1,150 @@
1/*
2 * Allwinner A1X SoCs IRQ chip driver.
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * Based on code from
9 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
10 * Benn Huang <benn@allwinnertech.com>
11 *
12 * This file is licensed under the terms of the GNU General Public
13 * License version 2. This program is licensed "as is" without any
14 * warranty of any kind, whether express or implied.
15 */
16
17#include <linux/io.h>
18#include <linux/irq.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include <linux/of_irq.h>
22
23#include <linux/irqchip/sunxi.h>
24
25#define SUNXI_IRQ_VECTOR_REG 0x00
26#define SUNXI_IRQ_PROTECTION_REG 0x08
27#define SUNXI_IRQ_NMI_CTRL_REG 0x0c
28#define SUNXI_IRQ_PENDING_REG(x) (0x10 + 0x4 * x)
29#define SUNXI_IRQ_FIQ_PENDING_REG(x) (0x20 + 0x4 * x)
30#define SUNXI_IRQ_ENABLE_REG(x) (0x40 + 0x4 * x)
31#define SUNXI_IRQ_MASK_REG(x) (0x50 + 0x4 * x)
32
33static void __iomem *sunxi_irq_base;
34static struct irq_domain *sunxi_irq_domain;
35
36void sunxi_irq_ack(struct irq_data *irqd)
37{
38 unsigned int irq = irqd_to_hwirq(irqd);
39 unsigned int irq_off = irq % 32;
40 int reg = irq / 32;
41 u32 val;
42
43 val = readl(sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
44 writel(val | (1 << irq_off),
45 sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
46}
47
48static void sunxi_irq_mask(struct irq_data *irqd)
49{
50 unsigned int irq = irqd_to_hwirq(irqd);
51 unsigned int irq_off = irq % 32;
52 int reg = irq / 32;
53 u32 val;
54
55 val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
56 writel(val & ~(1 << irq_off),
57 sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
58}
59
60static void sunxi_irq_unmask(struct irq_data *irqd)
61{
62 unsigned int irq = irqd_to_hwirq(irqd);
63 unsigned int irq_off = irq % 32;
64 int reg = irq / 32;
65 u32 val;
66
67 val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
68 writel(val | (1 << irq_off),
69 sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
70}
71
72static struct irq_chip sunxi_irq_chip = {
73 .name = "sunxi_irq",
74 .irq_ack = sunxi_irq_ack,
75 .irq_mask = sunxi_irq_mask,
76 .irq_unmask = sunxi_irq_unmask,
77};
78
79static int sunxi_irq_map(struct irq_domain *d, unsigned int virq,
80 irq_hw_number_t hw)
81{
82 irq_set_chip_and_handler(virq, &sunxi_irq_chip,
83 handle_level_irq);
84 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
85
86 return 0;
87}
88
89static struct irq_domain_ops sunxi_irq_ops = {
90 .map = sunxi_irq_map,
91 .xlate = irq_domain_xlate_onecell,
92};
93
94static int __init sunxi_of_init(struct device_node *node,
95 struct device_node *parent)
96{
97 sunxi_irq_base = of_iomap(node, 0);
98 if (!sunxi_irq_base)
99 panic("%s: unable to map IC registers\n",
100 node->full_name);
101
102 /* Disable all interrupts */
103 writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(0));
104 writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(1));
105 writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(2));
106
107 /* Mask all the interrupts */
108 writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(0));
109 writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(1));
110 writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(2));
111
112 /* Clear all the pending interrupts */
113 writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(0));
114 writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(1));
115 writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(2));
116
117 /* Enable protection mode */
118 writel(0x01, sunxi_irq_base + SUNXI_IRQ_PROTECTION_REG);
119
120 /* Configure the external interrupt source type */
121 writel(0x00, sunxi_irq_base + SUNXI_IRQ_NMI_CTRL_REG);
122
123 sunxi_irq_domain = irq_domain_add_linear(node, 3 * 32,
124 &sunxi_irq_ops, NULL);
125 if (!sunxi_irq_domain)
126 panic("%s: unable to create IRQ domain\n", node->full_name);
127
128 return 0;
129}
130
131static struct of_device_id sunxi_irq_dt_ids[] __initconst = {
132 { .compatible = "allwinner,sunxi-ic", .data = sunxi_of_init }
133};
134
135void __init sunxi_init_irq(void)
136{
137 of_irq_init(sunxi_irq_dt_ids);
138}
139
140asmlinkage void __exception_irq_entry sunxi_handle_irq(struct pt_regs *regs)
141{
142 u32 irq, hwirq;
143
144 hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
145 while (hwirq != 0) {
146 irq = irq_find_mapping(sunxi_irq_domain, hwirq);
147 handle_IRQ(irq, regs);
148 hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
149 }
150}
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
new file mode 100644
index 000000000000..e074fdd5a236
--- /dev/null
+++ b/include/linux/clk/sunxi.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifndef __LINUX_CLK_SUNXI_H_
18#define __LINUX_CLK_SUNXI_H_
19
20void __init sunxi_init_clocks(void);
21
22#endif
diff --git a/include/linux/irqchip/sunxi.h b/include/linux/irqchip/sunxi.h
new file mode 100644
index 000000000000..1fe2c2260e2b
--- /dev/null
+++ b/include/linux/irqchip/sunxi.h
@@ -0,0 +1,27 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifndef __LINUX_IRQCHIP_SUNXI_H
18#define __LINUX_IRQCHIP_SUNXI_H
19
20#include <asm/exception.h>
21
22extern void sunxi_init_irq(void);
23
24extern asmlinkage void __exception_irq_entry sunxi_handle_irq(
25 struct pt_regs *regs);
26
27#endif
diff --git a/include/linux/sunxi_timer.h b/include/linux/sunxi_timer.h
new file mode 100644
index 000000000000..b9165bba6e61
--- /dev/null
+++ b/include/linux/sunxi_timer.h
@@ -0,0 +1,24 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifndef __SUNXI_TIMER_H
18#define __SUNXI_TIMER_H
19
20#include <asm/mach/time.h>
21
22extern struct sys_timer sunxi_timer;
23
24#endif