| From 8d9c4a0ac852d5877e731c70f7a04bff6c4e992b Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 4 Dec 2020 14:34:29 -0800 |
| Subject: drm/kmb: Enable alpha blended second plane |
| |
| From: Edmund Dea <edmund.j.dea@intel.com> |
| |
| [ Upstream commit c026565fe9be813fe826f7e5533ed763283af5f0 ] |
| |
| Enable one additional plane that is alpha blended on top |
| of the primary plane. |
| |
| This also fixes the below warnings when building with |
| -Warray-bounds: |
| |
| drivers/gpu/drm/kmb/kmb_plane.c:135:20: warning: array subscript 3 is |
| above array bounds of 'struct layer_status[1]' [-Warray-bounds] |
| drivers/gpu/drm/kmb/kmb_plane.c:132:20: warning: array subscript 2 is |
| above array bounds of 'struct layer_status[1]' [-Warray-bounds] |
| drivers/gpu/drm/kmb/kmb_plane.c:129:20: warning: array subscript 1 is |
| above array bounds of 'struct layer_status[1]' [-Warray-bounds] |
| |
| v2: corrected previous patch dependecies so it builds |
| |
| Signed-off-by: Edmund Dea <edmund.j.dea@intel.com> |
| Signed-off-by: Anitha Chrisanthus <anitha.chrisanthus@intel.com> |
| Acked-by: Sam Ravnborg <sam@ravnborg.org> |
| Link: https://patchwork.kernel.org/project/dri-devel/patch/20210728003126.1425028-13-anitha.chrisanthus@intel.com/ |
| Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/gpu/drm/kmb/kmb_drv.c | 8 ++-- |
| drivers/gpu/drm/kmb/kmb_drv.h | 5 ++ |
| drivers/gpu/drm/kmb/kmb_plane.c | 81 +++++++++++++++++++++++++++++---- |
| drivers/gpu/drm/kmb/kmb_plane.h | 5 +- |
| drivers/gpu/drm/kmb/kmb_regs.h | 3 ++ |
| 5 files changed, 87 insertions(+), 15 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c |
| index bb7eca9e13ae..d3091bf38cc0 100644 |
| --- a/drivers/gpu/drm/kmb/kmb_drv.c |
| +++ b/drivers/gpu/drm/kmb/kmb_drv.c |
| @@ -173,10 +173,10 @@ static int kmb_setup_mode_config(struct drm_device *drm) |
| ret = drmm_mode_config_init(drm); |
| if (ret) |
| return ret; |
| - drm->mode_config.min_width = KMB_MIN_WIDTH; |
| - drm->mode_config.min_height = KMB_MIN_HEIGHT; |
| - drm->mode_config.max_width = KMB_MAX_WIDTH; |
| - drm->mode_config.max_height = KMB_MAX_HEIGHT; |
| + drm->mode_config.min_width = KMB_FB_MIN_WIDTH; |
| + drm->mode_config.min_height = KMB_FB_MIN_HEIGHT; |
| + drm->mode_config.max_width = KMB_FB_MAX_WIDTH; |
| + drm->mode_config.max_height = KMB_FB_MAX_HEIGHT; |
| drm->mode_config.funcs = &kmb_mode_config_funcs; |
| |
| ret = kmb_setup_crtc(drm); |
| diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h |
| index 178aa14f2efc..5869890b8fc7 100644 |
| --- a/drivers/gpu/drm/kmb/kmb_drv.h |
| +++ b/drivers/gpu/drm/kmb/kmb_drv.h |
| @@ -20,6 +20,11 @@ |
| #define DRIVER_MAJOR 1 |
| #define DRIVER_MINOR 1 |
| |
| +#define KMB_FB_MAX_WIDTH 1920 |
| +#define KMB_FB_MAX_HEIGHT 1080 |
| +#define KMB_FB_MIN_WIDTH 1 |
| +#define KMB_FB_MIN_HEIGHT 1 |
| + |
| #define KMB_LCD_DEFAULT_CLK 200000000 |
| #define KMB_SYS_CLK_MHZ 500 |
| |
| diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c |
| index 45cb096455b5..00404ba4126d 100644 |
| --- a/drivers/gpu/drm/kmb/kmb_plane.c |
| +++ b/drivers/gpu/drm/kmb/kmb_plane.c |
| @@ -113,9 +113,10 @@ static int kmb_plane_atomic_check(struct drm_plane *plane, |
| if (ret) |
| return ret; |
| |
| - if (new_plane_state->crtc_w > KMB_MAX_WIDTH || new_plane_state->crtc_h > KMB_MAX_HEIGHT) |
| - return -EINVAL; |
| - if (new_plane_state->crtc_w < KMB_MIN_WIDTH || new_plane_state->crtc_h < KMB_MIN_HEIGHT) |
| + if (new_plane_state->crtc_w > KMB_FB_MAX_WIDTH || |
| + new_plane_state->crtc_h > KMB_FB_MAX_HEIGHT || |
| + new_plane_state->crtc_w < KMB_FB_MIN_WIDTH || |
| + new_plane_state->crtc_h < KMB_FB_MIN_HEIGHT) |
| return -EINVAL; |
| |
| /* Due to HW limitations, changing plane height or width after |
| @@ -306,6 +307,44 @@ static void config_csc(struct kmb_drm_private *kmb, int plane_id) |
| kmb_write_lcd(kmb, LCD_LAYERn_CSC_OFF3(plane_id), csc_coef_lcd[11]); |
| } |
| |
| +static void kmb_plane_set_alpha(struct kmb_drm_private *kmb, |
| + const struct drm_plane_state *state, |
| + unsigned char plane_id, |
| + unsigned int *val) |
| +{ |
| + u16 plane_alpha = state->alpha; |
| + u16 pixel_blend_mode = state->pixel_blend_mode; |
| + int has_alpha = state->fb->format->has_alpha; |
| + |
| + if (plane_alpha != DRM_BLEND_ALPHA_OPAQUE) |
| + *val |= LCD_LAYER_ALPHA_STATIC; |
| + |
| + if (has_alpha) { |
| + switch (pixel_blend_mode) { |
| + case DRM_MODE_BLEND_PIXEL_NONE: |
| + break; |
| + case DRM_MODE_BLEND_PREMULTI: |
| + *val |= LCD_LAYER_ALPHA_EMBED | LCD_LAYER_ALPHA_PREMULT; |
| + break; |
| + case DRM_MODE_BLEND_COVERAGE: |
| + *val |= LCD_LAYER_ALPHA_EMBED; |
| + break; |
| + default: |
| + DRM_DEBUG("Missing pixel blend mode case (%s == %ld)\n", |
| + __stringify(pixel_blend_mode), |
| + (long)pixel_blend_mode); |
| + break; |
| + } |
| + } |
| + |
| + if (plane_alpha == DRM_BLEND_ALPHA_OPAQUE && !has_alpha) { |
| + *val &= LCD_LAYER_ALPHA_DISABLED; |
| + return; |
| + } |
| + |
| + kmb_write_lcd(kmb, LCD_LAYERn_ALPHA(plane_id), plane_alpha); |
| +} |
| + |
| static void kmb_plane_atomic_update(struct drm_plane *plane, |
| struct drm_atomic_state *state) |
| { |
| @@ -333,11 +372,12 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, |
| fb = new_plane_state->fb; |
| if (!fb) |
| return; |
| + |
| num_planes = fb->format->num_planes; |
| kmb_plane = to_kmb_plane(plane); |
| - plane_id = kmb_plane->id; |
| |
| kmb = to_kmb(plane->dev); |
| + plane_id = kmb_plane->id; |
| |
| spin_lock_irq(&kmb->irq_lock); |
| if (kmb->kmb_under_flow || kmb->kmb_flush_done) { |
| @@ -431,20 +471,32 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, |
| config_csc(kmb, plane_id); |
| } |
| |
| + kmb_plane_set_alpha(kmb, plane->state, plane_id, &val); |
| + |
| kmb_write_lcd(kmb, LCD_LAYERn_CFG(plane_id), val); |
| |
| + /* Configure LCD_CONTROL */ |
| + ctrl = kmb_read_lcd(kmb, LCD_CONTROL); |
| + |
| + /* Set layer blending config */ |
| + ctrl &= ~LCD_CTRL_ALPHA_ALL; |
| + ctrl |= LCD_CTRL_ALPHA_BOTTOM_VL1 | |
| + LCD_CTRL_ALPHA_BLEND_VL2; |
| + |
| + ctrl &= ~LCD_CTRL_ALPHA_BLEND_BKGND_DISABLE; |
| + |
| switch (plane_id) { |
| case LAYER_0: |
| - ctrl = LCD_CTRL_VL1_ENABLE; |
| + ctrl |= LCD_CTRL_VL1_ENABLE; |
| break; |
| case LAYER_1: |
| - ctrl = LCD_CTRL_VL2_ENABLE; |
| + ctrl |= LCD_CTRL_VL2_ENABLE; |
| break; |
| case LAYER_2: |
| - ctrl = LCD_CTRL_GL1_ENABLE; |
| + ctrl |= LCD_CTRL_GL1_ENABLE; |
| break; |
| case LAYER_3: |
| - ctrl = LCD_CTRL_GL2_ENABLE; |
| + ctrl |= LCD_CTRL_GL2_ENABLE; |
| break; |
| } |
| |
| @@ -456,7 +508,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, |
| */ |
| ctrl |= LCD_CTRL_VHSYNC_IDLE_LVL; |
| |
| - kmb_set_bitmask_lcd(kmb, LCD_CONTROL, ctrl); |
| + kmb_write_lcd(kmb, LCD_CONTROL, ctrl); |
| |
| /* Enable pipeline AXI read transactions for the DMA |
| * after setting graphics layers. This must be done |
| @@ -531,6 +583,9 @@ struct kmb_plane *kmb_plane_init(struct drm_device *drm) |
| enum drm_plane_type plane_type; |
| const u32 *plane_formats; |
| int num_plane_formats; |
| + unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | |
| + BIT(DRM_MODE_BLEND_PREMULTI) | |
| + BIT(DRM_MODE_BLEND_COVERAGE); |
| |
| for (i = 0; i < KMB_MAX_PLANES; i++) { |
| plane = drmm_kzalloc(drm, sizeof(*plane), GFP_KERNEL); |
| @@ -562,8 +617,16 @@ struct kmb_plane *kmb_plane_init(struct drm_device *drm) |
| drm_dbg(drm, "%s : %d i=%d type=%d", |
| __func__, __LINE__, |
| i, plane_type); |
| + drm_plane_create_alpha_property(&plane->base_plane); |
| + |
| + drm_plane_create_blend_mode_property(&plane->base_plane, |
| + blend_caps); |
| + |
| + drm_plane_create_zpos_immutable_property(&plane->base_plane, i); |
| + |
| drm_plane_helper_add(&plane->base_plane, |
| &kmb_plane_helper_funcs); |
| + |
| if (plane_type == DRM_PLANE_TYPE_PRIMARY) { |
| primary = plane; |
| kmb->plane = plane; |
| diff --git a/drivers/gpu/drm/kmb/kmb_plane.h b/drivers/gpu/drm/kmb/kmb_plane.h |
| index 99207b35365c..b51144044fe8 100644 |
| --- a/drivers/gpu/drm/kmb/kmb_plane.h |
| +++ b/drivers/gpu/drm/kmb/kmb_plane.h |
| @@ -35,6 +35,9 @@ |
| #define POSSIBLE_CRTCS 1 |
| #define to_kmb_plane(x) container_of(x, struct kmb_plane, base_plane) |
| |
| +#define POSSIBLE_CRTCS 1 |
| +#define KMB_MAX_PLANES 2 |
| + |
| enum layer_id { |
| LAYER_0, |
| LAYER_1, |
| @@ -43,8 +46,6 @@ enum layer_id { |
| /* KMB_MAX_PLANES */ |
| }; |
| |
| -#define KMB_MAX_PLANES 1 |
| - |
| enum sub_plane_id { |
| Y_PLANE, |
| U_PLANE, |
| diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h |
| index 48150569f702..9756101b0d32 100644 |
| --- a/drivers/gpu/drm/kmb/kmb_regs.h |
| +++ b/drivers/gpu/drm/kmb/kmb_regs.h |
| @@ -43,8 +43,10 @@ |
| #define LCD_CTRL_OUTPUT_ENABLED BIT(19) |
| #define LCD_CTRL_BPORCH_ENABLE BIT(21) |
| #define LCD_CTRL_FPORCH_ENABLE BIT(22) |
| +#define LCD_CTRL_ALPHA_BLEND_BKGND_DISABLE BIT(23) |
| #define LCD_CTRL_PIPELINE_DMA BIT(28) |
| #define LCD_CTRL_VHSYNC_IDLE_LVL BIT(31) |
| +#define LCD_CTRL_ALPHA_ALL (0xff << 6) |
| |
| /* interrupts */ |
| #define LCD_INT_STATUS (0x4 * 0x001) |
| @@ -115,6 +117,7 @@ |
| #define LCD_LAYER_ALPHA_EMBED BIT(5) |
| #define LCD_LAYER_ALPHA_COMBI (LCD_LAYER_ALPHA_STATIC | \ |
| LCD_LAYER_ALPHA_EMBED) |
| +#define LCD_LAYER_ALPHA_DISABLED ~(LCD_LAYER_ALPHA_COMBI) |
| /* RGB multiplied with alpha */ |
| #define LCD_LAYER_ALPHA_PREMULT BIT(6) |
| #define LCD_LAYER_INVERT_COL BIT(7) |
| -- |
| 2.33.0 |
| |