aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Gaignard <benjamin.gaignard@linaro.org>2014-12-11 07:34:42 -0500
committerBenjamin Gaignard <benjamin.gaignard@linaro.org>2014-12-11 08:00:09 -0500
commit96006a770df80d69cbde4802e1e7cdfd70c510b3 (patch)
tree8f99791fa1a346effdff490dc880dd341cebca9a
parent5e03abc52cd16c852552f9eaae497c9d6e55e5d0 (diff)
drm: sti: add cursor plane
stih407 SoC have a dedicated hardware cursor plane, this patch enable it. The hardware have a color look up table, fix it to be able to use ARGB8888. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
-rw-r--r--drivers/gpu/drm/sti/Makefile1
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c8
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c242
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.h12
-rw-r--r--drivers/gpu/drm/sti/sti_layer.c5
-rw-r--r--drivers/gpu/drm/sti/sti_layer.h2
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c6
7 files changed, 273 insertions, 3 deletions
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile
index 04ac2ceef27f..d6128f7fa12c 100644
--- a/drivers/gpu/drm/sti/Makefile
+++ b/drivers/gpu/drm/sti/Makefile
@@ -3,6 +3,7 @@ sticompositor-y := \
3 sti_mixer.o \ 3 sti_mixer.o \
4 sti_gdp.o \ 4 sti_gdp.o \
5 sti_vid.o \ 5 sti_vid.o \
6 sti_cursor.o \
6 sti_compositor.o \ 7 sti_compositor.o \
7 sti_drm_crtc.o \ 8 sti_drm_crtc.o \
8 sti_drm_plane.o 9 sti_drm_plane.o
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index bbf8462879ce..b9415b3f3720 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -24,8 +24,9 @@
24 * stiH407 compositor properties 24 * stiH407 compositor properties
25 */ 25 */
26struct sti_compositor_data stih407_compositor_data = { 26struct sti_compositor_data stih407_compositor_data = {
27 .nb_subdev = 7, 27 .nb_subdev = 8,
28 .subdev_desc = { 28 .subdev_desc = {
29 {STI_CURSOR_SUBDEV, (int)STI_CURSOR, 0x000},
29 {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100}, 30 {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100},
30 {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200}, 31 {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
31 {STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300}, 32 {STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300},
@@ -68,11 +69,11 @@ static int sti_compositor_init_subdev(struct sti_compositor *compo,
68 break; 69 break;
69 case STI_GPD_SUBDEV: 70 case STI_GPD_SUBDEV:
70 case STI_VID_SUBDEV: 71 case STI_VID_SUBDEV:
72 case STI_CURSOR_SUBDEV:
71 compo->layer[layer_id++] = 73 compo->layer[layer_id++] =
72 sti_layer_create(compo->dev, desc[i].id, 74 sti_layer_create(compo->dev, desc[i].id,
73 compo->regs + desc[i].offset); 75 compo->regs + desc[i].offset);
74 break; 76 break;
75 /* case STI_CURSOR_SUBDEV : TODO */
76 default: 77 default:
77 DRM_ERROR("Unknow subdev compoment type\n"); 78 DRM_ERROR("Unknow subdev compoment type\n");
78 return 1; 79 return 1;
@@ -125,11 +126,12 @@ static int sti_compositor_bind(struct device *dev, struct device *master,
125 } 126 }
126 127
127 /* The first planes are reserved for primary planes*/ 128 /* The first planes are reserved for primary planes*/
128 if (crtc < compo->nb_mixers) { 129 if (crtc < compo->nb_mixers && primary) {
129 sti_drm_crtc_init(drm_dev, compo->mixer[crtc], 130 sti_drm_crtc_init(drm_dev, compo->mixer[crtc],
130 primary, cursor); 131 primary, cursor);
131 crtc++; 132 crtc++;
132 cursor = NULL; 133 cursor = NULL;
134 primary = NULL;
133 } 135 }
134 } 136 }
135 } 137 }
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
new file mode 100644
index 000000000000..010eaee60bf7
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -0,0 +1,242 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Vincent Abriou <vincent.abriou@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8#include <drm/drmP.h>
9
10#include "sti_cursor.h"
11#include "sti_layer.h"
12#include "sti_vtg.h"
13
14/* Registers */
15#define CUR_CTL 0x00
16#define CUR_VPO 0x0C
17#define CUR_PML 0x14
18#define CUR_PMP 0x18
19#define CUR_SIZE 0x1C
20#define CUR_CML 0x20
21#define CUR_AWS 0x28
22#define CUR_AWE 0x2C
23
24#define CUR_CTL_CLUT_UPDATE BIT(1)
25
26#define STI_CURS_MIN_SIZE 1
27#define STI_CURS_MAX_SIZE 128
28
29/*
30 * pixmap dma buffer stucture
31 *
32 * @paddr: physical address
33 * @size: buffer size
34 * @base: virtual address
35 */
36struct dma_pixmap {
37 dma_addr_t paddr;
38 size_t size;
39 void *base;
40};
41
42/**
43 * STI Cursor structure
44 *
45 * @layer: layer structure
46 * @width: cursor width
47 * @height: cursor height
48 * @clut: color look up table
49 * @clut_paddr: color look up table physical address
50 * @pixmap: pixmap dma buffer (clut8-format cursor)
51 */
52struct sti_cursor {
53 struct sti_layer layer;
54 unsigned int width;
55 unsigned int height;
56 unsigned short *clut;
57 dma_addr_t clut_paddr;
58 struct dma_pixmap pixmap;
59};
60
61static const uint32_t cursor_supported_formats[] = {
62 DRM_FORMAT_ARGB8888,
63};
64
65#define to_sti_cursor(x) container_of(x, struct sti_cursor, layer)
66
67static const uint32_t *sti_cursor_get_formats(struct sti_layer *layer)
68{
69 return cursor_supported_formats;
70}
71
72static unsigned int sti_cursor_get_nb_formats(struct sti_layer *layer)
73{
74 return ARRAY_SIZE(cursor_supported_formats);
75}
76
77static void sti_cursor_argb8888_to_clut8(struct sti_layer *layer)
78{
79 struct sti_cursor *cursor = to_sti_cursor(layer);
80 u32 *src = layer->vaddr;
81 u8 *dst = cursor->pixmap.base;
82 unsigned int i, j;
83 u32 a, r, g, b;
84
85 for (i = 0; i < cursor->height; i++) {
86 for (j = 0; j < cursor->width; j++) {
87 /* Pick the 2 higher bits of each component */
88 a = (*src >> 30) & 3;
89 r = (*src >> 22) & 3;
90 g = (*src >> 14) & 3;
91 b = (*src >> 6) & 3;
92 *dst = a << 6 | r << 4 | g << 2 | b;
93 src++;
94 dst++;
95 }
96 }
97}
98
99static int sti_cursor_prepare_layer(struct sti_layer *layer, bool first_prepare)
100{
101 struct sti_cursor *cursor = to_sti_cursor(layer);
102 struct drm_display_mode *mode = layer->mode;
103 u32 y, x;
104 u32 val;
105
106 DRM_DEBUG_DRIVER("\n");
107
108 dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
109
110 if (layer->src_w < STI_CURS_MIN_SIZE ||
111 layer->src_h < STI_CURS_MIN_SIZE ||
112 layer->src_w > STI_CURS_MAX_SIZE ||
113 layer->src_h > STI_CURS_MAX_SIZE) {
114 DRM_ERROR("Invalid cursor size (%dx%d)\n",
115 layer->src_w, layer->src_h);
116 return -EINVAL;
117 }
118
119 /* If the cursor size has changed, re-allocated the pixmap */
120 if (!cursor->pixmap.base ||
121 (cursor->width != layer->src_w) ||
122 (cursor->height != layer->src_h)) {
123 cursor->width = layer->src_w;
124 cursor->height = layer->src_h;
125
126 if (cursor->pixmap.base)
127 dma_free_writecombine(layer->dev,
128 cursor->pixmap.size,
129 cursor->pixmap.base,
130 cursor->pixmap.paddr);
131
132 cursor->pixmap.size = cursor->width * cursor->height;
133
134 cursor->pixmap.base = dma_alloc_writecombine(layer->dev,
135 cursor->pixmap.size,
136 &cursor->pixmap.paddr,
137 GFP_KERNEL | GFP_DMA);
138 if (!cursor->pixmap.base) {
139 DRM_ERROR("Failed to allocate memory for pixmap\n");
140 return -ENOMEM;
141 }
142 }
143
144 /* Convert ARGB8888 to CLUT8 */
145 sti_cursor_argb8888_to_clut8(layer);
146
147 /* AWS and AWE depend on the mode */
148 y = sti_vtg_get_line_number(*mode, 0);
149 x = sti_vtg_get_pixel_number(*mode, 0);
150 val = y << 16 | x;
151 writel(val, layer->regs + CUR_AWS);
152 y = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
153 x = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
154 val = y << 16 | x;
155 writel(val, layer->regs + CUR_AWE);
156
157 if (first_prepare) {
158 /* Set and fetch CLUT */
159 writel(cursor->clut_paddr, layer->regs + CUR_CML);
160 writel(CUR_CTL_CLUT_UPDATE, layer->regs + CUR_CTL);
161 }
162
163 return 0;
164}
165
166static int sti_cursor_commit_layer(struct sti_layer *layer)
167{
168 struct sti_cursor *cursor = to_sti_cursor(layer);
169 struct drm_display_mode *mode = layer->mode;
170 u32 ydo, xdo;
171
172 dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
173
174 /* Set memory location, size, and position */
175 writel(cursor->pixmap.paddr, layer->regs + CUR_PML);
176 writel(cursor->width, layer->regs + CUR_PMP);
177 writel(cursor->height << 16 | cursor->width, layer->regs + CUR_SIZE);
178
179 ydo = sti_vtg_get_line_number(*mode, layer->dst_y);
180 xdo = sti_vtg_get_pixel_number(*mode, layer->dst_y);
181 writel((ydo << 16) | xdo, layer->regs + CUR_VPO);
182
183 return 0;
184}
185
186static int sti_cursor_disable_layer(struct sti_layer *layer)
187{
188 return 0;
189}
190
191static void sti_cursor_init(struct sti_layer *layer)
192{
193 struct sti_cursor *cursor = to_sti_cursor(layer);
194 unsigned short *base = cursor->clut;
195 unsigned int a, r, g, b;
196
197 /* Assign CLUT values, ARGB444 format */
198 for (a = 0; a < 4; a++)
199 for (r = 0; r < 4; r++)
200 for (g = 0; g < 4; g++)
201 for (b = 0; b < 4; b++)
202 *base++ = (a * 5) << 12 |
203 (r * 5) << 8 |
204 (g * 5) << 4 |
205 (b * 5);
206}
207
208static const struct sti_layer_funcs cursor_ops = {
209 .get_formats = sti_cursor_get_formats,
210 .get_nb_formats = sti_cursor_get_nb_formats,
211 .init = sti_cursor_init,
212 .prepare = sti_cursor_prepare_layer,
213 .commit = sti_cursor_commit_layer,
214 .disable = sti_cursor_disable_layer,
215};
216
217struct sti_layer *sti_cursor_create(struct device *dev)
218{
219 struct sti_cursor *cursor;
220
221 cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
222 if (!cursor) {
223 DRM_ERROR("Failed to allocate memory for cursor\n");
224 return NULL;
225 }
226
227 /* Allocate clut buffer */
228 cursor->clut = dma_alloc_writecombine(dev,
229 0x100 * sizeof(unsigned short),
230 &cursor->clut_paddr,
231 GFP_KERNEL | GFP_DMA);
232
233 if (!cursor->clut) {
234 DRM_ERROR("Failed to allocate memory for cursor clut\n");
235 devm_kfree(dev, cursor);
236 return NULL;
237 }
238
239 cursor->layer.ops = &cursor_ops;
240
241 return (struct sti_layer *)cursor;
242}
diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h
new file mode 100644
index 000000000000..3c9827404f27
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_cursor.h
@@ -0,0 +1,12 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2013
3 * Authors: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_CURSOR_H_
8#define _STI_CURSOR_H_
9
10struct sti_layer *sti_cursor_create(struct device *dev);
11
12#endif
diff --git a/drivers/gpu/drm/sti/sti_layer.c b/drivers/gpu/drm/sti/sti_layer.c
index 06a587c4f1bb..5051b4cfc46b 100644
--- a/drivers/gpu/drm/sti/sti_layer.c
+++ b/drivers/gpu/drm/sti/sti_layer.c
@@ -11,6 +11,7 @@
11#include <drm/drm_fb_cma_helper.h> 11#include <drm/drm_fb_cma_helper.h>
12 12
13#include "sti_compositor.h" 13#include "sti_compositor.h"
14#include "sti_cursor.h"
14#include "sti_gdp.h" 15#include "sti_gdp.h"
15#include "sti_layer.h" 16#include "sti_layer.h"
16#include "sti_vid.h" 17#include "sti_vid.h"
@@ -50,6 +51,9 @@ struct sti_layer *sti_layer_create(struct device *dev, int desc,
50 case STI_VID: 51 case STI_VID:
51 layer = sti_vid_create(dev); 52 layer = sti_vid_create(dev);
52 break; 53 break;
54 case STI_CUR:
55 layer = sti_cursor_create(dev);
56 break;
53 } 57 }
54 58
55 if (!layer) { 59 if (!layer) {
@@ -100,6 +104,7 @@ int sti_layer_prepare(struct sti_layer *layer, struct drm_framebuffer *fb,
100 layer->src_w = src_w; 104 layer->src_w = src_w;
101 layer->src_h = src_h; 105 layer->src_h = src_h;
102 layer->format = fb->pixel_format; 106 layer->format = fb->pixel_format;
107 layer->vaddr = cma_obj->vaddr;
103 layer->paddr = cma_obj->paddr; 108 layer->paddr = cma_obj->paddr;
104 for (i = 0; i < 4; i++) { 109 for (i = 0; i < 4; i++) {
105 layer->pitches[i] = fb->pitches[i]; 110 layer->pitches[i] = fb->pitches[i];
diff --git a/drivers/gpu/drm/sti/sti_layer.h b/drivers/gpu/drm/sti/sti_layer.h
index 198c3774cc12..68bfdca4d738 100644
--- a/drivers/gpu/drm/sti/sti_layer.h
+++ b/drivers/gpu/drm/sti/sti_layer.h
@@ -82,6 +82,7 @@ struct sti_layer_funcs {
82 * @format: format 82 * @format: format
83 * @pitches: pitch of 'planes' (eg: Y, U, V) 83 * @pitches: pitch of 'planes' (eg: Y, U, V)
84 * @offsets: offset of 'planes' 84 * @offsets: offset of 'planes'
85 * @vaddr: virtual address of the input buffer
85 * @paddr: physical address of the input buffer 86 * @paddr: physical address of the input buffer
86 */ 87 */
87struct sti_layer { 88struct sti_layer {
@@ -102,6 +103,7 @@ struct sti_layer {
102 uint32_t format; 103 uint32_t format;
103 unsigned int pitches[4]; 104 unsigned int pitches[4];
104 unsigned int offsets[4]; 105 unsigned int offsets[4];
106 void *vaddr;
105 dma_addr_t paddr; 107 dma_addr_t paddr;
106}; 108};
107 109
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c
index 6bcdf3f86d22..9a4ce74ac329 100644
--- a/drivers/gpu/drm/sti/sti_mixer.c
+++ b/drivers/gpu/drm/sti/sti_mixer.c
@@ -45,6 +45,7 @@ static const u32 mixerColorSpaceMatIdentity[] = {
45#define GAM_CTL_GDP1_MASK BIT(4) 45#define GAM_CTL_GDP1_MASK BIT(4)
46#define GAM_CTL_GDP2_MASK BIT(5) 46#define GAM_CTL_GDP2_MASK BIT(5)
47#define GAM_CTL_GDP3_MASK BIT(6) 47#define GAM_CTL_GDP3_MASK BIT(6)
48#define GAM_CTL_CURSOR_MASK BIT(9)
48 49
49const char *sti_mixer_to_str(struct sti_mixer *mixer) 50const char *sti_mixer_to_str(struct sti_mixer *mixer)
50{ 51{
@@ -127,6 +128,9 @@ int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer)
127 case STI_VID_1: 128 case STI_VID_1:
128 layer_id = GAM_DEPTH_VID1_ID; 129 layer_id = GAM_DEPTH_VID1_ID;
129 break; 130 break;
131 case STI_CURSOR:
132 /* no need to set depth for cursor */
133 return 0;
130 default: 134 default:
131 DRM_ERROR("Unknown layer %d\n", layer->desc); 135 DRM_ERROR("Unknown layer %d\n", layer->desc);
132 return 1; 136 return 1;
@@ -188,6 +192,8 @@ static u32 sti_mixer_get_layer_mask(struct sti_layer *layer)
188 return GAM_CTL_VID0_MASK; 192 return GAM_CTL_VID0_MASK;
189 case STI_VID_1: 193 case STI_VID_1:
190 return GAM_CTL_VID1_MASK; 194 return GAM_CTL_VID1_MASK;
195 case STI_CURSOR:
196 return GAM_CTL_CURSOR_MASK;
191 default: 197 default:
192 return 0; 198 return 0;
193 } 199 }