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