aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 1a022dc4188e..47a493c8a71f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -48,8 +48,14 @@
48 48
49/* registers for base address */ 49/* registers for base address */
50#define G2D_SRC_BASE_ADDR 0x0304 50#define G2D_SRC_BASE_ADDR 0x0304
51#define G2D_SRC_COLOR_MODE 0x030C
52#define G2D_SRC_LEFT_TOP 0x0310
53#define G2D_SRC_RIGHT_BOTTOM 0x0314
51#define G2D_SRC_PLANE2_BASE_ADDR 0x0318 54#define G2D_SRC_PLANE2_BASE_ADDR 0x0318
52#define G2D_DST_BASE_ADDR 0x0404 55#define G2D_DST_BASE_ADDR 0x0404
56#define G2D_DST_COLOR_MODE 0x040C
57#define G2D_DST_LEFT_TOP 0x0410
58#define G2D_DST_RIGHT_BOTTOM 0x0414
53#define G2D_DST_PLANE2_BASE_ADDR 0x0418 59#define G2D_DST_PLANE2_BASE_ADDR 0x0418
54#define G2D_PAT_BASE_ADDR 0x0500 60#define G2D_PAT_BASE_ADDR 0x0500
55#define G2D_MSK_BASE_ADDR 0x0520 61#define G2D_MSK_BASE_ADDR 0x0520
@@ -91,6 +97,22 @@
91#define G2D_START_NHOLT (1 << 1) 97#define G2D_START_NHOLT (1 << 1)
92#define G2D_START_BITBLT (1 << 0) 98#define G2D_START_BITBLT (1 << 0)
93 99
100/* buffer color format */
101#define G2D_FMT_XRGB8888 0
102#define G2D_FMT_ARGB8888 1
103#define G2D_FMT_RGB565 2
104#define G2D_FMT_XRGB1555 3
105#define G2D_FMT_ARGB1555 4
106#define G2D_FMT_XRGB4444 5
107#define G2D_FMT_ARGB4444 6
108#define G2D_FMT_PACKED_RGB888 7
109#define G2D_FMT_A8 11
110#define G2D_FMT_L8 12
111
112/* buffer valid length */
113#define G2D_LEN_MIN 1
114#define G2D_LEN_MAX 8000
115
94#define G2D_CMDLIST_SIZE (PAGE_SIZE / 4) 116#define G2D_CMDLIST_SIZE (PAGE_SIZE / 4)
95#define G2D_CMDLIST_NUM 64 117#define G2D_CMDLIST_NUM 64
96#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) 118#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
@@ -123,12 +145,31 @@ struct g2d_cmdlist {
123}; 145};
124 146
125/* 147/*
148 * A structure of buffer description
149 *
150 * @format: color format
151 * @left_x: the x coordinates of left top corner
152 * @top_y: the y coordinates of left top corner
153 * @right_x: the x coordinates of right bottom corner
154 * @bottom_y: the y coordinates of right bottom corner
155 *
156 */
157struct g2d_buf_desc {
158 unsigned int format;
159 unsigned int left_x;
160 unsigned int top_y;
161 unsigned int right_x;
162 unsigned int bottom_y;
163};
164
165/*
126 * A structure of buffer information 166 * A structure of buffer information
127 * 167 *
128 * @map_nr: manages the number of mapped buffers 168 * @map_nr: manages the number of mapped buffers
129 * @reg_types: stores regitster type in the order of requested command 169 * @reg_types: stores regitster type in the order of requested command
130 * @handles: stores buffer handle in its reg_type position 170 * @handles: stores buffer handle in its reg_type position
131 * @types: stores buffer type in its reg_type position 171 * @types: stores buffer type in its reg_type position
172 * @descs: stores buffer description in its reg_type position
132 * 173 *
133 */ 174 */
134struct g2d_buf_info { 175struct g2d_buf_info {
@@ -136,6 +177,7 @@ struct g2d_buf_info {
136 enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; 177 enum g2d_reg_type reg_types[MAX_REG_TYPE_NR];
137 unsigned long handles[MAX_REG_TYPE_NR]; 178 unsigned long handles[MAX_REG_TYPE_NR];
138 unsigned int types[MAX_REG_TYPE_NR]; 179 unsigned int types[MAX_REG_TYPE_NR];
180 struct g2d_buf_desc descs[MAX_REG_TYPE_NR];
139}; 181};
140 182
141struct drm_exynos_pending_g2d_event { 183struct drm_exynos_pending_g2d_event {
@@ -543,12 +585,18 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
543 585
544 switch (reg_offset) { 586 switch (reg_offset) {
545 case G2D_SRC_BASE_ADDR: 587 case G2D_SRC_BASE_ADDR:
588 case G2D_SRC_COLOR_MODE:
589 case G2D_SRC_LEFT_TOP:
590 case G2D_SRC_RIGHT_BOTTOM:
546 reg_type = REG_TYPE_SRC; 591 reg_type = REG_TYPE_SRC;
547 break; 592 break;
548 case G2D_SRC_PLANE2_BASE_ADDR: 593 case G2D_SRC_PLANE2_BASE_ADDR:
549 reg_type = REG_TYPE_SRC_PLANE2; 594 reg_type = REG_TYPE_SRC_PLANE2;
550 break; 595 break;
551 case G2D_DST_BASE_ADDR: 596 case G2D_DST_BASE_ADDR:
597 case G2D_DST_COLOR_MODE:
598 case G2D_DST_LEFT_TOP:
599 case G2D_DST_RIGHT_BOTTOM:
552 reg_type = REG_TYPE_DST; 600 reg_type = REG_TYPE_DST;
553 break; 601 break;
554 case G2D_DST_PLANE2_BASE_ADDR: 602 case G2D_DST_PLANE2_BASE_ADDR:
@@ -569,6 +617,69 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
569 return reg_type; 617 return reg_type;
570} 618}
571 619
620static unsigned long g2d_get_buf_bpp(unsigned int format)
621{
622 unsigned long bpp;
623
624 switch (format) {
625 case G2D_FMT_XRGB8888:
626 case G2D_FMT_ARGB8888:
627 bpp = 4;
628 break;
629 case G2D_FMT_RGB565:
630 case G2D_FMT_XRGB1555:
631 case G2D_FMT_ARGB1555:
632 case G2D_FMT_XRGB4444:
633 case G2D_FMT_ARGB4444:
634 bpp = 2;
635 break;
636 case G2D_FMT_PACKED_RGB888:
637 bpp = 3;
638 break;
639 default:
640 bpp = 1;
641 break;
642 }
643
644 return bpp;
645}
646
647static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
648 enum g2d_reg_type reg_type,
649 unsigned long size)
650{
651 unsigned int width, height;
652 unsigned long area;
653
654 /*
655 * check source and destination buffers only.
656 * so the others are always valid.
657 */
658 if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
659 return true;
660
661 width = buf_desc->right_x - buf_desc->left_x;
662 if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
663 DRM_ERROR("width[%u] is out of range!\n", width);
664 return false;
665 }
666
667 height = buf_desc->bottom_y - buf_desc->top_y;
668 if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
669 DRM_ERROR("height[%u] is out of range!\n", height);
670 return false;
671 }
672
673 area = (unsigned long)width * (unsigned long)height *
674 g2d_get_buf_bpp(buf_desc->format);
675 if (area > size) {
676 DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size);
677 return false;
678 }
679
680 return true;
681}
682
572static int g2d_map_cmdlist_gem(struct g2d_data *g2d, 683static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
573 struct g2d_cmdlist_node *node, 684 struct g2d_cmdlist_node *node,
574 struct drm_device *drm_dev, 685 struct drm_device *drm_dev,
@@ -581,6 +692,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
581 int i; 692 int i;
582 693
583 for (i = 0; i < buf_info->map_nr; i++) { 694 for (i = 0; i < buf_info->map_nr; i++) {
695 struct g2d_buf_desc *buf_desc;
584 enum g2d_reg_type reg_type; 696 enum g2d_reg_type reg_type;
585 int reg_pos; 697 int reg_pos;
586 unsigned long handle; 698 unsigned long handle;
@@ -597,7 +709,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
597 goto err; 709 goto err;
598 } 710 }
599 711
712 buf_desc = &buf_info->descs[reg_type];
713
600 if (buf_info->types[reg_type] == BUF_TYPE_GEM) { 714 if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
715 unsigned long size;
716
717 size = exynos_drm_gem_get_size(drm_dev, handle, file);
718 if (!size) {
719 ret = -EFAULT;
720 goto err;
721 }
722
723 if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
724 size)) {
725 ret = -EFAULT;
726 goto err;
727 }
728
601 addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, 729 addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,
602 file); 730 file);
603 if (IS_ERR(addr)) { 731 if (IS_ERR(addr)) {
@@ -613,6 +741,12 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
613 goto err; 741 goto err;
614 } 742 }
615 743
744 if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
745 g2d_userptr.size)) {
746 ret = -EFAULT;
747 goto err;
748 }
749
616 addr = g2d_userptr_get_dma_addr(drm_dev, 750 addr = g2d_userptr_get_dma_addr(drm_dev,
617 g2d_userptr.userptr, 751 g2d_userptr.userptr,
618 g2d_userptr.size, 752 g2d_userptr.size,
@@ -645,11 +779,13 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
645 int i; 779 int i;
646 780
647 for (i = 0; i < buf_info->map_nr; i++) { 781 for (i = 0; i < buf_info->map_nr; i++) {
782 struct g2d_buf_desc *buf_desc;
648 enum g2d_reg_type reg_type; 783 enum g2d_reg_type reg_type;
649 unsigned long handle; 784 unsigned long handle;
650 785
651 reg_type = buf_info->reg_types[i]; 786 reg_type = buf_info->reg_types[i];
652 787
788 buf_desc = &buf_info->descs[reg_type];
653 handle = buf_info->handles[reg_type]; 789 handle = buf_info->handles[reg_type];
654 790
655 if (buf_info->types[reg_type] == BUF_TYPE_GEM) 791 if (buf_info->types[reg_type] == BUF_TYPE_GEM)
@@ -662,6 +798,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
662 buf_info->reg_types[i] = REG_TYPE_NONE; 798 buf_info->reg_types[i] = REG_TYPE_NONE;
663 buf_info->handles[reg_type] = 0; 799 buf_info->handles[reg_type] = 0;
664 buf_info->types[reg_type] = 0; 800 buf_info->types[reg_type] = 0;
801 memset(buf_desc, 0x00, sizeof(*buf_desc));
665 } 802 }
666 803
667 buf_info->map_nr = 0; 804 buf_info->map_nr = 0;
@@ -808,7 +945,9 @@ static int g2d_check_reg_offset(struct device *dev,
808 945
809 for (i = 0; i < nr; i++) { 946 for (i = 0; i < nr; i++) {
810 struct g2d_buf_info *buf_info = &node->buf_info; 947 struct g2d_buf_info *buf_info = &node->buf_info;
948 struct g2d_buf_desc *buf_desc;
811 enum g2d_reg_type reg_type; 949 enum g2d_reg_type reg_type;
950 unsigned long value;
812 951
813 index = cmdlist->last - 2 * (i + 1); 952 index = cmdlist->last - 2 * (i + 1);
814 953
@@ -839,6 +978,50 @@ static int g2d_check_reg_offset(struct device *dev,
839 } else 978 } else
840 buf_info->types[reg_type] = BUF_TYPE_GEM; 979 buf_info->types[reg_type] = BUF_TYPE_GEM;
841 break; 980 break;
981 case G2D_SRC_COLOR_MODE:
982 case G2D_DST_COLOR_MODE:
983 if (for_addr)
984 goto err;
985
986 reg_type = g2d_get_reg_type(reg_offset);
987 if (reg_type == REG_TYPE_NONE)
988 goto err;
989
990 buf_desc = &buf_info->descs[reg_type];
991 value = cmdlist->data[index + 1];
992
993 buf_desc->format = value & 0xf;
994 break;
995 case G2D_SRC_LEFT_TOP:
996 case G2D_DST_LEFT_TOP:
997 if (for_addr)
998 goto err;
999
1000 reg_type = g2d_get_reg_type(reg_offset);
1001 if (reg_type == REG_TYPE_NONE)
1002 goto err;
1003
1004 buf_desc = &buf_info->descs[reg_type];
1005 value = cmdlist->data[index + 1];
1006
1007 buf_desc->left_x = value & 0x1fff;
1008 buf_desc->top_y = (value & 0x1fff0000) >> 16;
1009 break;
1010 case G2D_SRC_RIGHT_BOTTOM:
1011 case G2D_DST_RIGHT_BOTTOM:
1012 if (for_addr)
1013 goto err;
1014
1015 reg_type = g2d_get_reg_type(reg_offset);
1016 if (reg_type == REG_TYPE_NONE)
1017 goto err;
1018
1019 buf_desc = &buf_info->descs[reg_type];
1020 value = cmdlist->data[index + 1];
1021
1022 buf_desc->right_x = value & 0x1fff;
1023 buf_desc->bottom_y = (value & 0x1fff0000) >> 16;
1024 break;
842 default: 1025 default:
843 if (for_addr) 1026 if (for_addr)
844 goto err; 1027 goto err;