uboot/drivers/clk/clk-hsdk-cgu.c
<<
>>
Prefs
   1/*
   2 * Synopsys HSDK SDP CGU clock driver
   3 *
   4 * Copyright (C) 2017 Synopsys
   5 * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
   6 *
   7 * This file is licensed under the terms of the GNU General Public
   8 * License version 2. This program is licensed "as is" without any
   9 * warranty of any kind, whether express or implied.
  10 */
  11
  12#include <common.h>
  13#include <clk-uclass.h>
  14#include <div64.h>
  15#include <dm.h>
  16#include <linux/io.h>
  17
  18/*
  19 * Synopsys ARC HSDK clock tree.
  20 *
  21 *   ------------------
  22 *   | 33.33 MHz xtal |
  23 *   ------------------
  24 *            |
  25 *            |   -----------
  26 *            |-->| ARC PLL |
  27 *            |   -----------
  28 *            |        |
  29 *            |        |-->|CGU_ARC_IDIV|----------->
  30 *            |        |-->|CREG_CORE_IF_DIV|------->
  31 *            |
  32 *            |   --------------
  33 *            |-->| SYSTEM PLL |
  34 *            |   --------------
  35 *            |        |
  36 *            |        |-->|CGU_SYS_IDIV_APB|------->
  37 *            |        |-->|CGU_SYS_IDIV_AXI|------->
  38 *            |        |-->|CGU_SYS_IDIV_*|--------->
  39 *            |        |-->|CGU_SYS_IDIV_EBI_REF|--->
  40 *            |
  41 *            |   --------------
  42 *            |-->| TUNNEL PLL |
  43 *            |   --------------
  44 *            |        |
  45 *            |        |-->|CGU_TUN_IDIV_TUN|----------->
  46 *            |        |-->|CGU_TUN_IDIV_ROM|----------->
  47 *            |        |-->|CGU_TUN_IDIV_PWM|----------->
  48 *            |
  49 *            |   ------------
  50 *            |-->| HDMI PLL |
  51 *            |   ------------
  52 *            |        |
  53 *            |        |-->|CGU_HDMI_IDIV_APB|------>
  54 *            |
  55 *            |   -----------
  56 *            |-->| DDR PLL |
  57 *                -----------
  58 *                     |
  59 *                     |---------------------------->
  60 */
  61
  62#define CGU_ARC_IDIV            0x080
  63#define CGU_TUN_IDIV_TUN        0x380
  64#define CGU_TUN_IDIV_ROM        0x390
  65#define CGU_TUN_IDIV_PWM        0x3A0
  66#define CGU_HDMI_IDIV_APB       0x480
  67#define CGU_SYS_IDIV_APB        0x180
  68#define CGU_SYS_IDIV_AXI        0x190
  69#define CGU_SYS_IDIV_ETH        0x1A0
  70#define CGU_SYS_IDIV_USB        0x1B0
  71#define CGU_SYS_IDIV_SDIO       0x1C0
  72#define CGU_SYS_IDIV_HDMI       0x1D0
  73#define CGU_SYS_IDIV_GFX_CORE   0x1E0
  74#define CGU_SYS_IDIV_GFX_DMA    0x1F0
  75#define CGU_SYS_IDIV_GFX_CFG    0x200
  76#define CGU_SYS_IDIV_DMAC_CORE  0x210
  77#define CGU_SYS_IDIV_DMAC_CFG   0x220
  78#define CGU_SYS_IDIV_SDIO_REF   0x230
  79#define CGU_SYS_IDIV_SPI_REF    0x240
  80#define CGU_SYS_IDIV_I2C_REF    0x250
  81#define CGU_SYS_IDIV_UART_REF   0x260
  82#define CGU_SYS_IDIV_EBI_REF    0x270
  83
  84#define CGU_IDIV_MASK           0xFF /* All idiv have 8 significant bits */
  85
  86#define CGU_ARC_PLL             0x0
  87#define CGU_SYS_PLL             0x10
  88#define CGU_DDR_PLL             0x20
  89#define CGU_TUN_PLL             0x30
  90#define CGU_HDMI_PLL            0x40
  91
  92#define CGU_PLL_CTRL            0x000 /* ARC PLL control register */
  93#define CGU_PLL_STATUS          0x004 /* ARC PLL status register */
  94#define CGU_PLL_FMEAS           0x008 /* ARC PLL frequency measurement register */
  95#define CGU_PLL_MON             0x00C /* ARC PLL monitor register */
  96
  97#define CGU_PLL_CTRL_ODIV_SHIFT         2
  98#define CGU_PLL_CTRL_IDIV_SHIFT         4
  99#define CGU_PLL_CTRL_FBDIV_SHIFT        9
 100#define CGU_PLL_CTRL_BAND_SHIFT         20
 101
 102#define CGU_PLL_CTRL_ODIV_MASK          GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT)
 103#define CGU_PLL_CTRL_IDIV_MASK          GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT)
 104#define CGU_PLL_CTRL_FBDIV_MASK         GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT)
 105
 106#define CGU_PLL_CTRL_PD                 BIT(0)
 107#define CGU_PLL_CTRL_BYPASS             BIT(1)
 108
 109#define CGU_PLL_STATUS_LOCK             BIT(0)
 110#define CGU_PLL_STATUS_ERR              BIT(1)
 111
 112#define HSDK_PLL_MAX_LOCK_TIME          100 /* 100 us */
 113
 114#define CREG_CORE_IF_DIV                0x000 /* ARC CORE interface divider */
 115#define CORE_IF_CLK_THRESHOLD_HZ        500000000
 116#define CREG_CORE_IF_CLK_DIV_1          0x0
 117#define CREG_CORE_IF_CLK_DIV_2          0x1
 118
 119#define MIN_PLL_RATE                    100000000 /* 100 MHz */
 120#define PARENT_RATE                     33333333 /* fixed clock - xtal */
 121#define CGU_MAX_CLOCKS                  26
 122
 123#define CGU_SYS_CLOCKS                  16
 124#define MAX_AXI_CLOCKS                  4
 125
 126#define CGU_TUN_CLOCKS                  3
 127#define MAX_TUN_CLOCKS                  6
 128
 129struct hsdk_tun_idiv_cfg {
 130        u32 oft;
 131        u8  val[MAX_TUN_CLOCKS];
 132};
 133
 134struct hsdk_tun_clk_cfg {
 135        const u32 clk_rate[MAX_TUN_CLOCKS];
 136        const u32 pll_rate[MAX_TUN_CLOCKS];
 137        const struct hsdk_tun_idiv_cfg idiv[CGU_TUN_CLOCKS];
 138};
 139
 140static const struct hsdk_tun_clk_cfg tun_clk_cfg = {
 141        { 25000000,  50000000,  75000000,  100000000, 125000000, 150000000 },
 142        { 600000000, 600000000, 600000000, 600000000, 700000000, 600000000 }, {
 143        { CGU_TUN_IDIV_TUN,     { 24,   12,     8,      6,      6,      4 } },
 144        { CGU_TUN_IDIV_ROM,     { 4,    4,      4,      4,      5,      4 } },
 145        { CGU_TUN_IDIV_PWM,     { 8,    8,      8,      8,      10,     8 } }
 146        }
 147};
 148
 149struct hsdk_sys_idiv_cfg {
 150        u32 oft;
 151        u8  val[MAX_AXI_CLOCKS];
 152};
 153
 154struct hsdk_axi_clk_cfg {
 155        const u32 clk_rate[MAX_AXI_CLOCKS];
 156        const u32 pll_rate[MAX_AXI_CLOCKS];
 157        const struct hsdk_sys_idiv_cfg idiv[CGU_SYS_CLOCKS];
 158};
 159
 160static const struct hsdk_axi_clk_cfg axi_clk_cfg = {
 161        { 200000000,    400000000,      600000000,      800000000 },
 162        { 800000000,    800000000,      600000000,      800000000 }, {
 163        { CGU_SYS_IDIV_APB,      { 4,   4,      3,      4 } },  /* APB */
 164        { CGU_SYS_IDIV_AXI,      { 4,   2,      1,      1 } },  /* AXI */
 165        { CGU_SYS_IDIV_ETH,      { 2,   2,      2,      2 } },  /* ETH */
 166        { CGU_SYS_IDIV_USB,      { 2,   2,      2,      2 } },  /* USB */
 167        { CGU_SYS_IDIV_SDIO,     { 2,   2,      2,      2 } },  /* SDIO */
 168        { CGU_SYS_IDIV_HDMI,     { 2,   2,      2,      2 } },  /* HDMI */
 169        { CGU_SYS_IDIV_GFX_CORE, { 1,   1,      1,      1 } },  /* GPU-CORE */
 170        { CGU_SYS_IDIV_GFX_DMA,  { 2,   2,      2,      2 } },  /* GPU-DMA */
 171        { CGU_SYS_IDIV_GFX_CFG,  { 4,   4,      3,      4 } },  /* GPU-CFG */
 172        { CGU_SYS_IDIV_DMAC_CORE,{ 2,   2,      2,      2 } },  /* DMAC-CORE */
 173        { CGU_SYS_IDIV_DMAC_CFG, { 4,   4,      3,      4 } },  /* DMAC-CFG */
 174        { CGU_SYS_IDIV_SDIO_REF, { 8,   8,      6,      8 } },  /* SDIO-REF */
 175        { CGU_SYS_IDIV_SPI_REF,  { 24,  24,     18,     24 } }, /* SPI-REF */
 176        { CGU_SYS_IDIV_I2C_REF,  { 4,   4,      3,      4 } },  /* I2C-REF */
 177        { CGU_SYS_IDIV_UART_REF, { 24,  24,     18,     24 } }, /* UART-REF */
 178        { CGU_SYS_IDIV_EBI_REF,  { 16,  16,     12,     16 } }  /* EBI-REF */
 179        }
 180};
 181
 182struct hsdk_pll_cfg {
 183        u32 rate;
 184        u32 idiv;
 185        u32 fbdiv;
 186        u32 odiv;
 187        u32 band;
 188};
 189
 190static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
 191        { 100000000,  0, 11, 3, 0 },
 192        { 125000000,  0, 14, 3, 0 },
 193        { 133000000,  0, 15, 3, 0 },
 194        { 150000000,  0, 17, 3, 0 },
 195        { 200000000,  1, 47, 3, 0 },
 196        { 233000000,  1, 27, 2, 0 },
 197        { 300000000,  1, 35, 2, 0 },
 198        { 333000000,  1, 39, 2, 0 },
 199        { 400000000,  1, 47, 2, 0 },
 200        { 500000000,  0, 14, 1, 0 },
 201        { 600000000,  0, 17, 1, 0 },
 202        { 700000000,  0, 20, 1, 0 },
 203        { 800000000,  0, 23, 1, 0 },
 204        { 900000000,  1, 26, 0, 0 },
 205        { 1000000000, 1, 29, 0, 0 },
 206        { 1100000000, 1, 32, 0, 0 },
 207        { 1200000000, 1, 35, 0, 0 },
 208        { 1300000000, 1, 38, 0, 0 },
 209        { 1400000000, 1, 41, 0, 0 },
 210        { 1500000000, 1, 44, 0, 0 },
 211        { 1600000000, 1, 47, 0, 0 },
 212        {}
 213};
 214
 215static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
 216        { 297000000,  0, 21, 2, 0 },
 217        { 540000000,  0, 19, 1, 0 },
 218        { 594000000,  0, 21, 1, 0 },
 219        {}
 220};
 221
 222struct hsdk_cgu_clk {
 223        /* CGU block register */
 224        void __iomem *cgu_regs;
 225        /* CREG block register */
 226        void __iomem *creg_regs;
 227
 228        /* PLLs registers */
 229        void __iomem *regs;
 230        /* PLLs special registers */
 231        void __iomem *spec_regs;
 232        /* PLLs devdata */
 233        const struct hsdk_pll_devdata *pll_devdata;
 234
 235        /* Dividers registers */
 236        void __iomem *idiv_regs;
 237};
 238
 239struct hsdk_pll_devdata {
 240        const struct hsdk_pll_cfg *pll_cfg;
 241        int (*update_rate)(struct hsdk_cgu_clk *clk, unsigned long rate,
 242                           const struct hsdk_pll_cfg *cfg);
 243};
 244
 245static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *, unsigned long,
 246                                     const struct hsdk_pll_cfg *);
 247static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *, unsigned long,
 248                                     const struct hsdk_pll_cfg *);
 249
 250static const struct hsdk_pll_devdata core_pll_dat = {
 251        .pll_cfg = asdt_pll_cfg,
 252        .update_rate = hsdk_pll_core_update_rate,
 253};
 254
 255static const struct hsdk_pll_devdata sdt_pll_dat = {
 256        .pll_cfg = asdt_pll_cfg,
 257        .update_rate = hsdk_pll_comm_update_rate,
 258};
 259
 260static const struct hsdk_pll_devdata hdmi_pll_dat = {
 261        .pll_cfg = hdmi_pll_cfg,
 262        .update_rate = hsdk_pll_comm_update_rate,
 263};
 264
 265static ulong idiv_set(struct clk *, ulong);
 266static ulong cpu_clk_set(struct clk *, ulong);
 267static ulong axi_clk_set(struct clk *, ulong);
 268static ulong tun_clk_set(struct clk *, ulong);
 269static ulong idiv_get(struct clk *);
 270static int idiv_off(struct clk *);
 271static ulong pll_set(struct clk *, ulong);
 272static ulong pll_get(struct clk *);
 273
 274struct hsdk_cgu_clock_map {
 275        u32 cgu_pll_oft;
 276        u32 creg_div_oft;
 277        u32 cgu_div_oft;
 278        const struct hsdk_pll_devdata *pll_devdata;
 279        ulong (*get_rate)(struct clk *clk);
 280        ulong (*set_rate)(struct clk *clk, ulong rate);
 281        int (*disable)(struct clk *clk);
 282};
 283
 284static const struct hsdk_cgu_clock_map clock_map[] = {
 285        { CGU_ARC_PLL, 0, 0, &core_pll_dat, pll_get, pll_set, NULL },
 286        { CGU_ARC_PLL, 0, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
 287        { CGU_DDR_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
 288        { CGU_SYS_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
 289        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 290        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
 291        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 292        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 293        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 294        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 295        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 296        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 297        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 298        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 299        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 300        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 301        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 302        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 303        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 304        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 305        { CGU_TUN_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
 306        { CGU_TUN_PLL, 0, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off },
 307        { CGU_TUN_PLL, 0, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 308        { CGU_TUN_PLL, 0, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
 309        { CGU_HDMI_PLL, 0, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
 310        { CGU_HDMI_PLL, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
 311};
 312
 313static inline void hsdk_idiv_write(struct hsdk_cgu_clk *clk, u32 val)
 314{
 315        iowrite32(val, clk->idiv_regs);
 316}
 317
 318static inline u32 hsdk_idiv_read(struct hsdk_cgu_clk *clk)
 319{
 320        return ioread32(clk->idiv_regs);
 321}
 322
 323static inline void hsdk_pll_write(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
 324{
 325        iowrite32(val, clk->regs + reg);
 326}
 327
 328static inline u32 hsdk_pll_read(struct hsdk_cgu_clk *clk, u32 reg)
 329{
 330        return ioread32(clk->regs + reg);
 331}
 332
 333static inline void hsdk_pll_spcwrite(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
 334{
 335        iowrite32(val, clk->spec_regs + reg);
 336}
 337
 338static inline u32 hsdk_pll_spcread(struct hsdk_cgu_clk *clk, u32 reg)
 339{
 340        return ioread32(clk->spec_regs + reg);
 341}
 342
 343static inline void hsdk_pll_set_cfg(struct hsdk_cgu_clk *clk,
 344                                    const struct hsdk_pll_cfg *cfg)
 345{
 346        u32 val = 0;
 347
 348        /* Powerdown and Bypass bits should be cleared */
 349        val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
 350        val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
 351        val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
 352        val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
 353
 354        pr_debug("write configurarion: %#x\n", val);
 355
 356        hsdk_pll_write(clk, CGU_PLL_CTRL, val);
 357}
 358
 359static inline bool hsdk_pll_is_locked(struct hsdk_cgu_clk *clk)
 360{
 361        return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK);
 362}
 363
 364static inline bool hsdk_pll_is_err(struct hsdk_cgu_clk *clk)
 365{
 366        return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR);
 367}
 368
 369static ulong pll_get(struct clk *sclk)
 370{
 371        u32 val;
 372        u64 rate;
 373        u32 idiv, fbdiv, odiv;
 374        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 375
 376        val = hsdk_pll_read(clk, CGU_PLL_CTRL);
 377
 378        pr_debug("current configurarion: %#x\n", val);
 379
 380        /* Check if PLL is disabled */
 381        if (val & CGU_PLL_CTRL_PD)
 382                return 0;
 383
 384        /* Check if PLL is bypassed */
 385        if (val & CGU_PLL_CTRL_BYPASS)
 386                return PARENT_RATE;
 387
 388        /* input divider = reg.idiv + 1 */
 389        idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT);
 390        /* fb divider = 2*(reg.fbdiv + 1) */
 391        fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT));
 392        /* output divider = 2^(reg.odiv) */
 393        odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT);
 394
 395        rate = (u64)PARENT_RATE * fbdiv;
 396        do_div(rate, idiv * odiv);
 397
 398        return rate;
 399}
 400
 401static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate)
 402{
 403        int i;
 404        unsigned long best_rate;
 405        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 406        const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
 407
 408        if (pll_cfg[0].rate == 0)
 409                return -EINVAL;
 410
 411        best_rate = pll_cfg[0].rate;
 412
 413        for (i = 1; pll_cfg[i].rate != 0; i++) {
 414                if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
 415                        best_rate = pll_cfg[i].rate;
 416        }
 417
 418        pr_debug("chosen best rate: %lu\n", best_rate);
 419
 420        return best_rate;
 421}
 422
 423static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *clk,
 424                                     unsigned long rate,
 425                                     const struct hsdk_pll_cfg *cfg)
 426{
 427        hsdk_pll_set_cfg(clk, cfg);
 428
 429        /*
 430         * Wait until CGU relocks and check error status.
 431         * If after timeout CGU is unlocked yet return error.
 432         */
 433        udelay(HSDK_PLL_MAX_LOCK_TIME);
 434        if (!hsdk_pll_is_locked(clk))
 435                return -ETIMEDOUT;
 436
 437        if (hsdk_pll_is_err(clk))
 438                return -EINVAL;
 439
 440        return 0;
 441}
 442
 443static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *clk,
 444                                     unsigned long rate,
 445                                     const struct hsdk_pll_cfg *cfg)
 446{
 447        /*
 448         * When core clock exceeds 500MHz, the divider for the interface
 449         * clock must be programmed to div-by-2.
 450         */
 451        if (rate > CORE_IF_CLK_THRESHOLD_HZ)
 452                hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_2);
 453
 454        hsdk_pll_set_cfg(clk, cfg);
 455
 456        /*
 457         * Wait until CGU relocks and check error status.
 458         * If after timeout CGU is unlocked yet return error.
 459         */
 460        udelay(HSDK_PLL_MAX_LOCK_TIME);
 461        if (!hsdk_pll_is_locked(clk))
 462                return -ETIMEDOUT;
 463
 464        if (hsdk_pll_is_err(clk))
 465                return -EINVAL;
 466
 467        /*
 468         * Program divider to div-by-1 if we succesfuly set core clock below
 469         * 500MHz threshold.
 470         */
 471        if (rate <= CORE_IF_CLK_THRESHOLD_HZ)
 472                hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_1);
 473
 474        return 0;
 475}
 476
 477static ulong pll_set(struct clk *sclk, ulong rate)
 478{
 479        int i;
 480        unsigned long best_rate;
 481        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 482        const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
 483
 484        best_rate = hsdk_pll_round_rate(sclk, rate);
 485
 486        for (i = 0; pll_cfg[i].rate != 0; i++) {
 487                if (pll_cfg[i].rate == best_rate) {
 488                        return clk->pll_devdata->update_rate(clk, best_rate,
 489                                                             &pll_cfg[i]);
 490                }
 491        }
 492
 493        pr_err("invalid rate=%ld Hz, parent_rate=%d Hz\n", best_rate, PARENT_RATE);
 494
 495        return -EINVAL;
 496}
 497
 498static int idiv_off(struct clk *sclk)
 499{
 500        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 501
 502        hsdk_idiv_write(clk, 0);
 503
 504        return 0;
 505}
 506
 507static ulong idiv_get(struct clk *sclk)
 508{
 509        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 510        ulong parent_rate = pll_get(sclk);
 511        u32 div_factor = hsdk_idiv_read(clk);
 512
 513        div_factor &= CGU_IDIV_MASK;
 514
 515        pr_debug("current configurarion: %#x (%d)\n", div_factor, div_factor);
 516
 517        if (div_factor == 0)
 518                return 0;
 519
 520        return parent_rate / div_factor;
 521}
 522
 523/* Special behavior: wen we set this clock we set both idiv and pll */
 524static ulong cpu_clk_set(struct clk *sclk, ulong rate)
 525{
 526        ulong ret;
 527
 528        ret = pll_set(sclk, rate);
 529        idiv_set(sclk, rate);
 530
 531        return ret;
 532}
 533
 534/* Special behavior: wen we set this clock we set both idiv and pll and all pll dividers */
 535static ulong axi_clk_set(struct clk *sclk, ulong rate)
 536{
 537        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 538        ulong pll_rate;
 539        int i, freq_idx = -1;
 540        ulong ret = 0;
 541
 542        pll_rate = pll_get(sclk);
 543
 544        for (i = 0; i < MAX_AXI_CLOCKS; i++) {
 545                if (axi_clk_cfg.clk_rate[i] == rate) {
 546                        freq_idx = i;
 547                        break;
 548                }
 549        }
 550
 551        if (freq_idx < 0) {
 552                pr_err("axi clk: invalid rate=%ld Hz\n", rate);
 553                return -EINVAL;
 554        }
 555
 556        /* configure PLL before dividers */
 557        if (axi_clk_cfg.pll_rate[freq_idx] < pll_rate)
 558                ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
 559
 560        /* configure SYS dividers */
 561        for (i = 0; i < CGU_SYS_CLOCKS; i++) {
 562                clk->idiv_regs = clk->cgu_regs + axi_clk_cfg.idiv[i].oft;
 563                hsdk_idiv_write(clk, axi_clk_cfg.idiv[i].val[freq_idx]);
 564        }
 565
 566        /* configure PLL after dividers */
 567        if (axi_clk_cfg.pll_rate[freq_idx] >= pll_rate)
 568                ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
 569
 570        return ret;
 571}
 572
 573static ulong tun_clk_set(struct clk *sclk, ulong rate)
 574{
 575        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 576        ulong pll_rate;
 577        int i, freq_idx = -1;
 578        ulong ret = 0;
 579
 580        pll_rate = pll_get(sclk);
 581
 582        for (i = 0; i < MAX_TUN_CLOCKS; i++) {
 583                if (tun_clk_cfg.clk_rate[i] == rate) {
 584                        freq_idx = i;
 585                        break;
 586                }
 587        }
 588
 589        if (freq_idx < 0) {
 590                pr_err("tun clk: invalid rate=%ld Hz\n", rate);
 591                return -EINVAL;
 592        }
 593
 594        /* configure PLL before dividers */
 595        if (tun_clk_cfg.pll_rate[freq_idx] < pll_rate)
 596                ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
 597
 598        /* configure SYS dividers */
 599        for (i = 0; i < CGU_TUN_CLOCKS; i++) {
 600                clk->idiv_regs = clk->cgu_regs + tun_clk_cfg.idiv[i].oft;
 601                hsdk_idiv_write(clk, tun_clk_cfg.idiv[i].val[freq_idx]);
 602        }
 603
 604        /* configure PLL after dividers */
 605        if (tun_clk_cfg.pll_rate[freq_idx] >= pll_rate)
 606                ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
 607
 608        return ret;
 609}
 610
 611static ulong idiv_set(struct clk *sclk, ulong rate)
 612{
 613        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 614        ulong parent_rate = pll_get(sclk);
 615        u32 div_factor;
 616
 617        div_factor = parent_rate / rate;
 618        if (abs(rate - parent_rate / (div_factor + 1)) <=
 619            abs(rate - parent_rate / div_factor)) {
 620                div_factor += 1;
 621        }
 622
 623        if (div_factor & ~CGU_IDIV_MASK) {
 624                pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: max divider valie is%d\n",
 625                       rate, parent_rate, div_factor, CGU_IDIV_MASK);
 626
 627                div_factor = CGU_IDIV_MASK;
 628        }
 629
 630        if (div_factor == 0) {
 631                pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: min divider valie is 1\n",
 632                       rate, parent_rate, div_factor);
 633
 634                div_factor = 1;
 635        }
 636
 637        hsdk_idiv_write(clk, div_factor);
 638
 639        return 0;
 640}
 641
 642static int hsdk_prepare_clock_tree_branch(struct clk *sclk)
 643{
 644        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
 645
 646        if (sclk->id >= CGU_MAX_CLOCKS)
 647                return -EINVAL;
 648
 649        clk->pll_devdata = clock_map[sclk->id].pll_devdata;
 650        clk->regs = clk->cgu_regs + clock_map[sclk->id].cgu_pll_oft;
 651        clk->spec_regs = clk->creg_regs + clock_map[sclk->id].creg_div_oft;
 652        clk->idiv_regs = clk->cgu_regs + clock_map[sclk->id].cgu_div_oft;
 653
 654        return 0;
 655}
 656
 657static ulong hsdk_cgu_get_rate(struct clk *sclk)
 658{
 659        if (hsdk_prepare_clock_tree_branch(sclk))
 660                return -EINVAL;
 661
 662        return clock_map[sclk->id].get_rate(sclk);
 663}
 664
 665static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate)
 666{
 667        if (hsdk_prepare_clock_tree_branch(sclk))
 668                return -EINVAL;
 669
 670        return clock_map[sclk->id].set_rate(sclk, rate);
 671}
 672
 673static int hsdk_cgu_disable(struct clk *sclk)
 674{
 675        if (hsdk_prepare_clock_tree_branch(sclk))
 676                return -EINVAL;
 677
 678        if (clock_map[sclk->id].disable)
 679                return clock_map[sclk->id].disable(sclk);
 680
 681        return -ENOTSUPP;
 682}
 683
 684static const struct clk_ops hsdk_cgu_ops = {
 685        .set_rate = hsdk_cgu_set_rate,
 686        .get_rate = hsdk_cgu_get_rate,
 687        .disable = hsdk_cgu_disable,
 688};
 689
 690static int hsdk_cgu_clk_probe(struct udevice *dev)
 691{
 692        struct hsdk_cgu_clk *pll_clk = dev_get_priv(dev);
 693
 694        BUILD_BUG_ON(ARRAY_SIZE(clock_map) != CGU_MAX_CLOCKS);
 695
 696        pll_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0);
 697        if (!pll_clk->cgu_regs)
 698                return -EINVAL;
 699
 700        pll_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1);
 701        if (!pll_clk->creg_regs)
 702                return -EINVAL;
 703
 704        return 0;
 705}
 706
 707static const struct udevice_id hsdk_cgu_clk_id[] = {
 708        { .compatible = "snps,hsdk-cgu-clock" },
 709        { }
 710};
 711
 712U_BOOT_DRIVER(hsdk_cgu_clk) = {
 713        .name = "hsdk-cgu-clk",
 714        .id = UCLASS_CLK,
 715        .of_match = hsdk_cgu_clk_id,
 716        .probe = hsdk_cgu_clk_probe,
 717        .priv_auto_alloc_size = sizeof(struct hsdk_cgu_clk),
 718        .ops = &hsdk_cgu_ops,
 719};
 720