aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/zynq-7000.txt55
-rw-r--r--arch/arm/Kconfig14
-rw-r--r--arch/arm/Kconfig.debug18
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/boot/dts/Makefile1
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi166
-rw-r--r--arch/arm/boot/dts/zynq-ep107.dts52
-rw-r--r--arch/arm/boot/dts/zynq-zc702.dts44
-rw-r--r--arch/arm/include/debug/zynq.S (renamed from arch/arm/mach-zynq/include/mach/debug-macro.S)23
-rw-r--r--arch/arm/mach-zynq/Kconfig13
-rw-r--r--arch/arm/mach-zynq/common.c80
-rw-r--r--arch/arm/mach-zynq/common.h4
-rw-r--r--arch/arm/mach-zynq/include/mach/clkdev.h32
-rw-r--r--arch/arm/mach-zynq/include/mach/hardware.h18
-rw-r--r--arch/arm/mach-zynq/include/mach/irqs.h21
-rw-r--r--arch/arm/mach-zynq/include/mach/timex.h23
-rw-r--r--arch/arm/mach-zynq/include/mach/uart.h25
-rw-r--r--arch/arm/mach-zynq/include/mach/uncompress.h51
-rw-r--r--arch/arm/mach-zynq/include/mach/zynq_soc.h48
-rw-r--r--arch/arm/mach-zynq/timer.c298
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-zynq.c383
-rw-r--r--include/linux/clk/zynq.h24
23 files changed, 936 insertions, 459 deletions
diff --git a/Documentation/devicetree/bindings/clock/zynq-7000.txt b/Documentation/devicetree/bindings/clock/zynq-7000.txt
new file mode 100644
index 000000000000..23ae1db1bc13
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/zynq-7000.txt
@@ -0,0 +1,55 @@
1Device Tree Clock bindings for the Zynq 7000 EPP
2
3The Zynq EPP has several different clk providers, each with there own bindings.
4The purpose of this document is to document their usage.
5
6See clock_bindings.txt for more information on the generic clock bindings.
7See Chapter 25 of Zynq TRM for more information about Zynq clocks.
8
9== PLLs ==
10
11Used to describe the ARM_PLL, DDR_PLL, and IO_PLL.
12
13Required properties:
14- #clock-cells : shall be 0 (only one clock is output from this node)
15- compatible : "xlnx,zynq-pll"
16- reg : pair of u32 values, which are the address offsets within the SLCR
17 of the relevant PLL_CTRL register and PLL_CFG register respectively
18- clocks : phandle for parent clock. should be the phandle for ps_clk
19
20Optional properties:
21- clock-output-names : name of the output clock
22
23Example:
24 armpll: armpll {
25 #clock-cells = <0>;
26 compatible = "xlnx,zynq-pll";
27 clocks = <&ps_clk>;
28 reg = <0x100 0x110>;
29 clock-output-names = "armpll";
30 };
31
32== Peripheral clocks ==
33
34Describes clock node for the SDIO, SMC, SPI, QSPI, and UART clocks.
35
36Required properties:
37- #clock-cells : shall be 1
38- compatible : "xlnx,zynq-periph-clock"
39- reg : a single u32 value, describing the offset within the SLCR where
40 the CLK_CTRL register is found for this peripheral
41- clocks : phandle for parent clocks. should hold phandles for
42 the IO_PLL, ARM_PLL, and DDR_PLL in order
43- clock-output-names : names of the output clock(s). For peripherals that have
44 two output clocks (for example, the UART), two clocks
45 should be listed.
46
47Example:
48 uart_clk: uart_clk {
49 #clock-cells = <1>;
50 compatible = "xlnx,zynq-periph-clock";
51 clocks = <&iopll &armpll &ddrpll>;
52 reg = <0x154>;
53 clock-output-names = "uart0_ref_clk",
54 "uart1_ref_clk";
55 };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9277f503481c..d244249178b6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -960,18 +960,6 @@ config ARCH_VT8500_SINGLE
960 help 960 help
961 Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. 961 Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip.
962 962
963config ARCH_ZYNQ
964 bool "Xilinx Zynq ARM Cortex A9 Platform"
965 select ARM_AMBA
966 select ARM_GIC
967 select CLKDEV_LOOKUP
968 select CPU_V7
969 select GENERIC_CLOCKEVENTS
970 select ICST
971 select MIGHT_HAVE_CACHE_L2X0
972 select USE_OF
973 help
974 Support for Xilinx Zynq ARM Cortex A9 Platform
975endchoice 963endchoice
976 964
977menu "Multiple platform selection" 965menu "Multiple platform selection"
@@ -1134,6 +1122,8 @@ source "arch/arm/mach-vt8500/Kconfig"
1134 1122
1135source "arch/arm/mach-w90x900/Kconfig" 1123source "arch/arm/mach-w90x900/Kconfig"
1136 1124
1125source "arch/arm/mach-zynq/Kconfig"
1126
1137# Definitions to make life easier 1127# Definitions to make life easier
1138config ARCH_ACORN 1128config ARCH_ACORN
1139 bool 1129 bool
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 96b9425219d9..be70fe56bbeb 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -132,6 +132,23 @@ choice
132 their output to UART1 serial port on DaVinci TNETV107X 132 their output to UART1 serial port on DaVinci TNETV107X
133 devices. 133 devices.
134 134
135 config DEBUG_ZYNQ_UART0
136 bool "Kernel low-level debugging on Xilinx Zynq using UART0"
137 depends on ARCH_ZYNQ
138 help
139 Say Y here if you want the debug print routines to direct
140 their output to UART0 on the Zynq platform.
141
142 config DEBUG_ZYNQ_UART1
143 bool "Kernel low-level debugging on Xilinx Zynq using UART1"
144 depends on ARCH_ZYNQ
145 help
146 Say Y here if you want the debug print routines to direct
147 their output to UART1 on the Zynq platform.
148
149 If you have a ZC702 board and want early boot messages to
150 appear on the USB serial adaptor, select this option.
151
135 config DEBUG_DC21285_PORT 152 config DEBUG_DC21285_PORT
136 bool "Kernel low-level debugging messages via footbridge serial port" 153 bool "Kernel low-level debugging messages via footbridge serial port"
137 depends on FOOTBRIDGE 154 depends on FOOTBRIDGE
@@ -456,6 +473,7 @@ config DEBUG_LL_INCLUDE
456 default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \ 473 default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \
457 DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1 474 DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1
458 default "debug/tegra.S" if DEBUG_TEGRA_UART 475 default "debug/tegra.S" if DEBUG_TEGRA_UART
476 default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
459 default "mach/debug-macro.S" 477 default "mach/debug-macro.S"
460 478
461config EARLY_PRINTK 479config EARLY_PRINTK
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 89087d599ad2..aa90b6670794 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -199,7 +199,6 @@ machine-$(CONFIG_ARCH_ZYNQ) += zynq
199plat-$(CONFIG_ARCH_MXC) += mxc 199plat-$(CONFIG_ARCH_MXC) += mxc
200plat-$(CONFIG_ARCH_OMAP) += omap 200plat-$(CONFIG_ARCH_OMAP) += omap
201plat-$(CONFIG_ARCH_S3C64XX) += samsung 201plat-$(CONFIG_ARCH_S3C64XX) += samsung
202plat-$(CONFIG_ARCH_ZYNQ) += versatile
203plat-$(CONFIG_PLAT_IOP) += iop 202plat-$(CONFIG_PLAT_IOP) += iop
204plat-$(CONFIG_PLAT_ORION) += orion 203plat-$(CONFIG_PLAT_ORION) += orion
205plat-$(CONFIG_PLAT_PXA) += pxa 204plat-$(CONFIG_PLAT_PXA) += pxa
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index f37cf9fa5fa0..76ed11e68f72 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -103,5 +103,6 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
103dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ 103dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \
104 wm8505-ref.dtb \ 104 wm8505-ref.dtb \
105 wm8650-mid.dtb 105 wm8650-mid.dtb
106dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb
106 107
107endif 108endif
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
new file mode 100644
index 000000000000..401c1262d4ed
--- /dev/null
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -0,0 +1,166 @@
1/*
2 * Copyright (C) 2011 Xilinx
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13/include/ "skeleton.dtsi"
14
15/ {
16 compatible = "xlnx,zynq-7000";
17
18 amba {
19 compatible = "simple-bus";
20 #address-cells = <1>;
21 #size-cells = <1>;
22 interrupt-parent = <&intc>;
23 ranges;
24
25 intc: interrupt-controller@f8f01000 {
26 compatible = "arm,cortex-a9-gic";
27 #interrupt-cells = <3>;
28 #address-cells = <1>;
29 interrupt-controller;
30 reg = <0xF8F01000 0x1000>,
31 <0xF8F00100 0x100>;
32 };
33
34 L2: cache-controller {
35 compatible = "arm,pl310-cache";
36 reg = <0xF8F02000 0x1000>;
37 arm,data-latency = <2 3 2>;
38 arm,tag-latency = <2 3 2>;
39 cache-unified;
40 cache-level = <2>;
41 };
42
43 uart0: uart@e0000000 {
44 compatible = "xlnx,xuartps";
45 reg = <0xE0000000 0x1000>;
46 interrupts = <0 27 4>;
47 clock = <50000000>;
48 };
49
50 uart1: uart@e0001000 {
51 compatible = "xlnx,xuartps";
52 reg = <0xE0001000 0x1000>;
53 interrupts = <0 50 4>;
54 clock = <50000000>;
55 };
56
57 slcr: slcr@f8000000 {
58 compatible = "xlnx,zynq-slcr";
59 reg = <0xF8000000 0x1000>;
60
61 clocks {
62 #address-cells = <1>;
63 #size-cells = <0>;
64
65 ps_clk: ps_clk {
66 #clock-cells = <0>;
67 compatible = "fixed-clock";
68 /* clock-frequency set in board-specific file */
69 clock-output-names = "ps_clk";
70 };
71 armpll: armpll {
72 #clock-cells = <0>;
73 compatible = "xlnx,zynq-pll";
74 clocks = <&ps_clk>;
75 reg = <0x100 0x110>;
76 clock-output-names = "armpll";
77 };
78 ddrpll: ddrpll {
79 #clock-cells = <0>;
80 compatible = "xlnx,zynq-pll";
81 clocks = <&ps_clk>;
82 reg = <0x104 0x114>;
83 clock-output-names = "ddrpll";
84 };
85 iopll: iopll {
86 #clock-cells = <0>;
87 compatible = "xlnx,zynq-pll";
88 clocks = <&ps_clk>;
89 reg = <0x108 0x118>;
90 clock-output-names = "iopll";
91 };
92 uart_clk: uart_clk {
93 #clock-cells = <1>;
94 compatible = "xlnx,zynq-periph-clock";
95 clocks = <&iopll &armpll &ddrpll>;
96 reg = <0x154>;
97 clock-output-names = "uart0_ref_clk",
98 "uart1_ref_clk";
99 };
100 cpu_clk: cpu_clk {
101 #clock-cells = <1>;
102 compatible = "xlnx,zynq-cpu-clock";
103 clocks = <&iopll &armpll &ddrpll>;
104 reg = <0x120 0x1C4>;
105 clock-output-names = "cpu_6x4x",
106 "cpu_3x2x",
107 "cpu_2x",
108 "cpu_1x";
109 };
110 };
111 };
112
113 ttc0: ttc0@f8001000 {
114 #address-cells = <1>;
115 #size-cells = <0>;
116 compatible = "xlnx,ttc";
117 reg = <0xF8001000 0x1000>;
118 clocks = <&cpu_clk 3>;
119 clock-names = "cpu_1x";
120 clock-ranges;
121
122 ttc0_0: ttc0.0 {
123 status = "disabled";
124 reg = <0>;
125 interrupts = <0 10 4>;
126 };
127 ttc0_1: ttc0.1 {
128 status = "disabled";
129 reg = <1>;
130 interrupts = <0 11 4>;
131 };
132 ttc0_2: ttc0.2 {
133 status = "disabled";
134 reg = <2>;
135 interrupts = <0 12 4>;
136 };
137 };
138
139 ttc1: ttc1@f8002000 {
140 #interrupt-parent = <&intc>;
141 #address-cells = <1>;
142 #size-cells = <0>;
143 compatible = "xlnx,ttc";
144 reg = <0xF8002000 0x1000>;
145 clocks = <&cpu_clk 3>;
146 clock-names = "cpu_1x";
147 clock-ranges;
148
149 ttc1_0: ttc1.0 {
150 status = "disabled";
151 reg = <0>;
152 interrupts = <0 37 4>;
153 };
154 ttc1_1: ttc1.1 {
155 status = "disabled";
156 reg = <1>;
157 interrupts = <0 38 4>;
158 };
159 ttc1_2: ttc1.2 {
160 status = "disabled";
161 reg = <2>;
162 interrupts = <0 39 4>;
163 };
164 };
165 };
166};
diff --git a/arch/arm/boot/dts/zynq-ep107.dts b/arch/arm/boot/dts/zynq-ep107.dts
deleted file mode 100644
index 37ca192fb193..000000000000
--- a/arch/arm/boot/dts/zynq-ep107.dts
+++ /dev/null
@@ -1,52 +0,0 @@
1/*
2 * Copyright (C) 2011 Xilinx
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14/dts-v1/;
15/ {
16 model = "Xilinx Zynq EP107";
17 compatible = "xlnx,zynq-ep107";
18 #address-cells = <1>;
19 #size-cells = <1>;
20 interrupt-parent = <&intc>;
21
22 memory {
23 device_type = "memory";
24 reg = <0x0 0x10000000>;
25 };
26
27 chosen {
28 bootargs = "console=ttyPS0,9600 root=/dev/ram rw initrd=0x800000,8M earlyprintk";
29 linux,stdout-path = &uart0;
30 };
31
32 amba {
33 compatible = "simple-bus";
34 #address-cells = <1>;
35 #size-cells = <1>;
36 ranges;
37
38 intc: interrupt-controller@f8f01000 {
39 interrupt-controller;
40 compatible = "arm,gic";
41 reg = <0xF8F01000 0x1000>;
42 #interrupt-cells = <2>;
43 };
44
45 uart0: uart@e0000000 {
46 compatible = "xlnx,xuartps";
47 reg = <0xE0000000 0x1000>;
48 interrupts = <59 0>;
49 clock = <50000000>;
50 };
51 };
52};
diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts
new file mode 100644
index 000000000000..c772942a399a
--- /dev/null
+++ b/arch/arm/boot/dts/zynq-zc702.dts
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2011 Xilinx
3 * Copyright (C) 2012 National Instruments Corp.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14/dts-v1/;
15/include/ "zynq-7000.dtsi"
16
17/ {
18 model = "Zynq ZC702 Development Board";
19 compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";
20
21 memory {
22 device_type = "memory";
23 reg = <0x0 0x40000000>;
24 };
25
26 chosen {
27 bootargs = "console=ttyPS1,115200 earlyprintk";
28 };
29
30};
31
32&ps_clk {
33 clock-frequency = <33333330>;
34};
35
36&ttc0_0 {
37 status = "ok";
38 compatible = "xlnx,ttc-counter-clocksource";
39};
40
41&ttc0_1 {
42 status = "ok";
43 compatible = "xlnx,ttc-counter-clockevent";
44};
diff --git a/arch/arm/mach-zynq/include/mach/debug-macro.S b/arch/arm/include/debug/zynq.S
index 3ab0be1f6191..f9aa9740a73f 100644
--- a/arch/arm/mach-zynq/include/mach/debug-macro.S
+++ b/arch/arm/include/debug/zynq.S
@@ -1,5 +1,4 @@
1/* arch/arm/mach-zynq/include/mach/debug-macro.S 1/*
2 *
3 * Debugging macro include header 2 * Debugging macro include header
4 * 3 *
5 * Copyright (C) 2011 Xilinx 4 * Copyright (C) 2011 Xilinx
@@ -13,9 +12,25 @@
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details. 13 * GNU General Public License for more details.
15 */ 14 */
15#define UART_CR_OFFSET 0x00 /* Control Register [8:0] */
16#define UART_SR_OFFSET 0x2C /* Channel Status [11:0] */
17#define UART_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */
18
19#define UART_SR_TXFULL 0x00000010 /* TX FIFO full */
20#define UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
21
22#define UART0_PHYS 0xE0000000
23#define UART1_PHYS 0xE0001000
24#define UART_SIZE SZ_4K
25#define UART_VIRT 0xF0001000
26
27#if IS_ENABLED(CONFIG_DEBUG_ZYNQ_UART1)
28# define LL_UART_PADDR UART1_PHYS
29#else
30# define LL_UART_PADDR UART0_PHYS
31#endif
16 32
17#include <mach/zynq_soc.h> 33#define LL_UART_VADDR UART_VIRT
18#include <mach/uart.h>
19 34
20 .macro addruart, rp, rv, tmp 35 .macro addruart, rp, rv, tmp
21 ldr \rp, =LL_UART_PADDR @ physical 36 ldr \rp, =LL_UART_PADDR @ physical
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
new file mode 100644
index 000000000000..adb6c0ea0e53
--- /dev/null
+++ b/arch/arm/mach-zynq/Kconfig
@@ -0,0 +1,13 @@
1config ARCH_ZYNQ
2 bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7
3 select ARM_AMBA
4 select ARM_GIC
5 select COMMON_CLK
6 select CPU_V7
7 select GENERIC_CLOCKEVENTS
8 select ICST
9 select MIGHT_HAVE_CACHE_L2X0
10 select USE_OF
11 select SPARSE_IRQ
12 help
13 Support for Xilinx Zynq ARM Cortex A9 Platform
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index ab5cfddc0d7b..e16d4bed0f7a 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -19,19 +19,21 @@
19#include <linux/cpumask.h> 19#include <linux/cpumask.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/clk.h> 21#include <linux/clk.h>
22#include <linux/clk/zynq.h>
23#include <linux/of_address.h>
22#include <linux/of_irq.h> 24#include <linux/of_irq.h>
23#include <linux/of_platform.h> 25#include <linux/of_platform.h>
24#include <linux/of.h> 26#include <linux/of.h>
25 27
26#include <asm/mach/arch.h> 28#include <asm/mach/arch.h>
27#include <asm/mach/map.h> 29#include <asm/mach/map.h>
30#include <asm/mach/time.h>
28#include <asm/mach-types.h> 31#include <asm/mach-types.h>
29#include <asm/page.h> 32#include <asm/page.h>
33#include <asm/pgtable.h>
30#include <asm/hardware/gic.h> 34#include <asm/hardware/gic.h>
31#include <asm/hardware/cache-l2x0.h> 35#include <asm/hardware/cache-l2x0.h>
32 36
33#include <mach/zynq_soc.h>
34#include <mach/clkdev.h>
35#include "common.h" 37#include "common.h"
36 38
37static struct of_device_id zynq_of_bus_ids[] __initdata = { 39static struct of_device_id zynq_of_bus_ids[] __initdata = {
@@ -45,55 +47,57 @@ static struct of_device_id zynq_of_bus_ids[] __initdata = {
45 */ 47 */
46static void __init xilinx_init_machine(void) 48static void __init xilinx_init_machine(void)
47{ 49{
48#ifdef CONFIG_CACHE_L2X0
49 /* 50 /*
50 * 64KB way size, 8-way associativity, parity disabled 51 * 64KB way size, 8-way associativity, parity disabled
51 */ 52 */
52 l2x0_init(PL310_L2CC_BASE, 0x02060000, 0xF0F0FFFF); 53 l2x0_of_init(0x02060000, 0xF0F0FFFF);
53#endif
54 54
55 of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); 55 of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL);
56} 56}
57 57
58static struct of_device_id irq_match[] __initdata = {
59 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
60 { }
61};
62
58/** 63/**
59 * xilinx_irq_init() - Interrupt controller initialization for the GIC. 64 * xilinx_irq_init() - Interrupt controller initialization for the GIC.
60 */ 65 */
61static void __init xilinx_irq_init(void) 66static void __init xilinx_irq_init(void)
62{ 67{
63 gic_init(0, 29, SCU_GIC_DIST_BASE, SCU_GIC_CPU_BASE); 68 of_irq_init(irq_match);
64} 69}
65 70
66/* The minimum devices needed to be mapped before the VM system is up and 71#define SCU_PERIPH_PHYS 0xF8F00000
67 * running include the GIC, UART and Timer Counter. 72#define SCU_PERIPH_SIZE SZ_8K
68 */ 73#define SCU_PERIPH_VIRT (VMALLOC_END - SCU_PERIPH_SIZE)
74
75static struct map_desc scu_desc __initdata = {
76 .virtual = SCU_PERIPH_VIRT,
77 .pfn = __phys_to_pfn(SCU_PERIPH_PHYS),
78 .length = SCU_PERIPH_SIZE,
79 .type = MT_DEVICE,
80};
81
82static void __init xilinx_zynq_timer_init(void)
83{
84 struct device_node *np;
85 void __iomem *slcr;
86
87 np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr");
88 slcr = of_iomap(np, 0);
89 WARN_ON(!slcr);
90
91 xilinx_zynq_clocks_init(slcr);
69 92
70static struct map_desc io_desc[] __initdata = { 93 xttcpss_timer_init();
71 { 94}
72 .virtual = TTC0_VIRT,
73 .pfn = __phys_to_pfn(TTC0_PHYS),
74 .length = SZ_4K,
75 .type = MT_DEVICE,
76 }, {
77 .virtual = SCU_PERIPH_VIRT,
78 .pfn = __phys_to_pfn(SCU_PERIPH_PHYS),
79 .length = SZ_8K,
80 .type = MT_DEVICE,
81 }, {
82 .virtual = PL310_L2CC_VIRT,
83 .pfn = __phys_to_pfn(PL310_L2CC_PHYS),
84 .length = SZ_4K,
85 .type = MT_DEVICE,
86 },
87
88#ifdef CONFIG_DEBUG_LL
89 {
90 .virtual = UART0_VIRT,
91 .pfn = __phys_to_pfn(UART0_PHYS),
92 .length = SZ_4K,
93 .type = MT_DEVICE,
94 },
95#endif
96 95
96/*
97 * Instantiate and initialize the system timer structure
98 */
99static struct sys_timer xttcpss_sys_timer = {
100 .init = xilinx_zynq_timer_init,
97}; 101};
98 102
99/** 103/**
@@ -101,11 +105,13 @@ static struct map_desc io_desc[] __initdata = {
101 */ 105 */
102static void __init xilinx_map_io(void) 106static void __init xilinx_map_io(void)
103{ 107{
104 iotable_init(io_desc, ARRAY_SIZE(io_desc)); 108 debug_ll_io_init();
109 iotable_init(&scu_desc, 1);
105} 110}
106 111
107static const char *xilinx_dt_match[] = { 112static const char *xilinx_dt_match[] = {
108 "xlnx,zynq-ep107", 113 "xlnx,zynq-zc702",
114 "xlnx,zynq-7000",
109 NULL 115 NULL
110}; 116};
111 117
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
index a009644a1555..954b91c13c91 100644
--- a/arch/arm/mach-zynq/common.h
+++ b/arch/arm/mach-zynq/common.h
@@ -17,8 +17,6 @@
17#ifndef __MACH_ZYNQ_COMMON_H__ 17#ifndef __MACH_ZYNQ_COMMON_H__
18#define __MACH_ZYNQ_COMMON_H__ 18#define __MACH_ZYNQ_COMMON_H__
19 19
20#include <asm/mach/time.h> 20void __init xttcpss_timer_init(void);
21
22extern struct sys_timer xttcpss_sys_timer;
23 21
24#endif 22#endif
diff --git a/arch/arm/mach-zynq/include/mach/clkdev.h b/arch/arm/mach-zynq/include/mach/clkdev.h
deleted file mode 100644
index c6e73d81a459..000000000000
--- a/arch/arm/mach-zynq/include/mach/clkdev.h
+++ /dev/null
@@ -1,32 +0,0 @@
1/*
2 * arch/arm/mach-zynq/include/mach/clkdev.h
3 *
4 * Copyright (C) 2011 Xilinx, Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __MACH_CLKDEV_H__
18#define __MACH_CLKDEV_H__
19
20#include <plat/clock.h>
21
22struct clk {
23 unsigned long rate;
24 const struct clk_ops *ops;
25 const struct icst_params *params;
26 void __iomem *vcoreg;
27};
28
29#define __clk_get(clk) ({ 1; })
30#define __clk_put(clk) do { } while (0)
31
32#endif
diff --git a/arch/arm/mach-zynq/include/mach/hardware.h b/arch/arm/mach-zynq/include/mach/hardware.h
deleted file mode 100644
index d558d8a94be7..000000000000
--- a/arch/arm/mach-zynq/include/mach/hardware.h
+++ /dev/null
@@ -1,18 +0,0 @@
1/* arch/arm/mach-zynq/include/mach/hardware.h
2 *
3 * Copyright (C) 2011 Xilinx
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef __MACH_HARDWARE_H__
16#define __MACH_HARDWARE_H__
17
18#endif
diff --git a/arch/arm/mach-zynq/include/mach/irqs.h b/arch/arm/mach-zynq/include/mach/irqs.h
deleted file mode 100644
index 5fb04fd3bac8..000000000000
--- a/arch/arm/mach-zynq/include/mach/irqs.h
+++ /dev/null
@@ -1,21 +0,0 @@
1/* arch/arm/mach-zynq/include/mach/irqs.h
2 *
3 * Copyright (C) 2011 Xilinx
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef __MACH_IRQS_H
16#define __MACH_IRQS_H
17
18#define ARCH_NR_GPIOS 118
19#define NR_IRQS (128 + ARCH_NR_GPIOS)
20
21#endif
diff --git a/arch/arm/mach-zynq/include/mach/timex.h b/arch/arm/mach-zynq/include/mach/timex.h
deleted file mode 100644
index 6c0245e42a5e..000000000000
--- a/arch/arm/mach-zynq/include/mach/timex.h
+++ /dev/null
@@ -1,23 +0,0 @@
1/* arch/arm/mach-zynq/include/mach/timex.h
2 *
3 * Copyright (C) 2011 Xilinx
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef __MACH_TIMEX_H__
16#define __MACH_TIMEX_H__
17
18/* the following is needed for the system to build but will be removed
19 in the future, the value is not important but won't hurt
20*/
21#define CLOCK_TICK_RATE (100 * HZ)
22
23#endif
diff --git a/arch/arm/mach-zynq/include/mach/uart.h b/arch/arm/mach-zynq/include/mach/uart.h
deleted file mode 100644
index 5c47c97156f3..000000000000
--- a/arch/arm/mach-zynq/include/mach/uart.h
+++ /dev/null
@@ -1,25 +0,0 @@
1/* arch/arm/mach-zynq/include/mach/uart.h
2 *
3 * Copyright (C) 2011 Xilinx
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef __MACH_UART_H__
16#define __MACH_UART_H__
17
18#define UART_CR_OFFSET 0x00 /* Control Register [8:0] */
19#define UART_SR_OFFSET 0x2C /* Channel Status [11:0] */
20#define UART_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */
21
22#define UART_SR_TXFULL 0x00000010 /* TX FIFO full */
23#define UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
24
25#endif
diff --git a/arch/arm/mach-zynq/include/mach/uncompress.h b/arch/arm/mach-zynq/include/mach/uncompress.h
deleted file mode 100644
index af4e8447bfa3..000000000000
--- a/arch/arm/mach-zynq/include/mach/uncompress.h
+++ /dev/null
@@ -1,51 +0,0 @@
1/* arch/arm/mach-zynq/include/mach/uncompress.h
2 *
3 * Copyright (C) 2011 Xilinx
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef __MACH_UNCOMPRESS_H__
16#define __MACH_UNCOMPRESS_H__
17
18#include <linux/io.h>
19#include <asm/processor.h>
20#include <mach/zynq_soc.h>
21#include <mach/uart.h>
22
23void arch_decomp_setup(void)
24{
25}
26
27static inline void flush(void)
28{
29 /*
30 * Wait while the FIFO is not empty
31 */
32 while (!(__raw_readl(IOMEM(LL_UART_PADDR + UART_SR_OFFSET)) &
33 UART_SR_TXEMPTY))
34 cpu_relax();
35}
36
37#define arch_decomp_wdog()
38
39static void putc(char ch)
40{
41 /*
42 * Wait for room in the FIFO, then write the char into the FIFO
43 */
44 while (__raw_readl(IOMEM(LL_UART_PADDR + UART_SR_OFFSET)) &
45 UART_SR_TXFULL)
46 cpu_relax();
47
48 __raw_writel(ch, IOMEM(LL_UART_PADDR + UART_FIFO_OFFSET));
49}
50
51#endif
diff --git a/arch/arm/mach-zynq/include/mach/zynq_soc.h b/arch/arm/mach-zynq/include/mach/zynq_soc.h
deleted file mode 100644
index d0d3f8fb06dd..000000000000
--- a/arch/arm/mach-zynq/include/mach/zynq_soc.h
+++ /dev/null
@@ -1,48 +0,0 @@
1/* arch/arm/mach-zynq/include/mach/zynq_soc.h
2 *
3 * Copyright (C) 2011 Xilinx
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef __MACH_XILINX_SOC_H__
16#define __MACH_XILINX_SOC_H__
17
18#define PERIPHERAL_CLOCK_RATE 2500000
19
20/* For now, all mappings are flat (physical = virtual)
21 */
22#define UART0_PHYS 0xE0000000
23#define UART0_VIRT UART0_PHYS
24
25#define TTC0_PHYS 0xF8001000
26#define TTC0_VIRT TTC0_PHYS
27
28#define PL310_L2CC_PHYS 0xF8F02000
29#define PL310_L2CC_VIRT PL310_L2CC_PHYS
30
31#define SCU_PERIPH_PHYS 0xF8F00000
32#define SCU_PERIPH_VIRT SCU_PERIPH_PHYS
33
34/* The following are intended for the devices that are mapped early */
35
36#define TTC0_BASE IOMEM(TTC0_VIRT)
37#define SCU_PERIPH_BASE IOMEM(SCU_PERIPH_VIRT)
38#define SCU_GIC_CPU_BASE (SCU_PERIPH_BASE + 0x100)
39#define SCU_GIC_DIST_BASE (SCU_PERIPH_BASE + 0x1000)
40#define PL310_L2CC_BASE IOMEM(PL310_L2CC_VIRT)
41
42/*
43 * Mandatory for CONFIG_LL_DEBUG, UART is mapped virtual = physical
44 */
45#define LL_UART_PADDR UART0_PHYS
46#define LL_UART_VADDR UART0_VIRT
47
48#endif
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c
index c2c96cc7d6e7..de3df283da74 100644
--- a/arch/arm/mach-zynq/timer.c
+++ b/arch/arm/mach-zynq/timer.c
@@ -23,32 +23,14 @@
23#include <linux/clocksource.h> 23#include <linux/clocksource.h>
24#include <linux/clockchips.h> 24#include <linux/clockchips.h>
25#include <linux/io.h> 25#include <linux/io.h>
26#include <linux/of.h>
27#include <linux/of_address.h>
28#include <linux/of_irq.h>
29#include <linux/slab.h>
30#include <linux/clk-provider.h>
26 31
27#include <asm/mach/time.h>
28#include <mach/zynq_soc.h>
29#include "common.h" 32#include "common.h"
30 33
31#define IRQ_TIMERCOUNTER0 42
32
33/*
34 * This driver configures the 2 16-bit count-up timers as follows:
35 *
36 * T1: Timer 1, clocksource for generic timekeeping
37 * T2: Timer 2, clockevent source for hrtimers
38 * T3: Timer 3, <unused>
39 *
40 * The input frequency to the timer module for emulation is 2.5MHz which is
41 * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
42 * the timers are clocked at 78.125KHz (12.8 us resolution).
43 *
44 * The input frequency to the timer module in silicon will be 200MHz. With the
45 * pre-scaler of 32, the timers are clocked at 6.25MHz (160ns resolution).
46 */
47#define XTTCPSS_CLOCKSOURCE 0 /* Timer 1 as a generic timekeeping */
48#define XTTCPSS_CLOCKEVENT 1 /* Timer 2 as a clock event */
49
50#define XTTCPSS_TIMER_BASE TTC0_BASE
51#define XTTCPCC_EVENT_TIMER_IRQ (IRQ_TIMERCOUNTER0 + 1)
52/* 34/*
53 * Timer Register Offset Definitions of Timer 1, Increment base address by 4 35 * Timer Register Offset Definitions of Timer 1, Increment base address by 4
54 * and use same offsets for Timer 2 36 * and use same offsets for Timer 2
@@ -65,9 +47,14 @@
65 47
66#define XTTCPSS_CNT_CNTRL_DISABLE_MASK 0x1 48#define XTTCPSS_CNT_CNTRL_DISABLE_MASK 0x1
67 49
68/* Setup the timers to use pre-scaling */ 50/* Setup the timers to use pre-scaling, using a fixed value for now that will
69 51 * work across most input frequency, but it may need to be more dynamic
70#define TIMER_RATE (PERIPHERAL_CLOCK_RATE / 32) 52 */
53#define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
54#define PRESCALE 2048 /* The exponent must match this */
55#define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1)
56#define CLK_CNTRL_PRESCALE_EN 1
57#define CNT_CNTRL_RESET (1<<4)
71 58
72/** 59/**
73 * struct xttcpss_timer - This definition defines local timer structure 60 * struct xttcpss_timer - This definition defines local timer structure
@@ -75,11 +62,25 @@
75 * @base_addr: Base address of timer 62 * @base_addr: Base address of timer
76 **/ 63 **/
77struct xttcpss_timer { 64struct xttcpss_timer {
78 void __iomem *base_addr; 65 void __iomem *base_addr;
79}; 66};
80 67
81static struct xttcpss_timer timers[2]; 68struct xttcpss_timer_clocksource {
82static struct clock_event_device xttcpss_clockevent; 69 struct xttcpss_timer xttc;
70 struct clocksource cs;
71};
72
73#define to_xttcpss_timer_clksrc(x) \
74 container_of(x, struct xttcpss_timer_clocksource, cs)
75
76struct xttcpss_timer_clockevent {
77 struct xttcpss_timer xttc;
78 struct clock_event_device ce;
79 struct clk *clk;
80};
81
82#define to_xttcpss_timer_clkevent(x) \
83 container_of(x, struct xttcpss_timer_clockevent, ce)
83 84
84/** 85/**
85 * xttcpss_set_interval - Set the timer interval value 86 * xttcpss_set_interval - Set the timer interval value
@@ -101,7 +102,7 @@ static void xttcpss_set_interval(struct xttcpss_timer *timer,
101 102
102 /* Reset the counter (0x10) so that it starts from 0, one-shot 103 /* Reset the counter (0x10) so that it starts from 0, one-shot
103 mode makes this needed for timing to be right. */ 104 mode makes this needed for timing to be right. */
104 ctrl_reg |= 0x10; 105 ctrl_reg |= CNT_CNTRL_RESET;
105 ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK; 106 ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK;
106 __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); 107 __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
107} 108}
@@ -116,90 +117,31 @@ static void xttcpss_set_interval(struct xttcpss_timer *timer,
116 **/ 117 **/
117static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id) 118static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id)
118{ 119{
119 struct clock_event_device *evt = &xttcpss_clockevent; 120 struct xttcpss_timer_clockevent *xttce = dev_id;
120 struct xttcpss_timer *timer = dev_id; 121 struct xttcpss_timer *timer = &xttce->xttc;
121 122
122 /* Acknowledge the interrupt and call event handler */ 123 /* Acknowledge the interrupt and call event handler */
123 __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET), 124 __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET),
124 timer->base_addr + XTTCPSS_ISR_OFFSET); 125 timer->base_addr + XTTCPSS_ISR_OFFSET);
125 126
126 evt->event_handler(evt); 127 xttce->ce.event_handler(&xttce->ce);
127 128
128 return IRQ_HANDLED; 129 return IRQ_HANDLED;
129} 130}
130 131
131static struct irqaction event_timer_irq = {
132 .name = "xttcpss clockevent",
133 .flags = IRQF_DISABLED | IRQF_TIMER,
134 .handler = xttcpss_clock_event_interrupt,
135};
136
137/** 132/**
138 * xttcpss_timer_hardware_init - Initialize the timer hardware 133 * __xttc_clocksource_read - Reads the timer counter register
139 *
140 * Initialize the hardware to start the clock source, get the clock
141 * event timer ready to use, and hook up the interrupt.
142 **/
143static void __init xttcpss_timer_hardware_init(void)
144{
145 /* Setup the clock source counter to be an incrementing counter
146 * with no interrupt and it rolls over at 0xFFFF. Pre-scale
147 it by 32 also. Let it start running now.
148 */
149 timers[XTTCPSS_CLOCKSOURCE].base_addr = XTTCPSS_TIMER_BASE;
150
151 __raw_writel(0x0, timers[XTTCPSS_CLOCKSOURCE].base_addr +
152 XTTCPSS_IER_OFFSET);
153 __raw_writel(0x9, timers[XTTCPSS_CLOCKSOURCE].base_addr +
154 XTTCPSS_CLK_CNTRL_OFFSET);
155 __raw_writel(0x10, timers[XTTCPSS_CLOCKSOURCE].base_addr +
156 XTTCPSS_CNT_CNTRL_OFFSET);
157
158 /* Setup the clock event timer to be an interval timer which
159 * is prescaled by 32 using the interval interrupt. Leave it
160 * disabled for now.
161 */
162
163 timers[XTTCPSS_CLOCKEVENT].base_addr = XTTCPSS_TIMER_BASE + 4;
164
165 __raw_writel(0x23, timers[XTTCPSS_CLOCKEVENT].base_addr +
166 XTTCPSS_CNT_CNTRL_OFFSET);
167 __raw_writel(0x9, timers[XTTCPSS_CLOCKEVENT].base_addr +
168 XTTCPSS_CLK_CNTRL_OFFSET);
169 __raw_writel(0x1, timers[XTTCPSS_CLOCKEVENT].base_addr +
170 XTTCPSS_IER_OFFSET);
171
172 /* Setup IRQ the clock event timer */
173 event_timer_irq.dev_id = &timers[XTTCPSS_CLOCKEVENT];
174 setup_irq(XTTCPCC_EVENT_TIMER_IRQ, &event_timer_irq);
175}
176
177/**
178 * __raw_readl_cycles - Reads the timer counter register
179 * 134 *
180 * returns: Current timer counter register value 135 * returns: Current timer counter register value
181 **/ 136 **/
182static cycle_t __raw_readl_cycles(struct clocksource *cs) 137static cycle_t __xttc_clocksource_read(struct clocksource *cs)
183{ 138{
184 struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKSOURCE]; 139 struct xttcpss_timer *timer = &to_xttcpss_timer_clksrc(cs)->xttc;
185 140
186 return (cycle_t)__raw_readl(timer->base_addr + 141 return (cycle_t)__raw_readl(timer->base_addr +
187 XTTCPSS_COUNT_VAL_OFFSET); 142 XTTCPSS_COUNT_VAL_OFFSET);
188} 143}
189 144
190
191/*
192 * Instantiate and initialize the clock source structure
193 */
194static struct clocksource clocksource_xttcpss = {
195 .name = "xttcpss_timer1",
196 .rating = 200, /* Reasonable clock source */
197 .read = __raw_readl_cycles,
198 .mask = CLOCKSOURCE_MASK(16),
199 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
200};
201
202
203/** 145/**
204 * xttcpss_set_next_event - Sets the time interval for next event 146 * xttcpss_set_next_event - Sets the time interval for next event
205 * 147 *
@@ -211,7 +153,8 @@ static struct clocksource clocksource_xttcpss = {
211static int xttcpss_set_next_event(unsigned long cycles, 153static int xttcpss_set_next_event(unsigned long cycles,
212 struct clock_event_device *evt) 154 struct clock_event_device *evt)
213{ 155{
214 struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT]; 156 struct xttcpss_timer_clockevent *xttce = to_xttcpss_timer_clkevent(evt);
157 struct xttcpss_timer *timer = &xttce->xttc;
215 158
216 xttcpss_set_interval(timer, cycles); 159 xttcpss_set_interval(timer, cycles);
217 return 0; 160 return 0;
@@ -226,12 +169,15 @@ static int xttcpss_set_next_event(unsigned long cycles,
226static void xttcpss_set_mode(enum clock_event_mode mode, 169static void xttcpss_set_mode(enum clock_event_mode mode,
227 struct clock_event_device *evt) 170 struct clock_event_device *evt)
228{ 171{
229 struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT]; 172 struct xttcpss_timer_clockevent *xttce = to_xttcpss_timer_clkevent(evt);
173 struct xttcpss_timer *timer = &xttce->xttc;
230 u32 ctrl_reg; 174 u32 ctrl_reg;
231 175
232 switch (mode) { 176 switch (mode) {
233 case CLOCK_EVT_MODE_PERIODIC: 177 case CLOCK_EVT_MODE_PERIODIC:
234 xttcpss_set_interval(timer, TIMER_RATE / HZ); 178 xttcpss_set_interval(timer,
179 DIV_ROUND_CLOSEST(clk_get_rate(xttce->clk),
180 PRESCALE * HZ));
235 break; 181 break;
236 case CLOCK_EVT_MODE_ONESHOT: 182 case CLOCK_EVT_MODE_ONESHOT:
237 case CLOCK_EVT_MODE_UNUSED: 183 case CLOCK_EVT_MODE_UNUSED:
@@ -252,15 +198,106 @@ static void xttcpss_set_mode(enum clock_event_mode mode,
252 } 198 }
253} 199}
254 200
255/* 201static void __init zynq_ttc_setup_clocksource(struct device_node *np,
256 * Instantiate and initialize the clock event structure 202 void __iomem *base)
257 */ 203{
258static struct clock_event_device xttcpss_clockevent = { 204 struct xttcpss_timer_clocksource *ttccs;
259 .name = "xttcpss_timer2", 205 struct clk *clk;
260 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 206 int err;
261 .set_next_event = xttcpss_set_next_event, 207 u32 reg;
262 .set_mode = xttcpss_set_mode, 208
263 .rating = 200, 209 ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
210 if (WARN_ON(!ttccs))
211 return;
212
213 err = of_property_read_u32(np, "reg", &reg);
214 if (WARN_ON(err))
215 return;
216
217 clk = of_clk_get_by_name(np, "cpu_1x");
218 if (WARN_ON(IS_ERR(clk)))
219 return;
220
221 err = clk_prepare_enable(clk);
222 if (WARN_ON(err))
223 return;
224
225 ttccs->xttc.base_addr = base + reg * 4;
226
227 ttccs->cs.name = np->name;
228 ttccs->cs.rating = 200;
229 ttccs->cs.read = __xttc_clocksource_read;
230 ttccs->cs.mask = CLOCKSOURCE_MASK(16);
231 ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
232
233 __raw_writel(0x0, ttccs->xttc.base_addr + XTTCPSS_IER_OFFSET);
234 __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
235 ttccs->xttc.base_addr + XTTCPSS_CLK_CNTRL_OFFSET);
236 __raw_writel(CNT_CNTRL_RESET,
237 ttccs->xttc.base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
238
239 err = clocksource_register_hz(&ttccs->cs, clk_get_rate(clk) / PRESCALE);
240 if (WARN_ON(err))
241 return;
242}
243
244static void __init zynq_ttc_setup_clockevent(struct device_node *np,
245 void __iomem *base)
246{
247 struct xttcpss_timer_clockevent *ttcce;
248 int err, irq;
249 u32 reg;
250
251 ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
252 if (WARN_ON(!ttcce))
253 return;
254
255 err = of_property_read_u32(np, "reg", &reg);
256 if (WARN_ON(err))
257 return;
258
259 ttcce->xttc.base_addr = base + reg * 4;
260
261 ttcce->clk = of_clk_get_by_name(np, "cpu_1x");
262 if (WARN_ON(IS_ERR(ttcce->clk)))
263 return;
264
265 err = clk_prepare_enable(ttcce->clk);
266 if (WARN_ON(err))
267 return;
268
269 irq = irq_of_parse_and_map(np, 0);
270 if (WARN_ON(!irq))
271 return;
272
273 ttcce->ce.name = np->name;
274 ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
275 ttcce->ce.set_next_event = xttcpss_set_next_event;
276 ttcce->ce.set_mode = xttcpss_set_mode;
277 ttcce->ce.rating = 200;
278 ttcce->ce.irq = irq;
279
280 __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
281 __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
282 ttcce->xttc.base_addr + XTTCPSS_CLK_CNTRL_OFFSET);
283 __raw_writel(0x1, ttcce->xttc.base_addr + XTTCPSS_IER_OFFSET);
284
285 err = request_irq(irq, xttcpss_clock_event_interrupt, IRQF_TIMER,
286 np->name, ttcce);
287 if (WARN_ON(err))
288 return;
289
290 clockevents_config_and_register(&ttcce->ce,
291 clk_get_rate(ttcce->clk) / PRESCALE,
292 1, 0xfffe);
293}
294
295static const __initconst struct of_device_id zynq_ttc_match[] = {
296 { .compatible = "xlnx,ttc-counter-clocksource",
297 .data = zynq_ttc_setup_clocksource, },
298 { .compatible = "xlnx,ttc-counter-clockevent",
299 .data = zynq_ttc_setup_clockevent, },
300 {}
264}; 301};
265 302
266/** 303/**
@@ -269,30 +306,27 @@ static struct clock_event_device xttcpss_clockevent = {
269 * Initializes the timer hardware and register the clock source and clock event 306 * Initializes the timer hardware and register the clock source and clock event
270 * timers with Linux kernal timer framework 307 * timers with Linux kernal timer framework
271 **/ 308 **/
272static void __init xttcpss_timer_init(void) 309void __init xttcpss_timer_init(void)
273{ 310{
274 xttcpss_timer_hardware_init(); 311 struct device_node *np;
275 clocksource_register_hz(&clocksource_xttcpss, TIMER_RATE); 312
276 313 for_each_compatible_node(np, NULL, "xlnx,ttc") {
277 /* Calculate the parameters to allow the clockevent to operate using 314 struct device_node *np_chld;
278 integer math 315 void __iomem *base;
279 */ 316
280 clockevents_calc_mult_shift(&xttcpss_clockevent, TIMER_RATE, 4); 317 base = of_iomap(np, 0);
281 318 if (WARN_ON(!base))
282 xttcpss_clockevent.max_delta_ns = 319 return;
283 clockevent_delta2ns(0xfffe, &xttcpss_clockevent); 320
284 xttcpss_clockevent.min_delta_ns = 321 for_each_available_child_of_node(np, np_chld) {
285 clockevent_delta2ns(1, &xttcpss_clockevent); 322 int (*cb)(struct device_node *np, void __iomem *base);
286 323 const struct of_device_id *match;
287 /* Indicate that clock event is on 1st CPU as SMP boot needs it */ 324
288 325 match = of_match_node(zynq_ttc_match, np_chld);
289 xttcpss_clockevent.cpumask = cpumask_of(0); 326 if (match) {
290 clockevents_register_device(&xttcpss_clockevent); 327 cb = match->data;
328 cb(np_chld, base);
329 }
330 }
331 }
291} 332}
292
293/*
294 * Instantiate and initialize the system timer structure
295 */
296struct sys_timer xttcpss_sys_timer = {
297 .init = xttcpss_timer_init,
298};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 71a25b91de00..d35a34c58369 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_ZYNQ) += clk-zynq.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-zynq.c b/drivers/clk/clk-zynq.c
new file mode 100644
index 000000000000..37a30514fd66
--- /dev/null
+++ b/drivers/clk/clk-zynq.c
@@ -0,0 +1,383 @@
1/*
2 * Copyright (c) 2012 National Instruments
3 *
4 * Josh Cartwright <josh.cartwright@ni.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include <linux/io.h>
19#include <linux/of.h>
20#include <linux/slab.h>
21#include <linux/kernel.h>
22#include <linux/clk-provider.h>
23
24static void __iomem *slcr_base;
25
26struct zynq_pll_clk {
27 struct clk_hw hw;
28 void __iomem *pll_ctrl;
29 void __iomem *pll_cfg;
30};
31
32#define to_zynq_pll_clk(hw) container_of(hw, struct zynq_pll_clk, hw)
33
34#define CTRL_PLL_FDIV(x) ((x) >> 12)
35
36static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw,
37 unsigned long parent_rate)
38{
39 struct zynq_pll_clk *pll = to_zynq_pll_clk(hw);
40 return parent_rate * CTRL_PLL_FDIV(ioread32(pll->pll_ctrl));
41}
42
43static const struct clk_ops zynq_pll_clk_ops = {
44 .recalc_rate = zynq_pll_recalc_rate,
45};
46
47static void __init zynq_pll_clk_setup(struct device_node *np)
48{
49 struct clk_init_data init;
50 struct zynq_pll_clk *pll;
51 const char *parent_name;
52 struct clk *clk;
53 u32 regs[2];
54 int ret;
55
56 ret = of_property_read_u32_array(np, "reg", regs, ARRAY_SIZE(regs));
57 if (WARN_ON(ret))
58 return;
59
60 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
61 if (WARN_ON(!pll))
62 return;
63
64 pll->pll_ctrl = slcr_base + regs[0];
65 pll->pll_cfg = slcr_base + regs[1];
66
67 of_property_read_string(np, "clock-output-names", &init.name);
68
69 init.ops = &zynq_pll_clk_ops;
70 parent_name = of_clk_get_parent_name(np, 0);
71 init.parent_names = &parent_name;
72 init.num_parents = 1;
73
74 pll->hw.init = &init;
75
76 clk = clk_register(NULL, &pll->hw);
77 if (WARN_ON(IS_ERR(clk)))
78 return;
79
80 ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
81 if (WARN_ON(ret))
82 return;
83}
84
85struct zynq_periph_clk {
86 struct clk_hw hw;
87 struct clk_onecell_data onecell_data;
88 struct clk *gates[2];
89 void __iomem *clk_ctrl;
90 spinlock_t clkact_lock;
91};
92
93#define to_zynq_periph_clk(hw) container_of(hw, struct zynq_periph_clk, hw)
94
95static const u8 periph_clk_parent_map[] = {
96 0, 0, 1, 2
97};
98#define PERIPH_CLK_CTRL_SRC(x) (periph_clk_parent_map[((x) & 0x30) >> 4])
99#define PERIPH_CLK_CTRL_DIV(x) (((x) & 0x3F00) >> 8)
100
101static unsigned long zynq_periph_recalc_rate(struct clk_hw *hw,
102 unsigned long parent_rate)
103{
104 struct zynq_periph_clk *periph = to_zynq_periph_clk(hw);
105 return parent_rate / PERIPH_CLK_CTRL_DIV(ioread32(periph->clk_ctrl));
106}
107
108static u8 zynq_periph_get_parent(struct clk_hw *hw)
109{
110 struct zynq_periph_clk *periph = to_zynq_periph_clk(hw);
111 return PERIPH_CLK_CTRL_SRC(ioread32(periph->clk_ctrl));
112}
113
114static const struct clk_ops zynq_periph_clk_ops = {
115 .recalc_rate = zynq_periph_recalc_rate,
116 .get_parent = zynq_periph_get_parent,
117};
118
119static void __init zynq_periph_clk_setup(struct device_node *np)
120{
121 struct zynq_periph_clk *periph;
122 const char *parent_names[3];
123 struct clk_init_data init;
124 int clk_num = 0, err;
125 const char *name;
126 struct clk *clk;
127 u32 reg;
128 int i;
129
130 err = of_property_read_u32(np, "reg", &reg);
131 if (WARN_ON(err))
132 return;
133
134 periph = kzalloc(sizeof(*periph), GFP_KERNEL);
135 if (WARN_ON(!periph))
136 return;
137
138 periph->clk_ctrl = slcr_base + reg;
139 spin_lock_init(&periph->clkact_lock);
140
141 init.name = np->name;
142 init.ops = &zynq_periph_clk_ops;
143 for (i = 0; i < ARRAY_SIZE(parent_names); i++)
144 parent_names[i] = of_clk_get_parent_name(np, i);
145 init.parent_names = parent_names;
146 init.num_parents = ARRAY_SIZE(parent_names);
147
148 periph->hw.init = &init;
149
150 clk = clk_register(NULL, &periph->hw);
151 if (WARN_ON(IS_ERR(clk)))
152 return;
153
154 err = of_clk_add_provider(np, of_clk_src_simple_get, clk);
155 if (WARN_ON(err))
156 return;
157
158 err = of_property_read_string_index(np, "clock-output-names", 0,
159 &name);
160 if (WARN_ON(err))
161 return;
162
163 periph->gates[0] = clk_register_gate(NULL, name, np->name, 0,
164 periph->clk_ctrl, 0, 0,
165 &periph->clkact_lock);
166 if (WARN_ON(IS_ERR(periph->gates[0])))
167 return;
168 clk_num++;
169
170 /* some periph clks have 2 downstream gates */
171 err = of_property_read_string_index(np, "clock-output-names", 1,
172 &name);
173 if (err != -ENODATA) {
174 periph->gates[1] = clk_register_gate(NULL, name, np->name, 0,
175 periph->clk_ctrl, 1, 0,
176 &periph->clkact_lock);
177 if (WARN_ON(IS_ERR(periph->gates[1])))
178 return;
179 clk_num++;
180 }
181
182 periph->onecell_data.clks = periph->gates;
183 periph->onecell_data.clk_num = clk_num;
184
185 err = of_clk_add_provider(np, of_clk_src_onecell_get,
186 &periph->onecell_data);
187 if (WARN_ON(err))
188 return;
189}
190
191/* CPU Clock domain is modelled as a mux with 4 children subclks, whose
192 * derivative rates depend on CLK_621_TRUE
193 */
194
195struct zynq_cpu_clk {
196 struct clk_hw hw;
197 struct clk_onecell_data onecell_data;
198 struct clk *subclks[4];
199 void __iomem *clk_ctrl;
200 spinlock_t clkact_lock;
201};
202
203#define to_zynq_cpu_clk(hw) container_of(hw, struct zynq_cpu_clk, hw)
204
205static const u8 zynq_cpu_clk_parent_map[] = {
206 1, 1, 2, 0
207};
208#define CPU_CLK_SRCSEL(x) (zynq_cpu_clk_parent_map[(((x) & 0x30) >> 4)])
209#define CPU_CLK_CTRL_DIV(x) (((x) & 0x3F00) >> 8)
210
211static u8 zynq_cpu_clk_get_parent(struct clk_hw *hw)
212{
213 struct zynq_cpu_clk *cpuclk = to_zynq_cpu_clk(hw);
214 return CPU_CLK_SRCSEL(ioread32(cpuclk->clk_ctrl));
215}
216
217static unsigned long zynq_cpu_clk_recalc_rate(struct clk_hw *hw,
218 unsigned long parent_rate)
219{
220 struct zynq_cpu_clk *cpuclk = to_zynq_cpu_clk(hw);
221 return parent_rate / CPU_CLK_CTRL_DIV(ioread32(cpuclk->clk_ctrl));
222}
223
224static const struct clk_ops zynq_cpu_clk_ops = {
225 .get_parent = zynq_cpu_clk_get_parent,
226 .recalc_rate = zynq_cpu_clk_recalc_rate,
227};
228
229struct zynq_cpu_subclk {
230 struct clk_hw hw;
231 void __iomem *clk_621;
232 enum {
233 CPU_SUBCLK_6X4X,
234 CPU_SUBCLK_3X2X,
235 CPU_SUBCLK_2X,
236 CPU_SUBCLK_1X,
237 } which;
238};
239
240#define CLK_621_TRUE(x) ((x) & 1)
241
242#define to_zynq_cpu_subclk(hw) container_of(hw, struct zynq_cpu_subclk, hw);
243
244static unsigned long zynq_cpu_subclk_recalc_rate(struct clk_hw *hw,
245 unsigned long parent_rate)
246{
247 unsigned long uninitialized_var(rate);
248 struct zynq_cpu_subclk *subclk;
249 bool is_621;
250
251 subclk = to_zynq_cpu_subclk(hw)
252 is_621 = CLK_621_TRUE(ioread32(subclk->clk_621));
253
254 switch (subclk->which) {
255 case CPU_SUBCLK_6X4X:
256 rate = parent_rate;
257 break;
258 case CPU_SUBCLK_3X2X:
259 rate = parent_rate / 2;
260 break;
261 case CPU_SUBCLK_2X:
262 rate = parent_rate / (is_621 ? 3 : 2);
263 break;
264 case CPU_SUBCLK_1X:
265 rate = parent_rate / (is_621 ? 6 : 4);
266 break;
267 };
268
269 return rate;
270}
271
272static const struct clk_ops zynq_cpu_subclk_ops = {
273 .recalc_rate = zynq_cpu_subclk_recalc_rate,
274};
275
276static struct clk *zynq_cpu_subclk_setup(struct device_node *np, u8 which,
277 void __iomem *clk_621)
278{
279 struct zynq_cpu_subclk *subclk;
280 struct clk_init_data init;
281 struct clk *clk;
282 int err;
283
284 err = of_property_read_string_index(np, "clock-output-names",
285 which, &init.name);
286 if (WARN_ON(err))
287 goto err_read_output_name;
288
289 subclk = kzalloc(sizeof(*subclk), GFP_KERNEL);
290 if (!subclk)
291 goto err_subclk_alloc;
292
293 subclk->clk_621 = clk_621;
294 subclk->which = which;
295
296 init.ops = &zynq_cpu_subclk_ops;
297 init.parent_names = &np->name;
298 init.num_parents = 1;
299
300 subclk->hw.init = &init;
301
302 clk = clk_register(NULL, &subclk->hw);
303 if (WARN_ON(IS_ERR(clk)))
304 goto err_clk_register;
305
306 return clk;
307
308err_clk_register:
309 kfree(subclk);
310err_subclk_alloc:
311err_read_output_name:
312 return ERR_PTR(-EINVAL);
313}
314
315static void __init zynq_cpu_clk_setup(struct device_node *np)
316{
317 struct zynq_cpu_clk *cpuclk;
318 const char *parent_names[3];
319 struct clk_init_data init;
320 void __iomem *clk_621;
321 struct clk *clk;
322 u32 reg[2];
323 int err;
324 int i;
325
326 err = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
327 if (WARN_ON(err))
328 return;
329
330 cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
331 if (WARN_ON(!cpuclk))
332 return;
333
334 cpuclk->clk_ctrl = slcr_base + reg[0];
335 clk_621 = slcr_base + reg[1];
336 spin_lock_init(&cpuclk->clkact_lock);
337
338 init.name = np->name;
339 init.ops = &zynq_cpu_clk_ops;
340 for (i = 0; i < ARRAY_SIZE(parent_names); i++)
341 parent_names[i] = of_clk_get_parent_name(np, i);
342 init.parent_names = parent_names;
343 init.num_parents = ARRAY_SIZE(parent_names);
344
345 cpuclk->hw.init = &init;
346
347 clk = clk_register(NULL, &cpuclk->hw);
348 if (WARN_ON(IS_ERR(clk)))
349 return;
350
351 err = of_clk_add_provider(np, of_clk_src_simple_get, clk);
352 if (WARN_ON(err))
353 return;
354
355 for (i = 0; i < 4; i++) {
356 cpuclk->subclks[i] = zynq_cpu_subclk_setup(np, i, clk_621);
357 if (WARN_ON(IS_ERR(cpuclk->subclks[i])))
358 return;
359 }
360
361 cpuclk->onecell_data.clks = cpuclk->subclks;
362 cpuclk->onecell_data.clk_num = i;
363
364 err = of_clk_add_provider(np, of_clk_src_onecell_get,
365 &cpuclk->onecell_data);
366 if (WARN_ON(err))
367 return;
368}
369
370static const __initconst struct of_device_id zynq_clk_match[] = {
371 { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
372 { .compatible = "xlnx,zynq-pll", .data = zynq_pll_clk_setup, },
373 { .compatible = "xlnx,zynq-periph-clock",
374 .data = zynq_periph_clk_setup, },
375 { .compatible = "xlnx,zynq-cpu-clock", .data = zynq_cpu_clk_setup, },
376 {}
377};
378
379void __init xilinx_zynq_clocks_init(void __iomem *slcr)
380{
381 slcr_base = slcr;
382 of_clk_init(zynq_clk_match);
383}
diff --git a/include/linux/clk/zynq.h b/include/linux/clk/zynq.h
new file mode 100644
index 000000000000..56be7cd9aa8b
--- /dev/null
+++ b/include/linux/clk/zynq.h
@@ -0,0 +1,24 @@
1/*
2 * Copyright (C) 2012 National Instruments
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#ifndef __LINUX_CLK_ZYNQ_H_
20#define __LINUX_CLK_ZYNQ_H_
21
22void __init xilinx_zynq_clocks_init(void __iomem *slcr);
23
24#endif