diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-24 17:16:31 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-24 17:16:31 -0800 |
commit | b788769e0641daf90a8d7e800081285f8ca80bd9 (patch) | |
tree | d2cb6a926c55f4ea0ffc6089d54fb3768d82d7aa /drivers/video | |
parent | 91466574be1a3701fab4abf5ac1539b556575a81 (diff) | |
parent | cb1fbad7ec250ac408a4682d38b205958a17a02b (diff) |
Merge tag 'fbdev-3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux
Pull fbdev changes from Tomi Valkeinen:
"This is a rather boring pull request. There is one new fb driver,
OpenCores VGA/LCD, but other than that it's just minor cleanups and
fixes"
* tag 'fbdev-3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (51 commits)
i810: delete useless variable
video: add OpenCores VGA/LCD framebuffer driver
video/logo: Remove MIPS-specific include section
tgafb: potential NULL dereference in init
video: mmp: Using plain integer as NULL pointer
video: mmp: delete a stray mutex_unlock()
video: amba-clcd: Make CLCD driver available on more platforms
video: Replace local macro with PCI standard macro
fbmem: really support wildcard video=options for all fbdev drivers
video: vgacon: Don't build on arm64
video: mx3fb: Allow blocking during framebuffer allocation
fbcon: Fix memory leak in fbcon_exit().
fbcon: trivial optimization for fbcon_exit
video: pxa168fb: Cleanup pxa168fb.h file
video: pxa: Cleanup video-pxafb.h header
video: msm: Cleanup video-msm_fb.h header
video: ep93xx: Cleanup video-ep93xx.h header
video: mxsfb: fix broken videomode selection
video: mxsfb: convert pr_debug()/dev_dbg() to pr_err()/dev_err() for error messages
video: vmlfb: remove unnecessary pci_set_drvdata()
...
Diffstat (limited to 'drivers/video')
39 files changed, 945 insertions, 400 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 4f2e1b35eb3..22262a3a0e2 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -312,7 +312,8 @@ config FB_PM2_FIFO_DISCONNECT config FB_ARMCLCD tristate "ARM PrimeCell PL110 support" - depends on FB && ARM && ARM_AMBA + depends on ARM || ARM64 || COMPILE_TEST + depends on FB && ARM_AMBA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -979,6 +980,22 @@ config FB_PVR2 (<file:drivers/video/pvr2fb.c>). Please see the file <file:Documentation/fb/pvr2fb.txt>. +config FB_OPENCORES + tristate "OpenCores VGA/LCD core 2.0 framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This enables support for the OpenCores VGA/LCD core. + + The OpenCores VGA/LCD core is typically used together with + softcore CPUs (e.g. OpenRISC or Microblaze) or hard processor + systems (e.g. Altera socfpga or Xilinx Zynq) on FPGAs. + + The source code and specification for the core is available at + <http://opencores.org/project,vga_lcd> + config FB_S1D13XXX tristate "Epson S1D13XXX framebuffer support" depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e8bae8dd480..ae17ddf49a0 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -150,6 +150,7 @@ obj-$(CONFIG_FB_NUC900) += nuc900fb.o obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o +obj-$(CONFIG_FB_OPENCORES) += ocfb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c index d611f1a1ac5..7e8ddf00ccc 100644 --- a/drivers/video/asiliantfb.c +++ b/drivers/video/asiliantfb.c @@ -589,7 +589,6 @@ static void asiliantfb_remove(struct pci_dev *dp) fb_dealloc_cmap(&p->cmap); iounmap(p->screen_base); release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); - pci_set_drvdata(dp, NULL); framebuffer_release(p); } diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 846caab75a4..fe1cd0148e1 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -8,7 +8,8 @@ config VGA_CONSOLE bool "VGA text console" if EXPERT || !X86 depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \ !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \ - (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) + (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ + !ARM64 default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index cd8a8027f8a..4e39291ac8b 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -3547,8 +3547,10 @@ static void fbcon_exit(void) "no")); for (j = first_fb_vc; j <= last_fb_vc; j++) { - if (con2fb_map[j] == i) + if (con2fb_map[j] == i) { mapped = 1; + break; + } } if (mapped) { @@ -3561,6 +3563,7 @@ static void fbcon_exit(void) fbcon_del_cursor_timer(info); kfree(ops->cursor_src); + kfree(ops->cursor_state.mask); kfree(info->fbcon_par); info->fbcon_par = NULL; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 010d19105eb..cde46193276 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1930,6 +1930,9 @@ int fb_get_options(const char *name, char **option) options = opt + name_len + 1; } } + /* No match, pass global option */ + if (!options && option && fb_mode_option) + options = kstrdup(fb_mode_option, GFP_KERNEL); if (options && !strncmp(options, "off", 3)) retval = 1; diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 038192ac736..bb674e43174 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -2011,9 +2011,7 @@ static int i810fb_init_pci(struct pci_dev *dev, struct fb_info *info; struct i810fb_par *par = NULL; struct fb_videomode mode; - int i, err = -1, vfreq, hfreq, pixclock; - - i = 0; + int err = -1, vfreq, hfreq, pixclock; info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev); if (!info) diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 080c35b34bb..b670cbda38e 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -17,10 +17,6 @@ #include <asm/setup.h> #endif -#ifdef CONFIG_MIPS -#include <asm/bootinfo.h> -#endif - static bool nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); diff --git a/drivers/video/mmp/core.c b/drivers/video/mmp/core.c index 84de2632857..b563b920f15 100644 --- a/drivers/video/mmp/core.c +++ b/drivers/video/mmp/core.c @@ -30,7 +30,7 @@ static struct mmp_overlay *path_get_overlay(struct mmp_path *path, { if (path && overlay_id < path->overlay_num) return &path->overlays[overlay_id]; - return 0; + return NULL; } static int path_check_status(struct mmp_path *path) @@ -173,7 +173,7 @@ struct mmp_path *mmp_register_path(struct mmp_path_info *info) + sizeof(struct mmp_overlay) * info->overlay_num; path = kzalloc(size, GFP_KERNEL); if (!path) - goto failed; + return NULL; /* path set */ mutex_init(&path->access_ok); @@ -219,11 +219,6 @@ struct mmp_path *mmp_register_path(struct mmp_path_info *info) mutex_unlock(&disp_lock); return path; - -failed: - kfree(path); - mutex_unlock(&disp_lock); - return NULL; } EXPORT_SYMBOL_GPL(mmp_register_path); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 804f874d32d..142e860fb52 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -1263,7 +1263,7 @@ static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len, fbi->screen_base = dma_alloc_writecombine(fbi->device, mem_len, - &addr, GFP_DMA); + &addr, GFP_DMA | GFP_KERNEL); if (!fbi->screen_base) { dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n", diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 27197a8048c..accf48a2cce 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -49,6 +49,7 @@ #include <linux/fb.h> #include <linux/regulator/consumer.h> #include <video/of_display_timing.h> +#include <video/of_videomode.h> #include <video/videomode.h> #define REG_SET 4 @@ -297,7 +298,7 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var, } break; default: - pr_debug("Unsupported colour depth: %u\n", var->bits_per_pixel); + pr_err("Unsupported colour depth: %u\n", var->bits_per_pixel); return -EINVAL; } @@ -426,7 +427,7 @@ static int mxsfb_set_par(struct fb_info *fb_info) ctrl |= CTRL_SET_WORD_LENGTH(3); switch (host->ld_intf_width) { case STMLCDIF_8BIT: - dev_dbg(&host->pdev->dev, + dev_err(&host->pdev->dev, "Unsupported LCD bus width mapping\n"); return -EINVAL; case STMLCDIF_16BIT: @@ -439,7 +440,7 @@ static int mxsfb_set_par(struct fb_info *fb_info) writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1); break; default: - dev_dbg(&host->pdev->dev, "Unhandled color depth of %u\n", + dev_err(&host->pdev->dev, "Unhandled color depth of %u\n", fb_info->var.bits_per_pixel); return -EINVAL; } @@ -589,7 +590,8 @@ static struct fb_ops mxsfb_ops = { .fb_imageblit = cfb_imageblit, }; -static int mxsfb_restore_mode(struct mxsfb_info *host) +static int mxsfb_restore_mode(struct mxsfb_info *host, + struct fb_videomode *vmode) { struct fb_info *fb_info = &host->fb_info; unsigned line_count; @@ -597,7 +599,6 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) unsigned long pa, fbsize; int bits_per_pixel, ofs; u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; - struct fb_videomode vmode; /* Only restore the mode when the controller is running */ ctrl = readl(host->base + LCDC_CTRL); @@ -611,8 +612,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) transfer_count = readl(host->base + host->devdata->transfer_count); - vmode.xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count); - vmode.yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count); + vmode->xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count); + vmode->yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count); switch (CTRL_GET_WORD_LENGTH(ctrl)) { case 0: @@ -628,40 +629,39 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) fb_info->var.bits_per_pixel = bits_per_pixel; - vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U); - vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2); - vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len; - vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len - - vmode.left_margin - vmode.xres; - vmode.vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0); + vmode->pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U); + vmode->hsync_len = get_hsync_pulse_width(host, vdctrl2); + vmode->left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode->hsync_len; + vmode->right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - + vmode->hsync_len - vmode->left_margin - vmode->xres; + vmode->vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0); period = readl(host->base + LCDC_VDCTRL1); - vmode.upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode.vsync_len; - vmode.lower_margin = period - vmode.vsync_len - vmode.upper_margin - vmode.yres; + vmode->upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode->vsync_len; + vmode->lower_margin = period - vmode->vsync_len - + vmode->upper_margin - vmode->yres; - vmode.vmode = FB_VMODE_NONINTERLACED; + vmode->vmode = FB_VMODE_NONINTERLACED; - vmode.sync = 0; + vmode->sync = 0; if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH) - vmode.sync |= FB_SYNC_HOR_HIGH_ACT; + vmode->sync |= FB_SYNC_HOR_HIGH_ACT; if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH) - vmode.sync |= FB_SYNC_VERT_HIGH_ACT; + vmode->sync |= FB_SYNC_VERT_HIGH_ACT; pr_debug("Reconstructed video mode:\n"); pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n", - vmode.xres, vmode.yres, - vmode.hsync_len, vmode.left_margin, vmode.right_margin, - vmode.vsync_len, vmode.upper_margin, vmode.lower_margin); - pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode.pixclock)); - - fb_add_videomode(&vmode, &fb_info->modelist); + vmode->xres, vmode->yres, vmode->hsync_len, vmode->left_margin, + vmode->right_margin, vmode->vsync_len, vmode->upper_margin, + vmode->lower_margin); + pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode->pixclock)); host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl); host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4); - fb_info->fix.line_length = vmode.xres * (bits_per_pixel >> 3); + fb_info->fix.line_length = vmode->xres * (bits_per_pixel >> 3); pa = readl(host->base + host->devdata->cur_buf); - fbsize = fb_info->fix.line_length * vmode.yres; + fbsize = fb_info->fix.line_length * vmode->yres; if (pa < fb_info->fix.smem_start) return -EINVAL; if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) @@ -681,18 +681,17 @@ static int mxsfb_restore_mode(struct mxsfb_info *host) return 0; } -static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host) +static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host, + struct fb_videomode *vmode) { struct fb_info *fb_info = &host->fb_info; struct fb_var_screeninfo *var = &fb_info->var; struct device *dev = &host->pdev->dev; struct device_node *np = host->pdev->dev.of_node; struct device_node *display_np; - struct device_node *timings_np; - struct display_timings *timings; + struct videomode vm; u32 width; - int i; - int ret = 0; + int ret; display_np = of_parse_phandle(np, "display", 0); if (!display_np) { @@ -732,54 +731,35 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host) goto put_display_node; } - timings = of_get_display_timings(display_np); - if (!timings) { - dev_err(dev, "failed to get display timings\n"); - ret = -ENOENT; + ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE); + if (ret) { + dev_err(dev, "failed to get videomode from DT\n"); goto put_display_node; } - timings_np = of_find_node_by_name(display_np, - "display-timings"); - if (!timings_np) { - dev_err(dev, "failed to find display-timings node\n"); - ret = -ENOENT; + ret = fb_videomode_from_videomode(&vm, vmode); + if (ret < 0) goto put_display_node; - } - for (i = 0; i < of_get_child_count(timings_np); i++) { - struct videomode vm; - struct fb_videomode fb_vm; - - ret = videomode_from_timings(timings, &vm, i); - if (ret < 0) - goto put_timings_node; - ret = fb_videomode_from_videomode(&vm, &fb_vm); - if (ret < 0) - goto put_timings_node; - - if (vm.flags & DISPLAY_FLAGS_DE_HIGH) - host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; - if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) - host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT; - fb_add_videomode(&fb_vm, &fb_info->modelist); - } + if (vm.flags & DISPLAY_FLAGS_DE_HIGH) + host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; + if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) + host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT; -put_timings_node: - of_node_put(timings_np); put_display_node: of_node_put(display_np); return ret; } -static int mxsfb_init_fbinfo(struct mxsfb_info *host) +static int mxsfb_init_fbinfo(struct mxsfb_info *host, + struct fb_videomode *vmode) { + int ret; struct fb_info *fb_info = &host->fb_info; struct fb_var_screeninfo *var = &fb_info->var; dma_addr_t fb_phys; void *fb_virt; unsigned fb_size; - int ret; fb_info->fbops = &mxsfb_ops; fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; @@ -789,7 +769,7 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host) fb_info->fix.visual = FB_VISUAL_TRUECOLOR, fb_info->fix.accel = FB_ACCEL_NONE; - ret = mxsfb_init_fbinfo_dt(host); + ret = mxsfb_init_fbinfo_dt(host, vmode); if (ret) return ret; @@ -810,7 +790,7 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host) fb_info->screen_base = fb_virt; fb_info->screen_size = fb_info->fix.smem_len = fb_size; - if (mxsfb_restore_mode(host)) + if (mxsfb_restore_mode(host, vmode)) memset(fb_virt, 0, fb_size); return 0; @@ -850,7 +830,7 @@ static int mxsfb_probe(struct platform_device *pdev) struct resource *res; struct mxsfb_info *host; struct fb_info *fb_info; - struct fb_modelist *modelist; + struct fb_videomode *mode; int ret; if (of_id) @@ -862,6 +842,11 @@ static int mxsfb_probe(struct platform_device *pdev) return -ENOMEM; } + mode = devm_kzalloc(&pdev->dev, sizeof(struct fb_videomode), + GFP_KERNEL); + if (mode == NULL) + return -ENOMEM; + host = to_imxfb_host(fb_info); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -893,15 +878,11 @@ static int mxsfb_probe(struct platform_device *pdev) goto fb_release; } - INIT_LIST_HEAD(&fb_info->modelist); - - ret = mxsfb_init_fbinfo(host); + ret = mxsfb_init_fbinfo(host, mode); if (ret != 0) goto fb_release; - modelist = list_first_entry(&fb_info->modelist, - struct fb_modelist, list); - fb_videomode_to_var(&fb_info->var, &modelist->mode); + fb_videomode_to_var(&fb_info->var, mode); /* init the color fields */ mxsfb_check_var(&fb_info->var, fb_info); @@ -927,7 +908,6 @@ static int mxsfb_probe(struct platform_device *pdev) fb_destroy: if (host->enabled) clk_disable_unprepare(host->clk); - fb_destroy_modelist(&fb_info->modelist); fb_release: framebuffer_release(fb_info); diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index ff228713425..def04120467 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1461,7 +1461,6 @@ static void nvidiafb_remove(struct pci_dev *pd) pci_release_regions(pd); kfree(info->pixmap.addr); framebuffer_release(info); - pci_set_drvdata(pd, NULL); NVTRACE_LEAVE(); } diff --git a/drivers/video/ocfb.c b/drivers/video/ocfb.c new file mode 100644 index 00000000000..7f9dc9bec30 --- /dev/null +++ b/drivers/video/ocfb.c @@ -0,0 +1,440 @@ +/* + * OpenCores VGA/LCD 2.0 core frame buffer driver + * + * Copyright (C) 2013 Stefan Kristiansson, stefan.kristiansson@saunalahti.fi + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/slab.h> + +/* OCFB register defines */ +#define OCFB_CTRL 0x000 +#define OCFB_STAT 0x004 +#define OCFB_HTIM 0x008 +#define OCFB_VTIM 0x00c +#define OCFB_HVLEN 0x010 +#define OCFB_VBARA 0x014 +#define OCFB_PALETTE 0x800 + +#define OCFB_CTRL_VEN 0x00000001 /* Video Enable */ +#define OCFB_CTRL_HIE 0x00000002 /* HSync Interrupt Enable */ +#define OCFB_CTRL_PC 0x00000800 /* 8-bit Pseudo Color Enable*/ +#define OCFB_CTRL_CD8 0x00000000 /* Color Depth 8 */ +#define OCFB_CTRL_CD16 0x00000200 /* Color Depth 16 */ +#define OCFB_CTRL_CD24 0x00000400 /* Color Depth 24 */ +#define OCFB_CTRL_CD32 0x00000600 /* Color Depth 32 */ +#define OCFB_CTRL_VBL1 0x00000000 /* Burst Length 1 */ +#define OCFB_CTRL_VBL2 0x00000080 /* Burst Length 2 */ +#define OCFB_CTRL_VBL4 0x00000100 /* Burst Length 4 */ +#define OCFB_CTRL_VBL8 0x00000180 /* Burst Length 8 */ + +#define PALETTE_SIZE 256 + +#define OCFB_NAME "OC VGA/LCD" + +static char *mode_option; + +static const struct fb_videomode default_mode = { + /* 640x480 @ 60 Hz, 31.5 kHz hsync */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + +struct ocfb_dev { + struct fb_info info; + void __iomem *regs; + /* flag indicating whether the regs are little endian accessed */ + int little_endian; + /* Physical and virtual addresses of framebuffer */ + phys_addr_t fb_phys; + void __iomem *fb_virt; + u32 pseudo_palette[PALETTE_SIZE]; +}; + +#ifndef MODULE +static int __init ocfb_setup(char *options) +{ + char *curr_opt; + + if (!options || !*options) + return 0; + + while ((curr_opt = strsep(&options, ",")) != NULL) { + if (!*curr_opt) + continue; + mode_option = curr_opt; + } + + return 0; +} +#endif + +static inline u32 ocfb_readreg(struct ocfb_dev *fbdev, loff_t offset) +{ + if (fbdev->little_endian) + return ioread32(fbdev->regs + offset); + else + return ioread32be(fbdev->regs + offset); +} + +static void ocfb_writereg(struct ocfb_dev *fbdev, loff_t offset, u32 data) +{ + if (fbdev->little_endian) + iowrite32(data, fbdev->regs + offset); + else + iowrite32be(data, fbdev->regs + offset); +} + +static int ocfb_setupfb(struct ocfb_dev *fbdev) +{ + unsigned long bpp_config; + struct fb_var_screeninfo *var = &fbdev->info.var; + struct device *dev = fbdev->info.device; + u32 hlen; + u32 vlen; + + /* Disable display */ + ocfb_writereg(fbdev, OCFB_CTRL, 0); + + /* Register framebuffer address */ + fbdev->little_endian = 0; + ocfb_writereg(fbdev, OCFB_VBARA, fbdev->fb_phys); + + /* Detect endianess */ + if (ocfb_readreg(fbdev, OCFB_VBARA) != fbdev->fb_phys) { + fbdev->little_endian = 1; + ocfb_writereg(fbdev, OCFB_VBARA, fbdev->fb_phys); + } + + /* Horizontal timings */ + ocfb_writereg(fbdev, OCFB_HTIM, (var->hsync_len - 1) << 24 | + (var->right_margin - 1) << 16 | (var->xres - 1)); + + /* Vertical timings */ + ocfb_writereg(fbdev, OCFB_VTIM, (var->vsync_len - 1) << 24 | + (var->lower_margin - 1) << 16 | (var->yres - 1)); + + /* Total length of frame */ + hlen = var->left_margin + var->right_margin + var->hsync_len + + var->xres; + + vlen = var->upper_margin + var->lower_margin + var->vsync_len + + var->yres; + + ocfb_writereg(fbdev, OCFB_HVLEN, (hlen - 1) << 16 | (vlen - 1)); + + bpp_config = OCFB_CTRL_CD8; + switch (var->bits_per_pixel) { + case 8: + if (!var->grayscale) + bpp_config |= OCFB_CTRL_PC; /* enable palette */ + break; + + case 16: + bpp_config |= OCFB_CTRL_CD16; + break; + + case 24: + bpp_config |= OCFB_CTRL_CD24; + break; + + case 32: + bpp_config |= OCFB_CTRL_CD32; + break; + + default: + dev_err(dev, "no bpp specified\n"); + break; + } + + /* maximum (8) VBL (video memory burst length) */ + bpp_config |= OCFB_CTRL_VBL8; + + /* Enable output */ + ocfb_writereg(fbdev, OCFB_CTRL, (OCFB_CTRL_VEN | bpp_config)); + + return 0; +} + +static int ocfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct ocfb_dev *fbdev = (struct ocfb_dev *)info->par; + u32 color; + + if (regno >= info->cmap.len) { + dev_err(info->device, "regno >= cmap.len\n"); + return 1; + } + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + transp >>= (16 - info->var.transp.length); + + if (info->var.bits_per_pixel == 8 && !info->var.grayscale) { + regno <<= 2; + color = (red << 16) | (green << 8) | blue; + ocfb_writereg(fbdev, OCFB_PALETTE + regno, color); + } else { + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + } + + return 0; +} + +static int ocfb_init_fix(struct ocfb_dev *fbdev) +{ + struct fb_var_screeninfo *var = &fbdev->info.var; + struct fb_fix_screeninfo *fix = &fbdev->info.fix; + + strcpy(fix->id, OCFB_NAME); + + fix->line_length = var->xres * var->bits_per_pixel/8; + fix->smem_len = fix->line_length * var->yres; + fix->type = FB_TYPE_PACKED_PIXELS; + + if (var->bits_per_pixel == 8 |