Merge "disp: msm: dsi: rework DSI PLL to be configured within PHY" into display-kernel.lnx.5.10

This commit is contained in:
Linux Build Service Account
2021-01-13 14:24:33 -08:00
committed by Gerrit - the friendly Code Review server
16 changed files with 1174 additions and 4195 deletions

View File

@@ -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 \

View File

@@ -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 <linux/errno.h>
@@ -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;
}

View File

@@ -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_ */

View File

@@ -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;

View File

@@ -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 <linux/of.h>
@@ -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);

View File

@@ -742,6 +742,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;

View File

@@ -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(pll_byte, clk_name)) {
pll->byte_clk = dsi_clk;
continue;
}
}
if (dsi_display_check_prefix(src_byte, clk_name)) {
src->byte_clk = dsi_clk;
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;
}
@@ -5530,6 +5424,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;

View File

@@ -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;
};
/**

View File

@@ -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 <linux/of_device.h>
@@ -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)
{

View File

@@ -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_ */

View File

@@ -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);
};
/**

View File

@@ -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;

View File

@@ -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 dsi_pll_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_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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

250
msm/dsi/dsi_pll_5nm.h Normal file
View File

@@ -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}
};