[PATCH] Xilinx framebuffer device driver - 2nd version

Andrei Konovalov akonovalov at ru.mvista.com
Fri Apr 27 04:31:52 EST 2007


Add support for the video controller IP block included into Xilinx ML300 and
ML403 reference designs.

Signed-off-by: Andrei Konovalov <akonovalov at ru.mvista.com>
---

This patch relies on the "Patchset to establish sanity in Xilinx Virtex support" by Gran Likely to have
the frame buffer device registered on the platform bus. Without this patchset one needs to fill in
the struct platform_device and make sure platform_device_register() is called elsewhere.
The DCR access has been added but not tested - my targets are configured in the "memory mapped IO" way.
I would appreciate if those having the video controller registers accessible as DCRs
test the DCR mode.

This is the 2nd version that addresses what was pointed out by Arnd and Grant.
Please find the interdiff against the 1st version below, and the whole patch attached to this message
Comments are welcome.

Would be nice to get this driver into mainline for the 2.6.22.

Thanks,
Andrei

-----------------------------------------------------------------
Index: linux-2.6.20/drivers/video/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/video/Kconfig
+++ linux-2.6.20/drivers/video/Kconfig
@@ -1648,6 +1648,16 @@ config FB_XILINX_ROTATE
  	bool "Rotate display"
  	depends on FB_XILINX

+config FB_XILINX_SCR_HEIGHT
+	int "Screen height in mm"
+	depends on FB_XILINX
+	default 99
+
+config FB_XILINX_SCR_WIDTH
+	int "Screen width in mm"
+	depends on FB_XILINX
+	default 132
+
  config FB_VIRTUAL
  	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
  	depends on FB
Index: linux-2.6.20/drivers/video/xilinxfb.c
===================================================================
--- linux-2.6.20.orig/drivers/video/xilinxfb.c
+++ linux-2.6.20/drivers/video/xilinxfb.c
@@ -30,6 +30,7 @@
  #include <linux/platform_device.h>

  #include <asm/io.h>
+#include <syslib/virtex_devices.h>

  #define DRIVER_NAME		"xilinxfb"
  #define DRIVER_DESCRIPTION	"Xilinx TFT LCD frame buffer driver"
@@ -97,19 +98,18 @@ static struct fb_var_screeninfo xilinx_f
  	.blue =		{ 0, 8, 0 },
  	.transp =	{ 0, 0, 0 },

-	.activate =	FB_ACTIVATE_NOW,
-	.height = 	99,	/* in mm of NEC NL6448BC20-08 on ML300 */
-	.width =	132	/* in mm of NEC NL6448BC20-08 on ML300 */
+	.activate =	FB_ACTIVATE_NOW
  };

  struct xilinxfb_drvdata {

  	struct fb_info	info;		/* FB driver info record */

-	unsigned long	regs_phys;	/* phys. address of the control registers */
-	u32 		*regs;		/* virt. address of the control registers */
+	u32		regs_phys;	/* phys. address of the control registers */
+	u32 __iomem	*regs;		/* virt. address of the control registers */
+	u32		use_dcr;	/* (use_dcr) ? mtdcr() : out_be32(); */

-	unsigned char	*fb_virt;	/* virt. address of the frame buffer */
+	unsigned char __iomem	*fb_virt;	/* virt. address of the frame buffer */
  	dma_addr_t	fb_phys;	/* phys. address of the frame buffer */

  	u32		pseudo_palette[16];	/* Fake palette of 16 colors */
@@ -118,6 +118,12 @@ struct xilinxfb_drvdata {
  #define to_xilinxfb_drvdata(_info) \
  	container_of(_info, struct xilinxfb_drvdata, info)

+#define xilinx_fb_out_be32(driverdata, offset, val) \
+	if (driverdata->use_dcr) \
+		mtdcr(driverdata->regs_phys + offset, val); \
+	else \
+		out_be32(driverdata->regs + offset, val)
+
  static int
  xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
  	unsigned transp, struct fb_info *fbi)
@@ -153,14 +159,14 @@ xilinx_fb_blank(int blank_mode, struct f
  	switch (blank_mode) {
  	case VESA_NO_BLANKING:
  		/* turn on panel */
-		out_be32(drvdata->regs + REG_CTRL, REG_CTRL_DEFAULT);
+		xilinx_fb_out_be32(drvdata, REG_CTRL, REG_CTRL_DEFAULT);
  		break;

  	case VESA_VSYNC_SUSPEND:
  	case VESA_HSYNC_SUSPEND:
  	case VESA_POWERDOWN:
  		/* turn off panel */
-		out_be32(drvdata->regs + REG_CTRL, 0);
+		xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
  	default:
  		break;

@@ -193,6 +199,8 @@ static struct fb_ops xilinxfb_ops =
  static int
  xilinxfb_drv_probe(struct device *dev)
  {
+	struct platform_device *pdev;
+	struct xilinxfb_platform_data *pdata;
  	struct xilinxfb_drvdata *drvdata;
  	struct resource *regs_res;
  	int retval;
@@ -200,32 +208,41 @@ xilinxfb_drv_probe(struct device *dev)
  	if (!dev)
  		return -EINVAL;

-	drvdata = kmalloc(sizeof(struct xilinxfb_drvdata), GFP_KERNEL);
+	pdev = to_platform_device(dev);
+	pdata = (struct xilinxfb_platform_data *)pdev->dev.platform_data;
+
+	if (pdata == NULL) {
+		printk(KERN_ERR "Couldn't find platform data.\n");
+		return -EFAULT;
+	}
+
+	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
  	if (!drvdata) {
  		printk(KERN_ERR "Couldn't allocate device private record\n");
  		return -ENOMEM;
  	}
-	memset((void*)drvdata, 0, sizeof(struct xilinxfb_drvdata));
  	dev_set_drvdata(dev, (void *)drvdata);

  	/* Map the control registers in */
-	regs_res = platform_get_resource(to_platform_device(dev),
-			IORESOURCE_IO, 0);
+	regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
  	if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) {
  		printk(KERN_ERR "Couldn't get registers resource\n");
  		retval = -EFAULT;
  		goto failed1;
  	}

-	if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) {
-		printk(KERN_ERR "Couldn't lock memory region at 0x%08lX\n",
-			regs_res->start);
-		retval = -EBUSY;
-		goto failed1;
+	drvdata->use_dcr = pdata->use_dcr;
+	if (!drvdata->use_dcr) {
+		if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) {
+			printk(KERN_ERR
+			       "Couldn't lock memory region at 0x%08X\n",
+			       regs_res->start);
+			retval = -EBUSY;
+			goto failed1;
+		}
+		drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8);
  	}
-
  	drvdata->regs_phys = regs_res->start;
-	drvdata->regs = (u32 *) ioremap(regs_res->start, 8);

  	/* Allocate the framebuffer memory */
  	drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE),
