Merge tag 'drm-next-2018-08-15' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.git] / drivers / gpu / drm / vc4 / vc4_plane.c
index a951ec7..cfb50fe 100644 (file)
@@ -470,12 +470,14 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        struct drm_framebuffer *fb = state->fb;
        u32 ctl0_offset = vc4_state->dlist_count;
        const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
+       u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
        int num_planes = drm_format_num_planes(format->drm);
        bool mix_plane_alpha;
        bool covers_screen;
        u32 scl0, scl1, pitch0;
        u32 lbm_size, tiling;
        unsigned long irqflags;
+       u32 hvs_format = format->hvs;
        int ret, i;
 
        ret = vc4_plane_setup_clipping_and_scaling(state);
@@ -515,7 +517,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                scl1 = vc4_get_scl_field(state, 0);
        }
 
-       switch (fb->modifier) {
+       switch (base_format_mod) {
        case DRM_FORMAT_MOD_LINEAR:
                tiling = SCALER_CTL0_TILING_LINEAR;
                pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
@@ -538,6 +540,49 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                break;
        }
 
+       case DRM_FORMAT_MOD_BROADCOM_SAND64:
+       case DRM_FORMAT_MOD_BROADCOM_SAND128:
+       case DRM_FORMAT_MOD_BROADCOM_SAND256: {
+               uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
+
+               /* Column-based NV12 or RGBA.
+                */
+               if (fb->format->num_planes > 1) {
+                       if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) {
+                               DRM_DEBUG_KMS("SAND format only valid for NV12/21");
+                               return -EINVAL;
+                       }
+                       hvs_format = HVS_PIXEL_FORMAT_H264;
+               } else {
+                       if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) {
+                               DRM_DEBUG_KMS("SAND256 format only valid for H.264");
+                               return -EINVAL;
+                       }
+               }
+
+               switch (base_format_mod) {
+               case DRM_FORMAT_MOD_BROADCOM_SAND64:
+                       tiling = SCALER_CTL0_TILING_64B;
+                       break;
+               case DRM_FORMAT_MOD_BROADCOM_SAND128:
+                       tiling = SCALER_CTL0_TILING_128B;
+                       break;
+               case DRM_FORMAT_MOD_BROADCOM_SAND256:
+                       tiling = SCALER_CTL0_TILING_256B_OR_T;
+                       break;
+               default:
+                       break;
+               }
+
+               if (param > SCALER_TILE_HEIGHT_MASK) {
+                       DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
+                       return -EINVAL;
+               }
+
+               pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
+               break;
+       }
+
        default:
                DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
                              (long long)fb->modifier);
@@ -547,8 +592,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        /* Control word */
        vc4_dlist_write(vc4_state,
                        SCALER_CTL0_VALID |
+                       VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
                        (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
-                       (format->hvs << SCALER_CTL0_PIXEL_FORMAT_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) |
@@ -610,8 +656,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
 
        /* Pitch word 1/2 */
        for (i = 1; i < num_planes; i++) {
-               vc4_dlist_write(vc4_state,
-                               VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
+               if (hvs_format != HVS_PIXEL_FORMAT_H264) {
+                       vc4_dlist_write(vc4_state,
+                                       VC4_SET_FIELD(fb->pitches[i],
+                                                     SCALER_SRC_PITCH));
+               } else {
+                       vc4_dlist_write(vc4_state, pitch0);
+               }
        }
 
        /* Colorspace conversion words */
@@ -813,18 +864,21 @@ static int vc4_prepare_fb(struct drm_plane *plane,
        struct dma_fence *fence;
        int ret;
 
-       if ((plane->state->fb == state->fb) || !state->fb)
+       if (!state->fb)
                return 0;
 
        bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
 
+       fence = reservation_object_get_excl_rcu(bo->resv);
+       drm_atomic_set_fence_for_plane(state, fence);
+
+       if (plane->state->fb == state->fb)
+               return 0;
+
        ret = vc4_bo_inc_usecnt(bo);
        if (ret)
                return ret;
 
-       fence = reservation_object_get_excl_rcu(bo->resv);
-       drm_atomic_set_fence_for_plane(state, fence);
-
        return 0;
 }
 
@@ -851,7 +905,7 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
 
 static void vc4_plane_destroy(struct drm_plane *plane)
 {
-       drm_plane_helper_disable(plane);
+       drm_plane_helper_disable(plane, NULL);
        drm_plane_cleanup(plane);
 }
 
@@ -869,13 +923,32 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
        case DRM_FORMAT_BGR565:
        case DRM_FORMAT_ARGB1555:
        case DRM_FORMAT_XRGB1555:
-               return true;
+               switch (fourcc_mod_broadcom_mod(modifier)) {
+               case DRM_FORMAT_MOD_LINEAR:
+               case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+               case DRM_FORMAT_MOD_BROADCOM_SAND64:
+               case DRM_FORMAT_MOD_BROADCOM_SAND128:
+                       return true;
+               default:
+                       return false;
+               }
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+               switch (fourcc_mod_broadcom_mod(modifier)) {
+               case DRM_FORMAT_MOD_LINEAR:
+               case DRM_FORMAT_MOD_BROADCOM_SAND64:
+               case DRM_FORMAT_MOD_BROADCOM_SAND128:
+               case DRM_FORMAT_MOD_BROADCOM_SAND256:
+                       return true;
+               default:
+                       return false;
+               }
        case DRM_FORMAT_YUV422:
        case DRM_FORMAT_YVU422:
        case DRM_FORMAT_YUV420:
        case DRM_FORMAT_YVU420:
-       case DRM_FORMAT_NV12:
        case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
        default:
                return (modifier == DRM_FORMAT_MOD_LINEAR);
        }
@@ -903,6 +976,9 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
        unsigned i;
        static const uint64_t modifiers[] = {
                DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
+               DRM_FORMAT_MOD_BROADCOM_SAND128,
+               DRM_FORMAT_MOD_BROADCOM_SAND64,
+               DRM_FORMAT_MOD_BROADCOM_SAND256,
                DRM_FORMAT_MOD_LINEAR,
                DRM_FORMAT_MOD_INVALID
        };