Merge tag 'media/v4.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[deliverable/linux.git] / drivers / gpu / drm / exynos / exynos_drm_g2d.c
index 7584834a53c9b62a0538dab1244f9d57b3bdda3b..3734c34aed16a22938509454cf794e5b4069ac35 100644 (file)
 
 /* registers for base address */
 #define G2D_SRC_BASE_ADDR              0x0304
+#define G2D_SRC_STRIDE_REG             0x0308
 #define G2D_SRC_COLOR_MODE             0x030C
 #define G2D_SRC_LEFT_TOP               0x0310
 #define G2D_SRC_RIGHT_BOTTOM           0x0314
 #define G2D_SRC_PLANE2_BASE_ADDR       0x0318
 #define G2D_DST_BASE_ADDR              0x0404
+#define G2D_DST_STRIDE_REG             0x0408
 #define G2D_DST_COLOR_MODE             0x040C
 #define G2D_DST_LEFT_TOP               0x0410
 #define G2D_DST_RIGHT_BOTTOM           0x0414
@@ -148,6 +150,7 @@ struct g2d_cmdlist {
  * A structure of buffer description
  *
  * @format: color format
+ * @stride: buffer stride/pitch in bytes
  * @left_x: the x coordinates of left top corner
  * @top_y: the y coordinates of left top corner
  * @right_x: the x coordinates of right bottom corner
@@ -156,6 +159,7 @@ struct g2d_cmdlist {
  */
 struct g2d_buf_desc {
        unsigned int    format;
+       unsigned int    stride;
        unsigned int    left_x;
        unsigned int    top_y;
        unsigned int    right_x;
@@ -558,6 +562,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
 
        switch (reg_offset) {
        case G2D_SRC_BASE_ADDR:
+       case G2D_SRC_STRIDE_REG:
        case G2D_SRC_COLOR_MODE:
        case G2D_SRC_LEFT_TOP:
        case G2D_SRC_RIGHT_BOTTOM:
@@ -567,6 +572,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
                reg_type = REG_TYPE_SRC_PLANE2;
                break;
        case G2D_DST_BASE_ADDR:
+       case G2D_DST_STRIDE_REG:
        case G2D_DST_COLOR_MODE:
        case G2D_DST_LEFT_TOP:
        case G2D_DST_RIGHT_BOTTOM:
@@ -621,8 +627,8 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
                                                enum g2d_reg_type reg_type,
                                                unsigned long size)
 {
-       unsigned int width, height;
-       unsigned long area;
+       int width, height;
+       unsigned long bpp, last_pos;
 
        /*
         * check source and destination buffers only.
@@ -631,22 +637,37 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
        if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
                return true;
 
-       width = buf_desc->right_x - buf_desc->left_x;
+       /* This check also makes sure that right_x > left_x. */
+       width = (int)buf_desc->right_x - (int)buf_desc->left_x;
        if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
-               DRM_ERROR("width[%u] is out of range!\n", width);
+               DRM_ERROR("width[%d] is out of range!\n", width);
                return false;
        }
 
-       height = buf_desc->bottom_y - buf_desc->top_y;
+       /* This check also makes sure that bottom_y > top_y. */
+       height = (int)buf_desc->bottom_y - (int)buf_desc->top_y;
        if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
-               DRM_ERROR("height[%u] is out of range!\n", height);
+               DRM_ERROR("height[%d] is out of range!\n", height);
                return false;
        }
 
-       area = (unsigned long)width * (unsigned long)height *
-                                       g2d_get_buf_bpp(buf_desc->format);
-       if (area > size) {
-               DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size);
+       bpp = g2d_get_buf_bpp(buf_desc->format);
+
+       /* Compute the position of the last byte that the engine accesses. */
+       last_pos = ((unsigned long)buf_desc->bottom_y - 1) *
+               (unsigned long)buf_desc->stride +
+               (unsigned long)buf_desc->right_x * bpp - 1;
+
+       /*
+        * Since right_x > left_x and bottom_y > top_y we already know
+        * that the first_pos < last_pos (first_pos being the position
+        * of the first byte the engine accesses), it just remains to
+        * check if last_pos is smaller then the buffer size.
+        */
+
+       if (last_pos >= size) {
+               DRM_ERROR("last engine access position [%lu] "
+                       "is out of range [%lu]!\n", last_pos, size);
                return false;
        }
 
@@ -942,8 +963,6 @@ static int g2d_check_reg_offset(struct device *dev,
                                goto err;
 
                        reg_type = g2d_get_reg_type(reg_offset);
-                       if (reg_type == REG_TYPE_NONE)
-                               goto err;
 
                        /* check userptr buffer type. */
                        if ((cmdlist->data[index] & ~0x7fffffff) >> 31) {
@@ -952,14 +971,22 @@ static int g2d_check_reg_offset(struct device *dev,
                        } else
                                buf_info->types[reg_type] = BUF_TYPE_GEM;
                        break;
+               case G2D_SRC_STRIDE_REG:
+               case G2D_DST_STRIDE_REG:
+                       if (for_addr)
+                               goto err;
+
+                       reg_type = g2d_get_reg_type(reg_offset);
+
+                       buf_desc = &buf_info->descs[reg_type];
+                       buf_desc->stride = cmdlist->data[index + 1];
+                       break;
                case G2D_SRC_COLOR_MODE:
                case G2D_DST_COLOR_MODE:
                        if (for_addr)
                                goto err;
 
                        reg_type = g2d_get_reg_type(reg_offset);
-                       if (reg_type == REG_TYPE_NONE)
-                               goto err;
 
                        buf_desc = &buf_info->descs[reg_type];
                        value = cmdlist->data[index + 1];
@@ -972,8 +999,6 @@ static int g2d_check_reg_offset(struct device *dev,
                                goto err;
 
                        reg_type = g2d_get_reg_type(reg_offset);
-                       if (reg_type == REG_TYPE_NONE)
-                               goto err;
 
                        buf_desc = &buf_info->descs[reg_type];
                        value = cmdlist->data[index + 1];
@@ -987,8 +1012,6 @@ static int g2d_check_reg_offset(struct device *dev,
                                goto err;
 
                        reg_type = g2d_get_reg_type(reg_offset);
-                       if (reg_type == REG_TYPE_NONE)
-                               goto err;
 
                        buf_desc = &buf_info->descs[reg_type];
                        value = cmdlist->data[index + 1];
@@ -1288,9 +1311,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
                return ret;
        }
 
-       if (!is_drm_iommu_supported(drm_dev))
-               return 0;
-
        ret = drm_iommu_attach_device(drm_dev, dev);
        if (ret < 0) {
                dev_err(dev, "failed to enable iommu.\n");
@@ -1303,9 +1323,6 @@ static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 
 static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 {
-       if (!is_drm_iommu_supported(drm_dev))
-               return;
-
        drm_iommu_detach_device(drm_dev, dev);
 }
 
This page took 0.03073 seconds and 5 git commands to generate.