drm/rockchip: vop2: Support hdmi qms-vrr

Change-Id: Icc2931661b50a3a8168a98b983a676a74a9ba9da
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
This commit is contained in:
Algea Cao
2025-02-24 17:09:02 +08:00
parent da450eccf5
commit d0e8f558bc
3 changed files with 721 additions and 17 deletions

View File

@@ -78,6 +78,502 @@ static const struct drm_driver rockchip_drm_driver;
static unsigned int drm_debug;
module_param_named(debug, drm_debug, int, 0600);
static const u16 tfr_vrefresh_table[TFR_MAX] = {
[TFR_QMSVRR_INACTIVE] = 0,
[TFR_23P97] = 2397,
[TFR_24] = 2400,
[TFR_25] = 2500,
[TFR_29P97] = 2997,
[TFR_30] = 3000,
[TFR_47P95] = 4795,
[TFR_48] = 4800,
[TFR_50] = 5000,
[TFR_59P94] = 5994,
[TFR_60] = 6000,
[TFR_100] = 10000,
[TFR_119P88] = 11988,
[TFR_120] = 12000,
};
/* BRR 720p60hz */
static const struct mvrr_const_val const_hdmi720p60_6000 = {
.vrefresh_khz = 6000,
.vtotal_fixed = 750,
};
/**
* @vrefresh_khz: qms-vrr target refresh rate is 59.94Hz
* @vtotal_fixed: When switch to target refresh rate, vtotal is 750
* @bit_len: frac_array's bit length
* @frac_array: Sources may also alternate between two sequential values
* of actual vtotal to better approximate the target refresh
* rate when target vtotal is fractional. For this example,
* the source vtotal would vary between 750 and 751.
* The value in frac_array indicates the order in which the
* vtotal changes during this process. Each bit of 0 indicates
* that the current frame vtotal is 750, and each bit of 1
* indicates that the current frame vtotal is 751.
* Take 0x3f(00111111B) as an example, it represents a vtotal
* of 750 for the first and second frames, and 751 for the
* remaining six frames. 0xe3 and 0xfe also have the same meaning.
* The current frac_array represents the value of vtotal for 24
* consecutive frames.
*/
static const struct mvrr_const_val const_hdmi720p60_5994 = {
.vrefresh_khz = 5994,
.vtotal_fixed = 750, /* 0.75 */
.bit_len = 24,
.frac_array = {0x3f, 0xe3, 0xfe},
};
static const struct mvrr_const_val const_hdmi720p60_5000 = {
.vrefresh_khz = 5000,
.vtotal_fixed = 900,
};
static const struct mvrr_const_val const_hdmi720p60_4800 = {
.vrefresh_khz = 4800,
.vtotal_fixed = 937, /* 0.5 */
.bit_len = 8,
.frac_array = {0x3c},
};
static const struct mvrr_const_val const_hdmi720p60_4795 = {
.vrefresh_khz = 4795,
.vtotal_fixed = 938, /* 0.4375 */
.bit_len = 16,
.frac_array = {0x1e, 0x0e},
};
static const struct mvrr_const_val const_hdmi720p60_3000 = {
.vrefresh_khz = 3000,
.vtotal_fixed = 1500,
};
static const struct mvrr_const_val const_hdmi720p60_2997 = {
.vrefresh_khz = 2997,
.vtotal_fixed = 1501, /* 0.5 */
.bit_len = 56,
.frac_array = {0x1f, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xf8},
};
static const struct mvrr_const_val const_hdmi720p60_2500 = {
.vrefresh_khz = 2500,
.vtotal_fixed = 1800,
};
static const struct mvrr_const_val const_hdmi720p60_2400 = {
.vrefresh_khz = 2400,
.vtotal_fixed = 1875,
};
static const struct mvrr_const_val const_hdmi720p60_2397 = {
.vrefresh_khz = 2397,
.vtotal_fixed = 1876, /* 0.875 */
.bit_len = 40,
.frac_array = {0x1f, 0xff, 0xff, 0xff, 0xfc},
};
/* BRR 720p120hz */
static const struct mvrr_const_val const_hdmi720p120_12000 = {
.vrefresh_khz = 12000,
.vtotal_fixed = 750,
};
static const struct mvrr_const_val const_hdmi720p120_11988 = {
.vrefresh_khz = 11988,
.vtotal_fixed = 750, /* 0.75 */
.bit_len = 24,
.frac_array = {0x3f, 0xe3, 0xfe},
};
static const struct mvrr_const_val const_hdmi720p120_10000 = {
.vrefresh_khz = 10000,
.vtotal_fixed = 900,
};
static const struct mvrr_const_val const_hdmi720p120_6000 = {
.vrefresh_khz = 6000,
.vtotal_fixed = 1500,
};
static const struct mvrr_const_val const_hdmi720p120_5994 = {
.vrefresh_khz = 5994,
.vtotal_fixed = 1501, /* 0.5 */
.bit_len = 56,
.frac_array = {0x0f, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xf8},
};
static const struct mvrr_const_val const_hdmi720p120_5000 = {
.vrefresh_khz = 5000,
.vtotal_fixed = 1800,
};
static const struct mvrr_const_val const_hdmi720p120_4800 = {
.vrefresh_khz = 4800,
.vtotal_fixed = 1875,
};
static const struct mvrr_const_val const_hdmi720p120_4795 = {
.vrefresh_khz = 4795,
.vtotal_fixed = 1876, /* 0.875 */
.bit_len = 40,
.frac_array = {0x1f, 0xff, 0xff, 0xff, 0xfc},
};
static const struct mvrr_const_val const_hdmi720p120_3000 = {
.vrefresh_khz = 3000,
.vtotal_fixed = 3000,
};
static const struct mvrr_const_val const_hdmi720p120_2997 = {
.vrefresh_khz = 2997,
.vtotal_fixed = 3003,
};
static const struct mvrr_const_val const_hdmi720p120_2500 = {
.vrefresh_khz = 2500,
.vtotal_fixed = 3600,
};
static const struct mvrr_const_val const_hdmi720p120_2400 = {
.vrefresh_khz = 2400,
.vtotal_fixed = 3750,
};
static const struct mvrr_const_val const_hdmi720p120_2397 = {
.vrefresh_khz = 2397,
.vtotal_fixed = 3753, /* 0.75 */
.bit_len = 88,
.frac_array = {
0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0
},
};
/* BRR 1080p60hz */
static const struct mvrr_const_val const_hdmi1080p60_6000 = {
.vrefresh_khz = 6000,
.vtotal_fixed = 1125,
};
static const struct mvrr_const_val const_hdmi1080p60_5994 = {
.vrefresh_khz = 5994,
.vtotal_fixed = 1126, /* 0.125 */
.bit_len = 24,
.frac_array = {0x00, 0x38, 0x00},
};
static const struct mvrr_const_val const_hdmi1080p60_5000 = {
.vrefresh_khz = 5000,
.vtotal_fixed = 1350,
};
static const struct mvrr_const_val const_hdmi1080p60_4800 = {
.vrefresh_khz = 4800,
.vtotal_fixed = 1406, /* 0.25 */
.bit_len = 16,
.frac_array = {0x03, 0xc0},
};
static const struct mvrr_const_val const_hdmi1080p60_4795 = {
.vrefresh_khz = 4795,
.vtotal_fixed = 1407, /* 0.65625 */
.bit_len = 32,
.frac_array = {0x1f, 0xf1, 0x7f, 0xf0},
};
static const struct mvrr_const_val const_hdmi1080p60_3000 = {
.vrefresh_khz = 3000,
.vtotal_fixed = 2250,
};
static const struct mvrr_const_val const_hdmi1080p60_2997 = {
.vrefresh_khz = 2997,
.vtotal_fixed = 2252, /* 0.25 */
.bit_len = 56,
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00},
};
static const struct mvrr_const_val const_hdmi1080p60_2500 = {
.vrefresh_khz = 2500,
.vtotal_fixed = 2700,
};
static const struct mvrr_const_val const_hdmi1080p60_2400 = {
.vrefresh_khz = 2400,
.vtotal_fixed = 2812, /* 0.5 */
.bit_len = 24,
.frac_array = {0x03, 0xff, 0xc0},
};
static const struct mvrr_const_val const_hdmi1080p60_2397 = {
.vrefresh_khz = 2397,
.vtotal_fixed = 2815, /* 0.3125 */
.bit_len = 128,
.frac_array = {
0x00, 0x7f, 0x80, 0x00, 0x3f, 0xc0, 0x00, 0x0f,
0xf0, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00,
},
};
/* BRR 1080p120hz */
static const struct mvrr_const_val const_hdmi1080p120_12000 = {
.vrefresh_khz = 12000,
.vtotal_fixed = 1125,
};
static const struct mvrr_const_val const_hdmi1080p120_11988 = {
.vrefresh_khz = 11988,
.vtotal_fixed = 1126, /* 0.125 */
.bit_len = 24,
.frac_array = {0x00, 0x38, 0x00},
};
static const struct mvrr_const_val const_hdmi1080p120_10000 = {
.vrefresh_khz = 10000,
.vtotal_fixed = 1350,
};
static const struct mvrr_const_val const_hdmi1080p120_6000 = {
.vrefresh_khz = 6000,
.vtotal_fixed = 2250,
};
static const struct mvrr_const_val const_hdmi1080p120_5994 = {
.vrefresh_khz = 5994,
.vtotal_fixed = 2252, /* 0.25 */
.bit_len = 56,
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00},
};
static const struct mvrr_const_val const_hdmi1080p120_5000 = {
.vrefresh_khz = 5000,
.vtotal_fixed = 2700,
};
static const struct mvrr_const_val const_hdmi1080p120_4800 = {
.vrefresh_khz = 4800,
.vtotal_fixed = 2812, /* 0.5 */
.bit_len = 24,
.frac_array = {0x03, 0xff, 0xc0},
};
static const struct mvrr_const_val const_hdmi1080p120_4795 = {
.vrefresh_khz = 4795,
.vtotal_fixed = 2812, /* 0.3125 */
.bit_len = 48,
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x3f, 0xc0},
};
static const struct mvrr_const_val const_hdmi1080p120_3000 = {
.vrefresh_khz = 3000,
.vtotal_fixed = 4500,
};
static const struct mvrr_const_val const_hdmi1080p120_2997 = {
.vrefresh_khz = 2997,
.vtotal_fixed = 4504, /* 0.5 */
.bit_len = 32,
.frac_array = {0x00, 0xff, 0xff, 0x00},
};
static const struct mvrr_const_val const_hdmi1080p120_2500 = {
.vrefresh_khz = 2500,
.vtotal_fixed = 5400,
};
static const struct mvrr_const_val const_hdmi1080p120_2400 = {
.vrefresh_khz = 2400,
.vtotal_fixed = 5625,
};
static const struct mvrr_const_val const_hdmi1080p120_2397 = {
.vrefresh_khz = 2397,
.vtotal_fixed = 5630, /* 0.625 */
.bit_len = 48,
.frac_array = {0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00},
};
/* BRR 2160p60hz */
static const struct mvrr_const_val const_hdmi2160p60_6000 = {
.vrefresh_khz = 6000,
.vtotal_fixed = 2250,
};
static const struct mvrr_const_val const_hdmi2160p60_5994 = {
.vrefresh_khz = 5994,
.vtotal_fixed = 2252, /* 0.25 */
.bit_len = 56,
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x03, 0xf8, 0x00},
};
static const struct mvrr_const_val const_hdmi2160p60_5000 = {
.vrefresh_khz = 5000,
.vtotal_fixed = 2700,
};
static const struct mvrr_const_val const_hdmi2160p60_4800 = {
.vrefresh_khz = 4800,
.vtotal_fixed = 2812, /* 0.5 */
.bit_len = 24,
.frac_array = {0x03, 0xff, 0xc0},
};
static const struct mvrr_const_val const_hdmi2160p60_4795 = {
.vrefresh_khz = 4795,
.vtotal_fixed = 2815, /* 0.3125 */
.bit_len = 48,
.frac_array = {0x00, 0x3f, 0x80, 0x00, 0x3f, 0xc0},
};
static const struct mvrr_const_val const_hdmi2160p60_3000 = {
.vrefresh_khz = 3000,
.vtotal_fixed = 4500,
};
static const struct mvrr_const_val const_hdmi2160p60_2997 = {
.vrefresh_khz = 2997,
.vtotal_fixed = 4504, /* 0.5 */
.bit_len = 32,
.frac_array = {0x00, 0xff, 0xff, 0x00},
};
static const struct mvrr_const_val const_hdmi2160p60_2500 = {
.vrefresh_khz = 2500,
.vtotal_fixed = 5400,
};
static const struct mvrr_const_val const_hdmi2160p60_2400 = {
.vrefresh_khz = 2400,
.vtotal_fixed = 5625,
};
static const struct mvrr_const_val const_hdmi2160p60_2397 = {
.vrefresh_khz = 2397,
.vtotal_fixed = 5630, /* 0.625 */
.bit_len = 48,
.frac_array = {0x00, 0x3f, 0xff, 0xff, 0xff, 0x00},
};
const struct mvrr_const_st const_hdmi1080p60_val = {
.brr_vic = HDMI_16_1920x1080P60_16x9,
.val = {
&const_hdmi1080p60_6000,
&const_hdmi1080p60_5994,
&const_hdmi1080p60_5000,
&const_hdmi1080p60_4800,
&const_hdmi1080p60_4795,
&const_hdmi1080p60_3000,
&const_hdmi1080p60_2997,
&const_hdmi1080p60_2500,
&const_hdmi1080p60_2400,
&const_hdmi1080p60_2397,
NULL,
},
};
const struct mvrr_const_st const_hdmi1080p120_val = {
.brr_vic = HDMI_63_1920x1080P120_16x9,
.val = {
&const_hdmi1080p120_12000,
&const_hdmi1080p120_11988,
&const_hdmi1080p120_10000,
&const_hdmi1080p120_6000,
&const_hdmi1080p120_5994,
&const_hdmi1080p120_5000,
&const_hdmi1080p120_4800,
&const_hdmi1080p120_4795,
&const_hdmi1080p120_3000,
&const_hdmi1080p120_2997,
&const_hdmi1080p120_2500,
&const_hdmi1080p120_2400,
&const_hdmi1080p120_2397,
NULL,
},
};
const struct mvrr_const_st const_hdmi720p60_val = {
.brr_vic = HDMI_4_1280x720P60_16x9,
.val = {
&const_hdmi720p60_6000,
&const_hdmi720p60_5994,
&const_hdmi720p60_5000,
&const_hdmi720p60_4800,
&const_hdmi720p60_4795,
&const_hdmi720p60_3000,
&const_hdmi720p60_2997,
&const_hdmi720p60_2500,
&const_hdmi720p60_2400,
&const_hdmi720p60_2397,
NULL,
},
};
const struct mvrr_const_st const_hdmi720p120_val = {
.brr_vic = HDMI_47_1280x720P120_16x9,
.val = {
&const_hdmi720p120_12000,
&const_hdmi720p120_11988,
&const_hdmi720p120_10000,
&const_hdmi720p120_6000,
&const_hdmi720p120_5994,
&const_hdmi720p120_5000,
&const_hdmi720p120_4800,
&const_hdmi720p120_4795,
&const_hdmi720p120_3000,
&const_hdmi720p120_2997,
&const_hdmi720p120_2500,
&const_hdmi720p120_2400,
&const_hdmi720p120_2397,
NULL,
},
};
const struct mvrr_const_st const_hdmi2160p60_val = {
.brr_vic = HDMI_97_3840x2160P60_16x9,
.val = {
&const_hdmi2160p60_6000,
&const_hdmi2160p60_5994,
&const_hdmi2160p60_5000,
&const_hdmi2160p60_4800,
&const_hdmi2160p60_4795,
&const_hdmi2160p60_3000,
&const_hdmi2160p60_2997,
&const_hdmi2160p60_2500,
&const_hdmi2160p60_2400,
&const_hdmi2160p60_2397,
NULL,
},
};
/* The vtotal parameters of 4096x2160p60hz are the same as 3840x2160p60hz */
const struct mvrr_const_st const_hdmismpte60_val = {
.brr_vic = HDMI_102_4096x2160P60_256x135,
.val = {
&const_hdmi2160p60_6000,
&const_hdmi2160p60_5994,
&const_hdmi2160p60_5000,
&const_hdmi2160p60_4800,
&const_hdmi2160p60_4795,
&const_hdmi2160p60_3000,
&const_hdmi2160p60_2997,
&const_hdmi2160p60_2500,
&const_hdmi2160p60_2400,
&const_hdmi2160p60_2397,
NULL,
},
};
const struct mvrr_const_st *qms_const[] = {
&const_hdmi1080p60_val,
&const_hdmi1080p120_val,
&const_hdmi2160p60_val,
&const_hdmi720p60_val,
&const_hdmi720p120_val,
&const_hdmismpte60_val,
NULL,
};
static inline bool rockchip_drm_debug_enabled(enum rockchip_drm_debug_category category)
{
return unlikely(drm_debug & category);
@@ -1259,6 +1755,63 @@ void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc)
priv->crtc_funcs[pipe] = NULL;
}
u16 rockchip_hdmi_vrr_tfr_match_to_vrefresh(u8 tfr)
{
if (tfr < 0 || tfr >= TFR_MAX) {
DRM_ERROR("qms-vrr tfr is out of range\n");
return 0;
}
return tfr_vrefresh_table[tfr];
}
const struct
mvrr_const_val *rockchip_hdmi_vrr_get_vrrconf_mconst(enum hdmi_brr_vic brr_vic, u16 vrefresh_khz)
{
const struct mvrr_const_st **table_vic = NULL;
const struct mvrr_const_val *const *table_val = NULL;
for (table_vic = qms_const; table_vic; table_vic++) {
if ((*table_vic)->brr_vic == brr_vic) {
table_val = (*table_vic)->val;
for (; table_val; table_val++) {
if ((*table_val)->vrefresh_khz == vrefresh_khz)
break;
}
break;
}
}
if (!table_val) {
DRM_ERROR("%s[%d] not find brr_vic: %d vrefresh_khz: %d\n",
__func__, __LINE__, brr_vic, vrefresh_khz);
return NULL;
}
return *table_val;
}
u16 rockchip_hdmi_vrr_calc_new_vtotal(const struct mvrr_const_val *mvrr, u32 frame_cnt)
{
u32 pos;
u16 vtotal = 0;
if (!mvrr)
return vtotal;
vtotal = mvrr->vtotal_fixed;
/* if bit_len is 0, then means there is no fraction */
if (!mvrr->bit_len)
return vtotal;
/* calculate the fraction number */
pos = frame_cnt % mvrr->bit_len;
if (mvrr->frac_array[pos / 8] & (1 << (7 - (pos % 8))))
vtotal++;
return vtotal;
}
/*
* a high frequency of page faults will follow up, if
* there is a iommu fault, so it's better to limit the

View File

@@ -266,6 +266,14 @@ struct post_sharp {
u32 regs[SHARP_REG_LENGTH / 4];
};
struct rockchip_hdmi_vrr_state {
bool refresh_rate_ready_to_change;
bool m_const;
u8 next_tfr_val;
unsigned int vrr_frame_cnt;
const struct mvrr_const_val *mconst_val;
};
struct rockchip_crtc_state {
struct drm_crtc_state base;
int vp_id;
@@ -344,6 +352,7 @@ struct rockchip_crtc_state {
struct drm_dsc_picture_parameter_set pps;
struct rockchip_dsc_sink_cap dsc_sink_cap;
struct rockchip_hdr_state hdr;
struct rockchip_hdmi_vrr_state hdmi_vrr;
struct drm_property_blob *hdr_ext_data;
struct drm_property_blob *acm_lut_data;
struct drm_property_blob *post_csc_data;
@@ -494,6 +503,47 @@ struct next_hdr_sink_data {
struct ver_12_v2 ver_12_v2;
} __packed;
/* refer to HDMI2.1B P453 */
enum TARGET_FRAME_RATE {
TFR_QMSVRR_INACTIVE = 0,
TFR_23P97,
TFR_24,
TFR_25,
TFR_29P97,
TFR_30,
TFR_47P95,
TFR_48,
TFR_50,
TFR_59P94,
TFR_60,
TFR_100,
TFR_119P88,
TFR_120,
TFR_MAX,
};
enum hdmi_brr_vic {
HDMI_16_1920x1080P60_16x9 = 16,
HDMI_63_1920x1080P120_16x9 = 63,
HDMI_4_1280x720P60_16x9 = 4,
HDMI_47_1280x720P120_16x9 = 47,
HDMI_97_3840x2160P60_16x9 = 97,
HDMI_102_4096x2160P60_256x135 = 102,
};
struct mvrr_const_val {
/* unit: 100 6000, 5994, 5000, 3000, 2997, 2500, 2400, 2397 */
u16 vrefresh_khz;
u16 vtotal_fixed; /* vtotal_fixed is mutex with bit_len */
u8 bit_len; /* current max value is 16 * 8, 128 */
u8 frac_array[16];
};
struct mvrr_const_st {
enum hdmi_brr_vic brr_vic; /* the vic of brr */
const struct mvrr_const_val *val[];
};
/*
* Rockchip drm private crtc funcs.
* @loader_protect: protect loader logo crtc's power
@@ -721,6 +771,10 @@ __printf(3, 4)
void rockchip_drm_dbg_thread_info(const struct device *dev,
enum rockchip_drm_debug_category category,
const char *format, ...);
u16 rockchip_hdmi_vrr_tfr_match_to_vrefresh(u8 tfr);
const struct
mvrr_const_val *rockchip_hdmi_vrr_get_vrrconf_mconst(enum hdmi_brr_vic brr_vic, u16 vrefresh_khz);
u16 rockchip_hdmi_vrr_calc_new_vtotal(const struct mvrr_const_val *mvrr, u32 frame_cnt);
extern struct platform_driver cdn_dp_driver;
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;

View File

@@ -5955,6 +5955,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
vcstate->splice_mode = false;
vcstate->output_flags = 0;
vcstate->output_type = 0;
vcstate->hdmi_vrr.m_const = 0;
vcstate->hdmi_vrr.next_tfr_val = 0;
vcstate->hdmi_vrr.refresh_rate_ready_to_change = false;
vp->splice_mode_right = false;
vp->loader_protect = false;
vp->enabled_win_mask = 0;
@@ -10682,10 +10685,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
VOP_MODULE_SET(vop2, vp, dsp_vtotal, vtotal);
VOP_MODULE_SET(vop2, vp, dsp_vs_end, vsync_len);
/**
* when display interface support vrr, config vtotal valid immediately
/*
* when display interface support vrr, config vtotal
* valid immediately except HDMI QMS-VRR. HDMI QMS-VRR
* requires cfg done to accurately handle the vrr process.
* Fixme: HDMI GAMING-VRR needs to config vtotal valid immediately,
* the next version will be implemented.
*/
if (vcstate->max_refresh_rate && vcstate->min_refresh_rate)
if (vcstate->max_refresh_rate && vcstate->min_refresh_rate &&
!output_if_is_hdmi(vcstate->output_if))
VOP_MODULE_SET(vop2, vp, sw_dsp_vtotal_imd, 1);
snprintf(clk_name, sizeof(clk_name), "dclk_out%d", vp->id);
@@ -12502,22 +12510,13 @@ static void vop2_crtc_hfp_seamless_switch(struct drm_crtc *crtc)
VOP_MODULE_SET(vop2, vp, htotal_pw, (new_htotal << 16) | hsync_len);
}
static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc)
static void
vop2_crtc_update_vrr_timing(struct drm_crtc *crtc, unsigned int new_vtotal, unsigned int new_vfp)
{
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
struct drm_display_mode *adjust_mode = &crtc->state->adjusted_mode;
unsigned int vrefresh;
unsigned int new_vtotal, vfp, new_vfp;
DRM_DEV_INFO(vop2->dev, "change refresh rate by changing vfp\n");
vrefresh = drm_mode_vrefresh(adjust_mode);
/* calculate new vfp for new refresh rate */
new_vtotal = adjust_mode->vtotal * vrefresh / vcstate->request_refresh_rate;
vfp = adjust_mode->vsync_start - adjust_mode->vdisplay;
new_vfp = vfp + new_vtotal - adjust_mode->vtotal;
/* config vop2 vtotal register */
VOP_MODULE_SET(vop2, vp, dsp_vtotal, new_vtotal);
@@ -12539,13 +12538,81 @@ static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc)
rockchip_connector_update_vfp_for_vrr(crtc, adjust_mode, new_vfp);
}
static void vop2_crtc_vfp_seamless_switch(struct drm_crtc *crtc)
{
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
struct drm_display_mode *adjust_mode = &crtc->state->adjusted_mode;
struct rockchip_hdmi_vrr_state *hdmi_vrr = &vcstate->hdmi_vrr;
unsigned int vrefresh, vrefresh_khz;
unsigned int new_vtotal, vfp, new_vfp;
u8 brr_vic;
DRM_DEV_DEBUG(vop2->dev, "change refresh rate by changing vfp\n");
/*
* If next_tfr_val is no zero, current mode is hdmi qms-vrr.
* If next_tfr_val is 0, it indicates that current mode is hdmi
* gaming-vrr/fva, or eDP/DSI vrr.
*/
if (hdmi_vrr->next_tfr_val) {
brr_vic = drm_match_cea_mode(adjust_mode);
if (!brr_vic) {
DRM_ERROR("qms vrr can't support resolution:\n");
DRM_ERROR(DRM_MODE_FMT "\n", DRM_MODE_ARG(adjust_mode));
return;
}
vrefresh_khz = rockchip_hdmi_vrr_tfr_match_to_vrefresh(hdmi_vrr->next_tfr_val);
if (!vrefresh_khz) {
DRM_ERROR("qms vrr unsupported tfr:%d\n", hdmi_vrr->next_tfr_val);
return;
}
hdmi_vrr->mconst_val = rockchip_hdmi_vrr_get_vrrconf_mconst(brr_vic, vrefresh_khz);
if (!hdmi_vrr->mconst_val) {
DRM_ERROR("qms vrr can't find mconst_val\n");
return;
}
hdmi_vrr->vrr_frame_cnt = 0;
new_vtotal = rockchip_hdmi_vrr_calc_new_vtotal(hdmi_vrr->mconst_val,
hdmi_vrr->vrr_frame_cnt);
if (!new_vtotal) {
DRM_ERROR("qms vrr invalid vtotal\n");
return;
}
hdmi_vrr->vrr_frame_cnt++;
vfp = adjust_mode->vsync_start - adjust_mode->vdisplay;
new_vfp = vfp + new_vtotal - adjust_mode->vtotal;
hdmi_vrr->refresh_rate_ready_to_change = false;
} else {
vrefresh = drm_mode_vrefresh(adjust_mode);
/* calculate new vfp for new refresh rate */
new_vtotal = adjust_mode->vtotal * vrefresh / vcstate->request_refresh_rate;
vfp = adjust_mode->vsync_start - adjust_mode->vdisplay;
new_vfp = vfp + new_vtotal - adjust_mode->vtotal;
}
vop2_crtc_update_vrr_timing(crtc, new_vtotal, new_vfp);
}
static void vop2_crtc_update_vrr(struct drm_crtc *crtc)
{
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct vop2_video_port *vp = to_vop2_video_port(crtc);
if (!vp->refresh_rate_change)
return;
/*
* In hdmi qms vrr scenarios, it is possible to switch
* timing several frames after refresh rate is configured
*/
if (output_if_is_hdmi(vcstate->output_if)) {
if (!vcstate->hdmi_vrr.refresh_rate_ready_to_change)
return;
} else {
if (!vp->refresh_rate_change)
return;
}
if (!vcstate->min_refresh_rate || !vcstate->max_refresh_rate)
return;
@@ -12722,7 +12789,7 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat
vop2_wait_for_scan_timing_max_to_assigned_line(vp, current_line, assigned_line);
}
if (vop2->version == VOP_VERSION_RK3588)
if (vop2->version == VOP_VERSION_RK3588 || vop2->version == VOP_VERSION_RK3576)
vop2_crtc_update_vrr(crtc);
/* Process cluster sub windows overlay. */
@@ -14249,6 +14316,34 @@ static void vop2_dsc_isr(struct vop2 *vop2)
}
}
static void vop2_frac_mvrr_update(struct drm_crtc *crtc, struct vop2_video_port *vp)
{
struct rockchip_crtc_state *vcstate;
struct drm_display_mode *adjust_mode;
unsigned int new_vtotal, vfp, new_vfp;
vcstate = to_rockchip_crtc_state(crtc->state);
/*
* When hdmi qms-vrr is enabled and M_VRR(The difference between
* current refresh rate vfp and the vfp of the base fresh rate)
* is fractional. Sources should alternate between two sequential
* values of M_VRR to better approximate the fractional M_VRR.
*/
if (vcstate->hdmi_vrr.next_tfr_val && vcstate->hdmi_vrr.m_const) {
adjust_mode = &crtc->state->adjusted_mode;
new_vtotal = rockchip_hdmi_vrr_calc_new_vtotal(vcstate->hdmi_vrr.mconst_val,
vcstate->hdmi_vrr.vrr_frame_cnt);
if (!new_vtotal) {
DRM_ERROR("qms vrr invalid vtotal\n");
} else {
vfp = adjust_mode->vsync_start - adjust_mode->vdisplay;
new_vfp = vfp + new_vtotal - adjust_mode->vtotal;
vop2_crtc_update_vrr_timing(crtc, new_vtotal, new_vfp);
vcstate->hdmi_vrr.vrr_frame_cnt++;
}
}
}
static irqreturn_t vop2_isr(int irq, void *data)
{
struct vop2 *vop2 = data;
@@ -14340,6 +14435,7 @@ static irqreturn_t vop2_isr(int irq, void *data)
drm_crtc_handle_vblank(crtc);
vop2_handle_vblank(vop2, crtc);
}
vop2_frac_mvrr_update(crtc, vp);
active_irqs &= ~FS_FIELD_INTR;
ret = IRQ_HANDLED;
}
@@ -14544,6 +14640,7 @@ static irqreturn_t vop3_vp_isr(int irq, void *data)
rockchip_drm_dbg(vop2->dev, VOP_DEBUG_VSYNC, "vsync_vp%d", vp->id);
drm_crtc_handle_vblank(crtc);
vop2_handle_vblank(vop2, crtc);
vop2_frac_mvrr_update(crtc, vp);
active_irqs &= ~FS_FIELD_INTR;
ret = IRQ_HANDLED;
}