aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchit Taneja <archit@ti.com>2012-11-07 04:17:22 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-11-12 06:52:59 -0500
commit02b5ff1a96af7fab8db602677c220c0a35b1f687 (patch)
treefa965208d134dcbf12bee86e72b5dd245c257103
parent6be0d73e2a5de2e6a2570a48e6e11bbc4563f5e3 (diff)
OMAPDSS: APPLY: Don't treat an overlay's channel out as shadow bits
An overlay's channel out field isn't a shadow register. The TRM says that it's taken into effect immediately. This understanding was missing and channel out was treated as a shadow parameter, and in overlay's private data as extra info. Program channel out bits directly in dss_ovl_set_manager(). In order to do this safely, we need to be totally sure that the overlay is disabled in hardware. For auto update managers, we can assume that the overlay was truly disabled at dss_ovl_unset_manager() through the wait_pending_extra_info_updates() call. However, when unsetting manager for an overlay that was previously connected to a manager in manual update, we can't be sure if the overlay is truly disabled. That is, op->enabled might not reflect the actual state of the overlay in hardware. The older manager may require a manual update transfer to truly disable the overlay. We expect the user of OMAPDSS to take care of this, in OMAPDSS, we make sure that an overlay's manager isn't unset if there if extra_info is still dirty for that overlay. The wrong understanding of channel out bits also explains the reason why we see sync lost when changing an overlay's manager which was previously connected to a manual update manager. The following sequence of events caused this: - When we disable the overlay, no register writes are actually done since the manager is manual update, op->enabled is set to false, and the extra_info_dirty flag is set. However, in hardware, the overlay is still enabled in both shadow and working registers. - When we unset the manager, the software just configures the overlay's manager to point to NULL. - When we set the overlay to a new manager(which is in auto update) through dss_ovl_set_manager, the check for op->enabled passes, the channel field in extra info is set to the new manager. When we do an apply on this manager, the new channel out field is set in the hardware immediately, and since the overlay enable bit is still set in hardware, the new manager sees that the overlay is enabled, and tries to retrieve pixels from it, this leads to sync lost as it might be in the middle of processing a frame when we set the channel out bit. The solution to this was to ensure that user space does another update after disabling the overlay, this actually worked because the overlay was now truly disabled, and an immediate write to channel out didn't impact since the manager saw the new overlay as disabled, and doesn't try to retrieve pixels from it. Remove channel as an extra_info field. Make dss_ovl_unset_manager more strict about the overlay being disabled when detaching the manager. For overlays connected to a manual update manager, unset_manager fails if we need another update to disable the overlay. We still need to a manual update to ensure the overlay is disabled to get change the overlay's manager. We could work on doing a dummy update by using DISPC's capability to gate the different video port signals. This is left for later. Remove the comment about the sync lost issue. Signed-off-by: Archit Taneja <archit@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r--drivers/video/omap2/dss/apply.c44
1 files changed, 26 insertions, 18 deletions
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 8d9521609150..ecac6b6e5a8d 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -70,7 +70,6 @@ struct ovl_priv_data {
70 bool shadow_extra_info_dirty; 70 bool shadow_extra_info_dirty;
71 71
72 bool enabled; 72 bool enabled;
73 enum omap_channel channel;
74 u32 fifo_low, fifo_high; 73 u32 fifo_low, fifo_high;
75 74
76 /* 75 /*
@@ -615,7 +614,6 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
615 * disabled */ 614 * disabled */
616 615
617 dispc_ovl_enable(ovl->id, op->enabled); 616 dispc_ovl_enable(ovl->id, op->enabled);
618 dispc_ovl_set_channel_out(ovl->id, op->channel);
619 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); 617 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
620 618
621 mp = get_mgr_priv(ovl->manager); 619 mp = get_mgr_priv(ovl->manager);
@@ -1276,39 +1274,34 @@ int dss_ovl_set_manager(struct omap_overlay *ovl,
1276 goto err; 1274 goto err;
1277 } 1275 }
1278 1276
1277 r = dispc_runtime_get();
1278 if (r)
1279 goto err;
1280
1279 spin_lock_irqsave(&data_lock, flags); 1281 spin_lock_irqsave(&data_lock, flags);
1280 1282
1281 if (op->enabled) { 1283 if (op->enabled) {
1282 spin_unlock_irqrestore(&data_lock, flags); 1284 spin_unlock_irqrestore(&data_lock, flags);
1283 DSSERR("overlay has to be disabled to change the manager\n"); 1285 DSSERR("overlay has to be disabled to change the manager\n");
1284 r = -EINVAL; 1286 r = -EINVAL;
1285 goto err; 1287 goto err1;
1286 } 1288 }
1287 1289
1288 op->channel = mgr->id; 1290 dispc_ovl_set_channel_out(ovl->id, mgr->id);
1289 op->extra_info_dirty = true;
1290 1291
1291 ovl->manager = mgr; 1292 ovl->manager = mgr;
1292 list_add_tail(&ovl->list, &mgr->overlays); 1293 list_add_tail(&ovl->list, &mgr->overlays);
1293 1294
1294 spin_unlock_irqrestore(&data_lock, flags); 1295 spin_unlock_irqrestore(&data_lock, flags);
1295 1296
1296 /* XXX: When there is an overlay on a DSI manual update display, and 1297 dispc_runtime_put();
1297 * the overlay is first disabled, then moved to tv, and enabled, we
1298 * seem to get SYNC_LOST_DIGIT error.
1299 *
1300 * Waiting doesn't seem to help, but updating the manual update display
1301 * after disabling the overlay seems to fix this. This hints that the
1302 * overlay is perhaps somehow tied to the LCD output until the output
1303 * is updated.
1304 *
1305 * Userspace workaround for this is to update the LCD after disabling
1306 * the overlay, but before moving the overlay to TV.
1307 */
1308 1298
1309 mutex_unlock(&apply_lock); 1299 mutex_unlock(&apply_lock);
1310 1300
1311 return 0; 1301 return 0;
1302
1303err1:
1304 dispc_runtime_put();
1312err: 1305err:
1313 mutex_unlock(&apply_lock); 1306 mutex_unlock(&apply_lock);
1314 return r; 1307 return r;
@@ -1342,9 +1335,24 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl)
1342 /* wait for pending extra_info updates to ensure the ovl is disabled */ 1335 /* wait for pending extra_info updates to ensure the ovl is disabled */
1343 wait_pending_extra_info_updates(); 1336 wait_pending_extra_info_updates();
1344 1337
1338 /*
1339 * For a manual update display, there is no guarantee that the overlay
1340 * is really disabled in HW, we may need an extra update from this
1341 * manager before the configurations can go in. Return an error if the
1342 * overlay needed an update from the manager.
1343 *
1344 * TODO: Instead of returning an error, try to do a dummy manager update
1345 * here to disable the overlay in hardware. Use the *GATED fields in
1346 * the DISPC_CONFIG registers to do a dummy update.
1347 */
1345 spin_lock_irqsave(&data_lock, flags); 1348 spin_lock_irqsave(&data_lock, flags);
1346 1349
1347 op->channel = -1; 1350 if (ovl_manual_update(ovl) && op->extra_info_dirty) {
1351 spin_unlock_irqrestore(&data_lock, flags);
1352 DSSERR("need an update to change the manager\n");
1353 r = -EINVAL;
1354 goto err;
1355 }
1348 1356
1349 ovl->manager = NULL; 1357 ovl->manager = NULL;
1350 list_del(&ovl->list); 1358 list_del(&ovl->list);