|
53 | 53 | #include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h" |
54 | 54 | #include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h" |
55 | 55 |
|
| 56 | +#include "link/protocols/link_frl_training.h" |
| 57 | + |
56 | 58 | #if defined(CONFIG_DRM_AMD_DC_SI) |
57 | 59 | #include "dce60/dce60_resource.h" |
58 | 60 | #endif |
@@ -3974,332 +3976,6 @@ static bool acquire_otg_master_pipe_for_stream( |
3974 | 3976 | return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND; |
3975 | 3977 | } |
3976 | 3978 |
|
3977 | | -/* DFM calc |
3978 | | - * References: |
3979 | | - * https://github.com/openharmony/device_soc_hisilicon/blob/master/hi3516dv300/sdk_linux/drv/mpp/component/hdmi/src/mkp/drv_hdmi_dfm.c#L264 |
3980 | | - * https://github.com/jelyoussefi/intel-gpu-i915/blob/e366083d562341ce15d5fe1a39bb6e07f18a4745/drivers/gpu/drm/i915/display/intel_hdmi.c#L4217 |
3981 | | - * TODO Move to separate file in protocols */ |
3982 | | - |
3983 | | -#define DFM_TOLERANCE_PIXEL_CLOCK_PCT_X1000 5 /* +0.50% -> 5/1000 */ |
3984 | | -#define DFM_TOLERANCE_AUDIO_CLOCK_PPM 1000 /* +/- 1000 ppm */ |
3985 | | -#define DFM_TOLERANCE_FRL_BIT_RATE_PPM 300 /* +/- 300 ppm */ |
3986 | | -#define DFM_TB_BORROWED_MAX 400 |
3987 | | -#define DFM_FRL_CFRL_CB 510 |
3988 | | - |
3989 | | -struct dfm_config { |
3990 | | - /* Video Timing */ |
3991 | | - uint32_t pixel_clock_khz; /* Nominal */ |
3992 | | - uint32_t hactive; |
3993 | | - uint32_t hblank; |
3994 | | - uint32_t bpc; /* Bits per component */ |
3995 | | - enum dc_pixel_encoding encoding; |
3996 | | - |
3997 | | - /* FRL Configuration */ |
3998 | | - uint32_t frl_bit_rate_gbps; /* 3, 6, 8, 10, 12 */ |
3999 | | - uint8_t lanes; /* 3 or 4 */ |
4000 | | - |
4001 | | - /* Audio */ |
4002 | | - bool audio_enable; |
4003 | | - uint32_t audio_freq_hz; |
4004 | | - uint8_t audio_channels; |
4005 | | -}; |
4006 | | - |
4007 | | -struct dfm_results { |
4008 | | - /* Calculated Parameters */ |
4009 | | - uint64_t f_pixel_clock_max; |
4010 | | - uint64_t r_frl_char_min; |
4011 | | - uint32_t overhead_ppm; |
4012 | | - |
4013 | | - /* Audio */ |
4014 | | - uint32_t audio_packets_line; |
4015 | | - uint32_t hblank_audio_min; |
4016 | | - |
4017 | | - /* Tri-Bytes */ |
4018 | | - uint32_t tb_active; |
4019 | | - uint32_t tb_blank; |
4020 | | - |
4021 | | - /* Compression */ |
4022 | | - uint32_t cfrl_rc_savings; |
4023 | | - |
4024 | | - /* Timing (ns) */ |
4025 | | - uint64_t t_active_min; |
4026 | | - uint64_t t_active_ref; |
4027 | | - uint64_t t_blank_min; |
4028 | | - uint64_t t_blank_ref; |
4029 | | - |
4030 | | - /* Borrowing */ |
4031 | | - uint64_t tb_borrowed; |
4032 | | - |
4033 | | - /* Utilization */ |
4034 | | - uint32_t cfrl_line; |
4035 | | - uint32_t cfrl_actual_payload; |
4036 | | - int32_t margin_ppm; /* Can be negative */ |
4037 | | - |
4038 | | - /* Pass/Fail Flags */ |
4039 | | - bool audio_supported; |
4040 | | - bool dfm_supported; |
4041 | | - bool utilization_supported; |
4042 | | - bool total_supported; |
4043 | | -}; |
4044 | | - |
4045 | | - |
4046 | | -#define CEILING(x, y) (((x) + (y) - 1) / (y)) |
4047 | | - |
4048 | | -static uint32_t calc_overhead_ppm(uint8_t lanes) |
4049 | | -{ |
4050 | | - uint32_t cfrl_sb = (4 * 510) + lanes; |
4051 | | - |
4052 | | - uint64_t oh_sb_num = (uint64_t)lanes * 1000000ULL; |
4053 | | - uint32_t oh_sb = (uint32_t)((oh_sb_num + (cfrl_sb/2)) / cfrl_sb); /* Rounding */ |
4054 | | - |
4055 | | - uint64_t oh_rs_num = 32ULL * 1000000ULL; |
4056 | | - uint32_t oh_rs = (uint32_t)((oh_rs_num + (cfrl_sb/2)) / cfrl_sb); |
4057 | | - |
4058 | | - uint64_t oh_map_num = 2500000ULL; /* 2.5 * 1M */ |
4059 | | - uint32_t oh_map = (uint32_t)((oh_map_num + (cfrl_sb/2)) / cfrl_sb); |
4060 | | - |
4061 | | - uint32_t oh_m = 3000; |
4062 | | - |
4063 | | - return oh_sb + oh_rs + oh_map + oh_m; |
4064 | | -} |
4065 | | - |
4066 | | -static void calc_audio(const struct dfm_config *cfg, |
4067 | | - uint64_t t_line_ns, |
4068 | | - struct dfm_results *res) |
4069 | | -{ |
4070 | | - if (!cfg->audio_enable) { |
4071 | | - res->audio_packets_line = 0; |
4072 | | - res->hblank_audio_min = 64; |
4073 | | - return; |
4074 | | - } |
4075 | | - |
4076 | | - uint32_t ap = 1; |
4077 | | - if (cfg->audio_channels > 22) { |
4078 | | - ap = 4; /* ACAT 3 (up to 30.2ch) */ |
4079 | | - } else if (cfg->audio_channels > 10) { |
4080 | | - ap = 3; /* ACAT 2 (up to 22.2ch) */ |
4081 | | - } else if (cfg->audio_channels > 8) { |
4082 | | - ap = 2; /* ACAT 1 (up to 10.2ch) */ |
4083 | | - } else { |
4084 | | - ap = 1; /* Layout 0/1 */ |
4085 | | - } |
4086 | | - |
4087 | | - uint64_t rap = (uint64_t)cfg->audio_freq_hz * (1000000 + DFM_TOLERANCE_AUDIO_CLOCK_PPM); |
4088 | | - rap = (rap * ap) / 1000000; |
4089 | | - |
4090 | | - uint64_t avg_pkts_x1000 = (rap * t_line_ns) / 1000000; /* ns to ms scale */ |
4091 | | - |
4092 | | - res->audio_packets_line = (uint32_t)((avg_pkts_x1000 + 999) / 1000); |
4093 | | - |
4094 | | - res->hblank_audio_min = 64 + (32 * res->audio_packets_line); |
4095 | | -} |
4096 | | - |
4097 | | -/* Table 6-44: RC Compression Savings */ |
4098 | | -static void calc_rc_compression(const struct dfm_config *cfg, struct dfm_results *res) |
4099 | | -{ |
4100 | | - uint32_t k420 = (cfg->encoding == PIXEL_ENCODING_YCBCR420) ? 2 : 1; |
4101 | | - uint32_t kcd = (cfg->encoding == PIXEL_ENCODING_YCBCR422) ? 1 : cfg->bpc; |
4102 | | - |
4103 | | - uint64_t raw_num = (uint64_t)cfg->hblank * kcd * 8; |
4104 | | - uint64_t raw_den = (uint64_t)k420 * 7; |
4105 | | - uint32_t raw_capacity = (uint32_t)(raw_num / raw_den); /* FLOOR */ |
4106 | | - |
4107 | | - uint32_t deduct = 32 * (1 + res->audio_packets_line) + 7; |
4108 | | - int32_t free_chars = (int32_t)raw_capacity - (int32_t)deduct; |
4109 | | - |
4110 | | - if (free_chars < 0) free_chars = 0; |
4111 | | - |
4112 | | - int32_t margin = 4; |
4113 | | - |
4114 | | - int32_t base = free_chars - margin; |
4115 | | - if (base < 0) base = 0; |
4116 | | - |
4117 | | - res->cfrl_rc_savings = (uint32_t)((base * 7) / 8); |
4118 | | -} |
4119 | | - |
4120 | | -/* Core DFM Check Function */ |
4121 | | -static void perform_dfm_check(const struct dfm_config *cfg, struct dfm_results *res) |
4122 | | -{ |
4123 | | - memset(res, 0, sizeof(struct dfm_results)); |
4124 | | - |
4125 | | - uint32_t htotal = cfg->hactive + cfg->hblank; |
4126 | | - |
4127 | | - res->overhead_ppm = calc_overhead_ppm(cfg->lanes); |
4128 | | - |
4129 | | - res->f_pixel_clock_max = (uint64_t)cfg->pixel_clock_khz * 1000; |
4130 | | - res->f_pixel_clock_max = res->f_pixel_clock_max * (1000 + DFM_TOLERANCE_PIXEL_CLOCK_PCT_X1000) / 1000; |
4131 | | - |
4132 | | - uint64_t t_line_ns = ((uint64_t)htotal * 1000000000ULL) / res->f_pixel_clock_max; |
4133 | | - |
4134 | | - uint64_t r_bit_nominal = (uint64_t)cfg->frl_bit_rate_gbps * 1000000000ULL; |
4135 | | - uint64_t r_bit_min = r_bit_nominal * (1000000 - DFM_TOLERANCE_FRL_BIT_RATE_PPM) / 1000000; |
4136 | | - |
4137 | | - res->r_frl_char_min = r_bit_min / 18; |
4138 | | - |
4139 | | - uint64_t cap_calc = (t_line_ns * res->r_frl_char_min * cfg->lanes) / 1000000000ULL; |
4140 | | - res->cfrl_line = (uint32_t)cap_calc; |
4141 | | - |
4142 | | - calc_audio(cfg, t_line_ns, res); |
4143 | | - |
4144 | | - calc_rc_compression(cfg, res); |
4145 | | - |
4146 | | - uint32_t bpp; |
4147 | | - uint32_t k420 = (cfg->encoding == PIXEL_ENCODING_YCBCR420) ? 2 : 1; |
4148 | | - uint32_t kcd = (cfg->encoding == PIXEL_ENCODING_YCBCR422) ? 1 : cfg->bpc; |
4149 | | - |
4150 | | - bpp = (24 * kcd) / (k420 * 8); |
4151 | | - |
4152 | | - uint64_t bytes_line = ((uint64_t)bpp * cfg->hactive) / 8; |
4153 | | - |
4154 | | - res->tb_active = (uint32_t)CEILING(bytes_line, 3); |
4155 | | - |
4156 | | - uint64_t tb_blank_num = (uint64_t)cfg->hblank * kcd; |
4157 | | - uint64_t tb_blank_den = (uint64_t)k420 * 8; |
4158 | | - res->tb_blank = (uint32_t)CEILING(tb_blank_num, tb_blank_den); |
4159 | | - |
4160 | | - if (res->hblank_audio_min <= res->tb_blank) { |
4161 | | - res->audio_supported = true; |
4162 | | - } else { |
4163 | | - res->audio_supported = false; |
4164 | | - res->total_supported = false; |
4165 | | - return; |
4166 | | - } |
4167 | | - |
4168 | | - uint64_t tb_total = res->tb_active + res->tb_blank; |
4169 | | - uint64_t f_tb_avg = (res->f_pixel_clock_max * tb_total) / htotal; |
4170 | | - |
4171 | | - res->t_active_ref = (t_line_ns * cfg->hactive) / htotal; |
4172 | | - |
4173 | | - res->t_blank_ref = (t_line_ns * cfg->hblank) / htotal; |
4174 | | - |
4175 | | - uint64_t r_frl_eff = res->r_frl_char_min * (1000000 - res->overhead_ppm) / 1000000; |
4176 | | - |
4177 | | - res->t_active_min = (3ULL * res->tb_active * 1000000000ULL) / (2ULL * cfg->lanes * r_frl_eff); |
4178 | | - |
4179 | | - res->t_blank_min = (res->tb_blank * 1000000000ULL) / (cfg->lanes * r_frl_eff); |
4180 | | - |
4181 | | - if (res->t_active_ref >= res->t_active_min && res->t_blank_ref >= res->t_blank_min) { |
4182 | | - res->tb_borrowed = 0; |
4183 | | - res->dfm_supported = true; |
4184 | | - } else if (res->t_active_ref < res->t_active_min) { |
4185 | | - uint64_t borrow_time_ns = res->t_active_min - res->t_active_ref; |
4186 | | - |
4187 | | - res->tb_borrowed = CEILING(borrow_time_ns * f_tb_avg, 1000000000ULL); |
4188 | | - |
4189 | | - if (res->tb_borrowed <= DFM_TB_BORROWED_MAX) { |
4190 | | - res->dfm_supported = true; |
4191 | | - } else { |
4192 | | - res->dfm_supported = false; |
4193 | | - } |
4194 | | - } else { |
4195 | | - /* Blanking needs more time than available */ |
4196 | | - res->dfm_supported = false; |
4197 | | - } |
4198 | | - |
4199 | | - if (!res->dfm_supported) { |
4200 | | - res->total_supported = false; |
4201 | | - return; |
4202 | | - } |
4203 | | - |
4204 | | - uint64_t total_chars_req = (3 * tb_total) / 2; |
4205 | | - if (total_chars_req > res->cfrl_rc_savings) { |
4206 | | - res->cfrl_actual_payload = (uint32_t)CEILING((total_chars_req - res->cfrl_rc_savings), 1); |
4207 | | - } else { |
4208 | | - res->cfrl_actual_payload = 0; |
4209 | | - } |
4210 | | - |
4211 | | - uint64_t util_ppm = ((uint64_t)res->cfrl_actual_payload * 1000000ULL) / res->cfrl_line; |
4212 | | - |
4213 | | - int32_t margin_ppm = 1000000 - (int32_t)util_ppm + (int32_t)res->overhead_ppm; |
4214 | | - res->margin_ppm = margin_ppm; |
4215 | | - |
4216 | | - if (margin_ppm >= 0) { |
4217 | | - res->utilization_supported = true; |
4218 | | - res->total_supported = true; |
4219 | | - } else { |
4220 | | - res->utilization_supported = false; |
4221 | | - res->total_supported = false; |
4222 | | - } |
4223 | | -} |
4224 | | - |
4225 | | -static bool hdmi_decide_link_settings( |
4226 | | - struct dc_stream_state *stream, |
4227 | | - struct pipe_ctx *pipe_ctx) |
4228 | | -{ |
4229 | | - struct dfm_config cfg; |
4230 | | - struct dfm_results res; |
4231 | | - uint8_t frl_rate; |
4232 | | - static const uint32_t frl_rates_gbps[] = {3, 6, 6, 8, 10, 12}; |
4233 | | - uint8_t max_rate = stream->link->local_sink->edid_caps.frl_caps.max_rate; |
4234 | | - uint8_t best_borrow_rate = 0; |
4235 | | - uint8_t best_borrow_lanes = 0; |
4236 | | - struct dfm_results best_borrow_res = {0}; |
4237 | | - |
4238 | | - if (max_rate == 0 || max_rate > 6) |
4239 | | - return false; |
4240 | | - |
4241 | | - memset(&cfg, 0, sizeof(cfg)); |
4242 | | - |
4243 | | - cfg.pixel_clock_khz = stream->timing.pix_clk_100hz / 10; |
4244 | | - cfg.hactive = stream->timing.h_addressable; |
4245 | | - cfg.hblank = stream->timing.h_total - stream->timing.h_addressable; |
4246 | | - cfg.encoding = stream->timing.pixel_encoding; |
4247 | | - |
4248 | | - switch (stream->timing.display_color_depth) { |
4249 | | - case COLOR_DEPTH_888: cfg.bpc = 8; break; |
4250 | | - case COLOR_DEPTH_101010: cfg.bpc = 10; break; |
4251 | | - case COLOR_DEPTH_121212: cfg.bpc = 12; break; |
4252 | | - case COLOR_DEPTH_161616: cfg.bpc = 16; break; |
4253 | | - default: |
4254 | | - cfg.bpc = 8; |
4255 | | - break; |
4256 | | - } |
4257 | | - |
4258 | | - if (stream->audio_info.mode_count) { |
4259 | | - cfg.audio_enable = true; |
4260 | | - /* If we assume the worst case (e.g. 192KHz 32 channel audio) we risk |
4261 | | - * unfairly pruning low res modes with short Hblank periods. Instead, |
4262 | | - * assume a standard surround sound mode that should allow all video |
4263 | | - * modes to work. |
4264 | | - */ |
4265 | | - cfg.audio_freq_hz = 48000; |
4266 | | - cfg.audio_channels = 8; |
4267 | | - } |
4268 | | - |
4269 | | - for (frl_rate = 1; frl_rate <= max_rate; frl_rate++) { |
4270 | | - cfg.frl_bit_rate_gbps = frl_rates_gbps[frl_rate - 1]; |
4271 | | - cfg.lanes = (frl_rate <= 2) ? 3 : 4; |
4272 | | - |
4273 | | - perform_dfm_check(&cfg, &res); |
4274 | | - |
4275 | | - if (res.total_supported) { |
4276 | | - if (res.tb_borrowed == 0) { |
4277 | | - pipe_ctx->link_config.dp_link_settings.frl_rate = frl_rate; |
4278 | | - pipe_ctx->link_config.dp_link_settings.lane_count = cfg.lanes; |
4279 | | - |
4280 | | - pr_info("HDMI FRL: Rate %d Supported. Borrowed: 0, Margin: %d ppm\n", |
4281 | | - frl_rate, res.margin_ppm); |
4282 | | - return true; |
4283 | | - } else if (best_borrow_rate == 0) { |
4284 | | - best_borrow_rate = frl_rate; |
4285 | | - best_borrow_lanes = cfg.lanes; |
4286 | | - best_borrow_res = res; |
4287 | | - } |
4288 | | - } |
4289 | | - } |
4290 | | - |
4291 | | - if (best_borrow_rate > 0) { |
4292 | | - pipe_ctx->link_config.dp_link_settings.frl_rate = best_borrow_rate; |
4293 | | - pipe_ctx->link_config.dp_link_settings.lane_count = best_borrow_lanes; |
4294 | | - |
4295 | | - pr_info("HDMI FRL: Rate %d Supported (with borrowing). Borrowed: %llu, Margin: %d ppm\n", |
4296 | | - best_borrow_rate, best_borrow_res.tb_borrowed, best_borrow_res.margin_ppm); |
4297 | | - return true; |
4298 | | - } |
4299 | | - |
4300 | | - return false; |
4301 | | -} |
4302 | | - |
4303 | 3979 | enum dc_status resource_map_pool_resources( |
4304 | 3980 | const struct dc *dc, |
4305 | 3981 | struct dc_state *context, |
|
0 commit comments