aboutsummaryrefslogtreecommitdiff
path: root/drivers/clk/zynq/clkc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/zynq/clkc.c')
-rw-r--r--drivers/clk/zynq/clkc.c137
1 files changed, 105 insertions, 32 deletions
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index cc40fe64f2d..246cf1226ea 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -21,37 +21,41 @@
#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
+#define DBG_CLK_CTRL_CLKACT_TRC BIT(0)
+#define DBG_CLK_CTRL_CPU_1XCLKACT BIT(1)
+
enum zynq_clk {
armpll, ddrpll, iopll,
cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x,
@@ -102,9 +106,10 @@ static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"};
static void __init zynq_clk_register_fclk(enum zynq_clk fclk,
const char *clk_name, void __iomem *fclk_ctrl_reg,
- const char **parents)
+ const char **parents, int enable)
{
struct clk *clk;
+ u32 enable_reg;
char *mux_name;
char *div0_name;
char *div1_name;
@@ -117,13 +122,19 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk,
goto err;
fclk_gate_lock = kmalloc(sizeof(*fclk_gate_lock), GFP_KERNEL);
if (!fclk_gate_lock)
- goto err;
+ goto err_fclk_gate_lock;
spin_lock_init(fclk_lock);
spin_lock_init(fclk_gate_lock);
mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name);
+ if (!mux_name)
+ goto err_mux_name;
div0_name = kasprintf(GFP_KERNEL, "%s_div0", clk_name);
+ if (!div0_name)
+ goto err_div0_name;
div1_name = kasprintf(GFP_KERNEL, "%s_div1", clk_name);
+ if (!div1_name)
+ goto err_div1_name;
clk = clk_register_mux(NULL, mux_name, parents, 4,
CLK_SET_RATE_NO_REPARENT, fclk_ctrl_reg, 4, 2, 0,
@@ -141,12 +152,26 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk,
clks[fclk] = clk_register_gate(NULL, clk_name,
div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg,
0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock);
+ enable_reg = clk_readl(fclk_gate_reg) & 1;
+ if (enable && !enable_reg) {
+ if (clk_prepare_enable(clks[fclk]))
+ pr_warn("%s: FCLK%u enable failed\n", __func__,
+ fclk - fclk0);
+ }
kfree(mux_name);
kfree(div0_name);
kfree(div1_name);
return;
+err_div1_name:
+ kfree(div0_name);
+err_div0_name:
+ kfree(mux_name);
+err_mux_name:
+ kfree(fclk_gate_lock);
+err_fclk_gate_lock:
+ kfree(fclk_lock);
err:
clks[fclk] = ERR_PTR(-ENOMEM);
}
@@ -199,6 +224,7 @@ static void __init zynq_clk_setup(struct device_node *np)
int ret;
struct clk *clk;
char *clk_name;
+ unsigned int fclk_enable = 0;
const char *clk_output_name[clk_max];
const char *cpu_parents[4];
const char *periph_parents[4];
@@ -224,6 +250,8 @@ static void __init zynq_clk_setup(struct device_node *np)
periph_parents[2] = clk_output_name[armpll];
periph_parents[3] = clk_output_name[ddrpll];
+ of_property_read_u32(np, "fclk-enable", &fclk_enable);
+
/* ps_clk */
ret = of_property_read_u32(np, "ps-clk-frequency", &tmp);
if (ret) {
@@ -253,7 +281,7 @@ static void __init zynq_clk_setup(struct device_node *np)
SLCR_IOPLL_CTRL, 4, 1, 0, &iopll_lock);
/* CPU clocks */
- tmp = readl(SLCR_621_TRUE) & 1;
+ tmp = clk_readl(SLCR_621_TRUE) & 1;
clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4,
CLK_SET_RATE_NO_REPARENT, SLCR_ARM_CLK_CTRL, 4, 2, 0,
&armclk_lock);
@@ -326,10 +354,12 @@ static void __init zynq_clk_setup(struct device_node *np)
clk_prepare_enable(clks[dci]);
/* Peripheral clocks */
- for (i = fclk0; i <= fclk3; i++)
+ for (i = fclk0; i <= fclk3; i++) {
+ int enable = !!(fclk_enable & BIT(i - fclk0));
zynq_clk_register_fclk(i, clk_output_name[i],
SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0),
- periph_parents);
+ periph_parents, enable);
+ }
zynq_clk_register_periph_clk(lqspi, 0, clk_output_name[lqspi], NULL,
SLCR_LQSPI_CLK_CTRL, periph_parents, 0);
@@ -472,6 +502,15 @@ static void __init zynq_clk_setup(struct device_node *np)
clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0,
&dbgclk_lock);
+ /* leave debug clocks in the state the bootloader set them up to */
+ tmp = clk_readl(SLCR_DBG_CLK_CTRL);
+ if (tmp & DBG_CLK_CTRL_CLKACT_TRC)
+ if (clk_prepare_enable(clks[dbg_trc]))
+ pr_warn("%s: trace clk enable failed\n", __func__);
+ if (tmp & DBG_CLK_CTRL_CPU_1XCLKACT)
+ if (clk_prepare_enable(clks[dbg_apb]))
+ pr_warn("%s: debug APB clk enable failed\n", __func__);
+
/* One gated clock for all APER clocks. */
clks[dma] = clk_register_gate(NULL, clk_output_name[dma],
clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0,
@@ -543,8 +582,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;
}