Merge remote-tracking branch 'quic/dev/msm-4.14-display' into msm-4.14

* quic/dev/msm-4.14-display:
  drm/msm/dp: clear HDR data for each session
  drm/msm/sde: Send blank notification only when CRTC active changed
  drm/msm/sde: allow PP buffer overflow irq disable after encoder disable
  drm/msm: export symbols for drm client registration API
  drm/msm/dp: complete link training before hot plug notification
  drm/msm/sde: prevent null pointer access on disabled encoder
  drm/msm/sde: manage sde pm_qos vote through atomic counter
  drm/msm/sde: fix out of bounds memory access in sde kms
  drm/msm: avoid memory allocation when sgt is imported

Change-Id: I5d2dd5bc966875d05e717719ac62633b8106a033
Signed-off-by: Namratha Siddappa <namratha@codeaurora.org>
This commit is contained in:
Namratha Siddappa 2018-08-24 18:56:44 -07:00
commit 1d42f5a0f0
18 changed files with 434 additions and 512 deletions

View File

@ -607,7 +607,6 @@
<&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
<&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
<&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
<&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
<&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
<&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
<&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>,
@ -616,9 +615,8 @@
<&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
<&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>;
clock-names = "core_aux_clk", "core_usb_ref_clk_src",
"core_usb_ref_clk",
"core_usb_pipe_clk", "ctrl_link_clk",
"ctrl_link_iface_clk", "ctrl_pixel_clk",
"core_usb_ref_clk", "core_usb_pipe_clk",
"link_clk", "link_iface_clk",
"crypto_clk", "pixel_clk_rcg", "pixel_parent",
"pixel1_clk_rcg", "pixel1_parent",
"strm0_pixel_clk", "strm1_pixel_clk";

View File

@ -41,6 +41,7 @@ struct dp_aux_private {
bool read;
bool no_send_addr;
bool no_send_stop;
bool enabled;
u32 offset;
u32 segment;
@ -623,12 +624,16 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
if (aux->enabled)
return;
dp_aux_reset_phy_config_indices(aux_cfg);
aux->catalog->setup(aux->catalog, aux_cfg);
aux->catalog->reset(aux->catalog);
aux->catalog->enable(aux->catalog, true);
atomic_set(&aux->aborted, 0);
aux->retry_cnt = 0;
aux->enabled = true;
}
static void dp_aux_deinit(struct dp_aux *dp_aux)
@ -642,8 +647,12 @@ static void dp_aux_deinit(struct dp_aux *dp_aux)
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
if (!aux->enabled)
return;
atomic_set(&aux->aborted, 1);
aux->catalog->enable(aux->catalog, false);
aux->enabled = false;
}
static int dp_aux_register(struct dp_aux *dp_aux)

View File

@ -122,19 +122,12 @@ static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
ctrl->catalog->state_ctrl(ctrl->catalog, state);
}
static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl, enum dp_stream_id strm)
static void dp_ctrl_push_idle(struct dp_ctrl_private *ctrl,
enum dp_stream_id strm)
{
int const idle_pattern_completion_timeout_ms = 3 * HZ / 100;
struct dp_ctrl_private *ctrl;
int const idle_pattern_completion_timeout_ms = HZ / 10;
u32 state = 0x0;
if (!dp_ctrl) {
pr_err("Invalid input data\n");
return;
}
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
if (!ctrl->power_on) {
pr_err("CTRL off, return\n");
return;
@ -158,7 +151,7 @@ trigger_idle:
if (!wait_for_completion_timeout(&ctrl->idle_comp,
idle_pattern_completion_timeout_ms))
pr_warn("PUSH_IDLE time out\n");
pr_warn("time out\n");
pr_debug("mainlink off done\n");
}
@ -301,7 +294,12 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
tries = 0;
old_v_level = ctrl->link->phy_params.v_level;
while (!atomic_read(&ctrl->aborted)) {
while (1) {
if (atomic_read(&ctrl->aborted)) {
ret = -EINVAL;
break;
}
drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
ret = dp_ctrl_read_link_status(ctrl, link_status);
@ -417,6 +415,11 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
}
do {
if (atomic_read(&ctrl->aborted)) {
ret = -EINVAL;
break;
}
drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
ret = dp_ctrl_read_link_status(ctrl, link_status);
@ -439,7 +442,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
ret = -EINVAL;
break;
}
} while (!atomic_read(&ctrl->aborted));
} while (1);
end:
ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED;
@ -467,8 +470,10 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
link_info.capabilities = ctrl->panel->link_info.capabilities;
ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
if (ret)
if (ret) {
pr_err_ratelimited("link_configure failed, rc=%d\n", ret);
goto end;
}
ret = drm_dp_dpcd_write(ctrl->aux->drm_aux,
DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1);
@ -504,7 +509,7 @@ end:
return ret;
}
static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)
static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
{
int ret = 0;
@ -513,9 +518,6 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
goto end;
if (!train)
goto end;
/*
* As part of previous calls, DP controller state might have
* transitioned to PUSH_IDLE. In order to start transmitting a link
@ -548,14 +550,17 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
pr_err("%s clock could not be set with rate %d\n", name, rate);
}
static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
static int dp_ctrl_enable_link_clock(struct dp_ctrl_private *ctrl)
{
int ret = 0;
u32 rate = drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code);
enum dp_pm_type type = DP_LINK_PM;
dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk", DP_CTRL_PM,
drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code));
pr_debug("rate=%d\n", rate);
ret = ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, true);
dp_ctrl_set_clock_rate(ctrl, "link_clk", type, rate);
ret = ctrl->power->clk_enable(ctrl->power, type, true);
if (ret) {
pr_err("Unabled to start link clocks\n");
ret = -EINVAL;
@ -564,9 +569,46 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
return ret;
}
static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl)
static void dp_ctrl_disable_link_clock(struct dp_ctrl_private *ctrl)
{
return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false);
ctrl->power->clk_enable(ctrl->power, DP_LINK_PM, false);
}
static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl)
{
int rc = -EINVAL;
u32 link_train_max_retries = 100;
struct dp_catalog_ctrl *catalog;
struct dp_link_params *link_params;
catalog = ctrl->catalog;
link_params = &ctrl->link->link_params;
catalog->hpd_config(catalog, true);
catalog->phy_lane_cfg(catalog, ctrl->orientation,
link_params->lane_count);
while (--link_train_max_retries || !atomic_read(&ctrl->aborted)) {
pr_debug("bw_code=%d, lane_count=%d\n",
link_params->bw_code, link_params->lane_count);
dp_ctrl_enable_link_clock(ctrl);
dp_ctrl_configure_source_link_params(ctrl, true);
rc = dp_ctrl_setup_main_link(ctrl);
if (!rc)
break;
dp_ctrl_link_rate_down_shift(ctrl);
dp_ctrl_configure_source_link_params(ctrl, false);
dp_ctrl_disable_link_clock(ctrl);
/* hw recommended delays before retrying link training */
msleep(20);
}
return rc;
}
static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl,
@ -645,6 +687,7 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
catalog->phy_reset(ctrl->catalog);
}
catalog->enable_irq(ctrl->catalog, true);
atomic_set(&ctrl->aborted, 0);
return 0;
}
@ -686,51 +729,24 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)
if (!ctrl->power_on || atomic_read(&ctrl->aborted)) {
pr_err("CTRL off, return\n");
return -EINVAL;
ret = -EINVAL;
goto end;
}
ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;
ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;
ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
do {
if (ret == -EAGAIN) {
/* try with lower link rate */
dp_ctrl_link_rate_down_shift(ctrl);
dp_ctrl_configure_source_link_params(ctrl, false);
}
ctrl->catalog->phy_lane_cfg(ctrl->catalog,
ctrl->orientation, ctrl->link->link_params.lane_count);
/*
* Disable and re-enable the mainlink clock since the
* link clock might have been adjusted as part of the
* link maintenance.
*/
dp_ctrl_disable_mainlink_clocks(ctrl);
ret = dp_ctrl_enable_mainlink_clocks(ctrl);
if (ret)
continue;
dp_ctrl_configure_source_link_params(ctrl, true);
reinit_completion(&ctrl->idle_comp);
ret = dp_ctrl_setup_main_link(ctrl, true);
} while (ret == -EAGAIN);
ctrl->catalog->reset(ctrl->catalog);
dp_ctrl_disable_link_clock(ctrl);
ret = dp_ctrl_link_setup(ctrl);
ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED;
if (ret)
ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED;
else
ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED;
end:
return ret;
}
@ -753,13 +769,13 @@ static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl)
pr_debug("start\n");
ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl, DP_STREAM_0);
/*
* The global reset will need DP link ralated clocks to be
* running. Add the global reset just before disabling the
* link clocks and core clocks.
*/
ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
ctrl->catalog->reset(ctrl->catalog);
ctrl->dp_ctrl.stream_pre_off(&ctrl->dp_ctrl, ctrl->panel);
ctrl->dp_ctrl.stream_off(&ctrl->dp_ctrl, ctrl->panel);
ctrl->dp_ctrl.off(&ctrl->dp_ctrl);
@ -826,19 +842,6 @@ static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
dp_link_get_phy_test_pattern(pattern_requested));
}
static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl)
{
struct dp_ctrl_private *ctrl;
if (!dp_ctrl) {
pr_err("invalid params\n");
return;
}
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
ctrl->catalog->reset(ctrl->catalog);
}
static void dp_ctrl_send_video(struct dp_ctrl_private *ctrl)
{
ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO);
@ -1052,12 +1055,16 @@ static void dp_ctrl_mst_stream_pre_off(struct dp_ctrl *dp_ctrl,
static void dp_ctrl_stream_pre_off(struct dp_ctrl *dp_ctrl,
struct dp_panel *panel)
{
struct dp_ctrl_private *ctrl;
if (!dp_ctrl || !panel) {
pr_err("invalid input\n");
return;
}
dp_ctrl_push_idle(dp_ctrl, panel->stream_id);
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
dp_ctrl_push_idle(ctrl, panel->stream_id);
dp_ctrl_mst_stream_pre_off(dp_ctrl, panel);
}
@ -1081,7 +1088,6 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode)
int rc = 0;
struct dp_ctrl_private *ctrl;
u32 rate = 0;
u32 link_train_max_retries = 100;
if (!dp_ctrl) {
rc = -EINVAL;
@ -1090,13 +1096,9 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode)
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
atomic_set(&ctrl->aborted, 0);
ctrl->mst_mode = mst_mode;
rate = ctrl->panel->link_info.rate;
ctrl->catalog->hpd_config(ctrl->catalog, true);
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
pr_debug("using phy test link parameters\n");
} else {
@ -1110,38 +1112,11 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode)
ctrl->link->link_params.bw_code,
ctrl->link->link_params.lane_count);
ctrl->catalog->phy_lane_cfg(ctrl->catalog,
ctrl->orientation, ctrl->link->link_params.lane_count);
rc = dp_ctrl_enable_mainlink_clocks(ctrl);
rc = dp_ctrl_link_setup(ctrl);
if (rc)
goto end;
reinit_completion(&ctrl->idle_comp);
dp_ctrl_configure_source_link_params(ctrl, true);
while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
rc = dp_ctrl_setup_main_link(ctrl, true);
if (!rc)
break;
/* try with lower link rate */
dp_ctrl_link_rate_down_shift(ctrl);
dp_ctrl_configure_source_link_params(ctrl, false);
dp_ctrl_disable_mainlink_clocks(ctrl);
/* hw recommended delay before re-enabling clocks */
msleep(20);
dp_ctrl_enable_mainlink_clocks(ctrl);
}
ctrl->power_on = true;
pr_debug("End-\n");
end:
return rc;
}
@ -1161,7 +1136,7 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
/* Make sure DP is disabled before clk disable */
wmb();
dp_ctrl_disable_mainlink_clocks(ctrl);
dp_ctrl_disable_link_clock(ctrl);
ctrl->mst_mode = false;
ctrl->power_on = false;
@ -1249,10 +1224,8 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
dp_ctrl->deinit = dp_ctrl_host_deinit;
dp_ctrl->on = dp_ctrl_on;
dp_ctrl->off = dp_ctrl_off;
dp_ctrl->push_idle = dp_ctrl_push_idle;
dp_ctrl->abort = dp_ctrl_abort;
dp_ctrl->isr = dp_ctrl_isr;
dp_ctrl->reset = dp_ctrl_reset;
dp_ctrl->link_maintenance = dp_ctrl_link_maintenance;
dp_ctrl->process_phy_test_request = dp_ctrl_process_phy_test_request;
dp_ctrl->stream_on = dp_ctrl_stream_on;

View File

@ -27,8 +27,6 @@ struct dp_ctrl {
void (*deinit)(struct dp_ctrl *dp_ctrl);
int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode);
void (*off)(struct dp_ctrl *dp_ctrl);
void (*reset)(struct dp_ctrl *dp_ctrl);
void (*push_idle)(struct dp_ctrl *dp_ctrl, enum dp_stream_id strm);
void (*abort)(struct dp_ctrl *dp_ctrl);
void (*isr)(struct dp_ctrl *dp_ctrl);
bool (*handle_sink_request)(struct dp_ctrl *dp_ctrl);

View File

@ -35,8 +35,6 @@ struct dp_debug_private {
u8 *dpcd;
u32 dpcd_size;
int vdo;
char exe_mode[SZ_32];
char reg_dump[SZ_32];
@ -47,7 +45,6 @@ struct dp_debug_private {
struct dp_catalog *catalog;
struct drm_connector **connector;
struct device *dev;
struct work_struct sim_work;
struct dp_debug dp_debug;
struct dp_parser *parser;
};
@ -1068,9 +1065,7 @@ static ssize_t dp_debug_write_attention(struct file *file,
if (kstrtoint(buf, 10, &vdo) != 0)
goto end;
debug->vdo = vdo;
schedule_work(&debug->sim_work);
debug->hpd->simulate_attention(debug->hpd, vdo);
end:
return len;
}
@ -1399,14 +1394,6 @@ error:
return rc;
}
static void dp_debug_sim_work(struct work_struct *work)
{
struct dp_debug_private *debug =
container_of(work, typeof(*debug), sim_work);
debug->hpd->simulate_attention(debug->hpd, debug->vdo);
}
u8 *dp_debug_get_edid(struct dp_debug *dp_debug)
{
struct dp_debug_private *debug;
@ -1441,8 +1428,6 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
goto error;
}
INIT_WORK(&debug->sim_work, dp_debug_sim_work);
debug->dp_debug.debug_en = false;
debug->hpd = hpd;
debug->link = link;

View File

@ -67,6 +67,7 @@ struct dp_display_private {
/* state variables */
bool core_initialized;
bool power_on;
bool is_connected;
atomic_t aborted;
@ -74,7 +75,6 @@ struct dp_display_private {
struct device_node *aux_switch_node;
struct dentry *root;
struct completion notification_comp;
struct completion disconnect_comp;
struct dp_hpd *hpd;
struct dp_parser *parser;
@ -200,7 +200,7 @@ static void dp_display_notify_hdcp_status_cb(void *ptr,
dp->link->hdcp_status.hdcp_state = state;
if (dp->dp_display.is_connected)
if (dp->is_connected)
queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4);
}
@ -475,23 +475,27 @@ static void dp_display_post_open(struct dp_display *dp_display)
dp_display->post_open = NULL;
}
static int dp_display_send_hpd_notification(struct dp_display_private *dp,
bool hpd)
static int dp_display_send_hpd_notification(struct dp_display_private *dp)
{
u32 timeout_sec;
int ret = 0;
bool hpd = dp->is_connected;
dp->dp_display.is_connected = hpd;
if (dp_display_framework_ready(dp))
if (dp_display_framework_ready(dp))
timeout_sec = 5;
else
timeout_sec = 10;
dp->aux->state |= DP_STATE_NOTIFICATION_SENT;
if (!dp->mst.mst_active)
if (!dp->mst.mst_active) {
if (dp->dp_display.is_sst_connected == hpd) {
pr_debug("SKIPPED:hpd:%d\n", hpd);
goto skip_wait;
}
dp->dp_display.is_sst_connected = hpd;
}
reinit_completion(&dp->notification_comp);
dp_display_send_hpd_event(dp);
@ -504,11 +508,9 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
ret = -EINVAL;
}
skip_wait:
dp->aux->state &= ~DP_STATE_NOTIFICATION_SENT;
return ret;
skip_wait:
return 0;
}
static void dp_display_process_mst_hpd_high(struct dp_display_private *dp)
@ -552,10 +554,56 @@ static void dp_display_host_init(struct dp_display_private *dp)
dp->power->init(dp->power, flip);
dp->ctrl->init(dp->ctrl, flip, reset);
dp->aux->init(dp->aux, dp->parser->aux_cfg);
enable_irq(dp->irq);
dp->core_initialized = true;
}
static int dp_display_update_pclk(struct dp_display_private *dp)
{
int rc = 0;
u32 rate, max_pclk_khz;
u32 const enc_factx10 = 8;
u32 const default_bpp = 30;
if (dp->debug->max_pclk_khz) {
dp->dp_display.max_pclk_khz = dp->debug->max_pclk_khz;
goto end;
}
rate = drm_dp_bw_code_to_link_rate(dp->link->link_params.bw_code);
rate /= default_bpp;
max_pclk_khz = dp->link->link_params.lane_count * rate * enc_factx10;
dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz,
max_pclk_khz);
pr_debug("dp max_pclk_khz = %d\n", dp->dp_display.max_pclk_khz);
end:
return rc;
}
static void dp_display_host_deinit(struct dp_display_private *dp)
{
if (!dp->core_initialized) {
pr_debug("DP core already off\n");
return;
}
if (dp->active_stream_cnt) {
pr_debug("active stream present\n");
return;
}
dp->aux->deinit(dp->aux);
dp->ctrl->deinit(dp->ctrl);
dp->power->deinit(dp->power);
disable_irq(dp->irq);
dp->core_initialized = false;
dp->aux->state = 0;
}
static int dp_display_process_hpd_high(struct dp_display_private *dp)
{
int rc = 0;
@ -566,9 +614,9 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
goto end;
}
dp_display_host_init(dp);
dp->is_connected = true;
dp->aux->init(dp->aux, dp->parser->aux_cfg);
dp_display_host_init(dp);
if (dp->debug->psm_enabled) {
dp->link->psm_config(dp->link, &dp->panel->link_info, false);
@ -576,51 +624,39 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
}
if (!dp->dp_display.base_connector)
return 0;
goto end;
rc = dp->panel->read_sink_caps(dp->panel,
dp->dp_display.base_connector, dp->hpd->multi_func);
if (rc) {
/*
* ETIMEDOUT --> cable may have been removed
* ENOTCONN --> no downstream device connected
*/
if (rc == -ETIMEDOUT || rc == -ENOTCONN)
goto end;
else
goto notify;
}
/*
* ETIMEDOUT --> cable may have been removed
* ENOTCONN --> no downstream device connected
*/
if (rc == -ETIMEDOUT || rc == -ENOTCONN)
goto end;
dp->link->process_request(dp->link);
dp->panel->handle_sink_request(dp->panel);
if (dp->debug->max_pclk_khz)
dp->dp_display.max_pclk_khz = dp->debug->max_pclk_khz;
else
dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz;
pr_debug("dp max_pclk_khz = %d\n", dp->dp_display.max_pclk_khz);
dp_display_process_mst_hpd_high(dp);
notify:
dp_display_send_hpd_notification(dp, true);
end:
return rc;
}
static void dp_display_host_deinit(struct dp_display_private *dp)
{
if (!dp->core_initialized) {
pr_debug("DP core already off\n");
return;
mutex_lock(&dp->session_lock);
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active);
if (rc) {
mutex_unlock(&dp->session_lock);
goto end;
}
dp->ctrl->deinit(dp->ctrl);
dp->power->deinit(dp->power);
disable_irq(dp->irq);
dp->core_initialized = false;
dp->aux->state = 0;
rc = dp_display_update_pclk(dp);
if (rc) {
mutex_unlock(&dp->session_lock);
goto end;
}
mutex_unlock(&dp->session_lock);
dp_display_send_hpd_notification(dp);
end:
return rc;
}
static void dp_display_process_mst_hpd_low(struct dp_display_private *dp)
@ -648,11 +684,7 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp)
mutex_lock(&dp->session_lock);
if (!dp->dp_display.is_connected) {
pr_debug("HPD already off\n");
mutex_unlock(&dp->session_lock);
return 0;
}
dp->is_connected = false;
if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off)
dp->hdcp.ops->off(dp->hdcp.data);
@ -673,7 +705,7 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp)
dp_display_process_mst_hpd_low(dp);
rc = dp_display_send_hpd_notification(dp, false);
rc = dp_display_send_hpd_notification(dp);
dp->panel->video_test = false;
@ -699,7 +731,7 @@ static int dp_display_usbpd_configure_cb(struct device *dev)
}
/* check for hpd high and framework ready */
if (dp->hpd->hpd_high && dp_display_framework_ready(dp))
if (dp->hpd->hpd_high && dp_display_framework_ready(dp))
queue_delayed_work(dp->wq, &dp->connect_work, 0);
end:
return rc;
@ -707,6 +739,9 @@ end:
static void dp_display_clean(struct dp_display_private *dp)
{
int idx;
struct dp_panel *dp_panel;
if (dp_display_is_hdcp_enabled(dp)) {
dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
@ -715,10 +750,16 @@ static void dp_display_clean(struct dp_display_private *dp)
dp->hdcp.ops->off(dp->hdcp.data);
}
dp->ctrl->push_idle(dp->ctrl, DP_STREAM_0);
dp->ctrl->off(dp->ctrl);
dp->panel->deinit(dp->panel);
dp->aux->deinit(dp->aux);
for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
if (!dp->active_panels[idx])
continue;
dp_panel = dp->active_panels[idx];
dp->ctrl->stream_pre_off(dp->ctrl, dp_panel);
dp->ctrl->stream_off(dp->ctrl, dp_panel);
}
dp->power_on = false;
}
@ -737,17 +778,8 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp)
if (rc && dp->power_on)
dp_display_clean(dp);
/*
* De-initialize the display core only if the display controller has
* been turned off either through the DRM bridge disable call or
* through the error handling code. This ensures that the power
* resource vote is still present in cases when the bridge disable is
* delayed.
*/
if (!dp->power_on && !dp->hpd->alt_mode_cfg_done)
dp_display_host_deinit(dp);
dp_display_host_deinit(dp);
complete_all(&dp->disconnect_comp);
mutex_unlock(&dp->session_lock);
return rc;
@ -791,11 +823,11 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
cancel_work(&dp->attention_work);
flush_workqueue(dp->wq);
dp_display_handle_disconnect(dp);
if (!dp->debug->sim_mode && !dp->parser->no_aux_switch)
dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE);
dp_display_handle_disconnect(dp);
/* Reset abort value to allow future connections */
atomic_set(&dp->aborted, 0);
@ -857,25 +889,16 @@ static void dp_display_attention_work(struct work_struct *work)
{
struct dp_display_private *dp = container_of(work,
struct dp_display_private, attention_work);
bool is_sink_cnt_zero;
if (!dp->power_on)
goto mst_attention;
if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
is_sink_cnt_zero = dp_display_is_sink_count_zero(dp);
if (dp->mst.mst_active && !is_sink_cnt_zero)
goto mst_attention;
dp_display_handle_disconnect(dp);
if (is_sink_cnt_zero) {
pr_debug("sink count is zero, nothing to do\n");
goto mst_attention;
if (dp_display_is_sink_count_zero(dp)) {
dp_display_handle_disconnect(dp);
} else {
if (!dp->mst.mst_active)
queue_delayed_work(dp->wq,
&dp->connect_work, 0);
}
queue_delayed_work(dp->wq, &dp->connect_work, 0);
goto mst_attention;
}
@ -883,8 +906,7 @@ static void dp_display_attention_work(struct work_struct *work)
dp_display_handle_disconnect(dp);
dp->panel->video_test = true;
dp_display_send_hpd_notification(dp, true);
dp->link->send_test_response(dp->link);
queue_delayed_work(dp->wq, &dp->connect_work, 0);
goto mst_attention;
}
@ -924,28 +946,11 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
return -ENODEV;
}
/* check if framework is ready */
if (!dp_display_framework_ready(dp)) {
pr_err("framework not ready\n");
return -ENODEV;
}
DP_MST_DEBUG("mst: hpd_irq:%d, hpd_high:%d, power_on:%d\n",
dp->hpd->hpd_irq, dp->hpd->hpd_high,
dp->power_on);
if (dp->hpd->hpd_irq && dp->hpd->hpd_high &&
dp->power_on) {
dp->link->process_request(dp->link);
queue_work(dp->wq, &dp->attention_work);
} else if (dp->hpd->hpd_high && dp->hpd->hpd_irq) {
queue_delayed_work(dp->wq, &dp->connect_work, 0);
queue_work(dp->wq, &dp->attention_work);
} else if (dp->hpd->hpd_high) {
queue_delayed_work(dp->wq, &dp->connect_work, 0);
} else if (dp->hpd->hpd_irq) {
queue_work(dp->wq, &dp->attention_work);
} else {
if (!dp->hpd->hpd_high) {
/* cancel any pending request */
atomic_set(&dp->aborted, 1);
dp->ctrl->abort(dp->ctrl);
@ -958,6 +963,11 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
dp_display_handle_disconnect(dp);
atomic_set(&dp->aborted, 0);
} else if (dp->hpd->hpd_irq && dp->core_initialized) {
dp->link->process_request(dp->link);
queue_work(dp->wq, &dp->attention_work);
} else {
queue_delayed_work(dp->wq, &dp->connect_work, 0);
}
return 0;
@ -965,35 +975,10 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
static void dp_display_connect_work(struct work_struct *work)
{
int rc = 0;
struct delayed_work *dw = to_delayed_work(work);
struct dp_display_private *dp = container_of(dw,
struct dp_display_private, connect_work);
u32 const disconnect_timeout_sec = 20;
if (dp->dp_display.is_connected && dp_display_framework_ready(dp)) {
pr_debug("HPD already on\n");
return;
}
if (atomic_read(&dp->aborted)) {
/*
* If we receive a connection event while processing a
* disconnect event from the previous session then we have to
* wait until that disconnect event completes or expires. We
* give the highest priority to handling disconnect events
* since they represent a state change triggered by a physical
* removal of the cable/plug.
*/
pr_warn("disconnect pending, waiting for %d sec\n",
disconnect_timeout_sec);
reinit_completion(&dp->disconnect_comp);
if (!wait_for_completion_timeout(&dp->disconnect_comp,
HZ * disconnect_timeout_sec)) {
pr_warn("disconnect completion timeout\n");
return;
}
}
if (atomic_read(&dp->aborted)) {
pr_warn("HPD off requested\n");
@ -1005,7 +990,10 @@ static void dp_display_connect_work(struct work_struct *work)
return;
}
dp_display_process_hpd_high(dp);
rc = dp_display_process_hpd_high(dp);
if (!rc && dp->panel->video_test)
dp->link->send_test_response(dp->link);
}
static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
@ -1251,6 +1239,13 @@ static int dp_display_set_mode(struct dp_display *dp_display, void *panel,
return 0;
}
static bool dp_display_is_ready(struct dp_display_private *dp)
{
return dp->hpd->hpd_high && dp->is_connected &&
!dp_display_is_sink_count_zero(dp) &&
dp->hpd->alt_mode_cfg_done;
}
static int dp_display_prepare(struct dp_display *dp_display, void *panel)
{
struct dp_display_private *dp;
@ -1277,7 +1272,10 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel)
if (dp->power_on)
goto end;
dp->aux->init(dp->aux, dp->parser->aux_cfg);
if (dp_display_is_ready(dp))
dp_display_host_init(dp);
else
goto end;
if (dp->debug->psm_enabled) {
dp->link->psm_config(dp->link, &dp->panel->link_info, false);
@ -1367,29 +1365,23 @@ static int dp_display_enable(struct dp_display *dp_display, void *panel)
mutex_lock(&dp->session_lock);
if (dp->power_on) {
pr_debug("Link already setup, perform setup stream\n");
goto stream_setup;
}
if (atomic_read(&dp->aborted)) {
pr_err("aborted\n");
goto end;
}
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active);
if (rc)
if (!dp_display_is_ready(dp) || !dp->core_initialized) {
pr_err("display not ready\n");
goto end;
}
dp->power_on = true;
stream_setup:
rc = dp_display_stream_enable(dp, panel);
if (rc && (dp->active_stream_cnt == 0)) {
dp->ctrl->off(dp->ctrl);
dp->power_on = false;
goto end;
}
dp->power_on = true;
end:
mutex_unlock(&dp->session_lock);
return rc;
@ -1430,6 +1422,11 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel)
goto end;
}
if (!dp_display_is_ready(dp) || !dp->core_initialized) {
pr_err("display not ready\n");
goto end;
}
dp_display_stream_post_enable(dp, dp_panel);
edid = dp_panel->edid_ctrl->edid;
@ -1502,8 +1499,7 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
rc = dp_display_stream_pre_disable(dp, dp_panel);
if (dp->hpd->hpd_high && !dp_display_is_sink_count_zero(dp) &&
dp->hpd->alt_mode_cfg_done && !dp->mst.mst_active) {
if (dp_display_is_ready(dp) && !dp->mst.mst_active) {
dp->link->psm_config(dp->link, &dp->panel->link_info, true);
dp->debug->psm_enabled = true;
}
@ -1563,10 +1559,10 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel)
* any notification from driver. Initialize post_open callback to notify
* DP connection once framework restarts.
*/
if (dp->hpd->hpd_high && !dp_display_is_sink_count_zero(dp) &&
dp->hpd->alt_mode_cfg_done && !dp->mst.mst_active) {
if (dp_display_is_ready(dp) && !dp->mst.mst_active) {
dp_display->post_open = dp_display_post_open;
dp->dp_display.is_sst_connected = false;
dp_display_host_deinit(dp);
}
dp->power_on = false;
@ -1637,10 +1633,7 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel)
if (dp->active_stream_cnt)
goto end;
if (!dp->mst.mst_active) {
dp->aux->deinit(dp->aux);
dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
}
dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
complete_all(&dp->notification_comp);
@ -1650,46 +1643,70 @@ end:
return 0;
}
static int dp_display_validate_mode(struct dp_display *dp, void *panel,
u32 mode_pclk_khz)
static enum drm_mode_status dp_display_validate_mode(
struct dp_display *dp_display,
void *panel, struct drm_display_mode *mode)
{
const u32 num_components = 3, default_bpp = 24;
struct dp_display_private *dp_display;
struct dp_display_private *dp;
struct drm_dp_link *link_info;
u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
struct dp_panel *dp_panel;
struct dp_debug *debug;
enum drm_mode_status mode_status = MODE_BAD;
if (!dp || !mode_pclk_khz || !panel) {
if (!dp_display || !mode || !panel) {
pr_err("invalid params\n");
return -EINVAL;
return mode_status;
}
dp = container_of(dp_display, struct dp_display_private, dp_display);
mutex_lock(&dp->session_lock);
dp_panel = panel;
if (!dp_panel->connector) {
pr_err("invalid connector\n");
return -EINVAL;
goto end;
}
dp_display = container_of(dp, struct dp_display_private, dp_display);
link_info = &dp_display->panel->link_info;
link_info = &dp->panel->link_info;
debug = dp->debug;
if (!debug)
goto end;
mode_bpp = dp_panel->connector->display_info.bpc * num_components;
if (!mode_bpp)
mode_bpp = default_bpp;
mode_bpp = dp_panel->get_mode_bpp(dp_panel, mode_bpp, mode_pclk_khz);
mode_bpp = dp_panel->get_mode_bpp(dp_panel, mode_bpp, mode->clock);
mode_rate_khz = mode_pclk_khz * mode_bpp;
mode_rate_khz = mode->clock * mode_bpp;
supported_rate_khz = link_info->num_lanes * link_info->rate * 8;
if (mode_rate_khz > supported_rate_khz) {
DP_MST_DEBUG("pclk:%d, supported_rate:%d\n",
mode_pclk_khz, supported_rate_khz);
return MODE_BAD;
mode->clock, supported_rate_khz);
goto end;
}
return MODE_OK;
if (mode->clock > dp_display->max_pclk_khz) {
DP_MST_DEBUG("clk:%d, max:%d\n", mode->clock,
dp_display->max_pclk_khz);
goto end;
}
if (debug->debug_en && (mode->hdisplay != debug->hdisplay ||
mode->vdisplay != debug->vdisplay ||
mode->vrefresh != debug->vrefresh ||
mode->picture_aspect_ratio != debug->aspect_ratio))
goto end;
mode_status = MODE_OK;
end:
mutex_unlock(&dp->session_lock);
return mode_status;
}
static int dp_display_get_modes(struct dp_display *dp, void *panel,
@ -2034,7 +2051,6 @@ static int dp_display_probe(struct platform_device *pdev)
}
init_completion(&dp->notification_comp);
init_completion(&dp->disconnect_comp);
dp->pdev = pdev;
dp->name = "drm_dp";

View File

@ -48,7 +48,6 @@ struct dp_display {
struct dp_bridge *bridge;
struct drm_connector *base_connector;
void *base_dp_panel;
bool is_connected;
bool is_sst_connected;
u32 max_pclk_khz;
void *dp_mst_prv_info;
@ -61,8 +60,8 @@ struct dp_display {
int (*set_mode)(struct dp_display *dp_display, void *panel,
struct dp_display_mode *mode);
int (*validate_mode)(struct dp_display *dp_display, void *panel,
u32 mode_pclk_khz);
enum drm_mode_status (*validate_mode)(struct dp_display *dp_display,
void *panel, struct drm_display_mode *mode);
int (*get_modes)(struct dp_display *dp_display, void *panel,
struct dp_display_mode *dp_mode);
int (*prepare)(struct dp_display *dp_display, void *panel);

View File

@ -568,11 +568,9 @@ void dp_drm_bridge_deinit(void *data)
}
enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode,
void *display)
struct drm_display_mode *mode, void *display)
{
struct dp_display *dp_disp;
struct dp_debug *debug;
struct sde_connector *sde_conn;
if (!mode || !display || !connector) {
@ -587,22 +585,7 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
}
dp_disp = display;
debug = dp_disp->get_debug(dp_disp);
mode->vrefresh = drm_mode_vrefresh(mode);
if (mode->clock > dp_disp->max_pclk_khz) {
DP_MST_DEBUG("clk:%d, max:%d\n", mode->clock,
dp_disp->max_pclk_khz);
return MODE_BAD;
}
if (debug->debug_en && (mode->hdisplay != debug->hdisplay ||
mode->vdisplay != debug->vdisplay ||
mode->vrefresh != debug->vrefresh ||
mode->picture_aspect_ratio != debug->aspect_ratio))
return MODE_BAD;
return dp_disp->validate_mode(dp_disp, sde_conn->drv_panel,
mode->clock);
return dp_disp->validate_mode(dp_disp, sde_conn->drv_panel, mode);
}

