disp: msm: dsi: snapshot of dsi from 4.14 to 4.19

This change is a snapshot of dsi files taken of 4.14
as of commit 764f7c2 (Merge remote-tracking branch
'quic/dev/msm-4.14-display' into msm-4.14)

Change-Id: I8361a844c35a4450f7800964a8da2741676fd6c7
Signed-off-by: Satya Rama Aditya Pinapala <psraditya30@codeaurora.org>
This commit is contained in:
Satya Rama Aditya Pinapala 2019-05-23 09:48:41 -07:00 committed by Gerrit - the friendly Code Review server
parent 91f4bcda9d
commit edef6ae040
21 changed files with 632 additions and 171 deletions

View File

@ -64,6 +64,7 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
ctrl->ops.set_continuous_clk = dsi_ctrl_hw_cmn_set_continuous_clk;
ctrl->ops.wait4dynamic_refresh_done =
dsi_ctrl_hw_cmn_wait4dynamic_refresh_done;
ctrl->ops.hs_req_sel = dsi_ctrl_hw_cmn_hs_req_sel;
switch (version) {
case DSI_CTRL_VERSION_1_4:
@ -261,6 +262,7 @@ static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy)
dsi_phy_hw_v4_0_dyn_refresh_helper;
phy->ops.dyn_refresh_ops.cache_phy_timings =
dsi_phy_hw_v4_0_cache_phy_timings;
phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk;
}
/**

View File

@ -115,6 +115,7 @@ int dsi_phy_hw_timing_val_v4_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
int dsi_phy_hw_v4_0_lane_reset(struct dsi_phy_hw *phy);
void dsi_phy_hw_v4_0_toggle_resync_fifo(struct dsi_phy_hw *phy);
void dsi_phy_hw_v4_0_reset_clk_en_sel(struct dsi_phy_hw *phy);
void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable);
/* DSI controller common ops */
u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl);
@ -239,6 +240,7 @@ void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable,
enum dsi_clk_gate_type clk_selection);
void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable);
void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy);
/* dynamic refresh specific functions */
void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);

View File

@ -1272,23 +1272,15 @@ static int dsi_display_link_clk_force_update(void *client)
goto error;
}
rc = dsi_display_link_clk_disable(l_clks,
(DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
mngr->dsi_ctrl_count, mngr->master_ndx);
if (rc) {
pr_err("%s, failed to stop link clk, rc = %d\n",
__func__, rc);
rc = dsi_clk_update_link_clk_state(mngr, l_clks, (DSI_LINK_LP_CLK |
DSI_LINK_HS_CLK), DSI_CLK_OFF, false);
if (rc)
goto error;
}
rc = dsi_display_link_clk_enable(l_clks,
(DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
mngr->dsi_ctrl_count, mngr->master_ndx);
if (rc) {
pr_err("%s, failed to start link clk rc= %d\n",
__func__, rc);
rc = dsi_clk_update_link_clk_state(mngr, l_clks, (DSI_LINK_LP_CLK |
DSI_LINK_HS_CLK), DSI_CLK_ON, true);
if (rc)
goto error;
}
error:
mutex_unlock(&mngr->clk_mutex);

View File

@ -34,22 +34,6 @@
#define TICKS_IN_MICRO_SECOND 1000000
/**
* enum dsi_ctrl_driver_ops - controller driver ops
*/
enum dsi_ctrl_driver_ops {
DSI_CTRL_OP_POWER_STATE_CHANGE,
DSI_CTRL_OP_CMD_ENGINE,
DSI_CTRL_OP_VID_ENGINE,
DSI_CTRL_OP_HOST_ENGINE,
DSI_CTRL_OP_CMD_TX,
DSI_CTRL_OP_HOST_INIT,
DSI_CTRL_OP_TPG,
DSI_CTRL_OP_PHY_SW_RESET,
DSI_CTRL_OP_ASYNC_TIMING,
DSI_CTRL_OP_MAX
};
struct dsi_ctrl_list_item {
struct dsi_ctrl *ctrl;
struct list_head list;
@ -833,6 +817,7 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane,
byte_clk_rate;
struct dsi_host_common_cfg *host_cfg = &config->common_config;
struct dsi_split_link_config *split_link = &host_cfg->split_link;
struct dsi_mode_info *timing = &config->video_timing;
u64 dsi_transfer_time_us = mode->priv_info->dsi_transfer_time_us;
u64 min_dsi_clk_hz = mode->priv_info->min_dsi_clk_hz;
@ -850,6 +835,9 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
if (host_cfg->data_lanes & DSI_DATA_LANE_3)
num_of_lanes++;
if (split_link->split_link_enabled)
num_of_lanes = split_link->lanes_per_sublink;
config->common_config.num_data_lanes = num_of_lanes;
config->common_config.bpp = bpp;
@ -943,6 +931,7 @@ static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl,
int rc = 0;
u8 *buf = NULL;
u32 len, i;
u8 cmd_type = 0;
len = packet->size;
len += 0x3; len &= ~0x03; /* Align to 32 bits */
@ -965,7 +954,11 @@ static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl,
/* send embedded BTA for read commands */
if ((buf[2] & 0x3f) == MIPI_DSI_DCS_READ)
cmd_type = buf[2] & 0x3f;
if ((cmd_type == MIPI_DSI_DCS_READ) ||
(cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) ||
(cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) ||
(cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM))
buf[3] |= BIT(5);
*buffer = buf;
@ -1509,7 +1502,7 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,
cmd = buff[0];
switch (cmd) {
case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
pr_err("Rx ACK_ERROR\n");
pr_err("Rx ACK_ERROR 0x%x\n", cmd);
rc = 0;
break;
case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
@ -1525,7 +1518,7 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,
rc = dsi_parse_long_read_resp(msg, buff);
break;
default:
pr_warn("Invalid response\n");
pr_warn("Invalid response: 0x%x\n", cmd);
rc = 0;
}
@ -1601,6 +1594,18 @@ static int dsi_disable_ulps(struct dsi_ctrl *dsi_ctrl)
return rc;
}
static void dsi_ctrl_enable_error_interrupts(struct dsi_ctrl *dsi_ctrl)
{
if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE &&
!dsi_ctrl->host_config.u.video_engine.bllp_lp11_en &&
!dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en)
dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw,
0xFF00A0);
else
dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw,
0xFF00E0);
}
static int dsi_ctrl_drv_state_init(struct dsi_ctrl *dsi_ctrl)
{
int rc = 0;
@ -1730,6 +1735,9 @@ static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl,
dsi_ctrl->null_insertion_enabled = of_property_read_bool(of_node,
"qcom,null-insertion-enabled");
dsi_ctrl->split_link_supported = of_property_read_bool(of_node,
"qcom,split-link-supported");
rc = of_property_read_u32(of_node, "frame-threshold-time-us",
&frame_threshold_time_us);
if (rc) {
@ -2217,7 +2225,7 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl)
}
dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0);
dsi_ctrl_enable_error_interrupts(dsi_ctrl);
dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true);
mutex_unlock(&dsi_ctrl->ctrl_lock);
@ -2340,6 +2348,12 @@ static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl,
if (error & 0x3000E00)
pr_err("dsi PHY contention error: 0x%lx\n", error);
/* ignore TX timeout if blpp_lp11 is disabled */
if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE &&
!dsi_ctrl->host_config.u.video_engine.bllp_lp11_en &&
!dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en)
error &= ~DSI_HS_TX_TIMEOUT;
/* TX timeout error */
if (error & 0xE0) {
if (error & 0xA0) {
@ -2637,27 +2651,34 @@ int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl)
}
/**
* dsi_ctrl_update_host_init_state() - Update the host initialization state.
* dsi_ctrl_update_host_state() - Update the host initialization state.
* @dsi_ctrl: DSI controller handle.
* @op: ctrl driver ops
* @enable: boolean signifying host state.
*
* Update the host initialization status only while exiting from ulps during
* suspend state.
* Update the host status only while exiting from ulps during suspend state.
*
* Return: error code.
*/
int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool enable)
int dsi_ctrl_update_host_state(struct dsi_ctrl *dsi_ctrl,
enum dsi_ctrl_driver_ops op, bool enable)
{
int rc = 0;
u32 state = enable ? 0x1 : 0x0;
rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state);
if (!dsi_ctrl)
return rc;
mutex_lock(&dsi_ctrl->ctrl_lock);
rc = dsi_ctrl_check_state(dsi_ctrl, op, state);
if (rc) {
pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
dsi_ctrl->cell_index, rc);
mutex_unlock(&dsi_ctrl->ctrl_lock);
return rc;
}
dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state);
dsi_ctrl_update_state(dsi_ctrl, op, state);
mutex_unlock(&dsi_ctrl->ctrl_lock);
return rc;
}
@ -2720,7 +2741,7 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled)
}
dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0);
dsi_ctrl_enable_error_interrupts(dsi_ctrl);
pr_debug("[DSI_%d]Host initialization complete, continuous splash status:%d\n",
dsi_ctrl->cell_index, is_splash_enabled);
@ -2749,6 +2770,16 @@ void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable)
mutex_unlock(&dsi_ctrl->ctrl_lock);
}
void dsi_ctrl_hs_req_sel(struct dsi_ctrl *dsi_ctrl, bool sel_phy)
{
if (!dsi_ctrl)
return;
mutex_lock(&dsi_ctrl->ctrl_lock);
dsi_ctrl->hw.ops.hs_req_sel(&dsi_ctrl->hw, sel_phy);
mutex_unlock(&dsi_ctrl->ctrl_lock);
}
void dsi_ctrl_set_continuous_clk(struct dsi_ctrl *dsi_ctrl, bool enable)
{
if (!dsi_ctrl)

View File

@ -75,6 +75,22 @@ enum dsi_engine_state {
DSI_CTRL_ENGINE_MAX,
};
/**
* enum dsi_ctrl_driver_ops - controller driver ops
*/
enum dsi_ctrl_driver_ops {
DSI_CTRL_OP_POWER_STATE_CHANGE,
DSI_CTRL_OP_CMD_ENGINE,
DSI_CTRL_OP_VID_ENGINE,
DSI_CTRL_OP_HOST_ENGINE,
DSI_CTRL_OP_CMD_TX,
DSI_CTRL_OP_HOST_INIT,
DSI_CTRL_OP_TPG,
DSI_CTRL_OP_PHY_SW_RESET,
DSI_CTRL_OP_ASYNC_TIMING,
DSI_CTRL_OP_MAX
};
/**
* struct dsi_ctrl_power_info - digital and analog power supplies for dsi host
* @digital: Digital power supply required to turn on DSI controller hardware.
@ -212,6 +228,7 @@ struct dsi_ctrl_interrupts {
* @null_insertion_enabled: A boolean property to allow dsi controller to
* insert null packet.
* @modeupdated: Boolean to send new roi if mode is updated.
* @split_link_supported: Boolean to check if hw supports split link.
*/
struct dsi_ctrl {
struct platform_device *pdev;
@ -267,6 +284,7 @@ struct dsi_ctrl {
bool phy_isolation_enabled;
bool null_insertion_enabled;
bool modeupdated;
bool split_link_supported;
};
/**
@ -786,15 +804,24 @@ int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl,
*/
int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl);
/**
* dsi_ctrl_update_host_init_state() - Set the host initialization state
* dsi_ctrl_update_host_state() - Set the host state
*/
int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool en);
int dsi_ctrl_update_host_state(struct dsi_ctrl *dsi_ctrl,
enum dsi_ctrl_driver_ops op, bool en);
/**
* dsi_ctrl_pixel_format_to_bpp() - returns number of bits per pxl
*/
int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format);
/**
* dsi_ctrl_hs_req_sel() - API to enable continuous clk support through phy
* @dsi_ctrl: DSI controller handle.
* @sel_phy: Boolean to control whether to select phy or
* controller
*/
void dsi_ctrl_hs_req_sel(struct dsi_ctrl *dsi_ctrl, bool sel_phy);
/**
* dsi_ctrl_set_continuous_clk() - API to set/unset force clock lane HS request.
* @dsi_ctrl: DSI controller handle.

View File

@ -823,6 +823,12 @@ struct dsi_ctrl_hw_ops {
* @ctrl: Pointer to the controller host hardware.
*/
int (*wait4dynamic_refresh_done)(struct dsi_ctrl_hw *ctrl);
/**
* hw.ops.hs_req_sel() - enable continuous clk support through phy
* @ctrl: Pointer to the controller host hardware.
* @sel_phy: Bool to control whether to select phy or controller
*/
void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy);
};
/*

View File

@ -19,6 +19,8 @@
#define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21))
#define DSI_CTRL_CMD_MISR_ENABLE BIT(28)
#define DSI_CTRL_VIDEO_MISR_ENABLE BIT(16)
#define DSI_CTRL_DMA_LINK_SEL (BIT(12)|BIT(13))
#define DSI_CTRL_MDP0_LINK_SEL (BIT(20)|BIT(22))
/* Unsupported formats default to RGB888 */
static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = {
@ -26,6 +28,38 @@ static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = {
static const u8 video_mode_format_map[DSI_PIXEL_FORMAT_MAX] = {
0x0, 0x1, 0x2, 0x3, 0x3, 0x3, 0x3 };
/**
* dsi_split_link_setup() - setup dsi split link configurations
* @ctrl: Pointer to the controller host hardware.
* @cfg: DSI host configuration that is common to both video and
* command modes.
*/
static void dsi_split_link_setup(struct dsi_ctrl_hw *ctrl,
struct dsi_host_common_cfg *cfg)
{
u32 reg;
if (!cfg->split_link.split_link_enabled)
return;
reg = DSI_R32(ctrl, DSI_SPLIT_LINK);
/* DMA_LINK_SEL */
reg &= ~(0x7 << 12);
reg |= DSI_CTRL_DMA_LINK_SEL;
/* MDP0_LINK_SEL */
reg &= ~(0x7 << 20);
reg |= DSI_CTRL_MDP0_LINK_SEL;
/* EN */
reg |= 0x1;
/* DSI_SPLIT_LINK */
DSI_W32(ctrl, DSI_SPLIT_LINK, reg);
wmb(); /* make sure split link is asserted */
}
/**
* dsi_setup_trigger_controls() - setup dsi trigger configurations
* @ctrl: Pointer to the controller host hardware.
@ -57,6 +91,7 @@ void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl,
u32 reg_value = 0;
dsi_setup_trigger_controls(ctrl, cfg);
dsi_split_link_setup(ctrl, cfg);
/* Setup clocking timing controls */
reg_value = ((cfg->t_clk_post & 0x3F) << 8);
@ -1533,6 +1568,19 @@ int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl)
return rc;
}
void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy)
{
u32 reg = 0;
reg = DSI_R32(ctrl, DSI_LANE_CTRL);
if (sel_phy)
reg &= ~BIT(24);
else
reg |= BIT(24);
DSI_W32(ctrl, DSI_LANE_CTRL, reg);
wmb(); /* make sure request is set */
}
void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable)
{
u32 reg = 0;

View File

@ -145,6 +145,7 @@
#define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0)
#define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4)
#define DSI_LOGICAL_LANE_SWAP_CTRL (0x0310)
#define DSI_SPLIT_LINK (0x0330)
#endif /* _DSI_CTRL_REG_H_ */

View File

@ -78,6 +78,11 @@ static int dsi_display_config_clk_gating(struct dsi_display *display,
return -EINVAL;
}
if (display->panel->host_config.force_hs_clk_lane) {
pr_debug("no dsi clock gating for continuous clock mode\n");
return 0;
}
mctrl = &display->ctrl[display->clk_master_idx];
if (!mctrl) {
pr_err("Invalid controller\n");
@ -586,8 +591,11 @@ static bool dsi_display_validate_reg_read(struct dsi_panel *panel)
for (j = 0; j < config->groups; ++j) {
for (i = 0; i < len; ++i) {
if (config->return_buf[i] !=
config->status_value[group + i])
config->status_value[group + i]) {
DRM_ERROR("mismatch: 0x%x\n",
config->return_buf[i]);
break;
}
}
if (i == len)
@ -828,6 +836,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
if (te_check_override && gpio_is_valid(dsi_display->disp_te_gpio))
status_mode = ESD_MODE_PANEL_TE;
if (status_mode == ESD_MODE_PANEL_TE) {
rc = dsi_display_status_check_te(dsi_display);
goto exit;
}
dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
DSI_ALL_CLKS, DSI_CLK_ON);
@ -843,23 +856,25 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
} else if (status_mode == ESD_MODE_PANEL_TE) {
rc = dsi_display_status_check_te(dsi_display);
} else {
pr_warn("unsupported check status mode\n");
pr_warn("Unsupported check status mode: %d\n", status_mode);
panel->esd_config.esd_enabled = false;
}
/* Unmask error interrupts */
/* Unmask error interrupts if check passed*/
if (rc > 0) {
dsi_display_set_ctrl_esd_check_flag(dsi_display, false);
dsi_display_mask_ctrl_error_interrupts(dsi_display, mask,
false);
} else {
/* Handle Panel failures during display disable sequence */
atomic_set(&panel->esd_recovery_pending, 1);
}
dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
DSI_ALL_CLKS, DSI_CLK_OFF);
exit:
/* Handle Panel failures during display disable sequence */
if (rc <=0)
atomic_set(&panel->esd_recovery_pending, 1);
release_panel_lock:
dsi_panel_release_panel_lock(panel);
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
@ -1620,12 +1635,25 @@ static int dsi_display_debugfs_deinit(struct dsi_display *display)
static void adjust_timing_by_ctrl_count(const struct dsi_display *display,
struct dsi_display_mode *mode)
{
mode->timing.h_active /= display->ctrl_count;
mode->timing.h_front_porch /= display->ctrl_count;
mode->timing.h_sync_width /= display->ctrl_count;
mode->timing.h_back_porch /= display->ctrl_count;
mode->timing.h_skew /= display->ctrl_count;
mode->pixel_clk_khz /= display->ctrl_count;
struct dsi_host_common_cfg *host = &display->panel->host_config;
bool is_split_link = host->split_link.split_link_enabled;
u32 sublinks_count = host->split_link.num_sublinks;
if (is_split_link && sublinks_count > 1) {
mode->timing.h_active /= sublinks_count;
mode->timing.h_front_porch /= sublinks_count;
mode->timing.h_sync_width /= sublinks_count;
mode->timing.h_back_porch /= sublinks_count;
mode->timing.h_skew /= sublinks_count;
mode->pixel_clk_khz /= sublinks_count;
} else {
mode->timing.h_active /= display->ctrl_count;
mode->timing.h_front_porch /= display->ctrl_count;
mode->timing.h_sync_width /= display->ctrl_count;
mode->timing.h_back_porch /= display->ctrl_count;
mode->timing.h_skew /= display->ctrl_count;
mode->pixel_clk_khz /= display->ctrl_count;
}
}
static int dsi_display_is_ulps_req_valid(struct dsi_display *display,
@ -2366,7 +2394,9 @@ static int dsi_display_ctrl_init(struct dsi_display *display)
} else {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_ctrl_update_host_init_state(ctrl->ctrl, true);
rc = dsi_ctrl_update_host_state(ctrl->ctrl,
DSI_CTRL_OP_HOST_INIT,
true);
if (rc)
pr_debug("host init update failed rc=%d\n", rc);
}
@ -2450,6 +2480,25 @@ static int dsi_display_ctrl_host_disable(struct dsi_display *display)
struct dsi_display_ctrl *m_ctrl, *ctrl;
m_ctrl = &display->ctrl[display->cmd_master_idx];
/*
* For platforms where ULPS is controlled by DSI controller block,
* do not disable dsi controller block if lanes are to be
* kept in ULPS during suspend. So just update the SW state
* and return early.
*/
if (display->panel->ulps_suspend_enabled &&
!m_ctrl->phy->hw.ops.ulps_ops.ulps_request) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_ctrl_update_host_state(ctrl->ctrl,
DSI_CTRL_OP_HOST_ENGINE,
false);
if (rc)
pr_debug("host state update failed %d\n", rc);
}
return rc;
}
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (!ctrl->ctrl || (ctrl == m_ctrl))
@ -4609,6 +4658,42 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
return rc;
}
static int dsi_display_validate_split_link(struct dsi_display *display)
{
int i, rc = 0;
struct dsi_display_ctrl *ctrl;
struct dsi_host_common_cfg *host = &display->panel->host_config;
if (!host->split_link.split_link_enabled)
return 0;
if (display->panel->panel_mode == DSI_OP_CMD_MODE) {
pr_err("[%s] split link is not supported in command mode\n",
display->name);
rc = -ENOTSUPP;
goto error;
}
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (!ctrl->ctrl->split_link_supported) {
pr_err("[%s] split link is not supported by hw\n",
display->name);
rc = -ENOTSUPP;
goto error;
}
set_bit(DSI_PHY_SPLIT_LINK, ctrl->phy->hw.feature_map);
}
pr_debug("Split link is enabled\n");
return 0;
error:
host->split_link.split_link_enabled = false;
return rc;
}
/**
* dsi_display_bind - bind dsi device with controlling device
* @dev: Pointer to base of platform device
@ -4649,8 +4734,28 @@ static int dsi_display_bind(struct device *dev,
if (!display->fw)
display->name = display->panel_node->name;
/* defer bind if ext bridge driver is not loaded */
if (display->panel && display->panel->host_config.ext_bridge_mode) {
for (i = 0; i < display->ext_bridge_cnt; i++) {
if (!of_drm_find_bridge(
display->ext_bridge[i].node_of)) {
pr_debug("defer for bridge[%d] %s\n", i,
display->ext_bridge[i].node_of->full_name);
return -EPROBE_DEFER;
}
}
}
mutex_lock(&display->display_lock);
rc = dsi_display_validate_split_link(display);
if (rc) {
pr_err("[%s] split link validation failed, rc=%d\n",
display->name, rc);
goto error;
}
rc = dsi_display_debugfs_init(display);
if (rc) {
pr_err("[%s] debugfs init failed, rc=%d\n", display->name, rc);
@ -5273,7 +5378,7 @@ static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge(
sde_conn = to_sde_connector(conn_iter);
if (sde_conn->encoder == bridge->encoder) {
display = sde_conn->display;
for (i = 0; i < display->ctrl_count; i++) {
display_for_each_ctrl(i, display) {
if (display->ext_bridge[i].bridge == bridge)
return &display->ext_bridge[i];
}
@ -5440,6 +5545,9 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
struct drm_bridge *prev_bridge = bridge;
int rc = 0, i;
if (display->panel && !display->panel->host_config.ext_bridge_mode)
return 0;
for (i = 0; i < display->ext_bridge_cnt; i++) {
struct dsi_display_ext_bridge *ext_bridge_info =
&display->ext_bridge[i];
@ -5750,8 +5858,10 @@ int dsi_display_get_modes(struct dsi_display *display,
{
struct dsi_dfps_capabilities dfps_caps;
struct dsi_display_ctrl *ctrl;
struct dsi_host_common_cfg *host = &display->panel->host_config;
bool is_split_link;
u32 num_dfps_rates, panel_mode_count, total_mode_count;
u32 mode_idx, array_idx = 0;
u32 sublinks_count, mode_idx, array_idx = 0;
struct dsi_dyn_clk_caps *dyn_clk_caps;
int i, start, end, rc = -EINVAL;
@ -5827,15 +5937,25 @@ int dsi_display_get_modes(struct dsi_display *display,
panel_mode.timing.dsi_transfer_time_us;
}
panel_mode.timing.h_active *= display->ctrl_count;
panel_mode.timing.h_front_porch *= display->ctrl_count;
panel_mode.timing.h_sync_width *= display->ctrl_count;
panel_mode.timing.h_back_porch *= display->ctrl_count;
panel_mode.timing.h_skew *= display->ctrl_count;
panel_mode.pixel_clk_khz *= display->ctrl_count;
is_split_link = host->split_link.split_link_enabled;
sublinks_count = host->split_link.num_sublinks;
if (is_split_link && sublinks_count > 1) {
panel_mode.timing.h_active *= sublinks_count;
panel_mode.timing.h_front_porch *= sublinks_count;
panel_mode.timing.h_sync_width *= sublinks_count;
panel_mode.timing.h_back_porch *= sublinks_count;
panel_mode.timing.h_skew *= sublinks_count;
panel_mode.pixel_clk_khz *= sublinks_count;
} else {
panel_mode.timing.h_active *= display->ctrl_count;
panel_mode.timing.h_front_porch *= display->ctrl_count;
panel_mode.timing.h_sync_width *= display->ctrl_count;
panel_mode.timing.h_back_porch *= display->ctrl_count;
panel_mode.timing.h_skew *= display->ctrl_count;
panel_mode.pixel_clk_khz *= display->ctrl_count;
}
start = array_idx;
for (i = 0; i < num_dfps_rates; i++) {
struct dsi_display_mode *sub_mode =
&display->modes[array_idx];
@ -5886,6 +6006,7 @@ int dsi_display_get_panel_vfp(void *dsi_display,
u32 count, refresh_rate = 0;
struct dsi_dfps_capabilities dfps_caps;
struct dsi_display *display = (struct dsi_display *)dsi_display;
struct dsi_host_common_cfg *host;
if (!display)
return -EINVAL;
@ -5909,7 +6030,11 @@ int dsi_display_get_panel_vfp(void *dsi_display,
return -EINVAL;
}
h_active *= display->ctrl_count;
host = &display->panel->host_config;
if (host->split_link.split_link_enabled)
h_active *= host->split_link.num_sublinks;
else
h_active *= display->ctrl_count;
for (i = 0; i < count; i++) {
struct dsi_display_mode *m = &display->modes[i];
@ -6574,7 +6699,8 @@ int dsi_display_prepare(struct dsi_display *display)
if (display->is_cont_splash_enabled &&
display->config.panel_mode == DSI_OP_VIDEO_MODE) {
pr_err("DMS not supported on first frame\n");
return -EINVAL;
rc = -EINVAL;
goto error;
}
/* update dsi ctrl for new mode */
@ -6771,8 +6897,7 @@ static int dsi_display_qsync(struct dsi_display *display, bool enable)
mutex_lock(&display->display_lock);
for (i = 0; i < display->ctrl_count; i++) {
display_for_each_ctrl(i, display) {
if (enable) {
/* send the commands to enable qsync */
rc = dsi_panel_send_qsync_on_dcs(display->panel, i);

View File

@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/pwm.h>
#include <video/mipi_display.h>
#include "dsi_panel.h"
@ -587,17 +588,16 @@ error:
static int dsi_panel_wled_register(struct dsi_panel *panel,
struct dsi_backlight_config *bl)
{
int rc = 0;
struct backlight_device *bd;
bd = backlight_device_get_by_type(BACKLIGHT_RAW);
if (!bd) {
pr_err("[%s] fail raw backlight register\n", panel->name);
rc = -EINVAL;
return -EPROBE_DEFER;
}
bl->raw_bd = bd;
return rc;
return 0;
}
static int dsi_panel_update_backlight(struct dsi_panel *panel,
@ -620,6 +620,57 @@ static int dsi_panel_update_backlight(struct dsi_panel *panel,
return rc;
}
static int dsi_panel_update_pwm_backlight(struct dsi_panel *panel,
u32 bl_lvl)
{
int rc = 0;
u32 duty = 0;
u32 period_ns = 0;
struct dsi_backlight_config *bl;
if (!panel) {
pr_err("Invalid Params\n");
return -EINVAL;
}
bl = &panel->bl_config;
if (!bl->pwm_bl) {
pr_err("pwm device not found\n");
return -EINVAL;
}
period_ns = bl->pwm_period_usecs * NSEC_PER_USEC;
duty = bl_lvl * period_ns;
duty /= bl->bl_max_level;
rc = pwm_config(bl->pwm_bl, duty, period_ns);
if (rc) {
pr_err("[%s] failed to change pwm config, rc=\n", panel->name,
rc);
goto error;
}
if (bl_lvl == 0 && bl->pwm_enabled) {
pwm_disable(bl->pwm_bl);
bl->pwm_enabled = false;
return 0;
}
if (!bl->pwm_enabled) {
rc = pwm_enable(bl->pwm_bl);
if (rc) {
pr_err("[%s] failed to enable pwm, rc=\n", panel->name,
rc);
goto error;
}
bl->pwm_enabled = true;
}
error:
return rc;
}
int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl)
{
int rc = 0;
@ -638,6 +689,9 @@ int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl)
break;
case DSI_BACKLIGHT_EXTERNAL:
break;
case DSI_BACKLIGHT_PWM:
rc = dsi_panel_update_pwm_backlight(panel, bl_lvl);
break;
default:
pr_err("Backlight type(%d) not supported\n", bl->type);
rc = -ENOTSUPP;
@ -662,6 +716,7 @@ static u32 dsi_panel_get_brightness(struct dsi_backlight_config *bl)
break;
case DSI_BACKLIGHT_DCS:
case DSI_BACKLIGHT_EXTERNAL:
case DSI_BACKLIGHT_PWM:
default:
/*
* Ideally, we should read the backlight level from the
@ -681,6 +736,22 @@ void dsi_panel_bl_handoff(struct dsi_panel *panel)
bl->bl_level = dsi_panel_get_brightness(bl);
}
static int dsi_panel_pwm_register(struct dsi_panel *panel)
{
int rc = 0;
struct dsi_backlight_config *bl = &panel->bl_config;
bl->pwm_bl = devm_of_pwm_get(panel->parent, panel->panel_of_node, NULL);
if (IS_ERR_OR_NULL(bl->pwm_bl)) {
rc = PTR_ERR(bl->pwm_bl);
pr_err("[%s] failed to request pwm, rc=%d\n", panel->name,
rc);
return rc;
}
return 0;
}
static int dsi_panel_bl_register(struct dsi_panel *panel)
{
int rc = 0;
@ -697,6 +768,9 @@ static int dsi_panel_bl_register(struct dsi_panel *panel)
break;
case DSI_BACKLIGHT_EXTERNAL:
break;
case DSI_BACKLIGHT_PWM:
rc = dsi_panel_pwm_register(panel);
break;
default:
pr_err("Backlight type(%d) not supported\n", bl->type);
rc = -ENOTSUPP;
@ -707,6 +781,13 @@ error:
return rc;
}
static void dsi_panel_pwm_unregister(struct dsi_panel *panel)
{
struct dsi_backlight_config *bl = &panel->bl_config;
devm_pwm_put(panel->parent, bl->pwm_bl);
}
static int dsi_panel_bl_unregister(struct dsi_panel *panel)
{
int rc = 0;
@ -722,6 +803,9 @@ static int dsi_panel_bl_unregister(struct dsi_panel *panel)
break;
case DSI_BACKLIGHT_EXTERNAL:
break;
case DSI_BACKLIGHT_PWM:
dsi_panel_pwm_unregister(panel);
break;
default:
pr_err("Backlight type(%d) not supported\n", bl->type);
rc = -ENOTSUPP;
@ -1085,6 +1169,44 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host,
return 0;
}
static void dsi_panel_parse_split_link_config(struct dsi_host_common_cfg *host,
struct dsi_parser_utils *utils,
const char *name)
{
int rc = 0;
u32 val = 0;
bool supported = false;
struct dsi_split_link_config *split_link = &host->split_link;
supported = utils->read_bool(utils->data, "qcom,split-link-enabled");
if (!supported) {
pr_debug("[%s] Split link is not supported\n", name);
split_link->split_link_enabled = false;
return;
}
rc = utils->read_u32(utils->data, "qcom,sublinks-count", &val);
if (rc || val < 1) {
pr_debug("[%s] Using default sublinks count\n", name);
split_link->num_sublinks = 2;
} else {
split_link->num_sublinks = val;
}
rc = utils->read_u32(utils->data, "qcom,lanes-per-sublink", &val);
if (rc || val < 1) {
pr_debug("[%s] Using default lanes per sublink\n", name);
split_link->lanes_per_sublink = 2;
} else {
split_link->lanes_per_sublink = val;
}
pr_debug("[%s] Split link is supported %d-%d\n", name,
split_link->num_sublinks, split_link->lanes_per_sublink);
split_link->split_link_enabled = true;
}
static int dsi_panel_parse_host_config(struct dsi_panel *panel)
{
int rc = 0;
@ -1130,6 +1252,9 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel)
goto error;
}
dsi_panel_parse_split_link_config(&panel->host_config, utils,
panel->name);
error:
return rc;
}
@ -2021,34 +2146,14 @@ static int dsi_panel_parse_bl_pwm_config(struct dsi_panel *panel)
struct dsi_backlight_config *config = &panel->bl_config;
struct dsi_parser_utils *utils = &panel->utils;
rc = utils->read_u32(utils->data, "qcom,dsi-bl-pmic-bank-select",
rc = utils->read_u32(utils->data, "qcom,bl-pmic-pwm-period-usecs",
&val);
if (rc) {
pr_err("bl-pmic-bank-select is not defined, rc=%d\n", rc);
goto error;
}
config->pwm_pmic_bank = val;
rc = utils->read_u32(utils->data, "qcom,dsi-bl-pmic-pwm-frequency",
&val);
if (rc) {
pr_err("bl-pmic-bank-select is not defined, rc=%d\n", rc);
pr_err("bl-pmic-pwm-period-usecs is not defined, rc=%d\n", rc);
goto error;
}
config->pwm_period_usecs = val;
config->pwm_pmi_control = utils->read_bool(utils->data,
"qcom,mdss-dsi-bl-pwm-pmi");
config->pwm_gpio = utils->get_named_gpio(utils->data,
"qcom,mdss-dsi-pwm-gpio",
0);
if (!gpio_is_valid(config->pwm_gpio)) {
pr_err("pwm gpio is invalid\n");
rc = -EINVAL;
goto error;
}
error:
return rc;
}
@ -2139,9 +2244,17 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel)
"qcom,platform-bklight-en-gpio",
0);
if (!gpio_is_valid(panel->bl_config.en_gpio)) {
pr_debug("[%s] failed get bklt gpio, rc=%d\n", panel->name, rc);
rc = 0;
goto error;
if (panel->bl_config.en_gpio == -EPROBE_DEFER) {
pr_debug("[%s] failed to get bklt gpio, rc=%d\n",
panel->name, rc);
rc = -EPROBE_DEFER;
goto error;
} else {
pr_debug("[%s] failed to get bklt gpio, rc=%d\n",
panel->name, rc);
rc = 0;
goto error;
}
}
error:
@ -2341,12 +2454,16 @@ int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc)
static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode,
struct dsi_parser_utils *utils)
struct dsi_parser_utils *utils)
{
const char *data;
u32 len, i;
int rc = 0;
struct dsi_display_mode_priv_info *priv_info;
struct dsi_mode_info *timing = NULL;
if (!mode || !mode->priv_info)
return -EINVAL;
priv_info = mode->priv_info;
@ -2366,9 +2483,11 @@ static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode,
priv_info->phy_timing_len = len;
}
mode->pixel_clk_khz = (DSI_H_TOTAL_DSC(&mode->timing) *
DSI_V_TOTAL(&mode->timing) *
mode->timing.refresh_rate) / 1000;
timing = &mode->timing;
mode->pixel_clk_khz = (DSI_H_TOTAL(&mode->timing) *
DSI_V_TOTAL(&mode->timing) *
mode->timing.refresh_rate) / 1000;
return rc;
}
@ -3111,9 +3230,11 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
pr_err("failed to parse power config, rc=%d\n", rc);
rc = dsi_panel_parse_bl_config(panel);
if (rc)
if (rc) {
pr_err("failed to parse backlight config, rc=%d\n", rc);
if (rc == -EPROBE_DEFER)
goto error;
}
rc = dsi_panel_parse_misc_features(panel);
if (rc)
@ -3637,10 +3758,14 @@ int dsi_panel_set_lp1(struct dsi_panel *panel)
}
mutex_lock(&panel->panel_lock);
if (!panel->panel_initialized)
goto exit;
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
if (rc)
pr_err("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n",
panel->name, rc);
exit:
mutex_unlock(&panel->panel_lock);
return rc;
}
@ -3655,10 +3780,14 @@ int dsi_panel_set_lp2(struct dsi_panel *panel)
}
mutex_lock(&panel->panel_lock);
if (!panel->panel_initialized)
goto exit;
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2);
if (rc)
pr_err("[%s] failed to send DSI_CMD_SET_LP2 cmd, rc=%d\n",
panel->name, rc);
exit:
mutex_unlock(&panel->panel_lock);
return rc;
}
@ -3673,10 +3802,14 @@ int dsi_panel_set_nolp(struct dsi_panel *panel)
}
mutex_lock(&panel->panel_lock);
if (!panel->panel_initialized)
goto exit;
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
if (rc)
pr_err("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n",
panel->name, rc);
exit:
mutex_unlock(&panel->panel_lock);
return rc;
}
@ -3868,6 +4001,7 @@ int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
mutex_unlock(&panel->panel_lock);
dsi_panel_destroy_cmd_packets(set);
dsi_panel_dealloc_cmd_packets(set);
return rc;
}
@ -4004,11 +4138,11 @@ int dsi_panel_enable(struct dsi_panel *panel)
mutex_lock(&panel->panel_lock);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON);
if (rc) {
if (rc)
pr_err("[%s] failed to send DSI_CMD_SET_ON cmds, rc=%d\n",
panel->name, rc);
}
panel->panel_initialized = true;
else
panel->panel_initialized = true;
mutex_unlock(&panel->panel_lock);
return rc;
}

View File

@ -102,10 +102,9 @@ struct dsi_backlight_config {
int en_gpio;
/* PWM params */
bool pwm_pmi_control;
u32 pwm_pmic_bank;
struct pwm_device *pwm_bl;
bool pwm_enabled;
u32 pwm_period_usecs;
int pwm_gpio;
/* WLED params */
struct led_trigger *wled;

View File

@ -1139,7 +1139,6 @@ int dsi_phy_conv_logical_to_phy_lane(
return i;
}
/**
* dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers
* @phy: DSI PHY handle
@ -1239,6 +1238,27 @@ void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy)
mutex_unlock(&phy->phy_lock);
}
/**
* dsi_phy_set_continuous_clk() - set/unset force clock lane HS request
* @phy: DSI PHY handle
* @enable: variable to control continuous clock
*/
void dsi_phy_set_continuous_clk(struct msm_dsi_phy *phy, bool enable)
{
if (!phy)
return;
mutex_lock(&phy->phy_lock);
if (phy->hw.ops.set_continuous_clk)
phy->hw.ops.set_continuous_clk(&phy->hw, enable);
else
pr_warn("set_continuous_clk ops not present\n");
mutex_unlock(&phy->phy_lock);
}
void dsi_phy_drv_register(void)
{
platform_driver_register(&dsi_phy_platform_driver);

View File

@ -330,5 +330,13 @@ void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy);
* @size: Number of phy lane settings.
*/
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.
* @enable: variable to control continuous clock.
*/
void dsi_phy_set_continuous_clk(struct msm_dsi_phy *phy, bool enable);
#endif /* _DSI_PHY_H_ */

View File

@ -40,11 +40,13 @@ enum dsi_phy_version {
* enum dsi_phy_hw_features - features supported by DSI PHY hardware
* @DSI_PHY_DPHY: Supports DPHY
* @DSI_PHY_CPHY: Supports CPHY
* @DSI_PHY_SPLIT_LINK: Supports Split Link
* @DSI_PHY_MAX_FEATURES:
*/
enum dsi_phy_hw_features {
DSI_PHY_DPHY,
DSI_PHY_CPHY,
DSI_PHY_SPLIT_LINK,
DSI_PHY_MAX_FEATURES
};
@ -303,6 +305,13 @@ struct dsi_phy_hw_ops {
*/
void (*reset_clk_en_sel)(struct dsi_phy_hw *phy);
/**
* set_continuous_clk() - Set continuous clock
* @phy: Pointer to DSI PHY hardware object
* @enable: Bool to control continuous clock request.
*/
void (*set_continuous_clk)(struct dsi_phy_hw *phy, bool enable);
void *timing_ops;
struct phy_ulps_config_ops ulps_ops;
struct phy_dyn_refresh_ops dyn_refresh_ops;

View File

@ -34,23 +34,17 @@
#define DSIPHY_CMN_REGULATOR_CAL_STATUS1 0x0068
#define DSI_MDP_ULPS_CLAMP_ENABLE_OFF 0x0054
/* n = 0..3 for data lanes and n = 4 for clock lane */
#define DSIPHY_DLNX_CFG0(n) (0x100 + ((n) * 0x80))
#define DSIPHY_DLNX_CFG1(n) (0x104 + ((n) * 0x80))
#define DSIPHY_DLNX_CFG2(n) (0x108 + ((n) * 0x80))
#define DSIPHY_DLNX_CFG3(n) (0x10C + ((n) * 0x80))
/* n = 0..3 for data lanes and n = 4 for clock lane
* t for count per lane
*/
#define DSIPHY_DLNX_CFG(n, t) \
(0x100 + ((t) * 0x04) + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL(n, t) \
(0x118 + ((t) * 0x04) + ((n) * 0x80))
#define DSIPHY_DLNX_STRENGTH_CTRL(n, t) \
(0x138 + ((t) * 0x04) + ((n) * 0x80))
#define DSIPHY_DLNX_TEST_DATAPATH(n) (0x110 + ((n) * 0x80))
#define DSIPHY_DLNX_TEST_STR(n) (0x114 + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_4(n) (0x118 + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_5(n) (0x11C + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_6(n) (0x120 + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_7(n) (0x124 + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_8(n) (0x128 + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_9(n) (0x12C + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_10(n) (0x130 + ((n) * 0x80))
#define DSIPHY_DLNX_TIMING_CTRL_11(n) (0x134 + ((n) * 0x80))
#define DSIPHY_DLNX_STRENGTH_CTRL_0(n) (0x138 + ((n) * 0x80))
#define DSIPHY_DLNX_STRENGTH_CTRL_1(n) (0x13C + ((n) * 0x80))
#define DSIPHY_DLNX_BIST_POLY(n) (0x140 + ((n) * 0x80))
#define DSIPHY_DLNX_BIST_SEED0(n) (0x144 + ((n) * 0x80))
#define DSIPHY_DLNX_BIST_SEED1(n) (0x148 + ((n) * 0x80))
@ -80,10 +74,15 @@ void dsi_phy_hw_v2_0_regulator_enable(struct dsi_phy_hw *phy,
struct dsi_phy_per_lane_cfgs *reg_cfg)
{
int i;
bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map);
for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++)
DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(i), reg_cfg->lane[i][0]);
if (is_split_link)
DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(DSI_LOGICAL_CLOCK_LANE+1),
reg_cfg->lane[DSI_LOGICAL_CLOCK_LANE][0]);
/* make sure all values are written to hardware */
wmb();
@ -108,35 +107,55 @@ void dsi_phy_hw_v2_0_regulator_disable(struct dsi_phy_hw *phy)
void dsi_phy_hw_v2_0_enable(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg)
{
int i;
int i, j;
struct dsi_phy_per_lane_cfgs *lanecfg = &cfg->lanecfg;
struct dsi_phy_per_lane_cfgs *timing = &cfg->timing;
struct dsi_phy_per_lane_cfgs *strength = &cfg->strength;
u32 data;
bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map);
DSI_W32(phy, DSIPHY_CMN_LDO_CNTRL, 0x1C);
DSI_W32(phy, DSIPHY_CMN_GLBL_TEST_CTRL, 0x1);
for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
DSI_W32(phy, DSIPHY_DLNX_CFG0(i), cfg->lanecfg.lane[i][0]);
DSI_W32(phy, DSIPHY_DLNX_CFG1(i), cfg->lanecfg.lane[i][1]);
DSI_W32(phy, DSIPHY_DLNX_CFG2(i), cfg->lanecfg.lane[i][2]);
DSI_W32(phy, DSIPHY_DLNX_CFG3(i), cfg->lanecfg.lane[i][3]);
for (j = 0; j < lanecfg->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_CFG(i, j),
lanecfg->lane[i][j]);
DSI_W32(phy, DSIPHY_DLNX_TEST_STR(i), 0x88);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_4(i), timing->lane[i][0]);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_5(i), timing->lane[i][1]);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_6(i), timing->lane[i][2]);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_7(i), timing->lane[i][3]);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_8(i), timing->lane[i][4]);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_9(i), timing->lane[i][5]);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_10(i), timing->lane[i][6]);
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL_11(i), timing->lane[i][7]);
for (j = 0; j < timing->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL(i, j),
timing->lane[i][j]);
for (j = 0; j < strength->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i, j),
strength->lane[i][j]);
}
if (is_split_link) {
i = DSI_LOGICAL_CLOCK_LANE;
for (j = 0; j < lanecfg->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_CFG(i+1, j),
lanecfg->lane[i][j]);
DSI_W32(phy, DSIPHY_DLNX_TEST_STR(i+1), 0x0);
DSI_W32(phy, DSIPHY_DLNX_TEST_DATAPATH(i+1), 0x88);
for (j = 0; j < timing->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL(i+1, j),
timing->lane[i][j]);
for (j = 0; j < strength->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i+1, j),
strength->lane[i][j]);
/* enable split link for cmn clk cfg1 */
data = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1);
data |= BIT(1);
DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, data);
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL_0(i),
cfg->strength.lane[i][0]);
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL_1(i),
cfg->strength.lane[i][1]);
}
/* make sure all values are written to hardware before enabling phy */
@ -193,13 +212,20 @@ void dsi_phy_hw_v2_0_disable(struct dsi_phy_hw *phy,
*/
void dsi_phy_hw_v2_0_idle_on(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg)
{
int i = 0;
int i = 0, j;
struct dsi_phy_per_lane_cfgs *strength = &cfg->strength;
bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map);
for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL_0(i),
cfg->strength.lane[i][0]);
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL_1(i),
cfg->strength.lane[i][1]);
for (j = 0; j < strength->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i, j),
strength->lane[i][j]);
}
if (is_split_link) {
i = DSI_LOGICAL_CLOCK_LANE;
for (j = 0; j < strength->count_per_lane; j++)
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i+1, j),
strength->lane[i][j]);
}
wmb(); /* make sure write happens */
pr_debug("[DSI_%d]Phy enabled out of idle screen\n", phy->index);
@ -213,14 +239,23 @@ void dsi_phy_hw_v2_0_idle_on(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg)
void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy)
{
int i = 0;
bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map);
DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f);
for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++)
DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(i), 0x1c);
if (is_split_link)
DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(DSI_LOGICAL_CLOCK_LANE+1),
0x1c);
DSI_W32(phy, DSIPHY_CMN_LDO_CNTRL, 0x1C);
for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++)
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL_1(i), 0x0);
DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i, 1), 0x0);
if (is_split_link)
DSI_W32(phy,
DSIPHY_DLNX_STRENGTH_CTRL(DSI_LOGICAL_CLOCK_LANE+1, 1), 0x0);
wmb(); /* make sure write happens */
pr_debug("[DSI_%d]Phy disabled during idle screen\n", phy->index);
}

View File

@ -182,12 +182,6 @@ static void dsi_phy_hw_v4_0_lane_settings(struct dsi_phy_hw *phy,
DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]);
}
if (cfg->force_clk_lane_hs) {
u32 reg = DSI_R32(phy, DSIPHY_CMN_LANE_CTRL1);
reg |= BIT(5) | BIT(6);
DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg);
}
}
/**
@ -692,3 +686,18 @@ int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
return 0;
}
void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable)
{
u32 reg = 0;
reg = DSI_R32(phy, DSIPHY_CMN_LANE_CTRL1);
if (enable)
reg |= BIT(5) | BIT(6);
else
reg &= ~(BIT(5) | BIT(6));
DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg);
wmb(); /* make sure request is set */
}

View File

@ -64,6 +64,14 @@ static int dsi_pwr_parse_supply_node(struct dsi_parser_utils *utils,
regs->vregs[i].disable_load = tmp;
/* Optional values */
rc = utils->read_u32(node, "qcom,supply-off-min-voltage", &tmp);
if (rc) {
pr_debug("off-min-voltage not specified\n");
rc = 0;
} else {
regs->vregs[i].off_min_voltage = tmp;
}
rc = utils->read_u32(node, "qcom,supply-pre-on-sleep", &tmp);
if (rc) {
pr_debug("pre-on-sleep not specified\n");
@ -158,6 +166,11 @@ static int dsi_pwr_enable_vregs(struct dsi_regulator_info *regs, bool enable)
if (regs->vregs[i].pre_off_sleep)
msleep(regs->vregs[i].pre_off_sleep);
if (regs->vregs[i].off_min_voltage)
(void)regulator_set_voltage(regs->vregs[i].vreg,
regs->vregs[i].off_min_voltage,
regs->vregs[i].max_voltage);
(void)regulator_set_load(regs->vregs[i].vreg,
regs->vregs[i].disable_load);
(void)regulator_disable(regs->vregs[i].vreg);

View File

@ -21,6 +21,7 @@ struct dsi_parser_utils;
* @max_voltage: Maximum voltage in uV.
* @enable_load: Load, in uA, when enabled.
* @disable_load: Load, in uA, when disabled.
* @off_min_voltage: Minimum voltage in uV when regulator is disabled.
* @pre_on_sleep: Sleep, in ms, before enabling the regulator.
* @post_on_sleep: Sleep, in ms, after enabling the regulator.
* @pre_off_sleep: Sleep, in ms, before disabling the regulator.
@ -33,6 +34,7 @@ struct dsi_vreg {
u32 max_voltage;
u32 enable_load;
u32 disable_load;
u32 off_min_voltage;
u32 pre_on_sleep;
u32 post_on_sleep;
u32 pre_off_sleep;

View File

@ -506,7 +506,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
sde_connector_event_notify(conn, DRM_EVENT_SDE_HW_RECOVERY,
sizeof(uint8_t), event);
} else if (cmd_enc->pp_timeout_report_cnt) {
SDE_DBG_DUMP("panic");
SDE_DBG_DUMP("dsi_dbg_bus", "panic");
}
/* request a ctl reset before the next kickoff */

View File

@ -1292,9 +1292,19 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
SDE_ERROR("dsi %d connector init failed\n", i);
dsi_display_drm_bridge_deinit(display);
sde_encoder_destroy(encoder);
continue;
}
}
rc = dsi_display_drm_ext_bridge_init(display,
encoder, connector);
if (rc) {
SDE_ERROR("dsi %d ext bridge init failed\n", rc);
dsi_display_drm_bridge_deinit(display);
sde_encoder_destroy(encoder);
sde_connector_destroy(connector);
}
/* wb */
for (i = 0; i < sde_kms->wb_display_count &&
priv->num_encoders < max_encoders; ++i) {
@ -2193,7 +2203,6 @@ static void _sde_kms_post_open(struct msm_kms *kms, struct drm_file *file)
struct drm_connector *connector = NULL;
struct drm_connector_list_iter conn_iter;
struct sde_connector *sde_conn = NULL;
int i;
if (!kms) {
SDE_ERROR("invalid kms\n");
@ -2211,18 +2220,6 @@ static void _sde_kms_post_open(struct msm_kms *kms, struct drm_file *file)
if (!dev->mode_config.poll_enabled)
return;
/* init external dsi bridge here to make sure ext bridge is probed*/
for (i = 0; i < sde_kms->dsi_display_count; ++i) {
struct dsi_display *dsi_display;
dsi_display = sde_kms->dsi_displays[i];
if (dsi_display->bridge) {
dsi_display_drm_ext_bridge_init(dsi_display,
dsi_display->bridge->base.encoder,
dsi_display->drm_conn);
}
}
mutex_lock(&dev->mode_config.mutex);
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {

View File

@ -4517,7 +4517,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion)
memset(&dbg->dbgbus_vbif_rt, 0, sizeof(dbg->dbgbus_vbif_rt));
if (IS_SM8150_TARGET(hwversion) || IS_SM6150_TARGET(hwversion) ||
IS_SDMMAGPIE_TARGET(hwversion)) {
IS_SDMMAGPIE_TARGET(hwversion) ||
IS_SDMTRINKET_TARGET(hwversion)) {
dbg->dbgbus_sde.entries = dbg_bus_sde_sm8150;
dbg->dbgbus_sde.cmn.entries_size =
ARRAY_SIZE(dbg_bus_sde_sm8150);