summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/arm/malidp_planes.c
diff options
context:
space:
mode:
authorAyan Kumar Halder <ayan.halder@arm.com>2018-05-16 19:23:08 +0100
committerAyan kumar halder <ayan.halder@arm.com>2019-03-12 18:25:06 +0000
commit54b4260ac404813d97a499eec370204f6de8f43b (patch)
tree750befe9ffb6c2a122dd3721fcff8b4d5d01d4cb /drivers/gpu/drm/arm/malidp_planes.c
parente9961ab95af81b8d29054361cd5f0c575102cf87 (diff)
drm/arm/malidp: Set the AFBC register bits if the framebuffer has AFBC modifier
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. Changes from v3: - Rebased on top of latest drm-misc-next - Some cleanups/sanity changes based on Liviu's comments Changes from v3 (series): - Added the ack - Rebased on the latest drm-misc-next Signed-off-by: Ayan Kumar Halder <ayan.halder@arm.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> Acked-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Link: https://patchwork.freedesktop.org/patch/291760/?series=57895&rev=1
Diffstat (limited to 'drivers/gpu/drm/arm/malidp_planes.c')
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c107
1 files changed, 95 insertions, 12 deletions
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index c9a6d3e0cada..181957c9e89d 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -592,6 +592,83 @@ 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);
+
+ /*
+ * drm_fb_cma_get_gem_addr() alters the physical base address of the
+ * framebuffer as per the plane's src_x, src_y co-ordinates (ie to
+ * take care of source cropping).
+ * For AFBC, this is not needed as the cropping is handled by _AD_CROP_H
+ * and _AD_CROP_V registers.
+ */
+ 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)
{
@@ -602,12 +679,23 @@ static void malidp_de_plane_update(struct drm_plane *plane,
u8 plane_alpha = state->alpha >> 8;
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;
+ /*
+ * 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 = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+ }
+
dest_w = state->crtc_w;
dest_h = state->crtc_h;
@@ -615,15 +703,8 @@ static void malidp_de_plane_update(struct drm_plane *plane,
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 +738,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);
+
/* first clear the rotation bits */
val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
val &= ~LAYER_ROT_MASK;