linux/drivers/clk/xilinx/xlnx_vcu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx VCU Init
   4 *
   5 * Copyright (C) 2016 - 2017 Xilinx, Inc.
   6 *
   7 * Contacts   Dhaval Shah <dshah@xilinx.com>
   8 */
   9#include <linux/bitfield.h>
  10#include <linux/clk.h>
  11#include <linux/clk-provider.h>
  12#include <linux/device.h>
  13#include <linux/errno.h>
  14#include <linux/io.h>
  15#include <linux/mfd/syscon.h>
  16#include <linux/mfd/syscon/xlnx-vcu.h>
  17#include <linux/module.h>
  18#include <linux/of_platform.h>
  19#include <linux/platform_device.h>
  20#include <linux/regmap.h>
  21
  22#include <dt-bindings/clock/xlnx-vcu.h>
  23
  24#define VCU_PLL_CTRL                    0x24
  25#define VCU_PLL_CTRL_RESET              BIT(0)
  26#define VCU_PLL_CTRL_POR_IN             BIT(1)
  27#define VCU_PLL_CTRL_PWR_POR            BIT(2)
  28#define VCU_PLL_CTRL_BYPASS             BIT(3)
  29#define VCU_PLL_CTRL_FBDIV              GENMASK(14, 8)
  30#define VCU_PLL_CTRL_CLKOUTDIV          GENMASK(18, 16)
  31
  32#define VCU_PLL_CFG                     0x28
  33#define VCU_PLL_CFG_RES                 GENMASK(3, 0)
  34#define VCU_PLL_CFG_CP                  GENMASK(8, 5)
  35#define VCU_PLL_CFG_LFHF                GENMASK(12, 10)
  36#define VCU_PLL_CFG_LOCK_CNT            GENMASK(22, 13)
  37#define VCU_PLL_CFG_LOCK_DLY            GENMASK(31, 25)
  38#define VCU_ENC_CORE_CTRL               0x30
  39#define VCU_ENC_MCU_CTRL                0x34
  40#define VCU_DEC_CORE_CTRL               0x38
  41#define VCU_DEC_MCU_CTRL                0x3c
  42#define VCU_PLL_STATUS                  0x60
  43#define VCU_PLL_STATUS_LOCK_STATUS      BIT(0)
  44
  45#define MHZ                             1000000
  46#define FVCO_MIN                        (1500U * MHZ)
  47#define FVCO_MAX                        (3000U * MHZ)
  48
  49/**
  50 * struct xvcu_device - Xilinx VCU init device structure
  51 * @dev: Platform device
  52 * @pll_ref: pll ref clock source
  53 * @aclk: axi clock source
  54 * @logicore_reg_ba: logicore reg base address
  55 * @vcu_slcr_ba: vcu_slcr Register base address
  56 * @pll: handle for the VCU PLL
  57 * @pll_post: handle for the VCU PLL post divider
  58 * @clk_data: clocks provided by the vcu clock provider
  59 */
  60struct xvcu_device {
  61        struct device *dev;
  62        struct clk *pll_ref;
  63        struct clk *aclk;
  64        struct regmap *logicore_reg_ba;
  65        void __iomem *vcu_slcr_ba;
  66        struct clk_hw *pll;
  67        struct clk_hw *pll_post;
  68        struct clk_hw_onecell_data *clk_data;
  69};
  70
  71static struct regmap_config vcu_settings_regmap_config = {
  72        .name = "regmap",
  73        .reg_bits = 32,
  74        .val_bits = 32,
  75        .reg_stride = 4,
  76        .max_register = 0xfff,
  77        .cache_type = REGCACHE_NONE,
  78};
  79
  80/**
  81 * struct xvcu_pll_cfg - Helper data
  82 * @fbdiv: The integer portion of the feedback divider to the PLL
  83 * @cp: PLL charge pump control
  84 * @res: PLL loop filter resistor control
  85 * @lfhf: PLL loop filter high frequency capacitor control
  86 * @lock_dly: Lock circuit configuration settings for lock windowsize
  87 * @lock_cnt: Lock circuit counter setting
  88 */
  89struct xvcu_pll_cfg {
  90        u32 fbdiv;
  91        u32 cp;
  92        u32 res;
  93        u32 lfhf;
  94        u32 lock_dly;
  95        u32 lock_cnt;
  96};
  97
  98static const struct xvcu_pll_cfg xvcu_pll_cfg[] = {
  99        { 25, 3, 10, 3, 63, 1000 },
 100        { 26, 3, 10, 3, 63, 1000 },
 101        { 27, 4, 6, 3, 63, 1000 },
 102        { 28, 4, 6, 3, 63, 1000 },
 103        { 29, 4, 6, 3, 63, 1000 },
 104        { 30, 4, 6, 3, 63, 1000 },
 105        { 31, 6, 1, 3, 63, 1000 },
 106        { 32, 6, 1, 3, 63, 1000 },
 107        { 33, 4, 10, 3, 63, 1000 },
 108        { 34, 5, 6, 3, 63, 1000 },
 109        { 35, 5, 6, 3, 63, 1000 },
 110        { 36, 5, 6, 3, 63, 1000 },
 111        { 37, 5, 6, 3, 63, 1000 },
 112        { 38, 5, 6, 3, 63, 975 },
 113        { 39, 3, 12, 3, 63, 950 },
 114        { 40, 3, 12, 3, 63, 925 },
 115        { 41, 3, 12, 3, 63, 900 },
 116        { 42, 3, 12, 3, 63, 875 },
 117        { 43, 3, 12, 3, 63, 850 },
 118        { 44, 3, 12, 3, 63, 850 },
 119        { 45, 3, 12, 3, 63, 825 },
 120        { 46, 3, 12, 3, 63, 800 },
 121        { 47, 3, 12, 3, 63, 775 },
 122        { 48, 3, 12, 3, 63, 775 },
 123        { 49, 3, 12, 3, 63, 750 },
 124        { 50, 3, 12, 3, 63, 750 },
 125        { 51, 3, 2, 3, 63, 725 },
 126        { 52, 3, 2, 3, 63, 700 },
 127        { 53, 3, 2, 3, 63, 700 },
 128        { 54, 3, 2, 3, 63, 675 },
 129        { 55, 3, 2, 3, 63, 675 },
 130        { 56, 3, 2, 3, 63, 650 },
 131        { 57, 3, 2, 3, 63, 650 },
 132        { 58, 3, 2, 3, 63, 625 },
 133        { 59, 3, 2, 3, 63, 625 },
 134        { 60, 3, 2, 3, 63, 625 },
 135        { 61, 3, 2, 3, 63, 600 },
 136        { 62, 3, 2, 3, 63, 600 },
 137        { 63, 3, 2, 3, 63, 600 },
 138        { 64, 3, 2, 3, 63, 600 },
 139        { 65, 3, 2, 3, 63, 600 },
 140        { 66, 3, 2, 3, 63, 600 },
 141        { 67, 3, 2, 3, 63, 600 },
 142        { 68, 3, 2, 3, 63, 600 },
 143        { 69, 3, 2, 3, 63, 600 },
 144        { 70, 3, 2, 3, 63, 600 },
 145        { 71, 3, 2, 3, 63, 600 },
 146        { 72, 3, 2, 3, 63, 600 },
 147        { 73, 3, 2, 3, 63, 600 },
 148        { 74, 3, 2, 3, 63, 600 },
 149        { 75, 3, 2, 3, 63, 600 },
 150        { 76, 3, 2, 3, 63, 600 },
 151        { 77, 3, 2, 3, 63, 600 },
 152        { 78, 3, 2, 3, 63, 600 },
 153        { 79, 3, 2, 3, 63, 600 },
 154        { 80, 3, 2, 3, 63, 600 },
 155        { 81, 3, 2, 3, 63, 600 },
 156        { 82, 3, 2, 3, 63, 600 },
 157        { 83, 4, 2, 3, 63, 600 },
 158        { 84, 4, 2, 3, 63, 600 },
 159        { 85, 4, 2, 3, 63, 600 },
 160        { 86, 4, 2, 3, 63, 600 },
 161        { 87, 4, 2, 3, 63, 600 },
 162        { 88, 4, 2, 3, 63, 600 },
 163        { 89, 4, 2, 3, 63, 600 },
 164        { 90, 4, 2, 3, 63, 600 },
 165        { 91, 4, 2, 3, 63, 600 },
 166        { 92, 4, 2, 3, 63, 600 },
 167        { 93, 4, 2, 3, 63, 600 },
 168        { 94, 4, 2, 3, 63, 600 },
 169        { 95, 4, 2, 3, 63, 600 },
 170        { 96, 4, 2, 3, 63, 600 },
 171        { 97, 4, 2, 3, 63, 600 },
 172        { 98, 4, 2, 3, 63, 600 },
 173        { 99, 4, 2, 3, 63, 600 },
 174        { 100, 4, 2, 3, 63, 600 },
 175        { 101, 4, 2, 3, 63, 600 },
 176        { 102, 4, 2, 3, 63, 600 },
 177        { 103, 5, 2, 3, 63, 600 },
 178        { 104, 5, 2, 3, 63, 600 },
 179        { 105, 5, 2, 3, 63, 600 },
 180        { 106, 5, 2, 3, 63, 600 },
 181        { 107, 3, 4, 3, 63, 600 },
 182        { 108, 3, 4, 3, 63, 600 },
 183        { 109, 3, 4, 3, 63, 600 },
 184        { 110, 3, 4, 3, 63, 600 },
 185        { 111, 3, 4, 3, 63, 600 },
 186        { 112, 3, 4, 3, 63, 600 },
 187        { 113, 3, 4, 3, 63, 600 },
 188        { 114, 3, 4, 3, 63, 600 },
 189        { 115, 3, 4, 3, 63, 600 },
 190        { 116, 3, 4, 3, 63, 600 },
 191        { 117, 3, 4, 3, 63, 600 },
 192        { 118, 3, 4, 3, 63, 600 },
 193        { 119, 3, 4, 3, 63, 600 },
 194        { 120, 3, 4, 3, 63, 600 },
 195        { 121, 3, 4, 3, 63, 600 },
 196        { 122, 3, 4, 3, 63, 600 },
 197        { 123, 3, 4, 3, 63, 600 },
 198        { 124, 3, 4, 3, 63, 600 },
 199        { 125, 3, 4, 3, 63, 600 },
 200};
 201
 202/**
 203 * xvcu_read - Read from the VCU register space
 204 * @iomem:      vcu reg space base address
 205 * @offset:     vcu reg offset from base
 206 *
 207 * Return:      Returns 32bit value from VCU register specified
 208 *
 209 */
 210static inline u32 xvcu_read(void __iomem *iomem, u32 offset)
 211{
 212        return ioread32(iomem + offset);
 213}
 214
 215/**
 216 * xvcu_write - Write to the VCU register space
 217 * @iomem:      vcu reg space base address
 218 * @offset:     vcu reg offset from base
 219 * @value:      Value to write
 220 */
 221static inline void xvcu_write(void __iomem *iomem, u32 offset, u32 value)
 222{
 223        iowrite32(value, iomem + offset);
 224}
 225
 226#define to_vcu_pll(_hw) container_of(_hw, struct vcu_pll, hw)
 227
 228struct vcu_pll {
 229        struct clk_hw hw;
 230        void __iomem *reg_base;
 231        unsigned long fvco_min;
 232        unsigned long fvco_max;
 233};
 234
 235static int xvcu_pll_wait_for_lock(struct vcu_pll *pll)
 236{
 237        void __iomem *base = pll->reg_base;
 238        unsigned long timeout;
 239        u32 lock_status;
 240
 241        timeout = jiffies + msecs_to_jiffies(2000);
 242        do {
 243                lock_status = xvcu_read(base, VCU_PLL_STATUS);
 244                if (lock_status & VCU_PLL_STATUS_LOCK_STATUS)
 245                        return 0;
 246        } while (!time_after(jiffies, timeout));
 247
 248        return -ETIMEDOUT;
 249}
 250
 251static struct clk_hw *xvcu_register_pll_post(struct device *dev,
 252                                             const char *name,
 253                                             const struct clk_hw *parent_hw,
 254                                             void __iomem *reg_base)
 255{
 256        u32 div;
 257        u32 vcu_pll_ctrl;
 258
 259        /*
 260         * The output divider of the PLL must be set to 1/2 to meet the
 261         * timing in the design.
 262         */
 263        vcu_pll_ctrl = xvcu_read(reg_base, VCU_PLL_CTRL);
 264        div = FIELD_GET(VCU_PLL_CTRL_CLKOUTDIV, vcu_pll_ctrl);
 265        if (div != 1)
 266                return ERR_PTR(-EINVAL);
 267
 268        return clk_hw_register_fixed_factor(dev, "vcu_pll_post",
 269                                            clk_hw_get_name(parent_hw),
 270                                            CLK_SET_RATE_PARENT, 1, 2);
 271}
 272
 273static const struct xvcu_pll_cfg *xvcu_find_cfg(int div)
 274{
 275        const struct xvcu_pll_cfg *cfg = NULL;
 276        unsigned int i;
 277
 278        for (i = 0; i < ARRAY_SIZE(xvcu_pll_cfg) - 1; i++)
 279                if (xvcu_pll_cfg[i].fbdiv == div)
 280                        cfg = &xvcu_pll_cfg[i];
 281
 282        return cfg;
 283}
 284
 285static int xvcu_pll_set_div(struct vcu_pll *pll, int div)
 286{
 287        void __iomem *base = pll->reg_base;
 288        const struct xvcu_pll_cfg *cfg = NULL;
 289        u32 vcu_pll_ctrl;
 290        u32 cfg_val;
 291
 292        cfg = xvcu_find_cfg(div);
 293        if (!cfg)
 294                return -EINVAL;
 295
 296        vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
 297        vcu_pll_ctrl &= ~VCU_PLL_CTRL_FBDIV;
 298        vcu_pll_ctrl |= FIELD_PREP(VCU_PLL_CTRL_FBDIV, cfg->fbdiv);
 299        xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
 300
 301        cfg_val = FIELD_PREP(VCU_PLL_CFG_RES, cfg->res) |
 302                  FIELD_PREP(VCU_PLL_CFG_CP, cfg->cp) |
 303                  FIELD_PREP(VCU_PLL_CFG_LFHF, cfg->lfhf) |
 304                  FIELD_PREP(VCU_PLL_CFG_LOCK_CNT, cfg->lock_cnt) |
 305                  FIELD_PREP(VCU_PLL_CFG_LOCK_DLY, cfg->lock_dly);
 306        xvcu_write(base, VCU_PLL_CFG, cfg_val);
 307
 308        return 0;
 309}
 310
 311static long xvcu_pll_round_rate(struct clk_hw *hw,
 312                                unsigned long rate, unsigned long *parent_rate)
 313{
 314        struct vcu_pll *pll = to_vcu_pll(hw);
 315        unsigned int feedback_div;
 316
 317        rate = clamp_t(unsigned long, rate, pll->fvco_min, pll->fvco_max);
 318
 319        feedback_div = DIV_ROUND_CLOSEST_ULL(rate, *parent_rate);
 320        feedback_div = clamp_t(unsigned int, feedback_div, 25, 125);
 321
 322        return *parent_rate * feedback_div;
 323}
 324
 325static unsigned long xvcu_pll_recalc_rate(struct clk_hw *hw,
 326                                          unsigned long parent_rate)
 327{
 328        struct vcu_pll *pll = to_vcu_pll(hw);
 329        void __iomem *base = pll->reg_base;
 330        unsigned int div;
 331        u32 vcu_pll_ctrl;
 332
 333        vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
 334        div = FIELD_GET(VCU_PLL_CTRL_FBDIV, vcu_pll_ctrl);
 335
 336        return div * parent_rate;
 337}
 338
 339static int xvcu_pll_set_rate(struct clk_hw *hw,
 340                             unsigned long rate, unsigned long parent_rate)
 341{
 342        struct vcu_pll *pll = to_vcu_pll(hw);
 343
 344        return xvcu_pll_set_div(pll, rate / parent_rate);
 345}
 346
 347static int xvcu_pll_enable(struct clk_hw *hw)
 348{
 349        struct vcu_pll *pll = to_vcu_pll(hw);
 350        void __iomem *base = pll->reg_base;
 351        u32 vcu_pll_ctrl;
 352        int ret;
 353
 354        vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
 355        vcu_pll_ctrl |= VCU_PLL_CTRL_BYPASS;
 356        xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
 357
 358        vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
 359        vcu_pll_ctrl &= ~VCU_PLL_CTRL_POR_IN;
 360        vcu_pll_ctrl &= ~VCU_PLL_CTRL_PWR_POR;
 361        vcu_pll_ctrl &= ~VCU_PLL_CTRL_RESET;
 362        xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
 363
 364        ret = xvcu_pll_wait_for_lock(pll);
 365        if (ret) {
 366                pr_err("VCU PLL is not locked\n");
 367                goto err;
 368        }
 369
 370        vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
 371        vcu_pll_ctrl &= ~VCU_PLL_CTRL_BYPASS;
 372        xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
 373
 374err:
 375        return ret;
 376}
 377
 378static void xvcu_pll_disable(struct clk_hw *hw)
 379{
 380        struct vcu_pll *pll = to_vcu_pll(hw);
 381        void __iomem *base = pll->reg_base;
 382        u32 vcu_pll_ctrl;
 383
 384        vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
 385        vcu_pll_ctrl |= VCU_PLL_CTRL_POR_IN;
 386        vcu_pll_ctrl |= VCU_PLL_CTRL_PWR_POR;
 387        vcu_pll_ctrl |= VCU_PLL_CTRL_RESET;
 388        xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
 389}
 390
 391static const struct clk_ops vcu_pll_ops = {
 392        .enable = xvcu_pll_enable,
 393        .disable = xvcu_pll_disable,
 394        .round_rate = xvcu_pll_round_rate,
 395        .recalc_rate = xvcu_pll_recalc_rate,
 396        .set_rate = xvcu_pll_set_rate,
 397};
 398
 399static struct clk_hw *xvcu_register_pll(struct device *dev,
 400                                        void __iomem *reg_base,
 401                                        const char *name, const char *parent,
 402                                        unsigned long flags)
 403{
 404        struct vcu_pll *pll;
 405        struct clk_hw *hw;
 406        struct clk_init_data init;
 407        int ret;
 408
 409        init.name = name;
 410        init.parent_names = &parent;
 411        init.ops = &vcu_pll_ops;
 412        init.num_parents = 1;
 413        init.flags = flags;
 414
 415        pll = devm_kmalloc(dev, sizeof(*pll), GFP_KERNEL);
 416        if (!pll)
 417                return ERR_PTR(-ENOMEM);
 418
 419        pll->hw.init = &init;
 420        pll->reg_base = reg_base;
 421        pll->fvco_min = FVCO_MIN;
 422        pll->fvco_max = FVCO_MAX;
 423
 424        hw = &pll->hw;
 425        ret = devm_clk_hw_register(dev, hw);
 426        if (ret)
 427                return ERR_PTR(ret);
 428
 429        clk_hw_set_rate_range(hw, pll->fvco_min, pll->fvco_max);
 430
 431        return hw;
 432}
 433
 434static struct clk_hw *xvcu_clk_hw_register_leaf(struct device *dev,
 435                                                const char *name,
 436                                                const struct clk_parent_data *parent_data,
 437                                                u8 num_parents,
 438                                                void __iomem *reg)
 439{
 440        u8 mux_flags = CLK_MUX_ROUND_CLOSEST;
 441        u8 divider_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
 442                           CLK_DIVIDER_ROUND_CLOSEST;
 443        struct clk_hw *mux = NULL;
 444        struct clk_hw *divider = NULL;
 445        struct clk_hw *gate = NULL;
 446        char *name_mux;
 447        char *name_div;
 448        int err;
 449        /* Protect register shared by clocks */
 450        spinlock_t *lock;
 451
 452        lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
 453        if (!lock)
 454                return ERR_PTR(-ENOMEM);
 455        spin_lock_init(lock);
 456
 457        name_mux = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_mux");
 458        if (!name_mux)
 459                return ERR_PTR(-ENOMEM);
 460        mux = clk_hw_register_mux_parent_data(dev, name_mux,
 461                                              parent_data, num_parents,
 462                                              CLK_SET_RATE_PARENT,
 463                                              reg, 0, 1, mux_flags, lock);
 464        if (IS_ERR(mux))
 465                return mux;
 466
 467        name_div = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_div");
 468        if (!name_div) {
 469                err = -ENOMEM;
 470                goto unregister_mux;
 471        }
 472        divider = clk_hw_register_divider_parent_hw(dev, name_div, mux,
 473                                                    CLK_SET_RATE_PARENT,
 474                                                    reg, 4, 6, divider_flags,
 475                                                    lock);
 476        if (IS_ERR(divider)) {
 477                err = PTR_ERR(divider);
 478                goto unregister_mux;
 479        }
 480
 481        gate = clk_hw_register_gate_parent_hw(dev, name, divider,
 482                                              CLK_SET_RATE_PARENT, reg, 12, 0,
 483                                              lock);
 484        if (IS_ERR(gate)) {
 485                err = PTR_ERR(gate);
 486                goto unregister_divider;
 487        }
 488
 489        return gate;
 490
 491unregister_divider:
 492        clk_hw_unregister_divider(divider);
 493unregister_mux:
 494        clk_hw_unregister_mux(mux);
 495
 496        return ERR_PTR(err);
 497}
 498
 499static void xvcu_clk_hw_unregister_leaf(struct clk_hw *hw)
 500{
 501        struct clk_hw *gate = hw;
 502        struct clk_hw *divider;
 503        struct clk_hw *mux;
 504
 505        if (!gate)
 506                return;
 507
 508        divider = clk_hw_get_parent(gate);
 509        clk_hw_unregister_gate(gate);
 510        if (!divider)
 511                return;
 512
 513        mux = clk_hw_get_parent(divider);
 514        clk_hw_unregister_mux(mux);
 515        if (!divider)
 516                return;
 517
 518        clk_hw_unregister_divider(divider);
 519}
 520
 521static int xvcu_register_clock_provider(struct xvcu_device *xvcu)
 522{
 523        struct device *dev = xvcu->dev;
 524        struct clk_parent_data parent_data[2] = { 0 };
 525        struct clk_hw_onecell_data *data;
 526        struct clk_hw **hws;
 527        struct clk_hw *hw;
 528        void __iomem *reg_base = xvcu->vcu_slcr_ba;
 529
 530        data = devm_kzalloc(dev, struct_size(data, hws, CLK_XVCU_NUM_CLOCKS), GFP_KERNEL);
 531        if (!data)
 532                return -ENOMEM;
 533        data->num = CLK_XVCU_NUM_CLOCKS;
 534        hws = data->hws;
 535
 536        xvcu->clk_data = data;
 537
 538        hw = xvcu_register_pll(dev, reg_base,
 539                               "vcu_pll", __clk_get_name(xvcu->pll_ref),
 540                               CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE);
 541        if (IS_ERR(hw))
 542                return PTR_ERR(hw);
 543        xvcu->pll = hw;
 544
 545        hw = xvcu_register_pll_post(dev, "vcu_pll_post", xvcu->pll, reg_base);
 546        if (IS_ERR(hw))
 547                return PTR_ERR(hw);
 548        xvcu->pll_post = hw;
 549
 550        parent_data[0].fw_name = "pll_ref";
 551        parent_data[1].hw = xvcu->pll_post;
 552
 553        hws[CLK_XVCU_ENC_CORE] =
 554                xvcu_clk_hw_register_leaf(dev, "venc_core_clk",
 555                                          parent_data,
 556                                          ARRAY_SIZE(parent_data),
 557                                          reg_base + VCU_ENC_CORE_CTRL);
 558        hws[CLK_XVCU_ENC_MCU] =
 559                xvcu_clk_hw_register_leaf(dev, "venc_mcu_clk",
 560                                          parent_data,
 561                                          ARRAY_SIZE(parent_data),
 562                                          reg_base + VCU_ENC_MCU_CTRL);
 563        hws[CLK_XVCU_DEC_CORE] =
 564                xvcu_clk_hw_register_leaf(dev, "vdec_core_clk",
 565                                          parent_data,
 566                                          ARRAY_SIZE(parent_data),
 567                                          reg_base + VCU_DEC_CORE_CTRL);
 568        hws[CLK_XVCU_DEC_MCU] =
 569                xvcu_clk_hw_register_leaf(dev, "vdec_mcu_clk",
 570                                          parent_data,
 571                                          ARRAY_SIZE(parent_data),
 572                                          reg_base + VCU_DEC_MCU_CTRL);
 573
 574        return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
 575}
 576
 577static void xvcu_unregister_clock_provider(struct xvcu_device *xvcu)
 578{
 579        struct clk_hw_onecell_data *data = xvcu->clk_data;
 580        struct clk_hw **hws = data->hws;
 581
 582        if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_MCU]))
 583                xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_MCU]);
 584        if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_CORE]))
 585                xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_CORE]);
 586        if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_MCU]))
 587                xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_MCU]);
 588        if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_CORE]))
 589                xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_CORE]);
 590
 591        clk_hw_unregister_fixed_factor(xvcu->pll_post);
 592}
 593
 594/**
 595 * xvcu_probe - Probe existence of the logicoreIP
 596 *                      and initialize PLL
 597 *
 598 * @pdev:       Pointer to the platform_device structure
 599 *
 600 * Return:      Returns 0 on success
 601 *              Negative error code otherwise
 602 */
 603static int xvcu_probe(struct platform_device *pdev)
 604{
 605        struct resource *res;
 606        struct xvcu_device *xvcu;
 607        void __iomem *regs;
 608        int ret;
 609
 610        xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
 611        if (!xvcu)
 612                return -ENOMEM;
 613
 614        xvcu->dev = &pdev->dev;
 615        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
 616        if (!res) {
 617                dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
 618                return -ENODEV;
 619        }
 620
 621        xvcu->vcu_slcr_ba = devm_ioremap(&pdev->dev, res->start,
 622                                         resource_size(res));
 623        if (!xvcu->vcu_slcr_ba) {
 624                dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
 625                return -ENOMEM;
 626        }
 627
 628        xvcu->logicore_reg_ba =
 629                syscon_regmap_lookup_by_compatible("xlnx,vcu-settings");
 630        if (IS_ERR(xvcu->logicore_reg_ba)) {
 631                dev_info(&pdev->dev,
 632                         "could not find xlnx,vcu-settings: trying direct register access\n");
 633
 634                res = platform_get_resource_byname(pdev,
 635                                                   IORESOURCE_MEM, "logicore");
 636                if (!res) {
 637                        dev_err(&pdev->dev, "get logicore memory resource failed.\n");
 638                        return -ENODEV;
 639                }
 640
 641                regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
 642                if (!regs) {
 643                        dev_err(&pdev->dev, "logicore register mapping failed.\n");
 644                        return -ENOMEM;
 645                }
 646
 647                xvcu->logicore_reg_ba =
 648                        devm_regmap_init_mmio(&pdev->dev, regs,
 649                                              &vcu_settings_regmap_config);
 650                if (IS_ERR(xvcu->logicore_reg_ba)) {
 651                        dev_err(&pdev->dev, "failed to init regmap\n");
 652                        return PTR_ERR(xvcu->logicore_reg_ba);
 653                }
 654        }
 655
 656        xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
 657        if (IS_ERR(xvcu->aclk)) {
 658                dev_err(&pdev->dev, "Could not get aclk clock\n");
 659                return PTR_ERR(xvcu->aclk);
 660        }
 661
 662        xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
 663        if (IS_ERR(xvcu->pll_ref)) {
 664                dev_err(&pdev->dev, "Could not get pll_ref clock\n");
 665                return PTR_ERR(xvcu->pll_ref);
 666        }
 667
 668        ret = clk_prepare_enable(xvcu->aclk);
 669        if (ret) {
 670                dev_err(&pdev->dev, "aclk clock enable failed\n");
 671                return ret;
 672        }
 673
 674        /*
 675         * Do the Gasket isolation and put the VCU out of reset
 676         * Bit 0 : Gasket isolation
 677         * Bit 1 : put VCU out of reset
 678         */
 679        regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE);
 680
 681        ret = xvcu_register_clock_provider(xvcu);
 682        if (ret) {
 683                dev_err(&pdev->dev, "failed to register clock provider\n");
 684                goto error_clk_provider;
 685        }
 686
 687        dev_set_drvdata(&pdev->dev, xvcu);
 688
 689        return 0;
 690
 691error_clk_provider:
 692        xvcu_unregister_clock_provider(xvcu);
 693        clk_disable_unprepare(xvcu->aclk);
 694        return ret;
 695}
 696
 697/**
 698 * xvcu_remove - Insert gasket isolation
 699 *                      and disable the clock
 700 * @pdev:       Pointer to the platform_device structure
 701 *
 702 * Return:      Returns 0 on success
 703 *              Negative error code otherwise
 704 */
 705static int xvcu_remove(struct platform_device *pdev)
 706{
 707        struct xvcu_device *xvcu;
 708
 709        xvcu = platform_get_drvdata(pdev);
 710        if (!xvcu)
 711                return -ENODEV;
 712
 713        xvcu_unregister_clock_provider(xvcu);
 714
 715        /* Add the Gasket isolation and put the VCU in reset. */
 716        regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
 717
 718        clk_disable_unprepare(xvcu->aclk);
 719
 720        return 0;
 721}
 722
 723static const struct of_device_id xvcu_of_id_table[] = {
 724        { .compatible = "xlnx,vcu" },
 725        { .compatible = "xlnx,vcu-logicoreip-1.0" },
 726        { }
 727};
 728MODULE_DEVICE_TABLE(of, xvcu_of_id_table);
 729
 730static struct platform_driver xvcu_driver = {
 731        .driver = {
 732                .name           = "xilinx-vcu",
 733                .of_match_table = xvcu_of_id_table,
 734        },
 735        .probe                  = xvcu_probe,
 736        .remove                 = xvcu_remove,
 737};
 738
 739module_platform_driver(xvcu_driver);
 740
 741MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
 742MODULE_DESCRIPTION("Xilinx VCU init Driver");
 743MODULE_LICENSE("GPL v2");
 744