|
@@ -105,6 +105,9 @@ static struct {
|
|
|
struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
|
|
|
struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
|
|
|
|
|
|
+ bool fifo_merge_dirty;
|
|
|
+ bool fifo_merge;
|
|
|
+
|
|
|
bool irq_enabled;
|
|
|
} dss_data;
|
|
|
|
|
@@ -585,11 +588,40 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void dss_write_regs_common(void)
|
|
|
+{
|
|
|
+ const int num_mgrs = omap_dss_get_num_overlay_managers();
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!dss_data.fifo_merge_dirty)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (i = 0; i < num_mgrs; ++i) {
|
|
|
+ struct omap_overlay_manager *mgr;
|
|
|
+ struct mgr_priv_data *mp;
|
|
|
+
|
|
|
+ mgr = omap_dss_get_overlay_manager(i);
|
|
|
+ mp = get_mgr_priv(mgr);
|
|
|
+
|
|
|
+ if (mp->enabled) {
|
|
|
+ if (dss_data.fifo_merge_dirty) {
|
|
|
+ dispc_enable_fifomerge(dss_data.fifo_merge);
|
|
|
+ dss_data.fifo_merge_dirty = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mp->updating)
|
|
|
+ mp->shadow_info_dirty = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void dss_write_regs(void)
|
|
|
{
|
|
|
const int num_mgrs = omap_dss_get_num_overlay_managers();
|
|
|
int i;
|
|
|
|
|
|
+ dss_write_regs_common();
|
|
|
+
|
|
|
for (i = 0; i < num_mgrs; ++i) {
|
|
|
struct omap_overlay_manager *mgr;
|
|
|
struct mgr_priv_data *mp;
|
|
@@ -659,6 +691,8 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
|
|
|
|
|
|
dss_mgr_write_regs(mgr);
|
|
|
|
|
|
+ dss_write_regs_common();
|
|
|
+
|
|
|
mp->updating = true;
|
|
|
|
|
|
if (!dss_data.irq_enabled && need_isr())
|
|
@@ -859,11 +893,20 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
|
|
|
op->extra_info_dirty = true;
|
|
|
}
|
|
|
|
|
|
-static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
|
|
|
+static void dss_apply_fifo_merge(bool use_fifo_merge)
|
|
|
+{
|
|
|
+ if (dss_data.fifo_merge == use_fifo_merge)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dss_data.fifo_merge = use_fifo_merge;
|
|
|
+ dss_data.fifo_merge_dirty = true;
|
|
|
+}
|
|
|
+
|
|
|
+static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
|
|
|
+ bool use_fifo_merge)
|
|
|
{
|
|
|
struct ovl_priv_data *op = get_ovl_priv(ovl);
|
|
|
struct omap_dss_device *dssdev;
|
|
|
- u32 size, burst_size;
|
|
|
u32 fifo_low, fifo_high;
|
|
|
|
|
|
if (!op->enabled && !op->enabling)
|
|
@@ -871,33 +914,14 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
|
|
|
|
|
|
dssdev = ovl->manager->device;
|
|
|
|
|
|
- size = dispc_ovl_get_fifo_size(ovl->id);
|
|
|
-
|
|
|
- burst_size = dispc_ovl_get_burst_size(ovl->id);
|
|
|
-
|
|
|
- switch (dssdev->type) {
|
|
|
- case OMAP_DISPLAY_TYPE_DPI:
|
|
|
- case OMAP_DISPLAY_TYPE_DBI:
|
|
|
- case OMAP_DISPLAY_TYPE_SDI:
|
|
|
- case OMAP_DISPLAY_TYPE_VENC:
|
|
|
- case OMAP_DISPLAY_TYPE_HDMI:
|
|
|
- default_get_overlay_fifo_thresholds(ovl->id, size,
|
|
|
- burst_size, &fifo_low, &fifo_high);
|
|
|
- break;
|
|
|
-#ifdef CONFIG_OMAP2_DSS_DSI
|
|
|
- case OMAP_DISPLAY_TYPE_DSI:
|
|
|
- dsi_get_overlay_fifo_thresholds(ovl->id, size,
|
|
|
- burst_size, &fifo_low, &fifo_high);
|
|
|
- break;
|
|
|
-#endif
|
|
|
- default:
|
|
|
- BUG();
|
|
|
- }
|
|
|
+ dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
|
|
|
+ use_fifo_merge);
|
|
|
|
|
|
dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
|
|
|
}
|
|
|
|
|
|
-static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
|
|
|
+static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
|
|
|
+ bool use_fifo_merge)
|
|
|
{
|
|
|
struct omap_overlay *ovl;
|
|
|
struct mgr_priv_data *mp;
|
|
@@ -908,19 +932,94 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
|
|
|
return;
|
|
|
|
|
|
list_for_each_entry(ovl, &mgr->overlays, list)
|
|
|
- dss_ovl_setup_fifo(ovl);
|
|
|
+ dss_ovl_setup_fifo(ovl, use_fifo_merge);
|
|
|
+}
|
|
|
+
|
|
|
+static void dss_setup_fifos(bool use_fifo_merge)
|
|
|
+{
|
|
|
+ const int num_mgrs = omap_dss_get_num_overlay_managers();
|
|
|
+ struct omap_overlay_manager *mgr;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < num_mgrs; ++i) {
|
|
|
+ mgr = omap_dss_get_overlay_manager(i);
|
|
|
+ dss_mgr_setup_fifos(mgr, use_fifo_merge);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static void dss_setup_fifos(void)
|
|
|
+static int get_num_used_managers(void)
|
|
|
{
|
|
|
const int num_mgrs = omap_dss_get_num_overlay_managers();
|
|
|
struct omap_overlay_manager *mgr;
|
|
|
+ struct mgr_priv_data *mp;
|
|
|
int i;
|
|
|
+ int enabled_mgrs;
|
|
|
+
|
|
|
+ enabled_mgrs = 0;
|
|
|
|
|
|
for (i = 0; i < num_mgrs; ++i) {
|
|
|
mgr = omap_dss_get_overlay_manager(i);
|
|
|
- dss_mgr_setup_fifos(mgr);
|
|
|
+ mp = get_mgr_priv(mgr);
|
|
|
+
|
|
|
+ if (!mp->enabled)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ enabled_mgrs++;
|
|
|
}
|
|
|
+
|
|
|
+ return enabled_mgrs;
|
|
|
+}
|
|
|
+
|
|
|
+static int get_num_used_overlays(void)
|
|
|
+{
|
|
|
+ const int num_ovls = omap_dss_get_num_overlays();
|
|
|
+ struct omap_overlay *ovl;
|
|
|
+ struct ovl_priv_data *op;
|
|
|
+ struct mgr_priv_data *mp;
|
|
|
+ int i;
|
|
|
+ int enabled_ovls;
|
|
|
+
|
|
|
+ enabled_ovls = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < num_ovls; ++i) {
|
|
|
+ ovl = omap_dss_get_overlay(i);
|
|
|
+ op = get_ovl_priv(ovl);
|
|
|
+
|
|
|
+ if (!op->enabled && !op->enabling)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ mp = get_mgr_priv(ovl->manager);
|
|
|
+
|
|
|
+ if (!mp->enabled)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ enabled_ovls++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return enabled_ovls;
|
|
|
+}
|
|
|
+
|
|
|
+static bool get_use_fifo_merge(void)
|
|
|
+{
|
|
|
+ int enabled_mgrs = get_num_used_managers();
|
|
|
+ int enabled_ovls = get_num_used_overlays();
|
|
|
+
|
|
|
+ if (!dss_has_feature(FEAT_FIFO_MERGE))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In theory the only requirement for fifomerge is enabled_ovls <= 1.
|
|
|
+ * However, if we have two managers enabled and set/unset the fifomerge,
|
|
|
+ * we need to set the GO bits in particular sequence for the managers,
|
|
|
+ * and wait in between.
|
|
|
+ *
|
|
|
+ * This is rather difficult as new apply calls can happen at any time,
|
|
|
+ * so we simplify the problem by requiring also that enabled_mgrs <= 1.
|
|
|
+ * In practice this shouldn't matter, because when only one overlay is
|
|
|
+ * enabled, most likely only one output is enabled.
|
|
|
+ */
|
|
|
+
|
|
|
+ return enabled_mgrs <= 1 && enabled_ovls <= 1;
|
|
|
}
|
|
|
|
|
|
int dss_mgr_enable(struct omap_overlay_manager *mgr)
|
|
@@ -928,6 +1027,7 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
|
|
|
struct mgr_priv_data *mp = get_mgr_priv(mgr);
|
|
|
unsigned long flags;
|
|
|
int r;
|
|
|
+ bool fifo_merge;
|
|
|
|
|
|
mutex_lock(&apply_lock);
|
|
|
|
|
@@ -945,11 +1045,23 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
- dss_setup_fifos();
|
|
|
+ /* step 1: setup fifos/fifomerge before enabling the manager */
|
|
|
+
|
|
|
+ fifo_merge = get_use_fifo_merge();
|
|
|
+ dss_setup_fifos(fifo_merge);
|
|
|
+ dss_apply_fifo_merge(fifo_merge);
|
|
|
|
|
|
dss_write_regs();
|
|
|
dss_set_go_bits();
|
|
|
|
|
|
+ spin_unlock_irqrestore(&data_lock, flags);
|
|
|
+
|
|
|
+ /* wait until fifo config is in */
|
|
|
+ wait_pending_extra_info_updates();
|
|
|
+
|
|
|
+ /* step 2: enable the manager */
|
|
|
+ spin_lock_irqsave(&data_lock, flags);
|
|
|
+
|
|
|
if (!mgr_manual_update(mgr))
|
|
|
mp->updating = true;
|
|
|
|
|
@@ -974,6 +1086,7 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
|
|
|
{
|
|
|
struct mgr_priv_data *mp = get_mgr_priv(mgr);
|
|
|
unsigned long flags;
|
|
|
+ bool fifo_merge;
|
|
|
|
|
|
mutex_lock(&apply_lock);
|
|
|
|
|
@@ -988,8 +1101,16 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
|
|
|
mp->updating = false;
|
|
|
mp->enabled = false;
|
|
|
|
|
|
+ fifo_merge = get_use_fifo_merge();
|
|
|
+ dss_setup_fifos(fifo_merge);
|
|
|
+ dss_apply_fifo_merge(fifo_merge);
|
|
|
+
|
|
|
+ dss_write_regs();
|
|
|
+ dss_set_go_bits();
|
|
|
+
|
|
|
spin_unlock_irqrestore(&data_lock, flags);
|
|
|
|
|
|
+ wait_pending_extra_info_updates();
|
|
|
out:
|
|
|
mutex_unlock(&apply_lock);
|
|
|
}
|
|
@@ -1241,6 +1362,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
|
|
|
{
|
|
|
struct ovl_priv_data *op = get_ovl_priv(ovl);
|
|
|
unsigned long flags;
|
|
|
+ bool fifo_merge;
|
|
|
int r;
|
|
|
|
|
|
mutex_lock(&apply_lock);
|
|
@@ -1266,7 +1388,22 @@ int dss_ovl_enable(struct omap_overlay *ovl)
|
|
|
goto err2;
|
|
|
}
|
|
|
|
|
|
- dss_setup_fifos();
|
|
|
+ /* step 1: configure fifos/fifomerge for currently enabled ovls */
|
|
|
+
|
|
|
+ fifo_merge = get_use_fifo_merge();
|
|
|
+ dss_setup_fifos(fifo_merge);
|
|
|
+ dss_apply_fifo_merge(fifo_merge);
|
|
|
+
|
|
|
+ dss_write_regs();
|
|
|
+ dss_set_go_bits();
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&data_lock, flags);
|
|
|
+
|
|
|
+ /* wait for fifo configs to go in */
|
|
|
+ wait_pending_extra_info_updates();
|
|
|
+
|
|
|
+ /* step 2: enable the overlay */
|
|
|
+ spin_lock_irqsave(&data_lock, flags);
|
|
|
|
|
|
op->enabling = false;
|
|
|
dss_apply_ovl_enable(ovl, true);
|
|
@@ -1276,6 +1413,9 @@ int dss_ovl_enable(struct omap_overlay *ovl)
|
|
|
|
|
|
spin_unlock_irqrestore(&data_lock, flags);
|
|
|
|
|
|
+ /* wait for overlay to be enabled */
|
|
|
+ wait_pending_extra_info_updates();
|
|
|
+
|
|
|
mutex_unlock(&apply_lock);
|
|
|
|
|
|
return 0;
|
|
@@ -1291,6 +1431,7 @@ int dss_ovl_disable(struct omap_overlay *ovl)
|
|
|
{
|
|
|
struct ovl_priv_data *op = get_ovl_priv(ovl);
|
|
|
unsigned long flags;
|
|
|
+ bool fifo_merge;
|
|
|
int r;
|
|
|
|
|
|
mutex_lock(&apply_lock);
|
|
@@ -1305,14 +1446,34 @@ int dss_ovl_disable(struct omap_overlay *ovl)
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
+ /* step 1: disable the overlay */
|
|
|
spin_lock_irqsave(&data_lock, flags);
|
|
|
|
|
|
dss_apply_ovl_enable(ovl, false);
|
|
|
+
|
|
|
dss_write_regs();
|
|
|
dss_set_go_bits();
|
|
|
|
|
|
spin_unlock_irqrestore(&data_lock, flags);
|
|
|
|
|
|
+ /* wait for the overlay to be disabled */
|
|
|
+ wait_pending_extra_info_updates();
|
|
|
+
|
|
|
+ /* step 2: configure fifos/fifomerge */
|
|
|
+ spin_lock_irqsave(&data_lock, flags);
|
|
|
+
|
|
|
+ fifo_merge = get_use_fifo_merge();
|
|
|
+ dss_setup_fifos(fifo_merge);
|
|
|
+ dss_apply_fifo_merge(fifo_merge);
|
|
|
+
|
|
|
+ dss_write_regs();
|
|
|
+ dss_set_go_bits();
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&data_lock, flags);
|
|
|
+
|
|
|
+ /* wait for fifo config to go in */
|
|
|
+ wait_pending_extra_info_updates();
|
|
|
+
|
|
|
mutex_unlock(&apply_lock);
|
|
|
|
|
|
return 0;
|