Thread (3 messages) 3 messages, 3 authors, 2009-05-18

Re: [PATCH 01/11] video: Add support for the Avionic Design Xanthos framebuffer.

From: Mike Rapoport <hidden>
Date: 2009-05-14 15:05:47

(cc'ed fbdev list and maintainer)

Thierry Reding wrote:
quoted hunk
This patch adds support for the Avionic Design Xanthos framebuffer.

Signed-off-by: Thierry Reding <redacted>
---
 drivers/video/Kconfig         |   12 +
 drivers/video/Makefile        |    1 +
 drivers/video/adxfb/Makefile  |    1 +
 drivers/video/adxfb/adxfb.h   |  120 +++++++++++
 drivers/video/adxfb/fb.c      |  456 +++++++++++++++++++++++++++++++++++++++++
 drivers/video/adxfb/overlay.c |  190 +++++++++++++++++
 drivers/video/adxfb/scaler.c  |  231 +++++++++++++++++++++
 include/video/Kbuild          |    1 +
 include/video/adxfb.h         |  128 ++++++++++++
 9 files changed, 1140 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/adxfb/Makefile
 create mode 100644 drivers/video/adxfb/adxfb.h
 create mode 100644 drivers/video/adxfb/fb.c
 create mode 100644 drivers/video/adxfb/overlay.c
 create mode 100644 drivers/video/adxfb/scaler.c
 create mode 100644 include/video/adxfb.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7826bdc..976238f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1678,6 +1678,18 @@ config CARMINE_DRAM_CUSTOM
 	  Use custom board timings.
 endchoice
 
+config FB_ADX
+	tristate "Avionic Design Xanthos framebuffer support"
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  Framebuffer driver for the LCD controller in Avionic Design
+	  Xanthos boards.
+
+	  If in doubt, say N.
+
 config FB_AU1100
 	bool "Au1100 LCD Driver"
 	depends on (FB = y) && MIPS && SOC_AU1100
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index d8d0be5..4de52a5 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_FB_OMAP)             += omap/
 obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
 obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 obj-$(CONFIG_FB_MB862XX)	  += mb862xx/
