diff --git a/msm/Kbuild b/msm/Kbuild index f08ab2863b..c2bab439a7 100644 --- a/msm/Kbuild +++ b/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 \ diff --git a/msm/dsi/dsi_catalog.c b/msm/dsi/dsi_catalog.c index 96f0615123..836bfddbe4 100644 --- a/msm/dsi/dsi_catalog.c +++ b/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 @@ -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; diff --git a/msm/dsi/dsi_catalog.h b/msm/dsi/dsi_catalog.h index 1e02beb50c..f878484f08 100644 --- a/msm/dsi/dsi_catalog.h +++ b/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); diff --git a/msm/dsi/dsi_phy_hw.h b/msm/dsi/dsi_phy_hw.h index 775381e23c..351f37b5a5 100644 --- a/msm/dsi/dsi_phy_hw.h +++ b/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 diff --git a/msm/dsi/dsi_phy_hw_v5_0.c b/msm/dsi/dsi_phy_hw_v5_0.c new file mode 100644 index 0000000000..3ce77bd8bb --- /dev/null +++ b/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 +#include +#include +#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 */ +} diff --git a/msm/dsi/dsi_pll.c b/msm/dsi/dsi_pll.c index 8483c85947..3a2e640dd1 100644 --- a/msm/dsi/dsi_pll.c +++ b/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; diff --git a/msm/dsi/dsi_pll.h b/msm/dsi/dsi_pll.h index 2d60c57b1b..77a307cbdd 100644 --- a/msm/dsi/dsi_pll.h +++ b/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); diff --git a/msm/dsi/dsi_pll_4nm.c b/msm/dsi/dsi_pll_4nm.c new file mode 100644 index 0000000000..adcf0a12c8 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#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; +} diff --git a/msm/dsi/dsi_pll_4nm.h b/msm/dsi/dsi_pll_4nm.h new file mode 100644 index 0000000000..052a28089d --- /dev/null +++ b/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} +};