[PATCH] This patch adds VRFB based rotation support to omapfb

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

This patch implements VRFB based rotation support to the
framebuffer driver (for omap 2430 platform).

It is tested in VGA and QVGA resolution in omap2evm board,
i was unable to test it on 2430sdp because my SDP is not booting
with the latest git kernel.

I am really glad to hear your comments about this , please
let me know you suggestions i will try to change accordingly.

Many thanks to khasim for the help received from him.

######################################################
>From e10a7dd4c624b20d50ac715ef867fa28d7068d97 Mon Sep 17 00:00:00 2001
From: arun <arunedarath@xxxxxxxxxxxxxxxxxxxx>
Date: Sat, 19 Apr 2008 18:33:43 +0530
Subject: [PATCH] This patch adds VRFB based rotation support to omapfb

The features are:

a) Processor and applications writes to VRFB0 space and the display
   controller reads from different VRFB space according to degree of
   rotation.

b) Pass video=omapfb:rotate:<degree> to see the penguin rotate.

c) Clean up code is not implemented as of now(like unmapping the VRFB regions)
---
 drivers/video/omap/dispc.c       |  210 ++++++++++++++++++++++++++++++++++++++
 drivers/video/omap/omapfb_main.c |   23 +++--
 2 files changed, 225 insertions(+), 8 deletions(-)

diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
index 4c055a2..419472e 100644
--- a/drivers/video/omap/dispc.c
+++ b/drivers/video/omap/dispc.c
@@ -148,6 +148,44 @@
 #define RESMAP_MASK(_page_nr)						\
 	(1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1)))

