Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 361747
b: refs/heads/master
c: 2dec17c
h: refs/heads/master
i:
  361745: 3705bb8
  361743: ef295b5
v: v3
  • Loading branch information
YoungJun Cho authored and Inki Dae committed Mar 20, 2013
1 parent 2fc0721 commit 8f6d695
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a4f19aaab3e69f9d15cc995e3378d27c8ef4f780
refs/heads/master: 2dec17c70e7567f226331c26d8daa0c16d3e7e6d
183 changes: 183 additions & 0 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_g2d.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,14 @@

/* registers for base address */
#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_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_PAT_BASE_ADDR 0x0500
#define G2D_MSK_BASE_ADDR 0x0520
Expand Down Expand Up @@ -91,6 +97,22 @@
#define G2D_START_NHOLT (1 << 1)
#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_NUM 64
#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
Expand Down Expand Up @@ -122,20 +144,40 @@ struct g2d_cmdlist {
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
*
* @map_nr: manages the number of mapped buffers
* @reg_types: stores regitster type in the order of requested command
* @handles: stores buffer handle 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 {
unsigned int map_nr;
enum g2d_reg_type reg_types[MAX_REG_TYPE_NR];
unsigned long handles[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 {
Expand Down Expand Up @@ -543,12 +585,18 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)

switch (reg_offset) {
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;
break;
case G2D_SRC_PLANE2_BASE_ADDR:
reg_type = REG_TYPE_SRC_PLANE2;
break;
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;
break;
case G2D_DST_PLANE2_BASE_ADDR:
Expand All @@ -569,6 +617,69 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
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,
struct g2d_cmdlist_node *node,
struct drm_device *drm_dev,
Expand All @@ -581,6 +692,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
int i;

for (i = 0; i < buf_info->map_nr; i++) {
struct g2d_buf_desc *buf_desc;
enum g2d_reg_type reg_type;
int reg_pos;
unsigned long handle;
Expand All @@ -597,7 +709,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
goto err;
}

buf_desc = &buf_info->descs[reg_type];

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,
file);
if (IS_ERR(addr)) {
Expand All @@ -613,6 +741,12 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
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,
g2d_userptr.userptr,
g2d_userptr.size,
Expand Down Expand Up @@ -645,11 +779,13 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
int i;

for (i = 0; i < buf_info->map_nr; i++) {
struct g2d_buf_desc *buf_desc;
enum g2d_reg_type reg_type;
unsigned long handle;

reg_type = buf_info->reg_types[i];

buf_desc = &buf_info->descs[reg_type];
handle = buf_info->handles[reg_type];

if (buf_info->types[reg_type] == BUF_TYPE_GEM)
Expand All @@ -662,6 +798,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
buf_info->reg_types[i] = REG_TYPE_NONE;
buf_info->handles[reg_type] = 0;
buf_info->types[reg_type] = 0;
memset(buf_desc, 0x00, sizeof(*buf_desc));
}

buf_info->map_nr = 0;
Expand Down Expand Up @@ -808,7 +945,9 @@ static int g2d_check_reg_offset(struct device *dev,

for (i = 0; i < nr; i++) {
struct g2d_buf_info *buf_info = &node->buf_info;
struct g2d_buf_desc *buf_desc;
enum g2d_reg_type reg_type;
unsigned long value;

index = cmdlist->last - 2 * (i + 1);

Expand Down Expand Up @@ -839,6 +978,50 @@ static int g2d_check_reg_offset(struct device *dev,
} else
buf_info->types[reg_type] = BUF_TYPE_GEM;
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:
if (for_addr)
goto err;
Expand Down

0 comments on commit 8f6d695

Please sign in to comment.