Browse Source

Merge branch 'work/fifomerge'

Tomi Valkeinen 13 years ago
parent
commit
5e36097889

+ 191 - 30
drivers/video/omap2/dss/apply.c

@@ -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;

+ 49 - 6
drivers/video/omap2/dss/dispc.c

@@ -909,7 +909,7 @@ static void dispc_configure_burst_sizes(void)
 		dispc_ovl_set_burst_size(i, burst_size);
 }
 
-u32 dispc_ovl_get_burst_size(enum omap_plane plane)
+static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
 {
 	unsigned unit = dss_feat_get_burst_size_unit();
 	/* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
@@ -1018,7 +1018,7 @@ static void dispc_read_plane_fifo_sizes(void)
 	}
 }
 
-u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
+static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
 {
 	return dispc.fifo_size[plane];
 }
@@ -1039,13 +1039,13 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
 	dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
 	dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
 
-	DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
+	DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
 			plane,
 			REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
-				lo_start, lo_end),
+				lo_start, lo_end) * unit,
 			REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
-				hi_start, hi_end),
-			low, high);
+				hi_start, hi_end) * unit,
+			low * unit, high * unit);
 
 	dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
 			FLD_VAL(high, hi_start, hi_end) |
@@ -1054,10 +1054,53 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
 
 void dispc_enable_fifomerge(bool enable)
 {
+	if (!dss_has_feature(FEAT_FIFO_MERGE)) {
+		WARN_ON(enable);
+		return;
+	}
+
 	DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
 	REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
 }
 
+void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
+		u32 *fifo_low, u32 *fifo_high, bool use_fifomerge)
+{
+	/*
+	 * All sizes are in bytes. Both the buffer and burst are made of
+	 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
+	 */
+
+	unsigned buf_unit = dss_feat_get_buffer_size_unit();
+	unsigned ovl_fifo_size, total_fifo_size, burst_size;
+	int i;
+
+	burst_size = dispc_ovl_get_burst_size(plane);
+	ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
+
+	if (use_fifomerge) {
+		total_fifo_size = 0;
+		for (i = 0; i < omap_dss_get_num_overlays(); ++i)
+			total_fifo_size += dispc_ovl_get_fifo_size(i);
+	} else {
+		total_fifo_size = ovl_fifo_size;
+	}
+
+	/*
+	 * We use the same low threshold for both fifomerge and non-fifomerge
+	 * cases, but for fifomerge we calculate the high threshold using the
+	 * combined fifo size
+	 */
+
+	if (dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
+		*fifo_low = ovl_fifo_size - burst_size * 2;
+		*fifo_high = total_fifo_size - burst_size;
+	} else {
+		*fifo_low = ovl_fifo_size - burst_size;
+		*fifo_high = total_fifo_size - buf_unit;
+	}
+}
+
 static void dispc_ovl_set_fir(enum omap_plane plane,
 				int hinc, int vinc,
 				enum omap_color_component color_comp)

+ 0 - 10
drivers/video/omap2/dss/display.c

@@ -279,16 +279,6 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omapdss_default_get_resolution);
 
-void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high)
-{
-	unsigned buf_unit = dss_feat_get_buffer_size_unit();
-
-	*fifo_high = fifo_size - buf_unit;
-	*fifo_low = fifo_size - burst_size;
-}
-
 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
 {
 	switch (dssdev->type) {

+ 0 - 8
drivers/video/omap2/dss/dsi.c

@@ -4524,14 +4524,6 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
-void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high)
-{
-	*fifo_high = fifo_size - burst_size;
-	*fifo_low = fifo_size - burst_size * 2;
-}
-
 int dsi_init_display(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);

+ 2 - 8
drivers/video/omap2/dss/dss.h

@@ -202,9 +202,6 @@ void dss_uninit_device(struct platform_device *pdev,
 		struct omap_dss_device *dssdev);
 bool dss_use_replication(struct omap_dss_device *dssdev,
 		enum omap_color_mode mode);
-void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high);
 
 /* manager */
 int dss_init_overlay_managers(struct platform_device *pdev);
@@ -313,9 +310,6 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
 int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
 		bool enable_hsdiv);
 void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
-void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high);
 void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
 void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
 struct platform_device *dsi_get_dsidev_from_id(int module);
@@ -429,8 +423,8 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
 
 
 void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
-u32 dispc_ovl_get_fifo_size(enum omap_plane plane);
-u32 dispc_ovl_get_burst_size(enum omap_plane plane);
+void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
+		u32 *fifo_low, u32 *fifo_high, bool use_fifomerge);
 int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
 		bool ilace, bool replication);
 int dispc_ovl_enable(enum omap_plane plane, bool enable);

+ 7 - 4
drivers/video/omap2/dss/dss_features.c

@@ -370,7 +370,8 @@ static const struct omap_dss_features omap3430_dss_features = {
 		FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
 		FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC |
 		FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD |
-		FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER,
+		FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER | FEAT_FIFO_MERGE |
+		FEAT_OMAP3_DSI_FIFO_BUG,
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
@@ -394,7 +395,8 @@ static const struct omap_dss_features omap3630_dss_features = {
 		FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
 		FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
 		FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD |
-		FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER,
+		FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER | FEAT_FIFO_MERGE |
+		FEAT_OMAP3_DSI_FIFO_BUG,
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
@@ -419,7 +421,7 @@ static const struct omap_dss_features omap4430_es1_0_dss_features  = {
 		FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
 		FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 |
 		FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V |
-		FEAT_ALPHA_FREE_ZORDER,
+		FEAT_ALPHA_FREE_ZORDER | FEAT_FIFO_MERGE,
 
 	.num_mgrs = 3,
 	.num_ovls = 4,
@@ -443,7 +445,8 @@ static const struct omap_dss_features omap4_dss_features = {
 		FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
 		FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
 		FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR |
-		FEAT_PRELOAD | FEAT_FIR_COEF_V | FEAT_ALPHA_FREE_ZORDER,
+		FEAT_PRELOAD | FEAT_FIR_COEF_V | FEAT_ALPHA_FREE_ZORDER |
+		FEAT_FIFO_MERGE,
 
 	.num_mgrs = 3,
 	.num_ovls = 4,

+ 3 - 0
drivers/video/omap2/dss/dss_features.h

@@ -58,6 +58,9 @@ enum dss_feat_id {
 	FEAT_FIR_COEF_V			= 1 << 25,
 	FEAT_ALPHA_FIXED_ZORDER		= 1 << 26,
 	FEAT_ALPHA_FREE_ZORDER		= 1 << 27,
+	FEAT_FIFO_MERGE			= 1 << 28,
+	/* An unknown HW bug causing the normal FIFO thresholds not to work */
+	FEAT_OMAP3_DSI_FIFO_BUG		= 1 << 29,
 };
 
 /* DSS register field id */