0001
0002
0003
0004
0005
0006 #include <linux/bitfield.h>
0007 #include <linux/clk.h>
0008 #include <linux/component.h>
0009 #include <linux/delay.h>
0010 #include <linux/iopoll.h>
0011 #include <linux/kernel.h>
0012 #include <linux/media-bus-format.h>
0013 #include <linux/mfd/syscon.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/of_device.h>
0017 #include <linux/of_graph.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/pm_runtime.h>
0020 #include <linux/regmap.h>
0021 #include <linux/swab.h>
0022
0023 #include <drm/drm.h>
0024 #include <drm/drm_atomic.h>
0025 #include <drm/drm_atomic_uapi.h>
0026 #include <drm/drm_blend.h>
0027 #include <drm/drm_crtc.h>
0028 #include <drm/drm_crtc_helper.h>
0029 #include <drm/drm_debugfs.h>
0030 #include <drm/drm_flip_work.h>
0031 #include <drm/drm_framebuffer.h>
0032 #include <drm/drm_plane_helper.h>
0033 #include <drm/drm_probe_helper.h>
0034 #include <drm/drm_vblank.h>
0035
0036 #include <uapi/linux/videodev2.h>
0037 #include <dt-bindings/soc/rockchip,vop2.h>
0038
0039 #include "rockchip_drm_drv.h"
0040 #include "rockchip_drm_gem.h"
0041 #include "rockchip_drm_fb.h"
0042 #include "rockchip_drm_vop2.h"
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 enum vop2_data_format {
0075 VOP2_FMT_ARGB8888 = 0,
0076 VOP2_FMT_RGB888,
0077 VOP2_FMT_RGB565,
0078 VOP2_FMT_XRGB101010,
0079 VOP2_FMT_YUV420SP,
0080 VOP2_FMT_YUV422SP,
0081 VOP2_FMT_YUV444SP,
0082 VOP2_FMT_YUYV422 = 8,
0083 VOP2_FMT_YUYV420,
0084 VOP2_FMT_VYUY422,
0085 VOP2_FMT_VYUY420,
0086 VOP2_FMT_YUV420SP_TILE_8x4 = 0x10,
0087 VOP2_FMT_YUV420SP_TILE_16x2,
0088 VOP2_FMT_YUV422SP_TILE_8x4,
0089 VOP2_FMT_YUV422SP_TILE_16x2,
0090 VOP2_FMT_YUV420SP_10,
0091 VOP2_FMT_YUV422SP_10,
0092 VOP2_FMT_YUV444SP_10,
0093 };
0094
0095 enum vop2_afbc_format {
0096 VOP2_AFBC_FMT_RGB565,
0097 VOP2_AFBC_FMT_ARGB2101010 = 2,
0098 VOP2_AFBC_FMT_YUV420_10BIT,
0099 VOP2_AFBC_FMT_RGB888,
0100 VOP2_AFBC_FMT_ARGB8888,
0101 VOP2_AFBC_FMT_YUV420 = 9,
0102 VOP2_AFBC_FMT_YUV422 = 0xb,
0103 VOP2_AFBC_FMT_YUV422_10BIT = 0xe,
0104 VOP2_AFBC_FMT_INVALID = -1,
0105 };
0106
0107 union vop2_alpha_ctrl {
0108 u32 val;
0109 struct {
0110
0111 u32 color_mode:1;
0112 u32 alpha_mode:1;
0113
0114 u32 blend_mode:2;
0115 u32 alpha_cal_mode:1;
0116
0117 u32 factor_mode:3;
0118
0119 u32 alpha_en:1;
0120 u32 src_dst_swap:1;
0121 u32 reserved:6;
0122
0123 u32 glb_alpha:8;
0124 } bits;
0125 };
0126
0127 struct vop2_alpha {
0128 union vop2_alpha_ctrl src_color_ctrl;
0129 union vop2_alpha_ctrl dst_color_ctrl;
0130 union vop2_alpha_ctrl src_alpha_ctrl;
0131 union vop2_alpha_ctrl dst_alpha_ctrl;
0132 };
0133
0134 struct vop2_alpha_config {
0135 bool src_premulti_en;
0136 bool dst_premulti_en;
0137 bool src_pixel_alpha_en;
0138 bool dst_pixel_alpha_en;
0139 u16 src_glb_alpha_value;
0140 u16 dst_glb_alpha_value;
0141 };
0142
0143 struct vop2_win {
0144 struct vop2 *vop2;
0145 struct drm_plane base;
0146 const struct vop2_win_data *data;
0147 struct regmap_field *reg[VOP2_WIN_MAX_REG];
0148
0149
0150
0151
0152
0153 u8 win_id;
0154 u8 delay;
0155 u32 offset;
0156
0157 enum drm_plane_type type;
0158 };
0159
0160 struct vop2_video_port {
0161 struct drm_crtc crtc;
0162 struct vop2 *vop2;
0163 struct clk *dclk;
0164 unsigned int id;
0165 const struct vop2_video_port_regs *regs;
0166 const struct vop2_video_port_data *data;
0167
0168 struct completion dsp_hold_completion;
0169
0170
0171
0172
0173 u32 win_mask;
0174
0175 struct vop2_win *primary_plane;
0176 struct drm_pending_vblank_event *event;
0177
0178 unsigned int nlayers;
0179 };
0180
0181 struct vop2 {
0182 struct device *dev;
0183 struct drm_device *drm;
0184 struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];
0185
0186 const struct vop2_data *data;
0187
0188
0189
0190
0191 u32 registered_num_wins;
0192
0193 void __iomem *regs;
0194 struct regmap *map;
0195
0196 struct regmap *grf;
0197
0198
0199 u32 len;
0200
0201 void __iomem *lut_regs;
0202
0203
0204 struct mutex vop2_lock;
0205
0206 int irq;
0207
0208
0209
0210
0211
0212 unsigned int enable_count;
0213 struct clk *hclk;
0214 struct clk *aclk;
0215
0216
0217 struct vop2_win win[];
0218 };
0219
0220 static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
0221 {
0222 return container_of(crtc, struct vop2_video_port, crtc);
0223 }
0224
0225 static struct vop2_win *to_vop2_win(struct drm_plane *p)
0226 {
0227 return container_of(p, struct vop2_win, base);
0228 }
0229
0230 static void vop2_lock(struct vop2 *vop2)
0231 {
0232 mutex_lock(&vop2->vop2_lock);
0233 }
0234
0235 static void vop2_unlock(struct vop2 *vop2)
0236 {
0237 mutex_unlock(&vop2->vop2_lock);
0238 }
0239
0240 static void vop2_writel(struct vop2 *vop2, u32 offset, u32 v)
0241 {
0242 regmap_write(vop2->map, offset, v);
0243 }
0244
0245 static void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v)
0246 {
0247 regmap_write(vp->vop2->map, vp->data->offset + offset, v);
0248 }
0249
0250 static u32 vop2_readl(struct vop2 *vop2, u32 offset)
0251 {
0252 u32 val;
0253
0254 regmap_read(vop2->map, offset, &val);
0255
0256 return val;
0257 }
0258
0259 static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v)
0260 {
0261 regmap_field_write(win->reg[reg], v);
0262 }
0263
0264 static bool vop2_cluster_window(const struct vop2_win *win)
0265 {
0266 return win->data->feature & WIN_FEATURE_CLUSTER;
0267 }
0268
0269 static void vop2_cfg_done(struct vop2_video_port *vp)
0270 {
0271 struct vop2 *vop2 = vp->vop2;
0272
0273 regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE,
0274 BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
0275 }
0276
0277 static void vop2_win_disable(struct vop2_win *win)
0278 {
0279 vop2_win_write(win, VOP2_WIN_ENABLE, 0);
0280
0281 if (vop2_cluster_window(win))
0282 vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 0);
0283 }
0284
0285 static enum vop2_data_format vop2_convert_format(u32 format)
0286 {
0287 switch (format) {
0288 case DRM_FORMAT_XRGB8888:
0289 case DRM_FORMAT_ARGB8888:
0290 case DRM_FORMAT_XBGR8888:
0291 case DRM_FORMAT_ABGR8888:
0292 return VOP2_FMT_ARGB8888;
0293 case DRM_FORMAT_RGB888:
0294 case DRM_FORMAT_BGR888:
0295 return VOP2_FMT_RGB888;
0296 case DRM_FORMAT_RGB565:
0297 case DRM_FORMAT_BGR565:
0298 return VOP2_FMT_RGB565;
0299 case DRM_FORMAT_NV12:
0300 return VOP2_FMT_YUV420SP;
0301 case DRM_FORMAT_NV16:
0302 return VOP2_FMT_YUV422SP;
0303 case DRM_FORMAT_NV24:
0304 return VOP2_FMT_YUV444SP;
0305 case DRM_FORMAT_YUYV:
0306 case DRM_FORMAT_YVYU:
0307 return VOP2_FMT_VYUY422;
0308 case DRM_FORMAT_VYUY:
0309 case DRM_FORMAT_UYVY:
0310 return VOP2_FMT_YUYV422;
0311 default:
0312 DRM_ERROR("unsupported format[%08x]\n", format);
0313 return -EINVAL;
0314 }
0315 }
0316
0317 static enum vop2_afbc_format vop2_convert_afbc_format(u32 format)
0318 {
0319 switch (format) {
0320 case DRM_FORMAT_XRGB8888:
0321 case DRM_FORMAT_ARGB8888:
0322 case DRM_FORMAT_XBGR8888:
0323 case DRM_FORMAT_ABGR8888:
0324 return VOP2_AFBC_FMT_ARGB8888;
0325 case DRM_FORMAT_RGB888:
0326 case DRM_FORMAT_BGR888:
0327 return VOP2_AFBC_FMT_RGB888;
0328 case DRM_FORMAT_RGB565:
0329 case DRM_FORMAT_BGR565:
0330 return VOP2_AFBC_FMT_RGB565;
0331 case DRM_FORMAT_NV12:
0332 return VOP2_AFBC_FMT_YUV420;
0333 case DRM_FORMAT_NV16:
0334 return VOP2_AFBC_FMT_YUV422;
0335 default:
0336 return VOP2_AFBC_FMT_INVALID;
0337 }
0338
0339 return VOP2_AFBC_FMT_INVALID;
0340 }
0341
0342 static bool vop2_win_rb_swap(u32 format)
0343 {
0344 switch (format) {
0345 case DRM_FORMAT_XBGR8888:
0346 case DRM_FORMAT_ABGR8888:
0347 case DRM_FORMAT_BGR888:
0348 case DRM_FORMAT_BGR565:
0349 return true;
0350 default:
0351 return false;
0352 }
0353 }
0354
0355 static bool vop2_afbc_rb_swap(u32 format)
0356 {
0357 switch (format) {
0358 case DRM_FORMAT_NV24:
0359 return true;
0360 default:
0361 return false;
0362 }
0363 }
0364
0365 static bool vop2_afbc_uv_swap(u32 format)
0366 {
0367 switch (format) {
0368 case DRM_FORMAT_NV12:
0369 case DRM_FORMAT_NV16:
0370 return true;
0371 default:
0372 return false;
0373 }
0374 }
0375
0376 static bool vop2_win_uv_swap(u32 format)
0377 {
0378 switch (format) {
0379 case DRM_FORMAT_NV12:
0380 case DRM_FORMAT_NV16:
0381 case DRM_FORMAT_NV24:
0382 return true;
0383 default:
0384 return false;
0385 }
0386 }
0387
0388 static bool vop2_win_dither_up(u32 format)
0389 {
0390 switch (format) {
0391 case DRM_FORMAT_BGR565:
0392 case DRM_FORMAT_RGB565:
0393 return true;
0394 default:
0395 return false;
0396 }
0397 }
0398
0399 static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode)
0400 {
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410 if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 ||
0411 bus_format == MEDIA_BUS_FMT_VYUY8_1X16 ||
0412 bus_format == MEDIA_BUS_FMT_YVYU8_2X8 ||
0413 bus_format == MEDIA_BUS_FMT_VYUY8_2X8 ||
0414 ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
0415 bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&
0416 (output_mode == ROCKCHIP_OUT_MODE_AAAA ||
0417 output_mode == ROCKCHIP_OUT_MODE_P888)))
0418 return true;
0419 else
0420 return false;
0421 }
0422
0423 static bool is_yuv_output(u32 bus_format)
0424 {
0425 switch (bus_format) {
0426 case MEDIA_BUS_FMT_YUV8_1X24:
0427 case MEDIA_BUS_FMT_YUV10_1X30:
0428 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
0429 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
0430 case MEDIA_BUS_FMT_YUYV8_2X8:
0431 case MEDIA_BUS_FMT_YVYU8_2X8:
0432 case MEDIA_BUS_FMT_UYVY8_2X8:
0433 case MEDIA_BUS_FMT_VYUY8_2X8:
0434 case MEDIA_BUS_FMT_YUYV8_1X16:
0435 case MEDIA_BUS_FMT_YVYU8_1X16:
0436 case MEDIA_BUS_FMT_UYVY8_1X16:
0437 case MEDIA_BUS_FMT_VYUY8_1X16:
0438 return true;
0439 default:
0440 return false;
0441 }
0442 }
0443
0444 static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
0445 {
0446 int i;
0447
0448 if (modifier == DRM_FORMAT_MOD_LINEAR)
0449 return false;
0450
0451 for (i = 0 ; i < plane->modifier_count; i++)
0452 if (plane->modifiers[i] == modifier)
0453 return true;
0454
0455 return false;
0456 }
0457
0458 static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
0459 u64 modifier)
0460 {
0461 struct vop2_win *win = to_vop2_win(plane);
0462 struct vop2 *vop2 = win->vop2;
0463
0464 if (modifier == DRM_FORMAT_MOD_INVALID)
0465 return false;
0466
0467 if (modifier == DRM_FORMAT_MOD_LINEAR)
0468 return true;
0469
0470 if (!rockchip_afbc(plane, modifier)) {
0471 drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n",
0472 modifier);
0473
0474 return false;
0475 }
0476
0477 return vop2_convert_afbc_format(format) >= 0;
0478 }
0479
0480 static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate,
0481 bool afbc_half_block_en)
0482 {
0483 struct drm_rect *src = &pstate->src;
0484 struct drm_framebuffer *fb = pstate->fb;
0485 u32 bpp = fb->format->cpp[0] * 8;
0486 u32 vir_width = (fb->pitches[0] << 3) / bpp;
0487 u32 width = drm_rect_width(src) >> 16;
0488 u32 height = drm_rect_height(src) >> 16;
0489 u32 act_xoffset = src->x1 >> 16;
0490 u32 act_yoffset = src->y1 >> 16;
0491 u32 align16_crop = 0;
0492 u32 align64_crop = 0;
0493 u32 height_tmp;
0494 u8 tx, ty;
0495 u8 bottom_crop_line_num = 0;
0496
0497
0498 if (height & 0xf)
0499 align16_crop = 16 - (height & 0xf);
0500
0501 height_tmp = height + align16_crop;
0502
0503
0504 if (height_tmp & 0x3f)
0505 align64_crop = 64 - (height_tmp & 0x3f);
0506
0507 bottom_crop_line_num = align16_crop + align64_crop;
0508
0509 switch (pstate->rotation &
0510 (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y |
0511 DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) {
0512 case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
0513 tx = 16 - ((act_xoffset + width) & 0xf);
0514 ty = bottom_crop_line_num - act_yoffset;
0515 break;
0516 case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90:
0517 tx = bottom_crop_line_num - act_yoffset;
0518 ty = vir_width - width - act_xoffset;
0519 break;
0520 case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270:
0521 tx = act_yoffset;
0522 ty = act_xoffset;
0523 break;
0524 case DRM_MODE_REFLECT_X:
0525 tx = 16 - ((act_xoffset + width) & 0xf);
0526 ty = act_yoffset;
0527 break;
0528 case DRM_MODE_REFLECT_Y:
0529 tx = act_xoffset;
0530 ty = bottom_crop_line_num - act_yoffset;
0531 break;
0532 case DRM_MODE_ROTATE_90:
0533 tx = bottom_crop_line_num - act_yoffset;
0534 ty = act_xoffset;
0535 break;
0536 case DRM_MODE_ROTATE_270:
0537 tx = act_yoffset;
0538 ty = vir_width - width - act_xoffset;
0539 break;
0540 case 0:
0541 tx = act_xoffset;
0542 ty = act_yoffset;
0543 break;
0544 }
0545
0546 if (afbc_half_block_en)
0547 ty &= 0x7f;
0548
0549 #define TRANSFORM_XOFFSET GENMASK(7, 0)
0550 #define TRANSFORM_YOFFSET GENMASK(23, 16)
0551 return FIELD_PREP(TRANSFORM_XOFFSET, tx) |
0552 FIELD_PREP(TRANSFORM_YOFFSET, ty);
0553 }
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564 static int vop2_get_cluster_lb_mode(struct vop2_win *win,
0565 struct drm_plane_state *pstate)
0566 {
0567 if ((pstate->rotation & DRM_MODE_ROTATE_270) ||
0568 (pstate->rotation & DRM_MODE_ROTATE_90))
0569 return 2;
0570 else
0571 return 0;
0572 }
0573
0574 static u16 vop2_scale_factor(u32 src, u32 dst)
0575 {
0576 u32 fac;
0577 int shift;
0578
0579 if (src == dst)
0580 return 0;
0581
0582 if (dst < 2)
0583 return U16_MAX;
0584
0585 if (src < 2)
0586 return 0;
0587
0588 if (src > dst)
0589 shift = 12;
0590 else
0591 shift = 16;
0592
0593 src--;
0594 dst--;
0595
0596 fac = DIV_ROUND_UP(src << shift, dst) - 1;
0597
0598 if (fac > U16_MAX)
0599 return U16_MAX;
0600
0601 return fac;
0602 }
0603
0604 static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win,
0605 u32 src_w, u32 src_h, u32 dst_w,
0606 u32 dst_h, u32 pixel_format)
0607 {
0608 const struct drm_format_info *info;
0609 u16 hor_scl_mode, ver_scl_mode;
0610 u16 hscl_filter_mode, vscl_filter_mode;
0611 u8 gt2 = 0;
0612 u8 gt4 = 0;
0613 u32 val;
0614
0615 info = drm_format_info(pixel_format);
0616
0617 if (src_h >= (4 * dst_h)) {
0618 gt4 = 1;
0619 src_h >>= 2;
0620 } else if (src_h >= (2 * dst_h)) {
0621 gt2 = 1;
0622 src_h >>= 1;
0623 }
0624
0625 hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
0626 ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
0627
0628 if (hor_scl_mode == SCALE_UP)
0629 hscl_filter_mode = VOP2_SCALE_UP_BIC;
0630 else
0631 hscl_filter_mode = VOP2_SCALE_DOWN_BIL;
0632
0633 if (ver_scl_mode == SCALE_UP)
0634 vscl_filter_mode = VOP2_SCALE_UP_BIL;
0635 else
0636 vscl_filter_mode = VOP2_SCALE_DOWN_BIL;
0637
0638
0639
0640
0641
0642 if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
0643 if ((hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) {
0644 drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n",
0645 win->data->name, dst_w);
0646 dst_w++;
0647 }
0648 }
0649
0650 val = vop2_scale_factor(src_w, dst_w);
0651 vop2_win_write(win, VOP2_WIN_SCALE_YRGB_X, val);
0652 val = vop2_scale_factor(src_h, dst_h);
0653 vop2_win_write(win, VOP2_WIN_SCALE_YRGB_Y, val);
0654
0655 vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT4, gt4);
0656 vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT2, gt2);
0657
0658 vop2_win_write(win, VOP2_WIN_YRGB_HOR_SCL_MODE, hor_scl_mode);
0659 vop2_win_write(win, VOP2_WIN_YRGB_VER_SCL_MODE, ver_scl_mode);
0660
0661 if (vop2_cluster_window(win))
0662 return;
0663
0664 vop2_win_write(win, VOP2_WIN_YRGB_HSCL_FILTER_MODE, hscl_filter_mode);
0665 vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode);
0666
0667 if (info->is_yuv) {
0668 src_w /= info->hsub;
0669 src_h /= info->vsub;
0670
0671 gt4 = 0;
0672 gt2 = 0;
0673
0674 if (src_h >= (4 * dst_h)) {
0675 gt4 = 1;
0676 src_h >>= 2;
0677 } else if (src_h >= (2 * dst_h)) {
0678 gt2 = 1;
0679 src_h >>= 1;
0680 }
0681
0682 hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
0683 ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
0684
0685 val = vop2_scale_factor(src_w, dst_w);
0686 vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val);
0687
0688 val = vop2_scale_factor(src_h, dst_h);
0689 vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val);
0690
0691 vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4);
0692 vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT2, gt2);
0693 vop2_win_write(win, VOP2_WIN_CBCR_HOR_SCL_MODE, hor_scl_mode);
0694 vop2_win_write(win, VOP2_WIN_CBCR_VER_SCL_MODE, ver_scl_mode);
0695 vop2_win_write(win, VOP2_WIN_CBCR_HSCL_FILTER_MODE, hscl_filter_mode);
0696 vop2_win_write(win, VOP2_WIN_CBCR_VSCL_FILTER_MODE, vscl_filter_mode);
0697 }
0698 }
0699
0700 static int vop2_convert_csc_mode(int csc_mode)
0701 {
0702 switch (csc_mode) {
0703 case V4L2_COLORSPACE_SMPTE170M:
0704 case V4L2_COLORSPACE_470_SYSTEM_M:
0705 case V4L2_COLORSPACE_470_SYSTEM_BG:
0706 return CSC_BT601L;
0707 case V4L2_COLORSPACE_REC709:
0708 case V4L2_COLORSPACE_SMPTE240M:
0709 case V4L2_COLORSPACE_DEFAULT:
0710 return CSC_BT709L;
0711 case V4L2_COLORSPACE_JPEG:
0712 return CSC_BT601F;
0713 case V4L2_COLORSPACE_BT2020:
0714 return CSC_BT2020;
0715 default:
0716 return CSC_BT709L;
0717 }
0718 }
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753 static void vop2_setup_csc_mode(struct vop2_video_port *vp,
0754 struct vop2_win *win,
0755 struct drm_plane_state *pstate)
0756 {
0757 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
0758 int is_input_yuv = pstate->fb->format->is_yuv;
0759 int is_output_yuv = is_yuv_output(vcstate->bus_format);
0760 int input_csc = V4L2_COLORSPACE_DEFAULT;
0761 int output_csc = vcstate->color_space;
0762 bool r2y_en, y2r_en;
0763 int csc_mode;
0764
0765 if (is_input_yuv && !is_output_yuv) {
0766 y2r_en = true;
0767 r2y_en = false;
0768 csc_mode = vop2_convert_csc_mode(input_csc);
0769 } else if (!is_input_yuv && is_output_yuv) {
0770 y2r_en = false;
0771 r2y_en = true;
0772 csc_mode = vop2_convert_csc_mode(output_csc);
0773 } else {
0774 y2r_en = false;
0775 r2y_en = false;
0776 csc_mode = false;
0777 }
0778
0779 vop2_win_write(win, VOP2_WIN_Y2R_EN, y2r_en);
0780 vop2_win_write(win, VOP2_WIN_R2Y_EN, r2y_en);
0781 vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode);
0782 }
0783
0784 static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq)
0785 {
0786 struct vop2 *vop2 = vp->vop2;
0787
0788 vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irq << 16 | irq);
0789 vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16 | irq);
0790 }
0791
0792 static void vop2_crtc_disable_irq(struct vop2_video_port *vp, u32 irq)
0793 {
0794 struct vop2 *vop2 = vp->vop2;
0795
0796 vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16);
0797 }
0798
0799 static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
0800 {
0801 int ret;
0802
0803 ret = clk_prepare_enable(vop2->hclk);
0804 if (ret < 0) {
0805 drm_err(vop2->drm, "failed to enable hclk - %d\n", ret);
0806 return ret;
0807 }
0808
0809 ret = clk_prepare_enable(vop2->aclk);
0810 if (ret < 0) {
0811 drm_err(vop2->drm, "failed to enable aclk - %d\n", ret);
0812 goto err;
0813 }
0814
0815 return 0;
0816 err:
0817 clk_disable_unprepare(vop2->hclk);
0818
0819 return ret;
0820 }
0821
0822 static void vop2_enable(struct vop2 *vop2)
0823 {
0824 int ret;
0825
0826 ret = pm_runtime_get_sync(vop2->dev);
0827 if (ret < 0) {
0828 drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret);
0829 return;
0830 }
0831
0832 ret = vop2_core_clks_prepare_enable(vop2);
0833 if (ret) {
0834 pm_runtime_put_sync(vop2->dev);
0835 return;
0836 }
0837
0838 ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev);
0839 if (ret) {
0840 drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret);
0841 return;
0842 }
0843
0844 if (vop2->data->soc_id == 3566)
0845 vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
0846
0847 vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
0848
0849
0850
0851
0852
0853 regmap_clear_bits(vop2->map, RK3568_SYS_AUTO_GATING_CTRL,
0854 RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN);
0855
0856 vop2_writel(vop2, RK3568_SYS0_INT_CLR,
0857 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
0858 vop2_writel(vop2, RK3568_SYS0_INT_EN,
0859 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
0860 vop2_writel(vop2, RK3568_SYS1_INT_CLR,
0861 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
0862 vop2_writel(vop2, RK3568_SYS1_INT_EN,
0863 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR);
0864 }
0865
0866 static void vop2_disable(struct vop2 *vop2)
0867 {
0868 rockchip_drm_dma_detach_device(vop2->drm, vop2->dev);
0869
0870 pm_runtime_put_sync(vop2->dev);
0871
0872 clk_disable_unprepare(vop2->aclk);
0873 clk_disable_unprepare(vop2->hclk);
0874 }
0875
0876 static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
0877 struct drm_atomic_state *state)
0878 {
0879 struct vop2_video_port *vp = to_vop2_video_port(crtc);
0880 struct vop2 *vop2 = vp->vop2;
0881 int ret;
0882
0883 vop2_lock(vop2);
0884
0885 drm_crtc_vblank_off(crtc);
0886
0887
0888
0889
0890
0891
0892
0893
0894 reinit_completion(&vp->dsp_hold_completion);
0895
0896 vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID);
0897
0898 vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY);
0899
0900 ret = wait_for_completion_timeout(&vp->dsp_hold_completion,
0901 msecs_to_jiffies(50));
0902 if (!ret)
0903 drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id);
0904
0905 vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID);
0906
0907 clk_disable_unprepare(vp->dclk);
0908
0909 vop2->enable_count--;
0910
0911 if (!vop2->enable_count)
0912 vop2_disable(vop2);
0913
0914 vop2_unlock(vop2);
0915
0916 if (crtc->state->event && !crtc->state->active) {
0917 spin_lock_irq(&crtc->dev->event_lock);
0918 drm_crtc_send_vblank_event(crtc, crtc->state->event);
0919 spin_unlock_irq(&crtc->dev->event_lock);
0920
0921 crtc->state->event = NULL;
0922 }
0923 }
0924
0925 static int vop2_plane_atomic_check(struct drm_plane *plane,
0926 struct drm_atomic_state *astate)
0927 {
0928 struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane);
0929 struct drm_framebuffer *fb = pstate->fb;
0930 struct drm_crtc *crtc = pstate->crtc;
0931 struct drm_crtc_state *cstate;
0932 struct vop2_video_port *vp;
0933 struct vop2 *vop2;
0934 const struct vop2_data *vop2_data;
0935 struct drm_rect *dest = &pstate->dst;
0936 struct drm_rect *src = &pstate->src;
0937 int min_scale = FRAC_16_16(1, 8);
0938 int max_scale = FRAC_16_16(8, 1);
0939 int format;
0940 int ret;
0941
0942 if (!crtc)
0943 return 0;
0944
0945 vp = to_vop2_video_port(crtc);
0946 vop2 = vp->vop2;
0947 vop2_data = vop2->data;
0948
0949 cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc);
0950 if (WARN_ON(!cstate))
0951 return -EINVAL;
0952
0953 ret = drm_atomic_helper_check_plane_state(pstate, cstate,
0954 min_scale, max_scale,
0955 true, true);
0956 if (ret)
0957 return ret;
0958
0959 if (!pstate->visible)
0960 return 0;
0961
0962 format = vop2_convert_format(fb->format->format);
0963 if (format < 0)
0964 return format;
0965
0966 if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 ||
0967 drm_rect_width(dest) < 4 || drm_rect_width(dest) < 4) {
0968 drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n",
0969 drm_rect_width(src) >> 16, drm_rect_height(src) >> 16,
0970 drm_rect_width(dest), drm_rect_height(dest));
0971 pstate->visible = false;
0972 return 0;
0973 }
0974
0975 if (drm_rect_width(src) >> 16 > vop2_data->max_input.width ||
0976 drm_rect_height(src) >> 16 > vop2_data->max_input.height) {
0977 drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n",
0978 drm_rect_width(src) >> 16,
0979 drm_rect_height(src) >> 16,
0980 vop2_data->max_input.width,
0981 vop2_data->max_input.height);
0982 return -EINVAL;
0983 }
0984
0985
0986
0987
0988
0989 if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) {
0990 drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n");
0991 return -EINVAL;
0992 }
0993
0994 return 0;
0995 }
0996
0997 static void vop2_plane_atomic_disable(struct drm_plane *plane,
0998 struct drm_atomic_state *state)
0999 {
1000 struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state, plane);
1001 struct vop2_win *win = to_vop2_win(plane);
1002 struct vop2 *vop2 = win->vop2;
1003
1004 drm_dbg(vop2->drm, "%s disable\n", win->data->name);
1005
1006 if (!old_pstate->crtc)
1007 return;
1008
1009 vop2_win_disable(win);
1010 vop2_win_write(win, VOP2_WIN_YUV_CLIP, 0);
1011 }
1012
1013
1014
1015
1016
1017 static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key)
1018 {
1019 struct drm_plane_state *pstate = plane->state;
1020 struct drm_framebuffer *fb = pstate->fb;
1021 struct vop2_win *win = to_vop2_win(plane);
1022 u32 color_key_en = 0;
1023 u32 r = 0;
1024 u32 g = 0;
1025 u32 b = 0;
1026
1027 if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) {
1028 vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, 0);
1029 return;
1030 }
1031
1032 switch (fb->format->format) {
1033 case DRM_FORMAT_RGB565:
1034 case DRM_FORMAT_BGR565:
1035 r = (color_key & 0xf800) >> 11;
1036 g = (color_key & 0x7e0) >> 5;
1037 b = (color_key & 0x1f);
1038 r <<= 5;
1039 g <<= 4;
1040 b <<= 5;
1041 color_key_en = 1;
1042 break;
1043 case DRM_FORMAT_XRGB8888:
1044 case DRM_FORMAT_ARGB8888:
1045 case DRM_FORMAT_XBGR8888:
1046 case DRM_FORMAT_ABGR8888:
1047 case DRM_FORMAT_RGB888:
1048 case DRM_FORMAT_BGR888:
1049 r = (color_key & 0xff0000) >> 16;
1050 g = (color_key & 0xff00) >> 8;
1051 b = (color_key & 0xff);
1052 r <<= 2;
1053 g <<= 2;
1054 b <<= 2;
1055 color_key_en = 1;
1056 break;
1057 }
1058
1059 vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, color_key_en);
1060 vop2_win_write(win, VOP2_WIN_COLOR_KEY, (r << 20) | (g << 10) | b);
1061 }
1062
1063 static void vop2_plane_atomic_update(struct drm_plane *plane,
1064 struct drm_atomic_state *state)
1065 {
1066 struct drm_plane_state *pstate = plane->state;
1067 struct drm_crtc *crtc = pstate->crtc;
1068 struct vop2_win *win = to_vop2_win(plane);
1069 struct vop2_video_port *vp = to_vop2_video_port(crtc);
1070 struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
1071 struct vop2 *vop2 = win->vop2;
1072 struct drm_framebuffer *fb = pstate->fb;
1073 u32 bpp = fb->format->cpp[0] * 8;
1074 u32 actual_w, actual_h, dsp_w, dsp_h;
1075 u32 act_info, dsp_info;
1076 u32 format;
1077 u32 afbc_format;
1078 u32 rb_swap;
1079 u32 uv_swap;
1080 struct drm_rect *src = &pstate->src;
1081 struct drm_rect *dest = &pstate->dst;
1082 u32 afbc_tile_num;
1083 u32 transform_offset;
1084 bool dither_up;
1085 bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false;
1086 bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false;
1087 bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
1088 bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
1089 struct rockchip_gem_object *rk_obj;
1090 unsigned long offset;
1091 bool afbc_en;
1092 dma_addr_t yrgb_mst;
1093 dma_addr_t uv_mst;
1094
1095
1096
1097
1098 if (WARN_ON(!crtc))
1099 return;
1100
1101 if (!pstate->visible) {
1102 vop2_plane_atomic_disable(plane, state);
1103 return;
1104 }
1105
1106 afbc_en = rockchip_afbc(plane, fb->modifier);
1107
1108 offset = (src->x1 >> 16) * fb->format->cpp[0];
1109
1110
1111
1112
1113 if (afbc_en)
1114 offset = 0;
1115 else if (pstate->rotation & DRM_MODE_REFLECT_Y)
1116 offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
1117 else
1118 offset += (src->y1 >> 16) * fb->pitches[0];
1119
1120 rk_obj = to_rockchip_obj(fb->obj[0]);
1121
1122 yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
1123 if (fb->format->is_yuv) {
1124 int hsub = fb->format->hsub;
1125 int vsub = fb->format->vsub;
1126
1127 offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub;
1128 offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
1129
1130 if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en)
1131 offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2) / vsub;
1132
1133 rk_obj = to_rockchip_obj(fb->obj[0]);
1134 uv_mst = rk_obj->dma_addr + offset + fb->offsets[1];
1135 }
1136
1137 actual_w = drm_rect_width(src) >> 16;
1138 actual_h = drm_rect_height(src) >> 16;
1139 dsp_w = drm_rect_width(dest);
1140
1141 if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
1142 drm_err(vop2->drm, "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
1143 vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
1144 dsp_w = adjusted_mode->hdisplay - dest->x1;
1145 if (dsp_w < 4)
1146 dsp_w = 4;
1147 actual_w = dsp_w * actual_w / drm_rect_width(dest);
1148 }
1149
1150 dsp_h = drm_rect_height(dest);
1151
1152 if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
1153 drm_err(vop2->drm, "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
1154 vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
1155 dsp_h = adjusted_mode->vdisplay - dest->y1;
1156 if (dsp_h < 4)
1157 dsp_h = 4;
1158 actual_h = dsp_h * actual_h / drm_rect_height(dest);
1159 }
1160
1161
1162
1163
1164
1165 if (!(win->data->feature & WIN_FEATURE_AFBDC)) {
1166 if (actual_w > dsp_w && (actual_w & 0xf) == 1) {
1167 drm_err(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n",
1168 vp->id, win->data->name, actual_w);
1169 actual_w -= 1;
1170 }
1171 }
1172
1173 if (afbc_en && actual_w % 4) {
1174 drm_err(vop2->drm, "vp%d %s actual_w[%d] not 4 pixel aligned\n",
1175 vp->id, win->data->name, actual_w);
1176 actual_w = ALIGN_DOWN(actual_w, 4);
1177 }
1178
1179 act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
1180 dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff);
1181
1182 format = vop2_convert_format(fb->format->format);
1183
1184 drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n",
1185 vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h,
1186 dest->x1, dest->y1,
1187 &fb->format->format,
1188 afbc_en ? "AFBC" : "", &yrgb_mst);
1189
1190 if (afbc_en) {
1191 u32 stride;
1192
1193
1194 afbc_format = vop2_convert_afbc_format(fb->format->format);
1195
1196
1197 if (fb->modifier & AFBC_FORMAT_MOD_YTR)
1198 afbc_format |= (1 << 4);
1199
1200 afbc_tile_num = ALIGN(actual_w, 16) >> 4;
1201
1202
1203
1204
1205
1206 stride = (fb->pitches[0] << 3) / bpp;
1207 if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270))
1208 drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
1209 vp->id, win->data->name, stride);
1210
1211 rb_swap = vop2_afbc_rb_swap(fb->format->format);
1212 uv_swap = vop2_afbc_uv_swap(fb->format->format);
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222 if (fb->format->is_yuv && bpp == 10)
1223 format = VOP2_CLUSTER_YUV444_10;
1224
1225 if (vop2_cluster_window(win))
1226 vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1);
1227 vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format);
1228 vop2_win_write(win, VOP2_WIN_AFBC_RB_SWAP, rb_swap);
1229 vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap);
1230 vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);
1231 vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);
1232 if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90)) {
1233 vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 0);
1234 transform_offset = vop2_afbc_transform_offset(pstate, false);
1235 } else {
1236 vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 1);
1237 transform_offset = vop2_afbc_transform_offset(pstate, true);
1238 }
1239 vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);
1240 vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info);
1241 vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, transform_offset);
1242 vop2_win_write(win, VOP2_WIN_AFBC_PIC_OFFSET, ((src->x1 >> 16) | src->y1));
1243 vop2_win_write(win, VOP2_WIN_AFBC_DSP_OFFSET, (dest->x1 | (dest->y1 << 16)));
1244 vop2_win_write(win, VOP2_WIN_AFBC_PIC_VIR_WIDTH, stride);
1245 vop2_win_write(win, VOP2_WIN_AFBC_TILE_NUM, afbc_tile_num);
1246 vop2_win_write(win, VOP2_WIN_XMIRROR, xmirror);
1247 vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270);
1248 vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90);
1249 } else {
1250 vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4));
1251 }
1252
1253 vop2_win_write(win, VOP2_WIN_YMIRROR, ymirror);
1254
1255 if (rotate_90 || rotate_270) {
1256 act_info = swahw32(act_info);
1257 actual_w = drm_rect_height(src) >> 16;
1258 actual_h = drm_rect_width(src) >> 16;
1259 }
1260
1261 vop2_win_write(win, VOP2_WIN_FORMAT, format);
1262 vop2_win_write(win, VOP2_WIN_YRGB_MST, yrgb_mst);
1263
1264 rb_swap = vop2_win_rb_swap(fb->format->format);
1265 vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap);
1266 if (!vop2_cluster_window(win)) {
1267 uv_swap = vop2_win_uv_swap(fb->format->format);
1268 vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap);
1269 }
1270
1271 if (fb->format->is_yuv) {
1272 vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4));
1273 vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst);
1274 }
1275
1276 vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format);
1277 if (!vop2_cluster_window(win))
1278 vop2_plane_setup_color_key(plane, 0);
1279 vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info);
1280 vop2_win_write(win, VOP2_WIN_DSP_INFO, dsp_info);
1281 vop2_win_write(win, VOP2_WIN_DSP_ST, dest->y1 << 16 | (dest->x1 & 0xffff));
1282
1283 vop2_setup_csc_mode(vp, win, pstate);
1284
1285 dither_up = vop2_win_dither_up(fb->format->format);
1286 vop2_win_write(win, VOP2_WIN_DITHER_UP, dither_up);
1287
1288 vop2_win_write(win, VOP2_WIN_ENABLE, 1);
1289
1290 if (vop2_cluster_window(win)) {
1291 int lb_mode = vop2_get_cluster_lb_mode(win, pstate);
1292
1293 vop2_win_write(win, VOP2_WIN_CLUSTER_LB_MODE, lb_mode);
1294 vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 1);
1295 }
1296 }
1297
1298 static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = {
1299 .atomic_check = vop2_plane_atomic_check,
1300 .atomic_update = vop2_plane_atomic_update,
1301 .atomic_disable = vop2_plane_atomic_disable,
1302 };
1303
1304 static const struct drm_plane_funcs vop2_plane_funcs = {
1305 .update_plane = drm_atomic_helper_update_plane,
1306 .disable_plane = drm_atomic_helper_disable_plane,
1307 .destroy = drm_plane_cleanup,
1308 .reset = drm_atomic_helper_plane_reset,
1309 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
1310 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
1311 .format_mod_supported = rockchip_vop2_mod_supported,
1312 };
1313
1314 static int vop2_crtc_enable_vblank(struct drm_crtc *crtc)
1315 {
1316 struct vop2_video_port *vp = to_vop2_video_port(crtc);
1317
1318 vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD);
1319
1320 return 0;
1321 }
1322
1323 static void vop2_crtc_disable_vblank(struct drm_crtc *crtc)
1324 {
1325 struct vop2_video_port *vp = to_vop2_video_port(crtc);
1326
1327 vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD);
1328 }
1329
1330 static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
1331 const struct drm_display_mode *mode,
1332 struct drm_display_mode *adj_mode)
1333 {
1334 drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V |
1335 CRTC_STEREO_DOUBLE);
1336
1337 return true;
1338 }
1339
1340 static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)
1341 {
1342 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
1343
1344 switch (vcstate->bus_format) {
1345 case MEDIA_BUS_FMT_RGB565_1X16:
1346 *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
1347 break;
1348 case MEDIA_BUS_FMT_RGB666_1X18:
1349 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
1350 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
1351 *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN;
1352 *dsp_ctrl |= RGB888_TO_RGB666;
1353 break;
1354 case MEDIA_BUS_FMT_YUV8_1X24:
1355 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
1356 *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
1357 break;
1358 default:
1359 break;
1360 }
1361
1362 if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA)
1363 *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN;
1364
1365 *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL,
1366 DITHER_DOWN_ALLEGRO);
1367 }
1368
1369 static void vop2_post_config(struct drm_crtc *crtc)
1370 {
1371 struct vop2_video_port *vp = to_vop2_video_port(crtc);
1372 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
1373 u16 vtotal = mode->crtc_vtotal;
1374 u16 hdisplay = mode->crtc_hdisplay;
1375 u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
1376 u16 vdisplay = mode->crtc_vdisplay;
1377 u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
1378 u32 left_margin = 100, right_margin = 100;
1379 u32 top_margin = 100, bottom_margin = 100;
1380 u16 hsize = hdisplay * (left_margin + right_margin) / 200;
1381 u16 vsize = vdisplay * (top_margin + bottom_margin) / 200;
1382 u16 hact_end, vact_end;
1383 u32 val;
1384
1385 vsize = rounddown(vsize, 2);
1386 hsize = rounddown(hsize, 2);
1387 hact_st += hdisplay * (100 - left_margin) / 200;
1388 hact_end = hact_st + hsize;
1389 val = hact_st << 16;
1390 val |= hact_end;
1391 vop2_vp_write(vp, RK3568_VP_POST_DSP_HACT_INFO, val);
1392 vact_st += vdisplay * (100 - top_margin) / 200;
1393 vact_end = vact_st + vsize;
1394 val = vact_st << 16;
1395 val |= vact_end;
1396 vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO, val);
1397 val = scl_cal_scale2(vdisplay, vsize) << 16;
1398 val |= scl_cal_scale2(hdisplay, hsize);
1399 vop2_vp_write(vp, RK3568_VP_POST_SCL_FACTOR_YRGB, val);
1400
1401 val = 0;
1402 if (hdisplay != hsize)
1403 val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN;
1404 if (vdisplay != vsize)
1405 val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN;
1406 vop2_vp_write(vp, RK3568_VP_POST_SCL_CTRL, val);
1407
1408 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1409 u16 vact_st_f1 = vtotal + vact_st + 1;
1410 u16 vact_end_f1 = vact_st_f1 + vsize;
1411
1412 val = vact_st_f1 << 16 | vact_end_f1;
1413 vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val);
1414 }
1415
1416 vop2_vp_write(vp, RK3568_VP_DSP_BG, 0);
1417 }
1418
1419 static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
1420 u32 polflags)
1421 {
1422 struct vop2 *vop2 = vp->vop2;
1423 u32 die, dip;
1424
1425 die = vop2_readl(vop2, RK3568_DSP_IF_EN);
1426 dip = vop2_readl(vop2, RK3568_DSP_IF_POL);
1427
1428 switch (id) {
1429 case ROCKCHIP_VOP2_EP_RGB0:
1430 die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX;
1431 die |= RK3568_SYS_DSP_INFACE_EN_RGB |
1432 FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id);
1433 if (polflags & POLFLAG_DCLK_INV)
1434 regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3));
1435 else
1436 regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16));
1437 break;
1438 case ROCKCHIP_VOP2_EP_HDMI0:
1439 die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX;
1440 die |= RK3568_SYS_DSP_INFACE_EN_HDMI |
1441 FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id);
1442 dip &= ~RK3568_DSP_IF_POL__HDMI_PIN_POL;
1443 dip |= FIELD_PREP(RK3568_DSP_IF_POL__HDMI_PIN_POL, polflags);
1444 break;
1445 case ROCKCHIP_VOP2_EP_EDP0:
1446 die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX;
1447 die |= RK3568_SYS_DSP_INFACE_EN_EDP |
1448 FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id);
1449 dip &= ~RK3568_DSP_IF_POL__EDP_PIN_POL;
1450 dip |= FIELD_PREP(RK3568_DSP_IF_POL__EDP_PIN_POL, polflags);
1451 break;
1452 case ROCKCHIP_VOP2_EP_MIPI0:
1453 die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX;
1454 die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 |
1455 FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id);
1456 dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
1457 dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
1458 break;
1459 case ROCKCHIP_VOP2_EP_MIPI1:
1460 die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX;
1461 die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 |
1462 FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);
1463 dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL;
1464 dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags);
1465 break;
1466 case ROCKCHIP_VOP2_EP_LVDS0:
1467 die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX;
1468 die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 |
1469 FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id);
1470 dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
1471 dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
1472 break;
1473 case ROCKCHIP_VOP2_EP_LVDS1:
1474 die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX;
1475 die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 |
1476 FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id);
1477 dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL;
1478 dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags);
1479 break;
1480 default:
1481 drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id);
1482 return;
1483 }
1484
1485 dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;
1486
1487 vop2_writel(vop2, RK3568_DSP_IF_EN, die);
1488 vop2_writel(vop2, RK3568_DSP_IF_POL, dip);
1489 }
1490
1491 static int us_to_vertical_line(struct drm_display_mode *mode, int us)
1492 {
1493 return us * mode->clock / mode->htotal / 1000;
1494 }
1495
1496 static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
1497 struct drm_atomic_state *state)
1498 {
1499 struct vop2_video_port *vp = to_vop2_video_port(crtc);
1500 struct vop2 *vop2 = vp->vop2;
1501 const struct vop2_data *vop2_data = vop2->data;
1502 const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
1503 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1504 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
1505 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
1506 unsigned long clock = mode->crtc_clock * 1000;
1507 u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
1508 u16 hdisplay = mode->crtc_hdisplay;
1509 u16 htotal = mode->crtc_htotal;
1510 u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
1511 u16 hact_end = hact_st + hdisplay;
1512 u16 vdisplay = mode->crtc_vdisplay;
1513 u16 vtotal = mode->crtc_vtotal;
1514 u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
1515 u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
1516 u16 vact_end = vact_st + vdisplay;
1517 u8 out_mode;
1518 u32 dsp_ctrl = 0;
1519 int act_end;
1520 u32 val, polflags;
1521 int ret;
1522 struct drm_encoder *encoder;
1523
1524 drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n",
1525 hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p",
1526 drm_mode_vrefresh(mode), vcstate->output_type, vp->id);
1527
1528 vop2_lock(vop2);
1529
1530 ret = clk_prepare_enable(vp->dclk);
1531 if (ret < 0) {
1532 drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n",
1533 vp->id, ret);
1534 vop2_unlock(vop2);
1535 return;
1536 }
1537
1538 if (!vop2->enable_count)
1539 vop2_enable(vop2);
1540
1541 vop2->enable_count++;
1542
1543 vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY);
1544
1545 polflags = 0;
1546 if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
1547 polflags |= POLFLAG_DCLK_INV;
1548 if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1549 polflags |= BIT(HSYNC_POSITIVE);
1550 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1551 polflags |= BIT(VSYNC_POSITIVE);
1552
1553 drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
1554 struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
1555
1556 rk3568_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);
1557 }
1558
1559 if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
1560 !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT))
1561 out_mode = ROCKCHIP_OUT_MODE_P888;
1562 else
1563 out_mode = vcstate->output_mode;
1564
1565 dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode);
1566
1567 if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
1568 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;
1569
1570 if (is_yuv_output(vcstate->bus_format))
1571 dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;
1572
1573 vop2_dither_setup(crtc, &dsp_ctrl);
1574
1575 vop2_vp_write(vp, RK3568_VP_DSP_HTOTAL_HS_END, (htotal << 16) | hsync_len);
1576 val = hact_st << 16;
1577 val |= hact_end;
1578 vop2_vp_write(vp, RK3568_VP_DSP_HACT_ST_END, val);
1579
1580 val = vact_st << 16;
1581 val |= vact_end;
1582 vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END, val);
1583
1584 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1585 u16 vact_st_f1 = vtotal + vact_st + 1;
1586 u16 vact_end_f1 = vact_st_f1 + vdisplay;
1587
1588 val = vact_st_f1 << 16 | vact_end_f1;
1589 vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END_F1, val);
1590
1591 val = vtotal << 16 | (vtotal + vsync_len);
1592 vop2_vp_write(vp, RK3568_VP_DSP_VS_ST_END_F1, val);
1593 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE;
1594 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL;
1595 dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN;
1596 vtotal += vtotal + 1;
1597 act_end = vact_end_f1;
1598 } else {
1599 act_end = vact_end;
1600 }
1601
1602 vop2_writel(vop2, RK3568_VP_LINE_FLAG(vp->id),
1603 (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end);
1604
1605 vop2_vp_write(vp, RK3568_VP_DSP_VTOTAL_VS_END, vtotal << 16 | vsync_len);
1606
1607 if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
1608 dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV;
1609 clock *= 2;
1610 }
1611
1612 vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0);
1613
1614 clk_set_rate(vp->dclk, clock);
1615
1616 vop2_post_config(crtc);
1617
1618 vop2_cfg_done(vp);
1619
1620 vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
1621
1622 drm_crtc_vblank_on(crtc);
1623
1624 vop2_unlock(vop2);
1625 }
1626
1627 static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
1628 struct drm_atomic_state *state)
1629 {
1630 struct vop2_video_port *vp = to_vop2_video_port(crtc);
1631 struct drm_plane *plane;
1632 int nplanes = 0;
1633 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1634
1635 drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
1636 nplanes++;
1637
1638 if (nplanes > vp->nlayers)
1639 return -EINVAL;
1640
1641 return 0;
1642 }
1643
1644 static bool is_opaque(u16 alpha)
1645 {
1646 return (alpha >> 8) == 0xff;
1647 }
1648
1649 static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
1650 struct vop2_alpha *alpha)
1651 {
1652 int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1;
1653 int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1;
1654 int src_color_mode = alpha_config->src_premulti_en ?
1655 ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
1656 int dst_color_mode = alpha_config->dst_premulti_en ?
1657 ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL;
1658
1659 alpha->src_color_ctrl.val = 0;
1660 alpha->dst_color_ctrl.val = 0;
1661 alpha->src_alpha_ctrl.val = 0;
1662 alpha->dst_alpha_ctrl.val = 0;
1663
1664 if (!alpha_config->src_pixel_alpha_en)
1665 alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
1666 else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en)
1667 alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX;
1668 else
1669 alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
1670
1671 alpha->src_color_ctrl.bits.alpha_en = 1;
1672
1673 if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) {
1674 alpha->src_color_ctrl.bits.color_mode = src_color_mode;
1675 alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
1676 } else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) {
1677 alpha->src_color_ctrl.bits.color_mode = src_color_mode;
1678 alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE;
1679 } else {
1680 alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL;
1681 alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL;
1682 }
1683 alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8;
1684 alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
1685 alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
1686
1687 alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
1688 alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
1689 alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL;
1690 alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8;
1691 alpha->dst_color_ctrl.bits.color_mode = dst_color_mode;
1692 alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
1693
1694 alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
1695 alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode;
1696 alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION;
1697 alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE;
1698
1699 alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT;
1700 if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en)
1701 alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX;
1702 else
1703 alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL;
1704 alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION;
1705 alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
1706 }
1707
1708 static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)
1709 {
1710 struct vop2_video_port *vp;
1711 int used_layer = 0;
1712 int i;
1713
1714 for (i = 0; i < port_id; i++) {
1715 vp = &vop2->vps[i];
1716 used_layer += hweight32(vp->win_mask);
1717 }
1718
1719 return used_layer;
1720 }
1721
1722 static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
1723 {
1724 u32 offset = (main_win->data->phys_id * 0x10);
1725 struct vop2_alpha_config alpha_config;
1726 struct vop2_alpha alpha;
1727 struct drm_plane_state *bottom_win_pstate;
1728 bool src_pixel_alpha_en = false;
1729 u16 src_glb_alpha_val, dst_glb_alpha_val;
1730 bool premulti_en = false;
1731 bool swap = false;
1732
1733
1734 bottom_win_pstate = main_win->base.state;
1735 src_glb_alpha_val = 0;
1736 dst_glb_alpha_val = main_win->base.state->alpha;
1737
1738 if (!bottom_win_pstate->fb)
1739 return;
1740
1741 alpha_config.src_premulti_en = premulti_en;
1742 alpha_config.dst_premulti_en = false;
1743 alpha_config.src_pixel_alpha_en = src_pixel_alpha_en;
1744 alpha_config.dst_pixel_alpha_en = true;
1745 alpha_config.src_glb_alpha_value = src_glb_alpha_val;
1746 alpha_config.dst_glb_alpha_value = dst_glb_alpha_val;
1747 vop2_parse_alpha(&alpha_config, &alpha);
1748
1749 alpha.src_color_ctrl.bits.src_dst_swap = swap;
1750 vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset,
1751 alpha.src_color_ctrl.val);
1752 vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset,
1753 alpha.dst_color_ctrl.val);
1754 vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset,
1755 alpha.src_alpha_ctrl.val);
1756 vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset,
1757 alpha.dst_alpha_ctrl.val);
1758 }
1759
1760 static void vop2_setup_alpha(struct vop2_video_port *vp)
1761 {
1762 struct vop2 *vop2 = vp->vop2;
1763 struct drm_framebuffer *fb;
1764 struct vop2_alpha_config alpha_config;
1765 struct vop2_alpha alpha;
1766 struct drm_plane *plane;
1767 int pixel_alpha_en;
1768 int premulti_en, gpremulti_en = 0;
1769 int mixer_id;
1770 u32 offset;
1771 bool bottom_layer_alpha_en = false;
1772 u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
1773
1774 mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
1775 alpha_config.dst_pixel_alpha_en = true;
1776
1777 drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
1778 struct vop2_win *win = to_vop2_win(plane);
1779
1780 if (plane->state->normalized_zpos == 0 &&
1781 !is_opaque(plane->state->alpha) &&
1782 !vop2_cluster_window(win)) {
1783
1784
1785
1786
1787
1788 bottom_layer_alpha_en = true;
1789 dst_global_alpha = plane->state->alpha;
1790 }
1791 }
1792
1793 drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
1794 struct vop2_win *win = to_vop2_win(plane);
1795 int zpos = plane->state->normalized_zpos;
1796
1797 if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
1798 premulti_en = 1;
1799 else
1800 premulti_en = 0;
1801
1802 plane = &win->base;
1803 fb = plane->state->fb;
1804
1805 pixel_alpha_en = fb->format->has_alpha;
1806
1807 alpha_config.src_premulti_en = premulti_en;
1808
1809 if (bottom_layer_alpha_en && zpos == 1) {
1810 gpremulti_en = premulti_en;
1811
1812 alpha_config.dst_premulti_en = false;
1813 alpha_config.src_pixel_alpha_en = pixel_alpha_en;
1814 alpha_config.src_glb_alpha_value = plane->state->alpha;
1815 alpha_config.dst_glb_alpha_value = dst_global_alpha;
1816 } else if (vop2_cluster_window(win)) {
1817
1818 alpha_config.dst_premulti_en = true;
1819 alpha_config.src_pixel_alpha_en = true;
1820 alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
1821 alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
1822 } else {
1823
1824 alpha_config.dst_premulti_en = true;
1825 alpha_config.src_pixel_alpha_en = pixel_alpha_en;
1826 alpha_config.src_glb_alpha_value = plane->state->alpha;
1827 alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
1828 }
1829
1830 vop2_parse_alpha(&alpha_config, &alpha);
1831
1832 offset = (mixer_id + zpos - 1) * 0x10;
1833 vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset,
1834 alpha.src_color_ctrl.val);
1835 vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset,
1836 alpha.dst_color_ctrl.val);
1837 vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset,
1838 alpha.src_alpha_ctrl.val);
1839 vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset,
1840 alpha.dst_alpha_ctrl.val);
1841 }
1842
1843 if (vp->id == 0) {
1844 if (bottom_layer_alpha_en) {
1845
1846 alpha_config.src_premulti_en = gpremulti_en;
1847 alpha_config.dst_premulti_en = true;
1848 alpha_config.src_pixel_alpha_en = true;
1849 alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
1850 alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE;
1851 vop2_parse_alpha(&alpha_config, &alpha);
1852
1853 vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL,
1854 alpha.src_color_ctrl.val);
1855 vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL,
1856 alpha.dst_color_ctrl.val);
1857 vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL,
1858 alpha.src_alpha_ctrl.val);
1859 vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL,
1860 alpha.dst_alpha_ctrl.val);
1861 } else {
1862 vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0);
1863 }
1864 }
1865 }
1866
1867 static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
1868 {
1869 struct vop2 *vop2 = vp->vop2;
1870 struct drm_plane *plane;
1871 u32 layer_sel = 0;
1872 u32 port_sel;
1873 unsigned int nlayer, ofs;
1874 struct drm_display_mode *adjusted_mode;
1875 u16 hsync_len;
1876 u16 hdisplay;
1877 u32 bg_dly;
1878 u32 pre_scan_dly;
1879 int i;
1880 struct vop2_video_port *vp0 = &vop2->vps[0];
1881 struct vop2_video_port *vp1 = &vop2->vps[1];
1882 struct vop2_video_port *vp2 = &vop2->vps[2];
1883
1884 adjusted_mode = &vp->crtc.state->adjusted_mode;
1885 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
1886 hdisplay = adjusted_mode->crtc_hdisplay;
1887
1888 bg_dly = vp->data->pre_scan_max_dly[3];
1889 vop2_writel(vop2, RK3568_VP_BG_MIX_CTRL(vp->id),
1890 FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly));
1891
1892 pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len;
1893 vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly);
1894
1895 vop2_writel(vop2, RK3568_OVL_CTRL, 0);
1896 port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
1897 port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
1898
1899 if (vp0->nlayers)
1900 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX,
1901 vp0->nlayers - 1);
1902 else
1903 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8);
1904
1905 if (vp1->nlayers)
1906 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX,
1907 (vp0->nlayers + vp1->nlayers - 1));
1908 else
1909 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
1910
1911 if (vp2->nlayers)
1912 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX,
1913 (vp2->nlayers + vp1->nlayers + vp0->nlayers - 1));
1914 else
1915 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8);
1916
1917 layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
1918
1919 ofs = 0;
1920 for (i = 0; i < vp->id; i++)
1921 ofs += vop2->vps[i].nlayers;
1922
1923 nlayer = 0;
1924 drm_atomic_crtc_for_each_plane(plane, &vp->crtc) {
1925 struct vop2_win *win = to_vop2_win(plane);
1926
1927 switch (win->data->phys_id) {
1928 case ROCKCHIP_VOP2_CLUSTER0:
1929 port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0;
1930 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id);
1931 break;
1932 case ROCKCHIP_VOP2_CLUSTER1:
1933 port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1;
1934 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id);
1935 break;
1936 case ROCKCHIP_VOP2_ESMART0:
1937 port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0;
1938 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id);
1939 break;
1940 case ROCKCHIP_VOP2_ESMART1:
1941 port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1;
1942 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id);
1943 break;
1944 case ROCKCHIP_VOP2_SMART0:
1945 port_sel &= ~RK3568_OVL_PORT_SEL__SMART0;
1946 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id);
1947 break;
1948 case ROCKCHIP_VOP2_SMART1:
1949 port_sel &= ~RK3568_OVL_PORT_SEL__SMART1;
1950 port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id);
1951 break;
1952 }
1953
1954 layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs,
1955 0x7);
1956 layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs,
1957 win->data->layer_sel_id);
1958 nlayer++;
1959 }
1960
1961
1962 for (; nlayer < vp->nlayers; nlayer++) {
1963 layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7);
1964 layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5);
1965 }
1966
1967 vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
1968 vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
1969 vop2_writel(vop2, RK3568_OVL_CTRL, RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD);
1970 }
1971
1972 static void vop2_setup_dly_for_windows(struct vop2 *vop2)
1973 {
1974 struct vop2_win *win;
1975 int i = 0;
1976 u32 cdly = 0, sdly = 0;
1977
1978 for (i = 0; i < vop2->data->win_size; i++) {
1979 u32 dly;
1980
1981 win = &vop2->win[i];
1982 dly = win->delay;
1983
1984 switch (win->data->phys_id) {
1985 case ROCKCHIP_VOP2_CLUSTER0:
1986 cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly);
1987 cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly);
1988 break;
1989 case ROCKCHIP_VOP2_CLUSTER1:
1990 cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly);
1991 cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly);
1992 break;
1993 case ROCKCHIP_VOP2_ESMART0:
1994 sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly);
1995 break;
1996 case ROCKCHIP_VOP2_ESMART1:
1997 sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly);
1998 break;
1999 case ROCKCHIP_VOP2_SMART0:
2000 sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly);
2001 break;
2002 case ROCKCHIP_VOP2_SMART1:
2003 sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly);
2004 break;
2005 }
2006 }
2007
2008 vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly);
2009 vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly);
2010 }
2011
2012 static void vop2_crtc_atomic_begin(struct drm_crtc *crtc,
2013 struct drm_atomic_state *state)
2014 {
2015 struct vop2_video_port *vp = to_vop2_video_port(crtc);
2016 struct vop2 *vop2 = vp->vop2;
2017 struct drm_plane *plane;
2018
2019 vp->win_mask = 0;
2020
2021 drm_atomic_crtc_for_each_plane(plane, crtc) {
2022 struct vop2_win *win = to_vop2_win(plane);
2023
2024 win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT];
2025
2026 vp->win_mask |= BIT(win->data->phys_id);
2027
2028 if (vop2_cluster_window(win))
2029 vop2_setup_cluster_alpha(vop2, win);
2030 }
2031
2032 if (!vp->win_mask)
2033 return;
2034
2035 vop2_setup_layer_mixer(vp);
2036 vop2_setup_alpha(vp);
2037 vop2_setup_dly_for_windows(vop2);
2038 }
2039
2040 static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
2041 struct drm_atomic_state *state)
2042 {
2043 struct vop2_video_port *vp = to_vop2_video_port(crtc);
2044
2045 vop2_post_config(crtc);
2046
2047 vop2_cfg_done(vp);
2048
2049 spin_lock_irq(&crtc->dev->event_lock);
2050
2051 if (crtc->state->event) {
2052 WARN_ON(drm_crtc_vblank_get(crtc));
2053 vp->event = crtc->state->event;
2054 crtc->state->event = NULL;
2055 }
2056
2057 spin_unlock_irq(&crtc->dev->event_lock);
2058 }
2059
2060 static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = {
2061 .mode_fixup = vop2_crtc_mode_fixup,
2062 .atomic_check = vop2_crtc_atomic_check,
2063 .atomic_begin = vop2_crtc_atomic_begin,
2064 .atomic_flush = vop2_crtc_atomic_flush,
2065 .atomic_enable = vop2_crtc_atomic_enable,
2066 .atomic_disable = vop2_crtc_atomic_disable,
2067 };
2068
2069 static void vop2_crtc_reset(struct drm_crtc *crtc)
2070 {
2071 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
2072
2073 if (crtc->state) {
2074 __drm_atomic_helper_crtc_destroy_state(crtc->state);
2075 kfree(vcstate);
2076 }
2077
2078 vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL);
2079 if (!vcstate)
2080 return;
2081
2082 crtc->state = &vcstate->base;
2083 crtc->state->crtc = crtc;
2084 }
2085
2086 static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
2087 {
2088 struct rockchip_crtc_state *vcstate, *old_vcstate;
2089
2090 old_vcstate = to_rockchip_crtc_state(crtc->state);
2091
2092 vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL);
2093 if (!vcstate)
2094 return NULL;
2095
2096 __drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base);
2097
2098 return &vcstate->base;
2099 }
2100
2101 static void vop2_crtc_destroy_state(struct drm_crtc *crtc,
2102 struct drm_crtc_state *state)
2103 {
2104 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);
2105
2106 __drm_atomic_helper_crtc_destroy_state(&vcstate->base);
2107 kfree(vcstate);
2108 }
2109
2110 static const struct drm_crtc_funcs vop2_crtc_funcs = {
2111 .set_config = drm_atomic_helper_set_config,
2112 .page_flip = drm_atomic_helper_page_flip,
2113 .destroy = drm_crtc_cleanup,
2114 .reset = vop2_crtc_reset,
2115 .atomic_duplicate_state = vop2_crtc_duplicate_state,
2116 .atomic_destroy_state = vop2_crtc_destroy_state,
2117 .enable_vblank = vop2_crtc_enable_vblank,
2118 .disable_vblank = vop2_crtc_disable_vblank,
2119 };
2120
2121 static irqreturn_t vop2_isr(int irq, void *data)
2122 {
2123 struct vop2 *vop2 = data;
2124 const struct vop2_data *vop2_data = vop2->data;
2125 u32 axi_irqs[VOP2_SYS_AXI_BUS_NUM];
2126 int ret = IRQ_NONE;
2127 int i;
2128
2129
2130
2131
2132
2133 if (!pm_runtime_get_if_in_use(vop2->dev))
2134 return IRQ_NONE;
2135
2136 for (i = 0; i < vop2_data->nr_vps; i++) {
2137 struct vop2_video_port *vp = &vop2->vps[i];
2138 struct drm_crtc *crtc = &vp->crtc;
2139 u32 irqs;
2140
2141 irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id));
2142 vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs);
2143
2144 if (irqs & VP_INT_DSP_HOLD_VALID) {
2145 complete(&vp->dsp_hold_completion);
2146 ret = IRQ_HANDLED;
2147 }
2148
2149 if (irqs & VP_INT_FS_FIELD) {
2150 drm_crtc_handle_vblank(crtc);
2151 spin_lock(&crtc->dev->event_lock);
2152 if (vp->event) {
2153 u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE);
2154
2155 if (!(val & BIT(vp->id))) {
2156 drm_crtc_send_vblank_event(crtc, vp->event);
2157 vp->event = NULL;
2158 drm_crtc_vblank_put(crtc);
2159 }
2160 }
2161 spin_unlock(&crtc->dev->event_lock);
2162
2163 ret = IRQ_HANDLED;
2164 }
2165
2166 if (irqs & VP_INT_POST_BUF_EMPTY) {
2167 drm_err_ratelimited(vop2->drm,
2168 "POST_BUF_EMPTY irq err at vp%d\n",
2169 vp->id);
2170 ret = IRQ_HANDLED;
2171 }
2172 }
2173
2174 axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS);
2175 vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]);
2176 axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS);
2177 vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]);
2178
2179 for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) {
2180 if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) {
2181 drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n");
2182 ret = IRQ_HANDLED;
2183 }
2184 }
2185
2186 pm_runtime_put(vop2->dev);
2187
2188 return ret;
2189 }
2190
2191 static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win,
2192 unsigned long possible_crtcs)
2193 {
2194 const struct vop2_win_data *win_data = win->data;
2195 unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
2196 BIT(DRM_MODE_BLEND_PREMULTI) |
2197 BIT(DRM_MODE_BLEND_COVERAGE);
2198 int ret;
2199
2200 ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs,
2201 &vop2_plane_funcs, win_data->formats,
2202 win_data->nformats,
2203 win_data->format_modifiers,
2204 win->type, win_data->name);
2205 if (ret) {
2206 drm_err(vop2->drm, "failed to initialize plane %d\n", ret);
2207 return ret;
2208 }
2209
2210 drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs);
2211
2212 if (win->data->supported_rotations)
2213 drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0,
2214 DRM_MODE_ROTATE_0 |
2215 win->data->supported_rotations);
2216 drm_plane_create_alpha_property(&win->base);
2217 drm_plane_create_blend_mode_property(&win->base, blend_caps);
2218 drm_plane_create_zpos_property(&win->base, win->win_id, 0,
2219 vop2->registered_num_wins - 1);
2220
2221 return 0;
2222 }
2223
2224 static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2)
2225 {
2226 int i;
2227
2228 for (i = 0; i < vop2->data->nr_vps; i++) {
2229 struct vop2_video_port *vp = &vop2->vps[i];
2230
2231 if (!vp->crtc.port)
2232 continue;
2233 if (vp->primary_plane)
2234 continue;
2235
2236 return vp;
2237 }
2238
2239 return NULL;
2240 }
2241
2242 #define NR_LAYERS 6
2243
2244 static int vop2_create_crtc(struct vop2 *vop2)
2245 {
2246 const struct vop2_data *vop2_data = vop2->data;
2247 struct drm_device *drm = vop2->drm;
2248 struct device *dev = vop2->dev;
2249 struct drm_plane *plane;
2250 struct device_node *port;
2251 struct vop2_video_port *vp;
2252 int i, nvp, nvps = 0;
2253 int ret;
2254
2255 for (i = 0; i < vop2_data->nr_vps; i++) {
2256 const struct vop2_video_port_data *vp_data;
2257 struct device_node *np;
2258 char dclk_name[9];
2259
2260 vp_data = &vop2_data->vp[i];
2261 vp = &vop2->vps[i];
2262 vp->vop2 = vop2;
2263 vp->id = vp_data->id;
2264 vp->regs = vp_data->regs;
2265 vp->data = vp_data;
2266
2267 snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);
2268 vp->dclk = devm_clk_get(vop2->dev, dclk_name);
2269 if (IS_ERR(vp->dclk)) {
2270 drm_err(vop2->drm, "failed to get %s\n", dclk_name);
2271 return PTR_ERR(vp->dclk);
2272 }
2273
2274 np = of_graph_get_remote_node(dev->of_node, i, -1);
2275 if (!np) {
2276 drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i);
2277 continue;
2278 }
2279 of_node_put(np);
2280
2281 port = of_graph_get_port_by_id(dev->of_node, i);
2282 if (!port) {
2283 drm_err(vop2->drm, "no port node found for video_port%d\n", i);
2284 return -ENOENT;
2285 }
2286
2287 vp->crtc.port = port;
2288 nvps++;
2289 }
2290
2291 nvp = 0;
2292 for (i = 0; i < vop2->registered_num_wins; i++) {
2293 struct vop2_win *win = &vop2->win[i];
2294 u32 possible_crtcs;
2295
2296 if (vop2->data->soc_id == 3566) {
2297
2298
2299
2300
2301
2302 switch (win->data->phys_id) {
2303 case ROCKCHIP_VOP2_SMART1:
2304 case ROCKCHIP_VOP2_ESMART1:
2305 case ROCKCHIP_VOP2_CLUSTER1:
2306 continue;
2307 }
2308 }
2309
2310 if (win->type == DRM_PLANE_TYPE_PRIMARY) {
2311 vp = find_vp_without_primary(vop2);
2312 if (vp) {
2313 possible_crtcs = BIT(nvp);
2314 vp->primary_plane = win;
2315 nvp++;
2316 } else {
2317
2318 win->type = DRM_PLANE_TYPE_OVERLAY;
2319 }
2320 }
2321
2322 if (win->type == DRM_PLANE_TYPE_OVERLAY)
2323 possible_crtcs = (1 << nvps) - 1;
2324
2325 ret = vop2_plane_init(vop2, win, possible_crtcs);
2326 if (ret) {
2327 drm_err(vop2->drm, "failed to init plane %s: %d\n",
2328 win->data->name, ret);
2329 return ret;
2330 }
2331 }
2332
2333 for (i = 0; i < vop2_data->nr_vps; i++) {
2334 vp = &vop2->vps[i];
2335
2336 if (!vp->crtc.port)
2337 continue;
2338
2339 plane = &vp->primary_plane->base;
2340
2341 ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL,
2342 &vop2_crtc_funcs,
2343 "video_port%d", vp->id);
2344 if (ret) {
2345 drm_err(vop2->drm, "crtc init for video_port%d failed\n", i);
2346 return ret;
2347 }
2348
2349 drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
2350
2351 init_completion(&vp->dsp_hold_completion);
2352 }
2353
2354
2355
2356
2357
2358
2359 for (i = 0; i < vop2->data->nr_vps; i++) {
2360 struct vop2_video_port *vp = &vop2->vps[i];
2361
2362 if (vp->crtc.port)
2363 vp->nlayers = NR_LAYERS / nvps;
2364 }
2365
2366 return 0;
2367 }
2368
2369 static void vop2_destroy_crtc(struct drm_crtc *crtc)
2370 {
2371 of_node_put(crtc->port);
2372
2373
2374
2375
2376
2377 drm_crtc_cleanup(crtc);
2378 }
2379
2380 static struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] = {
2381 [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0),
2382 [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5),
2383 [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14),
2384 [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 18, 18),
2385 [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_ACT_INFO, 0, 31),
2386 [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_INFO, 0, 31),
2387 [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_ST, 0, 31),
2388 [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_CLUSTER_WIN_YRGB_MST, 0, 31),
2389 [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_CLUSTER_WIN_CBR_MST, 0, 31),
2390 [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 19, 19),
2391 [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 0, 15),
2392 [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 16, 31),
2393 [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 8, 8),
2394 [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 9, 9),
2395 [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 10, 11),
2396
2397
2398 [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0, 15),
2399 [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 16, 31),
2400 [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 14, 15),
2401 [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 12, 13),
2402 [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 2, 3),
2403 [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 28, 28),
2404 [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 29, 29),
2405
2406
2407 [VOP2_WIN_AFBC_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 1, 1),
2408 [VOP2_WIN_CLUSTER_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 0, 0),
2409 [VOP2_WIN_CLUSTER_LB_MODE] = REG_FIELD(RK3568_CLUSTER_CTRL, 4, 7),
2410
2411
2412 [VOP2_WIN_AFBC_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 2, 6),
2413 [VOP2_WIN_AFBC_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 9, 9),
2414 [VOP2_WIN_AFBC_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 10, 10),
2415 [VOP2_WIN_AFBC_AUTO_GATING_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 4, 4),
2416 [VOP2_WIN_AFBC_HALF_BLOCK_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 7, 7),
2417 [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 8, 8),
2418 [VOP2_WIN_AFBC_HDR_PTR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0, 31),
2419 [VOP2_WIN_AFBC_PIC_SIZE] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0, 31),
2420 [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0, 15),
2421 [VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31),
2422 [VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31),
2423 [VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31),
2424 [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31),
2425 [VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0),
2426 [VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1),
2427 [VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2),
2428 [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 3, 3),
2429 [VOP2_WIN_UV_SWAP] = { .reg = 0xffffffff },
2430 [VOP2_WIN_COLOR_KEY] = { .reg = 0xffffffff },
2431 [VOP2_WIN_COLOR_KEY_EN] = { .reg = 0xffffffff },
2432 [VOP2_WIN_SCALE_CBCR_X] = { .reg = 0xffffffff },
2433 [VOP2_WIN_SCALE_CBCR_Y] = { .reg = 0xffffffff },
2434 [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = { .reg = 0xffffffff },
2435 [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = { .reg = 0xffffffff },
2436 [VOP2_WIN_CBCR_VER_SCL_MODE] = { .reg = 0xffffffff },
2437 [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = { .reg = 0xffffffff },
2438 [VOP2_WIN_CBCR_HOR_SCL_MODE] = { .reg = 0xffffffff },
2439 [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = { .reg = 0xffffffff },
2440 [VOP2_WIN_VSD_CBCR_GT2] = { .reg = 0xffffffff },
2441 [VOP2_WIN_VSD_CBCR_GT4] = { .reg = 0xffffffff },
2442 };
2443
2444 static int vop2_cluster_init(struct vop2_win *win)
2445 {
2446 struct vop2 *vop2 = win->vop2;
2447 struct reg_field *cluster_regs;
2448 int ret, i;
2449
2450 cluster_regs = kmemdup(vop2_cluster_regs, sizeof(vop2_cluster_regs),
2451 GFP_KERNEL);
2452 if (!cluster_regs)
2453 return -ENOMEM;
2454
2455 for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++)
2456 if (cluster_regs[i].reg != 0xffffffff)
2457 cluster_regs[i].reg += win->offset;
2458
2459 ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,
2460 cluster_regs,
2461 ARRAY_SIZE(vop2_cluster_regs));
2462
2463 kfree(cluster_regs);
2464
2465 return ret;
2466 };
2467
2468 static struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] = {
2469 [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0),
2470 [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5),
2471 [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12),
2472 [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 14, 14),
2473 [VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 16, 16),
2474 [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_SMART_REGION0_ACT_INFO, 0, 31),
2475 [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_SMART_REGION0_DSP_INFO, 0, 31),
2476 [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_SMART_REGION0_DSP_ST, 0, 28),
2477 [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_SMART_REGION0_YRGB_MST, 0, 31),
2478 [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_SMART_REGION0_CBR_MST, 0, 31),
2479 [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 17, 17),
2480 [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 0, 15),
2481 [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 16, 31),
2482 [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_SMART_CTRL0, 0, 0),
2483 [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_SMART_CTRL0, 1, 1),
2484 [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_SMART_CTRL0, 2, 3),
2485 [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_SMART_CTRL1, 31, 31),
2486 [VOP2_WIN_COLOR_KEY] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 0, 29),
2487 [VOP2_WIN_COLOR_KEY_EN] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 31, 31),
2488
2489
2490 [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0, 15),
2491 [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 16, 31),
2492 [VOP2_WIN_SCALE_CBCR_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0, 15),
2493 [VOP2_WIN_SCALE_CBCR_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 16, 31),
2494 [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 0, 1),
2495 [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 2, 3),
2496 [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 4, 5),
2497 [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 6, 7),
2498 [VOP2_WIN_CBCR_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 8, 9),
2499 [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 10, 11),
2500 [VOP2_WIN_CBCR_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 12, 13),
2501 [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 14, 15),
2502 [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 16, 17),
2503 [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 8, 8),
2504 [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 9, 9),
2505 [VOP2_WIN_VSD_CBCR_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 10, 10),
2506 [VOP2_WIN_VSD_CBCR_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 11, 11),
2507 [VOP2_WIN_XMIRROR] = { .reg = 0xffffffff },
2508 [VOP2_WIN_CLUSTER_ENABLE] = { .reg = 0xffffffff },
2509 [VOP2_WIN_AFBC_ENABLE] = { .reg = 0xffffffff },
2510 [VOP2_WIN_CLUSTER_LB_MODE] = { .reg = 0xffffffff },
2511 [VOP2_WIN_AFBC_FORMAT] = { .reg = 0xffffffff },
2512 [VOP2_WIN_AFBC_RB_SWAP] = { .reg = 0xffffffff },
2513 [VOP2_WIN_AFBC_UV_SWAP] = { .reg = 0xffffffff },
2514 [VOP2_WIN_AFBC_AUTO_GATING_EN] = { .reg = 0xffffffff },
2515 [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = { .reg = 0xffffffff },
2516 [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = { .reg = 0xffffffff },
2517 [VOP2_WIN_AFBC_TILE_NUM] = { .reg = 0xffffffff },
2518 [VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff },
2519 [VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff },
2520 [VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff },
2521 [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff },
2522 [VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff },
2523 [VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff },
2524 [VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff },
2525 [VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff },
2526 };
2527
2528 static int vop2_esmart_init(struct vop2_win *win)
2529 {
2530 struct vop2 *vop2 = win->vop2;
2531 struct reg_field *esmart_regs;
2532 int ret, i;
2533
2534 esmart_regs = kmemdup(vop2_esmart_regs, sizeof(vop2_esmart_regs),
2535 GFP_KERNEL);
2536 if (!esmart_regs)
2537 return -ENOMEM;
2538
2539 for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++)
2540 if (esmart_regs[i].reg != 0xffffffff)
2541 esmart_regs[i].reg += win->offset;
2542
2543 ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,
2544 esmart_regs,
2545 ARRAY_SIZE(vop2_esmart_regs));
2546
2547 kfree(esmart_regs);
2548
2549 return ret;
2550 };
2551
2552 static int vop2_win_init(struct vop2 *vop2)
2553 {
2554 const struct vop2_data *vop2_data = vop2->data;
2555 struct vop2_win *win;
2556 int i, ret;
2557
2558 for (i = 0; i < vop2_data->win_size; i++) {
2559 const struct vop2_win_data *win_data = &vop2_data->win[i];
2560
2561 win = &vop2->win[i];
2562 win->data = win_data;
2563 win->type = win_data->type;
2564 win->offset = win_data->base;
2565 win->win_id = i;
2566 win->vop2 = vop2;
2567 if (vop2_cluster_window(win))
2568 ret = vop2_cluster_init(win);
2569 else
2570 ret = vop2_esmart_init(win);
2571 if (ret)
2572 return ret;
2573 }
2574
2575 vop2->registered_num_wins = vop2_data->win_size;
2576
2577 return 0;
2578 }
2579
2580
2581
2582
2583
2584
2585
2586 static const struct regmap_range vop2_nonvolatile_range[] = {
2587 regmap_reg_range(0x1000, 0x23ff),
2588 };
2589
2590 static const struct regmap_access_table vop2_volatile_table = {
2591 .no_ranges = vop2_nonvolatile_range,
2592 .n_no_ranges = ARRAY_SIZE(vop2_nonvolatile_range),
2593 };
2594
2595 static const struct regmap_config vop2_regmap_config = {
2596 .reg_bits = 32,
2597 .val_bits = 32,
2598 .reg_stride = 4,
2599 .max_register = 0x3000,
2600 .name = "vop2",
2601 .volatile_table = &vop2_volatile_table,
2602 .cache_type = REGCACHE_RBTREE,
2603 };
2604
2605 static int vop2_bind(struct device *dev, struct device *master, void *data)
2606 {
2607 struct platform_device *pdev = to_platform_device(dev);
2608 const struct vop2_data *vop2_data;
2609 struct drm_device *drm = data;
2610 struct vop2 *vop2;
2611 struct resource *res;
2612 size_t alloc_size;
2613 int ret;
2614
2615 vop2_data = of_device_get_match_data(dev);
2616 if (!vop2_data)
2617 return -ENODEV;
2618
2619
2620 alloc_size = sizeof(*vop2) + sizeof(*vop2->win) * vop2_data->win_size;
2621 vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
2622 if (!vop2)
2623 return -ENOMEM;
2624
2625 vop2->dev = dev;
2626 vop2->data = vop2_data;
2627 vop2->drm = drm;
2628
2629 dev_set_drvdata(dev, vop2);
2630
2631 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vop");
2632 if (!res) {
2633 drm_err(vop2->drm, "failed to get vop2 register byname\n");
2634 return -EINVAL;
2635 }
2636
2637 vop2->regs = devm_ioremap_resource(dev, res);
2638 if (IS_ERR(vop2->regs))
2639 return PTR_ERR(vop2->regs);
2640 vop2->len = resource_size(res);
2641
2642 vop2->map = devm_regmap_init_mmio(dev, vop2->regs, &vop2_regmap_config);
2643
2644 ret = vop2_win_init(vop2);
2645 if (ret)
2646 return ret;
2647
2648 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma-lut");
2649 if (res) {
2650 vop2->lut_regs = devm_ioremap_resource(dev, res);
2651 if (IS_ERR(vop2->lut_regs))
2652 return PTR_ERR(vop2->lut_regs);
2653 }
2654
2655 vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
2656
2657 vop2->hclk = devm_clk_get(vop2->dev, "hclk");
2658 if (IS_ERR(vop2->hclk)) {
2659 drm_err(vop2->drm, "failed to get hclk source\n");
2660 return PTR_ERR(vop2->hclk);
2661 }
2662
2663 vop2->aclk = devm_clk_get(vop2->dev, "aclk");
2664 if (IS_ERR(vop2->aclk)) {
2665 drm_err(vop2->drm, "failed to get aclk source\n");
2666 return PTR_ERR(vop2->aclk);
2667 }
2668
2669 vop2->irq = platform_get_irq(pdev, 0);
2670 if (vop2->irq < 0) {
2671 drm_err(vop2->drm, "cannot find irq for vop2\n");
2672 return vop2->irq;
2673 }
2674
2675 mutex_init(&vop2->vop2_lock);
2676
2677 ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
2678 if (ret)
2679 return ret;
2680
2681 ret = vop2_create_crtc(vop2);
2682 if (ret)
2683 return ret;
2684
2685 rockchip_drm_dma_init_device(vop2->drm, vop2->dev);
2686
2687 pm_runtime_enable(&pdev->dev);
2688
2689 return 0;
2690 }
2691
2692 static void vop2_unbind(struct device *dev, struct device *master, void *data)
2693 {
2694 struct vop2 *vop2 = dev_get_drvdata(dev);
2695 struct drm_device *drm = vop2->drm;
2696 struct list_head *plane_list = &drm->mode_config.plane_list;
2697 struct list_head *crtc_list = &drm->mode_config.crtc_list;
2698 struct drm_crtc *crtc, *tmpc;
2699 struct drm_plane *plane, *tmpp;
2700
2701 pm_runtime_disable(dev);
2702
2703 list_for_each_entry_safe(plane, tmpp, plane_list, head)
2704 drm_plane_cleanup(plane);
2705
2706 list_for_each_entry_safe(crtc, tmpc, crtc_list, head)
2707 vop2_destroy_crtc(crtc);
2708 }
2709
2710 const struct component_ops vop2_component_ops = {
2711 .bind = vop2_bind,
2712 .unbind = vop2_unbind,
2713 };
2714 EXPORT_SYMBOL_GPL(vop2_component_ops);