Thread (11 messages) flat view 11 messages, 3 authors, 2008-07-30

[RFC 2.6.26-rc9 1/5] pxafb: add shared framebuffer interface

From: Jaya Kumar <hidden>
Date: 2008-07-26 05:29:15
Subsystem: framebuffer layer, the rest · Maintainers: Helge Deller, Linus Torvalds

These changes are to make it possible for a secondary driver to share the
pxafb framebuffer. The changes include:
- adding custom_lccr_bpp entry so that a driver can set a specific
  transfer width on the AMLCD bus while using a separate bits per pixel for
  its actual framebuffer.
- adding extra_video_mem entry so that a driver can tell pxafb of its
  additional needs.
- adding share_video_mem/unshare_video_mem callbacks to notify the secondary
  driver of the framebuffer address, to allow refcounting, and to cleanup on
  completion.

Signed-off-by: Jaya Kumar <redacted>
---
 drivers/video/pxafb.c            |   65 +++++++++++++++++++++++++++++++++-----
 include/asm-arm/arch-pxa/pxafb.h |    8 +++++
 2 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index bb25143..54e0ad1 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -57,6 +57,8 @@
  */
 #define DEBUG_VAR 1
 
+static struct platform_driver pxafb_driver;
+
 #include "pxafb.h"
 
 /* Bits which should not be set in machine configuration structures */
@@ -218,9 +220,25 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  *  pxafb_bpp_to_lccr3():
  *    Convert a bits per pixel value to the correct bit pattern for LCCR3
  */
-static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
+static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var,
+				struct pxafb_mach_info *inf)
 {
 	int ret = 0;
+
+	/* this is to support devices that have customized
+	 * bpp settings for LCCR that are independent from
+	 * the actual bpp used in the framebuffer.
+	 */
+	if (inf->custom_lccr_bpp) {
+		switch (inf->custom_lccr_bpp) {
+		case 1:  ret = LCCR3_1BPP; break;
+		case 2:  ret = LCCR3_2BPP; break;
+		case 4:  ret = LCCR3_4BPP; break;
+		case 8:  ret = LCCR3_8BPP; break;
+		case 16: ret = LCCR3_16BPP; break;
+		}
+		return ret;
+	}
 	switch (var->bits_per_pixel) {
 	case 1:  ret = LCCR3_1BPP; break;
 	case 2:  ret = LCCR3_2BPP; break;
@@ -826,10 +844,22 @@ int pxafb_smart_flush(struct fb_info *info)
 static void setup_parallel_timing(struct pxafb_info *fbi,
 				  struct fb_var_screeninfo *var)
 {
+	struct pxafb_mach_info *inf = fbi->dev->platform_data;
 	unsigned int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
+	unsigned int pix_per_line = var->xres;
+
+	/*
+	 * We can have a device that needs a different width for its AMLCD
+	 * transfers than its framebuffer's bits per pixel. So we need to
+	 * divide down the x resolution. Eg: 800 pixels at 8bpp is the fb.
+	 * The device uses 16-bit xfers so the desired result is:
+	 * 800 pixels / ( 16 bit xfer / 8bpp ) = 400 pixels per line
+	 */
+	if (inf->custom_lccr_bpp)
+		pix_per_line /= (inf->custom_lccr_bpp / var->bits_per_pixel);
 
 	fbi->reg_lccr1 =
-		LCCR1_DisWdth(var->xres) +
+		LCCR1_DisWdth(pix_per_line) +
 		LCCR1_HorSnchWdth(var->hsync_len) +
 		LCCR1_BegLnDel(var->left_margin) +
 		LCCR1_EndLnDel(var->right_margin);
@@ -870,6 +900,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
 {
 	u_long flags;
 	size_t nbytes;
+	struct pxafb_mach_info *inf = fbi->dev->platform_data;
 
 #if DEBUG_VAR
 	if (!(fbi->lccr0 & LCCR0_LCDT)) {
@@ -928,7 +959,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
 		(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
 		 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
 
-	fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var);
+	fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var, inf);
 
 	nbytes = var->yres * fbi->fb.fix.line_length;
 
@@ -1304,14 +1335,17 @@ static int pxafb_resume(struct platform_device *dev)
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
+static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi,
+						struct pxafb_mach_info *inf)
 {
+	int ret;
 	/*
 	 * We reserve one page for the palette, plus the size
 	 * of the framebuffer.
 	 */
 	fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
-	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset +
+					inf->extra_video_mem);
 	fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
 					      &fbi->map_dma, GFP_KERNEL);
 
@@ -1340,6 +1374,13 @@ static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
 		fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
 		fbi->n_smart_cmds = 0;
 #endif
+		if (inf->share_video_mem) {
+			ret = inf->share_video_mem(fbi->fb.screen_base,
+				fbi->screen_dma, pxafb_driver.driver.owner,
+				inf->extra_data);
+			if (ret)
+				return ret;
+		}
 	}
 
 	return fbi->map_cpu ? 0 : -ENOMEM;
@@ -1761,10 +1802,12 @@ static int __devinit pxafb_probe(struct platform_device *dev)
 	}
 
 	/* Initialize video memory */
-	ret = pxafb_map_video_memory(fbi);
-	if (ret) {
+	ret = pxafb_map_video_memory(fbi, inf);
+	if (ret == -ENODEV) {
+		dev_err(&dev->dev, "Failed device binding: %d\n", ret);
+		goto failed_free_mem;
+	} else if (ret) {
 		dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
-		ret = -ENOMEM;
 		goto failed_free_io;
 	}
 
@@ -1836,6 +1879,8 @@ failed_free_cmap:
 failed_free_irq:
 	free_irq(irq, fbi);
 failed_free_mem:
+	if (inf->unshare_video_mem)
+		inf->unshare_video_mem(inf->extra_data);
 	dma_free_writecombine(&dev->dev, fbi->map_size,
 			fbi->map_cpu, fbi->map_dma);
 failed_free_io:
@@ -1856,6 +1901,7 @@ static int __devexit pxafb_remove(struct platform_device *dev)
 	struct resource *r;
 	int irq;
 	struct fb_info *info;
+	struct pxafb_mach_info *inf;
 
 	if (!fbi)
 		return 0;
@@ -1872,6 +1918,9 @@ static int __devexit pxafb_remove(struct platform_device *dev)
 	irq = platform_get_irq(dev, 0);
 	free_irq(irq, fbi);
 
+	inf = dev->dev.platform_data;
+	if (inf->unshare_video_mem)
+		inf->unshare_video_mem(inf->extra_data);
 	dma_free_writecombine(&dev->dev, fbi->map_size,
 					fbi->map_cpu, fbi->map_dma);
 
diff --git a/include/asm-arm/arch-pxa/pxafb.h b/include/asm-arm/arch-pxa/pxafb.h
index daf018d..c8c3e84 100644
--- a/include/asm-arm/arch-pxa/pxafb.h
+++ b/include/asm-arm/arch-pxa/pxafb.h
@@ -139,9 +139,17 @@ struct pxafb_mach_info {
 	 * All other bits in LCCR4 should be left alone.
 	 */
 	u_int		lccr4;
+	unsigned int	custom_lccr_bpp; /* custom bpp setting */
+	/* size of extra mem needed for secondary driver */
+	unsigned int	extra_video_mem;
+	void		*extra_data; /* extra data for secondary */
 	void (*pxafb_backlight_power)(int);
 	void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
 	void (*smart_update)(struct fb_info *);
+	/* share_video_mem allows client drivers to get our framebuffer */
+	int (*share_video_mem)(char __iomem *, dma_addr_t, struct module *,
+				void *);
+	void (*unshare_video_mem)(void *);
 };
 void set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info);
 void set_pxa_fb_parent(struct device *parent_dev);
-- 
1.5.3.6


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help