mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-24 11:16:51 +00:00
Allwinner: linux: Add 10-bit HDMI and Cedrus support
This commit is contained in:
parent
3855985fae
commit
6cddae6dee
@ -4202,7 +4202,7 @@ CONFIG_DRM_PANEL_BRIDGE=y
|
||||
#
|
||||
# CONFIG_DRM_CHIPONE_ICN6211 is not set
|
||||
# CONFIG_DRM_CHRONTEL_CH7033 is not set
|
||||
# CONFIG_DRM_DISPLAY_CONNECTOR is not set
|
||||
CONFIG_DRM_DISPLAY_CONNECTOR=y
|
||||
# CONFIG_DRM_ITE_IT6505 is not set
|
||||
# CONFIG_DRM_LONTIUM_LT8912B is not set
|
||||
# CONFIG_DRM_LONTIUM_LT9211 is not set
|
||||
|
@ -3928,7 +3928,7 @@ CONFIG_DRM_PANEL_BRIDGE=y
|
||||
#
|
||||
# CONFIG_DRM_CHIPONE_ICN6211 is not set
|
||||
# CONFIG_DRM_CHRONTEL_CH7033 is not set
|
||||
CONFIG_DRM_DISPLAY_CONNECTOR=m
|
||||
CONFIG_DRM_DISPLAY_CONNECTOR=y
|
||||
# CONFIG_DRM_ITE_IT6505 is not set
|
||||
# CONFIG_DRM_LONTIUM_LT8912B is not set
|
||||
# CONFIG_DRM_LONTIUM_LT9211 is not set
|
||||
|
@ -27,7 +27,7 @@ new file mode 100644
|
||||
index 000000000000..6a5df1103a90
|
||||
--- /dev/null
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
|
||||
@@ -0,0 +1,315 @@
|
||||
@@ -0,0 +1,316 @@
|
||||
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
+// Copyright (C) 2023 Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
+// Based on sun50i-h6-orangepi-3.dts, which is:
|
||||
@ -37,6 +37,7 @@ index 000000000000..6a5df1103a90
|
||||
+
|
||||
+#include "sun50i-h6.dtsi"
|
||||
+#include "sun50i-h6-cpu-opp.dtsi"
|
||||
+#include "sun50i-h6-gpu-opp.dtsi"
|
||||
+
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
|
@ -0,0 +1,75 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mingjia Zhang <mingjia.zhang@mediatek.com>
|
||||
Date: Sat, 29 Jul 2023 11:41:10 +0800
|
||||
Subject: [PATCH] media: mediatek: vcodec: Add capture format to support 10bit
|
||||
tile mode
|
||||
|
||||
Define one uncompressed capture format V4L2_PIX_FMT_MT2110T in order to
|
||||
support 10bit for AV1/VP9/HEVC in mt8195.
|
||||
|
||||
Signed-off-by: Mingjia Zhang <mingjia.zhang@mediatek.com>
|
||||
Co-developed-by: Yunfei Dong <yunfei.dong@mediatek.com>
|
||||
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
|
||||
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
|
||||
---
|
||||
Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 7 +++++++
|
||||
drivers/media/v4l2-core/v4l2-common.c | 2 ++
|
||||
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
|
||||
include/uapi/linux/videodev2.h | 1 +
|
||||
4 files changed, 11 insertions(+)
|
||||
|
||||
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
|
||||
index 58f6ae25b2e7..0bc69639baaa 100644
|
||||
--- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
|
||||
+++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
|
||||
@@ -275,6 +275,13 @@ please make a proposal on the linux-media mailing list.
|
||||
|
||||
Decoder's implementation can be found here,
|
||||
`aspeed_codec <https://github.com/AspeedTech-BMC/aspeed_codec/>`__
|
||||
+ * .. _V4L2-PIX-FMT-MT2110T:
|
||||
+
|
||||
+ - ``V4L2_PIX_FMT_MT2110T``
|
||||
+ - 'MT2110T'
|
||||
+ - This format is two-planar 10-Bit tile mode and having similitude with
|
||||
+ ``V4L2_PIX_FMT_MM21`` in term of alignment and tiling. Used for VP9, AV1
|
||||
+ and HEVC.
|
||||
.. raw:: latex
|
||||
|
||||
\normalsize
|
||||
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
|
||||
index bee1535b04d3..869fc09a210b 100644
|
||||
--- a/drivers/media/v4l2-core/v4l2-common.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-common.c
|
||||
@@ -262,6 +262,8 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
|
||||
{ .format = V4L2_PIX_FMT_VYUY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
|
||||
{ .format = V4L2_PIX_FMT_Y212, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
|
||||
{ .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
|
||||
+ { .format = V4L2_PIX_FMT_MT2110T, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
|
||||
+ .block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }},
|
||||
|
||||
/* YUV planar formats */
|
||||
{ .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
|
||||
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
index 01ba27f2ef87..f465c0e3d6e3 100644
|
||||
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
@@ -1508,6 +1508,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
|
||||
case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break;
|
||||
case V4L2_PIX_FMT_AJPG: descr = "Aspeed JPEG"; break;
|
||||
case V4L2_PIX_FMT_AV1_FRAME: descr = "AV1 Frame"; break;
|
||||
+ case V4L2_PIX_FMT_MT2110T: descr = "Mediatek 10bit Tile Mode"; break;
|
||||
default:
|
||||
if (fmt->description[0])
|
||||
return;
|
||||
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
|
||||
index 3af6a82d0cad..8c7d71afbdc7 100644
|
||||
--- a/include/uapi/linux/videodev2.h
|
||||
+++ b/include/uapi/linux/videodev2.h
|
||||
@@ -796,6 +796,7 @@ struct v4l2_pix_format {
|
||||
#define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
|
||||
#define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */
|
||||
#define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1') /* Mediatek 8-bit block mode, two non-contiguous planes */
|
||||
+#define V4L2_PIX_FMT_MT2110T v4l2_fourcc('M', 'T', '2', 'T') /* Mediatek 10-bit block tile mode */
|
||||
#define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */
|
||||
#define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */
|
||||
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* BTTV 8-bit dithered RGB */
|
@ -0,0 +1,74 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mingjia Zhang <mingjia.zhang@mediatek.com>
|
||||
Date: Sat, 29 Jul 2023 11:41:11 +0800
|
||||
Subject: [PATCH] media: mediatek: vcodec: Add capture format to support 10bit
|
||||
raster mode
|
||||
|
||||
Define one uncompressed capture format V4L2_PIX_FMT_MT2110R in order to
|
||||
support 10bit for H264 in mt8195.
|
||||
|
||||
Signed-off-by: Mingjia Zhang <mingjia.zhang@mediatek.com>
|
||||
Co-developed-by: Yunfei Dong <yunfei.dong@mediatek.com>
|
||||
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
|
||||
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
|
||||
---
|
||||
Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 6 ++++++
|
||||
drivers/media/v4l2-core/v4l2-common.c | 2 ++
|
||||
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
|
||||
include/uapi/linux/videodev2.h | 1 +
|
||||
4 files changed, 10 insertions(+)
|
||||
|
||||
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
|
||||
index 0bc69639baaa..296ad2025e8d 100644
|
||||
--- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
|
||||
+++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst
|
||||
@@ -282,6 +282,12 @@ please make a proposal on the linux-media mailing list.
|
||||
- This format is two-planar 10-Bit tile mode and having similitude with
|
||||
``V4L2_PIX_FMT_MM21`` in term of alignment and tiling. Used for VP9, AV1
|
||||
and HEVC.
|
||||
+ * .. _V4L2-PIX-FMT-MT2110R:
|
||||
+
|
||||
+ - ``V4L2_PIX_FMT_MT2110R``
|
||||
+ - 'MT2110R'
|
||||
+ - This format is two-planar 10-Bit raster mode and having similitude with
|
||||
+ ``V4L2_PIX_FMT_MM21`` in term of alignment and tiling. Used for AVC.
|
||||
.. raw:: latex
|
||||
|
||||
\normalsize
|
||||
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
|
||||
index 869fc09a210b..3a4b15a98e02 100644
|
||||
--- a/drivers/media/v4l2-core/v4l2-common.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-common.c
|
||||
@@ -264,6 +264,8 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
|
||||
{ .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
|
||||
{ .format = V4L2_PIX_FMT_MT2110T, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
|
||||
.block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }},
|
||||
+ { .format = V4L2_PIX_FMT_MT2110R, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
|
||||
+ .block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }},
|
||||
|
||||
/* YUV planar formats */
|
||||
{ .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
|
||||
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
index f465c0e3d6e3..f4d9d6279094 100644
|
||||
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
@@ -1509,6 +1509,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
|
||||
case V4L2_PIX_FMT_AJPG: descr = "Aspeed JPEG"; break;
|
||||
case V4L2_PIX_FMT_AV1_FRAME: descr = "AV1 Frame"; break;
|
||||
case V4L2_PIX_FMT_MT2110T: descr = "Mediatek 10bit Tile Mode"; break;
|
||||
+ case V4L2_PIX_FMT_MT2110R: descr = "Mediatek 10bit Raster Mode"; break;
|
||||
default:
|
||||
if (fmt->description[0])
|
||||
return;
|
||||
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
|
||||
index 8c7d71afbdc7..78260e5d9985 100644
|
||||
--- a/include/uapi/linux/videodev2.h
|
||||
+++ b/include/uapi/linux/videodev2.h
|
||||
@@ -797,6 +797,7 @@ struct v4l2_pix_format {
|
||||
#define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */
|
||||
#define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1') /* Mediatek 8-bit block mode, two non-contiguous planes */
|
||||
#define V4L2_PIX_FMT_MT2110T v4l2_fourcc('M', 'T', '2', 'T') /* Mediatek 10-bit block tile mode */
|
||||
+#define V4L2_PIX_FMT_MT2110R v4l2_fourcc('M', 'T', '2', 'R') /* Mediatek 10-bit block raster mode */
|
||||
#define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */
|
||||
#define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */
|
||||
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* BTTV 8-bit dithered RGB */
|
@ -1,131 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Fri, 14 Oct 2022 23:35:13 +0200
|
||||
Subject: [PATCH] Revert "drm/sun4i: dw-hdmi: Fix ddc-en GPIO consumer
|
||||
conflict"
|
||||
|
||||
This reverts commit 920169041baa0a7497ed702aa97d6a2d6285efd3.
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 54 +++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 +
|
||||
2 files changed, 52 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index 477cb6985b4d..a8d75fd7e9f4 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -93,10 +93,34 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm,
|
||||
return crtcs;
|
||||
}
|
||||
|
||||
+static int sun8i_dw_hdmi_find_connector_pdev(struct device *dev,
|
||||
+ struct platform_device **pdev_out)
|
||||
+{
|
||||
+ struct platform_device *pdev;
|
||||
+ struct device_node *remote;
|
||||
+
|
||||
+ remote = of_graph_get_remote_node(dev->of_node, 1, -1);
|
||||
+ if (!remote)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ if (!of_device_is_compatible(remote, "hdmi-connector")) {
|
||||
+ of_node_put(remote);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ pdev = of_find_device_by_node(remote);
|
||||
+ of_node_put(remote);
|
||||
+ if (!pdev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ *pdev_out = pdev;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
- struct platform_device *pdev = to_platform_device(dev);
|
||||
+ struct platform_device *pdev = to_platform_device(dev), *connector_pdev;
|
||||
struct dw_hdmi_plat_data *plat_data;
|
||||
struct drm_device *drm = data;
|
||||
struct device_node *phy_node;
|
||||
@@ -143,16 +167,30 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->regulator),
|
||||
"Couldn't get regulator\n");
|
||||
|
||||
+ ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev);
|
||||
+ if (!ret) {
|
||||
+ hdmi->ddc_en = gpiod_get_optional(&connector_pdev->dev,
|
||||
+ "ddc-en", GPIOD_OUT_HIGH);
|
||||
+ platform_device_put(connector_pdev);
|
||||
+
|
||||
+ if (IS_ERR(hdmi->ddc_en)) {
|
||||
+ dev_err(dev, "Couldn't get ddc-en gpio\n");
|
||||
+ return PTR_ERR(hdmi->ddc_en);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
ret = regulator_enable(hdmi->regulator);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator\n");
|
||||
- return ret;
|
||||
+ goto err_unref_ddc_en;
|
||||
}
|
||||
|
||||
+ gpiod_set_value(hdmi->ddc_en, 1);
|
||||
+
|
||||
ret = reset_control_deassert(hdmi->rst_ctrl);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not deassert ctrl reset control\n");
|
||||
- goto err_disable_regulator;
|
||||
+ goto err_disable_ddc_en;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->clk_tmds);
|
||||
@@ -207,8 +245,12 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
err_assert_ctrl_reset:
|
||||
reset_control_assert(hdmi->rst_ctrl);
|
||||
-err_disable_regulator:
|
||||
+err_disable_ddc_en:
|
||||
+ gpiod_set_value(hdmi->ddc_en, 0);
|
||||
regulator_disable(hdmi->regulator);
|
||||
+err_unref_ddc_en:
|
||||
+ if (hdmi->ddc_en)
|
||||
+ gpiod_put(hdmi->ddc_en);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -222,7 +264,11 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
|
||||
sun8i_hdmi_phy_deinit(hdmi->phy);
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
reset_control_assert(hdmi->rst_ctrl);
|
||||
+ gpiod_set_value(hdmi->ddc_en, 0);
|
||||
regulator_disable(hdmi->regulator);
|
||||
+
|
||||
+ if (hdmi->ddc_en)
|
||||
+ gpiod_put(hdmi->ddc_en);
|
||||
}
|
||||
|
||||
static const struct component_ops sun8i_dw_hdmi_ops = {
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
index ab80d52a70bb..f082b8ecfe2c 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <linux/clk.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
@@ -187,6 +188,7 @@ struct sun8i_dw_hdmi {
|
||||
struct regulator *regulator;
|
||||
const struct sun8i_dw_hdmi_quirks *quirks;
|
||||
struct reset_control *rst_ctrl;
|
||||
+ struct gpio_desc *ddc_en;
|
||||
};
|
||||
|
||||
extern struct platform_driver sun8i_hdmi_phy_driver;
|
@ -0,0 +1,31 @@
|
||||
From 519b9e72303cabcb87f4d5b8792069ca20b7f13b Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 23 Sep 2023 10:23:45 +0200
|
||||
Subject: [PATCH 01/23] drm/sun4i: dw-hdmi: Deinit PHY in fail path
|
||||
|
||||
Commit 9bf3797796f5 ("drm/sun4i: dw-hdmi: Make HDMI PHY into a platform
|
||||
device") removed code for PHY deinitialization in fail path.
|
||||
|
||||
Add it back.
|
||||
|
||||
Fixes: 9bf3797796f5 ("drm/sun4i: dw-hdmi: Make HDMI PHY into a platform device")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index 4727dfaa8fb9..0b647b030b15 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -203,6 +203,7 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
|
||||
cleanup_encoder:
|
||||
drm_encoder_cleanup(encoder);
|
||||
+ sun8i_hdmi_phy_deinit(hdmi->phy);
|
||||
err_disable_clk_tmds:
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
err_assert_ctrl_reset:
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,80 @@
|
||||
From 9047008f1c8cebcc33cb068d9961fcfb8ff0eea7 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 11 Dec 2021 18:17:49 +0100
|
||||
Subject: [PATCH 02/23] drm/sun4i: dw-hdmi: Remove double encoder cleanup
|
||||
|
||||
It turns out that comment is wrong - dw hdmi driver never does any
|
||||
encoder cleanup. In fact, cleanup is done automatically, in destroy
|
||||
callback of encoder. Even more, encoder memory will be freed when hdmi
|
||||
device is destroyed. However, encoder will be cleaned up after that, in
|
||||
drm_mode_config_cleanup(), which is called later. This will cause use
|
||||
after free bug.
|
||||
|
||||
Remove redundant encoder cleanup, switch memory allocation to live as
|
||||
long as drm object and while at it, check return code of encoder
|
||||
initialization.
|
||||
|
||||
Fixes: b7c7436a5ff0 ("drm/sun4i: Implement A83T HDMI driver")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 17 +++++++----------
|
||||
1 file changed, 7 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index 0b647b030b15..8f8d3bdba5ce 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
+#include <drm/drm_managed.h>
|
||||
#include <drm/drm_modeset_helper_vtables.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
@@ -107,7 +108,7 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
+ hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -180,7 +181,9 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
goto err_disable_clk_tmds;
|
||||
|
||||
drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
|
||||
- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
+ ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
+ if (ret)
|
||||
+ goto err_deinit_phy;
|
||||
|
||||
plat_data->mode_valid = hdmi->quirks->mode_valid;
|
||||
plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe;
|
||||
@@ -189,20 +192,14 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
-
|
||||
- /*
|
||||
- * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
|
||||
- * which would have called the encoder cleanup. Do it manually.
|
||||
- */
|
||||
if (IS_ERR(hdmi->hdmi)) {
|
||||
ret = PTR_ERR(hdmi->hdmi);
|
||||
- goto cleanup_encoder;
|
||||
+ goto err_deinit_phy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
-cleanup_encoder:
|
||||
- drm_encoder_cleanup(encoder);
|
||||
+err_deinit_phy:
|
||||
sun8i_hdmi_phy_deinit(hdmi->phy);
|
||||
err_disable_clk_tmds:
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,213 @@
|
||||
From 8d284097c6b9e7513e2946e17567aa490e19b779 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 23 Sep 2023 12:55:32 +0200
|
||||
Subject: [PATCH 03/23] drm/sun4i: dw-hdmi: Switch to bridge functions
|
||||
|
||||
Since ddc-en property handling was moved from sun8i dw-hdmi driver to
|
||||
display connector driver, probe order of drivers determines if EDID is
|
||||
properly read at boot time or not.
|
||||
|
||||
In order to fix this, let's switch to bridge functions which allows us
|
||||
to build proper chain and defer execution until all drivers are probed.
|
||||
|
||||
Fixes: 920169041baa ("drm/sun4i: dw-hdmi: Fix ddc-en GPIO consumer conflict")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 114 +++++++++++++++++++++++++-
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 5 ++
|
||||
2 files changed, 117 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index 8f8d3bdba5ce..93831cdf1917 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -8,14 +8,82 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.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_simple_kms_helper.h>
|
||||
|
||||
+#include <media/cec-notifier.h>
|
||||
+
|
||||
#include "sun8i_dw_hdmi.h"
|
||||
#include "sun8i_tcon_top.h"
|
||||
|
||||
+#define bridge_to_sun8i_dw_hdmi(x) \
|
||||
+ container_of(x, struct sun8i_dw_hdmi, enc_bridge)
|
||||
+
|
||||
+static int sun8i_hdmi_enc_attach(struct drm_bridge *bridge,
|
||||
+ enum drm_bridge_attach_flags flags)
|
||||
+{
|
||||
+ struct sun8i_dw_hdmi *hdmi = bridge_to_sun8i_dw_hdmi(bridge);
|
||||
+
|
||||
+ return drm_bridge_attach(&hdmi->encoder, hdmi->hdmi_bridge,
|
||||
+ &hdmi->enc_bridge, flags);
|
||||
+}
|
||||
+
|
||||
+static void sun8i_hdmi_enc_detach(struct drm_bridge *bridge)
|
||||
+{
|
||||
+ struct sun8i_dw_hdmi *hdmi = bridge_to_sun8i_dw_hdmi(bridge);
|
||||
+
|
||||
+ cec_notifier_conn_unregister(hdmi->cec_notifier);
|
||||
+ hdmi->cec_notifier = NULL;
|
||||
+}
|
||||
+
|
||||
+static void sun8i_hdmi_enc_hpd_notify(struct drm_bridge *bridge,
|
||||
+ enum drm_connector_status status)
|
||||
+{
|
||||
+ struct sun8i_dw_hdmi *hdmi = bridge_to_sun8i_dw_hdmi(bridge);
|
||||
+ struct edid *edid;
|
||||
+
|
||||
+ if (!hdmi->cec_notifier)
|
||||
+ return;
|
||||
+
|
||||
+ if (status == connector_status_connected) {
|
||||
+ edid = drm_bridge_get_edid(hdmi->hdmi_bridge, hdmi->connector);
|
||||
+ if (edid)
|
||||
+ cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier,
|
||||
+ edid);
|
||||
+ } else {
|
||||
+ cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int sun8i_hdmi_enc_atomic_check(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct drm_connector_state *old_conn_state =
|
||||
+ drm_atomic_get_old_connector_state(conn_state->state,
|
||||
+ conn_state->connector);
|
||||
+
|
||||
+ if (!drm_connector_atomic_hdr_metadata_equal(old_conn_state, conn_state))
|
||||
+ crtc_state->mode_changed = true;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct drm_bridge_funcs sun8i_hdmi_enc_bridge_funcs = {
|
||||
+ .attach = sun8i_hdmi_enc_attach,
|
||||
+ .detach = sun8i_hdmi_enc_detach,
|
||||
+ .hpd_notify = sun8i_hdmi_enc_hpd_notify,
|
||||
+ .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_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)
|
||||
@@ -99,6 +167,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dw_hdmi_plat_data *plat_data;
|
||||
+ struct cec_connector_info conn_info;
|
||||
+ struct drm_connector *connector;
|
||||
struct drm_device *drm = data;
|
||||
struct device_node *phy_node;
|
||||
struct drm_encoder *encoder;
|
||||
@@ -187,18 +257,57 @@ 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->output_port = 1;
|
||||
sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
+ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data);
|
||||
if (IS_ERR(hdmi->hdmi)) {
|
||||
ret = PTR_ERR(hdmi->hdmi);
|
||||
goto err_deinit_phy;
|
||||
}
|
||||
|
||||
+ hdmi->hdmi_bridge = of_drm_find_bridge(dev->of_node);
|
||||
+
|
||||
+ hdmi->enc_bridge.funcs = &sun8i_hdmi_enc_bridge_funcs;
|
||||
+ hdmi->enc_bridge.type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
+ hdmi->enc_bridge.interlace_allowed = true;
|
||||
+
|
||||
+ drm_bridge_add(&hdmi->enc_bridge);
|
||||
+
|
||||
+ ret = drm_bridge_attach(encoder, &hdmi->enc_bridge, NULL,
|
||||
+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
+ if (ret)
|
||||
+ goto err_remove_dw_hdmi;
|
||||
+
|
||||
+ connector = drm_bridge_connector_init(drm, encoder);
|
||||
+ if (IS_ERR(connector)) {
|
||||
+ dev_err(dev, "Unable to create HDMI bridge connector\n");
|
||||
+ ret = PTR_ERR(connector);
|
||||
+ goto err_remove_dw_hdmi;
|
||||
+ }
|
||||
+
|
||||
+ hdmi->connector = connector;
|
||||
+ drm_connector_attach_encoder(connector, encoder);
|
||||
+
|
||||
+ if (hdmi->quirks->use_drm_infoframe)
|
||||
+ drm_connector_attach_hdr_output_metadata_property(connector);
|
||||
+
|
||||
+ cec_fill_conn_info_from_drm(&conn_info, connector);
|
||||
+
|
||||
+ hdmi->cec_notifier = cec_notifier_conn_register(&pdev->dev, NULL,
|
||||
+ &conn_info);
|
||||
+ if (!hdmi->cec_notifier) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_remove_dw_hdmi;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
+err_remove_dw_hdmi:
|
||||
+ drm_bridge_remove(&hdmi->enc_bridge);
|
||||
+ dw_hdmi_remove(hdmi->hdmi);
|
||||
err_deinit_phy:
|
||||
sun8i_hdmi_phy_deinit(hdmi->phy);
|
||||
err_disable_clk_tmds:
|
||||
@@ -216,7 +325,8 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
|
||||
{
|
||||
struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
- dw_hdmi_unbind(hdmi->hdmi);
|
||||
+ drm_bridge_remove(&hdmi->enc_bridge);
|
||||
+ dw_hdmi_remove(hdmi->hdmi);
|
||||
sun8i_hdmi_phy_deinit(hdmi->phy);
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
reset_control_assert(hdmi->rst_ctrl);
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
index ab80d52a70bb..18ffc1b4841f 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
@@ -7,6 +7,7 @@
|
||||
#define _SUN8I_DW_HDMI_H_
|
||||
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
+#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -178,9 +179,13 @@ struct sun8i_dw_hdmi_quirks {
|
||||
};
|
||||
|
||||
struct sun8i_dw_hdmi {
|
||||
+ struct cec_notifier *cec_notifier;
|
||||
struct clk *clk_tmds;
|
||||
+ struct drm_connector *connector;
|
||||
struct device *dev;
|
||||
+ struct drm_bridge enc_bridge;
|
||||
struct dw_hdmi *hdmi;
|
||||
+ struct drm_bridge *hdmi_bridge;
|
||||
struct drm_encoder encoder;
|
||||
struct sun8i_hdmi_phy *phy;
|
||||
struct dw_hdmi_plat_data plat_data;
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,30 @@
|
||||
From 5cd81f7bbbd50529e8534986e3ea40276c4a26cc Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 23 Sep 2023 13:31:23 +0200
|
||||
Subject: [PATCH 04/23] drm/sun4i: Don't show error for deferred probes.
|
||||
|
||||
Drivers probing in display pipeline can be deferred for many reasons.
|
||||
Don't print error for such cases.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun4i_drv.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
|
||||
index 6a8dfc022d3c..b4816a1b0be3 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
|
||||
@@ -88,7 +88,8 @@ static int sun4i_drv_bind(struct device *dev)
|
||||
|
||||
ret = component_bind_all(drm->dev, drm);
|
||||
if (ret) {
|
||||
- dev_err(drm->dev, "Couldn't bind all pipelines components\n");
|
||||
+ dev_err_probe(drm->dev, ret,
|
||||
+ "Couldn't bind all pipelines components\n");
|
||||
goto cleanup_mode_config;
|
||||
}
|
||||
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,85 @@
|
||||
From 873d6afcf4f64ac7380e7f18cd3604d47bea7570 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 23 Sep 2023 17:52:08 +0200
|
||||
Subject: [PATCH 05/23] drm/sun4i: dw-hdmi: Make sun8i_hdmi_phy_get() more
|
||||
intuitive
|
||||
|
||||
Let's make sun8i_hdmi_phy_get() to behave more like other kernel
|
||||
functions and return phy pointer instead of setting field in struct.
|
||||
This also makes function more universal.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 5 +++--
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 +-
|
||||
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 10 ++++------
|
||||
3 files changed, 8 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index 93831cdf1917..50cffdbc4b5c 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -239,10 +239,11 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
goto err_disable_clk_tmds;
|
||||
}
|
||||
|
||||
- ret = sun8i_hdmi_phy_get(hdmi, phy_node);
|
||||
+ hdmi->phy = sun8i_hdmi_phy_get(phy_node);
|
||||
of_node_put(phy_node);
|
||||
- if (ret) {
|
||||
+ if (IS_ERR(hdmi->phy)) {
|
||||
dev_err(dev, "Couldn't get the HDMI PHY\n");
|
||||
+ ret = PTR_ERR(hdmi->phy);
|
||||
goto err_disable_clk_tmds;
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
index 18ffc1b4841f..5383d9267a4d 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
@@ -202,7 +202,7 @@ encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder)
|
||||
return container_of(encoder, struct sun8i_dw_hdmi, encoder);
|
||||
}
|
||||
|
||||
-int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
|
||||
+struct sun8i_hdmi_phy *sun8i_hdmi_phy_get(struct device_node *node);
|
||||
|
||||
int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
|
||||
void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy);
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
index 489ea94693ff..581233d6eaf2 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
@@ -650,25 +650,23 @@ static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
-int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
|
||||
+struct sun8i_hdmi_phy *sun8i_hdmi_phy_get(struct device_node *node)
|
||||
{
|
||||
struct platform_device *pdev = of_find_device_by_node(node);
|
||||
struct sun8i_hdmi_phy *phy;
|
||||
|
||||
if (!pdev)
|
||||
- return -EPROBE_DEFER;
|
||||
+ return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
phy = platform_get_drvdata(pdev);
|
||||
if (!phy) {
|
||||
put_device(&pdev->dev);
|
||||
- return -EPROBE_DEFER;
|
||||
+ return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
- hdmi->phy = phy;
|
||||
-
|
||||
put_device(&pdev->dev);
|
||||
|
||||
- return 0;
|
||||
+ return phy;
|
||||
}
|
||||
|
||||
static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,97 @@
|
||||
From c3f41c49cd55dbb6fa23472e35673875a09e2cb7 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 23 Sep 2023 18:07:07 +0200
|
||||
Subject: [PATCH 06/23] drm/sun4i: dw-hdmi: check for phy device first
|
||||
|
||||
Let's check for phy device first. Since it uses much of the same clocks
|
||||
and resets it also lowers amount of possible deferred probes.
|
||||
|
||||
While at it, don't report error for deferred phy probe.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 35 +++++++++++++--------------
|
||||
1 file changed, 17 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index 50cffdbc4b5c..22e084989ee6 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -173,11 +173,24 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
struct device_node *phy_node;
|
||||
struct drm_encoder *encoder;
|
||||
struct sun8i_dw_hdmi *hdmi;
|
||||
+ struct sun8i_hdmi_phy *phy;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
+ phy_node = of_parse_phandle(dev->of_node, "phys", 0);
|
||||
+ if (!phy_node) {
|
||||
+ dev_err(dev, "Can't find PHY phandle\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ phy = sun8i_hdmi_phy_get(phy_node);
|
||||
+ of_node_put(phy_node);
|
||||
+ if (IS_ERR(phy))
|
||||
+ return dev_err_probe(dev, PTR_ERR(phy),
|
||||
+ "Couldn't get the HDMI PHY\n");
|
||||
+
|
||||
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
@@ -185,6 +198,7 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
plat_data = &hdmi->plat_data;
|
||||
hdmi->dev = &pdev->dev;
|
||||
encoder = &hdmi->encoder;
|
||||
+ hdmi->phy = phy;
|
||||
|
||||
hdmi->quirks = of_device_get_match_data(dev);
|
||||
|
||||
@@ -232,22 +246,7 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
goto err_assert_ctrl_reset;
|
||||
}
|
||||
|
||||
- phy_node = of_parse_phandle(dev->of_node, "phys", 0);
|
||||
- if (!phy_node) {
|
||||
- dev_err(dev, "Can't found PHY phandle\n");
|
||||
- ret = -EINVAL;
|
||||
- goto err_disable_clk_tmds;
|
||||
- }
|
||||
-
|
||||
- hdmi->phy = sun8i_hdmi_phy_get(phy_node);
|
||||
- of_node_put(phy_node);
|
||||
- if (IS_ERR(hdmi->phy)) {
|
||||
- dev_err(dev, "Couldn't get the HDMI PHY\n");
|
||||
- ret = PTR_ERR(hdmi->phy);
|
||||
- goto err_disable_clk_tmds;
|
||||
- }
|
||||
-
|
||||
- ret = sun8i_hdmi_phy_init(hdmi->phy);
|
||||
+ ret = sun8i_hdmi_phy_init(phy);
|
||||
if (ret)
|
||||
goto err_disable_clk_tmds;
|
||||
|
||||
@@ -259,7 +258,7 @@ 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->output_port = 1;
|
||||
- sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
|
||||
+ sun8i_hdmi_phy_set_ops(phy, plat_data);
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
@@ -310,7 +309,7 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
drm_bridge_remove(&hdmi->enc_bridge);
|
||||
dw_hdmi_remove(hdmi->hdmi);
|
||||
err_deinit_phy:
|
||||
- sun8i_hdmi_phy_deinit(hdmi->phy);
|
||||
+ sun8i_hdmi_phy_deinit(phy);
|
||||
err_disable_clk_tmds:
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
err_assert_ctrl_reset:
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,176 @@
|
||||
From 846aad8037db9e4503f89007c0d9a8e79d7fc816 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Tue, 18 Feb 2020 22:07:37 +0100
|
||||
Subject: [PATCH 07/23] drm/sun4i: de2/de3: Change CSC argument
|
||||
|
||||
Currently, CSC module takes care only for converting YUV to RGB.
|
||||
However, DE3 is more suited to work in YUV color space. Change CSC mode
|
||||
argument to format type to be more neutral. New argument only tells
|
||||
layer format type and doesn't imply output type.
|
||||
|
||||
This commit doesn't make any functional change.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_csc.c | 22 +++++++++++-----------
|
||||
drivers/gpu/drm/sun4i/sun8i_csc.h | 10 +++++-----
|
||||
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 16 ++++++++--------
|
||||
3 files changed, 24 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
index 58480d8e4f70..6ebd1c3aa3ab 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
@@ -108,7 +108,7 @@ static const u32 yuv2rgb_de3[2][3][12] = {
|
||||
};
|
||||
|
||||
static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
|
||||
- enum sun8i_csc_mode mode,
|
||||
+ enum format_type fmt_type,
|
||||
enum drm_color_encoding encoding,
|
||||
enum drm_color_range range)
|
||||
{
|
||||
@@ -118,12 +118,12 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
|
||||
|
||||
table = yuv2rgb[range][encoding];
|
||||
|
||||
- switch (mode) {
|
||||
- case SUN8I_CSC_MODE_YUV2RGB:
|
||||
+ switch (fmt_type) {
|
||||
+ case FORMAT_TYPE_YUV:
|
||||
base_reg = SUN8I_CSC_COEFF(base, 0);
|
||||
regmap_bulk_write(map, base_reg, table, 12);
|
||||
break;
|
||||
- case SUN8I_CSC_MODE_YVU2RGB:
|
||||
+ case FORMAT_TYPE_YVU:
|
||||
for (i = 0; i < 12; i++) {
|
||||
if ((i & 3) == 1)
|
||||
base_reg = SUN8I_CSC_COEFF(base, i + 1);
|
||||
@@ -141,7 +141,7 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
|
||||
}
|
||||
|
||||
static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
|
||||
- enum sun8i_csc_mode mode,
|
||||
+ enum format_type fmt_type,
|
||||
enum drm_color_encoding encoding,
|
||||
enum drm_color_range range)
|
||||
{
|
||||
@@ -151,12 +151,12 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
|
||||
|
||||
table = yuv2rgb_de3[range][encoding];
|
||||
|
||||
- switch (mode) {
|
||||
- case SUN8I_CSC_MODE_YUV2RGB:
|
||||
+ switch (fmt_type) {
|
||||
+ case FORMAT_TYPE_YUV:
|
||||
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
|
||||
regmap_bulk_write(map, addr, table, 12);
|
||||
break;
|
||||
- case SUN8I_CSC_MODE_YVU2RGB:
|
||||
+ case FORMAT_TYPE_YVU:
|
||||
for (i = 0; i < 12; i++) {
|
||||
if ((i & 3) == 1)
|
||||
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
|
||||
@@ -206,7 +206,7 @@ static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
|
||||
}
|
||||
|
||||
void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
|
||||
- enum sun8i_csc_mode mode,
|
||||
+ enum format_type fmt_type,
|
||||
enum drm_color_encoding encoding,
|
||||
enum drm_color_range range)
|
||||
{
|
||||
@@ -214,14 +214,14 @@ void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
|
||||
|
||||
if (mixer->cfg->is_de3) {
|
||||
sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
|
||||
- mode, encoding, range);
|
||||
+ fmt_type, encoding, range);
|
||||
return;
|
||||
}
|
||||
|
||||
base = ccsc_base[mixer->cfg->ccsc][layer];
|
||||
|
||||
sun8i_csc_set_coefficients(mixer->engine.regs, base,
|
||||
- mode, encoding, range);
|
||||
+ fmt_type, encoding, range);
|
||||
}
|
||||
|
||||
void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
|
||||
index 828b86fd0cab..7322770f39f0 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
|
||||
@@ -22,14 +22,14 @@ struct sun8i_mixer;
|
||||
|
||||
#define SUN8I_CSC_CTRL_EN BIT(0)
|
||||
|
||||
-enum sun8i_csc_mode {
|
||||
- SUN8I_CSC_MODE_OFF,
|
||||
- SUN8I_CSC_MODE_YUV2RGB,
|
||||
- SUN8I_CSC_MODE_YVU2RGB,
|
||||
+enum format_type {
|
||||
+ FORMAT_TYPE_RGB,
|
||||
+ FORMAT_TYPE_YUV,
|
||||
+ FORMAT_TYPE_YVU,
|
||||
};
|
||||
|
||||
void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
|
||||
- enum sun8i_csc_mode mode,
|
||||
+ enum format_type fmt_type,
|
||||
enum drm_color_encoding encoding,
|
||||
enum drm_color_range range);
|
||||
void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable);
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
index f9c0a56d3a14..76e2d3ec0a78 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
@@ -242,19 +242,19 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static u32 sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
|
||||
+static u32 sun8i_vi_layer_get_format_type(const struct drm_format_info *format)
|
||||
{
|
||||
if (!format->is_yuv)
|
||||
- return SUN8I_CSC_MODE_OFF;
|
||||
+ return FORMAT_TYPE_RGB;
|
||||
|
||||
switch (format->format) {
|
||||
case DRM_FORMAT_YVU411:
|
||||
case DRM_FORMAT_YVU420:
|
||||
case DRM_FORMAT_YVU422:
|
||||
case DRM_FORMAT_YVU444:
|
||||
- return SUN8I_CSC_MODE_YVU2RGB;
|
||||
+ return FORMAT_TYPE_YVU;
|
||||
default:
|
||||
- return SUN8I_CSC_MODE_YUV2RGB;
|
||||
+ return FORMAT_TYPE_YUV;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
|
||||
int overlay, struct drm_plane *plane)
|
||||
{
|
||||
struct drm_plane_state *state = plane->state;
|
||||
- u32 val, ch_base, csc_mode, hw_fmt;
|
||||
+ u32 val, ch_base, fmt_type, hw_fmt;
|
||||
const struct drm_format_info *fmt;
|
||||
int ret;
|
||||
|
||||
@@ -280,9 +280,9 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
|
||||
SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
|
||||
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
|
||||
|
||||
- csc_mode = sun8i_vi_layer_get_csc_mode(fmt);
|
||||
- if (csc_mode != SUN8I_CSC_MODE_OFF) {
|
||||
- sun8i_csc_set_ccsc_coefficients(mixer, channel, csc_mode,
|
||||
+ fmt_type = sun8i_vi_layer_get_format_type(fmt);
|
||||
+ if (fmt_type != FORMAT_TYPE_RGB) {
|
||||
+ sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_type,
|
||||
state->color_encoding,
|
||||
state->color_range);
|
||||
sun8i_csc_enable_ccsc(mixer, channel, true);
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,220 @@
|
||||
From 9a4784752427c56839353f09446c5344a3b84641 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Tue, 18 Feb 2020 23:19:48 +0100
|
||||
Subject: [PATCH 08/23] drm/sun4i: de2/de3: Merge CSC functions into one
|
||||
|
||||
Merging both function into one lets this one decide on it's own if CSC
|
||||
should be enabled or not. Currently heuristics for that is pretty simple
|
||||
- enable it for YUV formats and disable for RGB. However, DE3 can have
|
||||
whole pipeline in RGB or YUV format. YUV pipeline will be supported in
|
||||
later commits.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_csc.c | 89 ++++++++++----------------
|
||||
drivers/gpu/drm/sun4i/sun8i_csc.h | 9 ++-
|
||||
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 11 +---
|
||||
3 files changed, 40 insertions(+), 69 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
index 6ebd1c3aa3ab..0dcbc0866ae8 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
@@ -107,23 +107,28 @@ static const u32 yuv2rgb_de3[2][3][12] = {
|
||||
},
|
||||
};
|
||||
|
||||
-static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
|
||||
- enum format_type fmt_type,
|
||||
- enum drm_color_encoding encoding,
|
||||
- enum drm_color_range range)
|
||||
+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;
|
||||
const u32 *table;
|
||||
- u32 base_reg;
|
||||
int i;
|
||||
|
||||
table = yuv2rgb[range][encoding];
|
||||
|
||||
switch (fmt_type) {
|
||||
+ case FORMAT_TYPE_RGB:
|
||||
+ val = 0;
|
||||
+ break;
|
||||
case FORMAT_TYPE_YUV:
|
||||
+ val = SUN8I_CSC_CTRL_EN;
|
||||
base_reg = SUN8I_CSC_COEFF(base, 0);
|
||||
regmap_bulk_write(map, base_reg, table, 12);
|
||||
break;
|
||||
case FORMAT_TYPE_YVU:
|
||||
+ val = SUN8I_CSC_CTRL_EN;
|
||||
for (i = 0; i < 12; i++) {
|
||||
if ((i & 3) == 1)
|
||||
base_reg = SUN8I_CSC_COEFF(base, i + 1);
|
||||
@@ -135,28 +140,37 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
+ val = 0;
|
||||
DRM_WARN("Wrong CSC mode specified.\n");
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ regmap_write(map, SUN8I_CSC_CTRL(base), val);
|
||||
}
|
||||
|
||||
-static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
|
||||
- enum format_type fmt_type,
|
||||
- enum drm_color_encoding encoding,
|
||||
- enum drm_color_range range)
|
||||
+static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
|
||||
+ enum format_type fmt_type,
|
||||
+ enum drm_color_encoding encoding,
|
||||
+ enum drm_color_range range)
|
||||
{
|
||||
+ u32 addr, val, mask;
|
||||
const u32 *table;
|
||||
- u32 addr;
|
||||
int i;
|
||||
|
||||
+ mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
|
||||
table = yuv2rgb_de3[range][encoding];
|
||||
|
||||
switch (fmt_type) {
|
||||
+ case FORMAT_TYPE_RGB:
|
||||
+ val = 0;
|
||||
+ break;
|
||||
case FORMAT_TYPE_YUV:
|
||||
+ 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:
|
||||
+ val = mask;
|
||||
for (i = 0; i < 12; i++) {
|
||||
if ((i & 3) == 1)
|
||||
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
|
||||
@@ -173,67 +187,30 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
+ val = 0;
|
||||
DRM_WARN("Wrong CSC mode specified.\n");
|
||||
return;
|
||||
}
|
||||
-}
|
||||
-
|
||||
-static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
|
||||
-{
|
||||
- u32 val;
|
||||
-
|
||||
- if (enable)
|
||||
- val = SUN8I_CSC_CTRL_EN;
|
||||
- else
|
||||
- val = 0;
|
||||
-
|
||||
- regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
|
||||
-}
|
||||
-
|
||||
-static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
|
||||
-{
|
||||
- u32 val, mask;
|
||||
-
|
||||
- mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
|
||||
-
|
||||
- if (enable)
|
||||
- val = mask;
|
||||
- else
|
||||
- val = 0;
|
||||
|
||||
regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
|
||||
mask, val);
|
||||
}
|
||||
|
||||
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
|
||||
- enum format_type fmt_type,
|
||||
- enum drm_color_encoding encoding,
|
||||
- enum drm_color_range range)
|
||||
+void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
|
||||
+ enum format_type fmt_type,
|
||||
+ enum drm_color_encoding encoding,
|
||||
+ enum drm_color_range range)
|
||||
{
|
||||
u32 base;
|
||||
|
||||
if (mixer->cfg->is_de3) {
|
||||
- sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
|
||||
- fmt_type, encoding, range);
|
||||
+ sun8i_de3_ccsc_setup(mixer->engine.regs, layer,
|
||||
+ fmt_type, encoding, range);
|
||||
return;
|
||||
}
|
||||
|
||||
base = ccsc_base[mixer->cfg->ccsc][layer];
|
||||
|
||||
- sun8i_csc_set_coefficients(mixer->engine.regs, base,
|
||||
- fmt_type, encoding, range);
|
||||
-}
|
||||
-
|
||||
-void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
|
||||
-{
|
||||
- u32 base;
|
||||
-
|
||||
- if (mixer->cfg->is_de3) {
|
||||
- sun8i_de3_ccsc_enable(mixer->engine.regs, layer, enable);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- base = ccsc_base[mixer->cfg->ccsc][layer];
|
||||
-
|
||||
- sun8i_csc_enable(mixer->engine.regs, base, enable);
|
||||
+ sun8i_csc_setup(mixer->engine.regs, base,
|
||||
+ fmt_type, encoding, range);
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
|
||||
index 7322770f39f0..b7546e06e315 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
|
||||
@@ -28,10 +28,9 @@ enum format_type {
|
||||
FORMAT_TYPE_YVU,
|
||||
};
|
||||
|
||||
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
|
||||
- enum format_type fmt_type,
|
||||
- enum drm_color_encoding encoding,
|
||||
- enum drm_color_range range);
|
||||
-void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable);
|
||||
+void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
|
||||
+ enum format_type fmt_type,
|
||||
+ enum drm_color_encoding encoding,
|
||||
+ enum drm_color_range range);
|
||||
|
||||
#endif
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
index 76e2d3ec0a78..6ee3790a2a81 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
@@ -281,14 +281,9 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
|
||||
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
|
||||
|
||||
fmt_type = sun8i_vi_layer_get_format_type(fmt);
|
||||
- if (fmt_type != FORMAT_TYPE_RGB) {
|
||||
- sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_type,
|
||||
- state->color_encoding,
|
||||
- state->color_range);
|
||||
- sun8i_csc_enable_ccsc(mixer, channel, true);
|
||||
- } else {
|
||||
- sun8i_csc_enable_ccsc(mixer, channel, false);
|
||||
- }
|
||||
+ sun8i_csc_set_ccsc(mixer, channel, fmt_type,
|
||||
+ state->color_encoding,
|
||||
+ state->color_range);
|
||||
|
||||
if (!fmt->is_yuv)
|
||||
val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,63 @@
|
||||
From f2a3b64aec5e23c89f5ae5a5121a4226b8ad2ee9 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Wed, 19 Feb 2020 20:59:27 +0100
|
||||
Subject: [PATCH 09/23] drm/sun4i: de2/de3: call csc setup also for UI layer
|
||||
|
||||
Currently, only VI layer calls CSC setup function. This comes from DE2
|
||||
limitation, which doesn't have CSC unit for UI layers. However, DE3 has
|
||||
separate CSC units for each layer. This allows display pipeline to make
|
||||
output signal in different color spaces. To support both use cases, add
|
||||
a call to CSC setup function also in UI layer code. For DE2, this will
|
||||
be a no-op, but it will allow DE3 to output signal in multiple formats.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_csc.c | 8 +++++---
|
||||
drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 6 ++++++
|
||||
2 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
index 0dcbc0866ae8..68d955c63b05 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
|
||||
@@ -209,8 +209,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
|
||||
return;
|
||||
}
|
||||
|
||||
- base = ccsc_base[mixer->cfg->ccsc][layer];
|
||||
+ if (layer < mixer->cfg->vi_num) {
|
||||
+ base = ccsc_base[mixer->cfg->ccsc][layer];
|
||||
|
||||
- sun8i_csc_setup(mixer->engine.regs, base,
|
||||
- fmt_type, encoding, range);
|
||||
+ sun8i_csc_setup(mixer->engine.regs, base,
|
||||
+ fmt_type, encoding, range);
|
||||
+ }
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
index ca75ca0835a6..884abe3cf773 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <drm/drm_gem_dma_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
+#include "sun8i_csc.h"
|
||||
#include "sun8i_mixer.h"
|
||||
#include "sun8i_ui_layer.h"
|
||||
#include "sun8i_ui_scaler.h"
|
||||
@@ -184,6 +185,11 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
|
||||
SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
|
||||
SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
|
||||
|
||||
+ /* Note: encoding and range arguments are ignored for RGB */
|
||||
+ sun8i_csc_set_ccsc(mixer, channel, FORMAT_TYPE_RGB,
|
||||
+ DRM_COLOR_YCBCR_BT601,
|
||||
+ DRM_COLOR_YCBCR_FULL_RANGE);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,80 @@
|
||||
From c792bfdebef49c299a2043f7aecf4b44e376c332 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Mon, 20 Jul 2020 18:00:44 +0000
|
||||
Subject: [PATCH 10/23] drm/bridge: dw-hdmi: add mtmdsclock parameter to phy
|
||||
configure ops
|
||||
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 10 ++++++----
|
||||
drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c | 3 ++-
|
||||
include/drm/bridge/dw_hdmi.h | 3 ++-
|
||||
3 files changed, 10 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 9721bdc2b7a3..c00fb616b587 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -124,7 +124,8 @@ struct dw_hdmi_phy_data {
|
||||
bool has_svsret;
|
||||
int (*configure)(struct dw_hdmi *hdmi,
|
||||
const struct dw_hdmi_plat_data *pdata,
|
||||
- unsigned long mpixelclock);
|
||||
+ unsigned long mpixelclock,
|
||||
+ unsigned long mtmdsclock);
|
||||
};
|
||||
|
||||
struct dw_hdmi {
|
||||
@@ -1571,7 +1572,8 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
|
||||
*/
|
||||
static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
||||
const struct dw_hdmi_plat_data *pdata,
|
||||
- unsigned long mpixelclock)
|
||||
+ unsigned long mpixelclock,
|
||||
+ unsigned long mtmdsclock)
|
||||
{
|
||||
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
|
||||
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
|
||||
@@ -1648,9 +1650,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi,
|
||||
|
||||
/* Write to the PHY as configured by the platform */
|
||||
if (pdata->configure_phy)
|
||||
- ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock);
|
||||
+ ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock, mtmdsclock);
|
||||
else
|
||||
- ret = phy->configure(hdmi, pdata, mpixelclock);
|
||||
+ ret = phy->configure(hdmi, pdata, mpixelclock, mtmdsclock);
|
||||
if (ret) {
|
||||
dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n",
|
||||
mpixelclock);
|
||||
diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c
|
||||
index 119d69d20b23..3d0e7f94ed77 100644
|
||||
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c
|
||||
@@ -53,7 +53,8 @@ rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data,
|
||||
}
|
||||
|
||||
static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data,
|
||||
- unsigned long mpixelclock)
|
||||
+ unsigned long mpixelclock,
|
||||
+ unsigned long mtmdsclock)
|
||||
{
|
||||
const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params;
|
||||
|
||||
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
|
||||
index 6a46baa0737c..4c0f850ce3c7 100644
|
||||
--- a/include/drm/bridge/dw_hdmi.h
|
||||
+++ b/include/drm/bridge/dw_hdmi.h
|
||||
@@ -159,7 +159,8 @@ struct dw_hdmi_plat_data {
|
||||
const struct dw_hdmi_curr_ctrl *cur_ctr;
|
||||
const struct dw_hdmi_phy_config *phy_config;
|
||||
int (*configure_phy)(struct dw_hdmi *hdmi, void *data,
|
||||
- unsigned long mpixelclock);
|
||||
+ unsigned long mpixelclock,
|
||||
+ unsigned long mtmdsclock);
|
||||
|
||||
unsigned int disable_cec : 1;
|
||||
};
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,63 @@
|
||||
From 760dd4bfec9f57bb1260f7b3219054a2ad28ceb3 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Mon, 20 Jul 2020 21:34:48 +0000
|
||||
Subject: [PATCH 11/23] drm/bridge: dw-hdmi: support configuring phy for deep
|
||||
color
|
||||
|
||||
Q: Should we rename dw_hdmi_curr_ctrl and dw_hdmi_phy_config mpixelclock to mtmdsclock ?
|
||||
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 ++++++++++++-----
|
||||
1 file changed, 12 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index c00fb616b587..da2641a65e75 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -1578,6 +1578,7 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
||||
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
|
||||
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
|
||||
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
|
||||
+ int depth;
|
||||
|
||||
/* TOFIX Will need 420 specific PHY configuration tables */
|
||||
|
||||
@@ -1587,11 +1588,11 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
||||
break;
|
||||
|
||||
for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
|
||||
- if (mpixelclock <= curr_ctrl->mpixelclock)
|
||||
+ if (mtmdsclock <= curr_ctrl->mpixelclock)
|
||||
break;
|
||||
|
||||
for (; phy_config->mpixelclock != ~0UL; phy_config++)
|
||||
- if (mpixelclock <= phy_config->mpixelclock)
|
||||
+ if (mtmdsclock <= phy_config->mpixelclock)
|
||||
break;
|
||||
|
||||
if (mpll_config->mpixelclock == ~0UL ||
|
||||
@@ -1599,11 +1600,17 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
||||
phy_config->mpixelclock == ~0UL)
|
||||
return -EINVAL;
|
||||
|
||||
- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
|
||||
+ depth = hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format);
|
||||
+ if (depth > 8 && mpixelclock != mtmdsclock)
|
||||
+ depth = fls(depth - 8) - 1;
|
||||
+ else
|
||||
+ depth = 0;
|
||||
+
|
||||
+ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].cpce,
|
||||
HDMI_3D_TX_PHY_CPCE_CTRL);
|
||||
- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
|
||||
+ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].gmp,
|
||||
HDMI_3D_TX_PHY_GMPCTRL);
|
||||
- dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
|
||||
+ dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[depth],
|
||||
HDMI_3D_TX_PHY_CURRCTRL);
|
||||
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,211 @@
|
||||
From e9a6924289b7ba7ca604272cbe52756f385d26df Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Fri, 20 Dec 2019 08:12:43 +0000
|
||||
Subject: [PATCH 12/23] WIP: drm/bridge: dw-hdmi: limit mode and bus format to
|
||||
max_tmds_clock
|
||||
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 113 ++++++++++++++--------
|
||||
1 file changed, 73 insertions(+), 40 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index da2641a65e75..9c8c17827956 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -1989,6 +1989,21 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi,
|
||||
HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN);
|
||||
}
|
||||
|
||||
+static unsigned int
|
||||
+hdmi_get_tmdsclock(unsigned int bus_format, unsigned int pixelclock)
|
||||
+{
|
||||
+ int color_depth = hdmi_bus_fmt_color_depth(bus_format);
|
||||
+ unsigned int tmdsclock = pixelclock;
|
||||
+
|
||||
+ if (!hdmi_bus_fmt_is_yuv422(bus_format) && color_depth > 8)
|
||||
+ tmdsclock = (u64)pixelclock * color_depth / 8;
|
||||
+
|
||||
+ if (hdmi_bus_fmt_is_yuv420(bus_format))
|
||||
+ tmdsclock /= 2;
|
||||
+
|
||||
+ return tmdsclock;
|
||||
+}
|
||||
+
|
||||
static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
||||
const struct drm_display_info *display,
|
||||
const struct drm_display_mode *mode)
|
||||
@@ -2000,29 +2015,11 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
||||
unsigned int vdisplay, hdisplay;
|
||||
|
||||
vmode->mpixelclock = mode->clock * 1000;
|
||||
+ vmode->mtmdsclock =
|
||||
+ hdmi_get_tmdsclock(hdmi->hdmi_data.enc_out_bus_format,
|
||||
+ vmode->mpixelclock);
|
||||
|
||||
dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
|
||||
-
|
||||
- vmode->mtmdsclock = vmode->mpixelclock;
|
||||
-
|
||||
- if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
|
||||
- switch (hdmi_bus_fmt_color_depth(
|
||||
- hdmi->hdmi_data.enc_out_bus_format)) {
|
||||
- case 16:
|
||||
- vmode->mtmdsclock = vmode->mpixelclock * 2;
|
||||
- break;
|
||||
- case 12:
|
||||
- vmode->mtmdsclock = vmode->mpixelclock * 3 / 2;
|
||||
- break;
|
||||
- case 10:
|
||||
- vmode->mtmdsclock = vmode->mpixelclock * 5 / 4;
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
|
||||
- vmode->mtmdsclock /= 2;
|
||||
-
|
||||
dev_dbg(hdmi->dev, "final tmdsclock = %d\n", vmode->mtmdsclock);
|
||||
|
||||
/* Set up HDMI_FC_INVIDCONF */
|
||||
@@ -2646,8 +2643,21 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi)
|
||||
* - MEDIA_BUS_FMT_RGB888_1X24,
|
||||
*/
|
||||
|
||||
-/* Can return a maximum of 11 possible output formats for a mode/connector */
|
||||
-#define MAX_OUTPUT_SEL_FORMATS 11
|
||||
+/* Can return a maximum of 15 possible output formats for a mode/connector */
|
||||
+#define MAX_OUTPUT_SEL_FORMATS 15
|
||||
+
|
||||
+static bool is_tmds_allowed(struct drm_display_info *info,
|
||||
+ struct drm_display_mode *mode,
|
||||
+ u32 bus_format)
|
||||
+{
|
||||
+ unsigned long tmdsclock = hdmi_get_tmdsclock(bus_format, mode->clock);
|
||||
+ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000;
|
||||
+
|
||||
+ if (max_tmds_clock >= tmdsclock)
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
|
||||
static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
@@ -2690,19 +2700,23 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
||||
|
||||
/* Order bus formats from 16bit to 8bit if supported */
|
||||
if (max_bpc >= 16 && info->bpc == 16 &&
|
||||
- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48))
|
||||
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY16_0_5X48))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48;
|
||||
|
||||
if (max_bpc >= 12 && info->bpc >= 12 &&
|
||||
- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36))
|
||||
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY12_0_5X36))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
|
||||
|
||||
if (max_bpc >= 10 && info->bpc >= 10 &&
|
||||
- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30))
|
||||
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY10_0_5X30))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
|
||||
|
||||
/* Default 8bit fallback */
|
||||
- output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
|
||||
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY8_0_5X24))
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
|
||||
|
||||
if (drm_mode_is_420_only(info, mode)) {
|
||||
*num_output_fmts = i;
|
||||
@@ -2715,42 +2729,52 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
||||
* if supported. In any case the default RGB888 format is added
|
||||
*/
|
||||
|
||||
- /* Default 8bit RGB fallback */
|
||||
- output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
-
|
||||
if (max_bpc >= 16 && info->bpc == 16) {
|
||||
- if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
||||
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR444) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV16_1X48))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
||||
|
||||
- output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
||||
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB161616_1X48))
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
||||
}
|
||||
|
||||
if (max_bpc >= 12 && info->bpc >= 12) {
|
||||
- if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
|
||||
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR422) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY12_1X24))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
||||
|
||||
- if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
||||
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR444) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV12_1X36))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
||||
|
||||
- output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
||||
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB121212_1X36))
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
||||
}
|
||||
|
||||
if (max_bpc >= 10 && info->bpc >= 10) {
|
||||
- if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
|
||||
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR422) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY10_1X20))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
||||
|
||||
- if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
||||
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR444) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV10_1X30))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
||||
|
||||
- output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
||||
+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB101010_1X30))
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
||||
}
|
||||
|
||||
- if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
|
||||
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR422) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY8_1X16))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
|
||||
- if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
||||
+ if ((info->color_formats & DRM_COLOR_FORMAT_YCBCR444) &&
|
||||
+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV8_1X24))
|
||||
output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
|
||||
+ /* Default 8bit RGB fallback */
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+
|
||||
*num_output_fmts = i;
|
||||
|
||||
return output_fmts;
|
||||
@@ -2930,11 +2954,20 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
|
||||
enum drm_mode_status mode_status = MODE_OK;
|
||||
+ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000;
|
||||
+ int clock = mode->clock;
|
||||
|
||||
/* We don't support double-clocked modes */
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
return MODE_BAD;
|
||||
|
||||
+ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) &&
|
||||
+ (info->color_formats & DRM_COLOR_FORMAT_YCBCR420))
|
||||
+ clock /= 2;
|
||||
+
|
||||
+ if (clock > max_tmds_clock)
|
||||
+ return MODE_CLOCK_HIGH;
|
||||
+
|
||||
if (pdata->mode_valid)
|
||||
mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info,
|
||||
mode);
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,886 @@
|
||||
From d8126b4e7ec771a5be4ab9513aed390461a70d3d 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/23] 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 | 97 +++++++++++-
|
||||
drivers/gpu/drm/sun4i/sun8i_mixer.c | 51 ++++++-
|
||||
drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 +
|
||||
drivers/gpu/drm/sun4i/sunxi_engine.h | 48 ++++++
|
||||
11 files changed, 509 insertions(+), 25 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 9c8c17827956..8b4b4d45c1c9 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..7309590feb56 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -7,6 +7,7 @@
|
||||
#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>
|
||||
@@ -17,8 +18,10 @@
|
||||
|
||||
#include <media/cec-notifier.h>
|
||||
|
||||
+#include "sun4i_crtc.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 +67,89 @@ 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;
|
||||
+ enum drm_color_encoding encoding;
|
||||
+
|
||||
+ 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:
|
||||
+ 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:
|
||||
+ 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:
|
||||
+ encoding = DRM_COLOR_YCBCR_BT2020;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (crtc->engine->format != bridge_state->output_bus_cfg.format)
|
||||
+ crtc_state->mode_changed = true;
|
||||
+
|
||||
+ sunxi_engine_set_format(engine, bridge_state->output_bus_cfg.format,
|
||||
+ encoding);
|
||||
+
|
||||
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,6 +157,7 @@ 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,
|
||||
};
|
||||
|
||||
@@ -114,6 +191,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 +339,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 +375,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..8e32d0b24ac9 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,51 @@ 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(8, 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_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 +434,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 +697,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..5e64cda5675a 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,20 @@ 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);
|
||||
+
|
||||
+ void (*set_format)(struct sunxi_engine *engine, u32 format,
|
||||
+ enum drm_color_encoding encoding);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -137,6 +153,9 @@ struct sunxi_engine {
|
||||
|
||||
int id;
|
||||
|
||||
+ u32 format;
|
||||
+ enum drm_color_encoding encoding;
|
||||
+
|
||||
/* Engine list management */
|
||||
struct list_head list;
|
||||
};
|
||||
@@ -208,4 +227,33 @@ 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;
|
||||
+}
|
||||
+
|
||||
+static inline void
|
||||
+sunxi_engine_set_format(struct sunxi_engine *engine, u32 format,
|
||||
+ enum drm_color_encoding encoding)
|
||||
+{
|
||||
+ if (engine->ops && engine->ops->set_format)
|
||||
+ return engine->ops->set_format(engine, format, encoding);
|
||||
+
|
||||
+ engine->format = format;
|
||||
+ engine->encoding = encoding;
|
||||
+}
|
||||
#endif /* _SUNXI_ENGINE_H_ */
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,65 @@
|
||||
From 6fba61d436ed9d610e1001860e2fcdf2ccf96803 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 7 Oct 2023 08:36:47 +0200
|
||||
Subject: [PATCH 14/23] media: cedrus: h265: Fix configuring bitstream size
|
||||
|
||||
bit_size field holds size of slice, not slice + header. Because of HW
|
||||
quirks, driver can't program in just slice, but also preceeding header.
|
||||
But that means that currently used bit_size is wrong (too small).
|
||||
Instead, just use size of whole buffer. There is no harm in doing this.
|
||||
|
||||
Fixes: 86caab29da78 ("media: cedrus: Add HEVC/H.265 decoding support")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 10 ++++------
|
||||
1 file changed, 4 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
|
||||
index fc9297232456..16c822637dc6 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
|
||||
@@ -427,11 +427,11 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
|
||||
unsigned int ctb_addr_x, ctb_addr_y;
|
||||
struct cedrus_buffer *cedrus_buf;
|
||||
dma_addr_t src_buf_addr;
|
||||
- dma_addr_t src_buf_end_addr;
|
||||
u32 chroma_log2_weight_denom;
|
||||
u32 num_entry_point_offsets;
|
||||
u32 output_pic_list_index;
|
||||
u32 pic_order_cnt[2];
|
||||
+ size_t slice_bytes;
|
||||
u8 padding;
|
||||
int count;
|
||||
u32 reg;
|
||||
@@ -443,6 +443,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
|
||||
pred_weight_table = &slice_params->pred_weight_table;
|
||||
num_entry_point_offsets = slice_params->num_entry_point_offsets;
|
||||
cedrus_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
|
||||
+ slice_bytes = vb2_get_plane_payload(&run->src->vb2_buf, 0);
|
||||
|
||||
/*
|
||||
* If entry points offsets are present, we should get them
|
||||
@@ -490,7 +491,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
|
||||
|
||||
cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, 0);
|
||||
|
||||
- reg = slice_params->bit_size;
|
||||
+ reg = slice_bytes * 8;
|
||||
cedrus_write(dev, VE_DEC_H265_BITS_LEN, reg);
|
||||
|
||||
/* Source beginning and end addresses. */
|
||||
@@ -504,10 +505,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
|
||||
|
||||
cedrus_write(dev, VE_DEC_H265_BITS_ADDR, reg);
|
||||
|
||||
- src_buf_end_addr = src_buf_addr +
|
||||
- DIV_ROUND_UP(slice_params->bit_size, 8);
|
||||
-
|
||||
- reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_end_addr);
|
||||
+ reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_addr + slice_bytes);
|
||||
cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg);
|
||||
|
||||
/* Coding tree block address */
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,45 @@
|
||||
From b60d442e96407bf90126e455b6466465438a5381 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 7 Oct 2023 09:43:35 +0200
|
||||
Subject: [PATCH 15/23] media: Add NV12 and P010 AFBC compressed formats
|
||||
|
||||
Cedrus supports AFBC compressed NV12 and P010 formats, which
|
||||
considerably speed up H265 decoding. Add them.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++
|
||||
include/uapi/linux/videodev2.h | 4 ++++
|
||||
2 files changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
index f4d9d6279094..1e07066fa129 100644
|
||||
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
@@ -1510,6 +1510,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
|
||||
case V4L2_PIX_FMT_AV1_FRAME: descr = "AV1 Frame"; break;
|
||||
case V4L2_PIX_FMT_MT2110T: descr = "Mediatek 10bit Tile Mode"; break;
|
||||
case V4L2_PIX_FMT_MT2110R: descr = "Mediatek 10bit Raster Mode"; break;
|
||||
+ case V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT: descr = "YUV 4:2:0 (AFBC 16x16)"; break;
|
||||
+ case V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT: descr = "10-bit YUV 4:2:0 (AFBC 16x16)"; break;
|
||||
default:
|
||||
if (fmt->description[0])
|
||||
return;
|
||||
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
|
||||
index 78260e5d9985..968cdb3d0306 100644
|
||||
--- a/include/uapi/linux/videodev2.h
|
||||
+++ b/include/uapi/linux/videodev2.h
|
||||
@@ -683,6 +683,10 @@ struct v4l2_pix_format {
|
||||
#define V4L2_PIX_FMT_NV12M_8L128 v4l2_fourcc('N', 'A', '1', '2') /* Y/CbCr 4:2:0 8x128 tiles */
|
||||
#define V4L2_PIX_FMT_NV12M_10BE_8L128 v4l2_fourcc_be('N', 'T', '1', '2') /* Y/CbCr 4:2:0 10-bit 8x128 tiles */
|
||||
|
||||
+/* AFBC YUV formats */
|
||||
+#define V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT v4l2_fourcc('A', 'S', '1', '2') /* YUV420 AFBC compressed, 16x16 macroblocks, split */
|
||||
+#define V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT v4l2_fourcc('A', 'S', '0', '1') /* YUV420 10-bit AFBC compressed, 16x16 macroblocks, split */
|
||||
+
|
||||
/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
|
||||
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */
|
||||
#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,51 @@
|
||||
From ef817a8f5bfd38d91f9250b138a90edafb7b21a0 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sat, 7 Oct 2023 09:45:25 +0200
|
||||
Subject: [PATCH 16/23] media: cedrus: add format filtering based on depth and
|
||||
src format
|
||||
|
||||
Some Cedrus variant, like that found in H6, support special output
|
||||
formats only with specific codecs, like H265.
|
||||
|
||||
Add extra filtering fields based on bit depth and source format.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/staging/media/sunxi/cedrus/cedrus_video.c | 7 +++++++
|
||||
drivers/staging/media/sunxi/cedrus/cedrus_video.h | 2 ++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
|
||||
index b00feaf4072c..75b6f2e85a5f 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
|
||||
@@ -87,6 +87,13 @@ static struct cedrus_format *cedrus_find_format(struct cedrus_ctx *ctx,
|
||||
!(fmt->directions & directions))
|
||||
continue;
|
||||
|
||||
+ if (fmt->depth && fmt->depth != ctx->bit_depth)
|
||||
+ continue;
|
||||
+
|
||||
+ if (fmt->src_format &&
|
||||
+ fmt->src_format != ctx->src_fmt.pixelformat)
|
||||
+ continue;
|
||||
+
|
||||
if (fmt->pixelformat == pixelformat)
|
||||
break;
|
||||
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.h b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
|
||||
index 8e1afc16a6a1..c8e9909ecdee 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.h
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
|
||||
@@ -20,6 +20,8 @@ struct cedrus_format {
|
||||
u32 pixelformat;
|
||||
u32 directions;
|
||||
unsigned int capabilities;
|
||||
+ unsigned int depth;
|
||||
+ u32 src_format;
|
||||
};
|
||||
|
||||
extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,169 @@
|
||||
From eaa6dd41f9c4c9a12d7f81a6ead80cc5d7146afa Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sun, 8 Oct 2023 12:44:59 +0200
|
||||
Subject: [PATCH 17/23] media: cedrus: Implement AFBC YUV420 formats for H265
|
||||
|
||||
AFBC output formats are more performant, since they are optimized for
|
||||
more efficient memory operations and transfers.
|
||||
|
||||
Add support for them.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/staging/media/sunxi/cedrus/cedrus.h | 11 ++++++
|
||||
.../staging/media/sunxi/cedrus/cedrus_h265.c | 3 +-
|
||||
.../staging/media/sunxi/cedrus/cedrus_hw.c | 16 +++++++++
|
||||
.../staging/media/sunxi/cedrus/cedrus_regs.h | 6 ++++
|
||||
.../staging/media/sunxi/cedrus/cedrus_video.c | 36 +++++++++++++++++++
|
||||
5 files changed, 71 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
|
||||
index 522c184e2afc..c7ec4dee8630 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
|
||||
@@ -268,6 +268,17 @@ cedrus_is_capable(struct cedrus_ctx *ctx, unsigned int capabilities)
|
||||
return (ctx->dev->capabilities & capabilities) == capabilities;
|
||||
}
|
||||
|
||||
+static inline bool is_afbc_format(u32 format)
|
||||
+{
|
||||
+ switch (format) {
|
||||
+ case V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT:
|
||||
+ case V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
|
||||
u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id);
|
||||
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
|
||||
index 16c822637dc6..2372fafab475 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
|
||||
@@ -120,7 +120,8 @@ static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx,
|
||||
{
|
||||
struct cedrus_dev *dev = ctx->dev;
|
||||
dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buf, 0);
|
||||
- dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buf, 1);
|
||||
+ dma_addr_t dst_chroma_addr = is_afbc_format(ctx->dst_fmt.pixelformat) ?
|
||||
+ 0 : cedrus_dst_buf_addr(ctx, buf, 1);
|
||||
dma_addr_t mv_col_buf_addr[2] = {
|
||||
cedrus_h265_frame_info_mv_col_buf_addr(buf, 0),
|
||||
cedrus_h265_frame_info_mv_col_buf_addr(buf, field_pic ? 1 : 0)
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
|
||||
index b696bf884cbd..ac0a88d47e10 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
|
||||
@@ -65,6 +65,18 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx)
|
||||
reg |= VE_MODE_PIC_WIDTH_IS_4096;
|
||||
if (ctx->src_fmt.width > 2048)
|
||||
reg |= VE_MODE_PIC_WIDTH_MORE_2048;
|
||||
+ /*
|
||||
+ * NOTE: Not sure if RGB default color feature is part of official
|
||||
+ * AFBC standard or not and if it is, which feature that is. However,
|
||||
+ * in order to render it properly with display engine, default color
|
||||
+ * has to be set to white there.
|
||||
+ */
|
||||
+ if (is_afbc_format(ctx->dst_fmt.pixelformat))
|
||||
+ reg |= VE_MODE_COMPRESS_EN |
|
||||
+ VE_MODE_MIN_VAL_WRAP_EN |
|
||||
+ VE_MODE_RGB_DEF_COLOR_EN |
|
||||
+ VE_MODE_BODYBUF_1K_ALIGNED |
|
||||
+ VE_MODE_COMPRESS_MODE_AFBC;
|
||||
|
||||
cedrus_write(ctx->dev, VE_MODE, reg);
|
||||
|
||||
@@ -85,6 +97,10 @@ void cedrus_dst_format_set(struct cedrus_dev *dev,
|
||||
u32 reg;
|
||||
|
||||
switch (fmt->pixelformat) {
|
||||
+ case V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT:
|
||||
+ case V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT:
|
||||
+ /* format is already set in cedrus_engine_enable() */
|
||||
+ break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
chroma_size = ALIGN(width, 16) * ALIGN(height, 16) / 2;
|
||||
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
|
||||
index 05e6cbc548ab..c3dcd93a29eb 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
|
||||
@@ -35,12 +35,18 @@
|
||||
|
||||
#define VE_MODE 0x00
|
||||
|
||||
+#define VE_MODE_COMPRESS_EN BIT(29)
|
||||
+#define VE_MODE_MIN_VAL_WRAP_EN BIT(27)
|
||||
+#define VE_MODE_RGB_DEF_COLOR_EN BIT(26)
|
||||
#define VE_MODE_PIC_WIDTH_IS_4096 BIT(22)
|
||||
#define VE_MODE_PIC_WIDTH_MORE_2048 BIT(21)
|
||||
#define VE_MODE_REC_WR_MODE_2MB (0x01 << 20)
|
||||
#define VE_MODE_REC_WR_MODE_1MB (0x00 << 20)
|
||||
#define VE_MODE_DDR_MODE_BW_128 (0x03 << 16)
|
||||
#define VE_MODE_DDR_MODE_BW_256 (0x02 << 16)
|
||||
+#define VE_MODE_BODYBUF_1K_ALIGNED BIT(12)
|
||||
+#define VE_MODE_COMPRESS_MODE_LOSSLESS (0x00 << 4)
|
||||
+#define VE_MODE_COMPRESS_MODE_AFBC (0x01 << 4)
|
||||
#define VE_MODE_DISABLED (0x07 << 0)
|
||||
#define VE_MODE_DEC_H265 (0x04 << 0)
|
||||
#define VE_MODE_DEC_H264 (0x01 << 0)
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
|
||||
index 75b6f2e85a5f..a61b30946204 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
|
||||
@@ -55,6 +55,22 @@ static struct cedrus_format cedrus_formats[] = {
|
||||
.directions = CEDRUS_DECODE_SRC,
|
||||
.capabilities = CEDRUS_CAPABILITY_VP8_DEC,
|
||||
},
|
||||
+ {
|
||||
+ .pixelformat = V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT,
|
||||
+ .directions = CEDRUS_DECODE_DST,
|
||||
+ .capabilities = CEDRUS_CAPABILITY_UNTILED |
|
||||
+ CEDRUS_CAPABILITY_H265_10_DEC,
|
||||
+ .depth = 10,
|
||||
+ .src_format = V4L2_PIX_FMT_HEVC_SLICE,
|
||||
+ },
|
||||
+ {
|
||||
+ .pixelformat = V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT,
|
||||
+ .directions = CEDRUS_DECODE_DST,
|
||||
+ .capabilities = CEDRUS_CAPABILITY_UNTILED |
|
||||
+ CEDRUS_CAPABILITY_H265_10_DEC,
|
||||
+ .depth = 8,
|
||||
+ .src_format = V4L2_PIX_FMT_HEVC_SLICE,
|
||||
+ },
|
||||
{
|
||||
.pixelformat = V4L2_PIX_FMT_NV12,
|
||||
.directions = CEDRUS_DECODE_DST,
|
||||
@@ -160,6 +176,26 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
|
||||
sizeimage += bytesperline * height / 2;
|
||||
|
||||
break;
|
||||
+
|
||||
+ case V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT:
|
||||
+ /* Zero bytes per line for compressed destination. */
|
||||
+ bytesperline = 0;
|
||||
+
|
||||
+ sizeimage = DIV_ROUND_UP(width, 16) *
|
||||
+ DIV_ROUND_UP(height + 4, 16) * (512 + 16) +
|
||||
+ 32 + SZ_1K;
|
||||
+
|
||||
+ break;
|
||||
+
|
||||
+ case V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT:
|
||||
+ /* Zero bytes per line for compressed destination. */
|
||||
+ bytesperline = 0;
|
||||
+
|
||||
+ sizeimage = DIV_ROUND_UP(width, 16) *
|
||||
+ DIV_ROUND_UP(height + 4, 16) * (384 + 16) +
|
||||
+ 32 + SZ_1K;
|
||||
+
|
||||
+ break;
|
||||
}
|
||||
|
||||
pix_fmt->width = width;
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,68 @@
|
||||
From 678c304daf5a489a781179b25fe72e4e856d0c6c Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sun, 8 Oct 2023 12:48:12 +0200
|
||||
Subject: [PATCH 18/23] drm/sun4i: de2: Initialize layer fields earlier
|
||||
|
||||
drm_universal_plane_init() can already call some callbacks, like
|
||||
format_mod_supported, during initialization. Because of that, fields
|
||||
should be initialized beforehand.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 7 ++++---
|
||||
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 7 ++++---
|
||||
2 files changed, 8 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
index 884abe3cf773..91781b5bbbbc 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
@@ -365,6 +365,10 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
|
||||
if (!layer)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
+ layer->mixer = mixer;
|
||||
+ layer->channel = channel;
|
||||
+ layer->overlay = 0;
|
||||
+
|
||||
if (index == 0)
|
||||
type = DRM_PLANE_TYPE_PRIMARY;
|
||||
|
||||
@@ -395,9 +399,6 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
|
||||
}
|
||||
|
||||
drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
|
||||
- layer->mixer = mixer;
|
||||
- layer->channel = channel;
|
||||
- layer->overlay = 0;
|
||||
|
||||
return layer;
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
index 6ee3790a2a81..329e8bf8cd20 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
@@ -549,6 +549,10 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
||||
if (!layer)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
+ layer->mixer = mixer;
|
||||
+ layer->channel = index;
|
||||
+ layer->overlay = 0;
|
||||
+
|
||||
if (mixer->cfg->is_de3) {
|
||||
formats = sun8i_vi_layer_de3_formats;
|
||||
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
|
||||
@@ -607,9 +611,6 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
||||
}
|
||||
|
||||
drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
|
||||
- layer->mixer = mixer;
|
||||
- layer->channel = index;
|
||||
- layer->overlay = 0;
|
||||
|
||||
return layer;
|
||||
}
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,571 @@
|
||||
From 75f9a78d91a37c0eadf952e97e93d3f51bfda1b6 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sun, 8 Oct 2023 13:01:01 +0200
|
||||
Subject: [PATCH 19/23] drm/sun4i: de3: Implement AFBC support
|
||||
|
||||
Buffers, compressed with AFBC, are generally more efficient for memory
|
||||
transfers. Add support for them.
|
||||
|
||||
Currently it's implemented only for VI layers, but vendor code and
|
||||
documentation suggest UI layers can have them too. However, I haven't
|
||||
observed any SoC with such feature.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/Makefile | 2 +-
|
||||
drivers/gpu/drm/sun4i/sun50i_afbc.c | 240 +++++++++++++++++++++++++
|
||||
drivers/gpu/drm/sun4i/sun50i_afbc.h | 87 +++++++++
|
||||
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 81 +++++++--
|
||||
4 files changed, 397 insertions(+), 13 deletions(-)
|
||||
create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
|
||||
create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
|
||||
index 3f516329f51e..78290f1660fb 100644
|
||||
--- a/drivers/gpu/drm/sun4i/Makefile
|
||||
+++ b/drivers/gpu/drm/sun4i/Makefile
|
||||
@@ -17,7 +17,7 @@ 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 \
|
||||
- sun50i_fmt.o
|
||||
+ sun50i_fmt.o sun50i_afbc.o
|
||||
|
||||
sun4i-tcon-y += sun4i_crtc.o
|
||||
sun4i-tcon-y += sun4i_tcon_dclk.o
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.c b/drivers/gpu/drm/sun4i/sun50i_afbc.c
|
||||
new file mode 100644
|
||||
index 000000000000..27a771608eef
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.c
|
||||
@@ -0,0 +1,240 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
+ */
|
||||
+
|
||||
+#include <drm/drm_blend.h>
|
||||
+#include <drm/drm_fb_dma_helper.h>
|
||||
+#include <drm/drm_framebuffer.h>
|
||||
+#include <drm/drm_gem_dma_helper.h>
|
||||
+#include <drm/drm_plane.h>
|
||||
+#include <uapi/drm/drm_fourcc.h>
|
||||
+
|
||||
+#include "sun50i_afbc.h"
|
||||
+#include "sun8i_mixer.h"
|
||||
+
|
||||
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
|
||||
+ u32 format, u64 modifier)
|
||||
+{
|
||||
+ u64 mode;
|
||||
+
|
||||
+ if (modifier == DRM_FORMAT_MOD_INVALID)
|
||||
+ return false;
|
||||
+
|
||||
+ if (modifier == DRM_FORMAT_MOD_LINEAR) {
|
||||
+ if (format == DRM_FORMAT_YUV420_8BIT ||
|
||||
+ format == DRM_FORMAT_YUV420_10BIT ||
|
||||
+ format == DRM_FORMAT_Y210)
|
||||
+ return false;
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ if (!mixer->cfg->is_de3)
|
||||
+ return false;
|
||||
+
|
||||
+ mode = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
||||
+ AFBC_FORMAT_MOD_SPARSE |
|
||||
+ AFBC_FORMAT_MOD_SPLIT;
|
||||
+
|
||||
+ switch (format) {
|
||||
+ case DRM_FORMAT_RGBA8888:
|
||||
+ case DRM_FORMAT_RGB888:
|
||||
+ case DRM_FORMAT_RGB565:
|
||||
+ case DRM_FORMAT_RGBA4444:
|
||||
+ case DRM_FORMAT_RGBA5551:
|
||||
+ case DRM_FORMAT_RGBA1010102:
|
||||
+ mode |= AFBC_FORMAT_MOD_YTR;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_YUYV:
|
||||
+ case DRM_FORMAT_Y210:
|
||||
+ case DRM_FORMAT_YUV420_8BIT:
|
||||
+ case DRM_FORMAT_YUV420_10BIT:
|
||||
+ break;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return modifier == DRM_FORMAT_MOD_ARM_AFBC(mode);
|
||||
+}
|
||||
+
|
||||
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
|
||||
+ struct drm_plane *plane)
|
||||
+{
|
||||
+ struct drm_plane_state *state = plane->state;
|
||||
+ struct drm_framebuffer *fb = state->fb;
|
||||
+ const struct drm_format_info *format = fb->format;
|
||||
+ struct drm_gem_dma_object *gem;
|
||||
+ u32 base, val, src_w, src_h;
|
||||
+ u32 def_color0, def_color1;
|
||||
+ struct regmap *regs;
|
||||
+ dma_addr_t dma_addr;
|
||||
+
|
||||
+ base = sun8i_channel_base(mixer, channel) + SUN50I_AFBC_CH_OFFSET;
|
||||
+ regs = mixer->engine.regs;
|
||||
+
|
||||
+ src_w = drm_rect_width(&state->src) >> 16;
|
||||
+ src_h = drm_rect_height(&state->src) >> 16;
|
||||
+
|
||||
+ val = SUN50I_FBD_SIZE_HEIGHT(src_h);
|
||||
+ val |= SUN50I_FBD_SIZE_WIDTH(src_w);
|
||||
+ regmap_write(regs, SUN50I_FBD_SIZE(base), val);
|
||||
+
|
||||
+ val = SUN50I_FBD_BLK_SIZE_HEIGHT(DIV_ROUND_UP(src_h, 16));
|
||||
+ val = SUN50I_FBD_BLK_SIZE_WIDTH(DIV_ROUND_UP(src_w, 16));
|
||||
+ regmap_write(regs, SUN50I_FBD_BLK_SIZE(base), val);
|
||||
+
|
||||
+ val = SUN50I_FBD_SRC_CROP_TOP(0);
|
||||
+ val |= SUN50I_FBD_SRC_CROP_LEFT(0);
|
||||
+ regmap_write(regs, SUN50I_FBD_SRC_CROP(base), val);
|
||||
+
|
||||
+ val = SUN50I_FBD_LAY_CROP_TOP(state->src.y1 >> 16);
|
||||
+ val |= SUN50I_FBD_LAY_CROP_LEFT(state->src.x1 >> 16);
|
||||
+ regmap_write(regs, SUN50I_FBD_LAY_CROP(base), val);
|
||||
+
|
||||
+ /*
|
||||
+ * Default color is always set to white, in colorspace and bitness
|
||||
+ * that coresponds to used format. If it is actually used or not
|
||||
+ * depends on AFBC buffer. At least in Cedrus it can be turned on
|
||||
+ * or off.
|
||||
+ * NOTE: G and B channels are off by 1 (up). It's unclear if this
|
||||
+ * is because HW need such value or it is due to good enough code
|
||||
+ * in vendor driver and HW clips the value anyway.
|
||||
+ */
|
||||
+ def_color0 = 0;
|
||||
+ def_color1 = 0;
|
||||
+
|
||||
+ val = 0;
|
||||
+ switch (format->format) {
|
||||
+ case DRM_FORMAT_YUYV:
|
||||
+ case DRM_FORMAT_YUV420_10BIT:
|
||||
+ val |= SUN50I_FBD_FMT_SBS1(2);
|
||||
+ val |= SUN50I_FBD_FMT_SBS0(1);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_Y210:
|
||||
+ val |= SUN50I_FBD_FMT_SBS1(3);
|
||||
+ val |= SUN50I_FBD_FMT_SBS0(2);
|
||||
+ break;
|
||||
+ default:
|
||||
+ val |= SUN50I_FBD_FMT_SBS1(1);
|
||||
+ val |= SUN50I_FBD_FMT_SBS0(1);
|
||||
+ break;
|
||||
+ }
|
||||
+ switch (format->format) {
|
||||
+ case DRM_FORMAT_RGBA8888:
|
||||
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_8888);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(255) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(256) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(256);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_RGB888:
|
||||
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGB_888);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(256) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(256);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_RGB565:
|
||||
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGB_565);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(31);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(64) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(32);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_RGBA4444:
|
||||
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_4444);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(15) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(15);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(16) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(16);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_RGBA5551:
|
||||
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_5551);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(1) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(31);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(32) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(32);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_RGBA1010102:
|
||||
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA1010102);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(3) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(1024) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(1024);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_YUV420_8BIT:
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_YUV420);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(128) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(128);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_YUYV:
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_YUV422);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(128) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(128);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_YUV420_10BIT:
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_P010);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(512) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(512);
|
||||
+ break;
|
||||
+ case DRM_FORMAT_Y210:
|
||||
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_P210);
|
||||
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
|
||||
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(512) |
|
||||
+ SUN50I_FBD_DEFAULT_COLOR1_VB(512);
|
||||
+ break;
|
||||
+ }
|
||||
+ regmap_write(regs, SUN50I_FBD_FMT(base), val);
|
||||
+
|
||||
+ /* Get the physical address of the buffer in memory */
|
||||
+ gem = drm_fb_dma_get_gem_obj(fb, 0);
|
||||
+
|
||||
+ DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr);
|
||||
+
|
||||
+ /* Compute the start of the displayed memory */
|
||||
+ dma_addr = gem->dma_addr + fb->offsets[0];
|
||||
+
|
||||
+ regmap_write(regs, SUN50I_FBD_LADDR(base), lower_32_bits(dma_addr));
|
||||
+ regmap_write(regs, SUN50I_FBD_HADDR(base), upper_32_bits(dma_addr));
|
||||
+
|
||||
+ val = SUN50I_FBD_OVL_SIZE_HEIGHT(src_h);
|
||||
+ val |= SUN50I_FBD_OVL_SIZE_WIDTH(src_w);
|
||||
+ regmap_write(regs, SUN50I_FBD_OVL_SIZE(base), val);
|
||||
+
|
||||
+ val = SUN50I_FBD_OVL_COOR_Y(0);
|
||||
+ val |= SUN50I_FBD_OVL_COOR_X(0);
|
||||
+ regmap_write(regs, SUN50I_FBD_OVL_COOR(base), val);
|
||||
+
|
||||
+ regmap_write(regs, SUN50I_FBD_OVL_BG_COLOR(base),
|
||||
+ SUN8I_MIXER_BLEND_COLOR_BLACK);
|
||||
+ regmap_write(regs, SUN50I_FBD_DEFAULT_COLOR0(base), def_color0);
|
||||
+ regmap_write(regs, SUN50I_FBD_DEFAULT_COLOR1(base), def_color1);
|
||||
+
|
||||
+ val = SUN50I_FBD_CTL_GLB_ALPHA(state->alpha >> 16);
|
||||
+ val |= SUN50I_FBD_CTL_CLK_GATE;
|
||||
+ val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
|
||||
+ SUN50I_FBD_CTL_ALPHA_MODE_PIXEL :
|
||||
+ SUN50I_FBD_CTL_ALPHA_MODE_COMBINED;
|
||||
+ val |= SUN50I_FBD_CTL_FBD_EN;
|
||||
+ regmap_write(regs, SUN50I_FBD_CTL(base), val);
|
||||
+}
|
||||
+
|
||||
+void sun50i_afbc_disable(struct sun8i_mixer *mixer, unsigned int channel)
|
||||
+{
|
||||
+ u32 base = sun8i_channel_base(mixer, channel) + SUN50I_AFBC_CH_OFFSET;
|
||||
+
|
||||
+ regmap_write(mixer->engine.regs, SUN50I_FBD_CTL(base), 0);
|
||||
+}
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.h b/drivers/gpu/drm/sun4i/sun50i_afbc.h
|
||||
new file mode 100644
|
||||
index 000000000000..cea685c86855
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.h
|
||||
@@ -0,0 +1,87 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
+/*
|
||||
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
+ */
|
||||
+
|
||||
+#ifndef _SUN50I_AFBC_H_
|
||||
+#define _SUN50I_AFBC_H_
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+#define SUN50I_AFBC_CH_OFFSET 0x300
|
||||
+
|
||||
+#define SUN50I_AFBC_RGBA_8888 0x02
|
||||
+#define SUN50I_AFBC_RGB_888 0x08
|
||||
+#define SUN50I_AFBC_RGB_565 0x0a
|
||||
+#define SUN50I_AFBC_RGBA_4444 0x0e
|
||||
+#define SUN50I_AFBC_RGBA_5551 0x12
|
||||
+#define SUN50I_AFBC_RGBA1010102 0x16
|
||||
+#define SUN50I_AFBC_YUV422 0x26
|
||||
+#define SUN50I_AFBC_YUV420 0x2a
|
||||
+#define SUN50I_AFBC_P010 0x30
|
||||
+#define SUN50I_AFBC_P210 0x32
|
||||
+
|
||||
+#define SUN50I_FBD_CTL(base) ((base) + 0x00)
|
||||
+#define SUN50I_FBD_CTL_GLB_ALPHA(v) ((v) << 24)
|
||||
+#define SUN50I_FBD_CTL_CLK_GATE BIT(4)
|
||||
+#define SUN50I_FBD_CTL_ALPHA_MODE_PIXEL ((0) << 2)
|
||||
+#define SUN50I_FBD_CTL_ALPHA_MODE_LAYER ((1) << 2)
|
||||
+#define SUN50I_FBD_CTL_ALPHA_MODE_COMBINED ((2) << 2)
|
||||
+#define SUN50I_FBD_CTL_FBD_FCEN BIT(1)
|
||||
+#define SUN50I_FBD_CTL_FBD_EN BIT(0)
|
||||
+
|
||||
+#define SUN50I_FBD_SIZE(base) ((base) + 0x08)
|
||||
+#define SUN50I_FBD_SIZE_HEIGHT(v) (((v) - 1) << 16)
|
||||
+#define SUN50I_FBD_SIZE_WIDTH(v) (((v) - 1) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_BLK_SIZE(base) ((base) + 0x0c)
|
||||
+#define SUN50I_FBD_BLK_SIZE_HEIGHT(v) ((v) << 16)
|
||||
+#define SUN50I_FBD_BLK_SIZE_WIDTH(v) ((v) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_SRC_CROP(base) ((base) + 0x10)
|
||||
+#define SUN50I_FBD_SRC_CROP_TOP(v) ((v) << 16)
|
||||
+#define SUN50I_FBD_SRC_CROP_LEFT(v) ((v) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_LAY_CROP(base) ((base) + 0x14)
|
||||
+#define SUN50I_FBD_LAY_CROP_TOP(v) ((v) << 16)
|
||||
+#define SUN50I_FBD_LAY_CROP_LEFT(v) ((v) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_FMT(base) ((base) + 0x18)
|
||||
+#define SUN50I_FBD_FMT_SBS1(v) ((v) << 18)
|
||||
+#define SUN50I_FBD_FMT_SBS0(v) ((v) << 16)
|
||||
+#define SUN50I_FBD_FMT_YUV_TRAN BIT(7)
|
||||
+#define SUN50I_FBD_FMT_IN_FMT(v) ((v) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_LADDR(base) ((base) + 0x20)
|
||||
+#define SUN50I_FBD_HADDR(base) ((base) + 0x24)
|
||||
+
|
||||
+#define SUN50I_FBD_OVL_SIZE(base) ((base) + 0x30)
|
||||
+#define SUN50I_FBD_OVL_SIZE_HEIGHT(v) (((v) - 1) << 16)
|
||||
+#define SUN50I_FBD_OVL_SIZE_WIDTH(v) (((v) - 1) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_OVL_COOR(base) ((base) + 0x34)
|
||||
+#define SUN50I_FBD_OVL_COOR_Y(v) ((v) << 16)
|
||||
+#define SUN50I_FBD_OVL_COOR_X(v) ((v) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_OVL_BG_COLOR(base) ((base) + 0x38)
|
||||
+#define SUN50I_FBD_OVL_FILL_COLOR(base) ((base) + 0x3c)
|
||||
+
|
||||
+#define SUN50I_FBD_DEFAULT_COLOR0(base) ((base) + 0x50)
|
||||
+#define SUN50I_FBD_DEFAULT_COLOR0_ALPHA(v) ((v) << 16)
|
||||
+#define SUN50I_FBD_DEFAULT_COLOR0_YR(v) ((v) << 0)
|
||||
+
|
||||
+#define SUN50I_FBD_DEFAULT_COLOR1(base) ((base) + 0x54)
|
||||
+#define SUN50I_FBD_DEFAULT_COLOR1_VB(v) ((v) << 16)
|
||||
+#define SUN50I_FBD_DEFAULT_COLOR1_UG(v) ((v) << 0)
|
||||
+
|
||||
+struct sun8i_mixer;
|
||||
+struct drm_plane;
|
||||
+
|
||||
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
|
||||
+ u32 format, u64 modifier);
|
||||
+
|
||||
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
|
||||
+ struct drm_plane *plane);
|
||||
+void sun50i_afbc_disable(struct sun8i_mixer *mixer, unsigned int channel);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
index 329e8bf8cd20..28a2c44843e6 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
@@ -11,8 +11,10 @@
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_gem_dma_helper.h>
|
||||
+#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
+#include "sun50i_afbc.h"
|
||||
#include "sun8i_csc.h"
|
||||
#include "sun8i_mixer.h"
|
||||
#include "sun8i_vi_layer.h"
|
||||
@@ -99,7 +101,7 @@ static void sun8i_vi_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
|
||||
|
||||
static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
|
||||
int overlay, struct drm_plane *plane,
|
||||
- unsigned int zpos)
|
||||
+ unsigned int zpos, bool afbc)
|
||||
{
|
||||
struct drm_plane_state *state = plane->state;
|
||||
const struct drm_format_info *format = state->fb->format;
|
||||
@@ -182,7 +184,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
|
||||
|
||||
required = src_h * 100 / dst_h;
|
||||
|
||||
- if (ability < required) {
|
||||
+ if (!afbc && ability < required) {
|
||||
DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
|
||||
vm = src_h;
|
||||
vn = (u32)ability * dst_h / 100;
|
||||
@@ -192,7 +194,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
|
||||
/* it seems that every RGB scaler has buffer for 2048 pixels */
|
||||
scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;
|
||||
|
||||
- if (src_w > scanline) {
|
||||
+ if (!afbc && src_w > scanline) {
|
||||
DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
|
||||
hm = src_w;
|
||||
hn = scanline;
|
||||
@@ -356,6 +358,15 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void sun8i_vi_layer_prepare_non_linear(struct sun8i_mixer *mixer,
|
||||
+ int channel, int overlay)
|
||||
+{
|
||||
+ u32 base = sun8i_channel_base(mixer, channel);
|
||||
+
|
||||
+ regmap_write(mixer->engine.regs,
|
||||
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(base, overlay), 0);
|
||||
+}
|
||||
+
|
||||
static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
@@ -399,6 +410,7 @@ static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
|
||||
|
||||
sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
|
||||
old_zpos);
|
||||
+ sun50i_afbc_disable(mixer, layer->channel);
|
||||
}
|
||||
|
||||
static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
|
||||
@@ -411,26 +423,51 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
|
||||
struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
|
||||
unsigned int zpos = new_state->normalized_zpos;
|
||||
unsigned int old_zpos = old_state->normalized_zpos;
|
||||
+ struct drm_framebuffer *fb = plane->state->fb;
|
||||
struct sun8i_mixer *mixer = layer->mixer;
|
||||
+ bool afbc = drm_is_afbc(fb->modifier);
|
||||
|
||||
if (!new_state->visible) {
|
||||
sun8i_vi_layer_enable(mixer, layer->channel,
|
||||
layer->overlay, false, 0, old_zpos);
|
||||
+ sun50i_afbc_disable(mixer, layer->channel);
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (afbc) {
|
||||
+ u32 fmt_type;
|
||||
+
|
||||
+ sun8i_vi_layer_prepare_non_linear(mixer, layer->channel,
|
||||
+ layer->overlay);
|
||||
+ sun50i_afbc_atomic_update(mixer, layer->channel, plane);
|
||||
+
|
||||
+ fmt_type = sun8i_vi_layer_get_format_type(fb->format);
|
||||
+ sun8i_csc_set_ccsc(mixer, layer->channel, fmt_type,
|
||||
+ plane->state->color_encoding,
|
||||
+ plane->state->color_range);
|
||||
+ } else {
|
||||
+ sun50i_afbc_disable(mixer, layer->channel);
|
||||
+ sun8i_vi_layer_update_alpha(mixer, layer->channel,
|
||||
+ layer->overlay, plane);
|
||||
+ sun8i_vi_layer_update_formats(mixer, layer->channel,
|
||||
+ layer->overlay, plane);
|
||||
+ sun8i_vi_layer_update_buffer(mixer, layer->channel,
|
||||
+ layer->overlay, plane);
|
||||
+ }
|
||||
sun8i_vi_layer_update_coord(mixer, layer->channel,
|
||||
- layer->overlay, plane, zpos);
|
||||
- sun8i_vi_layer_update_alpha(mixer, layer->channel,
|
||||
- layer->overlay, plane);
|
||||
- sun8i_vi_layer_update_formats(mixer, layer->channel,
|
||||
- layer->overlay, plane);
|
||||
- sun8i_vi_layer_update_buffer(mixer, layer->channel,
|
||||
- layer->overlay, plane);
|
||||
+ layer->overlay, plane, zpos, afbc);
|
||||
sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
|
||||
true, zpos, old_zpos);
|
||||
}
|
||||
|
||||
+static bool sun8i_vi_layer_format_mod_supported(struct drm_plane *plane,
|
||||
+ u32 format, u64 modifier)
|
||||
+{
|
||||
+ struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
|
||||
+
|
||||
+ return sun50i_afbc_format_mod_supported(layer->mixer, format, modifier);
|
||||
+}
|
||||
+
|
||||
static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
|
||||
.atomic_check = sun8i_vi_layer_atomic_check,
|
||||
.atomic_disable = sun8i_vi_layer_atomic_disable,
|
||||
@@ -444,6 +481,7 @@ static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
+ .format_mod_supported = sun8i_vi_layer_format_mod_supported,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -527,6 +565,11 @@ static const u32 sun8i_vi_layer_de3_formats[] = {
|
||||
DRM_FORMAT_YVU411,
|
||||
DRM_FORMAT_YVU420,
|
||||
DRM_FORMAT_YVU422,
|
||||
+
|
||||
+ /* AFBC only formats */
|
||||
+ DRM_FORMAT_YUV420_8BIT,
|
||||
+ DRM_FORMAT_YUV420_10BIT,
|
||||
+ DRM_FORMAT_Y210,
|
||||
};
|
||||
|
||||
static const uint64_t sun8i_layer_modifiers[] = {
|
||||
@@ -534,6 +577,18 @@ static const uint64_t sun8i_layer_modifiers[] = {
|
||||
DRM_FORMAT_MOD_INVALID
|
||||
};
|
||||
|
||||
+static const uint64_t sun50i_layer_de3_modifiers[] = {
|
||||
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
||||
+ AFBC_FORMAT_MOD_SPARSE |
|
||||
+ AFBC_FORMAT_MOD_SPLIT),
|
||||
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
||||
+ AFBC_FORMAT_MOD_YTR |
|
||||
+ AFBC_FORMAT_MOD_SPARSE |
|
||||
+ AFBC_FORMAT_MOD_SPLIT),
|
||||
+ DRM_FORMAT_MOD_LINEAR,
|
||||
+ DRM_FORMAT_MOD_INVALID
|
||||
+};
|
||||
+
|
||||
struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
||||
struct sun8i_mixer *mixer,
|
||||
int index)
|
||||
@@ -542,6 +597,7 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
||||
u32 supported_encodings, supported_ranges;
|
||||
unsigned int plane_cnt, format_count;
|
||||
struct sun8i_vi_layer *layer;
|
||||
+ const uint64_t *modifiers;
|
||||
const u32 *formats;
|
||||
int ret;
|
||||
|
||||
@@ -556,9 +612,11 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
||||
if (mixer->cfg->is_de3) {
|
||||
formats = sun8i_vi_layer_de3_formats;
|
||||
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
|
||||
+ modifiers = sun50i_layer_de3_modifiers;
|
||||
} else {
|
||||
formats = sun8i_vi_layer_formats;
|
||||
format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
|
||||
+ modifiers = sun8i_layer_modifiers;
|
||||
}
|
||||
|
||||
if (!mixer->cfg->ui_num && index == 0)
|
||||
@@ -568,8 +626,7 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
||||
ret = drm_universal_plane_init(drm, &layer->plane, 0,
|
||||
&sun8i_vi_layer_funcs,
|
||||
formats, format_count,
|
||||
- sun8i_layer_modifiers,
|
||||
- type, NULL);
|
||||
+ modifiers, type, NULL);
|
||||
if (ret) {
|
||||
dev_err(drm->dev, "Couldn't initialize layer\n");
|
||||
return ERR_PTR(ret);
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,29 @@
|
||||
From c7999f0a3a7f275756a10a87849bb8fa47d315d3 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Mon, 9 Oct 2023 20:16:27 +0200
|
||||
Subject: [PATCH 20/23] media: cedrus: Increase H6 clock rate
|
||||
|
||||
Vendor driver runs Cedrus at 648 MHz, supposedly to be able to decode
|
||||
4k HEVC at 60 fps.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
|
||||
index 8e248d4a0aec..8d1ad841f66f 100644
|
||||
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
|
||||
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
|
||||
@@ -646,7 +646,7 @@ static const struct cedrus_variant sun50i_h6_cedrus_variant = {
|
||||
CEDRUS_CAPABILITY_H265_DEC |
|
||||
CEDRUS_CAPABILITY_H265_10_DEC |
|
||||
CEDRUS_CAPABILITY_VP8_DEC,
|
||||
- .mod_rate = 600000000,
|
||||
+ .mod_rate = 648000000,
|
||||
};
|
||||
|
||||
static const struct of_device_id cedrus_dt_match[] = {
|
||||
--
|
||||
2.42.0
|
||||
|
@ -0,0 +1,67 @@
|
||||
From c0652e260579791f38bc1d7c9c634135a1065c82 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Mon, 9 Oct 2023 20:55:25 +0200
|
||||
Subject: [PATCH 21/23] arm64: dts: allwinner: h6: Add GPU OPP to all boards
|
||||
|
||||
All H6 boards have GPU. Let's enable OPP table for it on all boards.
|
||||
That allows either better performance or lower power consumption.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts | 1 +
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi | 1 +
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts | 1 +
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi | 1 +
|
||||
4 files changed, 4 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
|
||||
index 6fc65e8db220..817976ba20f3 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "sun50i-h6.dtsi"
|
||||
#include "sun50i-h6-cpu-opp.dtsi"
|
||||
+#include "sun50i-h6-gpu-opp.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
|
||||
index 92745128fcfe..6a0e3bf9bdb7 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
|
||||
@@ -5,6 +5,7 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "sun50i-h6.dtsi"
|
||||
+#include "sun50i-h6-gpu-opp.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
|
||||
index 1ffd68f43f87..ee31303dc886 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "sun50i-h6.dtsi"
|
||||
#include "sun50i-h6-cpu-opp.dtsi"
|
||||
+#include "sun50i-h6-gpu-opp.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi
|
||||
index c3faefa651d9..531c8f2b423d 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "sun50i-h6.dtsi"
|
||||
#include "sun50i-h6-cpu-opp.dtsi"
|
||||
+#include "sun50i-h6-gpu-opp.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
--
|
||||
2.42.0
|
||||
|
@ -1,23 +1,23 @@
|
||||
From 24545292c40900c0871381b8697ade70aa9e3bdf Mon Sep 17 00:00:00 2001
|
||||
From d7b2340cd84ba5ce3494e8acbf52191e1d85bbe8 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Wed, 20 Jan 2021 22:15:36 +0100
|
||||
Subject: [PATCH] wip h3/h5 cvbs
|
||||
Subject: [PATCH 22/23] wip h3/h5 cvbs
|
||||
|
||||
---
|
||||
arch/arm/boot/dts/allwinner/sun8i-h3.dtsi | 22 +++++
|
||||
arch/arm/boot/dts/allwinner/sunxi-h3-h5.dtsi | 95 +++++++++++++++++++-
|
||||
arch/arm/boot/dts/allwinner/sun8i-h3.dtsi | 22 +++++
|
||||
arch/arm/boot/dts/allwinner/sunxi-h3-h5.dtsi | 95 +++++++++++++++++++-
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 22 +++++
|
||||
drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 14 ++-
|
||||
drivers/gpu/drm/sun4i/sun4i_tv.c | 35 +++++++-
|
||||
drivers/gpu/drm/sun4i/sun8i_mixer.c | 44 ++++++++-
|
||||
drivers/gpu/drm/sun4i/sun8i_mixer.c | 38 ++++++++
|
||||
drivers/gpu/drm/sun4i/sun8i_mixer.h | 5 +-
|
||||
7 files changed, 226 insertions(+), 11 deletions(-)
|
||||
7 files changed, 223 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/allwinner/sun8i-h3.dtsi b/arch/arm/boot/dts/allwinner/sun8i-h3.dtsi
|
||||
index 448dd325f8c3..d896dc5502f5 100644
|
||||
index eac2349a2380..411640fca509 100644
|
||||
--- a/arch/arm/boot/dts/allwinner/sun8i-h3.dtsi
|
||||
+++ b/arch/arm/boot/dts/allwinner/sun8i-h3.dtsi
|
||||
@@ -252,6 +252,20 @@ ths: thermal-sensor@1c25000 {
|
||||
@@ -239,6 +239,20 @@ ths: thermal-sensor@1c25000 {
|
||||
nvmem-cell-names = "calibration";
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
@ -38,7 +38,7 @@ index 448dd325f8c3..d896dc5502f5 100644
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
@@ -299,6 +313,10 @@ &mbus {
|
||||
@@ -286,6 +300,10 @@ &mbus {
|
||||
compatible = "allwinner,sun8i-h3-mbus";
|
||||
};
|
||||
|
||||
@ -49,7 +49,7 @@ index 448dd325f8c3..d896dc5502f5 100644
|
||||
&mmc0 {
|
||||
compatible = "allwinner,sun7i-a20-mmc";
|
||||
clocks = <&ccu CLK_BUS_MMC0>,
|
||||
@@ -346,3 +364,7 @@ &rtc {
|
||||
@@ -333,3 +351,7 @@ &rtc {
|
||||
&sid {
|
||||
compatible = "allwinner,sun8i-h3-sid";
|
||||
};
|
||||
@ -58,10 +58,10 @@ index 448dd325f8c3..d896dc5502f5 100644
|
||||
+ remote-endpoint = <&tve_in_tcon1>;
|
||||
+};
|
||||
diff --git a/arch/arm/boot/dts/allwinner/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/allwinner/sunxi-h3-h5.dtsi
|
||||
index 3d37a6a586b6..152029413784 100644
|
||||
index ade1cd50e445..dc2ae4270347 100644
|
||||
--- a/arch/arm/boot/dts/allwinner/sunxi-h3-h5.dtsi
|
||||
+++ b/arch/arm/boot/dts/allwinner/sunxi-h3-h5.dtsi
|
||||
@@ -119,7 +119,7 @@ osc32k: osc32k_clk {
|
||||
@@ -102,7 +102,7 @@ osc32k: osc32k_clk {
|
||||
|
||||
de: display-engine {
|
||||
compatible = "allwinner,sun8i-h3-display-engine";
|
||||
@ -70,7 +70,7 @@ index 3d37a6a586b6..152029413784 100644
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -163,11 +163,50 @@ ports {
|
||||
@@ -139,11 +139,50 @@ ports {
|
||||
#size-cells = <0>;
|
||||
|
||||
mixer0_out: port@1 {
|
||||
@ -122,7 +122,7 @@ index 3d37a6a586b6..152029413784 100644
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -196,11 +235,19 @@ ports {
|
||||
@@ -172,11 +211,19 @@ ports {
|
||||
#size-cells = <0>;
|
||||
|
||||
tcon0_in: port@0 {
|
||||
@ -143,7 +143,7 @@ index 3d37a6a586b6..152029413784 100644
|
||||
};
|
||||
|
||||
tcon0_out: port@1 {
|
||||
@@ -216,6 +263,48 @@ tcon0_out_hdmi: endpoint@1 {
|
||||
@@ -192,6 +239,48 @@ tcon0_out_hdmi: endpoint@1 {
|
||||
};
|
||||
};
|
||||
|
||||
@ -193,10 +193,10 @@ index 3d37a6a586b6..152029413784 100644
|
||||
/* compatible and clocks are in per SoC .dtsi file */
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
|
||||
index 4f00ae227cce..d30c85948ac5 100644
|
||||
index d3caf27b6a55..31e67b91e4fa 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
|
||||
@@ -197,6 +197,20 @@ ths: thermal-sensor@1c25000 {
|
||||
@@ -184,6 +184,20 @@ ths: thermal-sensor@1c25000 {
|
||||
nvmem-cell-names = "calibration";
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
@ -217,7 +217,7 @@ index 4f00ae227cce..d30c85948ac5 100644
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
@@ -250,6 +264,10 @@ &mbus {
|
||||
@@ -237,6 +251,10 @@ &mbus {
|
||||
compatible = "allwinner,sun50i-h5-mbus";
|
||||
};
|
||||
|
||||
@ -228,7 +228,7 @@ index 4f00ae227cce..d30c85948ac5 100644
|
||||
&mmc0 {
|
||||
compatible = "allwinner,sun50i-h5-mmc",
|
||||
"allwinner,sun50i-a64-mmc";
|
||||
@@ -285,3 +303,7 @@ &rtc {
|
||||
@@ -272,3 +290,7 @@ &rtc {
|
||||
&sid {
|
||||
compatible = "allwinner,sun50i-h5-sid";
|
||||
};
|
||||
@ -237,10 +237,10 @@ index 4f00ae227cce..d30c85948ac5 100644
|
||||
+ remote-endpoint = <&tve_in_tcon1>;
|
||||
+};
|
||||
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
|
||||
index e058cf691aea..0b0df6d6bc9c 100644
|
||||
index 74274c17efb3..c4f4ba836408 100644
|
||||
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
|
||||
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
|
||||
@@ -458,8 +458,18 @@ static SUNXI_CCU_M_WITH_MUX_GATE(tcon_clk, "tcon", tcon_parents,
|
||||
@@ -463,8 +463,18 @@ static SUNXI_CCU_M_WITH_MUX_GATE(tcon_clk, "tcon", tcon_parents,
|
||||
CLK_SET_RATE_PARENT);
|
||||
|
||||
static const char * const tve_parents[] = { "pll-de", "pll-periph1" };
|
||||
@ -262,7 +262,7 @@ index e058cf691aea..0b0df6d6bc9c 100644
|
||||
static const char * const deinterlace_parents[] = { "pll-periph0", "pll-periph1" };
|
||||
static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents,
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
|
||||
index 94883abe0dfd..9c7090a0d52a 100644
|
||||
index ec65d9d59de7..d2235d5a7416 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
|
||||
@@ -10,6 +10,7 @@
|
||||
@ -273,7 +273,7 @@ index 94883abe0dfd..9c7090a0d52a 100644
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
@@ -167,6 +168,11 @@ struct tv_mode {
|
||||
@@ -159,6 +160,11 @@ struct tv_mode {
|
||||
const struct resync_parameters *resync_params;
|
||||
};
|
||||
|
||||
@ -285,7 +285,7 @@ index 94883abe0dfd..9c7090a0d52a 100644
|
||||
struct sun4i_tv {
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder encoder;
|
||||
@@ -527,7 +533,7 @@ static const struct regmap_config sun4i_tv_regmap_config = {
|
||||
@@ -419,7 +425,7 @@ static const struct regmap_config sun4i_tv_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
@ -294,7 +294,7 @@ index 94883abe0dfd..9c7090a0d52a 100644
|
||||
.name = "tv-encoder",
|
||||
};
|
||||
|
||||
@@ -537,13 +543,19 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
|
||||
@@ -429,13 +435,19 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct drm_device *drm = data;
|
||||
struct sun4i_drv *drv = drm->dev_private;
|
||||
@ -314,7 +314,7 @@ index 94883abe0dfd..9c7090a0d52a 100644
|
||||
tv->drv = drv;
|
||||
dev_set_drvdata(dev, tv);
|
||||
|
||||
@@ -580,6 +592,11 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
|
||||
@@ -472,6 +484,11 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
|
||||
}
|
||||
clk_prepare_enable(tv->clk);
|
||||
|
||||
@ -326,8 +326,8 @@ index 94883abe0dfd..9c7090a0d52a 100644
|
||||
drm_encoder_helper_add(&tv->encoder,
|
||||
&sun4i_tv_helper_funcs);
|
||||
ret = drm_simple_encoder_init(drm, &tv->encoder,
|
||||
@@ -648,8 +665,22 @@ static int sun4i_tv_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
@@ -551,8 +568,22 @@ static void sun4i_tv_remove(struct platform_device *pdev)
|
||||
component_del(&pdev->dev, &sun4i_tv_ops);
|
||||
}
|
||||
|
||||
+static const struct sun4i_tv_quirks a10_quirks = {
|
||||
@ -351,10 +351,10 @@ index 94883abe0dfd..9c7090a0d52a 100644
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun4i_tv_of_table);
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
||||
index f5291170bf5e..490e8e74450f 100644
|
||||
index 8e32d0b24ac9..854f5ab76463 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
||||
@@ -32,6 +32,12 @@ struct de2_fmt_info {
|
||||
@@ -36,6 +36,12 @@ struct de2_fmt_info {
|
||||
u32 de2_fmt;
|
||||
};
|
||||
|
||||
@ -367,8 +367,8 @@ index f5291170bf5e..490e8e74450f 100644
|
||||
static const struct de2_fmt_info de2_formats[] = {
|
||||
{
|
||||
.drm_fmt = DRM_FORMAT_ARGB8888,
|
||||
@@ -327,10 +333,29 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
|
||||
interlaced ? "on" : "off");
|
||||
@@ -369,11 +375,30 @@ static u32 *sun8i_mixer_get_supported_fmts(struct sunxi_engine *engine, u32 *num
|
||||
return formats;
|
||||
}
|
||||
|
||||
+static void sun8i_mixer_apply_color_correction(struct sunxi_engine *engine)
|
||||
@ -389,18 +389,16 @@ index f5291170bf5e..490e8e74450f 100644
|
||||
+}
|
||||
+
|
||||
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,
|
||||
.commit = sun8i_mixer_commit,
|
||||
.layers_init = sun8i_layers_init,
|
||||
.mode_set = sun8i_mixer_mode_set,
|
||||
.get_supported_fmts = sun8i_mixer_get_supported_fmts,
|
||||
+ .apply_color_correction = sun8i_mixer_apply_color_correction,
|
||||
+ .disable_color_correction = sun8i_mixer_disable_color_correction,
|
||||
};
|
||||
|
||||
static bool sun8i_mixer_volatile_reg(struct device *dev, unsigned int reg)
|
||||
@@ -600,6 +625,15 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
|
||||
static const struct regmap_config sun8i_mixer_regmap_config = {
|
||||
@@ -631,6 +656,15 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
|
||||
.vi_num = 1,
|
||||
};
|
||||
|
||||
@ -416,7 +414,7 @@ index f5291170bf5e..490e8e74450f 100644
|
||||
static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
|
||||
.ccsc = CCSC_MIXER0_LAYOUT,
|
||||
.mod_rate = 297000000,
|
||||
@@ -686,6 +720,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
|
||||
@@ -718,6 +752,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
|
||||
.compatible = "allwinner,sun8i-h3-de2-mixer-0",
|
||||
.data = &sun8i_h3_mixer0_cfg,
|
||||
},
|
||||
@ -428,7 +426,7 @@ index f5291170bf5e..490e8e74450f 100644
|
||||
.compatible = "allwinner,sun8i-r40-de2-mixer-0",
|
||||
.data = &sun8i_r40_mixer0_cfg,
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
||||
index 85c94884fb9a..28cdaf0044d9 100644
|
||||
index 13401643c7bf..5951adb66e69 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
||||
@@ -118,6 +118,10 @@
|
||||
@ -451,5 +449,5 @@ index 85c94884fb9a..28cdaf0044d9 100644
|
||||
#define SUN50I_MIXER_FCE_EN 0x70000
|
||||
#define SUN50I_MIXER_PEAK_EN 0x70800
|
||||
--
|
||||
2.37.3
|
||||
2.42.0
|
||||
|
@ -1,7 +1,7 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From 24edf1dbd1ea0935d425333ab1e1041de2b4874c Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Mon, 11 Oct 2021 20:13:41 +0200
|
||||
Subject: [PATCH] HACK: SW CEC implementation for H3
|
||||
Subject: [PATCH 23/23] HACK: SW CEC implementation for H3
|
||||
|
||||
Many H3 boards lack 32768 Hz external oscillator, so internal RC is used
|
||||
instead. However, it's too unstable for CEC. Use SW implementation
|
||||
@ -10,25 +10,41 @@ instead. That makes it usable, albeit sensitive to cpufreq changes.
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/Kconfig | 2 +
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 13 ++++
|
||||
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 83 +++++++++++++++++++++++++-
|
||||
3 files changed, 96 insertions(+), 2 deletions(-)
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 4 ++
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 14 ++++
|
||||
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 98 +++++++++++++++++++++++++-
|
||||
4 files changed, 116 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
|
||||
index 5755f0432e77..b93eb2fb52ce 100644
|
||||
index 4741d9f6544c..4dac2dddf707 100644
|
||||
--- a/drivers/gpu/drm/sun4i/Kconfig
|
||||
+++ b/drivers/gpu/drm/sun4i/Kconfig
|
||||
@@ -56,6 +56,8 @@ config DRM_SUN8I_DW_HDMI
|
||||
tristate "Support for Allwinner version of DesignWare HDMI"
|
||||
@@ -59,6 +59,8 @@ config DRM_SUN8I_DW_HDMI
|
||||
depends on DRM_SUN4I
|
||||
default DRM_SUN4I
|
||||
select DRM_DW_HDMI
|
||||
+ select CEC_CORE
|
||||
+ select CEC_PIN
|
||||
help
|
||||
Choose this option if you have an Allwinner SoC with the
|
||||
DesignWare HDMI controller with custom HDMI PHY. If M is
|
||||
DesignWare HDMI controller. SoCs that support HDMI and
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index 7309590feb56..bde6b81def55 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -273,6 +273,10 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
return dev_err_probe(dev, PTR_ERR(phy),
|
||||
"Couldn't get the HDMI PHY\n");
|
||||
|
||||
+ ret = sun8i_hdmi_phy_register_cec(phy, dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
index bffe1b9cd3dc..61c97619cba1 100644
|
||||
index 5383d9267a4d..9d1158f24ddb 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
@@ -13,6 +13,8 @@
|
||||
@ -54,7 +70,7 @@ index bffe1b9cd3dc..61c97619cba1 100644
|
||||
|
||||
struct sun8i_hdmi_phy;
|
||||
|
||||
@@ -164,6 +173,8 @@ struct sun8i_hdmi_phy_variant {
|
||||
@@ -159,6 +168,8 @@ struct sun8i_hdmi_phy_variant {
|
||||
};
|
||||
|
||||
struct sun8i_hdmi_phy {
|
||||
@ -63,7 +79,7 @@ index bffe1b9cd3dc..61c97619cba1 100644
|
||||
struct clk *clk_bus;
|
||||
struct clk *clk_mod;
|
||||
struct clk *clk_phy;
|
||||
@@ -174,6 +185,8 @@ struct sun8i_hdmi_phy {
|
||||
@@ -169,6 +180,8 @@ struct sun8i_hdmi_phy {
|
||||
struct regmap *regs;
|
||||
struct reset_control *rst_phy;
|
||||
const struct sun8i_hdmi_phy_variant *variant;
|
||||
@ -72,11 +88,18 @@ index bffe1b9cd3dc..61c97619cba1 100644
|
||||
};
|
||||
|
||||
struct sun8i_dw_hdmi_quirks {
|
||||
@@ -211,5 +224,6 @@ void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
|
||||
|
||||
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
|
||||
bool second_parent);
|
||||
+int sun8i_hdmi_phy_register_cec(struct sun8i_hdmi_phy *phy, struct device *dev);
|
||||
|
||||
#endif /* _SUN8I_DW_HDMI_H_ */
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
index b64d93da651d..e2936e7745b8 100644
|
||||
index 581233d6eaf2..a5771b5d9b67 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
@@ -506,8 +506,9 @@
|
||||
@@ -507,8 +507,9 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
|
||||
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
|
||||
SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0);
|
||||
|
||||
@ -88,7 +111,7 @@ index b64d93da651d..e2936e7745b8 100644
|
||||
|
||||
/* read calibration data */
|
||||
regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
|
||||
@@ -584,8 +585,47 @@
|
||||
@@ -585,8 +586,47 @@ void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
|
||||
plat_data->cur_ctr = variant->cur_ctr;
|
||||
plat_data->phy_config = variant->phy_cfg;
|
||||
}
|
||||
@ -136,40 +159,36 @@ index b64d93da651d..e2936e7745b8 100644
|
||||
static const struct regmap_config sun8i_hdmi_phy_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
@@ -653,6 +693,7 @@
|
||||
{
|
||||
struct platform_device *pdev = of_find_device_by_node(node);
|
||||
struct sun8i_hdmi_phy *phy;
|
||||
@@ -669,6 +709,41 @@ struct sun8i_hdmi_phy *sun8i_hdmi_phy_get(struct device_node *node)
|
||||
return phy;
|
||||
}
|
||||
|
||||
+int sun8i_hdmi_phy_register_cec(struct sun8i_hdmi_phy *phy, struct device *dev)
|
||||
+{
|
||||
+ int ret;
|
||||
|
||||
if (!pdev)
|
||||
return -EPROBE_DEFER;
|
||||
@@ -666,8 +707,35 @@
|
||||
hdmi->phy = phy;
|
||||
|
||||
put_device(&pdev->dev);
|
||||
+
|
||||
+ if (phy->bit_bang_cec) {
|
||||
+ phy->cec_adapter =
|
||||
+ cec_pin_allocate_adapter(&sun8i_hdmi_phy_cec_pin_ops,
|
||||
+ phy, "sun8i-cec",
|
||||
+ CEC_CAP_DEFAULTS);
|
||||
+ ret = PTR_ERR_OR_ZERO(phy->cec_adapter);
|
||||
+ if (ret < 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ phy->cec_notifier = cec_notifier_cec_adap_register(hdmi->dev, NULL, phy->cec_adapter);
|
||||
+ if (!phy->cec_notifier) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_delete_cec_adapter;
|
||||
+ }
|
||||
+ if (!phy->bit_bang_cec)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = cec_register_adapter(phy->cec_adapter, hdmi->dev);
|
||||
+ if (ret < 0)
|
||||
+ goto err_put_cec_notifier;
|
||||
+ phy->cec_adapter =
|
||||
+ cec_pin_allocate_adapter(&sun8i_hdmi_phy_cec_pin_ops,
|
||||
+ phy, "sun8i-cec",
|
||||
+ CEC_CAP_DEFAULTS);
|
||||
+ if (IS_ERR(phy->cec_adapter))
|
||||
+ return PTR_ERR(phy->cec_adapter);
|
||||
+
|
||||
+ phy->cec_notifier = cec_notifier_cec_adap_register(dev, NULL,
|
||||
+ phy->cec_adapter);
|
||||
+ if (!phy->cec_notifier) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_delete_cec_adapter;
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
+
|
||||
+ ret = cec_register_adapter(phy->cec_adapter, dev);
|
||||
+ if (ret < 0)
|
||||
+ goto err_put_cec_notifier;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_put_cec_notifier:
|
||||
+ cec_notifier_cec_adap_unregister(phy->cec_notifier, phy->cec_adapter);
|
||||
@ -177,10 +196,12 @@ index b64d93da651d..e2936e7745b8 100644
|
||||
+ cec_delete_adapter(phy->cec_adapter);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
+}
|
||||
+
|
||||
static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
|
||||
@@ -682,6 +750,14 @@
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -681,6 +756,14 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
|
||||
|
||||
phy->variant = of_device_get_match_data(dev);
|
||||
phy->dev = dev;
|
||||
@ -195,7 +216,7 @@ index b64d93da651d..e2936e7745b8 100644
|
||||
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
@@ -728,8 +804,19 @@
|
||||
@@ -727,8 +810,19 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -215,3 +236,6 @@ index b64d93da651d..e2936e7745b8 100644
|
||||
.driver = {
|
||||
.name = "sun8i-hdmi-phy",
|
||||
.of_match_table = sun8i_hdmi_phy_of_table,
|
||||
--
|
||||
2.42.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user