/*
* linux/drivers/video/stifb.c -
* Low level Frame buffer driver for HP workstations with
* STI (standard text interface) video firmware.
*
* Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
* Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
*
* Based on:
* - linux/drivers/video/artistfb.c -- Artist frame buffer driver
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* - based on skeletonfb, which was
* Created 28 Dec 1997 by Geert Uytterhoeven
* - HP Xhp cfb-based X11 window driver for XFree86
* (c)Copyright 1992 Hewlett-Packard Co.
*
*
* The following graphics display devices (NGLE family) are supported by this driver:
*
* HPA4070A known as "HCRX", a 1280x1024 color device with 8 planes
* HPA4071A known as "HCRX24", a 1280x1024 color device with 24 planes,
* optionally available with a hardware accelerator as HPA4071A_Z
* HPA1659A known as "CRX", a 1280x1024 color device with 8 planes
* HPA1439A known as "CRX24", a 1280x1024 color device with 24 planes,
* optionally available with a hardware accelerator.
* HPA1924A known as "GRX", a 1280x1024 grayscale device with 8 planes
* HPA2269A known as "Dual CRX", a 1280x1024 color device with 8 planes,
* implements support for two displays on a single graphics card.
* HP710C internal graphics support optionally available on the HP9000s710 SPU,
* supports 1280x1024 color displays with 8 planes.
* HP710G same as HP710C, 1280x1024 grayscale only
* HP710L same as HP710C, 1024x768 color only
* HP712 internal graphics support on HP9000s712 SPU, supports 640x480,
* 1024x768 or 1280x1024 color displays on 8 planes (Artist)
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
/* TODO:
* - 1bpp mode is completely untested
* - add support for h/w acceleration
* - add hardware cursor
* - automatically disable double buffering (e.g. on RDI precisionbook laptop)
*/
/* on supported graphic devices you may:
* #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
* #undef FALLBACK_TO_1BPP to reject support for unsupported cards */
#undef FALLBACK_TO_1BPP
#undef DEBUG_STIFB_REGS /* debug sti register accesses */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <asm/grfioctl.h> /* for HP-UX compatibility */
#include <linux/uaccess.h>
#include <video/sticore.h>
/* REGION_BASE(fb_info, index) returns the physical address for region <index> */
#define REGION_BASE(fb_info, index) \
F_EXTEND(fb_info->sti->regions_phys[index])
#define NGLEDEVDEPROM_CRT_REGION 1
#define NR_PALETTE 256
typedef struct {
__s32 video_config_reg;
__s32 misc_video_start;
__s32 horiz_timing_fmt;
__s32 serr_timing_fmt;
__s32 vert_timing_fmt;
__s32 horiz_state;
__s32 vert_state;
__s32 vtg_state_elements;
__s32 pipeline_delay;
__s32 misc_video_end;
} video_setup_t;
typedef struct {
__s16 sizeof_ngle_data;
__s16 x_size_visible; /* visible screen dim in pixels */
__s16 y_size_visible;
__s16 pad2[15];
__s16 cursor_pipeline_delay;
__s16 video_interleaves;
__s32 pad3[11];
} ngle_rom_t;
struct stifb_info {
struct fb_info *info;
unsigned int id;
ngle_rom_t ngle_rom;
struct sti_struct *sti;
int deviceSpecificConfig;
u32 pseudo_palette[16];
};
static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
/* ------------------- chipset specific functions -------------------------- */
/* offsets to graphic-chip internal registers */
#define REG_1 0x000118
#define REG_2 0x000480
#define REG_3 0x0004a0
#define REG_4 0x000600
#define REG_6 0x000800
#define REG_7 0x000804
#define REG_8 0x000820
#define REG_9 0x000a04
#define REG_10 0x018000
#define REG_11 0x018004
#define REG_12 0x01800c
#define REG_13 0x018018
#define REG_14 0x01801c
#define REG_15 0x200000
#define REG_15b0 0x200000
#define REG_16b1 0x200005
#define REG_16b3 0x200007
#define REG_21 0x200218
#define REG_22 0x0005a0
#define REG_23 0x0005c0
#define REG_24 0x000808
#define REG_25 0x000b00
#define REG_26 0x200118
#define REG_27 0x200308
#define REG_32 0x21003c
#define REG_33 0x210040
#define REG_34 0x200008
#define REG_35 0x018010
#define REG_38 0x210020
#define REG_39 0x210120
#define REG_40 0x210130
#define REG_42 0x210028
#define REG_43 0x21002c
#define REG_44 0x210030
#define REG_45 0x210034
#define READ_BYTE(fb, reg) gsc_readb((fb)->info->fix.mmio_start + (reg))
#define READ_WORD(fb, reg) gsc_readl((fb)->info->fix.mmio_start + (reg))
#ifndef DEBUG_STIFB_REGS
# define DEBUG_OFF()
# define DEBUG_ON()
# define WRITE_BYTE(value, fb, reg) gsc_writeb((value), (fb)->info->fix.mmio_start + (reg))
# define WRITE_WORD(value, fb, reg) gsc_writel((value), (fb)->info->fix.mmio_start + (reg))
#else
static int debug_on = 1;
# define DEBUG_OFF() debug_on=0
# define DEBUG_ON() debug_on=1
# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
__func__, reg, value, READ_BYTE(fb,reg)); \
gsc_writeb((value), (fb)->info->fix.mmio_start + (reg)); } while (0)
# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
__func__, reg, value, READ_WORD(fb,reg)); \
gsc_writel((value), (fb)->info->fix.mmio_start + (reg)); } while (0)
#endif /* DEBUG_STIFB_REGS */
#define ENABLE 1 /* for enabling/disabling screen */
#define DISABLE 0
#define NGLE_LOCK(fb_info) do { } while (0)
#define NGLE_UNLOCK(fb_info) do { } while (0)
static void
SETUP_HW(struct stifb_info *fb)
{
char stat;
do {
stat = READ_BYTE(fb, REG_15b0);
if (!stat)
stat = READ_BYTE(fb, REG_15b0);
} while (stat);
}
static void
SETUP_FB(struct stifb_info *fb)
{
unsigned int reg10_value = 0;
SETUP_HW(fb);
switch (fb->id)
{
case CRT_ID_VISUALIZE_EG:
case S9000_ID_ARTIST:
case S9000_ID_A1659A:
reg10_value = 0x13601000;
break;
case S9000_ID_A1439A:
if (fb->info->var.bits_per_pixel == 32)
reg10_value = 0xBBA0A000;
else
reg10_value = 0x13601000;
break;
case S9000_ID_HCRX:
if (fb->info->var.bits_per_pixel == 32)
reg10_value = 0xBBA0A000;
else
reg10_value = 0x13602000;
break;
case S9000_ID_TIMBER:
case CRX24_OVERLAY_PLANES:
reg10_value = 0x13602000;
break;
}
if (reg10_value)
WRITE_WORD(reg10_value, fb, REG_10);
WRITE_WORD(0x83000300, fb, REG_14);
SETUP_HW(fb);
WRITE_BYTE(1, fb, REG_16b1);
}
static void
START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
{
SETUP_HW(fb);
WRITE_WORD(0xBBE0F000, fb, REG_10);
WRITE_WORD(0x03000300, fb, REG_14);
WRITE_WORD(~0, fb, REG_13);
}
static void
WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
{
SETUP_HW(fb);
WRITE_WORD(((0x100+index)<<2), fb, REG_3);
WRITE_WORD(color, fb, REG_4);
}
static void
FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
{
WRITE_WORD(0x400, fb, REG_2);
if (fb->info->var.bits_per_pixel == 32) {
WRITE_WORD(0x83000100, fb, REG_1);
} else {
if (fb->id == S9000_
|