]> git.neil.brown.name Git - history.git/commitdiff
Import 2.2.12pre5 2.2.12pre5
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:19:29 +0000 (15:19 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:19:29 +0000 (15:19 -0500)
18 files changed:
CREDITS
Documentation/Configure.help
Documentation/sysrq.txt
MAINTAINERS
arch/ppc/kernel/head.S
arch/ppc/kernel/pci.c
arch/ppc/kernel/ppc-stub.c
arch/ppc/kernel/process.c
arch/ppc/kernel/prom.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/syscalls.c
drivers/video/Config.in
drivers/video/Makefile
drivers/video/fbcon.c
drivers/video/font_6x11.c
drivers/video/sgivwfb.c
drivers/video/sgivwfb.h
net/ipv6/ip6_input.c

diff --git a/CREDITS b/CREDITS
index 126812378c55ca8a70c1c7989fe5d353c35ff2b2..91045d6a4f41118d557098aa7c1516fc7bcaf606 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1570,6 +1570,13 @@ S: Demonstratsii 8-382
 S: Tula 300000
 S: Russia
 
+N: Johnnie Peters
+E: jpeters@phx.mcd.mot.com
+D: Motorola PowerPC changes for PReP
+S: 2900 S. Diable Way
+S: Tempe, Arizona 85282
+S: USA
+
 N: Kirk Petersen
 E: kirk@speakeasy.org
 W: http://www.speakeasy.org/~kirk/
index d2ae9cacb1e5f5096cf248e186d091972465ec69..0707cacf2cb06e3500e6730c1c4def8a161b488a 100644 (file)
@@ -5874,6 +5874,25 @@ CONFIG_YELLOWFIN
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called yellowfin.o.
 
+General Instruments Surfboard 1000
+CONFIG_NET_SB1000
+  This is a driver for the General Instrument SURFboard 1000 internal cable
+  modem.  This is an ISA card which is used by a number of cable TV companies
+  to provide cable modem access.  It's a one-way downstream-only cable modem,
+  meaning that your upstream net link is provided by your regular phone modem.
+
+  At present this driver only compiles as a module, so say M here if you
+  have this card.  Then read Documentation/networking/README.sb1000 for
+  information on how to use this module, as it needs special ppp scripts for
+  establishing a connection.  Further documentation and the necessary scripts
+  can be found at:
+
+  http://www.jacksonville.net/~fventuri/
+  http://home.adelphia.net/~siglercm/sb1000.html
+  http://linuxpower.cx/~cable/
+
+  If you don't have this card, of course say N.
+
 Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
   Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
index ab8676fafe505af14e2427b38a793e63f2af2236..ed6b35f41e962419a64febac02c84503202d8a3f 100644 (file)
@@ -21,6 +21,8 @@ On x86   - You press the key combo 'ALT-SysRQ-<command key>'. Note - Some
 
 On SPARC - You press 'ALT-STOP-<command key>', I believe.
 
+On PowerPC - You press 'ALT-Print Screen-<command key>'.
+
 On other - If you know of the key combos for other architectures, please
            let me know so I can add them to this section. 
 
index d9b201db098566599fb368f7872a619ac8a99a35..99ffcebfd7a4ec3a6a54558d474b46ee358b8ff9 100644 (file)
@@ -175,6 +175,16 @@ M: jgarzik@pobox.com
 L:     linux-fbdev@vuser.vu.union.edu
 S:     Maintained
 
+COMPUTONE INTELLIPORT MULTIPORT CARD
+P:     Doug McNash
+P:     Michael H. Warfield
+M:     Doug McNash <dmcnash@computone.com>
+M:     Michael H. Warfield <mhw@wittsend.com>
+W:     http://www.computone.com/
+W:     http://www.wittsend.com/computone.html
+L:     linux-computone@lazuli.wittsend.com
+S:     Supported
+
 CONFIGURE, MENUCONFIG, XCONFIG
 P:     Michael Elizabeth Chastain
 M:     mec@shout.net
index 2dd18ea29d29d9131daff74e4c08a3c6c6954318..b5c1e9328730ba28eea59d8f5ba987bb694654a4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.130.2.2 1999/06/30 04:53:21 paulus Exp $
+ *  $Id: head.S,v 1.130.2.3 1999/08/10 21:36:48 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -433,16 +433,7 @@ __secondary_start:
  * ready to work.
  */
 #endif /* CONFIG_8xx */
-
-turn_on_mmu:
-       mfmsr   r0
-       ori     r0,r0,MSR_DR|MSR_IR
-       mtspr   SRR1,r0
-       lis     r0,start_here@h
-       ori     r0,r0,start_here@l
-       mtspr   SRR0,r0
-       SYNC
-       rfi                             /* enables MMU */
+       b       turn_on_mmu
 
 /*
  * GCC sometimes accesses words at negative offsets from the stack
@@ -1729,6 +1720,37 @@ copy_and_flush:
        . = 0x4000
 #endif
 
+turn_on_mmu:
+       mfmsr   r0
+       ori     r1,r0,MSR_DR|MSR_IR
+       mtspr   SRR1,r1
+#ifdef CONFIG_SMP
+       /* see the function start_here_ibm_hack for explanation -- Cort */
+       andi.   0,r1,MSR_DR     /* check if the MMU is already on */
+       bne     10f
+       lis     r5,smp_ibm_chrp_hack@h
+       ori     r5,r5,smp_ibm_chrp_hack@l
+       tophys(r5,r5,r6)
+       lwz     r5,0(r5)
+       cmpi    0,r5,0
+       beq     10f
+       lis     r5,first_cpu_booted@h
+       ori     r5,r5,first_cpu_booted@l
+       tophys(r5,r5,r6)
+       lwz     r5,0(r5)
+       cmpi    0,r5,0
+       beq     10f
+       lis     r0,start_here_ibm_hack@h
+       ori     r0,r0,start_here_ibm_hack@l
+       b       1010f
+10:    
+#endif /* CONFIG_SMP */
+       lis     r0,start_here@h
+       ori     r0,r0,start_here@l
+1010:  mtspr   SRR0,r0
+       SYNC
+       rfi                             /* enables MMU */
+
 #ifdef CONFIG_SMP
        .globl  __secondary_start_psurge
 __secondary_start_psurge:
@@ -1758,11 +1780,27 @@ __secondary_hold:
        blr
 #endif /* CONFIG_SMP */
        
-/*
- * This is where the main kernel code starts.
+/* 
+ * We get _strange_ behavior on the new IBM chrp firmware.
+ * We end up here with the MMU disabled, even though we enable
+ * it with the rfi that takes us here.  Somehow, a physical address
+ * access fixes this by enabling the MMU.
+ *
+ * The IBM engineers can't explain this behavior and AIX doesn't 
+ * seem to find it.  This hack gets around it for now.
+ *          -- Cort
  */
-start_here:
+start_here_ibm_hack:
+       mfmsr   r1
+       lis     r5,smp_ibm_chrp_hack@h
+       ori     r5,r5,smp_ibm_chrp_hack@l
+       tophys(r5,r5,r6)
+       mfmsr   r1
+       stw     r1,_MSR-16(r5)
+       addi    r5,r5,_MSR-16
+       dcbf    0,r5
 #ifndef CONFIG_8xx
+start_here:
        /*
         * Enable caches and 604-specific features if necessary.
         */
index 985abf6e6295a1358abb7ca8c28aa5408734eda5..39b2337fa533819e0ce12cedefea8e4ee56ec61e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $
+ * $Id: pci.c,v 1.54.2.1 1999/07/20 05:04:41 paulus Exp $
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
index d7fef0869b7ae7eb7880f9d1475bf13c990d310a..ac18a8c14e1a9e4c3e9b3d1692d03cad3b6b1cb5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ppc-stub.c,v 1.4 1998/07/28 08:25:01 paulus Exp $
+/* $Id: ppc-stub.c,v 1.4.2.1 1999/07/20 05:04:42 paulus Exp $
  * ppc-stub.c:  KGDB support for the Linux kernel.
  *
  * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
index 1bf375c2910df88772c624bdc1e376c02a779fec..b1d9815d77c3311e32eb47f1fd5f84e6334801a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $
+ * $Id: process.c,v 1.83.2.6 1999/08/10 03:24:06 cort Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
@@ -47,6 +47,7 @@ extern unsigned long _get_SP(void);
 struct task_struct *last_task_used_math = NULL;
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM;
index 582428b80b351869e94f6ac9dda3d88c94a08e07..8b1272443c7a1b1f043eba9c5f492f648801360f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.54.2.5 1999/07/21 20:28:18 cort Exp $
+ * $Id: prom.c,v 1.54.2.6 1999/08/10 21:36:46 cort Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -257,11 +257,12 @@ prom_print(const char *msg)
        }
 }
 
+unsigned long smp_ibm_chrp_hack __initdata = 0;
+
 /*
  * We enter here early on, when the Open Firmware prom is still
  * handling exceptions and the MMU hash table for us.
  */
-unsigned long promi = 0;
 __init
 void
 prom_init(int r3, int r4, prom_entry pp)
@@ -527,6 +528,7 @@ prom_init(int r3, int r4, prom_entry pp)
                /* XXX: hack - don't start cpu 0, this cpu -- Cort */
                if ( cpu++ == 0 )
                        continue;
+               RELOC(smp_ibm_chrp_hack) = 1;
                prom_print(RELOC("starting cpu "));
                prom_print(path);
                *(unsigned long *)(0x4) = 0;
index cd32968b55a74d6c47a6645a6536ea0e97c5bd27..45481b732cc291e4aabbc4ede68dd2ab7f02f421 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.132.2.1 1999/06/03 03:03:45 paulus Exp $
+ * $Id: setup.c,v 1.132.2.2 1999/07/20 05:04:47 paulus Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
index bc0ac5307423deb46ad452418f49a85146d69369..3aa0becef6fba1891e4c6a4655fc8451c3ec0253 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
-#include <linux/file.h>
 #include <linux/sys.h>
 #include <linux/ipc.h>
 #include <linux/utsname.h>
index 06dacf03f4ff01435099a772ea930e94e16d469d..a067290e9d510c3dd8c01c88551085e216fdbd36 100644 (file)
@@ -79,6 +79,7 @@ if [ "$CONFIG_FB" = "y" ]; then
   fi
   if [ "$CONFIG_VISWS" = "y" ]; then
     tristate 'SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
+    define_bool CONFIG_BUS_I2C y
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     if [ "$CONFIG_PCI" != "n" ]; then
index 534d0fed0bf34292e5c679e77d0c7fb2ee6c2386..cbb454e910ea8bf24e849bfd0f6905842fe23b54 100644 (file)
@@ -141,10 +141,10 @@ else
 endif
 
 ifeq ($(CONFIG_FB_SGIVW),y)
-L_OBJS += sgivwfb.o
+LX_OBJS += sgivwfb.o
 else
   ifeq ($(CONFIG_FB_SGIVW),m)
-  M_OBJS += sgivwfb.o
+  MX_OBJS += sgivwfb.o
   endif
 endif
 
index 450ada8a6cd382137cd6155a7367374d74bb4d64..fed7c11b7fbfd5cace696e5111ef316803abc8fb 100644 (file)
@@ -1386,14 +1386,6 @@ static int fbcon_blank(struct vc_data *conp, int blank)
 
     if (!p->can_soft_blank) {
        if (blank) {
-#ifdef CONFIG_MAC
-           if (MACH_IS_MAC) {
-               if (p->screen_base)
-                   mymemset(p->screen_base,
-                            p->var.xres_virtual*p->var.yres_virtual*
-                            p->var.bits_per_pixel>>3);
-           } else
-#endif
            if (p->visual == FB_VISUAL_MONO01) {
                if (p->screen_base)
                    mymemset(p->screen_base,
@@ -2228,12 +2220,13 @@ __initfunc(static int fbcon_show_logo( void ))
                           p->type == FB_TYPE_INTERLEAVED_PLANES)) {
 
            /* monochrome */
-           unsigned char inverse = p->inverse ? 0x00 : 0xff;
+           unsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01
+               ? 0x00 : 0xff;
 
            /* can't use simply memcpy because need to apply inverse */
            for( y1 = 0; y1 < LOGO_H; y1++ ) {
-               src = logo + y1*LOGO_LINE + x/8;
-               dst = fb + y1*line;
+               src = logo + y1*LOGO_LINE;
+               dst = fb + y1*line + x/8;
                for( x1 = 0; x1 < LOGO_LINE; ++x1 )
                    *dst++ = *src++ ^ inverse;
            }
index 362529c2b65706126b42c0cecfe84bc149b7d07d..aa95f8863830063f9713e51855f5036c0147fecf 100644 (file)
@@ -1207,6 +1207,8 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
 
        /* 92 0x5c '\' */
+       0x40, /* 0 000000 */
+       0x40, /* 0 000000 */
        0x20, /* 00 00000 */
        0x20, /* 00 00000 */
        0x10, /* 000 0000 */
@@ -1215,8 +1217,6 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x08, /* 0000 000 */
        0x04, /* 00000 00 */
        0x04, /* 00000 00 */
-       0x02, /* 000000 0 */
-       0x02, /* 000000 0 */
        0x00, /* 00000000 */
 
        /* 93 0x5d ']' */
@@ -1253,7 +1253,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x7e, /* 0      0 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2222,9 +2222,9 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
 
        /* 170 0xaa '\252' */
        0x00, /* 00000000 */
-       0x7a, /* 0    0 0 */
-       0x2e, /* 00 0   0 */
-       0x2e, /* 00 0   0 */
+       0xf4, /*     0 00 */
+       0x5c, /* 0 0   00 */
+       0x5c, /* 0 0   00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2732,7 +2732,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x7e, /* 0      0 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2834,11 +2834,11 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
        /* 217 0xd9 '\331' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-       0x7e, /* 0      0 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
-       0x7e, /* 0      0 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
-       0x7e, /* 0      0 */
+       0xfc, /*       00 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
index 71aafc340fdb13a8e2dd14a816732719e1c10295..a7fbb50caf9d1541055d9227d479532a2c2cedf3 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *  linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device
  *
- *     Copyright (C) 1999 Silicon Graphics, Inc.
- *      Jeffrey Newquist, newquist@engr.sgi.som
+ *      Copyright (C) 1999 Silicon Graphics, Inc.
+ *      Jeffrey Newquist, newquist@engr.sgi.com
  *
  *  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
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
+#include <linux/i2c.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
 #include <video/fbcon-cfb32.h>
 
-#define INCLUDE_TIMING_TABLE_DATA
 #define DBE_REG_BASE regs
 #include "sgivwfb.h"
 
+#define FLATPANEL_SGI_1600SW 5
+
+/*
+ * Video Timing Data Structure
+ */
+
+typedef struct dbe_timing_info
+{
+  int flags;
+  short width;              /* Monitor resolution               */
+  short height;
+  int cfreq;                /* pixel clock frequency (KHz) */
+  short htotal;             /* Horizontal total pixels  */
+  short hblank_start;   /* Horizontal blank start       */
+  short hblank_end;         /* Horizontal blank end             */
+  short hsync_start;    /* Horizontal sync start        */
+  short hsync_end;          /* Horizontal sync end              */
+  short vtotal;             /* Vertical total lines             */
+  short vblank_start;   /* Vertical blank start         */
+  short vblank_end;         /* Vertical blank end               */
+  short vsync_start;    /* Vertical sync start          */
+  short vsync_end;          /* Vertical sync end                */
+  short pll_m;              /* PLL M parameter          */
+  short pll_n;              /* PLL P parameter          */
+  short pll_p;              /* PLL N parameter          */
+} dbe_timing_info_t;
+
 struct sgivwfb_par {
   struct fb_var_screeninfo var;
-  u_long timing_num;
+  dbe_timing_info_t timing;
   int valid;
 };
 
+struct i2c_private {
+    int sda;
+    int scl;
+    volatile u32 *reg;
+};
+
 /*
  *  RAM we reserve for the frame buffer. This defines the maximum screen
  *  size
- *
- *  The default can be overridden if the driver is compiled as a module
  */
 
 /* set by arch/i386/kernel/setup.c */
 u_long                sgivwfb_mem_phys;
 u_long                sgivwfb_mem_size;
 
+EXPORT_SYMBOL(sgivwfb_mem_phys);
+EXPORT_SYMBOL(sgivwfb_mem_size);
+
 static volatile char  *fbmem;
 static asregs         *regs;
 static struct fb_info fb_info;
@@ -60,6 +94,7 @@ static char           sgivwfb_name[16] = "SGI Vis WS FB";
 static u32            cmap_fifo;
 static int            ypan       = 0;
 static int            ywrap      = 0;
+static int            flatpanel_id = -1;
 
 /* console related variables */
 static int currcon = 0;
@@ -75,15 +110,27 @@ static union {
 } fbcon_cmap;
 
 static struct sgivwfb_par par_current = {
-  {                             /* var (screeninfo) */
-    /* 640x480, 8 bpp */
-    640, 480, 640, 480, 0, 0, 8, 0,
+  { /* var (screeninfo) */
+    /* 800x600, 8 bpp */
+    800, 600, 800, 600, 0, 0, 8, 0,
     {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-    0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2,
-    0, FB_VMODE_NONINTERLACED
+    0, 0, -1, -1, 0,
+    25000, 88, 40, 23, 1, 128, 4,
+    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+  },
+  { /* timing (dbe_timing_info_t) */
+    0,
   },
-  0,                            /* timing_num */
-  0                            /* par not activated */
+  0     /* par not activated */
+};
+
+struct fb_var_screeninfo SGI_1600SW_TIMING = 
+{
+    1600, 1024, 1600, 1024, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0,
+    9353, 20, 30, 37, 3, 20, 3,
+    0, FB_VMODE_NONINTERLACED
 };
 
 /*
@@ -94,19 +141,19 @@ void sgivwfb_setup(char *options, int *ints);
 static int sgivwfb_open(struct fb_info *info, int user);
 static int sgivwfb_release(struct fb_info *info, int user);
 static int sgivwfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-                          struct fb_info *info);
+                           struct fb_info *info);
 static int sgivwfb_get_var(struct fb_var_screeninfo *var, int con,
-                          struct fb_info *info);
+                           struct fb_info *info);
 static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
-                          struct fb_info *info);
+                           struct fb_info *info);
 static int sgivwfb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info);
+                               struct fb_info *info);
 static int sgivwfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-                           struct fb_info *info);
+                            struct fb_info *info);
 static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-                           struct fb_info *info);
+                            struct fb_info *info);
 static int sgivwfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                        u_long arg, int con, struct fb_info *info);
+                         u_long arg, int con, struct fb_info *info);
 static int sgivwfb_mmap(struct fb_info *info, struct file *file,
                         struct vm_area_struct *vma);
 
@@ -123,6 +170,37 @@ static struct fb_ops sgivwfb_ops = {
   sgivwfb_mmap
 };
 
+/* i2c bus functions */
+static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data);
+static int i2c_getdataline(struct i2c_bus *bus);
+static int i2c_flatpanel_status(struct i2c_bus *bus);
+static int i2c_flatpanel_id(struct i2c_bus *bus);
+static int i2c_flatpanel_power(struct i2c_bus *bus, int flag);
+
+static struct i2c_bus sgivwfb_i2c_bus_template = 
+{
+        "sgivwfb",
+        I2C_BUSID_SGIVWFB,
+        NULL,
+
+#if LINUX_VERSION_CODE >= 0x020100
+        SPIN_LOCK_UNLOCKED,
+#endif
+
+        NULL,
+        NULL,
+        
+        i2c_setlines,
+        i2c_getdataline,
+        NULL,
+        NULL,
+};
+
+static struct i2c_private flatpanel_i2c =
+{
+    0, 0, NULL
+};
+
 /*
  *  Interface to the low level console driver
  */
@@ -138,11 +216,11 @@ static u_long get_line_length(int xres_virtual, int bpp);
 static unsigned long bytes_per_pixel(int bpp);
 static void activate_par(struct sgivwfb_par *par);
 static void sgivwfb_encode_fix(struct fb_fix_screeninfo *fix,
-                              struct fb_var_screeninfo *var);
+                               struct fb_var_screeninfo *var);
 static int sgivwfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                            u_int *transp, struct fb_info *info);
+                             u_int *transp, struct fb_info *info);
 static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                            u_int transp, struct fb_info *info);
+                             u_int transp, struct fb_info *info);
 static void do_install_cmap(int con, struct fb_info *info);
 
 static unsigned long get_line_length(int xres_virtual, int bpp)
@@ -158,6 +236,7 @@ static unsigned long bytes_per_pixel(int bpp)
   case 8:
     length = 1;
     break;
+  case 15:
   case 16:
     length = 2;
     break;
@@ -173,9 +252,52 @@ static unsigned long bytes_per_pixel(int bpp)
 }
 
 /*
- * Function:   dbe_TurnOffDma
- * Parameters: (None)
- * Description:        This should turn off the monitor and dbe.  This is used
+ * Function:    dbe_CalcClock
+ * Parameters:  Target clock and pointers to PLL parameter destinations
+ * Description: Calculate DBE PLL parameters which give dot clock closest
+ *              to requested TargetClock.  Attempt to make this reasonably
+ *              efficient by skipping obviously wrong parameters.
+ */
+
+static int
+dbe_CalcClock(int TargetClock, short *M, short *N, short *P)
+{
+  short m, n, p;
+  int mBase, nBase, TestClock, PickClock=0, delta, minDelta=10000;
+
+  if (TargetClock > 256*DBE_CLOCK_REF_KHZ)
+    return 0;
+  
+  for (m=TargetClock/DBE_CLOCK_REF_KHZ; m<=256; m++) {
+    mBase = m * DBE_CLOCK_REF_KHZ;
+    for (n=1; n<=64; n++) {
+      nBase = mBase/n;
+      for (p=0; p<=3; p++) {
+        TestClock = nBase>>p;
+        delta = TestClock-TargetClock;
+        if (delta<0)
+          delta = -delta;
+        if (delta < minDelta) {
+          minDelta = delta;
+          PickClock = TestClock;
+          *M = m;
+          *N = n;
+          *P = p;
+        }
+        if (TestClock < TargetClock)
+          break; /* Only going to get smaller, so break this loop */
+      }
+      if (nBase < TargetClock)
+        break; /* Only going to get smaller, so break this loop */
+    }
+  }
+  return PickClock;
+}
+
+/*
+ * Function:    dbe_TurnOffDma
+ * Parameters:  (None)
+ * Description: This should turn off the monitor and dbe.  This is used
  *              when switching between the serial console and the graphics
  *              console.
  */
@@ -246,7 +368,7 @@ static void dbe_TurnOffDma(void)
  */
 static void activate_par(struct sgivwfb_par *par)
 {
-  int i,j, htmp, temp;
+  int i,j, htmp, temp, fp_wid, fp_hgt, fp_vbs, fp_vbe;
   u32 readVal, outputVal;
   int wholeTilesX, maxPixelsPerTileX;
   int frmWrite1, frmWrite2, frmWrite3b;
@@ -254,7 +376,7 @@ static void activate_par(struct sgivwfb_par *par)
   int xpmax, ypmax;                       // Monitor resolution
   int bytesPerPixel;                      // Bytes per pixel
 
-  currentTiming = &dbeVTimings[par->timing_num];
+  currentTiming = &par->timing;
   bytesPerPixel = bytes_per_pixel(par->var.bits_per_pixel);
   xpmax = currentTiming->width;
   ypmax = currentTiming->height;
@@ -271,9 +393,6 @@ static void activate_par(struct sgivwfb_par *par)
   if (wholeTilesX*maxPixelsPerTileX < xpmax)
     wholeTilesX++;
 
-  printk("sgivwfb: pixPerTile=%d wholeTilesX=%d\n",
-        maxPixelsPerTileX, wholeTilesX);
-
   /* dbe_InitGammaMap(); */
   udelay(10);
 
@@ -293,6 +412,7 @@ static void activate_par(struct sgivwfb_par *par)
     dbe_TurnOffDma();
 
   /* dbe_Initdbe(); */
+  DBE_SETREG(config, DBE_CONFIG_FBDEV);
   for (i = 0; i < 256; i++)
     {
       for (j = 0; j < 100; j++)
@@ -345,7 +465,7 @@ static void activate_par(struct sgivwfb_par *par)
         SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8);
         break;
       case 2:
-        SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5);
+        SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_ARGB5);
         break;
       case 4:
         SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8);
@@ -391,6 +511,38 @@ static void activate_par(struct sgivwfb_par *par)
   SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, currentTiming->hblank_end-3);
   DBE_SETREG(vt_hcmap, outputVal);
 
+  outputVal = 0;
+  SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, 
+    (currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
+  SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, 
+    (currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
+  DBE_SETREG(vt_flags, outputVal);
+
+  /* Turn on the flat panel */
+  switch(flatpanel_id) {
+    case FLATPANEL_SGI_1600SW:
+      fp_wid=1600; fp_hgt=1024; fp_vbs=0; fp_vbe=1600;
+      currentTiming->pll_m = 4;
+      currentTiming->pll_n = 1;
+      currentTiming->pll_p = 0;
+      break;
+    default:
+      fp_wid=0xfff; fp_hgt=0xfff; fp_vbs=0xfff; fp_vbe=0xfff;
+      break;
+  }
+
+  outputVal = 0;
+  SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs);
+  SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe);
+  DBE_SETREG(fp_de, outputVal);
+  outputVal = 0;
+  SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid);
+  DBE_SETREG(fp_hdrv, outputVal);
+  outputVal = 0;
+  SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1);
+  SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt+1);
+  DBE_SETREG(fp_vdrv, outputVal);
+
   outputVal = 0;
   temp = currentTiming->vblank_start - currentTiming->vblank_end - 1;
   if (temp > 0)
@@ -490,6 +642,17 @@ static void activate_par(struct sgivwfb_par *par)
   DBE_GETREG(ctrlstat, readVal);
   readVal &= 0x02000000;
 
+  if (flatpanel_id != -1) {
+    // Turn on half-phase & enable FP signals
+    DBE_GETREG(config, readVal);
+    readVal |= 1<<3;
+    DBE_SETREG(config, readVal);
+
+    DBE_GETREG(ctrlstat, readVal);
+    readVal |= 1<<26;
+    DBE_SETREG(ctrlstat, readVal);
+  }
+
   if (readVal != 0)
     {
       DBE_SETREG(ctrlstat, 0x30000000);
@@ -497,7 +660,7 @@ static void activate_par(struct sgivwfb_par *par)
 }
 
 static void sgivwfb_encode_fix(struct fb_fix_screeninfo *fix,
-                              struct fb_var_screeninfo *var)
+                               struct fb_var_screeninfo *var)
 {
   memset(fix, 0, sizeof(struct fb_fix_screeninfo));
   strcpy(fix->id, sgivwfb_name);
@@ -561,19 +724,19 @@ static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
     cmap_fifo = regs->cm_fifo;
 
   regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
-  cmap_fifo--;                 /* assume FIFO is filling up */
+  cmap_fifo--;                  /* assume FIFO is filling up */
   return 0;
 }
 
 static void do_install_cmap(int con, struct fb_info *info)
 {
     if (con != currcon)
-       return;
+        return;
     if (fb_display[con].cmap.len)
-       fb_set_cmap(&fb_display[con].cmap, 1, sgivwfb_setcolreg, info);
+        fb_set_cmap(&fb_display[con].cmap, 1, sgivwfb_setcolreg, info);
     else
-       fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1,
-                   sgivwfb_setcolreg, info);
+        fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1,
+                    sgivwfb_setcolreg, info);
 }
 
 /* ---------------------------------------------------- */
@@ -600,7 +763,7 @@ static int sgivwfb_release(struct fb_info *info, int user)
  *  Get the Fixed Part of the Display
  */
 static int sgivwfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-                          struct fb_info *info)
+                           struct fb_info *info)
 {
   struct fb_var_screeninfo *var;
 
@@ -616,7 +779,7 @@ static int sgivwfb_get_fix(struct fb_fix_screeninfo *fix, int con,
  *  Get the User Defined Part of the Display. If a real par get it form there
  */
 static int sgivwfb_get_var(struct fb_var_screeninfo *var, int con,
-                          struct fb_info *info)
+                           struct fb_info *info)
 {
   if (con == -1)
     *var = par_current.var;
@@ -630,23 +793,22 @@ static int sgivwfb_get_var(struct fb_var_screeninfo *var, int con,
  *  real video mode.
  */
 static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
-                          struct fb_info *info)
+                           struct fb_info *info)
 {
   int err, activate = var->activate;
   int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
   u_long line_length;
-  u_long min_mode;
   int req_dot;
-  int test_mode;
+  u32 bpp;
 
-  struct dbe_timing_info *timing;
+  struct dbe_timing_info timing;
 
   struct display *display;
 
   if (con >= 0)
     display = &fb_display[con];
   else
-    display = &disp;   /* used during initialization */
+    display = &disp;    /* used during initialization */
 
   /*
    *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
@@ -663,9 +825,11 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
   var->xoffset = 0;
   var->yoffset = 0;
 
-  /* Limit bpp to 8, 16, and 32 */
+  /* Limit bpp to 8, 15/16, and 32 */
   if (var->bits_per_pixel <= 8)
     var->bits_per_pixel = 8;
+  else if (var->bits_per_pixel <= 15)
+    var->bits_per_pixel = 15;
   else if (var->bits_per_pixel <= 16)
     var->bits_per_pixel = 16;
   else if (var->bits_per_pixel <= 32)
@@ -676,31 +840,33 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
   var->grayscale = 0;           /* No grayscale for now */
 
   /* determine valid resolution and timing */
-  for (min_mode=0; min_mode<DBE_VT_SIZE; min_mode++) {
-    if (dbeVTimings[min_mode].width >= var->xres &&
-        dbeVTimings[min_mode].height >= var->yres)
-      break;
-  }
-
-  if (min_mode == DBE_VT_SIZE)
-    return -EINVAL;             /* Resolution to high */
-
-  /* XXX FIXME - should try to pick best refresh rate */
-  /* for now, pick closest dot-clock within 3MHz*/
-  req_dot = (int)((1.0e3/1.0e6) / (1.0e-12 * (float)var->pixclock));
-  printk("sgivwfb: requested pixclock=%d ps (%d KHz)\n", var->pixclock,
-        req_dot);
-  test_mode=min_mode;
-  while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) {
-    if (dbeVTimings[test_mode].cfreq+3000 > req_dot)
+  /* XXX FIXME: Needs sanity check */
+  switch (flatpanel_id) {
+    case FLATPANEL_SGI_1600SW:
+      bpp = var->bits_per_pixel;
+      *var = SGI_1600SW_TIMING;
+      var->bits_per_pixel = bpp;
       break;
-    test_mode++;
+    default:
+      flatpanel_id = -1;
   }
-  if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width)
-    test_mode--;
-  min_mode = test_mode;
-  timing = &dbeVTimings[min_mode];
-  printk("sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq);
+  req_dot = 1000000000 / var->pixclock;
+  req_dot = dbe_CalcClock(req_dot, &timing.pll_m, &timing.pll_n, &timing.pll_p);
+  var->pixclock = 1000000000 / req_dot;
+  timing.flags = var->sync;
+  timing.width = var->xres;
+  timing.height = var->yres;
+  timing.cfreq = req_dot;
+  timing.htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
+  timing.hblank_start = var->xres;
+  timing.hblank_end = timing.htotal;
+  timing.hsync_start = var->xres + var->right_margin;
+  timing.hsync_end = timing.hsync_start + var->hsync_len;
+  timing.vtotal = var->upper_margin + var->yres + var->lower_margin + var->vsync_len;
+  timing.vblank_start = var->yres;
+  timing.vblank_end = timing.vtotal;
+  timing.vsync_start = var->yres + var->lower_margin;
+  timing.vsync_end = timing.vsync_start + var->vsync_len;
 
   /* Adjust virtual resolution, if necessary */
   if (var->xres > var->xres_virtual || (!ywrap && !ypan))
@@ -727,24 +893,25 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
       var->transp.offset = 0;
       var->transp.length = 0;
       break;
-    case 16:   /* RGBA 5551 */
-      var->red.offset = 11;
+    case 15:    /* ARGB 1555 */
+    case 16:    /* ARGB 1555 */
+      var->red.offset = 10;
       var->red.length = 5;
-      var->green.offset = 6;
+      var->green.offset = 5;
       var->green.length = 5;
-      var->blue.offset = 1;
+      var->blue.offset = 0;
       var->blue.length = 5;
-      var->transp.offset = 0;
-      var->transp.length = 0;
+      var->transp.offset = 15;
+      var->transp.length = 1;
       break;
-    case 32:   /* RGB 8888 */
-      var->red.offset = 0;
+    case 32:    /* RGBA 8888 */
+      var->red.offset = 24;
       var->red.length = 8;
-      var->green.offset = 8;
+      var->green.offset = 16;
       var->green.length = 8;
-      var->blue.offset = 16;
+      var->blue.offset = 8;
       var->blue.length = 8;
-      var->transp.offset = 24;
+      var->transp.offset = 0;
       var->transp.length = 8;
       break;
     }
@@ -753,15 +920,6 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
   var->blue.msb_right = 0;
   var->transp.msb_right = 0;
 
-  /* set video timing information */
-  var->pixclock = (__u32)(1.0e+9/(float)timing->cfreq);
-  var->left_margin = timing->htotal - timing->hsync_end;
-  var->right_margin = timing->hsync_start - timing->width;
-  var->upper_margin = timing->vtotal - timing->vsync_end;
-  var->lower_margin = timing->vsync_start - timing->height;
-  var->hsync_len = timing->hsync_end - timing->hsync_start;
-  var->vsync_len = timing->vsync_end -  timing->vsync_start;
-
   if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
     oldxres = display->var.xres;
     oldyres = display->var.yres;
@@ -770,15 +928,15 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
     oldbpp = display->var.bits_per_pixel;
     display->var = *var;
     par_current.var = *var;
-    par_current.timing_num = min_mode;
+    par_current.timing = timing;
     if (oldxres != var->xres || oldyres != var->yres ||
-       oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-       oldbpp != var->bits_per_pixel || !par_current.valid) {
+        oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+        oldbpp != var->bits_per_pixel || !par_current.valid) {
       struct fb_fix_screeninfo fix;
       printk("sgivwfb: new video mode xres=%d yres=%d bpp=%d\n",
-            var->xres, var->yres, var->bits_per_pixel);
+             var->xres, var->yres, var->bits_per_pixel);
       printk("         vxres=%d vyres=%d\n",
-            var->xres_virtual, var->yres_virtual);
+             var->xres_virtual, var->yres_virtual);
       activate_par(&par_current);
       sgivwfb_encode_fix(&fix, var);
       display->screen_base = (char *)fbmem;
@@ -791,35 +949,35 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
       display->can_soft_blank = 1;
       display->inverse = 0;
       if (oldbpp != var->bits_per_pixel || !par_current.valid) {
-       if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-         return err;
-       do_install_cmap(con, info);
+        if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+          return err;
+        do_install_cmap(con, info);
       }
       switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
       case 8:
-       display->dispsw = &fbcon_cfb8;
-       break;
+        display->dispsw = &fbcon_cfb8;
+        break;
 #endif
 #ifdef FBCON_HAS_CFB16
       case 16:
-       display->dispsw = &fbcon_cfb16;
-       display->dispsw_data = fbcon_cmap.cfb16;
-       break;
+        display->dispsw = &fbcon_cfb16;
+        display->dispsw_data = fbcon_cmap.cfb16;
+        break;
 #endif
 #ifdef FBCON_HAS_CFB32
       case 32:
-       display->dispsw = &fbcon_cfb32;
-       display->dispsw_data = fbcon_cmap.cfb32;
-       break;
+        display->dispsw = &fbcon_cfb32;
+        display->dispsw_data = fbcon_cmap.cfb32;
+        break;
 #endif
       default:
-       display->dispsw = &fbcon_dummy;
-       break;
+        display->dispsw = &fbcon_dummy;
+        break;
       }
       par_current.valid = 1;
       if (fb_info.changevar)
-       (*fb_info.changevar)(con);
+        (*fb_info.changevar)(con);
     }
   }
   return 0;
@@ -832,19 +990,19 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con,
  */
 
 static int sgivwfb_pan_display(struct fb_var_screeninfo *var, int con,
-                              struct fb_info *info)
+                               struct fb_info *info)
 {
 #if 0
   if (var->vmode & FB_VMODE_YWRAP) {
     if (var->yoffset < 0 ||
-       var->yoffset >= fb_display[con].var.yres_virtual ||
-       var->xoffset)
+        var->yoffset >= fb_display[con].var.yres_virtual ||
+        var->xoffset)
       return -EINVAL;
   } else {
     if (var->xoffset+fb_display[con].var.xres >
-       fb_display[con].var.xres_virtual ||
-       var->yoffset+fb_display[con].var.yres >
-       fb_display[con].var.yres_virtual)
+        fb_display[con].var.xres_virtual ||
+        var->yoffset+fb_display[con].var.yres >
+        fb_display[con].var.yres_virtual)
       return -EINVAL;
   }
   fb_display[con].var.xoffset = var->xoffset;
@@ -862,7 +1020,7 @@ static int sgivwfb_pan_display(struct fb_var_screeninfo *var, int con,
  *  Get the Colormap
  */
 static int sgivwfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-                           struct fb_info *info)
+                            struct fb_info *info)
 {
   if (con == currcon) /* current console? */
     return fb_get_cmap(cmap, kspc, sgivwfb_getcolreg, info);
@@ -870,7 +1028,7 @@ static int sgivwfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
     fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
   else
     fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-                cmap, kspc ? 0 : 2);
+                 cmap, kspc ? 0 : 2);
   return 0;
 }
 
@@ -878,16 +1036,16 @@ static int sgivwfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  *  Set the Colormap
  */
 static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-                           struct fb_info *info)
+                            struct fb_info *info)
 {
   int err;
 
-  if (!fb_display[con].cmap.len) {     /* no colormap allocated? */
+  if (!fb_display[con].cmap.len) {      /* no colormap allocated? */
     if ((err = fb_alloc_cmap(&fb_display[con].cmap,
-                            1<<fb_display[con].var.bits_per_pixel, 0)))
+                             1<<fb_display[con].var.bits_per_pixel, 0)))
       return err;
   }
-  if (con == currcon)                  /* current console? */
+  if (con == currcon)                   /* current console? */
     return fb_set_cmap(cmap, kspc, sgivwfb_setcolreg, info);
   else
     fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
@@ -898,7 +1056,7 @@ static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  *  Virtual Frame Buffer Specific ioctls
  */
 static int sgivwfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                        u_long arg, int con, struct fb_info *info)
+                         u_long arg, int con, struct fb_info *info)
 {
   return -EINVAL;
 }
@@ -915,7 +1073,6 @@ static int sgivwfb_mmap(struct fb_info *info, struct file *file,
   if (remap_page_range(vma->vm_start, offset, size, vma->vm_page_prot))
     return -EAGAIN;
   vma->vm_file = file;
-  printk("sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", offset, vma->vm_start);
   return 0;
 }
 
@@ -936,12 +1093,12 @@ __initfunc(void sgivwfb_setup(char *options, int *ints))
 }
 
 /*
- *  Initialisation
+ *  Initialization
  */
 __initfunc(void sgivwfb_init(void))
 {
   printk("sgivwfb: framebuffer at 0x%lx, size %ldk\n",
-        sgivwfb_mem_phys, sgivwfb_mem_size/1024);
+         sgivwfb_mem_phys, sgivwfb_mem_size/1024);
 
   regs = (asregs*)ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE);
   if (!regs) {
@@ -968,7 +1125,32 @@ __initfunc(void sgivwfb_init(void))
     printk("sgivwfb: couldn't ioremap fbmem\n");
     goto fail_ioremap_fbmem;
   }
+  
+  /* setup i2c support, set idle condition on i2c bus */
+  flatpanel_i2c.reg = &regs->i2cfp;
+  sgivwfb_i2c_bus_template.data = (void*)&flatpanel_i2c;
+  i2c_setlines(&sgivwfb_i2c_bus_template, 1, 1);
+  if (i2c_register_bus(&sgivwfb_i2c_bus_template)) {
+    printk("sgivwfb: couldn't register i2c bus\n");
+  }
 
+  /* query flatpanel */
+  flatpanel_id = i2c_flatpanel_id(&sgivwfb_i2c_bus_template);
+  if (flatpanel_id == -1)
+    printk("sgivwfb: flatpanel not detected.\n");
+  else {
+    switch (flatpanel_id) {
+      case FLATPANEL_SGI_1600SW:
+        printk("sgivwfb: SGI 1600SW flatpanel detected (excellent choice).\n");
+        break;
+      default:
+        // XXX TODO: query panel for resolution?
+        printk("sgivwfb: Unknown flatpanel type %d detected.\n", flatpanel_id);
+        flatpanel_id = -1; //ignore it for now
+        break;
+    }
+  }
   /* turn on default video mode */
   sgivwfb_set_var(&par_current.var, -1, &fb_info);
 
@@ -978,7 +1160,7 @@ __initfunc(void sgivwfb_init(void))
   }
 
   printk("fb%d: Virtual frame buffer device, using %ldK of video memory\n",
-        GET_FB_IDX(fb_info.node), sgivwfb_mem_size>>10);
+         GET_FB_IDX(fb_info.node), sgivwfb_mem_size>>10);
 
   return;
 
@@ -1030,8 +1212,78 @@ void cleanup_module(void)
 {
   unregister_framebuffer(&fb_info);
   dbe_TurnOffDma();
+  i2c_unregister_bus(&flatpanel_i2c);
   iounmap(regs);
   iounmap(fbmem);
 }
 
 #endif /* MODULE */
+
+#define I2C_DELAY 1000
+#define I2C_FLATPANEL_BASE 0x70
+
+/* Apply clock and data state to the i2c bus */
+static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data)
+{
+    struct i2c_private *info = (struct i2c_private*)bus->data;
+    int timeout = 10000; /* 10ms timeout */
+    
+    if (info->scl==1 && ctrl==0) {
+        /* data change lags falling clock edge */
+        *info->reg = ~(ctrl<<1 | info->sda);
+        info->scl = ctrl;
+        udelay(I2C_DELAY);
+    }
+    /* apply data change, if any */
+    if (data != info->sda) {
+        *info->reg = ~(info->scl<<1 | data);
+        info->sda = data;
+        udelay(I2C_DELAY);
+    }
+    if (info->scl==0 && ctrl==1) {
+        /* data change leads rising clock edge */
+        *info->reg = ~(ctrl<<1 | info->sda);
+        info->scl = ctrl;
+        udelay(I2C_DELAY);
+        
+        /* wait for slave to be ready */
+        while (((~*info->reg)&2) == 0 && timeout != 0) {
+            timeout--;
+            udelay(1);
+        }
+        if (timeout==0)
+            printk("sgivwfb: i2c wait-state timeout.\n");
+    }
+}
+
+/* Get the data line state */
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+    struct i2c_private *info = (struct i2c_private*)bus->data;
+    return (int)((~*info->reg) & 1);
+}
+
+static int i2c_flatpanel_status(struct i2c_bus *bus)
+{
+    return i2c_read(bus, I2C_FLATPANEL_BASE | 1);
+}
+
+static int i2c_flatpanel_id(struct i2c_bus *bus)
+{
+    int id = i2c_flatpanel_status(bus);
+    if (id == -1)
+        return -1;
+    id = (id & 0xe0) >> 5;
+    return id;
+}
+
+static int i2c_flatpanel_power(struct i2c_bus *bus, int flag)
+{
+    int status = i2c_flatpanel_status(bus);
+    if (status == -1)
+        return -1;
+    if (flag == -1)
+        return status & (1<<2);
+    return 0;
+}
+
index 8ff8a77f43e2660ae172f14f243492556f25c881..52a668382070be247b6ba704d959853db8a1a678 100644 (file)
@@ -2,7 +2,7 @@
  *  linux/drivers/video/sgivwfb.h -- SGI DBE frame buffer device header
  *
  *      Copyright (C) 1999 Silicon Graphics, Inc.
- *      Jeffrey Newquist, newquist@engr.sgi.som
+ *      Jeffrey Newquist, newquist@engr.sgi.com
  *
  *  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
@@ -26,7 +26,7 @@
 
 /* NOTE: All loads/stores must be 32 bits and uncached */
 
-#define DBE_REG_PHYS   0xd0000000
+#define DBE_REG_PHYS    0xd0000000
 #define DBE_REG_SIZE        0x01000000
 
 typedef struct {
@@ -73,7 +73,7 @@ typedef struct {
   volatile u32 frm_size_tile;  /* 0x030000 normal plane ctrl 0 */
   volatile u32 frm_size_pixel; /* 0x030004 normal plane ctrl 1 */
   volatile u32 frm_inhwctrl;   /* 0x030008 normal plane ctrl 2 */
-  volatile u32 frm_control;       /* 0x03000C normal plane ctrl 3 */
+  volatile u32 frm_control;        /* 0x03000C normal plane ctrl 3 */
 
   char _pad3[ 0x040000 - 0x030010 ];
 
@@ -144,6 +144,21 @@ typedef struct {
 #define DBE_VT_XY_VT_FREEZE_MSB     31
 #define DBE_VT_XY_VT_FREEZE_LSB     31
 
+#define DBE_FP_VDRV_FP_VDRV_ON_MSB        23
+#define DBE_FP_VDRV_FP_VDRV_ON_LSB        12
+#define DBE_FP_VDRV_FP_VDRV_OFF_MSB       11
+#define DBE_FP_VDRV_FP_VDRV_OFF_LSB       0
+
+#define DBE_FP_HDRV_FP_HDRV_ON_MSB        23
+#define DBE_FP_HDRV_FP_HDRV_ON_LSB        12
+#define DBE_FP_HDRV_FP_HDRV_OFF_MSB       11
+#define DBE_FP_HDRV_FP_HDRV_OFF_LSB       0
+
+#define DBE_FP_DE_FP_DE_ON_MSB        23
+#define DBE_FP_DE_FP_DE_ON_LSB        12
+#define DBE_FP_DE_FP_DE_OFF_MSB       11
+#define DBE_FP_DE_FP_DE_OFF_LSB       0
+
 #define DBE_VT_VSYNC_VT_VSYNC_ON_MSB        23
 #define DBE_VT_VSYNC_VT_VSYNC_ON_LSB        12
 #define DBE_VT_VSYNC_VT_VSYNC_OFF_MSB       11
@@ -164,6 +179,11 @@ typedef struct {
 #define DBE_VT_HBLANK_VT_HBLANK_OFF_MSB       11
 #define DBE_VT_HBLANK_VT_HBLANK_OFF_LSB       0
 
+#define DBE_VT_FLAGS_VDRV_INVERT_MSB  0
+#define DBE_VT_FLAGS_VDRV_INVERT_LSB  0
+#define DBE_VT_FLAGS_HDRV_INVERT_MSB  2
+#define DBE_VT_FLAGS_HDRV_INVERT_LSB  2
+
 #define DBE_VT_VCMAP_VT_VCMAP_ON_MSB        23
 #define DBE_VT_VCMAP_VT_VCMAP_ON_LSB        12
 #define DBE_VT_VCMAP_VT_VCMAP_OFF_MSB       11
@@ -264,6 +284,8 @@ typedef struct {
 
 #define DBE_CRS_MAGIC       54
 
+#define DBE_CLOCK_REF_KHZ 27000
+
 /* Config Register (DBE Only) Definitions */
 
 #define DBE_CONFIG_VDAC_ENABLE       0x00000001
@@ -280,381 +302,4 @@ typedef struct {
                                       DBE_CONFIG_LENDIAN     | \
                                       DBE_CONFIG_EXT_ADDR )
 
-/*
- * Available Video Timings and Corresponding Indices
- */
-
-typedef enum {
-  DBE_VT_640_480_60,
-
-  DBE_VT_800_600_60,
-  DBE_VT_800_600_75,
-  DBE_VT_800_600_120,
-
-  DBE_VT_1024_768_50,
-  DBE_VT_1024_768_60,
-  DBE_VT_1024_768_75,
-  DBE_VT_1024_768_85,
-  DBE_VT_1024_768_120,
-
-  DBE_VT_1280_1024_50,
-  DBE_VT_1280_1024_60,
-  DBE_VT_1280_1024_75,
-  DBE_VT_1280_1024_85,
-
-  DBE_VT_1600_1024_53,
-  DBE_VT_1600_1024_60,
-
-  DBE_VT_1600_1200_50,
-  DBE_VT_1600_1200_60,
-  DBE_VT_1600_1200_75,
-
-  DBE_VT_1920_1080_50,
-  DBE_VT_1920_1080_60,
-  DBE_VT_1920_1080_72,
-
-  DBE_VT_1920_1200_50,
-  DBE_VT_1920_1200_60,
-  DBE_VT_1920_1200_66,
-
-  DBE_VT_UNKNOWN
-} dbe_timing_t;
-
-
-
-/*
- * Crime Video Timing Data Structure
- */
-
-typedef struct dbe_timing_info
-{
-  dbe_timing_t type;
-  int flags;                           
-  short width;             /* Monitor resolution               */
-  short height;
-  int fields_sec;          /* fields/sec  (Hz -3 dec. places */
-  int cfreq;               /* pixel clock frequency (MHz -3 dec. places) */
-  short htotal;                    /* Horizontal total pixels  */
-  short hblank_start;      /* Horizontal blank start   */
-  short hblank_end;        /* Horizontal blank end             */
-  short hsync_start;       /* Horizontal sync start    */
-  short hsync_end;         /* Horizontal sync end              */
-  short vtotal;                    /* Vertical total lines             */
-  short vblank_start;      /* Vertical blank start             */
-  short vblank_end;        /* Vertical blank end               */
-  short vsync_start;       /* Vertical sync start              */
-  short vsync_end;         /* Vertical sync end                */
-  short pll_m;             /* PLL M parameter          */
-  short pll_n;             /* PLL P parameter          */
-  short pll_p;             /* PLL N parameter          */
-} dbe_timing_info_t;
-
-/* Defines for dbe_vof_info_t flags */
-
-#define DBE_VOF_UNKNOWNMON    1
-#define DBE_VOF_STEREO        2
-#define DBE_VOF_DO_GENSYNC    4          /* enable incoming sync */
-#define DBE_VOF_SYNC_ON_GREEN 8          /* sync on green */
-#define DBE_VOF_FLATPANEL     0x1000     /* FLATPANEL Timing */
-#define DBE_VOF_MAGICKEY      0x2000     /* Backdoor key */
-
-/*
- * DBE Timing Tables
- */
-
-#ifdef INCLUDE_TIMING_TABLE_DATA
-struct dbe_timing_info dbeVTimings[] = {
-  {
-    DBE_VT_640_480_60,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,         640,                    480,            59940,                  25175,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    800,       640,                800,                656,            752,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    525,       480,                525,                490,                492,
-    /* pll_m,  pll_n,                  pll_p */
-    15,            2,                          3
-  },
-
-  {
-    DBE_VT_800_600_60,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,     800,                        600,            60317,                  40000,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1056,      800,                1056,               840,                968,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    628,       600,                628,                601,                605,
-    /* pll_m,  pll_n,                  pll_p */
-    3,     1,                          1
-  },
-
-  {
-    DBE_VT_800_600_75,
-    /* flags,  width,              height,             fields_sec,         cfreq */
-    0,     800,                    600,                75000,              49500,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1056,      800,                1056,               816,                896,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    625,       600,                625,                601,                604,
-    /* pll_m,  pll_n,              pll_p */
-    11,            3,                  1
-  },
-
-  {
-    DBE_VT_800_600_120,
-    /* flags,                                  width,          height,                 fields_sec,         cfreq */
-    DBE_VOF_STEREO,        800,                600,                    119800,             82978,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1040,      800,                1040,               856,                976,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    666,       600,                666,                637,                643,
-    /* pll_m,  pll_n,              pll_p */
-    31,            5,                  1
-  },
-
-  {
-    DBE_VT_1024_768_50,
-    /* flags,  width,              height,             fields_sec,         cfreq */
-    0,     1024,                   768,                50000,              54163,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1344,      1024,               1344,               1048,               1184,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    806,       768,                806,                771,                777,
-    /* pll_m,  pll_n,              pll_p */
-    4,     1,                  1
-  },
-
-  {
-    DBE_VT_1024_768_60,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,     1024,                       768,            60004,                  65000,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1344,      1024,               1344,               1048,               1184,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    806,       768,                806,                771,                777,
-    /* pll_m,  pll_n,                  pll_p */
-    12,            5,                          0
-  },
-
-  {
-    DBE_VT_1024_768_75,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,     1024,                       768,            75029,                  78750,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1312,      1024,               1312,               1040,               1136,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    800,       768,                800,                769,                772,
-    /* pll_m,  pll_n,                  pll_p */
-    29,            5,                          1
-  },
-
-  {
-    DBE_VT_1024_768_85,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,     1024,                       768,            84997,                  94500,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1376,      1024,               1376,               1072,               1168,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    808,       768,                808,                769,                772,
-    /* pll_m,  pll_n,                  pll_p */
-    7,     2,                          0
-  },
-
-  {
-    DBE_VT_1024_768_120,
-    /* flags,                                  width,          height,                 fields_sec,             cfreq */
-    DBE_VOF_STEREO,        1024,               768,                    119800,                 133195,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1376,      1024,               1376,               1072,               1168,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    808,       768,                808,                769,                772,
-    /* pll_m,  pll_n,                  pll_p */
-    5,     1,                          0
-  },
-
-  {
-    DBE_VT_1280_1024_50,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,     1280,                       1024,           50000,                  89460,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1680,      1280,               1680,               1360,               1480,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1065,      1024,               1065,               1027,               1030,
-    /* pll_m,  pll_n,                  pll_p */
-    10,            3,                          0
-  },
-
-  {
-    DBE_VT_1280_1024_60,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,     1280,                       1024,           60020,                  108000,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1688,      1280,               1688,               1328,               1440,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1066,      1024,               1066,               1025,               1028,
-    /* pll_m,  pll_n,                  pll_p */
-    4,     1,                      0
-  },
-
-  {
-    DBE_VT_1280_1024_75,
-    /* flags,  width,                  height,         fields_sec,             cfreq */
-    0,     1280,                       1024,           75025,                  135000,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1688,      1280,               1688,               1296,               1440,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1066,      1024,               1066,               1025,               1028,
-    /* pll_m,  pll_n,                  pll_p */
-    5,     1,                          0
-  },
-
-  {
-    DBE_VT_1280_1024_85,
-    /* flags,  width,              height,             fields_sec,         cfreq */
-    0,     1280,                   1024,               85024,              157500,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1728,      1280,               1728,               1344,               1504,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1072,      1024,               1072,               1025,               1028,
-    /* pll_m,  pll_n,              pll_p */
-    29,            5,                  0
-  },
-
-  {
-    DBE_VT_1600_1024_53,
-    /* flags,  width,                  height,         fields_sec,     cfreq */
-    DBE_VOF_FLATPANEL | DBE_VOF_MAGICKEY,
-    1600,                      1024,           53000,                  107447,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1900,   1600,           1900,           1630,           1730,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1067,   1024,           1067,           1027,           1030,
-    /* pll_m,  pll_n,          pll_p */
-    4,      1,              0
-  },
-
-  {
-    DBE_VT_1600_1024_60,
-    /* flags,                                  width,          height,                 fields_sec,     cfreq */
-    DBE_VOF_FLATPANEL,   1600,           1024,                 60000,          106913,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    1670,   1600,           1670,           1630,           1650,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1067,   1024,           1067,           1027,           1030,
-    /* pll_m,  pll_n,          pll_p */
-    4,      1,              0
-  },
-
-  {
-    DBE_VT_1600_1200_50,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1600,           1200,           50000,          130500,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2088,   1600,           2088,           1644,           1764,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1250,   1200,           1250,           1205,           1211,
-    /* pll_m,  pll_n,          pll_p */
-    24,     5,              0
-  },
-
-  {
-    DBE_VT_1600_1200_60,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1600,           1200,           59940,          162000,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2160,   1600,           2160,           1644,           1856,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1250,   1200,           1250,           1201,           1204,
-    /* pll_m,  pll_n,          pll_p */
-    6,         1,              0
-  },
-
-  {
-    DBE_VT_1600_1200_75,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1600,           1200,           75000,          202500,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2160,   1600,           2160,           1644,           1856,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1250,   1200,           1250,           1201,           1204,
-    /* pll_m,  pll_n,          pll_p */
-    15,                2,              0
-  },
-
-  {
-    DBE_VT_1920_1080_50,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1920,           1080,           50000,          133200,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2368,   1920,           2368,           1952,           2096,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1125,   1080,           1125,           1083,           1086,
-    /* pll_m,  pll_n,          pll_p */
-    5,      1,              0
-  },
-
-  {
-    DBE_VT_1920_1080_60,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1920,           1080,           59940,          159840,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2368,   1920,           2368,           1952,           2096,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1125,   1080,           1125,           1083,           1086,
-    /* pll_m,  pll_n,          pll_p */
-    6,      1,              0
-  },
-
-  {
-    DBE_VT_1920_1080_72,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1920,           1080,           72000,          216023,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2560,   1920,           2560,           1968,           2184,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1172,   1080,           1172,           1083,           1086,
-    /* pll_m,  pll_n,          pll_p */
-    8,      1,              0
-  },
-
-  {
-    DBE_VT_1920_1200_50,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1920,           1200,           50000,          161500,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2584,   1920,           2584,           1984,           2240,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1250,   1200,           1250,           1203,           1206,
-    /* pll_m,  pll_n,          pll_p */
-    6,      1,              0
-  },
-       
-  {
-    DBE_VT_1920_1200_60,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1920,           1200,           59940,          193800,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2584,   1920,           2584,           1984,           2240,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1250,   1200,           1250,           1203,           1206,
-    /* pll_m,  pll_n,          pll_p */
-    29,     4,              0
-  },
-
-  {
-    DBE_VT_1920_1200_66,
-    /* flags,  width,          height,         fields_sec,     cfreq */
-    0,      1920,           1200,           66000,          213180,
-    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
-    2584,   1920,           2584,           1984,           2240,
-    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
-    1250,   1200,           1250,           1203,           1206,
-    /* pll_m,  pll_n,          pll_p */
-    8,      1,              0
-  }
-};
-
-#define DBE_VT_SIZE  (sizeof(dbeVTimings)/sizeof(dbeVTimings[0]))
-#endif // INCLUDE_TIMING_TABLE_DATA
-
-#endif // ! __SGIVWFB_H__
+#endif
index 382071dff5f4186a152077d01974236459785f4b..786279c0ccff4f4e0655f8fed1eeeec7c096c660 100644 (file)
@@ -6,7 +6,7 @@
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *     Ian P. Morris           <I.P.Morris@soton.ac.uk>
  *
- *     $Id: ip6_input.c,v 1.11 1998/08/26 12:04:59 davem Exp $
+ *     $Id: ip6_input.c,v 1.11.2.1 1999/08/14 04:02:43 davem Exp $
  *
  *     Based in linux/net/ipv4/ip_input.c
  *