linux/drivers/video/fbdev/sstfb.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/drivers/video/sstfb.c -- voodoo graphics frame buffer
 *
 *     Copyright (c) 2000-2002 Ghozlane Toumi <[email protected]>
 *
 *     Created 15 Jan 2000 by Ghozlane Toumi
 *
 * Contributions (and many thanks) :
 *
 * 03/2001 James Simmons   <[email protected]>
 * 04/2001 Paul Mundt      <[email protected]>
 * 05/2001 Urs Ganse       <[email protected]>
 *	(initial work on voodoo2 port, interlace)
 * 09/2002 Helge Deller    <[email protected]>
 *	(enable driver on big-endian machines (hppa), ioctl fixes)
 * 12/2002 Helge Deller    <[email protected]>
 *	(port driver to new frambuffer infrastructure)
 * 01/2003 Helge Deller    <[email protected]>
 *	(initial work on fb hardware acceleration for voodoo2)
 * 08/2006 Alan Cox 	   <[email protected]>
 *	Remove never finished and bogus 24/32bit support
 *	Clean up macro abuse
 *	Minor tidying for format.
 * 12/2006 Helge Deller    <[email protected]>
 *	add /sys/class/graphics/fbX/vgapass sysfs-interface
 *	add module option "mode_option" to set initial screen mode
 *	use fbdev default videomode database
 *	remove debug functions from ioctl
 */

/*
 * The voodoo1 has the following memory mapped address space:
 * 0x000000 - 0x3fffff : registers              (4MB)
 * 0x400000 - 0x7fffff : linear frame buffer    (4MB)
 * 0x800000 - 0xffffff : texture memory         (8MB)
 */

/*
 * misc notes, TODOs, toASKs, and deep thoughts

-TODO: at one time or another test that the mode is acceptable by the monitor
-ASK: Can I choose different ordering for the color bitfields (rgba argb ...)
      which one should i use ? is there any preferred one ? It seems ARGB is
      the one ...
-TODO: in  set_var check the validity of timings (hsync vsync)...
-TODO: check and recheck the use of sst_wait_idle : we don't flush the fifo via
       a nop command. so it's ok as long as the commands we pass don't go
       through the fifo. warning: issuing a nop command seems to need pci_fifo
-FIXME: in case of failure in the init sequence, be sure we return to a safe
        state.
- FIXME: Use accelerator for 2D scroll
-FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20)
 */

/*
 * debug info
 * SST_DEBUG : enable debugging
 * SST_DEBUG_REG : debug registers
 *   0 :  no debug
 *   1 : dac calls, [un]set_bits, FbiInit
 *   2 : insane debug level (log every register read/write)
 * SST_DEBUG_FUNC : functions
 *   0 : no debug
 *   1 : function call / debug ioctl
 *   2 : variables
 *   3 : flood . you don't want to do that. trust me.
 * SST_DEBUG_VAR : debug display/var structs
 *   0 : no debug
 *   1 : dumps display, fb_var
 *
 * sstfb specific ioctls:
 *   		toggle vga (0x46db) : toggle vga_pass_through
 */

#undef SST_DEBUG


/*
 * Includes
 */

#include <linux/aperture.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <video/sstfb.h>


/* initialized by setup */

static bool vgapass;		/* enable VGA passthrough cable */
static int mem;			/* mem size in MB, 0 = autodetect */
static bool clipping =;	/* use clipping (slower, safer) */
static int gfxclk;		/* force FBI freq in Mhz . Dangerous */
static bool slowpci;		/* slow PCI settings */

/*
  Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60
*/
#define DEFAULT_VIDEO_MODE

static char *mode_option =;

enum {};

#define IS_VOODOO2(par)

static struct sst_spec voodoo_spec[] =;


/*
 * debug functions
 */

#if (SST_DEBUG_REG > 0)
static void sst_dbg_print_read_reg(u32 reg, u32 val) {
	const char *regname;
	switch (reg) {
	case FBIINIT0:	regname = "FbiInit0"; break;
	case FBIINIT1:	regname = "FbiInit1"; break;
	case FBIINIT2:	regname = "FbiInit2"; break;
	case FBIINIT3:	regname = "FbiInit3"; break;
	case FBIINIT4:	regname = "FbiInit4"; break;
	case FBIINIT5:	regname = "FbiInit5"; break;
	case FBIINIT6:	regname = "FbiInit6"; break;
	default:	regname = NULL;       break;
	}
	if (regname == NULL)
		r_ddprintk("sst_read(%#x): %#x\n", reg, val);
	else
		r_dprintk(" sst_read(%s): %#x\n", regname, val);
}

