video: move fbdev to drivers/video/fbdev

The drivers/video directory is a mess. It contains generic video related
files, directories for backlight, console, linux logo, lots of fbdev
device drivers, fbdev framework files.

Make some order into the chaos by creating drivers/video/fbdev
directory, and move all fbdev related files there.

No functionality is changed, although I guess it is possible that some
subtle Makefile build order related issue could be created by this
patch.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Rob Clark <robdclark@gmail.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Tomi Valkeinen 2014-02-13 15:31:38 +02:00
commit f7018c2135
481 changed files with 2672 additions and 2662 deletions

View file

@ -276,7 +276,7 @@ X!Isound/sound_firmware.c
</para>
<sect1><title>Frame Buffer Memory</title>
!Edrivers/video/fbmem.c
!Edrivers/video/fbdev/fbmem.c
</sect1>
<!--
<sect1><title>Frame Buffer Console</title>
@ -284,7 +284,7 @@ X!Edrivers/video/console/fbcon.c
</sect1>
-->
<sect1><title>Frame Buffer Colormap</title>
!Edrivers/video/fbcmap.c
!Edrivers/video/fbdev/fbcmap.c
</sect1>
<!-- FIXME:
drivers/video/fbgen.c has no docs, which stuffs up the sgml. Comment
@ -294,11 +294,11 @@ X!Idrivers/video/fbgen.c
</sect1>
KAO -->
<sect1><title>Frame Buffer Video Mode Database</title>
!Idrivers/video/modedb.c
!Edrivers/video/modedb.c
!Idrivers/video/fbdev/modedb.c
!Edrivers/video/fbdev/modedb.c
</sect1>
<sect1><title>Frame Buffer Macintosh Video Mode Database</title>
!Edrivers/video/macmodes.c
!Edrivers/video/fbdev/macmodes.c
</sect1>
<sect1><title>Frame Buffer Fonts</title>
<para>

View file

@ -53,8 +53,8 @@ obj-y += gpu/
obj-$(CONFIG_CONNECTOR) += connector/
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/i810/
obj-$(CONFIG_FB_INTEL) += video/intelfb/
obj-$(CONFIG_FB_I810) += video/fbdev/i810/
obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ nfc/

View file

@ -1,6 +1,6 @@
#ifndef _VB_DEF_
#define _VB_DEF_
#include "../../video/sis/initdef.h"
#include "../../video/fbdev/sis/initdef.h"
#define VB_XGI301C 0x0020 /* for 301C */

View file

@ -1,6 +1,6 @@
#ifndef _VB_STRUCT_
#define _VB_STRUCT_
#include "../../video/sis/vstruct.h"
#include "../../video/fbdev/sis/vstruct.h"
struct XGI_LVDSCRT1HDataStruct {
unsigned char Reg[8];

View file

@ -2,8 +2,8 @@
#define _VGATYPES_
#include <linux/fb.h> /* for struct fb_var_screeninfo for sis.h */
#include "../../video/sis/vgatypes.h"
#include "../../video/sis/sis.h" /* for LCD_TYPE */
#include "../../video/fbdev/sis/vgatypes.h"
#include "../../video/fbdev/sis/sis.h" /* for LCD_TYPE */
#ifndef XGI_VB_CHIP_TYPE
enum XGI_VB_CHIP_TYPE {

File diff suppressed because it is too large Load diff

View file

@ -1,175 +1,11 @@
# Makefile for the Linux video drivers.
# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net>
# Rewritten to use lists instead of if-statements.
# Each configuration option enables a list of files.
obj-$(CONFIG_VGASTATE) += vgastate.o
obj-$(CONFIG_HDMI) += hdmi.o
obj-y += fb_notify.o
obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o
fb-objs := $(fb-y)
obj-$(CONFIG_VT) += console/
obj-$(CONFIG_LOGO) += logo/
obj-y += backlight/
obj-$(CONFIG_EXYNOS_VIDEO) += exynos/
obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o
obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o
obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
obj-$(CONFIG_FB_SVGALIB) += svgalib.o
obj-$(CONFIG_FB_MACMODES) += macmodes.o
obj-$(CONFIG_FB_DDC) += fb_ddc.o
obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o
# Hardware specific drivers go first
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_GRVGA) += grvga.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o
obj-$(CONFIG_FB_I740) += i740fb.o
obj-$(CONFIG_FB_MATROX) += matrox/
obj-$(CONFIG_FB_RIVA) += riva/
obj-$(CONFIG_FB_NVIDIA) += nvidia/
obj-$(CONFIG_FB_ATY) += aty/ macmodes.o
obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o
obj-$(CONFIG_FB_RADEON) += aty/
obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_VIA) += via/
obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
obj-$(CONFIG_FB_MBX) += mbx/
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o
obj-$(CONFIG_FB_PLATINUM) += platinumfb.o
obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o
obj-$(CONFIG_FB_CT65550) += chipsfb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
obj-$(CONFIG_FB_VT8623) += vt8623fb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_LE80578) += vermilion/
obj-$(CONFIG_FB_S3) += s3fb.o
obj-$(CONFIG_FB_ARK) += arkfb.o
obj-$(CONFIG_FB_STI) += stifb.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o
obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o
obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o
obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o
obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o
obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \
atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
obj-$(CONFIG_FB_MAC) += macfb.o
obj-$(CONFIG_FB_HECUBA) += hecubafb.o
obj-$(CONFIG_FB_N411) += n411.o
obj-$(CONFIG_FB_HGA) += hgafb.o
obj-$(CONFIG_FB_XVR500) += sunxvr500.o
obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o
obj-$(CONFIG_FB_XVR1000) += sunxvr1000.o
obj-$(CONFIG_FB_IGA) += igafb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o
obj-$(CONFIG_FB_Q40) += q40fb.o
obj-$(CONFIG_FB_TGA) += tgafb.o
obj-$(CONFIG_FB_HP300) += hpfb.o
obj-$(CONFIG_FB_G364) += g364fb.o
obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o
obj-$(CONFIG_FB_68328) += 68328fb.o
obj-$(CONFIG_FB_GBE) += gbefb.o
obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o
obj-$(CONFIG_FB_PXA) += pxafb.o
obj-$(CONFIG_FB_PXA168) += pxa168fb.o
obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o
obj-$(CONFIG_MMP_DISP) += mmp/
obj-$(CONFIG_FB_W100) += w100fb.o
obj-$(CONFIG_FB_TMIO) += tmiofb.o
obj-$(CONFIG_FB_AU1100) += au1100fb.o
obj-$(CONFIG_FB_AU1200) += au1200fb.o
obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o
obj-$(CONFIG_FB_WM8505) += wm8505fb.o
obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o
obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o
obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o
obj-$(CONFIG_FB_MAXINE) += maxinefb.o
obj-$(CONFIG_FB_METRONOME) += metronomefb.o
obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o
obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o
obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o
obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_UDL) += udlfb.o
obj-$(CONFIG_FB_SMSCUFX) += smscufx.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o
obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
obj-y += omap2/
obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
obj-$(CONFIG_FB_MSM) += msm/
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
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_EFI) += efifb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_BF537_LQ035) += bf537-lq035.o
obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o
obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o
obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o
obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o
obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
obj-$(CONFIG_FB_MXS) += mxsfb.o
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
obj-y += fbdev/
obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
ifeq ($(CONFIG_OF),y)

View file

@ -46,7 +46,7 @@
#include <asm/io.h>
#include "../sticore.h"
#include "../fbdev/sticore.h"
/* switching to graphics mode */
#define BLANK 0

View file

@ -28,7 +28,7 @@
#include <asm/cacheflush.h>
#include <asm/grfioctl.h>
#include "../sticore.h"
#include "../fbdev/sticore.h"
#define STI_DRIVERVERSION "Version 0.9b"

View file

@ -0,0 +1,503 @@
/*
* linux/drivers/video/68328fb.c -- Low level implementation of the
* mc68x328 LCD frame buffer device
*
* Copyright (C) 2003 Georges Menie
*
* This driver assumes an already configured controller (e.g. from config.c)
* Keep the code clean of board specific initialization.
*
* This code has not been tested with colors, colormap management functions
* are minimal (no colormap data written to the 68328 registers...)
*
* initial version of this driver:
* Copyright (C) 1998,1999 Kenneth Albanowski <kjahds@kjahds.com>,
* The Silver Hammer Group, Ltd.
*
* this version is based on :
*
* linux/drivers/video/vfb.c -- Virtual frame buffer device
*
* Copyright (C) 2002 James Simmons
*
* Copyright (C) 1997 Geert Uytterhoeven
*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/fb.h>
#include <linux/init.h>
#if defined(CONFIG_M68VZ328)
#include <asm/MC68VZ328.h>
#elif defined(CONFIG_M68EZ328)
#include <asm/MC68EZ328.h>
#elif defined(CONFIG_M68328)
#include <asm/MC68328.h>
#else
#error wrong architecture for the MC68x328 frame buffer device
#endif
#if defined(CONFIG_FB_68328_INVERT)
#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO01
#else
#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO10
#endif
static u_long videomemory;
static u_long videomemorysize;
static struct fb_info fb_info;
static u32 mc68x328fb_pseudo_palette[16];
static struct fb_var_screeninfo mc68x328fb_default __initdata = {
.red = { 0, 8, 0 },
.green = { 0, 8, 0 },
.blue = { 0, 8, 0 },
.activate = FB_ACTIVATE_TEST,
.height = -1,
.width = -1,
.pixclock = 20000,
.left_margin = 64,
.right_margin = 64,
.upper_margin = 32,
.lower_margin = 32,
.hsync_len = 64,
.vsync_len = 2,
.vmode = FB_VMODE_NONINTERLACED,
};
static struct fb_fix_screeninfo mc68x328fb_fix __initdata = {
.id = "68328fb",
.type = FB_TYPE_PACKED_PIXELS,
.xpanstep = 1,
.ypanstep = 1,
.ywrapstep = 1,
.accel = FB_ACCEL_NONE,
};
/*
* Interface used by the world
*/
int mc68x328fb_init(void);
int mc68x328fb_setup(char *);
static int mc68x328fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);
static int mc68x328fb_set_par(struct fb_info *info);
static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info);
static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
static struct fb_ops mc68x328fb_ops = {
.fb_check_var = mc68x328fb_check_var,
.fb_set_par = mc68x328fb_set_par,
.fb_setcolreg = mc68x328fb_setcolreg,
.fb_pan_display = mc68x328fb_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_mmap = mc68x328fb_mmap,
};
/*
* Internal routines
*/
static u_long get_line_length(int xres_virtual, int bpp)
{
u_long length;
length = xres_virtual * bpp;
length = (length + 31) & ~31;
length >>= 3;
return (length);
}
/*
* Setting the video mode has been split into two parts.
* First part, xxxfb_check_var, must not write anything
* to hardware, it should only verify and adjust var.
* This means it doesn't alter par but it does use hardware
* data from it to check this var.
*/
static int mc68x328fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
u_long line_length;
/*
* FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
* as FB_VMODE_SMOOTH_XPAN is only used internally
*/
if (var->vmode & FB_VMODE_CONUPDATE) {
var->vmode |= FB_VMODE_YWRAP;
var->xoffset = info->var.xoffset;
var->yoffset = info->var.yoffset;
}
/*
* Some very basic checks
*/
if (!var->xres)
var->xres = 1;
if (!var->yres)
var->yres = 1;
if (var->xres > var->xres_virtual)
var->xres_virtual = var->xres;
if (var->yres > var->yres_virtual)
var->yres_virtual = var->yres;
if (var->bits_per_pixel <= 1)
var->bits_per_pixel = 1;
else if (var->bits_per_pixel <= 8)
var->bits_per_pixel = 8;
else if (var->bits_per_pixel <= 16)
var->bits_per_pixel = 16;
else if (var->bits_per_pixel <= 24)
var->bits_per_pixel = 24;
else if (var->bits_per_pixel <= 32)
var->bits_per_pixel = 32;
else
return -EINVAL;
if (var->xres_virtual < var->xoffset + var->xres)
var->xres_virtual = var->xoffset + var->xres;
if (var->yres_virtual < var->yoffset + var->yres)
var->yres_virtual = var->yoffset + var->yres;
/*
* Memory limit
*/
line_length =
get_line_length(var->xres_virtual, var->bits_per_pixel);
if (line_length * var->yres_virtual > videomemorysize)
return -ENOMEM;
/*
* Now that we checked it we alter var. The reason being is that the video
* mode passed in might not work but slight changes to it might make it
* work. This way we let the user know what is acceptable.
*/
switch (var->bits_per_pixel) {
case 1:
var->red.offset = 0;
var->red.length = 1;
var->green.offset = 0;
var->green.length = 1;
var->blue.offset = 0;
var->blue.length = 1;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 8:
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 16: /* RGBA 5551 */
if (var->transp.length) {
var->red.offset = 0;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 5;
var->blue.offset = 10;
var->blue.length = 5;
var->transp.offset = 15;
var->transp.length = 1;
} else { /* RGB 565 */
var->red.offset = 0;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 6;
var->blue.offset = 11;
var->blue.length = 5;
var->transp.offset = 0;
var->transp.length = 0;
}
break;
case 24: /* RGB 888 */
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 16;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 32: /* RGBA 8888 */
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 16;
var->blue.length = 8;
var->transp.offset = 24;
var->transp.length = 8;
break;
}
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
return 0;
}
/* This routine actually sets the video mode. It's in here where we
* the hardware state info->par and fix which can be affected by the
* change in par. For this driver it doesn't do much.
*/
static int mc68x328fb_set_par(struct fb_info *info)
{
info->fix.line_length = get_line_length(info->var.xres_virtual,
info->var.bits_per_pixel);
return 0;
}
/*
* Set a single color register. The values supplied are already
* rounded down to the hardware's capabilities (according to the
* entries in the var structure). Return != 0 for invalid regno.
*/
static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
if (regno >= 256) /* no. of hw registers */
return 1;
/*
* Program hardware... do anything you want with transp
*/
/* grayscale works only partially under directcolor */
if (info->var.grayscale) {
/* grayscale = 0.30*R + 0.59*G + 0.11*B */
red = green = blue =
(red * 77 + green * 151 + blue * 28) >> 8;
}
/* Directcolor:
* var->{color}.offset contains start of bitfield
* var->{color}.length contains length of bitfield
* {hardwarespecific} contains width of RAMDAC
* cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
* RAMDAC[X] is programmed to (red, green, blue)
*
* Pseudocolor:
* uses offset = 0 && length = RAMDAC register width.
* var->{color}.offset is 0
* var->{color}.length contains width of DAC
* cmap is not used
* RAMDAC[X] is programmed to (red, green, blue)
* Truecolor:
* does not use DAC. Usually 3 are present.
* var->{color}.offset contains start of bitfield
* var->{color}.length contains length of bitfield
* cmap is programmed to (red << red.offset) | (green << green.offset) |
* (blue << blue.offset) | (transp << transp.offset)
* RAMDAC does not exist
*/
#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_PSEUDOCOLOR:
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length);
break;
case FB_VISUAL_DIRECTCOLOR:
red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */
green = CNVT_TOHW(green, 8);
blue = CNVT_TOHW(blue, 8);
/* hey, there is bug in transp handling... */
transp = CNVT_TOHW(transp, 8);
break;
}
#undef CNVT_TOHW
/* Truecolor has hardware independent palette */
if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
u32 v;
if (regno >= 16)
return 1;
v = (red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset) |
(transp << info->var.transp.offset);
switch (info->var.bits_per_pixel) {
case 8:
break;
case 16:
((u32 *) (info->pseudo_palette))[regno] = v;
break;
case 24:
case 32:
((u32 *) (info->pseudo_palette))[regno] = v;
break;
}
return 0;
}
return 0;
}
/*
* Pan or Wrap the Display
*
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0
|| var->yoffset >= info->var.yres_virtual
|| var->xoffset)
return -EINVAL;
} else {
if (var->xoffset + info->var.xres > info->var.xres_virtual ||
var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
}
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
info->var.vmode |= FB_VMODE_YWRAP;
else
info->var.vmode &= ~FB_VMODE_YWRAP;
return 0;
}
/*
* Most drivers don't need their own mmap function
*/
static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
#ifndef MMU
/* this is uClinux (no MMU) specific code */
vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_start = videomemory;
return 0;
#else
return -EINVAL;
#endif
}
int __init mc68x328fb_setup(char *options)
{
#if 0
char *this_opt;
#endif
if (!options || !*options)
return 1;
#if 0
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
if (!strncmp(this_opt, "disable", 7))
mc68x328fb_enable = 0;
}
#endif
return 1;
}
/*
* Initialisation
*/
int __init mc68x328fb_init(void)
{
#ifndef MODULE
char *option = NULL;
if (fb_get_options("68328fb", &option))
return -ENODEV;
mc68x328fb_setup(option);
#endif
/*
* initialize the default mode from the LCD controller registers
*/
mc68x328fb_default.xres = LXMAX;
mc68x328fb_default.yres = LYMAX+1;
mc68x328fb_default.xres_virtual = mc68x328fb_default.xres;
mc68x328fb_default.yres_virtual = mc68x328fb_default.yres;
mc68x328fb_default.bits_per_pixel = 1 + (LPICF & 0x01);
videomemory = LSSA;
videomemorysize = (mc68x328fb_default.xres_virtual+7) / 8 *
mc68x328fb_default.yres_virtual * mc68x328fb_default.bits_per_pixel;
fb_info.screen_base = (void *)videomemory;
fb_info.fbops = &mc68x328fb_ops;
fb_info.var = mc68x328fb_default;
fb_info.fix = mc68x328fb_fix;
fb_info.fix.smem_start = videomemory;
fb_info.fix.smem_len = videomemorysize;
fb_info.fix.line_length =
get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel);
fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ?
MC68X328FB_MONO_VISUAL : FB_VISUAL_PSEUDOCOLOR;
if (fb_info.var.bits_per_pixel == 1) {
fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1;
fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0;
}
fb_info.pseudo_palette = &mc68x328fb_pseudo_palette;
fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
if (fb_alloc_cmap(&fb_info.cmap, 256, 0))
return -ENOMEM;
if (register_framebuffer(&fb_info) < 0) {
fb_dealloc_cmap(&fb_info.cmap);
return -EINVAL;
}
fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id);
fb_info(&fb_info, "%dx%dx%d at 0x%08lx\n",
mc68x328fb_default.xres_virtual,
mc68x328fb_default.yres_virtual,
1 << mc68x328fb_default.bits_per_pixel, videomemory);
return 0;
}
module_init(mc68x328fb_init);
#ifdef MODULE
static void __exit mc68x328fb_cleanup(void)
{
unregister_framebuffer(&fb_info);
fb_dealloc_cmap(&fb_info.cmap);
}
module_exit(mc68x328fb_cleanup);
MODULE_LICENSE("GPL");
#endif /* MODULE */

2474
drivers/video/fbdev/Kconfig Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,166 @@
# Makefile for the Linux video drivers.
# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net>
# Rewritten to use lists instead of if-statements.
# Each configuration option enables a list of files.
obj-y += fb_notify.o
obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o
fb-objs := $(fb-y)
obj-$(CONFIG_EXYNOS_VIDEO) += exynos/
obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o
obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o
obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
obj-$(CONFIG_FB_SVGALIB) += svgalib.o
obj-$(CONFIG_FB_MACMODES) += macmodes.o
obj-$(CONFIG_FB_DDC) += fb_ddc.o
obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o
# Hardware specific drivers go first
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_GRVGA) += grvga.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o
obj-$(CONFIG_FB_I740) += i740fb.o
obj-$(CONFIG_FB_MATROX) += matrox/
obj-$(CONFIG_FB_RIVA) += riva/
obj-$(CONFIG_FB_NVIDIA) += nvidia/
obj-$(CONFIG_FB_ATY) += aty/ macmodes.o
obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o
obj-$(CONFIG_FB_RADEON) += aty/
obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_VIA) += via/
obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
obj-$(CONFIG_FB_MBX) += mbx/
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o
obj-$(CONFIG_FB_PLATINUM) += platinumfb.o
obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o
obj-$(CONFIG_FB_CT65550) += chipsfb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
obj-$(CONFIG_FB_VT8623) += vt8623fb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_LE80578) += vermilion/
obj-$(CONFIG_FB_S3) += s3fb.o
obj-$(CONFIG_FB_ARK) += arkfb.o
obj-$(CONFIG_FB_STI) += stifb.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o
obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o
obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o
obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o
obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o
obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \
atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
obj-$(CONFIG_FB_MAC) += macfb.o
obj-$(CONFIG_FB_HECUBA) += hecubafb.o
obj-$(CONFIG_FB_N411) += n411.o
obj-$(CONFIG_FB_HGA) += hgafb.o
obj-$(CONFIG_FB_XVR500) += sunxvr500.o
obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o
obj-$(CONFIG_FB_XVR1000) += sunxvr1000.o
obj-$(CONFIG_FB_IGA) += igafb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o
obj-$(CONFIG_FB_Q40) += q40fb.o
obj-$(CONFIG_FB_TGA) += tgafb.o
obj-$(CONFIG_FB_HP300) += hpfb.o
obj-$(CONFIG_FB_G364) += g364fb.o
obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o
obj-$(CONFIG_FB_68328) += 68328fb.o
obj-$(CONFIG_FB_GBE) += gbefb.o
obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o
obj-$(CONFIG_FB_PXA) += pxafb.o
obj-$(CONFIG_FB_PXA168) += pxa168fb.o
obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o
obj-$(CONFIG_MMP_DISP) += mmp/
obj-$(CONFIG_FB_W100) += w100fb.o
obj-$(CONFIG_FB_TMIO) += tmiofb.o
obj-$(CONFIG_FB_AU1100) += au1100fb.o
obj-$(CONFIG_FB_AU1200) += au1200fb.o
obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o
obj-$(CONFIG_FB_WM8505) += wm8505fb.o
obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o
obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o
obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o
obj-$(CONFIG_FB_MAXINE) += maxinefb.o
obj-$(CONFIG_FB_METRONOME) += metronomefb.o
obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o
obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o
obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o
obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_UDL) += udlfb.o
obj-$(CONFIG_FB_SMSCUFX) += smscufx.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o
obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
obj-y += omap2/
obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
obj-$(CONFIG_FB_MSM) += msm/
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
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_EFI) += efifb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_BF537_LQ035) += bf537-lq035.o
obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o
obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o
obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o
obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o
obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
obj-$(CONFIG_FB_MXS) += mxsfb.o
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
/*
* linux/drivers/video/acornfb.h
*
* Copyright (C) 1998,1999 Russell King
*
* 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.
*
* Frame buffer code for Acorn platforms
*/
#if defined(HAS_VIDC20)
#include <asm/hardware/iomd.h>
#define VIDC_PALETTE_SIZE 256
#define VIDC_NAME "VIDC20"
#endif
#define EXTEND8(x) ((x)|(x)<<8)
#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<12)
struct vidc20_palette {
u_int red:8;
u_int green:8;
u_int blue:8;
u_int ext:4;
u_int unused:4;
};
struct vidc_palette {
u_int red:4;
u_int green:4;
u_int blue:4;
u_int trans:1;
u_int sbz1:13;
u_int reg:4;
u_int sbz2:2;
};
union palette {
struct vidc20_palette vidc20;
struct vidc_palette vidc;
u_int p;
};
struct acornfb_par {
struct device *dev;
unsigned long screen_end;
unsigned int dram_size;
unsigned int vram_half_sam;
unsigned int palette_size;
signed int montype;
unsigned int using_vram : 1;
unsigned int dpms : 1;
union palette palette[VIDC_PALETTE_SIZE];
u32 pseudo_palette[16];
};
struct vidc_timing {
u_int h_cycle;
u_int h_sync_width;
u_int h_border_start;
u_int h_display_start;
u_int h_display_end;
u_int h_border_end;
u_int h_interlace;
u_int v_cycle;
u_int v_sync_width;
u_int v_border_start;
u_int v_display_start;
u_int v_display_end;
u_int v_border_end;
u_int control;
/* VIDC20 only */
u_int pll_ctl;
};
struct modey_params {
u_int y_res;
u_int u_margin;
u_int b_margin;
u_int vsync_len;
u_int vf;
};
struct modex_params {
u_int x_res;
u_int l_margin;
u_int r_margin;
u_int hsync_len;
u_int clock;
u_int hf;
const struct modey_params *modey;
};
#ifdef HAS_VIDC20
/*
* VIDC20 registers
*/
#define VIDC20_CTRL 0xe0000000
#define VIDC20_CTRL_PIX_VCLK (0 << 0)
#define VIDC20_CTRL_PIX_HCLK (1 << 0)
#define VIDC20_CTRL_PIX_RCLK (2 << 0)
#define VIDC20_CTRL_PIX_CK (0 << 2)
#define VIDC20_CTRL_PIX_CK2 (1 << 2)
#define VIDC20_CTRL_PIX_CK3 (2 << 2)
#define VIDC20_CTRL_PIX_CK4 (3 << 2)
#define VIDC20_CTRL_PIX_CK5 (4 << 2)
#define VIDC20_CTRL_PIX_CK6 (5 << 2)
#define VIDC20_CTRL_PIX_CK7 (6 << 2)
#define VIDC20_CTRL_PIX_CK8 (7 << 2)
#define VIDC20_CTRL_1BPP (0 << 5)
#define VIDC20_CTRL_2BPP (1 << 5)
#define VIDC20_CTRL_4BPP (2 << 5)
#define VIDC20_CTRL_8BPP (3 << 5)
#define VIDC20_CTRL_16BPP (4 << 5)
#define VIDC20_CTRL_32BPP (6 << 5)
#define VIDC20_CTRL_FIFO_NS (0 << 8)
#define VIDC20_CTRL_FIFO_4 (1 << 8)
#define VIDC20_CTRL_FIFO_8 (2 << 8)
#define VIDC20_CTRL_FIFO_12 (3 << 8)
#define VIDC20_CTRL_FIFO_16 (4 << 8)
#define VIDC20_CTRL_FIFO_20 (5 << 8)
#define VIDC20_CTRL_FIFO_24 (6 << 8)
#define VIDC20_CTRL_FIFO_28 (7 << 8)
#define VIDC20_CTRL_INT (1 << 12)
#define VIDC20_CTRL_DUP (1 << 13)
#define VIDC20_CTRL_PDOWN (1 << 14)
#define VIDC20_ECTL 0xc0000000
#define VIDC20_ECTL_REG(x) ((x) & 0xf3)
#define VIDC20_ECTL_ECK (1 << 2)
#define VIDC20_ECTL_REDPED (1 << 8)
#define VIDC20_ECTL_GREENPED (1 << 9)
#define VIDC20_ECTL_BLUEPED (1 << 10)
#define VIDC20_ECTL_DAC (1 << 12)
#define VIDC20_ECTL_LCDGS (1 << 13)
#define VIDC20_ECTL_HRM (1 << 14)
#define VIDC20_ECTL_HS_MASK (3 << 16)
#define VIDC20_ECTL_HS_HSYNC (0 << 16)
#define VIDC20_ECTL_HS_NHSYNC (1 << 16)
#define VIDC20_ECTL_HS_CSYNC (2 << 16)
#define VIDC20_ECTL_HS_NCSYNC (3 << 16)
#define VIDC20_ECTL_VS_MASK (3 << 18)
#define VIDC20_ECTL_VS_VSYNC (0 << 18)
#define VIDC20_ECTL_VS_NVSYNC (1 << 18)
#define VIDC20_ECTL_VS_CSYNC (2 << 18)
#define VIDC20_ECTL_VS_NCSYNC (3 << 18)
#define VIDC20_DCTL 0xf0000000
/* 0-9 = number of words in scanline */
#define VIDC20_DCTL_SNA (1 << 12)
#define VIDC20_DCTL_HDIS (1 << 13)
#define VIDC20_DCTL_BUS_NS (0 << 16)
#define VIDC20_DCTL_BUS_D31_0 (1 << 16)
#define VIDC20_DCTL_BUS_D63_32 (2 << 16)
#define VIDC20_DCTL_BUS_D63_0 (3 << 16)
#define VIDC20_DCTL_VRAM_DIS (0 << 18)
#define VIDC20_DCTL_VRAM_PXCLK (1 << 18)
#define VIDC20_DCTL_VRAM_PXCLK2 (2 << 18)
#define VIDC20_DCTL_VRAM_PXCLK4 (3 << 18)
#endif

View file

