disp: msm: dsi: add support for phy/pll bypass

This change adds support for bypassing hw access in DSI PHY/PLL
drivers which enables the DSI driver to run on emulation
platforms that might be missing those modules.

Change-Id: I3e83155a79d60f2357606746214d776cefabd651
Signed-off-by: Rajkumar Subbiah <quic_rsubbia@quicinc.com>
Signed-off-by: Shamika Joshi <quic_shamjosh@quicinc.com>
Signed-off-by: Alex Danila <quic_eadanila@quicinc.com>
This commit is contained in:
Rajkumar Subbiah
2022-01-21 08:34:35 -08:00
committed by Gerrit - the friendly Code Review server
parent 8f1d4ca416
commit 6d5a850504
16 changed files with 102 additions and 12 deletions

View File

@@ -111,6 +111,7 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
* @version: DSI controller version.
* @index: DSI controller instance ID.
* @phy_isolation_enabled: DSI controller works isolated from phy.
* @phy_pll_bypass: DSI PHY/PLL drivers bypass HW access.
* @null_insertion_enabled: DSI controller inserts null packet.
*
* This function setups the catalog information in the dsi_ctrl_hw object.
@@ -119,7 +120,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
*/
int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
enum dsi_ctrl_version version, u32 index,
bool phy_isolation_enabled, bool null_insertion_enabled)
bool phy_isolation_enabled, bool phy_pll_bypass,
bool null_insertion_enabled)
{
int rc = 0;
@@ -143,6 +145,7 @@ int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
case DSI_CTRL_VERSION_2_3:
case DSI_CTRL_VERSION_2_4:
ctrl->phy_isolation_enabled = phy_isolation_enabled;
ctrl->phy_pll_bypass = phy_pll_bypass;
dsi_catalog_cmn_init(ctrl, version);
break;
case DSI_CTRL_VERSION_2_5:
@@ -151,6 +154,7 @@ int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
case DSI_CTRL_VERSION_2_8:
ctrl->widebus_support = true;
ctrl->phy_isolation_enabled = phy_isolation_enabled;
ctrl->phy_pll_bypass = phy_pll_bypass;
dsi_catalog_cmn_init(ctrl, version);
break;
default:
@@ -324,6 +328,8 @@ int dsi_catalog_phy_pll_setup(struct dsi_phy_hw *phy, u32 pll_ver)
if (pll_ver >= DSI_PLL_VERSION_UNKNOWN) {
DSI_ERR("Unsupported version: %d\n", pll_ver);
return -EOPNOTSUPP;
} else if (phy->phy_pll_bypass) {
return 0;
}
switch (pll_ver) {

View File

@@ -16,6 +16,7 @@
* @version: DSI controller version.
* @index: DSI controller instance ID.
* @phy_isolation_enabled: DSI controller works isolated from phy.
* @phy_pll_bypass: DSI PHY/PLL drivers bypass HW access.
* @null_insertion_enabled: DSI controller inserts null packet.
*
* This function setups the catalog information in the dsi_ctrl_hw object.
@@ -24,7 +25,8 @@
*/
int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
enum dsi_ctrl_version version, u32 index,
bool phy_isolation_enabled, bool null_insertion_enabled);
bool phy_isolation_enabled, bool phy_pll_bypass,
bool null_insertion_enabled);
/**
* dsi_catalog_phy_setup() - return catalog info for dsi phy hardware

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _DSI_CLK_H_
@@ -209,6 +210,7 @@ typedef int (*pll_toggle_cb)(void *priv, bool prepare);
* @priv_data pointer to private data
* @master_ndx master DSI controller index
* @dsi_ctrl_count number of DSI controllers
* @phy_pll_bypass bypass PLL clock related operations
*/
struct dsi_clk_info {
char name[MAX_STRING_LEN];
@@ -225,6 +227,7 @@ struct dsi_clk_info {
void *priv_data;
u32 master_ndx;
u32 dsi_ctrl_count;
bool phy_pll_bypass;
};
/**

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/of.h>
@@ -41,6 +42,7 @@ struct dsi_clk_mngr {
pre_clockon_cb pre_clkon_cb;
bool is_cont_splash_enabled;
bool phy_pll_bypass;
void *priv_data;
};
@@ -119,6 +121,10 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index)
struct dsi_clk_mngr *mngr;
mngr = c->mngr;
if (mngr->phy_pll_bypass)
return 0;
rc = clk_set_rate(mngr->link_clks[index].hs_clks.pixel_clk, pixel_clk);
if (rc)
DSI_ERR("failed to set clk rate for pixel clk, rc=%d\n", rc);
@@ -144,6 +150,10 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk,
struct dsi_clk_mngr *mngr;
mngr = c->mngr;
if (mngr->phy_pll_bypass)
return 0;
rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
if (rc)
DSI_ERR("failed to set clk rate for byte clk, rc=%d\n", rc);
@@ -333,6 +343,9 @@ static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks,
if (mngr->is_cont_splash_enabled)
return 0;
if (mngr->phy_pll_bypass)
return 0;
rc = clk_set_rate(link_hs_clks->byte_clk,
l_clks->freq.byte_clk_rate);
if (rc) {
@@ -1451,6 +1464,7 @@ void *dsi_display_clk_mngr_register(struct dsi_clk_info *info)
mngr->phy_config_cb = info->phy_config_cb;
mngr->phy_pll_toggle_cb = info->phy_pll_toggle_cb;
mngr->priv_data = info->priv_data;
mngr->phy_pll_bypass = info->phy_pll_bypass;
memcpy(mngr->name, info->name, MAX_STRING_LEN);
error:

View File

@@ -2066,6 +2066,9 @@ static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl,
dsi_ctrl->split_link_supported = of_property_read_bool(of_node,
"qcom,split-link-supported");
dsi_ctrl->phy_pll_bypass = of_property_read_bool(of_node,
"qcom,dsi-phy-pll-bypass");
rc = of_property_read_u32(of_node, "frame-threshold-time-us",
&frame_threshold_time_us);
if (rc) {
@@ -2139,7 +2142,7 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev)
rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version,
dsi_ctrl->cell_index, dsi_ctrl->phy_isolation_enabled,
dsi_ctrl->null_insertion_enabled);
dsi_ctrl->phy_pll_bypass, dsi_ctrl->null_insertion_enabled);
if (rc) {
DSI_CTRL_ERR(dsi_ctrl, "Catalog does not support version (%d)\n",
dsi_ctrl->version);

View File

@@ -234,6 +234,8 @@ struct dsi_ctrl_interrupts {
* next TE for command mode.
* @phy_isolation_enabled: A boolean property allows to isolate the phy from
* dsi controller and run only dsi controller.
* @phy_pll_bypass: A boolean property that enables skipping HW access in
* DSI PHY/PLL drivers for running on emulation platforms.
* @null_insertion_enabled: A boolean property to allow dsi controller to
* insert null packet.
* @modeupdated: Boolean to send new roi if mode is updated.
@@ -310,6 +312,7 @@ struct dsi_ctrl {
unsigned int error_interrupt_count;
bool phy_isolation_enabled;
bool phy_pll_bypass;
bool null_insertion_enabled;
bool modeupdated;
bool split_link_supported;

View File

@@ -948,6 +948,8 @@ struct dsi_ctrl_hw_ops {
* @supported_errors: Number of supported errors.
* @phy_isolation_enabled: A boolean property allows to isolate the phy from
* dsi controller and run only dsi controller.
* @phy_pll_bypass: A boolean property that enables skipping HW access in
* PHY/PLL drivers for running on emulation platforms.
* @null_insertion_enabled: A boolean property to allow dsi controller to
* insert null packet.
* @widebus_support: 48 bit wide data bus is supported.
@@ -973,6 +975,7 @@ struct dsi_ctrl_hw {
u64 supported_errors;
bool phy_isolation_enabled;
bool phy_pll_bypass;
bool null_insertion_enabled;
bool widebus_support;
bool reset_trig_ctrl;

View File

@@ -1440,6 +1440,11 @@ void dsi_ctrl_hw_cmn_enable_error_interrupts(struct dsi_ctrl_hw *ctrl,
else
int_ctrl &= ~BIT(25);
if (ctrl->phy_pll_bypass) {
int_ctrl &= ~BIT(25);
goto dsi_write;
}
/* Do not clear interrupt status */
int_ctrl &= 0xAAEEAAFE;
@@ -1499,6 +1504,7 @@ void dsi_ctrl_hw_cmn_enable_error_interrupts(struct dsi_ctrl_hw *ctrl,
if (errors & DSI_INTERLEAVE_OP_CONTENTION)
int_mask0 &= ~BIT(8);
dsi_write:
DSI_W32(ctrl, DSI_INT_CTRL, int_ctrl);
DSI_W32(ctrl, DSI_ERR_INT_MASK0, int_mask0);

View File

@@ -70,6 +70,11 @@ static bool is_sim_panel(struct dsi_display *display)
display->panel->panel_ack_disabled);
}
static bool phy_pll_bypass(struct dsi_display *display)
{
return display->ctrl[display->cmd_master_idx].phy->hw.phy_pll_bypass;
}
static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display,
u32 mask, bool enable)
{
@@ -773,6 +778,9 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
if (!dsi_ctrl_validate_host_state(ctrl->ctrl))
return 1;
if (phy_pll_bypass(display))
return 0;
config = &(panel->esd_config);
lenp = config->status_valid_params ?: config->status_cmds_rlen;
count = config->status_cmd.count;
@@ -1067,6 +1075,9 @@ static int dsi_display_cmd_rx(struct dsi_display *display,
goto release_panel_lock;
}
if (phy_pll_bypass(display))
goto release_panel_lock;
flags = DSI_CTRL_CMD_READ;
dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON);
@@ -2810,7 +2821,7 @@ int dsi_display_phy_pll_toggle(void *priv, bool prepare)
return -EINVAL;
}
if (is_skip_op_required(display))
if (is_skip_op_required(display) || phy_pll_bypass(display))
return 0;
if (prepare)
@@ -3254,6 +3265,9 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display, struct dsi_cmd
int i;
u32 flags = 0;
if (phy_pll_bypass(display))
return 0;
/*
* 1. Setup commands in FIFO
* 2. Trigger commands
@@ -3335,7 +3349,7 @@ static int dsi_display_phy_sw_reset(struct dsi_display *display)
* ctrl states are updated separately and hence we do
* an early return
*/
if (is_skip_op_required(display)) {
if (is_skip_op_required(display) || phy_pll_bypass(display)) {
DSI_DEBUG(
"cont splash/trusted vm use case, phy sw reset not required\n");
return 0;
@@ -3390,6 +3404,9 @@ int dsi_host_transfer_sub(struct mipi_dsi_host *host, struct dsi_cmd_desc *cmd)
display = to_dsi_display(host);
if (phy_pll_bypass(display))
return 0;
/* Avoid sending DCS commands when ESD recovery is pending */
if (atomic_read(&display->panel->esd_recovery_pending)) {
DSI_DEBUG("ESD recovery pending\n");
@@ -5689,6 +5706,7 @@ static int dsi_display_bind(struct device *dev,
info.priv_data = display;
info.master_ndx = display->clk_master_idx;
info.dsi_ctrl_count = display->ctrl_count;
info.phy_pll_bypass = phy_pll_bypass(display);
snprintf(info.name, MAX_STRING_LEN,
"DSI_MNGR-%s", display->name);

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/of_device.h>
@@ -405,6 +405,9 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
if (!dsi_phy->name)
dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
dsi_phy->hw.phy_pll_bypass = of_property_read_bool(pdev->dev.of_node,
"qcom,dsi-phy-pll-bypass");
DSI_PHY_DBG(dsi_phy, "Probing device\n");
dsi_phy->ver_info = ver_info;

View File

@@ -392,6 +392,7 @@ struct dsi_phy_hw_ops {
* @dyn_pll_base: VA for the DSI dynamic refresh base address.
* @length: Length of the DSI dynamic refresh register base map.
* @index: Instance ID of the controller.
* @phy_pll_bypass: DSI PHY bypass
* @version: DSI PHY version.
* @phy_clamp_base: Base address of phy clamp register map.
* @feature_map: Features supported by DSI PHY.
@@ -403,6 +404,7 @@ struct dsi_phy_hw {
void __iomem *dyn_pll_base;
u32 dyn_refresh_len;
u32 index;
bool phy_pll_bypass;
enum dsi_phy_version version;
void __iomem *phy_clamp_base;

View File

@@ -119,6 +119,9 @@ static int dsi_phy_hw_v5_0_is_pll_on(struct dsi_phy_hw *phy)
{
u32 data = 0;
if (phy->phy_pll_bypass)
return 0;
data = DSI_R32(phy, DSIPHY_CMN_PLL_CNTRL);
mb(); /*make sure read happened */
return (data & BIT(0));
@@ -435,6 +438,7 @@ void dsi_phy_hw_v5_0_enable(struct dsi_phy_hw *phy,
DSI_W32(phy, DSIPHY_CMN_GLBL_DIGTOP_SPARE10, 0x1);
udelay(500);
if (!phy->phy_pll_bypass) {
/* wait for REFGEN READY */
rc = DSI_READ_POLL_TIMEOUT_ATOMIC(phy, DSIPHY_CMN_PHY_STATUS,
status, (status & BIT(0)), delay_us, timeout_us);
@@ -442,6 +446,7 @@ void dsi_phy_hw_v5_0_enable(struct dsi_phy_hw *phy,
DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n");
return;
}
}
if (cfg->phy_type == DSI_PHY_TYPE_CPHY)
dsi_phy_hw_cphy_enable(phy, cfg);
@@ -459,6 +464,9 @@ void dsi_phy_hw_v5_0_disable(struct dsi_phy_hw *phy,
{
u32 data = 0;
if (phy->phy_pll_bypass)
return;
if (dsi_phy_hw_v5_0_is_pll_on(phy))
DSI_PHY_WARN(phy, "Turning OFF PHY while PLL is on\n");
@@ -497,6 +505,9 @@ void dsi_phy_hw_v5_0_reset_clk_en_sel(struct dsi_phy_hw *phy)
{
u32 data = 0;
if (phy->phy_pll_bypass)
return;
/*Turning off CLK_EN_SEL after retime buffer sync */
data = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1);
data &= ~BIT(4);
@@ -514,6 +525,9 @@ int dsi_phy_hw_v5_0_wait_for_lane_idle(
u32 const timeout_us = 100;
bool split_link_enabled = dsi_phy_hw_v5_0_is_split_link_enabled(phy);
if (phy->phy_pll_bypass)
return 0;
stop_state_mask = BIT(4); /* clock lane */
if (split_link_enabled)
stop_state_mask |= BIT(5);

View File

@@ -304,6 +304,8 @@ int dsi_pll_init(struct platform_device *pdev, struct dsi_pll_resource **pll)
pll_res->ssc_center = true;
}
pll_res->phy_pll_bypass = of_property_read_bool(pdev->dev.of_node,
"qcom,dsi-phy-pll-bypass");
if (dsi_pll_get_ioresources(pdev, &pll_res->pll_base, "pll_base")) {
DSI_PLL_ERR(pll_res, "Unable to remap pll base resources\n");
@@ -335,6 +337,9 @@ int dsi_pll_init(struct platform_device *pdev, struct dsi_pll_resource **pll)
return rc;
}
if (pll_res->phy_pll_bypass)
return 0;
rc = dsi_pll_clock_register(pdev, pll_res);
if (rc) {
DSI_PLL_ERR(pll_res, "clock register failed rc=%d\n", rc);

View File

@@ -169,6 +169,8 @@ struct dsi_pll_resource {
int bpp;
int lanes;
bool phy_pll_bypass;
/*
* DSI PHY type DPHY/CPHY
*/

View File

@@ -548,6 +548,9 @@ static int dsi_pll_4nm_lock_status(struct dsi_pll_resource *pll)
u32 const delay_us = 100;
u32 const timeout_us = 5000;
if (pll->phy_pll_bypass)
return 0;
rc = DSI_READ_POLL_TIMEOUT_ATOMIC_GEN(pll->pll_base, pll->index, PLL_COMMON_STATUS_ONE,
status,
((status & BIT(0)) > 0),

View File

@@ -4720,6 +4720,9 @@ static int _sde_kms_get_splash_data(struct sde_splash_data *data)
int num_displays, num_regions;
struct sde_splash_display *splash_display;
if (of_find_node_with_property(NULL, "qcom,sde-emulated-env"))
return 0;
if (!data)
return -EINVAL;