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;
+
+}
+
+

Reply via email to