* Re: [PATCH 01/11] video: Add support for the Avionic Design Xanthos framebuffer.
[not found] <1242294422-10478-1-git-send-email-thierry.reding@avionic-design.de>
@ 2009-05-14 15:05 ` Mike Rapoport
2009-05-16 9:22 ` Krzysztof Helt
0 siblings, 1 reply; 4+ messages in thread
From: Mike Rapoport @ 2009-05-14 15:05 UTC (permalink / raw)
To: Thierry Reding
Cc: Russell King - ARM Linux, linux-arm-kernel, Antonino A. Daplas,
linux-fbdev-devel
(cc'ed fbdev list and maintainer)
Thierry Reding wrote:
> This patch adds support for the Avionic Design Xanthos framebuffer.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> ---
> 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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 01/11] video: Add support for the Avionic Design Xanthos framebuffer.
2009-05-14 15:05 ` [PATCH 01/11] video: Add support for the Avionic Design Xanthos framebuffer Mike Rapoport
@ 2009-05-16 9:22 ` Krzysztof Helt
2009-05-18 8:53 ` [Linux-fbdev-devel] " Thierry Reding
0 siblings, 1 reply; 4+ messages in thread
From: Krzysztof Helt @ 2009-05-16 9:22 UTC (permalink / raw)
To: Mike Rapoport, Thierry Reding
Cc: Russell King - ARM Linux, linux-fbdev-devel, linux-arm-kernel,
Antonino A. Daplas
Hi Thierry
> (cc'ed fbdev list and maintainer)
>
> Thierry Reding wrote:
> > This patch adds support for the Avionic Design Xanthos framebuffer.
> >
> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> > ---
> > 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)
This macro is not needed. The info->par is void* type so
it can be casted to any pointer without warning.
> > +
> > +/* 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;
The fb->ioctl() is the adxfb_ioctl() here. It will cause infinite
recursion if called with unknown ioctl command.
Do not define the clause at all or return the -ENOTTY here.
> > + }
> > +
> > + 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)
> > +{
Your mmap function works exactly the same as the generic fb_mmap() function.
The generic one is not architecture specific. The pgprot_writecombine() does
not exist on some architectures (e.g. MIPS) and your framebuffer was not
defined only for ARMs. Please use the generic mmap (does not define driver's one).
> > + 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 */
The obvious check here is if requested color format is allowed.
> > + 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);
If this is the RGBA mode you should define transparency mask (A).
If the mode has the A component the pixels may not be displayed correctly
(there is no obligation to zero the padding byte).
> > + 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");
I have no comments to rest of the patch so I removed it.
I have a general comment that you should make your driver
conform to the fbdev API (check_var/set_par) for mode setting.
I know you have the scaler, so leave the adfxfb_ioctl to handle it.
If you define the set_par/check_var functions to handle size of
the overlay's input (without scaling) and color format one can
use standard FBIOPUT_VSCREENINFO and
FBIOGET_VSCREENINFO ioctls to set and read your overlay.
If the overlay should be scaled use the custom ioctls to set the
scaling factors only.
Currently, your driver looks like it wants to work around the
fbdev API. See the skeletonfb.c for guidance.
Regards,
Krzysztof
----------------------------------------------------------------------
Audi kilka tysiecy zlotych taniej? Przebieraj wsrod tysiecy ogloszen!
Sprawdz: http://link.interia.pl/f216f
------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables
unlimited royalty-free distribution of the report engine
for externally facing server and web deployment.
http://p.sf.net/sfu/businessobjects
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Linux-fbdev-devel] [PATCH 01/11] video: Add support for the Avionic Design Xanthos framebuffer.
2009-05-16 9:22 ` Krzysztof Helt
@ 2009-05-18 8:53 ` Thierry Reding
[not found] ` <20090518144028.9b8dbc3f.krzysztof.h1@poczta.fm>
0 siblings, 1 reply; 4+ messages in thread
From: Thierry Reding @ 2009-05-18 8:53 UTC (permalink / raw)
To: Krzysztof Helt
Cc: Mike Rapoport, linux-fbdev-devel, Russell King - ARM Linux,
linux-arm-kernel, Antonino A. Daplas
* Krzysztof Helt wrote:
> Hi Thierry
[...]
> > > +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;
>
> The fb->ioctl() is the adxfb_ioctl() here. It will cause infinite
> recursion if called with unknown ioctl command.
> Do not define the clause at all or return the -ENOTTY here.
It is not, actually. The fb->ioctl is supposed to allow board-specific
extensions and is usually NULL. It is not the same as adxfb_ioctl() but is
defined in the adxfb_info structure.
[...]
> I have no comments to rest of the patch so I removed it.
>
> I have a general comment that you should make your driver
> conform to the fbdev API (check_var/set_par) for mode setting.
> I know you have the scaler, so leave the adfxfb_ioctl to handle it.
> If you define the set_par/check_var functions to handle size of
> the overlay's input (without scaling) and color format one can
> use standard FBIOPUT_VSCREENINFO and
> FBIOGET_VSCREENINFO ioctls to set and read your overlay.
> If the overlay should be scaled use the custom ioctls to set the
> scaling factors only.
> Currently, your driver looks like it wants to work around the
> fbdev API. See the skeletonfb.c for guidance.
I was under the impression that FBIOPUT_SCREENINFO was used to set the
framebuffer resolution, which can be (even usually is) different from
that of the overlay. How can I distinguish between which of the video
pages (framebuffer or overlay) should be modified?
> Regards,
> Krzysztof
Thierry
-------------------------------------------------------------------
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 01/11] video: Add support for the Avionic Design Xanthos framebuffer.
[not found] ` <20090518144028.9b8dbc3f.krzysztof.h1@poczta.fm>
@ 2009-05-18 13:55 ` Thierry Reding
0 siblings, 0 replies; 4+ messages in thread
From: Thierry Reding @ 2009-05-18 13:55 UTC (permalink / raw)
To: Krzysztof Helt
Cc: Russell King - ARM Linux, linux-fbdev-devel, linux-arm-kernel,
Antonino A. Daplas
* Krzysztof Helt wrote:
> On Mon, 18 May 2009 10:53:01 +0200
> Thierry Reding <thierry.reding@avionic-design.de> wrote:
[...]
> > > I have no comments to rest of the patch so I removed it.
> > >
> > > I have a general comment that you should make your driver
> > > conform to the fbdev API (check_var/set_par) for mode setting.
> > > I know you have the scaler, so leave the adfxfb_ioctl to handle it.
> > > If you define the set_par/check_var functions to handle size of
> > > the overlay's input (without scaling) and color format one can
> > > use standard FBIOPUT_VSCREENINFO and
> > > FBIOGET_VSCREENINFO ioctls to set and read your overlay.
> > > If the overlay should be scaled use the custom ioctls to set the
> > > scaling factors only.
> > > Currently, your driver looks like it wants to work around the
> > > fbdev API. See the skeletonfb.c for guidance.
> >
> > I was under the impression that FBIOPUT_SCREENINFO was used to set the
> > framebuffer resolution, which can be (even usually is) different from
> > that of the overlay. How can I distinguish between which of the video
> > pages (framebuffer or overlay) should be modified?
> >
>
> The FBIOPUT_SCREENINFO is used for the framebuffer and not the overlay.
> I got an impression that your framebuffer has a scaler and can be scaled to
> display resolution without changing framebuffer resolution.
It is possible to use the scaler for that purpose, but we've never done (or
needed) that. The framebuffer always runs at the native resolution (the
processor board is tightly coupled to the rest of the hardware, including
display). The scaler is only used to take arbitrary-sized images and resize
them to another arbitrary size for display in the overlay (used for video
playback, for instance).
> How do you program framebuffer registers? Usually, there is a set_par()
> function to do this. If you have a framebuffer that cannot change a resolution
> (either fixed resolution framebuffer or with resolution which can be set only
> during board set up) do not define fb_check_var() or check there if the mode
> has not changed.
The framebuffer can actually change the resolution, though we've never tried
that in practice. Each derived board comes with a default predefined
resolution that is never changed (because the displays we use don't support
mode setting either). Therefore changing the resolution does not make sense.
I guess it is better, as you say, to not define fb_check_var() in this case
until at some point it may become relevant.
> Regards,
> Krzysztof
Thierry
------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables
unlimited royalty-free distribution of the report engine
for externally facing server and web deployment.
http://p.sf.net/sfu/businessobjects
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-05-18 14:01 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1242294422-10478-1-git-send-email-thierry.reding@avionic-design.de>
2009-05-14 15:05 ` [PATCH 01/11] video: Add support for the Avionic Design Xanthos framebuffer Mike Rapoport
2009-05-16 9:22 ` Krzysztof Helt
2009-05-18 8:53 ` [Linux-fbdev-devel] " Thierry Reding
[not found] ` <20090518144028.9b8dbc3f.krzysztof.h1@poczta.fm>
2009-05-18 13:55 ` Thierry Reding
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).