Merge remote-tracking branch 'quic/display-kernel.lnx.4.19' into display-kernel.lnx.1.0

Merge commit to pull display-kernel.lnx.1.0 to tip
* quic/display-kernel.lnx.4.19:
  disp: msm: sde: wait for lp2 and pm_suspend frame trigger
  disp: msm: sde: update max display resolution with scale config
  drm: msm: add support for ltm off event
  disp: msm: sde: switch to WD vsync on unexpected panel jitter
  disp: msm: sde: add null check for pingpong hw block
  disp: msm: dsi: add null check for panel and proper ctrl iteration
  disp: msm: sde: add pending flush for merge3d
  disp: msm: dsi: Set OLED reugalor mode when exit LP1
  disp: msm: config AB/IBB power when AOD mode enter/exit
  disp: msm: Set the dsi panel type
  disp: msm: only set nolp command when panel in LP1/LP2 mode
  disp: msm: sde: Init ltm_buf_busy list head before adding new node
  disp: msm: update topology based on clock requirement
  makefile: add Bengal config support for display techpack
  drm/msm/sde: Fix UBSan warnings in sde
  disp: msm: sde: reserve primary CTL and LM for primary connector
  disp: msm: sde: fix inline rotator downscale ratio check
  disp: msm: add changes for bengal target compilation
  clk: qcom: mdss: remove recalculation of vco rate for 10nm pll
  disp: msm: sde: avoid plane update if crtc inactive
  drm: msm: dp: Fix DSC and FEC handling
  disp: msm: dp: Detect failure cases when setting mst topology manager
  disp: msm: dp: Fix dp mst vcpi slot management for inactive crtcs
  disp: msm: dp: Fix incorrect NULL pointer check
  disp: msm: sde: increase rsc min_threshold time
  disp: msm: sde: fix panel mode check during SUI validations
  disp: msm: dsi: refine the logic for mode filling and calculation
  drm/msm/dsi-staging: update dsi debug bus error message
  disp: drm: dp: wait for a graceful dp_mst disable
  disp: msm: sde: ensure input handler unregistration in command mode
  disp: msm: dp: fix locking in hotplug processing
  disp: msm: dsi: enable multi mode support for video mode panel
  disp: msm: sde: fix panel mode check during secure transition
  disp: msm: sde: Get connector roi state even PU disabled
  disp: msm: sde: Add check to avoid list double add
  disp: msm: sde: revert to previous smmu state upon failure to switch
  disp: msm: dp: fix for dp link layer cts failures
  disp: msm: dsi: Enable ESD check after POMS done
  disp: msm: dp: remove session lock for power state update
  disp: msm: dp: clear scrambler bypass for test pattern 4
  disp: pll: update dynamic dsi clock sequence
  drm: msm: dp: turn off audio before dp lane status toggling
  disp: msm: add length check for debugfs_ctrl
  drm:msm:dsi: Add check for max controller count
  drm: sde: Remove feature support for IGC/3D LUT for virtual planes
  drm: msm: dp: change voltage swing levels for lito/kona

Change-Id: Ie2f7020274c75192228a9b367132b1a53d1301c8
Signed-off-by: Alisha Thapaliya <athapali@codeaurora.org>
This commit is contained in:
Alisha Thapaliya 2019-10-09 16:49:08 -07:00 • committed by Linux Build Service Account
commit 388e19fcd4
51 changed files with 1073 additions and 412 deletions

View file

@ -17,6 +17,14 @@ ifeq ($(CONFIG_ARCH_LITO), y)
LINUXINCLUDE += -include $(srctree)/techpack/display/config/saipdispconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
include $(srctree)/techpack/display/config/bengaldisp.conf
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
LINUXINCLUDE += -include $(srctree)/techpack/display/config/bengaldispconf.h
endif
obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_MSM_SDE_ROTATOR) += rotator/
obj-$(CONFIG_QCOM_MDSS_PLL) += pll/

16
config/bengaldisp.conf Normal file
View file

@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2019, The Linux Foundation. All rights reserved.
export CONFIG_DRM_MSM=y
export CONFIG_DRM_MSM_SDE=y
export CONFIG_SYNC_FILE=y
export CONFIG_DRM_MSM_DSI=y
export CONFIG_DRM_MSM_DP=n
export CONFIG_QCOM_MDSS_DP_PLL=n
export CONFIG_DSI_PARSER=y
export CONFIG_DRM_SDE_WB=n
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_QCOM_MDSS_PLL=y
export CONFIG_MSM_SDE_ROTATOR=y
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
export CONFIG_DRM_SDE_RSC=n

15
config/bengaldispconf.h Normal file
View file

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#define CONFIG_DRM_MSM 1
#define CONFIG_DRM_MSM_SDE 1
#define CONFIG_SYNC_FILE 1
#define CONFIG_DRM_MSM_DSI 1
#define CONFIG_DSI_PARSER 1
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_MSM_SDE_ROTATOR 1
#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1

View file

@ -377,7 +377,7 @@ static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev)
}
dp_audio = ext_data->intf_data;
if (!ext_data) {
if (!dp_audio) {
DP_ERR("invalid intf data\n");
return ERR_PTR(-EINVAL);
}
@ -424,6 +424,11 @@ static int dp_audio_get_edid_blk(struct platform_device *pdev,
struct dp_audio_private *audio;
struct sde_edid_ctrl *edid;
if (!blk) {
DP_ERR("invalid input\n");
return -EINVAL;
}
audio = dp_audio_get_data(pdev);
if (IS_ERR(audio)) {
rc = PTR_ERR(audio);

View file

@ -1824,7 +1824,7 @@ static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl,
dp_write(DP_MAINLINK_CTRL, value);
break;
case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3:
dp_write(DP_MAINLINK_CTRL, 0x11);
dp_write(DP_MAINLINK_CTRL, 0x01);
dp_write(DP_STATE_CTRL, 0x8);
break;
default:

View file

@ -65,7 +65,7 @@ static u8 const dp_pre_emp_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
static u8 const dp_swing_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
{0x08, 0x0F, 0x16, 0x1F}, /* sw0, 0.4v */
{0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6v */
{0x1A, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */
{0x16, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */
{0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */
};

View file

@ -69,6 +69,7 @@ struct dp_ctrl_private {
bool power_on;
bool mst_mode;
bool fec_mode;
bool dsc_mode;
atomic_t aborted;
@ -575,7 +576,6 @@ end:
static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
{
int ret = 0;
const unsigned int fec_cfg_dpcd = 0x120;
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
goto end;
@ -588,7 +588,8 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
ctrl->catalog->reset(ctrl->catalog);
if (ctrl->fec_mode)
drm_dp_dpcd_writeb(ctrl->aux->drm_aux, fec_cfg_dpcd, 0x01);
drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_FEC_CONFIGURATION,
0x01);
ret = dp_ctrl_link_train(ctrl);
@ -926,7 +927,7 @@ static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl)
ctrl->aux->init(ctrl->aux, ctrl->parser->aux_cfg);
ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl, ctrl->mst_mode,
ctrl->fec_mode, false);
ctrl->fec_mode, ctrl->dsc_mode, false);
if (ret)
DP_ERR("failed to enable DP controller\n");
@ -1138,19 +1139,18 @@ static void dp_ctrl_fec_dsc_setup(struct dp_ctrl_private *ctrl)
u8 fec_sts = 0;
int rlen;
u32 dsc_enable;
const unsigned int fec_sts_dpcd = 0x280;
if (ctrl->stream_count || !ctrl->fec_mode)
if (!ctrl->fec_mode)
return;
ctrl->catalog->fec_config(ctrl->catalog, ctrl->fec_mode);
/* wait for controller to start fec sequence */
usleep_range(900, 1000);
drm_dp_dpcd_readb(ctrl->aux->drm_aux, fec_sts_dpcd, &fec_sts);
drm_dp_dpcd_readb(ctrl->aux->drm_aux, DP_FEC_STATUS, &fec_sts);
DP_DEBUG("sink fec status:%d\n", fec_sts);
dsc_enable = ctrl->fec_mode ? 1 : 0;
dsc_enable = ctrl->dsc_mode ? 1 : 0;
rlen = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_DSC_ENABLE,
dsc_enable);
if (rlen < 1)
@ -1191,13 +1191,14 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
dp_ctrl_wait4video_ready(ctrl);
dp_ctrl_fec_dsc_setup(ctrl);
ctrl->stream_count++;
link_ready = ctrl->catalog->mainlink_ready(ctrl->catalog);
DP_DEBUG("mainlink %s\n", link_ready ? "READY" : "NOT READY");
/* wait for link training completion before fec config as per spec */
dp_ctrl_fec_dsc_setup(ctrl);
return rc;
}
@ -1266,7 +1267,7 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
}
static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,
bool fec_mode, bool shallow)
bool fec_mode, bool dsc_mode, bool shallow)
{
int rc = 0;
struct dp_ctrl_private *ctrl;
@ -1285,7 +1286,11 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,
goto end;
ctrl->mst_mode = mst_mode;
ctrl->fec_mode = fec_mode;
if (fec_mode) {
ctrl->fec_mode = fec_mode;
ctrl->dsc_mode = dsc_mode;
}
rate = ctrl->panel->link_info.rate;
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
@ -1323,6 +1328,7 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
if (!ctrl->power_on)
return;
ctrl->catalog->fec_config(ctrl->catalog, false);
dp_ctrl_configure_source_link_params(ctrl, false);
ctrl->catalog->reset(ctrl->catalog);
@ -1333,6 +1339,7 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
ctrl->mst_mode = false;
ctrl->fec_mode = false;
ctrl->dsc_mode = false;
ctrl->power_on = false;
memset(&ctrl->mst_ch_info, 0, sizeof(ctrl->mst_ch_info));
DP_DEBUG("DP off done\n");

View file

@ -17,7 +17,7 @@ struct dp_ctrl {
int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
void (*deinit)(struct dp_ctrl *dp_ctrl);
int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool fec_en,
bool shallow);
bool dsc_en, bool shallow);
void (*off)(struct dp_ctrl *dp_ctrl);
void (*abort)(struct dp_ctrl *dp_ctrl);
void (*isr)(struct dp_ctrl *dp_ctrl);

View file

@ -45,10 +45,12 @@ enum dp_display_states {
DP_STATE_INITIALIZED = BIT(1),
DP_STATE_READY = BIT(2),
DP_STATE_CONNECTED = BIT(3),
DP_STATE_ENABLED = BIT(4),
DP_STATE_SUSPENDED = BIT(5),
DP_STATE_ABORTED = BIT(6),
DP_STATE_HDCP_ABORTED = BIT(7),
DP_STATE_CONNECT_NOTIFIED = BIT(4),
DP_STATE_DISCONNECT_NOTIFIED = BIT(5),
DP_STATE_ENABLED = BIT(6),
DP_STATE_SUSPENDED = BIT(7),
DP_STATE_ABORTED = BIT(8),
DP_STATE_HDCP_ABORTED = BIT(9),
};
static char *dp_display_state_name(enum dp_display_states state)
@ -74,6 +76,14 @@ static char *dp_display_state_name(enum dp_display_states state)
len += scnprintf(buf + len, sizeof(buf) - len, "|%s|",
"CONNECTED");
if (state & DP_STATE_CONNECT_NOTIFIED)
len += scnprintf(buf + len, sizeof(buf) - len, "|%s|",
"CONNECT_NOTIFIED");
if (state & DP_STATE_DISCONNECT_NOTIFIED)
len += scnprintf(buf + len, sizeof(buf) - len, "|%s|",
"DISCONNECT_NOTIFIED");
if (state & DP_STATE_ENABLED)
len += scnprintf(buf + len, sizeof(buf) - len, "|%s|",
"ENABLED");
@ -653,6 +663,14 @@ static void dp_display_send_hpd_event(struct dp_display_private *dp)
envp[4] = NULL;
kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
envp);
if (connector->status == connector_status_connected) {
dp_display_state_add(DP_STATE_CONNECT_NOTIFIED);
dp_display_state_remove(DP_STATE_DISCONNECT_NOTIFIED);
} else {
dp_display_state_add(DP_STATE_DISCONNECT_NOTIFIED);
dp_display_state_remove(DP_STATE_CONNECT_NOTIFIED);
}
}
static int dp_display_send_hpd_notification(struct dp_display_private *dp)
@ -833,8 +851,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
if (dp_display_state_is(DP_STATE_CONNECTED)) {
DP_DEBUG("dp already connected, skipping hpd high\n");
mutex_unlock(&dp->session_lock);
rc = -EISCONN;
goto end;
return -EISCONN;
}
dp_display_state_add(DP_STATE_CONNECTED);
@ -867,7 +884,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
dp_display_process_mst_hpd_high(dp, false);
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active,
dp->panel->fec_en, false);
dp->panel->fec_en, dp->panel->dsc_en, false);
if (rc) {
dp_display_state_remove(DP_STATE_CONNECTED);
goto end;
@ -911,7 +928,9 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp)
dp_display_process_mst_hpd_low(dp);
if (dp_display_state_is(DP_STATE_ENABLED) && !dp->mst.mst_active)
if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) ||
dp_display_state_is(DP_STATE_ENABLED)) &&
!dp->mst.mst_active)
rc = dp_display_send_hpd_notification(dp);
mutex_lock(&dp->session_lock);
@ -991,6 +1010,30 @@ static void dp_display_stream_disable(struct dp_display_private *dp,
dp->active_stream_cnt--;
}
static void dp_audio_enable(struct dp_display_private *dp, bool enable)
{
struct dp_panel *dp_panel;
int idx;
for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
if (!dp->active_panels[idx])
continue;
dp_panel = dp->active_panels[idx];
if (dp_panel->audio_supported) {
if (enable) {
dp_panel->audio->bw_code =
dp->link->link_params.bw_code;
dp_panel->audio->lane_count =
dp->link->link_params.lane_count;
dp_panel->audio->on(dp->panel->audio);
} else {
dp_panel->audio->off(dp_panel->audio);
}
}
}
}
static void dp_display_clean(struct dp_display_private *dp)
{
int idx;
@ -1082,10 +1125,8 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
dp_display_state_remove(DP_STATE_CONFIGURED);
mutex_lock(&dp->session_lock);
if (dp->debug->psm_enabled && dp_display_state_is(DP_STATE_READY))
dp->link->psm_config(dp->link, &dp->panel->link_info, true);
mutex_unlock(&dp->session_lock);
dp_display_disconnect_sync(dp);
@ -1178,19 +1219,33 @@ static void dp_display_attention_work(struct work_struct *work)
goto mst_attention;
}
if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
dp->ctrl->process_phy_test_request(dp->ctrl);
goto mst_attention;
if (dp->link->sink_request & (DP_TEST_LINK_PHY_TEST_PATTERN |
DP_TEST_LINK_TRAINING | DP_LINK_STATUS_UPDATED)) {
mutex_lock(&dp->session_lock);
dp_audio_enable(dp, false);
mutex_unlock(&dp->session_lock);
if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
dp->ctrl->process_phy_test_request(dp->ctrl);
if (dp->link->sink_request & DP_TEST_LINK_TRAINING) {
dp->link->send_test_response(dp->link);
dp->ctrl->link_maintenance(dp->ctrl);
}
if (dp->link->sink_request & DP_LINK_STATUS_UPDATED)
dp->ctrl->link_maintenance(dp->ctrl);
mutex_lock(&dp->session_lock);
dp_audio_enable(dp, true);
mutex_unlock(&dp->session_lock);
if (dp->link->sink_request & (DP_TEST_LINK_PHY_TEST_PATTERN |
DP_TEST_LINK_TRAINING))
goto mst_attention;
}
if (dp->link->sink_request & DP_TEST_LINK_TRAINING) {
dp->link->send_test_response(dp->link);
dp->ctrl->link_maintenance(dp->ctrl);
goto mst_attention;
}
if (dp->link->sink_request & DP_LINK_STATUS_UPDATED)
dp->ctrl->link_maintenance(dp->ctrl);
cp_irq:
if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq)
dp->hdcp.ops->cp_irq(dp->hdcp.data);
@ -1608,7 +1663,8 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel)
* So, we execute in shallow mode here to do only minimal
* and required things.
*/
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp_panel->fec_en, true);
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp_panel->fec_en,
dp_panel->dsc_en, true);
if (rc)
goto end;
@ -2004,6 +2060,7 @@ static enum drm_mode_status dp_display_validate_mode(
struct dp_display_mode dp_mode;
bool dsc_en;
u32 num_lm = 0;
int rc = 0;
if (!dp_display || !mode || !panel ||
!avail_res || !avail_res->max_mixer_width) {
@ -2049,8 +2106,12 @@ static enum drm_mode_status dp_display_validate_mode(
goto end;
}
num_lm = (avail_res->max_mixer_width <= mode->hdisplay) ?
2 : 1;
rc = msm_get_mixer_count(dp->priv, mode, avail_res, &num_lm);
if (rc) {
DP_ERR("error getting mixer count. rc:%d\n", rc);
goto end;
}
if (num_lm > avail_res->num_lm ||
(num_lm == 2 && !avail_res->num_3dmux)) {
DP_MST_DEBUG("num_lm:%d, req lm:%d 3dmux:%d\n", num_lm,

View file

@ -376,8 +376,6 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
struct msm_mode_info *mode_info,
void *display, const struct msm_resource_caps_info *avail_res)
{
const u32 dual_lm = 2;
const u32 single_lm = 1;
const u32 single_intf = 1;
const u32 no_enc = 0;
struct msm_display_topology *topology;
@ -385,9 +383,12 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
struct dp_panel *dp_panel;
struct dp_display_mode dp_mode;
struct dp_display *dp_disp = display;
struct msm_drm_private *priv;
int rc = 0;
if (!drm_mode || !mode_info || !avail_res ||
!avail_res->max_mixer_width || !connector || !display) {
!avail_res->max_mixer_width || !connector || !display ||
!connector->dev || !connector->dev->dev_private) {
DP_ERR("invalid params\n");
return -EINVAL;
}
@ -396,10 +397,17 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
sde_conn = to_sde_connector(connector);
dp_panel = sde_conn->drv_panel;
priv = connector->dev->dev_private;
topology = &mode_info->topology;
topology->num_lm = (avail_res->max_mixer_width < drm_mode->hdisplay) ?
dual_lm : single_lm;
rc = msm_get_mixer_count(priv, drm_mode, avail_res,
&topology->num_lm);
if (rc) {
DP_ERR("error getting mixer count. rc:%d\n", rc);
return rc;
}
topology->num_enc = no_enc;
topology->num_intf = single_intf;

View file

@ -184,6 +184,19 @@ static inline int dp_connector_config_hdr(struct drm_connector *connector,
return 0;
}
int dp_connector_atomic_check(struct drm_connector *connector,
void *display,
struct drm_connector_state *c_state)
{
return 0;
}
int dp_connector_set_colorspace(struct drm_connector *connector,
void *display)
{
return 0;
}
static inline int dp_connector_post_init(struct drm_connector *connector,
void *display)
{

View file

@ -1122,7 +1122,7 @@ static int dp_link_process_link_status_update(struct dp_link_private *link)
return -EINVAL;
DP_DEBUG("channel_eq_done = %d, clock_recovery_done = %d\n",
drm_dp_clock_recovery_ok(link->link_status,
drm_dp_channel_eq_ok(link->link_status,
link->dp_link.link_params.lane_count),
drm_dp_clock_recovery_ok(link->link_status,
link->dp_link.link_params.lane_count));

View file

@ -403,10 +403,16 @@ static int dp_mst_sim_topology_mgr_set_mst(
struct drm_dp_mst_topology_mgr *mgr,
bool mst_state)
{
int rc;
struct dp_mst_private *mst = container_of(mgr,
struct dp_mst_private, mst_mgr);
drm_dp_mst_topology_mgr_set_mst(mgr, mst_state);
rc = drm_dp_mst_topology_mgr_set_mst(mgr, mst_state);
if (rc < 0) {
DRM_ERROR("unable to set mst topology mgr, rc: %d\n", rc);
return rc;
}
if (mst_state)
queue_work(system_long_wq, &mst->simulator.probe_work);
@ -1451,7 +1457,7 @@ mode_set:
crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) {
c_conn = to_sde_connector(connector);
dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel,
@ -1945,9 +1951,12 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status,
mst->mst_session_state = hpd_status;
mutex_unlock(&mst->mst_lock);
if (!hpd_status)
if (!hpd_status) {
rc = mst->mst_fw_cbs->topology_mgr_set_mst(&mst->mst_mgr,
hpd_status);
if (rc < 0)
goto fail;
}
if (info && !info->mst_protocol) {
if (hpd_status) {
@ -1959,13 +1968,21 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status,
mst->mst_fw_cbs = &drm_dp_mst_fw_helper_ops;
}
if (hpd_status)
if (hpd_status) {
rc = mst->mst_fw_cbs->topology_mgr_set_mst(&mst->mst_mgr,
hpd_status);
if (rc < 0)
goto fail;
}
dp_mst_hpd_event_notify(mst, hpd_status);
DP_MST_INFO_LOG("mst display hpd:%d, rc:%d\n", hpd_status, rc);
DP_MST_INFO_LOG("mst display hpd success. hpd:%d, rc:%d\n", hpd_status,
rc);
return;
fail:
DRM_ERROR("mst display hpd failed. hpd: %d, rc: %d\n",
hpd_status, rc);
}
static void dp_mst_display_hpd_irq(void *dp_display,

View file

@ -2019,14 +2019,7 @@ end:
static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel)
{
s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1);
if (!dp_panel->dsc_feature_enable || !dp_panel->fec_feature_enable) {
DP_DEBUG("source dsc is not supported\n");
return;
}
if (dp_panel->dsc_dpcd[0] && dp_panel->fec_dpcd) {
if (dp_panel->dsc_dpcd[0]) {
dp_panel->sink_dsc_caps.dsc_capable = true;
dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1];
dp_panel->sink_dsc_caps.block_pred_en =
@ -2039,21 +2032,13 @@ static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel)
dp_panel->dsc_en = false;
}
dp_panel->fec_en = dp_panel->dsc_en;
dp_panel->widebus_en = dp_panel->dsc_en;
/* fec_overhead = 1.00 / 0.97582 */
if (dp_panel->fec_en)
fec_overhead_fp = drm_fixp_from_fraction(100000, 97582);
dp_panel->fec_overhead_fp = fec_overhead_fp;
}
static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel)
{
int rlen;
struct dp_panel_private *panel;
const int fec_cap = 0x90;
int dpcd_rev;
if (!dp_panel) {
@ -2061,14 +2046,9 @@ static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel)
return;
}
dp_panel->dsc_en = false;
dp_panel->fec_en = false;
dpcd_rev = dp_panel->dpcd[DP_DPCD_REV];
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
dp_panel->fec_overhead_fp = 0;
if (panel->parser->dsc_feature_enable && dpcd_rev >= 0x14) {
rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DSC_SUPPORT,
dp_panel->dsc_dpcd, (DP_RECEIVER_DSC_CAP_SIZE + 1));
@ -2081,17 +2061,38 @@ static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel)
DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen,
false);
rlen = drm_dp_dpcd_read(panel->aux->drm_aux, fec_cap,
&dp_panel->fec_dpcd, 1);
if (rlen < 1) {
DP_ERR("fec dpcd read failed, rlen=%d\n", rlen);
return;
}
dp_panel_decode_dsc_dpcd(dp_panel);
}
}
static void dp_panel_read_sink_fec_caps(struct dp_panel *dp_panel)
{
int rlen;
struct dp_panel_private *panel;
s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1);
if (!dp_panel) {
DP_ERR("invalid input\n");
return;
}
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
rlen = drm_dp_dpcd_readb(panel->aux->drm_aux, DP_FEC_CAPABILITY,
&dp_panel->fec_dpcd);
if (rlen < 1) {
DP_ERR("fec capability read failed, rlen=%d\n", rlen);
return;
}
dp_panel->fec_en = dp_panel->fec_dpcd & DP_FEC_CAPABLE;
if (dp_panel->fec_en)
fec_overhead_fp = drm_fixp_from_fraction(100000, 97582);
dp_panel->fec_overhead_fp = fec_overhead_fp;
return;
}
static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
struct drm_connector *connector, bool multi_func)
{
@ -2148,7 +2149,18 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable;
dp_panel->fec_feature_enable = panel->parser->fec_feature_enable;
dp_panel_read_sink_dsc_caps(dp_panel);
dp_panel->fec_en = false;
dp_panel->dsc_en = false;
if (dp_panel->fec_feature_enable) {
dp_panel_read_sink_fec_caps(dp_panel);
if (dp_panel->dsc_feature_enable && dp_panel->fec_en)
dp_panel_read_sink_dsc_caps(dp_panel);
}
DP_INFO("fec_en=%d, dsc_en=%d, widebus_en=%d\n", dp_panel->fec_en,
dp_panel->dsc_en, dp_panel->widebus_en);
end:
return rc;
}
@ -2157,9 +2169,13 @@ static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel,
u32 mode_edid_bpp, u32 mode_pclk_khz)
{
struct drm_dp_link *link_info;
const u32 max_supported_bpp = 30, min_supported_bpp = 18;
const u32 max_supported_bpp = 30;
u32 min_supported_bpp = 18;
u32 bpp = 0, data_rate_khz = 0;
if (dp_panel->dsc_en)
min_supported_bpp = 24;
bpp = min_t(u32, mode_edid_bpp, max_supported_bpp);
link_info = &dp_panel->link_info;

View file

@ -17,6 +17,8 @@
fmt, c ? c->index : -1, ##__VA_ARGS__)
#define DSI_CTRL_HW_ERR(c, fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dsi-error]: DSI_%d: "\
fmt, c ? c->index : -1, ##__VA_ARGS__)
#define DSI_CTRL_HW_INFO(c, fmt, ...) DRM_DEV_INFO(NULL, "[msm-dsi-info]: DSI_%d: "\
fmt, c ? c->index : -1, ##__VA_ARGS__)
/**
* Modifier flag for command transmission. If this flag is set, command

View file

@ -509,7 +509,7 @@ void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl, u32 *entries, u32 size)
/* make sure that debug test point is enabled */
wmb();
reg = DSI_R32(ctrl, DSI_DEBUG_BUS_STATUS);
DSI_CTRL_HW_ERR(ctrl, "debug bus ctrl: 0x%x status:0x%x\n",
DSI_CTRL_HW_INFO(ctrl, "debug bus ctrl: 0x%x status:0x%x\n",
entries[i], reg);
}
}

View file

@ -1060,10 +1060,22 @@ int dsi_display_set_power(struct drm_connector *connector,
case SDE_MODE_DPMS_LP2:
rc = dsi_panel_set_lp2(display->panel);
break;
default:
rc = dsi_panel_set_nolp(display->panel);
case SDE_MODE_DPMS_ON:
if ((display->panel->power_mode == SDE_MODE_DPMS_LP1) ||
(display->panel->power_mode == SDE_MODE_DPMS_LP2))
rc = dsi_panel_set_nolp(display->panel);
break;
case SDE_MODE_DPMS_OFF:
default:
return rc;
}
DSI_DEBUG("Power mode transition from %d to %d %s",
display->panel->power_mode, power_mode,
rc ? "failed" : "successful");
if (!rc)
display->panel->power_mode = power_mode;
return rc;
}
@ -3839,7 +3851,7 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
display->config.bit_clk_rate_hz = bit_clk_rate;
for (i = 0; i < display->ctrl_count; i++) {
display_for_each_ctrl(i, display) {
struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
u32 num_of_lanes = 0, bpp;
@ -3967,8 +3979,7 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
goto exit;
}
for (i = 0; (i < display->ctrl_count) &&
(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (!ctrl->ctrl)
continue;
@ -3986,8 +3997,7 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
}
}
for (i = 0; (i < display->ctrl_count) &&
(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (ctrl == m_ctrl)
continue;
@ -3996,8 +4006,7 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
dsi_phy_dynamic_refresh_trigger(m_ctrl->phy, true);
/* wait for dynamic refresh done */
for (i = 0; (i < display->ctrl_count) &&
(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_ctrl_wait4dynamic_refresh_done(ctrl->ctrl);
if (rc) {
@ -4009,8 +4018,7 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
}
}
for (i = 0; (i < display->ctrl_count) &&
(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
dsi_phy_dynamic_refresh_clear(ctrl->phy);
}
@ -4025,8 +4033,7 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
return rc;
recover_pix_clk:
for (i = 0; (i < display->ctrl_count) &&
(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (!ctrl->ctrl)
continue;
@ -4035,8 +4042,7 @@ recover_pix_clk:
}
recover_byte_clk:
for (i = 0; (i < display->ctrl_count) &&
(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (!ctrl->ctrl)
continue;
@ -4070,7 +4076,7 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display,
dsi_display_mask_ctrl_error_interrupts(display, mask, true);
/* update the phy timings based on new mode */
for (i = 0; i < display->ctrl_count; i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
dsi_phy_update_phy_timings(ctrl->phy, &display->config);
}
@ -4090,7 +4096,7 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display,
_dsi_display_calc_pipe_delay(display, &delay, mode);
/* configure dynamic refresh ctrl registers */
for (i = 0; i < display->ctrl_count; i++) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (!ctrl->phy)
continue;
@ -5756,55 +5762,17 @@ error:
return rc;
}
static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
u32 *count)
{
struct dsi_dfps_capabilities dfps_caps;
struct dsi_dyn_clk_caps *dyn_clk_caps;
int num_dfps_rates, num_bit_clks, rc = 0;
if (!display || !display->panel) {
DSI_ERR("invalid display:%d panel:%d\n", display != NULL,
display ? display->panel != NULL : 0);
return -EINVAL;
}
*count = display->panel->num_timing_nodes;
rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
if (rc) {
DSI_ERR("[%s] failed to get dfps caps from panel\n",
display->name);
return rc;
}
num_dfps_rates = !dfps_caps.dfps_support ? 1 : dfps_caps.dfps_list_len;
dyn_clk_caps = &(display->panel->dyn_clk_caps);
num_bit_clks = !dyn_clk_caps->dyn_clk_support ? 1 :
dyn_clk_caps->bit_clk_list_len;
/* Inflate num_of_modes by fps and bit clks in dfps */
*count = display->panel->num_timing_nodes *
num_dfps_rates * num_bit_clks;
return 0;
}
int dsi_display_get_mode_count(struct dsi_display *display,
u32 *count)
{
int rc;
if (!display || !display->panel) {
DSI_ERR("invalid display:%d panel:%d\n", display != NULL,
display ? display->panel != NULL : 0);
display ? display->panel != NULL : 0);
return -EINVAL;
}
mutex_lock(&display->display_lock);
rc = dsi_display_get_mode_count_no_lock(display, count);
*count = display->panel->num_display_modes;
mutex_unlock(&display->display_lock);
return 0;
@ -5837,7 +5805,7 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
if (cfg->data_lanes & DSI_DATA_LANE_3)
lanes++;
dsi_display_get_mode_count_no_lock(display, &total_modes);
total_modes = display->panel->num_display_modes;
for (i = start; i < end; i++) {
src = &display->modes[i];
@ -5889,8 +5857,8 @@ 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;
bool is_split_link, is_cmd_mode;
u32 num_dfps_rates, timing_mode_count, display_mode_count;
u32 sublinks_count, mode_idx, array_idx = 0;
struct dsi_dyn_clk_caps *dyn_clk_caps;
int i, start, end, rc = -EINVAL;
@ -5908,11 +5876,9 @@ int dsi_display_get_modes(struct dsi_display *display,
if (display->modes)
goto exit;
rc = dsi_display_get_mode_count_no_lock(display, &total_mode_count);
if (rc)
goto error;
display_mode_count = display->panel->num_display_modes;
display->modes = kcalloc(total_mode_count, sizeof(*display->modes),
display->modes = kcalloc(display_mode_count, sizeof(*display->modes),
GFP_KERNEL);
if (!display->modes) {
rc = -ENOMEM;
@ -5930,20 +5896,20 @@ int dsi_display_get_modes(struct dsi_display *display,
num_dfps_rates = !dfps_caps.dfps_support ? 1 : dfps_caps.dfps_list_len;
panel_mode_count = display->panel->num_timing_nodes;
timing_mode_count = display->panel->num_timing_nodes;
for (mode_idx = 0; mode_idx < panel_mode_count; mode_idx++) {
struct dsi_display_mode panel_mode;
for (mode_idx = 0; mode_idx < timing_mode_count; mode_idx++) {
struct dsi_display_mode display_mode;
int topology_override = NO_OVERRIDE;
u32 frame_threshold_us = ctrl->ctrl->frame_threshold_time_us;
if (display->cmdline_timing == mode_idx)
topology_override = display->cmdline_topology;
memset(&panel_mode, 0, sizeof(panel_mode));
memset(&display_mode, 0, sizeof(display_mode));
rc = dsi_panel_get_mode(display->panel, mode_idx,
&panel_mode,
&display_mode,
topology_override);
if (rc) {
DSI_ERR("[%s] failed to get mode idx %d from panel\n",
@ -5951,38 +5917,43 @@ int dsi_display_get_modes(struct dsi_display *display,
goto error;
}
is_cmd_mode = (display_mode.panel_mode == DSI_OP_CMD_MODE);
/* Calculate dsi frame transfer time */
if (display->panel->panel_mode == DSI_OP_CMD_MODE) {
if (is_cmd_mode) {
dsi_panel_calc_dsi_transfer_time(
&display->panel->host_config,
&panel_mode, frame_threshold_us);
panel_mode.priv_info->dsi_transfer_time_us =
panel_mode.timing.dsi_transfer_time_us;
panel_mode.priv_info->min_dsi_clk_hz =
panel_mode.timing.min_dsi_clk_hz;
&display_mode, frame_threshold_us);
display_mode.priv_info->dsi_transfer_time_us =
display_mode.timing.dsi_transfer_time_us;
display_mode.priv_info->min_dsi_clk_hz =
display_mode.timing.min_dsi_clk_hz;
panel_mode.priv_info->mdp_transfer_time_us =
panel_mode.priv_info->dsi_transfer_time_us;
panel_mode.timing.mdp_transfer_time_us =
panel_mode.timing.dsi_transfer_time_us;
display_mode.priv_info->mdp_transfer_time_us =
display_mode.priv_info->dsi_transfer_time_us;
display_mode.timing.mdp_transfer_time_us =
display_mode.timing.dsi_transfer_time_us;
}
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;
display_mode.timing.h_active *= sublinks_count;
display_mode.timing.h_front_porch *= sublinks_count;
display_mode.timing.h_sync_width *= sublinks_count;
display_mode.timing.h_back_porch *= sublinks_count;
display_mode.timing.h_skew *= sublinks_count;
display_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;
display_mode.timing.h_active *= display->ctrl_count;
display_mode.timing.h_front_porch *=
display->ctrl_count;
display_mode.timing.h_sync_width *=
display->ctrl_count;
display_mode.timing.h_back_porch *=
display->ctrl_count;
display_mode.timing.h_skew *= display->ctrl_count;
display_mode.pixel_clk_khz *= display->ctrl_count;
}
start = array_idx;
@ -5997,10 +5968,10 @@ int dsi_display_get_modes(struct dsi_display *display,
goto error;
}
memcpy(sub_mode, &panel_mode, sizeof(panel_mode));
memcpy(sub_mode, &display_mode, sizeof(display_mode));
array_idx++;
if (!dfps_caps.dfps_support)
if (!dfps_caps.dfps_support || is_cmd_mode)
continue;
curr_refresh_rate = sub_mode->timing.refresh_rate;
@ -6038,16 +6009,14 @@ int dsi_display_get_panel_vfp(void *dsi_display,
struct dsi_display *display = (struct dsi_display *)dsi_display;
struct dsi_host_common_cfg *host;
if (!display)
if (!display || !display->panel)
return -EINVAL;
rc = dsi_display_get_mode_count(display, &count);
if (rc)
return rc;
mutex_lock(&display->display_lock);
if (display->panel && display->panel->cur_mode)
count = display->panel->num_display_modes;
if (display->panel->cur_mode)
refresh_rate = display->panel->cur_mode->timing.refresh_rate;
dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
@ -6089,9 +6058,9 @@ int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm)
*num_lm = 0;
rc = dsi_display_get_mode_count(display, &count);
if (rc)
return rc;
mutex_lock(&display->display_lock);
count = display->panel->num_display_modes;
mutex_unlock(&display->display_lock);
if (!display->modes) {
struct dsi_display_mode *m;
@ -6124,9 +6093,9 @@ int dsi_display_find_mode(struct dsi_display *display,
*out_mode = NULL;
rc = dsi_display_get_mode_count(display, &count);
if (rc)
return rc;
mutex_lock(&display->display_lock);
count = display->panel->num_display_modes;
mutex_unlock(&display->display_lock);
if (!display->modes) {
struct dsi_display_mode *m;

View file

@ -359,7 +359,7 @@ int dsi_display_get_mode_count(struct dsi_display *display, u32 *count);
* dsi_display_get_modes() - get modes supported by display
* @display: Handle to display.
* @modes; Output param, list of DSI modes. Number of modes matches
* count returned by dsi_display_get_mode_count
* count got from display->panel->num_display_modes;
*
* Return: error code.
*/

View file

@ -242,8 +242,12 @@ static void dsi_bridge_enable(struct drm_bridge *bridge)
DSI_ERR("[%d] DSI display post enabled failed, rc=%d\n",
c_bridge->id, rc);
if (display && display->drm_conn)
if (display && display->drm_conn) {
sde_connector_helper_bridge_enable(display->drm_conn);
if (c_bridge->dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS)
sde_connector_schedule_status_work(display->drm_conn,
true);
}
}
static void dsi_bridge_disable(struct drm_bridge *bridge)

View file

@ -3212,6 +3212,7 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
{
struct dsi_panel *panel;
struct dsi_parser_utils *utils;
const char *panel_physical_type;
int rc = 0;
panel = kzalloc(sizeof(*panel), GFP_KERNEL);
@ -3230,6 +3231,14 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
if (!panel->name)
panel->name = DSI_PANEL_DEFAULT_LABEL;
/*
* Set panel type to LCD as default.
*/
panel->panel_type = DSI_DISPLAY_PANEL_TYPE_LCD;
panel_physical_type = utils->get_property(utils->data,
"qcom,mdss-dsi-panel-physical-type", NULL);
if (panel_physical_type && !strcmp(panel_physical_type, "oled"))
panel->panel_type = DSI_DISPLAY_PANEL_TYPE_OLED;
rc = dsi_panel_parse_host_config(panel);
if (rc) {
DSI_ERR("failed to parse host configuration, rc=%d\n",
@ -3306,6 +3315,7 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
if (rc)
DSI_DEBUG("failed to parse esd config, rc=%d\n", rc);
panel->power_mode = SDE_MODE_DPMS_OFF;
drm_panel_init(&panel->drm_panel);
panel->drm_panel.dev = &panel->mipi_device.dev;
panel->mipi_device.dev.of_node = of_node;
@ -3446,8 +3456,11 @@ int dsi_panel_get_mode_count(struct dsi_panel *panel)
{
const u32 SINGLE_MODE_SUPPORT = 1;
struct dsi_parser_utils *utils;
struct device_node *timings_np;
struct device_node *timings_np, *child_np;
int num_dfps_rates, num_bit_clks;
int num_video_modes = 0, num_cmd_modes = 0;
int count, rc = 0;
void *utils_data = NULL;
if (!panel) {
DSI_ERR("invalid params\n");
@ -3474,12 +3487,37 @@ int dsi_panel_get_mode_count(struct dsi_panel *panel)
goto error;
}
/* No multiresolution support is available for video mode panels */
/* No multiresolution support is available for video mode panels.
* Multi-mode is supported for video mode during POMS is enabled.
*/
if (panel->panel_mode != DSI_OP_CMD_MODE &&
!panel->host_config.ext_bridge_mode)
!panel->host_config.ext_bridge_mode &&
!panel->panel_mode_switch_enabled)
count = SINGLE_MODE_SUPPORT;
panel->num_timing_nodes = count;
dsi_for_each_child_node(timings_np, child_np) {
utils_data = child_np;
if (utils->read_bool(utils->data, "qcom,mdss-dsi-video-mode"))
num_video_modes++;
else if (utils->read_bool(utils->data,
"qcom,mdss-dsi-cmd-mode"))
num_cmd_modes++;
else if (panel->panel_mode == DSI_OP_VIDEO_MODE)
num_video_modes++;
else if (panel->panel_mode == DSI_OP_CMD_MODE)
num_cmd_modes++;
}
num_dfps_rates = !panel->dfps_caps.dfps_support ? 1 :
panel->dfps_caps.dfps_list_len;
num_bit_clks = !panel->dyn_clk_caps.dyn_clk_support ? 1 :
panel->dyn_clk_caps.bit_clk_list_len;
/* Inflate num_of_modes by fps and bit clks in dfps */
panel->num_display_modes = (num_cmd_modes * num_bit_clks) +
(num_video_modes * num_bit_clks * num_dfps_rates);
error:
return rc;
@ -3851,6 +3889,17 @@ int dsi_panel_set_lp1(struct dsi_panel *panel)
if (!panel->panel_initialized)
goto exit;
/*
* Consider LP1->LP2->LP1.
* If the panel is already in LP mode, do not need to
* set the regulator.
* IBB and AB power mode would be set at the same time
* in PMIC driver, so we only call ibb setting that is enough.
*/
if (dsi_panel_is_type_oled(panel) &&
panel->power_mode != SDE_MODE_DPMS_LP2)
dsi_pwr_panel_regulator_mode_set(&panel->power_info,
"ibb", REGULATOR_MODE_IDLE);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
if (rc)
DSI_ERR("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n",
@ -3895,6 +3944,14 @@ int dsi_panel_set_nolp(struct dsi_panel *panel)
if (!panel->panel_initialized)
goto exit;
/*
* Consider about LP1->LP2->NOLP.
*/
if (dsi_panel_is_type_oled(panel) &&
(panel->power_mode == SDE_MODE_DPMS_LP1 ||
panel->power_mode == SDE_MODE_DPMS_LP2))
dsi_pwr_panel_regulator_mode_set(&panel->power_info,
"ibb", REGULATOR_MODE_NORMAL);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
if (rc)
DSI_ERR("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n",
@ -4295,6 +4352,15 @@ int dsi_panel_disable(struct dsi_panel *panel)
/* Avoid sending panel off commands when ESD recovery is underway */
if (!atomic_read(&panel->esd_recovery_pending)) {
/*
* Need to set IBB/AB regulator mode to STANDBY,
* if panel is going off from AOD mode.
*/
if (dsi_panel_is_type_oled(panel) &&
(panel->power_mode == SDE_MODE_DPMS_LP1 ||
panel->power_mode == SDE_MODE_DPMS_LP2))
dsi_pwr_panel_regulator_mode_set(&panel->power_info,
"ibb", REGULATOR_MODE_STANDBY);
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_OFF);
if (rc) {
/*
@ -4309,6 +4375,7 @@ int dsi_panel_disable(struct dsi_panel *panel)
}
}
panel->panel_initialized = false;
panel->power_mode = SDE_MODE_DPMS_OFF;
mutex_unlock(&panel->panel_lock);
return rc;

View file

@ -62,6 +62,12 @@ enum dsi_dms_mode {
DSI_DMS_MODE_RES_SWITCH_IMMEDIATE,
};
enum dsi_panel_physical_type {
DSI_DISPLAY_PANEL_TYPE_LCD = 0,
DSI_DISPLAY_PANEL_TYPE_OLED,
DSI_DISPLAY_PANEL_TYPE_MAX,
};
struct dsi_dfps_capabilities {
enum dsi_dfps_type type;
u32 min_refresh_rate;
@ -171,6 +177,7 @@ struct dsi_panel {
struct dsi_display_mode *cur_mode;
u32 num_timing_nodes;
u32 num_display_modes;
struct dsi_regulator_info power_info;
struct dsi_backlight_config bl_config;
@ -197,6 +204,8 @@ struct dsi_panel {
bool sync_broadcast_en;
int panel_test_gpio;
int power_mode;
enum dsi_panel_physical_type panel_type;
};
static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel)
@ -219,6 +228,11 @@ static inline void dsi_panel_release_panel_lock(struct dsi_panel *panel)
mutex_unlock(&panel->panel_lock);
}
static inline bool dsi_panel_is_type_oled(struct dsi_panel *panel)
{
return (panel->panel_type == DSI_DISPLAY_PANEL_TYPE_OLED);
}
struct dsi_panel *dsi_panel_get(struct device *parent,
struct device_node *of_node,
struct device_node *parser_node,

View file

@ -378,3 +378,51 @@ int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable)
return rc;
}
/*
* dsi_pwr_panel_regulator_mode_set()
* set the AB/IBB regulator mode for OLED panel
* AOD mode entry and exit
* @regs: Pointer to set of regulators to enable or disable.
* @reg_name: Name of panel power we want to set.
* @retulator_mode: Regulator mode values, like:
* REGULATOR_MODE_INVALID
* REGULATOR_MODE_FAST
* REGULATOR_MODE_NORMAL
* REGULATOR_MODE_IDLE
* REGULATOR_MODE_STANDBY
*
* return: error code in case of failure or 0 for success.
*/
int dsi_pwr_panel_regulator_mode_set(struct dsi_regulator_info *regs,
const char *reg_name,
int regulator_mode)
{
int i = 0, rc = 0;
struct dsi_vreg *vreg;
if (regs->count == 0)
return -EINVAL;
if (!regs->vregs)
return -EINVAL;
for (i = 0; i < regs->count; i++) {
vreg = &regs->vregs[i];
if (!strcmp(vreg->vreg_name, reg_name)) {
rc = regulator_set_mode(vreg->vreg,
regulator_mode);
if (rc)
DSI_ERR("Regulator %s set mode %d failed\n",
vreg->vreg_name, rc);
break;
}
}
if (i >= regs->count) {
DSI_ERR("Regulator %s was not found\n", reg_name);
return -EINVAL;
}
return rc;
}

View file

@ -85,4 +85,22 @@ int dsi_pwr_get_dt_vreg_data(struct device *dev,
* return: error code in case of failure or 0 for success.
*/
int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable);
/**
* dsi_pwr_panel_regulator_mode_set()
* set regulator mode for OLED panel
* @regs: Pointer to set of regulators to enable or disable.
* @reg_name: Panel regulator name
* @regulator_mode: Regulator mode values, like:
* REGULATOR_MODE_INVALID
* REGULATOR_MODE_FAST
* REGULATOR_MODE_NORMAL
* REGULATOR_MODE_IDLE
* REGULATOR_MODE_STANDBY
*
* return: error code in case of failure or 0 for success.
*/
int dsi_pwr_panel_regulator_mode_set(struct dsi_regulator_info *regs,
const char *reg_name,
int regulator_mode);
#endif /* _DSI_PWR_H_ */

View file

@ -535,7 +535,8 @@ static void complete_commit(struct msm_commit *c)
msm_atomic_helper_commit_modeset_disables(dev, state);
drm_atomic_helper_commit_planes(dev, state, 0);
drm_atomic_helper_commit_planes(dev, state,
DRM_PLANE_COMMIT_ACTIVE_ONLY);
msm_atomic_helper_commit_modeset_enables(dev, state);

View file

@ -1938,6 +1938,33 @@ msm_gem_smmu_address_space_get(struct drm_device *dev,
return funcs->get_address_space(priv->kms, domain);
}
int msm_get_mixer_count(struct msm_drm_private *priv,
const struct drm_display_mode *mode,
const struct msm_resource_caps_info *res, u32 *num_lm)
{
struct msm_kms *kms;
const struct msm_kms_funcs *funcs;
if (!priv) {
DRM_ERROR("invalid drm private struct\n");
return -EINVAL;
}
kms = priv->kms;
if (!kms) {
DRM_ERROR("invalid msm kms struct\n");
return -EINVAL;
}
funcs = kms->funcs;
if (!funcs || !funcs->get_mixer_count) {
DRM_ERROR("invalid function pointers\n");
return -EINVAL;
}
return funcs->get_mixer_count(priv->kms, mode, res, num_lm);
}
static int msm_drm_bind(struct device *dev)
{
return msm_drm_init(dev, &msm_driver);
@ -2024,16 +2051,6 @@ static struct platform_driver msm_platform_driver = {
},
};
#ifdef CONFIG_QCOM_KGSL
void __init adreno_register(void)
{
}
void __exit adreno_unregister(void)
{
}
#endif
static int __init msm_drm_register(void)
{
if (!modeset)
@ -2044,7 +2061,6 @@ static int __init msm_drm_register(void)
msm_dsi_register();
msm_edp_register();
msm_hdmi_register();
adreno_register();
return platform_driver_register(&msm_platform_driver);
}
@ -2053,7 +2069,6 @@ static void __exit msm_drm_unregister(void)
DBG("fini");
platform_driver_unregister(&msm_platform_driver);
msm_hdmi_unregister();
adreno_unregister();
msm_edp_unregister();
msm_dsi_unregister();
msm_smmu_driver_cleanup();

View file

@ -1029,4 +1029,8 @@ static inline unsigned long timeout_to_jiffies(const ktime_t *timeout)
return remaining_jiffies;
}
int msm_get_mixer_count(struct msm_drm_private *priv,
const struct drm_display_mode *mode,
const struct msm_resource_caps_info *res, u32 *num_lm);
#endif /* __MSM_DRV_H__ */

View file

@ -122,6 +122,10 @@ struct msm_kms_funcs {
int (*cont_splash_config)(struct msm_kms *kms);
/* check for continuous splash status */
bool (*check_for_splash)(struct msm_kms *kms);
/* topology information */
int (*get_mixer_count)(const struct msm_kms *kms,
const struct drm_display_mode *mode,
const struct msm_resource_caps_info *res, u32 *num_lm);
};
struct msm_kms {

View file

@ -2787,8 +2787,9 @@ static void _sde_cp_crtc_queue_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg)
struct drm_msm_ltm_buffer *buf;
struct drm_msm_ltm_stats_data *ltm_data = NULL;
u32 i;
bool found = false;
bool found = false, already = false;
unsigned long irq_flags;
struct sde_ltm_buffer *buffer = NULL, *n = NULL;
if (!sde_crtc || !cfg) {
DRM_ERROR("invalid parameters sde_crtc %pK cfg %pK\n", sde_crtc,
@ -2818,7 +2819,13 @@ static void _sde_cp_crtc_queue_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg)
sde_crtc->ltm_buffers[i]->offset);
ltm_data->status_flag = 0;
list_add_tail(&sde_crtc->ltm_buffers[i]->node,
list_for_each_entry_safe(buffer, n,
&sde_crtc->ltm_buf_free, node) {
if (buffer->drm_fb_id == buf->fd)
already = true;
}
if (!already)
list_add_tail(&sde_crtc->ltm_buffers[i]->node,
&sde_crtc->ltm_buf_free);
found = true;
}
@ -2892,6 +2899,7 @@ static void _sde_cp_crtc_enable_ltm_hist(struct sde_crtc *sde_crtc,
sde_crtc->ltm_hist_en = true;
hw_dspp->ops.setup_ltm_hist_ctrl(hw_dspp, hw_cfg,
true, addr);
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
}
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
}
@ -2902,15 +2910,30 @@ static void _sde_cp_crtc_disable_ltm_hist(struct sde_crtc *sde_crtc,
{
unsigned long irq_flags;
u32 i = 0;
bool notify = false;
u8 hist_off = 1;
struct drm_event event;
spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags);
notify = sde_crtc->ltm_hist_en;
sde_crtc->ltm_hist_en = false;
INIT_LIST_HEAD(&sde_crtc->ltm_buf_free);
INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy);
for (i = 0; i < sde_crtc->ltm_buffer_cnt; i++)
list_add(&sde_crtc->ltm_buffers[i]->node,
&sde_crtc->ltm_buf_free);
hw_dspp->ops.setup_ltm_hist_ctrl(hw_dspp, NULL,
false, 0);
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
event.type = DRM_EVENT_LTM_OFF;
event.length = sizeof(hist_off);
if (notify) {
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
msm_mode_object_event_notify(&sde_crtc->base.base,
sde_crtc->base.dev, &event,
(u8 *)&hist_off);
}
}
static void sde_cp_ltm_hist_interrupt_cb(void *arg, int irq_idx)
@ -2970,6 +2993,7 @@ static void sde_cp_ltm_hist_interrupt_cb(void *arg, int irq_idx)
}
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
DRM_DEBUG_DRIVER("LTM histogram is disabled\n");
return;
}
@ -3010,6 +3034,7 @@ static void sde_cp_ltm_hist_interrupt_cb(void *arg, int irq_idx)
list_del_init(&busy_buf->node);
list_del_init(&free_buf->node);
INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy);
list_add_tail(&free_buf->node, &sde_crtc->ltm_buf_busy);
ltm_data = (struct drm_msm_ltm_stats_data *)
@ -3019,6 +3044,7 @@ static void sde_cp_ltm_hist_interrupt_cb(void *arg, int irq_idx)
hw_lm = sde_crtc->mixers[0].hw_lm;
if (!hw_lm) {
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
DRM_ERROR("invalid layer mixer\n");
return;
}
@ -3085,6 +3111,7 @@ static void sde_cp_notify_ltm_hist(struct drm_crtc *crtc, void *arg)
/* histogram is disabled, no need to notify user space */
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
mutex_unlock(&sde_crtc->ltm_buffer_lock);
DRM_DEBUG_DRIVER("ltm histogram is disabled\n");
return;
}
@ -3093,6 +3120,8 @@ static void sde_cp_notify_ltm_hist(struct drm_crtc *crtc, void *arg)
payload.offset = buf->offset;
event.length = sizeof(struct drm_msm_ltm_buffer);
event.type = DRM_EVENT_LTM_HIST;
DRM_DEBUG_DRIVER("notify with LTM hist event drm_fb_id %d\n",
buf->drm_fb_id);
msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
(u8 *)&payload);
spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags);
@ -3305,3 +3334,9 @@ static void _sde_cp_crtc_update_ltm_roi(struct sde_crtc *sde_crtc,
sde_crtc->ltm_cfg = *cfg_param;
}
int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en,
struct sde_irq_callback *hist_irq)
{
return 0;
}

View file

@ -182,4 +182,12 @@ int sde_cp_ltm_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
int sde_cp_ltm_wb_pb_interrupt(struct drm_crtc *crtc_drm, bool en,
struct sde_irq_callback *hist_irq);
/**
* sde_cp_ltm_off_event_handler: API to enable/disable LTM off notification
* @crtc: Pointer to crtc.
* @en: Variable to enable/disable notification.
* @irq: Pointer to irq callback
*/
int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en,
struct sde_irq_callback *hist_irq);
#endif /*_SDE_COLOR_PROCESSING_H */

View file

@ -456,7 +456,7 @@ static inline bool _sde_core_perf_is_wb(struct drm_crtc *crtc)
{
enum sde_intf_mode if_mode = INTF_MODE_NONE;
if_mode = sde_crtc_get_intf_mode(crtc);
if_mode = sde_crtc_get_intf_mode(crtc, crtc->state);
if (if_mode == INTF_MODE_WB_BLOCK ||
if_mode == INTF_MODE_WB_LINE)
return true;
@ -678,7 +678,7 @@ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)
sde_cstate = to_sde_crtc_state(crtc->state);
/* only do this for command mode rt client (non-rsc client) */
if ((sde_crtc_get_intf_mode(crtc) != INTF_MODE_CMD) &&
if ((sde_crtc_get_intf_mode(crtc, crtc->state) != INTF_MODE_CMD) &&
(sde_crtc_get_client_type(crtc) != RT_RSC_CLIENT))
return;
@ -686,11 +686,11 @@ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)
* If video interface present, cmd panel bandwidth cannot be
* released.
*/
if (sde_crtc_get_intf_mode(crtc) == INTF_MODE_CMD)
if (sde_crtc_get_intf_mode(crtc, crtc->state) == INTF_MODE_CMD)
drm_for_each_crtc(tmp_crtc, crtc->dev) {
if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
sde_crtc_get_intf_mode(tmp_crtc) ==
INTF_MODE_VIDEO)
sde_crtc_get_intf_mode(tmp_crtc,
tmp_crtc->state) == INTF_MODE_VIDEO)
return;
}

View file

@ -66,6 +66,7 @@ static struct sde_crtc_custom_events custom_events[] = {
{DRM_EVENT_SDE_POWER, sde_crtc_pm_event_handler},
{DRM_EVENT_LTM_HIST, sde_cp_ltm_hist_interrupt},
{DRM_EVENT_LTM_WB_PB, sde_cp_ltm_wb_pb_interrupt},
{DRM_EVENT_LTM_OFF, sde_cp_ltm_off_event_handler},
};
/* default input fence timeout, in ms */
@ -729,9 +730,6 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
return -EINVAL;
}
if (!mode_info.roi_caps.enabled)
continue;
sde_conn = to_sde_connector(conn_state->connector);
sde_conn_state = to_sde_connector_state(conn_state);
@ -741,6 +739,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
&sde_conn_state->property_state,
CONNECTOR_PROP_ROI_V1);
if (!mode_info.roi_caps.enabled)
continue;
/*
* current driver only supports same connector and crtc size,
* but if support for different sizes is added, driver needs
@ -1781,6 +1782,8 @@ int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
return -EINVAL;
smmu_state = &sde_kms->smmu_state;
smmu_state->prev_state = smmu_state->state;
sde_crtc = to_sde_crtc(crtc);
secure_level = sde_crtc_get_secure_level(crtc, crtc->state);
catalog = sde_kms->catalog;
@ -1791,7 +1794,8 @@ int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
*/
drm_for_each_encoder_mask(encoder, crtc->dev,
crtc->state->encoder_mask) {
post_commit |= sde_encoder_check_curr_mode(encoder,
if (sde_encoder_is_dsi_display(encoder))
post_commit |= sde_encoder_check_curr_mode(encoder,
MSM_DISPLAY_VIDEO_MODE);
}
@ -2224,17 +2228,18 @@ end:
spin_unlock_irqrestore(&dev->event_lock, flags);
}
enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc)
enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc,
struct drm_crtc_state *cstate)
{
struct drm_encoder *encoder;
if (!crtc || !crtc->dev) {
if (!crtc || !crtc->dev || !cstate) {
SDE_ERROR("invalid crtc\n");
return INTF_MODE_NONE;
}
drm_for_each_encoder_mask(encoder, crtc->dev,
crtc->state->encoder_mask) {
cstate->encoder_mask) {
/* continue if copy encoder is encountered */
if (sde_encoder_in_clone_mode(encoder))
continue;
@ -4272,9 +4277,11 @@ static int _sde_crtc_check_secure_state_smmu_translation(struct drm_crtc *crtc,
struct drm_encoder *encoder;
int is_video_mode = false;
drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask)
is_video_mode |= sde_encoder_check_curr_mode(encoder,
drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) {
if (sde_encoder_is_dsi_display(encoder))
is_video_mode |= sde_encoder_check_curr_mode(encoder,
MSM_DISPLAY_VIDEO_MODE);
}
/*
* In video mode check for null commit before transition
@ -5584,7 +5591,8 @@ static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v)
seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc));
seq_printf(s, "intf_mode: %d\n", sde_crtc_get_intf_mode(crtc));
seq_printf(s, "intf_mode: %d\n", sde_crtc_get_intf_mode(crtc,
crtc->state));
seq_printf(s, "core_clk_rate: %llu\n",
sde_crtc->cur_perf.core_clk_rate);
for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC;

View file

@ -593,9 +593,11 @@ int sde_crtc_register_custom_event(struct sde_kms *kms,
/**
* sde_crtc_get_intf_mode - get interface mode of the given crtc
* @crtc: Pointert to crtc
* @crtc: Pointert to DRM crtc
* @crtc: Pointert to DRM crtc_state
*/
enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc);
enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc,
struct drm_crtc_state *cstate);
/**
* sde_crtc_get_fps_mode - get frame rate of the given crtc
@ -621,14 +623,16 @@ static inline enum sde_crtc_client_type sde_crtc_get_client_type(
/**
* sde_crtc_is_rt_client - check if real-time client or not
* @crtc: Pointer to crtc
* @crtc: Pointer to DRM crtc
* @crtc_state: Pointer to DRM crtc_state
*/
static inline bool sde_crtc_is_rt_client(struct drm_crtc *crtc)
static inline bool sde_crtc_is_rt_client(struct drm_crtc *crtc,
struct drm_crtc_state *cstate)
{
if (!crtc || !crtc->state)
if (!crtc || !cstate)
return true;
return (sde_crtc_get_intf_mode(crtc) != INTF_MODE_WB_LINE);
return (sde_crtc_get_intf_mode(crtc, cstate) != INTF_MODE_WB_LINE);
}
/**

View file

@ -456,6 +456,14 @@ bool sde_encoder_is_primary_display(struct drm_encoder *drm_enc)
SDE_CONNECTOR_PRIMARY);
}
bool sde_encoder_is_dsi_display(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
return sde_enc &&
(sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI);
}
int sde_encoder_in_cont_splash(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
@ -769,8 +777,8 @@ void sde_encoder_helper_update_intf_cfg(
struct sde_hw_intf_cfg_v1 *intf_cfg;
enum sde_3d_blend_mode mode_3d;
if (!phys_enc) {
SDE_ERROR("invalid arg, encoder %d\n", !phys_enc);
if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid args, encoder %d\n", !phys_enc);
return;
}
@ -1761,6 +1769,9 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
else
vsync_source = sde_enc->te_source;
SDE_EVT32(DRMID(&sde_enc->base), vsync_source, is_dummy,
disp_info->is_te_using_watchdog_timer);
for (i = 0; i < sde_enc->num_phys_encs; i++) {
phys = sde_enc->phys_encs[i];
@ -1817,7 +1828,8 @@ static void _sde_encoder_dsc_disable(struct sde_encoder_virt *sde_enc)
*/
}
static int _sde_encoder_switch_to_watchdog_vsync(struct drm_encoder *drm_enc)
int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
bool watchdog_te)
{
struct sde_encoder_virt *sde_enc;
struct msm_display_info disp_info;
@ -1832,7 +1844,7 @@ static int _sde_encoder_switch_to_watchdog_vsync(struct drm_encoder *drm_enc)
sde_encoder_control_te(drm_enc, false);
memcpy(&disp_info, &sde_enc->disp_info, sizeof(disp_info));
disp_info.is_te_using_watchdog_timer = true;
disp_info.is_te_using_watchdog_timer = watchdog_te;
_sde_encoder_update_vsync_source(sde_enc, &disp_info, false);
sde_encoder_control_te(drm_enc, true);
@ -1893,7 +1905,7 @@ static int _sde_encoder_rsc_client_update_vsync_wait(
* by generating the vsync from watchdog timer.
*/
if (crtc->base.id == wait_vblank_crtc_id)
_sde_encoder_switch_to_watchdog_vsync(drm_enc);
sde_encoder_helper_switch_vsync(drm_enc, true);
}
}
@ -3336,7 +3348,8 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
/* wait for idle */
sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
if (sde_enc->input_handler)
if (sde_enc->input_handler &&
sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
input_unregister_handler(sde_enc->input_handler);
/*
@ -5687,6 +5700,28 @@ int sde_encoder_wait_for_event(struct drm_encoder *drm_enc,
return ret;
}
void sde_encoder_helper_get_jitter_bounds_ns(struct drm_encoder *drm_enc,
u64 *l_bound, u64 *u_bound)
{
struct sde_encoder_virt *sde_enc;
u64 jitter_ns, frametime_ns;
struct msm_mode_info *info;
if (!drm_enc) {
SDE_ERROR("invalid encoder\n");
return;
}
sde_enc = to_sde_encoder_virt(drm_enc);
info = &sde_enc->mode_info;
frametime_ns = (1 * 1000000000) / info->frame_rate;
jitter_ns = (info->jitter_numer * frametime_ns) /
(info->jitter_denom * 100);
*l_bound = frametime_ns - jitter_ns;
*u_bound = frametime_ns + jitter_ns;
}
u32 sde_encoder_get_fps(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc;
@ -5984,12 +6019,12 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc,
kthread_flush_work(&sde_enc->esd_trigger_work);
}
/**
/*
* panel may stop generating te signal (vsync) during esd failure. rsc
* hardware may hang without vsync. Avoid rsc hang by generating the
* vsync from watchdog timer instead of panel.
*/
_sde_encoder_switch_to_watchdog_vsync(enc);
sde_encoder_helper_switch_vsync(enc, true);
if (!skip_pre_kickoff)
sde_encoder_wait_for_event(enc, MSM_ENC_TX_COMPLETE);

View file

@ -24,6 +24,7 @@
#include "msm_prop.h"
#include "sde_hw_mdss.h"
#include "sde_kms.h"
#include "sde_connector.h"
#define MAX_CHANNELS_PER_ENC 2
@ -51,7 +52,7 @@ struct sde_encoder_hw_resources {
enum sde_intf_mode wbs[WB_MAX];
bool needs_cdm;
u32 display_num_of_h_tiles;
bool display_type;
enum sde_connector_display display_type;
struct msm_display_topology topology;
};
@ -319,6 +320,14 @@ bool sde_encoder_in_clone_mode(struct drm_encoder *enc);
*/
bool sde_encoder_is_primary_display(struct drm_encoder *enc);
/**
* sde_encoder_is_dsi_display - checks if underlying display is DSI
* display or not.
* @drm_enc: Pointer to drm encoder structure
* @Return: true if it is primary display. false if secondary display
*/
bool sde_encoder_is_dsi_display(struct drm_encoder *enc);
/**
* sde_encoder_control_idle_pc - control enable/disable of idle power collapse
* @drm_enc: Pointer to drm encoder structure

View file

@ -25,6 +25,7 @@
#define KICKOFF_TIMEOUT_MS 84
#define KICKOFF_TIMEOUT_JIFFIES msecs_to_jiffies(KICKOFF_TIMEOUT_MS)
#define MAX_TE_PROFILE_COUNT 5
/**
* enum sde_enc_split_role - Role this physical encoder will play in a
* split-panel configuration, where one panel is master, and others slaves.
@ -361,6 +362,17 @@ struct sde_encoder_phys_cmd_autorefresh {
wait_queue_head_t kickoff_wq;
};
/**
* struct sde_encoder_phys_cmd_te_timestamp - list node to keep track of
* rd_ptr/TE timestamp
* @list: list node
* @timestamp: TE timestamp
*/
struct sde_encoder_phys_cmd_te_timestamp {
struct list_head list;
ktime_t timestamp;
};
/**
* struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command
* mode specific operations
@ -371,6 +383,8 @@ struct sde_encoder_phys_cmd_autorefresh {
* @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
* @pending_vblank_wq: Wait queue for blocking until VBLANK received
* @wr_ptr_wait_success: log wr_ptr_wait success for release fence trigger
* @te_timestamp_list: List head for the TE timestamp list
* @te_timestamp: Array of size MAX_TE_PROFILE_COUNT te_timestamp_list elements
*/
struct sde_encoder_phys_cmd {
struct sde_encoder_phys base;
@ -380,6 +394,9 @@ struct sde_encoder_phys_cmd {
atomic_t pending_vblank_cnt;
wait_queue_head_t pending_vblank_wq;
bool wr_ptr_wait_success;
struct list_head te_timestamp_list;
struct sde_encoder_phys_cmd_te_timestamp
te_timestamp[MAX_TE_PROFILE_COUNT];
};
/**
@ -558,6 +575,21 @@ int sde_encoder_helper_wait_event_timeout(
int32_t hw_id,
struct sde_encoder_wait_info *info);
/*
* sde_encoder_get_fps - get the allowed panel jitter in nanoseconds
* @encoder: Pointer to drm encoder object
*/
void sde_encoder_helper_get_jitter_bounds_ns(struct drm_encoder *encoder,
u64 *l_bound, u64 *u_bound);
/**
* sde_encoder_helper_switch_vsync - switch vsync source to WD or default
* @drm_enc: Pointer to drm encoder structure
* @watchdog_te: switch vsync source to watchdog TE
*/
int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
bool watchdog_te);
/**
* sde_encoder_helper_hw_reset - issue ctl hw reset
* This helper function may be optionally specified by physical

View file

@ -230,6 +230,8 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx)
u32 scheduler_status = INVALID_CTL_STATUS;
struct sde_hw_ctl *ctl;
struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}};
struct sde_encoder_phys_cmd_te_timestamp *te_timestamp;
unsigned long lock_flags;
if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf)
return;
@ -241,6 +243,16 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx)
if (ctl && ctl->ops.get_scheduler_status)
scheduler_status = ctl->ops.get_scheduler_status(ctl);
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
te_timestamp = list_first_entry_or_null(&cmd_enc->te_timestamp_list,
struct sde_encoder_phys_cmd_te_timestamp, list);
if (te_timestamp) {
list_del_init(&te_timestamp->list);
te_timestamp->timestamp = ktime_get();
list_add_tail(&te_timestamp->list, &cmd_enc->te_timestamp_list);
}
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
sde_encoder_helper_get_pp_line_count(phys_enc->parent, info);
SDE_EVT32_IRQ(DRMID(phys_enc->parent),
info[0].pp_idx, info[0].intf_idx,
@ -1337,11 +1349,54 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
return ret;
}
static bool _sde_encoder_phys_cmd_needs_vsync_change(
struct sde_encoder_phys *phys_enc, ktime_t profile_timestamp)
{
struct sde_encoder_phys_cmd *cmd_enc;
struct sde_encoder_phys_cmd_te_timestamp *cur;
struct sde_encoder_phys_cmd_te_timestamp *prev = NULL;
ktime_t time_diff;
u64 l_bound = 0, u_bound = 0;
bool ret = false;
unsigned long lock_flags;
cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
sde_encoder_helper_get_jitter_bounds_ns(phys_enc->parent,
&l_bound, &u_bound);
if (!l_bound || !u_bound) {
SDE_ERROR_CMDENC(cmd_enc, "invalid vsync jitter bounds\n");
return false;
}
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
list_for_each_entry_reverse(cur, &cmd_enc->te_timestamp_list, list) {
if (prev && ktime_after(cur->timestamp, profile_timestamp)) {
time_diff = ktime_sub(prev->timestamp, cur->timestamp);
if ((time_diff < l_bound) || (time_diff > u_bound)) {
ret = true;
break;
}
}
prev = cur;
}
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
if (ret) {
SDE_DEBUG_CMDENC(cmd_enc,
"time_diff:%llu, prev:%llu, cur:%llu, jitter:%llu/%llu\n",
time_diff, prev->timestamp, cur->timestamp,
l_bound, u_bound);
SDE_EVT32(DRMID(phys_enc->parent),
(u32) (l_bound / 1000), (u32) (u_bound / 1000),
(u32) (time_diff / 1000), SDE_EVTLOG_ERROR);
}
return ret;
}
static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
struct sde_encoder_phys *phys_enc)
{
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
struct sde_encoder_wait_info wait_info = {0};
int ret;
bool frame_pending = true;
@ -1369,29 +1424,9 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
if (ctl && ctl->ops.get_start_state)
frame_pending = ctl->ops.get_start_state(ctl);
if (frame_pending)
SDE_ERROR_CMDENC(cmd_enc,
"wr_ptrt start interrupt wait failed\n");
else
ret = 0;
/*
* Signaling the retire fence at wr_ptr timeout
* to allow the next commit and avoid device freeze.
* As wr_ptr timeout can occurs due to no read ptr,
* updating pending_rd_ptr_cnt here may not cover all
* cases. Hence signaling the retire fence.
*/
if (sde_encoder_phys_cmd_is_master(phys_enc) &&
atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
-1, 0))
phys_enc->parent_ops.handle_frame_done(
phys_enc->parent, phys_enc,
SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
ret = frame_pending ? ret : 0;
}
cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false;
return ret;
}
@ -1406,6 +1441,13 @@ static int sde_encoder_phys_cmd_wait_for_tx_complete(
cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
if (!atomic_read(&phys_enc->pending_kickoff_cnt)) {
SDE_EVT32(DRMID(phys_enc->parent),
phys_enc->intf_idx - INTF_0,
phys_enc->enable_state);
return 0;
}
rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
if (rc) {
SDE_EVT32(DRMID(phys_enc->parent),
@ -1416,11 +1458,60 @@ static int sde_encoder_phys_cmd_wait_for_tx_complete(
return rc;
}
static int _sde_encoder_phys_cmd_handle_wr_ptr_timeout(
struct sde_encoder_phys *phys_enc,
ktime_t profile_timestamp)
{
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
bool switch_te;
int ret = -ETIMEDOUT;
switch_te = _sde_encoder_phys_cmd_needs_vsync_change(
phys_enc, profile_timestamp);
SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_FUNC_ENTRY);
if (switch_te) {
SDE_DEBUG_CMDENC(cmd_enc,
"wr_ptr_irq wait failed, retry with WD TE\n");
/* switch to watchdog TE and wait again */
sde_encoder_helper_switch_vsync(phys_enc->parent, true);
ret = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
/* switch back to default TE */
sde_encoder_helper_switch_vsync(phys_enc->parent, false);
}
/*
* Signaling the retire fence at wr_ptr timeout
* to allow the next commit and avoid device freeze.
*/
if (ret == -ETIMEDOUT) {
SDE_ERROR_CMDENC(cmd_enc,
"wr_ptr_irq wait failed, switch_te:%d\n", switch_te);
SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_ERROR);
if (sde_encoder_phys_cmd_is_master(phys_enc) &&
atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0))
phys_enc->parent_ops.handle_frame_done(
phys_enc->parent, phys_enc,
SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
}
cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false;
return ret;
}
static int sde_encoder_phys_cmd_wait_for_commit_done(
struct sde_encoder_phys *phys_enc)
{
int rc = 0, i, pending_cnt;
struct sde_encoder_phys_cmd *cmd_enc;
ktime_t profile_timestamp = ktime_get();
if (!phys_enc)
return -EINVAL;
@ -1430,8 +1521,18 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(
/* only required for master controller */
if (sde_encoder_phys_cmd_is_master(phys_enc)) {
rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
if (rc == -ETIMEDOUT)
goto wait_for_idle;
if (rc == -ETIMEDOUT) {
/*
* Profile all the TE received after profile_timestamp
* and if the jitter is more, switch to watchdog TE
* and wait for wr_ptr again. Finally move back to
* default TE.
*/
rc = _sde_encoder_phys_cmd_handle_wr_ptr_timeout(
phys_enc, profile_timestamp);
if (rc == -ETIMEDOUT)
goto wait_for_idle;
}
if (cmd_enc->autorefresh.cfg.enable)
rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(
@ -1753,6 +1854,10 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init(
init_waitqueue_head(&cmd_enc->pending_vblank_wq);
atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0);
init_waitqueue_head(&cmd_enc->autorefresh.kickoff_wq);
INIT_LIST_HEAD(&cmd_enc->te_timestamp_list);
for (i = 0; i < MAX_TE_PROFILE_COUNT; i++)
list_add(&cmd_enc->te_timestamp[i].list,
&cmd_enc->te_timestamp_list);
SDE_DEBUG_CMDENC(cmd_enc, "created\n");

View file

@ -4127,14 +4127,15 @@ static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg,
sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth *
max_horz_deci;
else
sde_cfg->max_display_width = sde_cfg->max_mixer_width *
sde_cfg->max_lm_per_display;
sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth *
MAX_DOWNSCALE_RATIO;
if (max_vert_deci)
sde_cfg->max_display_height =
MAX_DISPLAY_HEIGHT_WITH_DECIMATION * max_vert_deci;
else
sde_cfg->max_display_height = MAX_DISPLAY_HEIGHT;
sde_cfg->max_display_height = MAX_DISPLAY_HEIGHT_WITH_DECIMATION
* MAX_DOWNSCALE_RATIO;
sde_cfg->min_display_height = MIN_DISPLAY_HEIGHT;
sde_cfg->min_display_width = MIN_DISPLAY_WIDTH;

View file

@ -150,7 +150,7 @@ void sde_setup_dspp_igcv3(struct sde_hw_dspp *ctx, void *cfg)
struct drm_msm_igc_lut *lut_cfg;
struct sde_hw_cp_cfg *hw_cfg = cfg;
int i = 0, j = 0;
u32 *addr = NULL;
u32 *addr[IGC_TBL_NUM];
u32 offset = 0;
if (!ctx || !cfg) {
@ -172,17 +172,20 @@ void sde_setup_dspp_igcv3(struct sde_hw_dspp *ctx, void *cfg)
lut_cfg = hw_cfg->payload;
addr[0] = lut_cfg->c0;
addr[1] = lut_cfg->c1;
addr[2] = lut_cfg->c2;
for (i = 0; i < IGC_TBL_NUM; i++) {
addr = lut_cfg->c0 + (i * ARRAY_SIZE(lut_cfg->c0));
offset = IGC_C0_OFF + (i * sizeof(u32));
for (j = 0; j < IGC_TBL_LEN; j++) {
addr[j] &= IGC_DATA_MASK;
addr[j] |= IGC_DSPP_SEL_MASK(ctx->idx - 1);
addr[i][j] &= IGC_DATA_MASK;
addr[i][j] |= IGC_DSPP_SEL_MASK(ctx->idx - 1);
if (j == 0)
addr[j] |= IGC_INDEX_UPDATE;
addr[i][j] |= IGC_INDEX_UPDATE;
/* IGC lut registers are part of DSPP Top HW block */
SDE_REG_WRITE(&ctx->hw_top, offset, addr[j]);
SDE_REG_WRITE(&ctx->hw_top, offset, addr[i][j]);
}
}

View file

@ -1041,6 +1041,7 @@ static int sde_hw_ctl_reset_post_disable(struct sde_hw_ctl *ctx,
ctx->flush.pending_merge_3d_flush_mask =
BIT(merge_3d_idx - MERGE_3D_0);
merge_3d_active &= ~BIT(merge_3d_idx - MERGE_3D_0);
UPDATE_MASK(ctx->flush.pending_flush_mask, MERGE_3D_IDX, 1);
SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active);
}

View file

@ -830,6 +830,7 @@ void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg)
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
int rc, i = 0;
u32 reg;
u32 *addr[GC_TBL_NUM];
u32 num_of_mixers, blk = 0;
rc = reg_dma_dspp_check(ctx, cfg, GC);
@ -870,6 +871,9 @@ void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg)
return;
}
addr[0] = lut_cfg->c0;
addr[1] = lut_cfg->c1;
addr[2] = lut_cfg->c2;
for (i = 0; i < GC_TBL_NUM; i++) {
reg = 0;
REG_DMA_SETUP_OPS(dma_write_cfg,
@ -885,7 +889,7 @@ void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg)
REG_DMA_SETUP_OPS(dma_write_cfg,
ctx->cap->sblk->gc.base + GC_C0_OFF +
(i * sizeof(u32) * 2),
lut_cfg->c0 + (ARRAY_SIZE(lut_cfg->c0) * i),
addr[i],
PGC_TBL_LEN * sizeof(u32),
REG_BLK_WRITE_INC, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
@ -981,7 +985,7 @@ void reg_dmav1_setup_dspp_igcv31(struct sde_hw_dspp *ctx, void *cfg)
struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
struct sde_hw_dspp *dspp_list[DSPP_MAX];
int rc, i = 0, j = 0;
u32 *addr = NULL;
u32 *addr[IGC_TBL_NUM];
u32 offset = 0;
u32 reg;
u32 index, num_of_mixers, dspp_sel, blk = 0;
@ -1038,18 +1042,20 @@ void reg_dmav1_setup_dspp_igcv31(struct sde_hw_dspp *ctx, void *cfg)
for (index = 0; index < num_of_mixers; index++)
dspp_sel &= IGC_DSPP_SEL_MASK(dspp_list[index]->idx - 1);
addr[0] = lut_cfg->c0;
addr[1] = lut_cfg->c1;
addr[2] = lut_cfg->c2;
for (i = 0; i < IGC_TBL_NUM; i++) {
addr = lut_cfg->c0 + (i * ARRAY_SIZE(lut_cfg->c0));
offset = IGC_C0_OFF + (i * sizeof(u32));
for (j = 0; j < IGC_TBL_LEN; j++) {
addr[j] &= IGC_DATA_MASK;
addr[j] |= dspp_sel;
addr[i][j] &= IGC_DATA_MASK;
addr[i][j] |= dspp_sel;
if (j == 0)
addr[j] |= IGC_INDEX_UPDATE;
addr[i][j] |= IGC_INDEX_UPDATE;
}
REG_DMA_SETUP_OPS(dma_write_cfg, offset, addr,
REG_DMA_SETUP_OPS(dma_write_cfg, offset, addr[i],
IGC_TBL_LEN * sizeof(u32),
REG_BLK_WRITE_INC, 0, 0, 0);
rc = dma_ops->setup_payload(&dma_write_cfg);
@ -2231,6 +2237,7 @@ static int reg_dmav1_setup_vig_igc_common(struct sde_hw_reg_dma_ops *dma_ops,
u32 lut_sel = 0, lut_enable = 0;
u32 *data = NULL, *data_ptr = NULL;
u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF;
u32 *addr[IGC_TBL_NUM];
if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) {
DRM_ERROR("invalid size of payload len %d exp %zd\n",
@ -2248,6 +2255,9 @@ static int reg_dmav1_setup_vig_igc_common(struct sde_hw_reg_dma_ops *dma_ops,
if (lut_enable)
lut_sel = (~lut_sel) && BIT(0);
addr[0] = igc_lut->c0;
addr[1] = igc_lut->c1;
addr[2] = igc_lut->c2;
for (i = 0; i < IGC_TBL_NUM; i++) {
/* write 0 to the index register */
index = 0;
@ -2260,7 +2270,7 @@ static int reg_dmav1_setup_vig_igc_common(struct sde_hw_reg_dma_ops *dma_ops,
}
offset = igc_base + 0x1B4 + i * sizeof(u32);
data_ptr = igc_lut->c0 + (ARRAY_SIZE(igc_lut->c0) * i);
data_ptr = addr[i];
for (j = 0; j < VIG_1D_LUT_IGC_LEN; j++)
data[j] = (data_ptr[2 * j] & mask) |
(data_ptr[2 * j + 1] & mask) << 16;

View file

@ -1023,10 +1023,16 @@ static void sde_hw_sspp_setup_uidle(struct sde_hw_pipe *ctx,
}
static void _setup_layer_ops_colorproc(struct sde_hw_pipe *c,
unsigned long features)
unsigned long features, bool is_virtual_pipe)
{
int ret = 0;
if (is_virtual_pipe) {
features &=
~(BIT(SDE_SSPP_VIG_IGC) | BIT(SDE_SSPP_VIG_GAMUT));
c->cap->features = features;
}
if (test_bit(SDE_SSPP_HSIC, &features)) {
if (c->cap->sblk->hsic_blk.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x7))) {
@ -1181,7 +1187,8 @@ static void sde_hw_sspp_setup_dgm_csc(struct sde_hw_pipe *ctx,
}
static void _setup_layer_ops(struct sde_hw_pipe *c,
unsigned long features, unsigned long perf_features)
unsigned long features, unsigned long perf_features,
bool is_virtual_pipe)
{
int ret;
@ -1247,7 +1254,7 @@ static void _setup_layer_ops(struct sde_hw_pipe *c,
if (test_bit(SDE_PERF_SSPP_UIDLE, &perf_features))
c->ops.setup_uidle = sde_hw_sspp_setup_uidle;
_setup_layer_ops_colorproc(c, features);
_setup_layer_ops_colorproc(c, features, is_virtual_pipe);
if (test_bit(SDE_SSPP_DGM_INVERSE_PMA, &features))
c->ops.setup_inverse_pma = sde_hw_sspp_setup_dgm_inverse_pma;
@ -1264,6 +1271,7 @@ static struct sde_sspp_cfg *_sspp_offset(enum sde_sspp sspp,
struct sde_hw_blk_reg_map *b)
{
int i;
struct sde_sspp_cfg *cfg;
if ((sspp < SSPP_MAX) && catalog && addr && b) {
for (i = 0; i < catalog->sspp_count; i++) {
@ -1273,7 +1281,14 @@ static struct sde_sspp_cfg *_sspp_offset(enum sde_sspp sspp,
b->length = catalog->sspp[i].len;
b->hwversion = catalog->hwversion;
b->log_mask = SDE_DBG_MASK_SSPP;
return &catalog->sspp[i];
/* Only shallow copy is needed */
cfg = kmemdup(&catalog->sspp[i], sizeof(*cfg),
GFP_KERNEL);
if (!cfg)
return ERR_PTR(-ENOMEM);
return cfg;
}
}
}
@ -1313,7 +1328,7 @@ struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx,
hw_pipe->idx = idx;
hw_pipe->cap = cfg;
_setup_layer_ops(hw_pipe, hw_pipe->cap->features,
hw_pipe->cap->perf_features);
hw_pipe->cap->perf_features, is_virtual_pipe);
if (hw_pipe->ops.get_scaler_ver) {
sde_init_scaler_blk(&hw_pipe->cap->sblk->scaler_blk,
@ -1353,6 +1368,7 @@ void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx)
if (ctx) {
sde_hw_blk_destroy(&ctx->base);
reg_dmav1_deinit_sspp_ops(ctx->idx);
kfree(ctx->cap);
}
kfree(ctx);
}

View file

@ -19,6 +19,7 @@
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
#include <drm/drm_crtc.h>
#include <drm/drm_fixed.h>
#include <linux/debugfs.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -528,12 +529,24 @@ static int _sde_kms_secure_ctrl(struct sde_kms *sde_kms, struct drm_crtc *crtc,
end:
smmu_state->sui_misr_state = NONE;
smmu_state->transition_type = NONE;
smmu_state->transition_error = ret ? true : false;
smmu_state->transition_error = false;
SDE_DEBUG("crtc %d: old_state %d, new_state %d, sec_lvl %d, ret %d\n",
DRMID(crtc), old_smmu_state, smmu_state->state,
smmu_state->secure_level, ret);
SDE_EVT32(DRMID(crtc), smmu_state->state, smmu_state->transition_type,
/*
* If switch failed, toggling secure_level is enough since
* there are only two secure levels - secure/non-secure
*/
if (ret) {
smmu_state->transition_error = true;
smmu_state->state = smmu_state->prev_state;
smmu_state->secure_level = !smmu_state->secure_level;
}
SDE_DEBUG(
"crtc %d: old_state %d, req_state %d, new_state %d, sec_lvl %d, ret %d\n",
DRMID(crtc), smmu_state->prev_state, old_smmu_state,
smmu_state->state, smmu_state->secure_level, ret);
SDE_EVT32(DRMID(crtc), smmu_state->prev_state,
smmu_state->state, smmu_state->transition_type,
smmu_state->transition_error, smmu_state->secure_level,
smmu_state->sui_misr_state, ret, SDE_EVTLOG_FUNC_EXIT);
@ -2456,6 +2469,52 @@ static bool sde_kms_check_for_splash(struct msm_kms *kms)
return sde_kms->splash_data.num_splash_displays;
}
static int sde_kms_get_mixer_count(const struct msm_kms *kms,
const struct drm_display_mode *mode,
const struct msm_resource_caps_info *res, u32 *num_lm)
{
struct sde_kms *sde_kms;
s64 mode_clock_hz = 0;
s64 max_mdp_clock_hz = 0;
s64 mdp_fudge_factor = 0;
s64 temp = 0;
s64 htotal_fp = 0;
s64 vtotal_fp = 0;
s64 vrefresh_fp = 0;
if (!num_lm) {
SDE_ERROR("invalid num_lm pointer\n");
return -EINVAL;
}
*num_lm = 1;
if (!kms || !mode || !res) {
SDE_ERROR("invalid input args\n");
return -EINVAL;
}
sde_kms = to_sde_kms(kms);
max_mdp_clock_hz = drm_fixp_from_fraction(
sde_kms->perf.max_core_clk_rate, 1);
mdp_fudge_factor = drm_fixp_from_fraction(105, 100); /* 1.05 */
htotal_fp = drm_fixp_from_fraction(mode->htotal, 1);
vtotal_fp = drm_fixp_from_fraction(mode->vtotal, 1);
vrefresh_fp = drm_fixp_from_fraction(mode->vrefresh, 1);
temp = drm_fixp_mul(htotal_fp, vtotal_fp);
temp = drm_fixp_mul(temp, vrefresh_fp);
mode_clock_hz = drm_fixp_mul(temp, mdp_fudge_factor);
if (mode_clock_hz > max_mdp_clock_hz ||
mode->hdisplay > res->max_mixer_width)
*num_lm = 2;
SDE_DEBUG("[%s] h=%d, v=%d, fps=%d, max_mdp_clk_hz=%llu, num_lm=%d\n",
mode->name, mode->htotal, mode->vtotal, mode->vrefresh,
sde_kms->perf.max_core_clk_rate, *num_lm);
return 0;
}
static void _sde_kms_null_commit(struct drm_device *dev,
struct drm_encoder *enc)
{
@ -2528,6 +2587,45 @@ end:
drm_modeset_acquire_fini(&ctx);
}
static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms,
struct device *dev)
{
int i, ret;
struct drm_device *ddev = dev_get_drvdata(dev);
struct drm_connector *conn;
struct drm_connector_list_iter conn_iter;
struct msm_drm_private *priv = sde_kms->dev->dev_private;
drm_connector_list_iter_begin(ddev, &conn_iter);
drm_for_each_connector_iter(conn, &conn_iter) {
uint64_t lp;
lp = sde_connector_get_lp(conn);
if (lp != SDE_MODE_DPMS_LP2)
continue;
ret = sde_encoder_wait_for_event(conn->encoder,
MSM_ENC_TX_COMPLETE);
if (ret && ret != -EWOULDBLOCK)
SDE_ERROR(
"[conn: %d] wait for commit done returned %d\n",
conn->base.id, ret);
else if (!ret)
sde_encoder_idle_request(conn->encoder);
}
drm_connector_list_iter_end(&conn_iter);
for (i = 0; i < priv->num_crtcs; i++) {
if (priv->disp_thread[i].thread)
kthread_flush_worker(
&priv->disp_thread[i].worker);
if (priv->event_thread[i].thread)
kthread_flush_worker(
&priv->event_thread[i].worker);
}
kthread_flush_worker(&priv->pp_event_worker);
}
static int sde_kms_pm_suspend(struct device *dev)
{
struct drm_device *ddev;
@ -2548,6 +2646,7 @@ static int sde_kms_pm_suspend(struct device *dev)
sde_kms = to_sde_kms(ddev_to_msm_kms(ddev));
SDE_EVT32(0);
pm_runtime_put_noidle(dev);
/* disable hot-plug polling */
drm_kms_helper_poll_disable(ddev);
@ -2630,6 +2729,7 @@ retry:
if (num_crtcs == 0) {
DRM_DEBUG("all crtcs are already in the off state\n");
sde_kms->suspend_block = true;
_sde_kms_pm_suspend_idle_helper(sde_kms, dev);
goto unlock;
}
@ -2641,25 +2741,8 @@ retry:
}
sde_kms->suspend_block = true;
_sde_kms_pm_suspend_idle_helper(sde_kms, dev);
drm_connector_list_iter_begin(ddev, &conn_iter);
drm_for_each_connector_iter(conn, &conn_iter) {
uint64_t lp;
lp = sde_connector_get_lp(conn);
if (lp != SDE_MODE_DPMS_LP2)
continue;
ret = sde_encoder_wait_for_event(conn->encoder,
MSM_ENC_TX_COMPLETE);
if (ret && ret != -EWOULDBLOCK)
SDE_ERROR(
"[enc: %d] wait for commit done returned %d\n",
conn->encoder->base.id, ret);
else if (!ret)
sde_encoder_idle_request(conn->encoder);
}
drm_connector_list_iter_end(&conn_iter);
unlock:
if (state) {
drm_atomic_state_put(state);
@ -2672,6 +2755,7 @@ unlock:
}
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
pm_runtime_get_noresume(dev);
return ret;
}
@ -2766,6 +2850,7 @@ static const struct msm_kms_funcs kms_funcs = {
.get_address_space_device = _sde_kms_get_address_space_device,
.postopen = _sde_kms_post_open,
.check_for_splash = sde_kms_check_for_splash,
.get_mixer_count = sde_kms_get_mixer_count,
};
/* the caller api needs to turn on clock before calling it */

View file

@ -187,12 +187,14 @@ enum frame_trigger_mode_type {
/**
* struct sde_kms_smmu_state_data: stores the smmu state and transition type
* @state: current state of smmu context banks
* @prev_state: previous state of smmu context banks
* @secure_level: secure level cached from crtc
* @transition_type: transition request type
* @transition_error: whether there is error while transitioning the state
*/
struct sde_kms_smmu_state_data {
uint32_t state;
uint32_t prev_state;
uint32_t secure_level;
uint32_t transition_type;
uint32_t transition_error;

View file

@ -2406,6 +2406,12 @@ static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state,
uint32_t max_upscale, max_linewidth;
bool inline_rotation, rt_client;
struct drm_crtc *crtc;
struct drm_crtc_state *new_cstate;
if (!state || !state->state || !state->crtc) {
SDE_ERROR_PLANE(psde, "invalid arguments\n");
return -EINVAL;
}
deci_w = sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
deci_h = sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
@ -2427,7 +2433,9 @@ static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state,
max_linewidth = psde->pipe_sblk->maxlinewidth;
crtc = state->crtc;
rt_client = sde_crtc_is_rt_client(crtc);
new_cstate = drm_atomic_get_new_crtc_state(state->state, crtc);
rt_client = sde_crtc_is_rt_client(crtc, new_cstate);
max_downscale_denom = 1;
/* inline rotation RT clients have a different max downscaling limit */
@ -3208,7 +3216,7 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
return 0;
pstate->pending = true;
psde->is_rt_pipe = sde_crtc_is_rt_client(crtc);
psde->is_rt_pipe = sde_crtc_is_rt_client(crtc, crtc->state);
_sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
_sde_plane_update_properties(plane, crtc, fb);

View file

@ -929,19 +929,24 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
{
const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap;
const struct sde_pingpong_cfg *pp_cfg;
bool ret;
u32 display_pref, cwb_pref;
bool ret, is_conn_primary, is_conn_secondary;
u32 lm_primary_pref, lm_secondary_pref, cwb_pref;
*dspp = NULL;
*ds = NULL;
*pp = NULL;
display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF) ||
lm_cfg->features & BIT(SDE_DISP_SECONDARY_PREF);
cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF);
SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n",
lm_cfg->id, lm_cfg->dspp, lm_cfg->ds,
lm_cfg->pingpong, display_pref, cwb_pref);
lm_primary_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF);
lm_secondary_pref = lm_cfg->features & BIT(SDE_DISP_SECONDARY_PREF);
cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF);
is_conn_primary = (reqs->hw_res.display_type ==
SDE_CONNECTOR_PRIMARY) ? true : false;
is_conn_secondary = (reqs->hw_res.display_type ==
SDE_CONNECTOR_SECONDARY) ? true : false;
SDE_DEBUG("check lm %d: dspp %d ds %d pp %d features %d disp type %d\n",
lm_cfg->id, lm_cfg->dspp, lm_cfg->ds, lm_cfg->pingpong,
lm_cfg->features, (int)reqs->hw_res.display_type);
/* Check if this layer mixer is a peer of the proposed primary LM */
if (primary_lm) {
@ -956,7 +961,7 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
}
/* bypass rest of the checks if LM for primary display is found */
if (!display_pref) {
if (!lm_primary_pref && !lm_secondary_pref) {
/* Check lm for valid requirements */
ret = _sde_rm_check_lm(rm, rsvp, reqs, lm_cfg, lm,
dspp, ds, pp);
@ -971,10 +976,11 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
SDE_DEBUG("fail: cwb supported lm not allocated\n");
return false;
}
} else if (!(reqs->hw_res.display_type && display_pref)) {
} else if ((!is_conn_primary && lm_primary_pref) ||
(!is_conn_secondary && lm_secondary_pref)) {
SDE_DEBUG(
"display preference is not met. display_type: %d display_pref: %d\n",
(int)reqs->hw_res.display_type, (int)display_pref);
"display preference is not met. display_type: %d lm_features: %x\n",
(int)reqs->hw_res.display_type, lm_cfg->features);
return false;
}

View file

@ -288,9 +288,7 @@ int sde_wb_config(struct drm_device *drm_dev, void *data,
}
static inline
int sde_wb_connector_post_init(struct drm_connector *connector,
void *info,
void *display,
struct msm_mode_info *mode_info)
void *display)
{
return 0;
}
@ -318,7 +316,8 @@ int sde_wb_connector_set_property(struct drm_connector *connector,
return 0;
}
static inline
int sde_wb_get_info(struct msm_display_info *info, void *display)
int sde_wb_get_info(struct drm_connector *connector,
struct msm_display_info *info, void *display)
{
return 0;
}
@ -341,7 +340,23 @@ int sde_wb_connector_state_get_output_roi(struct drm_connector_state *state,
{
return 0;
}
static inline
int sde_wb_connector_set_info_blob(struct drm_connector *connector,
void *info,
void *display,
struct msm_mode_info *mode_info)
{
return 0;
}
static inline
int sde_wb_get_mode_info(struct drm_connector *connector,
const struct drm_display_mode *drm_mode,
struct msm_mode_info *mode_info,
void *display, const struct msm_resource_caps_info *avail_res)
{
return 0;
}
#endif
#endif /* __SDE_WB_H__ */

View file

@ -3754,6 +3754,9 @@ static ssize_t sde_dbg_ctrl_read(struct file *file, char __user *buff,
pr_debug("%s: ctrl:0x%x len:0x%zx\n",
__func__, sde_dbg_base.debugfs_ctrl, len);
if (len < 0 || len >= sizeof(buf))
return 0;
if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) {
pr_err("error copying the buffer! count:0x%zx\n", count);
return -EFAULT;

View file

@ -37,10 +37,11 @@
/**
* rsc_min_threshold will be set to MIN_THRESHOLD_OVERHEAD_TIME which
* takes into account back off time + overhead from RSC/RSC_WRAPPER. The
* overhead buffer time is required to be greater than 14. For measure,
* this value assumes 18.
* overhead buffer time is required to be greater than 14. Program it
* with a higher value (3.3 ms), so it has sufficient time to complete
* the sequence in rare cases.
*/
#define MIN_THRESHOLD_OVERHEAD_TIME 18
#define MIN_THRESHOLD_OVERHEAD_TIME 64
#define DEFAULT_PANEL_FPS 60
#define DEFAULT_PANEL_JITTER_NUMERATOR 2

View file

@ -872,14 +872,19 @@ int rsc_hw_tcs_wait(struct sde_rsc_priv *rsc)
}
/* check for sequence running status before exiting */
for (count = MAX_CHECK_LOOPS; count > 0; count--) {
for (count = (MAX_CHECK_LOOPS / 4); count > 0; count--) {
seq_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
rsc->debug_mode) & BIT(1);
if (!seq_status) {
rc = 0;
break;
}
usleep_range(1, 2);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
0x1, rsc->debug_mode);
usleep_range(3, 4);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
0x0, rsc->debug_mode);
}
return rc;

View file

@ -1189,13 +1189,6 @@ static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw,
struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw);
struct mdss_pll_resources *pll = vco->priv;
int rc;
u64 ref_clk = vco->ref_clk_rate;
u64 vco_rate;
u64 multiplier;
u32 frac;
u32 dec;
u32 outdiv;
u64 pll_freq, tmp64;
if (!vco->priv)
pr_err("vco priv is null\n");
@ -1206,12 +1199,10 @@ static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw,
}
/*
* Calculate the vco rate from HW registers only for handoff cases.
* For other cases where a vco_10nm_set_rate() has already been
* called, just return the rate that was set earlier. This is due
* to the fact that recalculating VCO rate requires us to read the
* correct value of the pll_out_div divider clock, which is only set
* afterwards.
* In the case when vco arte is set, the recalculation function should
* return the current rate as to avoid trying to set the vco rate
* again. However durng handoff, recalculation should set the flag
* according to the status of PLL.
*/
if (pll->vco_current_rate != 0) {
pr_debug("returning vco rate = %lld\n", pll->vco_current_rate);
@ -1228,40 +1219,10 @@ static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw,
if (!dsi_pll_10nm_lock_status(pll))
pll->handoff_resources = true;
dec = MDSS_PLL_REG_R(pll->pll_base, PLL_DECIMAL_DIV_START_1);
dec &= 0xFF;
frac = MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_LOW_1);
frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_MID_1) &
0xFF) <<
8);
frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_HIGH_1) &
0x3) <<
16);
/* OUTDIV_1:0 field is (log(outdiv, 2)) */
outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE);
outdiv &= 0x3;
outdiv = 1 << outdiv;
/*
* TODO:
* 1. Assumes prescaler is disabled
* 2. Multiplier is 2^18. it should be 2^(num_of_frac_bits)
**/
multiplier = 1 << 18;
pll_freq = dec * (ref_clk * 2);
tmp64 = (ref_clk * 2 * frac);
pll_freq += div_u64(tmp64, multiplier);
vco_rate = div_u64(pll_freq, outdiv);
pr_debug("dec=0x%x, frac=0x%x, outdiv=%d, vco=%llu\n",
dec, frac, outdiv, vco_rate);
(void)mdss_pll_resource_enable(pll, false);
return (unsigned long)vco_rate;
return rc;
}
static int pixel_clk_get_div(void *context, unsigned int reg, unsigned int *div)

View file

@ -1046,7 +1046,7 @@ static void shadow_dsi_pll_dynamic_refresh_7nm(struct dsi_pll_7nm *pll,
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL4,
(PLL_SYSTEM_MUXES + offset),
(PLL_PLL_LOCKDET_RATE_1 + offset),
0xc0, 0x40);
0xc0, 0x10);
upper_addr |= (upper_8_bit(PLL_SYSTEM_MUXES + offset) << 8);
upper_addr |= (upper_8_bit(PLL_PLL_LOCKDET_RATE_1 + offset) << 9);
@ -1077,92 +1077,88 @@ static void shadow_dsi_pll_dynamic_refresh_7nm(struct dsi_pll_7nm *pll,
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL8,
(PLL_ANALOG_CONTROLS_FIVE + offset),
(PLL_DSM_DIVIDER + offset), 0x01, 0);
(PLL_ANALOG_CONTROLS_TWO + offset), 0x01, 0x03);
upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_FIVE + offset) << 16);
upper_addr |= (upper_8_bit(PLL_DSM_DIVIDER + offset) << 17);
upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_TWO + offset) << 17);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL9,
(PLL_FEEDBACK_DIVIDER + offset),
(PLL_CALIBRATION_SETTINGS + offset), 0x4E, 0x40);
upper_addr |= (upper_8_bit(PLL_FEEDBACK_DIVIDER + offset) << 18);
upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 19);
(PLL_ANALOG_CONTROLS_THREE + offset),
(PLL_DSM_DIVIDER + offset),
rsc->cache_pll_trim_codes[2], 0x00);
upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_THREE + offset) << 18);
upper_addr |= (upper_8_bit(PLL_DSM_DIVIDER + offset) << 19);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL10,
(PLL_FEEDBACK_DIVIDER + offset),
(PLL_CALIBRATION_SETTINGS + offset), 0x4E, 0x40);
upper_addr |= (upper_8_bit(PLL_FEEDBACK_DIVIDER + offset) << 20);
upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 21);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL11,
(PLL_BAND_SEL_CAL_SETTINGS_THREE + offset),
(PLL_FREQ_DETECT_SETTINGS_ONE + offset), 0xBA, 0x0C);
upper_addr |= (upper_8_bit(PLL_BAND_SEL_CAL_SETTINGS_THREE + offset)
<< 20);
<< 22);
upper_addr |= (upper_8_bit(PLL_FREQ_DETECT_SETTINGS_ONE + offset)
<< 21);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL11,
(PLL_OUTDIV + offset),
(PLL_CORE_OVERRIDE + offset), 0, 0);
upper_addr |= (upper_8_bit(PLL_OUTDIV + offset) << 22);
upper_addr |= (upper_8_bit(PLL_CORE_OVERRIDE + offset) << 23);
<< 23);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL12,
(PLL_OUTDIV + offset),
(PLL_CORE_OVERRIDE + offset), 0, 0);
upper_addr |= (upper_8_bit(PLL_OUTDIV + offset) << 24);
upper_addr |= (upper_8_bit(PLL_CORE_OVERRIDE + offset) << 25);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL13,
(PLL_PLL_DIGITAL_TIMERS_TWO + offset),
(PLL_PLL_PROP_GAIN_RATE_1 + offset),
0x08, reg->pll_prop_gain_rate);
upper_addr |= (upper_8_bit(PLL_PLL_DIGITAL_TIMERS_TWO + offset) << 24);
upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 25);
upper_addr |= (upper_8_bit(PLL_PLL_DIGITAL_TIMERS_TWO + offset) << 26);
upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 27);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL13,
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL14,
(PLL_PLL_BAND_SEL_RATE_1 + offset),
(PLL_PLL_INT_GAIN_IFILT_BAND_1 + offset),
0xC0, 0x82);
upper_addr |= (upper_8_bit(PLL_PLL_BAND_SEL_RATE_1 + offset) << 26);
upper_addr |= (upper_8_bit(PLL_PLL_BAND_SEL_RATE_1 + offset) << 28);
upper_addr |= (upper_8_bit(PLL_PLL_INT_GAIN_IFILT_BAND_1 + offset)
<< 27);
<< 29);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL14,
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL15,
(PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 + offset),
(PLL_PLL_LOCK_OVERRIDE + offset),
0x4c, 0x80);
upper_addr |= (upper_8_bit(PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 + offset)
<< 28);
upper_addr |= (upper_8_bit(PLL_PLL_LOCK_OVERRIDE + offset) << 29);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL15,
(PLL_PFILT + offset),
(PLL_IFILT + offset),
0x2f, 0x3f);
upper_addr |= (upper_8_bit(PLL_PFILT + offset) << 30);
upper_addr |= (upper_8_bit(PLL_IFILT + offset) << 31);
<< 30);
upper_addr |= (upper_8_bit(PLL_PLL_LOCK_OVERRIDE + offset) << 31);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL16,
(PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset),
(PLL_FREQ_TUNE_ACCUM_INIT_MID + offset),
rsc->cache_pll_trim_codes[0], rsc->cache_pll_trim_codes[1] );
upper_addr2 |= (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset) << 0);
upper_addr2 |= (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MID + offset) << 1);
(PLL_PFILT + offset),
(PLL_IFILT + offset),
0x29, 0x3f);
upper_addr2 |= (upper_8_bit(PLL_PFILT + offset) << 0);
upper_addr2 |= (upper_8_bit(PLL_IFILT + offset) << 1);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL17,
(PLL_PLL_BAND_SEL_RATE_1 + offset),
( PLL_PLL_BAND_SEL_RATE_1+ offset),
rsc->cache_pll_trim_codes[2], rsc->cache_pll_trim_codes[2]);
upper_addr2 |= (upper_8_bit(PLL_PLL_BAND_SEL_RATE_1 + offset) << 0);
upper_addr2 |= (upper_8_bit(PLL_PLL_BAND_SEL_RATE_1 + offset) << 1);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL18,
(PLL_SYSTEM_MUXES + offset),
(PLL_CALIBRATION_SETTINGS + offset),
0xc0, 0x40);
0xe0, 0x44);
upper_addr2 |= (upper_8_bit(PLL_BAND_SEL_CAL + offset) << 2);
upper_addr2 |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 3);
data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL27,
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL18,
PHY_CMN_CTRL_2, PHY_CMN_CLK_CFG0, 0x40, data);
if (rsc->slave)
MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base,
DSI_DYNAMIC_REFRESH_PLL_CTRL10,
PHY_CMN_CLK_CFG0, PHY_CMN_CTRL_0,
data, 0x7f);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL27,
PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL28,
PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);
MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL29,
PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01);