aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/qualcomm/sc7280/display/edp_ctrl.c287
1 files changed, 151 insertions, 136 deletions
diff --git a/src/soc/qualcomm/sc7280/display/edp_ctrl.c b/src/soc/qualcomm/sc7280/display/edp_ctrl.c
index 0bc1fe4964..7ec450224f 100644
--- a/src/soc/qualcomm/sc7280/display/edp_ctrl.c
+++ b/src/soc/qualcomm/sc7280/display/edp_ctrl.c
@@ -739,7 +739,7 @@ static int edp_link_rate_down_shift(struct edp_ctrl *ctrl, uint8_t *dpcd)
ctrl->link_rate_khz = link_rate;
ctrl->link_rate = link_rate / 27000;
printk(BIOS_INFO, "new rate=0x%x\n", ctrl->link_rate_khz);
-}
+ }
return ret;
}
@@ -916,7 +916,7 @@ static void edp_ctrl_config_misc(struct edp_ctrl *ctrl)
write32(&edp_lclk->misc1_misc0, misc_val);
}
-static void edp_ctrl_pixel_clock_dividers(struct edp_ctrl *ctrl,
+static int edp_ctrl_pixel_clock_dividers(struct edp_ctrl *ctrl,
uint32_t *pixel_m, uint32_t *pixel_n)
{
uint32_t pixel_div = 0, dispcc_input_rate;
@@ -924,14 +924,16 @@ static void edp_ctrl_pixel_clock_dividers(struct edp_ctrl *ctrl,
uint8_t rate = ctrl->link_rate;
uint32_t stream_rate_khz = ctrl->pixel_rate;
- if (rate == DP_LINK_BW_8_1)
+ if (rate == DP_LINK_BW_8_1) {
pixel_div = 6;
- else if (rate == DP_LINK_BW_1_62 || rate == DP_LINK_BW_2_7)
+ } else if (rate == DP_LINK_BW_1_62 || rate == DP_LINK_BW_2_7) {
pixel_div = 2;
- else if (rate == DP_LINK_BW_5_4)
+ } else if (rate == DP_LINK_BW_5_4) {
pixel_div = 4;
- else
+ } else {
printk(BIOS_ERR, "Invalid pixel mux divider\n");
+ return -1;
+ }
dispcc_input_rate = (ctrl->link_rate_khz * 10) / pixel_div;
@@ -940,16 +942,20 @@ static void edp_ctrl_pixel_clock_dividers(struct edp_ctrl *ctrl,
(unsigned long)(1 << 16) - 1, &den, &num);
*pixel_m = num;
*pixel_n = den;
+
+ return 0;
}
-static void edp_ctrl_config_msa(struct edp_ctrl *ctrl)
+static int edp_ctrl_config_msa(struct edp_ctrl *ctrl)
{
uint32_t pixel_m, pixel_n;
uint32_t mvid, nvid;
u32 const nvid_fixed = 0x8000;
uint8_t rate = ctrl->link_rate;
- edp_ctrl_pixel_clock_dividers(ctrl, &pixel_m, &pixel_n);
+ if (edp_ctrl_pixel_clock_dividers(ctrl, &pixel_m, &pixel_n) < 0)
+ return -1;
+
pixel_n = ~(pixel_n - pixel_m);
pixel_n = pixel_n & 0xFFFF;
mvid = (pixel_m & 0xFFFF) * 5;
@@ -973,6 +979,8 @@ static void edp_ctrl_config_msa(struct edp_ctrl *ctrl)
write32(&edp_lclk->software_mvid, mvid);
write32(&edp_lclk->software_nvid, nvid);
write32(&edp_p0clk->dsc_dto, 0x0);
+
+ return 0;
}
static void tu_valid_boundary_calc(struct tu_algo_data *tu)
@@ -1070,7 +1078,7 @@ static void tu_valid_boundary_calc(struct tu_algo_data *tu)
static void edp_ctrl_calc_tu(struct edp_ctrl *ctrl, struct edid *edid,
struct edp_ctrl_tu *tu_table)
{
- struct tu_algo_data *tu = NULL;
+ struct tu_algo_data tu;
int64_t f = 100000;
int64_t LCLK_FAST_SKEW_fp = (6 * f) / 1000; /* 0.0006 */
uint8_t DP_BRUTE_FORCE = 1;
@@ -1081,156 +1089,150 @@ static void edp_ctrl_calc_tu(struct edp_ctrl *ctrl, struct edid *edid,
int EXTRA_PIXCLK_CYCLE_DELAY = 4;
int64_t temp = 0;
int64_t temp_fp = 0;
- uint32_t async_en = 0;
-
- tu = malloc(sizeof(*tu));
- memset(tu, 0, sizeof(*tu));
-
- tu->lclk_fp = ctrl->link_rate_khz * f;
- tu->lclk = ctrl->link_rate_khz;
- tu->pclk = edid->mode.pixel_clock;
- tu->pclk_fp = edid->mode.pixel_clock * f;
- tu->nlanes = ctrl->lane_cnt;
- tu->bpp = edid->panel_bits_per_pixel;
- tu->lwidth = edid->mode.ha;
- tu->lwidth_fp = tu->lwidth * f;
- tu->hbp_relative_to_pclk = edid->mode.hbl;
- tu->hbp_relative_to_pclk_fp = tu->hbp_relative_to_pclk * f;
- tu->err_fp = 1000 * f;
- tu->extra_buffer_margin = DIV_ROUND_UP(tu->lclk * 4, tu->pclk);
- tu->ratio_fp = ((int64_t)(tu->pclk_fp * tu->bpp) / 8) / (tu->nlanes * tu->lclk);
- tu->original_ratio_fp = tu->ratio_fp;
- tu->err_fp = 1000 * f;
- if (((tu->lwidth % tu->nlanes) != 0) && (tu->ratio_fp < f)) {
- tu->ratio_fp = (tu->ratio_fp * RATIO_SCALE_NUM) / RATIO_SCALE_DEN;
- tu->ratio_fp = tu->ratio_fp < f ? tu->ratio_fp : f;
+
+ tu.lclk_fp = ctrl->link_rate_khz * f;
+ tu.lclk = ctrl->link_rate_khz;
+ tu.pclk = edid->mode.pixel_clock;
+ tu.pclk_fp = edid->mode.pixel_clock * f;
+ tu.nlanes = ctrl->lane_cnt;
+ tu.bpp = edid->panel_bits_per_pixel;
+ tu.lwidth = edid->mode.ha;
+ tu.lwidth_fp = tu.lwidth * f;
+ tu.hbp_relative_to_pclk = edid->mode.hbl;
+ tu.hbp_relative_to_pclk_fp = tu.hbp_relative_to_pclk * f;
+ tu.err_fp = 1000 * f;
+ tu.extra_buffer_margin = DIV_ROUND_UP(tu.lclk * 4, tu.pclk);
+ tu.ratio_fp = ((int64_t)(tu.pclk_fp * tu.bpp) / 8) / (tu.nlanes * tu.lclk);
+ tu.original_ratio_fp = tu.ratio_fp;
+ tu.err_fp = 1000 * f;
+ if (((tu.lwidth % tu.nlanes) != 0) && (tu.ratio_fp < f)) {
+ tu.ratio_fp = (tu.ratio_fp * RATIO_SCALE_NUM) / RATIO_SCALE_DEN;
+ tu.ratio_fp = tu.ratio_fp < f ? tu.ratio_fp : f;
}
- tu->err_fp = 1000 * f;
- if (tu->ratio_fp > f)
- tu->ratio_fp = f;
+ tu.err_fp = 1000 * f;
+ if (tu.ratio_fp > f)
+ tu.ratio_fp = f;
- for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
- tu->new_err_fp = (tu->ratio_fp * tu->tu_size) -
- (((tu->ratio_fp * tu->tu_size) / f) * f);
- if (tu->new_err_fp > 0)
- tu->new_err_fp = f - tu->new_err_fp;
+ for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
+ tu.new_err_fp = (tu.ratio_fp * tu.tu_size) -
+ (((tu.ratio_fp * tu.tu_size) / f) * f);
+ if (tu.new_err_fp > 0)
+ tu.new_err_fp = f - tu.new_err_fp;
- if (tu->new_err_fp < tu->err_fp) {
- tu->err_fp = tu->new_err_fp;
- tu->tu_size_desired = tu->tu_size;
+ if (tu.new_err_fp < tu.err_fp) {
+ tu.err_fp = tu.new_err_fp;
+ tu.tu_size_desired = tu.tu_size;
}
}
- tu->tu_size_minus1 = tu->tu_size_desired - 1;
- tu->valid_boundary_link = DIV_ROUND_UP(tu->tu_size_desired * tu->ratio_fp, f);
- tu->num_tus = ((tu->bpp * tu->lwidth) / 8) / tu->valid_boundary_link;
- tu->even_distribution_legacy = tu->num_tus % tu->nlanes == 0 ? 1 : 0;
- tu->extra_bytes = DIV_ROUND_UP(((tu->num_tus + 1) * (tu->valid_boundary_link * f -
- tu->original_ratio_fp * tu->tu_size_desired)), f);
- tu->extra_pclk_cycles = DIV_ROUND_UP(tu->extra_bytes * 8, tu->bpp);
- tu->extra_pclk_cycles_in_link_clk = DIV_ROUND_UP(tu->extra_pclk_cycles * tu->lclk,
- tu->pclk);
- tu->filler_size = tu->tu_size_desired - tu->valid_boundary_link;
- tu->ratio_by_tu_fp = tu->ratio_fp * tu->tu_size_desired;
- tu->delay_start_link = tu->extra_pclk_cycles_in_link_clk + tu->filler_size +
- tu->extra_buffer_margin;
- tu->resulting_valid_fp = tu->valid_boundary_link * f;
- tu->TU_ratio_err_fp = (tu->resulting_valid_fp / tu->tu_size_desired) -
- tu->original_ratio_fp;
- tu->hbp_time_fp = (tu->hbp_relative_to_pclk_fp - HBLANK_MARGIN * f) / tu->pclk;
- tu->delay_start_time_fp = (tu->delay_start_link * f) / tu->lclk;
- if (tu->hbp_time_fp < tu->delay_start_time_fp)
- tu->min_hblank_violated = 1;
-
- tu->hactive_time_fp = (tu->lwidth * f) / tu->pclk;
- if (tu->hactive_time_fp < tu->delay_start_time_fp)
- tu->min_hblank_violated = 1;
-
- tu->delay_start_time_fp = 0;
+ tu.tu_size_minus1 = tu.tu_size_desired - 1;
+ tu.valid_boundary_link = DIV_ROUND_UP(tu.tu_size_desired * tu.ratio_fp, f);
+ tu.num_tus = ((tu.bpp * tu.lwidth) / 8) / tu.valid_boundary_link;
+ tu.even_distribution_legacy = tu.num_tus % tu.nlanes == 0 ? 1 : 0;
+ tu.extra_bytes = DIV_ROUND_UP(((tu.num_tus + 1) * (tu.valid_boundary_link * f -
+ tu.original_ratio_fp * tu.tu_size_desired)), f);
+ tu.extra_pclk_cycles = DIV_ROUND_UP(tu.extra_bytes * 8, tu.bpp);
+ tu.extra_pclk_cycles_in_link_clk = DIV_ROUND_UP(tu.extra_pclk_cycles * tu.lclk,
+ tu.pclk);
+ tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
+ tu.ratio_by_tu_fp = tu.ratio_fp * tu.tu_size_desired;
+ tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk + tu.filler_size +
+ tu.extra_buffer_margin;
+ tu.resulting_valid_fp = tu.valid_boundary_link * f;
+ tu.TU_ratio_err_fp = (tu.resulting_valid_fp / tu.tu_size_desired) -
+ tu.original_ratio_fp;
+ tu.hbp_time_fp = (tu.hbp_relative_to_pclk_fp - HBLANK_MARGIN * f) / tu.pclk;
+ tu.delay_start_time_fp = (tu.delay_start_link * f) / tu.lclk;
+ if (tu.hbp_time_fp < tu.delay_start_time_fp)
+ tu.min_hblank_violated = 1;
+
+ tu.hactive_time_fp = (tu.lwidth * f) / tu.pclk;
+ if (tu.hactive_time_fp < tu.delay_start_time_fp)
+ tu.min_hblank_violated = 1;
+
+ tu.delay_start_time_fp = 0;
/* brute force */
- tu->delay_start_link_extra_pclk = EXTRA_PIXCLK_CYCLE_DELAY;
- tu->diff_abs_fp = tu->resulting_valid_fp - tu->ratio_by_tu_fp;
- if (tu->diff_abs_fp < 0)
- tu->diff_abs_fp = 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.delay_start_link_extra_pclk = EXTRA_PIXCLK_CYCLE_DELAY;
+ tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
+ if (tu.diff_abs_fp < 0)
+ tu.diff_abs_fp = 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) ||
(DP_BRUTE_FORCE == 1))) ||
- (tu->min_hblank_violated == 1)) {
+ (tu.min_hblank_violated == 1)) {
do {
- tu->err_fp = 1000 * f;
- tu->extra_buffer_margin = DIV_ROUND_UP(tu->lclk_fp *
- tu->delay_start_link_extra_pclk,
- tu->pclk_fp);
- tu->n_symbols = DIV_ROUND_UP(tu->bpp * tu->lwidth, 8);
- 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.err_fp = 1000 * f;
+ tu.extra_buffer_margin = DIV_ROUND_UP(tu.lclk_fp *
+ tu.delay_start_link_extra_pclk,
+ tu.pclk_fp);
+ tu.n_symbols = DIV_ROUND_UP(tu.bpp * tu.lwidth, 8);
+ 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_pclk--;
- } while (tu->boundary_moderation_en != true &&
- tu->boundary_mod_lower_err == 1 &&
- tu->delay_start_link_extra_pclk != 0);
-
- if (tu->boundary_moderation_en == true) {
- tu->resulting_valid_fp = f * (tu->upper_boundary_count *
- tu->valid_boundary_link +
- tu->lower_boundary_count *
- (tu->valid_boundary_link - 1));
- tu->resulting_valid_fp /= (tu->upper_boundary_count +
- tu->lower_boundary_count);
- tu->ratio_by_tu_fp = tu->original_ratio_fp * tu->tu_size_desired;
- tu->valid_lower_boundary_link = tu->valid_boundary_link - 1;
- tu->num_tus = ((tu->bpp / 8) * tu->lwidth_fp) / tu->resulting_valid_fp;
- tu->tu_size_minus1 = tu->tu_size_desired - 1;
- tu->even_distribution_BF = 1;
- tu->TU_ratio_err_fp = ((tu->tu_size_desired * f /
- tu->resulting_valid_fp) * f);
- tu->TU_ratio_err_fp -= tu->original_ratio_fp;
+ tu.delay_start_link_extra_pclk--;
+ } while (tu.boundary_moderation_en != true &&
+ tu.boundary_mod_lower_err == 1 &&
+ tu.delay_start_link_extra_pclk != 0);
+
+ if (tu.boundary_moderation_en == true) {
+ tu.resulting_valid_fp = f * (tu.upper_boundary_count *
+ tu.valid_boundary_link +
+ tu.lower_boundary_count *
+ (tu.valid_boundary_link - 1));
+ tu.resulting_valid_fp /= (tu.upper_boundary_count +
+ tu.lower_boundary_count);
+ tu.ratio_by_tu_fp = tu.original_ratio_fp * tu.tu_size_desired;
+ tu.valid_lower_boundary_link = tu.valid_boundary_link - 1;
+ tu.num_tus = ((tu.bpp / 8) * tu.lwidth_fp) / tu.resulting_valid_fp;
+ tu.tu_size_minus1 = tu.tu_size_desired - 1;
+ tu.even_distribution_BF = 1;
+ tu.TU_ratio_err_fp = ((tu.tu_size_desired * f /
+ tu.resulting_valid_fp) * f);
+ tu.TU_ratio_err_fp -= tu.original_ratio_fp;
}
}
- temp_fp = LCLK_FAST_SKEW_fp * tu->lwidth;
+ temp_fp = LCLK_FAST_SKEW_fp * tu.lwidth;
temp = DIV_ROUND_UP(temp_fp, f);
- temp_fp = ((tu->bpp * f / 8) / (tu->nlanes * tu->original_ratio_fp)) * f * temp;
+ temp_fp = ((tu.bpp * f / 8) / (tu.nlanes * tu.original_ratio_fp)) * f * temp;
temp = temp_fp / f;
- if (async_en)
- tu->delay_start_link += (int)temp;
- tu->delay_start_time_fp = (tu->delay_start_link * f) / tu->lclk;
+ tu.delay_start_time_fp = (tu.delay_start_link * f) / tu.lclk;
/* 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;
printk(BIOS_INFO, "TU: valid_boundary_link: %d\n",
- tu_table->valid_boundary_link);
+ tu_table->valid_boundary_link);
printk(BIOS_INFO, "TU: delay_start_link: %d\n",
- tu_table->delay_start_link);
+ tu_table->delay_start_link);
printk(BIOS_INFO, "TU: boundary_moderation_en: %d\n",
- tu_table->boundary_moderation_en);
+ tu_table->boundary_moderation_en);
printk(BIOS_INFO, "TU: valid_lower_boundary_link: %d\n",
- tu_table->valid_lower_boundary_link);
+ tu_table->valid_lower_boundary_link);
printk(BIOS_INFO, "TU: upper_boundary_count: %d\n",
- tu_table->upper_boundary_count);
+ tu_table->upper_boundary_count);
printk(BIOS_INFO, "TU: lower_boundary_count: %d\n",
- tu_table->lower_boundary_count);
+ tu_table->lower_boundary_count);
printk(BIOS_INFO, "TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
}
@@ -1356,7 +1358,7 @@ static int edp_ctrl_training(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *
return ret;
}
-static void edp_ctrl_on(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *dpcd)
+static int edp_ctrl_on(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *dpcd)
{
uint8_t value;
int ret;
@@ -1374,15 +1376,19 @@ static void edp_ctrl_on(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *dpcd)
/* DP_SET_POWER register is only available on DPCD v1.1 and later */
if (dpcd[DP_DPCD_REV] >= 0x11) {
ret = edp_aux_transfer(DP_SET_POWER, DP_AUX_NATIVE_READ, &value, 1);
- if (ret < 0)
+ if (ret < 0) {
printk(BIOS_ERR, "ERROR: edp native read failure\n");
+ return -1;
+ }
value &= ~DP_SET_POWER_MASK;
value |= DP_SET_POWER_D0;
ret = edp_aux_transfer(DP_SET_POWER, DP_AUX_NATIVE_WRITE, &value, 1);
- if (ret < 0)
+ if (ret < 0) {
printk(BIOS_ERR, "ERROR: edp native read failure\n");
+ return -1;
+ }
/*
* According to the DP 1.1 specification, a "Sink Device must
@@ -1396,8 +1402,10 @@ static void edp_ctrl_on(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *dpcd)
edp_ctrl_link_enable(ctrl, edid, dpcd, 1);
/* Start link training */
ret = edp_ctrl_training(ctrl, edid, dpcd);
- if (ret != EDP_TRAIN_SUCCESS)
+ if (ret != EDP_TRAIN_SUCCESS) {
printk(BIOS_ERR, "ERROR: edp training failure\n");
+ return -1;
+ }
edp_train_pattern_set_write(0);
@@ -1408,10 +1416,15 @@ static void edp_ctrl_on(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *dpcd)
edp_config_ctrl(ctrl, dpcd);
edp_ctrl_config_misc(ctrl);
edp_ctrl_timing_cfg(edid);
- edp_ctrl_config_msa(ctrl);
+
+ if (edp_ctrl_config_msa(ctrl) < 0)
+ return -1;
+
edp_ctrl_config_TU(ctrl, edid);
edp_state_ctrl(SW_SEND_VIDEO);
edp_ctrl_irq_enable(0);
+
+ return 0;
}
static bool edp_ctrl_panel_connected(uint8_t *dpcd)
@@ -1441,7 +1454,9 @@ enum cb_err edp_ctrl_init(struct edid *edid)
mdss_clock_enable(GCC_EDP_CLKREF_EN);
if (edp_ctrl_panel_connected(dpcd) && edp_read_edid(edid) == 0) {
- edp_ctrl_on(&ctrl, edid, dpcd);
+ if (edp_ctrl_on(&ctrl, edid, dpcd) < 0)
+ return CB_ERR;
+
return CB_SUCCESS;
}