drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 + drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 10 ++++++++++ 3 files changed, 14 insertions(+)
The display might offer modes, which exceed the maximum clock rate of a
video output. This usually happens for displays that offer refresh rates
above 60 Hz. This results in no picture being displayed without manual
intervention. Fix this by teaching the driver about the maximum
achievable clock rates.
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
I've taken the max. clock rate information from the video output
information of the RK3568/RK3588/RK3576 datasheets. The real max. clock
rates should be above those to take blank times into account. I haven't
found the proper information source for this. I hope Andy can help out.
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 +++
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 +
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 10 ++++++++++
3 files changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index ec3b4fde10db..1051418e5fff 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1434,6 +1434,9 @@ static enum drm_mode_status vop2_crtc_mode_valid(struct drm_crtc *crtc,
if (mode->hdisplay > vp->data->max_output.width)
return MODE_BAD_HVALUE;
+ if (mode->clock > vp->data->max_clock_rate / 1000)
+ return MODE_CLOCK_HIGH;
+
return MODE_OK;
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
index 9124191899ba..42d70426bf08 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
@@ -225,6 +225,7 @@ struct vop2_video_port_data {
u16 gamma_lut_len;
u16 cubic_lut_len;
struct vop_rect max_output;
+ u32 max_clock_rate;
const u8 pre_scan_max_dly[4];
unsigned int offset;
/**
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
index f3950e8476a7..8be2cf0c47b6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
@@ -559,18 +559,21 @@ static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
.gamma_lut_len = 1024,
.cubic_lut_len = 9 * 9 * 9,
.max_output = { 4096, 2304 },
+ .max_clock_rate = 4096 * 2304 * 60,
.pre_scan_max_dly = { 69, 53, 53, 42 },
.offset = 0xc00,
}, {
.id = 1,
.gamma_lut_len = 1024,
.max_output = { 2048, 1536 },
+ .max_clock_rate = 2048 * 1536 * 60,
.pre_scan_max_dly = { 40, 40, 40, 40 },
.offset = 0xd00,
}, {
.id = 2,
.gamma_lut_len = 1024,
.max_output = { 1920, 1080 },
+ .max_clock_rate = 1920 * 1080 * 60,
.pre_scan_max_dly = { 40, 40, 40, 40 },
.offset = 0xe00,
},
@@ -775,6 +778,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
.gamma_lut_len = 1024,
.cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
.max_output = { 4096, 2304 },
+ .max_clock_rate = 4096 * 2304 * 120,
/* win layer_mix hdr */
.pre_scan_max_dly = { 10, 8, 2, 0 },
.offset = 0xc00,
@@ -785,6 +789,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
.gamma_lut_len = 1024,
.cubic_lut_len = 729, /* 9x9x9 */
.max_output = { 2560, 1600 },
+ .max_clock_rate = 2560 * 1600 * 60,
/* win layer_mix hdr */
.pre_scan_max_dly = { 10, 6, 0, 0 },
.offset = 0xd00,
@@ -793,6 +798,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
.id = 2,
.gamma_lut_len = 1024,
.max_output = { 1920, 1080 },
+ .max_clock_rate = 1920 * 1080 * 60,
/* win layer_mix hdr */
.pre_scan_max_dly = { 10, 6, 0, 0 },
.offset = 0xe00,
@@ -1061,6 +1067,7 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
.gamma_lut_len = 1024,
.cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
.max_output = { 4096, 2304 },
+ .max_clock_rate = 7680 * 4320 * 60,
/* hdr2sdr sdr2hdr hdr2hdr sdr2sdr */
.pre_scan_max_dly = { 76, 65, 65, 54 },
.offset = 0xc00,
@@ -1070,6 +1077,7 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
.gamma_lut_len = 1024,
.cubic_lut_len = 729, /* 9x9x9 */
.max_output = { 4096, 2304 },
+ .max_clock_rate = 4096 * 2304 * 60,
.pre_scan_max_dly = { 76, 65, 65, 54 },
.offset = 0xd00,
}, {
@@ -1078,12 +1086,14 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
.gamma_lut_len = 1024,
.cubic_lut_len = 17 * 17 * 17, /* 17x17x17 */
.max_output = { 4096, 2304 },
+ .max_clock_rate = 4096 * 2304 * 60,
.pre_scan_max_dly = { 52, 52, 52, 52 },
.offset = 0xe00,
}, {
.id = 3,
.gamma_lut_len = 1024,
.max_output = { 2048, 1536 },
+ .max_clock_rate = 1920 * 1080 * 60,
.pre_scan_max_dly = { 52, 52, 52, 52 },
.offset = 0xf00,
},
---
base-commit: 9702969978695d9a699a1f34771580cdbb153b33
change-id: 20260217-vop2-clk-rate-check-268269778cac
Best regards,
--
Sebastian Reichel <sebastian.reichel@collabora.com>
Hello Sebastian,
At 2026-02-18 00:08:45, "Sebastian Reichel" <sebastian.reichel@collabora.com> wrote:
>The display might offer modes, which exceed the maximum clock rate of a
>video output. This usually happens for displays that offer refresh rates
>above 60 Hz. This results in no picture being displayed without manual
>intervention. Fix this by teaching the driver about the maximum
>achievable clock rates.
>
>Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
>---
>I've taken the max. clock rate information from the video output
>information of the RK3568/RK3588/RK3576 datasheets. The real max. clock
>rates should be above those to take blank times into account. I haven't
>found the proper information source for this. I hope Andy can help out.
>---
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 +++
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 +
> drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 10 ++++++++++
> 3 files changed, 14 insertions(+)
>
>diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>index ec3b4fde10db..1051418e5fff 100644
>--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>@@ -1434,6 +1434,9 @@ static enum drm_mode_status vop2_crtc_mode_valid(struct drm_crtc *crtc,
> if (mode->hdisplay > vp->data->max_output.width)
> return MODE_BAD_HVALUE;
>
>+ if (mode->clock > vp->data->max_clock_rate / 1000)
>+ return MODE_CLOCK_HIGH;
>+
> return MODE_OK;
> }
>
>diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
>index 9124191899ba..42d70426bf08 100644
>--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
>+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
>@@ -225,6 +225,7 @@ struct vop2_video_port_data {
> u16 gamma_lut_len;
> u16 cubic_lut_len;
> struct vop_rect max_output;
>+ u32 max_clock_rate;
> const u8 pre_scan_max_dly[4];
> unsigned int offset;
> /**
>diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
>index f3950e8476a7..8be2cf0c47b6 100644
>--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
>+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
>@@ -559,18 +559,21 @@ static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
> .gamma_lut_len = 1024,
> .cubic_lut_len = 9 * 9 * 9,
> .max_output = { 4096, 2304 },
>+ .max_clock_rate = 4096 * 2304 * 60,
600000000 MHZ
> .pre_scan_max_dly = { 69, 53, 53, 42 },
> .offset = 0xc00,
> }, {
> .id = 1,
> .gamma_lut_len = 1024,
> .max_output = { 2048, 1536 },
>+ .max_clock_rate = 2048 * 1536 * 60,
200000000 Mhz
> .pre_scan_max_dly = { 40, 40, 40, 40 },
> .offset = 0xd00,
> }, {
> .id = 2,
> .gamma_lut_len = 1024,
> .max_output = { 1920, 1080 },
>+ .max_clock_rate = 1920 * 1080 * 60,
150000000 Hz
> .pre_scan_max_dly = { 40, 40, 40, 40 },
> .offset = 0xe00,
> },
>@@ -775,6 +778,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
> .gamma_lut_len = 1024,
> .cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
> .max_output = { 4096, 2304 },
>+ .max_clock_rate = 4096 * 2304 * 120,
600000000Mhz
> /* win layer_mix hdr */
> .pre_scan_max_dly = { 10, 8, 2, 0 },
> .offset = 0xc00,
>@@ -785,6 +789,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
> .gamma_lut_len = 1024,
> .cubic_lut_len = 729, /* 9x9x9 */
> .max_output = { 2560, 1600 },
>+ .max_clock_rate = 2560 * 1600 * 60,
300000000 Mhz
> /* win layer_mix hdr */
> .pre_scan_max_dly = { 10, 6, 0, 0 },
> .offset = 0xd00,
>@@ -793,6 +798,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
> .id = 2,
> .gamma_lut_len = 1024,
> .max_output = { 1920, 1080 },
>+ .max_clock_rate = 1920 * 1080 * 60,
150000000 Mhz
> /* win layer_mix hdr */
> .pre_scan_max_dly = { 10, 6, 0, 0 },
> .offset = 0xe00,
>@@ -1061,6 +1067,7 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
> .gamma_lut_len = 1024,
> .cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
> .max_output = { 4096, 2304 },
>+ .max_clock_rate = 7680 * 4320 * 60,
600 000000 Mhz
For all current platforms, the maximum dclk input supported by VOP is 600 MHz.
The tricky part is that when we need to display a resolution higher than 4K@60, even though
the required dclk exceeds 600 MHz, VOP internally processes 2 or 4 pixels per clock cycle to
output a higher resolution using a lower dclk. Therefore, even when outputting an 8K@60 resolution,
CRU only needs to provide VOP with a dclk of 594 MHz. This is what the rk3588_calc_cru_cfg function does.
> /* hdr2sdr sdr2hdr hdr2hdr sdr2sdr */
> .pre_scan_max_dly = { 76, 65, 65, 54 },
> .offset = 0xc00,
>@@ -1070,6 +1077,7 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
> .gamma_lut_len = 1024,
> .cubic_lut_len = 729, /* 9x9x9 */
> .max_output = { 4096, 2304 },
>+ .max_clock_rate = 4096 * 2304 * 60,
600 000000 Mhz
> .pre_scan_max_dly = { 76, 65, 65, 54 },
> .offset = 0xd00,
> }, {
>@@ -1078,12 +1086,14 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
> .gamma_lut_len = 1024,
> .cubic_lut_len = 17 * 17 * 17, /* 17x17x17 */
> .max_output = { 4096, 2304 },
>+ .max_clock_rate = 4096 * 2304 * 60,
600 000000 Mhz
> .pre_scan_max_dly = { 52, 52, 52, 52 },
> .offset = 0xe00,
> }, {
> .id = 3,
> .gamma_lut_len = 1024,
> .max_output = { 2048, 1536 },
>+ .max_clock_rate = 1920 * 1080 * 60,
150 000000 Mhz
> .pre_scan_max_dly = { 52, 52, 52, 52 },
> .offset = 0xf00,
> },
>
>---
>base-commit: 9702969978695d9a699a1f34771580cdbb153b33
>change-id: 20260217-vop2-clk-rate-check-268269778cac
>
>Best regards,
>--
>Sebastian Reichel <sebastian.reichel@collabora.com>
© 2016 - 2026 Red Hat, Inc.