[U-Boot] [PATCH 4/9] clk: exynos: add clock driver for Exynos7420 Soc

Thomas Abraham
2016-04-13T10:43:37Z

From: Thomas Abraham <thomas.ab@samsung.com>

Add a clock driver for Exynos7420 SoC. There are about 25 clock controller
blocks in Exynos7420 out of which support for topc, top0 and peric1 blocks
are added in this initial version of the driver.

Cc: Minkyu Kang <mk7.kang@samsung.com>
Cc: Simon Glass <sjg@chromium.org>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/exynos/Kconfig | 18 +++
drivers/clk/exynos/Makefile | 9 +
drivers/clk/exynos/clk-exynos7420.c | 227 ++++++++++++++++++++++++++++
drivers/clk/exynos/clk-pll.c | 35 +++++
drivers/clk/exynos/clk-pll.h | 9 +
include/dt-bindings/clock/exynos7420-clk.h | 207 +++++++++++++++++++++++++
8 files changed, 507 insertions(+), 0 deletions(-)
create mode 100644 drivers/clk/exynos/Kconfig
create mode 100644 drivers/clk/exynos/Makefile
create mode 100644 drivers/clk/exynos/clk-exynos7420.c
create mode 100644 drivers/clk/exynos/clk-pll.c
create mode 100644 drivers/clk/exynos/clk-pll.h
create mode 100644 include/dt-bindings/clock/exynos7420-clk.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index a98b74b..6eee8eb 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -21,5 +21,6 @@ config SPL_CLK
used as U-Boot proper.

source "drivers/clk/uniphier/Kconfig"
+source "drivers/clk/exynos/Kconfig"

endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c51db15..81fe600 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
obj-$(CONFIG_SANDBOX) += clk_sandbox.o
obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
+obj-$(CONFIG_CLK_EXYNOS) += exynos/
diff --git a/drivers/clk/exynos/Kconfig b/drivers/clk/exynos/Kconfig
new file mode 100644
index 0000000..eb0efa9
--- /dev/null
+++ b/drivers/clk/exynos/Kconfig
@@ -0,0 +1,18 @@
+config CLK_EXYNOS
+ bool
+ select CLK
+ help
+ This enables support for common clock driver API on Samsung
+ Exynos SoCs.
+
+menu "Clock drivers for Exynos SoCs"
+ depends on CLK_EXYNOS
+
+config CLK_EXYNOS7420
+ bool "Clock driver for Samsung's Exynos7420 SoC"
+ default y
+ help
+ This enables common clock driver support for platforms based
+ on Samsung Exynos7420 SoC.
+
+endmenu
diff --git a/drivers/clk/exynos/Makefile b/drivers/clk/exynos/Makefile
new file mode 100644
index 0000000..1df10fe
--- /dev/null
+++ b/drivers/clk/exynos/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (C) 2016 Samsung Electronics
+# Thomas Abraham <thomas.ab@samsung.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += clk-pll.o
+obj-$(CONFIG_CLK_EXYNOS7420) += clk-exynos7420.o
diff --git a/drivers/clk/exynos/clk-exynos7420.c b/drivers/clk/exynos/clk-exynos7420.c
new file mode 100644
index 0000000..1feaea4
--- /dev/null
+++ b/drivers/clk/exynos/clk-exynos7420.c
@@ -0,0 +1,226 @@
+/*
+ * Samsung Exynos7420 clock driver.
+ * Copyright (C) 2016 Samsung Electronics
+ * Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <clk.h>
+#include "clk-pll.h"
+#include <dt-bindings/clock/exynos7420-clk.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DIVIDER(reg, shift, mask) \
+ (((readl(reg) >> shift) & mask) + 1)
+
+struct exynos7420_clk_cmu_topc {
+ unsigned int rsvd1[68];
+ unsigned int bus0_pll_con[2];
+ unsigned int rsvd2[2];
+ unsigned int bus1_pll_con[2];
+ unsigned int rsvd3[54];
+ unsigned int mux_sel[6];
+ unsigned int rsvd4[250];
+ unsigned int div[4];
+};
+
+struct exynos7420_clk_topc_priv {
+ struct exynos7420_clk_cmu_topc *topc;
+ unsigned long fin_freq;
+ unsigned long sclk_bus0_pll_a;
+ unsigned long sclk_bus1_pll_a;
+};
+
+static ulong exynos7420_topc_get_periph_rate(struct udevice *dev, int periph)
+{
+ struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
+
+ switch (periph) {
+ case DOUT_SCLK_BUS0_PLL:
+ case SCLK_BUS0_PLL_A:
+ case SCLK_BUS0_PLL_B:
+ return priv->sclk_bus0_pll_a;
+ case DOUT_SCLK_BUS1_PLL:
+ case SCLK_BUS1_PLL_A:
+ case SCLK_BUS1_PLL_B:
+ return priv->sclk_bus1_pll_a;
+ default:
+ return 0;
+ }
+}
+
+static struct clk_ops exynos7420_clk_topc_ops = {
+ .get_periph_rate = exynos7420_topc_get_periph_rate,
+};
+
+static int exynos7420_clk_topc_probe(struct udevice *dev)
+{
+ struct exynos7420_clk_topc_priv *priv;
+ struct exynos7420_clk_cmu_topc *topc;
+ struct udevice *clk_dev;
+ unsigned long rate;
+ fdt_addr_t base;
+ int ret;
+
+ priv = dev_get_priv(dev);
+ if (!priv)
+ return -EINVAL;
+
+ base = dev_get_addr(dev);
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ topc = (struct exynos7420_clk_cmu_topc *)base;
+ priv->topc = topc;
+
+ ret = clk_get_by_index(dev, 0, &clk_dev);
+ if (ret >= 0)
+ priv->fin_freq = clk_get_rate(clk_dev);
+
+ rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
+ if (readl(&topc->mux_sel[1]) & (1 << 16))
+ rate >>= 1;
+ rate /= DIVIDER(&topc->div[3], 0, 0xf);
+ priv->sclk_bus0_pll_a = rate;
+
+ rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
+ DIVIDER(&topc->div[3], 8, 0xf);
+ priv->sclk_bus1_pll_a = rate;
+
+ return 0;
+}
+
+static const struct udevice_id exynos7420_clk_topc_compat[] = {
+ { .compatible = "samsung,exynos7-clock-topc" },
+ { }
+};
+
+U_BOOT_DRIVER(exynos7420_clk_topc) = {
+ .name = "exynos7420-clock-topc",
+ .id = UCLASS_CLK,
+ .of_match = exynos7420_clk_topc_compat,
+ .probe = exynos7420_clk_topc_probe,
+ .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
+ .ops = &exynos7420_clk_topc_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+struct exynos7420_clk_cmu_top0 {
+ unsigned int rsvd0[128];
+ unsigned int mux_sel[7];
+ unsigned int rsvd1[261];
+ unsigned int div_peric[5];
+};
+
+struct exynos7420_clk_top0_priv {
+ struct exynos7420_clk_cmu_top0 *top0;
+ unsigned long mout_top0_bus0_pll_half;
+ unsigned long sclk_uart2;
+};
+
+static ulong exynos7420_top0_get_periph_rate(struct udevice *dev, int periph)
+{
+ struct exynos7420_clk_top0_priv *priv = dev_get_priv(dev);
+ struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
+
+ switch (periph) {
+ case CLK_SCLK_UART2:
+ return priv->mout_top0_bus0_pll_half /
+ DIVIDER(&top0->div_peric[3], 8, 0xf);
+ default:
+ return 0;
+ }
+}
+
+static struct clk_ops exynos7420_clk_top0_ops = {
+ .get_periph_rate = exynos7420_top0_get_periph_rate,
+};
+
+static int exynos7420_clk_top0_probe(struct udevice *dev)
+{
+ struct exynos7420_clk_top0_priv *priv;
+ struct exynos7420_clk_cmu_top0 *top0;
+ struct udevice *clk_dev;
+ fdt_addr_t base;
+ int ret;
+
+ priv = dev_get_priv(dev);
+ if (!priv)
+ return -EINVAL;
+
+ base = dev_get_addr(dev);
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ top0 = (struct exynos7420_clk_cmu_top0 *)base;
+ priv->top0 = top0;
+
+ ret = clk_get_by_index(dev, 1, &clk_dev);
+ if (ret >= 0) {
+ priv->mout_top0_bus0_pll_half =
+ clk_get_periph_rate(clk_dev, ret);
+ if (readl(&top0->mux_sel[1]) & (1 << 16))
+ priv->mout_top0_bus0_pll_half >>= 1;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id exynos7420_clk_top0_compat[] = {
+ { .compatible = "samsung,exynos7-clock-top0" },
+ { }
+};
+
+U_BOOT_DRIVER(exynos7420_clk_top0) = {
+ .name = "exynos7420-clock-top0",
+ .id = UCLASS_CLK,
+ .of_match = exynos7420_clk_top0_compat,
+ .probe = exynos7420_clk_top0_probe,
+ .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
+ .ops = &exynos7420_clk_top0_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static ulong exynos7420_peric1_get_periph_rate(struct udevice *dev, int periph)
+{
+ struct udevice *clk_dev;
+ unsigned int ret;
+
+ switch (periph) {
+ case SCLK_UART2:
+ ret = clk_get_by_index(dev, 3, &clk_dev);
+ if (ret >= 0)
+ return clk_get_periph_rate(clk_dev, ret);
+ default:
+ return 0;
+ }
+}
+
+static struct clk_ops exynos7420_clk_peric1_ops = {
+ .get_periph_rate = exynos7420_peric1_get_periph_rate,
+};
+
+static int exynos7420_clk_peric1_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct udevice_id exynos7420_clk_peric1_compat[] = {
+ { .compatible = "samsung,exynos7-clock-peric1" },
+ { }
+};
+
+U_BOOT_DRIVER(exynos7420_clk_peric1) = {
+ .name = "exynos7420-clock-peric1",
+ .id = UCLASS_CLK,
+ .of_match = exynos7420_clk_peric1_compat,
+ .probe = exynos7420_clk_peric1_probe,
+ .ops = &exynos7420_clk_peric1_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/exynos/clk-pll.c b/drivers/clk/exynos/clk-pll.c
new file mode 100644
index 0000000..dd11268
--- /dev/null
+++ b/drivers/clk/exynos/clk-pll.c
@@ -0,0 +1,33 @@
+/*
+ * Exynos PLL helper functions for clock drivers.
+ * Copyright (C) 2016 Samsung Electronics
+ * Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <div64.h>
+
+#define PLL145X_MDIV_SHIFT 16
+#define PLL145X_MDIV_MASK 0x3ff
+#define PLL145X_PDIV_SHIFT 8
+#define PLL145X_PDIV_MASK 0x3f
+#define PLL145X_SDIV_SHIFT 0
+#define PLL145X_SDIV_MASK 0x7
+
+unsigned long pll145x_get_rate(unsigned int *con1, unsigned long fin_freq)
+{
+ unsigned long pll_con1 = readl(con1);
+ unsigned long mdiv, sdiv, pdiv;
+ uint64_t fvco = fin_freq;
+
+ mdiv = (pll_con1 >> PLL145X_MDIV_SHIFT) & PLL145X_MDIV_MASK;
+ pdiv = (pll_con1 >> PLL145X_PDIV_SHIFT) & PLL145X_PDIV_MASK;
+ sdiv = (pll_con1 >> PLL145X_SDIV_SHIFT) & PLL145X_SDIV_MASK;
+
+ fvco *= mdiv;
+ do_div(fvco, (pdiv << sdiv));
+ return (unsigned long)fvco;
+}
diff --git a/drivers/clk/exynos/clk-pll.h b/drivers/clk/exynos/clk-pll.h
new file mode 100644
index 0000000..631d035
--- /dev/null
+++ b/drivers/clk/exynos/clk-pll.h
@@ -0,0 +1,9 @@
+/*
+ * Exynos PLL helper functions for clock drivers.
+ * Copyright (C) 2016 Samsung Electronics
+ * Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+unsigned long pll145x_get_rate(unsigned int *con1, unsigned long fin_freq);
diff --git a/include/dt-bindings/clock/exynos7420-clk.h b/include/dt-bindings/clock/exynos7420-clk.h
new file mode 100644
index 0000000..10c5586
--- /dev/null
+++ b/include/dt-bindings/clock/exynos7420-clk.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Naveen Krishna Ch <naveenkrishna.ch@gmail.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.
+*/
+
+#ifndef _DT_BINDINGS_CLOCK_EXYNOS7_H
+#define _DT_BINDINGS_CLOCK_EXYNOS7_H
+
+/* TOPC */
+#define DOUT_ACLK_PERIS 1
+#define DOUT_SCLK_BUS0_PLL 2
+#define DOUT_SCLK_BUS1_PLL 3
+#define DOUT_SCLK_CC_PLL 4
+#define DOUT_SCLK_MFC_PLL 5
+#define DOUT_ACLK_CCORE_133 6
+#define DOUT_ACLK_MSCL_532 7
+#define ACLK_MSCL_532 8
+#define DOUT_SCLK_AUD_PLL 9
+#define FOUT_AUD_PLL 10
+#define SCLK_AUD_PLL 11
+#define SCLK_MFC_PLL_B 12
+#define SCLK_MFC_PLL_A 13
+#define SCLK_BUS1_PLL_B 14
+#define SCLK_BUS1_PLL_A 15
+#define SCLK_BUS0_PLL_B 16
+#define SCLK_BUS0_PLL_A 17
+#define SCLK_CC_PLL_B 18
+#define SCLK_CC_PLL_A 19
+#define ACLK_CCORE_133 20
+#define ACLK_PERIS_66 21
+#define TOPC_NR_CLK 22
+
+/* TOP0 */
+#define DOUT_ACLK_PERIC1 1
+#define DOUT_ACLK_PERIC0 2
+#define CLK_SCLK_UART0 3
+#define CLK_SCLK_UART1 4
+#define CLK_SCLK_UART2 5
+#define CLK_SCLK_UART3 6
+#define CLK_SCLK_SPI0 7
+#define CLK_SCLK_SPI1 8
+#define CLK_SCLK_SPI2 9
+#define CLK_SCLK_SPI3 10
+#define CLK_SCLK_SPI4 11
+#define CLK_SCLK_SPDIF 12
+#define CLK_SCLK_PCM1 13
+#define CLK_SCLK_I2S1 14
+#define CLK_ACLK_PERIC0_66 15
+#define CLK_ACLK_PERIC1_66 16
+#define TOP0_NR_CLK 17
+
+/* TOP1 */
+#define DOUT_ACLK_FSYS1_200 1
+#define DOUT_ACLK_FSYS0_200 2
+#define DOUT_SCLK_MMC2 3
+#define DOUT_SCLK_MMC1 4
+#define DOUT_SCLK_MMC0 5
+#define CLK_SCLK_MMC2 6
+#define CLK_SCLK_MMC1 7
+#define CLK_SCLK_MMC0 8
+#define CLK_ACLK_FSYS0_200 9
+#define CLK_ACLK_FSYS1_200 10
+#define CLK_SCLK_PHY_FSYS1 11
+#define CLK_SCLK_PHY_FSYS1_26M 12
+#define MOUT_SCLK_UFSUNIPRO20 13
+#define DOUT_SCLK_UFSUNIPRO20 14
+#define CLK_SCLK_UFSUNIPRO20 15
+#define DOUT_SCLK_PHY_FSYS1 16
+#define DOUT_SCLK_PHY_FSYS1_26M 17
+#define TOP1_NR_CLK 18
+
+/* CCORE */
+#define PCLK_RTC 1
+#define CCORE_NR_CLK 2
+
+/* PERIC0 */
+#define PCLK_UART0 1
+#define SCLK_UART0 2
+#define PCLK_HSI2C0 3
+#define PCLK_HSI2C1 4
+#define PCLK_HSI2C4 5
+#define PCLK_HSI2C5 6
+#define PCLK_HSI2C9 7
+#define PCLK_HSI2C10 8
+#define PCLK_HSI2C11 9
+#define PCLK_PWM 10
+#define SCLK_PWM 11
+#define PCLK_ADCIF 12
+#define PERIC0_NR_CLK 13
+
+/* PERIC1 */
+#define PCLK_UART1 1
+#define PCLK_UART2 2
+#define PCLK_UART3 3
+#define SCLK_UART1 4
+#define SCLK_UART2 5
+#define SCLK_UART3 6
+#define PCLK_HSI2C2 7
+#define PCLK_HSI2C3 8
+#define PCLK_HSI2C6 9
+#define PCLK_HSI2C7 10
+#define PCLK_HSI2C8 11
+#define PCLK_SPI0 12
+#define PCLK_SPI1 13
+#define PCLK_SPI2 14
+#define PCLK_SPI3 15
+#define PCLK_SPI4 16
+#define SCLK_SPI0 17
+#define SCLK_SPI1 18
+#define SCLK_SPI2 19
+#define SCLK_SPI3 20
+#define SCLK_SPI4 21
+#define PCLK_I2S1 22
+#define PCLK_PCM1 23
+#define PCLK_SPDIF 24
+#define SCLK_I2S1 25
+#define SCLK_PCM1 26
+#define SCLK_SPDIF 27
+#define PERIC1_NR_CLK 28
+
+/* PERIS */
+#define PCLK_CHIPID 1
+#define SCLK_CHIPID 2
+#define PCLK_WDT 3
+#define PCLK_TMU 4
+#define SCLK_TMU 5
+#define PERIS_NR_CLK 6
+
+/* FSYS0 */
+#define ACLK_MMC2 1
+#define ACLK_AXIUS_USBDRD30X_FSYS0X 2
+#define ACLK_USBDRD300 3
+#define SCLK_USBDRD300_SUSPENDCLK 4
+#define SCLK_USBDRD300_REFCLK 5
+#define PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER 6
+#define PHYCLK_USBDRD300_UDRD30_PHYCLK_USER 7
+#define OSCCLK_PHY_CLKOUT_USB30_PHY 8
+#define ACLK_PDMA0 9
+#define ACLK_PDMA1 10
+#define FSYS0_NR_CLK 11
+
+/* FSYS1 */
+#define ACLK_MMC1 1
+#define ACLK_MMC0 2
+#define PHYCLK_UFS20_TX0_SYMBOL 3
+#define PHYCLK_UFS20_RX0_SYMBOL 4
+#define PHYCLK_UFS20_RX1_SYMBOL 5
+#define ACLK_UFS20_LINK 6
+#define SCLK_UFSUNIPRO20_USER 7
+#define PHYCLK_UFS20_RX1_SYMBOL_USER 8
+#define PHYCLK_UFS20_RX0_SYMBOL_USER 9
+#define PHYCLK_UFS20_TX0_SYMBOL_USER 10
+#define OSCCLK_PHY_CLKOUT_EMBEDDED_COMBO_PHY 11
+#define SCLK_COMBO_PHY_EMBEDDED_26M 12
+#define DOUT_PCLK_FSYS1 13
+#define PCLK_GPIO_FSYS1 14
+#define MOUT_FSYS1_PHYCLK_SEL1 15
+#define FSYS1_NR_CLK 16
+
+/* MSCL */
+#define USERMUX_ACLK_MSCL_532 1
+#define DOUT_PCLK_MSCL 2
+#define ACLK_MSCL_0 3
+#define ACLK_MSCL_1 4
+#define ACLK_JPEG 5
+#define ACLK_G2D 6
+#define ACLK_LH_ASYNC_SI_MSCL_0 7
+#define ACLK_LH_ASYNC_SI_MSCL_1 8
+#define ACLK_AXI2ACEL_BRIDGE 9
+#define ACLK_XIU_MSCLX_0 10
+#define ACLK_XIU_MSCLX_1 11
+#define ACLK_QE_MSCL_0 12
+#define ACLK_QE_MSCL_1 13
+#define ACLK_QE_JPEG 14
+#define ACLK_QE_G2D 15
+#define ACLK_PPMU_MSCL_0 16
+#define ACLK_PPMU_MSCL_1 17
+#define ACLK_MSCLNP_133 18
+#define ACLK_AHB2APB_MSCL0P 19
+#define ACLK_AHB2APB_MSCL1P 20
+
+#define PCLK_MSCL_0 21
+#define PCLK_MSCL_1 22
+#define PCLK_JPEG 23
+#define PCLK_G2D 24
+#define PCLK_QE_MSCL_0 25
+#define PCLK_QE_MSCL_1 26
+#define PCLK_QE_JPEG 27
+#define PCLK_QE_G2D 28
+#define PCLK_PPMU_MSCL_0 29
+#define PCLK_PPMU_MSCL_1 30
+#define PCLK_AXI2ACEL_BRIDGE 31
+#define PCLK_PMU_MSCL 32
+#define MSCL_NR_CLK 33
+
+/* AUD */
+#define SCLK_I2S 1
+#define SCLK_PCM 2
+#define PCLK_I2S 3
+#define PCLK_PCM 4
+#define ACLK_ADMA 5
+#define AUD_NR_CLK 6
+#endif /* _DT_BINDINGS_CLOCK_EXYNOS7_H */
--
1.6.6.rc2