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_SHIFT   0
 101#define CLK_CTRL_SRCSEL_MASK    (0x3 << CLK_CTRL_SRCSEL_SHIFT)
 102#define PLLCTRL_FBDIV_MASK      0x7f00
 103#define PLLCTRL_FBDIV_SHIFT     8
 104#define PLLCTRL_RESET_MASK      1
 105#define PLLCTRL_RESET_SHIFT     0
 106#define PLLCTRL_BYPASS_MASK     0x8
 107#define PLLCTRL_BYPASS_SHFT     3
 108#define PLLCTRL_POST_SRC_SHFT   24
 109#define PLLCTRL_POST_SRC_MASK   (0x7 << PLLCTRL_POST_SRC_SHFT)
 110#define PLLCTRL_PRE_SRC_SHFT    20
 111#define PLLCTRL_PRE_SRC_MASK    (0x7 << PLLCTRL_PRE_SRC_SHFT)
 112
 113
 114#define NUM_MIO_PINS    77
 115
 116enum zynqmp_clk {
 117        iopll, rpll,
 118        apll, dpll, vpll,
 119        iopll_to_fpd, rpll_to_fpd, apll_to_lpd, dpll_to_lpd, vpll_to_lpd,
 120        acpu, acpu_half,
 121        dbg_fpd, dbg_lpd, dbg_trace, dbg_tstmp,
 122        dp_video_ref, dp_audio_ref,
 123        dp_stc_ref, gdma_ref, dpdma_ref,
 124        ddr_ref, sata_ref, pcie_ref,
 125        gpu_ref, gpu_pp0_ref, gpu_pp1_ref,
 126        topsw_main, topsw_lsbus,
 127        gtgref0_ref,
 128        lpd_switch, lpd_lsbus,
 129        usb0_bus_ref, usb1_bus_ref, usb3_dual_ref, usb0, usb1,
 130        cpu_r5, cpu_r5_core,
 131        csu_spb, csu_pll, pcap,
 132        iou_switch,
 133        gem_tsu_ref, gem_tsu,
 134        gem0_ref, gem1_ref, gem2_ref, gem3_ref,
 135        gem0_rx, gem1_rx, gem2_rx, gem3_rx,
 136        qspi_ref,
 137        sdio0_ref, sdio1_ref,
 138        uart0_ref, uart1_ref,
 139        spi0_ref, spi1_ref,
 140        nand_ref,
 141        i2c0_ref, i2c1_ref, can0_ref, can1_ref, can0, can1,
 142        dll_ref,
 143        adma_ref,
 144        timestamp_ref,
 145        ams_ref,
 146        pl0, pl1, pl2, pl3,
 147        wdt,
 148        clk_max,
 149};
 150
 151static const char * const clk_names[clk_max] = {
 152        "iopll", "rpll", "apll", "dpll",
 153        "vpll", "iopll_to_fpd", "rpll_to_fpd",
 154        "apll_to_lpd", "dpll_to_lpd", "vpll_to_lpd",
 155        "acpu", "acpu_half", "dbf_fpd", "dbf_lpd",
 156        "dbg_trace", "dbg_tstmp", "dp_video_ref",
 157        "dp_audio_ref", "dp_stc_ref", "gdma_ref",
 158        "dpdma_ref", "ddr_ref", "sata_ref", "pcie_ref",
 159        "gpu_ref", "gpu_pp0_ref", "gpu_pp1_ref",
 160        "topsw_main", "topsw_lsbus", "gtgref0_ref",
 161        "lpd_switch", "lpd_lsbus", "usb0_bus_ref",
 162        "usb1_bus_ref", "usb3_dual_ref", "usb0",
 163        "usb1", "cpu_r5", "cpu_r5_core", "csu_spb",
 164        "csu_pll", "pcap", "iou_switch", "gem_tsu_ref",
 165        "gem_tsu", "gem0_ref", "gem1_ref", "gem2_ref",
 166        "gem3_ref", "gem0_tx", "gem1_tx", "gem2_tx",
 167        "gem3_tx", "qspi_ref", "sdio0_ref", "sdio1_ref",
 168        "uart0_ref", "uart1_ref", "spi0_ref",
 169        "spi1_ref", "nand_ref", "i2c0_ref", "i2c1_ref",
 170        "can0_ref", "can1_ref", "can0", "can1",
 171        "dll_ref", "adma_ref", "timestamp_ref",
 172        "ams_ref", "pl0", "pl1", "pl2", "pl3", "wdt"
 173};
 174
 175struct zynqmp_clk_priv {
 176        unsigned long ps_clk_freq;
 177        unsigned long video_clk;
 178        unsigned long pss_alt_ref_clk;
 179        unsigned long gt_crx_ref_clk;
 180        unsigned long aux_ref_clk;
 181};
 182
 183static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
 184{
 185        switch (id) {
 186        case iopll:
 187                return CRL_APB_IOPLL_CTRL;
 188        case rpll:
 189                return CRL_APB_RPLL_CTRL;
 190        case apll:
 191                return CRF_APB_APLL_CTRL;
 192        case dpll:
 193                return CRF_APB_DPLL_CTRL;
 194        case vpll:
 195                return CRF_APB_VPLL_CTRL;
 196        case acpu:
 197                return CRF_APB_ACPU_CTRL;
 198        case ddr_ref:
 199                return CRF_APB_DDR_CTRL;
 200        case qspi_ref:
 201                return CRL_APB_QSPI_REF_CTRL;
 202        case usb3_dual_ref:
 203                return CRL_APB_USB3_DUAL_REF_CTRL;
 204        case gem0_ref:
 205                return CRL_APB_GEM0_REF_CTRL;
 206        case gem1_ref:
 207                return CRL_APB_GEM1_REF_CTRL;
 208        case gem2_ref:
 209                return CRL_APB_GEM2_REF_CTRL;
 210        case gem3_ref:
 211                return CRL_APB_GEM3_REF_CTRL;
 212        case usb0_bus_ref:
 213                return CRL_APB_USB0_BUS_REF_CTRL;
 214        case usb1_bus_ref:
 215                return CRL_APB_USB1_BUS_REF_CTRL;
 216        case uart0_ref:
 217                return CRL_APB_UART0_REF_CTRL;
 218        case uart1_ref:
 219                return CRL_APB_UART1_REF_CTRL;
 220        case sdio0_ref:
 221                return CRL_APB_SDIO0_REF_CTRL;
 222        case sdio1_ref:
 223                return CRL_APB_SDIO1_REF_CTRL;
 224        case spi0_ref:
 225                return CRL_APB_SPI0_REF_CTRL;
 226        case spi1_ref:
 227                return CRL_APB_SPI1_REF_CTRL;
 228        case nand_ref:
 229                return CRL_APB_NAND_REF_CTRL;
 230        case i2c0_ref:
 231                return CRL_APB_I2C0_REF_CTRL;
 232        case i2c1_ref:
 233                return CRL_APB_I2C1_REF_CTRL;
 234        case can0_ref:
 235                return CRL_APB_CAN0_REF_CTRL;
 236        case can1_ref:
 237                return CRL_APB_CAN1_REF_CTRL;
 238        case pl0:
 239                return CRL_APB_PL0_REF_CTRL;
 240        case pl1:
 241                return CRL_APB_PL1_REF_CTRL;
 242        case pl2:
 243                return CRL_APB_PL2_REF_CTRL;
 244        case pl3:
 245                return CRL_APB_PL3_REF_CTRL;
 246        case wdt:
 247                return CRF_APB_TOPSW_LSBUS_CTRL;
 248        case iopll_to_fpd:
 249                return CRL_APB_IOPLL_TO_FPD_CTRL;
 250        default:
 251                debug("Invalid clk id%d\n", id);
 252        }
 253        return 0;
 254}
 255
 256static enum zynqmp_clk zynqmp_clk_get_cpu_pll(u32 clk_ctrl)
 257{
 258        u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
 259                      CLK_CTRL_SRCSEL_SHIFT;
 260
 261        switch (srcsel) {
 262        case 2:
 263                return dpll;
 264        case 3:
 265                return vpll;
 266        case 0 ... 1:
 267        default:
 268                return apll;
 269        }
 270}
 271
 272static enum zynqmp_clk zynqmp_clk_get_ddr_pll(u32 clk_ctrl)
 273{
 274        u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
 275                      CLK_CTRL_SRCSEL_SHIFT;
 276
 277        switch (srcsel) {
 278        case 1:
 279                return vpll;
 280        case 0:
 281        default:
 282                return dpll;
 283        }
 284}
 285
 286static enum zynqmp_clk zynqmp_clk_get_peripheral_pll(u32 clk_ctrl)
 287{
 288        u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
 289                      CLK_CTRL_SRCSEL_SHIFT;
 290
 291        switch (srcsel) {
 292        case 2:
 293                return rpll;
 294        case 3:
 295                return dpll;
 296        case 0 ... 1:
 297        default:
 298                return iopll;
 299        }
 300}
 301
 302static enum zynqmp_clk zynqmp_clk_get_wdt_pll(u32 clk_ctrl)
 303{
 304        u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
 305                      CLK_CTRL_SRCSEL_SHIFT;
 306
 307        switch (srcsel) {
 308        case 2:
 309                return iopll_to_fpd;
 310        case 3:
 311                return dpll;
 312        case 0 ... 1:
 313        default:
 314                return apll;
 315        }
 316}
 317
 318static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl,
 319                                    struct zynqmp_clk_priv *priv,
 320                                    bool is_pre_src)
 321{
 322        u32 src_sel;
 323
 324        if (is_pre_src)
 325                src_sel = (clk_ctrl & PLLCTRL_PRE_SRC_MASK) >>
 326                           PLLCTRL_PRE_SRC_SHFT;
 327        else
 328                src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >>
 329                           PLLCTRL_POST_SRC_SHFT;
 330
 331        switch (src_sel) {
 332        case 4:
 333                return priv->video_clk;
 334        case 5:
 335                return priv->pss_alt_ref_clk;
 336        case 6:
 337                return priv->aux_ref_clk;
 338        case 7:
 339                return priv->gt_crx_ref_clk;
 340        case 0 ... 3:
 341        default:
 342        return priv->ps_clk_freq;
 343        }
 344}
 345
 346static ulong zynqmp_clk_get_pll_rate(struct zynqmp_clk_priv *priv,
 347                                     enum zynqmp_clk id)
 348{
 349        u32 clk_ctrl, reset, mul;
 350        ulong freq;
 351        int ret;
 352
 353        ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
 354        if (ret) {
 355                printf("%s mio read fail\n", __func__);
 356                return -EIO;
 357        }
 358
 359        if (clk_ctrl & PLLCTRL_BYPASS_MASK)
 360                freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 0);
 361        else
 362                freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 1);
 363
 364        reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
 365        if (reset && !(clk_ctrl & PLLCTRL_BYPASS_MASK))
 366                return 0;
 367
 368        mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
 369
 370        freq *= mul;
 371
 372        if (clk_ctrl & (1 << 16))
 373                freq /= 2;
 374
 375        return freq;
 376}
 377
 378static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
 379                                     enum zynqmp_clk id)
 380{
 381        u32 clk_ctrl, div;
 382        enum zynqmp_clk pll;
 383        int ret;
 384        unsigned long pllrate;
 385
 386        ret = zynqmp_mmio_read(CRF_APB_ACPU_CTRL, &clk_ctrl);
 387        if (ret) {
 388                printf("%s mio read fail\n", __func__);
 389                return -EIO;
 390        }
 391
 392        div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 393
 394        pll = zynqmp_clk_get_cpu_pll(clk_ctrl);
 395        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 396        if (IS_ERR_VALUE(pllrate))
 397                return pllrate;
 398
 399        return DIV_ROUND_CLOSEST(pllrate, div);
 400}
 401
 402static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
 403{
 404        u32 clk_ctrl, div;
 405        enum zynqmp_clk pll;
 406        int ret;
 407        ulong pllrate;
 408
 409        ret = zynqmp_mmio_read(CRF_APB_DDR_CTRL, &clk_ctrl);
 410        if (ret) {
 411                printf("%s mio read fail\n", __func__);
 412                return -EIO;
 413        }
 414
 415        div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 416
 417        pll = zynqmp_clk_get_ddr_pll(clk_ctrl);
 418        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 419        if (IS_ERR_VALUE(pllrate))
 420                return pllrate;
 421
 422        return DIV_ROUND_CLOSEST(pllrate, div);
 423}
 424
 425static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
 426                                          enum zynqmp_clk id, bool two_divs)
 427{
 428        enum zynqmp_clk pll;
 429        u32 clk_ctrl, div0;
 430        u32 div1 = 1;
 431        int ret;
 432        ulong pllrate;
 433
 434        ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
 435        if (ret) {
 436                printf("%s mio read fail\n", __func__);
 437                return -EIO;
 438        }
 439
 440        div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 441        if (!div0)
 442                div0 = 1;
 443
 444        if (two_divs) {
 445                div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
 446                if (!div1)
 447                        div1 = 1;
 448        }
 449
 450        pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
 451        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 452        if (IS_ERR_VALUE(pllrate))
 453                return pllrate;
 454
 455        return
 456                DIV_ROUND_CLOSEST(
 457                        DIV_ROUND_CLOSEST(pllrate, div0), div1);
 458}
 459
 460static ulong zynqmp_clk_get_wdt_rate(struct zynqmp_clk_priv *priv,
 461                                     enum zynqmp_clk id, bool two_divs)
 462{
 463        enum zynqmp_clk pll;
 464        u32 clk_ctrl, div0;
 465        u32 div1 = 1;
 466        int ret;
 467        ulong pllrate;
 468
 469        ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
 470        if (ret) {
 471                printf("%d %s mio read fail\n", __LINE__, __func__);
 472                return -EIO;
 473        }
 474
 475        div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 476        if (!div0)
 477                div0 = 1;
 478
 479        pll = zynqmp_clk_get_wdt_pll(clk_ctrl);
 480        if (two_divs) {
 481                ret = zynqmp_mmio_read(zynqmp_clk_get_register(pll), &clk_ctrl);
 482                if (ret) {
 483                        printf("%d %s mio read fail\n", __LINE__, __func__);
 484                        return -EIO;
 485                }
 486                div1 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
 487                if (!div1)
 488                        div1 = 1;
 489        }
 490
 491        if (pll == iopll_to_fpd)
 492                pll = iopll;
 493
 494        pllrate = zynqmp_clk_get_pll_rate(priv, pll);
 495        if (IS_ERR_VALUE(pllrate))
 496                return pllrate;
 497
 498        return
 499                DIV_ROUND_CLOSEST(
 500                        DIV_ROUND_CLOSEST(pllrate, div0), div1);
 501}
 502
 503static unsigned long zynqmp_clk_calc_peripheral_two_divs(ulong rate,
 504                                                       ulong pll_rate,
 505                                                       u32 *div0, u32 *div1)
 506{
 507        long new_err, best_err = (long)(~0UL >> 1);
 508        ulong new_rate, best_rate = 0;
 509        u32 d0, d1;
 510
 511        for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
 512                for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
 513                        new_rate = DIV_ROUND_CLOSEST(
 514                                        DIV_ROUND_CLOSEST(pll_rate, d0), d1);
 515                        new_err = abs(new_rate - rate);
 516
 517                        if (new_err < best_err) {
 518                                *div0 = d0;
 519                                *div1 = d1;
 520                                best_err = new_err;
 521                                best_rate = new_rate;
 522                        }
 523                }
 524        }
 525
 526        return best_rate;
 527}
 528
 529static ulong zynqmp_clk_set_peripheral_rate(struct zynqmp_clk_priv *priv,
 530                                          enum zynqmp_clk id, ulong rate,
 531                                          bool two_divs)
 532{
 533        enum zynqmp_clk pll;
 534        u32 clk_ctrl, div0 = 0, div1 = 0;
 535        ulong pll_rate, new_rate;
 536        u32 reg;
 537        int ret;
 538        u32 mask;
 539
 540        reg = zynqmp_clk_get_register(id);
 541        ret = zynqmp_mmio_read(reg, &clk_ctrl);
 542        if (ret) {
 543                printf("%s mio read fail\n", __func__);
 544                return -EIO;
 545        }
 546
 547        pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
 548        pll_rate = zynqmp_clk_get_pll_rate(priv, pll);
 549        if (IS_ERR_VALUE(pll_rate))
 550                return pll_rate;
 551
 552        clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
 553        if (two_divs) {
 554                clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
 555                new_rate = zynqmp_clk_calc_peripheral_two_divs(rate, pll_rate,
 556                                &div0, &div1);
 557                clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
 558        } else {
 559                div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
 560                if (div0 > ZYNQ_CLK_MAXDIV)
 561                        div0 = ZYNQ_CLK_MAXDIV;
 562                new_rate = DIV_ROUND_CLOSEST(rate, div0);
 563        }
 564        clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
 565
 566        mask = (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) |
 567               (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT);
 568
 569        ret = zynqmp_mmio_write(reg, mask, clk_ctrl);
 570        if (ret) {
 571                printf("%s mio write fail\n", __func__);
 572                return -EIO;
 573        }
 574
 575        return new_rate;
 576}
 577
 578static ulong zynqmp_clk_get_rate(struct clk *clk)
 579{
 580        struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
 581        enum zynqmp_clk id = clk->id;
 582        bool two_divs = false;
 583
 584        switch (id) {
 585        case iopll ... vpll:
 586                return zynqmp_clk_get_pll_rate(priv, id);
 587        case acpu:
 588                return zynqmp_clk_get_cpu_rate(priv, id);
 589        case ddr_ref:
 590                return zynqmp_clk_get_ddr_rate(priv);
 591        case gem0_ref ... gem3_ref:
 592        case qspi_ref ... can1_ref:
 593        case pl0 ... pl3:
 594                two_divs = true;
 595                return zynqmp_clk_get_peripheral_rate(priv, id, two_divs);
 596        case wdt:
 597                two_divs = true;
 598                return zynqmp_clk_get_wdt_rate(priv, id, two_divs);
 599        default:
 600                return -ENXIO;
 601        }
 602}
 603
 604static ulong zynqmp_clk_set_rate(struct clk *clk, ulong rate)
 605{
 606        struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
 607        enum zynqmp_clk id = clk->id;
 608        bool two_divs = true;
 609
 610        switch (id) {
 611        case gem0_ref ... gem3_ref:
 612        case qspi_ref ... can1_ref:
 613                return zynqmp_clk_set_peripheral_rate(priv, id,
 614                                                      rate, two_divs);
 615        default:
 616                return -ENXIO;
 617        }
 618}
 619
 620int soc_clk_dump(void)
 621{
 622        struct udevice *dev;
 623        int i, ret;
 624
 625        ret = uclass_get_device_by_driver(UCLASS_CLK,
 626                DM_DRIVER_GET(zynqmp_clk), &dev);
 627        if (ret)
 628                return ret;
 629
 630        printf("clk\t\tfrequency\n");
 631        for (i = 0; i < clk_max; i++) {
 632                const char *name = clk_names[i];
 633                if (name) {
 634                        struct clk clk;
 635                        unsigned long rate;
 636
 637                        clk.id = i;
 638                        ret = clk_request(dev, &clk);
 639                        if (ret < 0)
 640                                return ret;
 641
 642                        rate = clk_get_rate(&clk);
 643
 644                        clk_free(&clk);
 645
 646                        if ((rate == (unsigned long)-ENOSYS) ||
 647                            (rate == (unsigned long)-ENXIO) ||
 648                            (rate == (unsigned long)-EIO))
 649                                printf("%10s%20s\n", name, "unknown");
 650                        else
 651                                printf("%10s%20lu\n", name, rate);
 652                }
 653        }
 654
 655        return 0;
 656}
 657
 658static int zynqmp_get_freq_by_name(char *name, struct udevice *dev, ulong *freq)
 659{
 660        struct clk clk;
 661        int ret;
 662
 663        ret = clk_get_by_name(dev, name, &clk);
 664        if (ret < 0) {
 665                dev_err(dev, "failed to get %s\n", name);
 666                return ret;
 667        }
 668
 669        *freq = clk_get_rate(&clk);
 670        if (IS_ERR_VALUE(*freq)) {
 671                dev_err(dev, "failed to get rate %s\n", name);
 672                return -EINVAL;
 673        }
 674
 675        return 0;
 676}
 677static int zynqmp_clk_probe(struct udevice *dev)
 678{
 679        int ret;
 680        struct zynqmp_clk_priv *priv = dev_get_priv(dev);
 681
 682        debug("%s\n", __func__);
 683        ret = zynqmp_get_freq_by_name("pss_ref_clk", dev, &priv->ps_clk_freq);
 684        if (ret < 0)
 685                return -EINVAL;
 686
 687        ret = zynqmp_get_freq_by_name("video_clk", dev, &priv->video_clk);
 688        if (ret < 0)
 689                return -EINVAL;
 690
 691        ret = zynqmp_get_freq_by_name("pss_alt_ref_clk", dev,
 692                                      &priv->pss_alt_ref_clk);
 693        if (ret < 0)
 694                return -EINVAL;
 695
 696        ret = zynqmp_get_freq_by_name("aux_ref_clk", dev, &priv->aux_ref_clk);
 697        if (ret < 0)
 698                return -EINVAL;
 699
 700        ret = zynqmp_get_freq_by_name("gt_crx_ref_clk", dev,
 701                                      &priv->gt_crx_ref_clk);
 702        if (ret < 0)
 703                return -EINVAL;
 704
 705        return 0;
 706}
 707
 708static int zynqmp_clk_enable(struct clk *clk)
 709{
 710        enum zynqmp_clk id = clk->id;
 711        u32 reg, clk_ctrl, clkact_shift, mask;
 712        int ret;
 713
 714        reg = zynqmp_clk_get_register(id);
 715        debug("%s, clk_id:%x, clk_base:0x%x\n", __func__, id, reg);
 716
 717        switch (id) {
 718        case usb0_bus_ref ... usb1:
 719                clkact_shift = 25;
 720                mask = 0x1;
 721                break;
 722        case gem0_ref ... gem3_ref:
 723                clkact_shift = 25;
 724                mask = 0x3;
 725                break;
 726        case qspi_ref ... can1_ref:
 727                clkact_shift = 24;
 728                mask = 0x1;
 729                break;
 730        default:
 731                return -ENXIO;
 732        }
 733
 734        ret = zynqmp_mmio_read(reg, &clk_ctrl);
 735        if (ret) {
 736                printf("%s mio read fail\n", __func__);
 737                return -EIO;
 738        }
 739
 740        clk_ctrl |= (mask << clkact_shift);
 741        ret = zynqmp_mmio_write(reg, mask << clkact_shift, clk_ctrl);
 742        if (ret) {
 743                printf("%s mio write fail\n", __func__);
 744                return -EIO;
 745        }
 746
 747        return ret;
 748}
 749
 750static struct clk_ops zynqmp_clk_ops = {
 751        .set_rate = zynqmp_clk_set_rate,
 752        .get_rate = zynqmp_clk_get_rate,
 753        .enable = zynqmp_clk_enable,
 754};
 755
 756static const struct udevice_id zynqmp_clk_ids[] = {
 757        { .compatible = "xlnx,zynqmp-clk" },
 758        { }
 759};
 760
 761U_BOOT_DRIVER(zynqmp_clk) = {
 762        .name = "zynqmp_clk",
 763        .id = UCLASS_CLK,
 764        .of_match = zynqmp_clk_ids,
 765        .probe = zynqmp_clk_probe,
 766        .ops = &zynqmp_clk_ops,
 767        .priv_auto      = sizeof(struct zynqmp_clk_priv),
 768};
 769