mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge "drm/msm/dp: complete link training before hot plug notification"
This commit is contained in:
commit
b278d1573b
@ -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";
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 "???";
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user