Message ID | 1460544222-5342-5-git-send-email-ta.omasab@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | Minkyu Kang |
Headers | show |
Hi Thomas, On 13 April 2016 at 04:43, Thomas Abraham <ta.omasab@gmail.com> wrote: > 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> Please see include order. http://www.denx.de/wiki/U-Boot/CodingStyle > + > +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; Comments on these members please. > +}; > + > +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) This cannot happen as it is auto-allocated. > + 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) = { It might be better to put all the U_BOOT_DRIVER() and compatible stuff at the end of the file? > + .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); Shouldn't this be: if (ret < 0) return ret; > + 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; Then you can omit this function. > +} > + > +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 > Regards, Simon
Hi Simon, On Wed, Apr 20, 2016 at 8:11 PM, Simon Glass <sjg@chromium.org> wrote: > Hi Thomas, > > On 13 April 2016 at 04:43, Thomas Abraham <ta.omasab@gmail.com> wrote: >> 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> > > Please see include order. > > > http://www.denx.de/wiki/U-Boot/CodingStyle >> + >> +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; > > Comments on these members please. > >> +}; >> + >> +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) > > This cannot happen as it is auto-allocated. Ok. This check will be removed. > >> + 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) = { > > It might be better to put all the U_BOOT_DRIVER() and compatible stuff > at the end of the file? Ok, will do this in the next version of the patch. > >> + .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); > > Shouldn't this be: > > if (ret < 0) > return ret; Ok. Thanks, Thomas. > >> + 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; > > Then you can omit this function. > >> +} >> + >> +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+ >> + */ >> +u-boot,dm-pre-reloc >> +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 >> > > Regards, > Simon
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 */