Эх сурвалжийг харах

disp: msm: dsi: add new PHY and PLL version files

Change adds the new files for DSI PHY version 5 and 4nm
DSI PLL.

Change-Id: I97712d6ce53a60a6fae1c8331b6ba9a5d17b8d34
Signed-off-by: Shashank Babu Chinta Venkata <[email protected]>
Shashank Babu Chinta Venkata 3 жил өмнө
parent
commit
122df95255

+ 2 - 0
msm/Kbuild

@@ -198,11 +198,13 @@ msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi_phy.o \
 				 dsi/dsi_phy.o \
 				 dsi/dsi_phy_hw_v3_0.o \
 				 dsi/dsi_phy_hw_v4_0.o \
+				 dsi/dsi_phy_hw_v5_0.o \
 				 dsi/dsi_phy_timing_calc.o \
 				 dsi/dsi_phy_timing_v3_0.o \
 				 dsi/dsi_phy_timing_v4_0.o \
 				 dsi/dsi_pll.o \
 				 dsi/dsi_pll_5nm.o \
+				 dsi/dsi_pll_4nm.o \
 				 dsi/dsi_ctrl_hw_cmn.o \
 				 dsi/dsi_ctrl_hw_2_2.o \
 				 dsi/dsi_ctrl.o \

+ 37 - 1
msm/dsi/dsi_catalog.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/errno.h>
@@ -231,6 +232,35 @@ static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy)
 	phy->ops.commit_phy_timing = dsi_phy_hw_v4_0_commit_phy_timing;
 }
 
+/**
+ * dsi_catalog_phy_5_0_init() - catalog init for DSI PHY 7nm
+ */
+static void dsi_catalog_phy_5_0_init(struct dsi_phy_hw *phy)
+{
+	phy->ops.regulator_enable = NULL;
+	phy->ops.regulator_disable = NULL;
+	phy->ops.enable = dsi_phy_hw_v5_0_enable;
+	phy->ops.disable = dsi_phy_hw_v5_0_disable;
+	phy->ops.calculate_timing_params = dsi_phy_hw_calculate_timing_params;
+	phy->ops.ulps_ops.wait_for_lane_idle = dsi_phy_hw_v5_0_wait_for_lane_idle;
+	phy->ops.ulps_ops.ulps_request = dsi_phy_hw_v5_0_ulps_request;
+	phy->ops.ulps_ops.ulps_exit = dsi_phy_hw_v5_0_ulps_exit;
+	phy->ops.ulps_ops.get_lanes_in_ulps = dsi_phy_hw_v5_0_get_lanes_in_ulps;
+	phy->ops.ulps_ops.is_lanes_in_ulps = dsi_phy_hw_v5_0_is_lanes_in_ulps;
+	phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v5_0;
+	phy->ops.phy_lane_reset = dsi_phy_hw_v5_0_lane_reset;
+	phy->ops.toggle_resync_fifo = dsi_phy_hw_v5_0_toggle_resync_fifo;
+	phy->ops.reset_clk_en_sel = dsi_phy_hw_v5_0_reset_clk_en_sel;
+
+	phy->ops.dyn_refresh_ops.dyn_refresh_config = dsi_phy_hw_v5_0_dyn_refresh_config;
+	phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay = dsi_phy_hw_v5_0_dyn_refresh_pipe_delay;
+	phy->ops.dyn_refresh_ops.dyn_refresh_helper = dsi_phy_hw_v5_0_dyn_refresh_helper;
+	phy->ops.dyn_refresh_ops.dyn_refresh_trigger_sel = dsi_phy_hw_v5_0_dyn_refresh_trigger_sel;
+	phy->ops.dyn_refresh_ops.cache_phy_timings = dsi_phy_hw_v5_0_cache_phy_timings;
+	phy->ops.set_continuous_clk = dsi_phy_hw_v5_0_set_continuous_clk;
+	phy->ops.commit_phy_timing = dsi_phy_hw_v5_0_commit_phy_timing;
+}
+
 /**
  * dsi_catalog_phy_setup() - return catalog info for dsi phy hardware
  * @ctrl:        Pointer to DSI PHY hw object.
@@ -267,9 +297,11 @@ int dsi_catalog_phy_setup(struct dsi_phy_hw *phy,
 	case DSI_PHY_VERSION_4_1:
 	case DSI_PHY_VERSION_4_2:
 	case DSI_PHY_VERSION_4_3:
-	case DSI_PHY_VERSION_5_2:
 		dsi_catalog_phy_4_0_init(phy);
 		break;
+	case DSI_PHY_VERSION_5_2:
+		dsi_catalog_phy_5_0_init(phy);
+		break;
 	default:
 		return -ENOTSUPP;
 	}
@@ -291,6 +323,10 @@ int dsi_catalog_phy_pll_setup(struct dsi_phy_hw *phy, u32 pll_ver)
 		phy->ops.configure = dsi_pll_5nm_configure;
 		phy->ops.pll_toggle = dsi_pll_5nm_toggle;
 		break;
+	case DSI_PLL_VERSION_4NM:
+		phy->ops.configure = dsi_pll_4nm_configure;
+		phy->ops.pll_toggle = dsi_pll_4nm_toggle;
+		break;
 	default:
 		phy->ops.configure = NULL;
 		phy->ops.pll_toggle = NULL;

+ 31 - 0
msm/dsi/dsi_catalog.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _DSI_CATALOG_H_
@@ -126,6 +127,24 @@ void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable);
 void dsi_phy_hw_v4_0_commit_phy_timing(struct dsi_phy_hw *phy,
 		struct dsi_phy_per_lane_cfgs *timing);
 
+/* Definitions for 4nm PHY hardware driver */
+void dsi_phy_hw_v5_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
+void dsi_phy_hw_v5_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
+int dsi_phy_hw_v5_0_wait_for_lane_idle(struct dsi_phy_hw *phy, u32 lanes);
+void dsi_phy_hw_v5_0_ulps_request(struct dsi_phy_hw *phy,
+		struct dsi_phy_cfg *cfg, u32 lanes);
+void dsi_phy_hw_v5_0_ulps_exit(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg, u32 lanes);
+u32 dsi_phy_hw_v5_0_get_lanes_in_ulps(struct dsi_phy_hw *phy);
+bool dsi_phy_hw_v5_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes);
+int dsi_phy_hw_timing_val_v5_0(struct dsi_phy_per_lane_cfgs *timing_cfg, u32 *timing_val,
+		u32 size);
+int dsi_phy_hw_v5_0_lane_reset(struct dsi_phy_hw *phy);
+void dsi_phy_hw_v5_0_toggle_resync_fifo(struct dsi_phy_hw *phy);
+void dsi_phy_hw_v5_0_reset_clk_en_sel(struct dsi_phy_hw *phy);
+void dsi_phy_hw_v5_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable);
+void dsi_phy_hw_v5_0_commit_phy_timing(struct dsi_phy_hw *phy,
+		struct dsi_phy_per_lane_cfgs *timing);
+
 /* DSI controller common ops */
 u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl);
 u32 dsi_ctrl_hw_cmn_poll_dma_status(struct dsi_ctrl_hw *ctrl);
@@ -279,6 +298,16 @@ void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
 int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
 				      u32 *dst, u32 size);
 
+void dsi_phy_hw_v5_0_dyn_refresh_trigger_sel(struct dsi_phy_hw *phy,
+		bool is_master);
+void dsi_phy_hw_v5_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
+void dsi_phy_hw_v5_0_dyn_refresh_config(struct dsi_phy_hw *phy,
+				struct dsi_phy_cfg *cfg, bool is_master);
+void dsi_phy_hw_v5_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
+					    struct dsi_dyn_clk_delay *delay);
+
+int dsi_phy_hw_v5_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
+				      u32 *dst, u32 size);
 void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
 		struct dsi_ctrl_cmd_dma_info *cmd,
 		u32 line_no, u32 window);
@@ -290,6 +319,8 @@ u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
 int dsi_catalog_phy_pll_setup(struct dsi_phy_hw *phy, u32 pll_ver);
 int dsi_pll_5nm_configure(void *pll, bool commit);
 int dsi_pll_5nm_toggle(void *pll, bool prepare);
+int dsi_pll_4nm_configure(void *pll, bool commit);
+int dsi_pll_4nm_toggle(void *pll, bool prepare);
 
 void dsi_ctrl_hw_22_configure_splitlink(struct dsi_ctrl_hw *ctrl,
 		struct dsi_host_common_cfg *common_cfg, u32 sublink);

