Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    3)  * linux/drivers/video/sstfb.c -- voodoo graphics frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    5)  *     Copyright (c) 2000-2002 Ghozlane Toumi <gtoumi@laposte.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    7)  *     Created 15 Jan 2000 by Ghozlane Toumi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    9)  * Contributions (and many thanks) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   11)  * 03/2001 James Simmons   <jsimmons@infradead.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   12)  * 04/2001 Paul Mundt      <lethal@chaoticdreams.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   13)  * 05/2001 Urs Ganse       <ursg@uni.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   14)  *	(initial work on voodoo2 port, interlace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   15)  * 09/2002 Helge Deller    <deller@gmx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   16)  *	(enable driver on big-endian machines (hppa), ioctl fixes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   17)  * 12/2002 Helge Deller    <deller@gmx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   18)  *	(port driver to new frambuffer infrastructure)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   19)  * 01/2003 Helge Deller    <deller@gmx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   20)  *	(initial work on fb hardware acceleration for voodoo2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   21)  * 08/2006 Alan Cox 	   <alan@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   22)  *	Remove never finished and bogus 24/32bit support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   23)  *	Clean up macro abuse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   24)  *	Minor tidying for format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   25)  * 12/2006 Helge Deller    <deller@gmx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   26)  *	add /sys/class/graphics/fbX/vgapass sysfs-interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   27)  *	add module option "mode_option" to set initial screen mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   28)  *	use fbdev default videomode database
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   29)  *	remove debug functions from ioctl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   30)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   33)  * The voodoo1 has the following memory mapped address space:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   34)  * 0x000000 - 0x3fffff : registers              (4MB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   35)  * 0x400000 - 0x7fffff : linear frame buffer    (4MB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   36)  * 0x800000 - 0xffffff : texture memory         (8MB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   37)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   39) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   40)  * misc notes, TODOs, toASKs, and deep thoughts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   42) -TODO: at one time or another test that the mode is acceptable by the monitor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   43) -ASK: Can I choose different ordering for the color bitfields (rgba argb ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   44)       which one should i use ? is there any preferred one ? It seems ARGB is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   45)       the one ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   46) -TODO: in  set_var check the validity of timings (hsync vsync)...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   47) -TODO: check and recheck the use of sst_wait_idle : we don't flush the fifo via
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   48)        a nop command. so it's ok as long as the commands we pass don't go
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   49)        through the fifo. warning: issuing a nop command seems to need pci_fifo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   50) -FIXME: in case of failure in the init sequence, be sure we return to a safe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   51)         state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   52) - FIXME: Use accelerator for 2D scroll
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   53) -FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   54)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   56) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   57)  * debug info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   58)  * SST_DEBUG : enable debugging
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   59)  * SST_DEBUG_REG : debug registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   60)  *   0 :  no debug
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   61)  *   1 : dac calls, [un]set_bits, FbiInit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   62)  *   2 : insane debug level (log every register read/write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   63)  * SST_DEBUG_FUNC : functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   64)  *   0 : no debug
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   65)  *   1 : function call / debug ioctl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   66)  *   2 : variables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   67)  *   3 : flood . you don't want to do that. trust me.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   68)  * SST_DEBUG_VAR : debug display/var structs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   69)  *   0 : no debug
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   70)  *   1 : dumps display, fb_var
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   71)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   72)  * sstfb specific ioctls:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   73)  *   		toggle vga (0x46db) : toggle vga_pass_through
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   74)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   76) #undef SST_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   79) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   80)  * Includes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   81)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   83) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   84) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   85) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   86) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   87) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   88) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   89) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   90) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   91) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   92) #include <video/sstfb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   95) /* initialized by setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   97) static bool vgapass;		/* enable VGA passthrough cable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   98) static int mem;			/* mem size in MB, 0 = autodetect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   99) static bool clipping = 1;	/* use clipping (slower, safer) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  100) static int gfxclk;		/* force FBI freq in Mhz . Dangerous */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  101) static bool slowpci;		/* slow PCI settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  103) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  104)   Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  106) #define DEFAULT_VIDEO_MODE "640x480@60"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  108) static char *mode_option = DEFAULT_VIDEO_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  110) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  111) 	ID_VOODOO1 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  112) 	ID_VOODOO2 = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  115) #define IS_VOODOO2(par) ((par)->type == ID_VOODOO2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  117) static struct sst_spec voodoo_spec[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  118)  { .name = "Voodoo Graphics", .default_gfx_clock = 50000, .max_gfxclk = 60 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  119)  { .name = "Voodoo2",	      .default_gfx_clock = 75000, .max_gfxclk = 85 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  120) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  123) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  124)  * debug functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  125)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  127) #if (SST_DEBUG_REG > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  128) static void sst_dbg_print_read_reg(u32 reg, u32 val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  129) 	const char *regname;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  130) 	switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  131) 	case FBIINIT0:	regname = "FbiInit0"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  132) 	case FBIINIT1:	regname = "FbiInit1"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  133) 	case FBIINIT2:	regname = "FbiInit2"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  134) 	case FBIINIT3:	regname = "FbiInit3"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  135) 	case FBIINIT4:	regname = "FbiInit4"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  136) 	case FBIINIT5:	regname = "FbiInit5"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  137) 	case FBIINIT6:	regname = "FbiInit6"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  138) 	default:	regname = NULL;       break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  139) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  140) 	if (regname == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  141) 		r_ddprintk("sst_read(%#x): %#x\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  142) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  143) 		r_dprintk(" sst_read(%s): %#x\n", regname, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  146) static void sst_dbg_print_write_reg(u32 reg, u32 val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  147) 	const char *regname;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  148) 	switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  149) 	case FBIINIT0:	regname = "FbiInit0"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  150) 	case FBIINIT1:	regname = "FbiInit1"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  151) 	case FBIINIT2:	regname = "FbiInit2"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  152) 	case FBIINIT3:	regname = "FbiInit3"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  153) 	case FBIINIT4:	regname = "FbiInit4"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  154) 	case FBIINIT5:	regname = "FbiInit5"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  155) 	case FBIINIT6:	regname = "FbiInit6"; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  156) 	default:	regname = NULL;       break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  157) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  158) 	if (regname == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  159) 		r_ddprintk("sst_write(%#x, %#x)\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  160) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  161) 		r_dprintk(" sst_write(%s, %#x)\n", regname, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  163) #else /*  (SST_DEBUG_REG > 0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  164) #  define sst_dbg_print_read_reg(reg, val)	do {} while(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  165) #  define sst_dbg_print_write_reg(reg, val)	do {} while(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  166) #endif /*  (SST_DEBUG_REG > 0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  167) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  168) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  169)  * hardware access functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  170)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  172) /* register access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  173) #define sst_read(reg)		__sst_read(par->mmio_vbase, reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  174) #define sst_write(reg,val)	__sst_write(par->mmio_vbase, reg, val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  175) #define sst_set_bits(reg,val)	__sst_set_bits(par->mmio_vbase, reg, val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  176) #define sst_unset_bits(reg,val)	__sst_unset_bits(par->mmio_vbase, reg, val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  177) #define sst_dac_read(reg)	__sst_dac_read(par->mmio_vbase, reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  178) #define sst_dac_write(reg,val)	__sst_dac_write(par->mmio_vbase, reg, val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  179) #define dac_i_read(reg)		__dac_i_read(par->mmio_vbase, reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  180) #define dac_i_write(reg,val)	__dac_i_write(par->mmio_vbase, reg, val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  182) static inline u32 __sst_read(u8 __iomem *vbase, u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  184) 	u32 ret = readl(vbase + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  185) 	sst_dbg_print_read_reg(reg, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  186) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  188) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  189) static inline void __sst_write(u8 __iomem *vbase, u32 reg, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  191) 	sst_dbg_print_write_reg(reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  192) 	writel(val, vbase + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  195) static inline void __sst_set_bits(u8 __iomem *vbase, u32 reg, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  197) 	r_dprintk("sst_set_bits(%#x, %#x)\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  198) 	__sst_write(vbase, reg, __sst_read(vbase, reg) | val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  201) static inline void __sst_unset_bits(u8 __iomem *vbase, u32 reg, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  203) 	r_dprintk("sst_unset_bits(%#x, %#x)\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  204) 	__sst_write(vbase, reg, __sst_read(vbase, reg) & ~val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  207) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  208)  * wait for the fbi chip. ASK: what happens if the fbi is stuck ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  209)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  210)  * the FBI is supposed to be ready if we receive 5 time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  211)  * in a row a "idle" answer to our requests
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  212)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  214) #define sst_wait_idle() __sst_wait_idle(par->mmio_vbase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  215) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  216) static int __sst_wait_idle(u8 __iomem *vbase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  218) 	int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  220) 	/* if (doFBINOP) __sst_write(vbase, NOPCMD, 0); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  222) 	while(1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  223) 		if (__sst_read(vbase, STATUS) & STATUS_FBI_BUSY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  224) 			f_dddprintk("status: busy\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  225) /* FIXME basically, this is a busy wait. maybe not that good. oh well;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  226)  * this is a small loop after all.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  227)  * Or maybe we should use mdelay() or udelay() here instead ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  228) 			count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  229) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  230) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  231) 			f_dddprintk("status: idle(%d)\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  232) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  233) 		if (count >= 5) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  234) /* XXX  do something to avoid hanging the machine if the voodoo is out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  235) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  238) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  239) /* dac access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  240) /* dac_read should be remaped to FbiInit2 (via the pci reg init_enable) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  241) static u8 __sst_dac_read(u8 __iomem *vbase, u8 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  243) 	u8 ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  244) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  245) 	reg &= 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  246) 	__sst_write(vbase, DAC_DATA, ((u32)reg << 8) | DAC_READ_CMD );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  247) 	__sst_wait_idle(vbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  248) 	/* udelay(10); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  249) 	ret = __sst_read(vbase, DAC_READ) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  250) 	r_dprintk("sst_dac_read(%#x): %#x\n", reg, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  252) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  254) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  255) static void __sst_dac_write(u8 __iomem *vbase, u8 reg, u8 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  257) 	r_dprintk("sst_dac_write(%#x, %#x)\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  258) 	reg &= 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  259) 	__sst_write(vbase, DAC_DATA,(((u32)reg << 8)) | (u32)val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  260) 	__sst_wait_idle(vbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  263) /* indexed access to ti/att dacs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  264) static u32 __dac_i_read(u8 __iomem *vbase, u8 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  266) 	u32 ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  268) 	__sst_dac_write(vbase, DACREG_ADDR_I, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  269) 	ret = __sst_dac_read(vbase, DACREG_DATA_I);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  270) 	r_dprintk("sst_dac_read_i(%#x): %#x\n", reg, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  271) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  273) static void __dac_i_write(u8 __iomem *vbase, u8 reg,u8 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  275) 	r_dprintk("sst_dac_write_i(%#x, %#x)\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  276) 	__sst_dac_write(vbase, DACREG_ADDR_I, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  277) 	__sst_dac_write(vbase, DACREG_DATA_I, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  279) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  280) /* compute the m,n,p  , returns the real freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  281)  * (ics datasheet :  N <-> N1 , P <-> N2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  282)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  283)  * Fout= Fref * (M+2)/( 2^P * (N+2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  284)  *  we try to get close to the asked freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  285)  *  with P as high, and M as low as possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  286)  * range:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  287)  * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  288)  * ics    : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  289)  * we'll use the lowest limitation, should be precise enouth
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  290)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  291) static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  293) 	int m, m2, n, p, best_err, fout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  294) 	int best_n = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  295) 	int best_m = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  297) 	best_err = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  298) 	p = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  299) 	/* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  300) 	while (((1 << p) * freq > VCO_MAX) && (p >= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  301) 		p--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  302) 	if (p == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  303) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  304) 	for (n = 1; n < 32; n++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  305) 		/* calc 2 * m so we can round it later*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  306) 		m2 = (2 * freq * (1 << p) * (n + 2) ) / DAC_FREF - 4 ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  307) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  308) 		m = (m2 % 2 ) ? m2/2+1 : m2/2 ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  309) 		if (m >= 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  310) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  311) 		fout = (DAC_FREF * (m + 2)) / ((1 << p) * (n + 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  312) 		if ((abs(fout - freq) < best_err) && (m > 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  313) 			best_n = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  314) 			best_m = m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  315) 			best_err = abs(fout - freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  316) 			/* we get the lowest m , allowing 0.5% error in freq*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  317) 			if (200*best_err < freq) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  318) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  319) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  320) 	if (best_n == -1)  /* unlikely, but who knows ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  321) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  322) 	t->p = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  323) 	t->n = best_n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  324) 	t->m = best_m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  325) 	*freq_out = (DAC_FREF * (t->m + 2)) / ((1 << t->p) * (t->n + 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  326) 	f_ddprintk ("m: %d, n: %d, p: %d, F: %dKhz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  327) 		  t->m, t->n, t->p, *freq_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  328) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  331) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  332)  * clear lfb screen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  333)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  334) static void sstfb_clear_screen(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  335) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  336) 	/* clear screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  337) 	fb_memset(info->screen_base, 0, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  341) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  342)  *      sstfb_check_var - Optional function.  Validates a var passed in.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  343)  *      @var: frame buffer variable screen structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  344)  *      @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  345)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  346)  *	Limit to the abilities of a single chip as SLI is not supported
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  347)  *	by this driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  348)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  350) static int sstfb_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  351) 		struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  353) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  354) 	int hSyncOff   = var->xres + var->right_margin + var->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  355) 	int vSyncOff   = var->yres + var->lower_margin + var->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  356) 	int vBackPorch = var->left_margin, yDim = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  357) 	int vSyncOn    = var->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  358) 	int tiles_in_X, real_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  359) 	unsigned int freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  361) 	if (sst_calc_pll(PICOS2KHZ(var->pixclock), &freq, &par->pll)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  362) 		printk(KERN_ERR "sstfb: Pixclock at %ld KHZ out of range\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  363) 				PICOS2KHZ(var->pixclock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  364) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  365) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  366) 	var->pixclock = KHZ2PICOS(freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  367) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  368) 	if (var->vmode & FB_VMODE_INTERLACED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  369) 		vBackPorch += (vBackPorch % 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  370) 	if (var->vmode & FB_VMODE_DOUBLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  371) 		vBackPorch <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  372) 		yDim <<=1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  373) 		vSyncOn <<=1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  374) 		vSyncOff <<=1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  375) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  376) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  377) 	switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  378) 	case 0 ... 16 :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  379) 		var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  380) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  381) 	default :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  382) 		printk(KERN_ERR "sstfb: Unsupported bpp %d\n", var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  383) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  384) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  385) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  386) 	/* validity tests */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  387) 	if (var->xres <= 1 || yDim <= 0 || var->hsync_len <= 1  ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  388) 	    hSyncOff <= 1  || var->left_margin <= 2  || vSyncOn <= 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  389) 	    vSyncOff <= 0 || vBackPorch <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  390) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  391) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  393) 	if (IS_VOODOO2(par)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  394) 		/* Voodoo 2 limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  395) 		tiles_in_X = (var->xres + 63 ) / 64 * 2;		
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  396) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  397) 		if (var->xres  > POW2(11) || yDim >= POW2(11)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  398) 			printk(KERN_ERR "sstfb: Unsupported resolution %dx%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  399) 			         var->xres, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  400) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  401) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  402) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  403) 		if (var->hsync_len > POW2(9) || hSyncOff > POW2(11) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  404) 		    var->left_margin - 2 >= POW2(9) || vSyncOn >= POW2(13) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  405) 		    vSyncOff >= POW2(13) || vBackPorch >= POW2(9) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  406) 		    tiles_in_X >= POW2(6) || tiles_in_X <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  407) 			printk(KERN_ERR "sstfb: Unsupported timings\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  408) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  409) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  410) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  411) 		/* Voodoo limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  412) 		tiles_in_X = (var->xres + 63 ) / 64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  413) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  414) 		if (var->vmode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  415) 			printk(KERN_ERR "sstfb: Interlace/doublescan not supported %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  416) 				var->vmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  417) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  418) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  419) 		if (var->xres > POW2(10) || var->yres >= POW2(10)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  420) 			printk(KERN_ERR "sstfb: Unsupported resolution %dx%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  421) 			         var->xres, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  422) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  423) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  424) 		if (var->hsync_len > POW2(8) || hSyncOff - 1 > POW2(10) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  425) 		    var->left_margin - 2 >= POW2(8) || vSyncOn >= POW2(12) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  426) 		    vSyncOff >= POW2(12) || vBackPorch >= POW2(8) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  427) 		    tiles_in_X >= POW2(4) || tiles_in_X <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  428) 			printk(KERN_ERR "sstfb: Unsupported timings\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  429) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  430) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  431) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  433) 	/* it seems that the fbi uses tiles of 64x16 pixels to "map" the mem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  434) 	/* FIXME: i don't like this... looks wrong */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  435) 	real_length = tiles_in_X  * (IS_VOODOO2(par) ? 32 : 64 )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  436) 	              * ((var->bits_per_pixel == 16) ? 2 : 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  437) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  438) 	if (real_length * yDim > info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  439) 		printk(KERN_ERR "sstfb: Not enough video memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  440) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  441) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  442) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  443) 	var->sync &= (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  444) 	var->vmode &= (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  445) 	var->xoffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  446) 	var->yoffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  447) 	var->height  = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  448) 	var->width   = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  449) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  450) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  451) 	 * correct the color bit fields
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  452) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  453) 	/* var->{red|green|blue}.msb_right = 0; */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  455) 	switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  456) 	case 16:	/* RGB 565  LfbMode 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  457) 		var->red.length    = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  458) 		var->green.length  = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  459) 		var->blue.length   = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  460) 		var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  461) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  462) 		var->red.offset    = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  463) 		var->green.offset  = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  464) 		var->blue.offset   = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  465) 		var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  466) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  467) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  468) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  469) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  470) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  472) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  473) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  474)  *      sstfb_set_par - Optional function.  Alters the hardware state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  475)  *      @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  476)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  477) static int sstfb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  479) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  480) 	u32 lfbmode, fbiinit1, fbiinit2, fbiinit3, fbiinit5, fbiinit6=0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  481) 	struct pci_dev *sst_dev = par->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  482) 	unsigned int freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  483) 	int ntiles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  485) 	par->hSyncOff	= info->var.xres + info->var.right_margin + info->var.left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  486) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  487) 	par->yDim 	= info->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  488) 	par->vSyncOn 	= info->var.vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  489) 	par->vSyncOff	= info->var.yres + info->var.lower_margin + info->var.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  490) 	par->vBackPorch = info->var.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  491) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  492) 	/* We need par->pll */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  493) 	sst_calc_pll(PICOS2KHZ(info->var.pixclock), &freq, &par->pll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  494) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  495) 	if (info->var.vmode & FB_VMODE_INTERLACED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  496) 		par->vBackPorch += (par->vBackPorch % 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  497) 	if (info->var.vmode & FB_VMODE_DOUBLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  498) 		par->vBackPorch <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  499) 		par->yDim <<=1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  500) 		par->vSyncOn <<=1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  501) 		par->vSyncOff <<=1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  502) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  504) 	if (IS_VOODOO2(par)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  505) 		/* voodoo2 has 32 pixel wide tiles , BUT strange things
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  506) 		   happen with odd number of tiles */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  507) 		par->tiles_in_X = (info->var.xres + 63 ) / 64 * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  508) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  509) 		/* voodoo1 has 64 pixels wide tiles. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  510) 		par->tiles_in_X = (info->var.xres + 63 ) / 64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  511) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  513) 	f_ddprintk("hsync_len hSyncOff vsync_len vSyncOff\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  514) 	f_ddprintk("%-7d %-8d %-7d %-8d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  515) 	           info->var.hsync_len, par->hSyncOff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  516) 	           par->vSyncOn, par->vSyncOff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  517) 	f_ddprintk("left_margin upper_margin xres yres Freq\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  518) 	f_ddprintk("%-10d %-10d %-4d %-4d %-8ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  519) 	           info->var.left_margin, info->var.upper_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  520) 	           info->var.xres, info->var.yres, PICOS2KHZ(info->var.pixclock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  521) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  522) 	sst_write(NOPCMD, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  523) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  524) 	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  525) 	sst_set_bits(FBIINIT1, VIDEO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  526) 	sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  527) 	sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  528) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  529) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  530) 	/*sst_unset_bits (FBIINIT0, FBI_RESET); / reenable FBI ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  531) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  532) 	sst_write(BACKPORCH, par->vBackPorch << 16 | (info->var.left_margin - 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  533) 	sst_write(VIDEODIMENSIONS, par->yDim << 16 | (info->var.xres - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  534) 	sst_write(HSYNC, (par->hSyncOff - 1) << 16 | (info->var.hsync_len - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  535) 	sst_write(VSYNC,       par->vSyncOff << 16 | par->vSyncOn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  536) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  537) 	fbiinit2 = sst_read(FBIINIT2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  538) 	fbiinit3 = sst_read(FBIINIT3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  539) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  540) 	/* everything is reset. we enable fbiinit2/3 remap : dac access ok */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  541) 	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  542) 	                       PCI_EN_INIT_WR | PCI_REMAP_DAC );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  543) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  544) 	par->dac_sw.set_vidmod(info, info->var.bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  545) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  546) 	/* set video clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  547) 	par->dac_sw.set_pll(info, &par->pll, VID_CLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  548) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  549) 	/* disable fbiinit2/3 remap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  550) 	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  551) 	                       PCI_EN_INIT_WR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  552) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  553) 	/* restore fbiinit2/3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  554) 	sst_write(FBIINIT2,fbiinit2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  555) 	sst_write(FBIINIT3,fbiinit3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  556) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  557) 	fbiinit1 = (sst_read(FBIINIT1) & VIDEO_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  558) 	            | EN_DATA_OE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  559) 	            | EN_BLANK_OE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  560) 	            | EN_HVSYNC_OE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  561) 	            | EN_DCLK_OE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  562) 		 /* | (15 << TILES_IN_X_SHIFT) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  563) 	            | SEL_INPUT_VCLK_2X
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  564) 		 /* | (2 << VCLK_2X_SEL_DEL_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  565) 	            | (2 << VCLK_DEL_SHIFT) */;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  566) /* try with vclk_in_delay =0 (bits 29:30) , vclk_out_delay =0 (bits(27:28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  567)  in (near) future set them accordingly to revision + resolution (cf glide)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  568)  first understand what it stands for :)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  569)  FIXME: there are some artefacts... check for the vclk_in_delay
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  570)  lets try with 6ns delay in both vclk_out & in...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  571)  doh... they're still there :\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  572) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  573) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  574) 	ntiles = par->tiles_in_X;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  575) 	if (IS_VOODOO2(par)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  576) 		fbiinit1 |= ((ntiles & 0x20) >> 5) << TILES_IN_X_MSB_SHIFT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  577) 		            | ((ntiles & 0x1e) >> 1) << TILES_IN_X_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  578) /* as the only value of importance for us in fbiinit6 is tiles in X (lsb),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  579)    and as reading fbinit 6 will return crap (see FBIINIT6_DEFAULT) we just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  580)    write our value. BTW due to the dac unable to read odd number of tiles, this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  581)    field is always null ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  582) 		fbiinit6 = (ntiles & 0x1) << TILES_IN_X_LSB_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  583) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  584) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  585) 		fbiinit1 |= ntiles << TILES_IN_X_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  586) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  587) 	switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  588) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  589) 		fbiinit1 |=  SEL_SOURCE_VCLK_2X_SEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  590) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  591) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  592) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  593) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  594) 	sst_write(FBIINIT1, fbiinit1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  595) 	if (IS_VOODOO2(par)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  596) 		sst_write(FBIINIT6, fbiinit6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  597) 		fbiinit5=sst_read(FBIINIT5) & FBIINIT5_MASK ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  598) 		if (info->var.vmode & FB_VMODE_INTERLACED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  599) 			fbiinit5 |= INTERLACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  600) 		if (info->var.vmode & FB_VMODE_DOUBLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  601) 			fbiinit5 |= VDOUBLESCAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  602) 		if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  603) 			fbiinit5 |= HSYNC_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  604) 		if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  605) 			fbiinit5 |= VSYNC_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  606) 		sst_write(FBIINIT5, fbiinit5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  607) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  608) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  609) 	sst_unset_bits(FBIINIT1, VIDEO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  610) 	sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  611) 	sst_set_bits(FBIINIT2, EN_DRAM_REFRESH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  612) 	/* disables fbiinit writes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  613) 	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  614) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  615) 	/* set lfbmode : set mode + front buffer for reads/writes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  616) 	   + disable pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  617) 	switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  618) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  619) 		lfbmode = LFB_565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  620) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  621) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  622) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  623) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  624) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  625) #if defined(__BIG_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  626) 	/* Enable byte-swizzle functionality in hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  627) 	 * With this enabled, all our read- and write-accesses to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  628) 	 * the voodoo framebuffer can be done in native format, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  629) 	 * the hardware will automatically convert it to little-endian.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  630) 	 * - tested on HP-PARISC, Helge Deller <deller@gmx.de> */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  631) 	lfbmode |= ( LFB_WORD_SWIZZLE_WR | LFB_BYTE_SWIZZLE_WR |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  632) 		     LFB_WORD_SWIZZLE_RD | LFB_BYTE_SWIZZLE_RD );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  633) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  634) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  635) 	if (clipping) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  636) 		sst_write(LFBMODE, lfbmode | EN_PXL_PIPELINE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  637) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  638) 	 * Set "clipping" dimensions. If clipping is disabled and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  639) 	 * writes to offscreen areas of the framebuffer are performed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  640) 	 * the "behaviour is undefined" (_very_ undefined) - Urs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  641) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  642) 	/* btw, it requires enabling pixel pipeline in LFBMODE .
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  643) 	   off screen read/writes will just wrap and read/print pixels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  644) 	   on screen. Ugly but not that dangerous */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  645) 		f_ddprintk("setting clipping dimensions 0..%d, 0..%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  646) 		            info->var.xres - 1, par->yDim - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  647) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  648) 		sst_write(CLIP_LEFT_RIGHT, info->var.xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  649) 		sst_write(CLIP_LOWY_HIGHY, par->yDim);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  650) 		sst_set_bits(FBZMODE, EN_CLIPPING | EN_RGB_WRITE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  651) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  652) 		/* no clipping : direct access, no pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  653) 		sst_write(LFBMODE, lfbmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  654) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  655) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  657) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  658) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  659)  *      sstfb_setcolreg - Optional function. Sets a color register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  660)  *      @regno: hardware colormap register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  661)  *      @red: frame buffer colormap structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  662)  *      @green: The green value which can be up to 16 bits wide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  663)  *      @blue:  The blue value which can be up to 16 bits wide.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  664)  *      @transp: If supported the alpha value which can be up to 16 bits wide.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  665)  *      @info: frame buffer info structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  666)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  667) static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  668)                            u_int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  669) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  670) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  671) 	u32 col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  672) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  673) 	f_dddprintk("sstfb_setcolreg\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  674) 	f_dddprintk("%-2d rgbt: %#x, %#x, %#x, %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  675) 	            regno, red, green, blue, transp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  676) 	if (regno > 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  677) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  678) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  679) 	red    >>= (16 - info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  680) 	green  >>= (16 - info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  681) 	blue   >>= (16 - info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  682) 	transp >>= (16 - info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  683) 	col = (red << info->var.red.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  684) 	    | (green << info->var.green.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  685) 	    | (blue  << info->var.blue.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  686) 	    | (transp << info->var.transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  687) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  688) 	par->palette[regno] = col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  689) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  690) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  692) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  693) static void sstfb_setvgapass( struct fb_info *info, int enable )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  694) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  695) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  696) 	struct pci_dev *sst_dev = par->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  697) 	u32 fbiinit0, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  698) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  699) 	enable = enable ? 1:0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  700) 	if (par->vgapass == enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  701) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  702) 	par->vgapass = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  703) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  704) 	pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  705) 	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  706) 			       tmp | PCI_EN_INIT_WR );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  707) 	fbiinit0 = sst_read (FBIINIT0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  708) 	if (par->vgapass) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  709) 		sst_write(FBIINIT0, fbiinit0 & ~DIS_VGA_PASSTHROUGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  710) 		fb_info(info, "Enabling VGA pass-through\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  711) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  712) 		sst_write(FBIINIT0, fbiinit0 | DIS_VGA_PASSTHROUGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  713) 		fb_info(info, "Disabling VGA pass-through\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  714) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  715) 	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  716) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  717) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  718) static ssize_t store_vgapass(struct device *device, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  719) 			const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  720) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  721) 	struct fb_info *info = dev_get_drvdata(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  722) 	char ** last = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  723) 	int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  724) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  725) 	val = simple_strtoul(buf, last, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  726) 	sstfb_setvgapass(info, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  727) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  728) 	return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  729) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  730) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  731) static ssize_t show_vgapass(struct device *device, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  732) 			char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  733) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  734) 	struct fb_info *info = dev_get_drvdata(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  735) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  736) 	return sprintf(buf, "%d\n", par->vgapass);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  738) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  739) static struct device_attribute device_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  740) 	__ATTR(vgapass, S_IRUGO|S_IWUSR, show_vgapass, store_vgapass)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  741) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  742) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  743) static int sstfb_ioctl(struct fb_info *info, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  744) 			unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  745) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  746) 	struct sstfb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  747) 	u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  748) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  749) 	switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  750) 	/* set/get VGA pass_through mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  751) 	case SSTFB_SET_VGAPASS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  752) 		if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  753) 			return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  754) 		sstfb_setvgapass(info, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  755) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  756) 	case SSTFB_GET_VGAPASS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  757) 		par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  758) 		val = par->vgapass;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  759) 		if (copy_to_user((void __user *)arg, &val, sizeof(val)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  760) 			return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  761) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  762) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  763) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  764) 	return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  765) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  766) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  767) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  768) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  769)  * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) - Voodoo2 only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  770)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  771) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  772) static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  773) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  774) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  775) 	u32 stride = info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  776)    
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  777) 	if (!IS_VOODOO2(par))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  778) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  779) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  780) 	sst_write(BLTSRCBASEADDR, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  781) 	sst_write(BLTDSTBASEADDR, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  782) 	sst_write(BLTROP, BLTROP_COPY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  783) 	sst_write(BLTXYSTRIDES, stride | (stride << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  784) 	sst_write(BLTSRCXY, area->sx | (area->sy << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  785) 	sst_write(BLTDSTXY, area->dx | (area->dy << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  786) 	sst_write(BLTSIZE, area->width | (area->height << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  787) 	sst_write(BLTCOMMAND, BLT_SCR2SCR_BITBLT | LAUNCH_BITBLT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  788) 		(BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  789) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  791) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  792) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  793) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  794) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  795)  * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  796)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  797) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  798) static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  799) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  800) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  801) 	u32 stride = info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  802) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  803) 	if (!IS_VOODOO2(par))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  804) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  805)    	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  806) 	sst_write(BLTCLIPX, info->var.xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  807) 	sst_write(BLTCLIPY, info->var.yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  808) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  809) 	sst_write(BLTDSTBASEADDR, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  810) 	sst_write(BLTCOLOR, rect->color);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  811) 	sst_write(BLTROP, rect->rop == ROP_COPY ? BLTROP_COPY : BLTROP_XOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  812) 	sst_write(BLTXYSTRIDES, stride | (stride << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  813) 	sst_write(BLTDSTXY, rect->dx | (rect->dy << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  814) 	sst_write(BLTSIZE, rect->width | (rect->height << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  815) 	sst_write(BLTCOMMAND, BLT_RECFILL_BITBLT | LAUNCH_BITBLT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  816) 		 | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  817) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  819) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  820) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  821) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  822) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  823) /* 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  824)  * get lfb size 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  825)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  826) static int sst_get_memsize(struct fb_info *info, __u32 *memsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  827) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  828) 	u8 __iomem *fbbase_virt = info->screen_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  829) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  830) 	/* force memsize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  831) 	if (mem >= 1  && mem <= 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  832) 		*memsize = (mem * 0x100000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  833) 		printk(KERN_INFO "supplied memsize: %#x\n", *memsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  834) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  835) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  836) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  837) 	writel(0xdeadbeef, fbbase_virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  838) 	writel(0xdeadbeef, fbbase_virt+0x100000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  839) 	writel(0xdeadbeef, fbbase_virt+0x200000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  840) 	f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  841) 	           readl(fbbase_virt), readl(fbbase_virt + 0x100000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  842) 	           readl(fbbase_virt + 0x200000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  843) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  844) 	writel(0xabcdef01, fbbase_virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  845) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  846) 	f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  847) 	           readl(fbbase_virt), readl(fbbase_virt + 0x100000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  848) 	           readl(fbbase_virt + 0x200000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  849) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  850) 	/* checks for 4mb lfb, then 2, then defaults to 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  851) 	if (readl(fbbase_virt + 0x200000) == 0xdeadbeef)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  852) 		*memsize = 0x400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  853) 	else if (readl(fbbase_virt + 0x100000) == 0xdeadbeef)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  854) 		*memsize = 0x200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  855) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  856) 		*memsize = 0x100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  857) 	f_ddprintk("detected memsize: %dMB\n", *memsize >> 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  858) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  860) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  861) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  862) /* 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  863)  * DAC detection routines 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  864)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  865) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  866) /* fbi should be idle, and fifo emty and mem disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  867) /* supposed to detect AT&T ATT20C409 and Ti TVP3409 ramdacs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  868) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  869) static int sst_detect_att(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  870) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  871) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  872) 	int i, mir, dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  873) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  874) 	for (i = 0; i < 3; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  875) 		sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  876) 		sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  877) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  878) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  879) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  880) 		/* the fifth time,  CR0 is read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  881) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  882) 		/* the 6th, manufacturer id register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  883) 		mir = sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  884) 		/*the 7th, device ID register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  885) 		dir = sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  886) 		f_ddprintk("mir: %#x, dir: %#x\n", mir, dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  887) 		if (mir == DACREG_MIR_ATT && dir == DACREG_DIR_ATT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  888) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  889) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  890) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  891) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  893) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  894) static int sst_detect_ti(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  895) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  896) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  897) 	int i, mir, dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  898) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  899) 	for (i = 0; i<3; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  900) 		sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  901) 		sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  902) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  903) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  904) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  905) 		/* the fifth time,  CR0 is read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  906) 		sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  907) 		/* the 6th, manufacturer id register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  908) 		mir = sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  909) 		/*the 7th, device ID register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  910) 		dir = sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  911) 		f_ddprintk("mir: %#x, dir: %#x\n", mir, dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  912) 		if ((mir == DACREG_MIR_TI ) && (dir == DACREG_DIR_TI)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  913) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  914) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  915) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  916) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  918) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  919) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  920)  * try to detect ICS5342  ramdac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  921)  * we get the 1st byte (M value) of preset f1,f7 and fB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  922)  * why those 3 ? mmmh... for now, i'll do it the glide way...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  923)  * and ask questions later. anyway, it seems that all the freq registers are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  924)  * really at their default state (cf specs) so i ask again, why those 3 regs ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  925)  * mmmmh.. it seems that's much more ugly than i thought. we use f0 and fA for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  926)  * pll programming, so in fact, we *hope* that the f1, f7 & fB won't be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  927)  * touched...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  928)  * is it really safe ? how can i reset this ramdac ? geee...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  929)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  930) static int sst_detect_ics(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  931) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  932) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  933) 	int m_clk0_1, m_clk0_7, m_clk1_b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  934) 	int n_clk0_1, n_clk0_7, n_clk1_b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  935) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  936) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  937) 	for (i = 0; i<5; i++ ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  938) 		sst_dac_write(DACREG_ICS_PLLRMA, 0x1);	/* f1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  939) 		m_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  940) 		n_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  941) 		sst_dac_write(DACREG_ICS_PLLRMA, 0x7);	/* f7 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  942) 		m_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  943) 		n_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  944) 		sst_dac_write(DACREG_ICS_PLLRMA, 0xb);	/* fB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  945) 		m_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  946) 		n_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  947) 		f_ddprintk("m_clk0_1: %#x, m_clk0_7: %#x, m_clk1_b: %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  948) 			m_clk0_1, m_clk0_7, m_clk1_b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  949) 		f_ddprintk("n_clk0_1: %#x, n_clk0_7: %#x, n_clk1_b: %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  950) 			n_clk0_1, n_clk0_7, n_clk1_b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  951) 		if ((   m_clk0_1 == DACREG_ICS_PLL_CLK0_1_INI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  952) 		    && (m_clk0_7 == DACREG_ICS_PLL_CLK0_7_INI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  953) 		    && (m_clk1_b == DACREG_ICS_PLL_CLK1_B_INI)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  954) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  955) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  956) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  957) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  958) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  959) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  960) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  961) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  962)  * gfx, video, pci fifo should be reset, dram refresh disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  963)  * see detect_dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  964)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  965) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  966) static int sst_set_pll_att_ti(struct fb_info *info, 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  967) 		const struct pll_timing *t, const int clock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  968) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  969) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  970) 	u8 cr0, cc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  971) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  972) 	/* enable indexed mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  973) 	sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  974) 	sst_dac_read(DACREG_RMR);	/* 1 time:  RMR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  975) 	sst_dac_read(DACREG_RMR);	/* 2 RMR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  976) 	sst_dac_read(DACREG_RMR);	/* 3 //  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  977) 	sst_dac_read(DACREG_RMR);	/* 4 //  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  978) 	cr0 = sst_dac_read(DACREG_RMR);	/* 5 CR0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  979) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  980) 	sst_dac_write(DACREG_WMA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  981) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  982) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  983) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  984) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  985) 	sst_dac_write(DACREG_RMR, (cr0 & 0xf0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  986) 	              | DACREG_CR0_EN_INDEXED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  987) 	              | DACREG_CR0_8BIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  988) 	              | DACREG_CR0_PWDOWN );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  989) 	/* so, now we are in indexed mode . dunno if its common, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  990) 	   i find this way of doing things a little bit weird :p */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  991) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  992) 	udelay(300);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  993) 	cc = dac_i_read(DACREG_CC_I);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  994) 	switch (clock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  995) 	case VID_CLOCK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  996) 		dac_i_write(DACREG_AC0_I, t->m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  997) 		dac_i_write(DACREG_AC1_I, t->p << 6 | t->n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  998) 		dac_i_write(DACREG_CC_I,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  999) 		            (cc & 0x0f) | DACREG_CC_CLKA | DACREG_CC_CLKA_C);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) 	case GFX_CLOCK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) 		dac_i_write(DACREG_BD0_I, t->m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) 		dac_i_write(DACREG_BD1_I, t->p << 6 | t->n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) 		dac_i_write(DACREG_CC_I,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) 		            (cc & 0xf0) | DACREG_CC_CLKB | DACREG_CC_CLKB_D);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) 		dprintk("%s: wrong clock code '%d'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) 		        __func__, clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) 	udelay(300);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) 	/* power up the dac & return to "normal" non-indexed mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) 	dac_i_write(DACREG_CR0_I,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) 	            cr0 & ~DACREG_CR0_PWDOWN & ~DACREG_CR0_EN_INDEXED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) static int sst_set_pll_ics(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) 		const struct pll_timing *t, const int clock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) 	u8 pll_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) 	sst_dac_write(DACREG_ICS_PLLRMA, DACREG_ICS_PLL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) 	pll_ctrl = sst_dac_read(DACREG_ICS_PLLDATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) 	switch(clock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) 	case VID_CLOCK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) 		sst_dac_write(DACREG_ICS_PLLWMA, 0x0);	/* CLK0, f0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) 		sst_dac_write(DACREG_ICS_PLLDATA, t->m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) 		sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) 		/* selects freq f0 for clock 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) 		sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) 		sst_dac_write(DACREG_ICS_PLLDATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) 		              (pll_ctrl & 0xd8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) 		              | DACREG_ICS_CLK0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) 		              | DACREG_ICS_CLK0_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) 	case GFX_CLOCK :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) 		sst_dac_write(DACREG_ICS_PLLWMA, 0xa);	/* CLK1, fA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) 		sst_dac_write(DACREG_ICS_PLLDATA, t->m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) 		sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) 		/* selects freq fA for clock 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) 		sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) 		sst_dac_write(DACREG_ICS_PLLDATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) 		              (pll_ctrl & 0xef) | DACREG_ICS_CLK1_A);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) 		dprintk("%s: wrong clock code '%d'\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) 		        __func__, clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) 	udelay(300);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) 	u8 cr0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) 	sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) 	sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) 	/* the fifth time,  CR0 is read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) 	cr0 = sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) 	sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) 	sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) 	sst_dac_read(DACREG_RMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) 	/* cr0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) 	switch(bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) 		sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) 		dprintk("%s: bad depth '%u'\n", __func__, bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) static void sst_set_vidmod_ics(struct fb_info *info, const int bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) 	switch(bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) 		sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) 		dprintk("%s: bad depth '%u'\n", __func__, bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)  * detect dac type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)  * prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)  * dram refresh disabled, FbiInit remaped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105)  * TODO: mmh.. maybe i should put the "prerequisite" in the func ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) static struct dac_switch dacs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) 	{	.name		= "TI TVP3409",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) 		.detect		= sst_detect_ti,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) 		.set_pll	= sst_set_pll_att_ti,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) 		.set_vidmod	= sst_set_vidmod_att_ti },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) 	{	.name		= "AT&T ATT20C409",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) 		.detect		= sst_detect_att,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) 		.set_pll	= sst_set_pll_att_ti,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) 		.set_vidmod	= sst_set_vidmod_att_ti },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) 	{	.name		= "ICS ICS5342",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) 		.detect		= sst_detect_ics,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) 		.set_pll	= sst_set_pll_ics,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) 		.set_vidmod	= sst_set_vidmod_ics },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) static int sst_detect_dactype(struct fb_info *info, struct sstfb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) 	int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) 	for (i = 0; i < ARRAY_SIZE(dacs); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) 		ret = dacs[i].detect(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) 	if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) 	f_dprintk("%s found %s\n", __func__, dacs[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) 	par->dac_sw = dacs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)  * Internal Routines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) static int sst_init(struct fb_info *info, struct sstfb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) 	u32 fbiinit0, fbiinit1, fbiinit4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) 	struct pci_dev *dev = par->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) 	struct pll_timing gfx_timings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) 	struct sst_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) 	int Fout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) 	int gfx_clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) 	spec = &voodoo_spec[par->type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) 	f_ddprintk(" fbiinit0   fbiinit1   fbiinit2   fbiinit3   fbiinit4  "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) 	           " fbiinit6\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) 	f_ddprintk("%0#10x %0#10x %0#10x %0#10x %0#10x %0#10x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) 	            sst_read(FBIINIT0), sst_read(FBIINIT1), sst_read(FBIINIT2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) 	            sst_read(FBIINIT3), sst_read(FBIINIT4), sst_read(FBIINIT6));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) 	/* disable video clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) 	pci_write_config_dword(dev, PCI_VCLK_DISABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) 	/* enable writing to init registers, disable pci fifo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) 	pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) 	/* reset video */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) 	sst_set_bits(FBIINIT1, VIDEO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) 	/* reset gfx + pci fifo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) 	sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) 	/* unreset fifo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) 	/*sst_unset_bits(FBIINIT0, FIFO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) 	sst_wait_idle();*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) 	/* unreset FBI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) 	/*sst_unset_bits(FBIINIT0, FBI_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) 	sst_wait_idle();*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) 	/* disable dram refresh */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) 	sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) 	/* remap fbinit2/3 to dac */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) 	pci_write_config_dword(dev, PCI_INIT_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) 				PCI_EN_INIT_WR | PCI_REMAP_DAC );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) 	/* detect dac type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) 	if (!sst_detect_dactype(info, par)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) 		printk(KERN_ERR "sstfb: unknown dac type.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) 		//FIXME watch it: we are not in a safe state, bad bad bad.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) 	/* set graphic clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) 	gfx_clock = spec->default_gfx_clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) 	if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) 		printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) 		 gfx_clock = gfxclk *1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) 	} else if (gfxclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) 		printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) 	sst_calc_pll(gfx_clock, &Fout, &gfx_timings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) 	par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) 	/* disable fbiinit remap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) 	pci_write_config_dword(dev, PCI_INIT_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) 	                       PCI_EN_INIT_WR| PCI_EN_FIFO_WR );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) 	/* defaults init registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) 	/* FbiInit0: unreset gfx, unreset fifo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) 	fbiinit0 = FBIINIT0_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) 	fbiinit1 = FBIINIT1_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) 	fbiinit4 = FBIINIT4_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) 	par->vgapass = vgapass;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) 	if (par->vgapass)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) 		fbiinit0 &= ~DIS_VGA_PASSTHROUGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) 		fbiinit0 |= DIS_VGA_PASSTHROUGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) 	if (slowpci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) 		fbiinit1 |= SLOW_PCI_WRITES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) 		fbiinit4 |= SLOW_PCI_READS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) 		fbiinit1 &= ~SLOW_PCI_WRITES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) 		fbiinit4 &= ~SLOW_PCI_READS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) 	sst_write(FBIINIT0, fbiinit0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) 	sst_write(FBIINIT1, fbiinit1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) 	sst_write(FBIINIT2, FBIINIT2_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) 	sst_write(FBIINIT3, FBIINIT3_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) 	sst_write(FBIINIT4, fbiinit4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) 	if (IS_VOODOO2(par)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) 		sst_write(FBIINIT6, FBIINIT6_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) 		sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) 	pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) 	pci_write_config_dword(dev, PCI_VCLK_ENABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) static void sst_shutdown(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) 	struct sstfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) 	struct pci_dev *dev = par->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) 	struct pll_timing gfx_timings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) 	int Fout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) 	/* reset video, gfx, fifo, disable dram + remap fbiinit2/3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) 	pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) 	sst_set_bits(FBIINIT1, VIDEO_RESET | EN_BLANKING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) 	sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) 	sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) 	sst_wait_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) 	pci_write_config_dword(dev, PCI_INIT_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) 	                       PCI_EN_INIT_WR | PCI_REMAP_DAC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) 	/* set 20Mhz gfx clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) 	sst_calc_pll(20000, &Fout, &gfx_timings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) 	par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) 	/* TODO maybe shutdown the dac, vrefresh and so on... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) 	pci_write_config_dword(dev, PCI_INIT_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) 	                       PCI_EN_INIT_WR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) 	sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | DIS_VGA_PASSTHROUGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) 	pci_write_config_dword(dev, PCI_VCLK_DISABLE,0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) 	/* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) 	 * from start ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) 	pci_write_config_dword(dev, PCI_INIT_ENABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273)  * Interface to the world
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) static int sstfb_setup(char *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) 	char *this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) 	if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) 	while ((this_opt = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) 		if (!*this_opt) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) 		f_ddprintk("option %s\n", this_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) 		if (!strcmp(this_opt, "vganopass"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) 			vgapass = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) 		else if (!strcmp(this_opt, "vgapass"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) 			vgapass = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) 		else if (!strcmp(this_opt, "clipping"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) 		        clipping = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) 		else if (!strcmp(this_opt, "noclipping"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) 		        clipping = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) 		else if (!strcmp(this_opt, "fastpci"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) 		        slowpci = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) 		else if (!strcmp(this_opt, "slowpci"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) 		        slowpci = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) 		else if (!strncmp(this_opt, "mem:",4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) 			mem = simple_strtoul (this_opt+4, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) 		else if (!strncmp(this_opt, "gfxclk:",7))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) 			gfxclk = simple_strtoul (this_opt+7, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) 			mode_option = this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) static const struct fb_ops sstfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) 	.fb_check_var	= sstfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) 	.fb_set_par	= sstfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) 	.fb_setcolreg	= sstfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) 	.fb_fillrect	= cfb_fillrect, /* sstfb_fillrect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) 	.fb_copyarea	= cfb_copyarea, /* sstfb_copyarea */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) 	.fb_imageblit	= cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) 	.fb_ioctl	= sstfb_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) 	struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) 	struct fb_fix_screeninfo *fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) 	struct sstfb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) 	struct sst_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) 	/* Enable device in PCI config. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) 	if ((err=pci_enable_device(pdev))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) 		printk(KERN_ERR "cannot enable device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) 	/* Allocate the fb and par structures.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) 	info = framebuffer_alloc(sizeof(struct sstfb_par), &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) 	if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) 	pci_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) 	par  = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) 	fix  = &info->fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) 	par->type = id->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) 	spec = &voodoo_spec[par->type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) 	f_ddprintk("found device : %s\n", spec->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) 	par->dev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) 	par->revision = pdev->revision;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) 	fix->mmio_start = pci_resource_start(pdev,0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) 	fix->mmio_len	= 0x400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) 	fix->smem_start = fix->mmio_start + 0x400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) 	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "sstfb MMIO")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) 		printk(KERN_ERR "sstfb: cannot reserve mmio memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) 		goto fail_mmio_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) 	if (!request_mem_region(fix->smem_start, 0x400000,"sstfb FB")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) 		printk(KERN_ERR "sstfb: cannot reserve fb memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) 		goto fail_fb_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) 	par->mmio_vbase = ioremap(fix->mmio_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) 					fix->mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) 	if (!par->mmio_vbase) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) 		printk(KERN_ERR "sstfb: cannot remap register area %#lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) 		        fix->mmio_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) 		goto fail_mmio_remap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) 	info->screen_base = ioremap(fix->smem_start, 0x400000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) 	if (!info->screen_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) 		printk(KERN_ERR "sstfb: cannot remap framebuffer %#lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) 		        fix->smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) 		goto fail_fb_remap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) 	if (!sst_init(info, par)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) 		printk(KERN_ERR "sstfb: Init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) 		goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) 	sst_get_memsize(info, &fix->smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) 	strlcpy(fix->id, spec->name, sizeof(fix->id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) 	printk(KERN_INFO "%s (revision %d) with %s dac\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) 		fix->id, par->revision, par->dac_sw.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) 	printk(KERN_INFO "framebuffer at %#lx, mapped to 0x%p, size %dMB\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) 	        fix->smem_start, info->screen_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) 	        fix->smem_len >> 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) 	f_ddprintk("regbase_virt: %#lx\n", par->mmio_vbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) 	f_ddprintk("membase_phys: %#lx\n", fix->smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) 	f_ddprintk("fbbase_virt: %p\n", info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) 	info->flags	= FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) 	info->fbops	= &sstfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) 	info->pseudo_palette = par->palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) 	fix->type	= FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) 	fix->visual	= FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) 	fix->accel	= FB_ACCEL_NONE;  /* FIXME */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) 	 * According to the specs, the linelength must be of 1024 *pixels*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) 	 * and the 24bpp mode is in fact a 32 bpp mode (and both are in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) 	 * fact dithered to 16bit).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) 	fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) 	fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) 	if (sstfb_check_var(&info->var, info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) 		printk(KERN_ERR "sstfb: invalid video mode.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) 		goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) 	if (sstfb_set_par(info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) 		printk(KERN_ERR "sstfb: can't set default video mode.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) 		goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) 	if (fb_alloc_cmap(&info->cmap, 256, 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) 		printk(KERN_ERR "sstfb: can't alloc cmap memory.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) 		goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) 	/* register fb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) 	info->device = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) 	if (register_framebuffer(info) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) 		printk(KERN_ERR "sstfb: can't register framebuffer.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) 		goto fail_register;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) 	sstfb_clear_screen(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) 	if (device_create_file(info->dev, &device_attrs[0]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) 		printk(KERN_WARNING "sstfb: can't create sysfs entry.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) 	fb_info(info, "%s frame buffer device at 0x%p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) 		fix->id, info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) fail_register:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) 	fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) 	iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) fail_fb_remap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) 	iounmap(par->mmio_vbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) fail_mmio_remap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) 	release_mem_region(fix->smem_start, 0x400000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) fail_fb_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) 	release_mem_region(fix->mmio_start, info->fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) fail_mmio_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) 	framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) 	return -ENXIO; 	/* no voodoo detected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) static void sstfb_remove(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) 	struct sstfb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) 	struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) 	info = pci_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) 	par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) 	device_remove_file(info->dev, &device_attrs[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) 	sst_shutdown(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) 	iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) 	iounmap(par->mmio_vbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) 	release_mem_region(info->fix.smem_start, 0x400000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) 	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) 	fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) 	unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) 	framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) static const struct pci_device_id sstfb_id_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) 	{ PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO ),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) 		.driver_data = ID_VOODOO1, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) 	{ PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) 		.driver_data = ID_VOODOO2, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) 	{ 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) static struct pci_driver sstfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) 	.name		= "sstfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) 	.id_table	= sstfb_id_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) 	.probe		= sstfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) 	.remove		= sstfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) static int sstfb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) 	char *option = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) 	if (fb_get_options("sstfb", &option))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) 	sstfb_setup(option);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) 	return pci_register_driver(&sstfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) static void sstfb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) 	pci_unregister_driver(&sstfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) module_init(sstfb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) module_exit(sstfb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) module_param(mem, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) MODULE_PARM_DESC(mem, "Size of frame buffer memory in MB (1, 2, 4 MB, default=autodetect)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) module_param(vgapass, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) MODULE_PARM_DESC(vgapass, "Enable VGA PassThrough mode (0 or 1) (default=0)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) module_param(clipping, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) MODULE_PARM_DESC(clipping, "Enable clipping (slower, safer) (0 or 1) (default=1)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) module_param(gfxclk, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) module_param(slowpci, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) module_param(mode_option, charp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) MODULE_PARM_DESC(mode_option, "Initial video mode (default=" DEFAULT_VIDEO_MODE ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533)