1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-02-14 20:31:54 +00:00

Remove some RPI 5.15 patches

This commit is contained in:
Ycarus (Yannick Chabanois) 2022-04-23 07:25:33 +02:00
parent 9011816ca0
commit 06e084a790
5 changed files with 0 additions and 1268 deletions

View file

@ -1,131 +0,0 @@
From ba5c4bb79f7707a662782a87eea811588634bbd0 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime@cerno.tech>
Date: Fri, 10 Dec 2021 15:29:56 +0100
Subject: [PATCH 650/828] drm/vc4: hdmi: Always try to have the highest bpc
Currently we take the max_bpc property as the bpc value and do not try
anything else.
However, what the other drivers seem to be doing is that they would try
with the highest bpc allowed by the max_bpc property and the hardware
capabilities, test if it results in an acceptable configuration, and if
not decrease the bpc and try again.
Let's use the same logic.
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 44 ++++++++++++++++++++++++++++++----
drivers/gpu/drm/vc4/vc4_hdmi.h | 4 +++-
2 files changed, 43 insertions(+), 5 deletions(-)
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -356,6 +356,7 @@ vc4_hdmi_connector_duplicate_state(struc
return NULL;
new_state->pixel_rate = vc4_state->pixel_rate;
+ new_state->output_bpc = vc4_state->output_bpc;
__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
return &new_state->base;
@@ -913,6 +914,8 @@ static void vc5_hdmi_set_timings(struct
struct drm_connector_state *state,
struct drm_display_mode *mode)
{
+ const struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(state);
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
@@ -960,7 +963,7 @@ static void vc5_hdmi_set_timings(struct
HDMI_WRITE(HDMI_VERTB0, vertb_even);
HDMI_WRITE(HDMI_VERTB1, vertb);
- switch (state->max_bpc) {
+ switch (vc4_state->output_bpc) {
case 12:
gcp = 6;
gcp_en = true;
@@ -1250,9 +1253,11 @@ static void vc4_hdmi_encoder_atomic_mode
struct drm_connector_state *conn_state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+ struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(conn_state);
mutex_lock(&vc4_hdmi->mutex);
- vc4_hdmi->output_bpc = conn_state->max_bpc;
+ vc4_hdmi->output_bpc = vc4_state->output_bpc;
memcpy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode,
sizeof(vc4_hdmi->saved_adjusted_mode));
@@ -1307,6 +1312,38 @@ vc4_hdmi_encoder_compute_clock(const str
return 0;
}
+static int
+vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi,
+ struct vc4_hdmi_connector_state *vc4_state,
+ const struct drm_display_mode *mode)
+{
+ struct drm_connector_state *conn_state = &vc4_state->base;
+ unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12);
+ unsigned int bpc;
+ int ret;
+
+ for (bpc = max_bpc; bpc >= 8; bpc -= 2) {
+ drm_dbg(dev, "Trying with a %d bpc output\n", bpc);
+
+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state,
+ mode, bpc);
+ if (ret)
+ continue;
+
+ vc4_state->output_bpc = bpc;
+
+ drm_dbg(dev,
+ "Mode %ux%u @ %uHz: Found configuration: bpc: %u, clock: %llu\n",
+ mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
+ vc4_state->output_bpc,
+ vc4_state->pixel_rate);
+
+ break;
+ }
+
+ return ret;
+}
+
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
#define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL
@@ -1341,8 +1378,7 @@ static int vc4_hdmi_encoder_atomic_check
pixel_rate = mode->clock * 1000;
}
- ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, mode,
- conn_state->max_bpc);
+ ret = vc4_hdmi_encoder_compute_config(vc4_hdmi, vc4_state, mode);
if (ret)
return ret;
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -222,7 +222,8 @@ struct vc4_hdmi {
bool scdc_enabled;
/**
- * @output_bpc: BPC currently being used. Protected by @mutex.
+ * @output_bpc: Copy of @vc4_connector_state.output_bpc for use
+ * outside of KMS hooks. Protected by @mutex.
*/
unsigned int output_bpc;
@@ -252,6 +253,7 @@ encoder_to_vc4_hdmi(struct drm_encoder *
struct vc4_hdmi_connector_state {
struct drm_connector_state base;
unsigned long long pixel_rate;
+ unsigned int output_bpc;
};
static inline struct vc4_hdmi_connector_state *

View file

@ -1,578 +0,0 @@
From 3a02d131688be3206ba46b43e5d33c81b9a850c3 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime@cerno.tech>
Date: Fri, 4 Dec 2020 17:12:06 +0100
Subject: [PATCH 651/828] drm/vc4: hdmi: Support HDMI YUV output
In addition to the RGB444 output, the BCM2711 HDMI controller supports
the YUV444 and YUV422 output formats.
Let's add support for them in the driver, but still use RGB as the
preferred format.
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 289 ++++++++++++++++++++++++++--
drivers/gpu/drm/vc4/vc4_hdmi.h | 14 ++
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 6 +
drivers/gpu/drm/vc4/vc4_regs.h | 16 ++
4 files changed, 309 insertions(+), 16 deletions(-)
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -102,15 +102,30 @@
#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
+static const char * const output_format_str[] = {
+ [VC4_HDMI_OUTPUT_RGB] = "RGB",
+ [VC4_HDMI_OUTPUT_YUV420] = "YUV 4:2:0",
+ [VC4_HDMI_OUTPUT_YUV422] = "YUV 4:2:2",
+ [VC4_HDMI_OUTPUT_YUV444] = "YUV 4:4:4",
+};
+
+static const char *vc4_hdmi_output_fmt_str(enum vc4_hdmi_output_format fmt)
+{
+ if (fmt >= ARRAY_SIZE(output_format_str))
+ return "invalid";
+
+ return output_format_str[fmt];
+}
static unsigned long long
vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
- unsigned int bpc);
+ unsigned int bpc, enum vc4_hdmi_output_format fmt);
static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
- unsigned int bpc)
+ unsigned int bpc,
+ enum vc4_hdmi_output_format fmt)
{
- unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc);
+ unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt);
return clock > HDMI_14_MAX_TMDS_CLK;
}
@@ -284,7 +299,7 @@ static int vc4_hdmi_connector_get_modes(
struct drm_display_mode *mode;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode, 8)) {
+ if (vc4_hdmi_mode_needs_scrambling(mode, 8, VC4_HDMI_OUTPUT_RGB)) {
drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
}
@@ -341,6 +356,7 @@ static void vc4_hdmi_connector_reset(str
new_state->base.max_bpc = 8;
new_state->base.max_requested_bpc = 8;
+ new_state->output_format = VC4_HDMI_OUTPUT_RGB;
drm_atomic_helper_connector_tv_reset(connector);
}
@@ -357,6 +373,7 @@ vc4_hdmi_connector_duplicate_state(struc
new_state->pixel_rate = vc4_state->pixel_rate;
new_state->output_bpc = vc4_state->output_bpc;
+ new_state->output_format = vc4_state->output_format;
__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
return &new_state->base;
@@ -510,11 +527,38 @@ static void vc4_hdmi_write_infoframe(str
DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
}
+static void vc4_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame,
+ enum vc4_hdmi_output_format fmt)
+{
+ switch (fmt) {
+ case VC4_HDMI_OUTPUT_RGB:
+ frame->colorspace = HDMI_COLORSPACE_RGB;
+ break;
+
+ case VC4_HDMI_OUTPUT_YUV420:
+ frame->colorspace = HDMI_COLORSPACE_YUV420;
+ break;
+
+ case VC4_HDMI_OUTPUT_YUV422:
+ frame->colorspace = HDMI_COLORSPACE_YUV422;
+ break;
+
+ case VC4_HDMI_OUTPUT_YUV444:
+ frame->colorspace = HDMI_COLORSPACE_YUV444;
+ break;
+
+ default:
+ break;
+ }
+}
+
static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_connector_state *cstate = connector->state;
+ struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(cstate);
const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
union hdmi_infoframe frame;
int ret;
@@ -534,6 +578,7 @@ static void vc4_hdmi_set_avi_infoframe(s
HDMI_QUANTIZATION_RANGE_FULL :
HDMI_QUANTIZATION_RANGE_LIMITED);
drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate);
+ vc4_hdmi_avi_infoframe_colorspace(&frame.avi, vc4_state->output_format);
drm_hdmi_avi_infoframe_bars(&frame.avi, cstate);
vc4_hdmi_write_infoframe(encoder, &frame);
@@ -636,7 +681,9 @@ static void vc4_hdmi_enable_scrambling(s
if (!vc4_hdmi_supports_scrambling(encoder, mode))
return;
- if (!vc4_hdmi_mode_needs_scrambling(mode, vc4_hdmi->output_bpc))
+ if (!vc4_hdmi_mode_needs_scrambling(mode,
+ vc4_hdmi->output_bpc,
+ vc4_hdmi->output_format))
return;
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
@@ -824,6 +871,38 @@ static const u16 vc5_hdmi_csc_full_rgb_t
{ 0x0000, 0x0000, 0x1b80, 0x0400 },
};
+/*
+ * Conversion between Full Range RGB and Full Range YUV422 using the
+ * BT.709 Colorspace
+ *
+ * [ 0.212639 0.715169 0.072192 0 ]
+ * [ -0.117208 -0.394207 0.511416 128 ]
+ * [ 0.511416 -0.464524 -0.046891 128 ]
+ *
+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
+ */
+static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709[3][4] = {
+ { 0x06ce, 0x16e3, 0x024f, 0x0000 },
+ { 0xfc41, 0xf364, 0x105e, 0x2000 },
+ { 0x105e, 0xf124, 0xfe81, 0x2000 },
+};
+
+/*
+ * Conversion between Full Range RGB and Full Range YUV444 using the
+ * BT.709 Colorspace
+ *
+ * [ -0.117208 -0.394207 0.511416 128 ]
+ * [ 0.511416 -0.464524 -0.046891 128 ]
+ * [ 0.212639 0.715169 0.072192 0 ]
+ *
+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
+ */
+static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709[3][4] = {
+ { 0xfc41, 0xf364, 0x105e, 0x2000 },
+ { 0x105e, 0xf124, 0xfe81, 0x2000 },
+ { 0x06ce, 0x16e3, 0x024f, 0x0000 },
+};
+
static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi,
const u16 coeffs[3][4])
{
@@ -841,19 +920,53 @@ static void vc5_hdmi_csc_setup(struct vc
struct drm_connector_state *state,
const struct drm_display_mode *mode)
{
+ struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(state);
unsigned long flags;
+ u32 if_cfg = 0;
+ u32 if_xbar = 0x543210;
+ u32 csc_chan_ctl = 0;
u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
VC5_MT_CP_CSC_CTL_MODE);
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
- HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
+ switch (vc4_state->output_format) {
+ case VC4_HDMI_OUTPUT_YUV444:
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709);
+ break;
+
+ case VC4_HDMI_OUTPUT_YUV422:
+ csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
+ VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
+ VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
+ VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION;
- if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
- else
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
+ csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE,
+ VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP);
+
+ if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
+ VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
+
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709);
+ break;
+ case VC4_HDMI_OUTPUT_RGB:
+ if_xbar = 0x354021;
+
+ if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
+ else
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
+ break;
+
+ default:
+ break;
+ }
+
+ HDMI_WRITE(HDMI_VEC_INTERFACE_CFG, if_cfg);
+ HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, if_xbar);
+ HDMI_WRITE(HDMI_CSC_CHANNEL_CTL, csc_chan_ctl);
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
@@ -979,6 +1092,15 @@ static void vc5_hdmi_set_timings(struct
break;
}
+ /*
+ * YCC422 is always 36-bit and not considered deep colour so
+ * doesn't signal in GCP
+ */
+ if (vc4_state->output_format == VC4_HDMI_OUTPUT_YUV422) {
+ gcp = 4;
+ gcp_en = false;
+ }
+
reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1);
reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK);
@@ -1258,12 +1380,97 @@ static void vc4_hdmi_encoder_atomic_mode
mutex_lock(&vc4_hdmi->mutex);
vc4_hdmi->output_bpc = vc4_state->output_bpc;
+ vc4_hdmi->output_format = vc4_state->output_format;
memcpy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode,
sizeof(vc4_hdmi->saved_adjusted_mode));
mutex_unlock(&vc4_hdmi->mutex);
}
+static bool
+vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode,
+ unsigned int format, unsigned int bpc)
+{
+ struct drm_device *dev = vc4_hdmi->connector.dev;
+ u8 vic = drm_match_cea_mode(mode);
+
+ if (vic == 1 && bpc != 8) {
+ drm_dbg(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
+ return false;
+ }
+
+ if (!info->is_hdmi &&
+ (format != VC4_HDMI_OUTPUT_RGB || bpc != 8)) {
+ drm_dbg(dev, "DVI Monitors require an RGB output at 8 bpc\n");
+ return false;
+ }
+
+ switch (format) {
+ case VC4_HDMI_OUTPUT_RGB:
+ drm_dbg(dev, "RGB Format, checking the constraints.\n");
+
+ if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
+ return false;
+
+ if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) {
+ drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
+ return false;
+ }
+
+ if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) {
+ drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
+ return false;
+ }
+
+ drm_dbg(dev, "RGB format supported in that configuration.\n");
+
+ return true;
+
+ case VC4_HDMI_OUTPUT_YUV422:
+ drm_dbg(dev, "YUV422 format, checking the constraints.\n");
+
+ if (!(info->color_formats & DRM_COLOR_FORMAT_YCRCB422)) {
+ drm_dbg(dev, "Sink doesn't support YUV422.\n");
+ return false;
+ }
+
+ if (bpc != 12) {
+ drm_dbg(dev, "YUV422 only supports 12 bpc.\n");
+ return false;
+ }
+
+ drm_dbg(dev, "YUV422 format supported in that configuration.\n");
+
+ return true;
+
+ case VC4_HDMI_OUTPUT_YUV444:
+ drm_dbg(dev, "YUV444 format, checking the constraints.\n");
+
+ if (!(info->color_formats & DRM_COLOR_FORMAT_YCRCB444)) {
+ drm_dbg(dev, "Sink doesn't support YUV444.\n");
+ return false;
+ }
+
+ if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) {
+ drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
+ return false;
+ }
+
+ if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) {
+ drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
+ return false;
+ }
+
+ drm_dbg(dev, "YUV444 format supported in that configuration.\n");
+
+ return true;
+ }
+
+ return false;
+}
+
static enum drm_mode_status
vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi,
unsigned long long clock)
@@ -1285,13 +1492,17 @@ vc4_hdmi_encoder_clock_valid(const struc
static unsigned long long
vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
- unsigned int bpc)
+ unsigned int bpc,
+ enum vc4_hdmi_output_format fmt)
{
unsigned long long clock = mode->crtc_clock * 1000;
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
clock = clock * 2;
+ if (fmt == VC4_HDMI_OUTPUT_YUV422)
+ bpc = 8;
+
return clock * bpc / 8;
}
@@ -1299,11 +1510,11 @@ static int
vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi,
struct vc4_hdmi_connector_state *vc4_state,
const struct drm_display_mode *mode,
- unsigned int bpc)
+ unsigned int bpc, unsigned int fmt)
{
unsigned long long clock;
- clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc);
+ clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt);
if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK)
return -EINVAL;
@@ -1313,10 +1524,55 @@ vc4_hdmi_encoder_compute_clock(const str
}
static int
+vc4_hdmi_encoder_compute_format(const struct vc4_hdmi *vc4_hdmi,
+ struct vc4_hdmi_connector_state *vc4_state,
+ const struct drm_display_mode *mode,
+ unsigned int bpc)
+{
+ struct drm_device *dev = vc4_hdmi->connector.dev;
+ const struct drm_connector *connector = &vc4_hdmi->connector;
+ const struct drm_display_info *info = &connector->display_info;
+ unsigned int format;
+
+ drm_dbg(dev, "Trying with an RGB output\n");
+
+ format = VC4_HDMI_OUTPUT_RGB;
+ if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) {
+ int ret;
+
+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state,
+ mode, bpc, format);
+ if (!ret) {
+ vc4_state->output_format = format;
+ return 0;
+ }
+ }
+
+ drm_dbg(dev, "Failed, Trying with an YUV422 output\n");
+
+ format = VC4_HDMI_OUTPUT_YUV422;
+ if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) {
+ int ret;
+
+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state,
+ mode, bpc, format);
+ if (!ret) {
+ vc4_state->output_format = format;
+ return 0;
+ }
+ }
+
+ drm_dbg(dev, "Failed. No Format Supported for that bpc count.\n");
+
+ return -EINVAL;
+}
+
+static int
vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi,
struct vc4_hdmi_connector_state *vc4_state,
const struct drm_display_mode *mode)
{
+ struct drm_device *dev = vc4_hdmi->connector.dev;
struct drm_connector_state *conn_state = &vc4_state->base;
unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12);
unsigned int bpc;
@@ -1325,17 +1581,18 @@ vc4_hdmi_encoder_compute_config(const st
for (bpc = max_bpc; bpc >= 8; bpc -= 2) {
drm_dbg(dev, "Trying with a %d bpc output\n", bpc);
- ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state,
- mode, bpc);
+ ret = vc4_hdmi_encoder_compute_format(vc4_hdmi, vc4_state,
+ mode, bpc);
if (ret)
continue;
vc4_state->output_bpc = bpc;
drm_dbg(dev,
- "Mode %ux%u @ %uHz: Found configuration: bpc: %u, clock: %llu\n",
+ "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n",
mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
vc4_state->output_bpc,
+ vc4_hdmi_output_fmt_str(vc4_state->output_format),
vc4_state->pixel_rate);
break;
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -121,6 +121,13 @@ struct vc4_hdmi_audio {
bool streaming;
};
+enum vc4_hdmi_output_format {
+ VC4_HDMI_OUTPUT_RGB,
+ VC4_HDMI_OUTPUT_YUV422,
+ VC4_HDMI_OUTPUT_YUV444,
+ VC4_HDMI_OUTPUT_YUV420,
+};
+
/* General HDMI hardware state. */
struct vc4_hdmi {
struct vc4_hdmi_audio audio;
@@ -227,6 +234,12 @@ struct vc4_hdmi {
*/
unsigned int output_bpc;
+ /**
+ * @output_format: Copy of @vc4_connector_state.output_format
+ * for use outside of KMS hooks. Protected by @mutex.
+ */
+ enum vc4_hdmi_output_format output_format;
+
/* VC5 debugfs regset */
struct debugfs_regset32 cec_regset;
struct debugfs_regset32 csc_regset;
@@ -254,6 +267,7 @@ struct vc4_hdmi_connector_state {
struct drm_connector_state base;
unsigned long long pixel_rate;
unsigned int output_bpc;
+ enum vc4_hdmi_output_format output_format;
};
static inline struct vc4_hdmi_connector_state *
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
@@ -54,6 +54,7 @@ enum vc4_hdmi_field {
HDMI_CSC_24_23,
HDMI_CSC_32_31,
HDMI_CSC_34_33,
+ HDMI_CSC_CHANNEL_CTL,
HDMI_CSC_CTL,
/*
@@ -119,6 +120,7 @@ enum vc4_hdmi_field {
HDMI_TX_PHY_POWERDOWN_CTL,
HDMI_TX_PHY_RESET_CTL,
HDMI_TX_PHY_TMDS_CLK_WORD_SEL,
+ HDMI_VEC_INTERFACE_CFG,
HDMI_VEC_INTERFACE_XBAR,
HDMI_VERTA0,
HDMI_VERTA1,
@@ -246,6 +248,7 @@ static const struct vc4_hdmi_register __
VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
+ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec),
VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
@@ -291,6 +294,7 @@ static const struct vc4_hdmi_register __
VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
+ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c),
};
static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = {
@@ -327,6 +331,7 @@ static const struct vc4_hdmi_register __
VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
+ VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec),
VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
@@ -372,6 +377,7 @@ static const struct vc4_hdmi_register __
VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
+ VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c),
};
static inline
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -796,11 +796,27 @@ enum {
# define VC4_HD_CSC_CTL_RGB2YCC BIT(1)
# define VC4_HD_CSC_CTL_ENABLE BIT(0)
+# define VC5_MT_CP_CSC_CTL_USE_444_TO_422 BIT(6)
+# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_MASK \
+ VC4_MASK(5, 4)
+# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD \
+ 3
+# define VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION BIT(3)
# define VC5_MT_CP_CSC_CTL_ENABLE BIT(2)
# define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0)
+# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_MASK \
+ VC4_MASK(7, 6)
+# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE \
+ 2
+
# define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1)
+# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_MASK \
+ VC4_MASK(3, 2)
+# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY \
+ 2
+
/* HVS display list information. */
#define HVS_BOOTLOADER_DLIST_END 32

View file

@ -1,29 +0,0 @@
From ca0632a13df15e8d1391671aa4cdc27131e6c1e6 Mon Sep 17 00:00:00 2001
From: Matthias Reichl <hias@horus.com>
Date: Thu, 30 Dec 2021 15:12:19 +0100
Subject: [PATCH 659/828] drm/vc4: hdmi: Fix no video output on DVI monitors
The drm edid parser doesn't signal RGB support on DVI monitors
with old edid versions, leading to 8-bit RGB mode being rejected
and no video on DVI monitors.
As 8-bit RGB is mandatory on HDMI and DVI monitors anyways we can
simply drop the RGB format check, aligning vc4 with other drivers.
Signed-off-by: Matthias Reichl <hias@horus.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 3 ---
1 file changed, 3 deletions(-)
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1414,9 +1414,6 @@ vc4_hdmi_sink_supports_format_bpc(const
case VC4_HDMI_OUTPUT_RGB:
drm_dbg(dev, "RGB Format, checking the constraints.\n");
- if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
- return false;
-
if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) {
drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
return false;

View file

@ -1,222 +0,0 @@
From ddd0084db2b52c4856447ea7a9dc6b9b6dc77905 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 8 Apr 2020 16:12:02 +0100
Subject: [PATCH 686/828] drm/vc4_hdmi: Add Broadcast RGB property to allow
override of RGB range
Copy Intel's "Broadcast RGB" property semantics to add manual override
of the HDMI pixel range for monitors that don't abide by the content
of the AVI Infoframe.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 103 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/vc4/vc4_hdmi.h | 15 +++++
2 files changed, 118 insertions(+)
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -56,6 +56,14 @@
#include "vc4_hdmi_regs.h"
#include "vc4_regs.h"
+/*
+ * "Broadcast RGB" property.
+ * Allows overriding of HDMI full or limited range RGB
+ */
+#define VC4_BROADCAST_RGB_AUTO 0
+#define VC4_BROADCAST_RGB_FULL 1
+#define VC4_BROADCAST_RGB_LIMITED 2
+
#define VC5_HDMI_HORZA_HFP_SHIFT 16
#define VC5_HDMI_HORZA_HFP_MASK VC4_MASK(28, 16)
#define VC5_HDMI_HORZA_VPOS BIT(15)
@@ -135,6 +143,10 @@ static bool vc4_hdmi_is_full_range_rgb(s
{
struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder;
+ if (vc4_hdmi->broadcast_rgb == VC4_BROADCAST_RGB_LIMITED)
+ return false;
+ else if (vc4_hdmi->broadcast_rgb == VC4_BROADCAST_RGB_FULL)
+ return true;
return !vc4_encoder->hdmi_monitor ||
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL;
}
@@ -341,6 +353,65 @@ static int vc4_hdmi_connector_atomic_che
return 0;
}
+/**
+ * vc4_hdmi_connector_atomic_get_property - hook for
+ * connector->atomic_get_property.
+ * @connector: Connector to get the property for.
+ * @state: Connector state to retrieve the property from.
+ * @property: Property to retrieve.
+ * @val: Return value for the property.
+ *
+ * Returns the atomic property value for a digital connector.
+ */
+int vc4_hdmi_connector_get_property(struct drm_connector *connector,
+ const struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+ const struct vc4_hdmi_connector_state *vc4_conn_state =
+ const_conn_state_to_vc4_hdmi_conn_state(state);
+
+ if (property == vc4_hdmi->broadcast_rgb_property) {
+ *val = vc4_conn_state->broadcast_rgb;
+ } else {
+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
+ property->base.id, property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vc4_hdmi_connector_atomic_set_property - hook for
+ * connector->atomic_set_property.
+ * @connector: Connector to set the property for.
+ * @state: Connector state to set the property on.
+ * @property: Property to set.
+ * @val: New value for the property.
+ *
+ * Sets the atomic property value for a digital connector.
+ */
+int vc4_hdmi_connector_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+ struct vc4_hdmi_connector_state *vc4_conn_state =
+ conn_state_to_vc4_hdmi_conn_state(state);
+
+ if (property == vc4_hdmi->broadcast_rgb_property) {
+ vc4_conn_state->broadcast_rgb = val;
+ return 0;
+ }
+
+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
+ property->base.id, property->name);
+ return -EINVAL;
+}
+
static void vc4_hdmi_connector_reset(struct drm_connector *connector)
{
struct vc4_hdmi_connector_state *old_state =
@@ -377,6 +448,7 @@ vc4_hdmi_connector_duplicate_state(struc
new_state->pixel_rate = vc4_state->pixel_rate;
new_state->output_bpc = vc4_state->output_bpc;
new_state->output_format = vc4_state->output_format;
+ new_state->broadcast_rgb = vc4_state->broadcast_rgb;
__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
return &new_state->base;
@@ -389,6 +461,8 @@ static const struct drm_connector_funcs
.reset = vc4_hdmi_connector_reset,
.atomic_duplicate_state = vc4_hdmi_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_get_property = vc4_hdmi_connector_get_property,
+ .atomic_set_property = vc4_hdmi_connector_set_property,
};
static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
@@ -396,6 +470,32 @@ static const struct drm_connector_helper
.atomic_check = vc4_hdmi_connector_atomic_check,
};
+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
+ { VC4_BROADCAST_RGB_AUTO, "Automatic" },
+ { VC4_BROADCAST_RGB_FULL, "Full" },
+ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
+};
+
+static void
+vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev,
+ struct vc4_hdmi *vc4_hdmi)
+{
+ struct drm_property *prop = vc4_hdmi->broadcast_rgb_property;
+
+ if (!prop) {
+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
+ "Broadcast RGB",
+ broadcast_rgb_names,
+ ARRAY_SIZE(broadcast_rgb_names));
+ if (!prop)
+ return;
+
+ vc4_hdmi->broadcast_rgb_property = prop;
+ }
+
+ drm_object_attach_property(&vc4_hdmi->connector.base, prop, 0);
+}
+
static int vc4_hdmi_connector_init(struct drm_device *dev,
struct vc4_hdmi *vc4_hdmi)
{
@@ -439,6 +539,8 @@ static int vc4_hdmi_connector_init(struc
if (vc4_hdmi->variant->supports_hdr)
drm_connector_attach_hdr_output_metadata_property(connector);
+ vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi);
+
drm_connector_attach_encoder(connector, encoder);
return 0;
@@ -1384,6 +1486,7 @@ static void vc4_hdmi_encoder_atomic_mode
mutex_lock(&vc4_hdmi->mutex);
vc4_hdmi->output_bpc = vc4_state->output_bpc;
vc4_hdmi->output_format = vc4_state->output_format;
+ vc4_hdmi->broadcast_rgb = vc4_state->broadcast_rgb;
memcpy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode,
sizeof(vc4_hdmi->saved_adjusted_mode));
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -140,6 +140,8 @@ struct vc4_hdmi {
struct delayed_work scrambling_work;
+ struct drm_property *broadcast_rgb_property;
+
struct i2c_adapter *ddc;
void __iomem *hdmicore_regs;
void __iomem *hd_regs;
@@ -240,6 +242,12 @@ struct vc4_hdmi {
*/
enum vc4_hdmi_output_format output_format;
+ /**
+ * @broadcast_rgb: Copy of @vc4_connector_state.broadcast_rgb
+ * for use outside of KMS hooks. Protected by @mutex.
+ */
+ int broadcast_rgb;
+
/* VC5 debugfs regset */
struct debugfs_regset32 cec_regset;
struct debugfs_regset32 csc_regset;
@@ -268,6 +276,7 @@ struct vc4_hdmi_connector_state {
unsigned long long pixel_rate;
unsigned int output_bpc;
enum vc4_hdmi_output_format output_format;
+ int broadcast_rgb;
};
static inline struct vc4_hdmi_connector_state *
@@ -275,6 +284,12 @@ conn_state_to_vc4_hdmi_conn_state(struct
{
return container_of(conn_state, struct vc4_hdmi_connector_state, base);
}
+
+static inline const struct vc4_hdmi_connector_state *
+const_conn_state_to_vc4_hdmi_conn_state(const struct drm_connector_state *conn_state)
+{
+ return container_of(conn_state, struct vc4_hdmi_connector_state, base);
+}
void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
struct vc4_hdmi_connector_state *vc4_conn_state);

View file

@ -1,308 +0,0 @@
From 6d3f80fe83b924d8ec4879a7d84eb2b464e0a7d8 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Mon, 7 Mar 2022 15:19:38 +0000
Subject: [PATCH 804/828] drm/vc4: hdmi: Add CSC for BT601/709/2020 limited and
full range output
The HVS always composes in the RGB domain, but there is a colourspace
conversion block on the output to allow for sending YCbCr over the
HDMI interface.
The colourspace on that link is configurable via the "Colorspace"
property on the connector, and that updates the infoframes. There
is also selection of limited or full range based on the mode selected
or an override.
Add code to update the CSC as well so that the metadata matches the
image data.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 198 ++++++++++++++++++++++++---------
1 file changed, 146 insertions(+), 52 deletions(-)
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -138,8 +138,8 @@ static bool vc4_hdmi_mode_needs_scrambli
return clock > HDMI_14_MAX_TMDS_CLK;
}
-static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi,
- const struct drm_display_mode *mode)
+static bool vc4_hdmi_is_full_range(struct vc4_hdmi *vc4_hdmi,
+ const struct drm_display_mode *mode)
{
struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder;
@@ -679,7 +679,7 @@ static void vc4_hdmi_set_avi_infoframe(s
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
connector, mode,
- vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ?
+ vc4_hdmi_is_full_range(vc4_hdmi, mode) ?
HDMI_QUANTIZATION_RANGE_FULL :
HDMI_QUANTIZATION_RANGE_LIMITED);
drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate);
@@ -913,7 +913,7 @@ static void vc4_hdmi_csc_setup(struct vc
csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
VC4_HD_CSC_CTL_ORDER);
- if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) {
+ if (!vc4_hdmi_is_full_range(vc4_hdmi, mode)) {
/* CEA VICs other than #1 requre limited range RGB
* output unless overridden by an AVI infoframe.
* Apply a colorspace conversion to squash 0-255 down
@@ -943,7 +943,6 @@ static void vc4_hdmi_csc_setup(struct vc
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
}
-
/*
* If we need to output Full Range RGB, then use the unity matrix
*
@@ -951,15 +950,6 @@ static void vc4_hdmi_csc_setup(struct vc
* [ 0 1 0 0]
* [ 0 0 1 0]
*
- * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
- */
-static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = {
- { 0x2000, 0x0000, 0x0000, 0x0000 },
- { 0x0000, 0x2000, 0x0000, 0x0000 },
- { 0x0000, 0x0000, 0x2000, 0x0000 },
-};
-
-/*
* CEA VICs other than #1 require limited range RGB output unless
* overridden by an AVI infoframe. Apply a colorspace conversion to
* squash 0-255 down to 16-235. The matrix here is:
@@ -970,42 +960,105 @@ static const u16 vc5_hdmi_csc_full_rgb_u
*
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
*/
-static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = {
- { 0x1b80, 0x0000, 0x0000, 0x0400 },
- { 0x0000, 0x1b80, 0x0000, 0x0400 },
- { 0x0000, 0x0000, 0x1b80, 0x0400 },
+static const u16 vc5_hdmi_csc_full_rgb_to_rgb[2][3][4] = {
+ {
+ /* Full range - unity */
+ { 0x2000, 0x0000, 0x0000, 0x0000 },
+ { 0x0000, 0x2000, 0x0000, 0x0000 },
+ { 0x0000, 0x0000, 0x2000, 0x0000 },
+ }, {
+ /* Limited range */
+ { 0x1b80, 0x0000, 0x0000, 0x0400 },
+ { 0x0000, 0x1b80, 0x0000, 0x0400 },
+ { 0x0000, 0x0000, 0x1b80, 0x0400 },
+ }
+};
+
+/*
+ * Conversion between Full Range RGB and YUV using the BT.601 Colorspace
+ *
+ * Full range
+ * [ 0.299000 0.587000 0.114000 0.000000 ]
+ * [ -0.168736 -0.331264 0.500000 128.000000 ]
+ * [ 0.500000 -0.418688 -0.081312 128.000000 ]
+ *
+ * Limited range
+ * [ 0.255785 0.502160 0.097523 16.000000 ]
+ * [ -0.147644 -0.289856 0.437500 128.000000 ]
+ * [ 0.437500 -0.366352 -0.071148 128.000000 ]
+ *
+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
+ */
+static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt601[2][3][4] = {
+ {
+ /* Full range */
+ { 0x0991, 0x12c9, 0x03a6, 0x0000 },
+ { 0xfa9b, 0xf567, 0x1000, 0x2000 },
+ { 0x1000, 0xf29b, 0xfd67, 0x2000 },
+ }, {
+ /* Limited range */
+ { 0x082f, 0x1012, 0x031f, 0x0400 },
+ { 0xfb48, 0xf6ba, 0x0e00, 0x2000 },
+ { 0x0e00, 0xf448, 0xfdba, 0x2000 },
+ }
};
/*
- * Conversion between Full Range RGB and Full Range YUV422 using the
- * BT.709 Colorspace
+ * Conversion between Full Range RGB and YUV using the BT.709 Colorspace
+ *
+ * Full range
+ * [ 0.212600 0.715200 0.072200 0.000000 ]
+ * [ -0.114572 -0.385428 0.500000 128.000000 ]
+ * [ 0.500000 -0.454153 -0.045847 128.000000 ]
*
- * [ 0.212639 0.715169 0.072192 0 ]
- * [ -0.117208 -0.394207 0.511416 128 ]
- * [ 0.511416 -0.464524 -0.046891 128 ]
+ * Limited range
+ * [ 0.181873 0.611831 0.061765 16.000000 ]
+ * [ -0.100251 -0.337249 0.437500 128.000000 ]
+ * [ 0.437500 -0.397384 -0.040116 128.000000 ]
*
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
*/
-static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709[3][4] = {
- { 0x06ce, 0x16e3, 0x024f, 0x0000 },
- { 0xfc41, 0xf364, 0x105e, 0x2000 },
- { 0x105e, 0xf124, 0xfe81, 0x2000 },
+static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt709[2][3][4] = {
+ {
+ /* Full range */
+ { 0x06ce, 0x16e3, 0x024f, 0x0000 },
+ { 0xfc56, 0xf3ac, 0x1000, 0x2000 },
+ { 0x1000, 0xf179, 0xfe89, 0x2000 },
+ }, {
+ /* Limited range */
+ { 0x05d2, 0x1394, 0x01fa, 0x0400 },
+ { 0xfccc, 0xf536, 0x0e00, 0x2000 },
+ { 0x0e00, 0xf34a, 0xfeb8, 0x2000 },
+ }
};
/*
- * Conversion between Full Range RGB and Full Range YUV444 using the
- * BT.709 Colorspace
+ * Conversion between Full Range RGB and YUV using the BT.2020 Colorspace
+ *
+ * Full range
+ * [ 0.262700 0.678000 0.059300 0.000000 ]
+ * [ -0.139630 -0.360370 0.500000 128.000000 ]
+ * [ 0.500000 -0.459786 -0.040214 128.000000 ]
*
- * [ -0.117208 -0.394207 0.511416 128 ]
- * [ 0.511416 -0.464524 -0.046891 128 ]
- * [ 0.212639 0.715169 0.072192 0 ]
+ * Limited range
+ * [ 0.224732 0.580008 0.050729 16.000000 ]
+ * [ -0.122176 -0.315324 0.437500 128.000000 ]
+ * [ 0.437500 -0.402312 -0.035188 128.000000 ]
*
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
*/
-static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709[3][4] = {
- { 0xfc41, 0xf364, 0x105e, 0x2000 },
- { 0x105e, 0xf124, 0xfe81, 0x2000 },
- { 0x06ce, 0x16e3, 0x024f, 0x0000 },
+static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt2020[2][3][4] = {
+ {
+ /* Full range */
+ { 0x0868, 0x15b2, 0x01e6, 0x0000 },
+ { 0xfb89, 0xf479, 0x1000, 0x2000 },
+ { 0x1000, 0xf14a, 0xfeb8, 0x2000 },
+ }, {
+ /* Limited range */
+ { 0x0731, 0x128f, 0x01a0, 0x0400 },
+ { 0xfc18, 0xf5ea, 0x0e00, 0x2000 },
+ { 0x0e00, 0xf321, 0xfee1, 0x2000 },
+ }
};
static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi,
@@ -1021,12 +1074,28 @@ static void vc5_hdmi_set_csc_coeffs(stru
HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]);
}
+static void vc5_hdmi_set_csc_coeffs_swap(struct vc4_hdmi *vc4_hdmi,
+ const u16 coeffs[3][4])
+{
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
+
+ /* YUV444 needs the CSC matrices using the channels in a different order */
+ HDMI_WRITE(HDMI_CSC_12_11, (coeffs[2][1] << 16) | coeffs[2][0]);
+ HDMI_WRITE(HDMI_CSC_14_13, (coeffs[2][3] << 16) | coeffs[2][2]);
+ HDMI_WRITE(HDMI_CSC_22_21, (coeffs[0][1] << 16) | coeffs[0][0]);
+ HDMI_WRITE(HDMI_CSC_24_23, (coeffs[0][3] << 16) | coeffs[0][2]);
+ HDMI_WRITE(HDMI_CSC_32_31, (coeffs[1][1] << 16) | coeffs[1][0]);
+ HDMI_WRITE(HDMI_CSC_34_33, (coeffs[1][3] << 16) | coeffs[1][2]);
+}
+
static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
struct drm_connector_state *state,
const struct drm_display_mode *mode)
{
struct vc4_hdmi_connector_state *vc4_state =
conn_state_to_vc4_hdmi_conn_state(state);
+ unsigned int lim_range = vc4_hdmi_is_full_range(vc4_hdmi, mode) ? 0 : 1;
+ const u16 (*csc)[4];
unsigned long flags;
u32 if_cfg = 0;
u32 if_xbar = 0x543210;
@@ -1038,31 +1107,56 @@ static void vc5_hdmi_csc_setup(struct vc
switch (vc4_state->output_format) {
case VC4_HDMI_OUTPUT_YUV444:
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709);
- break;
-
case VC4_HDMI_OUTPUT_YUV422:
- csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
- VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
- VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
- VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION;
-
- csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE,
- VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP);
+ switch (state->colorspace) {
+ default:
+ case DRM_MODE_COLORIMETRY_NO_DATA:
+ case DRM_MODE_COLORIMETRY_BT709_YCC:
+ case DRM_MODE_COLORIMETRY_XVYCC_709:
+ case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED:
+ case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT:
+ csc = vc5_hdmi_csc_full_rgb_to_yuv_bt709[lim_range];
+ break;
+ case DRM_MODE_COLORIMETRY_SMPTE_170M_YCC:
+ case DRM_MODE_COLORIMETRY_XVYCC_601:
+ case DRM_MODE_COLORIMETRY_SYCC_601:
+ case DRM_MODE_COLORIMETRY_OPYCC_601:
+ case DRM_MODE_COLORIMETRY_BT601_YCC:
+ csc = vc5_hdmi_csc_full_rgb_to_yuv_bt601[lim_range];
+ break;
+ case DRM_MODE_COLORIMETRY_BT2020_CYCC:
+ case DRM_MODE_COLORIMETRY_BT2020_YCC:
+ case DRM_MODE_COLORIMETRY_BT2020_RGB:
+ case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
+ case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
+ csc = vc5_hdmi_csc_full_rgb_to_yuv_bt2020[lim_range];
+ break;
+ }
- if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
- VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
+ if (vc4_state->output_format == VC4_HDMI_OUTPUT_YUV422) {
+ csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
+ VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
+ VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
+ VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION;
+
+ csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE,
+ VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP);
+
+ if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
+ VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
+
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, csc);
+ } else {
+ vc5_hdmi_set_csc_coeffs_swap(vc4_hdmi, csc);
+ }
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709);
break;
case VC4_HDMI_OUTPUT_RGB:
if_xbar = 0x354021;
- if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
- else
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi,
+ vc5_hdmi_csc_full_rgb_to_rgb[lim_range]);
break;
default: