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