View File

@ -1206,6 +1206,7 @@ static int dp_panel_set_stream_info(struct dp_panel *dp_panel,
static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
{
int rc = 0;
struct dp_panel_private *panel;
struct dp_panel_info *pinfo;
if (!dp_panel) {
@ -1214,27 +1215,22 @@ static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
goto end;
}
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
pinfo = &dp_panel->pinfo;
/*
* print resolution info as this is a result
* of user initiated action of cable connection
*/
pr_info("SET NEW RESOLUTION:\n");
pr_info("%dx%d@%dfps\n", pinfo->h_active,
pinfo->v_active, pinfo->refresh_rate);
pr_info("h_porches(back|front|width) = (%d|%d|%d)\n",
pinfo->h_back_porch,
pinfo->h_front_porch,
pinfo->h_sync_width);
pr_info("v_porches(back|front|width) = (%d|%d|%d)\n",
pinfo->v_back_porch,
pinfo->v_front_porch,
pinfo->v_sync_width);
pr_info("pixel clock (KHz)=(%d)\n", pinfo->pixel_clk_khz);
pr_info("bpp = %d\n", pinfo->bpp);
pr_info("active low (h|v)=(%d|%d)\n", pinfo->h_active_low,
pinfo->v_active_low);
pr_info("DP RESOLUTION: active(back|front|width|low)\n");
pr_info("%d(%d|%d|%d|%d)x%d(%d|%d|%d|%d)@%dfps %dbpp %dKhz %dLR %dLn\n",
pinfo->h_active, pinfo->h_back_porch, pinfo->h_front_porch,
pinfo->h_sync_width, pinfo->h_active_low,
pinfo->v_active, pinfo->v_back_porch, pinfo->v_front_porch,
pinfo->v_sync_width, pinfo->v_active_low,
pinfo->refresh_rate, pinfo->bpp, pinfo->pixel_clk_khz,
panel->link->link_params.bw_code,
panel->link->link_params.lane_count);
end:
return rc;
}
@ -1271,6 +1267,7 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel)
connector->hdr_max_luminance = 0;
connector->hdr_avg_luminance = 0;
connector->hdr_min_luminance = 0;
connector->hdr_supported = false;
memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));

View File

@ -455,18 +455,18 @@ static void dp_parser_put_gpio_data(struct device *dev,
static int dp_parser_init_clk_data(struct dp_parser *parser)
{
int num_clk = 0, i = 0, rc = 0;
int core_clk_count = 0, ctrl_clk_count = 0;
int core_clk_count = 0, link_clk_count = 0;
int strm0_clk_count = 0, strm1_clk_count = 0;
const char *core_clk = "core";
const char *ctrl_clk = "ctrl";
const char *strm0_clk = "strm0";
const char *strm1_clk = "strm1";
const char *link_clk = "link";
const char *clk_name;
struct device *dev = &parser->pdev->dev;
struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM];
struct dss_module_power *strm0_power = &parser->mp[DP_STREAM0_PM];
struct dss_module_power *strm1_power = &parser->mp[DP_STREAM1_PM];
struct dss_module_power *link_power = &parser->mp[DP_LINK_PM];
num_clk = of_property_count_strings(dev->of_node, "clock-names");
if (num_clk <= 0) {
@ -482,16 +482,14 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
if (dp_parser_check_prefix(core_clk, clk_name))
core_clk_count++;
if (dp_parser_check_prefix(ctrl_clk, clk_name)) {
if (strcmp(clk_name, "ctrl_pixel_clk"))
ctrl_clk_count++;
}
if (dp_parser_check_prefix(strm0_clk, clk_name))
strm0_clk_count++;
if (dp_parser_check_prefix(strm1_clk, clk_name))
strm1_clk_count++;
if (dp_parser_check_prefix(link_clk, clk_name))
link_clk_count++;
}
/* Initialize the CORE power module */
@ -510,23 +508,6 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
goto exit;
}
/* Initialize the CTRL power module */
if (ctrl_clk_count <= 0) {
pr_err("no ctrl clocks are defined\n");
rc = -EINVAL;
goto ctrl_clock_error;
}
ctrl_power->num_clk = ctrl_clk_count;
ctrl_power->clk_config = devm_kzalloc(dev,
sizeof(struct dss_clk) * ctrl_power->num_clk,
GFP_KERNEL);
if (!ctrl_power->clk_config) {
ctrl_power->num_clk = 0;
rc = -EINVAL;
goto ctrl_clock_error;
}
/* Initialize the STREAM0 power module */
if (strm0_clk_count <= 0) {
pr_debug("no strm0 clocks are defined\n");
@ -557,13 +538,30 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
}
}
/* Initialize the link power module */
if (link_clk_count <= 0) {
pr_err("no link clocks are defined\n");
rc = -EINVAL;
goto link_clock_error;
}
link_power->num_clk = link_clk_count;
link_power->clk_config = devm_kzalloc(dev,
sizeof(struct dss_clk) * link_power->num_clk,
GFP_KERNEL);
if (!link_power->clk_config) {
link_power->num_clk = 0;
rc = -EINVAL;
goto link_clock_error;
}
return rc;
link_clock_error:
dp_parser_put_clk_data(dev, strm1_power);
strm1_clock_error:
dp_parser_put_clk_data(dev, strm0_power);
strm0_clock_error:
dp_parser_put_clk_data(dev, ctrl_power);
ctrl_clock_error:
dp_parser_put_clk_data(dev, core_power);
exit:
return rc;
@ -573,25 +571,25 @@ static int dp_parser_clock(struct dp_parser *parser)
{
int rc = 0, i = 0;
int num_clk = 0;
int core_clk_index = 0, ctrl_clk_index = 0;
int core_clk_count = 0, ctrl_clk_count = 0;
int core_clk_index = 0, link_clk_index = 0;
int core_clk_count = 0, link_clk_count = 0;
int strm0_clk_index = 0, strm1_clk_index = 0;
int strm0_clk_count = 0, strm1_clk_count = 0;
const char *clk_name;
const char *core_clk = "core";
const char *ctrl_clk = "ctrl";
const char *strm0_clk = "strm0";
const char *strm1_clk = "strm1";
const char *link_clk = "link";
struct device *dev = &parser->pdev->dev;
struct dss_module_power *core_power;
struct dss_module_power *ctrl_power;
struct dss_module_power *strm0_power;
struct dss_module_power *strm1_power;
struct dss_module_power *link_power;
core_power = &parser->mp[DP_CORE_PM];
ctrl_power = &parser->mp[DP_CTRL_PM];
strm0_power = &parser->mp[DP_STREAM0_PM];
strm1_power = &parser->mp[DP_STREAM1_PM];
link_power = &parser->mp[DP_LINK_PM];
rc = dp_parser_init_clk_data(parser);
if (rc) {
@ -601,7 +599,7 @@ static int dp_parser_clock(struct dp_parser *parser)
}
core_clk_count = core_power->num_clk;
ctrl_clk_count = ctrl_power->num_clk;
link_clk_count = link_power->num_clk;
strm0_clk_count = strm0_power->num_clk;
strm1_clk_count = strm1_power->num_clk;
@ -618,15 +616,14 @@ static int dp_parser_clock(struct dp_parser *parser)
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
clk->type = DSS_CLK_AHB;
core_clk_index++;
} else if (dp_parser_check_prefix(ctrl_clk, clk_name) &&
ctrl_clk_index < ctrl_clk_count) {
} else if (dp_parser_check_prefix(link_clk, clk_name) &&
link_clk_index < link_clk_count) {
struct dss_clk *clk =
&ctrl_power->clk_config[ctrl_clk_index];
&link_power->clk_config[link_clk_index];
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
ctrl_clk_index++;
link_clk_index++;
if (!strcmp(clk_name, "ctrl_link_clk") ||
!strcmp(clk_name, "ctrl_pixel_clk"))
if (!strcmp(clk_name, "link_clk"))
clk->type = DSS_CLK_PCLK;
else
clk->type = DSS_CLK_AHB;

View File

@ -27,6 +27,7 @@ enum dp_pm_type {
DP_PHY_PM,
DP_STREAM0_PM,
DP_STREAM1_PM,
DP_LINK_PM,
DP_MAX_PM
};
@ -38,6 +39,7 @@ static inline const char *dp_parser_pm_name(enum dp_pm_type module)
case DP_PHY_PM: return "DP_PHY_PM";
case DP_STREAM0_PM: return "DP_STREAM0_PM";
case DP_STREAM1_PM: return "DP_STREAM1_PM";
case DP_LINK_PM: return "DP_LINK_PM";
default: return "???";
}
}

View File

@ -147,49 +147,25 @@ static int dp_power_pinctrl_set(struct dp_power_private *power, bool active)
static int dp_power_clk_init(struct dp_power_private *power, bool enable)
{
int rc = 0;
struct dss_module_power *core, *ctrl, *strm0, *strm1;
struct device *dev;
core = &power->parser->mp[DP_CORE_PM];
ctrl = &power->parser->mp[DP_CTRL_PM];
strm0 = &power->parser->mp[DP_STREAM0_PM];
strm1 = &power->parser->mp[DP_STREAM1_PM];
enum dp_pm_type module;
dev = &power->pdev->dev;
if (!core || !ctrl) {
pr_err("invalid power_data\n");
rc = -EINVAL;
goto exit;
}
if (enable) {
rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk);
if (rc) {
pr_err("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_CORE_PM), rc);
goto exit;
}
for (module = DP_CORE_PM; module < DP_MAX_PM; module++) {
struct dss_module_power *pm =
&power->parser->mp[module];
rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk);
if (rc) {
pr_err("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_CTRL_PM), rc);
goto ctrl_get_error;
}
if (!pm->num_clk)
continue;
rc = msm_dss_get_clk(dev, strm0->clk_config, strm0->num_clk);
if (rc) {
pr_err("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_STREAM0_PM), rc);
goto strm0_get_error;
}
rc = msm_dss_get_clk(dev, strm1->clk_config, strm1->num_clk);
if (rc) {
pr_err("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_STREAM1_PM), rc);
goto strm1_get_error;
rc = msm_dss_get_clk(dev, pm->clk_config, pm->num_clk);
if (rc) {
pr_err("failed to get %s clk. err=%d\n",
dp_parser_pm_name(module), rc);
goto exit;
}
}
power->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg");
@ -228,20 +204,16 @@ static int dp_power_clk_init(struct dp_power_private *power, bool enable)
if (power->pixel1_clk_rcg)
devm_clk_put(dev, power->pixel1_clk_rcg);
msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
msm_dss_put_clk(core->clk_config, core->num_clk);
msm_dss_put_clk(strm0->clk_config, strm0->num_clk);
msm_dss_put_clk(strm1->clk_config, strm1->num_clk);
for (module = DP_CORE_PM; module < DP_MAX_PM; module++) {
struct dss_module_power *pm =
&power->parser->mp[module];
if (!pm->num_clk)
continue;
msm_dss_put_clk(pm->clk_config, pm->num_clk);
}
}
return rc;
strm1_get_error:
msm_dss_put_clk(strm0->clk_config, strm0->num_clk);
strm0_get_error:
msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
ctrl_get_error:
msm_dss_put_clk(core->clk_config, core->num_clk);
exit:
return rc;
}
@ -300,35 +272,24 @@ static int dp_power_clk_enable(struct dp_power *dp_power,
mp = &power->parser->mp[pm_type];
if ((pm_type != DP_CORE_PM) && (pm_type != DP_CTRL_PM) &&
(pm_type != DP_STREAM0_PM) &&
(pm_type != DP_STREAM1_PM)) {
if (pm_type >= DP_MAX_PM) {
pr_err("unsupported power module: %s\n",
dp_parser_pm_name(pm_type));
return -EINVAL;
}
if (enable) {
if ((pm_type == DP_CORE_PM)
&& (power->core_clks_on)) {
if (pm_type == DP_CORE_PM && power->core_clks_on) {
pr_debug("core clks already enabled\n");
return 0;
}
if ((pm_type == DP_CTRL_PM)
&& (power->link_clks_on)) {
pr_debug("links clks already enabled\n");
return 0;
}
if ((pm_type == DP_STREAM0_PM)
&& (power->strm0_clks_on)) {
if ((pm_type == DP_STREAM0_PM) && (power->strm0_clks_on)) {
pr_debug("strm0 clks already enabled\n");
return 0;
}
if ((pm_type == DP_STREAM1_PM)
&& (power->strm1_clks_on)) {
if ((pm_type == DP_STREAM1_PM) && (power->strm1_clks_on)) {
pr_debug("strm1 clks already enabled\n");
return 0;
}
@ -345,6 +306,11 @@ static int dp_power_clk_enable(struct dp_power *dp_power,
power->core_clks_on = true;
}
}
if (pm_type == DP_LINK_PM && power->link_clks_on) {
pr_debug("links clks already enabled\n");
return 0;
}
}
rc = dp_power_clk_set_rate(power, pm_type, enable);
@ -357,12 +323,12 @@ static int dp_power_clk_enable(struct dp_power *dp_power,
if (pm_type == DP_CORE_PM)
power->core_clks_on = enable;
else if (pm_type == DP_CTRL_PM)
power->link_clks_on = enable;
else if (pm_type == DP_STREAM0_PM)
power->strm0_clks_on = enable;
else if (pm_type == DP_STREAM1_PM)
power->strm1_clks_on = enable;
else if (pm_type == DP_LINK_PM)
power->link_clks_on = enable;
pr_debug("%s clocks for %s\n",
enable ? "enable" : "disable",
@ -637,15 +603,10 @@ static int dp_power_deinit(struct dp_power *dp_power)
power = container_of(dp_power, struct dp_power_private, dp_power);
dp_power_clk_enable(dp_power, DP_CORE_PM, false);
/*
* If the display power on event was not successful, for example if
* there was a link training failure, then the link clocks could
* possibly still be on. In this scenario, we need to turn off the
* link clocks as soon as the cable is disconnected so that the clock
* state is cleaned up before subsequent connection events.
*/
if (power->link_clks_on)
dp_power_clk_enable(dp_power, DP_CTRL_PM, false);
dp_power_clk_enable(dp_power, DP_LINK_PM, false);
rc = sde_power_resource_enable(power->phandle,
power->dp_core_client, false);
if (rc) {

View File

@ -50,6 +50,7 @@ int msm_drm_register_client(struct notifier_block *nb)
return blocking_notifier_chain_register(&msm_drm_notifier_list,
nb);
}
EXPORT_SYMBOL(msm_drm_register_client);
/**
* msm_drm_unregister_client - unregister a client notifier
@ -63,6 +64,7 @@ int msm_drm_unregister_client(struct notifier_block *nb)
return blocking_notifier_chain_unregister(&msm_drm_notifier_list,
nb);
}
EXPORT_SYMBOL(msm_drm_unregister_client);
/**
* msm_drm_notifier_call_chain - notify clients of drm_events
@ -239,11 +241,14 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n",
encoder->base.id, encoder->name);
blank = MSM_DRM_BLANK_POWERDOWN;
notifier_data.data = &blank;
notifier_data.id = crtc_idx;
msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK,
&notifier_data);
if (connector->state->crtc &&
connector->state->crtc->state->active_changed) {
blank = MSM_DRM_BLANK_POWERDOWN;
notifier_data.data = &blank;
notifier_data.id = crtc_idx;
msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK,
&notifier_data);
}
/*
* Each encoder has at most one connector (since we always steal
* it away), so we won't call disable hooks twice.
@ -259,8 +264,12 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
drm_bridge_post_disable(encoder->bridge);
msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK,
&notifier_data);
if (connector->state->crtc &&
connector->state->crtc->state->active_changed) {
DRM_DEBUG_ATOMIC("Notify blank\n");
msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK,
&notifier_data);
}
}
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
@ -465,7 +474,8 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n",
encoder->base.id, encoder->name);
if (connector->state->crtc->state->active_changed) {
if (connector->state->crtc &&
connector->state->crtc->state->active_changed) {
blank = MSM_DRM_BLANK_UNBLANK;
notifier_data.data = &blank;
notifier_data.id =
@ -522,7 +532,8 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
encoder->base.id, encoder->name);
drm_bridge_enable(encoder->bridge);
if (connector->state->crtc->state->active_changed) {
if (connector->state->crtc &&
connector->state->crtc->state->active_changed) {
DRM_DEBUG_ATOMIC("Notify unblank\n");
msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK,
&notifier_data);

View File

@ -78,6 +78,9 @@ static struct page **get_pages(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
if (obj->import_attach)
return msm_obj->pages;
if (!msm_obj->pages) {
struct drm_device *dev = obj->dev;
struct page **p;
@ -644,8 +647,14 @@ void *msm_gem_get_vaddr(struct drm_gem_object *obj)
ret = PTR_ERR(pages);
goto fail;
}
msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
if (obj->import_attach)
msm_obj->vaddr =
dma_buf_vmap(obj->import_attach->dmabuf);
else
msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
VM_MAP, pgprot_writecombine(PAGE_KERNEL));
if (msm_obj->vaddr == NULL) {
ret = -ENOMEM;
goto fail;
@ -742,7 +751,11 @@ static void msm_gem_vunmap_locked(struct drm_gem_object *obj)
if (!msm_obj->vaddr || WARN_ON(!is_vunmapable(msm_obj)))
return;
vunmap(msm_obj->vaddr);
if (obj->import_attach)
dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr);
else
vunmap(msm_obj->vaddr);
msm_obj->vaddr = NULL;
}
@ -1134,8 +1147,6 @@ int msm_gem_delayed_import(struct drm_gem_object *obj)
struct dma_buf_attachment *attach;
struct sg_table *sgt;
struct msm_gem_object *msm_obj;
uint32_t size;
int npages;
int ret = 0;
if (!obj) {
@ -1171,18 +1182,8 @@ int msm_gem_delayed_import(struct drm_gem_object *obj)
ret);
goto fail_import;
}
size = PAGE_ALIGN(attach->dmabuf->size);
npages = size >> PAGE_SHIFT;
msm_obj->sgt = sgt;
ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages,
NULL, npages);
if (ret) {
DRM_ERROR("fail drm_prime_sg_to_page_addr_arrays, err=%d\n",
ret);
goto fail_import;
}
msm_obj->pages = NULL;
fail_import:
return ret;
@ -1194,7 +1195,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
struct msm_gem_object *msm_obj;
struct drm_gem_object *obj = NULL;
uint32_t size;
int ret, npages;
int ret;
unsigned long flags = 0;
/* if we don't have IOMMU, don't bother pretending we can import: */
@ -1212,32 +1213,16 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
drm_gem_private_object_init(dev, obj, size);
npages = size >> PAGE_SHIFT;
msm_obj = to_msm_bo(obj);
mutex_lock(&msm_obj->lock);
msm_obj->sgt = sgt;
msm_obj->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
if (!msm_obj->pages) {
mutex_unlock(&msm_obj->lock);
ret = -ENOMEM;
goto fail;
}
msm_obj->pages = NULL;
/*
* If sg table is NULL, user should call msm_gem_delayed_import to add
* back the sg table to the drm gem object
*/
if (sgt) {
ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages,
NULL, npages);
if (ret) {
mutex_unlock(&msm_obj->lock);
goto fail;
}
} else {
if (!sgt)
msm_obj->flags |= MSM_BO_EXTBUF;
}
/*
* For all uncached buffers, there is no need to perform cache

View File

@ -308,14 +308,17 @@ static void _sde_encoder_pm_qos_add_request(struct drm_encoder *drm_enc)
if (!cpu_mask)
return;
req = &sde_kms->pm_qos_cpu_req;
req->type = PM_QOS_REQ_AFFINE_CORES;
cpumask_empty(&req->cpus_affine);
for_each_possible_cpu(cpu) {
if ((1 << cpu) & cpu_mask)
cpumask_set_cpu(cpu, &req->cpus_affine);
if (atomic_inc_return(&sde_kms->pm_qos_counts) == 1) {
req = &sde_kms->pm_qos_cpu_req;
req->type = PM_QOS_REQ_AFFINE_CORES;
cpumask_empty(&req->cpus_affine);
for_each_possible_cpu(cpu) {
if ((1 << cpu) & cpu_mask)
cpumask_set_cpu(cpu, &req->cpus_affine);
}
pm_qos_add_request(req, PM_QOS_CPU_DMA_LATENCY,
cpu_dma_latency);
}
pm_qos_add_request(req, PM_QOS_CPU_DMA_LATENCY, cpu_dma_latency);
SDE_EVT32_VERBOSE(DRMID(drm_enc), cpu_mask, cpu_dma_latency);
}
@ -340,7 +343,9 @@ static void _sde_encoder_pm_qos_remove_request(struct drm_encoder *drm_enc)
if (!sde_kms || !sde_kms->catalog || !sde_kms->catalog->perf.cpu_mask)
return;
pm_qos_remove_request(&sde_kms->pm_qos_cpu_req);
atomic_add_unless(&sde_kms->pm_qos_counts, -1, 0);
if (atomic_read(&sde_kms->pm_qos_counts) == 0)
pm_qos_remove_request(&sde_kms->pm_qos_cpu_req);
}
static struct drm_connector_state *_sde_encoder_get_conn_state(
@ -3289,6 +3294,12 @@ static void sde_encoder_frame_done_callback(
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
unsigned int i;
if (!drm_enc || !sde_enc->cur_master) {
SDE_ERROR("invalid param: drm_enc %x, cur_master %x\n",
drm_enc, drm_enc ? sde_enc->cur_master : 0);
return;
}
sde_enc->crtc_frame_event_cb_data.connector =
sde_enc->cur_master->connector;

View File

@ -1120,18 +1120,14 @@ static void sde_encoder_phys_wb_irq_ctrl(
if (enable) {
sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE);
if (phys->in_clone_mode) {
for (index = 0; index < CRTC_DUAL_MIXERS; index++)
sde_encoder_helper_register_irq(phys,
cwb_irq_tbl[index + pp]);
}
for (index = 0; index < CRTC_DUAL_MIXERS; index++)
sde_encoder_helper_register_irq(phys,
cwb_irq_tbl[index + pp]);
} else {
sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE);
if (phys->in_clone_mode) {
for (index = 0; index < CRTC_DUAL_MIXERS; index++)
sde_encoder_helper_unregister_irq(phys,
cwb_irq_tbl[index + pp]);
}
for (index = 0; index < CRTC_DUAL_MIXERS; index++)
sde_encoder_helper_unregister_irq(phys,
cwb_irq_tbl[index + pp]);
}
}

View File

@ -492,8 +492,7 @@ static int _sde_kms_scm_call(struct sde_kms *sde_kms, int vmid)
SDE_ERROR("Error:scm_call2, vmid %lld, ret%d\n",
desc.args[3], ret);
SDE_EVT32(mem_protect_sd_ctrl_id,
desc.args[0], desc.args[3], num_sids,
sec_sid[0], sec_sid[1], ret);
desc.args[0], desc.args[3], num_sids, ret);
kfree(sec_sid);
return ret;
@ -3202,6 +3201,7 @@ static int sde_kms_hw_init(struct msm_kms *kms)
mutex_init(&sde_kms->secure_transition_lock);
atomic_set(&sde_kms->detach_sec_cb, 0);
atomic_set(&sde_kms->detach_all_cb, 0);
atomic_set(&sde_kms->pm_qos_counts, 0);
/*
* Support format modifiers for compression etc.

View File

@ -225,6 +225,7 @@ struct sde_kms {
struct msm_gem_address_space *aspace[MSM_SMMU_DOMAIN_MAX];
struct sde_power_client *core_client;
struct pm_qos_request pm_qos_cpu_req;
atomic_t pm_qos_counts;
struct sde_power_event *power_event;