diff options
Diffstat (limited to 'target/linux/ep93xx/patches-2.6.30/009-ep93xx-fb.patch')
-rw-r--r-- | target/linux/ep93xx/patches-2.6.30/009-ep93xx-fb.patch | 3565 |
1 files changed, 3565 insertions, 0 deletions
diff --git a/target/linux/ep93xx/patches-2.6.30/009-ep93xx-fb.patch b/target/linux/ep93xx/patches-2.6.30/009-ep93xx-fb.patch new file mode 100644 index 0000000..d7816bd --- /dev/null +++ b/target/linux/ep93xx/patches-2.6.30/009-ep93xx-fb.patch @@ -0,0 +1,3565 @@ +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -255,6 +255,25 @@ config FB_CIRRUS + Say N unless you have such a graphics board or plan to get one + before you next recompile the kernel. + ++config FB_EP93XX ++ tristate "EP93xx frame buffer support" ++ depends on FB ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ This is the frame buffer device driver for the internal raster engine ++ on certain members of the EP93xx family. For VGA and LCD output. ++ ++config FB_EP93XX_MONO ++ tristate "EP93xx Mono frame buffer support" ++ depends on FB ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ help ++ This is the frame buffer device driver for the internal raster engine ++ on certain members of the EP93xx family. For LCD output. ++ + config FB_PM2 + tristate "Permedia2 support" + depends on FB && ((AMIGA && BROKEN) || PCI) +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -95,6 +95,8 @@ obj-$(CONFIG_FB_ARMCLCD) += amba-clcd. + obj-$(CONFIG_FB_68328) += 68328fb.o + obj-$(CONFIG_FB_GBE) += gbefb.o + obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o ++obj-$(CONFIG_FB_EP93XX) += ep93xxfb.o ++obj-$(CONFIG_FB_EP93XX_MONO) += ep93xxfb_mono.o + obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o + obj-$(CONFIG_FB_PXA) += pxafb.o + obj-$(CONFIG_FB_W100) += w100fb.o +--- /dev/null ++++ b/drivers/video/ep93xxfb.c +@@ -0,0 +1,1628 @@ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/reboot.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/dma-mapping.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include "ep93xxfb.h" ++#include <mach/hardware.h> ++#include <linux/platform_device.h> ++ ++#include "console/fbcon.h" ++ ++ ++#if defined(CONFIG_MACH_EDB9312) || defined(CONFIG_MACH_EDB9315) || defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) ++#define CONFIG_EP93XX_SDCS3 ++#else ++#define CONFIG_EP93XX_SDCS0 ++#endif ++ ++//#define DEBUG 1 ++#ifdef DEBUG ++#define DPRINTK( fmt, arg... ) printk( fmt, ##arg ) ++#else ++#define DPRINTK( fmt, arg... ) ++#endif ++ ++#define FBDEV_NAME "ep93xxfb" ++ ++#define ep93xxfb_outl(value, reg) \ ++{ \ ++ outl(RASTER_SWLOCK_VALUE, RASTER_SWLOCK); \ ++ outl(value, reg); \ ++} ++ ++#define DEFAULT_OUT CRT_OUT ++#define DEFAULT_MODE 7 ++#define DEFAULT_BPP 24 ++ ++static DECLARE_WAIT_QUEUE_HEAD(ep93xxfb_wait_in); ++ ++static unsigned int pseudo_palette[256]; ++static unsigned long *cursor_data = NULL; ++static struct ep93xxfb_info epinfo; ++ ++static int vout = DEFAULT_OUT; ++static int vmode = DEFAULT_MODE; ++static int depth = DEFAULT_BPP; ++ ++ ++static int ep93xxfb_setcol(struct fb_info *info, int bpp); ++ ++ ++static struct ep93xxfb_videomodes ep93xxfb_vmods[] = { ++ { ++ "Philips-LB064V02-640x480x60", ++ 640, 24, 96, 40, 480, 10, 2, 33, 60, ++ CLK_INTERNAL, EDGE_FALLING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 1 ++ "CRT-640x480-60", ++ 640, 24, 96, 40, 480, 11, 2, 32, 60, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 2 ++ "CRT-640x480-72", ++ 640, 40, 40, 144, 480, 8, 3, 30, 72, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 3 ++ "CRT-640x480-75", ++ 640, 16, 76, 120, 480, 1, 3, 16, 75, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 4 ++ "CRT-640x480-85", ++ 640, 56, 56, 80, 480, 1, 3, 25, 85, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 5 ++ "CTR-640x480-100", ++ 640, 32, 96, 96, 480, 8, 6, 36, 100, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 6 ++ "CRT-800x600-56", ++ 800, 24, 72, 128, 600, 1, 2, 22, 56, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 7 ++ "CRT-800x600-60", ++ 800, 40, 128, 88, 600, 1, 4, 23, 60, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_HIGH, POL_HIGH, ++ }, ++ { // 8 ++ "CRT-800x600-72", ++ 800, 56, 120, 64, 600, 37, 6, 23, 72, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 9 ++ "CRT-800x600-85", ++ 800, 64, 64, 160, 600, 16, 5, 36, 85, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 10 ++ "CRT-800x600-100", ++ 800, 64, 64, 160, 600, 4, 6, 30, 100, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 11 ++ "CRT-1024x768-60", ++ 1024, 8, 144, 168, 768, 3, 6, 29, 60, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 12 ++ "CRT-1024x768-70", ++ 1024, 24, 136, 144, 768, 3, 6, 29, 70, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_LOW, POL_LOW, ++ }, ++ { // 13 ++ "CRT-1024x768-75", ++ 1024, 16, 96, 176, 768, 1, 3, 28, 75, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_HIGH, POL_HIGH, ++ }, ++ { // 14 ++ "CRT-1024x768-85", ++ 1024, 48, 96, 208, 768, 1, 3, 36, 85, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_HIGH, POL_HIGH, ++ }, ++ { // 15 ++ "CRT-1280x720-60", ++ 1280, 48, 112, 248, 720, 1, 3, 38, 60, ++ CLK_INTERNAL, EDGE_RISING, POL_LOW, POL_HIGH, POL_HIGH, ++ } ++}; ++ ++static void philips_lb064v02_on(unsigned char value) ++{ ++ DPRINTK("philips_lb064v02_on \n"); ++ outl(inl(GPIO_PADDR) | 2, GPIO_PADDR); ++ outl(inl(GPIO_PADR) | 2, GPIO_PADR); ++} ++ ++static void philips_lb064v02_off(unsigned char value) ++{ ++ DPRINTK("philips_lb064v02_off \n"); ++ outl(inl(GPIO_PADR) & ~2, GPIO_PADR); ++} ++ ++static irqreturn_t ep93xxfb_irq_handler(int i, void *blah) ++{ ++ outl(0x00000000, BLOCKCTRL); ++ wake_up(&ep93xxfb_wait_in); ++ return IRQ_HANDLED; ++} ++ ++static void ep93xxfb_wait(void) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ add_wait_queue(&ep93xxfb_wait_in, &wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ while (inl(BLOCKCTRL) & 0x00000001){ ++ if(/*(pls_proba==1)&&*/(!in_atomic())) ++ schedule(); ++ } ++ ++ remove_wait_queue(&ep93xxfb_wait_in, &wait); ++ set_current_state(TASK_RUNNING); ++ ++} ++ ++void ep93xxfb_fillrect(struct fb_info *p, const struct fb_fillrect *fill) ++{ ++ unsigned long blkdestwidth,tmp; ++ ++ if (!fill->width || !fill->height || ++ (fill->dx >= p->var.xres) || ++ (fill->dy >= p->var.yres) || ++ ((fill->dx + fill->width - 1) >= p->var.xres) || ++ ((fill->dy + fill->height - 1) >= p->var.yres)) ++ return; ++ ++ tmp = (( fill->dx + fill->width ) * epinfo.bpp ); ++ blkdestwidth = tmp / 32; ++ if(blkdestwidth > 0 && (tmp % 32 == 0)) ++ blkdestwidth--; ++ blkdestwidth = blkdestwidth - (fill->dx * epinfo.bpp) / 32; ++ ++ outl(fill->color, BLOCKMASK); ++ outl( ((fill->dx * epinfo.bpp) & 0x1F) | ++ ((((fill->dx + fill->width - 1) * epinfo.bpp ) & 0x1F) << 16), ++ DESTPIXELSTRT); ++ outl( ((epinfo.xres * epinfo.bpp) / 32), DESTLINELENGTH); ++ outl( blkdestwidth, BLKDESTWIDTH ); ++ outl(fill->height - 1, BLKDESTHEIGHT); ++ outl((epinfo.fb_phys + (fill->dy * epinfo.xres * epinfo.bpp ) / 8 + ++ (fill->dx * epinfo.bpp ) / 8 ) ++ , BLKDSTSTRT); ++ outl( epinfo.pixformat | 0x0000000B, BLOCKCTRL); ++ ep93xxfb_wait(); ++ ++} ++ ++void ep93xxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) ++{ ++ unsigned long startsx,stopsx,startdx,stopdx,startsy,startdy; ++ unsigned long blksrcwidth,blkdestwidth,tmp; ++ unsigned long val = 0; ++ ++ if( !area->width || !area->width || ++ (area->sx >= p->var.xres) || (area->sy >= p->var.yres) || ++ (area->dx >= p->var.xres) || (area->dy >= p->var.yres) || ++ ((area->dx + area->width - 1) >= p->var.xres) || ++ ((area->dy + area->height - 1) >= p->var.yres)) ++ return; ++ ++ if(area->sx == area->dx && area->sy == area->dy) ++ return; ++ ++ if ((area->dy == area->sy) && (area->dx > area->sx) && ++ (area->dx < (area->sx + area->width - 1))) { ++ startdx = area->dx + area->width - 1; ++ stopdx = area->dx; ++ startsx = area->sx + area->width - 1; ++ stopsx = area->sx; ++ val |= 0x000000A0; ++ } ++ else { ++ startdx = area->dx; ++ stopdx = area->dx + area->width - 1; ++ startsx = area->sx; ++ stopsx = area->sx + area->width - 1; ++ } ++ ++ if (area->dy <= area->sy) { ++ startdy = area->dy; ++ startsy = area->sy; ++ } ++ else { ++ startdy = area->dy + area->height -1; ++ startsy = area->sy + area->height -1; ++ val |= 0x00000140; ++ } ++ ++ tmp = (( area->sx + area->width ) * epinfo.bpp ); ++ blksrcwidth = tmp / 32; ++ if(blksrcwidth > 0 && (tmp % 32 == 0)) ++ blksrcwidth--; ++ blksrcwidth = blksrcwidth - (area->sx * epinfo.bpp) / 32; ++ ++ tmp = (( area->dx + area->width ) * epinfo.bpp ); ++ blkdestwidth = tmp / 32; ++ if(blkdestwidth > 0 && (tmp % 32 == 0)) ++ blkdestwidth--; ++ blkdestwidth = blkdestwidth - (area->dx * epinfo.bpp) / 32; ++ ++ outl( 0x00000000 , BLOCKCTRL); ++ ++ /*** src ***/ ++ outl((((startsx * epinfo.bpp) & 0x1F) | ++ (((stopsx * epinfo.bpp ) & 0x1F) << 16)) ++ , SRCPIXELSTRT); ++ outl((epinfo.fb_phys + (startsy * epinfo.xres * epinfo.bpp ) / 8 + ++ (startsx * epinfo.bpp ) / 8 ) ++ , BLKSRCSTRT); ++ outl(((epinfo.xres * epinfo.bpp) / 32), SRCLINELENGTH); ++ outl( blksrcwidth, BLKSRCWIDTH ); ++ ++ /*** dest ***/ ++ outl((((startdx * epinfo.bpp) & 0x1F) | ++ (((stopdx * epinfo.bpp ) & 0x1F) << 16)) ++ , DESTPIXELSTRT); ++ outl((epinfo.fb_phys + (startdy * epinfo.xres * epinfo.bpp ) / 8 + ++ (startdx * epinfo.bpp ) / 8 ) ++ , BLKDSTSTRT); ++ outl( ((epinfo.xres * epinfo.bpp) / 32), DESTLINELENGTH); ++ outl( blkdestwidth, BLKDESTWIDTH); ++ outl( area->height - 1 , BLKDESTHEIGHT); ++ outl( epinfo.pixformat | val | 0x00000003, BLOCKCTRL); ++ ep93xxfb_wait(); ++} ++ ++void ep93xxfb_imageblit(struct fb_info *p, const struct fb_image *image) ++{ ++// unsigned long blkdestwidth,tmp; ++// void * pucBlitBuf; ++ cfb_imageblit( p , image ); ++ return; ++/* ++ if ((image->dx >= p->var.xres) || ++ (image->dy >= p->var.yres) || ++ ((image->dx + image->width - 1) >= p->var.xres) || ++ ((image->dy + image->height - 1) >= p->var.yres)) ++ return; ++ if (epinfo.bpp != image->depth ) ++ return; ++ ++ tmp = (( image->dx + image->width ) * epinfo.bpp ); ++ blkdestwidth = tmp / 32; ++ if(blkdestwidth > 0 && (tmp % 32 == 0)) ++ blkdestwidth--; ++ blkdestwidth = blkdestwidth - (image->dx * epinfo.bpp) / 32; ++ ++ pucBlitBuf = kmalloc(1024*8,GFP_KERNEL); ++ copy_from_user(pucBlitBuf, image->data, 5000); ++ ++ outl( 0x00000000 , BLOCKCTRL); ++ ++ outl( 0x00000000, SRCPIXELSTRT); ++ outl( virt_to_phys(pucBlitBuf), BLKSRCSTRT); ++ outl( (image->width * epinfo.bpp) / 32 , SRCLINELENGTH); ++ outl(((image->width - 1) * epinfo.bpp) / 32, BLKSRCWIDTH ); ++ ++ outl(((image->dx * epinfo.bpp) & 0x1F) | ++ ((((image->dx + image->width - 1) * epinfo.bpp ) & 0x1F) << 16) ++ , DESTPIXELSTRT); ++ outl((epinfo.fb_phys + (image->dy * epinfo.xres * epinfo.bpp ) / 8 + ++ (image->dx * epinfo.bpp ) / 8 ) ++ , BLKDSTSTRT); ++ outl( ((epinfo.xres * epinfo.bpp) / 32), DESTLINELENGTH ); ++ outl( blkdestwidth, BLKDESTWIDTH ); ++ outl( image->height - 1 , BLKDESTHEIGHT); ++ outl(image->fg_color, BLOCKMASK); ++ outl(image->bg_color, BACKGROUND); ++ outl( epinfo.pixformat | 0x00000003, BLOCKCTRL ); ++ ep93xxfb_wait(); ++*/ ++} ++ ++ ++static unsigned long isqrt(unsigned long a) ++{ ++ unsigned long rem = 0; ++ unsigned long root = 0; ++ int i; ++ ++ for (i = 0; i < 16; i++) { ++ root <<= 1; ++ rem = ((rem << 2) + (a >> 30)); ++ a <<= 2; ++ root++; ++ if (root <= rem) { ++ rem -= root; ++ root++; ++ } ++ else ++ root--; ++ } ++ return root >> 1; ++} ++ ++int ep93xxfb_line(struct fb_info *info, struct ep93xx_line *line) ++{ ++ unsigned long value = 0; ++ long x, y, dx, dy, count, xinc, yinc, xval, yval, incr; ++ ++ if ((line->x1 > info->var.xres) || ++ (line->x2 > info->var.xres) || ++ (line->y1 > info->var.yres) || ++ (line->y2 > info->var.yres)) ++ return -EFAULT; ++ x = line->x1; ++ y = line->y1; ++ dx = line->x2 - line->x1; ++ dy = line->y2 - line->y1; ++ ++ if ( !dx || !dy ) ++ return -EFAULT; ++ ++ if ( dx < 0 && dy < 0 ) { ++ x = line->x2; ++ y = line->y2; ++ dx *= -1; ++ dy *= -1; ++ } ++ else if ( dx < 0 && dy > 0 ){ ++ dx *= -1; ++ value = 0x000000A0; ++ } ++ else if( dy < 0 && dx > 0 ){ ++ dy *= -1; ++ value = 0x00000140; ++ } ++ ++ if (line->flags & LINE_PRECISE) { ++ count = isqrt(((dy * dy) + (dx * dx)) * 4096); ++ xinc = (4095 * 64 * dx) / count; ++ yinc = (4095 * 64 * dy) / count; ++ xval = 2048; ++ yval = 2048; ++ count = 0; ++ while (dx || dy) { ++ incr = 0; ++ xval -= xinc; ++ if (xval <= 0) { ++ xval += 4096; ++ dx--; ++ incr = 1; ++ } ++ yval -= yinc; ++ if (yval <= 0) { ++ yval += 4096; ++ dy--; ++ incr = 1; ++ } ++ count += incr; ++ } ++ } ++ else { ++ if ( dx == dy ) { ++ xinc = 4095; ++ yinc = 4095; ++ count = dx; ++ ++ } ++ else if ( dx < dy ) { ++ xinc = ( dx * 4095 ) / dy; ++ yinc = 4095; ++ count = dy; ++ ++ } ++ else { ++ xinc = 4095; ++ yinc = ( dy * 4095 ) / dx; ++ count = dx; ++ } ++ } ++ ++ outl(0x08000800, LINEINIT); ++ if (line->flags & LINE_PATTERN) ++ outl(line->pattern, LINEPATTRN); ++ else ++ outl(0x000fffff, LINEPATTRN); ++ outl(epinfo.fb_phys + ((y * epinfo.xres * epinfo.bpp) / 8) + ++ ((x * epinfo.bpp ) / 8 ), BLKDSTSTRT); ++ ++ outl(((x * epinfo.bpp) & 0x1F) | ++ ((((x + dx - 1) * epinfo.bpp) & 0x1F ) << 16), ++ DESTPIXELSTRT); ++ outl((epinfo.xres * epinfo.bpp) / 32, DESTLINELENGTH); ++ outl(line->fgcolor, BLOCKMASK); ++ outl(line->bgcolor, BACKGROUND); ++ outl((yinc << 16) | xinc, LINEINC); ++ outl( count & 0xFFF, BLKDESTWIDTH); ++ outl( 0 , BLKDESTHEIGHT); ++ value |= (line->flags & LINE_BACKGROUND) ? 0x00004000 : 0; ++ outl(epinfo.pixformat | value | 0x00000013, BLOCKCTRL); ++ ep93xxfb_wait(); ++ return 0; ++} ++ ++int ioctl_cursor=0; ++ ++int ep93xxfb_cursor(struct fb_info *info, struct ep93xx_cursor *cursor) ++{ ++ unsigned long x,y,save; ++ ++ if((cursor->width ==0) || (cursor->height ==0) ) ++ { ++ struct fb_cursor *fbcon_cursor =(struct fb_cursor *)cursor; ++ struct fbcon_ops *ops = (struct fbcon_ops *)info->fbcon_par; ++ unsigned int scan_align = info->pixmap.scan_align - 1; ++ unsigned int buf_align = info->pixmap.buf_align - 1; ++ unsigned int i, size, dsize, s_pitch, d_pitch; ++ struct fb_image *image; ++ u8 *src, *dst; ++ ++ if(ioctl_cursor==1 ){ ++ DPRINTK("softcursor error return\n"); ++ return 0; ++ } ++ ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return 0; ++ ++ s_pitch = (fbcon_cursor->image.width + 7) >> 3; ++ dsize = s_pitch * fbcon_cursor->image.height; ++ ++ if (dsize + sizeof(struct fb_image) != ops->cursor_size) { ++ if (ops->cursor_src != NULL) ++ kfree(ops->cursor_src); ++ ops->cursor_size = dsize + sizeof(struct fb_image); ++ ++ ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC); ++ if (!ops->cursor_src) { ++ ops->cursor_size = 0; ++ return -ENOMEM; ++ } ++ } ++ src = ops->cursor_src + sizeof(struct fb_image); ++ image = (struct fb_image *)ops->cursor_src; ++ *image = fbcon_cursor->image; ++ d_pitch = (s_pitch + scan_align) & ~scan_align; ++ ++ size = d_pitch * image->height + buf_align; ++ size &= ~buf_align; ++ dst = fb_get_buffer_offset(info, &info->pixmap, size); ++ ++ if (fbcon_cursor->enable) { ++ switch (fbcon_cursor->rop) { ++ case ROP_XOR: ++ for (i = 0; i < dsize; i++) ++ src[i] = image->data[i] ^ fbcon_cursor->mask[i]; ++ break; ++ case ROP_COPY: ++ default: ++ for (i = 0; i < dsize; i++) ++ src[i] = image->data[i] & fbcon_cursor->mask[i]; ++ break; ++ } ++ } else ++ memcpy(src, image->data, dsize); ++ ++ fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height); ++ image->data = dst; ++ info->fbops->fb_imageblit(info, image); ++ return 0; ++ ++ } ++ else{ ++ ioctl_cursor = 1; ++ ++ /*if (cursor->width > 16 || cursor->height > 16){ ++ DPRINTK("%s width %d or heright %d error\n",__FUNCTION__,cursor->width,cursor->height); ++ return -ENXIO; ++ }*/ ++ ++ if (cursor->flags & CURSOR_OFF) ++ outl(inl(CURSORXYLOC) & ~0x00008000, CURSORXYLOC); ++ ++ if (cursor->flags & CURSOR_SETSHAPE) { ++ copy_from_user(cursor_data, cursor->data, ++ cursor->width * cursor->height / 4); ++ save = inl(CURSORXYLOC); ++ outl(save & ~0x00008000, CURSORXYLOC); ++ ++ outl(virt_to_phys(cursor_data), CURSOR_ADR_START); ++ outl(virt_to_phys(cursor_data), CURSOR_ADR_RESET); ++ outl(((cursor->width - 1) & 0x30) << 4 | ((cursor->height - 1) << 2) | ++ ((cursor->width - 1) >> 4), CURSORSIZE); ++ outl(save, CURSORXYLOC); ++ ++ } ++ ++ if (cursor->flags & CURSOR_SETCOLOR) { ++ outl(cursor->color1, CURSORCOLOR1); ++ outl(cursor->color2, CURSORCOLOR2); ++ outl(cursor->blinkcolor1, CURSORBLINK1); ++ outl(cursor->blinkcolor2, CURSORBLINK2); ++ } ++ ++ if (cursor->flags & CURSOR_BLINK) { ++ if (cursor->blinkrate) ++ outl(0x00000100 | cursor->blinkrate, CURSORBLINK); ++ else ++ outl(0x0000000FF, CURSORBLINK); ++ } ++ ++ if (cursor->flags & CURSOR_MOVE) { ++ x = (inl(HACTIVESTRTSTOP) & 0x000007ff) - cursor->dx - 2; ++ y = (inl(VACTIVESTRTSTOP) & 0x000007ff) - cursor->dy; ++ outl((inl(CURSORXYLOC) & 0x8000) | (y << 16) | x, CURSORXYLOC); ++ } ++ ++ if(cursor->flags & CURSOR_ON) ++ outl(inl(CURSORXYLOC) | 0x00008000, CURSORXYLOC); ++ ++ return 0; ++ } ++} ++ ++ ++ ++static inline void ++ep93xxfb_palette_write(u_int regno, u_int red, u_int green, ++ u_int blue, u_int trans) ++{ ++ unsigned int cont, i, pal; ++ DPRINTK("ep93xxfb_palette_write - enter\n"); ++ pal = ((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); ++ pseudo_palette[regno] = pal; ++ outl( pal, ( COLOR_LUT + ( regno << 2 ))); ++ cont = inl( LUTCONT ); ++ ++ if (( cont & LUTCONT_STAT && cont & LUTCONT_RAM1 ) || ++ ( !( cont & LUTCONT_STAT ) && !( cont&LUTCONT_RAM1 ))) { ++ for ( i = 0; i < 256; i++ ) { ++ outl( pseudo_palette[i], ( COLOR_LUT + ( i << 2 )) ); ++ } ++ outl( cont ^ LUTCONT_RAM1, LUTCONT ); ++ } ++} ++ ++int ep93xxfb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, ++ struct fb_info *info) ++{ ++ ++#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) ++ ++ switch ( info->fix.visual ) ++ { ++ case FB_VISUAL_PSEUDOCOLOR: ++ ep93xxfb_palette_write(regno, red, green, blue, transp); ++ break; ++ case FB_VISUAL_TRUECOLOR: ++ if (regno >= 16) ++ return 1; ++ 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); ++ ((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); ++ break; ++ case FB_VISUAL_DIRECTCOLOR: ++ red = CNVT_TOHW(red, 8); ++ green = CNVT_TOHW(green, 8); ++ blue = CNVT_TOHW(blue, 8); ++ transp = CNVT_TOHW(transp, 8); ++ break; ++ } ++#undef CNVT_TOHW ++ return 0; ++} ++ ++static int ep93xx_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ DPRINTK("ep93xx_pan_display - enter\n"); ++ ++ if (var->yoffset < 0 ++ || var->yoffset + var->yres > info->var.yres_virtual ++ || var->xoffset) ++ return -EINVAL; ++ ++ outl(epinfo.fb_phys + info->fix.line_length * var->yoffset ++ , VIDSCRNPAGE); ++ ++ info->var.xoffset = var->xoffset; ++ info->var.yoffset = var->yoffset; ++ ++ DPRINTK("ep93xx_pan_display - exit\n"); ++ return 0; ++} ++ ++ ++static int ++ep93xxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct fb_var_screeninfo tmp_var; ++ unsigned long pclk; ++ DPRINTK("ep93xxfb_check_var - enter\n"); ++ ++ if( vout != 0) { ++ printk(" ep93xxfb_check_var - vout != 0\n"); ++ return -EINVAL; ++ } ++ ++ memcpy (&tmp_var, var, sizeof (tmp_var)); ++ ++ if( (tmp_var.vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED ) { ++ printk(" ep93xxfb_check_var - unsupported video mode\n"); ++ return -EINVAL; ++ } ++ ++ if( ((tmp_var.xres * tmp_var.yres * tmp_var.bits_per_pixel) / 8) > ++ MAX_FBMEM_SIZE ) { ++ printk(" ep93xxfb_check_var - memory error \n"); ++ return -ENOMEM; ++ } ++ ++ if( ((tmp_var.xres_virtual * tmp_var.yres_virtual * tmp_var.bits_per_pixel) / 8) > ++ MAX_FBMEM_SIZE ) { ++ printk(" ep93xxfb_check_var - memory error \n"); ++ return -ENOMEM; ++ } ++ ++ pclk = 1000 * (1000000000 / tmp_var.pixclock); ++ ++ if( pclk > ep93xx_get_max_video_clk() ) { ++ printk(" ep93xxfb_check_var - pixel clock error %lu\n",pclk); ++ return -EINVAL; ++ } ++ ++ if (var->xres_virtual != var->xres) ++ var->xres_virtual = var->xres; ++ if (var->yres_virtual < var->yres) ++ var->yres_virtual = var->yres; ++ ++ if (var->xoffset < 0) ++ var->xoffset = 0; ++ if (var->yoffset < 0) ++ var->yoffset = 0; ++ ++ switch (tmp_var.bits_per_pixel) { ++ case 8: ++ break; ++ case 16: ++ break; ++ case 24: ++ break; ++ case 32: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ DPRINTK("ep93xxfb_check_var - exit\n"); ++ return 0; ++} ++ ++ ++static int ep93xxfb_set_par(struct fb_info *info) ++{ ++ struct fb_var_screeninfo tmp_var; ++ unsigned long attribs; ++ ++ DPRINTK("ep93xxfb_set_par - enter\n"); ++ ++ if( ep93xxfb_check_var(&info->var,info) < 0 ) ++ return -EINVAL; ++ ++ if( !ep93xxfb_setcol(info,info->var.bits_per_pixel) ) ++ return -EINVAL; ++ ++ ++ info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8; ++ ++ ep93xxfb_blank( 1 , info ); ++ ++ memcpy(&tmp_var,&info->var,sizeof(tmp_var)); ++ ++ epinfo.xres = tmp_var.xres; ++ epinfo.xsync = tmp_var.hsync_len; ++ epinfo.xfp = tmp_var.right_margin; ++ epinfo.xbp = tmp_var.left_margin; ++ epinfo.xtotal = epinfo.xres + epinfo.xsync + ++ epinfo.xfp + epinfo.xbp; ++ ++ epinfo.yres = tmp_var.yres; ++ epinfo.ysync = tmp_var.vsync_len; ++ epinfo.yfp = tmp_var.lower_margin; ++ epinfo.ybp = tmp_var.upper_margin; ++ epinfo.ytotal = epinfo.yres + epinfo.ysync + ++ epinfo.yfp + epinfo.ybp; ++ ++ epinfo.pixclock = tmp_var.pixclock ; ++ epinfo.refresh = 1000 * (1000000000 / tmp_var.pixclock) ; ++ ++ if( epinfo.refresh > ep93xx_get_max_video_clk()) ++ epinfo.refresh = ep93xx_get_max_video_clk(); ++ epinfo.bpp = tmp_var.bits_per_pixel; ++ ++ ep93xxfb_setclk(); ++ ep93xxfb_timing_signal_generation(); ++ ++ // set video memory parameters ++ outl(epinfo.fb_phys, VIDSCRNPAGE); ++ outl(epinfo.yres , SCRNLINES); ++ outl(((epinfo.xres * epinfo.bpp) / 32) - 1, LINELENGTH); ++ outl((epinfo.xres * epinfo.bpp) / 32, VLINESTEP); ++ ++ // set pixel mode ++ ep93xxfb_pixelmod(epinfo.bpp); ++ ++ attribs = 0; ++#ifdef CONFIG_EP93XX_SDCS0 ++ attribs |= 0 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS1 ++ attribs |= 1 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS2 ++ attribs |= 2 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS3 ++ attribs |= 3 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++ ++ attribs |= VIDEOATTRIBS_INVCLK; ++ if( tmp_var.sync & FB_SYNC_HOR_HIGH_ACT ) ++ attribs |= VIDEOATTRIBS_HSPOL; ++ if( tmp_var.sync & FB_SYNC_VERT_HIGH_ACT ) ++ attribs |= VIDEOATTRIBS_VCPOL; ++ ++ ep93xxfb_outl(attribs, VIDEOATTRIBS); ++ ep93xxfb_blank( 0 , info ); ++ ++ DPRINTK("ep93xxfb_set_par - exit\n"); ++ ++ return 0; ++} ++ ++ ++static int ep93xxfb_blank(int blank_mode,struct fb_info *info) ++{ ++ unsigned long attribs; ++ DPRINTK("ep93xxfb_blank - enter\n"); ++ attribs = inl(VIDEOATTRIBS); ++ ++#ifdef CONFIG_EP93XX_SDCS0 ++ attribs |= 0 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS1 ++ attribs |= 1 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS2 ++ attribs |= 2 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS3 ++ attribs |= 3 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++ ++ if (blank_mode) { ++ if (epinfo.off) ++ (epinfo.off)( 0 ); ++ ++ ep93xxfb_outl(attribs & ~(VIDEOATTRIBS_DATAEN | ++ VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_PCLKEN | ++ VIDEOATTRIBS_EN), VIDEOATTRIBS); ++ } ++ else { ++ if (epinfo.clk_src == CLK_INTERNAL) ++ attribs |= VIDEOATTRIBS_PCLKEN; ++ else ++ attribs &= ~VIDEOATTRIBS_PCLKEN; ++ ++ ep93xxfb_outl(attribs | VIDEOATTRIBS_DATAEN | ++ VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_EN, ++ VIDEOATTRIBS); ++ ++ if (epinfo.configure) ++ (epinfo.configure)( epinfo.automods ); ++ if (epinfo.on) ++ (epinfo.on)( 0 ); ++ } ++ return 0; ++} ++ ++static int ep93xxfb_mmap(struct fb_info *info,struct vm_area_struct *vma) ++{ ++ unsigned long off, start, len; ++ ++ DPRINTK("ep93xxfb_mmap - enter\n"); ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ start = info->fix.smem_start; ++ len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; ++ start &= PAGE_MASK; ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ ++ off += start; ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ ++ vma->vm_flags |= VM_IO; ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) { ++ DPRINTK("ep93xxfb_mmap error\n"); ++ return -EAGAIN; ++ } ++ ++ DPRINTK("ep93xxfb_mmap - exit\n"); ++ return 0; ++} ++ ++static unsigned long ep93xx_get_pll_frequency(unsigned long pll) ++{ ++ unsigned long fb1, fb2, ipd, ps, freq; ++ ++ if (pll == 1) ++ pll = inl(EP93XX_SYSCON_CLOCK_SET1); ++ else if (pll == 2) ++ pll = inl(EP93XX_SYSCON_CLOCK_SET2); ++ else ++ return 0; ++ ++ ps = (pll & SYSCON_CLKSET1_PLL1_PS_MASK) >> SYSCON_CLKSET1_PLL1_PS_SHIFT; ++ fb1 = ((pll & SYSCON_CLKSET1_PLL1_X1FBD1_MASK) >> SYSCON_CLKSET1_PLL1_X1FBD1_SHIFT); ++ fb2 = ((pll & SYSCON_CLKSET1_PLL1_X2FBD2_MASK) >> SYSCON_CLKSET1_PLL1_X2FBD2_SHIFT); ++ ipd = ((pll & SYSCON_CLKSET1_PLL1_X2IPD_MASK) >> SYSCON_CLKSET1_PLL1_X2IPD_SHIFT); ++ ++ freq = (((0x00e10000 * (fb1+1)) / (ipd+1)) * (fb2+1)) >> ps; ++ return freq; ++} ++ ++static int ep93xx_get_max_video_clk() ++{ ++ unsigned long f,freq = 0; ++ ++ freq = 14745600 / 4; ++ f = ep93xx_get_pll_frequency(1) / 4; ++ if ( f > freq ) ++ freq = f; ++ f = ep93xx_get_pll_frequency(2) / 4; ++ if ( f > freq ) ++ freq = f; ++ ++ return freq; ++} ++ ++static int ep93xx_set_video_div(unsigned long freq) ++{ ++ unsigned long pdiv = 0, div = 0, psel = 0, esel = 0; ++ unsigned long err, f, i, j, k; ++ ++ err = -1; ++ ++ for (i = 0; i < 3; i++) { ++ if (i == 0) ++ f = 14745600 * 2; ++ else if (i == 1) ++ f = ep93xx_get_pll_frequency(1) * 2; ++ else ++ f = ep93xx_get_pll_frequency(2) * 2; ++ ++ for (j = 4; j <= 6; j++) { ++ k = f / (freq * j); ++ if (k < 2) ++ continue; ++ ++ if (abs(((f / (j * k))) - freq ) < err ) { ++ pdiv = j - 3; ++ div = k; ++ psel = (i == 2) ? 1 : 0; ++ esel = (i == 0) ? 0 : 1; ++ err = (f / (j * k)) - freq; ++ } ++ } ++ } ++ ++ if (err == -1) ++ return -1; ++ ++ SysconSetLocked(SYSCON_VIDDIV,SYSCON_VIDDIV_VENA | (esel ? SYSCON_VIDDIV_ESEL : 0) | ++ (psel ? SYSCON_VIDDIV_PSEL : 0) | ++ (pdiv << SYSCON_VIDDIV_PDIV_SHIFT) | ++ (div << SYSCON_VIDDIV_VDIV_SHIFT) ++ ); ++ ++ return freq + err; ++} ++ ++static void ep93xxfb_pixelmod(int bpp) ++{ ++ unsigned long tmpdata = 0; ++ ++ DPRINTK("ep93xxfb_pixelmod %dbpp -enter\n",bpp); ++ switch(bpp) { ++ case 8: ++ tmpdata = PIXELMODE_P_8BPP | ++ PIXELMODE_S_1PPCMAPPED | ++ PIXELMODE_C_LUT; ++ epinfo.pixformat = PIXEL_FORMAT_8; ++ break; ++ case 16: ++ tmpdata = PIXELMODE_P_16BPP | ++ PIXELMODE_S_1PPCMAPPED | ++ PIXELMODE_C_565; ++ epinfo.pixformat = PIXEL_FORMAT_16; ++ break; ++ case 24: ++ tmpdata = PIXELMODE_P_24BPP | ++ PIXELMODE_S_1PPC | ++ PIXELMODE_C_888; ++ epinfo.pixformat = PIXEL_FORMAT_24; ++ break; ++ case 32: ++ tmpdata = PIXELMODE_P_32BPP | ++ PIXELMODE_S_1PPC | ++ PIXELMODE_C_888; ++ epinfo.pixformat = PIXEL_FORMAT_32; ++ break; ++ default: ++ break; ++ } ++ outl(tmpdata,PIXELMODE); ++} ++ ++static void ep93xxfb_timing_signal_generation(void) ++{ ++ unsigned long vlinestotal,vsyncstart,vsyncstop, ++ vactivestart,vactivestop, ++ vblankstart,vblankstop, ++ vclkstart,vclkstop; ++ ++ unsigned long hclkstotal,hsyncstart,hsyncstop, ++ hactivestart,hactivestop, ++ hblankstart,hblankstop, ++ hclkstart,hclkstop; ++ ++ DPRINTK("ep93xxfb_timing_signal_generation - enter\n"); ++ ++ vlinestotal = epinfo.ytotal - 1; ++ vsyncstart = vlinestotal; ++ vsyncstop = vlinestotal - epinfo.ysync; ++ vblankstart = vlinestotal - epinfo.ysync - epinfo.ybp; ++ vblankstop = epinfo.yfp - 1; ++ vactivestart = vblankstart; ++ vactivestop = vblankstop; ++ vclkstart = vlinestotal; ++ vclkstop = vlinestotal + 1; ++ ++ hclkstotal = epinfo.xtotal - 1; ++ hsyncstart = hclkstotal; ++ hsyncstop = hclkstotal - epinfo.xsync; ++ hblankstart = hclkstotal - epinfo.xsync - epinfo.xbp; ++ hblankstop = epinfo.xfp - 1; ++ hactivestart = hblankstart; ++ hactivestop = hblankstop; ++ hclkstart = hclkstotal ; ++ hclkstop = hclkstotal ; ++ ++ ep93xxfb_outl(0, VIDEOATTRIBS); ++ ++ ep93xxfb_outl( vlinestotal , VLINESTOTAL ); ++ ep93xxfb_outl( vsyncstart + (vsyncstop << 16), VSYNCSTRTSTOP ); ++ ep93xxfb_outl( vactivestart + (vactivestop << 16), VACTIVESTRTSTOP ); ++ ep93xxfb_outl( vblankstart + (vblankstop << 16), VBLANKSTRTSTOP ); ++ ep93xxfb_outl( vclkstart + (vclkstop << 16), VCLKSTRTSTOP ); ++ ++ ep93xxfb_outl( hclkstotal , HCLKSTOTAL ); ++ ep93xxfb_outl( hsyncstart + (hsyncstop << 16), HSYNCSTRTSTOP ); ++ ep93xxfb_outl( hactivestart + (hactivestop << 16) , HACTIVESTRTSTOP ); ++ ep93xxfb_outl( hblankstart + (hblankstop << 16) , HBLANKSTRTSTOP ); ++ ep93xxfb_outl( hclkstart + (hclkstop << 16) , HCLKSTRTSTOP ); ++ ++ ep93xxfb_outl(0, LINECARRY); ++ ++} ++ ++static int ep93xxfb_setcol(struct fb_info *info, int bpp) ++{ ++ ++ DPRINTK("ep93xxfb_setcol %dbpp\n",bpp); ++ switch(bpp) { ++ case 8: ++ info->var.bits_per_pixel = 8; ++ info->var.red.length = 8; ++ info->var.green.length = 8; ++ info->var.blue.length = 8; ++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ break; ++ case 16: ++ info->var.bits_per_pixel = 16; ++ info->var.red.offset = 11; ++ info->var.red.length = 5; ++ info->var.green.offset = 5; ++ info->var.green.length = 6; ++ info->var.blue.offset = 0; ++ info->var.blue.length = 5; ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ break; ++ case 24: ++ info->var.bits_per_pixel = 24; ++ info->var.red.length = 8; ++ info->var.blue.length = 8; ++ info->var.green.length = 8; ++ info->var.red.offset = 16; ++ info->var.green.offset = 8; ++ info->var.blue.offset = 0; ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ break; ++ case 32: ++ info->var.bits_per_pixel = 32; ++ info->var.red.length = 8; ++ info->var.blue.length = 8; ++ info->var.green.length = 8; ++ info->var.transp.length = 0; ++ info->var.red.offset = 16; ++ info->var.green.offset = 8; ++ info->var.blue.offset = 0; ++ info->var.transp.offset = 0; ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ break; ++ default: ++ return 0; ++ } ++ return 1; ++} ++ ++static int ep93xxfb_setclk() ++{ ++ unsigned long calc_clk,act_clk; ++ ++ if ( epinfo.clk_src == CLK_INTERNAL ) { ++ SysconSetLocked(EP93XX_SYSCON_DEVICE_CONFIG,inl(EP93XX_SYSCON_DEVICE_CONFIG) & ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE); ++ calc_clk = epinfo.refresh; ++ act_clk = ep93xx_set_video_div( calc_clk ); ++ if ( act_clk == -1 ) ++ return -ENODEV; ++ ++ epinfo.refresh = act_clk; ++ epinfo.pixclock = 1000000000 / (act_clk / 1000); ++ } ++ else { ++ SysconSetLocked(SYSCON_VIDDIV,0); ++ SysconSetLocked(EP93XX_SYSCON_DEVICE_CONFIG,inl(EP93XX_SYSCON_DEVICE_CONFIG) | EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE); ++ ++ } ++ ++ return 0; ++} ++ ++ ++static void ep93xxfb_get_par(struct fb_info *info) ++{ ++ ++ DPRINTK("ep93xxfb_get_par - enter\n"); ++ epinfo.configure = NULL; ++ epinfo.on = NULL; ++ epinfo.off = NULL; ++ ++ switch( vout ) { ++ case LCD_OUT: ++ epinfo.on = philips_lb064v02_on; ++ epinfo.off = philips_lb064v02_off; ++ ++ case CRT_OUT: ++ epinfo.xres = ep93xxfb_vmods[vmode].hres; ++ epinfo.xsync = ep93xxfb_vmods[vmode].hsync; ++ epinfo.xfp = ep93xxfb_vmods[vmode].hfp; ++ epinfo.xbp = ep93xxfb_vmods[vmode].hbp; ++ epinfo.xtotal = epinfo.xres + epinfo.xsync + ++ epinfo.xfp + epinfo.xbp; ++ ++ epinfo.yres = ep93xxfb_vmods[vmode].vres; ++ epinfo.ysync = ep93xxfb_vmods[vmode].vsync; ++ epinfo.yfp = ep93xxfb_vmods[vmode].vfp; ++ epinfo.ybp = ep93xxfb_vmods[vmode].vbp; ++ epinfo.ytotal = epinfo.yres + epinfo.ysync + ++ epinfo.yfp + epinfo.ybp; ++ ++ epinfo.refresh = ep93xxfb_vmods[vmode].refresh; ++ epinfo.refresh = epinfo.xtotal * epinfo.ytotal * epinfo.refresh; ++ epinfo.pixclock = 1000000000 / ( epinfo.refresh / 1000); ++ epinfo.bpp = depth; ++ ++ epinfo.clk_src = ep93xxfb_vmods[vmode].clk_src; ++ epinfo.clk_edge = ep93xxfb_vmods[vmode].clk_edge; ++ epinfo.pol_blank = ep93xxfb_vmods[vmode].pol_blank; ++ epinfo.pol_xsync = ep93xxfb_vmods[vmode].pol_hsync; ++ epinfo.pol_ysync = ep93xxfb_vmods[vmode].pol_vsync; ++ break; ++ ++ } ++} ++ ++static int ep93xxfb_alloc_videomem(void) ++{ ++ unsigned long adr,size,pgsize; ++ int order; ++ ++ DPRINTK("ep93xxfb_alloc_videomem - enter \n"); ++ ++ epinfo.fb_log = NULL; ++ epinfo.fb_size = PAGE_ALIGN( MAX_FBMEM_SIZE/*ep93xxfb_vmods[vmode].hres * ep93xxfb_vmods[vmode].vres * (depth / 8)*/ ); ++ order = get_order( epinfo.fb_size ); ++ epinfo.fb_log = (void*) __get_free_pages( GFP_KERNEL, order ); ++ ++ if (epinfo.fb_log) { ++ epinfo.fb_phys = __virt_to_phys((int) epinfo.fb_log ); ++ adr = (unsigned long)epinfo.fb_log; ++ size = epinfo.fb_size; ++ pgsize = 1 << order; ++ do { ++ adr += pgsize; ++ SetPageReserved(virt_to_page(adr)); ++ } while(size -= pgsize); ++ } ++ else{ ++ printk("%s memory fail \n",__FUNCTION__); ++ return -ENOMEM; ++ } ++ ++ memset(epinfo.fb_log,0x00,epinfo.fb_size); ++ DPRINTK(" fb_log_addres = 0x%x\n",epinfo.fb_log); ++ DPRINTK(" fb_phys_address = 0x%x\n",epinfo.fb_phys); ++ DPRINTK(" fb_size = %lu\n",epinfo.fb_size); ++ DPRINTK(" fb_page_order = %d\n",order); ++ DPRINTK("ep93xxfb_alloc_videomem - exit \n"); ++ return 0; ++} ++ ++static void ep93xxfb_release_videomem(void) ++{ ++ unsigned long adr,size,psize; ++ int order; ++ ++ DPRINTK("ep93xxfb_release_videomem - enter \n"); ++ ++ if (epinfo.fb_log) { ++ order = get_order(epinfo.fb_size); ++ adr = (unsigned long)epinfo.fb_log; ++ size = epinfo.fb_size; ++ psize = 1 << order ; ++ do { ++ adr += psize; ++ ClearPageReserved(virt_to_page(adr)); ++ } while(size -= psize); ++ free_pages((unsigned long)epinfo.fb_log, order ); ++ } ++ ++ ++ DPRINTK("ep93xxfb_release_videomem - exit \n"); ++} ++ ++static void ep93xxfb_setinfo(struct fb_info *info) ++{ ++ ++ info->pseudo_palette = pseudo_palette; ++ info->var.xres = epinfo.xres; ++ info->var.yres = epinfo.yres; ++ info->var.xres_virtual = epinfo.xres; ++ info->var.yres_virtual = epinfo.yres; ++ ++ ep93xxfb_setcol( info, depth ); ++ ++ info->var.activate = FB_ACTIVATE_NOW; ++ info->var.left_margin = epinfo.xbp; ++ info->var.right_margin = epinfo.xfp; ++ info->var.upper_margin = epinfo.ybp; ++ info->var.lower_margin = epinfo.yfp; ++ info->var.hsync_len = epinfo.xsync; ++ info->var.vsync_len = epinfo.ysync; ++ ++ if( epinfo.pol_xsync == POL_HIGH ) ++ info->var.sync |= FB_SYNC_HOR_HIGH_ACT; ++ if( epinfo.pol_ysync == POL_HIGH ) ++ info->var.sync |= FB_SYNC_VERT_HIGH_ACT; ++ ++ info->var.vmode = FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP; ++ info->fix.smem_start = epinfo.fb_phys; ++ info->fix.smem_len = epinfo.fb_size; ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++ info->fix.line_length = epinfo.xres * (epinfo.bpp / 8); ++ info->screen_base = epinfo.fb_log; ++ info->var.pixclock = epinfo.pixclock; ++ info->fix.ypanstep = 1; ++ info->fix.ywrapstep = 1; ++ ++} ++ ++static int ep93xxfb_config(struct fb_info *info) ++{ ++ unsigned long attribs; ++ ++ DPRINTK("ep93xxfb_config - enter\n"); ++ ++ ep93xxfb_get_par( info ); ++ if( ep93xxfb_alloc_videomem() != 0 ) { ++ printk("Unable to allocate video memory\n"); ++ return -ENOMEM; ++ } ++ ++ if( ep93xxfb_setclk() != 0 ) { ++ printk("Unable to set pixel clock\n"); ++ ep93xxfb_release_videomem(); ++ return -ENODEV; ++ } ++ ++ SysconSetLocked(EP93XX_SYSCON_DEVICE_CONFIG, inl(EP93XX_SYSCON_DEVICE_CONFIG) |EP93XX_SYSCON_DEVCFG_RasOnP3); ++ ep93xxfb_timing_signal_generation(); ++ ++ /* set video memory parameters */ ++ outl(epinfo.fb_phys, VIDSCRNPAGE); ++ outl(epinfo.yres , SCRNLINES); ++ outl(((epinfo.xres * epinfo.bpp) / 32) - 1, LINELENGTH); ++ outl((epinfo.xres * epinfo.bpp) / 32, VLINESTEP); ++ ++ ++ /* set pixel mode */ ++ ep93xxfb_pixelmod(depth); ++ ++ attribs = 0; ++ ++#ifdef CONFIG_EP93XX_SDCS0 ++ attribs |= 0 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS1 ++ attribs |= 1 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS2 ++ attribs |= 2 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS3 ++ attribs |= 3 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++ ++ if(epinfo.clk_edge == EDGE_RISING) ++ attribs |= VIDEOATTRIBS_INVCLK; ++ if(epinfo.pol_blank == POL_HIGH) ++ attribs |= VIDEOATTRIBS_BLKPOL; ++ if(epinfo.pol_xsync == POL_HIGH) ++ attribs |= VIDEOATTRIBS_HSPOL; ++ if(epinfo.pol_ysync == POL_HIGH) ++ attribs |= VIDEOATTRIBS_VCPOL; ++ ++ ep93xxfb_outl(attribs, VIDEOATTRIBS); ++ ep93xxfb_setinfo( info ); ++ ++ if(epinfo.configure) ++ (epinfo.configure)( epinfo.automods ); ++ ++ ep93xxfb_blank( 0 , info ); ++ ++ DPRINTK("ep93xxfb_config - exit\n"); ++ return 0; ++} ++ ++int ep93xxfb_ioctl(struct fb_info *info,unsigned int cmd, unsigned long arg) ++{ ++ struct fb_fillrect fill; ++ struct fb_copyarea cparea; ++ struct fb_image img; ++ struct ep93xx_line line; ++ struct ep93xx_cursor cursor; ++ ++ switch (cmd) { ++ case FBIO_EP93XX_CURSOR: ++ copy_from_user(&cursor, (void *)arg, sizeof(struct ep93xx_cursor)); ++ ep93xxfb_cursor(info,&cursor); ++ break; ++ case FBIO_EP93XX_LINE: ++ copy_from_user(&line, (void *)arg, sizeof(struct ep93xx_line)); ++ ep93xxfb_line(info,&line); ++ break; ++ case FBIO_EP93XX_FILL: ++ copy_from_user(&fill, (void *)arg, sizeof(struct fb_fillrect)); ++ ep93xxfb_fillrect(info,&fill); ++ break; ++ case FBIO_EP93XX_BLIT: ++ copy_from_user(&img, (void *)arg, sizeof(struct fb_image)); ++ ep93xxfb_imageblit(info, &img); ++ break; ++ case FBIO_EP93XX_COPY: ++ copy_from_user(&cparea, (void *)arg, sizeof(struct fb_copyarea)); ++ ep93xxfb_copyarea(info,&cparea); ++ break; ++ default: ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++ ++static struct fb_ops ep93xxfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_setcolreg = ep93xxfb_setcolreg, ++ .fb_check_var = ep93xxfb_check_var, ++ .fb_set_par = ep93xxfb_set_par, ++ .fb_blank = ep93xxfb_blank, ++ .fb_pan_display = ep93xx_pan_display, ++ .fb_fillrect = ep93xxfb_fillrect, ++ .fb_copyarea = ep93xxfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_cursor = ep93xxfb_cursor, ++ .fb_ioctl = ep93xxfb_ioctl, ++ .fb_mmap = ep93xxfb_mmap, ++}; ++ ++ ++static struct resource ep93xxfb_raster_resources = { ++ .start = EP93XX_RASTER_PHYS_BASE, ++ .end = EP93XX_RASTER_PHYS_BASE + 0x1ffff, ++ .flags = IORESOURCE_MEM, ++}; ++ ++ ++static int __init ep93xxfb_probe(struct platform_device *device) ++{ ++ struct fb_info *info = NULL; ++ struct resource *res = NULL; ++ int ret = 0; ++ int arb = 0; ++ ++ DPRINTK("ep93xxfb_probe - enter \n"); ++ ++ ++ if(!device) { ++ printk("error : to_platform_device\n"); ++ return -ENODEV; ++ } ++ res = platform_get_resource( device, IORESOURCE_MEM, 0); ++ if(!res) { ++ printk("error : platform_get_resource \n"); ++ return -ENODEV; ++ } ++ cursor_data = kmalloc( 64 * 64 * 2, GFP_KERNEL ); ++ memset( cursor_data, 0x00, 64 * 64 * 2 ); ++ if(!cursor_data) { ++ printk("Unable to allocate memory for hw_cursor\n"); ++ return -ENOMEM; ++ } ++ if (!request_mem_region(res->start,res->end - res->start + 1, FBDEV_NAME )) ++ return -EBUSY; ++ ++ info = framebuffer_alloc(sizeof(u32) * 256, &device->dev); ++ ++ if(!info) { ++ printk("Unable to allocate memory for frame buffer\n"); ++ return -ENOMEM; ++ } ++ ++ info->flags = FBINFO_DEFAULT; ++ strncpy(info->fix.id, FBDEV_NAME, sizeof(info->fix.id)); ++ info->fix.mmio_start = res->start; ++ info->fix.mmio_len = res->end - res->start + 1; ++ info->fbops = &ep93xxfb_ops; ++ info->pseudo_palette = info->par; ++ info->state = FBINFO_STATE_RUNNING; ++ ++ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { ++ ret = -ENOMEM; ++ goto fbuff; ++ } ++ ++ if ((ret = ep93xxfb_config(info)) < 0) ++ goto clmap; ++ ++ if (register_framebuffer(info) < 0) { ++ printk(KERN_ERR "Unable to register ep93xxfb frame buffer\n"); ++ ret = -EINVAL; ++ goto clmap; ++ } ++ platform_set_drvdata(device, info); ++ printk(KERN_INFO "fb%d: EP93xx frame buffer at %dx%dx%dbpp\n", info->node, ++ info->var.xres, info->var.yres, info->var.bits_per_pixel); ++ ++ /*change the raster arb to the highest one--Bo*/ ++ arb = inl(EP93XX_SYSCON_BMAR); ++ arb = (arb & 0x3f8) | 0x01; ++ outl(arb,EP93XX_SYSCON_BMAR); ++ ++ DPRINTK("ep93xxfb_probe - exit \n"); ++ return 0; ++ ++clmap: ++ fb_dealloc_cmap(&info->cmap); ++ ++fbuff: ++ framebuffer_release(info); ++ return ret; ++} ++ ++static int ep93xxfb_remove(struct platform_device *device) ++{ ++ struct resource *res; ++ struct fb_info *info; ++ struct ep93xx_cursor cursor; ++ ++ DPRINTK("ep93xxfb_remove - enter \n"); ++ ++ info = platform_get_drvdata(device); ++ ++ ep93xxfb_release_videomem(); ++ ++ res = platform_get_resource( device, IORESOURCE_MEM, 0); ++ release_mem_region(res->start, res->end - res->start + 1); ++ ++ platform_set_drvdata(device, NULL); ++ unregister_framebuffer(info); ++ ++ fb_dealloc_cmap(&info->cmap); ++ framebuffer_release(info); ++ ++ cursor.flags = CURSOR_OFF; ++ ep93xxfb_cursor(info,&cursor); ++ if(cursor_data!=NULL) ++ kfree(cursor_data); ++ ++ ep93xxfb_blank( 1, info ); ++ ++ DPRINTK("ep93xxfb_remove - exit \n"); ++ return 0; ++} ++ ++static void ep93xxfb_platform_release(struct device *device) ++{ ++ DPRINTK("ep93xxfb_platform_release - enter\n"); ++} ++ ++static int ep93xxfb_check_param(void) ++{ ++ ++ switch(vout) { ++ case CRT_OUT: ++ if( vmode >=(sizeof(ep93xxfb_vmods)/sizeof(ep93xxfb_vmods[0]))){ ++ vmode = 1; ++ depth = DEFAULT_BPP; ++ return 0; ++ } ++ break; ++ case LCD_OUT: ++ if( vmode != 0 || depth != 16 ) { ++ vmode = 0; ++ depth = DEFAULT_BPP; ++ return 0; ++ } ++ break; ++ default: ++ vmode = DEFAULT_MODE; ++ depth = DEFAULT_BPP; ++ vout = DEFAULT_OUT; ++ return 0; ++ break; ++ } ++ ++ if(!((depth == 8) || (depth == 16) || (depth == 24) || (depth == 32))) ++ depth = DEFAULT_BPP; ++ ++ return 1; ++} ++ ++int __init ep93xxfb_setup(char *options) ++{ ++ char *opt; ++ ++ DPRINTK("ep93xxfb_setup - %s\n",options); ++ ++ if (!options || !*options) ++ return 0; ++ ++ while ((opt = strsep(&options, ",")) != NULL) { ++ if (!strncmp(opt, "vout=", 5)) ++ vout = simple_strtoul(opt + 5, NULL, 0); ++ else if (!strncmp(opt, "vmode=", 6)) ++ vmode = simple_strtoul(opt + 6, NULL, 0); ++ else if (!strncmp(opt, "depth=", 6)) ++ depth = simple_strtoul(opt + 6, NULL, 0); ++ } ++ ep93xxfb_check_param(); ++ return 0; ++} ++ ++ ++static struct platform_driver ep93xxfb_driver = { ++ .probe = ep93xxfb_probe, ++ .remove = ep93xxfb_remove, ++ .driver = { ++ .name = FBDEV_NAME, ++ }, ++}; ++ ++static struct platform_device ep93xxfb_device = { ++ .name = FBDEV_NAME, ++ .id = -1, ++ .dev = { ++ .release = ep93xxfb_platform_release, ++ }, ++ .num_resources = 1, ++ .resource = &ep93xxfb_raster_resources, ++}; ++ ++int __init ep93xxfb_init(void) ++{ ++ int ret = 0; ++ char *option = NULL; ++ ++ DPRINTK("ep93xxfb_init - enter\n"); ++ ++ if (fb_get_options("ep93xxfb", &option)) ++ return -ENODEV; ++ ep93xxfb_setup(option); ++ ++ ++ if( !ep93xxfb_check_param() ) { ++ printk("Unsupported format \n"); ++ return -1; ++ } ++ /*Add the Hardware accel irq */ ++ outl(0x00000000, BLOCKCTRL); ++ ret = request_irq(IRQ_EP93XX_GRAPHICS, ep93xxfb_irq_handler, IRQF_DISABLED,"graphics",NULL); ++ ++ if (ret != 0) { ++ printk("%s: can't get irq %i, err %d\n",__FUNCTION__, IRQ_EP93XX_GRAPHICS, ret); ++ return -EBUSY; ++ } ++ ++ /*-------------------------------*/ ++ ret = platform_driver_register(&ep93xxfb_driver); ++ ++ if (!ret) { ++ ret = platform_device_register(&ep93xxfb_device); ++ if (ret) ++ platform_driver_unregister(&ep93xxfb_driver); ++ } ++ ++ DPRINTK("ep93xxfb_init - exit\n"); ++ return ret; ++} ++ ++ ++ ++static void __exit ep93xxfb_exit(void) ++{ ++ DPRINTK("ep93xxfb_exit - enter\n"); ++ platform_driver_unregister(&ep93xxfb_driver); ++ platform_device_unregister(&ep93xxfb_device); ++ DPRINTK("ep93xxfb_exit - exit\n"); ++} ++ ++module_init(ep93xxfb_init); ++module_exit(ep93xxfb_exit); ++ ++ ++module_param( vmode, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); ++MODULE_PARM_DESC(vmode, "Specify the video mode number that should be used"); ++module_param( vout , int , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ); ++MODULE_PARM_DESC(vout ,"Specify video output (0 = CRT ,1 = LCD )"); ++module_param( depth , int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); ++MODULE_PARM_DESC(depth ,"Color depth (8,16,24,32)"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/video/ep93xxfb.h +@@ -0,0 +1,236 @@ ++#ifndef __EP93XXFB_H__ ++#define __EP93XXFB_H__ ++ ++ ++#define POL_HIGH 1 ++#define POL_LOW 0 ++#define EDGE_RISING 1 ++#define EDGE_FALLING 0 ++#define CLK_INTERNAL 1 ++#define CLK_EXTERNAL 0 ++ ++#define CRT_OUT 0 ++#define LCD_OUT 1 ++#define TV_OUT 2 ++ ++#define MAX_XRES 1280 ++#define MAX_YRES 1024 ++#define MAX_BPP 16 ++#define MAX_FBMEM_SIZE 3686400/*1920000*/ ++ ++#define MAX_XRES_CRT MAX_XRES ++#define MAX_YRES_CRT MAX_YRES ++#define MAX_XRES_SVIDEO 1024 ++#define MAX_YRES_SVIDEO 768 ++ ++#define PIXEL_FORMAT_SHIFT 17 ++#define PIXEL_FORMAT_4 ( 1 << PIXEL_FORMAT_SHIFT ) ++#define PIXEL_FORMAT_8 ( 2 << PIXEL_FORMAT_SHIFT ) ++#define PIXEL_FORMAT_16 ( 4 << PIXEL_FORMAT_SHIFT ) ++#define PIXEL_FORMAT_24 ( 6 << PIXEL_FORMAT_SHIFT ) ++#define PIXEL_FORMAT_32 ( 7 << PIXEL_FORMAT_SHIFT ) ++ ++ ++struct ep93xxfb_videomodes ++{ ++ const char *name; ++ ++ unsigned long hres; // Horizontal Valid ++ unsigned long hfp; // Horizontal Front Porch ++ unsigned long hsync; // Horizontal Sync Width ++ unsigned long hbp; // Horizontal Back Porch ++ ++ unsigned long vres; // Vertical Valid ++ unsigned long vfp; // Vertical Front Porch ++ unsigned long vsync; // Vertical Sync Width ++ unsigned long vbp; // Vertical Back Porch ++ ++ unsigned long refresh; // Vertical Sync Frequency ++ ++ unsigned long clk_src; ++ unsigned long clk_edge; ++ unsigned long pol_blank; ++ unsigned long pol_hsync; ++ unsigned long pol_vsync; ++}; ++ ++ ++struct ep93xxfb_info ++{ ++ ++ ++ dma_addr_t fb_phys; ++ void *fb_log; ++ unsigned long fb_size; ++ unsigned long fb_actsize; ++ ++ unsigned long xtotal; ++ unsigned long ytotal; ++ ++ unsigned int xres; ++ unsigned int xfp; ++ unsigned int xsync; ++ unsigned int xbp; ++ ++ unsigned int yres; ++ unsigned int yfp; ++ unsigned int ysync; ++ unsigned int ybp; ++ unsigned int bpp; ++ ++ unsigned long refresh; ++ unsigned long pixclock; ++ unsigned long pixformat; ++ ++ unsigned int clk_src; ++ unsigned int clk_edge; ++ unsigned int pol_blank; ++ unsigned int pol_xsync; ++ unsigned int pol_ysync; ++ ++ unsigned char automods; ++ ++ void (*configure)(unsigned char value); ++ void (*on)(unsigned char value); ++ void (*off)(unsigned char value); ++}; ++ ++static int ep93xxfb_setclk(void); ++static int ep93xx_get_max_video_clk(void); ++static void ep93xxfb_pixelmod(int bpp); ++static void ep93xxfb_timing_signal_generation(void); ++static int ep93xxfb_blank(int blank_mode,struct fb_info *info); ++ ++#define EE_DELAY_USEC 2 ++#define EE_READ_TIMEOUT 100 ++#define CX25871_DEV_ADDRESS 0x88 ++#define GPIOG_EEDAT 2 ++#define GPIOG_EECLK 1 ++#define CXMODES_COUNT 24 ++ ++struct cx25871_vmodes ++{ ++ ++ const char *name; ++ unsigned char automode; ++ unsigned int hres; ++ unsigned int vres; ++ unsigned int hclktotal; ++ unsigned int vclktotal; ++ unsigned int hblank; ++ unsigned int vblank; ++ unsigned long clkfrequency; ++ ++}; ++ ++ ++int write_reg(unsigned char ucRegAddr, unsigned char ucRegValue); ++void cx25871_on(unsigned char value); ++void cx25871_off(unsigned char value); ++void cx25871_config(unsigned char value); ++ ++static void philips_lb064v02_on(unsigned char value); ++static void philips_lb064v02_off(unsigned char value); ++ ++ ++#define FBIO_EP93XX_CURSOR 0x000046c1 ++#define FBIO_EP93XX_LINE 0x000046c2 ++#define FBIO_EP93XX_FILL 0x000046c3 ++#define FBIO_EP93XX_BLIT 0x000046c4 ++#define FBIO_EP93XX_COPY 0x000046c5 ++ ++ ++#define CURSOR_BLINK 0x00000001 ++#define CURSOR_MOVE 0x00000002 ++#define CURSOR_SETSHAPE 0x00000004 ++#define CURSOR_SETCOLOR 0x00000008 ++#define CURSOR_ON 0x00000010 ++#define CURSOR_OFF 0x00000020 ++ ++ ++/* ++* ioctl(fd, FBIO_EP93XX_CURSOR, ep93xx_cursor *) ++* ++* "data" points to an array of pixels that define the cursor; each row should ++* be a multiple of 32-bit values (i.e. 16 pixels). Each pixel is two bits, ++* where the values are: ++* ++* 00 => transparent 01 => invert 10 => color1 11 => color2 ++* ++* The data is arranged as follows (per word): ++* ++* bits: |31-30|29-28|27-26|25-24|23-22|21-20|19-18|17-16| ++* pixel: | 12 | 13 | 14 | 15 | 8 | 9 | 10 | 11 | ++* bits: |15-14|13-12|11-10| 9-8 | 7-6 | 5-4 | 3-2 | 1-0 | ++* pixel: | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | ++* ++* Regardless of the frame buffer color depth, "color1", "color2", ++* "blinkcolor1", and "blinkcolor2" are 24-bit colors since the cursor is ++* injected into the data stream right before the video DAC. ++* ++* When "blinkrate" is not zero, pixel value 10 will alternate between "color1" ++* and "blinkcolor1" (similar for pixel value 11 and "color2"/"blinkcolor2"). ++* ++* "blinkrate" ranges between 0 and 255. When 0, blinking is disabled. 255 is ++* the fastest blink rate and 1 is the slowest. ++* ++* Both "width" and "height" must be between 1 and 64; it is preferable to have ++* "width" a multiple of 16. ++*/ ++struct ep93xx_cursor { ++ unsigned long flags; ++ unsigned long dx; // Only used if CURSOR_MOVE is set ++ unsigned long dy; // Only used if CURSOR_MOVE is set ++ unsigned long width; // Only used if CURSOR_SETSHAPE is set ++ unsigned long height; // Only used if CURSOR_SETSHAPE is set ++ const char *data; // Only used if CURSOR_SETSHAPE is set ++ unsigned long blinkrate; // Only used if CURSOR_BLINK is set ++ unsigned long color1; // Only used if CURSOR_SETCOLOR is set ++ unsigned long color2; // Only used if CURSOR_SETCOLOR is set ++ unsigned long blinkcolor1; // Only used if CURSOR_SETCOLOR is set ++ unsigned long blinkcolor2; // Only used if CURSOR_SETCOLOR is set ++}; ++ ++ ++/* ++ * The bits in the flags field of ep93xx_line. ++*/ ++/* ++* ioctl(fd, FBIO_EP93XX_LINE, ep93xx_line *) ++* ++* The line starts at ("x1","y1") and ends at ("x2","y2"). This means that ++* when using a pattern, the two coordinates are not transitive (i.e. swapping ++* ("x1","y1") with ("x2","y2") will not necessarily draw the exact same line, ++* pattern-wise). ++* ++* "pattern" is a 2 to 16 bit pattern (since a 1 bit pattern isn't much of a ++* pattern). The lower 16 bits define the pattern (1 being foreground, 0 being ++* background or transparent), and bits 19-16 define the length of the pattern ++* (as pattern length - 1). So, for example, "0xf00ff" defines a 16 bit ++* with the first 8 pixels in the foreground color and the next 8 pixels in the ++* background color or transparent. ++* ++* LINE_PRECISE is used to apply angularly corrected patterns to line. It ++* should only be used when LINE_PATTERN is also set. The pattern will be ++* applied along the length of the line, instead of along the length of the ++* major axis. This may result in the loss of fine details in the pattern, and ++* will take more time to draw the line in most cases. ++*/ ++ ++#define LINE_PATTERN 0x00000001 ++#define LINE_PRECISE 0x00000002 ++#define LINE_BACKGROUND 0x00000004 ++ ++struct ep93xx_line { ++ unsigned long flags; ++ unsigned long x1; ++ unsigned long y1; ++ unsigned long x2; ++ unsigned long y2; ++ unsigned long fgcolor; ++ unsigned long bgcolor; // Only used if LINE_BACKGROUND is set ++ unsigned long pattern; // Only used if LINE_PATTERN is set ++}; ++ ++#endif /* __EP93XXFB_H__ */ ++ +--- /dev/null ++++ b/drivers/video/ep93xxfb_mono.c +@@ -0,0 +1,1281 @@ ++/* ++ * drivers/video/ep93xxfb_mono.c -- grayscale on mono LCD driver for ++ * Cirrus Logic EP93xx. ++ * ++ * Copyright (C) 2007 Cirrus Logic ++ * ++ * 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. ++ * ++ * This driver works for the following two LCD: ++ * SHARP LM121VB1T01 - A dual scan 640x480 monochrome LCD. ++ * HOSIDEN HLM6323 - A single scan 320x240 monochrome LCD. ++ * ++ * And support two gray modes: ++ * 8 levels of gray - Actually is 7 levels of gray. Two of the levels ++ * have the same gray. ++ * 16 levels of gray - Extending the gray levels by switching the LUT ++ * for each frame. ++ * ++ * HW connection for SHARP LM121VB1T01: ++ * P12 <------> LCD_U0 ++ * P8 <------> LCD_U1 ++ * P4 <------> LCD_U2 ++ * P0 <------> LCD_U3 ++ * P14 <------> LCD_L0 ++ * P10 <------> LCD_L1 ++ * P6 <------> LCD_L2 ++ * P2 <------> LCD_L3 ++ * HW connection for HOSIDEN HLM6323: ++ * P12 <------> LCD_0 ++ * P8 <------> LCD_1 ++ * P4 <------> LCD_2 ++ * P0 <------> LCD_3 ++ * ++ */ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/reboot.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/dma-mapping.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <mach/hardware.h> ++ ++ ++#include <linux/platform_device.h> ++ ++#define CONFIG_EP93XX_SDCS0 ++ ++#undef DEBUG ++#ifdef DEBUG ++#define DPRINTK( fmt, arg... ) printk( fmt, ##arg ) ++#else ++#define DPRINTK( fmt, arg... ) ++#endif ++ ++#define FBDEV_NAME "ep93xxfb" ++ ++#define ep93xxfb_lock_outl(value, reg) \ ++{ \ ++ outl(RASTER_SWLOCK_VALUE, RASTER_SWLOCK); \ ++ outl(value, reg); \ ++ DPRINTK(#reg"=0x%08x\n", (unsigned int)(value)); \ ++} ++ ++#define ep93xxfb_outl(value, reg) \ ++{ \ ++ outl(value, reg); \ ++ DPRINTK(#reg"=0x%08x\n", (unsigned int)(value)); \ ++} ++ ++static unsigned int pseudo_palette[256]; ++ ++struct ep93xxfb_mono_videomodes ++{ ++ const char *name; ++ ++ unsigned long hres; // Horizontal Valid ++ unsigned long vres; // Vertical Valid ++ unsigned int freq; ++ unsigned int dualscan; ++ unsigned int bpp; ++ unsigned int graylevel; ++ ++ void (*configure)(unsigned char value); ++ void (*on)(unsigned char value); ++ void (*off)(unsigned char value); ++}; ++ ++struct ep93xxfb_mono_info ++{ ++ dma_addr_t fb_phys; ++ void *fb_log; ++ unsigned long fb_size; ++ unsigned long fb_actsize; ++ ++ unsigned int xres; ++ unsigned int yres; ++ ++ unsigned int freq; ++ unsigned int dualscan; ++ unsigned int bpp; ++ unsigned int graylevel; ++ ++ void (*configure)(unsigned char value); ++ void (*on)(unsigned char value); ++ void (*off)(unsigned char value); ++}; ++ ++ ++void LM121VB1T01_configure(unsigned char value); ++void HOSIDEN_HLM6323_configure(unsigned char value); ++ ++static int vmode = 1; ++ ++static struct ep93xxfb_mono_info epinfo; ++static struct ep93xxfb_mono_videomodes ep93xxfb_vmods[] = ++{ ++ { ++ "SHARP-LM121VB1T01-8GRAY", ++ 640, 480, 100, ++ 1, //dual scan ++ 4, //4bpp ++ 8, //8-level grayscale ++ LM121VB1T01_configure, ++ NULL, ++ NULL, ++ }, ++ { ++ "SHARP-LM121VB1T01-16GRAY", ++ 640, 480, 120, ++ 1, //dual scan ++ 4, //4bpp ++ 16, //16-level grayscale ++ LM121VB1T01_configure, ++ NULL, ++ NULL, ++ }, ++ { ++ "HOSIDEN HLM6323", ++ 320, 240, 115, ++ 0, //single scan ++ 4, //4bpp ++ 8, //8-level grayscale ++ HOSIDEN_HLM6323_configure, ++ NULL, ++ NULL, ++ }, ++ { ++ "HOSIDEN HLM6323", ++ 320, 240, 115, ++ 0, //single scan ++ 4, //4bpp ++ 16, //16-level grayscale ++ HOSIDEN_HLM6323_configure, ++ NULL, ++ NULL, ++ }, ++}; ++ ++ ++#define EP93XX_GS_OFFSET(lut, frame, pixel) ( (lut) + ( (pixel) << 2) + ((frame) << 5 )) ++ ++static unsigned long DY_LUT[2][16]; ++ ++static unsigned long GSLUT[32] = ++{ ++ 0x00070000, 0x00070000, 0x00070000, 0x00070000, /*0%*/ ++ 0x00078241, 0x00074182, 0x00071428, 0x00072814, /*25%*/ ++ 0x00000412, 0x00000241, 0x00000124, 0x00000000, /*33%*/ ++ 0x0007aa55, 0x000755aa, 0x000755aa, 0x0007aa55, /*50%*/ ++ 0x00000bed, 0x00000dbe, 0x00000edb, 0x00000000, /*66%*/ ++ 0x00077dbe, 0x0007be7d, 0x0007ebd7, 0x0007d7eb, /*75%*/ ++ 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, /*100%*/ ++ 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, ++}; ++ ++static void ep93xxfb_8gray_palette_init(void) ++{ ++ unsigned int cont, i, n; ++ unsigned int frame, pixval, gslut; ++ cont = inl(LUTCONT); ++ for (i=0; i< 16; i++) ++ { ++ n = (i & 0xe) << 4; ++ outl( n, (COLOR_LUT+(i<<2)) ); ++ } ++ for (pixval=0; pixval < 8; pixval++) ++ { ++ for (frame=0; frame < 4; frame++) ++ { ++ gslut = GSLUT[pixval*4 + frame]; ++ outl(gslut,EP93XX_GS_OFFSET(GS_LUT, frame, pixval)); ++ } ++ } ++ outl( cont ^ LUTCONT_RAM1, LUTCONT ); ++} ++ ++static void ep93xxfb_16gray_palette_switch(int index) ++{ ++ unsigned int cont, i, n; ++ cont = inl(LUTCONT); ++ n = index & 0x1; ++ for (i=0; i< 16; i++) ++ { ++ outl( DY_LUT[n][i], (COLOR_LUT+(i<<2)) ); ++ } ++ outl( cont ^ LUTCONT_RAM1, LUTCONT ); ++} ++ ++static void ep93xxfb_16gray_palette_init(void) ++{ ++ int i; ++ unsigned int cont; ++ unsigned int frame, pixval, gslut; ++ int split_table[16][2] = ++ { ++ {0, 0 }, ++ {0, 2 }, ++ {1, 1 }, ++ {3, 0 }, ++ ++ {2, 2 }, ++ {4, 0 }, ++ {3, 2 }, ++ {4, 2 }, ++ ++ {3, 3 }, // {6, 0 }, ++ {3, 4 }, ++ {4, 4 }, ++ {6, 2 }, ++ ++ {5, 5 }, ++ {3, 6 }, ++ {4, 6 }, ++ {6, 6 }, ++ }; ++ ++ cont = inl(LUTCONT); ++ for (i=0; i< 16; i++) ++ { ++ DY_LUT[0][i]=split_table[i][0] << 5; ++ DY_LUT[1][i]=split_table[i][1] << 5; ++ ++ outl( DY_LUT[0][i], (COLOR_LUT+(i<<2)) ); ++ } ++ ++ for (pixval=0; pixval < 8; pixval++) ++ { ++ for (frame=0; frame < 4; frame++) ++ { ++ gslut = GSLUT[pixval*4 + frame]; ++ outl(gslut,EP93XX_GS_OFFSET(GS_LUT, frame, pixval)); ++ outl(gslut,EP93XX_GS_OFFSET(GS_LUT2, frame, pixval)); ++ outl(gslut,EP93XX_GS_OFFSET(GS_LUT3, frame, pixval)); ++ } ++ } ++ outl( cont ^ LUTCONT_RAM1, LUTCONT ); ++} ++ ++static int ep93xxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct fb_var_screeninfo tmp_var; ++ DPRINTK("ep93xxfb_check_var - enter\n"); ++ ++ memcpy (&tmp_var, var, sizeof (tmp_var)); ++ ++ if (var->xres_virtual != var->xres) ++ var->xres_virtual = var->xres; ++ if (var->yres_virtual < var->yres) ++ var->yres_virtual = var->yres; ++ ++ if (var->xoffset < 0) ++ var->xoffset = 0; ++ if (var->yoffset < 0) ++ var->yoffset = 0; ++ ++ switch (tmp_var.bits_per_pixel) ++ { ++ case 4: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ DPRINTK("ep93xxfb_check_var - exit\n"); ++ return 0; ++} ++ ++static int ep93xxfb_set_par(struct fb_info *info) ++{ ++ DPRINTK("ep93xxfb_set_par\n"); ++ switch (info->var.bits_per_pixel) { ++ case 4: ++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++ ++static int ep93xxfb_blank(int blank_mode,struct fb_info *info) ++{ ++ unsigned long attribs; ++ DPRINTK("ep93xxfb_blank - enter\n"); ++ attribs = inl(VIDEOATTRIBS); ++ ++ if (blank_mode) { ++ if (epinfo.off) ++ (epinfo.off)( 0 ); ++ ++ ep93xxfb_lock_outl(attribs & ~(VIDEOATTRIBS_DATAEN | ++ VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_PCLKEN | ++ VIDEOATTRIBS_EN), VIDEOATTRIBS); ++ } ++ else { ++ ++ if (epinfo.configure) ++ (epinfo.configure)( (unsigned char) epinfo.graylevel ); ++ if (epinfo.on) ++ (epinfo.on)( 0 ); ++ } ++ return 0; ++} ++ ++static void ep93xxfb_get_par(struct fb_info *info) ++{ ++ ++ DPRINTK("ep93xxfb_get_par - enter\n"); ++ ++ epinfo.configure = ep93xxfb_vmods[vmode].configure; ++ epinfo.on = ep93xxfb_vmods[vmode].on; ++ epinfo.off = ep93xxfb_vmods[vmode].off; ++ ++ epinfo.freq = ep93xxfb_vmods[vmode].freq; ++ epinfo.dualscan = ep93xxfb_vmods[vmode].dualscan; ++ epinfo.bpp = ep93xxfb_vmods[vmode].bpp; ++ epinfo.graylevel = ep93xxfb_vmods[vmode].graylevel; ++ ++ epinfo.xres = ep93xxfb_vmods[vmode].hres; ++ epinfo.yres = ep93xxfb_vmods[vmode].vres; ++ ++} ++ ++static int ep93xxfb_alloc_videomem(void) ++{ ++ unsigned long adr,size,pgsize; ++ int order; ++ ++ DPRINTK("ep93xxfb_alloc_videomem - enter \n"); ++ ++ epinfo.fb_log = NULL; ++ epinfo.fb_size = epinfo.xres*epinfo.yres*epinfo.bpp/8; ++ order = get_order( epinfo.fb_size ); ++ epinfo.fb_log = (void*) __get_free_pages( GFP_KERNEL, order ); ++ ++ if (epinfo.fb_log) { ++ epinfo.fb_phys = __virt_to_phys((int) epinfo.fb_log ); ++ adr = (unsigned long)epinfo.fb_log; ++ size = epinfo.fb_size; ++ pgsize = 1 << order; ++ do { ++ adr += pgsize; ++ SetPageReserved(virt_to_page(adr)); ++ } while(size -= pgsize); ++ } ++ else ++ return -ENOMEM; ++ ++ memset(epinfo.fb_log,0x00,epinfo.fb_size); ++ ++ DPRINTK(" fb_log_addres = 0x%x\n", (unsigned int)epinfo.fb_log); ++ DPRINTK(" fb_phys_address = 0x%x\n", (unsigned int)epinfo.fb_phys); ++ DPRINTK(" fb_size = %lu\n", (unsigned long)epinfo.fb_size); ++ DPRINTK(" fb_page_order = %d\n", (unsigned int)order); ++ DPRINTK("ep93xxfb_alloc_videomem - exit \n"); ++ return 0; ++} ++ ++static void ep93xxfb_release_videomem(void) ++{ ++ unsigned long adr,size,psize; ++ int order; ++ ++ DPRINTK("ep93xxfb_release_videomem - enter \n"); ++ if (epinfo.fb_log) { ++ order = get_order(epinfo.fb_size); ++ adr = (unsigned long)epinfo.fb_log; ++ size = epinfo.fb_size; ++ psize = 1 << order ; ++ do { ++ adr += psize; ++ ClearPageReserved(virt_to_page(adr)); ++ } while(size -= psize); ++ free_pages((unsigned long)epinfo.fb_log, order ); ++ } ++ DPRINTK("ep93xxfb_release_videomem - exit \n"); ++} ++ ++static void ep93xxfb_setinfo(struct fb_info *info) ++{ ++ ++ DPRINTK("ep93xxfb_setinfo - enter \n"); ++ info->pseudo_palette = pseudo_palette; ++ info->var.xres = epinfo.xres; ++ info->var.yres = epinfo.yres; ++ info->var.xres_virtual = epinfo.xres; ++ info->var.yres_virtual = epinfo.yres; ++ ++ info->var.bits_per_pixel = epinfo.bpp; ++ info->var.red.length = epinfo.bpp; ++ info->var.green.length = epinfo.bpp; ++ info->var.blue.length = epinfo.bpp; ++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ info->var.red.offset = 0; ++ info->var.green.offset =0; ++ info->var.blue.offset = 0; ++ ++ info->fix.smem_start = epinfo.fb_phys; ++ info->fix.smem_len = epinfo.fb_size; ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++ info->fix.line_length = (epinfo.xres * epinfo.bpp) / 8; ++ info->fix.accel = FB_ACCEL_NONE; ++ info->screen_base = epinfo.fb_log; ++ info->fix.ypanstep = 1; ++ info->fix.ywrapstep = 1; ++ ++ DPRINTK("ep93xxfb_setinfo - exit \n"); ++} ++ ++static int ep93xxfb_config(struct fb_info *info) ++{ ++ DPRINTK("ep93xxfb_config - enter\n"); ++ ++ ep93xxfb_get_par( info ); ++ if( ep93xxfb_alloc_videomem() != 0 ) { ++ printk("Unable to allocate video memory\n"); ++ return -ENOMEM; ++ } ++ ++ /* set video memory parameters */ ++ ep93xxfb_outl(epinfo.fb_phys, VIDSCRNPAGE); ++ if(epinfo.dualscan) ++ { ++ ep93xxfb_outl(epinfo.fb_phys + (epinfo.bpp*epinfo.xres*epinfo.yres/16) ++ , VIDSCRNHPG); ++ } ++ ++ DPRINTK(" fb_phys = 0x%x\n", inl(VIDSCRNPAGE) ); ++ DPRINTK(" fb_phys_hpg = 0x%x\n", inl(VIDSCRNHPG)); ++ ++ ep93xxfb_outl(epinfo.yres , SCRNLINES); ++ ep93xxfb_outl(((epinfo.xres * epinfo.bpp) / 32) - 1, LINELENGTH); ++ ep93xxfb_outl((epinfo.xres * epinfo.bpp) / 32, VLINESTEP); ++ ++ if(epinfo.configure) ++ (epinfo.configure)( (unsigned char) epinfo.graylevel ); ++ ++ ep93xxfb_setinfo( info ); ++ ++ ++ DPRINTK("ep93xxfb_config - exit\n"); ++ return 0; ++} ++ ++static unsigned long ep93xx_get_pll_frequency(unsigned long pll) ++{ ++ unsigned long fb1, fb2, ipd, ps, freq; ++ ++ if (pll == 1) ++ pll = inl(EP93XX_SYSCON_CLOCK_SET1); ++ else if (pll == 2) ++ pll = inl(EP93XX_SYSCON_CLOCK_SET2); ++ else ++ return 0; ++ ++ ps = (pll & SYSCON_CLKSET1_PLL1_PS_MASK) >> SYSCON_CLKSET1_PLL1_PS_SHIFT; ++ fb1 = ((pll & SYSCON_CLKSET1_PLL1_X1FBD1_MASK) >> SYSCON_CLKSET1_PLL1_X1FBD1_SHIFT); ++ fb2 = ((pll & SYSCON_CLKSET1_PLL1_X2FBD2_MASK) >> SYSCON_CLKSET1_PLL1_X2FBD2_SHIFT); ++ ipd = ((pll & SYSCON_CLKSET1_PLL1_X2IPD_MASK) >> SYSCON_CLKSET1_PLL1_X2IPD_SHIFT); ++ ++ freq = (((0x00e10000 * (fb1+1)) / (ipd+1)) * (fb2+1)) >> ps; ++ return freq; ++} ++ ++static int ep93xx_set_video_div(unsigned long freq) ++{ ++ unsigned long pdiv = 0, div = 0, psel = 0, esel = 0; ++ unsigned long err, f, i, j, k; ++ ++ err = -1; ++ ++ for (i = 0; i < 3; i++) { ++ if (i == 0) ++ f = 14745600 * 2; ++ else if (i == 1) ++ f = ep93xx_get_pll_frequency(1) * 2; ++ else ++ f = ep93xx_get_pll_frequency(2) * 2; ++ ++ for (j = 4; j <= 6; j++) { ++ k = f / (freq * j); ++ if (k < 2) ++ continue; ++ ++ if (abs(((f / (j * k))) - freq ) < err ) { ++ pdiv = j - 3; ++ div = k; ++ psel = (i == 2) ? 1 : 0; ++ esel = (i == 0) ? 0 : 1; ++ err = (f / (j * k)) - freq; ++ } ++ } ++ } ++ ++ if (err == -1) ++ return -1; ++ ++ f = SYSCON_VIDDIV_VENA | (esel ? SYSCON_VIDDIV_ESEL : 0) | ++ (psel ? SYSCON_VIDDIV_PSEL : 0) | ++ (pdiv << SYSCON_VIDDIV_PDIV_SHIFT) | ++ (div << SYSCON_VIDDIV_VDIV_SHIFT); ++ outl(0xaa, EP93XX_SYSCON_SWLOCK); ++ outl(f, SYSCON_VIDDIV); ++ ++ return freq + err; ++} ++ ++static int interrupt_hooked = 0; ++static int vs_counter = 0; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) ++static irqreturn_t ep93xxfb_irq_handler(int i, void *blah) ++#else ++static irqreturn_t ep93xxfb_irq_handler(int i, void *blah, struct pt_regs *regs) ++#endif ++{ ++ ++ outl(RASTER_SWLOCK_VALUE, RASTER_SWLOCK); ++ outl( ++#ifdef CONFIG_EP93XX_SDCS0 ++ (0 << VIDEOATTRIBS_SDSEL_SHIFT) | ++#endif ++#ifdef CONFIG_EP93XX_SDCS1 ++ (1 << VIDEOATTRIBS_SDSEL_SHIFT) | ++#endif ++#ifdef CONFIG_EP93XX_SDCS2 ++ (2 << VIDEOATTRIBS_SDSEL_SHIFT) | ++#endif ++#ifdef CONFIG_EP93XX_SDCS3 ++ (3 << VIDEOATTRIBS_SDSEL_SHIFT) | ++#endif ++ VIDEOATTRIBS_VCPOL | VIDEOATTRIBS_HSPOL | ++ VIDEOATTRIBS_DATAEN | VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_INVCLK | ++ VIDEOATTRIBS_PCLKEN | VIDEOATTRIBS_EN | VIDEOATTRIBS_INTEN , ++ VIDEOATTRIBS ); ++ ++ ep93xxfb_16gray_palette_switch(vs_counter++); ++ ++ return IRQ_HANDLED; ++} ++ ++void LM121VB1T01_configure(unsigned char value) ++{ ++ ++ int n; ++ unsigned long attribs; ++ printk("LM121VB1T01_configure\n"); ++ ++ switch(value) ++ { ++ case 8: ++ ep93xxfb_8gray_palette_init(); ++ break; ++ case 16: ++ ep93xxfb_16gray_palette_init(); ++ break; ++ default: ++ return; ++ } ++ ++ SysconSetLocked(EP93XX_SYSCON_DEVICE_CONFIG, (inl(EP93XX_SYSCON_DEVICE_CONFIG) & ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE) | EP93XX_SYSCON_DEVCFG_RasOnP3); ++ ++ ep93xx_set_video_div(epinfo.freq*240*1280); ++ ++ ep93xxfb_lock_outl( 0x00000000 , VIDEOATTRIBS ); ++ ++ n = 240; ++ ep93xxfb_lock_outl( n + 3 , VLINESTOTAL ); ++ ep93xxfb_lock_outl( ((n)<<16) + n+1 , VSYNCSTRTSTOP ); ++ ep93xxfb_lock_outl( ((2)<<16) + n+2 , VACTIVESTRTSTOP ); ++ ep93xxfb_lock_outl( ((3)<<16) + n+3 , VBLANKSTRTSTOP ); ++ ep93xxfb_lock_outl( ((n+3)<<16) + n+3 , VCLKSTRTSTOP ); ++ ++ n = 1280; ++ ep93xxfb_lock_outl( n + 15 , HCLKSTOTAL ); ++ ep93xxfb_lock_outl( ((n+5)<<16) + n+ 14 , HSYNCSTRTSTOP ); ++ ep93xxfb_lock_outl( ((15)<<16) + n + 15 , HACTIVESTRTSTOP ); ++ ep93xxfb_lock_outl( ((n+15)<<16) + 15 , HBLANKSTRTSTOP ); ++ ep93xxfb_lock_outl( ((n)<<16) + n , HCLKSTRTSTOP ); ++ ++ ep93xxfb_lock_outl( 14 , LINECARRY ); ++ ++ attribs = 0; ++ ++#ifdef CONFIG_EP93XX_SDCS0 ++ attribs |= 0 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS1 ++ attribs |= 1 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS2 ++ attribs |= 2 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS3 ++ attribs |= 3 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++ ++ switch(value) ++ { ++ case 8: ++ ep93xxfb_lock_outl( PIXELMODE_DSCAN | ++ PIXELMODE_S_8PPC | PIXELMODE_P_4BPP | ++ PIXELMODE_C_GSLUT , PIXELMODE ); ++ ++ ep93xxfb_lock_outl( ++ attribs | VIDEOATTRIBS_VCPOL | VIDEOATTRIBS_HSPOL | ++ VIDEOATTRIBS_DATAEN | VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_INVCLK | ++ VIDEOATTRIBS_PCLKEN | VIDEOATTRIBS_EN , ++ VIDEOATTRIBS ); ++ break; ++ case 16: ++ if(!interrupt_hooked) ++ { ++ request_irq(IRQ_EP93XX_VSYNC, ep93xxfb_irq_handler, IRQF_DISABLED, "lut switch interrupt", NULL); ++ interrupt_hooked = 1; ++ } ++ ep93xxfb_lock_outl( PIXELMODE_DSCAN | ++ PIXELMODE_S_8PPC | PIXELMODE_P_4BPP | PIXELMODE_C_GSLUT, PIXELMODE ); ++ ++ ep93xxfb_lock_outl( ++ attribs | VIDEOATTRIBS_VCPOL | VIDEOATTRIBS_HSPOL | ++ VIDEOATTRIBS_DATAEN | VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_INVCLK | ++ VIDEOATTRIBS_PCLKEN | VIDEOATTRIBS_EN | VIDEOATTRIBS_INTEN, ++ VIDEOATTRIBS ); ++ break; ++ default: ++ return; ++ } ++ ++} ++ ++void HOSIDEN_HLM6323_configure(unsigned char value) ++{ ++ int n; ++ unsigned long attribs; ++ ++ printk("HOSIDEN_HLM6323_configure\n"); ++ ++ switch(value) ++ { ++ case 8: ++ ep93xxfb_8gray_palette_init(); ++ break; ++ case 16: ++ ep93xxfb_16gray_palette_init(); ++ break; ++ default: ++ return; ++ } ++ ++ SysconSetLocked(EP93XX_SYSCON_DEVICE_CONFIG, inl(EP93XX_SYSCON_DEVICE_CONFIG) |EP93XX_SYSCON_DEVCFG_RasOnP3); ++ ++ ep93xxfb_lock_outl( 0x00000000 , VIDEOATTRIBS ); ++ ++ ep93xx_set_video_div(epinfo.freq*320*240); ++ mdelay(10); ++ ++ n = 240; ++ ep93xxfb_lock_outl( n + 3 , VLINESTOTAL ); ++ ep93xxfb_lock_outl( ((n+1)<<16) + n +2 , VSYNCSTRTSTOP ); ++ ep93xxfb_lock_outl( ((3)<<16) + n +3 , VACTIVESTRTSTOP ); ++ ep93xxfb_lock_outl( ((3)<<16) + n +3 , VBLANKSTRTSTOP ); ++ ep93xxfb_lock_outl( ((n+3)<<16) + n +3, VCLKSTRTSTOP ); ++ ++ n = 320; ++ ep93xxfb_lock_outl( n + 3, HCLKSTOTAL ); ++ ep93xxfb_lock_outl( ((n+1)<<16) + n+2 , HSYNCSTRTSTOP ); ++ ep93xxfb_lock_outl( ((3)<<16) + n+3 , HACTIVESTRTSTOP ); ++ ep93xxfb_lock_outl( ((3)<<16) + n+3 , HBLANKSTRTSTOP ); ++ ep93xxfb_lock_outl( ((n+3)<<16) + n+3 , HCLKSTRTSTOP ); ++ ++ ep93xxfb_lock_outl( 3 , LINECARRY ); ++ ++ attribs = 0; ++ ++#ifdef CONFIG_EP93XX_SDCS0 ++ attribs |= 0 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS1 ++ attribs |= 1 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS2 ++ attribs |= 2 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++#ifdef CONFIG_EP93XX_SDCS3 ++ attribs |= 3 << VIDEOATTRIBS_SDSEL_SHIFT; ++#endif ++ ++ switch(value) ++ { ++ case 8: ++ ep93xxfb_lock_outl( ++ PIXELMODE_S_4PPC | PIXELMODE_P_4BPP | PIXELMODE_C_GSLUT, PIXELMODE ); ++ ep93xxfb_lock_outl( ++ attribs | VIDEOATTRIBS_VCPOL | VIDEOATTRIBS_HSPOL | ++ VIDEOATTRIBS_DATAEN | VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_INVCLK | ++ VIDEOATTRIBS_PCLKEN | VIDEOATTRIBS_EN , ++ VIDEOATTRIBS ); ++ break; ++ case 16: ++ ep93xxfb_lock_outl( ++ PIXELMODE_S_4PPC | PIXELMODE_P_4BPP | PIXELMODE_C_GSLUT, PIXELMODE ); ++ if(!interrupt_hooked) ++ { ++ request_irq(IRQ_EP93XX_VSYNC, ep93xxfb_irq_handler, IRQF_DISABLED, "lut switch interrupt", NULL); ++ interrupt_hooked = 1; ++ } ++ ep93xxfb_lock_outl( ++ attribs | VIDEOATTRIBS_VCPOL | VIDEOATTRIBS_HSPOL | ++ VIDEOATTRIBS_DATAEN | VIDEOATTRIBS_SYNCEN | VIDEOATTRIBS_INVCLK | ++ VIDEOATTRIBS_PCLKEN | VIDEOATTRIBS_EN | VIDEOATTRIBS_INTEN, ++ VIDEOATTRIBS ); ++ break; ++ default: ++ return; ++ } ++} ++ ++#define FB_WRITEL fb_writel ++#define FB_READL fb_readl ++#define LEFT_POS(bpp) (0) ++#define SHIFT_HIGH(val, bits) ((val) << (bits)) ++#define SHIFT_LOW(val, bits) ((val) >> (bits)) ++static inline void color_imageblit(const struct fb_image *image, ++ struct fb_info *p, u8 *dst1, ++ u32 start_index, ++ u32 pitch_index) ++{ ++ /* Draw the penguin */ ++ u32 *dst, *dst2; ++ u32 color = 0, val, shift; ++ int i, n, bpp = p->var.bits_per_pixel; ++ u32 null_bits = 32 - bpp; ++ u32 *palette = (u32 *) p->pseudo_palette; ++ const u8 *src = image->data; ++ ++ dst2 = (u32 *) dst1; ++ for (i = image->height; i--; ) { ++ n = image->width; ++ dst = (u32 *) dst1; ++ shift = 0; ++ val = 0; ++ ++ if (start_index) { ++ u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index)); ++ val = FB_READL(dst) & start_mask; ++ shift = start_index; ++ } ++ while (n--) { ++ if (p->fix.visual == FB_VISUAL_TRUECOLOR || ++ p->fix.visual == FB_VISUAL_DIRECTCOLOR ) ++ color = palette[*src]; ++ else ++ color = *src; ++ color <<= LEFT_POS(bpp); ++ val |= SHIFT_HIGH(color, shift); ++ if (shift >= null_bits) { ++ FB_WRITEL(val, dst++); ++ ++ val = (shift == null_bits) ? 0 : ++ SHIFT_LOW(color, 32 - shift); ++ } ++ shift += bpp; ++ shift &= (32 - 1); ++ src++; ++ } ++ if (shift) { ++ u32 end_mask = SHIFT_HIGH(~(u32)0, shift); ++ ++ FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); ++ } ++ dst1 += p->fix.line_length; ++ if (pitch_index) { ++ dst2 += p->fix.line_length; ++ dst1 = (u8 *)((long __force)dst2 & ~(sizeof(u32) - 1)); ++ ++ start_index += pitch_index; ++ start_index &= 32 - 1; ++ } ++ } ++} ++ ++static const int reversebit[]= ++{ ++ 7, 6, 5, 4, 3, 2, 1, 0, ++ 15,14,13,12,11,10, 9, 8, ++ 23,22,21,20,19,18,17,16, ++ 31,30,29,28,27,26,25,24, ++}; ++static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, ++ u8 *dst1, u32 fgcolor, ++ u32 bgcolor, ++ u32 start_index, ++ u32 pitch_index) ++{ ++ u32 shift, color = 0, bpp = p->var.bits_per_pixel; ++ u32 *dst, *dst2; ++ u32 val, pitch = p->fix.line_length; ++ u32 null_bits = 32 - bpp; ++ u32 spitch = (image->width+7)/8; ++ const u8 *src = image->data, *s; ++ u32 i, j, l; ++ ++ dst2 = (u32 *) dst1; ++ fgcolor <<= LEFT_POS(bpp); ++ bgcolor <<= LEFT_POS(bpp); ++ for (i = image->height; i--; ) { ++ shift = val = 0; ++ l = 8; ++ j = image->width; ++ dst = (u32 *) dst1; ++ s = src; ++ ++ /* write leading bits */ ++ if (start_index) { ++ u32 start_mask = ~(SHIFT_HIGH(~(u32)0,start_index)); ++ val = FB_READL(dst) & start_mask; ++ shift = start_index; ++ } ++ ++ while (j--) { ++ l--; ++ color = (*s & (1 << l)) ? fgcolor : bgcolor; ++ val |= SHIFT_HIGH(color, reversebit[shift]); ++ /* Did the bitshift spill bits to the next long? */ ++ if (shift >= null_bits) { ++ FB_WRITEL(val, dst++); ++ val = (shift == null_bits) ? 0 : ++ SHIFT_LOW(color, 32 - reversebit[shift]); ++ } ++ shift += bpp; ++ shift &= (32 - 1); ++ if (!l) { l = 8; s++; }; ++ } ++ ++ /* write trailing bits */ ++ if (shift) { ++ u32 end_mask = SHIFT_HIGH(~(u32)0, shift); ++ ++ FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); ++ } ++ ++ dst1 += pitch; ++ src += spitch; ++ if (pitch_index) { ++ dst2 += pitch; ++ dst1 = (u8 *)((long __force)dst2 & ~(sizeof(u32) - 1)); ++ start_index += pitch_index; ++ start_index &= 32 - 1; ++ } ++ ++ } ++} ++ ++static void ep93xx_imageblit(struct fb_info *p, const struct fb_image *image) ++{ ++ u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; ++ u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; ++ u32 dx = image->dx, dy = image->dy; ++ u8 *dst1; ++ ++ if (p->state != FBINFO_STATE_RUNNING) ++ return; ++ ++ bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); ++ start_index = bitstart & (32 - 1); ++ pitch_index = (p->fix.line_length & (bpl - 1)) * 8; ++ ++ bitstart /= 8; ++ bitstart &= ~(bpl - 1); ++ dst1 = p->screen_base + bitstart; ++ ++ if (p->fbops->fb_sync) ++ p->fbops->fb_sync(p); ++ ++ if (image->depth == 1) { ++ if (p->fix.visual == FB_VISUAL_TRUECOLOR || ++ p->fix.visual == FB_VISUAL_DIRECTCOLOR) { ++ fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color]; ++ bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color]; ++ } else { ++ fgcolor = image->fg_color; ++ bgcolor = image->bg_color; ++ } ++ slow_imageblit(image, p, dst1, fgcolor, bgcolor, ++ start_index, pitch_index); ++ } else ++ color_imageblit(image, p, dst1, start_index, pitch_index); ++} ++ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) ++ ++int ep93xxfb_ioctl(struct fb_info *info,unsigned int cmd, unsigned long arg) ++{ ++ return 0; ++} ++ ++static int ep93xxfb_mmap(struct fb_info *info,struct vm_area_struct *vma) ++{ ++ unsigned long off, start, len; ++ ++ DPRINTK("ep93xxfb_mmap - enter\n"); ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ start = info->fix.smem_start; ++ len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; ++ start &= PAGE_MASK; ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ ++ off += start; ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ ++ vma->vm_flags |= VM_IO; ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) { ++ DPRINTK("ep93xxfb_mmap error\n"); ++ return -EAGAIN; ++ } ++ ++ DPRINTK("ep93xxfb_mmap - exit\n"); ++ return 0; ++} ++ ++ ++static struct fb_ops ep93xxfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = ep93xxfb_check_var, ++ .fb_set_par = ep93xxfb_set_par, ++ .fb_blank = ep93xxfb_blank, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ // .fb_imageblit = cfb_imageblit, ++ .fb_imageblit = ep93xx_imageblit, ++ .fb_ioctl = ep93xxfb_ioctl, ++ .fb_mmap = ep93xxfb_mmap, ++}; ++ ++ ++static struct resource ep93xxfb_raster_resources = { ++ .start = EP93XX_RASTER_PHYS_BASE, ++ .end = EP93XX_RASTER_PHYS_BASE + 0x1ffff, ++ .flags = IORESOURCE_MEM, ++}; ++ ++ ++static int __init ep93xxfb_probe(struct platform_device *device) ++{ ++ struct fb_info *info = NULL; ++ struct resource *res = NULL; ++ int ret = 0; ++ int arb = 0; ++ ++ DPRINTK("ep93xxfb_probe - enter \n"); ++ ++ if(!device) { ++ printk("error : to_platform_device\n"); ++ return -ENODEV; ++ } ++ res = platform_get_resource( device, IORESOURCE_MEM, 0); ++ if(!res) { ++ printk("error : platform_get_resource \n"); ++ return -ENODEV; ++ } ++ if (!request_mem_region(res->start,res->end - res->start + 1, FBDEV_NAME )) ++ return -EBUSY; ++ ++ info = framebuffer_alloc(sizeof(u32) * 256, &device->dev); ++ ++ if(!info) { ++ printk("Unable to allocate memory for frame buffer\n"); ++ return -ENOMEM; ++ } ++ ++ info->flags = FBINFO_DEFAULT; ++ strncpy(info->fix.id, FBDEV_NAME, sizeof(info->fix.id)); ++ info->fix.mmio_start = res->start; ++ info->fix.mmio_len = res->end - res->start + 1; ++ info->fbops = &ep93xxfb_ops; ++ info->pseudo_palette = info->par; ++ info->state = FBINFO_STATE_RUNNING; ++ ++ printk("mmio_start = 0x%08x\n", res->start); ++ printk("mmio_len = 0x%08x\n", res->end - res->start + 1); ++ ++ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { ++ ret = -ENOMEM; ++ goto fbuff; ++ } ++ ++ if ((ret = ep93xxfb_config(info)) < 0) ++ goto clmap; ++ ++ if (register_framebuffer(info) < 0) { ++ printk(KERN_ERR "Unable to register ep93xxfb frame buffer\n"); ++ ret = -EINVAL; ++ goto clmap; ++ } ++ platform_set_drvdata(device, info); ++ printk(KERN_INFO "fb%d: EP93xx frame buffer at %dx%dx%dbpp\n", info->node, ++ info->var.xres, info->var.yres, info->var.bits_per_pixel); ++ ++ /*change the raster arb to the highest one--Bo*/ ++ arb = inl(EP93XX_SYSCON_BMAR); ++ arb = (arb & 0x3f8) | 0x01; ++ ep93xxfb_outl(arb,EP93XX_SYSCON_BMAR); ++ ++ DPRINTK("ep93xxfb_probe - exit \n"); ++ return 0; ++ ++clmap: ++ fb_dealloc_cmap(&info->cmap); ++ ++fbuff: ++ framebuffer_release(info); ++ return ret; ++} ++ ++static int ep93xxfb_remove(struct platform_device *device) ++{ ++ struct resource *res; ++ struct fb_info *info; ++ ++ DPRINTK("ep93xxfb_remove - enter \n"); ++ ++ info = platform_get_drvdata(device); ++ ++ ep93xxfb_release_videomem(); ++ ++ res = platform_get_resource( device, IORESOURCE_MEM, 0); ++ release_mem_region(res->start, res->end - res->start + 1); ++ ++ platform_set_drvdata(device, NULL); ++ unregister_framebuffer(info); ++ ++ fb_dealloc_cmap(&info->cmap); ++ framebuffer_release(info); ++ ++ ep93xxfb_blank( 1, info ); ++ ++ DPRINTK("ep93xxfb_remove - exit \n"); ++ return 0; ++} ++ ++static void ep93xxfb_platform_release(struct device *device) ++{ ++ DPRINTK("ep93xxfb_platform_release - enter\n"); ++} ++ ++ ++static struct platform_driver ep93xxfb_driver = { ++ .probe = ep93xxfb_probe, ++ .remove = ep93xxfb_remove, ++ .driver = { ++ .name = FBDEV_NAME, ++ }, ++}; ++ ++static struct platform_device ep93xxfb_device = { ++ .name = FBDEV_NAME, ++ .id = -1, ++ .dev = { ++ .release = ep93xxfb_platform_release, ++ }, ++ .num_resources = 1, ++ .resource = &ep93xxfb_raster_resources, ++}; ++ ++int __init ep93xxfb_init(void) ++{ ++ int ret = 0; ++ ++ DPRINTK("ep93xxfb_init - enter\n"); ++ ++ ret = platform_driver_register(&ep93xxfb_driver); ++ ++ if (!ret) { ++ ret = platform_device_register(&ep93xxfb_device); ++ if (ret) ++ platform_driver_unregister(&ep93xxfb_driver); ++ } ++ DPRINTK("ep93xxfb_init - exit\n"); ++ return ret; ++} ++ ++static void __exit ep93xxfb_exit(void) ++{ ++ DPRINTK("ep93xxfb_exit - enter\n"); ++ platform_driver_unregister(&ep93xxfb_driver); ++ platform_device_unregister(&ep93xxfb_device); ++ DPRINTK("ep93xxfb_exit - exit\n"); ++} ++ ++#else // LINUX_VERSION_CODE ++ ++ ++int ep93xxfb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, ++ struct fb_info *info) ++{ ++ return 0; ++} ++static struct fb_ops ep93xxfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_setcolreg = ep93xxfb_setcolreg, ++ .fb_check_var = ep93xxfb_check_var, ++ .fb_set_par = ep93xxfb_set_par, ++ .fb_blank = ep93xxfb_blank, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = ep93xx_imageblit, ++ .fb_cursor = soft_cursor, ++}; ++ ++static int __init ep93xxfb_probe(struct device *device) ++{ ++ struct platform_device *pdev = to_platform_device(device); ++ struct fb_info *info = NULL; ++ struct resource *res = NULL; ++ int ret = 0; ++ int arb = 0; ++ ++ DPRINTK("ep93xxfb_probe - enter \n"); ++ ++ ++ if(!device) { ++ printk("error : to_platform_device\n"); ++ return -ENODEV; ++ } ++ res = platform_get_resource( pdev, IORESOURCE_MEM, 0); ++ if(!res) { ++ printk("error : platform_get_resource \n"); ++ return -ENODEV; ++ } ++ if (!request_mem_region(res->start,res->end - res->start + 1, FBDEV_NAME )) ++ return -EBUSY; ++ ++ info = framebuffer_alloc(sizeof(u32) * 256, &pdev->dev); ++ ++ if(!info) { ++ printk("Unable to allocate memory for frame buffer\n"); ++ return -ENOMEM; ++ } ++ ++ info->flags = FBINFO_DEFAULT; ++ strncpy(info->fix.id, FBDEV_NAME, sizeof(info->fix.id)); ++ info->fix.mmio_start = res->start; ++ info->fix.mmio_len = res->end - res->start + 1; ++ info->fbops = &ep93xxfb_ops; ++ info->pseudo_palette = info->par; ++ info->state = FBINFO_STATE_RUNNING; ++ ++ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { ++ ret = -ENOMEM; ++ goto fbuff; ++ } ++ ++ if ((ret = ep93xxfb_config(info)) < 0) ++ goto clmap; ++ ++ if (register_framebuffer(info) < 0) { ++ printk(KERN_ERR "Unable to register ep93xxfb frame buffer\n"); ++ ret = -EINVAL; ++ goto clmap; ++ } ++ dev_set_drvdata(device, info); ++ printk(KERN_INFO "fb%d: EP93xx frame buffer at %dx%dx%dbpp\n", info->node, ++ info->var.xres, info->var.yres, info->var.bits_per_pixel); ++ ++ /*change the raster arb to the highest one--Bo*/ ++ arb = inl(EP93XX_SYSCON_BMAR); ++ arb = (arb & 0x3f8) | 0x01; ++ ep93xxfb_outl(arb,EP93XX_SYSCON_BMAR); ++ ++ DPRINTK("ep93xxfb_probe - exit \n"); ++ return 0; ++ ++clmap: ++ fb_dealloc_cmap(&info->cmap); ++ ++fbuff: ++ framebuffer_release(info); ++ return ret; ++} ++ ++static int ep93xxfb_remove(struct device *device) ++{ ++ struct platform_device *pdev = to_platform_device(device); ++ struct resource *res; ++ struct fb_info *info; ++ ++ DPRINTK("ep93xxfb_remove - enter \n"); ++ ++ info = dev_get_drvdata(device); ++ ++ ep93xxfb_release_videomem(); ++ ++ res = platform_get_resource( pdev, IORESOURCE_MEM, 0); ++ release_mem_region(res->start, res->end - res->start + 1); ++ ++ dev_set_drvdata(device, NULL); ++ unregister_framebuffer(info); ++ ++ fb_dealloc_cmap(&info->cmap); ++ framebuffer_release(info); ++ ++ ep93xxfb_blank( 1, info ); ++ ++ DPRINTK("ep93xxfb_remove - exit \n"); ++ return 0; ++} ++static struct device_driver ep93xxfb_driver = { ++ .name = FBDEV_NAME, ++ .bus = &platform_bus_type, ++ .probe = ep93xxfb_probe, ++ .remove = ep93xxfb_remove, ++}; ++int __init ep93xxfb_init(void) ++{ ++ DPRINTK("ep93xxfb_init\n"); ++ return driver_register(&ep93xxfb_driver); ++} ++ ++static void __exit ep93xxfb_exit(void) ++{ ++ DPRINTK("ep93xxfb_exit\n"); ++ return driver_unregister(&ep93xxfb_driver); ++} ++ ++int __init ep93xxfb_setup(char *options) ++{ ++ DPRINTK("ep93xxfb_setup\n"); ++ return 0; ++} ++ ++#endif // LINUX_VERSION_CODE ++ ++ ++module_init(ep93xxfb_init); ++module_exit(ep93xxfb_exit); ++MODULE_AUTHOR("John Zheng <yujiang.zheng@cirrus.com>"); ++MODULE_LICENSE("GPL"); ++ +--- a/arch/arm/mach-ep93xx/include/mach/hardware.h ++++ b/arch/arm/mach-ep93xx/include/mach/hardware.h +@@ -7,6 +7,7 @@ + #include "ep93xx-regs.h" + + #define pcibios_assign_all_busses() 0 ++#include "regs_raster.h" + #include "regs_touch.h" + + #include "platform.h" +--- a/arch/arm/mach-ep93xx/include/mach/irqs.h ++++ b/arch/arm/mach-ep93xx/include/mach/irqs.h +@@ -34,7 +34,8 @@ + #define IRQ_EP93XX_UART3TX 28 + #define IRQ_EP93XX_KEY 29 + #define IRQ_EP93XX_TOUCH 30 +-#define EP93XX_VIC1_VALID_IRQ_MASK 0x7ffffffc ++#define IRQ_EP93XX_GRAPHICS 31 ++#define EP93XX_VIC1_VALID_IRQ_MASK 0xfffffffc + + #define IRQ_EP93XX_EXT0 32 + #define IRQ_EP93XX_EXT1 33 +--- /dev/null ++++ b/arch/arm/mach-ep93xx/include/mach/regs_raster.h +@@ -0,0 +1,347 @@ ++/*============================================================================= ++ * ++ * FILE: regs_raster.h ++ * ++ * DESCRIPTION: ep93xx Raster Engine Register Definition ++ * ++ * Copyright Cirrus Logic, 2001-2003 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ *============================================================================= ++ */ ++#ifndef _REGS_RASTER_H_ ++#define _REGS_RASTER_H_ ++ ++//----------------------------------------------------------------------------- ++// VLINESTOTAL Register Definitions ++//----------------------------------------------------------------------------- ++#define VLINESTOTAL_MASK 0x000007ff ++ ++//----------------------------------------------------------------------------- ++// VSYNCSTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define VSYNCSTRTSTOP_STRT_MASK 0x07ff0000 ++#define VSYNCSTRTSTOP_STRT_SHIFT 0 ++#define VSYNCSTRTSTOP_STOP_MASK 0x000007ff ++#define VSYNCSTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// VACTIVESTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define VACTIVESTRTSTOP_STRT_MASK 0x07ff0000 ++#define VACTIVESTRTSTOP_STRT_SHIFT 0 ++#define VACTIVESTRTSTOP_STOP_MASK 0x000007ff ++#define VACTIVESTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// VCLKSTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define VCLKSTRTSTOP_STRT_MASK 0x07ff0000 ++#define VCLKSTRTSTOP_STRT_SHIFT 0 ++#define VCLKSTRTSTOP_STOP_MASK 0x000007ff ++#define VCLKSTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// VBLANKSTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define VBLANKSTRTSTOP_STRT_MASK 0x07ff0000 ++#define VBLANKSTRTSTOP_STRT_SHIFT 0 ++#define VBLANKSTRTSTOP_STOP_MASK 0x000007ff ++#define VBLANKSTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// HSYNCSTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define HSYNCSTRTSTOP_STRT_MASK 0x07ff0000 ++#define HSYNCSTRTSTOP_STRT_SHIFT 0 ++#define HSYNCSTRTSTOP_STOP_MASK 0x000007ff ++#define HSYNCSTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// HACTIVESTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define HACTIVESTRTSTOP_STRT_MASK 0x07ff0000 ++#define HACTIVESTRTSTOP_STRT_SHIFT 0 ++#define HACTIVESTRTSTOP_STOP_MASK 0x000007ff ++#define HACTIVESTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// HCLKSTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define HCLKSTRTSTOP_STRT_MASK 0x07ff0000 ++#define HCLKSTRTSTOP_STRT_SHIFT 0 ++#define HCLKSTRTSTOP_STOP_MASK 0x000007ff ++#define HCLKSTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// BRIGHTNESS Register Definitions ++//----------------------------------------------------------------------------- ++#define BRIGHTNESS_MASK 0x0000ffff ++#define BRIGHTNESS_CNT_MASK 0x000000ff ++#define BRIGHTNESS_CNT_SHIFT 0 ++#define BRIGHTNESS_CMP_MASK 0x0000ff00 ++#define BRIGHTNESS_CMP_SHIFT 8 ++ ++//----------------------------------------------------------------------------- ++// VIDEOATTRIBS Register Definitions ++//----------------------------------------------------------------------------- ++#define VIDEOATTRIBS_MASK 0x001fffff ++#define VIDEOATTRIBS_EN 0x00000001 ++#define VIDEOATTRIBS_PCLKEN 0x00000002 ++#define VIDEOATTRIBS_SYNCEN 0x00000004 ++#define VIDEOATTRIBS_DATAEN 0x00000008 ++#define VIDEOATTRIBS_CSYNC 0x00000010 ++#define VIDEOATTRIBS_VCPOL 0x00000020 ++#define VIDEOATTRIBS_HSPOL 0x00000040 ++#define VIDEOATTRIBS_BLKPOL 0x00000080 ++#define VIDEOATTRIBS_INVCLK 0x00000100 ++#define VIDEOATTRIBS_ACEN 0x00000200 ++#define VIDEOATTRIBS_LCDEN 0x00000400 ++#define VIDEOATTRIBS_CCIREN 0x00001000 ++#define VIDEOATTRIBS_PIFEN 0x00002000 ++#define VIDEOATTRIBS_INTEN 0x00004000 ++#define VIDEOATTRIBS_INT 0x00008000 ++#define VIDEOATTRIBS_INTRLC 0x00010000 ++#define VIDEOATTRIBS_EQUSER 0x00020000 ++#define VIDEOATTRIBS_DHORZ 0x00040000 ++#define VIDEOATTRIBS_DVERT 0x00080000 ++#define VIDEOATTRIBS_BKPXD 0x00100000 ++ ++#define VIDEOATTRIBS_SDSEL_MASK 0x00600000 ++#define VIDEOATTRIBS_SDSEL_SHIFT 21 ++ ++//----------------------------------------------------------------------------- ++// HBLANKSTRTSTOP Register Definitions ++//----------------------------------------------------------------------------- ++#define HBLANKSTRTSTOP_STRT_MASK 0x07ff0000 ++#define HBLANKSTRTSTOP_STRT_SHIFT 0 ++#define HBLANKSTRTSTOP_STOP_MASK 0x000007ff ++#define HBLANKSTRTSTOP_STOP_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// LINECARRY Register Definitions ++//----------------------------------------------------------------------------- ++#define LINECARRY_LCARY_MASK 0x000007ff ++#define LINECARRY_LCARY_SHIFT 0 ++ ++//----------------------------------------------------------------------------- ++// BLINKRATE Register Definitons ++//----------------------------------------------------------------------------- ++#define BLINKRATE_MASK 0x000000ff ++ ++//----------------------------------------------------------------------------- ++// BLINKMASK Register Definitons ++//----------------------------------------------------------------------------- ++#define BLINKMASK_MASK 0x00ffffff ++ ++//----------------------------------------------------------------------------- ++// VIDSCRNPAGE Register Definitons ++//----------------------------------------------------------------------------- ++#define VIDSCRNPAGE_PAGE_MASK 0x0ffffffc ++ ++//----------------------------------------------------------------------------- ++// VIDSCRNHPG Register Definitons ++//----------------------------------------------------------------------------- ++#define VIDSCRNHPG_MASK 0x0ffffffc ++ ++//----------------------------------------------------------------------------- ++// SCRNLINES Register Definitons ++//----------------------------------------------------------------------------- ++#define SCRNLINES_MASK 0x000007ff ++ ++//----------------------------------------------------------------------------- ++// LINELENGTH Register Definitons ++//----------------------------------------------------------------------------- ++#define LINELENGTH_MASK 0x000007ff ++ ++//----------------------------------------------------------------------------- ++// VLINESTEP Register Definitons ++//----------------------------------------------------------------------------- ++#define VLINESTEP_MASK 0x00000fff ++ ++//----------------------------------------------------------------------------- ++// RASTER_SWLOCK Register Definitons ++//----------------------------------------------------------------------------- ++#define RASTER_SWLOCK_MASK_WR 0xff ++#define RASTER_SWLOCK_MASK_R 0x1 ++#define RASTER_SWLOCK_VALUE 0xaa ++ ++//----------------------------------------------------------------------------- ++// LUTCONT Register Definitions ++//----------------------------------------------------------------------------- ++#define LUTCONT_MASK 0x00000003 ++#define LUTCONT_SWTCH 0x00000001 ++#define LUTCONT_STAT 0x00000002 ++#define LUTCONT_RAM0 0 ++#define LUTCONT_RAM1 1 ++ ++//----------------------------------------------------------------------------- ++// CURSORBLINK1 Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSORBLINK1_MASK 0x00ffffff ++//----------------------------------------------------------------------------- ++// CURSORBLINK2 Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSORBLINK2_MASK 0x00ffffff ++ ++//----------------------------------------------------------------------------- ++// CURSORBLINK Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSORBLINK_MASK 0x000001ff ++#define CURSORBLINK_RATE_MASK 0x000000ff ++#define CURSORBLINK_RATE_SHIFT 0 ++#define CURSORBLINK_EN 0x00000100 ++ ++//----------------------------------------------------------------------------- ++// BLINKPATRN Register Definitions ++//----------------------------------------------------------------------------- ++#define BLINKPATRN_MASK 0x00ffffff ++ ++//----------------------------------------------------------------------------- ++// PATRNMASK Register Definitions ++//----------------------------------------------------------------------------- ++#define PATRNMASK_MASK 0x00ffffff ++ ++//----------------------------------------------------------------------------- ++// BG_OFFSET Register Definitions ++//----------------------------------------------------------------------------- ++#define BG_OFFSET_MASK 0x00ffffff ++ ++//----------------------------------------------------------------------------- ++// PIXELMODE Register Definitions ++//----------------------------------------------------------------------------- ++#define PIXELMODE_P_MASK 0x00000007 ++#define PIXELMODE_P_MUX_DISABLE 0x00000000 ++#define PIXELMODE_P_4BPP 0x00000001 ++#define PIXELMODE_P_8BPP 0x00000002 ++#define PIXELMODE_P_16BPP 0x00000004 ++#define PIXELMODE_P_24BPP 0x00000006 ++#define PIXELMODE_P_32BPP 0x00000007 ++ ++#define PIXELMODE_S_MASK 0x00000038 ++#define PIXELMODE_S_1PPC 0x00000000 ++#define PIXELMODE_S_1PPCMAPPED 0x00000008 ++#define PIXELMODE_S_2PPC 0x00000010 ++#define PIXELMODE_S_4PPC 0x00000018 ++#define PIXELMODE_S_8PPC 0x00000020 ++#define PIXELMODE_S_223PPC 0x00000028 ++#define PIXELMODE_S_DS223PPC 0x00000030 ++#define PIXELMODE_S_UNDEF 0x00000038 ++ ++#define PIXELMODE_M_MASK 0x000003c0 ++#define PIXELMODE_M_NOBLINK 0x00000000 ++#define PIXELMODE_M_ANDBLINK 0x00000040 ++#define PIXELMODE_M_ORBLINK 0x00000080 ++#define PIXELMODE_M_XORBLINK 0x000000c0 ++#define PIXELMODE_M_BGBLINK 0x00000100 ++#define PIXELMODE_M_OFFSINGBLINK 0x00000140 ++#define PIXELMODE_M_OFF888BLINK 0x00000180 ++#define PIXELMODE_M_DIMBLINK 0x00000300 ++#define PIXELMODE_M_BRTBLINK 0x00000340 ++#define PIXELMODE_M_DIM888BLINK 0x00000380 ++#define PIXELMODE_M_BRT888BLINK 0x000003c0 ++ ++#define PIXELMODE_C_MASK 0x00003c00 ++#define PIXELMODE_C_LUT 0x00000000 ++#define PIXELMODE_C_888 0x00001000 ++#define PIXELMODE_C_565 0x00001400 ++#define PIXELMODE_C_555 0x00001800 ++#define PIXELMODE_C_GSLUT 0x00002000 ++ ++#define PIXELMODE_DSCAN 0x00004000 ++#define PIXELMODE_TRBSW 0x00008000 ++ ++//----------------------------------------------------------------------------- ++//PARLLIFOUT Register Defintions ++//----------------------------------------------------------------------------- ++#define PARLLIFOUT_DAT_MASK 0x0000000f ++#define PARLLIFOUT_DAT_SHIFT 0 ++#define PARLLIFOUT_RD 0x00000010 ++ ++//----------------------------------------------------------------------------- ++//PARLLIFIN Register Defintions ++//----------------------------------------------------------------------------- ++#define PARLLIFIN_DAT_MASK 0x0000000f ++#define PARLLIFIN_DAT_SHIFT 0 ++#define PARLLIFIN_CNT_MASK 0x000f0000 ++#define PARLLIFIN_CNT_SHIFT 16 ++#define PARLLIFIN_ESTRT_MASK 0x00f00000 ++#define PARLLIFIN_ESTRT_SHIFT 20 ++ ++//----------------------------------------------------------------------------- ++// CURSORADRSTART Register Defintions ++//----------------------------------------------------------------------------- ++#define CURSOR_ADR_START_MASK 0xfffffffc ++ ++//----------------------------------------------------------------------------- ++// CURSORADRSTART Register Defintions ++//----------------------------------------------------------------------------- ++#define CURSOR_ADR_RESET_MASK 0xfffffffc ++ ++//----------------------------------------------------------------------------- ++// CURSORCOLOR1 Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSORCOLOR1_MASK 0x00ffffff ++//----------------------------------------------------------------------------- ++// CURSORCOLOR2 Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSORCOLOR2_MASK 0x00ffffff ++ ++//----------------------------------------------------------------------------- ++// CURSORXYLOC Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSORXYLOC_MASK 0x07ff87ff ++#define CURSORXYLOC_XLOC_MASK 0x000007ff ++#define CURSORXYLOC_XLOC_SHIFT 0 ++#define CURSORXYLOC_CEN 0x00008000 ++#define CURSORXYLOC_YLOC_MASK 0x07ff0000 ++#define CURSORXYLOC_YLOC_SHIFT 16 ++ ++//----------------------------------------------------------------------------- ++// CURSOR_DSCAN_LH_YLOC Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSOR_DSCAN_LH_YLOC_MASK 0x000087ff ++ ++#define CURSOR_DSCAN_LH_YLOC_YLOC_MASK 0x000007ff ++#define CURSOR_DSCAN_LH_YLOC_YLOC_SHIFT 0 ++#define CURSOR_DSCAN_LH_YLOC_CLHEN 0x00008000 ++ ++//----------------------------------------------------------------------------- ++// CURSORSIZE Register Definitions ++//----------------------------------------------------------------------------- ++#define CURSORSIZE_MASK 0x0000ffff ++ ++#define CURSORSIZE_CWID_MASK 0x00000003 ++#define CURSORSIZE_CWID_SHIFT 0 ++#define CURSORSIZE_CWID_1_WORD 0 ++#define CURSORSIZE_CWID_2_WORD 1 ++#define CURSORSIZE_CWID_3_WORD 2 ++#define CURSORSIZE_CWID_4_WORD 3 ++ ++#define CURSORSIZE_CLINS_MASK 0x000000fc ++#define CURSORSIZE_CLINS_SHIFT 2 ++ ++#define CURSORSIZE_CSTEP_MASK 0x00000300 ++#define CURSORSIZE_CSTEP_SHIFT 8 ++#define CURSORSIZE_CSTEP_1_WORD 0 ++#define CURSORSIZE_CSTEP_2_WORD 1 ++#define CURSORSIZE_CSTEP_3_WORD 2 ++#define CURSORSIZE_CSTEP_4_WORD 3 ++ ++#define CURSORSIZE_DLNS_MASK 0x0000fc00 ++#define CURSORSIZE_DLNS_SHIFT 10 ++ ++#endif /* _REGS_RASTER_H_ */ |