+obj-$(CONFIG_FB_ADX)              += adxfb/
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
diff --git a/drivers/video/adxfb/Makefile b/drivers/video/adxfb/Makefile
new file mode 100644
index 0000000..389d65c
--- /dev/null
+++ b/drivers/video/adxfb/Makefile
@@ -0,0 +1 @@
+obj-y	+= fb.o overlay.o scaler.o
diff --git a/drivers/video/adxfb/adxfb.h b/drivers/video/adxfb/adxfb.h
new file mode 100644
index 0000000..d6535c2
--- /dev/null
+++ b/drivers/video/adxfb/adxfb.h
@@ -0,0 +1,120 @@
+/*
+ * linux/drivers/video/adxfb/adxfb.h
+ *
+ * Copyright (C) 2007-2008 Avionic Design Development GmbH
+ * Copyright (C) 2008-2009 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Written by Thierry Reding <thierry.reding@avionic-design.de>
+ */
+
+#ifndef _DRIVERS_VIDEO_ADXFB_ADXFB_H
+#define _DRIVERS_VIDEO_ADXFB_ADXFB_H 1
+
+#include <linux/spinlock.h>
+#include <video/adxfb.h>
+
+/**
+ * struct adxfb_info - Avionic Design Xanthos framebuffer info structure
+ * @palette:		VGA palette storage
+ * @io_base:		memory-mapped base address for graphics controller
+ * @scaler_base:	memory-mapped base address for scaler
+ * @ioctl:		machine-specific I/O control handler
+ */
+struct adxfb_info {
+	u32 palette[16];
+
+	void __iomem *io_base;
+	void __iomem *scaler_base;
+	spinlock_t lock;
+
+	int (*ioctl)(struct fb_info *info, unsigned int command,
+			unsigned long arg);
+};
+
+#define to_adxfb_info(info) ((struct adxfb_info *)(info)->par)
+
+/* register definitions */
+#define ADXFB_CONTROL			0x000
+#define ADXFB_CONTROL_ENABLE		(1 <<  0)
+#define ADXFB_CONTROL_SYNC		(1 <<  1)
+#define ADXFB_CONTROL_DOUBLE_Y		(1 <<  2)
+#define ADXFB_CONTROL_HALVE_X		(1 <<  3)
+#define ADXFB_CONTROL_TRIPLE_Y		(1 <<  4)
+#define ADXFB_CONTROL_LOCK		(1 << 31)
+#define ADXFB_OVERLAY_CONTROL		0x008
+#define ADXFB_OVERLAY_CONTROL_OVERLAY	(1 << 0)
+#define ADXFB_OVERLAY_CONTROL_ALPHA	(1 << 1)
+#define ADXFB_OVERLAY_START		0x010
+#define ADXFB_OVERLAY_END		0x018
+#define ADXFB_OVERLAY_PAGE0_START	0x020
+#define ADXFB_OVERLAY_PAGE0_END		0x028
+#define ADXFB_OVERLAY_PAGE0_SIZE	0x030
+#define ADXFB_OVERLAY_PAGE1_START	0x038
+#define ADXFB_OVERLAY_PAGE1_END		0x040
+#define ADXFB_OVERLAY_PAGE1_SIZE	0x048
+#define ADXFB_OVERLAY_LEVEL		0x050
+#define ADXFB_ALPHA_START		0x058
+#define ADXFB_ALPHA_END			0x060
+#define ADXFB_ALPHA_PAGE1_START		0x068
+#define ADXFB_ALPHA_PAGE1_END		0x070
+#define ADXFB_ALPHA_PAGE1_SIZE		0x078
+#define ADXFB_PAGE0_BASE		0x080
+#define ADXFB_PAGE0_FORMAT		0x088
+#define ADXFB_PAGE0_RESOLUTION		0x090
+#define ADXFB_PAGE0_RESOLUTION_BYTE	0x098
+#define ADXFB_PAGE0_SIZE		0x0a0
+#define ADXFB_PAGE1_BASE		0x0b0
+#define ADXFB_PAGE1_FORMAT		0x0b8
+#define ADXFB_PAGE1_RESOLUTION		0x0c0
+#define ADXFB_PAGE1_RESOLUTION_PHYSICAL	0x0c8
+#define ADXFB_PAGE1_RESOLUTION_VIRTUAL	0x0d0
+#define ADXFB_PAGE1_SIZE_PHYSICAL	0x0d8
+#define ADXFB_PAGE1_SIZE_VIRTUAL	0x0e0
+#define ADXFB_PAGE1_OFFSET		0x0e8
+#define ADXFB_PAGE1_SECONDARY_BASE	0x0f0
+#define ADXFB_COLOR_OFFSET		0x100
+#define ADXFB_COLOR_MUL			0x108
+
+/* page format (ADXFB_PAGE0_FORMAT, ADXFB_PAGE1_FORMAT) */
+#define ADXFB_FMT_NONE		0
+#define ADXFB_FMT_GRAYSCALE_8	1
+#define ADXFB_FMT_RGB_565	2
+#define ADXFB_FMT_RGB_888	3
+#define ADXFB_FMT_RGBA_8888	4
+
+/**
+ * adxfb_r32() - read 32-bit register
+ * @fb:		framebuffer context
+ * @offset:	relative register offset
+ */
+static inline u32 adxfb_r32(struct adxfb_info *fb, unsigned long offset)
+{
+	return ioread32(fb->io_base + offset);
+}
+
+/**
+ * adxfb_w32() - write 32-bit register
+ * @fb:		framebuffer context
+ * @offset:	relative register offset
+ * @value:	value to write to register
+ */
+static inline void adxfb_w32(struct adxfb_info *fb, unsigned long offset,
+		u32 value)
+{
+	iowrite32(value, fb->io_base + offset);
+}
+
+extern int adxfb_scaler_set_mode(struct fb_info *info,
+		struct adxfb_scaler_mode *mode);
+extern int adxfb_scaler_get_mode(struct fb_info *info,
+		struct adxfb_scaler_mode *mode);
+
+extern int adxfb_overlay_enable(struct fb_info *info, unsigned long flags);
+extern int adxfb_overlay_set_viewport(struct fb_info *info,
+		struct adxfb_viewport *viewport);
+
+#endif /* !_DRIVERS_VIDEO_ADXFB_ADXFB_H */
diff --git a/drivers/video/adxfb/fb.c b/drivers/video/adxfb/fb.c
new file mode 100644
index 0000000..755cdce
--- /dev/null
+++ b/drivers/video/adxfb/fb.c
@@ -0,0 +1,456 @@
+/*
+ * linux/drivers/video/adxfb/fb.c
+ *
+ * Copyright (C) 2007-2008 Avionic Design Development GmbH
+ * Copyright (C) 2008-2009 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Written by Thierry Reding <thierry.reding@avionic-design.de>
+ */
+
+#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+
+#include "adxfb.h"
+
+/**
+ * adxfb_setcolreg() - set color register
+ * @regno:	register number to set
+ * @red:	red color component
+ * @green:	green color component
+ * @blue:	blue color component
+ * @transp:	transparency component
+ * @info:	framebuffer context
+ */
+static int adxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+		unsigned blue, unsigned transp, struct fb_info *info)
+{
+	if ((regno >= info->cmap.len) || (regno > 255))
+		return 1;
+
+#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		if (regno < 16) {
+			((struct adxfb_info *)info->par)->palette[regno] =
+				(CNVT_TOHW(red, info->var.red.length)
+					<< info->var.red.offset) |
+				(CNVT_TOHW(green, info->var.green.length)
+					<< info->var.green.offset) |
+				(CNVT_TOHW(blue, info->var.blue.length)
+					<< info->var.blue.offset) |
+				(CNVT_TOHW(transp, info->var.transp.length)
+					<< info->var.transp.offset);
+		}
+		break;
+
+	default:
+		dev_err(info->dev, "bad depth: %u\n", info->var.bits_per_pixel);
+		break;
+	}
+#undef CNVT_TOHW
+
+	return 0;
+}
+
+/**
+ * adxfb_ioctl() - handle I/O controls
+ * @info:	framebuffer context
+ * @command:	I/O control code
+ * @arg:	I/O control argument
+ */
+static int adxfb_ioctl(struct fb_info *info, unsigned int command,
+		unsigned long arg)
+{
+	struct adxfb_info *fb = to_adxfb_info(info);
+	void __user *argp = (void __user *)arg;
+	struct adxfb_scaler_mode mode;
+	struct adxfb_viewport viewport;
+	int err = 0;
+
+	switch (command) {
+	case ADXFB_IOCTL_SCALER_SET_MODE:
+		if (copy_from_user(&mode, argp, sizeof(mode)))
+			return -EFAULT;
+
+		err = adxfb_scaler_set_mode(info, &mode);
+		if (err < 0)
+			return err;
+
+		break;
+
+	case ADXFB_IOCTL_SCALER_GET_MODE:
+		err = adxfb_scaler_get_mode(info, &mode);
+		if (err < 0)
+			return err;
+
+		if (copy_to_user(argp, &mode, sizeof(mode)))
+			return -EFAULT;
+
+		break;
+
+	case ADXFB_IOCTL_OVERLAY_ENABLE:
+		err = adxfb_overlay_enable(info, arg);
+		if (err < 0)
+			return err;
+
+		break;
+
+	case ADXFB_IOCTL_OVERLAY_SET_VIEWPORT:
+		if (copy_from_user(&viewport, argp, sizeof(viewport)))
+			return -EFAULT;
+
+		err = adxfb_overlay_set_viewport(info, &viewport);
+		if (err < 0)
+			return err;
+
+		break;
+
+	default:
+		if (fb && fb->ioctl)
+			return fb->ioctl(info, command, arg);
+
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * adxfb_mmap() - map framebuffer memory
+ * @info:	framebuffer context
+ * @vma:	list of memory pages to map
+ */
+static int adxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	unsigned long off, start, len;
+	int retval = 0;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+	start = info->fix.smem_start;
+	len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len;
+	start &= PAGE_MASK;
+
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	vma->vm_flags |= VM_IO;
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	retval = io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+			vma->vm_end - vma->vm_start, vma->vm_page_prot);
+	if (retval)
+		return retval;
+
+	return 0;
+}
+
+/**
+ * adxfb_check_var() - check variables
+ * @var:	variable screen information
+ * @info:	framebuffer context
+ */
+static int adxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	/* TODO: implement something useful */
+	return 0;
+}
+
+/* framebuffer operations */
+static struct fb_ops adxfb_ops = {
+	.owner = THIS_MODULE,
+	.fb_setcolreg = adxfb_setcolreg,
+	.fb_ioctl = adxfb_ioctl,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_mmap = adxfb_mmap,
+	.fb_check_var = adxfb_check_var,
+};
+
+/**
+ * adxfb_set_bitfield() - initialize a bitfield structure
+ * @bf:		bitfield structure to fill
+ * @offset:	value for offset field
+ * @length:	value for length field
+ * @msb_right:	value for msb_right field
+ */
+static void adxfb_set_bitfield(struct fb_bitfield *bf, u32 offset, u32 length,
+		u32 msb_right)
+{
+	bf->offset = offset;
+	bf->length = length;
+	bf->msb_right = msb_right;
+}
+
+/**
+ * adxfb_fmt_to_mode() - convert format type to video mode parameters
+ * @fmt:	ADXFB format type
+ * @mode:	video mode
+ */
+static int adxfb_fmt_to_mode(u8 fmt, struct adxfb_mode_info *mode)
+{
+	switch (fmt) {
+	case ADXFB_FMT_GRAYSCALE_8:
+		/* FIXME: use correct values here */
+		adxfb_set_bitfield(&mode->red,   5, 3, 0);
+		adxfb_set_bitfield(&mode->green, 3, 2, 0);
+		adxfb_set_bitfield(&mode->blue,  0, 3, 0);
+		mode->bpp = 8;
+		break;
+
+	case ADXFB_FMT_RGB_565:
+		adxfb_set_bitfield(&mode->red,   11, 5, 0);
+		adxfb_set_bitfield(&mode->green,  5, 6, 0);
+		adxfb_set_bitfield(&mode->blue,   0, 5, 0);
+		mode->bpp = 16;
+		break;
+
+	case ADXFB_FMT_RGB_888:
+		/* FIXME: verify that these are correct values */
+		adxfb_set_bitfield(&mode->red,   16, 8, 0);
+		adxfb_set_bitfield(&mode->green,  8, 8, 0);
+		adxfb_set_bitfield(&mode->blue,   0, 8, 0);
+		mode->bpp = 24;
+		break;
+
+	case ADXFB_FMT_RGBA_8888:
+		/* FIXME: verify that these are correct values */
+		adxfb_set_bitfield(&mode->red,   16, 8, 0);
+		adxfb_set_bitfield(&mode->green,  8, 8, 0);
+		adxfb_set_bitfield(&mode->blue,   0, 8, 0);
+		mode->bpp = 32;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * adxfb_get_mach_mode() - obtain the current video mode
+ * @fb:		framebuffer context
+ * @mode:	structure to return the video mode in
+ */
+static int adxfb_get_mach_mode(struct adxfb_info *fb,
+		struct adxfb_mode_info *mode)
+{
+	u32 size;
+	u16 resx;
+	u16 resy;
+	u8 fmt;
+
+	size = adxfb_r32(fb, ADXFB_PAGE0_RESOLUTION);
+	resx = (size >> 16) & 0x7ff;
+	resy = (size >>  0) & 0x7ff;
+
+	fmt = adxfb_r32(fb, ADXFB_PAGE0_FORMAT) & 0xff;
+
+	mode->xres = resx;
+	mode->yres = resy;
+
+	return adxfb_fmt_to_mode(fmt, mode);
+}
+
+/**
+ * adxfb_probe() - initialize the framebuffer device
+ * @pdev:	platform device
+ */
+static int __init adxfb_probe(struct platform_device *pdev)
+{
+	struct adxfb_mach_info *mach_info = pdev->dev.platform_data;
+	struct adxfb_mode_info mode;
+	struct adxfb_info *fb;
+	struct fb_info *info;
+	struct resource *res;
+	int err = 0;
+
+	info = framebuffer_alloc(sizeof(struct adxfb_info), &pdev->dev);
+	if (!info) {
+		dev_err(&pdev->dev, "failed to allocate framebuffer device\n");
+		return -ENOMEM;
+	}
+
+	fb = to_adxfb_info(info);
+	spin_lock_init(&fb->lock);
+
+	if (mach_info)
+		fb->ioctl = mach_info->ioctl;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get graphics controller I/O "
+				"memory resource\n");
+		err = -ENXIO;
+		goto free;
+	}
+
+	res = devm_request_mem_region(&pdev->dev, res->start,
+			res->end - res->start + 1, res->name);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to request graphics controller "
+				"I/O memory region\n");
+		err = -ENXIO;
+		goto free;
+	}
+
+	fb->io_base = devm_ioremap_nocache(&pdev->dev, res->start,
+			res->end - res->start + 1);
+	if (!fb->io_base) {
+		err = -ENXIO;
+		goto free;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get scaler I/O memory "
+				"resource\n");
+		err = -ENXIO;
+		goto free;
+	}
+
+	res = devm_request_mem_region(&pdev->dev, res->start,
+			res->end - res->start + 1, res->name);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to request scaler I/O memory "
+				"region\n");
+		err = -ENXIO;
+		goto free;
+	}
+
+	fb->scaler_base = devm_ioremap_nocache(&pdev->dev, res->start,
+			res->end - res->start + 1);
+	if (!fb->scaler_base) {
+		err = -ENXIO;
+		goto free;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get framebuffer I/O memory "
+				"resource\n");
+		err = -ENXIO;
+		goto free;
+	}
+
+	res = devm_request_mem_region(&pdev->dev, res->start,
+			res->end - res->start + 1, res->name);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to request framebuffer I/O "
+				"memory region\n");
+		err = -ENXIO;
+		goto free;
+	}
+
+	info->screen_base = devm_ioremap_nocache(&pdev->dev, res->start,
+			res->end - res->start + 1);
+	if (!info->screen_base) {
+		err = -ENXIO;
+		goto free;
+	}
+
+	/* TODO: add some checking for these parameters */
+	memset(&mode, 0, sizeof(mode));
+	adxfb_get_mach_mode(fb, &mode);
+
+	snprintf(info->fix.id, sizeof(info->fix.id), "adxfb");
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->fix.line_length = mode.xres * (mode.bpp / 8);
+	info->fix.smem_start = res->start;
+	info->fix.smem_len = res->end - res->start + 1;
+
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.vmode = FB_VMODE_NONINTERLACED;
+	info->var.xres = mode.xres;
+	info->var.yres = mode.yres;
+	info->var.xres_virtual = mode.xres;
+	info->var.yres_virtual = mode.yres;
+	info->var.bits_per_pixel = mode.bpp;
+	info->var.red = mode.red;
+	info->var.green = mode.green;
+	info->var.blue = mode.blue;
+	info->var.width = mode.xres;
+	info->var.height = mode.yres;
+
+	info->fbops = &adxfb_ops;
+	info->flags = FBINFO_DEFAULT;
+	info->pseudo_palette = fb->palette;
+
+	err = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (err < 0) {
+		err = -ENOMEM;
+		goto free;
+	}
+
+	err = register_framebuffer(info);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to register framebuffer\n");
+		goto cmap;
+	}
+
+	dev_info(info->dev, "ADX framebuffer initialized\n");
+	platform_set_drvdata(pdev, info);
+	return 0;
+
+cmap:
+	fb_dealloc_cmap(&info->cmap);
+free:
+	framebuffer_release(info);
+	return err;
+}
+
+/**
+ * adxfb_remove() - shutdown the framebuffer device
+ * @pdev:	platform device
+ */
+static int adxfb_remove(struct platform_device *pdev)
+{
+	struct fb_info *info = platform_get_drvdata(pdev);
+	unregister_framebuffer(info);
+	return 0;
+}
+
+/* ADXFB platform driver */
+static struct platform_driver adxfb_driver = {
+	.probe = adxfb_probe,
+	.remove = adxfb_remove,
+	.driver = {
+		.name = "adxfb",
+	},
+};
+
+/**
+ * adxfb_init() - module initialization
+ */
+int __init adxfb_init(void)
+{
+	return platform_driver_register(&adxfb_driver);
+}
+
+/**
+ * adxfb_exit() - module cleanup
+ */
+void __exit adxfb_exit(void)
+{
+	platform_driver_unregister(&adxfb_driver);
+}
+
+module_init(adxfb_init);
+module_exit(adxfb_exit);
+
+MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
+MODULE_DESCRIPTION("Avionic Design Xanthos framebuffer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/adxfb/overlay.c b/drivers/video/adxfb/overlay.c
new file mode 100644
index 0000000..52d1755
--- /dev/null
+++ b/drivers/video/adxfb/overlay.c
@@ -0,0 +1,190 @@
+/*
+ * linux/drivers/video/adxfb/overlay.c
+ *
+ * Copyright (C) 2008 Avionic Design Development GmbH
+ * Copyright (C) 2008 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Written by Thierry Reding <thierry.reding@avionic-design.de>
+ */
+
+#include <linux/fb.h>
+#include "adxfb.h"
+
+/* format to bit-depth table */
+struct fmt_bpp {
+	u8  fmt;
+	int bpp;
+};
+
+static struct fmt_bpp formats[] = {
+	{ ADXFB_FMT_GRAYSCALE_8,  8 },
+	{ ADXFB_FMT_RGB_565,     16 },
+	{ ADXFB_FMT_RGB_888,     24 },
+	{ ADXFB_FMT_RGBA_8888,   32 },
+};
+
+/**
+ * fmt_to_bpp() - obtain the bit-depth for a given page format
+ * @fmt:	format of which to retrieve the bit-depth
+ */
+static int fmt_to_bpp(u8 fmt)
+{
+	int bpp = 0, i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (fmt == formats[i].fmt) {
+			bpp = formats[i].bpp;
+			break;
+		}
+	}
+
+	return bpp;
+}
+
+/**
+ * adxfb_disable() - disable the graphics controller
+ * @fb:		framebuffer context
+ */
+static inline void adxfb_disable(struct adxfb_info *fb)
+{
+	u32 ctrl;
+
+	spin_lock(&fb->lock);
+
+	ctrl = adxfb_r32(fb, ADXFB_CONTROL);
+	ctrl &= ~ADXFB_CONTROL_ENABLE;
+	ctrl |=  ADXFB_CONTROL_LOCK;
+	adxfb_w32(fb, ADXFB_CONTROL, ctrl);
+
+	spin_unlock(&fb->lock);
+}
+
+/**
+ * adxfb_enable() - enable the graphics controller
+ * @fb:		framebuffer context
+ */
+static inline void adxfb_enable(struct adxfb_info *fb)
+{
+	u32 ctrl;
+
+	spin_lock(&fb->lock);
+
+	ctrl = adxfb_r32(fb, ADXFB_CONTROL);
+	ctrl &= ~ADXFB_CONTROL_LOCK;
+	ctrl |=  ADXFB_CONTROL_ENABLE;
+	adxfb_w32(fb, ADXFB_CONTROL, ctrl);
+
+	spin_unlock(&fb->lock);
+}
+
+/**
+ * adxfb_overlay_enable() - enable the overlay window
+ * @info:	framebuffer context
+ * @flags:	flags for enabling/disabling
+ */
+int adxfb_overlay_enable(struct fb_info *info, unsigned long flags)
+{
+	struct adxfb_info *fb = to_adxfb_info(info);
+	u32 ctrl;
+
+	if (!info)
+		return -EINVAL;
+
+	spin_lock(&fb->lock);
+
+	ctrl = adxfb_r32(fb, ADXFB_OVERLAY_CONTROL);
+
+	if (flags & ADXFB_OVERLAY_ENABLE)
+		ctrl |=  ADXFB_OVERLAY_CONTROL_OVERLAY;
+	else
+		ctrl &= ~ADXFB_OVERLAY_CONTROL_OVERLAY;
+
+	adxfb_w32(fb, ADXFB_OVERLAY_CONTROL, ctrl);
+
+	spin_unlock(&fb->lock);
+	return 0;
+}
+
+/**
+ * adxfb_overlay_set_viewport() - set the region for the overlay window
+ * @info:	framebuffer context
+ * @viewport:	new screen region for the overlay window
+ */
+int adxfb_overlay_set_viewport(struct fb_info *info,
+		struct adxfb_viewport *viewport)
+{
+	struct adxfb_info *fb = to_adxfb_info(info);
+	int sx, sy, dx, dy, ex, ey;
+	int p0dx, p0dy;
+	int p0ps, p1ps;
+	u32 size;
+
+	if (!info || !viewport)
+		return -EINVAL;
+
+	sx = viewport->x & ~0x3;
+	sy = viewport->y & ~0x3;
+	dx = viewport->width & ~0x3;
+	dy = viewport->height & ~0x3;
+	ex = sx + dx - 1;
+	ey = sy + dy - 1;
+
+	size = adxfb_r32(fb, ADXFB_PAGE0_RESOLUTION);
+	p0dx = (size >> 16) & 0x7ff;
+	p0dy = (size >>  0) & 0x7ff;
+
+	size = adxfb_r32(fb, ADXFB_PAGE0_FORMAT) & 0xff;
+	p0ps = fmt_to_bpp(size) / 8;
+
+	size = adxfb_r32(fb, ADXFB_PAGE1_FORMAT) & 0xff;
+	p1ps = fmt_to_bpp(size) / 8;
+
+	adxfb_disable(fb);
+	spin_lock(&fb->lock);
+
+	size = (((dx + 0) & 0x7ff) << 16) | (dy & 0x7ff);
+	adxfb_w32(fb, ADXFB_PAGE1_RESOLUTION, size);
+
+	/* FIXME: (dx + 4) is a hack! */
+	size = ((((dx + 4) * p1ps) & 0x1fff) << 16) | (dy & 0x7ff);
+	adxfb_w32(fb, ADXFB_PAGE1_RESOLUTION_PHYSICAL, size);
+
+	size = ((((p0dx + 0) * p1ps) & 0x1fff) << 16) | (p0dy & 0x7ff);
+	adxfb_w32(fb, ADXFB_PAGE1_RESOLUTION_VIRTUAL, size);
+
+	adxfb_w32(fb, ADXFB_PAGE1_SIZE_PHYSICAL, dx * dy * p1ps);
+	adxfb_w32(fb, ADXFB_PAGE1_SIZE_VIRTUAL, p0dx * p0dy * p1ps);
+
+	size = ((sx & 0x7ff) << 16) | (sy & 0x7ff);
+	adxfb_w32(fb, ADXFB_OVERLAY_START, size);
+
+	size = ((ex & 0x7ff) << 16) | (ey & 0x7ff);
+	adxfb_w32(fb, ADXFB_OVERLAY_END, size);
+
+	size = (((sx * p0ps) & 0x1fff) << 16) | (sy & 0x7ff);
+	adxfb_w32(fb, ADXFB_OVERLAY_PAGE0_START, size);
+	adxfb_w32(fb, ADXFB_PAGE1_OFFSET, size);
+
+	size = (((ex * p0ps) & 0x1fff) << 16) | (ey & 0x7ff);
+	adxfb_w32(fb, ADXFB_OVERLAY_PAGE0_END, size);
+
+	size = (((sx * p1ps) & 0x1fff) << 16) | (sy & 0x7ff);
+	adxfb_w32(fb, ADXFB_OVERLAY_PAGE1_START, size);
+
+	size = (((ex * p1ps) & 0x1fff) << 16) | (ey & 0x7ff);
+	adxfb_w32(fb, ADXFB_OVERLAY_PAGE1_END, size);
+
+	adxfb_w32(fb, ADXFB_OVERLAY_PAGE0_SIZE, dx * dy * p0ps);
+	adxfb_w32(fb, ADXFB_OVERLAY_PAGE1_SIZE, dx * dy * p1ps);
+
+	adxfb_w32(fb, ADXFB_OVERLAY_LEVEL, 0xff);
+
+	spin_unlock(&fb->lock);
+	adxfb_enable(fb);
+
+	return 0;
+}
diff --git a/drivers/video/adxfb/scaler.c b/drivers/video/adxfb/scaler.c
new file mode 100644
index 0000000..5559156
--- /dev/null
+++ b/drivers/video/adxfb/scaler.c
@@ -0,0 +1,231 @@
+/*
+ * linux/drivers/video/adxfb/fb.c
+ *
+ * Copyright (C) 2007-2008 Avionic Design Development GmbH
+ * Copyright (C) 2008 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Written by Thierry Reding <thierry.reding@avionic-design.de>
+ */
+
+#include <linux/fb.h>
+#include "adxfb.h"
+
+/**
+ * struct scaler_mode - scaler mode values
+ * @uh:		horizontal up scaling factor
+ * @dh:		horizontal down scaling factor
+ * @uv:		vertical up scaling factor
+ * @dv:		vertical down scaling factor
+ * @ox:		original horizontal resolution
+ * @oy:		original vertical resolution
+ * @tx:		target horizontal resolution
+ * @ty:		target vertical resolution
+ */
+struct scaler_mode {
+	u16 uh, dh;
+	u16 uv, dv;
+	u16 ox, oy;
+	u16 tx, ty;
+};
+
+/* register definitions */
+#define SCALER_MODE				0x000
+#define SCALER_MODE_ENABLE_X	(1 <<  0)
+#define SCALER_MODE_ENABLE_Y	(1 <<  1)
+#define SCALER_MODE_BYPASS_X	(1 <<  2)
+#define SCALER_MODE_BYPASS_Y	(1 <<  3)
+#define SCALER_MODE_RGB_888	(1 <<  4)
+#define SCALER_MODE_LOWPASS	(1 <<  7)
+#define SCALER_MODE_SYNC	(1 <<  8)
+#define SCALER_MODE_RESET	(1 << 15)
+#define SCALER_MODE_LOCK	(1 << 31)
+#define SCALER_UH				0x008
+#define SCALER_DH				0x010
+#define SCALER_UV				0x030
+#define SCALER_DV				0x038
+#define SCALER_ORIGIN_X				0x040
+#define SCALER_ORIGIN_Y				0x048
+#define SCALER_OFFSET_X				0x050
+#define SCALER_OFFSET_Y				0x058
+#define SCALER_TARGET_X				0x060
+#define SCALER_TARGET_Y				0x068
+#define SCALER_ORIGIN_STRIDE			0x070
+#define SCALER_TARGET_STRIDE			0x078
+#define SCALER_ORIGIN_SIZE			0x080
+#define SCALER_TARGET_SIZE			0x088
+#define SCALER_PRIMARY_PRE_TARGET_ADDR		0x090
+#define SCALER_PRIMARY_TARGET_ADDR		0x098
+#define SCALER_SECONDARY_PRE_TARGET_ADDR	0x0a0
+#define SCALER_SECONDARY_TARGET_ADDR		0x0a8
+
+/**
+ * scaler_r32() - read a 32-bit register
+ * @fb:		framebuffer context
+ * @offset:	relative register offset
+ */
+static inline u32 scaler_r32(struct adxfb_info *fb, unsigned long offset)
+{
+	return ioread32(fb->scaler_base + offset);
+}
+
+/**
+ * scaler_w32() - write a 32-bit register
+ * @fb:		framebuffer context
+ * @offset:	relative register offset
+ * @value:	value to write to the register
+ */
+static inline void scaler_w32(struct adxfb_info *fb, unsigned long offset,
+		u32 value)
+{
+	iowrite32(value, fb->scaler_base + offset);
+}
+
+/**
+ * scaler_enable() - enable the scaling unit
+ * @fb:		framebuffer context
+ */
+static inline void scaler_enable(struct adxfb_info *fb)
+{
+	u32 mode;
+
+	spin_lock(&fb->lock);
+
+	mode = scaler_r32(fb, SCALER_MODE);
+	mode |=  SCALER_MODE_ENABLE_X;
+	mode |=  SCALER_MODE_ENABLE_Y;
+	mode &= ~SCALER_MODE_LOCK;
+	scaler_w32(fb, SCALER_MODE, mode);
+
+	spin_unlock(&fb->lock);
+}
+
+/**
+ * scaler_disable() - disable the scaling unit
+ * @fb:		framebuffer context
+ */
+static inline void scaler_disable(struct adxfb_info *fb)
+{
+	u32 mode;
+
+	spin_lock(&fb->lock);
+
+	mode = scaler_r32(fb, SCALER_MODE);
+	mode |=  SCALER_MODE_LOCK;
+	mode &= ~SCALER_MODE_ENABLE_Y;
+	mode &= ~SCALER_MODE_ENABLE_X;
+	scaler_w32(fb, SCALER_MODE, mode);
+
+	spin_unlock(&fb->lock);
+}
+
+/**
+ * find_mode() - match a request to the best mode that can be achieved
+ * @fb:		framebuffer context
+ * @mode:	requested mode
+ */
+static int find_mode(struct adxfb_info *fb, struct scaler_mode *mode)
+{
+	if (!fb || !mode)
+		return -EINVAL;
+
+	if ((mode->tx == 0) || (mode->ty == 0))
+		return 0;
+
+	mode->uh = scaler_r32(fb, SCALER_UH) & 0x7ff;
+	mode->uh = 128; /* FIXME: don't hardcode */
+	mode->uv = scaler_r32(fb, SCALER_UV) & 0x7ff;
+	mode->uv = 128; /* FIXME: don't hardcode */
+
+	mode->dh = (mode->ox * mode->uh) / mode->tx;
+	mode->dv = (mode->oy * mode->uv) / mode->ty;
+
+	mode->tx = (mode->ox * mode->uh) / mode->dh;
+	mode->ty = (mode->oy * mode->uv) / mode->dv;
+
+	/* TODO: check the parameters */
+
+	return 0;
+}
+
+/**
+ * adxfb_scaler_set_mode() - set a given scaler mode
+ * @info:	framebuffer context
+ * @modep:	scaler mode
+ */
+int adxfb_scaler_set_mode(struct fb_info *info,
+		struct adxfb_scaler_mode *modep)
+{
+	struct adxfb_info *fb = to_adxfb_info(info);
+	struct scaler_mode mode;
+	int err, bpp;
+	u32 ctrl;
+
+	memset(&mode, 0, sizeof(mode));
+	mode.ox = modep->origin_x;
+	mode.oy = modep->origin_y;
+	mode.tx = modep->target_x;
+	mode.ty = modep->target_y;
+
+	scaler_disable(fb);
+	spin_lock(&fb->lock);
+
+	err = find_mode(fb, &mode);
+	if (err < 0) {
+		spin_unlock(&fb->lock);
+		scaler_enable(fb);
+		return err;
+	}
+
+	ctrl = scaler_r32(fb, SCALER_MODE);
+	if (ctrl & SCALER_MODE_RGB_888)
+		bpp = 24;
+	else
+		bpp = 16;
+
+	scaler_w32(fb, SCALER_UH, mode.uh);
+	scaler_w32(fb, SCALER_DH, mode.dh);
+	scaler_w32(fb, SCALER_UV, mode.uv);
+	scaler_w32(fb, SCALER_DV, mode.dv);
+
+	scaler_w32(fb, SCALER_OFFSET_X, 0);
+	scaler_w32(fb, SCALER_OFFSET_Y, 0);
+
+	scaler_w32(fb, SCALER_ORIGIN_X, mode.ox);
+	scaler_w32(fb, SCALER_ORIGIN_Y, mode.oy);
+	scaler_w32(fb, SCALER_TARGET_X, mode.tx);
+	scaler_w32(fb, SCALER_TARGET_Y, mode.ty);
+
+	scaler_w32(fb, SCALER_ORIGIN_STRIDE, mode.ox * (bpp / 8));
+	scaler_w32(fb, SCALER_TARGET_STRIDE, mode.tx * (bpp / 8));
+
+	scaler_w32(fb, SCALER_ORIGIN_SIZE, mode.ox * mode.oy * (bpp / 8));
+	scaler_w32(fb, SCALER_TARGET_SIZE, mode.tx * mode.ty * (bpp / 8));
+
+	spin_unlock(&fb->lock);
+	scaler_enable(fb);
+	return 0;
+}
+
+/**
+ * adxfb_scaler_mode() - obtain the current scaler mode
+ * @info:	framebuffer context
+ * @modep:	structure to return the mode in
+ */
+int adxfb_scaler_get_mode(struct fb_info *info, struct adxfb_scaler_mode *modep)
+{
+	struct adxfb_info *fb = to_adxfb_info(info);
+
+	spin_lock(&fb->lock);
+
+	modep->origin_x = scaler_r32(fb, SCALER_ORIGIN_X) & 0x7ff;
+	modep->origin_y = scaler_r32(fb, SCALER_ORIGIN_Y) & 0x7ff;
+	modep->target_x = scaler_r32(fb, SCALER_TARGET_X) & 0x7ff;
+	modep->target_y = scaler_r32(fb, SCALER_TARGET_Y) & 0x7ff;
+
+	spin_unlock(&fb->lock);
+	return 0;
+}
diff --git a/include/video/Kbuild b/include/video/Kbuild
index 0e406f7..72fc9b0 100644
--- a/include/video/Kbuild
+++ b/include/video/Kbuild
@@ -1,2 +1,3 @@
 unifdef-y += sisfb.h uvesafb.h
 unifdef-y += edid.h
+unifdef-y += adxfb.h
diff --git a/include/video/adxfb.h b/include/video/adxfb.h
new file mode 100644
index 0000000..e7ef6d0
--- /dev/null
+++ b/include/video/adxfb.h
@@ -0,0 +1,128 @@
+/*
+ * linux/include/video/adxfb.h
+ *
+ * Copyright (C) 2007-2008 Avionic Design Development GmbH
+ * Copyright (C) 2008-2009 Avionic Design GmbH
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Written by Thierry Reding <thierry.reding@avionic-design.de>
+ */
+
+#ifndef _VIDEO_ADXFB_H
+#define _VIDEO_ADXFB_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+/* overlay control register */
+#define ADXFB_OVERLAY_CONTROL			0x008
+#define ADXFB_OVERLAY_CONTROL_OVERLAY_ENABLE	(1 << 0)
+#define ADXFB_OVERLAY_CONTROL_ALPHA_ENABLE	(1 << 1)
+
+#define ADXFB_PAGE0_BASE			0x080
+
+/* color correction (brightness) register */
+#define ADXFB_COLOR_BRIGHTNESS			0x100
+#define ADXFB_COLOR_BRIGHTNESS_MIN		0x00
+#define ADXFB_COLOR_BRIGHTNESS_MAX		0x7f
+
+/* color correction (contrast) register */
+#define ADXFB_COLOR_CONTRAST			0x108
+#define ADXFB_COLOR_CONTRAST_MIN		0x48
+#define ADXFB_COLOR_CONTRAST_MAX		0x7f
+
+/**
+ * struct adxfb_mode_info - video mode information structure
+ * @xres:	horizontal resolution
+ * @yres:	vertical resolution
+ * @bpp:	pixel depth
+ * @red:	packing for red color component
+ * @green:	packing for green color component
+ * @blue:	packing for blue color component
+ */
+struct adxfb_mode_info {
+	/* mode resolution */
+	u_short xres;
+	u_short yres;
+	u_short bpp;
+
+	/* color packing specification */
+	struct fb_bitfield red;
+	struct fb_bitfield green;
+	struct fb_bitfield blue;
+};
+
+/**
+ * struct adxfb_mach_info - machine-specific information structure
+ * @ioctl:	machine-specific I/O control handler
+ */
+struct adxfb_mach_info {
+	int (*ioctl)(struct fb_info *info, unsigned int command,
+			unsigned long arg);
+};
+#endif /* __KERNEL__ */
+
+/**
+ * struct adxfb_scaler_mode - scaler mode definition structure
+ * @origin_x:	original horizontal resolution
+ * @origin_y:	original vertical resolution
+ * @target_x:	targetted horizontal resolution
+ * @target_y:	targetted vertical resolution
+ */
+struct adxfb_scaler_mode {
+	/* original resolution */
+	__u16 origin_x;
+	__u16 origin_y;
+	/* target resolution */
+	__u16 target_x;
+	__u16 target_y;
+};
+
+/**
+ * struct adxfb_viewport - overlay viewport structure
+ * @x:		horizontal start position of the overlay window
+ * @y:		vertical start position of the overlay window
+ * @width:	width of the overlay window
+ * @height:	height of the overlay window
+ */
+struct adxfb_viewport {
+	/* viewport position */
+	__u16 x;
+	__u16 y;
+	/* viewport resolution */
+	__u16 width;
+	__u16 height;
+};
+
+/* I/O control codes */
+#define ADXFB_IOC_MAGIC 'a'
+
+/* set a new scaler mode */
+#define ADXFB_IOCTL_SCALER_SET_MODE \
+			_IOW(ADXFB_IOC_MAGIC, 0, struct adxfb_scaler_mode)
+/* obtain the current scaler mode */
+#define ADXFB_IOCTL_SCALER_GET_MODE \
+			_IOR(ADXFB_IOC_MAGIC, 1, struct adxfb_scaler_mode)
+/* enable/disable the overlay window */
+#define ADXFB_IOCTL_OVERLAY_ENABLE \
+			_IOW(ADXFB_IOC_MAGIC, 2, unsigned long)
+/* set a new region for the overlay window */
+#define ADXFB_IOCTL_OVERLAY_SET_VIEWPORT \
+			_IOW(ADXFB_IOC_MAGIC, 3, struct adxfb_viewport)
+/* set a new input video standard */
+#define ADXFB_IOCTL_SET_INPUT \
+			_IOW(ADXFB_IOC_MAGIC, 4, unsigned long)
+
+/* ADXFB_IOCTL_OVERLAY_ENABLE flags */
+#define ADXFB_OVERLAY_ENABLE	(1 << 0)	/* enable/disable overlay */
+
+/* ADXFB_IOCTL_SET_INPUT parameters */
+#define ADXFB_INPUT_PAL		(0x00)		/* input is PAL standard */
+#define ADXFB_INPUT_NTSC	(0x01)		/* input is NTSC stardard */
+#define ADXFB_INPUT_MASK	(0xff)		/* mask to extract input */
+
+#endif /* !_VIDEO_ADXFB_H */
-- 
Sincerely yours,
Mike.


-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ:        http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette:  http://www.arm.linux.org.uk/mailinglists/etiquette.php
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help