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

Thomas Abraham ta.omasab at gmail.com
Wed Apr 13 12:43:37 CEST 2016


From: Thomas Abraham <thomas.ab at 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 at samsung.com>
Cc: Simon Glass <sjg at chromium.org>
Signed-off-by: Thomas Abraham <thomas.ab at 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 at 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 at 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 at 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 at 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 at 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



More information about the U-Boot mailing list