Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
   4 * Author:Mark Yao <mark.yao@rock-chips.com>
   5 */
   6
   7#include <linux/component.h>
   8#include <linux/mod_devicetable.h>
   9#include <linux/module.h>
  10#include <linux/of.h>
  11#include <linux/platform_device.h>
  12
  13#include <drm/drm_fourcc.h>
  14#include <drm/drm_plane.h>
  15#include <drm/drm_print.h>
  16
  17#include "rockchip_drm_vop.h"
  18#include "rockchip_vop_reg.h"
  19#include "rockchip_drm_drv.h"
  20
  21#define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \
  22		{ \
  23		 .offset = off, \
  24		 .mask = _mask, \
  25		 .shift = _shift, \
  26		 .write_mask = _write_mask, \
  27		 .relaxed = _relaxed, \
  28		}
  29
  30#define VOP_REG(off, _mask, _shift) \
  31		_VOP_REG(off, _mask, _shift, false, true)
  32
  33#define VOP_REG_SYNC(off, _mask, _shift) \
  34		_VOP_REG(off, _mask, _shift, false, false)
  35
  36#define VOP_REG_MASK_SYNC(off, _mask, _shift) \
  37		_VOP_REG(off, _mask, _shift, true, false)
  38
  39static const uint32_t formats_win_full[] = {
  40	DRM_FORMAT_XRGB8888,
  41	DRM_FORMAT_ARGB8888,
  42	DRM_FORMAT_XBGR8888,
  43	DRM_FORMAT_ABGR8888,
  44	DRM_FORMAT_RGB888,
  45	DRM_FORMAT_BGR888,
  46	DRM_FORMAT_RGB565,
  47	DRM_FORMAT_BGR565,
  48	DRM_FORMAT_NV12,
  49	DRM_FORMAT_NV16,
  50	DRM_FORMAT_NV24,
  51};
  52
  53static const uint64_t format_modifiers_win_full[] = {
  54	DRM_FORMAT_MOD_LINEAR,
  55	DRM_FORMAT_MOD_INVALID,
  56};
  57
  58static const uint64_t format_modifiers_win_full_afbc[] = {
  59	ROCKCHIP_AFBC_MOD,
  60	DRM_FORMAT_MOD_LINEAR,
  61	DRM_FORMAT_MOD_INVALID,
  62};
  63
  64static const uint32_t formats_win_lite[] = {
  65	DRM_FORMAT_XRGB8888,
  66	DRM_FORMAT_ARGB8888,
  67	DRM_FORMAT_XBGR8888,
  68	DRM_FORMAT_ABGR8888,
  69	DRM_FORMAT_RGB888,
  70	DRM_FORMAT_BGR888,
  71	DRM_FORMAT_RGB565,
  72	DRM_FORMAT_BGR565,
  73};
  74
  75static const uint64_t format_modifiers_win_lite[] = {
  76	DRM_FORMAT_MOD_LINEAR,
  77	DRM_FORMAT_MOD_INVALID,
  78};
  79
  80static const struct vop_scl_regs rk3036_win_scl = {
  81	.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
  82	.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
  83	.scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
  84	.scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
  85};
  86
  87static const struct vop_win_phy rk3036_win0_data = {
  88	.scl = &rk3036_win_scl,
  89	.data_formats = formats_win_full,
  90	.nformats = ARRAY_SIZE(formats_win_full),
  91	.format_modifiers = format_modifiers_win_full,
  92	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
  93	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
  94	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
  95	.act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
  96	.dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
  97	.dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
  98	.yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
  99	.uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
 100	.yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
 101	.uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
 102};
 103
 104static const struct vop_win_phy rk3036_win1_data = {
 105	.data_formats = formats_win_lite,
 106	.nformats = ARRAY_SIZE(formats_win_lite),
 107	.format_modifiers = format_modifiers_win_lite,
 108	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 109	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 110	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
 111	.act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
 112	.dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
 113	.dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
 114	.yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
 115	.yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
 116};
 117
 118static const struct vop_win_data rk3036_vop_win_data[] = {
 119	{ .base = 0x00, .phy = &rk3036_win0_data,
 120	  .type = DRM_PLANE_TYPE_PRIMARY },
 121	{ .base = 0x00, .phy = &rk3036_win1_data,
 122	  .type = DRM_PLANE_TYPE_CURSOR },
 123};
 124
 125static const int rk3036_vop_intrs[] = {
 126	DSP_HOLD_VALID_INTR,
 127	FS_INTR,
 128	LINE_FLAG_INTR,
 129	BUS_ERROR_INTR,
 130};
 131
 132static const struct vop_intr rk3036_intr = {
 133	.intrs = rk3036_vop_intrs,
 134	.nintrs = ARRAY_SIZE(rk3036_vop_intrs),
 135	.line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12),
 136	.status = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 0),
 137	.enable = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 4),
 138	.clear = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 8),
 139};
 140
 141static const struct vop_modeset rk3036_modeset = {
 142	.htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
 143	.hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
 144	.vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
 145	.vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
 146};
 147
 148static const struct vop_output rk3036_output = {
 149	.pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
 150};
 151
 152static const struct vop_common rk3036_common = {
 153	.standby = VOP_REG_SYNC(RK3036_SYS_CTRL, 0x1, 30),
 154	.out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
 155	.dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24),
 156	.dither_down_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 27),
 157	.dither_down_en = VOP_REG(RK3036_DSP_CTRL0, 0x1, 11),
 158	.dither_down_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 10),
 159	.cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0),
 160};
 161
 162static const struct vop_data rk3036_vop = {
 163	.intr = &rk3036_intr,
 164	.common = &rk3036_common,
 165	.modeset = &rk3036_modeset,
 166	.output = &rk3036_output,
 167	.win = rk3036_vop_win_data,
 168	.win_size = ARRAY_SIZE(rk3036_vop_win_data),
 169};
 170
 171static const struct vop_win_phy rk3126_win1_data = {
 172	.data_formats = formats_win_lite,
 173	.nformats = ARRAY_SIZE(formats_win_lite),
 174	.format_modifiers = format_modifiers_win_lite,
 175	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 176	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 177	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
 178	.dsp_info = VOP_REG(RK3126_WIN1_DSP_INFO, 0x0fff0fff, 0),
 179	.dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0),
 180	.yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0),
 181	.yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
 182};
 183
 184static const struct vop_win_data rk3126_vop_win_data[] = {
 185	{ .base = 0x00, .phy = &rk3036_win0_data,
 186	  .type = DRM_PLANE_TYPE_PRIMARY },
 187	{ .base = 0x00, .phy = &rk3126_win1_data,
 188	  .type = DRM_PLANE_TYPE_CURSOR },
 189};
 190
 191static const struct vop_data rk3126_vop = {
 192	.intr = &rk3036_intr,
 193	.common = &rk3036_common,
 194	.modeset = &rk3036_modeset,
 195	.output = &rk3036_output,
 196	.win = rk3126_vop_win_data,
 197	.win_size = ARRAY_SIZE(rk3126_vop_win_data),
 198};
 199
 200static const int px30_vop_intrs[] = {
 201	FS_INTR,
 202	0, 0,
 203	LINE_FLAG_INTR,
 204	0,
 205	BUS_ERROR_INTR,
 206	0, 0,
 207	DSP_HOLD_VALID_INTR,
 208};
 209
 210static const struct vop_intr px30_intr = {
 211	.intrs = px30_vop_intrs,
 212	.nintrs = ARRAY_SIZE(px30_vop_intrs),
 213	.line_flag_num[0] = VOP_REG(PX30_LINE_FLAG, 0xfff, 0),
 214	.status = VOP_REG_MASK_SYNC(PX30_INTR_STATUS, 0xffff, 0),
 215	.enable = VOP_REG_MASK_SYNC(PX30_INTR_EN, 0xffff, 0),
 216	.clear = VOP_REG_MASK_SYNC(PX30_INTR_CLEAR, 0xffff, 0),
 217};
 218
 219static const struct vop_common px30_common = {
 220	.standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1),
 221	.out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16),
 222	.dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14),
 223	.dither_down_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 8),
 224	.dither_down_sel = VOP_REG(PX30_DSP_CTRL2, 0x1, 7),
 225	.dither_down_mode = VOP_REG(PX30_DSP_CTRL2, 0x1, 6),
 226	.cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0),
 227};
 228
 229static const struct vop_modeset px30_modeset = {
 230	.htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
 231	.hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0),
 232	.vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
 233	.vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0),
 234};
 235
 236static const struct vop_output px30_output = {
 237	.rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1),
 238	.rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2),
 239	.rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0),
 240	.mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25),
 241	.mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26),
 242	.mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24),
 243};
 244
 245static const struct vop_scl_regs px30_win_scl = {
 246	.scale_yrgb_x = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 247	.scale_yrgb_y = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
 248	.scale_cbcr_x = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
 249	.scale_cbcr_y = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
 250};
 251
 252static const struct vop_win_phy px30_win0_data = {
 253	.scl = &px30_win_scl,
 254	.data_formats = formats_win_full,
 255	.nformats = ARRAY_SIZE(formats_win_full),
 256	.format_modifiers = format_modifiers_win_full,
 257	.enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
 258	.format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
 259	.rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
 260	.act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0),
 261	.dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0),
 262	.dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0),
 263	.yrgb_mst = VOP_REG(PX30_WIN0_YRGB_MST0, 0xffffffff, 0),
 264	.uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0),
 265	.yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0),
 266	.uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16),
 267	.alpha_pre_mul = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 2),
 268	.alpha_mode = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 1),
 269	.alpha_en = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 0),
 270};
 271
 272static const struct vop_win_phy px30_win1_data = {
 273	.data_formats = formats_win_lite,
 274	.nformats = ARRAY_SIZE(formats_win_lite),
 275	.format_modifiers = format_modifiers_win_lite,
 276	.enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
 277	.format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
 278	.rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
 279	.dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0),
 280	.dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0),
 281	.yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0),
 282	.yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0),
 283	.alpha_pre_mul = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 2),
 284	.alpha_mode = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 1),
 285	.alpha_en = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 0),
 286};
 287
 288static const struct vop_win_phy px30_win2_data = {
 289	.data_formats = formats_win_lite,
 290	.nformats = ARRAY_SIZE(formats_win_lite),
 291	.format_modifiers = format_modifiers_win_lite,
 292	.gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
 293	.enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
 294	.format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
 295	.rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20),
 296	.dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0),
 297	.dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0),
 298	.yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0),
 299	.yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0),
 300	.alpha_pre_mul = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 2),
 301	.alpha_mode = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 1),
 302	.alpha_en = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 0),
 303};
 304
 305static const struct vop_win_data px30_vop_big_win_data[] = {
 306	{ .base = 0x00, .phy = &px30_win0_data,
 307	  .type = DRM_PLANE_TYPE_PRIMARY },
 308	{ .base = 0x00, .phy = &px30_win1_data,
 309	  .type = DRM_PLANE_TYPE_OVERLAY },
 310	{ .base = 0x00, .phy = &px30_win2_data,
 311	  .type = DRM_PLANE_TYPE_CURSOR },
 312};
 313
 314static const struct vop_data px30_vop_big = {
 315	.intr = &px30_intr,
 316	.feature = VOP_FEATURE_INTERNAL_RGB,
 317	.common = &px30_common,
 318	.modeset = &px30_modeset,
 319	.output = &px30_output,
 320	.win = px30_vop_big_win_data,
 321	.win_size = ARRAY_SIZE(px30_vop_big_win_data),
 322};
 323
 324static const struct vop_win_data px30_vop_lit_win_data[] = {
 325	{ .base = 0x00, .phy = &px30_win1_data,
 326	  .type = DRM_PLANE_TYPE_PRIMARY },
 327};
 328
 329static const struct vop_data px30_vop_lit = {
 330	.intr = &px30_intr,
 331	.feature = VOP_FEATURE_INTERNAL_RGB,
 332	.common = &px30_common,
 333	.modeset = &px30_modeset,
 334	.output = &px30_output,
 335	.win = px30_vop_lit_win_data,
 336	.win_size = ARRAY_SIZE(px30_vop_lit_win_data),
 337};
 338
 339static const struct vop_scl_regs rk3066_win_scl = {
 340	.scale_yrgb_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 341	.scale_yrgb_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
 342	.scale_cbcr_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
 343	.scale_cbcr_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
 344};
 345
 346static const struct vop_win_phy rk3066_win0_data = {
 347	.scl = &rk3066_win_scl,
 348	.data_formats = formats_win_full,
 349	.nformats = ARRAY_SIZE(formats_win_full),
 350	.format_modifiers = format_modifiers_win_full,
 351	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
 352	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4),
 353	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19),
 354	.act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0),
 355	.dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0),
 356	.dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0),
 357	.yrgb_mst = VOP_REG(RK3066_WIN0_YRGB_MST0, 0xffffffff, 0),
 358	.uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0),
 359	.yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0),
 360	.uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16),
 361};
 362
 363static const struct vop_win_phy rk3066_win1_data = {
 364	.scl = &rk3066_win_scl,
 365	.data_formats = formats_win_full,
 366	.nformats = ARRAY_SIZE(formats_win_full),
 367	.format_modifiers = format_modifiers_win_full,
 368	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
 369	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7),
 370	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23),
 371	.act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0),
 372	.dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0),
 373	.dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0),
 374	.yrgb_mst = VOP_REG(RK3066_WIN1_YRGB_MST, 0xffffffff, 0),
 375	.uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0),
 376	.yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0),
 377	.uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16),
 378};
 379
 380static const struct vop_win_phy rk3066_win2_data = {
 381	.data_formats = formats_win_lite,
 382	.nformats = ARRAY_SIZE(formats_win_lite),
 383	.format_modifiers = format_modifiers_win_lite,
 384	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
 385	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10),
 386	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27),
 387	.dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0),
 388	.dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0),
 389	.yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0),
 390	.yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0),
 391};
 392
 393static const struct vop_modeset rk3066_modeset = {
 394	.htotal_pw = VOP_REG(RK3066_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
 395	.hact_st_end = VOP_REG(RK3066_DSP_HACT_ST_END, 0x1fff1fff, 0),
 396	.vtotal_pw = VOP_REG(RK3066_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
 397	.vact_st_end = VOP_REG(RK3066_DSP_VACT_ST_END, 0x1fff1fff, 0),
 398};
 399
 400static const struct vop_output rk3066_output = {
 401	.pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4),
 402};
 403
 404static const struct vop_common rk3066_common = {
 405	.standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1),
 406	.out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0),
 407	.cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0),
 408	.dither_down_en = VOP_REG(RK3066_DSP_CTRL0, 0x1, 11),
 409	.dither_down_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 10),
 410	.dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24),
 411};
 412
 413static const struct vop_win_data rk3066_vop_win_data[] = {
 414	{ .base = 0x00, .phy = &rk3066_win0_data,
 415	  .type = DRM_PLANE_TYPE_PRIMARY },
 416	{ .base = 0x00, .phy = &rk3066_win1_data,
 417	  .type = DRM_PLANE_TYPE_OVERLAY },
 418	{ .base = 0x00, .phy = &rk3066_win2_data,
 419	  .type = DRM_PLANE_TYPE_CURSOR },
 420};
 421
 422static const int rk3066_vop_intrs[] = {
 423	/*
 424	 * hs_start interrupt fires at frame-start, so serves
 425	 * the same purpose as dsp_hold in the driver.
 426	 */
 427	DSP_HOLD_VALID_INTR,
 428	FS_INTR,
 429	LINE_FLAG_INTR,
 430	BUS_ERROR_INTR,
 431};
 432
 433static const struct vop_intr rk3066_intr = {
 434	.intrs = rk3066_vop_intrs,
 435	.nintrs = ARRAY_SIZE(rk3066_vop_intrs),
 436	.line_flag_num[0] = VOP_REG(RK3066_INT_STATUS, 0xfff, 12),
 437	.status = VOP_REG(RK3066_INT_STATUS, 0xf, 0),
 438	.enable = VOP_REG(RK3066_INT_STATUS, 0xf, 4),
 439	.clear = VOP_REG(RK3066_INT_STATUS, 0xf, 8),
 440};
 441
 442static const struct vop_data rk3066_vop = {
 443	.version = VOP_VERSION(2, 1),
 444	.intr = &rk3066_intr,
 445	.common = &rk3066_common,
 446	.modeset = &rk3066_modeset,
 447	.output = &rk3066_output,
 448	.win = rk3066_vop_win_data,
 449	.win_size = ARRAY_SIZE(rk3066_vop_win_data),
 450};
 451
 452static const struct vop_scl_regs rk3188_win_scl = {
 453	.scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 454	.scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
 455	.scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
 456	.scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
 457};
 458
 459static const struct vop_win_phy rk3188_win0_data = {
 460	.scl = &rk3188_win_scl,
 461	.data_formats = formats_win_full,
 462	.nformats = ARRAY_SIZE(formats_win_full),
 463	.format_modifiers = format_modifiers_win_full,
 464	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
 465	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
 466	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
 467	.act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0),
 468	.dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0),
 469	.dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0),
 470	.yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0),
 471	.uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0),
 472	.yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0),
 473};
 474
 475static const struct vop_win_phy rk3188_win1_data = {
 476	.data_formats = formats_win_lite,
 477	.nformats = ARRAY_SIZE(formats_win_lite),
 478	.format_modifiers = format_modifiers_win_lite,
 479	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
 480	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
 481	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
 482	/* no act_info on window1 */
 483	.dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0),
 484	.dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0),
 485	.yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0),
 486	.yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16),
 487};
 488
 489static const struct vop_modeset rk3188_modeset = {
 490	.htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
 491	.hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0),
 492	.vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
 493	.vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0),
 494};
 495
 496static const struct vop_output rk3188_output = {
 497	.pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4),
 498};
 499
 500static const struct vop_common rk3188_common = {
 501	.gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31),
 502	.standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30),
 503	.out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0),
 504	.cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0),
 505	.dither_down_sel = VOP_REG(RK3188_DSP_CTRL0, 0x1, 27),
 506	.dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11),
 507	.dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10),
 508	.dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24),
 509};
 510
 511static const struct vop_win_data rk3188_vop_win_data[] = {
 512	{ .base = 0x00, .phy = &rk3188_win0_data,
 513	  .type = DRM_PLANE_TYPE_PRIMARY },
 514	{ .base = 0x00, .phy = &rk3188_win1_data,
 515	  .type = DRM_PLANE_TYPE_CURSOR },
 516};
 517
 518static const int rk3188_vop_intrs[] = {
 519	/*
 520	 * hs_start interrupt fires at frame-start, so serves
 521	 * the same purpose as dsp_hold in the driver.
 522	 */
 523	DSP_HOLD_VALID_INTR,
 524	FS_INTR,
 525	LINE_FLAG_INTR,
 526	BUS_ERROR_INTR,
 527};
 528
 529static const struct vop_intr rk3188_vop_intr = {
 530	.intrs = rk3188_vop_intrs,
 531	.nintrs = ARRAY_SIZE(rk3188_vop_intrs),
 532	.line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12),
 533	.status = VOP_REG(RK3188_INT_STATUS, 0xf, 0),
 534	.enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4),
 535	.clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8),
 536};
 537
 538static const struct vop_data rk3188_vop = {
 539	.intr = &rk3188_vop_intr,
 540	.common = &rk3188_common,
 541	.modeset = &rk3188_modeset,
 542	.output = &rk3188_output,
 543	.win = rk3188_vop_win_data,
 544	.win_size = ARRAY_SIZE(rk3188_vop_win_data),
 545	.feature = VOP_FEATURE_INTERNAL_RGB,
 546};
 547
 548static const struct vop_scl_extension rk3288_win_full_scl_ext = {
 549	.cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
 550	.cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
 551	.cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
 552	.cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
 553	.cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
 554	.yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
 555	.yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
 556	.yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
 557	.yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
 558	.yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
 559	.line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
 560	.cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
 561	.yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
 562	.vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
 563	.vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
 564	.vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
 565	.vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
 566	.bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
 567	.cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
 568	.yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
 569	.lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
 570};
 571
 572static const struct vop_scl_regs rk3288_win_full_scl = {
 573	.ext = &rk3288_win_full_scl_ext,
 574	.scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 575	.scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
 576	.scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
 577	.scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
 578};
 579
 580static const struct vop_win_phy rk3288_win01_data = {
 581	.scl = &rk3288_win_full_scl,
 582	.data_formats = formats_win_full,
 583	.nformats = ARRAY_SIZE(formats_win_full),
 584	.format_modifiers = format_modifiers_win_full,
 585	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
 586	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
 587	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
 588	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
 589	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
 590	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
 591	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
 592	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
 593	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
 594	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
 595	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
 596	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
 597	.channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
 598};
 599
 600static const struct vop_win_phy rk3288_win23_data = {
 601	.data_formats = formats_win_lite,
 602	.nformats = ARRAY_SIZE(formats_win_lite),
 603	.format_modifiers = format_modifiers_win_lite,
 604	.enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
 605	.gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
 606	.format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
 607	.rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
 608	.dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
 609	.dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
 610	.yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
 611	.yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
 612	.src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
 613	.dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
 614};
 615
 616static const struct vop_modeset rk3288_modeset = {
 617	.htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
 618	.hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
 619	.vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
 620	.vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
 621	.hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
 622	.vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
 623};
 624
 625static const struct vop_output rk3288_output = {
 626	.pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
 627	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
 628	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
 629	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
 630	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
 631};
 632
 633static const struct vop_common rk3288_common = {
 634	.standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
 635	.gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
 636	.mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
 637	.dither_down_sel = VOP_REG(RK3288_DSP_CTRL1, 0x1, 4),
 638	.dither_down_mode = VOP_REG(RK3288_DSP_CTRL1, 0x1, 3),
 639	.dither_down_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 2),
 640	.pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
 641	.dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
 642	.dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0),
 643	.data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
 644	.dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
 645	.out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
 646	.cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
 647};
 648
 649/*
 650 * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
 651 * special support to get alpha blending working.  For now, just use overlay
 652 * window 3 for the drm cursor.
 653 *
 654 */
 655static const struct vop_win_data rk3288_vop_win_data[] = {
 656	{ .base = 0x00, .phy = &rk3288_win01_data,
 657	  .type = DRM_PLANE_TYPE_PRIMARY },
 658	{ .base = 0x40, .phy = &rk3288_win01_data,
 659	  .type = DRM_PLANE_TYPE_OVERLAY },
 660	{ .base = 0x00, .phy = &rk3288_win23_data,
 661	  .type = DRM_PLANE_TYPE_OVERLAY },
 662	{ .base = 0x50, .phy = &rk3288_win23_data,
 663	  .type = DRM_PLANE_TYPE_CURSOR },
 664};
 665
 666static const int rk3288_vop_intrs[] = {
 667	DSP_HOLD_VALID_INTR,
 668	FS_INTR,
 669	LINE_FLAG_INTR,
 670	BUS_ERROR_INTR,
 671};
 672
 673static const struct vop_intr rk3288_vop_intr = {
 674	.intrs = rk3288_vop_intrs,
 675	.nintrs = ARRAY_SIZE(rk3288_vop_intrs),
 676	.line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
 677	.status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
 678	.enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
 679	.clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
 680};
 681
 682static const struct vop_data rk3288_vop = {
 683	.version = VOP_VERSION(3, 1),
 684	.feature = VOP_FEATURE_OUTPUT_RGB10,
 685	.intr = &rk3288_vop_intr,
 686	.common = &rk3288_common,
 687	.modeset = &rk3288_modeset,
 688	.output = &rk3288_output,
 689	.win = rk3288_vop_win_data,
 690	.win_size = ARRAY_SIZE(rk3288_vop_win_data),
 691	.lut_size = 1024,
 692};
 693
 694static const int rk3368_vop_intrs[] = {
 695	FS_INTR,
 696	0, 0,
 697	LINE_FLAG_INTR,
 698	0,
 699	BUS_ERROR_INTR,
 700	0, 0, 0, 0, 0, 0, 0,
 701	DSP_HOLD_VALID_INTR,
 702};
 703
 704static const struct vop_intr rk3368_vop_intr = {
 705	.intrs = rk3368_vop_intrs,
 706	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
 707	.line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
 708	.line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
 709	.status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0),
 710	.enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0),
 711	.clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0),
 712};
 713
 714static const struct vop_win_phy rk3368_win01_data = {
 715	.scl = &rk3288_win_full_scl,
 716	.data_formats = formats_win_full,
 717	.nformats = ARRAY_SIZE(formats_win_full),
 718	.format_modifiers = format_modifiers_win_full,
 719	.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
 720	.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
 721	.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
 722	.x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21),
 723	.y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22),
 724	.act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0),
 725	.dsp_info = VOP_REG(RK3368_WIN0_DSP_INFO, 0x0fff0fff, 0),
 726	.dsp_st = VOP_REG(RK3368_WIN0_DSP_ST, 0x1fff1fff, 0),
 727	.yrgb_mst = VOP_REG(RK3368_WIN0_YRGB_MST, 0xffffffff, 0),
 728	.uv_mst = VOP_REG(RK3368_WIN0_CBR_MST, 0xffffffff, 0),
 729	.yrgb_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 0),
 730	.uv_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 16),
 731	.src_alpha_ctl = VOP_REG(RK3368_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
 732	.dst_alpha_ctl = VOP_REG(RK3368_WIN0_DST_ALPHA_CTRL, 0xff, 0),
 733	.channel = VOP_REG(RK3368_WIN0_CTRL2, 0xff, 0),
 734};
 735
 736static const struct vop_win_phy rk3368_win23_data = {
 737	.data_formats = formats_win_lite,
 738	.nformats = ARRAY_SIZE(formats_win_lite),
 739	.format_modifiers = format_modifiers_win_lite,
 740	.gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
 741	.enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
 742	.format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
 743	.rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
 744	.y_mir_en = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15),
 745	.dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
 746	.dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
 747	.yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
 748	.yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
 749	.src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
 750	.dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
 751};
 752
 753static const struct vop_win_data rk3368_vop_win_data[] = {
 754	{ .base = 0x00, .phy = &rk3368_win01_data,
 755	  .type = DRM_PLANE_TYPE_PRIMARY },
 756	{ .base = 0x40, .phy = &rk3368_win01_data,
 757	  .type = DRM_PLANE_TYPE_OVERLAY },
 758	{ .base = 0x00, .phy = &rk3368_win23_data,
 759	  .type = DRM_PLANE_TYPE_OVERLAY },
 760	{ .base = 0x50, .phy = &rk3368_win23_data,
 761	  .type = DRM_PLANE_TYPE_CURSOR },
 762};
 763
 764static const struct vop_output rk3368_output = {
 765	.rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
 766	.hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
 767	.edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
 768	.mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
 769	.rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
 770	.hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
 771	.edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
 772	.mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
 773	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
 774	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
 775	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
 776	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
 777};
 778
 779static const struct vop_misc rk3368_misc = {
 780	.global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11),
 781};
 782
 783static const struct vop_data rk3368_vop = {
 784	.version = VOP_VERSION(3, 2),
 785	.intr = &rk3368_vop_intr,
 786	.common = &rk3288_common,
 787	.modeset = &rk3288_modeset,
 788	.output = &rk3368_output,
 789	.misc = &rk3368_misc,
 790	.win = rk3368_vop_win_data,
 791	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
 792};
 793
 794static const struct vop_intr rk3366_vop_intr = {
 795	.intrs = rk3368_vop_intrs,
 796	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
 797	.line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
 798	.line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
 799	.status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0),
 800	.enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0),
 801	.clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0),
 802};
 803
 804static const struct vop_data rk3366_vop = {
 805	.version = VOP_VERSION(3, 4),
 806	.intr = &rk3366_vop_intr,
 807	.common = &rk3288_common,
 808	.modeset = &rk3288_modeset,
 809	.output = &rk3368_output,
 810	.misc = &rk3368_misc,
 811	.win = rk3368_vop_win_data,
 812	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
 813};
 814
 815static const struct vop_output rk3399_output = {
 816	.dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19),
 817	.rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
 818	.hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
 819	.edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
 820	.mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
 821	.dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16),
 822	.rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
 823	.hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
 824	.edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
 825	.mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
 826	.dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
 827	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
 828	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
 829	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
 830	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
 831	.mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
 832};
 833
 834static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = {
 835	.y2r_coefficients = {
 836		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0),
 837		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16),
 838		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0),
 839		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16),
 840		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0),
 841		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16),
 842		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0),
 843		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16),
 844		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0),
 845		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0),
 846		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0),
 847		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0),
 848	},
 849};
 850
 851static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { };
 852
 853static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
 854	{ .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
 855	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) },
 856	{ .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data,
 857	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
 858	{ .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
 859	{ .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
 860
 861};
 862
 863static const struct vop_win_phy rk3399_win01_data = {
 864	.scl = &rk3288_win_full_scl,
 865	.data_formats = formats_win_full,
 866	.nformats = ARRAY_SIZE(formats_win_full),
 867	.format_modifiers = format_modifiers_win_full_afbc,
 868	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
 869	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
 870	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
 871	.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
 872	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
 873	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
 874	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
 875	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
 876	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
 877	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
 878	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
 879	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
 880	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
 881};
 882
 883/*
 884 * rk3399 vop big windows register layout is same as rk3288, but we
 885 * have a separate rk3399 win data array here so that we can advertise
 886 * AFBC on the primary plane.
 887 */
 888static const struct vop_win_data rk3399_vop_win_data[] = {
 889	{ .base = 0x00, .phy = &rk3399_win01_data,
 890	  .type = DRM_PLANE_TYPE_PRIMARY },
 891	{ .base = 0x40, .phy = &rk3288_win01_data,
 892	  .type = DRM_PLANE_TYPE_OVERLAY },
 893	{ .base = 0x00, .phy = &rk3288_win23_data,
 894	  .type = DRM_PLANE_TYPE_OVERLAY },
 895	{ .base = 0x50, .phy = &rk3288_win23_data,
 896	  .type = DRM_PLANE_TYPE_CURSOR },
 897};
 898
 899static const struct vop_afbc rk3399_vop_afbc = {
 900	.rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
 901	.enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
 902	.win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
 903	.format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
 904	.hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
 905	.hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
 906	.pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
 907};
 908
 909static const struct vop_data rk3399_vop_big = {
 910	.version = VOP_VERSION(3, 5),
 911	.feature = VOP_FEATURE_OUTPUT_RGB10,
 912	.intr = &rk3366_vop_intr,
 913	.common = &rk3288_common,
 914	.modeset = &rk3288_modeset,
 915	.output = &rk3399_output,
 916	.afbc = &rk3399_vop_afbc,
 917	.misc = &rk3368_misc,
 918	.win = rk3399_vop_win_data,
 919	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
 920	.win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
 921};
 922
 923static const struct vop_win_data rk3399_vop_lit_win_data[] = {
 924	{ .base = 0x00, .phy = &rk3368_win01_data,
 925	  .type = DRM_PLANE_TYPE_PRIMARY },
 926	{ .base = 0x00, .phy = &rk3368_win23_data,
 927	  .type = DRM_PLANE_TYPE_CURSOR},
 928};
 929
 930static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = {
 931	{ .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
 932	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)},
 933	{ .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data },
 934};
 935
 936static const struct vop_data rk3399_vop_lit = {
 937	.version = VOP_VERSION(3, 6),
 938	.intr = &rk3366_vop_intr,
 939	.common = &rk3288_common,
 940	.modeset = &rk3288_modeset,
 941	.output = &rk3399_output,
 942	.misc = &rk3368_misc,
 943	.win = rk3399_vop_lit_win_data,
 944	.win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
 945	.win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data,
 946};
 947
 948static const struct vop_win_data rk3228_vop_win_data[] = {
 949	{ .base = 0x00, .phy = &rk3288_win01_data,
 950	  .type = DRM_PLANE_TYPE_PRIMARY },
 951	{ .base = 0x40, .phy = &rk3288_win01_data,
 952	  .type = DRM_PLANE_TYPE_CURSOR },
 953};
 954
 955static const struct vop_data rk3228_vop = {
 956	.version = VOP_VERSION(3, 7),
 957	.feature = VOP_FEATURE_OUTPUT_RGB10,
 958	.intr = &rk3366_vop_intr,
 959	.common = &rk3288_common,
 960	.modeset = &rk3288_modeset,
 961	.output = &rk3399_output,
 962	.misc = &rk3368_misc,
 963	.win = rk3228_vop_win_data,
 964	.win_size = ARRAY_SIZE(rk3228_vop_win_data),
 965};
 966
 967static const struct vop_modeset rk3328_modeset = {
 968	.htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
 969	.hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
 970	.vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
 971	.vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
 972	.hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
 973	.vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
 974};
 975
 976static const struct vop_output rk3328_output = {
 977	.rgb_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 19),
 978	.hdmi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 23),
 979	.edp_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 27),
 980	.mipi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 31),
 981	.rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
 982	.hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
 983	.edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
 984	.mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
 985	.rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 16),
 986	.hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 20),
 987	.edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 24),
 988	.mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 28),
 989};
 990
 991static const struct vop_misc rk3328_misc = {
 992	.global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
 993};
 994
 995static const struct vop_common rk3328_common = {
 996	.standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22),
 997	.dither_down_sel = VOP_REG(RK3328_DSP_CTRL1, 0x1, 4),
 998	.dither_down_mode = VOP_REG(RK3328_DSP_CTRL1, 0x1, 3),
 999	.dither_down_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 2),
1000	.pre_dither_down = VOP_REG(RK3328_DSP_CTRL1, 0x1, 1),
1001	.dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
1002	.dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
1003	.out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
1004	.cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
1005};
1006
1007static const struct vop_intr rk3328_vop_intr = {
1008	.intrs = rk3368_vop_intrs,
1009	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
1010	.line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
1011	.line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
1012	.status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0),
1013	.enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0),
1014	.clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0),
1015};
1016
1017static const struct vop_win_data rk3328_vop_win_data[] = {
1018	{ .base = 0xd0, .phy = &rk3368_win01_data,
1019	  .type = DRM_PLANE_TYPE_PRIMARY },
1020	{ .base = 0x1d0, .phy = &rk3368_win01_data,
1021	  .type = DRM_PLANE_TYPE_OVERLAY },
1022	{ .base = 0x2d0, .phy = &rk3368_win01_data,
1023	  .type = DRM_PLANE_TYPE_CURSOR },
1024};
1025
1026static const struct vop_data rk3328_vop = {
1027	.version = VOP_VERSION(3, 8),
1028	.feature = VOP_FEATURE_OUTPUT_RGB10,
1029	.intr = &rk3328_vop_intr,
1030	.common = &rk3328_common,
1031	.modeset = &rk3328_modeset,
1032	.output = &rk3328_output,
1033	.misc = &rk3328_misc,
1034	.win = rk3328_vop_win_data,
1035	.win_size = ARRAY_SIZE(rk3328_vop_win_data),
1036};
1037
1038static const struct of_device_id vop_driver_dt_match[] = {
1039	{ .compatible = "rockchip,rk3036-vop",
1040	  .data = &rk3036_vop },
1041	{ .compatible = "rockchip,rk3126-vop",
1042	  .data = &rk3126_vop },
1043	{ .compatible = "rockchip,px30-vop-big",
1044	  .data = &px30_vop_big },
1045	{ .compatible = "rockchip,px30-vop-lit",
1046	  .data = &px30_vop_lit },
1047	{ .compatible = "rockchip,rk3066-vop",
1048	  .data = &rk3066_vop },
1049	{ .compatible = "rockchip,rk3188-vop",
1050	  .data = &rk3188_vop },
1051	{ .compatible = "rockchip,rk3288-vop",
1052	  .data = &rk3288_vop },
1053	{ .compatible = "rockchip,rk3368-vop",
1054	  .data = &rk3368_vop },
1055	{ .compatible = "rockchip,rk3366-vop",
1056	  .data = &rk3366_vop },
1057	{ .compatible = "rockchip,rk3399-vop-big",
1058	  .data = &rk3399_vop_big },
1059	{ .compatible = "rockchip,rk3399-vop-lit",
1060	  .data = &rk3399_vop_lit },
1061	{ .compatible = "rockchip,rk3228-vop",
1062	  .data = &rk3228_vop },
1063	{ .compatible = "rockchip,rk3328-vop",
1064	  .data = &rk3328_vop },
1065	{},
1066};
1067MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
1068
1069static int vop_probe(struct platform_device *pdev)
1070{
1071	struct device *dev = &pdev->dev;
1072
1073	if (!dev->of_node) {
1074		DRM_DEV_ERROR(dev, "can't find vop devices\n");
1075		return -ENODEV;
1076	}
1077
1078	return component_add(dev, &vop_component_ops);
1079}
1080
1081static int vop_remove(struct platform_device *pdev)
1082{
1083	component_del(&pdev->dev, &vop_component_ops);
1084
1085	return 0;
1086}
1087
1088struct platform_driver vop_platform_driver = {
1089	.probe = vop_probe,
1090	.remove = vop_remove,
1091	.driver = {
1092		.name = "rockchip-vop",
1093		.of_match_table = of_match_ptr(vop_driver_dt_match),
1094	},
1095};