brintos

brintos / linux-shallow public Read only

0
0
Text · 93.5 KiB · 9873172 Raw
3228 lines · c
1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)2/*3 * Copyright (c) 2020 Rockchip Electronics Co., Ltd.4 * Author: Andy Yan <andy.yan@rock-chips.com>5 */6#include <linux/bitfield.h>7#include <linux/clk.h>8#include <linux/component.h>9#include <linux/delay.h>10#include <linux/iopoll.h>11#include <linux/kernel.h>12#include <linux/media-bus-format.h>13#include <linux/mfd/syscon.h>14#include <linux/module.h>15#include <linux/of.h>16#include <linux/of_graph.h>17#include <linux/platform_device.h>18#include <linux/pm_runtime.h>19#include <linux/regmap.h>20#include <linux/swab.h>21 22#include <drm/drm.h>23#include <drm/drm_atomic.h>24#include <drm/drm_atomic_uapi.h>25#include <drm/drm_blend.h>26#include <drm/drm_crtc.h>27#include <drm/drm_debugfs.h>28#include <drm/drm_flip_work.h>29#include <drm/drm_framebuffer.h>30#include <drm/drm_probe_helper.h>31#include <drm/drm_vblank.h>32 33#include <uapi/linux/videodev2.h>34#include <dt-bindings/soc/rockchip,vop2.h>35 36#include "rockchip_drm_drv.h"37#include "rockchip_drm_gem.h"38#include "rockchip_drm_vop2.h"39#include "rockchip_rgb.h"40 41/*42 * VOP2 architecture43 *44 +----------+   +-------------+                                                        +-----------+45 |  Cluster |   | Sel 1 from 6|                                                        | 1 from 3  |46 |  window0 |   |    Layer0   |                                                        |    RGB    |47 +----------+   +-------------+              +---------------+    +-------------+      +-----------+48 +----------+   +-------------+              |N from 6 layers|    |             |49 |  Cluster |   | Sel 1 from 6|              |   Overlay0    +--->| Video Port0 |      +-----------+50 |  window1 |   |    Layer1   |              |               |    |             |      | 1 from 3  |51 +----------+   +-------------+              +---------------+    +-------------+      |   LVDS    |52 +----------+   +-------------+                                                        +-----------+53 |  Esmart  |   | Sel 1 from 6|54 |  window0 |   |   Layer2    |              +---------------+    +-------------+      +-----------+55 +----------+   +-------------+              |N from 6 Layers|    |             | +--> | 1 from 3  |56 +----------+   +-------------+   -------->  |   Overlay1    +--->| Video Port1 |      |   MIPI    |57 |  Esmart  |   | Sel 1 from 6|   -------->  |               |    |             |      +-----------+58 |  Window1 |   |   Layer3    |              +---------------+    +-------------+59 +----------+   +-------------+                                                        +-----------+60 +----------+   +-------------+                                                        | 1 from 3  |61 |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |   HDMI    |62 |  Window0 |   |    Layer4   |              |N from 6 Layers|    |             |      +-----------+63 +----------+   +-------------+              |   Overlay2    +--->| Video Port2 |64 +----------+   +-------------+              |               |    |             |      +-----------+65 |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |  1 from 3 |66 |  Window1 |   |    Layer5   |                                                        |    eDP    |67 +----------+   +-------------+                                                        +-----------+68 *69 */70 71enum vop2_data_format {72	VOP2_FMT_ARGB8888 = 0,73	VOP2_FMT_RGB888,74	VOP2_FMT_RGB565,75	VOP2_FMT_XRGB101010,76	VOP2_FMT_YUV420SP,77	VOP2_FMT_YUV422SP,78	VOP2_FMT_YUV444SP,79	VOP2_FMT_YUYV422 = 8,80	VOP2_FMT_YUYV420,81	VOP2_FMT_VYUY422,82	VOP2_FMT_VYUY420,83	VOP2_FMT_YUV420SP_TILE_8x4 = 0x10,84	VOP2_FMT_YUV420SP_TILE_16x2,85	VOP2_FMT_YUV422SP_TILE_8x4,86	VOP2_FMT_YUV422SP_TILE_16x2,87	VOP2_FMT_YUV420SP_10,88	VOP2_FMT_YUV422SP_10,89	VOP2_FMT_YUV444SP_10,90};91 92enum vop2_afbc_format {93	VOP2_AFBC_FMT_RGB565,94	VOP2_AFBC_FMT_ARGB2101010 = 2,95	VOP2_AFBC_FMT_YUV420_10BIT,96	VOP2_AFBC_FMT_RGB888,97	VOP2_AFBC_FMT_ARGB8888,98	VOP2_AFBC_FMT_YUV420 = 9,99	VOP2_AFBC_FMT_YUV422 = 0xb,100	VOP2_AFBC_FMT_YUV422_10BIT = 0xe,101	VOP2_AFBC_FMT_INVALID = -1,102};103 104union vop2_alpha_ctrl {105	u32 val;106	struct {107		/* [0:1] */108		u32 color_mode:1;109		u32 alpha_mode:1;110		/* [2:3] */111		u32 blend_mode:2;112		u32 alpha_cal_mode:1;113		/* [5:7] */114		u32 factor_mode:3;115		/* [8:9] */116		u32 alpha_en:1;117		u32 src_dst_swap:1;118		u32 reserved:6;119		/* [16:23] */120		u32 glb_alpha:8;121	} bits;122};123 124struct vop2_alpha {125	union vop2_alpha_ctrl src_color_ctrl;126	union vop2_alpha_ctrl dst_color_ctrl;127	union vop2_alpha_ctrl src_alpha_ctrl;128	union vop2_alpha_ctrl dst_alpha_ctrl;129};130 131struct vop2_alpha_config {132	bool src_premulti_en;133	bool dst_premulti_en;134	bool src_pixel_alpha_en;135	bool dst_pixel_alpha_en;136	u16 src_glb_alpha_value;137	u16 dst_glb_alpha_value;138};139 140struct vop2_win {141	struct vop2 *vop2;142	struct drm_plane base;143	const struct vop2_win_data *data;144	struct regmap_field *reg[VOP2_WIN_MAX_REG];145 146	/**147	 * @win_id: graphic window id, a cluster may be split into two148	 * graphics windows.149	 */150	u8 win_id;151	u8 delay;152	u32 offset;153 154	enum drm_plane_type type;155};156 157struct vop2_video_port {158	struct drm_crtc crtc;159	struct vop2 *vop2;160	struct clk *dclk;161	unsigned int id;162	const struct vop2_video_port_data *data;163 164	struct completion dsp_hold_completion;165 166	/**167	 * @win_mask: Bitmask of windows attached to the video port;168	 */169	u32 win_mask;170 171	struct vop2_win *primary_plane;172	struct drm_pending_vblank_event *event;173 174	unsigned int nlayers;175};176 177struct vop2 {178	struct device *dev;179	struct drm_device *drm;180	struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];181 182	const struct vop2_data *data;183	/*184	 * Number of windows that are registered as plane, may be less than the185	 * total number of hardware windows.186	 */187	u32 registered_num_wins;188 189	void __iomem *regs;190	struct regmap *map;191 192	struct regmap *sys_grf;193	struct regmap *vop_grf;194	struct regmap *vo1_grf;195	struct regmap *sys_pmu;196 197	/* physical map length of vop2 register */198	u32 len;199 200	void __iomem *lut_regs;201 202	/* protects crtc enable/disable */203	struct mutex vop2_lock;204 205	int irq;206 207	/*208	 * Some global resources are shared between all video ports(crtcs), so209	 * we need a ref counter here.210	 */211	unsigned int enable_count;212	struct clk *hclk;213	struct clk *aclk;214	struct clk *pclk;215 216	/* optional internal rgb encoder */217	struct rockchip_rgb *rgb;218 219	/* must be put at the end of the struct */220	struct vop2_win win[];221};222 223#define vop2_output_if_is_hdmi(x)	((x) == ROCKCHIP_VOP2_EP_HDMI0 || \224					 (x) == ROCKCHIP_VOP2_EP_HDMI1)225 226#define vop2_output_if_is_dp(x)		((x) == ROCKCHIP_VOP2_EP_DP0 || \227					 (x) == ROCKCHIP_VOP2_EP_DP1)228 229#define vop2_output_if_is_edp(x)	((x) == ROCKCHIP_VOP2_EP_EDP0 || \230					 (x) == ROCKCHIP_VOP2_EP_EDP1)231 232#define vop2_output_if_is_mipi(x)	((x) == ROCKCHIP_VOP2_EP_MIPI0 || \233					 (x) == ROCKCHIP_VOP2_EP_MIPI1)234 235#define vop2_output_if_is_lvds(x)	((x) == ROCKCHIP_VOP2_EP_LVDS0 || \236					 (x) == ROCKCHIP_VOP2_EP_LVDS1)237 238#define vop2_output_if_is_dpi(x)	((x) == ROCKCHIP_VOP2_EP_RGB0)239 240static const struct regmap_config vop2_regmap_config;241 242static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)243{244	return container_of(crtc, struct vop2_video_port, crtc);245}246 247static struct vop2_win *to_vop2_win(struct drm_plane *p)248{249	return container_of(p, struct vop2_win, base);250}251 252static void vop2_lock(struct vop2 *vop2)253{254	mutex_lock(&vop2->vop2_lock);255}256 257static void vop2_unlock(struct vop2 *vop2)258{259	mutex_unlock(&vop2->vop2_lock);260}261 262static void vop2_writel(struct vop2 *vop2, u32 offset, u32 v)263{264	regmap_write(vop2->map, offset, v);265}266 267static void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v)268{269	regmap_write(vp->vop2->map, vp->data->offset + offset, v);270}271 272static u32 vop2_readl(struct vop2 *vop2, u32 offset)273{274	u32 val;275 276	regmap_read(vop2->map, offset, &val);277 278	return val;279}280 281static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v)282{283	regmap_field_write(win->reg[reg], v);284}285 286static bool vop2_cluster_window(const struct vop2_win *win)287{288	return win->data->feature & WIN_FEATURE_CLUSTER;289}290 291/*292 * Note:293 * The write mask function is documented but missing on rk3566/8, writes294 * to these bits have no effect. For newer soc(rk3588 and following) the295 * write mask is needed for register writes.296 *297 * GLB_CFG_DONE_EN has no write mask bit.298 *299 */300static void vop2_cfg_done(struct vop2_video_port *vp)301{302	struct vop2 *vop2 = vp->vop2;303	u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;304 305	val |= BIT(vp->id) | (BIT(vp->id) << 16);306 307	regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);308}309 310static void vop2_win_disable(struct vop2_win *win)311{312	vop2_win_write(win, VOP2_WIN_ENABLE, 0);313 314	if (vop2_cluster_window(win))315		vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 0);316}317 318static u32 vop2_get_bpp(const struct drm_format_info *format)319{320	switch (format->format) {321	case DRM_FORMAT_YUV420_8BIT:322		return 12;323	case DRM_FORMAT_YUV420_10BIT:324		return 15;325	case DRM_FORMAT_VUY101010:326		return 30;327	default:328		return drm_format_info_bpp(format, 0);329	}330}331 332static enum vop2_data_format vop2_convert_format(u32 format)333{334	switch (format) {335	case DRM_FORMAT_XRGB2101010:336	case DRM_FORMAT_ARGB2101010:337	case DRM_FORMAT_XBGR2101010:338	case DRM_FORMAT_ABGR2101010:339		return VOP2_FMT_XRGB101010;340	case DRM_FORMAT_XRGB8888:341	case DRM_FORMAT_ARGB8888:342	case DRM_FORMAT_XBGR8888:343	case DRM_FORMAT_ABGR8888:344		return VOP2_FMT_ARGB8888;345	case DRM_FORMAT_RGB888:346	case DRM_FORMAT_BGR888:347		return VOP2_FMT_RGB888;348	case DRM_FORMAT_RGB565:349	case DRM_FORMAT_BGR565:350		return VOP2_FMT_RGB565;351	case DRM_FORMAT_NV12:352	case DRM_FORMAT_NV21:353	case DRM_FORMAT_YUV420_8BIT:354		return VOP2_FMT_YUV420SP;355	case DRM_FORMAT_NV15:356	case DRM_FORMAT_YUV420_10BIT:357		return VOP2_FMT_YUV420SP_10;358	case DRM_FORMAT_NV16:359	case DRM_FORMAT_NV61:360		return VOP2_FMT_YUV422SP;361	case DRM_FORMAT_NV20:362	case DRM_FORMAT_Y210:363		return VOP2_FMT_YUV422SP_10;364	case DRM_FORMAT_NV24:365	case DRM_FORMAT_NV42:366		return VOP2_FMT_YUV444SP;367	case DRM_FORMAT_NV30:368		return VOP2_FMT_YUV444SP_10;369	case DRM_FORMAT_YUYV:370	case DRM_FORMAT_YVYU:371		return VOP2_FMT_VYUY422;372	case DRM_FORMAT_VYUY:373	case DRM_FORMAT_UYVY:374		return VOP2_FMT_YUYV422;375	default:376		DRM_ERROR("unsupported format[%08x]\n", format);377		return -EINVAL;378	}379}380 381static enum vop2_afbc_format vop2_convert_afbc_format(u32 format)382{383	switch (format) {384	case DRM_FORMAT_XRGB2101010:385	case DRM_FORMAT_ARGB2101010:386	case DRM_FORMAT_XBGR2101010:387	case DRM_FORMAT_ABGR2101010:388		return VOP2_AFBC_FMT_ARGB2101010;389	case DRM_FORMAT_XRGB8888:390	case DRM_FORMAT_ARGB8888:391	case DRM_FORMAT_XBGR8888:392	case DRM_FORMAT_ABGR8888:393		return VOP2_AFBC_FMT_ARGB8888;394	case DRM_FORMAT_RGB888:395	case DRM_FORMAT_BGR888:396		return VOP2_AFBC_FMT_RGB888;397	case DRM_FORMAT_RGB565:398	case DRM_FORMAT_BGR565:399		return VOP2_AFBC_FMT_RGB565;400	case DRM_FORMAT_YUV420_8BIT:401		return VOP2_AFBC_FMT_YUV420;402	case DRM_FORMAT_YUV420_10BIT:403		return VOP2_AFBC_FMT_YUV420_10BIT;404	case DRM_FORMAT_YVYU:405	case DRM_FORMAT_YUYV:406	case DRM_FORMAT_VYUY:407	case DRM_FORMAT_UYVY:408		return VOP2_AFBC_FMT_YUV422;409	case DRM_FORMAT_Y210:410		return VOP2_AFBC_FMT_YUV422_10BIT;411	default:412		return VOP2_AFBC_FMT_INVALID;413	}414 415	return VOP2_AFBC_FMT_INVALID;416}417 418static bool vop2_win_rb_swap(u32 format)419{420	switch (format) {421	case DRM_FORMAT_XBGR2101010:422	case DRM_FORMAT_ABGR2101010:423	case DRM_FORMAT_XBGR8888:424	case DRM_FORMAT_ABGR8888:425	case DRM_FORMAT_BGR888:426	case DRM_FORMAT_BGR565:427		return true;428	default:429		return false;430	}431}432 433static bool vop2_afbc_uv_swap(u32 format)434{435	switch (format) {436	case DRM_FORMAT_YUYV:437	case DRM_FORMAT_Y210:438	case DRM_FORMAT_YUV420_8BIT:439	case DRM_FORMAT_YUV420_10BIT:440		return true;441	default:442		return false;443	}444}445 446static bool vop2_win_uv_swap(u32 format)447{448	switch (format) {449	case DRM_FORMAT_NV12:450	case DRM_FORMAT_NV16:451	case DRM_FORMAT_NV24:452	case DRM_FORMAT_NV15:453	case DRM_FORMAT_NV20:454	case DRM_FORMAT_NV30:455	case DRM_FORMAT_YUYV:456	case DRM_FORMAT_UYVY:457		return true;458	default:459		return false;460	}461}462 463static bool vop2_win_dither_up(u32 format)464{465	switch (format) {466	case DRM_FORMAT_BGR565:467	case DRM_FORMAT_RGB565:468		return true;469	default:470		return false;471	}472}473 474static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode)475{476	/*477	 * FIXME:478	 *479	 * There is no media type for YUV444 output,480	 * so when out_mode is AAAA or P888, assume output is YUV444 on481	 * yuv format.482	 *483	 * From H/W testing, YUV444 mode need a rb swap.484	 */485	if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 ||486	    bus_format == MEDIA_BUS_FMT_VYUY8_1X16 ||487	    bus_format == MEDIA_BUS_FMT_YVYU8_2X8 ||488	    bus_format == MEDIA_BUS_FMT_VYUY8_2X8 ||489	    ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||490	      bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&491	     (output_mode == ROCKCHIP_OUT_MODE_AAAA ||492	      output_mode == ROCKCHIP_OUT_MODE_P888)))493		return true;494	else495		return false;496}497 498static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format)499{500	if (vop2->data->soc_id == 3588) {501		if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||502		    bus_format == MEDIA_BUS_FMT_YUV10_1X30)503			return true;504	}505 506	return false;507}508 509static bool is_yuv_output(u32 bus_format)510{511	switch (bus_format) {512	case MEDIA_BUS_FMT_YUV8_1X24:513	case MEDIA_BUS_FMT_YUV10_1X30:514	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:515	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:516	case MEDIA_BUS_FMT_YUYV8_2X8:517	case MEDIA_BUS_FMT_YVYU8_2X8:518	case MEDIA_BUS_FMT_UYVY8_2X8:519	case MEDIA_BUS_FMT_VYUY8_2X8:520	case MEDIA_BUS_FMT_YUYV8_1X16:521	case MEDIA_BUS_FMT_YVYU8_1X16:522	case MEDIA_BUS_FMT_UYVY8_1X16:523	case MEDIA_BUS_FMT_VYUY8_1X16:524		return true;525	default:526		return false;527	}528}529 530static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)531{532	int i;533 534	if (modifier == DRM_FORMAT_MOD_LINEAR)535		return false;536 537	for (i = 0 ; i < plane->modifier_count; i++)538		if (plane->modifiers[i] == modifier)539			return true;540 541	return false;542}543 544static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,545					u64 modifier)546{547	struct vop2_win *win = to_vop2_win(plane);548	struct vop2 *vop2 = win->vop2;549 550	if (modifier == DRM_FORMAT_MOD_INVALID)551		return false;552 553	if (modifier == DRM_FORMAT_MOD_LINEAR)554		return true;555 556	if (!rockchip_afbc(plane, modifier)) {557		drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n",558			    modifier);559 560		return false;561	}562 563	return vop2_convert_afbc_format(format) >= 0;564}565 566/*567 * 0: Full mode, 16 lines for one tail568 * 1: half block mode, 8 lines one tail569 */570static bool vop2_half_block_enable(struct drm_plane_state *pstate)571{572	if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90))573		return false;574	else575		return true;576}577 578static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate,579				      bool afbc_half_block_en)580{581	struct drm_rect *src = &pstate->src;582	struct drm_framebuffer *fb = pstate->fb;583	u32 bpp = vop2_get_bpp(fb->format);584	u32 vir_width = (fb->pitches[0] << 3) / bpp;585	u32 width = drm_rect_width(src) >> 16;586	u32 height = drm_rect_height(src) >> 16;587	u32 act_xoffset = src->x1 >> 16;588	u32 act_yoffset = src->y1 >> 16;589	u32 align16_crop = 0;590	u32 align64_crop = 0;591	u32 height_tmp;592	u8 tx, ty;593	u8 bottom_crop_line_num = 0;594 595	/* 16 pixel align */596	if (height & 0xf)597		align16_crop = 16 - (height & 0xf);598 599	height_tmp = height + align16_crop;600 601	/* 64 pixel align */602	if (height_tmp & 0x3f)603		align64_crop = 64 - (height_tmp & 0x3f);604 605	bottom_crop_line_num = align16_crop + align64_crop;606 607	switch (pstate->rotation &608		(DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y |609		 DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) {610	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:611		tx = 16 - ((act_xoffset + width) & 0xf);612		ty = bottom_crop_line_num - act_yoffset;613		break;614	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90:615		tx = bottom_crop_line_num - act_yoffset;616		ty = vir_width - width - act_xoffset;617		break;618	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270:619		tx = act_yoffset;620		ty = act_xoffset;621		break;622	case DRM_MODE_REFLECT_X:623		tx = 16 - ((act_xoffset + width) & 0xf);624		ty = act_yoffset;625		break;626	case DRM_MODE_REFLECT_Y:627		tx = act_xoffset;628		ty = bottom_crop_line_num - act_yoffset;629		break;630	case DRM_MODE_ROTATE_90:631		tx = bottom_crop_line_num - act_yoffset;632		ty = act_xoffset;633		break;634	case DRM_MODE_ROTATE_270:635		tx = act_yoffset;636		ty = vir_width - width - act_xoffset;637		break;638	case 0:639		tx = act_xoffset;640		ty = act_yoffset;641		break;642	}643 644	if (afbc_half_block_en)645		ty &= 0x7f;646 647#define TRANSFORM_XOFFSET GENMASK(7, 0)648#define TRANSFORM_YOFFSET GENMASK(23, 16)649	return FIELD_PREP(TRANSFORM_XOFFSET, tx) |650		FIELD_PREP(TRANSFORM_YOFFSET, ty);651}652 653/*654 * A Cluster window has 2048 x 16 line buffer, which can655 * works at 2048 x 16(Full) or 4096 x 8 (Half) mode.656 * for Cluster_lb_mode register:657 * 0: half mode, for plane input width range 2048 ~ 4096658 * 1: half mode, for cluster work at 2 * 2048 plane mode659 * 2: half mode, for rotate_90/270 mode660 *661 */662static int vop2_get_cluster_lb_mode(struct vop2_win *win,663				    struct drm_plane_state *pstate)664{665	if ((pstate->rotation & DRM_MODE_ROTATE_270) ||666	    (pstate->rotation & DRM_MODE_ROTATE_90))667		return 2;668	else669		return 0;670}671 672static u16 vop2_scale_factor(u32 src, u32 dst)673{674	u32 fac;675	int shift;676 677	if (src == dst)678		return 0;679 680	if (dst < 2)681		return U16_MAX;682 683	if (src < 2)684		return 0;685 686	if (src > dst)687		shift = 12;688	else689		shift = 16;690 691	src--;692	dst--;693 694	fac = DIV_ROUND_UP(src << shift, dst) - 1;695 696	if (fac > U16_MAX)697		return U16_MAX;698 699	return fac;700}701 702static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win,703			     u32 src_w, u32 src_h, u32 dst_w,704			     u32 dst_h, u32 pixel_format)705{706	const struct drm_format_info *info;707	u16 hor_scl_mode, ver_scl_mode;708	u16 hscl_filter_mode, vscl_filter_mode;709	uint16_t cbcr_src_w = src_w;710	uint16_t cbcr_src_h = src_h;711	u8 gt2 = 0;712	u8 gt4 = 0;713	u32 val;714 715	info = drm_format_info(pixel_format);716 717	if (src_h >= (4 * dst_h)) {718		gt4 = 1;719		src_h >>= 2;720	} else if (src_h >= (2 * dst_h)) {721		gt2 = 1;722		src_h >>= 1;723	}724 725	hor_scl_mode = scl_get_scl_mode(src_w, dst_w);726	ver_scl_mode = scl_get_scl_mode(src_h, dst_h);727 728	if (hor_scl_mode == SCALE_UP)729		hscl_filter_mode = VOP2_SCALE_UP_BIC;730	else731		hscl_filter_mode = VOP2_SCALE_DOWN_BIL;732 733	if (ver_scl_mode == SCALE_UP)734		vscl_filter_mode = VOP2_SCALE_UP_BIL;735	else736		vscl_filter_mode = VOP2_SCALE_DOWN_BIL;737 738	/*739	 * RK3568 VOP Esmart/Smart dsp_w should be even pixel740	 * at scale down mode741	 */742	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {743		if ((hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) {744			drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n",745				win->data->name, dst_w);746			dst_w++;747		}748	}749 750	val = vop2_scale_factor(src_w, dst_w);751	vop2_win_write(win, VOP2_WIN_SCALE_YRGB_X, val);752	val = vop2_scale_factor(src_h, dst_h);753	vop2_win_write(win, VOP2_WIN_SCALE_YRGB_Y, val);754 755	vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT4, gt4);756	vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT2, gt2);757 758	vop2_win_write(win, VOP2_WIN_YRGB_HOR_SCL_MODE, hor_scl_mode);759	vop2_win_write(win, VOP2_WIN_YRGB_VER_SCL_MODE, ver_scl_mode);760 761	if (vop2_cluster_window(win))762		return;763 764	vop2_win_write(win, VOP2_WIN_YRGB_HSCL_FILTER_MODE, hscl_filter_mode);765	vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode);766 767	if (info->is_yuv) {768		cbcr_src_w /= info->hsub;769		cbcr_src_h /= info->vsub;770 771		gt4 = 0;772		gt2 = 0;773 774		if (cbcr_src_h >= (4 * dst_h)) {775			gt4 = 1;776			cbcr_src_h >>= 2;777		} else if (cbcr_src_h >= (2 * dst_h)) {778			gt2 = 1;779			cbcr_src_h >>= 1;780		}781 782		hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);783		ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);784 785		val = vop2_scale_factor(cbcr_src_w, dst_w);786		vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val);787 788		val = vop2_scale_factor(cbcr_src_h, dst_h);789		vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val);790 791		vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4);792		vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT2, gt2);793		vop2_win_write(win, VOP2_WIN_CBCR_HOR_SCL_MODE, hor_scl_mode);794		vop2_win_write(win, VOP2_WIN_CBCR_VER_SCL_MODE, ver_scl_mode);795		vop2_win_write(win, VOP2_WIN_CBCR_HSCL_FILTER_MODE, hscl_filter_mode);796		vop2_win_write(win, VOP2_WIN_CBCR_VSCL_FILTER_MODE, vscl_filter_mode);797	}798}799 800static int vop2_convert_csc_mode(int csc_mode)801{802	switch (csc_mode) {803	case V4L2_COLORSPACE_SMPTE170M:804	case V4L2_COLORSPACE_470_SYSTEM_M:805	case V4L2_COLORSPACE_470_SYSTEM_BG:806		return CSC_BT601L;807	case V4L2_COLORSPACE_REC709:808	case V4L2_COLORSPACE_SMPTE240M:809	case V4L2_COLORSPACE_DEFAULT:810		return CSC_BT709L;811	case V4L2_COLORSPACE_JPEG:812		return CSC_BT601F;813	case V4L2_COLORSPACE_BT2020:814		return CSC_BT2020;815	default:816		return CSC_BT709L;817	}818}819 820/*821 * colorspace path:822 *      Input        Win csc                     Output823 * 1. YUV(2020)  --> Y2R->2020To709->R2Y   --> YUV_OUTPUT(601/709)824 *    RGB        --> R2Y                  __/825 *826 * 2. YUV(2020)  --> bypasss               --> YUV_OUTPUT(2020)827 *    RGB        --> 709To2020->R2Y       __/828 *829 * 3. YUV(2020)  --> Y2R->2020To709        --> RGB_OUTPUT(709)830 *    RGB        --> R2Y                  __/831 *832 * 4. YUV(601/709)-> Y2R->709To2020->R2Y   --> YUV_OUTPUT(2020)833 *    RGB        --> 709To2020->R2Y       __/834 *835 * 5. YUV(601/709)-> bypass                --> YUV_OUTPUT(709)836 *    RGB        --> R2Y                  __/837 *838 * 6. YUV(601/709)-> bypass                --> YUV_OUTPUT(601)839 *    RGB        --> R2Y(601)             __/840 *841 * 7. YUV        --> Y2R(709)              --> RGB_OUTPUT(709)842 *    RGB        --> bypass               __/843 *844 * 8. RGB        --> 709To2020->R2Y        --> YUV_OUTPUT(2020)845 *846 * 9. RGB        --> R2Y(709)              --> YUV_OUTPUT(709)847 *848 * 10. RGB       --> R2Y(601)              --> YUV_OUTPUT(601)849 *850 * 11. RGB       --> bypass                --> RGB_OUTPUT(709)851 */852 853static void vop2_setup_csc_mode(struct vop2_video_port *vp,854				struct vop2_win *win,855				struct drm_plane_state *pstate)856{857	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);858	int is_input_yuv = pstate->fb->format->is_yuv;859	int is_output_yuv = is_yuv_output(vcstate->bus_format);860	int input_csc = V4L2_COLORSPACE_DEFAULT;861	int output_csc = vcstate->color_space;862	bool r2y_en, y2r_en;863	int csc_mode;864 865	if (is_input_yuv && !is_output_yuv) {866		y2r_en = true;867		r2y_en = false;868		csc_mode = vop2_convert_csc_mode(input_csc);869	} else if (!is_input_yuv && is_output_yuv) {870		y2r_en = false;871		r2y_en = true;872		csc_mode = vop2_convert_csc_mode(output_csc);873	} else {874		y2r_en = false;875		r2y_en = false;876		csc_mode = false;877	}878 879	vop2_win_write(win, VOP2_WIN_Y2R_EN, y2r_en);880	vop2_win_write(win, VOP2_WIN_R2Y_EN, r2y_en);881	vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode);882}883 884static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq)885{886	struct vop2 *vop2 = vp->vop2;887 888	vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irq << 16 | irq);889	vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16 | irq);890}891 892static void vop2_crtc_disable_irq(struct vop2_video_port *vp, u32 irq)893{894	struct vop2 *vop2 = vp->vop2;895 896	vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16);897}898 899static int vop2_core_clks_prepare_enable(struct vop2 *vop2)900{901	int ret;902 903	ret = clk_prepare_enable(vop2->hclk);904	if (ret < 0) {905		drm_err(vop2->drm, "failed to enable hclk - %d\n", ret);906		return ret;907	}908 909	ret = clk_prepare_enable(vop2->aclk);910	if (ret < 0) {911		drm_err(vop2->drm, "failed to enable aclk - %d\n", ret);912		goto err;913	}914 915	ret = clk_prepare_enable(vop2->pclk);916	if (ret < 0) {917		drm_err(vop2->drm, "failed to enable pclk - %d\n", ret);918		goto err1;919	}920 921	return 0;922err1:923	clk_disable_unprepare(vop2->aclk);924err:925	clk_disable_unprepare(vop2->hclk);926 927	return ret;928}929 930static void rk3588_vop2_power_domain_enable_all(struct vop2 *vop2)931{932	u32 pd;933 934	pd = vop2_readl(vop2, RK3588_SYS_PD_CTRL);935	pd &= ~(VOP2_PD_CLUSTER0 | VOP2_PD_CLUSTER1 | VOP2_PD_CLUSTER2 |936		VOP2_PD_CLUSTER3 | VOP2_PD_ESMART);937 938	vop2_writel(vop2, RK3588_SYS_PD_CTRL, pd);939}940 941static void vop2_enable(struct vop2 *vop2)942{943	int ret;944 945	ret = pm_runtime_resume_and_get(vop2->dev);946	if (ret < 0) {947		drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret);948		return;949	}950 951	ret = vop2_core_clks_prepare_enable(vop2);952	if (ret) {953		pm_runtime_put_sync(vop2->dev);954		return;955	}956 957	ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev);958	if (ret) {959		drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret);960		return;961	}962 963	if (vop2->data->soc_id == 3566)964		vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);965 966	if (vop2->data->soc_id == 3588)967		rk3588_vop2_power_domain_enable_all(vop2);968 969	vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);970 971	/*972	 * Disable auto gating, this is a workaround to973	 * avoid display image shift when a window enabled.974	 */975	regmap_clear_bits(vop2->map, RK3568_SYS_AUTO_GATING_CTRL,976			  RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN);977 978	vop2_writel(vop2, RK3568_SYS0_INT_CLR,979		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);980	vop2_writel(vop2, RK3568_SYS0_INT_EN,981		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);982	vop2_writel(vop2, RK3568_SYS1_INT_CLR,983		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);984	vop2_writel(vop2, RK3568_SYS1_INT_EN,985		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);986}987 988static void vop2_disable(struct vop2 *vop2)989{990	rockchip_drm_dma_detach_device(vop2->drm, vop2->dev);991 992	pm_runtime_put_sync(vop2->dev);993 994	regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register);995 996	clk_disable_unprepare(vop2->pclk);997	clk_disable_unprepare(vop2->aclk);998	clk_disable_unprepare(vop2->hclk);999}1000 1001static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,1002				     struct drm_atomic_state *state)1003{1004	struct vop2_video_port *vp = to_vop2_video_port(crtc);1005	struct vop2 *vop2 = vp->vop2;1006	struct drm_crtc_state *old_crtc_state;1007	int ret;1008 1009	vop2_lock(vop2);1010 1011	old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);1012	drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);1013 1014	drm_crtc_vblank_off(crtc);1015 1016	/*1017	 * Vop standby will take effect at end of current frame,1018	 * if dsp hold valid irq happen, it means standby complete.1019	 *1020	 * we must wait standby complete when we want to disable aclk,1021	 * if not, memory bus maybe dead.1022	 */1023	reinit_completion(&vp->dsp_hold_completion);1024 1025	vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID);1026 1027	vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY);1028 1029	ret = wait_for_completion_timeout(&vp->dsp_hold_completion,1030					  msecs_to_jiffies(50));1031	if (!ret)1032		drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id);1033 1034	vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID);1035 1036	clk_disable_unprepare(vp->dclk);1037 1038	vop2->enable_count--;1039 1040	if (!vop2->enable_count)1041		vop2_disable(vop2);1042 1043	vop2_unlock(vop2);1044 1045	if (crtc->state->event && !crtc->state->active) {1046		spin_lock_irq(&crtc->dev->event_lock);1047		drm_crtc_send_vblank_event(crtc, crtc->state->event);1048		spin_unlock_irq(&crtc->dev->event_lock);1049 1050		crtc->state->event = NULL;1051	}1052}1053 1054static int vop2_plane_atomic_check(struct drm_plane *plane,1055				   struct drm_atomic_state *astate)1056{1057	struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane);1058	struct drm_framebuffer *fb = pstate->fb;1059	struct drm_crtc *crtc = pstate->crtc;1060	struct drm_crtc_state *cstate;1061	struct vop2_video_port *vp;1062	struct vop2 *vop2;1063	const struct vop2_data *vop2_data;1064	struct drm_rect *dest = &pstate->dst;1065	struct drm_rect *src = &pstate->src;1066	int min_scale = FRAC_16_16(1, 8);1067	int max_scale = FRAC_16_16(8, 1);1068	int format;1069	int ret;1070 1071	if (!crtc)1072		return 0;1073 1074	vp = to_vop2_video_port(crtc);1075	vop2 = vp->vop2;1076	vop2_data = vop2->data;1077 1078	cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc);1079	if (WARN_ON(!cstate))1080		return -EINVAL;1081 1082	ret = drm_atomic_helper_check_plane_state(pstate, cstate,1083						  min_scale, max_scale,1084						  true, true);1085	if (ret)1086		return ret;1087 1088	if (!pstate->visible)1089		return 0;1090 1091	format = vop2_convert_format(fb->format->format);1092	if (format < 0)1093		return format;1094 1095	if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 ||1096	    drm_rect_width(dest) < 4 || drm_rect_width(dest) < 4) {1097		drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n",1098			drm_rect_width(src) >> 16, drm_rect_height(src) >> 16,1099			drm_rect_width(dest), drm_rect_height(dest));1100		pstate->visible = false;1101		return 0;1102	}1103 1104	if (drm_rect_width(src) >> 16 > vop2_data->max_input.width ||1105	    drm_rect_height(src) >> 16 > vop2_data->max_input.height) {1106		drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n",1107			drm_rect_width(src) >> 16,1108			drm_rect_height(src) >> 16,1109			vop2_data->max_input.width,1110			vop2_data->max_input.height);1111		return -EINVAL;1112	}1113 1114	/*1115	 * Src.x1 can be odd when do clip, but yuv plane start point1116	 * need align with 2 pixel.1117	 */1118	if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) {1119		drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n");1120		return -EINVAL;1121	}1122 1123	return 0;1124}1125 1126static void vop2_plane_atomic_disable(struct drm_plane *plane,1127				      struct drm_atomic_state *state)1128{1129	struct drm_plane_state *old_pstate = NULL;1130	struct vop2_win *win = to_vop2_win(plane);1131	struct vop2 *vop2 = win->vop2;1132 1133	drm_dbg(vop2->drm, "%s disable\n", win->data->name);1134 1135	if (state)1136		old_pstate = drm_atomic_get_old_plane_state(state, plane);1137	if (old_pstate && !old_pstate->crtc)1138		return;1139 1140	vop2_win_disable(win);1141	vop2_win_write(win, VOP2_WIN_YUV_CLIP, 0);1142}1143 1144/*1145 * The color key is 10 bit, so all format should1146 * convert to 10 bit here.1147 */1148static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key)1149{1150	struct drm_plane_state *pstate = plane->state;1151	struct drm_framebuffer *fb = pstate->fb;1152	struct vop2_win *win = to_vop2_win(plane);1153	u32 color_key_en = 0;1154	u32 r = 0;1155	u32 g = 0;1156	u32 b = 0;1157 1158	if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) {1159		vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, 0);1160		return;1161	}1162 1163	switch (fb->format->format) {1164	case DRM_FORMAT_RGB565:1165	case DRM_FORMAT_BGR565:1166		r = (color_key & 0xf800) >> 11;1167		g = (color_key & 0x7e0) >> 5;1168		b = (color_key & 0x1f);1169		r <<= 5;1170		g <<= 4;1171		b <<= 5;1172		color_key_en = 1;1173		break;1174	case DRM_FORMAT_XRGB8888:1175	case DRM_FORMAT_ARGB8888:1176	case DRM_FORMAT_XBGR8888:1177	case DRM_FORMAT_ABGR8888:1178	case DRM_FORMAT_RGB888:1179	case DRM_FORMAT_BGR888:1180		r = (color_key & 0xff0000) >> 16;1181		g = (color_key & 0xff00) >> 8;1182		b = (color_key & 0xff);1183		r <<= 2;1184		g <<= 2;1185		b <<= 2;1186		color_key_en = 1;1187		break;1188	}1189 1190	vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, color_key_en);1191	vop2_win_write(win, VOP2_WIN_COLOR_KEY, (r << 20) | (g << 10) | b);1192}1193 1194static void vop2_plane_atomic_update(struct drm_plane *plane,1195				     struct drm_atomic_state *state)1196{1197	struct drm_plane_state *pstate = plane->state;1198	struct drm_crtc *crtc = pstate->crtc;1199	struct vop2_win *win = to_vop2_win(plane);1200	struct vop2_video_port *vp = to_vop2_video_port(crtc);1201	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;1202	struct vop2 *vop2 = win->vop2;1203	struct drm_framebuffer *fb = pstate->fb;1204	u32 bpp = vop2_get_bpp(fb->format);1205	u32 actual_w, actual_h, dsp_w, dsp_h;1206	u32 act_info, dsp_info;1207	u32 format;1208	u32 afbc_format;1209	u32 rb_swap;1210	u32 uv_swap;1211	struct drm_rect *src = &pstate->src;1212	struct drm_rect *dest = &pstate->dst;1213	u32 afbc_tile_num;1214	u32 transform_offset;1215	bool dither_up;1216	bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false;1217	bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false;1218	bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;1219	bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;1220	struct rockchip_gem_object *rk_obj;1221	unsigned long offset;1222	bool half_block_en;1223	bool afbc_en;1224	dma_addr_t yrgb_mst;1225	dma_addr_t uv_mst;1226 1227	/*1228	 * can't update plane when vop2 is disabled.1229	 */1230	if (WARN_ON(!crtc))1231		return;1232 1233	if (!pstate->visible) {1234		vop2_plane_atomic_disable(plane, state);1235		return;1236	}1237 1238	afbc_en = rockchip_afbc(plane, fb->modifier);1239 1240	offset = (src->x1 >> 16) * fb->format->cpp[0];1241 1242	/*1243	 * AFBC HDR_PTR must set to the zero offset of the framebuffer.1244	 */1245	if (afbc_en)1246		offset = 0;1247	else if (pstate->rotation & DRM_MODE_REFLECT_Y)1248		offset += ((src->y2 >> 16) - 1) * fb->pitches[0];1249	else1250		offset += (src->y1 >> 16) * fb->pitches[0];1251 1252	rk_obj = to_rockchip_obj(fb->obj[0]);1253 1254	yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];1255	if (fb->format->is_yuv) {1256		int hsub = fb->format->hsub;1257		int vsub = fb->format->vsub;1258 1259		offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub;1260		offset += (src->y1 >> 16) * fb->pitches[1] / vsub;1261 1262		if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en)1263			offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2) / vsub;1264 1265		rk_obj = to_rockchip_obj(fb->obj[0]);1266		uv_mst = rk_obj->dma_addr + offset + fb->offsets[1];1267	}1268 1269	actual_w = drm_rect_width(src) >> 16;1270	actual_h = drm_rect_height(src) >> 16;1271	dsp_w = drm_rect_width(dest);1272 1273	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {1274		drm_err(vop2->drm, "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",1275			vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);1276		dsp_w = adjusted_mode->hdisplay - dest->x1;1277		if (dsp_w < 4)1278			dsp_w = 4;1279		actual_w = dsp_w * actual_w / drm_rect_width(dest);1280	}1281 1282	dsp_h = drm_rect_height(dest);1283 1284	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {1285		drm_err(vop2->drm, "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",1286			vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);1287		dsp_h = adjusted_mode->vdisplay - dest->y1;1288		if (dsp_h < 4)1289			dsp_h = 4;1290		actual_h = dsp_h * actual_h / drm_rect_height(dest);1291	}1292 1293	/*1294	 * This is workaround solution for IC design:1295	 * esmart can't support scale down when actual_w % 16 == 1.1296	 */1297	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {1298		if (actual_w > dsp_w && (actual_w & 0xf) == 1) {1299			drm_err(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",1300				vp->id, win->data->name, actual_w);1301			actual_w -= 1;1302		}1303	}1304 1305	if (afbc_en && actual_w % 4) {1306		drm_err(vop2->drm, "vp%d %s actual_w[%d] not 4 pixel aligned\n",1307			vp->id, win->data->name, actual_w);1308		actual_w = ALIGN_DOWN(actual_w, 4);1309	}1310 1311	act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);1312	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);1313 1314	format = vop2_convert_format(fb->format->format);1315	half_block_en = vop2_half_block_enable(pstate);1316 1317	drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n",1318		vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h,1319		dest->x1, dest->y1,1320		&fb->format->format,1321		afbc_en ? "AFBC" : "", &yrgb_mst);1322 1323	if (vop2_cluster_window(win))1324		vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, half_block_en);1325 1326	if (afbc_en) {1327		u32 stride;1328 1329		/* the afbc superblock is 16 x 16 */1330		afbc_format = vop2_convert_afbc_format(fb->format->format);1331 1332		/* Enable color transform for YTR */1333		if (fb->modifier & AFBC_FORMAT_MOD_YTR)1334			afbc_format |= (1 << 4);1335 1336		afbc_tile_num = ALIGN(actual_w, 16) >> 4;1337 1338		/*1339		 * AFBC pic_vir_width is count by pixel, this is different1340		 * with WIN_VIR_STRIDE.1341		 */1342		stride = (fb->pitches[0] << 3) / bpp;1343		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))1344			drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",1345				vp->id, win->data->name, stride);1346 1347		uv_swap = vop2_afbc_uv_swap(fb->format->format);1348		/*1349		 * This is a workaround for crazy IC design, Cluster1350		 * and Esmart/Smart use different format configuration map:1351		 * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart.1352		 *1353		 * This is one thing we can make the convert simple:1354		 * AFBCD decode all the YUV data to YUV444. So we just1355		 * set all the yuv 10 bit to YUV444_10.1356		 */1357		if (fb->format->is_yuv && bpp == 10)1358			format = VOP2_CLUSTER_YUV444_10;1359 1360		if (vop2_cluster_window(win))1361			vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1);1362		vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format);1363		vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap);1364		/*1365		 * On rk3566/8, this bit is auto gating enable,1366		 * but this function is not work well so we need1367		 * to disable it for these two platform.1368		 * On rk3588, and the following new soc(rk3528/rk3576),1369		 * this bit is gating disable, we should write 1 to1370		 * disable gating when enable afbc.1371		 */1372		if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)1373			vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);1374		else1375			vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1);1376 1377		vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);1378		transform_offset = vop2_afbc_transform_offset(pstate, half_block_en);1379		vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);1380		vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info);1381		vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, transform_offset);1382		vop2_win_write(win, VOP2_WIN_AFBC_PIC_OFFSET, ((src->x1 >> 16) | src->y1));1383		vop2_win_write(win, VOP2_WIN_AFBC_DSP_OFFSET, (dest->x1 | (dest->y1 << 16)));1384		vop2_win_write(win, VOP2_WIN_AFBC_PIC_VIR_WIDTH, stride);1385		vop2_win_write(win, VOP2_WIN_AFBC_TILE_NUM, afbc_tile_num);1386		vop2_win_write(win, VOP2_WIN_XMIRROR, xmirror);1387		vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270);1388		vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90);1389	} else {1390		if (vop2_cluster_window(win)) {1391			vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 0);1392			vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, 0);1393		}1394 1395		vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4));1396	}1397 1398	vop2_win_write(win, VOP2_WIN_YMIRROR, ymirror);1399 1400	if (rotate_90 || rotate_270) {1401		act_info = swahw32(act_info);1402		actual_w = drm_rect_height(src) >> 16;1403		actual_h = drm_rect_width(src) >> 16;1404	}1405 1406	vop2_win_write(win, VOP2_WIN_FORMAT, format);1407	vop2_win_write(win, VOP2_WIN_YRGB_MST, yrgb_mst);1408 1409	rb_swap = vop2_win_rb_swap(fb->format->format);1410	vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap);1411	if (!vop2_cluster_window(win)) {1412		uv_swap = vop2_win_uv_swap(fb->format->format);1413		vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap);1414	}1415 1416	if (fb->format->is_yuv) {1417		vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4));1418		vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst);1419	}1420 1421	vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format);1422	if (!vop2_cluster_window(win))1423		vop2_plane_setup_color_key(plane, 0);1424	vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info);1425	vop2_win_write(win, VOP2_WIN_DSP_INFO, dsp_info);1426	vop2_win_write(win, VOP2_WIN_DSP_ST, dest->y1 << 16 | (dest->x1 & 0xffff));1427 1428	vop2_setup_csc_mode(vp, win, pstate);1429 1430	dither_up = vop2_win_dither_up(fb->format->format);1431	vop2_win_write(win, VOP2_WIN_DITHER_UP, dither_up);1432 1433	vop2_win_write(win, VOP2_WIN_ENABLE, 1);1434 1435	if (vop2_cluster_window(win)) {1436		int lb_mode = vop2_get_cluster_lb_mode(win, pstate);1437 1438		vop2_win_write(win, VOP2_WIN_CLUSTER_LB_MODE, lb_mode);1439		vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 1);1440	}1441}1442 1443static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = {1444	.atomic_check = vop2_plane_atomic_check,1445	.atomic_update = vop2_plane_atomic_update,1446	.atomic_disable = vop2_plane_atomic_disable,1447};1448 1449static const struct drm_plane_funcs vop2_plane_funcs = {1450	.update_plane	= drm_atomic_helper_update_plane,1451	.disable_plane	= drm_atomic_helper_disable_plane,1452	.destroy = drm_plane_cleanup,1453	.reset = drm_atomic_helper_plane_reset,1454	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,1455	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,1456	.format_mod_supported = rockchip_vop2_mod_supported,1457};1458 1459static int vop2_crtc_enable_vblank(struct drm_crtc *crtc)1460{1461	struct vop2_video_port *vp = to_vop2_video_port(crtc);1462 1463	vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD);1464 1465	return 0;1466}1467 1468static void vop2_crtc_disable_vblank(struct drm_crtc *crtc)1469{1470	struct vop2_video_port *vp = to_vop2_video_port(crtc);1471 1472	vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD);1473}1474 1475static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,1476				 const struct drm_display_mode *mode,1477				 struct drm_display_mode *adj_mode)1478{1479	drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V |1480					CRTC_STEREO_DOUBLE);1481 1482	return true;1483}1484 1485static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)1486{1487	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);1488 1489	switch (vcstate->bus_format) {1490	case MEDIA_BUS_FMT_RGB565_1X16:1491		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;1492		break;1493	case MEDIA_BUS_FMT_RGB666_1X18:1494	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:1495	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:1496		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;1497		*dsp_ctrl |= RGB888_TO_RGB666;1498		break;1499	case MEDIA_BUS_FMT_YUV8_1X24:1500	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:1501		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;1502		break;1503	default:1504		break;1505	}1506 1507	if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)1508		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;1509 1510	*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,1511				DITHER_DOWN_ALLEGRO);1512}1513 1514static void vop2_post_config(struct drm_crtc *crtc)1515{1516	struct vop2_video_port *vp = to_vop2_video_port(crtc);1517	struct drm_display_mode *mode = &crtc->state->adjusted_mode;1518	u16 vtotal = mode->crtc_vtotal;1519	u16 hdisplay = mode->crtc_hdisplay;1520	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;1521	u16 vdisplay = mode->crtc_vdisplay;1522	u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;1523	u32 left_margin = 100, right_margin = 100;1524	u32 top_margin = 100, bottom_margin = 100;1525	u16 hsize = hdisplay * (left_margin + right_margin) / 200;1526	u16 vsize = vdisplay * (top_margin + bottom_margin) / 200;1527	u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;1528	u16 hact_end, vact_end;1529	u32 val;1530	u32 bg_dly;1531	u32 pre_scan_dly;1532 1533	bg_dly = vp->data->pre_scan_max_dly[3];1534	vop2_writel(vp->vop2, RK3568_VP_BG_MIX_CTRL(vp->id),1535		    FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly));1536 1537	pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len;1538	vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly);1539 1540	vsize = rounddown(vsize, 2);1541	hsize = rounddown(hsize, 2);1542	hact_st += hdisplay * (100 - left_margin) / 200;1543	hact_end = hact_st + hsize;1544	val = hact_st << 16;1545	val |= hact_end;1546	vop2_vp_write(vp, RK3568_VP_POST_DSP_HACT_INFO, val);1547	vact_st += vdisplay * (100 - top_margin) / 200;1548	vact_end = vact_st + vsize;1549	val = vact_st << 16;1550	val |= vact_end;1551	vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO, val);1552	val = scl_cal_scale2(vdisplay, vsize) << 16;1553	val |= scl_cal_scale2(hdisplay, hsize);1554	vop2_vp_write(vp, RK3568_VP_POST_SCL_FACTOR_YRGB, val);1555 1556	val = 0;1557	if (hdisplay != hsize)1558		val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN;1559	if (vdisplay != vsize)1560		val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN;1561	vop2_vp_write(vp, RK3568_VP_POST_SCL_CTRL, val);1562 1563	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {1564		u16 vact_st_f1 = vtotal + vact_st + 1;1565		u16 vact_end_f1 = vact_st_f1 + vsize;1566 1567		val = vact_st_f1 << 16 | vact_end_f1;1568		vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val);1569	}1570 1571	vop2_vp_write(vp, RK3568_VP_DSP_BG, 0);1572}1573 1574static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)1575{1576	struct vop2 *vop2 = vp->vop2;1577	struct drm_crtc *crtc = &vp->crtc;1578	u32 die, dip;1579 1580	die = vop2_readl(vop2, RK3568_DSP_IF_EN);1581	dip = vop2_readl(vop2, RK3568_DSP_IF_POL);1582 1583	switch (id) {1584	case ROCKCHIP_VOP2_EP_RGB0:1585		die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX;1586		die |= RK3568_SYS_DSP_INFACE_EN_RGB |1587			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id);1588		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;1589		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);1590		if (polflags & POLFLAG_DCLK_INV)1591			regmap_write(vop2->sys_grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3));1592		else1593			regmap_write(vop2->sys_grf, RK3568_GRF_VO_CON1, BIT(3 + 16));1594		break;1595	case ROCKCHIP_VOP2_EP_HDMI0:1596		die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX;1597		die |= RK3568_SYS_DSP_INFACE_EN_HDMI |1598			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id);1599		dip &= ~RK3568_DSP_IF_POL__HDMI_PIN_POL;1600		dip |= FIELD_PREP(RK3568_DSP_IF_POL__HDMI_PIN_POL, polflags);1601		break;1602	case ROCKCHIP_VOP2_EP_EDP0:1603		die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX;1604		die |= RK3568_SYS_DSP_INFACE_EN_EDP |1605			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id);1606		dip &= ~RK3568_DSP_IF_POL__EDP_PIN_POL;1607		dip |= FIELD_PREP(RK3568_DSP_IF_POL__EDP_PIN_POL, polflags);1608		break;1609	case ROCKCHIP_VOP2_EP_MIPI0:1610		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX;1611		die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 |1612			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id);1613		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;1614		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);1615		break;1616	case ROCKCHIP_VOP2_EP_MIPI1:1617		die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX;1618		die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 |1619			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);1620		dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;1621		dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);1622		break;1623	case ROCKCHIP_VOP2_EP_LVDS0:1624		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX;1625		die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 |1626			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id);1627		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;1628		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);1629		break;1630	case ROCKCHIP_VOP2_EP_LVDS1:1631		die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX;1632		die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 |1633			   FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id);1634		dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;1635		dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);1636		break;1637	default:1638		drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id);1639		return 0;1640	}1641 1642	dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;1643 1644	vop2_writel(vop2, RK3568_DSP_IF_EN, die);1645	vop2_writel(vop2, RK3568_DSP_IF_POL, dip);1646 1647	return crtc->state->adjusted_mode.crtc_clock  * 1000LL;1648}1649 1650/*1651 * calc the dclk on rk35881652 * the available div of dclk is 1, 2, 41653 */1654static unsigned long rk3588_calc_dclk(unsigned long child_clk, unsigned long max_dclk)1655{1656	if (child_clk * 4 <= max_dclk)1657		return child_clk * 4;1658	else if (child_clk * 2 <= max_dclk)1659		return child_clk * 2;1660	else if (child_clk <= max_dclk)1661		return child_clk;1662	else1663		return 0;1664}1665 1666/*1667 * 4 pixclk/cycle on rk35881668 * RGB/eDP/HDMI: if_pixclk >= dclk_core1669 * DP: dp_pixclk = dclk_out <= dclk_core1670 * DSI: mipi_pixclk <= dclk_out <= dclk_core1671 */1672static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id,1673					 int *dclk_core_div, int *dclk_out_div,1674					 int *if_pixclk_div, int *if_dclk_div)1675{1676	struct vop2 *vop2 = vp->vop2;1677	struct drm_crtc *crtc = &vp->crtc;1678	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;1679	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);1680	int output_mode = vcstate->output_mode;1681	unsigned long v_pixclk = adjusted_mode->crtc_clock * 1000LL; /* video timing pixclk */1682	unsigned long dclk_core_rate = v_pixclk >> 2;1683	unsigned long dclk_rate = v_pixclk;1684	unsigned long dclk_out_rate;1685	unsigned long if_pixclk_rate;1686	int K = 1;1687 1688	if (vop2_output_if_is_hdmi(id)) {1689		/*1690		 * K = 2: dclk_core = if_pixclk_rate > if_dclk_rate1691		 * K = 1: dclk_core = hdmie_edp_dclk > if_pixclk_rate1692		 */1693		if (output_mode == ROCKCHIP_OUT_MODE_YUV420) {1694			dclk_rate = dclk_rate >> 1;1695			K = 2;1696		}1697 1698		if_pixclk_rate = (dclk_core_rate << 1) / K;1699		/*1700		 * if_dclk_rate = dclk_core_rate / K;1701		 * *if_pixclk_div = dclk_rate / if_pixclk_rate;1702		 * *if_dclk_div = dclk_rate / if_dclk_rate;1703		 */1704		*if_pixclk_div = 2;1705		*if_dclk_div = 4;1706	} else if (vop2_output_if_is_edp(id)) {1707		/*1708		 * edp_pixclk = edp_dclk > dclk_core1709		 */1710		if_pixclk_rate = v_pixclk / K;1711		dclk_rate = if_pixclk_rate * K;1712		/*1713		 * *if_pixclk_div = dclk_rate / if_pixclk_rate;1714		 * *if_dclk_div = *if_pixclk_div;1715		 */1716		*if_pixclk_div = K;1717		*if_dclk_div = K;1718	} else if (vop2_output_if_is_dp(id)) {1719		if (output_mode == ROCKCHIP_OUT_MODE_YUV420)1720			dclk_out_rate = v_pixclk >> 3;1721		else1722			dclk_out_rate = v_pixclk >> 2;1723 1724		dclk_rate = rk3588_calc_dclk(dclk_out_rate, 600000);1725		if (!dclk_rate) {1726			drm_err(vop2->drm, "DP dclk_out_rate out of range, dclk_out_rate: %ld KHZ\n",1727				dclk_out_rate);1728			return 0;1729		}1730		*dclk_out_div = dclk_rate / dclk_out_rate;1731	} else if (vop2_output_if_is_mipi(id)) {1732		if_pixclk_rate = dclk_core_rate / K;1733		/*1734		 * dclk_core = dclk_out * K = if_pixclk * K = v_pixclk / 41735		 */1736		dclk_out_rate = if_pixclk_rate;1737		/*1738		 * dclk_rate = N * dclk_core_rate N = (1,2,4 ),1739		 * we get a little factor here1740		 */1741		dclk_rate = rk3588_calc_dclk(dclk_out_rate, 600000);1742		if (!dclk_rate) {1743			drm_err(vop2->drm, "MIPI dclk out of range, dclk_out_rate: %ld KHZ\n",1744				dclk_out_rate);1745			return 0;1746		}1747		*dclk_out_div = dclk_rate / dclk_out_rate;1748		/*1749		 * mipi pixclk == dclk_out1750		 */1751		*if_pixclk_div = 1;1752	} else if (vop2_output_if_is_dpi(id)) {1753		dclk_rate = v_pixclk;1754	}1755 1756	*dclk_core_div = dclk_rate / dclk_core_rate;1757	*if_pixclk_div = ilog2(*if_pixclk_div);1758	*if_dclk_div = ilog2(*if_dclk_div);1759	*dclk_core_div = ilog2(*dclk_core_div);1760	*dclk_out_div = ilog2(*dclk_out_div);1761 1762	drm_dbg(vop2->drm, "dclk: %ld, pixclk_div: %d, dclk_div: %d\n",1763		dclk_rate, *if_pixclk_div, *if_dclk_div);1764 1765	return dclk_rate;1766}1767 1768/*1769 * MIPI port mux on rk3588:1770 * 0: Video Port21771 * 1: Video Port31772 * 3: Video Port 1(MIPI1 only)1773 */1774static u32 rk3588_get_mipi_port_mux(int vp_id)1775{1776	if (vp_id == 1)1777		return 3;1778	else if (vp_id == 3)1779		return 1;1780	else1781		return 0;1782}1783 1784static u32 rk3588_get_hdmi_pol(u32 flags)1785{1786	u32 val;1787 1788	val = (flags & DRM_MODE_FLAG_NHSYNC) ? BIT(HSYNC_POSITIVE) : 0;1789	val |= (flags & DRM_MODE_FLAG_NVSYNC) ? BIT(VSYNC_POSITIVE) : 0;1790 1791	return val;1792}1793 1794static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)1795{1796	struct vop2 *vop2 = vp->vop2;1797	int dclk_core_div, dclk_out_div, if_pixclk_div, if_dclk_div;1798	unsigned long clock;1799	u32 die, dip, div, vp_clk_div, val;1800 1801	clock = rk3588_calc_cru_cfg(vp, id, &dclk_core_div, &dclk_out_div,1802				    &if_pixclk_div, &if_dclk_div);1803	if (!clock)1804		return 0;1805 1806	vp_clk_div = FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_CORE_DIV, dclk_core_div);1807	vp_clk_div |= FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_OUT_DIV, dclk_out_div);1808 1809	die = vop2_readl(vop2, RK3568_DSP_IF_EN);1810	dip = vop2_readl(vop2, RK3568_DSP_IF_POL);1811	div = vop2_readl(vop2, RK3568_DSP_IF_CTRL);1812 1813	switch (id) {1814	case ROCKCHIP_VOP2_EP_HDMI0:1815		div &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV;1816		div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV;1817		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);1818		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);1819		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX;1820		die |= RK3588_SYS_DSP_INFACE_EN_HDMI0 |1821			    FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id);1822		val = rk3588_get_hdmi_pol(polflags);1823		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 1, 1));1824		regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 6, 5));1825		break;1826	case ROCKCHIP_VOP2_EP_HDMI1:1827		div &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV;1828		div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV;1829		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV, if_dclk_div);1830		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV, if_pixclk_div);1831		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX;1832		die |= RK3588_SYS_DSP_INFACE_EN_HDMI1 |1833			    FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id);1834		val = rk3588_get_hdmi_pol(polflags);1835		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 4, 4));1836		regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 8, 7));1837		break;1838	case ROCKCHIP_VOP2_EP_EDP0:1839		div &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV;1840		div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV;1841		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);1842		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);1843		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX;1844		die |= RK3588_SYS_DSP_INFACE_EN_EDP0 |1845			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id);1846		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 0, 0));1847		break;1848	case ROCKCHIP_VOP2_EP_EDP1:1849		div &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV;1850		div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV;1851		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);1852		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);1853		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX;1854		die |= RK3588_SYS_DSP_INFACE_EN_EDP1 |1855			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id);1856		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 3, 3));1857		break;1858	case ROCKCHIP_VOP2_EP_MIPI0:1859		div &= ~RK3588_DSP_IF_MIPI0_PCLK_DIV;1860		div |= FIELD_PREP(RK3588_DSP_IF_MIPI0_PCLK_DIV, if_pixclk_div);1861		die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX;1862		val = rk3588_get_mipi_port_mux(vp->id);1863		die |= RK3588_SYS_DSP_INFACE_EN_MIPI0 |1864			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX, !!val);1865		break;1866	case ROCKCHIP_VOP2_EP_MIPI1:1867		div &= ~RK3588_DSP_IF_MIPI1_PCLK_DIV;1868		div |= FIELD_PREP(RK3588_DSP_IF_MIPI1_PCLK_DIV, if_pixclk_div);1869		die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX;1870		val = rk3588_get_mipi_port_mux(vp->id);1871		die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 |1872			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, val);1873		break;1874	case ROCKCHIP_VOP2_EP_DP0:1875		die &= ~RK3588_SYS_DSP_INFACE_EN_DP0_MUX;1876		die |= RK3588_SYS_DSP_INFACE_EN_DP0 |1877			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_DP0_MUX, vp->id);1878		dip &= ~RK3588_DSP_IF_POL__DP0_PIN_POL;1879		dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP0_PIN_POL, polflags);1880		break;1881	case ROCKCHIP_VOP2_EP_DP1:1882		die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX;1883		die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 |1884			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);1885		dip &= ~RK3588_DSP_IF_POL__DP1_PIN_POL;1886		dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP1_PIN_POL, polflags);1887		break;1888	default:1889		drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id);1890		return 0;1891	}1892 1893	dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;1894 1895	vop2_vp_write(vp, RK3588_VP_CLK_CTRL, vp_clk_div);1896	vop2_writel(vop2, RK3568_DSP_IF_EN, die);1897	vop2_writel(vop2, RK3568_DSP_IF_CTRL, div);1898	vop2_writel(vop2, RK3568_DSP_IF_POL, dip);1899 1900	return clock;1901}1902 1903static unsigned long vop2_set_intf_mux(struct vop2_video_port *vp, int ep_id, u32 polflags)1904{1905	struct vop2 *vop2 = vp->vop2;1906 1907	if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)1908		return rk3568_set_intf_mux(vp, ep_id, polflags);1909	else if (vop2->data->soc_id == 3588)1910		return rk3588_set_intf_mux(vp, ep_id, polflags);1911	else1912		return 0;1913}1914 1915static int us_to_vertical_line(struct drm_display_mode *mode, int us)1916{1917	return us * mode->clock / mode->htotal / 1000;1918}1919 1920static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,1921				    struct drm_atomic_state *state)1922{1923	struct vop2_video_port *vp = to_vop2_video_port(crtc);1924	struct vop2 *vop2 = vp->vop2;1925	const struct vop2_data *vop2_data = vop2->data;1926	const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];1927	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1928	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);1929	struct drm_display_mode *mode = &crtc->state->adjusted_mode;1930	unsigned long clock = mode->crtc_clock * 1000;1931	u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;1932	u16 hdisplay = mode->crtc_hdisplay;1933	u16 htotal = mode->crtc_htotal;1934	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;1935	u16 hact_end = hact_st + hdisplay;1936	u16 vdisplay = mode->crtc_vdisplay;1937	u16 vtotal = mode->crtc_vtotal;1938	u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;1939	u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;1940	u16 vact_end = vact_st + vdisplay;1941	u8 out_mode;1942	u32 dsp_ctrl = 0;1943	int act_end;1944	u32 val, polflags;1945	int ret;1946	struct drm_encoder *encoder;1947 1948	drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n",1949		hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",1950		drm_mode_vrefresh(mode), vcstate->output_type, vp->id);1951 1952	vop2_lock(vop2);1953 1954	ret = clk_prepare_enable(vp->dclk);1955	if (ret < 0) {1956		drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n",1957			vp->id, ret);1958		vop2_unlock(vop2);1959		return;1960	}1961 1962	if (!vop2->enable_count)1963		vop2_enable(vop2);1964 1965	vop2->enable_count++;1966 1967	vcstate->yuv_overlay = is_yuv_output(vcstate->bus_format);1968 1969	vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY);1970 1971	polflags = 0;1972	if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)1973		polflags |= POLFLAG_DCLK_INV;1974	if (mode->flags & DRM_MODE_FLAG_PHSYNC)1975		polflags |= BIT(HSYNC_POSITIVE);1976	if (mode->flags & DRM_MODE_FLAG_PVSYNC)1977		polflags |= BIT(VSYNC_POSITIVE);1978 1979	drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {1980		struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);1981 1982		/*1983		 * for drive a high resolution(4KP120, 8K), vop on rk3588/rk3576 need1984		 * process multi(1/2/4/8) pixels per cycle, so the dclk feed by the1985		 * system cru may be the 1/2 or 1/4 of mode->clock.1986		 */1987		clock = vop2_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);1988	}1989 1990	if (!clock) {1991		vop2_unlock(vop2);1992		return;1993	}1994 1995	if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&1996	    !(vp_data->feature & VOP2_VP_FEATURE_OUTPUT_10BIT))1997		out_mode = ROCKCHIP_OUT_MODE_P888;1998	else1999		out_mode = vcstate->output_mode;2000 2001	dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode);2002 2003	if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))2004		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;2005	if (vop2_output_rg_swap(vop2, vcstate->bus_format))2006		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RG_SWAP;2007 2008	if (vcstate->yuv_overlay)2009		dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;2010 2011	vop2_dither_setup(crtc, &dsp_ctrl);2012 2013	vop2_vp_write(vp, RK3568_VP_DSP_HTOTAL_HS_END, (htotal << 16) | hsync_len);2014	val = hact_st << 16;2015	val |= hact_end;2016	vop2_vp_write(vp, RK3568_VP_DSP_HACT_ST_END, val);2017 2018	val = vact_st << 16;2019	val |= vact_end;2020	vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END, val);2021 2022	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {2023		u16 vact_st_f1 = vtotal + vact_st + 1;2024		u16 vact_end_f1 = vact_st_f1 + vdisplay;2025 2026		val = vact_st_f1 << 16 | vact_end_f1;2027		vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END_F1, val);2028 2029		val = vtotal << 16 | (vtotal + vsync_len);2030		vop2_vp_write(vp, RK3568_VP_DSP_VS_ST_END_F1, val);2031		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE;2032		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL;2033		dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN;2034		vtotal += vtotal + 1;2035		act_end = vact_end_f1;2036	} else {2037		act_end = vact_end;2038	}2039 2040	vop2_writel(vop2, RK3568_VP_LINE_FLAG(vp->id),2041		    (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end);2042 2043	vop2_vp_write(vp, RK3568_VP_DSP_VTOTAL_VS_END, vtotal << 16 | vsync_len);2044 2045	if (mode->flags & DRM_MODE_FLAG_DBLCLK) {2046		dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV;2047		clock *= 2;2048	}2049 2050	vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0);2051 2052	clk_set_rate(vp->dclk, clock);2053 2054	vop2_post_config(crtc);2055 2056	vop2_cfg_done(vp);2057 2058	vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);2059 2060	drm_crtc_vblank_on(crtc);2061 2062	vop2_unlock(vop2);2063}2064 2065static int vop2_crtc_atomic_check(struct drm_crtc *crtc,2066				  struct drm_atomic_state *state)2067{2068	struct vop2_video_port *vp = to_vop2_video_port(crtc);2069	struct drm_plane *plane;2070	int nplanes = 0;2071	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);2072 2073	drm_atomic_crtc_state_for_each_plane(plane, crtc_state)2074		nplanes++;2075 2076	if (nplanes > vp->nlayers)2077		return -EINVAL;2078 2079	return 0;2080}2081 2082static bool is_opaque(u16 alpha)2083{2084	return (alpha >> 8) == 0xff;2085}2086 2087static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,2088			     struct vop2_alpha *alpha)2089{2090	int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1;2091	int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1;2092	int src_color_mode = alpha_config->src_premulti_en ?2093				ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;2094	int dst_color_mode = alpha_config->dst_premulti_en ?2095				ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;2096 2097	alpha->src_color_ctrl.val = 0;2098	alpha->dst_color_ctrl.val = 0;2099	alpha->src_alpha_ctrl.val = 0;2100	alpha->dst_alpha_ctrl.val = 0;2101 2102	if (!alpha_config->src_pixel_alpha_en)2103		alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;2104	else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en)2105		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX;2106	else2107		alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;2108 2109	alpha->src_color_ctrl.bits.alpha_en = 1;2110 2111	if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) {2112		alpha->src_color_ctrl.bits.color_mode = src_color_mode;2113		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;2114	} else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) {2115		alpha->src_color_ctrl.bits.color_mode = src_color_mode;2116		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE;2117	} else {2118		alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL;2119		alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;2120	}2121	alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8;2122	alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;2123	alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;2124 2125	alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;2126	alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;2127	alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;2128	alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8;2129	alpha->dst_color_ctrl.bits.color_mode = dst_color_mode;2130	alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;2131 2132	alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;2133	alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode;2134	alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;2135	alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE;2136 2137	alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;2138	if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en)2139		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX;2140	else2141		alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;2142	alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION;2143	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;2144}2145 2146static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)2147{2148	struct vop2_video_port *vp;2149	int used_layer = 0;2150	int i;2151 2152	for (i = 0; i < port_id; i++) {2153		vp = &vop2->vps[i];2154		used_layer += hweight32(vp->win_mask);2155	}2156 2157	return used_layer;2158}2159 2160static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)2161{2162	u32 offset = (main_win->data->phys_id * 0x10);2163	struct vop2_alpha_config alpha_config;2164	struct vop2_alpha alpha;2165	struct drm_plane_state *bottom_win_pstate;2166	bool src_pixel_alpha_en = false;2167	u16 src_glb_alpha_val, dst_glb_alpha_val;2168	bool premulti_en = false;2169	bool swap = false;2170 2171	/* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */2172	bottom_win_pstate = main_win->base.state;2173	src_glb_alpha_val = 0;2174	dst_glb_alpha_val = main_win->base.state->alpha;2175 2176	if (!bottom_win_pstate->fb)2177		return;2178 2179	alpha_config.src_premulti_en = premulti_en;2180	alpha_config.dst_premulti_en = false;2181	alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;2182	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */2183	alpha_config.src_glb_alpha_value = src_glb_alpha_val;2184	alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;2185	vop2_parse_alpha(&alpha_config, &alpha);2186 2187	alpha.src_color_ctrl.bits.src_dst_swap = swap;2188	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,2189		    alpha.src_color_ctrl.val);2190	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,2191		    alpha.dst_color_ctrl.val);2192	vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,2193		    alpha.src_alpha_ctrl.val);2194	vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,2195		    alpha.dst_alpha_ctrl.val);2196}2197 2198static void vop2_setup_alpha(struct vop2_video_port *vp)2199{2200	struct vop2 *vop2 = vp->vop2;2201	struct drm_framebuffer *fb;2202	struct vop2_alpha_config alpha_config;2203	struct vop2_alpha alpha;2204	struct drm_plane *plane;2205	int pixel_alpha_en;2206	int premulti_en, gpremulti_en = 0;2207	int mixer_id;2208	u32 offset;2209	bool bottom_layer_alpha_en = false;2210	u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;2211 2212	mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);2213	alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */2214 2215	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {2216		struct vop2_win *win = to_vop2_win(plane);2217 2218		if (plane->state->normalized_zpos == 0 &&2219		    !is_opaque(plane->state->alpha) &&2220		    !vop2_cluster_window(win)) {2221			/*2222			 * If bottom layer have global alpha effect [except cluster layer,2223			 * because cluster have deal with bottom layer global alpha value2224			 * at cluster mix], bottom layer mix need deal with global alpha.2225			 */2226			bottom_layer_alpha_en = true;2227			dst_global_alpha = plane->state->alpha;2228		}2229	}2230 2231	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {2232		struct vop2_win *win = to_vop2_win(plane);2233		int zpos = plane->state->normalized_zpos;2234 2235		if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)2236			premulti_en = 1;2237		else2238			premulti_en = 0;2239 2240		plane = &win->base;2241		fb = plane->state->fb;2242 2243		pixel_alpha_en = fb->format->has_alpha;2244 2245		alpha_config.src_premulti_en = premulti_en;2246 2247		if (bottom_layer_alpha_en && zpos == 1) {2248			gpremulti_en = premulti_en;2249			/* Cd = Cs + (1 - As) * Cd * Agd */2250			alpha_config.dst_premulti_en = false;2251			alpha_config.src_pixel_alpha_en = pixel_alpha_en;2252			alpha_config.src_glb_alpha_value = plane->state->alpha;2253			alpha_config.dst_glb_alpha_value = dst_global_alpha;2254		} else if (vop2_cluster_window(win)) {2255			/* Mix output data only have pixel alpha */2256			alpha_config.dst_premulti_en = true;2257			alpha_config.src_pixel_alpha_en = true;2258			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;2259			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;2260		} else {2261			/* Cd = Cs + (1 - As) * Cd */2262			alpha_config.dst_premulti_en = true;2263			alpha_config.src_pixel_alpha_en = pixel_alpha_en;2264			alpha_config.src_glb_alpha_value = plane->state->alpha;2265			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;2266		}2267 2268		vop2_parse_alpha(&alpha_config, &alpha);2269 2270		offset = (mixer_id + zpos - 1) * 0x10;2271		vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset,2272			    alpha.src_color_ctrl.val);2273		vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset,2274			    alpha.dst_color_ctrl.val);2275		vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset,2276			    alpha.src_alpha_ctrl.val);2277		vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset,2278			    alpha.dst_alpha_ctrl.val);2279	}2280 2281	if (vp->id == 0) {2282		if (bottom_layer_alpha_en) {2283			/* Transfer pixel alpha to hdr mix */2284			alpha_config.src_premulti_en = gpremulti_en;2285			alpha_config.dst_premulti_en = true;2286			alpha_config.src_pixel_alpha_en = true;2287			alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;2288			alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;2289			vop2_parse_alpha(&alpha_config, &alpha);2290 2291			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL,2292				    alpha.src_color_ctrl.val);2293			vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL,2294				    alpha.dst_color_ctrl.val);2295			vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL,2296				    alpha.src_alpha_ctrl.val);2297			vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL,2298				    alpha.dst_alpha_ctrl.val);2299		} else {2300			vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0);2301		}2302	}2303}2304 2305static void vop2_setup_layer_mixer(struct vop2_video_port *vp)2306{2307	struct vop2 *vop2 = vp->vop2;2308	struct drm_plane *plane;2309	u32 layer_sel = 0;2310	u32 port_sel;2311	unsigned int nlayer, ofs;2312	u32 ovl_ctrl;2313	int i;2314	struct vop2_video_port *vp0 = &vop2->vps[0];2315	struct vop2_video_port *vp1 = &vop2->vps[1];2316	struct vop2_video_port *vp2 = &vop2->vps[2];2317	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);2318 2319	ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL);2320	ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;2321	if (vcstate->yuv_overlay)2322		ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id);2323	else2324		ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(vp->id);2325 2326	vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);2327 2328	port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);2329	port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;2330 2331	if (vp0->nlayers)2332		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX,2333				     vp0->nlayers - 1);2334	else2335		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8);2336 2337	if (vp1->nlayers)2338		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX,2339				     (vp0->nlayers + vp1->nlayers - 1));2340	else2341		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);2342 2343	if (vp2->nlayers)2344		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX,2345			(vp2->nlayers + vp1->nlayers + vp0->nlayers - 1));2346	else2347		port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8);2348 2349	layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);2350 2351	ofs = 0;2352	for (i = 0; i < vp->id; i++)2353		ofs += vop2->vps[i].nlayers;2354 2355	nlayer = 0;2356	drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {2357		struct vop2_win *win = to_vop2_win(plane);2358 2359		switch (win->data->phys_id) {2360		case ROCKCHIP_VOP2_CLUSTER0:2361			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0;2362			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id);2363			break;2364		case ROCKCHIP_VOP2_CLUSTER1:2365			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1;2366			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id);2367			break;2368		case ROCKCHIP_VOP2_CLUSTER2:2369			port_sel &= ~RK3588_OVL_PORT_SEL__CLUSTER2;2370			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__CLUSTER2, vp->id);2371			break;2372		case ROCKCHIP_VOP2_CLUSTER3:2373			port_sel &= ~RK3588_OVL_PORT_SEL__CLUSTER3;2374			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__CLUSTER3, vp->id);2375			break;2376		case ROCKCHIP_VOP2_ESMART0:2377			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0;2378			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id);2379			break;2380		case ROCKCHIP_VOP2_ESMART1:2381			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1;2382			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id);2383			break;2384		case ROCKCHIP_VOP2_ESMART2:2385			port_sel &= ~RK3588_OVL_PORT_SEL__ESMART2;2386			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__ESMART2, vp->id);2387			break;2388		case ROCKCHIP_VOP2_ESMART3:2389			port_sel &= ~RK3588_OVL_PORT_SEL__ESMART3;2390			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__ESMART3, vp->id);2391			break;2392		case ROCKCHIP_VOP2_SMART0:2393			port_sel &= ~RK3568_OVL_PORT_SEL__SMART0;2394			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id);2395			break;2396		case ROCKCHIP_VOP2_SMART1:2397			port_sel &= ~RK3568_OVL_PORT_SEL__SMART1;2398			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id);2399			break;2400		}2401 2402		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs,2403							  0x7);2404		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs,2405							 win->data->layer_sel_id);2406		nlayer++;2407	}2408 2409	/* configure unused layers to 0x5 (reserved) */2410	for (; nlayer < vp->nlayers; nlayer++) {2411		layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);2412		layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5);2413	}2414 2415	vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);2416	vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);2417}2418 2419static void vop2_setup_dly_for_windows(struct vop2 *vop2)2420{2421	struct vop2_win *win;2422	int i = 0;2423	u32 cdly = 0, sdly = 0;2424 2425	for (i = 0; i < vop2->data->win_size; i++) {2426		u32 dly;2427 2428		win = &vop2->win[i];2429		dly = win->delay;2430 2431		switch (win->data->phys_id) {2432		case ROCKCHIP_VOP2_CLUSTER0:2433			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly);2434			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly);2435			break;2436		case ROCKCHIP_VOP2_CLUSTER1:2437			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly);2438			cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly);2439			break;2440		case ROCKCHIP_VOP2_ESMART0:2441			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly);2442			break;2443		case ROCKCHIP_VOP2_ESMART1:2444			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly);2445			break;2446		case ROCKCHIP_VOP2_SMART0:2447			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly);2448			break;2449		case ROCKCHIP_VOP2_SMART1:2450			sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly);2451			break;2452		}2453	}2454 2455	vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly);2456	vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly);2457}2458 2459static void vop2_crtc_atomic_begin(struct drm_crtc *crtc,2460				   struct drm_atomic_state *state)2461{2462	struct vop2_video_port *vp = to_vop2_video_port(crtc);2463	struct vop2 *vop2 = vp->vop2;2464	struct drm_plane *plane;2465 2466	vp->win_mask = 0;2467 2468	drm_atomic_crtc_for_each_plane(plane, crtc) {2469		struct vop2_win *win = to_vop2_win(plane);2470 2471		win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT];2472 2473		vp->win_mask |= BIT(win->data->phys_id);2474 2475		if (vop2_cluster_window(win))2476			vop2_setup_cluster_alpha(vop2, win);2477	}2478 2479	if (!vp->win_mask)2480		return;2481 2482	vop2_setup_layer_mixer(vp);2483	vop2_setup_alpha(vp);2484	vop2_setup_dly_for_windows(vop2);2485}2486 2487static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,2488				   struct drm_atomic_state *state)2489{2490	struct vop2_video_port *vp = to_vop2_video_port(crtc);2491 2492	vop2_post_config(crtc);2493 2494	vop2_cfg_done(vp);2495 2496	spin_lock_irq(&crtc->dev->event_lock);2497 2498	if (crtc->state->event) {2499		WARN_ON(drm_crtc_vblank_get(crtc));2500		vp->event = crtc->state->event;2501		crtc->state->event = NULL;2502	}2503 2504	spin_unlock_irq(&crtc->dev->event_lock);2505}2506 2507static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = {2508	.mode_fixup = vop2_crtc_mode_fixup,2509	.atomic_check = vop2_crtc_atomic_check,2510	.atomic_begin = vop2_crtc_atomic_begin,2511	.atomic_flush = vop2_crtc_atomic_flush,2512	.atomic_enable = vop2_crtc_atomic_enable,2513	.atomic_disable = vop2_crtc_atomic_disable,2514};2515 2516static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)2517{2518	struct rockchip_crtc_state *vcstate;2519 2520	if (WARN_ON(!crtc->state))2521		return NULL;2522 2523	vcstate = kmemdup(to_rockchip_crtc_state(crtc->state),2524			  sizeof(*vcstate), GFP_KERNEL);2525	if (!vcstate)2526		return NULL;2527 2528	__drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base);2529 2530	return &vcstate->base;2531}2532 2533static void vop2_crtc_destroy_state(struct drm_crtc *crtc,2534				    struct drm_crtc_state *state)2535{2536	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);2537 2538	__drm_atomic_helper_crtc_destroy_state(&vcstate->base);2539	kfree(vcstate);2540}2541 2542static void vop2_crtc_reset(struct drm_crtc *crtc)2543{2544	struct rockchip_crtc_state *vcstate =2545		kzalloc(sizeof(*vcstate), GFP_KERNEL);2546 2547	if (crtc->state)2548		vop2_crtc_destroy_state(crtc, crtc->state);2549 2550	if (vcstate)2551		__drm_atomic_helper_crtc_reset(crtc, &vcstate->base);2552	else2553		__drm_atomic_helper_crtc_reset(crtc, NULL);2554}2555 2556static const struct drm_crtc_funcs vop2_crtc_funcs = {2557	.set_config = drm_atomic_helper_set_config,2558	.page_flip = drm_atomic_helper_page_flip,2559	.destroy = drm_crtc_cleanup,2560	.reset = vop2_crtc_reset,2561	.atomic_duplicate_state = vop2_crtc_duplicate_state,2562	.atomic_destroy_state = vop2_crtc_destroy_state,2563	.enable_vblank = vop2_crtc_enable_vblank,2564	.disable_vblank = vop2_crtc_disable_vblank,2565};2566 2567static irqreturn_t vop2_isr(int irq, void *data)2568{2569	struct vop2 *vop2 = data;2570	const struct vop2_data *vop2_data = vop2->data;2571	u32 axi_irqs[VOP2_SYS_AXI_BUS_NUM];2572	int ret = IRQ_NONE;2573	int i;2574 2575	/*2576	 * The irq is shared with the iommu. If the runtime-pm state of the2577	 * vop2-device is disabled the irq has to be targeted at the iommu.2578	 */2579	if (!pm_runtime_get_if_in_use(vop2->dev))2580		return IRQ_NONE;2581 2582	for (i = 0; i < vop2_data->nr_vps; i++) {2583		struct vop2_video_port *vp = &vop2->vps[i];2584		struct drm_crtc *crtc = &vp->crtc;2585		u32 irqs;2586 2587		irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id));2588		vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs);2589 2590		if (irqs & VP_INT_DSP_HOLD_VALID) {2591			complete(&vp->dsp_hold_completion);2592			ret = IRQ_HANDLED;2593		}2594 2595		if (irqs & VP_INT_FS_FIELD) {2596			drm_crtc_handle_vblank(crtc);2597			spin_lock(&crtc->dev->event_lock);2598			if (vp->event) {2599				u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE);2600 2601				if (!(val & BIT(vp->id))) {2602					drm_crtc_send_vblank_event(crtc, vp->event);2603					vp->event = NULL;2604					drm_crtc_vblank_put(crtc);2605				}2606			}2607			spin_unlock(&crtc->dev->event_lock);2608 2609			ret = IRQ_HANDLED;2610		}2611 2612		if (irqs & VP_INT_POST_BUF_EMPTY) {2613			drm_err_ratelimited(vop2->drm,2614					    "POST_BUF_EMPTY irq err at vp%d\n",2615					    vp->id);2616			ret = IRQ_HANDLED;2617		}2618	}2619 2620	axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS);2621	vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]);2622	axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS);2623	vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]);2624 2625	for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) {2626		if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) {2627			drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n");2628			ret = IRQ_HANDLED;2629		}2630	}2631 2632	pm_runtime_put(vop2->dev);2633 2634	return ret;2635}2636 2637static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win,2638			   unsigned long possible_crtcs)2639{2640	const struct vop2_win_data *win_data = win->data;2641	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |2642				  BIT(DRM_MODE_BLEND_PREMULTI) |2643				  BIT(DRM_MODE_BLEND_COVERAGE);2644	int ret;2645 2646	ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs,2647				       &vop2_plane_funcs, win_data->formats,2648				       win_data->nformats,2649				       win_data->format_modifiers,2650				       win->type, win_data->name);2651	if (ret) {2652		drm_err(vop2->drm, "failed to initialize plane %d\n", ret);2653		return ret;2654	}2655 2656	drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs);2657 2658	if (win->data->supported_rotations)2659		drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0,2660						   DRM_MODE_ROTATE_0 |2661						   win->data->supported_rotations);2662	drm_plane_create_alpha_property(&win->base);2663	drm_plane_create_blend_mode_property(&win->base, blend_caps);2664	drm_plane_create_zpos_property(&win->base, win->win_id, 0,2665				       vop2->registered_num_wins - 1);2666 2667	return 0;2668}2669 2670static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2)2671{2672	int i;2673 2674	for (i = 0; i < vop2->data->nr_vps; i++) {2675		struct vop2_video_port *vp = &vop2->vps[i];2676 2677		if (!vp->crtc.port)2678			continue;2679		if (vp->primary_plane)2680			continue;2681 2682		return vp;2683	}2684 2685	return NULL;2686}2687 2688static int vop2_create_crtcs(struct vop2 *vop2)2689{2690	const struct vop2_data *vop2_data = vop2->data;2691	struct drm_device *drm = vop2->drm;2692	struct device *dev = vop2->dev;2693	struct drm_plane *plane;2694	struct device_node *port;2695	struct vop2_video_port *vp;2696	int i, nvp, nvps = 0;2697	int ret;2698 2699	for (i = 0; i < vop2_data->nr_vps; i++) {2700		const struct vop2_video_port_data *vp_data;2701		struct device_node *np;2702		char dclk_name[9];2703 2704		vp_data = &vop2_data->vp[i];2705		vp = &vop2->vps[i];2706		vp->vop2 = vop2;2707		vp->id = vp_data->id;2708		vp->data = vp_data;2709 2710		snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);2711		vp->dclk = devm_clk_get(vop2->dev, dclk_name);2712		if (IS_ERR(vp->dclk)) {2713			drm_err(vop2->drm, "failed to get %s\n", dclk_name);2714			return PTR_ERR(vp->dclk);2715		}2716 2717		np = of_graph_get_remote_node(dev->of_node, i, -1);2718		if (!np) {2719			drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i);2720			continue;2721		}2722		of_node_put(np);2723 2724		port = of_graph_get_port_by_id(dev->of_node, i);2725		if (!port) {2726			drm_err(vop2->drm, "no port node found for video_port%d\n", i);2727			return -ENOENT;2728		}2729 2730		vp->crtc.port = port;2731		nvps++;2732	}2733 2734	nvp = 0;2735	for (i = 0; i < vop2->registered_num_wins; i++) {2736		struct vop2_win *win = &vop2->win[i];2737		u32 possible_crtcs = 0;2738 2739		if (vop2->data->soc_id == 3566) {2740			/*2741			 * On RK3566 these windows don't have an independent2742			 * framebuffer. They share the framebuffer with smart0,2743			 * esmart0 and cluster0 respectively.2744			 */2745			switch (win->data->phys_id) {2746			case ROCKCHIP_VOP2_SMART1:2747			case ROCKCHIP_VOP2_ESMART1:2748			case ROCKCHIP_VOP2_CLUSTER1:2749				continue;2750			}2751		}2752 2753		if (win->type == DRM_PLANE_TYPE_PRIMARY) {2754			vp = find_vp_without_primary(vop2);2755			if (vp) {2756				possible_crtcs = BIT(nvp);2757				vp->primary_plane = win;2758				nvp++;2759			} else {2760				/* change the unused primary window to overlay window */2761				win->type = DRM_PLANE_TYPE_OVERLAY;2762			}2763		}2764 2765		if (win->type == DRM_PLANE_TYPE_OVERLAY)2766			possible_crtcs = (1 << nvps) - 1;2767 2768		ret = vop2_plane_init(vop2, win, possible_crtcs);2769		if (ret) {2770			drm_err(vop2->drm, "failed to init plane %s: %d\n",2771				win->data->name, ret);2772			return ret;2773		}2774	}2775 2776	for (i = 0; i < vop2_data->nr_vps; i++) {2777		vp = &vop2->vps[i];2778 2779		if (!vp->crtc.port)2780			continue;2781 2782		plane = &vp->primary_plane->base;2783 2784		ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL,2785						&vop2_crtc_funcs,2786						"video_port%d", vp->id);2787		if (ret) {2788			drm_err(vop2->drm, "crtc init for video_port%d failed\n", i);2789			return ret;2790		}2791 2792		drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);2793 2794		init_completion(&vp->dsp_hold_completion);2795	}2796 2797	/*2798	 * On the VOP2 it's very hard to change the number of layers on a VP2799	 * during runtime, so we distribute the layers equally over the used2800	 * VPs2801	 */2802	for (i = 0; i < vop2->data->nr_vps; i++) {2803		struct vop2_video_port *vp = &vop2->vps[i];2804 2805		if (vp->crtc.port)2806			vp->nlayers = vop2_data->win_size / nvps;2807	}2808 2809	return 0;2810}2811 2812static void vop2_destroy_crtcs(struct vop2 *vop2)2813{2814	struct drm_device *drm = vop2->drm;2815	struct list_head *crtc_list = &drm->mode_config.crtc_list;2816	struct list_head *plane_list = &drm->mode_config.plane_list;2817	struct drm_crtc *crtc, *tmpc;2818	struct drm_plane *plane, *tmpp;2819 2820	list_for_each_entry_safe(plane, tmpp, plane_list, head)2821		drm_plane_cleanup(plane);2822 2823	/*2824	 * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane()2825	 * references the CRTC.2826	 */2827	list_for_each_entry_safe(crtc, tmpc, crtc_list, head) {2828		of_node_put(crtc->port);2829		drm_crtc_cleanup(crtc);2830	}2831}2832 2833static int vop2_find_rgb_encoder(struct vop2 *vop2)2834{2835	struct device_node *node = vop2->dev->of_node;2836	struct device_node *endpoint;2837	int i;2838 2839	for (i = 0; i < vop2->data->nr_vps; i++) {2840		endpoint = of_graph_get_endpoint_by_regs(node, i,2841							 ROCKCHIP_VOP2_EP_RGB0);2842		if (!endpoint)2843			continue;2844 2845		of_node_put(endpoint);2846		return i;2847	}2848 2849	return -ENOENT;2850}2851 2852static struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] = {2853	[VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0),2854	[VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5),2855	[VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14),2856	[VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 18, 18),2857	[VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_ACT_INFO, 0, 31),2858	[VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_INFO, 0, 31),2859	[VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_ST, 0, 31),2860	[VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_CLUSTER_WIN_YRGB_MST, 0, 31),2861	[VOP2_WIN_UV_MST] = REG_FIELD(RK3568_CLUSTER_WIN_CBR_MST, 0, 31),2862	[VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 19, 19),2863	[VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 0, 15),2864	[VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 16, 31),2865	[VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 8, 8),2866	[VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 9, 9),2867	[VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 10, 11),2868 2869	/* Scale */2870	[VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0, 15),2871	[VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 16, 31),2872	[VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 14, 15),2873	[VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 12, 13),2874	[VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 2, 3),2875	[VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 28, 28),2876	[VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 29, 29),2877 2878	/* cluster regs */2879	[VOP2_WIN_AFBC_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 1, 1),2880	[VOP2_WIN_CLUSTER_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 0, 0),2881	[VOP2_WIN_CLUSTER_LB_MODE] = REG_FIELD(RK3568_CLUSTER_CTRL, 4, 7),2882 2883	/* afbc regs */2884	[VOP2_WIN_AFBC_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 2, 6),2885	[VOP2_WIN_AFBC_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 9, 9),2886	[VOP2_WIN_AFBC_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 10, 10),2887	[VOP2_WIN_AFBC_AUTO_GATING_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 4, 4),2888	[VOP2_WIN_AFBC_HALF_BLOCK_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 7, 7),2889	[VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 8, 8),2890	[VOP2_WIN_AFBC_HDR_PTR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0, 31),2891	[VOP2_WIN_AFBC_PIC_SIZE] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0, 31),2892	[VOP2_WIN_AFBC_PIC_VIR_WIDTH] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0, 15),2893	[VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31),2894	[VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31),2895	[VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31),2896	[VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31),2897	[VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0),2898	[VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1),2899	[VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2),2900	[VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 3, 3),2901	[VOP2_WIN_UV_SWAP] = { .reg = 0xffffffff },2902	[VOP2_WIN_COLOR_KEY] = { .reg = 0xffffffff },2903	[VOP2_WIN_COLOR_KEY_EN] = { .reg = 0xffffffff },2904	[VOP2_WIN_SCALE_CBCR_X] = { .reg = 0xffffffff },2905	[VOP2_WIN_SCALE_CBCR_Y] = { .reg = 0xffffffff },2906	[VOP2_WIN_YRGB_HSCL_FILTER_MODE] = { .reg = 0xffffffff },2907	[VOP2_WIN_YRGB_VSCL_FILTER_MODE] = { .reg = 0xffffffff },2908	[VOP2_WIN_CBCR_VER_SCL_MODE] = { .reg = 0xffffffff },2909	[VOP2_WIN_CBCR_HSCL_FILTER_MODE] = { .reg = 0xffffffff },2910	[VOP2_WIN_CBCR_HOR_SCL_MODE] = { .reg = 0xffffffff },2911	[VOP2_WIN_CBCR_VSCL_FILTER_MODE] = { .reg = 0xffffffff },2912	[VOP2_WIN_VSD_CBCR_GT2] = { .reg = 0xffffffff },2913	[VOP2_WIN_VSD_CBCR_GT4] = { .reg = 0xffffffff },2914};2915 2916static int vop2_cluster_init(struct vop2_win *win)2917{2918	struct vop2 *vop2 = win->vop2;2919	struct reg_field *cluster_regs;2920	int ret, i;2921 2922	cluster_regs = kmemdup(vop2_cluster_regs, sizeof(vop2_cluster_regs),2923			       GFP_KERNEL);2924	if (!cluster_regs)2925		return -ENOMEM;2926 2927	for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++)2928		if (cluster_regs[i].reg != 0xffffffff)2929			cluster_regs[i].reg += win->offset;2930 2931	ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,2932					   cluster_regs,2933					   ARRAY_SIZE(vop2_cluster_regs));2934 2935	kfree(cluster_regs);2936 2937	return ret;2938};2939 2940static struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] = {2941	[VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0),2942	[VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5),2943	[VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12),2944	[VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 14, 14),2945	[VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 16, 16),2946	[VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_SMART_REGION0_ACT_INFO, 0, 31),2947	[VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_SMART_REGION0_DSP_INFO, 0, 31),2948	[VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_SMART_REGION0_DSP_ST, 0, 28),2949	[VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_SMART_REGION0_YRGB_MST, 0, 31),2950	[VOP2_WIN_UV_MST] = REG_FIELD(RK3568_SMART_REGION0_CBR_MST, 0, 31),2951	[VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 17, 17),2952	[VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 0, 15),2953	[VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 16, 31),2954	[VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_SMART_CTRL0, 0, 0),2955	[VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_SMART_CTRL0, 1, 1),2956	[VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_SMART_CTRL0, 2, 3),2957	[VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_SMART_CTRL1, 31, 31),2958	[VOP2_WIN_COLOR_KEY] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 0, 29),2959	[VOP2_WIN_COLOR_KEY_EN] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 31, 31),2960 2961	/* Scale */2962	[VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0, 15),2963	[VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 16, 31),2964	[VOP2_WIN_SCALE_CBCR_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0, 15),2965	[VOP2_WIN_SCALE_CBCR_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 16, 31),2966	[VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 0, 1),2967	[VOP2_WIN_YRGB_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 2, 3),2968	[VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 4, 5),2969	[VOP2_WIN_YRGB_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 6, 7),2970	[VOP2_WIN_CBCR_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 8, 9),2971	[VOP2_WIN_CBCR_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 10, 11),2972	[VOP2_WIN_CBCR_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 12, 13),2973	[VOP2_WIN_CBCR_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 14, 15),2974	[VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 16, 17),2975	[VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 8, 8),2976	[VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 9, 9),2977	[VOP2_WIN_VSD_CBCR_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 10, 10),2978	[VOP2_WIN_VSD_CBCR_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 11, 11),2979	[VOP2_WIN_XMIRROR] = { .reg = 0xffffffff },2980	[VOP2_WIN_CLUSTER_ENABLE] = { .reg = 0xffffffff },2981	[VOP2_WIN_AFBC_ENABLE] = { .reg = 0xffffffff },2982	[VOP2_WIN_CLUSTER_LB_MODE] = { .reg = 0xffffffff },2983	[VOP2_WIN_AFBC_FORMAT] = { .reg = 0xffffffff },2984	[VOP2_WIN_AFBC_RB_SWAP] = { .reg = 0xffffffff },2985	[VOP2_WIN_AFBC_UV_SWAP] = { .reg = 0xffffffff },2986	[VOP2_WIN_AFBC_AUTO_GATING_EN] = { .reg = 0xffffffff },2987	[VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = { .reg = 0xffffffff },2988	[VOP2_WIN_AFBC_PIC_VIR_WIDTH] = { .reg = 0xffffffff },2989	[VOP2_WIN_AFBC_TILE_NUM] = { .reg = 0xffffffff },2990	[VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff },2991	[VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff },2992	[VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff },2993	[VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff },2994	[VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff },2995	[VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff },2996	[VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff },2997	[VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff },2998};2999 3000static int vop2_esmart_init(struct vop2_win *win)3001{3002	struct vop2 *vop2 = win->vop2;3003	struct reg_field *esmart_regs;3004	int ret, i;3005 3006	esmart_regs = kmemdup(vop2_esmart_regs, sizeof(vop2_esmart_regs),3007			      GFP_KERNEL);3008	if (!esmart_regs)3009		return -ENOMEM;3010 3011	for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++)3012		if (esmart_regs[i].reg != 0xffffffff)3013			esmart_regs[i].reg += win->offset;3014 3015	ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,3016					   esmart_regs,3017					   ARRAY_SIZE(vop2_esmart_regs));3018 3019	kfree(esmart_regs);3020 3021	return ret;3022};3023 3024static int vop2_win_init(struct vop2 *vop2)3025{3026	const struct vop2_data *vop2_data = vop2->data;3027	struct vop2_win *win;3028	int i, ret;3029 3030	for (i = 0; i < vop2_data->win_size; i++) {3031		const struct vop2_win_data *win_data = &vop2_data->win[i];3032 3033		win = &vop2->win[i];3034		win->data = win_data;3035		win->type = win_data->type;3036		win->offset = win_data->base;3037		win->win_id = i;3038		win->vop2 = vop2;3039		if (vop2_cluster_window(win))3040			ret = vop2_cluster_init(win);3041		else3042			ret = vop2_esmart_init(win);3043		if (ret)3044			return ret;3045	}3046 3047	vop2->registered_num_wins = vop2_data->win_size;3048 3049	return 0;3050}3051 3052/*3053 * The window registers are only updated when config done is written.3054 * Until that they read back the old value. As we read-modify-write3055 * these registers mark them as non-volatile. This makes sure we read3056 * the new values from the regmap register cache.3057 */3058static const struct regmap_range vop2_nonvolatile_range[] = {3059	regmap_reg_range(0x1000, 0x23ff),3060};3061 3062static const struct regmap_access_table vop2_volatile_table = {3063	.no_ranges = vop2_nonvolatile_range,3064	.n_no_ranges = ARRAY_SIZE(vop2_nonvolatile_range),3065};3066 3067static const struct regmap_config vop2_regmap_config = {3068	.reg_bits	= 32,3069	.val_bits	= 32,3070	.reg_stride	= 4,3071	.max_register	= 0x3000,3072	.name		= "vop2",3073	.volatile_table	= &vop2_volatile_table,3074	.cache_type	= REGCACHE_MAPLE,3075};3076 3077static int vop2_bind(struct device *dev, struct device *master, void *data)3078{3079	struct platform_device *pdev = to_platform_device(dev);3080	const struct vop2_data *vop2_data;3081	struct drm_device *drm = data;3082	struct vop2 *vop2;3083	struct resource *res;3084	size_t alloc_size;3085	int ret;3086 3087	vop2_data = of_device_get_match_data(dev);3088	if (!vop2_data)3089		return -ENODEV;3090 3091	/* Allocate vop2 struct and its vop2_win array */3092	alloc_size = struct_size(vop2, win, vop2_data->win_size);3093	vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL);3094	if (!vop2)3095		return -ENOMEM;3096 3097	vop2->dev = dev;3098	vop2->data = vop2_data;3099	vop2->drm = drm;3100 3101	dev_set_drvdata(dev, vop2);3102 3103	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vop");3104	if (!res) {3105		drm_err(vop2->drm, "failed to get vop2 register byname\n");3106		return -EINVAL;3107	}3108 3109	vop2->regs = devm_ioremap_resource(dev, res);3110	if (IS_ERR(vop2->regs))3111		return PTR_ERR(vop2->regs);3112	vop2->len = resource_size(res);3113 3114	vop2->map = devm_regmap_init_mmio(dev, vop2->regs, &vop2_regmap_config);3115	if (IS_ERR(vop2->map))3116		return PTR_ERR(vop2->map);3117 3118	ret = vop2_win_init(vop2);3119	if (ret)3120		return ret;3121 3122	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma-lut");3123	if (res) {3124		vop2->lut_regs = devm_ioremap_resource(dev, res);3125		if (IS_ERR(vop2->lut_regs))3126			return PTR_ERR(vop2->lut_regs);3127	}3128	if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_GRF) {3129		vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");3130		if (IS_ERR(vop2->sys_grf))3131			return dev_err_probe(dev, PTR_ERR(vop2->sys_grf), "cannot get sys_grf");3132	}3133 3134	if (vop2_data->feature & VOP2_FEATURE_HAS_VOP_GRF) {3135		vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf");3136		if (IS_ERR(vop2->vop_grf))3137			return dev_err_probe(dev, PTR_ERR(vop2->vop_grf), "cannot get vop_grf");3138	}3139 3140	if (vop2_data->feature & VOP2_FEATURE_HAS_VO1_GRF) {3141		vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf");3142		if (IS_ERR(vop2->vo1_grf))3143			return dev_err_probe(dev, PTR_ERR(vop2->vo1_grf), "cannot get vo1_grf");3144	}3145 3146	if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_PMU) {3147		vop2->sys_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu");3148		if (IS_ERR(vop2->sys_pmu))3149			return dev_err_probe(dev, PTR_ERR(vop2->sys_pmu), "cannot get sys_pmu");3150	}3151 3152	vop2->hclk = devm_clk_get(vop2->dev, "hclk");3153	if (IS_ERR(vop2->hclk)) {3154		drm_err(vop2->drm, "failed to get hclk source\n");3155		return PTR_ERR(vop2->hclk);3156	}3157 3158	vop2->aclk = devm_clk_get(vop2->dev, "aclk");3159	if (IS_ERR(vop2->aclk)) {3160		drm_err(vop2->drm, "failed to get aclk source\n");3161		return PTR_ERR(vop2->aclk);3162	}3163 3164	vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk_vop");3165	if (IS_ERR(vop2->pclk)) {3166		drm_err(vop2->drm, "failed to get pclk source\n");3167		return PTR_ERR(vop2->pclk);3168	}3169 3170	vop2->irq = platform_get_irq(pdev, 0);3171	if (vop2->irq < 0) {3172		drm_err(vop2->drm, "cannot find irq for vop2\n");3173		return vop2->irq;3174	}3175 3176	mutex_init(&vop2->vop2_lock);3177 3178	ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);3179	if (ret)3180		return ret;3181 3182	ret = vop2_create_crtcs(vop2);3183	if (ret)3184		return ret;3185 3186	ret = vop2_find_rgb_encoder(vop2);3187	if (ret >= 0) {3188		vop2->rgb = rockchip_rgb_init(dev, &vop2->vps[ret].crtc,3189					      vop2->drm, ret);3190		if (IS_ERR(vop2->rgb)) {3191			if (PTR_ERR(vop2->rgb) == -EPROBE_DEFER) {3192				ret = PTR_ERR(vop2->rgb);3193				goto err_crtcs;3194			}3195			vop2->rgb = NULL;3196		}3197	}3198 3199	rockchip_drm_dma_init_device(vop2->drm, vop2->dev);3200 3201	pm_runtime_enable(&pdev->dev);3202 3203	return 0;3204 3205err_crtcs:3206	vop2_destroy_crtcs(vop2);3207 3208	return ret;3209}3210 3211static void vop2_unbind(struct device *dev, struct device *master, void *data)3212{3213	struct vop2 *vop2 = dev_get_drvdata(dev);3214 3215	pm_runtime_disable(dev);3216 3217	if (vop2->rgb)3218		rockchip_rgb_fini(vop2->rgb);3219 3220	vop2_destroy_crtcs(vop2);3221}3222 3223const struct component_ops vop2_component_ops = {3224	.bind = vop2_bind,3225	.unbind = vop2_unbind,3226};3227EXPORT_SYMBOL_GPL(vop2_component_ops);3228