0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/bitfield.h>
0010 #include <linux/clk.h>
0011 #include <linux/clk-provider.h>
0012 #include <linux/device.h>
0013 #include <linux/errno.h>
0014 #include <linux/io.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/mfd/syscon/xlnx-vcu.h>
0017 #include <linux/module.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regmap.h>
0021
0022 #include <dt-bindings/clock/xlnx-vcu.h>
0023
0024 #define VCU_PLL_CTRL 0x24
0025 #define VCU_PLL_CTRL_RESET BIT(0)
0026 #define VCU_PLL_CTRL_POR_IN BIT(1)
0027 #define VCU_PLL_CTRL_PWR_POR BIT(2)
0028 #define VCU_PLL_CTRL_BYPASS BIT(3)
0029 #define VCU_PLL_CTRL_FBDIV GENMASK(14, 8)
0030 #define VCU_PLL_CTRL_CLKOUTDIV GENMASK(18, 16)
0031
0032 #define VCU_PLL_CFG 0x28
0033 #define VCU_PLL_CFG_RES GENMASK(3, 0)
0034 #define VCU_PLL_CFG_CP GENMASK(8, 5)
0035 #define VCU_PLL_CFG_LFHF GENMASK(12, 10)
0036 #define VCU_PLL_CFG_LOCK_CNT GENMASK(22, 13)
0037 #define VCU_PLL_CFG_LOCK_DLY GENMASK(31, 25)
0038 #define VCU_ENC_CORE_CTRL 0x30
0039 #define VCU_ENC_MCU_CTRL 0x34
0040 #define VCU_DEC_CORE_CTRL 0x38
0041 #define VCU_DEC_MCU_CTRL 0x3c
0042 #define VCU_PLL_STATUS 0x60
0043 #define VCU_PLL_STATUS_LOCK_STATUS BIT(0)
0044
0045 #define MHZ 1000000
0046 #define FVCO_MIN (1500U * MHZ)
0047 #define FVCO_MAX (3000U * MHZ)
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 struct xvcu_device {
0061 struct device *dev;
0062 struct clk *pll_ref;
0063 struct clk *aclk;
0064 struct regmap *logicore_reg_ba;
0065 void __iomem *vcu_slcr_ba;
0066 struct clk_hw *pll;
0067 struct clk_hw *pll_post;
0068 struct clk_hw_onecell_data *clk_data;
0069 };
0070
0071 static struct regmap_config vcu_settings_regmap_config = {
0072 .name = "regmap",
0073 .reg_bits = 32,
0074 .val_bits = 32,
0075 .reg_stride = 4,
0076 .max_register = 0xfff,
0077 .cache_type = REGCACHE_NONE,
0078 };
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 struct xvcu_pll_cfg {
0090 u32 fbdiv;
0091 u32 cp;
0092 u32 res;
0093 u32 lfhf;
0094 u32 lock_dly;
0095 u32 lock_cnt;
0096 };
0097
0098 static const struct xvcu_pll_cfg xvcu_pll_cfg[] = {
0099 { 25, 3, 10, 3, 63, 1000 },
0100 { 26, 3, 10, 3, 63, 1000 },
0101 { 27, 4, 6, 3, 63, 1000 },
0102 { 28, 4, 6, 3, 63, 1000 },
0103 { 29, 4, 6, 3, 63, 1000 },
0104 { 30, 4, 6, 3, 63, 1000 },
0105 { 31, 6, 1, 3, 63, 1000 },
0106 { 32, 6, 1, 3, 63, 1000 },
0107 { 33, 4, 10, 3, 63, 1000 },
0108 { 34, 5, 6, 3, 63, 1000 },
0109 { 35, 5, 6, 3, 63, 1000 },
0110 { 36, 5, 6, 3, 63, 1000 },
0111 { 37, 5, 6, 3, 63, 1000 },
0112 { 38, 5, 6, 3, 63, 975 },
0113 { 39, 3, 12, 3, 63, 950 },
0114 { 40, 3, 12, 3, 63, 925 },
0115 { 41, 3, 12, 3, 63, 900 },
0116 { 42, 3, 12, 3, 63, 875 },
0117 { 43, 3, 12, 3, 63, 850 },
0118 { 44, 3, 12, 3, 63, 850 },
0119 { 45, 3, 12, 3, 63, 825 },
0120 { 46, 3, 12, 3, 63, 800 },
0121 { 47, 3, 12, 3, 63, 775 },
0122 { 48, 3, 12, 3, 63, 775 },
0123 { 49, 3, 12, 3, 63, 750 },
0124 { 50, 3, 12, 3, 63, 750 },
0125 { 51, 3, 2, 3, 63, 725 },
0126 { 52, 3, 2, 3, 63, 700 },
0127 { 53, 3, 2, 3, 63, 700 },
0128 { 54, 3, 2, 3, 63, 675 },
0129 { 55, 3, 2, 3, 63, 675 },
0130 { 56, 3, 2, 3, 63, 650 },
0131 { 57, 3, 2, 3, 63, 650 },
0132 { 58, 3, 2, 3, 63, 625 },
0133 { 59, 3, 2, 3, 63, 625 },
0134 { 60, 3, 2, 3, 63, 625 },
0135 { 61, 3, 2, 3, 63, 600 },
0136 { 62, 3, 2, 3, 63, 600 },
0137 { 63, 3, 2, 3, 63, 600 },
0138 { 64, 3, 2, 3, 63, 600 },
0139 { 65, 3, 2, 3, 63, 600 },
0140 { 66, 3, 2, 3, 63, 600 },
0141 { 67, 3, 2, 3, 63, 600 },
0142 { 68, 3, 2, 3, 63, 600 },
0143 { 69, 3, 2, 3, 63, 600 },
0144 { 70, 3, 2, 3, 63, 600 },
0145 { 71, 3, 2, 3, 63, 600 },
0146 { 72, 3, 2, 3, 63, 600 },
0147 { 73, 3, 2, 3, 63, 600 },
0148 { 74, 3, 2, 3, 63, 600 },
0149 { 75, 3, 2, 3, 63, 600 },
0150 { 76, 3, 2, 3, 63, 600 },
0151 { 77, 3, 2, 3, 63, 600 },
0152 { 78, 3, 2, 3, 63, 600 },
0153 { 79, 3, 2, 3, 63, 600 },
0154 { 80, 3, 2, 3, 63, 600 },
0155 { 81, 3, 2, 3, 63, 600 },
0156 { 82, 3, 2, 3, 63, 600 },
0157 { 83, 4, 2, 3, 63, 600 },
0158 { 84, 4, 2, 3, 63, 600 },
0159 { 85, 4, 2, 3, 63, 600 },
0160 { 86, 4, 2, 3, 63, 600 },
0161 { 87, 4, 2, 3, 63, 600 },
0162 { 88, 4, 2, 3, 63, 600 },
0163 { 89, 4, 2, 3, 63, 600 },
0164 { 90, 4, 2, 3, 63, 600 },
0165 { 91, 4, 2, 3, 63, 600 },
0166 { 92, 4, 2, 3, 63, 600 },
0167 { 93, 4, 2, 3, 63, 600 },
0168 { 94, 4, 2, 3, 63, 600 },
0169 { 95, 4, 2, 3, 63, 600 },
0170 { 96, 4, 2, 3, 63, 600 },
0171 { 97, 4, 2, 3, 63, 600 },
0172 { 98, 4, 2, 3, 63, 600 },
0173 { 99, 4, 2, 3, 63, 600 },
0174 { 100, 4, 2, 3, 63, 600 },
0175 { 101, 4, 2, 3, 63, 600 },
0176 { 102, 4, 2, 3, 63, 600 },
0177 { 103, 5, 2, 3, 63, 600 },
0178 { 104, 5, 2, 3, 63, 600 },
0179 { 105, 5, 2, 3, 63, 600 },
0180 { 106, 5, 2, 3, 63, 600 },
0181 { 107, 3, 4, 3, 63, 600 },
0182 { 108, 3, 4, 3, 63, 600 },
0183 { 109, 3, 4, 3, 63, 600 },
0184 { 110, 3, 4, 3, 63, 600 },
0185 { 111, 3, 4, 3, 63, 600 },
0186 { 112, 3, 4, 3, 63, 600 },
0187 { 113, 3, 4, 3, 63, 600 },
0188 { 114, 3, 4, 3, 63, 600 },
0189 { 115, 3, 4, 3, 63, 600 },
0190 { 116, 3, 4, 3, 63, 600 },
0191 { 117, 3, 4, 3, 63, 600 },
0192 { 118, 3, 4, 3, 63, 600 },
0193 { 119, 3, 4, 3, 63, 600 },
0194 { 120, 3, 4, 3, 63, 600 },
0195 { 121, 3, 4, 3, 63, 600 },
0196 { 122, 3, 4, 3, 63, 600 },
0197 { 123, 3, 4, 3, 63, 600 },
0198 { 124, 3, 4, 3, 63, 600 },
0199 { 125, 3, 4, 3, 63, 600 },
0200 };
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 static inline u32 xvcu_read(void __iomem *iomem, u32 offset)
0211 {
0212 return ioread32(iomem + offset);
0213 }
0214
0215
0216
0217
0218
0219
0220
0221 static inline void xvcu_write(void __iomem *iomem, u32 offset, u32 value)
0222 {
0223 iowrite32(value, iomem + offset);
0224 }
0225
0226 #define to_vcu_pll(_hw) container_of(_hw, struct vcu_pll, hw)
0227
0228 struct vcu_pll {
0229 struct clk_hw hw;
0230 void __iomem *reg_base;
0231 unsigned long fvco_min;
0232 unsigned long fvco_max;
0233 };
0234
0235 static int xvcu_pll_wait_for_lock(struct vcu_pll *pll)
0236 {
0237 void __iomem *base = pll->reg_base;
0238 unsigned long timeout;
0239 u32 lock_status;
0240
0241 timeout = jiffies + msecs_to_jiffies(2000);
0242 do {
0243 lock_status = xvcu_read(base, VCU_PLL_STATUS);
0244 if (lock_status & VCU_PLL_STATUS_LOCK_STATUS)
0245 return 0;
0246 } while (!time_after(jiffies, timeout));
0247
0248 return -ETIMEDOUT;
0249 }
0250
0251 static struct clk_hw *xvcu_register_pll_post(struct device *dev,
0252 const char *name,
0253 const struct clk_hw *parent_hw,
0254 void __iomem *reg_base)
0255 {
0256 u32 div;
0257 u32 vcu_pll_ctrl;
0258
0259
0260
0261
0262
0263 vcu_pll_ctrl = xvcu_read(reg_base, VCU_PLL_CTRL);
0264 div = FIELD_GET(VCU_PLL_CTRL_CLKOUTDIV, vcu_pll_ctrl);
0265 if (div != 1)
0266 return ERR_PTR(-EINVAL);
0267
0268 return clk_hw_register_fixed_factor(dev, "vcu_pll_post",
0269 clk_hw_get_name(parent_hw),
0270 CLK_SET_RATE_PARENT, 1, 2);
0271 }
0272
0273 static const struct xvcu_pll_cfg *xvcu_find_cfg(int div)
0274 {
0275 const struct xvcu_pll_cfg *cfg = NULL;
0276 unsigned int i;
0277
0278 for (i = 0; i < ARRAY_SIZE(xvcu_pll_cfg) - 1; i++)
0279 if (xvcu_pll_cfg[i].fbdiv == div)
0280 cfg = &xvcu_pll_cfg[i];
0281
0282 return cfg;
0283 }
0284
0285 static int xvcu_pll_set_div(struct vcu_pll *pll, int div)
0286 {
0287 void __iomem *base = pll->reg_base;
0288 const struct xvcu_pll_cfg *cfg = NULL;
0289 u32 vcu_pll_ctrl;
0290 u32 cfg_val;
0291
0292 cfg = xvcu_find_cfg(div);
0293 if (!cfg)
0294 return -EINVAL;
0295
0296 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
0297 vcu_pll_ctrl &= ~VCU_PLL_CTRL_FBDIV;
0298 vcu_pll_ctrl |= FIELD_PREP(VCU_PLL_CTRL_FBDIV, cfg->fbdiv);
0299 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
0300
0301 cfg_val = FIELD_PREP(VCU_PLL_CFG_RES, cfg->res) |
0302 FIELD_PREP(VCU_PLL_CFG_CP, cfg->cp) |
0303 FIELD_PREP(VCU_PLL_CFG_LFHF, cfg->lfhf) |
0304 FIELD_PREP(VCU_PLL_CFG_LOCK_CNT, cfg->lock_cnt) |
0305 FIELD_PREP(VCU_PLL_CFG_LOCK_DLY, cfg->lock_dly);
0306 xvcu_write(base, VCU_PLL_CFG, cfg_val);
0307
0308 return 0;
0309 }
0310
0311 static long xvcu_pll_round_rate(struct clk_hw *hw,
0312 unsigned long rate, unsigned long *parent_rate)
0313 {
0314 struct vcu_pll *pll = to_vcu_pll(hw);
0315 unsigned int feedback_div;
0316
0317 rate = clamp_t(unsigned long, rate, pll->fvco_min, pll->fvco_max);
0318
0319 feedback_div = DIV_ROUND_CLOSEST_ULL(rate, *parent_rate);
0320 feedback_div = clamp_t(unsigned int, feedback_div, 25, 125);
0321
0322 return *parent_rate * feedback_div;
0323 }
0324
0325 static unsigned long xvcu_pll_recalc_rate(struct clk_hw *hw,
0326 unsigned long parent_rate)
0327 {
0328 struct vcu_pll *pll = to_vcu_pll(hw);
0329 void __iomem *base = pll->reg_base;
0330 unsigned int div;
0331 u32 vcu_pll_ctrl;
0332
0333 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
0334 div = FIELD_GET(VCU_PLL_CTRL_FBDIV, vcu_pll_ctrl);
0335
0336 return div * parent_rate;
0337 }
0338
0339 static int xvcu_pll_set_rate(struct clk_hw *hw,
0340 unsigned long rate, unsigned long parent_rate)
0341 {
0342 struct vcu_pll *pll = to_vcu_pll(hw);
0343
0344 return xvcu_pll_set_div(pll, rate / parent_rate);
0345 }
0346
0347 static int xvcu_pll_enable(struct clk_hw *hw)
0348 {
0349 struct vcu_pll *pll = to_vcu_pll(hw);
0350 void __iomem *base = pll->reg_base;
0351 u32 vcu_pll_ctrl;
0352 int ret;
0353
0354 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
0355 vcu_pll_ctrl |= VCU_PLL_CTRL_BYPASS;
0356 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
0357
0358 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
0359 vcu_pll_ctrl &= ~VCU_PLL_CTRL_POR_IN;
0360 vcu_pll_ctrl &= ~VCU_PLL_CTRL_PWR_POR;
0361 vcu_pll_ctrl &= ~VCU_PLL_CTRL_RESET;
0362 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
0363
0364 ret = xvcu_pll_wait_for_lock(pll);
0365 if (ret) {
0366 pr_err("VCU PLL is not locked\n");
0367 goto err;
0368 }
0369
0370 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
0371 vcu_pll_ctrl &= ~VCU_PLL_CTRL_BYPASS;
0372 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
0373
0374 err:
0375 return ret;
0376 }
0377
0378 static void xvcu_pll_disable(struct clk_hw *hw)
0379 {
0380 struct vcu_pll *pll = to_vcu_pll(hw);
0381 void __iomem *base = pll->reg_base;
0382 u32 vcu_pll_ctrl;
0383
0384 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
0385 vcu_pll_ctrl |= VCU_PLL_CTRL_POR_IN;
0386 vcu_pll_ctrl |= VCU_PLL_CTRL_PWR_POR;
0387 vcu_pll_ctrl |= VCU_PLL_CTRL_RESET;
0388 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
0389 }
0390
0391 static const struct clk_ops vcu_pll_ops = {
0392 .enable = xvcu_pll_enable,
0393 .disable = xvcu_pll_disable,
0394 .round_rate = xvcu_pll_round_rate,
0395 .recalc_rate = xvcu_pll_recalc_rate,
0396 .set_rate = xvcu_pll_set_rate,
0397 };
0398
0399 static struct clk_hw *xvcu_register_pll(struct device *dev,
0400 void __iomem *reg_base,
0401 const char *name, const char *parent,
0402 unsigned long flags)
0403 {
0404 struct vcu_pll *pll;
0405 struct clk_hw *hw;
0406 struct clk_init_data init;
0407 int ret;
0408
0409 init.name = name;
0410 init.parent_names = &parent;
0411 init.ops = &vcu_pll_ops;
0412 init.num_parents = 1;
0413 init.flags = flags;
0414
0415 pll = devm_kmalloc(dev, sizeof(*pll), GFP_KERNEL);
0416 if (!pll)
0417 return ERR_PTR(-ENOMEM);
0418
0419 pll->hw.init = &init;
0420 pll->reg_base = reg_base;
0421 pll->fvco_min = FVCO_MIN;
0422 pll->fvco_max = FVCO_MAX;
0423
0424 hw = &pll->hw;
0425 ret = devm_clk_hw_register(dev, hw);
0426 if (ret)
0427 return ERR_PTR(ret);
0428
0429 clk_hw_set_rate_range(hw, pll->fvco_min, pll->fvco_max);
0430
0431 return hw;
0432 }
0433
0434 static struct clk_hw *xvcu_clk_hw_register_leaf(struct device *dev,
0435 const char *name,
0436 const struct clk_parent_data *parent_data,
0437 u8 num_parents,
0438 void __iomem *reg)
0439 {
0440 u8 mux_flags = CLK_MUX_ROUND_CLOSEST;
0441 u8 divider_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
0442 CLK_DIVIDER_ROUND_CLOSEST;
0443 struct clk_hw *mux = NULL;
0444 struct clk_hw *divider = NULL;
0445 struct clk_hw *gate = NULL;
0446 char *name_mux;
0447 char *name_div;
0448 int err;
0449
0450 spinlock_t *lock;
0451
0452 lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
0453 if (!lock)
0454 return ERR_PTR(-ENOMEM);
0455 spin_lock_init(lock);
0456
0457 name_mux = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_mux");
0458 if (!name_mux)
0459 return ERR_PTR(-ENOMEM);
0460 mux = clk_hw_register_mux_parent_data(dev, name_mux,
0461 parent_data, num_parents,
0462 CLK_SET_RATE_PARENT,
0463 reg, 0, 1, mux_flags, lock);
0464 if (IS_ERR(mux))
0465 return mux;
0466
0467 name_div = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_div");
0468 if (!name_div) {
0469 err = -ENOMEM;
0470 goto unregister_mux;
0471 }
0472 divider = clk_hw_register_divider_parent_hw(dev, name_div, mux,
0473 CLK_SET_RATE_PARENT,
0474 reg, 4, 6, divider_flags,
0475 lock);
0476 if (IS_ERR(divider)) {
0477 err = PTR_ERR(divider);
0478 goto unregister_mux;
0479 }
0480
0481 gate = clk_hw_register_gate_parent_hw(dev, name, divider,
0482 CLK_SET_RATE_PARENT, reg, 12, 0,
0483 lock);
0484 if (IS_ERR(gate)) {
0485 err = PTR_ERR(gate);
0486 goto unregister_divider;
0487 }
0488
0489 return gate;
0490
0491 unregister_divider:
0492 clk_hw_unregister_divider(divider);
0493 unregister_mux:
0494 clk_hw_unregister_mux(mux);
0495
0496 return ERR_PTR(err);
0497 }
0498
0499 static void xvcu_clk_hw_unregister_leaf(struct clk_hw *hw)
0500 {
0501 struct clk_hw *gate = hw;
0502 struct clk_hw *divider;
0503 struct clk_hw *mux;
0504
0505 if (!gate)
0506 return;
0507
0508 divider = clk_hw_get_parent(gate);
0509 clk_hw_unregister_gate(gate);
0510 if (!divider)
0511 return;
0512
0513 mux = clk_hw_get_parent(divider);
0514 clk_hw_unregister_mux(mux);
0515 if (!divider)
0516 return;
0517
0518 clk_hw_unregister_divider(divider);
0519 }
0520
0521 static int xvcu_register_clock_provider(struct xvcu_device *xvcu)
0522 {
0523 struct device *dev = xvcu->dev;
0524 struct clk_parent_data parent_data[2] = { 0 };
0525 struct clk_hw_onecell_data *data;
0526 struct clk_hw **hws;
0527 struct clk_hw *hw;
0528 void __iomem *reg_base = xvcu->vcu_slcr_ba;
0529
0530 data = devm_kzalloc(dev, struct_size(data, hws, CLK_XVCU_NUM_CLOCKS), GFP_KERNEL);
0531 if (!data)
0532 return -ENOMEM;
0533 data->num = CLK_XVCU_NUM_CLOCKS;
0534 hws = data->hws;
0535
0536 xvcu->clk_data = data;
0537
0538 hw = xvcu_register_pll(dev, reg_base,
0539 "vcu_pll", __clk_get_name(xvcu->pll_ref),
0540 CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE);
0541 if (IS_ERR(hw))
0542 return PTR_ERR(hw);
0543 xvcu->pll = hw;
0544
0545 hw = xvcu_register_pll_post(dev, "vcu_pll_post", xvcu->pll, reg_base);
0546 if (IS_ERR(hw))
0547 return PTR_ERR(hw);
0548 xvcu->pll_post = hw;
0549
0550 parent_data[0].fw_name = "pll_ref";
0551 parent_data[1].hw = xvcu->pll_post;
0552
0553 hws[CLK_XVCU_ENC_CORE] =
0554 xvcu_clk_hw_register_leaf(dev, "venc_core_clk",
0555 parent_data,
0556 ARRAY_SIZE(parent_data),
0557 reg_base + VCU_ENC_CORE_CTRL);
0558 hws[CLK_XVCU_ENC_MCU] =
0559 xvcu_clk_hw_register_leaf(dev, "venc_mcu_clk",
0560 parent_data,
0561 ARRAY_SIZE(parent_data),
0562 reg_base + VCU_ENC_MCU_CTRL);
0563 hws[CLK_XVCU_DEC_CORE] =
0564 xvcu_clk_hw_register_leaf(dev, "vdec_core_clk",
0565 parent_data,
0566 ARRAY_SIZE(parent_data),
0567 reg_base + VCU_DEC_CORE_CTRL);
0568 hws[CLK_XVCU_DEC_MCU] =
0569 xvcu_clk_hw_register_leaf(dev, "vdec_mcu_clk",
0570 parent_data,
0571 ARRAY_SIZE(parent_data),
0572 reg_base + VCU_DEC_MCU_CTRL);
0573
0574 return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
0575 }
0576
0577 static void xvcu_unregister_clock_provider(struct xvcu_device *xvcu)
0578 {
0579 struct clk_hw_onecell_data *data = xvcu->clk_data;
0580 struct clk_hw **hws = data->hws;
0581
0582 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_MCU]))
0583 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_MCU]);
0584 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_CORE]))
0585 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_CORE]);
0586 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_MCU]))
0587 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_MCU]);
0588 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_CORE]))
0589 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_CORE]);
0590
0591 clk_hw_unregister_fixed_factor(xvcu->pll_post);
0592 }
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603 static int xvcu_probe(struct platform_device *pdev)
0604 {
0605 struct resource *res;
0606 struct xvcu_device *xvcu;
0607 void __iomem *regs;
0608 int ret;
0609
0610 xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
0611 if (!xvcu)
0612 return -ENOMEM;
0613
0614 xvcu->dev = &pdev->dev;
0615 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
0616 if (!res) {
0617 dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
0618 return -ENODEV;
0619 }
0620
0621 xvcu->vcu_slcr_ba = devm_ioremap(&pdev->dev, res->start,
0622 resource_size(res));
0623 if (!xvcu->vcu_slcr_ba) {
0624 dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
0625 return -ENOMEM;
0626 }
0627
0628 xvcu->logicore_reg_ba =
0629 syscon_regmap_lookup_by_compatible("xlnx,vcu-settings");
0630 if (IS_ERR(xvcu->logicore_reg_ba)) {
0631 dev_info(&pdev->dev,
0632 "could not find xlnx,vcu-settings: trying direct register access\n");
0633
0634 res = platform_get_resource_byname(pdev,
0635 IORESOURCE_MEM, "logicore");
0636 if (!res) {
0637 dev_err(&pdev->dev, "get logicore memory resource failed.\n");
0638 return -ENODEV;
0639 }
0640
0641 regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
0642 if (!regs) {
0643 dev_err(&pdev->dev, "logicore register mapping failed.\n");
0644 return -ENOMEM;
0645 }
0646
0647 xvcu->logicore_reg_ba =
0648 devm_regmap_init_mmio(&pdev->dev, regs,
0649 &vcu_settings_regmap_config);
0650 if (IS_ERR(xvcu->logicore_reg_ba)) {
0651 dev_err(&pdev->dev, "failed to init regmap\n");
0652 return PTR_ERR(xvcu->logicore_reg_ba);
0653 }
0654 }
0655
0656 xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
0657 if (IS_ERR(xvcu->aclk)) {
0658 dev_err(&pdev->dev, "Could not get aclk clock\n");
0659 return PTR_ERR(xvcu->aclk);
0660 }
0661
0662 xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
0663 if (IS_ERR(xvcu->pll_ref)) {
0664 dev_err(&pdev->dev, "Could not get pll_ref clock\n");
0665 return PTR_ERR(xvcu->pll_ref);
0666 }
0667
0668 ret = clk_prepare_enable(xvcu->aclk);
0669 if (ret) {
0670 dev_err(&pdev->dev, "aclk clock enable failed\n");
0671 return ret;
0672 }
0673
0674
0675
0676
0677
0678
0679 regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE);
0680
0681 ret = xvcu_register_clock_provider(xvcu);
0682 if (ret) {
0683 dev_err(&pdev->dev, "failed to register clock provider\n");
0684 goto error_clk_provider;
0685 }
0686
0687 dev_set_drvdata(&pdev->dev, xvcu);
0688
0689 return 0;
0690
0691 error_clk_provider:
0692 xvcu_unregister_clock_provider(xvcu);
0693 clk_disable_unprepare(xvcu->aclk);
0694 return ret;
0695 }
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705 static int xvcu_remove(struct platform_device *pdev)
0706 {
0707 struct xvcu_device *xvcu;
0708
0709 xvcu = platform_get_drvdata(pdev);
0710 if (!xvcu)
0711 return -ENODEV;
0712
0713 xvcu_unregister_clock_provider(xvcu);
0714
0715
0716 regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
0717
0718 clk_disable_unprepare(xvcu->aclk);
0719
0720 return 0;
0721 }
0722
0723 static const struct of_device_id xvcu_of_id_table[] = {
0724 { .compatible = "xlnx,vcu" },
0725 { .compatible = "xlnx,vcu-logicoreip-1.0" },
0726 { }
0727 };
0728 MODULE_DEVICE_TABLE(of, xvcu_of_id_table);
0729
0730 static struct platform_driver xvcu_driver = {
0731 .driver = {
0732 .name = "xilinx-vcu",
0733 .of_match_table = xvcu_of_id_table,
0734 },
0735 .probe = xvcu_probe,
0736 .remove = xvcu_remove,
0737 };
0738
0739 module_platform_driver(xvcu_driver);
0740
0741 MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
0742 MODULE_DESCRIPTION("Xilinx VCU init Driver");
0743 MODULE_LICENSE("GPL v2");