aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2012-01-16 13:51:17 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-08 17:14:11 -0500
commit9a0774e0991c82a95ef5e5848b318bd15aba0dcd (patch)
tree4dc77726aefdda5dd3c48eaf1f026d92322f9276
parentbb5c2d9aaaa26a55e684c175c431df95aa178233 (diff)
staging: drm/omap: multiplanar and YUV support
Add support in framebuffer objects for other color formats and multi- planar YUV (NV12). Since this requires changing the API between the plane and fb for getting scanout information (paddr, etc), take advantage of the opportunity and put in place a way to allow fb's to be unpinned when they are not being scanned out. Now, before start of scanout the plane calls omap_framebuffer_pin() which takes care to pin all the backing bo's, then omap_framebuffer_update_scanout() however many times to update the scanout address(es), etc, and then when finished omap_framebuffer_unpin(). Signed-off-by: Rob Clark <rob@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/omapdrm/omap_crtc.c2
-rw-r--r--drivers/staging/omapdrm/omap_drv.h8
-rw-r--r--drivers/staging/omapdrm/omap_fb.c149
-rw-r--r--drivers/staging/omapdrm/omap_gem.c5
-rw-r--r--drivers/staging/omapdrm/omap_plane.c53
5 files changed, 149 insertions, 68 deletions
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index a91c78898019..3cee04edcec8 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -168,7 +168,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
168 omap_crtc->event = event; 168 omap_crtc->event = event;
169 crtc->fb = fb; 169 crtc->fb = fb;
170 170
171 omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ, 171 omap_gem_op_async(omap_framebuffer_bo(fb, 0), OMAP_GEM_READ,
172 page_flip_cb, crtc); 172 page_flip_cb, crtc);
173 173
174 return 0; 174 return 0;
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index e2b1b553e8b6..48f6fce614b6 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -90,9 +90,11 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
90 struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd); 90 struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
91struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, 91struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
92 struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); 92 struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
93struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb); 93struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
94int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y, 94int omap_framebuffer_pin(struct drm_framebuffer *fb);
95 void **vaddr, dma_addr_t *paddr, unsigned int *screen_width); 95void omap_framebuffer_unpin(struct drm_framebuffer *fb);
96void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
97 struct omap_overlay_info *info);
96struct drm_connector *omap_framebuffer_get_next_connector( 98struct drm_connector *omap_framebuffer_get_next_connector(
97 struct drm_framebuffer *fb, struct drm_connector *from); 99 struct drm_framebuffer *fb, struct drm_connector *from);
98void omap_framebuffer_flush(struct drm_framebuffer *fb, 100void omap_framebuffer_flush(struct drm_framebuffer *fb,
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 805a18e559c4..d021a7ec58df 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -59,14 +59,20 @@ static const struct format formats[] = {
59 { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true }, 59 { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true },
60}; 60};
61 61
62/* per-plane info for the fb: */
63struct plane {
64 struct drm_gem_object *bo;
65 uint32_t pitch;
66 uint32_t offset;
67 dma_addr_t paddr;
68};
69
62#define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base) 70#define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base)
63 71
64struct omap_framebuffer { 72struct omap_framebuffer {
65 struct drm_framebuffer base; 73 struct drm_framebuffer base;
66 struct drm_gem_object *bo;
67 int size;
68 dma_addr_t paddr;
69 const struct format *format; 74 const struct format *format;
75 struct plane planes[4];
70}; 76};
71 77
72static int omap_framebuffer_create_handle(struct drm_framebuffer *fb, 78static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
@@ -74,22 +80,23 @@ static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
74 unsigned int *handle) 80 unsigned int *handle)
75{ 81{
76 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 82 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
77 return drm_gem_handle_create(file_priv, omap_fb->bo, handle); 83 return drm_gem_handle_create(file_priv,
84 omap_fb->planes[0].bo, handle);
78} 85}
79 86
80static void omap_framebuffer_destroy(struct drm_framebuffer *fb) 87static void omap_framebuffer_destroy(struct drm_framebuffer *fb)
81{ 88{
82 struct drm_device *dev = fb->dev;
83 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 89 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
90 int i, n = drm_format_num_planes(omap_fb->format->pixel_format);
84 91
85 DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); 92 DBG("destroy: FB ID: %d (%p)", fb->base.id, fb);
86 93
87 drm_framebuffer_cleanup(fb); 94 drm_framebuffer_cleanup(fb);
88 95
89 if (omap_fb->bo) { 96 for (i = 0; i < n; i++) {
90 if (omap_fb->paddr && omap_gem_put_paddr(omap_fb->bo)) 97 struct plane *plane = &omap_fb->planes[i];
91 dev_err(dev->dev, "could not unmap!\n"); 98 if (plane->bo)
92 drm_gem_object_unreference_unlocked(omap_fb->bo); 99 drm_gem_object_unreference_unlocked(plane->bo);
93 } 100 }
94 101
95 kfree(omap_fb); 102 kfree(omap_fb);
@@ -116,37 +123,76 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
116 .dirty = omap_framebuffer_dirty, 123 .dirty = omap_framebuffer_dirty,
117}; 124};
118 125
119/* returns the buffer size */ 126/* pins buffer in preparation for scanout */
120int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y, 127int omap_framebuffer_pin(struct drm_framebuffer *fb)
121 void **vaddr, dma_addr_t *paddr, unsigned int *screen_width)
122{ 128{
123 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 129 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
124 int bpp = fb->bits_per_pixel / 8; 130 int ret, i, n = drm_format_num_planes(omap_fb->format->pixel_format);
125 unsigned long offset; 131
126 132 for (i = 0; i < n; i++) {
127 offset = (x * bpp) + (y * fb->pitches[0]); 133 struct plane *plane = &omap_fb->planes[i];
128 134 ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
129 if (vaddr) { 135 if (ret)
130 void *bo_vaddr = omap_gem_vaddr(omap_fb->bo); 136 goto fail;
131 /* note: we can only count on having a vaddr for buffers that
132 * are allocated physically contiguously to begin with (ie.
133 * dma_alloc_coherent()). But this should be ok because it
134 * is only used by legacy fbdev
135 */
136 BUG_ON(IS_ERR_OR_NULL(bo_vaddr));
137 *vaddr = bo_vaddr + offset;
138 } 137 }
139 138
140 *paddr = omap_fb->paddr + offset; 139 return 0;
141 *screen_width = fb->pitches[0] / bpp;
142 140
143 return omap_fb->size - offset; 141fail:
142 while (--i > 0) {
143 struct plane *plane = &omap_fb->planes[i];
144 omap_gem_put_paddr(plane->bo);
145 }
146 return ret;
144} 147}
145 148
146struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb) 149/* releases buffer when done with scanout */
150void omap_framebuffer_unpin(struct drm_framebuffer *fb)
147{ 151{
148 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 152 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
149 return omap_fb->bo; 153 int i, n = drm_format_num_planes(omap_fb->format->pixel_format);
154
155 for (i = 0; i < n; i++) {
156 struct plane *plane = &omap_fb->planes[i];
157 omap_gem_put_paddr(plane->bo);
158 }
159}
160
161/* update ovl info for scanout, handles cases of multi-planar fb's, etc.
162 */
163void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
164 struct omap_overlay_info *info)
165{
166 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
167 const struct format *format = omap_fb->format;
168 struct plane *plane = &omap_fb->planes[0];
169 unsigned int offset;
170
171 offset = plane->offset +
172 (x * format->planes[0].stride_bpp) +
173 (y * plane->pitch / format->planes[0].sub_y);
174
175 info->color_mode = format->dss_format;
176 info->paddr = plane->paddr + offset;
177 info->screen_width = plane->pitch / format->planes[0].stride_bpp;
178
179 if (format->dss_format == OMAP_DSS_COLOR_NV12) {
180 plane = &omap_fb->planes[1];
181 offset = plane->offset +
182 (x * format->planes[1].stride_bpp) +
183 (y * plane->pitch / format->planes[1].sub_y);
184 info->p_uv_addr = plane->paddr + offset;
185 } else {
186 info->p_uv_addr = 0;
187 }
188}
189
190struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p)
191{
192 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
193 if (p >= drm_format_num_planes(omap_fb->format->pixel_format))
194 return NULL;
195 return omap_fb->planes[p].bo;
150} 196}
151 197
152/* iterate thru all the connectors, returning ones that are attached 198/* iterate thru all the connectors, returning ones that are attached
@@ -231,7 +277,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
231 struct omap_framebuffer *omap_fb; 277 struct omap_framebuffer *omap_fb;
232 struct drm_framebuffer *fb = NULL; 278 struct drm_framebuffer *fb = NULL;
233 const struct format *format = NULL; 279 const struct format *format = NULL;
234 int i, size, ret; 280 int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
235 281
236 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", 282 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
237 dev, mode_cmd, mode_cmd->width, mode_cmd->height, 283 dev, mode_cmd, mode_cmd->width, mode_cmd->height,
@@ -251,10 +297,6 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
251 goto fail; 297 goto fail;
252 } 298 }
253 299
254 /* in case someone tries to feed us a completely bogus stride: */
255 mode_cmd->pitches[0] = align_pitch(mode_cmd->pitches[0],
256 mode_cmd->width, format->planes[0].stride_bpp);
257
258 omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL); 300 omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL);
259 if (!omap_fb) { 301 if (!omap_fb) {
260 dev_err(dev->dev, "could not allocate fb\n"); 302 dev_err(dev->dev, "could not allocate fb\n");
@@ -271,21 +313,32 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
271 313
272 DBG("create: FB ID: %d (%p)", fb->base.id, fb); 314 DBG("create: FB ID: %d (%p)", fb->base.id, fb);
273 315
274 size = PAGE_ALIGN(mode_cmd->pitches[0] * mode_cmd->height); 316 omap_fb->format = format;
275 317
276 if (size > bos[0]->size) { 318 for (i = 0; i < n; i++) {
277 dev_err(dev->dev, "provided buffer object is too small!\n"); 319 struct plane *plane = &omap_fb->planes[i];
278 ret = -EINVAL; 320 int size, pitch = mode_cmd->pitches[i];
279 goto fail;
280 }
281 321
282 omap_fb->bo = bos[0]; 322 if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) {
283 omap_fb->size = size; 323 dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n",
324 pitch, mode_cmd->width * format->planes[i].stride_bpp);
325 ret = -EINVAL;
326 goto fail;
327 }
284 328
285 ret = omap_gem_get_paddr(bos[0], &omap_fb->paddr, true); 329 size = pitch * mode_cmd->height / format->planes[i].sub_y;
286 if (ret) { 330
287 dev_err(dev->dev, "could not map (paddr)!\n"); 331 if (size > (bos[i]->size - mode_cmd->offsets[i])) {
288 goto fail; 332 dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
333 bos[i]->size - mode_cmd->offsets[i], size);
334 ret = -EINVAL;
335 goto fail;
336 }
337
338 plane->bo = bos[i];
339 plane->offset = mode_cmd->offsets[i];
340 plane->pitch = mode_cmd->pitches[i];
341 plane->paddr = pitch;
289 } 342 }
290 343
291 drm_helper_mode_fill_fb_struct(fb, mode_cmd); 344 drm_helper_mode_fill_fb_struct(fb, mode_cmd);
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index e0ebd1d139f6..ae1ad357f7f2 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -1034,6 +1034,11 @@ void omap_gem_free_object(struct drm_gem_object *obj)
1034 drm_gem_free_mmap_offset(obj); 1034 drm_gem_free_mmap_offset(obj);
1035 } 1035 }
1036 1036
1037 /* this means the object is still pinned.. which really should
1038 * not happen. I think..
1039 */
1040 WARN_ON(omap_obj->paddr_cnt > 0);
1041
1037 /* don't free externally allocated backing memory */ 1042 /* don't free externally allocated backing memory */
1038 if (!(omap_obj->flags & OMAP_BO_EXT_MEM)) { 1043 if (!(omap_obj->flags & OMAP_BO_EXT_MEM)) {
1039 if (omap_obj->pages) { 1044 if (omap_obj->pages) {
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index a1d948c45ab6..66eed75e634d 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -40,6 +40,9 @@ struct omap_plane {
40 * fractional positions: 40 * fractional positions:
41 */ 41 */
42 unsigned int src_x, src_y; 42 unsigned int src_x, src_y;
43
44 /* last fb that we pinned: */
45 struct drm_framebuffer *pinned_fb;
43}; 46};
44 47
45 48
@@ -55,7 +58,8 @@ static int commit(struct drm_plane *plane)
55 DBG("%s", ovl->name); 58 DBG("%s", ovl->name);
56 DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width, 59 DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
57 info->out_height, info->screen_width); 60 info->out_height, info->screen_width);
58 DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr); 61 DBG("%d,%d %08x %08x", info->pos_x, info->pos_y,
62 info->paddr, info->p_uv_addr);
59 63
60 /* NOTE: do we want to do this at all here, or just wait 64 /* NOTE: do we want to do this at all here, or just wait
61 * for dpms(ON) since other CRTC's may not have their mode 65 * for dpms(ON) since other CRTC's may not have their mode
@@ -133,6 +137,23 @@ static void update_manager(struct drm_plane *plane)
133 } 137 }
134} 138}
135 139
140/* update which fb (if any) is pinned for scanout */
141static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
142{
143 struct omap_plane *omap_plane = to_omap_plane(plane);
144 int ret = 0;
145
146 if (omap_plane->pinned_fb != fb) {
147 if (omap_plane->pinned_fb)
148 omap_framebuffer_unpin(omap_plane->pinned_fb);
149 omap_plane->pinned_fb = fb;
150 if (fb)
151 ret = omap_framebuffer_pin(fb);
152 }
153
154 return ret;
155}
156
136/* update parameters that are dependent on the framebuffer dimensions and 157/* update parameters that are dependent on the framebuffer dimensions and
137 * position within the fb that this plane scans out from. This is called 158 * position within the fb that this plane scans out from. This is called
138 * when framebuffer or x,y base may have changed. 159 * when framebuffer or x,y base may have changed.
@@ -140,19 +161,23 @@ static void update_manager(struct drm_plane *plane)
140static void update_scanout(struct drm_plane *plane) 161static void update_scanout(struct drm_plane *plane)
141{ 162{
142 struct omap_plane *omap_plane = to_omap_plane(plane); 163 struct omap_plane *omap_plane = to_omap_plane(plane);
143 unsigned int screen_width; /* really means "pitch" */ 164 struct omap_overlay_info *info = &omap_plane->info;
144 dma_addr_t paddr; 165 int ret;
145 166
146 omap_framebuffer_get_buffer(plane->fb, 167 ret = update_pin(plane, plane->fb);
147 omap_plane->src_x, omap_plane->src_y, 168 if (ret) {
148 NULL, &paddr, &screen_width); 169 dev_err(plane->dev->dev,
170 "could not pin fb: %d\n", ret);
171 omap_plane->info.enabled = false;
172 }
149 173
150 DBG("%s: %d,%d: %08x (%d)", omap_plane->ovl->name, 174 omap_framebuffer_update_scanout(plane->fb,
151 omap_plane->src_x, omap_plane->src_y, 175 omap_plane->src_x, omap_plane->src_y, info);
152 (u32)paddr, screen_width);
153 176
154 omap_plane->info.paddr = paddr; 177 DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name,
155 omap_plane->info.screen_width = screen_width; 178 omap_plane->src_x, omap_plane->src_y,
179 (u32)info->paddr, (u32)info->p_uv_addr,
180 info->screen_width);
156} 181}
157 182
158static int omap_plane_update(struct drm_plane *plane, 183static int omap_plane_update(struct drm_plane *plane,
@@ -219,6 +244,7 @@ int omap_plane_dpms(struct drm_plane *plane, int mode)
219 omap_plane->info.enabled = true; 244 omap_plane->info.enabled = true;
220 } else { 245 } else {
221 omap_plane->info.enabled = false; 246 omap_plane->info.enabled = false;
247 update_pin(plane, NULL);
222 } 248 }
223 249
224 return commit(plane); 250 return commit(plane);
@@ -291,11 +317,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
291 else 317 else
292 omap_plane->info.zorder = 1; 318 omap_plane->info.zorder = 1;
293 319
294 /* TODO color mode should come from fb.. this will come in a
295 * subsequent patch
296 */
297 omap_plane->info.color_mode = OMAP_DSS_COLOR_RGB24U;
298
299 update_manager(plane); 320 update_manager(plane);
300 321
301 return plane; 322 return plane;