root/drivers/soc/xilinx/xlnx_vcu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xvcu_read
  2. xvcu_write
  3. xvcu_write_field_reg
  4. xvcu_set_vcu_pll_info
  5. xvcu_set_pll
  6. xvcu_probe
  7. xvcu_remove

   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/clk.h>
  10 #include <linux/device.h>
  11 #include <linux/errno.h>
  12 #include <linux/io.h>
  13 #include <linux/module.h>
  14 #include <linux/of_platform.h>
  15 #include <linux/platform_device.h>
  16 
  17 /* Address map for different registers implemented in the VCU LogiCORE IP. */
  18 #define VCU_ECODER_ENABLE               0x00
  19 #define VCU_DECODER_ENABLE              0x04
  20 #define VCU_MEMORY_DEPTH                0x08
  21 #define VCU_ENC_COLOR_DEPTH             0x0c
  22 #define VCU_ENC_VERTICAL_RANGE          0x10
  23 #define VCU_ENC_FRAME_SIZE_X            0x14
  24 #define VCU_ENC_FRAME_SIZE_Y            0x18
  25 #define VCU_ENC_COLOR_FORMAT            0x1c
  26 #define VCU_ENC_FPS                     0x20
  27 #define VCU_MCU_CLK                     0x24
  28 #define VCU_CORE_CLK                    0x28
  29 #define VCU_PLL_BYPASS                  0x2c
  30 #define VCU_ENC_CLK                     0x30
  31 #define VCU_PLL_CLK                     0x34
  32 #define VCU_ENC_VIDEO_STANDARD          0x38
  33 #define VCU_STATUS                      0x3c
  34 #define VCU_AXI_ENC_CLK                 0x40
  35 #define VCU_AXI_DEC_CLK                 0x44
  36 #define VCU_AXI_MCU_CLK                 0x48
  37 #define VCU_DEC_VIDEO_STANDARD          0x4c
  38 #define VCU_DEC_FRAME_SIZE_X            0x50
  39 #define VCU_DEC_FRAME_SIZE_Y            0x54
  40 #define VCU_DEC_FPS                     0x58
  41 #define VCU_BUFFER_B_FRAME              0x5c
  42 #define VCU_WPP_EN                      0x60
  43 #define VCU_PLL_CLK_DEC                 0x64
  44 #define VCU_GASKET_INIT                 0x74
  45 #define VCU_GASKET_VALUE                0x03
  46 
  47 /* vcu slcr registers, bitmask and shift */
  48 #define VCU_PLL_CTRL                    0x24
  49 #define VCU_PLL_CTRL_RESET_MASK         0x01
  50 #define VCU_PLL_CTRL_RESET_SHIFT        0
  51 #define VCU_PLL_CTRL_BYPASS_MASK        0x01
  52 #define VCU_PLL_CTRL_BYPASS_SHIFT       3
  53 #define VCU_PLL_CTRL_FBDIV_MASK         0x7f
  54 #define VCU_PLL_CTRL_FBDIV_SHIFT        8
  55 #define VCU_PLL_CTRL_POR_IN_MASK        0x01
  56 #define VCU_PLL_CTRL_POR_IN_SHIFT       1
  57 #define VCU_PLL_CTRL_PWR_POR_MASK       0x01
  58 #define VCU_PLL_CTRL_PWR_POR_SHIFT      2
  59 #define VCU_PLL_CTRL_CLKOUTDIV_MASK     0x03
  60 #define VCU_PLL_CTRL_CLKOUTDIV_SHIFT    16
  61 #define VCU_PLL_CTRL_DEFAULT            0
  62 #define VCU_PLL_DIV2                    2
  63 
  64 #define VCU_PLL_CFG                     0x28
  65 #define VCU_PLL_CFG_RES_MASK            0x0f
  66 #define VCU_PLL_CFG_RES_SHIFT           0
  67 #define VCU_PLL_CFG_CP_MASK             0x0f
  68 #define VCU_PLL_CFG_CP_SHIFT            5
  69 #define VCU_PLL_CFG_LFHF_MASK           0x03
  70 #define VCU_PLL_CFG_LFHF_SHIFT          10
  71 #define VCU_PLL_CFG_LOCK_CNT_MASK       0x03ff
  72 #define VCU_PLL_CFG_LOCK_CNT_SHIFT      13
  73 #define VCU_PLL_CFG_LOCK_DLY_MASK       0x7f
  74 #define VCU_PLL_CFG_LOCK_DLY_SHIFT      25
  75 #define VCU_ENC_CORE_CTRL               0x30
  76 #define VCU_ENC_MCU_CTRL                0x34
  77 #define VCU_DEC_CORE_CTRL               0x38
  78 #define VCU_DEC_MCU_CTRL                0x3c
  79 #define VCU_PLL_DIVISOR_MASK            0x3f
  80 #define VCU_PLL_DIVISOR_SHIFT           4
  81 #define VCU_SRCSEL_MASK                 0x01
  82 #define VCU_SRCSEL_SHIFT                0
  83 #define VCU_SRCSEL_PLL                  1
  84 
  85 #define VCU_PLL_STATUS                  0x60
  86 #define VCU_PLL_STATUS_LOCK_STATUS_MASK 0x01
  87 
  88 #define MHZ                             1000000
  89 #define FVCO_MIN                        (1500U * MHZ)
  90 #define FVCO_MAX                        (3000U * MHZ)
  91 #define DIVISOR_MIN                     0
  92 #define DIVISOR_MAX                     63
  93 #define FRAC                            100
  94 #define LIMIT                           (10 * MHZ)
  95 
  96 /**
  97  * struct xvcu_device - Xilinx VCU init device structure
  98  * @dev: Platform device
  99  * @pll_ref: pll ref clock source
 100  * @aclk: axi clock source
 101  * @logicore_reg_ba: logicore reg base address
 102  * @vcu_slcr_ba: vcu_slcr Register base address
 103  * @coreclk: core clock frequency
 104  */
 105 struct xvcu_device {
 106         struct device *dev;
 107         struct clk *pll_ref;
 108         struct clk *aclk;
 109         void __iomem *logicore_reg_ba;
 110         void __iomem *vcu_slcr_ba;
 111         u32 coreclk;
 112 };
 113 
 114 /**
 115  * struct xvcu_pll_cfg - Helper data
 116  * @fbdiv: The integer portion of the feedback divider to the PLL
 117  * @cp: PLL charge pump control
 118  * @res: PLL loop filter resistor control
 119  * @lfhf: PLL loop filter high frequency capacitor control
 120  * @lock_dly: Lock circuit configuration settings for lock windowsize
 121  * @lock_cnt: Lock circuit counter setting
 122  */
 123 struct xvcu_pll_cfg {
 124         u32 fbdiv;
 125         u32 cp;
 126         u32 res;
 127         u32 lfhf;
 128         u32 lock_dly;
 129         u32 lock_cnt;
 130 };
 131 
 132 static const struct xvcu_pll_cfg xvcu_pll_cfg[] = {
 133         { 25, 3, 10, 3, 63, 1000 },
 134         { 26, 3, 10, 3, 63, 1000 },
 135         { 27, 4, 6, 3, 63, 1000 },
 136         { 28, 4, 6, 3, 63, 1000 },
 137         { 29, 4, 6, 3, 63, 1000 },
 138         { 30, 4, 6, 3, 63, 1000 },
 139         { 31, 6, 1, 3, 63, 1000 },
 140         { 32, 6, 1, 3, 63, 1000 },
 141         { 33, 4, 10, 3, 63, 1000 },
 142         { 34, 5, 6, 3, 63, 1000 },
 143         { 35, 5, 6, 3, 63, 1000 },
 144         { 36, 5, 6, 3, 63, 1000 },
 145         { 37, 5, 6, 3, 63, 1000 },
 146         { 38, 5, 6, 3, 63, 975 },
 147         { 39, 3, 12, 3, 63, 950 },
 148         { 40, 3, 12, 3, 63, 925 },
 149         { 41, 3, 12, 3, 63, 900 },
 150         { 42, 3, 12, 3, 63, 875 },
 151         { 43, 3, 12, 3, 63, 850 },
 152         { 44, 3, 12, 3, 63, 850 },
 153         { 45, 3, 12, 3, 63, 825 },
 154         { 46, 3, 12, 3, 63, 800 },
 155         { 47, 3, 12, 3, 63, 775 },
 156         { 48, 3, 12, 3, 63, 775 },
 157         { 49, 3, 12, 3, 63, 750 },
 158         { 50, 3, 12, 3, 63, 750 },
 159         { 51, 3, 2, 3, 63, 725 },
 160         { 52, 3, 2, 3, 63, 700 },
 161         { 53, 3, 2, 3, 63, 700 },
 162         { 54, 3, 2, 3, 63, 675 },
 163         { 55, 3, 2, 3, 63, 675 },
 164         { 56, 3, 2, 3, 63, 650 },
 165         { 57, 3, 2, 3, 63, 650 },
 166         { 58, 3, 2, 3, 63, 625 },
 167         { 59, 3, 2, 3, 63, 625 },
 168         { 60, 3, 2, 3, 63, 625 },
 169         { 61, 3, 2, 3, 63, 600 },
 170         { 62, 3, 2, 3, 63, 600 },
 171         { 63, 3, 2, 3, 63, 600 },
 172         { 64, 3, 2, 3, 63, 600 },
 173         { 65, 3, 2, 3, 63, 600 },
 174         { 66, 3, 2, 3, 63, 600 },
 175         { 67, 3, 2, 3, 63, 600 },
 176         { 68, 3, 2, 3, 63, 600 },
 177         { 69, 3, 2, 3, 63, 600 },
 178         { 70, 3, 2, 3, 63, 600 },
 179         { 71, 3, 2, 3, 63, 600 },
 180         { 72, 3, 2, 3, 63, 600 },
 181         { 73, 3, 2, 3, 63, 600 },
 182         { 74, 3, 2, 3, 63, 600 },
 183         { 75, 3, 2, 3, 63, 600 },
 184         { 76, 3, 2, 3, 63, 600 },
 185         { 77, 3, 2, 3, 63, 600 },
 186         { 78, 3, 2, 3, 63, 600 },
 187         { 79, 3, 2, 3, 63, 600 },
 188         { 80, 3, 2, 3, 63, 600 },
 189         { 81, 3, 2, 3, 63, 600 },
 190         { 82, 3, 2, 3, 63, 600 },
 191         { 83, 4, 2, 3, 63, 600 },
 192         { 84, 4, 2, 3, 63, 600 },
 193         { 85, 4, 2, 3, 63, 600 },
 194         { 86, 4, 2, 3, 63, 600 },
 195         { 87, 4, 2, 3, 63, 600 },
 196         { 88, 4, 2, 3, 63, 600 },
 197         { 89, 4, 2, 3, 63, 600 },
 198         { 90, 4, 2, 3, 63, 600 },
 199         { 91, 4, 2, 3, 63, 600 },
 200         { 92, 4, 2, 3, 63, 600 },
 201         { 93, 4, 2, 3, 63, 600 },
 202         { 94, 4, 2, 3, 63, 600 },
 203         { 95, 4, 2, 3, 63, 600 },
 204         { 96, 4, 2, 3, 63, 600 },
 205         { 97, 4, 2, 3, 63, 600 },
 206         { 98, 4, 2, 3, 63, 600 },
 207         { 99, 4, 2, 3, 63, 600 },
 208         { 100, 4, 2, 3, 63, 600 },
 209         { 101, 4, 2, 3, 63, 600 },
 210         { 102, 4, 2, 3, 63, 600 },
 211         { 103, 5, 2, 3, 63, 600 },
 212         { 104, 5, 2, 3, 63, 600 },
 213         { 105, 5, 2, 3, 63, 600 },
 214         { 106, 5, 2, 3, 63, 600 },
 215         { 107, 3, 4, 3, 63, 600 },
 216         { 108, 3, 4, 3, 63, 600 },
 217         { 109, 3, 4, 3, 63, 600 },
 218         { 110, 3, 4, 3, 63, 600 },
 219         { 111, 3, 4, 3, 63, 600 },
 220         { 112, 3, 4, 3, 63, 600 },
 221         { 113, 3, 4, 3, 63, 600 },
 222         { 114, 3, 4, 3, 63, 600 },
 223         { 115, 3, 4, 3, 63, 600 },
 224         { 116, 3, 4, 3, 63, 600 },
 225         { 117, 3, 4, 3, 63, 600 },
 226         { 118, 3, 4, 3, 63, 600 },
 227         { 119, 3, 4, 3, 63, 600 },
 228         { 120, 3, 4, 3, 63, 600 },
 229         { 121, 3, 4, 3, 63, 600 },
 230         { 122, 3, 4, 3, 63, 600 },
 231         { 123, 3, 4, 3, 63, 600 },
 232         { 124, 3, 4, 3, 63, 600 },
 233         { 125, 3, 4, 3, 63, 600 },
 234 };
 235 
 236 /**
 237  * xvcu_read - Read from the VCU register space
 238  * @iomem:      vcu reg space base address
 239  * @offset:     vcu reg offset from base
 240  *
 241  * Return:      Returns 32bit value from VCU register specified
 242  *
 243  */
 244 static inline u32 xvcu_read(void __iomem *iomem, u32 offset)
 245 {
 246         return ioread32(iomem + offset);
 247 }
 248 
 249 /**
 250  * xvcu_write - Write to the VCU register space
 251  * @iomem:      vcu reg space base address
 252  * @offset:     vcu reg offset from base
 253  * @value:      Value to write
 254  */
 255 static inline void xvcu_write(void __iomem *iomem, u32 offset, u32 value)
 256 {
 257         iowrite32(value, iomem + offset);
 258 }
 259 
 260 /**
 261  * xvcu_write_field_reg - Write to the vcu reg field
 262  * @iomem:      vcu reg space base address
 263  * @offset:     vcu reg offset from base
 264  * @field:      vcu reg field to write to
 265  * @mask:       vcu reg mask
 266  * @shift:      vcu reg number of bits to shift the bitfield
 267  */
 268 static void xvcu_write_field_reg(void __iomem *iomem, int offset,
 269                                  u32 field, u32 mask, int shift)
 270 {
 271         u32 val = xvcu_read(iomem, offset);
 272 
 273         val &= ~(mask << shift);
 274         val |= (field & mask) << shift;
 275 
 276         xvcu_write(iomem, offset, val);
 277 }
 278 
 279 /**
 280  * xvcu_set_vcu_pll_info - Set the VCU PLL info
 281  * @xvcu:       Pointer to the xvcu_device structure
 282  *
 283  * Programming the VCU PLL based on the user configuration
 284  * (ref clock freq, core clock freq, mcu clock freq).
 285  * Core clock frequency has higher priority than mcu clock frequency
 286  * Errors in following cases
 287  *    - When mcu or clock clock get from logicoreIP is 0
 288  *    - When VCU PLL DIV related bits value other than 1
 289  *    - When proper data not found for given data
 290  *    - When sis570_1 clocksource related operation failed
 291  *
 292  * Return:      Returns status, either success or error+reason
 293  */
 294 static int xvcu_set_vcu_pll_info(struct xvcu_device *xvcu)
 295 {
 296         u32 refclk, coreclk, mcuclk, inte, deci;
 297         u32 divisor_mcu, divisor_core, fvco;
 298         u32 clkoutdiv, vcu_pll_ctrl, pll_clk;
 299         u32 cfg_val, mod, ctrl;
 300         int ret, i;
 301         const struct xvcu_pll_cfg *found = NULL;
 302 
 303         inte = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK);
 304         deci = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK_DEC);
 305         coreclk = xvcu_read(xvcu->logicore_reg_ba, VCU_CORE_CLK) * MHZ;
 306         mcuclk = xvcu_read(xvcu->logicore_reg_ba, VCU_MCU_CLK) * MHZ;
 307         if (!mcuclk || !coreclk) {
 308                 dev_err(xvcu->dev, "Invalid mcu and core clock data\n");
 309                 return -EINVAL;
 310         }
 311 
 312         refclk = (inte * MHZ) + (deci * (MHZ / FRAC));
 313         dev_dbg(xvcu->dev, "Ref clock from logicoreIP is %uHz\n", refclk);
 314         dev_dbg(xvcu->dev, "Core clock from logicoreIP is %uHz\n", coreclk);
 315         dev_dbg(xvcu->dev, "Mcu clock from logicoreIP is %uHz\n", mcuclk);
 316 
 317         clk_disable_unprepare(xvcu->pll_ref);
 318         ret = clk_set_rate(xvcu->pll_ref, refclk);
 319         if (ret)
 320                 dev_warn(xvcu->dev, "failed to set logicoreIP refclk rate\n");
 321 
 322         ret = clk_prepare_enable(xvcu->pll_ref);
 323         if (ret) {
 324                 dev_err(xvcu->dev, "failed to enable pll_ref clock source\n");
 325                 return ret;
 326         }
 327 
 328         refclk = clk_get_rate(xvcu->pll_ref);
 329 
 330         /*
 331          * The divide-by-2 should be always enabled (==1)
 332          * to meet the timing in the design.
 333          * Otherwise, it's an error
 334          */
 335         vcu_pll_ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_PLL_CTRL);
 336         clkoutdiv = vcu_pll_ctrl >> VCU_PLL_CTRL_CLKOUTDIV_SHIFT;
 337         clkoutdiv = clkoutdiv & VCU_PLL_CTRL_CLKOUTDIV_MASK;
 338         if (clkoutdiv != 1) {
 339                 dev_err(xvcu->dev, "clkoutdiv value is invalid\n");
 340                 return -EINVAL;
 341         }
 342 
 343         for (i = ARRAY_SIZE(xvcu_pll_cfg) - 1; i >= 0; i--) {
 344                 const struct xvcu_pll_cfg *cfg = &xvcu_pll_cfg[i];
 345 
 346                 fvco = cfg->fbdiv * refclk;
 347                 if (fvco >= FVCO_MIN && fvco <= FVCO_MAX) {
 348                         pll_clk = fvco / VCU_PLL_DIV2;
 349                         if (fvco % VCU_PLL_DIV2 != 0)
 350                                 pll_clk++;
 351                         mod = pll_clk % coreclk;
 352                         if (mod < LIMIT) {
 353                                 divisor_core = pll_clk / coreclk;
 354                         } else if (coreclk - mod < LIMIT) {
 355                                 divisor_core = pll_clk / coreclk;
 356                                 divisor_core++;
 357                         } else {
 358                                 continue;
 359                         }
 360                         if (divisor_core >= DIVISOR_MIN &&
 361                             divisor_core <= DIVISOR_MAX) {
 362                                 found = cfg;
 363                                 divisor_mcu = pll_clk / mcuclk;
 364                                 mod = pll_clk % mcuclk;
 365                                 if (mcuclk - mod < LIMIT)
 366                                         divisor_mcu++;
 367                                 break;
 368                         }
 369                 }
 370         }
 371 
 372         if (!found) {
 373                 dev_err(xvcu->dev, "Invalid clock combination.\n");
 374                 return -EINVAL;
 375         }
 376 
 377         xvcu->coreclk = pll_clk / divisor_core;
 378         mcuclk = pll_clk / divisor_mcu;
 379         dev_dbg(xvcu->dev, "Actual Ref clock freq is %uHz\n", refclk);
 380         dev_dbg(xvcu->dev, "Actual Core clock freq is %uHz\n", xvcu->coreclk);
 381         dev_dbg(xvcu->dev, "Actual Mcu clock freq is %uHz\n", mcuclk);
 382 
 383         vcu_pll_ctrl &= ~(VCU_PLL_CTRL_FBDIV_MASK << VCU_PLL_CTRL_FBDIV_SHIFT);
 384         vcu_pll_ctrl |= (found->fbdiv & VCU_PLL_CTRL_FBDIV_MASK) <<
 385                          VCU_PLL_CTRL_FBDIV_SHIFT;
 386         vcu_pll_ctrl &= ~(VCU_PLL_CTRL_POR_IN_MASK <<
 387                           VCU_PLL_CTRL_POR_IN_SHIFT);
 388         vcu_pll_ctrl |= (VCU_PLL_CTRL_DEFAULT & VCU_PLL_CTRL_POR_IN_MASK) <<
 389                          VCU_PLL_CTRL_POR_IN_SHIFT;
 390         vcu_pll_ctrl &= ~(VCU_PLL_CTRL_PWR_POR_MASK <<
 391                           VCU_PLL_CTRL_PWR_POR_SHIFT);
 392         vcu_pll_ctrl |= (VCU_PLL_CTRL_DEFAULT & VCU_PLL_CTRL_PWR_POR_MASK) <<
 393                          VCU_PLL_CTRL_PWR_POR_SHIFT;
 394         xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CTRL, vcu_pll_ctrl);
 395 
 396         /* Set divisor for the core and mcu clock */
 397         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_ENC_CORE_CTRL);
 398         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
 399         ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK) <<
 400                  VCU_PLL_DIVISOR_SHIFT;
 401         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
 402         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
 403         xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_CORE_CTRL, ctrl);
 404 
 405         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_DEC_CORE_CTRL);
 406         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
 407         ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK) <<
 408                  VCU_PLL_DIVISOR_SHIFT;
 409         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
 410         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
 411         xvcu_write(xvcu->vcu_slcr_ba, VCU_DEC_CORE_CTRL, ctrl);
 412 
 413         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_ENC_MCU_CTRL);
 414         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
 415         ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK) << VCU_PLL_DIVISOR_SHIFT;
 416         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
 417         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
 418         xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_MCU_CTRL, ctrl);
 419 
 420         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_DEC_MCU_CTRL);
 421         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
 422         ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK) << VCU_PLL_DIVISOR_SHIFT;
 423         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
 424         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
 425         xvcu_write(xvcu->vcu_slcr_ba, VCU_DEC_MCU_CTRL, ctrl);
 426 
 427         /* Set RES, CP, LFHF, LOCK_CNT and LOCK_DLY cfg values */
 428         cfg_val = (found->res << VCU_PLL_CFG_RES_SHIFT) |
 429                    (found->cp << VCU_PLL_CFG_CP_SHIFT) |
 430                    (found->lfhf << VCU_PLL_CFG_LFHF_SHIFT) |
 431                    (found->lock_cnt << VCU_PLL_CFG_LOCK_CNT_SHIFT) |
 432                    (found->lock_dly << VCU_PLL_CFG_LOCK_DLY_SHIFT);
 433         xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CFG, cfg_val);
 434 
 435         return 0;
 436 }
 437 
 438 /**
 439  * xvcu_set_pll - PLL init sequence
 440  * @xvcu:       Pointer to the xvcu_device structure
 441  *
 442  * Call the api to set the PLL info and once that is done then
 443  * init the PLL sequence to make the PLL stable.
 444  *
 445  * Return:      Returns status, either success or error+reason
 446  */
 447 static int xvcu_set_pll(struct xvcu_device *xvcu)
 448 {
 449         u32 lock_status;
 450         unsigned long timeout;
 451         int ret;
 452 
 453         ret = xvcu_set_vcu_pll_info(xvcu);
 454         if (ret) {
 455                 dev_err(xvcu->dev, "failed to set pll info\n");
 456                 return ret;
 457         }
 458 
 459         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
 460                              1, VCU_PLL_CTRL_BYPASS_MASK,
 461                              VCU_PLL_CTRL_BYPASS_SHIFT);
 462         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
 463                              1, VCU_PLL_CTRL_RESET_MASK,
 464                              VCU_PLL_CTRL_RESET_SHIFT);
 465         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
 466                              0, VCU_PLL_CTRL_RESET_MASK,
 467                              VCU_PLL_CTRL_RESET_SHIFT);
 468         /*
 469          * Defined the timeout for the max time to wait the
 470          * PLL_STATUS to be locked.
 471          */
 472         timeout = jiffies + msecs_to_jiffies(2000);
 473         do {
 474                 lock_status = xvcu_read(xvcu->vcu_slcr_ba, VCU_PLL_STATUS);
 475                 if (lock_status & VCU_PLL_STATUS_LOCK_STATUS_MASK) {
 476                         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
 477                                              0, VCU_PLL_CTRL_BYPASS_MASK,
 478                                              VCU_PLL_CTRL_BYPASS_SHIFT);
 479                         return 0;
 480                 }
 481         } while (!time_after(jiffies, timeout));
 482 
 483         /* PLL is not locked even after the timeout of the 2sec */
 484         dev_err(xvcu->dev, "PLL is not locked\n");
 485         return -ETIMEDOUT;
 486 }
 487 
 488 /**
 489  * xvcu_probe - Probe existence of the logicoreIP
 490  *                      and initialize PLL
 491  *
 492  * @pdev:       Pointer to the platform_device structure
 493  *
 494  * Return:      Returns 0 on success
 495  *              Negative error code otherwise
 496  */
 497 static int xvcu_probe(struct platform_device *pdev)
 498 {
 499         struct resource *res;
 500         struct xvcu_device *xvcu;
 501         int ret;
 502 
 503         xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
 504         if (!xvcu)
 505                 return -ENOMEM;
 506 
 507         xvcu->dev = &pdev->dev;
 508         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
 509         if (!res) {
 510                 dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
 511                 return -ENODEV;
 512         }
 513 
 514         xvcu->vcu_slcr_ba = devm_ioremap_nocache(&pdev->dev, res->start,
 515                                                  resource_size(res));
 516         if (!xvcu->vcu_slcr_ba) {
 517                 dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
 518                 return -ENOMEM;
 519         }
 520 
 521         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "logicore");
 522         if (!res) {
 523                 dev_err(&pdev->dev, "get logicore memory resource failed.\n");
 524                 return -ENODEV;
 525         }
 526 
 527         xvcu->logicore_reg_ba = devm_ioremap_nocache(&pdev->dev, res->start,
 528                                                      resource_size(res));
 529         if (!xvcu->logicore_reg_ba) {
 530                 dev_err(&pdev->dev, "logicore register mapping failed.\n");
 531                 return -ENOMEM;
 532         }
 533 
 534         xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
 535         if (IS_ERR(xvcu->aclk)) {
 536                 dev_err(&pdev->dev, "Could not get aclk clock\n");
 537                 return PTR_ERR(xvcu->aclk);
 538         }
 539 
 540         xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
 541         if (IS_ERR(xvcu->pll_ref)) {
 542                 dev_err(&pdev->dev, "Could not get pll_ref clock\n");
 543                 return PTR_ERR(xvcu->pll_ref);
 544         }
 545 
 546         ret = clk_prepare_enable(xvcu->aclk);
 547         if (ret) {
 548                 dev_err(&pdev->dev, "aclk clock enable failed\n");
 549                 return ret;
 550         }
 551 
 552         ret = clk_prepare_enable(xvcu->pll_ref);
 553         if (ret) {
 554                 dev_err(&pdev->dev, "pll_ref clock enable failed\n");
 555                 goto error_aclk;
 556         }
 557 
 558         /*
 559          * Do the Gasket isolation and put the VCU out of reset
 560          * Bit 0 : Gasket isolation
 561          * Bit 1 : put VCU out of reset
 562          */
 563         xvcu_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE);
 564 
 565         /* Do the PLL Settings based on the ref clk,core and mcu clk freq */
 566         ret = xvcu_set_pll(xvcu);
 567         if (ret) {
 568                 dev_err(&pdev->dev, "Failed to set the pll\n");
 569                 goto error_pll_ref;
 570         }
 571 
 572         dev_set_drvdata(&pdev->dev, xvcu);
 573 
 574         dev_info(&pdev->dev, "%s: Probed successfully\n", __func__);
 575 
 576         return 0;
 577 
 578 error_pll_ref:
 579         clk_disable_unprepare(xvcu->pll_ref);
 580 error_aclk:
 581         clk_disable_unprepare(xvcu->aclk);
 582         return ret;
 583 }
 584 
 585 /**
 586  * xvcu_remove - Insert gasket isolation
 587  *                      and disable the clock
 588  * @pdev:       Pointer to the platform_device structure
 589  *
 590  * Return:      Returns 0 on success
 591  *              Negative error code otherwise
 592  */
 593 static int xvcu_remove(struct platform_device *pdev)
 594 {
 595         struct xvcu_device *xvcu;
 596 
 597         xvcu = platform_get_drvdata(pdev);
 598         if (!xvcu)
 599                 return -ENODEV;
 600 
 601         /* Add the the Gasket isolation and put the VCU in reset. */
 602         xvcu_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
 603 
 604         clk_disable_unprepare(xvcu->pll_ref);
 605         clk_disable_unprepare(xvcu->aclk);
 606 
 607         return 0;
 608 }
 609 
 610 static const struct of_device_id xvcu_of_id_table[] = {
 611         { .compatible = "xlnx,vcu" },
 612         { .compatible = "xlnx,vcu-logicoreip-1.0" },
 613         { }
 614 };
 615 MODULE_DEVICE_TABLE(of, xvcu_of_id_table);
 616 
 617 static struct platform_driver xvcu_driver = {
 618         .driver = {
 619                 .name           = "xilinx-vcu",
 620                 .of_match_table = xvcu_of_id_table,
 621         },
 622         .probe                  = xvcu_probe,
 623         .remove                 = xvcu_remove,
 624 };
 625 
 626 module_platform_driver(xvcu_driver);
 627 
 628 MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
 629 MODULE_DESCRIPTION("Xilinx VCU init Driver");
 630 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */