diff --git a/msm/Makefile b/msm/Makefile index 9c7df05e71..fb0c7bfdf5 100644 --- a/msm/Makefile +++ b/msm/Makefile @@ -109,7 +109,6 @@ msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi_phy.o \ dsi/dsi_phy_timing_v4_0.o \ dsi/dsi_pll.o \ dsi/dsi_pll_5nm.o \ - dsi/dsi_pll_10nm.o \ dsi/dsi_ctrl_hw_cmn.o \ dsi/dsi_ctrl_hw_1_4.o \ dsi/dsi_ctrl_hw_2_0.o \ diff --git a/msm/dsi/dsi_catalog.c b/msm/dsi/dsi_catalog.c index 60880e663e..636f000c8c 100644 --- a/msm/dsi/dsi_catalog.c +++ b/msm/dsi/dsi_catalog.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #include @@ -343,3 +343,26 @@ int dsi_catalog_phy_setup(struct dsi_phy_hw *phy, return rc; } + +int dsi_catalog_phy_pll_setup(struct dsi_phy_hw *phy, u32 pll_ver) +{ + int rc = 0; + + if (pll_ver >= DSI_PLL_VERSION_UNKNOWN) { + DSI_ERR("Unsupported version: %d\n", pll_ver); + return -EOPNOTSUPP; + } + + switch (pll_ver) { + case DSI_PLL_VERSION_5NM: + phy->ops.configure = dsi_pll_5nm_configure; + phy->ops.pll_toggle = dsi_pll_5nm_toggle; + break; + default: + phy->ops.configure = NULL; + phy->ops.pll_toggle = NULL; + break; + } + + return rc; +} diff --git a/msm/dsi/dsi_catalog.h b/msm/dsi/dsi_catalog.h index 18214259ec..f76aae181e 100644 --- a/msm/dsi/dsi_catalog.h +++ b/msm/dsi/dsi_catalog.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_CATALOG_H_ @@ -284,4 +284,10 @@ void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl, void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *cfg); u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode); + +/* PLL specific functions */ +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); + #endif /* _DSI_CATALOG_H_ */ diff --git a/msm/dsi/dsi_clk.h b/msm/dsi/dsi_clk.h index e990ee047e..8a45460fd2 100644 --- a/msm/dsi/dsi_clk.h +++ b/msm/dsi/dsi_clk.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_CLK_H_ @@ -173,6 +173,25 @@ typedef int (*pre_clockon_cb)(void *priv, enum dsi_clk_state new_state); +/** + * typedef *phy_configure_cb() - Callback to configure PHY for PLL clocks + * @priv: private data pointer. + * @commit: boolean to specify if calculated PHY configuration needs to be + * committed. Set to false in case of dynamic clock switch. + * + * @return: error code. + */ +typedef int (*phy_configure_cb)(void *priv, bool commit); + +/** + * typedef *pll_toggle_cb() - Callback to toggle PHY PLL + * @priv: private data pointer. + * @prepare: specifies if the PLL needs to be turned on or off. + * + * @return: error code. + */ +typedef int (*pll_toggle_cb)(void *priv, bool prepare); + /** * struct dsi_clk_info - clock information for DSI hardware. * @name: client name. @@ -185,6 +204,8 @@ typedef int (*pre_clockon_cb)(void *priv, * @post_clkoff_cb callback after clock is turned off * @post_clkon_cb callback after clock is turned on * @pre_clkon_cb callback before clock is turned on + * @phy_config_cb callback to configure PHY PLL + * @phy_pll_toggle_cb callback to toggle PHY PLL state * @priv_data pointer to private data * @master_ndx master DSI controller index * @dsi_ctrl_count number of DSI controllers @@ -199,6 +220,8 @@ struct dsi_clk_info { post_clockoff_cb post_clkoff_cb; post_clockon_cb post_clkon_cb; pre_clockon_cb pre_clkon_cb; + phy_configure_cb phy_config_cb; + pll_toggle_cb phy_pll_toggle_cb; void *priv_data; u32 master_ndx; u32 dsi_ctrl_count; diff --git a/msm/dsi/dsi_clk_manager.c b/msm/dsi/dsi_clk_manager.c index b8b5bec682..2333f1bd1f 100644 --- a/msm/dsi/dsi_clk_manager.c +++ b/msm/dsi/dsi_clk_manager.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #include @@ -33,6 +33,8 @@ struct dsi_clk_mngr { u32 core_clk_state; u32 link_clk_state; + phy_configure_cb phy_config_cb; + pll_toggle_cb phy_pll_toggle_cb; pre_clockoff_cb pre_clkoff_cb; post_clockoff_cb post_clkoff_cb; post_clockon_cb post_clkon_cb; @@ -498,10 +500,6 @@ error: */ static int dsi_link_hs_clk_stop(struct dsi_link_hs_clk_info *link_hs_clks) { - struct dsi_link_clks *l_clks; - - l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); - dsi_link_hs_clk_disable(link_hs_clks); dsi_link_hs_clk_unprepare(link_hs_clks); @@ -616,6 +614,9 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, int rc = 0; int i; struct dsi_link_clks *clk, *m_clks; + struct dsi_clk_mngr *mngr; + + mngr = container_of(clks, struct dsi_clk_mngr, link_clks[master_ndx]); /* * In case of split DSI usecases, the clock for master controller should @@ -635,6 +636,10 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, } if (l_type & DSI_LINK_HS_CLK) { + if (!mngr->is_cont_splash_enabled) { + mngr->phy_config_cb(mngr->priv_data, true); + mngr->phy_pll_toggle_cb(mngr->priv_data, true); + } rc = dsi_link_hs_clk_start(&m_clks->hs_clks, DSI_LINK_CLK_START, master_ndx); if (rc) { @@ -724,6 +729,9 @@ static int dsi_display_link_clk_disable(struct dsi_link_clks *clks, int rc = 0; int i; struct dsi_link_clks *clk, *m_clks; + struct dsi_clk_mngr *mngr; + + mngr = container_of(clks, struct dsi_clk_mngr, link_clks[master_ndx]); /* * In case of split DSI usecases, clock for slave DSI controllers should @@ -767,6 +775,8 @@ static int dsi_display_link_clk_disable(struct dsi_link_clks *clks, if (rc) DSI_ERR("failed to turn off master hs link clocks, rc=%d\n", rc); + if (!mngr->is_cont_splash_enabled) + mngr->phy_pll_toggle_cb(mngr->priv_data, false); } return rc; @@ -1439,6 +1449,8 @@ void *dsi_display_clk_mngr_register(struct dsi_clk_info *info) mngr->post_clkon_cb = info->post_clkon_cb; mngr->pre_clkoff_cb = info->pre_clkoff_cb; mngr->post_clkoff_cb = info->post_clkoff_cb; + mngr->phy_config_cb = info->phy_config_cb; + mngr->phy_pll_toggle_cb = info->phy_pll_toggle_cb; mngr->priv_data = info->priv_data; memcpy(mngr->name, info->name, MAX_STRING_LEN); diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 9f424781b7..72bab7b38e 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_DEFS_H_ @@ -739,6 +739,23 @@ static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt) return 24; } +/* return number of DSI data lanes */ +static inline int dsi_get_num_of_data_lanes(enum dsi_data_lanes dlanes) +{ + int num_of_lanes = 0; + + if (dlanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (dlanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (dlanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (dlanes & DSI_DATA_LANE_3) + num_of_lanes++; + + return num_of_lanes; +} + static inline u64 dsi_h_active_dce(struct dsi_mode_info *mode) { u64 h_active = 0; diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 746c039974..1b3daab468 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #include @@ -2608,26 +2608,68 @@ error: return rc; } +int dsi_display_phy_pll_toggle(void *priv, bool prepare) +{ + int rc = 0; + struct dsi_display *display = priv; + struct dsi_display_ctrl *m_ctrl; + + if (!display) { + DSI_ERR("invalid arguments\n"); + return -EINVAL; + } + + m_ctrl = &display->ctrl[display->clk_master_idx]; + if (!m_ctrl->phy) { + DSI_ERR("[%s] PHY not found\n", display->name); + return -EINVAL; + } + + rc = dsi_phy_pll_toggle(m_ctrl->phy, prepare); + + return rc; +} + +int dsi_display_phy_configure(void *priv, bool commit) +{ + int rc = 0; + struct dsi_display *display = priv; + struct dsi_display_ctrl *m_ctrl; + struct dsi_pll_resource *pll_res; + struct dsi_ctrl *ctrl; + + if (!display) { + DSI_ERR("invalid arguments\n"); + return -EINVAL; + } + + m_ctrl = &display->ctrl[display->clk_master_idx]; + if ((!m_ctrl->phy) || (!m_ctrl->ctrl)) { + DSI_ERR("[%s] PHY not found\n", display->name); + return -EINVAL; + } + + pll_res = m_ctrl->phy->pll; + if (!pll_res) { + DSI_ERR("[%s] PLL res not found\n", display->name); + return -EINVAL; + } + + ctrl = m_ctrl->ctrl; + pll_res->byteclk_rate = ctrl->clk_freq.byte_clk_rate; + pll_res->pclk_rate = ctrl->clk_freq.pix_clk_rate; + + rc = dsi_phy_configure(m_ctrl->phy, commit); + + return rc; +} + static int dsi_display_set_clk_src(struct dsi_display *display) { int rc = 0; int i; struct dsi_display_ctrl *m_ctrl, *ctrl; - /* - * For CPHY mode, the parent of mux_clks need to be set - * to Cphy_clks to have correct dividers for byte and - * pixel clocks. - */ - if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) { - rc = dsi_clk_update_parent(&display->clock_info.cphy_clks, - &display->clock_info.mux_clks); - if (rc) { - DSI_ERR("failed update mux parent to shadow\n"); - return rc; - } - } - /* * In case of split DSI usecases, the clock for master controller should * be enabled before the other controller. Master controller in the @@ -2636,7 +2678,7 @@ static int dsi_display_set_clk_src(struct dsi_display *display) m_ctrl = &display->ctrl[display->clk_master_idx]; rc = dsi_ctrl_set_clock_source(m_ctrl->ctrl, - &display->clock_info.mux_clks); + &display->clock_info.pll_clks); if (rc) { DSI_ERR("[%s] failed to set source clocks for master, rc=%d\n", display->name, rc); @@ -2650,7 +2692,7 @@ static int dsi_display_set_clk_src(struct dsi_display *display) continue; rc = dsi_ctrl_set_clock_source(ctrl->ctrl, - &display->clock_info.mux_clks); + &display->clock_info.pll_clks); if (rc) { DSI_ERR("[%s] failed to set source clocks, rc=%d\n", display->name, rc); @@ -3320,46 +3362,6 @@ static int dsi_display_mipi_host_deinit(struct dsi_display *display) return rc; } -static int dsi_display_clocks_deinit(struct dsi_display *display) -{ - int rc = 0; - struct dsi_clk_link_set *src = &display->clock_info.src_clks; - struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; - struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks; - - if (src->byte_clk) { - devm_clk_put(&display->pdev->dev, src->byte_clk); - src->byte_clk = NULL; - } - - if (src->pixel_clk) { - devm_clk_put(&display->pdev->dev, src->pixel_clk); - src->pixel_clk = NULL; - } - - if (mux->byte_clk) { - devm_clk_put(&display->pdev->dev, mux->byte_clk); - mux->byte_clk = NULL; - } - - if (mux->pixel_clk) { - devm_clk_put(&display->pdev->dev, mux->pixel_clk); - mux->pixel_clk = NULL; - } - - if (shadow->byte_clk) { - devm_clk_put(&display->pdev->dev, shadow->byte_clk); - shadow->byte_clk = NULL; - } - - if (shadow->pixel_clk) { - devm_clk_put(&display->pdev->dev, shadow->pixel_clk); - shadow->pixel_clk = NULL; - } - - return rc; -} - static bool dsi_display_check_prefix(const char *clk_prefix, const char *clk_name) { @@ -3393,20 +3395,9 @@ static int dsi_display_clocks_init(struct dsi_display *display) { int i, rc = 0, num_clk = 0; const char *clk_name; - const char *src_byte = "src_byte", *src_pixel = "src_pixel"; - const char *mux_byte = "mux_byte", *mux_pixel = "mux_pixel"; - const char *cphy_byte = "cphy_byte", *cphy_pixel = "cphy_pixel"; - const char *shadow_byte = "shadow_byte", *shadow_pixel = "shadow_pixel"; - const char *shadow_cphybyte = "shadow_cphybyte", - *shadow_cphypixel = "shadow_cphypixel"; + const char *pll_byte = "pll_byte", *pll_dsi = "pll_dsi"; struct clk *dsi_clk; - struct dsi_clk_link_set *src = &display->clock_info.src_clks; - struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; - struct dsi_clk_link_set *cphy = &display->clock_info.cphy_clks; - struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks; - struct dsi_clk_link_set *shadow_cphy = - &display->clock_info.shadow_cphy_clks; - struct dsi_dyn_clk_caps *dyn_clk_caps = &(display->panel->dyn_clk_caps); + struct dsi_clk_link_set *pll = &display->clock_info.pll_clks; char *dsi_clock_name; if (!strcmp(display->display_type, "primary")) @@ -3416,8 +3407,6 @@ static int dsi_display_clocks_init(struct dsi_display *display) num_clk = dsi_display_get_clocks_count(display, dsi_clock_name); - DSI_DEBUG("clk count=%d\n", num_clk); - for (i = 0; i < num_clk; i++) { dsi_display_get_clock_name(display, dsi_clock_name, i, &clk_name); @@ -3430,105 +3419,30 @@ static int dsi_display_clocks_init(struct dsi_display *display) DSI_ERR("failed to get %s, rc=%d\n", clk_name, rc); - if (dsi_display_check_prefix(mux_byte, clk_name)) { - mux->byte_clk = NULL; - goto error; - } - if (dsi_display_check_prefix(mux_pixel, clk_name)) { - mux->pixel_clk = NULL; + if (dsi_display_check_prefix(pll_byte, clk_name)) { + pll->byte_clk = NULL; goto error; } - if (dsi_display_check_prefix(cphy_byte, clk_name)) { - cphy->byte_clk = NULL; + if (dsi_display_check_prefix(pll_dsi, clk_name)) { + pll->pixel_clk = NULL; goto error; } - if (dsi_display_check_prefix(cphy_pixel, clk_name)) { - cphy->pixel_clk = NULL; - goto error; - } - - if (dyn_clk_caps->dyn_clk_support && - (display->panel->panel_mode == - DSI_OP_VIDEO_MODE)) { - - if (dsi_display_check_prefix(src_byte, - clk_name)) - src->byte_clk = NULL; - if (dsi_display_check_prefix(src_pixel, - clk_name)) - src->pixel_clk = NULL; - if (dsi_display_check_prefix(shadow_byte, - clk_name)) - shadow->byte_clk = NULL; - if (dsi_display_check_prefix(shadow_pixel, - clk_name)) - shadow->pixel_clk = NULL; - if (dsi_display_check_prefix(shadow_cphybyte, - clk_name)) - shadow_cphy->byte_clk = NULL; - if (dsi_display_check_prefix(shadow_cphypixel, - clk_name)) - shadow_cphy->pixel_clk = NULL; - - dyn_clk_caps->dyn_clk_support = false; - } } - if (dsi_display_check_prefix(src_byte, clk_name)) { - src->byte_clk = dsi_clk; + if (dsi_display_check_prefix(pll_byte, clk_name)) { + pll->byte_clk = dsi_clk; + continue; + } + if (dsi_display_check_prefix(pll_dsi, clk_name)) { + pll->pixel_clk = dsi_clk; continue; } - if (dsi_display_check_prefix(src_pixel, clk_name)) { - src->pixel_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(cphy_byte, clk_name)) { - cphy->byte_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(cphy_pixel, clk_name)) { - cphy->pixel_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(mux_byte, clk_name)) { - mux->byte_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(mux_pixel, clk_name)) { - mux->pixel_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(shadow_byte, clk_name)) { - shadow->byte_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(shadow_pixel, clk_name)) { - shadow->pixel_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(shadow_cphybyte, clk_name)) { - shadow_cphy->byte_clk = dsi_clk; - continue; - } - - if (dsi_display_check_prefix(shadow_cphypixel, clk_name)) { - shadow_cphy->pixel_clk = dsi_clk; - continue; - } } return 0; error: - (void)dsi_display_clocks_deinit(display); return rc; } @@ -4168,10 +4082,6 @@ static int dsi_display_res_deinit(struct dsi_display *display) int i; struct dsi_display_ctrl *ctrl; - rc = dsi_display_clocks_deinit(display); - if (rc) - DSI_ERR("clocks deinit failed, rc=%d\n", rc); - display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; dsi_phy_put(ctrl->phy); @@ -4506,28 +4416,17 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display, u8 ctrl_version; struct dsi_display_ctrl *m_ctrl, *ctrl; struct dsi_dyn_clk_caps *dyn_clk_caps; - struct dsi_clk_link_set *parent_clk, *enable_clk; + struct dsi_clk_link_set *enable_clk; m_ctrl = &display->ctrl[display->clk_master_idx]; dyn_clk_caps = &(display->panel->dyn_clk_caps); ctrl_version = m_ctrl->ctrl->version; - if (dsi_display_is_type_cphy(display)) { - enable_clk = &display->clock_info.cphy_clks; - parent_clk = &display->clock_info.shadow_cphy_clks; - } else { - enable_clk = &display->clock_info.src_clks; - parent_clk = &display->clock_info.shadow_clks; - } + enable_clk = &display->clock_info.pll_clks; dsi_clk_prepare_enable(enable_clk); - rc = dsi_clk_update_parent(parent_clk, - &display->clock_info.mux_clks); - if (rc) { - DSI_ERR("failed to update mux parent\n"); - goto exit; - } + dsi_display_phy_configure(display, false); display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; @@ -4584,8 +4483,6 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display, } defer_dfps_wait: - rc = dsi_clk_update_parent(enable_clk, - &display->clock_info.mux_clks); if (rc) DSI_ERR("could not switch back to src clks %d\n", rc); @@ -4612,9 +4509,6 @@ recover_byte_clk: bkp_freq->byte_intf_clk_rate, i); } -exit: - dsi_clk_disable_unprepare(&display->clock_info.src_clks); - return rc; } @@ -5526,6 +5420,8 @@ static int dsi_display_bind(struct device *dev, info.pre_clkon_cb = dsi_pre_clkon_cb; info.post_clkoff_cb = dsi_post_clkoff_cb; info.post_clkon_cb = dsi_post_clkon_cb; + info.phy_config_cb = dsi_display_phy_configure; + info.phy_pll_toggle_cb = dsi_display_phy_pll_toggle; info.priv_data = display; info.master_ndx = display->clk_master_idx; info.dsi_ctrl_count = display->ctrl_count; diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index f829ac8d91..cce1500ed4 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_DISPLAY_H_ @@ -104,17 +104,10 @@ struct dsi_display_boot_param { /** * struct dsi_display_clk_info - dsi display clock source information - * @src_clks: Source clocks for DSI display. - * @mux_clks: Mux clocks used for DFPS. - * @shadow_clks: Used for D-phy clock switch. - * @shadow_cphy_clks: Used for C-phy clock switch. + * @pll_clks: PLL clocks for DSI. */ struct dsi_display_clk_info { - struct dsi_clk_link_set src_clks; - struct dsi_clk_link_set mux_clks; - struct dsi_clk_link_set cphy_clks; - struct dsi_clk_link_set shadow_clks; - struct dsi_clk_link_set shadow_cphy_clks; + struct dsi_clk_link_set pll_clks; }; /** diff --git a/msm/dsi/dsi_phy.c b/msm/dsi/dsi_phy.c index 952618133b..4eb372d81c 100644 --- a/msm/dsi/dsi_phy.c +++ b/msm/dsi/dsi_phy.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #include @@ -461,6 +461,14 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) goto fail_settings; } + rc = dsi_catalog_phy_pll_setup(&dsi_phy->hw, + dsi_phy->pll->pll_revision); + if (rc) { + DSI_PHY_ERR(dsi_phy, "Catalog does not support PLL version (%d)\n", + dsi_phy->pll->pll_revision); + goto fail_settings; + } + item->phy = dsi_phy; mutex_lock(&dsi_phy_list_lock); @@ -760,6 +768,45 @@ error: return rc; } +/** + * dsi_phy_configure() - Configure DSI PHY PLL + * @dsi_phy: DSI PHY handle. + * @commit: boolean to specify if calculated PHY configuration + * needs to be committed. Set to false in case of + * dynamic clock switch. + * + * Return: error code. + */ +int dsi_phy_configure(struct msm_dsi_phy *phy, bool commit) +{ + int rc = 0; + + phy->pll->type = phy->cfg.phy_type; + phy->pll->bpp = dsi_pixel_format_to_bpp(phy->dst_format); + phy->pll->lanes = dsi_get_num_of_data_lanes(phy->data_lanes); + if (phy->hw.ops.configure) + rc = phy->hw.ops.configure(phy->pll, commit); + + return rc; +} + +/** + * dsi_phy_pll_toggle() - Toggle DSI PHY PLL + * @dsi_phy: DSI PHY handle. + * @prepare: specifies if PLL needs to be turned on or not. + * + * Return: error code. + */ +int dsi_phy_pll_toggle(struct msm_dsi_phy *phy, bool prepare) +{ + int rc = 0; + + if (phy->hw.ops.pll_toggle) + rc = phy->hw.ops.pll_toggle(phy->pll, prepare); + + return rc; +} + static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config, bool clamp_enabled) { diff --git a/msm/dsi/dsi_phy.h b/msm/dsi/dsi_phy.h index 7fe7c060c8..8e36c70dd4 100644 --- a/msm/dsi/dsi_phy.h +++ b/msm/dsi/dsi_phy.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_PHY_H_ @@ -356,9 +356,9 @@ void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy); * @dst: Pointer to cache location. * @size: Number of phy lane settings. */ -int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy, +int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy, u32 *dst, + u32 size); - u32 *dst, u32 size); /** * dsi_phy_set_continuous_clk() - API to set/unset force clock lane HS request. * @phy: DSI PHY Handle. @@ -375,4 +375,31 @@ void dsi_phy_set_continuous_clk(struct msm_dsi_phy *phy, bool enable); */ int dsi_phy_get_io_resources(struct msm_io_res *io_res); +/** + * dsi_phy_configure() - Configure DSI PHY PLL + * @dsi_phy: DSI PHY handle. + * @commit: boolean to specify if calculated PHY configuration + * needs to be committed. Set to false in case of + * dynamic clock switch. + * + * Return: error code. + */ +int dsi_phy_configure(struct msm_dsi_phy *dsi_phy, bool commit); + +/** + * dsi_phy_pll_toggle() - Toggle DSI PHY PLL + * @dsi_phy: DSI PHY handle. + * @prepare: specifies if PLL needs to be turned on or not. + * + * Return: error code. + */ +int dsi_phy_pll_toggle(struct msm_dsi_phy *dsi_phy, bool prepare); + +/** + * dsi_phy_dynclk_configure() - Configure DSI PHY PLL during dynamic clock + * @dsi_phy: DSI PHY handle. + * + * Return: error code. + */ +int dsi_phy_dynclk_configure(struct msm_dsi_phy *phy); #endif /* _DSI_PHY_H_ */ diff --git a/msm/dsi/dsi_phy_hw.h b/msm/dsi/dsi_phy_hw.h index 62e9e01254..fd27dd42b6 100644 --- a/msm/dsi/dsi_phy_hw.h +++ b/msm/dsi/dsi_phy_hw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_PHY_HW_H_ @@ -47,6 +47,18 @@ enum dsi_phy_version { DSI_PHY_VERSION_MAX }; +/** + * enum dsi_pll_version - DSI PHY PLL version enumeration + * @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_5NM, + DSI_PLL_VERSION_10NM, + DSI_PLL_VERSION_UNKNOWN +}; + /** * enum dsi_phy_hw_features - features supported by DSI PHY hardware * @DSI_PHY_DPHY: Supports DPHY @@ -344,6 +356,23 @@ struct dsi_phy_hw_ops { void *timing_ops; struct phy_ulps_config_ops ulps_ops; struct phy_dyn_refresh_ops dyn_refresh_ops; + + /** + * configure() - Configure the DSI PHY PLL + * @pll: Pointer to DSI PLL. + * @commit: boolean to specify if calculated PHY configuration + needs to be committed. Set to false in case of + dynamic clock switch. + */ + int (*configure)(void *pll, bool commit); + + /** + * pll_toggle() - Toggle the DSI PHY PLL + * @pll: Pointer to DSI PLL. + * @prepare: specify if PLL needs to be turned on or off. + */ + int (*pll_toggle)(void *pll, bool prepare); + }; /** diff --git a/msm/dsi/dsi_pll.c b/msm/dsi/dsi_pll.c index ce5d1cf3e2..3f8c927f8e 100644 --- a/msm/dsi/dsi_pll.c +++ b/msm/dsi/dsi_pll.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -23,9 +23,6 @@ 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_10NM: - rc = dsi_pll_clock_register_10nm(pdev, pll_res); - break; default: rc = -EINVAL; break; @@ -144,14 +141,12 @@ 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 and 10nm PLL version. Will add + * Currently, Only supports 5nm. Will add * support for other versions as needed. */ if (!strcmp(label, "dsi_pll_5nm")) pll_res->pll_revision = DSI_PLL_5NM; - else if (!strcmp(label, "dsi_pll_10nm")) - pll_res->pll_revision = DSI_PLL_10NM; else return -ENOTSUPP; diff --git a/msm/dsi/dsi_pll.h b/msm/dsi/dsi_pll.h index 386fe6a931..351790305d 100644 --- a/msm/dsi/dsi_pll.h +++ b/msm/dsi/dsi_pll.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef __DSI_PLL_H @@ -87,20 +87,11 @@ struct dsi_pll_resource { void __iomem *dyn_pll_base; s64 vco_current_rate; - s64 vco_locking_rate; s64 vco_ref_clk_rate; - - /* - * Certain pll's needs to update the same vco rate after resume in - * suspend/resume scenario. Cached the vco rate for such plls. - */ - unsigned long vco_cached_rate; - u32 cached_cfg0; - u32 cached_cfg1; - u32 cached_outdiv; - - u32 cached_postdiv1; - u32 cached_postdiv3; + s64 vco_min_rate; + s64 vco_rate; + s64 byteclk_rate; + s64 pclk_rate; u32 pll_revision; @@ -115,24 +106,11 @@ struct dsi_pll_resource { */ bool pll_on; - /* - * handoff_status is true of pll is already enabled by bootloader with - * continuous splash enable case. Clock API will call the handoff API - * to enable the status. It is disabled if continuous splash - * feature is disabled. - */ - bool handoff_resources; - /* * caching the pll trim codes in the case of dynamic refresh */ int cache_pll_trim_codes[3]; - /* - * for maintaining the status of saving trim codes - */ - bool reg_upd; - /* * PLL index if multiple index are available. Eg. in case of @@ -147,11 +125,6 @@ struct dsi_pll_resource { struct dsi_pll_resource *slave; - /* - * target pll revision information - */ - int revision; - void *priv; /* @@ -160,24 +133,20 @@ struct dsi_pll_resource { struct dfps_info *dfps; /* - * for cases where dfps trigger happens before first - * suspend/resume and handoff is not finished. + * DSI pixel depth and lane information */ - bool dfps_trigger; + int bpp; + int lanes; + + /* + * DSI PHY type DPHY/CPHY + */ + enum dsi_phy_type type; }; -struct dsi_pll_vco_clk { - struct clk_hw hw; - unsigned long ref_clk_rate; - u64 min_rate; - u64 max_rate; - u32 pll_en_seq_cnt; - struct lpfr_cfg *lpfr_lut; - u32 lpfr_lut_size; - void *priv; - - int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS]) - (struct dsi_pll_resource *pll_res); +struct dsi_pll_clk { + struct clk_hw hw; + void *priv; }; struct dsi_pll_vco_calc { @@ -191,47 +160,21 @@ struct dsi_pll_vco_calc { s64 pll_plllock_cmp3; }; -static inline bool is_gdsc_disabled(struct dsi_pll_resource *pll_res) -{ - if (!pll_res->gdsc_base) { - WARN(1, "gdsc_base register is not defined\n"); - return true; - } - return readl_relaxed(pll_res->gdsc_base) & BIT(31) ? false : true; -} +struct dsi_pll_div_table { + u32 min_hz; + u32 max_hz; + int pll_div; + int phy_div; +}; -static inline int dsi_pll_div_prepare(struct clk_hw *hw) +static inline struct dsi_pll_clk *to_pll_clk_hw(struct clk_hw *hw) { - struct clk_hw *parent_hw = clk_hw_get_parent(hw); - /* Restore the divider's value */ - return hw->init->ops->set_rate(hw, clk_hw_get_rate(hw), - clk_hw_get_rate(parent_hw)); -} - -static inline int dsi_set_mux_sel(void *context, unsigned int reg, - unsigned int val) -{ - return 0; -} - -static inline int dsi_get_mux_sel(void *context, unsigned int reg, - unsigned int *val) -{ - *val = 0; - return 0; -} - -static inline struct dsi_pll_vco_clk *to_vco_clk_hw(struct clk_hw *hw) -{ - return container_of(hw, struct dsi_pll_vco_clk, hw); + return container_of(hw, struct dsi_pll_clk, hw); } int dsi_pll_clock_register_5nm(struct platform_device *pdev, struct dsi_pll_resource *pll_res); -int dsi_pll_clock_register_10nm(struct platform_device *pdev, - struct dsi_pll_resource *pll_res); - int dsi_pll_init(struct platform_device *pdev, struct dsi_pll_resource **pll_res); #endif diff --git a/msm/dsi/dsi_pll_10nm.c b/msm/dsi/dsi_pll_10nm.c deleted file mode 100644 index cf641943f4..0000000000 --- a/msm/dsi/dsi_pll_10nm.c +++ /dev/null @@ -1,2074 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. - */ - -#define pr_fmt(fmt) "%s: " fmt, __func__ - -#include -#include -#include -#include -#include "dsi_pll.h" -#include - -#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 - -/* Register Offsets from PLL base address */ -#define PLL_ANALOG_CONTROLS_ONE 0x000 -#define PLL_ANALOG_CONTROLS_TWO 0x004 -#define PLL_INT_LOOP_SETTINGS 0x008 -#define PLL_INT_LOOP_SETTINGS_TWO 0x00c -#define PLL_ANALOG_CONTROLS_THREE 0x010 -#define PLL_ANALOG_CONTROLS_FOUR 0x014 -#define PLL_INT_LOOP_CONTROLS 0x018 -#define PLL_DSM_DIVIDER 0x01c -#define PLL_FEEDBACK_DIVIDER 0x020 -#define PLL_SYSTEM_MUXES 0x024 -#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x028 -#define PLL_CMODE 0x02c -#define PLL_CALIBRATION_SETTINGS 0x030 -#define PLL_BAND_SEL_CAL_TIMER_LOW 0x034 -#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x038 -#define PLL_BAND_SEL_CAL_SETTINGS 0x03c -#define PLL_BAND_SEL_MIN 0x040 -#define PLL_BAND_SEL_MAX 0x044 -#define PLL_BAND_SEL_PFILT 0x048 -#define PLL_BAND_SEL_IFILT 0x04c -#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x050 -#define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054 -#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x058 -#define PLL_BAND_SEL_ICODE_HIGH 0x05c -#define PLL_BAND_SEL_ICODE_LOW 0x060 -#define PLL_FREQ_DETECT_SETTINGS_ONE 0x064 -#define PLL_PFILT 0x07c -#define PLL_IFILT 0x080 -#define PLL_GAIN 0x084 -#define PLL_ICODE_LOW 0x088 -#define PLL_ICODE_HIGH 0x08c -#define PLL_LOCKDET 0x090 -#define PLL_OUTDIV 0x094 -#define PLL_FASTLOCK_CONTROL 0x098 -#define PLL_PASS_OUT_OVERRIDE_ONE 0x09c -#define PLL_PASS_OUT_OVERRIDE_TWO 0x0a0 -#define PLL_CORE_OVERRIDE 0x0a4 -#define PLL_CORE_INPUT_OVERRIDE 0x0a8 -#define PLL_RATE_CHANGE 0x0ac -#define PLL_PLL_DIGITAL_TIMERS 0x0b0 -#define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4 -#define PLL_DEC_FRAC_MUXES 0x0c8 -#define PLL_DECIMAL_DIV_START_1 0x0cc -#define PLL_FRAC_DIV_START_LOW_1 0x0d0 -#define PLL_FRAC_DIV_START_MID_1 0x0d4 -#define PLL_FRAC_DIV_START_HIGH_1 0x0d8 -#define PLL_MASH_CONTROL 0x0ec -#define PLL_SSC_MUX_CONTROL 0x108 -#define PLL_SSC_STEPSIZE_LOW_1 0x10c -#define PLL_SSC_STEPSIZE_HIGH_1 0x110 -#define PLL_SSC_DIV_PER_LOW_1 0x114 -#define PLL_SSC_DIV_PER_HIGH_1 0x118 -#define PLL_SSC_DIV_ADJPER_LOW_1 0x11c -#define PLL_SSC_DIV_ADJPER_HIGH_1 0x120 -#define PLL_SSC_CONTROL 0x13c -#define PLL_PLL_OUTDIV_RATE 0x140 -#define PLL_PLL_LOCKDET_RATE_1 0x144 -#define PLL_PLL_PROP_GAIN_RATE_1 0x14c -#define PLL_PLL_BAND_SET_RATE_1 0x154 -#define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c -#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164 -#define PLL_FASTLOCK_EN_BAND 0x16c -#define PLL_FREQ_TUNE_ACCUM_INIT_LOW 0x170 -#define PLL_FREQ_TUNE_ACCUM_INIT_MID 0x174 -#define PLL_FREQ_TUNE_ACCUM_INIT_HIGH 0x178 -#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c -#define PLL_PLL_LOCK_OVERRIDE 0x180 -#define PLL_PLL_LOCK_DELAY 0x184 -#define PLL_PLL_LOCK_MIN_DELAY 0x188 -#define PLL_CLOCK_INVERTERS 0x18c -#define PLL_SPARE_AND_JPC_OVERRIDES 0x190 -#define PLL_BIAS_CONTROL_1 0x194 -#define PLL_BIAS_CONTROL_2 0x198 -#define PLL_ALOG_OBSV_BUS_CTRL_1 0x19c -#define PLL_COMMON_STATUS_ONE 0x1a0 - -/* Register Offsets from PHY base address */ -#define PHY_CMN_CLK_CFG0 0x010 -#define PHY_CMN_CLK_CFG1 0x014 -#define PHY_CMN_RBUF_CTRL 0x01c -#define PHY_CMN_PLL_CNTRL 0x038 -#define PHY_CMN_CTRL_0 0x024 -#define PHY_CMN_CTRL_2 0x02c - -/* 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 (0x600) -enum { - DSI_PLL_0, - DSI_PLL_1, - DSI_PLL_MAX -}; - -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_10nm { - struct dsi_pll_resource *rsc; - struct dsi_pll_config pll_configuration; - struct dsi_pll_regs reg_setup; -}; - -static inline int pll_reg_read(void *context, unsigned int reg, - unsigned int *val) -{ - int rc = 0; - u32 data; - struct dsi_pll_resource *rsc = context; - - 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)); - ndelay(250); - *val = DSI_PLL_REG_R(rsc->pll_base, reg); - - DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data); - - return rc; -} - -static inline int pll_reg_write(void *context, unsigned int reg, - unsigned int val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - DSI_PLL_REG_W(rsc->pll_base, reg, val); - - return rc; -} - -static inline int phy_reg_read(void *context, unsigned int reg, - unsigned int *val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - *val = DSI_PLL_REG_R(rsc->phy_base, reg); - - return rc; -} - -static inline int phy_reg_write(void *context, unsigned int reg, - unsigned int val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - DSI_PLL_REG_W(rsc->phy_base, reg, val); - - return rc; -} - -static inline int phy_reg_update_bits_sub(struct dsi_pll_resource *rsc, - unsigned int reg, unsigned int mask, unsigned int val) -{ - u32 reg_val; - - reg_val = DSI_PLL_REG_R(rsc->phy_base, reg); - reg_val &= ~mask; - reg_val |= (val & mask); - DSI_PLL_REG_W(rsc->phy_base, reg, reg_val); - - return 0; -} - -static inline int phy_reg_update_bits(void *context, unsigned int reg, - unsigned int mask, unsigned int val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - rc = phy_reg_update_bits_sub(rsc, reg, mask, val); - if (!rc && rsc->slave) - rc = phy_reg_update_bits_sub(rsc->slave, reg, mask, val); - - return rc; -} - -static inline int pclk_mux_read_sel(void *context, unsigned int reg, - unsigned int *val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - *val = (DSI_PLL_REG_R(rsc->phy_base, reg) & 0x3); - - return rc; -} - -static inline int pclk_mux_write_sel_sub(struct dsi_pll_resource *rsc, - unsigned int reg, unsigned int val) -{ - u32 reg_val; - - reg_val = DSI_PLL_REG_R(rsc->phy_base, reg); - reg_val &= ~0x03; - reg_val |= val; - - DSI_PLL_REG_W(rsc->phy_base, reg, reg_val); - - return 0; -} - -static inline int pclk_mux_write_sel(void *context, unsigned int reg, - unsigned int val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - rc = pclk_mux_write_sel_sub(rsc, reg, val); - if (!rc && rsc->slave) - rc = pclk_mux_write_sel_sub(rsc->slave, reg, val); - - /* - * cache the current parent index for cases where parent - * is not changing but rate is changing. In that case - * clock framework won't call parent_set and hence dsiclk_sel - * bit won't be programmed. e.g. dfps update use case. - */ - rsc->cached_cfg1 = val; - - return rc; -} - -static int dsi_pll_10nm_get_gdsc_status(struct dsi_pll_resource *rsc) -{ - u32 reg = 0; - bool status; - - reg = DSI_PLL_REG_R(rsc->gdsc_base, 0x0); - status = reg & BIT(31); - pr_err("reg:0x%x status:%d\n", reg, status); - - return status; -} - -static struct dsi_pll_resource *pll_rsc_db[DSI_PLL_MAX]; -static struct dsi_pll_10nm 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) { - pr_debug("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 */ - - pr_debug("Slave PLL %s\n", rsc->slave ? "configured" : "absent"); -} - -static void dsi_pll_setup_config(struct dsi_pll_10nm *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 = 5000; - 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; - } - - dsi_pll_config_slave(rsc); -} - -static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *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 <= MHZ_1900) - regs->pll_prop_gain_rate = 8; - else if (pll_freq <= MHZ_3000) - regs->pll_prop_gain_rate = 10; - else - regs->pll_prop_gain_rate = 12; - if (pll_freq < MHZ_1100) - regs->pll_clock_inverters = 8; - else - regs->pll_clock_inverters = 0; - - 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; -} - -static void dsi_pll_calc_ssc(struct dsi_pll_10nm *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) { - pr_debug("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; - - pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", - regs->decimal_div_start, frac, config->frac_bits); - pr_debug("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_10nm *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) { - pr_debug("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_DIV_ADJPER_LOW_1, - regs->ssc_adjper_low); - DSI_PLL_REG_W(pll_base, PLL_SSC_DIV_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_10nm *pll, - struct dsi_pll_resource *rsc) -{ - void __iomem *pll_base = rsc->pll_base; - - DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_ONE, 0x80); - 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, 0x08); - DSI_PLL_REG_W(pll_base, PLL_PLL_BAND_SET_RATE_1, 0xc0); - DSI_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); - 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_IFILT, 0x3f); -} - -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_CORE_INPUT_OVERRIDE, 0x10); - DSI_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f); - DSI_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0); - DSI_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0); - DSI_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80); - DSI_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a); - DSI_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0); - DSI_PLL_REG_W(pll_base, PLL_GAIN, 0x42); - DSI_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00); - DSI_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00); - DSI_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30); - DSI_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04); - DSI_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00); - DSI_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00); - DSI_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01); - DSI_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08); - DSI_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00); - DSI_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03); - DSI_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0); - DSI_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0); - DSI_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03); - DSI_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0); - DSI_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19); - DSI_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0); - DSI_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40); - DSI_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20); - DSI_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0); -} - -static void dsi_pll_commit(struct dsi_pll_10nm *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, 0x40); - DSI_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06); - DSI_PLL_REG_W(pll_base, PLL_CMODE, 0x10); - DSI_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters); - -} - -static int vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *rsc = vco->priv; - struct dsi_pll_10nm *pll; - - if (!rsc) { - pr_err("pll resource not found\n"); - return -EINVAL; - } - - if (rsc->pll_on) - return 0; - - pll = rsc->priv; - if (!pll) { - pr_err("pll configuration not found\n"); - return -EINVAL; - } - - pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); - - rsc->vco_current_rate = rate; - rsc->vco_ref_clk_rate = vco->ref_clk_rate; - rsc->dfps_trigger = false; - - dsi_pll_init_val(rsc); - - dsi_pll_setup_config(pll, rsc); - - dsi_pll_calc_dec_frac(pll, rsc); - - dsi_pll_calc_ssc(pll, rsc); - - dsi_pll_commit(pll, rsc); - - dsi_pll_config_hzindep_reg(pll, rsc); - - dsi_pll_ssc_commit(pll, rsc); - - /* 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]; - - pr_debug("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; - - pr_debug("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 shadow_dsi_pll_dynamic_refresh_10nm(struct dsi_pll_10nm *pll, - struct dsi_pll_resource *rsc) -{ - u32 data; - u32 offset = DSI_PHY_TO_PLL_OFFSET; - u32 upper_addr = 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_DECIMAL_DIV_START_1 + offset), - 0, reg->decimal_div_start); - upper_addr |= (upper_8_bit(PHY_CMN_RBUF_CTRL) << 2); - upper_addr |= (upper_8_bit(PLL_DECIMAL_DIV_START_1 + offset) << 3); - - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL2, - (PLL_FRAC_DIV_START_LOW_1 + offset), - (PLL_FRAC_DIV_START_MID_1 + offset), - reg->frac_div_start_low, reg->frac_div_start_mid); - upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_LOW_1 + offset) << 4); - upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_MID_1 + offset) << 5); - - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL3, - (PLL_FRAC_DIV_START_HIGH_1 + offset), - (PLL_PLL_PROP_GAIN_RATE_1 + offset), - reg->frac_div_start_high, reg->pll_prop_gain_rate); - upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_HIGH_1 + offset) << 6); - upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 7); - - 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_CTRL4, - (PLL_PLL_OUTDIV_RATE + offset), - (PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset), - data, 0); - upper_addr |= (upper_8_bit(PLL_PLL_OUTDIV_RATE + offset) << 8); - upper_addr |= (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset) << 9); - - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL5, - (PLL_FREQ_TUNE_ACCUM_INIT_MID + offset), - (PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset), - rsc->cache_pll_trim_codes[1], - rsc->cache_pll_trim_codes[0]); - upper_addr |= - (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MID + offset) << 10); - upper_addr |= - (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset) << 11); - - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL6, - (PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset), - (PLL_PLL_BAND_SET_RATE_1 + offset), - 0x07, rsc->cache_pll_trim_codes[2]); - upper_addr |= - (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset) << 12); - upper_addr |= (upper_8_bit(PLL_PLL_BAND_SET_RATE_1 + offset) << 13); - - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL7, - (PLL_CALIBRATION_SETTINGS + offset), - (PLL_BAND_SEL_CAL_SETTINGS + offset), 0x44, 0x3a); - upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 14); - upper_addr |= (upper_8_bit(PLL_BAND_SEL_CAL_SETTINGS + offset) << 15); - - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL8, - (PLL_PLL_LOCKDET_RATE_1 + offset), - (PLL_PLL_LOCK_DELAY + offset), 0x10, 0x06); - upper_addr |= (upper_8_bit(PLL_PLL_LOCKDET_RATE_1 + offset) << 16); - upper_addr |= (upper_8_bit(PLL_PLL_LOCK_DELAY + offset) << 17); - - 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_CTRL17, - 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_CTRL18, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - /* Dummy register writes */ - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL19, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL20, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL21, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL22, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL23, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL24, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL25, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - DSI_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL26, - PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); - 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); - - /* Registers to configure after PLL enable delay */ - 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, 0); - wmb(); /* commit register writes */ -} - -static int shadow_vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - int rc; - struct dsi_pll_10nm *pll; - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *rsc = vco->priv; - - if (!rsc) { - pr_err("pll resource not found\n"); - return -EINVAL; - } - - pll = rsc->priv; - if (!pll) { - pr_err("pll configuration not found\n"); - return -EINVAL; - } - - rc = dsi_pll_read_stored_trim_codes(rsc, rate); - if (rc) { - pr_err("cannot find pll codes rate=%ld\n", rate); - return -EINVAL; - } - pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); - - rsc->vco_current_rate = rate; - rsc->vco_ref_clk_rate = vco->ref_clk_rate; - - dsi_pll_setup_config(pll, rsc); - - dsi_pll_calc_dec_frac(pll, rsc); - - /* program dynamic refresh control registers */ - shadow_dsi_pll_dynamic_refresh_10nm(pll, rsc); - - /* update cached vco rate */ - rsc->vco_cached_rate = rate; - rsc->dfps_trigger = true; - - return 0; -} - -static int dsi_pll_10nm_lock_status(struct dsi_pll_resource *pll) -{ - int rc; - u32 status; - u32 const delay_us = 100; - u32 const timeout_us = 5000; - - rc = readl_poll_timeout_atomic(pll->pll_base + PLL_COMMON_STATUS_ONE, - status, - ((status & BIT(0)) > 0), - delay_us, - timeout_us); - if (rc) - pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", - pll->index, 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; - - 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 int dsi_pll_enable(struct dsi_pll_vco_clk *vco) -{ - int rc; - struct dsi_pll_resource *rsc = vco->priv; - - dsi_pll_enable_pll_bias(rsc); - if (rsc->slave) - dsi_pll_enable_pll_bias(rsc->slave); - - phy_reg_update_bits_sub(rsc, PHY_CMN_CLK_CFG1, 0x03, rsc->cached_cfg1); - if (rsc->slave) - phy_reg_update_bits_sub(rsc->slave, PHY_CMN_CLK_CFG1, - 0x03, rsc->slave->cached_cfg1); - wmb(); /* ensure dsiclk_sel is always programmed before pll start */ - - /* 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_10nm_lock_status(rsc); - if (rc) { - pr_err("PLL(%d) lock failed\n", rsc->index); - goto error; - } - - rsc->pll_on = true; - - dsi_pll_enable_global_clk(rsc); - if (rsc->slave) - dsi_pll_enable_global_clk(rsc->slave); - - DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0x01); - if (rsc->slave) - DSI_PLL_REG_W(rsc->slave->phy_base, PHY_CMN_RBUF_CTRL, 0x01); - -error: - return rc; -} - -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_disable(struct dsi_pll_vco_clk *vco) -{ - struct dsi_pll_resource *rsc = vco->priv; - - if (!rsc->pll_on) { - pr_err("failed to enable pll (%d) resources\n", rsc->index); - return; - } - - rsc->handoff_resources = false; - rsc->dfps_trigger = false; - - pr_debug("stop PLL (%d)\n", rsc->index); - - /* - * 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(); - rsc->pll_on = false; -} - -long vco_10nm_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - unsigned long rrate = rate; - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - - if (rate < vco->min_rate) - rrate = vco->min_rate; - if (rate > vco->max_rate) - rrate = vco->max_rate; - - *parent_rate = rrate; - - return rrate; -} - -static void vco_10nm_unprepare(struct clk_hw *hw) -{ - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *pll = vco->priv; - - if (!pll) { - pr_err("dsi pll resources not available\n"); - return; - } - - /* - * During unprepare in continuous splash use case we want driver - * to pick all dividers instead of retaining bootloader configurations. - * Also handle use cases where dynamic refresh triggered before - * first suspend/resume. - */ - if (!pll->handoff_resources || pll->dfps_trigger) { - pll->cached_cfg0 = DSI_PLL_REG_R(pll->phy_base, - PHY_CMN_CLK_CFG0); - pll->cached_outdiv = DSI_PLL_REG_R(pll->pll_base, - PLL_PLL_OUTDIV_RATE); - pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0, - pll->cached_cfg1, pll->cached_outdiv); - - pll->vco_cached_rate = clk_get_rate(hw->clk); - } - - /* - * When continuous splash screen feature is enabled, we need to cache - * the mux configuration for the pixel_clk_src mux clock. The clock - * framework does not call back to re-configure the mux value if it is - * does not change.For such usecases, we need to ensure that the cached - * value is programmed prior to PLL being locked - */ - if (pll->handoff_resources) { - pll->cached_cfg1 = DSI_PLL_REG_R(pll->phy_base, - PHY_CMN_CLK_CFG1); - if (pll->slave) - pll->slave->cached_cfg1 = - DSI_PLL_REG_R(pll->slave->phy_base, - PHY_CMN_CLK_CFG1); - } - - dsi_pll_disable(vco); -} - -static int vco_10nm_prepare(struct clk_hw *hw) -{ - int rc = 0; - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *pll = vco->priv; - - if (!pll) { - pr_err("dsi pll resources are not available\n"); - return -EINVAL; - } - - /* Skip vco recalculation for continuous splash use case */ - if (pll->handoff_resources) { - pll->pll_on = true; - return 0; - } - - if ((pll->vco_cached_rate != 0) && - (pll->vco_cached_rate == clk_hw_get_rate(hw))) { - rc = vco_10nm_set_rate(hw, pll->vco_cached_rate, - pll->vco_cached_rate); - if (rc) { - pr_err("pll(%d) set_rate failed, rc=%d\n", - pll->index, rc); - return rc; - } - pr_debug("cfg0=%d, cfg1=%d\n", pll->cached_cfg0, - pll->cached_cfg1); - DSI_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, - pll->cached_cfg0); - if (pll->slave) - DSI_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, - pll->cached_cfg0); - DSI_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE, - pll->cached_outdiv); - } - rc = dsi_pll_enable(vco); - - return rc; -} - -static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *pll = vco->priv; - int rc = 0; - - if (!vco->priv) - pr_err("vco priv is null\n"); - - if (!pll) { - pr_err("pll is null\n"); - return 0; - } - - /* - * In the case when vco rate is set, the recalculation function should - * return the current rate as to avoid trying to set the vco rate - * again. However durng handoff, recalculation should set the flag - * according to the status of PLL. - */ - if (pll->vco_current_rate != 0) { - pr_debug("returning vco rate = %lld\n", pll->vco_current_rate); - return pll->vco_current_rate; - } - - pll->handoff_resources = true; - - if (!dsi_pll_10nm_get_gdsc_status(pll)) { - pll->handoff_resources = false; - pr_err("Hand_off_resources not needed since gdsc is off\n"); - return 0; - } - - if (dsi_pll_10nm_lock_status(pll)) { - pll->handoff_resources = false; - pr_err("PLL not enabled\n"); - } - - return rc; -} - -static int pixel_clk_get_div(void *context, unsigned int reg, unsigned int *div) -{ - struct dsi_pll_resource *pll = context; - u32 reg_val; - - reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); - *div = (reg_val & 0xF0) >> 4; - - /** - * Common clock framework the divider value is interpreted as one less - * hence we return one less for all dividers except when zero - */ - if (*div != 0) - *div -= 1; - - return 0; -} - -static void pixel_clk_set_div_sub(struct dsi_pll_resource *pll, int div) -{ - u32 reg_val; - - reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); - reg_val &= ~0xF0; - reg_val |= (div << 4); - DSI_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val); - - /* - * cache the current parent index for cases where parent - * is not changing but rate is changing. In that case - * clock framework won't call parent_set and hence dsiclk_sel - * bit won't be programmed. e.g. dfps update use case. - */ - pll->cached_cfg0 = reg_val; -} - -static int pixel_clk_set_div(void *context, unsigned int reg, unsigned int div) -{ - struct dsi_pll_resource *pll = context; - - /** - * In common clock framework the divider value provided is one less and - * and hence adjusting the divider value by one prior to writing it to - * hardware - */ - div++; - pixel_clk_set_div_sub(pll, div); - if (pll->slave) - pixel_clk_set_div_sub(pll->slave, div); - - return 0; -} - -static int bit_clk_get_div(void *context, unsigned int reg, unsigned int *div) -{ - struct dsi_pll_resource *pll = context; - u32 reg_val; - - reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); - *div = (reg_val & 0x0F); - - /** - *Common clock framework the divider value is interpreted as one less - * hence we return one less for all dividers except when zero - */ - if (*div != 0) - *div -= 1; - - return 0; -} - -static void bit_clk_set_div_sub(struct dsi_pll_resource *rsc, int div) -{ - u32 reg_val; - - reg_val = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0); - reg_val &= ~0x0F; - reg_val |= div; - DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG0, reg_val); -} - -static int bit_clk_set_div(void *context, unsigned int reg, unsigned int div) -{ - struct dsi_pll_resource *rsc = context; - - if (!rsc) { - pr_err("pll resource not found\n"); - return -EINVAL; - } - - /** - * In common clock framework the divider value provided is one less and - * and hence adjusting the divider value by one prior to writing it to - * hardware - */ - div++; - - bit_clk_set_div_sub(rsc, div); - /* For slave PLL, this divider always should be set to 1 */ - if (rsc->slave) - bit_clk_set_div_sub(rsc->slave, 1); - - return 0; -} - -static struct regmap_config dsi_pll_10nm_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = 0x7c0, -}; - -static struct regmap_bus pll_regmap_bus = { - .reg_write = pll_reg_write, - .reg_read = pll_reg_read, -}; - -static struct regmap_bus pclk_src_mux_regmap_bus = { - .reg_read = pclk_mux_read_sel, - .reg_write = pclk_mux_write_sel, -}; - -static struct regmap_bus pclk_src_regmap_bus = { - .reg_write = pixel_clk_set_div, - .reg_read = pixel_clk_get_div, -}; - -static struct regmap_bus bitclk_src_regmap_bus = { - .reg_write = bit_clk_set_div, - .reg_read = bit_clk_get_div, -}; - -static const struct clk_ops clk_ops_vco_10nm = { - .recalc_rate = vco_10nm_recalc_rate, - .set_rate = vco_10nm_set_rate, - .round_rate = vco_10nm_round_rate, - .prepare = vco_10nm_prepare, - .unprepare = vco_10nm_unprepare, -}; - -static const struct clk_ops clk_ops_shadow_vco_10nm = { - .recalc_rate = vco_10nm_recalc_rate, - .set_rate = shadow_vco_10nm_set_rate, - .round_rate = vco_10nm_round_rate, -}; - -static struct regmap_bus dsi_mux_regmap_bus = { - .reg_write = dsi_set_mux_sel, - .reg_read = dsi_get_mux_sel, -}; - -/* - * Clock tree for generating DSI byte and pixel clocks. - * - * - * +---------------+ - * | vco_clk | - * +-------+-------+ - * | - * | - * +---------------+ - * | pll_out_div | - * | DIV(1,2,4,8) | - * +-------+-------+ - * | - * +-----------------------------+--------+ - * | | | - * +-------v-------+ | | - * | bitclk_src | | | - * | DIV(1..15) | | | - * +-------+-------+ | | - * | | | - * +----------+---------+ | | - * Shadow Path | | | | | - * + +-------v-------+ | +------v------+ | +------v-------+ - * | | byteclk_src | | |post_bit_div | | |post_vco_div | - * | | DIV(8) | | |DIV (2) | | |DIV(4) | - * | +-------+-------+ | +------+------+ | +------+-------+ - * | | | | | | | - * | | | +------+ | | - * | | +-------------+ | | +----+ - * | +--------+ | | | | - * | | +-v--v-v---v------+ - * +-v---------v----+ \ pclk_src_mux / - * \ byteclk_mux / \ / - * \ / +-----+-----+ - * +----+-----+ | Shadow Path - * | | + - * v +-----v------+ | - * dsi_byte_clk | pclk_src | | - * | DIV(1..15) | | - * +-----+------+ | - * | | - * | | - * +--------+ | - * | | - * +---v----v----+ - * \ pclk_mux / - * \ / - * +---+---+ - * | - * | - * v - * dsi_pclk - * - */ - -static struct dsi_pll_vco_clk dsi0pll_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_vco_10nm, - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_shadow_vco_10nm, - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct dsi_pll_vco_clk dsi1pll_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_vco_10nm, - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_shadow_vco_10nm, - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct clk_regmap_div dsi0pll_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pll_out_div", - .parent_names = (const char *[]){"dsi0pll_vco_clk"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_shadow_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_pll_out_div", - .parent_names = (const char *[]){ - "dsi0pll_shadow_vco_clk"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pll_out_div", - .parent_names = (const char *[]){"dsi1pll_vco_clk"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_shadow_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_pll_out_div", - .parent_names = (const char *[]){ - "dsi1pll_shadow_vco_clk"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_bitclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_bitclk_src", - .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_shadow_bitclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_bitclk_src", - .parent_names = (const char *[]){ - "dsi0pll_shadow_pll_out_div"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_bitclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_bitclk_src", - .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_shadow_bitclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_bitclk_src", - .parent_names = (const char *[]){ - "dsi1pll_shadow_pll_out_div"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_fixed_factor dsi0pll_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_post_vco_div", - .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_post_vco_div", - .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_post_vco_div", - .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_post_vco_div", - .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_byteclk_src", - .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_byteclk_src", - .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_byteclk_src", - .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_byteclk_src", - .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_post_bit_div", - .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_post_bit_div", - .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_post_bit_div", - .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_post_bit_div", - .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_regmap_mux dsi0pll_byteclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0_phy_pll_out_byteclk", - .parent_names = (const char *[]){"dsi0pll_byteclk_src", - "dsi0pll_shadow_byteclk_src"}, - .num_parents = 2, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_byteclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1_phy_pll_out_byteclk", - .parent_names = (const char *[]){"dsi1pll_byteclk_src", - "dsi1pll_shadow_byteclk_src"}, - .num_parents = 2, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pclk_src_mux", - .parent_names = (const char *[]){"dsi0pll_bitclk_src", - "dsi0pll_post_bit_div", - "dsi0pll_pll_out_div", - "dsi0pll_post_vco_div"}, - .num_parents = 4, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_shadow_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_pclk_src_mux", - .parent_names = (const char *[]){ - "dsi0pll_shadow_bitclk_src", - "dsi0pll_shadow_post_bit_div", - "dsi0pll_shadow_pll_out_div", - "dsi0pll_shadow_post_vco_div"}, - .num_parents = 4, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pclk_src_mux", - .parent_names = (const char *[]){"dsi1pll_bitclk_src", - "dsi1pll_post_bit_div", - "dsi1pll_pll_out_div", - "dsi1pll_post_vco_div"}, - .num_parents = 4, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_shadow_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_pclk_src_mux", - .parent_names = (const char *[]){ - "dsi1pll_shadow_bitclk_src", - "dsi1pll_shadow_post_bit_div", - "dsi1pll_shadow_pll_out_div", - "dsi1pll_shadow_post_vco_div"}, - .num_parents = 4, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_pclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pclk_src", - .parent_names = (const char *[]){ - "dsi0pll_pclk_src_mux"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_shadow_pclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_pclk_src", - .parent_names = (const char *[]){ - "dsi0pll_shadow_pclk_src_mux"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_pclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pclk_src", - .parent_names = (const char *[]){ - "dsi1pll_pclk_src_mux"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_shadow_pclk_src = { - .shift = 0, - .width = 4, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_pclk_src", - .parent_names = (const char *[]){ - "dsi1pll_shadow_pclk_src_mux"}, - .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_pclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0_phy_pll_out_dsiclk", - .parent_names = (const char *[]){"dsi0pll_pclk_src", - "dsi0pll_shadow_pclk_src"}, - .num_parents = 2, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_pclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1_phy_pll_out_dsiclk", - .parent_names = (const char *[]){"dsi1pll_pclk_src", - "dsi1pll_shadow_pclk_src"}, - .num_parents = 2, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_hw *dsi_pllcc_10nm[] = { - [VCO_CLK_0] = &dsi0pll_vco_clk.hw, - [PLL_OUT_DIV_0_CLK] = &dsi0pll_pll_out_div.clkr.hw, - [BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw, - [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw, - [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.hw, - [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.hw, - [BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw, - [PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw, - [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw, - [PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw, - [SHADOW_VCO_CLK_0] = &dsi0pll_shadow_vco_clk.hw, - [SHADOW_PLL_OUT_DIV_0_CLK] = &dsi0pll_shadow_pll_out_div.clkr.hw, - [SHADOW_BITCLK_SRC_0_CLK] = &dsi0pll_shadow_bitclk_src.clkr.hw, - [SHADOW_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_byteclk_src.hw, - [SHADOW_POST_BIT_DIV_0_CLK] = &dsi0pll_shadow_post_bit_div.hw, - [SHADOW_POST_VCO_DIV_0_CLK] = &dsi0pll_shadow_post_vco_div.hw, - [SHADOW_PCLK_SRC_MUX_0_CLK] = &dsi0pll_shadow_pclk_src_mux.clkr.hw, - [SHADOW_PCLK_SRC_0_CLK] = &dsi0pll_shadow_pclk_src.clkr.hw, - [VCO_CLK_1] = &dsi1pll_vco_clk.hw, - [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw, - [BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw, - [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw, - [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.hw, - [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.hw, - [BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw, - [PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw, - [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw, - [PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw, - [SHADOW_VCO_CLK_1] = &dsi1pll_shadow_vco_clk.hw, - [SHADOW_PLL_OUT_DIV_1_CLK] = &dsi1pll_shadow_pll_out_div.clkr.hw, - [SHADOW_BITCLK_SRC_1_CLK] = &dsi1pll_shadow_bitclk_src.clkr.hw, - [SHADOW_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_byteclk_src.hw, - [SHADOW_POST_BIT_DIV_1_CLK] = &dsi1pll_shadow_post_bit_div.hw, - [SHADOW_POST_VCO_DIV_1_CLK] = &dsi1pll_shadow_post_vco_div.hw, - [SHADOW_PCLK_SRC_MUX_1_CLK] = &dsi1pll_shadow_pclk_src_mux.clkr.hw, - [SHADOW_PCLK_SRC_1_CLK] = &dsi1pll_shadow_pclk_src.clkr.hw, -}; - -int dsi_pll_clock_register_10nm(struct platform_device *pdev, - struct dsi_pll_resource *pll_res) -{ - int rc = 0, ndx, i; - struct clk *clk; - struct clk_onecell_data *clk_data; - int num_clks = ARRAY_SIZE(dsi_pllcc_10nm); - struct regmap *rmap; - struct regmap_config *rmap_config; - - ndx = pll_res->index; - - if (ndx >= DSI_PLL_MAX) { - pr_err("pll index(%d) NOT supported\n", ndx); - 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; - - clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); - if (!clk_data) - return -ENOMEM; - - clk_data->clks = devm_kcalloc(&pdev->dev, num_clks, - sizeof(struct clk *), GFP_KERNEL); - if (!clk_data->clks) - return -ENOMEM; - - clk_data->clk_num = num_clks; - - rmap_config = devm_kmemdup(&pdev->dev, &dsi_pll_10nm_config, - sizeof(struct regmap_config), GFP_KERNEL); - if (!rmap_config) - return -ENOMEM; - - /* Establish client data */ - if (ndx == 0) { - rmap_config->name = "pll_out"; - rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, - pll_res, rmap_config); - dsi0pll_pll_out_div.clkr.regmap = rmap; - dsi0pll_shadow_pll_out_div.clkr.regmap = rmap; - - rmap_config->name = "bitclk_src"; - rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, - pll_res, rmap_config); - dsi0pll_bitclk_src.clkr.regmap = rmap; - dsi0pll_shadow_bitclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_src"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, - pll_res, rmap_config); - dsi0pll_pclk_src.clkr.regmap = rmap; - dsi0pll_shadow_pclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_mux"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi0pll_pclk_mux.clkr.regmap = rmap; - - rmap_config->name = "pclk_src_mux"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, - pll_res, rmap_config); - dsi0pll_pclk_src_mux.clkr.regmap = rmap; - dsi0pll_shadow_pclk_src_mux.clkr.regmap = rmap; - - rmap_config->name = "byteclk_mux"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi0pll_byteclk_mux.clkr.regmap = rmap; - - dsi0pll_vco_clk.priv = pll_res; - dsi0pll_shadow_vco_clk.priv = pll_res; - - for (i = VCO_CLK_0; i <= SHADOW_PCLK_SRC_0_CLK; i++) { - clk = devm_clk_register(&pdev->dev, - dsi_pllcc_10nm[i]); - if (IS_ERR(clk)) { - pr_err("clk registration failed for DSI clock:%d\n", - pll_res->index); - rc = -EINVAL; - goto clk_register_fail; - } - clk_data->clks[i] = clk; - - } - - rc = of_clk_add_provider(pdev->dev.of_node, - of_clk_src_onecell_get, clk_data); - } else { - rmap_config->name = "pll_out"; - rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, - pll_res, rmap_config); - dsi1pll_pll_out_div.clkr.regmap = rmap; - dsi1pll_shadow_pll_out_div.clkr.regmap = rmap; - - rmap_config->name = "bitclk_src"; - rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, - pll_res, rmap_config); - dsi1pll_bitclk_src.clkr.regmap = rmap; - dsi1pll_shadow_bitclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_src"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, - pll_res, rmap_config); - dsi1pll_pclk_src.clkr.regmap = rmap; - dsi1pll_shadow_pclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_mux"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi1pll_pclk_mux.clkr.regmap = rmap; - - rmap_config->name = "pclk_src_mux"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, - pll_res, rmap_config); - dsi1pll_pclk_src_mux.clkr.regmap = rmap; - dsi1pll_shadow_pclk_src_mux.clkr.regmap = rmap; - - rmap_config->name = "byteclk_mux"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi1pll_byteclk_mux.clkr.regmap = rmap; - - dsi1pll_vco_clk.priv = pll_res; - dsi1pll_shadow_vco_clk.priv = pll_res; - - for (i = VCO_CLK_1; i <= SHADOW_PCLK_SRC_1_CLK; i++) { - clk = devm_clk_register(&pdev->dev, - dsi_pllcc_10nm[i]); - if (IS_ERR(clk)) { - pr_err("clk registration failed for DSI clock:%d\n", - pll_res->index); - rc = -EINVAL; - goto clk_register_fail; - } - clk_data->clks[i] = clk; - - } - - rc = of_clk_add_provider(pdev->dev.of_node, - of_clk_src_onecell_get, clk_data); - } - if (!rc) { - pr_info("Registered DSI PLL ndx=%d, clocks successfully\n", - ndx); - - return rc; - } -clk_register_fail: - return rc; -} diff --git a/msm/dsi/dsi_pll_5nm.c b/msm/dsi/dsi_pll_5nm.c index 8ecd313536..182775e70a 100644 --- a/msm/dsi/dsi_pll_5nm.c +++ b/msm/dsi/dsi_pll_5nm.c @@ -1,18 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ -#define pr_fmt(fmt) "%s: " fmt, __func__ - #include #include #include #include #include #include -#include "dsi_pll.h" -#include +#include "dsi_pll_5nm.h" #define VCO_DELAY_USEC 1 @@ -23,225 +20,6 @@ #define MHZ_1900 1900000000UL #define MHZ_3000 3000000000UL -/* 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_regs { u32 pll_prop_gain_rate; u32 pll_lockdet_rate; @@ -291,186 +69,113 @@ static inline bool dsi_pll_5nm_is_hw_revision( true : false; } -static inline int pll_reg_read(void *context, unsigned int reg, - unsigned int *val) +static inline void dsi_pll_set_pll_post_div(struct dsi_pll_resource *pll, u32 + pll_post_div) { - int rc = 0; - u32 data; - struct dsi_pll_resource *rsc = context; + u32 pll_post_div_val = 0; - 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)); - ndelay(250); + 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; - *val = DSI_PLL_REG_R(rsc->pll_base, reg); - - DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data); - - return rc; + 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 pll_reg_write(void *context, unsigned int reg, - unsigned int val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - DSI_PLL_REG_W(rsc->pll_base, reg, val); - - return rc; -} - -static inline int phy_reg_read(void *context, unsigned int reg, - unsigned int *val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - *val = DSI_PLL_REG_R(rsc->phy_base, reg); - - return rc; -} - -static inline int phy_reg_write(void *context, unsigned int reg, - unsigned int val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - DSI_PLL_REG_W(rsc->phy_base, reg, val); - - return rc; -} - -static inline int phy_reg_update_bits_sub(struct dsi_pll_resource *rsc, - unsigned int reg, unsigned int mask, unsigned int val) +static inline int dsi_pll_get_pll_post_div(struct dsi_pll_resource *pll) { u32 reg_val; - reg_val = DSI_PLL_REG_R(rsc->phy_base, reg); - reg_val &= ~mask; - reg_val |= (val & mask); - DSI_PLL_REG_W(rsc->phy_base, reg, reg_val); + reg_val = DSI_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE); - return 0; + return (1 << reg_val); } -static inline int phy_reg_update_bits(void *context, unsigned int reg, - unsigned int mask, unsigned int val) +static inline void dsi_pll_set_phy_post_div(struct dsi_pll_resource *pll, u32 + phy_post_div) { - int rc = 0; - struct dsi_pll_resource *rsc = context; + u32 reg_val = 0; - rc = phy_reg_update_bits_sub(rsc, reg, mask, val); - if (!rc && rsc->slave) - rc = phy_reg_update_bits_sub(rsc->slave, reg, mask, val); - - return rc; -} - -static inline int pclk_mux_read_sel(void *context, unsigned int reg, - unsigned int *val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - - /* Return cached cfg1 as its updated with cached cfg1 in pll_enable */ - if (!rsc->handoff_resources) { - *val = (rsc->cached_cfg1) & 0x3; - return rc; + 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); + if (pll->slave) { + reg_val = DSI_PLL_REG_R(pll->slave->phy_base, PHY_CMN_CLK_CFG0); + reg_val &= ~0x0F; + reg_val |= phy_post_div; + DSI_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, reg_val); } - - *val = (DSI_PLL_REG_R(rsc->phy_base, reg) & 0x3); - - return rc; } -static inline int pclk_mux_write_sel_sub(struct dsi_pll_resource *rsc, - unsigned int reg, unsigned int 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(rsc->phy_base, reg); - reg_val &= ~0x03; - reg_val |= val; + reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1); - DSI_PLL_REG_W(rsc->phy_base, reg, reg_val); - - return 0; + return (reg_val & 0x3); } -static inline int pclk_mux_write_sel(void *context, unsigned int reg, - unsigned int val) +static inline void dsi_pll_set_pclk_div(struct dsi_pll_resource *pll, u32 + pclk_div) { - int rc = 0; - struct dsi_pll_resource *rsc = context; - struct dsi_pll_5nm *pll = rsc->priv; + u32 reg_val = 0; - if (pll->cphy_enabled) - WARN_ON("PHY is in CPHY mode. PLL config is incorrect\n"); - rc = pclk_mux_write_sel_sub(rsc, reg, val); - if (!rc && rsc->slave) - rc = pclk_mux_write_sel_sub(rsc->slave, reg, val); - - - /* - * cache the current parent index for cases where parent - * is not changing but rate is changing. In that case - * clock framework won't call parent_set and hence dsiclk_sel - * bit won't be programmed. e.g. dfps update use case. - */ - rsc->cached_cfg1 = val; - - return rc; + 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 cphy_pclk_mux_read_sel(void *context, unsigned int reg, - unsigned int *val) +static inline int dsi_pll_get_pclk_div(struct dsi_pll_resource *pll) { - struct dsi_pll_resource *rsc = context; + u32 reg_val; - *val = (DSI_PLL_REG_R(rsc->phy_base, reg) & 0x3); + reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); - return 0; -} - -static inline int cphy_pclk_mux_write_sel(void *context, unsigned int reg, - unsigned int val) -{ - int rc = 0; - struct dsi_pll_resource *rsc = context; - struct dsi_pll_5nm *pll = rsc->priv; - - if (!pll->cphy_enabled) - WARN_ON("PHY-> not in CPHY mode. PLL config is incorrect\n"); - /* For Cphy configuration, val should always be 3 */ - val = 3; - rc = pclk_mux_write_sel_sub(rsc, reg, val); - if (!rc && rsc->slave) - rc = pclk_mux_write_sel_sub(rsc->slave, reg, val); - - /* - * cache the current parent index for cases where parent - * is not changing but rate is changing. In that case - * clock framework won't call parent_set and hence dsiclk_sel - * bit won't be programmed. e.g. dfps update use case. - */ - rsc->cached_cfg1 = val; - - return rc; -} - -static int dsi_pll_5nm_get_gdsc_status(struct dsi_pll_resource *rsc) -{ - u32 reg = 0; - bool status; - - reg = DSI_PLL_REG_R(rsc->gdsc_base, 0x0); - status = reg & BIT(31); - pr_err("reg:0x%x status:%d\n", reg, status); - - return status; + return ((reg_val & 0xF0) >> 4); } static struct dsi_pll_resource *pll_rsc_db[DSI_PLL_MAX]; @@ -492,7 +197,8 @@ static void dsi_pll_config_slave(struct dsi_pll_resource *rsc) rsc->slave = NULL; if (!orsc) { - pr_warn("slave PLL unavilable, assuming standalone config\n"); + DSI_PLL_WARN(rsc, + "slave PLL unavilable, assuming standalone config\n"); return; } @@ -502,7 +208,8 @@ static void dsi_pll_config_slave(struct dsi_pll_resource *rsc) if (reg == 0x04) rsc->slave = pll_rsc_db[DSI_PLL_1]; /* external source */ - pr_debug("Slave PLL %s\n", rsc->slave ? "configured" : "absent"); + DSI_PLL_DBG(rsc, "Slave PLL %s\n", + rsc->slave ? "configured" : "absent"); } static void dsi_pll_setup_config(struct dsi_pll_5nm *pll, @@ -595,7 +302,7 @@ static void dsi_pll_calc_ssc(struct dsi_pll_5nm *pll, u64 frac; if (!config->enable_ssc) { - pr_debug("SSC not enabled\n"); + DSI_PLL_DBG(rsc, "SSC not enabled\n"); return; } @@ -623,9 +330,9 @@ static void dsi_pll_calc_ssc(struct dsi_pll_5nm *pll, regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; - pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", + DSI_PLL_DBG(rsc, "SCC: Dec:%d, frac:%llu, frac_bits:%d\n", regs->decimal_div_start, frac, config->frac_bits); - pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", + 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); } @@ -636,7 +343,7 @@ static void dsi_pll_ssc_commit(struct dsi_pll_5nm *pll, struct dsi_pll_regs *regs = &pll->reg_setup; if (pll->pll_configuration.enable_ssc) { - pr_debug("SSC is enabled\n"); + DSI_PLL_DBG(rsc, "SSC is enabled\n"); DSI_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1, regs->ssc_stepsize_low); @@ -885,48 +592,507 @@ static void dsi_pll_commit(struct dsi_pll_5nm *pll, reg->pll_clock_inverters); } -static int vco_5nm_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int dsi_pll_5nm_lock_status(struct dsi_pll_resource *pll) +{ + int rc; + u32 status; + u32 const delay_us = 100; + u32 const timeout_us = 5000; + + rc = readl_poll_timeout_atomic(pll->pll_base + 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; + + ref_clk = pll->vco_ref_clk_rate; + + 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 << 18; + 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(vco_rate, 8); + else + byte_rate = div_u64(vco_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_5nm(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; + + 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_5nm_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; + u32 bitclk_rate; + + if (pll->type == DSI_PHY_TYPE_DPHY) { + bitclk_rate = pll->byteclk_rate * 8; + table_size = ARRAY_SIZE(pll_5nm_dphy); + table = pll_5nm_dphy; + } else { + bitclk_rate = pll->byteclk_rate * 7; + table_size = ARRAY_SIZE(pll_5nm_cphy); + table = pll_5nm_cphy; + } + + 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_5nm_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); + } else { + dsi_clk = 0x3; + pclk_src_rate *= 2; + pclk_src_rate = div_u64(pclk_src_rate, 7); + } + + pclk_div = pclk_src_rate / pll->pclk_rate; + + 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_5nm_vco_set_rate(struct dsi_pll_resource *pll_res) { - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *rsc = vco->priv; struct dsi_pll_5nm *pll; - if (!rsc) { - pr_err("pll resource not found\n"); - return -EINVAL; - } - - if (rsc->pll_on) + if (pll_res->pll_on) return 0; - pll = rsc->priv; + pll = pll_res->priv; if (!pll) { - pr_err("pll configuration not found\n"); + DSI_PLL_ERR(pll_res, "pll configuration not found\n"); return -EINVAL; } - pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + DSI_PLL_DBG(pll_res, "rate=%lu\n", pll_res->vco_rate); - rsc->vco_current_rate = rate; - rsc->vco_ref_clk_rate = vco->ref_clk_rate; - rsc->dfps_trigger = false; + pll_res->vco_current_rate = pll_res->vco_rate; - dsi_pll_init_val(rsc); + dsi_pll_detect_phy_mode(pll, pll_res); - dsi_pll_detect_phy_mode(pll, rsc); + dsi_pll_setup_config(pll, pll_res); - dsi_pll_setup_config(pll, rsc); + dsi_pll_calc_dec_frac(pll, pll_res); - dsi_pll_calc_dec_frac(pll, rsc); + dsi_pll_calc_ssc(pll, pll_res); - dsi_pll_calc_ssc(pll, rsc); + dsi_pll_commit(pll, pll_res); - dsi_pll_commit(pll, rsc); + dsi_pll_config_hzindep_reg(pll, pll_res); - dsi_pll_config_hzindep_reg(pll, rsc); - - dsi_pll_ssc_commit(pll, rsc); + dsi_pll_ssc_commit(pll, pll_res); /* flush, ensure all register writes are done*/ wmb(); @@ -947,7 +1113,7 @@ static int dsi_pll_read_stored_trim_codes(struct dsi_pll_resource *pll_res, struct dfps_codes_info *codes_info = &pll_res->dfps->codes_dfps[i]; - pr_debug("valid=%d vco_rate=%d, code %d %d %d\n", + 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, @@ -970,7 +1136,7 @@ static int dsi_pll_read_stored_trim_codes(struct dsi_pll_resource *pll_res, if (!found) return -EINVAL; - pr_debug("trim_code_0=0x%x trim_code_1=0x%x trim_code_2=0x%x\n", + 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]); @@ -978,8 +1144,8 @@ static int dsi_pll_read_stored_trim_codes(struct dsi_pll_resource *pll_res, return 0; } -static void shadow_dsi_pll_dynamic_refresh_5nm(struct dsi_pll_5nm *pll, - struct dsi_pll_resource *rsc) +static void dsi_pll_5nm_dynamic_refresh(struct dsi_pll_5nm *pll, + struct dsi_pll_resource *rsc) { u32 data; u32 offset = DSI_PHY_TO_PLL_OFFSET; @@ -1036,8 +1202,7 @@ static void shadow_dsi_pll_dynamic_refresh_5nm(struct dsi_pll_5nm *pll, (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_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); @@ -1162,143 +1327,47 @@ static void shadow_dsi_pll_dynamic_refresh_5nm(struct dsi_pll_5nm *pll, wmb(); /* commit register writes */ } -static int shadow_vco_5nm_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int dsi_pll_5nm_dynamic_clk_vco_set_rate(struct dsi_pll_resource *rsc) { int rc; struct dsi_pll_5nm *pll; - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *rsc = vco->priv; + u32 rate; if (!rsc) { - pr_err("pll resource not found\n"); + DSI_PLL_ERR(rsc, "pll resource not found\n"); return -EINVAL; } + rate = rsc->vco_rate; pll = rsc->priv; if (!pll) { - pr_err("pll configuration not found\n"); + DSI_PLL_ERR(rsc, "pll configuration not found\n"); return -EINVAL; } rc = dsi_pll_read_stored_trim_codes(rsc, rate); if (rc) { - pr_err("cannot find pll codes rate=%ld\n", rate); + DSI_PLL_ERR(rsc, "cannot find pll codes rate=%ld\n", rate); return -EINVAL; } - pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + DSI_PLL_DBG(rsc, "ndx=%d, rate=%lu\n", rate); rsc->vco_current_rate = rate; - rsc->vco_ref_clk_rate = vco->ref_clk_rate; dsi_pll_setup_config(pll, rsc); dsi_pll_calc_dec_frac(pll, rsc); /* program dynamic refresh control registers */ - shadow_dsi_pll_dynamic_refresh_5nm(pll, rsc); - - /* update cached vco rate */ - rsc->vco_cached_rate = rate; - rsc->dfps_trigger = true; + dsi_pll_5nm_dynamic_refresh(pll, rsc); return 0; } -static int dsi_pll_5nm_lock_status(struct dsi_pll_resource *pll) +static int dsi_pll_5nm_enable(struct dsi_pll_resource *rsc) { - int rc; - u32 status; - u32 const delay_us = 100; - u32 const timeout_us = 5000; - - rc = readl_poll_timeout_atomic(pll->pll_base + PLL_COMMON_STATUS_ONE, - status, - ((status & BIT(0)) > 0), - delay_us, - timeout_us); - if (rc && !pll->handoff_resources) - pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", - pll->index, 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 int dsi_pll_enable(struct dsi_pll_vco_clk *vco) -{ - int rc; - struct dsi_pll_resource *rsc = vco->priv; - struct dsi_pll_5nm *pll = rsc->priv; - - dsi_pll_enable_pll_bias(rsc); - if (rsc->slave) - dsi_pll_enable_pll_bias(rsc->slave); - - /* For Cphy configuration, pclk_mux is always set to 3 divider */ - if (pll->cphy_enabled) { - rsc->cached_cfg1 |= 0x3; - if (rsc->slave) - rsc->slave->cached_cfg1 |= 0x3; - } - - phy_reg_update_bits_sub(rsc, PHY_CMN_CLK_CFG1, 0x03, rsc->cached_cfg1); - if (rsc->slave) - phy_reg_update_bits_sub(rsc->slave, PHY_CMN_CLK_CFG1, - 0x03, rsc->slave->cached_cfg1); - wmb(); /* ensure dsiclk_sel is always programmed before pll start */ + int rc = 0; /* Start PLL */ DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01); @@ -1312,7 +1381,7 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) /* Check for PLL lock */ rc = dsi_pll_5nm_lock_status(rsc); if (rc) { - pr_err("PLL(%d) lock failed\n", rsc->index); + DSI_PLL_ERR(rsc, "lock failed\n"); goto error; } @@ -1331,29 +1400,22 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) if (rsc->slave) dsi_pll_enable_global_clk(rsc->slave); + /* flush, ensure all register writes are done*/ + wmb(); error: return rc; } -static void dsi_pll_disable_sub(struct dsi_pll_resource *rsc) +static int dsi_pll_5nm_disable(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_disable(struct dsi_pll_vco_clk *vco) -{ - struct dsi_pll_resource *rsc = vco->priv; + int rc = 0; if (!rsc->pll_on) { - pr_err("failed to enable pll (%d) resources\n", rsc->index); - return; + DSI_PLL_ERR(rsc, "is not enabled\n"); + return -EINVAL; } - rsc->handoff_resources = false; - rsc->dfps_trigger = false; - - pr_debug("stop PLL (%d)\n", rsc->index); + DSI_PLL_DBG(rsc, "stop PLL\n"); /* * To avoid any stray glitches while @@ -1372,1323 +1434,54 @@ static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) /* flush, ensure all register writes are done*/ wmb(); rsc->pll_on = false; -} - -long vco_5nm_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - unsigned long rrate = rate; - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - - if (rate < vco->min_rate) - rrate = vco->min_rate; - if (rate > vco->max_rate) - rrate = vco->max_rate; - - *parent_rate = rrate; - - return rrate; -} - -static void vco_5nm_unprepare(struct clk_hw *hw) -{ - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *pll = vco->priv; - - if (!pll) { - pr_err("dsi pll resources not available\n"); - return; - } - - /* - * During unprepare in continuous splash use case we want driver - * to pick all dividers instead of retaining bootloader configurations. - * Also handle the usecases when dynamic refresh gets triggered while - * handoff_resources flag is still set. For video mode, this flag does - * not get cleared until first suspend. Whereas for command mode, it - * doesnt get cleared until first idle power collapse. We need to make - * sure that we save and restore the divider settings when dynamic FPS - * is triggered. - */ - if (!pll->handoff_resources || pll->dfps_trigger) { - pll->cached_cfg0 = DSI_PLL_REG_R(pll->phy_base, - PHY_CMN_CLK_CFG0); - pll->cached_outdiv = DSI_PLL_REG_R(pll->pll_base, - PLL_PLL_OUTDIV_RATE); - pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0, - pll->cached_cfg1, pll->cached_outdiv); - - pll->vco_cached_rate = clk_get_rate(hw->clk); - } - - /* - * When continuous splash screen feature is enabled, we need to cache - * the mux configuration for the pixel_clk_src mux clock. The clock - * framework does not call back to re-configure the mux value if it is - * does not change.For such usecases, we need to ensure that the cached - * value is programmed prior to PLL being locked - */ - if (pll->handoff_resources) { - pll->cached_cfg1 = DSI_PLL_REG_R(pll->phy_base, - PHY_CMN_CLK_CFG1); - if (pll->slave) - pll->slave->cached_cfg1 = - DSI_PLL_REG_R(pll->slave->phy_base, - PHY_CMN_CLK_CFG1); - } - - dsi_pll_disable(vco); -} - -static int vco_5nm_prepare(struct clk_hw *hw) -{ - int rc = 0; - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *pll = vco->priv; - - if (!pll) { - pr_err("dsi pll resources are not available\n"); - return -EINVAL; - } - - /* Skip vco recalculation for continuous splash use case */ - if (pll->handoff_resources) { - pll->pll_on = true; - return 0; - } - - if ((pll->vco_cached_rate != 0) && - (pll->vco_cached_rate == clk_hw_get_rate(hw))) { - rc = vco_5nm_set_rate(hw, pll->vco_cached_rate, - pll->vco_cached_rate); - if (rc) { - pr_err("pll(%d) set_rate failed, rc=%d\n", - pll->index, rc); - return rc; - } - pr_debug("cfg0=%d, cfg1=%d\n", pll->cached_cfg0, - pll->cached_cfg1); - DSI_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, - pll->cached_cfg0); - if (pll->slave) - DSI_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, - pll->cached_cfg0); - DSI_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE, - pll->cached_outdiv); - } - - rc = dsi_pll_enable(vco); return rc; } -static unsigned long vco_5nm_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +int dsi_pll_5nm_configure(void *pll, bool commit) { + int rc = 0; - struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); - struct dsi_pll_resource *pll = vco->priv; + struct dsi_pll_resource *rsc = (struct dsi_pll_resource *)pll; - if (!vco->priv) { - pr_err("vco priv is null\n"); - return 0; - } - - if (!pll->priv) { - pr_err("pll priv is null\n"); - return 0; - } - /* - * In the case when vco arte is set, the recalculation function should - * return the current rate as to avoid trying to set the vco rate - * again. However durng handoff, recalculation should set the flag - * according to the status of PLL. - */ - if (pll->vco_current_rate != 0) { - pr_debug("returning vco rate = %lld\n", pll->vco_current_rate); - return pll->vco_current_rate; - } - - pll->handoff_resources = true; - - - if (!dsi_pll_5nm_get_gdsc_status(pll)) { - pll->handoff_resources = false; - pr_err("Hand_off_resources not needed since gdsc is off\n"); - return 0; - } - - dsi_pll_detect_phy_mode(pll->priv, pll); - - if (dsi_pll_5nm_lock_status(pll)) { - pr_err("PLL not enabled\n"); - pll->handoff_resources = false; - } - pr_err("handoff_resources %s\n", pll->handoff_resources ? "true" : "false"); - - return rc; -} - -static int pixel_clk_get_div(void *context, unsigned int reg, unsigned int *div) -{ - struct dsi_pll_resource *pll = context; - u32 reg_val; - - reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); - *div = (reg_val & 0xF0) >> 4; - - return 0; -} - -static void pixel_clk_set_div_sub(struct dsi_pll_resource *pll, int div) -{ - u32 reg_val; - - reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); - reg_val &= ~0xF0; - reg_val |= (div << 4); - DSI_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val); - - /* - * cache the current parent index for cases where parent - * is not changing but rate is changing. In that case - * clock framework won't call parent_set and hence dsiclk_sel - * bit won't be programmed. e.g. dfps update use case. - */ - pll->cached_cfg0 = reg_val; -} - -static int pixel_clk_set_div(void *context, unsigned int reg, unsigned int div) -{ - struct dsi_pll_resource *pll = context; - - pixel_clk_set_div_sub(pll, div); - if (pll->slave) - pixel_clk_set_div_sub(pll->slave, div); - - return 0; -} - -static int bit_clk_get_div(void *context, unsigned int reg, unsigned int *div) -{ - struct dsi_pll_resource *pll = context; - u32 reg_val; - - reg_val = DSI_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); - *div = (reg_val & 0x0F); - - return 0; -} - -static void bit_clk_set_div_sub(struct dsi_pll_resource *rsc, int div) -{ - u32 reg_val; - - reg_val = DSI_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0); - reg_val &= ~0x0F; - reg_val |= div; - DSI_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG0, reg_val); -} - -static int bit_clk_set_div(void *context, unsigned int reg, unsigned int div) -{ - struct dsi_pll_resource *rsc = context; - - if (!rsc) { - pr_err("pll resource not found\n"); - return -EINVAL; - } - - bit_clk_set_div_sub(rsc, div); - /* For slave PLL, this divider always should be set to 1 */ + /* PLL power needs to be enabled before accessing PLL registers */ + dsi_pll_enable_pll_bias(rsc); if (rsc->slave) - bit_clk_set_div_sub(rsc->slave, 1); + dsi_pll_enable_pll_bias(rsc->slave); + + dsi_pll_init_val(rsc); + + rc = dsi_pll_5nm_set_byteclk_div(rsc, commit); + + if (commit) { + rc = dsi_pll_5nm_set_pclk_div(rsc, commit); + rc = dsi_pll_5nm_vco_set_rate(rsc); + } else { + rc = dsi_pll_5nm_dynamic_clk_vco_set_rate(rsc); + } return 0; } -static struct regmap_config dsi_pll_5nm_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = 0x7c0, -}; - -static struct regmap_bus pll_regmap_bus = { - .reg_write = pll_reg_write, - .reg_read = pll_reg_read, -}; - -static struct regmap_bus pclk_src_mux_regmap_bus = { - .reg_read = pclk_mux_read_sel, - .reg_write = pclk_mux_write_sel, -}; - -static struct regmap_bus cphy_pclk_src_mux_regmap_bus = { - .reg_read = cphy_pclk_mux_read_sel, - .reg_write = cphy_pclk_mux_write_sel, -}; - -static struct regmap_bus pclk_src_regmap_bus = { - .reg_write = pixel_clk_set_div, - .reg_read = pixel_clk_get_div, -}; - -static struct regmap_bus bitclk_src_regmap_bus = { - .reg_write = bit_clk_set_div, - .reg_read = bit_clk_get_div, -}; - -static const struct clk_ops clk_ops_vco_5nm = { - .recalc_rate = vco_5nm_recalc_rate, - .set_rate = vco_5nm_set_rate, - .round_rate = vco_5nm_round_rate, - .prepare = vco_5nm_prepare, - .unprepare = vco_5nm_unprepare, -}; - -static const struct clk_ops clk_ops_shadow_vco_5nm = { - .recalc_rate = vco_5nm_recalc_rate, - .set_rate = shadow_vco_5nm_set_rate, - .round_rate = vco_5nm_round_rate, -}; - -static struct regmap_bus dsi_mux_regmap_bus = { - .reg_write = dsi_set_mux_sel, - .reg_read = dsi_get_mux_sel, -}; - -/* - * Clock tree for generating DSI byte and pclk. - * - * - * +---------------+ - * | vco_clk | - * +-------+-------+ - * | - * | - * +---------------+ - * | pll_out_div | - * | DIV(1,2,4,8) | - * +-------+-------+ - * | - * +-----------------------------+-------+---------------+ - * | | | | - * +-------v-------+ | | | - * | bitclk_src | | - * | DIV(1..15) | Not supported for DPHY | - * +-------+-------+ | - * | | | | - * +-------------v+---------+---------+ | | | - * | | | | | | | - * +-----v-----+ +-----v-----+ | +------v------+ | +-----v------+ +-----v------+ - * |byteclk_src| |byteclk_src| | |post_bit_div | | |post_vco_div| |post_vco_div| - * | DIV(8) | | DIV(7) | | | DIV (2) | | | DIV(4) | | DIV(3.5) | - * +-----+-----+ +-----+-----+ | +------+------+ | +-----+------+ +------+-----+ - * | | | | | | | - *Shadow Path | CPHY Path | | | | +----v - * + | | +------+ | | +---+ | - * +---+ | +-----+ | | | | | - * | | | +-v--v----v---v---+ +--------v--------+ - * +---v--v--------v---+ \ pclk_src_mux / \ cphy_pclk_src / - * \ byteclk_mux / \ / \ mux / - * \ / +-----+-----+ +-----+-----+ - * +------+------+ | Shadow Path | - * | | + | - * v +-----v------+ | +------v------+ - * dsi_byte_clk | pclk_src | | |cphy_pclk_src| - * | DIV(1..15) | | | DIV(1..15) | - * +-----+------+ | +------+------+ - * | | | - * | | CPHY Path - * | | | - * +-------+ | +-------+ - * | | | - * +---v---v----v------+ - * \ pclk_mux / - * +------+------+ - * | - * v - * dsi_pclk - * - */ - -static struct dsi_pll_vco_clk dsi0pll_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_vco_5nm, - }, -}; - -static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_shadow_vco_5nm, - }, -}; - -static struct dsi_pll_vco_clk dsi1pll_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_vco_5nm, - }, -}; - -static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { - .ref_clk_rate = 19200000UL, - .min_rate = 1000000000UL, - .max_rate = 3500000000UL, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_vco_clk", - .parent_names = (const char *[]){"bi_tcxo"}, - .num_parents = 1, - .ops = &clk_ops_shadow_vco_5nm, - }, -}; - -static struct clk_regmap_div dsi0pll_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pll_out_div", - .parent_names = (const char *[]){"dsi0pll_vco_clk"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_shadow_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_pll_out_div", - .parent_names = (const char *[]){ - "dsi0pll_shadow_vco_clk"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pll_out_div", - .parent_names = (const char *[]){"dsi1pll_vco_clk"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_shadow_pll_out_div = { - .reg = PLL_PLL_OUTDIV_RATE, - .shift = 0, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_pll_out_div", - .parent_names = (const char *[]){ - "dsi1pll_shadow_vco_clk"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_bitclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_bitclk_src", - .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_shadow_bitclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_bitclk_src", - .parent_names = (const char *[]){ - "dsi0pll_shadow_pll_out_div"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_bitclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_bitclk_src", - .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_shadow_bitclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_bitclk_src", - .parent_names = (const char *[]){ - "dsi1pll_shadow_pll_out_div"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_fixed_factor dsi0pll_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_post_vco_div", - .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_post_vco_div", - .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_post_vco_div", - .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_post_vco_div3_5 = { - .div = 7, - .mult = 2, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_post_vco_div3_5", - .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_post_vco_div3_5 = { - .div = 7, - .mult = 2, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_post_vco_div3_5", - .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_post_vco_div3_5 = { - .div = 7, - .mult = 2, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_post_vco_div3_5", - .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_post_vco_div3_5 = { - .div = 7, - .mult = 2, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_post_vco_div3_5", - .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_post_vco_div = { - .div = 4, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_post_vco_div", - .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_byteclk_src", - .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_byteclk_src", - .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_byteclk_src", - .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_cphy_byteclk_src = { - .div = 7, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_cphy_byteclk_src", - .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_cphy_byteclk_src = { - .div = 7, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_cphy_byteclk_src", - .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_cphy_byteclk_src = { - .div = 7, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_cphy_byteclk_src", - .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_cphy_byteclk_src = { - .div = 7, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_cphy_byteclk_src", - .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_byteclk_src = { - .div = 8, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_byteclk_src", - .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_post_bit_div", - .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi0pll_shadow_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_post_bit_div", - .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_post_bit_div", - .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_fixed_factor dsi1pll_shadow_post_bit_div = { - .div = 2, - .mult = 1, - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_post_bit_div", - .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, - .num_parents = 1, - .ops = &clk_fixed_factor_ops, - }, -}; - -static struct clk_regmap_mux dsi0pll_byteclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0_phy_pll_out_byteclk", - .parent_names = (const char *[]){"dsi0pll_byteclk_src", - "dsi0pll_shadow_byteclk_src", - "dsi0pll_cphy_byteclk_src", - "dsi0pll_shadow_cphy_byteclk_src"}, - .num_parents = 4, - .flags = (CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_byteclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1_phy_pll_out_byteclk", - .parent_names = (const char *[]){"dsi1pll_byteclk_src", - "dsi1pll_shadow_byteclk_src", - "dsi1pll_cphy_byteclk_src", - "dsi1pll_shadow_cphy_byteclk_src"}, - .num_parents = 4, - .flags = (CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pclk_src_mux", - .parent_names = (const char *[]){"dsi0pll_bitclk_src", - "dsi0pll_post_bit_div"}, - .num_parents = 2, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_shadow_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_pclk_src_mux", - .parent_names = (const char *[]){ - "dsi0pll_shadow_bitclk_src", - "dsi0pll_shadow_post_bit_div"}, - .num_parents = 2, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_cphy_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_cphy_pclk_src_mux", - .parent_names = - (const char *[]){"dsi0pll_post_vco_div3_5"}, - .num_parents = 1, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_shadow_cphy_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_cphy_pclk_src_mux", - .parent_names = - (const char *[]){ - "dsi0pll_shadow_post_vco_div3_5"}, - .num_parents = 1, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pclk_src_mux", - .parent_names = (const char *[]){"dsi1pll_bitclk_src", - "dsi1pll_post_bit_div"}, - .num_parents = 2, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_shadow_cphy_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_cphy_pclk_src_mux", - .parent_names = - (const char *[]){ - "dsi1pll_shadow_post_vco_div3_5"}, - .num_parents = 1, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_shadow_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_pclk_src_mux", - .parent_names = (const char *[]){ - "dsi1pll_shadow_bitclk_src", - "dsi1pll_shadow_post_bit_div"}, - .num_parents = 2, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_cphy_pclk_src_mux = { - .reg = PHY_CMN_CLK_CFG1, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_cphy_pclk_src_mux", - .parent_names = - (const char *[]){"dsi1pll_post_vco_div3_5"}, - .num_parents = 1, - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pclk_src", - .parent_names = (const char *[]){ - "dsi0pll_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_shadow_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_pclk_src", - .parent_names = (const char *[]){ - "dsi0pll_shadow_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_cphy_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_cphy_pclk_src", - .parent_names = (const char *[]){ - "dsi0pll_cphy_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi0pll_shadow_cphy_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_shadow_cphy_pclk_src", - .parent_names = (const char *[]){ - "dsi0pll_shadow_cphy_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pclk_src", - .parent_names = (const char *[]){ - "dsi1pll_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_shadow_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_pclk_src", - .parent_names = (const char *[]){ - "dsi1pll_shadow_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_cphy_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_cphy_pclk_src", - .parent_names = (const char *[]){ - "dsi1pll_cphy_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_div dsi1pll_shadow_cphy_pclk_src = { - .shift = 0, - .width = 4, - .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_shadow_cphy_pclk_src", - .parent_names = (const char *[]){ - "dsi1pll_shadow_cphy_pclk_src_mux"}, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_regmap_div_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi0pll_pclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0_phy_pll_out_dsiclk", - .parent_names = (const char *[]){"dsi0pll_pclk_src", - "dsi0pll_shadow_pclk_src", - "dsi0pll_cphy_pclk_src", - "dsi0pll_shadow_cphy_pclk_src"}, - .num_parents = 4, - .flags = (CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_regmap_mux dsi1pll_pclk_mux = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1_phy_pll_out_dsiclk", - .parent_names = (const char *[]){"dsi1pll_pclk_src", - "dsi1pll_shadow_pclk_src", - "dsi1pll_cphy_pclk_src", - "dsi1pll_shadow_cphy_pclk_src"}, - .num_parents = 4, - .flags = (CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT), - .ops = &clk_regmap_mux_closest_ops, - }, - }, -}; - -static struct clk_hw *dsi_pllcc_5nm[] = { - [VCO_CLK_0] = &dsi0pll_vco_clk.hw, - [PLL_OUT_DIV_0_CLK] = &dsi0pll_pll_out_div.clkr.hw, - [BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw, - [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw, - [CPHY_BYTECLK_SRC_0_CLK] = &dsi0pll_cphy_byteclk_src.hw, - [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.hw, - [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.hw, - [POST_VCO_DIV3_5_0_CLK] = &dsi0pll_post_vco_div3_5.hw, - [BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw, - [PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw, - [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw, - [PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw, - [CPHY_PCLK_SRC_MUX_0_CLK] = &dsi0pll_cphy_pclk_src_mux.clkr.hw, - [CPHY_PCLK_SRC_0_CLK] = &dsi0pll_cphy_pclk_src.clkr.hw, - [SHADOW_VCO_CLK_0] = &dsi0pll_shadow_vco_clk.hw, - [SHADOW_PLL_OUT_DIV_0_CLK] = &dsi0pll_shadow_pll_out_div.clkr.hw, - [SHADOW_BITCLK_SRC_0_CLK] = &dsi0pll_shadow_bitclk_src.clkr.hw, - [SHADOW_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_byteclk_src.hw, - [SHADOW_CPHY_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_cphy_byteclk_src.hw, - [SHADOW_POST_BIT_DIV_0_CLK] = &dsi0pll_shadow_post_bit_div.hw, - [SHADOW_POST_VCO_DIV_0_CLK] = &dsi0pll_shadow_post_vco_div.hw, - [SHADOW_POST_VCO_DIV3_5_0_CLK] = &dsi0pll_shadow_post_vco_div3_5.hw, - [SHADOW_PCLK_SRC_MUX_0_CLK] = &dsi0pll_shadow_pclk_src_mux.clkr.hw, - [SHADOW_PCLK_SRC_0_CLK] = &dsi0pll_shadow_pclk_src.clkr.hw, - [SHADOW_CPHY_PCLK_SRC_MUX_0_CLK] = - &dsi0pll_shadow_cphy_pclk_src_mux.clkr.hw, - [SHADOW_CPHY_PCLK_SRC_0_CLK] = &dsi0pll_shadow_cphy_pclk_src.clkr.hw, - [VCO_CLK_1] = &dsi1pll_vco_clk.hw, - [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw, - [BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw, - [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw, - [CPHY_BYTECLK_SRC_1_CLK] = &dsi1pll_cphy_byteclk_src.hw, - [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.hw, - [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.hw, - [POST_VCO_DIV3_5_1_CLK] = &dsi1pll_post_vco_div3_5.hw, - [BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw, - [PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw, - [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw, - [PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw, - [CPHY_PCLK_SRC_MUX_1_CLK] = &dsi1pll_cphy_pclk_src_mux.clkr.hw, - [CPHY_PCLK_SRC_1_CLK] = &dsi1pll_cphy_pclk_src.clkr.hw, - [SHADOW_VCO_CLK_1] = &dsi1pll_shadow_vco_clk.hw, - [SHADOW_PLL_OUT_DIV_1_CLK] = &dsi1pll_shadow_pll_out_div.clkr.hw, - [SHADOW_BITCLK_SRC_1_CLK] = &dsi1pll_shadow_bitclk_src.clkr.hw, - [SHADOW_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_byteclk_src.hw, - [SHADOW_CPHY_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_cphy_byteclk_src.hw, - [SHADOW_POST_BIT_DIV_1_CLK] = &dsi1pll_shadow_post_bit_div.hw, - [SHADOW_POST_VCO_DIV_1_CLK] = &dsi1pll_shadow_post_vco_div.hw, - [SHADOW_POST_VCO_DIV3_5_1_CLK] = &dsi1pll_shadow_post_vco_div3_5.hw, - [SHADOW_PCLK_SRC_MUX_1_CLK] = &dsi1pll_shadow_pclk_src_mux.clkr.hw, - [SHADOW_PCLK_SRC_1_CLK] = &dsi1pll_shadow_pclk_src.clkr.hw, - [SHADOW_CPHY_PCLK_SRC_MUX_1_CLK] = - &dsi1pll_shadow_cphy_pclk_src_mux.clkr.hw, - [SHADOW_CPHY_PCLK_SRC_1_CLK] = &dsi1pll_shadow_cphy_pclk_src.clkr.hw, -}; - -int dsi_pll_clock_register_5nm(struct platform_device *pdev, - struct dsi_pll_resource *pll_res) +int dsi_pll_5nm_toggle(void *pll, bool prepare) { - int rc = 0, ndx, i; - struct clk *clk; - struct clk_onecell_data *clk_data; - int num_clks = ARRAY_SIZE(dsi_pllcc_5nm); - struct regmap *rmap; - struct regmap_config *rmap_config; + int rc = 0; + struct dsi_pll_resource *pll_res = (struct dsi_pll_resource *)pll; - if (!pdev || !pdev->dev.of_node || - !pll_res || !pll_res->pll_base || !pll_res->phy_base) { - pr_err("Invalid params\n"); + if (!pll_res) { + DSI_PLL_ERR(pll_res, "dsi pll resources are not available\n"); return -EINVAL; } - ndx = pll_res->index; - - if (ndx >= DSI_PLL_MAX) { - pr_err("pll index(%d) NOT supported\n", ndx); - 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; - - 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; - - rmap_config = devm_kmemdup(&pdev->dev, &dsi_pll_5nm_config, - sizeof(struct regmap_config), GFP_KERNEL); - if (!rmap_config) - return -ENOMEM; - - /* Establish client data */ - if (ndx == 0) { - rmap_config->name = "pll_out"; - rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, - pll_res, rmap_config); - dsi0pll_pll_out_div.clkr.regmap = rmap; - dsi0pll_shadow_pll_out_div.clkr.regmap = rmap; - - rmap_config->name = "bitclk_src"; - rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, - pll_res, rmap_config); - dsi0pll_bitclk_src.clkr.regmap = rmap; - dsi0pll_shadow_bitclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_src"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, - pll_res, rmap_config); - dsi0pll_pclk_src.clkr.regmap = rmap; - dsi0pll_cphy_pclk_src.clkr.regmap = rmap; - dsi0pll_shadow_pclk_src.clkr.regmap = rmap; - dsi0pll_shadow_cphy_pclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_mux"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi0pll_pclk_mux.clkr.regmap = rmap; - - rmap_config->name = "pclk_src_mux"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, - pll_res, rmap_config); - dsi0pll_pclk_src_mux.clkr.regmap = rmap; - dsi0pll_shadow_pclk_src_mux.clkr.regmap = rmap; - - rmap_config->name = "cphy_pclk_src_mux"; - rmap = devm_regmap_init(&pdev->dev, - &cphy_pclk_src_mux_regmap_bus, - pll_res, rmap_config); - dsi0pll_cphy_pclk_src_mux.clkr.regmap = rmap; - dsi0pll_shadow_cphy_pclk_src_mux.clkr.regmap = rmap; - - rmap_config->name = "byteclk_mux"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi0pll_byteclk_mux.clkr.regmap = rmap; - - dsi0pll_vco_clk.priv = pll_res; - dsi0pll_shadow_vco_clk.priv = pll_res; - - if (dsi_pll_5nm_is_hw_revision(pll_res)) { - dsi0pll_vco_clk.min_rate = 600000000; - dsi0pll_vco_clk.max_rate = 5000000000; - dsi0pll_shadow_vco_clk.min_rate = 600000000; - dsi0pll_shadow_vco_clk.max_rate = 5000000000; - } - - for (i = VCO_CLK_0; i <= SHADOW_CPHY_PCLK_SRC_0_CLK; i++) { - clk = devm_clk_register(&pdev->dev, - dsi_pllcc_5nm[i]); - if (IS_ERR(clk)) { - pr_err("clk registration failed for DSI clock:%d\n", - pll_res->index); - rc = -EINVAL; - goto clk_register_fail; - } - clk_data->clks[i] = clk; - - } - - rc = of_clk_add_provider(pdev->dev.of_node, - of_clk_src_onecell_get, clk_data); + if (prepare) { + rc = dsi_pll_5nm_enable(pll_res); + if (rc) + DSI_PLL_ERR(pll_res, "enable failed: %d\n", rc); } else { - rmap_config->name = "pll_out"; - rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, - pll_res, rmap_config); - dsi1pll_pll_out_div.clkr.regmap = rmap; - dsi1pll_shadow_pll_out_div.clkr.regmap = rmap; - - rmap_config->name = "bitclk_src"; - rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, - pll_res, rmap_config); - dsi1pll_bitclk_src.clkr.regmap = rmap; - dsi1pll_shadow_bitclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_src"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, - pll_res, rmap_config); - dsi1pll_pclk_src.clkr.regmap = rmap; - dsi1pll_cphy_pclk_src.clkr.regmap = rmap; - dsi1pll_shadow_pclk_src.clkr.regmap = rmap; - dsi1pll_shadow_cphy_pclk_src.clkr.regmap = rmap; - - rmap_config->name = "pclk_mux"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi1pll_pclk_mux.clkr.regmap = rmap; - - rmap_config->name = "pclk_src_mux"; - rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, - pll_res, rmap_config); - dsi1pll_pclk_src_mux.clkr.regmap = rmap; - dsi1pll_shadow_pclk_src_mux.clkr.regmap = rmap; - dsi1pll_shadow_cphy_pclk_src_mux.clkr.regmap = rmap; - - rmap_config->name = "cphy_pclk_src_mux"; - rmap = devm_regmap_init(&pdev->dev, - &cphy_pclk_src_mux_regmap_bus, - pll_res, rmap_config); - dsi1pll_cphy_pclk_src_mux.clkr.regmap = rmap; - - rmap_config->name = "byteclk_mut"; - rmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, - pll_res, rmap_config); - dsi1pll_byteclk_mux.clkr.regmap = rmap; - - dsi1pll_vco_clk.priv = pll_res; - dsi1pll_shadow_vco_clk.priv = pll_res; - - if (dsi_pll_5nm_is_hw_revision(pll_res)) { - dsi1pll_vco_clk.min_rate = 600000000; - dsi1pll_vco_clk.max_rate = 5000000000; - dsi1pll_shadow_vco_clk.min_rate = 600000000; - dsi1pll_shadow_vco_clk.max_rate = 5000000000; - } - - for (i = VCO_CLK_1; i <= CPHY_PCLK_SRC_1_CLK; i++) { - clk = devm_clk_register(&pdev->dev, - dsi_pllcc_5nm[i]); - if (IS_ERR(clk)) { - pr_err("clk registration failed for DSI clock:%d\n", - pll_res->index); - rc = -EINVAL; - goto clk_register_fail; - } - clk_data->clks[i] = clk; - - } - - rc = of_clk_add_provider(pdev->dev.of_node, - of_clk_src_onecell_get, clk_data); + rc = dsi_pll_5nm_disable(pll_res); + if (rc) + DSI_PLL_ERR(pll_res, "disable failed: %d\n", rc); } - if (!rc) { - pr_info("Registered DSI PLL ndx=%d, clocks successfully\n", - ndx); - return rc; - } -clk_register_fail: return rc; } diff --git a/msm/dsi/dsi_pll_5nm.h b/msm/dsi/dsi_pll_5nm.h new file mode 100644 index 0000000000..113a9cdc85 --- /dev/null +++ b/msm/dsi/dsi_pll_5nm.h @@ -0,0 +1,250 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. 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_5nm_dphy[] = { + {60000000, 86670000, 2, 5}, + {86670000, 97500000, 1, 9}, + {97500000, 111430000, 8, 1}, + {111430000, 130000000, 1, 7}, + {130000000, 156000000, 2, 3}, + {150000000, 195000000, 1, 5}, + {195000000, 260000000, 4, 1}, + {260000000, 390000000, 1, 3}, + {390000000, 780000000, 2, 1}, + {780000000, 3500000000, 1, 1} +}; + +struct dsi_pll_div_table pll_5nm_cphy[] = { + {60000000, 97500000, 2, 5}, + {97500000, 130000000, 8, 1}, + {130000000, 156000000, 2, 3}, + {156000000, 195000000, 1, 5}, + {195000000, 260000000, 4, 1}, + {260000000, 390000000, 1, 3}, + {390000000, 780000000, 2, 1}, + {780000000, 3500000000, 1, 1} +};