uboot/drivers/clk/clk_zynqmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * ZynqMP clock driver
   4 *
   5 * Copyright (C) 2016 Xilinx, Inc.
   6 */
   7
   8#include <common.h>
   9#include <log.h>
  10#include <malloc.h>
  11#include <dm/device_compat.h>
  12#include <linux/bitops.h>
  13#include <clk-uclass.h>
  14#include <clk.h>
  15#include <asm/arch/sys_proto.h>
  16#include <dm.h>
  17#include <linux/err.h>
  18
  19static const resource_size_t zynqmp_crf_apb_clkc_base = 0xfd1a0020;
  20static const resource_size_t zynqmp_crl_apb_clkc_base = 0xff5e0020;
  21
  22/* Full power domain clocks */
  23#define CRF_APB_APLL_CTRL               (zynqmp_crf_apb_clkc_base + 0x00)
  24#define CRF_APB_DPLL_CTRL               (zynqmp_crf_apb_clkc_base + 0x0c)
  25#define CRF_APB_VPLL_CTRL               (zynqmp_crf_apb_clkc_base + 0x18)
  26#define CRF_APB_PLL_STATUS              (zynqmp_crf_apb_clkc_base + 0x24)
  27#define CRF_APB_APLL_TO_LPD_CTRL        (zynqmp_crf_apb_clkc_base + 0x28)
  28#define CRF_APB_DPLL_TO_LPD_CTRL        (zynqmp_crf_apb_clkc_base + 0x2c)
  29#define CRF_APB_VPLL_TO_LPD_CTRL        (zynqmp_crf_apb_clkc_base + 0x30)
  30/* Peripheral clocks */
  31#define CRF_APB_ACPU_CTRL               (zynqmp_crf_apb_clkc_base + 0x40)
  32#define CRF_APB_DBG_TRACE_CTRL          (zynqmp_crf_apb_clkc_base + 0x44)
  33#define CRF_APB_DBG_FPD_CTRL            (zynqmp_crf_apb_clkc_base + 0x48)
  34#define CRF_APB_DP_VIDEO_REF_CTRL       (zynqmp_crf_apb_clkc_base + 0x50)
  35#define CRF_APB_DP_AUDIO_REF_CTRL       (zynqmp_crf_apb_clkc_base + 0x54)
  36#define CRF_APB_DP_STC_REF_CTRL         (zynqmp_crf_apb_clkc_base + 0x5c)
  37#define CRF_APB_DDR_CTRL                (zynqmp_crf_apb_clkc_base + 0x60)
  38#define CRF_APB_GPU_REF_CTRL            (zynqmp_crf_apb_clkc_base + 0x64)
  39#define CRF_APB_SATA_REF_CTRL           (zynqmp_crf_apb_clkc_base + 0x80)
  40#define CRF_APB_PCIE_REF_CTRL           (zynqmp_crf_apb_clkc_base + 0x94)
  41#define CRF_APB_GDMA_REF_CTRL           (zynqmp_crf_apb_clkc_base + 0x98)
  42#define CRF_APB_DPDMA_REF_CTRL          (zynqmp_crf_apb_clkc_base + 0x9c)
  43#define CRF_APB_TOPSW_MAIN_CTRL         (zynqmp_crf_apb_clkc_base + 0xa0)
  44#define CRF_APB_TOPSW_LSBUS_CTRL        (zynqmp_crf_apb_clkc_base + 0xa4)
  45#define CRF_APB_GTGREF0_REF_CTRL        (zynqmp_crf_apb_clkc_base + 0xa8)
  46#define CRF_APB_DBG_TSTMP_CTRL          (zynqmp_crf_apb_clkc_base + 0xd8)
  47
  48/* Low power domain clocks */
  49#define CRL_APB_IOPLL_CTRL              (zynqmp_crl_apb_clkc_base + 0x00)
  50#define CRL_APB_RPLL_CTRL               (zynqmp_crl_apb_clkc_base + 0x10)
  51#define CRL_APB_PLL_STATUS              (zynqmp_crl_apb_clkc_base + 0x20)
  52#define CRL_APB_IOPLL_TO_FPD_CTRL       (zynqmp_crl_apb_clkc_base + 0x24)
  53#define CRL_APB_RPLL_TO_FPD_CTRL        (zynqmp_crl_apb_clkc_base + 0x28)
  54/* Peripheral clocks */
  55#define CRL_APB_USB3_DUAL_REF_CTRL      (zynqmp_crl_apb_clkc_base + 0x2c)
  56#define CRL_APB_GEM0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x30)
  57#define CRL_APB_GEM1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x34)
  58#define CRL_APB_GEM2_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x38)
  59#define CRL_APB_GEM3_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x3c)
  60#define CRL_APB_USB0_BUS_REF_CTRL       (zynqmp_crl_apb_clkc_base + 0x40)
  61#define CRL_APB_USB1_BUS_REF_CTRL       (zynqmp_crl_apb_clkc_base + 0x44)
  62#define CRL_APB_QSPI_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x48)
  63#define CRL_APB_SDIO0_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x4c)
  64#define CRL_APB_SDIO1_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x50)
  65#define CRL_APB_UART0_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x54)
  66#define CRL_APB_UART1_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x58)
  67#define CRL_APB_SPI0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x5c)
  68#define CRL_APB_SPI1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x60)
  69#define CRL_APB_CAN0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x64)
  70#define CRL_APB_CAN1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x68)
  71#define CRL_APB_CPU_R5_CTRL             (zynqmp_crl_apb_clkc_base + 0x70)
  72#define CRL_APB_IOU_SWITCH_CTRL         (zynqmp_crl_apb_clkc_base + 0x7c)
  73#define CRL_APB_CSU_PLL_CTRL            (zynqmp_crl_apb_clkc_base + 0x80)
  74#define CRL_APB_PCAP_CTRL               (zynqmp_crl_apb_clkc_base + 0x84)
  75#define CRL_APB_LPD_SWITCH_CTRL         (zynqmp_crl_apb_clkc_base + 0x88)
  76#define CRL_APB_LPD_LSBUS_CTRL          (zynqmp_crl_apb_clkc_base + 0x8c)
  77#define CRL_APB_DBG_LPD_CTRL            (zynqmp_crl_apb_clkc_base + 0x90)
  78#define CRL_APB_NAND_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x94)
  79#define CRL_APB_ADMA_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x98)
  80#define CRL_APB_PL0_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xa0)
  81#define CRL_APB_PL1_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xa4)
  82#define CRL_APB_PL2_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xa8)
  83#define CRL_APB_PL3_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xac)
  84#define CRL_APB_PL0_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xb4)
  85#define CRL_APB_PL1_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xbc)
  86#define CRL_APB_PL2_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xc4)
  87#define CRL_APB_PL3_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xdc)
  88#define CRL_APB_GEM_TSU_REF_CTRL        (zynqmp_crl_apb_clkc_base + 0xe0)
  89#define CRL_APB_DLL_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xe4)
  90#define CRL_APB_AMS_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xe8)
  91#define CRL_APB_I2C0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x100)
  92#define CRL_APB_I2C1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x104)
  93#define CRL_APB_TIMESTAMP_REF_CTRL      (zynqmp_crl_apb_clkc_base + 0x108)
  94
  95#define ZYNQ_CLK_MAXDIV         0x3f
  96#define CLK_CTRL_DIV1_SHIFT     16
  97#define CLK_CTRL_DIV1_MASK      (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT)
  98#define CLK_CTRL_DIV0_SHIFT     8
  99#define CLK_CTRL_DIV0_MASK      (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT)
 100#define CLK_CTRL_SRCSEL_MASK    0x7
 101#define PLLCTRL_FBDIV_MASK      0x7f00
 102#define PLLCTRL_FBDIV_SHIFT     8
 103#define PLLCTRL_RESET_MASK      1
 104#define PLLCTRL_RESET_SHIFT     0
 105#define PLLCTRL_BYPASS_MASK     0x8
 106#define PLLCTRL_BYPASS_SHFT     3
 107#define PLLCTRL_POST_SRC_SHFT   24
 108#define PLLCTRL_POST_SRC_MASK   (0x7 << PLLCTRL_POST_SRC_SHFT)
 109#define PLLCTRL_PRE_SRC_SHFT    20
 110#define PLLCTRL_PRE_SRC_MASK    (0x7 << PLLCTRL_PRE_SRC_SHFT)
 111
 112
 113#define NUM_MIO_PINS    77
 114
 115enum zynqmp_clk {
 116        iopll, rpll,
 117        apll, dpll, vpll,
 118        iopll_to_fpd, rpll_to_fpd, apll_to_lpd, dpll_to_lpd, vpll_to_lpd,
 119        acpu, acpu_half,
 120        dbg_fpd, dbg_lpd, dbg_trace, dbg_tstmp,
 121        dp_video_ref, dp_audio_ref,
 122        dp_stc_ref, gdma_ref, dpdma_ref,
 123        ddr_ref, sata_ref, pcie_ref,
 124        gpu_ref, gpu_pp0_ref, gpu_pp1_ref,
 125        topsw_main, topsw_lsbus,
 126        gtgref0_ref,
 127        lpd_switch, lpd_lsbus,
 128        usb0_bus_ref, usb1_bus_ref, usb3_dual_ref, usb0, usb1,
 129        cpu_r5, cpu_r5_core,
 130        csu_spb, csu_pll, pcap,
 131        iou_switch,
 132        gem_tsu_ref, gem_tsu,
 133        gem0_ref, gem1_ref, gem2_ref, gem3_ref,
 134        gem0_tx, gem1_tx, gem2_tx, gem3_tx,
 135        qspi_ref,
 136        sdio0_ref, sdio1_ref,
 137        uart0_ref, uart1_ref,
 138        spi0_ref, spi1_ref,
 139        nand_ref,
 140        i2c0_ref, i2c1_ref, can0_ref, can1_ref, can0, can1,
 141        dll_ref,
 142        adma_ref,
 143        timestamp_ref,
 144        ams_ref,
 145        pl0, pl1, pl2, pl3,
 146        wdt,
 147        clk_max,
 148};
 149
 150static const char * const clk_names[clk_max] = {
 151        "iopll", "rpll", "apll", "dpll",
 152        "vpll", "iopll_to_fpd", "rpll_to_fpd",
 153        "apll_to_lpd", "dpll_to_lpd", "vpll_to_lpd",
 154        "acpu", "acpu_half", "dbg_fpd", "dbg_lpd",
 155        "dbg_trace", "dbg_tstmp", "dp_video_ref",
 156        "dp_audio_ref", "dp_stc_ref", "gdma_ref",
 157        "dpdma_ref", "ddr_ref", "sata_ref", "pcie_ref",
 158        "gpu_ref", "gpu_pp0_ref", "gpu_pp1_ref",
 159        "topsw_main", "topsw_lsbus", "gtgref0_ref",
 160        "lpd_switch", "lpd_lsbus", "usb0_bus_ref",
 161        "usb1_bus_ref", "usb3_dual_ref", "usb0",
 162        "usb1", "cpu_r5", "cpu_r5_core", "csu_spb",
 163        "csu_pll", "pcap", "iou_switch", "gem_tsu_ref",
 164        "gem_tsu", "gem0_ref", "gem1_ref", "gem2_ref",
 165        "gem3_ref", "gem0_tx", "gem1_tx", "gem2_tx",
 166        "gem3_tx", "qspi_ref", "sdio0_ref", "sdio1_ref",
 167        "uart0_ref", "uart1_ref", "spi0_ref",
 168        "spi1_ref", "nand_ref", "i2c0_ref", "i2c1_ref",
 169        "can0_ref", "can1_ref", "can0", "can1",
 170        "dll_ref", "adma_ref", "timestamp_ref",
 171        "ams_ref", "pl0", "pl1", "pl2", "pl3", "wdt"
 172};
 173
 174static const u32 pll_src[][4] = {
 175        {apll, 0xff, dpll, vpll},               /* acpu */
 176        {dpll, vpll, 0xff, 0xff},               /* ddr_ref */
 177        {rpll, iopll, 0xff, 0xff},              /* dll_ref */
 178        {iopll, 0xff, rpll, dpll_to_lpd},       /* gem_tsu_ref */
 179        {iopll, 0xff, rpll, dpll},              /* peripheral */
 180        {apll, 0xff, iopll_to_fpd, dpll},       /* wdt */
 181        {iopll_to_fpd, 0xff, dpll, apll},       /* dbg_fpd */
 182        {iopll, 0xff, rpll, dpll_to_lpd},       /* timestamp_ref */
 183        {iopll_to_fpd, 0xff, apll, dpll},       /* sata_ref */
 184        {iopll_to_fpd, 0xff, rpll_to_fpd, dpll},/* pcie_ref */
 185        {iopll_to_fpd, 0xff, vpll, dpll},       /* gpu_ref */
 186        {apll, 0xff, vpll, dpll},               /* topsw_main_ref */
 187        {rpll, 0xff, iopll, dpll_to_lpd},       /* cpu_r5_ref */
 188};
 189
 190enum zynqmp_clk_pll_src {
 191        ACPU_CLK_SRC = 0,
 192        DDR_CLK_SRC,
 193        DLL_CLK_SRC,
 194        GEM_TSU_CLK_SRC,
 195        PERI_CLK_SRC,
 196        WDT_CLK_SRC,
 197        DBG_FPD_CLK_SRC,
 198        TIMESTAMP_CLK_SRC,
 199        SATA_CLK_SRC,
 200        PCIE_CLK_SRC,
 201        GPU_CLK_SRC,
 202        TOPSW_MAIN_CLK_SRC,
 203        CPU_R5_CLK_SRC
 204};
 205
 206struct zynqmp_clk_priv {
 207        unsigned long ps_clk_freq;
 208        unsigned long video_clk;
 209        unsigned long pss_alt_ref_clk;
 210        unsigned long gt_crx_ref_clk;
 211        unsigned long aux_ref_clk;
 212};
 213
 214static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
 215{
 216        switch (id) {
 217        case iopll:
 218                return CRL_APB_IOPLL_CTRL;
 219        case rpll:
 220                return CRL_APB_RPLL_CTRL;
 221        case apll:
 222                return CRF_APB_APLL_CTRL;
 223        case dpll:
 224                return CRF_APB_DPLL_CTRL;
 225        case vpll:
 226                return CRF_APB_VPLL_CTRL;
 227        case acpu:
 228                return CRF_APB_ACPU_CTRL;
 229        case dbg_fpd:
 230                return CRF_APB_DBG_FPD_CTRL;
 231        case dbg_trace:
 232                return CRF_APB_DBG_TRACE_CTRL;
 233        case dbg_tstmp:
 234                return CRF_APB_DBG_TSTMP_CTRL;
 235        case gpu_ref ...  gpu_pp1_ref:
 236                return CRF_APB_GPU_REF_CTRL;
 237        case ddr_ref:
 238                return CRF_APB_DDR_CTRL;
 239        case sata_ref:
 240                return CRF_APB_SATA_REF_CTRL;
 241        case pcie_ref:
 242                return CRF_APB_PCIE_REF_CTRL;
 243        case gdma_ref:
 244                return CRF_APB_GDMA_REF_CTRL;
 245        case dpdma_ref:
 246                return CRF_APB_DPDMA_REF_CTRL;
 247        case topsw_main:
 248                return CRF_APB_TOPSW_MAIN_CTRL;
 249        case topsw_lsbus:
 250                return CRF_APB_TOPSW_LSBUS_CTRL;
 251        case lpd_switch:
 252                return CRL_APB_LPD_SWITCH_CTRL;
 253        case lpd_lsbus:
 254                return CRL_APB_LPD_LSBUS_CTRL;
 255        case qspi_ref:
 256                return CRL_APB_QSPI_REF_CTRL;
 257        case usb3_dual_ref:
 258                return CRL_APB_USB3_DUAL_REF_CTRL;
 259        case gem_tsu_ref:
 260                return CRL_APB_GEM_TSU_REF_CTRL;
 261        case gem0_ref:
 262                return CRL_APB_GEM0_REF_CTRL;
 263        case gem1_ref:
 264                return CRL_APB_GEM1_REF_CTRL;
 265        case gem2_ref:
 266                return CRL_APB_GEM2_REF_CTRL;
 267        case gem3_ref:
 268                return CRL_APB_GEM3_REF_CTRL;
 269        case usb0_bus_ref:
 270                return CRL_APB_USB0_BUS_REF_CTRL;
 271        case usb1_bus_ref:
 272                return CRL_APB_USB1_BUS_REF_CTRL;
 273        case cpu_r5:
 274                return CRL_APB_CPU_R5_CTRL;
 275        case uart0_ref:
 276                return CRL_APB_UART0_REF_CTRL;
 277        case uart1_ref:
 278                return CRL_APB_UART1_REF_CTRL;
 279        case sdio0_ref:
 280                return CRL_APB_SDIO0_REF_CTRL;
 281        case sdio1_ref:
 282                return CRL_APB_SDIO1_REF_CTRL;
 283        case spi0_ref:
 284                return CRL_APB_SPI0_REF_CTRL;
 285        case spi1_ref:
 286                return CRL_APB_SPI1_REF_CTRL;
 287        case nand_ref:
 288                return CRL_APB_NAND_REF_CTRL;
 289        case i2c0_ref:
 290                return CRL_APB_I2C0_REF_CTRL;
 291        case i2c1_ref:
 292                return CRL_APB_I2C1_REF_CTRL;
 293        case can0_ref:
 294                return CRL_APB_CAN0_REF_CTRL;
 295        case can1_ref:
 296                return CRL_APB_CAN1_REF_CTRL;
 297        case dll_ref:
 298                return CRL_APB_DLL_REF_CTRL;
 299        case adma_ref:
 300                return CRL_APB_ADMA_REF_CTRL;
 301        case timestamp_ref:
 302                return CRL_APB_TIMESTAMP_REF_CTRL;
 303        case ams_ref:
 304                return CRL_APB_AMS_REF_CTRL;
 305        case pl0:
 306                return CRL_APB_PL0_REF_CTRL;
 307        case pl1:
 308                return CRL_APB_PL1_REF_CTRL;
 309        case pl2:
 310                return CRL_APB_PL2_REF_CTRL;
 311        case pl3:
 312                return CRL_APB_PL3_REF_CTRL;
 313        case wdt:
 314                return CRF_APB_TOPSW_LSBUS_CTRL;
 315        case iopll_to_fpd:
 316                return CRL_APB_IOPLL_TO_FPD_CTRL;
 317        default:
 318                debug("Invalid clk id%d\n", id);
 319        }
 320        return 0;
 321}
 322
 323static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl,
 324                                    struct zynqmp_clk_priv *priv,
 325                                    bool is_pre_src)
 326{
 327        u32 src_sel;
 328
 329        if (is_pre_src)
 330                src_sel = (clk_ctrl & PLLCTRL_PRE_SRC_MASK) >>
 331                           PLLCTRL_PRE_SRC_SHFT;
 332        else
 333                src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >>
 334                           PLLCTRL_POST_SRC_SHFT;
 335
 336        switch (src_sel) {
 337        case 4:
 338                return priv->video_clk;
 339        case 5:
 340                return priv->pss_alt_ref_clk;
 341        case 6:
 342                return priv->aux_ref_clk;
 343        case 7:
 344                return priv->gt_crx_ref_clk;
 345        case 0 ... 3:
 346        default:
 347        return priv->ps_clk_freq;
 348        }
 349}
 350
 351static ulong zynqmp_clk_get_pll_rate(struct zynqmp_clk_priv *priv,
 352                                     enum zynqmp_clk id)
 353{
 354        u32 clk_ctrl, reset, mul;
 355        ulong freq;
 356        int ret;
 357
 358        ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
 359        if (ret) {
 360                printf("%s mio read fail\n", __func__);
 361                return -EIO;
 362        }
 363
 364        if (clk_ctrl & PLLCTRL_BYPASS_MASK)
 365                freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 0);
 366        else
 367                freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 1);
 368
 369        reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
 370        if (reset && !(clk_ctrl & PLLCTRL_BYPASS_MASK))
 371                return 0;
 372
 373        mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
 374
 375        freq *= mul;
 376
 377        if (clk_ctrl & (1 << 16))
 378                freq /= 2;
 379
 380        return freq;
 381}
 382
 383static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
 384                                     enum zynqmp_clk id)
 385{
 386        u32 clk_ctrl, div, srcsel;
 387        enum zynqmp_clk pll;
 388        int ret;
 389        unsigned long pllrate;
 390
 391        ret = zynqmp_mmio_read(CRF_APB_ACPU_CTRL, &clk_ctrl);
 392        if (ret) {
 393                printf("%s mio read fail\n", __func__);
 394                return -EIO;
 395        }
 396
 397        div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 398
 399        srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
 400        pll = pll_src[ACPU_CLK_SRC][srcsel];
 401        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 402        if (IS_ERR_VALUE(pllrate))
 403                return pllrate;
 404
 405        return DIV_ROUND_CLOSEST(pllrate, div);
 406}
 407
 408static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
 409{
 410        u32 clk_ctrl, div, srcsel;
 411        enum zynqmp_clk pll;
 412        int ret;
 413        ulong pllrate;
 414
 415        ret = zynqmp_mmio_read(CRF_APB_DDR_CTRL, &clk_ctrl);
 416        if (ret) {
 417                printf("%s mio read fail\n", __func__);
 418                return -EIO;
 419        }
 420
 421        div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 422
 423        srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
 424        pll = pll_src[DDR_CLK_SRC][srcsel];
 425        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 426        if (IS_ERR_VALUE(pllrate))
 427                return pllrate;
 428
 429        return DIV_ROUND_CLOSEST(pllrate, div);
 430}
 431
 432static ulong zynqmp_clk_get_dll_rate(struct zynqmp_clk_priv *priv)
 433{
 434        u32 clk_ctrl, srcsel;
 435        enum zynqmp_clk pll;
 436        ulong pllrate;
 437        int ret;
 438
 439        ret = zynqmp_mmio_read(CRL_APB_DLL_REF_CTRL, &clk_ctrl);
 440        if (ret) {
 441                printf("%s mio read fail\n", __func__);
 442                return -EIO;
 443        }
 444
 445        srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
 446        pll = pll_src[DLL_CLK_SRC][srcsel];
 447        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 448        if (IS_ERR_VALUE(pllrate))
 449                return pllrate;
 450
 451        return pllrate;
 452}
 453
 454static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
 455                                            enum zynqmp_clk id, bool two_divs)
 456{
 457        enum zynqmp_clk pll;
 458        u32 clk_ctrl, div0, srcsel;
 459        u32 div1 = 1;
 460        int ret;
 461        ulong pllrate;
 462
 463        ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
 464        if (ret) {
 465                printf("%s mio read fail\n", __func__);
 466                return -EIO;
 467        }
 468
 469        div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 470        if (!div0)
 471                div0 = 1;
 472
 473        if (two_divs) {
 474                div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
 475                if (!div1)
 476                        div1 = 1;
 477        }
 478        srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
 479
 480        if (id == gem_tsu_ref)
 481                pll = pll_src[GEM_TSU_CLK_SRC][srcsel];
 482        else
 483                pll = pll_src[PERI_CLK_SRC][srcsel];
 484
 485        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 486        if (IS_ERR_VALUE(pllrate))
 487                return pllrate;
 488
 489        return
 490                DIV_ROUND_CLOSEST(
 491                        DIV_ROUND_CLOSEST(pllrate, div0), div1);
 492}
 493
 494static ulong zynqmp_clk_get_crf_crl_rate(struct zynqmp_clk_priv *priv,
 495                                         enum zynqmp_clk id, bool two_divs)
 496{
 497        enum zynqmp_clk pll;
 498        u32 clk_ctrl, div0, srcsel;
 499        u32 div1 = 1;
 500        int ret;
 501        ulong pllrate;
 502
 503        ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
 504        if (ret) {
 505                printf("%d %s mio read fail\n", __LINE__, __func__);
 506                return -EIO;
 507        }
 508
 509        div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 510        if (!div0)
 511                div0 = 1;
 512        srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
 513
 514        switch (id) {
 515        case wdt:
 516        case dbg_trace:
 517        case topsw_lsbus:
 518                pll = pll_src[WDT_CLK_SRC][srcsel];
 519                break;
 520        case dbg_fpd:
 521        case dbg_tstmp:
 522                pll = pll_src[DBG_FPD_CLK_SRC][srcsel];
 523                break;
 524        case timestamp_ref:
 525                pll = pll_src[TIMESTAMP_CLK_SRC][srcsel];
 526                break;
 527        case sata_ref:
 528                pll = pll_src[SATA_CLK_SRC][srcsel];
 529                break;
 530        case pcie_ref:
 531                pll = pll_src[PCIE_CLK_SRC][srcsel];
 532                break;
 533        case gpu_ref ... gpu_pp1_ref:
 534                pll = pll_src[GPU_CLK_SRC][srcsel];
 535                break;
 536        case gdma_ref:
 537        case dpdma_ref:
 538        case topsw_main:
 539                pll = pll_src[TOPSW_MAIN_CLK_SRC][srcsel];
 540                break;
 541        case cpu_r5:
 542        case ams_ref:
 543        case adma_ref:
 544        case lpd_lsbus:
 545        case lpd_switch:
 546                pll = pll_src[CPU_R5_CLK_SRC][srcsel];
 547                break;
 548        default:
 549                return -ENXIO;
 550        }
 551        if (two_divs) {
 552                ret = zynqmp_mmio_read(zynqmp_clk_get_register(pll), &clk_ctrl);
 553                if (ret) {
 554                        printf("%d %s mio read fail\n", __LINE__, __func__);
 555                        return -EIO;
 556                }
 557                div1 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 558                if (!div1)
 559                        div1 = 1;
 560        }
 561
 562        if (pll == iopll_to_fpd)
 563                pll = iopll;
 564
 565        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 566        if (IS_ERR_VALUE(pllrate))
 567                return pllrate;
 568
 569        return
 570                DIV_ROUND_CLOSEST(
 571                        DIV_ROUND_CLOSEST(pllrate, div0), div1);
 572}
 573
 574static unsigned long zynqmp_clk_calc_peripheral_two_divs(ulong rate,
 575                                                       ulong pll_rate,
 576                                                       u32 *div0, u32 *div1)
 577{
 578        long new_err, best_err = (long)(~0UL >> 1);
 579        ulong new_rate, best_rate = 0;
 580        u32 d0, d1;
 581
 582        for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
 583                for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
 584                        new_rate = DIV_ROUND_CLOSEST(
 585                                        DIV_ROUND_CLOSEST(pll_rate, d0), d1);
 586                        new_err = abs(new_rate - rate);
 587
 588                        if (new_err < best_err) {
 589                                *div0 = d0;
 590                                *div1 = d1;
 591                                best_err = new_err;
 592                                best_rate = new_rate;
 593                        }
 594                }
 595        }
 596
 597        return best_rate;
 598}
 599
 600static ulong zynqmp_clk_set_peripheral_rate(struct zynqmp_clk_priv *priv,
 601                                          enum zynqmp_clk id, ulong rate,
 602                                          bool two_divs)
 603{
 604        enum zynqmp_clk pll;
 605        u32 clk_ctrl, div0 = 0, div1 = 0;
 606        ulong pll_rate, new_rate;
 607        u32 reg, srcsel;
 608        int ret;
 609        u32 mask;
 610
 611        reg = zynqmp_clk_get_register(id);
 612        ret = zynqmp_mmio_read(reg, &clk_ctrl);
 613        if (ret) {
 614                printf("%s mio read fail\n", __func__);
 615                return -EIO;
 616        }
 617
 618        srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
 619        pll = pll_src[PERI_CLK_SRC][srcsel];
 620        pll_rate = zynqmp_clk_get_pll_rate(priv, pll);
 621        if (IS_ERR_VALUE(pll_rate))
 622                return pll_rate;
 623
 624        clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
 625        if (two_divs) {
 626                clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
 627                new_rate = zynqmp_clk_calc_peripheral_two_divs(rate, pll_rate,
 628                                &div0, &div1);
 629                clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
 630        } else {
 631                div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
 632                if (div0 > ZYNQ_CLK_MAXDIV)
 633                        div0 = ZYNQ_CLK_MAXDIV;
 634                new_rate = DIV_ROUND_CLOSEST(rate, div0);
 635        }
 636        clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
 637
 638        mask = (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) |
 639               (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT);
 640
 641        ret = zynqmp_mmio_write(reg, mask, clk_ctrl);
 642        if (ret) {
 643                printf("%s mio write fail\n", __func__);
 644                return -EIO;
 645        }
 646
 647        return new_rate;
 648}
 649
 650static ulong zynqmp_clk_get_rate(struct clk *clk)
 651{
 652        struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
 653        enum zynqmp_clk id = clk->id;
 654        bool two_divs = false;
 655
 656        switch (id) {
 657        case iopll ... vpll:
 658                return zynqmp_clk_get_pll_rate(priv, id);
 659        case acpu:
 660                return zynqmp_clk_get_cpu_rate(priv, id);
 661        case ddr_ref:
 662                return zynqmp_clk_get_ddr_rate(priv);
 663        case dll_ref:
 664                return zynqmp_clk_get_dll_rate(priv);
 665        case gem_tsu_ref:
 666        case pl0 ... pl3:
 667        case gem0_ref ... gem3_ref:
 668        case qspi_ref ... can1_ref:
 669        case usb0_bus_ref ... usb3_dual_ref:
 670                two_divs = true;
 671                return zynqmp_clk_get_peripheral_rate(priv, id, two_divs);
 672        case wdt:
 673        case topsw_lsbus:
 674        case sata_ref ... gpu_pp1_ref:
 675                two_divs = true;
 676        case cpu_r5:
 677        case dbg_fpd:
 678        case ams_ref:
 679        case adma_ref:
 680        case lpd_lsbus:
 681        case dbg_trace:
 682        case dbg_tstmp:
 683        case lpd_switch:
 684        case topsw_main:
 685        case timestamp_ref:
 686        case gdma_ref ... dpdma_ref:
 687                return zynqmp_clk_get_crf_crl_rate(priv, id, two_divs);
 688        default:
 689                return -ENXIO;
 690        }
 691}
 692
 693static ulong zynqmp_clk_set_rate(struct clk *clk, ulong rate)
 694{
 695        struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
 696        enum zynqmp_clk id = clk->id;
 697        bool two_divs = true;
 698
 699        switch (id) {
 700        case gem0_ref ... gem3_ref:
 701        case qspi_ref ... can1_ref:
 702                return zynqmp_clk_set_peripheral_rate(priv, id,
 703                                                      rate, two_divs);
 704        default:
 705                return -ENXIO;
 706        }
 707}
 708
 709int soc_clk_dump(void)
 710{
 711        struct udevice *dev;
 712        int i, ret;
 713
 714        ret = uclass_get_device_by_driver(UCLASS_CLK,
 715                DM_DRIVER_GET(zynqmp_clk), &dev);
 716        if (ret)
 717                return ret;
 718
 719        printf("clk\t\tfrequency\n");
 720        for (i = 0; i < clk_max; i++) {
 721                const char *name = clk_names[i];
 722                if (name) {
 723                        struct clk clk;
 724                        unsigned long rate;
 725
 726                        clk.id = i;
 727                        ret = clk_request(dev, &clk);
 728                        if (ret < 0)
 729                                return ret;
 730
 731                        rate = clk_get_rate(&clk);
 732
 733                        clk_free(&clk);
 734
 735                        if ((rate == (unsigned long)-ENOSYS) ||
 736                            (rate == (unsigned long)-ENXIO) ||
 737                            (rate == (unsigned long)-EIO))
 738                                printf("%10s%20s\n", name, "unknown");
 739                        else
 740                                printf("%10s%20lu\n", name, rate);
 741                }
 742        }
 743
 744        return 0;
 745}
 746
 747static int zynqmp_get_freq_by_name(char *name, struct udevice *dev, ulong *freq)
 748{
 749        struct clk clk;
 750        int ret;
 751
 752        ret = clk_get_by_name(dev, name, &clk);
 753        if (ret < 0) {
 754                dev_err(dev, "failed to get %s\n", name);
 755                return ret;
 756        }
 757
 758        *freq = clk_get_rate(&clk);
 759        if (IS_ERR_VALUE(*freq)) {
 760                dev_err(dev, "failed to get rate %s\n", name);
 761                return -EINVAL;
 762        }
 763
 764        return 0;
 765}
 766static int zynqmp_clk_probe(struct udevice *dev)
 767{
 768        int ret;
 769        struct zynqmp_clk_priv *priv = dev_get_priv(dev);
 770
 771        debug("%s\n", __func__);
 772        ret = zynqmp_get_freq_by_name("pss_ref_clk", dev, &priv->ps_clk_freq);
 773        if (ret < 0)
 774                return -EINVAL;
 775
 776        ret = zynqmp_get_freq_by_name("video_clk", dev, &priv->video_clk);
 777        if (ret < 0)
 778                return -EINVAL;
 779
 780        ret = zynqmp_get_freq_by_name("pss_alt_ref_clk", dev,
 781                                      &priv->pss_alt_ref_clk);
 782        if (ret < 0)
 783                return -EINVAL;
 784
 785        ret = zynqmp_get_freq_by_name("aux_ref_clk", dev, &priv->aux_ref_clk);
 786        if (ret < 0)
 787                return -EINVAL;
 788
 789        ret = zynqmp_get_freq_by_name("gt_crx_ref_clk", dev,
 790                                      &priv->gt_crx_ref_clk);
 791        if (ret < 0)
 792                return -EINVAL;
 793
 794        return 0;
 795}
 796
 797static int zynqmp_clk_enable(struct clk *clk)
 798{
 799        enum zynqmp_clk id = clk->id;
 800        u32 reg, clk_ctrl, clkact_shift, mask;
 801        int ret;
 802
 803        reg = zynqmp_clk_get_register(id);
 804        debug("%s, clk_id:%x, clk_base:0x%x\n", __func__, id, reg);
 805
 806        switch (id) {
 807        case usb0_bus_ref ... usb1:
 808                clkact_shift = 25;
 809                mask = 0x1;
 810                break;
 811        case gem0_ref ... gem3_ref:
 812                clkact_shift = 25;
 813                mask = 0x3;
 814                break;
 815        case qspi_ref ... can1_ref:
 816        case lpd_lsbus:
 817                clkact_shift = 24;
 818                mask = 0x1;
 819                break;
 820        default:
 821                return -ENXIO;
 822        }
 823
 824        ret = zynqmp_mmio_read(reg, &clk_ctrl);
 825        if (ret) {
 826                printf("%s mio read fail\n", __func__);
 827                return -EIO;
 828        }
 829
 830        clk_ctrl |= (mask << clkact_shift);
 831        ret = zynqmp_mmio_write(reg, mask << clkact_shift, clk_ctrl);
 832        if (ret) {
 833                printf("%s mio write fail\n", __func__);
 834                return -EIO;
 835        }
 836
 837        return ret;
 838}
 839
 840static struct clk_ops zynqmp_clk_ops = {
 841        .set_rate = zynqmp_clk_set_rate,
 842        .get_rate = zynqmp_clk_get_rate,
 843        .enable = zynqmp_clk_enable,
 844};
 845
 846static const struct udevice_id zynqmp_clk_ids[] = {
 847        { .compatible = "xlnx,zynqmp-clk" },
 848        { }
 849};
 850
 851U_BOOT_DRIVER(zynqmp_clk) = {
 852        .name = "zynqmp_clk",
 853        .id = UCLASS_CLK,
 854        .of_match = zynqmp_clk_ids,
 855        .probe = zynqmp_clk_probe,
 856        .ops = &zynqmp_clk_ops,
 857        .priv_auto      = sizeof(struct zynqmp_clk_priv),
 858};
 859