From 059bcbb1d034c8467ca7f849c559bd8d503bb76c Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Thu, 13 Jun 2019 09:58:57 +0800 Subject: [PATCH] drm/rockchip: vop: use new register config interface Change-Id: I63a5a41da3a4f8a1686594769167c31a7dfecb50 Signed-off-by: Sandy Huang --- .../display/rockchip/rockchip-vop.txt | 20 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 13 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 1200 +++++++++---- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 431 ++++- drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1522 +++++++++++++---- drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 164 +- 6 files changed, 2569 insertions(+), 781 deletions(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index eeda3597011e..425a3ff9d2a7 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -7,8 +7,15 @@ buffer to an external LCD interface. Required properties: - compatible: value should be one of the following "rockchip,rk3036-vop"; + "rockchip,rk3066-vop"; "rockchip,rk3126-vop"; - "rockchip,rk3288-vop"; + "rockchip,px30-vop-big"; + "rockchip,px30-vop-lit"; + "rockchip,rk3308-vop"; + "rockchip,rk1808-vop-lit"; + "rockchip,rk1808-vop-raw"; + "rockchip,rk3288-vop-lit"; + "rockchip,rk3288-vop-big"; "rockchip,rk3368-vop"; "rockchip,rk3366-vop"; "rockchip,rk3399-vop-big"; @@ -16,6 +23,13 @@ Required properties: "rockchip,rk3228-vop"; "rockchip,rk3328-vop"; +- reg: Address and length of the register set for the device. +- reg-names: The names of register regions. contain following regions: + - "regs" : (Required) Base address and size of the controllers. + - "gamma_lut" : (Optional) gamma function lut table registers, + take care of this register's length, driver would use + register's length to decide gamma table size. + - interrupts: should contain a list of all VOP IP block interrupts in the order: VSYNC, LCD_SYSTEM. The interrupt specifier format depends on the interrupt controller used. @@ -27,6 +41,7 @@ Required properties: aclk_vop: for ddr buffer transfer. hclk_vop: for ahb bus to R/W the phy regs. dclk_vop: pixel clock. + dclk_source: optional, dclk sources from display plls. - resets: Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. @@ -44,7 +59,8 @@ Example: SoC specific DT entry: vopb: vopb@ff930000 { compatible = "rockchip,rk3288-vop"; - reg = <0xff930000 0x19c>; + reg = <0xff930000 0x19c>, <0xff931000 0x1000>; + reg-names = "regs", "gamma_lut"; interrupts = ; clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>; clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 3b2acdbe508b..58c685968b6d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -35,10 +35,23 @@ struct iommu_domain; struct rockchip_crtc_state { struct drm_crtc_state base; + int left_margin; + int right_margin; + int top_margin; + int bottom_margin; int dsp_layer_sel; int output_type; int output_mode; int output_bpc; + int output_flags; + int bus_format; + int yuv_overlay; + int post_r2y_en; + int post_y2r_en; + int post_csc_mode; + int bcsh_en; + int color_space; + struct drm_framebuffer *crtc_primary_fb; }; #define to_rockchip_crtc_state(s) \ container_of(s, struct rockchip_crtc_state, base) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 37f6ae4d5758..4b0b9f123cc8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -33,10 +33,13 @@ #include #include #include +#include +#include #include #include #include +#include #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" @@ -44,28 +47,65 @@ #include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" -#define VOP_WIN_SET(vop, win, name, v) \ - vop_reg_set(vop, &win->phy->name, win->offset, ~0, v, #name) -#define VOP_SCL_SET(vop, win, name, v) \ - vop_reg_set(vop, &win->phy->scl->name, win->offset, ~0, v, #name) -#define VOP_SCL_SET_EXT(vop, win, name, v) \ - vop_reg_set(vop, &win->phy->scl->ext->name, \ - win->offset, ~0, v, #name) +#define VOP_REG_SUPPORT(vop, reg) \ + (reg.mask && \ + (!reg.major || \ + (reg.major == VOP_MAJOR(vop->version) && \ + reg.begin_minor <= VOP_MINOR(vop->version) && \ + reg.end_minor >= VOP_MINOR(vop->version)))) -#define VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, name, v) \ +#define VOP_WIN_SUPPORT(vop, win, name) \ + VOP_REG_SUPPORT(vop, win->phy->name) + +#define VOP_WIN_SCL_EXT_SUPPORT(vop, win, name) \ + (win->phy->scl->ext && \ + VOP_REG_SUPPORT(vop, win->phy->scl->ext->name)) + +#define VOP_CTRL_SUPPORT(vop, name) \ + VOP_REG_SUPPORT(vop, vop->data->ctrl->name) + +#define VOP_INTR_SUPPORT(vop, name) \ + VOP_REG_SUPPORT(vop, vop->data->intr->name) + +#define __REG_SET(x, off, mask, shift, v, write_mask, relaxed) \ + vop_mask_write(x, off, mask, shift, v, write_mask, relaxed) + +#define _REG_SET(vop, name, off, reg, mask, v, relaxed) \ do { \ - if (win_yuv2yuv && win_yuv2yuv->name.mask) \ - vop_reg_set(vop, &win_yuv2yuv->name, 0, ~0, v, #name); \ + if (VOP_REG_SUPPORT(vop, reg)) \ + __REG_SET(vop, off + reg.offset, mask, reg.shift, \ + v, reg.write_mask, relaxed); \ + else \ + dev_dbg(vop->dev, "Warning: not support "#name"\n"); \ } while (0) -#define VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, win_yuv2yuv, name, v) \ - do { \ - if (win_yuv2yuv && win_yuv2yuv->phy->name.mask) \ - vop_reg_set(vop, &win_yuv2yuv->phy->name, win_yuv2yuv->base, ~0, v, #name); \ - } while (0) +#define REG_SET(x, name, off, reg, v, relaxed) \ + _REG_SET(x, name, off, reg, reg.mask, v, relaxed) +#define REG_SET_MASK(x, name, off, reg, mask, v, relaxed) \ + _REG_SET(x, name, off, reg, reg.mask & mask, v, relaxed) +#define VOP_WIN_SET(x, win, name, v) \ + REG_SET(x, name, win->offset, VOP_WIN_NAME(win, name), v, true) +#define VOP_WIN_SET_EXT(x, win, ext, name, v) \ + REG_SET(x, name, 0, win->ext->name, v, true) +#define VOP_SCL_SET(x, win, name, v) \ + REG_SET(x, name, win->offset, win->phy->scl->name, v, true) +#define VOP_SCL_SET_EXT(x, win, name, v) \ + REG_SET(x, name, win->offset, win->phy->scl->ext->name, v, true) + +#define VOP_CTRL_SET(x, name, v) \ + REG_SET(x, name, 0, (x)->data->ctrl->name, v, false) + +#define VOP_INTR_GET(vop, name) \ + vop_read_reg(vop, 0, &vop->data->ctrl->name) + +#define VOP_INTR_SET(vop, name, v) \ + REG_SET(vop, name, 0, vop->data->intr->name, \ + v, false) #define VOP_INTR_SET_MASK(vop, name, mask, v) \ - vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) + REG_SET_MASK(vop, name, 0, vop->data->intr->name, \ + mask, v, false) + #define VOP_REG_SET(vop, group, name, v) \ vop_reg_set(vop, &vop->data->group->name, 0, ~0, v, #name) @@ -84,37 +124,29 @@ #define VOP_INTR_GET_TYPE(vop, name, type) \ vop_get_intr_type(vop, &vop->data->intr->name, type) +#define VOP_CTRL_GET(x, name) \ + vop_read_reg(x, 0, &vop->data->ctrl->name) + #define VOP_WIN_GET(vop, win, name) \ vop_read_reg(vop, win->offset, &VOP_WIN_NAME(win, name)) #define VOP_WIN_NAME(win, name) \ (vop_get_win_phy(win, &win->phy->name)->name) -#define VOP_WIN_HAS_REG(win, name) \ - (!!(&win->phy->name)->mask) - -#define VOP_WIN_GET_YRGBADDR(vop, win) \ - vop_readl(vop, win->offset + VOP_WIN_NAME(win, yrgb_mst).offset) - #define VOP_WIN_TO_INDEX(vop_win) \ ((vop_win) - (vop_win)->vop->win) +#define VOP_GRF_SET(vop, reg, v) \ + do { \ + if (vop->data->grf_ctrl) { \ + vop_grf_writel(vop, vop->data->grf_ctrl->reg, v); \ + } \ + } while (0) + #define to_vop(x) container_of(x, struct vop, crtc) #define to_vop_win(x) container_of(x, struct vop_win, base) #define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base) -/* - * The coefficients of the following matrix are all fixed points. - * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets. - * They are all represented in two's complement. - */ -static const uint32_t bt601_yuv2rgb[] = { - 0x4A8, 0x0, 0x662, - 0x4A8, 0x1E6F, 0x1CBF, - 0x4A8, 0x812, 0x0, - 0x321168, 0x0877CF, 0x2EB127 -}; - enum vop_pending { VOP_PENDING_FB_UNREF, }; @@ -159,9 +191,10 @@ struct vop_win { uint32_t offset; enum drm_plane_type type; const struct vop_win_phy *phy; + const struct vop_csc *csc; const uint32_t *data_formats; uint32_t nformats; - + u64 feature; const struct vop_win_yuv2yuv_data *yuv2yuv_data; struct vop *vop; struct vop_plane_state state; @@ -172,8 +205,17 @@ struct vop { struct device *dev; struct drm_device *drm_dev; struct drm_property *plane_zpos_prop; + struct drm_property *plane_feature_prop; + struct drm_property *feature_prop; + bool is_iommu_enabled; + bool is_iommu_needed; bool is_enabled; + bool mode_update; + u32 version; + + struct drm_tv_connector_state active_tv_state; + bool pre_overlay; struct completion dsp_hold_completion; /* protected by dev->event_lock */ @@ -189,6 +231,7 @@ struct vop { uint32_t *regsbak; void __iomem *regs; + struct regmap *grf; /* physical map length of vop register */ uint32_t len; @@ -215,6 +258,19 @@ struct vop { struct vop_win win[]; }; +static inline void vop_grf_writel(struct vop *vop, struct vop_reg reg, u32 v) +{ + u32 val = 0; + + if (IS_ERR_OR_NULL(vop->grf)) + return; + + if (VOP_REG_SUPPORT(vop, reg)) { + val = (v << reg.shift) | (reg.mask << (reg.shift + 16)); + regmap_write(vop->grf, reg.offset, val); + } +} + static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v) { writel(v, vop->regs + offset); @@ -232,23 +288,15 @@ static inline uint32_t vop_read_reg(struct vop *vop, uint32_t base, return (vop_readl(vop, base + reg->offset) >> reg->shift) & reg->mask; } -static void vop_reg_set(struct vop *vop, const struct vop_reg *reg, - uint32_t _offset, uint32_t _mask, uint32_t v, - const char *reg_name) +static inline void vop_mask_write(struct vop *vop, uint32_t offset, + uint32_t mask, uint32_t shift, uint32_t v, + bool write_mask, bool relaxed) { - int offset, mask, shift; - - if (!reg || !reg->mask) { - DRM_DEV_DEBUG(vop->dev, "Warning: not support %s\n", reg_name); + if (!mask) return; - } - offset = reg->offset + _offset; - mask = reg->mask & _mask; - shift = reg->shift; - - if (reg->write_mask) { - v = ((v << shift) & 0xffff) | (mask << (shift + 16)); + if (write_mask) { + v = ((v & mask) << shift) | (mask << (shift + 16)); } else { uint32_t cached_val = vop->regsbak[offset >> 2]; @@ -256,7 +304,7 @@ static void vop_reg_set(struct vop *vop, const struct vop_reg *reg, vop->regsbak[offset >> 2] = v; } - if (reg->relaxed) + if (relaxed) writel_relaxed(v, vop->regs + offset); else writel(v, vop->regs + offset); @@ -287,7 +335,49 @@ static inline uint32_t vop_get_intr_type(struct vop *vop, static inline void vop_cfg_done(struct vop *vop) { - VOP_REG_SET(vop, common, cfg_done, 1); + VOP_CTRL_SET(vop, cfg_done, 1); +} + +static bool vop_is_allwin_disabled(struct vop *vop) +{ + int i; + + for (i = 0; i < vop->num_wins; i++) { + struct vop_win *win = &vop->win[i]; + + if (VOP_WIN_GET(vop, win, enable) != 0) + return false; + } + + return true; +} + +static void vop_disable_allwin(struct vop *vop) +{ + int i; + + for (i = 0; i < vop->num_wins; i++) { + struct vop_win *win = &vop->win[i]; + + if (win->phy->scl && win->phy->scl->ext) { + VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, SCALE_NONE); + VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, SCALE_NONE); + VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, SCALE_NONE); + VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, SCALE_NONE); + } + VOP_WIN_SET(vop, win, enable, 0); + VOP_WIN_SET(vop, win, gate, 0); + } +} + +static __maybe_unused bool vop_fs_irq_is_active(struct vop *vop) +{ + return VOP_INTR_GET_TYPE(vop, status, FS_INTR); +} + +static __maybe_unused bool vop_line_flag_is_active(struct vop *vop) +{ + return VOP_INTR_GET_TYPE(vop, status, LINE_FLAG_INTR); } static bool has_rb_swapped(uint32_t format) @@ -329,6 +419,50 @@ static enum vop_data_format vop_convert_format(uint32_t format) } } +static bool is_uv_swap(uint32_t bus_format, uint32_t output_mode) +{ + /* + * FIXME: + * + * There is no media type for YUV444 output, + * so when out_mode is AAAA or P888, assume output is YUV444 on + * yuv format. + * + * From H/W testing, YUV444 mode need a rb swap. + */ + if ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 || + bus_format == MEDIA_BUS_FMT_YUV10_1X30) && + (output_mode == ROCKCHIP_OUT_MODE_AAAA || + output_mode == ROCKCHIP_OUT_MODE_P888)) + return true; + else + return false; +} + +static bool is_yuv_output(uint32_t bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + return true; + default: + return false; + } +} + +static bool is_alpha_support(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + return true; + default: + return false; + } +} + static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, uint32_t dst, bool is_horizontal, int vsu_mode, int *vskiplines) @@ -475,6 +609,32 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win *win, } } +static void vop_disable_all_planes(struct vop *vop) +{ + bool active; + int ret; + + vop_disable_allwin(vop); + vop_cfg_done(vop); + ret = readx_poll_timeout_atomic(vop_is_allwin_disabled, + vop, active, active, + 0, 500 * 1000); + if (ret) + dev_err(vop->dev, "wait win close timeout\n"); +} + +static void vop_enable_debug_irq(struct drm_crtc *crtc) +{ + struct vop *vop = to_vop(crtc); + uint32_t irqs; + + irqs = BUS_ERROR_INTR | WIN0_EMPTY_INTR | WIN1_EMPTY_INTR | + WIN2_EMPTY_INTR | WIN3_EMPTY_INTR | HWC_EMPTY_INTR | + POST_BUF_EMPTY_INTR; + VOP_INTR_SET_TYPE(vop, clear, irqs, 1); + VOP_INTR_SET_TYPE(vop, enable, irqs, 1); +} + static void vop_dsp_hold_valid_irq_enable(struct vop *vop) { unsigned long flags; @@ -594,78 +754,83 @@ static void vop_core_clks_disable(struct vop *vop) clk_disable(vop->hclk); } -static int vop_enable(struct drm_crtc *crtc) +static void vop_power_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); - int ret, i; + int ret; - ret = pm_runtime_get_sync(vop->dev); + ret = clk_prepare_enable(vop->hclk); if (ret < 0) { - DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); - return ret; + dev_err(vop->dev, "failed to enable hclk - %d\n", ret); + return; } - ret = vop_core_clks_enable(vop); - if (WARN_ON(ret < 0)) - goto err_put_pm_runtime; + ret = clk_prepare_enable(vop->dclk); + if (ret < 0) { + dev_err(vop->dev, "failed to enable dclk - %d\n", ret); + goto err_disable_hclk; + } - ret = clk_enable(vop->dclk); - if (WARN_ON(ret < 0)) - goto err_disable_core; - - /* - * Slave iommu shares power, irq and clock with vop. It was associated - * automatically with this master device via common driver code. - * Now that we have enabled the clock we attach it to the shared drm - * mapping. - */ - ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev); - if (ret) { - DRM_DEV_ERROR(vop->dev, - "failed to attach dma mapping, %d\n", ret); + ret = clk_prepare_enable(vop->aclk); + if (ret < 0) { + dev_err(vop->dev, "failed to enable aclk - %d\n", ret); goto err_disable_dclk; } - spin_lock(&vop->reg_lock); - for (i = 0; i < vop->len; i += 4) - writel_relaxed(vop->regsbak[i / 4], vop->regs + i); + ret = pm_runtime_get_sync(vop->dev); + if (ret < 0) { + dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); + return; + } + + memcpy(vop->regsbak, vop->regs, vop->len); + + if (VOP_CTRL_SUPPORT(vop, version)) { + uint32_t version = VOP_CTRL_GET(vop, version); + + /* + * Fixup rk3288w version. + */ + if (version && version == 0x0a05) + vop->version = VOP_VERSION(3, 1); + } + + vop->is_enabled = true; + + return; + +err_disable_dclk: + clk_disable_unprepare(vop->dclk); +err_disable_hclk: + clk_disable_unprepare(vop->hclk); +} + +static void vop_initial(struct drm_crtc *crtc) +{ + struct vop *vop = to_vop(crtc); + int i; + + vop_power_enable(crtc); + + VOP_CTRL_SET(vop, global_regdone_en, 1); + VOP_CTRL_SET(vop, dsp_blank, 0); + VOP_CTRL_SET(vop, axi_outstanding_max_num, 30); + VOP_CTRL_SET(vop, axi_max_outstanding_en, 1); + VOP_CTRL_SET(vop, reg_done_frm, 1); /* - * We need to make sure that all windows are disabled before we - * enable the crtc. Otherwise we might try to scan from a destroyed + * We need to make sure that all windows are disabled before resume + * the crtc. Otherwise we might try to scan from a destroyed * buffer later. */ for (i = 0; i < vop->num_wins; i++) { struct vop_win *win = &vop->win[i]; + int channel = i * 2 + 1; - VOP_WIN_SET(vop, win, enable, 0); + VOP_WIN_SET(vop, win, channel, (channel + 1) << 4 | channel); } - spin_unlock(&vop->reg_lock); - - vop_cfg_done(vop); - - /* - * At here, vop clock & iommu is enable, R/W vop regs would be safe. - */ - vop->is_enabled = true; - - spin_lock(&vop->reg_lock); - - VOP_REG_SET(vop, common, standby, 1); - - spin_unlock(&vop->reg_lock); - - drm_crtc_vblank_on(crtc); - - return 0; - -err_disable_dclk: - clk_disable(vop->dclk); -err_disable_core: - vop_core_clks_disable(vop); -err_put_pm_runtime: - pm_runtime_put_sync(vop->dev); - return ret; + VOP_CTRL_SET(vop, afbdc_en, 0); + vop_enable_debug_irq(crtc); } static void vop_crtc_atomic_disable(struct drm_crtc *crtc, @@ -677,6 +842,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, mutex_lock(&vop->vop_lock); drm_crtc_vblank_off(crtc); + vop_disable_all_planes(vop); /* * Vop standby will take effect at end of current frame, @@ -690,24 +856,31 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, spin_lock(&vop->reg_lock); - VOP_REG_SET(vop, common, standby, 1); + VOP_CTRL_SET(vop, standby, 1); spin_unlock(&vop->reg_lock); - wait_for_completion(&vop->dsp_hold_completion); + WARN_ON(!wait_for_completion_timeout(&vop->dsp_hold_completion, + msecs_to_jiffies(50))); vop_dsp_hold_valid_irq_disable(vop); + disable_irq(vop->irq); + vop->is_enabled = false; + if (vop->is_iommu_enabled) { + /* + * vop standby complete, so iommu detach is safe. + */ + VOP_CTRL_SET(vop, dma_stop, 1); + rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); + vop->is_iommu_enabled = false; + } - /* - * vop standby complete, so iommu detach is safe. - */ - rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); - - clk_disable(vop->dclk); - vop_core_clks_disable(vop); pm_runtime_put(vop->dev); + clk_disable_unprepare(vop->dclk); + clk_disable_unprepare(vop->aclk); + clk_disable_unprepare(vop->hclk); mutex_unlock(&vop->vop_lock); if (crtc->state->event && !crtc->state->active) { @@ -826,7 +999,8 @@ static int vop_plane_atomic_check(struct drm_plane *plane, static void vop_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { - const struct vop_win *win = to_vop_win(plane); + struct vop_plane_state *vop_plane_state = to_vop_plane_state(old_state); + struct vop_win *win = to_vop_win(plane); struct vop *vop = to_vop(old_state->crtc); if (!old_state->crtc) @@ -834,9 +1008,32 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, spin_lock(&vop->reg_lock); + /* + * FIXUP: some of the vop scale would be abnormal after windows power + * on/off so deinit scale to scale_none mode. + */ + if (win->phy->scl && win->phy->scl->ext) { + VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, SCALE_NONE); + VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, SCALE_NONE); + VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, SCALE_NONE); + VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, SCALE_NONE); + } VOP_WIN_SET(vop, win, enable, 0); + if (win->area_id == 0) + VOP_WIN_SET(vop, win, gate, 0); + + /* + * IC design bug: in the bandwidth tension environment when close win2, + * vop will access the freed memory lead to iommu pagefault. + * so we add this reset to workaround. + */ + if (VOP_MAJOR(vop->version) == 2 && VOP_MINOR(vop->version) == 5 && + win->win_id == 2) + VOP_WIN_SET(vop, win, yrgb_mst, 0); spin_unlock(&vop->reg_lock); + + vop_plane_state->enable = false; } static void vop_plane_atomic_update(struct drm_plane *plane, @@ -844,9 +1041,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane, { struct drm_plane_state *state = plane->state; struct drm_crtc *crtc = state->crtc; - const struct vop_win *win = to_vop_win(plane); + struct vop_win *win = to_vop_win(plane); struct vop_plane_state *vop_plane_state = to_vop_plane_state(state); - const struct vop_win_yuv2yuv_data *win_yuv2yuv = win->yuv2yuv_data; + struct rockchip_crtc_state *s; struct vop *vop = to_vop(state->crtc); struct drm_framebuffer *fb = state->fb; unsigned int actual_w, actual_h; @@ -855,10 +1052,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, struct drm_rect *src = &vop_plane_state->src; struct drm_rect *dest = &vop_plane_state->dest; uint32_t val; - bool rb_swap; - int win_index = VOP_WIN_TO_INDEX(win); + bool rb_swap, global_alpha_en; int is_yuv = fb->format->is_yuv; - int i; /* * can't update plane when vop is disabled. @@ -885,27 +1080,21 @@ static void vop_plane_atomic_update(struct drm_plane *plane, dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start; dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); + s = to_rockchip_crtc_state(crtc->state); spin_lock(&vop->reg_lock); VOP_WIN_SET(vop, win, format, vop_plane_state->format); VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst); - VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); - VOP_WIN_SET(vop, win, y_mir_en, + + VOP_WIN_SET(vop, win, ymirror, (state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0); - VOP_WIN_SET(vop, win, x_mir_en, + VOP_WIN_SET(vop, win, xmirror, (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0); if (is_yuv) { VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); - VOP_WIN_SET(vop, win, uv_mst, vop_plane_state->yrgb_mst); - - for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) { - VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, - win_yuv2yuv, - y2r_coefficients[i], - bt601_yuv2rgb[i]); - } + VOP_WIN_SET(vop, win, uv_mst, vop_plane_state->uv_mst); } if (win->phy->scl) @@ -920,27 +1109,39 @@ static void vop_plane_atomic_update(struct drm_plane *plane, rb_swap = has_rb_swapped(fb->format->format); VOP_WIN_SET(vop, win, rb_swap, rb_swap); - /* - * Blending win0 with the background color doesn't seem to work - * correctly. We only get the background color, no matter the contents - * of the win0 framebuffer. However, blending pre-multiplied color - * with the default opaque black default background color is a no-op, - * so we can just disable blending to get the correct result. - */ - if (fb->format->has_alpha && win_index > 0) { + global_alpha_en = (vop_plane_state->global_alpha == 0xff) ? 0 : 1; + if ((is_alpha_support(fb->format->format) || global_alpha_en) && + (s->dsp_layer_sel & 0x3) != win->win_id) { + int src_bland_m0; + + if (is_alpha_support(fb->format->format) && global_alpha_en) + src_bland_m0 = ALPHA_PER_PIX_GLOBAL; + else if (is_alpha_support(fb->format->format)) + src_bland_m0 = ALPHA_PER_PIX; + else + src_bland_m0 = ALPHA_GLOBAL; + VOP_WIN_SET(vop, win, dst_alpha_ctl, DST_FACTOR_M0(ALPHA_SRC_INVERSE)); val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) | SRC_ALPHA_M0(ALPHA_STRAIGHT) | - SRC_BLEND_M0(ALPHA_PER_PIX) | + SRC_BLEND_M0(src_bland_m0) | SRC_ALPHA_CAL_M0(ALPHA_NO_SATURATION) | - SRC_FACTOR_M0(ALPHA_ONE); + SRC_FACTOR_M0(global_alpha_en ? + ALPHA_SRC_GLOBAL : ALPHA_ONE); VOP_WIN_SET(vop, win, src_alpha_ctl, val); + VOP_WIN_SET(vop, win, alpha_pre_mul, + vop_plane_state->blend_mode); + VOP_WIN_SET(vop, win, alpha_mode, 1); + VOP_WIN_SET(vop, win, alpha_en, 1); } else { VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0)); + VOP_WIN_SET(vop, win, alpha_en, 0); } + VOP_WIN_SET(vop, win, global_alpha_val, vop_plane_state->global_alpha); VOP_WIN_SET(vop, win, enable, 1); + VOP_WIN_SET(vop, win, gate, 1); spin_unlock(&vop->reg_lock); } @@ -1094,104 +1295,352 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +static void vop_update_csc(struct drm_crtc *crtc) +{ + struct rockchip_crtc_state *s = + to_rockchip_crtc_state(crtc->state); + struct vop *vop = to_vop(crtc); + u32 val; + + //todo + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + + if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && + !(vop->data->feature & VOP_FEATURE_OUTPUT_10BIT)) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + + if (is_uv_swap(s->bus_format, s->output_mode)) + VOP_CTRL_SET(vop, dsp_data_swap, DSP_RB_SWAP); + else + VOP_CTRL_SET(vop, dsp_data_swap, 0); + + VOP_CTRL_SET(vop, out_mode, s->output_mode); + + switch (s->bus_format) { + case MEDIA_BUS_FMT_RGB565_1X16: + VOP_CTRL_SET(vop, dither_down_en, 1); + VOP_CTRL_SET(vop, dither_down_mode, RGB888_TO_RGB565); + break; + case MEDIA_BUS_FMT_RGB666_1X18: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + VOP_CTRL_SET(vop, dither_down_en, 1); + VOP_CTRL_SET(vop, dither_down_mode, RGB888_TO_RGB666); + break; + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + VOP_CTRL_SET(vop, dither_down_en, 0); + VOP_CTRL_SET(vop, pre_dither_down_en, 1); + break; + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + VOP_CTRL_SET(vop, dither_down_en, 0); + VOP_CTRL_SET(vop, pre_dither_down_en, 0); + break; + case MEDIA_BUS_FMT_RGB888_1X24: + default: + VOP_CTRL_SET(vop, dither_down_en, 0); + VOP_CTRL_SET(vop, pre_dither_down_en, 0); + break; + } + + VOP_CTRL_SET(vop, pre_dither_down_en, + s->output_mode == ROCKCHIP_OUT_MODE_AAAA ? 0 : 1); + VOP_CTRL_SET(vop, dither_down_sel, DITHER_DOWN_ALLEGRO); + + VOP_CTRL_SET(vop, dclk_ddr, + s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); + VOP_CTRL_SET(vop, hdmi_dclk_out_en, + s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); + + VOP_CTRL_SET(vop, overlay_mode, s->yuv_overlay); + VOP_CTRL_SET(vop, dsp_out_yuv, is_yuv_output(s->bus_format)); + + /* + * Background color is 10bit depth if vop version >= 3.5 + */ + if (!is_yuv_output(s->bus_format)) + val = 0; + else if (VOP_MAJOR(vop->version) == 3 && VOP_MINOR(vop->version) == 8/* && + s->hdr.pre_overlay*/) + val = 0; + else if (VOP_MAJOR(vop->version) == 3 && VOP_MINOR(vop->version) >= 5) + val = 0x20010200; + else + val = 0x801080; + VOP_CTRL_SET(vop, dsp_background, val); +} + +/* + * if adjusted mode update, return true, else return false + */ +static bool vop_crtc_mode_update(struct drm_crtc *crtc) +{ + struct vop *vop = to_vop(crtc); + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + u16 hsync_len = adjusted_mode->crtc_hsync_end - + adjusted_mode->crtc_hsync_start; + u16 hdisplay = adjusted_mode->crtc_hdisplay; + u16 htotal = adjusted_mode->crtc_htotal; + u16 hact_st = adjusted_mode->crtc_htotal - + adjusted_mode->crtc_hsync_start; + u16 hact_end = hact_st + hdisplay; + u16 vdisplay = adjusted_mode->crtc_vdisplay; + u16 vtotal = adjusted_mode->crtc_vtotal; + u16 vsync_len = adjusted_mode->crtc_vsync_end - + adjusted_mode->crtc_vsync_start; + u16 vact_st = adjusted_mode->crtc_vtotal - + adjusted_mode->crtc_vsync_start; + u16 vact_end = vact_st + vdisplay; + u32 htotal_sync = htotal << 16 | hsync_len; + u32 hactive_st_end = hact_st << 16 | hact_end; + u32 vtotal_sync = vtotal << 16 | vsync_len; + u32 vactive_st_end = vact_st << 16 | vact_end; + u32 crtc_clock = adjusted_mode->crtc_clock * 100; + + if (htotal_sync != VOP_CTRL_GET(vop, htotal_pw) || + hactive_st_end != VOP_CTRL_GET(vop, hact_st_end) || + vtotal_sync != VOP_CTRL_GET(vop, vtotal_pw) || + vactive_st_end != VOP_CTRL_GET(vop, vact_st_end) || + crtc_clock != clk_get_rate(vop->dclk)) + return true; + + return false; +} + static void vop_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct vop *vop = to_vop(crtc); - const struct vop_data *vop_data = vop->data; struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; - u16 hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start; - u16 hdisplay = adjusted_mode->hdisplay; - u16 htotal = adjusted_mode->htotal; - u16 hact_st = adjusted_mode->htotal - adjusted_mode->hsync_start; + u16 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + u16 hdisplay = adjusted_mode->crtc_hdisplay; + u16 htotal = adjusted_mode->crtc_htotal; + u16 hact_st = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_start; u16 hact_end = hact_st + hdisplay; - u16 vdisplay = adjusted_mode->vdisplay; - u16 vtotal = adjusted_mode->vtotal; - u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start; - u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start; + u16 vdisplay = adjusted_mode->crtc_vdisplay; + u16 vtotal = adjusted_mode->crtc_vtotal; + u16 vsync_len = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; + u16 vact_st = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_start; u16 vact_end = vact_st + vdisplay; - uint32_t pin_pol, val; - int ret; + uint32_t val; + int act_end; + bool interlaced = !!(adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE); + int for_ddr_freq = 0; + bool dclk_inv; - mutex_lock(&vop->vop_lock); + //rockchip_set_system_status(sys_status); + //vop_lock(vop); + DRM_DEV_INFO(vop->dev, "Update mode to %dx%d%s%d, type: %d\n", + hdisplay, vdisplay, interlaced ? "i" : "p", + adjusted_mode->vrefresh, s->output_type); + vop_initial(crtc); + vop_disable_allwin(vop); + VOP_CTRL_SET(vop, standby, 0); + vop->mode_update = vop_crtc_mode_update(crtc); + dclk_inv = (adjusted_mode->flags & DRM_MODE_FLAG_CLKDIV2) ? 0 : 1; - WARN_ON(vop->event); - - ret = vop_enable(crtc); - if (ret) { - mutex_unlock(&vop->vop_lock); - DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); - return; - } - - pin_pol = BIT(DCLK_INVERT); - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) ? - BIT(HSYNC_POSITIVE) : 0; - pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ? - BIT(VSYNC_POSITIVE) : 0; - VOP_REG_SET(vop, output, pin_pol, pin_pol); + VOP_CTRL_SET(vop, dclk_pol, dclk_inv); + val = (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? + 0 : BIT(HSYNC_POSITIVE); + val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? + 0 : BIT(VSYNC_POSITIVE); + VOP_CTRL_SET(vop, pin_pol, val); switch (s->output_type) { case DRM_MODE_CONNECTOR_LVDS: - VOP_REG_SET(vop, output, rgb_en, 1); - VOP_REG_SET(vop, output, rgb_pin_pol, pin_pol); + VOP_CTRL_SET(vop, rgb_en, 1); + VOP_CTRL_SET(vop, rgb_pin_pol, val); + VOP_CTRL_SET(vop, rgb_dclk_pol, dclk_inv); + VOP_CTRL_SET(vop, lvds_en, 1); + VOP_CTRL_SET(vop, lvds_pin_pol, val); + VOP_CTRL_SET(vop, lvds_dclk_pol, dclk_inv); + + VOP_GRF_SET(vop, grf_dclk_inv, !dclk_inv); break; case DRM_MODE_CONNECTOR_eDP: - VOP_REG_SET(vop, output, edp_pin_pol, pin_pol); - VOP_REG_SET(vop, output, edp_en, 1); + VOP_CTRL_SET(vop, edp_en, 1); + VOP_CTRL_SET(vop, edp_pin_pol, val); + VOP_CTRL_SET(vop, edp_dclk_pol, dclk_inv); break; case DRM_MODE_CONNECTOR_HDMIA: - VOP_REG_SET(vop, output, hdmi_pin_pol, pin_pol); - VOP_REG_SET(vop, output, hdmi_en, 1); + VOP_CTRL_SET(vop, hdmi_en, 1); + VOP_CTRL_SET(vop, hdmi_pin_pol, val); + VOP_CTRL_SET(vop, hdmi_dclk_pol, 1); break; case DRM_MODE_CONNECTOR_DSI: - VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol); - VOP_REG_SET(vop, output, mipi_en, 1); + VOP_CTRL_SET(vop, mipi_en, 1); + VOP_CTRL_SET(vop, mipi_pin_pol, val); + VOP_CTRL_SET(vop, mipi_dclk_pol, dclk_inv); + VOP_CTRL_SET(vop, mipi_dual_channel_en, + !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL)); + VOP_CTRL_SET(vop, data01_swap, + !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_LINK)); break; case DRM_MODE_CONNECTOR_DisplayPort: - pin_pol &= ~BIT(DCLK_INVERT); - VOP_REG_SET(vop, output, dp_pin_pol, pin_pol); - VOP_REG_SET(vop, output, dp_en, 1); + VOP_CTRL_SET(vop, dp_dclk_pol, 0); + VOP_CTRL_SET(vop, dp_pin_pol, val); + VOP_CTRL_SET(vop, dp_en, 1); + break; + case DRM_MODE_CONNECTOR_TV: + if (vdisplay == CVBS_PAL_VDISPLAY) + VOP_CTRL_SET(vop, tve_sw_mode, 1); + else + VOP_CTRL_SET(vop, tve_sw_mode, 0); + + VOP_CTRL_SET(vop, tve_dclk_pol, 1); + VOP_CTRL_SET(vop, tve_dclk_en, 1); + /* use the same pol reg with hdmi */ + VOP_CTRL_SET(vop, hdmi_pin_pol, val); + VOP_CTRL_SET(vop, sw_genlock, 1); + VOP_CTRL_SET(vop, sw_uv_offset_en, 1); + VOP_CTRL_SET(vop, dither_up_en, 1); break; default: - DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", - s->output_type); + DRM_ERROR("unsupported connector_type[%d]\n", s->output_type); } - - /* - * if vop is not support RGB10 output, need force RGB10 to RGB888. - */ - if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && - !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) - s->output_mode = ROCKCHIP_OUT_MODE_P888; - - if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && s->output_bpc == 8) - VOP_REG_SET(vop, common, pre_dither_down, 1); - else - VOP_REG_SET(vop, common, pre_dither_down, 0); - - VOP_REG_SET(vop, common, out_mode, s->output_mode); - VOP_REG_SET(vop, common, yuv_overlay, 0); - - VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len); + vop_update_csc(crtc); + VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len); val = hact_st << 16; val |= hact_end; - VOP_REG_SET(vop, modeset, hact_st_end, val); - VOP_REG_SET(vop, modeset, hpost_st_end, val); + VOP_CTRL_SET(vop, hact_st_end, val); + VOP_CTRL_SET(vop, hpost_st_end, val); - VOP_REG_SET(vop, modeset, vtotal_pw, (vtotal << 16) | vsync_len); val = vact_st << 16; val |= vact_end; - VOP_REG_SET(vop, modeset, vact_st_end, val); - VOP_REG_SET(vop, modeset, vpost_st_end, val); + VOP_CTRL_SET(vop, vact_st_end, val); + VOP_CTRL_SET(vop, vpost_st_end, val); - VOP_REG_SET(vop, intr, line_flag_num[0], vact_end); + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + u16 vact_st_f1 = vtotal + vact_st + 1; + u16 vact_end_f1 = vact_st_f1 + vdisplay; - clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); + val = vact_st_f1 << 16 | vact_end_f1; + VOP_CTRL_SET(vop, vact_st_end_f1, val); + VOP_CTRL_SET(vop, vpost_st_end_f1, val); - VOP_REG_SET(vop, common, standby, 0); - mutex_unlock(&vop->vop_lock); + val = vtotal << 16 | (vtotal + vsync_len); + VOP_CTRL_SET(vop, vs_st_end_f1, val); + VOP_CTRL_SET(vop, dsp_interlace, 1); + VOP_CTRL_SET(vop, p2i_en, 1); + vtotal += vtotal + 1; + act_end = vact_end_f1; + } else { + VOP_CTRL_SET(vop, dsp_interlace, 0); + VOP_CTRL_SET(vop, p2i_en, 0); + act_end = vact_end; + } + + if (VOP_MAJOR(vop->version) == 3 && + (VOP_MINOR(vop->version) == 2 || VOP_MINOR(vop->version) == 8)) + for_ddr_freq = 1000; + VOP_INTR_SET(vop, line_flag_num[0], act_end); + VOP_INTR_SET(vop, line_flag_num[1], + act_end - us_to_vertical_line(adjusted_mode, for_ddr_freq)); + + VOP_CTRL_SET(vop, vtotal_pw, vtotal << 16 | vsync_len); + + VOP_CTRL_SET(vop, core_dclk_div, + !!(adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)); + + VOP_CTRL_SET(vop, win_csc_mode_sel, 1); + + clk_set_rate(vop->dclk, adjusted_mode->crtc_clock * 1000); + + vop_cfg_done(vop); + + enable_irq(vop->irq); + drm_crtc_vblank_on(crtc); + //vop_unlock(vop); +} + +static void vop_post_config(struct drm_crtc *crtc) +{ + struct vop *vop = to_vop(crtc); + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + u16 vtotal = mode->crtc_vtotal; + u16 hdisplay = mode->crtc_hdisplay; + u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; + u16 vdisplay = mode->crtc_vdisplay; + u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; + u16 hsize = hdisplay * (s->left_margin + s->right_margin) / 200; + u16 vsize = vdisplay * (s->top_margin + s->bottom_margin) / 200; + u16 hact_end, vact_end; + u32 val; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vsize = rounddown(vsize, 2); + + hact_st += hdisplay * (100 - s->left_margin) / 200; + hact_end = hact_st + hsize; + val = hact_st << 16; + val |= hact_end; + VOP_CTRL_SET(vop, hpost_st_end, val); + vact_st += vdisplay * (100 - s->top_margin) / 200; + vact_end = vact_st + vsize; + val = vact_st << 16; + val |= vact_end; + VOP_CTRL_SET(vop, vpost_st_end, val); + val = scl_cal_scale2(vdisplay, vsize) << 16; + val |= scl_cal_scale2(hdisplay, hsize); + VOP_CTRL_SET(vop, post_scl_factor, val); + +#define POST_HORIZONTAL_SCALEDOWN_EN(x) ((x) << 0) +#define POST_VERTICAL_SCALEDOWN_EN(x) ((x) << 1) + VOP_CTRL_SET(vop, post_scl_ctrl, + POST_HORIZONTAL_SCALEDOWN_EN(hdisplay != hsize) | + POST_VERTICAL_SCALEDOWN_EN(vdisplay != vsize)); + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + u16 vact_st_f1 = vtotal + vact_st + 1; + u16 vact_end_f1 = vact_st_f1 + vsize; + + val = vact_st_f1 << 16 | vact_end_f1; + VOP_CTRL_SET(vop, vpost_st_end_f1, val); + } +} + +static void vop_cfg_update(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct rockchip_crtc_state *s = + to_rockchip_crtc_state(crtc->state); + struct vop *vop = to_vop(crtc); + + spin_lock(&vop->reg_lock); + + vop_update_csc(crtc); +#if 0 + vop_tv_config_update(crtc, old_crtc_state); + + if (s->afbdc_en) { + u32 pic_size, pic_offset; + + VOP_CTRL_SET(vop, afbdc_format, s->afbdc_win_format | 1 << 4); + VOP_CTRL_SET(vop, afbdc_hreg_block_split, 0); + VOP_CTRL_SET(vop, afbdc_sel, s->afbdc_win_id); + VOP_CTRL_SET(vop, afbdc_hdr_ptr, s->afbdc_win_ptr); + pic_size = (s->afbdc_win_width & 0xffff); + pic_size |= s->afbdc_win_height << 16; + VOP_CTRL_SET(vop, afbdc_pic_size, pic_size); + + VOP_CTRL_SET(vop, afbdc_pic_vir_width, s->afbdc_win_vir_width); + pic_offset = (s->afbdc_win_xoffset & 0xffff); + pic_offset |= s->afbdc_win_yoffset << 16; + VOP_CTRL_SET(vop, afbdc_pic_offset, pic_offset); + } + + VOP_CTRL_SET(vop, afbdc_en, s->afbdc_en); +#endif + VOP_CTRL_SET(vop, dsp_layer_sel, /*s->dsp_layer_sel*/0x24); + + s->left_margin = 100; + s->right_margin = 100; + s->top_margin = 100; + s->bottom_margin = 100; + vop_post_config(crtc); + + spin_unlock(&vop->reg_lock); } static bool vop_fs_irq_is_pending(struct vop *vop) @@ -1296,22 +1745,75 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct drm_atomic_state *old_state = old_crtc_state->state; - struct drm_plane_state *old_plane_state, *new_plane_state; + struct drm_plane_state *old_plane_state; struct vop *vop = to_vop(crtc); - struct drm_plane *plane = NULL; + struct drm_plane *plane; int i; - struct rockchip_crtc_state *s = - to_rockchip_crtc_state(crtc->state); + unsigned long flags; - if (WARN_ON(!vop->is_enabled)) - return; + vop_cfg_update(crtc, old_crtc_state); - spin_lock(&vop->reg_lock); + if (!vop->is_iommu_enabled && vop->is_iommu_needed) { + bool need_wait_vblank = 0; + int ret; - VOP_REG_SET(vop, common, dsp_layer_sel, s->dsp_layer_sel); + //if (vop->mode_update) + // vop_disable_all_planes(vop); + + need_wait_vblank = !vop_is_allwin_disabled(vop); + if (vop->mode_update && need_wait_vblank) + dev_warn(vop->dev, "mode_update:%d, need wait blk:%d\n", + vop->mode_update, need_wait_vblank); + + if (need_wait_vblank) { + bool active; + + disable_irq(vop->irq); + drm_crtc_vblank_get(crtc); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + ret = readx_poll_timeout_atomic(vop_fs_irq_is_active, + vop, active, active, + 0, 50 * 1000); + if (ret) + dev_err(vop->dev, "wait fs irq timeout\n"); + + VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1); + vop_cfg_done(vop); + + ret = readx_poll_timeout_atomic(vop_line_flag_is_active, + vop, active, active, + 0, 50 * 1000); + if (ret) + dev_err(vop->dev, "wait line flag timeout\n"); + + enable_irq(vop->irq); + } + ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev); + if (ret) { + vop->is_iommu_enabled = false; + vop_disable_all_planes(vop); + dev_err(vop->dev, "failed to attach dma mapping, %d\n", + ret); + } else { + vop->is_iommu_enabled = true; + VOP_CTRL_SET(vop, dma_stop, 0); + } + + if (need_wait_vblank) { + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); + drm_crtc_vblank_put(crtc); + } + } + + //vop_update_cabc(crtc, old_crtc_state); + //vop_update_hdr(crtc, old_crtc_state); + + spin_lock_irqsave(&vop->irq_lock, flags); + //vop->pre_overlay = s->hdr.pre_overlay; vop_cfg_done(vop); - - spin_unlock(&vop->reg_lock); + vop->mode_update = false; + spin_unlock_irqrestore(&vop->irq_lock, flags); /* * There is a (rather unlikely) possiblity that a vblank interrupt @@ -1330,12 +1832,12 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, } spin_unlock_irq(&crtc->dev->event_lock); - for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, - new_plane_state, i) { +#if 0 + for_each_plane_in_state(old_state, plane, old_plane_state, i) { if (!old_plane_state->fb) continue; - if (old_plane_state->fb == new_plane_state->fb) + if (old_plane_state->fb == plane->state->fb) continue; drm_framebuffer_get(old_plane_state->fb); @@ -1343,6 +1845,20 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb); set_bit(VOP_PENDING_FB_UNREF, &vop->pending); } +#else + for_each_old_plane_in_state(old_state, plane, old_plane_state, i) { + if (!old_plane_state->fb) + continue; + + if (old_plane_state->fb == plane->state->fb) + continue; + + drm_framebuffer_get(old_plane_state->fb); + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb); + set_bit(VOP_PENDING_FB_UNREF, &vop->pending); + } +#endif } static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { @@ -1360,13 +1876,23 @@ static void vop_crtc_destroy(struct drm_crtc *crtc) static void vop_crtc_reset(struct drm_crtc *crtc) { - if (crtc->state) - __drm_atomic_helper_crtc_destroy_state(crtc->state); - kfree(crtc->state); + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); - crtc->state = kzalloc(sizeof(struct drm_crtc_state), GFP_KERNEL); - if (crtc->state) - crtc->state->crtc = crtc; + if (crtc->state) { + __drm_atomic_helper_crtc_destroy_state(crtc->state); + kfree(s); + } + + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return; + crtc->state = &s->base; + crtc->state->crtc = crtc; + + s->left_margin = 100; + s->right_margin = 100; + s->top_margin = 100; + s->bottom_margin = 100; } static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) @@ -1481,14 +2007,15 @@ static void vop_handle_vblank(struct vop *vop) { struct drm_device *drm = vop->drm_dev; struct drm_crtc *crtc = &vop->crtc; + unsigned long flags; - spin_lock(&drm->event_lock); + spin_lock_irqsave(&drm->event_lock, flags); if (vop->event) { drm_crtc_send_vblank_event(crtc, vop->event); drm_crtc_vblank_put(crtc); vop->event = NULL; } - spin_unlock(&drm->event_lock); + spin_unlock_irqrestore(&drm->event_lock, flags); if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq); @@ -1499,6 +2026,7 @@ static irqreturn_t vop_isr(int irq, void *data) struct vop *vop = data; struct drm_crtc *crtc = &vop->crtc; uint32_t active_irqs; + unsigned long flags; int ret = IRQ_NONE; /* @@ -1517,14 +2045,14 @@ static irqreturn_t vop_isr(int irq, void *data) * interrupt register has interrupt status, enable and clear bits, we * must hold irq_lock to avoid a race with enable/disable_vblank(). */ - spin_lock(&vop->irq_lock); + spin_lock_irqsave(&vop->irq_lock, flags); active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK); /* Clear all active interrupt sources */ if (active_irqs) VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1); - spin_unlock(&vop->irq_lock); + spin_unlock_irqrestore(&vop->irq_lock, flags); /* This is expected for vop iommu irqs, since the irq is shared */ if (!active_irqs) @@ -1543,16 +2071,40 @@ static irqreturn_t vop_isr(int irq, void *data) } if (active_irqs & FS_INTR) { + /* This is IC design not reasonable, this two register bit need + * frame effective, but actually it's effective immediately, so + * we config this register at frame start. + */ + spin_lock_irqsave(&vop->irq_lock, flags); + VOP_CTRL_SET(vop, level2_overlay_en, vop->pre_overlay); + VOP_CTRL_SET(vop, alpha_hard_calc, vop->pre_overlay); + spin_unlock_irqrestore(&vop->irq_lock, flags); drm_crtc_handle_vblank(crtc); vop_handle_vblank(vop); active_irqs &= ~FS_INTR; ret = IRQ_HANDLED; } +#define ERROR_HANDLER(x) \ + do { \ + if (active_irqs & x##_INTR) {\ + DRM_DEV_ERROR_RATELIMITED(vop->dev, #x " irq err\n"); \ + active_irqs &= ~x##_INTR; \ + ret = IRQ_HANDLED; \ + } \ + } while (0) + + ERROR_HANDLER(BUS_ERROR); + ERROR_HANDLER(WIN0_EMPTY); + ERROR_HANDLER(WIN1_EMPTY); + ERROR_HANDLER(WIN2_EMPTY); + ERROR_HANDLER(WIN3_EMPTY); + ERROR_HANDLER(HWC_EMPTY); + ERROR_HANDLER(POST_BUF_EMPTY); + /* Unhandled irqs are spurious. */ if (active_irqs) - DRM_DEV_ERROR(vop->dev, "Unknown VOP IRQs: %#02x\n", - active_irqs); + DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs); out_disable: vop_core_clks_disable(vop); @@ -1561,13 +2113,14 @@ static irqreturn_t vop_isr(int irq, void *data) return ret; } -static void vop_plane_add_properties(struct drm_plane *plane, +static void vop_plane_add_properties(struct vop *vop, + struct drm_plane *plane, const struct vop_win *win) { unsigned int flags = 0; - flags |= VOP_WIN_HAS_REG(win, x_mir_en) ? DRM_MODE_REFLECT_X : 0; - flags |= VOP_WIN_HAS_REG(win, y_mir_en) ? DRM_MODE_REFLECT_Y : 0; + flags |= (VOP_WIN_SUPPORT(vop, win, xmirror)) ? DRM_MODE_REFLECT_X : 0; + flags |= (VOP_WIN_SUPPORT(vop, win, ymirror)) ? DRM_MODE_REFLECT_Y : 0; if (flags) drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | flags); @@ -1652,7 +2205,7 @@ static int vop_create_crtc(struct vop *vop) DRM_DEV_ERROR(vop->dev, "failed to init overlay\n"); goto err_cleanup_crtc; } - vop_plane_add_properties(&win->base, win); + vop_plane_add_properties(vop, &win->base, win); } port = of_get_child_by_name(dev->of_node, "port"); @@ -1709,118 +2262,6 @@ static void vop_destroy_crtc(struct vop *vop) drm_flip_work_cleanup(&vop->fb_unref_work); } -static int vop_initial(struct vop *vop) -{ - struct reset_control *ahb_rst; - int i, ret; - - vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); - if (IS_ERR(vop->hclk)) { - DRM_DEV_ERROR(vop->dev, "failed to get hclk source\n"); - return PTR_ERR(vop->hclk); - } - vop->aclk = devm_clk_get(vop->dev, "aclk_vop"); - if (IS_ERR(vop->aclk)) { - DRM_DEV_ERROR(vop->dev, "failed to get aclk source\n"); - return PTR_ERR(vop->aclk); - } - vop->dclk = devm_clk_get(vop->dev, "dclk_vop"); - if (IS_ERR(vop->dclk)) { - DRM_DEV_ERROR(vop->dev, "failed to get dclk source\n"); - return PTR_ERR(vop->dclk); - } - - ret = pm_runtime_get_sync(vop->dev); - if (ret < 0) { - DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); - return ret; - } - - ret = clk_prepare(vop->dclk); - if (ret < 0) { - DRM_DEV_ERROR(vop->dev, "failed to prepare dclk\n"); - goto err_put_pm_runtime; - } - - /* Enable both the hclk and aclk to setup the vop */ - ret = clk_prepare_enable(vop->hclk); - if (ret < 0) { - DRM_DEV_ERROR(vop->dev, "failed to prepare/enable hclk\n"); - goto err_unprepare_dclk; - } - - ret = clk_prepare_enable(vop->aclk); - if (ret < 0) { - DRM_DEV_ERROR(vop->dev, "failed to prepare/enable aclk\n"); - goto err_disable_hclk; - } - - /* - * do hclk_reset, reset all vop registers. - */ - ahb_rst = devm_reset_control_get(vop->dev, "ahb"); - if (IS_ERR(ahb_rst)) { - DRM_DEV_ERROR(vop->dev, "failed to get ahb reset\n"); - ret = PTR_ERR(ahb_rst); - goto err_disable_aclk; - } - reset_control_assert(ahb_rst); - usleep_range(10, 20); - reset_control_deassert(ahb_rst); - - VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1); - VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0); - - for (i = 0; i < vop->len; i += sizeof(u32)) - vop->regsbak[i / 4] = readl_relaxed(vop->regs + i); - - VOP_REG_SET(vop, misc, global_regdone_en, 1); - VOP_REG_SET(vop, common, dsp_blank, 0); - - for (i = 0; i < vop->num_wins; i++) { - struct vop_win *win = &vop->win[i]; - int channel = i * 2 + 1; - - VOP_WIN_SET(vop, win, channel, (channel + 1) << 4 | channel); - VOP_WIN_SET(vop, win, enable, 0); - VOP_WIN_SET(vop, win, gate, 1); - } - - vop_cfg_done(vop); - - /* - * do dclk_reset, let all config take affect. - */ - vop->dclk_rst = devm_reset_control_get(vop->dev, "dclk"); - if (IS_ERR(vop->dclk_rst)) { - DRM_DEV_ERROR(vop->dev, "failed to get dclk reset\n"); - ret = PTR_ERR(vop->dclk_rst); - goto err_disable_aclk; - } - reset_control_assert(vop->dclk_rst); - usleep_range(10, 20); - reset_control_deassert(vop->dclk_rst); - - clk_disable(vop->hclk); - clk_disable(vop->aclk); - - vop->is_enabled = false; - - pm_runtime_put_sync(vop->dev); - - return 0; - -err_disable_aclk: - clk_disable_unprepare(vop->aclk); -err_disable_hclk: - clk_disable_unprepare(vop->hclk); -err_unprepare_dclk: - clk_unprepare(vop->dclk); -err_put_pm_runtime: - pm_runtime_put_sync(vop->dev); - return ret; -} - /* * Initialize the vop->win array elements. */ @@ -1835,13 +2276,17 @@ static int vop_win_init(struct vop *vop) struct vop_win *vop_win = &vop->win[num_wins]; const struct vop_win_data *win_data = &vop_data->win[i]; + if (!win_data->phy) + continue; + vop_win->phy = win_data->phy; + vop_win->csc = win_data->csc; vop_win->offset = win_data->base; vop_win->type = win_data->type; vop_win->data_formats = win_data->phy->data_formats; vop_win->nformats = win_data->phy->nformats; + vop_win->feature = win_data->feature; vop_win->vop = vop; - vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i]; vop_win->win_id = i; vop_win->area_id = 0; num_wins++; @@ -1862,6 +2307,9 @@ static int vop_win_init(struct vop *vop) num_wins++; } } + + vop->num_wins = num_wins; + prop = drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_ATOMIC, "ZPOS", 0, vop_data->win_size); if (!prop) { @@ -1929,6 +2377,7 @@ static int vop_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm_dev = data; struct vop *vop; struct resource *res; + size_t alloc_size; int ret, irq, i; int num_wins = 0; @@ -1943,8 +2392,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data) } /* Allocate vop struct and its vop_win array */ - vop = devm_kzalloc(dev, struct_size(vop, win, num_wins), - GFP_KERNEL); + alloc_size = sizeof(*vop) + sizeof(*vop->win) * num_wins; + vop = devm_kzalloc(dev, alloc_size, GFP_KERNEL); if (!vop) return -ENOMEM; @@ -1952,22 +2401,46 @@ static int vop_bind(struct device *dev, struct device *master, void *data) vop->data = vop_data; vop->drm_dev = drm_dev; vop->num_wins = num_wins; + vop->version = vop_data->version; dev_set_drvdata(dev, vop); ret = vop_win_init(vop); if (ret) return ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vop->len = resource_size(res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!res) { + dev_warn(vop->dev, "failed to get vop register byname\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + } vop->regs = devm_ioremap_resource(dev, res); if (IS_ERR(vop->regs)) return PTR_ERR(vop->regs); + vop->len = resource_size(res); vop->regsbak = devm_kzalloc(dev, vop->len, GFP_KERNEL); if (!vop->regsbak) return -ENOMEM; + vop->grf = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + if (IS_ERR(vop->grf)) + dev_err(dev, "missing rockchip,grf property\n"); + vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); + if (IS_ERR(vop->hclk)) { + dev_err(vop->dev, "failed to get hclk source\n"); + return PTR_ERR(vop->hclk); + } + vop->aclk = devm_clk_get(vop->dev, "aclk_vop"); + if (IS_ERR(vop->aclk)) { + dev_err(vop->dev, "failed to get aclk source\n"); + return PTR_ERR(vop->aclk); + } + vop->dclk = devm_clk_get(vop->dev, "dclk_vop"); + if (IS_ERR(vop->dclk)) { + dev_err(vop->dev, "failed to get dclk source\n"); + return PTR_ERR(vop->dclk); + } irq = platform_get_irq(pdev, 0); if (irq < 0) { DRM_DEV_ERROR(dev, "cannot find irq for vop\n"); @@ -1979,30 +2452,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data) spin_lock_init(&vop->irq_lock); mutex_init(&vop->vop_lock); + ret = devm_request_irq(dev, vop->irq, vop_isr, + IRQF_SHARED, dev_name(dev), vop); + if (ret) + return ret; + disable_irq(vop->irq); ret = vop_create_crtc(vop); if (ret) return ret; pm_runtime_enable(&pdev->dev); - ret = vop_initial(vop); - if (ret < 0) { - DRM_DEV_ERROR(&pdev->dev, - "cannot initial vop dev - err %d\n", ret); - goto err_disable_pm_runtime; - } - - ret = devm_request_irq(dev, vop->irq, vop_isr, - IRQF_SHARED, dev_name(dev), vop); - if (ret) - goto err_disable_pm_runtime; return 0; - -err_disable_pm_runtime: - pm_runtime_disable(&pdev->dev); - vop_destroy_crtc(vop); - return ret; } static void vop_unbind(struct device *dev, struct device *master, void *data) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 52e9494084c8..3e630a9f9fe8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -23,7 +23,47 @@ #define VOP_MAJOR(version) ((version) >> 8) #define VOP_MINOR(version) ((version) & 0xff) -#define NUM_YUV2YUV_COEFFICIENTS 12 +#define ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL BIT(0) +#define ROCKCHIP_OUTPUT_DSI_DUAL_LINK BIT(1) + +#define AFBDC_FMT_RGB565 0x0 +#define AFBDC_FMT_U8U8U8U8 0x5 +#define AFBDC_FMT_U8U8U8 0x4 + +enum bcsh_out_mode { + BCSH_OUT_MODE_BLACK, + BCSH_OUT_MODE_BLUE, + BCSH_OUT_MODE_COLOR_BAR, + BCSH_OUT_MODE_NORMAL_VIDEO, +}; + +enum cabc_stage_mode { + LAST_FRAME_PWM_VAL = 0x0, + CUR_FRAME_PWM_VAL = 0x1, + STAGE_BY_STAGE = 0x2 +}; + +enum cabc_stage_up_mode { + MUL_MODE, + ADD_MODE, +}; + +#define DSP_BG_SWAP 0x1 +#define DSP_RB_SWAP 0x2 +#define DSP_RG_SWAP 0x4 +#define DSP_DELTA_SWAP 0x8 + +enum vop_csc_format { + CSC_BT601L, + CSC_BT709L, + CSC_BT601F, + CSC_BT2020, +}; + +enum vop_csc_mode { + CSC_RGB, + CSC_YUV, +}; enum vop_data_format { VOP_FMT_ARGB8888 = 0, @@ -34,60 +74,177 @@ enum vop_data_format { VOP_FMT_YUV444SP, }; +struct vop_reg_data { + uint32_t offset; + uint32_t value; +}; + struct vop_reg { uint32_t mask; - uint16_t offset; - uint8_t shift; - bool write_mask; - bool relaxed; + uint32_t offset:12; + uint32_t shift:5; + uint32_t begin_minor:4; + uint32_t end_minor:4; + uint32_t major:3; + uint32_t write_mask:1; }; -struct vop_modeset { +struct vop_csc { + struct vop_reg y2r_en; + struct vop_reg r2r_en; + struct vop_reg r2y_en; + + uint32_t y2r_offset; + uint32_t r2r_offset; + uint32_t r2y_offset; +}; + +struct vop_ctrl { + struct vop_reg version; + struct vop_reg standby; + struct vop_reg dma_stop; + struct vop_reg axi_outstanding_max_num; + struct vop_reg axi_max_outstanding_en; struct vop_reg htotal_pw; struct vop_reg hact_st_end; - struct vop_reg hpost_st_end; struct vop_reg vtotal_pw; struct vop_reg vact_st_end; + struct vop_reg vact_st_end_f1; + struct vop_reg vs_st_end_f1; + struct vop_reg hpost_st_end; struct vop_reg vpost_st_end; -}; - -struct vop_output { - struct vop_reg pin_pol; - struct vop_reg dp_pin_pol; - struct vop_reg edp_pin_pol; - struct vop_reg hdmi_pin_pol; - struct vop_reg mipi_pin_pol; - struct vop_reg rgb_pin_pol; - struct vop_reg dp_en; + struct vop_reg vpost_st_end_f1; + struct vop_reg post_scl_factor; + struct vop_reg post_scl_ctrl; + struct vop_reg dsp_interlace; + struct vop_reg global_regdone_en; + struct vop_reg auto_gate_en; + struct vop_reg post_lb_mode; + struct vop_reg dsp_layer_sel; + struct vop_reg overlay_mode; + struct vop_reg core_dclk_div; + struct vop_reg dclk_ddr; + struct vop_reg p2i_en; + struct vop_reg hdmi_dclk_out_en; + struct vop_reg rgb_en; + struct vop_reg lvds_en; struct vop_reg edp_en; struct vop_reg hdmi_en; struct vop_reg mipi_en; - struct vop_reg rgb_en; -}; + struct vop_reg data01_swap; + struct vop_reg mipi_dual_channel_en; + struct vop_reg dp_en; + struct vop_reg dclk_pol; + struct vop_reg pin_pol; + struct vop_reg rgb_dclk_pol; + struct vop_reg rgb_pin_pol; + struct vop_reg lvds_dclk_pol; + struct vop_reg lvds_pin_pol; + struct vop_reg hdmi_dclk_pol; + struct vop_reg hdmi_pin_pol; + struct vop_reg edp_dclk_pol; + struct vop_reg edp_pin_pol; + struct vop_reg mipi_dclk_pol; + struct vop_reg mipi_pin_pol; + struct vop_reg dp_dclk_pol; + struct vop_reg dp_pin_pol; + struct vop_reg dither_down_sel; + struct vop_reg dither_down_mode; + struct vop_reg dither_down_en; + struct vop_reg pre_dither_down_en; + struct vop_reg dither_up_en; -struct vop_common { - struct vop_reg cfg_done; + struct vop_reg sw_dac_sel; + struct vop_reg tve_sw_mode; + struct vop_reg tve_dclk_pol; + struct vop_reg tve_dclk_en; + struct vop_reg sw_genlock; + struct vop_reg sw_uv_offset_en; + struct vop_reg dsp_out_yuv; + struct vop_reg dsp_data_swap; + struct vop_reg dsp_ccir656_avg; + struct vop_reg dsp_black; struct vop_reg dsp_blank; - struct vop_reg data_blank; - struct vop_reg pre_dither_down; - struct vop_reg dither_down; - struct vop_reg dither_up; - struct vop_reg gate_en; - struct vop_reg mmu_en; - struct vop_reg out_mode; - struct vop_reg standby; - struct vop_reg yuv_overlay; - struct vop_reg dsp_layer_sel; -}; + struct vop_reg dsp_outzero; + struct vop_reg update_gamma_lut; + struct vop_reg lut_buffer_index; + struct vop_reg dsp_lut_en; -struct vop_misc { - struct vop_reg global_regdone_en; + struct vop_reg out_mode; + + struct vop_reg xmirror; + struct vop_reg ymirror; + struct vop_reg dsp_background; + + /* AFBDC */ + struct vop_reg afbdc_en; + struct vop_reg afbdc_sel; + struct vop_reg afbdc_format; + struct vop_reg afbdc_hreg_block_split; + struct vop_reg afbdc_pic_size; + struct vop_reg afbdc_hdr_ptr; + struct vop_reg afbdc_rstn; + struct vop_reg afbdc_pic_vir_width; + struct vop_reg afbdc_pic_offset; + struct vop_reg afbdc_axi_ctrl; + + /* BCSH */ + struct vop_reg bcsh_brightness; + struct vop_reg bcsh_contrast; + struct vop_reg bcsh_sat_con; + struct vop_reg bcsh_sin_hue; + struct vop_reg bcsh_cos_hue; + struct vop_reg bcsh_r2y_csc_mode; + struct vop_reg bcsh_r2y_en; + struct vop_reg bcsh_y2r_csc_mode; + struct vop_reg bcsh_y2r_en; + struct vop_reg bcsh_color_bar; + struct vop_reg bcsh_out_mode; + struct vop_reg bcsh_en; + + /* HDR */ + struct vop_reg level2_overlay_en; + struct vop_reg alpha_hard_calc; + struct vop_reg hdr2sdr_en; + struct vop_reg hdr2sdr_en_win0_csc; + struct vop_reg hdr2sdr_src_min; + struct vop_reg hdr2sdr_src_max; + struct vop_reg hdr2sdr_normfaceetf; + struct vop_reg hdr2sdr_dst_min; + struct vop_reg hdr2sdr_dst_max; + struct vop_reg hdr2sdr_normfacgamma; + + struct vop_reg bt1886eotf_pre_conv_en; + struct vop_reg rgb2rgb_pre_conv_en; + struct vop_reg rgb2rgb_pre_conv_mode; + struct vop_reg st2084oetf_pre_conv_en; + struct vop_reg bt1886eotf_post_conv_en; + struct vop_reg rgb2rgb_post_conv_en; + struct vop_reg rgb2rgb_post_conv_mode; + struct vop_reg st2084oetf_post_conv_en; + struct vop_reg win_csc_mode_sel; + + /* MCU OUTPUT */ + struct vop_reg mcu_pix_total; + struct vop_reg mcu_cs_pst; + struct vop_reg mcu_cs_pend; + struct vop_reg mcu_rw_pst; + struct vop_reg mcu_rw_pend; + struct vop_reg mcu_clk_sel; + struct vop_reg mcu_hold_mode; + struct vop_reg mcu_frame_st; + struct vop_reg mcu_rs; + struct vop_reg mcu_bypass; + struct vop_reg mcu_type; + struct vop_reg mcu_rw_bypass_port; + + struct vop_reg reg_done_frm; + struct vop_reg cfg_done; }; struct vop_intr { const int *intrs; uint32_t nintrs; - struct vop_reg line_flag_num[2]; struct vop_reg enable; struct vop_reg clear; @@ -127,8 +284,90 @@ struct vop_scl_regs { struct vop_reg scale_cbcr_y; }; -struct vop_yuv2yuv_phy { - struct vop_reg y2r_coefficients[NUM_YUV2YUV_COEFFICIENTS]; +struct vop_csc_table { + const uint32_t *y2r_bt601; + const uint32_t *y2r_bt601_12_235; + const uint32_t *y2r_bt601_10bit; + const uint32_t *y2r_bt601_10bit_12_235; + const uint32_t *r2y_bt601; + const uint32_t *r2y_bt601_12_235; + const uint32_t *r2y_bt601_10bit; + const uint32_t *r2y_bt601_10bit_12_235; + + const uint32_t *y2r_bt709; + const uint32_t *y2r_bt709_10bit; + const uint32_t *r2y_bt709; + const uint32_t *r2y_bt709_10bit; + + const uint32_t *y2r_bt2020; + const uint32_t *r2y_bt2020; + + const uint32_t *r2r_bt709_to_bt2020; + const uint32_t *r2r_bt2020_to_bt709; +}; + +struct vop_hdr_table { + const uint32_t hdr2sdr_eetf_oetf_y0_offset; + const uint32_t hdr2sdr_eetf_oetf_y1_offset; + const uint32_t *hdr2sdr_eetf_yn; + const uint32_t *hdr2sdr_bt1886oetf_yn; + const uint32_t hdr2sdr_sat_y0_offset; + const uint32_t hdr2sdr_sat_y1_offset; + const uint32_t *hdr2sdr_sat_yn; + + const uint32_t hdr2sdr_src_range_min; + const uint32_t hdr2sdr_src_range_max; + const uint32_t hdr2sdr_normfaceetf; + const uint32_t hdr2sdr_dst_range_min; + const uint32_t hdr2sdr_dst_range_max; + const uint32_t hdr2sdr_normfacgamma; + + const uint32_t sdr2hdr_eotf_oetf_y0_offset; + const uint32_t sdr2hdr_eotf_oetf_y1_offset; + const uint32_t *sdr2hdr_bt1886eotf_yn_for_hlg_hdr; + const uint32_t *sdr2hdr_bt1886eotf_yn_for_bt2020; + const uint32_t *sdr2hdr_bt1886eotf_yn_for_hdr; + const uint32_t *sdr2hdr_st2084oetf_yn_for_hlg_hdr; + const uint32_t *sdr2hdr_st2084oetf_yn_for_bt2020; + const uint32_t *sdr2hdr_st2084oetf_yn_for_hdr; + const uint32_t sdr2hdr_oetf_dx_dxpow1_offset; + const uint32_t *sdr2hdr_st2084oetf_dxn_pow2; + const uint32_t *sdr2hdr_st2084oetf_dxn; + const uint32_t sdr2hdr_oetf_xn1_offset; + const uint32_t *sdr2hdr_st2084oetf_xn; +}; + +enum { + VOP_CSC_Y2R_BT601, + VOP_CSC_Y2R_BT709, + VOP_CSC_Y2R_BT2020, + VOP_CSC_R2Y_BT601, + VOP_CSC_R2Y_BT709, + VOP_CSC_R2Y_BT2020, + VOP_CSC_R2R_BT2020_TO_BT709, + VOP_CSC_R2R_BT709_TO_2020, +}; + +enum _vop_overlay_mode { + VOP_RGB_DOMAIN, + VOP_YUV_DOMAIN +}; + +enum _vop_sdr2hdr_func { + SDR2HDR_FOR_BT2020, + SDR2HDR_FOR_HDR, + SDR2HDR_FOR_HLG_HDR, +}; + +enum _vop_rgb2rgb_conv_mode { + BT709_TO_BT2020, + BT2020_TO_BT709, +}; + +enum _MCU_IOCTL { + MCU_WRCMD = 0, + MCU_WRDATA, + MCU_SETBYPASS, }; struct vop_win_phy { @@ -136,9 +375,13 @@ struct vop_win_phy { const uint32_t *data_formats; uint32_t nformats; - struct vop_reg enable; struct vop_reg gate; + struct vop_reg enable; struct vop_reg format; + struct vop_reg fmt_10; + struct vop_reg csc_mode; + struct vop_reg xmirror; + struct vop_reg ymirror; struct vop_reg rb_swap; struct vop_reg act_info; struct vop_reg dsp_info; @@ -147,59 +390,89 @@ struct vop_win_phy { struct vop_reg uv_mst; struct vop_reg yrgb_vir; struct vop_reg uv_vir; - struct vop_reg y_mir_en; - struct vop_reg x_mir_en; + struct vop_reg channel; struct vop_reg dst_alpha_ctl; struct vop_reg src_alpha_ctl; - struct vop_reg channel; -}; - -struct vop_win_yuv2yuv_data { - uint32_t base; - const struct vop_yuv2yuv_phy *phy; - struct vop_reg y2r_en; + struct vop_reg alpha_mode; + struct vop_reg alpha_en; + struct vop_reg alpha_pre_mul; + struct vop_reg global_alpha_val; + struct vop_reg key_color; + struct vop_reg key_en; }; struct vop_win_data { uint32_t base; - const struct vop_win_phy *phy; enum drm_plane_type type; + const struct vop_win_phy *phy; const struct vop_win_phy **area; + const struct vop_csc *csc; unsigned int area_size; + u64 feature; }; +struct vop_grf_ctrl { + struct vop_reg grf_dclk_inv; +}; + +#define VOP_FEATURE_OUTPUT_10BIT BIT(0) +#define VOP_FEATURE_AFBDC BIT(1) +#define VOP_FEATURE_ALPHA_SCALE BIT(2) + +#define WIN_FEATURE_HDR2SDR BIT(0) +#define WIN_FEATURE_SDR2HDR BIT(1) +#define WIN_FEATURE_PRE_OVERLAY BIT(2) +#define WIN_FEATURE_AFBDC BIT(3) + struct vop_rect { int width; int height; }; struct vop_data { - uint32_t version; + const struct vop_reg_data *init_table; + unsigned int table_size; + const struct vop_ctrl *ctrl; const struct vop_intr *intr; - const struct vop_common *common; - const struct vop_misc *misc; - const struct vop_modeset *modeset; - const struct vop_output *output; - const struct vop_win_yuv2yuv_data *win_yuv2yuv; const struct vop_win_data *win; + const struct vop_csc_table *csc_table; + const struct vop_hdr_table *hdr_table; + const struct vop_grf_ctrl *grf_ctrl; unsigned int win_size; - + uint32_t version; struct vop_rect max_input; struct vop_rect max_output; - -#define VOP_FEATURE_OUTPUT_RGB10 BIT(0) u64 feature; }; +#define CVBS_PAL_VDISPLAY 288 + /* interrupt define */ -#define DSP_HOLD_VALID_INTR (1 << 0) -#define FS_INTR (1 << 1) -#define LINE_FLAG_INTR (1 << 2) -#define BUS_ERROR_INTR (1 << 3) +#define DSP_HOLD_VALID_INTR BIT(0) +#define FS_INTR BIT(1) +#define LINE_FLAG_INTR BIT(2) +#define BUS_ERROR_INTR BIT(3) +#define FS_NEW_INTR BIT(4) +#define ADDR_SAME_INTR BIT(5) +#define LINE_FLAG1_INTR BIT(6) +#define WIN0_EMPTY_INTR BIT(7) +#define WIN1_EMPTY_INTR BIT(8) +#define WIN2_EMPTY_INTR BIT(9) +#define WIN3_EMPTY_INTR BIT(10) +#define HWC_EMPTY_INTR BIT(11) +#define POST_BUF_EMPTY_INTR BIT(12) +#define PWM_GEN_INTR BIT(13) +#define DMA_FINISH_INTR BIT(14) #define INTR_MASK (DSP_HOLD_VALID_INTR | FS_INTR | \ - LINE_FLAG_INTR | BUS_ERROR_INTR) + LINE_FLAG_INTR | BUS_ERROR_INTR | \ + FS_NEW_INTR | LINE_FLAG1_INTR | \ + WIN0_EMPTY_INTR | WIN1_EMPTY_INTR | \ + WIN2_EMPTY_INTR | WIN3_EMPTY_INTR | \ + HWC_EMPTY_INTR | \ + POST_BUF_EMPTY_INTR | \ + DMA_FINISH_INTR) #define DSP_HOLD_VALID_INTR_EN(x) ((x) << 4) #define FS_INTR_EN(x) ((x) << 5) @@ -234,11 +507,17 @@ struct vop_data { /* * display output interface supported by rockchip lcdc */ -#define ROCKCHIP_OUT_MODE_P888 0 -#define ROCKCHIP_OUT_MODE_P666 1 -#define ROCKCHIP_OUT_MODE_P565 2 +#define ROCKCHIP_OUT_MODE_P888 0 +#define ROCKCHIP_OUT_MODE_P666 1 +#define ROCKCHIP_OUT_MODE_P565 2 +#define ROCKCHIP_OUT_MODE_S888 8 +#define ROCKCHIP_OUT_MODE_S888_DUMMY 12 +#define ROCKCHIP_OUT_MODE_YUV420 14 /* for use special outface */ -#define ROCKCHIP_OUT_MODE_AAAA 15 +#define ROCKCHIP_OUT_MODE_AAAA 15 + +#define ROCKCHIP_OUT_MODE_TYPE(x) ((x) >> 16) +#define ROCKCHIP_OUT_MODE(x) ((x) & 0xffff) enum alpha_mode { ALPHA_STRAIGHT, @@ -294,6 +573,16 @@ enum scale_down_mode { SCALE_DOWN_AVG = 0x1 }; +enum dither_down_mode { + RGB888_TO_RGB565 = 0x0, + RGB888_TO_RGB666 = 0x1 +}; + +enum dither_down_mode_sel { + DITHER_DOWN_ALLEGRO = 0x0, + DITHER_DOWN_FRC = 0x1 +}; + enum vop_pol { HSYNC_POSITIVE = 0, VSYNC_POSITIVE = 1, @@ -375,5 +664,15 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv) return lb_mode; } +static inline int us_to_vertical_line(struct drm_display_mode *mode, int us) +{ + return us * mode->clock / mode->htotal / 1000; +} + +static inline int interpolate(int x1, int y1, int x2, int y2, int x) +{ + return y1 + (y2 - y1) * (x - x1) / (x2 - x1); +} + extern const struct component_ops vop_component_ops; #endif /* _ROCKCHIP_DRM_VOP_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 9d288f9fcdd4..ec844188d919 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -20,23 +20,26 @@ #include "rockchip_drm_vop.h" #include "rockchip_vop_reg.h" -#define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \ - { \ - .offset = off, \ +#define VOP_REG_VER_MASK(off, _mask, s, _write_mask, _major, \ + _begin_minor, _end_minor) \ + {.offset = off, \ .mask = _mask, \ - .shift = _shift, \ + .shift = s, \ .write_mask = _write_mask, \ - .relaxed = _relaxed, \ - } + .major = _major, \ + .begin_minor = _begin_minor, \ + .end_minor = _end_minor,} -#define VOP_REG(off, _mask, _shift) \ - _VOP_REG(off, _mask, _shift, false, true) +#define VOP_REG(off, _mask, s) \ + VOP_REG_VER_MASK(off, _mask, s, false, 0, 0, -1) -#define VOP_REG_SYNC(off, _mask, _shift) \ - _VOP_REG(off, _mask, _shift, false, false) +#define VOP_REG_MASK(off, _mask, s) \ + VOP_REG_VER_MASK(off, _mask, s, true, 0, 0, -1) + +#define VOP_REG_VER(off, _mask, s, _major, _begin_minor, _end_minor) \ + VOP_REG_VER_MASK(off, _mask, s, false, \ + _major, _begin_minor, _end_minor) -#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, @@ -63,125 +66,6 @@ static const uint32_t formats_win_lite[] = { DRM_FORMAT_BGR565, }; -static const struct vop_scl_regs rk3036_win_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_win_phy rk3036_win0_data = { - .scl = &rk3036_win_scl, - .data_formats = formats_win_full, - .nformats = ARRAY_SIZE(formats_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), - .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0), - .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), -}; - -static const struct vop_win_phy rk3036_win1_data = { - .data_formats = formats_win_lite, - .nformats = ARRAY_SIZE(formats_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), - .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0), - .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), -}; - -static const struct vop_win_data rk3036_vop_win_data[] = { - { .base = 0x00, .phy = &rk3036_win0_data, - .type = DRM_PLANE_TYPE_PRIMARY }, - { .base = 0x00, .phy = &rk3036_win1_data, - .type = DRM_PLANE_TYPE_CURSOR }, -}; - -static const int rk3036_vop_intrs[] = { - DSP_HOLD_VALID_INTR, - FS_INTR, - LINE_FLAG_INTR, - BUS_ERROR_INTR, -}; - -static const struct vop_intr rk3036_intr = { - .intrs = rk3036_vop_intrs, - .nintrs = ARRAY_SIZE(rk3036_vop_intrs), - .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_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), -}; - -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), - .cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0), - .dsp_layer_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 8), -}; - -static const struct vop_data rk3036_vop = { - .max_input = {1920, 8192}, - .max_output = {1920, 1080}, - .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), -}; - -static const struct vop_win_phy rk3126_win1_data = { - .data_formats = formats_win_lite, - .nformats = ARRAY_SIZE(formats_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), -}; - -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_data rk3126_vop = { - .max_input = {1920, 8192}, - .max_output = {1920, 1080}, - .intr = &rk3036_intr, - .common = &rk3036_common, - .modeset = &rk3036_modeset, - .output = &rk3036_output, - .win = rk3126_vop_win_data, - .win_size = ARRAY_SIZE(rk3126_vop_win_data), -}; - static const struct vop_scl_extension rk3288_win_full_scl_ext = { .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31), .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30), @@ -220,7 +104,11 @@ static const struct vop_win_phy rk3288_win01_data = { .nformats = ARRAY_SIZE(formats_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, 0x7, 4), + .csc_mode = VOP_REG_VER(RK3288_WIN0_CTRL0, 0x3, 10, 3, 2, -1), .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .xmirror = VOP_REG_VER(RK3368_WIN0_CTRL0, 0x1, 21, 3, 2, -1), + .ymirror = VOP_REG_VER(RK3368_WIN0_CTRL0, 0x1, 22, 3, 2, -1), .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), @@ -228,24 +116,26 @@ static const struct vop_win_phy rk3288_win01_data = { .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), .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), + .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xffff, 0), + .global_alpha_val = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 16), + .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xffffffff, 0), + .channel = VOP_REG_VER(RK3288_WIN0_CTRL2, 0xff, 0, 3, 8, 8), }; 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, 4), .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), + .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4), .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), .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0), .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0), .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0), - .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0), - .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0), + .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xffff, 0), + .global_alpha_val = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 16), + .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xffffffff, 0), }; static const struct vop_win_phy rk3288_area1_data = { @@ -278,35 +168,104 @@ static const struct vop_win_phy *rk3288_area_data[] = { &rk3288_area3_data }; -static const struct vop_modeset rk3288_modeset = { +static const struct vop_ctrl rk3288_ctrl_data = { + .version = VOP_REG(RK3288_VERSION_INFO, 0xffff, 16), + .standby = VOP_REG(RK3288_SYS_CTRL, 0x1, 22), + .dma_stop = VOP_REG(RK3288_SYS_CTRL, 0x1, 21), + .axi_outstanding_max_num = VOP_REG(RK3288_SYS_CTRL1, 0x1f, 13), + .axi_max_outstanding_en = VOP_REG(RK3288_SYS_CTRL1, 0x1, 12), + .reg_done_frm = VOP_REG_VER(RK3288_SYS_CTRL1, 0x1, 24, 3, 7, -1), .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), + .vact_st_end_f1 = VOP_REG(RK3288_DSP_VACT_ST_END_F1, 0x1fff1fff, 0), + .vs_st_end_f1 = VOP_REG(RK3288_DSP_VS_ST_END_F1, 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), -}; + .vpost_st_end_f1 = VOP_REG(RK3288_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3288_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3288_POST_SCL_CTRL, 0x3, 0), -static const struct vop_output rk3288_output = { - .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4), + .dsp_interlace = VOP_REG(RK3288_DSP_CTRL0, 0x1, 10), + .auto_gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23), + .dsp_layer_sel = VOP_REG(RK3288_DSP_CTRL1, 0xff, 8), + .post_lb_mode = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 18, 3, 2, -1), + .global_regdone_en = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 11, 3, 2, -1), + .overlay_mode = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 16, 3, 2, -1), + .core_dclk_div = VOP_REG_VER(RK3366_DSP_CTRL0, 0x1, 4, 3, 4, -1), + .p2i_en = VOP_REG_VER(RK3366_DSP_CTRL0, 0x1, 5, 3, 4, -1), + .dclk_ddr = VOP_REG_VER(RK3288_DSP_CTRL0, 0x1, 8, 3, 1, -1), + .dp_en = VOP_REG_VER(RK3399_SYS_CTRL, 0x1, 11, 3, 5, -1), + .hdmi_dclk_out_en = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 11, 3, 1, 1), .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), -}; + .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), + .data01_swap = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 17, 3, 5, -1), + .dclk_pol = VOP_REG_VER(RK3288_DSP_CTRL0, 0x1, 7, 3, 0, 1), + .pin_pol = VOP_REG_VER(RK3288_DSP_CTRL0, 0x7, 4, 3, 0, 1), + .dp_dclk_pol = VOP_REG_VER(RK3399_DSP_CTRL1, 0x1, 19, 3, 5, -1), + .dp_pin_pol = VOP_REG_VER(RK3399_DSP_CTRL1, 0x7, 16, 3, 5, -1), + .rgb_dclk_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x1, 19, 3, 2, -1), + .rgb_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x7, 16, 3, 2, -1), + .tve_dclk_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 24), + .tve_dclk_pol = VOP_REG(RK3288_SYS_CTRL, 0x1, 25), + .tve_sw_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 26), + .sw_uv_offset_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 27), + .sw_genlock = VOP_REG(RK3288_SYS_CTRL, 0x1, 28), + .hdmi_dclk_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x1, 23, 3, 2, -1), + .hdmi_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x7, 20, 3, 2, -1), + .edp_dclk_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x1, 27, 3, 2, -1), + .edp_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x7, 24, 3, 2, -1), + .mipi_dclk_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x1, 31, 3, 2, -1), + .mipi_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0x7, 28, 3, 2, -1), -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), - .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1), - .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), + .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_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1), + .dither_up_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6), + + .dsp_out_yuv = VOP_REG_VER(RK3399_POST_SCL_CTRL, 0x1, 2, 3, 5, -1), + .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), + .dsp_ccir656_avg = VOP_REG(RK3288_DSP_CTRL0, 0x1, 20), .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), + .update_gamma_lut = VOP_REG_VER(RK3288_DSP_CTRL1, 0x1, 7, 3, 5, -1), + .lut_buffer_index = VOP_REG_VER(RK3399_DBG_POST_REG1, 0x1, 1, 3, 5, -1), + .dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0), .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), - .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), - .dsp_layer_sel = VOP_REG(RK3288_DSP_CTRL1, 0xff, 8), + + .afbdc_rstn = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x1, 3, 3, 5, -1), + .afbdc_en = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x1, 0, 3, 5, -1), + .afbdc_sel = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x3, 1, 3, 5, -1), + .afbdc_format = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x1f, 16, 3, 5, -1), + .afbdc_hreg_block_split = VOP_REG_VER(RK3399_AFBCD0_CTRL, + 0x1, 21, 3, 5, -1), + .afbdc_hdr_ptr = VOP_REG_VER(RK3399_AFBCD0_HDR_PTR, 0xffffffff, + 0, 3, 5, -1), + .afbdc_pic_size = VOP_REG_VER(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, + 0, 3, 5, -1), + .bcsh_brightness = VOP_REG(RK3288_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3288_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3288_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3288_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3288_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3288_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG_VER(RK3368_BCSH_CTRL, 0x1, 6, 3, 1, -1), + .bcsh_r2y_en = VOP_REG_VER(RK3368_BCSH_CTRL, 0x1, 4, 3, 1, -1), + .bcsh_y2r_csc_mode = VOP_REG_VER(RK3368_BCSH_CTRL, 0x3, 2, 3, 1, -1), + .bcsh_y2r_en = VOP_REG_VER(RK3368_BCSH_CTRL, 0x1, 0, 3, 1, -1), + .bcsh_color_bar = VOP_REG(RK3288_BCSH_COLOR_BAR, 0xffffff, 8), + .bcsh_en = VOP_REG(RK3288_BCSH_COLOR_BAR, 0x1, 0), + + .xmirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 22), + .ymirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 23), + + .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), + + .cfg_done = VOP_REG(RK3288_REG_CFG_DONE, 0x1, 0), }; /* @@ -346,26 +305,52 @@ static const struct vop_intr rk3288_vop_intr = { .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8), }; -static const struct vop_data rk3288_vop = { - .version = VOP_VERSION(3, 1), +static const struct vop_grf_ctrl rk3288_vop_big_grf_ctrl = { + .grf_dclk_inv = VOP_REG(RK3288_GRF_SOC_CON15, 0x1, 12), +}; + +static const struct vop_grf_ctrl rk3288_vop_lit_grf_ctrl = { + .grf_dclk_inv = VOP_REG(RK3288_GRF_SOC_CON15, 0x1, 14), +}; + +static const struct vop_data rk3288_vop_big = { + .version = VOP_VERSION(3, 0), + .feature = VOP_FEATURE_OUTPUT_10BIT | VOP_FEATURE_ALPHA_SCALE, .max_input = {4096, 8192}, - .max_output = {4096, 2160}, - .feature = VOP_FEATURE_OUTPUT_RGB10, + .max_output = {3840, 2160}, .intr = &rk3288_vop_intr, - .common = &rk3288_common, - .modeset = &rk3288_modeset, - .output = &rk3288_output, + .grf_ctrl = &rk3288_vop_big_grf_ctrl, + .ctrl = &rk3288_ctrl_data, + .win = rk3288_vop_win_data, + .win_size = ARRAY_SIZE(rk3288_vop_win_data), +}; + +static const struct vop_data rk3288_vop_lit = { + .version = VOP_VERSION(3, 0), + .feature = VOP_FEATURE_OUTPUT_10BIT | VOP_FEATURE_ALPHA_SCALE, + .max_input = {4096, 8192}, + .max_output = {2560, 1600}, + .intr = &rk3288_vop_intr, + .grf_ctrl = &rk3288_vop_lit_grf_ctrl, + .ctrl = &rk3288_ctrl_data, .win = rk3288_vop_win_data, .win_size = ARRAY_SIZE(rk3288_vop_win_data), }; static const int rk3368_vop_intrs[] = { FS_INTR, - 0, 0, + FS_NEW_INTR, + ADDR_SAME_INTR, LINE_FLAG_INTR, - 0, + LINE_FLAG1_INTR, BUS_ERROR_INTR, - 0, 0, 0, 0, 0, 0, 0, + WIN0_EMPTY_INTR, + WIN1_EMPTY_INTR, + WIN2_EMPTY_INTR, + WIN3_EMPTY_INTR, + HWC_EMPTY_INTR, + POST_BUF_EMPTY_INTR, + PWM_GEN_INTR, DSP_HOLD_VALID_INTR, }; @@ -374,9 +359,9 @@ static const struct vop_intr rk3368_vop_intr = { .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), + .status = VOP_REG_MASK(RK3368_INTR_STATUS, 0x3fff, 0), + .enable = VOP_REG_MASK(RK3368_INTR_EN, 0x3fff, 0), + .clear = VOP_REG_MASK(RK3368_INTR_CLEAR, 0x3fff, 0), }; static const struct vop_win_phy rk3368_win23_data = { @@ -385,14 +370,15 @@ static const struct vop_win_phy rk3368_win23_data = { .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0), .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), + .ymirror = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15), .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), + .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xffff, 0), + .global_alpha_val = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 16), + .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xffffffff, 0), }; static const struct vop_win_phy rk3368_area1_data = { @@ -446,30 +432,13 @@ static const struct vop_win_data rk3368_vop_win_data[] = { .area_size = ARRAY_SIZE(rk3368_area_data), }, }; -static const struct vop_output rk3368_output = { - .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16), - .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20), - .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24), - .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 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), + .feature = VOP_FEATURE_ALPHA_SCALE, .max_input = {4096, 8192}, .max_output = {4096, 2160}, .intr = &rk3368_vop_intr, - .common = &rk3288_common, - .modeset = &rk3288_modeset, - .output = &rk3368_output, - .misc = &rk3368_misc, + .ctrl = &rk3288_ctrl_data, .win = rk3368_vop_win_data, .win_size = ARRAY_SIZE(rk3368_vop_win_data), }; @@ -479,177 +448,182 @@ static const struct vop_intr rk3366_vop_intr = { .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), + .status = VOP_REG_MASK(RK3366_INTR_STATUS0, 0xffff, 0), + .enable = VOP_REG_MASK(RK3366_INTR_EN0, 0xffff, 0), + .clear = VOP_REG_MASK(RK3366_INTR_CLEAR0, 0xffff, 0), +}; + +static const struct vop_grf_ctrl rk3368_vop_grf_ctrl = { + .grf_dclk_inv = VOP_REG(RK3368_GRF_SOC_CON6, 0x1, 5), }; static const struct vop_data rk3366_vop = { .version = VOP_VERSION(3, 4), + .feature = VOP_FEATURE_ALPHA_SCALE, .max_input = {4096, 8192}, .max_output = {4096, 2160}, .intr = &rk3366_vop_intr, - .common = &rk3288_common, - .modeset = &rk3288_modeset, - .output = &rk3368_output, - .misc = &rk3368_misc, + .grf_ctrl = &rk3368_vop_grf_ctrl, + .ctrl = &rk3288_ctrl_data, .win = rk3368_vop_win_data, .win_size = ARRAY_SIZE(rk3368_vop_win_data), }; -static const struct vop_output rk3399_output = { - .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16), - .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16), - .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20), - .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24), - .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28), - .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), - .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 uint32_t vop_csc_y2r_bt601[] = { + 0x00000400, 0x0400059c, 0xfd25fea0, 0x07170400, + 0x00000000, 0xfffecab4, 0x00087932, 0xfff1d4f2, }; -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 uint32_t vop_csc_y2r_bt601_12_235[] = { + 0x000004a8, 0x04a80662, 0xfcbffe6f, 0x081204a8, + 0x00000000, 0xfff2134e, 0x00087b58, 0xffeeb4b0, }; -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 uint32_t vop_csc_r2y_bt601[] = { + 0x02590132, 0xff530075, 0x0200fead, 0xfe530200, + 0x0000ffad, 0x00000200, 0x00080200, 0x00080200, }; -static const struct vop_win_phy rk3399_win23_data = { - .data_formats = formats_win_lite, - .nformats = ARRAY_SIZE(formats_win_lite), - .enable = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 4), - .format = VOP_REG(RK3399_WIN2_CTRL0, 0x3, 5), - .rb_swap = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 20), - .dsp_info = VOP_REG(RK3399_WIN2_DSP_INFO0, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3399_WIN2_DSP_ST0, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3399_WIN2_MST0, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3399_WIN2_VIR0_1, 0x1fff, 0), - .src_alpha_ctl = VOP_REG(RK3399_WIN2_SRC_ALPHA_CTRL, 0xff, 0), - .dst_alpha_ctl = VOP_REG(RK3399_WIN2_DST_ALPHA_CTRL, 0xff, 0), +static const uint32_t vop_csc_r2y_bt601_12_235[] = { + 0x02040107, 0xff680064, 0x01c2fed6, 0xffb7fe87, + 0x0000ffb7, 0x00010200, 0x00080200, 0x00080200, }; -static const struct vop_win_phy rk3399_area1_data = { - .enable = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 8), - .format = VOP_REG(RK3399_WIN2_CTRL0, 0x3, 9), - .rb_swap = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 23), - .dsp_info = VOP_REG(RK3399_WIN2_DSP_INFO1, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3399_WIN2_DSP_ST1, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3399_WIN2_MST1, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3399_WIN2_VIR0_1, 0x1fff, 16), +static const uint32_t vop_csc_y2r_bt709[] = { + 0x000004a8, 0x04a8072c, 0xfddeff26, 0x087304a8, + 0x00000000, 0xfff08077, 0x0004cfed, 0xffedf1b8, }; -static const struct vop_win_phy rk3399_area2_data = { - .enable = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 12), - .format = VOP_REG(RK3399_WIN2_CTRL0, 0x3, 13), - .rb_swap = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 26), - .dsp_info = VOP_REG(RK3399_WIN2_DSP_INFO2, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3399_WIN2_DSP_ST2, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3399_WIN2_MST2, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3399_WIN2_VIR2_3, 0x1fff, 0), +static const uint32_t vop_csc_r2y_bt709[] = { + 0x027500bb, 0xff99003f, 0x01c2fea5, 0xfe6801c2, + 0x0000ffd7, 0x00010200, 0x00080200, 0x00080200, }; -static const struct vop_win_phy rk3399_area3_data = { - .enable = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 16), - .format = VOP_REG(RK3399_WIN2_CTRL0, 0x3, 17), - .rb_swap = VOP_REG(RK3399_WIN2_CTRL0, 0x1, 29), - .dsp_info = VOP_REG(RK3399_WIN2_DSP_INFO3, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3399_WIN2_DSP_ST3, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3399_WIN2_MST3, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3399_WIN2_VIR2_3, 0x1fff, 16), +static const uint32_t vop_csc_y2r_bt2020[] = { + 0x000004a8, 0x04a806b6, 0xfd66ff40, 0x089004a8, + 0x00000000, 0xfff16bfc, 0x00058ae9, 0xffedb828, }; -static const struct vop_win_phy *rk3399_area_data[] = { - &rk3399_area1_data, - &rk3399_area2_data, - &rk3399_area3_data +static const uint32_t vop_csc_r2y_bt2020[] = { + 0x025300e6, 0xff830034, 0x01c1febd, 0xfe6401c1, + 0x0000ffdc, 0x00010200, 0x00080200, 0x00080200, +}; + +static const uint32_t vop_csc_r2r_bt709_to_bt2020[] = { + 0xfda606a4, 0xff80ffb5, 0xfff80488, 0xff99ffed, + 0x0000047a, 0x00000200, 0x00000200, 0x00000200, +}; + +static const uint32_t vop_csc_r2r_bt2020_to_bt709[] = { + 0x01510282, 0x0047002c, 0x000c03ae, 0x005a0011, + 0x00000394, 0x00000200, 0x00000200, 0x00000200, +}; + +static const struct vop_csc_table rk3399_csc_table = { + .y2r_bt601 = vop_csc_y2r_bt601, + .y2r_bt601_12_235 = vop_csc_y2r_bt601_12_235, + .r2y_bt601 = vop_csc_r2y_bt601, + .r2y_bt601_12_235 = vop_csc_r2y_bt601_12_235, + + .y2r_bt709 = vop_csc_y2r_bt709, + .r2y_bt709 = vop_csc_r2y_bt709, + + .y2r_bt2020 = vop_csc_y2r_bt2020, + .r2y_bt2020 = vop_csc_r2y_bt2020, + + .r2r_bt709_to_bt2020 = vop_csc_r2r_bt709_to_bt2020, + .r2r_bt2020_to_bt709 = vop_csc_r2r_bt2020_to_bt709, +}; + +static const struct vop_csc rk3399_win0_csc = { + .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 0), + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1), + .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 2), + .y2r_offset = RK3399_WIN0_YUV2YUV_Y2R, + .r2r_offset = RK3399_WIN0_YUV2YUV_3X3, + .r2y_offset = RK3399_WIN0_YUV2YUV_R2Y, +}; + +static const struct vop_csc rk3399_win1_csc = { + .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 8), + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9), + .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 10), + .y2r_offset = RK3399_WIN1_YUV2YUV_Y2R, + .r2r_offset = RK3399_WIN1_YUV2YUV_3X3, + .r2y_offset = RK3399_WIN1_YUV2YUV_R2Y, +}; + +static const struct vop_csc rk3399_win2_csc = { + .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 16), + .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 18), + .r2r_offset = RK3399_WIN2_YUV2YUV_3X3, +}; + +static const struct vop_csc rk3399_win3_csc = { + .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 24), + .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 26), + .r2r_offset = RK3399_WIN3_YUV2YUV_3X3, }; static const struct vop_win_data rk3399_vop_win_data[] = { - { .base = 0x00, .phy = &rk3288_win01_data, - .type = DRM_PLANE_TYPE_PRIMARY }, - { .base = 0x40, .phy = &rk3288_win01_data, - .type = DRM_PLANE_TYPE_OVERLAY }, - { .base = 0x00, .phy = &rk3399_win23_data, + { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc, + .type = DRM_PLANE_TYPE_PRIMARY, + .feature = WIN_FEATURE_AFBDC }, + { .base = 0x40, .phy = &rk3288_win01_data, .csc = &rk3399_win1_csc, .type = DRM_PLANE_TYPE_OVERLAY, - .area = rk3399_area_data, - .area_size = ARRAY_SIZE(rk3399_area_data), }, - { .base = 0x50, .phy = &rk3399_win23_data, + .feature = WIN_FEATURE_AFBDC }, + { .base = 0x00, .phy = &rk3368_win23_data, .csc = &rk3399_win2_csc, + .type = DRM_PLANE_TYPE_OVERLAY, + .feature = WIN_FEATURE_AFBDC, + .area = rk3368_area_data, + .area_size = ARRAY_SIZE(rk3368_area_data), }, + { .base = 0x50, .phy = &rk3368_win23_data, .csc = &rk3399_win3_csc, .type = DRM_PLANE_TYPE_CURSOR, - .area = rk3399_area_data, - .area_size = ARRAY_SIZE(rk3399_area_data), }, + .feature = WIN_FEATURE_AFBDC, + .area = rk3368_area_data, + .area_size = ARRAY_SIZE(rk3368_area_data), }, }; static const struct vop_data rk3399_vop_big = { .version = VOP_VERSION(3, 5), - .feature = VOP_FEATURE_OUTPUT_RGB10, + .csc_table = &rk3399_csc_table, + .feature = VOP_FEATURE_OUTPUT_10BIT | VOP_FEATURE_AFBDC | + VOP_FEATURE_ALPHA_SCALE, .max_input = {4096, 8192}, .max_output = {4096, 2160}, .intr = &rk3366_vop_intr, - .common = &rk3288_common, - .modeset = &rk3288_modeset, - .output = &rk3399_output, - .misc = &rk3368_misc, + .ctrl = &rk3288_ctrl_data, .win = rk3399_vop_win_data, .win_size = ARRAY_SIZE(rk3399_vop_win_data), - .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, }; static const struct vop_win_data rk3399_vop_lit_win_data[] = { - { .base = 0x00, .phy = &rk3288_win01_data, - .type = DRM_PLANE_TYPE_PRIMARY, }, + { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc, + .type = DRM_PLANE_TYPE_PRIMARY, + .feature = WIN_FEATURE_AFBDC }, { .phy = NULL }, - { .base = 0x00, .phy = &rk3368_win23_data, + { .base = 0x00, .phy = &rk3368_win23_data, .csc = &rk3399_win2_csc, .type = DRM_PLANE_TYPE_CURSOR, + .feature = WIN_FEATURE_AFBDC, .area = rk3368_area_data, .area_size = ARRAY_SIZE(rk3368_area_data), }, { .phy = NULL }, }; -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 = { .version = VOP_VERSION(3, 6), + .feature = VOP_FEATURE_ALPHA_SCALE, + .csc_table = &rk3399_csc_table, .max_input = {4096, 8192}, .max_output = {2560, 1600}, .intr = &rk3366_vop_intr, - .common = &rk3288_common, - .modeset = &rk3288_modeset, - .output = &rk3399_output, - .misc = &rk3368_misc, + .ctrl = &rk3288_ctrl_data, .win = rk3399_vop_lit_win_data, .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), - .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data, }; -static const struct vop_win_data rk3228_vop_win_data[] = { +static const struct vop_win_data rk322x_vop_win_data[] = { { .base = 0x00, .phy = &rk3288_win01_data, .type = DRM_PLANE_TYPE_PRIMARY }, { .base = 0x40, .phy = &rk3288_win01_data, @@ -658,51 +632,353 @@ static const struct vop_win_data rk3228_vop_win_data[] = { static const struct vop_data rk3228_vop = { .version = VOP_VERSION(3, 7), - .feature = VOP_FEATURE_OUTPUT_RGB10, + .feature = VOP_FEATURE_OUTPUT_10BIT | VOP_FEATURE_ALPHA_SCALE, .max_input = {4096, 8192}, .max_output = {4096, 2160}, .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), + .ctrl = &rk3288_ctrl_data, + .win = rk322x_vop_win_data, + .win_size = ARRAY_SIZE(rk322x_vop_win_data), }; -static const struct vop_modeset rk3328_modeset = { +static const u32 sdr2hdr_bt1886eotf_yn_for_hlg_hdr[65] = { + 0, + 1, 7, 17, 35, + 60, 92, 134, 184, + 244, 315, 396, 487, + 591, 706, 833, 915, + 1129, 1392, 1717, 2118, + 2352, 2612, 2900, 3221, + 3577, 3972, 4411, 4899, + 5441, 6042, 6710, 7452, + 7853, 8276, 8721, 9191, + 9685, 10207, 10756, 11335, + 11945, 12588, 13266, 13980, + 14732, 15525, 16361, 17241, + 17699, 18169, 18652, 19147, + 19656, 20178, 20714, 21264, + 21829, 22408, 23004, 23615, + 24242, 24886, 25547, 26214, +}; + +static const u32 sdr2hdr_bt1886eotf_yn_for_bt2020[65] = { + 0, + 1820, 3640, 5498, 7674, + 10256, 13253, 16678, 20539, + 24847, 29609, 34833, 40527, + 46699, 53354, 60499, 68141, + 76285, 84937, 94103, 103787, + 108825, 113995, 119296, 124731, + 130299, 136001, 141837, 147808, + 153915, 160158, 166538, 173055, + 176365, 179709, 183089, 186502, + 189951, 193434, 196952, 200505, + 204093, 207715, 211373, 215066, + 218795, 222558, 226357, 230191, + 232121, 234060, 236008, 237965, + 239931, 241906, 243889, 245882, + 247883, 249894, 251913, 253941, + 255978, 258024, 260079, 262143, +}; + +static u32 sdr2hdr_bt1886eotf_yn_for_hdr[65] = { + /* dst_range 425int */ + 0, + 5, 21, 49, 91, + 150, 225, 320, 434, + 569, 726, 905, 1108, + 1336, 1588, 1866, 2171, + 2502, 2862, 3250, 3667, + 3887, 4114, 4349, 4591, + 4841, 5099, 5364, 5638, + 5920, 6209, 6507, 6812, + 6968, 7126, 7287, 7449, + 7613, 7779, 7948, 8118, + 8291, 8466, 8643, 8822, + 9003, 9187, 9372, 9560, + 9655, 9750, 9846, 9942, + 10039, 10136, 10234, 10333, + 10432, 10531, 10631, 10732, + 10833, 10935, 11038, 11141, +}; + +static const u32 sdr2hdr_st2084oetf_yn_for_hlg_hdr[65] = { + 0, + 668, 910, 1217, 1600, + 2068, 2384, 2627, 3282, + 3710, 4033, 4879, 5416, + 5815, 6135, 6401, 6631, + 6833, 7176, 7462, 7707, + 7921, 8113, 8285, 8442, + 8586, 8843, 9068, 9268, + 9447, 9760, 10027, 10259, + 10465, 10650, 10817, 10971, + 11243, 11480, 11689, 11877, + 12047, 12202, 12345, 12477, + 12601, 12716, 12926, 13115, + 13285, 13441, 13583, 13716, + 13839, 13953, 14163, 14350, + 14519, 14673, 14945, 15180, + 15570, 15887, 16153, 16383, +}; + +static const u32 sdr2hdr_st2084oetf_yn_for_bt2020[65] = { + 0, + 0, 0, 1, 2, + 4, 6, 9, 18, + 27, 36, 72, 108, + 144, 180, 216, 252, + 288, 360, 432, 504, + 576, 648, 720, 792, + 864, 1008, 1152, 1296, + 1444, 1706, 1945, 2166, + 2372, 2566, 2750, 2924, + 3251, 3553, 3834, 4099, + 4350, 4588, 4816, 5035, + 5245, 5447, 5832, 6194, + 6536, 6862, 7173, 7471, + 7758, 8035, 8560, 9055, + 9523, 9968, 10800, 11569, + 12963, 14210, 15347, 16383, +}; + +static u32 sdr2hdr_st2084oetf_yn_for_hdr[65] = { + 0, + 281, 418, 610, 871, + 1217, 1464, 1662, 2218, + 2599, 2896, 3699, 4228, + 4628, 4953, 5227, 5466, + 5676, 6038, 6341, 6602, + 6833, 7039, 7226, 7396, + 7554, 7835, 8082, 8302, + 8501, 8848, 9145, 9405, + 9635, 9842, 10031, 10204, + 10512, 10779, 11017, 11230, + 11423, 11599, 11762, 11913, + 12054, 12185, 12426, 12641, + 12835, 13013, 13177, 13328, + 13469, 13600, 13840, 14055, + 14248, 14425, 14737, 15006, + 15453, 15816, 16121, 16383, +}; + +static const u32 sdr2hdr_st2084oetf_dxn_pow2[64] = { + 0, 0, 1, 2, + 3, 3, 3, 5, + 5, 5, 7, 7, + 7, 7, 7, 7, + 7, 8, 8, 8, + 8, 8, 8, 8, + 8, 9, 9, 9, + 9, 10, 10, 10, + 10, 10, 10, 10, + 11, 11, 11, 11, + 11, 11, 11, 11, + 11, 11, 12, 12, + 12, 12, 12, 12, + 12, 12, 13, 13, + 13, 13, 14, 14, + 15, 15, 15, 15, +}; + +static const u32 sdr2hdr_st2084oetf_dxn[64] = { + 1, 1, 2, 4, + 8, 8, 8, 32, + 32, 32, 128, 128, + 128, 128, 128, 128, + 128, 256, 256, 256, + 256, 256, 256, 256, + 256, 512, 512, 512, + 512, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, + 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, + 2048, 2048, 4096, 4096, + 4096, 4096, 4096, 4096, + 4096, 4096, 8192, 8192, + 8192, 8192, 16384, 16384, + 32768, 32768, 32768, 32768, +}; + +static const u32 sdr2hdr_st2084oetf_xn[63] = { + 1, 2, 4, 8, + 16, 24, 32, 64, + 96, 128, 256, 384, + 512, 640, 768, 896, + 1024, 1280, 1536, 1792, + 2048, 2304, 2560, 2816, + 3072, 3584, 4096, 4608, + 5120, 6144, 7168, 8192, + 9216, 10240, 11264, 12288, + 14336, 16384, 18432, 20480, + 22528, 24576, 26624, 28672, + 30720, 32768, 36864, 40960, + 45056, 49152, 53248, 57344, + 61440, 65536, 73728, 81920, + 90112, 98304, 114688, 131072, + 163840, 196608, 229376, +}; + +static u32 hdr2sdr_eetf_yn[33] = { + 1716, + 1880, 2067, 2277, 2508, + 2758, 3026, 3310, 3609, + 3921, 4246, 4581, 4925, + 5279, 5640, 6007, 6380, + 6758, 7140, 7526, 7914, + 8304, 8694, 9074, 9438, + 9779, 10093, 10373, 10615, + 10812, 10960, 11053, 11084, +}; + +static u32 hdr2sdr_bt1886oetf_yn[33] = { + 0, + 0, 0, 0, 0, + 0, 0, 0, 314, + 746, 1323, 2093, 2657, + 3120, 3519, 3874, 4196, + 4492, 5024, 5498, 5928, + 6323, 7034, 7666, 8239, + 8766, 9716, 10560, 11325, + 12029, 13296, 14422, 16383, +}; + +static const u32 hdr2sdr_sat_yn[9] = { + 0, + 1792, 3584, 3472, 2778, + 2083, 1389, 694, 0, +}; + +static const struct vop_hdr_table rk3328_hdr_table = { + .hdr2sdr_eetf_oetf_y0_offset = RK3328_HDR2SDR_EETF_OETF_Y0, + .hdr2sdr_eetf_oetf_y1_offset = RK3328_HDR2SDR_EETF_OETF_Y1, + .hdr2sdr_eetf_yn = hdr2sdr_eetf_yn, + .hdr2sdr_bt1886oetf_yn = hdr2sdr_bt1886oetf_yn, + .hdr2sdr_sat_y0_offset = RK3328_HDR2DR_SAT_Y0, + .hdr2sdr_sat_y1_offset = RK3328_HDR2DR_SAT_Y1, + .hdr2sdr_sat_yn = hdr2sdr_sat_yn, + + .hdr2sdr_src_range_min = 494, + .hdr2sdr_src_range_max = 12642, + .hdr2sdr_normfaceetf = 1327, + .hdr2sdr_dst_range_min = 4, + .hdr2sdr_dst_range_max = 3276, + .hdr2sdr_normfacgamma = 5120, + + .sdr2hdr_eotf_oetf_y0_offset = RK3328_SDR2HDR_EOTF_OETF_Y0, + .sdr2hdr_eotf_oetf_y1_offset = RK3328_SDR2HDR_EOTF_OETF_Y1, + .sdr2hdr_bt1886eotf_yn_for_hlg_hdr = sdr2hdr_bt1886eotf_yn_for_hlg_hdr, + .sdr2hdr_bt1886eotf_yn_for_bt2020 = sdr2hdr_bt1886eotf_yn_for_bt2020, + .sdr2hdr_bt1886eotf_yn_for_hdr = sdr2hdr_bt1886eotf_yn_for_hdr, + .sdr2hdr_st2084oetf_yn_for_hlg_hdr = sdr2hdr_st2084oetf_yn_for_hlg_hdr, + .sdr2hdr_st2084oetf_yn_for_bt2020 = sdr2hdr_st2084oetf_yn_for_bt2020, + .sdr2hdr_st2084oetf_yn_for_hdr = sdr2hdr_st2084oetf_yn_for_hdr, + .sdr2hdr_oetf_dx_dxpow1_offset = RK3328_SDR2HDR_OETF_DX_DXPOW1, + .sdr2hdr_oetf_xn1_offset = RK3328_SDR2HDR_OETF_XN1, + .sdr2hdr_st2084oetf_dxn_pow2 = sdr2hdr_st2084oetf_dxn_pow2, + .sdr2hdr_st2084oetf_dxn = sdr2hdr_st2084oetf_dxn, + .sdr2hdr_st2084oetf_xn = sdr2hdr_st2084oetf_xn, +}; + +static const struct vop_ctrl rk3328_ctrl_data = { + .standby = VOP_REG(RK3328_SYS_CTRL, 0x1, 22), + .dma_stop = VOP_REG(RK3328_SYS_CTRL, 0x1, 21), + .axi_outstanding_max_num = VOP_REG(RK3328_SYS_CTRL1, 0x1f, 13), + .axi_max_outstanding_en = VOP_REG(RK3328_SYS_CTRL1, 0x1, 12), + .reg_done_frm = VOP_REG(RK3328_SYS_CTRL1, 0x1, 24), + .auto_gate_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 23), .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), + .vact_st_end_f1 = VOP_REG(RK3328_DSP_VACT_ST_END_F1, 0x1fff1fff, 0), + .vs_st_end_f1 = VOP_REG(RK3328_DSP_VS_ST_END_F1, 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 = { + .vpost_st_end_f1 = VOP_REG(RK3328_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3328_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3328_POST_SCL_CTRL, 0x3, 0), + .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), + .dsp_interlace = VOP_REG(RK3328_DSP_CTRL0, 0x1, 10), + .dsp_layer_sel = VOP_REG(RK3328_DSP_CTRL1, 0xff, 8), + .post_lb_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 18), + .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11), + .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), + .core_dclk_div = VOP_REG(RK3328_DSP_CTRL0, 0x1, 4), + .dclk_ddr = VOP_REG(RK3328_DSP_CTRL0, 0x1, 8), + .p2i_en = VOP_REG(RK3328_DSP_CTRL0, 0x1, 5), .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, 0xf, 16), - .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 20), - .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 24), - .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 28), -}; + .tve_dclk_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 24), + .tve_dclk_pol = VOP_REG(RK3328_SYS_CTRL, 0x1, 25), + .tve_sw_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 26), + .sw_uv_offset_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 27), + .sw_genlock = VOP_REG(RK3328_SYS_CTRL, 0x1, 28), + .sw_dac_sel = VOP_REG(RK3328_SYS_CTRL, 0x1, 29), + .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), + .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), -static const struct vop_misc rk3328_misc = { - .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11), -}; + .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_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 1), + .dither_up_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6), -static const struct vop_common rk3328_common = { - .standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22), - .yuv_overlay = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 16), - .dither_down = VOP_REG(RK3328_DSP_CTRL1, 0xf, 1), - .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6), + .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), + .dsp_ccir656_avg = VOP_REG(RK3328_DSP_CTRL0, 0x1, 20), .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18), + .dsp_lut_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 0), .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0), - .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), - .dsp_layer_sel = VOP_REG(RK3328_DSP_CTRL1, 0xff, 8), + + .xmirror = VOP_REG(RK3328_DSP_CTRL0, 0x1, 22), + .ymirror = VOP_REG(RK3328_DSP_CTRL0, 0x1, 23), + + .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + + .alpha_hard_calc = VOP_REG(RK3328_SYS_CTRL1, 0x1, 27), + .level2_overlay_en = VOP_REG(RK3328_SYS_CTRL1, 0x1, 28), + + .hdr2sdr_en = VOP_REG(RK3328_HDR2DR_CTRL, 0x1, 0), + .hdr2sdr_en_win0_csc = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 9), + .hdr2sdr_src_min = VOP_REG(RK3328_HDR2DR_SRC_RANGE, 0x3fff, 0), + .hdr2sdr_src_max = VOP_REG(RK3328_HDR2DR_SRC_RANGE, 0x3fff, 16), + .hdr2sdr_normfaceetf = VOP_REG(RK3328_HDR2DR_NORMFACEETF, 0x7ff, 0), + .hdr2sdr_dst_min = VOP_REG(RK3328_HDR2DR_DST_RANGE, 0x3fff, 0), + .hdr2sdr_dst_max = VOP_REG(RK3328_HDR2DR_DST_RANGE, 0x3fff, 16), + .hdr2sdr_normfacgamma = VOP_REG(RK3328_HDR2DR_NORMFACGAMMA, 0xffff, 0), + + .bt1886eotf_pre_conv_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 0), + .rgb2rgb_pre_conv_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 1), + .rgb2rgb_pre_conv_mode = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 2), + .st2084oetf_pre_conv_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 3), + .bt1886eotf_post_conv_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 4), + .rgb2rgb_post_conv_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 5), + .rgb2rgb_post_conv_mode = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 6), + .st2084oetf_post_conv_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 7), + .win_csc_mode_sel = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 31), + + .bcsh_brightness = VOP_REG(RK3328_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3328_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3328_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3328_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3328_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3328_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3328_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3328_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3328_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3328_BCSH_CTRL, 0x1, 0), + .bcsh_color_bar = VOP_REG(RK3328_BCSH_COLOR_BAR, 0xffffff, 8), + .bcsh_en = VOP_REG(RK3328_BCSH_COLOR_BAR, 0x1, 0), + + .cfg_done = VOP_REG(RK3328_REG_CFG_DONE, 0x1, 0), }; static const struct vop_intr rk3328_vop_intr = { @@ -710,41 +986,605 @@ static const struct vop_intr rk3328_vop_intr = { .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), + .status = VOP_REG_MASK(RK3328_INTR_STATUS0, 0xffff, 0), + .enable = VOP_REG_MASK(RK3328_INTR_EN0, 0xffff, 0), + .clear = VOP_REG_MASK(RK3328_INTR_CLEAR0, 0xffff, 0), +}; + +static const struct vop_csc rk3328_win0_csc = { + .r2y_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 8), + .r2r_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 5), + .y2r_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 9), +}; + +static const struct vop_csc rk3328_win1_csc = { + .r2y_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 10), + .r2r_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 1), + .y2r_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 11), +}; + +static const struct vop_csc rk3328_win2_csc = { + .r2y_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 12), + .r2r_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 1), + .y2r_en = VOP_REG(RK3328_SDR2HDR_CTRL, 0x1, 13), }; static const struct vop_win_data rk3328_vop_win_data[] = { - { .base = 0xd0, .phy = &rk3288_win01_data, - .type = DRM_PLANE_TYPE_PRIMARY }, - { .base = 0x1d0, .phy = &rk3288_win01_data, - .type = DRM_PLANE_TYPE_OVERLAY }, - { .base = 0x2d0, .phy = &rk3288_win01_data, - .type = DRM_PLANE_TYPE_CURSOR }, + { .base = 0xd0, .phy = &rk3288_win01_data, .csc = &rk3328_win0_csc, + .type = DRM_PLANE_TYPE_PRIMARY, + .feature = WIN_FEATURE_HDR2SDR | WIN_FEATURE_SDR2HDR }, + { .base = 0x1d0, .phy = &rk3288_win01_data, .csc = &rk3328_win1_csc, + .type = DRM_PLANE_TYPE_OVERLAY, + .feature = WIN_FEATURE_SDR2HDR | WIN_FEATURE_PRE_OVERLAY }, + { .base = 0x2d0, .phy = &rk3288_win01_data, .csc = &rk3328_win2_csc, + .type = DRM_PLANE_TYPE_CURSOR, + .feature = WIN_FEATURE_SDR2HDR | WIN_FEATURE_PRE_OVERLAY }, }; static const struct vop_data rk3328_vop = { .version = VOP_VERSION(3, 8), - .feature = VOP_FEATURE_OUTPUT_RGB10, + .feature = VOP_FEATURE_OUTPUT_10BIT | VOP_FEATURE_ALPHA_SCALE, + .hdr_table = &rk3328_hdr_table, .max_input = {4096, 8192}, .max_output = {4096, 2160}, .intr = &rk3328_vop_intr, - .common = &rk3328_common, - .modeset = &rk3328_modeset, - .output = &rk3328_output, - .misc = &rk3328_misc, + .ctrl = &rk3328_ctrl_data, .win = rk3328_vop_win_data, .win_size = ARRAY_SIZE(rk3328_vop_win_data), }; +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_win0_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_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), + .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0), + .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) +}; + +static const struct vop_win_phy rk3036_win1_data = { + .scl = &rk3036_win1_scl, + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_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), + .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0), + .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) +}; + +static const struct vop_win_data rk3036_vop_win_data[] = { + { .base = 0x00, .phy = &rk3036_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3036_win1_data, + .type = DRM_PLANE_TYPE_OVERLAY }, +}; + +static const int rk3036_vop_intrs[] = { + DSP_HOLD_VALID_INTR, + FS_INTR, + LINE_FLAG_INTR, + BUS_ERROR_INTR, +}; + +static const struct vop_intr rk3036_intr = { + .intrs = rk3036_vop_intrs, + .nintrs = ARRAY_SIZE(rk3036_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12), + .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0), + .enable = VOP_REG(RK3036_INT_STATUS, 0xf, 4), + .clear = VOP_REG(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), + .dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24), + .dclk_pol = VOP_REG(RK3036_DSP_CTRL0, 0x1, 7), + .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0x7, 4), + .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), + .dither_up_en = VOP_REG(RK3036_DSP_CTRL0, 0x1, 9), + .dsp_layer_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 8), + .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), + .cfg_done = VOP_REG(RK3036_REG_CFG_DONE, 0x1, 0), +}; + +static const struct vop_data rk3036_vop = { + .version = VOP_VERSION(2, 2), + .max_input = {1920, 1080}, + .max_output = {1920, 1080}, + .ctrl = &rk3036_ctrl_data, + .intr = &rk3036_intr, + .win = rk3036_vop_win_data, + .win_size = ARRAY_SIZE(rk3036_vop_win_data), +}; + +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), + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), + .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4), + .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19), + .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 = { + .scl = &rk3066_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), + .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7), + .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23), + .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), + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), + .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10), + .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 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_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[] = { + 0, + 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_ctrl rk3066_ctrl_data = { + .standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1), + .out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0), + .dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24), + .dclk_pol = VOP_REG(RK3066_DSP_CTRL0, 0x1, 7), + .pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4), + .dsp_layer_sel = VOP_REG(RK3066_DSP_CTRL0, 0x1, 8), + .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), + .cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0), +}; + +static const struct vop_data rk3066_vop = { + .version = VOP_VERSION(2, 1), + .max_input = {1920, 4096}, + .max_output = {1920, 1080}, + .ctrl = &rk3066_ctrl_data, + .intr = &rk3066_intr, + .win = rk3066_vop_win_data, + .win_size = ARRAY_SIZE(rk3066_vop_win_data), +}; + +static const int rk3366_vop_lit_intrs[] = { + FS_INTR, + FS_NEW_INTR, + ADDR_SAME_INTR, + LINE_FLAG_INTR, + LINE_FLAG1_INTR, + BUS_ERROR_INTR, + WIN0_EMPTY_INTR, + WIN1_EMPTY_INTR, + DSP_HOLD_VALID_INTR, + DMA_FINISH_INTR, + WIN2_EMPTY_INTR, + POST_BUF_EMPTY_INTR +}; + +static const struct vop_scl_regs rk3366_lit_win_scl = { + .scale_yrgb_x = VOP_REG(RK3366_LIT_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3366_LIT_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3366_LIT_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3366_LIT_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy rk3366_lit_win0_data = { + .scl = &rk3366_lit_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + + .enable = VOP_REG(RK3366_LIT_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3366_LIT_WIN0_CTRL0, 0x7, 1), + .rb_swap = VOP_REG(RK3366_LIT_WIN0_CTRL0, 0x1, 12), + .act_info = VOP_REG(RK3366_LIT_WIN0_ACT_INFO, 0xffffffff, 0), + .dsp_info = VOP_REG(RK3366_LIT_WIN0_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(RK3366_LIT_WIN0_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(RK3366_LIT_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3366_LIT_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3366_LIT_WIN0_VIR, 0x1fff, 0), + .uv_vir = VOP_REG(RK3366_LIT_WIN0_VIR, 0x1fff, 16), + + .alpha_pre_mul = VOP_REG(RK3366_LIT_WIN0_ALPHA_CTRL, 0x1, 2), + .alpha_mode = VOP_REG(RK3366_LIT_WIN0_ALPHA_CTRL, 0x1, 1), + .alpha_en = VOP_REG(RK3366_LIT_WIN0_ALPHA_CTRL, 0x1, 0), + .global_alpha_val = VOP_REG(RK3366_LIT_WIN0_ALPHA_CTRL, 0xff, 4), + .key_color = VOP_REG(RK3366_LIT_WIN0_COLOR_KEY, 0xffffff, 0), + .key_en = VOP_REG(RK3366_LIT_WIN0_COLOR_KEY, 0x1, 24), +}; + +static const struct vop_win_phy rk3366_lit_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + + .enable = VOP_REG(RK3366_LIT_WIN1_CTRL0, 0x1, 0), + .format = VOP_REG(RK3366_LIT_WIN1_CTRL0, 0x7, 4), + .rb_swap = VOP_REG(RK3366_LIT_WIN1_CTRL0, 0x1, 12), + .dsp_info = VOP_REG(RK3366_LIT_WIN1_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(RK3366_LIT_WIN1_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(RK3366_LIT_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3366_LIT_WIN1_VIR, 0x1fff, 0), + + .alpha_pre_mul = VOP_REG(RK3366_LIT_WIN1_ALPHA_CTRL, 0x1, 2), + .alpha_mode = VOP_REG(RK3366_LIT_WIN1_ALPHA_CTRL, 0x1, 1), + .alpha_en = VOP_REG(RK3366_LIT_WIN1_ALPHA_CTRL, 0x1, 0), + .global_alpha_val = VOP_REG(RK3366_LIT_WIN1_ALPHA_CTRL, 0xff, 4), + .key_color = VOP_REG(RK3366_LIT_WIN1_COLOR_KEY, 0xffffff, 0), + .key_en = VOP_REG(RK3366_LIT_WIN1_COLOR_KEY, 0x1, 24), +}; + +static const struct vop_win_data rk3366_vop_lit_win_data[] = { + { .base = 0x00, .phy = &rk3366_lit_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3366_lit_win1_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_intr rk3366_lit_intr = { + .intrs = rk3366_vop_lit_intrs, + .nintrs = ARRAY_SIZE(rk3366_vop_lit_intrs), + .line_flag_num[0] = VOP_REG(RK3366_LIT_LINE_FLAG, 0xfff, 0), + .line_flag_num[1] = VOP_REG(RK3366_LIT_LINE_FLAG, 0xfff, 16), + .status = VOP_REG_MASK(RK3366_LIT_INTR_STATUS, 0xffff, 0), + .enable = VOP_REG_MASK(RK3366_LIT_INTR_EN, 0xffff, 0), + .clear = VOP_REG_MASK(RK3366_LIT_INTR_CLEAR, 0xffff, 0), +}; + +static const struct vop_win_phy rk3126_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_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) +}; + +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_data rk3126_vop = { + .version = VOP_VERSION(2, 4), + .max_input = {1920, 8192}, + .max_output = {1920, 1080}, + .ctrl = &rk3036_ctrl_data, + .intr = &rk3036_intr, + .win = rk3126_vop_win_data, + .win_size = ARRAY_SIZE(rk3126_vop_win_data), +}; + +/* PX30 VOPB win2 is same with RK3368, + * but RK3368 win2 register offset is 0xb0 and px30 is 0x190, + * so we set the PX30 VOPB win2 base = 0x190 - 0xb0 = 0xe0 + */ + +static const struct vop_ctrl px30_ctrl_data = { + .standby = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 1), + .axi_outstanding_max_num = VOP_REG(RK3366_LIT_SYS_CTRL1, 0x1f, 16), + .axi_max_outstanding_en = VOP_REG(RK3366_LIT_SYS_CTRL1, 0x1, 12), + .htotal_pw = VOP_REG(RK3366_LIT_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(RK3366_LIT_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(RK3366_LIT_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(RK3366_LIT_DSP_VACT_ST_END, 0x0fff0fff, 0), + .vact_st_end_f1 = VOP_REG(RK3366_LIT_DSP_VACT_ST_END_F1, 0x0fff0fff, 0), + .vs_st_end_f1 = VOP_REG(RK3366_LIT_DSP_VS_ST_END_F1, 0x0fff0fff, 0), + .dsp_interlace = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 0), + .global_regdone_en = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 13), + .auto_gate_en = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 0), + .dsp_layer_sel = VOP_REG(RK3366_LIT_DSP_CTRL2, 0xff, 22), + .overlay_mode = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 4), + .core_dclk_div = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 13), + .dclk_ddr = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 14), + .rgb_en = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 0), + .rgb_pin_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x7, 2), + .hdmi_en = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 8), + .hdmi_pin_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x7, 10), + .lvds_en = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 16), + .lvds_pin_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x7, 18), + .mipi_en = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 24), + .mipi_pin_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x7, 26), + .mipi_dclk_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 25), + .lvds_dclk_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 17), + .hdmi_dclk_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 9), + .rgb_dclk_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 1), + .dither_down_en = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 8), + .dither_down_sel = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 7), + .dither_down_mode = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 6), + .dither_up_en = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 2), + .dsp_data_swap = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1f, 9), + .dsp_ccir656_avg = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 5), + .dsp_black = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 15), + .dsp_blank = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 14), + .dsp_outzero = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 3), + .dsp_lut_en = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 5), + .out_mode = VOP_REG(RK3366_LIT_DSP_CTRL2, 0xf, 16), + .dsp_background = VOP_REG(RK3366_LIT_DSP_BG, 0x00ffffff, 0), + .cfg_done = VOP_REG(RK3366_LIT_REG_CFG_DONE, 0x1, 0), + + .bcsh_en = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 0), + .bcsh_r2y_csc_mode = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 1), + .bcsh_out_mode = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_csc_mode = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x3, 4), + .bcsh_y2r_en = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 6), + .bcsh_r2y_en = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 7), + .bcsh_color_bar = VOP_REG(RK3366_LIT_BCSH_COL_BAR, 0xffffff, 0), + .bcsh_brightness = VOP_REG(RK3366_LIT_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3366_LIT_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3366_LIT_BCSH_BCS, 0x3ff, 20), + .bcsh_sin_hue = VOP_REG(RK3366_LIT_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3366_LIT_BCSH_H, 0x1ff, 16), + + .afbdc_en = VOP_REG(PX30_AFBCD0_CTRL, 0x1, 0), + .afbdc_format = VOP_REG(PX30_AFBCD0_CTRL, 0x1f, 4), + .afbdc_pic_vir_width = VOP_REG(PX30_AFBCD0_CTRL, 0xffff, 16), + .afbdc_hdr_ptr = VOP_REG(PX30_AFBCD0_HDR_PTR, 0xffffffff, 0), + .afbdc_pic_size = VOP_REG(PX30_AFBCD0_PIC_SIZE, 0xffffffff, 0), + .afbdc_pic_offset = VOP_REG(PX30_AFBCD0_PIC_OFFSET, 0xffffffff, 0), + .afbdc_axi_ctrl = VOP_REG(PX30_AFBCD0_AXI_CTRL, 0xffffffff, 0), + + .mcu_pix_total = VOP_REG(RK3366_LIT_MCU_CTRL, 0x3f, 0), + .mcu_cs_pst = VOP_REG(RK3366_LIT_MCU_CTRL, 0xf, 6), + .mcu_cs_pend = VOP_REG(RK3366_LIT_MCU_CTRL, 0x3f, 10), + .mcu_rw_pst = VOP_REG(RK3366_LIT_MCU_CTRL, 0xf, 16), + .mcu_rw_pend = VOP_REG(RK3366_LIT_MCU_CTRL, 0x3f, 20), + .mcu_clk_sel = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 26), + .mcu_hold_mode = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 27), + .mcu_frame_st = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 28), + .mcu_rs = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 29), + .mcu_bypass = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 30), + .mcu_type = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 31), + .mcu_rw_bypass_port = VOP_REG(RK3366_LIT_MCU_RW_BYPASS_PORT, + 0xffffffff, 0), +}; + +static const struct vop_win_phy px30_win23_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_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), + .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), + .alpha_pre_mul = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0x1, 2), + .alpha_mode = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0x1, 1), + .alpha_en = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0x1, 0), + .global_alpha_val = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 4), + .channel = VOP_REG(RK3368_WIN2_CTRL1, 0xf, 8), +}; + +static const struct vop_win_data px30_vop_big_win_data[] = { + { .base = 0x00, .phy = &rk3366_lit_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3366_lit_win1_data, + .type = DRM_PLANE_TYPE_CURSOR, + .feature = WIN_FEATURE_AFBDC }, + { .base = 0xe0, .phy = &px30_win23_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .area = rk3368_area_data, + .area_size = ARRAY_SIZE(rk3368_area_data), }, +}; + +static const struct vop_win_data px30_vop_lit_win_data[] = { + { .phy = NULL }, + { .base = 0x00, .phy = &rk3366_lit_win1_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .phy = NULL }, +}; + +static const struct vop_grf_ctrl px30_grf_ctrl = { + .grf_dclk_inv = VOP_REG(PX30_GRF_PD_VO_CON1, 0x1, 4), +}; + +static const struct vop_data px30_vop_lit = { + .version = VOP_VERSION(2, 5), + .max_input = {1920, 8192}, + .max_output = {1920, 1080}, + .ctrl = &px30_ctrl_data, + .intr = &rk3366_lit_intr, + .grf_ctrl = &px30_grf_ctrl, + .win = px30_vop_lit_win_data, + .win_size = ARRAY_SIZE(px30_vop_lit_win_data), +}; + +static const struct vop_data px30_vop_big = { + .version = VOP_VERSION(2, 6), + .feature = VOP_FEATURE_AFBDC, + .max_input = {1920, 8192}, + .max_output = {1920, 1080}, + .ctrl = &px30_ctrl_data, + .intr = &rk3366_lit_intr, + .grf_ctrl = &px30_grf_ctrl, + .win = px30_vop_big_win_data, + .win_size = ARRAY_SIZE(px30_vop_big_win_data), +}; + +static const struct vop_ctrl rk3308_ctrl_data = { + .standby = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 1), + .axi_outstanding_max_num = VOP_REG(RK3366_LIT_SYS_CTRL1, 0x1f, 16), + .axi_max_outstanding_en = VOP_REG(RK3366_LIT_SYS_CTRL1, 0x1, 12), + .htotal_pw = VOP_REG(RK3366_LIT_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(RK3366_LIT_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(RK3366_LIT_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(RK3366_LIT_DSP_VACT_ST_END, 0x0fff0fff, 0), + .vact_st_end_f1 = VOP_REG(RK3366_LIT_DSP_VACT_ST_END_F1, 0x0fff0fff, 0), + .vs_st_end_f1 = VOP_REG(RK3366_LIT_DSP_VS_ST_END_F1, 0x0fff0fff, 0), + .global_regdone_en = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 13), + .auto_gate_en = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 0), + .dsp_layer_sel = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 3), + .overlay_mode = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 4), + .dclk_ddr = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 14), + .rgb_en = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 0), + .rgb_pin_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x7, 2), + .rgb_dclk_pol = VOP_REG(RK3366_LIT_DSP_CTRL0, 0x1, 1), + .dither_down_en = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 8), + .dither_down_sel = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 7), + .dither_down_mode = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 6), + .dither_up_en = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 2), + .dsp_data_swap = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1f, 9), + .dsp_ccir656_avg = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 5), + .dsp_black = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 15), + .dsp_blank = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 14), + .dsp_outzero = VOP_REG(RK3366_LIT_SYS_CTRL2, 0x1, 3), + .dsp_lut_en = VOP_REG(RK3366_LIT_DSP_CTRL2, 0x1, 5), + .out_mode = VOP_REG(RK3366_LIT_DSP_CTRL2, 0xf, 16), + .dsp_background = VOP_REG(RK3366_LIT_DSP_BG, 0x00ffffff, 0), + .cfg_done = VOP_REG(RK3366_LIT_REG_CFG_DONE, 0x1, 0), + + .bcsh_en = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 0), + .bcsh_r2y_csc_mode = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 1), + .bcsh_out_mode = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_csc_mode = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x3, 4), + .bcsh_y2r_en = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 6), + .bcsh_r2y_en = VOP_REG(RK3366_LIT_BCSH_CTRL, 0x1, 7), + .bcsh_color_bar = VOP_REG(RK3366_LIT_BCSH_COL_BAR, 0xffffff, 0), + .bcsh_brightness = VOP_REG(RK3366_LIT_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3366_LIT_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3366_LIT_BCSH_BCS, 0x3ff, 20), + .bcsh_sin_hue = VOP_REG(RK3366_LIT_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3366_LIT_BCSH_H, 0x1ff, 16), + + .mcu_pix_total = VOP_REG(RK3366_LIT_MCU_CTRL, 0x3f, 0), + .mcu_cs_pst = VOP_REG(RK3366_LIT_MCU_CTRL, 0xf, 6), + .mcu_cs_pend = VOP_REG(RK3366_LIT_MCU_CTRL, 0x3f, 10), + .mcu_rw_pst = VOP_REG(RK3366_LIT_MCU_CTRL, 0xf, 16), + .mcu_rw_pend = VOP_REG(RK3366_LIT_MCU_CTRL, 0x3f, 20), + .mcu_clk_sel = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 26), + .mcu_hold_mode = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 27), + .mcu_frame_st = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 28), + .mcu_rs = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 29), + .mcu_bypass = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 30), + .mcu_type = VOP_REG(RK3366_LIT_MCU_CTRL, 0x1, 31), + .mcu_rw_bypass_port = VOP_REG(RK3366_LIT_MCU_RW_BYPASS_PORT, + 0xffffffff, 0), +}; + +static const struct vop_data rk3308_vop = { + .version = VOP_VERSION(2, 7), + .max_input = {1920, 8192}, + .max_output = {1920, 1080}, + .ctrl = &rk3308_ctrl_data, + .intr = &rk3366_lit_intr, + .win = rk3366_vop_lit_win_data, + .win_size = ARRAY_SIZE(rk3366_vop_lit_win_data), +}; + static const struct of_device_id vop_driver_dt_match[] = { { .compatible = "rockchip,rk3036-vop", .data = &rk3036_vop }, + { .compatible = "rockchip,rk3066-vop", + .data = &rk3066_vop }, { .compatible = "rockchip,rk3126-vop", .data = &rk3126_vop }, - { .compatible = "rockchip,rk3288-vop", - .data = &rk3288_vop }, + { .compatible = "rockchip,px30-vop-lit", + .data = &px30_vop_lit }, + { .compatible = "rockchip,px30-vop-big", + .data = &px30_vop_big }, + { .compatible = "rockchip,rk3308-vop", + .data = &rk3308_vop }, + { .compatible = "rockchip,rk3288-vop-big", + .data = &rk3288_vop_big }, + { .compatible = "rockchip,rk3288-vop-lit", + .data = &rk3288_vop_lit }, { .compatible = "rockchip,rk3368-vop", .data = &rk3368_vop }, { .compatible = "rockchip,rk3366-vop", diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index f81b510ea99c..e0b435d5098c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -121,6 +121,11 @@ #define RK3288_DSP_VACT_ST_END 0x0194 #define RK3288_DSP_VS_ST_END_F1 0x0198 #define RK3288_DSP_VACT_ST_END_F1 0x019c + +#define RK3288_BCSH_COLOR_BAR 0x01b0 +#define RK3288_BCSH_BCS 0x01b4 +#define RK3288_BCSH_H 0x01b8 +#define RK3288_GRF_SOC_CON15 0x03a4 /* register definition end */ /* rk3368 register definition */ @@ -308,6 +313,7 @@ #define RK3368_CABC_GAMMA_LUT_ADDR 0x1800 #define RK3368_MCU_BYPASS_WPORT 0x2200 #define RK3368_MCU_BYPASS_RPORT 0x2300 +#define RK3368_GRF_SOC_CON6 0x0418 /* rk3368 register definition end */ #define RK3366_REG_CFG_DONE 0x0000 @@ -636,6 +642,7 @@ #define RK3399_YUV2YUV_WIN 0x02c0 #define RK3399_YUV2YUV_POST 0x02c4 #define RK3399_AUTO_GATING_EN 0x02cc +#define RK3399_DBG_POST_REG1 0x036c #define RK3399_WIN0_CSC_COE 0x03a0 #define RK3399_WIN1_CSC_COE 0x03c0 #define RK3399_WIN2_CSC_COE 0x03e0 @@ -806,6 +813,21 @@ #define RK3328_DBG_POST_RESERVED 0x000006ec #define RK3328_DBG_DATAO 0x000006f0 #define RK3328_DBG_DATAO_2 0x000006f4 +#define RK3328_SDR2HDR_CTRL 0x00000700 +#define RK3328_SDR2HDR_EOTF_OETF_Y0 0x00000704 +#define RK3328_SDR2HDR_EOTF_OETF_Y1 0x00000710 +#define RK3328_SDR2HDR_OETF_DX_DXPOW1 0x00000810 +#define RK3328_SDR2HDR_OETF_XN1 0x00000910 + +#define RK3328_HDR2DR_CTRL 0x00000a10 +#define RK3328_HDR2DR_SRC_RANGE 0x00000a14 +#define RK3328_HDR2DR_NORMFACEETF 0x00000a18 +#define RK3328_HDR2DR_DST_RANGE 0x00000a20 +#define RK3328_HDR2DR_NORMFACGAMMA 0x00000a24 +#define RK3328_HDR2SDR_EETF_OETF_Y0 0x00000a28 +#define RK3328_HDR2DR_SAT_Y0 0x00000a2C +#define RK3328_HDR2SDR_EETF_OETF_Y1 0x00000a30 +#define RK3328_HDR2DR_SAT_Y1 0x00000ab0 /* sdr to hdr */ #define RK3328_SDR2HDR_CTRL 0x00000700 @@ -878,10 +900,146 @@ #define RK3036_HWC_LUT_ADDR 0x800 /* rk3036 register definition end */ +#define RK3066_SYS_CTRL0 0x00 +#define RK3066_SYS_CTRL1 0x04 +#define RK3066_DSP_CTRL0 0x08 +#define RK3066_DSP_CTRL1 0x0c +#define RK3066_INT_STATUS 0x10 +#define RK3066_MCU_CTRL 0x14 +#define RK3066_BLEND_CTRL 0x18 +#define RK3066_WIN0_COLOR_KEY_CTRL 0x1c +#define RK3066_WIN1_COLOR_KEY_CTRL 0x20 +#define RK3066_WIN2_COLOR_KEY_CTRL 0x24 +#define RK3066_WIN0_YRGB_MST0 0x28 +#define RK3066_WIN0_CBR_MST0 0x2c +#define RK3066_WIN0_YRGB_MST1 0x30 +#define RK3066_WIN0_CBR_MST1 0x34 +#define RK3066_WIN0_VIR 0x38 +#define RK3066_WIN0_ACT_INFO 0x3c +#define RK3066_WIN0_DSP_INFO 0x40 +#define RK3066_WIN0_DSP_ST 0x44 +#define RK3066_WIN0_SCL_FACTOR_YRGB 0x48 +#define RK3066_WIN0_SCL_FACTOR_CBR 0x4c +#define RK3066_WIN0_SCL_OFFSET 0x50 +#define RK3066_WIN1_YRGB_MST 0x54 +#define RK3066_WIN1_CBR_MST 0x58 +#define RK3066_WIN1_VIR 0x5c +#define RK3066_WIN1_ACT_INFO 0x60 +#define RK3066_WIN1_DSP_INFO 0x64 +#define RK3066_WIN1_DSP_ST 0x68 +#define RK3066_WIN1_SCL_FACTOR_YRGB 0x6c +#define RK3066_WIN1_SCL_FACTOR_CBR 0x70 +#define RK3066_WIN1_SCL_OFFSET 0x74 +#define RK3066_WIN2_MST 0x78 +#define RK3066_WIN2_VIR 0x7c +#define RK3066_WIN2_DSP_INFO 0x80 +#define RK3066_WIN2_DSP_ST 0x84 +#define RK3066_HWC_MST 0x88 +#define RK3066_HWC_DSP_ST 0x8c +#define RK3066_HWC_COLOR_LUT0 0x90 +#define RK3066_HWC_COLOR_LUT1 0x94 +#define RK3066_HWC_COLOR_LUT2 0x98 +#define RK3066_DSP_HTOTAL_HS_END 0x9c +#define RK3066_DSP_HACT_ST_END 0xa0 +#define RK3066_DSP_VTOTAL_VS_END 0xa4 +#define RK3066_DSP_VACT_ST_END 0xa8 +#define RK3066_DSP_VS_ST_END_F1 0xac +#define RK3066_DSP_VACT_ST_END_F1 0xb0 +#define RK3066_REG_CFG_DONE 0xc0 +#define RK3066_MCU_BYPASS_WPORT 0x100 +#define RK3066_MCU_BYPASS_RPORT 0x200 +#define RK3066_WIN2_LUT_ADDR 0x400 +#define RK3066_DSP_LUT_ADDR 0x800 + +/* rk3366 register definition */ +#define RK3366_LIT_REG_CFG_DONE 0x00000 +#define RK3366_LIT_VERSION 0x00004 +#define RK3366_LIT_DSP_BG 0x00008 +#define RK3366_LIT_MCU_CTRL 0x0000c +#define RK3366_LIT_SYS_CTRL0 0x00010 +#define RK3366_LIT_SYS_CTRL1 0x00014 +#define RK3366_LIT_SYS_CTRL2 0x00018 +#define RK3366_LIT_DSP_CTRL0 0x00020 +#define RK3366_LIT_DSP_CTRL2 0x00028 +#define RK3366_LIT_VOP_STATUS 0x0002c +#define RK3366_LIT_LINE_FLAG 0x00030 +#define RK3366_LIT_INTR_EN 0x00034 +#define RK3366_LIT_INTR_CLEAR 0x00038 +#define RK3366_LIT_INTR_STATUS 0x0003c +#define RK3366_LIT_WIN0_CTRL0 0x00050 +#define RK3366_LIT_WIN0_CTRL1 0x00054 +#define RK3366_LIT_WIN0_COLOR_KEY 0x00058 +#define RK3366_LIT_WIN0_VIR 0x0005c +#define RK3366_LIT_WIN0_YRGB_MST0 0x00060 +#define RK3366_LIT_WIN0_CBR_MST0 0x00064 +#define RK3366_LIT_WIN0_ACT_INFO 0x00068 +#define RK3366_LIT_WIN0_DSP_INFO 0x0006c +#define RK3366_LIT_WIN0_DSP_ST 0x00070 +#define RK3366_LIT_WIN0_SCL_FACTOR_YRGB 0x00074 +#define RK3366_LIT_WIN0_SCL_FACTOR_CBR 0x00078 +#define RK3366_LIT_WIN0_SCL_OFFSET 0x0007c +#define RK3366_LIT_WIN0_ALPHA_CTRL 0x00080 +#define RK3366_LIT_WIN1_CTRL0 0x00090 +#define RK3366_LIT_WIN1_CTRL1 0x00094 +#define RK3366_LIT_WIN1_VIR 0x00098 +#define RK3366_LIT_WIN1_MST 0x000a0 +#define RK3366_LIT_WIN1_DSP_INFO 0x000a4 +#define RK3366_LIT_WIN1_DSP_ST 0x000a8 +#define RK3366_LIT_WIN1_COLOR_KEY 0x000ac +#define RK3366_LIT_WIN1_ALPHA_CTRL 0x000bc +#define RK3366_LIT_HWC_CTRL0 0x000e0 +#define RK3366_LIT_HWC_CTRL1 0x000e4 +#define RK3366_LIT_HWC_MST 0x000e8 +#define RK3366_LIT_HWC_DSP_ST 0x000ec +#define RK3366_LIT_HWC_ALPHA_CTRL 0x000f0 +#define RK3366_LIT_DSP_HTOTAL_HS_END 0x00100 +#define RK3366_LIT_DSP_HACT_ST_END 0x00104 +#define RK3366_LIT_DSP_VTOTAL_VS_END 0x00108 +#define RK3366_LIT_DSP_VACT_ST_END 0x0010c +#define RK3366_LIT_DSP_VS_ST_END_F1 0x00110 +#define RK3366_LIT_DSP_VACT_ST_END_F1 0x00114 +#define RK3366_LIT_BCSH_CTRL 0x00160 +#define RK3366_LIT_BCSH_COL_BAR 0x00164 +#define RK3366_LIT_BCSH_BCS 0x00168 +#define RK3366_LIT_BCSH_H 0x0016c +#define RK3366_LIT_FRC_LOWER01_0 0x00170 +#define RK3366_LIT_FRC_LOWER01_1 0x00174 +#define RK3366_LIT_FRC_LOWER10_0 0x00178 +#define RK3366_LIT_FRC_LOWER10_1 0x0017c +#define RK3366_LIT_FRC_LOWER11_0 0x00180 +#define RK3366_LIT_FRC_LOWER11_1 0x00184 +#define RK3366_LIT_MCU_RW_BYPASS_PORT 0x0018c +#define RK3366_LIT_DBG_REG_000 0x00190 +#define RK3366_LIT_BLANKING_VALUE 0x001f4 +#define RK3366_LIT_FLAG_REG_FRM_VALID 0x001f8 +#define RK3366_LIT_FLAG_REG 0x001fc +#define RK3366_LIT_HWC_LUT_ADDR 0x00600 +#define RK3366_LIT_GAMMA_LUT_ADDR 0x00a00 +/* rk3366 register definition end */ + /* rk3126 register definition */ -#define RK3126_WIN1_MST 0x4c -#define RK3126_WIN1_DSP_INFO 0x50 -#define RK3126_WIN1_DSP_ST 0x54 +#define RK3126_WIN1_MST 0x0004c +#define RK3126_WIN1_DSP_INFO 0x00050 +#define RK3126_WIN1_DSP_ST 0x00054 /* rk3126 register definition end */ +/* px30 register definition */ +#define PX30_CABC_CTRL0 0x00200 +#define PX30_CABC_CTRL1 0x00204 +#define PX30_CABC_CTRL2 0x00208 +#define PX30_CABC_CTRL3 0x0020c +#define PX30_CABC_GAUSS_LINE0_0 0x00210 +#define PX30_CABC_GAUSS_LINE0_1 0x00214 +#define PX30_CABC_GAUSS_LINE1_0 0x00218 +#define PX30_CABC_GAUSS_LINE1_1 0x0021c +#define PX30_CABC_GAUSS_LINE2_0 0x00220 +#define PX30_CABC_GAUSS_LINE2_1 0x00224 +#define PX30_AFBCD0_CTRL 0x00240 +#define PX30_AFBCD0_HDR_PTR 0x00244 +#define PX30_AFBCD0_PIC_SIZE 0x00248 +#define PX30_AFBCD0_PIC_OFFSET 0x0024c +#define PX30_AFBCD0_AXI_CTRL 0x00250 +#define PX30_GRF_PD_VO_CON1 0x00438 +/* px30 register definition end */ + #endif /* _ROCKCHIP_VOP_REG_H */