From patchwork Tue Oct 29 09:54:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854587 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 06243D2AB12 for ; Tue, 29 Oct 2024 09:56:09 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E81F010E606; Tue, 29 Oct 2024 09:56:06 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="UrS1L6mG"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.5]) by gabe.freedesktop.org (Postfix) with ESMTP id 0AC6410E5FB for ; Tue, 29 Oct 2024 09:55:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=p+Qil pSAChXt7p9zyPFIHyqGwnVfC76EJbML+X3PUu0=; b=UrS1L6mGNDpi2c6xLhSIw HwsAIwBFG+aBoMAwsRfVwvDpLw74c9xyJ50aFnedB/OXlSfaAnFtlQAVmcE2a8Qy MyzGqf+Qq2452SlJulNW9npSu8u6V1c6VDO8OI87dHgtE1eS/ZydL3Pm/tsNX3zU plizn2QSo8w7prRdHSmvbA= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S3; Tue, 29 Oct 2024 17:55:20 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 01/14] drm/rockchip: vop2: Add debugfs support Date: Tue, 29 Oct 2024 17:54:54 +0800 Message-ID: <20241029095513.391006-2-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S3 X-Coremail-Antispam: 1Uf129KBjvAXoWfJw18WFy7GF1fKryDAF1xAFb_yoW8Aw4fto ZFgFsaqr1xtFy0qrW0kF48tFy29F10vFn2kryjkF98Z3ZxW345KrW8GrnIvFsxArWFkFy8 Zanaq3WfXryxJayrn29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxUFuWLUUUUU X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiqQyHXmcgr44a3QABsc X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan /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 activated modules Signed-off-by: Andy Yan Reviewed-by: Sascha Hauer Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v1) drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 260 +++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 11 + drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 191 ++++++++++++++ 3 files changed, 462 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 9873172e3fd33..cd861c022a66c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -24,9 +24,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -186,6 +188,7 @@ struct vop2 { */ u32 registered_num_wins; + struct resource *res; void __iomem *regs; struct regmap *map; @@ -237,6 +240,37 @@ struct vop2 { #define vop2_output_if_is_dpi(x) ((x) == ROCKCHIP_VOP2_EP_RGB0) + +/* + * 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) @@ -2513,6 +2547,230 @@ 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 ? + "DISABLED" : 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[i]; + rk_obj = to_rockchip_obj(obj); + fb_addr = rk_obj->dma_addr + fb->offsets[i]; + + 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, + const struct vop2_regs_dump *dump, bool active_only) +{ + resource_size_t start; + u32 val; + int i; + + if (dump->en_mask && active_only) { + 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 < dump->size >> 2; i += 4) { + 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)))); + } +} + +static void __vop2_regs_dump(struct seq_file *s, bool active_only) +{ + struct drm_info_node *node = s->private; + struct vop2 *vop2 = node->info_ent->data; + struct drm_minor *minor = node->minor; + struct drm_device *drm_dev = minor->dev; + const struct vop2_regs_dump *dump; + unsigned int i; + + drm_modeset_lock_all(drm_dev); + + regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register); + + if (vop2->enable_count) { + for (i = 0; i < vop2->data->regs_dump_size; i++) { + dump = &vop2->data->regs_dump[i]; + vop2_regs_print(vop2, s, dump, active_only); + } + } else { + seq_printf(s, "VOP disabled\n"); + } + drm_modeset_unlock_all(drm_dev); + +} + +static int vop2_regs_show(struct seq_file *s, void *arg) +{ + __vop2_regs_dump(s, false); + + return 0; +} + +static int vop2_active_regs_show(struct seq_file *s, void *data) +{ + __vop2_regs_dump(s, true); + + 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; @@ -2562,6 +2820,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) @@ -3106,6 +3365,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); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 615a16196aff6..59cd6b933bfba 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -122,6 +122,15 @@ enum vop2_win_regs { VOP2_WIN_MAX_REG, }; +struct vop2_regs_dump { + const char *name; + u32 base; + u32 size; + u32 en_reg; + u32 en_val; + u32 en_mask; +}; + struct vop2_win_data { const char *name; unsigned int phys_id; @@ -160,10 +169,12 @@ struct vop2_data { u64 feature; const struct vop2_win_data *win; const struct vop2_video_port_data *vp; + const struct vop2_regs_dump *regs_dump; struct vop_rect max_input; struct vop_rect max_output; unsigned int win_size; + unsigned int regs_dump_size; unsigned int soc_id; }; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 18efb3fe1c000..8ff0bd528d65d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -258,6 +258,88 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { }, }; +static const struct vop2_regs_dump rk3568_regs_dump[] = { + { + .name = "SYS", + .base = RK3568_REG_CFG_DONE, + .size = 0x100, + .en_reg = 0, + .en_val = 0, + .en_mask = 0 + }, { + .name = "OVL", + .base = RK3568_OVL_CTRL, + .size = 0x100, + .en_reg = 0, + .en_val = 0, + .en_mask = 0, + }, { + .name = "VP0", + .base = RK3568_VP0_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "VP1", + .base = RK3568_VP1_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "VP2", + .base = RK3568_VP2_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + + }, { + .name = "Cluster0", + .base = RK3568_CLUSTER0_CTRL_BASE, + .size = 0x110, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Cluster1", + .base = RK3568_CLUSTER1_CTRL_BASE, + .size = 0x110, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Esmart0", + .base = RK3568_ESMART0_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Esmart1", + .base = RK3568_ESMART1_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Smart0", + .base = RK3568_SMART0_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Smart1", + .base = RK3568_SMART1_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, +}; + static const struct vop2_video_port_data rk3588_vop_video_ports[] = { { .id = 0, @@ -438,6 +520,109 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { }, }; +static const struct vop2_regs_dump rk3588_regs_dump[] = { + { + .name = "SYS", + .base = RK3568_REG_CFG_DONE, + .size = 0x100, + .en_reg = 0, + .en_val = 0, + .en_mask = 0 + }, { + .name = "OVL", + .base = RK3568_OVL_CTRL, + .size = 0x100, + .en_reg = 0, + .en_val = 0, + .en_mask = 0, + }, { + .name = "VP0", + .base = RK3568_VP0_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "VP1", + .base = RK3568_VP1_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "VP2", + .base = RK3568_VP2_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + + }, { + .name = "VP3", + .base = RK3588_VP3_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "Cluster0", + .base = RK3568_CLUSTER0_CTRL_BASE, + .size = 0x110, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Cluster1", + .base = RK3568_CLUSTER1_CTRL_BASE, + .size = 0x110, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Cluster2", + .base = RK3588_CLUSTER2_CTRL_BASE, + .size = 0x110, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Cluster3", + .base = RK3588_CLUSTER3_CTRL_BASE, + .size = 0x110, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Esmart0", + .base = RK3568_ESMART0_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Esmart1", + .base = RK3568_ESMART1_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Esmart2", + .base = RK3588_ESMART2_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Esmart3", + .base = RK3588_ESMART3_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, +}; + static const struct vop2_data rk3566_vop = { .feature = VOP2_FEATURE_HAS_SYS_GRF, .nr_vps = 3, @@ -446,6 +631,8 @@ static const struct vop2_data rk3566_vop = { .vp = rk3568_vop_video_ports, .win = rk3568_vop_win_data, .win_size = ARRAY_SIZE(rk3568_vop_win_data), + .regs_dump = rk3568_regs_dump, + .regs_dump_size = ARRAY_SIZE(rk3568_regs_dump), .soc_id = 3566, }; @@ -457,6 +644,8 @@ static const struct vop2_data rk3568_vop = { .vp = rk3568_vop_video_ports, .win = rk3568_vop_win_data, .win_size = ARRAY_SIZE(rk3568_vop_win_data), + .regs_dump = rk3568_regs_dump, + .regs_dump_size = ARRAY_SIZE(rk3568_regs_dump), .soc_id = 3568, }; @@ -469,6 +658,8 @@ static const struct vop2_data rk3588_vop = { .vp = rk3588_vop_video_ports, .win = rk3588_vop_win_data, .win_size = ARRAY_SIZE(rk3588_vop_win_data), + .regs_dump = rk3588_regs_dump, + .regs_dump_size = ARRAY_SIZE(rk3588_regs_dump), .soc_id = 3588, }; From patchwork Tue Oct 29 09:54:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854578 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BCFAFD2AB12 for ; Tue, 29 Oct 2024 09:55:38 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5739510E5FA; Tue, 29 Oct 2024 09:55:37 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="U1WnoWYN"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.3]) by gabe.freedesktop.org (Postfix) with ESMTP id 4193210E5FA for ; Tue, 29 Oct 2024 09:55:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=qsh1K mKsTwRgUaxttwXK875+A+NkuqnK07Vadhw2lcw=; b=U1WnoWYNsZNtS6yR2zcRY Gou9TXEAt8m+F1c85pGEQR22Xq53OL0FGikXDtMiVRT0aDmamfIGr//EFGAhZgON L79ladvNjLBr6oLrDbfnf44vzhd2PkZkNrXlneoe5+hD/5UV9bwJYMKID7ShFyXs ZUdbF/lKgLg7oJcquyG848= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S4; Tue, 29 Oct 2024 17:55:21 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 02/14] drm/rockchip: vop2: Fix cluster windows alpha ctrl registers offset Date: Tue, 29 Oct 2024 17:54:55 +0800 Message-ID: <20241029095513.391006-3-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S4 X-Coremail-Antispam: 1Uf129KBjvJXoW7AryUWryUZF1fKr1xWr4xtFb_yoW8tFyxpF n7Ar90qr47JFs0gw1xJF4DuryfKws2kFW7JF97K3Wagry3Kr9rC3Wq93WDCry5JFyUCr12 ka9xGrW7uF4jkr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jI5l8UUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMwqHXmcgqJmjwgAAs3 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan The phy_id of cluster windws are not increase one for each window. Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver") Signed-off-by: Andy Yan Tested-by: Derek Foreman Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- Changes in v4: - Fix some typo drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index cd861c022a66c..bff190151ae8c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2193,7 +2193,6 @@ static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id) static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win) { - u32 offset = (main_win->data->phys_id * 0x10); struct vop2_alpha_config alpha_config; struct vop2_alpha alpha; struct drm_plane_state *bottom_win_pstate; @@ -2201,6 +2200,7 @@ static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_wi u16 src_glb_alpha_val, dst_glb_alpha_val; bool premulti_en = false; bool swap = false; + u32 offset = 0; /* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */ bottom_win_pstate = main_win->base.state; @@ -2219,6 +2219,22 @@ static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_wi vop2_parse_alpha(&alpha_config, &alpha); alpha.src_color_ctrl.bits.src_dst_swap = swap; + + switch (main_win->data->phys_id) { + case ROCKCHIP_VOP2_CLUSTER0: + offset = 0x0; + break; + case ROCKCHIP_VOP2_CLUSTER1: + offset = 0x10; + break; + case ROCKCHIP_VOP2_CLUSTER2: + offset = 0x20; + break; + case ROCKCHIP_VOP2_CLUSTER3: + offset = 0x30; + break; + } + vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset, alpha.src_color_ctrl.val); vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset, From patchwork Tue Oct 29 09:54:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854586 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 855B1D2AB11 for ; Tue, 29 Oct 2024 09:56:09 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DC58610E604; Tue, 29 Oct 2024 09:56:06 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="nT1GAGRm"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.2]) by gabe.freedesktop.org (Postfix) with ESMTP id 9FDAB10E5FF for ; Tue, 29 Oct 2024 09:55:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=sWL+u A6N3RP7S0oEEy+dt5J028U96XG2qpaI3whbCC8=; b=nT1GAGRm3e1rS7G0nQxdk c12589OMffZqPCBHdrB63piwn1vO3q01+e6Y5o76j5mt75cxO1DDhI63vta2bqkI SNHF2pXbY+bwfkrbz9d595BqKvUtBiLptepisQ7O/p5qu+toYnxeaIwSl0LJe83k zkyqKB1cbZBVnTH2lu9/7Q= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S5; Tue, 29 Oct 2024 17:55:22 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 03/14] drm/rockchip: vop2: Fix the mixer alpha setup for layer 0 Date: Tue, 29 Oct 2024 17:54:56 +0800 Message-ID: <20241029095513.391006-4-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S5 X-Coremail-Antispam: 1Uf129KBjvJXoW7WrWDGF1UXryfGrWrXr4fXwb_yoW8Gr43pF s8uFWj9w40krsFqr1DJan7uF4Syan7Cay7Grs7J3W3X3W3KF9rCwnxWr98ArZ8JF4xWF4a krZrKr98Wa12vrJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jBD73UUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMwqHXmcgqJmjwgABs2 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan The alpha setup should start from the second layer, the current calculation starts incorrectly from the first layer, a negative offset will be obtained in the following formula: offset = (mixer_id + zpos - 1) * 0x10 Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver") Signed-off-by: Andy Yan Tested-by: Derek Foreman Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v1) drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index bff190151ae8c..c50d93df84046 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2282,6 +2282,12 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) struct vop2_win *win = to_vop2_win(plane); int zpos = plane->state->normalized_zpos; + /* + * Need to configure alpha from second layer. + */ + if (zpos == 0) + continue; + if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) premulti_en = 1; else From patchwork Tue Oct 29 09:54:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854582 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7CA53D2AB12 for ; Tue, 29 Oct 2024 09:55:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id AD23610E5FF; Tue, 29 Oct 2024 09:55:49 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="W0qonfrO"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.5]) by gabe.freedesktop.org (Postfix) with ESMTP id 1B3F910E5FB for ; Tue, 29 Oct 2024 09:55:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=ckN+C I+XvxtAc4aLpkYX8g6tnnWLc/g+v0ub9LUeR+c=; b=W0qonfrOL+NbdHPQ8X6c9 +RplHHZiTzZ2/IyVI30ClQ0uVBhaNDVzbCtGnZgaufUAhOlgG1JldzF+tj6EfRdt tMtpdP/UMuOBo+4CcbF2QJ0Q+swOh8mhIOXjTo3CL+N55IaYw+xJbqXFvSCV+Y3r bW+JnlMbaIto/56yaKZjC0= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S6; Tue, 29 Oct 2024 17:55:23 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 04/14] drm/rockchip: vop2: Fix the windows switch between different layers Date: Tue, 29 Oct 2024 17:54:57 +0800 Message-ID: <20241029095513.391006-5-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S6 X-Coremail-Antispam: 1Uf129KBjvJXoWxZw4fWF4DAFW7Gw15KryfWFg_yoW5ZFy3pF 15WrWjgw4UKFsIqr9rtr48uF4ayws7Gay7W3Z7tw1rGFyrtr1DJwn8Cr9ayryUGFn3uryY yr1j9r909FWqyr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jF2NtUUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMwqHXmcgqJmjwgACs1 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan Every layer of vop2 should bind a window, and we also need to make sure that this window is not used by other layer. 0x5 is a reserved layer sel value on rk3568, but it will select Cluster3 on rk3588, configure unused layers to 0x5 will lead alpha blending error on rk3588. When we bind a window from layerM to layerN, we move the old window on layerN to layerM. Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver") Signed-off-by: Andy Yan Tested-by: Derek Foreman Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v1) drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 38 +++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index c50d93df84046..4776a227e62c8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2364,7 +2364,9 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp) struct drm_plane *plane; u32 layer_sel = 0; u32 port_sel; - unsigned int nlayer, ofs; + u8 old_layer_id; + u8 layer_sel_id; + unsigned int ofs; u32 ovl_ctrl; int i; struct vop2_video_port *vp0 = &vop2->vps[0]; @@ -2408,9 +2410,28 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp) for (i = 0; i < vp->id; i++) ofs += vop2->vps[i].nlayers; - nlayer = 0; drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { struct vop2_win *win = to_vop2_win(plane); + struct vop2_win *old_win; + + /* + * Find the layer this win bind in old state. + */ + for (old_layer_id = 0; old_layer_id < vop2->data->win_size; old_layer_id++) { + layer_sel_id = (layer_sel >> (4 * old_layer_id)) & 0xf; + if (layer_sel_id == win->data->layer_sel_id) + break; + } + + /* + * Find the win bind to this layer in old state + */ + for (i = 0; i < vop2->data->win_size; i++) { + old_win = &vop2->win[i]; + layer_sel_id = (layer_sel >> (4 * (plane->state->normalized_zpos + ofs))) & 0xf; + if (layer_sel_id == old_win->data->layer_sel_id) + break; + } switch (win->data->phys_id) { case ROCKCHIP_VOP2_CLUSTER0: @@ -2459,13 +2480,12 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp) 0x7); layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, win->data->layer_sel_id); - nlayer++; - } - - /* configure unused layers to 0x5 (reserved) */ - for (; nlayer < vp->nlayers; nlayer++) { - layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7); - layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5); + /* + * When we bind a window from layerM to layerN, we also need to move the old + * window on layerN to layerM to avoid one window selected by two or more layers. + */ + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, 0x7); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, old_win->data->layer_sel_id); } vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); From patchwork Tue Oct 29 09:54:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854577 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D0F32D2AB11 for ; Tue, 29 Oct 2024 09:55:37 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 25C2110E13B; Tue, 29 Oct 2024 09:55:37 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="WPlyYo5K"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.3]) by gabe.freedesktop.org (Postfix) with ESMTP id 1DFF910E13B for ; Tue, 29 Oct 2024 09:55:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=UeECk 2NNGiU4afGhFyL6WxYiXpnwwPdwR71UMoipH+k=; b=WPlyYo5KbueiL+n/e+PkV zjiLcAhhcKb74u/uFHcjbpieA/BqZ7jgEG7yUIs2yC0xcD5EvEsWUT9Q523BKm/K NYxTY49pMfXqpu7bR/nnT/A9bLaUNoAvC7MEFNAx1A+M2YNLu3izSADppKzy03vs NirC1Z/BqWdmKjnppAzVq4= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S7; Tue, 29 Oct 2024 17:55:24 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan Subject: [PATCH v4 05/14] drm/rockchip: vop2: include rockchip_drm_drv.h Date: Tue, 29 Oct 2024 17:54:58 +0800 Message-ID: <20241029095513.391006-6-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S7 X-Coremail-Antispam: 1Uf129KBjvJXoW7uFyxKw45Wr48JrWfuF4fAFb_yoW8CFW3pF s8AFWUZrWxKFWjqr1DAF9Ikr4Fy3ZrCayxG3Z7G3W3ZF12gF1DGwnrW3s8JrZrXr42vF42 krs3J34UCF42vr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07UZVysUUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMwqHXmcgqJmjwgADs0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Min-Hua Chen Move rockchip_drm_drv.h in rockchip_drm_vop2.h to fix the follow sparse warning: ARCH=arm64 LLVM=1 make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' mrproper defconfig all -j12 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c:502:24: sparse: warning: symbol 'vop2_platform_driver' was not declared. Should it be static? It is also beneficial for the upcoming support for rk3576. Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver") Signed-off-by: Andy Yan Signed-off-by: Min-Hua Chen --- (no changes since v3) Changes in v3: - Split it from 10/15, as it fix a exiting compile warning. drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 1 - drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 4776a227e62c8..a7f9f88869a6d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -35,7 +35,6 @@ #include #include -#include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" #include "rockchip_drm_vop2.h" #include "rockchip_rgb.h" diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 59cd6b933bfba..bc001f7158476 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -9,6 +9,7 @@ #include #include +#include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" #define VOP2_VP_FEATURE_OUTPUT_10BIT BIT(0) From patchwork Tue Oct 29 09:54:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854581 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 79B52D2AB11 for ; Tue, 29 Oct 2024 09:55:49 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0571D10E5FB; Tue, 29 Oct 2024 09:55:49 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="capxqMZu"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.3]) by gabe.freedesktop.org (Postfix) with ESMTP id 739B110E5FB for ; Tue, 29 Oct 2024 09:55:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=ylorO LmPl6t2JByoZBwwtJAWf1Xy95NtaZucuHlp0rc=; b=capxqMZu1/nGgdbn6IGeq 8hP7JCtNyblFA/MsA6c2wPffyGRJ/Zzo7tcTHxANTiQUvRu6XPWUqpFSME5joGPV MktO03n+f2DRbpIOp5GoYCWmfNUvRddedmNGXKmWDREeHNz0QQxT3DEVTabbAjTo +6e2d8Lm+vLR3grmfL//rM= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S8; Tue, 29 Oct 2024 17:55:25 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 06/14] drm/rockchip: vop2: Support 32x8 superblock afbc Date: Tue, 29 Oct 2024 17:54:59 +0800 Message-ID: <20241029095513.391006-7-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S8 X-Coremail-Antispam: 1Uf129KBjvJXoWxCrW3XF4xJw4xGr1DGry7GFg_yoW5Gry8pr W3ZrWqgw4DKF1jqanrJFWDZF43Jan2k3y7XrnrJr1jqryYkr9rG34qka4DZrWDtrWfGFW0 vFn7trW7Zw1Fyr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07U_9N3UUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiqQWHXmcgr44bRAAAsM X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan This is the only afbc format supported by the upcoming VOP for rk3576. Add support for it. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v2) Changes in v2: - split it from main patch add support for rk3576 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index a7f9f88869a6d..f6a030fd8e55b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1357,16 +1357,18 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, half_block_en); if (afbc_en) { - u32 stride; + u32 stride, block_w; + + /* the afbc superblock is 16 x 16 or 32 x 8 */ + block_w = fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 ? 32 : 16; - /* the afbc superblock is 16 x 16 */ afbc_format = vop2_convert_afbc_format(fb->format->format); /* Enable color transform for YTR */ if (fb->modifier & AFBC_FORMAT_MOD_YTR) afbc_format |= (1 << 4); - afbc_tile_num = ALIGN(actual_w, 16) >> 4; + afbc_tile_num = ALIGN(actual_w, block_w) / block_w; /* * AFBC pic_vir_width is count by pixel, this is different @@ -1377,6 +1379,9 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n", vp->id, win->data->name, stride); + /* It's for head stride, each head size is 16 byte */ + stride = ALIGN(stride, block_w) / block_w * 16; + uv_swap = vop2_afbc_uv_swap(fb->format->format); /* * This is a workaround for crazy IC design, Cluster @@ -1407,7 +1412,11 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, else vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1); - vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0); + if (fb->modifier & AFBC_FORMAT_MOD_SPLIT) + vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 1); + else + 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); vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info); From patchwork Tue Oct 29 09:55:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854584 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F0FE3D2AB13 for ; Tue, 29 Oct 2024 09:55:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id AB5C110E5FE; Tue, 29 Oct 2024 09:55:49 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="dNBqbXy+"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.2]) by gabe.freedesktop.org (Postfix) with ESMTP id C266810E5FB for ; Tue, 29 Oct 2024 09:55:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=8hiGY xcrzF/FXdOPdh0mLSwZYHqeMWdxIwyNjT9YdZM=; b=dNBqbXy+AkMrhSmQ0GM5/ xcpKW06IJUIvkHa4w66tjcrRqYLIVeQmuE1mSDvAP8VqKqt7y3afozu2XL/40qUK lz1C3Qxbj5Q+TslJEhJaQyBO8HYXk3Iq/m5A4Xqvh/o5MXdTguN9WcT9Pef0IqRU o58TAcgHmWrqiT5iAeLPJQ= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S9; Tue, 29 Oct 2024 17:55:26 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 07/14] drm/rockchip: vop2: Add platform specific callback Date: Tue, 29 Oct 2024 17:55:00 +0800 Message-ID: <20241029095513.391006-8-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S9 X-Coremail-Antispam: 1Uf129KBjvAXoWDtFWfuFy3JFyfAw4ktr13urg_yoWfCFyUto W7uF1Yqr4Iqw1Fg39rWr17Xa47W3y8Can7Cr17XFnxZ39xX3yjkF92q3ZrtF17Jr15Cay5 Aws5t3WrZa1fXFs7n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxU4sjjDUUUU X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiqQWHXmcgr44bRAABsN X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan The VOP interface mux, overlay, background delay cycle configuration of different SOC are much different. Add platform specific callback ops to let the core driver look cleaner and more refined. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v2) Changes in v2: - Add platform specific callback drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 1125 +----------------- drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 159 +++ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 982 +++++++++++++++ 3 files changed, 1161 insertions(+), 1105 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index f6a030fd8e55b..6a7982ad35509 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -33,7 +33,6 @@ #include #include -#include #include "rockchip_drm_gem.h" #include "rockchip_drm_vop2.h" @@ -102,143 +101,6 @@ enum vop2_afbc_format { VOP2_AFBC_FMT_INVALID = -1, }; -union vop2_alpha_ctrl { - u32 val; - struct { - /* [0:1] */ - u32 color_mode:1; - u32 alpha_mode:1; - /* [2:3] */ - u32 blend_mode:2; - u32 alpha_cal_mode:1; - /* [5:7] */ - u32 factor_mode:3; - /* [8:9] */ - u32 alpha_en:1; - u32 src_dst_swap:1; - u32 reserved:6; - /* [16:23] */ - u32 glb_alpha:8; - } bits; -}; - -struct vop2_alpha { - union vop2_alpha_ctrl src_color_ctrl; - union vop2_alpha_ctrl dst_color_ctrl; - union vop2_alpha_ctrl src_alpha_ctrl; - union vop2_alpha_ctrl dst_alpha_ctrl; -}; - -struct vop2_alpha_config { - bool src_premulti_en; - bool dst_premulti_en; - bool src_pixel_alpha_en; - bool dst_pixel_alpha_en; - u16 src_glb_alpha_value; - u16 dst_glb_alpha_value; -}; - -struct vop2_win { - struct vop2 *vop2; - struct drm_plane base; - const struct vop2_win_data *data; - struct regmap_field *reg[VOP2_WIN_MAX_REG]; - - /** - * @win_id: graphic window id, a cluster may be split into two - * graphics windows. - */ - u8 win_id; - u8 delay; - u32 offset; - - enum drm_plane_type type; -}; - -struct vop2_video_port { - struct drm_crtc crtc; - struct vop2 *vop2; - struct clk *dclk; - unsigned int id; - const struct vop2_video_port_data *data; - - struct completion dsp_hold_completion; - - /** - * @win_mask: Bitmask of windows attached to the video port; - */ - u32 win_mask; - - struct vop2_win *primary_plane; - struct drm_pending_vblank_event *event; - - unsigned int nlayers; -}; - -struct vop2 { - struct device *dev; - struct drm_device *drm; - struct vop2_video_port vps[ROCKCHIP_MAX_CRTC]; - - const struct vop2_data *data; - /* - * Number of windows that are registered as plane, may be less than the - * total number of hardware windows. - */ - u32 registered_num_wins; - - struct resource *res; - void __iomem *regs; - 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; - - void __iomem *lut_regs; - - /* protects crtc enable/disable */ - struct mutex vop2_lock; - - int irq; - - /* - * Some global resources are shared between all video ports(crtcs), so - * we need a ref counter here. - */ - unsigned int enable_count; - struct clk *hclk; - struct clk *aclk; - struct clk *pclk; - - /* optional internal rgb encoder */ - struct rockchip_rgb *rgb; - - /* must be put at the end of the struct */ - 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) - /* * bus-format types. @@ -272,15 +134,6 @@ 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) -{ - return container_of(crtc, struct vop2_video_port, crtc); -} - -static struct vop2_win *to_vop2_win(struct drm_plane *p) -{ - return container_of(p, struct vop2_win, base); -} static void vop2_lock(struct vop2 *vop2) { @@ -292,35 +145,6 @@ static void vop2_unlock(struct vop2 *vop2) mutex_unlock(&vop2->vop2_lock); } -static void vop2_writel(struct vop2 *vop2, u32 offset, u32 v) -{ - regmap_write(vop2->map, offset, v); -} - -static void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v) -{ - regmap_write(vp->vop2->map, vp->data->offset + offset, v); -} - -static u32 vop2_readl(struct vop2 *vop2, u32 offset) -{ - u32 val; - - regmap_read(vop2->map, offset, &val); - - return val; -} - -static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v) -{ - regmap_field_write(win->reg[reg], v); -} - -static bool vop2_cluster_window(const struct vop2_win *win) -{ - return win->data->feature & WIN_FEATURE_CLUSTER; -} - /* * Note: * The write mask function is documented but missing on rk3566/8, writes @@ -1556,6 +1380,7 @@ static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl) static void vop2_post_config(struct drm_crtc *crtc) { struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; struct drm_display_mode *mode = &crtc->state->adjusted_mode; u16 vtotal = mode->crtc_vtotal; u16 hdisplay = mode->crtc_hdisplay; @@ -1566,18 +1391,10 @@ static void vop2_post_config(struct drm_crtc *crtc) u32 top_margin = 100, bottom_margin = 100; u16 hsize = hdisplay * (left_margin + right_margin) / 200; u16 vsize = vdisplay * (top_margin + bottom_margin) / 200; - u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; u16 hact_end, vact_end; u32 val; - u32 bg_dly; - u32 pre_scan_dly; - - bg_dly = vp->data->pre_scan_max_dly[3]; - vop2_writel(vp->vop2, RK3568_VP_BG_MIX_CTRL(vp->id), - FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly)); - pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len; - vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly); + vop2->ops->setup_bg_dly(vp); vsize = rounddown(vsize, 2); hsize = rounddown(hsize, 2); @@ -1613,347 +1430,6 @@ static void vop2_post_config(struct drm_crtc *crtc) vop2_vp_write(vp, RK3568_VP_DSP_BG, 0); } -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); - dip = vop2_readl(vop2, RK3568_DSP_IF_POL); - - switch (id) { - case ROCKCHIP_VOP2_EP_RGB0: - die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX; - die |= RK3568_SYS_DSP_INFACE_EN_RGB | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->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->sys_grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3)); - else - 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; - die |= RK3568_SYS_DSP_INFACE_EN_HDMI | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__HDMI_PIN_POL; - dip |= FIELD_PREP(RK3568_DSP_IF_POL__HDMI_PIN_POL, polflags); - break; - case ROCKCHIP_VOP2_EP_EDP0: - die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX; - die |= RK3568_SYS_DSP_INFACE_EN_EDP | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__EDP_PIN_POL; - dip |= FIELD_PREP(RK3568_DSP_IF_POL__EDP_PIN_POL, polflags); - break; - case ROCKCHIP_VOP2_EP_MIPI0: - die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX; - die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL; - dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags); - break; - case ROCKCHIP_VOP2_EP_MIPI1: - die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX; - die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL; - dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags); - break; - case ROCKCHIP_VOP2_EP_LVDS0: - die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX; - die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; - dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags); - break; - case ROCKCHIP_VOP2_EP_LVDS1: - die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX; - die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 | - FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id); - dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; - dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_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_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 rk3588_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 rk3588_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_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; - */ - *if_pixclk_div = 2; - *if_dclk_div = 4; - } else if (vop2_output_if_is_edp(id)) { - /* - * edp_pixclk = edp_dclk > dclk_core - */ - if_pixclk_rate = v_pixclk / K; - dclk_rate = if_pixclk_rate * K; - /* - * *if_pixclk_div = dclk_rate / if_pixclk_rate; - * *if_dclk_div = *if_pixclk_div; - */ - *if_pixclk_div = K; - *if_dclk_div = K; - } 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 = rk3588_calc_dclk(dclk_out_rate, 600000); - if (!dclk_rate) { - drm_err(vop2->drm, "DP dclk_out_rate out of range, dclk_out_rate: %ld KHZ\n", - dclk_out_rate); - return 0; - } - *dclk_out_div = dclk_rate / dclk_out_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 = rk3588_calc_dclk(dclk_out_rate, 600000); - if (!dclk_rate) { - drm_err(vop2->drm, "MIPI dclk out of range, dclk_out_rate: %ld KHZ\n", - dclk_out_rate); - return 0; - } - *dclk_out_div = dclk_rate / dclk_out_rate; - /* - * mipi pixclk == dclk_out - */ - *if_pixclk_div = 1; - } 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_dbg(vop2->drm, "dclk: %ld, pixclk_div: %d, 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 = rk3588_calc_cru_cfg(vp, id, &dclk_core_div, &dclk_out_div, - &if_pixclk_div, &if_dclk_div); - if (!clock) - return 0; - - 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 &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV; - div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV; - 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 &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV; - div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV; - 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 &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV; - div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV; - 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 &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV; - div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV; - 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 &= ~RK3588_DSP_IF_MIPI0_PCLK_DIV; - 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 &= ~RK3588_DSP_IF_MIPI1_PCLK_DIV; - 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) { return us * mode->clock / mode->htotal / 1000; @@ -2026,7 +1502,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, * process multi(1/2/4/8) pixels per cycle, so the dclk feed by the * system cru may be the 1/2 or 1/4 of mode->clock. */ - clock = vop2_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); + clock = vop2->ops->setup_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); } if (!clock) { @@ -2121,451 +1597,13 @@ static int vop2_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static bool is_opaque(u16 alpha) -{ - return (alpha >> 8) == 0xff; -} - -static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config, - struct vop2_alpha *alpha) -{ - int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1; - int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1; - int src_color_mode = alpha_config->src_premulti_en ? - ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; - int dst_color_mode = alpha_config->dst_premulti_en ? - ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; - - alpha->src_color_ctrl.val = 0; - alpha->dst_color_ctrl.val = 0; - alpha->src_alpha_ctrl.val = 0; - alpha->dst_alpha_ctrl.val = 0; - - if (!alpha_config->src_pixel_alpha_en) - alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; - else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en) - alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX; - else - alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; - - alpha->src_color_ctrl.bits.alpha_en = 1; - - if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) { - alpha->src_color_ctrl.bits.color_mode = src_color_mode; - alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; - } else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) { - alpha->src_color_ctrl.bits.color_mode = src_color_mode; - alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE; - } else { - alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL; - alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; - } - alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8; - alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; - alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; - - alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; - alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; - alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; - alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8; - alpha->dst_color_ctrl.bits.color_mode = dst_color_mode; - alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; - - alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; - alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode; - alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; - alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE; - - alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; - if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en) - alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX; - else - alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; - alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION; - alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; -} - -static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id) -{ - struct vop2_video_port *vp; - int used_layer = 0; - int i; - - for (i = 0; i < port_id; i++) { - vp = &vop2->vps[i]; - used_layer += hweight32(vp->win_mask); - } - - return used_layer; -} - -static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win) -{ - struct vop2_alpha_config alpha_config; - struct vop2_alpha alpha; - struct drm_plane_state *bottom_win_pstate; - bool src_pixel_alpha_en = false; - u16 src_glb_alpha_val, dst_glb_alpha_val; - bool premulti_en = false; - bool swap = false; - u32 offset = 0; - - /* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */ - bottom_win_pstate = main_win->base.state; - src_glb_alpha_val = 0; - dst_glb_alpha_val = main_win->base.state->alpha; - - if (!bottom_win_pstate->fb) - return; - - alpha_config.src_premulti_en = premulti_en; - alpha_config.dst_premulti_en = false; - alpha_config.src_pixel_alpha_en = src_pixel_alpha_en; - alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ - alpha_config.src_glb_alpha_value = src_glb_alpha_val; - alpha_config.dst_glb_alpha_value = dst_glb_alpha_val; - vop2_parse_alpha(&alpha_config, &alpha); - - alpha.src_color_ctrl.bits.src_dst_swap = swap; - - switch (main_win->data->phys_id) { - case ROCKCHIP_VOP2_CLUSTER0: - offset = 0x0; - break; - case ROCKCHIP_VOP2_CLUSTER1: - offset = 0x10; - break; - case ROCKCHIP_VOP2_CLUSTER2: - offset = 0x20; - break; - case ROCKCHIP_VOP2_CLUSTER3: - offset = 0x30; - break; - } - - vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset, - alpha.src_color_ctrl.val); - vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset, - alpha.dst_color_ctrl.val); - vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset, - alpha.src_alpha_ctrl.val); - vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset, - alpha.dst_alpha_ctrl.val); -} - -static void vop2_setup_alpha(struct vop2_video_port *vp) -{ - struct vop2 *vop2 = vp->vop2; - struct drm_framebuffer *fb; - struct vop2_alpha_config alpha_config; - struct vop2_alpha alpha; - struct drm_plane *plane; - int pixel_alpha_en; - int premulti_en, gpremulti_en = 0; - int mixer_id; - u32 offset; - bool bottom_layer_alpha_en = false; - u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE; - - mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); - alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ - - drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { - struct vop2_win *win = to_vop2_win(plane); - - if (plane->state->normalized_zpos == 0 && - !is_opaque(plane->state->alpha) && - !vop2_cluster_window(win)) { - /* - * If bottom layer have global alpha effect [except cluster layer, - * because cluster have deal with bottom layer global alpha value - * at cluster mix], bottom layer mix need deal with global alpha. - */ - bottom_layer_alpha_en = true; - dst_global_alpha = plane->state->alpha; - } - } - - drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { - struct vop2_win *win = to_vop2_win(plane); - int zpos = plane->state->normalized_zpos; - - /* - * Need to configure alpha from second layer. - */ - if (zpos == 0) - continue; - - if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) - premulti_en = 1; - else - premulti_en = 0; - - plane = &win->base; - fb = plane->state->fb; - - pixel_alpha_en = fb->format->has_alpha; - - alpha_config.src_premulti_en = premulti_en; - - if (bottom_layer_alpha_en && zpos == 1) { - gpremulti_en = premulti_en; - /* Cd = Cs + (1 - As) * Cd * Agd */ - alpha_config.dst_premulti_en = false; - alpha_config.src_pixel_alpha_en = pixel_alpha_en; - alpha_config.src_glb_alpha_value = plane->state->alpha; - alpha_config.dst_glb_alpha_value = dst_global_alpha; - } else if (vop2_cluster_window(win)) { - /* Mix output data only have pixel alpha */ - alpha_config.dst_premulti_en = true; - alpha_config.src_pixel_alpha_en = true; - alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; - alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; - } else { - /* Cd = Cs + (1 - As) * Cd */ - alpha_config.dst_premulti_en = true; - alpha_config.src_pixel_alpha_en = pixel_alpha_en; - alpha_config.src_glb_alpha_value = plane->state->alpha; - alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; - } - - vop2_parse_alpha(&alpha_config, &alpha); - - offset = (mixer_id + zpos - 1) * 0x10; - vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset, - alpha.src_color_ctrl.val); - vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset, - alpha.dst_color_ctrl.val); - vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset, - alpha.src_alpha_ctrl.val); - vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset, - alpha.dst_alpha_ctrl.val); - } - - if (vp->id == 0) { - if (bottom_layer_alpha_en) { - /* Transfer pixel alpha to hdr mix */ - alpha_config.src_premulti_en = gpremulti_en; - alpha_config.dst_premulti_en = true; - alpha_config.src_pixel_alpha_en = true; - alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; - alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; - vop2_parse_alpha(&alpha_config, &alpha); - - vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, - alpha.src_color_ctrl.val); - vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL, - alpha.dst_color_ctrl.val); - vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL, - alpha.src_alpha_ctrl.val); - vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL, - alpha.dst_alpha_ctrl.val); - } else { - vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0); - } - } -} - -static void vop2_setup_layer_mixer(struct vop2_video_port *vp) -{ - struct vop2 *vop2 = vp->vop2; - struct drm_plane *plane; - u32 layer_sel = 0; - u32 port_sel; - u8 old_layer_id; - u8 layer_sel_id; - unsigned int ofs; - 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); - - ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL); - ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; - if (vcstate->yuv_overlay) - ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id); - else - ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(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; - - if (vp0->nlayers) - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, - vp0->nlayers - 1); - else - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8); - - if (vp1->nlayers) - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, - (vp0->nlayers + vp1->nlayers - 1)); - else - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8); - - if (vp2->nlayers) - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, - (vp2->nlayers + vp1->nlayers + vp0->nlayers - 1)); - else - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8); - - layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); - - ofs = 0; - for (i = 0; i < vp->id; i++) - ofs += vop2->vps[i].nlayers; - - drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { - struct vop2_win *win = to_vop2_win(plane); - struct vop2_win *old_win; - - /* - * Find the layer this win bind in old state. - */ - for (old_layer_id = 0; old_layer_id < vop2->data->win_size; old_layer_id++) { - layer_sel_id = (layer_sel >> (4 * old_layer_id)) & 0xf; - if (layer_sel_id == win->data->layer_sel_id) - break; - } - - /* - * Find the win bind to this layer in old state - */ - for (i = 0; i < vop2->data->win_size; i++) { - old_win = &vop2->win[i]; - layer_sel_id = (layer_sel >> (4 * (plane->state->normalized_zpos + ofs))) & 0xf; - if (layer_sel_id == old_win->data->layer_sel_id) - break; - } - - switch (win->data->phys_id) { - case ROCKCHIP_VOP2_CLUSTER0: - port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0; - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id); - break; - case ROCKCHIP_VOP2_CLUSTER1: - 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); - break; - case ROCKCHIP_VOP2_ESMART1: - 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); - break; - case ROCKCHIP_VOP2_SMART1: - port_sel &= ~RK3568_OVL_PORT_SEL__SMART1; - port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id); - break; - } - - layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, - 0x7); - layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, - win->data->layer_sel_id); - /* - * When we bind a window from layerM to layerN, we also need to move the old - * window on layerN to layerM to avoid one window selected by two or more layers. - */ - layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, 0x7); - layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, old_win->data->layer_sel_id); - } - - vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); - vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel); -} - -static void vop2_setup_dly_for_windows(struct vop2 *vop2) -{ - struct vop2_win *win; - int i = 0; - u32 cdly = 0, sdly = 0; - - for (i = 0; i < vop2->data->win_size; i++) { - u32 dly; - - win = &vop2->win[i]; - dly = win->delay; - - switch (win->data->phys_id) { - case ROCKCHIP_VOP2_CLUSTER0: - cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly); - cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly); - break; - case ROCKCHIP_VOP2_CLUSTER1: - cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly); - cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly); - break; - case ROCKCHIP_VOP2_ESMART0: - sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly); - break; - case ROCKCHIP_VOP2_ESMART1: - sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly); - break; - case ROCKCHIP_VOP2_SMART0: - sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly); - break; - case ROCKCHIP_VOP2_SMART1: - sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly); - break; - } - } - - vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly); - vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly); -} - static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; - struct drm_plane *plane; - - vp->win_mask = 0; - - drm_atomic_crtc_for_each_plane(plane, crtc) { - struct vop2_win *win = to_vop2_win(plane); - - win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT]; - - vp->win_mask |= BIT(win->data->phys_id); - - if (vop2_cluster_window(win)) - vop2_setup_cluster_alpha(vop2, win); - } - - if (!vp->win_mask) - return; - vop2_setup_layer_mixer(vp); - vop2_setup_alpha(vp); - vop2_setup_dly_for_windows(vop2); + vop2->ops->setup_overlay(vp); } static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, @@ -3158,174 +2196,50 @@ static int vop2_find_rgb_encoder(struct vop2 *vop2) return -ENOENT; } -static struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] = { - [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0), - [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5), - [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14), - [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 18, 18), - [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_ACT_INFO, 0, 31), - [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_INFO, 0, 31), - [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_ST, 0, 31), - [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_CLUSTER_WIN_YRGB_MST, 0, 31), - [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_CLUSTER_WIN_CBR_MST, 0, 31), - [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 19, 19), - [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 0, 15), - [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 16, 31), - [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 8, 8), - [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 9, 9), - [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 10, 11), - - /* Scale */ - [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0, 15), - [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 16, 31), - [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 14, 15), - [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 12, 13), - [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 2, 3), - [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 28, 28), - [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 29, 29), - - /* cluster regs */ - [VOP2_WIN_AFBC_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 1, 1), - [VOP2_WIN_CLUSTER_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 0, 0), - [VOP2_WIN_CLUSTER_LB_MODE] = REG_FIELD(RK3568_CLUSTER_CTRL, 4, 7), - - /* afbc regs */ - [VOP2_WIN_AFBC_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 2, 6), - [VOP2_WIN_AFBC_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 9, 9), - [VOP2_WIN_AFBC_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 10, 10), - [VOP2_WIN_AFBC_AUTO_GATING_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 4, 4), - [VOP2_WIN_AFBC_HALF_BLOCK_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 7, 7), - [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 8, 8), - [VOP2_WIN_AFBC_HDR_PTR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0, 31), - [VOP2_WIN_AFBC_PIC_SIZE] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0, 31), - [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0, 15), - [VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31), - [VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31), - [VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31), - [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31), - [VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0), - [VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1), - [VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2), - [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 3, 3), - [VOP2_WIN_UV_SWAP] = { .reg = 0xffffffff }, - [VOP2_WIN_COLOR_KEY] = { .reg = 0xffffffff }, - [VOP2_WIN_COLOR_KEY_EN] = { .reg = 0xffffffff }, - [VOP2_WIN_SCALE_CBCR_X] = { .reg = 0xffffffff }, - [VOP2_WIN_SCALE_CBCR_Y] = { .reg = 0xffffffff }, - [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, - [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, - [VOP2_WIN_CBCR_VER_SCL_MODE] = { .reg = 0xffffffff }, - [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, - [VOP2_WIN_CBCR_HOR_SCL_MODE] = { .reg = 0xffffffff }, - [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, - [VOP2_WIN_VSD_CBCR_GT2] = { .reg = 0xffffffff }, - [VOP2_WIN_VSD_CBCR_GT4] = { .reg = 0xffffffff }, -}; - static int vop2_cluster_init(struct vop2_win *win) { struct vop2 *vop2 = win->vop2; struct reg_field *cluster_regs; int ret, i; - cluster_regs = kmemdup(vop2_cluster_regs, sizeof(vop2_cluster_regs), + cluster_regs = kmemdup(vop2->data->cluster_reg, + sizeof(struct reg_field) * vop2->data->nr_cluster_regs, GFP_KERNEL); if (!cluster_regs) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++) + for (i = 0; i < vop2->data->nr_cluster_regs; i++) if (cluster_regs[i].reg != 0xffffffff) cluster_regs[i].reg += win->offset; ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg, cluster_regs, - ARRAY_SIZE(vop2_cluster_regs)); - + vop2->data->nr_cluster_regs); kfree(cluster_regs); return ret; }; -static struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] = { - [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0), - [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5), - [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12), - [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 14, 14), - [VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 16, 16), - [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_SMART_REGION0_ACT_INFO, 0, 31), - [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_SMART_REGION0_DSP_INFO, 0, 31), - [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_SMART_REGION0_DSP_ST, 0, 28), - [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_SMART_REGION0_YRGB_MST, 0, 31), - [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_SMART_REGION0_CBR_MST, 0, 31), - [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 17, 17), - [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 0, 15), - [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 16, 31), - [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_SMART_CTRL0, 0, 0), - [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_SMART_CTRL0, 1, 1), - [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_SMART_CTRL0, 2, 3), - [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_SMART_CTRL1, 31, 31), - [VOP2_WIN_COLOR_KEY] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 0, 29), - [VOP2_WIN_COLOR_KEY_EN] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 31, 31), - - /* Scale */ - [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0, 15), - [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 16, 31), - [VOP2_WIN_SCALE_CBCR_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0, 15), - [VOP2_WIN_SCALE_CBCR_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 16, 31), - [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 0, 1), - [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 2, 3), - [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 4, 5), - [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 6, 7), - [VOP2_WIN_CBCR_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 8, 9), - [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 10, 11), - [VOP2_WIN_CBCR_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 12, 13), - [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 14, 15), - [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 16, 17), - [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 8, 8), - [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 9, 9), - [VOP2_WIN_VSD_CBCR_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 10, 10), - [VOP2_WIN_VSD_CBCR_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 11, 11), - [VOP2_WIN_XMIRROR] = { .reg = 0xffffffff }, - [VOP2_WIN_CLUSTER_ENABLE] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_ENABLE] = { .reg = 0xffffffff }, - [VOP2_WIN_CLUSTER_LB_MODE] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_FORMAT] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_RB_SWAP] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_UV_SWAP] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_AUTO_GATING_EN] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_TILE_NUM] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff }, - [VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff }, -}; - static int vop2_esmart_init(struct vop2_win *win) { struct vop2 *vop2 = win->vop2; - struct reg_field *esmart_regs; + struct reg_field *smart_regs; int ret, i; - esmart_regs = kmemdup(vop2_esmart_regs, sizeof(vop2_esmart_regs), - GFP_KERNEL); - if (!esmart_regs) + smart_regs = kmemdup(vop2->data->smart_reg, + sizeof(struct reg_field) * vop2->data->nr_smart_regs, + GFP_KERNEL); + if (!smart_regs) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++) - if (esmart_regs[i].reg != 0xffffffff) - esmart_regs[i].reg += win->offset; + for (i = 0; i < vop2->data->nr_smart_regs; i++) + if (smart_regs[i].reg != 0xffffffff) + smart_regs[i].reg += win->offset; ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg, - esmart_regs, - ARRAY_SIZE(vop2_esmart_regs)); - - kfree(esmart_regs); + smart_regs, + vop2->data->nr_smart_regs); + kfree(smart_regs); return ret; }; @@ -3405,6 +2319,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) vop2->dev = dev; vop2->data = vop2_data; + vop2->ops = vop2_data->ops; vop2->drm = drm; dev_set_drvdata(dev, vop2); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index bc001f7158476..b27163f561dea 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -9,6 +9,7 @@ #include #include +#include #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" @@ -58,6 +59,23 @@ enum vop2_scale_down_mode { #define VOP2_PD_DSC_4K BIT(6) #define VOP2_PD_ESMART BIT(7) +#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) + enum vop2_win_regs { VOP2_WIN_ENABLE, VOP2_WIN_FORMAT, @@ -155,6 +173,23 @@ struct vop2_win_data { const u8 dly[VOP2_DLY_MODE_MAX]; }; +struct vop2_win { + struct vop2 *vop2; + struct drm_plane base; + const struct vop2_win_data *data; + struct regmap_field *reg[VOP2_WIN_MAX_REG]; + + /** + * @win_id: graphic window id, a cluster may be split into two + * graphics windows. + */ + u8 win_id; + u8 delay; + u32 offset; + + enum drm_plane_type type; +}; + struct vop2_video_port_data { unsigned int id; u32 feature; @@ -165,20 +200,105 @@ struct vop2_video_port_data { unsigned int offset; }; +struct vop2_video_port { + struct drm_crtc crtc; + struct vop2 *vop2; + struct clk *dclk; + unsigned int id; + const struct vop2_video_port_data *data; + + struct completion dsp_hold_completion; + + /** + * @win_mask: Bitmask of windows attached to the video port; + */ + u32 win_mask; + + struct vop2_win *primary_plane; + struct drm_pending_vblank_event *event; + + unsigned int nlayers; +}; + +/** + * struct vop2_ops - helper operations for vop2 hardware + * + * These hooks are used by the common part of the vop2 driver to + * implement the proper behaviour of different variants. + */ +struct vop2_ops { + unsigned long (*setup_intf_mux)(struct vop2_video_port *vp, int ep_id, u32 polflags); + void (*setup_bg_dly)(struct vop2_video_port *vp); + void (*setup_overlay)(struct vop2_video_port *vp); +}; + struct vop2_data { u8 nr_vps; u64 feature; + const struct vop2_ops *ops; const struct vop2_win_data *win; const struct vop2_video_port_data *vp; + const struct reg_field *cluster_reg; + const struct reg_field *smart_reg; const struct vop2_regs_dump *regs_dump; struct vop_rect max_input; struct vop_rect max_output; + unsigned int nr_cluster_regs; + unsigned int nr_smart_regs; unsigned int win_size; unsigned int regs_dump_size; unsigned int soc_id; }; +struct vop2 { + struct device *dev; + struct drm_device *drm; + struct vop2_video_port vps[ROCKCHIP_MAX_CRTC]; + + const struct vop2_data *data; + const struct vop2_ops *ops; + /* + * Number of windows that are registered as plane, may be less than the + * total number of hardware windows. + */ + u32 registered_num_wins; + + struct resource *res; + void __iomem *regs; + 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; + + void __iomem *lut_regs; + + /* protects crtc enable/disable */ + struct mutex vop2_lock; + + int irq; + + /* + * Some global resources are shared between all video ports(crtcs), so + * we need a ref counter here. + */ + unsigned int enable_count; + struct clk *hclk; + struct clk *aclk; + struct clk *pclk; + + /* optional internal rgb encoder */ + struct rockchip_rgb *rgb; + + /* must be put at the end of the struct */ + struct vop2_win win[]; +}; + /* interrupt define */ #define FS_NEW_INTR BIT(4) #define ADDR_SAME_INTR BIT(5) @@ -546,4 +666,43 @@ enum vop2_layer_phy_id { extern const struct component_ops vop2_component_ops; +static inline void vop2_writel(struct vop2 *vop2, u32 offset, u32 v) +{ + regmap_write(vop2->map, offset, v); +} + +static inline void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v) +{ + regmap_write(vp->vop2->map, vp->data->offset + offset, v); +} + +static inline u32 vop2_readl(struct vop2 *vop2, u32 offset) +{ + u32 val; + + regmap_read(vop2->map, offset, &val); + + return val; +} + +static inline void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v) +{ + regmap_field_write(win->reg[reg], v); +} + +static inline bool vop2_cluster_window(const struct vop2_win *win) +{ + return win->data->feature & WIN_FEATURE_CLUSTER; +} + +static inline struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc) +{ + return container_of(crtc, struct vop2_video_port, crtc); +} + +static inline struct vop2_win *to_vop2_win(struct drm_plane *p) +{ + return container_of(p, struct vop2_win, base); +} + #endif /* _ROCKCHIP_DRM_VOP2_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 8ff0bd528d65d..0e577aabc9e49 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -9,12 +9,50 @@ #include #include #include +#include #include +#include #include #include #include "rockchip_drm_vop2.h" +union vop2_alpha_ctrl { + u32 val; + struct { + /* [0:1] */ + u32 color_mode:1; + u32 alpha_mode:1; + /* [2:3] */ + u32 blend_mode:2; + u32 alpha_cal_mode:1; + /* [5:7] */ + u32 factor_mode:3; + /* [8:9] */ + u32 alpha_en:1; + u32 src_dst_swap:1; + u32 reserved:6; + /* [16:23] */ + u32 glb_alpha:8; + } bits; +}; + +struct vop2_alpha { + union vop2_alpha_ctrl src_color_ctrl; + union vop2_alpha_ctrl dst_color_ctrl; + union vop2_alpha_ctrl src_alpha_ctrl; + union vop2_alpha_ctrl dst_alpha_ctrl; +}; + +struct vop2_alpha_config { + bool src_premulti_en; + bool dst_premulti_en; + bool src_pixel_alpha_en; + bool dst_pixel_alpha_en; + u16 src_glb_alpha_value; + u16 dst_glb_alpha_value; +}; + static const uint32_t formats_cluster[] = { DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, @@ -131,6 +169,130 @@ static const uint64_t format_modifiers_afbc[] = { DRM_FORMAT_MOD_INVALID, }; +static const struct reg_field rk3568_vop_cluster_regs[VOP2_WIN_MAX_REG] = { + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0), + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5), + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14), + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 18, 18), + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_ACT_INFO, 0, 31), + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_INFO, 0, 31), + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_ST, 0, 31), + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_CLUSTER_WIN_YRGB_MST, 0, 31), + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_CLUSTER_WIN_CBR_MST, 0, 31), + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 19, 19), + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 0, 15), + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 16, 31), + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 8, 8), + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 9, 9), + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 10, 11), + + /* Scale */ + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0, 15), + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 16, 31), + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 14, 15), + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 12, 13), + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 2, 3), + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 28, 28), + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 29, 29), + + /* cluster regs */ + [VOP2_WIN_AFBC_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 1, 1), + [VOP2_WIN_CLUSTER_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 0, 0), + [VOP2_WIN_CLUSTER_LB_MODE] = REG_FIELD(RK3568_CLUSTER_CTRL, 4, 7), + + /* afbc regs */ + [VOP2_WIN_AFBC_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 2, 6), + [VOP2_WIN_AFBC_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 9, 9), + [VOP2_WIN_AFBC_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 10, 10), + [VOP2_WIN_AFBC_AUTO_GATING_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 4, 4), + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 7, 7), + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 8, 8), + [VOP2_WIN_AFBC_HDR_PTR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0, 31), + [VOP2_WIN_AFBC_PIC_SIZE] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0, 31), + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0, 15), + [VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31), + [VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31), + [VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31), + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31), + [VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0), + [VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1), + [VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2), + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 3, 3), + [VOP2_WIN_UV_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_COLOR_KEY] = { .reg = 0xffffffff }, + [VOP2_WIN_COLOR_KEY_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_SCALE_CBCR_X] = { .reg = 0xffffffff }, + [VOP2_WIN_SCALE_CBCR_Y] = { .reg = 0xffffffff }, + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_VER_SCL_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_HOR_SCL_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_VSD_CBCR_GT2] = { .reg = 0xffffffff }, + [VOP2_WIN_VSD_CBCR_GT4] = { .reg = 0xffffffff }, +}; + +static const struct reg_field rk3568_vop_smart_regs[VOP2_WIN_MAX_REG] = { + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0), + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5), + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12), + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 14, 14), + [VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 16, 16), + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_SMART_REGION0_ACT_INFO, 0, 31), + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_SMART_REGION0_DSP_INFO, 0, 31), + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_SMART_REGION0_DSP_ST, 0, 28), + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_SMART_REGION0_YRGB_MST, 0, 31), + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_SMART_REGION0_CBR_MST, 0, 31), + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 17, 17), + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 0, 15), + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 16, 31), + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_SMART_CTRL0, 0, 0), + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_SMART_CTRL0, 1, 1), + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_SMART_CTRL0, 2, 3), + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_SMART_CTRL1, 31, 31), + [VOP2_WIN_COLOR_KEY] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 0, 29), + [VOP2_WIN_COLOR_KEY_EN] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 31, 31), + + /* Scale */ + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0, 15), + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 16, 31), + [VOP2_WIN_SCALE_CBCR_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0, 15), + [VOP2_WIN_SCALE_CBCR_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 16, 31), + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 0, 1), + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 2, 3), + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 4, 5), + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 6, 7), + [VOP2_WIN_CBCR_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 8, 9), + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 10, 11), + [VOP2_WIN_CBCR_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 12, 13), + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 14, 15), + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 16, 17), + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 8, 8), + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 9, 9), + [VOP2_WIN_VSD_CBCR_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 10, 10), + [VOP2_WIN_VSD_CBCR_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 11, 11), + [VOP2_WIN_XMIRROR] = { .reg = 0xffffffff }, + [VOP2_WIN_CLUSTER_ENABLE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ENABLE] = { .reg = 0xffffffff }, + [VOP2_WIN_CLUSTER_LB_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_FORMAT] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_RB_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_UV_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_AUTO_GATING_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_TILE_NUM] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff }, +}; + static const struct vop2_video_port_data rk3568_vop_video_ports[] = { { .id = 0, @@ -623,6 +785,811 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = { }, }; +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); + dip = vop2_readl(vop2, RK3568_DSP_IF_POL); + + switch (id) { + case ROCKCHIP_VOP2_EP_RGB0: + die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_RGB | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->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->sys_grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3)); + else + 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; + die |= RK3568_SYS_DSP_INFACE_EN_HDMI | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__HDMI_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__HDMI_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_EDP0: + die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_EDP | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__EDP_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__EDP_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_MIPI0: + die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_MIPI1: + die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_LVDS0: + die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_LVDS1: + die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_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_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 rk3588_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 rk3588_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_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; + */ + *if_pixclk_div = 2; + *if_dclk_div = 4; + } else if (vop2_output_if_is_edp(id)) { + /* + * edp_pixclk = edp_dclk > dclk_core + */ + if_pixclk_rate = v_pixclk / K; + dclk_rate = if_pixclk_rate * K; + /* + * *if_pixclk_div = dclk_rate / if_pixclk_rate; + * *if_dclk_div = *if_pixclk_div; + */ + *if_pixclk_div = K; + *if_dclk_div = K; + } 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 = rk3588_calc_dclk(dclk_out_rate, 600000); + if (!dclk_rate) { + drm_err(vop2->drm, "DP dclk_out_rate out of range, dclk_out_rate: %ld KHZ\n", + dclk_out_rate); + return 0; + } + *dclk_out_div = dclk_rate / dclk_out_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 = rk3588_calc_dclk(dclk_out_rate, 600000); + if (!dclk_rate) { + drm_err(vop2->drm, "MIPI dclk out of range, dclk_out_rate: %ld KHZ\n", + dclk_out_rate); + return 0; + } + *dclk_out_div = dclk_rate / dclk_out_rate; + /* + * mipi pixclk == dclk_out + */ + *if_pixclk_div = 1; + } 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_dbg(vop2->drm, "dclk: %ld, pixclk_div: %d, 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 = rk3588_calc_cru_cfg(vp, id, &dclk_core_div, &dclk_out_div, + &if_pixclk_div, &if_dclk_div); + if (!clock) + return 0; + + 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 &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV; + div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV; + 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 &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV; + div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV; + 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 &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV; + div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV; + 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 &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV; + div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV; + 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 &= ~RK3588_DSP_IF_MIPI0_PCLK_DIV; + 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 &= ~RK3588_DSP_IF_MIPI1_PCLK_DIV; + 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 bool is_opaque(u16 alpha) +{ + return (alpha >> 8) == 0xff; +} + +static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config, + struct vop2_alpha *alpha) +{ + int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1; + int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1; + int src_color_mode = alpha_config->src_premulti_en ? + ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; + int dst_color_mode = alpha_config->dst_premulti_en ? + ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; + + alpha->src_color_ctrl.val = 0; + alpha->dst_color_ctrl.val = 0; + alpha->src_alpha_ctrl.val = 0; + alpha->dst_alpha_ctrl.val = 0; + + if (!alpha_config->src_pixel_alpha_en) + alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; + else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en) + alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX; + else + alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; + + alpha->src_color_ctrl.bits.alpha_en = 1; + + if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) { + alpha->src_color_ctrl.bits.color_mode = src_color_mode; + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; + } else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) { + alpha->src_color_ctrl.bits.color_mode = src_color_mode; + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE; + } else { + alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL; + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; + } + alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8; + alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; + + alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; + alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; + alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8; + alpha->dst_color_ctrl.bits.color_mode = dst_color_mode; + alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; + + alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode; + alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; + alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE; + + alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en) + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX; + else + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; + alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION; + alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; +} + +static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id) +{ + struct vop2_video_port *vp; + int used_layer = 0; + int i; + + for (i = 0; i < port_id; i++) { + vp = &vop2->vps[i]; + used_layer += hweight32(vp->win_mask); + } + + return used_layer; +} + +static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win) +{ + struct vop2_alpha_config alpha_config; + struct vop2_alpha alpha; + struct drm_plane_state *bottom_win_pstate; + bool src_pixel_alpha_en = false; + u16 src_glb_alpha_val, dst_glb_alpha_val; + u32 offset = 0; + bool premulti_en = false; + bool swap = false; + + /* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */ + bottom_win_pstate = main_win->base.state; + src_glb_alpha_val = 0; + dst_glb_alpha_val = main_win->base.state->alpha; + + if (!bottom_win_pstate->fb) + return; + + alpha_config.src_premulti_en = premulti_en; + alpha_config.dst_premulti_en = false; + alpha_config.src_pixel_alpha_en = src_pixel_alpha_en; + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ + alpha_config.src_glb_alpha_value = src_glb_alpha_val; + alpha_config.dst_glb_alpha_value = dst_glb_alpha_val; + vop2_parse_alpha(&alpha_config, &alpha); + + alpha.src_color_ctrl.bits.src_dst_swap = swap; + + switch (main_win->data->phys_id) { + case ROCKCHIP_VOP2_CLUSTER0: + offset = 0x0; + break; + case ROCKCHIP_VOP2_CLUSTER1: + offset = 0x10; + break; + case ROCKCHIP_VOP2_CLUSTER2: + offset = 0x20; + break; + case ROCKCHIP_VOP2_CLUSTER3: + offset = 0x30; + break; + } + + vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset, + alpha.src_color_ctrl.val); + vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset, + alpha.dst_color_ctrl.val); + vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset, + alpha.src_alpha_ctrl.val); + vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset, + alpha.dst_alpha_ctrl.val); +} + +static void vop2_setup_alpha(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + struct drm_framebuffer *fb; + struct vop2_alpha_config alpha_config; + struct vop2_alpha alpha; + struct drm_plane *plane; + int pixel_alpha_en; + int premulti_en, gpremulti_en = 0; + int mixer_id; + u32 offset; + bool bottom_layer_alpha_en = false; + u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE; + + mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ + + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + struct vop2_win *win = to_vop2_win(plane); + + if (plane->state->normalized_zpos == 0 && + !is_opaque(plane->state->alpha) && + !vop2_cluster_window(win)) { + /* + * If bottom layer have global alpha effect [except cluster layer, + * because cluster have deal with bottom layer global alpha value + * at cluster mix], bottom layer mix need deal with global alpha. + */ + bottom_layer_alpha_en = true; + dst_global_alpha = plane->state->alpha; + } + } + + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + struct vop2_win *win = to_vop2_win(plane); + int zpos = plane->state->normalized_zpos; + + /* + * Need to configure alpha from second layer. + */ + if (zpos == 0) + continue; + + if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) + premulti_en = 1; + else + premulti_en = 0; + + plane = &win->base; + fb = plane->state->fb; + + pixel_alpha_en = fb->format->has_alpha; + + alpha_config.src_premulti_en = premulti_en; + + if (bottom_layer_alpha_en && zpos == 1) { + gpremulti_en = premulti_en; + /* Cd = Cs + (1 - As) * Cd * Agd */ + alpha_config.dst_premulti_en = false; + alpha_config.src_pixel_alpha_en = pixel_alpha_en; + alpha_config.src_glb_alpha_value = plane->state->alpha; + alpha_config.dst_glb_alpha_value = dst_global_alpha; + } else if (vop2_cluster_window(win)) { + /* Mix output data only have pixel alpha */ + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = true; + alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + } else { + /* Cd = Cs + (1 - As) * Cd */ + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = pixel_alpha_en; + alpha_config.src_glb_alpha_value = plane->state->alpha; + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + } + + vop2_parse_alpha(&alpha_config, &alpha); + + offset = (mixer_id + zpos - 1) * 0x10; + vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset, + alpha.src_color_ctrl.val); + vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset, + alpha.dst_color_ctrl.val); + vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset, + alpha.src_alpha_ctrl.val); + vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset, + alpha.dst_alpha_ctrl.val); + } + + if (vp->id == 0) { + if (bottom_layer_alpha_en) { + /* Transfer pixel alpha to hdr mix */ + alpha_config.src_premulti_en = gpremulti_en; + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = true; + alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + vop2_parse_alpha(&alpha_config, &alpha); + + vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, + alpha.src_color_ctrl.val); + vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL, + alpha.dst_color_ctrl.val); + vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL, + alpha.src_alpha_ctrl.val); + vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL, + alpha.dst_alpha_ctrl.val); + } else { + vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0); + } + } +} + +static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + struct drm_plane *plane; + u32 layer_sel = 0; + u32 port_sel; + u8 old_layer_id; + u8 layer_sel_id; + unsigned int ofs; + 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); + + ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL); + ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; + if (vcstate->yuv_overlay) + ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id); + else + ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(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; + + if (vp0->nlayers) + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, + vp0->nlayers - 1); + else + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8); + + if (vp1->nlayers) + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, + (vp0->nlayers + vp1->nlayers - 1)); + else + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8); + + if (vp2->nlayers) + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, + (vp2->nlayers + vp1->nlayers + vp0->nlayers - 1)); + else + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8); + + layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); + + ofs = 0; + for (i = 0; i < vp->id; i++) + ofs += vop2->vps[i].nlayers; + + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + struct vop2_win *win = to_vop2_win(plane); + struct vop2_win *old_win; + + /* + * Find the layer this win bind in old state. + */ + for (old_layer_id = 0; old_layer_id < vop2->data->win_size; old_layer_id++) { + layer_sel_id = (layer_sel >> (4 * old_layer_id)) & 0xf; + if (layer_sel_id == win->data->layer_sel_id) + break; + } + + /* + * Find the win bind to this layer in old state + */ + for (i = 0; i < vop2->data->win_size; i++) { + old_win = &vop2->win[i]; + layer_sel_id = (layer_sel >> (4 * (plane->state->normalized_zpos + ofs))) & 0xf; + if (layer_sel_id == old_win->data->layer_sel_id) + break; + } + + switch (win->data->phys_id) { + case ROCKCHIP_VOP2_CLUSTER0: + port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id); + break; + case ROCKCHIP_VOP2_CLUSTER1: + 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); + break; + case ROCKCHIP_VOP2_ESMART1: + 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); + break; + case ROCKCHIP_VOP2_SMART1: + port_sel &= ~RK3568_OVL_PORT_SEL__SMART1; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id); + break; + } + + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, + 0x7); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, + win->data->layer_sel_id); + /* + * When we bind a window from layerM to layerN, we also need to move the old + * window on layerN to layerM to avoid one window selected by two or more layers. + */ + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, 0x7); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, old_win->data->layer_sel_id); + } + + vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); + vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel); +} + +static void rk3568_vop2_setup_dly_for_windows(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + struct vop2_win *win; + int i = 0; + u32 cdly = 0, sdly = 0; + + for (i = 0; i < vop2->data->win_size; i++) { + u32 dly; + + win = &vop2->win[i]; + dly = win->delay; + + switch (win->data->phys_id) { + case ROCKCHIP_VOP2_CLUSTER0: + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly); + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly); + break; + case ROCKCHIP_VOP2_CLUSTER1: + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly); + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly); + break; + case ROCKCHIP_VOP2_ESMART0: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly); + break; + case ROCKCHIP_VOP2_ESMART1: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly); + break; + case ROCKCHIP_VOP2_SMART0: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly); + break; + case ROCKCHIP_VOP2_SMART1: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly); + break; + } + } + + vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly); + vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly); +} + +static void rk3568_vop2_setup_overlay(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + struct drm_crtc *crtc = &vp->crtc; + struct drm_plane *plane; + + vp->win_mask = 0; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct vop2_win *win = to_vop2_win(plane); + + win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT]; + + vp->win_mask |= BIT(win->data->phys_id); + + if (vop2_cluster_window(win)) + vop2_setup_cluster_alpha(vop2, win); + } + + if (!vp->win_mask) + return; + + rk3568_vop2_setup_layer_mixer(vp); + vop2_setup_alpha(vp); + rk3568_vop2_setup_dly_for_windows(vp); +} + +static void rk3568_vop2_setup_bg_dly(struct vop2_video_port *vp) +{ + struct drm_crtc *crtc = &vp->crtc; + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + u16 hdisplay = mode->crtc_hdisplay; + u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + u32 bg_dly; + u32 pre_scan_dly; + + bg_dly = vp->data->pre_scan_max_dly[3]; + vop2_writel(vp->vop2, RK3568_VP_BG_MIX_CTRL(vp->id), + FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly)); + + pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len; + vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly); +} + +static const struct vop2_ops rk3568_vop_ops = { + .setup_intf_mux = rk3568_set_intf_mux, + .setup_bg_dly = rk3568_vop2_setup_bg_dly, + .setup_overlay = rk3568_vop2_setup_overlay, +}; + +static const struct vop2_ops rk3588_vop_ops = { + .setup_intf_mux = rk3588_set_intf_mux, + .setup_bg_dly = rk3568_vop2_setup_bg_dly, + .setup_overlay = rk3568_vop2_setup_overlay, +}; + static const struct vop2_data rk3566_vop = { .feature = VOP2_FEATURE_HAS_SYS_GRF, .nr_vps = 3, @@ -631,8 +1598,13 @@ static const struct vop2_data rk3566_vop = { .vp = rk3568_vop_video_ports, .win = rk3568_vop_win_data, .win_size = ARRAY_SIZE(rk3568_vop_win_data), + .cluster_reg = rk3568_vop_cluster_regs, + .nr_cluster_regs = ARRAY_SIZE(rk3568_vop_cluster_regs), + .smart_reg = rk3568_vop_smart_regs, + .nr_smart_regs = ARRAY_SIZE(rk3568_vop_smart_regs), .regs_dump = rk3568_regs_dump, .regs_dump_size = ARRAY_SIZE(rk3568_regs_dump), + .ops = &rk3568_vop_ops, .soc_id = 3566, }; @@ -644,8 +1616,13 @@ static const struct vop2_data rk3568_vop = { .vp = rk3568_vop_video_ports, .win = rk3568_vop_win_data, .win_size = ARRAY_SIZE(rk3568_vop_win_data), + .cluster_reg = rk3568_vop_cluster_regs, + .nr_cluster_regs = ARRAY_SIZE(rk3568_vop_cluster_regs), + .smart_reg = rk3568_vop_smart_regs, + .nr_smart_regs = ARRAY_SIZE(rk3568_vop_smart_regs), .regs_dump = rk3568_regs_dump, .regs_dump_size = ARRAY_SIZE(rk3568_regs_dump), + .ops = &rk3568_vop_ops, .soc_id = 3568, }; @@ -658,8 +1635,13 @@ static const struct vop2_data rk3588_vop = { .vp = rk3588_vop_video_ports, .win = rk3588_vop_win_data, .win_size = ARRAY_SIZE(rk3588_vop_win_data), + .cluster_reg = rk3568_vop_cluster_regs, + .nr_cluster_regs = ARRAY_SIZE(rk3568_vop_cluster_regs), + .smart_reg = rk3568_vop_smart_regs, + .nr_smart_regs = ARRAY_SIZE(rk3568_vop_smart_regs), .regs_dump = rk3588_regs_dump, .regs_dump_size = ARRAY_SIZE(rk3588_regs_dump), + .ops = &rk3588_vop_ops, .soc_id = 3588, }; From patchwork Tue Oct 29 09:55:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854579 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3A7EBD2AB14 for ; Tue, 29 Oct 2024 09:55:40 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DE31210E5FC; Tue, 29 Oct 2024 09:55:37 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="qLRwsqLD"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.4]) by gabe.freedesktop.org (Postfix) with ESMTP id 413EC10E13B for ; Tue, 29 Oct 2024 09:55:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=gO972 vPWIhe4zly4yr2H4uC4lZBv1i4XKsX7IhxkJlo=; b=qLRwsqLD+LZ64UuOjTQ7S jZhHh0zdl4gyADooNULb6KVqrtU84LWyc+oBej7LwUMP4USXbyOgYXMmaHHoWZrE Rvf2B91txhPyYPvEO2U7jPE6Wp6YkL0jXp81/trNnX7hn0IvFo1LLJBC5QcvQz5K +HKzu1eTejTDRZncZjHSe4= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S10; Tue, 29 Oct 2024 17:55:27 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 08/14] drm/rockchip: vop2: Support for different layer select configuration between VPs Date: Tue, 29 Oct 2024 17:55:01 +0800 Message-ID: <20241029095513.391006-9-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S10 X-Coremail-Antispam: 1Uf129KBjvJXoWxtrW8JF4UZF47CF4UWFy8Zrb_yoWfGF43pa yUursIg3Z8Cr45tryUJay8Zr4rGwnxtay3uan3Kw1xGF1rKrWDJF4ktF93A3Z8KF93Zry8 Xw1YgryDZrZrtFJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jF38nUUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbB0hyHXmcgp1S+TwAAsS X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan In the upcoming VOP for rk3576, every VP has it's own LAYER_SEL register, and the configuration value of each VP for the same window maybe different, so extend the layer_sel_id to array, let it can descption the layer select configuration value for different VP. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- Changes in v4: - Typo fix: selet->select drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 4 +-- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 38 ++++++++++---------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index b27163f561dea..9b269f6e576e8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -163,9 +163,9 @@ struct vop2_win_data { const unsigned int supported_rotations; /** - * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2 + * @layer_sel_id: defined by register OVERLAY_LAYER_SEL or PORTn_LAYER_SEL */ - unsigned int layer_sel_id; + unsigned int layer_sel_id[ROCKCHIP_MAX_CRTC]; uint64_t feature; unsigned int max_upscale_factor; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 0e577aabc9e49..8473dc9c232c1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -342,7 +342,8 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .formats = formats_smart, .nformats = ARRAY_SIZE(formats_smart), .format_modifiers = format_modifiers, - .layer_sel_id = 3, + /* 0xf means this layer can't attached to this VP */ + .layer_sel_id = { 3, 3, 3, 0xf }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_PRIMARY, .max_upscale_factor = 8, @@ -355,7 +356,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_smart), .format_modifiers = format_modifiers, .base = 0x1e00, - .layer_sel_id = 7, + .layer_sel_id = { 7, 7, 7, 0xf }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_PRIMARY, .max_upscale_factor = 8, @@ -368,7 +369,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_rk356x_esmart), .format_modifiers = format_modifiers, .base = 0x1a00, - .layer_sel_id = 6, + .layer_sel_id = { 6, 6, 6, 0xf }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_PRIMARY, .max_upscale_factor = 8, @@ -381,7 +382,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_rk356x_esmart), .format_modifiers = format_modifiers, .base = 0x1800, - .layer_sel_id = 2, + .layer_sel_id = { 2, 2, 2, 0xf }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_PRIMARY, .max_upscale_factor = 8, @@ -394,7 +395,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 0, + .layer_sel_id = { 0, 0, 0, 0xf }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .max_upscale_factor = 4, @@ -409,7 +410,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 1, + .layer_sel_id = { 1, 1, 1, 0xf }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_OVERLAY, @@ -574,7 +575,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 0, + .layer_sel_id = { 0, 0, 0, 0 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .max_upscale_factor = 4, @@ -589,7 +590,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 1, + .layer_sel_id = { 1, 1, 1, 1 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_PRIMARY, @@ -604,7 +605,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 4, + .layer_sel_id = { 4, 4, 4, 4 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_PRIMARY, @@ -619,7 +620,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 5, + .layer_sel_id = { 5, 5, 5, 5 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_PRIMARY, @@ -634,7 +635,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, .base = 0x1800, - .layer_sel_id = 2, + .layer_sel_id = { 2, 2, 2, 2 }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_OVERLAY, .max_upscale_factor = 8, @@ -647,7 +648,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, .base = 0x1a00, - .layer_sel_id = 3, + .layer_sel_id = { 3, 3, 3, 3 }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_OVERLAY, .max_upscale_factor = 8, @@ -660,7 +661,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_esmart, .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, - .layer_sel_id = 6, + .layer_sel_id = { 6, 6, 6, 6 }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_OVERLAY, .max_upscale_factor = 8, @@ -673,7 +674,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, .base = 0x1e00, - .layer_sel_id = 7, + .layer_sel_id = { 7, 7, 7, 7 }, .supported_rotations = DRM_MODE_REFLECT_Y, .type = DRM_PLANE_TYPE_OVERLAY, .max_upscale_factor = 8, @@ -1420,7 +1421,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) */ for (old_layer_id = 0; old_layer_id < vop2->data->win_size; old_layer_id++) { layer_sel_id = (layer_sel >> (4 * old_layer_id)) & 0xf; - if (layer_sel_id == win->data->layer_sel_id) + if (layer_sel_id == win->data->layer_sel_id[vp->id]) break; } @@ -1430,7 +1431,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) for (i = 0; i < vop2->data->win_size; i++) { old_win = &vop2->win[i]; layer_sel_id = (layer_sel >> (4 * (plane->state->normalized_zpos + ofs))) & 0xf; - if (layer_sel_id == old_win->data->layer_sel_id) + if (layer_sel_id == old_win->data->layer_sel_id[vp->id]) break; } @@ -1480,13 +1481,14 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, 0x7); layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, - win->data->layer_sel_id); + win->data->layer_sel_id[vp->id]); /* * When we bind a window from layerM to layerN, we also need to move the old * window on layerN to layerM to avoid one window selected by two or more layers. */ layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, 0x7); - layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, old_win->data->layer_sel_id); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, + old_win->data->layer_sel_id[vp->id]); } vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); From patchwork Tue Oct 29 09:55:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854583 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0CDC9D2AB11 for ; Tue, 29 Oct 2024 09:55:52 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 13D3010E600; Tue, 29 Oct 2024 09:55:50 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="JHYa7XiV"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.4]) by gabe.freedesktop.org (Postfix) with ESMTP id 1064C10E5FB for ; Tue, 29 Oct 2024 09:55:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=p037w Wfo3tumQW4UJk0pIjLuOAeGXDeRm1d46l7m6Po=; b=JHYa7XiVo9rSbEFimBhY1 jYdf3N78yn/ZbFl3OoB6lSu+fqnmC7m84VPbV8FPMvp9vBbwtBc7dRxOYacnkhDr GaKFPcnIKEZGUrejbLosBaZO81QCJxzzVzcS2XOzrzBETd9BRaDSEKpTGG0qbJEq zNprCi8QeN711By1faogPo= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S11; Tue, 29 Oct 2024 17:55:28 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 09/14] drm/rockchip: vop2: Introduce vop hardware version Date: Tue, 29 Oct 2024 17:55:02 +0800 Message-ID: <20241029095513.391006-10-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S11 X-Coremail-Antispam: 1Uf129KBjvJXoW3Xry3ZFWkurWfuFWrtr43Wrg_yoW7CFW3pF W7AFWYqrWxGa12gws7Xay3ZF4aywn7AayxGanrGw13tasxKr9rG3Z0qF1ayFs0qFnFkr42 krs7A34UWF42yr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jF38nUUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMx6HXmcgqJmkJQAAsD X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan There is a version number hardcoded in the VOP VERSION_INFO register, and the version number increments sequentially based on the production order of the SOC. So using this version number to distinguish different VOP features will simplify the code. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v3) Changes in v3: - Add comments for why we should treat rk3566 with special care. - Add hardware version check Changes in v2: - Introduce vop hardware version drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 17 ++++++++++++++--- drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 11 +++++++++++ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 3 +++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 6a7982ad35509..b4964c70149f9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -354,7 +354,7 @@ static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode) static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format) { - if (vop2->data->soc_id == 3588) { + if (vop2->version == VOP_VERSION_RK3588) { if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 || bus_format == MEDIA_BUS_FMT_YUV10_1X30) return true; @@ -798,6 +798,7 @@ static void rk3588_vop2_power_domain_enable_all(struct vop2 *vop2) static void vop2_enable(struct vop2 *vop2) { int ret; + u32 version; ret = pm_runtime_resume_and_get(vop2->dev); if (ret < 0) { @@ -817,10 +818,19 @@ static void vop2_enable(struct vop2 *vop2) return; } + version = vop2_readl(vop2, RK3568_VERSION_INFO); + if (version != vop2->version) { + drm_err(vop2->drm, "Hardware version(0x%08x) mismatch\n", version); + return; + } + /* + * rk3566 share the same vop version with rk3568, so + * wen need to use soc_id for identification here. + */ if (vop2->data->soc_id == 3566) vop2_writel(vop2, RK3568_OTP_WIN_EN, 1); - if (vop2->data->soc_id == 3588) + if (vop2->version == VOP_VERSION_RK3588) rk3588_vop2_power_domain_enable_all(vop2); vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); @@ -1231,7 +1241,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, * this bit is gating disable, we should write 1 to * disable gating when enable afbc. */ - if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568) + if (vop2->version == VOP_VERSION_RK3568) vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0); else vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1); @@ -2320,6 +2330,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) vop2->dev = dev; vop2->data = vop2_data; vop2->ops = vop2_data->ops; + vop2->version = vop2_data->version; vop2->drm = drm; dev_set_drvdata(dev, vop2); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 9b269f6e576e8..871d9bcd1d80e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -13,6 +13,15 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" +#define VOP2_VERSION(major, minor, build) ((major) << 24 | (minor) << 16 | (build)) + +/* The new SOC VOP version is bigger than the old */ +#define VOP_VERSION_RK3568 VOP2_VERSION(0x40, 0x15, 0x8023) +#define VOP_VERSION_RK3588 VOP2_VERSION(0x40, 0x17, 0x6786) +#define VOP_VERSION_RK3528 VOP2_VERSION(0x50, 0x17, 0x1263) +#define VOP_VERSION_RK3562 VOP2_VERSION(0x50, 0x17, 0x4350) +#define VOP_VERSION_RK3576 VOP2_VERSION(0x50, 0x19, 0x9765) + #define VOP2_VP_FEATURE_OUTPUT_10BIT BIT(0) #define VOP2_FEATURE_HAS_SYS_GRF BIT(0) @@ -235,6 +244,7 @@ struct vop2_ops { struct vop2_data { u8 nr_vps; u64 feature; + u32 version; const struct vop2_ops *ops; const struct vop2_win_data *win; const struct vop2_video_port_data *vp; @@ -252,6 +262,7 @@ struct vop2_data { }; struct vop2 { + u32 version; struct device *dev; struct drm_device *drm; struct vop2_video_port vps[ROCKCHIP_MAX_CRTC]; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 8473dc9c232c1..efd704464fabf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -1593,6 +1593,7 @@ static const struct vop2_ops rk3588_vop_ops = { }; static const struct vop2_data rk3566_vop = { + .version = VOP_VERSION_RK3568, .feature = VOP2_FEATURE_HAS_SYS_GRF, .nr_vps = 3, .max_input = { 4096, 2304 }, @@ -1611,6 +1612,7 @@ static const struct vop2_data rk3566_vop = { }; static const struct vop2_data rk3568_vop = { + .version = VOP_VERSION_RK3568, .feature = VOP2_FEATURE_HAS_SYS_GRF, .nr_vps = 3, .max_input = { 4096, 2304 }, @@ -1629,6 +1631,7 @@ static const struct vop2_data rk3568_vop = { }; static const struct vop2_data rk3588_vop = { + .version = VOP_VERSION_RK3588, .feature = VOP2_FEATURE_HAS_SYS_GRF | VOP2_FEATURE_HAS_VO1_GRF | VOP2_FEATURE_HAS_VOP_GRF | VOP2_FEATURE_HAS_SYS_PMU, .nr_vps = 4, From patchwork Tue Oct 29 09:55:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854585 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D4DC3D2AB11 for ; Tue, 29 Oct 2024 09:56:02 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 330CD10E601; Tue, 29 Oct 2024 09:56:02 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="hzqWU9A+"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.5]) by gabe.freedesktop.org (Postfix) with ESMTP id 74C1810E5FE for ; Tue, 29 Oct 2024 09:55:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=2K18z rS3b6QRZrom3kgySEmB2nRHDJXT/VicnhzDTCo=; b=hzqWU9A+TwHh3NZoeeVBt vaOPgffeIj0OayE25mXs1qJqXmGcVrvUy9FW2DL7TDLbDZAI0F3reHiQiDatugdl CbTi4uTfHaLrLSbIYJEQvV/z+1fYJuDl4dGp6pL9zeZ99e75sJuBqkdUvDNcTN/V 4GO3GALYxAisKfVte06Eks= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3nxoCsSBn8+3dEA--.3291S12; Tue, 29 Oct 2024 17:55:29 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 10/14] drm/rockchip: vop2: Register the primary plane and overlay plane separately Date: Tue, 29 Oct 2024 17:55:03 +0800 Message-ID: <20241029095513.391006-11-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3nxoCsSBn8+3dEA--.3291S12 X-Coremail-Antispam: 1Uf129KBjvJXoWxGFWxtw4kKr17ZF18AF18Xwb_yoWrZrWDpa 13ta90yr4xWrsFgry8AF4jyFWYyan2kay7Crs8Jw1a934Sgr93ur4rKFn8AF1ruFnrWFya kFW3K39YgF4q9r7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jF-eOUUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/xtbB0hKHXmcgp1S+egAAsp X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan In the upcoming VOP of rk3576, a Window cannot attach to all Video Ports, so make sure all VP find it's suitable primary plane, then register the remain windows as overlay plane will make code easier. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v3) Changes in v3: - Add comments for why we should treat rk3566 with special care. drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 100 +++++++++++-------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index b4964c70149f9..e293310b30420 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2024,22 +2024,29 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, return 0; } -static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2) +/* + * On RK3566 these windows don't have an independent + * framebuffer. They can only share/mirror the framebuffer + * with smart0, esmart0 and cluster0 respectively. + * And RK3566 share the same vop version with Rk3568, so we + * need to use soc_id for identification here. + */ +static bool vop2_is_mirror_win(struct vop2_win *win) { - int i; - - for (i = 0; i < vop2->data->nr_vps; i++) { - struct vop2_video_port *vp = &vop2->vps[i]; - - if (!vp->crtc.port) - continue; - if (vp->primary_plane) - continue; + struct vop2 *vop2 = win->vop2; - return vp; + if (vop2->data->soc_id == 3566) { + switch (win->data->phys_id) { + case ROCKCHIP_VOP2_SMART1: + case ROCKCHIP_VOP2_ESMART1: + case ROCKCHIP_VOP2_CLUSTER1: + return true; + default: + return false; + } + } else { + return false; } - - return NULL; } static int vop2_create_crtcs(struct vop2 *vop2) @@ -2050,7 +2057,9 @@ static int vop2_create_crtcs(struct vop2 *vop2) struct drm_plane *plane; struct device_node *port; struct vop2_video_port *vp; - int i, nvp, nvps = 0; + struct vop2_win *win; + u32 possible_crtcs; + int i, j, nvp, nvps = 0; int ret; for (i = 0; i < vop2_data->nr_vps; i++) { @@ -2089,42 +2098,55 @@ static int vop2_create_crtcs(struct vop2 *vop2) } nvp = 0; - for (i = 0; i < vop2->registered_num_wins; i++) { - struct vop2_win *win = &vop2->win[i]; - u32 possible_crtcs = 0; - - if (vop2->data->soc_id == 3566) { - /* - * On RK3566 these windows don't have an independent - * framebuffer. They share the framebuffer with smart0, - * esmart0 and cluster0 respectively. - */ - switch (win->data->phys_id) { - case ROCKCHIP_VOP2_SMART1: - case ROCKCHIP_VOP2_ESMART1: - case ROCKCHIP_VOP2_CLUSTER1: + /* Register a primary plane for every crtc */ + for (i = 0; i < vop2_data->nr_vps; i++) { + vp = &vop2->vps[i]; + + if (!vp->crtc.port) + continue; + + for (j = 0; j < vop2->registered_num_wins; j++) { + win = &vop2->win[j]; + + /* Aready registered as primary plane */ + if (win->base.type == DRM_PLANE_TYPE_PRIMARY) + continue; + + if (vop2_is_mirror_win(win)) continue; - } - } - if (win->type == DRM_PLANE_TYPE_PRIMARY) { - vp = find_vp_without_primary(vop2); - if (vp) { + if (win->type == DRM_PLANE_TYPE_PRIMARY) { possible_crtcs = BIT(nvp); vp->primary_plane = win; + ret = vop2_plane_init(vop2, win, possible_crtcs); + if (ret) { + drm_err(vop2->drm, "failed to init primary plane %s: %d\n", + win->data->name, ret); + return ret; + } nvp++; - } else { - /* change the unused primary window to overlay window */ - win->type = DRM_PLANE_TYPE_OVERLAY; + break; } } + } + + /* Register all unused window as overlay plane */ + for (i = 0; i < vop2->registered_num_wins; i++) { + win = &vop2->win[i]; + + /* Aready registered as primary plane */ + if (win->base.type == DRM_PLANE_TYPE_PRIMARY) + continue; + + if (vop2_is_mirror_win(win)) + continue; - if (win->type == DRM_PLANE_TYPE_OVERLAY) - possible_crtcs = (1 << nvps) - 1; + win->type = DRM_PLANE_TYPE_OVERLAY; + possible_crtcs = (1 << nvps) - 1; ret = vop2_plane_init(vop2, win, possible_crtcs); if (ret) { - drm_err(vop2->drm, "failed to init plane %s: %d\n", + drm_err(vop2->drm, "failed to init overlay plane %s: %d\n", win->data->name, ret); return ret; } From patchwork Tue Oct 29 09:57:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854588 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id ED133D2AB13 for ; Tue, 29 Oct 2024 09:57:37 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0F88910E602; Tue, 29 Oct 2024 09:57:37 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="kSvkhaH6"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.5]) by gabe.freedesktop.org (Postfix) with ESMTP id 1126710E602 for ; Tue, 29 Oct 2024 09:57:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=hko8H LeJVCtg5vYzlfNWu7c2UKqmiEp/cfawOZQluVs=; b=kSvkhaH60zFLxR2cWEyRI jG4XganOtaxtHOj0PMulD2Tik9IhIR0Z1m75szHoAvMlZ+ra3dJq0ca8VfIXR4xA nnMjzTpx+htPPQvYfyxIZwrHR9v7Pa/AuuHyZhgpmFGLR1EIHWelcC3hGxj2jbx0 /7DEsOeEs+VHp01kdm6eRM= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g0-0 (Coremail) with SMTP id _____wD3_1WBsSBnLXlDCA--.941S2; Tue, 29 Oct 2024 17:57:25 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 11/14] drm/rockchip: vop2: Set plane possible crtcs by possible vp mask Date: Tue, 29 Oct 2024 17:57:16 +0800 Message-ID: <20241029095720.391076-1-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3_1WBsSBnLXlDCA--.941S2 X-Coremail-Antispam: 1Uf129KBjvJXoWxtrW8JFWkXF43Zr17tw45GFg_yoWxKrW3pa yxZFnxWF43Cr4agry7Ja98ZFyak3sxAw4a93ZrKFsxKr13Kry7Wr1UK3Z8CF1DWFy8Zr1j vw43tryDur17tFJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jnhL8UUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMwSHXmcgqJms1QAAsh X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan In the upcoming VOP of rk3576, a window cannot attach to all Video Ports, we introduce a possible_vp_mask for every window to indicate which Video Ports this window can attach to. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v1) drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 18 +++++++++++++++++- drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 + drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index e293310b30420..9603bd8491bc3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2112,6 +2112,10 @@ static int vop2_create_crtcs(struct vop2 *vop2) if (win->base.type == DRM_PLANE_TYPE_PRIMARY) continue; + /* If this win can not attached to this VP */ + if (!(win->data->possible_vp_mask & BIT(vp->id))) + continue; + if (vop2_is_mirror_win(win)) continue; @@ -2143,7 +2147,19 @@ static int vop2_create_crtcs(struct vop2 *vop2) win->type = DRM_PLANE_TYPE_OVERLAY; - possible_crtcs = (1 << nvps) - 1; + possible_crtcs = 0; + nvp = 0; + for (j = 0; j < vop2_data->nr_vps; j++) { + vp = &vop2->vps[j]; + + if (!vp->crtc.port) + continue; + + if (win->data->possible_vp_mask & BIT(vp->id)) + possible_crtcs |= BIT(nvp); + nvp++; + } + ret = vop2_plane_init(vop2, win, possible_crtcs); if (ret) { drm_err(vop2->drm, "failed to init overlay plane %s: %d\n", diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 871d9bcd1d80e..064167afebf49 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -164,6 +164,7 @@ struct vop2_win_data { unsigned int phys_id; u32 base; + u32 possible_vp_mask; enum drm_plane_type type; u32 nformats; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index efd704464fabf..95e31ee84f4f2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -339,6 +339,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .name = "Smart0-win0", .phys_id = ROCKCHIP_VOP2_SMART0, .base = 0x1c00, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2), .formats = formats_smart, .nformats = ARRAY_SIZE(formats_smart), .format_modifiers = format_modifiers, @@ -352,6 +353,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { }, { .name = "Smart1-win0", .phys_id = ROCKCHIP_VOP2_SMART1, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2), .formats = formats_smart, .nformats = ARRAY_SIZE(formats_smart), .format_modifiers = format_modifiers, @@ -365,6 +367,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { }, { .name = "Esmart1-win0", .phys_id = ROCKCHIP_VOP2_ESMART1, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2), .formats = formats_rk356x_esmart, .nformats = ARRAY_SIZE(formats_rk356x_esmart), .format_modifiers = format_modifiers, @@ -378,6 +381,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { }, { .name = "Esmart0-win0", .phys_id = ROCKCHIP_VOP2_ESMART0, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2), .formats = formats_rk356x_esmart, .nformats = ARRAY_SIZE(formats_rk356x_esmart), .format_modifiers = format_modifiers, @@ -392,6 +396,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .name = "Cluster0-win0", .phys_id = ROCKCHIP_VOP2_CLUSTER0, .base = 0x1000, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2), .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, @@ -407,6 +412,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .name = "Cluster1-win0", .phys_id = ROCKCHIP_VOP2_CLUSTER1, .base = 0x1200, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2), .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, @@ -572,6 +578,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .name = "Cluster0-win0", .phys_id = ROCKCHIP_VOP2_CLUSTER0, .base = 0x1000, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, @@ -587,6 +594,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .name = "Cluster1-win0", .phys_id = ROCKCHIP_VOP2_CLUSTER1, .base = 0x1200, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, @@ -602,6 +610,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .name = "Cluster2-win0", .phys_id = ROCKCHIP_VOP2_CLUSTER2, .base = 0x1400, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, @@ -617,6 +626,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .name = "Cluster3-win0", .phys_id = ROCKCHIP_VOP2_CLUSTER3, .base = 0x1600, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_cluster, .nformats = ARRAY_SIZE(formats_cluster), .format_modifiers = format_modifiers_afbc, @@ -631,6 +641,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { }, { .name = "Esmart0-win0", .phys_id = ROCKCHIP_VOP2_ESMART0, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_esmart, .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, @@ -644,6 +655,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { }, { .name = "Esmart1-win0", .phys_id = ROCKCHIP_VOP2_ESMART1, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_esmart, .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, @@ -658,6 +670,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .name = "Esmart2-win0", .phys_id = ROCKCHIP_VOP2_ESMART2, .base = 0x1c00, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_esmart, .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, @@ -670,6 +683,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { }, { .name = "Esmart3-win0", .phys_id = ROCKCHIP_VOP2_ESMART3, + .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3), .formats = formats_esmart, .nformats = ARRAY_SIZE(formats_esmart), .format_modifiers = format_modifiers, From patchwork Tue Oct 29 09:57:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854600 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 27F70D2AB13 for ; Tue, 29 Oct 2024 09:57:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9A5A610E605; Tue, 29 Oct 2024 09:57:49 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="IQupB7NM"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.2]) by gabe.freedesktop.org (Postfix) with ESMTP id 1EEA610E605 for ; Tue, 29 Oct 2024 09:57:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=Ebd2N R+FrvOf/s5g3A8lj2DRjveKn76Ov6EDVujGgZ0=; b=IQupB7NMRW6Y54FbKabYP YyKOh988v8GoiHYCK3HOwAgIrUpKTrdmmYqtl6IdTioccHNH+Qi+/MHJgGNzxGpk 524knLKmRdPC5UTj/aUWv4uCL/uXtvqo1Xf04sojr+BKp59JP6Ju7s3lLvFBG8Bt dyXG2LBkDBczsBy3u4rqNY= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wDXXwWNsSBntUreEA--.3518S2; Tue, 29 Oct 2024 17:57:37 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 12/14] drm/rockchip: vop2: Add uv swap for cluster window Date: Tue, 29 Oct 2024 17:57:31 +0800 Message-ID: <20241029095732.391105-1-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wDXXwWNsSBntUreEA--.3518S2 X-Coremail-Antispam: 1Uf129KBjvJXoW7tFW8Ww1kAF4UAw47JFy7ZFb_yoW8XrWkpr 43ArWqgw45Kws2q34DJFW5ZFWfJwnxKayxZwsrtw1F9ry3KFyDGwn0kFWUAr1qyanFkF47 tF93XrW7Zr4jvrJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jnOzsUUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiqRaHXmcgr44kwAAAsk X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan The Cluster windows of upcoming VOP on rk3576 also support linear YUV support, we need to set uv swap bit for it. As the VOP2_WIN_UV_SWA register defined on rk3568/rk3588 is 0xffffffff, so this register will not be touched on these two platforms. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v1) drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 9603bd8491bc3..84c67f5d267f6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1284,10 +1284,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, rb_swap = vop2_win_rb_swap(fb->format->format); vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap); - if (!vop2_cluster_window(win)) { - uv_swap = vop2_win_uv_swap(fb->format->format); - vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); - } + uv_swap = vop2_win_uv_swap(fb->format->format); + vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); if (fb->format->is_yuv) { vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4)); From patchwork Tue Oct 29 09:57:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854601 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DA602D2AB13 for ; Tue, 29 Oct 2024 09:57:59 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4216810E603; Tue, 29 Oct 2024 09:57:59 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="DSpswal2"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.4]) by gabe.freedesktop.org (Postfix) with ESMTP id 43EAE10E603 for ; Tue, 29 Oct 2024 09:57:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=yxux1 By2rnGvzR/PFyyiJzKm2Pk7omvqYG5lZ9tl4rk=; b=DSpswal2Zm/aheRuKJx2V fS5U4Lryow77QLGUaBTOAcI1SHQp6riOHVMLGgrN8osMeNTcNMaBwWwq7T9Nq/G2 EyMAgoR+c65Ip0C86iOfkU+wW4r7wGuvbHmmWjUfzAwgnHNe+ux3BUGBrSL+qk+N h69hCruroxFw6KM2BtVfgA= Received: from ProDesk.. (unknown [58.22.7.114]) by gzsmtp1 (Coremail) with SMTP id PCgvCgBn7OKZsSBncgm2Bg--.53474S2; Tue, 29 Oct 2024 17:57:49 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Krzysztof Kozlowski Subject: [PATCH v4 13/14] dt-bindings: display: vop2: Add rk3576 support Date: Tue, 29 Oct 2024 17:57:42 +0800 Message-ID: <20241029095744.391134-1-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: PCgvCgBn7OKZsSBncgm2Bg--.53474S2 X-Coremail-Antispam: 1Uf129KBjvJXoW7WrWrKFW5try7CFWkWw17Wrg_yoW8WF4Upa 93CF9rXry8GF17X34kGF1rCrs8XF97Aa13GF4ktw1xtrsxKrsYgw4agrn8Zr45GFyxZaya 9F4ak34UJ392vrJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07UBMKtUUUUU= X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiqQqHXmcgr44lkQAAso X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan Add vop found on rk3576, the main difference between rk3576 and the previous vop is that each VP has its own interrupt line. Signed-off-by: Andy Yan Reviewed-by: Krzysztof Kozlowski --- (no changes since v3) Changes in v3: - ordered by soc name - Add description for newly added interrupt Changes in v2: - Add dt bindings .../bindings/display/rockchip/rockchip-vop2.yaml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml index 2531726af306b..a44964b6c36a0 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,rk3576-vop - rockchip,rk3588-vop reg: @@ -37,10 +38,14 @@ properties: - const: gamma-lut interrupts: - maxItems: 1 - description: - The VOP interrupt is shared by several interrupt sources, such as - frame start (VSYNC), line flag and other status interrupts. + minItems: 1 + items: + - description: + vop system interrupt, such as bus error, and vsync for vop version under + rk3576. + - description: + independent interrupts for each video port, such as vsync and other video + port related error interrupts. # See compatible-specific constraints below. clocks: From patchwork Tue Oct 29 09:57:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Yan X-Patchwork-Id: 13854602 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A8880D2AB14 for ; Tue, 29 Oct 2024 09:58:17 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D66EF10E607; Tue, 29 Oct 2024 09:58:16 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=163.com header.i=@163.com header.b="dL3AylFz"; dkim-atps=neutral Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.2]) by gabe.freedesktop.org (Postfix) with ESMTP id 54FB310E607 for ; Tue, 29 Oct 2024 09:58:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=0qp08 NMAg0+RSY58yqBKhPP2lUW//Rxs6NNMmedM0v0=; b=dL3AylFzYLtbB2VH4ca5U Dq4SC1gSYjSUmUrwwu0N2KLUpCM/pp+wkBYZU5M9a1qM0SZUQR1HTqi9+iPYAjx2 zIdiXHbMYqXviSZB2Byr/l/CMIdo8SUShaIeP0M6KhyeRYwI+Il94gz9mjuKCloX BSxgX+S9xp+jGxfAW69C6k= Received: from ProDesk.. (unknown [58.22.7.114]) by gzga-smtp-mtada-g1-1 (Coremail) with SMTP id _____wD3_zemsSBnJ1veEA--.3294S2; Tue, 29 Oct 2024 17:58:02 +0800 (CST) From: Andy Yan To: heiko@sntech.de Cc: hjc@rock-chips.com, krzk+dt@kernel.org, s.hauer@pengutronix.de, devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, derek.foreman@collabora.com, minhuadotchen@gmail.com, detlev.casanova@collabora.com, Andy Yan , Michael Riesch Subject: [PATCH v4 14/14] drm/rockchip: vop2: Add support for rk3576 Date: Tue, 29 Oct 2024 17:57:55 +0800 Message-ID: <20241029095757.391165-1-andyshrk@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241029095513.391006-1-andyshrk@163.com> References: <20241029095513.391006-1-andyshrk@163.com> MIME-Version: 1.0 X-CM-TRANSID: _____wD3_zemsSBnJ1veEA--.3294S2 X-Coremail-Antispam: 1Uf129KBjvAXoWDCFW3Jry5CFyDZrW8ArykGrg_yoW7Jr4DZo W3CFnIqryxt34Sk395Gr17XFyxWF4vkan7ur1IyFy2k3y3X3y5Cryxt3ZIqF4ayw45CFWr A3sYq3WrZFWfZw1xn29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxU2nmRUUUUU X-Originating-IP: [58.22.7.114] X-CM-SenderInfo: 5dqg52xkunqiywtou0bp/1tbiMwCHXmcgqJmvhAAAs3 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Andy Yan VOP2 on rk3576: Three video ports: VP0 Max 4096x2160 VP1 Max 2560x1600 VP2 Max 1920x1080 2 4K Cluster windows with AFBC/RFBC, line RGB and YUV 4 Esmart windows with line RGB/YUV support: Esmart0/1: 4K Esmart2/3: 2k, or worked together as a single 4K plane at shared line buffer mode. Compared to the previous VOP, another difference is that each VP has its own independent vsync interrupt number. Signed-off-by: Andy Yan Tested-by: Michael Riesch # on RK3568 Tested-by: Detlev Casanova --- (no changes since v3) Changes in v3: - Share the alpha setup function with rk3568 - recoder the code block by soc Changes in v2: - Add platform specific callback drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 144 +++- drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 87 +++ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 780 ++++++++++++++++++- 3 files changed, 956 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 84c67f5d267f6..e25904e4f97ba 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1187,6 +1187,9 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, &fb->format->format, afbc_en ? "AFBC" : "", &yrgb_mst); + if (vop2->version >= VOP_VERSION_RK3576) + vop2_win_write(win, VOP2_WIN_VP_SEL, vp->id); + if (vop2_cluster_window(win)) vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, half_block_en); @@ -1251,6 +1254,11 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, else vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0); + if (vop2->version >= VOP_VERSION_RK3576) { + vop2_win_write(win, VOP2_WIN_AFBC_PLD_OFFSET_EN, 1); + vop2_win_write(win, VOP2_WIN_AFBC_PLD_OFFSET, yrgb_mst); + } + 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); @@ -1919,6 +1927,56 @@ static const struct drm_crtc_funcs vop2_crtc_funcs = { .late_register = vop2_crtc_late_register, }; +static irqreturn_t rk3576_vp_isr(int irq, void *data) +{ + struct vop2_video_port *vp = data; + struct vop2 *vop2 = vp->vop2; + struct drm_crtc *crtc = &vp->crtc; + uint32_t irqs; + int ret = IRQ_NONE; + + /* + * The irq is shared with the iommu. If the runtime-pm state of the + * vop2-device is disabled the irq has to be targeted at the iommu. + */ + if (!pm_runtime_get_if_in_use(vop2->dev)) + return IRQ_NONE; + + irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id)); + vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs); + + if (irqs & VP_INT_DSP_HOLD_VALID) { + complete(&vp->dsp_hold_completion); + ret = IRQ_HANDLED; + } + + if (irqs & VP_INT_FS_FIELD) { + drm_crtc_handle_vblank(crtc); + spin_lock(&crtc->dev->event_lock); + if (vp->event) { + u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); + + if (!(val & BIT(vp->id))) { + drm_crtc_send_vblank_event(crtc, vp->event); + vp->event = NULL; + drm_crtc_vblank_put(crtc); + } + } + spin_unlock(&crtc->dev->event_lock); + + ret = IRQ_HANDLED; + } + + if (irqs & VP_INT_POST_BUF_EMPTY) { + drm_err_ratelimited(vop2->drm, "POST_BUF_EMPTY irq err at vp%d\n", vp->id); + ret = IRQ_HANDLED; + } + + pm_runtime_put(vop2->dev); + + return ret; +} + static irqreturn_t vop2_isr(int irq, void *data) { struct vop2 *vop2 = data; @@ -1934,41 +1992,43 @@ static irqreturn_t vop2_isr(int irq, void *data) if (!pm_runtime_get_if_in_use(vop2->dev)) return IRQ_NONE; - for (i = 0; i < vop2_data->nr_vps; i++) { - struct vop2_video_port *vp = &vop2->vps[i]; - struct drm_crtc *crtc = &vp->crtc; - u32 irqs; + if (vop2->version < VOP_VERSION_RK3576) { + for (i = 0; i < vop2_data->nr_vps; i++) { + struct vop2_video_port *vp = &vop2->vps[i]; + struct drm_crtc *crtc = &vp->crtc; + u32 irqs; - irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id)); - vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs); + irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id)); + vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs); - if (irqs & VP_INT_DSP_HOLD_VALID) { - complete(&vp->dsp_hold_completion); - ret = IRQ_HANDLED; - } - - if (irqs & VP_INT_FS_FIELD) { - drm_crtc_handle_vblank(crtc); - spin_lock(&crtc->dev->event_lock); - if (vp->event) { - u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); + if (irqs & VP_INT_DSP_HOLD_VALID) { + complete(&vp->dsp_hold_completion); + ret = IRQ_HANDLED; + } - if (!(val & BIT(vp->id))) { - drm_crtc_send_vblank_event(crtc, vp->event); - vp->event = NULL; - drm_crtc_vblank_put(crtc); + if (irqs & VP_INT_FS_FIELD) { + drm_crtc_handle_vblank(crtc); + spin_lock(&crtc->dev->event_lock); + if (vp->event) { + u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); + + if (!(val & BIT(vp->id))) { + drm_crtc_send_vblank_event(crtc, vp->event); + vp->event = NULL; + drm_crtc_vblank_put(crtc); + } } - } - spin_unlock(&crtc->dev->event_lock); + spin_unlock(&crtc->dev->event_lock); - ret = IRQ_HANDLED; - } + ret = IRQ_HANDLED; + } - if (irqs & VP_INT_POST_BUF_EMPTY) { - drm_err_ratelimited(vop2->drm, - "POST_BUF_EMPTY irq err at vp%d\n", - vp->id); - ret = IRQ_HANDLED; + if (irqs & VP_INT_POST_BUF_EMPTY) { + drm_err_ratelimited(vop2->drm, + "POST_BUF_EMPTY irq err at vp%d\n", + vp->id); + ret = IRQ_HANDLED; + } } } @@ -2455,6 +2515,32 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; + if (vop2->version >= VOP_VERSION_RK3576) { + struct drm_crtc *crtc; + + drm_for_each_crtc(crtc, drm) { + struct vop2_video_port *vp = to_vop2_video_port(crtc); + int vp_irq; + const char *irq_name = devm_kasprintf(dev, GFP_KERNEL, "vop-vp%d", vp->id); + + if (!irq_name) + return -ENOMEM; + + vp_irq = platform_get_irq_byname(pdev, irq_name); + if (vp_irq < 0) { + DRM_DEV_ERROR(dev, "cannot find irq for vop2 vp%d\n", vp->id); + return vp_irq; + } + + ret = devm_request_irq(dev, vp_irq, rk3576_vp_isr, IRQF_SHARED, irq_name, + vp); + if (ret) { + DRM_DEV_ERROR(dev, "request irq for vop2 vp%d failed\n", vp->id); + return ret; + } + } + } + ret = vop2_find_rgb_encoder(vop2); if (ret >= 0) { vop2->rgb = rockchip_rgb_init(dev, &vop2->vps[ret].crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 064167afebf49..e2485c2285ad8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -44,6 +44,13 @@ enum win_dly_mode { VOP2_DLY_MODE_MAX, }; +enum vop2_dly_module { + VOP2_DLY_WIN, /** Win delay cycle for this VP */ + VOP2_DLY_LAYER_MIX, /** Layer Mix delay cycle for this VP */ + VOP2_DLY_HDR_MIX, /** HDR delay cycle for this VP */ + VOP2_DLY_MAX, +}; + enum vop2_scale_up_mode { VOP2_SCALE_UP_NRST_NBOR, VOP2_SCALE_UP_BIL, @@ -137,16 +144,22 @@ enum vop2_win_regs { VOP2_WIN_AFBC_UV_SWAP, VOP2_WIN_AFBC_AUTO_GATING_EN, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, + VOP2_WIN_AFBC_PLD_OFFSET_EN, VOP2_WIN_AFBC_PIC_VIR_WIDTH, VOP2_WIN_AFBC_TILE_NUM, VOP2_WIN_AFBC_PIC_OFFSET, VOP2_WIN_AFBC_PIC_SIZE, VOP2_WIN_AFBC_DSP_OFFSET, + VOP2_WIN_AFBC_PLD_OFFSET, VOP2_WIN_AFBC_TRANSFORM_OFFSET, VOP2_WIN_AFBC_HDR_PTR, VOP2_WIN_AFBC_HALF_BLOCK_EN, VOP2_WIN_AFBC_ROTATE_270, VOP2_WIN_AFBC_ROTATE_90, + + VOP2_WIN_VP_SEL, + VOP2_WIN_DLY_NUM, + VOP2_WIN_MAX_REG, }; @@ -208,6 +221,10 @@ struct vop2_video_port_data { struct vop_rect max_output; const u8 pre_scan_max_dly[4]; unsigned int offset; + /** + * @pixel_rate: pixel per cycle + */ + u8 pixel_rate; }; struct vop2_video_port { @@ -365,10 +382,13 @@ enum dst_factor_mode { #define RK3568_REG_CFG_DONE 0x000 #define RK3568_VERSION_INFO 0x004 #define RK3568_SYS_AUTO_GATING_CTRL 0x008 +#define RK3576_SYS_MMU_CTRL_IMD 0x020 #define RK3568_SYS_AXI_LUT_CTRL 0x024 #define RK3568_DSP_IF_EN 0x028 +#define RK3576_SYS_PORT_CTRL_IMD 0x028 #define RK3568_DSP_IF_CTRL 0x02c #define RK3568_DSP_IF_POL 0x030 +#define RK3576_SYS_CLUSTER_PD_CTRL_IMD 0x030 #define RK3588_SYS_PD_CTRL 0x034 #define RK3568_WB_CTRL 0x40 #define RK3568_WB_XSCAL_FACTOR 0x44 @@ -388,6 +408,55 @@ enum dst_factor_mode { #define RK3568_VP_INT_CLR(vp) (0xA4 + (vp) * 0x10) #define RK3568_VP_INT_STATUS(vp) (0xA8 + (vp) * 0x10) #define RK3568_VP_INT_RAW_STATUS(vp) (0xAC + (vp) * 0x10) +#define RK3576_WB_CTRL 0x100 +#define RK3576_WB_XSCAL_FACTOR 0x104 +#define RK3576_WB_YRGB_MST 0x108 +#define RK3576_WB_CBR_MST 0x10C +#define RK3576_WB_VIR_STRIDE 0x110 +#define RK3576_WB_TIMEOUT_CTRL 0x114 +#define RK3576_MIPI0_IF_CTRL 0x180 +#define RK3576_HDMI0_IF_CTRL 0x184 +#define RK3576_EDP0_IF_CTRL 0x188 +#define RK3576_DP0_IF_CTRL 0x18C +#define RK3576_RGB_IF_CTRL 0x194 +#define RK3576_DP1_IF_CTRL 0x1A4 +#define RK3576_DP2_IF_CTRL 0x1B0 + +/* Extra OVL register definition */ +#define RK3576_SYS_EXTRA_ALPHA_CTRL 0x500 +#define RK3576_CLUSTER0_MIX_SRC_COLOR_CTRL 0x530 +#define RK3576_CLUSTER0_MIX_DST_COLOR_CTRL 0x534 +#define RK3576_CLUSTER0_MIX_SRC_ALPHA_CTRL 0x538 +#define RK3576_CLUSTER0_MIX_DST_ALPHA_CTRL 0x53c +#define RK3576_CLUSTER1_MIX_SRC_COLOR_CTRL 0x540 +#define RK3576_CLUSTER1_MIX_DST_COLOR_CTRL 0x544 +#define RK3576_CLUSTER1_MIX_SRC_ALPHA_CTRL 0x548 +#define RK3576_CLUSTER1_MIX_DST_ALPHA_CTRL 0x54c + +/* OVL registers for Video Port definition */ +#define RK3576_OVL_CTRL(vp) (0x600 + (vp) * 0x100) +#define RK3576_OVL_LAYER_SEL(vp) (0x604 + (vp) * 0x100) +#define RK3576_OVL_MIX0_SRC_COLOR_CTRL(vp) (0x620 + (vp) * 0x100) +#define RK3576_OVL_MIX0_DST_COLOR_CTRL(vp) (0x624 + (vp) * 0x100) +#define RK3576_OVL_MIX0_SRC_ALPHA_CTRL(vp) (0x628 + (vp) * 0x100) +#define RK3576_OVL_MIX0_DST_ALPHA_CTRL(vp) (0x62C + (vp) * 0x100) +#define RK3576_OVL_MIX1_SRC_COLOR_CTRL(vp) (0x630 + (vp) * 0x100) +#define RK3576_OVL_MIX1_DST_COLOR_CTRL(vp) (0x634 + (vp) * 0x100) +#define RK3576_OVL_MIX1_SRC_ALPHA_CTRL(vp) (0x638 + (vp) * 0x100) +#define RK3576_OVL_MIX1_DST_ALPHA_CTRL(vp) (0x63C + (vp) * 0x100) +#define RK3576_OVL_MIX2_SRC_COLOR_CTRL(vp) (0x640 + (vp) * 0x100) +#define RK3576_OVL_MIX2_DST_COLOR_CTRL(vp) (0x644 + (vp) * 0x100) +#define RK3576_OVL_MIX2_SRC_ALPHA_CTRL(vp) (0x648 + (vp) * 0x100) +#define RK3576_OVL_MIX2_DST_ALPHA_CTRL(vp) (0x64C + (vp) * 0x100) +#define RK3576_EXTRA_OVL_SRC_COLOR_CTRL(vp) (0x650 + (vp) * 0x100) +#define RK3576_EXTRA_OVL_DST_COLOR_CTRL(vp) (0x654 + (vp) * 0x100) +#define RK3576_EXTRA_OVL_SRC_ALPHA_CTRL(vp) (0x658 + (vp) * 0x100) +#define RK3576_EXTRA_OVL_DST_ALPHA_CTRL(vp) (0x65C + (vp) * 0x100) +#define RK3576_OVL_HDR_SRC_COLOR_CTRL(vp) (0x660 + (vp) * 0x100) +#define RK3576_OVL_HDR_DST_COLOR_CTRL(vp) (0x664 + (vp) * 0x100) +#define RK3576_OVL_HDR_SRC_ALPHA_CTRL(vp) (0x668 + (vp) * 0x100) +#define RK3576_OVL_HDR_DST_ALPHA_CTRL(vp) (0x66C + (vp) * 0x100) +#define RK3576_OVL_BG_MIX_CTRL(vp) (0x670 + (vp) * 0x100) /* Video Port registers definition */ #define RK3568_VP0_CTRL_BASE 0x0C00 @@ -469,7 +538,11 @@ enum dst_factor_mode { #define RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET 0x68 #define RK3568_CLUSTER_WIN_AFBCD_CTRL 0x6C +#define RK3576_CLUSTER_WIN_AFBCD_PLD_PTR_OFFSET 0x78 + #define RK3568_CLUSTER_CTRL 0x100 +#define RK3576_CLUSTER_PORT_SEL_IMD 0x1F4 +#define RK3576_CLUSTER_DLY_NUM 0x1F8 /* (E)smart register definition, offset relative to window base */ #define RK3568_SMART_CTRL0 0x00 @@ -519,6 +592,9 @@ enum dst_factor_mode { #define RK3568_SMART_REGION3_SCL_FACTOR_CBR 0xC8 #define RK3568_SMART_REGION3_SCL_OFFSET 0xCC #define RK3568_SMART_COLOR_KEY_CTRL 0xD0 +#define RK3576_SMART_ALPHA_MAP 0xD8 +#define RK3576_SMART_PORT_SEL_IMD 0xF4 +#define RK3576_SMART_DLY_NUM 0xF8 /* HDR register definition */ #define RK3568_HDR_LUT_CTRL 0x2000 @@ -662,6 +738,17 @@ enum dst_factor_mode { #define POLFLAG_DCLK_INV BIT(3) +#define RK3576_OVL_CTRL__YUV_MODE BIT(0) +#define RK3576_OVL_BG_MIX_CTRL__BG_DLY GENMASK(31, 24) + +#define RK3576_DSP_IF_CFG_DONE_IMD BIT(31) +#define RK3576_DSP_IF_DCLK_SEL_OUT BIT(21) +#define RK3576_DSP_IF_PCLK_DIV BIT(20) +#define RK3576_DSP_IF_PIN_POL GENMASK(5, 4) +#define RK3576_DSP_IF_MUX GENMASK(3, 2) +#define RK3576_DSP_IF_CLK_OUT_EN BIT(1) +#define RK3576_DSP_IF_EN BIT(0) + enum vop2_layer_phy_id { ROCKCHIP_VOP2_CLUSTER0 = 0, ROCKCHIP_VOP2_CLUSTER1, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 95e31ee84f4f2..91c2443567d14 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -70,6 +70,37 @@ static const uint32_t formats_cluster[] = { DRM_FORMAT_Y210, /* yuv422_10bit non-Linear mode only */ }; +/* + * The cluster windows on rk3576 support: + * RGB: linear mode and afbc + * YUV: linear mode and rfbc + * rfbc is a rockchip defined non-linear mode, produced by + * Video decoder + */ +static const uint32_t formats_rk3576_cluster[] = { + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + 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_NV20, /* yuv422_10bit linear mode, 2 plane, no padding */ + DRM_FORMAT_NV30, /* yuv444_10bit linear mode, 2 plane, no padding */ +}; + static const uint32_t formats_esmart[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, @@ -116,6 +147,41 @@ static const uint32_t formats_rk356x_esmart[] = { DRM_FORMAT_VYUY, /* yuv422_8bit[VYUY] linear mode */ }; +/* + * Add XRGB2101010/ARGB2101010ARGB1555/XRGB1555 + */ +static const uint32_t formats_rk3576_esmart[] = { + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + 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_ARGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XBGR1555, + 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_NV20, /* yuv422_10bit linear mode, 2 plane, no padding */ + DRM_FORMAT_NV24, /* yuv444_8bit linear mode, 2 plane */ + DRM_FORMAT_NV42, /* yvu444_8bit linear mode, 2 plane */ + DRM_FORMAT_NV30, /* yuv444_10bit linear mode, 2 plane, no padding */ + 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_smart[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, @@ -169,6 +235,48 @@ static const uint64_t format_modifiers_afbc[] = { DRM_FORMAT_MOD_INVALID, }; +/* used from rk3576, afbc 32*8 half mode */ +static const uint64_t format_modifiers_rk3576_afbc[] = { + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_SPLIT), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPLIT), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_CBR | + AFBC_FORMAT_MOD_SPLIT), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_CBR | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_CBR | + AFBC_FORMAT_MOD_SPLIT), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_CBR | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + + /* SPLIT mandates SPARSE, RGB modes mandates YTR */ + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + static const struct reg_field rk3568_vop_cluster_regs[VOP2_WIN_MAX_REG] = { [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0), [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5), @@ -293,6 +401,136 @@ static const struct reg_field rk3568_vop_smart_regs[VOP2_WIN_MAX_REG] = { [VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff }, }; +static const struct reg_field rk3576_vop_cluster_regs[VOP2_WIN_MAX_REG] = { + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0), + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5), + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14), + [VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 17, 17), + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 18, 18), + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_ACT_INFO, 0, 31), + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_INFO, 0, 31), + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_ST, 0, 31), + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_CLUSTER_WIN_YRGB_MST, 0, 31), + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_CLUSTER_WIN_CBR_MST, 0, 31), + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 19, 19), + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 0, 15), + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 16, 31), + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 8, 8), + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 9, 9), + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 10, 11), + [VOP2_WIN_VP_SEL] = REG_FIELD(RK3576_CLUSTER_PORT_SEL_IMD, 0, 1), + [VOP2_WIN_DLY_NUM] = REG_FIELD(RK3576_CLUSTER_DLY_NUM, 0, 7), + + /* Scale */ + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0, 15), + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 16, 31), + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 2, 3), + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 14, 15), + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 22, 23), + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 28, 28), + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 29, 29), + + /* cluster regs */ + [VOP2_WIN_AFBC_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 1, 1), + [VOP2_WIN_CLUSTER_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 0, 0), + [VOP2_WIN_CLUSTER_LB_MODE] = REG_FIELD(RK3568_CLUSTER_CTRL, 4, 7), + + /* afbc regs */ + [VOP2_WIN_AFBC_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 2, 6), + [VOP2_WIN_AFBC_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 9, 9), + [VOP2_WIN_AFBC_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 10, 10), + [VOP2_WIN_AFBC_AUTO_GATING_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 4, 4), + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 7, 7), + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 8, 8), + [VOP2_WIN_AFBC_PLD_OFFSET_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 16, 16), + [VOP2_WIN_AFBC_HDR_PTR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0, 31), + [VOP2_WIN_AFBC_PIC_SIZE] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0, 31), + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0, 15), + [VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31), + [VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31), + [VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31), + [VOP2_WIN_AFBC_PLD_OFFSET] = REG_FIELD(RK3576_CLUSTER_WIN_AFBCD_PLD_PTR_OFFSET, 0, 31), + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31), + [VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0), + [VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1), + [VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2), + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 3, 3), + [VOP2_WIN_COLOR_KEY] = { .reg = 0xffffffff }, + [VOP2_WIN_COLOR_KEY_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_SCALE_CBCR_X] = { .reg = 0xffffffff }, + [VOP2_WIN_SCALE_CBCR_Y] = { .reg = 0xffffffff }, + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_VER_SCL_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_HOR_SCL_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_VSD_CBCR_GT2] = { .reg = 0xffffffff }, + [VOP2_WIN_VSD_CBCR_GT4] = { .reg = 0xffffffff }, +}; + +static const struct reg_field rk3576_vop_smart_regs[VOP2_WIN_MAX_REG] = { + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0), + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5), + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12), + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 14, 14), + [VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 16, 16), + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_SMART_REGION0_ACT_INFO, 0, 31), + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_SMART_REGION0_DSP_INFO, 0, 31), + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_SMART_REGION0_DSP_ST, 0, 28), + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_SMART_REGION0_YRGB_MST, 0, 31), + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_SMART_REGION0_CBR_MST, 0, 31), + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 17, 17), + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 0, 15), + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 16, 31), + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_SMART_CTRL0, 0, 0), + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_SMART_CTRL0, 1, 1), + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_SMART_CTRL0, 2, 3), + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_SMART_CTRL1, 31, 31), + [VOP2_WIN_COLOR_KEY] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 0, 29), + [VOP2_WIN_COLOR_KEY_EN] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 31, 31), + [VOP2_WIN_VP_SEL] = REG_FIELD(RK3576_SMART_PORT_SEL_IMD, 0, 1), + [VOP2_WIN_DLY_NUM] = REG_FIELD(RK3576_SMART_DLY_NUM, 0, 7), + + /* Scale */ + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0, 15), + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 16, 31), + [VOP2_WIN_SCALE_CBCR_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0, 15), + [VOP2_WIN_SCALE_CBCR_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 16, 31), + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 0, 1), + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 2, 3), + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 4, 5), + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 6, 7), + [VOP2_WIN_CBCR_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 8, 9), + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 10, 11), + [VOP2_WIN_CBCR_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 12, 13), + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 14, 15), + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 16, 17), + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 8, 8), + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 9, 9), + [VOP2_WIN_VSD_CBCR_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 10, 10), + [VOP2_WIN_VSD_CBCR_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 11, 11), + [VOP2_WIN_XMIRROR] = { .reg = 0xffffffff }, + [VOP2_WIN_CLUSTER_ENABLE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ENABLE] = { .reg = 0xffffffff }, + [VOP2_WIN_CLUSTER_LB_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_FORMAT] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_RB_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_UV_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_AUTO_GATING_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_TILE_NUM] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff }, +}; + static const struct vop2_video_port_data rk3568_vop_video_ports[] = { { .id = 0, @@ -509,6 +747,272 @@ static const struct vop2_regs_dump rk3568_regs_dump[] = { }, }; +static const struct vop2_video_port_data rk3576_vop_video_ports[] = { + { + .id = 0, + .feature = VOP2_VP_FEATURE_OUTPUT_10BIT, + .gamma_lut_len = 1024, + .cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */ + .max_output = { 4096, 2304 }, + /* win layer_mix hdr */ + .pre_scan_max_dly = { 10, 8, 2, 0 }, + .offset = 0xc00, + .pixel_rate = 2, + }, { + .id = 1, + .feature = VOP2_VP_FEATURE_OUTPUT_10BIT, + .gamma_lut_len = 1024, + .cubic_lut_len = 729, /* 9x9x9 */ + .max_output = { 2560, 1600 }, + /* win layer_mix hdr */ + .pre_scan_max_dly = { 10, 6, 0, 0 }, + .offset = 0xd00, + .pixel_rate = 1, + }, { + .id = 2, + .gamma_lut_len = 1024, + .max_output = { 1920, 1080 }, + /* win layer_mix hdr */ + .pre_scan_max_dly = { 10, 6, 0, 0 }, + .offset = 0xe00, + .pixel_rate = 1, + }, +}; + +/* + * rk3576 vop with 2 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 support 4 Multi-region. + * + * VP0 can use Cluster0/1 and Esmart0/2 + * VP1 can use Cluster0/1 and Esmart1/3 + * VP2 can use Esmart0/1/2/3 + * + * Scale filter mode: + * + * * Cluster: + * * Support prescale down: + * * H/V: gt2/avg2 or gt4/avg4 + * * After prescale down: + * * nearest-neighbor/bilinear/multi-phase filter for scale up + * * nearest-neighbor/bilinear/multi-phase filter for scale down + * + * * Esmart: + * * Support prescale down: + * * H: gt2/avg2 or gt4/avg4 + * * V: gt2 or gt4 + * * After prescale down: + * * nearest-neighbor/bilinear/bicubic for scale up + * * nearest-neighbor/bilinear for scale down + * + * AXI config:: + * + * * Cluster0 win0: 0xa, 0xb [AXI0] + * * Cluster0 win1: 0xc, 0xd [AXI0] + * * Cluster1 win0: 0x6, 0x7 [AXI0] + * * Cluster1 win1: 0x8, 0x9 [AXI0] + * * Esmart0: 0x10, 0x11 [AXI0] + * * Esmart1: 0x12, 0x13 [AXI0] + * * Esmart2: 0xa, 0xb [AXI1] + * * Esmart3: 0xc, 0xd [AXI1] + * * Lut dma rid: 0x1, 0x2, 0x3 [AXI0] + * * DCI dma rid: 0x4 [AXI0] + * * Metadata rid: 0x5 [AXI0] + * + * * Limit: + * * (1) 0x0 and 0xf can't be used; + * * (2) cluster and lut/dci/metadata rid must smaller than 0xf, + * * if Cluster rid is bigger than 0xf, VOP will dead at the + * * system bandwidth very terrible scene. + */ +static const struct vop2_win_data rk3576_vop_win_data[] = { + { + .name = "Cluster0-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER0, + .base = 0x1000, + .possible_vp_mask = BIT(0) | BIT(1), + .formats = formats_rk3576_cluster, + .nformats = ARRAY_SIZE(formats_rk3576_cluster), + .format_modifiers = format_modifiers_rk3576_afbc, + .layer_sel_id = { 0, 0, 0xf, 0xf }, + .supported_rotations = DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .type = DRM_PLANE_TYPE_PRIMARY, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, + }, { + .name = "Cluster1-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER1, + .base = 0x1200, + .possible_vp_mask = BIT(0) | BIT(1), + .formats = formats_rk3576_cluster, + .nformats = ARRAY_SIZE(formats_rk3576_cluster), + .format_modifiers = format_modifiers_rk3576_afbc, + .layer_sel_id = { 1, 1, 0xf, 0xf }, + .supported_rotations = DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, + }, { + .name = "Esmart0-win0", + .phys_id = ROCKCHIP_VOP2_ESMART0, + .base = 0x1800, + .possible_vp_mask = BIT(0) | BIT(2), + .formats = formats_rk3576_esmart, + .nformats = ARRAY_SIZE(formats_rk3576_esmart), + .format_modifiers = format_modifiers, + .layer_sel_id = { 2, 0xf, 0, 0xf }, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + }, { + .name = "Esmart1-win0", + .phys_id = ROCKCHIP_VOP2_ESMART1, + .base = 0x1a00, + .possible_vp_mask = BIT(1) | BIT(2), + .formats = formats_rk3576_esmart, + .nformats = ARRAY_SIZE(formats_rk3576_esmart), + .format_modifiers = format_modifiers, + .layer_sel_id = { 0xf, 2, 1, 0xf }, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + }, { + .name = "Esmart2-win0", + .phys_id = ROCKCHIP_VOP2_ESMART2, + .base = 0x1c00, + .possible_vp_mask = BIT(0) | BIT(2), + .formats = formats_rk3576_esmart, + .nformats = ARRAY_SIZE(formats_rk3576_esmart), + .format_modifiers = format_modifiers, + .layer_sel_id = { 3, 0xf, 2, 0xf }, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + }, { + .name = "Esmart3-win0", + .phys_id = ROCKCHIP_VOP2_ESMART3, + .base = 0x1e00, + .possible_vp_mask = BIT(1) | BIT(2), + .formats = formats_rk3576_esmart, + .nformats = ARRAY_SIZE(formats_rk3576_esmart), + .format_modifiers = format_modifiers, + .layer_sel_id = { 0xf, 3, 3, 0xf }, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + }, +}; + +static const struct vop2_regs_dump rk3576_regs_dump[] = { + { + .name = "SYS", + .base = RK3568_REG_CFG_DONE, + .size = 0x200, + .en_reg = 0, + .en_val = 0, + .en_mask = 0 + }, { + .name = "OVL_SYS", + .base = RK3576_SYS_EXTRA_ALPHA_CTRL, + .size = 0x50, + .en_reg = 0, + .en_val = 0, + .en_mask = 0, + }, { + .name = "OVL_VP0", + .base = RK3576_OVL_CTRL(0), + .size = 0x80, + .en_reg = 0, + .en_val = 0, + .en_mask = 0, + }, { + .name = "OVL_VP1", + .base = RK3576_OVL_CTRL(1), + .size = 0x80, + .en_reg = 0, + .en_val = 0, + .en_mask = 0, + }, { + .name = "OVL_VP2", + .base = RK3576_OVL_CTRL(2), + .size = 0x80, + .en_reg = 0, + .en_val = 0, + .en_mask = 0, + }, { + .name = "VP0", + .base = RK3568_VP0_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "VP1", + .base = RK3568_VP1_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "VP2", + .base = RK3568_VP2_CTRL_BASE, + .size = 0x100, + .en_reg = RK3568_VP_DSP_CTRL, + .en_val = 0, + .en_mask = RK3568_VP_DSP_CTRL__STANDBY, + }, { + .name = "Cluster0", + .base = RK3568_CLUSTER0_CTRL_BASE, + .size = 0x200, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Cluster1", + .base = RK3568_CLUSTER1_CTRL_BASE, + .size = 0x200, + .en_reg = RK3568_CLUSTER_WIN_CTRL0, + .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN, + }, { + .name = "Esmart0", + .base = RK3568_ESMART0_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Esmart1", + .base = RK3568_ESMART1_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Esmart2", + .base = RK3588_ESMART2_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, { + .name = "Esmart3", + .base = RK3588_ESMART3_CTRL_BASE, + .size = 0xf0, + .en_reg = RK3568_SMART_REGION0_CTRL, + .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN, + .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN, + }, +}; + static const struct vop2_video_port_data rk3588_vop_video_ports[] = { { .id = 0, @@ -876,6 +1380,84 @@ static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 return crtc->state->adjusted_mode.crtc_clock * 1000LL; } +static unsigned long rk3576_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags) +{ + 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); + u8 port_pix_rate = vp->data->pixel_rate; + int dclk_core_div, dclk_out_div, if_pixclk_div, if_dclk_sel; + u32 ctrl, vp_clk_div, reg, dclk_div; + unsigned long dclk_in_rate, dclk_core_rate; + + if (vcstate->output_mode == ROCKCHIP_OUT_MODE_YUV420 || adjusted_mode->crtc_clock > 600000) + dclk_div = 2; + else + dclk_div = 1; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) + dclk_core_rate = adjusted_mode->crtc_clock / 2; + else + dclk_core_rate = adjusted_mode->crtc_clock / port_pix_rate; + + dclk_in_rate = adjusted_mode->crtc_clock / dclk_div; + + dclk_core_div = dclk_in_rate > dclk_core_rate ? 1 : 0; + + if (vop2_output_if_is_edp(id)) + if_pixclk_div = port_pix_rate == 2 ? RK3576_DSP_IF_PCLK_DIV : 0; + else + if_pixclk_div = port_pix_rate == 1 ? RK3576_DSP_IF_PCLK_DIV : 0; + + if (vcstate->output_mode == ROCKCHIP_OUT_MODE_YUV420) { + if_dclk_sel = RK3576_DSP_IF_DCLK_SEL_OUT; + dclk_out_div = 1; + } else { + if_dclk_sel = 0; + dclk_out_div = 0; + } + + switch (id) { + case ROCKCHIP_VOP2_EP_HDMI0: + reg = RK3576_HDMI0_IF_CTRL; + break; + case ROCKCHIP_VOP2_EP_EDP0: + reg = RK3576_EDP0_IF_CTRL; + break; + case ROCKCHIP_VOP2_EP_MIPI0: + reg = RK3576_MIPI0_IF_CTRL; + break; + case ROCKCHIP_VOP2_EP_DP0: + reg = RK3576_DP0_IF_CTRL; + break; + case ROCKCHIP_VOP2_EP_DP1: + reg = RK3576_DP1_IF_CTRL; + break; + default: + drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id); + return 0; + } + + ctrl = vop2_readl(vop2, reg); + ctrl &= ~RK3576_DSP_IF_DCLK_SEL_OUT; + ctrl &= ~RK3576_DSP_IF_PCLK_DIV; + ctrl &= ~RK3576_DSP_IF_MUX; + ctrl |= RK3576_DSP_IF_CFG_DONE_IMD; + ctrl |= if_dclk_sel | if_pixclk_div; + ctrl |= RK3576_DSP_IF_CLK_OUT_EN | RK3576_DSP_IF_EN; + ctrl |= FIELD_PREP(RK3576_DSP_IF_MUX, vp->id); + ctrl |= FIELD_PREP(RK3576_DSP_IF_PIN_POL, polflags); + vop2_writel(vop2, reg, ctrl); + + 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); + + vop2_vp_write(vp, RK3588_VP_CLK_CTRL, vp_clk_div); + + return dclk_in_rate * 1000LL; +} + /* * calc the dclk on rk3588 * the available div of dclk is 1, 2, 4 @@ -1214,6 +1796,7 @@ static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_wi struct drm_plane_state *bottom_win_pstate; bool src_pixel_alpha_en = false; u16 src_glb_alpha_val, dst_glb_alpha_val; + u32 src_color_ctrl_reg, dst_color_ctrl_reg, src_alpha_ctrl_reg, dst_alpha_ctrl_reg; u32 offset = 0; bool premulti_en = false; bool swap = false; @@ -1251,14 +1834,22 @@ static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_wi break; } - vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset, - alpha.src_color_ctrl.val); - vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset, - alpha.dst_color_ctrl.val); - vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset, - alpha.src_alpha_ctrl.val); - vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset, - alpha.dst_alpha_ctrl.val); + if (vop2->version <= VOP_VERSION_RK3588) { + src_color_ctrl_reg = RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL; + dst_color_ctrl_reg = RK3568_CLUSTER0_MIX_DST_COLOR_CTRL; + src_alpha_ctrl_reg = RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL; + dst_alpha_ctrl_reg = RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL; + } else { + src_color_ctrl_reg = RK3576_CLUSTER0_MIX_SRC_COLOR_CTRL; + dst_color_ctrl_reg = RK3576_CLUSTER0_MIX_DST_COLOR_CTRL; + src_alpha_ctrl_reg = RK3576_CLUSTER0_MIX_SRC_ALPHA_CTRL; + dst_alpha_ctrl_reg = RK3576_CLUSTER0_MIX_DST_ALPHA_CTRL; + } + + vop2_writel(vop2, src_color_ctrl_reg + offset, alpha.src_color_ctrl.val); + vop2_writel(vop2, dst_color_ctrl_reg + offset, alpha.dst_color_ctrl.val); + vop2_writel(vop2, src_alpha_ctrl_reg + offset, alpha.src_alpha_ctrl.val); + vop2_writel(vop2, dst_alpha_ctrl_reg + offset, alpha.dst_alpha_ctrl.val); } static void vop2_setup_alpha(struct vop2_video_port *vp) @@ -1271,11 +1862,16 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) int pixel_alpha_en; int premulti_en, gpremulti_en = 0; int mixer_id; + u32 src_color_ctrl_reg, dst_color_ctrl_reg, src_alpha_ctrl_reg, dst_alpha_ctrl_reg; u32 offset; bool bottom_layer_alpha_en = false; u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE; - mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); + if (vop2->version <= VOP_VERSION_RK3588) + mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); + else + mixer_id = 0; + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { @@ -1294,6 +1890,18 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) } } + if (vop2->version <= VOP_VERSION_RK3588) { + src_color_ctrl_reg = RK3568_MIX0_SRC_COLOR_CTRL; + dst_color_ctrl_reg = RK3568_MIX0_DST_COLOR_CTRL; + src_alpha_ctrl_reg = RK3568_MIX0_SRC_ALPHA_CTRL; + dst_alpha_ctrl_reg = RK3568_MIX0_DST_ALPHA_CTRL; + } else { + src_color_ctrl_reg = RK3576_OVL_MIX0_SRC_COLOR_CTRL(vp->id); + dst_color_ctrl_reg = RK3576_OVL_MIX0_DST_COLOR_CTRL(vp->id); + src_alpha_ctrl_reg = RK3576_OVL_MIX0_SRC_ALPHA_CTRL(vp->id); + dst_alpha_ctrl_reg = RK3576_OVL_MIX0_DST_ALPHA_CTRL(vp->id); + } + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { struct vop2_win *win = to_vop2_win(plane); int zpos = plane->state->normalized_zpos; @@ -1340,17 +1948,26 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) vop2_parse_alpha(&alpha_config, &alpha); offset = (mixer_id + zpos - 1) * 0x10; - vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset, - alpha.src_color_ctrl.val); - vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset, - alpha.dst_color_ctrl.val); - vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset, - alpha.src_alpha_ctrl.val); - vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset, - alpha.dst_alpha_ctrl.val); + + vop2_writel(vop2, src_color_ctrl_reg + offset, alpha.src_color_ctrl.val); + vop2_writel(vop2, dst_color_ctrl_reg + offset, alpha.dst_color_ctrl.val); + vop2_writel(vop2, src_alpha_ctrl_reg + offset, alpha.src_alpha_ctrl.val); + vop2_writel(vop2, dst_alpha_ctrl_reg + offset, alpha.dst_alpha_ctrl.val); } if (vp->id == 0) { + if (vop2->version <= VOP_VERSION_RK3588) { + src_color_ctrl_reg = RK3568_HDR0_SRC_COLOR_CTRL; + dst_color_ctrl_reg = RK3568_HDR0_DST_COLOR_CTRL; + src_alpha_ctrl_reg = RK3568_HDR0_SRC_ALPHA_CTRL; + dst_alpha_ctrl_reg = RK3568_HDR0_DST_ALPHA_CTRL; + } else { + src_color_ctrl_reg = RK3576_OVL_HDR_SRC_COLOR_CTRL(vp->id); + dst_color_ctrl_reg = RK3576_OVL_HDR_DST_COLOR_CTRL(vp->id); + src_alpha_ctrl_reg = RK3576_OVL_HDR_SRC_ALPHA_CTRL(vp->id); + dst_alpha_ctrl_reg = RK3576_OVL_HDR_DST_ALPHA_CTRL(vp->id); + } + if (bottom_layer_alpha_en) { /* Transfer pixel alpha to hdr mix */ alpha_config.src_premulti_en = gpremulti_en; @@ -1358,18 +1975,15 @@ static void vop2_setup_alpha(struct vop2_video_port *vp) alpha_config.src_pixel_alpha_en = true; alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + vop2_parse_alpha(&alpha_config, &alpha); - vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, - alpha.src_color_ctrl.val); - vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL, - alpha.dst_color_ctrl.val); - vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL, - alpha.src_alpha_ctrl.val); - vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL, - alpha.dst_alpha_ctrl.val); + vop2_writel(vop2, src_color_ctrl_reg, alpha.src_color_ctrl.val); + vop2_writel(vop2, dst_color_ctrl_reg, alpha.dst_color_ctrl.val); + vop2_writel(vop2, src_alpha_ctrl_reg, alpha.src_alpha_ctrl.val); + vop2_writel(vop2, dst_alpha_ctrl_reg, alpha.dst_alpha_ctrl.val); } else { - vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0); + vop2_writel(vop2, src_color_ctrl_reg, 0); } } } @@ -1577,6 +2191,72 @@ static void rk3568_vop2_setup_overlay(struct vop2_video_port *vp) rk3568_vop2_setup_dly_for_windows(vp); } +static void rk3576_vop2_setup_layer_mixer(struct vop2_video_port *vp) +{ + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); + struct vop2 *vop2 = vp->vop2; + struct drm_plane *plane; + u32 layer_sel = 0xffff; /* 0xf means this layer is disabled */ + u32 ovl_ctrl; + + ovl_ctrl = vop2_readl(vop2, RK3576_OVL_CTRL(vp->id)); + if (vcstate->yuv_overlay) + ovl_ctrl |= RK3576_OVL_CTRL__YUV_MODE; + else + ovl_ctrl &= ~RK3576_OVL_CTRL__YUV_MODE; + + vop2_writel(vop2, RK3576_OVL_CTRL(vp->id), ovl_ctrl); + + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + struct vop2_win *win = to_vop2_win(plane); + + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos, + 0xf); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos, + win->data->layer_sel_id[vp->id]); + } + + vop2_writel(vop2, RK3576_OVL_LAYER_SEL(vp->id), layer_sel); +} + +static void rk3576_vop2_setup_dly_for_windows(struct vop2_video_port *vp) +{ + struct drm_plane *plane; + struct vop2_win *win; + + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + win = to_vop2_win(plane); + vop2_win_write(win, VOP2_WIN_DLY_NUM, 0); + } +} + +static void rk3576_vop2_setup_overlay(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + struct drm_crtc *crtc = &vp->crtc; + struct drm_plane *plane; + + vp->win_mask = 0; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct vop2_win *win = to_vop2_win(plane); + + win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT]; + + vp->win_mask |= BIT(win->data->phys_id); + + if (vop2_cluster_window(win)) + vop2_setup_cluster_alpha(vop2, win); + } + + if (!vp->win_mask) + return; + + rk3576_vop2_setup_layer_mixer(vp); + vop2_setup_alpha(vp); + rk3576_vop2_setup_dly_for_windows(vp); +} + static void rk3568_vop2_setup_bg_dly(struct vop2_video_port *vp) { struct drm_crtc *crtc = &vp->crtc; @@ -1594,12 +2274,38 @@ static void rk3568_vop2_setup_bg_dly(struct vop2_video_port *vp) vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly); } +static void rk3576_vop2_setup_bg_dly(struct vop2_video_port *vp) +{ + struct drm_crtc *crtc = &vp->crtc; + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + u16 hdisplay = mode->crtc_hdisplay; + u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + u32 bg_dly; + u32 pre_scan_dly; + + bg_dly = vp->data->pre_scan_max_dly[VOP2_DLY_WIN] + + vp->data->pre_scan_max_dly[VOP2_DLY_LAYER_MIX] + + vp->data->pre_scan_max_dly[VOP2_DLY_HDR_MIX]; + + vop2_writel(vp->vop2, RK3576_OVL_BG_MIX_CTRL(vp->id), + FIELD_PREP(RK3576_OVL_BG_MIX_CTRL__BG_DLY, bg_dly)); + + pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len; + vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly); +} + static const struct vop2_ops rk3568_vop_ops = { .setup_intf_mux = rk3568_set_intf_mux, .setup_bg_dly = rk3568_vop2_setup_bg_dly, .setup_overlay = rk3568_vop2_setup_overlay, }; +static const struct vop2_ops rk3576_vop_ops = { + .setup_intf_mux = rk3576_set_intf_mux, + .setup_bg_dly = rk3576_vop2_setup_bg_dly, + .setup_overlay = rk3576_vop2_setup_overlay, +}; + static const struct vop2_ops rk3588_vop_ops = { .setup_intf_mux = rk3588_set_intf_mux, .setup_bg_dly = rk3568_vop2_setup_bg_dly, @@ -1644,6 +2350,25 @@ static const struct vop2_data rk3568_vop = { .soc_id = 3568, }; +static const struct vop2_data rk3576_vop = { + .version = VOP_VERSION_RK3576, + .feature = VOP2_FEATURE_HAS_SYS_PMU, + .nr_vps = 3, + .max_input = { 4096, 4320 }, + .max_output = { 4096, 4320 }, + .vp = rk3576_vop_video_ports, + .win = rk3576_vop_win_data, + .win_size = ARRAY_SIZE(rk3576_vop_win_data), + .cluster_reg = rk3576_vop_cluster_regs, + .nr_cluster_regs = ARRAY_SIZE(rk3576_vop_cluster_regs), + .smart_reg = rk3576_vop_smart_regs, + .nr_smart_regs = ARRAY_SIZE(rk3576_vop_smart_regs), + .regs_dump = rk3576_regs_dump, + .regs_dump_size = ARRAY_SIZE(rk3576_regs_dump), + .ops = &rk3576_vop_ops, + .soc_id = 3576, +}; + static const struct vop2_data rk3588_vop = { .version = VOP_VERSION_RK3588, .feature = VOP2_FEATURE_HAS_SYS_GRF | VOP2_FEATURE_HAS_VO1_GRF | @@ -1671,6 +2396,9 @@ static const struct of_device_id vop2_dt_match[] = { }, { .compatible = "rockchip,rk3568-vop", .data = &rk3568_vop, + }, { + .compatible = "rockchip,rk3576-vop", + .data = &rk3576_vop, }, { .compatible = "rockchip,rk3588-vop", .data = &rk3588_vop