aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2012-03-05 11:48:35 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-07 16:38:07 -0500
commitb33f34d3d10b9b00ca568740e7099da107d525b9 (patch)
treef63a9d59ae626af10018a38eb63b7f318c4a4800 /drivers/staging
parent9f18c95abba6dbfd13c86e0b8f3e7219df753f7e (diff)
staging: drm/omap: defer unpin until scanout completes
When flipping, defer unpinning until scanout completes, as indicated by the appropriate END_WIN irq. This also re-organizes things a bit, in replacing omap_fb_{pin,unpin} with omap_fb_replace(), to make it easier to add support for scanout synchronized DMM refill mode (flipping by just reprogramming DMM synchronized with DSS scanout). Signed-off-by: Rob Clark <rob@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/omapdrm/omap_drv.h5
-rw-r--r--drivers/staging/omapdrm/omap_fb.c84
-rw-r--r--drivers/staging/omapdrm/omap_plane.c136
3 files changed, 181 insertions, 44 deletions
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index a84547c2464..fe4766e27b9 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -101,8 +101,9 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
101struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, 101struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
102 struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); 102 struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
103struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p); 103struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
104int omap_framebuffer_pin(struct drm_framebuffer *fb); 104int omap_framebuffer_replace(struct drm_framebuffer *a,
105void omap_framebuffer_unpin(struct drm_framebuffer *fb); 105 struct drm_framebuffer *b, void *arg,
106 void (*unpin)(void *arg, struct drm_gem_object *bo));
106void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, 107void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
107 struct omap_overlay_info *info); 108 struct omap_overlay_info *info);
108struct drm_connector *omap_framebuffer_get_next_connector( 109struct drm_connector *omap_framebuffer_get_next_connector(
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 08e2e356b58..fcb248f4cb0 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -137,41 +137,6 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
137 .dirty = omap_framebuffer_dirty, 137 .dirty = omap_framebuffer_dirty,
138}; 138};
139 139
140/* pins buffer in preparation for scanout */
141int omap_framebuffer_pin(struct drm_framebuffer *fb)
142{
143 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
144 int ret, i, n = drm_format_num_planes(omap_fb->format->pixel_format);
145
146 for (i = 0; i < n; i++) {
147 struct plane *plane = &omap_fb->planes[i];
148 ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
149 if (ret)
150 goto fail;
151 }
152
153 return 0;
154
155fail:
156 while (--i > 0) {
157 struct plane *plane = &omap_fb->planes[i];
158 omap_gem_put_paddr(plane->bo);
159 }
160 return ret;
161}
162
163/* releases buffer when done with scanout */
164void omap_framebuffer_unpin(struct drm_framebuffer *fb)
165{
166 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
167 int i, n = drm_format_num_planes(omap_fb->format->pixel_format);
168
169 for (i = 0; i < n; i++) {
170 struct plane *plane = &omap_fb->planes[i];
171 omap_gem_put_paddr(plane->bo);
172 }
173}
174
175/* update ovl info for scanout, handles cases of multi-planar fb's, etc. 140/* update ovl info for scanout, handles cases of multi-planar fb's, etc.
176 */ 141 */
177void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, 142void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
@@ -201,6 +166,55 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
201 } 166 }
202} 167}
203 168
169/* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL). Although
170 * buffers to unpin are just just pushed to the unpin fifo so that the
171 * caller can defer unpin until vblank.
172 *
173 * Note if this fails (ie. something went very wrong!), all buffers are
174 * unpinned, and the caller disables the overlay. We could have tried
175 * to revert back to the previous set of pinned buffers but if things are
176 * hosed there is no guarantee that would succeed.
177 */
178int omap_framebuffer_replace(struct drm_framebuffer *a,
179 struct drm_framebuffer *b, void *arg,
180 void (*unpin)(void *arg, struct drm_gem_object *bo))
181{
182 int ret = 0, i, na, nb;
183 struct omap_framebuffer *ofba = to_omap_framebuffer(a);
184 struct omap_framebuffer *ofbb = to_omap_framebuffer(b);
185
186 na = a ? drm_format_num_planes(a->pixel_format) : 0;
187 nb = b ? drm_format_num_planes(b->pixel_format) : 0;
188
189 for (i = 0; i < max(na, nb); i++) {
190 struct plane *pa, *pb;
191
192 pa = (i < na) ? &ofba->planes[i] : NULL;
193 pb = (i < nb) ? &ofbb->planes[i] : NULL;
194
195 if (pa) {
196 unpin(arg, pa->bo);
197 pa->paddr = 0;
198 }
199
200 if (pb && !ret)
201 ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true);
202 }
203
204 if (ret) {
205 /* something went wrong.. unpin what has been pinned */
206 for (i = 0; i < nb; i++) {
207 struct plane *pb = &ofba->planes[i];
208 if (pb->paddr) {
209 unpin(arg, pb->bo);
210 pb->paddr = 0;
211 }
212 }
213 }
214
215 return ret;
216}
217
204struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p) 218struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p)
205{ 219{
206 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 220 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index c5625e3461b..55ddc580fe6 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -17,6 +17,8 @@
17 * this program. If not, see <http://www.gnu.org/licenses/>. 17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */ 18 */
19 19
20#include <linux/kfifo.h>
21
20#include "omap_drv.h" 22#include "omap_drv.h"
21 23
22/* some hackery because omapdss has an 'enum omap_plane' (which would be 24/* some hackery because omapdss has an 'enum omap_plane' (which would be
@@ -46,8 +48,57 @@ struct omap_plane {
46 48
47 uint32_t nformats; 49 uint32_t nformats;
48 uint32_t formats[32]; 50 uint32_t formats[32];
51
52 /* for synchronizing access to unpins fifo */
53 struct mutex unpin_mutex;
54
55 /* set of bo's pending unpin until next END_WIN irq */
56 DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *);
57 int num_unpins, pending_num_unpins;
58
59 /* for deferred unpin when we need to wait for scanout complete irq */
60 struct work_struct work;
61};
62
63/* map from ovl->id to the irq we are interested in for scanout-done */
64static const uint32_t id2irq[] = {
65 [OMAP_DSS_GFX] = DISPC_IRQ_GFX_END_WIN,
66 [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN,
67 [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN,
68 [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN,
49}; 69};
50 70
71static void dispc_isr(void *arg, uint32_t mask)
72{
73 struct drm_plane *plane = arg;
74 struct omap_plane *omap_plane = to_omap_plane(plane);
75 struct omap_drm_private *priv = plane->dev->dev_private;
76
77 omap_dispc_unregister_isr(dispc_isr, plane,
78 id2irq[omap_plane->ovl->id]);
79
80 queue_work(priv->wq, &omap_plane->work);
81}
82
83static void unpin_worker(struct work_struct *work)
84{
85 struct omap_plane *omap_plane =
86 container_of(work, struct omap_plane, work);
87
88 mutex_lock(&omap_plane->unpin_mutex);
89 DBG("unpinning %d of %d", omap_plane->num_unpins,
90 omap_plane->num_unpins + omap_plane->pending_num_unpins);
91 while (omap_plane->num_unpins > 0) {
92 struct drm_gem_object *bo = NULL;
93 int ret = kfifo_get(&omap_plane->unpin_fifo, &bo);
94 WARN_ON(!ret);
95 omap_gem_put_paddr(bo);
96 drm_gem_object_unreference_unlocked(bo);
97 omap_plane->num_unpins--;
98 }
99 mutex_unlock(&omap_plane->unpin_mutex);
100}
101
51/* push changes down to dss2 */ 102/* push changes down to dss2 */
52static int commit(struct drm_plane *plane) 103static int commit(struct drm_plane *plane)
53{ 104{
@@ -73,6 +124,11 @@ static int commit(struct drm_plane *plane)
73 return ret; 124 return ret;
74 } 125 }
75 126
127 mutex_lock(&omap_plane->unpin_mutex);
128 omap_plane->num_unpins += omap_plane->pending_num_unpins;
129 omap_plane->pending_num_unpins = 0;
130 mutex_unlock(&omap_plane->unpin_mutex);
131
76 /* our encoder doesn't necessarily get a commit() after this, in 132 /* our encoder doesn't necessarily get a commit() after this, in
77 * particular in the dpms() and mode_set_base() cases, so force the 133 * particular in the dpms() and mode_set_base() cases, so force the
78 * manager to update: 134 * manager to update:
@@ -85,8 +141,29 @@ static int commit(struct drm_plane *plane)
85 dev_err(dev->dev, "could not apply settings\n"); 141 dev_err(dev->dev, "could not apply settings\n");
86 return ret; 142 return ret;
87 } 143 }
144
145 /*
146 * NOTE: really this should be atomic w/ mgr->apply() but
147 * omapdss does not expose such an API
148 */
149 if (omap_plane->num_unpins > 0) {
150 ret = omap_dispc_register_isr(dispc_isr,
151 plane, id2irq[ovl->id]);
152 }
153
154 /*
155 * omapdss has upper limit on # of registered irq handlers,
156 * which we shouldn't hit.. but if we do the limit should
157 * be raised or bad things happen:
158 */
159 WARN_ON(ret == -EBUSY);
160
161 } else {
162 struct omap_drm_private *priv = dev->dev_private;
163 queue_work(priv->wq, &omap_plane->work);
88 } 164 }
89 165
166
90 if (ovl->is_enabled(ovl)) { 167 if (ovl->is_enabled(ovl)) {
91 omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, 168 omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
92 info->out_width, info->out_height); 169 info->out_width, info->out_height);
@@ -139,21 +216,48 @@ static void update_manager(struct drm_plane *plane)
139 } 216 }
140} 217}
141 218
219static void unpin(void *arg, struct drm_gem_object *bo)
220{
221 struct drm_plane *plane = arg;
222 struct omap_plane *omap_plane = to_omap_plane(plane);
223
224 if (kfifo_put(&omap_plane->unpin_fifo,
225 (const struct drm_gem_object **)&bo)) {
226 omap_plane->pending_num_unpins++;
227 /* also hold a ref so it isn't free'd while pinned */
228 drm_gem_object_reference(bo);
229 } else {
230 dev_err(plane->dev->dev, "unpin fifo full!\n");
231 omap_gem_put_paddr(bo);
232 }
233}
234
142/* update which fb (if any) is pinned for scanout */ 235/* update which fb (if any) is pinned for scanout */
143static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) 236static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
144{ 237{
145 struct omap_plane *omap_plane = to_omap_plane(plane); 238 struct omap_plane *omap_plane = to_omap_plane(plane);
146 int ret = 0; 239 struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb;
240
241 if (pinned_fb != fb) {
242 int ret;
243
244 DBG("%p -> %p", pinned_fb, fb);
245
246 mutex_lock(&omap_plane->unpin_mutex);
247 ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin);
248 mutex_unlock(&omap_plane->unpin_mutex);
249
250 if (ret) {
251 dev_err(plane->dev->dev, "could not swap %p -> %p\n",
252 omap_plane->pinned_fb, fb);
253 omap_plane->pinned_fb = NULL;
254 return ret;
255 }
147 256
148 if (omap_plane->pinned_fb != fb) {
149 if (omap_plane->pinned_fb)
150 omap_framebuffer_unpin(omap_plane->pinned_fb);
151 omap_plane->pinned_fb = fb; 257 omap_plane->pinned_fb = fb;
152 if (fb)
153 ret = omap_framebuffer_pin(fb);
154 } 258 }
155 259
156 return ret; 260 return 0;
157} 261}
158 262
159/* update parameters that are dependent on the framebuffer dimensions and 263/* update parameters that are dependent on the framebuffer dimensions and
@@ -243,6 +347,8 @@ static void omap_plane_destroy(struct drm_plane *plane)
243 DBG("%s", omap_plane->ovl->name); 347 DBG("%s", omap_plane->ovl->name);
244 omap_plane_disable(plane); 348 omap_plane_disable(plane);
245 drm_plane_cleanup(plane); 349 drm_plane_cleanup(plane);
350 WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0);
351 kfifo_free(&omap_plane->unpin_fifo);
246 kfree(omap_plane); 352 kfree(omap_plane);
247} 353}
248 354
@@ -260,8 +366,10 @@ int omap_plane_dpms(struct drm_plane *plane, int mode)
260 if (!r) 366 if (!r)
261 r = ovl->enable(ovl); 367 r = ovl->enable(ovl);
262 } else { 368 } else {
369 struct omap_drm_private *priv = plane->dev->dev_private;
263 r = ovl->disable(ovl); 370 r = ovl->disable(ovl);
264 update_pin(plane, NULL); 371 update_pin(plane, NULL);
372 queue_work(priv->wq, &omap_plane->work);
265 } 373 }
266 374
267 return r; 375 return r;
@@ -280,16 +388,30 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
280{ 388{
281 struct drm_plane *plane = NULL; 389 struct drm_plane *plane = NULL;
282 struct omap_plane *omap_plane; 390 struct omap_plane *omap_plane;
391 int ret;
283 392
284 DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name, 393 DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name,
285 possible_crtcs, priv); 394 possible_crtcs, priv);
286 395
396 /* friendly reminder to update table for future hw: */
397 WARN_ON(ovl->id >= ARRAY_SIZE(id2irq));
398
287 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 399 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
288 if (!omap_plane) { 400 if (!omap_plane) {
289 dev_err(dev->dev, "could not allocate plane\n"); 401 dev_err(dev->dev, "could not allocate plane\n");
290 goto fail; 402 goto fail;
291 } 403 }
292 404
405 mutex_init(&omap_plane->unpin_mutex);
406
407 ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL);
408 if (ret) {
409 dev_err(dev->dev, "could not allocate unpin FIFO\n");
410 goto fail;
411 }
412
413 INIT_WORK(&omap_plane->work, unpin_worker);
414
293 omap_plane->nformats = omap_framebuffer_get_formats( 415 omap_plane->nformats = omap_framebuffer_get_formats(
294 omap_plane->formats, ARRAY_SIZE(omap_plane->formats), 416 omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
295 ovl->supported_modes); 417 ovl->supported_modes);