834 lines
23 KiB
Diff
834 lines
23 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: 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 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
|
|
|