Hi, Attached you will find a patch implementing a Linux framebuffer driver for the Xilinx TFT interface. It was tested on a Xilinx Virtex2Pro implementation.
Comments welcome, Peter. -------------- next part -------------- diff -urN -x CVS -x config -x modules -x mtd -x jffs2 -x jffs linuxppc_2_4_clean/drivers/video/Config.in linuxppc_2_4_xseg2.new.clean2/drivers/video/Config.in --- linuxppc_2_4_clean/drivers/video/Config.in 2002-07-20 12:03:22.000000000 +0200 +++ linuxppc_2_4_xseg2.new.clean2/drivers/video/Config.in 2002-09-01 17:10:29.000000000 +0200 @@ -216,6 +216,10 @@ if [ "$CONFIG_NINO" = "y" ]; then bool ' TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912 fi + + if [ "$CONFIG_XSEG2" = "y" ]; then + bool ' Xilinx TFT core framebuffer support' CONFIG_FB_XILINX_TFT + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL fi @@ -377,7 +381,8 @@ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \ "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \ - "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then + "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ + "$CONFIG_FB_XILINX_TFT" = "y" ]; then define_tristate CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ diff -urN -x CVS -x config -x modules -x mtd -x jffs2 -x jffs linuxppc_2_4_clean/drivers/video/Makefile linuxppc_2_4_xseg2.new.clean2/drivers/video/Makefile --- linuxppc_2_4_clean/drivers/video/Makefile 2002-07-20 12:03:24.000000000 +0200 +++ linuxppc_2_4_xseg2.new.clean2/drivers/video/Makefile 2002-09-01 16:33:47.000000000 +0200 @@ -89,7 +89,7 @@ obj-$(CONFIG_FB_MAXINE) += maxinefb.o obj-$(CONFIG_FB_TX3912) += tx3912fb.o obj-$(CONFIG_FB_RPX) += rpxfb.o - +obj-$(CONFIG_FB_XILINX_TFT) += xilinx_tft.o subdir-$(CONFIG_FB_MATROX) += matrox ifeq ($(CONFIG_FB_MATROX),y) diff -urN -x CVS -x config -x modules -x mtd -x jffs2 -x jffs linuxppc_2_4_clean/drivers/video/fbmem.c linuxppc_2_4_xseg2.new.clean2/drivers/video/fbmem.c --- linuxppc_2_4_clean/drivers/video/fbmem.c 2002-07-20 12:03:53.000000000 +0200 +++ linuxppc_2_4_xseg2.new.clean2/drivers/video/fbmem.c 2002-09-04 21:24:39.000000000 +0200 @@ -136,6 +136,7 @@ extern int pvr2fb_setup(char*); extern int sstfb_init(void); extern int sstfb_setup(char*); +extern int xtftfb_init(void); static struct { const char *name; @@ -227,6 +228,10 @@ #ifdef CONFIG_FB_VOODOO1 { "sst", sstfb_init, sstfb_setup }, #endif +#ifdef CONFIG_FB_XILINX_TFT + { "xilinxtft", xtftfb_init, NULL }, +#endif + /* * Generic drivers that are used as fallbacks diff -urN -x CVS -x config -x modules -x mtd -x jffs2 -x jffs linuxppc_2_4_clean/drivers/video/xilinx_tft.c linuxppc_2_4_xseg2.new.clean2/drivers/video/xilinx_tft.c --- linuxppc_2_4_clean/drivers/video/xilinx_tft.c 1970-01-01 01:00:00.000000000 +0100 +++ linuxppc_2_4_xseg2.new.clean2/drivers/video/xilinx_tft.c 2002-09-04 20:43:45.000000000 +0200 @@ -0,0 +1,286 @@ +/* + * xilinx_tft.c: A driver for Xilinx TFT screen interface core + * + * Copyright 2002 Mind NV + * + * http://www.mind.be/ + * + * Author : Peter De Schrijver (p2 at mind.be) + * + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL) version 2, incorporated herein by + * reference. Drivers based on or derived from this code fall under the GPL + * and must retain the authorship, copyright and this license notice. This + * file is not a complete program and may only be used when the entire + * operating system is licensed under the GPL. + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <asm/uaccess.h> +#include <asm/setup.h> +#include <asm/segment.h> +#include <asm/system.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <asm/pgtable.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb32.h> + +#define TFT_FB_PHYS_ADDR 0x30000000 +#define TFT_BASE_ADDR (0xE0020000 + 0x80 * 4) +#define TFT_CFG (0xE0020000 + 0x81 * 4) + +static int xtftfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); +static int xtftfb_get_var(struct fb_var_screeninfo *var, int con,struct fb_info *info); +static int xtftfb_set_var(struct fb_var_screeninfo *var, int con,struct fb_info *info); +static int xtftfb_get_cmap(struct fb_cmap *cmap,int kspc,int con,struct fb_info *info); +static int xtftfb_set_cmap(struct fb_cmap *cmap,int kspc,int con,struct fb_info *info); + + + +static int currcon = 0; + +static struct fb_ops xtftfb_ops = { + owner: THIS_MODULE, + fb_get_fix: xtftfb_get_fix, + fb_get_var: xtftfb_get_var, + fb_set_var: xtftfb_set_var, + fb_get_cmap: xtftfb_get_cmap, + fb_set_cmap: xtftfb_set_cmap, +}; + +static struct fb_var_screeninfo xtft_default_var = { + xres: 640, + yres: 480, + xres_virtual: 1024, + yres_virtual: 480, + xoffset: 0, + yoffset: 0, + bits_per_pixel: 32, + grayscale: 0, + transp: {24, 8, 0}, + red: {16, 8, 0}, + green: {8, 8, 0}, + blue: {0, 8, 0}, + nonstd: 0, + activate: 0, + height: -1, + width: -1, + accel_flags: 0, +}; + +static struct fb_fix_screeninfo xtft_fix = { + id: "XilinxTFT", + type: FB_TYPE_PACKED_PIXELS, + visual: FB_VISUAL_TRUECOLOR, + line_length: 4096, + accel: FB_ACCEL_NONE +}; + +static struct fb_info fb_info; +static struct display disp; + +static int xtftfb_getcolreg(unsigned regno, + unsigned *red, + unsigned *green, + unsigned *blue, + unsigned *transp, + struct fb_info *fb) { + + if (regno > 256) return 1; + + *transp=((unsigned int *)(fb->disp->dispsw_data))[regno]>> + fb->var.transp.offset; + *red=((unsigned int *)(fb->disp->dispsw_data))[regno] + >>fb->var.red.offset & (~(1<<fb->var.red.offset)); + *green=((unsigned int *)(fb->disp->dispsw_data))[regno] + >>fb->var.green.offset & (~(1<<fb->var.green.offset)); + *blue=((unsigned int *)(fb->disp->dispsw_data))[regno] + >>fb->var.blue.offset & (~(1<<fb->var.blue.offset)); + + return 0; +} + +static int xtftfb_setcolreg(unsigned regno, + unsigned red, + unsigned green, + unsigned blue, + unsigned transp, + struct fb_info *fb) { + + if (regno > 256) return 1; + + ((unsigned int *)fb->disp->dispsw_data)[regno]= + (transp << fb->var.transp.offset) + | (red << fb->var.red.offset) + | (green << fb->var.green.offset) + | (blue << fb->var.blue.offset); + return 0; +} + +static int xtftfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { + + *fix=info->fix; + + return 0; + +} + +static int xtftfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { + + *var = info->var; + + return 0; + +} + +static int xtftfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { + + struct display *disp; + + if(con >= 0) + disp = &fb_display[con]; + else + disp = info->disp; + + if(var->xres != 640 || var->yres != 480 || + var->xres_virtual != 1024 || + var->yres_virtual != 480 || + var->bits_per_pixel != 32 || var->grayscale != 0) { + return -EINVAL; + } + + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + info->var = *var; + if (info->changevar) + (*info->changevar)(con); + } + return 0; +} + +static int xtftfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb) { + + struct display *d=(con<0) ? fb->disp : fb_display + con; + + if(con == currcon) { + return fb_get_cmap(cmap, kspc, xtftfb_getcolreg, fb); + } else if(d->cmap.len) { + fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2); + } else { + fb_copy_cmap(fb_default_cmap(256), cmap, kspc ? 0 : 2); + } + + return 0; + +} + +static int xtftfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb) { + + struct display *d=(con<0) ? fb->disp : fb_display + con; + + if(con == currcon) { + return fb_set_cmap(cmap, kspc, xtftfb_setcolreg, fb); + } else { + fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1); + } + + return 0; + +} + +static int xtftfbcon_switch(int con, struct fb_info *info) { + + + if(currcon != -1) + memcpy(&fb_display[currcon].var, &info->var, sizeof(struct fb_var_screeninfo)); + + memcpy(&info->var, &fb_display[con].var,sizeof(struct fb_var_screeninfo)); + + + currcon = con; + + return 0; + +} + +static int xtftfbcon_updatevar(int con, struct fb_info *info) { + + return (con < 0) ? -EINVAL : 0; + +} + +static void xtftfbcon_blank(int blank_mode, struct fb_info *info) { + + return ; + +} + +int __init xtftfb_init(void) { + + *(unsigned int *)TFT_BASE_ADDR=TFT_FB_PHYS_ADDR; + + xtft_fix.smem_start=ioremap(TFT_FB_PHYS_ADDR, 1024*480*4); + xtft_fix.smem_len=1024*480*4; + + disp.var=xtft_default_var; + disp.screen_base=(char *)xtft_fix.smem_start; + + disp.visual = xtft_fix.visual; + disp.type = xtft_fix.type; + disp.type_aux = xtft_fix.type_aux; + disp.ypanstep = xtft_fix.ypanstep; + disp.ywrapstep = xtft_fix.ywrapstep; + disp.line_length = xtft_fix.line_length; + disp.can_soft_blank = 0; + disp.inverse = 0; + + disp.dispsw = &fbcon_cfb32; + disp.dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL); + if(disp.dispsw_data == NULL) + return -1; + memset(disp.dispsw_data, 0, 16 * sizeof(u32)); + + *(unsigned int *)TFT_CFG=0x1; + + disp.scrollmode = SCROLL_YREDRAW; + + strcpy (fb_info.modename, xtft_fix.id); + fb_info.node = -1; + fb_info.flags = FBINFO_FLAG_DEFAULT; + + fb_info.var = xtft_default_var; + fb_info.fix = xtft_fix; + + fb_info.fbops = &xtftfb_ops; + + fb_info.screen_base = (char *)xtft_fix.smem_start; + fb_info.disp = &disp; + fb_info.changevar = NULL; + fb_info.switch_con = xtftfbcon_switch; + fb_info.updatevar = xtftfbcon_updatevar; + fb_info.blank = xtftfbcon_blank; + fb_info.pseudo_palette = NULL; /* ??? */ + fb_info.par = NULL; + + if(register_framebuffer(&fb_info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + GET_FB_IDX(fb_info.node), fb_info.modename); + + return 0; + +} + +