123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- /*
- * 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-uclass.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_rate(struct clk *clk)
- {
- struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
- switch (clk->id) {
- 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_rate = exynos7420_topc_get_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 clk in_clk;
- 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, &in_clk);
- if (ret >= 0)
- priv->fin_freq = clk_get_rate(&in_clk);
- 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_rate(struct clk *clk)
- {
- struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
- struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
- switch (clk->id) {
- 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_rate = exynos7420_top0_get_rate,
- };
- static int exynos7420_clk_top0_probe(struct udevice *dev)
- {
- struct exynos7420_clk_top0_priv *priv;
- struct exynos7420_clk_cmu_top0 *top0;
- struct clk in_clk;
- 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, &in_clk);
- if (ret >= 0) {
- priv->mout_top0_bus0_pll_half =
- clk_get_rate(&in_clk);
- if (readl(&top0->mux_sel[1]) & (1 << 16))
- priv->mout_top0_bus0_pll_half >>= 1;
- }
- return 0;
- }
- static ulong exynos7420_peric1_get_rate(struct clk *clk)
- {
- struct clk in_clk;
- unsigned int ret;
- unsigned long freq = 0;
- switch (clk->id) {
- case SCLK_UART2:
- ret = clk_get_by_index(clk->dev, 3, &in_clk);
- if (ret < 0)
- return ret;
- freq = clk_get_rate(&in_clk);
- break;
- }
- return freq;
- }
- static struct clk_ops exynos7420_clk_peric1_ops = {
- .get_rate = exynos7420_peric1_get_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,
- };
|