summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/dp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dp')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_catalog.c14
-rw-r--r--drivers/gpu/drm/msm/dp/dp_catalog.h1
-rw-r--r--drivers/gpu/drm/msm/dp/dp_ctrl.c434
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c272
-rw-r--r--drivers/gpu/drm/msm/dp/dp_link.c41
-rw-r--r--drivers/gpu/drm/msm/dp/dp_link.h1
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.c5
-rw-r--r--drivers/gpu/drm/msm/dp/dp_power.c44
-rw-r--r--drivers/gpu/drm/msm/dp/dp_power.h2
-rw-r--r--drivers/gpu/drm/msm/dp/dp_reg.h2
10 files changed, 503 insertions, 313 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index b15b4ce4ba35..44f0c57798d0 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -5,7 +5,6 @@
#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
-#include <linux/rational.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/phy/phy.h>
@@ -572,6 +571,19 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
}
+u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
+{
+ struct dp_catalog_private *catalog = container_of(dp_catalog,
+ struct dp_catalog_private, dp_catalog);
+ u32 status;
+
+ status = dp_read_aux(catalog, REG_DP_DP_HPD_INT_STATUS);
+ status >>= DP_DP_HPD_STATE_STATUS_BITS_SHIFT;
+ status &= DP_DP_HPD_STATE_STATUS_BITS_MASK;
+
+ return status;
+}
+
u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog)
{
struct dp_catalog_private *catalog = container_of(dp_catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 4b7666f1fe6f..176a9020a520 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -97,6 +97,7 @@ void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool enable);
void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog,
u32 intr_mask, bool en);
void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog);
+u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog);
u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog);
void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog);
int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog, u8 v_level,
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 2e3e1917351f..e3462f5d96d7 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy-dp.h>
+#include <linux/pm_opp.h>
#include <drm/drm_fixed.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_print.h>
@@ -76,6 +77,8 @@ struct dp_ctrl_private {
struct dp_parser *parser;
struct dp_catalog *catalog;
+ struct opp_table *opp_table;
+
struct completion idle_comp;
struct completion video_comp;
};
@@ -611,7 +614,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
static void _dp_ctrl_calc_tu(struct dp_tu_calc_input *in,
struct dp_vc_tu_mapping_table *tu_table)
{
- struct tu_algo_data tu;
+ struct tu_algo_data *tu;
int compare_result_1, compare_result_2;
u64 temp = 0;
s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0;
@@ -626,298 +629,300 @@ static void _dp_ctrl_calc_tu(struct dp_tu_calc_input *in,
uint EXTRA_PIXCLK_CYCLE_DELAY = 4;
uint HBLANK_MARGIN = 4;
- memset(&tu, 0, sizeof(tu));
+ tu = kzalloc(sizeof(*tu), GFP_KERNEL);
+ if (!tu)
+ return
- dp_panel_update_tu_timings(in, &tu);
+ dp_panel_update_tu_timings(in, tu);
- tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
+ tu->err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
temp1_fp = drm_fixp_from_fraction(4, 1);
- temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp);
- temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp);
- tu.extra_buffer_margin = drm_fixp2int_ceil(temp_fp);
+ temp2_fp = drm_fixp_mul(temp1_fp, tu->lclk_fp);
+ temp_fp = drm_fixp_div(temp2_fp, tu->pclk_fp);
+ tu->extra_buffer_margin = drm_fixp2int_ceil(temp_fp);
- temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
- temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp);
- temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
+ temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+ temp2_fp = drm_fixp_mul(tu->pclk_fp, temp1_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
- tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp);
-
- tu.original_ratio_fp = tu.ratio_fp;
- tu.boundary_moderation_en = false;
- tu.upper_boundary_count = 0;
- tu.lower_boundary_count = 0;
- tu.i_upper_boundary_count = 0;
- tu.i_lower_boundary_count = 0;
- tu.valid_lower_boundary_link = 0;
- tu.even_distribution_BF = 0;
- tu.even_distribution_legacy = 0;
- tu.even_distribution = 0;
- tu.delay_start_time_fp = 0;
-
- tu.err_fp = drm_fixp_from_fraction(1000, 1);
- tu.n_err_fp = 0;
- tu.n_n_err_fp = 0;
-
- tu.ratio = drm_fixp2int(tu.ratio_fp);
- temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
- div64_u64_rem(tu.lwidth_fp, temp1_fp, &temp2_fp);
+ tu->ratio_fp = drm_fixp_div(temp2_fp, tu->lclk_fp);
+
+ tu->original_ratio_fp = tu->ratio_fp;
+ tu->boundary_moderation_en = false;
+ tu->upper_boundary_count = 0;
+ tu->lower_boundary_count = 0;
+ tu->i_upper_boundary_count = 0;
+ tu->i_lower_boundary_count = 0;
+ tu->valid_lower_boundary_link = 0;
+ tu->even_distribution_BF = 0;
+ tu->even_distribution_legacy = 0;
+ tu->even_distribution = 0;
+ tu->delay_start_time_fp = 0;
+
+ tu->err_fp = drm_fixp_from_fraction(1000, 1);
+ tu->n_err_fp = 0;
+ tu->n_n_err_fp = 0;
+
+ tu->ratio = drm_fixp2int(tu->ratio_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
+ div64_u64_rem(tu->lwidth_fp, temp1_fp, &temp2_fp);
if (temp2_fp != 0 &&
- !tu.ratio && tu.dsc_en == 0) {
- tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp);
- tu.ratio = drm_fixp2int(tu.ratio_fp);
- if (tu.ratio)
- tu.ratio_fp = drm_fixp_from_fraction(1, 1);
+ !tu->ratio && tu->dsc_en == 0) {
+ tu->ratio_fp = drm_fixp_mul(tu->ratio_fp, RATIO_SCALE_fp);
+ tu->ratio = drm_fixp2int(tu->ratio_fp);
+ if (tu->ratio)
+ tu->ratio_fp = drm_fixp_from_fraction(1, 1);
}
- if (tu.ratio > 1)
- tu.ratio = 1;
+ if (tu->ratio > 1)
+ tu->ratio = 1;
- if (tu.ratio == 1)
+ if (tu->ratio == 1)
goto tu_size_calc;
- compare_result_1 = _tu_param_compare(tu.ratio_fp, const_p49_fp);
+ compare_result_1 = _tu_param_compare(tu->ratio_fp, const_p49_fp);
if (!compare_result_1 || compare_result_1 == 1)
compare_result_1 = 1;
else
compare_result_1 = 0;
- compare_result_2 = _tu_param_compare(tu.ratio_fp, const_p56_fp);
+ compare_result_2 = _tu_param_compare(tu->ratio_fp, const_p56_fp);
if (!compare_result_2 || compare_result_2 == 2)
compare_result_2 = 1;
else
compare_result_2 = 0;
- if (tu.dsc_en && compare_result_1 && compare_result_2) {
+ if (tu->dsc_en && compare_result_1 && compare_result_2) {
HBLANK_MARGIN += 4;
DRM_DEBUG_DP("Info: increase HBLANK_MARGIN to %d\n",
HBLANK_MARGIN);
}
tu_size_calc:
- for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
- temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1);
- temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+ for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
+ temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
+ temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
temp = drm_fixp2int_ceil(temp2_fp);
temp1_fp = drm_fixp_from_fraction(temp, 1);
- tu.n_err_fp = temp1_fp - temp2_fp;
+ tu->n_err_fp = temp1_fp - temp2_fp;
- if (tu.n_err_fp < tu.err_fp) {
- tu.err_fp = tu.n_err_fp;
- tu.tu_size_desired = tu.tu_size;
+ if (tu->n_err_fp < tu->err_fp) {
+ tu->err_fp = tu->n_err_fp;
+ tu->tu_size_desired = tu->tu_size;
}
}
- tu.tu_size_minus1 = tu.tu_size_desired - 1;
+ tu->tu_size_minus1 = tu->tu_size_desired - 1;
- temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
- temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
- tu.valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
+ temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
+ tu->valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
- temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
- temp2_fp = tu.lwidth_fp;
+ temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+ temp2_fp = tu->lwidth_fp;
temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp);
- temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+ temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
- tu.n_tus = drm_fixp2int(temp2_fp);
+ tu->n_tus = drm_fixp2int(temp2_fp);
if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000)
- tu.n_tus += 1;
+ tu->n_tus += 1;
- tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0;
+ tu->even_distribution_legacy = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
DRM_DEBUG_DP("Info: n_sym = %d, num_of_tus = %d\n",
- tu.valid_boundary_link, tu.n_tus);
+ tu->valid_boundary_link, tu->n_tus);
- temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
- temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
- temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+ temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
+ temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
temp2_fp = temp1_fp - temp2_fp;
- temp1_fp = drm_fixp_from_fraction(tu.n_tus + 1, 1);
+ temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1);
temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
temp = drm_fixp2int(temp2_fp);
if (temp && temp2_fp)
- tu.extra_bytes = drm_fixp2int_ceil(temp2_fp);
+ tu->extra_bytes = drm_fixp2int_ceil(temp2_fp);
else
- tu.extra_bytes = 0;
+ tu->extra_bytes = 0;
- temp1_fp = drm_fixp_from_fraction(tu.extra_bytes, 1);
- temp2_fp = drm_fixp_from_fraction(8, tu.bpp);
+ temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1);
+ temp2_fp = drm_fixp_from_fraction(8, tu->bpp);
temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
if (temp && temp1_fp)
- tu.extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp);
+ tu->extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp);
else
- tu.extra_pclk_cycles = drm_fixp2int(temp1_fp);
+ tu->extra_pclk_cycles = drm_fixp2int(temp1_fp);
- temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
- temp2_fp = drm_fixp_from_fraction(tu.extra_pclk_cycles, 1);
+ temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
+ temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1);
temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
if (temp1_fp)
- tu.extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp);
+ tu->extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp);
else
- tu.extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp);
+ tu->extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp);
- tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
+ tu->filler_size = tu->tu_size_desired - tu->valid_boundary_link;
- temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
- tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
+ tu->ratio_by_tu_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
- tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk +
- tu.filler_size + tu.extra_buffer_margin;
+ tu->delay_start_link = tu->extra_pclk_cycles_in_link_clk +
+ tu->filler_size + tu->extra_buffer_margin;
- tu.resulting_valid_fp =
- drm_fixp_from_fraction(tu.valid_boundary_link, 1);
+ tu->resulting_valid_fp =
+ drm_fixp_from_fraction(tu->valid_boundary_link, 1);
- temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
- temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
- tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
+ temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
+ temp2_fp = drm_fixp_div(tu->resulting_valid_fp, temp1_fp);
+ tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp;
temp1_fp = drm_fixp_from_fraction(HBLANK_MARGIN, 1);
- temp1_fp = tu.hbp_relative_to_pclk_fp - temp1_fp;
- tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
+ temp1_fp = tu->hbp_relative_to_pclk_fp - temp1_fp;
+ tu->hbp_time_fp = drm_fixp_div(temp1_fp, tu->pclk_fp);
- temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
- tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1);
+ tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
- compare_result_1 = _tu_param_compare(tu.hbp_time_fp,
- tu.delay_start_time_fp);
+ compare_result_1 = _tu_param_compare(tu->hbp_time_fp,
+ tu->delay_start_time_fp);
if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp) */
- tu.min_hblank_violated = 1;
+ tu->min_hblank_violated = 1;
- tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp);
+ tu->hactive_time_fp = drm_fixp_div(tu->lwidth_fp, tu->pclk_fp);
- compare_result_2 = _tu_param_compare(tu.hactive_time_fp,
- tu.delay_start_time_fp);
+ compare_result_2 = _tu_param_compare(tu->hactive_time_fp,
+ tu->delay_start_time_fp);
if (compare_result_2 == 2)
- tu.min_hblank_violated = 1;
+ tu->min_hblank_violated = 1;
- tu.delay_start_time_fp = 0;
+ tu->delay_start_time_fp = 0;
/* brute force */
- tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
- tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
+ tu->delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
+ tu->diff_abs_fp = tu->resulting_valid_fp - tu->ratio_by_tu_fp;
- temp = drm_fixp2int(tu.diff_abs_fp);
- if (!temp && tu.diff_abs_fp <= 0xffff)
- tu.diff_abs_fp = 0;
+ temp = drm_fixp2int(tu->diff_abs_fp);
+ if (!temp && tu->diff_abs_fp <= 0xffff)
+ tu->diff_abs_fp = 0;
/* if(diff_abs < 0) diff_abs *= -1 */
- if (tu.diff_abs_fp < 0)
- tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1);
+ if (tu->diff_abs_fp < 0)
+ tu->diff_abs_fp = drm_fixp_mul(tu->diff_abs_fp, -1);
- tu.boundary_mod_lower_err = 0;
- if ((tu.diff_abs_fp != 0 &&
- ((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
- (tu.even_distribution_legacy == 0) ||
+ tu->boundary_mod_lower_err = 0;
+ if ((tu->diff_abs_fp != 0 &&
+ ((tu->diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
+ (tu->even_distribution_legacy == 0) ||
(DP_BRUTE_FORCE == 1))) ||
- (tu.min_hblank_violated == 1)) {
+ (tu->min_hblank_violated == 1)) {
do {
- tu.err_fp = drm_fixp_from_fraction(1000, 1);
+ tu->err_fp = drm_fixp_from_fraction(1000, 1);
- temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
+ temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
temp2_fp = drm_fixp_from_fraction(
- tu.delay_start_link_extra_pixclk, 1);
+ tu->delay_start_link_extra_pixclk, 1);
temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
if (temp1_fp)
- tu.extra_buffer_margin =
+ tu->extra_buffer_margin =
drm_fixp2int_ceil(temp1_fp);
else
- tu.extra_buffer_margin = 0;
+ tu->extra_buffer_margin = 0;
- temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
- temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+ temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
if (temp1_fp)
- tu.n_symbols = drm_fixp2int_ceil(temp1_fp);
+ tu->n_symbols = drm_fixp2int_ceil(temp1_fp);
else
- tu.n_symbols = 0;
-
- for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
- for (tu.i_upper_boundary_count = 1;
- tu.i_upper_boundary_count <= 15;
- tu.i_upper_boundary_count++) {
- for (tu.i_lower_boundary_count = 1;
- tu.i_lower_boundary_count <= 15;
- tu.i_lower_boundary_count++) {
- _tu_valid_boundary_calc(&tu);
+ tu->n_symbols = 0;
+
+ for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
+ for (tu->i_upper_boundary_count = 1;
+ tu->i_upper_boundary_count <= 15;
+ tu->i_upper_boundary_count++) {
+ for (tu->i_lower_boundary_count = 1;
+ tu->i_lower_boundary_count <= 15;
+ tu->i_lower_boundary_count++) {
+ _tu_valid_boundary_calc(tu);
}
}
}
- tu.delay_start_link_extra_pixclk--;
- } while (tu.boundary_moderation_en != true &&
- tu.boundary_mod_lower_err == 1 &&
- tu.delay_start_link_extra_pixclk != 0);
+ tu->delay_start_link_extra_pixclk--;
+ } while (tu->boundary_moderation_en != true &&
+ tu->boundary_mod_lower_err == 1 &&
+ tu->delay_start_link_extra_pixclk != 0);
- if (tu.boundary_moderation_en == true) {
+ if (tu->boundary_moderation_en == true) {
temp1_fp = drm_fixp_from_fraction(
- (tu.upper_boundary_count *
- tu.valid_boundary_link +
- tu.lower_boundary_count *
- (tu.valid_boundary_link - 1)), 1);
+ (tu->upper_boundary_count *
+ tu->valid_boundary_link +
+ tu->lower_boundary_count *
+ (tu->valid_boundary_link - 1)), 1);
temp2_fp = drm_fixp_from_fraction(
- (tu.upper_boundary_count +
- tu.lower_boundary_count), 1);
- tu.resulting_valid_fp =
+ (tu->upper_boundary_count +
+ tu->lower_boundary_count), 1);
+ tu->resulting_valid_fp =
drm_fixp_div(temp1_fp, temp2_fp);
temp1_fp = drm_fixp_from_fraction(
- tu.tu_size_desired, 1);
- tu.ratio_by_tu_fp =
- drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+ tu->tu_size_desired, 1);
+ tu->ratio_by_tu_fp =
+ drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
- tu.valid_lower_boundary_link =
- tu.valid_boundary_link - 1;
+ tu->valid_lower_boundary_link =
+ tu->valid_boundary_link - 1;
- temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
- temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+ temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
temp2_fp = drm_fixp_div(temp1_fp,
- tu.resulting_valid_fp);
- tu.n_tus = drm_fixp2int(temp2_fp);
+ tu->resulting_valid_fp);
+ tu->n_tus = drm_fixp2int(temp2_fp);
- tu.tu_size_minus1 = tu.tu_size_desired - 1;
- tu.even_distribution_BF = 1;
+ tu->tu_size_minus1 = tu->tu_size_desired - 1;
+ tu->even_distribution_BF = 1;
temp1_fp =
- drm_fixp_from_fraction(tu.tu_size_desired, 1);
+ drm_fixp_from_fraction(tu->tu_size_desired, 1);
temp2_fp =
- drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
- tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
+ drm_fixp_div(tu->resulting_valid_fp, temp1_fp);
+ tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp;
}
}
- temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp);
+ temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu->lwidth_fp);
if (temp2_fp)
temp = drm_fixp2int_ceil(temp2_fp);
else
temp = 0;
- temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
- temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
- temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+ temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
+ temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
temp1_fp = drm_fixp_from_fraction(temp, 1);
temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
temp = drm_fixp2int(temp2_fp);
- if (tu.async_en)
- tu.delay_start_link += (int)temp;
+ if (tu->async_en)
+ tu->delay_start_link += (int)temp;
- temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
- tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
+ temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1);
+ tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
/* OUTPUTS */
- tu_table->valid_boundary_link = tu.valid_boundary_link;
- tu_table->delay_start_link = tu.delay_start_link;
- tu_table->boundary_moderation_en = tu.boundary_moderation_en;
- tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link;
- tu_table->upper_boundary_count = tu.upper_boundary_count;
- tu_table->lower_boundary_count = tu.lower_boundary_count;
- tu_table->tu_size_minus1 = tu.tu_size_minus1;
+ tu_table->valid_boundary_link = tu->valid_boundary_link;
+ tu_table->delay_start_link = tu->delay_start_link;
+ tu_table->boundary_moderation_en = tu->boundary_moderation_en;
+ tu_table->valid_lower_boundary_link = tu->valid_lower_boundary_link;
+ tu_table->upper_boundary_count = tu->upper_boundary_count;
+ tu_table->lower_boundary_count = tu->lower_boundary_count;
+ tu_table->tu_size_minus1 = tu->tu_size_minus1;
DRM_DEBUG_DP("TU: valid_boundary_link: %d\n",
tu_table->valid_boundary_link);
@@ -932,6 +937,8 @@ tu_size_calc:
DRM_DEBUG_DP("TU: lower_boundary_count: %d\n",
tu_table->lower_boundary_count);
DRM_DEBUG_DP("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
+
+ kfree(tu);
}
static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
@@ -1061,23 +1068,15 @@ static bool dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
u8 *link_status)
{
- int len = 0;
- u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS;
- u32 link_status_read_max_retries = 100;
-
- while (--link_status_read_max_retries) {
- len = drm_dp_dpcd_read_link_status(ctrl->aux,
- link_status);
- if (len != DP_LINK_STATUS_SIZE) {
- DRM_ERROR("DP link status read failed, err: %d\n", len);
- return len;
- }
+ int ret = 0, len;
- if (!(link_status[offset] & DP_LINK_STATUS_UPDATED))
- return 0;
+ len = drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
+ if (len != DP_LINK_STATUS_SIZE) {
+ DRM_ERROR("DP link status read failed, err: %d\n", len);
+ ret = -EINVAL;
}
- return -ETIMEDOUT;
+ return ret;
}
static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl,
@@ -1400,6 +1399,8 @@ int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip)
void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
{
struct dp_ctrl_private *ctrl;
+ struct dp_io *dp_io;
+ struct phy *phy;
if (!dp_ctrl) {
DRM_ERROR("Invalid input data\n");
@@ -1407,8 +1408,11 @@ void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
}
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+ dp_io = &ctrl->parser->io;
+ phy = dp_io->phy;
dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
+ phy_exit(phy);
DRM_DEBUG_DP("Host deinitialized successfully\n");
}
@@ -1463,6 +1467,30 @@ static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)
return ret;
}
+static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
+{
+ struct dp_io *dp_io;
+ struct phy *phy;
+ int ret;
+
+ dp_io = &ctrl->parser->io;
+ phy = dp_io->phy;
+
+ dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
+
+ dp_catalog_ctrl_reset(ctrl->catalog);
+
+ ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
+ if (ret) {
+ DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
+ }
+
+ phy_power_off(phy);
+ phy_exit(phy);
+
+ return 0;
+}
+
static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
{
int ret = 0;
@@ -1643,11 +1671,7 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
if (rc)
return rc;
- ctrl->link->phy_params.p_level = 0;
- ctrl->link->phy_params.v_level = 0;
-
- while (--link_train_max_retries &&
- !atomic_read(&ctrl->dp_ctrl.aborted)) {
+ while (--link_train_max_retries) {
rc = dp_ctrl_reinitialize_mainlink(ctrl);
if (rc) {
DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n",
@@ -1662,6 +1686,10 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
break;
} else if (training_step == DP_TRAINING_1) {
/* link train_1 failed */
+ if (!dp_catalog_link_is_connected(ctrl->catalog)) {
+ break;
+ }
+
rc = dp_ctrl_link_rate_down_shift(ctrl);
if (rc < 0) { /* already in RBR = 1.6G */
if (cr.lane_0_1 & DP_LANE0_1_CR_DONE) {
@@ -1681,6 +1709,10 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
}
} else if (training_step == DP_TRAINING_2) {
/* link train_2 failed, lower lane rate */
+ if (!dp_catalog_link_is_connected(ctrl->catalog)) {
+ break;
+ }
+
rc = dp_ctrl_link_lane_down_shift(ctrl);
if (rc < 0) {
/* end with failure */
@@ -1701,6 +1733,11 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
*/
if (rc == 0) /* link train successfully */
dp_ctrl_push_idle(dp_ctrl);
+ else {
+ /* link training failed */
+ dp_ctrl_deinitialize_mainlink(ctrl);
+ rc = -ECONNRESET;
+ }
return rc;
}
@@ -1836,6 +1873,7 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,
struct dp_parser *parser)
{
struct dp_ctrl_private *ctrl;
+ int ret;
if (!dev || !panel || !aux ||
!link || !catalog) {
@@ -1849,6 +1887,21 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,
return ERR_PTR(-ENOMEM);
}
+ ctrl->opp_table = dev_pm_opp_set_clkname(dev, "ctrl_link");
+ if (IS_ERR(ctrl->opp_table)) {
+ dev_err(dev, "invalid DP OPP table in device tree\n");
+ /* caller do PTR_ERR(ctrl->opp_table) */
+ return (struct dp_ctrl *)ctrl->opp_table;
+ }
+
+ /* OPP table is optional */
+ ret = dev_pm_opp_of_add_table(dev);
+ if (ret) {
+ dev_err(dev, "failed to add DP OPP table\n");
+ dev_pm_opp_put_clkname(ctrl->opp_table);
+ ctrl->opp_table = NULL;
+ }
+
init_completion(&ctrl->idle_comp);
init_completion(&ctrl->video_comp);
@@ -1866,4 +1919,13 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,
void dp_ctrl_put(struct dp_ctrl *dp_ctrl)
{
+ struct dp_ctrl_private *ctrl;
+
+ ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+ if (ctrl->opp_table) {
+ dev_pm_opp_of_remove_table(ctrl->dev);
+ dev_pm_opp_put_clkname(ctrl->opp_table);
+ ctrl->opp_table = NULL;
+ }
}
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index e175aa3fd3a9..6e971d552911 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -45,7 +45,7 @@ enum {
ST_CONNECT_PENDING,
ST_CONNECTED,
ST_DISCONNECT_PENDING,
- ST_SUSPEND_PENDING,
+ ST_DISPLAY_OFF,
ST_SUSPENDED,
};
@@ -102,20 +102,20 @@ struct dp_display_private {
struct dp_display_mode dp_mode;
struct msm_dp dp_display;
+ bool encoder_mode_set;
+
/* wait for audio signaling */
struct completion audio_comp;
/* event related only access by event thread */
struct mutex event_mutex;
wait_queue_head_t event_q;
- atomic_t hpd_state;
+ u32 hpd_state;
u32 event_pndx;
u32 event_gndx;
struct dp_event event_list[DP_EVENT_Q_MAX];
spinlock_t event_lock;
- struct completion resume_comp;
-
struct dp_audio *audio;
};
@@ -281,13 +281,24 @@ static void dp_display_send_hpd_event(struct msm_dp *dp_display)
drm_helper_hpd_irq_event(connector->dev);
}
-static int dp_display_send_hpd_notification(struct dp_display_private *dp,
- bool hpd)
+
+static void dp_display_set_encoder_mode(struct dp_display_private *dp)
{
- static bool encoder_mode_set;
struct msm_drm_private *priv = dp->dp_display.drm_dev->dev_private;
struct msm_kms *kms = priv->kms;
+ if (!dp->encoder_mode_set && dp->dp_display.encoder &&
+ kms->funcs->set_encoder_mode) {
+ kms->funcs->set_encoder_mode(kms,
+ dp->dp_display.encoder, false);
+
+ dp->encoder_mode_set = true;
+ }
+}
+
+static int dp_display_send_hpd_notification(struct dp_display_private *dp,
+ bool hpd)
+{
if ((hpd && dp->dp_display.is_connected) ||
(!hpd && !dp->dp_display.is_connected)) {
DRM_DEBUG_DP("HPD already %s\n", (hpd ? "on" : "off"));
@@ -300,15 +311,6 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
dp->dp_display.is_connected = hpd;
- if (dp->dp_display.is_connected && dp->dp_display.encoder
- && !encoder_mode_set
- && kms->funcs->set_encoder_mode) {
- kms->funcs->set_encoder_mode(kms,
- dp->dp_display.encoder, false);
- DRM_DEBUG_DP("set_encoder_mode() Completed\n");
- encoder_mode_set = true;
- }
-
dp_display_send_hpd_event(&dp->dp_display);
return 0;
@@ -335,6 +337,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes;
+ dp_link_reset_phy_params_vx_px(dp->link);
rc = dp_ctrl_on_link(dp->ctrl);
if (rc) {
DRM_ERROR("failed to complete DP link training\n");
@@ -343,7 +346,6 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
dp_add_event(dp, EV_USER_NOTIFICATION, true, 0);
-
end:
return rc;
}
@@ -360,12 +362,28 @@ static void dp_display_host_init(struct dp_display_private *dp)
if (dp->usbpd->orientation == ORIENTATION_CC2)
flip = true;
+ dp_display_set_encoder_mode(dp);
+
dp_power_init(dp->power, flip);
dp_ctrl_host_init(dp->ctrl, flip);
dp_aux_init(dp->aux);
dp->core_initialized = true;
}
+static void dp_display_host_deinit(struct dp_display_private *dp)
+{
+ if (!dp->core_initialized) {
+ DRM_DEBUG_DP("DP core not initialized\n");
+ return;
+ }
+
+ dp_ctrl_host_deinit(dp->ctrl);
+ dp_aux_deinit(dp->aux);
+ dp_power_deinit(dp->power);
+
+ dp->core_initialized = false;
+}
+
static int dp_display_usbpd_configure_cb(struct device *dev)
{
int rc = 0;
@@ -429,25 +447,42 @@ static void dp_display_handle_video_request(struct dp_display_private *dp)
}
}
-static int dp_display_handle_irq_hpd(struct dp_display_private *dp)
+static int dp_display_handle_port_ststus_changed(struct dp_display_private *dp)
{
- u32 sink_request;
-
- sink_request = dp->link->sink_request;
+ int rc = 0;
- if (sink_request & DS_PORT_STATUS_CHANGED) {
- dp_add_event(dp, EV_USER_NOTIFICATION, false, 0);
- if (dp_display_is_sink_count_zero(dp)) {
- DRM_DEBUG_DP("sink count is zero, nothing to do\n");
- return 0;
+ if (dp_display_is_sink_count_zero(dp)) {
+ DRM_DEBUG_DP("sink count is zero, nothing to do\n");
+ if (dp->hpd_state != ST_DISCONNECTED) {
+ dp->hpd_state = ST_DISCONNECT_PENDING;
+ dp_add_event(dp, EV_USER_NOTIFICATION, false, 0);
}
+ } else {
+ if (dp->hpd_state == ST_DISCONNECTED) {
+ dp->hpd_state = ST_CONNECT_PENDING;
+ rc = dp_display_process_hpd_high(dp);
+ if (rc)
+ dp->hpd_state = ST_DISCONNECTED;
+ }
+ }
+
+ return rc;
+}
- return dp_display_process_hpd_high(dp);
+static int dp_display_handle_irq_hpd(struct dp_display_private *dp)
+{
+ u32 sink_request = dp->link->sink_request;
+
+ if (dp->hpd_state == ST_DISCONNECTED) {
+ if (sink_request & DP_LINK_STATUS_UPDATED) {
+ DRM_ERROR("Disconnected, no DP_LINK_STATUS_UPDATED\n");
+ return -EINVAL;
+ }
}
dp_ctrl_handle_sink_request(dp->ctrl);
- if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN)
+ if (sink_request & DP_TEST_LINK_VIDEO_PATTERN)
dp_display_handle_video_request(dp);
return 0;
@@ -456,7 +491,9 @@ static int dp_display_handle_irq_hpd(struct dp_display_private *dp)
static int dp_display_usbpd_attention_cb(struct device *dev)
{
int rc = 0;
+ u32 sink_request;
struct dp_display_private *dp;
+ struct dp_usbpd *hpd;
if (!dev) {
DRM_ERROR("invalid dev\n");
@@ -470,10 +507,17 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
return -ENODEV;
}
+ hpd = dp->usbpd;
+
/* check for any test request issued by sink */
rc = dp_link_process_request(dp->link);
- if (!rc)
- dp_display_handle_irq_hpd(dp);
+ if (!rc) {
+ sink_request = dp->link->sink_request;
+ if (sink_request & DS_PORT_STATUS_CHANGED)
+ rc = dp_display_handle_port_ststus_changed(dp);
+ else
+ rc = dp_display_handle_irq_hpd(dp);
+ }
return rc;
}
@@ -490,8 +534,8 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
mutex_lock(&dp->event_mutex);
- state = atomic_read(&dp->hpd_state);
- if (state == ST_SUSPEND_PENDING) {
+ state = dp->hpd_state;
+ if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
mutex_unlock(&dp->event_mutex);
return 0;
}
@@ -508,21 +552,23 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
return 0;
}
- if (state == ST_SUSPENDED)
- tout = DP_TIMEOUT_NONE;
-
- atomic_set(&dp->hpd_state, ST_CONNECT_PENDING);
+ dp->hpd_state = ST_CONNECT_PENDING;
hpd->hpd_high = 1;
ret = dp_display_usbpd_configure_cb(&dp->pdev->dev);
- if (ret) { /* failed */
+ if (ret) { /* link train failed */
hpd->hpd_high = 0;
- atomic_set(&dp->hpd_state, ST_DISCONNECTED);
- }
+ dp->hpd_state = ST_DISCONNECTED;
+
+ if (ret == -ECONNRESET) { /* cable unplugged */
+ dp->core_initialized = false;
+ }
- /* start sanity checking */
- dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout);
+ } else {
+ /* start sentinel checking in case of missing uevent */
+ dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout);
+ }
mutex_unlock(&dp->event_mutex);
@@ -539,10 +585,10 @@ static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data)
mutex_lock(&dp->event_mutex);
- state = atomic_read(&dp->hpd_state);
+ state = dp->hpd_state;
if (state == ST_CONNECT_PENDING) {
dp_display_enable(dp, 0);
- atomic_set(&dp->hpd_state, ST_CONNECTED);
+ dp->hpd_state = ST_CONNECTED;
}
mutex_unlock(&dp->event_mutex);
@@ -553,7 +599,14 @@ static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data)
static void dp_display_handle_plugged_change(struct msm_dp *dp_display,
bool plugged)
{
- if (dp_display->plugged_cb && dp_display->codec_dev)
+ struct dp_display_private *dp;
+
+ dp = container_of(dp_display,
+ struct dp_display_private, dp_display);
+
+ /* notify audio subsystem only if sink supports audio */
+ if (dp_display->plugged_cb && dp_display->codec_dev &&
+ dp->audio_supported)
dp_display->plugged_cb(dp_display->codec_dev, plugged);
}
@@ -567,12 +620,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
mutex_lock(&dp->event_mutex);
- state = atomic_read(&dp->hpd_state);
- if (state == ST_SUSPEND_PENDING) {
- mutex_unlock(&dp->event_mutex);
- return 0;
- }
-
+ state = dp->hpd_state;
if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) {
mutex_unlock(&dp->event_mutex);
return 0;
@@ -585,7 +633,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
return 0;
}
- atomic_set(&dp->hpd_state, ST_DISCONNECT_PENDING);
+ dp->hpd_state = ST_DISCONNECT_PENDING;
/* disable HPD plug interrupt until disconnect is done */
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK
@@ -599,7 +647,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
*/
dp_display_usbpd_disconnect_cb(&dp->pdev->dev);
- /* start sanity checking */
+ /* start sentinel checking in case of missing uevent */
dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND);
/* signal the disconnect event early to ensure proper teardown */
@@ -620,10 +668,10 @@ static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data
mutex_lock(&dp->event_mutex);
- state = atomic_read(&dp->hpd_state);
+ state = dp->hpd_state;
if (state == ST_DISCONNECT_PENDING) {
dp_display_disable(dp, 0);
- atomic_set(&dp->hpd_state, ST_DISCONNECTED);
+ dp->hpd_state = ST_DISCONNECTED;
}
mutex_unlock(&dp->event_mutex);
@@ -634,17 +682,21 @@ static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data
static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
{
u32 state;
+ int ret;
mutex_lock(&dp->event_mutex);
/* irq_hpd can happen at either connected or disconnected state */
- state = atomic_read(&dp->hpd_state);
- if (state == ST_SUSPEND_PENDING) {
+ state = dp->hpd_state;
+ if (state == ST_DISPLAY_OFF) {
mutex_unlock(&dp->event_mutex);
return 0;
}
- dp_display_usbpd_attention_cb(&dp->pdev->dev);
+ ret = dp_display_usbpd_attention_cb(&dp->pdev->dev);
+ if (ret == -ECONNRESET) { /* cable unplugged */
+ dp->core_initialized = false;
+ }
mutex_unlock(&dp->event_mutex);
@@ -698,7 +750,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
goto error;
}
- dp->power = dp_power_get(dp->parser);
+ dp->power = dp_power_get(dev, dp->parser);
if (IS_ERR(dp->power)) {
rc = PTR_ERR(dp->power);
DRM_ERROR("failed to initialize power, rc = %d\n", rc);
@@ -798,8 +850,6 @@ static int dp_display_enable(struct dp_display_private *dp, u32 data)
if (!rc)
dp_display->power_on = true;
- /* complete resume_comp regardless it is armed or not */
- complete(&dp->resume_comp);
return rc;
}
@@ -829,7 +879,7 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data)
dp_display = g_dp_display;
if (!dp_display->power_on)
- return -EINVAL;
+ return 0;
/* wait only if audio was enabled */
if (dp_display->audio_enabled) {
@@ -1074,7 +1124,7 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id)
}
if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) {
- /* delete connect pending event first */
+ /* stop sentinel connect pending checking */
dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT);
dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0);
}
@@ -1151,9 +1201,6 @@ static int dp_display_probe(struct platform_device *pdev)
}
mutex_init(&dp->event_mutex);
-
- init_completion(&dp->resume_comp);
-
g_dp_display = &dp->dp_display;
/* Store DP audio handle inside DP display */
@@ -1189,20 +1236,54 @@ static int dp_display_remove(struct platform_device *pdev)
static int dp_pm_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_dp *dp_display = platform_get_drvdata(pdev);
+ struct dp_display_private *dp;
+ u32 status;
+
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ mutex_lock(&dp->event_mutex);
+
+ /* start from disconnected state */
+ dp->hpd_state = ST_DISCONNECTED;
+
+ /* turn on dp ctrl/phy */
+ dp_display_host_init(dp);
+
+ dp_catalog_ctrl_hpd_config(dp->catalog);
+
+ status = dp_catalog_link_is_connected(dp->catalog);
+
+ if (status)
+ dp->dp_display.is_connected = true;
+ else
+ dp->dp_display.is_connected = false;
+
+ mutex_unlock(&dp->event_mutex);
+
return 0;
}
static int dp_pm_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct dp_display_private *dp = platform_get_drvdata(pdev);
+ struct msm_dp *dp_display = platform_get_drvdata(pdev);
+ struct dp_display_private *dp;
- if (!dp) {
- DRM_ERROR("DP driver bind failed. Invalid driver data\n");
- return -EINVAL;
- }
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ mutex_lock(&dp->event_mutex);
+
+ if (dp->core_initialized == true)
+ dp_display_host_deinit(dp);
+
+ dp->hpd_state = ST_SUSPENDED;
+
+ /* host_init will be called at pm_resume */
+ dp->core_initialized = false;
- atomic_set(&dp->hpd_state, ST_SUSPENDED);
+ mutex_unlock(&dp->event_mutex);
return 0;
}
@@ -1317,19 +1398,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
return 0;
}
-static int dp_display_wait4resume_done(struct dp_display_private *dp)
-{
- int ret = 0;
-
- reinit_completion(&dp->resume_comp);
- if (!wait_for_completion_timeout(&dp->resume_comp,
- WAIT_FOR_RESUME_TIMEOUT_JIFFIES)) {
- DRM_ERROR("wait4resume_done timedout\n");
- ret = -ETIMEDOUT;
- }
- return ret;
-}
-
int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
{
int rc = 0;
@@ -1344,6 +1412,9 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
mutex_lock(&dp_display->event_mutex);
+ /* stop sentinel checking */
+ dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT);
+
rc = dp_display_set_mode(dp, &dp_display->dp_mode);
if (rc) {
DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
@@ -1358,15 +1429,10 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
return rc;
}
- state = atomic_read(&dp_display->hpd_state);
- if (state == ST_SUSPENDED) {
- /* start link training */
- dp_add_event(dp_display, EV_HPD_PLUG_INT, 0, 0);
- mutex_unlock(&dp_display->event_mutex);
+ state = dp_display->hpd_state;
- /* wait until dp interface is up */
- goto resume_done;
- }
+ if (state == ST_DISPLAY_OFF)
+ dp_display_host_init(dp_display);
dp_display_enable(dp_display, 0);
@@ -1377,21 +1443,16 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
dp_display_unprepare(dp);
}
- dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT);
-
- if (state == ST_SUSPEND_PENDING)
+ /* manual kick off plug event to train link */
+ if (state == ST_DISPLAY_OFF)
dp_add_event(dp_display, EV_IRQ_HPD_INT, 0, 0);
/* completed connection */
- atomic_set(&dp_display->hpd_state, ST_CONNECTED);
+ dp_display->hpd_state = ST_CONNECTED;
mutex_unlock(&dp_display->event_mutex);
return rc;
-
-resume_done:
- dp_display_wait4resume_done(dp_display);
- return rc;
}
int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder)
@@ -1415,20 +1476,21 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder)
mutex_lock(&dp_display->event_mutex);
+ /* stop sentinel checking */
+ dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT);
+
dp_display_disable(dp_display, 0);
rc = dp_display_unprepare(dp);
if (rc)
DRM_ERROR("DP display unprepare failed, rc=%d\n", rc);
- dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT);
-
- state = atomic_read(&dp_display->hpd_state);
+ state = dp_display->hpd_state;
if (state == ST_DISCONNECT_PENDING) {
/* completed disconnection */
- atomic_set(&dp_display->hpd_state, ST_DISCONNECTED);
+ dp_display->hpd_state = ST_DISCONNECTED;
} else {
- atomic_set(&dp_display->hpd_state, ST_SUSPEND_PENDING);
+ dp_display->hpd_state = ST_DISPLAY_OFF;
}
mutex_unlock(&dp_display->event_mutex);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index c811da515fb3..be986da78c4a 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -773,7 +773,8 @@ static int dp_link_process_link_training_request(struct dp_link_private *link)
link->request.test_lane_count);
link->dp_link.link_params.num_lanes = link->request.test_lane_count;
- link->dp_link.link_params.rate = link->request.test_link_rate;
+ link->dp_link.link_params.rate =
+ drm_dp_bw_code_to_link_rate(link->request.test_link_rate);
return 0;
}
@@ -869,6 +870,9 @@ static int dp_link_parse_vx_px(struct dp_link_private *link)
drm_dp_get_adjust_request_voltage(link->link_status, 0);
link->dp_link.phy_params.p_level =
drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0);
+
+ link->dp_link.phy_params.p_level >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
+
DRM_DEBUG_DP("Requested: v_level = 0x%x, p_level = 0x%x\n",
link->dp_link.phy_params.v_level,
link->dp_link.phy_params.p_level);
@@ -911,7 +915,8 @@ static int dp_link_process_phy_test_pattern_request(
link->request.test_lane_count);
link->dp_link.link_params.num_lanes = link->request.test_lane_count;
- link->dp_link.link_params.rate = link->request.test_link_rate;
+ link->dp_link.link_params.rate =
+ drm_dp_bw_code_to_link_rate(link->request.test_link_rate);
ret = dp_link_parse_vx_px(link);
@@ -939,22 +944,20 @@ static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
*/
static int dp_link_process_link_status_update(struct dp_link_private *link)
{
- if (!(get_link_status(link->link_status,
- DP_LANE_ALIGN_STATUS_UPDATED) &
- DP_LINK_STATUS_UPDATED) ||
- (drm_dp_clock_recovery_ok(link->link_status,
- link->dp_link.link_params.num_lanes) &&
- drm_dp_channel_eq_ok(link->link_status,
- link->dp_link.link_params.num_lanes)))
- return -EINVAL;
+ bool channel_eq_done = drm_dp_channel_eq_ok(link->link_status,
+ link->dp_link.link_params.num_lanes);
- DRM_DEBUG_DP("channel_eq_done = %d, clock_recovery_done = %d\n",
- drm_dp_clock_recovery_ok(link->link_status,
- link->dp_link.link_params.num_lanes),
- drm_dp_clock_recovery_ok(link->link_status,
- link->dp_link.link_params.num_lanes));
+ bool clock_recovery_done = drm_dp_clock_recovery_ok(link->link_status,
+ link->dp_link.link_params.num_lanes);
- return 0;
+ DRM_DEBUG_DP("channel_eq_done = %d, clock_recovery_done = %d\n",
+ channel_eq_done, clock_recovery_done);
+
+ if (channel_eq_done && clock_recovery_done)
+ return -EINVAL;
+
+
+ return 0;
}
/**
@@ -1156,6 +1159,12 @@ int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
return 0;
}
+void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link)
+{
+ dp_link->phy_params.v_level = 0;
+ dp_link->phy_params.p_level = 0;
+}
+
u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)
{
u32 tbd;
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 49811b6221e5..9dd4dd926530 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -135,6 +135,7 @@ static inline u32 dp_link_bit_depth_to_bpc(u32 tbd)
}
}
+void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link);
u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp);
int dp_link_process_request(struct dp_link *dp_link);
int dp_link_get_colorimetry_config(struct dp_link *dp_link);
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 18cec4fc5e0b..97dca3e378b7 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -196,6 +196,11 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
&panel->aux->ddc);
if (!dp_panel->edid) {
DRM_ERROR("panel edid read failed\n");
+ /* check edid read fail is due to unplug */
+ if (!dp_catalog_link_is_connected(panel->catalog)) {
+ rc = -ETIMEDOUT;
+ goto end;
+ }
/* fail safe edid */
mutex_lock(&connector->dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c
index 17c1fc6a2d44..9c4ea00a5f2a 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -8,12 +8,14 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regulator/consumer.h>
+#include <linux/pm_opp.h>
#include "dp_power.h"
#include "msm_drv.h"
struct dp_power_private {
struct dp_parser *parser;
struct platform_device *pdev;
+ struct device *dev;
struct clk *link_clk_src;
struct clk *pixel_provider;
struct clk *link_provider;
@@ -148,18 +150,51 @@ static int dp_power_clk_deinit(struct dp_power_private *power)
return 0;
}
+static int dp_power_clk_set_link_rate(struct dp_power_private *power,
+ struct dss_clk *clk_arry, int num_clk, int enable)
+{
+ u32 rate;
+ int i, rc = 0;
+
+ for (i = 0; i < num_clk; i++) {
+ if (clk_arry[i].clk) {
+ if (clk_arry[i].type == DSS_CLK_PCLK) {
+ if (enable)
+ rate = clk_arry[i].rate;
+ else
+ rate = 0;
+
+ rc = dev_pm_opp_set_rate(power->dev, rate);
+ if (rc)
+ break;
+ }
+
+ }
+ }
+ return rc;
+}
+
static int dp_power_clk_set_rate(struct dp_power_private *power,
enum dp_pm_type module, bool enable)
{
int rc = 0;
struct dss_module_power *mp = &power->parser->mp[module];
- if (enable) {
- rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
+ if (module == DP_CTRL_PM) {
+ rc = dp_power_clk_set_link_rate(power, mp->clk_config, mp->num_clk, enable);
if (rc) {
- DRM_ERROR("failed to set clks rate.\n");
+ DRM_ERROR("failed to set link clks rate\n");
return rc;
}
+ } else {
+
+ if (enable) {
+ rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
+ if (rc) {
+ DRM_ERROR("failed to set clks rate\n");
+ return rc;
+ }
+ }
}
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
@@ -349,7 +384,7 @@ int dp_power_deinit(struct dp_power *dp_power)
return 0;
}
-struct dp_power *dp_power_get(struct dp_parser *parser)
+struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
{
struct dp_power_private *power;
struct dp_power *dp_power;
@@ -365,6 +400,7 @@ struct dp_power *dp_power_get(struct dp_parser *parser)
power->parser = parser;
power->pdev = parser->pdev;
+ power->dev = dev;
dp_power = &power->dp_power;
diff --git a/drivers/gpu/drm/msm/dp/dp_power.h b/drivers/gpu/drm/msm/dp/dp_power.h
index 76743d755833..7d0327bbc0d5 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.h
+++ b/drivers/gpu/drm/msm/dp/dp_power.h
@@ -102,6 +102,6 @@ void dp_power_client_deinit(struct dp_power *power);
* methods to be called by the client to configure the power related
* modueles.
*/
-struct dp_power *dp_power_get(struct dp_parser *parser);
+struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser);
#endif /* _DP_POWER_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 43042ff90a19..268602803d9a 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -32,6 +32,8 @@
#define DP_DP_IRQ_HPD_INT_ACK (0x00000002)
#define DP_DP_HPD_REPLUG_INT_ACK (0x00000004)
#define DP_DP_HPD_UNPLUG_INT_ACK (0x00000008)
+#define DP_DP_HPD_STATE_STATUS_BITS_MASK (0x0000000F)
+#define DP_DP_HPD_STATE_STATUS_BITS_SHIFT (0x1C)
#define REG_DP_DP_HPD_INT_MASK (0x0000000C)
#define DP_DP_HPD_PLUG_INT_MASK (0x00000001)