@@ -240,10 +257,10 @@ xilinxfb_drv_probe(struct device *dev)
  	memset((void *) drvdata->fb_virt, 0, FB_SIZE);

  	/* Tell the hardware where the frame buffer is */
-	out_be32(drvdata->regs + REG_FB_ADDR, drvdata->fb_phys);
+	xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);

  	/* Turn on the display */
-	out_be32(drvdata->regs + REG_CTRL, REG_CTRL_DEFAULT);
+	xilinx_fb_out_be32(drvdata, REG_CTRL, REG_CTRL_DEFAULT);

  	/* Fill struct fb_info */
  	drvdata->info.screen_base = drvdata->fb_virt;
@@ -260,6 +277,8 @@ xilinxfb_drv_probe(struct device *dev)
  	}

  	drvdata->info.flags = FBINFO_DEFAULT;
+	xilinx_fb_var.height = pdata->screen_height_mm;
+	xilinx_fb_var.width = pdata->screen_width_mm;
  	drvdata->info.var = xilinx_fb_var;

  	/* Register new frame buffer */
@@ -279,8 +298,8 @@ failed3:
  		drvdata->fb_phys);

  	/* Turn off the display */
-	out_be32(drvdata->regs + REG_CTRL, 0);
-	iounmap(drvdata->regs);
+	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+	if (!drvdata->use_dcr) iounmap(drvdata->regs);

  failed2:
  	release_mem_region(regs_res->start, 8);
@@ -314,8 +333,8 @@ xilinxfb_drv_remove(struct device *dev)
  		drvdata->fb_phys);

  	/* Turn off the display */
-	out_be32(drvdata->regs + REG_CTRL, 0);
-	iounmap(drvdata->regs);
+	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+	if (!drvdata->use_dcr) iounmap(drvdata->regs);

  	release_mem_region(drvdata->regs_phys, 8);

Index: linux-2.6.20/arch/ppc/syslib/virtex_devices.c
===================================================================
--- linux-2.6.20.orig/arch/ppc/syslib/virtex_devices.c
+++ linux-2.6.20/arch/ppc/syslib/virtex_devices.c
@@ -90,6 +90,18 @@ struct plat_serial8250_port virtex_seria
  };


+/* ML300/403 reference design framebuffer driver platform data table */
+static struct xilinxfb_platform_data xilinxfb_pdata = {
+#if defined(XPAR_TFT_0_USE_DCR) && (XPAR_TFT_0_USE_DCR != 0)
+	.use_dcr = 1,
+#else
+	.use_dcr = 0,
+#endif
+	.screen_height_mm = CONFIG_FB_XILINX_SCR_HEIGHT,
+	.screen_width_mm = CONFIG_FB_XILINX_SCR_WIDTH,
+};
+
+
  struct platform_device virtex_platform_devices[] = {
  	/* UARTLITE instances */
  #if defined(XPAR_UARTLITE_0_BASEADDR)
@@ -127,6 +139,7 @@ struct platform_device virtex_platform_d
  	{
  		.name		= "xilinxfb",
  		.id		= 0,
+		.dev.platform_data = &xilinxfb_pdata,
  		.num_resources	= 1,
  		.resource = (struct resource[]) {
  			{
Index: linux-2.6.20/arch/ppc/syslib/virtex_devices.h
===================================================================
--- linux-2.6.20.orig/arch/ppc/syslib/virtex_devices.h
+++ linux-2.6.20/arch/ppc/syslib/virtex_devices.h
@@ -13,6 +13,13 @@

  #include <linux/platform_device.h>

+/* ML300/403 reference design framebuffer driver platform data struct */
+struct xilinxfb_platform_data {
+	u32 use_dcr;
+	u32 screen_height_mm;
+	u32 screen_width_mm;
+};
+
  void __init virtex_early_serial_map(void);

  /* Prototype for device fixup routine.  Implement this routine in the
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ppc32-xilinx_fb.patch
Type: text/x-patch
Size: 13819 bytes
Desc: not available
Url : http://ozlabs.org/pipermail/linuxppc-embedded/attachments/20070426/8ff568c2/attachment.bin 


More information about the Linuxppc-embedded mailing list