+/* Rotation using VRFB */
+#define	ROTATION_TEST		1
+#define SMS_ROT_VIRT_BASE(context, degree)	(0x70000000 		\
+						| 0x4000000 * (context)	\
+						| 0x1000000 * (degree/90))
+#define	VRFB_SIZE		(2048 * 640 * (16/8))
+#define	PAGE_WIDTH_EXP		5 /* Assuming SDRAM pagesize= 1024 */
+#define	PAGE_HEIGHT_EXP		5 /* 1024 = 2^5 * 2^5 */
+#define	SMS_IMAGEHEIGHT_OFFSET	16
+#define	SMS_IMAGEWIDTH_OFFSET	0
+#define	SMS_PH_OFFSET		8
+#define	SMS_PW_OFFSET		4
+#define	SMS_PS_OFFSET		0
+#define	ROT_LINE_LENGTH		2048
+
+#define	OMAP_SMS_BASE	(0x6C000000)
+
+#define	SMS_ROT0_PHYSICAL_BA(context)	__REG32(OMAP_SMS_BASE + 0x188 \
+						+ 0x10 * context)
+#define	SMS_ROT_CONTROL(context)	__REG32(OMAP_SMS_BASE + 0x180 \
+						+ 0x10 * context)
+#define	SMS_ROT0_SIZE(context)		__REG32(OMAP_SMS_BASE + 0x184 \
+						+ 0x10 * context)
+
+dma_addr_t save_paddr;
+unsigned long save_vaddr;
+unsigned long save_offset;
+int vrfb_rotation;
+
+static struct {
+	dma_addr_t	sms_rot_phy[4];
+	unsigned long	sms_rot_virt[4];
+	u32 xoffset;
+	u32 yoffset;
+} vrfb;
+
+static int omap2_disp_set_vrfb(u32 width, u32 height, u32 bytes_per_pixel);
+
 struct resmap {
 	unsigned long	start;
 	unsigned	page_cnt;
@@ -449,6 +487,7 @@ static int omap_dispc_setup_plane(int plane, int
channel_out,

 	if ((unsigned)plane > dispc.mem_desc.region_cnt)
 		return -EINVAL;
+	save_offset = offset;
 	paddr = dispc.mem_desc.region[plane].paddr + offset;
 	enable_lcd_clocks(1);
 	r = _setup_plane(plane, channel_out, paddr,
@@ -458,6 +497,111 @@ static int omap_dispc_setup_plane(int plane, int
channel_out,
 	return r;
 }

+static inline u32
+calc_vrfb_div(u32 img_side, u32 page_exp)
+{
+	u32 div;
+	div = img_side / page_exp;
+	if ((div * page_exp) < img_side)
+		return div + 1;
+	else
+		return div;
+}
+
+static int omap2_disp_set_vrfb(u32 width, u32 height, u32 bytes_per_pixel)
+{
+	int page_width_exp, page_height_exp, pixel_size_exp;
+	int context = 0;
+	int div;
+	u32 vrfb_width;
+	u32 vrfb_height;
+
+	page_width_exp = PAGE_WIDTH_EXP;
+	page_height_exp = PAGE_HEIGHT_EXP;
+	pixel_size_exp = bytes_per_pixel >> 1;
+
+	div = calc_vrfb_div(width * bytes_per_pixel, 1 << page_width_exp);
+	vrfb_width = (div * (1 << page_width_exp)) / bytes_per_pixel;
+
+	div = calc_vrfb_div(height, 1 << page_height_exp);
+	vrfb_height = div * (1 << page_height_exp);
+
+	SMS_ROT0_PHYSICAL_BA(context) = save_paddr;
+	SMS_ROT0_SIZE(context) = 0;
+	SMS_ROT0_SIZE(context)	|= (vrfb_width << SMS_IMAGEWIDTH_OFFSET)
+				| (vrfb_height << SMS_IMAGEHEIGHT_OFFSET);
+	SMS_ROT_CONTROL(context) = 0;
+	SMS_ROT_CONTROL(context) |= pixel_size_exp << SMS_PS_OFFSET
+			| page_width_exp  << SMS_PW_OFFSET
+			| page_height_exp << SMS_PH_OFFSET;
+
+	vrfb.xoffset = vrfb_width - width;
+	vrfb.yoffset = vrfb_height - height;
+	return 0;
+}
+
+static int omap_dispc_set_rotate(int angle)
+{
+	const u32 ba_reg[] = { DISPC_GFX_BA0 };
+	const u32 ri_reg[] = { DISPC_GFX_ROW_INC };
+	const u32 pi_reg[] = { DISPC_GFX_PIXEL_INC };
+	int width, height;
+	u32 addr_base;
+	u32 Bpp;
+
+	if (vrfb_rotation != 1)
+		return 0;
+
+	width = dispc.fbdev->fb_info[0]->var.xres;
+	height = dispc.fbdev->fb_info[0]->var.yres;
+	Bpp = dispc.fbdev->fb_info[0]->var.bits_per_pixel / 8;
+
+	enable_lcd_clocks(1);
+
+	switch (angle) {
+	case 0:
+		omap2_disp_set_vrfb(width, height, Bpp);
+		addr_base = SMS_ROT_VIRT_BASE(0, 0) + save_offset;
+		dispc_write_reg(ba_reg[0], addr_base);
+		dispc_write_reg(pi_reg[0], 1);
+		dispc_write_reg(ri_reg[0], (ROT_LINE_LENGTH - width) * Bpp + 1);
+		break;
+	case 90:
+		omap2_disp_set_vrfb(height, width, Bpp);
+		addr_base = SMS_ROT_VIRT_BASE(0, 90) + save_offset
+					+ vrfb.yoffset * Bpp;
+
+		dispc_write_reg(ba_reg[0], addr_base);
+		dispc_write_reg(pi_reg[0], 1);
+		dispc_write_reg(ri_reg[0], (ROT_LINE_LENGTH - width) * Bpp + 1);
+		break;
+	case 180:
+		omap2_disp_set_vrfb(width, height, Bpp);
+		addr_base = SMS_ROT_VIRT_BASE(0, 180) + save_offset
+					+ vrfb.xoffset * Bpp
+					+ ROT_LINE_LENGTH * vrfb.yoffset * Bpp;
+
+		dispc_write_reg(ba_reg[0], addr_base);
+		dispc_write_reg(pi_reg[0], 1);
+		dispc_write_reg(ri_reg[0], (ROT_LINE_LENGTH - width) * Bpp + 1);
+		break;
+	case 270:
+		omap2_disp_set_vrfb(height, width, Bpp);
+		addr_base = SMS_ROT_VIRT_BASE(0, 270) + save_offset
+				+ ROT_LINE_LENGTH * vrfb.xoffset * Bpp;
+
+		dispc_write_reg(ba_reg[0], addr_base);
+		dispc_write_reg(pi_reg[0], 1);
+		dispc_write_reg(ri_reg[0], (ROT_LINE_LENGTH - width) * Bpp + 1);
+		break;
+	}
+	
+	MOD_REG_FLD(DISPC_CONTROL, 0x20, 0); /* Sets & clears the GOLCD bit */
+	MOD_REG_FLD(DISPC_CONTROL, 0x20, 0x20);
+	enable_lcd_clocks(0);
+	return 0;
+}
+
 static void write_firh_reg(int plane, int reg, u32 value)
 {
 	u32 base;
@@ -1422,9 +1566,74 @@ static int omap_dispc_init(struct omapfb_device
*fbdev, int ext_mode,
 	if ((r = alloc_palette_ram()) < 0)
 		goto fail2;

+#ifdef ROTATION_TEST
+	memset(&vrfb, 0, sizeof(vrfb));
+	vrfb_rotation = 1;
+	vrfb.sms_rot_phy[0] = SMS_ROT_VIRT_BASE(0, 0);
+	vrfb.sms_rot_phy[1] = SMS_ROT_VIRT_BASE(0, 90);
+	vrfb.sms_rot_phy[2] = SMS_ROT_VIRT_BASE(0, 180);
+	vrfb.sms_rot_phy[3] = SMS_ROT_VIRT_BASE(0, 270);
+
+	if (!request_mem_region(vrfb.sms_rot_phy[0],
+			  req_vram->region[0].size, "omapfb")) {
+		printk(KERN_ERR "omapfb:can't reserve VRFB0 area\n");
+		vrfb_rotation++;
+	}
+
+	if (!request_mem_region(vrfb.sms_rot_phy[1],
+			  req_vram->region[0].size, "omapfb")) {
+		printk(KERN_ERR "omapfb:can't reserve VRFB90 area\n");
+		vrfb_rotation++;
+	}
+
+	if (!request_mem_region(vrfb.sms_rot_phy[2],
+			  req_vram->region[0].size, "omapfb")) {
+		printk(KERN_ERR "omapfb:can't reserve VRFB180 area\n");
+		vrfb_rotation++;
+	}
+
+	if (!request_mem_region(vrfb.sms_rot_phy[3],
+			  req_vram->region[0].size, "omapfb")) {
+		printk(KERN_ERR "omapfb:can,t reserve VRFB270 area\n");
+		vrfb_rotation++;
+	}
+
+	if (!(vrfb.sms_rot_virt[0] =
+	(unsigned long) ioremap(vrfb.sms_rot_phy[0],
+				req_vram->region[0].size))      ||
+	!(vrfb.sms_rot_virt[1] =
+	(unsigned long) ioremap(vrfb.sms_rot_phy[1],
+				req_vram->region[0].size))      ||
+	!(vrfb.sms_rot_virt[2] =
+	(unsigned long) ioremap(vrfb.sms_rot_phy[2],
+				req_vram->region[0].size))      ||
+	!(vrfb.sms_rot_virt[3] =
+	(unsigned long) ioremap(vrfb.sms_rot_phy[3],
+				req_vram->region[0].size)))
+
+	{
+		printk(KERN_ERR "omapfb: cannot map rotated view(s)\n");
+		vrfb_rotation++;
+	}
+#endif
+
 	if ((r = setup_fbmem(req_vram)) < 0)
 		goto fail3;

+	if (vrfb_rotation == 1) {
+		save_paddr = dispc.mem_desc.region[0].paddr;
+		save_vaddr = (unsigned long)dispc.mem_desc.region[0].vaddr;
+
+		dispc.mem_desc.region[0].vaddr = (void *)vrfb.sms_rot_virt[0];
+		dispc.mem_desc.region[0].paddr = vrfb.sms_rot_phy[0];
+		dispc.fbdev->mem_desc.region[0].vaddr =
+						(void *)vrfb.sms_rot_virt[0];
+
+		dispc.fbdev->mem_desc.region[0].paddr = vrfb.sms_rot_phy[0];
+		omap2_disp_set_vrfb(panel->x_res, panel->y_res,
+							 panel->bpp / 8);
+	}
+
 	if (!skip_init) {
 		for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
 			memset(dispc.mem_desc.region[i].vaddr, 0,
@@ -1503,4 +1712,5 @@ const struct lcd_ctrl omap2_int_ctrl = {
 	.set_color_key		= omap_dispc_set_color_key,
 	.get_color_key		= omap_dispc_get_color_key,
 	.mmap			= omap_dispc_mmap_user,
+	.set_rotate		= omap_dispc_set_rotate,
 };
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 418ed9f..2a9500b 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -32,6 +32,8 @@
 #include <asm/arch/omapfb.h>

 #define MODULE_NAME	"omapfb"
+#define	ROTATION_TEST	1
+#define	ROT_LINE_LENGTH	2048

 static unsigned int	def_accel;
 static unsigned long	def_vram[OMAPFB_PLANE_NUM];
@@ -422,7 +424,11 @@ static void set_fb_fix(struct fb_info *fbi)
 		break;
 	}
 	fix->accel		= FB_ACCEL_OMAP1610;
+#ifdef ROTATION_TEST
+	fix->line_length	= ROT_LINE_LENGTH * bpp / 8;
+#else
 	fix->line_length	= var->xres_virtual * bpp / 8;
+#endif
 }

 static int set_color_mode(struct omapfb_plane_struct *plane,
@@ -495,13 +501,14 @@ static int set_fb_var(struct fb_info *fbi,
 	if (plane->color_mode == OMAPFB_COLOR_RGB444)
 		bpp = 16;

+	xres_min = OMAPFB_PLANE_XRES_MIN;
+	xres_max = panel->x_res;
+	yres_min = OMAPFB_PLANE_YRES_MIN;
+	yres_max = panel->y_res;
+
 	switch (var->rotate) {
 	case 0:
 	case 180:
-		xres_min = OMAPFB_PLANE_XRES_MIN;
-		xres_max = panel->x_res;
-		yres_min = OMAPFB_PLANE_YRES_MIN;
-		yres_max = panel->y_res;
 		if (cpu_is_omap15xx()) {
 			var->xres = panel->x_res;
 			var->yres = panel->y_res;
@@ -509,10 +516,6 @@ static int set_fb_var(struct fb_info *fbi,
 		break;
 	case 90:
 	case 270:
-		xres_min = OMAPFB_PLANE_YRES_MIN;
-		xres_max = panel->y_res;
-		yres_min = OMAPFB_PLANE_XRES_MIN;
-		yres_max = panel->x_res;
 		if (cpu_is_omap15xx()) {
 			var->xres = panel->y_res;
 			var->yres = panel->x_res;
@@ -1715,7 +1718,11 @@ static int omapfb_do_probe(struct platform_device *pdev,

 	pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);

+#ifdef ROTATION_TEST
+	def_vxres = ROT_LINE_LENGTH;
+#else
 	def_vxres = def_vxres ? : fbdev->panel->x_res;
+#endif
 	def_vyres = def_vyres ? : fbdev->panel->y_res;

 	init_state++;
-- 
1.5.3.4



Regards,
Arun C
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux