disp: msm: dsi: update PHY configuration to support cphy

Add support to read cphy boolean flag from panel dtsi
and configure DSI PHY registers accordingly. Update the
bit/byte clock calculation according to cphy specifications.
Update clock parents so that the relevant divider blocks
are configured to support cphy.

Change-Id: Iaca61eec01a488657b086f59910c52f8c79e26a4
Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org>
Signed-off-by: Yuan Zhao <yzhao@codeaurora.org>
This commit is contained in:
Yuan Zhao
2020-05-07 00:34:24 +08:00
committed by Gerrit - the friendly Code Review server
orang tua 43069ad44a
melakukan 5139cad2d4
9 mengubah file dengan 240 tambahan dan 35 penghapusan

Melihat File

@@ -865,6 +865,7 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
{
int rc = 0;
u32 num_of_lanes = 0;
u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */
u32 bpp, frame_time_us, byte_intf_clk_div;
u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane,
byte_clk_rate, byte_intf_clk_rate;
@@ -895,6 +896,10 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
if (config->bit_clk_rate_hz_override != 0) {
bit_rate = config->bit_clk_rate_hz_override * num_of_lanes;
if (host_cfg->phy_type == DSI_PHY_TYPE_CPHY) {
bit_rate *= bits_per_symbol;
do_div(bit_rate, num_of_symbols);
}
} else if (config->panel_mode == DSI_OP_CMD_MODE) {
/* Calculate the bit rate needed to match dsi transfer time */
bit_rate = min_dsi_clk_hz * frame_time_us;
@@ -906,16 +911,29 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
bit_rate = h_period * v_period * timing->refresh_rate * bpp;
}
bit_rate_per_lane = bit_rate;
do_div(bit_rate_per_lane, num_of_lanes);
pclk_rate = bit_rate;
do_div(pclk_rate, bpp);
byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 8);
byte_intf_clk_rate = byte_clk_rate;
byte_intf_clk_div = host_cfg->byte_intf_clk_div;
do_div(byte_intf_clk_rate, byte_intf_clk_div);
if (host_cfg->phy_type == DSI_PHY_TYPE_DPHY) {
bit_rate_per_lane = bit_rate;
do_div(bit_rate_per_lane, num_of_lanes);
byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 8);
byte_intf_clk_rate = byte_clk_rate;
byte_intf_clk_div = host_cfg->byte_intf_clk_div;
do_div(byte_intf_clk_rate, byte_intf_clk_div);
config->bit_clk_rate_hz = byte_clk_rate * 8;
} else {
do_div(bit_rate, bits_per_symbol);
bit_rate *= num_of_symbols;
bit_rate_per_lane = bit_rate;
do_div(bit_rate_per_lane, num_of_lanes);
byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 7);
/* For CPHY, byte_intf_clk is same as byte_clk */
byte_intf_clk_rate = byte_clk_rate;
config->bit_clk_rate_hz = byte_clk_rate * 7;
}
DSI_CTRL_DEBUG(dsi_ctrl, "bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
bit_rate, bit_rate_per_lane);
DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, byte_intf_clk = %llu\n",
@@ -923,10 +941,9 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
DSI_CTRL_DEBUG(dsi_ctrl, "pclk_rate = %llu\n", pclk_rate);
dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate;
dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate;
dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz;
dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate;
config->bit_clk_rate_hz = dsi_ctrl->clk_freq.byte_clk_rate * 8;
rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq,
dsi_ctrl->cell_index);

Melihat File

@@ -135,6 +135,9 @@ void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl,
DSI_W32(ctrl, DSI_CTRL, reg_value);
if (cfg->phy_type == DSI_PHY_TYPE_CPHY)
DSI_W32(ctrl, DSI_CPHY_MODE_CTRL, BIT(0));
if (ctrl->phy_isolation_enabled)
DSI_W32(ctrl, DSI_DEBUG_CTRL, BIT(28));
DSI_CTRL_HW_DBG(ctrl, "Host configuration complete\n");

Melihat File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _DSI_CTRL_REG_H_
@@ -144,6 +144,7 @@
#define DSI_SECURE_DISPLAY_STATUS (0x02CC)
#define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0)
#define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4)
#define DSI_CPHY_MODE_CTRL (0x02D8)
#define DSI_LOGICAL_LANE_SWAP_CTRL (0x0310)
#define DSI_SPLIT_LINK (0x0330)

Melihat File

@@ -469,6 +469,7 @@ struct dsi_split_link_config {
* true.
* @ext_bridge_mode: External bridge is connected.
* @force_hs_clk_lane: Send continuous clock to the panel.
* @phy_type: DPHY/CPHY is enabled for this panel.
* @dsi_split_link_config: Split Link Configuration.
* @byte_intf_clk_div: Determines the factor for calculating byte intf clock.
*/
@@ -493,6 +494,7 @@ struct dsi_host_common_cfg {
bool append_tx_eot;
bool ext_bridge_mode;
bool force_hs_clk_lane;
enum dsi_phy_type phy_type;
struct dsi_split_link_config split_link;
u32 byte_intf_clk_div;
};

Melihat File

@@ -2316,6 +2316,20 @@ static int dsi_display_set_clk_src(struct dsi_display *display)
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
@@ -2382,8 +2396,12 @@ static void dsi_display_toggle_resync_fifo(struct dsi_display *display)
/*
* After retime buffer synchronization we need to turn of clk_en_sel
* bit on each phy.
* bit on each phy. Avoid this for Cphy.
*/
if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY)
return;
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
dsi_phy_reset_clk_en_sel(ctrl->phy);
@@ -3038,10 +3056,12 @@ static int dsi_display_clocks_init(struct dsi_display *display)
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";
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_dyn_clk_caps *dyn_clk_caps = &(display->panel->dyn_clk_caps);
char *dsi_clock_name;
@@ -3076,6 +3096,15 @@ static int dsi_display_clocks_init(struct dsi_display *display)
goto error;
}
if (dsi_display_check_prefix(cphy_byte, clk_name)) {
cphy->byte_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)) {
@@ -3107,6 +3136,16 @@ static int dsi_display_clocks_init(struct dsi_display *display)
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;
@@ -3729,6 +3768,8 @@ static int dsi_display_res_init(struct dsi_display *display)
phy->cfg.force_clk_lane_hs =
display->panel->host_config.force_hs_clk_lane;
phy->cfg.phy_type =
display->panel->host_config.phy_type;
}
rc = dsi_display_parse_lane_map(display);
@@ -3942,6 +3983,7 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
u32 num_of_lanes = 0, bpp, byte_intf_clk_div;
u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate,
byte_intf_clk_rate;
u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */
struct dsi_host_common_cfg *host_cfg;
mutex_lock(&ctrl->ctrl_lock);
@@ -3969,11 +4011,24 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
do_div(bit_rate_per_lane, num_of_lanes);
pclk_rate = bit_rate;
do_div(pclk_rate, bpp);
byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 8);
byte_intf_clk_rate = byte_clk_rate;
byte_intf_clk_div = host_cfg->byte_intf_clk_div;
do_div(byte_intf_clk_rate, byte_intf_clk_div);
if (host_cfg->phy_type == DSI_PHY_TYPE_DPHY) {
bit_rate_per_lane = bit_rate;
do_div(bit_rate_per_lane, num_of_lanes);
byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 8);
byte_intf_clk_rate = byte_clk_rate;
byte_intf_clk_div = host_cfg->byte_intf_clk_div;
do_div(byte_intf_clk_rate, byte_intf_clk_div);
} else {
do_div(bit_rate, bits_per_symbol);
bit_rate *= num_of_symbols;
bit_rate_per_lane = bit_rate;
do_div(bit_rate_per_lane, num_of_lanes);
byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 7);
/* For CPHY, byte_intf_clk is same as byte_clk */
byte_intf_clk_rate = byte_clk_rate;
}
DSI_DEBUG("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
bit_rate, bit_rate_per_lane);

