Re: [RFC v3 AFBC 04/12] drm/arm/malidp: Set the AFBC register bits if the framebuffer has AFBC modifier

From: Liviu Dudau
Date: Tue Dec 04 2018 - 11:50:57 EST


On Mon, Dec 03, 2018 at 11:31:58AM +0000, Ayan Halder wrote:
> Added the AFBC decoder registers for DP500 , DP550 and DP650.
> These registers control the processing of AFBC buffers. It controls various
> features like AFBC decoder enable, lossless transformation and block split
> as well as setting of the left, right, top and bottom cropping of AFBC buffers
> (in number of pixels).
> All the layers (except DE_SMART) support framebuffers with AFBC modifiers.
> One needs to set the pixel values of the top, left, bottom and right cropping
> for the AFBC framebuffer.
> Cropping an AFBC framebuffer is controlled by the AFBC crop registers.
> In that case, the layer input size registers should be configured with
> framebuffer's dimensions and not with drm_plane_state source width/height
> values (which is used for non AFBC framebuffer to denote cropping).
>
> Changes from v1:
> - Removed the "if (fb->modifier)" check from malidp_de_plane_update()
> and added it in malidp_de_set_plane_afbc(). This will consolidate all the
> AFBC specific register configurations in a single function ie
> malidp_de_set_plane_afbc().
>
> Changes from v2:
> - For AFBC framebuffer, layer input size register should be set to framebuffer's
> width and height
>
> Signed-off-by: Ayan Kumar Halder <ayan.halder@xxxxxxx>
> ---
> drivers/gpu/drm/arm/malidp_hw.c | 25 +++++----
> drivers/gpu/drm/arm/malidp_hw.h | 2 +
> drivers/gpu/drm/arm/malidp_planes.c | 109 +++++++++++++++++++++++++++++++-----
> drivers/gpu/drm/arm/malidp_regs.h | 20 +++++++
> 4 files changed, 130 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
> index b9bed11..87b7b12 100644
> --- a/drivers/gpu/drm/arm/malidp_hw.c
> +++ b/drivers/gpu/drm/arm/malidp_hw.c
> @@ -94,11 +94,12 @@ static const struct malidp_layer malidp500_layers[] = {
> * yuv2rgb matrix offset, mmu control register offset, rotation_features
> */
> { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
> - MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY },
> + MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY,
> + MALIDP500_DE_LV_AD_CTRL },
> { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
> - MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
> + MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY, MALIDP500_DE_LG1_AD_CTRL },
> { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
> - MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
> + MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY, MALIDP500_DE_LG2_AD_CTRL },
> };
>
> static const struct malidp_layer malidp550_layers[] = {
> @@ -106,13 +107,15 @@ static const struct malidp_layer malidp550_layers[] = {
> * yuv2rgb matrix offset, mmu control register offset, rotation_features
> */
> { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
> - MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
> + MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
> + MALIDP550_DE_LV1_AD_CTRL },
> { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
> - MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
> + MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY, MALIDP550_DE_LG_AD_CTRL },
> { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
> - MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
> + MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
> + MALIDP550_DE_LV2_AD_CTRL },
> { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
> - MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE },
> + MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE, 0 },
> };
>
> static const struct malidp_layer malidp650_layers[] = {
> @@ -122,16 +125,16 @@ static const struct malidp_layer malidp650_layers[] = {
> */
> { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
> MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
> - MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
> + MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY, MALIDP550_DE_LV1_AD_CTRL },
> { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
> MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
> - ROTATE_COMPRESSED },
> + ROTATE_COMPRESSED, MALIDP550_DE_LG_AD_CTRL },
> { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
> MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
> - MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
> + MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY, MALIDP550_DE_LV2_AD_CTRL },
> { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
> MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
> - ROTATE_NONE },
> + ROTATE_NONE, 0 },
> };
>
> #define SE_N_SCALING_COEFFS 96
> diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
> index 40155e2..651558f 100644
> --- a/drivers/gpu/drm/arm/malidp_hw.h
> +++ b/drivers/gpu/drm/arm/malidp_hw.h
> @@ -70,6 +70,8 @@ struct malidp_layer {
> s16 yuv2rgb_offset; /* offset to the YUV->RGB matrix entries */
> u16 mmu_ctrl_offset; /* offset to the MMU control register */
> enum rotation_features rot; /* type of rotation supported */
> + /* address offset for the AFBC decoder registers */
> + u16 afbc_decoder_offset;
> };
>
> enum malidp_scaling_coeff_set {
> diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
> index c9a6d3e..cd60f73 100644
> --- a/drivers/gpu/drm/arm/malidp_planes.c
> +++ b/drivers/gpu/drm/arm/malidp_planes.c
> @@ -592,6 +592,80 @@ static void malidp_de_set_mmu_control(struct malidp_plane *mp,
> mp->layer->base + mp->layer->mmu_ctrl_offset);
> }
>
> +static void malidp_set_plane_base_addr(struct drm_framebuffer *fb,
> + struct malidp_plane *mp,
> + int plane_index)
> +{
> + dma_addr_t paddr;
> + u16 ptr;
> + struct drm_plane *plane = &mp->base;
> + bool afbc = fb->modifier ? true : false;
> +
> + ptr = mp->layer->ptr + (plane_index << 4);
> +
> + /*
> + * For AFBC buffers, cropping is handled by AFBC decoder rather than
> + * pointer manipulation.
> + */

I think this comment needs to go in malidp_de_plane_update, not in this function.
This function only updates the plane's base address.

> + if (!afbc) {
> + paddr = drm_fb_cma_get_gem_addr(fb, plane->state,
> + plane_index);
> + } else {
> + struct drm_gem_cma_object *obj;
> +
> + obj = drm_fb_cma_get_gem_obj(fb, plane_index);
> +
> + if (WARN_ON(!obj))
> + return;
> + paddr = obj->paddr;
> + }
> +
> + malidp_hw_write(mp->hwdev, lower_32_bits(paddr), ptr);
> + malidp_hw_write(mp->hwdev, upper_32_bits(paddr), ptr + 4);
> +}
> +
> +static void malidp_de_set_plane_afbc(struct drm_plane *plane)
> +{
> + struct malidp_plane *mp;
> + u32 src_w, src_h, val = 0, src_x, src_y;
> + struct drm_framebuffer *fb = plane->state->fb;
> +
> + mp = to_malidp_plane(plane);
> +
> + /* no afbc_decoder_offset means AFBC is not supported on this plane */
> + if (!mp->layer->afbc_decoder_offset)
> + return;
> +
> + if (!fb->modifier) {
> + malidp_hw_write(mp->hwdev, 0, mp->layer->afbc_decoder_offset);
> + return;
> + }
> +
> + /* convert src values from Q16 fixed point to integer */
> + src_w = plane->state->src_w >> 16;
> + src_h = plane->state->src_h >> 16;
> + src_x = plane->state->src_x >> 16;
> + src_y = plane->state->src_y >> 16;
> +
> + val = ((fb->width - (src_x + src_w)) << MALIDP_AD_CROP_RIGHT_OFFSET) |
> + src_x;
> + malidp_hw_write(mp->hwdev, val,
> + mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_H);
> +
> + val = ((fb->height - (src_y + src_h)) << MALIDP_AD_CROP_BOTTOM_OFFSET) |
> + src_y;
> + malidp_hw_write(mp->hwdev, val,
> + mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_V);
> +
> + val = MALIDP_AD_EN;
> + if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
> + val |= MALIDP_AD_BS;
> + if (fb->modifier & AFBC_FORMAT_MOD_YTR)
> + val |= MALIDP_AD_YTR;
> +
> + malidp_hw_write(mp->hwdev, val, mp->layer->afbc_decoder_offset);
> +}
> +
> static void malidp_de_plane_update(struct drm_plane *plane,
> struct drm_plane_state *old_state)
> {
> @@ -600,30 +674,33 @@ static void malidp_de_plane_update(struct drm_plane *plane,
> struct drm_plane_state *state = plane->state;
> u16 pixel_alpha = state->pixel_blend_mode;
> u8 plane_alpha = state->alpha >> 8;
> + bool format_has_alpha = state->fb->format->has_alpha;
> u32 src_w, src_h, dest_w, dest_h, val;
> int i;
> + struct drm_framebuffer *fb = plane->state->fb;
>
> mp = to_malidp_plane(plane);
>
> - /* convert src values from Q16 fixed point to integer */
> - src_w = state->src_w >> 16;
> - src_h = state->src_h >> 16;
> - dest_w = state->crtc_w;
> - dest_h = state->crtc_h;
> + /* For AFBC framebuffer, use the framebuffer width and height for configuring
> + * layer input size register.
> + */
> + if (fb->modifier) {
> + src_w = fb->width;
> + src_h = fb->height;
> + } else {
> + /* convert src values from Q16 fixed point to integer */
> + src_w = ms->base.src_w >> 16;
> + src_h = ms->base.src_h >> 16;
> + }
> + dest_w = ms->base.crtc_w;
> + dest_h = ms->base.crtc_h;

These two lines above are equivalent to the last two lines you deleted. Why you need this change?

>
> val = malidp_hw_read(mp->hwdev, mp->layer->base);
> val = (val & ~LAYER_FORMAT_MASK) | ms->format;
> malidp_hw_write(mp->hwdev, val, mp->layer->base);
>
> - for (i = 0; i < ms->n_planes; i++) {
> - /* calculate the offset for the layer's plane registers */
> - u16 ptr = mp->layer->ptr + (i << 4);
> - dma_addr_t fb_addr = drm_fb_cma_get_gem_addr(state->fb,
> - state, i);
> -
> - malidp_hw_write(mp->hwdev, lower_32_bits(fb_addr), ptr);
> - malidp_hw_write(mp->hwdev, upper_32_bits(fb_addr), ptr + 4);
> - }
> + for (i = 0; i < ms->n_planes; i++)
> + malidp_set_plane_base_addr(fb, mp, i);
>
> malidp_de_set_mmu_control(mp, ms);
>
> @@ -657,6 +734,8 @@ static void malidp_de_plane_update(struct drm_plane *plane,
> mp->layer->base + MALIDP550_LS_R1_IN_SIZE);
> }
>
> + malidp_de_set_plane_afbc(plane);

I feel like this function call should be done only if (fb->modifier) is
true.

> +
> /* first clear the rotation bits */
> val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
> val &= ~LAYER_ROT_MASK;
> @@ -674,7 +753,7 @@ static void malidp_de_plane_update(struct drm_plane *plane,
>
> if (state->alpha != DRM_BLEND_ALPHA_OPAQUE) {
> val |= LAYER_COMP_PLANE;
> - } else if (state->fb->format->has_alpha) {
> + } else if (format_has_alpha) {

This change has nothing to do with AFBC, it should not be in this patch.

> /* We only care about blend mode if the format has alpha */
> switch (pixel_alpha) {
> case DRM_MODE_BLEND_PREMULTI:
> diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
> index 7ce3e14..a0dd6e1 100644
> --- a/drivers/gpu/drm/arm/malidp_regs.h
> +++ b/drivers/gpu/drm/arm/malidp_regs.h
> @@ -198,10 +198,13 @@
> #define MALIDP500_LV_YUV2RGB ((s16)(-0xB8))
> #define MALIDP500_DE_LV_BASE 0x00100
> #define MALIDP500_DE_LV_PTR_BASE 0x00124
> +#define MALIDP500_DE_LV_AD_CTRL 0x00400
> #define MALIDP500_DE_LG1_BASE 0x00200
> #define MALIDP500_DE_LG1_PTR_BASE 0x0021c
> +#define MALIDP500_DE_LG1_AD_CTRL 0x0040c
> #define MALIDP500_DE_LG2_BASE 0x00300
> #define MALIDP500_DE_LG2_PTR_BASE 0x0031c
> +#define MALIDP500_DE_LG2_AD_CTRL 0x00418
> #define MALIDP500_SE_BASE 0x00c00
> #define MALIDP500_SE_CONTROL 0x00c0c
> #define MALIDP500_SE_MEMWRITE_OUT_SIZE 0x00c2c
> @@ -228,10 +231,13 @@
> #define MALIDP550_LV_YUV2RGB 0x00084
> #define MALIDP550_DE_LV1_BASE 0x00100
> #define MALIDP550_DE_LV1_PTR_BASE 0x00124
> +#define MALIDP550_DE_LV1_AD_CTRL 0x001B8
> #define MALIDP550_DE_LV2_BASE 0x00200
> #define MALIDP550_DE_LV2_PTR_BASE 0x00224
> +#define MALIDP550_DE_LV2_AD_CTRL 0x002B8
> #define MALIDP550_DE_LG_BASE 0x00300
> #define MALIDP550_DE_LG_PTR_BASE 0x0031c
> +#define MALIDP550_DE_LG_AD_CTRL 0x00330
> #define MALIDP550_DE_LS_BASE 0x00400
> #define MALIDP550_DE_LS_PTR_BASE 0x0042c
> #define MALIDP550_DE_PERF_BASE 0x00500
> @@ -258,6 +264,20 @@
> #define MALIDP_MMU_CTRL_PX_PS(x) (1 << (8 + (x)))
> #define MALIDP_MMU_CTRL_PP_NUM_REQ(x) (((x) & 0x7f) << 12)
>
> +/* AFBC register offsets relative to MALIDPXXX_DE_LX_AD_CTRL */
> +/* The following register offsets are common for DP500, DP550 and DP650 */
> +#define MALIDP_AD_CROP_H 0x4
> +#define MALIDP_AD_CROP_V 0x8
> +#define MALIDP_AD_END_PTR_LOW 0xc
> +#define MALIDP_AD_END_PTR_HIGH 0x10
> +
> +/* AFBC decoder Registers */
> +#define MALIDP_AD_EN BIT(0)
> +#define MALIDP_AD_YTR BIT(4)
> +#define MALIDP_AD_BS BIT(8)
> +#define MALIDP_AD_CROP_RIGHT_OFFSET 16
> +#define MALIDP_AD_CROP_BOTTOM_OFFSET 16
> +
> /*
> * Starting with DP550 the register map blocks has been standardised to the
> * following layout:
> --
> 2.7.4
>

Best regards,
Liviu


--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
Â\_(ã)_/Â