+ 3 - 0
msm/dsi/dsi_phy_hw.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _DSI_PHY_HW_H_
@@ -50,11 +51,13 @@ enum dsi_phy_version {
 
 /**
  * enum dsi_pll_version - DSI PHY PLL version enumeration
+ * @DSI_PLL_VERSION_4NM:        4nm PLL
  * @DSI_PLL_VERSION_5NM:        5nm PLL
  * @DSI_PLL_VERSION_10NM:	10nm PLL
  * @DSI_PLL_VERSION_UNKNOWN:	Unknown PLL version
  */
 enum dsi_pll_version {
+	DSI_PLL_VERSION_4NM,
 	DSI_PLL_VERSION_5NM,
 	DSI_PLL_VERSION_10NM,
 	DSI_PLL_VERSION_UNKNOWN

+ 881 - 0
msm/dsi/dsi_phy_hw_v5_0.c

@@ -0,0 +1,881 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/math64.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include "dsi_hw.h"
+#include "dsi_defs.h"
+#include "dsi_phy_hw.h"
+#include "dsi_catalog.h"
+
+#define DSIPHY_CMN_REVISION_ID0                                   0x000
+#define DSIPHY_CMN_REVISION_ID1                                   0x004
+#define DSIPHY_CMN_REVISION_ID2                                   0x008
+#define DSIPHY_CMN_REVISION_ID3                                   0x00C
+#define DSIPHY_CMN_CLK_CFG0                                       0x010
+#define DSIPHY_CMN_CLK_CFG1                                       0x014
+#define DSIPHY_CMN_GLBL_CTRL                                      0x018
+#define DSIPHY_CMN_RBUF_CTRL                                      0x01C
+#define DSIPHY_CMN_VREG_CTRL_0                                    0x020
+#define DSIPHY_CMN_CTRL_0                                         0x024
+#define DSIPHY_CMN_CTRL_1                                         0x028
+#define DSIPHY_CMN_CTRL_2                                         0x02C
+#define DSIPHY_CMN_CTRL_3                                         0x030
+#define DSIPHY_CMN_LANE_CFG0                                      0x034
+#define DSIPHY_CMN_LANE_CFG1                                      0x038
+#define DSIPHY_CMN_PLL_CNTRL                                      0x03C
+#define DSIPHY_CMN_DPHY_SOT                                       0x040
+#define DSIPHY_CMN_LANE_CTRL0                                     0x0A0
+#define DSIPHY_CMN_LANE_CTRL1                                     0x0A4
+#define DSIPHY_CMN_LANE_CTRL2                                     0x0A8
+#define DSIPHY_CMN_LANE_CTRL3                                     0x0AC
+#define DSIPHY_CMN_LANE_CTRL4                                     0x0B0
+#define DSIPHY_CMN_TIMING_CTRL_0                                  0x0B4
+#define DSIPHY_CMN_TIMING_CTRL_1                                  0x0B8
+#define DSIPHY_CMN_TIMING_CTRL_2                                  0x0Bc
+#define DSIPHY_CMN_TIMING_CTRL_3                                  0x0C0
+#define DSIPHY_CMN_TIMING_CTRL_4                                  0x0C4
+#define DSIPHY_CMN_TIMING_CTRL_5                                  0x0C8
+#define DSIPHY_CMN_TIMING_CTRL_6                                  0x0CC
+#define DSIPHY_CMN_TIMING_CTRL_7                                  0x0D0
+#define DSIPHY_CMN_TIMING_CTRL_8                                  0x0D4
+#define DSIPHY_CMN_TIMING_CTRL_9                                  0x0D8
+#define DSIPHY_CMN_TIMING_CTRL_10                                 0x0DC
+#define DSIPHY_CMN_TIMING_CTRL_11                                 0x0E0
+#define DSIPHY_CMN_TIMING_CTRL_12                                 0x0E4
+#define DSIPHY_CMN_TIMING_CTRL_13                                 0x0E8
+#define DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0                           0x0EC
+#define DSIPHY_CMN_GLBL_HSTX_STR_CTRL_1                           0x0F0
+#define DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL                   0x0F4
+#define DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL                   0x0F8
+#define DSIPHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL                   0x0FC
+#define DSIPHY_CMN_GLBL_LPTX_STR_CTRL                             0x100
+#define DSIPHY_CMN_GLBL_PEMPH_CTRL_0                              0x104
+#define DSIPHY_CMN_GLBL_PEMPH_CTRL_1                              0x108
+#define DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL                      0x10C
+#define DSIPHY_CMN_VREG_CTRL_1                                    0x110
+#define DSIPHY_CMN_CTRL_4                                         0x114
+#define DSIPHY_CMN_PHY_STATUS                                     0x140
+#define DSIPHY_CMN_LANE_STATUS0                                   0x148
+#define DSIPHY_CMN_LANE_STATUS1                                   0x14C
+#define DSIPHY_CMN_GLBL_DIGTOP_SPARE10                            0x1AC
+#define DSIPHY_CMN_SL_DSI_LANE_CTRL1                              0x1B4
+
+/* n = 0..3 for data lanes and n = 4 for clock lane */
+#define DSIPHY_LNX_CFG0(n)                         (0x200 + (0x80 * (n)))
+#define DSIPHY_LNX_CFG1(n)                         (0x204 + (0x80 * (n)))
+#define DSIPHY_LNX_CFG2(n)                         (0x208 + (0x80 * (n)))
+#define DSIPHY_LNX_TEST_DATAPATH(n)                (0x20C + (0x80 * (n)))
+#define DSIPHY_LNX_PIN_SWAP(n)                     (0x210 + (0x80 * (n)))
+#define DSIPHY_LNX_LPRX_CTRL(n)                    (0x214 + (0x80 * (n)))
+#define DSIPHY_LNX_TX_DCTRL(n)                     (0x218 + (0x80 * (n)))
+
+/* dynamic refresh control registers */
+#define DSI_DYN_REFRESH_CTRL                   (0x000)
+#define DSI_DYN_REFRESH_PIPE_DELAY             (0x004)
+#define DSI_DYN_REFRESH_PIPE_DELAY2            (0x008)
+#define DSI_DYN_REFRESH_PLL_DELAY              (0x00C)
+#define DSI_DYN_REFRESH_STATUS                 (0x010)
+#define DSI_DYN_REFRESH_PLL_CTRL0              (0x014)
+#define DSI_DYN_REFRESH_PLL_CTRL1              (0x018)
+#define DSI_DYN_REFRESH_PLL_CTRL2              (0x01C)
+#define DSI_DYN_REFRESH_PLL_CTRL3              (0x020)
+#define DSI_DYN_REFRESH_PLL_CTRL4              (0x024)
+#define DSI_DYN_REFRESH_PLL_CTRL5              (0x028)
+#define DSI_DYN_REFRESH_PLL_CTRL6              (0x02C)
+#define DSI_DYN_REFRESH_PLL_CTRL7              (0x030)
+#define DSI_DYN_REFRESH_PLL_CTRL8              (0x034)
+#define DSI_DYN_REFRESH_PLL_CTRL9              (0x038)
+#define DSI_DYN_REFRESH_PLL_CTRL10             (0x03C)
+#define DSI_DYN_REFRESH_PLL_CTRL11             (0x040)
+#define DSI_DYN_REFRESH_PLL_CTRL12             (0x044)
+#define DSI_DYN_REFRESH_PLL_CTRL13             (0x048)
+#define DSI_DYN_REFRESH_PLL_CTRL14             (0x04C)
+#define DSI_DYN_REFRESH_PLL_CTRL15             (0x050)
+#define DSI_DYN_REFRESH_PLL_CTRL16             (0x054)
+#define DSI_DYN_REFRESH_PLL_CTRL17             (0x058)
+#define DSI_DYN_REFRESH_PLL_CTRL18             (0x05C)
+#define DSI_DYN_REFRESH_PLL_CTRL19             (0x060)
+#define DSI_DYN_REFRESH_PLL_CTRL20             (0x064)
+#define DSI_DYN_REFRESH_PLL_CTRL21             (0x068)
+#define DSI_DYN_REFRESH_PLL_CTRL22             (0x06C)
+#define DSI_DYN_REFRESH_PLL_CTRL23             (0x070)
+#define DSI_DYN_REFRESH_PLL_CTRL24             (0x074)
+#define DSI_DYN_REFRESH_PLL_CTRL25             (0x078)
+#define DSI_DYN_REFRESH_PLL_CTRL26             (0x07C)
+#define DSI_DYN_REFRESH_PLL_CTRL27             (0x080)
+#define DSI_DYN_REFRESH_PLL_CTRL28             (0x084)
+#define DSI_DYN_REFRESH_PLL_CTRL29             (0x088)
+#define DSI_DYN_REFRESH_PLL_CTRL30             (0x08C)
+#define DSI_DYN_REFRESH_PLL_CTRL31             (0x090)
+#define DSI_DYN_REFRESH_PLL_UPPER_ADDR         (0x094)
+#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2        (0x098)
+
+static int dsi_phy_hw_v5_0_is_pll_on(struct dsi_phy_hw *phy)
+{
+	u32 data = 0;
+
+	data = DSI_R32(phy, DSIPHY_CMN_PLL_CNTRL);
+	mb(); /*make sure read happened */
+	return (data & BIT(0));
+}
+
+static bool dsi_phy_hw_v5_0_is_split_link_enabled(struct dsi_phy_hw *phy)
+{
+	u32 reg = 0;
+
+	reg = DSI_R32(phy, DSIPHY_CMN_GLBL_CTRL);
+	mb(); /*make sure read happened */
+	return (reg & BIT(5));
+}
+
+static void dsi_phy_hw_v5_0_config_lpcdrx(struct dsi_phy_hw *phy,
+	struct dsi_phy_cfg *cfg, bool enable)
+{
+	int phy_lane_0 = dsi_phy_conv_logical_to_phy_lane(&cfg->lane_map, DSI_LOGICAL_LANE_0);
+
+	/*
+	 * LPRX and CDRX need to enabled only for physical data lane
+	 * corresponding to the logical data lane 0
+	 */
+
+	if (enable)
+		DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(phy_lane_0), cfg->strength.lane[phy_lane_0][1]);
+	else
+		DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(phy_lane_0), 0);
+}
+
+static void dsi_phy_hw_v5_0_lane_swap_config(struct dsi_phy_hw *phy,
+		struct dsi_lane_map *lane_map)
+{
+	DSI_W32(phy, DSIPHY_CMN_LANE_CFG0,
+		(lane_map->lane_map_v2[DSI_LOGICAL_LANE_0] |
+		(lane_map->lane_map_v2[DSI_LOGICAL_LANE_1] << 4)));
+	DSI_W32(phy, DSIPHY_CMN_LANE_CFG1,
+		(lane_map->lane_map_v2[DSI_LOGICAL_LANE_2] |
+		(lane_map->lane_map_v2[DSI_LOGICAL_LANE_3] << 4)));
+}
+
+static void dsi_phy_hw_v5_0_lane_settings(struct dsi_phy_hw *phy,
+			    struct dsi_phy_cfg *cfg)
+{
+	int i;
+	u8 tx_dctrl[] = {0x40, 0x40, 0x40, 0x46, 0x41};
+	bool split_link_enabled;
+	u32 lanes_per_sublink;
+
+	split_link_enabled = cfg->split_link.enabled;
+	lanes_per_sublink = cfg->split_link.lanes_per_sublink;
+
+	/* Strength ctrl settings */
+	for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
+		/*
+		 * Disable LPRX and CDRX for all lanes. And later on, it will
+		 * be only enabled for the physical data lane corresponding
+		 * to the logical data lane 0
+		 */
+		DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(i), 0);
+		DSI_W32(phy, DSIPHY_LNX_PIN_SWAP(i), 0x0);
+	}
+	dsi_phy_hw_v5_0_config_lpcdrx(phy, cfg, true);
+
+	/* other settings */
+	for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
+		DSI_W32(phy, DSIPHY_LNX_CFG0(i), cfg->lanecfg.lane[i][0]);
+		DSI_W32(phy, DSIPHY_LNX_CFG1(i), cfg->lanecfg.lane[i][1]);
+		DSI_W32(phy, DSIPHY_LNX_CFG2(i), cfg->lanecfg.lane[i][2]);
+		DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]);
+	}
+
+	/* remove below check if cphy splitlink is enabled */
+	if (split_link_enabled && (cfg->phy_type == DSI_PHY_TYPE_CPHY))
+		return;
+
+	/* Configure the splitlink clock lane with clk lane settings */
+	if (split_link_enabled) {
+		DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(5), 0x0);
+		DSI_W32(phy, DSIPHY_LNX_PIN_SWAP(5), 0x0);
+		DSI_W32(phy, DSIPHY_LNX_CFG0(5), cfg->lanecfg.lane[4][0]);
+		DSI_W32(phy, DSIPHY_LNX_CFG1(5), cfg->lanecfg.lane[4][1]);
+		DSI_W32(phy, DSIPHY_LNX_CFG2(5), cfg->lanecfg.lane[4][2]);
+		DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(5), tx_dctrl[4]);
+	}
+}
+
+void dsi_phy_hw_v5_0_commit_phy_timing(struct dsi_phy_hw *phy,
+		struct dsi_phy_per_lane_cfgs *timing)
+{
+	/* Commit DSI PHY timings */
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_0, timing->lane_v4[0]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_1, timing->lane_v4[1]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_2, timing->lane_v4[2]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_3, timing->lane_v4[3]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_4, timing->lane_v4[4]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_5, timing->lane_v4[5]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_6, timing->lane_v4[6]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_7, timing->lane_v4[7]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_8, timing->lane_v4[8]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_9, timing->lane_v4[9]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_10, timing->lane_v4[10]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_11, timing->lane_v4[11]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_12, timing->lane_v4[12]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_13, timing->lane_v4[13]);
+}
+
+/**
+ * cphy_enable() - Enable CPHY hardware
+ * @phy:      Pointer to DSI PHY hardware object.
+ * @cfg:      Per lane configurations for timing, strength and lane
+ *	      configurations.
+ */
+static void dsi_phy_hw_cphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg)
+{
+	struct dsi_phy_per_lane_cfgs *timing = &cfg->timing;
+	u32 data;
+	/* For C-PHY, no low power settings for lower clk rate */
+	u32 glbl_str_swi_cal_sel_ctrl = 0;
+	u32 glbl_hstx_str_ctrl_0 = 0;
+
+	/* de-assert digital and pll power down */
+	data = BIT(6) | BIT(5);
+	DSI_W32(phy, DSIPHY_CMN_CTRL_0, data);
+
+	/* Assert PLL core reset */
+	DSI_W32(phy, DSIPHY_CMN_PLL_CNTRL, 0x00);
+
+	/* turn off resync FIFO */
+	DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00);
+
+	/* program CMN_CTRL_4 for minor_ver greater than 2 chipsets*/
+	DSI_W32(phy, DSIPHY_CMN_CTRL_4, 0x04);
+
+	/* Configure PHY lane swap */
+	dsi_phy_hw_v5_0_lane_swap_config(phy, &cfg->lane_map);
+
+	DSI_W32(phy, DSIPHY_CMN_GLBL_CTRL, BIT(6));
+
+	/* Enable LDO */
+	DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, 0x45);
+	DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x41);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, glbl_str_swi_cal_sel_ctrl);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, glbl_hstx_str_ctrl_0);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_0, 0x11);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_1, 0x01);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL, 0x00);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, 0x00);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55);
+
+	/* Remove power down from all blocks */
+	DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f);
+
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x17);
+
+	switch (cfg->pll_source) {
+	case DSI_PLL_SOURCE_STANDALONE:
+	case DSI_PLL_SOURCE_NATIVE:
+		data = 0x0; /* internal PLL */
+		break;
+	case DSI_PLL_SOURCE_NON_NATIVE:
+		data = 0x1; /* external PLL */
+		break;
+	default:
+		break;
+	}
+	DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, (data << 2)); /* set PLL src */
+
+	/* DSI PHY timings */
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_0, timing->lane_v4[0]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_4, timing->lane_v4[4]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_5, timing->lane_v4[5]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_6, timing->lane_v4[6]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_7, timing->lane_v4[7]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_8, timing->lane_v4[8]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_9, timing->lane_v4[9]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_10, timing->lane_v4[10]);
+	DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_11, timing->lane_v4[11]);
+
+	/* DSI lane settings */
+	dsi_phy_hw_v5_0_lane_settings(phy, cfg);
+
+	DSI_PHY_DBG(phy, "C-Phy enabled\n");
+}
+
+/**
+ * dphy_enable() - Enable DPHY hardware
+ * @phy:      Pointer to DSI PHY hardware object.
+ * @cfg:      Per lane configurations for timing, strength and lane
+ *	      configurations.
+ */
+static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg)
+{
+	struct dsi_phy_per_lane_cfgs *timing = &cfg->timing;
+	u32 data;
+	bool less_than_1500_mhz = false;
+	u32 vreg_ctrl_0 = 0;
+	u32 glbl_str_swi_cal_sel_ctrl = 0;
+	u32 glbl_hstx_str_ctrl_0 = 0;
+	u32 glbl_rescode_top_ctrl = 0;
+	u32 glbl_rescode_bot_ctrl = 0;
+	bool split_link_enabled;
+	u32 lanes_per_sublink;
+
+	/* Alter PHY configurations if data rate less than 1.5GHZ*/
+	if (cfg->bit_clk_rate_hz <= 1500000000)
+		less_than_1500_mhz = true;
+
+	vreg_ctrl_0 = 0x44;
+	glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3c : 0x03;
+	glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x3c;
+	glbl_str_swi_cal_sel_ctrl = 0x00;
+	glbl_hstx_str_ctrl_0 = 0x88;
+
+
+	split_link_enabled = cfg->split_link.enabled;
+	lanes_per_sublink = cfg->split_link.lanes_per_sublink;
+	/* de-assert digital and pll power down */
+	data = BIT(6) | BIT(5);
+	DSI_W32(phy, DSIPHY_CMN_CTRL_0, data);
+
+	if (split_link_enabled) {
+		data = DSI_R32(phy, DSIPHY_CMN_GLBL_CTRL);
+		/* set SPLIT_LINK_ENABLE in global control */
+		DSI_W32(phy, DSIPHY_CMN_GLBL_CTRL, (data | BIT(5)));
+	}
+	/* Assert PLL core reset */
+	DSI_W32(phy, DSIPHY_CMN_PLL_CNTRL, 0x00);
+
+	/* turn off resync FIFO */
+	DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00);
+
+	/* program CMN_CTRL_4 for minor_ver greater than 2 chipsets*/
+	DSI_W32(phy, DSIPHY_CMN_CTRL_4, 0x04);
+
+	/* Configure PHY lane swap */
+	dsi_phy_hw_v5_0_lane_swap_config(phy, &cfg->lane_map);
+
+	/* Enable LDO */
+	DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0);
+	DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x19);
+	DSI_W32(phy, DSIPHY_CMN_CTRL_3, 0x00);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL,
+					glbl_str_swi_cal_sel_ctrl);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, glbl_hstx_str_ctrl_0);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_0, 0x00);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL,
+			glbl_rescode_top_ctrl);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL,
+			glbl_rescode_bot_ctrl);
+	DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55);
+
+	if (split_link_enabled) {
+		if (lanes_per_sublink == 1) {
+			/* remove Lane1 and Lane3 configs */
+			DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0xed);
+			DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x35);
+		} else {
+			/* enable all together with sublink clock */
+			DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0xff);
+			DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x3F);
+		}
+
+		DSI_W32(phy, DSIPHY_CMN_SL_DSI_LANE_CTRL1, 0x03);
+	} else {
+		/* Remove power down from all blocks */
+		DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f);
+		DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x1F);
+	}
+
+	/* Select full-rate mode */
+	DSI_W32(phy, DSIPHY_CMN_CTRL_2, 0x40);
+
+	switch (cfg->pll_source) {
+	case DSI_PLL_SOURCE_STANDALONE:
+	case DSI_PLL_SOURCE_NATIVE:
+		data = 0x0; /* internal PLL */
+		break;
+	case DSI_PLL_SOURCE_NON_NATIVE:
+		data = 0x1; /* external PLL */
+		break;
+	default:
+		break;
+	}
+	DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, (data << 2)); /* set PLL src */
+
+	/* DSI PHY timings */
+	dsi_phy_hw_v5_0_commit_phy_timing(phy, timing);
+
+	/* DSI lane settings */
+	dsi_phy_hw_v5_0_lane_settings(phy, cfg);
+
+	DSI_PHY_DBG(phy, "D-Phy enabled\n");
+}
+
+/**
+ * enable() - Enable PHY hardware
+ * @phy:      Pointer to DSI PHY hardware object.
+ * @cfg:      Per lane configurations for timing, strength and lane
+ *	      configurations.
+ */
+void dsi_phy_hw_v5_0_enable(struct dsi_phy_hw *phy,
+			    struct dsi_phy_cfg *cfg)
+{
+	int rc = 0;
+	u32 status;
+	u32 const delay_us = 5;
+	u32 const timeout_us = 1000;
+
+	if (dsi_phy_hw_v5_0_is_pll_on(phy))
+		DSI_PHY_WARN(phy, "PLL turned on before configuring PHY\n");
+
+	/* Request for REFGEN ready */
+	DSI_W32(phy, DSIPHY_CMN_GLBL_DIGTOP_SPARE10, 0x1);
+	udelay(500);
+
+	/* wait for REFGEN READY */
+	rc = DSI_READ_POLL_TIMEOUT_ATOMIC(phy, DSIPHY_CMN_PHY_STATUS,
+		status, (status & BIT(0)), delay_us, timeout_us);
+	if (rc) {
+		DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n");
+		return;
+	}
+
+	if (cfg->phy_type == DSI_PHY_TYPE_CPHY)
+		dsi_phy_hw_cphy_enable(phy, cfg);
+	else /* Default PHY type is DPHY */
+		dsi_phy_hw_dphy_enable(phy, cfg);
+
+}
+
+/**
+ * disable() - Disable PHY hardware
+ * @phy:      Pointer to DSI PHY hardware object.
+ */
+void dsi_phy_hw_v5_0_disable(struct dsi_phy_hw *phy,
+			    struct dsi_phy_cfg *cfg)
+{
+	u32 data = 0;
+
+	if (dsi_phy_hw_v5_0_is_pll_on(phy))
+		DSI_PHY_WARN(phy, "Turning OFF PHY while PLL is on\n");
+
+	dsi_phy_hw_v5_0_config_lpcdrx(phy, cfg, false);
+
+	/* Turn off REFGEN Vote */
+	DSI_W32(phy, DSIPHY_CMN_GLBL_DIGTOP_SPARE10, 0x0);
+	wmb();
+	/* Delay to ensure HW removes vote before PHY shut down */
+	udelay(2);
+
+	data = DSI_R32(phy, DSIPHY_CMN_CTRL_0);
+	/* disable all lanes and splitlink clk lane*/
+	data &= ~0x9F;
+	DSI_W32(phy, DSIPHY_CMN_CTRL_0, data);
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0);
+
+	/* Turn off all PHY blocks */
+	DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x00);
+	/* make sure phy is turned off */
+	wmb();
+	DSI_PHY_DBG(phy, "Phy disabled\n");
+}
+
+void dsi_phy_hw_v5_0_toggle_resync_fifo(struct dsi_phy_hw *phy)
+{
+	DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00);
+	/* ensure that the FIFO is off */
+	wmb();
+	DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x1);
+	/* ensure that the FIFO is toggled back on */
+	wmb();
+}
+
+void dsi_phy_hw_v5_0_reset_clk_en_sel(struct dsi_phy_hw *phy)
+{
+	u32 data = 0;
+
+	/*Turning off CLK_EN_SEL after retime buffer sync */
+	data = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1);
+	data &= ~BIT(4);
+	DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, data);
+	/* ensure that clk_en_sel bit is turned off */
+	wmb();
+}
+
+int dsi_phy_hw_v5_0_wait_for_lane_idle(
+		struct dsi_phy_hw *phy, u32 lanes)
+{
+	int rc = 0, val = 0;
+	u32 stop_state_mask = 0;
+	u32 const sleep_us = 10;
+	u32 const timeout_us = 100;
+	bool split_link_enabled = dsi_phy_hw_v5_0_is_split_link_enabled(phy);
+
+	stop_state_mask = BIT(4); /* clock lane */
+	if (split_link_enabled)
+		stop_state_mask |= BIT(5);
+	if (lanes & DSI_DATA_LANE_0)
+		stop_state_mask |= BIT(0);
+	if (lanes & DSI_DATA_LANE_1)
+		stop_state_mask |= BIT(1);
+	if (lanes & DSI_DATA_LANE_2)
+		stop_state_mask |= BIT(2);
+	if (lanes & DSI_DATA_LANE_3)
+		stop_state_mask |= BIT(3);
+
+	DSI_PHY_DBG(phy, "polling for lanes to be in stop state, mask=0x%08x\n", stop_state_mask);
+	rc = DSI_READ_POLL_TIMEOUT(phy, DSIPHY_CMN_LANE_STATUS1, val,
+				((val & stop_state_mask) == stop_state_mask),
+				sleep_us, timeout_us);
+	if (rc) {
+		DSI_PHY_ERR(phy, "lanes not in stop state, LANE_STATUS=0x%08x\n", val);
+		return rc;
+	}
+
+	return 0;
+}
+
+void dsi_phy_hw_v5_0_ulps_request(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg, u32 lanes)
+{
+	u32 reg = 0, sl_lane_ctrl1 = 0;
+
+	if (lanes & DSI_CLOCK_LANE)
+		reg = BIT(4);
+	if (lanes & DSI_DATA_LANE_0)
+		reg |= BIT(0);
+	if (lanes & DSI_DATA_LANE_1)
+		reg |= BIT(1);
+	if (lanes & DSI_DATA_LANE_2)
+		reg |= BIT(2);
+	if (lanes & DSI_DATA_LANE_3)
+		reg |= BIT(3);
+	if (cfg->split_link.enabled)
+		reg |= BIT(7);
+
+	if (cfg->force_clk_lane_hs) {
+		reg |= BIT(5) | BIT(6);
+		if (cfg->split_link.enabled) {
+			sl_lane_ctrl1 = DSI_R32(phy, DSIPHY_CMN_SL_DSI_LANE_CTRL1);
+			sl_lane_ctrl1 |= BIT(2);
+			DSI_W32(phy, DSIPHY_CMN_SL_DSI_LANE_CTRL1, sl_lane_ctrl1);
+		}
+	}
+
+	/*
+	 * ULPS entry request. Wait for short time to make sure
+	 * that the lanes enter ULPS. Recommended as per HPG.
+	 */
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg);
+	usleep_range(100, 110);
+
+	/* disable LPRX and CDRX */
+	dsi_phy_hw_v5_0_config_lpcdrx(phy, cfg, false);
+
+	DSI_PHY_DBG(phy, "ULPS requested for lanes 0x%x\n", lanes);
+}
+
+int dsi_phy_hw_v5_0_lane_reset(struct dsi_phy_hw *phy)
+{
+	int ret = 0, loop = 10, u_dly = 200;
+	u32 ln_status = 0;
+
+	while ((ln_status != 0x1f) && loop) {
+		DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0x1f);
+		wmb(); /* ensure register is committed */
+		loop--;
+		udelay(u_dly);
+		ln_status = DSI_R32(phy, DSIPHY_CMN_LANE_STATUS1);
+		DSI_PHY_DBG(phy, "trial no: %d\n", loop);
+	}
+
+	if (!loop)
+		DSI_PHY_DBG(phy, "could not reset phy lanes\n");
+
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0x0);
+	wmb(); /* ensure register is committed */
+
+	return ret;
+}
+
+void dsi_phy_hw_v5_0_ulps_exit(struct dsi_phy_hw *phy,
+			struct dsi_phy_cfg *cfg, u32 lanes)
+{
+	u32 reg = 0, sl_lane_ctrl1 = 0;
+
+	if (lanes & DSI_CLOCK_LANE)
+		reg = BIT(4);
+	if (lanes & DSI_DATA_LANE_0)
+		reg |= BIT(0);
+	if (lanes & DSI_DATA_LANE_1)
+		reg |= BIT(1);
+	if (lanes & DSI_DATA_LANE_2)
+		reg |= BIT(2);
+	if (lanes & DSI_DATA_LANE_3)
+		reg |= BIT(3);
+	if (cfg->split_link.enabled)
+		reg |= BIT(5);
+
+	/* enable LPRX and CDRX */
+	dsi_phy_hw_v5_0_config_lpcdrx(phy, cfg, true);
+
+	/* ULPS exit request */
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL2, reg);
+	usleep_range(1000, 1010);
+
+	/* Clear ULPS request flags on all lanes */
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, 0);
+	/* Clear ULPS exit flags on all lanes */
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL2, 0);
+
+	/*
+	 * Sometimes when exiting ULPS, it is possible that some DSI
+	 * lanes are not in the stop state which could lead to DSI
+	 * commands not going through. To avoid this, force the lanes
+	 * to be in stop state.
+	 */
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, reg);
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0);
+	usleep_range(100, 110);
+
+	if (cfg->force_clk_lane_hs) {
+		reg = BIT(5) | BIT(6);
+		DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg);
+		if (cfg->split_link.enabled) {
+			sl_lane_ctrl1 = DSI_R32(phy, DSIPHY_CMN_SL_DSI_LANE_CTRL1);
+			sl_lane_ctrl1 |= BIT(2);
+			DSI_W32(phy, DSIPHY_CMN_SL_DSI_LANE_CTRL1, sl_lane_ctrl1);
+		}
+	}
+}
+
+u32 dsi_phy_hw_v5_0_get_lanes_in_ulps(struct dsi_phy_hw *phy)
+{
+	u32 lanes = 0;
+
+	lanes = DSI_R32(phy, DSIPHY_CMN_LANE_STATUS0);
+	DSI_PHY_DBG(phy, "lanes in ulps = 0x%x\n", lanes);
+	return lanes;
+}
+
+bool dsi_phy_hw_v5_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes)
+{
+	if (lanes & ulps_lanes)
+		return false;
+
+	return true;
+}
+
+int dsi_phy_hw_timing_val_v5_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
+		u32 *timing_val, u32 size)
+{
+	int i = 0;
+
+	if (size != DSI_PHY_TIMING_V4_SIZE) {
+		DSI_ERR("Unexpected timing array size %d\n", size);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i++)
+		timing_cfg->lane_v4[i] = timing_val[i];
+	return 0;
+}
+
+void dsi_phy_hw_v5_0_dyn_refresh_config(struct dsi_phy_hw *phy,
+					struct dsi_phy_cfg *cfg, bool is_master)
+{
+	u32 reg;
+	bool is_cphy = (cfg->phy_type == DSI_PHY_TYPE_CPHY) ? true : false;
+
+	if (is_master) {
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL19,
+				DSIPHY_CMN_TIMING_CTRL_0, DSIPHY_CMN_TIMING_CTRL_1,
+				cfg->timing.lane_v4[0], cfg->timing.lane_v4[1]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL20,
+				DSIPHY_CMN_TIMING_CTRL_2, DSIPHY_CMN_TIMING_CTRL_3,
+				cfg->timing.lane_v4[2], cfg->timing.lane_v4[3]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL21,
+				DSIPHY_CMN_TIMING_CTRL_4, DSIPHY_CMN_TIMING_CTRL_5,
+				cfg->timing.lane_v4[4], cfg->timing.lane_v4[5]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL22,
+				DSIPHY_CMN_TIMING_CTRL_6, DSIPHY_CMN_TIMING_CTRL_7,
+				cfg->timing.lane_v4[6], cfg->timing.lane_v4[7]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL23,
+				DSIPHY_CMN_TIMING_CTRL_8, DSIPHY_CMN_TIMING_CTRL_9,
+				cfg->timing.lane_v4[8], cfg->timing.lane_v4[9]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL24,
+				DSIPHY_CMN_TIMING_CTRL_10, DSIPHY_CMN_TIMING_CTRL_11,
+				cfg->timing.lane_v4[10], cfg->timing.lane_v4[11]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL25,
+				DSIPHY_CMN_TIMING_CTRL_12, DSIPHY_CMN_TIMING_CTRL_13,
+				cfg->timing.lane_v4[12], cfg->timing.lane_v4[13]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL26,
+				DSIPHY_CMN_CTRL_0, DSIPHY_CMN_LANE_CTRL0, 0x7f,
+				is_cphy ? 0x17 : 0x1f);
+
+	} else {
+		reg = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1);
+		reg &= ~BIT(5);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
+				DSIPHY_CMN_CLK_CFG1, DSIPHY_CMN_PLL_CNTRL, reg, 0x0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1,
+				DSIPHY_CMN_RBUF_CTRL, DSIPHY_CMN_TIMING_CTRL_0, 0x0,
+				cfg->timing.lane_v4[0]);
+
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
+				DSIPHY_CMN_TIMING_CTRL_1, DSIPHY_CMN_TIMING_CTRL_2,
+				cfg->timing.lane_v4[1], cfg->timing.lane_v4[2]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
+				DSIPHY_CMN_TIMING_CTRL_3, DSIPHY_CMN_TIMING_CTRL_4,
+				cfg->timing.lane_v4[3], cfg->timing.lane_v4[4]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
+				DSIPHY_CMN_TIMING_CTRL_5, DSIPHY_CMN_TIMING_CTRL_6,
+				cfg->timing.lane_v4[5], cfg->timing.lane_v4[6]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
+				DSIPHY_CMN_TIMING_CTRL_7, DSIPHY_CMN_TIMING_CTRL_8,
+				cfg->timing.lane_v4[7], cfg->timing.lane_v4[8]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
+				DSIPHY_CMN_TIMING_CTRL_9, DSIPHY_CMN_TIMING_CTRL_10,
+				cfg->timing.lane_v4[9], cfg->timing.lane_v4[10]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
+				DSIPHY_CMN_TIMING_CTRL_11, DSIPHY_CMN_TIMING_CTRL_12,
+				cfg->timing.lane_v4[11], cfg->timing.lane_v4[12]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
+				DSIPHY_CMN_TIMING_CTRL_13, DSIPHY_CMN_CTRL_0,
+				cfg->timing.lane_v4[13], 0x7f);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
+				DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_2,
+				is_cphy ? 0x17 : 0x1f, 0x40);
+		/*
+		 * fill with dummy register writes since controller will blindly
+		 * send these values to DSI PHY.
+		 */
+		reg = DSI_DYN_REFRESH_PLL_CTRL11;
+		while (reg <= DSI_DYN_REFRESH_PLL_CTRL29) {
+			DSI_DYN_REF_REG_W(phy->dyn_pll_base, reg, DSIPHY_CMN_LANE_CTRL0,
+					DSIPHY_CMN_CTRL_0, is_cphy ? 0x17 : 0x1f, 0x7f);
+			reg += 0x4;
+		}
+
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR, 0);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR2, 0);
+	}
+
+	wmb(); /* make sure all registers are updated */
+}
+
+void dsi_phy_hw_v5_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, struct dsi_dyn_clk_delay *delay)
+{
+	if (!delay)
+		return;
+
+	DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY, delay->pipe_delay);
+	DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2, delay->pipe_delay2);
+	DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY, delay->pll_delay);
+}
+
+void dsi_phy_hw_v5_0_dyn_refresh_trigger_sel(struct dsi_phy_hw *phy, bool is_master)
+{
+	u32 reg;
+
+	/*
+	 * Dynamic refresh will take effect at next mdp flush event.
+	 * This makes sure that any update to frame timings together
+	 * with dfps will take effect in one vsync at next mdp flush.
+	 */
+	if (is_master) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(17);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+	}
+}
+
+void dsi_phy_hw_v5_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset)
+{
+	u32 reg;
+
+	/*
+	 * if no offset is mentioned then this means we want to clear
+	 * the dynamic refresh ctrl register which is the last step
+	 * of dynamic refresh sequence.
+	 */
+	if (!offset) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg &= ~(BIT(0) | BIT(8) | BIT(13) | BIT(16) | BIT(17));
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+		wmb(); /* ensure dynamic fps is cleared */
+		return;
+	}
+
+	if (offset & BIT(DYN_REFRESH_INTF_SEL)) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(13);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+	}
+
+	if (offset & BIT(DYN_REFRESH_SYNC_MODE)) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(16);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+	}
+
+	if (offset & BIT(DYN_REFRESH_SWI_CTRL)) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(0);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+	}
+
+	if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(8);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+		wmb(); /* ensure dynamic fps is triggered */
+	}
+}
+
+int dsi_phy_hw_v5_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
+				      u32 *dst, u32 size)
+{
+	int i;
+
+	if (!timings || !dst || !size)
+		return -EINVAL;
+
+	if (size != DSI_PHY_TIMING_V4_SIZE) {
+		DSI_ERR("size mis-match\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i++)
+		dst[i] = timings->lane_v4[i];
+
+	return 0;
+}
+
+void dsi_phy_hw_v5_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable)
+{
+	u32 reg = 0, sl_lane_ctrl1 = 0;
+	bool is_split_link_enabled = dsi_phy_hw_v5_0_is_split_link_enabled(phy);
+
+	reg = DSI_R32(phy, DSIPHY_CMN_LANE_CTRL1);
+
+	if (enable)
+		reg |= BIT(5) | BIT(6);
+	else
+		reg &= ~(BIT(5) | BIT(6));
+
+	DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg);
+
+	if (is_split_link_enabled) {
+		sl_lane_ctrl1 = DSI_R32(phy, DSIPHY_CMN_SL_DSI_LANE_CTRL1);
+		if (enable)
+			sl_lane_ctrl1 |= BIT(2);
+		else
+			sl_lane_ctrl1 &= ~BIT(2);
+		DSI_W32(phy, DSIPHY_CMN_SL_DSI_LANE_CTRL1, sl_lane_ctrl1);
+	}
+
+	wmb(); /* make sure request is set */
+}

+ 7 - 5
msm/dsi/dsi_pll.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
@@ -23,6 +24,9 @@ static int dsi_pll_clock_register(struct platform_device *pdev,
 	case DSI_PLL_5NM:
 		rc = dsi_pll_clock_register_5nm(pdev, pll_res);
 		break;
+	case DSI_PLL_4NM:
+		rc = dsi_pll_clock_register_4nm(pdev, pll_res);
+		break;
 	default:
 		rc = -EINVAL;
 		break;
@@ -265,12 +269,10 @@ int dsi_pll_init(struct platform_device *pdev, struct dsi_pll_resource **pll)
 
 	DSI_PLL_INFO(pll_res, "DSI pll label = %s\n", label);
 
-	/**
-	  * Currently, Only supports 5nm. Will add
-	  * support for other versions as needed.
-	  */
 
-	if (!strcmp(label, "dsi_pll_5nm"))
+	if (!strcmp(label, "dsi_pll_4nm"))
+		pll_res->pll_revision = DSI_PLL_4NM;
+	else if (!strcmp(label, "dsi_pll_5nm"))
 		pll_res->pll_revision = DSI_PLL_5NM;
 	else
 		return -ENOTSUPP;

+ 3 - 0
msm/dsi/dsi_pll.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef __DSI_PLL_H
@@ -59,6 +60,7 @@ struct lpfr_cfg {
 };
 
 enum {
+	DSI_PLL_4NM,
 	DSI_PLL_5NM,
 	DSI_PLL_10NM,
 	DSI_UNKNOWN_PLL,
@@ -203,6 +205,7 @@ static inline struct dsi_pll_clk *to_pll_clk_hw(struct clk_hw *hw)
 
 int dsi_pll_clock_register_5nm(struct platform_device *pdev,
 				  struct dsi_pll_resource *pll_res);
+int dsi_pll_clock_register_4nm(struct platform_device *pdev, struct dsi_pll_resource *pll_res);
 
 int dsi_pll_init(struct platform_device *pdev,
 				struct dsi_pll_resource **pll_res);

+ 1487 - 0
msm/dsi/dsi_pll_4nm.c

@@ -0,0 +1,1487 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include "dsi_pll_4nm.h"
+
+#define VCO_DELAY_USEC 1
+
+#define MHZ_250		250000000UL
+#define MHZ_500		500000000UL
+#define MHZ_1000	1000000000UL
+#define MHZ_1100	1100000000UL
+#define MHZ_1900	1900000000UL
+#define MHZ_3000	3000000000UL
+
+struct dsi_pll_regs {
+	u32 pll_prop_gain_rate;
+	u32 pll_lockdet_rate;
+	u32 decimal_div_start;
+	u32 frac_div_start_low;
+	u32 frac_div_start_mid;
+	u32 frac_div_start_high;
+	u32 pll_clock_inverters;
+	u32 ssc_stepsize_low;
+	u32 ssc_stepsize_high;
+	u32 ssc_div_per_low;
+	u32 ssc_div_per_high;
+	u32 ssc_adjper_low;
+	u32 ssc_adjper_high;
+	u32 ssc_control;
+};
+
+struct dsi_pll_config {
+	u32 ref_freq;
+	bool div_override;
+	u32 output_div;
+	bool ignore_frac;
+	bool disable_prescaler;
+	bool enable_ssc;
+	bool ssc_center;
+	u32 dec_bits;
+	u32 frac_bits;
+	u32 lock_timer;
+	u32 ssc_freq;
+	u32 ssc_offset;
+	u32 ssc_adj_per;
+	u32 thresh_cycles;
+	u32 refclk_cycles;
+};
+
+struct dsi_pll_4nm {
+	struct dsi_pll_resource *rsc;
+	struct dsi_pll_config pll_configuration;
+	struct dsi_pll_regs reg_setup;
+	bool cphy_enabled;
+};
+
+static inline bool dsi_pll_4nm_is_hw_revision(struct dsi_pll_resource *rsc)
+{
+	return (rsc->pll_revision == DSI_PLL_4NM) ? true : false;
+}
+
+static inline void dsi_pll_set_pll_post_div(struct dsi_pll_resource *pll, u32 pll_post_div)
+{
+	u32 pll_post_div_val = 0;
+
+	if (pll_post_div == 1)
+		pll_post_div_val = 0;
+	if (pll_post_div == 2)
+		pll_post_div_val = 1;
+	if (pll_post_div == 4)
+		pll_post_div_val = 2;
+	if (pll_post_div == 8)
+		pll_post_div_val = 3;
+
+	DSI_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE, pll_post_div_val);
+	if (pll->slave)
+		DSI_PLL_REG_W(pll->slave->pll_base, PLL_PLL_OUTDIV_RATE, pll_post_div_val);
+}
+
+static inline int dsi_pll_get_pll_post_div(struct dsi_pll_resource *pll)
+{
+	u32 reg_val;
+
+	reg_val = DSI_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE);
+
+	return (1 << reg_val);
+}
+
+static inline void dsi_pll_set_phy_post_div(struct dsi_pll_resource *pll, u32 phy_post_div)
+{
+	u32 reg_val = 0;
+
+	reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
+	reg_val &= ~0x0F;
+	reg_val |= phy_post_div;
+	DSI_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val);
+	/* For slave PLL, this divider always should be set to 1 */
+	if (pll->slave) {
+		reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
+		reg_val &= ~0x0F;
+		reg_val |= 0x1;
+		DSI_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, reg_val);
+	}
+}
+
+
+static inline int dsi_pll_get_phy_post_div(struct dsi_pll_resource *pll)
+{
+	u32 reg_val = 0;
+
+	reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
+
+	return (reg_val & 0xF);
+}
+
+
+static inline void dsi_pll_set_dsi_clk(struct dsi_pll_resource *pll, u32 dsi_clk)
+{
+	u32 reg_val = 0;
+
+	reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
+	reg_val &= ~0x3;
+	reg_val |= dsi_clk;
+	DSI_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val);
+	if (pll->slave) {
+		reg_val = DSI_PLL_REG_R(pll->slave->phy_base, PHY_CMN_CLK_CFG1);
+		reg_val &= ~0x3;
+		reg_val |= dsi_clk;
+		DSI_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG1, reg_val);
+	}
+}
+
+static inline int dsi_pll_get_dsi_clk(struct dsi_pll_resource *pll)
+{
+	u32 reg_val;
+
+	reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
+
+	return (reg_val & 0x3);
+}
+
+static inline void dsi_pll_set_pclk_div(struct dsi_pll_resource *pll, u32 pclk_div)
+{
+	u32 reg_val = 0;
+
+	reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
+	reg_val &= ~0xF0;
+	reg_val |= (pclk_div << 4);
+	DSI_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val);
+	if (pll->slave) {
+		reg_val = DSI_PLL_REG_R(pll->slave->phy_base, PHY_CMN_CLK_CFG0);
+		reg_val &= ~0xF0;
+		reg_val |= (pclk_div << 4);
+		DSI_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, reg_val);
+	}
+}
+
+static inline int dsi_pll_get_pclk_div(struct dsi_pll_resource *pll)
+{
+	u32 reg_val;
+
+	reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
+
+	return ((reg_val & 0xF0) >> 4);
+}
+
+static struct dsi_pll_resource *pll_rsc_db[DSI_PLL_MAX];
+static struct dsi_pll_4nm plls[DSI_PLL_MAX];
+
+static void dsi_pll_config_slave(struct dsi_pll_resource *rsc)
+{
+	u32 reg;
+	struct dsi_pll_resource *orsc = pll_rsc_db[DSI_PLL_1];
+
+	if (!rsc)
+		return;
+
+	/* Only DSI PLL0 can act as a master */
+	if (rsc->index != DSI_PLL_0)
+		return;
+
+	/* default configuration: source is either internal or ref clock */
+	rsc->slave = NULL;
+
+	if (!orsc) {
+		DSI_PLL_WARN(rsc, "slave PLL unavilable, assuming standalone config\n");
+		return;
+	}
+
+	/* check to see if the source of DSI1 PLL bitclk is set to external */
+	reg = DSI_PLL_REG_R(orsc->phy_base, PHY_CMN_CLK_CFG1);
+	reg &= (BIT(2) | BIT(3));
+	if (reg == 0x04)
+		rsc->slave = pll_rsc_db[DSI_PLL_1]; /* external source */
+
+	DSI_PLL_DBG(rsc, "Slave PLL %s\n",
+			rsc->slave ? "configured" : "absent");
+}
+
+static void dsi_pll_setup_config(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	struct dsi_pll_config *config = &pll->pll_configuration;
+
+	config->ref_freq = 19200000;
+	config->output_div = 1;
+	config->dec_bits = 8;
+	config->frac_bits = 18;
+	config->lock_timer = 64;
+	config->ssc_freq = 31500;
+	config->ssc_offset = 4800;
+	config->ssc_adj_per = 2;
+	config->thresh_cycles = 32;
+	config->refclk_cycles = 256;
+
+	config->div_override = false;
+	config->ignore_frac = false;
+	config->disable_prescaler = false;
+	config->enable_ssc = rsc->ssc_en;
+	config->ssc_center = rsc->ssc_center;
+
+	if (config->enable_ssc) {
+		if (rsc->ssc_freq)
+			config->ssc_freq = rsc->ssc_freq;
+		if (rsc->ssc_ppm)
+			config->ssc_offset = rsc->ssc_ppm;
+	}
+}
+
+static void dsi_pll_calc_dec_frac(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	struct dsi_pll_config *config = &pll->pll_configuration;
+	struct dsi_pll_regs *regs = &pll->reg_setup;
+	u64 fref = rsc->vco_ref_clk_rate;
+	u64 pll_freq;
+	u64 divider;
+	u64 dec, dec_multiple;
+	u32 frac;
+	u64 multiplier;
+
+	pll_freq = rsc->vco_current_rate;
+
+	if (config->disable_prescaler)
+		divider = fref;
+	else
+		divider = fref * 2;
+
+	multiplier = 1 << config->frac_bits;
+	dec_multiple = div_u64(pll_freq * multiplier, divider);
+	div_u64_rem(dec_multiple, multiplier, &frac);
+
+	dec = div_u64(dec_multiple, multiplier);
+
+	if (pll_freq <= 1300000000ULL)
+		regs->pll_clock_inverters = 0xA0;
+	else if (pll_freq <= 2500000000ULL)
+		regs->pll_clock_inverters = 0x20;
+	else if (pll_freq <= 4000000000ULL)
+		regs->pll_clock_inverters = 0x00;
+	else
+		regs->pll_clock_inverters = 0x40;
+
+	regs->pll_lockdet_rate = config->lock_timer;
+	regs->decimal_div_start = dec;
+	regs->frac_div_start_low = (frac & 0xff);
+	regs->frac_div_start_mid = (frac & 0xff00) >> 8;
+	regs->frac_div_start_high = (frac & 0x30000) >> 16;
+	regs->pll_prop_gain_rate = 10;
+}
+
+static void dsi_pll_calc_ssc(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	struct dsi_pll_config *config = &pll->pll_configuration;
+	struct dsi_pll_regs *regs = &pll->reg_setup;
+	u32 ssc_per;
+	u32 ssc_mod;
+	u64 ssc_step_size;
+	u64 frac;
+
+	if (!config->enable_ssc) {
+		DSI_PLL_DBG(rsc, "SSC not enabled\n");
+		return;
+	}
+
+	ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1;
+	ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
+	ssc_per -= ssc_mod;
+
+	frac = regs->frac_div_start_low | (regs->frac_div_start_mid << 8) |
+			(regs->frac_div_start_high << 16);
+	ssc_step_size = regs->decimal_div_start;
+	ssc_step_size *= (1 << config->frac_bits);
+	ssc_step_size += frac;
+	ssc_step_size *= config->ssc_offset;
+	ssc_step_size *= (config->ssc_adj_per + 1);
+	ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
+	ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
+
+	regs->ssc_div_per_low = ssc_per & 0xFF;
+	regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8;
+	regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF);
+	regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8);
+	regs->ssc_adjper_low = config->ssc_adj_per & 0xFF;
+	regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8;
+
+	regs->ssc_control = config->ssc_center ? SSC_CENTER : 0;
+
+	DSI_PLL_DBG(rsc, "SCC: Dec:%d, frac:%llu, frac_bits:%d\n", regs->decimal_div_start, frac,
+			config->frac_bits);
+	DSI_PLL_DBG(rsc, "SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", ssc_per,
+			(u32)ssc_step_size, config->ssc_adj_per);
+}
+
+static void dsi_pll_ssc_commit(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	void __iomem *pll_base = rsc->pll_base;
+	struct dsi_pll_regs *regs = &pll->reg_setup;
+
+	if (pll->pll_configuration.enable_ssc) {
+		DSI_PLL_DBG(rsc, "SSC is enabled\n");
+		DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1, regs->ssc_stepsize_low);
+		DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_1, regs->ssc_stepsize_high);
+		DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_1, regs->ssc_div_per_low);
+		DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_1, regs->ssc_div_per_high);
+		DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW_1, regs->ssc_adjper_low);
+		DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH_1, regs->ssc_adjper_high);
+		DSI_PLL_REG_W(pll_base, PLL_SSC_CONTROL, SSC_EN | regs->ssc_control);
+	}
+}
+
+static void dsi_pll_config_hzindep_reg(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	void __iomem *pll_base = rsc->pll_base;
+	u64 vco_rate = rsc->vco_current_rate;
+
+	if (vco_rate < 3100000000ULL)
+		DSI_PLL_REG_W(pll_base,
+				PLL_ANALOG_CONTROLS_FIVE_1, 0x01);
+	else
+		DSI_PLL_REG_W(pll_base,
+				PLL_ANALOG_CONTROLS_FIVE_1, 0x03);
+
+	if (vco_rate < 1557000000ULL)
+		DSI_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x08);
+	else
+		DSI_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x01);
+
+
+	DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FIVE, 0x01);
+	DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_TWO, 0x03);
+	DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_THREE, 0x00);
+	DSI_PLL_REG_W(pll_base, PLL_DSM_DIVIDER, 0x00);
+	DSI_PLL_REG_W(pll_base, PLL_FEEDBACK_DIVIDER, 0x4e);
+	DSI_PLL_REG_W(pll_base, PLL_CALIBRATION_SETTINGS, 0x40);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
+	DSI_PLL_REG_W(pll_base, PLL_OUTDIV, 0x00);
+	DSI_PLL_REG_W(pll_base, PLL_CORE_OVERRIDE, 0x00);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x0a);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_BAND_SEL_RATE_1, 0xc0);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x84);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x82);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x80);
+	DSI_PLL_REG_W(pll_base, PLL_PFILT, 0x29);
+	DSI_PLL_REG_W(pll_base, PLL_PFILT, 0x2f);
+	DSI_PLL_REG_W(pll_base, PLL_IFILT, 0x2a);
+	DSI_PLL_REG_W(pll_base, PLL_IFILT, 0x3F);
+	DSI_PLL_REG_W(pll_base, PLL_PERF_OPTIMIZE, 0x22);
+	if (rsc->slave)
+		DSI_PLL_REG_W(rsc->slave->pll_base, PLL_PERF_OPTIMIZE, 0x22);
+}
+
+static void dsi_pll_init_val(struct dsi_pll_resource *rsc)
+{
+	void __iomem *pll_base = rsc->pll_base;
+
+	DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_ONE, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x0000003F);
+	DSI_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x00000080);
+	DSI_PLL_REG_W(pll_base, PLL_SYSTEM_MUXES, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_CMODE, 0x00000010);
+	DSI_PLL_REG_W(pll_base, PLL_PSM_CTRL, 0x00000020);
+	DSI_PLL_REG_W(pll_base, PLL_RSM_CTRL, 0x00000010);
+	DSI_PLL_REG_W(pll_base, PLL_VCO_TUNE_MAP, 0x00000002);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_CNTRL, 0x0000001C);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x00000002);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x00000020);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0x000000FF);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x0000000A);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x00000025);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0x000000BA);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x0000004F);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0000000A);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0000000C);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_DETECT_THRESH, 0x00000020);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_DET_REFCLK_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_DET_REFCLK_LOW, 0x000000FF);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_DET_PLLCLK_HIGH, 0x00000010);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_DET_PLLCLK_LOW, 0x00000046);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_GAIN, 0x00000054);
+	DSI_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_LOCKDET, 0x00000040);
+	DSI_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x00000004);
+	DSI_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_CORE_OVERRIDE, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x00000010);
+	DSI_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x00000008);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x00000008);
+	DSI_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x00000003);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x00000040);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_2, 0x00000040);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x0000000C);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_2, 0x0000000A);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_BAND_SEL_RATE_1, 0x000000C0);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_BAND_SEL_RATE_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x00000054);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_2, 0x00000054);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x0000004C);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_2, 0x0000004C);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_FASTLOCK_EN_BAND, 0x00000003);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MID, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x00000080);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x00000006);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x00000019);
+	DSI_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x00000040);
+	DSI_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x00000020);
+	DSI_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_COMMON_STATUS_ONE, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_COMMON_STATUS_TWO, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_ICODE_ACCUM_STATUS_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_ICODE_ACCUM_STATUS_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FD_OUT_LOW, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FD_OUT_HIGH, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_STATUS_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_MISC_CONFIG, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FLL_CONFIG, 0x00000002);
+	DSI_PLL_REG_W(pll_base, PLL_FLL_FREQ_ACQ_TIME, 0x00000011);
+	DSI_PLL_REG_W(pll_base, PLL_FLL_CODE0, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FLL_CODE1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FLL_GAIN0, 0x00000080);
+	DSI_PLL_REG_W(pll_base, PLL_FLL_GAIN1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_SW_RESET, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_FAST_PWRUP, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_LOCKTIME0, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_LOCKTIME1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_DEBUG_BUS_SEL, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_DEBUG_BUS0, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_DEBUG_BUS1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_DEBUG_BUS2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_DEBUG_BUS3, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_ANALOG_FLL_CONTROL_OVERRIDES, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_VCO_CONFIG, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_VCO_CAL_CODE1_MODE0_STATUS, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_VCO_CAL_CODE1_MODE1_STATUS, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_RESET_SM_STATUS, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_TDC_OFFSET, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_PS3_PWRDOWN_CONTROLS, 0x0000001D);
+	DSI_PLL_REG_W(pll_base, PLL_PS4_PWRDOWN_CONTROLS, 0x0000001C);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_RST_CONTROLS, 0x000000FF);
+	DSI_PLL_REG_W(pll_base, PLL_GEAR_BAND_SELECT_CONTROLS, 0x00000022);
+	DSI_PLL_REG_W(pll_base, PLL_PSM_CLK_CONTROLS, 0x00000009);
+	DSI_PLL_REG_W(pll_base, PLL_SYSTEM_MUXES_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_VCO_CONFIG_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS_1, 0x00000040);
+	DSI_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS_2, 0x00000000);
+	DSI_PLL_REG_W(pll_base, PLL_CMODE_1, 0x00000010);
+	DSI_PLL_REG_W(pll_base, PLL_CMODE_2, 0x00000010);
+	DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FIVE_2, 0x00000003);
+
+}
+
+static void dsi_pll_detect_phy_mode(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	u32 reg_val;
+
+	reg_val = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_GLBL_CTRL);
+	pll->cphy_enabled = (reg_val & BIT(6)) ? true : false;
+}
+
+static void dsi_pll_commit(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	void __iomem *pll_base = rsc->pll_base;
+	struct dsi_pll_regs *reg = &pll->reg_setup;
+
+	DSI_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x12);
+	DSI_PLL_REG_W(pll_base, PLL_DECIMAL_DIV_START_1, reg->decimal_div_start);
+	DSI_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_LOW_1, reg->frac_div_start_low);
+	DSI_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_MID_1, reg->frac_div_start_mid);
+	DSI_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1, reg->frac_div_start_high);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, reg->pll_lockdet_rate);
+	DSI_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06);
+	DSI_PLL_REG_W(pll_base, PLL_CMODE_1, pll->cphy_enabled ? 0x00 : 0x10);
+	DSI_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS_1, reg->pll_clock_inverters);
+}
+
+static int dsi_pll_4nm_lock_status(struct dsi_pll_resource *pll)
+{
+	int rc;
+	u32 status;
+	u32 const delay_us = 100;
+	u32 const timeout_us = 5000;
+
+	rc = DSI_READ_POLL_TIMEOUT_ATOMIC_GEN(pll->pll_base, pll->index, PLL_COMMON_STATUS_ONE,
+				       status,
+				       ((status & BIT(0)) > 0),
+				       delay_us,
+				       timeout_us);
+	if (rc)
+		DSI_PLL_ERR(pll, "lock failed, status=0x%08x\n", status);
+
+	return rc;
+}
+
+static void dsi_pll_disable_pll_bias(struct dsi_pll_resource *rsc)
+{
+	u32 data = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0);
+
+	DSI_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0);
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5));
+	ndelay(250);
+}
+
+static void dsi_pll_enable_pll_bias(struct dsi_pll_resource *rsc)
+{
+	u32 data = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0);
+
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5));
+	DSI_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0xc0);
+	ndelay(250);
+}
+
+static void dsi_pll_disable_global_clk(struct dsi_pll_resource *rsc)
+{
+	u32 data;
+
+	data = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data & ~BIT(5)));
+}
+
+static void dsi_pll_enable_global_clk(struct dsi_pll_resource *rsc)
+{
+	u32 data;
+
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_3, 0x04);
+
+	data = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+
+	/* Turn on clk_en_sel bit prior to resync toggle fifo */
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data | BIT(5) | BIT(4)));
+}
+
+static void dsi_pll_phy_dig_reset(struct dsi_pll_resource *rsc)
+{
+	/*
+	 * Reset the PHY digital domain. This would be needed when
+	 * coming out of a CX or analog rail power collapse while
+	 * ensuring that the pads maintain LP00 or LP11 state
+	 */
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_GLBL_DIGTOP_SPARE4, BIT(0));
+	wmb(); /* Ensure that the reset is asserted */
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_GLBL_DIGTOP_SPARE4, 0x0);
+	wmb(); /* Ensure that the reset is deasserted */
+}
+
+static void dsi_pll_disable_sub(struct dsi_pll_resource *rsc)
+{
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0);
+	dsi_pll_disable_pll_bias(rsc);
+}
+
+static void dsi_pll_unprepare_stub(struct clk_hw *hw)
+{
+	return;
+}
+
+static int dsi_pll_prepare_stub(struct clk_hw *hw)
+{
+	return 0;
+}
+
+static int dsi_pll_set_rate_stub(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
+{
+	return 0;
+}
+
+static long dsi_pll_byteclk_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct dsi_pll_clk *pll = to_pll_clk_hw(hw);
+	struct dsi_pll_resource *pll_res = pll->priv;
+
+	return pll_res->byteclk_rate;
+}
+
+static long dsi_pll_pclk_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct dsi_pll_clk *pll = to_pll_clk_hw(hw);
+	struct dsi_pll_resource *pll_res = pll->priv;
+
+	return pll_res->pclk_rate;
+}
+
+static unsigned long dsi_pll_vco_recalc_rate(struct dsi_pll_resource *pll)
+{
+	u64 ref_clk;
+	u64 multiplier;
+	u32 frac;
+	u32 dec;
+	u32 pll_post_div;
+	u64 pll_freq, tmp64;
+	u64 vco_rate;
+	struct dsi_pll_4nm *pll_4nm;
+	struct dsi_pll_config *config;
+
+	ref_clk = pll->vco_ref_clk_rate;
+	pll_4nm = pll->priv;
+	if (!pll_4nm) {
+		DSI_PLL_ERR(pll, "pll configuration not found\n");
+		return -EINVAL;
+	}
+
+	config = &pll_4nm->pll_configuration;
+
+	dec = DSI_PLL_REG_R(pll->pll_base, PLL_DECIMAL_DIV_START_1);
+	dec &= 0xFF;
+
+	frac = DSI_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_LOW_1);
+	frac |= ((DSI_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_MID_1) & 0xFF) << 8);
+	frac |= ((DSI_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_HIGH_1) & 0x3) << 16);
+
+	multiplier = 1 << config->frac_bits;
+	pll_freq = dec * (ref_clk * 2);
+	tmp64 = (ref_clk * 2 * frac);
+	pll_freq += div_u64(tmp64, multiplier);
+
+	pll_post_div = dsi_pll_get_pll_post_div(pll);
+
+	vco_rate = div_u64(pll_freq, pll_post_div);
+
+	return vco_rate;
+}
+
+static unsigned long dsi_pll_byteclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct dsi_pll_clk *byte_pll = to_pll_clk_hw(hw);
+	struct dsi_pll_resource *pll = NULL;
+	u64 vco_rate = 0;
+	u64 byte_rate = 0;
+	u32 phy_post_div;
+
+	if (!byte_pll->priv) {
+		DSI_PLL_INFO(pll, "pll priv is null\n");
+		return 0;
+	}
+
+	pll = byte_pll->priv;
+
+	/*
+	 * In the case when byteclk rate is set, the recalculation function
+	 * should  return the current rate. Recalc rate is also called during
+	 * clock registration, during which the function should reverse
+	 * calculate clock rates that were set as part of UEFI.
+	 */
+	if (pll->byteclk_rate != 0) {
+		DSI_PLL_DBG(pll, "returning byte clk rate = %lld %lld\n", pll->byteclk_rate,
+				parent_rate);
+		return  pll->byteclk_rate;
+	}
+
+	vco_rate = dsi_pll_vco_recalc_rate(pll);
+
+	phy_post_div = dsi_pll_get_phy_post_div(pll);
+	byte_rate = div_u64(vco_rate, phy_post_div);
+
+	if (pll->type == DSI_PHY_TYPE_DPHY)
+		byte_rate = div_u64(byte_rate, 8);
+	else
+		byte_rate = div_u64(byte_rate, 7);
+
+	return byte_rate;
+}
+
+static unsigned long dsi_pll_pclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct dsi_pll_clk *pix_pll = to_pll_clk_hw(hw);
+	struct dsi_pll_resource *pll = NULL;
+	u64 vco_rate = 0;
+	u64 pclk_rate = 0;
+	u32 phy_post_div, pclk_div;
+
+	if (!pix_pll->priv) {
+		DSI_PLL_INFO(pll, "pll priv is null\n");
+		return 0;
+	}
+
+	pll = pix_pll->priv;
+
+	/*
+	 * In the case when pclk rate is set, the recalculation function
+	 * should  return the current rate. Recalc rate is also called during
+	 * clock registration, during which the function should reverse
+	 * calculate the clock rates that were set as part of UEFI.
+	 */
+	if (pll->pclk_rate != 0) {
+		DSI_PLL_DBG(pll, "returning pclk rate = %lld %lld\n", pll->pclk_rate, parent_rate);
+		return pll->pclk_rate;
+	}
+
+	vco_rate = dsi_pll_vco_recalc_rate(pll);
+
+	if (pll->type == DSI_PHY_TYPE_DPHY) {
+		phy_post_div = dsi_pll_get_phy_post_div(pll);
+		pclk_rate = div_u64(vco_rate, phy_post_div);
+		pclk_rate = div_u64(pclk_rate, 2);
+		pclk_div = dsi_pll_get_pclk_div(pll);
+		pclk_rate = div_u64(pclk_rate, pclk_div);
+	} else {
+		pclk_rate = vco_rate * 2;
+		pclk_rate = div_u64(pclk_rate, 7);
+		pclk_div = dsi_pll_get_pclk_div(pll);
+		pclk_rate = div_u64(pclk_rate, pclk_div);
+	}
+
+	return pclk_rate;
+}
+
+static const struct clk_ops pll_byteclk_ops = {
+	.recalc_rate = dsi_pll_byteclk_recalc_rate,
+	.set_rate = dsi_pll_set_rate_stub,
+	.round_rate = dsi_pll_byteclk_round_rate,
+	.prepare = dsi_pll_prepare_stub,
+	.unprepare = dsi_pll_unprepare_stub,
+};
+
+static const struct clk_ops pll_pclk_ops = {
+	.recalc_rate = dsi_pll_pclk_recalc_rate,
+	.set_rate = dsi_pll_set_rate_stub,
+	.round_rate = dsi_pll_pclk_round_rate,
+	.prepare = dsi_pll_prepare_stub,
+	.unprepare = dsi_pll_unprepare_stub,
+};
+
+/*
+ * Clock tree for generating DSI byte and pclk.
+ *
+ *
+ *  +-------------------------------+		+----------------------------+
+ *  |    dsi_phy_pll_out_byteclk    |		|    dsi_phy_pll_out_dsiclk  |
+ *  +---------------+---------------+		+--------------+-------------+
+ *                  |                                          |
+ *                  |                                          |
+ *                  v                                          v
+ *            dsi_byte_clk                                  dsi_pclk
+ *
+ *
+ */
+
+static struct dsi_pll_clk dsi0_phy_pll_out_byteclk = {
+	.hw.init = &(struct clk_init_data){
+			.name = "dsi0_phy_pll_out_byteclk",
+			.ops = &pll_byteclk_ops,
+	},
+};
+
+static struct dsi_pll_clk dsi1_phy_pll_out_byteclk = {
+	.hw.init = &(struct clk_init_data){
+			.name = "dsi1_phy_pll_out_byteclk",
+			.ops = &pll_byteclk_ops,
+	},
+};
+
+static struct dsi_pll_clk dsi0_phy_pll_out_dsiclk = {
+	.hw.init = &(struct clk_init_data){
+			.name = "dsi0_phy_pll_out_dsiclk",
+			.ops = &pll_pclk_ops,
+	},
+};
+
+static struct dsi_pll_clk dsi1_phy_pll_out_dsiclk = {
+	.hw.init = &(struct clk_init_data){
+			.name = "dsi1_phy_pll_out_dsiclk",
+			.ops = &pll_pclk_ops,
+	},
+};
+
+int dsi_pll_clock_register_4nm(struct platform_device *pdev, struct dsi_pll_resource *pll_res)
+{
+	int rc = 0, ndx;
+	struct clk *clk;
+	struct clk_onecell_data *clk_data;
+	int num_clks = 4;
+
+	if (!pdev || !pdev->dev.of_node || !pll_res || !pll_res->pll_base || !pll_res->phy_base) {
+		DSI_PLL_ERR(pll_res, "Invalid params\n");
+		return -EINVAL;
+	}
+
+	ndx = pll_res->index;
+
+	if (ndx >= DSI_PLL_MAX) {
+		DSI_PLL_ERR(pll_res, "not supported\n");
+		return -EINVAL;
+	}
+
+	pll_rsc_db[ndx] = pll_res;
+	plls[ndx].rsc = pll_res;
+	pll_res->priv = &plls[ndx];
+	pll_res->vco_delay = VCO_DELAY_USEC;
+	pll_res->vco_min_rate = 600000000;
+	pll_res->vco_ref_clk_rate = 19200000UL;
+
+	dsi_pll_setup_config(pll_res->priv, pll_res);
+
+	clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
+					GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * sizeof(struct clk *)), GFP_KERNEL);
+	if (!clk_data->clks)
+		return -ENOMEM;
+
+	clk_data->clk_num = num_clks;
+
+	/* Establish client data */
+	if (ndx == 0) {
+		dsi0_phy_pll_out_byteclk.priv = pll_res;
+		dsi0_phy_pll_out_dsiclk.priv = pll_res;
+
+		clk = devm_clk_register(&pdev->dev, &dsi0_phy_pll_out_byteclk.hw);
+		if (IS_ERR(clk)) {
+			DSI_PLL_ERR(pll_res, "clk registration failed for DSI clock\n");
+			rc = -EINVAL;
+			goto clk_register_fail;
+		}
+		clk_data->clks[0] = clk;
+
+		clk = devm_clk_register(&pdev->dev, &dsi0_phy_pll_out_dsiclk.hw);
+		if (IS_ERR(clk)) {
+			DSI_PLL_ERR(pll_res, "clk registration failed for DSI clock\n");
+			rc = -EINVAL;
+			goto clk_register_fail;
+		}
+		clk_data->clks[1] = clk;
+
+
+		rc = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, clk_data);
+	} else {
+		dsi1_phy_pll_out_byteclk.priv = pll_res;
+		dsi1_phy_pll_out_dsiclk.priv = pll_res;
+
+		clk = devm_clk_register(&pdev->dev, &dsi1_phy_pll_out_byteclk.hw);
+		if (IS_ERR(clk)) {
+			DSI_PLL_ERR(pll_res, "clk registration failed for DSI clock\n");
+			rc = -EINVAL;
+			goto clk_register_fail;
+		}
+		clk_data->clks[2] = clk;
+
+		clk = devm_clk_register(&pdev->dev, &dsi1_phy_pll_out_dsiclk.hw);
+		if (IS_ERR(clk)) {
+			DSI_PLL_ERR(pll_res, "clk registration failed for DSI clock\n");
+			rc = -EINVAL;
+			goto clk_register_fail;
+		}
+		clk_data->clks[3] = clk;
+
+		rc = of_clk_add_provider(pdev->dev.of_node,
+				of_clk_src_onecell_get, clk_data);
+	}
+	if (!rc) {
+		DSI_PLL_INFO(pll_res, "Registered clocks successfully\n");
+
+		return rc;
+	}
+clk_register_fail:
+	return rc;
+}
+
+static int dsi_pll_4nm_set_byteclk_div(struct dsi_pll_resource *pll, bool commit)
+{
+
+	int i = 0;
+	int table_size;
+	u32 pll_post_div = 0, phy_post_div = 0;
+	struct dsi_pll_div_table *table;
+	u64 bitclk_rate;
+	u64 const phy_rate_split = 1500000000UL;
+
+	if (pll->type == DSI_PHY_TYPE_DPHY) {
+		bitclk_rate = pll->byteclk_rate * 8;
+
+		if (bitclk_rate <= phy_rate_split) {
+			table = pll_4nm_dphy_lb;
+			table_size = ARRAY_SIZE(pll_4nm_dphy_lb);
+		} else {
+			table = pll_4nm_dphy_hb;
+			table_size = ARRAY_SIZE(pll_4nm_dphy_hb);
+		}
+	} else {
+		bitclk_rate = pll->byteclk_rate * 7;
+
+		if (bitclk_rate <= phy_rate_split) {
+			table = pll_4nm_cphy_lb;
+			table_size = ARRAY_SIZE(pll_4nm_cphy_lb);
+		} else {
+			table = pll_4nm_cphy_hb;
+			table_size = ARRAY_SIZE(pll_4nm_cphy_hb);
+		}
+	}
+
+	for (i = 0; i < table_size; i++) {
+		if ((table[i].min_hz <= bitclk_rate) && (bitclk_rate <= table[i].max_hz)) {
+			pll_post_div = table[i].pll_div;
+			phy_post_div = table[i].phy_div;
+			break;
+		}
+	}
+
+	DSI_PLL_DBG(pll, "bit clk rate: %llu, pll_post_div: %d, phy_post_div: %d\n",
+			bitclk_rate, pll_post_div, phy_post_div);
+
+	if (commit) {
+		dsi_pll_set_pll_post_div(pll, pll_post_div);
+		dsi_pll_set_phy_post_div(pll, phy_post_div);
+	}
+
+	pll->vco_rate = bitclk_rate * pll_post_div * phy_post_div;
+
+	return 0;
+}
+
+static int dsi_pll_calc_dphy_pclk_div(struct dsi_pll_resource *pll)
+{
+	u32 m_val, n_val; /* M and N values of MND trio */
+	u32 pclk_div;
+
+	if (pll->bpp == 30 && pll->lanes == 4) {
+		/* RGB101010 */
+		m_val = 2;
+		n_val = 3;
+	} else if (pll->bpp == 18 && pll->lanes == 2) {
+		/* RGB666_packed */
+		m_val = 2;
+		n_val = 9;
+	} else if (pll->bpp == 18 && pll->lanes == 4) {
+		/* RGB666_packed */
+		m_val = 4;
+		n_val = 9;
+	} else if (pll->bpp == 16 && pll->lanes == 3) {
+		/* RGB565 */
+		m_val = 3;
+		n_val = 8;
+	} else {
+		m_val = 1;
+		n_val = 1;
+	}
+
+	/* Calculating pclk_div assuming dsiclk_sel to be 1 */
+	pclk_div = pll->bpp;
+	pclk_div = mult_frac(pclk_div, m_val, n_val);
+	do_div(pclk_div, 2);
+	do_div(pclk_div, pll->lanes);
+
+	DSI_PLL_DBG(pll, "bpp: %d, lanes: %d, m_val: %u, n_val: %u, pclk_div: %u\n",
+                          pll->bpp, pll->lanes, m_val, n_val, pclk_div);
+
+	return pclk_div;
+}
+
+static int dsi_pll_calc_cphy_pclk_div(struct dsi_pll_resource *pll)
+{
+	u32 m_val, n_val; /* M and N values of MND trio */
+	u32 pclk_div;
+	u32 phy_post_div = dsi_pll_get_phy_post_div(pll);
+
+	if (pll->bpp == 24 && pll->lanes == 2) {
+		/*
+		 * RGB888 or DSC is enabled
+		 * Skipping DSC enabled check
+		 */
+		m_val = 2;
+		n_val = 3;
+	} else if (pll->bpp == 30) {
+		/* RGB101010 */
+		if (pll->lanes == 1) {
+			m_val = 4;
+			n_val = 15;
+		} else {
+			m_val = 16;
+			n_val = 35;
+		}
+	} else if (pll->bpp == 18) {
+		/* RGB666_packed */
+		if (pll->lanes == 1) {
+			m_val = 8;
+			n_val = 63;
+		} else if (pll->lanes == 2) {
+			m_val = 16;
+			n_val = 63;
+		} else if (pll->lanes == 3) {
+			m_val = 8;
+			n_val = 21;
+		} else {
+			m_val = 1;
+			n_val = 1;
+		}
+	} else if (pll->bpp == 16 && pll->lanes == 3) {
+		/* RGB565 */
+		m_val = 3;
+		n_val = 7;
+	} else {
+		m_val = 1;
+		n_val = 1;
+	}
+
+	/* Calculating pclk_div assuming dsiclk_sel to be 3 */
+	pclk_div =  pll->bpp * phy_post_div;
+	pclk_div = mult_frac(pclk_div, m_val, n_val);
+	do_div(pclk_div, 8);
+	do_div(pclk_div, pll->lanes);
+
+	DSI_PLL_DBG(pll, "bpp: %d, lanes: %d, m_val: %u, n_val: %u, phy_post_div: %u pclk_div: %u\n",
+                          pll->bpp, pll->lanes, m_val, n_val, phy_post_div, pclk_div);
+
+	return pclk_div;
+}
+
+static int dsi_pll_4nm_set_pclk_div(struct dsi_pll_resource *pll, bool commit)
+{
+
+	int dsi_clk = 0, pclk_div = 0;
+	u64 pclk_src_rate;
+	u32 pll_post_div;
+	u32 phy_post_div;
+
+	pll_post_div = dsi_pll_get_pll_post_div(pll);
+	pclk_src_rate = div_u64(pll->vco_rate, pll_post_div);
+	if (pll->type == DSI_PHY_TYPE_DPHY) {
+		dsi_clk = 0x1;
+		phy_post_div = dsi_pll_get_phy_post_div(pll);
+		pclk_src_rate = div_u64(pclk_src_rate, phy_post_div);
+		pclk_src_rate = div_u64(pclk_src_rate, 2);
+		pclk_div = dsi_pll_calc_dphy_pclk_div(pll);
+	} else {
+		dsi_clk = 0x3;
+		pclk_src_rate *= 2;
+		pclk_src_rate = div_u64(pclk_src_rate, 7);
+		pclk_div = dsi_pll_calc_cphy_pclk_div(pll);
+	}
+
+	pll->pclk_rate = div_u64(pclk_src_rate, pclk_div);
+
+	DSI_PLL_DBG(pll, "pclk rate: %llu, dsi_clk: %d, pclk_div: %d\n",
+			pll->pclk_rate, dsi_clk, pclk_div);
+
+	if (commit) {
+		dsi_pll_set_dsi_clk(pll, dsi_clk);
+		dsi_pll_set_pclk_div(pll, pclk_div);
+	}
+
+	return 0;
+
+}
+
+static int dsi_pll_4nm_vco_set_rate(struct dsi_pll_resource *pll_res)
+{
+	struct dsi_pll_4nm *pll;
+
+	pll = pll_res->priv;
+	if (!pll) {
+		DSI_PLL_ERR(pll_res, "pll configuration not found\n");
+		return -EINVAL;
+	}
+
+	DSI_PLL_DBG(pll_res, "rate=%lu\n", pll_res->vco_rate);
+
+	pll_res->vco_current_rate = pll_res->vco_rate;
+
+	dsi_pll_detect_phy_mode(pll, pll_res);
+
+	dsi_pll_calc_dec_frac(pll, pll_res);
+
+	dsi_pll_calc_ssc(pll, pll_res);
+
+	dsi_pll_commit(pll, pll_res);
+
+	dsi_pll_config_hzindep_reg(pll, pll_res);
+
+	dsi_pll_ssc_commit(pll, pll_res);
+
+	/* flush, ensure all register writes are done*/
+	wmb();
+
+	return 0;
+}
+
+static int dsi_pll_read_stored_trim_codes(struct dsi_pll_resource *pll_res,
+					  unsigned long vco_clk_rate)
+{
+	int i;
+	bool found = false;
+
+	if (!pll_res->dfps)
+		return -EINVAL;
+
+	for (i = 0; i < pll_res->dfps->vco_rate_cnt; i++) {
+		struct dfps_codes_info *codes_info = &pll_res->dfps->codes_dfps[i];
+
+		DSI_PLL_DBG(pll_res, "valid=%d vco_rate=%d, code %d %d %d\n",
+			codes_info->is_valid, codes_info->clk_rate,
+			codes_info->pll_codes.pll_codes_1,
+			codes_info->pll_codes.pll_codes_2,
+			codes_info->pll_codes.pll_codes_3);
+
+		if (vco_clk_rate != codes_info->clk_rate && codes_info->is_valid)
+			continue;
+
+		pll_res->cache_pll_trim_codes[0] = codes_info->pll_codes.pll_codes_1;
+		pll_res->cache_pll_trim_codes[1] = codes_info->pll_codes.pll_codes_2;
+		pll_res->cache_pll_trim_codes[2] = codes_info->pll_codes.pll_codes_3;
+		found = true;
+		break;
+	}
+
+	if (!found)
+		return -EINVAL;
+
+	DSI_PLL_DBG(pll_res, "trim_code_0=0x%x trim_code_1=0x%x trim_code_2=0x%x\n",
+			pll_res->cache_pll_trim_codes[0],
+			pll_res->cache_pll_trim_codes[1],
+			pll_res->cache_pll_trim_codes[2]);
+
+	return 0;
+}
+
+static void dsi_pll_4nm_dynamic_refresh(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
+{
+	u32 data;
+	u32 offset = DSI_PHY_TO_PLL_OFFSET;
+	u32 upper_addr = 0;
+	u32 upper_addr2 = 0;
+	struct dsi_pll_regs *reg = &pll->reg_setup;
+
+	data = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+	data &= ~BIT(5);
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL0, PHY_CMN_CLK_CFG1,
+			PHY_CMN_PLL_CNTRL, data, 0);
+	upper_addr |= (upper_8_bit(PHY_CMN_CLK_CFG1) << 0);
+	upper_addr |= (upper_8_bit(PHY_CMN_PLL_CNTRL) << 1);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL1,
+			   PHY_CMN_RBUF_CTRL, (PLL_CORE_INPUT_OVERRIDE + offset), 0, 0x12);
+	upper_addr |= (upper_8_bit(PHY_CMN_RBUF_CTRL) << 2);
+	upper_addr |= (upper_8_bit(PLL_CORE_INPUT_OVERRIDE + offset) << 3);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL2,
+			(PLL_DECIMAL_DIV_START_1 + offset), (PLL_FRAC_DIV_START_LOW_1 + offset),
+			reg->decimal_div_start, reg->frac_div_start_low);
+	upper_addr |= (upper_8_bit(PLL_DECIMAL_DIV_START_1 + offset) << 4);
+	upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_LOW_1 + offset) << 5);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL3,
+			(PLL_FRAC_DIV_START_MID_1 + offset), (PLL_FRAC_DIV_START_HIGH_1 + offset),
+			reg->frac_div_start_mid, reg->frac_div_start_high);
+	upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_MID_1 + offset) << 6);
+	upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_HIGH_1 + offset) << 7);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL4,
+			(PLL_SYSTEM_MUXES + offset), (PLL_PLL_LOCKDET_RATE_1 + offset), 0xc0, 0x10);
+	upper_addr |= (upper_8_bit(PLL_SYSTEM_MUXES + offset) << 8);
+	upper_addr |= (upper_8_bit(PLL_PLL_LOCKDET_RATE_1 + offset) << 9);
+
+	data = DSI_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE) & 0x03;
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL5,
+			(PLL_PLL_OUTDIV_RATE + offset), (PLL_PLL_LOCK_DELAY + offset), data, 0x06);
+
+	upper_addr |= (upper_8_bit(PLL_PLL_OUTDIV_RATE + offset) << 10);
+	upper_addr |= (upper_8_bit(PLL_PLL_LOCK_DELAY + offset) << 11);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL6,
+			(PLL_CMODE_1 + offset), (PLL_CLOCK_INVERTERS_1 + offset),
+			pll->cphy_enabled ? 0x00 : 0x10, reg->pll_clock_inverters);
+	upper_addr |= (upper_8_bit(PLL_CMODE_1 + offset) << 12);
+	upper_addr |= (upper_8_bit(PLL_CLOCK_INVERTERS_1 + offset) << 13);
+
+	data = DSI_PLL_REG_R(rsc->pll_base, PLL_VCO_CONFIG_1);
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL7,
+			(PLL_ANALOG_CONTROLS_FIVE_1 + offset), (PLL_VCO_CONFIG_1 + offset), 0x01,
+			data);
+	upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_FIVE_1 + offset) << 14);
+	upper_addr |= (upper_8_bit(PLL_VCO_CONFIG_1 + offset) << 15);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL8,
+			(PLL_ANALOG_CONTROLS_FIVE + offset), (PLL_ANALOG_CONTROLS_TWO + offset),
+			0x01, 0x03);
+	upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_FIVE + offset) << 16);
+	upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_TWO + offset) << 17);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL9,
+			(PLL_ANALOG_CONTROLS_THREE + offset), (PLL_DSM_DIVIDER + offset),
+			rsc->cache_pll_trim_codes[2], 0x00);
+	upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_THREE + offset) << 18);
+	upper_addr |= (upper_8_bit(PLL_DSM_DIVIDER + offset) << 19);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL10,
+			(PLL_FEEDBACK_DIVIDER + offset), (PLL_CALIBRATION_SETTINGS + offset),
+			0x4E, 0x40);
+	upper_addr |= (upper_8_bit(PLL_FEEDBACK_DIVIDER + offset) << 20);
+	upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 21);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL11,
+			(PLL_BAND_SEL_CAL_SETTINGS_THREE + offset),
+			(PLL_FREQ_DETECT_SETTINGS_ONE + offset), 0xBA, 0x0C);
+	upper_addr |= (upper_8_bit(PLL_BAND_SEL_CAL_SETTINGS_THREE + offset) << 22);
+	upper_addr |= (upper_8_bit(PLL_FREQ_DETECT_SETTINGS_ONE + offset) << 23);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL12,
+			(PLL_OUTDIV + offset), (PLL_CORE_OVERRIDE + offset), 0, 0);
+	upper_addr |= (upper_8_bit(PLL_OUTDIV + offset) << 24);
+	upper_addr |= (upper_8_bit(PLL_CORE_OVERRIDE + offset) << 25);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL13,
+			(PLL_PLL_DIGITAL_TIMERS_TWO + offset), (PLL_PLL_PROP_GAIN_RATE_1 + offset),
+			0x08, reg->pll_prop_gain_rate);
+	upper_addr |= (upper_8_bit(PLL_PLL_DIGITAL_TIMERS_TWO + offset) << 26);
+	upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 27);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL14,
+			(PLL_PLL_BAND_SEL_RATE_1 + offset),
+			(PLL_PLL_INT_GAIN_IFILT_BAND_1 + offset), 0xC0, 0x82);
+	upper_addr |= (upper_8_bit(PLL_PLL_BAND_SEL_RATE_1 + offset) << 28);
+	upper_addr |= (upper_8_bit(PLL_PLL_INT_GAIN_IFILT_BAND_1 + offset) << 29);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL15,
+			(PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 + offset),
+			(PLL_PLL_LOCK_OVERRIDE + offset), 0x4c, 0x80);
+	upper_addr |= (upper_8_bit(PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 + offset) << 30);
+	upper_addr |= (upper_8_bit(PLL_PLL_LOCK_OVERRIDE + offset) << 31);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL16,
+			(PLL_PFILT + offset), (PLL_IFILT + offset),
+			0x29, 0x3f);
+	upper_addr2 |= (upper_8_bit(PLL_PFILT + offset) << 0);
+	upper_addr2 |= (upper_8_bit(PLL_IFILT + offset) << 1);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL17,
+			(PLL_SYSTEM_MUXES + offset), (PLL_CALIBRATION_SETTINGS + offset),
+			0xe0, 0x44);
+	upper_addr2 |= (upper_8_bit(PLL_BAND_SEL_CAL + offset) << 2);
+	upper_addr2 |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 3);
+
+	data = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0);
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL18,
+			PHY_CMN_CTRL_2, PHY_CMN_CLK_CFG0, 0x40, data);
+
+	if (rsc->slave)
+		DSI_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL10,
+				PHY_CMN_CLK_CFG0, PHY_CMN_CTRL_0, data, 0x7f);
+
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL27,
+			PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL28,
+			PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL29,
+			PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
+
+	data = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1) | BIT(5);
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL30,
+			PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, data, 0x01);
+	DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL31,
+			PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, data, data);
+
+	if (rsc->slave) {
+		data = DSI_PLL_REG_R(rsc->slave->phy_base, PHY_CMN_CLK_CFG1) | BIT(5);
+
+		DSI_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL30,
+				PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, data, 0x01);
+		DSI_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL31,
+				PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, data, data);
+	}
+
+	DSI_PLL_REG_W(rsc->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, upper_addr);
+	DSI_PLL_REG_W(rsc->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, upper_addr2);
+	wmb(); /* commit register writes */
+}
+
+static int dsi_pll_4nm_dynamic_clk_vco_set_rate(struct dsi_pll_resource *rsc)
+{
+	int rc;
+	struct dsi_pll_4nm *pll;
+	u32 rate;
+
+	if (!rsc) {
+		DSI_PLL_ERR(rsc, "pll resource not found\n");
+		return -EINVAL;
+	}
+
+	rate = rsc->vco_rate;
+	pll = rsc->priv;
+	if (!pll) {
+		DSI_PLL_ERR(rsc, "pll configuration not found\n");
+		return -EINVAL;
+	}
+
+	rc = dsi_pll_read_stored_trim_codes(rsc, rate);
+	if (rc) {
+		DSI_PLL_ERR(rsc, "cannot find pll codes rate=%ld\n", rate);
+		return -EINVAL;
+	}
+
+	DSI_PLL_DBG(rsc, "ndx=%d, rate=%lu\n", rsc->index, rate);
+	rsc->vco_current_rate = rate;
+
+	dsi_pll_calc_dec_frac(pll, rsc);
+
+	/* program dynamic refresh control registers */
+	dsi_pll_4nm_dynamic_refresh(pll, rsc);
+
+	return 0;
+}
+
+static int dsi_pll_4nm_enable(struct dsi_pll_resource *rsc)
+{
+	int rc = 0;
+
+	/* Start PLL */
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01);
+
+	/*
+	 * ensure all PLL configurations are written prior to checking
+	 * for PLL lock.
+	 */
+	wmb();
+
+	/* Check for PLL lock */
+	rc = dsi_pll_4nm_lock_status(rsc);
+	if (rc) {
+		DSI_PLL_ERR(rsc, "lock failed\n");
+		goto error;
+	}
+
+	/*
+	 * assert power on reset for PHY digital in case the PLL is
+	 * enabled after CX of analog domain power collapse. This needs
+	 * to be done before enabling the global clk.
+	 */
+	dsi_pll_phy_dig_reset(rsc);
+	if (rsc->slave)
+		dsi_pll_phy_dig_reset(rsc->slave);
+
+	dsi_pll_enable_global_clk(rsc);
+	if (rsc->slave)
+		dsi_pll_enable_global_clk(rsc->slave);
+
+	/* flush, ensure all register writes are done*/
+	wmb();
+error:
+	return rc;
+}
+
+static int dsi_pll_4nm_disable(struct dsi_pll_resource *rsc)
+{
+	int rc = 0;
+
+	DSI_PLL_DBG(rsc, "stop PLL\n");
+
+	/*
+	 * To avoid any stray glitches while
+	 * abruptly powering down the PLL
+	 * make sure to gate the clock using
+	 * the clock enable bit before powering
+	 * down the PLL
+	 */
+	dsi_pll_disable_global_clk(rsc);
+	DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0);
+	dsi_pll_disable_sub(rsc);
+	if (rsc->slave) {
+		dsi_pll_disable_global_clk(rsc->slave);
+		dsi_pll_disable_sub(rsc->slave);
+	}
+	/* flush, ensure all register writes are done*/
+	wmb();
+
+	return rc;
+}
+
+int dsi_pll_4nm_configure(void *pll, bool commit)
+{
+
+	int rc = 0;
+	struct dsi_pll_resource *rsc = (struct dsi_pll_resource *)pll;
+
+	dsi_pll_config_slave(rsc);
+
+	/* PLL power needs to be enabled before accessing PLL registers */
+	dsi_pll_enable_pll_bias(rsc);
+	if (rsc->slave)
+		dsi_pll_enable_pll_bias(rsc->slave);
+
+	dsi_pll_init_val(rsc);
+
+	rc = dsi_pll_4nm_set_byteclk_div(rsc, commit);
+
+	if (commit) {
+		rc = dsi_pll_4nm_set_pclk_div(rsc, commit);
+		rc = dsi_pll_4nm_vco_set_rate(rsc);
+	} else {
+		rc = dsi_pll_4nm_dynamic_clk_vco_set_rate(rsc);
+	}
+
+	return 0;
+}
+
+int dsi_pll_4nm_toggle(void *pll, bool prepare)
+{
+	int rc = 0;
+	struct dsi_pll_resource *pll_res = (struct dsi_pll_resource *)pll;
+
+	if (!pll_res) {
+		DSI_PLL_ERR(pll_res, "dsi pll resources are not available\n");
+		return -EINVAL;
+	}
+
+	if (prepare) {
+		rc = dsi_pll_4nm_enable(pll_res);
+		if (rc)
+			DSI_PLL_ERR(pll_res, "enable failed: %d\n", rc);
+	} else {
+		rc = dsi_pll_4nm_disable(pll_res);
+		if (rc)
+			DSI_PLL_ERR(pll_res, "disable failed: %d\n", rc);
+	}
+
+	return rc;
+}

+ 299 - 0
msm/dsi/dsi_pll_4nm.h

@@ -0,0 +1,299 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "dsi_pll.h"
+
+/* Register Offsets from PLL base address */
+#define PLL_ANALOG_CONTROLS_ONE			0x0000
+#define PLL_ANALOG_CONTROLS_TWO			0x0004
+#define PLL_INT_LOOP_SETTINGS			0x0008
+#define PLL_INT_LOOP_SETTINGS_TWO		0x000C
+#define PLL_ANALOG_CONTROLS_THREE		0x0010
+#define PLL_ANALOG_CONTROLS_FOUR		0x0014
+#define PLL_ANALOG_CONTROLS_FIVE		0x0018
+#define PLL_INT_LOOP_CONTROLS			0x001C
+#define PLL_DSM_DIVIDER				0x0020
+#define PLL_FEEDBACK_DIVIDER			0x0024
+#define PLL_SYSTEM_MUXES			0x0028
+#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES	0x002C
+#define PLL_CMODE				0x0030
+#define PLL_PSM_CTRL				0x0034
+#define PLL_RSM_CTRL				0x0038
+#define PLL_VCO_TUNE_MAP			0x003C
+#define PLL_PLL_CNTRL				0x0040
+#define PLL_CALIBRATION_SETTINGS		0x0044
+#define PLL_BAND_SEL_CAL_TIMER_LOW		0x0048
+#define PLL_BAND_SEL_CAL_TIMER_HIGH		0x004C
+#define PLL_BAND_SEL_CAL_SETTINGS		0x0050
+#define PLL_BAND_SEL_MIN			0x0054
+#define PLL_BAND_SEL_MAX			0x0058
+#define PLL_BAND_SEL_PFILT			0x005C
+#define PLL_BAND_SEL_IFILT			0x0060
+#define PLL_BAND_SEL_CAL_SETTINGS_TWO		0x0064
+#define PLL_BAND_SEL_CAL_SETTINGS_THREE		0x0068
+#define PLL_BAND_SEL_CAL_SETTINGS_FOUR		0x006C
+#define PLL_BAND_SEL_ICODE_HIGH			0x0070
+#define PLL_BAND_SEL_ICODE_LOW			0x0074
+#define PLL_FREQ_DETECT_SETTINGS_ONE		0x0078
+#define PLL_FREQ_DETECT_THRESH			0x007C
+#define PLL_FREQ_DET_REFCLK_HIGH		0x0080
+#define PLL_FREQ_DET_REFCLK_LOW			0x0084
+#define PLL_FREQ_DET_PLLCLK_HIGH		0x0088
+#define PLL_FREQ_DET_PLLCLK_LOW			0x008C
+#define PLL_PFILT				0x0090
+#define PLL_IFILT				0x0094
+#define PLL_PLL_GAIN				0x0098
+#define PLL_ICODE_LOW				0x009C
+#define PLL_ICODE_HIGH				0x00A0
+#define PLL_LOCKDET				0x00A4
+#define PLL_OUTDIV				0x00A8
+#define PLL_FASTLOCK_CONTROL			0x00AC
+#define PLL_PASS_OUT_OVERRIDE_ONE		0x00B0
+#define PLL_PASS_OUT_OVERRIDE_TWO		0x00B4
+#define PLL_CORE_OVERRIDE			0x00B8
+#define PLL_CORE_INPUT_OVERRIDE			0x00BC
+#define PLL_RATE_CHANGE				0x00C0
+#define PLL_PLL_DIGITAL_TIMERS			0x00C4
+#define PLL_PLL_DIGITAL_TIMERS_TWO		0x00C8
+#define PLL_DECIMAL_DIV_START			0x00CC
+#define PLL_FRAC_DIV_START_LOW			0x00D0
+#define PLL_FRAC_DIV_START_MID			0x00D4
+#define PLL_FRAC_DIV_START_HIGH			0x00D8
+#define PLL_DEC_FRAC_MUXES			0x00DC
+#define PLL_DECIMAL_DIV_START_1			0x00E0
+#define PLL_FRAC_DIV_START_LOW_1		0x00E4
+#define PLL_FRAC_DIV_START_MID_1		0x00E8
+#define PLL_FRAC_DIV_START_HIGH_1		0x00EC
+#define PLL_DECIMAL_DIV_START_2			0x00F0
+#define PLL_FRAC_DIV_START_LOW_2		0x00F4
+#define PLL_FRAC_DIV_START_MID_2		0x00F8
+#define PLL_FRAC_DIV_START_HIGH_2		0x00FC
+#define PLL_MASH_CONTROL			0x0100
+#define PLL_SSC_STEPSIZE_LOW			0x0104
+#define PLL_SSC_STEPSIZE_HIGH			0x0108
+#define PLL_SSC_DIV_PER_LOW			0x010C
+#define PLL_SSC_DIV_PER_HIGH			0x0110
+#define PLL_SSC_ADJPER_LOW			0x0114
+#define PLL_SSC_ADJPER_HIGH			0x0118
+#define PLL_SSC_MUX_CONTROL			0x011C
+#define PLL_SSC_STEPSIZE_LOW_1			0x0120
+#define PLL_SSC_STEPSIZE_HIGH_1			0x0124
+#define PLL_SSC_DIV_PER_LOW_1			0x0128
+#define PLL_SSC_DIV_PER_HIGH_1			0x012C
+#define PLL_SSC_ADJPER_LOW_1			0x0130
+#define PLL_SSC_ADJPER_HIGH_1			0x0134
+#define PLL_SSC_STEPSIZE_LOW_2			0x0138
+#define PLL_SSC_STEPSIZE_HIGH_2			0x013C
+#define PLL_SSC_DIV_PER_LOW_2			0x0140
+#define PLL_SSC_DIV_PER_HIGH_2			0x0144
+#define PLL_SSC_ADJPER_LOW_2			0x0148
+#define PLL_SSC_ADJPER_HIGH_2			0x014C
+#define PLL_SSC_CONTROL				0x0150
+#define PLL_PLL_OUTDIV_RATE			0x0154
+#define PLL_PLL_LOCKDET_RATE_1			0x0158
+#define PLL_PLL_LOCKDET_RATE_2			0x015C
+#define PLL_PLL_PROP_GAIN_RATE_1		0x0160
+#define PLL_PLL_PROP_GAIN_RATE_2		0x0164
+#define PLL_PLL_BAND_SEL_RATE_1			0x0168
+#define PLL_PLL_BAND_SEL_RATE_2			0x016C
+#define PLL_PLL_INT_GAIN_IFILT_BAND_1		0x0170
+#define PLL_PLL_INT_GAIN_IFILT_BAND_2		0x0174
+#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1	0x0178
+#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_2	0x017C
+#define PLL_PLL_FASTLOCK_EN_BAND		0x0180
+#define PLL_FREQ_TUNE_ACCUM_INIT_MID		0x0184
+#define PLL_FREQ_TUNE_ACCUM_INIT_HIGH		0x0188
+#define PLL_FREQ_TUNE_ACCUM_INIT_MUX		0x018C
+#define PLL_PLL_LOCK_OVERRIDE			0x0190
+#define PLL_PLL_LOCK_DELAY			0x0194
+#define PLL_PLL_LOCK_MIN_DELAY			0x0198
+#define PLL_CLOCK_INVERTERS			0x019C
+#define PLL_SPARE_AND_JPC_OVERRIDES		0x01A0
+#define PLL_BIAS_CONTROL_1			0x01A4
+#define PLL_BIAS_CONTROL_2			0x01A8
+#define PLL_ALOG_OBSV_BUS_CTRL_1		0x01AC
+#define PLL_COMMON_STATUS_ONE			0x01B0
+#define PLL_COMMON_STATUS_TWO			0x01B4
+#define PLL_BAND_SEL_CAL			0x01B8
+#define PLL_ICODE_ACCUM_STATUS_LOW		0x01BC
+#define PLL_ICODE_ACCUM_STATUS_HIGH		0x01C0
+#define PLL_FD_OUT_LOW				0x01C4
+#define PLL_FD_OUT_HIGH				0x01C8
+#define PLL_ALOG_OBSV_BUS_STATUS_1		0x01CC
+#define PLL_PLL_MISC_CONFIG			0x01D0
+#define PLL_FLL_CONFIG				0x01D4
+#define PLL_FLL_FREQ_ACQ_TIME			0x01D8
+#define PLL_FLL_CODE0				0x01DC
+#define PLL_FLL_CODE1				0x01E0
+#define PLL_FLL_GAIN0				0x01E4
+#define PLL_FLL_GAIN1				0x01E8
+#define PLL_SW_RESET				0x01EC
+#define PLL_FAST_PWRUP				0x01F0
+#define PLL_LOCKTIME0				0x01F4
+#define PLL_LOCKTIME1				0x01F8
+#define PLL_DEBUG_BUS_SEL			0x01FC
+#define PLL_DEBUG_BUS0				0x0200
+#define PLL_DEBUG_BUS1				0x0204
+#define PLL_DEBUG_BUS2				0x0208
+#define PLL_DEBUG_BUS3				0x020C
+#define PLL_ANALOG_FLL_CONTROL_OVERRIDES	0x0210
+#define PLL_VCO_CONFIG				0x0214
+#define PLL_VCO_CAL_CODE1_MODE0_STATUS		0x0218
+#define PLL_VCO_CAL_CODE1_MODE1_STATUS		0x021C
+#define PLL_RESET_SM_STATUS			0x0220
+#define PLL_TDC_OFFSET				0x0224
+#define PLL_PS3_PWRDOWN_CONTROLS		0x0228
+#define PLL_PS4_PWRDOWN_CONTROLS		0x022C
+#define PLL_PLL_RST_CONTROLS			0x0230
+#define PLL_GEAR_BAND_SELECT_CONTROLS		0x0234
+#define PLL_PSM_CLK_CONTROLS			0x0238
+#define PLL_SYSTEM_MUXES_2			0x023C
+#define PLL_VCO_CONFIG_1			0x0240
+#define PLL_VCO_CONFIG_2			0x0244
+#define PLL_CLOCK_INVERTERS_1			0x0248
+#define PLL_CLOCK_INVERTERS_2			0x024C
+#define PLL_CMODE_1				0x0250
+#define PLL_CMODE_2				0x0254
+#define PLL_ANALOG_CONTROLS_FIVE_1		0x0258
+#define PLL_ANALOG_CONTROLS_FIVE_2		0x025C
+#define PLL_PERF_OPTIMIZE			0x0260
+
+/* Register Offsets from PHY base address */
+#define PHY_CMN_CLK_CFG0	0x010
+#define PHY_CMN_CLK_CFG1	0x014
+#define PHY_CMN_GLBL_CTRL	0x018
+#define PHY_CMN_RBUF_CTRL	0x01C
+#define PHY_CMN_CTRL_0		0x024
+#define PHY_CMN_CTRL_2		0x02C
+#define PHY_CMN_CTRL_3		0x030
+#define PHY_CMN_PLL_CNTRL	0x03C
+#define PHY_CMN_GLBL_DIGTOP_SPARE4 0x128
+
+/* Bit definition of SSC control registers */
+#define SSC_CENTER		BIT(0)
+#define SSC_EN			BIT(1)
+#define SSC_FREQ_UPDATE		BIT(2)
+#define SSC_FREQ_UPDATE_MUX	BIT(3)
+#define SSC_UPDATE_SSC		BIT(4)
+#define SSC_UPDATE_SSC_MUX	BIT(5)
+#define SSC_START		BIT(6)
+#define SSC_START_MUX		BIT(7)
+
+/* Dynamic Refresh Control Registers */
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL0		(0x014)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL1		(0x018)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL2		(0x01C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL3		(0x020)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL4		(0x024)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL5		(0x028)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL6		(0x02C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL7		(0x030)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL8		(0x034)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL9		(0x038)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL10		(0x03C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL11		(0x040)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL12		(0x044)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL13		(0x048)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL14		(0x04C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL15		(0x050)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL16		(0x054)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL17		(0x058)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL18		(0x05C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL19		(0x060)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL20		(0x064)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL21		(0x068)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL22		(0x06C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL23		(0x070)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL24		(0x074)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL25		(0x078)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL26		(0x07C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL27		(0x080)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL28		(0x084)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL29		(0x088)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL30		(0x08C)
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL31		(0x090)
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR	(0x094)
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2	(0x098)
+
+#define DSI_PHY_TO_PLL_OFFSET	(0x500)
+
+enum {
+	DSI_PLL_0,
+	DSI_PLL_1,
+	DSI_PLL_MAX
+};
+
+struct dsi_pll_div_table pll_4nm_dphy_lb[] = {
+	{27270000, 30000000, 2, 11},
+	{30000000, 33330000, 4, 5},
+	{33330000, 37500000, 2, 9},
+	{37500000, 40000000, 8, 2},
+	{40000000, 42860000, 1, 15},
+	{42860000, 46150000, 2, 7},
+	{46150000, 50000000, 1, 13},
+	{50000000, 54550000, 4, 3},
+	{54550000, 60000000, 1, 11},
+	{60000000, 66670000, 2, 5},
+	{66670000, 75000000, 1, 9},
+	{75000000, 85710000, 8, 1},
+	{85710000, 100000000, 1, 7},
+	{100000000, 120000000, 2, 3},
+	{120000000, 150000000, 1, 5},
+	{150000000, 200000000, 4, 1},
+	{200000000, 300000000, 1, 3},
+	{300000000, 600000000, 2, 1},
+	{600000000, 1500000000, 1, 1}
+};
+
+struct dsi_pll_div_table pll_4nm_dphy_hb[] = {
+	{68180000, 75000000, 2, 11},
+	{75000000, 83330000, 4, 5},
+	{83330000, 93750000, 2, 9},
+	{93750000, 100000000, 8, 2},
+	{100000000, 107140000, 1, 15},
+	{107140000, 115380000, 2, 7},
+	{115380000, 125000000, 1, 13},
+	{125000000, 136360000, 4, 3},
+	{136360000, 150000000, 1, 11},
+	{150000000, 166670000, 2, 5},
+	{166670000, 187500000, 1, 9},
+	{187500000, 214290000, 8, 1},
+	{214290000, 250000000, 1, 7},
+	{250000000, 300000000, 2, 3},
+	{300000000, 375000000, 1, 5},
+	{375000000, 500000000, 4, 1},
+	{500000000, 750000000, 1, 3},
+	{750000000, 1500000000, 2, 1},
+	{1500000000, 5000000000, 1, 1}
+};
+
+struct dsi_pll_div_table pll_4nm_cphy_lb[] = {
+	{30000000, 37500000, 4, 5},
+	{37500000, 50000000, 8, 2},
+	{50000000, 60000000, 4, 3},
+	{60000000, 75000000, 2, 5},
+	{75000000, 100000000, 8, 1},
+	{100000000, 120000000, 2, 3},
+	{120000000, 150000000, 1, 5},
+	{150000000, 200000000, 4, 1},
+	{200000000, 300000000, 1, 3},
+	{300000000, 600000000, 2, 1},
+	{600000000, 1500000000, 1, 1}
+};
+
+struct dsi_pll_div_table pll_4nm_cphy_hb[] = {
+	{75000000, 93750000, 4, 5},
+	{93750000, 12500000, 8, 2},
+	{125000000, 150000000, 4, 3},
+	{150000000, 187500000, 2, 5},
+	{187500000, 250000000, 8, 1},
+	{250000000, 300000000, 2, 3},
+	{300000000, 375000000, 1, 5},
+	{375000000, 500000000, 4, 1},
+	{500000000, 750000000, 1, 3},
+	{750000000, 1500000000, 2, 1},
+	{1500000000, 5000000000, 1, 1}
+};