1 /* 2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 3 * Author:Mark Yao <mark.yao@rock-chips.com> 4 * 5 * This software is licensed under the terms of the GNU General Public 6 * License version 2, as published by the Free Software Foundation, and 7 * may be copied, distributed, and modified under those terms. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15 #include <drm/drmP.h> 16 17 #include <linux/kernel.h> 18 #include <linux/component.h> 19 20 #include "rockchip_drm_vop.h" 21 #include "rockchip_vop_reg.h" 22 23 #define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \ 24 { \ 25 .offset = off, \ 26 .mask = _mask, \ 27 .shift = _shift, \ 28 .write_mask = _write_mask, \ 29 .relaxed = _relaxed, \ 30 } 31 32 #define VOP_REG(off, _mask, _shift) \ 33 _VOP_REG(off, _mask, _shift, false, true) 34 35 #define VOP_REG_SYNC(off, _mask, _shift) \ 36 _VOP_REG(off, _mask, _shift, false, false) 37 38 #define VOP_REG_MASK_SYNC(off, _mask, _shift) \ 39 _VOP_REG(off, _mask, _shift, true, false) 40 41 static const uint32_t formats_win_full[] = { 42 DRM_FORMAT_XRGB8888, 43 DRM_FORMAT_ARGB8888, 44 DRM_FORMAT_XBGR8888, 45 DRM_FORMAT_ABGR8888, 46 DRM_FORMAT_RGB888, 47 DRM_FORMAT_BGR888, 48 DRM_FORMAT_RGB565, 49 DRM_FORMAT_BGR565, 50 DRM_FORMAT_NV12, 51 DRM_FORMAT_NV16, 52 DRM_FORMAT_NV24, 53 }; 54 55 static const uint32_t formats_win_lite[] = { 56 DRM_FORMAT_XRGB8888, 57 DRM_FORMAT_ARGB8888, 58 DRM_FORMAT_XBGR8888, 59 DRM_FORMAT_ABGR8888, 60 DRM_FORMAT_RGB888, 61 DRM_FORMAT_BGR888, 62 DRM_FORMAT_RGB565, 63 DRM_FORMAT_BGR565, 64 }; 65 66 static const struct vop_scl_regs rk3036_win_scl = { 67 .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), 68 .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), 69 .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), 70 .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16), 71 }; 72 73 static const struct vop_win_phy rk3036_win0_data = { 74 .scl = &rk3036_win_scl, 75 .data_formats = formats_win_full, 76 .nformats = ARRAY_SIZE(formats_win_full), 77 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0), 78 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3), 79 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15), 80 .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0), 81 .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0), 82 .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0), 83 .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0), 84 .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0), 85 .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0), 86 .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16), 87 }; 88 89 static const struct vop_win_phy rk3036_win1_data = { 90 .data_formats = formats_win_lite, 91 .nformats = ARRAY_SIZE(formats_win_lite), 92 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), 93 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), 94 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), 95 .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0), 96 .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0), 97 .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0), 98 .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0), 99 .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), 100 }; 101 102 static const struct vop_win_data rk3036_vop_win_data[] = { 103 { .base = 0x00, .phy = &rk3036_win0_data, 104 .type = DRM_PLANE_TYPE_PRIMARY }, 105 { .base = 0x00, .phy = &rk3036_win1_data, 106 .type = DRM_PLANE_TYPE_CURSOR }, 107 }; 108 109 static const int rk3036_vop_intrs[] = { 110 DSP_HOLD_VALID_INTR, 111 FS_INTR, 112 LINE_FLAG_INTR, 113 BUS_ERROR_INTR, 114 }; 115 116 static const struct vop_intr rk3036_intr = { 117 .intrs = rk3036_vop_intrs, 118 .nintrs = ARRAY_SIZE(rk3036_vop_intrs), 119 .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12), 120 .status = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 0), 121 .enable = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 4), 122 .clear = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 8), 123 }; 124 125 static const struct vop_modeset rk3036_modeset = { 126 .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), 127 .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0), 128 .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), 129 .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0), 130 }; 131 132 static const struct vop_output rk3036_output = { 133 .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4), 134 }; 135 136 static const struct vop_common rk3036_common = { 137 .standby = VOP_REG_SYNC(RK3036_SYS_CTRL, 0x1, 30), 138 .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0), 139 .dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24), 140 .cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0), 141 }; 142 143 static const struct vop_data rk3036_vop = { 144 .intr = &rk3036_intr, 145 .common = &rk3036_common, 146 .modeset = &rk3036_modeset, 147 .output = &rk3036_output, 148 .win = rk3036_vop_win_data, 149 .win_size = ARRAY_SIZE(rk3036_vop_win_data), 150 }; 151 152 static const struct vop_scl_extension rk3288_win_full_scl_ext = { 153 .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31), 154 .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30), 155 .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28), 156 .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26), 157 .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24), 158 .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23), 159 .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22), 160 .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20), 161 .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18), 162 .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16), 163 .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15), 164 .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12), 165 .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8), 166 .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7), 167 .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6), 168 .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5), 169 .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4), 170 .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2), 171 .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1), 172 .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0), 173 .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5), 174 }; 175 176 static const struct vop_scl_regs rk3288_win_full_scl = { 177 .ext = &rk3288_win_full_scl_ext, 178 .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), 179 .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), 180 .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), 181 .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16), 182 }; 183 184 static const struct vop_win_phy rk3288_win01_data = { 185 .scl = &rk3288_win_full_scl, 186 .data_formats = formats_win_full, 187 .nformats = ARRAY_SIZE(formats_win_full), 188 .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), 189 .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), 190 .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), 191 .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), 192 .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), 193 .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), 194 .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), 195 .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), 196 .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), 197 .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), 198 .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), 199 .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), 200 .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), 201 }; 202 203 static const struct vop_win_phy rk3288_win23_data = { 204 .data_formats = formats_win_lite, 205 .nformats = ARRAY_SIZE(formats_win_lite), 206 .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4), 207 .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), 208 .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1), 209 .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12), 210 .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0), 211 .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0), 212 .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0), 213 .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0), 214 .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0), 215 .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0), 216 }; 217 218 static const struct vop_modeset rk3288_modeset = { 219 .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), 220 .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0), 221 .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), 222 .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0), 223 .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0), 224 .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0), 225 }; 226 227 static const struct vop_output rk3288_output = { 228 .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4), 229 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), 230 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), 231 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), 232 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), 233 }; 234 235 static const struct vop_common rk3288_common = { 236 .standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22), 237 .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23), 238 .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20), 239 .dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1), 240 .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6), 241 .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19), 242 .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), 243 .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), 244 .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), 245 }; 246 247 /* 248 * Note: rk3288 has a dedicated 'cursor' window, however, that window requires 249 * special support to get alpha blending working. For now, just use overlay 250 * window 3 for the drm cursor. 251 * 252 */ 253 static const struct vop_win_data rk3288_vop_win_data[] = { 254 { .base = 0x00, .phy = &rk3288_win01_data, 255 .type = DRM_PLANE_TYPE_PRIMARY }, 256 { .base = 0x40, .phy = &rk3288_win01_data, 257 .type = DRM_PLANE_TYPE_OVERLAY }, 258 { .base = 0x00, .phy = &rk3288_win23_data, 259 .type = DRM_PLANE_TYPE_OVERLAY }, 260 { .base = 0x50, .phy = &rk3288_win23_data, 261 .type = DRM_PLANE_TYPE_CURSOR }, 262 }; 263 264 static const int rk3288_vop_intrs[] = { 265 DSP_HOLD_VALID_INTR, 266 FS_INTR, 267 LINE_FLAG_INTR, 268 BUS_ERROR_INTR, 269 }; 270 271 static const struct vop_intr rk3288_vop_intr = { 272 .intrs = rk3288_vop_intrs, 273 .nintrs = ARRAY_SIZE(rk3288_vop_intrs), 274 .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12), 275 .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), 276 .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4), 277 .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8), 278 }; 279 280 static const struct vop_data rk3288_vop = { 281 .version = VOP_VERSION(3, 1), 282 .feature = VOP_FEATURE_OUTPUT_RGB10, 283 .intr = &rk3288_vop_intr, 284 .common = &rk3288_common, 285 .modeset = &rk3288_modeset, 286 .output = &rk3288_output, 287 .win = rk3288_vop_win_data, 288 .win_size = ARRAY_SIZE(rk3288_vop_win_data), 289 }; 290 291 static const int rk3368_vop_intrs[] = { 292 FS_INTR, 293 0, 0, 294 LINE_FLAG_INTR, 295 0, 296 BUS_ERROR_INTR, 297 0, 0, 0, 0, 0, 0, 0, 298 DSP_HOLD_VALID_INTR, 299 }; 300 301 static const struct vop_intr rk3368_vop_intr = { 302 .intrs = rk3368_vop_intrs, 303 .nintrs = ARRAY_SIZE(rk3368_vop_intrs), 304 .line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0), 305 .line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16), 306 .status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0), 307 .enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0), 308 .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0), 309 }; 310 311 static const struct vop_win_phy rk3368_win23_data = { 312 .data_formats = formats_win_lite, 313 .nformats = ARRAY_SIZE(formats_win_lite), 314 .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0), 315 .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), 316 .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), 317 .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20), 318 .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0), 319 .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0), 320 .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0), 321 .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0), 322 .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0), 323 .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0), 324 }; 325 326 static const struct vop_win_data rk3368_vop_win_data[] = { 327 { .base = 0x00, .phy = &rk3288_win01_data, 328 .type = DRM_PLANE_TYPE_PRIMARY }, 329 { .base = 0x40, .phy = &rk3288_win01_data, 330 .type = DRM_PLANE_TYPE_OVERLAY }, 331 { .base = 0x00, .phy = &rk3368_win23_data, 332 .type = DRM_PLANE_TYPE_OVERLAY }, 333 { .base = 0x50, .phy = &rk3368_win23_data, 334 .type = DRM_PLANE_TYPE_CURSOR }, 335 }; 336 337 static const struct vop_output rk3368_output = { 338 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16), 339 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20), 340 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24), 341 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28), 342 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), 343 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), 344 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), 345 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), 346 }; 347 348 static const struct vop_misc rk3368_misc = { 349 .global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11), 350 }; 351 352 static const struct vop_data rk3368_vop = { 353 .version = VOP_VERSION(3, 2), 354 .intr = &rk3368_vop_intr, 355 .common = &rk3288_common, 356 .modeset = &rk3288_modeset, 357 .output = &rk3368_output, 358 .misc = &rk3368_misc, 359 .win = rk3368_vop_win_data, 360 .win_size = ARRAY_SIZE(rk3368_vop_win_data), 361 }; 362 363 static const struct vop_intr rk3366_vop_intr = { 364 .intrs = rk3368_vop_intrs, 365 .nintrs = ARRAY_SIZE(rk3368_vop_intrs), 366 .line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0), 367 .line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16), 368 .status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0), 369 .enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0), 370 .clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0), 371 }; 372 373 static const struct vop_data rk3366_vop = { 374 .version = VOP_VERSION(3, 4), 375 .intr = &rk3366_vop_intr, 376 .common = &rk3288_common, 377 .modeset = &rk3288_modeset, 378 .output = &rk3368_output, 379 .misc = &rk3368_misc, 380 .win = rk3368_vop_win_data, 381 .win_size = ARRAY_SIZE(rk3368_vop_win_data), 382 }; 383 384 static const struct vop_output rk3399_output = { 385 .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), 386 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16), 387 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20), 388 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24), 389 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28), 390 .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), 391 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), 392 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), 393 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), 394 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), 395 }; 396 397 static const struct vop_data rk3399_vop_big = { 398 .version = VOP_VERSION(3, 5), 399 .feature = VOP_FEATURE_OUTPUT_RGB10, 400 .intr = &rk3366_vop_intr, 401 .common = &rk3288_common, 402 .modeset = &rk3288_modeset, 403 .output = &rk3399_output, 404 .misc = &rk3368_misc, 405 .win = rk3368_vop_win_data, 406 .win_size = ARRAY_SIZE(rk3368_vop_win_data), 407 }; 408 409 static const struct vop_win_data rk3399_vop_lit_win_data[] = { 410 { .base = 0x00, .phy = &rk3288_win01_data, 411 .type = DRM_PLANE_TYPE_PRIMARY }, 412 { .base = 0x00, .phy = &rk3368_win23_data, 413 .type = DRM_PLANE_TYPE_CURSOR}, 414 }; 415 416 static const struct vop_data rk3399_vop_lit = { 417 .version = VOP_VERSION(3, 6), 418 .intr = &rk3366_vop_intr, 419 .common = &rk3288_common, 420 .modeset = &rk3288_modeset, 421 .output = &rk3399_output, 422 .misc = &rk3368_misc, 423 .win = rk3399_vop_lit_win_data, 424 .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), 425 }; 426 427 static const struct vop_win_data rk3228_vop_win_data[] = { 428 { .base = 0x00, .phy = &rk3288_win01_data, 429 .type = DRM_PLANE_TYPE_PRIMARY }, 430 { .base = 0x40, .phy = &rk3288_win01_data, 431 .type = DRM_PLANE_TYPE_CURSOR }, 432 }; 433 434 static const struct vop_data rk3228_vop = { 435 .version = VOP_VERSION(3, 7), 436 .feature = VOP_FEATURE_OUTPUT_RGB10, 437 .intr = &rk3366_vop_intr, 438 .common = &rk3288_common, 439 .modeset = &rk3288_modeset, 440 .output = &rk3399_output, 441 .misc = &rk3368_misc, 442 .win = rk3228_vop_win_data, 443 .win_size = ARRAY_SIZE(rk3228_vop_win_data), 444 }; 445 446 static const struct vop_modeset rk3328_modeset = { 447 .htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), 448 .hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0), 449 .vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), 450 .vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0), 451 .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0), 452 .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0), 453 }; 454 455 static const struct vop_output rk3328_output = { 456 .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12), 457 .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13), 458 .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14), 459 .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15), 460 .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 16), 461 .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 20), 462 .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 24), 463 .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 28), 464 }; 465 466 static const struct vop_misc rk3328_misc = { 467 .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11), 468 }; 469 470 static const struct vop_common rk3328_common = { 471 .standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22), 472 .dither_down = VOP_REG(RK3328_DSP_CTRL1, 0xf, 1), 473 .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6), 474 .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18), 475 .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0), 476 .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), 477 }; 478 479 static const struct vop_intr rk3328_vop_intr = { 480 .intrs = rk3368_vop_intrs, 481 .nintrs = ARRAY_SIZE(rk3368_vop_intrs), 482 .line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0), 483 .line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16), 484 .status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0), 485 .enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0), 486 .clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0), 487 }; 488 489 static const struct vop_win_data rk3328_vop_win_data[] = { 490 { .base = 0xd0, .phy = &rk3288_win01_data, 491 .type = DRM_PLANE_TYPE_PRIMARY }, 492 { .base = 0x1d0, .phy = &rk3288_win01_data, 493 .type = DRM_PLANE_TYPE_OVERLAY }, 494 { .base = 0x2d0, .phy = &rk3288_win01_data, 495 .type = DRM_PLANE_TYPE_CURSOR }, 496 }; 497 498 static const struct vop_data rk3328_vop = { 499 .version = VOP_VERSION(3, 8), 500 .feature = VOP_FEATURE_OUTPUT_RGB10, 501 .intr = &rk3328_vop_intr, 502 .common = &rk3328_common, 503 .modeset = &rk3328_modeset, 504 .output = &rk3328_output, 505 .misc = &rk3328_misc, 506 .win = rk3328_vop_win_data, 507 .win_size = ARRAY_SIZE(rk3328_vop_win_data), 508 }; 509 510 static const struct of_device_id vop_driver_dt_match[] = { 511 { .compatible = "rockchip,rk3036-vop", 512 .data = &rk3036_vop }, 513 { .compatible = "rockchip,rk3288-vop", 514 .data = &rk3288_vop }, 515 { .compatible = "rockchip,rk3368-vop", 516 .data = &rk3368_vop }, 517 { .compatible = "rockchip,rk3366-vop", 518 .data = &rk3366_vop }, 519 { .compatible = "rockchip,rk3399-vop-big", 520 .data = &rk3399_vop_big }, 521 { .compatible = "rockchip,rk3399-vop-lit", 522 .data = &rk3399_vop_lit }, 523 { .compatible = "rockchip,rk3228-vop", 524 .data = &rk3228_vop }, 525 { .compatible = "rockchip,rk3328-vop", 526 .data = &rk3328_vop }, 527 {}, 528 }; 529 MODULE_DEVICE_TABLE(of, vop_driver_dt_match); 530 531 static int vop_probe(struct platform_device *pdev) 532 { 533 struct device *dev = &pdev->dev; 534 535 if (!dev->of_node) { 536 dev_err(dev, "can't find vop devices\n"); 537 return -ENODEV; 538 } 539 540 return component_add(dev, &vop_component_ops); 541 } 542 543 static int vop_remove(struct platform_device *pdev) 544 { 545 component_del(&pdev->dev, &vop_component_ops); 546 547 return 0; 548 } 549 550 struct platform_driver vop_platform_driver = { 551 .probe = vop_probe, 552 .remove = vop_remove, 553 .driver = { 554 .name = "rockchip-vop", 555 .of_match_table = of_match_ptr(vop_driver_dt_match), 556 }, 557 }; 558