162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Xilinx VCU Init 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016 - 2017 Xilinx, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Contacts Dhaval Shah <dshah@xilinx.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/bitfield.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/clk-provider.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1662306a36Sopenharmony_ci#include <linux/mfd/syscon/xlnx-vcu.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/regmap.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <dt-bindings/clock/xlnx-vcu.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define VCU_PLL_CTRL 0x24 2562306a36Sopenharmony_ci#define VCU_PLL_CTRL_RESET BIT(0) 2662306a36Sopenharmony_ci#define VCU_PLL_CTRL_POR_IN BIT(1) 2762306a36Sopenharmony_ci#define VCU_PLL_CTRL_PWR_POR BIT(2) 2862306a36Sopenharmony_ci#define VCU_PLL_CTRL_BYPASS BIT(3) 2962306a36Sopenharmony_ci#define VCU_PLL_CTRL_FBDIV GENMASK(14, 8) 3062306a36Sopenharmony_ci#define VCU_PLL_CTRL_CLKOUTDIV GENMASK(18, 16) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define VCU_PLL_CFG 0x28 3362306a36Sopenharmony_ci#define VCU_PLL_CFG_RES GENMASK(3, 0) 3462306a36Sopenharmony_ci#define VCU_PLL_CFG_CP GENMASK(8, 5) 3562306a36Sopenharmony_ci#define VCU_PLL_CFG_LFHF GENMASK(12, 10) 3662306a36Sopenharmony_ci#define VCU_PLL_CFG_LOCK_CNT GENMASK(22, 13) 3762306a36Sopenharmony_ci#define VCU_PLL_CFG_LOCK_DLY GENMASK(31, 25) 3862306a36Sopenharmony_ci#define VCU_ENC_CORE_CTRL 0x30 3962306a36Sopenharmony_ci#define VCU_ENC_MCU_CTRL 0x34 4062306a36Sopenharmony_ci#define VCU_DEC_CORE_CTRL 0x38 4162306a36Sopenharmony_ci#define VCU_DEC_MCU_CTRL 0x3c 4262306a36Sopenharmony_ci#define VCU_PLL_STATUS 0x60 4362306a36Sopenharmony_ci#define VCU_PLL_STATUS_LOCK_STATUS BIT(0) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define MHZ 1000000 4662306a36Sopenharmony_ci#define FVCO_MIN (1500U * MHZ) 4762306a36Sopenharmony_ci#define FVCO_MAX (3000U * MHZ) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/** 5062306a36Sopenharmony_ci * struct xvcu_device - Xilinx VCU init device structure 5162306a36Sopenharmony_ci * @dev: Platform device 5262306a36Sopenharmony_ci * @pll_ref: pll ref clock source 5362306a36Sopenharmony_ci * @aclk: axi clock source 5462306a36Sopenharmony_ci * @logicore_reg_ba: logicore reg base address 5562306a36Sopenharmony_ci * @vcu_slcr_ba: vcu_slcr Register base address 5662306a36Sopenharmony_ci * @pll: handle for the VCU PLL 5762306a36Sopenharmony_ci * @pll_post: handle for the VCU PLL post divider 5862306a36Sopenharmony_ci * @clk_data: clocks provided by the vcu clock provider 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistruct xvcu_device { 6162306a36Sopenharmony_ci struct device *dev; 6262306a36Sopenharmony_ci struct clk *pll_ref; 6362306a36Sopenharmony_ci struct clk *aclk; 6462306a36Sopenharmony_ci struct regmap *logicore_reg_ba; 6562306a36Sopenharmony_ci void __iomem *vcu_slcr_ba; 6662306a36Sopenharmony_ci struct clk_hw *pll; 6762306a36Sopenharmony_ci struct clk_hw *pll_post; 6862306a36Sopenharmony_ci struct clk_hw_onecell_data *clk_data; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic struct regmap_config vcu_settings_regmap_config = { 7262306a36Sopenharmony_ci .name = "regmap", 7362306a36Sopenharmony_ci .reg_bits = 32, 7462306a36Sopenharmony_ci .val_bits = 32, 7562306a36Sopenharmony_ci .reg_stride = 4, 7662306a36Sopenharmony_ci .max_register = 0xfff, 7762306a36Sopenharmony_ci .cache_type = REGCACHE_NONE, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/** 8162306a36Sopenharmony_ci * struct xvcu_pll_cfg - Helper data 8262306a36Sopenharmony_ci * @fbdiv: The integer portion of the feedback divider to the PLL 8362306a36Sopenharmony_ci * @cp: PLL charge pump control 8462306a36Sopenharmony_ci * @res: PLL loop filter resistor control 8562306a36Sopenharmony_ci * @lfhf: PLL loop filter high frequency capacitor control 8662306a36Sopenharmony_ci * @lock_dly: Lock circuit configuration settings for lock windowsize 8762306a36Sopenharmony_ci * @lock_cnt: Lock circuit counter setting 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistruct xvcu_pll_cfg { 9062306a36Sopenharmony_ci u32 fbdiv; 9162306a36Sopenharmony_ci u32 cp; 9262306a36Sopenharmony_ci u32 res; 9362306a36Sopenharmony_ci u32 lfhf; 9462306a36Sopenharmony_ci u32 lock_dly; 9562306a36Sopenharmony_ci u32 lock_cnt; 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct xvcu_pll_cfg xvcu_pll_cfg[] = { 9962306a36Sopenharmony_ci { 25, 3, 10, 3, 63, 1000 }, 10062306a36Sopenharmony_ci { 26, 3, 10, 3, 63, 1000 }, 10162306a36Sopenharmony_ci { 27, 4, 6, 3, 63, 1000 }, 10262306a36Sopenharmony_ci { 28, 4, 6, 3, 63, 1000 }, 10362306a36Sopenharmony_ci { 29, 4, 6, 3, 63, 1000 }, 10462306a36Sopenharmony_ci { 30, 4, 6, 3, 63, 1000 }, 10562306a36Sopenharmony_ci { 31, 6, 1, 3, 63, 1000 }, 10662306a36Sopenharmony_ci { 32, 6, 1, 3, 63, 1000 }, 10762306a36Sopenharmony_ci { 33, 4, 10, 3, 63, 1000 }, 10862306a36Sopenharmony_ci { 34, 5, 6, 3, 63, 1000 }, 10962306a36Sopenharmony_ci { 35, 5, 6, 3, 63, 1000 }, 11062306a36Sopenharmony_ci { 36, 5, 6, 3, 63, 1000 }, 11162306a36Sopenharmony_ci { 37, 5, 6, 3, 63, 1000 }, 11262306a36Sopenharmony_ci { 38, 5, 6, 3, 63, 975 }, 11362306a36Sopenharmony_ci { 39, 3, 12, 3, 63, 950 }, 11462306a36Sopenharmony_ci { 40, 3, 12, 3, 63, 925 }, 11562306a36Sopenharmony_ci { 41, 3, 12, 3, 63, 900 }, 11662306a36Sopenharmony_ci { 42, 3, 12, 3, 63, 875 }, 11762306a36Sopenharmony_ci { 43, 3, 12, 3, 63, 850 }, 11862306a36Sopenharmony_ci { 44, 3, 12, 3, 63, 850 }, 11962306a36Sopenharmony_ci { 45, 3, 12, 3, 63, 825 }, 12062306a36Sopenharmony_ci { 46, 3, 12, 3, 63, 800 }, 12162306a36Sopenharmony_ci { 47, 3, 12, 3, 63, 775 }, 12262306a36Sopenharmony_ci { 48, 3, 12, 3, 63, 775 }, 12362306a36Sopenharmony_ci { 49, 3, 12, 3, 63, 750 }, 12462306a36Sopenharmony_ci { 50, 3, 12, 3, 63, 750 }, 12562306a36Sopenharmony_ci { 51, 3, 2, 3, 63, 725 }, 12662306a36Sopenharmony_ci { 52, 3, 2, 3, 63, 700 }, 12762306a36Sopenharmony_ci { 53, 3, 2, 3, 63, 700 }, 12862306a36Sopenharmony_ci { 54, 3, 2, 3, 63, 675 }, 12962306a36Sopenharmony_ci { 55, 3, 2, 3, 63, 675 }, 13062306a36Sopenharmony_ci { 56, 3, 2, 3, 63, 650 }, 13162306a36Sopenharmony_ci { 57, 3, 2, 3, 63, 650 }, 13262306a36Sopenharmony_ci { 58, 3, 2, 3, 63, 625 }, 13362306a36Sopenharmony_ci { 59, 3, 2, 3, 63, 625 }, 13462306a36Sopenharmony_ci { 60, 3, 2, 3, 63, 625 }, 13562306a36Sopenharmony_ci { 61, 3, 2, 3, 63, 600 }, 13662306a36Sopenharmony_ci { 62, 3, 2, 3, 63, 600 }, 13762306a36Sopenharmony_ci { 63, 3, 2, 3, 63, 600 }, 13862306a36Sopenharmony_ci { 64, 3, 2, 3, 63, 600 }, 13962306a36Sopenharmony_ci { 65, 3, 2, 3, 63, 600 }, 14062306a36Sopenharmony_ci { 66, 3, 2, 3, 63, 600 }, 14162306a36Sopenharmony_ci { 67, 3, 2, 3, 63, 600 }, 14262306a36Sopenharmony_ci { 68, 3, 2, 3, 63, 600 }, 14362306a36Sopenharmony_ci { 69, 3, 2, 3, 63, 600 }, 14462306a36Sopenharmony_ci { 70, 3, 2, 3, 63, 600 }, 14562306a36Sopenharmony_ci { 71, 3, 2, 3, 63, 600 }, 14662306a36Sopenharmony_ci { 72, 3, 2, 3, 63, 600 }, 14762306a36Sopenharmony_ci { 73, 3, 2, 3, 63, 600 }, 14862306a36Sopenharmony_ci { 74, 3, 2, 3, 63, 600 }, 14962306a36Sopenharmony_ci { 75, 3, 2, 3, 63, 600 }, 15062306a36Sopenharmony_ci { 76, 3, 2, 3, 63, 600 }, 15162306a36Sopenharmony_ci { 77, 3, 2, 3, 63, 600 }, 15262306a36Sopenharmony_ci { 78, 3, 2, 3, 63, 600 }, 15362306a36Sopenharmony_ci { 79, 3, 2, 3, 63, 600 }, 15462306a36Sopenharmony_ci { 80, 3, 2, 3, 63, 600 }, 15562306a36Sopenharmony_ci { 81, 3, 2, 3, 63, 600 }, 15662306a36Sopenharmony_ci { 82, 3, 2, 3, 63, 600 }, 15762306a36Sopenharmony_ci { 83, 4, 2, 3, 63, 600 }, 15862306a36Sopenharmony_ci { 84, 4, 2, 3, 63, 600 }, 15962306a36Sopenharmony_ci { 85, 4, 2, 3, 63, 600 }, 16062306a36Sopenharmony_ci { 86, 4, 2, 3, 63, 600 }, 16162306a36Sopenharmony_ci { 87, 4, 2, 3, 63, 600 }, 16262306a36Sopenharmony_ci { 88, 4, 2, 3, 63, 600 }, 16362306a36Sopenharmony_ci { 89, 4, 2, 3, 63, 600 }, 16462306a36Sopenharmony_ci { 90, 4, 2, 3, 63, 600 }, 16562306a36Sopenharmony_ci { 91, 4, 2, 3, 63, 600 }, 16662306a36Sopenharmony_ci { 92, 4, 2, 3, 63, 600 }, 16762306a36Sopenharmony_ci { 93, 4, 2, 3, 63, 600 }, 16862306a36Sopenharmony_ci { 94, 4, 2, 3, 63, 600 }, 16962306a36Sopenharmony_ci { 95, 4, 2, 3, 63, 600 }, 17062306a36Sopenharmony_ci { 96, 4, 2, 3, 63, 600 }, 17162306a36Sopenharmony_ci { 97, 4, 2, 3, 63, 600 }, 17262306a36Sopenharmony_ci { 98, 4, 2, 3, 63, 600 }, 17362306a36Sopenharmony_ci { 99, 4, 2, 3, 63, 600 }, 17462306a36Sopenharmony_ci { 100, 4, 2, 3, 63, 600 }, 17562306a36Sopenharmony_ci { 101, 4, 2, 3, 63, 600 }, 17662306a36Sopenharmony_ci { 102, 4, 2, 3, 63, 600 }, 17762306a36Sopenharmony_ci { 103, 5, 2, 3, 63, 600 }, 17862306a36Sopenharmony_ci { 104, 5, 2, 3, 63, 600 }, 17962306a36Sopenharmony_ci { 105, 5, 2, 3, 63, 600 }, 18062306a36Sopenharmony_ci { 106, 5, 2, 3, 63, 600 }, 18162306a36Sopenharmony_ci { 107, 3, 4, 3, 63, 600 }, 18262306a36Sopenharmony_ci { 108, 3, 4, 3, 63, 600 }, 18362306a36Sopenharmony_ci { 109, 3, 4, 3, 63, 600 }, 18462306a36Sopenharmony_ci { 110, 3, 4, 3, 63, 600 }, 18562306a36Sopenharmony_ci { 111, 3, 4, 3, 63, 600 }, 18662306a36Sopenharmony_ci { 112, 3, 4, 3, 63, 600 }, 18762306a36Sopenharmony_ci { 113, 3, 4, 3, 63, 600 }, 18862306a36Sopenharmony_ci { 114, 3, 4, 3, 63, 600 }, 18962306a36Sopenharmony_ci { 115, 3, 4, 3, 63, 600 }, 19062306a36Sopenharmony_ci { 116, 3, 4, 3, 63, 600 }, 19162306a36Sopenharmony_ci { 117, 3, 4, 3, 63, 600 }, 19262306a36Sopenharmony_ci { 118, 3, 4, 3, 63, 600 }, 19362306a36Sopenharmony_ci { 119, 3, 4, 3, 63, 600 }, 19462306a36Sopenharmony_ci { 120, 3, 4, 3, 63, 600 }, 19562306a36Sopenharmony_ci { 121, 3, 4, 3, 63, 600 }, 19662306a36Sopenharmony_ci { 122, 3, 4, 3, 63, 600 }, 19762306a36Sopenharmony_ci { 123, 3, 4, 3, 63, 600 }, 19862306a36Sopenharmony_ci { 124, 3, 4, 3, 63, 600 }, 19962306a36Sopenharmony_ci { 125, 3, 4, 3, 63, 600 }, 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/** 20362306a36Sopenharmony_ci * xvcu_read - Read from the VCU register space 20462306a36Sopenharmony_ci * @iomem: vcu reg space base address 20562306a36Sopenharmony_ci * @offset: vcu reg offset from base 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * Return: Returns 32bit value from VCU register specified 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_cistatic inline u32 xvcu_read(void __iomem *iomem, u32 offset) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return ioread32(iomem + offset); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/** 21662306a36Sopenharmony_ci * xvcu_write - Write to the VCU register space 21762306a36Sopenharmony_ci * @iomem: vcu reg space base address 21862306a36Sopenharmony_ci * @offset: vcu reg offset from base 21962306a36Sopenharmony_ci * @value: Value to write 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic inline void xvcu_write(void __iomem *iomem, u32 offset, u32 value) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci iowrite32(value, iomem + offset); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci#define to_vcu_pll(_hw) container_of(_hw, struct vcu_pll, hw) 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistruct vcu_pll { 22962306a36Sopenharmony_ci struct clk_hw hw; 23062306a36Sopenharmony_ci void __iomem *reg_base; 23162306a36Sopenharmony_ci unsigned long fvco_min; 23262306a36Sopenharmony_ci unsigned long fvco_max; 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int xvcu_pll_wait_for_lock(struct vcu_pll *pll) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci void __iomem *base = pll->reg_base; 23862306a36Sopenharmony_ci unsigned long timeout; 23962306a36Sopenharmony_ci u32 lock_status; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(2000); 24262306a36Sopenharmony_ci do { 24362306a36Sopenharmony_ci lock_status = xvcu_read(base, VCU_PLL_STATUS); 24462306a36Sopenharmony_ci if (lock_status & VCU_PLL_STATUS_LOCK_STATUS) 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci } while (!time_after(jiffies, timeout)); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return -ETIMEDOUT; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic struct clk_hw *xvcu_register_pll_post(struct device *dev, 25262306a36Sopenharmony_ci const char *name, 25362306a36Sopenharmony_ci const struct clk_hw *parent_hw, 25462306a36Sopenharmony_ci void __iomem *reg_base) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci u32 div; 25762306a36Sopenharmony_ci u32 vcu_pll_ctrl; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * The output divider of the PLL must be set to 1/2 to meet the 26162306a36Sopenharmony_ci * timing in the design. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci vcu_pll_ctrl = xvcu_read(reg_base, VCU_PLL_CTRL); 26462306a36Sopenharmony_ci div = FIELD_GET(VCU_PLL_CTRL_CLKOUTDIV, vcu_pll_ctrl); 26562306a36Sopenharmony_ci if (div != 1) 26662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return clk_hw_register_fixed_factor(dev, "vcu_pll_post", 26962306a36Sopenharmony_ci clk_hw_get_name(parent_hw), 27062306a36Sopenharmony_ci CLK_SET_RATE_PARENT, 1, 2); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic const struct xvcu_pll_cfg *xvcu_find_cfg(int div) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci const struct xvcu_pll_cfg *cfg = NULL; 27662306a36Sopenharmony_ci unsigned int i; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xvcu_pll_cfg) - 1; i++) 27962306a36Sopenharmony_ci if (xvcu_pll_cfg[i].fbdiv == div) 28062306a36Sopenharmony_ci cfg = &xvcu_pll_cfg[i]; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return cfg; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int xvcu_pll_set_div(struct vcu_pll *pll, int div) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci void __iomem *base = pll->reg_base; 28862306a36Sopenharmony_ci const struct xvcu_pll_cfg *cfg = NULL; 28962306a36Sopenharmony_ci u32 vcu_pll_ctrl; 29062306a36Sopenharmony_ci u32 cfg_val; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci cfg = xvcu_find_cfg(div); 29362306a36Sopenharmony_ci if (!cfg) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL); 29762306a36Sopenharmony_ci vcu_pll_ctrl &= ~VCU_PLL_CTRL_FBDIV; 29862306a36Sopenharmony_ci vcu_pll_ctrl |= FIELD_PREP(VCU_PLL_CTRL_FBDIV, cfg->fbdiv); 29962306a36Sopenharmony_ci xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci cfg_val = FIELD_PREP(VCU_PLL_CFG_RES, cfg->res) | 30262306a36Sopenharmony_ci FIELD_PREP(VCU_PLL_CFG_CP, cfg->cp) | 30362306a36Sopenharmony_ci FIELD_PREP(VCU_PLL_CFG_LFHF, cfg->lfhf) | 30462306a36Sopenharmony_ci FIELD_PREP(VCU_PLL_CFG_LOCK_CNT, cfg->lock_cnt) | 30562306a36Sopenharmony_ci FIELD_PREP(VCU_PLL_CFG_LOCK_DLY, cfg->lock_dly); 30662306a36Sopenharmony_ci xvcu_write(base, VCU_PLL_CFG, cfg_val); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic long xvcu_pll_round_rate(struct clk_hw *hw, 31262306a36Sopenharmony_ci unsigned long rate, unsigned long *parent_rate) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct vcu_pll *pll = to_vcu_pll(hw); 31562306a36Sopenharmony_ci unsigned int feedback_div; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci rate = clamp_t(unsigned long, rate, pll->fvco_min, pll->fvco_max); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci feedback_div = DIV_ROUND_CLOSEST_ULL(rate, *parent_rate); 32062306a36Sopenharmony_ci feedback_div = clamp_t(unsigned int, feedback_div, 25, 125); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return *parent_rate * feedback_div; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic unsigned long xvcu_pll_recalc_rate(struct clk_hw *hw, 32662306a36Sopenharmony_ci unsigned long parent_rate) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct vcu_pll *pll = to_vcu_pll(hw); 32962306a36Sopenharmony_ci void __iomem *base = pll->reg_base; 33062306a36Sopenharmony_ci unsigned int div; 33162306a36Sopenharmony_ci u32 vcu_pll_ctrl; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL); 33462306a36Sopenharmony_ci div = FIELD_GET(VCU_PLL_CTRL_FBDIV, vcu_pll_ctrl); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return div * parent_rate; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int xvcu_pll_set_rate(struct clk_hw *hw, 34062306a36Sopenharmony_ci unsigned long rate, unsigned long parent_rate) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct vcu_pll *pll = to_vcu_pll(hw); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return xvcu_pll_set_div(pll, rate / parent_rate); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int xvcu_pll_enable(struct clk_hw *hw) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct vcu_pll *pll = to_vcu_pll(hw); 35062306a36Sopenharmony_ci void __iomem *base = pll->reg_base; 35162306a36Sopenharmony_ci u32 vcu_pll_ctrl; 35262306a36Sopenharmony_ci int ret; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL); 35562306a36Sopenharmony_ci vcu_pll_ctrl |= VCU_PLL_CTRL_BYPASS; 35662306a36Sopenharmony_ci xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL); 35962306a36Sopenharmony_ci vcu_pll_ctrl &= ~VCU_PLL_CTRL_POR_IN; 36062306a36Sopenharmony_ci vcu_pll_ctrl &= ~VCU_PLL_CTRL_PWR_POR; 36162306a36Sopenharmony_ci vcu_pll_ctrl &= ~VCU_PLL_CTRL_RESET; 36262306a36Sopenharmony_ci xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ret = xvcu_pll_wait_for_lock(pll); 36562306a36Sopenharmony_ci if (ret) { 36662306a36Sopenharmony_ci pr_err("VCU PLL is not locked\n"); 36762306a36Sopenharmony_ci goto err; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL); 37162306a36Sopenharmony_ci vcu_pll_ctrl &= ~VCU_PLL_CTRL_BYPASS; 37262306a36Sopenharmony_ci xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cierr: 37562306a36Sopenharmony_ci return ret; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void xvcu_pll_disable(struct clk_hw *hw) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct vcu_pll *pll = to_vcu_pll(hw); 38162306a36Sopenharmony_ci void __iomem *base = pll->reg_base; 38262306a36Sopenharmony_ci u32 vcu_pll_ctrl; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL); 38562306a36Sopenharmony_ci vcu_pll_ctrl |= VCU_PLL_CTRL_POR_IN; 38662306a36Sopenharmony_ci vcu_pll_ctrl |= VCU_PLL_CTRL_PWR_POR; 38762306a36Sopenharmony_ci vcu_pll_ctrl |= VCU_PLL_CTRL_RESET; 38862306a36Sopenharmony_ci xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic const struct clk_ops vcu_pll_ops = { 39262306a36Sopenharmony_ci .enable = xvcu_pll_enable, 39362306a36Sopenharmony_ci .disable = xvcu_pll_disable, 39462306a36Sopenharmony_ci .round_rate = xvcu_pll_round_rate, 39562306a36Sopenharmony_ci .recalc_rate = xvcu_pll_recalc_rate, 39662306a36Sopenharmony_ci .set_rate = xvcu_pll_set_rate, 39762306a36Sopenharmony_ci}; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic struct clk_hw *xvcu_register_pll(struct device *dev, 40062306a36Sopenharmony_ci void __iomem *reg_base, 40162306a36Sopenharmony_ci const char *name, const char *parent, 40262306a36Sopenharmony_ci unsigned long flags) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct vcu_pll *pll; 40562306a36Sopenharmony_ci struct clk_hw *hw; 40662306a36Sopenharmony_ci struct clk_init_data init; 40762306a36Sopenharmony_ci int ret; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci init.name = name; 41062306a36Sopenharmony_ci init.parent_names = &parent; 41162306a36Sopenharmony_ci init.ops = &vcu_pll_ops; 41262306a36Sopenharmony_ci init.num_parents = 1; 41362306a36Sopenharmony_ci init.flags = flags; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci pll = devm_kmalloc(dev, sizeof(*pll), GFP_KERNEL); 41662306a36Sopenharmony_ci if (!pll) 41762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci pll->hw.init = &init; 42062306a36Sopenharmony_ci pll->reg_base = reg_base; 42162306a36Sopenharmony_ci pll->fvco_min = FVCO_MIN; 42262306a36Sopenharmony_ci pll->fvco_max = FVCO_MAX; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci hw = &pll->hw; 42562306a36Sopenharmony_ci ret = devm_clk_hw_register(dev, hw); 42662306a36Sopenharmony_ci if (ret) 42762306a36Sopenharmony_ci return ERR_PTR(ret); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci clk_hw_set_rate_range(hw, pll->fvco_min, pll->fvco_max); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return hw; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic struct clk_hw *xvcu_clk_hw_register_leaf(struct device *dev, 43562306a36Sopenharmony_ci const char *name, 43662306a36Sopenharmony_ci const struct clk_parent_data *parent_data, 43762306a36Sopenharmony_ci u8 num_parents, 43862306a36Sopenharmony_ci void __iomem *reg) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci u8 mux_flags = CLK_MUX_ROUND_CLOSEST; 44162306a36Sopenharmony_ci u8 divider_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | 44262306a36Sopenharmony_ci CLK_DIVIDER_ROUND_CLOSEST; 44362306a36Sopenharmony_ci struct clk_hw *mux = NULL; 44462306a36Sopenharmony_ci struct clk_hw *divider = NULL; 44562306a36Sopenharmony_ci struct clk_hw *gate = NULL; 44662306a36Sopenharmony_ci char *name_mux; 44762306a36Sopenharmony_ci char *name_div; 44862306a36Sopenharmony_ci int err; 44962306a36Sopenharmony_ci /* Protect register shared by clocks */ 45062306a36Sopenharmony_ci spinlock_t *lock; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL); 45362306a36Sopenharmony_ci if (!lock) 45462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 45562306a36Sopenharmony_ci spin_lock_init(lock); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci name_mux = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_mux"); 45862306a36Sopenharmony_ci if (!name_mux) 45962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 46062306a36Sopenharmony_ci mux = clk_hw_register_mux_parent_data(dev, name_mux, 46162306a36Sopenharmony_ci parent_data, num_parents, 46262306a36Sopenharmony_ci CLK_SET_RATE_PARENT, 46362306a36Sopenharmony_ci reg, 0, 1, mux_flags, lock); 46462306a36Sopenharmony_ci if (IS_ERR(mux)) 46562306a36Sopenharmony_ci return mux; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci name_div = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_div"); 46862306a36Sopenharmony_ci if (!name_div) { 46962306a36Sopenharmony_ci err = -ENOMEM; 47062306a36Sopenharmony_ci goto unregister_mux; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci divider = clk_hw_register_divider_parent_hw(dev, name_div, mux, 47362306a36Sopenharmony_ci CLK_SET_RATE_PARENT, 47462306a36Sopenharmony_ci reg, 4, 6, divider_flags, 47562306a36Sopenharmony_ci lock); 47662306a36Sopenharmony_ci if (IS_ERR(divider)) { 47762306a36Sopenharmony_ci err = PTR_ERR(divider); 47862306a36Sopenharmony_ci goto unregister_mux; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci gate = clk_hw_register_gate_parent_hw(dev, name, divider, 48262306a36Sopenharmony_ci CLK_SET_RATE_PARENT, reg, 12, 0, 48362306a36Sopenharmony_ci lock); 48462306a36Sopenharmony_ci if (IS_ERR(gate)) { 48562306a36Sopenharmony_ci err = PTR_ERR(gate); 48662306a36Sopenharmony_ci goto unregister_divider; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return gate; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ciunregister_divider: 49262306a36Sopenharmony_ci clk_hw_unregister_divider(divider); 49362306a36Sopenharmony_ciunregister_mux: 49462306a36Sopenharmony_ci clk_hw_unregister_mux(mux); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return ERR_PTR(err); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void xvcu_clk_hw_unregister_leaf(struct clk_hw *hw) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct clk_hw *gate = hw; 50262306a36Sopenharmony_ci struct clk_hw *divider; 50362306a36Sopenharmony_ci struct clk_hw *mux; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (!gate) 50662306a36Sopenharmony_ci return; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci divider = clk_hw_get_parent(gate); 50962306a36Sopenharmony_ci clk_hw_unregister_gate(gate); 51062306a36Sopenharmony_ci if (!divider) 51162306a36Sopenharmony_ci return; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci mux = clk_hw_get_parent(divider); 51462306a36Sopenharmony_ci clk_hw_unregister_mux(mux); 51562306a36Sopenharmony_ci if (!divider) 51662306a36Sopenharmony_ci return; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci clk_hw_unregister_divider(divider); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int xvcu_register_clock_provider(struct xvcu_device *xvcu) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct device *dev = xvcu->dev; 52462306a36Sopenharmony_ci struct clk_parent_data parent_data[2] = { 0 }; 52562306a36Sopenharmony_ci struct clk_hw_onecell_data *data; 52662306a36Sopenharmony_ci struct clk_hw **hws; 52762306a36Sopenharmony_ci struct clk_hw *hw; 52862306a36Sopenharmony_ci void __iomem *reg_base = xvcu->vcu_slcr_ba; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci data = devm_kzalloc(dev, struct_size(data, hws, CLK_XVCU_NUM_CLOCKS), GFP_KERNEL); 53162306a36Sopenharmony_ci if (!data) 53262306a36Sopenharmony_ci return -ENOMEM; 53362306a36Sopenharmony_ci data->num = CLK_XVCU_NUM_CLOCKS; 53462306a36Sopenharmony_ci hws = data->hws; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci xvcu->clk_data = data; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci hw = xvcu_register_pll(dev, reg_base, 53962306a36Sopenharmony_ci "vcu_pll", __clk_get_name(xvcu->pll_ref), 54062306a36Sopenharmony_ci CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE); 54162306a36Sopenharmony_ci if (IS_ERR(hw)) 54262306a36Sopenharmony_ci return PTR_ERR(hw); 54362306a36Sopenharmony_ci xvcu->pll = hw; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci hw = xvcu_register_pll_post(dev, "vcu_pll_post", xvcu->pll, reg_base); 54662306a36Sopenharmony_ci if (IS_ERR(hw)) 54762306a36Sopenharmony_ci return PTR_ERR(hw); 54862306a36Sopenharmony_ci xvcu->pll_post = hw; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci parent_data[0].fw_name = "pll_ref"; 55162306a36Sopenharmony_ci parent_data[1].hw = xvcu->pll_post; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci hws[CLK_XVCU_ENC_CORE] = 55462306a36Sopenharmony_ci xvcu_clk_hw_register_leaf(dev, "venc_core_clk", 55562306a36Sopenharmony_ci parent_data, 55662306a36Sopenharmony_ci ARRAY_SIZE(parent_data), 55762306a36Sopenharmony_ci reg_base + VCU_ENC_CORE_CTRL); 55862306a36Sopenharmony_ci hws[CLK_XVCU_ENC_MCU] = 55962306a36Sopenharmony_ci xvcu_clk_hw_register_leaf(dev, "venc_mcu_clk", 56062306a36Sopenharmony_ci parent_data, 56162306a36Sopenharmony_ci ARRAY_SIZE(parent_data), 56262306a36Sopenharmony_ci reg_base + VCU_ENC_MCU_CTRL); 56362306a36Sopenharmony_ci hws[CLK_XVCU_DEC_CORE] = 56462306a36Sopenharmony_ci xvcu_clk_hw_register_leaf(dev, "vdec_core_clk", 56562306a36Sopenharmony_ci parent_data, 56662306a36Sopenharmony_ci ARRAY_SIZE(parent_data), 56762306a36Sopenharmony_ci reg_base + VCU_DEC_CORE_CTRL); 56862306a36Sopenharmony_ci hws[CLK_XVCU_DEC_MCU] = 56962306a36Sopenharmony_ci xvcu_clk_hw_register_leaf(dev, "vdec_mcu_clk", 57062306a36Sopenharmony_ci parent_data, 57162306a36Sopenharmony_ci ARRAY_SIZE(parent_data), 57262306a36Sopenharmony_ci reg_base + VCU_DEC_MCU_CTRL); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic void xvcu_unregister_clock_provider(struct xvcu_device *xvcu) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct clk_hw_onecell_data *data = xvcu->clk_data; 58062306a36Sopenharmony_ci struct clk_hw **hws = data->hws; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_MCU])) 58362306a36Sopenharmony_ci xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_MCU]); 58462306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_CORE])) 58562306a36Sopenharmony_ci xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_CORE]); 58662306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_MCU])) 58762306a36Sopenharmony_ci xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_MCU]); 58862306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_CORE])) 58962306a36Sopenharmony_ci xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_CORE]); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci clk_hw_unregister_fixed_factor(xvcu->pll_post); 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/** 59562306a36Sopenharmony_ci * xvcu_probe - Probe existence of the logicoreIP 59662306a36Sopenharmony_ci * and initialize PLL 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * @pdev: Pointer to the platform_device structure 59962306a36Sopenharmony_ci * 60062306a36Sopenharmony_ci * Return: Returns 0 on success 60162306a36Sopenharmony_ci * Negative error code otherwise 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_cistatic int xvcu_probe(struct platform_device *pdev) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct resource *res; 60662306a36Sopenharmony_ci struct xvcu_device *xvcu; 60762306a36Sopenharmony_ci void __iomem *regs; 60862306a36Sopenharmony_ci int ret; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL); 61162306a36Sopenharmony_ci if (!xvcu) 61262306a36Sopenharmony_ci return -ENOMEM; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci xvcu->dev = &pdev->dev; 61562306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr"); 61662306a36Sopenharmony_ci if (!res) { 61762306a36Sopenharmony_ci dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n"); 61862306a36Sopenharmony_ci return -ENODEV; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci xvcu->vcu_slcr_ba = devm_ioremap(&pdev->dev, res->start, 62262306a36Sopenharmony_ci resource_size(res)); 62362306a36Sopenharmony_ci if (!xvcu->vcu_slcr_ba) { 62462306a36Sopenharmony_ci dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n"); 62562306a36Sopenharmony_ci return -ENOMEM; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci xvcu->logicore_reg_ba = 62962306a36Sopenharmony_ci syscon_regmap_lookup_by_compatible("xlnx,vcu-settings"); 63062306a36Sopenharmony_ci if (IS_ERR(xvcu->logicore_reg_ba)) { 63162306a36Sopenharmony_ci dev_info(&pdev->dev, 63262306a36Sopenharmony_ci "could not find xlnx,vcu-settings: trying direct register access\n"); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, 63562306a36Sopenharmony_ci IORESOURCE_MEM, "logicore"); 63662306a36Sopenharmony_ci if (!res) { 63762306a36Sopenharmony_ci dev_err(&pdev->dev, "get logicore memory resource failed.\n"); 63862306a36Sopenharmony_ci return -ENODEV; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 64262306a36Sopenharmony_ci if (!regs) { 64362306a36Sopenharmony_ci dev_err(&pdev->dev, "logicore register mapping failed.\n"); 64462306a36Sopenharmony_ci return -ENOMEM; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci xvcu->logicore_reg_ba = 64862306a36Sopenharmony_ci devm_regmap_init_mmio(&pdev->dev, regs, 64962306a36Sopenharmony_ci &vcu_settings_regmap_config); 65062306a36Sopenharmony_ci if (IS_ERR(xvcu->logicore_reg_ba)) { 65162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to init regmap\n"); 65262306a36Sopenharmony_ci return PTR_ERR(xvcu->logicore_reg_ba); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci xvcu->aclk = devm_clk_get(&pdev->dev, "aclk"); 65762306a36Sopenharmony_ci if (IS_ERR(xvcu->aclk)) { 65862306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not get aclk clock\n"); 65962306a36Sopenharmony_ci return PTR_ERR(xvcu->aclk); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref"); 66362306a36Sopenharmony_ci if (IS_ERR(xvcu->pll_ref)) { 66462306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not get pll_ref clock\n"); 66562306a36Sopenharmony_ci return PTR_ERR(xvcu->pll_ref); 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci ret = clk_prepare_enable(xvcu->aclk); 66962306a36Sopenharmony_ci if (ret) { 67062306a36Sopenharmony_ci dev_err(&pdev->dev, "aclk clock enable failed\n"); 67162306a36Sopenharmony_ci return ret; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * Do the Gasket isolation and put the VCU out of reset 67662306a36Sopenharmony_ci * Bit 0 : Gasket isolation 67762306a36Sopenharmony_ci * Bit 1 : put VCU out of reset 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ret = xvcu_register_clock_provider(xvcu); 68262306a36Sopenharmony_ci if (ret) { 68362306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register clock provider\n"); 68462306a36Sopenharmony_ci goto error_clk_provider; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci dev_set_drvdata(&pdev->dev, xvcu); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cierror_clk_provider: 69262306a36Sopenharmony_ci xvcu_unregister_clock_provider(xvcu); 69362306a36Sopenharmony_ci clk_disable_unprepare(xvcu->aclk); 69462306a36Sopenharmony_ci return ret; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/** 69862306a36Sopenharmony_ci * xvcu_remove - Insert gasket isolation 69962306a36Sopenharmony_ci * and disable the clock 70062306a36Sopenharmony_ci * @pdev: Pointer to the platform_device structure 70162306a36Sopenharmony_ci * 70262306a36Sopenharmony_ci * Return: Returns 0 on success 70362306a36Sopenharmony_ci * Negative error code otherwise 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_cistatic void xvcu_remove(struct platform_device *pdev) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct xvcu_device *xvcu; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci xvcu = platform_get_drvdata(pdev); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci xvcu_unregister_clock_provider(xvcu); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Add the Gasket isolation and put the VCU in reset. */ 71462306a36Sopenharmony_ci regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci clk_disable_unprepare(xvcu->aclk); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic const struct of_device_id xvcu_of_id_table[] = { 72062306a36Sopenharmony_ci { .compatible = "xlnx,vcu" }, 72162306a36Sopenharmony_ci { .compatible = "xlnx,vcu-logicoreip-1.0" }, 72262306a36Sopenharmony_ci { } 72362306a36Sopenharmony_ci}; 72462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, xvcu_of_id_table); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic struct platform_driver xvcu_driver = { 72762306a36Sopenharmony_ci .driver = { 72862306a36Sopenharmony_ci .name = "xilinx-vcu", 72962306a36Sopenharmony_ci .of_match_table = xvcu_of_id_table, 73062306a36Sopenharmony_ci }, 73162306a36Sopenharmony_ci .probe = xvcu_probe, 73262306a36Sopenharmony_ci .remove_new = xvcu_remove, 73362306a36Sopenharmony_ci}; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cimodule_platform_driver(xvcu_driver); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ciMODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>"); 73862306a36Sopenharmony_ciMODULE_DESCRIPTION("Xilinx VCU init Driver"); 73962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 740