From 1ef94095e9399a9a387b7b457b48f6c5de7013d8 Mon Sep 17 00:00:00 2001
From: Tuomas Kulve <tuomas.kulve@movial.com>
Date: Fri, 31 Oct 2008 14:23:57 +0200
Subject: [PATCH] Implement downsampling (with debugs).

---
 drivers/video/omap/dispc.c |   75 +++++++++++++++++++++++++++++++++++++-------
 1 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
index 68bc887..3640dbe 100644
--- a/drivers/video/omap/dispc.c
+++ b/drivers/video/omap/dispc.c
@@ -18,6 +18,8 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
+#define DEBUG
+#define VERBOSE_DEBUG
 #include <linux/kernel.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
@@ -545,6 +547,17 @@ static void write_firhv_reg(int plane, int reg, u32 value)
 	dispc_write_reg(base + reg * 8,	value);
 }
 
+static void write_firv_reg(int plane, int reg, u32 value)
+{
+	u32 base;
+
+	if (plane == 1)
+		base = 0x1E0;
+	else
+		base = 0x1E0 + 0x20;
+	dispc_write_reg(base + reg * 4,	value);
+}
+
 static void set_upsampling_coef_table(int plane)
 {
 	const u32 coef[][2] = {
@@ -565,6 +578,27 @@ static void set_upsampling_coef_table(int plane)
 	}
 }
 
+static void set_downsampling_coef_table(int plane)
+{
+	const u32 coef[][3] = {
+                { 0x24382400, 0x24382400, 0x00000000 },
+                { 0x28371FFE, 0x28391F04, 0x000004FE },
+                { 0x2C361BFB, 0x2D381B08, 0x000008FB },
+                { 0x303516F9, 0x3237170C, 0x00000CF9 },
+                { 0x11343311, 0x123737F7, 0x0000F711 },
+                { 0x1635300C, 0x173732F9, 0x0000F90C },
+                { 0x1B362C08, 0x1B382DFB, 0x0000FB08 },
+                { 0x1F372804, 0x1F3928FE, 0x0000FE04 },
+	};
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		write_firh_reg(plane, i, coef[i][0]);
+		write_firhv_reg(plane, i, coef[i][1]);
+		write_firv_reg(plane, i, coef[i][2]);
+	}
+}
+
 static int omap_dispc_set_scale(int plane,
 				int orig_width, int orig_height,
 				int out_width, int out_height)
@@ -592,25 +626,47 @@ static int omap_dispc_set_scale(int plane,
 		if (orig_height > out_height ||
 		    orig_width * 8 < out_width ||
 		    orig_height * 8 < out_height) {
+                        dev_dbg(dispc.fbdev->dev, 
+                                "Max upsampling is 8x, "
+                                "tried: %dx%d -> %dx%d\n",
+                                orig_width, orig_height,
+                                out_width, out_height);
 			enable_lcd_clocks(0);
 			return -EINVAL;
 		}
 		set_upsampling_coef_table(plane);
 	} else if (orig_width > out_width) {
-		/* Downsampling not yet supported
-		*/
-
-		enable_lcd_clocks(0);
-		return -EINVAL;
+		/*
+		 * Downsampling.
+		 * Currently you can only scale both dimensions in one way.
+		 */
+		if (orig_height < out_height ||
+		    orig_width > out_width * 4||
+		    orig_height > out_height * 4) {
+                        dev_dbg(dispc.fbdev->dev, 
+                                "Max downsampling is 4x, "
+                                "tried: %dx%d -> %dx%d\n",
+                                orig_width, orig_height,
+                                out_width, out_height);
+			enable_lcd_clocks(0);
+			return -EINVAL;
+		}
+		set_downsampling_coef_table(plane);
 	}
 	if (!orig_width || orig_width == out_width)
 		fir_hinc = 0;
 	else
-		fir_hinc = 1024 * orig_width / out_width;
+		fir_hinc = 1024 * (orig_width -1)/ (out_width -1);
 	if (!orig_height || orig_height == out_height)
 		fir_vinc = 0;
 	else
-		fir_vinc = 1024 * orig_height / out_height;
+		fir_vinc = 1024 * (orig_height-1) / (out_height -1 );
+
+	dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
+		"orig_height %d fir_hinc  %d fir_vinc %d\n",
+		out_width, out_height, orig_width, orig_height,
+		fir_hinc, fir_vinc);
+
 	dispc.fir_hinc[plane] = fir_hinc;
 	dispc.fir_vinc[plane] = fir_vinc;
 
@@ -619,11 +675,6 @@ static int omap_dispc_set_scale(int plane,
 		    ((fir_vinc & 4095) << 16) |
 		    (fir_hinc & 4095));
 
-	dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
-		"orig_height %d fir_hinc  %d fir_vinc %d\n",
-		out_width, out_height, orig_width, orig_height,
-		fir_hinc, fir_vinc);
-
 	MOD_REG_FLD(vs_reg[plane],
 		    FLD_MASK(16, 11) | FLD_MASK(0, 11),
 		    ((out_height - 1) << 16) | (out_width - 1));
-- 
1.5.6.5