/*
 * linux/arch/m68k/amiga/cyberfb.c -- Low level implementation of the
 *                                    Cybervision frame buffer device
 *
 *    Copyright (C) 1996 Martin Apel
 *                       Geert Uytterhoeven
 *
 *
 * This file is based on the Amiga frame buffer device (amifb.c):
 *
 *    Copyright (C) 1995 Geert Uytterhoeven
 *
 *
 * History:
 *   - 22 Dec 95: Original version by Martin Apel
 *   - 05 Jan 96: Geert: integration into the current source tree
 *
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */


#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/config.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/bootinfo.h>
#include <asm/zorro.h>
#include <asm/pgtable.h>
#include <linux/fb.h>
#include "s3blit.h"


#define arraysize(x)    (sizeof(x)/sizeof(*(x)))

struct Cyber_fb_par {
   int xres;
   int yres;
   int bpp;
};

static struct Cyber_fb_par current_par;

static int current_par_valid = 0;
static int currcon = 0;

static struct display disp[MAX_NR_CONSOLES];
static struct fb_info fb_info;

static int node;        /* node of the /dev/fb?current file */


   /*
    *    Switch for Chipset Independency
    */

static struct fb_hwswitch {

   /* Initialisation */

   int (*init)(void);

   /* Display Control */

   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct Cyber_fb_par *par);
   int (*decode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
   int (*encode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
   int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
                    u_int *transp);
   int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
                    u_int transp);
   void (*blank)(int blank);
} *fbhw;


   /*
    *    Frame Buffer Name
    */

static char Cyber_fb_name[16] = "Cybervision";


   /*
    *    Cybervision Graphics Board
    */

#define CYBER8_WIDTH 1152
#define CYBER8_HEIGHT 886
#define CYBER8_PIXCLOCK 12500    /* ++Geert: Just a guess */

#define CYBER16_WIDTH 800
#define CYBER16_HEIGHT 600
#define CYBER16_PIXCLOCK 25000   /* ++Geert: Just a guess */


static int CyberKey = 0;
static u_char Cyber_colour_table [256][4];
static unsigned long CyberMem;
static unsigned long CyberSize;
static volatile char *CyberRegs;

static long *memstart;


   /*
    *    Predefined Video Mode Names
    */

static char *Cyber_fb_modenames[] = {

   /*
    *    Autodetect (Default) Video Mode
    */

   "default",

   /*
    *    Predefined Video Modes
    */
    
   "cyber8",            /* Cybervision 8 bpp */
   "cyber16",           /* Cybervision 16 bpp */

   /*
    *    Dummy Video Modes
    */

   "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
   "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
   "dummy", "dummy", "dummy", "dummy",

   /*
    *    User Defined Video Modes
    *
    *    This doesn't work yet!!
    */

   "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
};


   /*
    *    Predefined Video Mode Definitions
    */

static struct fb_var_screeninfo Cyber_fb_predefined[] = {

   /*
    *    Autodetect (Default) Video Mode
    */

   { 0, },

   /*
    *    Predefined Video Modes
    */
    
   {
      /* Cybervision 8 bpp */
      CYBER8_WIDTH, CYBER8_HEIGHT, CYBER8_WIDTH, CYBER8_HEIGHT, 0, 0, 8, 0,
      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
      0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
      FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
   }, {
      /* Cybervision 16 bpp */
      CYBER16_WIDTH, CYBER16_HEIGHT, CYBER16_WIDTH, CYBER16_HEIGHT, 0, 0, 16, 0,
      {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
      0, 0, -1, -1, FB_ACCEL_NONE, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
      FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
   },

   /*
    *    Dummy Video Modes
    */

   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
   { 0, }, { 0, },

   /*
    *    User Defined Video Modes
    */

   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
};


#define NUM_TOTAL_MODES    arraysize(Cyber_fb_predefined)
#define NUM_PREDEF_MODES   (3)


static int Cyberfb_inverse = 0;
static int Cyberfb_Cyber8 = 0;        /* Use Cybervision board */
static int Cyberfb_Cyber16 = 0;       /* Use Cybervision board */
static int Cyberfb_mode = 0;


   /*
    *    Some default modes
    */

#define CYBER8_DEFMODE     (1)
#define CYBER16_DEFMODE    (2)


   /*
    *    Interface used by the world
    */

int Cyber_probe(void);
void Cyber_video_setup(char *options, int *ints);

static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con);
static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con);
static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con);
static int Cyber_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
                          u_long arg, int con);


   /*
    *    Interface to the low level console driver
    */

struct fb_info *Cyber_fb_init(long *mem_start); /* Through amiga_fb_init() */
static int Cyberfb_switch(int con);
static int Cyberfb_updatevar(int con);
static void Cyberfb_blank(int blank);


   /*
    *    Accelerated Functions used by the low level console driver
    */

void Cyber_WaitQueue(u_short fifo);
void Cyber_WaitBlit(void);
void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
                  u_short width, u_short height, u_short mode);
void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
                    u_short mode, u_short color);
void Cyber_MoveCursor(u_short x, u_short y);


   /*
    *   Hardware Specific Routines
    */

static int Cyber_init(void);
static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
                          struct Cyber_fb_par *par);
static int Cyber_decode_var(struct fb_var_screeninfo *var,
                          struct Cyber_fb_par *par);
static int Cyber_encode_var(struct fb_var_screeninfo *var,
                          struct Cyber_fb_par *par);
static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
                         u_int *transp);
static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                         u_int transp);
static void Cyber_blank(int blank);


   /*
    *    Internal routines
    */

static void Cyber_fb_get_par(struct Cyber_fb_par *par);
static void Cyber_fb_set_par(struct Cyber_fb_par *par);
static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
static struct fb_cmap *get_default_colormap(int bpp);
static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
                          int kspc);
static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
                          int kspc);
static void do_install_cmap(int con);
static void memcpy_fs(int fsfromto, void *to, void *from, int len);
static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
static void Cyber_fb_set_disp(int con);
static int get_video_mode(const char *name);


/* -------------------- Hardware specific routines -------------------------- */


   /*
    *    Initialization
    *
    *    Set the default video mode for this chipset. If a video mode was
    *    specified on the command line, it will override the default mode.
    */

static int Cyber_init(void)
{
  return 0;
}


   /*
    *    This function should fill in the `fix' structure based on the
    *    values in the `par' structure.
    */

static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
                          struct Cyber_fb_par *par)
{
  return 0;
}


   /*
    *    Get the video params out of `var'. If a value doesn't fit, round
    *    it up, if it's too big, return -EINVAL.
    */

static int Cyber_decode_var(struct fb_var_screeninfo *var,
                          struct Cyber_fb_par *par)
{
  return 0;
}


   /*
    *    Fill the `var' structure based on the values in `par' and maybe
    *    other values read out of the hardware.
    */

static int Cyber_encode_var(struct fb_var_screeninfo *var,
                          struct Cyber_fb_par *par)
{
  return 0;
}


   /*
    *    Set a single color register. The values supplied are already
    *    rounded down to the hardware's capabilities (according to the
    *    entries in the var structure). Return != 0 for invalid regno.
    */

static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                         u_int transp)
{
  return 0;
}


   /*
    *    Read a single color register and split it into
    *    colors/transparent. Return != 0 for invalid regno.
    */

static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
                         u_int *transp)
{
  return 0;
}


   /*
    *    (Un)Blank the screen
    */

void Cyber_blank(int blank)
{
}


/**************************************************************
 * We are waiting for "fifo" FIFO-slots empty
 */
void Cyber_WaitQueue (u_short fifo)
{
}

/**************************************************************
 * We are waiting for Hardware (Graphics Engine) not busy
 */
void Cyber_WaitBlit (void)
{
}

/**************************************************************
 * BitBLT - Through the Plane
 */
void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
                   u_short width, u_short height, u_short mode)
{
}

/**************************************************************
 * Rectangle Fill Solid
 */
void Cyber_RectFill (u_short x, u_short y, u_short width, u_short height,
                     u_short mode, u_short color)
{
}


/**************************************************************
 * Move cursor to x, y
 */
void Cyber_MoveCursor (u_short x, u_short y)
{
}


/* -------------------- Interfaces to hardware functions -------------------- */


static struct fb_hwswitch Cyber_switch = {
   Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var,
   Cyber_getcolreg, Cyber_setcolreg, Cyber_blank
};


/* -------------------- Generic routines ------------------------------------ */


   /*
    *    Fill the hardware's `par' structure.
    */

static void Cyber_fb_get_par(struct Cyber_fb_par *par)
{
}


static void Cyber_fb_set_par(struct Cyber_fb_par *par)
{
}


static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
{
  return 0;
}


   /*
    *    Default Colormaps
    */

static u_short red16[] =
   { 0xc000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0x0000,
     0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff};
static u_short green16[] =
   { 0xc000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0x0000,
     0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff};
static u_short blue16[] =
   { 0xc000, 0x0000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0x0000,
     0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff};


static struct fb_cmap default_16_colors =
   { 0, 16, red16, green16, blue16, NULL };


static struct fb_cmap *get_default_colormap(int bpp)
{
  return NULL;
}


#define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
#define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
                                              ((1<<(width))-1)) : 0))

static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
                          int kspc)
{
  return 0;
}


static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
                          int kspc)
{
  return 0;
}


static void do_install_cmap(int con)
{
}


static void memcpy_fs(int fsfromto, void *to, void *from, int len)
{
}


static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
{
}


static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
{
  return 0;
}


   /*
    *    Get the Fixed Part of the Display
    */

static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
{
  return 0;
}


   /*
    *    Get the User Defined Part of the Display
    */

static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con)
{
  return 0;
}


static void Cyber_fb_set_disp(int con)
{
}


   /*
    *    Set the User Defined Part of the Display
    */

static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con)
{
  return 0;
}


   /*
    *    Get the Colormap
    */

static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
{
  return 0;
}


   /*
    *    Set the Colormap
    */

static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
{
  return 0;
}


   /*
    *    Pan or Wrap the Display
    *
    *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
    */

static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con)
{
  return 0;
}


   /*
    *    Cybervision Frame Buffer Specific ioctls
    */

static int Cyber_fb_ioctl(struct inode *inode, struct file *file,
                          u_int cmd, u_long arg, int con)
{
  return 0;
}


static struct fb_ops Cyber_fb_ops = {
   Cyber_fb_get_fix, Cyber_fb_get_var, Cyber_fb_set_var, Cyber_fb_get_cmap,
   Cyber_fb_set_cmap, Cyber_fb_pan_display, Cyber_fb_ioctl
};


int Cyber_probe(void)
{
  return 0;
}


void Cyber_video_setup(char *options, int *ints)
{
}


   /*
    *    Initialization
    */

struct fb_info *Cyber_fb_init(long *mem_start)
{
  return NULL;
}


static int Cyberfb_switch(int con)
{
  return 0;
}


   /*
    *    Update the `var' structure (called by fbcon.c)
    *
    *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
    *    Since it's called by a kernel driver, no range checking is done.
    */

static int Cyberfb_updatevar(int con)
{
  return 0;
}


   /*
    *    Blank the display.
    */

static void Cyberfb_blank(int blank)
{
}


   /*
    *    Get a Video Mode
    */

static int get_video_mode(const char *name)
{
  return 0;
}
