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 */ 105struct 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 */ 123struct 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 132static 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 */ 244static 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 */ 255static 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 */ 268static 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 */ 294static 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 */ 447static 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 */ 497static 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(&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(&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 578error_pll_ref: 579 clk_disable_unprepare(xvcu->pll_ref); 580error_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 */ 593static 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 610static const struct of_device_id xvcu_of_id_table[] = { 611 { .compatible = "xlnx,vcu" }, 612 { .compatible = "xlnx,vcu-logicoreip-1.0" }, 613 { } 614}; 615MODULE_DEVICE_TABLE(of, xvcu_of_id_table); 616 617static 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 626module_platform_driver(xvcu_driver); 627 628MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>"); 629MODULE_DESCRIPTION("Xilinx VCU init Driver"); 630MODULE_LICENSE("GPL v2"); 631