]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - drivers/gpu/drm/vc4/vc4_plane.c
Merge drm/drm-next into drm-misc-next
[mirror_ubuntu-hirsute-kernel.git] / drivers / gpu / drm / vc4 / vc4_plane.c
index d040d9f12c6d769bd633f076236a5c769bc58a26..89543fa8ca4de2ad6bc2641a003763c91bdfb3b6 100644 (file)
@@ -32,45 +32,60 @@ static const struct hvs_format {
        u32 drm; /* DRM_FORMAT_* */
        u32 hvs; /* HVS_FORMAT_* */
        u32 pixel_order;
+       u32 pixel_order_hvs5;
 } hvs_formats[] = {
        {
-               .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_XRGB8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
        },
        {
-               .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_ARGB8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
        },
        {
-               .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_ABGR8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ARGB,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_XBGR8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ARGB,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
+               .drm = DRM_FORMAT_RGB565,
+               .hvs = HVS_PIXEL_FORMAT_RGB565,
                .pixel_order = HVS_PIXEL_ORDER_XRGB,
        },
        {
-               .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
+               .drm = DRM_FORMAT_BGR565,
+               .hvs = HVS_PIXEL_FORMAT_RGB565,
                .pixel_order = HVS_PIXEL_ORDER_XBGR,
        },
        {
-               .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
+               .drm = DRM_FORMAT_ARGB1555,
+               .hvs = HVS_PIXEL_FORMAT_RGBA5551,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
+               .drm = DRM_FORMAT_XRGB1555,
+               .hvs = HVS_PIXEL_FORMAT_RGBA5551,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
+               .drm = DRM_FORMAT_RGB888,
+               .hvs = HVS_PIXEL_FORMAT_RGB888,
                .pixel_order = HVS_PIXEL_ORDER_XRGB,
        },
        {
-               .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888,
+               .drm = DRM_FORMAT_BGR888,
+               .hvs = HVS_PIXEL_FORMAT_RGB888,
                .pixel_order = HVS_PIXEL_ORDER_XBGR,
        },
        {
@@ -422,10 +437,7 @@ static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
 static u32 vc4_lbm_size(struct drm_plane_state *state)
 {
        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
-       /* This is the worst case number.  One of the two sizes will
-        * be used depending on the scaling configuration.
-        */
-       u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
+       u32 pix_per_line;
        u32 lbm;
 
        /* LBM is not needed when there's no vertical scaling. */
@@ -433,6 +445,18 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
            vc4_state->y_scaling[1] == VC4_SCALING_NONE)
                return 0;
 
+       /*
+        * This can be further optimized in the RGB/YUV444 case if the PPF
+        * decimation factor is between 0.5 and 1.0 by using crtc_w.
+        *
+        * It's not an issue though, since in that case since src_w[0] is going
+        * to be greater than or equal to crtc_w.
+        */
+       if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ)
+               pix_per_line = vc4_state->crtc_w;
+       else
+               pix_per_line = vc4_state->src_w[0];
+
        if (!vc4_state->is_yuv) {
                if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
                        lbm = pix_per_line * 8;
@@ -492,6 +516,11 @@ static void vc4_plane_calc_load(struct drm_plane_state *state)
        struct vc4_plane_state *vc4_state;
        struct drm_crtc_state *crtc_state;
        unsigned int vscale_factor;
+       struct vc4_dev *vc4;
+
+       vc4 = to_vc4_dev(state->plane->dev);
+       if (!vc4->load_tracker_available)
+               return;
 
        vc4_state = to_vc4_plane_state(state);
        crtc_state = drm_atomic_get_existing_crtc_state(state->state,
@@ -563,7 +592,9 @@ static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
                spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
                ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
                                                 &vc4_state->lbm,
-                                                lbm_size, 32, 0, 0);
+                                                lbm_size,
+                                                vc4->hvs->hvs5 ? 64 : 32,
+                                                0, 0);
                spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
 
                if (ret)
@@ -776,35 +807,6 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                return -EINVAL;
        }
 
-       /* Control word */
-       vc4_dlist_write(vc4_state,
-                       SCALER_CTL0_VALID |
-                       (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
-                       (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
-                       VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
-                       (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
-                       (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
-                       VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
-                       (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
-                       VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
-                       VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
-
-       /* Position Word 0: Image Positions and Alpha Value */
-       vc4_state->pos0_offset = vc4_state->dlist_count;
-       vc4_dlist_write(vc4_state,
-                       VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
-                       VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
-                       VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
-
-       /* Position Word 1: Scaled Image Dimensions. */
-       if (!vc4_state->is_unity) {
-               vc4_dlist_write(vc4_state,
-                               VC4_SET_FIELD(vc4_state->crtc_w,
-                                             SCALER_POS1_SCL_WIDTH) |
-                               VC4_SET_FIELD(vc4_state->crtc_h,
-                                             SCALER_POS1_SCL_HEIGHT));
-       }
-
        /* Don't waste cycles mixing with plane alpha if the set alpha
         * is opaque or there is no per-pixel alpha information.
         * In any case we use the alpha property value as the fixed alpha.
@@ -812,20 +814,120 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
                          fb->format->has_alpha;
 
-       /* Position Word 2: Source Image Size, Alpha */
-       vc4_state->pos2_offset = vc4_state->dlist_count;
-       vc4_dlist_write(vc4_state,
-                       VC4_SET_FIELD(fb->format->has_alpha ?
-                                     SCALER_POS2_ALPHA_MODE_PIPELINE :
-                                     SCALER_POS2_ALPHA_MODE_FIXED,
-                                     SCALER_POS2_ALPHA_MODE) |
-                       (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
-                       (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) |
-                       VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
-                       VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
+       if (!vc4->hvs->hvs5) {
+       /* Control word */
+               vc4_dlist_write(vc4_state,
+                               SCALER_CTL0_VALID |
+                               (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
+                               (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
+                               VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
+                               (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+                               (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+                               VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
+                               (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
+                               VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
+                               VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
+
+               /* Position Word 0: Image Positions and Alpha Value */
+               vc4_state->pos0_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
+                               VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
+                               VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
 
-       /* Position Word 3: Context.  Written by the HVS. */
-       vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+               /* Position Word 1: Scaled Image Dimensions. */
+               if (!vc4_state->is_unity) {
+                       vc4_dlist_write(vc4_state,
+                                       VC4_SET_FIELD(vc4_state->crtc_w,
+                                                     SCALER_POS1_SCL_WIDTH) |
+                                       VC4_SET_FIELD(vc4_state->crtc_h,
+                                                     SCALER_POS1_SCL_HEIGHT));
+               }
+
+               /* Position Word 2: Source Image Size, Alpha */
+               vc4_state->pos2_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(fb->format->has_alpha ?
+                                             SCALER_POS2_ALPHA_MODE_PIPELINE :
+                                             SCALER_POS2_ALPHA_MODE_FIXED,
+                                             SCALER_POS2_ALPHA_MODE) |
+                               (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
+                               (fb->format->has_alpha ?
+                                               SCALER_POS2_ALPHA_PREMULT : 0) |
+                               VC4_SET_FIELD(vc4_state->src_w[0],
+                                             SCALER_POS2_WIDTH) |
+                               VC4_SET_FIELD(vc4_state->src_h[0],
+                                             SCALER_POS2_HEIGHT));
+
+               /* Position Word 3: Context.  Written by the HVS. */
+               vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+
+       } else {
+               u32 hvs_pixel_order = format->pixel_order;
+
+               if (format->pixel_order_hvs5)
+                       hvs_pixel_order = format->pixel_order_hvs5;
+
+               /* Control word */
+               vc4_dlist_write(vc4_state,
+                               SCALER_CTL0_VALID |
+                               (hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+                               (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+                               VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
+                               (vc4_state->is_unity ?
+                                               SCALER5_CTL0_UNITY : 0) |
+                               VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
+                               VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |
+                               SCALER5_CTL0_ALPHA_EXPAND |
+                               SCALER5_CTL0_RGB_EXPAND);
+
+               /* Position Word 0: Image Positions and Alpha Value */
+               vc4_state->pos0_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               (rotation & DRM_MODE_REFLECT_Y ?
+                                               SCALER5_POS0_VFLIP : 0) |
+                               VC4_SET_FIELD(vc4_state->crtc_x,
+                                             SCALER_POS0_START_X) |
+                               (rotation & DRM_MODE_REFLECT_X ?
+                                             SCALER5_POS0_HFLIP : 0) |
+                               VC4_SET_FIELD(vc4_state->crtc_y,
+                                             SCALER5_POS0_START_Y)
+                              );
+
+               /* Control Word 2 */
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(state->alpha >> 4,
+                                             SCALER5_CTL2_ALPHA) |
+                               (fb->format->has_alpha ?
+                                       SCALER5_CTL2_ALPHA_PREMULT : 0) |
+                               (mix_plane_alpha ?
+                                       SCALER5_CTL2_ALPHA_MIX : 0) |
+                               VC4_SET_FIELD(fb->format->has_alpha ?
+                                     SCALER5_CTL2_ALPHA_MODE_PIPELINE :
+                                     SCALER5_CTL2_ALPHA_MODE_FIXED,
+                                     SCALER5_CTL2_ALPHA_MODE)
+                              );
+
+               /* Position Word 1: Scaled Image Dimensions. */
+               if (!vc4_state->is_unity) {
+                       vc4_dlist_write(vc4_state,
+                                       VC4_SET_FIELD(vc4_state->crtc_w,
+                                                     SCALER_POS1_SCL_WIDTH) |
+                                       VC4_SET_FIELD(vc4_state->crtc_h,
+                                                     SCALER_POS1_SCL_HEIGHT));
+               }
+
+               /* Position Word 2: Source Image Size */
+               vc4_state->pos2_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(vc4_state->src_w[0],
+                                             SCALER5_POS2_WIDTH) |
+                               VC4_SET_FIELD(vc4_state->src_h[0],
+                                             SCALER5_POS2_HEIGHT));
+
+               /* Position Word 3: Context.  Written by the HVS. */
+               vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+       }
 
 
        /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
@@ -1203,6 +1305,10 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
                default:
                        return false;
                }
+       case DRM_FORMAT_RGBX1010102:
+       case DRM_FORMAT_BGRX1010102:
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_BGRA1010102:
        case DRM_FORMAT_YUV422:
        case DRM_FORMAT_YVU422:
        case DRM_FORMAT_YUV420:
@@ -1283,7 +1389,7 @@ int vc4_plane_create_additional_planes(struct drm_device *drm)
         * modest number of planes to expose, that should hopefully
         * still cover any sane usecase.
         */
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < 16; i++) {
                struct drm_plane *plane =
                        vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY);