diff options
Diffstat (limited to 'drivers/gpu/drm/mediatek/mtk_disp_ovl.c')
-rw-r--r-- | drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 140 |
1 files changed, 87 insertions, 53 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c index b552a02d7eae..9d6d9fd8342e 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c @@ -38,10 +38,15 @@ #define DISP_REG_OVL_PITCH_MSB(n) (0x0040 + 0x20 * (n)) #define OVL_PITCH_MSB_2ND_SUBBUF BIT(16) #define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n)) +#define OVL_CONST_BLEND BIT(28) #define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n)) #define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n)) #define DISP_REG_OVL_ADDR_MT2701 0x0040 -#define DISP_REG_OVL_CLRFMT_EXT 0x02D0 +#define DISP_REG_OVL_CLRFMT_EXT 0x02d0 +#define OVL_CON_CLRFMT_BIT_DEPTH_MASK(n) (GENMASK(1, 0) << (4 * (n))) +#define OVL_CON_CLRFMT_BIT_DEPTH(depth, n) ((depth) << (4 * (n))) +#define OVL_CON_CLRFMT_8_BIT (0) +#define OVL_CON_CLRFMT_10_BIT (1) #define DISP_REG_OVL_ADDR_MT8173 0x0f40 #define DISP_REG_OVL_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n)) #define DISP_REG_OVL_HDR_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n) + 0x04) @@ -54,23 +59,39 @@ #define OVL_CON_BYTE_SWAP BIT(24) #define OVL_CON_MTX_YUV_TO_RGB (6 << 16) #define OVL_CON_CLRFMT_RGB (1 << 12) -#define OVL_CON_CLRFMT_RGBA8888 (2 << 12) -#define OVL_CON_CLRFMT_ARGB8888 (3 << 12) +#define OVL_CON_CLRFMT_ARGB8888 (2 << 12) +#define OVL_CON_CLRFMT_RGBA8888 (3 << 12) +#define OVL_CON_CLRFMT_ABGR8888 (OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP) +#define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP) #define OVL_CON_CLRFMT_UYVY (4 << 12) #define OVL_CON_CLRFMT_YUYV (5 << 12) #define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \ 0 : OVL_CON_CLRFMT_RGB) #define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \ OVL_CON_CLRFMT_RGB : 0) -#define OVL_CON_CLRFMT_BIT_DEPTH_MASK(ovl) (0xFF << 4 * (ovl)) -#define OVL_CON_CLRFMT_BIT_DEPTH(depth, ovl) (depth << 4 * (ovl)) -#define OVL_CON_CLRFMT_8_BIT 0x00 -#define OVL_CON_CLRFMT_10_BIT 0x01 #define OVL_CON_AEN BIT(8) #define OVL_CON_ALPHA 0xff #define OVL_CON_VIRT_FLIP BIT(9) #define OVL_CON_HORZ_FLIP BIT(10) +#define OVL_COLOR_ALPHA GENMASK(31, 24) + +static inline bool is_10bit_rgb(u32 fmt) +{ + switch (fmt) { + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_BGRA1010102: + return true; + } + return false; +} + static const u32 mt8173_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, @@ -88,12 +109,20 @@ static const u32 mt8173_formats[] = { static const u32 mt8195_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_BGRX8888, DRM_FORMAT_BGRA8888, + DRM_FORMAT_BGRX1010102, DRM_FORMAT_BGRA1010102, DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_RGBX1010102, + DRM_FORMAT_RGBA1010102, DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, DRM_FORMAT_RGB565, @@ -244,24 +273,17 @@ static void mtk_ovl_set_bit_depth(struct device *dev, int idx, u32 format, struct cmdq_pkt *cmdq_pkt) { struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); - unsigned int reg; unsigned int bit_depth = OVL_CON_CLRFMT_8_BIT; if (!ovl->data->supports_clrfmt_ext) return; - reg = readl(ovl->regs + DISP_REG_OVL_CLRFMT_EXT); - reg &= ~OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx); - - if (format == DRM_FORMAT_RGBA1010102 || - format == DRM_FORMAT_BGRA1010102 || - format == DRM_FORMAT_ARGB2101010) + if (is_10bit_rgb(format)) bit_depth = OVL_CON_CLRFMT_10_BIT; - reg |= OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx); - - mtk_ddp_write(cmdq_pkt, reg, &ovl->cmdq_reg, - ovl->regs, DISP_REG_OVL_CLRFMT_EXT); + mtk_ddp_write_mask(cmdq_pkt, OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx), + &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CLRFMT_EXT, + OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx)); } void mtk_ovl_config(struct device *dev, unsigned int w, @@ -273,7 +295,13 @@ void mtk_ovl_config(struct device *dev, unsigned int w, if (w != 0 && h != 0) mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_SIZE); - mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR); + + /* + * The background color must be opaque black (ARGB), + * otherwise the alpha blending will have no effect + */ + mtk_ddp_write_relaxed(cmdq_pkt, OVL_COLOR_ALPHA, &ovl->cmdq_reg, + ovl->regs, DISP_REG_OVL_ROI_BGCLR); mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); @@ -296,27 +324,20 @@ int mtk_ovl_layer_check(struct device *dev, unsigned int idx, struct mtk_plane_state *mtk_state) { struct drm_plane_state *state = &mtk_state->base; - unsigned int rotation = 0; - rotation = drm_rotation_simplify(state->rotation, - DRM_MODE_ROTATE_0 | - DRM_MODE_REFLECT_X | - DRM_MODE_REFLECT_Y); - rotation &= ~DRM_MODE_ROTATE_0; - - /* We can only do reflection, not rotation */ - if ((rotation & DRM_MODE_ROTATE_MASK) != 0) + /* check if any unsupported rotation is set */ + if (state->rotation & ~mtk_ovl_supported_rotations(dev)) return -EINVAL; /* * TODO: Rotating/reflecting YUV buffers is not supported at this time. * Only RGB[AX] variants are supported. + * Since DRM_MODE_ROTATE_0 means "no rotation", we should not + * reject layers with this property. */ - if (state->fb->format->is_yuv && rotation != 0) + if (state->fb->format->is_yuv && (state->rotation & ~DRM_MODE_ROTATE_0)) return -EINVAL; - state->rotation = rotation; - return 0; } @@ -375,18 +396,24 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt) return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP; case DRM_FORMAT_RGBX8888: case DRM_FORMAT_RGBA8888: - return OVL_CON_CLRFMT_ARGB8888; + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_RGBA1010102: + return OVL_CON_CLRFMT_RGBA8888; case DRM_FORMAT_BGRX8888: case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX1010102: case DRM_FORMAT_BGRA1010102: - return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP; + return OVL_CON_CLRFMT_BGRA8888; case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_ARGB2101010: - return OVL_CON_CLRFMT_RGBA8888; + return OVL_CON_CLRFMT_ARGB8888; case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ABGR8888: - return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + return OVL_CON_CLRFMT_ABGR8888; case DRM_FORMAT_UYVY: return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB; case DRM_FORMAT_YUYV: @@ -407,6 +434,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, unsigned int fmt = pending->format; unsigned int offset = (pending->y << 16) | pending->x; unsigned int src_size = (pending->height << 16) | pending->width; + unsigned int ignore_pixel_alpha = 0; unsigned int con; bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR; union overlay_pitch { @@ -425,8 +453,18 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, } con = ovl_fmt_convert(ovl, fmt); - if (state->base.fb && state->base.fb->format->has_alpha) - con |= OVL_CON_AEN | OVL_CON_ALPHA; + if (state->base.fb) { + con |= OVL_CON_AEN; + con |= state->base.alpha & OVL_CON_ALPHA; + } + + /* CONST_BLD must be enabled for XRGB formats although the alpha channel + * can be ignored, or OVL will still read the value from memory. + * For RGB888 related formats, whether CONST_BLD is enabled or not won't + * affect the result. Therefore we use !has_alpha as the condition. + */ + if (state->base.fb && !state->base.fb->format->has_alpha) + ignore_pixel_alpha = OVL_CONST_BLEND; if (pending->rotation & DRM_MODE_REFLECT_Y) { con |= OVL_CON_VIRT_FLIP; @@ -443,8 +481,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CON(idx)); - mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb, &ovl->cmdq_reg, ovl->regs, - DISP_REG_OVL_PITCH(idx)); + mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb | ignore_pixel_alpha, + &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx)); mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_SRC_SIZE(idx)); mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs, @@ -523,17 +561,15 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) return irq; priv->clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(dev, "failed to get ovl clk\n"); - return PTR_ERR(priv->clk); - } + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), + "failed to get ovl clk\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->regs)) { - dev_err(dev, "failed to ioremap ovl\n"); - return PTR_ERR(priv->regs); - } + if (IS_ERR(priv->regs)) + return dev_err_probe(dev, PTR_ERR(priv->regs), + "failed to ioremap ovl\n"); #if IS_REACHABLE(CONFIG_MTK_CMDQ) ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0); if (ret) @@ -545,20 +581,18 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, IRQF_TRIGGER_NONE, dev_name(dev), priv); - if (ret < 0) { - dev_err(dev, "Failed to request irq %d: %d\n", irq, ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to request irq %d\n", irq); pm_runtime_enable(dev); ret = component_add(dev, &mtk_disp_ovl_component_ops); if (ret) { pm_runtime_disable(dev); - dev_err(dev, "Failed to add component: %d\n", ret); + return dev_err_probe(dev, ret, "Failed to add component\n"); } - return ret; + return 0; } static void mtk_disp_ovl_remove(struct platform_device *pdev) |