1a67719d1SMark Yao /* 2a67719d1SMark Yao * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 3a67719d1SMark Yao * Author:Mark Yao <mark.yao@rock-chips.com> 4a67719d1SMark Yao * 5a67719d1SMark Yao * This software is licensed under the terms of the GNU General Public 6a67719d1SMark Yao * License version 2, as published by the Free Software Foundation, and 7a67719d1SMark Yao * may be copied, distributed, and modified under those terms. 8a67719d1SMark Yao * 9a67719d1SMark Yao * This program is distributed in the hope that it will be useful, 10a67719d1SMark Yao * but WITHOUT ANY WARRANTY; without even the implied warranty of 11a67719d1SMark Yao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12a67719d1SMark Yao * GNU General Public License for more details. 13a67719d1SMark Yao */ 14a67719d1SMark Yao 15a67719d1SMark Yao #include <drm/drmP.h> 16a67719d1SMark Yao 17a67719d1SMark Yao #include <linux/kernel.h> 18a67719d1SMark Yao #include <linux/component.h> 19a67719d1SMark Yao 20a67719d1SMark Yao #include "rockchip_drm_vop.h" 21a67719d1SMark Yao #include "rockchip_vop_reg.h" 22a67719d1SMark Yao 23a67719d1SMark Yao #define VOP_REG(off, _mask, s) \ 24a67719d1SMark Yao {.offset = off, \ 25a67719d1SMark Yao .mask = _mask, \ 26d49463ecSMark Yao .shift = s, \ 27d49463ecSMark Yao .write_mask = false,} 28d49463ecSMark Yao 29d49463ecSMark Yao #define VOP_REG_MASK(off, _mask, s) \ 30d49463ecSMark Yao {.offset = off, \ 31d49463ecSMark Yao .mask = _mask, \ 32d49463ecSMark Yao .shift = s, \ 33d49463ecSMark Yao .write_mask = true,} 34a67719d1SMark Yao 35f7673453SMark Yao static const uint32_t formats_win_full[] = { 36a67719d1SMark Yao DRM_FORMAT_XRGB8888, 37a67719d1SMark Yao DRM_FORMAT_ARGB8888, 38a67719d1SMark Yao DRM_FORMAT_XBGR8888, 39a67719d1SMark Yao DRM_FORMAT_ABGR8888, 40a67719d1SMark Yao DRM_FORMAT_RGB888, 41a67719d1SMark Yao DRM_FORMAT_BGR888, 42a67719d1SMark Yao DRM_FORMAT_RGB565, 43a67719d1SMark Yao DRM_FORMAT_BGR565, 44a67719d1SMark Yao DRM_FORMAT_NV12, 45a67719d1SMark Yao DRM_FORMAT_NV16, 46a67719d1SMark Yao DRM_FORMAT_NV24, 47a67719d1SMark Yao }; 48a67719d1SMark Yao 49f7673453SMark Yao static const uint32_t formats_win_lite[] = { 50a67719d1SMark Yao DRM_FORMAT_XRGB8888, 51a67719d1SMark Yao DRM_FORMAT_ARGB8888, 52a67719d1SMark Yao DRM_FORMAT_XBGR8888, 53a67719d1SMark Yao DRM_FORMAT_ABGR8888, 54a67719d1SMark Yao DRM_FORMAT_RGB888, 55a67719d1SMark Yao DRM_FORMAT_BGR888, 56a67719d1SMark Yao DRM_FORMAT_RGB565, 57a67719d1SMark Yao DRM_FORMAT_BGR565, 58a67719d1SMark Yao }; 59a67719d1SMark Yao 60b51502adSMark Yao static const struct vop_scl_regs rk3036_win_scl = { 61b51502adSMark Yao .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), 62b51502adSMark Yao .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), 63b51502adSMark Yao .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), 64b51502adSMark Yao .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16), 65b51502adSMark Yao }; 66b51502adSMark Yao 67b51502adSMark Yao static const struct vop_win_phy rk3036_win0_data = { 68b51502adSMark Yao .scl = &rk3036_win_scl, 69b51502adSMark Yao .data_formats = formats_win_full, 70b51502adSMark Yao .nformats = ARRAY_SIZE(formats_win_full), 71b51502adSMark Yao .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0), 72b51502adSMark Yao .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3), 73b51502adSMark Yao .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15), 74b51502adSMark Yao .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0), 75b51502adSMark Yao .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0), 76b51502adSMark Yao .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0), 77b51502adSMark Yao .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0), 78b51502adSMark Yao .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0), 79b51502adSMark Yao .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0), 80b51502adSMark Yao .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16), 81b51502adSMark Yao }; 82b51502adSMark Yao 83b51502adSMark Yao static const struct vop_win_phy rk3036_win1_data = { 84b51502adSMark Yao .data_formats = formats_win_lite, 85b51502adSMark Yao .nformats = ARRAY_SIZE(formats_win_lite), 86b51502adSMark Yao .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), 87b51502adSMark Yao .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), 88b51502adSMark Yao .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), 89b51502adSMark Yao .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0), 90b51502adSMark Yao .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0), 91b51502adSMark Yao .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0), 92b51502adSMark Yao .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0), 93b51502adSMark Yao .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), 94b51502adSMark Yao }; 95b51502adSMark Yao 96b51502adSMark Yao static const struct vop_win_data rk3036_vop_win_data[] = { 97b51502adSMark Yao { .base = 0x00, .phy = &rk3036_win0_data, 98b51502adSMark Yao .type = DRM_PLANE_TYPE_PRIMARY }, 99b51502adSMark Yao { .base = 0x00, .phy = &rk3036_win1_data, 100b51502adSMark Yao .type = DRM_PLANE_TYPE_CURSOR }, 101b51502adSMark Yao }; 102b51502adSMark Yao 103b51502adSMark Yao static const int rk3036_vop_intrs[] = { 104b51502adSMark Yao DSP_HOLD_VALID_INTR, 105b51502adSMark Yao FS_INTR, 106b51502adSMark Yao LINE_FLAG_INTR, 107b51502adSMark Yao BUS_ERROR_INTR, 108b51502adSMark Yao }; 109b51502adSMark Yao 110b51502adSMark Yao static const struct vop_intr rk3036_intr = { 111b51502adSMark Yao .intrs = rk3036_vop_intrs, 112b51502adSMark Yao .nintrs = ARRAY_SIZE(rk3036_vop_intrs), 113b51502adSMark Yao .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0), 114b51502adSMark Yao .enable = VOP_REG(RK3036_INT_STATUS, 0xf, 4), 115b51502adSMark Yao .clear = VOP_REG(RK3036_INT_STATUS, 0xf, 8), 116b51502adSMark Yao }; 117b51502adSMark Yao 118b51502adSMark Yao static const struct vop_ctrl rk3036_ctrl_data = { 119b51502adSMark Yao .standby = VOP_REG(RK3036_SYS_CTRL, 0x1, 30), 120b51502adSMark Yao .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0), 121b51502adSMark Yao .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4), 122b51502adSMark Yao .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), 123b51502adSMark Yao .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0), 124b51502adSMark Yao .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), 125b51502adSMark Yao .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0), 12669c34e41SYakir Yang .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12), 127b51502adSMark Yao .cfg_done = VOP_REG(RK3036_REG_CFG_DONE, 0x1, 0), 128b51502adSMark Yao }; 129b51502adSMark Yao 130b51502adSMark Yao static const struct vop_reg_data rk3036_vop_init_reg_table[] = { 131b51502adSMark Yao {RK3036_DSP_CTRL1, 0x00000000}, 132b51502adSMark Yao }; 133b51502adSMark Yao 134b51502adSMark Yao static const struct vop_data rk3036_vop = { 135b51502adSMark Yao .init_table = rk3036_vop_init_reg_table, 136b51502adSMark Yao .table_size = ARRAY_SIZE(rk3036_vop_init_reg_table), 137b51502adSMark Yao .ctrl = &rk3036_ctrl_data, 138b51502adSMark Yao .intr = &rk3036_intr, 139b51502adSMark Yao .win = rk3036_vop_win_data, 140b51502adSMark Yao .win_size = ARRAY_SIZE(rk3036_vop_win_data), 141b51502adSMark Yao }; 142b51502adSMark Yao 143f7673453SMark Yao static const struct vop_scl_extension rk3288_win_full_scl_ext = { 144f7673453SMark Yao .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31), 145f7673453SMark Yao .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30), 146f7673453SMark Yao .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28), 147f7673453SMark Yao .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26), 148f7673453SMark Yao .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24), 149f7673453SMark Yao .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23), 150f7673453SMark Yao .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22), 151f7673453SMark Yao .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20), 152f7673453SMark Yao .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18), 153f7673453SMark Yao .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16), 154f7673453SMark Yao .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15), 155f7673453SMark Yao .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12), 156f7673453SMark Yao .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8), 157f7673453SMark Yao .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7), 158f7673453SMark Yao .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6), 159f7673453SMark Yao .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5), 160f7673453SMark Yao .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4), 161f7673453SMark Yao .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2), 162f7673453SMark Yao .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1), 163f7673453SMark Yao .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0), 164f7673453SMark Yao .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5), 1651194fffbSMark Yao }; 1661194fffbSMark Yao 167f7673453SMark Yao static const struct vop_scl_regs rk3288_win_full_scl = { 168f7673453SMark Yao .ext = &rk3288_win_full_scl_ext, 169f7673453SMark Yao .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), 170f7673453SMark Yao .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), 171f7673453SMark Yao .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), 172f7673453SMark Yao .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16), 173a67719d1SMark Yao }; 174a67719d1SMark Yao 175f7673453SMark Yao static const struct vop_win_phy rk3288_win01_data = { 176f7673453SMark Yao .scl = &rk3288_win_full_scl, 177f7673453SMark Yao .data_formats = formats_win_full, 178f7673453SMark Yao .nformats = ARRAY_SIZE(formats_win_full), 179f7673453SMark Yao .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), 180f7673453SMark Yao .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), 181f7673453SMark Yao .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), 182f7673453SMark Yao .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), 183f7673453SMark Yao .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), 184f7673453SMark Yao .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), 185f7673453SMark Yao .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), 186f7673453SMark Yao .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), 187f7673453SMark Yao .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), 188f7673453SMark Yao .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), 189f7673453SMark Yao .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), 190f7673453SMark Yao .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), 191a67719d1SMark Yao }; 192a67719d1SMark Yao 193f7673453SMark Yao static const struct vop_win_phy rk3288_win23_data = { 194f7673453SMark Yao .data_formats = formats_win_lite, 195f7673453SMark Yao .nformats = ARRAY_SIZE(formats_win_lite), 196f7673453SMark Yao .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), 197f7673453SMark Yao .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1), 198f7673453SMark Yao .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12), 199f7673453SMark Yao .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0), 200f7673453SMark Yao .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0), 201f7673453SMark Yao .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0), 202f7673453SMark Yao .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0), 203f7673453SMark Yao .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0), 204f7673453SMark Yao .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0), 205a67719d1SMark Yao }; 206a67719d1SMark Yao 207f7673453SMark Yao static const struct vop_ctrl rk3288_ctrl_data = { 208f7673453SMark Yao .standby = VOP_REG(RK3288_SYS_CTRL, 0x1, 22), 209f7673453SMark Yao .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23), 210f7673453SMark Yao .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20), 211f7673453SMark Yao .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), 212f7673453SMark Yao .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), 213f7673453SMark Yao .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), 214f7673453SMark Yao .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), 215f7673453SMark Yao .dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1), 216f7673453SMark Yao .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6), 217f7673453SMark Yao .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19), 218f7673453SMark Yao .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), 219f7673453SMark Yao .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4), 220f7673453SMark Yao .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), 221f7673453SMark Yao .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0), 222f7673453SMark Yao .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), 223f7673453SMark Yao .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0), 224f7673453SMark Yao .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0), 225f7673453SMark Yao .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0), 22669c34e41SYakir Yang .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12), 227f7673453SMark Yao .cfg_done = VOP_REG(RK3288_REG_CFG_DONE, 0x1, 0), 228a67719d1SMark Yao }; 229a67719d1SMark Yao 230f7673453SMark Yao static const struct vop_reg_data rk3288_init_reg_table[] = { 231f7673453SMark Yao {RK3288_SYS_CTRL, 0x00c00000}, 232f7673453SMark Yao {RK3288_DSP_CTRL0, 0x00000000}, 233f7673453SMark Yao {RK3288_WIN0_CTRL0, 0x00000080}, 234f7673453SMark Yao {RK3288_WIN1_CTRL0, 0x00000080}, 235a67719d1SMark Yao /* TODO: Win2/3 support multiple area function, but we haven't found 236a67719d1SMark Yao * a suitable way to use it yet, so let's just use them as other windows 237a67719d1SMark Yao * with only area 0 enabled. 238a67719d1SMark Yao */ 239f7673453SMark Yao {RK3288_WIN2_CTRL0, 0x00000010}, 240f7673453SMark Yao {RK3288_WIN3_CTRL0, 0x00000010}, 241a67719d1SMark Yao }; 242a67719d1SMark Yao 243a67719d1SMark Yao /* 244a67719d1SMark Yao * Note: rk3288 has a dedicated 'cursor' window, however, that window requires 245a67719d1SMark Yao * special support to get alpha blending working. For now, just use overlay 246a67719d1SMark Yao * window 3 for the drm cursor. 247a67719d1SMark Yao * 248a67719d1SMark Yao */ 249a67719d1SMark Yao static const struct vop_win_data rk3288_vop_win_data[] = { 250f7673453SMark Yao { .base = 0x00, .phy = &rk3288_win01_data, 251f7673453SMark Yao .type = DRM_PLANE_TYPE_PRIMARY }, 252f7673453SMark Yao { .base = 0x40, .phy = &rk3288_win01_data, 253f7673453SMark Yao .type = DRM_PLANE_TYPE_OVERLAY }, 254f7673453SMark Yao { .base = 0x00, .phy = &rk3288_win23_data, 255f7673453SMark Yao .type = DRM_PLANE_TYPE_OVERLAY }, 256f7673453SMark Yao { .base = 0x50, .phy = &rk3288_win23_data, 257f7673453SMark Yao .type = DRM_PLANE_TYPE_CURSOR }, 258a67719d1SMark Yao }; 259a67719d1SMark Yao 260a67719d1SMark Yao static const int rk3288_vop_intrs[] = { 261a67719d1SMark Yao DSP_HOLD_VALID_INTR, 262a67719d1SMark Yao FS_INTR, 263a67719d1SMark Yao LINE_FLAG_INTR, 264a67719d1SMark Yao BUS_ERROR_INTR, 265a67719d1SMark Yao }; 266a67719d1SMark Yao 267a67719d1SMark Yao static const struct vop_intr rk3288_vop_intr = { 268a67719d1SMark Yao .intrs = rk3288_vop_intrs, 269a67719d1SMark Yao .nintrs = ARRAY_SIZE(rk3288_vop_intrs), 270f7673453SMark Yao .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), 271f7673453SMark Yao .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4), 272f7673453SMark Yao .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8), 273a67719d1SMark Yao }; 274a67719d1SMark Yao 275a67719d1SMark Yao static const struct vop_data rk3288_vop = { 276f7673453SMark Yao .init_table = rk3288_init_reg_table, 277f7673453SMark Yao .table_size = ARRAY_SIZE(rk3288_init_reg_table), 278efd11cc8SMark yao .feature = VOP_FEATURE_OUTPUT_RGB10, 279a67719d1SMark Yao .intr = &rk3288_vop_intr, 280f7673453SMark Yao .ctrl = &rk3288_ctrl_data, 281a67719d1SMark Yao .win = rk3288_vop_win_data, 282a67719d1SMark Yao .win_size = ARRAY_SIZE(rk3288_vop_win_data), 283a67719d1SMark Yao }; 284a67719d1SMark Yao 2850a63bfd0SMark Yao static const struct vop_ctrl rk3399_ctrl_data = { 2860a63bfd0SMark Yao .standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22), 2870a63bfd0SMark Yao .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), 2881a0f7ed3SChris Zhong .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), 2890a63bfd0SMark Yao .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), 2900a63bfd0SMark Yao .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), 2910a63bfd0SMark Yao .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), 2920a63bfd0SMark Yao .mipi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 15), 2930a63bfd0SMark Yao .dither_down = VOP_REG(RK3399_DSP_CTRL1, 0xf, 1), 2940a63bfd0SMark Yao .dither_up = VOP_REG(RK3399_DSP_CTRL1, 0x1, 6), 2950a63bfd0SMark Yao .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19), 2960a63bfd0SMark Yao .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0), 2970a63bfd0SMark Yao .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), 2981a0f7ed3SChris Zhong .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), 2990a63bfd0SMark Yao .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20), 3000a63bfd0SMark Yao .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24), 3010a63bfd0SMark Yao .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28), 3020a63bfd0SMark Yao .htotal_pw = VOP_REG(RK3399_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), 3030a63bfd0SMark Yao .hact_st_end = VOP_REG(RK3399_DSP_HACT_ST_END, 0x1fff1fff, 0), 3040a63bfd0SMark Yao .vtotal_pw = VOP_REG(RK3399_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), 3050a63bfd0SMark Yao .vact_st_end = VOP_REG(RK3399_DSP_VACT_ST_END, 0x1fff1fff, 0), 3060a63bfd0SMark Yao .hpost_st_end = VOP_REG(RK3399_POST_DSP_HACT_INFO, 0x1fff1fff, 0), 3070a63bfd0SMark Yao .vpost_st_end = VOP_REG(RK3399_POST_DSP_VACT_INFO, 0x1fff1fff, 0), 30869c34e41SYakir Yang .line_flag_num[0] = VOP_REG(RK3399_LINE_FLAG, 0xffff, 0), 30969c34e41SYakir Yang .line_flag_num[1] = VOP_REG(RK3399_LINE_FLAG, 0xffff, 16), 3100a63bfd0SMark Yao .cfg_done = VOP_REG_MASK(RK3399_REG_CFG_DONE, 0x1, 0), 311f7673453SMark Yao }; 312f7673453SMark Yao 3130a63bfd0SMark Yao static const int rk3399_vop_intrs[] = { 3140a63bfd0SMark Yao FS_INTR, 3150a63bfd0SMark Yao 0, 0, 3160a63bfd0SMark Yao LINE_FLAG_INTR, 3170a63bfd0SMark Yao 0, 3180a63bfd0SMark Yao BUS_ERROR_INTR, 3190a63bfd0SMark Yao 0, 0, 0, 0, 0, 0, 0, 3200a63bfd0SMark Yao DSP_HOLD_VALID_INTR, 321f7673453SMark Yao }; 322f7673453SMark Yao 3230a63bfd0SMark Yao static const struct vop_intr rk3399_vop_intr = { 3240a63bfd0SMark Yao .intrs = rk3399_vop_intrs, 3250a63bfd0SMark Yao .nintrs = ARRAY_SIZE(rk3399_vop_intrs), 3260a63bfd0SMark Yao .status = VOP_REG_MASK(RK3399_INTR_STATUS0, 0xffff, 0), 3270a63bfd0SMark Yao .enable = VOP_REG_MASK(RK3399_INTR_EN0, 0xffff, 0), 3280a63bfd0SMark Yao .clear = VOP_REG_MASK(RK3399_INTR_CLEAR0, 0xffff, 0), 329f7673453SMark Yao }; 330f7673453SMark Yao 3310a63bfd0SMark Yao static const struct vop_reg_data rk3399_init_reg_table[] = { 3320a63bfd0SMark Yao {RK3399_SYS_CTRL, 0x2000f800}, 3330a63bfd0SMark Yao {RK3399_DSP_CTRL0, 0x00000000}, 3340a63bfd0SMark Yao {RK3399_WIN0_CTRL0, 0x00000080}, 3350a63bfd0SMark Yao {RK3399_WIN1_CTRL0, 0x00000080}, 3360a63bfd0SMark Yao /* TODO: Win2/3 support multiple area function, but we haven't found 3370a63bfd0SMark Yao * a suitable way to use it yet, so let's just use them as other windows 3380a63bfd0SMark Yao * with only area 0 enabled. 3390a63bfd0SMark Yao */ 3400a63bfd0SMark Yao {RK3399_WIN2_CTRL0, 0x00000010}, 3410a63bfd0SMark Yao {RK3399_WIN3_CTRL0, 0x00000010}, 3420a63bfd0SMark Yao }; 3430a63bfd0SMark Yao 3440a63bfd0SMark Yao static const struct vop_data rk3399_vop_big = { 3450a63bfd0SMark Yao .init_table = rk3399_init_reg_table, 3460a63bfd0SMark Yao .table_size = ARRAY_SIZE(rk3399_init_reg_table), 347efd11cc8SMark yao .feature = VOP_FEATURE_OUTPUT_RGB10, 3480a63bfd0SMark Yao .intr = &rk3399_vop_intr, 3490a63bfd0SMark Yao .ctrl = &rk3399_ctrl_data, 3500a63bfd0SMark Yao /* 3510a63bfd0SMark Yao * rk3399 vop big windows register layout is same as rk3288. 3520a63bfd0SMark Yao */ 3530a63bfd0SMark Yao .win = rk3288_vop_win_data, 3540a63bfd0SMark Yao .win_size = ARRAY_SIZE(rk3288_vop_win_data), 3550a63bfd0SMark Yao }; 3560a63bfd0SMark Yao 3570a63bfd0SMark Yao static const struct vop_win_data rk3399_vop_lit_win_data[] = { 3580a63bfd0SMark Yao { .base = 0x00, .phy = &rk3288_win01_data, 359f7673453SMark Yao .type = DRM_PLANE_TYPE_PRIMARY }, 3600a63bfd0SMark Yao { .base = 0x00, .phy = &rk3288_win23_data, 361f7673453SMark Yao .type = DRM_PLANE_TYPE_CURSOR}, 362f7673453SMark Yao }; 363f7673453SMark Yao 3640a63bfd0SMark Yao static const struct vop_data rk3399_vop_lit = { 3650a63bfd0SMark Yao .init_table = rk3399_init_reg_table, 3660a63bfd0SMark Yao .table_size = ARRAY_SIZE(rk3399_init_reg_table), 3670a63bfd0SMark Yao .intr = &rk3399_vop_intr, 3680a63bfd0SMark Yao .ctrl = &rk3399_ctrl_data, 3690a63bfd0SMark Yao /* 3700a63bfd0SMark Yao * rk3399 vop lit windows register layout is same as rk3288, 3710a63bfd0SMark Yao * but cut off the win1 and win3 windows. 3720a63bfd0SMark Yao */ 3730a63bfd0SMark Yao .win = rk3399_vop_lit_win_data, 3740a63bfd0SMark Yao .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), 375f7673453SMark Yao }; 376f7673453SMark Yao 377a67719d1SMark Yao static const struct of_device_id vop_driver_dt_match[] = { 378f7673453SMark Yao { .compatible = "rockchip,rk3036-vop", 379f7673453SMark Yao .data = &rk3036_vop }, 380b51502adSMark Yao { .compatible = "rockchip,rk3288-vop", 381b51502adSMark Yao .data = &rk3288_vop }, 3820a63bfd0SMark Yao { .compatible = "rockchip,rk3399-vop-big", 3830a63bfd0SMark Yao .data = &rk3399_vop_big }, 3840a63bfd0SMark Yao { .compatible = "rockchip,rk3399-vop-lit", 3850a63bfd0SMark Yao .data = &rk3399_vop_lit }, 386a67719d1SMark Yao {}, 387a67719d1SMark Yao }; 388a67719d1SMark Yao MODULE_DEVICE_TABLE(of, vop_driver_dt_match); 389a67719d1SMark Yao 390a67719d1SMark Yao static int vop_probe(struct platform_device *pdev) 391a67719d1SMark Yao { 392a67719d1SMark Yao struct device *dev = &pdev->dev; 393a67719d1SMark Yao 394a67719d1SMark Yao if (!dev->of_node) { 395a67719d1SMark Yao dev_err(dev, "can't find vop devices\n"); 396a67719d1SMark Yao return -ENODEV; 397a67719d1SMark Yao } 398a67719d1SMark Yao 399a67719d1SMark Yao return component_add(dev, &vop_component_ops); 400a67719d1SMark Yao } 401a67719d1SMark Yao 402a67719d1SMark Yao static int vop_remove(struct platform_device *pdev) 403a67719d1SMark Yao { 404a67719d1SMark Yao component_del(&pdev->dev, &vop_component_ops); 405a67719d1SMark Yao 406a67719d1SMark Yao return 0; 407a67719d1SMark Yao } 408a67719d1SMark Yao 4098820b68bSJeffy Chen struct platform_driver vop_platform_driver = { 410a67719d1SMark Yao .probe = vop_probe, 411a67719d1SMark Yao .remove = vop_remove, 412a67719d1SMark Yao .driver = { 413a67719d1SMark Yao .name = "rockchip-vop", 414a67719d1SMark Yao .of_match_table = of_match_ptr(vop_driver_dt_match), 415a67719d1SMark Yao }, 416a67719d1SMark Yao }; 417