Commit 32adc19d authored by Arnd Bergmann's avatar Arnd Bergmann

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: default avatarArnd Bergmann <arnd@arndb.de>
parents 22673b71 1a259251
...@@ -14,6 +14,7 @@ for all clock consumers of PS clocks. ...@@ -14,6 +14,7 @@ for all clock consumers of PS clocks.
Required properties: Required properties:
- #clock-cells : Must be 1 - #clock-cells : Must be 1
- compatible : "xlnx,ps7-clkc" - 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 - ps-clk-frequency : Frequency of the oscillator providing ps_clk in HZ
(usually 33 MHz oscillators are used for Zynq platforms) (usually 33 MHz oscillators are used for Zynq platforms)
- clock-output-names : List of strings used to name the clock outputs. Shall be - clock-output-names : List of strings used to name the clock outputs. Shall be
...@@ -87,10 +88,11 @@ Clock outputs: ...@@ -87,10 +88,11 @@ Clock outputs:
47: dbg_apb 47: dbg_apb
Example: Example:
clkc: clkc { clkc: clkc@100 {
#clock-cells = <1>; #clock-cells = <1>;
compatible = "xlnx,ps7-clkc"; compatible = "xlnx,ps7-clkc";
ps-clk-frequency = <33333333>; ps-clk-frequency = <33333333>;
reg = <0x100 0x100>;
clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
"dci", "lqspi", "smc", "pcap", "gem0", "gem1", "dci", "lqspi", "smc", "pcap", "gem0", "gem1",
......
...@@ -123,29 +123,28 @@ sdhci1: ps7-sdhci@e0101000 { ...@@ -123,29 +123,28 @@ sdhci1: ps7-sdhci@e0101000 {
} ; } ;
slcr: slcr@f8000000 { slcr: slcr@f8000000 {
compatible = "xlnx,zynq-slcr"; #address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,zynq-slcr", "syscon";
reg = <0xF8000000 0x1000>; reg = <0xF8000000 0x1000>;
ranges;
clocks { clkc: clkc@100 {
#address-cells = <1>; #clock-cells = <1>;
#size-cells = <0>; compatible = "xlnx,ps7-clkc";
ps-clk-frequency = <33333333>;
clkc: clkc { fclk-enable = <0>;
#clock-cells = <1>; clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
compatible = "xlnx,ps7-clkc"; "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
ps-clk-frequency = <33333333>; "dci", "lqspi", "smc", "pcap", "gem0", "gem1",
clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
"dci", "lqspi", "smc", "pcap", "gem0", "gem1", "dma", "usb0_aper", "usb1_aper", "gem0_aper",
"fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", "gem1_aper", "sdio0_aper", "sdio1_aper",
"sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", "spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
"dma", "usb0_aper", "usb1_aper", "gem0_aper", "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
"gem1_aper", "sdio0_aper", "sdio1_aper", "gpio_aper", "lqspi_aper", "smc_aper", "swdt",
"spi0_aper", "spi1_aper", "can0_aper", "can1_aper", "dbg_trc", "dbg_apb";
"i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", reg = <0x100 0x100>;
"gpio_aper", "lqspi_aper", "smc_aper", "swdt",
"dbg_trc", "dbg_apb";
};
}; };
}; };
......
...@@ -42,6 +42,9 @@ ...@@ -42,6 +42,9 @@
.endm .endm
.macro waituart,rd,rx .macro waituart,rd,rx
1001: ldr \rd, [\rx, #UART_SR_OFFSET]
tst \rd, #UART_SR_TXEMPTY
beq 1001b
.endm .endm
.macro busyuart,rd,rx .macro busyuart,rd,rx
......
...@@ -14,5 +14,6 @@ config ARCH_ZYNQ ...@@ -14,5 +14,6 @@ config ARCH_ZYNQ
select SPARSE_IRQ select SPARSE_IRQ
select CADENCE_TTC_TIMER select CADENCE_TTC_TIMER
select ARM_GLOBAL_TIMER select ARM_GLOBAL_TIMER
select MFD_SYSCON
help help
Support for Xilinx Zynq ARM Cortex A9 Platform Support for Xilinx Zynq ARM Cortex A9 Platform
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/zynq.h> #include <linux/clk/zynq.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -72,11 +73,16 @@ static void __init zynq_init_machine(void) ...@@ -72,11 +73,16 @@ static void __init zynq_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register(&zynq_cpuidle_device); platform_device_register(&zynq_cpuidle_device);
zynq_slcr_init();
} }
static void __init zynq_timer_init(void) static void __init zynq_timer_init(void)
{ {
zynq_slcr_init(); zynq_early_slcr_init();
zynq_clock_init();
of_clk_init(NULL);
clocksource_of_init(); clocksource_of_init();
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
void zynq_secondary_startup(void); void zynq_secondary_startup(void);
extern int zynq_slcr_init(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_system_reset(void);
extern void zynq_slcr_cpu_stop(int cpu); extern void zynq_slcr_cpu_stop(int cpu);
extern void zynq_slcr_cpu_start(int cpu); extern void zynq_slcr_cpu_start(int cpu);
...@@ -33,7 +34,6 @@ extern int zynq_cpun_start(u32 address, int cpu); ...@@ -33,7 +34,6 @@ extern int zynq_cpun_start(u32 address, int cpu);
extern struct smp_operations zynq_smp_ops __initdata; extern struct smp_operations zynq_smp_ops __initdata;
#endif #endif
extern void __iomem *zynq_slcr_base;
extern void __iomem *zynq_scu_base; extern void __iomem *zynq_scu_base;
/* Hotplug */ /* Hotplug */
......
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
*/ */
#include <linux/io.h> #include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/clk/zynq.h> #include <linux/clk/zynq.h>
#include "common.h" #include "common.h"
...@@ -29,7 +31,56 @@ ...@@ -29,7 +31,56 @@
#define SLCR_A9_CPU_CLKSTOP 0x10 #define SLCR_A9_CPU_CLKSTOP 0x10
#define SLCR_A9_CPU_RST 0x1 #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. * zynq_slcr_system_reset - Reset the entire system.
...@@ -43,16 +94,16 @@ void zynq_slcr_system_reset(void) ...@@ -43,16 +94,16 @@ void zynq_slcr_system_reset(void)
* Note that this seems to require raw i/o * Note that this seems to require raw i/o
* functions or there's a lockup? * 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 * Clear 0x0F000000 bits of reboot status register to workaround
* the FSBL not loading the bitstream after soft-reboot * the FSBL not loading the bitstream after soft-reboot
* This is a temporary solution until we know more. * This is a temporary solution until we know more.
*/ */
reboot = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET); zynq_slcr_read(&reboot, SLCR_REBOOT_STATUS_OFFSET);
writel(reboot & 0xF0FFFFFF, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET); zynq_slcr_write(reboot & 0xF0FFFFFF, SLCR_REBOOT_STATUS_OFFSET);
writel(1, zynq_slcr_base + SLCR_PS_RST_CTRL_OFFSET); zynq_slcr_write(1, SLCR_PS_RST_CTRL_OFFSET);
} }
/** /**
...@@ -61,11 +112,13 @@ void zynq_slcr_system_reset(void) ...@@ -61,11 +112,13 @@ void zynq_slcr_system_reset(void)
*/ */
void zynq_slcr_cpu_start(int cpu) void zynq_slcr_cpu_start(int cpu)
{ {
u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET); u32 reg;
zynq_slcr_read(&reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
reg &= ~(SLCR_A9_CPU_RST << cpu); 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); 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,18 +127,39 @@ void zynq_slcr_cpu_start(int cpu) ...@@ -74,18 +127,39 @@ void zynq_slcr_cpu_start(int cpu)
*/ */
void zynq_slcr_cpu_stop(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(&reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
reg |= (SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu; 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 * zynq_slcr_init - Regular slcr driver init
* Returns 0 on success, negative errno otherwise. *
* Return: 0 on success, negative errno otherwise.
* *
* Called early during boot from platform code to remap SLCR area. * Called early during boot from platform code to remap SLCR area.
*/ */
int __init zynq_slcr_init(void) 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; struct device_node *np;
...@@ -101,13 +175,13 @@ int __init zynq_slcr_init(void) ...@@ -101,13 +175,13 @@ int __init zynq_slcr_init(void)
BUG(); BUG();
} }
np->data = (__force void *)zynq_slcr_base;
/* unlock the SLCR so that registers can be changed */ /* 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); pr_info("%s mapped to %p\n", np->name, zynq_slcr_base);
zynq_clock_init(zynq_slcr_base);
of_node_put(np); of_node_put(np);
return 0; return 0;
......
...@@ -21,34 +21,35 @@ ...@@ -21,34 +21,35 @@
#include <linux/clk/zynq.h> #include <linux/clk/zynq.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/io.h> #include <linux/io.h>
static void __iomem *zynq_slcr_base_priv; static void __iomem *zynq_clkc_base;
#define SLCR_ARMPLL_CTRL (zynq_slcr_base_priv + 0x100) #define SLCR_ARMPLL_CTRL (zynq_clkc_base + 0x00)
#define SLCR_DDRPLL_CTRL (zynq_slcr_base_priv + 0x104) #define SLCR_DDRPLL_CTRL (zynq_clkc_base + 0x04)
#define SLCR_IOPLL_CTRL (zynq_slcr_base_priv + 0x108) #define SLCR_IOPLL_CTRL (zynq_clkc_base + 0x08)
#define SLCR_PLL_STATUS (zynq_slcr_base_priv + 0x10c) #define SLCR_PLL_STATUS (zynq_clkc_base + 0x0c)
#define SLCR_ARM_CLK_CTRL (zynq_slcr_base_priv + 0x120) #define SLCR_ARM_CLK_CTRL (zynq_clkc_base + 0x20)
#define SLCR_DDR_CLK_CTRL (zynq_slcr_base_priv + 0x124) #define SLCR_DDR_CLK_CTRL (zynq_clkc_base + 0x24)
#define SLCR_DCI_CLK_CTRL (zynq_slcr_base_priv + 0x128) #define SLCR_DCI_CLK_CTRL (zynq_clkc_base + 0x28)
#define SLCR_APER_CLK_CTRL (zynq_slcr_base_priv + 0x12c) #define SLCR_APER_CLK_CTRL (zynq_clkc_base + 0x2c)
#define SLCR_GEM0_CLK_CTRL (zynq_slcr_base_priv + 0x140) #define SLCR_GEM0_CLK_CTRL (zynq_clkc_base + 0x40)
#define SLCR_GEM1_CLK_CTRL (zynq_slcr_base_priv + 0x144) #define SLCR_GEM1_CLK_CTRL (zynq_clkc_base + 0x44)
#define SLCR_SMC_CLK_CTRL (zynq_slcr_base_priv + 0x148) #define SLCR_SMC_CLK_CTRL (zynq_clkc_base + 0x48)
#define SLCR_LQSPI_CLK_CTRL (zynq_slcr_base_priv + 0x14c) #define SLCR_LQSPI_CLK_CTRL (zynq_clkc_base + 0x4c)
#define SLCR_SDIO_CLK_CTRL (zynq_slcr_base_priv + 0x150) #define SLCR_SDIO_CLK_CTRL (zynq_clkc_base + 0x50)
#define SLCR_UART_CLK_CTRL (zynq_slcr_base_priv + 0x154) #define SLCR_UART_CLK_CTRL (zynq_clkc_base + 0x54)
#define SLCR_SPI_CLK_CTRL (zynq_slcr_base_priv + 0x158) #define SLCR_SPI_CLK_CTRL (zynq_clkc_base + 0x58)
#define SLCR_CAN_CLK_CTRL (zynq_slcr_base_priv + 0x15c) #define SLCR_CAN_CLK_CTRL (zynq_clkc_base + 0x5c)
#define SLCR_CAN_MIOCLK_CTRL (zynq_slcr_base_priv + 0x160) #define SLCR_CAN_MIOCLK_CTRL (zynq_clkc_base + 0x60)
#define SLCR_DBG_CLK_CTRL (zynq_slcr_base_priv + 0x164) #define SLCR_DBG_CLK_CTRL (zynq_clkc_base + 0x64)
#define SLCR_PCAP_CLK_CTRL (zynq_slcr_base_priv + 0x168) #define SLCR_PCAP_CLK_CTRL (zynq_clkc_base + 0x68)
#define SLCR_FPGA0_CLK_CTRL (zynq_slcr_base_priv + 0x170) #define SLCR_FPGA0_CLK_CTRL (zynq_clkc_base + 0x70)
#define SLCR_621_TRUE (zynq_slcr_base_priv + 0x1c4) #define SLCR_621_TRUE (zynq_clkc_base + 0xc4)
#define SLCR_SWDT_CLK_SEL (zynq_slcr_base_priv + 0x304) #define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204)
#define NUM_MIO_PINS 54 #define NUM_MIO_PINS 54
...@@ -569,8 +570,42 @@ static void __init zynq_clk_setup(struct device_node *np) ...@@ -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); 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; struct device_node *np;
of_clk_init(NULL); 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;
} }
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <linux/spinlock.h> #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, struct clk *clk_register_zynq_pll(const char *name, const char *parent,
void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment