Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/rockchip: Add VOP2 driver

The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568.
It replaces the VOP unit found in the older Rockchip SoCs.

This driver has been derived from the downstream Rockchip Kernel and
heavily modified:

- All nonstandard DRM properties have been removed
- dropped struct vop2_plane_state and pass around less data between
functions
- Dropped all DRM_FORMAT_* not known on upstream
- rework register access to get rid of excessively used macros
- Drop all waiting for framesyncs

The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB
board. Overlay support is tested with the modetest utility. AFBC support
on the cluster windows is tested with weston-simple-dmabuf-egl on
weston using the (yet to be upstreamed) panfrost driver support.

Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Co-Developed-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Tested-by: Michael Riesch <michael.riesch@wolfvision.net>
[dt-binding-header:]
Acked-by: Rob Herring <robh@kernel.org>
[moved dt-binding header from dt-nodes patch to here
and made checkpatch --strict happier]
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20220422072841.2206452-23-s.hauer@pengutronix.de

authored by

Andy Yan and committed by
Heiko Stuebner
604be855 b382406a

+3507 -1
+6
drivers/gpu/drm/rockchip/Kconfig
··· 29 29 This selects support for the VOP driver. You should enable it 30 30 on older SoCs. 31 31 32 + config ROCKCHIP_VOP2 33 + bool "Rockchip VOP2 driver" 34 + help 35 + This selects support for the VOP2 driver. The VOP2 hardware is 36 + first found on the RK3568. 37 + 32 38 config ROCKCHIP_ANALOGIX_DP 33 39 bool "Rockchip specific extensions for Analogix DP driver" 34 40 depends on ROCKCHIP_VOP
+1
drivers/gpu/drm/rockchip/Makefile
··· 6 6 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ 7 7 rockchip_drm_gem.o 8 8 9 + rockchipdrm-$(CONFIG_ROCKCHIP_VOP2) += rockchip_drm_vop2.o rockchip_vop2_reg.o 9 10 rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o 10 11 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o 11 12 rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
+1
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
··· 482 482 483 483 num_rockchip_sub_drivers = 0; 484 484 ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP); 485 + ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2); 485 486 ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, 486 487 CONFIG_ROCKCHIP_LVDS); 487 488 ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
+5 -1
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
··· 18 18 19 19 #define ROCKCHIP_MAX_FB_BUFFER 3 20 20 #define ROCKCHIP_MAX_CONNECTOR 2 21 - #define ROCKCHIP_MAX_CRTC 2 21 + #define ROCKCHIP_MAX_CRTC 4 22 22 23 23 struct drm_device; 24 24 struct drm_connector; ··· 31 31 int output_bpc; 32 32 int output_flags; 33 33 bool enable_afbc; 34 + u32 bus_format; 35 + u32 bus_flags; 36 + int color_space; 34 37 }; 35 38 #define to_rockchip_crtc_state(s) \ 36 39 container_of(s, struct rockchip_crtc_state, base) ··· 75 72 extern struct platform_driver rockchip_lvds_driver; 76 73 extern struct platform_driver vop_platform_driver; 77 74 extern struct platform_driver rk3066_hdmi_driver; 75 + extern struct platform_driver vop2_platform_driver; 78 76 79 77 static inline struct rockchip_encoder *to_rockchip_encoder(struct drm_encoder *encoder) 80 78 {
+2
drivers/gpu/drm/rockchip/rockchip_drm_fb.c
··· 134 134 135 135 dev->mode_config.funcs = &rockchip_drm_mode_config_funcs; 136 136 dev->mode_config.helper_private = &rockchip_mode_config_helpers; 137 + 138 + dev->mode_config.normalize_zpos = true; 137 139 }
+14
drivers/gpu/drm/rockchip/rockchip_drm_vop.h
··· 54 54 struct vop_reg enable; 55 55 struct vop_reg win_sel; 56 56 struct vop_reg format; 57 + struct vop_reg rb_swap; 58 + struct vop_reg uv_swap; 59 + struct vop_reg auto_gating_en; 60 + struct vop_reg block_split_en; 61 + struct vop_reg pic_vir_width; 62 + struct vop_reg tile_num; 57 63 struct vop_reg hreg_block_split; 64 + struct vop_reg pic_offset; 58 65 struct vop_reg pic_size; 66 + struct vop_reg dsp_offset; 67 + struct vop_reg transform_offset; 59 68 struct vop_reg hdr_ptr; 69 + struct vop_reg half_block_en; 70 + struct vop_reg xmirror; 71 + struct vop_reg ymirror; 72 + struct vop_reg rotate_270; 73 + struct vop_reg rotate_90; 60 74 struct vop_reg rstn; 61 75 }; 62 76
+2706
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0+ OR MIT) 2 + /* 3 + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. 4 + * Author: Andy Yan <andy.yan@rock-chips.com> 5 + */ 6 + #include <linux/bitfield.h> 7 + #include <linux/clk.h> 8 + #include <linux/component.h> 9 + #include <linux/delay.h> 10 + #include <linux/iopoll.h> 11 + #include <linux/kernel.h> 12 + #include <linux/mfd/syscon.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/of_device.h> 16 + #include <linux/of_graph.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/pm_runtime.h> 19 + #include <linux/regmap.h> 20 + #include <linux/swab.h> 21 + 22 + #include <drm/drm.h> 23 + #include <drm/drm_atomic.h> 24 + #include <drm/drm_atomic_uapi.h> 25 + #include <drm/drm_crtc.h> 26 + #include <drm/drm_crtc_helper.h> 27 + #include <drm/drm_debugfs.h> 28 + #include <drm/drm_flip_work.h> 29 + #include <drm/drm_plane_helper.h> 30 + #include <drm/drm_probe_helper.h> 31 + #include <drm/drm_vblank.h> 32 + 33 + #include <uapi/linux/videodev2.h> 34 + #include <dt-bindings/soc/rockchip,vop2.h> 35 + 36 + #include "rockchip_drm_drv.h" 37 + #include "rockchip_drm_gem.h" 38 + #include "rockchip_drm_fb.h" 39 + #include "rockchip_drm_vop2.h" 40 + 41 + /* 42 + * VOP2 architecture 43 + * 44 + +----------+ +-------------+ +-----------+ 45 + | Cluster | | Sel 1 from 6| | 1 from 3 | 46 + | window0 | | Layer0 | | RGB | 47 + +----------+ +-------------+ +---------------+ +-------------+ +-----------+ 48 + +----------+ +-------------+ |N from 6 layers| | | 49 + | Cluster | | Sel 1 from 6| | Overlay0 +--->| Video Port0 | +-----------+ 50 + | window1 | | Layer1 | | | | | | 1 from 3 | 51 + +----------+ +-------------+ +---------------+ +-------------+ | LVDS | 52 + +----------+ +-------------+ +-----------+ 53 + | Esmart | | Sel 1 from 6| 54 + | window0 | | Layer2 | +---------------+ +-------------+ +-----------+ 55 + +----------+ +-------------+ |N from 6 Layers| | | +--> | 1 from 3 | 56 + +----------+ +-------------+ --------> | Overlay1 +--->| Video Port1 | | MIPI | 57 + | Esmart | | Sel 1 from 6| --------> | | | | +-----------+ 58 + | Window1 | | Layer3 | +---------------+ +-------------+ 59 + +----------+ +-------------+ +-----------+ 60 + +----------+ +-------------+ | 1 from 3 | 61 + | Smart | | Sel 1 from 6| +---------------+ +-------------+ | HDMI | 62 + | Window0 | | Layer4 | |N from 6 Layers| | | +-----------+ 63 + +----------+ +-------------+ | Overlay2 +--->| Video Port2 | 64 + +----------+ +-------------+ | | | | +-----------+ 65 + | Smart | | Sel 1 from 6| +---------------+ +-------------+ | 1 from 3 | 66 + | Window1 | | Layer5 | | eDP | 67 + +----------+ +-------------+ +-----------+ 68 + * 69 + */ 70 + 71 + enum vop2_data_format { 72 + VOP2_FMT_ARGB8888 = 0, 73 + VOP2_FMT_RGB888, 74 + VOP2_FMT_RGB565, 75 + VOP2_FMT_XRGB101010, 76 + VOP2_FMT_YUV420SP, 77 + VOP2_FMT_YUV422SP, 78 + VOP2_FMT_YUV444SP, 79 + VOP2_FMT_YUYV422 = 8, 80 + VOP2_FMT_YUYV420, 81 + VOP2_FMT_VYUY422, 82 + VOP2_FMT_VYUY420, 83 + VOP2_FMT_YUV420SP_TILE_8x4 = 0x10, 84 + VOP2_FMT_YUV420SP_TILE_16x2, 85 + VOP2_FMT_YUV422SP_TILE_8x4, 86 + VOP2_FMT_YUV422SP_TILE_16x2, 87 + VOP2_FMT_YUV420SP_10, 88 + VOP2_FMT_YUV422SP_10, 89 + VOP2_FMT_YUV444SP_10, 90 + }; 91 + 92 + enum vop2_afbc_format { 93 + VOP2_AFBC_FMT_RGB565, 94 + VOP2_AFBC_FMT_ARGB2101010 = 2, 95 + VOP2_AFBC_FMT_YUV420_10BIT, 96 + VOP2_AFBC_FMT_RGB888, 97 + VOP2_AFBC_FMT_ARGB8888, 98 + VOP2_AFBC_FMT_YUV420 = 9, 99 + VOP2_AFBC_FMT_YUV422 = 0xb, 100 + VOP2_AFBC_FMT_YUV422_10BIT = 0xe, 101 + VOP2_AFBC_FMT_INVALID = -1, 102 + }; 103 + 104 + union vop2_alpha_ctrl { 105 + u32 val; 106 + struct { 107 + /* [0:1] */ 108 + u32 color_mode:1; 109 + u32 alpha_mode:1; 110 + /* [2:3] */ 111 + u32 blend_mode:2; 112 + u32 alpha_cal_mode:1; 113 + /* [5:7] */ 114 + u32 factor_mode:3; 115 + /* [8:9] */ 116 + u32 alpha_en:1; 117 + u32 src_dst_swap:1; 118 + u32 reserved:6; 119 + /* [16:23] */ 120 + u32 glb_alpha:8; 121 + } bits; 122 + }; 123 + 124 + struct vop2_alpha { 125 + union vop2_alpha_ctrl src_color_ctrl; 126 + union vop2_alpha_ctrl dst_color_ctrl; 127 + union vop2_alpha_ctrl src_alpha_ctrl; 128 + union vop2_alpha_ctrl dst_alpha_ctrl; 129 + }; 130 + 131 + struct vop2_alpha_config { 132 + bool src_premulti_en; 133 + bool dst_premulti_en; 134 + bool src_pixel_alpha_en; 135 + bool dst_pixel_alpha_en; 136 + u16 src_glb_alpha_value; 137 + u16 dst_glb_alpha_value; 138 + }; 139 + 140 + struct vop2_win { 141 + struct vop2 *vop2; 142 + struct drm_plane base; 143 + const struct vop2_win_data *data; 144 + struct regmap_field *reg[VOP2_WIN_MAX_REG]; 145 + 146 + /** 147 + * @win_id: graphic window id, a cluster may be split into two 148 + * graphics windows. 149 + */ 150 + u8 win_id; 151 + u8 delay; 152 + u32 offset; 153 + 154 + enum drm_plane_type type; 155 + }; 156 + 157 + struct vop2_video_port { 158 + struct drm_crtc crtc; 159 + struct vop2 *vop2; 160 + struct clk *dclk; 161 + unsigned int id; 162 + const struct vop2_video_port_regs *regs; 163 + const struct vop2_video_port_data *data; 164 + 165 + struct completion dsp_hold_completion; 166 + 167 + /** 168 + * @win_mask: Bitmask of windows attached to the video port; 169 + */ 170 + u32 win_mask; 171 + 172 + struct vop2_win *primary_plane; 173 + struct drm_pending_vblank_event *event; 174 + 175 + unsigned int nlayers; 176 + }; 177 + 178 + struct vop2 { 179 + struct device *dev; 180 + struct drm_device *drm; 181 + struct vop2_video_port vps[ROCKCHIP_MAX_CRTC]; 182 + 183 + const struct vop2_data *data; 184 + /* 185 + * Number of windows that are registered as plane, may be less than the 186 + * total number of hardware windows. 187 + */ 188 + u32 registered_num_wins; 189 + 190 + void __iomem *regs; 191 + struct regmap *map; 192 + 193 + struct regmap *grf; 194 + 195 + /* physical map length of vop2 register */ 196 + u32 len; 197 + 198 + void __iomem *lut_regs; 199 + 200 + /* protects crtc enable/disable */ 201 + struct mutex vop2_lock; 202 + 203 + int irq; 204 + 205 + /* 206 + * Some global resources are shared between all video ports(crtcs), so 207 + * we need a ref counter here. 208 + */ 209 + unsigned int enable_count; 210 + struct clk *hclk; 211 + struct clk *aclk; 212 + 213 + /* must be put at the end of the struct */ 214 + struct vop2_win win[]; 215 + }; 216 + 217 + static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc) 218 + { 219 + return container_of(crtc, struct vop2_video_port, crtc); 220 + } 221 + 222 + static struct vop2_win *to_vop2_win(struct drm_plane *p) 223 + { 224 + return container_of(p, struct vop2_win, base); 225 + } 226 + 227 + static void vop2_lock(struct vop2 *vop2) 228 + { 229 + mutex_lock(&vop2->vop2_lock); 230 + } 231 + 232 + static void vop2_unlock(struct vop2 *vop2) 233 + { 234 + mutex_unlock(&vop2->vop2_lock); 235 + } 236 + 237 + static void vop2_writel(struct vop2 *vop2, u32 offset, u32 v) 238 + { 239 + regmap_write(vop2->map, offset, v); 240 + } 241 + 242 + static void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v) 243 + { 244 + regmap_write(vp->vop2->map, vp->data->offset + offset, v); 245 + } 246 + 247 + static u32 vop2_readl(struct vop2 *vop2, u32 offset) 248 + { 249 + u32 val; 250 + 251 + regmap_read(vop2->map, offset, &val); 252 + 253 + return val; 254 + } 255 + 256 + static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v) 257 + { 258 + regmap_field_write(win->reg[reg], v); 259 + } 260 + 261 + static bool vop2_cluster_window(const struct vop2_win *win) 262 + { 263 + return win->data->feature & WIN_FEATURE_CLUSTER; 264 + } 265 + 266 + static void vop2_cfg_done(struct vop2_video_port *vp) 267 + { 268 + struct vop2 *vop2 = vp->vop2; 269 + 270 + regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, 271 + BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); 272 + } 273 + 274 + static void vop2_win_disable(struct vop2_win *win) 275 + { 276 + vop2_win_write(win, VOP2_WIN_ENABLE, 0); 277 + 278 + if (vop2_cluster_window(win)) 279 + vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 0); 280 + } 281 + 282 + static enum vop2_data_format vop2_convert_format(u32 format) 283 + { 284 + switch (format) { 285 + case DRM_FORMAT_XRGB8888: 286 + case DRM_FORMAT_ARGB8888: 287 + case DRM_FORMAT_XBGR8888: 288 + case DRM_FORMAT_ABGR8888: 289 + return VOP2_FMT_ARGB8888; 290 + case DRM_FORMAT_RGB888: 291 + case DRM_FORMAT_BGR888: 292 + return VOP2_FMT_RGB888; 293 + case DRM_FORMAT_RGB565: 294 + case DRM_FORMAT_BGR565: 295 + return VOP2_FMT_RGB565; 296 + case DRM_FORMAT_NV12: 297 + return VOP2_FMT_YUV420SP; 298 + case DRM_FORMAT_NV16: 299 + return VOP2_FMT_YUV422SP; 300 + case DRM_FORMAT_NV24: 301 + return VOP2_FMT_YUV444SP; 302 + case DRM_FORMAT_YUYV: 303 + case DRM_FORMAT_YVYU: 304 + return VOP2_FMT_VYUY422; 305 + case DRM_FORMAT_VYUY: 306 + case DRM_FORMAT_UYVY: 307 + return VOP2_FMT_YUYV422; 308 + default: 309 + DRM_ERROR("unsupported format[%08x]\n", format); 310 + return -EINVAL; 311 + } 312 + } 313 + 314 + static enum vop2_afbc_format vop2_convert_afbc_format(u32 format) 315 + { 316 + switch (format) { 317 + case DRM_FORMAT_XRGB8888: 318 + case DRM_FORMAT_ARGB8888: 319 + case DRM_FORMAT_XBGR8888: 320 + case DRM_FORMAT_ABGR8888: 321 + return VOP2_AFBC_FMT_ARGB8888; 322 + case DRM_FORMAT_RGB888: 323 + case DRM_FORMAT_BGR888: 324 + return VOP2_AFBC_FMT_RGB888; 325 + case DRM_FORMAT_RGB565: 326 + case DRM_FORMAT_BGR565: 327 + return VOP2_AFBC_FMT_RGB565; 328 + case DRM_FORMAT_NV12: 329 + return VOP2_AFBC_FMT_YUV420; 330 + case DRM_FORMAT_NV16: 331 + return VOP2_AFBC_FMT_YUV422; 332 + default: 333 + return VOP2_AFBC_FMT_INVALID; 334 + } 335 + 336 + return VOP2_AFBC_FMT_INVALID; 337 + } 338 + 339 + static bool vop2_win_rb_swap(u32 format) 340 + { 341 + switch (format) { 342 + case DRM_FORMAT_XBGR8888: 343 + case DRM_FORMAT_ABGR8888: 344 + case DRM_FORMAT_BGR888: 345 + case DRM_FORMAT_BGR565: 346 + return true; 347 + default: 348 + return false; 349 + } 350 + } 351 + 352 + static bool vop2_afbc_rb_swap(u32 format) 353 + { 354 + switch (format) { 355 + case DRM_FORMAT_NV24: 356 + return true; 357 + default: 358 + return false; 359 + } 360 + } 361 + 362 + static bool vop2_afbc_uv_swap(u32 format) 363 + { 364 + switch (format) { 365 + case DRM_FORMAT_NV12: 366 + case DRM_FORMAT_NV16: 367 + return true; 368 + default: 369 + return false; 370 + } 371 + } 372 + 373 + static bool vop2_win_uv_swap(u32 format) 374 + { 375 + switch (format) { 376 + case DRM_FORMAT_NV12: 377 + case DRM_FORMAT_NV16: 378 + case DRM_FORMAT_NV24: 379 + return true; 380 + default: 381 + return false; 382 + } 383 + } 384 + 385 + static bool vop2_win_dither_up(u32 format) 386 + { 387 + switch (format) { 388 + case DRM_FORMAT_BGR565: 389 + case DRM_FORMAT_RGB565: 390 + return true; 391 + default: 392 + return false; 393 + } 394 + } 395 + 396 + static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode) 397 + { 398 + /* 399 + * FIXME: 400 + * 401 + * There is no media type for YUV444 output, 402 + * so when out_mode is AAAA or P888, assume output is YUV444 on 403 + * yuv format. 404 + * 405 + * From H/W testing, YUV444 mode need a rb swap. 406 + */ 407 + if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 || 408 + bus_format == MEDIA_BUS_FMT_VYUY8_1X16 || 409 + bus_format == MEDIA_BUS_FMT_YVYU8_2X8 || 410 + bus_format == MEDIA_BUS_FMT_VYUY8_2X8 || 411 + ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 || 412 + bus_format == MEDIA_BUS_FMT_YUV10_1X30) && 413 + (output_mode == ROCKCHIP_OUT_MODE_AAAA || 414 + output_mode == ROCKCHIP_OUT_MODE_P888))) 415 + return true; 416 + else 417 + return false; 418 + } 419 + 420 + static bool is_yuv_output(u32 bus_format) 421 + { 422 + switch (bus_format) { 423 + case MEDIA_BUS_FMT_YUV8_1X24: 424 + case MEDIA_BUS_FMT_YUV10_1X30: 425 + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: 426 + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: 427 + case MEDIA_BUS_FMT_YUYV8_2X8: 428 + case MEDIA_BUS_FMT_YVYU8_2X8: 429 + case MEDIA_BUS_FMT_UYVY8_2X8: 430 + case MEDIA_BUS_FMT_VYUY8_2X8: 431 + case MEDIA_BUS_FMT_YUYV8_1X16: 432 + case MEDIA_BUS_FMT_YVYU8_1X16: 433 + case MEDIA_BUS_FMT_UYVY8_1X16: 434 + case MEDIA_BUS_FMT_VYUY8_1X16: 435 + return true; 436 + default: 437 + return false; 438 + } 439 + } 440 + 441 + static bool rockchip_afbc(struct drm_plane *plane, u64 modifier) 442 + { 443 + int i; 444 + 445 + if (modifier == DRM_FORMAT_MOD_LINEAR) 446 + return false; 447 + 448 + for (i = 0 ; i < plane->modifier_count; i++) 449 + if (plane->modifiers[i] == modifier) 450 + return true; 451 + 452 + return false; 453 + } 454 + 455 + static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, 456 + u64 modifier) 457 + { 458 + struct vop2_win *win = to_vop2_win(plane); 459 + struct vop2 *vop2 = win->vop2; 460 + 461 + if (modifier == DRM_FORMAT_MOD_INVALID) 462 + return false; 463 + 464 + if (modifier == DRM_FORMAT_MOD_LINEAR) 465 + return true; 466 + 467 + if (!rockchip_afbc(plane, modifier)) { 468 + drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n", 469 + modifier); 470 + 471 + return false; 472 + } 473 + 474 + return vop2_convert_afbc_format(format) >= 0; 475 + } 476 + 477 + static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate, 478 + bool afbc_half_block_en) 479 + { 480 + struct drm_rect *src = &pstate->src; 481 + struct drm_framebuffer *fb = pstate->fb; 482 + u32 bpp = fb->format->cpp[0] * 8; 483 + u32 vir_width = (fb->pitches[0] << 3) / bpp; 484 + u32 width = drm_rect_width(src) >> 16; 485 + u32 height = drm_rect_height(src) >> 16; 486 + u32 act_xoffset = src->x1 >> 16; 487 + u32 act_yoffset = src->y1 >> 16; 488 + u32 align16_crop = 0; 489 + u32 align64_crop = 0; 490 + u32 height_tmp; 491 + u8 tx, ty; 492 + u8 bottom_crop_line_num = 0; 493 + 494 + /* 16 pixel align */ 495 + if (height & 0xf) 496 + align16_crop = 16 - (height & 0xf); 497 + 498 + height_tmp = height + align16_crop; 499 + 500 + /* 64 pixel align */ 501 + if (height_tmp & 0x3f) 502 + align64_crop = 64 - (height_tmp & 0x3f); 503 + 504 + bottom_crop_line_num = align16_crop + align64_crop; 505 + 506 + switch (pstate->rotation & 507 + (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | 508 + DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) { 509 + case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y: 510 + tx = 16 - ((act_xoffset + width) & 0xf); 511 + ty = bottom_crop_line_num - act_yoffset; 512 + break; 513 + case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90: 514 + tx = bottom_crop_line_num - act_yoffset; 515 + ty = vir_width - width - act_xoffset; 516 + break; 517 + case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270: 518 + tx = act_yoffset; 519 + ty = act_xoffset; 520 + break; 521 + case DRM_MODE_REFLECT_X: 522 + tx = 16 - ((act_xoffset + width) & 0xf); 523 + ty = act_yoffset; 524 + break; 525 + case DRM_MODE_REFLECT_Y: 526 + tx = act_xoffset; 527 + ty = bottom_crop_line_num - act_yoffset; 528 + break; 529 + case DRM_MODE_ROTATE_90: 530 + tx = bottom_crop_line_num - act_yoffset; 531 + ty = act_xoffset; 532 + break; 533 + case DRM_MODE_ROTATE_270: 534 + tx = act_yoffset; 535 + ty = vir_width - width - act_xoffset; 536 + break; 537 + case 0: 538 + tx = act_xoffset; 539 + ty = act_yoffset; 540 + break; 541 + } 542 + 543 + if (afbc_half_block_en) 544 + ty &= 0x7f; 545 + 546 + #define TRANSFORM_XOFFSET GENMASK(7, 0) 547 + #define TRANSFORM_YOFFSET GENMASK(23, 16) 548 + return FIELD_PREP(TRANSFORM_XOFFSET, tx) | 549 + FIELD_PREP(TRANSFORM_YOFFSET, ty); 550 + } 551 + 552 + /* 553 + * A Cluster window has 2048 x 16 line buffer, which can 554 + * works at 2048 x 16(Full) or 4096 x 8 (Half) mode. 555 + * for Cluster_lb_mode register: 556 + * 0: half mode, for plane input width range 2048 ~ 4096 557 + * 1: half mode, for cluster work at 2 * 2048 plane mode 558 + * 2: half mode, for rotate_90/270 mode 559 + * 560 + */ 561 + static int vop2_get_cluster_lb_mode(struct vop2_win *win, 562 + struct drm_plane_state *pstate) 563 + { 564 + if ((pstate->rotation & DRM_MODE_ROTATE_270) || 565 + (pstate->rotation & DRM_MODE_ROTATE_90)) 566 + return 2; 567 + else 568 + return 0; 569 + } 570 + 571 + static u16 vop2_scale_factor(u32 src, u32 dst) 572 + { 573 + u32 fac; 574 + int shift; 575 + 576 + if (src == dst) 577 + return 0; 578 + 579 + if (dst < 2) 580 + return U16_MAX; 581 + 582 + if (src < 2) 583 + return 0; 584 + 585 + if (src > dst) 586 + shift = 12; 587 + else 588 + shift = 16; 589 + 590 + src--; 591 + dst--; 592 + 593 + fac = DIV_ROUND_UP(src << shift, dst) - 1; 594 + 595 + if (fac > U16_MAX) 596 + return U16_MAX; 597 + 598 + return fac; 599 + } 600 + 601 + static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, 602 + u32 src_w, u32 src_h, u32 dst_w, 603 + u32 dst_h, u32 pixel_format) 604 + { 605 + const struct drm_format_info *info; 606 + u16 hor_scl_mode, ver_scl_mode; 607 + u16 hscl_filter_mode, vscl_filter_mode; 608 + u8 gt2 = 0; 609 + u8 gt4 = 0; 610 + u32 val; 611 + 612 + info = drm_format_info(pixel_format); 613 + 614 + if (src_h >= (4 * dst_h)) { 615 + gt4 = 1; 616 + src_h >>= 2; 617 + } else if (src_h >= (2 * dst_h)) { 618 + gt2 = 1; 619 + src_h >>= 1; 620 + } 621 + 622 + hor_scl_mode = scl_get_scl_mode(src_w, dst_w); 623 + ver_scl_mode = scl_get_scl_mode(src_h, dst_h); 624 + 625 + if (hor_scl_mode == SCALE_UP) 626 + hscl_filter_mode = VOP2_SCALE_UP_BIC; 627 + else 628 + hscl_filter_mode = VOP2_SCALE_DOWN_BIL; 629 + 630 + if (ver_scl_mode == SCALE_UP) 631 + vscl_filter_mode = VOP2_SCALE_UP_BIL; 632 + else 633 + vscl_filter_mode = VOP2_SCALE_DOWN_BIL; 634 + 635 + /* 636 + * RK3568 VOP Esmart/Smart dsp_w should be even pixel 637 + * at scale down mode 638 + */ 639 + if (!(win->data->feature & WIN_FEATURE_AFBDC)) { 640 + if ((hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) { 641 + drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n", 642 + win->data->name, dst_w); 643 + dst_w++; 644 + } 645 + } 646 + 647 + val = vop2_scale_factor(src_w, dst_w); 648 + vop2_win_write(win, VOP2_WIN_SCALE_YRGB_X, val); 649 + val = vop2_scale_factor(src_h, dst_h); 650 + vop2_win_write(win, VOP2_WIN_SCALE_YRGB_Y, val); 651 + 652 + vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT4, gt4); 653 + vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT2, gt2); 654 + 655 + vop2_win_write(win, VOP2_WIN_YRGB_HOR_SCL_MODE, hor_scl_mode); 656 + vop2_win_write(win, VOP2_WIN_YRGB_VER_SCL_MODE, ver_scl_mode); 657 + 658 + if (vop2_cluster_window(win)) 659 + return; 660 + 661 + vop2_win_write(win, VOP2_WIN_YRGB_HSCL_FILTER_MODE, hscl_filter_mode); 662 + vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode); 663 + 664 + if (info->is_yuv) { 665 + src_w /= info->hsub; 666 + src_h /= info->vsub; 667 + 668 + gt4 = 0; 669 + gt2 = 0; 670 + 671 + if (src_h >= (4 * dst_h)) { 672 + gt4 = 1; 673 + src_h >>= 2; 674 + } else if (src_h >= (2 * dst_h)) { 675 + gt2 = 1; 676 + src_h >>= 1; 677 + } 678 + 679 + hor_scl_mode = scl_get_scl_mode(src_w, dst_w); 680 + ver_scl_mode = scl_get_scl_mode(src_h, dst_h); 681 + 682 + val = vop2_scale_factor(src_w, dst_w); 683 + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val); 684 + 685 + val = vop2_scale_factor(src_h, dst_h); 686 + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val); 687 + 688 + vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4); 689 + vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT2, gt2); 690 + vop2_win_write(win, VOP2_WIN_CBCR_HOR_SCL_MODE, hor_scl_mode); 691 + vop2_win_write(win, VOP2_WIN_CBCR_VER_SCL_MODE, ver_scl_mode); 692 + vop2_win_write(win, VOP2_WIN_CBCR_HSCL_FILTER_MODE, hscl_filter_mode); 693 + vop2_win_write(win, VOP2_WIN_CBCR_VSCL_FILTER_MODE, vscl_filter_mode); 694 + } 695 + } 696 + 697 + static int vop2_convert_csc_mode(int csc_mode) 698 + { 699 + switch (csc_mode) { 700 + case V4L2_COLORSPACE_SMPTE170M: 701 + case V4L2_COLORSPACE_470_SYSTEM_M: 702 + case V4L2_COLORSPACE_470_SYSTEM_BG: 703 + return CSC_BT601L; 704 + case V4L2_COLORSPACE_REC709: 705 + case V4L2_COLORSPACE_SMPTE240M: 706 + case V4L2_COLORSPACE_DEFAULT: 707 + return CSC_BT709L; 708 + case V4L2_COLORSPACE_JPEG: 709 + return CSC_BT601F; 710 + case V4L2_COLORSPACE_BT2020: 711 + return CSC_BT2020; 712 + default: 713 + return CSC_BT709L; 714 + } 715 + } 716 + 717 + /* 718 + * colorspace path: 719 + * Input Win csc Output 720 + * 1. YUV(2020) --> Y2R->2020To709->R2Y --> YUV_OUTPUT(601/709) 721 + * RGB --> R2Y __/ 722 + * 723 + * 2. YUV(2020) --> bypasss --> YUV_OUTPUT(2020) 724 + * RGB --> 709To2020->R2Y __/ 725 + * 726 + * 3. YUV(2020) --> Y2R->2020To709 --> RGB_OUTPUT(709) 727 + * RGB --> R2Y __/ 728 + * 729 + * 4. YUV(601/709)-> Y2R->709To2020->R2Y --> YUV_OUTPUT(2020) 730 + * RGB --> 709To2020->R2Y __/ 731 + * 732 + * 5. YUV(601/709)-> bypass --> YUV_OUTPUT(709) 733 + * RGB --> R2Y __/ 734 + * 735 + * 6. YUV(601/709)-> bypass --> YUV_OUTPUT(601) 736 + * RGB --> R2Y(601) __/ 737 + * 738 + * 7. YUV --> Y2R(709) --> RGB_OUTPUT(709) 739 + * RGB --> bypass __/ 740 + * 741 + * 8. RGB --> 709To2020->R2Y --> YUV_OUTPUT(2020) 742 + * 743 + * 9. RGB --> R2Y(709) --> YUV_OUTPUT(709) 744 + * 745 + * 10. RGB --> R2Y(601) --> YUV_OUTPUT(601) 746 + * 747 + * 11. RGB --> bypass --> RGB_OUTPUT(709) 748 + */ 749 + 750 + static void vop2_setup_csc_mode(struct vop2_video_port *vp, 751 + struct vop2_win *win, 752 + struct drm_plane_state *pstate) 753 + { 754 + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); 755 + int is_input_yuv = pstate->fb->format->is_yuv; 756 + int is_output_yuv = is_yuv_output(vcstate->bus_format); 757 + int input_csc = V4L2_COLORSPACE_DEFAULT; 758 + int output_csc = vcstate->color_space; 759 + bool r2y_en, y2r_en; 760 + int csc_mode; 761 + 762 + if (is_input_yuv && !is_output_yuv) { 763 + y2r_en = true; 764 + r2y_en = false; 765 + csc_mode = vop2_convert_csc_mode(input_csc); 766 + } else if (!is_input_yuv && is_output_yuv) { 767 + y2r_en = false; 768 + r2y_en = true; 769 + csc_mode = vop2_convert_csc_mode(output_csc); 770 + } else { 771 + y2r_en = false; 772 + r2y_en = false; 773 + csc_mode = false; 774 + } 775 + 776 + vop2_win_write(win, VOP2_WIN_Y2R_EN, y2r_en); 777 + vop2_win_write(win, VOP2_WIN_R2Y_EN, r2y_en); 778 + vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode); 779 + } 780 + 781 + static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq) 782 + { 783 + struct vop2 *vop2 = vp->vop2; 784 + 785 + vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irq << 16 | irq); 786 + vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16 | irq); 787 + } 788 + 789 + static void vop2_crtc_disable_irq(struct vop2_video_port *vp, u32 irq) 790 + { 791 + struct vop2 *vop2 = vp->vop2; 792 + 793 + vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16); 794 + } 795 + 796 + static int vop2_core_clks_prepare_enable(struct vop2 *vop2) 797 + { 798 + int ret; 799 + 800 + ret = clk_prepare_enable(vop2->hclk); 801 + if (ret < 0) { 802 + drm_err(vop2->drm, "failed to enable hclk - %d\n", ret); 803 + return ret; 804 + } 805 + 806 + ret = clk_prepare_enable(vop2->aclk); 807 + if (ret < 0) { 808 + drm_err(vop2->drm, "failed to enable aclk - %d\n", ret); 809 + goto err; 810 + } 811 + 812 + return 0; 813 + err: 814 + clk_disable_unprepare(vop2->hclk); 815 + 816 + return ret; 817 + } 818 + 819 + static void vop2_enable(struct vop2 *vop2) 820 + { 821 + int ret; 822 + 823 + ret = pm_runtime_get_sync(vop2->dev); 824 + if (ret < 0) { 825 + drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret); 826 + return; 827 + } 828 + 829 + ret = vop2_core_clks_prepare_enable(vop2); 830 + if (ret) { 831 + pm_runtime_put_sync(vop2->dev); 832 + return; 833 + } 834 + 835 + ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev); 836 + if (ret) { 837 + drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret); 838 + return; 839 + } 840 + 841 + if (vop2->data->soc_id == 3566) 842 + vop2_writel(vop2, RK3568_OTP_WIN_EN, 1); 843 + 844 + vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); 845 + 846 + /* 847 + * Disable auto gating, this is a workaround to 848 + * avoid display image shift when a window enabled. 849 + */ 850 + regmap_clear_bits(vop2->map, RK3568_SYS_AUTO_GATING_CTRL, 851 + RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN); 852 + 853 + vop2_writel(vop2, RK3568_SYS0_INT_CLR, 854 + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 855 + vop2_writel(vop2, RK3568_SYS0_INT_EN, 856 + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 857 + vop2_writel(vop2, RK3568_SYS1_INT_CLR, 858 + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 859 + vop2_writel(vop2, RK3568_SYS1_INT_EN, 860 + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 861 + } 862 + 863 + static void vop2_disable(struct vop2 *vop2) 864 + { 865 + rockchip_drm_dma_detach_device(vop2->drm, vop2->dev); 866 + 867 + pm_runtime_put_sync(vop2->dev); 868 + 869 + clk_disable_unprepare(vop2->aclk); 870 + clk_disable_unprepare(vop2->hclk); 871 + } 872 + 873 + static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, 874 + struct drm_atomic_state *state) 875 + { 876 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 877 + struct vop2 *vop2 = vp->vop2; 878 + int ret; 879 + 880 + vop2_lock(vop2); 881 + 882 + drm_crtc_vblank_off(crtc); 883 + 884 + /* 885 + * Vop standby will take effect at end of current frame, 886 + * if dsp hold valid irq happen, it means standby complete. 887 + * 888 + * we must wait standby complete when we want to disable aclk, 889 + * if not, memory bus maybe dead. 890 + */ 891 + reinit_completion(&vp->dsp_hold_completion); 892 + 893 + vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID); 894 + 895 + vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY); 896 + 897 + ret = wait_for_completion_timeout(&vp->dsp_hold_completion, 898 + msecs_to_jiffies(50)); 899 + if (!ret) 900 + drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id); 901 + 902 + vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID); 903 + 904 + clk_disable_unprepare(vp->dclk); 905 + 906 + vop2->enable_count--; 907 + 908 + if (!vop2->enable_count) 909 + vop2_disable(vop2); 910 + 911 + vop2_unlock(vop2); 912 + 913 + if (crtc->state->event && !crtc->state->active) { 914 + spin_lock_irq(&crtc->dev->event_lock); 915 + drm_crtc_send_vblank_event(crtc, crtc->state->event); 916 + spin_unlock_irq(&crtc->dev->event_lock); 917 + 918 + crtc->state->event = NULL; 919 + } 920 + } 921 + 922 + static int vop2_plane_atomic_check(struct drm_plane *plane, 923 + struct drm_atomic_state *astate) 924 + { 925 + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane); 926 + struct drm_framebuffer *fb = pstate->fb; 927 + struct drm_crtc *crtc = pstate->crtc; 928 + struct drm_crtc_state *cstate; 929 + struct vop2_video_port *vp; 930 + struct vop2 *vop2; 931 + const struct vop2_data *vop2_data; 932 + struct drm_rect *dest = &pstate->dst; 933 + struct drm_rect *src = &pstate->src; 934 + int min_scale = FRAC_16_16(1, 8); 935 + int max_scale = FRAC_16_16(8, 1); 936 + int format; 937 + int ret; 938 + 939 + if (!crtc) 940 + return 0; 941 + 942 + vp = to_vop2_video_port(crtc); 943 + vop2 = vp->vop2; 944 + vop2_data = vop2->data; 945 + 946 + cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc); 947 + if (WARN_ON(!cstate)) 948 + return -EINVAL; 949 + 950 + ret = drm_atomic_helper_check_plane_state(pstate, cstate, 951 + min_scale, max_scale, 952 + true, true); 953 + if (ret) 954 + return ret; 955 + 956 + if (!pstate->visible) 957 + return 0; 958 + 959 + format = vop2_convert_format(fb->format->format); 960 + if (format < 0) 961 + return format; 962 + 963 + if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 || 964 + drm_rect_width(dest) < 4 || drm_rect_width(dest) < 4) { 965 + drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n", 966 + drm_rect_width(src) >> 16, drm_rect_height(src) >> 16, 967 + drm_rect_width(dest), drm_rect_height(dest)); 968 + pstate->visible = false; 969 + return 0; 970 + } 971 + 972 + if (drm_rect_width(src) >> 16 > vop2_data->max_input.width || 973 + drm_rect_height(src) >> 16 > vop2_data->max_input.height) { 974 + drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n", 975 + drm_rect_width(src) >> 16, 976 + drm_rect_height(src) >> 16, 977 + vop2_data->max_input.width, 978 + vop2_data->max_input.height); 979 + return -EINVAL; 980 + } 981 + 982 + /* 983 + * Src.x1 can be odd when do clip, but yuv plane start point 984 + * need align with 2 pixel. 985 + */ 986 + if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) { 987 + drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n"); 988 + return -EINVAL; 989 + } 990 + 991 + return 0; 992 + } 993 + 994 + static void vop2_plane_atomic_disable(struct drm_plane *plane, 995 + struct drm_atomic_state *state) 996 + { 997 + struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state, plane); 998 + struct vop2_win *win = to_vop2_win(plane); 999 + struct vop2 *vop2 = win->vop2; 1000 + 1001 + drm_dbg(vop2->drm, "%s disable\n", win->data->name); 1002 + 1003 + if (!old_pstate->crtc) 1004 + return; 1005 + 1006 + vop2_win_disable(win); 1007 + vop2_win_write(win, VOP2_WIN_YUV_CLIP, 0); 1008 + } 1009 + 1010 + /* 1011 + * The color key is 10 bit, so all format should 1012 + * convert to 10 bit here. 1013 + */ 1014 + static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key) 1015 + { 1016 + struct drm_plane_state *pstate = plane->state; 1017 + struct drm_framebuffer *fb = pstate->fb; 1018 + struct vop2_win *win = to_vop2_win(plane); 1019 + u32 color_key_en = 0; 1020 + u32 r = 0; 1021 + u32 g = 0; 1022 + u32 b = 0; 1023 + 1024 + if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) { 1025 + vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, 0); 1026 + return; 1027 + } 1028 + 1029 + switch (fb->format->format) { 1030 + case DRM_FORMAT_RGB565: 1031 + case DRM_FORMAT_BGR565: 1032 + r = (color_key & 0xf800) >> 11; 1033 + g = (color_key & 0x7e0) >> 5; 1034 + b = (color_key & 0x1f); 1035 + r <<= 5; 1036 + g <<= 4; 1037 + b <<= 5; 1038 + color_key_en = 1; 1039 + break; 1040 + case DRM_FORMAT_XRGB8888: 1041 + case DRM_FORMAT_ARGB8888: 1042 + case DRM_FORMAT_XBGR8888: 1043 + case DRM_FORMAT_ABGR8888: 1044 + case DRM_FORMAT_RGB888: 1045 + case DRM_FORMAT_BGR888: 1046 + r = (color_key & 0xff0000) >> 16; 1047 + g = (color_key & 0xff00) >> 8; 1048 + b = (color_key & 0xff); 1049 + r <<= 2; 1050 + g <<= 2; 1051 + b <<= 2; 1052 + color_key_en = 1; 1053 + break; 1054 + } 1055 + 1056 + vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, color_key_en); 1057 + vop2_win_write(win, VOP2_WIN_COLOR_KEY, (r << 20) | (g << 10) | b); 1058 + } 1059 + 1060 + static void vop2_plane_atomic_update(struct drm_plane *plane, 1061 + struct drm_atomic_state *state) 1062 + { 1063 + struct drm_plane_state *pstate = plane->state; 1064 + struct drm_crtc *crtc = pstate->crtc; 1065 + struct vop2_win *win = to_vop2_win(plane); 1066 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 1067 + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; 1068 + struct vop2 *vop2 = win->vop2; 1069 + struct drm_framebuffer *fb = pstate->fb; 1070 + u32 bpp = fb->format->cpp[0] * 8; 1071 + u32 actual_w, actual_h, dsp_w, dsp_h; 1072 + u32 act_info, dsp_info; 1073 + u32 format; 1074 + u32 afbc_format; 1075 + u32 rb_swap; 1076 + u32 uv_swap; 1077 + struct drm_rect *src = &pstate->src; 1078 + struct drm_rect *dest = &pstate->dst; 1079 + u32 afbc_tile_num; 1080 + u32 transform_offset; 1081 + bool dither_up; 1082 + bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false; 1083 + bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false; 1084 + bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270; 1085 + bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90; 1086 + struct rockchip_gem_object *rk_obj; 1087 + unsigned long offset; 1088 + bool afbc_en; 1089 + dma_addr_t yrgb_mst; 1090 + dma_addr_t uv_mst; 1091 + 1092 + /* 1093 + * can't update plane when vop2 is disabled. 1094 + */ 1095 + if (WARN_ON(!crtc)) 1096 + return; 1097 + 1098 + if (!pstate->visible) { 1099 + vop2_plane_atomic_disable(plane, state); 1100 + return; 1101 + } 1102 + 1103 + afbc_en = rockchip_afbc(plane, fb->modifier); 1104 + 1105 + offset = (src->x1 >> 16) * fb->format->cpp[0]; 1106 + 1107 + /* 1108 + * AFBC HDR_PTR must set to the zero offset of the framebuffer. 1109 + */ 1110 + if (afbc_en) 1111 + offset = 0; 1112 + else if (pstate->rotation & DRM_MODE_REFLECT_Y) 1113 + offset += ((src->y2 >> 16) - 1) * fb->pitches[0]; 1114 + else 1115 + offset += (src->y1 >> 16) * fb->pitches[0]; 1116 + 1117 + rk_obj = to_rockchip_obj(fb->obj[0]); 1118 + 1119 + yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; 1120 + if (fb->format->is_yuv) { 1121 + int hsub = fb->format->hsub; 1122 + int vsub = fb->format->vsub; 1123 + 1124 + offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub; 1125 + offset += (src->y1 >> 16) * fb->pitches[1] / vsub; 1126 + 1127 + if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en) 1128 + offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2) / vsub; 1129 + 1130 + rk_obj = to_rockchip_obj(fb->obj[0]); 1131 + uv_mst = rk_obj->dma_addr + offset + fb->offsets[1]; 1132 + } 1133 + 1134 + actual_w = drm_rect_width(src) >> 16; 1135 + actual_h = drm_rect_height(src) >> 16; 1136 + dsp_w = drm_rect_width(dest); 1137 + 1138 + if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { 1139 + drm_err(vop2->drm, "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", 1140 + vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay); 1141 + dsp_w = adjusted_mode->hdisplay - dest->x1; 1142 + if (dsp_w < 4) 1143 + dsp_w = 4; 1144 + actual_w = dsp_w * actual_w / drm_rect_width(dest); 1145 + } 1146 + 1147 + dsp_h = drm_rect_height(dest); 1148 + 1149 + if (dest->y1 + dsp_h > adjusted_mode->vdisplay) { 1150 + drm_err(vop2->drm, "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", 1151 + vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay); 1152 + dsp_h = adjusted_mode->vdisplay - dest->y1; 1153 + if (dsp_h < 4) 1154 + dsp_h = 4; 1155 + actual_h = dsp_h * actual_h / drm_rect_height(dest); 1156 + } 1157 + 1158 + /* 1159 + * This is workaround solution for IC design: 1160 + * esmart can't support scale down when actual_w % 16 == 1. 1161 + */ 1162 + if (!(win->data->feature & WIN_FEATURE_AFBDC)) { 1163 + if (actual_w > dsp_w && (actual_w & 0xf) == 1) { 1164 + drm_err(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", 1165 + vp->id, win->data->name, actual_w); 1166 + actual_w -= 1; 1167 + } 1168 + } 1169 + 1170 + if (afbc_en && actual_w % 4) { 1171 + drm_err(vop2->drm, "vp%d %s actual_w[%d] not 4 pixel aligned\n", 1172 + vp->id, win->data->name, actual_w); 1173 + actual_w = ALIGN_DOWN(actual_w, 4); 1174 + } 1175 + 1176 + act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); 1177 + dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); 1178 + 1179 + format = vop2_convert_format(fb->format->format); 1180 + 1181 + drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n", 1182 + vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h, 1183 + dest->x1, dest->y1, 1184 + &fb->format->format, 1185 + afbc_en ? "AFBC" : "", &yrgb_mst); 1186 + 1187 + if (afbc_en) { 1188 + u32 stride; 1189 + 1190 + /* the afbc superblock is 16 x 16 */ 1191 + afbc_format = vop2_convert_afbc_format(fb->format->format); 1192 + 1193 + /* Enable color transform for YTR */ 1194 + if (fb->modifier & AFBC_FORMAT_MOD_YTR) 1195 + afbc_format |= (1 << 4); 1196 + 1197 + afbc_tile_num = ALIGN(actual_w, 16) >> 4; 1198 + 1199 + /* 1200 + * AFBC pic_vir_width is count by pixel, this is different 1201 + * with WIN_VIR_STRIDE. 1202 + */ 1203 + stride = (fb->pitches[0] << 3) / bpp; 1204 + if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270)) 1205 + drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligened\n", 1206 + vp->id, win->data->name, stride); 1207 + 1208 + rb_swap = vop2_afbc_rb_swap(fb->format->format); 1209 + uv_swap = vop2_afbc_uv_swap(fb->format->format); 1210 + /* 1211 + * This is a workaround for crazy IC design, Cluster 1212 + * and Esmart/Smart use different format configuration map: 1213 + * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart. 1214 + * 1215 + * This is one thing we can make the convert simple: 1216 + * AFBCD decode all the YUV data to YUV444. So we just 1217 + * set all the yuv 10 bit to YUV444_10. 1218 + */ 1219 + if (fb->format->is_yuv && bpp == 10) 1220 + format = VOP2_CLUSTER_YUV444_10; 1221 + 1222 + if (vop2_cluster_window(win)) 1223 + vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1); 1224 + vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format); 1225 + vop2_win_write(win, VOP2_WIN_AFBC_RB_SWAP, rb_swap); 1226 + vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap); 1227 + vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0); 1228 + vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0); 1229 + if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90)) { 1230 + vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 0); 1231 + transform_offset = vop2_afbc_transform_offset(pstate, false); 1232 + } else { 1233 + vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 1); 1234 + transform_offset = vop2_afbc_transform_offset(pstate, true); 1235 + } 1236 + vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst); 1237 + vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info); 1238 + vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, transform_offset); 1239 + vop2_win_write(win, VOP2_WIN_AFBC_PIC_OFFSET, ((src->x1 >> 16) | src->y1)); 1240 + vop2_win_write(win, VOP2_WIN_AFBC_DSP_OFFSET, (dest->x1 | (dest->y1 << 16))); 1241 + vop2_win_write(win, VOP2_WIN_AFBC_PIC_VIR_WIDTH, stride); 1242 + vop2_win_write(win, VOP2_WIN_AFBC_TILE_NUM, afbc_tile_num); 1243 + vop2_win_write(win, VOP2_WIN_XMIRROR, xmirror); 1244 + vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270); 1245 + vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90); 1246 + } else { 1247 + vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4)); 1248 + } 1249 + 1250 + vop2_win_write(win, VOP2_WIN_YMIRROR, ymirror); 1251 + 1252 + if (rotate_90 || rotate_270) { 1253 + act_info = swahw32(act_info); 1254 + actual_w = drm_rect_height(src) >> 16; 1255 + actual_h = drm_rect_width(src) >> 16; 1256 + } 1257 + 1258 + vop2_win_write(win, VOP2_WIN_FORMAT, format); 1259 + vop2_win_write(win, VOP2_WIN_YRGB_MST, yrgb_mst); 1260 + 1261 + rb_swap = vop2_win_rb_swap(fb->format->format); 1262 + vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap); 1263 + if (!vop2_cluster_window(win)) { 1264 + uv_swap = vop2_win_uv_swap(fb->format->format); 1265 + vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); 1266 + } 1267 + 1268 + if (fb->format->is_yuv) { 1269 + vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4)); 1270 + vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst); 1271 + } 1272 + 1273 + vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format); 1274 + if (!vop2_cluster_window(win)) 1275 + vop2_plane_setup_color_key(plane, 0); 1276 + vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info); 1277 + vop2_win_write(win, VOP2_WIN_DSP_INFO, dsp_info); 1278 + vop2_win_write(win, VOP2_WIN_DSP_ST, dest->y1 << 16 | (dest->x1 & 0xffff)); 1279 + 1280 + vop2_setup_csc_mode(vp, win, pstate); 1281 + 1282 + dither_up = vop2_win_dither_up(fb->format->format); 1283 + vop2_win_write(win, VOP2_WIN_DITHER_UP, dither_up); 1284 + 1285 + vop2_win_write(win, VOP2_WIN_ENABLE, 1); 1286 + 1287 + if (vop2_cluster_window(win)) { 1288 + int lb_mode = vop2_get_cluster_lb_mode(win, pstate); 1289 + 1290 + vop2_win_write(win, VOP2_WIN_CLUSTER_LB_MODE, lb_mode); 1291 + vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 1); 1292 + } 1293 + } 1294 + 1295 + static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = { 1296 + .atomic_check = vop2_plane_atomic_check, 1297 + .atomic_update = vop2_plane_atomic_update, 1298 + .atomic_disable = vop2_plane_atomic_disable, 1299 + }; 1300 + 1301 + static const struct drm_plane_funcs vop2_plane_funcs = { 1302 + .update_plane = drm_atomic_helper_update_plane, 1303 + .disable_plane = drm_atomic_helper_disable_plane, 1304 + .destroy = drm_plane_cleanup, 1305 + .reset = drm_atomic_helper_plane_reset, 1306 + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 1307 + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 1308 + .format_mod_supported = rockchip_vop2_mod_supported, 1309 + }; 1310 + 1311 + static int vop2_crtc_enable_vblank(struct drm_crtc *crtc) 1312 + { 1313 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 1314 + 1315 + vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD); 1316 + 1317 + return 0; 1318 + } 1319 + 1320 + static void vop2_crtc_disable_vblank(struct drm_crtc *crtc) 1321 + { 1322 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 1323 + 1324 + vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD); 1325 + } 1326 + 1327 + static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc, 1328 + const struct drm_display_mode *mode, 1329 + struct drm_display_mode *adj_mode) 1330 + { 1331 + drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | 1332 + CRTC_STEREO_DOUBLE); 1333 + 1334 + return true; 1335 + } 1336 + 1337 + static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl) 1338 + { 1339 + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); 1340 + 1341 + switch (vcstate->bus_format) { 1342 + case MEDIA_BUS_FMT_RGB565_1X16: 1343 + *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN; 1344 + break; 1345 + case MEDIA_BUS_FMT_RGB666_1X18: 1346 + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 1347 + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: 1348 + *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN; 1349 + *dsp_ctrl |= RGB888_TO_RGB666; 1350 + break; 1351 + case MEDIA_BUS_FMT_YUV8_1X24: 1352 + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: 1353 + *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN; 1354 + break; 1355 + default: 1356 + break; 1357 + } 1358 + 1359 + if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA) 1360 + *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN; 1361 + 1362 + *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL, 1363 + DITHER_DOWN_ALLEGRO); 1364 + } 1365 + 1366 + static void vop2_post_config(struct drm_crtc *crtc) 1367 + { 1368 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 1369 + struct drm_display_mode *mode = &crtc->state->adjusted_mode; 1370 + u16 vtotal = mode->crtc_vtotal; 1371 + u16 hdisplay = mode->crtc_hdisplay; 1372 + u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; 1373 + u16 vdisplay = mode->crtc_vdisplay; 1374 + u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; 1375 + u32 left_margin = 100, right_margin = 100; 1376 + u32 top_margin = 100, bottom_margin = 100; 1377 + u16 hsize = hdisplay * (left_margin + right_margin) / 200; 1378 + u16 vsize = vdisplay * (top_margin + bottom_margin) / 200; 1379 + u16 hact_end, vact_end; 1380 + u32 val; 1381 + 1382 + vsize = rounddown(vsize, 2); 1383 + hsize = rounddown(hsize, 2); 1384 + hact_st += hdisplay * (100 - left_margin) / 200; 1385 + hact_end = hact_st + hsize; 1386 + val = hact_st << 16; 1387 + val |= hact_end; 1388 + vop2_vp_write(vp, RK3568_VP_POST_DSP_HACT_INFO, val); 1389 + vact_st += vdisplay * (100 - top_margin) / 200; 1390 + vact_end = vact_st + vsize; 1391 + val = vact_st << 16; 1392 + val |= vact_end; 1393 + vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO, val); 1394 + val = scl_cal_scale2(vdisplay, vsize) << 16; 1395 + val |= scl_cal_scale2(hdisplay, hsize); 1396 + vop2_vp_write(vp, RK3568_VP_POST_SCL_FACTOR_YRGB, val); 1397 + 1398 + val = 0; 1399 + if (hdisplay != hsize) 1400 + val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN; 1401 + if (vdisplay != vsize) 1402 + val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN; 1403 + vop2_vp_write(vp, RK3568_VP_POST_SCL_CTRL, val); 1404 + 1405 + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { 1406 + u16 vact_st_f1 = vtotal + vact_st + 1; 1407 + u16 vact_end_f1 = vact_st_f1 + vsize; 1408 + 1409 + val = vact_st_f1 << 16 | vact_end_f1; 1410 + vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val); 1411 + } 1412 + 1413 + vop2_vp_write(vp, RK3568_VP_DSP_BG, 0); 1414 + } 1415 + 1416 + static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id, 1417 + u32 polflags) 1418 + { 1419 + struct vop2 *vop2 = vp->vop2; 1420 + u32 die, dip; 1421 + 1422 + die = vop2_readl(vop2, RK3568_DSP_IF_EN); 1423 + dip = vop2_readl(vop2, RK3568_DSP_IF_POL); 1424 + 1425 + switch (id) { 1426 + case ROCKCHIP_VOP2_EP_RGB0: 1427 + die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX; 1428 + die |= RK3568_SYS_DSP_INFACE_EN_RGB | 1429 + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id); 1430 + if (polflags & POLFLAG_DCLK_INV) 1431 + regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3)); 1432 + else 1433 + regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16)); 1434 + break; 1435 + case ROCKCHIP_VOP2_EP_HDMI0: 1436 + die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX; 1437 + die |= RK3568_SYS_DSP_INFACE_EN_HDMI | 1438 + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id); 1439 + break; 1440 + case ROCKCHIP_VOP2_EP_EDP0: 1441 + die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX; 1442 + die |= RK3568_SYS_DSP_INFACE_EN_EDP | 1443 + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id); 1444 + break; 1445 + case ROCKCHIP_VOP2_EP_MIPI0: 1446 + die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX; 1447 + die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 | 1448 + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id); 1449 + dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL; 1450 + dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags); 1451 + break; 1452 + case ROCKCHIP_VOP2_EP_MIPI1: 1453 + die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX; 1454 + die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 | 1455 + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_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_LVDS0: 1460 + die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX; 1461 + die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 | 1462 + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id); 1463 + dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; 1464 + dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags); 1465 + break; 1466 + case ROCKCHIP_VOP2_EP_LVDS1: 1467 + die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX; 1468 + die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 | 1469 + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_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 + default: 1474 + drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id); 1475 + return; 1476 + }; 1477 + 1478 + dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD; 1479 + 1480 + vop2_writel(vop2, RK3568_DSP_IF_EN, die); 1481 + vop2_writel(vop2, RK3568_DSP_IF_POL, dip); 1482 + } 1483 + 1484 + static int us_to_vertical_line(struct drm_display_mode *mode, int us) 1485 + { 1486 + return us * mode->clock / mode->htotal / 1000; 1487 + } 1488 + 1489 + static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, 1490 + struct drm_atomic_state *state) 1491 + { 1492 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 1493 + struct vop2 *vop2 = vp->vop2; 1494 + const struct vop2_data *vop2_data = vop2->data; 1495 + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; 1496 + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 1497 + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); 1498 + struct drm_display_mode *mode = &crtc->state->adjusted_mode; 1499 + unsigned long clock = mode->crtc_clock * 1000; 1500 + u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; 1501 + u16 hdisplay = mode->crtc_hdisplay; 1502 + u16 htotal = mode->crtc_htotal; 1503 + u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; 1504 + u16 hact_end = hact_st + hdisplay; 1505 + u16 vdisplay = mode->crtc_vdisplay; 1506 + u16 vtotal = mode->crtc_vtotal; 1507 + u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; 1508 + u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; 1509 + u16 vact_end = vact_st + vdisplay; 1510 + u8 out_mode; 1511 + u32 dsp_ctrl = 0; 1512 + int act_end; 1513 + u32 val, polflags; 1514 + int ret; 1515 + struct drm_encoder *encoder; 1516 + 1517 + drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n", 1518 + hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p", 1519 + drm_mode_vrefresh(mode), vcstate->output_type, vp->id); 1520 + 1521 + vop2_lock(vop2); 1522 + 1523 + ret = clk_prepare_enable(vp->dclk); 1524 + if (ret < 0) { 1525 + drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n", 1526 + vp->id, ret); 1527 + return; 1528 + } 1529 + 1530 + if (!vop2->enable_count) 1531 + vop2_enable(vop2); 1532 + 1533 + vop2->enable_count++; 1534 + 1535 + vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY); 1536 + 1537 + polflags = 0; 1538 + if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) 1539 + polflags |= POLFLAG_DCLK_INV; 1540 + if (mode->flags & DRM_MODE_FLAG_PHSYNC) 1541 + polflags |= BIT(HSYNC_POSITIVE); 1542 + if (mode->flags & DRM_MODE_FLAG_PVSYNC) 1543 + polflags |= BIT(VSYNC_POSITIVE); 1544 + 1545 + drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { 1546 + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); 1547 + 1548 + rk3568_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); 1549 + } 1550 + 1551 + if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA && 1552 + !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) 1553 + out_mode = ROCKCHIP_OUT_MODE_P888; 1554 + else 1555 + out_mode = vcstate->output_mode; 1556 + 1557 + dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode); 1558 + 1559 + if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode)) 1560 + dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP; 1561 + 1562 + if (is_yuv_output(vcstate->bus_format)) 1563 + dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y; 1564 + 1565 + vop2_dither_setup(crtc, &dsp_ctrl); 1566 + 1567 + vop2_vp_write(vp, RK3568_VP_DSP_HTOTAL_HS_END, (htotal << 16) | hsync_len); 1568 + val = hact_st << 16; 1569 + val |= hact_end; 1570 + vop2_vp_write(vp, RK3568_VP_DSP_HACT_ST_END, val); 1571 + 1572 + val = vact_st << 16; 1573 + val |= vact_end; 1574 + vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END, val); 1575 + 1576 + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { 1577 + u16 vact_st_f1 = vtotal + vact_st + 1; 1578 + u16 vact_end_f1 = vact_st_f1 + vdisplay; 1579 + 1580 + val = vact_st_f1 << 16 | vact_end_f1; 1581 + vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END_F1, val); 1582 + 1583 + val = vtotal << 16 | (vtotal + vsync_len); 1584 + vop2_vp_write(vp, RK3568_VP_DSP_VS_ST_END_F1, val); 1585 + dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE; 1586 + dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL; 1587 + dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN; 1588 + vtotal += vtotal + 1; 1589 + act_end = vact_end_f1; 1590 + } else { 1591 + act_end = vact_end; 1592 + } 1593 + 1594 + vop2_writel(vop2, RK3568_VP_LINE_FLAG(vp->id), 1595 + (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end); 1596 + 1597 + vop2_vp_write(vp, RK3568_VP_DSP_VTOTAL_VS_END, vtotal << 16 | vsync_len); 1598 + 1599 + if (mode->flags & DRM_MODE_FLAG_DBLCLK) { 1600 + dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV; 1601 + clock *= 2; 1602 + } 1603 + 1604 + vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0); 1605 + 1606 + clk_set_rate(vp->dclk, clock); 1607 + 1608 + vop2_post_config(crtc); 1609 + 1610 + vop2_cfg_done(vp); 1611 + 1612 + vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); 1613 + 1614 + drm_crtc_vblank_on(crtc); 1615 + 1616 + vop2_unlock(vop2); 1617 + } 1618 + 1619 + static int vop2_crtc_atomic_check(struct drm_crtc *crtc, 1620 + struct drm_atomic_state *state) 1621 + { 1622 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 1623 + struct drm_plane *plane; 1624 + int nplanes = 0; 1625 + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 1626 + 1627 + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) 1628 + nplanes++; 1629 + 1630 + if (nplanes > vp->nlayers) 1631 + return -EINVAL; 1632 + 1633 + return 0; 1634 + } 1635 + 1636 + static bool is_opaque(u16 alpha) 1637 + { 1638 + return (alpha >> 8) == 0xff; 1639 + } 1640 + 1641 + static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config, 1642 + struct vop2_alpha *alpha) 1643 + { 1644 + int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1; 1645 + int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1; 1646 + int src_color_mode = alpha_config->src_premulti_en ? 1647 + ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; 1648 + int dst_color_mode = alpha_config->dst_premulti_en ? 1649 + ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; 1650 + 1651 + alpha->src_color_ctrl.val = 0; 1652 + alpha->dst_color_ctrl.val = 0; 1653 + alpha->src_alpha_ctrl.val = 0; 1654 + alpha->dst_alpha_ctrl.val = 0; 1655 + 1656 + if (!alpha_config->src_pixel_alpha_en) 1657 + alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; 1658 + else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en) 1659 + alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX; 1660 + else 1661 + alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; 1662 + 1663 + alpha->src_color_ctrl.bits.alpha_en = 1; 1664 + 1665 + if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) { 1666 + alpha->src_color_ctrl.bits.color_mode = src_color_mode; 1667 + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; 1668 + } else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) { 1669 + alpha->src_color_ctrl.bits.color_mode = src_color_mode; 1670 + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE; 1671 + } else { 1672 + alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL; 1673 + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; 1674 + } 1675 + alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8; 1676 + alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; 1677 + alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; 1678 + 1679 + alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; 1680 + alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; 1681 + alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; 1682 + alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8; 1683 + alpha->dst_color_ctrl.bits.color_mode = dst_color_mode; 1684 + alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; 1685 + 1686 + alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; 1687 + alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode; 1688 + alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; 1689 + alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE; 1690 + 1691 + alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; 1692 + if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en) 1693 + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX; 1694 + else 1695 + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; 1696 + alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION; 1697 + alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; 1698 + } 1699 + 1700 + static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id) 1701 + { 1702 + struct vop2_video_port *vp; 1703 + int used_layer = 0; 1704 + int i; 1705 + 1706 + for (i = 0; i < port_id; i++) { 1707 + vp = &vop2->vps[i]; 1708 + used_layer += hweight32(vp->win_mask); 1709 + } 1710 + 1711 + return used_layer; 1712 + } 1713 + 1714 + static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win) 1715 + { 1716 + u32 offset = (main_win->data->phys_id * 0x10); 1717 + struct vop2_alpha_config alpha_config; 1718 + struct vop2_alpha alpha; 1719 + struct drm_plane_state *bottom_win_pstate; 1720 + bool src_pixel_alpha_en = false; 1721 + u16 src_glb_alpha_val, dst_glb_alpha_val; 1722 + bool premulti_en = false; 1723 + bool swap = false; 1724 + 1725 + /* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */ 1726 + bottom_win_pstate = main_win->base.state; 1727 + src_glb_alpha_val = 0; 1728 + dst_glb_alpha_val = main_win->base.state->alpha; 1729 + 1730 + if (!bottom_win_pstate->fb) 1731 + return; 1732 + 1733 + alpha_config.src_premulti_en = premulti_en; 1734 + alpha_config.dst_premulti_en = false; 1735 + alpha_config.src_pixel_alpha_en = src_pixel_alpha_en; 1736 + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ 1737 + alpha_config.src_glb_alpha_value = src_glb_alpha_val; 1738 + alpha_config.dst_glb_alpha_value = dst_glb_alpha_val; 1739 + vop2_parse_alpha(&alpha_config, &alpha); 1740 + 1741 + alpha.src_color_ctrl.bits.src_dst_swap = swap; 1742 + vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset, 1743 + alpha.src_color_ctrl.val); 1744 + vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset, 1745 + alpha.dst_color_ctrl.val); 1746 + vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset, 1747 + alpha.src_alpha_ctrl.val); 1748 + vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset, 1749 + alpha.dst_alpha_ctrl.val); 1750 + } 1751 + 1752 + static void vop2_setup_alpha(struct vop2_video_port *vp) 1753 + { 1754 + struct vop2 *vop2 = vp->vop2; 1755 + struct drm_framebuffer *fb; 1756 + struct vop2_alpha_config alpha_config; 1757 + struct vop2_alpha alpha; 1758 + struct drm_plane *plane; 1759 + int pixel_alpha_en; 1760 + int premulti_en, gpremulti_en = 0; 1761 + int mixer_id; 1762 + u32 offset; 1763 + bool bottom_layer_alpha_en = false; 1764 + u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE; 1765 + 1766 + mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); 1767 + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ 1768 + 1769 + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { 1770 + struct vop2_win *win = to_vop2_win(plane); 1771 + 1772 + if (plane->state->normalized_zpos == 0 && 1773 + !is_opaque(plane->state->alpha) && 1774 + !vop2_cluster_window(win)) { 1775 + /* 1776 + * If bottom layer have global alpha effect [except cluster layer, 1777 + * because cluster have deal with bottom layer global alpha value 1778 + * at cluster mix], bottom layer mix need deal with global alpha. 1779 + */ 1780 + bottom_layer_alpha_en = true; 1781 + dst_global_alpha = plane->state->alpha; 1782 + } 1783 + } 1784 + 1785 + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { 1786 + struct vop2_win *win = to_vop2_win(plane); 1787 + int zpos = plane->state->normalized_zpos; 1788 + 1789 + if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) 1790 + premulti_en = 1; 1791 + else 1792 + premulti_en = 0; 1793 + 1794 + plane = &win->base; 1795 + fb = plane->state->fb; 1796 + 1797 + pixel_alpha_en = fb->format->has_alpha; 1798 + 1799 + alpha_config.src_premulti_en = premulti_en; 1800 + 1801 + if (bottom_layer_alpha_en && zpos == 1) { 1802 + gpremulti_en = premulti_en; 1803 + /* Cd = Cs + (1 - As) * Cd * Agd */ 1804 + alpha_config.dst_premulti_en = false; 1805 + alpha_config.src_pixel_alpha_en = pixel_alpha_en; 1806 + alpha_config.src_glb_alpha_value = plane->state->alpha; 1807 + alpha_config.dst_glb_alpha_value = dst_global_alpha; 1808 + } else if (vop2_cluster_window(win)) { 1809 + /* Mix output data only have pixel alpha */ 1810 + alpha_config.dst_premulti_en = true; 1811 + alpha_config.src_pixel_alpha_en = true; 1812 + alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; 1813 + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; 1814 + } else { 1815 + /* Cd = Cs + (1 - As) * Cd */ 1816 + alpha_config.dst_premulti_en = true; 1817 + alpha_config.src_pixel_alpha_en = pixel_alpha_en; 1818 + alpha_config.src_glb_alpha_value = plane->state->alpha; 1819 + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; 1820 + } 1821 + 1822 + vop2_parse_alpha(&alpha_config, &alpha); 1823 + 1824 + offset = (mixer_id + zpos - 1) * 0x10; 1825 + vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset, 1826 + alpha.src_color_ctrl.val); 1827 + vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset, 1828 + alpha.dst_color_ctrl.val); 1829 + vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset, 1830 + alpha.src_alpha_ctrl.val); 1831 + vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset, 1832 + alpha.dst_alpha_ctrl.val); 1833 + } 1834 + 1835 + if (vp->id == 0) { 1836 + if (bottom_layer_alpha_en) { 1837 + /* Transfer pixel alpha to hdr mix */ 1838 + alpha_config.src_premulti_en = gpremulti_en; 1839 + alpha_config.dst_premulti_en = true; 1840 + alpha_config.src_pixel_alpha_en = true; 1841 + alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; 1842 + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; 1843 + vop2_parse_alpha(&alpha_config, &alpha); 1844 + 1845 + vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 1846 + alpha.src_color_ctrl.val); 1847 + vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL, 1848 + alpha.dst_color_ctrl.val); 1849 + vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL, 1850 + alpha.src_alpha_ctrl.val); 1851 + vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL, 1852 + alpha.dst_alpha_ctrl.val); 1853 + } else { 1854 + vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0); 1855 + } 1856 + } 1857 + } 1858 + 1859 + static void vop2_setup_layer_mixer(struct vop2_video_port *vp) 1860 + { 1861 + struct vop2 *vop2 = vp->vop2; 1862 + struct drm_plane *plane; 1863 + u32 layer_sel = 0; 1864 + u32 port_sel; 1865 + unsigned int nlayer, ofs; 1866 + struct drm_display_mode *adjusted_mode; 1867 + u16 hsync_len; 1868 + u16 hdisplay; 1869 + u32 bg_dly; 1870 + u32 pre_scan_dly; 1871 + int i; 1872 + struct vop2_video_port *vp0 = &vop2->vps[0]; 1873 + struct vop2_video_port *vp1 = &vop2->vps[1]; 1874 + struct vop2_video_port *vp2 = &vop2->vps[2]; 1875 + 1876 + adjusted_mode = &vp->crtc.state->adjusted_mode; 1877 + hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; 1878 + hdisplay = adjusted_mode->crtc_hdisplay; 1879 + 1880 + bg_dly = vp->data->pre_scan_max_dly[3]; 1881 + vop2_writel(vop2, RK3568_VP_BG_MIX_CTRL(vp->id), 1882 + FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly)); 1883 + 1884 + pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len; 1885 + vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly); 1886 + 1887 + vop2_writel(vop2, RK3568_OVL_CTRL, 0); 1888 + port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL); 1889 + port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT; 1890 + 1891 + if (vp0->nlayers) 1892 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 1893 + vp0->nlayers - 1); 1894 + else 1895 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8); 1896 + 1897 + if (vp1->nlayers) 1898 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 1899 + (vp0->nlayers + vp1->nlayers - 1)); 1900 + else 1901 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8); 1902 + 1903 + if (vp2->nlayers) 1904 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 1905 + (vp2->nlayers + vp1->nlayers + vp0->nlayers - 1)); 1906 + else 1907 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8); 1908 + 1909 + layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); 1910 + 1911 + ofs = 0; 1912 + for (i = 0; i < vp->id; i++) 1913 + ofs += vop2->vps[i].nlayers; 1914 + 1915 + nlayer = 0; 1916 + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { 1917 + struct vop2_win *win = to_vop2_win(plane); 1918 + 1919 + switch (win->data->phys_id) { 1920 + case ROCKCHIP_VOP2_CLUSTER0: 1921 + port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0; 1922 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id); 1923 + break; 1924 + case ROCKCHIP_VOP2_CLUSTER1: 1925 + port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1; 1926 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id); 1927 + break; 1928 + case ROCKCHIP_VOP2_ESMART0: 1929 + port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0; 1930 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id); 1931 + break; 1932 + case ROCKCHIP_VOP2_ESMART1: 1933 + port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1; 1934 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id); 1935 + break; 1936 + case ROCKCHIP_VOP2_SMART0: 1937 + port_sel &= ~RK3568_OVL_PORT_SEL__SMART0; 1938 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id); 1939 + break; 1940 + case ROCKCHIP_VOP2_SMART1: 1941 + port_sel &= ~RK3568_OVL_PORT_SEL__SMART1; 1942 + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id); 1943 + break; 1944 + } 1945 + 1946 + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, 1947 + 0x7); 1948 + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, 1949 + win->data->layer_sel_id); 1950 + nlayer++; 1951 + } 1952 + 1953 + /* configure unused layers to 0x5 (reserved) */ 1954 + for (; nlayer < vp->nlayers; nlayer++) { 1955 + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7); 1956 + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5); 1957 + } 1958 + 1959 + vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); 1960 + vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel); 1961 + vop2_writel(vop2, RK3568_OVL_CTRL, RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD); 1962 + } 1963 + 1964 + static void vop2_setup_dly_for_windows(struct vop2 *vop2) 1965 + { 1966 + struct vop2_win *win; 1967 + int i = 0; 1968 + u32 cdly = 0, sdly = 0; 1969 + 1970 + for (i = 0; i < vop2->data->win_size; i++) { 1971 + u32 dly; 1972 + 1973 + win = &vop2->win[i]; 1974 + dly = win->delay; 1975 + 1976 + switch (win->data->phys_id) { 1977 + case ROCKCHIP_VOP2_CLUSTER0: 1978 + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly); 1979 + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly); 1980 + break; 1981 + case ROCKCHIP_VOP2_CLUSTER1: 1982 + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly); 1983 + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly); 1984 + break; 1985 + case ROCKCHIP_VOP2_ESMART0: 1986 + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly); 1987 + break; 1988 + case ROCKCHIP_VOP2_ESMART1: 1989 + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly); 1990 + break; 1991 + case ROCKCHIP_VOP2_SMART0: 1992 + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly); 1993 + break; 1994 + case ROCKCHIP_VOP2_SMART1: 1995 + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly); 1996 + break; 1997 + } 1998 + } 1999 + 2000 + vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly); 2001 + vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly); 2002 + } 2003 + 2004 + static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, 2005 + struct drm_atomic_state *state) 2006 + { 2007 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 2008 + struct vop2 *vop2 = vp->vop2; 2009 + struct drm_plane *plane; 2010 + 2011 + vp->win_mask = 0; 2012 + 2013 + drm_atomic_crtc_for_each_plane(plane, crtc) { 2014 + struct vop2_win *win = to_vop2_win(plane); 2015 + 2016 + win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT]; 2017 + 2018 + vp->win_mask |= BIT(win->data->phys_id); 2019 + 2020 + if (vop2_cluster_window(win)) 2021 + vop2_setup_cluster_alpha(vop2, win); 2022 + } 2023 + 2024 + if (!vp->win_mask) 2025 + return; 2026 + 2027 + vop2_setup_layer_mixer(vp); 2028 + vop2_setup_alpha(vp); 2029 + vop2_setup_dly_for_windows(vop2); 2030 + } 2031 + 2032 + static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, 2033 + struct drm_atomic_state *state) 2034 + { 2035 + struct vop2_video_port *vp = to_vop2_video_port(crtc); 2036 + 2037 + vop2_post_config(crtc); 2038 + 2039 + vop2_cfg_done(vp); 2040 + 2041 + spin_lock_irq(&crtc->dev->event_lock); 2042 + 2043 + if (crtc->state->event) { 2044 + WARN_ON(drm_crtc_vblank_get(crtc)); 2045 + vp->event = crtc->state->event; 2046 + crtc->state->event = NULL; 2047 + } 2048 + 2049 + spin_unlock_irq(&crtc->dev->event_lock); 2050 + } 2051 + 2052 + static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { 2053 + .mode_fixup = vop2_crtc_mode_fixup, 2054 + .atomic_check = vop2_crtc_atomic_check, 2055 + .atomic_begin = vop2_crtc_atomic_begin, 2056 + .atomic_flush = vop2_crtc_atomic_flush, 2057 + .atomic_enable = vop2_crtc_atomic_enable, 2058 + .atomic_disable = vop2_crtc_atomic_disable, 2059 + }; 2060 + 2061 + static void vop2_crtc_reset(struct drm_crtc *crtc) 2062 + { 2063 + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); 2064 + 2065 + if (crtc->state) { 2066 + __drm_atomic_helper_crtc_destroy_state(crtc->state); 2067 + kfree(vcstate); 2068 + } 2069 + 2070 + vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL); 2071 + if (!vcstate) 2072 + return; 2073 + 2074 + crtc->state = &vcstate->base; 2075 + crtc->state->crtc = crtc; 2076 + } 2077 + 2078 + static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc) 2079 + { 2080 + struct rockchip_crtc_state *vcstate, *old_vcstate; 2081 + 2082 + old_vcstate = to_rockchip_crtc_state(crtc->state); 2083 + 2084 + vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL); 2085 + if (!vcstate) 2086 + return NULL; 2087 + 2088 + __drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base); 2089 + 2090 + return &vcstate->base; 2091 + } 2092 + 2093 + static void vop2_crtc_destroy_state(struct drm_crtc *crtc, 2094 + struct drm_crtc_state *state) 2095 + { 2096 + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state); 2097 + 2098 + __drm_atomic_helper_crtc_destroy_state(&vcstate->base); 2099 + kfree(vcstate); 2100 + } 2101 + 2102 + static const struct drm_crtc_funcs vop2_crtc_funcs = { 2103 + .set_config = drm_atomic_helper_set_config, 2104 + .page_flip = drm_atomic_helper_page_flip, 2105 + .destroy = drm_crtc_cleanup, 2106 + .reset = vop2_crtc_reset, 2107 + .atomic_duplicate_state = vop2_crtc_duplicate_state, 2108 + .atomic_destroy_state = vop2_crtc_destroy_state, 2109 + .enable_vblank = vop2_crtc_enable_vblank, 2110 + .disable_vblank = vop2_crtc_disable_vblank, 2111 + }; 2112 + 2113 + static irqreturn_t vop2_isr(int irq, void *data) 2114 + { 2115 + struct vop2 *vop2 = data; 2116 + const struct vop2_data *vop2_data = vop2->data; 2117 + u32 axi_irqs[VOP2_SYS_AXI_BUS_NUM]; 2118 + int ret = IRQ_NONE; 2119 + int i; 2120 + 2121 + /* 2122 + * The irq is shared with the iommu. If the runtime-pm state of the 2123 + * vop2-device is disabled the irq has to be targeted at the iommu. 2124 + */ 2125 + if (!pm_runtime_get_if_in_use(vop2->dev)) 2126 + return IRQ_NONE; 2127 + 2128 + for (i = 0; i < vop2_data->nr_vps; i++) { 2129 + struct vop2_video_port *vp = &vop2->vps[i]; 2130 + struct drm_crtc *crtc = &vp->crtc; 2131 + u32 irqs; 2132 + 2133 + irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id)); 2134 + vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs); 2135 + 2136 + if (irqs & VP_INT_DSP_HOLD_VALID) { 2137 + complete(&vp->dsp_hold_completion); 2138 + ret = IRQ_HANDLED; 2139 + } 2140 + 2141 + if (irqs & VP_INT_FS_FIELD) { 2142 + drm_crtc_handle_vblank(crtc); 2143 + spin_lock(&crtc->dev->event_lock); 2144 + if (vp->event) { 2145 + u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); 2146 + 2147 + if (!(val & BIT(vp->id))) { 2148 + drm_crtc_send_vblank_event(crtc, vp->event); 2149 + vp->event = NULL; 2150 + drm_crtc_vblank_put(crtc); 2151 + } 2152 + } 2153 + spin_unlock(&crtc->dev->event_lock); 2154 + 2155 + ret = IRQ_HANDLED; 2156 + } 2157 + 2158 + if (irqs & VP_INT_POST_BUF_EMPTY) { 2159 + drm_err_ratelimited(vop2->drm, 2160 + "POST_BUF_EMPTY irq err at vp%d\n", 2161 + vp->id); 2162 + ret = IRQ_HANDLED; 2163 + } 2164 + } 2165 + 2166 + axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS); 2167 + vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]); 2168 + axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS); 2169 + vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]); 2170 + 2171 + for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) { 2172 + if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) { 2173 + drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n"); 2174 + ret = IRQ_HANDLED; 2175 + } 2176 + } 2177 + 2178 + pm_runtime_put(vop2->dev); 2179 + 2180 + return ret; 2181 + } 2182 + 2183 + static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, 2184 + unsigned long possible_crtcs) 2185 + { 2186 + const struct vop2_win_data *win_data = win->data; 2187 + unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | 2188 + BIT(DRM_MODE_BLEND_PREMULTI) | 2189 + BIT(DRM_MODE_BLEND_COVERAGE); 2190 + int ret; 2191 + 2192 + ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs, 2193 + &vop2_plane_funcs, win_data->formats, 2194 + win_data->nformats, 2195 + win_data->format_modifiers, 2196 + win->type, win_data->name); 2197 + if (ret) { 2198 + drm_err(vop2->drm, "failed to initialize plane %d\n", ret); 2199 + return ret; 2200 + } 2201 + 2202 + drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs); 2203 + 2204 + if (win->data->supported_rotations) 2205 + drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0, 2206 + DRM_MODE_ROTATE_0 | 2207 + win->data->supported_rotations); 2208 + drm_plane_create_alpha_property(&win->base); 2209 + drm_plane_create_blend_mode_property(&win->base, blend_caps); 2210 + drm_plane_create_zpos_property(&win->base, win->win_id, 0, 2211 + vop2->registered_num_wins - 1); 2212 + 2213 + return 0; 2214 + } 2215 + 2216 + static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2) 2217 + { 2218 + int i; 2219 + 2220 + for (i = 0; i < vop2->data->nr_vps; i++) { 2221 + struct vop2_video_port *vp = &vop2->vps[i]; 2222 + 2223 + if (!vp->crtc.port) 2224 + continue; 2225 + if (vp->primary_plane) 2226 + continue; 2227 + 2228 + return vp; 2229 + } 2230 + 2231 + return NULL; 2232 + } 2233 + 2234 + #define NR_LAYERS 6 2235 + 2236 + static int vop2_create_crtc(struct vop2 *vop2) 2237 + { 2238 + const struct vop2_data *vop2_data = vop2->data; 2239 + struct drm_device *drm = vop2->drm; 2240 + struct device *dev = vop2->dev; 2241 + struct drm_plane *plane; 2242 + struct device_node *port; 2243 + struct vop2_video_port *vp; 2244 + int i, nvp, nvps = 0; 2245 + int ret; 2246 + 2247 + for (i = 0; i < vop2_data->nr_vps; i++) { 2248 + const struct vop2_video_port_data *vp_data; 2249 + struct device_node *np; 2250 + char dclk_name[9]; 2251 + 2252 + vp_data = &vop2_data->vp[i]; 2253 + vp = &vop2->vps[i]; 2254 + vp->vop2 = vop2; 2255 + vp->id = vp_data->id; 2256 + vp->regs = vp_data->regs; 2257 + vp->data = vp_data; 2258 + 2259 + snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id); 2260 + vp->dclk = devm_clk_get(vop2->dev, dclk_name); 2261 + if (IS_ERR(vp->dclk)) { 2262 + drm_err(vop2->drm, "failed to get %s\n", dclk_name); 2263 + return PTR_ERR(vp->dclk); 2264 + } 2265 + 2266 + np = of_graph_get_remote_node(dev->of_node, i, -1); 2267 + if (!np) { 2268 + drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i); 2269 + continue; 2270 + } 2271 + of_node_put(np); 2272 + 2273 + port = of_graph_get_port_by_id(dev->of_node, i); 2274 + if (!port) { 2275 + drm_err(vop2->drm, "no port node found for video_port%d\n", i); 2276 + return -ENOENT; 2277 + } 2278 + 2279 + vp->crtc.port = port; 2280 + nvps++; 2281 + } 2282 + 2283 + nvp = 0; 2284 + for (i = 0; i < vop2->registered_num_wins; i++) { 2285 + struct vop2_win *win = &vop2->win[i]; 2286 + u32 possible_crtcs; 2287 + 2288 + if (vop2->data->soc_id == 3566) { 2289 + /* 2290 + * On RK3566 these windows don't have an independent 2291 + * framebuffer. They share the framebuffer with smart0, 2292 + * esmart0 and cluster0 respectively. 2293 + */ 2294 + switch (win->data->phys_id) { 2295 + case ROCKCHIP_VOP2_SMART1: 2296 + case ROCKCHIP_VOP2_ESMART1: 2297 + case ROCKCHIP_VOP2_CLUSTER1: 2298 + continue; 2299 + } 2300 + } 2301 + 2302 + if (win->type == DRM_PLANE_TYPE_PRIMARY) { 2303 + vp = find_vp_without_primary(vop2); 2304 + if (vp) { 2305 + possible_crtcs = BIT(nvp); 2306 + vp->primary_plane = win; 2307 + nvp++; 2308 + } else { 2309 + /* change the unused primary window to overlay window */ 2310 + win->type = DRM_PLANE_TYPE_OVERLAY; 2311 + } 2312 + } 2313 + 2314 + if (win->type == DRM_PLANE_TYPE_OVERLAY) 2315 + possible_crtcs = (1 << nvps) - 1; 2316 + 2317 + ret = vop2_plane_init(vop2, win, possible_crtcs); 2318 + if (ret) { 2319 + drm_err(vop2->drm, "failed to init plane %s: %d\n", 2320 + win->data->name, ret); 2321 + return ret; 2322 + } 2323 + } 2324 + 2325 + for (i = 0; i < vop2_data->nr_vps; i++) { 2326 + vp = &vop2->vps[i]; 2327 + 2328 + if (!vp->crtc.port) 2329 + continue; 2330 + 2331 + plane = &vp->primary_plane->base; 2332 + 2333 + ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL, 2334 + &vop2_crtc_funcs, 2335 + "video_port%d", vp->id); 2336 + if (ret) { 2337 + drm_err(vop2->drm, "crtc init for video_port%d failed\n", i); 2338 + return ret; 2339 + } 2340 + 2341 + drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs); 2342 + 2343 + init_completion(&vp->dsp_hold_completion); 2344 + } 2345 + 2346 + /* 2347 + * On the VOP2 it's very hard to change the number of layers on a VP 2348 + * during runtime, so we distribute the layers equally over the used 2349 + * VPs 2350 + */ 2351 + for (i = 0; i < vop2->data->nr_vps; i++) { 2352 + struct vop2_video_port *vp = &vop2->vps[i]; 2353 + 2354 + if (vp->crtc.port) 2355 + vp->nlayers = NR_LAYERS / nvps; 2356 + } 2357 + 2358 + return 0; 2359 + } 2360 + 2361 + static void vop2_destroy_crtc(struct drm_crtc *crtc) 2362 + { 2363 + of_node_put(crtc->port); 2364 + 2365 + /* 2366 + * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane() 2367 + * references the CRTC. 2368 + */ 2369 + drm_crtc_cleanup(crtc); 2370 + } 2371 + 2372 + static struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] = { 2373 + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0), 2374 + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5), 2375 + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14), 2376 + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 18, 18), 2377 + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_ACT_INFO, 0, 31), 2378 + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_INFO, 0, 31), 2379 + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_ST, 0, 31), 2380 + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_CLUSTER_WIN_YRGB_MST, 0, 31), 2381 + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_CLUSTER_WIN_CBR_MST, 0, 31), 2382 + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 19, 19), 2383 + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 0, 15), 2384 + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 16, 31), 2385 + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 8, 8), 2386 + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 9, 9), 2387 + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 10, 11), 2388 + 2389 + /* Scale */ 2390 + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0, 15), 2391 + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 16, 31), 2392 + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 14, 15), 2393 + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 12, 13), 2394 + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 2, 3), 2395 + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 28, 28), 2396 + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 29, 29), 2397 + 2398 + /* cluster regs */ 2399 + [VOP2_WIN_AFBC_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 1, 1), 2400 + [VOP2_WIN_CLUSTER_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 0, 0), 2401 + [VOP2_WIN_CLUSTER_LB_MODE] = REG_FIELD(RK3568_CLUSTER_CTRL, 4, 7), 2402 + 2403 + /* afbc regs */ 2404 + [VOP2_WIN_AFBC_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 2, 6), 2405 + [VOP2_WIN_AFBC_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 9, 9), 2406 + [VOP2_WIN_AFBC_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 10, 10), 2407 + [VOP2_WIN_AFBC_AUTO_GATING_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 4, 4), 2408 + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 7, 7), 2409 + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 8, 8), 2410 + [VOP2_WIN_AFBC_HDR_PTR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0, 31), 2411 + [VOP2_WIN_AFBC_PIC_SIZE] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0, 31), 2412 + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0, 15), 2413 + [VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31), 2414 + [VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31), 2415 + [VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31), 2416 + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31), 2417 + [VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0), 2418 + [VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1), 2419 + [VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2), 2420 + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 3, 3), 2421 + [VOP2_WIN_UV_SWAP] = { .reg = 0xffffffff }, 2422 + [VOP2_WIN_COLOR_KEY] = { .reg = 0xffffffff }, 2423 + [VOP2_WIN_COLOR_KEY_EN] = { .reg = 0xffffffff }, 2424 + [VOP2_WIN_SCALE_CBCR_X] = { .reg = 0xffffffff }, 2425 + [VOP2_WIN_SCALE_CBCR_Y] = { .reg = 0xffffffff }, 2426 + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, 2427 + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, 2428 + [VOP2_WIN_CBCR_VER_SCL_MODE] = { .reg = 0xffffffff }, 2429 + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, 2430 + [VOP2_WIN_CBCR_HOR_SCL_MODE] = { .reg = 0xffffffff }, 2431 + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, 2432 + [VOP2_WIN_VSD_CBCR_GT2] = { .reg = 0xffffffff }, 2433 + [VOP2_WIN_VSD_CBCR_GT4] = { .reg = 0xffffffff }, 2434 + }; 2435 + 2436 + static int vop2_cluster_init(struct vop2_win *win) 2437 + { 2438 + struct vop2 *vop2 = win->vop2; 2439 + struct reg_field *cluster_regs; 2440 + int ret, i; 2441 + 2442 + cluster_regs = kmemdup(vop2_cluster_regs, sizeof(vop2_cluster_regs), 2443 + GFP_KERNEL); 2444 + if (!cluster_regs) 2445 + return -ENOMEM; 2446 + 2447 + for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++) 2448 + if (cluster_regs[i].reg != 0xffffffff) 2449 + cluster_regs[i].reg += win->offset; 2450 + 2451 + ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg, 2452 + cluster_regs, 2453 + ARRAY_SIZE(vop2_cluster_regs)); 2454 + 2455 + kfree(cluster_regs); 2456 + 2457 + return ret; 2458 + }; 2459 + 2460 + static struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] = { 2461 + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0), 2462 + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5), 2463 + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12), 2464 + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 14, 14), 2465 + [VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 16, 16), 2466 + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_SMART_REGION0_ACT_INFO, 0, 31), 2467 + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_SMART_REGION0_DSP_INFO, 0, 31), 2468 + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_SMART_REGION0_DSP_ST, 0, 28), 2469 + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_SMART_REGION0_YRGB_MST, 0, 31), 2470 + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_SMART_REGION0_CBR_MST, 0, 31), 2471 + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 17, 17), 2472 + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 0, 15), 2473 + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 16, 31), 2474 + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_SMART_CTRL0, 0, 0), 2475 + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_SMART_CTRL0, 1, 1), 2476 + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_SMART_CTRL0, 2, 3), 2477 + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_SMART_CTRL1, 31, 31), 2478 + [VOP2_WIN_COLOR_KEY] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 0, 29), 2479 + [VOP2_WIN_COLOR_KEY_EN] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 31, 31), 2480 + 2481 + /* Scale */ 2482 + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0, 15), 2483 + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 16, 31), 2484 + [VOP2_WIN_SCALE_CBCR_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0, 15), 2485 + [VOP2_WIN_SCALE_CBCR_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 16, 31), 2486 + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 0, 1), 2487 + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 2, 3), 2488 + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 4, 5), 2489 + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 6, 7), 2490 + [VOP2_WIN_CBCR_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 8, 9), 2491 + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 10, 11), 2492 + [VOP2_WIN_CBCR_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 12, 13), 2493 + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 14, 15), 2494 + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 16, 17), 2495 + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 8, 8), 2496 + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 9, 9), 2497 + [VOP2_WIN_VSD_CBCR_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 10, 10), 2498 + [VOP2_WIN_VSD_CBCR_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 11, 11), 2499 + [VOP2_WIN_XMIRROR] = { .reg = 0xffffffff }, 2500 + [VOP2_WIN_CLUSTER_ENABLE] = { .reg = 0xffffffff }, 2501 + [VOP2_WIN_AFBC_ENABLE] = { .reg = 0xffffffff }, 2502 + [VOP2_WIN_CLUSTER_LB_MODE] = { .reg = 0xffffffff }, 2503 + [VOP2_WIN_AFBC_FORMAT] = { .reg = 0xffffffff }, 2504 + [VOP2_WIN_AFBC_RB_SWAP] = { .reg = 0xffffffff }, 2505 + [VOP2_WIN_AFBC_UV_SWAP] = { .reg = 0xffffffff }, 2506 + [VOP2_WIN_AFBC_AUTO_GATING_EN] = { .reg = 0xffffffff }, 2507 + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = { .reg = 0xffffffff }, 2508 + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = { .reg = 0xffffffff }, 2509 + [VOP2_WIN_AFBC_TILE_NUM] = { .reg = 0xffffffff }, 2510 + [VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff }, 2511 + [VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff }, 2512 + [VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff }, 2513 + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff }, 2514 + [VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff }, 2515 + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff }, 2516 + [VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff }, 2517 + [VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff }, 2518 + }; 2519 + 2520 + static int vop2_esmart_init(struct vop2_win *win) 2521 + { 2522 + struct vop2 *vop2 = win->vop2; 2523 + struct reg_field *esmart_regs; 2524 + int ret, i; 2525 + 2526 + esmart_regs = kmemdup(vop2_esmart_regs, sizeof(vop2_esmart_regs), 2527 + GFP_KERNEL); 2528 + if (!esmart_regs) 2529 + return -ENOMEM; 2530 + 2531 + for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++) 2532 + if (esmart_regs[i].reg != 0xffffffff) 2533 + esmart_regs[i].reg += win->offset; 2534 + 2535 + ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg, 2536 + esmart_regs, 2537 + ARRAY_SIZE(vop2_esmart_regs)); 2538 + 2539 + kfree(esmart_regs); 2540 + 2541 + return ret; 2542 + }; 2543 + 2544 + static int vop2_win_init(struct vop2 *vop2) 2545 + { 2546 + const struct vop2_data *vop2_data = vop2->data; 2547 + struct vop2_win *win; 2548 + int i, ret; 2549 + 2550 + for (i = 0; i < vop2_data->win_size; i++) { 2551 + const struct vop2_win_data *win_data = &vop2_data->win[i]; 2552 + 2553 + win = &vop2->win[i]; 2554 + win->data = win_data; 2555 + win->type = win_data->type; 2556 + win->offset = win_data->base; 2557 + win->win_id = i; 2558 + win->vop2 = vop2; 2559 + if (vop2_cluster_window(win)) 2560 + ret = vop2_cluster_init(win); 2561 + else 2562 + ret = vop2_esmart_init(win); 2563 + if (ret) 2564 + return ret; 2565 + } 2566 + 2567 + vop2->registered_num_wins = vop2_data->win_size; 2568 + 2569 + return 0; 2570 + } 2571 + 2572 + /* 2573 + * The window registers are only updated when config done is written. 2574 + * Until that they read back the old value. As we read-modify-write 2575 + * these registers mark them as non-volatile. This makes sure we read 2576 + * the new values from the regmap register cache. 2577 + */ 2578 + static const struct regmap_range vop2_nonvolatile_range[] = { 2579 + regmap_reg_range(0x1000, 0x23ff), 2580 + }; 2581 + 2582 + static const struct regmap_access_table vop2_volatile_table = { 2583 + .no_ranges = vop2_nonvolatile_range, 2584 + .n_no_ranges = ARRAY_SIZE(vop2_nonvolatile_range), 2585 + }; 2586 + 2587 + static const struct regmap_config vop2_regmap_config = { 2588 + .reg_bits = 32, 2589 + .val_bits = 32, 2590 + .reg_stride = 4, 2591 + .max_register = 0x3000, 2592 + .name = "vop2", 2593 + .volatile_table = &vop2_volatile_table, 2594 + .cache_type = REGCACHE_RBTREE, 2595 + }; 2596 + 2597 + static int vop2_bind(struct device *dev, struct device *master, void *data) 2598 + { 2599 + struct platform_device *pdev = to_platform_device(dev); 2600 + const struct vop2_data *vop2_data; 2601 + struct drm_device *drm = data; 2602 + struct vop2 *vop2; 2603 + struct resource *res; 2604 + size_t alloc_size; 2605 + int ret; 2606 + 2607 + vop2_data = of_device_get_match_data(dev); 2608 + if (!vop2_data) 2609 + return -ENODEV; 2610 + 2611 + /* Allocate vop2 struct and its vop2_win array */ 2612 + alloc_size = sizeof(*vop2) + sizeof(*vop2->win) * vop2_data->win_size; 2613 + vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL); 2614 + if (!vop2) 2615 + return -ENOMEM; 2616 + 2617 + vop2->dev = dev; 2618 + vop2->data = vop2_data; 2619 + vop2->drm = drm; 2620 + 2621 + dev_set_drvdata(dev, vop2); 2622 + 2623 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); 2624 + if (!res) { 2625 + drm_err(vop2->drm, "failed to get vop2 register byname\n"); 2626 + return -EINVAL; 2627 + } 2628 + 2629 + vop2->regs = devm_ioremap_resource(dev, res); 2630 + if (IS_ERR(vop2->regs)) 2631 + return PTR_ERR(vop2->regs); 2632 + vop2->len = resource_size(res); 2633 + 2634 + vop2->map = devm_regmap_init_mmio(dev, vop2->regs, &vop2_regmap_config); 2635 + 2636 + ret = vop2_win_init(vop2); 2637 + if (ret) 2638 + return ret; 2639 + 2640 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma_lut"); 2641 + if (res) { 2642 + vop2->lut_regs = devm_ioremap_resource(dev, res); 2643 + if (IS_ERR(vop2->lut_regs)) 2644 + return PTR_ERR(vop2->lut_regs); 2645 + } 2646 + 2647 + vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); 2648 + 2649 + vop2->hclk = devm_clk_get(vop2->dev, "hclk"); 2650 + if (IS_ERR(vop2->hclk)) { 2651 + drm_err(vop2->drm, "failed to get hclk source\n"); 2652 + return PTR_ERR(vop2->hclk); 2653 + } 2654 + 2655 + vop2->aclk = devm_clk_get(vop2->dev, "aclk"); 2656 + if (IS_ERR(vop2->aclk)) { 2657 + drm_err(vop2->drm, "failed to get aclk source\n"); 2658 + return PTR_ERR(vop2->aclk); 2659 + } 2660 + 2661 + vop2->irq = platform_get_irq(pdev, 0); 2662 + if (vop2->irq < 0) { 2663 + drm_err(vop2->drm, "cannot find irq for vop2\n"); 2664 + return vop2->irq; 2665 + } 2666 + 2667 + mutex_init(&vop2->vop2_lock); 2668 + 2669 + ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2); 2670 + if (ret) 2671 + return ret; 2672 + 2673 + ret = vop2_create_crtc(vop2); 2674 + if (ret) 2675 + return ret; 2676 + 2677 + rockchip_drm_dma_init_device(vop2->drm, vop2->dev); 2678 + 2679 + pm_runtime_enable(&pdev->dev); 2680 + 2681 + return 0; 2682 + } 2683 + 2684 + static void vop2_unbind(struct device *dev, struct device *master, void *data) 2685 + { 2686 + struct vop2 *vop2 = dev_get_drvdata(dev); 2687 + struct drm_device *drm = vop2->drm; 2688 + struct list_head *plane_list = &drm->mode_config.plane_list; 2689 + struct list_head *crtc_list = &drm->mode_config.crtc_list; 2690 + struct drm_crtc *crtc, *tmpc; 2691 + struct drm_plane *plane, *tmpp; 2692 + 2693 + pm_runtime_disable(dev); 2694 + 2695 + list_for_each_entry_safe(plane, tmpp, plane_list, head) 2696 + drm_plane_cleanup(plane); 2697 + 2698 + list_for_each_entry_safe(crtc, tmpc, crtc_list, head) 2699 + vop2_destroy_crtc(crtc); 2700 + } 2701 + 2702 + const struct component_ops vop2_component_ops = { 2703 + .bind = vop2_bind, 2704 + .unbind = vop2_unbind, 2705 + }; 2706 + EXPORT_SYMBOL_GPL(vop2_component_ops);
+477
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
··· 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 + #ifndef _ROCKCHIP_DRM_VOP2_H 8 + #define _ROCKCHIP_DRM_VOP2_H 9 + 10 + #include "rockchip_drm_vop.h" 11 + 12 + #include <linux/regmap.h> 13 + #include <drm/drm_modes.h> 14 + 15 + #define VOP_FEATURE_OUTPUT_10BIT BIT(0) 16 + 17 + #define WIN_FEATURE_AFBDC BIT(0) 18 + #define WIN_FEATURE_CLUSTER BIT(1) 19 + 20 + /* 21 + * the delay number of a window in different mode. 22 + */ 23 + enum win_dly_mode { 24 + VOP2_DLY_MODE_DEFAULT, /**< default mode */ 25 + VOP2_DLY_MODE_HISO_S, /** HDR in SDR out mode, as a SDR window */ 26 + VOP2_DLY_MODE_HIHO_H, /** HDR in HDR out mode, as a HDR window */ 27 + VOP2_DLY_MODE_MAX, 28 + }; 29 + 30 + struct vop_rect { 31 + int width; 32 + int height; 33 + }; 34 + 35 + enum vop2_scale_up_mode { 36 + VOP2_SCALE_UP_NRST_NBOR, 37 + VOP2_SCALE_UP_BIL, 38 + VOP2_SCALE_UP_BIC, 39 + }; 40 + 41 + enum vop2_scale_down_mode { 42 + VOP2_SCALE_DOWN_NRST_NBOR, 43 + VOP2_SCALE_DOWN_BIL, 44 + VOP2_SCALE_DOWN_AVG, 45 + }; 46 + 47 + enum vop2_win_regs { 48 + VOP2_WIN_ENABLE, 49 + VOP2_WIN_FORMAT, 50 + VOP2_WIN_CSC_MODE, 51 + VOP2_WIN_XMIRROR, 52 + VOP2_WIN_YMIRROR, 53 + VOP2_WIN_RB_SWAP, 54 + VOP2_WIN_UV_SWAP, 55 + VOP2_WIN_ACT_INFO, 56 + VOP2_WIN_DSP_INFO, 57 + VOP2_WIN_DSP_ST, 58 + VOP2_WIN_YRGB_MST, 59 + VOP2_WIN_UV_MST, 60 + VOP2_WIN_YRGB_VIR, 61 + VOP2_WIN_UV_VIR, 62 + VOP2_WIN_YUV_CLIP, 63 + VOP2_WIN_Y2R_EN, 64 + VOP2_WIN_R2Y_EN, 65 + VOP2_WIN_COLOR_KEY, 66 + VOP2_WIN_COLOR_KEY_EN, 67 + VOP2_WIN_DITHER_UP, 68 + 69 + /* scale regs */ 70 + VOP2_WIN_SCALE_YRGB_X, 71 + VOP2_WIN_SCALE_YRGB_Y, 72 + VOP2_WIN_SCALE_CBCR_X, 73 + VOP2_WIN_SCALE_CBCR_Y, 74 + VOP2_WIN_YRGB_HOR_SCL_MODE, 75 + VOP2_WIN_YRGB_HSCL_FILTER_MODE, 76 + VOP2_WIN_YRGB_VER_SCL_MODE, 77 + VOP2_WIN_YRGB_VSCL_FILTER_MODE, 78 + VOP2_WIN_CBCR_VER_SCL_MODE, 79 + VOP2_WIN_CBCR_HSCL_FILTER_MODE, 80 + VOP2_WIN_CBCR_HOR_SCL_MODE, 81 + VOP2_WIN_CBCR_VSCL_FILTER_MODE, 82 + VOP2_WIN_VSD_CBCR_GT2, 83 + VOP2_WIN_VSD_CBCR_GT4, 84 + VOP2_WIN_VSD_YRGB_GT2, 85 + VOP2_WIN_VSD_YRGB_GT4, 86 + VOP2_WIN_BIC_COE_SEL, 87 + 88 + /* cluster regs */ 89 + VOP2_WIN_CLUSTER_ENABLE, 90 + VOP2_WIN_AFBC_ENABLE, 91 + VOP2_WIN_CLUSTER_LB_MODE, 92 + 93 + /* afbc regs */ 94 + VOP2_WIN_AFBC_FORMAT, 95 + VOP2_WIN_AFBC_RB_SWAP, 96 + VOP2_WIN_AFBC_UV_SWAP, 97 + VOP2_WIN_AFBC_AUTO_GATING_EN, 98 + VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 99 + VOP2_WIN_AFBC_PIC_VIR_WIDTH, 100 + VOP2_WIN_AFBC_TILE_NUM, 101 + VOP2_WIN_AFBC_PIC_OFFSET, 102 + VOP2_WIN_AFBC_PIC_SIZE, 103 + VOP2_WIN_AFBC_DSP_OFFSET, 104 + VOP2_WIN_AFBC_TRANSFORM_OFFSET, 105 + VOP2_WIN_AFBC_HDR_PTR, 106 + VOP2_WIN_AFBC_HALF_BLOCK_EN, 107 + VOP2_WIN_AFBC_ROTATE_270, 108 + VOP2_WIN_AFBC_ROTATE_90, 109 + VOP2_WIN_MAX_REG, 110 + }; 111 + 112 + struct vop2_win_data { 113 + const char *name; 114 + unsigned int phys_id; 115 + 116 + u32 base; 117 + enum drm_plane_type type; 118 + 119 + u32 nformats; 120 + const u32 *formats; 121 + const uint64_t *format_modifiers; 122 + const unsigned int supported_rotations; 123 + 124 + /** 125 + * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2 126 + */ 127 + unsigned int layer_sel_id; 128 + uint64_t feature; 129 + 130 + unsigned int max_upscale_factor; 131 + unsigned int max_downscale_factor; 132 + const u8 dly[VOP2_DLY_MODE_MAX]; 133 + }; 134 + 135 + struct vop2_video_port_data { 136 + unsigned int id; 137 + u32 feature; 138 + u16 gamma_lut_len; 139 + u16 cubic_lut_len; 140 + struct vop_rect max_output; 141 + const u8 pre_scan_max_dly[4]; 142 + const struct vop2_video_port_regs *regs; 143 + unsigned int offset; 144 + }; 145 + 146 + struct vop2_data { 147 + u8 nr_vps; 148 + const struct vop2_ctrl *ctrl; 149 + const struct vop2_win_data *win; 150 + const struct vop2_video_port_data *vp; 151 + const struct vop_csc_table *csc_table; 152 + struct vop_rect max_input; 153 + struct vop_rect max_output; 154 + 155 + unsigned int win_size; 156 + unsigned int soc_id; 157 + }; 158 + 159 + /* interrupt define */ 160 + #define FS_NEW_INTR BIT(4) 161 + #define ADDR_SAME_INTR BIT(5) 162 + #define LINE_FLAG1_INTR BIT(6) 163 + #define WIN0_EMPTY_INTR BIT(7) 164 + #define WIN1_EMPTY_INTR BIT(8) 165 + #define WIN2_EMPTY_INTR BIT(9) 166 + #define WIN3_EMPTY_INTR BIT(10) 167 + #define HWC_EMPTY_INTR BIT(11) 168 + #define POST_BUF_EMPTY_INTR BIT(12) 169 + #define PWM_GEN_INTR BIT(13) 170 + #define DMA_FINISH_INTR BIT(14) 171 + #define FS_FIELD_INTR BIT(15) 172 + #define FE_INTR BIT(16) 173 + #define WB_UV_FIFO_FULL_INTR BIT(17) 174 + #define WB_YRGB_FIFO_FULL_INTR BIT(18) 175 + #define WB_COMPLETE_INTR BIT(19) 176 + 177 + /* 178 + * display output interface supported by rockchip lcdc 179 + */ 180 + #define ROCKCHIP_OUT_MODE_P888 0 181 + #define ROCKCHIP_OUT_MODE_BT1120 0 182 + #define ROCKCHIP_OUT_MODE_P666 1 183 + #define ROCKCHIP_OUT_MODE_P565 2 184 + #define ROCKCHIP_OUT_MODE_BT656 5 185 + #define ROCKCHIP_OUT_MODE_S888 8 186 + #define ROCKCHIP_OUT_MODE_S888_DUMMY 12 187 + #define ROCKCHIP_OUT_MODE_YUV420 14 188 + /* for use special outface */ 189 + #define ROCKCHIP_OUT_MODE_AAAA 15 190 + 191 + enum vop_csc_format { 192 + CSC_BT601L, 193 + CSC_BT709L, 194 + CSC_BT601F, 195 + CSC_BT2020, 196 + }; 197 + 198 + enum src_factor_mode { 199 + SRC_FAC_ALPHA_ZERO, 200 + SRC_FAC_ALPHA_ONE, 201 + SRC_FAC_ALPHA_DST, 202 + SRC_FAC_ALPHA_DST_INVERSE, 203 + SRC_FAC_ALPHA_SRC, 204 + SRC_FAC_ALPHA_SRC_GLOBAL, 205 + }; 206 + 207 + enum dst_factor_mode { 208 + DST_FAC_ALPHA_ZERO, 209 + DST_FAC_ALPHA_ONE, 210 + DST_FAC_ALPHA_SRC, 211 + DST_FAC_ALPHA_SRC_INVERSE, 212 + DST_FAC_ALPHA_DST, 213 + DST_FAC_ALPHA_DST_GLOBAL, 214 + }; 215 + 216 + #define RK3568_GRF_VO_CON1 0x0364 217 + /* System registers definition */ 218 + #define RK3568_REG_CFG_DONE 0x000 219 + #define RK3568_VERSION_INFO 0x004 220 + #define RK3568_SYS_AUTO_GATING_CTRL 0x008 221 + #define RK3568_SYS_AXI_LUT_CTRL 0x024 222 + #define RK3568_DSP_IF_EN 0x028 223 + #define RK3568_DSP_IF_CTRL 0x02c 224 + #define RK3568_DSP_IF_POL 0x030 225 + #define RK3568_WB_CTRL 0x40 226 + #define RK3568_WB_XSCAL_FACTOR 0x44 227 + #define RK3568_WB_YRGB_MST 0x48 228 + #define RK3568_WB_CBR_MST 0x4C 229 + #define RK3568_OTP_WIN_EN 0x050 230 + #define RK3568_LUT_PORT_SEL 0x058 231 + #define RK3568_SYS_STATUS0 0x060 232 + #define RK3568_VP_LINE_FLAG(vp) (0x70 + (vp) * 0x4) 233 + #define RK3568_SYS0_INT_EN 0x80 234 + #define RK3568_SYS0_INT_CLR 0x84 235 + #define RK3568_SYS0_INT_STATUS 0x88 236 + #define RK3568_SYS1_INT_EN 0x90 237 + #define RK3568_SYS1_INT_CLR 0x94 238 + #define RK3568_SYS1_INT_STATUS 0x98 239 + #define RK3568_VP_INT_EN(vp) (0xA0 + (vp) * 0x10) 240 + #define RK3568_VP_INT_CLR(vp) (0xA4 + (vp) * 0x10) 241 + #define RK3568_VP_INT_STATUS(vp) (0xA8 + (vp) * 0x10) 242 + #define RK3568_VP_INT_RAW_STATUS(vp) (0xAC + (vp) * 0x10) 243 + 244 + /* Video Port registers definition */ 245 + #define RK3568_VP_DSP_CTRL 0x00 246 + #define RK3568_VP_MIPI_CTRL 0x04 247 + #define RK3568_VP_COLOR_BAR_CTRL 0x08 248 + #define RK3568_VP_3D_LUT_CTRL 0x10 249 + #define RK3568_VP_3D_LUT_MST 0x20 250 + #define RK3568_VP_DSP_BG 0x2C 251 + #define RK3568_VP_PRE_SCAN_HTIMING 0x30 252 + #define RK3568_VP_POST_DSP_HACT_INFO 0x34 253 + #define RK3568_VP_POST_DSP_VACT_INFO 0x38 254 + #define RK3568_VP_POST_SCL_FACTOR_YRGB 0x3C 255 + #define RK3568_VP_POST_SCL_CTRL 0x40 256 + #define RK3568_VP_POST_DSP_VACT_INFO_F1 0x44 257 + #define RK3568_VP_DSP_HTOTAL_HS_END 0x48 258 + #define RK3568_VP_DSP_HACT_ST_END 0x4C 259 + #define RK3568_VP_DSP_VTOTAL_VS_END 0x50 260 + #define RK3568_VP_DSP_VACT_ST_END 0x54 261 + #define RK3568_VP_DSP_VS_ST_END_F1 0x58 262 + #define RK3568_VP_DSP_VACT_ST_END_F1 0x5C 263 + #define RK3568_VP_BCSH_CTRL 0x60 264 + #define RK3568_VP_BCSH_BCS 0x64 265 + #define RK3568_VP_BCSH_H 0x68 266 + #define RK3568_VP_BCSH_COLOR_BAR 0x6C 267 + 268 + /* Overlay registers definition */ 269 + #define RK3568_OVL_CTRL 0x600 270 + #define RK3568_OVL_LAYER_SEL 0x604 271 + #define RK3568_OVL_PORT_SEL 0x608 272 + #define RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL 0x610 273 + #define RK3568_CLUSTER0_MIX_DST_COLOR_CTRL 0x614 274 + #define RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL 0x618 275 + #define RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL 0x61C 276 + #define RK3568_MIX0_SRC_COLOR_CTRL 0x650 277 + #define RK3568_MIX0_DST_COLOR_CTRL 0x654 278 + #define RK3568_MIX0_SRC_ALPHA_CTRL 0x658 279 + #define RK3568_MIX0_DST_ALPHA_CTRL 0x65C 280 + #define RK3568_HDR0_SRC_COLOR_CTRL 0x6C0 281 + #define RK3568_HDR0_DST_COLOR_CTRL 0x6C4 282 + #define RK3568_HDR0_SRC_ALPHA_CTRL 0x6C8 283 + #define RK3568_HDR0_DST_ALPHA_CTRL 0x6CC 284 + #define RK3568_VP_BG_MIX_CTRL(vp) (0x6E0 + (vp) * 4) 285 + #define RK3568_CLUSTER_DLY_NUM 0x6F0 286 + #define RK3568_SMART_DLY_NUM 0x6F8 287 + 288 + /* Cluster register definition, offset relative to window base */ 289 + #define RK3568_CLUSTER_WIN_CTRL0 0x00 290 + #define RK3568_CLUSTER_WIN_CTRL1 0x04 291 + #define RK3568_CLUSTER_WIN_YRGB_MST 0x10 292 + #define RK3568_CLUSTER_WIN_CBR_MST 0x14 293 + #define RK3568_CLUSTER_WIN_VIR 0x18 294 + #define RK3568_CLUSTER_WIN_ACT_INFO 0x20 295 + #define RK3568_CLUSTER_WIN_DSP_INFO 0x24 296 + #define RK3568_CLUSTER_WIN_DSP_ST 0x28 297 + #define RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB 0x30 298 + #define RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET 0x3C 299 + #define RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL 0x50 300 + #define RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE 0x54 301 + #define RK3568_CLUSTER_WIN_AFBCD_HDR_PTR 0x58 302 + #define RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH 0x5C 303 + #define RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE 0x60 304 + #define RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET 0x64 305 + #define RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET 0x68 306 + #define RK3568_CLUSTER_WIN_AFBCD_CTRL 0x6C 307 + 308 + #define RK3568_CLUSTER_CTRL 0x100 309 + 310 + /* (E)smart register definition, offset relative to window base */ 311 + #define RK3568_SMART_CTRL0 0x00 312 + #define RK3568_SMART_CTRL1 0x04 313 + #define RK3568_SMART_REGION0_CTRL 0x10 314 + #define RK3568_SMART_REGION0_YRGB_MST 0x14 315 + #define RK3568_SMART_REGION0_CBR_MST 0x18 316 + #define RK3568_SMART_REGION0_VIR 0x1C 317 + #define RK3568_SMART_REGION0_ACT_INFO 0x20 318 + #define RK3568_SMART_REGION0_DSP_INFO 0x24 319 + #define RK3568_SMART_REGION0_DSP_ST 0x28 320 + #define RK3568_SMART_REGION0_SCL_CTRL 0x30 321 + #define RK3568_SMART_REGION0_SCL_FACTOR_YRGB 0x34 322 + #define RK3568_SMART_REGION0_SCL_FACTOR_CBR 0x38 323 + #define RK3568_SMART_REGION0_SCL_OFFSET 0x3C 324 + #define RK3568_SMART_REGION1_CTRL 0x40 325 + #define RK3568_SMART_REGION1_YRGB_MST 0x44 326 + #define RK3568_SMART_REGION1_CBR_MST 0x48 327 + #define RK3568_SMART_REGION1_VIR 0x4C 328 + #define RK3568_SMART_REGION1_ACT_INFO 0x50 329 + #define RK3568_SMART_REGION1_DSP_INFO 0x54 330 + #define RK3568_SMART_REGION1_DSP_ST 0x58 331 + #define RK3568_SMART_REGION1_SCL_CTRL 0x60 332 + #define RK3568_SMART_REGION1_SCL_FACTOR_YRGB 0x64 333 + #define RK3568_SMART_REGION1_SCL_FACTOR_CBR 0x68 334 + #define RK3568_SMART_REGION1_SCL_OFFSET 0x6C 335 + #define RK3568_SMART_REGION2_CTRL 0x70 336 + #define RK3568_SMART_REGION2_YRGB_MST 0x74 337 + #define RK3568_SMART_REGION2_CBR_MST 0x78 338 + #define RK3568_SMART_REGION2_VIR 0x7C 339 + #define RK3568_SMART_REGION2_ACT_INFO 0x80 340 + #define RK3568_SMART_REGION2_DSP_INFO 0x84 341 + #define RK3568_SMART_REGION2_DSP_ST 0x88 342 + #define RK3568_SMART_REGION2_SCL_CTRL 0x90 343 + #define RK3568_SMART_REGION2_SCL_FACTOR_YRGB 0x94 344 + #define RK3568_SMART_REGION2_SCL_FACTOR_CBR 0x98 345 + #define RK3568_SMART_REGION2_SCL_OFFSET 0x9C 346 + #define RK3568_SMART_REGION3_CTRL 0xA0 347 + #define RK3568_SMART_REGION3_YRGB_MST 0xA4 348 + #define RK3568_SMART_REGION3_CBR_MST 0xA8 349 + #define RK3568_SMART_REGION3_VIR 0xAC 350 + #define RK3568_SMART_REGION3_ACT_INFO 0xB0 351 + #define RK3568_SMART_REGION3_DSP_INFO 0xB4 352 + #define RK3568_SMART_REGION3_DSP_ST 0xB8 353 + #define RK3568_SMART_REGION3_SCL_CTRL 0xC0 354 + #define RK3568_SMART_REGION3_SCL_FACTOR_YRGB 0xC4 355 + #define RK3568_SMART_REGION3_SCL_FACTOR_CBR 0xC8 356 + #define RK3568_SMART_REGION3_SCL_OFFSET 0xCC 357 + #define RK3568_SMART_COLOR_KEY_CTRL 0xD0 358 + 359 + /* HDR register definition */ 360 + #define RK3568_HDR_LUT_CTRL 0x2000 361 + #define RK3568_HDR_LUT_MST 0x2004 362 + #define RK3568_SDR2HDR_CTRL 0x2010 363 + #define RK3568_HDR2SDR_CTRL 0x2020 364 + #define RK3568_HDR2SDR_SRC_RANGE 0x2024 365 + #define RK3568_HDR2SDR_NORMFACEETF 0x2028 366 + #define RK3568_HDR2SDR_DST_RANGE 0x202C 367 + #define RK3568_HDR2SDR_NORMFACCGAMMA 0x2030 368 + #define RK3568_HDR_EETF_OETF_Y0 0x203C 369 + #define RK3568_HDR_SAT_Y0 0x20C0 370 + #define RK3568_HDR_EOTF_OETF_Y0 0x20F0 371 + #define RK3568_HDR_OETF_DX_POW1 0x2200 372 + #define RK3568_HDR_OETF_XN1 0x2300 373 + 374 + #define RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN BIT(15) 375 + 376 + #define RK3568_VP_DSP_CTRL__STANDBY BIT(31) 377 + #define RK3568_VP_DSP_CTRL__DITHER_DOWN_MODE BIT(20) 378 + #define RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL GENMASK(19, 18) 379 + #define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN BIT(17) 380 + #define RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN BIT(16) 381 + #define RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y BIT(15) 382 + #define RK3568_VP_DSP_CTRL__DSP_RB_SWAP BIT(9) 383 + #define RK3568_VP_DSP_CTRL__DSP_INTERLACE BIT(7) 384 + #define RK3568_VP_DSP_CTRL__DSP_FILED_POL BIT(6) 385 + #define RK3568_VP_DSP_CTRL__P2I_EN BIT(5) 386 + #define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV BIT(4) 387 + #define RK3568_VP_DSP_CTRL__OUT_MODE GENMASK(3, 0) 388 + 389 + #define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN BIT(1) 390 + #define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN BIT(0) 391 + 392 + #define RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX GENMASK(26, 25) 393 + #define RK3568_SYS_DSP_INFACE_EN_LVDS1 BIT(24) 394 + #define RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX GENMASK(22, 21) 395 + #define RK3568_SYS_DSP_INFACE_EN_MIPI1 BIT(20) 396 + #define RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX GENMASK(19, 18) 397 + #define RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX GENMASK(17, 16) 398 + #define RK3568_SYS_DSP_INFACE_EN_EDP_MUX GENMASK(15, 14) 399 + #define RK3568_SYS_DSP_INFACE_EN_HDMI_MUX GENMASK(11, 10) 400 + #define RK3568_SYS_DSP_INFACE_EN_RGB_MUX GENMASK(9, 8) 401 + #define RK3568_SYS_DSP_INFACE_EN_LVDS0 BIT(5) 402 + #define RK3568_SYS_DSP_INFACE_EN_MIPI0 BIT(4) 403 + #define RK3568_SYS_DSP_INFACE_EN_EDP BIT(3) 404 + #define RK3568_SYS_DSP_INFACE_EN_HDMI BIT(1) 405 + #define RK3568_SYS_DSP_INFACE_EN_RGB BIT(0) 406 + 407 + #define RK3568_DSP_IF_POL__MIPI_PIN_POL GENMASK(19, 16) 408 + #define RK3568_DSP_IF_POL__EDP_PIN_POL GENMASK(15, 12) 409 + #define RK3568_DSP_IF_POL__HDMI_PIN_POL GENMASK(7, 4) 410 + #define RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL GENMASK(3, 0) 411 + 412 + #define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK BIT(5) 413 + #define RK3568_VP0_MIPI_CTRL__DCLK_DIV2 BIT(4) 414 + 415 + #define RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN BIT(31) 416 + 417 + #define RK3568_DSP_IF_POL__CFG_DONE_IMD BIT(28) 418 + 419 + #define VOP2_SYS_AXI_BUS_NUM 2 420 + 421 + #define VOP2_CLUSTER_YUV444_10 0x12 422 + 423 + #define VOP2_COLOR_KEY_MASK BIT(31) 424 + 425 + #define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD BIT(28) 426 + 427 + #define RK3568_VP_BG_MIX_CTRL__BG_DLY GENMASK(31, 24) 428 + 429 + #define RK3568_OVL_PORT_SEL__SEL_PORT GENMASK(31, 16) 430 + #define RK3568_OVL_PORT_SEL__SMART1 GENMASK(31, 30) 431 + #define RK3568_OVL_PORT_SEL__SMART0 GENMASK(29, 28) 432 + #define RK3568_OVL_PORT_SEL__ESMART1 GENMASK(27, 26) 433 + #define RK3568_OVL_PORT_SEL__ESMART0 GENMASK(25, 24) 434 + #define RK3568_OVL_PORT_SEL__CLUSTER1 GENMASK(19, 18) 435 + #define RK3568_OVL_PORT_SEL__CLUSTER0 GENMASK(17, 16) 436 + #define RK3568_OVL_PORT_SET__PORT2_MUX GENMASK(11, 8) 437 + #define RK3568_OVL_PORT_SET__PORT1_MUX GENMASK(7, 4) 438 + #define RK3568_OVL_PORT_SET__PORT0_MUX GENMASK(3, 0) 439 + #define RK3568_OVL_LAYER_SEL__LAYER(layer, x) ((x) << ((layer) * 4)) 440 + 441 + #define RK3568_CLUSTER_DLY_NUM__CLUSTER1_1 GENMASK(31, 24) 442 + #define RK3568_CLUSTER_DLY_NUM__CLUSTER1_0 GENMASK(23, 16) 443 + #define RK3568_CLUSTER_DLY_NUM__CLUSTER0_1 GENMASK(15, 8) 444 + #define RK3568_CLUSTER_DLY_NUM__CLUSTER0_0 GENMASK(7, 0) 445 + 446 + #define RK3568_SMART_DLY_NUM__SMART1 GENMASK(31, 24) 447 + #define RK3568_SMART_DLY_NUM__SMART0 GENMASK(23, 16) 448 + #define RK3568_SMART_DLY_NUM__ESMART1 GENMASK(15, 8) 449 + #define RK3568_SMART_DLY_NUM__ESMART0 GENMASK(7, 0) 450 + 451 + #define VP_INT_DSP_HOLD_VALID BIT(6) 452 + #define VP_INT_FS_FIELD BIT(5) 453 + #define VP_INT_POST_BUF_EMPTY BIT(4) 454 + #define VP_INT_LINE_FLAG1 BIT(3) 455 + #define VP_INT_LINE_FLAG0 BIT(2) 456 + #define VOP2_INT_BUS_ERRPR BIT(1) 457 + #define VP_INT_FS BIT(0) 458 + 459 + #define POLFLAG_DCLK_INV BIT(3) 460 + 461 + enum vop2_layer_phy_id { 462 + ROCKCHIP_VOP2_CLUSTER0 = 0, 463 + ROCKCHIP_VOP2_CLUSTER1, 464 + ROCKCHIP_VOP2_ESMART0, 465 + ROCKCHIP_VOP2_ESMART1, 466 + ROCKCHIP_VOP2_SMART0, 467 + ROCKCHIP_VOP2_SMART1, 468 + ROCKCHIP_VOP2_CLUSTER2, 469 + ROCKCHIP_VOP2_CLUSTER3, 470 + ROCKCHIP_VOP2_ESMART2, 471 + ROCKCHIP_VOP2_ESMART3, 472 + ROCKCHIP_VOP2_PHY_ID_INVALID = -1, 473 + }; 474 + 475 + extern const struct component_ops vop2_component_ops; 476 + 477 + #endif /* _ROCKCHIP_DRM_VOP2_H */
+281
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) Rockchip Electronics Co.Ltd 4 + * Author: Andy Yan <andy.yan@rock-chips.com> 5 + */ 6 + 7 + #include <linux/kernel.h> 8 + #include <linux/component.h> 9 + #include <linux/mod_devicetable.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/of.h> 12 + #include <drm/drm_fourcc.h> 13 + #include <drm/drm_plane.h> 14 + #include <drm/drm_print.h> 15 + 16 + #include "rockchip_drm_vop2.h" 17 + 18 + static const uint32_t formats_win_full_10bit[] = { 19 + DRM_FORMAT_XRGB8888, 20 + DRM_FORMAT_ARGB8888, 21 + DRM_FORMAT_XBGR8888, 22 + DRM_FORMAT_ABGR8888, 23 + DRM_FORMAT_RGB888, 24 + DRM_FORMAT_BGR888, 25 + DRM_FORMAT_RGB565, 26 + DRM_FORMAT_BGR565, 27 + DRM_FORMAT_NV12, 28 + DRM_FORMAT_NV16, 29 + DRM_FORMAT_NV24, 30 + }; 31 + 32 + static const uint32_t formats_win_full_10bit_yuyv[] = { 33 + DRM_FORMAT_XRGB8888, 34 + DRM_FORMAT_ARGB8888, 35 + DRM_FORMAT_XBGR8888, 36 + DRM_FORMAT_ABGR8888, 37 + DRM_FORMAT_RGB888, 38 + DRM_FORMAT_BGR888, 39 + DRM_FORMAT_RGB565, 40 + DRM_FORMAT_BGR565, 41 + DRM_FORMAT_NV12, 42 + DRM_FORMAT_NV16, 43 + DRM_FORMAT_NV24, 44 + DRM_FORMAT_YVYU, 45 + DRM_FORMAT_VYUY, 46 + }; 47 + 48 + static const uint32_t formats_win_lite[] = { 49 + DRM_FORMAT_XRGB8888, 50 + DRM_FORMAT_ARGB8888, 51 + DRM_FORMAT_XBGR8888, 52 + DRM_FORMAT_ABGR8888, 53 + DRM_FORMAT_RGB888, 54 + DRM_FORMAT_BGR888, 55 + DRM_FORMAT_RGB565, 56 + DRM_FORMAT_BGR565, 57 + }; 58 + 59 + static const uint64_t format_modifiers[] = { 60 + DRM_FORMAT_MOD_LINEAR, 61 + DRM_FORMAT_MOD_INVALID, 62 + }; 63 + 64 + static const uint64_t format_modifiers_afbc[] = { 65 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16), 66 + 67 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 68 + AFBC_FORMAT_MOD_SPARSE), 69 + 70 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 71 + AFBC_FORMAT_MOD_YTR), 72 + 73 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 74 + AFBC_FORMAT_MOD_CBR), 75 + 76 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 77 + AFBC_FORMAT_MOD_YTR | 78 + AFBC_FORMAT_MOD_SPARSE), 79 + 80 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 81 + AFBC_FORMAT_MOD_CBR | 82 + AFBC_FORMAT_MOD_SPARSE), 83 + 84 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 85 + AFBC_FORMAT_MOD_YTR | 86 + AFBC_FORMAT_MOD_CBR), 87 + 88 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 89 + AFBC_FORMAT_MOD_YTR | 90 + AFBC_FORMAT_MOD_CBR | 91 + AFBC_FORMAT_MOD_SPARSE), 92 + 93 + /* SPLIT mandates SPARSE, RGB modes mandates YTR */ 94 + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 95 + AFBC_FORMAT_MOD_YTR | 96 + AFBC_FORMAT_MOD_SPARSE | 97 + AFBC_FORMAT_MOD_SPLIT), 98 + DRM_FORMAT_MOD_INVALID, 99 + }; 100 + 101 + static const struct vop2_video_port_data rk3568_vop_video_ports[] = { 102 + { 103 + .id = 0, 104 + .feature = VOP_FEATURE_OUTPUT_10BIT, 105 + .gamma_lut_len = 1024, 106 + .cubic_lut_len = 9 * 9 * 9, 107 + .max_output = { 4096, 2304 }, 108 + .pre_scan_max_dly = { 69, 53, 53, 42 }, 109 + .offset = 0xc00, 110 + }, { 111 + .id = 1, 112 + .gamma_lut_len = 1024, 113 + .max_output = { 2048, 1536 }, 114 + .pre_scan_max_dly = { 40, 40, 40, 40 }, 115 + .offset = 0xd00, 116 + }, { 117 + .id = 2, 118 + .gamma_lut_len = 1024, 119 + .max_output = { 1920, 1080 }, 120 + .pre_scan_max_dly = { 40, 40, 40, 40 }, 121 + .offset = 0xe00, 122 + }, 123 + }; 124 + 125 + /* 126 + * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win. 127 + * Every cluster can work as 4K win or split into two win. 128 + * All win in cluster support AFBCD. 129 + * 130 + * Every esmart win and smart win support 4 Multi-region. 131 + * 132 + * Scale filter mode: 133 + * 134 + * * Cluster: bicubic for horizontal scale up, others use bilinear 135 + * * ESmart: 136 + * * nearest-neighbor/bilinear/bicubic for scale up 137 + * * nearest-neighbor/bilinear/average for scale down 138 + * 139 + * 140 + * @TODO describe the wind like cpu-map dt nodes; 141 + */ 142 + static const struct vop2_win_data rk3568_vop_win_data[] = { 143 + { 144 + .name = "Smart0-win0", 145 + .phys_id = ROCKCHIP_VOP2_SMART0, 146 + .base = 0x1c00, 147 + .formats = formats_win_lite, 148 + .nformats = ARRAY_SIZE(formats_win_lite), 149 + .format_modifiers = format_modifiers, 150 + .layer_sel_id = 3, 151 + .supported_rotations = DRM_MODE_REFLECT_Y, 152 + .type = DRM_PLANE_TYPE_PRIMARY, 153 + .max_upscale_factor = 8, 154 + .max_downscale_factor = 8, 155 + .dly = { 20, 47, 41 }, 156 + }, { 157 + .name = "Smart1-win0", 158 + .phys_id = ROCKCHIP_VOP2_SMART1, 159 + .formats = formats_win_lite, 160 + .nformats = ARRAY_SIZE(formats_win_lite), 161 + .format_modifiers = format_modifiers, 162 + .base = 0x1e00, 163 + .layer_sel_id = 7, 164 + .supported_rotations = DRM_MODE_REFLECT_Y, 165 + .type = DRM_PLANE_TYPE_PRIMARY, 166 + .max_upscale_factor = 8, 167 + .max_downscale_factor = 8, 168 + .dly = { 20, 47, 41 }, 169 + }, { 170 + .name = "Esmart1-win0", 171 + .phys_id = ROCKCHIP_VOP2_ESMART1, 172 + .formats = formats_win_full_10bit_yuyv, 173 + .nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv), 174 + .format_modifiers = format_modifiers, 175 + .base = 0x1a00, 176 + .layer_sel_id = 6, 177 + .supported_rotations = DRM_MODE_REFLECT_Y, 178 + .type = DRM_PLANE_TYPE_PRIMARY, 179 + .max_upscale_factor = 8, 180 + .max_downscale_factor = 8, 181 + .dly = { 20, 47, 41 }, 182 + }, { 183 + .name = "Esmart0-win0", 184 + .phys_id = ROCKCHIP_VOP2_ESMART0, 185 + .formats = formats_win_full_10bit_yuyv, 186 + .nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv), 187 + .format_modifiers = format_modifiers, 188 + .base = 0x1800, 189 + .layer_sel_id = 2, 190 + .supported_rotations = DRM_MODE_REFLECT_Y, 191 + .type = DRM_PLANE_TYPE_OVERLAY, 192 + .max_upscale_factor = 8, 193 + .max_downscale_factor = 8, 194 + .dly = { 20, 47, 41 }, 195 + }, { 196 + .name = "Cluster0-win0", 197 + .phys_id = ROCKCHIP_VOP2_CLUSTER0, 198 + .base = 0x1000, 199 + .formats = formats_win_full_10bit, 200 + .nformats = ARRAY_SIZE(formats_win_full_10bit), 201 + .format_modifiers = format_modifiers_afbc, 202 + .layer_sel_id = 0, 203 + .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | 204 + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, 205 + .max_upscale_factor = 4, 206 + .max_downscale_factor = 4, 207 + .dly = { 0, 27, 21 }, 208 + .type = DRM_PLANE_TYPE_OVERLAY, 209 + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, 210 + }, { 211 + .name = "Cluster1-win0", 212 + .phys_id = ROCKCHIP_VOP2_CLUSTER1, 213 + .base = 0x1200, 214 + .formats = formats_win_full_10bit, 215 + .nformats = ARRAY_SIZE(formats_win_full_10bit), 216 + .format_modifiers = format_modifiers_afbc, 217 + .layer_sel_id = 1, 218 + .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | 219 + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, 220 + .type = DRM_PLANE_TYPE_OVERLAY, 221 + .max_upscale_factor = 4, 222 + .max_downscale_factor = 4, 223 + .dly = { 0, 27, 21 }, 224 + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, 225 + }, 226 + }; 227 + 228 + static const struct vop2_data rk3566_vop = { 229 + .nr_vps = 3, 230 + .max_input = { 4096, 2304 }, 231 + .max_output = { 4096, 2304 }, 232 + .vp = rk3568_vop_video_ports, 233 + .win = rk3568_vop_win_data, 234 + .win_size = ARRAY_SIZE(rk3568_vop_win_data), 235 + .soc_id = 3566, 236 + }; 237 + 238 + static const struct vop2_data rk3568_vop = { 239 + .nr_vps = 3, 240 + .max_input = { 4096, 2304 }, 241 + .max_output = { 4096, 2304 }, 242 + .vp = rk3568_vop_video_ports, 243 + .win = rk3568_vop_win_data, 244 + .win_size = ARRAY_SIZE(rk3568_vop_win_data), 245 + .soc_id = 3568, 246 + }; 247 + 248 + static const struct of_device_id vop2_dt_match[] = { 249 + { 250 + .compatible = "rockchip,rk3566-vop", 251 + .data = &rk3566_vop, 252 + }, { 253 + .compatible = "rockchip,rk3568-vop", 254 + .data = &rk3568_vop, 255 + }, { 256 + }, 257 + }; 258 + MODULE_DEVICE_TABLE(of, vop2_dt_match); 259 + 260 + static int vop2_probe(struct platform_device *pdev) 261 + { 262 + struct device *dev = &pdev->dev; 263 + 264 + return component_add(dev, &vop2_component_ops); 265 + } 266 + 267 + static int vop2_remove(struct platform_device *pdev) 268 + { 269 + component_del(&pdev->dev, &vop2_component_ops); 270 + 271 + return 0; 272 + } 273 + 274 + struct platform_driver vop2_platform_driver = { 275 + .probe = vop2_probe, 276 + .remove = vop2_remove, 277 + .driver = { 278 + .name = "rockchip-vop2", 279 + .of_match_table = of_match_ptr(vop2_dt_match), 280 + }, 281 + };
+14
include/dt-bindings/soc/rockchip,vop2.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ 2 + 3 + #ifndef __DT_BINDINGS_ROCKCHIP_VOP2_H 4 + #define __DT_BINDINGS_ROCKCHIP_VOP2_H 5 + 6 + #define ROCKCHIP_VOP2_EP_RGB0 1 7 + #define ROCKCHIP_VOP2_EP_HDMI0 2 8 + #define ROCKCHIP_VOP2_EP_EDP0 3 9 + #define ROCKCHIP_VOP2_EP_MIPI0 4 10 + #define ROCKCHIP_VOP2_EP_LVDS0 5 11 + #define ROCKCHIP_VOP2_EP_MIPI1 6 12 + #define ROCKCHIP_VOP2_EP_LVDS1 7 13 + 14 + #endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */