diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip/rockchip_vop_reg.c')
| -rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1155 |
1 files changed, 1016 insertions, 139 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index bafd698a28b1..219f8c2fa88e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -1,36 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Copyright (C) Rockchip Electronics Co., Ltd. * Author:Mark Yao <mark.yao@rock-chips.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ -#include <drm/drmP.h> - -#include <linux/kernel.h> #include <linux/component.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include <drm/drm_fourcc.h> +#include <drm/drm_plane.h> +#include <drm/drm_print.h> #include "rockchip_drm_vop.h" #include "rockchip_vop_reg.h" +#include "rockchip_drm_drv.h" -#define VOP_REG(off, _mask, s) \ - {.offset = off, \ +#define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \ + { \ + .offset = off, \ .mask = _mask, \ - .shift = s, \ - .write_mask = false,} + .shift = _shift, \ + .write_mask = _write_mask, \ + .relaxed = _relaxed, \ + } -#define VOP_REG_MASK(off, _mask, s) \ - {.offset = off, \ - .mask = _mask, \ - .shift = s, \ - .write_mask = true,} +#define VOP_REG(off, _mask, _shift) \ + _VOP_REG(off, _mask, _shift, false, true) + +#define VOP_REG_SYNC(off, _mask, _shift) \ + _VOP_REG(off, _mask, _shift, false, false) + +#define VOP_REG_MASK_SYNC(off, _mask, _shift) \ + _VOP_REG(off, _mask, _shift, true, false) static const uint32_t formats_win_full[] = { DRM_FORMAT_XRGB8888, @@ -42,8 +46,42 @@ static const uint32_t formats_win_full[] = { DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV16, + DRM_FORMAT_NV61, + DRM_FORMAT_NV24, + DRM_FORMAT_NV42, +}; + +static const uint32_t formats_win_full_10[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, DRM_FORMAT_NV16, + DRM_FORMAT_NV61, DRM_FORMAT_NV24, + DRM_FORMAT_NV42, + DRM_FORMAT_NV15, + DRM_FORMAT_NV20, + DRM_FORMAT_NV30, +}; + +static const uint64_t format_modifiers_win_full[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + +static const uint64_t format_modifiers_win_full_afbc[] = { + ROCKCHIP_AFBC_MOD, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, }; static const uint32_t formats_win_lite[] = { @@ -57,17 +95,28 @@ static const uint32_t formats_win_lite[] = { DRM_FORMAT_BGR565, }; -static const struct vop_scl_regs rk3036_win_scl = { +static const uint64_t format_modifiers_win_lite[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + +static const struct vop_scl_regs rk3036_win0_scl = { .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16), }; +static const struct vop_scl_regs rk3036_win1_scl = { + .scale_yrgb_x = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 16), +}; + static const struct vop_win_phy rk3036_win0_data = { - .scl = &rk3036_win_scl, + .scl = &rk3036_win0_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0), .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3), .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15), @@ -78,11 +127,16 @@ static const struct vop_win_phy rk3036_win0_data = { .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0), .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0), .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16), + .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 18), + .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 0), + .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), }; static const struct vop_win_phy rk3036_win1_data = { + .scl = &rk3036_win1_scl, .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), @@ -91,6 +145,9 @@ static const struct vop_win_phy rk3036_win1_data = { .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0), .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0), .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), + .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), + .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), + .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), }; static const struct vop_win_data rk3036_vop_win_data[] = { @@ -110,34 +167,463 @@ static const int rk3036_vop_intrs[] = { static const struct vop_intr rk3036_intr = { .intrs = rk3036_vop_intrs, .nintrs = ARRAY_SIZE(rk3036_vop_intrs), - .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0), - .enable = VOP_REG(RK3036_INT_STATUS, 0xf, 4), - .clear = VOP_REG(RK3036_INT_STATUS, 0xf, 8), + .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12), + .status = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 0), + .enable = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 4), + .clear = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 8), }; -static const struct vop_ctrl rk3036_ctrl_data = { - .standby = VOP_REG(RK3036_SYS_CTRL, 0x1, 30), - .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0), - .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4), +static const struct vop_modeset rk3036_modeset = { .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0), .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0), - .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12), - .cfg_done = VOP_REG(RK3036_REG_CFG_DONE, 0x1, 0), }; -static const struct vop_reg_data rk3036_vop_init_reg_table[] = { - {RK3036_DSP_CTRL1, 0x00000000}, +static const struct vop_output rk3036_output = { + .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4), +}; + +static const struct vop_common rk3036_common = { + .standby = VOP_REG_SYNC(RK3036_SYS_CTRL, 0x1, 30), + .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0), + .dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24), + .dither_down_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 27), + .dither_down_en = VOP_REG(RK3036_DSP_CTRL0, 0x1, 11), + .dither_down_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 10), + .cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0), }; static const struct vop_data rk3036_vop = { - .init_table = rk3036_vop_init_reg_table, - .table_size = ARRAY_SIZE(rk3036_vop_init_reg_table), - .ctrl = &rk3036_ctrl_data, .intr = &rk3036_intr, + .common = &rk3036_common, + .modeset = &rk3036_modeset, + .output = &rk3036_output, .win = rk3036_vop_win_data, .win_size = ARRAY_SIZE(rk3036_vop_win_data), + .max_output = { 1920, 1080 }, +}; + +static const struct vop_win_phy rk3126_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), + .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), + .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), + .dsp_info = VOP_REG(RK3126_WIN1_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), + .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), + .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), + .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), +}; + +static const struct vop_win_data rk3126_vop_win_data[] = { + { .base = 0x00, .phy = &rk3036_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3126_win1_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_output rk3126_output = { + .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4), + .hdmi_pin_pol = VOP_REG(RK3126_INT_SCALER, 0x7, 4), + .hdmi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 22), + .hdmi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 23), + .rgb_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 24), + .rgb_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 25), + .mipi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 28), + .mipi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 29), +}; + +static const struct vop_data rk3126_vop = { + .intr = &rk3036_intr, + .common = &rk3036_common, + .modeset = &rk3036_modeset, + .output = &rk3126_output, + .win = rk3126_vop_win_data, + .win_size = ARRAY_SIZE(rk3126_vop_win_data), + .max_output = { 1920, 1080 }, +}; + +static const int px30_vop_intrs[] = { + FS_INTR, + 0, 0, + LINE_FLAG_INTR, + 0, + BUS_ERROR_INTR, + 0, 0, + DSP_HOLD_VALID_INTR, +}; + +static const struct vop_intr px30_intr = { + .intrs = px30_vop_intrs, + .nintrs = ARRAY_SIZE(px30_vop_intrs), + .line_flag_num[0] = VOP_REG(PX30_LINE_FLAG, 0xfff, 0), + .status = VOP_REG_MASK_SYNC(PX30_INTR_STATUS, 0xffff, 0), + .enable = VOP_REG_MASK_SYNC(PX30_INTR_EN, 0xffff, 0), + .clear = VOP_REG_MASK_SYNC(PX30_INTR_CLEAR, 0xffff, 0), +}; + +static const struct vop_common px30_common = { + .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1), + .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16), + .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14), + .dither_down_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 8), + .dither_down_sel = VOP_REG(PX30_DSP_CTRL2, 0x1, 7), + .dither_down_mode = VOP_REG(PX30_DSP_CTRL2, 0x1, 6), + .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0), +}; + +static const struct vop_modeset px30_modeset = { + .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output px30_output = { + .rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1), + .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2), + .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0), + .mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25), + .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26), + .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24), +}; + +static const struct vop_scl_regs px30_win_scl = { + .scale_yrgb_x = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy px30_win0_data = { + .scl = &px30_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1), + .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 15), + .act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0), + .dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(PX30_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0), + .uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16), + .alpha_pre_mul = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 2), + .alpha_mode = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 1), + .alpha_en = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 0), +}; + +static const struct vop_win_phy px30_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0), + .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4), + .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 15), + .dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0), + .alpha_pre_mul = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 2), + .alpha_mode = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 1), + .alpha_en = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 0), +}; + +static const struct vop_win_phy px30_win2_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4), + .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0), + .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5), + .rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20), + .dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0), + .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0), + .alpha_pre_mul = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 2), + .alpha_mode = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 1), + .alpha_en = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 0), +}; + +static const struct vop_win_data px30_vop_big_win_data[] = { + { .base = 0x00, .phy = &px30_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &px30_win1_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &px30_win2_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_data px30_vop_big = { + .version = VOP_VERSION(2, 6), + .intr = &px30_intr, + .feature = VOP_FEATURE_INTERNAL_RGB, + .common = &px30_common, + .modeset = &px30_modeset, + .output = &px30_output, + .win = px30_vop_big_win_data, + .win_size = ARRAY_SIZE(px30_vop_big_win_data), + .max_output = { 1920, 1080 }, +}; + +static const struct vop_win_data px30_vop_lit_win_data[] = { + { .base = 0x00, .phy = &px30_win1_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +}; + +static const struct vop_data px30_vop_lit = { + .version = VOP_VERSION(2, 5), + .intr = &px30_intr, + .feature = VOP_FEATURE_INTERNAL_RGB, + .common = &px30_common, + .modeset = &px30_modeset, + .output = &px30_output, + .win = px30_vop_lit_win_data, + .win_size = ARRAY_SIZE(px30_vop_lit_win_data), + .max_output = { 1920, 1080 }, +}; + +static const struct vop_scl_regs rk3066_win_scl = { + .scale_yrgb_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy rk3066_win0_data = { + .scl = &rk3066_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), + .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 4), + .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 19), + .uv_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 22), + .act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16), + .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 21), + .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 0), +}; + +static const struct vop_win_phy rk3066_win1_data = { + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), + .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 7), + .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 23), + .uv_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 26), + .act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN1_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16), + .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 22), + .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 1), +}; + +static const struct vop_win_phy rk3066_win2_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), + .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 10), + .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 27), + .dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0), + .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 23), + .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 2), +}; + +static const struct vop_modeset rk3066_modeset = { + .htotal_pw = VOP_REG(RK3066_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3066_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3066_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3066_DSP_VACT_ST_END, 0x1fff1fff, 0), +}; + +static const struct vop_output rk3066_output = { + .pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4), +}; + +static const struct vop_common rk3066_common = { + .dma_stop = VOP_REG(RK3066_SYS_CTRL0, 0x1, 0), + .standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1), + .out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0), + .dither_down_en = VOP_REG(RK3066_DSP_CTRL0, 0x1, 11), + .dither_down_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 10), + .dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24), + .dither_up = VOP_REG(RK3066_DSP_CTRL0, 0x1, 9), + .dsp_lut_en = VOP_REG(RK3066_SYS_CTRL1, 0x1, 31), + .data_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 25), +}; + +static const struct vop_win_data rk3066_vop_win_data[] = { + { .base = 0x00, .phy = &rk3066_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3066_win1_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &rk3066_win2_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const int rk3066_vop_intrs[] = { + /* + * hs_start interrupt fires at frame-start, so serves + * the same purpose as dsp_hold in the driver. + */ + DSP_HOLD_VALID_INTR, + FS_INTR, + LINE_FLAG_INTR, + BUS_ERROR_INTR, +}; + +static const struct vop_intr rk3066_intr = { + .intrs = rk3066_vop_intrs, + .nintrs = ARRAY_SIZE(rk3066_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3066_INT_STATUS, 0xfff, 12), + .status = VOP_REG(RK3066_INT_STATUS, 0xf, 0), + .enable = VOP_REG(RK3066_INT_STATUS, 0xf, 4), + .clear = VOP_REG(RK3066_INT_STATUS, 0xf, 8), +}; + +static const struct vop_data rk3066_vop = { + .version = VOP_VERSION(2, 1), + .intr = &rk3066_intr, + .common = &rk3066_common, + .modeset = &rk3066_modeset, + .output = &rk3066_output, + .win = rk3066_vop_win_data, + .win_size = ARRAY_SIZE(rk3066_vop_win_data), + .feature = VOP_FEATURE_INTERNAL_RGB, + .max_output = { 1920, 1080 }, +}; + +static const struct vop_scl_regs rk3188_win_scl = { + .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy rk3188_win0_data = { + .scl = &rk3188_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0), + .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3), + .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15), + .uv_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 18), + .act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0), + .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 18), + .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 0), + .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), +}; + +static const struct vop_win_phy rk3188_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1), + .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6), + .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19), + /* no act_info on window1 */ + .dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0), + .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16), + .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 19), + .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 1), + .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), +}; + +static const struct vop_modeset rk3188_modeset = { + .htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output rk3188_output = { + .pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4), +}; + +static const struct vop_common rk3188_common = { + .gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31), + .standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30), + .out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0), + .dither_down_sel = VOP_REG(RK3188_DSP_CTRL0, 0x1, 27), + .dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11), + .dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10), + .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 24), + .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9), + .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28), + .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25), +}; + +static const struct vop_win_data rk3188_vop_win_data[] = { + { .base = 0x00, .phy = &rk3188_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3188_win1_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const int rk3188_vop_intrs[] = { + /* + * hs_start interrupt fires at frame-start, so serves + * the same purpose as dsp_hold in the driver. + */ + DSP_HOLD_VALID_INTR, + FS_INTR, + LINE_FLAG_INTR, + BUS_ERROR_INTR, +}; + +static const struct vop_intr rk3188_vop_intr = { + .intrs = rk3188_vop_intrs, + .nintrs = ARRAY_SIZE(rk3188_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12), + .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0), + .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4), + .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8), +}; + +static const struct vop_data rk3188_vop = { + .intr = &rk3188_vop_intr, + .common = &rk3188_common, + .modeset = &rk3188_modeset, + .output = &rk3188_output, + .win = rk3188_vop_win_data, + .win_size = ARRAY_SIZE(rk3188_vop_win_data), + .feature = VOP_FEATURE_INTERNAL_RGB, + .max_output = { 2048, 1536 }, }; static const struct vop_scl_extension rk3288_win_full_scl_ext = { @@ -174,11 +660,14 @@ static const struct vop_scl_regs rk3288_win_full_scl = { static const struct vop_win_phy rk3288_win01_data = { .scl = &rk3288_win_full_scl, - .data_formats = formats_win_full, - .nformats = ARRAY_SIZE(formats_win_full), + .data_formats = formats_win_full_10, + .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), + .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 15), .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), @@ -188,12 +677,15 @@ static const struct vop_win_phy rk3288_win01_data = { .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), }; static const struct vop_win_phy rk3288_win23_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), - .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), + .format_modifiers = format_modifiers_win_lite, + .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4), + .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1), .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12), .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0), @@ -204,40 +696,37 @@ static const struct vop_win_phy rk3288_win23_data = { .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0), }; -static const struct vop_ctrl rk3288_ctrl_data = { - .standby = VOP_REG(RK3288_SYS_CTRL, 0x1, 22), - .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23), - .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20), - .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), - .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), - .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), - .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), - .dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1), - .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6), - .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19), - .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), - .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4), +static const struct vop_modeset rk3288_modeset = { .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0), .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0), .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0), .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0), - .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12), - .cfg_done = VOP_REG(RK3288_REG_CFG_DONE, 0x1, 0), }; -static const struct vop_reg_data rk3288_init_reg_table[] = { - {RK3288_SYS_CTRL, 0x00c00000}, - {RK3288_DSP_CTRL0, 0x00000000}, - {RK3288_WIN0_CTRL0, 0x00000080}, - {RK3288_WIN1_CTRL0, 0x00000080}, - /* TODO: Win2/3 support multiple area function, but we haven't found - * a suitable way to use it yet, so let's just use them as other windows - * with only area 0 enabled. - */ - {RK3288_WIN2_CTRL0, 0x00000010}, - {RK3288_WIN3_CTRL0, 0x00000010}, +static const struct vop_output rk3288_output = { + .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4), + .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), + .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), + .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), + .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), +}; + +static const struct vop_common rk3288_common = { + .standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22), + .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23), + .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20), + .dither_down_sel = VOP_REG(RK3288_DSP_CTRL1, 0x1, 4), + .dither_down_mode = VOP_REG(RK3288_DSP_CTRL1, 0x1, 3), + .dither_down_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 2), + .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1), + .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6), + .dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0), + .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19), + .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), }; /* @@ -267,122 +756,512 @@ static const int rk3288_vop_intrs[] = { static const struct vop_intr rk3288_vop_intr = { .intrs = rk3288_vop_intrs, .nintrs = ARRAY_SIZE(rk3288_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12), .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0), .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4), .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8), }; static const struct vop_data rk3288_vop = { - .init_table = rk3288_init_reg_table, - .table_size = ARRAY_SIZE(rk3288_init_reg_table), + .version = VOP_VERSION(3, 1), .feature = VOP_FEATURE_OUTPUT_RGB10, .intr = &rk3288_vop_intr, - .ctrl = &rk3288_ctrl_data, + .common = &rk3288_common, + .modeset = &rk3288_modeset, + .output = &rk3288_output, .win = rk3288_vop_win_data, .win_size = ARRAY_SIZE(rk3288_vop_win_data), + .lut_size = 1024, + /* + * This is the maximum resolution for the VOPB, the VOPL can only do + * 2560x1600, but we can't distinguish them as they have the same + * compatible. + */ + .max_output = { 3840, 2160 }, }; -static const struct vop_ctrl rk3399_ctrl_data = { - .standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22), - .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), +static const int rk3368_vop_intrs[] = { + FS_INTR, + 0, 0, + LINE_FLAG_INTR, + 0, + BUS_ERROR_INTR, + 0, 0, 0, 0, 0, 0, 0, + DSP_HOLD_VALID_INTR, +}; + +static const struct vop_intr rk3368_vop_intr = { + .intrs = rk3368_vop_intrs, + .nintrs = ARRAY_SIZE(rk3368_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0), + .line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16), + .status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0), + .enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0), + .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0), +}; + +static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), + .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 15), + .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3368_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3368_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3368_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3368_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3368_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3368_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3368_WIN0_CTRL2, 0xff, 0), +}; + +static const struct vop_win_phy rk3368_win23_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0), + .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), + .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), + .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20), + .y_mir_en = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15), + .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0), + .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0), +}; + +static const struct vop_win_data rk3368_vop_win_data[] = { + { .base = 0x00, .phy = &rk3368_win01_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x40, .phy = &rk3368_win01_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &rk3368_win23_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x50, .phy = &rk3368_win23_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_output rk3368_output = { + .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31), + .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28), + .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), + .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), + .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), + .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), +}; + +static const struct vop_misc rk3368_misc = { + .global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11), +}; + +static const struct vop_data rk3368_vop = { + .version = VOP_VERSION(3, 2), + .intr = &rk3368_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, + .output = &rk3368_output, + .misc = &rk3368_misc, + .win = rk3368_vop_win_data, + .win_size = ARRAY_SIZE(rk3368_vop_win_data), + .max_output = { 4096, 2160 }, + .lut_size = 1024, +}; + +static const struct vop_intr rk3366_vop_intr = { + .intrs = rk3368_vop_intrs, + .nintrs = ARRAY_SIZE(rk3368_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0), + .line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16), + .status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0), + .enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0), + .clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0), +}; + +static const struct vop_data rk3366_vop = { + .version = VOP_VERSION(3, 4), + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, + .output = &rk3368_output, + .misc = &rk3368_misc, + .win = rk3368_vop_win_data, + .win_size = ARRAY_SIZE(rk3368_vop_win_data), + .max_output = { 4096, 2160 }, +}; + +static const struct vop_output rk3399_output = { + .dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19), + .rgb_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 31), + .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16), + .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 28), .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), .mipi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 15), - .dither_down = VOP_REG(RK3399_DSP_CTRL1, 0xf, 1), + .mipi_dual_channel_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 3), +}; + +static const struct vop_common rk3399_common = { + .standby = VOP_REG_SYNC(RK3399_SYS_CTRL, 0x1, 22), + .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23), + .mmu_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 20), + .dither_down_sel = VOP_REG(RK3399_DSP_CTRL1, 0x1, 4), + .dither_down_mode = VOP_REG(RK3399_DSP_CTRL1, 0x1, 3), + .dither_down_en = VOP_REG(RK3399_DSP_CTRL1, 0x1, 2), + .pre_dither_down = VOP_REG(RK3399_DSP_CTRL1, 0x1, 1), .dither_up = VOP_REG(RK3399_DSP_CTRL1, 0x1, 6), + .dsp_lut_en = VOP_REG(RK3399_DSP_CTRL1, 0x1, 0), + .update_gamma_lut = VOP_REG(RK3399_DSP_CTRL1, 0x1, 7), + .lut_buffer_index = VOP_REG(RK3399_DBG_POST_REG1, 0x1, 1), .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19), + .dsp_blank = VOP_REG(RK3399_DSP_CTRL0, 0x3, 18), .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0), - .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), - .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), - .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20), - .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24), - .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28), - .htotal_pw = VOP_REG(RK3399_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), - .hact_st_end = VOP_REG(RK3399_DSP_HACT_ST_END, 0x1fff1fff, 0), - .vtotal_pw = VOP_REG(RK3399_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), - .vact_st_end = VOP_REG(RK3399_DSP_VACT_ST_END, 0x1fff1fff, 0), - .hpost_st_end = VOP_REG(RK3399_POST_DSP_HACT_INFO, 0x1fff1fff, 0), - .vpost_st_end = VOP_REG(RK3399_POST_DSP_VACT_INFO, 0x1fff1fff, 0), - .line_flag_num[0] = VOP_REG(RK3399_LINE_FLAG, 0xffff, 0), - .line_flag_num[1] = VOP_REG(RK3399_LINE_FLAG, 0xffff, 16), - .cfg_done = VOP_REG_MASK(RK3399_REG_CFG_DONE, 0x1, 0), -}; - -static const int rk3399_vop_intrs[] = { - FS_INTR, - 0, 0, - LINE_FLAG_INTR, - 0, - BUS_ERROR_INTR, - 0, 0, 0, 0, 0, 0, 0, - DSP_HOLD_VALID_INTR, + .cfg_done = VOP_REG_SYNC(RK3399_REG_CFG_DONE, 0x1, 0), }; -static const struct vop_intr rk3399_vop_intr = { - .intrs = rk3399_vop_intrs, - .nintrs = ARRAY_SIZE(rk3399_vop_intrs), - .status = VOP_REG_MASK(RK3399_INTR_STATUS0, 0xffff, 0), - .enable = VOP_REG_MASK(RK3399_INTR_EN0, 0xffff, 0), - .clear = VOP_REG_MASK(RK3399_INTR_CLEAR0, 0xffff, 0), +static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = { + .y2r_coefficients = { + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0), + }, }; -static const struct vop_reg_data rk3399_init_reg_table[] = { - {RK3399_SYS_CTRL, 0x2000f800}, - {RK3399_DSP_CTRL0, 0x00000000}, - {RK3399_WIN0_CTRL0, 0x00000080}, - {RK3399_WIN1_CTRL0, 0x00000080}, - /* TODO: Win2/3 support multiple area function, but we haven't found - * a suitable way to use it yet, so let's just use them as other windows - * with only area 0 enabled. - */ - {RK3399_WIN2_CTRL0, 0x00000010}, - {RK3399_WIN3_CTRL0, 0x00000010}, +static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { }; + +static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { + { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) }, + { .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) }, + { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data }, + { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, + +}; + +static const struct vop_win_phy rk3399_win0_data = { + .scl = &rk3288_win_full_scl, + .data_formats = formats_win_full_10, + .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full_afbc, + .enable = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3399_WIN0_CTRL0, 0x7, 1), + .fmt_10 = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 15), + .x_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3399_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3399_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3399_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3399_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3399_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3399_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3399_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3399_WIN0_CTRL2, 0xff, 0), +}; + +static const struct vop_win_phy rk3399_win1_data = { + .scl = &rk3288_win_full_scl, + .data_formats = formats_win_full_10, + .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3399_WIN0_CTRL0, 0x7, 1), + .fmt_10 = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 15), + .x_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3399_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3399_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3399_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3399_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3399_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3399_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3399_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3399_WIN0_CTRL2, 0xff, 0), +}; + +/* + * rk3399 vop big windows register layout is same as rk3288, but we + * have a separate rk3399 win data array here so that we can advertise + * AFBC on the primary plane. + */ +static const struct vop_win_data rk3399_vop_win_data[] = { + { .base = 0x00, .phy = &rk3399_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x40, .phy = &rk3399_win1_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &rk3368_win23_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x50, .phy = &rk3368_win23_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_afbc rk3399_vop_afbc = { + .rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3), + .enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0), + .win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1), + .format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16), + .hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21), + .hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0), + .pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0), }; static const struct vop_data rk3399_vop_big = { - .init_table = rk3399_init_reg_table, - .table_size = ARRAY_SIZE(rk3399_init_reg_table), + .version = VOP_VERSION(3, 5), .feature = VOP_FEATURE_OUTPUT_RGB10, - .intr = &rk3399_vop_intr, - .ctrl = &rk3399_ctrl_data, - /* - * rk3399 vop big windows register layout is same as rk3288. - */ - .win = rk3288_vop_win_data, - .win_size = ARRAY_SIZE(rk3288_vop_win_data), + .intr = &rk3366_vop_intr, + .common = &rk3399_common, + .modeset = &rk3288_modeset, + .output = &rk3399_output, + .afbc = &rk3399_vop_afbc, + .misc = &rk3368_misc, + .win = rk3399_vop_win_data, + .win_size = ARRAY_SIZE(rk3399_vop_win_data), + .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, + .lut_size = 1024, + .max_output = { 4096, 2160 }, }; static const struct vop_win_data rk3399_vop_lit_win_data[] = { - { .base = 0x00, .phy = &rk3288_win01_data, + { .base = 0x00, .phy = &rk3368_win01_data, .type = DRM_PLANE_TYPE_PRIMARY }, - { .base = 0x00, .phy = &rk3288_win23_data, + { .base = 0x00, .phy = &rk3368_win23_data, .type = DRM_PLANE_TYPE_CURSOR}, }; +static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { + { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)}, + { .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data }, +}; + static const struct vop_data rk3399_vop_lit = { - .init_table = rk3399_init_reg_table, - .table_size = ARRAY_SIZE(rk3399_init_reg_table), - .intr = &rk3399_vop_intr, - .ctrl = &rk3399_ctrl_data, - /* - * rk3399 vop lit windows register layout is same as rk3288, - * but cut off the win1 and win3 windows. - */ + .version = VOP_VERSION(3, 6), + .intr = &rk3366_vop_intr, + .common = &rk3399_common, + .modeset = &rk3288_modeset, + .output = &rk3399_output, + .misc = &rk3368_misc, .win = rk3399_vop_lit_win_data, .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), + .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data, + .lut_size = 256, + .max_output = { 2560, 1600 }, +}; + +static const struct vop_win_data rk3228_vop_win_data[] = { + { .base = 0x00, .phy = &rk3288_win01_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x40, .phy = &rk3288_win01_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_data rk3228_vop = { + .version = VOP_VERSION(3, 7), + .feature = VOP_FEATURE_OUTPUT_RGB10, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, + .output = &rk3399_output, + .misc = &rk3368_misc, + .win = rk3228_vop_win_data, + .win_size = ARRAY_SIZE(rk3228_vop_win_data), + .max_output = { 4096, 2160 }, +}; + +static const struct vop_modeset rk3328_modeset = { + .htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0), + .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0), + .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0), +}; + +static const struct vop_output rk3328_output = { + .rgb_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 31), + .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12), + .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13), + .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14), + .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15), + .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 28), +}; + +static const struct vop_misc rk3328_misc = { + .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11), +}; + +static const struct vop_common rk3328_common = { + .standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22), + .dither_down_sel = VOP_REG(RK3328_DSP_CTRL1, 0x1, 4), + .dither_down_mode = VOP_REG(RK3328_DSP_CTRL1, 0x1, 3), + .dither_down_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 2), + .pre_dither_down = VOP_REG(RK3328_DSP_CTRL1, 0x1, 1), + .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6), + .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), +}; + +static const struct vop_intr rk3328_vop_intr = { + .intrs = rk3368_vop_intrs, + .nintrs = ARRAY_SIZE(rk3368_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0), + .line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16), + .status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0), + .enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0), + .clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0), +}; + +static const struct vop_win_data rk3328_vop_win_data[] = { + { .base = 0xd0, .phy = &rk3399_win1_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x1d0, .phy = &rk3399_win1_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x2d0, .phy = &rk3399_win1_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_data rk3328_vop = { + .version = VOP_VERSION(3, 8), + .feature = VOP_FEATURE_OUTPUT_RGB10, + .intr = &rk3328_vop_intr, + .common = &rk3328_common, + .modeset = &rk3328_modeset, + .output = &rk3328_output, + .misc = &rk3328_misc, + .win = rk3328_vop_win_data, + .win_size = ARRAY_SIZE(rk3328_vop_win_data), + .max_output = { 4096, 2160 }, +}; + +static const struct vop_common rv1126_common = { + .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1), + .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16), + .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14), + .dither_down_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 8), + .dither_down_sel = VOP_REG(PX30_DSP_CTRL2, 0x1, 7), + .dither_down_mode = VOP_REG(PX30_DSP_CTRL2, 0x1, 6), + .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0), + .dither_up = VOP_REG(PX30_DSP_CTRL2, 0x1, 2), + .dsp_lut_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 5), + .gate_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 0), +}; + +static const struct vop_modeset rv1126_modeset = { + .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output rv1126_output = { + .rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1), + .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2), + .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0), + .mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25), + .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26), + .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24), +}; + +static const struct vop_misc rv1126_misc = { + .global_regdone_en = VOP_REG(PX30_SYS_CTRL2, 0x1, 13), +}; + +static const struct vop_win_data rv1126_vop_win_data[] = { + { .base = 0x00, .phy = &px30_win0_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &px30_win2_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +}; + +static const struct vop_data rv1126_vop = { + .version = VOP_VERSION(2, 0xb), + .intr = &px30_intr, + .common = &rv1126_common, + .modeset = &rv1126_modeset, + .output = &rv1126_output, + .misc = &rv1126_misc, + .win = rv1126_vop_win_data, + .win_size = ARRAY_SIZE(rv1126_vop_win_data), + .max_output = { 1920, 1080 }, + .lut_size = 1024, }; static const struct of_device_id vop_driver_dt_match[] = { { .compatible = "rockchip,rk3036-vop", .data = &rk3036_vop }, + { .compatible = "rockchip,rk3126-vop", + .data = &rk3126_vop }, + { .compatible = "rockchip,px30-vop-big", + .data = &px30_vop_big }, + { .compatible = "rockchip,px30-vop-lit", + .data = &px30_vop_lit }, + { .compatible = "rockchip,rk3066-vop", + .data = &rk3066_vop }, + { .compatible = "rockchip,rk3188-vop", + .data = &rk3188_vop }, { .compatible = "rockchip,rk3288-vop", .data = &rk3288_vop }, + { .compatible = "rockchip,rk3368-vop", + .data = &rk3368_vop }, + { .compatible = "rockchip,rk3366-vop", + .data = &rk3366_vop }, { .compatible = "rockchip,rk3399-vop-big", .data = &rk3399_vop_big }, { .compatible = "rockchip,rk3399-vop-lit", .data = &rk3399_vop_lit }, + { .compatible = "rockchip,rk3228-vop", + .data = &rk3228_vop }, + { .compatible = "rockchip,rk3328-vop", + .data = &rk3328_vop }, + { .compatible = "rockchip,rv1126-vop", + .data = &rv1126_vop }, {}, }; MODULE_DEVICE_TABLE(of, vop_driver_dt_match); @@ -392,18 +1271,16 @@ static int vop_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; if (!dev->of_node) { - dev_err(dev, "can't find vop devices\n"); + DRM_DEV_ERROR(dev, "can't find vop devices\n"); return -ENODEV; } return component_add(dev, &vop_component_ops); } -static int vop_remove(struct platform_device *pdev) +static void vop_remove(struct platform_device *pdev) { component_del(&pdev->dev, &vop_component_ops); - - return 0; } struct platform_driver vop_platform_driver = { @@ -411,6 +1288,6 @@ struct platform_driver vop_platform_driver = { .remove = vop_remove, .driver = { .name = "rockchip-vop", - .of_match_table = of_match_ptr(vop_driver_dt_match), + .of_match_table = vop_driver_dt_match, }, }; |
