Skip to content

Commit ed5efca

Browse files
committed
Move DFM calc to link_frl_training
1 parent e437475 commit ed5efca

3 files changed

Lines changed: 339 additions & 326 deletions

File tree

drivers/gpu/drm/amd/display/dc/core/dc_resource.c

Lines changed: 2 additions & 326 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
#include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h"
5454
#include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h"
5555

56+
#include "link/protocols/link_frl_training.h"
57+
5658
#if defined(CONFIG_DRM_AMD_DC_SI)
5759
#include "dce60/dce60_resource.h"
5860
#endif
@@ -3974,332 +3976,6 @@ static bool acquire_otg_master_pipe_for_stream(
39743976
return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND;
39753977
}
39763978

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-
43033979
enum dc_status resource_map_pool_resources(
43043980
const struct dc *dc,
43053981
struct dc_state *context,

0 commit comments

Comments
 (0)