[RESEND PATCH v2] drm/mediatek: Add AFBC support to Mediatek DRM driver

AngeloGioacchino Del Regno angelogioacchino.delregno at collabora.com
Wed Oct 12 01:25:45 PDT 2022


Il 11/10/22 20:28, Justin Green ha scritto:
> Hi Angelo,
> Thanks for the suggestions! I'll upload another patch with those changes.
> 
> Re the pitch register math, would it be acceptable to define separate
> macros for the LSB and MSB to abstract away the magic numbers? For
> example:
> #define OVL_PITCH_MSB(n)                        ((n >> 16) & GENMASK(15, 0))
> #define OVL_PITCH_LSB(n)                        (n & GENMASK(15, 0))
> 

These would be different from the macros that are available in bitfield.h, but
not *fundamentally* different, so these would look a little redundant...

I think that you refer to that `pitch` variable that's coming from the DRM(/fb)
API... and bitfield macros are for register access... so I guess that one clean
way of avoiding the magic shifting (that is purely used to split the 32-bits
number in two 16-bits 'chunks') would be to perhaps use a union, so that you
will have something like u.pitch_lsb, u.pitch_msb (with lsb/msb being two u16).

That'd better represent what is going on here, I believe?

Regards,
Angelo

> Regards,
> Justin
> 
> On Tue, Oct 11, 2022 at 5:09 AM AngeloGioacchino Del Regno
> <angelogioacchino.delregno at collabora.com> wrote:
>>
>> Il 10/10/22 17:01, Justin Green ha scritto:
>>> From: Justin Green <greenjustin at chromium.org>
>>>
>>> Add AFBC support to Mediatek DRM driver and enable on MT8195.
>>>
>>> Tested on MT8195 and confirmed both correct video output and improved DRAM
>>> bandwidth performance.
>>>
>>> v2:
>>> Marked mtk_ovl_set_afbc as static, reflowed some lines to fit column
>>> limit.
>>>
>>> Signed-off-by: Justin Green <greenjustin at chromium.org>
>>
>> Hello Justin,
>> thanks for the patch!
>>
>> However, there's something to improve...
>>
>>> ---
>>>    drivers/gpu/drm/mediatek/mtk_disp_ovl.c  | 108 ++++++++++++++++++++---
>>>    drivers/gpu/drm/mediatek/mtk_drm_plane.c |  37 +++++++-
>>>    drivers/gpu/drm/mediatek/mtk_drm_plane.h |   8 ++
>>>    3 files changed, 140 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
>>> index 002b0f6cae1a..1724ea85a840 100644
>>> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
>>> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
>>
>> ..snip..
>>
>>> @@ -208,6 +231,8 @@ int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
>>>    {
>>>        struct drm_plane_state *state = &mtk_state->base;
>>>        unsigned int rotation = 0;
>>> +     unsigned long long modifier;
>>> +     unsigned int fourcc;
>>>
>>>        rotation = drm_rotation_simplify(state->rotation,
>>>                                         DRM_MODE_ROTATE_0 |
>>> @@ -226,6 +251,30 @@ int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
>>>        if (state->fb->format->is_yuv && rotation != 0)
>>>                return -EINVAL;
>>>
>>> +     if (state->fb->modifier) {
>>> +             struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
>>
>> Since you're introducing modifier and fourcc for this branch only, you
>> may as well just declare them here instead, but either way is fine.
>>
>>> +
>>> +             if (!ovl->data->supports_afbc)
>>> +                     return -EINVAL;
>>> +
>>> +             modifier = state->fb->modifier;
>>> +
>>> +             if (modifier != DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
>>> +                                                     AFBC_FORMAT_MOD_SPLIT |
>>> +                                                     AFBC_FORMAT_MOD_SPARSE))
>>> +                     return -EINVAL;
>>> +
>>> +             fourcc = state->fb->format->format;
>>> +             if (fourcc != DRM_FORMAT_BGRA8888 &&
>>> +                 fourcc != DRM_FORMAT_ABGR8888 &&
>>> +                 fourcc != DRM_FORMAT_ARGB8888 &&
>>> +                 fourcc != DRM_FORMAT_XRGB8888 &&
>>> +                 fourcc != DRM_FORMAT_XBGR8888 &&
>>> +                 fourcc != DRM_FORMAT_RGB888 &&
>>> +                 fourcc != DRM_FORMAT_BGR888)
>>> +                     return -EINVAL;
>>> +     }
>>> +
>>>        state->rotation = rotation;
>>>
>>>        return 0;
>>> @@ -310,11 +359,14 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
>>>        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
>>>        struct mtk_plane_pending_state *pending = &state->pending;
>>>        unsigned int addr = pending->addr;
>>> -     unsigned int pitch = pending->pitch & 0xffff;
>>> +     unsigned int hdr_addr = pending->hdr_addr;
>>> +     unsigned int pitch = pending->pitch;
>>> +     unsigned int hdr_pitch = pending->hdr_pitch;
>>>        unsigned int fmt = pending->format;
>>>        unsigned int offset = (pending->y << 16) | pending->x;
>>>        unsigned int src_size = (pending->height << 16) | pending->width;
>>>        unsigned int con;
>>> +     bool is_afbc = pending->modifier;
>>>
>>>        if (!pending->enable) {
>>>                mtk_ovl_layer_off(dev, idx, cmdq_pkt);
>>> @@ -335,16 +387,39 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
>>>                addr += pending->pitch - 1;
>>>        }
>>>
>>> -     mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
>>> -                           DISP_REG_OVL_CON(idx));
>>> -     mtk_ddp_write_relaxed(cmdq_pkt, pitch, &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,
>>> -                           DISP_REG_OVL_OFFSET(idx));
>>> -     mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
>>> -                           DISP_REG_OVL_ADDR(ovl, idx));
>>> +     mtk_ovl_set_afbc(dev, cmdq_pkt, idx, is_afbc);
>>> +     if (!is_afbc) {
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_CON(idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, pitch & 0xFFFF, &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,
>>> +                                   DISP_REG_OVL_OFFSET(idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_ADDR(ovl, idx));
>>> +     } else {
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_ADDR(ovl, idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_HDR_ADDR(ovl, 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,
>>> +                                   OVL_PITCH_MSB_2ND_SUBBUF | ((pitch >> 16) & 0xFFFF),
>>
>> I say that this would be more readable if you use bitfield macros instead but,
>> anyway, that magic "16" number must get a definition.
>> I have the same comment about the GENMASK(15, 0) (== 0xffff), but I know that
>> doesn't come from you... would still be nice to also add a definition, which
>> is anyway "practically mandatory" if you use FIELD_PREP(mask, val).
>>
>>> +                                   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH_MSB(idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, pitch & 0xFFFF, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_PITCH(idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, hdr_pitch, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_HDR_PITCH(ovl, idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_CON(idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_OFFSET(idx));
>>> +             mtk_ddp_write_relaxed(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
>>> +                                   DISP_REG_OVL_CLIP(idx));
>>> +     }
>>
>> In any case - are you use that we *must* program the registers in this exact
>> sequence?
>>
>> Here, the OVL layer is supposed to be OFF (OVL_SRC_CON == 0, OVL_RDMA_CTRL == 0)
>> so the contents of the registers that you're modifying should not matter at all
>> until the layer is turned on.
>>
>> Note that, in case it doesn't matter, this gets greatly simplified, exactly as:
>>
>> at the top -- after DISP_REG_OVL_PITCH_MSB(n):
>> #define OVL_SRC_PITCH_MSB       GENMASK(3, 0)
>>
>> after DISP_REG_OVL_PITCH(n):
>> #define OVL_SRC_PITCH_LSB       GENMASK(15, 0)
>>
>>          mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
>>                                DISP_REG_OVL_CON(idx));
>>          mtk_ddp_write_relaxed(cmdq_pkt, FIELD_PREP(OVL_SRC_PITCH_LSB, pitch),
>>                                &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,
>>                                DISP_REG_OVL_OFFSET(idx));
>>          mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
>>                                DISP_REG_OVL_ADDR(ovl, idx));
>>
>>          if (is_afbc) {
>>                  pitch_msb = FIELD_PREP(OVL_SRC_PITCH_MSB, (pitch >> 16));
>>                  pitch_msb |= FIELD_PREP(OVL_PITCH_MSB_2ND_SUBBUF, 1);
>>                  mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs,
>>                                        DISP_REG_OVL_HDR_ADDR(ovl, idx));
>>                  mtk_ddp_write_relaxed(cmdq_pkt, val, &ovl->cmdq_reg, ovl->regs,
>>                                        DISP_REG_OVL_PITCH_MSB(idx));
>>                  mtk_ddp_write_relaxed(cmdq_pkt, hdr_pitch, &ovl->cmdq_reg, ovl->regs,
>>                                        DISP_REG_OVL_HDR_PITCH(ovl, idx));
>>                  mtk_ddp_write_relaxed(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
>>                                        DISP_REG_OVL_CLIP(idx));
>>          }
>>
>>>
>>>        mtk_ovl_layer_on(dev, idx, cmdq_pkt);
>>>    }
>>> @@ -492,6 +567,15 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
>>
>> ..snip..
>>
>>> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
>>> index 5c0d9ce69931..734d2554b2b8 100644
>>> --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
>>> +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
>>> @@ -12,6 +12,7 @@
>>>    #include <drm/drm_framebuffer.h>
>>>    #include <drm/drm_gem_atomic_helper.h>
>>>    #include <drm/drm_plane_helper.h>
>>> +#include <linux/align.h>
>>>
>>>    #include "mtk_drm_crtc.h"
>>>    #include "mtk_drm_ddp_comp.h"
>>> @@ -52,6 +53,7 @@ static void mtk_plane_reset(struct drm_plane *plane)
>>>
>>>        state->base.plane = plane;
>>>        state->pending.format = DRM_FORMAT_RGB565;
>>> +     state->pending.modifier = 0;
>>>    }
>>>
>>>    static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
>>> @@ -120,21 +122,52 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
>>>        struct drm_gem_object *gem;
>>>        struct mtk_drm_gem_obj *mtk_gem;
>>>        unsigned int pitch, format;
>>> +     unsigned long long modifier;
>>>        dma_addr_t addr;
>>> +     dma_addr_t hdr_addr = 0;
>>> +     unsigned int hdr_pitch = 0;
>>>
>>>        gem = fb->obj[0];
>>>        mtk_gem = to_mtk_gem_obj(gem);
>>>        addr = mtk_gem->dma_addr;
>>>        pitch = fb->pitches[0];
>>>        format = fb->format->format;
>>> +     modifier = fb->modifier;
>>>
>>> -     addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
>>> -     addr += (new_state->src.y1 >> 16) * pitch;
>>> +     if (!modifier) {
>>> +             addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
>>> +             addr += (new_state->src.y1 >> 16) * pitch;
>>> +     } else {
>>> +             int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH)
>>> +                                   / AFBC_DATA_BLOCK_WIDTH;
>>> +             int height_in_blocks = ALIGN(fb->height, AFBC_DATA_BLOCK_HEIGHT)
>>> +                                    / AFBC_DATA_BLOCK_HEIGHT;
>>> +             int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH;
>>> +             int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT;
>>> +             int hdr_size;
>>> +
>>> +             hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE;
>>> +             pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH *
>>> +                     AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0];
>>> +
>>> +             hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT);
>>> +
>>> +             hdr_addr = addr + hdr_pitch * y_offset_in_blocks +
>>> +                        AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks;
>>> +             // The data plane is offset by 1 additional block.
>>
>> C-style comments please.
>>
>>> +             addr = addr + hdr_size +
>>> +                    pitch * y_offset_in_blocks +
>>> +                    AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT *
>>> +                    fb->format->cpp[0] * (x_offset_in_blocks + 1);
>>> +     }
>>>
>>
>> Regards,
>> Angelo
>>





More information about the Linux-mediatek mailing list