@ -0,0 +1,656 @@
/*
* linux/drivers/video/amba-clcd.c
*
* Copyright (C) 2001 ARM Limited, by David A Rusling
* Updated to 2.5, Deep Blue Solutions Ltd.
*
* 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.
*
* ARM PrimeCell PL110 Color LCD Controller
*/
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/clk.h>
#include <linux/hardirq.h>
#include <asm/sizes.h>
#define to_clcd(info) container_of(info, struct clcd_fb, fb)
/* This is limited to 16 characters when displayed by X startup */
static const char *clcd_name = "CLCD FB";
/*
* Unfortunately, the enable/disable functions may be called either from
* process or IRQ context, and we _need_ to delay. This is _not_ good.
*/
static inline void clcdfb_sleep(unsigned int ms)
{
if (in_atomic()) {
mdelay(ms);
} else {
msleep(ms);
}
}
static inline void clcdfb_set_start(struct clcd_fb *fb)
{
unsigned long ustart = fb->fb.fix.smem_start;
unsigned long lstart;
ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
writel(ustart, fb->regs + CLCD_UBAS);
writel(lstart, fb->regs + CLCD_LBAS);
}
static void clcdfb_disable(struct clcd_fb *fb)
{
u32 val;
if (fb->board->disable)
fb->board->disable(fb);
val = readl(fb->regs + fb->off_cntl);
if (val & CNTL_LCDPWR) {
val &= ~CNTL_LCDPWR;
writel(val, fb->regs + fb->off_cntl);
clcdfb_sleep(20);
}
if (val & CNTL_LCDEN) {
val &= ~CNTL_LCDEN;
writel(val, fb->regs + fb->off_cntl);
}
/*
* Disable CLCD clock source.
*/
if (fb->clk_enabled) {
fb->clk_enabled = false;
clk_disable(fb->clk);
}
}
static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
{
/*
* Enable the CLCD clock source.
*/
if (!fb->clk_enabled) {
fb->clk_enabled = true;
clk_enable(fb->clk);
}
/*
* Bring up by first enabling..
*/
cntl |= CNTL_LCDEN;
writel(cntl, fb->regs + fb->off_cntl);
clcdfb_sleep(20);
/*
* and now apply power.
*/
cntl |= CNTL_LCDPWR;
writel(cntl, fb->regs + fb->off_cntl);
/*
* finally, enable the interface.
*/
if (fb->board->enable)
fb->board->enable(fb);
}
static int
clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
{
u32 caps;
int ret = 0;
if (fb->panel->caps && fb->board->caps)
caps = fb->panel->caps & fb->board->caps;
else {
/* Old way of specifying what can be used */
caps = fb->panel->cntl & CNTL_BGR ?
CLCD_CAP_BGR : CLCD_CAP_RGB;
/* But mask out 444 modes as they weren't supported */
caps &= ~CLCD_CAP_444;
}
/* Only TFT panels can do RGB888/BGR888 */
if (!(fb->panel->cntl & CNTL_LCDTFT))
caps &= ~CLCD_CAP_888;
memset(&var->transp, 0, sizeof(var->transp));
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
switch (var->bits_per_pixel) {
case 1:
case 2:
case 4:
case 8:
/* If we can't do 5551, reject */
caps &= CLCD_CAP_5551;
if (!caps) {
ret = -EINVAL;
break;
}
var->red.length = var->bits_per_pixel;
var->red.offset = 0;
var->green.length = var->bits_per_pixel;
var->green.offset = 0;
var->blue.length = var->bits_per_pixel;
var->blue.offset = 0;
break;
case 16:
/* If we can't do 444, 5551 or 565, reject */
if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
ret = -EINVAL;
break;
}
/*
* Green length can be 4, 5 or 6 depending whether
* we're operating in 444, 5551 or 565 mode.
*/
if (var->green.length == 4 && caps & CLCD_CAP_444)
caps &= CLCD_CAP_444;
if (var->green.length == 5 && caps & CLCD_CAP_5551)
caps &= CLCD_CAP_5551;
else if (var->green.length == 6 && caps & CLCD_CAP_565)
caps &= CLCD_CAP_565;
else {
/*
* PL110 officially only supports RGB555,
* but may be wired up to allow RGB565.
*/
if (caps & CLCD_CAP_565) {
var->green.length = 6;
caps &= CLCD_CAP_565;
} else if (caps & CLCD_CAP_5551) {
var->green.length = 5;
caps &= CLCD_CAP_5551;
} else {
var->green.length = 4;
caps &= CLCD_CAP_444;
}
}
if (var->green.length >= 5) {
var->red.length = 5;
var->blue.length = 5;
} else {
var->red.length = 4;
var->blue.length = 4;
}
break;
case 32:
/* If we can't do 888, reject */
caps &= CLCD_CAP_888;
if (!caps) {
ret = -EINVAL;
break;
}
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
break;
default:
ret = -EINVAL;
break;
}
/*
* >= 16bpp displays have separate colour component bitfields
* encoded in the pixel data. Calculate their position from
* the bitfield length defined above.
*/
if (ret == 0 && var->bits_per_pixel >= 16) {
bool bgr, rgb;
bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
if (!bgr && !rgb)
/*
* The requested format was not possible, try just
* our capabilities. One of BGR or RGB must be
* supported.
*/
bgr = caps & CLCD_CAP_BGR;
if (bgr) {
var->blue.offset = 0;
var->green.offset = var->blue.offset + var->blue.length;
var->red.offset = var->green.offset + var->green.length;
} else {
var->red.offset = 0;
var->green.offset = var->red.offset + var->red.length;
var->blue.offset = var->green.offset + var->green.length;
}
}
return ret;
}
static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
int ret = -EINVAL;
if (fb->board->check)
ret = fb->board->check(fb, var);
if (ret == 0 &&
var->xres_virtual * var->bits_per_pixel / 8 *
var->yres_virtual > fb->fb.fix.smem_len)
ret = -EINVAL;
if (ret == 0)
ret = clcdfb_set_bitfields(fb, var);
return ret;
}
static int clcdfb_set_par(struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
struct clcd_regs regs;
fb->fb.fix.line_length = fb->fb.var.xres_virtual *
fb->fb.var.bits_per_pixel / 8;
if (fb->fb.var.bits_per_pixel <= 8)
fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
else
fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
fb->board->decode(fb, &regs);
clcdfb_disable(fb);
writel(regs.tim0, fb->regs + CLCD_TIM0);
writel(regs.tim1, fb->regs + CLCD_TIM1);
writel(regs.tim2, fb->regs + CLCD_TIM2);
writel(regs.tim3, fb->regs + CLCD_TIM3);
clcdfb_set_start(fb);
clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
fb->clcd_cntl = regs.cntl;
clcdfb_enable(fb, regs.cntl);
#ifdef DEBUG
printk(KERN_INFO
"CLCD: Registers set to\n"
" %08x %08x %08x %08x\n"
" %08x %08x %08x %08x\n",
readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
#endif
return 0;
}
static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
{
unsigned int mask = (1 << bf->length) - 1;
return (val >> (16 - bf->length) & mask) << bf->offset;
}
/*
* Set a single color register. The values supplied have a 16 bit
* magnitude. Return != 0 for invalid regno.
*/
static int
clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
unsigned int blue, unsigned int transp, struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
if (regno < 16)
fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
convert_bitfield(blue, &fb->fb.var.blue) |
convert_bitfield(green, &fb->fb.var.green) |
convert_bitfield(red, &fb->fb.var.red);
if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
u32 val, mask, newval;
newval = (red >> 11) & 0x001f;
newval |= (green >> 6) & 0x03e0;
newval |= (blue >> 1) & 0x7c00;
/*
* 3.2.11: if we're configured for big endian
* byte order, the palette entries are swapped.
*/
if (fb->clcd_cntl & CNTL_BEBO)
regno ^= 1;
if (regno & 1) {
newval <<= 16;
mask = 0x0000ffff;
} else {
mask = 0xffff0000;
}
val = readl(fb->regs + hw_reg) & mask;
writel(val | newval, fb->regs + hw_reg);
}
return regno > 255;
}
/*
* Blank the screen if blank_mode != 0, else unblank. If blank == NULL
* then the caller blanks by setting the CLUT (Color Look Up Table) to all
* black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
* to e.g. a video mode which doesn't support it. Implements VESA suspend
* and powerdown modes on hardware that supports disabling hsync/vsync:
* blank_mode == 2: suspend vsync
* blank_mode == 3: suspend hsync
* blank_mode == 4: powerdown
*/
static int clcdfb_blank(int blank_mode, struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
if (blank_mode != 0) {
clcdfb_disable(fb);
} else {
clcdfb_enable(fb, fb->clcd_cntl);
}
return 0;
}
static int clcdfb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct clcd_fb *fb = to_clcd(info);
unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
int ret = -EINVAL;
len = info->fix.smem_len;
if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
fb->board->mmap)
ret = fb->board->mmap(fb, vma);
return ret;
}
static struct fb_ops clcdfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = clcdfb_check_var,
.fb_set_par = clcdfb_set_par,
.fb_setcolreg = clcdfb_setcolreg,
.fb_blank = clcdfb_blank,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_mmap = clcdfb_mmap,
};
static int clcdfb_register(struct clcd_fb *fb)
{
int ret;
/*
* ARM PL111 always has IENB at 0x1c; it's only PL110
* which is reversed on some platforms.
*/
if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
fb->off_ienb = CLCD_PL111_IENB;
fb->off_cntl = CLCD_PL111_CNTL;
} else {
#ifdef CONFIG_ARCH_VERSATILE
fb->off_ienb = CLCD_PL111_IENB;
fb->off_cntl = CLCD_PL111_CNTL;
#else
fb->off_ienb = CLCD_PL110_IENB;
fb->off_cntl = CLCD_PL110_CNTL;
#endif
}
fb->clk = clk_get(&fb->dev->dev, NULL);
if (IS_ERR(fb->clk)) {
ret = PTR_ERR(fb->clk);
goto out;
}
ret = clk_prepare(fb->clk);
if (ret)
goto free_clk;
fb->fb.device = &fb->dev->dev;
fb->fb.fix.mmio_start = fb->dev->res.start;
fb->fb.fix.mmio_len = resource_size(&fb->dev->res);
fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
if (!fb->regs) {
printk(KERN_ERR "CLCD: unable to remap registers\n");
ret = -ENOMEM;
goto clk_unprep;
}
fb->fb.fbops = &clcdfb_ops;
fb->fb.flags = FBINFO_FLAG_DEFAULT;
fb->fb.pseudo_palette = fb->cmap;
strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
fb->fb.fix.type_aux = 0;
fb->fb.fix.xpanstep = 0;
fb->fb.fix.ypanstep = 0;
fb->fb.fix.ywrapstep = 0;
fb->fb.fix.accel = FB_ACCEL_NONE;
fb->fb.var.xres = fb->panel->mode.xres;
fb->fb.var.yres = fb->panel->mode.yres;
fb->fb.var.xres_virtual = fb->panel->mode.xres;
fb->fb.var.yres_virtual = fb->panel->mode.yres;
fb->fb.var.bits_per_pixel = fb->panel->bpp;
fb->fb.var.grayscale = fb->panel->grayscale;
fb->fb.var.pixclock = fb->panel->mode.pixclock;
fb->fb.var.left_margin = fb->panel->mode.left_margin;
fb->fb.var.right_margin = fb->panel->mode.right_margin;
fb->fb.var.upper_margin = fb->panel->mode.upper_margin;
fb->fb.var.lower_margin = fb->panel->mode.lower_margin;
fb->fb.var.hsync_len = fb->panel->mode.hsync_len;
fb->fb.var.vsync_len = fb->panel->mode.vsync_len;
fb->fb.var.sync = fb->panel->mode.sync;
fb->fb.var.vmode = fb->panel->mode.vmode;
fb->fb.var.activate = FB_ACTIVATE_NOW;
fb->fb.var.nonstd = 0;
fb->fb.var.height = fb->panel->height;
fb->fb.var.width = fb->panel->width;
fb->fb.var.accel_flags = 0;
fb->fb.monspecs.hfmin = 0;
fb->fb.monspecs.hfmax = 100000;
fb->fb.monspecs.vfmin = 0;
fb->fb.monspecs.vfmax = 400;
fb->fb.monspecs.dclkmin = 1000000;
fb->fb.monspecs.dclkmax = 100000000;
/*
* Make sure that the bitfields are set appropriately.
*/
clcdfb_set_bitfields(fb, &fb->fb.var);
/*
* Allocate colourmap.
*/
ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
if (ret)
goto unmap;
/*
* Ensure interrupts are disabled.
*/
writel(0, fb->regs + fb->off_ienb);
fb_set_var(&fb->fb, &fb->fb.var);
dev_info(&fb->dev->dev, "%s hardware, %s display\n",
fb->board->name, fb->panel->mode.name);
ret = register_framebuffer(&fb->fb);
if (ret == 0)
goto out;
printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
fb_dealloc_cmap(&fb->fb.cmap);
unmap:
iounmap(fb->regs);
clk_unprep:
clk_unprepare(fb->clk);
free_clk:
clk_put(fb->clk);
out:
return ret;
}
static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
{
struct clcd_board *board = dev_get_platdata(&dev->dev);
struct clcd_fb *fb;
int ret;
if (!board)
return -EINVAL;
ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
if (ret)
goto out;
ret = amba_request_regions(dev, NULL);
if (ret) {
printk(KERN_ERR "CLCD: unable to reserve regs region\n");
goto out;
}
fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL);
if (!fb) {
printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
ret = -ENOMEM;
goto free_region;
}
fb->dev = dev;
fb->board = board;
dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n",
amba_part(dev), amba_rev(dev),
(unsigned long long)dev->res.start);
ret = fb->board->setup(fb);
if (ret)
goto free_fb;
ret = clcdfb_register(fb);
if (ret == 0) {
amba_set_drvdata(dev, fb);
goto out;
}
fb->board->remove(fb);
free_fb:
kfree(fb);
free_region:
amba_release_regions(dev);
out:
return ret;
}
static int clcdfb_remove(struct amba_device *dev)
{
struct clcd_fb *fb = amba_get_drvdata(dev);
clcdfb_disable(fb);
unregister_framebuffer(&fb->fb);
if (fb->fb.cmap.len)
fb_dealloc_cmap(&fb->fb.cmap);
iounmap(fb->regs);
clk_unprepare(fb->clk);
clk_put(fb->clk);
fb->board->remove(fb);
kfree(fb);
amba_release_regions(dev);
return 0;
}
static struct amba_id clcdfb_id_table[] = {
{
.id = 0x00041110,
.mask = 0x000ffffe,
},
{ 0, 0 },
};
MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
static struct amba_driver clcd_driver = {
.drv = {
.name = "clcd-pl11x",
},
.probe = clcdfb_probe,
.remove = clcdfb_remove,
.id_table = clcdfb_id_table,
};
static int __init amba_clcdfb_init(void)
{
if (fb_get_options("ambafb", NULL))
return -ENODEV;
return amba_driver_register(&clcd_driver);
}
module_init(amba_clcdfb_init);
static void __exit amba_clcdfb_exit(void)
{
amba_driver_unregister(&clcd_driver);
}
module_exit(amba_clcdfb_exit);
MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
MODULE_LICENSE("GPL");

3792
drivers/video/fbdev/amifb.c Normal file

File diff suppressed because it is too large Load diff

667
drivers/video/fbdev/arcfb.c Normal file
View file

@ -0,0 +1,667 @@
/*
* linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board
*
* Copyright (C) 2005, Jaya Kumar <jayalk@intworks.biz>
*
* 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.
*
* Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
*
* This driver was written to be used with the Arc LCD board. Arc uses a
* set of KS108 chips that control individual 64x64 LCD matrices. The board
* can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and
* so on. The interface between the board and the host is TTL based GPIO. The
* GPIO requirements are 8 writable data lines and 4+n lines for control. On a
* GPIO-less system, the board can be tested by connecting the respective sigs
* up to a parallel port connector. The driver requires the IO addresses for
* data and control GPIO at load time. It is unable to probe for the
* existence of the LCD so it must be told at load time whether it should
* be enabled or not.
*
* Todo:
* - testing with 4x4
* - testing with interrupt hw
*
* General notes:
* - User must set tuhold. It's in microseconds. According to the 108 spec,
* the hold time is supposed to be at least 1 microsecond.
* - User must set num_cols=x num_rows=y, eg: x=2 means 128
* - User must set arcfb_enable=1 to enable it
* - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/arcfb.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#define floor8(a) (a&(~0x07))
#define floorXres(a,xres) (a&(~(xres - 1)))
#define iceil8(a) (((int)((a+7)/8))*8)
#define ceil64(a) (a|0x3F)
#define ceilXres(a,xres) (a|(xres - 1))
/* ks108 chipset specific defines and code */
#define KS_SET_DPY_START_LINE 0xC0
#define KS_SET_PAGE_NUM 0xB8
#define KS_SET_X 0x40
#define KS_CEHI 0x01
#define KS_CELO 0x00
#define KS_SEL_CMD 0x08
#define KS_SEL_DATA 0x00
#define KS_DPY_ON 0x3F
#define KS_DPY_OFF 0x3E
#define KS_INTACK 0x40
#define KS_CLRINT 0x02
struct arcfb_par {
unsigned long dio_addr;
unsigned long cio_addr;
unsigned long c2io_addr;
atomic_t ref_count;
unsigned char cslut[9];
struct fb_info *info;
unsigned int irq;
spinlock_t lock;
};
static struct fb_fix_screeninfo arcfb_fix = {
.id = "arcfb",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_MONO01,
.xpanstep = 0,
.ypanstep = 1,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
static struct fb_var_screeninfo arcfb_var = {
.xres = 128,
.yres = 64,
.xres_virtual = 128,
.yres_virtual = 64,
.bits_per_pixel = 1,
.nonstd = 1,
};
static unsigned long num_cols;
static unsigned long num_rows;
static unsigned long dio_addr;
static unsigned long cio_addr;
static unsigned long c2io_addr;
static unsigned long splashval;
static unsigned long tuhold;
static unsigned int nosplash;
static unsigned int arcfb_enable;
static unsigned int irq;
static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq);
static void ks108_writeb_ctl(struct arcfb_par *par,
unsigned int chipindex, unsigned char value)
{
unsigned char chipselval = par->cslut[chipindex];
outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr);
outb(value, par->dio_addr);
udelay(tuhold);
outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr);
}
static void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value)
{
outb(value, par->cio_addr);
udelay(tuhold);
}
static unsigned char ks108_readb_ctl2(struct arcfb_par *par)
{
return inb(par->c2io_addr);
}
static void ks108_writeb_data(struct arcfb_par *par,
unsigned int chipindex, unsigned char value)
{
unsigned char chipselval = par->cslut[chipindex];
outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr);
outb(value, par->dio_addr);
udelay(tuhold);
outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr);
}
static void ks108_set_start_line(struct arcfb_par *par,
unsigned int chipindex, unsigned char y)
{
ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y);
}
static void ks108_set_yaddr(struct arcfb_par *par,
unsigned int chipindex, unsigned char y)
{
ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y);
}
static void ks108_set_xaddr(struct arcfb_par *par,
unsigned int chipindex, unsigned char x)
{
ks108_writeb_ctl(par, chipindex, KS_SET_X|x);
}
static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex)
{
int i,j;
for (i = 0; i <= 8; i++) {
ks108_set_yaddr(par, chipindex, i);
ks108_set_xaddr(par, chipindex, 0);
for (j = 0; j < 64; j++) {
ks108_writeb_data(par, chipindex,
(unsigned char) splashval);
}
}
}
/* main arcfb functions */
static int arcfb_open(struct fb_info *info, int user)
{
struct arcfb_par *par = info->par;
atomic_inc(&par->ref_count);
return 0;
}
static int arcfb_release(struct fb_info *info, int user)
{
struct arcfb_par *par = info->par;
int count = atomic_read(&par->ref_count);
if (!count)
return -EINVAL;
atomic_dec(&par->ref_count);
return 0;
}
static int arcfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
int i;
struct arcfb_par *par = info->par;
if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64)
&& (info->var.yres <= 64)) {
for (i = 0; i < num_cols; i++) {
ks108_set_start_line(par, i, var->yoffset);
}
info->var.yoffset = var->yoffset;
return 0;
}
return -EINVAL;
}
static irqreturn_t arcfb_interrupt(int vec, void *dev_instance)
{
struct fb_info *info = dev_instance;
unsigned char ctl2status;
struct arcfb_par *par = info->par;
ctl2status = ks108_readb_ctl2(par);
if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */
return IRQ_NONE;
ks108_writeb_mainctl(par, KS_CLRINT);
spin_lock(&par->lock);
if (waitqueue_active(&arcfb_waitq)) {
wake_up(&arcfb_waitq);
}
spin_unlock(&par->lock);
return IRQ_HANDLED;
}
/*
* here we handle a specific page on the lcd. the complexity comes from
* the fact that the fb is laidout in 8xX vertical columns. we extract
* each write of 8 vertical pixels. then we shift out as we move along
* X. That's what rightshift does. bitmask selects the desired input bit.
*/
static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper,
unsigned int left, unsigned int right, unsigned int distance)
{
unsigned char *src;
unsigned int xindex, yindex, chipindex, linesize;
int i;
unsigned char val;
unsigned char bitmask, rightshift;
xindex = left >> 6;
yindex = upper >> 6;
chipindex = (xindex + (yindex*num_cols));
ks108_set_yaddr(par, chipindex, upper/8);
linesize = par->info->var.xres/8;
src = (unsigned char __force *) par->info->screen_base + (left/8) +
(upper * linesize);
ks108_set_xaddr(par, chipindex, left);
bitmask=1;
rightshift=0;
while (left <= right) {
val = 0;
for (i = 0; i < 8; i++) {
if ( i > rightshift) {
val |= (*(src + (i*linesize)) & bitmask)
<< (i - rightshift);
} else {
val |= (*(src + (i*linesize)) & bitmask)
>> (rightshift - i);
}
}
ks108_writeb_data(par, chipindex, val);
left++;
if (bitmask == 0x80) {
bitmask = 1;
src++;
rightshift=0;
} else {
bitmask <<= 1;
rightshift++;
}
}
}
/*
* here we handle the entire vertical page of the update. we write across
* lcd chips. update_page uses the upper/left values to decide which
* chip to select for the right. upper is needed for setting the page
* desired for the write.
*/
static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top,
unsigned int bottom, unsigned int left, unsigned int right)
{
unsigned int distance, upper, lower;
distance = (bottom - top) + 1;
upper = top;
lower = top + 7;
while (distance > 0) {
distance -= 8;
arcfb_lcd_update_page(par, upper, left, right, 8);
upper = lower + 1;
lower = upper + 7;
}
}
/*
* here we handle horizontal blocks for the update. update_vert will
* handle spaning multiple pages. we break out each horizontal
* block in to individual blocks no taller than 64 pixels.
*/
static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left,
unsigned int right, unsigned int top, unsigned int h)
{
unsigned int distance, upper, lower;
distance = h;
upper = floor8(top);
lower = min(upper + distance - 1, ceil64(upper));
while (distance > 0) {
distance -= ((lower - upper) + 1 );
arcfb_lcd_update_vert(par, upper, lower, left, right);
upper = lower + 1;
lower = min(upper + distance - 1, ceil64(upper));
}
}
/*
* here we start the process of splitting out the fb update into
* individual blocks of pixels. we end up splitting into 64x64 blocks
* and finally down to 64x8 pages.
*/
static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx,
unsigned int dy, unsigned int w, unsigned int h)
{
unsigned int left, right, distance, y;
/* align the request first */
y = floor8(dy);
h += dy - y;
h = iceil8(h);
distance = w;
left = dx;
right = min(left + w - 1, ceil64(left));
while (distance > 0) {
arcfb_lcd_update_horiz(par, left, right, y, h);
distance -= ((right - left) + 1);
left = right + 1;
right = min(left + distance - 1, ceil64(left));
}
}
static void arcfb_fillrect(struct fb_info *info,
const struct fb_fillrect *rect)
{
struct arcfb_par *par = info->par;
sys_fillrect(info, rect);
/* update the physical lcd */
arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height);
}
static void arcfb_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
struct arcfb_par *par = info->par;
sys_copyarea(info, area);
/* update the physical lcd */
arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height);
}
static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct arcfb_par *par = info->par;
sys_imageblit(info, image);
/* update the physical lcd */
arcfb_lcd_update(par, image->dx, image->dy, image->width,
image->height);
}
static int arcfb_ioctl(struct fb_info *info,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
struct arcfb_par *par = info->par;
unsigned long flags;
switch (cmd) {
case FBIO_WAITEVENT:
{
DEFINE_WAIT(wait);
/* illegal to wait on arc if no irq will occur */
if (!par->irq)
return -EINVAL;
/* wait until the Arc has generated an interrupt
* which will wake us up */
spin_lock_irqsave(&par->lock, flags);
prepare_to_wait(&arcfb_waitq, &wait,
TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&par->lock, flags);
schedule();
finish_wait(&arcfb_waitq, &wait);
}
case FBIO_GETCONTROL2:
{
unsigned char ctl2;
ctl2 = ks108_readb_ctl2(info->par);
if (copy_to_user(argp, &ctl2, sizeof(ctl2)))
return -EFAULT;
return 0;
}
default:
return -EINVAL;
}
}
/*
* this is the access path from userspace. they can seek and write to
* the fb. it's inefficient for them to do anything less than 64*8
* writes since we update the lcd in each write() anyway.
*/
static ssize_t arcfb_write(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos)
{
/* modded from epson 1355 */
unsigned long p;
int err=-EINVAL;
unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
struct arcfb_par *par;
unsigned int xres;
p = *ppos;
par = info->par;
xres = info->var.xres;
fbmemlength = (xres * info->var.yres)/8;
if (p > fbmemlength)
return -ENOSPC;
err = 0;
if ((count + p) > fbmemlength) {
count = fbmemlength - p;
err = -ENOSPC;
}
if (count) {
char *base_addr;
base_addr = (char __force *)info->screen_base;
count -= copy_from_user(base_addr + p, buf, count);
*ppos += count;
err = -EFAULT;
}
bitppos = p*8;
startpos = floorXres(bitppos, xres);
endpos = ceilXres((bitppos + (count*8)), xres);
bitcount = endpos - startpos;
x = startpos % xres;
y = startpos / xres;
w = xres;
h = bitcount / xres;
arcfb_lcd_update(par, x, y, w, h);
if (count)
return count;
return err;
}
static struct fb_ops arcfb_ops = {
.owner = THIS_MODULE,
.fb_open = arcfb_open,
.fb_read = fb_sys_read,
.fb_write = arcfb_write,
.fb_release = arcfb_release,
.fb_pan_display = arcfb_pan_display,
.fb_fillrect = arcfb_fillrect,
.fb_copyarea = arcfb_copyarea,
.fb_imageblit = arcfb_imageblit,
.fb_ioctl = arcfb_ioctl,
};
static int arcfb_probe(struct platform_device *dev)
{
struct fb_info *info;
int retval = -ENOMEM;
int videomemorysize;
unsigned char *videomemory;
struct arcfb_par *par;
int i;
videomemorysize = (((64*64)*num_cols)*num_rows)/8;
/* We need a flat backing store for the Arc's
less-flat actual paged framebuffer */
videomemory = vzalloc(videomemorysize);
if (!videomemory)
return retval;
info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev);
if (!info)
goto err;
info->screen_base = (char __iomem *)videomemory;
info->fbops = &arcfb_ops;
info->var = arcfb_var;
info->fix = arcfb_fix;
par = info->par;
par->info = info;
if (!dio_addr || !cio_addr || !c2io_addr) {
printk(KERN_WARNING "no IO addresses supplied\n");
goto err1;
}
par->dio_addr = dio_addr;
par->cio_addr = cio_addr;
par->c2io_addr = c2io_addr;
par->cslut[0] = 0x00;
par->cslut[1] = 0x06;
info->flags = FBINFO_FLAG_DEFAULT;
spin_lock_init(&par->lock);
retval = register_framebuffer(info);
if (retval < 0)
goto err1;
platform_set_drvdata(dev, info);
if (irq) {
par->irq = irq;
if (request_irq(par->irq, &arcfb_interrupt, IRQF_SHARED,
"arcfb", info)) {
printk(KERN_INFO
"arcfb: Failed req IRQ %d\n", par->irq);
retval = -EBUSY;
goto err1;
}
}
fb_info(info, "Arc frame buffer device, using %dK of video memory\n",
videomemorysize >> 10);
/* this inits the lcd but doesn't clear dirty pixels */
for (i = 0; i < num_cols * num_rows; i++) {
ks108_writeb_ctl(par, i, KS_DPY_OFF);
ks108_set_start_line(par, i, 0);
ks108_set_yaddr(par, i, 0);
ks108_set_xaddr(par, i, 0);
ks108_writeb_ctl(par, i, KS_DPY_ON);
}
/* if we were told to splash the screen, we just clear it */
if (!nosplash) {
for (i = 0; i < num_cols * num_rows; i++) {
fb_info(info, "splashing lcd %d\n", i);
ks108_set_start_line(par, i, 0);
ks108_clear_lcd(par, i);
}
}
return 0;
err1:
framebuffer_release(info);
err:
vfree(videomemory);
return retval;
}
static int arcfb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
if (info) {
unregister_framebuffer(info);
vfree((void __force *)info->screen_base);
framebuffer_release(info);
}
return 0;
}
static struct platform_driver arcfb_driver = {
.probe = arcfb_probe,
.remove = arcfb_remove,
.driver = {
.name = "arcfb",
},
};
static struct platform_device *arcfb_device;
static int __init arcfb_init(void)
{
int ret;
if (!arcfb_enable)
return -ENXIO;
ret = platform_driver_register(&arcfb_driver);
if (!ret) {
arcfb_device = platform_device_alloc("arcfb", 0);
if (arcfb_device) {
ret = platform_device_add(arcfb_device);
} else {
ret = -ENOMEM;
}
if (ret) {
platform_device_put(arcfb_device);
platform_driver_unregister(&arcfb_driver);
}
}
return ret;
}
static void __exit arcfb_exit(void)
{
platform_device_unregister(arcfb_device);
platform_driver_unregister(&arcfb_driver);
}
module_param(num_cols, ulong, 0);
MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide");
module_param(num_rows, ulong, 0);
MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high");
module_param(nosplash, uint, 0);
MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
module_param(arcfb_enable, uint, 0);
MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board");
module_param(dio_addr, ulong, 0);
MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
module_param(cio_addr, ulong, 0);
MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
module_param(c2io_addr, ulong, 0);
MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
module_param(splashval, ulong, 0);
MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green");
module_param(tuhold, ulong, 0);
MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board");
module_param(irq, uint, 0);
MODULE_PARM_DESC(irq, "IRQ for the Arc board");
module_init(arcfb_init);
module_exit(arcfb_exit);
MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board");
MODULE_AUTHOR("Jaya Kumar");
MODULE_LICENSE("GPL");

1231
drivers/video/fbdev/arkfb.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,624 @@
/*
* drivers/video/asiliantfb.c
* frame buffer driver for Asiliant 69000 chip
* Copyright (C) 2001-2003 Saito.K & Jeanne
*
* from driver/video/chipsfb.c and,
*
* drivers/video/asiliantfb.c -- frame buffer device for
* Asiliant 69030 chip (formerly Intel, formerly Chips & Technologies)
* Author: apc@agelectronics.co.uk
* Copyright (C) 2000 AG Electronics
* Note: the data sheets don't seem to be available from Asiliant.
* They are available by searching developer.intel.com, but are not otherwise
* linked to.
*
* This driver should be portable with minimal effort to the 69000 display
* chip, and to the twin-display mode of the 69030.
* Contains code from Thomas Hhenleitner <th@visuelle-maschinen.de> (thanks)
*
* Derived from the CT65550 driver chipsfb.c:
* Copyright (C) 1998 Paul Mackerras
* ...which was derived from the Powermac "chips" driver:
* Copyright (C) 1997 Fabio Riccardi.
* And from the frame buffer device for Open Firmware-initialized devices:
* Copyright (C) 1997 Geert Uytterhoeven.
*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
/* Built in clock of the 69030 */
static const unsigned Fref = 14318180;
#define mmio_base (p->screen_base + 0x400000)
#define mm_write_ind(num, val, ap, dp) do { \
writeb((num), mmio_base + (ap)); writeb((val), mmio_base + (dp)); \
} while (0)
static void mm_write_xr(struct fb_info *p, u8 reg, u8 data)
{
mm_write_ind(reg, data, 0x7ac, 0x7ad);
}
#define write_xr(num, val) mm_write_xr(p, num, val)
static void mm_write_fr(struct fb_info *p, u8 reg, u8 data)
{
mm_write_ind(reg, data, 0x7a0, 0x7a1);
}
#define write_fr(num, val) mm_write_fr(p, num, val)
static void mm_write_cr(struct fb_info *p, u8 reg, u8 data)
{
mm_write_ind(reg, data, 0x7a8, 0x7a9);
}
#define write_cr(num, val) mm_write_cr(p, num, val)
static void mm_write_gr(struct fb_info *p, u8 reg, u8 data)
{
mm_write_ind(reg, data, 0x79c, 0x79d);
}
#define write_gr(num, val) mm_write_gr(p, num, val)
static void mm_write_sr(struct fb_info *p, u8 reg, u8 data)
{
mm_write_ind(reg, data, 0x788, 0x789);
}
#define write_sr(num, val) mm_write_sr(p, num, val)
static void mm_write_ar(struct fb_info *p, u8 reg, u8 data)
{
readb(mmio_base + 0x7b4);
mm_write_ind(reg, data, 0x780, 0x780);
}
#define write_ar(num, val) mm_write_ar(p, num, val)
static int asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *);
static int asiliantfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);
static int asiliantfb_set_par(struct fb_info *info);
static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static struct fb_ops asiliantfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = asiliantfb_check_var,
.fb_set_par = asiliantfb_set_par,
.fb_setcolreg = asiliantfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
/* Calculate the ratios for the dot clocks without using a single long long
* value */
static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div)
{
unsigned pixclock = *ppixclock;
unsigned Ftarget = 1000000 * (1000000 / pixclock);
unsigned n;
unsigned best_error = 0xffffffff;
unsigned best_m = 0xffffffff,
best_n = 0xffffffff;
unsigned ratio;
unsigned remainder;
unsigned char divisor = 0;
/* Calculate the frequency required. This is hard enough. */
ratio = 1000000 / pixclock;
remainder = 1000000 % pixclock;
Ftarget = 1000000 * ratio + (1000000 * remainder) / pixclock;
while (Ftarget < 100000000) {
divisor += 0x10;
Ftarget <<= 1;
}
ratio = Ftarget / Fref;
remainder = Ftarget % Fref;
/* This expresses the constraint that 150kHz <= Fref/n <= 5Mhz,
* together with 3 <= n <= 257. */
for (n = 3; n <= 257; n++) {
unsigned m = n * ratio + (n * remainder) / Fref;
/* 3 <= m <= 257 */
if (m >= 3 && m <= 257) {
unsigned new_error = Ftarget * n >= Fref * m ?
((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n));
if (new_error < best_error) {
best_n = n;
best_m = m;
best_error = new_error;
}
}
/* But if VLD = 4, then 4m <= 1028 */
else if (m <= 1028) {
/* remember there are still only 8-bits of precision in m, so
* avoid over-optimistic error calculations */
unsigned new_error = Ftarget * n >= Fref * (m & ~3) ?
((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n));
if (new_error < best_error) {
best_n = n;
best_m = m;
best_error = new_error;
}
}
}
if (best_m > 257)
best_m >>= 2; /* divide m by 4, and leave VCO loop divide at 4 */
else
divisor |= 4; /* or set VCO loop divide to 1 */
*dclk2_m = best_m - 2;
*dclk2_n = best_n - 2;
*dclk2_div = divisor;
*ppixclock = pixclock;
return;
}
static void asiliant_set_timing(struct fb_info *p)
{
unsigned hd = p->var.xres / 8;
unsigned hs = (p->var.xres + p->var.right_margin) / 8;
unsigned he = (p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
unsigned ht = (p->var.left_margin + p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
unsigned vd = p->var.yres;
unsigned vs = p->var.yres + p->var.lower_margin;
unsigned ve = p->var.yres + p->var.lower_margin + p->var.vsync_len;
unsigned vt = p->var.upper_margin + p->var.yres + p->var.lower_margin + p->var.vsync_len;
unsigned wd = (p->var.xres_virtual * ((p->var.bits_per_pixel+7)/8)) / 8;
if ((p->var.xres == 640) && (p->var.yres == 480) && (p->var.pixclock == 39722)) {
write_fr(0x01, 0x02); /* LCD */
} else {
write_fr(0x01, 0x01); /* CRT */
}
write_cr(0x11, (ve - 1) & 0x0f);
write_cr(0x00, (ht - 5) & 0xff);
write_cr(0x01, hd - 1);
write_cr(0x02, hd);
write_cr(0x03, ((ht - 1) & 0x1f) | 0x80);
write_cr(0x04, hs);
write_cr(0x05, (((ht - 1) & 0x20) <<2) | (he & 0x1f));
write_cr(0x3c, (ht - 1) & 0xc0);
write_cr(0x06, (vt - 2) & 0xff);
write_cr(0x30, (vt - 2) >> 8);
write_cr(0x07, 0x00);
write_cr(0x08, 0x00);
write_cr(0x09, 0x00);
write_cr(0x10, (vs - 1) & 0xff);
write_cr(0x32, ((vs - 1) >> 8) & 0xf);
write_cr(0x11, ((ve - 1) & 0x0f) | 0x80);
write_cr(0x12, (vd - 1) & 0xff);
write_cr(0x31, ((vd - 1) & 0xf00) >> 8);
write_cr(0x13, wd & 0xff);
write_cr(0x41, (wd & 0xf00) >> 8);
write_cr(0x15, (vs - 1) & 0xff);
write_cr(0x33, ((vs - 1) >> 8) & 0xf);
write_cr(0x38, ((ht - 5) & 0x100) >> 8);
write_cr(0x16, (vt - 1) & 0xff);
write_cr(0x18, 0x00);
if (p->var.xres == 640) {
writeb(0xc7, mmio_base + 0x784); /* set misc output reg */
} else {
writeb(0x07, mmio_base + 0x784); /* set misc output reg */
}
}
static int asiliantfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *p)
{
unsigned long Ftarget, ratio, remainder;
ratio = 1000000 / var->pixclock;
remainder = 1000000 % var->pixclock;
Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock;
/* First check the constraint that the maximum post-VCO divisor is 32,
* and the maximum Fvco is 220MHz */
if (Ftarget > 220000000 || Ftarget < 3125000) {
printk(KERN_ERR "asiliantfb dotclock must be between 3.125 and 220MHz\n");
return -ENXIO;
}
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
if (var->bits_per_pixel == 24) {
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = var->blue.length = var->green.length = 8;
} else if (var->bits_per_pixel == 16) {
switch (var->red.offset) {
case 11:
var->green.length = 6;
break;
case 10:
var->green.length = 5;
break;
default:
return -EINVAL;
}
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = var->blue.length = 5;
} else if (var->bits_per_pixel == 8) {
var->red.offset = var->green.offset = var->blue.offset = 0;
var->red.length = var->green.length = var->blue.length = 8;
}
return 0;
}
static int asiliantfb_set_par(struct fb_info *p)
{
u8 dclk2_m; /* Holds m-2 value for register */
u8 dclk2_n; /* Holds n-2 value for register */
u8 dclk2_div; /* Holds divisor bitmask */
/* Set pixclock */
asiliant_calc_dclk2(&p->var.pixclock, &dclk2_m, &dclk2_n, &dclk2_div);
/* Set color depth */
if (p->var.bits_per_pixel == 24) {
write_xr(0x81, 0x16); /* 24 bit packed color mode */
write_xr(0x82, 0x00); /* Disable palettes */
write_xr(0x20, 0x20); /* 24 bit blitter mode */
} else if (p->var.bits_per_pixel == 16) {
if (p->var.red.offset == 11)
write_xr(0x81, 0x15); /* 16 bit color mode */
else
write_xr(0x81, 0x14); /* 15 bit color mode */
write_xr(0x82, 0x00); /* Disable palettes */
write_xr(0x20, 0x10); /* 16 bit blitter mode */
} else if (p->var.bits_per_pixel == 8) {
write_xr(0x0a, 0x02); /* Linear */
write_xr(0x81, 0x12); /* 8 bit color mode */
write_xr(0x82, 0x00); /* Graphics gamma enable */
write_xr(0x20, 0x00); /* 8 bit blitter mode */
}
p->fix.line_length = p->var.xres * (p->var.bits_per_pixel >> 3);
p->fix.visual = (p->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
write_xr(0xc4, dclk2_m);
write_xr(0xc5, dclk2_n);
write_xr(0xc7, dclk2_div);
/* Set up the CR registers */
asiliant_set_timing(p);
return 0;
}
static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *p)
{
if (regno > 255)
return 1;
red >>= 8;
green >>= 8;
blue >>= 8;
/* Set hardware palete */
writeb(regno, mmio_base + 0x790);
udelay(1);
writeb(red, mmio_base + 0x791);
writeb(green, mmio_base + 0x791);
writeb(blue, mmio_base + 0x791);
if (regno < 16) {
switch(p->var.red.offset) {
case 10: /* RGB 555 */
((u32 *)(p->pseudo_palette))[regno] =
((red & 0xf8) << 7) |
((green & 0xf8) << 2) |
((blue & 0xf8) >> 3);
break;
case 11: /* RGB 565 */
((u32 *)(p->pseudo_palette))[regno] =
((red & 0xf8) << 8) |
((green & 0xfc) << 3) |
((blue & 0xf8) >> 3);
break;
case 16: /* RGB 888 */
((u32 *)(p->pseudo_palette))[regno] =
(red << 16) |
(green << 8) |
(blue);
break;
}
}
return 0;
}
struct chips_init_reg {
unsigned char addr;
unsigned char data;
};
static struct chips_init_reg chips_init_sr[] =
{
{0x00, 0x03}, /* Reset register */
{0x01, 0x01}, /* Clocking mode */
{0x02, 0x0f}, /* Plane mask */
{0x04, 0x0e} /* Memory mode */
};
static struct chips_init_reg chips_init_gr[] =
{
{0x03, 0x00}, /* Data rotate */
{0x05, 0x00}, /* Graphics mode */
{0x06, 0x01}, /* Miscellaneous */
{0x08, 0x00} /* Bit mask */
};
static struct chips_init_reg chips_init_ar[] =
{
{0x10, 0x01}, /* Mode control */
{0x11, 0x00}, /* Overscan */
{0x12, 0x0f}, /* Memory plane enable */
{0x13, 0x00} /* Horizontal pixel panning */
};
static struct chips_init_reg chips_init_cr[] =
{
{0x0c, 0x00}, /* Start address high */
{0x0d, 0x00}, /* Start address low */
{0x40, 0x00}, /* Extended Start Address */
{0x41, 0x00}, /* Extended Start Address */
{0x14, 0x00}, /* Underline location */
{0x17, 0xe3}, /* CRT mode control */
{0x70, 0x00} /* Interlace control */
};
static struct chips_init_reg chips_init_fr[] =
{
{0x01, 0x02},
{0x03, 0x08},
{0x08, 0xcc},
{0x0a, 0x08},
{0x18, 0x00},
{0x1e, 0x80},
{0x40, 0x83},
{0x41, 0x00},
{0x48, 0x13},
{0x4d, 0x60},
{0x4e, 0x0f},
{0x0b, 0x01},
{0x21, 0x51},
{0x22, 0x1d},
{0x23, 0x5f},
{0x20, 0x4f},
{0x34, 0x00},
{0x24, 0x51},
{0x25, 0x00},
{0x27, 0x0b},
{0x26, 0x00},
{0x37, 0x80},
{0x33, 0x0b},
{0x35, 0x11},
{0x36, 0x02},
{0x31, 0xea},
{0x32, 0x0c},
{0x30, 0xdf},
{0x10, 0x0c},
{0x11, 0xe0},
{0x12, 0x50},
{0x13, 0x00},
{0x16, 0x03},
{0x17, 0xbd},
{0x1a, 0x00},
};
static struct chips_init_reg chips_init_xr[] =
{
{0xce, 0x00}, /* set default memory clock */
{0xcc, 200 }, /* MCLK ratio M */
{0xcd, 18 }, /* MCLK ratio N */
{0xce, 0x90}, /* MCLK divisor = 2 */
{0xc4, 209 },
{0xc5, 118 },
{0xc7, 32 },
{0xcf, 0x06},
{0x09, 0x01}, /* IO Control - CRT controller extensions */
{0x0a, 0x02}, /* Frame buffer mapping */
{0x0b, 0x01}, /* PCI burst write */
{0x40, 0x03}, /* Memory access control */
{0x80, 0x82}, /* Pixel pipeline configuration 0 */
{0x81, 0x12}, /* Pixel pipeline configuration 1 */
{0x82, 0x08}, /* Pixel pipeline configuration 2 */
{0xd0, 0x0f},
{0xd1, 0x01},
};
static void chips_hw_init(struct fb_info *p)
{
int i;
for (i = 0; i < ARRAY_SIZE(chips_init_xr); ++i)
write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
write_xr(0x81, 0x12);
write_xr(0x82, 0x08);
write_xr(0x20, 0x00);
for (i = 0; i < ARRAY_SIZE(chips_init_sr); ++i)
write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
for (i = 0; i < ARRAY_SIZE(chips_init_gr); ++i)
write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
for (i = 0; i < ARRAY_SIZE(chips_init_ar); ++i)
write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
/* Enable video output in attribute index register */
writeb(0x20, mmio_base + 0x780);
for (i = 0; i < ARRAY_SIZE(chips_init_cr); ++i)
write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
for (i = 0; i < ARRAY_SIZE(chips_init_fr); ++i)
write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
}
static struct fb_fix_screeninfo asiliantfb_fix = {
.id = "Asiliant 69000",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
.accel = FB_ACCEL_NONE,
.line_length = 640,
.smem_len = 0x200000, /* 2MB */
};
static struct fb_var_screeninfo asiliantfb_var = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
.yres_virtual = 480,
.bits_per_pixel = 8,
.red = { .length = 8 },
.green = { .length = 8 },
.blue = { .length = 8 },
.height = -1,
.width = -1,
.vmode = FB_VMODE_NONINTERLACED,
.pixclock = 39722,
.left_margin = 48,
.right_margin = 16,
.upper_margin = 33,
.lower_margin = 10,
.hsync_len = 96,
.vsync_len = 2,
};
static int init_asiliant(struct fb_info *p, unsigned long addr)
{
int err;
p->fix = asiliantfb_fix;
p->fix.smem_start = addr;
p->var = asiliantfb_var;
p->fbops = &asiliantfb_ops;
p->flags = FBINFO_DEFAULT;
err = fb_alloc_cmap(&p->cmap, 256, 0);
if (err) {
printk(KERN_ERR "C&T 69000 fb failed to alloc cmap memory\n");
return err;
}
err = register_framebuffer(p);
if (err < 0) {
printk(KERN_ERR "C&T 69000 framebuffer failed to register\n");
fb_dealloc_cmap(&p->cmap);
return err;
}
fb_info(p, "Asiliant 69000 frame buffer (%dK RAM detected)\n",
p->fix.smem_len / 1024);
writeb(0xff, mmio_base + 0x78c);
chips_hw_init(p);
return 0;
}
static int asiliantfb_pci_init(struct pci_dev *dp,
const struct pci_device_id *ent)
{
unsigned long addr, size;
struct fb_info *p;
int err;
if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
return -ENODEV;
addr = pci_resource_start(dp, 0);
size = pci_resource_len(dp, 0);
if (addr == 0)
return -ENODEV;
if (!request_mem_region(addr, size, "asiliantfb"))
return -EBUSY;
p = framebuffer_alloc(sizeof(u32) * 16, &dp->dev);
if (!p) {
release_mem_region(addr, size);
return -ENOMEM;
}
p->pseudo_palette = p->par;
p->par = NULL;
p->screen_base = ioremap(addr, 0x800000);
if (p->screen_base == NULL) {
release_mem_region(addr, size);
framebuffer_release(p);
return -ENOMEM;
}
pci_write_config_dword(dp, 4, 0x02800083);
writeb(3, p->screen_base + 0x400784);
err = init_asiliant(p, addr);
if (err) {
iounmap(p->screen_base);
release_mem_region(addr, size);
framebuffer_release(p);
return err;
}
pci_set_drvdata(dp, p);
return 0;
}
static void asiliantfb_remove(struct pci_dev *dp)
{
struct fb_info *p = pci_get_drvdata(dp);
unregister_framebuffer(p);
fb_dealloc_cmap(&p->cmap);
iounmap(p->screen_base);
release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
framebuffer_release(p);
}
static struct pci_device_id asiliantfb_pci_tbl[] = {
{ PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000, PCI_ANY_ID, PCI_ANY_ID },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, asiliantfb_pci_tbl);
static struct pci_driver asiliantfb_driver = {
.name = "asiliantfb",
.id_table = asiliantfb_pci_tbl,
.probe = asiliantfb_pci_init,
.remove = asiliantfb_remove,
};
static int __init asiliantfb_init(void)
{
if (fb_get_options("asiliantfb", NULL))
return -ENODEV;
return pci_register_driver(&asiliantfb_driver);
}
module_init(asiliantfb_init);
static void __exit asiliantfb_exit(void)
{
pci_unregister_driver(&asiliantfb_driver);
}
MODULE_LICENSE("GPL");

3266
drivers/video/fbdev/atafb.c Normal file

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more