Melihat File

@@ -111,6 +111,7 @@ struct dsi_display_boot_param {
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;
};

Melihat File

@@ -1043,6 +1043,7 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host,
{
u32 val = 0;
int rc = 0;
bool panel_cphy_mode = false;
rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-post", &val);
if (!rc) {
@@ -1068,6 +1069,11 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host,
host->force_hs_clk_lane = utils->read_bool(utils->data,
"qcom,mdss-dsi-force-clock-lane-hs");
panel_cphy_mode = utils->read_bool(utils->data,
"qcom,panel-cphy-mode");
host->phy_type = panel_cphy_mode ? DSI_PHY_TYPE_CPHY
: DSI_PHY_TYPE_DPHY;
return 0;
}

Melihat File

@@ -100,6 +100,7 @@ struct dsi_phy_per_lane_cfgs {
* @pll_source: PLL source.
* @lane_map: DSI logical to PHY lane mapping.
* @force_clk_lane_hs:Boolean whether to force clock lane in HS mode.
* @phy_type: Phy-type (Dphy/Cphy).
* @bit_clk_rate_hz: DSI bit clk rate in HZ.
*/
struct dsi_phy_cfg {
@@ -111,6 +112,7 @@ struct dsi_phy_cfg {
enum dsi_phy_pll_source pll_source;
struct dsi_lane_map lane_map;
bool force_clk_lane_hs;
enum dsi_phy_type phy_type;
unsigned long bit_clk_rate_hz;
};

Melihat File

@@ -205,18 +205,115 @@ void dsi_phy_hw_v4_0_commit_phy_timing(struct dsi_phy_hw *phy,
}
/**
* enable() - Enable PHY hardware
* cphy_enable() - Enable CPHY hardware
* @phy: Pointer to DSI PHY hardware object.
* @cfg: Per lane configurations for timing, strength and lane
* configurations.
*/
void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy,
static void dsi_phy_hw_cphy_enable(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg)
{
struct dsi_phy_per_lane_cfgs *timing = &cfg->timing;
u32 data;
u32 minor_ver = 0;
/* For C-PHY, no low power settings for lower clk rate */
u32 vreg_ctrl_0 = 0x51;
u32 glbl_str_swi_cal_sel_ctrl = 0;
u32 glbl_hstx_str_ctrl_0 = 0;
u32 glbl_rescode_top_ctrl = 0;
u32 glbl_rescode_bot_ctrl = 0;
if (phy->version == DSI_PHY_VERSION_4_1) {
glbl_rescode_top_ctrl = 0x00;
glbl_rescode_bot_ctrl = 0x3C;
glbl_str_swi_cal_sel_ctrl = 0x00;
glbl_hstx_str_ctrl_0 = 0x88;
} else {
glbl_str_swi_cal_sel_ctrl = 0x03;
glbl_hstx_str_ctrl_0 = 0x66;
glbl_rescode_top_ctrl = 0x03;
glbl_rescode_bot_ctrl = 0x3c;
}
/* de-assert digital and pll power down */
data = BIT(6) | BIT(5);
DSI_W32(phy, DSIPHY_CMN_CTRL_0, data);
/* Assert PLL core reset */
DSI_W32(phy, DSIPHY_CMN_PLL_CNTRL, 0x00);
/* turn off resync FIFO */
DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00);
/* program CMN_CTRL_4 for minor_ver 2 chipsets*/
minor_ver = DSI_R32(phy, DSIPHY_CMN_REVISION_ID0);
minor_ver = minor_ver & (0xf0);
if (minor_ver == 0x20)
DSI_W32(phy, DSIPHY_CMN_CTRL_4, 0x04);
/* Configure PHY lane swap */
dsi_phy_hw_v4_0_lane_swap_config(phy, &cfg->lane_map);
DSI_W32(phy, DSIPHY_CMN_GLBL_CTRL, BIT(6));
/* Enable LDO */
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0);
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x55);
DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL,
glbl_str_swi_cal_sel_ctrl);
DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, glbl_hstx_str_ctrl_0);
DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_0, 0x11);
DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_1, 0x01);
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL,
glbl_rescode_top_ctrl);
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL,
glbl_rescode_bot_ctrl);
DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55);
/* Remove power down from all blocks */
DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f);
DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x17);
switch (cfg->pll_source) {
case DSI_PLL_SOURCE_STANDALONE:
case DSI_PLL_SOURCE_NATIVE:
data = 0x0; /* internal PLL */
break;
case DSI_PLL_SOURCE_NON_NATIVE:
data = 0x1; /* external PLL */
break;
default:
break;
}
DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, (data << 2)); /* set PLL src */
/* DSI PHY timings */
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_0, timing->lane_v4[0]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_4, timing->lane_v4[4]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_5, timing->lane_v4[5]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_6, timing->lane_v4[6]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_7, timing->lane_v4[7]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_8, timing->lane_v4[8]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_9, timing->lane_v4[9]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_10, timing->lane_v4[10]);
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_11, timing->lane_v4[11]);
/* DSI lane settings */
dsi_phy_hw_v4_0_lane_settings(phy, cfg);
DSI_PHY_DBG(phy, "C-Phy enabled\n");
}
/**
* dphy_enable() - Enable DPHY hardware
* @phy: Pointer to DSI PHY hardware object.
* @cfg: Per lane configurations for timing, strength and lane
* configurations.
*/
static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg)
{
int rc = 0;
u32 status;
u32 const delay_us = 5;
u32 const timeout_us = 1000;
struct dsi_phy_per_lane_cfgs *timing = &cfg->timing;
u32 data;
u32 minor_ver = 0;
@@ -227,17 +324,6 @@ void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy,
u32 glbl_rescode_top_ctrl = 0;
u32 glbl_rescode_bot_ctrl = 0;
if (dsi_phy_hw_v4_0_is_pll_on(phy))
DSI_PHY_WARN(phy, "PLL turned on before configuring PHY\n");
/* wait for REFGEN READY */
rc = readl_poll_timeout_atomic(phy->base + DSIPHY_CMN_PHY_STATUS,
status, (status & BIT(0)), delay_us, timeout_us);
if (rc) {
DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n");
return;
}
/* Alter PHY configurations if data rate less than 1.5GHZ*/
if (cfg->bit_clk_rate_hz <= 1500000000)
less_than_1500_mhz = true;
@@ -322,7 +408,39 @@ void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy,
/* DSI lane settings */
dsi_phy_hw_v4_0_lane_settings(phy, cfg);
DSI_PHY_DBG(phy, "Phy enabled\n");
DSI_PHY_DBG(phy, "D-Phy enabled\n");
}
/**
* enable() - Enable PHY hardware
* @phy: Pointer to DSI PHY hardware object.
* @cfg: Per lane configurations for timing, strength and lane
* configurations.
*/
void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg)
{
int rc = 0;
u32 status;
u32 const delay_us = 5;
u32 const timeout_us = 1000;
if (dsi_phy_hw_v4_0_is_pll_on(phy))
pr_warn("PLL turned on before configuring PHY\n");
/* wait for REFGEN READY */
rc = readl_poll_timeout_atomic(phy->base + DSIPHY_CMN_PHY_STATUS,
status, (status & BIT(0)), delay_us, timeout_us);
if (rc) {
DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n");
return;
}
if (cfg->phy_type == DSI_PHY_TYPE_CPHY)
dsi_phy_hw_cphy_enable(phy, cfg);
else /* Default PHY type is DPHY */
dsi_phy_hw_dphy_enable(phy, cfg);
}
/**