clk: exynos: add clock driver for Exynos7420 Soc
authorThomas Abraham <thomas.ab@samsung.com>
Sat, 23 Apr 2016 16:48:09 +0000 (22:18 +0530)
committerMinkyu Kang <mk7.kang@samsung.com>
Wed, 25 May 2016 01:00:18 +0000 (10:00 +0900)
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>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/exynos/Kconfig [new file with mode: 0644]
drivers/clk/exynos/Makefile [new file with mode: 0644]
drivers/clk/exynos/clk-exynos7420.c [new file with mode: 0644]
drivers/clk/exynos/clk-pll.c [new file with mode: 0644]
drivers/clk/exynos/clk-pll.h [new file with mode: 0644]
include/dt-bindings/clock/exynos7420-clk.h [new file with mode: 0644]

index a98b74bbc0cfe14b07b11b0ad760ea2521fff878..6eee8eb369bf5bee5d613dd76e506b83f4f99635 100644 (file)
@@ -21,5 +21,6 @@ config SPL_CLK
          used as U-Boot proper.
 
 source "drivers/clk/uniphier/Kconfig"
+source "drivers/clk/exynos/Kconfig"
 
 endmenu
index c51db1562b6436fcfab7df5ebd64c212112473de..81fe600188cc030cb9b585b987b5fc242a9a89c0 100644 (file)
@@ -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 (file)
index 0000000..eb0efa9
--- /dev/null
@@ -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 (file)
index 0000000..1df10fe
--- /dev/null
@@ -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 (file)
index 0000000..bf5d0e6
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * 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 <clk.h>
+#include <asm/io.h>
+#include <dt-bindings/clock/exynos7420-clk.h>
+#include "clk-pll.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DIVIDER(reg, shift, mask)      \
+       (((readl(reg) >> shift) & mask) + 1)
+
+/* CMU TOPC block device structure */
+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];
+};
+
+/* CMU TOP0 block device structure */
+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_topc_priv - private data for CMU topc clock driver.
+ *
+ * @topc: base address of the memory mapped CMU TOPC controller.
+ * @fin_freq: frequency of the Oscillator clock.
+ * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
+ * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
+ */
+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;
+};
+
+/**
+ * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
+ *
+ * @top0: base address of the memory mapped CMU TOP0 controller.
+ * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
+ * @sclk_uart2: frequency of sclk_uart2 clock.
+ */
+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_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 = dev_get_priv(dev);
+       struct exynos7420_clk_cmu_topc *topc;
+       struct udevice *clk_dev;
+       unsigned long rate;
+       fdt_addr_t base;
+       int ret;
+
+       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 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 ulong exynos7420_peric1_get_periph_rate(struct udevice *dev, int periph)
+{
+       struct udevice *clk_dev;
+       unsigned int ret;
+       unsigned long freq = 0;
+
+       switch (periph) {
+       case SCLK_UART2:
+               ret = clk_get_by_index(dev, 3, &clk_dev);
+               if (ret < 0)
+                       return ret;
+               freq = clk_get_periph_rate(clk_dev, ret);
+               break;
+       }
+
+       return freq;
+}
+
+static struct clk_ops exynos7420_clk_peric1_ops = {
+       .get_periph_rate        = exynos7420_peric1_get_periph_rate,
+};
+
+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,
+};
+
+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 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,
+       .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 (file)
index 0000000..27220c5
--- /dev/null
@@ -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 (file)
index 0000000..631d035
--- /dev/null
@@ -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 (file)
index 0000000..10c5586
--- /dev/null
@@ -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 */