diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2012-11-16 11:47:11 -0500 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2012-11-16 11:47:11 -0500 |
| commit | 8ec1c811722b940c09961edd20bffb9eda1027c3 (patch) | |
| tree | 7ea265830276e1b8dd658519d093692f05359f8e | |
| parent | bac2f668864eca45b702ee394bef4c5f3a86658c (diff) | |
| parent | 91dc985c5e51af7036c1ccf9cea1b05662c96791 (diff) | |
Merge branch 'arm-next' of git://git.xilinx.com/linux-xlnx into next/dt
From Michal Simek <michal.simek@xilinx.com>:
These are based on previous patches (arm-soc zynq/cleanup branch).
The branch is still based on rc3 but I have also tried to merged it
with the v3.7-rc5 and there is no issue.
* 'arm-next' of git://git.xilinx.com/linux-xlnx:
ARM: zynq: add clk binding support to the ttc
ARM: zynq: use zynq clk bindings
clk: Add support for fundamental zynq clks
ARM: zynq: dts: split up device tree
ARM: zynq: Allow UART1 to be used as DEBUG_LL console.
ARM: zynq: dts: add description of the second uart
ARM: zynq: move arm-specific sys_timer out of ttc
zynq: move static peripheral mappings
zynq: remove use of CLKDEV_LOOKUP
zynq: use pl310 device tree bindings
zynq: use GIC device tree bindings
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
| -rw-r--r-- | Documentation/devicetree/bindings/clock/zynq-7000.txt | 55 | ||||
| -rw-r--r-- | arch/arm/Kconfig | 2 | ||||
| -rw-r--r-- | arch/arm/Kconfig.debug | 17 | ||||
| -rw-r--r-- | arch/arm/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/boot/dts/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/boot/dts/zynq-7000.dtsi | 166 | ||||
| -rw-r--r-- | arch/arm/boot/dts/zynq-ep107.dts | 52 | ||||
| -rw-r--r-- | arch/arm/boot/dts/zynq-zc702.dts | 44 | ||||
| -rw-r--r-- | arch/arm/mach-zynq/common.c | 54 | ||||
| -rw-r--r-- | arch/arm/mach-zynq/common.h | 4 | ||||
| -rw-r--r-- | arch/arm/mach-zynq/include/mach/clkdev.h | 32 | ||||
| -rw-r--r-- | arch/arm/mach-zynq/include/mach/zynq_soc.h | 45 | ||||
| -rw-r--r-- | arch/arm/mach-zynq/timer.c | 297 | ||||
| -rw-r--r-- | drivers/clk/Makefile | 1 | ||||
| -rw-r--r-- | drivers/clk/clk-zynq.c | 383 | ||||
| -rw-r--r-- | include/linux/clk/zynq.h | 24 |
16 files changed, 922 insertions, 256 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 @@ | |||
| 1 | Device Tree Clock bindings for the Zynq 7000 EPP | ||
| 2 | |||
| 3 | The Zynq EPP has several different clk providers, each with there own bindings. | ||
| 4 | The purpose of this document is to document their usage. | ||
| 5 | |||
| 6 | See clock_bindings.txt for more information on the generic clock bindings. | ||
| 7 | See Chapter 25 of Zynq TRM for more information about Zynq clocks. | ||
| 8 | |||
| 9 | == PLLs == | ||
| 10 | |||
| 11 | Used to describe the ARM_PLL, DDR_PLL, and IO_PLL. | ||
| 12 | |||
| 13 | Required 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 | |||
| 20 | Optional properties: | ||
| 21 | - clock-output-names : name of the output clock | ||
| 22 | |||
| 23 | Example: | ||
| 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 | |||
| 34 | Describes clock node for the SDIO, SMC, SPI, QSPI, and UART clocks. | ||
| 35 | |||
| 36 | Required 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 | |||
| 47 | Example: | ||
| 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 d33dc606f7ec..23252783e93f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -945,7 +945,7 @@ config ARCH_ZYNQ | |||
| 945 | bool "Xilinx Zynq ARM Cortex A9 Platform" | 945 | bool "Xilinx Zynq ARM Cortex A9 Platform" |
| 946 | select ARM_AMBA | 946 | select ARM_AMBA |
| 947 | select ARM_GIC | 947 | select ARM_GIC |
| 948 | select CLKDEV_LOOKUP | 948 | select COMMON_CLK |
| 949 | select CPU_V7 | 949 | select CPU_V7 |
| 950 | select GENERIC_CLOCKEVENTS | 950 | select GENERIC_CLOCKEVENTS |
| 951 | select ICST | 951 | select ICST |
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 5566520686a5..5bbfcf0d35e0 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 |
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 3353b7613208..97252d86a701 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
| @@ -198,7 +198,6 @@ machine-$(CONFIG_ARCH_ZYNQ) += zynq | |||
| 198 | # by CONFIG_* macro name. | 198 | # by CONFIG_* macro name. |
| 199 | plat-$(CONFIG_ARCH_OMAP) += omap | 199 | plat-$(CONFIG_ARCH_OMAP) += omap |
| 200 | plat-$(CONFIG_ARCH_S3C64XX) += samsung | 200 | plat-$(CONFIG_ARCH_S3C64XX) += samsung |
| 201 | plat-$(CONFIG_ARCH_ZYNQ) += versatile | ||
| 202 | plat-$(CONFIG_PLAT_IOP) += iop | 201 | plat-$(CONFIG_PLAT_IOP) += iop |
| 203 | plat-$(CONFIG_PLAT_NOMADIK) += nomadik | 202 | plat-$(CONFIG_PLAT_NOMADIK) += nomadik |
| 204 | plat-$(CONFIG_PLAT_ORION) += orion | 203 | plat-$(CONFIG_PLAT_ORION) += orion |
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 2458b69e2be6..23b178389eb7 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile | |||
| @@ -105,5 +105,6 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ | |||
| 105 | dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ | 105 | dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ |
| 106 | wm8505-ref.dtb \ | 106 | wm8505-ref.dtb \ |
| 107 | wm8650-mid.dtb | 107 | wm8650-mid.dtb |
| 108 | dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb | ||
| 108 | 109 | ||
| 109 | endif | 110 | endif |
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/common.c b/arch/arm/mach-zynq/common.c index ab5cfddc0d7b..79bf5fb4dad3 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> |
| 30 | #include <asm/hardware/gic.h> | 33 | #include <asm/hardware/gic.h> |
| 31 | #include <asm/hardware/cache-l2x0.h> | 34 | #include <asm/hardware/cache-l2x0.h> |
| 32 | 35 | ||
| 33 | #include <mach/zynq_soc.h> | 36 | #include <mach/zynq_soc.h> |
| 34 | #include <mach/clkdev.h> | ||
| 35 | #include "common.h" | 37 | #include "common.h" |
| 36 | 38 | ||
| 37 | static struct of_device_id zynq_of_bus_ids[] __initdata = { | 39 | static struct of_device_id zynq_of_bus_ids[] __initdata = { |
| @@ -45,22 +47,25 @@ static struct of_device_id zynq_of_bus_ids[] __initdata = { | |||
| 45 | */ | 47 | */ |
| 46 | static void __init xilinx_init_machine(void) | 48 | static 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 | ||
| 58 | static 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 | */ |
| 61 | static void __init xilinx_irq_init(void) | 66 | static 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 | /* The minimum devices needed to be mapped before the VM system is up and |
| @@ -71,31 +76,47 @@ static struct map_desc io_desc[] __initdata = { | |||
| 71 | { | 76 | { |
| 72 | .virtual = TTC0_VIRT, | 77 | .virtual = TTC0_VIRT, |
| 73 | .pfn = __phys_to_pfn(TTC0_PHYS), | 78 | .pfn = __phys_to_pfn(TTC0_PHYS), |
| 74 | .length = SZ_4K, | 79 | .length = TTC0_SIZE, |
| 75 | .type = MT_DEVICE, | 80 | .type = MT_DEVICE, |
| 76 | }, { | 81 | }, { |
| 77 | .virtual = SCU_PERIPH_VIRT, | 82 | .virtual = SCU_PERIPH_VIRT, |
| 78 | .pfn = __phys_to_pfn(SCU_PERIPH_PHYS), | 83 | .pfn = __phys_to_pfn(SCU_PERIPH_PHYS), |
| 79 | .length = SZ_8K, | 84 | .length = SCU_PERIPH_SIZE, |
| 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, | 85 | .type = MT_DEVICE, |
| 86 | }, | 86 | }, |
| 87 | 87 | ||
| 88 | #ifdef CONFIG_DEBUG_LL | 88 | #ifdef CONFIG_DEBUG_LL |
| 89 | { | 89 | { |
| 90 | .virtual = UART0_VIRT, | 90 | .virtual = LL_UART_VADDR, |
| 91 | .pfn = __phys_to_pfn(UART0_PHYS), | 91 | .pfn = __phys_to_pfn(LL_UART_PADDR), |
| 92 | .length = SZ_4K, | 92 | .length = UART_SIZE, |
| 93 | .type = MT_DEVICE, | 93 | .type = MT_DEVICE, |
| 94 | }, | 94 | }, |
| 95 | #endif | 95 | #endif |
| 96 | 96 | ||
| 97 | }; | 97 | }; |
| 98 | 98 | ||
| 99 | static void __init xilinx_zynq_timer_init(void) | ||
| 100 | { | ||
| 101 | struct device_node *np; | ||
| 102 | void __iomem *slcr; | ||
| 103 | |||
| 104 | np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr"); | ||
| 105 | slcr = of_iomap(np, 0); | ||
| 106 | WARN_ON(!slcr); | ||
| 107 | |||
| 108 | xilinx_zynq_clocks_init(slcr); | ||
| 109 | |||
| 110 | xttcpss_timer_init(); | ||
| 111 | } | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Instantiate and initialize the system timer structure | ||
| 115 | */ | ||
| 116 | static struct sys_timer xttcpss_sys_timer = { | ||
| 117 | .init = xilinx_zynq_timer_init, | ||
| 118 | }; | ||
| 119 | |||
| 99 | /** | 120 | /** |
| 100 | * xilinx_map_io() - Create memory mappings needed for early I/O. | 121 | * xilinx_map_io() - Create memory mappings needed for early I/O. |
| 101 | */ | 122 | */ |
| @@ -105,7 +126,8 @@ static void __init xilinx_map_io(void) | |||
| 105 | } | 126 | } |
| 106 | 127 | ||
| 107 | static const char *xilinx_dt_match[] = { | 128 | static const char *xilinx_dt_match[] = { |
| 108 | "xlnx,zynq-ep107", | 129 | "xlnx,zynq-zc702", |
| 130 | "xlnx,zynq-7000", | ||
| 109 | NULL | 131 | NULL |
| 110 | }; | 132 | }; |
| 111 | 133 | ||
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> | 20 | void __init xttcpss_timer_init(void); |
| 21 | |||
| 22 | extern 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 | |||
| 22 | struct 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/zynq_soc.h b/arch/arm/mach-zynq/include/mach/zynq_soc.h index d0d3f8fb06dd..5ebbd8e6eeee 100644 --- a/arch/arm/mach-zynq/include/mach/zynq_soc.h +++ b/arch/arm/mach-zynq/include/mach/zynq_soc.h | |||
| @@ -15,34 +15,39 @@ | |||
| 15 | #ifndef __MACH_XILINX_SOC_H__ | 15 | #ifndef __MACH_XILINX_SOC_H__ |
| 16 | #define __MACH_XILINX_SOC_H__ | 16 | #define __MACH_XILINX_SOC_H__ |
| 17 | 17 | ||
| 18 | #include <asm/pgtable.h> | ||
| 19 | |||
| 18 | #define PERIPHERAL_CLOCK_RATE 2500000 | 20 | #define PERIPHERAL_CLOCK_RATE 2500000 |
| 19 | 21 | ||
| 20 | /* For now, all mappings are flat (physical = virtual) | 22 | /* Static peripheral mappings are mapped at the top of the vmalloc region. The |
| 23 | * early uart mapping causes intermediate problems/failure at certain | ||
| 24 | * addresses, including the very top of the vmalloc region. Map it at an | ||
| 25 | * address that is known to work. | ||
| 21 | */ | 26 | */ |
| 22 | #define UART0_PHYS 0xE0000000 | 27 | #define UART0_PHYS 0xE0000000 |
| 23 | #define UART0_VIRT UART0_PHYS | 28 | #define UART1_PHYS 0xE0001000 |
| 24 | 29 | #define UART_SIZE SZ_4K | |
| 25 | #define TTC0_PHYS 0xF8001000 | 30 | #define UART_VIRT 0xF0001000 |
| 26 | #define TTC0_VIRT TTC0_PHYS | 31 | |
| 27 | 32 | #define TTC0_PHYS 0xF8001000 | |
| 28 | #define PL310_L2CC_PHYS 0xF8F02000 | 33 | #define TTC0_SIZE SZ_4K |
| 29 | #define PL310_L2CC_VIRT PL310_L2CC_PHYS | 34 | #define TTC0_VIRT (VMALLOC_END - TTC0_SIZE) |
| 35 | |||
| 36 | #define SCU_PERIPH_PHYS 0xF8F00000 | ||
| 37 | #define SCU_PERIPH_SIZE SZ_8K | ||
| 38 | #define SCU_PERIPH_VIRT (TTC0_VIRT - SCU_PERIPH_SIZE) | ||
| 39 | |||
| 40 | #if IS_ENABLED(CONFIG_DEBUG_ZYNQ_UART1) | ||
| 41 | # define LL_UART_PADDR UART1_PHYS | ||
| 42 | #else | ||
| 43 | # define LL_UART_PADDR UART0_PHYS | ||
| 44 | #endif | ||
| 30 | 45 | ||
| 31 | #define SCU_PERIPH_PHYS 0xF8F00000 | 46 | #define LL_UART_VADDR UART_VIRT |
| 32 | #define SCU_PERIPH_VIRT SCU_PERIPH_PHYS | ||
| 33 | 47 | ||
| 34 | /* The following are intended for the devices that are mapped early */ | 48 | /* The following are intended for the devices that are mapped early */ |
| 35 | 49 | ||
| 36 | #define TTC0_BASE IOMEM(TTC0_VIRT) | 50 | #define TTC0_BASE IOMEM(TTC0_VIRT) |
| 37 | #define SCU_PERIPH_BASE IOMEM(SCU_PERIPH_VIRT) | 51 | #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 | 52 | ||
| 48 | #endif | 53 | #endif |
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c index c2c96cc7d6e7..9662306aa12f 100644 --- a/arch/arm/mach-zynq/timer.c +++ b/arch/arm/mach-zynq/timer.c | |||
| @@ -23,32 +23,15 @@ | |||
| 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> | 32 | #include <mach/zynq_soc.h> |
| 29 | #include "common.h" | 33 | #include "common.h" |
| 30 | 34 | ||
| 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 | /* | 35 | /* |
| 53 | * Timer Register Offset Definitions of Timer 1, Increment base address by 4 | 36 | * Timer Register Offset Definitions of Timer 1, Increment base address by 4 |
| 54 | * and use same offsets for Timer 2 | 37 | * and use same offsets for Timer 2 |
| @@ -65,9 +48,14 @@ | |||
| 65 | 48 | ||
| 66 | #define XTTCPSS_CNT_CNTRL_DISABLE_MASK 0x1 | 49 | #define XTTCPSS_CNT_CNTRL_DISABLE_MASK 0x1 |
| 67 | 50 | ||
| 68 | /* Setup the timers to use pre-scaling */ | 51 | /* Setup the timers to use pre-scaling, using a fixed value for now that will |
| 69 | 52 | * work across most input frequency, but it may need to be more dynamic | |
| 70 | #define TIMER_RATE (PERIPHERAL_CLOCK_RATE / 32) | 53 | */ |
| 54 | #define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */ | ||
| 55 | #define PRESCALE 2048 /* The exponent must match this */ | ||
| 56 | #define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1) | ||
| 57 | #define CLK_CNTRL_PRESCALE_EN 1 | ||
| 58 | #define CNT_CNTRL_RESET (1<<4) | ||
| 71 | 59 | ||
| 72 | /** | 60 | /** |
| 73 | * struct xttcpss_timer - This definition defines local timer structure | 61 | * struct xttcpss_timer - This definition defines local timer structure |
| @@ -75,11 +63,25 @@ | |||
| 75 | * @base_addr: Base address of timer | 63 | * @base_addr: Base address of timer |
| 76 | **/ | 64 | **/ |
| 77 | struct xttcpss_timer { | 65 | struct xttcpss_timer { |
| 78 | void __iomem *base_addr; | 66 | void __iomem *base_addr; |
| 79 | }; | 67 | }; |
| 80 | 68 | ||
| 81 | static struct xttcpss_timer timers[2]; | 69 | struct xttcpss_timer_clocksource { |
| 82 | static struct clock_event_device xttcpss_clockevent; | 70 | struct xttcpss_timer xttc; |
| 71 | struct clocksource cs; | ||
| 72 | }; | ||
| 73 | |||
| 74 | #define to_xttcpss_timer_clksrc(x) \ | ||
| 75 | container_of(x, struct xttcpss_timer_clocksource, cs) | ||
| 76 | |||
| 77 | struct xttcpss_timer_clockevent { | ||
| 78 | struct xttcpss_timer xttc; | ||
| 79 | struct clock_event_device ce; | ||
| 80 | struct clk *clk; | ||
| 81 | }; | ||
| 82 | |||
| 83 | #define to_xttcpss_timer_clkevent(x) \ | ||
| 84 | container_of(x, struct xttcpss_timer_clockevent, ce) | ||
| 83 | 85 | ||
| 84 | /** | 86 | /** |
| 85 | * xttcpss_set_interval - Set the timer interval value | 87 | * xttcpss_set_interval - Set the timer interval value |
| @@ -101,7 +103,7 @@ static void xttcpss_set_interval(struct xttcpss_timer *timer, | |||
| 101 | 103 | ||
| 102 | /* Reset the counter (0x10) so that it starts from 0, one-shot | 104 | /* Reset the counter (0x10) so that it starts from 0, one-shot |
| 103 | mode makes this needed for timing to be right. */ | 105 | mode makes this needed for timing to be right. */ |
| 104 | ctrl_reg |= 0x10; | 106 | ctrl_reg |= CNT_CNTRL_RESET; |
| 105 | ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK; | 107 | ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK; |
| 106 | __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); | 108 | __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); |
| 107 | } | 109 | } |
| @@ -116,90 +118,31 @@ static void xttcpss_set_interval(struct xttcpss_timer *timer, | |||
| 116 | **/ | 118 | **/ |
| 117 | static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id) | 119 | static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id) |
| 118 | { | 120 | { |
| 119 | struct clock_event_device *evt = &xttcpss_clockevent; | 121 | struct xttcpss_timer_clockevent *xttce = dev_id; |
| 120 | struct xttcpss_timer *timer = dev_id; | 122 | struct xttcpss_timer *timer = &xttce->xttc; |
| 121 | 123 | ||
| 122 | /* Acknowledge the interrupt and call event handler */ | 124 | /* Acknowledge the interrupt and call event handler */ |
| 123 | __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET), | 125 | __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET), |
| 124 | timer->base_addr + XTTCPSS_ISR_OFFSET); | 126 | timer->base_addr + XTTCPSS_ISR_OFFSET); |
| 125 | 127 | ||
| 126 | evt->event_handler(evt); | 128 | xttce->ce.event_handler(&xttce->ce); |
| 127 | 129 | ||
| 128 | return IRQ_HANDLED; | 130 | return IRQ_HANDLED; |
| 129 | } | 131 | } |
| 130 | 132 | ||
| 131 | static struct irqaction event_timer_irq = { | ||
| 132 | .name = "xttcpss clockevent", | ||
| 133 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
| 134 | .handler = xttcpss_clock_event_interrupt, | ||
| 135 | }; | ||
| 136 | |||
| 137 | /** | 133 | /** |
| 138 | * xttcpss_timer_hardware_init - Initialize the timer hardware | 134 | * __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 | **/ | ||
| 143 | static 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 | * | 135 | * |
| 180 | * returns: Current timer counter register value | 136 | * returns: Current timer counter register value |
| 181 | **/ | 137 | **/ |
| 182 | static cycle_t __raw_readl_cycles(struct clocksource *cs) | 138 | static cycle_t __xttc_clocksource_read(struct clocksource *cs) |
| 183 | { | 139 | { |
| 184 | struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKSOURCE]; | 140 | struct xttcpss_timer *timer = &to_xttcpss_timer_clksrc(cs)->xttc; |
| 185 | 141 | ||
| 186 | return (cycle_t)__raw_readl(timer->base_addr + | 142 | return (cycle_t)__raw_readl(timer->base_addr + |
| 187 | XTTCPSS_COUNT_VAL_OFFSET); | 143 | XTTCPSS_COUNT_VAL_OFFSET); |
| 188 | } | 144 | } |
| 189 | 145 | ||
| 190 | |||
| 191 | /* | ||
| 192 | * Instantiate and initialize the clock source structure | ||
| 193 | */ | ||
| 194 | static 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 | /** | 146 | /** |
| 204 | * xttcpss_set_next_event - Sets the time interval for next event | 147 | * xttcpss_set_next_event - Sets the time interval for next event |
| 205 | * | 148 | * |
| @@ -211,7 +154,8 @@ static struct clocksource clocksource_xttcpss = { | |||
| 211 | static int xttcpss_set_next_event(unsigned long cycles, | 154 | static int xttcpss_set_next_event(unsigned long cycles, |
| 212 | struct clock_event_device *evt) | 155 | struct clock_event_device *evt) |
| 213 | { | 156 | { |
| 214 | struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT]; | 157 | struct xttcpss_timer_clockevent *xttce = to_xttcpss_timer_clkevent(evt); |
| 158 | struct xttcpss_timer *timer = &xttce->xttc; | ||
| 215 | 159 | ||
| 216 | xttcpss_set_interval(timer, cycles); | 160 | xttcpss_set_interval(timer, cycles); |
| 217 | return 0; | 161 | return 0; |
| @@ -226,12 +170,15 @@ static int xttcpss_set_next_event(unsigned long cycles, | |||
| 226 | static void xttcpss_set_mode(enum clock_event_mode mode, | 170 | static void xttcpss_set_mode(enum clock_event_mode mode, |
| 227 | struct clock_event_device *evt) | 171 | struct clock_event_device *evt) |
| 228 | { | 172 | { |
| 229 | struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT]; | 173 | struct xttcpss_timer_clockevent *xttce = to_xttcpss_timer_clkevent(evt); |
| 174 | struct xttcpss_timer *timer = &xttce->xttc; | ||
| 230 | u32 ctrl_reg; | 175 | u32 ctrl_reg; |
| 231 | 176 | ||
| 232 | switch (mode) { | 177 | switch (mode) { |
| 233 | case CLOCK_EVT_MODE_PERIODIC: | 178 | case CLOCK_EVT_MODE_PERIODIC: |
| 234 | xttcpss_set_interval(timer, TIMER_RATE / HZ); | 179 | xttcpss_set_interval(timer, |
| 180 | DIV_ROUND_CLOSEST(clk_get_rate(xttce->clk), | ||
| 181 | PRESCALE * HZ)); | ||
| 235 | break; | 182 | break; |
| 236 | case CLOCK_EVT_MODE_ONESHOT: | 183 | case CLOCK_EVT_MODE_ONESHOT: |
| 237 | case CLOCK_EVT_MODE_UNUSED: | 184 | case CLOCK_EVT_MODE_UNUSED: |
| @@ -252,15 +199,106 @@ static void xttcpss_set_mode(enum clock_event_mode mode, | |||
| 252 | } | 199 | } |
| 253 | } | 200 | } |
| 254 | 201 | ||
| 255 | /* | 202 | static void __init zynq_ttc_setup_clocksource(struct device_node *np, |
| 256 | * Instantiate and initialize the clock event structure | 203 | void __iomem *base) |
| 257 | */ | 204 | { |
| 258 | static struct clock_event_device xttcpss_clockevent = { | 205 | struct xttcpss_timer_clocksource *ttccs; |
| 259 | .name = "xttcpss_timer2", | 206 | struct clk *clk; |
| 260 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 207 | int err; |
| 261 | .set_next_event = xttcpss_set_next_event, | 208 | u32 reg; |
| 262 | .set_mode = xttcpss_set_mode, | 209 | |
| 263 | .rating = 200, | 210 | ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); |
| 211 | if (WARN_ON(!ttccs)) | ||
| 212 | return; | ||
| 213 | |||
| 214 | err = of_property_read_u32(np, "reg", ®); | ||
| 215 | if (WARN_ON(err)) | ||
| 216 | return; | ||
| 217 | |||
| 218 | clk = of_clk_get_by_name(np, "cpu_1x"); | ||
| 219 | if (WARN_ON(IS_ERR(clk))) | ||
| 220 | return; | ||
| 221 | |||
| 222 | err = clk_prepare_enable(clk); | ||
| 223 | if (WARN_ON(err)) | ||
| 224 | return; | ||
| 225 | |||
| 226 | ttccs->xttc.base_addr = base + reg * 4; | ||
| 227 | |||
| 228 | ttccs->cs.name = np->name; | ||
| 229 | ttccs->cs.rating = 200; | ||
| 230 | ttccs->cs.read = __xttc_clocksource_read; | ||
| 231 | ttccs->cs.mask = CLOCKSOURCE_MASK(16); | ||
| 232 | ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
| 233 | |||
| 234 | __raw_writel(0x0, ttccs->xttc.base_addr + XTTCPSS_IER_OFFSET); | ||
| 235 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
| 236 | ttccs->xttc.base_addr + XTTCPSS_CLK_CNTRL_OFFSET); | ||
| 237 | __raw_writel(CNT_CNTRL_RESET, | ||
| 238 | ttccs->xttc.base_addr + XTTCPSS_CNT_CNTRL_OFFSET); | ||
| 239 | |||
| 240 | err = clocksource_register_hz(&ttccs->cs, clk_get_rate(clk) / PRESCALE); | ||
| 241 | if (WARN_ON(err)) | ||
| 242 | return; | ||
| 243 | } | ||
| 244 | |||
| 245 | static void __init zynq_ttc_setup_clockevent(struct device_node *np, | ||
| 246 | void __iomem *base) | ||
| 247 | { | ||
| 248 | struct xttcpss_timer_clockevent *ttcce; | ||
| 249 | int err, irq; | ||
| 250 | u32 reg; | ||
| 251 | |||
| 252 | ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); | ||
| 253 | if (WARN_ON(!ttcce)) | ||
| 254 | return; | ||
| 255 | |||
| 256 | err = of_property_read_u32(np, "reg", ®); | ||
| 257 | if (WARN_ON(err)) | ||
| 258 | return; | ||
| 259 | |||
| 260 | ttcce->xttc.base_addr = base + reg * 4; | ||
| 261 | |||
| 262 | ttcce->clk = of_clk_get_by_name(np, "cpu_1x"); | ||
| 263 | if (WARN_ON(IS_ERR(ttcce->clk))) | ||
| 264 | return; | ||
| 265 | |||
| 266 | err = clk_prepare_enable(ttcce->clk); | ||
| 267 | if (WARN_ON(err)) | ||
| 268 | return; | ||
| 269 | |||
| 270 | irq = irq_of_parse_and_map(np, 0); | ||
| 271 | if (WARN_ON(!irq)) | ||
| 272 | return; | ||
| 273 | |||
| 274 | ttcce->ce.name = np->name; | ||
| 275 | ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
| 276 | ttcce->ce.set_next_event = xttcpss_set_next_event; | ||
| 277 | ttcce->ce.set_mode = xttcpss_set_mode; | ||
| 278 | ttcce->ce.rating = 200; | ||
| 279 | ttcce->ce.irq = irq; | ||
| 280 | |||
| 281 | __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPSS_CNT_CNTRL_OFFSET); | ||
| 282 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
| 283 | ttcce->xttc.base_addr + XTTCPSS_CLK_CNTRL_OFFSET); | ||
| 284 | __raw_writel(0x1, ttcce->xttc.base_addr + XTTCPSS_IER_OFFSET); | ||
| 285 | |||
| 286 | err = request_irq(irq, xttcpss_clock_event_interrupt, IRQF_TIMER, | ||
| 287 | np->name, ttcce); | ||
| 288 | if (WARN_ON(err)) | ||
| 289 | return; | ||
| 290 | |||
| 291 | clockevents_config_and_register(&ttcce->ce, | ||
| 292 | clk_get_rate(ttcce->clk) / PRESCALE, | ||
| 293 | 1, 0xfffe); | ||
| 294 | } | ||
| 295 | |||
| 296 | static const __initconst struct of_device_id zynq_ttc_match[] = { | ||
| 297 | { .compatible = "xlnx,ttc-counter-clocksource", | ||
| 298 | .data = zynq_ttc_setup_clocksource, }, | ||
| 299 | { .compatible = "xlnx,ttc-counter-clockevent", | ||
| 300 | .data = zynq_ttc_setup_clockevent, }, | ||
| 301 | {} | ||
| 264 | }; | 302 | }; |
| 265 | 303 | ||
| 266 | /** | 304 | /** |
| @@ -269,30 +307,27 @@ static struct clock_event_device xttcpss_clockevent = { | |||
| 269 | * Initializes the timer hardware and register the clock source and clock event | 307 | * Initializes the timer hardware and register the clock source and clock event |
| 270 | * timers with Linux kernal timer framework | 308 | * timers with Linux kernal timer framework |
| 271 | **/ | 309 | **/ |
| 272 | static void __init xttcpss_timer_init(void) | 310 | void __init xttcpss_timer_init(void) |
| 273 | { | 311 | { |
| 274 | xttcpss_timer_hardware_init(); | 312 | struct device_node *np; |
| 275 | clocksource_register_hz(&clocksource_xttcpss, TIMER_RATE); | 313 | |
| 276 | 314 | for_each_compatible_node(np, NULL, "xlnx,ttc") { | |
| 277 | /* Calculate the parameters to allow the clockevent to operate using | 315 | struct device_node *np_chld; |
| 278 | integer math | 316 | void __iomem *base; |
| 279 | */ | 317 | |
| 280 | clockevents_calc_mult_shift(&xttcpss_clockevent, TIMER_RATE, 4); | 318 | base = of_iomap(np, 0); |
| 281 | 319 | if (WARN_ON(!base)) | |
| 282 | xttcpss_clockevent.max_delta_ns = | 320 | return; |
| 283 | clockevent_delta2ns(0xfffe, &xttcpss_clockevent); | 321 | |
| 284 | xttcpss_clockevent.min_delta_ns = | 322 | for_each_available_child_of_node(np, np_chld) { |
| 285 | clockevent_delta2ns(1, &xttcpss_clockevent); | 323 | int (*cb)(struct device_node *np, void __iomem *base); |
| 286 | 324 | const struct of_device_id *match; | |
| 287 | /* Indicate that clock event is on 1st CPU as SMP boot needs it */ | 325 | |
| 288 | 326 | match = of_match_node(zynq_ttc_match, np_chld); | |
| 289 | xttcpss_clockevent.cpumask = cpumask_of(0); | 327 | if (match) { |
| 290 | clockevents_register_device(&xttcpss_clockevent); | 328 | cb = match->data; |
| 329 | cb(np_chld, base); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | } | ||
| 291 | } | 333 | } |
| 292 | |||
| 293 | /* | ||
| 294 | * Instantiate and initialize the system timer structure | ||
| 295 | */ | ||
| 296 | struct 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 | |||
| 19 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o | 19 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o |
| 20 | obj-$(CONFIG_ARCH_U8500) += ux500/ | 20 | obj-$(CONFIG_ARCH_U8500) += ux500/ |
| 21 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o | 21 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o |
| 22 | obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o | ||
| 22 | 23 | ||
| 23 | # Chip specific | 24 | # Chip specific |
| 24 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o | 25 | obj-$(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 | |||
| 24 | static void __iomem *slcr_base; | ||
| 25 | |||
| 26 | struct 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 | |||
| 36 | static 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 | |||
| 43 | static const struct clk_ops zynq_pll_clk_ops = { | ||
| 44 | .recalc_rate = zynq_pll_recalc_rate, | ||
| 45 | }; | ||
| 46 | |||
| 47 | static 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 | |||
| 85 | struct 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 | |||
| 95 | static 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 | |||
| 101 | static 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 | |||
| 108 | static 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 | |||
| 114 | static const struct clk_ops zynq_periph_clk_ops = { | ||
| 115 | .recalc_rate = zynq_periph_recalc_rate, | ||
| 116 | .get_parent = zynq_periph_get_parent, | ||
| 117 | }; | ||
| 118 | |||
| 119 | static 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", ®); | ||
| 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 | |||
| 195 | struct 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 | |||
| 205 | static 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 | |||
| 211 | static 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 | |||
| 217 | static 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 | |||
| 224 | static 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 | |||
| 229 | struct 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 | |||
| 244 | static 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 | |||
| 272 | static const struct clk_ops zynq_cpu_subclk_ops = { | ||
| 273 | .recalc_rate = zynq_cpu_subclk_recalc_rate, | ||
| 274 | }; | ||
| 275 | |||
| 276 | static 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 | |||
| 308 | err_clk_register: | ||
| 309 | kfree(subclk); | ||
| 310 | err_subclk_alloc: | ||
| 311 | err_read_output_name: | ||
| 312 | return ERR_PTR(-EINVAL); | ||
| 313 | } | ||
| 314 | |||
| 315 | static 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 | |||
| 370 | static 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 | |||
| 379 | void __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 | |||
| 22 | void __init xilinx_zynq_clocks_init(void __iomem *slcr); | ||
| 23 | |||
| 24 | #endif | ||
