diff options
author | Arnd Bergmann <arnd@arndb.de> | 2014-03-27 02:10:57 +0100 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2014-03-27 02:19:41 +0100 |
commit | 32adc19d4b2f2d9a26fbbd0c1744d5b313106d6a (patch) | |
tree | 5e034ff3b39b6495a4d1d2cc3839b985b2e711d0 | |
parent | 22673b71689a65a89335d0f3e42ce952efb3e7e1 (diff) | |
parent | 1a259251f3638b04c1dbe07220958af9572c95bb (diff) | |
download | linux-32adc19d4b2f2d9a26fbbd0c1744d5b313106d6a.tar.bz2 |
Merge tag 'zynq-cleanup-for-3.15-v2' of git://git.xilinx.com/linux-xlnx into next/cleanup2
Merge "arm: Xilinx Zynq cleanup patches for v3.15" from Michal Simek:
- Redesign SLCR initialization to enable
driver developing which targets SLCR space
* tag 'zynq-cleanup-for-3.15-v2' of git://git.xilinx.com/linux-xlnx:
ARM: zynq: Add waituart implementation
ARM: zynq: Move of_clk_init from clock driver
ARM: zynq: Introduce zynq_slcr_unlock()
ARM: zynq: Add and use zynq_slcr_read/write() helper functions
ARM: zynq: Make zynq_slcr_base static
ARM: zynq: Map I/O memory on clkc init
ARM: zynq: Hang iomapped slcr address on device_node
ARM: zynq: Split slcr in two parts
ARM: zynq: Move clock_init from slcr to common
arm: dt: zynq: Add fclk-enable property to clkc node
[Arnd: remove SOC_BUS support from pull request]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | Documentation/devicetree/bindings/clock/zynq-7000.txt | 4 | ||||
-rw-r--r-- | arch/arm/boot/dts/zynq-7000.dtsi | 43 | ||||
-rw-r--r-- | arch/arm/include/debug/zynq.S | 3 | ||||
-rw-r--r-- | arch/arm/mach-zynq/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-zynq/common.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-zynq/common.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-zynq/slcr.c | 104 | ||||
-rw-r--r-- | drivers/clk/zynq/clkc.c | 89 | ||||
-rw-r--r-- | include/linux/clk/zynq.h | 2 |
9 files changed, 188 insertions, 68 deletions
diff --git a/Documentation/devicetree/bindings/clock/zynq-7000.txt b/Documentation/devicetree/bindings/clock/zynq-7000.txt index 17b4a94916d6..d93746cf2975 100644 --- a/Documentation/devicetree/bindings/clock/zynq-7000.txt +++ b/Documentation/devicetree/bindings/clock/zynq-7000.txt @@ -14,6 +14,7 @@ for all clock consumers of PS clocks. Required properties: - #clock-cells : Must be 1 - compatible : "xlnx,ps7-clkc" + - reg : SLCR offset and size taken via syscon < 0x100 0x100 > - ps-clk-frequency : Frequency of the oscillator providing ps_clk in HZ (usually 33 MHz oscillators are used for Zynq platforms) - clock-output-names : List of strings used to name the clock outputs. Shall be @@ -87,10 +88,11 @@ Clock outputs: 47: dbg_apb Example: - clkc: clkc { + clkc: clkc@100 { #clock-cells = <1>; compatible = "xlnx,ps7-clkc"; ps-clk-frequency = <33333333>; + reg = <0x100 0x100>; clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0", "gem1", diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 8b67b19392ec..602e12eedb01 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -123,29 +123,28 @@ } ; slcr: slcr@f8000000 { - compatible = "xlnx,zynq-slcr"; + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,zynq-slcr", "syscon"; reg = <0xF8000000 0x1000>; - - clocks { - #address-cells = <1>; - #size-cells = <0>; - - clkc: clkc { - #clock-cells = <1>; - compatible = "xlnx,ps7-clkc"; - ps-clk-frequency = <33333333>; - clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", - "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", - "dci", "lqspi", "smc", "pcap", "gem0", "gem1", - "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", - "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", - "dma", "usb0_aper", "usb1_aper", "gem0_aper", - "gem1_aper", "sdio0_aper", "sdio1_aper", - "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", - "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", - "gpio_aper", "lqspi_aper", "smc_aper", "swdt", - "dbg_trc", "dbg_apb"; - }; + ranges; + clkc: clkc@100 { + #clock-cells = <1>; + compatible = "xlnx,ps7-clkc"; + ps-clk-frequency = <33333333>; + fclk-enable = <0>; + clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", + "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", + "dci", "lqspi", "smc", "pcap", "gem0", "gem1", + "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", + "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", + "dma", "usb0_aper", "usb1_aper", "gem0_aper", + "gem1_aper", "sdio0_aper", "sdio1_aper", + "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", + "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", + "gpio_aper", "lqspi_aper", "smc_aper", "swdt", + "dbg_trc", "dbg_apb"; + reg = <0x100 0x100>; }; }; diff --git a/arch/arm/include/debug/zynq.S b/arch/arm/include/debug/zynq.S index f9aa9740a73f..0b762fafa758 100644 --- a/arch/arm/include/debug/zynq.S +++ b/arch/arm/include/debug/zynq.S @@ -42,6 +42,9 @@ .endm .macro waituart,rd,rx +1001: ldr \rd, [\rx, #UART_SR_OFFSET] + tst \rd, #UART_SR_TXEMPTY + beq 1001b .endm .macro busyuart,rd,rx diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index 6b04260aa142..323e5053cb9f 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -14,5 +14,6 @@ config ARCH_ZYNQ select SPARSE_IRQ select CADENCE_TTC_TIMER select ARM_GLOBAL_TIMER + select MFD_SYSCON help 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 8c09a8393fb6..dca60d5ba756 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -19,6 +19,7 @@ #include <linux/cpumask.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/clk/zynq.h> #include <linux/clocksource.h> #include <linux/of_address.h> @@ -72,11 +73,16 @@ static void __init zynq_init_machine(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); platform_device_register(&zynq_cpuidle_device); + + zynq_slcr_init(); } static void __init zynq_timer_init(void) { - zynq_slcr_init(); + zynq_early_slcr_init(); + + zynq_clock_init(); + of_clk_init(NULL); clocksource_of_init(); } diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index c22c92cea8cb..b097844d3175 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -20,6 +20,7 @@ void zynq_secondary_startup(void); extern int zynq_slcr_init(void); +extern int zynq_early_slcr_init(void); extern void zynq_slcr_system_reset(void); extern void zynq_slcr_cpu_stop(int cpu); extern void zynq_slcr_cpu_start(int cpu); @@ -33,7 +34,6 @@ extern int zynq_cpun_start(u32 address, int cpu); extern struct smp_operations zynq_smp_ops __initdata; #endif -extern void __iomem *zynq_slcr_base; extern void __iomem *zynq_scu_base; /* Hotplug */ diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c index 1836d5a34606..a37d49a6e657 100644 --- a/arch/arm/mach-zynq/slcr.c +++ b/arch/arm/mach-zynq/slcr.c @@ -15,7 +15,9 @@ */ #include <linux/io.h> +#include <linux/mfd/syscon.h> #include <linux/of_address.h> +#include <linux/regmap.h> #include <linux/clk/zynq.h> #include "common.h" @@ -29,7 +31,56 @@ #define SLCR_A9_CPU_CLKSTOP 0x10 #define SLCR_A9_CPU_RST 0x1 -void __iomem *zynq_slcr_base; +static void __iomem *zynq_slcr_base; +static struct regmap *zynq_slcr_regmap; + +/** + * zynq_slcr_write - Write to a register in SLCR block + * + * @val: Value to write to the register + * @offset: Register offset in SLCR block + * + * Return: a negative value on error, 0 on success + */ +static int zynq_slcr_write(u32 val, u32 offset) +{ + if (!zynq_slcr_regmap) { + writel(val, zynq_slcr_base + offset); + return 0; + } + + return regmap_write(zynq_slcr_regmap, offset, val); +} + +/** + * zynq_slcr_read - Read a register in SLCR block + * + * @val: Pointer to value to be read from SLCR + * @offset: Register offset in SLCR block + * + * Return: a negative value on error, 0 on success + */ +static int zynq_slcr_read(u32 *val, u32 offset) +{ + if (zynq_slcr_regmap) + return regmap_read(zynq_slcr_regmap, offset, val); + + *val = readl(zynq_slcr_base + offset); + + return 0; +} + +/** + * zynq_slcr_unlock - Unlock SLCR registers + * + * Return: a negative value on error, 0 on success + */ +static inline int zynq_slcr_unlock(void) +{ + zynq_slcr_write(SLCR_UNLOCK_MAGIC, SLCR_UNLOCK_OFFSET); + + return 0; +} /** * zynq_slcr_system_reset - Reset the entire system. @@ -43,16 +94,16 @@ void zynq_slcr_system_reset(void) * Note that this seems to require raw i/o * functions or there's a lockup? */ - writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK_OFFSET); + zynq_slcr_unlock(); /* * Clear 0x0F000000 bits of reboot status register to workaround * the FSBL not loading the bitstream after soft-reboot * This is a temporary solution until we know more. */ - reboot = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET); - writel(reboot & 0xF0FFFFFF, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET); - writel(1, zynq_slcr_base + SLCR_PS_RST_CTRL_OFFSET); + zynq_slcr_read(&reboot, SLCR_REBOOT_STATUS_OFFSET); + zynq_slcr_write(reboot & 0xF0FFFFFF, SLCR_REBOOT_STATUS_OFFSET); + zynq_slcr_write(1, SLCR_PS_RST_CTRL_OFFSET); } /** @@ -61,11 +112,13 @@ void zynq_slcr_system_reset(void) */ void zynq_slcr_cpu_start(int cpu) { - u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + u32 reg; + + zynq_slcr_read(®, SLCR_A9_CPU_RST_CTRL_OFFSET); reg &= ~(SLCR_A9_CPU_RST << cpu); - writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu); - writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); } /** @@ -74,19 +127,40 @@ void zynq_slcr_cpu_start(int cpu) */ void zynq_slcr_cpu_stop(int cpu) { - u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + u32 reg; + + zynq_slcr_read(®, SLCR_A9_CPU_RST_CTRL_OFFSET); reg |= (SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu; - writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); + zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); } /** - * zynq_slcr_init - * Returns 0 on success, negative errno otherwise. + * zynq_slcr_init - Regular slcr driver init + * + * Return: 0 on success, negative errno otherwise. * * Called early during boot from platform code to remap SLCR area. */ int __init zynq_slcr_init(void) { + zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr"); + if (IS_ERR(zynq_slcr_regmap)) { + pr_err("%s: failed to find zynq-slcr\n", __func__); + return -ENODEV; + } + + return 0; +} + +/** + * zynq_early_slcr_init - Early slcr init function + * + * Return: 0 on success, negative errno otherwise. + * + * Called very early during boot from platform code to unlock SLCR. + */ +int __init zynq_early_slcr_init(void) +{ struct device_node *np; np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr"); @@ -101,13 +175,13 @@ int __init zynq_slcr_init(void) BUG(); } + np->data = (__force void *)zynq_slcr_base; + /* unlock the SLCR so that registers can be changed */ - writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK_OFFSET); + zynq_slcr_unlock(); pr_info("%s mapped to %p\n", np->name, zynq_slcr_base); - zynq_clock_init(zynq_slcr_base); - of_node_put(np); return 0; diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 09dd0173ea0a..c812b93a52b2 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -21,34 +21,35 @@ #include <linux/clk/zynq.h> #include <linux/clk-provider.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/io.h> -static void __iomem *zynq_slcr_base_priv; - -#define SLCR_ARMPLL_CTRL (zynq_slcr_base_priv + 0x100) -#define SLCR_DDRPLL_CTRL (zynq_slcr_base_priv + 0x104) -#define SLCR_IOPLL_CTRL (zynq_slcr_base_priv + 0x108) -#define SLCR_PLL_STATUS (zynq_slcr_base_priv + 0x10c) -#define SLCR_ARM_CLK_CTRL (zynq_slcr_base_priv + 0x120) -#define SLCR_DDR_CLK_CTRL (zynq_slcr_base_priv + 0x124) -#define SLCR_DCI_CLK_CTRL (zynq_slcr_base_priv + 0x128) -#define SLCR_APER_CLK_CTRL (zynq_slcr_base_priv + 0x12c) -#define SLCR_GEM0_CLK_CTRL (zynq_slcr_base_priv + 0x140) -#define SLCR_GEM1_CLK_CTRL (zynq_slcr_base_priv + 0x144) -#define SLCR_SMC_CLK_CTRL (zynq_slcr_base_priv + 0x148) -#define SLCR_LQSPI_CLK_CTRL (zynq_slcr_base_priv + 0x14c) -#define SLCR_SDIO_CLK_CTRL (zynq_slcr_base_priv + 0x150) -#define SLCR_UART_CLK_CTRL (zynq_slcr_base_priv + 0x154) -#define SLCR_SPI_CLK_CTRL (zynq_slcr_base_priv + 0x158) -#define SLCR_CAN_CLK_CTRL (zynq_slcr_base_priv + 0x15c) -#define SLCR_CAN_MIOCLK_CTRL (zynq_slcr_base_priv + 0x160) -#define SLCR_DBG_CLK_CTRL (zynq_slcr_base_priv + 0x164) -#define SLCR_PCAP_CLK_CTRL (zynq_slcr_base_priv + 0x168) -#define SLCR_FPGA0_CLK_CTRL (zynq_slcr_base_priv + 0x170) -#define SLCR_621_TRUE (zynq_slcr_base_priv + 0x1c4) -#define SLCR_SWDT_CLK_SEL (zynq_slcr_base_priv + 0x304) +static void __iomem *zynq_clkc_base; + +#define SLCR_ARMPLL_CTRL (zynq_clkc_base + 0x00) +#define SLCR_DDRPLL_CTRL (zynq_clkc_base + 0x04) +#define SLCR_IOPLL_CTRL (zynq_clkc_base + 0x08) +#define SLCR_PLL_STATUS (zynq_clkc_base + 0x0c) +#define SLCR_ARM_CLK_CTRL (zynq_clkc_base + 0x20) +#define SLCR_DDR_CLK_CTRL (zynq_clkc_base + 0x24) +#define SLCR_DCI_CLK_CTRL (zynq_clkc_base + 0x28) +#define SLCR_APER_CLK_CTRL (zynq_clkc_base + 0x2c) +#define SLCR_GEM0_CLK_CTRL (zynq_clkc_base + 0x40) +#define SLCR_GEM1_CLK_CTRL (zynq_clkc_base + 0x44) +#define SLCR_SMC_CLK_CTRL (zynq_clkc_base + 0x48) +#define SLCR_LQSPI_CLK_CTRL (zynq_clkc_base + 0x4c) +#define SLCR_SDIO_CLK_CTRL (zynq_clkc_base + 0x50) +#define SLCR_UART_CLK_CTRL (zynq_clkc_base + 0x54) +#define SLCR_SPI_CLK_CTRL (zynq_clkc_base + 0x58) +#define SLCR_CAN_CLK_CTRL (zynq_clkc_base + 0x5c) +#define SLCR_CAN_MIOCLK_CTRL (zynq_clkc_base + 0x60) +#define SLCR_DBG_CLK_CTRL (zynq_clkc_base + 0x64) +#define SLCR_PCAP_CLK_CTRL (zynq_clkc_base + 0x68) +#define SLCR_FPGA0_CLK_CTRL (zynq_clkc_base + 0x70) +#define SLCR_621_TRUE (zynq_clkc_base + 0xc4) +#define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204) #define NUM_MIO_PINS 54 @@ -569,8 +570,42 @@ static void __init zynq_clk_setup(struct device_node *np) CLK_OF_DECLARE(zynq_clkc, "xlnx,ps7-clkc", zynq_clk_setup); -void __init zynq_clock_init(void __iomem *slcr_base) +void __init zynq_clock_init(void) { - zynq_slcr_base_priv = slcr_base; - of_clk_init(NULL); + struct device_node *np; + struct device_node *slcr; + struct resource res; + + np = of_find_compatible_node(NULL, NULL, "xlnx,ps7-clkc"); + if (!np) { + pr_err("%s: clkc node not found\n", __func__); + goto np_err; + } + + if (of_address_to_resource(np, 0, &res)) { + pr_err("%s: failed to get resource\n", np->name); + goto np_err; + } + + slcr = of_get_parent(np); + + if (slcr->data) { + zynq_clkc_base = (__force void __iomem *)slcr->data + res.start; + } else { + pr_err("%s: Unable to get I/O memory\n", np->name); + of_node_put(slcr); + goto np_err; + } + + pr_info("%s: clkc starts at %p\n", __func__, zynq_clkc_base); + + of_node_put(slcr); + of_node_put(np); + + return; + +np_err: + of_node_put(np); + BUG(); + return; } diff --git a/include/linux/clk/zynq.h b/include/linux/clk/zynq.h index e062d317ccce..7a5633b71533 100644 --- a/include/linux/clk/zynq.h +++ b/include/linux/clk/zynq.h @@ -22,7 +22,7 @@ #include <linux/spinlock.h> -void zynq_clock_init(void __iomem *slcr); +void zynq_clock_init(void); struct clk *clk_register_zynq_pll(const char *name, const char *parent, void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, |