|
@@ -48,8 +48,14 @@
|
|
|
|
|
|
/* registers for base address */
|
|
/* registers for base address */
|
|
#define G2D_SRC_BASE_ADDR 0x0304
|
|
#define G2D_SRC_BASE_ADDR 0x0304
|
|
|
|
+#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_SRC_PLANE2_BASE_ADDR 0x0318
|
|
#define G2D_DST_BASE_ADDR 0x0404
|
|
#define G2D_DST_BASE_ADDR 0x0404
|
|
|
|
+#define G2D_DST_COLOR_MODE 0x040C
|
|
|
|
+#define G2D_DST_LEFT_TOP 0x0410
|
|
|
|
+#define G2D_DST_RIGHT_BOTTOM 0x0414
|
|
#define G2D_DST_PLANE2_BASE_ADDR 0x0418
|
|
#define G2D_DST_PLANE2_BASE_ADDR 0x0418
|
|
#define G2D_PAT_BASE_ADDR 0x0500
|
|
#define G2D_PAT_BASE_ADDR 0x0500
|
|
#define G2D_MSK_BASE_ADDR 0x0520
|
|
#define G2D_MSK_BASE_ADDR 0x0520
|
|
@@ -91,6 +97,22 @@
|
|
#define G2D_START_NHOLT (1 << 1)
|
|
#define G2D_START_NHOLT (1 << 1)
|
|
#define G2D_START_BITBLT (1 << 0)
|
|
#define G2D_START_BITBLT (1 << 0)
|
|
|
|
|
|
|
|
+/* buffer color format */
|
|
|
|
+#define G2D_FMT_XRGB8888 0
|
|
|
|
+#define G2D_FMT_ARGB8888 1
|
|
|
|
+#define G2D_FMT_RGB565 2
|
|
|
|
+#define G2D_FMT_XRGB1555 3
|
|
|
|
+#define G2D_FMT_ARGB1555 4
|
|
|
|
+#define G2D_FMT_XRGB4444 5
|
|
|
|
+#define G2D_FMT_ARGB4444 6
|
|
|
|
+#define G2D_FMT_PACKED_RGB888 7
|
|
|
|
+#define G2D_FMT_A8 11
|
|
|
|
+#define G2D_FMT_L8 12
|
|
|
|
+
|
|
|
|
+/* buffer valid length */
|
|
|
|
+#define G2D_LEN_MIN 1
|
|
|
|
+#define G2D_LEN_MAX 8000
|
|
|
|
+
|
|
#define G2D_CMDLIST_SIZE (PAGE_SIZE / 4)
|
|
#define G2D_CMDLIST_SIZE (PAGE_SIZE / 4)
|
|
#define G2D_CMDLIST_NUM 64
|
|
#define G2D_CMDLIST_NUM 64
|
|
#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
|
|
#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
|
|
@@ -122,6 +144,24 @@ struct g2d_cmdlist {
|
|
u32 last; /* last data offset */
|
|
u32 last; /* last data offset */
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * A structure of buffer description
|
|
|
|
+ *
|
|
|
|
+ * @format: color format
|
|
|
|
+ * @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
|
|
|
|
+ * @bottom_y: the y coordinates of right bottom corner
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+struct g2d_buf_desc {
|
|
|
|
+ unsigned int format;
|
|
|
|
+ unsigned int left_x;
|
|
|
|
+ unsigned int top_y;
|
|
|
|
+ unsigned int right_x;
|
|
|
|
+ unsigned int bottom_y;
|
|
|
|
+};
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* A structure of buffer information
|
|
* A structure of buffer information
|
|
*
|
|
*
|
|
@@ -129,6 +169,7 @@ struct g2d_cmdlist {
|
|
* @reg_types: stores regitster type in the order of requested command
|
|
* @reg_types: stores regitster type in the order of requested command
|
|
* @handles: stores buffer handle in its reg_type position
|
|
* @handles: stores buffer handle in its reg_type position
|
|
* @types: stores buffer type in its reg_type position
|
|
* @types: stores buffer type in its reg_type position
|
|
|
|
+ * @descs: stores buffer description in its reg_type position
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
struct g2d_buf_info {
|
|
struct g2d_buf_info {
|
|
@@ -136,6 +177,7 @@ struct g2d_buf_info {
|
|
enum g2d_reg_type reg_types[MAX_REG_TYPE_NR];
|
|
enum g2d_reg_type reg_types[MAX_REG_TYPE_NR];
|
|
unsigned long handles[MAX_REG_TYPE_NR];
|
|
unsigned long handles[MAX_REG_TYPE_NR];
|
|
unsigned int types[MAX_REG_TYPE_NR];
|
|
unsigned int types[MAX_REG_TYPE_NR];
|
|
|
|
+ struct g2d_buf_desc descs[MAX_REG_TYPE_NR];
|
|
};
|
|
};
|
|
|
|
|
|
struct drm_exynos_pending_g2d_event {
|
|
struct drm_exynos_pending_g2d_event {
|
|
@@ -543,12 +585,18 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
|
|
|
|
|
|
switch (reg_offset) {
|
|
switch (reg_offset) {
|
|
case G2D_SRC_BASE_ADDR:
|
|
case G2D_SRC_BASE_ADDR:
|
|
|
|
+ case G2D_SRC_COLOR_MODE:
|
|
|
|
+ case G2D_SRC_LEFT_TOP:
|
|
|
|
+ case G2D_SRC_RIGHT_BOTTOM:
|
|
reg_type = REG_TYPE_SRC;
|
|
reg_type = REG_TYPE_SRC;
|
|
break;
|
|
break;
|
|
case G2D_SRC_PLANE2_BASE_ADDR:
|
|
case G2D_SRC_PLANE2_BASE_ADDR:
|
|
reg_type = REG_TYPE_SRC_PLANE2;
|
|
reg_type = REG_TYPE_SRC_PLANE2;
|
|
break;
|
|
break;
|
|
case G2D_DST_BASE_ADDR:
|
|
case G2D_DST_BASE_ADDR:
|
|
|
|
+ case G2D_DST_COLOR_MODE:
|
|
|
|
+ case G2D_DST_LEFT_TOP:
|
|
|
|
+ case G2D_DST_RIGHT_BOTTOM:
|
|
reg_type = REG_TYPE_DST;
|
|
reg_type = REG_TYPE_DST;
|
|
break;
|
|
break;
|
|
case G2D_DST_PLANE2_BASE_ADDR:
|
|
case G2D_DST_PLANE2_BASE_ADDR:
|
|
@@ -569,6 +617,69 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
|
|
return reg_type;
|
|
return reg_type;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static unsigned long g2d_get_buf_bpp(unsigned int format)
|
|
|
|
+{
|
|
|
|
+ unsigned long bpp;
|
|
|
|
+
|
|
|
|
+ switch (format) {
|
|
|
|
+ case G2D_FMT_XRGB8888:
|
|
|
|
+ case G2D_FMT_ARGB8888:
|
|
|
|
+ bpp = 4;
|
|
|
|
+ break;
|
|
|
|
+ case G2D_FMT_RGB565:
|
|
|
|
+ case G2D_FMT_XRGB1555:
|
|
|
|
+ case G2D_FMT_ARGB1555:
|
|
|
|
+ case G2D_FMT_XRGB4444:
|
|
|
|
+ case G2D_FMT_ARGB4444:
|
|
|
|
+ bpp = 2;
|
|
|
|
+ break;
|
|
|
|
+ case G2D_FMT_PACKED_RGB888:
|
|
|
|
+ bpp = 3;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ bpp = 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return bpp;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * check source and destination buffers only.
|
|
|
|
+ * so the others are always valid.
|
|
|
|
+ */
|
|
|
|
+ if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ width = buf_desc->right_x - buf_desc->left_x;
|
|
|
|
+ if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
|
|
|
|
+ DRM_ERROR("width[%u] is out of range!\n", width);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ height = buf_desc->bottom_y - buf_desc->top_y;
|
|
|
|
+ if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
|
|
|
|
+ DRM_ERROR("height[%u] 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);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|
static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|
struct g2d_cmdlist_node *node,
|
|
struct g2d_cmdlist_node *node,
|
|
struct drm_device *drm_dev,
|
|
struct drm_device *drm_dev,
|
|
@@ -581,6 +692,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|
int i;
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < buf_info->map_nr; i++) {
|
|
for (i = 0; i < buf_info->map_nr; i++) {
|
|
|
|
+ struct g2d_buf_desc *buf_desc;
|
|
enum g2d_reg_type reg_type;
|
|
enum g2d_reg_type reg_type;
|
|
int reg_pos;
|
|
int reg_pos;
|
|
unsigned long handle;
|
|
unsigned long handle;
|
|
@@ -597,7 +709,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|
goto err;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ buf_desc = &buf_info->descs[reg_type];
|
|
|
|
+
|
|
if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
|
|
if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
|
|
|
|
+ unsigned long size;
|
|
|
|
+
|
|
|
|
+ size = exynos_drm_gem_get_size(drm_dev, handle, file);
|
|
|
|
+ if (!size) {
|
|
|
|
+ ret = -EFAULT;
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
|
|
|
|
+ size)) {
|
|
|
|
+ ret = -EFAULT;
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+
|
|
addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,
|
|
addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,
|
|
file);
|
|
file);
|
|
if (IS_ERR(addr)) {
|
|
if (IS_ERR(addr)) {
|
|
@@ -613,6 +741,12 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|
goto err;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
|
|
|
|
+ g2d_userptr.size)) {
|
|
|
|
+ ret = -EFAULT;
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+
|
|
addr = g2d_userptr_get_dma_addr(drm_dev,
|
|
addr = g2d_userptr_get_dma_addr(drm_dev,
|
|
g2d_userptr.userptr,
|
|
g2d_userptr.userptr,
|
|
g2d_userptr.size,
|
|
g2d_userptr.size,
|
|
@@ -645,11 +779,13 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
|
|
int i;
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < buf_info->map_nr; i++) {
|
|
for (i = 0; i < buf_info->map_nr; i++) {
|
|
|
|
+ struct g2d_buf_desc *buf_desc;
|
|
enum g2d_reg_type reg_type;
|
|
enum g2d_reg_type reg_type;
|
|
unsigned long handle;
|
|
unsigned long handle;
|
|
|
|
|
|
reg_type = buf_info->reg_types[i];
|
|
reg_type = buf_info->reg_types[i];
|
|
|
|
|
|
|
|
+ buf_desc = &buf_info->descs[reg_type];
|
|
handle = buf_info->handles[reg_type];
|
|
handle = buf_info->handles[reg_type];
|
|
|
|
|
|
if (buf_info->types[reg_type] == BUF_TYPE_GEM)
|
|
if (buf_info->types[reg_type] == BUF_TYPE_GEM)
|
|
@@ -662,6 +798,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
|
|
buf_info->reg_types[i] = REG_TYPE_NONE;
|
|
buf_info->reg_types[i] = REG_TYPE_NONE;
|
|
buf_info->handles[reg_type] = 0;
|
|
buf_info->handles[reg_type] = 0;
|
|
buf_info->types[reg_type] = 0;
|
|
buf_info->types[reg_type] = 0;
|
|
|
|
+ memset(buf_desc, 0x00, sizeof(*buf_desc));
|
|
}
|
|
}
|
|
|
|
|
|
buf_info->map_nr = 0;
|
|
buf_info->map_nr = 0;
|
|
@@ -808,7 +945,9 @@ static int g2d_check_reg_offset(struct device *dev,
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
for (i = 0; i < nr; i++) {
|
|
struct g2d_buf_info *buf_info = &node->buf_info;
|
|
struct g2d_buf_info *buf_info = &node->buf_info;
|
|
|
|
+ struct g2d_buf_desc *buf_desc;
|
|
enum g2d_reg_type reg_type;
|
|
enum g2d_reg_type reg_type;
|
|
|
|
+ unsigned long value;
|
|
|
|
|
|
index = cmdlist->last - 2 * (i + 1);
|
|
index = cmdlist->last - 2 * (i + 1);
|
|
|
|
|
|
@@ -839,6 +978,50 @@ static int g2d_check_reg_offset(struct device *dev,
|
|
} else
|
|
} else
|
|
buf_info->types[reg_type] = BUF_TYPE_GEM;
|
|
buf_info->types[reg_type] = BUF_TYPE_GEM;
|
|
break;
|
|
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];
|
|
|
|
+
|
|
|
|
+ buf_desc->format = value & 0xf;
|
|
|
|
+ break;
|
|
|
|
+ case G2D_SRC_LEFT_TOP:
|
|
|
|
+ case G2D_DST_LEFT_TOP:
|
|
|
|
+ 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];
|
|
|
|
+
|
|
|
|
+ buf_desc->left_x = value & 0x1fff;
|
|
|
|
+ buf_desc->top_y = (value & 0x1fff0000) >> 16;
|
|
|
|
+ break;
|
|
|
|
+ case G2D_SRC_RIGHT_BOTTOM:
|
|
|
|
+ case G2D_DST_RIGHT_BOTTOM:
|
|
|
|
+ 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];
|
|
|
|
+
|
|
|
|
+ buf_desc->right_x = value & 0x1fff;
|
|
|
|
+ buf_desc->bottom_y = (value & 0x1fff0000) >> 16;
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
if (for_addr)
|
|
if (for_addr)
|
|
goto err;
|
|
goto err;
|