mirror of
https://github.com/libretro/Lakka-LibreELEC.git
synced 2024-12-15 19:09:46 +00:00
911 lines
29 KiB
Diff
911 lines
29 KiB
Diff
From bf64e38ca38de03d894db29cf0f006a03ec93688 Mon Sep 17 00:00:00 2001
|
|
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
Date: Sun, 24 Sep 2023 13:20:12 +0200
|
|
Subject: [PATCH 13/25] WIP: drm/sun4i: de3: Add support for YUV420 output
|
|
|
|
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
---
|
|
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 24 ++-
|
|
drivers/gpu/drm/drm_atomic_state_helper.c | 7 +
|
|
drivers/gpu/drm/sun4i/Makefile | 3 +-
|
|
drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 +++-
|
|
drivers/gpu/drm/sun4i/sun50i_fmt.c | 74 ++++++++++
|
|
drivers/gpu/drm/sun4i/sun50i_fmt.h | 30 ++++
|
|
drivers/gpu/drm/sun4i/sun8i_csc.c | 172 +++++++++++++++++++++-
|
|
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 121 ++++++++++++++-
|
|
drivers/gpu/drm/sun4i/sun8i_mixer.c | 52 ++++++-
|
|
drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 +
|
|
drivers/gpu/drm/sun4i/sunxi_engine.h | 34 +++++
|
|
11 files changed, 515 insertions(+), 30 deletions(-)
|
|
create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
|
|
create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
index 348f58b45e72..fc3c8c660d75 100644
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
|
@@ -1019,19 +1019,15 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
|
|
color_format = 0x07;
|
|
break;
|
|
|
|
- case MEDIA_BUS_FMT_YUV8_1X24:
|
|
case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
|
|
color_format = 0x09;
|
|
break;
|
|
- case MEDIA_BUS_FMT_YUV10_1X30:
|
|
case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
color_format = 0x0B;
|
|
break;
|
|
- case MEDIA_BUS_FMT_YUV12_1X36:
|
|
case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
|
|
color_format = 0x0D;
|
|
break;
|
|
- case MEDIA_BUS_FMT_YUV16_1X48:
|
|
case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
|
|
color_format = 0x0F;
|
|
break;
|
|
@@ -1046,6 +1042,19 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
|
|
color_format = 0x12;
|
|
break;
|
|
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ color_format = 0x17;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ color_format = 0x19;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_YUV12_1X36:
|
|
+ color_format = 0x1B;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_YUV16_1X48:
|
|
+ color_format = 0x1D;
|
|
+ break;
|
|
+
|
|
default:
|
|
return;
|
|
}
|
|
@@ -1165,7 +1174,7 @@ static void hdmi_video_csc(struct dw_hdmi *hdmi)
|
|
if (is_color_space_interpolation(hdmi))
|
|
interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
|
|
else if (is_color_space_decimation(hdmi))
|
|
- decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
|
|
+ decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1;
|
|
|
|
switch (hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format)) {
|
|
case 8:
|
|
@@ -1207,7 +1216,6 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
|
|
u8 val, vp_conf;
|
|
u8 clear_gcp_auto = 0;
|
|
|
|
-
|
|
if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
|
|
hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format) ||
|
|
hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
|
|
@@ -1803,7 +1811,9 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi,
|
|
frame.colorspace = HDMI_COLORSPACE_RGB;
|
|
|
|
/* Set up colorimetry */
|
|
- if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
|
|
+ if (connector->colorspace_property) {
|
|
+ drm_hdmi_avi_infoframe_colorimetry(&frame, connector->state);
|
|
+ } else if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
|
|
switch (hdmi->hdmi_data.enc_out_encoding) {
|
|
case V4L2_YCBCR_ENC_601:
|
|
if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
|
|
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
|
|
index 784e63d70a42..1f9cf2bc6445 100644
|
|
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
|
|
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
|
|
@@ -415,7 +415,14 @@ void
|
|
__drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_state,
|
|
struct drm_connector *connector)
|
|
{
|
|
+ struct drm_property *prop;
|
|
+
|
|
conn_state->connector = connector;
|
|
+ prop = connector->max_bpc_property;
|
|
+ if (prop) {
|
|
+ conn_state->max_bpc = prop->values[1];
|
|
+ conn_state->max_requested_bpc = prop->values[1];
|
|
+ }
|
|
}
|
|
EXPORT_SYMBOL(__drm_atomic_helper_connector_state_reset);
|
|
|
|
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
|
|
index bad7497a0d11..3f516329f51e 100644
|
|
--- a/drivers/gpu/drm/sun4i/Makefile
|
|
+++ b/drivers/gpu/drm/sun4i/Makefile
|
|
@@ -16,7 +16,8 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
|
|
|
|
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
|
|
sun8i_vi_layer.o sun8i_ui_scaler.o \
|
|
- sun8i_vi_scaler.o sun8i_csc.o
|
|
+ sun8i_vi_scaler.o sun8i_csc.o \
|
|
+ sun50i_fmt.o
|
|
|
|
sun4i-tcon-y += sun4i_crtc.o
|
|
sun4i-tcon-y += sun4i_tcon_dclk.o
|
|
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
|
|
index a1a2c845ade0..e39926e9f0b5 100644
|
|
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
|
|
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
|
|
@@ -598,14 +598,26 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
|
|
static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
- unsigned int bp, hsync, vsync, vtotal;
|
|
+ unsigned int bp, hsync, vsync, vtotal, div;
|
|
+ struct sun4i_crtc *scrtc = tcon->crtc;
|
|
+ struct sunxi_engine *engine = scrtc->engine;
|
|
u8 clk_delay;
|
|
u32 val;
|
|
|
|
WARN_ON(!tcon->quirks->has_channel_1);
|
|
|
|
+ switch (engine->format) {
|
|
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
|
|
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
+ div = 2;
|
|
+ break;
|
|
+ default:
|
|
+ div = 1;
|
|
+ break;
|
|
+ }
|
|
+
|
|
/* Configure the dot clock */
|
|
- clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
|
|
+ clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000 / div);
|
|
|
|
/* Adjust clock delay */
|
|
clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
|
|
@@ -624,17 +636,17 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
|
|
|
|
/* Set the input resolution */
|
|
regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
|
|
- SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
|
|
+ SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay / div) |
|
|
SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
|
|
|
|
/* Set the upscaling resolution */
|
|
regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
|
|
- SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
|
|
+ SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay / div) |
|
|
SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
|
|
|
|
/* Set the output resolution */
|
|
regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
|
|
- SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
|
|
+ SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay / div) |
|
|
SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
|
|
|
|
/* Set horizontal display timings */
|
|
@@ -642,8 +654,8 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
|
|
DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
|
|
mode->htotal, bp);
|
|
regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
|
|
- SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
|
|
- SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
|
|
+ SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal / div) |
|
|
+ SUN4I_TCON1_BASIC3_H_BACKPORCH(bp / div));
|
|
|
|
bp = mode->crtc_vtotal - mode->crtc_vsync_start;
|
|
DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
|
|
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c b/drivers/gpu/drm/sun4i/sun50i_fmt.c
|
|
new file mode 100644
|
|
index 000000000000..18a8d5032ddc
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
|
|
@@ -0,0 +1,74 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
+/*
|
|
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
+ */
|
|
+
|
|
+#include <uapi/linux/media-bus-format.h>
|
|
+
|
|
+#include "sun50i_fmt.h"
|
|
+
|
|
+static bool sun50i_fmt_is_10bit(u32 format)
|
|
+{
|
|
+ switch (format) {
|
|
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
+ case MEDIA_BUS_FMT_UYVY10_1X20:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+static u32 sun50i_fmt_get_colorspace(u32 format)
|
|
+{
|
|
+ switch (format) {
|
|
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
|
|
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
+ return SUN50I_FMT_CS_YUV420;
|
|
+ case MEDIA_BUS_FMT_UYVY8_1X16:
|
|
+ case MEDIA_BUS_FMT_UYVY10_1X20:
|
|
+ return SUN50I_FMT_CS_YUV422;
|
|
+ default:
|
|
+ return SUN50I_FMT_CS_YUV444RGB;
|
|
+ }
|
|
+}
|
|
+
|
|
+void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
|
|
+ u16 height, u32 format)
|
|
+{
|
|
+ u32 colorspace, limit[3];
|
|
+ bool bit10;
|
|
+
|
|
+ colorspace = sun50i_fmt_get_colorspace(format);
|
|
+ bit10 = sun50i_fmt_is_10bit(format);
|
|
+
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_CTRL, 0);
|
|
+
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_SIZE,
|
|
+ SUN8I_MIXER_SIZE(width, height));
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_SWAP, 0);
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_DEPTH, bit10);
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_FORMAT, colorspace);
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_COEF, 0);
|
|
+
|
|
+ if (colorspace != SUN50I_FMT_CS_YUV444RGB) {
|
|
+ limit[0] = SUN50I_FMT_LIMIT(64, 940);
|
|
+ limit[1] = SUN50I_FMT_LIMIT(64, 960);
|
|
+ limit[2] = SUN50I_FMT_LIMIT(64, 960);
|
|
+ } else if (bit10) {
|
|
+ limit[0] = SUN50I_FMT_LIMIT(0, 1023);
|
|
+ limit[1] = SUN50I_FMT_LIMIT(0, 1023);
|
|
+ limit[2] = SUN50I_FMT_LIMIT(0, 1023);
|
|
+ } else {
|
|
+ limit[0] = SUN50I_FMT_LIMIT(0, 1021);
|
|
+ limit[1] = SUN50I_FMT_LIMIT(0, 1021);
|
|
+ limit[2] = SUN50I_FMT_LIMIT(0, 1021);
|
|
+ }
|
|
+
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_LMT_Y, limit[0]);
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_LMT_C0, limit[1]);
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_LMT_C1, limit[2]);
|
|
+
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FMT_CTRL, 1);
|
|
+}
|
|
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h b/drivers/gpu/drm/sun4i/sun50i_fmt.h
|
|
new file mode 100644
|
|
index 000000000000..0fa1d2d22e59
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
|
|
@@ -0,0 +1,30 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
+/*
|
|
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
+ */
|
|
+
|
|
+#ifndef _SUN50I_FMT_H_
|
|
+#define _SUN50I_FMT_H_
|
|
+
|
|
+#include "sun8i_mixer.h"
|
|
+
|
|
+#define SUN50I_FMT_CTRL 0xa8000
|
|
+#define SUN50I_FMT_SIZE 0xa8004
|
|
+#define SUN50I_FMT_SWAP 0xa8008
|
|
+#define SUN50I_FMT_DEPTH 0xa800c
|
|
+#define SUN50I_FMT_FORMAT 0xa8010
|
|
+#define SUN50I_FMT_COEF 0xa8014
|
|
+#define SUN50I_FMT_LMT_Y 0xa8020
|
|
+#define SUN50I_FMT_LMT_C0 0xa8024
|
|
+#define SUN50I_FMT_LMT_C1 0xa8028
|
|
+
|
|
+#define SUN50I_FMT_LIMIT(low, high) (((high) << 16) | (low))
|
|
+
|
|
+#define SUN50I_FMT_CS_YUV444RGB 0
|
|
+#define SUN50I_FMT_CS_YUV422 1
|
|
+#define SUN50I_FMT_CS_YUV420 2
|
|
+
|
|
+void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
|
|
+ u16 height, u32 format);
|
|
+
|
|
+#endif
|
|
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
|
index 68d955c63b05..3b022bfb85ad 100644
|
|
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
|
|
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
|
@@ -5,6 +5,8 @@
|
|
|
|
#include <drm/drm_print.h>
|
|
|
|
+#include <uapi/linux/media-bus-format.h>
|
|
+
|
|
#include "sun8i_csc.h"
|
|
#include "sun8i_mixer.h"
|
|
|
|
@@ -107,12 +109,141 @@ static const u32 yuv2rgb_de3[2][3][12] = {
|
|
},
|
|
};
|
|
|
|
+/* always convert to limited mode */
|
|
+static const u32 rgb2yuv_de3[3][12] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ 0x0000837A, 0x0001021D, 0x00003221, 0x00000040,
|
|
+ 0xFFFFB41C, 0xFFFF6B03, 0x0000E0E1, 0x00000200,
|
|
+ 0x0000E0E1, 0xFFFF43B1, 0xFFFFDB6E, 0x00000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ 0x00005D7C, 0x00013A7C, 0x00001FBF, 0x00000040,
|
|
+ 0xFFFFCC78, 0xFFFF52A7, 0x0000E0E1, 0x00000200,
|
|
+ 0x0000E0E1, 0xFFFF33BE, 0xFFFFEB61, 0x00000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ 0x00007384, 0x00012A21, 0x00001A13, 0x00000040,
|
|
+ 0xFFFFC133, 0xFFFF5DEC, 0x0000E0E1, 0x00000200,
|
|
+ 0x0000E0E1, 0xFFFF3135, 0xFFFFEDEA, 0x00000200,
|
|
+ },
|
|
+};
|
|
+
|
|
+/* always convert to limited mode */
|
|
+static const u32 yuv2yuv_de3[2][3][3][12] = {
|
|
+ [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ 0x00020000, 0x00000000, 0x00000000, 0x00000000,
|
|
+ 0x00000000, 0x00020000, 0x00000000, 0x00000000,
|
|
+ 0x00000000, 0x00000000, 0x00020000, 0x00000000,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ 0x00020000, 0xFFFFC4D7, 0xFFFF9589, 0xFFC00040,
|
|
+ 0x00000000, 0x0002098B, 0x00003AAF, 0xFE000200,
|
|
+ 0x00000000, 0x0000266D, 0x00020CF8, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ 0x00020000, 0xFFFFBFCE, 0xFFFFC5FF, 0xFFC00040,
|
|
+ 0x00000000, 0x00020521, 0x00001F89, 0xFE000200,
|
|
+ 0x00000000, 0x00002C87, 0x00020F07, 0xFE000200,
|
|
+ },
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ 0x00020000, 0x000032D9, 0x00006226, 0xFFC00040,
|
|
+ 0x00000000, 0x0001FACE, 0xFFFFC759, 0xFE000200,
|
|
+ 0x00000000, 0xFFFFDAE7, 0x0001F780, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ 0x00020000, 0x00000000, 0x00000000, 0x00000000,
|
|
+ 0x00000000, 0x00020000, 0x00000000, 0x00000000,
|
|
+ 0x00000000, 0x00000000, 0x00020000, 0x00000000,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ 0x00020000, 0xFFFFF782, 0x00003036, 0xFFC00040,
|
|
+ 0x00000000, 0x0001FD99, 0xFFFFE5CA, 0xFE000200,
|
|
+ 0x00000000, 0x000005E4, 0x0002015A, 0xFE000200,
|
|
+ },
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ 0x00020000, 0x00003B03, 0x000034D2, 0xFFC00040,
|
|
+ 0x00000000, 0x0001FD8C, 0xFFFFE183, 0xFE000200,
|
|
+ 0x00000000, 0xFFFFD4F3, 0x0001F3FA, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ 0x00020000, 0x00000916, 0xFFFFD061, 0xFFC00040,
|
|
+ 0x00000000, 0x0002021C, 0x00001A40, 0xFE000200,
|
|
+ 0x00000000, 0xFFFFFA19, 0x0001FE5A, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ 0x00020000, 0x00000000, 0x00000000, 0x00000000,
|
|
+ 0x00000000, 0x00020000, 0x00000000, 0x00000000,
|
|
+ 0x00000000, 0x00000000, 0x00020000, 0x00000000,
|
|
+ },
|
|
+ },
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_FULL_RANGE] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ 0x0001B7B8, 0x00000000, 0x00000000, 0x00000040,
|
|
+ 0x00000000, 0x0001C1C2, 0x00000000, 0xFE000200,
|
|
+ 0x00000000, 0x00000000, 0x0001C1C2, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ 0x0001B7B8, 0xFFFFCC08, 0xFFFFA27B, 0x00000040,
|
|
+ 0x00000000, 0x0001CA24, 0x0000338D, 0xFE000200,
|
|
+ 0x00000000, 0x000021C1, 0x0001CD26, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ 0x0001B7B8, 0xFFFFC79C, 0xFFFFCD0C, 0x00000040,
|
|
+ 0x00000000, 0x0001C643, 0x00001BB4, 0xFE000200,
|
|
+ 0x00000000, 0x0000271D, 0x0001CEF5, 0xFE000200,
|
|
+ },
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ 0x0001B7B8, 0x00002CAB, 0x00005638, 0x00000040,
|
|
+ 0x00000000, 0x0001BD32, 0xFFFFCE3C, 0xFE000200,
|
|
+ 0x00000000, 0xFFFFDF6A, 0x0001BA4A, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ 0x0001B7B8, 0x00000000, 0x00000000, 0x00000040,
|
|
+ 0x00000000, 0x0001C1C2, 0x00000000, 0xFE000200,
|
|
+ 0x00000000, 0x00000000, 0x0001C1C2, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ 0x0001B7B8, 0xFFFFF88A, 0x00002A5A, 0x00000040,
|
|
+ 0x00000000, 0x0001BFA5, 0xFFFFE8FA, 0xFE000200,
|
|
+ 0x00000000, 0x0000052D, 0x0001C2F1, 0xFE000200,
|
|
+ },
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ [DRM_COLOR_YCBCR_BT601] = {
|
|
+ 0x0001B7B8, 0x000033D6, 0x00002E66, 0x00000040,
|
|
+ 0x00000000, 0x0001BF9A, 0xFFFFE538, 0xFE000200,
|
|
+ 0x00000000, 0xFFFFDA2F, 0x0001B732, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT709] = {
|
|
+ 0x0001B7B8, 0x000007FB, 0xFFFFD62B, 0x00000040,
|
|
+ 0x00000000, 0x0001C39D, 0x0000170F, 0xFE000200,
|
|
+ 0x00000000, 0xFFFFFAD1, 0x0001C04F, 0xFE000200,
|
|
+ },
|
|
+ [DRM_COLOR_YCBCR_BT2020] = {
|
|
+ 0x0001B7B8, 0x00000000, 0x00000000, 0x00000040,
|
|
+ 0x00000000, 0x0001C1C2, 0x00000000, 0xFE000200,
|
|
+ 0x00000000, 0x00000000, 0x0001C1C2, 0xFE000200,
|
|
+ },
|
|
+ },
|
|
+ },
|
|
+};
|
|
+
|
|
static void sun8i_csc_setup(struct regmap *map, u32 base,
|
|
enum format_type fmt_type,
|
|
enum drm_color_encoding encoding,
|
|
enum drm_color_range range)
|
|
{
|
|
- u32 base_reg, val;
|
|
+ u32 base_reg, val = 0;
|
|
const u32 *table;
|
|
int i;
|
|
|
|
@@ -148,28 +279,59 @@ static void sun8i_csc_setup(struct regmap *map, u32 base,
|
|
regmap_write(map, SUN8I_CSC_CTRL(base), val);
|
|
}
|
|
|
|
-static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
|
|
+static const u32 *sun8i_csc_get_de3_yuv_table(enum drm_color_encoding in_enc,
|
|
+ enum drm_color_range in_range,
|
|
+ u32 out_format,
|
|
+ enum drm_color_encoding out_enc)
|
|
+{
|
|
+ if (out_format == MEDIA_BUS_FMT_RGB888_1X24)
|
|
+ return yuv2rgb_de3[in_range][in_enc];
|
|
+
|
|
+ /* check for identity transformation */
|
|
+ if (in_range == DRM_COLOR_YCBCR_LIMITED_RANGE && out_enc == in_enc)
|
|
+ return NULL;
|
|
+
|
|
+ return yuv2yuv_de3[in_range][in_enc][out_enc];
|
|
+}
|
|
+
|
|
+static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
|
|
enum format_type fmt_type,
|
|
enum drm_color_encoding encoding,
|
|
enum drm_color_range range)
|
|
{
|
|
- u32 addr, val, mask;
|
|
+ u32 addr, val = 0, mask;
|
|
+ struct regmap *map;
|
|
const u32 *table;
|
|
int i;
|
|
|
|
mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
|
|
table = yuv2rgb_de3[range][encoding];
|
|
+ map = engine->regs;
|
|
|
|
switch (fmt_type) {
|
|
case FORMAT_TYPE_RGB:
|
|
- val = 0;
|
|
+ if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
|
|
+ break;
|
|
+ val = mask;
|
|
+ addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
|
|
+ regmap_bulk_write(map, addr, rgb2yuv_de3[engine->encoding], 12);
|
|
break;
|
|
case FORMAT_TYPE_YUV:
|
|
+ table = sun8i_csc_get_de3_yuv_table(encoding, range,
|
|
+ engine->format,
|
|
+ engine->encoding);
|
|
+ if (!table)
|
|
+ break;
|
|
val = mask;
|
|
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
|
|
regmap_bulk_write(map, addr, table, 12);
|
|
break;
|
|
case FORMAT_TYPE_YVU:
|
|
+ table = sun8i_csc_get_de3_yuv_table(encoding, range,
|
|
+ engine->format,
|
|
+ engine->encoding);
|
|
+ if (!table)
|
|
+ table = yuv2yuv_de3[range][encoding][encoding];
|
|
val = mask;
|
|
for (i = 0; i < 12; i++) {
|
|
if ((i & 3) == 1)
|
|
@@ -204,7 +366,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
|
|
u32 base;
|
|
|
|
if (mixer->cfg->is_de3) {
|
|
- sun8i_de3_ccsc_setup(mixer->engine.regs, layer,
|
|
+ sun8i_de3_ccsc_setup(&mixer->engine, layer,
|
|
fmt_type, encoding, range);
|
|
return;
|
|
}
|
|
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
|
index 22e084989ee6..0837e2576556 100644
|
|
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
|
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
|
@@ -7,18 +7,25 @@
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
+#include <linux/videodev2.h>
|
|
|
|
#include <drm/drm_atomic_state_helper.h>
|
|
#include <drm/drm_bridge_connector.h>
|
|
#include <drm/drm_managed.h>
|
|
#include <drm/drm_modeset_helper_vtables.h>
|
|
#include <drm/drm_of.h>
|
|
+#include <drm/drm_print.h>
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
#include <media/cec-notifier.h>
|
|
|
|
+#include <uapi/linux/media-bus-format.h>
|
|
+
|
|
+#include "sun4i_crtc.h"
|
|
+#include "sun4i_tcon.h"
|
|
#include "sun8i_dw_hdmi.h"
|
|
#include "sun8i_tcon_top.h"
|
|
+#include "sunxi_engine.h"
|
|
|
|
#define bridge_to_sun8i_dw_hdmi(x) \
|
|
container_of(x, struct sun8i_dw_hdmi, enc_bridge)
|
|
@@ -64,16 +71,85 @@ static int sun8i_hdmi_enc_atomic_check(struct drm_bridge *bridge,
|
|
struct drm_crtc_state *crtc_state,
|
|
struct drm_connector_state *conn_state)
|
|
{
|
|
- struct drm_connector_state *old_conn_state =
|
|
+ struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(crtc_state->crtc);
|
|
+ struct sunxi_engine *engine = crtc->engine;
|
|
+ struct drm_connector_state *old_conn_state;
|
|
+
|
|
+ old_conn_state =
|
|
drm_atomic_get_old_connector_state(conn_state->state,
|
|
conn_state->connector);
|
|
|
|
+ switch (conn_state->colorspace) {
|
|
+ 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:
|
|
+ engine->encoding = DRM_COLOR_YCBCR_BT601;
|
|
+ break;
|
|
+
|
|
+ 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:
|
|
+ engine->encoding = DRM_COLOR_YCBCR_BT709;
|
|
+ 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:
|
|
+ engine->encoding = DRM_COLOR_YCBCR_BT2020;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ engine->format = bridge_state->output_bus_cfg.format;
|
|
+ DRM_DEBUG_DRIVER("HDMI output bus format: 0x%04x\n", engine->format);
|
|
+
|
|
if (!drm_connector_atomic_hdr_metadata_equal(old_conn_state, conn_state))
|
|
crtc_state->mode_changed = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
+static u32 *
|
|
+sun8i_hdmi_enc_get_input_bus_fmts(struct drm_bridge *bridge,
|
|
+ struct drm_bridge_state *bridge_state,
|
|
+ struct drm_crtc_state *crtc_state,
|
|
+ struct drm_connector_state *conn_state,
|
|
+ u32 output_fmt,
|
|
+ unsigned int *num_input_fmts)
|
|
+{
|
|
+ struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(crtc_state->crtc);
|
|
+ u32 *input_fmt, *supported, count, i;
|
|
+
|
|
+ *num_input_fmts = 0;
|
|
+ input_fmt = NULL;
|
|
+
|
|
+ supported = sunxi_engine_get_supported_formats(crtc->engine, &count);
|
|
+ if (count == 0 || !supported)
|
|
+ return NULL;
|
|
+
|
|
+ for (i = 0; i < count; i++)
|
|
+ if (output_fmt == supported[i]) {
|
|
+ input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL);
|
|
+ if (!input_fmt)
|
|
+ break;
|
|
+
|
|
+ *num_input_fmts = 1;
|
|
+ *input_fmt = output_fmt;
|
|
+
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ kfree(supported);
|
|
+
|
|
+ return input_fmt;
|
|
+}
|
|
+
|
|
static const struct drm_bridge_funcs sun8i_hdmi_enc_bridge_funcs = {
|
|
.attach = sun8i_hdmi_enc_attach,
|
|
.detach = sun8i_hdmi_enc_detach,
|
|
@@ -81,21 +157,36 @@ static const struct drm_bridge_funcs sun8i_hdmi_enc_bridge_funcs = {
|
|
.atomic_check = sun8i_hdmi_enc_atomic_check,
|
|
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
|
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
|
+ .atomic_get_input_bus_fmts = sun8i_hdmi_enc_get_input_bus_fmts,
|
|
.atomic_reset = drm_atomic_helper_bridge_reset,
|
|
};
|
|
|
|
-static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|
- struct drm_display_mode *mode,
|
|
- struct drm_display_mode *adj_mode)
|
|
+static void
|
|
+sun8i_dw_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
|
|
+ struct drm_crtc_state *crtc_state,
|
|
+ struct drm_connector_state *conn_state)
|
|
{
|
|
+ struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(crtc_state->crtc);
|
|
struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder);
|
|
+ struct drm_display_mode *mode = &crtc_state->adjusted_mode;
|
|
+ int div;
|
|
|
|
- clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
|
|
+ switch (crtc->engine->format) {
|
|
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
|
|
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
|
+ div = 2;
|
|
+ break;
|
|
+ default:
|
|
+ div = 1;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000 / div);
|
|
}
|
|
|
|
static const struct drm_encoder_helper_funcs
|
|
sun8i_dw_hdmi_encoder_helper_funcs = {
|
|
- .mode_set = sun8i_dw_hdmi_encoder_mode_set,
|
|
+ .atomic_mode_set = sun8i_dw_hdmi_encoder_atomic_mode_set,
|
|
};
|
|
|
|
static enum drm_mode_status
|
|
@@ -114,6 +205,11 @@ sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data,
|
|
const struct drm_display_info *info,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
+ unsigned long clock = mode->crtc_clock * 1000;
|
|
+
|
|
+ if (drm_mode_is_420(info, mode))
|
|
+ clock /= 2;
|
|
+
|
|
/*
|
|
* Controller support maximum of 594 MHz, which correlates to
|
|
* 4K@60Hz 4:4:4 or RGB.
|
|
@@ -257,6 +353,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
|
|
|
plat_data->mode_valid = hdmi->quirks->mode_valid;
|
|
plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe;
|
|
+ plat_data->ycbcr_420_allowed = hdmi->quirks->use_drm_infoframe;
|
|
+ plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
|
|
plat_data->output_port = 1;
|
|
sun8i_hdmi_phy_set_ops(phy, plat_data);
|
|
|
|
@@ -291,8 +389,17 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
|
hdmi->connector = connector;
|
|
drm_connector_attach_encoder(connector, encoder);
|
|
|
|
- if (hdmi->quirks->use_drm_infoframe)
|
|
+ drm_atomic_helper_connector_reset(connector);
|
|
+
|
|
+ drm_mode_create_hdmi_colorspace_property(connector, 0);
|
|
+
|
|
+ if (hdmi->quirks->use_drm_infoframe) {
|
|
drm_connector_attach_hdr_output_metadata_property(connector);
|
|
+ drm_connector_attach_max_bpc_property(connector, 8, 12);
|
|
+ drm_connector_attach_colorspace_property(connector);
|
|
+ }
|
|
+
|
|
+ connector->ycbcr_420_allowed = hdmi->quirks->use_drm_infoframe;
|
|
|
|
cec_fill_conn_info_from_drm(&conn_info, connector);
|
|
|
|
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
|
index 01382860aaee..b1525906a25d 100644
|
|
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
|
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
|
@@ -22,7 +22,10 @@
|
|
#include <drm/drm_gem_dma_helper.h>
|
|
#include <drm/drm_probe_helper.h>
|
|
|
|
+#include <uapi/linux/media-bus-format.h>
|
|
+
|
|
#include "sun4i_drv.h"
|
|
+#include "sun50i_fmt.h"
|
|
#include "sun8i_mixer.h"
|
|
#include "sun8i_ui_layer.h"
|
|
#include "sun8i_vi_layer.h"
|
|
@@ -326,12 +329,52 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
|
|
|
|
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
|
|
interlaced ? "on" : "off");
|
|
+
|
|
+ if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
|
|
+ val = SUN8I_MIXER_BLEND_COLOR_BLACK;
|
|
+ else
|
|
+ val = 0xff108080;
|
|
+
|
|
+ regmap_write(mixer->engine.regs,
|
|
+ SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
|
|
+ regmap_write(mixer->engine.regs,
|
|
+ SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
|
|
+
|
|
+ if (mixer->cfg->has_formatter)
|
|
+ sun50i_fmt_setup(mixer, mode->hdisplay,
|
|
+ mode->vdisplay, mixer->engine.format);
|
|
+}
|
|
+
|
|
+static u32 *sun8i_mixer_get_supported_fmts(struct sunxi_engine *engine, u32 *num)
|
|
+{
|
|
+ struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
|
|
+ u32 *formats, count;
|
|
+
|
|
+ count = 0;
|
|
+
|
|
+ formats = kcalloc(5, sizeof(*formats), GFP_KERNEL);
|
|
+ if (!formats)
|
|
+ return NULL;
|
|
+
|
|
+ if (mixer->cfg->has_formatter) {
|
|
+ formats[count++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
|
|
+ formats[count++] = MEDIA_BUS_FMT_YUV8_1X24;
|
|
+ formats[count++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
|
+ formats[count++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
|
|
+ }
|
|
+
|
|
+ formats[count++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
+
|
|
+ *num = count;
|
|
+
|
|
+ return formats;
|
|
}
|
|
|
|
static const struct sunxi_engine_ops sun8i_engine_ops = {
|
|
- .commit = sun8i_mixer_commit,
|
|
- .layers_init = sun8i_layers_init,
|
|
- .mode_set = sun8i_mixer_mode_set,
|
|
+ .commit = sun8i_mixer_commit,
|
|
+ .layers_init = sun8i_layers_init,
|
|
+ .mode_set = sun8i_mixer_mode_set,
|
|
+ .get_supported_fmts = sun8i_mixer_get_supported_fmts,
|
|
};
|
|
|
|
static const struct regmap_config sun8i_mixer_regmap_config = {
|
|
@@ -392,6 +435,8 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
|
|
dev_set_drvdata(dev, mixer);
|
|
mixer->engine.ops = &sun8i_engine_ops;
|
|
mixer->engine.node = dev->of_node;
|
|
+ /* default output format, supported by all mixers */
|
|
+ mixer->engine.format = MEDIA_BUS_FMT_RGB888_1X24;
|
|
|
|
if (of_property_present(dev->of_node, "iommus")) {
|
|
/*
|
|
@@ -653,6 +698,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
|
|
static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
|
|
.ccsc = CCSC_MIXER0_LAYOUT,
|
|
.is_de3 = true,
|
|
+ .has_formatter = 1,
|
|
.mod_rate = 600000000,
|
|
.scaler_mask = 0xf,
|
|
.scanline_yuv = 4096,
|
|
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
|
index 85c94884fb9a..13401643c7bf 100644
|
|
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
|
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
|
@@ -162,6 +162,7 @@ enum {
|
|
* @mod_rate: module clock rate that needs to be set in order to have
|
|
* a functional block.
|
|
* @is_de3: true, if this is next gen display engine 3.0, false otherwise.
|
|
+ * @has_formatter: true, if mixer has formatter core, for 10-bit and YUV handling
|
|
* @scaline_yuv: size of a scanline for VI scaler for YUV formats.
|
|
*/
|
|
struct sun8i_mixer_cfg {
|
|
@@ -171,6 +172,7 @@ struct sun8i_mixer_cfg {
|
|
int ccsc;
|
|
unsigned long mod_rate;
|
|
unsigned int is_de3 : 1;
|
|
+ unsigned int has_formatter : 1;
|
|
unsigned int scanline_yuv;
|
|
};
|
|
|
|
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
|
|
index ec8cf9b2bda4..608a26c3f991 100644
|
|
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
|
|
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
|
|
@@ -6,6 +6,8 @@
|
|
#ifndef _SUNXI_ENGINE_H_
|
|
#define _SUNXI_ENGINE_H_
|
|
|
|
+#include <drm/drm_color_mgmt.h>
|
|
+
|
|
struct drm_plane;
|
|
struct drm_device;
|
|
struct drm_crtc_state;
|
|
@@ -120,6 +122,17 @@ struct sunxi_engine_ops {
|
|
*/
|
|
void (*mode_set)(struct sunxi_engine *engine,
|
|
const struct drm_display_mode *mode);
|
|
+
|
|
+ /**
|
|
+ * @get_supported_fmts
|
|
+ *
|
|
+ * This callback is used to enumerate all supported output
|
|
+ * formats by the engine. They are used for bridge format
|
|
+ * negotiation.
|
|
+ *
|
|
+ * This function is optional.
|
|
+ */
|
|
+ u32 *(*get_supported_fmts)(struct sunxi_engine *engine, u32 *num);
|
|
};
|
|
|
|
/**
|
|
@@ -137,6 +150,9 @@ struct sunxi_engine {
|
|
|
|
int id;
|
|
|
|
+ u32 format;
|
|
+ enum drm_color_encoding encoding;
|
|
+
|
|
/* Engine list management */
|
|
struct list_head list;
|
|
};
|
|
@@ -208,4 +224,22 @@ sunxi_engine_mode_set(struct sunxi_engine *engine,
|
|
if (engine->ops && engine->ops->mode_set)
|
|
engine->ops->mode_set(engine, mode);
|
|
}
|
|
+
|
|
+/**
|
|
+ * sunxi_engine_get_supported_formats - Provide array of supported formats
|
|
+ * @engine: pointer to the engine
|
|
+ * @num: pointer to variable, which will hold number of formats
|
|
+ *
|
|
+ * This list can be used for format negotiation by bridge.
|
|
+ */
|
|
+static inline u32 *
|
|
+sunxi_engine_get_supported_formats(struct sunxi_engine *engine, u32 *num)
|
|
+{
|
|
+ if (engine->ops && engine->ops->get_supported_fmts)
|
|
+ return engine->ops->get_supported_fmts(engine, num);
|
|
+
|
|
+ *num = 0;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
#endif /* _SUNXI_ENGINE_H_ */
|
|
--
|
|
2.42.0
|
|
|