File Index
Files and directories
Sign in
FILE

rockchip_drm_vop2.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c 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 <linux/debugfs.h>
  28#include <drm/drm_debugfs.h>
  29#include <drm/drm_flip_work.h>
  30#include <drm/drm_framebuffer.h>
  31#include <drm/drm_gem_framebuffer_helper.h>
  32#include <drm/drm_print.h>
  33#include <drm/drm_probe_helper.h>
  34#include <drm/drm_vblank.h>
  35
  36#include <uapi/linux/videodev2.h>
  37
  38#include "rockchip_drm_gem.h"
  39#include "rockchip_drm_vop2.h"
  40#include "rockchip_rgb.h"
  41
  42/*
  43 * VOP2 architecture
  44 *
  45 +----------+   +-------------+                                                        +-----------+
  46 |  Cluster |   | Sel 1 from 6|                                                        | 1 from 3  |
  47 |  window0 |   |    Layer0   |                                                        |    RGB    |
  48 +----------+   +-------------+              +---------------+    +-------------+      +-----------+
  49 +----------+   +-------------+              |N from 6 layers|    |             |
  50 |  Cluster |   | Sel 1 from 6|              |   Overlay0    +--->| Video Port0 |      +-----------+
  51 |  window1 |   |    Layer1   |              |               |    |             |      | 1 from 3  |
  52 +----------+   +-------------+              +---------------+    +-------------+      |   LVDS    |
  53 +----------+   +-------------+                                                        +-----------+
  54 |  Esmart  |   | Sel 1 from 6|
  55 |  window0 |   |   Layer2    |              +---------------+    +-------------+      +-----------+
  56 +----------+   +-------------+              |N from 6 Layers|    |             | +--> | 1 from 3  |
  57 +----------+   +-------------+   -------->  |   Overlay1    +--->| Video Port1 |      |   MIPI    |
  58 |  Esmart  |   | Sel 1 from 6|   -------->  |               |    |             |      +-----------+
  59 |  Window1 |   |   Layer3    |              +---------------+    +-------------+
  60 +----------+   +-------------+                                                        +-----------+
  61 +----------+   +-------------+                                                        | 1 from 3  |
  62 |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |   HDMI    |
  63 |  Window0 |   |    Layer4   |              |N from 6 Layers|    |             |      +-----------+
  64 +----------+   +-------------+              |   Overlay2    +--->| Video Port2 |
  65 +----------+   +-------------+              |               |    |             |      +-----------+
  66 |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |  1 from 3 |
  67 |  Window1 |   |    Layer5   |                                                        |    eDP    |
  68 +----------+   +-------------+                                                        +-----------+
  69 *
  70 */
  71
  72enum vop2_data_format {
  73	VOP2_FMT_ARGB8888 = 0,
  74	VOP2_FMT_RGB888,
  75	VOP2_FMT_RGB565,
  76	VOP2_FMT_XRGB101010,
  77	VOP2_FMT_YUV420SP,
  78	VOP2_FMT_YUV422SP,
  79	VOP2_FMT_YUV444SP,
  80	VOP2_FMT_YUYV422 = 8,
  81	VOP2_FMT_YUYV420,
  82	VOP2_FMT_VYUY422,
  83	VOP2_FMT_VYUY420,
  84	VOP2_FMT_YUV420SP_TILE_8x4 = 0x10,
  85	VOP2_FMT_YUV420SP_TILE_16x2,
  86	VOP2_FMT_YUV422SP_TILE_8x4,
  87	VOP2_FMT_YUV422SP_TILE_16x2,
  88	VOP2_FMT_YUV420SP_10,
  89	VOP2_FMT_YUV422SP_10,
  90	VOP2_FMT_YUV444SP_10,
  91};
  92
  93enum vop2_afbc_format {
  94	VOP2_AFBC_FMT_RGB565,
  95	VOP2_AFBC_FMT_ARGB2101010 = 2,
  96	VOP2_AFBC_FMT_YUV420_10BIT,
  97	VOP2_AFBC_FMT_RGB888,
  98	VOP2_AFBC_FMT_ARGB8888,
  99	VOP2_AFBC_FMT_YUV420 = 9,
 100	VOP2_AFBC_FMT_YUV422 = 0xb,
 101	VOP2_AFBC_FMT_YUV422_10BIT = 0xe,
 102	VOP2_AFBC_FMT_INVALID = -1,
 103};
 104
 105#define VOP2_MAX_DCLK_RATE		600000000UL
 106
 107/*
 108 * bus-format types.
 109 */
 110struct drm_bus_format_enum_list {
 111	int type;
 112	const char *name;
 113};
 114
 115static const struct drm_bus_format_enum_list drm_bus_format_enum_list[] = {
 116	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
 117	{ MEDIA_BUS_FMT_RGB565_1X16, "RGB565_1X16" },
 118	{ MEDIA_BUS_FMT_RGB666_1X18, "RGB666_1X18" },
 119	{ MEDIA_BUS_FMT_RGB666_1X24_CPADHI, "RGB666_1X24_CPADHI" },
 120	{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, "RGB666_1X7X3_SPWG" },
 121	{ MEDIA_BUS_FMT_YUV8_1X24, "YUV8_1X24" },
 122	{ MEDIA_BUS_FMT_UYYVYY8_0_5X24, "UYYVYY8_0_5X24" },
 123	{ MEDIA_BUS_FMT_YUV10_1X30, "YUV10_1X30" },
 124	{ MEDIA_BUS_FMT_UYYVYY10_0_5X30, "UYYVYY10_0_5X30" },
 125	{ MEDIA_BUS_FMT_RGB888_3X8, "RGB888_3X8" },
 126	{ MEDIA_BUS_FMT_RGB888_1X24, "RGB888_1X24" },
 127	{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, "RGB888_1X7X4_SPWG" },
 128	{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, "RGB888_1X7X4_JEIDA" },
 129	{ MEDIA_BUS_FMT_UYVY8_2X8, "UYVY8_2X8" },
 130	{ MEDIA_BUS_FMT_YUYV8_1X16, "YUYV8_1X16" },
 131	{ MEDIA_BUS_FMT_UYVY8_1X16, "UYVY8_1X16" },
 132	{ MEDIA_BUS_FMT_RGB101010_1X30, "RGB101010_1X30" },
 133	{ MEDIA_BUS_FMT_YUYV10_1X20, "YUYV10_1X20" },
 134};
 135
 136static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list)
 137
 138static const struct regmap_config vop2_regmap_config;
 139
 140static void vop2_lock(struct vop2 *vop2)
 141{
 142	mutex_lock(&vop2->vop2_lock);
 143}
 144
 145static void vop2_unlock(struct vop2 *vop2)
 146{
 147	mutex_unlock(&vop2->vop2_lock);
 148}
 149
 150static void vop2_win_disable(struct vop2_win *win)
 151{
 152	vop2_win_write(win, VOP2_WIN_ENABLE, 0);
 153
 154	if (vop2_cluster_window(win))
 155		vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 0);
 156}
 157
 158static u32 vop2_get_bpp(const struct drm_format_info *format)
 159{
 160	switch (format->format) {
 161	case DRM_FORMAT_YUV420_8BIT:
 162		return 12;
 163	case DRM_FORMAT_YUV420_10BIT:
 164		return 15;
 165	case DRM_FORMAT_VUY101010:
 166		return 30;
 167	default:
 168		return drm_format_info_bpp(format, 0);
 169	}
 170}
 171
 172static enum vop2_data_format vop2_convert_format(u32 format)
 173{
 174	switch (format) {
 175	case DRM_FORMAT_XRGB2101010:
 176	case DRM_FORMAT_ARGB2101010:
 177	case DRM_FORMAT_XBGR2101010:
 178	case DRM_FORMAT_ABGR2101010:
 179		return VOP2_FMT_XRGB101010;
 180	case DRM_FORMAT_XRGB8888:
 181	case DRM_FORMAT_ARGB8888:
 182	case DRM_FORMAT_XBGR8888:
 183	case DRM_FORMAT_ABGR8888:
 184		return VOP2_FMT_ARGB8888;
 185	case DRM_FORMAT_RGB888:
 186	case DRM_FORMAT_BGR888:
 187		return VOP2_FMT_RGB888;
 188	case DRM_FORMAT_RGB565:
 189	case DRM_FORMAT_BGR565:
 190		return VOP2_FMT_RGB565;
 191	case DRM_FORMAT_NV12:
 192	case DRM_FORMAT_NV21:
 193	case DRM_FORMAT_YUV420_8BIT:
 194		return VOP2_FMT_YUV420SP;
 195	case DRM_FORMAT_NV15:
 196	case DRM_FORMAT_YUV420_10BIT:
 197		return VOP2_FMT_YUV420SP_10;
 198	case DRM_FORMAT_NV16:
 199	case DRM_FORMAT_NV61:
 200		return VOP2_FMT_YUV422SP;
 201	case DRM_FORMAT_NV20:
 202	case DRM_FORMAT_Y210:
 203		return VOP2_FMT_YUV422SP_10;
 204	case DRM_FORMAT_NV24:
 205	case DRM_FORMAT_NV42:
 206		return VOP2_FMT_YUV444SP;
 207	case DRM_FORMAT_NV30:
 208		return VOP2_FMT_YUV444SP_10;
 209	case DRM_FORMAT_YUYV:
 210	case DRM_FORMAT_YVYU:
 211		return VOP2_FMT_VYUY422;
 212	case DRM_FORMAT_VYUY:
 213	case DRM_FORMAT_UYVY:
 214		return VOP2_FMT_YUYV422;
 215	default:
 216		DRM_ERROR("unsupported format[%08x]\n", format);
 217		return -EINVAL;
 218	}
 219}
 220
 221static enum vop2_afbc_format vop2_convert_afbc_format(u32 format)
 222{
 223	switch (format) {
 224	case DRM_FORMAT_XRGB2101010:
 225	case DRM_FORMAT_ARGB2101010:
 226	case DRM_FORMAT_XBGR2101010:
 227	case DRM_FORMAT_ABGR2101010:
 228		return VOP2_AFBC_FMT_ARGB2101010;
 229	case DRM_FORMAT_XRGB8888:
 230	case DRM_FORMAT_ARGB8888:
 231	case DRM_FORMAT_XBGR8888:
 232	case DRM_FORMAT_ABGR8888:
 233		return VOP2_AFBC_FMT_ARGB8888;
 234	case DRM_FORMAT_RGB888:
 235	case DRM_FORMAT_BGR888:
 236		return VOP2_AFBC_FMT_RGB888;
 237	case DRM_FORMAT_RGB565:
 238	case DRM_FORMAT_BGR565:
 239		return VOP2_AFBC_FMT_RGB565;
 240	case DRM_FORMAT_YUV420_8BIT:
 241		return VOP2_AFBC_FMT_YUV420;
 242	case DRM_FORMAT_YUV420_10BIT:
 243		return VOP2_AFBC_FMT_YUV420_10BIT;
 244	case DRM_FORMAT_YVYU:
 245	case DRM_FORMAT_YUYV:
 246	case DRM_FORMAT_VYUY:
 247	case DRM_FORMAT_UYVY:
 248		return VOP2_AFBC_FMT_YUV422;
 249	case DRM_FORMAT_Y210:
 250		return VOP2_AFBC_FMT_YUV422_10BIT;
 251	default:
 252		return VOP2_AFBC_FMT_INVALID;
 253	}
 254
 255	return VOP2_AFBC_FMT_INVALID;
 256}
 257
 258static bool vop2_win_rb_swap(u32 format)
 259{
 260	switch (format) {
 261	case DRM_FORMAT_XBGR2101010:
 262	case DRM_FORMAT_ABGR2101010:
 263	case DRM_FORMAT_XBGR8888:
 264	case DRM_FORMAT_ABGR8888:
 265	case DRM_FORMAT_BGR888:
 266	case DRM_FORMAT_BGR565:
 267		return true;
 268	default:
 269		return false;
 270	}
 271}
 272
 273static bool vop2_afbc_uv_swap(u32 format)
 274{
 275	switch (format) {
 276	case DRM_FORMAT_YUYV:
 277	case DRM_FORMAT_Y210:
 278	case DRM_FORMAT_YUV420_8BIT:
 279	case DRM_FORMAT_YUV420_10BIT:
 280		return true;
 281	default:
 282		return false;
 283	}
 284}
 285
 286static bool vop2_win_uv_swap(u32 format)
 287{
 288	switch (format) {
 289	case DRM_FORMAT_NV12:
 290	case DRM_FORMAT_NV16:
 291	case DRM_FORMAT_NV24:
 292	case DRM_FORMAT_NV15:
 293	case DRM_FORMAT_NV20:
 294	case DRM_FORMAT_NV30:
 295	case DRM_FORMAT_YUYV:
 296	case DRM_FORMAT_UYVY:
 297		return true;
 298	default:
 299		return false;
 300	}
 301}
 302
 303static bool vop2_win_dither_up(u32 format)
 304{
 305	switch (format) {
 306	case DRM_FORMAT_BGR565:
 307	case DRM_FORMAT_RGB565:
 308		return true;
 309	default:
 310		return false;
 311	}
 312}
 313
 314static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode)
 315{
 316	/*
 317	 * FIXME:
 318	 *
 319	 * There is no media type for YUV444 output,
 320	 * so when out_mode is AAAA or P888, assume output is YUV444 on
 321	 * yuv format.
 322	 *
 323	 * From H/W testing, YUV444 mode need a rb swap.
 324	 */
 325	if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 ||
 326	    bus_format == MEDIA_BUS_FMT_VYUY8_1X16 ||
 327	    bus_format == MEDIA_BUS_FMT_YVYU8_2X8 ||
 328	    bus_format == MEDIA_BUS_FMT_VYUY8_2X8 ||
 329	    ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
 330	      bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&
 331	     (output_mode == ROCKCHIP_OUT_MODE_AAAA ||
 332	      output_mode == ROCKCHIP_OUT_MODE_P888)))
 333		return true;
 334	else
 335		return false;
 336}
 337
 338static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format)
 339{
 340	if (vop2->version == VOP_VERSION_RK3588) {
 341		if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
 342		    bus_format == MEDIA_BUS_FMT_YUV10_1X30)
 343			return true;
 344	}
 345
 346	return false;
 347}
 348
 349static bool is_yuv_output(u32 bus_format)
 350{
 351	switch (bus_format) {
 352	case MEDIA_BUS_FMT_YUV8_1X24:
 353	case MEDIA_BUS_FMT_YUV10_1X30:
 354	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
 355	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
 356	case MEDIA_BUS_FMT_YUYV8_2X8:
 357	case MEDIA_BUS_FMT_YVYU8_2X8:
 358	case MEDIA_BUS_FMT_UYVY8_2X8:
 359	case MEDIA_BUS_FMT_VYUY8_2X8:
 360	case MEDIA_BUS_FMT_YUYV8_1X16:
 361	case MEDIA_BUS_FMT_YVYU8_1X16:
 362	case MEDIA_BUS_FMT_UYVY8_1X16:
 363	case MEDIA_BUS_FMT_VYUY8_1X16:
 364		return true;
 365	default:
 366		return false;
 367	}
 368}
 369
 370static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
 371{
 372	int i;
 373
 374	if (modifier == DRM_FORMAT_MOD_LINEAR)
 375		return false;
 376
 377	for (i = 0 ; i < plane->modifier_count; i++)
 378		if (plane->modifiers[i] == modifier)
 379			return true;
 380
 381	return false;
 382}
 383
 384static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
 385					u64 modifier)
 386{
 387	struct vop2_win *win = to_vop2_win(plane);
 388	struct vop2 *vop2 = win->vop2;
 389
 390	if (modifier == DRM_FORMAT_MOD_INVALID)
 391		return false;
 392
 393	if (vop2->version == VOP_VERSION_RK3568) {
 394		if (vop2_cluster_window(win)) {
 395			if (modifier == DRM_FORMAT_MOD_LINEAR) {
 396				drm_dbg_kms(vop2->drm,
 397					    "Cluster window only supports format with afbc\n");
 398				return false;
 399			}
 400		}
 401	}
 402
 403	if (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010) {
 404		if (vop2->version == VOP_VERSION_RK3588) {
 405			if (!rockchip_afbc(plane, modifier)) {
 406				drm_dbg_kms(vop2->drm, "Only support 32 bpp format with afbc\n");
 407				return false;
 408			}
 409		}
 410	}
 411
 412	if (modifier == DRM_FORMAT_MOD_LINEAR)
 413		return true;
 414
 415	if (!rockchip_afbc(plane, modifier)) {
 416		drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n",
 417			    modifier);
 418
 419		return false;
 420	}
 421
 422	return vop2_convert_afbc_format(format) >= 0;
 423}
 424
 425/*
 426 * 0: Full mode, 16 lines for one tail
 427 * 1: half block mode, 8 lines one tail
 428 */
 429static bool vop2_half_block_enable(struct drm_plane_state *pstate)
 430{
 431	if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90))
 432		return false;
 433	else
 434		return true;
 435}
 436
 437static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate,
 438				      bool afbc_half_block_en)
 439{
 440	struct drm_rect *src = &pstate->src;
 441	struct drm_framebuffer *fb = pstate->fb;
 442	u32 bpp = vop2_get_bpp(fb->format);
 443	u32 vir_width = (fb->pitches[0] << 3) / bpp;
 444	u32 width = drm_rect_width(src) >> 16;
 445	u32 height = drm_rect_height(src) >> 16;
 446	u32 act_xoffset = src->x1 >> 16;
 447	u32 act_yoffset = src->y1 >> 16;
 448	u32 align16_crop = 0;
 449	u32 align64_crop = 0;
 450	u32 height_tmp;
 451	u8 tx, ty;
 452	u8 bottom_crop_line_num = 0;
 453
 454	/* 16 pixel align */
 455	if (height & 0xf)
 456		align16_crop = 16 - (height & 0xf);
 457
 458	height_tmp = height + align16_crop;
 459
 460	/* 64 pixel align */
 461	if (height_tmp & 0x3f)
 462		align64_crop = 64 - (height_tmp & 0x3f);
 463
 464	bottom_crop_line_num = align16_crop + align64_crop;
 465
 466	switch (pstate->rotation &
 467		(DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y |
 468		 DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) {
 469	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
 470		tx = 16 - ((act_xoffset + width) & 0xf);
 471		ty = bottom_crop_line_num - act_yoffset;
 472		break;
 473	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90:
 474		tx = bottom_crop_line_num - act_yoffset;
 475		ty = vir_width - width - act_xoffset;
 476		break;
 477	case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270:
 478		tx = act_yoffset;
 479		ty = act_xoffset;
 480		break;
 481	case DRM_MODE_REFLECT_X:
 482		tx = 16 - ((act_xoffset + width) & 0xf);
 483		ty = act_yoffset;
 484		break;
 485	case DRM_MODE_REFLECT_Y:
 486		tx = act_xoffset;
 487		ty = bottom_crop_line_num - act_yoffset;
 488		break;
 489	case DRM_MODE_ROTATE_90:
 490		tx = bottom_crop_line_num - act_yoffset;
 491		ty = act_xoffset;
 492		break;
 493	case DRM_MODE_ROTATE_270:
 494		tx = act_yoffset;
 495		ty = vir_width - width - act_xoffset;
 496		break;
 497	case 0:
 498		tx = act_xoffset;
 499		ty = act_yoffset;
 500		break;
 501	}
 502
 503	if (afbc_half_block_en)
 504		ty &= 0x7f;
 505
 506#define TRANSFORM_XOFFSET GENMASK(7, 0)
 507#define TRANSFORM_YOFFSET GENMASK(23, 16)
 508	return FIELD_PREP(TRANSFORM_XOFFSET, tx) |
 509		FIELD_PREP(TRANSFORM_YOFFSET, ty);
 510}
 511
 512/*
 513 * A Cluster window has 2048 x 16 line buffer, which can
 514 * works at 2048 x 16(Full) or 4096 x 8 (Half) mode.
 515 * for Cluster_lb_mode register:
 516 * 0: half mode, for plane input width range 2048 ~ 4096
 517 * 1: half mode, for cluster work at 2 * 2048 plane mode
 518 * 2: half mode, for rotate_90/270 mode
 519 *
 520 */
 521static int vop2_get_cluster_lb_mode(struct vop2_win *win,
 522				    struct drm_plane_state *pstate)
 523{
 524	if ((pstate->rotation & DRM_MODE_ROTATE_270) ||
 525	    (pstate->rotation & DRM_MODE_ROTATE_90))
 526		return 2;
 527	else
 528		return 0;
 529}
 530
 531static u16 vop2_scale_factor(u32 src, u32 dst)
 532{
 533	u32 fac;
 534	int shift;
 535
 536	if (src == dst)
 537		return 0;
 538
 539	if (dst < 2)
 540		return U16_MAX;
 541
 542	if (src < 2)
 543		return 0;
 544
 545	if (src > dst)
 546		shift = 12;
 547	else
 548		shift = 16;
 549
 550	src--;
 551	dst--;
 552
 553	fac = DIV_ROUND_UP(src << shift, dst) - 1;
 554
 555	if (fac > U16_MAX)
 556		return U16_MAX;
 557
 558	return fac;
 559}
 560
 561static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win,
 562			     u32 src_w, u32 src_h, u32 dst_w,
 563			     u32 dst_h, u32 pixel_format)
 564{
 565	const struct drm_format_info *info;
 566	u16 hor_scl_mode, ver_scl_mode;
 567	u16 hscl_filter_mode, vscl_filter_mode;
 568	uint16_t cbcr_src_w = src_w;
 569	uint16_t cbcr_src_h = src_h;
 570	u8 gt2 = 0;
 571	u8 gt4 = 0;
 572	u32 val;
 573
 574	info = drm_format_info(pixel_format);
 575
 576	if (src_h >= (4 * dst_h)) {
 577		gt4 = 1;
 578		src_h >>= 2;
 579	} else if (src_h >= (2 * dst_h)) {
 580		gt2 = 1;
 581		src_h >>= 1;
 582	}
 583
 584	hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
 585	ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
 586
 587	if (hor_scl_mode == SCALE_UP)
 588		hscl_filter_mode = VOP2_SCALE_UP_BIC;
 589	else
 590		hscl_filter_mode = VOP2_SCALE_DOWN_BIL;
 591
 592	if (ver_scl_mode == SCALE_UP)
 593		vscl_filter_mode = VOP2_SCALE_UP_BIL;
 594	else
 595		vscl_filter_mode = VOP2_SCALE_DOWN_BIL;
 596
 597	/*
 598	 * RK3568 VOP Esmart/Smart dsp_w should be even pixel
 599	 * at scale down mode
 600	 */
 601	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
 602		if ((hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) {
 603			drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n",
 604				win->data->name, dst_w);
 605			dst_w++;
 606		}
 607	}
 608
 609	val = vop2_scale_factor(src_w, dst_w);
 610	vop2_win_write(win, VOP2_WIN_SCALE_YRGB_X, val);
 611	val = vop2_scale_factor(src_h, dst_h);
 612	vop2_win_write(win, VOP2_WIN_SCALE_YRGB_Y, val);
 613
 614	vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT4, gt4);
 615	vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT2, gt2);
 616
 617	vop2_win_write(win, VOP2_WIN_YRGB_HOR_SCL_MODE, hor_scl_mode);
 618	vop2_win_write(win, VOP2_WIN_YRGB_VER_SCL_MODE, ver_scl_mode);
 619
 620	if (vop2_cluster_window(win))
 621		return;
 622
 623	vop2_win_write(win, VOP2_WIN_YRGB_HSCL_FILTER_MODE, hscl_filter_mode);
 624	vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode);
 625
 626	if (info->is_yuv) {
 627		cbcr_src_w /= info->hsub;
 628		cbcr_src_h /= info->vsub;
 629
 630		gt4 = 0;
 631		gt2 = 0;
 632
 633		if (cbcr_src_h >= (4 * dst_h)) {
 634			gt4 = 1;
 635			cbcr_src_h >>= 2;
 636		} else if (cbcr_src_h >= (2 * dst_h)) {
 637			gt2 = 1;
 638			cbcr_src_h >>= 1;
 639		}
 640
 641		hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
 642		ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
 643
 644		val = vop2_scale_factor(cbcr_src_w, dst_w);
 645		vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val);
 646
 647		val = vop2_scale_factor(cbcr_src_h, dst_h);
 648		vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val);
 649
 650		vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4);
 651		vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT2, gt2);
 652		vop2_win_write(win, VOP2_WIN_CBCR_HOR_SCL_MODE, hor_scl_mode);
 653		vop2_win_write(win, VOP2_WIN_CBCR_VER_SCL_MODE, ver_scl_mode);
 654		vop2_win_write(win, VOP2_WIN_CBCR_HSCL_FILTER_MODE, hscl_filter_mode);
 655		vop2_win_write(win, VOP2_WIN_CBCR_VSCL_FILTER_MODE, vscl_filter_mode);
 656	}
 657}
 658
 659static int vop2_convert_csc_mode(int csc_mode)
 660{
 661	switch (csc_mode) {
 662	case V4L2_COLORSPACE_SMPTE170M:
 663	case V4L2_COLORSPACE_470_SYSTEM_M:
 664	case V4L2_COLORSPACE_470_SYSTEM_BG:
 665		return CSC_BT601L;
 666	case V4L2_COLORSPACE_REC709:
 667	case V4L2_COLORSPACE_SMPTE240M:
 668	case V4L2_COLORSPACE_DEFAULT:
 669		return CSC_BT709L;
 670	case V4L2_COLORSPACE_JPEG:
 671		return CSC_BT601F;
 672	case V4L2_COLORSPACE_BT2020:
 673		return CSC_BT2020;
 674	default:
 675		return CSC_BT709L;
 676	}
 677}
 678
 679/*
 680 * colorspace path:
 681 *      Input        Win csc                     Output
 682 * 1. YUV(2020)  --> Y2R->2020To709->R2Y   --> YUV_OUTPUT(601/709)
 683 *    RGB        --> R2Y                  __/
 684 *
 685 * 2. YUV(2020)  --> bypasss               --> YUV_OUTPUT(2020)
 686 *    RGB        --> 709To2020->R2Y       __/
 687 *
 688 * 3. YUV(2020)  --> Y2R->2020To709        --> RGB_OUTPUT(709)
 689 *    RGB        --> R2Y                  __/
 690 *
 691 * 4. YUV(601/709)-> Y2R->709To2020->R2Y   --> YUV_OUTPUT(2020)
 692 *    RGB        --> 709To2020->R2Y       __/
 693 *
 694 * 5. YUV(601/709)-> bypass                --> YUV_OUTPUT(709)
 695 *    RGB        --> R2Y                  __/
 696 *
 697 * 6. YUV(601/709)-> bypass                --> YUV_OUTPUT(601)
 698 *    RGB        --> R2Y(601)             __/
 699 *
 700 * 7. YUV        --> Y2R(709)              --> RGB_OUTPUT(709)
 701 *    RGB        --> bypass               __/
 702 *
 703 * 8. RGB        --> 709To2020->R2Y        --> YUV_OUTPUT(2020)
 704 *
 705 * 9. RGB        --> R2Y(709)              --> YUV_OUTPUT(709)
 706 *
 707 * 10. RGB       --> R2Y(601)              --> YUV_OUTPUT(601)
 708 *
 709 * 11. RGB       --> bypass                --> RGB_OUTPUT(709)
 710 */
 711
 712static void vop2_setup_csc_mode(struct vop2_video_port *vp,
 713				struct vop2_win *win,
 714				struct drm_plane_state *pstate)
 715{
 716	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
 717	int is_input_yuv = pstate->fb->format->is_yuv;
 718	int is_output_yuv = is_yuv_output(vcstate->bus_format);
 719	int input_csc = V4L2_COLORSPACE_DEFAULT;
 720	int output_csc = vcstate->color_space;
 721	bool r2y_en, y2r_en;
 722	int csc_mode;
 723
 724	if (is_input_yuv && !is_output_yuv) {
 725		y2r_en = true;
 726		r2y_en = false;
 727		csc_mode = vop2_convert_csc_mode(input_csc);
 728	} else if (!is_input_yuv && is_output_yuv) {
 729		y2r_en = false;
 730		r2y_en = true;
 731		csc_mode = vop2_convert_csc_mode(output_csc);
 732	} else {
 733		y2r_en = false;
 734		r2y_en = false;
 735		csc_mode = false;
 736	}
 737
 738	vop2_win_write(win, VOP2_WIN_Y2R_EN, y2r_en);
 739	vop2_win_write(win, VOP2_WIN_R2Y_EN, r2y_en);
 740	vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode);
 741}
 742
 743static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq)
 744{
 745	struct vop2 *vop2 = vp->vop2;
 746
 747	vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irq << 16 | irq);
 748	vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16 | irq);
 749}
 750
 751static void vop2_crtc_disable_irq(struct vop2_video_port *vp, u32 irq)
 752{
 753	struct vop2 *vop2 = vp->vop2;
 754
 755	vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16);
 756}
 757
 758static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
 759{
 760	int ret;
 761
 762	ret = clk_prepare_enable(vop2->hclk);
 763	if (ret < 0) {
 764		drm_err(vop2->drm, "failed to enable hclk - %d\n", ret);
 765		return ret;
 766	}
 767
 768	ret = clk_prepare_enable(vop2->aclk);
 769	if (ret < 0) {
 770		drm_err(vop2->drm, "failed to enable aclk - %d\n", ret);
 771		goto err;
 772	}
 773
 774	ret = clk_prepare_enable(vop2->pclk);
 775	if (ret < 0) {
 776		drm_err(vop2->drm, "failed to enable pclk - %d\n", ret);
 777		goto err1;
 778	}
 779
 780	return 0;
 781err1:
 782	clk_disable_unprepare(vop2->aclk);
 783err:
 784	clk_disable_unprepare(vop2->hclk);
 785
 786	return ret;
 787}
 788
 789static void rk3588_vop2_power_domain_enable_all(struct vop2 *vop2)
 790{
 791	u32 pd;
 792
 793	pd = vop2_readl(vop2, RK3588_SYS_PD_CTRL);
 794	pd &= ~(VOP2_PD_CLUSTER0 | VOP2_PD_CLUSTER1 | VOP2_PD_CLUSTER2 |
 795		VOP2_PD_CLUSTER3 | VOP2_PD_ESMART);
 796
 797	vop2_writel(vop2, RK3588_SYS_PD_CTRL, pd);
 798}
 799
 800static void vop2_enable(struct vop2 *vop2)
 801{
 802	int ret;
 803	u32 version;
 804
 805	ret = pm_runtime_resume_and_get(vop2->dev);
 806	if (ret < 0) {
 807		drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret);
 808		return;
 809	}
 810
 811	ret = vop2_core_clks_prepare_enable(vop2);
 812	if (ret) {
 813		pm_runtime_put_sync(vop2->dev);
 814		return;
 815	}
 816
 817	ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev);
 818	if (ret) {
 819		drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret);
 820		return;
 821	}
 822
 823	version = vop2_readl(vop2, RK3568_VERSION_INFO);
 824	if (version != vop2->version) {
 825		drm_err(vop2->drm, "Hardware version(0x%08x) mismatch\n", version);
 826		return;
 827	}
 828
 829	/*
 830	 * rk3566 share the same vop version with rk3568, so
 831	 * we need to use soc_id for identification here.
 832	 */
 833	if (vop2->data->soc_id == 3566)
 834		vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
 835
 836	if (vop2->version == VOP_VERSION_RK3588)
 837		rk3588_vop2_power_domain_enable_all(vop2);
 838
 839	if (vop2->version <= VOP_VERSION_RK3588) {
 840		vop2->old_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
 841		vop2->old_port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
 842	}
 843
 844	vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
 845
 846	/*
 847	 * Disable auto gating, this is a workaround to
 848	 * avoid display image shift when a window enabled.
 849	 */
 850	regmap_clear_bits(vop2->map, RK3568_SYS_AUTO_GATING_CTRL,
 851			  RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN);
 852
 853	vop2_writel(vop2, RK3568_SYS0_INT_CLR,
 854		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
 855	vop2_writel(vop2, RK3568_SYS0_INT_EN,
 856		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
 857	vop2_writel(vop2, RK3568_SYS1_INT_CLR,
 858		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
 859	vop2_writel(vop2, RK3568_SYS1_INT_EN,
 860		    VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
 861}
 862
 863static void vop2_disable(struct vop2 *vop2)
 864{
 865	rockchip_drm_dma_detach_device(vop2->drm, vop2->dev);
 866
 867	pm_runtime_put_sync(vop2->dev);
 868
 869	regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register);
 870
 871	clk_disable_unprepare(vop2->pclk);
 872	clk_disable_unprepare(vop2->aclk);
 873	clk_disable_unprepare(vop2->hclk);
 874}
 875
 876static bool vop2_vp_dsp_lut_is_enabled(struct vop2_video_port *vp)
 877{
 878	u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
 879
 880	return dsp_ctrl & RK3568_VP_DSP_CTRL__DSP_LUT_EN;
 881}
 882
 883static void vop2_vp_dsp_lut_disable(struct vop2_video_port *vp)
 884{
 885	u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
 886
 887	dsp_ctrl &= ~RK3568_VP_DSP_CTRL__DSP_LUT_EN;
 888	vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
 889}
 890
 891static bool vop2_vp_dsp_lut_poll_disabled(struct vop2_video_port *vp)
 892{
 893	u32 dsp_ctrl;
 894	int ret = readx_poll_timeout(vop2_vp_dsp_lut_is_enabled, vp, dsp_ctrl,
 895				!dsp_ctrl, 5, 30 * 1000);
 896	if (ret) {
 897		drm_err(vp->vop2->drm, "display LUT RAM enable timeout!\n");
 898		return false;
 899	}
 900
 901	return true;
 902}
 903
 904static void vop2_vp_dsp_lut_enable(struct vop2_video_port *vp)
 905{
 906	u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
 907
 908	dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_LUT_EN;
 909	vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
 910}
 911
 912static void vop2_vp_dsp_lut_update_enable(struct vop2_video_port *vp)
 913{
 914	u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
 915
 916	dsp_ctrl |= RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN;
 917	vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
 918}
 919
 920static inline bool vop2_supports_seamless_gamma_lut_update(struct vop2 *vop2)
 921{
 922	return vop2->version != VOP_VERSION_RK3568;
 923}
 924
 925static bool vop2_gamma_lut_in_use(struct vop2 *vop2, struct vop2_video_port *vp)
 926{
 927	const int nr_vps = vop2->data->nr_vps;
 928	int gamma_en_vp_id;
 929
 930	for (gamma_en_vp_id = 0; gamma_en_vp_id < nr_vps; gamma_en_vp_id++)
 931		if (vop2_vp_dsp_lut_is_enabled(&vop2->vps[gamma_en_vp_id]))
 932			break;
 933
 934	return gamma_en_vp_id != nr_vps && gamma_en_vp_id != vp->id;
 935}
 936
 937static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
 938				     struct drm_atomic_state *state)
 939{
 940	struct vop2_video_port *vp = to_vop2_video_port(crtc);
 941	struct vop2 *vop2 = vp->vop2;
 942	struct drm_crtc_state *old_crtc_state;
 943	int ret;
 944
 945	vop2_lock(vop2);
 946
 947	old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 948	drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
 949
 950	drm_crtc_vblank_off(crtc);
 951
 952	/*
 953	 * Vop standby will take effect at end of current frame,
 954	 * if dsp hold valid irq happen, it means standby complete.
 955	 *
 956	 * we must wait standby complete when we want to disable aclk,
 957	 * if not, memory bus maybe dead.
 958	 */
 959	reinit_completion(&vp->dsp_hold_completion);
 960
 961	vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID);
 962
 963	vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY);
 964
 965	ret = wait_for_completion_timeout(&vp->dsp_hold_completion,
 966					  msecs_to_jiffies(50));
 967	if (!ret)
 968		drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id);
 969
 970	vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID);
 971
 972	if (vp->dclk_src)
 973		clk_set_parent(vp->dclk, vp->dclk_src);
 974
 975	clk_disable_unprepare(vp->dclk);
 976
 977	vop2->enable_count--;
 978
 979	if (!vop2->enable_count)
 980		vop2_disable(vop2);
 981
 982	vop2_unlock(vop2);
 983
 984	if (crtc->state->event && !crtc->state->active) {
 985		spin_lock_irq(&crtc->dev->event_lock);
 986		drm_crtc_send_vblank_event(crtc, crtc->state->event);
 987		spin_unlock_irq(&crtc->dev->event_lock);
 988
 989		crtc->state->event = NULL;
 990	}
 991}
 992
 993static int vop2_plane_atomic_check(struct drm_plane *plane,
 994				   struct drm_atomic_state *astate)
 995{
 996	struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane);
 997	struct drm_framebuffer *fb = pstate->fb;
 998	struct drm_crtc *crtc = pstate->crtc;
 999	struct drm_crtc_state *cstate;
1000	struct vop2_video_port *vp;
1001	struct vop2 *vop2;
1002	const struct vop2_data *vop2_data;
1003	struct drm_rect *dest = &pstate->dst;
1004	struct drm_rect *src = &pstate->src;
1005	int min_scale = FRAC_16_16(1, 8);
1006	int max_scale = FRAC_16_16(8, 1);
1007	int src_x, src_w, src_h;
1008	int dest_w, dest_h;
1009	int format;
1010	int ret;
1011
1012	if (!crtc)
1013		return 0;
1014
1015	vp = to_vop2_video_port(crtc);
1016	vop2 = vp->vop2;
1017	vop2_data = vop2->data;
1018
1019	cstate = drm_atomic_get_new_crtc_state(pstate->state, crtc);
1020	if (WARN_ON(!cstate))
1021		return -EINVAL;
1022
1023	ret = drm_atomic_helper_check_plane_state(pstate, cstate,
1024						  min_scale, max_scale,
1025						  true, true);
1026	if (ret)
1027		return ret;
1028
1029	if (!pstate->visible)
1030		return 0;
1031
1032	format = vop2_convert_format(fb->format->format);
1033	if (format < 0)
1034		return format;
1035
1036	/* Co-ordinates have now been clipped */
1037	src_x = src->x1 >> 16;
1038	src_w = drm_rect_width(src) >> 16;
1039	src_h = drm_rect_height(src) >> 16;
1040	dest_w = drm_rect_width(dest);
1041	dest_h = drm_rect_height(dest);
1042
1043	if (src_w < 4 || src_h < 4 || dest_w < 4 || dest_h < 4) {
1044		drm_dbg_kms(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n",
1045			    src_w, src_h, dest_w, dest_h);
1046		return -EINVAL;
1047	}
1048
1049	if (src_w > vop2_data->max_input.width ||
1050	    src_h > vop2_data->max_input.height) {
1051		drm_dbg_kms(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n",
1052			    src_w, src_h,
1053			    vop2_data->max_input.width,
1054			    vop2_data->max_input.height);
1055		return -EINVAL;
1056	}
1057
1058	/*
1059	 * Src.x1 can be odd when do clip, but yuv plane start point
1060	 * need align with 2 pixel.
1061	 */
1062	if (fb->format->is_yuv && src_x % 2) {
1063		drm_dbg_kms(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n");
1064		return -EINVAL;
1065	}
1066
1067	return 0;
1068}
1069
1070static void vop2_plane_atomic_disable(struct drm_plane *plane,
1071				      struct drm_atomic_state *state)
1072{
1073	struct drm_plane_state *old_pstate = NULL;
1074	struct vop2_win *win = to_vop2_win(plane);
1075	struct vop2 *vop2 = win->vop2;
1076
1077	drm_dbg(vop2->drm, "%s disable\n", win->data->name);
1078
1079	if (state)
1080		old_pstate = drm_atomic_get_old_plane_state(state, plane);
1081	if (old_pstate && !old_pstate->crtc)
1082		return;
1083
1084	vop2_win_disable(win);
1085	vop2_win_write(win, VOP2_WIN_YUV_CLIP, 0);
1086}
1087
1088/*
1089 * The color key is 10 bit, so all format should
1090 * convert to 10 bit here.
1091 */
1092static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key)
1093{
1094	struct drm_plane_state *pstate = plane->state;
1095	struct drm_framebuffer *fb = pstate->fb;
1096	struct vop2_win *win = to_vop2_win(plane);
1097	u32 color_key_en = 0;
1098	u32 r = 0;
1099	u32 g = 0;
1100	u32 b = 0;
1101
1102	if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) {
1103		vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, 0);
1104		return;
1105	}
1106
1107	switch (fb->format->format) {
1108	case DRM_FORMAT_RGB565:
1109	case DRM_FORMAT_BGR565:
1110		r = (color_key & 0xf800) >> 11;
1111		g = (color_key & 0x7e0) >> 5;
1112		b = (color_key & 0x1f);
1113		r <<= 5;
1114		g <<= 4;
1115		b <<= 5;
1116		color_key_en = 1;
1117		break;
1118	case DRM_FORMAT_XRGB8888:
1119	case DRM_FORMAT_ARGB8888:
1120	case DRM_FORMAT_XBGR8888:
1121	case DRM_FORMAT_ABGR8888:
1122	case DRM_FORMAT_RGB888:
1123	case DRM_FORMAT_BGR888:
1124		r = (color_key & 0xff0000) >> 16;
1125		g = (color_key & 0xff00) >> 8;
1126		b = (color_key & 0xff);
1127		r <<= 2;
1128		g <<= 2;
1129		b <<= 2;
1130		color_key_en = 1;
1131		break;
1132	}
1133
1134	vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, color_key_en);
1135	vop2_win_write(win, VOP2_WIN_COLOR_KEY, (r << 20) | (g << 10) | b);
1136}
1137
1138static void vop2_plane_atomic_update(struct drm_plane *plane,
1139				     struct drm_atomic_state *state)
1140{
1141	struct drm_plane_state *pstate = plane->state;
1142	struct drm_crtc *crtc = pstate->crtc;
1143	struct vop2_win *win = to_vop2_win(plane);
1144	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1145	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
1146	struct vop2 *vop2 = win->vop2;
1147	struct drm_framebuffer *fb = pstate->fb;
1148	u32 bpp = vop2_get_bpp(fb->format);
1149	u32 src_w, src_h, dsp_w, dsp_h;
1150	u32 act_info, dsp_info;
1151	u32 format;
1152	u32 afbc_format;
1153	u32 rb_swap;
1154	u32 uv_swap;
1155	struct drm_rect *src = &pstate->src;
1156	struct drm_rect *dest = &pstate->dst;
1157	u32 afbc_tile_num;
1158	u32 transform_offset;
1159	bool dither_up;
1160	bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false;
1161	bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false;
1162	bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
1163	bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
1164	struct rockchip_gem_object *rk_obj;
1165	unsigned long offset;
1166	bool half_block_en;
1167	bool afbc_en;
1168	dma_addr_t yrgb_mst;
1169	dma_addr_t uv_mst;
1170
1171	/*
1172	 * can't update plane when vop2 is disabled.
1173	 */
1174	if (WARN_ON(!crtc))
1175		return;
1176
1177	if (!pstate->visible) {
1178		vop2_plane_atomic_disable(plane, state);
1179		return;
1180	}
1181
1182	afbc_en = rockchip_afbc(plane, fb->modifier);
1183
1184	offset = (src->x1 >> 16) * fb->format->cpp[0];
1185
1186	/*
1187	 * AFBC HDR_PTR must set to the zero offset of the framebuffer.
1188	 */
1189	if (afbc_en)
1190		offset = 0;
1191	else if (pstate->rotation & DRM_MODE_REFLECT_Y)
1192		offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
1193	else
1194		offset += (src->y1 >> 16) * fb->pitches[0];
1195
1196	rk_obj = to_rockchip_obj(fb->obj[0]);
1197
1198	yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
1199	if (fb->format->is_yuv) {
1200		int hsub = fb->format->hsub;
1201		int vsub = fb->format->vsub;
1202
1203		offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub;
1204		offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
1205
1206		if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en)
1207			offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2) / vsub;
1208
1209		rk_obj = to_rockchip_obj(fb->obj[0]);
1210		uv_mst = rk_obj->dma_addr + offset + fb->offsets[1];
1211	}
1212
1213	src_w = drm_rect_width(src) >> 16;
1214	src_h = drm_rect_height(src) >> 16;
1215	dsp_w = drm_rect_width(dest);
1216
1217	if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
1218		drm_dbg_kms(vop2->drm,
1219			    "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
1220			    vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
1221		dsp_w = adjusted_mode->hdisplay - dest->x1;
1222		if (dsp_w < 4)
1223			dsp_w = 4;
1224		src_w = dsp_w * src_w / drm_rect_width(dest);
1225	}
1226
1227	dsp_h = drm_rect_height(dest);
1228
1229	if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
1230		drm_dbg_kms(vop2->drm,
1231			    "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
1232			    vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
1233		dsp_h = adjusted_mode->vdisplay - dest->y1;
1234		if (dsp_h < 4)
1235			dsp_h = 4;
1236		src_h = dsp_h * src_h / drm_rect_height(dest);
1237	}
1238
1239	/*
1240	 * This is workaround solution for IC design:
1241	 * esmart can't support scale down when src_w % 16 == 1.
1242	 */
1243	if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
1244		if (src_w > dsp_w && (src_w & 0xf) == 1) {
1245			drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
1246				    vp->id, win->data->name, src_w);
1247			src_w -= 1;
1248		}
1249	}
1250
1251	if (afbc_en && src_w % 4) {
1252		drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n",
1253			    vp->id, win->data->name, src_w);
1254		src_w = ALIGN_DOWN(src_w, 4);
1255	}
1256
1257	act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff);
1258	dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
1259
1260	format = vop2_convert_format(fb->format->format);
1261	half_block_en = vop2_half_block_enable(pstate);
1262
1263	drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n",
1264		vp->id, win->data->name, src_w, src_h, dsp_w, dsp_h,
1265		dest->x1, dest->y1,
1266		&fb->format->format,
1267		afbc_en ? "AFBC" : "", &yrgb_mst);
1268
1269	if (vop2->version > VOP_VERSION_RK3568) {
1270		vop2_win_write(win, VOP2_WIN_AXI_BUS_ID, win->data->axi_bus_id);
1271		vop2_win_write(win, VOP2_WIN_AXI_YRGB_R_ID, win->data->axi_yrgb_r_id);
1272		vop2_win_write(win, VOP2_WIN_AXI_UV_R_ID, win->data->axi_uv_r_id);
1273	}
1274
1275	if (vop2->version >= VOP_VERSION_RK3576)
1276		vop2_win_write(win, VOP2_WIN_VP_SEL, vp->id);
1277
1278	if (vop2_cluster_window(win))
1279		vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, half_block_en);
1280
1281	if (afbc_en) {
1282		u32 stride, block_w;
1283
1284		/* the afbc superblock is 16 x 16 or 32 x 8 */
1285		block_w = fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 ? 32 : 16;
1286
1287		afbc_format = vop2_convert_afbc_format(fb->format->format);
1288
1289		/* Enable color transform for YTR */
1290		if (fb->modifier & AFBC_FORMAT_MOD_YTR)
1291			afbc_format |= (1 << 4);
1292
1293		afbc_tile_num = ALIGN(src_w, block_w) / block_w;
1294
1295		/*
1296		 * AFBC pic_vir_width is count by pixel, this is different
1297		 * with WIN_VIR_STRIDE.
1298		 */
1299		stride = (fb->pitches[0] << 3) / bpp;
1300		if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
1301			drm_dbg_kms(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
1302				    vp->id, win->data->name, stride);
1303
1304		 /* It's for head stride, each head size is 16 byte */
1305		stride = ALIGN(stride, block_w) / block_w * 16;
1306
1307		uv_swap = vop2_afbc_uv_swap(fb->format->format);
1308		/*
1309		 * This is a workaround for crazy IC design, Cluster
1310		 * and Esmart/Smart use different format configuration map:
1311		 * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart.
1312		 *
1313		 * This is one thing we can make the convert simple:
1314		 * AFBCD decode all the YUV data to YUV444. So we just
1315		 * set all the yuv 10 bit to YUV444_10.
1316		 */
1317		if (fb->format->is_yuv && bpp == 10)
1318			format = VOP2_CLUSTER_YUV444_10;
1319
1320		if (vop2_cluster_window(win))
1321			vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1);
1322		vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format);
1323		vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap);
1324		/*
1325		 * On rk3566/8, this bit is auto gating enable,
1326		 * but this function is not work well so we need
1327		 * to disable it for these two platform.
1328		 * On rk3588, and the following new soc(rk3528/rk3576),
1329		 * this bit is gating disable, we should write 1 to
1330		 * disable gating when enable afbc.
1331		 */
1332		if (vop2->version == VOP_VERSION_RK3568)
1333			vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);
1334		else
1335			vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1);
1336
1337		if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
1338			vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 1);
1339		else
1340			vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);
1341
1342		if (vop2->version >= VOP_VERSION_RK3576) {
1343			vop2_win_write(win, VOP2_WIN_AFBC_PLD_OFFSET_EN, 1);
1344			vop2_win_write(win, VOP2_WIN_AFBC_PLD_OFFSET, yrgb_mst);
1345		}
1346
1347		transform_offset = vop2_afbc_transform_offset(pstate, half_block_en);
1348		vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);
1349		vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info);
1350		vop2_win_write(win, VOP2_WIN_TRANSFORM_OFFSET, transform_offset);
1351		vop2_win_write(win, VOP2_WIN_AFBC_PIC_OFFSET, ((src->x1 >> 16) | src->y1));
1352		vop2_win_write(win, VOP2_WIN_AFBC_DSP_OFFSET, (dest->x1 | (dest->y1 << 16)));
1353		vop2_win_write(win, VOP2_WIN_AFBC_PIC_VIR_WIDTH, stride);
1354		vop2_win_write(win, VOP2_WIN_AFBC_TILE_NUM, afbc_tile_num);
1355		vop2_win_write(win, VOP2_WIN_XMIRROR, xmirror);
1356		vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270);
1357		vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90);
1358	} else {
1359		if (vop2_cluster_window(win)) {
1360			vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 0);
1361			vop2_win_write(win, VOP2_WIN_TRANSFORM_OFFSET, 0);
1362		}
1363
1364		vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4));
1365	}
1366
1367	vop2_win_write(win, VOP2_WIN_YMIRROR, ymirror);
1368
1369	if (rotate_90 || rotate_270) {
1370		act_info = swahw32(act_info);
1371		src_w = drm_rect_height(src) >> 16;
1372		src_h = drm_rect_width(src) >> 16;
1373	}
1374
1375	vop2_win_write(win, VOP2_WIN_FORMAT, format);
1376	vop2_win_write(win, VOP2_WIN_YRGB_MST, yrgb_mst);
1377
1378	rb_swap = vop2_win_rb_swap(fb->format->format);
1379	vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap);
1380	uv_swap = vop2_win_uv_swap(fb->format->format);
1381	vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap);
1382
1383	if (fb->format->is_yuv) {
1384		vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4));
1385		vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst);
1386	}
1387
1388	vop2_setup_scale(vop2, win, src_w, src_h, dsp_w, dsp_h, fb->format->format);
1389	if (!vop2_cluster_window(win))
1390		vop2_plane_setup_color_key(plane, 0);
1391	vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info);
1392	vop2_win_write(win, VOP2_WIN_DSP_INFO, dsp_info);
1393	vop2_win_write(win, VOP2_WIN_DSP_ST, dest->y1 << 16 | (dest->x1 & 0xffff));
1394
1395	vop2_setup_csc_mode(vp, win, pstate);
1396
1397	dither_up = vop2_win_dither_up(fb->format->format);
1398	vop2_win_write(win, VOP2_WIN_DITHER_UP, dither_up);
1399
1400	vop2_win_write(win, VOP2_WIN_ENABLE, 1);
1401
1402	if (vop2_cluster_window(win)) {
1403		int lb_mode = vop2_get_cluster_lb_mode(win, pstate);
1404
1405		vop2_win_write(win, VOP2_WIN_CLUSTER_LB_MODE, lb_mode);
1406		vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 1);
1407	}
1408}
1409
1410static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = {
1411	.atomic_check = vop2_plane_atomic_check,
1412	.atomic_update = vop2_plane_atomic_update,
1413	.atomic_disable = vop2_plane_atomic_disable,
1414};
1415
1416static const struct drm_plane_funcs vop2_plane_funcs = {
1417	.update_plane	= drm_atomic_helper_update_plane,
1418	.disable_plane	= drm_atomic_helper_disable_plane,
1419	.destroy = drm_plane_cleanup,
1420	.reset = drm_atomic_helper_plane_reset,
1421	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
1422	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
1423	.format_mod_supported = rockchip_vop2_mod_supported,
1424};
1425
1426static int vop2_crtc_enable_vblank(struct drm_crtc *crtc)
1427{
1428	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1429
1430	vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD);
1431
1432	return 0;
1433}
1434
1435static void vop2_crtc_disable_vblank(struct drm_crtc *crtc)
1436{
1437	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1438
1439	vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD);
1440}
1441
1442static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
1443				 const struct drm_display_mode *mode,
1444				 struct drm_display_mode *adj_mode)
1445{
1446	drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V |
1447					CRTC_STEREO_DOUBLE);
1448
1449	return true;
1450}
1451
1452static void vop2_crtc_write_gamma_lut(struct vop2 *vop2, struct drm_crtc *crtc)
1453{
1454	const struct vop2_video_port *vp = to_vop2_video_port(crtc);
1455	const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id];
1456	struct drm_color_lut *lut = crtc->state->gamma_lut->data;
1457	unsigned int i, bpc = ilog2(vp_data->gamma_lut_len);
1458	u32 word;
1459
1460	for (i = 0; i < crtc->gamma_size; i++) {
1461		word = (drm_color_lut_extract(lut[i].blue, bpc) << (2 * bpc)) |
1462		    (drm_color_lut_extract(lut[i].green, bpc) << bpc) |
1463		    drm_color_lut_extract(lut[i].red, bpc);
1464
1465		writel(word, vop2->lut_regs + i * 4);
1466	}
1467}
1468
1469static void vop2_crtc_atomic_set_gamma_seamless(struct vop2 *vop2,
1470						struct vop2_video_port *vp,
1471						struct drm_crtc *crtc)
1472{
1473	vop2_writel(vop2, RK3568_LUT_PORT_SEL,
1474		    FIELD_PREP(RK3588_LUT_PORT_SEL__GAMMA_AHB_WRITE_SEL, vp->id));
1475	vop2_vp_dsp_lut_enable(vp);
1476	vop2_crtc_write_gamma_lut(vop2, crtc);
1477	vop2_vp_dsp_lut_update_enable(vp);
1478}
1479
1480static void vop2_crtc_atomic_set_gamma_rk356x(struct vop2 *vop2,
1481					      struct vop2_video_port *vp,
1482					      struct drm_crtc *crtc)
1483{
1484	vop2_vp_dsp_lut_disable(vp);
1485	vop2_cfg_done(vp);
1486	if (!vop2_vp_dsp_lut_poll_disabled(vp))
1487		return;
1488
1489	vop2_writel(vop2, RK3568_LUT_PORT_SEL, vp->id);
1490	vop2_crtc_write_gamma_lut(vop2, crtc);
1491	vop2_vp_dsp_lut_enable(vp);
1492}
1493
1494static void vop2_crtc_atomic_try_set_gamma(struct vop2 *vop2,
1495					   struct vop2_video_port *vp,
1496					   struct drm_crtc *crtc,
1497					   struct drm_crtc_state *crtc_state)
1498{
1499	if (!vop2->lut_regs)
1500		return;
1501
1502	if (!crtc_state->gamma_lut) {
1503		vop2_vp_dsp_lut_disable(vp);
1504		return;
1505	}
1506
1507	if (vop2_supports_seamless_gamma_lut_update(vop2))
1508		vop2_crtc_atomic_set_gamma_seamless(vop2, vp, crtc);
1509	else
1510		vop2_crtc_atomic_set_gamma_rk356x(vop2, vp, crtc);
1511}
1512
1513static inline void vop2_crtc_atomic_try_set_gamma_locked(struct vop2 *vop2,
1514							 struct vop2_video_port *vp,
1515							 struct drm_crtc *crtc,
1516							 struct drm_crtc_state *crtc_state)
1517{
1518	vop2_lock(vop2);
1519	vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state);
1520	vop2_unlock(vop2);
1521}
1522
1523static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)
1524{
1525	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
1526
1527	switch (vcstate->bus_format) {
1528	case MEDIA_BUS_FMT_RGB565_1X16:
1529		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
1530		break;
1531	case MEDIA_BUS_FMT_RGB666_1X18:
1532	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
1533	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
1534		*dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
1535		*dsp_ctrl |= RGB888_TO_RGB666;
1536		break;
1537	case MEDIA_BUS_FMT_YUV8_1X24:
1538	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
1539		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
1540		break;
1541	default:
1542		break;
1543	}
1544
1545	if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
1546		*dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
1547
1548	*dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
1549				DITHER_DOWN_ALLEGRO);
1550}
1551
1552static void vop2_post_config(struct drm_crtc *crtc)
1553{
1554	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1555	struct vop2 *vop2 = vp->vop2;
1556	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
1557	u16 vtotal = mode->crtc_vtotal;
1558	u16 hdisplay = mode->crtc_hdisplay;
1559	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
1560	u16 vdisplay = mode->crtc_vdisplay;
1561	u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
1562	u32 left_margin = 100, right_margin = 100;
1563	u32 top_margin = 100, bottom_margin = 100;
1564	u16 hsize = hdisplay * (left_margin + right_margin) / 200;
1565	u16 vsize = vdisplay * (top_margin + bottom_margin) / 200;
1566	u16 hact_end, vact_end;
1567	u32 val;
1568
1569	vop2->ops->setup_bg_dly(vp);
1570
1571	vsize = rounddown(vsize, 2);
1572	hsize = rounddown(hsize, 2);
1573	hact_st += hdisplay * (100 - left_margin) / 200;
1574	hact_end = hact_st + hsize;
1575	val = hact_st << 16;
1576	val |= hact_end;
1577	vop2_vp_write(vp, RK3568_VP_POST_DSP_HACT_INFO, val);
1578	vact_st += vdisplay * (100 - top_margin) / 200;
1579	vact_end = vact_st + vsize;
1580	val = vact_st << 16;
1581	val |= vact_end;
1582	vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO, val);
1583	val = scl_cal_scale2(vdisplay, vsize) << 16;
1584	val |= scl_cal_scale2(hdisplay, hsize);
1585	vop2_vp_write(vp, RK3568_VP_POST_SCL_FACTOR_YRGB, val);
1586
1587	val = 0;
1588	if (hdisplay != hsize)
1589		val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN;
1590	if (vdisplay != vsize)
1591		val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN;
1592	vop2_vp_write(vp, RK3568_VP_POST_SCL_CTRL, val);
1593
1594	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1595		u16 vact_st_f1 = vtotal + vact_st + 1;
1596		u16 vact_end_f1 = vact_st_f1 + vsize;
1597
1598		val = vact_st_f1 << 16 | vact_end_f1;
1599		vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val);
1600	}
1601
1602	vop2_vp_write(vp, RK3568_VP_DSP_BG, 0);
1603}
1604
1605static int us_to_vertical_line(struct drm_display_mode *mode, int us)
1606{
1607	return us * mode->clock / mode->htotal / 1000;
1608}
1609
1610static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
1611				    struct drm_atomic_state *state)
1612{
1613	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1614	struct vop2 *vop2 = vp->vop2;
1615	const struct vop2_data *vop2_data = vop2->data;
1616	const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
1617	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1618	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
1619	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
1620	unsigned long clock = mode->crtc_clock * 1000;
1621	u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
1622	u16 hdisplay = mode->crtc_hdisplay;
1623	u16 htotal = mode->crtc_htotal;
1624	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
1625	u16 hact_end = hact_st + hdisplay;
1626	u16 vdisplay = mode->crtc_vdisplay;
1627	u16 vtotal = mode->crtc_vtotal;
1628	u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
1629	u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
1630	u16 vact_end = vact_st + vdisplay;
1631	u8 out_mode;
1632	u32 dsp_ctrl = 0;
1633	int act_end;
1634	u32 val, polflags;
1635	int ret;
1636	struct drm_encoder *encoder;
1637
1638	drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n",
1639		hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
1640		drm_mode_vrefresh(mode), vcstate->output_type, vp->id);
1641
1642	vop2_lock(vop2);
1643
1644	ret = clk_prepare_enable(vp->dclk);
1645	if (ret < 0) {
1646		drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n",
1647			vp->id, ret);
1648		vop2_unlock(vop2);
1649		return;
1650	}
1651
1652	if (!vop2->enable_count)
1653		vop2_enable(vop2);
1654
1655	vop2->enable_count++;
1656
1657	vcstate->yuv_overlay = is_yuv_output(vcstate->bus_format);
1658
1659	vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY);
1660
1661	polflags = 0;
1662	if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
1663		polflags |= POLFLAG_DCLK_INV;
1664	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1665		polflags |= BIT(HSYNC_POSITIVE);
1666	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1667		polflags |= BIT(VSYNC_POSITIVE);
1668
1669	drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
1670		struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
1671
1672		/*
1673		 * for drive a high resolution(4KP120, 8K), vop on rk3588/rk3576 need
1674		 * process multi(1/2/4/8) pixels per cycle, so the dclk feed by the
1675		 * system cru may be the 1/2 or 1/4 of mode->clock.
1676		 */
1677		clock = vop2->ops->setup_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);
1678	}
1679
1680	if (!clock) {
1681		vop2_unlock(vop2);
1682		return;
1683	}
1684
1685	if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
1686	    !(vp_data->feature & VOP2_VP_FEATURE_OUTPUT_10BIT))
1687		out_mode = ROCKCHIP_OUT_MODE_P888;
1688	else
1689		out_mode = vcstate->output_mode;
1690
1691	dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode);
1692
1693	if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
1694		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;
1695	if (vop2_output_rg_swap(vop2, vcstate->bus_format))
1696		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RG_SWAP;
1697
1698	if (vcstate->yuv_overlay)
1699		dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;
1700
1701	vop2_dither_setup(crtc, &dsp_ctrl);
1702
1703	vop2_vp_write(vp, RK3568_VP_DSP_HTOTAL_HS_END, (htotal << 16) | hsync_len);
1704	val = hact_st << 16;
1705	val |= hact_end;
1706	vop2_vp_write(vp, RK3568_VP_DSP_HACT_ST_END, val);
1707
1708	val = vact_st << 16;
1709	val |= vact_end;
1710	vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END, val);
1711
1712	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1713		u16 vact_st_f1 = vtotal + vact_st + 1;
1714		u16 vact_end_f1 = vact_st_f1 + vdisplay;
1715
1716		val = vact_st_f1 << 16 | vact_end_f1;
1717		vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END_F1, val);
1718
1719		val = vtotal << 16 | (vtotal + vsync_len);
1720		vop2_vp_write(vp, RK3568_VP_DSP_VS_ST_END_F1, val);
1721		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE;
1722		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL;
1723		dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN;
1724		vtotal += vtotal + 1;
1725		act_end = vact_end_f1;
1726	} else {
1727		act_end = vact_end;
1728	}
1729
1730	vop2_writel(vop2, RK3568_VP_LINE_FLAG(vp->id),
1731		    (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end);
1732
1733	vop2_vp_write(vp, RK3568_VP_DSP_VTOTAL_VS_END, vtotal << 16 | vsync_len);
1734
1735	if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
1736		dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV;
1737		clock *= 2;
1738	}
1739
1740	vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0);
1741
1742	/*
1743	 * Switch to HDMI PHY PLL as DCLK source for display modes up
1744	 * to 4K@60Hz, if available, otherwise keep using the system CRU.
1745	 */
1746	if (vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) {
1747		unsigned long max_dclk = DIV_ROUND_CLOSEST_ULL(VOP2_MAX_DCLK_RATE * 8,
1748							       vcstate->output_bpc);
1749		if (clock <= max_dclk) {
1750			drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
1751				struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
1752
1753				if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) {
1754					if (!vop2->pll_hdmiphy0)
1755						break;
1756
1757					if (!vp->dclk_src)
1758						vp->dclk_src = clk_get_parent(vp->dclk);
1759
1760					ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0);
1761					if (ret < 0)
1762						drm_warn(vop2->drm,
1763							 "Could not switch to HDMI0 PHY PLL: %d\n",
1764							 ret);
1765					break;
1766				}
1767
1768				if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) {
1769					if (!vop2->pll_hdmiphy1)
1770						break;
1771
1772					if (!vp->dclk_src)
1773						vp->dclk_src = clk_get_parent(vp->dclk);
1774
1775					ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1);
1776					if (ret < 0)
1777						drm_warn(vop2->drm,
1778							 "Could not switch to HDMI1 PHY PLL: %d\n",
1779							 ret);
1780					break;
1781				}
1782			}
1783		}
1784	}
1785
1786	clk_set_rate(vp->dclk, clock);
1787
1788	vop2_post_config(crtc);
1789
1790	vop2_cfg_done(vp);
1791
1792	vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
1793
1794	vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state);
1795
1796	drm_crtc_vblank_on(crtc);
1797
1798	vop2_unlock(vop2);
1799}
1800
1801static int vop2_crtc_atomic_check_gamma(struct vop2_video_port *vp,
1802					struct drm_crtc *crtc,
1803					struct drm_atomic_state *state,
1804					struct drm_crtc_state *crtc_state)
1805{
1806	struct vop2 *vop2 = vp->vop2;
1807	unsigned int len;
1808
1809	if (!vp->vop2->lut_regs || !crtc_state->color_mgmt_changed ||
1810	    !crtc_state->gamma_lut)
1811		return 0;
1812
1813	len = drm_color_lut_size(crtc_state->gamma_lut);
1814	if (len != crtc->gamma_size) {
1815		drm_dbg(vop2->drm, "Invalid LUT size; got %d, expected %d\n",
1816			len, crtc->gamma_size);
1817		return -EINVAL;
1818	}
1819
1820	if (!vop2_supports_seamless_gamma_lut_update(vop2) && vop2_gamma_lut_in_use(vop2, vp)) {
1821		drm_info(vop2->drm, "Gamma LUT can be enabled for only one CRTC at a time\n");
1822		return -EINVAL;
1823	}
1824
1825	return 0;
1826}
1827
1828static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
1829				  struct drm_atomic_state *state)
1830{
1831	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1832	struct drm_plane *plane;
1833	int nplanes = 0;
1834	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1835	int ret;
1836
1837	ret = vop2_crtc_atomic_check_gamma(vp, crtc, state, crtc_state);
1838	if (ret)
1839		return ret;
1840
1841	drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
1842		nplanes++;
1843
1844	if (nplanes > vp->nlayers)
1845		return -EINVAL;
1846
1847	return 0;
1848}
1849
1850static void vop2_crtc_atomic_begin(struct drm_crtc *crtc,
1851				   struct drm_atomic_state *state)
1852{
1853	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1854	struct vop2 *vop2 = vp->vop2;
1855
1856	vop2->ops->setup_overlay(vp);
1857}
1858
1859static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
1860				   struct drm_atomic_state *state)
1861{
1862	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1863	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1864	struct vop2 *vop2 = vp->vop2;
1865
1866	/* In case of modeset, gamma lut update already happened in atomic enable */
1867	if (!drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->color_mgmt_changed)
1868		vop2_crtc_atomic_try_set_gamma_locked(vop2, vp, crtc, crtc_state);
1869
1870	vop2_post_config(crtc);
1871
1872	vop2_cfg_done(vp);
1873
1874	spin_lock_irq(&crtc->dev->event_lock);
1875
1876	if (crtc->state->event) {
1877		WARN_ON(drm_crtc_vblank_get(crtc));
1878		vp->event = crtc->state->event;
1879		crtc->state->event = NULL;
1880	}
1881
1882	spin_unlock_irq(&crtc->dev->event_lock);
1883}
1884
1885static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = {
1886	.mode_fixup = vop2_crtc_mode_fixup,
1887	.atomic_check = vop2_crtc_atomic_check,
1888	.atomic_begin = vop2_crtc_atomic_begin,
1889	.atomic_flush = vop2_crtc_atomic_flush,
1890	.atomic_enable = vop2_crtc_atomic_enable,
1891	.atomic_disable = vop2_crtc_atomic_disable,
1892};
1893
1894static void vop2_dump_connector_on_crtc(struct drm_crtc *crtc, struct seq_file *s)
1895{
1896	struct drm_connector_list_iter conn_iter;
1897	struct drm_connector *connector;
1898
1899	drm_connector_list_iter_begin(crtc->dev, &conn_iter);
1900	drm_for_each_connector_iter(connector, &conn_iter) {
1901		if (crtc->state->connector_mask & drm_connector_mask(connector))
1902			seq_printf(s, "    Connector: %s\n", connector->name);
1903	}
1904	drm_connector_list_iter_end(&conn_iter);
1905}
1906
1907static int vop2_plane_state_dump(struct seq_file *s, struct drm_plane *plane)
1908{
1909	struct vop2_win *win = to_vop2_win(plane);
1910	struct drm_plane_state *pstate = plane->state;
1911	struct drm_rect *src, *dst;
1912	struct drm_framebuffer *fb;
1913	struct drm_gem_object *obj;
1914	struct rockchip_gem_object *rk_obj;
1915	bool xmirror;
1916	bool ymirror;
1917	bool rotate_270;
1918	bool rotate_90;
1919	dma_addr_t fb_addr;
1920	int i;
1921
1922	seq_printf(s, "    %s: %s\n", win->data->name, !pstate ?
1923		   "DISABLED" : pstate->crtc ? "ACTIVE" : "DISABLED");
1924
1925	if (!pstate || !pstate->fb)
1926		return 0;
1927
1928	fb = pstate->fb;
1929	src = &pstate->src;
1930	dst = &pstate->dst;
1931	xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false;
1932	ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false;
1933	rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
1934	rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
1935
1936	seq_printf(s, "\twin_id: %d\n", win->win_id);
1937
1938	seq_printf(s, "\tformat: %p4cc%s glb_alpha[0x%x]\n",
1939		   &fb->format->format,
1940		   drm_is_afbc(fb->modifier) ? "[AFBC]" : "",
1941		   pstate->alpha >> 8);
1942	seq_printf(s, "\trotate: xmirror: %d ymirror: %d rotate_90: %d rotate_270: %d\n",
1943		   xmirror, ymirror, rotate_90, rotate_270);
1944	seq_printf(s, "\tzpos: %d\n", pstate->normalized_zpos);
1945	seq_printf(s, "\tsrc: pos[%d, %d] rect[%d x %d]\n", src->x1 >> 16,
1946		   src->y1 >> 16, drm_rect_width(src) >> 16,
1947		   drm_rect_height(src) >> 16);
1948	seq_printf(s, "\tdst: pos[%d, %d] rect[%d x %d]\n", dst->x1, dst->y1,
1949		   drm_rect_width(dst), drm_rect_height(dst));
1950
1951	for (i = 0; i < fb->format->num_planes; i++) {
1952		obj = fb->obj[i];
1953		rk_obj = to_rockchip_obj(obj);
1954		fb_addr = rk_obj->dma_addr + fb->offsets[i];
1955
1956		seq_printf(s, "\tbuf[%d]: addr: %pad pitch: %d offset: %d\n",
1957			   i, &fb_addr, fb->pitches[i], fb->offsets[i]);
1958	}
1959
1960	return 0;
1961}
1962
1963static int vop2_crtc_state_dump(struct drm_crtc *crtc, struct seq_file *s)
1964{
1965	struct vop2_video_port *vp = to_vop2_video_port(crtc);
1966	struct drm_crtc_state *cstate = crtc->state;
1967	struct rockchip_crtc_state *vcstate;
1968	struct drm_display_mode *mode;
1969	struct drm_plane *plane;
1970	bool interlaced;
1971
1972	seq_printf(s, "Video Port%d: %s\n", vp->id, !cstate ?
1973		   "DISABLED" : cstate->active ? "ACTIVE" : "DISABLED");
1974
1975	if (!cstate || !cstate->active)
1976		return 0;
1977
1978	mode = &crtc->state->adjusted_mode;
1979	vcstate = to_rockchip_crtc_state(cstate);
1980	interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
1981
1982	vop2_dump_connector_on_crtc(crtc, s);
1983	seq_printf(s, "\tbus_format[%x]: %s\n", vcstate->bus_format,
1984		   drm_get_bus_format_name(vcstate->bus_format));
1985	seq_printf(s, "\toutput_mode[%x]", vcstate->output_mode);
1986	seq_printf(s, " color_space[%d]\n", vcstate->color_space);
1987	seq_printf(s, "    Display mode: %dx%d%s%d\n",
1988		   mode->hdisplay, mode->vdisplay, interlaced ? "i" : "p",
1989		   drm_mode_vrefresh(mode));
1990	seq_printf(s, "\tclk[%d] real_clk[%d] type[%x] flag[%x]\n",
1991		   mode->clock, mode->crtc_clock, mode->type, mode->flags);
1992	seq_printf(s, "\tH: %d %d %d %d\n", mode->hdisplay, mode->hsync_start,
1993		   mode->hsync_end, mode->htotal);
1994	seq_printf(s, "\tV: %d %d %d %d\n", mode->vdisplay, mode->vsync_start,
1995		   mode->vsync_end, mode->vtotal);
1996
1997	drm_atomic_crtc_for_each_plane(plane, crtc) {
1998		vop2_plane_state_dump(s, plane);
1999	}
2000
2001	return 0;
2002}
2003
2004static int vop2_summary_show(struct seq_file *s, void *data)
2005{
2006	struct drm_info_node *node = s->private;
2007	struct drm_minor *minor = node->minor;
2008	struct drm_device *drm_dev = minor->dev;
2009	struct drm_crtc *crtc;
2010
2011	drm_modeset_lock_all(drm_dev);
2012	drm_for_each_crtc(crtc, drm_dev) {
2013		vop2_crtc_state_dump(crtc, s);
2014	}
2015	drm_modeset_unlock_all(drm_dev);
2016
2017	return 0;
2018}
2019
2020static void vop2_regs_print(struct vop2 *vop2, struct seq_file *s,
2021			    const struct vop2_regs_dump *dump, bool active_only)
2022{
2023	resource_size_t start;
2024	u32 val;
2025	int i;
2026
2027	if (dump->en_mask && active_only) {
2028		val = vop2_readl(vop2, dump->base + dump->en_reg);
2029		if ((val & dump->en_mask) != dump->en_val)
2030			return;
2031	}
2032
2033	seq_printf(s, "\n%s:\n", dump->name);
2034
2035	start = vop2->res->start + dump->base;
2036	for (i = 0; i < dump->size >> 2; i += 4) {
2037		seq_printf(s, "%08x:  %08x %08x %08x %08x\n", (u32)start + i * 4,
2038			   vop2_readl(vop2, dump->base + (4 * i)),
2039			   vop2_readl(vop2, dump->base + (4 * (i + 1))),
2040			   vop2_readl(vop2, dump->base + (4 * (i + 2))),
2041			   vop2_readl(vop2, dump->base + (4 * (i + 3))));
2042	}
2043}
2044
2045static void __vop2_regs_dump(struct seq_file *s, bool active_only)
2046{
2047	struct drm_info_node *node = s->private;
2048	struct vop2 *vop2 = node->info_ent->data;
2049	struct drm_minor *minor = node->minor;
2050	struct drm_device *drm_dev = minor->dev;
2051	const struct vop2_regs_dump *dump;
2052	unsigned int i;
2053
2054	drm_modeset_lock_all(drm_dev);
2055
2056	regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register);
2057
2058	if (vop2->enable_count) {
2059		for (i = 0; i < vop2->data->regs_dump_size; i++) {
2060			dump = &vop2->data->regs_dump[i];
2061			vop2_regs_print(vop2, s, dump, active_only);
2062		}
2063	} else {
2064		seq_puts(s, "VOP disabled\n");
2065	}
2066	drm_modeset_unlock_all(drm_dev);
2067}
2068
2069static int vop2_regs_show(struct seq_file *s, void *arg)
2070{
2071	__vop2_regs_dump(s, false);
2072
2073	return 0;
2074}
2075
2076static int vop2_active_regs_show(struct seq_file *s, void *data)
2077{
2078	__vop2_regs_dump(s, true);
2079
2080	return 0;
2081}
2082
2083static struct drm_info_list vop2_debugfs_list[] = {
2084	{ "summary", vop2_summary_show, 0, NULL },
2085	{ "active_regs", vop2_active_regs_show,   0, NULL },
2086	{ "regs", vop2_regs_show,   0, NULL },
2087};
2088
2089static void vop2_debugfs_init(struct vop2 *vop2, struct drm_minor *minor)
2090{
2091	struct dentry *root;
2092	unsigned int i;
2093
2094	root = debugfs_create_dir("vop2", minor->debugfs_root);
2095	if (!IS_ERR(root)) {
2096		for (i = 0; i < ARRAY_SIZE(vop2_debugfs_list); i++)
2097			vop2_debugfs_list[i].data = vop2;
2098
2099		drm_debugfs_create_files(vop2_debugfs_list,
2100					 ARRAY_SIZE(vop2_debugfs_list),
2101					 root, minor);
2102	}
2103}
2104
2105static int vop2_crtc_late_register(struct drm_crtc *crtc)
2106{
2107	struct vop2_video_port *vp = to_vop2_video_port(crtc);
2108	struct vop2 *vop2 = vp->vop2;
2109
2110	if (drm_crtc_index(crtc) == 0)
2111		vop2_debugfs_init(vop2, crtc->dev->primary);
2112
2113	return 0;
2114}
2115
2116static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
2117{
2118	struct rockchip_crtc_state *vcstate;
2119
2120	if (WARN_ON(!crtc->state))
2121		return NULL;
2122
2123	vcstate = kmemdup(to_rockchip_crtc_state(crtc->state),
2124			  sizeof(*vcstate), GFP_KERNEL);
2125	if (!vcstate)
2126		return NULL;
2127
2128	__drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base);
2129
2130	return &vcstate->base;
2131}
2132
2133static void vop2_crtc_destroy_state(struct drm_crtc *crtc,
2134				    struct drm_crtc_state *state)
2135{
2136	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);
2137
2138	__drm_atomic_helper_crtc_destroy_state(&vcstate->base);
2139	kfree(vcstate);
2140}
2141
2142static void vop2_crtc_reset(struct drm_crtc *crtc)
2143{
2144	struct rockchip_crtc_state *vcstate =
2145		kzalloc(sizeof(*vcstate), GFP_KERNEL);
2146
2147	if (crtc->state)
2148		vop2_crtc_destroy_state(crtc, crtc->state);
2149
2150	if (vcstate)
2151		__drm_atomic_helper_crtc_reset(crtc, &vcstate->base);
2152	else
2153		__drm_atomic_helper_crtc_reset(crtc, NULL);
2154}
2155
2156static const struct drm_crtc_funcs vop2_crtc_funcs = {
2157	.set_config = drm_atomic_helper_set_config,
2158	.page_flip = drm_atomic_helper_page_flip,
2159	.destroy = drm_crtc_cleanup,
2160	.reset = vop2_crtc_reset,
2161	.atomic_duplicate_state = vop2_crtc_duplicate_state,
2162	.atomic_destroy_state = vop2_crtc_destroy_state,
2163	.enable_vblank = vop2_crtc_enable_vblank,
2164	.disable_vblank = vop2_crtc_disable_vblank,
2165	.late_register = vop2_crtc_late_register,
2166};
2167
2168static irqreturn_t rk3576_vp_isr(int irq, void *data)
2169{
2170	struct vop2_video_port *vp = data;
2171	struct vop2 *vop2 = vp->vop2;
2172	struct drm_crtc *crtc = &vp->crtc;
2173	uint32_t irqs;
2174	int ret = IRQ_NONE;
2175
2176	if (!pm_runtime_get_if_in_use(vop2->dev))
2177		return IRQ_NONE;
2178
2179	irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id));
2180	vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs);
2181
2182	if (irqs & VP_INT_DSP_HOLD_VALID) {
2183		complete(&vp->dsp_hold_completion);
2184		ret = IRQ_HANDLED;
2185	}
2186
2187	if (irqs & VP_INT_FS_FIELD) {
2188		drm_crtc_handle_vblank(crtc);
2189		spin_lock(&crtc->dev->event_lock);
2190		if (vp->event) {
2191			u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
2192
2193			if (!(val & BIT(vp->id))) {
2194				drm_crtc_send_vblank_event(crtc, vp->event);
2195				vp->event = NULL;
2196				drm_crtc_vblank_put(crtc);
2197			}
2198		}
2199		spin_unlock(&crtc->dev->event_lock);
2200
2201		ret = IRQ_HANDLED;
2202	}
2203
2204	if (irqs & VP_INT_POST_BUF_EMPTY) {
2205		drm_err_ratelimited(vop2->drm, "POST_BUF_EMPTY irq err at vp%d\n", vp->id);
2206		ret = IRQ_HANDLED;
2207	}
2208
2209	pm_runtime_put(vop2->dev);
2210
2211	return ret;
2212}
2213
2214static irqreturn_t vop2_isr(int irq, void *data)
2215{
2216	struct vop2 *vop2 = data;
2217	const struct vop2_data *vop2_data = vop2->data;
2218	u32 axi_irqs[VOP2_SYS_AXI_BUS_NUM];
2219	int ret = IRQ_NONE;
2220	int i;
2221
2222	/*
2223	 * The irq is shared with the iommu. If the runtime-pm state of the
2224	 * vop2-device is disabled the irq has to be targeted at the iommu.
2225	 */
2226	if (!pm_runtime_get_if_in_use(vop2->dev))
2227		return IRQ_NONE;
2228
2229	if (vop2->version < VOP_VERSION_RK3576) {
2230		for (i = 0; i < vop2_data->nr_vps; i++) {
2231			struct vop2_video_port *vp = &vop2->vps[i];
2232			struct drm_crtc *crtc = &vp->crtc;
2233			u32 irqs;
2234
2235			irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id));
2236			vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs);
2237
2238			if (irqs & VP_INT_DSP_HOLD_VALID) {
2239				complete(&vp->dsp_hold_completion);
2240				ret = IRQ_HANDLED;
2241			}
2242
2243			if (irqs & VP_INT_FS_FIELD) {
2244				drm_crtc_handle_vblank(crtc);
2245				spin_lock(&crtc->dev->event_lock);
2246				if (vp->event) {
2247					u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
2248
2249					if (!(val & BIT(vp->id))) {
2250						drm_crtc_send_vblank_event(crtc, vp->event);
2251						vp->event = NULL;
2252						drm_crtc_vblank_put(crtc);
2253					}
2254				}
2255				spin_unlock(&crtc->dev->event_lock);
2256
2257				ret = IRQ_HANDLED;
2258			}
2259
2260			if (irqs & VP_INT_POST_BUF_EMPTY) {
2261				drm_err_ratelimited(vop2->drm,
2262						    "POST_BUF_EMPTY irq err at vp%d\n",
2263						    vp->id);
2264				ret = IRQ_HANDLED;
2265			}
2266		}
2267	}
2268
2269	axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS);
2270	vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]);
2271	axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS);
2272	vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]);
2273
2274	for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) {
2275		if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) {
2276			drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n");
2277			ret = IRQ_HANDLED;
2278		}
2279	}
2280
2281	pm_runtime_put(vop2->dev);
2282
2283	return ret;
2284}
2285
2286static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win,
2287			   unsigned long possible_crtcs)
2288{
2289	const struct vop2_win_data *win_data = win->data;
2290	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
2291				  BIT(DRM_MODE_BLEND_PREMULTI) |
2292				  BIT(DRM_MODE_BLEND_COVERAGE);
2293	int ret;
2294
2295	ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs,
2296				       &vop2_plane_funcs, win_data->formats,
2297				       win_data->nformats,
2298				       win_data->format_modifiers,
2299				       win->type, win_data->name);
2300	if (ret) {
2301		drm_err(vop2->drm, "failed to initialize plane %d\n", ret);
2302		return ret;
2303	}
2304
2305	drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs);
2306
2307	if (win->data->supported_rotations)
2308		drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0,
2309						   DRM_MODE_ROTATE_0 |
2310						   win->data->supported_rotations);
2311	drm_plane_create_alpha_property(&win->base);
2312	drm_plane_create_blend_mode_property(&win->base, blend_caps);
2313	drm_plane_create_zpos_property(&win->base, win->win_id, 0,
2314				       vop2->registered_num_wins - 1);
2315
2316	return 0;
2317}
2318
2319/*
2320 * On RK3566 these windows don't have an independent
2321 * framebuffer. They can only share/mirror the framebuffer
2322 * with smart0, esmart0 and cluster0 respectively.
2323 * And RK3566 share the same vop version with Rk3568, so we
2324 * need to use soc_id for identification here.
2325 */
2326static bool vop2_is_mirror_win(struct vop2_win *win)
2327{
2328	struct vop2 *vop2 = win->vop2;
2329
2330	if (vop2->data->soc_id == 3566) {
2331		switch (win->data->phys_id) {
2332		case ROCKCHIP_VOP2_SMART1:
2333		case ROCKCHIP_VOP2_ESMART1:
2334		case ROCKCHIP_VOP2_CLUSTER1:
2335			return true;
2336		default:
2337			return false;
2338		}
2339	} else {
2340		return false;
2341	}
2342}
2343
2344static int vop2_create_crtcs(struct vop2 *vop2)
2345{
2346	const struct vop2_data *vop2_data = vop2->data;
2347	struct drm_device *drm = vop2->drm;
2348	struct device *dev = vop2->dev;
2349	struct drm_plane *plane;
2350	struct device_node *port;
2351	struct vop2_video_port *vp;
2352	struct vop2_win *win;
2353	u32 possible_crtcs;
2354	int i, j, nvp, nvps = 0;
2355	int ret;
2356
2357	for (i = 0; i < vop2_data->nr_vps; i++) {
2358		const struct vop2_video_port_data *vp_data;
2359		struct device_node *np;
2360		char dclk_name[9];
2361
2362		vp_data = &vop2_data->vp[i];
2363		vp = &vop2->vps[i];
2364		vp->vop2 = vop2;
2365		vp->id = vp_data->id;
2366		vp->data = vp_data;
2367
2368		snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);
2369		vp->dclk = devm_clk_get(vop2->dev, dclk_name);
2370		if (IS_ERR(vp->dclk))
2371			return dev_err_probe(drm->dev, PTR_ERR(vp->dclk),
2372					     "failed to get %s\n", dclk_name);
2373
2374		np = of_graph_get_remote_node(dev->of_node, i, -1);
2375		if (!np) {
2376			drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i);
2377			continue;
2378		}
2379		of_node_put(np);
2380
2381		port = of_graph_get_port_by_id(dev->of_node, i);
2382		if (!port)
2383			return dev_err_probe(drm->dev, -ENOENT,
2384					     "no port node found for video_port%d\n", i);
2385		vp->crtc.port = port;
2386		nvps++;
2387	}
2388
2389	nvp = 0;
2390	/* Register a primary plane for every crtc */
2391	for (i = 0; i < vop2_data->nr_vps; i++) {
2392		vp = &vop2->vps[i];
2393
2394		if (!vp->crtc.port)
2395			continue;
2396
2397		for (j = 0; j < vop2->registered_num_wins; j++) {
2398			win = &vop2->win[j];
2399
2400			/* Aready registered as primary plane */
2401			if (win->base.type == DRM_PLANE_TYPE_PRIMARY)
2402				continue;
2403
2404			/* If this win can not attached to this VP */
2405			if (!(win->data->possible_vp_mask & BIT(vp->id)))
2406				continue;
2407
2408			if (vop2_is_mirror_win(win))
2409				continue;
2410
2411			if (win->type == DRM_PLANE_TYPE_PRIMARY) {
2412				possible_crtcs = BIT(nvp);
2413				vp->primary_plane = win;
2414				ret = vop2_plane_init(vop2, win, possible_crtcs);
2415				if (ret)
2416					return dev_err_probe(drm->dev, ret,
2417							     "failed to init primary plane %s\n",
2418							     win->data->name);
2419				nvp++;
2420				break;
2421			}
2422		}
2423
2424		if (!vp->primary_plane)
2425			return dev_err_probe(drm->dev, -ENOENT,
2426					     "no primary plane for vp %d\n", i);
2427	}
2428
2429	/* Register all unused window as overlay plane */
2430	for (i = 0; i < vop2->registered_num_wins; i++) {
2431		win = &vop2->win[i];
2432
2433		/* Aready registered as primary plane */
2434		if (win->base.type == DRM_PLANE_TYPE_PRIMARY)
2435			continue;
2436
2437		if (vop2_is_mirror_win(win))
2438			continue;
2439
2440		win->type = DRM_PLANE_TYPE_OVERLAY;
2441
2442		possible_crtcs = 0;
2443		nvp = 0;
2444		for (j = 0; j < vop2_data->nr_vps; j++) {
2445			vp = &vop2->vps[j];
2446
2447			if (!vp->crtc.port)
2448				continue;
2449
2450			if (win->data->possible_vp_mask & BIT(vp->id))
2451				possible_crtcs |= BIT(nvp);
2452			nvp++;
2453		}
2454
2455		ret = vop2_plane_init(vop2, win, possible_crtcs);
2456		if (ret)
2457			return dev_err_probe(drm->dev, ret, "failed to init overlay plane %s\n",
2458					     win->data->name);
2459	}
2460
2461	for (i = 0; i < vop2_data->nr_vps; i++) {
2462		vp = &vop2->vps[i];
2463
2464		if (!vp->crtc.port)
2465			continue;
2466
2467		plane = &vp->primary_plane->base;
2468
2469		ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL,
2470						&vop2_crtc_funcs,
2471						"video_port%d", vp->id);
2472		if (ret)
2473			return dev_err_probe(drm->dev, ret,
2474					     "crtc init for video_port%d failed\n", i);
2475
2476		drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
2477		if (vop2->lut_regs) {
2478			const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
2479
2480			drm_mode_crtc_set_gamma_size(&vp->crtc, vp_data->gamma_lut_len);
2481			drm_crtc_enable_color_mgmt(&vp->crtc, 0, false, vp_data->gamma_lut_len);
2482		}
2483		init_completion(&vp->dsp_hold_completion);
2484	}
2485
2486	/*
2487	 * On the VOP2 it's very hard to change the number of layers on a VP
2488	 * during runtime, so we distribute the layers equally over the used
2489	 * VPs
2490	 */
2491	for (i = 0; i < vop2->data->nr_vps; i++) {
2492		struct vop2_video_port *vp = &vop2->vps[i];
2493
2494		if (vp->crtc.port)
2495			vp->nlayers = vop2_data->win_size / nvps;
2496	}
2497
2498	return 0;
2499}
2500
2501static void vop2_destroy_crtcs(struct vop2 *vop2)
2502{
2503	struct drm_device *drm = vop2->drm;
2504	struct list_head *crtc_list = &drm->mode_config.crtc_list;
2505	struct list_head *plane_list = &drm->mode_config.plane_list;
2506	struct drm_crtc *crtc, *tmpc;
2507	struct drm_plane *plane, *tmpp;
2508
2509	list_for_each_entry_safe(plane, tmpp, plane_list, head)
2510		drm_plane_cleanup(plane);
2511
2512	/*
2513	 * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane()
2514	 * references the CRTC.
2515	 */
2516	list_for_each_entry_safe(crtc, tmpc, crtc_list, head) {
2517		of_node_put(crtc->port);
2518		drm_crtc_cleanup(crtc);
2519	}
2520}
2521
2522static int vop2_find_rgb_encoder(struct vop2 *vop2)
2523{
2524	struct device_node *node = vop2->dev->of_node;
2525	struct device_node *endpoint;
2526	int i;
2527
2528	for (i = 0; i < vop2->data->nr_vps; i++) {
2529		endpoint = of_graph_get_endpoint_by_regs(node, i,
2530							 ROCKCHIP_VOP2_EP_RGB0);
2531		if (!endpoint)
2532			continue;
2533
2534		of_node_put(endpoint);
2535		return i;
2536	}
2537
2538	return -ENOENT;
2539}
2540
2541static int vop2_regmap_init(struct vop2_win *win, const struct reg_field *regs,
2542			    int nr_regs)
2543{
2544	struct vop2 *vop2 = win->vop2;
2545	int i;
2546
2547	for (i = 0; i < nr_regs; i++) {
2548		const struct reg_field field = {
2549			.reg = (regs[i].reg != 0xffffffff) ?
2550				regs[i].reg + win->offset : regs[i].reg,
2551			.lsb = regs[i].lsb,
2552			.msb = regs[i].msb
2553		};
2554
2555		win->reg[i] = devm_regmap_field_alloc(vop2->dev, vop2->map, field);
2556		if (IS_ERR(win->reg[i]))
2557			return PTR_ERR(win->reg[i]);
2558	}
2559
2560	return 0;
2561};
2562
2563static int vop2_win_init(struct vop2 *vop2)
2564{
2565	const struct vop2_data *vop2_data = vop2->data;
2566	struct vop2_win *win;
2567	int i, ret;
2568
2569	for (i = 0; i < vop2_data->win_size; i++) {
2570		const struct vop2_win_data *win_data = &vop2_data->win[i];
2571
2572		win = &vop2->win[i];
2573		win->data = win_data;
2574		win->type = win_data->type;
2575		win->offset = win_data->base;
2576		win->win_id = i;
2577		win->vop2 = vop2;
2578		if (vop2_cluster_window(win))
2579			ret = vop2_regmap_init(win, vop2->data->cluster_reg,
2580					       vop2->data->nr_cluster_regs);
2581		else
2582			ret = vop2_regmap_init(win, vop2->data->smart_reg,
2583					       vop2->data->nr_smart_regs);
2584		if (ret)
2585			return ret;
2586	}
2587
2588	vop2->registered_num_wins = vop2_data->win_size;
2589
2590	return 0;
2591}
2592
2593/*
2594 * The window and video port registers are only updated when config
2595 * done is written. Until that they read back the old value. As we
2596 * read-modify-write these registers mark them as non-volatile. This
2597 * makes sure we read the new values from the regmap register cache.
2598 */
2599static const struct regmap_range vop2_nonvolatile_range[] = {
2600	regmap_reg_range(RK3568_VP0_CTRL_BASE, RK3588_VP3_CTRL_BASE + 255),
2601	regmap_reg_range(0x1000, 0x23ff),
2602};
2603
2604static const struct regmap_access_table vop2_volatile_table = {
2605	.no_ranges = vop2_nonvolatile_range,
2606	.n_no_ranges = ARRAY_SIZE(vop2_nonvolatile_range),
2607};
2608
2609static const struct regmap_config vop2_regmap_config = {
2610	.reg_bits	= 32,
2611	.val_bits	= 32,
2612	.reg_stride	= 4,
2613	.max_register	= 0x3000,
2614	.name		= "vop2",
2615	.volatile_table	= &vop2_volatile_table,
2616	.cache_type	= REGCACHE_MAPLE,
2617};
2618
2619static int vop2_bind(struct device *dev, struct device *master, void *data)
2620{
2621	struct platform_device *pdev = to_platform_device(dev);
2622	const struct vop2_data *vop2_data;
2623	struct drm_device *drm = data;
2624	struct vop2 *vop2;
2625	struct resource *res;
2626	size_t alloc_size;
2627	int ret;
2628
2629	vop2_data = of_device_get_match_data(dev);
2630	if (!vop2_data)
2631		return -ENODEV;
2632
2633	/* Allocate vop2 struct and its vop2_win array */
2634	alloc_size = struct_size(vop2, win, vop2_data->win_size);
2635	vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
2636	if (!vop2)
2637		return -ENOMEM;
2638
2639	vop2->dev = dev;
2640	vop2->data = vop2_data;
2641	vop2->ops = vop2_data->ops;
2642	vop2->version = vop2_data->version;
2643	vop2->drm = drm;
2644
2645	dev_set_drvdata(dev, vop2);
2646
2647	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vop");
2648	if (!res)
2649		return dev_err_probe(drm->dev, -EINVAL,
2650				     "failed to get vop2 register byname\n");
2651
2652	vop2->res = res;
2653	vop2->regs = devm_ioremap_resource(dev, res);
2654	if (IS_ERR(vop2->regs))
2655		return PTR_ERR(vop2->regs);
2656	vop2->len = resource_size(res);
2657
2658	vop2->map = devm_regmap_init_mmio(dev, vop2->regs, &vop2_regmap_config);
2659	if (IS_ERR(vop2->map))
2660		return PTR_ERR(vop2->map);
2661
2662	/* Set the bounds for framebuffer creation */
2663	drm->mode_config.min_width = 4;
2664	drm->mode_config.min_height = 4;
2665	drm->mode_config.max_width = vop2_data->max_input.width;
2666	drm->mode_config.max_height = vop2_data->max_input.height;
2667
2668	ret = vop2_win_init(vop2);
2669	if (ret)
2670		return ret;
2671
2672	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma-lut");
2673	if (res) {
2674		vop2->lut_regs = devm_ioremap_resource(dev, res);
2675		if (IS_ERR(vop2->lut_regs))
2676			return PTR_ERR(vop2->lut_regs);
2677	}
2678	if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_GRF) {
2679		vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
2680		if (IS_ERR(vop2->sys_grf))
2681			return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_grf),
2682					     "cannot get sys_grf\n");
2683	}
2684
2685	if (vop2_data->feature & VOP2_FEATURE_HAS_VOP_GRF) {
2686		vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf");
2687		if (IS_ERR(vop2->vop_grf))
2688			return dev_err_probe(drm->dev, PTR_ERR(vop2->vop_grf),
2689					     "cannot get vop_grf\n");
2690	}
2691
2692	if (vop2_data->feature & VOP2_FEATURE_HAS_VO1_GRF) {
2693		vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf");
2694		if (IS_ERR(vop2->vo1_grf))
2695			return dev_err_probe(drm->dev, PTR_ERR(vop2->vo1_grf),
2696					     "cannot get vo1_grf\n");
2697	}
2698
2699	if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_PMU) {
2700		vop2->sys_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu");
2701		if (IS_ERR(vop2->sys_pmu))
2702			return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_pmu),
2703					     "cannot get sys_pmu\n");
2704	}
2705
2706	vop2->hclk = devm_clk_get(vop2->dev, "hclk");
2707	if (IS_ERR(vop2->hclk))
2708		return dev_err_probe(drm->dev, PTR_ERR(vop2->hclk),
2709				     "failed to get hclk source\n");
2710
2711	vop2->aclk = devm_clk_get(vop2->dev, "aclk");
2712	if (IS_ERR(vop2->aclk))
2713		return dev_err_probe(drm->dev, PTR_ERR(vop2->aclk),
2714				     "failed to get aclk source\n");
2715
2716	vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk_vop");
2717	if (IS_ERR(vop2->pclk))
2718		return dev_err_probe(drm->dev, PTR_ERR(vop2->pclk),
2719				     "failed to get pclk source\n");
2720
2721	vop2->pll_hdmiphy0 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy0");
2722	if (IS_ERR(vop2->pll_hdmiphy0))
2723		return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy0),
2724				     "failed to get pll_hdmiphy0\n");
2725
2726	vop2->pll_hdmiphy1 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy1");
2727	if (IS_ERR(vop2->pll_hdmiphy1))
2728		return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy1),
2729				     "failed to get pll_hdmiphy1\n");
2730
2731	vop2->irq = platform_get_irq(pdev, 0);
2732	if (vop2->irq < 0)
2733		return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n");
2734
2735	mutex_init(&vop2->vop2_lock);
2736	mutex_init(&vop2->ovl_lock);
2737
2738	ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
2739	if (ret)
2740		return ret;
2741
2742	ret = vop2_create_crtcs(vop2);
2743	if (ret)
2744		return ret;
2745
2746	if (vop2->version >= VOP_VERSION_RK3576) {
2747		struct drm_crtc *crtc;
2748
2749		drm_for_each_crtc(crtc, drm) {
2750			struct vop2_video_port *vp = to_vop2_video_port(crtc);
2751			int vp_irq;
2752			const char *irq_name = devm_kasprintf(dev, GFP_KERNEL, "vp%d", vp->id);
2753
2754			if (!irq_name)
2755				return -ENOMEM;
2756
2757			vp_irq = platform_get_irq_byname(pdev, irq_name);
2758			if (vp_irq < 0)
2759				return dev_err_probe(drm->dev, vp_irq,
2760						     "cannot find irq for vop2 vp%d\n", vp->id);
2761
2762			ret = devm_request_irq(dev, vp_irq, rk3576_vp_isr, IRQF_SHARED, irq_name,
2763					       vp);
2764			if (ret)
2765				dev_err_probe(drm->dev, ret,
2766					      "request irq for vop2 vp%d failed\n", vp->id);
2767		}
2768	}
2769
2770	ret = vop2_find_rgb_encoder(vop2);
2771	if (ret >= 0) {
2772		vop2->rgb = rockchip_rgb_init(dev, &vop2->vps[ret].crtc,
2773					      vop2->drm, ret);
2774		if (IS_ERR(vop2->rgb)) {
2775			if (PTR_ERR(vop2->rgb) == -EPROBE_DEFER) {
2776				ret = PTR_ERR(vop2->rgb);
2777				goto err_crtcs;
2778			}
2779			vop2->rgb = NULL;
2780		}
2781	}
2782
2783	rockchip_drm_dma_init_device(vop2->drm, vop2->dev);
2784
2785	pm_runtime_enable(&pdev->dev);
2786
2787	return 0;
2788
2789err_crtcs:
2790	vop2_destroy_crtcs(vop2);
2791
2792	return ret;
2793}
2794
2795static void vop2_unbind(struct device *dev, struct device *master, void *data)
2796{
2797	struct vop2 *vop2 = dev_get_drvdata(dev);
2798
2799	pm_runtime_disable(dev);
2800
2801	if (vop2->rgb)
2802		rockchip_rgb_fini(vop2->rgb);
2803
2804	vop2_destroy_crtcs(vop2);
2805}
2806
2807const struct component_ops vop2_component_ops = {
2808	.bind = vop2_bind,
2809	.unbind = vop2_unbind,
2810};
2811EXPORT_SYMBOL_GPL(vop2_component_ops);
~/ Read-only file preview.