uboot/drivers/clk/exynos/clk-exynos7420.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Samsung Exynos7420 clock driver.
   4 * Copyright (C) 2016 Samsung Electronics
   5 * Thomas Abraham <thomas.ab@samsung.com>
   6 */
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <errno.h>
  11#include <clk-uclass.h>
  12#include <asm/io.h>
  13#include <dt-bindings/clock/exynos7420-clk.h>
  14#include "clk-pll.h"
  15
  16#define DIVIDER(reg, shift, mask)       \
  17        (((readl(reg) >> shift) & mask) + 1)
  18
  19/* CMU TOPC block device structure */
  20struct exynos7420_clk_cmu_topc {
  21        unsigned int    rsvd1[68];
  22        unsigned int    bus0_pll_con[2];
  23        unsigned int    rsvd2[2];
  24        unsigned int    bus1_pll_con[2];
  25        unsigned int    rsvd3[54];
  26        unsigned int    mux_sel[6];
  27        unsigned int    rsvd4[250];
  28        unsigned int    div[4];
  29};
  30
  31/* CMU TOP0 block device structure */
  32struct exynos7420_clk_cmu_top0 {
  33        unsigned int    rsvd0[128];
  34        unsigned int    mux_sel[7];
  35        unsigned int    rsvd1[261];
  36        unsigned int    div_peric[5];
  37};
  38
  39/**
  40 * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver.
  41 *
  42 * @topc: base address of the memory mapped CMU TOPC controller.
  43 * @fin_freq: frequency of the Oscillator clock.
  44 * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
  45 * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
  46 */
  47struct exynos7420_clk_topc_priv {
  48        struct exynos7420_clk_cmu_topc *topc;
  49        unsigned long fin_freq;
  50        unsigned long sclk_bus0_pll_a;
  51        unsigned long sclk_bus1_pll_a;
  52};
  53
  54/**
  55 * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
  56 *
  57 * @top0: base address of the memory mapped CMU TOP0 controller.
  58 * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
  59 * @sclk_uart2: frequency of sclk_uart2 clock.
  60 */
  61struct exynos7420_clk_top0_priv {
  62        struct exynos7420_clk_cmu_top0 *top0;
  63        unsigned long mout_top0_bus0_pll_half;
  64        unsigned long sclk_uart2;
  65};
  66
  67static ulong exynos7420_topc_get_rate(struct clk *clk)
  68{
  69        struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
  70
  71        switch (clk->id) {
  72        case DOUT_SCLK_BUS0_PLL:
  73        case SCLK_BUS0_PLL_A:
  74        case SCLK_BUS0_PLL_B:
  75                return priv->sclk_bus0_pll_a;
  76        case DOUT_SCLK_BUS1_PLL:
  77        case SCLK_BUS1_PLL_A:
  78        case SCLK_BUS1_PLL_B:
  79                return priv->sclk_bus1_pll_a;
  80        default:
  81                return 0;
  82        }
  83}
  84
  85static struct clk_ops exynos7420_clk_topc_ops = {
  86        .get_rate       = exynos7420_topc_get_rate,
  87};
  88
  89static int exynos7420_clk_topc_probe(struct udevice *dev)
  90{
  91        struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
  92        struct exynos7420_clk_cmu_topc *topc;
  93        struct clk in_clk;
  94        unsigned long rate;
  95        fdt_addr_t base;
  96        int ret;
  97
  98        base = devfdt_get_addr(dev);
  99        if (base == FDT_ADDR_T_NONE)
 100                return -EINVAL;
 101
 102        topc = (struct exynos7420_clk_cmu_topc *)base;
 103        priv->topc = topc;
 104
 105        ret = clk_get_by_index(dev, 0, &in_clk);
 106        if (ret >= 0)
 107                priv->fin_freq = clk_get_rate(&in_clk);
 108
 109        rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
 110        if (readl(&topc->mux_sel[1]) & (1 << 16))
 111                rate >>= 1;
 112        rate /= DIVIDER(&topc->div[3], 0, 0xf);
 113        priv->sclk_bus0_pll_a = rate;
 114
 115        rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
 116                        DIVIDER(&topc->div[3], 8, 0xf);
 117        priv->sclk_bus1_pll_a = rate;
 118
 119        return 0;
 120}
 121
 122static ulong exynos7420_top0_get_rate(struct clk *clk)
 123{
 124        struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
 125        struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
 126
 127        switch (clk->id) {
 128        case CLK_SCLK_UART2:
 129                return priv->mout_top0_bus0_pll_half /
 130                        DIVIDER(&top0->div_peric[3], 8, 0xf);
 131        default:
 132                return 0;
 133        }
 134}
 135
 136static struct clk_ops exynos7420_clk_top0_ops = {
 137        .get_rate       = exynos7420_top0_get_rate,
 138};
 139
 140static int exynos7420_clk_top0_probe(struct udevice *dev)
 141{
 142        struct exynos7420_clk_top0_priv *priv;
 143        struct exynos7420_clk_cmu_top0 *top0;
 144        struct clk in_clk;
 145        fdt_addr_t base;
 146        int ret;
 147
 148        priv = dev_get_priv(dev);
 149        if (!priv)
 150                return -EINVAL;
 151
 152        base = devfdt_get_addr(dev);
 153        if (base == FDT_ADDR_T_NONE)
 154                return -EINVAL;
 155
 156        top0 = (struct exynos7420_clk_cmu_top0 *)base;
 157        priv->top0 = top0;
 158
 159        ret = clk_get_by_index(dev, 1, &in_clk);
 160        if (ret >= 0) {
 161                priv->mout_top0_bus0_pll_half =
 162                        clk_get_rate(&in_clk);
 163                if (readl(&top0->mux_sel[1]) & (1 << 16))
 164                        priv->mout_top0_bus0_pll_half >>= 1;
 165        }
 166
 167        return 0;
 168}
 169
 170static ulong exynos7420_peric1_get_rate(struct clk *clk)
 171{
 172        struct clk in_clk;
 173        unsigned int ret;
 174        unsigned long freq = 0;
 175
 176        switch (clk->id) {
 177        case SCLK_UART2:
 178                ret = clk_get_by_index(clk->dev, 3, &in_clk);
 179                if (ret < 0)
 180                        return ret;
 181                freq = clk_get_rate(&in_clk);
 182                break;
 183        }
 184
 185        return freq;
 186}
 187
 188static struct clk_ops exynos7420_clk_peric1_ops = {
 189        .get_rate       = exynos7420_peric1_get_rate,
 190};
 191
 192static const struct udevice_id exynos7420_clk_topc_compat[] = {
 193        { .compatible = "samsung,exynos7-clock-topc" },
 194        { }
 195};
 196
 197U_BOOT_DRIVER(exynos7420_clk_topc) = {
 198        .name = "exynos7420-clock-topc",
 199        .id = UCLASS_CLK,
 200        .of_match = exynos7420_clk_topc_compat,
 201        .probe = exynos7420_clk_topc_probe,
 202        .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
 203        .ops = &exynos7420_clk_topc_ops,
 204};
 205
 206static const struct udevice_id exynos7420_clk_top0_compat[] = {
 207        { .compatible = "samsung,exynos7-clock-top0" },
 208        { }
 209};
 210
 211U_BOOT_DRIVER(exynos7420_clk_top0) = {
 212        .name = "exynos7420-clock-top0",
 213        .id = UCLASS_CLK,
 214        .of_match = exynos7420_clk_top0_compat,
 215        .probe = exynos7420_clk_top0_probe,
 216        .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
 217        .ops = &exynos7420_clk_top0_ops,
 218};
 219
 220static const struct udevice_id exynos7420_clk_peric1_compat[] = {
 221        { .compatible = "samsung,exynos7-clock-peric1" },
 222        { }
 223};
 224
 225U_BOOT_DRIVER(exynos7420_clk_peric1) = {
 226        .name = "exynos7420-clock-peric1",
 227        .id = UCLASS_CLK,
 228        .of_match = exynos7420_clk_peric1_compat,
 229        .ops = &exynos7420_clk_peric1_ops,
 230};
 231