Rishabh Bhatnagar | e9a05bb | 2018-12-10 11:09:45 -0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2 | /* |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 3 | * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 4 | */ |
| 5 | |
| 6 | #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ |
| 7 | |
| 8 | #include "dp_panel.h" |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 9 | #include <drm/drm_fixed.h> |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 10 | |
| 11 | #define DP_KHZ_TO_HZ 1000 |
| 12 | #define DP_PANEL_DEFAULT_BPP 24 |
| 13 | #define DP_MAX_DS_PORT_COUNT 1 |
| 14 | |
| 15 | #define DPRX_FEATURE_ENUMERATION_LIST 0x2210 |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 16 | #define DPRX_EXTENDED_DPCD_FIELD 0x2200 |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 17 | #define VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED BIT(3) |
| 18 | #define VSC_EXT_VESA_SDP_SUPPORTED BIT(4) |
| 19 | #define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5) |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 20 | #define SEQ_INCREMENT_FOR_CHAINED_PACKETS BIT(6) |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 21 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 22 | enum dp_panel_hdr_pixel_encoding { |
| 23 | RGB, |
| 24 | YCbCr444, |
| 25 | YCbCr422, |
| 26 | YCbCr420, |
| 27 | YONLY, |
| 28 | RAW, |
| 29 | }; |
| 30 | |
| 31 | enum dp_panel_hdr_rgb_colorimetry { |
| 32 | sRGB, |
| 33 | RGB_WIDE_GAMUT_FIXED_POINT, |
| 34 | RGB_WIDE_GAMUT_FLOATING_POINT, |
| 35 | ADOBERGB, |
| 36 | DCI_P3, |
| 37 | CUSTOM_COLOR_PROFILE, |
| 38 | ITU_R_BT_2020_RGB, |
| 39 | }; |
| 40 | |
| 41 | enum dp_panel_hdr_dynamic_range { |
| 42 | VESA, |
| 43 | CEA, |
| 44 | }; |
| 45 | |
| 46 | enum dp_panel_hdr_content_type { |
| 47 | NOT_DEFINED, |
| 48 | GRAPHICS, |
| 49 | PHOTO, |
| 50 | VIDEO, |
| 51 | GAME, |
| 52 | }; |
| 53 | |
| 54 | enum dp_panel_hdr_state { |
| 55 | HDR_DISABLED, |
| 56 | HDR_ENABLED, |
| 57 | }; |
| 58 | |
| 59 | struct dp_panel_private { |
| 60 | struct device *dev; |
| 61 | struct dp_panel dp_panel; |
| 62 | struct dp_aux *aux; |
| 63 | struct dp_link *link; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 64 | struct dp_parser *parser; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 65 | struct dp_catalog_panel *catalog; |
| 66 | bool custom_edid; |
| 67 | bool custom_dpcd; |
| 68 | bool panel_on; |
| 69 | bool vsc_supported; |
| 70 | bool vscext_supported; |
| 71 | bool vscext_chaining_supported; |
| 72 | enum dp_panel_hdr_state hdr_state; |
| 73 | u8 spd_vendor_name[8]; |
| 74 | u8 spd_product_description[16]; |
| 75 | u8 major; |
| 76 | u8 minor; |
| 77 | }; |
| 78 | |
| 79 | static const struct dp_panel_info fail_safe = { |
| 80 | .h_active = 640, |
| 81 | .v_active = 480, |
| 82 | .h_back_porch = 48, |
| 83 | .h_front_porch = 16, |
| 84 | .h_sync_width = 96, |
| 85 | .h_active_low = 0, |
| 86 | .v_back_porch = 33, |
| 87 | .v_front_porch = 10, |
| 88 | .v_sync_width = 2, |
| 89 | .v_active_low = 0, |
| 90 | .h_skew = 0, |
| 91 | .refresh_rate = 60, |
| 92 | .pixel_clk_khz = 25200, |
| 93 | .bpp = 24, |
| 94 | }; |
| 95 | |
| 96 | /* OEM NAME */ |
| 97 | static const u8 vendor_name[8] = {81, 117, 97, 108, 99, 111, 109, 109}; |
| 98 | |
| 99 | /* MODEL NAME */ |
| 100 | static const u8 product_desc[16] = {83, 110, 97, 112, 100, 114, 97, 103, |
| 101 | 111, 110, 0, 0, 0, 0, 0, 0}; |
| 102 | |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 103 | struct dp_dhdr_maxpkt_calc_input { |
| 104 | u32 mdp_clk; |
| 105 | u32 lclk; |
| 106 | u32 pclk; |
| 107 | u32 h_active; |
| 108 | u32 nlanes; |
| 109 | s64 mst_target_sc; |
| 110 | bool mst_en; |
| 111 | bool fec_en; |
| 112 | }; |
| 113 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 114 | struct tu_algo_data { |
| 115 | s64 lclk_fp; |
| 116 | s64 pclk_fp; |
| 117 | s64 lwidth; |
| 118 | s64 lwidth_fp; |
| 119 | s64 hbp_relative_to_pclk; |
| 120 | s64 hbp_relative_to_pclk_fp; |
| 121 | int nlanes; |
| 122 | int bpp; |
| 123 | int pixelEnc; |
| 124 | int dsc_en; |
| 125 | int async_en; |
| 126 | int bpc; |
| 127 | |
| 128 | uint delay_start_link_extra_pixclk; |
| 129 | int extra_buffer_margin; |
| 130 | s64 ratio_fp; |
| 131 | s64 original_ratio_fp; |
| 132 | |
| 133 | s64 err_fp; |
| 134 | s64 n_err_fp; |
| 135 | s64 n_n_err_fp; |
| 136 | int tu_size; |
| 137 | int tu_size_desired; |
| 138 | int tu_size_minus1; |
| 139 | |
| 140 | int valid_boundary_link; |
| 141 | s64 resulting_valid_fp; |
| 142 | s64 total_valid_fp; |
| 143 | s64 effective_valid_fp; |
| 144 | s64 effective_valid_recorded_fp; |
| 145 | int n_tus; |
| 146 | int n_tus_per_lane; |
| 147 | int paired_tus; |
| 148 | int remainder_tus; |
| 149 | int remainder_tus_upper; |
| 150 | int remainder_tus_lower; |
| 151 | int extra_bytes; |
| 152 | int filler_size; |
| 153 | int delay_start_link; |
| 154 | |
| 155 | int extra_pclk_cycles; |
| 156 | int extra_pclk_cycles_in_link_clk; |
| 157 | s64 ratio_by_tu_fp; |
| 158 | s64 average_valid2_fp; |
| 159 | int new_valid_boundary_link; |
| 160 | int remainder_symbols_exist; |
| 161 | int n_symbols; |
| 162 | s64 n_remainder_symbols_per_lane_fp; |
| 163 | s64 last_partial_tu_fp; |
| 164 | s64 TU_ratio_err_fp; |
| 165 | |
| 166 | int n_tus_incl_last_incomplete_tu; |
| 167 | int extra_pclk_cycles_tmp; |
| 168 | int extra_pclk_cycles_in_link_clk_tmp; |
| 169 | int extra_required_bytes_new_tmp; |
| 170 | int filler_size_tmp; |
| 171 | int lower_filler_size_tmp; |
| 172 | int delay_start_link_tmp; |
| 173 | |
| 174 | bool boundary_moderation_en; |
| 175 | int boundary_mod_lower_err; |
| 176 | int upper_boundary_count; |
| 177 | int lower_boundary_count; |
| 178 | int i_upper_boundary_count; |
| 179 | int i_lower_boundary_count; |
| 180 | int valid_lower_boundary_link; |
| 181 | int even_distribution_BF; |
| 182 | int even_distribution_legacy; |
| 183 | int even_distribution; |
| 184 | int min_hblank_violated; |
| 185 | s64 delay_start_time_fp; |
| 186 | s64 hbp_time_fp; |
| 187 | s64 hactive_time_fp; |
| 188 | s64 diff_abs_fp; |
| 189 | |
| 190 | s64 ratio; |
| 191 | }; |
| 192 | |
| 193 | static int _tu_param_compare(s64 a, s64 b) |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 194 | { |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 195 | u32 a_int, a_frac, a_sign; |
| 196 | u32 b_int, b_frac, b_sign; |
| 197 | s64 a_temp, b_temp, minus_1; |
| 198 | |
| 199 | if (a == b) |
| 200 | return 0; |
| 201 | |
| 202 | minus_1 = drm_fixp_from_fraction(-1, 1); |
| 203 | |
| 204 | a_int = (a >> 32) & 0x7FFFFFFF; |
| 205 | a_frac = a & 0xFFFFFFFF; |
| 206 | a_sign = (a >> 32) & 0x80000000 ? 1 : 0; |
| 207 | |
| 208 | b_int = (b >> 32) & 0x7FFFFFFF; |
| 209 | b_frac = b & 0xFFFFFFFF; |
| 210 | b_sign = (b >> 32) & 0x80000000 ? 1 : 0; |
| 211 | |
| 212 | if (a_sign > b_sign) |
| 213 | return 2; |
| 214 | else if (b_sign > a_sign) |
| 215 | return 1; |
| 216 | |
| 217 | if (!a_sign && !b_sign) { /* positive */ |
| 218 | if (a > b) |
| 219 | return 1; |
| 220 | else |
| 221 | return 2; |
| 222 | } else { /* negative */ |
| 223 | a_temp = drm_fixp_mul(a, minus_1); |
| 224 | b_temp = drm_fixp_mul(b, minus_1); |
| 225 | |
| 226 | if (a_temp > b_temp) |
| 227 | return 2; |
| 228 | else |
| 229 | return 1; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 230 | } |
| 231 | } |
| 232 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 233 | static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, |
| 234 | struct tu_algo_data *tu) |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 235 | { |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 236 | int nlanes = in->nlanes; |
| 237 | int dsc_num_slices = in->num_of_dsc_slices; |
| 238 | int dsc_num_bytes = 0; |
| 239 | int numerator; |
| 240 | s64 pclk_dsc_fp; |
| 241 | s64 dwidth_dsc_fp; |
| 242 | s64 hbp_dsc_fp; |
| 243 | s64 overhead_dsc; |
| 244 | |
| 245 | int tot_num_eoc_symbols = 0; |
| 246 | int tot_num_hor_bytes = 0; |
| 247 | int tot_num_dummy_bytes = 0; |
| 248 | int dwidth_dsc_bytes = 0; |
| 249 | int eoc_bytes = 0; |
| 250 | |
| 251 | s64 temp1_fp, temp2_fp, temp3_fp; |
| 252 | |
| 253 | tu->lclk_fp = drm_fixp_from_fraction(in->lclk, 1); |
| 254 | tu->pclk_fp = drm_fixp_from_fraction(in->pclk_khz, 1000); |
| 255 | tu->lwidth = in->hactive; |
| 256 | tu->hbp_relative_to_pclk = in->hporch; |
| 257 | tu->nlanes = in->nlanes; |
| 258 | tu->bpp = in->bpp; |
| 259 | tu->pixelEnc = in->pixel_enc; |
| 260 | tu->dsc_en = in->dsc_en; |
| 261 | tu->async_en = in->async_en; |
| 262 | tu->lwidth_fp = drm_fixp_from_fraction(in->hactive, 1); |
| 263 | tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1); |
| 264 | |
| 265 | if (tu->pixelEnc == 420) { |
| 266 | temp1_fp = drm_fixp_from_fraction(2, 1); |
| 267 | tu->pclk_fp = drm_fixp_div(tu->pclk_fp, temp1_fp); |
| 268 | tu->lwidth_fp = drm_fixp_div(tu->lwidth_fp, temp1_fp); |
| 269 | tu->hbp_relative_to_pclk_fp = |
| 270 | drm_fixp_div(tu->hbp_relative_to_pclk_fp, 2); |
| 271 | } |
| 272 | |
| 273 | if (tu->pixelEnc == 422) { |
| 274 | switch (tu->bpp) { |
| 275 | case 24: |
| 276 | tu->bpp = 16; |
| 277 | tu->bpc = 8; |
| 278 | break; |
| 279 | case 30: |
| 280 | tu->bpp = 20; |
| 281 | tu->bpc = 10; |
| 282 | break; |
| 283 | default: |
| 284 | tu->bpp = 16; |
| 285 | tu->bpc = 8; |
| 286 | break; |
| 287 | } |
| 288 | } else |
| 289 | tu->bpc = tu->bpp/3; |
| 290 | |
| 291 | if (!in->dsc_en) |
| 292 | goto fec_check; |
| 293 | |
| 294 | temp1_fp = drm_fixp_from_fraction(in->compress_ratio, 100); |
| 295 | temp2_fp = drm_fixp_from_fraction(in->bpp, 1); |
| 296 | temp3_fp = drm_fixp_div(temp2_fp, temp1_fp); |
| 297 | temp2_fp = drm_fixp_mul(tu->lwidth_fp, temp3_fp); |
| 298 | |
| 299 | temp1_fp = drm_fixp_from_fraction(8, 1); |
| 300 | temp3_fp = drm_fixp_div(temp2_fp, temp1_fp); |
| 301 | |
| 302 | numerator = drm_fixp2int(temp3_fp); |
| 303 | |
| 304 | dsc_num_bytes = numerator / dsc_num_slices; |
| 305 | eoc_bytes = dsc_num_bytes % nlanes; |
| 306 | tot_num_eoc_symbols = nlanes * dsc_num_slices; |
| 307 | tot_num_hor_bytes = dsc_num_bytes * dsc_num_slices; |
| 308 | tot_num_dummy_bytes = (nlanes - eoc_bytes) * dsc_num_slices; |
| 309 | |
| 310 | if (dsc_num_bytes == 0) |
| 311 | pr_info("incorrect no of bytes per slice=%d\n", dsc_num_bytes); |
| 312 | |
| 313 | dwidth_dsc_bytes = (tot_num_hor_bytes + |
| 314 | tot_num_eoc_symbols + |
| 315 | (eoc_bytes == 0 ? 0 : tot_num_dummy_bytes)); |
| 316 | overhead_dsc = dwidth_dsc_bytes / tot_num_hor_bytes; |
| 317 | |
| 318 | dwidth_dsc_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, 3); |
| 319 | |
| 320 | temp2_fp = drm_fixp_mul(tu->pclk_fp, dwidth_dsc_fp); |
| 321 | temp1_fp = drm_fixp_div(temp2_fp, tu->lwidth_fp); |
| 322 | pclk_dsc_fp = temp1_fp; |
| 323 | |
| 324 | temp1_fp = drm_fixp_div(pclk_dsc_fp, tu->pclk_fp); |
| 325 | temp2_fp = drm_fixp_mul(tu->hbp_relative_to_pclk_fp, temp1_fp); |
| 326 | hbp_dsc_fp = temp2_fp; |
| 327 | |
| 328 | /* output */ |
| 329 | tu->pclk_fp = pclk_dsc_fp; |
| 330 | tu->lwidth_fp = dwidth_dsc_fp; |
| 331 | tu->hbp_relative_to_pclk_fp = hbp_dsc_fp; |
| 332 | |
| 333 | fec_check: |
| 334 | if (in->fec_en) { |
| 335 | temp1_fp = drm_fixp_from_fraction(976, 1000); /* 0.976 */ |
| 336 | tu->lclk_fp = drm_fixp_mul(tu->lclk_fp, temp1_fp); |
| 337 | } |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 338 | } |
| 339 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 340 | static void _tu_valid_boundary_calc(struct tu_algo_data *tu) |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 341 | { |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 342 | s64 temp1_fp, temp2_fp, temp, temp1, temp2; |
| 343 | int compare_result_1, compare_result_2, compare_result_3; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 344 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 345 | temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); |
| 346 | temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); |
| 347 | |
| 348 | tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp); |
| 349 | |
| 350 | temp = (tu->i_upper_boundary_count * |
| 351 | tu->new_valid_boundary_link + |
| 352 | tu->i_lower_boundary_count * |
| 353 | (tu->new_valid_boundary_link-1)); |
| 354 | tu->average_valid2_fp = drm_fixp_from_fraction(temp, |
| 355 | (tu->i_upper_boundary_count + |
| 356 | tu->i_lower_boundary_count)); |
| 357 | |
| 358 | temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); |
| 359 | temp2_fp = tu->lwidth_fp; |
| 360 | temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); |
| 361 | temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp); |
| 362 | tu->n_tus = drm_fixp2int(temp2_fp); |
| 363 | if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000) |
| 364 | tu->n_tus += 1; |
| 365 | |
| 366 | temp1_fp = drm_fixp_from_fraction(tu->n_tus, 1); |
| 367 | temp2_fp = drm_fixp_mul(temp1_fp, tu->average_valid2_fp); |
| 368 | temp1_fp = drm_fixp_from_fraction(tu->n_symbols, 1); |
| 369 | temp2_fp = temp1_fp - temp2_fp; |
| 370 | temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1); |
| 371 | temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); |
| 372 | tu->n_remainder_symbols_per_lane_fp = temp2_fp; |
| 373 | |
| 374 | temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); |
| 375 | tu->last_partial_tu_fp = |
| 376 | drm_fixp_div(tu->n_remainder_symbols_per_lane_fp, |
| 377 | temp1_fp); |
| 378 | |
| 379 | if (tu->n_remainder_symbols_per_lane_fp != 0) |
| 380 | tu->remainder_symbols_exist = 1; |
| 381 | else |
| 382 | tu->remainder_symbols_exist = 0; |
| 383 | |
| 384 | temp1_fp = drm_fixp_from_fraction(tu->n_tus, tu->nlanes); |
| 385 | tu->n_tus_per_lane = drm_fixp2int(temp1_fp); |
| 386 | |
| 387 | tu->paired_tus = (int)((tu->n_tus_per_lane) / |
| 388 | (tu->i_upper_boundary_count + |
| 389 | tu->i_lower_boundary_count)); |
| 390 | |
| 391 | tu->remainder_tus = tu->n_tus_per_lane - tu->paired_tus * |
| 392 | (tu->i_upper_boundary_count + |
| 393 | tu->i_lower_boundary_count); |
| 394 | |
| 395 | if ((tu->remainder_tus - tu->i_upper_boundary_count) > 0) { |
| 396 | tu->remainder_tus_upper = tu->i_upper_boundary_count; |
| 397 | tu->remainder_tus_lower = tu->remainder_tus - |
| 398 | tu->i_upper_boundary_count; |
| 399 | } else { |
| 400 | tu->remainder_tus_upper = tu->remainder_tus; |
| 401 | tu->remainder_tus_lower = 0; |
| 402 | } |
| 403 | |
| 404 | temp = tu->paired_tus * (tu->i_upper_boundary_count * |
| 405 | tu->new_valid_boundary_link + |
| 406 | tu->i_lower_boundary_count * |
| 407 | (tu->new_valid_boundary_link - 1)) + |
| 408 | (tu->remainder_tus_upper * |
| 409 | tu->new_valid_boundary_link) + |
| 410 | (tu->remainder_tus_lower * |
| 411 | (tu->new_valid_boundary_link - 1)); |
| 412 | tu->total_valid_fp = drm_fixp_from_fraction(temp, 1); |
| 413 | |
| 414 | if (tu->remainder_symbols_exist) { |
| 415 | temp1_fp = tu->total_valid_fp + |
| 416 | tu->n_remainder_symbols_per_lane_fp; |
| 417 | temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1); |
| 418 | temp2_fp = temp2_fp + tu->last_partial_tu_fp; |
| 419 | temp1_fp = drm_fixp_div(temp1_fp, temp2_fp); |
| 420 | } else { |
| 421 | temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1); |
| 422 | temp1_fp = drm_fixp_div(tu->total_valid_fp, temp2_fp); |
| 423 | } |
| 424 | tu->effective_valid_fp = temp1_fp; |
| 425 | |
| 426 | temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); |
| 427 | temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); |
| 428 | tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp; |
| 429 | |
| 430 | temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); |
| 431 | temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); |
| 432 | tu->n_err_fp = tu->average_valid2_fp - temp2_fp; |
| 433 | |
| 434 | tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0; |
| 435 | |
| 436 | temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); |
| 437 | temp2_fp = tu->lwidth_fp; |
| 438 | temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); |
| 439 | temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp); |
| 440 | |
| 441 | if (temp2_fp) |
| 442 | tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp); |
| 443 | else |
| 444 | tu->n_tus_incl_last_incomplete_tu = 0; |
| 445 | |
| 446 | temp1 = 0; |
| 447 | temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); |
| 448 | temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); |
| 449 | temp1_fp = tu->average_valid2_fp - temp2_fp; |
| 450 | temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1); |
| 451 | temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); |
| 452 | |
| 453 | if (temp1_fp) |
| 454 | temp1 = drm_fixp2int_ceil(temp1_fp); |
| 455 | |
| 456 | temp = tu->i_upper_boundary_count * tu->nlanes; |
| 457 | temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); |
| 458 | temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); |
| 459 | temp1_fp = drm_fixp_from_fraction(tu->new_valid_boundary_link, 1); |
| 460 | temp2_fp = temp1_fp - temp2_fp; |
| 461 | temp1_fp = drm_fixp_from_fraction(temp, 1); |
| 462 | temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); |
| 463 | |
| 464 | if (temp2_fp) |
| 465 | temp2 = drm_fixp2int_ceil(temp2_fp); |
| 466 | else |
| 467 | temp2 = 0; |
| 468 | tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2); |
| 469 | |
| 470 | temp1_fp = drm_fixp_from_fraction(8, tu->bpp); |
| 471 | temp2_fp = drm_fixp_from_fraction( |
| 472 | tu->extra_required_bytes_new_tmp, 1); |
| 473 | temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); |
| 474 | |
| 475 | if (temp1_fp) |
| 476 | tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp); |
| 477 | else |
| 478 | tu->extra_pclk_cycles_tmp = 0; |
| 479 | |
| 480 | temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1); |
| 481 | temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); |
| 482 | temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); |
| 483 | |
| 484 | if (temp1_fp) |
| 485 | tu->extra_pclk_cycles_in_link_clk_tmp = |
| 486 | drm_fixp2int_ceil(temp1_fp); |
| 487 | else |
| 488 | tu->extra_pclk_cycles_in_link_clk_tmp = 0; |
| 489 | |
| 490 | tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link; |
| 491 | |
| 492 | tu->lower_filler_size_tmp = tu->filler_size_tmp + 1; |
| 493 | |
| 494 | tu->delay_start_link_tmp = tu->extra_pclk_cycles_in_link_clk_tmp + |
| 495 | tu->lower_filler_size_tmp + |
| 496 | tu->extra_buffer_margin; |
| 497 | |
| 498 | temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1); |
| 499 | tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp); |
| 500 | |
| 501 | compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp); |
| 502 | if (compare_result_1 == 2) |
| 503 | compare_result_1 = 1; |
| 504 | else |
| 505 | compare_result_1 = 0; |
| 506 | |
| 507 | compare_result_2 = _tu_param_compare(tu->n_n_err_fp, tu->err_fp); |
| 508 | if (compare_result_2 == 2) |
| 509 | compare_result_2 = 1; |
| 510 | else |
| 511 | compare_result_2 = 0; |
| 512 | |
| 513 | compare_result_3 = _tu_param_compare(tu->hbp_time_fp, |
| 514 | tu->delay_start_time_fp); |
| 515 | if (compare_result_3 == 2) |
| 516 | compare_result_3 = 0; |
| 517 | else |
| 518 | compare_result_3 = 1; |
| 519 | |
| 520 | if (((tu->even_distribution == 1) || |
| 521 | ((tu->even_distribution_BF == 0) && |
| 522 | (tu->even_distribution_legacy == 0))) && |
| 523 | tu->n_err_fp >= 0 && tu->n_n_err_fp >= 0 && |
| 524 | compare_result_2 && |
| 525 | (compare_result_1 || (tu->min_hblank_violated == 1)) && |
| 526 | (tu->new_valid_boundary_link - 1) > 0 && |
| 527 | compare_result_3 && |
| 528 | (tu->delay_start_link_tmp <= 1023)) { |
| 529 | tu->upper_boundary_count = tu->i_upper_boundary_count; |
| 530 | tu->lower_boundary_count = tu->i_lower_boundary_count; |
| 531 | tu->err_fp = tu->n_n_err_fp; |
| 532 | tu->boundary_moderation_en = true; |
| 533 | tu->tu_size_desired = tu->tu_size; |
| 534 | tu->valid_boundary_link = tu->new_valid_boundary_link; |
| 535 | tu->effective_valid_recorded_fp = tu->effective_valid_fp; |
| 536 | tu->even_distribution_BF = 1; |
| 537 | tu->delay_start_link = tu->delay_start_link_tmp; |
| 538 | } else if (tu->boundary_mod_lower_err == 0) { |
| 539 | compare_result_1 = _tu_param_compare(tu->n_n_err_fp, |
| 540 | tu->diff_abs_fp); |
| 541 | if (compare_result_1 == 2) |
| 542 | tu->boundary_mod_lower_err = 1; |
| 543 | } |
| 544 | } |
| 545 | |
Satya Rama Aditya Pinapala | 9310db7 | 2018-11-07 15:10:56 -0800 | [diff] [blame] | 546 | static void _dp_calc_boundary(struct tu_algo_data *tu) |
| 547 | { |
| 548 | |
| 549 | s64 temp1_fp = 0, temp2_fp = 0; |
| 550 | |
| 551 | do { |
| 552 | tu->err_fp = drm_fixp_from_fraction(1000, 1); |
| 553 | |
| 554 | temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); |
| 555 | temp2_fp = drm_fixp_from_fraction( |
| 556 | tu->delay_start_link_extra_pixclk, 1); |
| 557 | temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); |
| 558 | |
| 559 | if (temp1_fp) |
| 560 | tu->extra_buffer_margin = |
| 561 | drm_fixp2int_ceil(temp1_fp); |
| 562 | else |
| 563 | tu->extra_buffer_margin = 0; |
| 564 | |
| 565 | temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); |
| 566 | temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp); |
| 567 | |
| 568 | if (temp1_fp) |
| 569 | tu->n_symbols = drm_fixp2int_ceil(temp1_fp); |
| 570 | else |
| 571 | tu->n_symbols = 0; |
| 572 | |
| 573 | for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) { |
| 574 | for (tu->i_upper_boundary_count = 1; |
| 575 | tu->i_upper_boundary_count <= 15; |
| 576 | tu->i_upper_boundary_count++) { |
| 577 | for (tu->i_lower_boundary_count = 1; |
| 578 | tu->i_lower_boundary_count <= 15; |
| 579 | tu->i_lower_boundary_count++) { |
| 580 | _tu_valid_boundary_calc(tu); |
| 581 | } |
| 582 | } |
| 583 | } |
| 584 | tu->delay_start_link_extra_pixclk--; |
| 585 | } while (!tu->boundary_moderation_en && |
| 586 | tu->boundary_mod_lower_err == 1 && |
| 587 | tu->delay_start_link_extra_pixclk != 0); |
| 588 | } |
| 589 | |
| 590 | static void _dp_calc_extra_bytes(struct tu_algo_data *tu) |
| 591 | { |
| 592 | u64 temp = 0; |
| 593 | s64 temp1_fp = 0, temp2_fp = 0; |
| 594 | |
| 595 | temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1); |
| 596 | temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); |
| 597 | temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1); |
| 598 | temp2_fp = temp1_fp - temp2_fp; |
| 599 | temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1); |
| 600 | temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); |
| 601 | |
| 602 | temp = drm_fixp2int(temp2_fp); |
| 603 | if (temp && temp2_fp) |
| 604 | tu->extra_bytes = drm_fixp2int_ceil(temp2_fp); |
| 605 | else |
| 606 | tu->extra_bytes = 0; |
| 607 | |
| 608 | temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1); |
| 609 | temp2_fp = drm_fixp_from_fraction(8, tu->bpp); |
| 610 | temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); |
| 611 | |
| 612 | if (temp1_fp) |
| 613 | tu->extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp); |
| 614 | else |
| 615 | tu->extra_pclk_cycles = drm_fixp2int(temp1_fp); |
| 616 | |
| 617 | temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); |
| 618 | temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1); |
| 619 | temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); |
| 620 | |
| 621 | if (temp1_fp) |
| 622 | tu->extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp); |
| 623 | else |
| 624 | tu->extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp); |
| 625 | } |
| 626 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 627 | static void _dp_panel_calc_tu(struct dp_tu_calc_input *in, |
| 628 | struct dp_vc_tu_mapping_table *tu_table) |
| 629 | { |
| 630 | struct tu_algo_data tu; |
| 631 | int compare_result_1, compare_result_2; |
| 632 | u64 temp = 0; |
| 633 | s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0; |
| 634 | |
| 635 | s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */ |
| 636 | s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */ |
| 637 | s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */ |
| 638 | s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000); |
| 639 | |
| 640 | u8 DP_BRUTE_FORCE = 1; |
| 641 | s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */ |
| 642 | uint EXTRA_PIXCLK_CYCLE_DELAY = 4; |
| 643 | uint HBLANK_MARGIN = 4; |
| 644 | |
| 645 | memset(&tu, 0, sizeof(tu)); |
| 646 | |
| 647 | dp_panel_update_tu_timings(in, &tu); |
| 648 | |
| 649 | tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */ |
| 650 | |
| 651 | temp1_fp = drm_fixp_from_fraction(4, 1); |
| 652 | temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp); |
| 653 | temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp); |
| 654 | tu.extra_buffer_margin = drm_fixp2int_ceil(temp_fp); |
| 655 | |
| 656 | temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); |
| 657 | temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp); |
| 658 | temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); |
| 659 | temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); |
| 660 | tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp); |
| 661 | |
| 662 | tu.original_ratio_fp = tu.ratio_fp; |
| 663 | tu.boundary_moderation_en = false; |
| 664 | tu.upper_boundary_count = 0; |
| 665 | tu.lower_boundary_count = 0; |
| 666 | tu.i_upper_boundary_count = 0; |
| 667 | tu.i_lower_boundary_count = 0; |
| 668 | tu.valid_lower_boundary_link = 0; |
| 669 | tu.even_distribution_BF = 0; |
| 670 | tu.even_distribution_legacy = 0; |
| 671 | tu.even_distribution = 0; |
| 672 | tu.delay_start_time_fp = 0; |
| 673 | |
| 674 | tu.err_fp = drm_fixp_from_fraction(1000, 1); |
| 675 | tu.n_err_fp = 0; |
| 676 | tu.n_n_err_fp = 0; |
| 677 | |
| 678 | tu.ratio = drm_fixp2int(tu.ratio_fp); |
| 679 | temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); |
| 680 | temp2_fp = tu.lwidth_fp % temp1_fp; |
| 681 | if (temp2_fp != 0 && |
| 682 | !tu.ratio && tu.dsc_en == 0) { |
| 683 | tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp); |
| 684 | tu.ratio = drm_fixp2int(tu.ratio_fp); |
| 685 | if (tu.ratio) |
| 686 | tu.ratio_fp = drm_fixp_from_fraction(1, 1); |
| 687 | } |
| 688 | |
| 689 | if (tu.ratio > 1) |
| 690 | tu.ratio = 1; |
| 691 | |
| 692 | if (tu.ratio == 1) |
| 693 | goto tu_size_calc; |
| 694 | |
| 695 | compare_result_1 = _tu_param_compare(tu.ratio_fp, const_p49_fp); |
| 696 | if (!compare_result_1 || compare_result_1 == 1) |
| 697 | compare_result_1 = 1; |
| 698 | else |
| 699 | compare_result_1 = 0; |
| 700 | |
| 701 | compare_result_2 = _tu_param_compare(tu.ratio_fp, const_p56_fp); |
| 702 | if (!compare_result_2 || compare_result_2 == 2) |
| 703 | compare_result_2 = 1; |
| 704 | else |
| 705 | compare_result_2 = 0; |
| 706 | |
| 707 | if (tu.dsc_en && compare_result_1 && compare_result_2) { |
| 708 | HBLANK_MARGIN += 4; |
| 709 | pr_info("Info: increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN); |
| 710 | } |
| 711 | |
| 712 | tu_size_calc: |
| 713 | for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) { |
| 714 | temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1); |
| 715 | temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); |
| 716 | temp = drm_fixp2int_ceil(temp2_fp); |
| 717 | temp1_fp = drm_fixp_from_fraction(temp, 1); |
| 718 | tu.n_err_fp = temp1_fp - temp2_fp; |
| 719 | |
| 720 | if (tu.n_err_fp < tu.err_fp) { |
| 721 | tu.err_fp = tu.n_err_fp; |
| 722 | tu.tu_size_desired = tu.tu_size; |
| 723 | } |
| 724 | } |
| 725 | |
| 726 | tu.tu_size_minus1 = tu.tu_size_desired - 1; |
| 727 | |
| 728 | temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); |
| 729 | temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); |
| 730 | tu.valid_boundary_link = drm_fixp2int_ceil(temp2_fp); |
| 731 | |
| 732 | temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); |
| 733 | temp2_fp = tu.lwidth_fp; |
| 734 | temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp); |
| 735 | |
| 736 | temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1); |
| 737 | temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); |
| 738 | tu.n_tus = drm_fixp2int(temp2_fp); |
| 739 | if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000) |
| 740 | tu.n_tus += 1; |
| 741 | |
| 742 | tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0; |
| 743 | pr_info("Info: n_sym = %d, num_of_tus = %d\n", |
| 744 | tu.valid_boundary_link, tu.n_tus); |
| 745 | |
Satya Rama Aditya Pinapala | 9310db7 | 2018-11-07 15:10:56 -0800 | [diff] [blame] | 746 | _dp_calc_extra_bytes(&tu); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 747 | |
| 748 | tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link; |
| 749 | |
| 750 | temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); |
| 751 | tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); |
| 752 | |
| 753 | tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk + |
| 754 | tu.filler_size + tu.extra_buffer_margin; |
| 755 | |
| 756 | tu.resulting_valid_fp = |
| 757 | drm_fixp_from_fraction(tu.valid_boundary_link, 1); |
| 758 | |
| 759 | temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); |
| 760 | temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp); |
| 761 | tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; |
| 762 | |
| 763 | temp1_fp = drm_fixp_from_fraction(HBLANK_MARGIN, 1); |
| 764 | temp1_fp = tu.hbp_relative_to_pclk_fp - temp1_fp; |
| 765 | tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp); |
| 766 | |
| 767 | temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); |
| 768 | tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); |
| 769 | |
| 770 | compare_result_1 = _tu_param_compare(tu.hbp_time_fp, |
| 771 | tu.delay_start_time_fp); |
| 772 | if (compare_result_1 == 2) /* hbp_time_fp < delay_start_time_fp */ |
| 773 | tu.min_hblank_violated = 1; |
| 774 | |
| 775 | tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp); |
| 776 | |
| 777 | compare_result_2 = _tu_param_compare(tu.hactive_time_fp, |
| 778 | tu.delay_start_time_fp); |
| 779 | if (compare_result_2 == 2) |
| 780 | tu.min_hblank_violated = 1; |
| 781 | |
| 782 | tu.delay_start_time_fp = 0; |
| 783 | |
| 784 | /* brute force */ |
| 785 | |
| 786 | tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY; |
| 787 | tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp; |
| 788 | |
| 789 | temp = drm_fixp2int(tu.diff_abs_fp); |
| 790 | if (!temp && tu.diff_abs_fp <= 0xffff) |
| 791 | tu.diff_abs_fp = 0; |
| 792 | |
| 793 | /* if(diff_abs < 0) diff_abs *= -1 */ |
| 794 | if (tu.diff_abs_fp < 0) |
| 795 | tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1); |
| 796 | |
| 797 | tu.boundary_mod_lower_err = 0; |
| 798 | if ((tu.diff_abs_fp != 0 && |
| 799 | ((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) || |
| 800 | (tu.even_distribution_legacy == 0) || |
| 801 | (DP_BRUTE_FORCE == 1))) || |
| 802 | (tu.min_hblank_violated == 1)) { |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 803 | |
Satya Rama Aditya Pinapala | 9310db7 | 2018-11-07 15:10:56 -0800 | [diff] [blame] | 804 | _dp_calc_boundary(&tu); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 805 | |
| 806 | if (tu.boundary_moderation_en) { |
| 807 | temp1_fp = drm_fixp_from_fraction( |
| 808 | (tu.upper_boundary_count * |
| 809 | tu.valid_boundary_link + |
| 810 | tu.lower_boundary_count * |
| 811 | (tu.valid_boundary_link - 1)), 1); |
| 812 | temp2_fp = drm_fixp_from_fraction( |
| 813 | (tu.upper_boundary_count + |
| 814 | tu.lower_boundary_count), 1); |
| 815 | tu.resulting_valid_fp = |
| 816 | drm_fixp_div(temp1_fp, temp2_fp); |
| 817 | |
| 818 | temp1_fp = drm_fixp_from_fraction( |
| 819 | tu.tu_size_desired, 1); |
| 820 | tu.ratio_by_tu_fp = |
| 821 | drm_fixp_mul(tu.original_ratio_fp, temp1_fp); |
| 822 | |
| 823 | tu.valid_lower_boundary_link = |
| 824 | tu.valid_boundary_link - 1; |
| 825 | |
| 826 | temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); |
| 827 | temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp); |
| 828 | temp2_fp = drm_fixp_div(temp1_fp, |
| 829 | tu.resulting_valid_fp); |
| 830 | tu.n_tus = drm_fixp2int(temp2_fp); |
| 831 | |
| 832 | tu.tu_size_minus1 = tu.tu_size_desired - 1; |
| 833 | tu.even_distribution_BF = 1; |
| 834 | |
| 835 | temp1_fp = |
| 836 | drm_fixp_from_fraction(tu.tu_size_desired, 1); |
| 837 | temp2_fp = |
| 838 | drm_fixp_div(tu.resulting_valid_fp, temp1_fp); |
| 839 | tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; |
| 840 | } |
| 841 | } |
| 842 | |
| 843 | temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp); |
| 844 | |
| 845 | if (temp2_fp) |
| 846 | temp = drm_fixp2int_ceil(temp2_fp); |
| 847 | else |
| 848 | temp = 0; |
| 849 | |
| 850 | temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); |
| 851 | temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp); |
| 852 | temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); |
| 853 | temp2_fp = drm_fixp_div(temp1_fp, temp2_fp); |
| 854 | temp1_fp = drm_fixp_from_fraction(temp, 1); |
| 855 | temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); |
| 856 | temp = drm_fixp2int(temp2_fp); |
| 857 | |
| 858 | if (tu.async_en) |
| 859 | tu.delay_start_link += (int)temp; |
| 860 | |
| 861 | temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); |
| 862 | tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); |
| 863 | |
| 864 | /* OUTPUTS */ |
| 865 | tu_table->valid_boundary_link = tu.valid_boundary_link; |
| 866 | tu_table->delay_start_link = tu.delay_start_link; |
| 867 | tu_table->boundary_moderation_en = tu.boundary_moderation_en; |
| 868 | tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link; |
| 869 | tu_table->upper_boundary_count = tu.upper_boundary_count; |
| 870 | tu_table->lower_boundary_count = tu.lower_boundary_count; |
| 871 | tu_table->tu_size_minus1 = tu.tu_size_minus1; |
| 872 | |
| 873 | pr_info("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link); |
| 874 | pr_info("TU: delay_start_link: %d\n", tu_table->delay_start_link); |
| 875 | pr_info("TU: boundary_moderation_en: %d\n", |
| 876 | tu_table->boundary_moderation_en); |
| 877 | pr_info("TU: valid_lower_boundary_link: %d\n", |
| 878 | tu_table->valid_lower_boundary_link); |
| 879 | pr_info("TU: upper_boundary_count: %d\n", |
| 880 | tu_table->upper_boundary_count); |
| 881 | pr_info("TU: lower_boundary_count: %d\n", |
| 882 | tu_table->lower_boundary_count); |
| 883 | pr_info("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 884 | } |
| 885 | |
| 886 | static void dp_panel_calc_tu_parameters(struct dp_panel *dp_panel, |
| 887 | struct dp_vc_tu_mapping_table *tu_table) |
| 888 | { |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 889 | struct dp_tu_calc_input in; |
| 890 | struct dp_panel_info *pinfo; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 891 | struct dp_panel_private *panel; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 892 | int bw_code; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 893 | |
| 894 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 895 | pinfo = &dp_panel->pinfo; |
| 896 | bw_code = panel->link->link_params.bw_code; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 897 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 898 | in.lclk = drm_dp_bw_code_to_link_rate(bw_code) / 1000; |
| 899 | in.pclk_khz = pinfo->pixel_clk_khz; |
| 900 | in.hactive = pinfo->h_active; |
| 901 | in.hporch = pinfo->h_back_porch + pinfo->h_front_porch + |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 902 | pinfo->h_sync_width; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 903 | in.nlanes = panel->link->link_params.lane_count; |
| 904 | in.bpp = pinfo->bpp; |
| 905 | in.pixel_enc = 444; |
| 906 | in.dsc_en = dp_panel->dsc_en; |
| 907 | in.async_en = 0; |
| 908 | in.fec_en = dp_panel->fec_en; |
| 909 | in.num_of_dsc_slices = pinfo->comp_info.dsc_info.slice_per_pkt; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 910 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 911 | switch (pinfo->comp_info.comp_ratio) { |
| 912 | case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: |
| 913 | in.compress_ratio = 200; |
| 914 | break; |
| 915 | case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: |
| 916 | in.compress_ratio = 300; |
| 917 | break; |
| 918 | default: |
| 919 | in.compress_ratio = 100; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 920 | } |
| 921 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 922 | _dp_panel_calc_tu(&in, tu_table); |
| 923 | } |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 924 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 925 | void dp_panel_calc_tu_test(struct dp_tu_calc_input *in, |
| 926 | struct dp_vc_tu_mapping_table *tu_table) |
| 927 | { |
| 928 | _dp_panel_calc_tu(in, tu_table); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 929 | } |
| 930 | |
| 931 | static void dp_panel_config_tr_unit(struct dp_panel *dp_panel) |
| 932 | { |
| 933 | struct dp_panel_private *panel; |
| 934 | struct dp_catalog_panel *catalog; |
| 935 | u32 dp_tu = 0x0; |
| 936 | u32 valid_boundary = 0x0; |
| 937 | u32 valid_boundary2 = 0x0; |
| 938 | struct dp_vc_tu_mapping_table tu_calc_table; |
| 939 | |
| 940 | if (!dp_panel) { |
| 941 | pr_err("invalid input\n"); |
| 942 | return; |
| 943 | } |
| 944 | |
| 945 | if (dp_panel->stream_id != DP_STREAM_0) |
| 946 | return; |
| 947 | |
| 948 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 949 | catalog = panel->catalog; |
| 950 | |
| 951 | dp_panel_calc_tu_parameters(dp_panel, &tu_calc_table); |
| 952 | |
| 953 | dp_tu |= tu_calc_table.tu_size_minus1; |
| 954 | valid_boundary |= tu_calc_table.valid_boundary_link; |
| 955 | valid_boundary |= (tu_calc_table.delay_start_link << 16); |
| 956 | |
| 957 | valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1); |
| 958 | valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16); |
| 959 | valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20); |
| 960 | |
| 961 | if (tu_calc_table.boundary_moderation_en) |
| 962 | valid_boundary2 |= BIT(0); |
| 963 | |
| 964 | pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n", |
| 965 | dp_tu, valid_boundary, valid_boundary2); |
| 966 | |
| 967 | catalog->dp_tu = dp_tu; |
| 968 | catalog->valid_boundary = valid_boundary; |
| 969 | catalog->valid_boundary2 = valid_boundary2; |
| 970 | |
| 971 | catalog->update_transfer_unit(catalog); |
| 972 | } |
| 973 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 974 | enum dp_dsc_ratio_type { |
| 975 | DSC_8BPC_8BPP, |
| 976 | DSC_10BPC_8BPP, |
| 977 | DSC_12BPC_8BPP, |
| 978 | DSC_RATIO_TYPE_MAX |
| 979 | }; |
| 980 | |
| 981 | static u32 dp_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, |
| 982 | 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e}; |
| 983 | |
| 984 | /* |
| 985 | * DSC 1.1 |
| 986 | * Rate control - Min QP values for each ratio type in dp_dsc_ratio_type |
| 987 | */ |
| 988 | static char dp_dsc_rc_range_min_qp_1_1[][15] = { |
| 989 | {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13}, |
| 990 | {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17}, |
| 991 | {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21}, |
| 992 | }; |
| 993 | |
| 994 | /* |
| 995 | * DSC 1.1 SCR |
| 996 | * Rate control - Min QP values for each ratio type in dp_dsc_ratio_type |
| 997 | */ |
| 998 | static char dp_dsc_rc_range_min_qp_1_1_scr1[][15] = { |
| 999 | {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12}, |
| 1000 | {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, |
| 1001 | {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20}, |
| 1002 | }; |
| 1003 | |
| 1004 | /* |
| 1005 | * DSC 1.1 |
| 1006 | * Rate control - Max QP values for each ratio type in dp_dsc_ratio_type |
| 1007 | */ |
| 1008 | static char dp_dsc_rc_range_max_qp_1_1[][15] = { |
| 1009 | {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15}, |
| 1010 | {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19}, |
| 1011 | {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 19, 20, 21, 21, 23}, |
| 1012 | }; |
| 1013 | |
| 1014 | /* |
| 1015 | * DSC 1.1 SCR |
| 1016 | * Rate control - Max QP values for each ratio type in dp_dsc_ratio_type |
| 1017 | */ |
| 1018 | static char dp_dsc_rc_range_max_qp_1_1_scr1[][15] = { |
| 1019 | {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13}, |
| 1020 | {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17}, |
| 1021 | {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21}, |
| 1022 | }; |
| 1023 | |
| 1024 | /* |
| 1025 | * DSC 1.1 and DSC 1.1 SCR |
| 1026 | * Rate control - bpg offset values |
| 1027 | */ |
| 1028 | static char dp_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8, |
| 1029 | -8, -10, -10, -12, -12, -12, -12}; |
| 1030 | |
| 1031 | struct dp_dsc_dto_data { |
| 1032 | enum msm_display_compression_ratio comp_ratio; |
| 1033 | u32 org_bpp; /* bits */ |
| 1034 | u32 dto_numerator; |
| 1035 | u32 dto_denominator; |
| 1036 | }; |
| 1037 | |
| 1038 | struct dp_dsc_dto_data dto_tbl[] = { |
| 1039 | {MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 24, 1, 2}, |
| 1040 | {MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 30, 5, 8}, |
| 1041 | {MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 24, 1, 3}, |
| 1042 | {MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 30, 5, 12}, |
| 1043 | }; |
| 1044 | |
| 1045 | static void _dp_panel_get_dto_m_n(enum msm_display_compression_ratio ratio, |
| 1046 | u32 org_bpp, u32 *dto_n, u32 *dto_d) |
| 1047 | { |
| 1048 | u32 idx; |
| 1049 | |
| 1050 | for (idx = 0; idx < ARRAY_SIZE(dto_tbl); idx++) { |
| 1051 | if (ratio == dto_tbl[idx].comp_ratio && |
| 1052 | org_bpp == dto_tbl[idx].org_bpp) { |
| 1053 | *dto_n = dto_tbl[idx].dto_numerator; |
| 1054 | *dto_d = dto_tbl[idx].dto_denominator; |
| 1055 | return; |
| 1056 | } |
| 1057 | } |
| 1058 | } |
| 1059 | |
| 1060 | static int dp_panel_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, |
| 1061 | char *buf, int pps_id) |
| 1062 | { |
| 1063 | char *bp = buf; |
| 1064 | char data; |
| 1065 | int i, bpp; |
| 1066 | |
| 1067 | *bp++ = (dsc->version & 0xff); /* pps0 */ |
| 1068 | *bp++ = (pps_id & 0xff); /* pps1 */ |
| 1069 | bp++; /* pps2, reserved */ |
| 1070 | |
| 1071 | data = dsc->line_buf_depth & 0x0f; |
| 1072 | data |= ((dsc->bpc & 0xf) << 4); |
| 1073 | *bp++ = data; /* pps3 */ |
| 1074 | |
| 1075 | bpp = dsc->bpp; |
| 1076 | bpp <<= 4; /* 4 fraction bits */ |
| 1077 | data = (bpp >> 8); |
| 1078 | data &= 0x03; /* upper two bits */ |
| 1079 | data |= ((dsc->block_pred_enable & 0x1) << 5); |
| 1080 | data |= ((dsc->convert_rgb & 0x1) << 4); |
| 1081 | data |= ((dsc->enable_422 & 0x1) << 3); |
| 1082 | data |= ((dsc->vbr_enable & 0x1) << 2); |
| 1083 | *bp++ = data; /* pps4 */ |
| 1084 | *bp++ = (bpp & 0xff); /* pps5 */ |
| 1085 | |
| 1086 | *bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */ |
| 1087 | *bp++ = (dsc->pic_height & 0x0ff); /* pps7 */ |
| 1088 | *bp++ = ((dsc->pic_width >> 8) & 0xff); /* pps8 */ |
| 1089 | *bp++ = (dsc->pic_width & 0x0ff); /* pps9 */ |
| 1090 | |
| 1091 | *bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */ |
| 1092 | *bp++ = (dsc->slice_height & 0x0ff); /* pps11 */ |
| 1093 | *bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */ |
| 1094 | *bp++ = (dsc->slice_width & 0x0ff); /* pps13 */ |
| 1095 | |
| 1096 | *bp++ = ((dsc->chunk_size >> 8) & 0xff);/* pps14 */ |
| 1097 | *bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */ |
| 1098 | |
| 1099 | *bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16*/ |
| 1100 | *bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */ |
| 1101 | |
| 1102 | *bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */ |
| 1103 | *bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */ |
| 1104 | |
| 1105 | bp++; /* pps20, reserved */ |
| 1106 | |
| 1107 | *bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */ |
| 1108 | |
| 1109 | *bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */ |
| 1110 | *bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */ |
| 1111 | |
| 1112 | *bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */ |
| 1113 | *bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */ |
| 1114 | |
| 1115 | bp++; /* pps26, reserved */ |
| 1116 | |
| 1117 | *bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */ |
| 1118 | |
| 1119 | *bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */ |
| 1120 | *bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */ |
| 1121 | *bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */ |
| 1122 | *bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */ |
| 1123 | |
| 1124 | *bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */ |
| 1125 | *bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */ |
| 1126 | |
| 1127 | *bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */ |
| 1128 | *bp++ = (dsc->final_offset & 0x0ff); /* pps35 */ |
| 1129 | |
| 1130 | *bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */ |
| 1131 | *bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */ |
| 1132 | |
| 1133 | *bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */ |
| 1134 | *bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */ |
| 1135 | |
| 1136 | *bp++ = (dsc->edge_factor & 0x0f); /* pps40 */ |
| 1137 | |
| 1138 | *bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */ |
| 1139 | *bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */ |
| 1140 | |
| 1141 | data = ((dsc->tgt_offset_hi & 0xf) << 4); |
| 1142 | data |= (dsc->tgt_offset_lo & 0x0f); |
| 1143 | *bp++ = data; /* pps43 */ |
| 1144 | |
| 1145 | for (i = 0; i < ARRAY_SIZE(dp_dsc_rc_buf_thresh); i++) |
| 1146 | *bp++ = (dsc->buf_thresh[i] & 0xff); /* pps44 - pps57 */ |
| 1147 | |
| 1148 | for (i = 0; i < 15; i++) { /* pps58 - pps87 */ |
| 1149 | data = (dsc->range_min_qp[i] & 0x1f); |
| 1150 | data <<= 3; |
| 1151 | data |= ((dsc->range_max_qp[i] >> 2) & 0x07); |
| 1152 | *bp++ = data; |
| 1153 | data = (dsc->range_max_qp[i] & 0x03); |
| 1154 | data <<= 6; |
| 1155 | data |= (dsc->range_bpg_offset[i] & 0x3f); |
| 1156 | *bp++ = data; |
| 1157 | } |
| 1158 | |
| 1159 | return 88; |
| 1160 | } |
| 1161 | |
| 1162 | static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel) |
| 1163 | { |
| 1164 | struct dp_panel_private *panel; |
| 1165 | struct dp_dsc_cfg_data *dsc; |
| 1166 | u8 *pps, *parity; |
| 1167 | u32 *pps_word, *parity_word; |
| 1168 | int i, index_4; |
| 1169 | |
| 1170 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 1171 | dsc = &panel->catalog->dsc; |
| 1172 | pps = dsc->pps; |
| 1173 | pps_word = dsc->pps_word; |
| 1174 | parity = dsc->parity; |
| 1175 | parity_word = dsc->parity_word; |
| 1176 | |
| 1177 | memset(parity, 0, sizeof(dsc->parity)); |
| 1178 | |
| 1179 | dsc->pps_word_len = dsc->pps_len >> 2; |
| 1180 | dsc->parity_len = dsc->pps_word_len; |
| 1181 | dsc->parity_word_len = (dsc->parity_len >> 2) + 1; |
| 1182 | |
| 1183 | for (i = 0; i < dsc->pps_word_len; i++) { |
| 1184 | index_4 = i << 2; |
| 1185 | pps_word[i] = pps[index_4 + 0] << 0 | |
| 1186 | pps[index_4 + 1] << 8 | |
| 1187 | pps[index_4 + 2] << 16 | |
| 1188 | pps[index_4 + 3] << 24; |
| 1189 | |
| 1190 | parity[i] = dp_header_get_parity(pps_word[i]); |
| 1191 | } |
| 1192 | |
| 1193 | for (i = 0; i < dsc->parity_word_len; i++) { |
| 1194 | index_4 = i << 2; |
| 1195 | parity_word[i] = parity[index_4 + 0] << 0 | |
| 1196 | parity[index_4 + 1] << 8 | |
| 1197 | parity[index_4 + 2] << 16 | |
| 1198 | parity[index_4 + 3] << 24; |
| 1199 | } |
| 1200 | } |
| 1201 | |
| 1202 | static void _dp_panel_dsc_get_num_extra_pclk(struct msm_display_dsc_info *dsc, |
| 1203 | enum msm_display_compression_ratio ratio) |
| 1204 | { |
| 1205 | unsigned int dto_n, dto_d, remainder; |
| 1206 | int ack_required, last_few_ack_required, accum_ack; |
| 1207 | int last_few_pclk, last_few_pclk_required; |
| 1208 | int start, temp, line_width = dsc->pic_width/2; |
| 1209 | s64 temp1_fp, temp2_fp; |
| 1210 | |
| 1211 | _dp_panel_get_dto_m_n(ratio, dsc->bpc * 3, &dto_n, &dto_d); |
| 1212 | |
| 1213 | ack_required = dsc->pclk_per_line; |
| 1214 | |
| 1215 | /* number of pclk cycles left outside of the complete DTO set */ |
| 1216 | last_few_pclk = line_width % dto_d; |
| 1217 | |
| 1218 | /* number of pclk cycles outside of the complete dto */ |
| 1219 | temp1_fp = drm_fixp_from_fraction(line_width, dto_d); |
| 1220 | temp2_fp = drm_fixp_from_fraction(dto_n, 1); |
| 1221 | temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); |
| 1222 | temp = drm_fixp2int(temp1_fp); |
| 1223 | last_few_ack_required = ack_required - temp; |
| 1224 | |
| 1225 | /* |
| 1226 | * check how many more pclk is needed to |
| 1227 | * accommodate the last few ack required |
| 1228 | */ |
| 1229 | remainder = dto_n; |
| 1230 | accum_ack = 0; |
| 1231 | last_few_pclk_required = 0; |
| 1232 | while (accum_ack < last_few_ack_required) { |
| 1233 | last_few_pclk_required++; |
| 1234 | |
| 1235 | if (remainder >= dto_n) |
| 1236 | start = remainder; |
| 1237 | else |
| 1238 | start = remainder + dto_d; |
| 1239 | |
| 1240 | remainder = start - dto_n; |
| 1241 | if (remainder < dto_n) |
| 1242 | accum_ack++; |
| 1243 | } |
| 1244 | |
| 1245 | /* if fewer pclk than required */ |
| 1246 | if (last_few_pclk < last_few_pclk_required) |
| 1247 | dsc->extra_width = last_few_pclk_required - last_few_pclk; |
| 1248 | else |
| 1249 | dsc->extra_width = 0; |
| 1250 | |
| 1251 | pr_debug("extra pclks required: %d\n", dsc->extra_width); |
| 1252 | } |
| 1253 | |
| 1254 | static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel, |
| 1255 | struct msm_display_dsc_info *dsc, |
| 1256 | struct dp_display_mode *dp_mode, u32 dsc_byte_cnt) |
| 1257 | { |
| 1258 | int num_slices, tot_num_eoc_symbols; |
| 1259 | int tot_num_hor_bytes, tot_num_dummy_bytes; |
| 1260 | int dwidth_dsc_bytes, eoc_bytes; |
| 1261 | u32 num_lanes; |
| 1262 | |
| 1263 | num_lanes = dp_panel->link_info.num_lanes; |
| 1264 | num_slices = dsc->slice_per_pkt; |
| 1265 | |
| 1266 | eoc_bytes = dsc_byte_cnt % num_lanes; |
| 1267 | tot_num_eoc_symbols = num_lanes * num_slices; |
| 1268 | tot_num_hor_bytes = dsc_byte_cnt * num_slices; |
| 1269 | tot_num_dummy_bytes = (num_lanes - eoc_bytes) * num_slices; |
| 1270 | |
| 1271 | if (!eoc_bytes) |
| 1272 | tot_num_dummy_bytes = 0; |
| 1273 | |
| 1274 | dwidth_dsc_bytes = tot_num_hor_bytes + tot_num_eoc_symbols + |
| 1275 | tot_num_dummy_bytes; |
| 1276 | |
| 1277 | pr_debug("dwidth_dsc_bytes:%d, tot_num_hor_bytes:%d\n", |
| 1278 | dwidth_dsc_bytes, tot_num_hor_bytes); |
| 1279 | |
| 1280 | dp_mode->dsc_overhead_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, |
| 1281 | tot_num_hor_bytes); |
| 1282 | dp_mode->timing.dsc_overhead_fp = dp_mode->dsc_overhead_fp; |
| 1283 | } |
| 1284 | |
| 1285 | static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, |
| 1286 | struct msm_display_dsc_info *dsc, |
| 1287 | enum msm_display_compression_ratio ratio, |
| 1288 | struct dp_display_mode *dp_mode) |
| 1289 | { |
| 1290 | int slice_per_pkt, slice_per_intf, intf_width; |
| 1291 | int bytes_in_slice, total_bytes_per_intf; |
| 1292 | int comp_ratio; |
| 1293 | s64 temp1_fp, temp2_fp; |
| 1294 | s64 numerator_fp, denominator_fp; |
| 1295 | s64 dsc_byte_count_fp; |
| 1296 | u32 dsc_byte_count, temp1, temp2; |
| 1297 | |
| 1298 | intf_width = dp_mode->timing.h_active; |
| 1299 | if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt || |
| 1300 | (intf_width < dsc->slice_width)) |
| 1301 | return; |
| 1302 | |
| 1303 | slice_per_pkt = dsc->slice_per_pkt; |
| 1304 | slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); |
| 1305 | |
| 1306 | if (slice_per_pkt > slice_per_intf) |
| 1307 | slice_per_pkt = 1; |
| 1308 | |
| 1309 | bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8); |
| 1310 | total_bytes_per_intf = bytes_in_slice * slice_per_intf; |
| 1311 | |
| 1312 | dsc->bytes_in_slice = bytes_in_slice; |
| 1313 | dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt; |
| 1314 | dsc->pkt_per_line = slice_per_intf / slice_per_pkt; |
| 1315 | |
| 1316 | switch (ratio) { |
| 1317 | case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: |
| 1318 | comp_ratio = 200; |
| 1319 | break; |
| 1320 | case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: |
| 1321 | comp_ratio = 300; |
| 1322 | break; |
| 1323 | default: |
| 1324 | comp_ratio = 100; |
| 1325 | break; |
| 1326 | } |
| 1327 | |
| 1328 | temp1_fp = drm_fixp_from_fraction(comp_ratio, 100); |
| 1329 | temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1); |
| 1330 | denominator_fp = drm_fixp_mul(temp1_fp, temp2_fp); |
| 1331 | numerator_fp = drm_fixp_from_fraction(intf_width * dsc->bpc * 3, 1); |
| 1332 | dsc_byte_count_fp = drm_fixp_div(numerator_fp, denominator_fp); |
| 1333 | dsc_byte_count = drm_fixp2int_ceil(dsc_byte_count_fp); |
| 1334 | |
| 1335 | temp1 = dsc_byte_count * slice_per_intf; |
| 1336 | temp2 = temp1; |
| 1337 | if (temp1 % 3 != 0) |
| 1338 | temp1 += 3 - (temp1 % 3); |
| 1339 | |
| 1340 | dsc->eol_byte_num = temp1 - temp2; |
| 1341 | |
| 1342 | temp1_fp = drm_fixp_from_fraction(slice_per_intf, 6); |
| 1343 | temp2_fp = drm_fixp_mul(dsc_byte_count_fp, temp1_fp); |
| 1344 | dsc->pclk_per_line = drm_fixp2int_ceil(temp2_fp); |
| 1345 | |
| 1346 | _dp_panel_dsc_get_num_extra_pclk(dsc, ratio); |
| 1347 | dsc->pclk_per_line--; |
| 1348 | |
| 1349 | _dp_panel_dsc_bw_overhead_calc(dp_panel, dsc, dp_mode, dsc_byte_count); |
| 1350 | } |
| 1351 | |
| 1352 | static void dp_panel_dsc_populate_static_params( |
| 1353 | struct msm_display_dsc_info *dsc) |
| 1354 | { |
| 1355 | int bpp, bpc; |
| 1356 | int mux_words_size; |
| 1357 | int groups_per_line, groups_total; |
| 1358 | int min_rate_buffer_size; |
| 1359 | int hrd_delay; |
| 1360 | int pre_num_extra_mux_bits, num_extra_mux_bits; |
| 1361 | int slice_bits; |
| 1362 | int data; |
| 1363 | int final_value, final_scale; |
| 1364 | int ratio_index, mod_offset; |
| 1365 | |
| 1366 | dsc->version = 0x11; |
| 1367 | dsc->scr_rev = 0; |
| 1368 | dsc->rc_model_size = 8192; |
| 1369 | |
| 1370 | if (dsc->version == 0x11 && dsc->scr_rev == 0x1) |
| 1371 | dsc->first_line_bpg_offset = 15; |
| 1372 | else |
| 1373 | dsc->first_line_bpg_offset = 12; |
| 1374 | |
| 1375 | dsc->edge_factor = 6; |
| 1376 | dsc->tgt_offset_hi = 3; |
| 1377 | dsc->tgt_offset_lo = 3; |
| 1378 | dsc->enable_422 = 0; |
| 1379 | dsc->convert_rgb = 1; |
| 1380 | dsc->vbr_enable = 0; |
| 1381 | |
| 1382 | dsc->buf_thresh = dp_dsc_rc_buf_thresh; |
| 1383 | |
| 1384 | bpp = dsc->bpp; |
| 1385 | bpc = dsc->bpc; |
| 1386 | |
| 1387 | if (bpc == 12) |
| 1388 | ratio_index = DSC_12BPC_8BPP; |
| 1389 | else if (bpc == 10) |
| 1390 | ratio_index = DSC_10BPC_8BPP; |
| 1391 | else |
| 1392 | ratio_index = DSC_8BPC_8BPP; |
| 1393 | |
| 1394 | if (dsc->version == 0x11 && dsc->scr_rev == 0x1) { |
| 1395 | dsc->range_min_qp = |
| 1396 | dp_dsc_rc_range_min_qp_1_1_scr1[ratio_index]; |
| 1397 | dsc->range_max_qp = |
| 1398 | dp_dsc_rc_range_max_qp_1_1_scr1[ratio_index]; |
| 1399 | } else { |
| 1400 | dsc->range_min_qp = dp_dsc_rc_range_min_qp_1_1[ratio_index]; |
| 1401 | dsc->range_max_qp = dp_dsc_rc_range_max_qp_1_1[ratio_index]; |
| 1402 | } |
| 1403 | dsc->range_bpg_offset = dp_dsc_rc_range_bpg_offset; |
| 1404 | |
| 1405 | if (bpp <= 10) |
| 1406 | dsc->initial_offset = 6144; |
| 1407 | else |
| 1408 | dsc->initial_offset = 2048; /* bpp = 12 */ |
| 1409 | |
| 1410 | if (bpc == 12) |
| 1411 | mux_words_size = 64; |
| 1412 | else |
| 1413 | mux_words_size = 48; /* bpc == 8/10 */ |
| 1414 | |
| 1415 | dsc->line_buf_depth = bpc + 1; |
| 1416 | |
| 1417 | if (bpc == 8) { |
| 1418 | dsc->input_10_bits = 0; |
| 1419 | dsc->min_qp_flatness = 3; |
| 1420 | dsc->max_qp_flatness = 12; |
| 1421 | dsc->quant_incr_limit0 = 11; |
| 1422 | dsc->quant_incr_limit1 = 11; |
| 1423 | } else if (bpc == 10) { /* 10bpc */ |
| 1424 | dsc->input_10_bits = 1; |
| 1425 | dsc->min_qp_flatness = 7; |
| 1426 | dsc->max_qp_flatness = 16; |
| 1427 | dsc->quant_incr_limit0 = 15; |
| 1428 | dsc->quant_incr_limit1 = 15; |
| 1429 | } else { /* 12 bpc */ |
| 1430 | dsc->input_10_bits = 0; |
| 1431 | dsc->min_qp_flatness = 11; |
| 1432 | dsc->max_qp_flatness = 20; |
| 1433 | dsc->quant_incr_limit0 = 19; |
| 1434 | dsc->quant_incr_limit1 = 19; |
| 1435 | } |
| 1436 | |
| 1437 | mod_offset = dsc->slice_width % 3; |
| 1438 | switch (mod_offset) { |
| 1439 | case 0: |
| 1440 | dsc->slice_last_group_size = 2; |
| 1441 | break; |
| 1442 | case 1: |
| 1443 | dsc->slice_last_group_size = 0; |
| 1444 | break; |
| 1445 | case 2: |
| 1446 | dsc->slice_last_group_size = 1; |
| 1447 | break; |
| 1448 | default: |
| 1449 | break; |
| 1450 | } |
| 1451 | |
| 1452 | dsc->det_thresh_flatness = 2 << (bpc - 8); |
| 1453 | |
| 1454 | dsc->initial_xmit_delay = dsc->rc_model_size / (2 * bpp); |
| 1455 | |
| 1456 | groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); |
| 1457 | |
| 1458 | dsc->chunk_size = dsc->slice_width * bpp / 8; |
| 1459 | if ((dsc->slice_width * bpp) % 8) |
| 1460 | dsc->chunk_size++; |
| 1461 | |
| 1462 | /* rbs-min */ |
| 1463 | min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + |
| 1464 | dsc->initial_xmit_delay * bpp + |
| 1465 | groups_per_line * dsc->first_line_bpg_offset; |
| 1466 | |
| 1467 | hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp); |
| 1468 | |
| 1469 | dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; |
| 1470 | |
| 1471 | dsc->initial_scale_value = 8 * dsc->rc_model_size / |
| 1472 | (dsc->rc_model_size - dsc->initial_offset); |
| 1473 | |
| 1474 | slice_bits = 8 * dsc->chunk_size * dsc->slice_height; |
| 1475 | |
| 1476 | groups_total = groups_per_line * dsc->slice_height; |
| 1477 | |
| 1478 | data = dsc->first_line_bpg_offset * 2048; |
| 1479 | |
| 1480 | dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); |
| 1481 | |
| 1482 | pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2); |
| 1483 | |
| 1484 | num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size - |
| 1485 | ((slice_bits - pre_num_extra_mux_bits) % mux_words_size)); |
| 1486 | |
| 1487 | data = 2048 * (dsc->rc_model_size - dsc->initial_offset |
| 1488 | + num_extra_mux_bits); |
| 1489 | dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); |
| 1490 | |
| 1491 | data = dsc->initial_xmit_delay * bpp; |
| 1492 | final_value = dsc->rc_model_size - data + num_extra_mux_bits; |
| 1493 | |
| 1494 | final_scale = 8 * dsc->rc_model_size / |
| 1495 | (dsc->rc_model_size - final_value); |
| 1496 | |
| 1497 | dsc->final_offset = final_value; |
| 1498 | |
| 1499 | data = (final_scale - 9) * (dsc->nfl_bpg_offset + |
| 1500 | dsc->slice_bpg_offset); |
| 1501 | dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; |
| 1502 | |
| 1503 | dsc->scale_decrement_interval = groups_per_line / |
| 1504 | (dsc->initial_scale_value - 8); |
| 1505 | } |
| 1506 | |
| 1507 | struct dp_dsc_slices_per_line { |
| 1508 | u32 min_ppr; |
| 1509 | u32 max_ppr; |
| 1510 | u8 num_slices; |
| 1511 | }; |
| 1512 | |
| 1513 | struct dp_dsc_slices_per_line slice_per_line_tbl[] = { |
| 1514 | {0, 340, 1 }, |
| 1515 | {340, 680, 2 }, |
| 1516 | {680, 1360, 4 }, |
| 1517 | {1360, 3200, 8 }, |
| 1518 | {3200, 4800, 12 }, |
| 1519 | {4800, 6400, 16 }, |
| 1520 | {6400, 8000, 20 }, |
| 1521 | {8000, 9600, 24 } |
| 1522 | }; |
| 1523 | |
| 1524 | static int dp_panel_dsc_prepare_basic_params( |
| 1525 | struct msm_compression_info *comp_info, |
| 1526 | const struct dp_display_mode *dp_mode, |
| 1527 | struct dp_panel *dp_panel) |
| 1528 | { |
| 1529 | int i; |
| 1530 | struct dp_dsc_slices_per_line *rec; |
| 1531 | int slice_width; |
| 1532 | u32 ppr = dp_mode->timing.pixel_clk_khz/1000; |
| 1533 | |
| 1534 | comp_info->dsc_info.slice_per_pkt = 0; |
| 1535 | for (i = 0; i < ARRAY_SIZE(slice_per_line_tbl); i++) { |
| 1536 | rec = &slice_per_line_tbl[i]; |
| 1537 | if ((ppr > rec->min_ppr) && (ppr <= rec->max_ppr)) { |
| 1538 | comp_info->dsc_info.slice_per_pkt = rec->num_slices; |
| 1539 | break; |
| 1540 | } |
| 1541 | } |
| 1542 | |
| 1543 | if (comp_info->dsc_info.slice_per_pkt == 0) |
| 1544 | return -EINVAL; |
| 1545 | |
| 1546 | slice_width = (dp_mode->timing.h_active / |
| 1547 | comp_info->dsc_info.slice_per_pkt); |
| 1548 | |
| 1549 | comp_info->dsc_info.block_pred_enable = |
| 1550 | dp_panel->sink_dsc_caps.block_pred_en; |
| 1551 | comp_info->dsc_info.vbr_enable = 0; |
| 1552 | comp_info->dsc_info.enable_422 = 0; |
| 1553 | comp_info->dsc_info.convert_rgb = 1; |
| 1554 | comp_info->dsc_info.input_10_bits = 0; |
| 1555 | |
| 1556 | comp_info->dsc_info.pic_width = dp_mode->timing.h_active; |
| 1557 | comp_info->dsc_info.pic_height = dp_mode->timing.v_active; |
| 1558 | comp_info->dsc_info.slice_width = slice_width; |
| 1559 | |
| 1560 | if (comp_info->dsc_info.pic_height % 16 == 0) |
| 1561 | comp_info->dsc_info.slice_height = 16; |
| 1562 | else if (comp_info->dsc_info.pic_height % 12 == 0) |
| 1563 | comp_info->dsc_info.slice_height = 12; |
| 1564 | else |
| 1565 | comp_info->dsc_info.slice_height = 15; |
| 1566 | |
| 1567 | comp_info->dsc_info.bpc = dp_mode->timing.bpp / 3; |
| 1568 | comp_info->dsc_info.bpp = comp_info->dsc_info.bpc; |
| 1569 | comp_info->dsc_info.full_frame_slices = |
| 1570 | DIV_ROUND_UP(dp_mode->timing.h_active, slice_width); |
| 1571 | |
| 1572 | comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC; |
| 1573 | comp_info->comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1; |
| 1574 | return 0; |
| 1575 | } |
| 1576 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1577 | static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func) |
| 1578 | { |
| 1579 | int rlen, rc = 0; |
| 1580 | struct dp_panel_private *panel; |
| 1581 | struct drm_dp_link *link_info; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1582 | struct drm_dp_aux *drm_aux; |
| 1583 | u8 *dpcd, rx_feature, temp; |
| 1584 | u32 dfp_count = 0, offset = DP_DPCD_REV; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1585 | unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING; |
| 1586 | |
| 1587 | if (!dp_panel) { |
| 1588 | pr_err("invalid input\n"); |
| 1589 | rc = -EINVAL; |
| 1590 | goto end; |
| 1591 | } |
| 1592 | |
| 1593 | dpcd = dp_panel->dpcd; |
| 1594 | |
| 1595 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1596 | drm_aux = panel->aux->drm_aux; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1597 | link_info = &dp_panel->link_info; |
| 1598 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1599 | /* reset vsc data */ |
| 1600 | panel->vsc_supported = false; |
| 1601 | panel->vscext_supported = false; |
| 1602 | panel->vscext_chaining_supported = false; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1603 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1604 | if (panel->custom_dpcd) { |
| 1605 | pr_debug("skip dpcd read in debug mode\n"); |
| 1606 | goto skip_dpcd_read; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1607 | } |
| 1608 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1609 | rlen = drm_dp_dpcd_read(drm_aux, DP_TRAINING_AUX_RD_INTERVAL, &temp, 1); |
| 1610 | if (rlen != 1) { |
| 1611 | pr_err("error reading DP_TRAINING_AUX_RD_INTERVAL\n"); |
| 1612 | rc = -EINVAL; |
| 1613 | goto end; |
| 1614 | } |
| 1615 | |
| 1616 | /* check for EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT */ |
| 1617 | if (temp & BIT(7)) { |
| 1618 | pr_debug("using EXTENDED_RECEIVER_CAPABILITY_FIELD\n"); |
| 1619 | offset = DPRX_EXTENDED_DPCD_FIELD; |
| 1620 | } |
| 1621 | |
| 1622 | rlen = drm_dp_dpcd_read(drm_aux, offset, |
| 1623 | dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1)); |
| 1624 | if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { |
| 1625 | pr_err("dpcd read failed, rlen=%d\n", rlen); |
| 1626 | if (rlen == -ETIMEDOUT) |
| 1627 | rc = rlen; |
| 1628 | else |
| 1629 | rc = -EINVAL; |
| 1630 | |
| 1631 | goto end; |
| 1632 | } |
| 1633 | |
| 1634 | print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ", |
| 1635 | DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false); |
| 1636 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1637 | rlen = drm_dp_dpcd_read(panel->aux->drm_aux, |
| 1638 | DPRX_FEATURE_ENUMERATION_LIST, &rx_feature, 1); |
| 1639 | if (rlen != 1) { |
| 1640 | pr_debug("failed to read DPRX_FEATURE_ENUMERATION_LIST\n"); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1641 | goto skip_dpcd_read; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1642 | } |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1643 | panel->vsc_supported = !!(rx_feature & |
| 1644 | VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED); |
| 1645 | panel->vscext_supported = !!(rx_feature & VSC_EXT_VESA_SDP_SUPPORTED); |
| 1646 | panel->vscext_chaining_supported = !!(rx_feature & |
| 1647 | VSC_EXT_VESA_SDP_CHAINING_SUPPORTED); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1648 | |
| 1649 | pr_debug("vsc=%d, vscext=%d, vscext_chaining=%d\n", |
| 1650 | panel->vsc_supported, panel->vscext_supported, |
| 1651 | panel->vscext_chaining_supported); |
| 1652 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1653 | skip_dpcd_read: |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1654 | link_info->revision = dp_panel->dpcd[DP_DPCD_REV]; |
| 1655 | |
| 1656 | panel->major = (link_info->revision >> 4) & 0x0f; |
| 1657 | panel->minor = link_info->revision & 0x0f; |
| 1658 | pr_debug("version: %d.%d\n", panel->major, panel->minor); |
| 1659 | |
| 1660 | link_info->rate = |
| 1661 | drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]); |
| 1662 | pr_debug("link_rate=%d\n", link_info->rate); |
| 1663 | |
| 1664 | link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] & |
| 1665 | DP_MAX_LANE_COUNT_MASK; |
| 1666 | |
| 1667 | if (multi_func) |
| 1668 | link_info->num_lanes = min_t(unsigned int, |
| 1669 | link_info->num_lanes, 2); |
| 1670 | |
| 1671 | pr_debug("lane_count=%d\n", link_info->num_lanes); |
| 1672 | |
| 1673 | if (drm_dp_enhanced_frame_cap(dpcd)) |
| 1674 | link_info->capabilities |= caps; |
| 1675 | |
| 1676 | dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] & |
| 1677 | DP_DOWN_STREAM_PORT_COUNT; |
| 1678 | |
| 1679 | if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) |
| 1680 | && (dpcd[DP_DPCD_REV] > 0x10)) { |
| 1681 | rlen = drm_dp_dpcd_read(panel->aux->drm_aux, |
| 1682 | DP_DOWNSTREAM_PORT_0, dp_panel->ds_ports, |
| 1683 | DP_MAX_DOWNSTREAM_PORTS); |
| 1684 | if (rlen < DP_MAX_DOWNSTREAM_PORTS) { |
| 1685 | pr_err("ds port status failed, rlen=%d\n", rlen); |
| 1686 | rc = -EINVAL; |
| 1687 | goto end; |
| 1688 | } |
| 1689 | } |
| 1690 | |
| 1691 | if (dfp_count > DP_MAX_DS_PORT_COUNT) |
| 1692 | pr_debug("DS port count %d greater that max (%d) supported\n", |
| 1693 | dfp_count, DP_MAX_DS_PORT_COUNT); |
| 1694 | |
| 1695 | end: |
| 1696 | return rc; |
| 1697 | } |
| 1698 | |
| 1699 | static int dp_panel_set_default_link_params(struct dp_panel *dp_panel) |
| 1700 | { |
| 1701 | struct drm_dp_link *link_info; |
| 1702 | const int default_bw_code = 162000; |
| 1703 | const int default_num_lanes = 1; |
| 1704 | |
| 1705 | if (!dp_panel) { |
| 1706 | pr_err("invalid input\n"); |
| 1707 | return -EINVAL; |
| 1708 | } |
| 1709 | link_info = &dp_panel->link_info; |
| 1710 | link_info->rate = default_bw_code; |
| 1711 | link_info->num_lanes = default_num_lanes; |
| 1712 | pr_debug("link_rate=%d num_lanes=%d\n", |
| 1713 | link_info->rate, link_info->num_lanes); |
| 1714 | |
| 1715 | return 0; |
| 1716 | } |
| 1717 | |
| 1718 | static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid) |
| 1719 | { |
| 1720 | struct dp_panel_private *panel; |
| 1721 | |
| 1722 | if (!dp_panel) { |
| 1723 | pr_err("invalid input\n"); |
| 1724 | return -EINVAL; |
| 1725 | } |
| 1726 | |
| 1727 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 1728 | |
| 1729 | if (edid) { |
| 1730 | dp_panel->edid_ctrl->edid = (struct edid *)edid; |
| 1731 | panel->custom_edid = true; |
| 1732 | } else { |
| 1733 | panel->custom_edid = false; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1734 | dp_panel->edid_ctrl->edid = NULL; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1735 | } |
| 1736 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1737 | pr_debug("%d\n", panel->custom_edid); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1738 | return 0; |
| 1739 | } |
| 1740 | |
| 1741 | static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd) |
| 1742 | { |
| 1743 | struct dp_panel_private *panel; |
| 1744 | u8 *dp_dpcd; |
| 1745 | |
| 1746 | if (!dp_panel) { |
| 1747 | pr_err("invalid input\n"); |
| 1748 | return -EINVAL; |
| 1749 | } |
| 1750 | |
| 1751 | dp_dpcd = dp_panel->dpcd; |
| 1752 | |
| 1753 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 1754 | |
| 1755 | if (dpcd) { |
| 1756 | memcpy(dp_dpcd, dpcd, DP_RECEIVER_CAP_SIZE + 1); |
| 1757 | panel->custom_dpcd = true; |
| 1758 | } else { |
| 1759 | panel->custom_dpcd = false; |
| 1760 | } |
| 1761 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1762 | pr_debug("%d\n", panel->custom_dpcd); |
| 1763 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1764 | return 0; |
| 1765 | } |
| 1766 | |
| 1767 | static int dp_panel_read_edid(struct dp_panel *dp_panel, |
| 1768 | struct drm_connector *connector) |
| 1769 | { |
| 1770 | int ret = 0; |
| 1771 | struct dp_panel_private *panel; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1772 | struct edid *edid; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1773 | |
| 1774 | if (!dp_panel) { |
| 1775 | pr_err("invalid input\n"); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1776 | return -EINVAL; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1777 | } |
| 1778 | |
| 1779 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 1780 | |
| 1781 | if (panel->custom_edid) { |
| 1782 | pr_debug("skip edid read in debug mode\n"); |
| 1783 | goto end; |
| 1784 | } |
| 1785 | |
| 1786 | sde_get_edid(connector, &panel->aux->drm_aux->ddc, |
| 1787 | (void **)&dp_panel->edid_ctrl); |
| 1788 | if (!dp_panel->edid_ctrl->edid) { |
| 1789 | pr_err("EDID read failed\n"); |
| 1790 | ret = -EINVAL; |
| 1791 | goto end; |
| 1792 | } |
| 1793 | end: |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1794 | edid = dp_panel->edid_ctrl->edid; |
| 1795 | dp_panel->audio_supported = drm_detect_monitor_audio(edid); |
| 1796 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1797 | return ret; |
| 1798 | } |
| 1799 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1800 | static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel) |
| 1801 | { |
| 1802 | s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1); |
| 1803 | |
| 1804 | if (!dp_panel->dsc_feature_enable || !dp_panel->fec_feature_enable) { |
| 1805 | pr_debug("source dsc is not supported\n"); |
| 1806 | return; |
| 1807 | } |
| 1808 | |
| 1809 | if (dp_panel->dsc_dpcd[0] && dp_panel->fec_dpcd) { |
| 1810 | dp_panel->sink_dsc_caps.dsc_capable = true; |
| 1811 | dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1]; |
| 1812 | dp_panel->sink_dsc_caps.block_pred_en = |
| 1813 | dp_panel->dsc_dpcd[6] ? true : false; |
| 1814 | |
| 1815 | if (dp_panel->sink_dsc_caps.version >= 0x11) |
| 1816 | dp_panel->dsc_en = true; |
| 1817 | } else { |
| 1818 | dp_panel->sink_dsc_caps.dsc_capable = false; |
| 1819 | dp_panel->dsc_en = false; |
| 1820 | } |
| 1821 | |
| 1822 | dp_panel->fec_en = dp_panel->dsc_en; |
| 1823 | dp_panel->widebus_en = dp_panel->dsc_en; |
| 1824 | |
| 1825 | /* fec_overhead = 1.00 / 0.97582 */ |
| 1826 | if (dp_panel->fec_en) |
| 1827 | fec_overhead_fp = drm_fixp_from_fraction(100000, 97582); |
| 1828 | |
| 1829 | dp_panel->fec_overhead_fp = fec_overhead_fp; |
| 1830 | } |
| 1831 | |
| 1832 | static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel) |
| 1833 | { |
| 1834 | int rlen; |
| 1835 | struct dp_panel_private *panel; |
| 1836 | const int fec_cap = 0x90; |
| 1837 | int dpcd_rev; |
| 1838 | |
| 1839 | if (!dp_panel) { |
| 1840 | pr_err("invalid input\n"); |
| 1841 | return; |
| 1842 | } |
| 1843 | |
| 1844 | dp_panel->dsc_en = false; |
| 1845 | dp_panel->fec_en = false; |
| 1846 | |
| 1847 | dpcd_rev = dp_panel->dpcd[DP_DPCD_REV]; |
| 1848 | |
| 1849 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 1850 | |
| 1851 | dp_panel->fec_overhead_fp = 0; |
| 1852 | if (panel->parser->dsc_feature_enable && dpcd_rev >= 0x14) { |
| 1853 | rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DSC_SUPPORT, |
| 1854 | dp_panel->dsc_dpcd, (DP_RECEIVER_DSC_CAP_SIZE + 1)); |
| 1855 | if (rlen < (DP_RECEIVER_DSC_CAP_SIZE + 1)) { |
| 1856 | pr_debug("dsc dpcd read failed, rlen=%d\n", rlen); |
| 1857 | return; |
| 1858 | } |
| 1859 | |
| 1860 | print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DSC DPCD: ", |
| 1861 | DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen, |
| 1862 | false); |
| 1863 | |
| 1864 | rlen = drm_dp_dpcd_read(panel->aux->drm_aux, fec_cap, |
| 1865 | &dp_panel->fec_dpcd, 1); |
| 1866 | if (rlen < 1) { |
| 1867 | pr_err("fec dpcd read failed, rlen=%d\n", rlen); |
| 1868 | return; |
| 1869 | } |
| 1870 | |
| 1871 | dp_panel_decode_dsc_dpcd(dp_panel); |
| 1872 | } |
| 1873 | } |
| 1874 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1875 | static int dp_panel_read_sink_caps(struct dp_panel *dp_panel, |
| 1876 | struct drm_connector *connector, bool multi_func) |
| 1877 | { |
| 1878 | int rc = 0, rlen, count, downstream_ports; |
| 1879 | const int count_len = 1; |
| 1880 | struct dp_panel_private *panel; |
| 1881 | |
| 1882 | if (!dp_panel || !connector) { |
| 1883 | pr_err("invalid input\n"); |
| 1884 | rc = -EINVAL; |
| 1885 | goto end; |
| 1886 | } |
| 1887 | |
| 1888 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 1889 | |
| 1890 | rc = dp_panel_read_dpcd(dp_panel, multi_func); |
| 1891 | if (rc || !is_link_rate_valid(drm_dp_link_rate_to_bw_code( |
| 1892 | dp_panel->link_info.rate)) || !is_lane_count_valid( |
| 1893 | dp_panel->link_info.num_lanes) || |
| 1894 | ((drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate)) > |
| 1895 | dp_panel->max_bw_code)) { |
| 1896 | if ((rc == -ETIMEDOUT) || (rc == -ENODEV)) { |
| 1897 | pr_err("DPCD read failed, return early\n"); |
| 1898 | goto end; |
| 1899 | } |
| 1900 | pr_err("panel dpcd read failed/incorrect, set default params\n"); |
| 1901 | dp_panel_set_default_link_params(dp_panel); |
| 1902 | } |
| 1903 | |
| 1904 | downstream_ports = dp_panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & |
| 1905 | DP_DWN_STRM_PORT_PRESENT; |
| 1906 | |
| 1907 | if (downstream_ports) { |
| 1908 | rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_SINK_COUNT, |
| 1909 | &count, count_len); |
| 1910 | if (rlen == count_len) { |
| 1911 | count = DP_GET_SINK_COUNT(count); |
| 1912 | if (!count) { |
| 1913 | pr_err("no downstream ports connected\n"); |
| 1914 | panel->link->sink_count.count = 0; |
| 1915 | rc = -ENOTCONN; |
| 1916 | goto end; |
| 1917 | } |
| 1918 | } |
| 1919 | } |
| 1920 | |
| 1921 | rc = dp_panel_read_edid(dp_panel, connector); |
| 1922 | if (rc) { |
| 1923 | pr_err("panel edid read failed, set failsafe mode\n"); |
| 1924 | return rc; |
| 1925 | } |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 1926 | |
| 1927 | dp_panel->widebus_en = panel->parser->has_widebus; |
| 1928 | dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable; |
| 1929 | dp_panel->fec_feature_enable = panel->parser->fec_feature_enable; |
| 1930 | |
| 1931 | dp_panel_read_sink_dsc_caps(dp_panel); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 1932 | end: |
| 1933 | return rc; |
| 1934 | } |
| 1935 | |
| 1936 | static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, |
| 1937 | u32 mode_edid_bpp, u32 mode_pclk_khz) |
| 1938 | { |
| 1939 | struct drm_dp_link *link_info; |
| 1940 | const u32 max_supported_bpp = 30, min_supported_bpp = 18; |
| 1941 | u32 bpp = 0, data_rate_khz = 0; |
| 1942 | |
| 1943 | bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); |
| 1944 | |
| 1945 | link_info = &dp_panel->link_info; |
| 1946 | data_rate_khz = link_info->num_lanes * link_info->rate * 8; |
| 1947 | |
| 1948 | while (bpp > min_supported_bpp) { |
| 1949 | if (mode_pclk_khz * bpp <= data_rate_khz) |
| 1950 | break; |
| 1951 | bpp -= 6; |
| 1952 | } |
| 1953 | |
| 1954 | return bpp; |
| 1955 | } |
| 1956 | |
| 1957 | static u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, |
| 1958 | u32 mode_edid_bpp, u32 mode_pclk_khz) |
| 1959 | { |
| 1960 | struct dp_panel_private *panel; |
| 1961 | u32 bpp = mode_edid_bpp; |
| 1962 | |
| 1963 | if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { |
| 1964 | pr_err("invalid input\n"); |
| 1965 | return 0; |
| 1966 | } |
| 1967 | |
| 1968 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 1969 | |
| 1970 | if (dp_panel->video_test) |
| 1971 | bpp = dp_link_bit_depth_to_bpp( |
| 1972 | panel->link->test_video.test_bit_depth); |
| 1973 | else |
| 1974 | bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp, |
| 1975 | mode_pclk_khz); |
| 1976 | |
| 1977 | return bpp; |
| 1978 | } |
| 1979 | |
| 1980 | static void dp_panel_set_test_mode(struct dp_panel_private *panel, |
| 1981 | struct dp_display_mode *mode) |
| 1982 | { |
| 1983 | struct dp_panel_info *pinfo = NULL; |
| 1984 | struct dp_link_test_video *test_info = NULL; |
| 1985 | |
| 1986 | if (!panel) { |
| 1987 | pr_err("invalid params\n"); |
| 1988 | return; |
| 1989 | } |
| 1990 | |
| 1991 | pinfo = &mode->timing; |
| 1992 | test_info = &panel->link->test_video; |
| 1993 | |
| 1994 | pinfo->h_active = test_info->test_h_width; |
| 1995 | pinfo->h_sync_width = test_info->test_hsync_width; |
| 1996 | pinfo->h_back_porch = test_info->test_h_start - |
| 1997 | test_info->test_hsync_width; |
| 1998 | pinfo->h_front_porch = test_info->test_h_total - |
| 1999 | (test_info->test_h_start + test_info->test_h_width); |
| 2000 | |
| 2001 | pinfo->v_active = test_info->test_v_height; |
| 2002 | pinfo->v_sync_width = test_info->test_vsync_width; |
| 2003 | pinfo->v_back_porch = test_info->test_v_start - |
| 2004 | test_info->test_vsync_width; |
| 2005 | pinfo->v_front_porch = test_info->test_v_total - |
| 2006 | (test_info->test_v_start + test_info->test_v_height); |
| 2007 | |
| 2008 | pinfo->bpp = dp_link_bit_depth_to_bpp(test_info->test_bit_depth); |
| 2009 | pinfo->h_active_low = test_info->test_hsync_pol; |
| 2010 | pinfo->v_active_low = test_info->test_vsync_pol; |
| 2011 | |
| 2012 | pinfo->refresh_rate = test_info->test_rr_n; |
| 2013 | pinfo->pixel_clk_khz = test_info->test_h_total * |
| 2014 | test_info->test_v_total * pinfo->refresh_rate; |
| 2015 | |
| 2016 | if (test_info->test_rr_d == 0) |
| 2017 | pinfo->pixel_clk_khz /= 1000; |
| 2018 | else |
| 2019 | pinfo->pixel_clk_khz /= 1001; |
| 2020 | |
| 2021 | if (test_info->test_h_width == 640) |
| 2022 | pinfo->pixel_clk_khz = 25170; |
| 2023 | } |
| 2024 | |
| 2025 | static int dp_panel_get_modes(struct dp_panel *dp_panel, |
| 2026 | struct drm_connector *connector, struct dp_display_mode *mode) |
| 2027 | { |
| 2028 | struct dp_panel_private *panel; |
| 2029 | |
| 2030 | if (!dp_panel) { |
| 2031 | pr_err("invalid input\n"); |
| 2032 | return -EINVAL; |
| 2033 | } |
| 2034 | |
| 2035 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2036 | |
| 2037 | if (dp_panel->video_test) { |
| 2038 | dp_panel_set_test_mode(panel, mode); |
| 2039 | return 1; |
| 2040 | } else if (dp_panel->edid_ctrl->edid) { |
| 2041 | return _sde_edid_update_modes(connector, dp_panel->edid_ctrl); |
| 2042 | } |
| 2043 | |
| 2044 | /* fail-safe mode */ |
| 2045 | memcpy(&mode->timing, &fail_safe, |
| 2046 | sizeof(fail_safe)); |
| 2047 | return 1; |
| 2048 | } |
| 2049 | |
| 2050 | static void dp_panel_handle_sink_request(struct dp_panel *dp_panel) |
| 2051 | { |
| 2052 | struct dp_panel_private *panel; |
| 2053 | |
| 2054 | if (!dp_panel) { |
| 2055 | pr_err("invalid input\n"); |
| 2056 | return; |
| 2057 | } |
| 2058 | |
| 2059 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2060 | |
| 2061 | if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { |
| 2062 | u8 checksum = sde_get_edid_checksum(dp_panel->edid_ctrl); |
| 2063 | |
| 2064 | panel->link->send_edid_checksum(panel->link, checksum); |
| 2065 | panel->link->send_test_response(panel->link); |
| 2066 | } |
| 2067 | } |
| 2068 | |
| 2069 | static void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) |
| 2070 | { |
| 2071 | u32 hsync_start_x, hsync_end_x; |
| 2072 | struct dp_catalog_panel *catalog; |
| 2073 | struct dp_panel_private *panel; |
| 2074 | struct dp_panel_info *pinfo; |
| 2075 | |
| 2076 | if (!dp_panel) { |
| 2077 | pr_err("invalid input\n"); |
| 2078 | return; |
| 2079 | } |
| 2080 | |
| 2081 | if (dp_panel->stream_id >= DP_STREAM_MAX) { |
| 2082 | pr_err("invalid stream id:%d\n", dp_panel->stream_id); |
| 2083 | return; |
| 2084 | } |
| 2085 | |
| 2086 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2087 | catalog = panel->catalog; |
| 2088 | pinfo = &panel->dp_panel.pinfo; |
| 2089 | |
| 2090 | if (!panel->panel_on) { |
| 2091 | pr_debug("DP panel not enabled, handle TPG on next panel on\n"); |
| 2092 | return; |
| 2093 | } |
| 2094 | |
| 2095 | if (!enable) { |
| 2096 | panel->catalog->tpg_config(catalog, false); |
| 2097 | return; |
| 2098 | } |
| 2099 | |
| 2100 | /* TPG config */ |
| 2101 | catalog->hsync_period = pinfo->h_sync_width + pinfo->h_back_porch + |
| 2102 | pinfo->h_active + pinfo->h_front_porch; |
| 2103 | catalog->vsync_period = pinfo->v_sync_width + pinfo->v_back_porch + |
| 2104 | pinfo->v_active + pinfo->v_front_porch; |
| 2105 | |
| 2106 | catalog->display_v_start = ((pinfo->v_sync_width + |
| 2107 | pinfo->v_back_porch) * catalog->hsync_period); |
| 2108 | catalog->display_v_end = ((catalog->vsync_period - |
| 2109 | pinfo->v_front_porch) * catalog->hsync_period) - 1; |
| 2110 | |
| 2111 | catalog->display_v_start += pinfo->h_sync_width + pinfo->h_back_porch; |
| 2112 | catalog->display_v_end -= pinfo->h_front_porch; |
| 2113 | |
| 2114 | hsync_start_x = pinfo->h_back_porch + pinfo->h_sync_width; |
| 2115 | hsync_end_x = catalog->hsync_period - pinfo->h_front_porch - 1; |
| 2116 | |
| 2117 | catalog->v_sync_width = pinfo->v_sync_width; |
| 2118 | |
| 2119 | catalog->hsync_ctl = (catalog->hsync_period << 16) | |
| 2120 | pinfo->h_sync_width; |
| 2121 | catalog->display_hctl = (hsync_end_x << 16) | hsync_start_x; |
| 2122 | |
| 2123 | panel->catalog->tpg_config(catalog, true); |
| 2124 | } |
| 2125 | |
| 2126 | static int dp_panel_config_timing(struct dp_panel *dp_panel) |
| 2127 | { |
| 2128 | int rc = 0; |
| 2129 | u32 data, total_ver, total_hor; |
| 2130 | struct dp_catalog_panel *catalog; |
| 2131 | struct dp_panel_private *panel; |
| 2132 | struct dp_panel_info *pinfo; |
| 2133 | |
| 2134 | if (!dp_panel) { |
| 2135 | pr_err("invalid input\n"); |
| 2136 | rc = -EINVAL; |
| 2137 | goto end; |
| 2138 | } |
| 2139 | |
| 2140 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2141 | catalog = panel->catalog; |
| 2142 | pinfo = &panel->dp_panel.pinfo; |
| 2143 | |
| 2144 | pr_debug("width=%d hporch= %d %d %d\n", |
| 2145 | pinfo->h_active, pinfo->h_back_porch, |
| 2146 | pinfo->h_front_porch, pinfo->h_sync_width); |
| 2147 | |
| 2148 | pr_debug("height=%d vporch= %d %d %d\n", |
| 2149 | pinfo->v_active, pinfo->v_back_porch, |
| 2150 | pinfo->v_front_porch, pinfo->v_sync_width); |
| 2151 | |
| 2152 | total_hor = pinfo->h_active + pinfo->h_back_porch + |
| 2153 | pinfo->h_front_porch + pinfo->h_sync_width; |
| 2154 | |
| 2155 | total_ver = pinfo->v_active + pinfo->v_back_porch + |
| 2156 | pinfo->v_front_porch + pinfo->v_sync_width; |
| 2157 | |
| 2158 | data = total_ver; |
| 2159 | data <<= 16; |
| 2160 | data |= total_hor; |
| 2161 | |
| 2162 | catalog->total = data; |
| 2163 | |
| 2164 | data = (pinfo->v_back_porch + pinfo->v_sync_width); |
| 2165 | data <<= 16; |
| 2166 | data |= (pinfo->h_back_porch + pinfo->h_sync_width); |
| 2167 | |
| 2168 | catalog->sync_start = data; |
| 2169 | |
| 2170 | data = pinfo->v_sync_width; |
| 2171 | data <<= 16; |
| 2172 | data |= (pinfo->v_active_low << 31); |
| 2173 | data |= pinfo->h_sync_width; |
| 2174 | data |= (pinfo->h_active_low << 15); |
| 2175 | |
| 2176 | catalog->width_blanking = data; |
| 2177 | |
| 2178 | data = pinfo->v_active; |
| 2179 | data <<= 16; |
| 2180 | data |= pinfo->h_active; |
| 2181 | |
| 2182 | catalog->dp_active = data; |
| 2183 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2184 | catalog->widebus_en = pinfo->widebus_en; |
| 2185 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2186 | panel->catalog->timing_cfg(catalog); |
| 2187 | panel->panel_on = true; |
| 2188 | end: |
| 2189 | return rc; |
| 2190 | } |
| 2191 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2192 | static u32 _dp_panel_calc_be_in_lane(struct dp_panel *dp_panel) |
| 2193 | { |
| 2194 | struct dp_panel_info *pinfo; |
| 2195 | struct msm_compression_info *comp_info; |
| 2196 | u32 dsc_htot_byte_cnt, mod_result; |
| 2197 | u32 numerator, denominator; |
| 2198 | s64 temp_fp; |
| 2199 | u32 be_in_lane = 10; |
| 2200 | |
| 2201 | pinfo = &dp_panel->pinfo; |
| 2202 | comp_info = &pinfo->comp_info; |
| 2203 | |
| 2204 | if (!dp_panel->mst_state) |
| 2205 | return be_in_lane; |
| 2206 | |
| 2207 | switch (pinfo->comp_info.comp_ratio) { |
| 2208 | case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: |
| 2209 | denominator = 16; /* 2 * bits-in-byte */ |
| 2210 | break; |
| 2211 | case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: |
| 2212 | denominator = 24; /* 3 * bits-in-byte */ |
| 2213 | break; |
| 2214 | default: |
| 2215 | denominator = 8; /* 1 * bits-in-byte */ |
| 2216 | } |
| 2217 | |
| 2218 | numerator = (pinfo->h_active + pinfo->h_back_porch + |
| 2219 | pinfo->h_front_porch + pinfo->h_sync_width) * |
| 2220 | pinfo->bpp; |
| 2221 | temp_fp = drm_fixp_from_fraction(numerator, denominator); |
| 2222 | dsc_htot_byte_cnt = drm_fixp2int_ceil(temp_fp); |
| 2223 | |
| 2224 | mod_result = dsc_htot_byte_cnt % 12; |
| 2225 | if (mod_result == 0) |
| 2226 | be_in_lane = 8; |
| 2227 | else if (mod_result <= 3) |
| 2228 | be_in_lane = 1; |
| 2229 | else if (mod_result <= 6) |
| 2230 | be_in_lane = 2; |
| 2231 | else if (mod_result <= 9) |
| 2232 | be_in_lane = 4; |
| 2233 | else if (mod_result <= 11) |
| 2234 | be_in_lane = 8; |
| 2235 | else |
| 2236 | be_in_lane = 10; |
| 2237 | |
| 2238 | return be_in_lane; |
| 2239 | } |
| 2240 | |
| 2241 | static void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable) |
| 2242 | { |
| 2243 | struct dp_catalog_panel *catalog; |
| 2244 | struct dp_panel_private *panel; |
| 2245 | struct dp_panel_info *pinfo; |
| 2246 | struct msm_compression_info *comp_info; |
| 2247 | struct dp_dsc_cfg_data *dsc; |
| 2248 | int pps_len; |
| 2249 | |
| 2250 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2251 | |
| 2252 | catalog = panel->catalog; |
| 2253 | dsc = &catalog->dsc; |
| 2254 | pinfo = &dp_panel->pinfo; |
| 2255 | comp_info = &pinfo->comp_info; |
| 2256 | |
| 2257 | if (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC && enable) { |
| 2258 | pps_len = dp_panel_dsc_create_pps_buf_cmd(&comp_info->dsc_info, |
| 2259 | dsc->pps, 0); |
| 2260 | dsc->pps_len = pps_len; |
| 2261 | dp_panel_dsc_prepare_pps_packet(dp_panel); |
| 2262 | |
| 2263 | dsc->slice_per_pkt = comp_info->dsc_info.slice_per_pkt - 1; |
| 2264 | dsc->bytes_per_pkt = comp_info->dsc_info.bytes_per_pkt; |
| 2265 | dsc->bytes_per_pkt /= comp_info->dsc_info.slice_per_pkt; |
| 2266 | dsc->eol_byte_num = comp_info->dsc_info.eol_byte_num; |
| 2267 | dsc->dto_count = comp_info->dsc_info.pclk_per_line; |
| 2268 | dsc->be_in_lane = _dp_panel_calc_be_in_lane(dp_panel); |
| 2269 | dsc->dsc_en = true; |
| 2270 | dsc->dto_en = true; |
| 2271 | |
| 2272 | _dp_panel_get_dto_m_n(comp_info->comp_ratio, pinfo->bpp, |
| 2273 | &dsc->dto_n, &dsc->dto_d); |
| 2274 | } else { |
| 2275 | dsc->dsc_en = false; |
| 2276 | dsc->dto_en = false; |
| 2277 | dsc->dto_n = 0; |
| 2278 | dsc->dto_d = 0; |
| 2279 | } |
| 2280 | |
| 2281 | catalog->stream_id = dp_panel->stream_id; |
| 2282 | catalog->dsc_cfg(catalog); |
| 2283 | |
| 2284 | if (catalog->dsc.dsc_en && enable) |
| 2285 | catalog->pps_flush(catalog); |
| 2286 | } |
| 2287 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2288 | static int dp_panel_edid_register(struct dp_panel_private *panel) |
| 2289 | { |
| 2290 | int rc = 0; |
| 2291 | |
| 2292 | panel->dp_panel.edid_ctrl = sde_edid_init(); |
| 2293 | if (!panel->dp_panel.edid_ctrl) { |
| 2294 | pr_err("sde edid init for DP failed\n"); |
| 2295 | rc = -ENOMEM; |
| 2296 | } |
| 2297 | |
| 2298 | return rc; |
| 2299 | } |
| 2300 | |
| 2301 | static void dp_panel_edid_deregister(struct dp_panel_private *panel) |
| 2302 | { |
| 2303 | sde_edid_deinit((void **)&panel->dp_panel.edid_ctrl); |
| 2304 | } |
| 2305 | |
| 2306 | static int dp_panel_set_stream_info(struct dp_panel *dp_panel, |
| 2307 | enum dp_stream_id stream_id, u32 ch_start_slot, |
| 2308 | u32 ch_tot_slots, u32 pbn) |
| 2309 | { |
| 2310 | if (!dp_panel || stream_id > DP_STREAM_MAX) { |
| 2311 | pr_err("invalid input. stream_id: %d\n", stream_id); |
| 2312 | return -EINVAL; |
| 2313 | } |
| 2314 | |
| 2315 | dp_panel->stream_id = stream_id; |
| 2316 | dp_panel->channel_start_slot = ch_start_slot; |
| 2317 | dp_panel->channel_total_slots = ch_tot_slots; |
| 2318 | dp_panel->pbn = pbn; |
| 2319 | |
| 2320 | return 0; |
| 2321 | } |
| 2322 | |
| 2323 | static int dp_panel_init_panel_info(struct dp_panel *dp_panel) |
| 2324 | { |
| 2325 | int rc = 0; |
| 2326 | struct dp_panel_private *panel; |
| 2327 | struct dp_panel_info *pinfo; |
| 2328 | |
| 2329 | if (!dp_panel) { |
| 2330 | pr_err("invalid input\n"); |
| 2331 | rc = -EINVAL; |
| 2332 | goto end; |
| 2333 | } |
| 2334 | |
| 2335 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2336 | pinfo = &dp_panel->pinfo; |
| 2337 | |
| 2338 | /* |
| 2339 | * print resolution info as this is a result |
| 2340 | * of user initiated action of cable connection |
| 2341 | */ |
| 2342 | pr_info("DP RESOLUTION: active(back|front|width|low)\n"); |
| 2343 | pr_info("%d(%d|%d|%d|%d)x%d(%d|%d|%d|%d)@%dfps %dbpp %dKhz %dLR %dLn\n", |
| 2344 | pinfo->h_active, pinfo->h_back_porch, pinfo->h_front_porch, |
| 2345 | pinfo->h_sync_width, pinfo->h_active_low, |
| 2346 | pinfo->v_active, pinfo->v_back_porch, pinfo->v_front_porch, |
| 2347 | pinfo->v_sync_width, pinfo->v_active_low, |
| 2348 | pinfo->refresh_rate, pinfo->bpp, pinfo->pixel_clk_khz, |
| 2349 | panel->link->link_params.bw_code, |
| 2350 | panel->link->link_params.lane_count); |
| 2351 | end: |
| 2352 | return rc; |
| 2353 | } |
| 2354 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2355 | static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2356 | { |
| 2357 | int rc = 0; |
| 2358 | struct dp_panel_private *panel; |
| 2359 | struct dp_catalog_hdr_data *hdr; |
| 2360 | struct drm_connector *connector; |
| 2361 | struct sde_connector_state *c_state; |
| 2362 | |
| 2363 | if (!dp_panel) { |
| 2364 | pr_err("invalid input\n"); |
| 2365 | return -EINVAL; |
| 2366 | } |
| 2367 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2368 | if (flags & DP_PANEL_SRC_INITIATED_POWER_DOWN) { |
| 2369 | pr_debug("retain states in src initiated power down request\n"); |
| 2370 | return 0; |
| 2371 | } |
| 2372 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2373 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2374 | hdr = &panel->catalog->hdr_data; |
| 2375 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2376 | if (!panel->custom_edid && dp_panel->edid_ctrl->edid) |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2377 | sde_free_edid((void **)&dp_panel->edid_ctrl); |
| 2378 | |
| 2379 | dp_panel_set_stream_info(dp_panel, DP_STREAM_MAX, 0, 0, 0); |
| 2380 | memset(&dp_panel->pinfo, 0, sizeof(dp_panel->pinfo)); |
| 2381 | memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); |
| 2382 | panel->panel_on = false; |
| 2383 | |
| 2384 | connector = dp_panel->connector; |
| 2385 | c_state = to_sde_connector_state(connector->state); |
| 2386 | |
| 2387 | connector->hdr_eotf = 0; |
| 2388 | connector->hdr_metadata_type_one = 0; |
| 2389 | connector->hdr_max_luminance = 0; |
| 2390 | connector->hdr_avg_luminance = 0; |
| 2391 | connector->hdr_min_luminance = 0; |
| 2392 | connector->hdr_supported = false; |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 2393 | connector->hdr_plus_app_ver = 0; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2394 | |
| 2395 | memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 2396 | memset(&c_state->dyn_hdr_meta, 0, sizeof(c_state->dyn_hdr_meta)); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2397 | |
| 2398 | return rc; |
| 2399 | } |
| 2400 | |
| 2401 | static u32 dp_panel_get_min_req_link_rate(struct dp_panel *dp_panel) |
| 2402 | { |
| 2403 | const u32 encoding_factx10 = 8; |
| 2404 | u32 min_link_rate_khz = 0, lane_cnt; |
| 2405 | struct dp_panel_info *pinfo; |
| 2406 | |
| 2407 | if (!dp_panel) { |
| 2408 | pr_err("invalid input\n"); |
| 2409 | goto end; |
| 2410 | } |
| 2411 | |
| 2412 | lane_cnt = dp_panel->link_info.num_lanes; |
| 2413 | pinfo = &dp_panel->pinfo; |
| 2414 | |
| 2415 | /* num_lanes * lane_count * 8 >= pclk * bpp * 10 */ |
| 2416 | min_link_rate_khz = pinfo->pixel_clk_khz / |
| 2417 | (lane_cnt * encoding_factx10); |
| 2418 | min_link_rate_khz *= pinfo->bpp; |
| 2419 | |
| 2420 | pr_debug("min lclk req=%d khz for pclk=%d khz, lanes=%d, bpp=%d\n", |
| 2421 | min_link_rate_khz, pinfo->pixel_clk_khz, lane_cnt, |
| 2422 | pinfo->bpp); |
| 2423 | end: |
| 2424 | return min_link_rate_khz; |
| 2425 | } |
| 2426 | |
| 2427 | static bool dp_panel_hdr_supported(struct dp_panel *dp_panel) |
| 2428 | { |
| 2429 | struct dp_panel_private *panel; |
| 2430 | |
| 2431 | if (!dp_panel) { |
| 2432 | pr_err("invalid input\n"); |
| 2433 | return false; |
| 2434 | } |
| 2435 | |
| 2436 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2437 | |
| 2438 | return panel->major >= 1 && panel->vsc_supported && |
| 2439 | (panel->minor >= 4 || panel->vscext_supported); |
| 2440 | } |
| 2441 | |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 2442 | static u32 dp_panel_calc_dhdr_pkt_limit(struct dp_panel *dp_panel, |
| 2443 | struct dp_dhdr_maxpkt_calc_input *input) |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2444 | { |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 2445 | s64 mdpclk_fp = drm_fixp_from_fraction(input->mdp_clk, 1000000); |
| 2446 | s64 lclk_fp = drm_fixp_from_fraction(input->lclk, 1000); |
| 2447 | s64 pclk_fp = drm_fixp_from_fraction(input->pclk, 1000); |
| 2448 | s64 nlanes_fp = drm_int2fixp(input->nlanes); |
| 2449 | s64 target_sc = input->mst_target_sc; |
| 2450 | s64 hactive_fp = drm_int2fixp(input->h_active); |
| 2451 | const s64 i1_fp = DRM_FIXED_ONE; |
| 2452 | const s64 i2_fp = drm_int2fixp(2); |
| 2453 | const s64 i10_fp = drm_int2fixp(10); |
| 2454 | const s64 i56_fp = drm_int2fixp(56); |
| 2455 | const s64 i64_fp = drm_int2fixp(64); |
| 2456 | s64 mst_bw_fp = i1_fp; |
| 2457 | s64 fec_factor_fp = i1_fp; |
| 2458 | s64 mst_bw64_fp, mst_bw64_ceil_fp, nlanes56_fp; |
| 2459 | u32 f1, f2, f3, f4, f5, deploy_period, target_period; |
| 2460 | s64 f3_f5_slot_fp; |
| 2461 | u32 calc_pkt_limit; |
| 2462 | const u32 max_pkt_limit = 64; |
| 2463 | |
| 2464 | if (input->fec_en && input->mst_en) |
| 2465 | fec_factor_fp = drm_fixp_from_fraction(64000, 65537); |
| 2466 | |
| 2467 | if (input->mst_en) |
| 2468 | mst_bw_fp = drm_fixp_div(target_sc, i64_fp); |
| 2469 | |
| 2470 | f1 = drm_fixp2int_ceil(drm_fixp_div(drm_fixp_mul(i10_fp, lclk_fp), |
| 2471 | mdpclk_fp)); |
| 2472 | f2 = drm_fixp2int_ceil(drm_fixp_div(drm_fixp_mul(i2_fp, lclk_fp), |
| 2473 | mdpclk_fp)) + drm_fixp2int_ceil(drm_fixp_div( |
| 2474 | drm_fixp_mul(i1_fp, lclk_fp), mdpclk_fp)); |
| 2475 | |
| 2476 | mst_bw64_fp = drm_fixp_mul(mst_bw_fp, i64_fp); |
| 2477 | if (drm_fixp2int(mst_bw64_fp) == 0) |
| 2478 | f3_f5_slot_fp = drm_fixp_div(i1_fp, drm_int2fixp( |
| 2479 | drm_fixp2int_ceil(drm_fixp_div( |
| 2480 | i1_fp, mst_bw64_fp)))); |
| 2481 | else |
| 2482 | f3_f5_slot_fp = drm_int2fixp(drm_fixp2int(mst_bw_fp)); |
| 2483 | |
| 2484 | mst_bw64_ceil_fp = drm_int2fixp(drm_fixp2int_ceil(mst_bw64_fp)); |
| 2485 | f3 = drm_fixp2int(drm_fixp_mul(drm_int2fixp(drm_fixp2int( |
| 2486 | drm_fixp_div(i2_fp, f3_f5_slot_fp)) + 1), |
| 2487 | (i64_fp - mst_bw64_ceil_fp))) + 2; |
| 2488 | |
| 2489 | if (!input->mst_en) { |
| 2490 | f4 = 1 + drm_fixp2int(drm_fixp_div(drm_int2fixp(50), |
| 2491 | nlanes_fp)) + drm_fixp2int(drm_fixp_div( |
| 2492 | nlanes_fp, i2_fp)); |
| 2493 | f5 = 0; |
| 2494 | } else { |
| 2495 | f4 = 0; |
| 2496 | nlanes56_fp = drm_fixp_div(i56_fp, nlanes_fp); |
| 2497 | f5 = drm_fixp2int(drm_fixp_mul(drm_int2fixp(drm_fixp2int( |
| 2498 | drm_fixp_div(i1_fp + nlanes56_fp, |
| 2499 | f3_f5_slot_fp)) + 1), (i64_fp - |
| 2500 | mst_bw64_ceil_fp + i1_fp + nlanes56_fp))); |
| 2501 | } |
| 2502 | |
| 2503 | deploy_period = f1 + f2 + f3 + f4 + f5 + 19; |
| 2504 | target_period = drm_fixp2int(drm_fixp_mul(fec_factor_fp, drm_fixp_mul( |
| 2505 | hactive_fp, drm_fixp_div(lclk_fp, pclk_fp)))); |
| 2506 | |
| 2507 | calc_pkt_limit = target_period / deploy_period; |
| 2508 | |
| 2509 | pr_debug("input: %d, %d, %d, %d, %d, 0x%llx, %d, %d\n", |
| 2510 | input->mdp_clk, input->lclk, input->pclk, input->h_active, |
| 2511 | input->nlanes, input->mst_target_sc, input->mst_en ? 1 : 0, |
| 2512 | input->fec_en ? 1 : 0); |
| 2513 | pr_debug("factors: %d, %d, %d, %d, %d\n", f1, f2, f3, f4, f5); |
| 2514 | pr_debug("d_p: %d, t_p: %d, maxPkts: %d%s\n", deploy_period, |
| 2515 | target_period, calc_pkt_limit, calc_pkt_limit > max_pkt_limit ? |
| 2516 | " CAPPED" : ""); |
| 2517 | |
| 2518 | if (calc_pkt_limit > max_pkt_limit) |
| 2519 | calc_pkt_limit = max_pkt_limit; |
| 2520 | |
| 2521 | pr_debug("packet limit per line = %d\n", calc_pkt_limit); |
| 2522 | return calc_pkt_limit; |
| 2523 | } |
| 2524 | |
| 2525 | static int dp_panel_setup_hdr(struct dp_panel *dp_panel, |
| 2526 | struct drm_msm_ext_hdr_metadata *hdr_meta, |
| 2527 | bool dhdr_update, u64 core_clk_rate) |
| 2528 | { |
| 2529 | int rc = 0, max_pkts = 0; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2530 | struct dp_panel_private *panel; |
| 2531 | struct dp_catalog_hdr_data *hdr; |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 2532 | struct dp_dhdr_maxpkt_calc_input input; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2533 | |
| 2534 | if (!dp_panel) { |
| 2535 | pr_err("invalid input\n"); |
| 2536 | rc = -EINVAL; |
| 2537 | goto end; |
| 2538 | } |
| 2539 | |
| 2540 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2541 | hdr = &panel->catalog->hdr_data; |
| 2542 | |
| 2543 | /* use cached meta data in case meta data not provided */ |
| 2544 | if (!hdr_meta) { |
| 2545 | if (hdr->hdr_meta.hdr_state) |
| 2546 | goto cached; |
| 2547 | else |
| 2548 | goto end; |
| 2549 | } |
| 2550 | |
| 2551 | panel->hdr_state = hdr_meta->hdr_state; |
| 2552 | |
| 2553 | hdr->ext_header_byte0 = 0x00; |
| 2554 | hdr->ext_header_byte1 = 0x04; |
| 2555 | hdr->ext_header_byte2 = 0x1F; |
| 2556 | hdr->ext_header_byte3 = 0x00; |
| 2557 | |
| 2558 | hdr->vsc_header_byte0 = 0x00; |
| 2559 | hdr->vsc_header_byte1 = 0x07; |
| 2560 | hdr->vsc_header_byte2 = 0x05; |
| 2561 | hdr->vsc_header_byte3 = 0x13; |
| 2562 | |
| 2563 | hdr->vscext_header_byte0 = 0x00; |
| 2564 | hdr->vscext_header_byte1 = 0x87; |
| 2565 | hdr->vscext_header_byte2 = 0x1D; |
| 2566 | hdr->vscext_header_byte3 = 0x13 << 2; |
| 2567 | |
| 2568 | /* VSC SDP Payload for DB16 */ |
| 2569 | hdr->pixel_encoding = RGB; |
| 2570 | hdr->colorimetry = ITU_R_BT_2020_RGB; |
| 2571 | |
| 2572 | /* VSC SDP Payload for DB17 */ |
| 2573 | hdr->dynamic_range = CEA; |
| 2574 | |
| 2575 | /* VSC SDP Payload for DB18 */ |
| 2576 | hdr->content_type = GRAPHICS; |
| 2577 | |
| 2578 | hdr->bpc = dp_panel->pinfo.bpp / 3; |
| 2579 | |
| 2580 | hdr->version = 0x01; |
| 2581 | hdr->length = 0x1A; |
| 2582 | |
| 2583 | if (panel->hdr_state) |
| 2584 | memcpy(&hdr->hdr_meta, hdr_meta, sizeof(hdr->hdr_meta)); |
| 2585 | else |
| 2586 | memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); |
| 2587 | cached: |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 2588 | if (dhdr_update) { |
| 2589 | hdr->vscext_header_byte2 |= SEQ_INCREMENT_FOR_CHAINED_PACKETS; |
| 2590 | |
| 2591 | input.mdp_clk = core_clk_rate; |
| 2592 | input.lclk = dp_panel->link_info.rate; |
| 2593 | input.nlanes = dp_panel->link_info.num_lanes; |
| 2594 | input.pclk = dp_panel->pinfo.pixel_clk_khz; |
| 2595 | input.h_active = dp_panel->pinfo.h_active; |
| 2596 | input.mst_target_sc = dp_panel->mst_target_sc; |
| 2597 | input.mst_en = dp_panel->mst_state; |
| 2598 | input.fec_en = dp_panel->fec_en; |
| 2599 | max_pkts = dp_panel_calc_dhdr_pkt_limit(dp_panel, &input); |
| 2600 | } |
| 2601 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2602 | if (panel->panel_on) { |
| 2603 | panel->catalog->stream_id = dp_panel->stream_id; |
Steve Cohen | 3ad0888 | 2019-02-01 19:05:41 -0500 | [diff] [blame] | 2604 | panel->catalog->config_hdr(panel->catalog, panel->hdr_state, |
| 2605 | max_pkts); |
| 2606 | if (dhdr_update) { |
| 2607 | panel->catalog->dhdr_flush(panel->catalog); |
| 2608 | hdr->vscext_header_byte2 &= |
| 2609 | ~SEQ_INCREMENT_FOR_CHAINED_PACKETS; |
| 2610 | } |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2611 | } |
| 2612 | end: |
| 2613 | return rc; |
| 2614 | } |
| 2615 | |
| 2616 | static int dp_panel_spd_config(struct dp_panel *dp_panel) |
| 2617 | { |
| 2618 | int rc = 0; |
| 2619 | struct dp_panel_private *panel; |
| 2620 | |
| 2621 | if (!dp_panel) { |
| 2622 | pr_err("invalid input\n"); |
| 2623 | rc = -EINVAL; |
| 2624 | goto end; |
| 2625 | } |
| 2626 | |
| 2627 | if (dp_panel->stream_id >= DP_STREAM_MAX) { |
| 2628 | pr_err("invalid stream id:%d\n", dp_panel->stream_id); |
| 2629 | return -EINVAL; |
| 2630 | } |
| 2631 | |
| 2632 | if (!dp_panel->spd_enabled) { |
| 2633 | pr_debug("SPD Infoframe not enabled\n"); |
| 2634 | goto end; |
| 2635 | } |
| 2636 | |
| 2637 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2638 | |
| 2639 | panel->catalog->spd_vendor_name = panel->spd_vendor_name; |
| 2640 | panel->catalog->spd_product_description = |
| 2641 | panel->spd_product_description; |
| 2642 | |
| 2643 | panel->catalog->stream_id = dp_panel->stream_id; |
| 2644 | panel->catalog->config_spd(panel->catalog); |
| 2645 | end: |
| 2646 | return rc; |
| 2647 | } |
| 2648 | |
| 2649 | static void dp_panel_config_ctrl(struct dp_panel *dp_panel) |
| 2650 | { |
| 2651 | u32 config = 0, tbd; |
| 2652 | u8 *dpcd = dp_panel->dpcd; |
| 2653 | struct dp_panel_private *panel; |
| 2654 | struct dp_catalog_panel *catalog; |
| 2655 | |
| 2656 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2657 | catalog = panel->catalog; |
| 2658 | |
| 2659 | config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */ |
| 2660 | config |= (0 << 11); /* RGB */ |
| 2661 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2662 | tbd = panel->link->get_test_bits_depth(panel->link, |
| 2663 | dp_panel->pinfo.bpp); |
| 2664 | |
| 2665 | if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) |
| 2666 | tbd = DP_TEST_BIT_DEPTH_8; |
| 2667 | |
| 2668 | config |= tbd << 8; |
| 2669 | |
| 2670 | /* Num of Lanes */ |
| 2671 | config |= ((panel->link->link_params.lane_count - 1) << 4); |
| 2672 | |
| 2673 | if (drm_dp_enhanced_frame_cap(dpcd)) |
| 2674 | config |= 0x40; |
| 2675 | |
| 2676 | config |= 0x04; /* progressive video */ |
| 2677 | |
| 2678 | config |= 0x03; /* sycn clock & static Mvid */ |
| 2679 | |
| 2680 | catalog->config_ctrl(catalog, config); |
| 2681 | } |
| 2682 | |
| 2683 | static void dp_panel_config_misc(struct dp_panel *dp_panel) |
| 2684 | { |
| 2685 | struct dp_panel_private *panel; |
| 2686 | struct dp_catalog_panel *catalog; |
| 2687 | u32 misc_val; |
| 2688 | u32 tb, cc; |
| 2689 | |
| 2690 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2691 | catalog = panel->catalog; |
| 2692 | |
| 2693 | tb = panel->link->get_test_bits_depth(panel->link, dp_panel->pinfo.bpp); |
| 2694 | cc = panel->link->get_colorimetry_config(panel->link); |
| 2695 | |
| 2696 | misc_val = cc; |
| 2697 | misc_val |= (tb << 5); |
| 2698 | misc_val |= BIT(0); /* Configure clock to synchronous mode */ |
| 2699 | |
| 2700 | catalog->misc_val = misc_val; |
| 2701 | catalog->config_misc(catalog); |
| 2702 | } |
| 2703 | |
| 2704 | static bool dp_panel_use_fixed_nvid(struct dp_panel *dp_panel) |
| 2705 | { |
| 2706 | u8 *dpcd = dp_panel->dpcd; |
| 2707 | struct sde_connector *c_conn = to_sde_connector(dp_panel->connector); |
| 2708 | |
| 2709 | /* use fixe mvid and nvid for MST streams */ |
| 2710 | if (c_conn->mst_port) |
| 2711 | return true; |
| 2712 | |
| 2713 | /* |
| 2714 | * For better interop experience, used a fixed NVID=0x8000 |
| 2715 | * whenever connected to a VGA dongle downstream. |
| 2716 | */ |
| 2717 | if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) { |
| 2718 | u8 type = dpcd[DP_DOWNSTREAMPORT_PRESENT] & |
| 2719 | DP_DWN_STRM_PORT_TYPE_MASK; |
| 2720 | if (type == DP_DWN_STRM_PORT_TYPE_ANALOG) |
| 2721 | return true; |
| 2722 | } |
| 2723 | |
| 2724 | return false; |
| 2725 | } |
| 2726 | |
| 2727 | static void dp_panel_config_msa(struct dp_panel *dp_panel) |
| 2728 | { |
| 2729 | struct dp_panel_private *panel; |
| 2730 | struct dp_catalog_panel *catalog; |
| 2731 | u32 rate; |
| 2732 | u32 stream_rate_khz; |
| 2733 | bool fixed_nvid; |
| 2734 | |
| 2735 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2736 | catalog = panel->catalog; |
| 2737 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2738 | catalog->widebus_en = dp_panel->widebus_en; |
| 2739 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2740 | fixed_nvid = dp_panel_use_fixed_nvid(dp_panel); |
| 2741 | rate = drm_dp_bw_code_to_link_rate(panel->link->link_params.bw_code); |
| 2742 | stream_rate_khz = dp_panel->pinfo.pixel_clk_khz; |
| 2743 | |
| 2744 | catalog->config_msa(catalog, rate, stream_rate_khz, fixed_nvid); |
| 2745 | } |
| 2746 | |
| 2747 | static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable) |
| 2748 | { |
| 2749 | struct dp_panel_private *panel; |
| 2750 | |
| 2751 | if (!dp_panel) { |
| 2752 | pr_err("invalid input\n"); |
| 2753 | return -EINVAL; |
| 2754 | } |
| 2755 | |
| 2756 | if (dp_panel->stream_id >= DP_STREAM_MAX) { |
| 2757 | pr_err("invalid stream_id: %d\n", dp_panel->stream_id); |
| 2758 | return -EINVAL; |
| 2759 | } |
| 2760 | |
| 2761 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2762 | panel->catalog->stream_id = dp_panel->stream_id; |
| 2763 | |
| 2764 | if (enable) { |
| 2765 | dp_panel_config_ctrl(dp_panel); |
| 2766 | dp_panel_config_misc(dp_panel); |
| 2767 | dp_panel_config_msa(dp_panel); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2768 | dp_panel_config_dsc(dp_panel, enable); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2769 | dp_panel_config_tr_unit(dp_panel); |
| 2770 | dp_panel_config_timing(dp_panel); |
| 2771 | } |
| 2772 | |
| 2773 | panel->catalog->config_dto(panel->catalog, !enable); |
| 2774 | |
| 2775 | return 0; |
| 2776 | } |
| 2777 | |
| 2778 | static int dp_panel_read_sink_sts(struct dp_panel *dp_panel, u8 *sts, u32 size) |
| 2779 | { |
| 2780 | int rlen, rc = 0; |
| 2781 | struct dp_panel_private *panel; |
| 2782 | |
| 2783 | if (!dp_panel || !sts || !size) { |
| 2784 | pr_err("invalid input\n"); |
| 2785 | rc = -EINVAL; |
| 2786 | return rc; |
| 2787 | } |
| 2788 | |
| 2789 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2790 | |
| 2791 | rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_SINK_COUNT_ESI, |
| 2792 | sts, size); |
| 2793 | if (rlen != size) { |
| 2794 | pr_err("dpcd sink sts fail rlen:%d size:%d\n", rlen, size); |
| 2795 | rc = -EINVAL; |
| 2796 | return rc; |
| 2797 | } |
| 2798 | |
| 2799 | return 0; |
| 2800 | } |
| 2801 | |
| 2802 | static int dp_panel_update_edid(struct dp_panel *dp_panel, struct edid *edid) |
| 2803 | { |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2804 | int rc; |
| 2805 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2806 | dp_panel->edid_ctrl->edid = edid; |
| 2807 | sde_parse_edid(dp_panel->edid_ctrl); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2808 | |
| 2809 | rc = _sde_edid_update_modes(dp_panel->connector, dp_panel->edid_ctrl); |
| 2810 | dp_panel->audio_supported = drm_detect_monitor_audio(edid); |
| 2811 | |
| 2812 | return rc; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2813 | } |
| 2814 | |
| 2815 | static bool dp_panel_read_mst_cap(struct dp_panel *dp_panel) |
| 2816 | { |
| 2817 | int rlen; |
| 2818 | struct dp_panel_private *panel; |
| 2819 | u8 dpcd; |
| 2820 | bool mst_cap = false; |
| 2821 | |
| 2822 | if (!dp_panel) { |
| 2823 | pr_err("invalid input\n"); |
| 2824 | goto end; |
| 2825 | } |
| 2826 | |
| 2827 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2828 | |
| 2829 | rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_MSTM_CAP, |
| 2830 | &dpcd, 1); |
| 2831 | if (rlen < 1) { |
| 2832 | pr_err("dpcd mstm_cap read failed, rlen=%d\n", rlen); |
| 2833 | goto end; |
| 2834 | } |
| 2835 | |
| 2836 | mst_cap = (dpcd & DP_MST_CAP) ? true : false; |
| 2837 | |
| 2838 | end: |
| 2839 | pr_debug("dp mst-cap: %d\n", mst_cap); |
| 2840 | |
| 2841 | return mst_cap; |
| 2842 | } |
| 2843 | |
| 2844 | static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, |
| 2845 | const struct drm_display_mode *drm_mode, |
| 2846 | struct dp_display_mode *dp_mode) |
| 2847 | { |
| 2848 | const u32 num_components = 3, default_bpp = 24; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2849 | struct msm_compression_info *comp_info; |
| 2850 | bool dsc_cap = (dp_mode->capabilities & DP_PANEL_CAPS_DSC) ? |
| 2851 | true : false; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2852 | |
| 2853 | dp_mode->timing.h_active = drm_mode->hdisplay; |
| 2854 | dp_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end; |
| 2855 | dp_mode->timing.h_sync_width = drm_mode->htotal - |
| 2856 | (drm_mode->hsync_start + dp_mode->timing.h_back_porch); |
| 2857 | dp_mode->timing.h_front_porch = drm_mode->hsync_start - |
| 2858 | drm_mode->hdisplay; |
| 2859 | dp_mode->timing.h_skew = drm_mode->hskew; |
| 2860 | |
| 2861 | dp_mode->timing.v_active = drm_mode->vdisplay; |
| 2862 | dp_mode->timing.v_back_porch = drm_mode->vtotal - drm_mode->vsync_end; |
| 2863 | dp_mode->timing.v_sync_width = drm_mode->vtotal - |
| 2864 | (drm_mode->vsync_start + dp_mode->timing.v_back_porch); |
| 2865 | |
| 2866 | dp_mode->timing.v_front_porch = drm_mode->vsync_start - |
| 2867 | drm_mode->vdisplay; |
| 2868 | |
| 2869 | dp_mode->timing.refresh_rate = drm_mode->vrefresh; |
| 2870 | |
| 2871 | dp_mode->timing.pixel_clk_khz = drm_mode->clock; |
| 2872 | |
| 2873 | dp_mode->timing.v_active_low = |
| 2874 | !!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC); |
| 2875 | |
| 2876 | dp_mode->timing.h_active_low = |
| 2877 | !!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC); |
| 2878 | |
| 2879 | dp_mode->timing.bpp = |
| 2880 | dp_panel->connector->display_info.bpc * num_components; |
| 2881 | if (!dp_mode->timing.bpp) |
| 2882 | dp_mode->timing.bpp = default_bpp; |
| 2883 | |
| 2884 | dp_mode->timing.bpp = dp_panel_get_mode_bpp(dp_panel, |
| 2885 | dp_mode->timing.bpp, dp_mode->timing.pixel_clk_khz); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2886 | |
| 2887 | dp_mode->timing.widebus_en = dp_panel->widebus_en; |
| 2888 | dp_mode->timing.dsc_overhead_fp = 0; |
| 2889 | |
| 2890 | if (dp_panel->dsc_en && dsc_cap) { |
| 2891 | comp_info = &dp_mode->timing.comp_info; |
| 2892 | |
| 2893 | if (dp_panel_dsc_prepare_basic_params(comp_info, |
| 2894 | dp_mode, dp_panel)) { |
| 2895 | pr_debug("prepare DSC basic params failed\n"); |
| 2896 | return; |
| 2897 | } |
| 2898 | |
| 2899 | dp_panel_dsc_populate_static_params(&comp_info->dsc_info); |
| 2900 | dp_panel_dsc_pclk_param_calc(dp_panel, |
| 2901 | &comp_info->dsc_info, |
| 2902 | comp_info->comp_ratio, |
| 2903 | dp_mode); |
| 2904 | } |
| 2905 | dp_mode->fec_overhead_fp = dp_panel->fec_overhead_fp; |
| 2906 | } |
| 2907 | |
| 2908 | static void dp_panel_update_pps(struct dp_panel *dp_panel, char *pps_cmd) |
| 2909 | { |
| 2910 | struct dp_catalog_panel *catalog; |
| 2911 | struct dp_panel_private *panel; |
| 2912 | |
| 2913 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 2914 | |
| 2915 | catalog = panel->catalog; |
| 2916 | catalog->stream_id = dp_panel->stream_id; |
| 2917 | catalog->pps_flush(catalog); |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2918 | } |
| 2919 | |
| 2920 | struct dp_panel *dp_panel_get(struct dp_panel_in *in) |
| 2921 | { |
| 2922 | int rc = 0; |
| 2923 | struct dp_panel_private *panel; |
| 2924 | struct dp_panel *dp_panel; |
| 2925 | struct sde_connector *sde_conn; |
| 2926 | |
| 2927 | if (!in->dev || !in->catalog || !in->aux || |
| 2928 | !in->link || !in->connector) { |
| 2929 | pr_err("invalid input\n"); |
| 2930 | rc = -EINVAL; |
| 2931 | goto error; |
| 2932 | } |
| 2933 | |
| 2934 | panel = devm_kzalloc(in->dev, sizeof(*panel), GFP_KERNEL); |
| 2935 | if (!panel) { |
| 2936 | rc = -ENOMEM; |
| 2937 | goto error; |
| 2938 | } |
| 2939 | |
| 2940 | panel->dev = in->dev; |
| 2941 | panel->aux = in->aux; |
| 2942 | panel->catalog = in->catalog; |
| 2943 | panel->link = in->link; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2944 | panel->parser = in->parser; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2945 | |
| 2946 | dp_panel = &panel->dp_panel; |
| 2947 | dp_panel->max_bw_code = DP_LINK_BW_8_1; |
| 2948 | dp_panel->spd_enabled = true; |
| 2949 | memcpy(panel->spd_vendor_name, vendor_name, (sizeof(u8) * 8)); |
| 2950 | memcpy(panel->spd_product_description, product_desc, (sizeof(u8) * 16)); |
| 2951 | dp_panel->connector = in->connector; |
| 2952 | |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2953 | dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable; |
| 2954 | dp_panel->fec_feature_enable = panel->parser->fec_feature_enable; |
| 2955 | |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2956 | if (in->base_panel) { |
| 2957 | memcpy(dp_panel->dpcd, in->base_panel->dpcd, |
| 2958 | DP_RECEIVER_CAP_SIZE + 1); |
| 2959 | memcpy(&dp_panel->link_info, &in->base_panel->link_info, |
| 2960 | sizeof(dp_panel->link_info)); |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2961 | dp_panel->mst_state = in->base_panel->mst_state; |
| 2962 | dp_panel->widebus_en = in->base_panel->widebus_en; |
| 2963 | dp_panel->fec_en = in->base_panel->fec_en; |
| 2964 | dp_panel->dsc_en = in->base_panel->dsc_en; |
| 2965 | dp_panel->fec_overhead_fp = in->base_panel->fec_overhead_fp; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2966 | } |
| 2967 | |
| 2968 | dp_panel->init = dp_panel_init_panel_info; |
| 2969 | dp_panel->deinit = dp_panel_deinit_panel_info; |
| 2970 | dp_panel->hw_cfg = dp_panel_hw_cfg; |
| 2971 | dp_panel->read_sink_caps = dp_panel_read_sink_caps; |
| 2972 | dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate; |
| 2973 | dp_panel->get_mode_bpp = dp_panel_get_mode_bpp; |
| 2974 | dp_panel->get_modes = dp_panel_get_modes; |
| 2975 | dp_panel->handle_sink_request = dp_panel_handle_sink_request; |
| 2976 | dp_panel->set_edid = dp_panel_set_edid; |
| 2977 | dp_panel->set_dpcd = dp_panel_set_dpcd; |
| 2978 | dp_panel->tpg_config = dp_panel_tpg_config; |
| 2979 | dp_panel->spd_config = dp_panel_spd_config; |
| 2980 | dp_panel->setup_hdr = dp_panel_setup_hdr; |
| 2981 | dp_panel->hdr_supported = dp_panel_hdr_supported; |
| 2982 | dp_panel->set_stream_info = dp_panel_set_stream_info; |
| 2983 | dp_panel->read_sink_status = dp_panel_read_sink_sts; |
| 2984 | dp_panel->update_edid = dp_panel_update_edid; |
| 2985 | dp_panel->read_mst_cap = dp_panel_read_mst_cap; |
| 2986 | dp_panel->convert_to_dp_mode = dp_panel_convert_to_dp_mode; |
Satya Rama Aditya Pinapala | 10ffbfa | 2019-01-21 11:02:56 -0800 | [diff] [blame] | 2987 | dp_panel->update_pps = dp_panel_update_pps; |
Samantha Tran | 1eae18f | 2018-10-15 14:04:01 -0700 | [diff] [blame] | 2988 | |
| 2989 | sde_conn = to_sde_connector(dp_panel->connector); |
| 2990 | sde_conn->drv_panel = dp_panel; |
| 2991 | |
| 2992 | dp_panel_edid_register(panel); |
| 2993 | |
| 2994 | return dp_panel; |
| 2995 | error: |
| 2996 | return ERR_PTR(rc); |
| 2997 | } |
| 2998 | |
| 2999 | void dp_panel_put(struct dp_panel *dp_panel) |
| 3000 | { |
| 3001 | struct dp_panel_private *panel; |
| 3002 | |
| 3003 | if (!dp_panel) |
| 3004 | return; |
| 3005 | |
| 3006 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
| 3007 | |
| 3008 | dp_panel_edid_deregister(panel); |
| 3009 | devm_kfree(panel->dev, panel); |
| 3010 | } |