2500 lines
79 KiB
Diff
2500 lines
79 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Sat, 4 Nov 2023 17:54:08 +0800
|
|
Subject: drm/rockchip: vop2: Add cursor plane support
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 88 ++++++++--
|
|
1 file changed, 73 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index 6862fb146ace..574eb75dec7c 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -170,6 +170,7 @@ struct vop2_video_port {
|
|
u32 win_mask;
|
|
|
|
struct vop2_win *primary_plane;
|
|
+ struct vop2_win *cursor_plane;
|
|
struct drm_pending_vblank_event *event;
|
|
|
|
unsigned int nlayers;
|
|
@@ -2285,12 +2286,63 @@ static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2)
|
|
return NULL;
|
|
}
|
|
|
|
+static struct vop2_video_port *find_vp_without_cursor(struct vop2 *vop2)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < vop2->data->nr_vps; i++) {
|
|
+ struct vop2_video_port *vp = &vop2->vps[i];
|
|
+
|
|
+ if (!vp->crtc.port)
|
|
+ continue;
|
|
+ /*
|
|
+ * Only assign a cursor plane for a VP if it has more than 2 layers
|
|
+ */
|
|
+ if (vp->nlayers <= 2)
|
|
+ continue;
|
|
+ if (vp->cursor_plane)
|
|
+ continue;
|
|
+
|
|
+ return vp;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * divide the total windows equally between all used vp
|
|
+ */
|
|
+static void vop2_calc_layers_for_each_vp(struct vop2 *vop2, int nvps)
|
|
+{
|
|
+ const struct vop2_data *vop2_data = vop2->data;
|
|
+ struct vop2_video_port *vp;
|
|
+ unsigned int nlayers = vop2_data->win_size / nvps;
|
|
+ unsigned int used_layers = 0;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < vop2->data->nr_vps; i++) {
|
|
+ vp = &vop2->vps[i];
|
|
+
|
|
+ if (!vp->crtc.port)
|
|
+ continue;
|
|
+ /*
|
|
+ * The last VP maybe get a fewer windows
|
|
+ */
|
|
+ if (vop2_data->win_size - used_layers < nlayers)
|
|
+ vp->nlayers = vop2_data->win_size - used_layers;
|
|
+ else
|
|
+ vp->nlayers = nlayers;
|
|
+ used_layers += vp->nlayers;
|
|
+ }
|
|
+}
|
|
+
|
|
static int vop2_create_crtcs(struct vop2 *vop2)
|
|
{
|
|
const struct vop2_data *vop2_data = vop2->data;
|
|
struct drm_device *drm = vop2->drm;
|
|
struct device *dev = vop2->dev;
|
|
- struct drm_plane *plane;
|
|
+ struct drm_plane *primary;
|
|
+ struct drm_plane *cursor;
|
|
struct device_node *port;
|
|
struct vop2_video_port *vp;
|
|
int i, nvp, nvps = 0;
|
|
@@ -2331,6 +2383,8 @@ static int vop2_create_crtcs(struct vop2 *vop2)
|
|
nvps++;
|
|
}
|
|
|
|
+ vop2_calc_layers_for_each_vp(vop2, nvps);
|
|
+
|
|
nvp = 0;
|
|
for (i = 0; i < vop2->registered_num_wins; i++) {
|
|
struct vop2_win *win = &vop2->win[i];
|
|
@@ -2362,6 +2416,18 @@ static int vop2_create_crtcs(struct vop2 *vop2)
|
|
}
|
|
}
|
|
|
|
+ if (win->type == DRM_PLANE_TYPE_OVERLAY) {
|
|
+ vp = find_vp_without_cursor(vop2);
|
|
+ if (vp) {
|
|
+ win->type = DRM_PLANE_TYPE_CURSOR;
|
|
+ /*
|
|
+ * let __drm_crtc_init_with_planes handle it
|
|
+ */
|
|
+ possible_crtcs = 0;
|
|
+ vp->cursor_plane = win;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (win->type == DRM_PLANE_TYPE_OVERLAY)
|
|
possible_crtcs = (1 << nvps) - 1;
|
|
|
|
@@ -2379,9 +2445,13 @@ static int vop2_create_crtcs(struct vop2 *vop2)
|
|
if (!vp->crtc.port)
|
|
continue;
|
|
|
|
- plane = &vp->primary_plane->base;
|
|
+ primary = &vp->primary_plane->base;
|
|
+ if (vp->cursor_plane)
|
|
+ cursor = &vp->cursor_plane->base;
|
|
+ else
|
|
+ cursor = NULL;
|
|
|
|
- ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL,
|
|
+ ret = drm_crtc_init_with_planes(drm, &vp->crtc, primary, cursor,
|
|
&vop2_crtc_funcs,
|
|
"video_port%d", vp->id);
|
|
if (ret) {
|
|
@@ -2394,18 +2464,6 @@ static int vop2_create_crtcs(struct vop2 *vop2)
|
|
init_completion(&vp->dsp_hold_completion);
|
|
}
|
|
|
|
- /*
|
|
- * On the VOP2 it's very hard to change the number of layers on a VP
|
|
- * during runtime, so we distribute the layers equally over the used
|
|
- * VPs
|
|
- */
|
|
- for (i = 0; i < vop2->data->nr_vps; i++) {
|
|
- struct vop2_video_port *vp = &vop2->vps[i];
|
|
-
|
|
- if (vp->crtc.port)
|
|
- vp->nlayers = vop2_data->win_size / nvps;
|
|
- }
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Fri, 10 Nov 2023 08:47:21 +0800
|
|
Subject: drm/rockchip: vop2: A workaround for cursor plane zpos
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 5 ++++-
|
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index 574eb75dec7c..bbca037acf67 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -2242,8 +2242,11 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win,
|
|
unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
|
|
BIT(DRM_MODE_BLEND_PREMULTI) |
|
|
BIT(DRM_MODE_BLEND_COVERAGE);
|
|
+ unsigned int zpos = win->win_id;
|
|
int ret;
|
|
|
|
+ if (win->type == DRM_PLANE_TYPE_CURSOR)
|
|
+ zpos = 8;
|
|
ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs,
|
|
&vop2_plane_funcs, win_data->formats,
|
|
win_data->nformats,
|
|
@@ -2262,7 +2265,7 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win,
|
|
win->data->supported_rotations);
|
|
drm_plane_create_alpha_property(&win->base);
|
|
drm_plane_create_blend_mode_property(&win->base, blend_caps);
|
|
- drm_plane_create_zpos_property(&win->base, win->win_id, 0,
|
|
+ drm_plane_create_zpos_property(&win->base, zpos, 0,
|
|
vop2->registered_num_wins - 1);
|
|
|
|
return 0;
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Thu, 26 Oct 2023 14:44:29 +0800
|
|
Subject: drm/rockchip: move output interface releated definition to
|
|
rockchip_drm_drv.h
|
|
|
|
The output interface releated definition can shared between
|
|
vop and vop2, move them to rockchip_drm_drv.h can avoid duplicated
|
|
definition.
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
|
|
Cover-letter:
|
|
Add VOP2 support on rk3588
|
|
This patch sets aims at enable the VOP2 support on rk3588.
|
|
|
|
Main feature of VOP2 on rk3588:
|
|
Four video ports:
|
|
VP0 Max 4096x2160
|
|
VP1 Max 4096x2160
|
|
VP2 Max 4096x2160
|
|
VP3 Max 2048x1080
|
|
|
|
4 4K Cluster windows with AFBC/line RGB and AFBC-only YUV support
|
|
4 4K Esmart windows with line RGB/YUV support
|
|
|
|
The current version support all the 8 windows with all the suppported
|
|
plane format.
|
|
|
|
And we don't have a upstreamed encoder/connector(HDMI/DP) for rk3588
|
|
yet, Cristian from collabora is working on adding upstream support for
|
|
HDMI on rk3588.
|
|
|
|
My current test is runing with a HDMI driver pick from our bsp kernel.
|
|
|
|
A branch based on linux-6.7 rc1 containing all the series and
|
|
HDMI driver(not compatible with rk3568 ) picked from our bsp kernel
|
|
is available[0].
|
|
END
|
|
---
|
|
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 1 -
|
|
drivers/gpu/drm/rockchip/cdn-dp-core.c | 1 -
|
|
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 1 -
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 -
|
|
drivers/gpu/drm/rockchip/inno_hdmi.c | 1 -
|
|
drivers/gpu/drm/rockchip/rk3066_hdmi.c | 1 -
|
|
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 17 ++++++++++
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 12 +------
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 16 +--------
|
|
drivers/gpu/drm/rockchip/rockchip_lvds.c | 1 -
|
|
drivers/gpu/drm/rockchip/rockchip_rgb.c | 1 -
|
|
11 files changed, 19 insertions(+), 34 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
|
index 84aa811ca1e9..bd08d57486fe 100644
|
|
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
|
@@ -30,7 +30,6 @@
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
|
|
#define RK3288_GRF_SOC_CON6 0x25c
|
|
#define RK3288_EDP_LCDC_SEL BIT(5)
|
|
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
|
|
index 21254e4e107a..a855c45ae7f3 100644
|
|
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
|
|
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
|
|
@@ -24,7 +24,6 @@
|
|
|
|
#include "cdn-dp-core.h"
|
|
#include "cdn-dp-reg.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
|
|
static inline struct cdn_dp_device *connector_to_dp(struct drm_connector *connector)
|
|
{
|
|
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
index 6396f9324dab..4cc8ed8f4fbd 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
|
|
@@ -26,7 +26,6 @@
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
|
|
#define DSI_PHY_RSTZ 0xa0
|
|
#define PHY_DISFORCEPLL 0
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 140e7be14236..b3a4ecaa8bf9 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -26,7 +26,6 @@
|
|
#include <uapi/linux/videodev2.h>
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
|
|
#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
|
|
index 6e5b922a121e..f6d819803c0e 100644
|
|
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
|
|
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
|
|
@@ -23,7 +23,6 @@
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
|
|
#include "inno_hdmi.h"
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
|
|
index fa6e592e0276..78136d0c5a65 100644
|
|
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
|
|
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
|
|
@@ -17,7 +17,6 @@
|
|
#include "rk3066_hdmi.h"
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
|
|
#define DEFAULT_PLLA_RATE 30000000
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
index aeb03a57240f..3d8ab2defa1b 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
@@ -20,6 +20,23 @@
|
|
#define ROCKCHIP_MAX_CONNECTOR 2
|
|
#define ROCKCHIP_MAX_CRTC 4
|
|
|
|
+/*
|
|
+ * display output interface supported by rockchip lcdc
|
|
+ */
|
|
+#define ROCKCHIP_OUT_MODE_P888 0
|
|
+#define ROCKCHIP_OUT_MODE_BT1120 0
|
|
+#define ROCKCHIP_OUT_MODE_P666 1
|
|
+#define ROCKCHIP_OUT_MODE_P565 2
|
|
+#define ROCKCHIP_OUT_MODE_BT656 5
|
|
+#define ROCKCHIP_OUT_MODE_S888 8
|
|
+#define ROCKCHIP_OUT_MODE_S888_DUMMY 12
|
|
+#define ROCKCHIP_OUT_MODE_YUV420 14
|
|
+/* for use special outface */
|
|
+#define ROCKCHIP_OUT_MODE_AAAA 15
|
|
+
|
|
+/* output flags */
|
|
+#define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0)
|
|
+
|
|
struct drm_device;
|
|
struct drm_connector;
|
|
struct iommu_domain;
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
index 4b2daefeb8c1..43d9c9191b7a 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
|
|
@@ -277,17 +277,7 @@ struct vop_data {
|
|
/* dst alpha ctrl define */
|
|
#define DST_FACTOR_M0(x) (((x) & 0x7) << 6)
|
|
|
|
-/*
|
|
- * display output interface supported by rockchip lcdc
|
|
- */
|
|
-#define ROCKCHIP_OUT_MODE_P888 0
|
|
-#define ROCKCHIP_OUT_MODE_P666 1
|
|
-#define ROCKCHIP_OUT_MODE_P565 2
|
|
-/* for use special outface */
|
|
-#define ROCKCHIP_OUT_MODE_AAAA 15
|
|
-
|
|
-/* output flags */
|
|
-#define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0)
|
|
+
|
|
|
|
enum alpha_mode {
|
|
ALPHA_STRAIGHT,
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
|
index 56fd31e05238..7175f46a2014 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
|
@@ -7,10 +7,9 @@
|
|
#ifndef _ROCKCHIP_DRM_VOP2_H
|
|
#define _ROCKCHIP_DRM_VOP2_H
|
|
|
|
-#include "rockchip_drm_vop.h"
|
|
-
|
|
#include <linux/regmap.h>
|
|
#include <drm/drm_modes.h>
|
|
+#include "rockchip_drm_vop.h"
|
|
|
|
#define VOP_FEATURE_OUTPUT_10BIT BIT(0)
|
|
|
|
@@ -166,19 +165,6 @@ struct vop2_data {
|
|
#define WB_YRGB_FIFO_FULL_INTR BIT(18)
|
|
#define WB_COMPLETE_INTR BIT(19)
|
|
|
|
-/*
|
|
- * display output interface supported by rockchip lcdc
|
|
- */
|
|
-#define ROCKCHIP_OUT_MODE_P888 0
|
|
-#define ROCKCHIP_OUT_MODE_BT1120 0
|
|
-#define ROCKCHIP_OUT_MODE_P666 1
|
|
-#define ROCKCHIP_OUT_MODE_P565 2
|
|
-#define ROCKCHIP_OUT_MODE_BT656 5
|
|
-#define ROCKCHIP_OUT_MODE_S888 8
|
|
-#define ROCKCHIP_OUT_MODE_S888_DUMMY 12
|
|
-#define ROCKCHIP_OUT_MODE_YUV420 14
|
|
-/* for use special outface */
|
|
-#define ROCKCHIP_OUT_MODE_AAAA 15
|
|
|
|
enum vop_csc_format {
|
|
CSC_BT601L,
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
|
index f0f47e9abf5a..59341654ec32 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
|
@@ -27,7 +27,6 @@
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
#include "rockchip_lvds.h"
|
|
|
|
#define DISPLAY_OUTPUT_RGB 0
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
|
|
index c677b71ae516..dbfbde24698e 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
|
|
@@ -19,7 +19,6 @@
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
#include "rockchip_drm_drv.h"
|
|
-#include "rockchip_drm_vop.h"
|
|
#include "rockchip_rgb.h"
|
|
|
|
struct rockchip_rgb {
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Thu, 2 Nov 2023 09:37:55 +0800
|
|
Subject: Revert "drm/rockchip: vop2: Use regcache_sync() to fix
|
|
suspend/resume"
|
|
|
|
This reverts commit b63a553e8f5aa6574eeb535a551817a93c426d8c.
|
|
|
|
regcache_sync will try to reload the configuration in regcache to
|
|
hardware, but the registers of 4 Cluster windows and Esmart1/2/3 on
|
|
the upcoming rk3588 can not be set successfully before internal PD
|
|
power on.
|
|
|
|
Also it's better to keep the hardware register as it is before we really
|
|
enable it.
|
|
|
|
So let's revert this version, and keep the first version:
|
|
afa965a45e01 ("drm/rockchip: vop2: fix suspend/resume")
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 10 +++++++---
|
|
1 file changed, 7 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index bbca037acf67..125cef9dbc52 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -218,6 +218,8 @@ struct vop2 {
|
|
struct vop2_win win[];
|
|
};
|
|
|
|
+static const struct regmap_config vop2_regmap_config;
|
|
+
|
|
static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
|
|
{
|
|
return container_of(crtc, struct vop2_video_port, crtc);
|
|
@@ -879,7 +881,11 @@ static void vop2_enable(struct vop2 *vop2)
|
|
return;
|
|
}
|
|
|
|
- regcache_sync(vop2->map);
|
|
+ ret = regmap_reinit_cache(vop2->map, &vop2_regmap_config);
|
|
+ if (ret) {
|
|
+ drm_err(vop2->drm, "failed to reinit cache: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
|
|
if (vop2->data->soc_id == 3566)
|
|
vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
|
|
@@ -909,8 +915,6 @@ static void vop2_disable(struct vop2 *vop2)
|
|
|
|
pm_runtime_put_sync(vop2->dev);
|
|
|
|
- regcache_mark_dirty(vop2->map);
|
|
-
|
|
clk_disable_unprepare(vop2->aclk);
|
|
clk_disable_unprepare(vop2->hclk);
|
|
}
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Wed, 25 Oct 2023 11:47:57 +0800
|
|
Subject: drm/rockchip: vop2: set half_block_en bit in all mode
|
|
|
|
At first we thought the half_block_en bit in AFBCD_CTRL register
|
|
only work in afbc mode. But the fact is that it control the line
|
|
buffer in all mode(afbc/tile/line), so we need configure it in
|
|
all case.
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 25 +++++++---
|
|
1 file changed, 18 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index 125cef9dbc52..0d4b22cf2d8c 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -517,6 +517,18 @@ static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
|
|
return vop2_convert_afbc_format(format) >= 0;
|
|
}
|
|
|
|
+/*
|
|
+ * 0: Full mode, 16 lines for one tail
|
|
+ * 1: half block mode, 8 lines one tail
|
|
+ */
|
|
+static bool vop2_half_block_enable(struct drm_plane_state *pstate)
|
|
+{
|
|
+ if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90))
|
|
+ return false;
|
|
+ else
|
|
+ return true;
|
|
+}
|
|
+
|
|
static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate,
|
|
bool afbc_half_block_en)
|
|
{
|
|
@@ -1140,6 +1152,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
|
|
bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
|
|
struct rockchip_gem_object *rk_obj;
|
|
unsigned long offset;
|
|
+ bool half_block_en;
|
|
bool afbc_en;
|
|
dma_addr_t yrgb_mst;
|
|
dma_addr_t uv_mst;
|
|
@@ -1232,6 +1245,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
|
|
dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
|
|
|
|
format = vop2_convert_format(fb->format->format);
|
|
+ half_block_en = vop2_half_block_enable(pstate);
|
|
|
|
drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n",
|
|
vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h,
|
|
@@ -1239,6 +1253,9 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
|
|
&fb->format->format,
|
|
afbc_en ? "AFBC" : "", &yrgb_mst);
|
|
|
|
+ if (vop2_cluster_window(win))
|
|
+ vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, half_block_en);
|
|
+
|
|
if (afbc_en) {
|
|
u32 stride;
|
|
|
|
@@ -1279,13 +1296,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
|
|
vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);
|
|
- if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90)) {
|
|
- vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 0);
|
|
- transform_offset = vop2_afbc_transform_offset(pstate, false);
|
|
- } else {
|
|
- vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 1);
|
|
- transform_offset = vop2_afbc_transform_offset(pstate, true);
|
|
- }
|
|
+ transform_offset = vop2_afbc_transform_offset(pstate, half_block_en);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, transform_offset);
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Wed, 1 Nov 2023 19:13:38 +0800
|
|
Subject: drm/rockchip: vop2: clear afbc en and transform bit for cluster
|
|
window at linear mode
|
|
|
|
The enable bit and transform offset of cluster windows should be
|
|
cleared when it work at linear mode, or we may have a iommu fault
|
|
issue.
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 5 +++++
|
|
1 file changed, 5 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index 0d4b22cf2d8c..c5fdb69497ed 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -1308,6 +1308,11 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
|
|
vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90);
|
|
} else {
|
|
+ if (vop2_cluster_window(win)) {
|
|
+ vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 0);
|
|
+ vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, 0);
|
|
+ }
|
|
+
|
|
vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4));
|
|
}
|
|
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Tue, 7 Nov 2023 18:14:17 +0800
|
|
Subject: drm/rockchip: vop2: Set YUV/RGB overlay mode
|
|
|
|
Set overlay mode register according to the
|
|
output mode is yuv or rgb.
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 19 ++++++++--
|
|
2 files changed, 17 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
index 3d8ab2defa1b..7a58c5c9d4ec 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
|
@@ -51,6 +51,7 @@ struct rockchip_crtc_state {
|
|
u32 bus_format;
|
|
u32 bus_flags;
|
|
int color_space;
|
|
+ bool yuv_overlay;
|
|
};
|
|
#define to_rockchip_crtc_state(s) \
|
|
container_of(s, struct rockchip_crtc_state, base)
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index c5fdb69497ed..407653eee901 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -1608,6 +1608,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
|
|
vop2->enable_count++;
|
|
|
|
+ vcstate->yuv_overlay = is_yuv_output(vcstate->bus_format);
|
|
+
|
|
vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY);
|
|
|
|
polflags = 0;
|
|
@@ -1635,7 +1637,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
|
|
dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;
|
|
|
|
- if (is_yuv_output(vcstate->bus_format))
|
|
+ if (vcstate->yuv_overlay)
|
|
dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;
|
|
|
|
vop2_dither_setup(crtc, &dsp_ctrl);
|
|
@@ -1944,10 +1946,12 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|
u16 hdisplay;
|
|
u32 bg_dly;
|
|
u32 pre_scan_dly;
|
|
+ u32 ovl_ctrl;
|
|
int i;
|
|
struct vop2_video_port *vp0 = &vop2->vps[0];
|
|
struct vop2_video_port *vp1 = &vop2->vps[1];
|
|
struct vop2_video_port *vp2 = &vop2->vps[2];
|
|
+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
|
|
|
|
adjusted_mode = &vp->crtc.state->adjusted_mode;
|
|
hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
|
|
@@ -1960,7 +1964,14 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|
pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len;
|
|
vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly);
|
|
|
|
- vop2_writel(vop2, RK3568_OVL_CTRL, 0);
|
|
+ ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL);
|
|
+ if (vcstate->yuv_overlay)
|
|
+ ovl_ctrl |= BIT(vp->id);
|
|
+ else
|
|
+ ovl_ctrl &= ~BIT(vp->id);
|
|
+
|
|
+ vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
|
|
+
|
|
port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
|
|
port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
|
|
|
|
@@ -2032,9 +2043,11 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|
layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5);
|
|
}
|
|
|
|
+ ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;
|
|
+
|
|
vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
|
|
vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
|
|
- vop2_writel(vop2, RK3568_OVL_CTRL, RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD);
|
|
+ vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
|
|
}
|
|
|
|
static void vop2_setup_dly_for_windows(struct vop2 *vop2)
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Thu, 19 Oct 2023 19:31:32 +0800
|
|
Subject: drm/rockchip: vop2: rename grf to sys_grf
|
|
|
|
The vop2 need to reference more grf(system grf, vop grf, vo0/1 grf,etc)
|
|
in the upcoming rk3588.
|
|
|
|
So we rename the current system grf to sys_grf.
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 8 ++++----
|
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index 407653eee901..c49786bd538d 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -191,7 +191,7 @@ struct vop2 {
|
|
void __iomem *regs;
|
|
struct regmap *map;
|
|
|
|
- struct regmap *grf;
|
|
+ struct regmap *sys_grf;
|
|
|
|
/* physical map length of vop2 register */
|
|
u32 len;
|
|
@@ -1499,9 +1499,9 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
|
|
dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
|
|
dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
|
|
if (polflags & POLFLAG_DCLK_INV)
|
|
- regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3));
|
|
+ regmap_write(vop2->sys_grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3));
|
|
else
|
|
- regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16));
|
|
+ regmap_write(vop2->sys_grf, RK3568_GRF_VO_CON1, BIT(3 + 16));
|
|
break;
|
|
case ROCKCHIP_VOP2_EP_HDMI0:
|
|
die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX;
|
|
@@ -2820,7 +2820,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
|
|
return PTR_ERR(vop2->lut_regs);
|
|
}
|
|
|
|
- vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
|
|
+ vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
|
|
|
|
vop2->hclk = devm_clk_get(vop2->dev, "hclk");
|
|
if (IS_ERR(vop2->hclk)) {
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Sat, 11 Nov 2023 09:27:56 +0800
|
|
Subject: dt-bindings: soc: rockchip: add rk3588 vop/vo syscon
|
|
|
|
Add VOP and VO GRF syscon compatibles for RK3588
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
Documentation/devicetree/bindings/soc/rockchip/grf.yaml | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml
|
|
index f8fc5285e4c1..12e7a78f7f6b 100644
|
|
--- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml
|
|
+++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml
|
|
@@ -31,6 +31,7 @@ properties:
|
|
- rockchip,rk3588-usb-grf
|
|
- rockchip,rk3588-usbdpphy-grf
|
|
- rockchip,rk3588-vo-grf
|
|
+ - rockchip,rk3588-vop-grf
|
|
- rockchip,rv1108-usbgrf
|
|
- const: syscon
|
|
- items:
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Sat, 11 Nov 2023 11:31:09 +0800
|
|
Subject: dt-bindings: display: vop2: Add rk3588 support
|
|
|
|
The vop2 on rk3588 is similar to which on rk356x
|
|
but with 4 video outputs and need to reference
|
|
more grf modules.
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml | 25 ++++++++++
|
|
1 file changed, 25 insertions(+)
|
|
|
|
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
|
|
index b60b90472d42..c333c651da1a 100644
|
|
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
|
|
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
|
|
@@ -20,6 +20,7 @@ properties:
|
|
enum:
|
|
- rockchip,rk3566-vop
|
|
- rockchip,rk3568-vop
|
|
+ - rockchip,rk3588-vop
|
|
|
|
reg:
|
|
items:
|
|
@@ -48,6 +49,8 @@ properties:
|
|
- description: Pixel clock for video port 0.
|
|
- description: Pixel clock for video port 1.
|
|
- description: Pixel clock for video port 2.
|
|
+ - description: Pixel clock for video port 4.
|
|
+ - description: Peripheral clock for vop on rk3588.
|
|
|
|
clock-names:
|
|
items:
|
|
@@ -56,12 +59,29 @@ properties:
|
|
- const: dclk_vp0
|
|
- const: dclk_vp1
|
|
- const: dclk_vp2
|
|
+ - const: dclk_vp3
|
|
+ - const: pclk_vop
|
|
|
|
rockchip,grf:
|
|
$ref: /schemas/types.yaml#/definitions/phandle
|
|
description:
|
|
Phandle to GRF regs used for misc control
|
|
|
|
+ rockchip,vo-grf:
|
|
+ $ref: /schemas/types.yaml#/definitions/phandle
|
|
+ description:
|
|
+ Phandle to VO GRF regs used for misc control, required for rk3588
|
|
+
|
|
+ rockchip,vop-grf:
|
|
+ $ref: /schemas/types.yaml#/definitions/phandle
|
|
+ description:
|
|
+ Phandle to VOP GRF regs used for misc control, required for rk3588
|
|
+
|
|
+ rockchip,pmu:
|
|
+ $ref: /schemas/types.yaml#/definitions/phandle
|
|
+ description:
|
|
+ Phandle to PMU regs used for misc control, required for rk3588
|
|
+
|
|
ports:
|
|
$ref: /schemas/graph.yaml#/properties/ports
|
|
|
|
@@ -81,6 +101,11 @@ properties:
|
|
description:
|
|
Output endpoint of VP2
|
|
|
|
+ port@3:
|
|
+ $ref: /schemas/graph.yaml#/properties/port
|
|
+ description:
|
|
+ Output endpoint of VP3
|
|
+
|
|
iommus:
|
|
maxItems: 1
|
|
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Mon, 16 Oct 2023 20:24:00 +0800
|
|
Subject: drm/rockchip: vop2: Add support for rk3588
|
|
|
|
VOP2 on rk3588:
|
|
|
|
Four video ports:
|
|
VP0 Max 4096x2160
|
|
VP1 Max 4096x2160
|
|
VP2 Max 4096x2160
|
|
VP3 Max 2048x1080
|
|
|
|
4 4K Cluster windows with AFBC/line RGB and AFBC-only YUV support
|
|
4 4K Esmart windows with line RGB/YUV support
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 321 +++++++++-
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 57 ++
|
|
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 215 +++++++
|
|
include/dt-bindings/soc/rockchip,vop2.h | 4 +
|
|
4 files changed, 590 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index c49786bd538d..bf12b6af14cf 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -192,6 +192,9 @@ struct vop2 {
|
|
struct regmap *map;
|
|
|
|
struct regmap *sys_grf;
|
|
+ struct regmap *vop_grf;
|
|
+ struct regmap *vo1_grf;
|
|
+ struct regmap *sys_pmu;
|
|
|
|
/* physical map length of vop2 register */
|
|
u32 len;
|
|
@@ -210,6 +213,7 @@ struct vop2 {
|
|
unsigned int enable_count;
|
|
struct clk *hclk;
|
|
struct clk *aclk;
|
|
+ struct clk *pclk;
|
|
|
|
/* optional internal rgb encoder */
|
|
struct rockchip_rgb *rgb;
|
|
@@ -218,6 +222,13 @@ struct vop2 {
|
|
struct vop2_win win[];
|
|
};
|
|
|
|
+#define vop2_output_if_is_hdmi(x) (x == ROCKCHIP_VOP2_EP_HDMI0 || x == ROCKCHIP_VOP2_EP_HDMI1)
|
|
+#define vop2_output_if_is_dp(x) (x == ROCKCHIP_VOP2_EP_DP0 || x == ROCKCHIP_VOP2_EP_DP1)
|
|
+#define vop2_output_if_is_edp(x) (x == ROCKCHIP_VOP2_EP_EDP0 || x == ROCKCHIP_VOP2_EP_EDP1)
|
|
+#define vop2_output_if_is_mipi(x) (x == ROCKCHIP_VOP2_EP_MIPI0 || x == ROCKCHIP_VOP2_EP_MIPI1)
|
|
+#define vop2_output_if_is_lvds(x) (x == ROCKCHIP_VOP2_EP_LVDS0 || x == ROCKCHIP_VOP2_EP_LVDS1)
|
|
+#define vop2_output_if_is_dpi(x) (x == ROCKCHIP_VOP2_EP_RGB0)
|
|
+
|
|
static const struct regmap_config vop2_regmap_config;
|
|
|
|
static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
|
|
@@ -272,9 +283,12 @@ static bool vop2_cluster_window(const struct vop2_win *win)
|
|
static void vop2_cfg_done(struct vop2_video_port *vp)
|
|
{
|
|
struct vop2 *vop2 = vp->vop2;
|
|
+ u32 val;
|
|
|
|
- regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE,
|
|
- BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
|
|
+ val = BIT(vp->id) | (BIT(vp->id) << 16) |
|
|
+ RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
|
|
+
|
|
+ regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
|
|
}
|
|
|
|
static void vop2_win_disable(struct vop2_win *win)
|
|
@@ -864,13 +878,31 @@ static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
|
|
goto err;
|
|
}
|
|
|
|
+ ret = clk_prepare_enable(vop2->pclk);
|
|
+ if (ret < 0) {
|
|
+ drm_err(vop2->drm, "failed to enable pclk - %d\n", ret);
|
|
+ goto err1;
|
|
+ }
|
|
+
|
|
return 0;
|
|
+err1:
|
|
+ clk_disable_unprepare(vop2->aclk);
|
|
err:
|
|
clk_disable_unprepare(vop2->hclk);
|
|
|
|
return ret;
|
|
}
|
|
|
|
+static void vop2_power_domain_all_on(struct vop2 *vop2)
|
|
+{
|
|
+ u32 pd;
|
|
+
|
|
+ pd = vop2_readl(vop2, RK3588_SYS_PD_CTRL);
|
|
+ pd &= ~(VOP2_PD_CLUSTER0 | VOP2_PD_CLUSTER1 | VOP2_PD_CLUSTER2 | VOP2_PD_CLUSTER3 | VOP2_PD_ESMART);
|
|
+
|
|
+ vop2_writel(vop2, RK3588_SYS_PD_CTRL, pd);
|
|
+}
|
|
+
|
|
static void vop2_enable(struct vop2 *vop2)
|
|
{
|
|
int ret;
|
|
@@ -902,6 +934,9 @@ static void vop2_enable(struct vop2 *vop2)
|
|
if (vop2->data->soc_id == 3566)
|
|
vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
|
|
|
|
+ if (vop2->data->soc_id == 3588)
|
|
+ vop2_power_domain_all_on(vop2);
|
|
+
|
|
vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
|
|
|
|
/*
|
|
@@ -927,6 +962,7 @@ static void vop2_disable(struct vop2 *vop2)
|
|
|
|
pm_runtime_put_sync(vop2->dev);
|
|
|
|
+ clk_disable_unprepare(vop2->pclk);
|
|
clk_disable_unprepare(vop2->aclk);
|
|
clk_disable_unprepare(vop2->hclk);
|
|
}
|
|
@@ -1294,7 +1330,11 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
|
|
vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap);
|
|
- vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);
|
|
+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
|
|
+ vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);
|
|
+ else
|
|
+ vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1);
|
|
+
|
|
vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);
|
|
transform_offset = vop2_afbc_transform_offset(pstate, half_block_en);
|
|
vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);
|
|
@@ -1482,10 +1522,10 @@ static void vop2_post_config(struct drm_crtc *crtc)
|
|
vop2_vp_write(vp, RK3568_VP_DSP_BG, 0);
|
|
}
|
|
|
|
-static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
|
|
- u32 polflags)
|
|
+static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
|
|
{
|
|
struct vop2 *vop2 = vp->vop2;
|
|
+ struct drm_crtc *crtc = &vp->crtc;
|
|
u32 die, dip;
|
|
|
|
die = vop2_readl(vop2, RK3568_DSP_IF_EN);
|
|
@@ -1547,13 +1587,255 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
|
|
break;
|
|
default:
|
|
drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id);
|
|
- return;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;
|
|
+
|
|
+ vop2_writel(vop2, RK3568_DSP_IF_EN, die);
|
|
+ vop2_writel(vop2, RK3568_DSP_IF_POL, dip);
|
|
+
|
|
+ return crtc->state->adjusted_mode.crtc_clock * 1000LL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * calc the dclk on rk3588
|
|
+ * the available div of dclk is 1, 2, 4
|
|
+ */
|
|
+static unsigned long vop2_calc_dclk(unsigned long child_clk, unsigned long max_dclk)
|
|
+{
|
|
+ if (child_clk * 4 <= max_dclk)
|
|
+ return child_clk * 4;
|
|
+ else if (child_clk * 2 <= max_dclk)
|
|
+ return child_clk * 2;
|
|
+ else if (child_clk <= max_dclk)
|
|
+ return child_clk;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * 4 pixclk/cycle on rk3588
|
|
+ * RGB/eDP/HDMI: if_pixclk >= dclk_core
|
|
+ * DP: dp_pixclk = dclk_out <= dclk_core
|
|
+ * DSI: mipi_pixclk <= dclk_out <= dclk_core
|
|
+ */
|
|
+static unsigned long vop2_calc_cru_cfg(struct vop2_video_port *vp, int id,
|
|
+ int *dclk_core_div, int *dclk_out_div,
|
|
+ int *if_pixclk_div, int *if_dclk_div)
|
|
+{
|
|
+ struct vop2 *vop2 = vp->vop2;
|
|
+ struct drm_crtc *crtc = &vp->crtc;
|
|
+ struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
|
|
+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
|
|
+ int output_mode = vcstate->output_mode;
|
|
+ unsigned long v_pixclk = adjusted_mode->crtc_clock * 1000LL; /* video timing pixclk */
|
|
+ unsigned long dclk_core_rate = v_pixclk >> 2;
|
|
+ unsigned long dclk_rate = v_pixclk;
|
|
+ unsigned long dclk_out_rate;
|
|
+ unsigned long if_dclk_rate;
|
|
+ unsigned long if_pixclk_rate;
|
|
+ int K = 1;
|
|
+
|
|
+ if (vop2_output_if_is_hdmi(id)) {
|
|
+ /*
|
|
+ * K = 2: dclk_core = if_pixclk_rate > if_dclk_rate
|
|
+ * K = 1: dclk_core = hdmie_edp_dclk > if_pixclk_rate
|
|
+ */
|
|
+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420) {
|
|
+ dclk_rate = dclk_rate >> 1;
|
|
+ K = 2;
|
|
+ }
|
|
+
|
|
+ if_pixclk_rate = (dclk_core_rate << 1) / K;
|
|
+ if_dclk_rate = dclk_core_rate / K;
|
|
+
|
|
+ *if_pixclk_div = dclk_rate / if_pixclk_rate;
|
|
+ *if_dclk_div = dclk_rate / if_dclk_rate;
|
|
+ *dclk_core_div = dclk_rate / dclk_core_rate;
|
|
+ } else if (vop2_output_if_is_edp(id)) {
|
|
+ /* edp_pixclk = edp_dclk > dclk_core */
|
|
+ if_pixclk_rate = v_pixclk / K;
|
|
+ if_dclk_rate = v_pixclk / K;
|
|
+ dclk_rate = if_pixclk_rate * K;
|
|
+ *dclk_core_div = dclk_rate / dclk_core_rate;
|
|
+ *if_pixclk_div = dclk_rate / if_pixclk_rate;
|
|
+ *if_dclk_div = *if_pixclk_div;
|
|
+ } else if (vop2_output_if_is_dp(id)) {
|
|
+ if (output_mode == ROCKCHIP_OUT_MODE_YUV420)
|
|
+ dclk_out_rate = v_pixclk >> 3;
|
|
+ else
|
|
+ dclk_out_rate = v_pixclk >> 2;
|
|
+
|
|
+ dclk_rate = vop2_calc_dclk(dclk_out_rate, 600000);
|
|
+ if (!dclk_rate) {
|
|
+ drm_err(vop2->drm, "DP dclk_out_rate out of range(max_dclk: 600 KHZ, dclk_out_rate: %ld KHZ)\n",
|
|
+ dclk_out_rate);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ *dclk_out_div = dclk_rate / dclk_out_rate;
|
|
+ *dclk_core_div = dclk_rate / dclk_core_rate;
|
|
+ } else if (vop2_output_if_is_mipi(id)) {
|
|
+ if_pixclk_rate = dclk_core_rate / K;
|
|
+ /* dclk_core = dclk_out * K = if_pixclk * K = v_pixclk / 4 */
|
|
+ dclk_out_rate = if_pixclk_rate;
|
|
+ /* dclk_rate = N * dclk_core_rate N = (1,2,4 ), we get a little factor here */
|
|
+ dclk_rate = vop2_calc_dclk(dclk_out_rate, 600000);
|
|
+ if (!dclk_rate) {
|
|
+ drm_err(vop2->drm, "MIPI dclk out of range(max_dclk: 600 KHZ, dclk_out_rate: %ld KHZ)\n",
|
|
+ dclk_out_rate);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ *dclk_out_div = dclk_rate / dclk_out_rate;
|
|
+ *dclk_core_div = dclk_rate / dclk_core_rate;
|
|
+ *if_pixclk_div = 1; /*mipi pixclk == dclk_out*/
|
|
+ } else if (vop2_output_if_is_dpi(id)) {
|
|
+ dclk_rate = v_pixclk;
|
|
+ *dclk_core_div = dclk_rate / dclk_core_rate;
|
|
+ }
|
|
+
|
|
+ *if_pixclk_div = ilog2(*if_pixclk_div);
|
|
+ *if_dclk_div = ilog2(*if_dclk_div);
|
|
+ *dclk_core_div = ilog2(*dclk_core_div);
|
|
+ *dclk_out_div = ilog2(*dclk_out_div);
|
|
+
|
|
+ DRM_DEV_INFO(vop2->dev, "dclk:%ld,if_pixclk_div;%d,if_dclk_div:%d\n", dclk_rate, *if_pixclk_div, *if_dclk_div);
|
|
+
|
|
+ return dclk_rate;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * MIPI port mux on rk3588:
|
|
+ * 0: Video Port2
|
|
+ * 1: Video Port3
|
|
+ * 3: Video Port 1(MIPI1 only)
|
|
+ */
|
|
+static u32 rk3588_get_mipi_port_mux(int vp_id)
|
|
+{
|
|
+ if (vp_id == 1)
|
|
+ return 3;
|
|
+ else if (vp_id == 3)
|
|
+ return 1;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static u32 rk3588_get_hdmi_pol(u32 flags)
|
|
+{
|
|
+ u32 val;
|
|
+
|
|
+ val = (flags & DRM_MODE_FLAG_NHSYNC) ? BIT(HSYNC_POSITIVE) : 0;
|
|
+ val |= (flags & DRM_MODE_FLAG_NVSYNC) ? BIT(VSYNC_POSITIVE) : 0;
|
|
+
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
|
|
+{
|
|
+ struct vop2 *vop2 = vp->vop2;
|
|
+ int dclk_core_div, dclk_out_div, if_pixclk_div, if_dclk_div;
|
|
+ unsigned long clock;
|
|
+ u32 die, dip, div, vp_clk_div, val;
|
|
+
|
|
+ clock = vop2_calc_cru_cfg(vp, id, &dclk_core_div, &dclk_out_div, &if_pixclk_div, &if_dclk_div);
|
|
+
|
|
+ vp_clk_div = FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_CORE_DIV, dclk_core_div);
|
|
+ vp_clk_div |= FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_OUT_DIV, dclk_out_div);
|
|
+
|
|
+ die = vop2_readl(vop2, RK3568_DSP_IF_EN);
|
|
+ dip = vop2_readl(vop2, RK3568_DSP_IF_POL);
|
|
+ div = vop2_readl(vop2, RK3568_DSP_IF_CTRL);
|
|
+
|
|
+ switch (id) {
|
|
+ case ROCKCHIP_VOP2_EP_HDMI0:
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX;
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_HDMI0 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id);
|
|
+ val = rk3588_get_hdmi_pol(polflags);
|
|
+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 1, 1));
|
|
+ regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 6, 5));
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_EP_HDMI1:
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV, if_dclk_div);
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV, if_pixclk_div);
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX;
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_HDMI1 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id);
|
|
+ val = rk3588_get_hdmi_pol(polflags);
|
|
+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 4, 4));
|
|
+ regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 8, 7));
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_EP_EDP0:
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX;
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_EDP0 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id);
|
|
+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 0, 0));
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_EP_EDP1:
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX;
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_EDP1 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id);
|
|
+ regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 3, 3));
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_EP_MIPI0:
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_MIPI0_PCLK_DIV, if_pixclk_div);
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX;
|
|
+ val = rk3588_get_mipi_port_mux(vp->id);
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_MIPI0 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX, !!val);
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_EP_MIPI1:
|
|
+ div |= FIELD_PREP(RK3588_DSP_IF_MIPI1_PCLK_DIV, if_pixclk_div);
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX;
|
|
+ val = rk3588_get_mipi_port_mux(vp->id);
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, val);
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_EP_DP0:
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_DP0_MUX;
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_DP0 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_DP0_MUX, vp->id);
|
|
+ dip &= ~RK3588_DSP_IF_POL__DP0_PIN_POL;
|
|
+ dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP0_PIN_POL, polflags);
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_EP_DP1:
|
|
+ die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX;
|
|
+ die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 |
|
|
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);
|
|
+ dip &= ~RK3588_DSP_IF_POL__DP1_PIN_POL;
|
|
+ dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP1_PIN_POL, polflags);
|
|
+ break;
|
|
+ default:
|
|
+ drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id);
|
|
+ return 0;
|
|
}
|
|
|
|
dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;
|
|
|
|
+ vop2_vp_write(vp, RK3588_VP_CLK_CTRL, vp_clk_div);
|
|
vop2_writel(vop2, RK3568_DSP_IF_EN, die);
|
|
+ vop2_writel(vop2, RK3568_DSP_IF_CTRL, div);
|
|
vop2_writel(vop2, RK3568_DSP_IF_POL, dip);
|
|
+
|
|
+ return clock;
|
|
+}
|
|
+
|
|
+static unsigned long vop2_set_intf_mux(struct vop2_video_port *vp, int ep_id, u32 polflags)
|
|
+{
|
|
+ struct vop2 *vop2 = vp->vop2;
|
|
+
|
|
+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
|
|
+ return rk3568_set_intf_mux(vp, ep_id, polflags);
|
|
+ else if(vop2->data->soc_id == 3588)
|
|
+ return rk3588_set_intf_mux(vp, ep_id, polflags);
|
|
+ else
|
|
+ return 0;
|
|
}
|
|
|
|
static int us_to_vertical_line(struct drm_display_mode *mode, int us)
|
|
@@ -1623,7 +1905,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
|
|
drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
|
|
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
|
|
|
|
- rk3568_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);
|
|
+ clock = vop2_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);
|
|
}
|
|
|
|
if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
|
|
@@ -2012,6 +2294,14 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|
port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1;
|
|
port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id);
|
|
break;
|
|
+ case ROCKCHIP_VOP2_CLUSTER2:
|
|
+ port_sel &= ~RK3588_OVL_PORT_SEL__CLUSTER2;
|
|
+ port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__CLUSTER2, vp->id);
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_CLUSTER3:
|
|
+ port_sel &= ~RK3588_OVL_PORT_SEL__CLUSTER3;
|
|
+ port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__CLUSTER3, vp->id);
|
|
+ break;
|
|
case ROCKCHIP_VOP2_ESMART0:
|
|
port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0;
|
|
port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id);
|
|
@@ -2020,6 +2310,14 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|
port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1;
|
|
port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id);
|
|
break;
|
|
+ case ROCKCHIP_VOP2_ESMART2:
|
|
+ port_sel &= ~RK3588_OVL_PORT_SEL__ESMART2;
|
|
+ port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__ESMART2, vp->id);
|
|
+ break;
|
|
+ case ROCKCHIP_VOP2_ESMART3:
|
|
+ port_sel &= ~RK3588_OVL_PORT_SEL__ESMART3;
|
|
+ port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__ESMART3, vp->id);
|
|
+ break;
|
|
case ROCKCHIP_VOP2_SMART0:
|
|
port_sel &= ~RK3568_OVL_PORT_SEL__SMART0;
|
|
port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id);
|
|
@@ -2821,6 +3119,9 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
|
|
}
|
|
|
|
vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
|
|
+ vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf");
|
|
+ vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf");
|
|
+ vop2->sys_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu");
|
|
|
|
vop2->hclk = devm_clk_get(vop2->dev, "hclk");
|
|
if (IS_ERR(vop2->hclk)) {
|
|
@@ -2834,6 +3135,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
|
|
return PTR_ERR(vop2->aclk);
|
|
}
|
|
|
|
+ vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk_vop");
|
|
+ if (IS_ERR(vop2->pclk)) {
|
|
+ drm_err(vop2->drm, "failed to get pclk source\n");
|
|
+ return PTR_ERR(vop2->pclk);
|
|
+ }
|
|
+
|
|
vop2->irq = platform_get_irq(pdev, 0);
|
|
if (vop2->irq < 0) {
|
|
drm_err(vop2->drm, "cannot find irq for vop2\n");
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
|
index 7175f46a2014..2fffe580b215 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
|
@@ -16,6 +16,7 @@
|
|
#define WIN_FEATURE_AFBDC BIT(0)
|
|
#define WIN_FEATURE_CLUSTER BIT(1)
|
|
|
|
+#define HIWORD_UPDATE(v, h, l) ((GENMASK(h, l) << 16) | ((v) << (l)))
|
|
/*
|
|
* the delay number of a window in different mode.
|
|
*/
|
|
@@ -38,6 +39,18 @@ enum vop2_scale_down_mode {
|
|
VOP2_SCALE_DOWN_AVG,
|
|
};
|
|
|
|
+/*
|
|
+ * vop2 internal power domain id,
|
|
+ * should be all none zero, 0 will be treat as invalid;
|
|
+ */
|
|
+#define VOP2_PD_CLUSTER0 BIT(0)
|
|
+#define VOP2_PD_CLUSTER1 BIT(1)
|
|
+#define VOP2_PD_CLUSTER2 BIT(2)
|
|
+#define VOP2_PD_CLUSTER3 BIT(3)
|
|
+#define VOP2_PD_DSC_8K BIT(5)
|
|
+#define VOP2_PD_DSC_4K BIT(6)
|
|
+#define VOP2_PD_ESMART BIT(7)
|
|
+
|
|
enum vop2_win_regs {
|
|
VOP2_WIN_ENABLE,
|
|
VOP2_WIN_FORMAT,
|
|
@@ -192,6 +205,11 @@ enum dst_factor_mode {
|
|
};
|
|
|
|
#define RK3568_GRF_VO_CON1 0x0364
|
|
+
|
|
+#define RK3588_GRF_SOC_CON1 0x0304
|
|
+#define RK3588_GRF_VOP_CON2 0x08
|
|
+#define RK3588_GRF_VO1_CON0 0x00
|
|
+
|
|
/* System registers definition */
|
|
#define RK3568_REG_CFG_DONE 0x000
|
|
#define RK3568_VERSION_INFO 0x004
|
|
@@ -200,6 +218,7 @@ enum dst_factor_mode {
|
|
#define RK3568_DSP_IF_EN 0x028
|
|
#define RK3568_DSP_IF_CTRL 0x02c
|
|
#define RK3568_DSP_IF_POL 0x030
|
|
+#define RK3588_SYS_PD_CTRL 0x034
|
|
#define RK3568_WB_CTRL 0x40
|
|
#define RK3568_WB_XSCAL_FACTOR 0x44
|
|
#define RK3568_WB_YRGB_MST 0x48
|
|
@@ -223,6 +242,7 @@ enum dst_factor_mode {
|
|
#define RK3568_VP_DSP_CTRL 0x00
|
|
#define RK3568_VP_MIPI_CTRL 0x04
|
|
#define RK3568_VP_COLOR_BAR_CTRL 0x08
|
|
+#define RK3588_VP_CLK_CTRL 0x0C
|
|
#define RK3568_VP_3D_LUT_CTRL 0x10
|
|
#define RK3568_VP_3D_LUT_MST 0x20
|
|
#define RK3568_VP_DSP_BG 0x2C
|
|
@@ -364,6 +384,9 @@ enum dst_factor_mode {
|
|
#define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV BIT(4)
|
|
#define RK3568_VP_DSP_CTRL__OUT_MODE GENMASK(3, 0)
|
|
|
|
+#define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV GENMASK(3, 2)
|
|
+#define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV GENMASK(1, 0)
|
|
+
|
|
#define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN BIT(1)
|
|
#define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN BIT(0)
|
|
|
|
@@ -382,11 +405,37 @@ enum dst_factor_mode {
|
|
#define RK3568_SYS_DSP_INFACE_EN_HDMI BIT(1)
|
|
#define RK3568_SYS_DSP_INFACE_EN_RGB BIT(0)
|
|
|
|
+#define RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX GENMASK(22, 21)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX GENMASK(20, 20)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX GENMASK(19, 18)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX GENMASK(17, 16)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_DP1_MUX GENMASK(15, 14)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_DP0_MUX GENMASK(13, 12)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_DPI GENMASK(9, 8)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_MIPI1 BIT(7)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_MIPI0 BIT(6)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_HDMI1 BIT(5)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_EDP1 BIT(4)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_HDMI0 BIT(3)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_EDP0 BIT(2)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_DP1 BIT(1)
|
|
+#define RK3588_SYS_DSP_INFACE_EN_DP0 BIT(0)
|
|
+
|
|
+#define RK3588_DSP_IF_MIPI1_PCLK_DIV GENMASK(27, 26)
|
|
+#define RK3588_DSP_IF_MIPI0_PCLK_DIV GENMASK(25, 24)
|
|
+#define RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV GENMASK(22, 22)
|
|
+#define RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV GENMASK(21, 20)
|
|
+#define RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV GENMASK(18, 18)
|
|
+#define RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV GENMASK(17, 16)
|
|
+
|
|
#define RK3568_DSP_IF_POL__MIPI_PIN_POL GENMASK(19, 16)
|
|
#define RK3568_DSP_IF_POL__EDP_PIN_POL GENMASK(15, 12)
|
|
#define RK3568_DSP_IF_POL__HDMI_PIN_POL GENMASK(7, 4)
|
|
#define RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL GENMASK(3, 0)
|
|
|
|
+#define RK3588_DSP_IF_POL__DP1_PIN_POL GENMASK(14, 12)
|
|
+#define RK3588_DSP_IF_POL__DP0_PIN_POL GENMASK(10, 8)
|
|
+
|
|
#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK BIT(5)
|
|
#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2 BIT(4)
|
|
|
|
@@ -407,8 +456,12 @@ enum dst_factor_mode {
|
|
#define RK3568_OVL_PORT_SEL__SEL_PORT GENMASK(31, 16)
|
|
#define RK3568_OVL_PORT_SEL__SMART1 GENMASK(31, 30)
|
|
#define RK3568_OVL_PORT_SEL__SMART0 GENMASK(29, 28)
|
|
+#define RK3588_OVL_PORT_SEL__ESMART3 GENMASK(31, 30)
|
|
+#define RK3588_OVL_PORT_SEL__ESMART2 GENMASK(29, 28)
|
|
#define RK3568_OVL_PORT_SEL__ESMART1 GENMASK(27, 26)
|
|
#define RK3568_OVL_PORT_SEL__ESMART0 GENMASK(25, 24)
|
|
+#define RK3588_OVL_PORT_SEL__CLUSTER3 GENMASK(23, 22)
|
|
+#define RK3588_OVL_PORT_SEL__CLUSTER2 GENMASK(21, 20)
|
|
#define RK3568_OVL_PORT_SEL__CLUSTER1 GENMASK(19, 18)
|
|
#define RK3568_OVL_PORT_SEL__CLUSTER0 GENMASK(17, 16)
|
|
#define RK3568_OVL_PORT_SET__PORT2_MUX GENMASK(11, 8)
|
|
@@ -421,6 +474,10 @@ enum dst_factor_mode {
|
|
#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_1 GENMASK(15, 8)
|
|
#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_0 GENMASK(7, 0)
|
|
|
|
+#define RK3568_CLUSTER_WIN_CTRL0__WIN0_EN BIT(0)
|
|
+
|
|
+#define RK3568_SMART_REGION0_CTRL__WIN0_EN BIT(0)
|
|
+
|
|
#define RK3568_SMART_DLY_NUM__SMART1 GENMASK(31, 24)
|
|
#define RK3568_SMART_DLY_NUM__SMART0 GENMASK(23, 16)
|
|
#define RK3568_SMART_DLY_NUM__ESMART1 GENMASK(15, 8)
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
|
index 22288ad7f326..4745a9260cf8 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
|
@@ -34,6 +34,28 @@ static const uint32_t formats_cluster[] = {
|
|
DRM_FORMAT_Y210, /* yuv422_10bit non-Linear mode only */
|
|
};
|
|
|
|
+static const uint32_t formats_esmart[] = {
|
|
+ DRM_FORMAT_XRGB8888,
|
|
+ DRM_FORMAT_ARGB8888,
|
|
+ DRM_FORMAT_XBGR8888,
|
|
+ DRM_FORMAT_ABGR8888,
|
|
+ DRM_FORMAT_RGB888,
|
|
+ DRM_FORMAT_BGR888,
|
|
+ DRM_FORMAT_RGB565,
|
|
+ DRM_FORMAT_BGR565,
|
|
+ DRM_FORMAT_NV12, /* yuv420_8bit linear mode, 2 plane */
|
|
+ DRM_FORMAT_NV21, /* yvu420_8bit linear mode, 2 plane */
|
|
+ DRM_FORMAT_NV16, /* yuv422_8bit linear mode, 2 plane */
|
|
+ DRM_FORMAT_NV61, /* yvu422_8bit linear mode, 2 plane */
|
|
+ DRM_FORMAT_NV24, /* yuv444_8bit linear mode, 2 plane */
|
|
+ DRM_FORMAT_NV42, /* yvu444_8bit linear mode, 2 plane */
|
|
+ DRM_FORMAT_NV15, /* yuv420_10bit linear mode, 2 plane, no padding */
|
|
+ DRM_FORMAT_YVYU, /* yuv422_8bit[YVYU] linear mode */
|
|
+ DRM_FORMAT_VYUY, /* yuv422_8bit[VYUY] linear mode */
|
|
+ DRM_FORMAT_YUYV, /* yuv422_8bit[YUYV] linear mode */
|
|
+ DRM_FORMAT_UYVY, /* yuv422_8bit[UYVY] linear mode */
|
|
+};
|
|
+
|
|
static const uint32_t formats_rk356x_esmart[] = {
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
@@ -234,6 +256,186 @@ static const struct vop2_win_data rk3568_vop_win_data[] = {
|
|
},
|
|
};
|
|
|
|
+static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
|
|
+ {
|
|
+ .id = 0,
|
|
+ .feature = VOP_FEATURE_OUTPUT_10BIT,
|
|
+ .gamma_lut_len = 1024,
|
|
+ .cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
|
|
+ .max_output = { 4096, 2304 },
|
|
+ /* hdr2sdr sdr2hdr hdr2hdr sdr2sdr */
|
|
+ .pre_scan_max_dly = { 76, 65, 65, 54 },
|
|
+ .offset = 0xc00,
|
|
+ }, {
|
|
+ .id = 1,
|
|
+ .feature = VOP_FEATURE_OUTPUT_10BIT,
|
|
+ .gamma_lut_len = 1024,
|
|
+ .cubic_lut_len = 729, /* 9x9x9 */
|
|
+ .max_output = { 4096, 2304 },
|
|
+ .pre_scan_max_dly = { 76, 65, 65, 54 },
|
|
+ .offset = 0xd00,
|
|
+ }, {
|
|
+ .id = 2,
|
|
+ .feature = VOP_FEATURE_OUTPUT_10BIT,
|
|
+ .gamma_lut_len = 1024,
|
|
+ .cubic_lut_len = 17 * 17 * 17, /* 17x17x17 */
|
|
+ .max_output = { 4096, 2304 },
|
|
+ .pre_scan_max_dly = { 52, 52, 52, 52 },
|
|
+ .offset = 0xe00,
|
|
+ }, {
|
|
+ .id = 3,
|
|
+ .gamma_lut_len = 1024,
|
|
+ .max_output = { 2048, 1536 },
|
|
+ .pre_scan_max_dly = { 52, 52, 52, 52 },
|
|
+ .offset = 0xf00,
|
|
+ },
|
|
+};
|
|
+
|
|
+/*
|
|
+ * rk3588 vop with 4 cluster, 4 esmart win.
|
|
+ * Every cluster can work as 4K win or split into two win.
|
|
+ * All win in cluster support AFBCD.
|
|
+ *
|
|
+ * Every esmart win and smart win support 4 Multi-region.
|
|
+ *
|
|
+ * Scale filter mode:
|
|
+ *
|
|
+ * * Cluster: bicubic for horizontal scale up, others use bilinear
|
|
+ * * ESmart:
|
|
+ * * nearest-neighbor/bilinear/bicubic for scale up
|
|
+ * * nearest-neighbor/bilinear/average for scale down
|
|
+ *
|
|
+ * AXI Read ID assignment:
|
|
+ * Two AXI bus:
|
|
+ * AXI0 is a read/write bus with a higher performance.
|
|
+ * AXI1 is a read only bus.
|
|
+ *
|
|
+ * Every window on a AXI bus must assigned two unique
|
|
+ * read id(yrgb_id/uv_id, valid id are 0x1~0xe).
|
|
+ *
|
|
+ * AXI0:
|
|
+ * Cluster0/1, Esmart0/1, WriteBack
|
|
+ *
|
|
+ * AXI 1:
|
|
+ * Cluster2/3, Esmart2/3
|
|
+ *
|
|
+ */
|
|
+static const struct vop2_win_data rk3588_vop_win_data[] = {
|
|
+ {
|
|
+ .name = "Cluster0-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_CLUSTER0,
|
|
+ .base = 0x1000,
|
|
+ .formats = formats_cluster,
|
|
+ .nformats = ARRAY_SIZE(formats_cluster),
|
|
+ .format_modifiers = format_modifiers_afbc,
|
|
+ .layer_sel_id = 0,
|
|
+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
|
+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
|
+ .max_upscale_factor = 4,
|
|
+ .max_downscale_factor = 4,
|
|
+ .dly = { 4, 26, 29 },
|
|
+ .type = DRM_PLANE_TYPE_PRIMARY,
|
|
+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
|
|
+ }, {
|
|
+ .name = "Cluster1-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_CLUSTER1,
|
|
+ .base = 0x1200,
|
|
+ .formats = formats_cluster,
|
|
+ .nformats = ARRAY_SIZE(formats_cluster),
|
|
+ .format_modifiers = format_modifiers_afbc,
|
|
+ .layer_sel_id = 1,
|
|
+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
|
+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
|
+ .type = DRM_PLANE_TYPE_PRIMARY,
|
|
+ .max_upscale_factor = 4,
|
|
+ .max_downscale_factor = 4,
|
|
+ .dly = { 4, 26, 29 },
|
|
+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
|
|
+ }, {
|
|
+ .name = "Cluster2-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_CLUSTER2,
|
|
+ .base = 0x1400,
|
|
+ .formats = formats_cluster,
|
|
+ .nformats = ARRAY_SIZE(formats_cluster),
|
|
+ .format_modifiers = format_modifiers_afbc,
|
|
+ .layer_sel_id = 4,
|
|
+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
|
+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
|
+ .type = DRM_PLANE_TYPE_PRIMARY,
|
|
+ .max_upscale_factor = 4,
|
|
+ .max_downscale_factor = 4,
|
|
+ .dly = { 4, 26, 29 },
|
|
+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
|
|
+ }, {
|
|
+ .name = "Cluster3-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_CLUSTER3,
|
|
+ .base = 0x1600,
|
|
+ .formats = formats_cluster,
|
|
+ .nformats = ARRAY_SIZE(formats_cluster),
|
|
+ .format_modifiers = format_modifiers_afbc,
|
|
+ .layer_sel_id = 5,
|
|
+ .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
|
+ DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
|
+ .type = DRM_PLANE_TYPE_PRIMARY,
|
|
+ .max_upscale_factor = 4,
|
|
+ .max_downscale_factor = 4,
|
|
+ .dly = { 4, 26, 29 },
|
|
+ .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
|
|
+ }, {
|
|
+ .name = "Esmart0-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_ESMART0,
|
|
+ .formats = formats_esmart,
|
|
+ .nformats = ARRAY_SIZE(formats_esmart),
|
|
+ .format_modifiers = format_modifiers,
|
|
+ .base = 0x1800,
|
|
+ .layer_sel_id = 2,
|
|
+ .supported_rotations = DRM_MODE_REFLECT_Y,
|
|
+ .type = DRM_PLANE_TYPE_OVERLAY,
|
|
+ .max_upscale_factor = 8,
|
|
+ .max_downscale_factor = 8,
|
|
+ .dly = { 23, 45, 48 },
|
|
+ }, {
|
|
+ .name = "Esmart1-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_ESMART1,
|
|
+ .formats = formats_esmart,
|
|
+ .nformats = ARRAY_SIZE(formats_esmart),
|
|
+ .format_modifiers = format_modifiers,
|
|
+ .base = 0x1a00,
|
|
+ .layer_sel_id = 3,
|
|
+ .supported_rotations = DRM_MODE_REFLECT_Y,
|
|
+ .type = DRM_PLANE_TYPE_OVERLAY,
|
|
+ .max_upscale_factor = 8,
|
|
+ .max_downscale_factor = 8,
|
|
+ .dly = { 23, 45, 48 },
|
|
+ }, {
|
|
+ .name = "Esmart2-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_ESMART2,
|
|
+ .base = 0x1c00,
|
|
+ .formats = formats_esmart,
|
|
+ .nformats = ARRAY_SIZE(formats_esmart),
|
|
+ .format_modifiers = format_modifiers,
|
|
+ .layer_sel_id = 6,
|
|
+ .supported_rotations = DRM_MODE_REFLECT_Y,
|
|
+ .type = DRM_PLANE_TYPE_OVERLAY,
|
|
+ .max_upscale_factor = 8,
|
|
+ .max_downscale_factor = 8,
|
|
+ .dly = { 23, 45, 48 },
|
|
+ }, {
|
|
+ .name = "Esmart3-win0",
|
|
+ .phys_id = ROCKCHIP_VOP2_ESMART3,
|
|
+ .formats = formats_esmart,
|
|
+ .nformats = ARRAY_SIZE(formats_esmart),
|
|
+ .format_modifiers = format_modifiers,
|
|
+ .base = 0x1e00,
|
|
+ .layer_sel_id = 7,
|
|
+ .supported_rotations = DRM_MODE_REFLECT_Y,
|
|
+ .type = DRM_PLANE_TYPE_OVERLAY,
|
|
+ .max_upscale_factor = 8,
|
|
+ .max_downscale_factor = 8,
|
|
+ .dly = { 23, 45, 48 },
|
|
+ },
|
|
+};
|
|
+
|
|
static const struct vop2_data rk3566_vop = {
|
|
.nr_vps = 3,
|
|
.max_input = { 4096, 2304 },
|
|
@@ -254,6 +456,16 @@ static const struct vop2_data rk3568_vop = {
|
|
.soc_id = 3568,
|
|
};
|
|
|
|
+static const struct vop2_data rk3588_vop = {
|
|
+ .nr_vps = 4,
|
|
+ .max_input = { 4096, 4320 },
|
|
+ .max_output = { 4096, 4320 },
|
|
+ .vp = rk3588_vop_video_ports,
|
|
+ .win = rk3588_vop_win_data,
|
|
+ .win_size = ARRAY_SIZE(rk3588_vop_win_data),
|
|
+ .soc_id = 3588,
|
|
+};
|
|
+
|
|
static const struct of_device_id vop2_dt_match[] = {
|
|
{
|
|
.compatible = "rockchip,rk3566-vop",
|
|
@@ -261,6 +473,9 @@ static const struct of_device_id vop2_dt_match[] = {
|
|
}, {
|
|
.compatible = "rockchip,rk3568-vop",
|
|
.data = &rk3568_vop,
|
|
+ }, {
|
|
+ .compatible = "rockchip,rk3588-vop",
|
|
+ .data = &rk3588_vop
|
|
}, {
|
|
},
|
|
};
|
|
diff --git a/include/dt-bindings/soc/rockchip,vop2.h b/include/dt-bindings/soc/rockchip,vop2.h
|
|
index 6e66a802b96a..668f199df9f0 100644
|
|
--- a/include/dt-bindings/soc/rockchip,vop2.h
|
|
+++ b/include/dt-bindings/soc/rockchip,vop2.h
|
|
@@ -10,5 +10,9 @@
|
|
#define ROCKCHIP_VOP2_EP_LVDS0 5
|
|
#define ROCKCHIP_VOP2_EP_MIPI1 6
|
|
#define ROCKCHIP_VOP2_EP_LVDS1 7
|
|
+#define ROCKCHIP_VOP2_EP_HDMI1 8
|
|
+#define ROCKCHIP_VOP2_EP_EDP1 9
|
|
+#define ROCKCHIP_VOP2_EP_DP0 10
|
|
+#define ROCKCHIP_VOP2_EP_DP1 11
|
|
|
|
#endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Tue, 7 Nov 2023 15:59:00 +0800
|
|
Subject: drm/rockchip: vop2: Add debugfs support
|
|
|
|
/sys/kernel/debug/dri/vop2/summary: dump vop display state
|
|
/sys/kernel/debug/dri/vop2/regs: dump whole vop registers
|
|
/sys/kernel/debug/dri/vop2/active_regs: only dump the registers of
|
|
actived modules
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 398 ++++++++++
|
|
1 file changed, 398 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
index bf12b6af14cf..49904f19b7cd 100644
|
|
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
|
@@ -27,6 +27,7 @@
|
|
#include <drm/drm_debugfs.h>
|
|
#include <drm/drm_flip_work.h>
|
|
#include <drm/drm_framebuffer.h>
|
|
+#include <drm/drm_gem_framebuffer_helper.h>
|
|
#include <drm/drm_probe_helper.h>
|
|
#include <drm/drm_vblank.h>
|
|
|
|
@@ -188,6 +189,7 @@ struct vop2 {
|
|
*/
|
|
u32 registered_num_wins;
|
|
|
|
+ struct resource *res;
|
|
void __iomem *regs;
|
|
struct regmap *map;
|
|
|
|
@@ -229,6 +231,44 @@ struct vop2 {
|
|
#define vop2_output_if_is_lvds(x) (x == ROCKCHIP_VOP2_EP_LVDS0 || x == ROCKCHIP_VOP2_EP_LVDS1)
|
|
#define vop2_output_if_is_dpi(x) (x == ROCKCHIP_VOP2_EP_RGB0)
|
|
|
|
+struct vop2_regs_dump {
|
|
+ const char *name;
|
|
+ u32 base;
|
|
+ u32 en_reg;
|
|
+ u32 en_val;
|
|
+ u32 en_mask;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * bus-format types.
|
|
+ */
|
|
+struct drm_bus_format_enum_list {
|
|
+ int type;
|
|
+ const char *name;
|
|
+};
|
|
+
|
|
+static const struct drm_bus_format_enum_list drm_bus_format_enum_list[] = {
|
|
+ { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
|
|
+ { MEDIA_BUS_FMT_RGB565_1X16, "RGB565_1X16" },
|
|
+ { MEDIA_BUS_FMT_RGB666_1X18, "RGB666_1X18" },
|
|
+ { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, "RGB666_1X24_CPADHI" },
|
|
+ { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, "RGB666_1X7X3_SPWG" },
|
|
+ { MEDIA_BUS_FMT_YUV8_1X24, "YUV8_1X24" },
|
|
+ { MEDIA_BUS_FMT_UYYVYY8_0_5X24, "UYYVYY8_0_5X24" },
|
|
+ { MEDIA_BUS_FMT_YUV10_1X30, "YUV10_1X30" },
|
|
+ { MEDIA_BUS_FMT_UYYVYY10_0_5X30, "UYYVYY10_0_5X30" },
|
|
+ { MEDIA_BUS_FMT_RGB888_3X8, "RGB888_3X8" },
|
|
+ { MEDIA_BUS_FMT_RGB888_1X24, "RGB888_1X24" },
|
|
+ { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, "RGB888_1X7X4_SPWG" },
|
|
+ { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, "RGB888_1X7X4_JEIDA" },
|
|
+ { MEDIA_BUS_FMT_UYVY8_2X8, "UYVY8_2X8" },
|
|
+ { MEDIA_BUS_FMT_YUYV8_1X16, "YUYV8_1X16" },
|
|
+ { MEDIA_BUS_FMT_UYVY8_1X16, "UYVY8_1X16" },
|
|
+ { MEDIA_BUS_FMT_RGB101010_1X30, "RGB101010_1X30" },
|
|
+ { MEDIA_BUS_FMT_YUYV10_1X20, "YUYV10_1X20" },
|
|
+};
|
|
+static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list)
|
|
+
|
|
static const struct regmap_config vop2_regmap_config;
|
|
|
|
static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
|
|
@@ -2445,6 +2485,362 @@ static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = {
|
|
.atomic_disable = vop2_crtc_atomic_disable,
|
|
};
|
|
|
|
+static void vop2_dump_connector_on_crtc(struct drm_crtc *crtc, struct seq_file *s)
|
|
+{
|
|
+ struct drm_connector_list_iter conn_iter;
|
|
+ struct drm_connector *connector;
|
|
+
|
|
+ drm_connector_list_iter_begin(crtc->dev, &conn_iter);
|
|
+ drm_for_each_connector_iter(connector, &conn_iter) {
|
|
+ if (crtc->state->connector_mask & drm_connector_mask(connector))
|
|
+ seq_printf(s, " Connector: %s\n", connector->name);
|
|
+
|
|
+ }
|
|
+ drm_connector_list_iter_end(&conn_iter);
|
|
+}
|
|
+
|
|
+static int vop2_plane_state_dump(struct seq_file *s, struct drm_plane *plane)
|
|
+{
|
|
+ struct vop2_win *win = to_vop2_win(plane);
|
|
+ struct drm_plane_state *pstate = plane->state;
|
|
+ struct drm_rect *src, *dst;
|
|
+ struct drm_framebuffer *fb;;
|
|
+ struct drm_gem_object *obj;
|
|
+ struct rockchip_gem_object *rk_obj;
|
|
+ bool xmirror;
|
|
+ bool ymirror;
|
|
+ bool rotate_270;
|
|
+ bool rotate_90;
|
|
+ dma_addr_t fb_addr;
|
|
+ int i;
|
|
+
|
|
+ seq_printf(s, " %s: %s\n", win->data->name, pstate->crtc ? "ACTIVE" : "DISABLED");
|
|
+ if (!pstate || !pstate->fb)
|
|
+ return 0;
|
|
+
|
|
+ fb = pstate->fb;
|
|
+ src = &pstate->src;
|
|
+ dst = &pstate->dst;
|
|
+ xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false;
|
|
+ ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false;
|
|
+ rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
|
|
+ rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
|
|
+
|
|
+ seq_printf(s, "\twin_id: %d\n", win->win_id);
|
|
+
|
|
+ seq_printf(s, "\tformat: %p4cc%s glb_alpha[0x%x]\n",
|
|
+ &fb->format->format,
|
|
+ drm_is_afbc(fb->modifier) ? "[AFBC]" : "",
|
|
+ pstate->alpha >> 8);
|
|
+ seq_printf(s, "\trotate: xmirror: %d ymirror: %d rotate_90: %d rotate_270: %d\n",
|
|
+ xmirror, ymirror, rotate_90, rotate_270);
|
|
+ seq_printf(s, "\tzpos: %d\n", pstate->normalized_zpos);
|
|
+ seq_printf(s, "\tsrc: pos[%d, %d] rect[%d x %d]\n", src->x1 >> 16,
|
|
+ src->y1 >> 16, drm_rect_width(src) >> 16,
|
|
+ drm_rect_height(src) >> 16);
|
|
+ seq_printf(s, "\tdst: pos[%d, %d] rect[%d x %d]\n", dst->x1, dst->y1,
|
|
+ drm_rect_width(dst), drm_rect_height(dst));
|
|
+
|
|
+ for (i = 0; i < fb->format->num_planes; i++) {
|
|
+ obj = fb->obj[0];
|
|
+ rk_obj = to_rockchip_obj(obj);
|
|
+ fb_addr = rk_obj->dma_addr + fb->offsets[0];
|
|
+
|
|
+ seq_printf(s, "\tbuf[%d]: addr: %pad pitch: %d offset: %d\n",
|
|
+ i, &fb_addr, fb->pitches[i], fb->offsets[i]);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vop2_crtc_state_dump(struct drm_crtc *crtc, struct seq_file *s)
|
|
+{
|
|
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
|
+ struct drm_crtc_state *cstate = crtc->state;
|
|
+ struct rockchip_crtc_state *vcstate;
|
|
+ struct drm_display_mode *mode;
|
|
+ struct drm_plane *plane;
|
|
+ bool interlaced;
|
|
+
|
|
+ seq_printf(s, "Video Port%d: %s\n", vp->id, !cstate ? "DISABLED": cstate->active ? "ACTIVE" : "DISABLED");
|
|
+
|
|
+ if (!cstate || !cstate->active)
|
|
+ return 0;
|
|
+
|
|
+ mode = &crtc->state->adjusted_mode;
|
|
+ vcstate = to_rockchip_crtc_state(cstate);
|
|
+ interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
|
|
+
|
|
+ vop2_dump_connector_on_crtc(crtc, s);
|
|
+ seq_printf(s, "\tbus_format[%x]: %s\n", vcstate->bus_format,
|
|
+ drm_get_bus_format_name(vcstate->bus_format));
|
|
+ seq_printf(s, "\toutput_mode[%x]", vcstate->output_mode);
|
|
+ seq_printf(s, " color_space[%d]\n", vcstate->color_space);
|
|
+ seq_printf(s, " Display mode: %dx%d%s%d\n",
|
|
+ mode->hdisplay, mode->vdisplay, interlaced ? "i" : "p",
|
|
+ drm_mode_vrefresh(mode));
|
|
+ seq_printf(s, "\tclk[%d] real_clk[%d] type[%x] flag[%x]\n",
|
|
+ mode->clock, mode->crtc_clock, mode->type, mode->flags);
|
|
+ seq_printf(s, "\tH: %d %d %d %d\n", mode->hdisplay, mode->hsync_start,
|
|
+ mode->hsync_end, mode->htotal);
|
|
+ seq_printf(s, "\tV: %d %d %d %d\n", mode->vdisplay, mode->vsync_start,
|
|
+ mode->vsync_end, mode->vtotal);
|
|
+
|
|
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
|
|
+ vop2_plane_state_dump(s, plane);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vop2_summary_show(struct seq_file *s, void *data)
|
|
+{
|
|
+ struct drm_info_node *node = s->private;
|
|
+ struct drm_minor *minor = node->minor;
|
|
+ struct drm_device *drm_dev = minor->dev;
|
|
+ struct drm_crtc *crtc;
|
|
+
|
|
+ drm_modeset_lock_all(drm_dev);
|
|
+ drm_for_each_crtc(crtc, drm_dev) {
|
|
+ vop2_crtc_state_dump(crtc, s);
|
|
+ }
|
|
+ drm_modeset_unlock_all(drm_dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void vop2_regs_print(struct vop2 *vop2, struct seq_file *s, struct vop2_regs_dump *dump)
|
|
+{
|
|
+ resource_size_t start;
|
|
+ const int reg_num = 0x110 / 4;
|
|
+ u32 val;
|
|
+ int i;
|
|
+
|
|
+ if (dump->en_mask) {
|
|
+ val = vop2_readl(vop2, dump->base + dump->en_reg);
|
|
+ if ((val & dump->en_mask) != dump->en_val)
|
|
+ return;
|
|
+ }
|
|
+ seq_printf(s, "\n%s:\n", dump->name);
|
|
+
|
|
+ start = vop2->res->start + dump->base;
|
|
+ for (i = 0; i < reg_num;) {
|
|
+ seq_printf(s, "%08x: %08x %08x %08x %08x\n", (u32)start + i * 4,
|
|
+ vop2_readl(vop2, dump->base + (4 * i)),
|
|
+ vop2_readl(vop2, dump->base + (4 * (i + 1))),
|
|
+ vop2_readl(vop2, dump->base + (4 * (i + 2))),
|
|
+ vop2_readl(vop2, dump->base + (4 * (i + 3))));
|
|
+ i += 4;
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+static int vop2_regs_show(struct seq_file *s, void *arg)
|
|
+{
|
|
+ struct drm_info_node *node = s->private;
|
|
+ struct vop2 *vop2 = (struct vop2 *)node->info_ent->data;
|
|
+ struct drm_minor *minor = node->minor;
|
|
+ struct drm_device *drm_dev = minor->dev;
|
|
+
|
|
+ struct vop2_regs_dump dump;
|
|
+
|
|
+ drm_modeset_lock_all(drm_dev);
|
|
+
|
|
+ if (vop2->enable_count) {
|
|
+ dump.en_mask = 0;
|
|
+
|
|
+ dump.name = "SYS";
|
|
+ dump.base = RK3568_REG_CFG_DONE;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "OVL";
|
|
+ dump.base = RK3568_OVL_CTRL;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "VP0";
|
|
+ dump.base = 0x0c00;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "VP1";
|
|
+ dump.base = 0x0c00 + 0x100;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "VP2";
|
|
+ dump.base = 0x0c00 + 0x200;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ if (vop2->data->soc_id == 3588) {
|
|
+ dump.name = "VP3";
|
|
+ dump.base = 0x0c00 + 0x300;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ }
|
|
+ dump.name = "Cluster0";
|
|
+ dump.base = 0x1000;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Cluster1";
|
|
+ dump.base = 0x1000 + 0x200;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ if (vop2->data->soc_id == 3588) {
|
|
+ dump.name = "Cluster2";
|
|
+ dump.base = 0x1000 + 0x400;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Cluster3";
|
|
+ dump.base = 0x1000 + 0x600;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ }
|
|
+ dump.name = "Esmart0";
|
|
+ dump.base = 0x1000 + 0x800;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Esmart1";
|
|
+ dump.base = 0x1000 + 0xa00;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Esmart2";
|
|
+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
|
|
+ dump.name = "Smart0";
|
|
+ dump.base = 0x1000 + 0xc00;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Esmart3";
|
|
+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
|
|
+ dump.name = "Smart1";
|
|
+ dump.base = 0x1000 + 0xe00;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ } else {
|
|
+ seq_printf(s, "VOP disabled:\n");
|
|
+ }
|
|
+ drm_modeset_unlock_all(drm_dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vop2_active_regs_show(struct seq_file *s, void *data)
|
|
+{
|
|
+ struct drm_info_node *node = s->private;
|
|
+ struct vop2 *vop2 = (struct vop2 *)node->info_ent->data;
|
|
+ struct drm_minor *minor = node->minor;
|
|
+ struct drm_device *drm_dev = minor->dev;
|
|
+
|
|
+ struct vop2_regs_dump dump;
|
|
+
|
|
+ drm_modeset_lock_all(drm_dev);
|
|
+ if (vop2->enable_count) {
|
|
+ dump.en_mask = 0;
|
|
+
|
|
+ dump.name = "SYS";
|
|
+ dump.base = RK3568_REG_CFG_DONE;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "OVL";
|
|
+ dump.base = RK3568_OVL_CTRL;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "VP0";
|
|
+ dump.base = 0x0c00;
|
|
+ dump.en_mask = RK3568_VP_DSP_CTRL__STANDBY;
|
|
+ dump.en_reg = RK3568_VP_DSP_CTRL;
|
|
+ dump.en_val = 0;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "VP1";
|
|
+ dump.base = 0x0c00 + 0x100;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "VP2";
|
|
+ dump.base = 0x0c00 + 0x200;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ if (vop2->data->soc_id == 3588) {
|
|
+ dump.name = "VP3";
|
|
+ dump.base = 0x0c00 + 0x300;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ }
|
|
+
|
|
+ dump.en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN;
|
|
+ dump.en_reg = RK3568_CLUSTER_WIN_CTRL0;
|
|
+ dump.en_val = 1;
|
|
+
|
|
+ dump.name = "Cluster0";
|
|
+ dump.base = 0x1000;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Cluster1";
|
|
+ dump.base = 0x1000 + 0x200;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ if (vop2->data->soc_id == 3588) {
|
|
+ dump.name = "Cluster2";
|
|
+ dump.base = 0x1000 + 0x400;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Cluster3";
|
|
+ dump.base = 0x1000 + 0x600;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ }
|
|
+
|
|
+ dump.name = "Esmart0";
|
|
+ dump.base = 0x1000 + 0x800;
|
|
+ dump.en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN;
|
|
+ dump.en_reg = RK3568_SMART_REGION0_CTRL;
|
|
+ dump.en_val = 1;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Esmart1";
|
|
+ dump.base = 0x1000 + 0xa00;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Esmart2";
|
|
+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
|
|
+ dump.name = "Smart0";
|
|
+ dump.base = 0x1000 + 0xc00;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+
|
|
+ dump.name = "Esmart3";
|
|
+ if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
|
|
+ dump.name = "Smart1";
|
|
+ dump.base = 0x1000 + 0xe00;
|
|
+ vop2_regs_print(vop2, s, &dump);
|
|
+ } else {
|
|
+ seq_printf(s, "VOP disabled:\n");
|
|
+ }
|
|
+ drm_modeset_unlock_all(drm_dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct drm_info_list vop2_debugfs_list[] = {
|
|
+ { "summary", vop2_summary_show, 0, NULL },
|
|
+ { "active_regs", vop2_active_regs_show, 0, NULL },
|
|
+ { "regs", vop2_regs_show, 0, NULL },
|
|
+};
|
|
+
|
|
+static void vop2_debugfs_init(struct vop2 *vop2, struct drm_minor *minor)
|
|
+{
|
|
+ struct dentry *root;
|
|
+ unsigned int i;
|
|
+
|
|
+ root = debugfs_create_dir("vop2", minor->debugfs_root);
|
|
+ if (!IS_ERR(root)) {
|
|
+ for (i = 0; i < ARRAY_SIZE(vop2_debugfs_list); i++)
|
|
+ vop2_debugfs_list[i].data = vop2;
|
|
+
|
|
+ drm_debugfs_create_files(vop2_debugfs_list,
|
|
+ ARRAY_SIZE(vop2_debugfs_list),
|
|
+ root, minor);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int vop2_crtc_late_register(struct drm_crtc *crtc)
|
|
+{
|
|
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
|
+ struct vop2 *vop2 = vp->vop2;
|
|
+
|
|
+ if (drm_crtc_index(crtc) == 0)
|
|
+ vop2_debugfs_init(vop2, crtc->dev->primary);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
|
|
{
|
|
struct rockchip_crtc_state *vcstate;
|
|
@@ -2494,6 +2890,7 @@ static const struct drm_crtc_funcs vop2_crtc_funcs = {
|
|
.atomic_destroy_state = vop2_crtc_destroy_state,
|
|
.enable_vblank = vop2_crtc_enable_vblank,
|
|
.disable_vblank = vop2_crtc_disable_vblank,
|
|
+ .late_register = vop2_crtc_late_register,
|
|
};
|
|
|
|
static irqreturn_t vop2_isr(int irq, void *data)
|
|
@@ -3098,6 +3495,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ vop2->res = res;
|
|
vop2->regs = devm_ioremap_resource(dev, res);
|
|
if (IS_ERR(vop2->regs))
|
|
return PTR_ERR(vop2->regs);
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Fri, 10 Nov 2023 18:55:02 +0800
|
|
Subject: arm64: dts: rockchip: Add vop on rk3588
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 96 ++++++++++
|
|
1 file changed, 96 insertions(+)
|
|
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
|
|
index 508b035c0a7f..670d367fc6fc 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
|
|
@@ -804,6 +804,11 @@ trip-point-2 {
|
|
};
|
|
};
|
|
|
|
+ display_subsystem: display-subsystem {
|
|
+ compatible = "rockchip,display-subsystem";
|
|
+ ports = <&vop_out>;
|
|
+ };
|
|
+
|
|
timer {
|
|
compatible = "arm,armv8-timer";
|
|
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH 0>,
|
|
@@ -948,6 +953,16 @@ bigcore1_grf: syscon@fd592000 {
|
|
reg = <0x0 0xfd592000 0x0 0x100>;
|
|
};
|
|
|
|
+ vop_grf: syscon@fd5a4000 {
|
|
+ compatible = "rockchip,rk3588-vop-grf", "syscon";
|
|
+ reg = <0x0 0xfd5a4000 0x0 0x2000>;
|
|
+ };
|
|
+
|
|
+ vo1_grf: syscon@fd5a8000 {
|
|
+ compatible = "rockchip,rk3588-vo-grf", "syscon";
|
|
+ reg = <0x0 0xfd5a8000 0x0 0x100>;
|
|
+ };
|
|
+
|
|
php_grf: syscon@fd5b0000 {
|
|
compatible = "rockchip,rk3588-php-grf", "syscon";
|
|
reg = <0x0 0xfd5b0000 0x0 0x1000>;
|
|
@@ -1109,6 +1124,87 @@ i2c0: i2c@fd880000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ vop: vop@fdd90000 {
|
|
+ compatible = "rockchip,rk3588-vop";
|
|
+ reg = <0x0 0xfdd90000 0x0 0x4200>, <0x0 0xfdd95000 0x0 0x1000>;
|
|
+ reg-names = "vop", "gamma_lut";
|
|
+ interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH 0>;
|
|
+ clocks = <&cru ACLK_VOP>,
|
|
+ <&cru HCLK_VOP>,
|
|
+ <&cru DCLK_VOP0>,
|
|
+ <&cru DCLK_VOP1>,
|
|
+ <&cru DCLK_VOP2>,
|
|
+ <&cru DCLK_VOP3>,
|
|
+ <&cru PCLK_VOP_ROOT>;
|
|
+ clock-names = "aclk",
|
|
+ "hclk",
|
|
+ "dclk_vp0",
|
|
+ "dclk_vp1",
|
|
+ "dclk_vp2",
|
|
+ "dclk_vp3",
|
|
+ "pclk_vop";
|
|
+ resets = <&cru SRST_A_VOP>,
|
|
+ <&cru SRST_H_VOP>,
|
|
+ <&cru SRST_D_VOP0>,
|
|
+ <&cru SRST_D_VOP1>,
|
|
+ <&cru SRST_D_VOP2>,
|
|
+ <&cru SRST_D_VOP3>;
|
|
+ reset-names = "axi",
|
|
+ "ahb",
|
|
+ "dclk_vp0",
|
|
+ "dclk_vp1",
|
|
+ "dclk_vp2",
|
|
+ "dclk_vp3";
|
|
+ iommus = <&vop_mmu>;
|
|
+ power-domains = <&power RK3588_PD_VOP>;
|
|
+ rockchip,grf = <&sys_grf>;
|
|
+ rockchip,vop-grf = <&vop_grf>;
|
|
+ rockchip,vo1-grf = <&vo1_grf>;
|
|
+ rockchip,pmu = <&pmu>;
|
|
+
|
|
+ status = "disabled";
|
|
+ vop_out: ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ vp0: port@0 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0>;
|
|
+ };
|
|
+
|
|
+ vp1: port@1 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <1>;
|
|
+ };
|
|
+
|
|
+ vp2: port@2 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <2>;
|
|
+ };
|
|
+
|
|
+ vp3: port@3 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <3>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ vop_mmu: iommu@fdd97e00 {
|
|
+ compatible = "rockchip,rk3568-iommu";
|
|
+ reg = <0x0 0xfdd97e00 0x0 0x100>, <0x0 0xfdd97f00 0x0 0x100>;
|
|
+ interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH 0>;
|
|
+ interrupt-names = "vop_mmu";
|
|
+ clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
|
|
+ clock-names = "aclk", "iface";
|
|
+ #iommu-cells = <0>;
|
|
+ power-domains = <&power RK3588_PD_VOP>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
uart0: serial@fd890000 {
|
|
compatible = "rockchip,rk3588-uart", "snps,dw-apb-uart";
|
|
reg = <0x0 0xfd890000 0x0 0x100>;
|
|
--
|
|
Armbian
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Andy Yan <andy.yan@rock-chips.com>
|
|
Date: Fri, 10 Nov 2023 19:01:37 +0800
|
|
Subject: arm64: dts: rockchip: Enable hdmi display on rk3588-evb1
|
|
|
|
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
|
---
|
|
arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts | 49 ++++++
|
|
arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 74 ++++++++++
|
|
2 files changed, 123 insertions(+)
|
|
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts
|
|
index 99ed48cd24a7..50822c2def7d 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts
|
|
@@ -10,6 +10,7 @@
|
|
#include <dt-bindings/input/input.h>
|
|
#include <dt-bindings/pinctrl/rockchip.h>
|
|
#include <dt-bindings/usb/pd.h>
|
|
+#include <dt-bindings/soc/rockchip,vop2.h>
|
|
#include "rk3588.dtsi"
|
|
|
|
/ {
|
|
@@ -103,6 +104,17 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator {
|
|
vin-supply = <&avcc_1v8_s0>;
|
|
};
|
|
|
|
+ hdmi-con {
|
|
+ compatible = "hdmi-connector";
|
|
+ type = "a";
|
|
+
|
|
+ port {
|
|
+ hdmi_con_in: endpoint {
|
|
+ remote-endpoint = <&hdmi0_out_con>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
vcc12v_dcin: vcc12v-dcin-regulator {
|
|
compatible = "regulator-fixed";
|
|
regulator-name = "vcc12v_dcin";
|
|
@@ -230,6 +242,43 @@ &cpu_l3 {
|
|
mem-supply = <&vdd_cpu_lit_mem_s0>;
|
|
};
|
|
|
|
+&hdmi0 {
|
|
+ enable-gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_HIGH>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+
|
|
+&hdptxphy_hdmi0 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&vop_mmu {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&hdmi0_in {
|
|
+ hdmi0_in_vp0: endpoint {
|
|
+ remote-endpoint = <&vp0_out_hdmi0>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&hdmi0_out {
|
|
+ hdmi0_out_con: endpoint {
|
|
+ remote-endpoint = <&hdmi_con_in>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vop {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&vp0 {
|
|
+ vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
|
|
+ reg = <ROCKCHIP_VOP2_EP_HDMI0>;
|
|
+ remote-endpoint = <&hdmi0_in_vp0>;
|
|
+ };
|
|
+};
|
|
+
|
|
&gmac0 {
|
|
clock_in_out = "output";
|
|
phy-handle = <&rgmii_phy>;
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
|
|
index 670d367fc6fc..7f59ba2f2126 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi
|
|
@@ -953,6 +953,59 @@ bigcore1_grf: syscon@fd592000 {
|
|
reg = <0x0 0xfd592000 0x0 0x100>;
|
|
};
|
|
|
|
+ hdptxphy0_grf: syscon@fd5e0000 {
|
|
+ compatible = "rockchip,rk3588-hdptxphy-grf", "syscon";
|
|
+ reg = <0x0 0xfd5e0000 0x0 0x100>;
|
|
+ };
|
|
+
|
|
+ hdmi0: hdmi@fde80000 {
|
|
+ compatible = "rockchip,rk3588-dw-hdmi";
|
|
+ reg = <0x0 0xfde80000 0x0 0x20000>;
|
|
+ interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH 0>,
|
|
+ <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>,
|
|
+ <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH 0>,
|
|
+ <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH 0>,
|
|
+ <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH 0>;
|
|
+ clocks = <&cru PCLK_HDMITX0>,
|
|
+ <&cru CLK_HDMIHDP0>,
|
|
+ <&cru CLK_HDMITX0_EARC>,
|
|
+ <&cru CLK_HDMITX0_REF>,
|
|
+ <&cru MCLK_I2S5_8CH_TX>,
|
|
+ <&cru HCLK_VO1>;
|
|
+ clock-names = "pclk",
|
|
+ "hpd",
|
|
+ "earc",
|
|
+ "hdmitx_ref",
|
|
+ "aud",
|
|
+ "hclk_vo1";
|
|
+ resets = <&cru SRST_HDMITX0_REF>, <&cru SRST_HDMIHDP0>;
|
|
+ reset-names = "ref", "hdp";
|
|
+ power-domains = <&power RK3588_PD_VO1>;
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd &hdmim0_tx0_scl &hdmim0_tx0_sda>;
|
|
+ reg-io-width = <4>;
|
|
+ rockchip,grf = <&sys_grf>;
|
|
+ rockchip,vo1_grf = <&vo1_grf>;
|
|
+ phys = <&hdptxphy_hdmi0>;
|
|
+ phy-names = "hdmi";
|
|
+ #sound-dai-cells = <0>;
|
|
+ status = "disabled";
|
|
+
|
|
+ ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ hdmi0_in: port@0 {
|
|
+ reg = <0>;
|
|
+ };
|
|
+
|
|
+ hdmi0_out: port@1 {
|
|
+ reg = <1>;
|
|
+ };
|
|
+
|
|
+ };
|
|
+ };
|
|
+
|
|
vop_grf: syscon@fd5a4000 {
|
|
compatible = "rockchip,rk3588-vop-grf", "syscon";
|
|
reg = <0x0 0xfd5a4000 0x0 0x2000>;
|
|
@@ -2909,6 +2962,27 @@ usbdp_phy0_u3: usb3-port {
|
|
};
|
|
};
|
|
|
|
+ hdptxphy_hdmi0: hdmiphy@fed60000 {
|
|
+ compatible = "rockchip,rk3588-hdptx-phy-hdmi";
|
|
+ reg = <0x0 0xfed60000 0x0 0x2000>;
|
|
+ clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>;
|
|
+ clock-names = "ref", "apb";
|
|
+ resets = <&cru SRST_HDPTX0>, <&cru SRST_P_HDPTX0>,
|
|
+ <&cru SRST_HDPTX0_INIT>, <&cru SRST_HDPTX0_CMN>,
|
|
+ <&cru SRST_HDPTX0_LANE>, <&cru SRST_HDPTX0_ROPLL>,
|
|
+ <&cru SRST_HDPTX0_LCPLL>;
|
|
+ reset-names = "phy", "apb", "init", "cmn", "lane", "ropll",
|
|
+ "lcpll";
|
|
+ rockchip,grf = <&hdptxphy0_grf>;
|
|
+ #phy-cells = <0>;
|
|
+ status = "disabled";
|
|
+
|
|
+ hdptxphy_hdmi_clk0: clk-port {
|
|
+ #clock-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+ };
|
|
+
|
|
combphy0_ps: phy@fee00000 {
|
|
compatible = "rockchip,rk3588-naneng-combphy";
|
|
reg = <0x0 0xfee00000 0x0 0x100>;
|
|
--
|
|
Armbian
|
|
|