static void sst_dbg_print_write_reg(u32 reg, u32 val) {
	const char *regname;
	switch (reg) {
	case FBIINIT0:	regname = "FbiInit0"; break;
	case FBIINIT1:	regname = "FbiInit1"; break;
	case FBIINIT2:	regname = "FbiInit2"; break;
	case FBIINIT3:	regname = "FbiInit3"; break;
	case FBIINIT4:	regname = "FbiInit4"; break;
	case FBIINIT5:	regname = "FbiInit5"; break;
	case FBIINIT6:	regname = "FbiInit6"; break;
	default:	regname = NULL;       break;
	}
	if (regname == NULL)
		r_ddprintk("sst_write(%#x, %#x)\n", reg, val);
	else
		r_dprintk(" sst_write(%s, %#x)\n", regname, val);
}
#else /*  (SST_DEBUG_REG > 0) */
#define sst_dbg_print_read_reg(reg, val)
#define sst_dbg_print_write_reg(reg, val)
#endif /*  (SST_DEBUG_REG > 0) */

/*
 * hardware access functions
 */

/* register access */
#define sst_read(reg)
#define sst_write(reg,val)
#define sst_set_bits(reg,val)
#define sst_unset_bits(reg,val)
#define sst_dac_read(reg)
#define sst_dac_write(reg,val)
#define dac_i_read(reg)
#define dac_i_write(reg,val)

static inline u32 __sst_read(u8 __iomem *vbase, u32 reg)
{}

static inline void __sst_write(u8 __iomem *vbase, u32 reg, u32 val)
{}

static inline void __sst_set_bits(u8 __iomem *vbase, u32 reg, u32 val)
{}

static inline void __sst_unset_bits(u8 __iomem *vbase, u32 reg, u32 val)
{}

/*
 * wait for the fbi chip. ASK: what happens if the fbi is stuck ?
 *
 * the FBI is supposed to be ready if we receive 5 time
 * in a row a "idle" answer to our requests
 */

#define sst_wait_idle()

static int __sst_wait_idle(u8 __iomem *vbase)
{}


/* dac access */
/* dac_read should be remaped to FbiInit2 (via the pci reg init_enable) */
static u8 __sst_dac_read(u8 __iomem *vbase, u8 reg)
{}

static void __sst_dac_write(u8 __iomem *vbase, u8 reg, u8 val)
{}

/* indexed access to ti/att dacs */
static u32 __dac_i_read(u8 __iomem *vbase, u8 reg)
{}
static void __dac_i_write(u8 __iomem *vbase, u8 reg,u8 val)
{}

/* compute the m,n,p  , returns the real freq
 * (ics datasheet :  N <-> N1 , P <-> N2)
 *
 * Fout= Fref * (M+2)/( 2^P * (N+2))
 *  we try to get close to the asked freq
 *  with P as high, and M as low as possible
 * range:
 * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63
 * ics    : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31
 * we'll use the lowest limitation, should be precise enouth
 */
static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t)
{}

/*
 * clear lfb screen
 */
static void sstfb_clear_screen(struct fb_info *info)
{}


/**
 *      sstfb_check_var - Optional function.  Validates a var passed in.
 *      @var: frame buffer variable screen structure
 *      @info: frame buffer structure that represents a single frame buffer
 *
 *	Limit to the abilities of a single chip as SLI is not supported
 *	by this driver.
 */

static int sstfb_check_var(struct fb_var_screeninfo *var,
		struct fb_info *info)
{}

/**
 *      sstfb_set_par - Optional function.  Alters the hardware state.
 *      @info: frame buffer structure that represents a single frame buffer
 */
static int sstfb_set_par(struct fb_info *info)
{}

/**
 *      sstfb_setcolreg - Optional function. Sets a color register.
 *      @regno: hardware colormap register
 *      @red: frame buffer colormap structure
 *      @green: The green value which can be up to 16 bits wide
 *      @blue:  The blue value which can be up to 16 bits wide.
 *      @transp: If supported the alpha value which can be up to 16 bits wide.
 *      @info: frame buffer info structure
 */
static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                           u_int transp, struct fb_info *info)
{}

static void sstfb_setvgapass( struct fb_info *info, int enable )
{}

#ifdef CONFIG_FB_DEVICE
static ssize_t store_vgapass(struct device *device, struct device_attribute *attr,
			const char *buf, size_t count)
{}

static ssize_t show_vgapass(struct device *device, struct device_attribute *attr,
			char *buf)
{}

static struct device_attribute device_attrs[] =;
#endif

static int sstfb_ioctl(struct fb_info *info, unsigned int cmd,
			unsigned long arg)
{}


/*
 * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) - Voodoo2 only
 */
#if 0
static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
	struct sstfb_par *par = info->par;
	u32 stride = info->fix.line_length;

	if (!IS_VOODOO2(par))
		return;

	sst_write(BLTSRCBASEADDR, 0);
	sst_write(BLTDSTBASEADDR, 0);
	sst_write(BLTROP, BLTROP_COPY);
	sst_write(BLTXYSTRIDES, stride | (stride << 16));
	sst_write(BLTSRCXY, area->sx | (area->sy << 16));
	sst_write(BLTDSTXY, area->dx | (area->dy << 16));
	sst_write(BLTSIZE, area->width | (area->height << 16));
	sst_write(BLTCOMMAND, BLT_SCR2SCR_BITBLT | LAUNCH_BITBLT |
		(BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) );
	sst_wait_idle();
}
#endif


/*
 * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only
 */
#if 0
static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
	struct sstfb_par *par = info->par;
	u32 stride = info->fix.line_length;

	if (!IS_VOODOO2(par))
		return;

	sst_write(BLTCLIPX, info->var.xres);
	sst_write(BLTCLIPY, info->var.yres);

	sst_write(BLTDSTBASEADDR, 0);
	sst_write(BLTCOLOR, rect->color);
	sst_write(BLTROP, rect->rop == ROP_COPY ? BLTROP_COPY : BLTROP_XOR);
	sst_write(BLTXYSTRIDES, stride | (stride << 16));
	sst_write(BLTDSTXY, rect->dx | (rect->dy << 16));
	sst_write(BLTSIZE, rect->width | (rect->height << 16));
	sst_write(BLTCOMMAND, BLT_RECFILL_BITBLT | LAUNCH_BITBLT
		 | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) );
	sst_wait_idle();
}
#endif



/*
 * get lfb size
 */
static int sst_get_memsize(struct fb_info *info, __u32 *memsize)
{}


/*
 * DAC detection routines
 */

/* fbi should be idle, and fifo emty and mem disabled */
/* supposed to detect AT&T ATT20C409 and Ti TVP3409 ramdacs */

static int sst_detect_att(struct fb_info *info)
{}

static int sst_detect_ti(struct fb_info *info)
{}

/*
 * try to detect ICS5342  ramdac
 * we get the 1st byte (M value) of preset f1,f7 and fB
 * why those 3 ? mmmh... for now, i'll do it the glide way...
 * and ask questions later. anyway, it seems that all the freq registers are
 * really at their default state (cf specs) so i ask again, why those 3 regs ?
 * mmmmh.. it seems that's much more ugly than i thought. we use f0 and fA for
 * pll programming, so in fact, we *hope* that the f1, f7 & fB won't be
 * touched...
 * is it really safe ? how can i reset this ramdac ? geee...
 */
static int sst_detect_ics(struct fb_info *info)
{}


/*
 * gfx, video, pci fifo should be reset, dram refresh disabled
 * see detect_dac
 */

static int sst_set_pll_att_ti(struct fb_info *info,
		const struct pll_timing *t, const int clock)
{}

static int sst_set_pll_ics(struct fb_info *info,
		const struct pll_timing *t, const int clock)
{}

static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp)
{}

static void sst_set_vidmod_ics(struct fb_info *info, const int bpp)
{}

/*
 * detect dac type
 * prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset,
 * dram refresh disabled, FbiInit remaped.
 * TODO: mmh.. maybe i should put the "prerequisite" in the func ...
 */


static struct dac_switch dacs[] =;

static int sst_detect_dactype(struct fb_info *info, struct sstfb_par *par)
{}

/*
 * Internal Routines
 */
static int sst_init(struct fb_info *info, struct sstfb_par *par)
{}

static void sst_shutdown(struct fb_info *info)
{}

/*
 * Interface to the world
 */
static int sstfb_setup(char *options)
{}


static const struct fb_ops sstfb_ops =;

static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{}

static void sstfb_remove(struct pci_dev *pdev)
{}


static const struct pci_device_id sstfb_id_tbl[] =;

static struct pci_driver sstfb_driver =;


static int sstfb_init(void)
{}

static void sstfb_exit(void)
{}


module_init();
module_exit(sstfb_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

module_param(mem, int, 0);
MODULE_PARM_DESC();
module_param(vgapass, bool, 0);
MODULE_PARM_DESC();
module_param(clipping, bool, 0);
MODULE_PARM_DESC();
module_param(gfxclk, int, 0);
MODULE_PARM_DESC();
module_param(slowpci, bool, 0);
MODULE_PARM_DESC();
module_param(mode_option, charp, 0);
MODULE_PARM_DESC();