The CPU clock provider supplies the clock to the CPU clock domain. The
composition and organization of the CPU clock provider could vary among
Exynos SoCs. A CPU clock provider can be composed of clock mux, dividers
and gates. This patch defines a new clock type for CPU clock provider and
adds infrastructure to register the CPU clock providers for Samsung
platforms.
Cc: Tomasz Figa t.f...@samsung.com
Signed-off-by: Thomas Abraham thomas...@samsung.com
---
drivers/clk/samsung/Makefile |2 +-
drivers/clk/samsung/clk-cpu.c | 335 +
drivers/clk/samsung/clk-cpu.h | 91 +++
3 files changed, 427 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/samsung/clk-cpu.c
create mode 100644 drivers/clk/samsung/clk-cpu.h
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index 6fb4bc6..8909c93 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -2,7 +2,7 @@
# Samsung Clock specific Makefile
#
-obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o
+obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-cpu.o
obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o
obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
new file mode 100644
index 000..009a21b
--- /dev/null
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Thomas Abraham thomas...@samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains the utility function to register CPU clock for Samsung
+ * Exynos platforms. A CPU clock is defined as a clock supplied to a CPU or a
+ * group of CPUs. The CPU clock is typically derived from a hierarchy of clock
+ * blocks which includes mux and divider blocks. There are a number of other
+ * auxiliary clocks supplied to the CPU domain such as the debug blocks and AXI
+ * clock for CPU domain. The rates of these auxiliary clocks are related to the
+ * CPU clock rate and this relation is usually specified in the hardware manual
+ * of the SoC or supplied after the SoC characterization.
+ *
+ * The below implementation of the CPU clock allows the rate changes of the CPU
+ * clock and the corresponding rate changes of the auxillary clocks of the CPU
+ * domain. The platform clock driver provides a clock register configuration
+ * for each configurable rate which is then used to program the clock hardware
+ * registers to acheive a fast co-oridinated rate change for all the CPU domain
+ * clocks.
+ *
+ * On a rate change request for the CPU clock, the rate change is propagated
+ * upto the PLL supplying the clock to the CPU domain clock blocks. While the
+ * CPU domain PLL is reconfigured, the CPU domain clocks are driven using an
+ * alternate clock source. If required, the alternate clock source is divided
+ * down in order to keep the output clock rate within the previous OPP limits.
+*/
+
+#include linux/errno.h
+#include clk-cpu.h
+
+#define E4210_SRC_CPU 0x0
+#define E4210_STAT_CPU 0x200
+#define E4210_DIV_CPU0 0x300
+#define E4210_DIV_CPU1 0x304
+#define E4210_DIV_STAT_CPU00x400
+#define E4210_DIV_STAT_CPU10x404
+
+#define E4210_DIV0_RATIO0_MASK 0x7
+#define E4210_DIV1_HPM_MASK(0x7 4)
+#define E4210_DIV1_COPY_MASK (0x7 0)
+#define E4210_MUX_HPM_MASK (1 20)
+#define E4210_DIV0_ATB_SHIFT 16
+#define E4210_DIV0_ATB_MASK(DIV_MASK E4210_DIV0_ATB_SHIFT)
+
+#define MAX_DIV8
+#define DIV_MASK 7
+#define DIV_MASK_ALL 0x
+#define MUX_MASK 7
+
+/*
+ * Helper function to wait until divider(s) have stabilized after the divider
+ * value has changed.
+ */
+static void wait_until_divider_stable(void __iomem *div_reg, unsigned long
mask)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+ do {
+ if (!(readl(div_reg) mask))
+ return;
+ } while (time_before(jiffies, timeout));
+
+ pr_err(%s: timeout in divider stablization\n, __func__);
+}
+
+/*
+ * Helper function to wait until mux has stabilized after the mux selection
+ * value was changed.
+ */
+static void wait_until_mux_stable(void __iomem *mux_reg, u32 mux_pos,
+ unsigned long mux_value)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+ do {
+ if (((readl(mux_reg) mux_pos) MUX_MASK) == mux_value)
+ return;
+ } while (time_before(jiffies, timeout));
+
+ pr_err(%s: re-parenting mux timed-out\n, __func__);
+}
+
+/* common round rate callback useable for all types of CPU clocks */
+static long