Commit 2eaf7c63 authored by James Simmons's avatar James Simmons

Port step some changes at authors request.

parent 8ef1bf6d
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* linux/drivers/video/riva/fbdevar->c - nVidia RIVA 128/TNT/TNT2 fb driver
* linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
*
* Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
*
......@@ -25,6 +25,7 @@
* Known bugs and issues:
* restoring text mode fails
* doublescan modes are broken
* option 'noaccel' has no effect
*/
#include <linux/config.h>
......@@ -51,10 +52,12 @@
#error This driver requires PCI support.
#endif
#include "../fbcon-accel.h"
/* version number of this driver */
#define RIVAFB_VERSION "0.9.3"
#define RIVAFB_VERSION "0.9.2a"
/* ------------------------------------------------------------------------- *
*
......@@ -88,8 +91,8 @@
#define Set8Bits(value) ((value)&0xff)
/* HW cursor parameters */
#define DEFAULT_CURSOR_BLINK_RATE (20)
#define CURSOR_HIDE_DELAY (10)
#define DEFAULT_CURSOR_BLINK_RATE (40)
#define CURSOR_HIDE_DELAY (20)
#define CURSOR_SHOW_DELAY (3)
#define CURSOR_COLOR 0x7fff
......@@ -97,6 +100,7 @@
#define MAX_CURS 32
/* ------------------------------------------------------------------------- *
*
* prototypes
......@@ -105,6 +109,11 @@
static int rivafb_blank(int blank, struct fb_info *info);
extern void riva_setup_accel(struct rivafb_info *rinfo);
extern inline void wait_for_idle(struct rivafb_info *rinfo);
/* ------------------------------------------------------------------------- *
*
* card identification
......@@ -127,11 +136,6 @@ enum riva_chips {
CH_GEFORCE2_GTS,
CH_GEFORCE2_ULTRA,
CH_QUADRO2_PRO,
CH_GEFORCE2_GO,
CH_GEFORCE3,
CH_GEFORCE3_1,
CH_GEFORCE3_2,
CH_QUADRO_DDC
};
/* directly indexed by riva_chips enum, above */
......@@ -154,11 +158,6 @@ static struct riva_chip_info {
{ "GeForce2-GTS", NV_ARCH_10},
{ "GeForce2-ULTRA", NV_ARCH_10},
{ "Quadro2-PRO", NV_ARCH_10},
{ "GeForce2-Go", NV_ARCH_10},
{ "GeForce3", NV_ARCH_20},
{ "GeForce3 Ti 200", NV_ARCH_20},
{ "GeForce3 Ti 500", NV_ARCH_20},
{ "Quadro DDC", NV_ARCH_20}
};
static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
......@@ -196,30 +195,64 @@ static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
/* ------------------------------------------------------------------------- *
*
* framebuffer related structures
*
* ------------------------------------------------------------------------- */
#ifdef FBCON_HAS_CFB8
extern struct display_switch fbcon_riva8;
#endif
#ifdef FBCON_HAS_CFB16
extern struct display_switch fbcon_riva16;
#endif
#ifdef FBCON_HAS_CFB32
extern struct display_switch fbcon_riva32;
#endif
#if 0
/* describes the state of a Riva board */
struct rivafb_par {
struct riva_regs state; /* state of hw board */
__u32 visual; /* FB_VISUAL_xxx */
unsigned depth; /* bpp of current mode */
};
#endif
struct riva_cursor {
int enable;
int on;
int vbl_cnt;
int last_move_delay;
int blink_rate;
struct {
u16 x, y;
} pos, size;
unsigned short image[MAX_CURS*MAX_CURS];
struct timer_list *timer;
};
/* ------------------------------------------------------------------------- *
*
* global variables
*
* ------------------------------------------------------------------------- */
struct fb_info *riva_boards = NULL;
struct rivafb_info *riva_boards = NULL;
/* command line data, set in rivafb_setup() */
static char fontname[40] __initdata = { 0 };
static char noaccel __initdata = 0;
static char nomove = 0;
static char nohwcursor __initdata = 0;
static char noblink = 0;
#ifdef CONFIG_MTRR
......@@ -232,26 +265,24 @@ static char *mode_option __initdata = NULL;
static char *font = NULL;
#endif
static struct fb_fix_screeninfo rivafb_fix = {
id: "nVidia",
type: FB_TYPE_PACKED_PIXELS,
xpanstep: 1,
ypanstep: 1,
};
static struct fb_var_screeninfo rivafb_default_var = {
xres: 640,
yres: 480,
xres_virtual: 640,
yres_virtual: 480,
xoffset: 0,
yoffset: 0,
bits_per_pixel: 8,
grayscale: 0,
red: {0, 6, 0},
green: {0, 6, 0},
blue: {0, 6, 0},
activate: FB_ACTIVATE_NOW,
transp: {0, 0, 0},
nonstd: 0,
activate: 0,
height: -1,
width: -1,
accel_flags: FB_ACCELF_TEXT,
accel_flags: 0,
pixclock: 39721,
left_margin: 40,
right_margin: 24,
......@@ -259,28 +290,10 @@ static struct fb_var_screeninfo rivafb_default_var = {
lower_margin: 11,
hsync_len: 96,
vsync_len: 2,
sync: 0,
vmode: FB_VMODE_NONINTERLACED
};
static u8 byte_rev[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
/* from GGI */
static const struct riva_regs reg_template = {
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */
......@@ -302,76 +315,78 @@ static const struct riva_regs reg_template = {
0xEB /* MISC */
};
/* ------------------------------------------------------------------------- *
*
* MMIO access macros
*
* ------------------------------------------------------------------------- */
static inline void CRTCout(struct riva_par *par, unsigned char index,
static inline void CRTCout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PCIO, 0x3d4, index);
VGA_WR08(par->riva.PCIO, 0x3d5, val);
VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
VGA_WR08(rinfo->riva.PCIO, 0x3d5, val);
}
static inline unsigned char CRTCin(struct riva_par *par,
static inline unsigned char CRTCin(struct rivafb_info *rinfo,
unsigned char index)
{
VGA_WR08(par->riva.PCIO, 0x3d4, index);
return (VGA_RD08(par->riva.PCIO, 0x3d5));
VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
return (VGA_RD08(rinfo->riva.PCIO, 0x3d5));
}
static inline void GRAout(struct riva_par *par, unsigned char index,
static inline void GRAout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3ce, index);
VGA_WR08(par->riva.PVIO, 0x3cf, val);
VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
VGA_WR08(rinfo->riva.PVIO, 0x3cf, val);
}
static inline unsigned char GRAin(struct riva_par *par,
static inline unsigned char GRAin(struct rivafb_info *rinfo,
unsigned char index)
{
VGA_WR08(par->riva.PVIO, 0x3ce, index);
return (VGA_RD08(par->riva.PVIO, 0x3cf));
VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
return (VGA_RD08(rinfo->riva.PVIO, 0x3cf));
}
static inline void SEQout(struct riva_par *par, unsigned char index,
static inline void SEQout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3c4, index);
VGA_WR08(par->riva.PVIO, 0x3c5, val);
VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
VGA_WR08(rinfo->riva.PVIO, 0x3c5, val);
}
static inline unsigned char SEQin(struct riva_par *par,
static inline unsigned char SEQin(struct rivafb_info *rinfo,
unsigned char index)
{
VGA_WR08(par->riva.PVIO, 0x3c4, index);
return (VGA_RD08(par->riva.PVIO, 0x3c5));
VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
return (VGA_RD08(rinfo->riva.PVIO, 0x3c5));
}
static inline void ATTRout(struct riva_par *par, unsigned char index,
static inline void ATTRout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PCIO, 0x3c0, index);
VGA_WR08(par->riva.PCIO, 0x3c0, val);
VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
VGA_WR08(rinfo->riva.PCIO, 0x3c0, val);
}
static inline unsigned char ATTRin(struct riva_par *par,
static inline unsigned char ATTRin(struct rivafb_info *rinfo,
unsigned char index)
{
VGA_WR08(par->riva.PCIO, 0x3c0, index);
return (VGA_RD08(par->riva.PCIO, 0x3c1));
VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
return (VGA_RD08(rinfo->riva.PCIO, 0x3c1));
}
static inline void MISCout(struct riva_par *par, unsigned char val)
static inline void MISCout(struct rivafb_info *rinfo, unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3c2, val);
VGA_WR08(rinfo->riva.PVIO, 0x3c2, val);
}
static inline unsigned char MISCin(struct riva_par *par)
static inline unsigned char MISCin(struct rivafb_info *rinfo)
{
return (VGA_RD08(par->riva.PVIO, 0x3cc));
return (VGA_RD08(rinfo->riva.PVIO, 0x3cc));
}
......@@ -384,40 +399,39 @@ static inline unsigned char MISCin(struct riva_par *par)
/**
* riva_cursor_timer_handler - blink timer
* @dev_addr: pointer to fb_info object containing info for current riva board
* @dev_addr: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Cursor blink timer.
*/
static void riva_cursor_timer_handler(unsigned long dev_addr)
{
struct fb_info *info = (struct fb_info *)dev_addr;
struct riva_par *par = (struct riva_par *) info->par;
struct rivafb_info *rinfo = (struct rivafb_info *)dev_addr;
if (!par->cursor) return;
if (!rinfo->cursor) return;
if (!par->cursor->enable) goto out;
if (!rinfo->cursor->enable) goto out;
par->cursor->prev_slice_moves = par->cursor->last_slice_moves;
par->cursor->last_slice_moves = 0;
if (rinfo->cursor->last_move_delay < 1000)
rinfo->cursor->last_move_delay++;
if (par->cursor->vbl_cnt && --par->cursor->vbl_cnt == 0) {
par->cursor->on ^= 1;
if (par->cursor->on)
*(par->riva.CURSORPOS) = (par->cursor->pos.x & 0xFFFF)
| (par->cursor->pos.y << 16);
par->riva.ShowHideCursor(&par->riva, par->cursor->on);
if (rinfo->cursor->vbl_cnt && --rinfo->cursor->vbl_cnt == 0) {
rinfo->cursor->on ^= 1;
if (rinfo->cursor->on)
*(rinfo->riva.CURSORPOS) = (rinfo->cursor->pos.x & 0xFFFF)
| (rinfo->cursor->pos.y << 16);
rinfo->riva.ShowHideCursor(&rinfo->riva, rinfo->cursor->on);
if (!noblink)
par->cursor->vbl_cnt = par->cursor->blink_rate;
rinfo->cursor->vbl_cnt = rinfo->cursor->blink_rate;
}
out:
par->cursor->timer->expires = jiffies + (HZ / 50);
add_timer(par->cursor->timer);
rinfo->cursor->timer->expires = jiffies + (HZ / 100);
add_timer(rinfo->cursor->timer);
}
/**
* rivafb_init_cursor - allocates cursor structure and starts blink timer
* @info: pointer to fb_info object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Allocates cursor structure and starts blink timer.
......@@ -428,7 +442,7 @@ static void riva_cursor_timer_handler(unsigned long dev_addr)
* CALLED FROM:
* rivafb_init_one()
*/
static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info)
static struct riva_cursor * __init rivafb_init_cursor(struct rivafb_info *rinfo)
{
struct riva_cursor *cursor;
......@@ -446,8 +460,8 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info)
cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
init_timer(cursor->timer);
cursor->timer->expires = jiffies + (HZ / 50);
cursor->timer->data = (unsigned long)info;
cursor->timer->expires = jiffies + (HZ / 100);
cursor->timer->data = (unsigned long)rinfo;
cursor->timer->function = riva_cursor_timer_handler;
add_timer(cursor->timer);
......@@ -456,7 +470,7 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info)
/**
* rivafb_exit_cursor - stops blink timer and releases cursor structure
* @par: pointer to riva_par object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Stops blink timer and releases cursor structure.
......@@ -465,9 +479,9 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info)
* rivafb_init_one()
* rivafb_remove_one()
*/
static void rivafb_exit_cursor(struct riva_par *par)
static void rivafb_exit_cursor(struct rivafb_info *rinfo)
{
struct riva_cursor *cursor = par->cursor;
struct riva_cursor *cursor = rinfo->cursor;
if (cursor) {
if (cursor->timer) {
......@@ -475,13 +489,13 @@ static void rivafb_exit_cursor(struct riva_par *par)
kfree(cursor->timer);
}
kfree(cursor);
par->cursor = NULL;
rinfo->cursor = 0;
}
}
/**
* rivafb_download_cursor - writes cursor shape into card registers
* @par: pointer to riva_par object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Writes cursor shape into card registers.
......@@ -489,24 +503,24 @@ static void rivafb_exit_cursor(struct riva_par *par)
* CALLED FROM:
* riva_load_video_mode()
*/
static void rivafb_download_cursor(struct riva_par *par)
static void rivafb_download_cursor(struct rivafb_info *rinfo)
{
int i, save;
int *image;
if (!par->cursor) return;
if (!rinfo->cursor) return;
image = (int *)par->cursor->image;
save = par->riva.ShowHideCursor(&par->riva, 0);
image = (int *)rinfo->cursor->image;
save = rinfo->riva.ShowHideCursor(&rinfo->riva, 0);
for (i = 0; i < (MAX_CURS*MAX_CURS*2)/sizeof(int); i++)
writel(image[i], par->riva.CURSOR + i);
writel(image[i], rinfo->riva.CURSOR + i);
par->riva.ShowHideCursor(&par->riva, save);
rinfo->riva.ShowHideCursor(&rinfo->riva, save);
}
/**
* rivafb_create_cursor - sets rectangular cursor
* @par: pointer to riva_par object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
* @width: cursor width in pixels
* @height: cursor height in pixels
*
......@@ -515,11 +529,11 @@ static void rivafb_download_cursor(struct riva_par *par)
*
* CALLED FROM:
* rivafb_set_font()
* rivafb_set_par()
* rivafb_set_var()
*/
static void rivafb_create_cursor(struct riva_par *par, int width, int height)
static void rivafb_create_cursor(struct rivafb_info *rinfo, int width, int height)
{
struct riva_cursor *c = par->cursor;
struct riva_cursor *c = rinfo->cursor;
int i, j, idx;
if (c) {
......@@ -561,10 +575,9 @@ static void rivafb_create_cursor(struct riva_par *par, int width, int height)
*/
static int rivafb_set_font(struct display *p, int width, int height)
{
struct fb_info *fb = p->fb_info;
struct riva_par *par = (struct riva_par *) fb->par;
struct rivafb_info *fb = (struct rivafb_info *)(p->fb_info);
rivafb_create_cursor(par, width, height);
rivafb_create_cursor(fb, width, height);
return 1;
}
......@@ -580,9 +593,8 @@ static int rivafb_set_font(struct display *p, int width, int height)
*/
static void rivafb_cursor(struct display *p, int mode, int x, int y)
{
struct fb_info *info = p->fb_info;
struct riva_par *par = (struct riva_par *) info->par;
struct riva_cursor *c = par->cursor;
struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
struct riva_cursor *c = rinfo->cursor;
if (!c) return;
......@@ -593,7 +605,7 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y)
return;
c->enable = 0;
if (c->on) par->riva.ShowHideCursor(&par->riva, 0);
if (c->on) rinfo->riva.ShowHideCursor(&rinfo->riva, 0);
c->pos.x = x;
c->pos.y = y;
......@@ -604,15 +616,15 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y)
break;
case CM_DRAW:
case CM_MOVE:
if (c->last_slice_moves > 2 || c->prev_slice_moves > 2) {
if (c->last_move_delay <= 1) { /* rapid cursor movement */
c->vbl_cnt = CURSOR_SHOW_DELAY;
} else {
*(par->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16);
par->riva.ShowHideCursor(&par->riva, 1);
*(rinfo->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16);
rinfo->riva.ShowHideCursor(&rinfo->riva, 1);
if (!noblink) c->vbl_cnt = CURSOR_HIDE_DELAY;
c->on = 1;
}
c->last_slice_moves++;
c->last_move_delay = 0;
c->enable = 1;
break;
}
......@@ -626,6 +638,80 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y)
*
* ------------------------------------------------------------------------- */
/**
* riva_set_dispsw - sets dispsw
* @rinfo: pointer to internal driver struct for a given Riva card
* @disp: pointer to display object
*
* DESCRIPTION:
* Sets up console low level operations depending on the current? color depth
* of the display.
*
* CALLED FROM:
* rivafb_set_var()
* rivafb_switch()
* riva_init_disp()
*/
static void riva_set_dispsw(struct rivafb_info *rinfo, struct display *disp)
{
int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
DPRINTK("ENTER\n");
assert(rinfo != NULL);
disp->dispsw_data = NULL;
disp->type = FB_TYPE_PACKED_PIXELS;
disp->type_aux = 0;
disp->ypanstep = 1;
disp->ywrapstep = 0;
disp->can_soft_blank = 1;
disp->inverse = 0;
switch (disp->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8:
rinfo->dispsw = accel ? fbcon_riva8 : fbcon_cfb8;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual;
disp->visual = FB_VISUAL_PSEUDOCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
rinfo->dispsw = accel ? fbcon_riva16 : fbcon_cfb16;
disp->dispsw_data = &rinfo->con_cmap.cfb16;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual * 2;
disp->visual = FB_VISUAL_DIRECTCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
rinfo->dispsw = accel ? fbcon_riva32 : fbcon_cfb32;
disp->dispsw_data = rinfo->con_cmap.cfb32;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual * 4;
disp->visual = FB_VISUAL_DIRECTCOLOR;
break;
#endif
default:
DPRINTK("Setting fbcon_dummy renderer\n");
rinfo->dispsw = fbcon_dummy;
disp->dispsw = &rinfo->dispsw;
}
/* FIXME: verify that the above code sets dsp->* fields correctly */
if (rinfo->cursor) {
rinfo->dispsw.cursor = rivafb_cursor;
rinfo->dispsw.set_font = rivafb_set_font;
}
DPRINTK("EXIT\n");
}
/**
* riva_wclut - set CLUT entry
* @chip: pointer to RIVA_HW_INST object
......@@ -652,7 +738,7 @@ static void riva_wclut(RIVA_HW_INST *chip,
/**
* riva_save_state - saves current chip state
* @par: pointer to riva_par object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
* @regs: pointer to riva_regs object
*
* DESCRIPTION:
......@@ -662,36 +748,36 @@ static void riva_wclut(RIVA_HW_INST *chip,
* rivafb_init_one()
*/
/* from GGI */
static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
static void riva_save_state(struct rivafb_info *rinfo, struct riva_regs *regs)
{
int i;
par->riva.LockUnlock(&par->riva, 0);
rinfo->riva.LockUnlock(&rinfo->riva, 0);
par->riva.UnloadStateExt(&par->riva, &regs->ext);
rinfo->riva.UnloadStateExt(&rinfo->riva, &regs->ext);
regs->misc_output = MISCin(par);
regs->misc_output = MISCin(rinfo);
for (i = 0; i < NUM_CRT_REGS; i++) {
regs->crtc[i] = CRTCin(par, i);
regs->crtc[i] = CRTCin(rinfo, i);
}
for (i = 0; i < NUM_ATC_REGS; i++) {
regs->attr[i] = ATTRin(par, i);
regs->attr[i] = ATTRin(rinfo, i);
}
for (i = 0; i < NUM_GRC_REGS; i++) {
regs->gra[i] = GRAin(par, i);
regs->gra[i] = GRAin(rinfo, i);
}
for (i = 0; i < NUM_SEQ_REGS; i++) {
regs->seq[i] = SEQin(par, i);
regs->seq[i] = SEQin(rinfo, i);
}
}
/**
* riva_load_state - loads current chip state
* @par: pointer to riva_par object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
* @regs: pointer to riva_regs object
*
* DESCRIPTION:
......@@ -703,18 +789,18 @@ static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
* rivafb_remove_one()
*/
/* from GGI */
static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
static void riva_load_state(struct rivafb_info *rinfo, struct riva_regs *regs)
{
RIVA_HW_STATE *state = &regs->ext;
int i;
CRTCout(par, 0x11, 0x00);
RIVA_HW_STATE *state = &regs->ext;
CRTCout(rinfo, 0x11, 0x00);
par->riva.LockUnlock(&par->riva, 0);
rinfo->riva.LockUnlock(&rinfo->riva, 0);
par->riva.LoadStateExt(&par->riva, state);
rinfo->riva.LoadStateExt(&rinfo->riva, state);
MISCout(par, regs->misc_output);
MISCout(rinfo, regs->misc_output);
for (i = 0; i < NUM_CRT_REGS; i++) {
switch (i) {
......@@ -722,44 +808,44 @@ static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
case 0x20 ... 0x40:
break;
default:
CRTCout(par, i, regs->crtc[i]);
CRTCout(rinfo, i, regs->crtc[i]);
}
}
for (i = 0; i < NUM_ATC_REGS; i++) {
ATTRout(par, i, regs->attr[i]);
ATTRout(rinfo, i, regs->attr[i]);
}
for (i = 0; i < NUM_GRC_REGS; i++) {
GRAout(par, i, regs->gra[i]);
GRAout(rinfo, i, regs->gra[i]);
}
for (i = 0; i < NUM_SEQ_REGS; i++) {
SEQout(par, i, regs->seq[i]);
SEQout(rinfo, i, regs->seq[i]);
}
}
/**
* riva_load_video_mode - calculate timings
* @info: pointer to fb_info object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
* @video_mode: video mode to set
*
* DESCRIPTION:
* Calculate some timings and then send em off to riva_load_state().
*
* CALLED FROM:
* rivafb_set_par()
* rivafb_set_var()
*/
static void riva_load_video_mode(struct fb_info *info,
static void riva_load_video_mode(struct rivafb_info *rinfo,
struct fb_var_screeninfo *video_mode)
{
struct riva_par *par = (struct riva_par *) info->par;
struct riva_regs newmode;
int bpp, width, hDisplaySize, hDisplay, hStart,
hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
/* time to calculate */
rivafb_blank(1, info);
rivafb_blank(1, (struct fb_info *)rinfo);
bpp = video_mode->bits_per_pixel;
if (bpp == 16 && video_mode->green.length == 5)
......@@ -813,27 +899,83 @@ static void riva_load_video_mode(struct fb_info *info,
newmode.ext.width = width;
newmode.ext.height = height;
par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width,
rinfo->riva.CalcStateExt(&rinfo->riva, &newmode.ext, bpp, width,
hDisplaySize, hDisplay, hStart, hEnd,
hTotal, height, vDisplay, vStart, vEnd,
vTotal, dotClock);
if (video_mode->sync & FB_SYNC_HOR_HIGH_ACT)
newmode.misc_output &= ~0x40;
if (video_mode->sync & FB_SYNC_VERT_HIGH_ACT)
newmode.misc_output &= ~0x80;
rinfo->current_state = newmode;
riva_load_state(rinfo, &rinfo->current_state);
rinfo->riva.LockUnlock(&rinfo->riva, 0); /* important for HW cursor */
rivafb_download_cursor(rinfo);
}
/**
* riva_board_list_add - maintains board list
* @board_list: root node of list of boards
* @new_node: new node to be added
*
* DESCRIPTION:
* Adds @new_node to the list referenced by @board_list.
*
* RETURNS:
* New root node
*
* CALLED FROM:
* rivafb_init_one()
*/
static struct rivafb_info *riva_board_list_add(struct rivafb_info *board_list,
struct rivafb_info *new_node)
{
struct rivafb_info *i_p = board_list;
new_node->next = NULL;
if (board_list == NULL)
return new_node;
par->current_state = newmode;
riva_load_state(par, &par->current_state);
while (i_p->next != NULL)
i_p = i_p->next;
i_p->next = new_node;
par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
rivafb_download_cursor(par);
return board_list;
}
/**
* riva_board_list_del - maintains board list
* @board_list: root node of list of boards
* @del_node: node to be removed
*
* DESCRIPTION:
* Removes @del_node from the list referenced by @board_list.
*
* RETURNS:
* New root node
*
* CALLED FROM:
* rivafb_remove_one()
*/
static struct rivafb_info *riva_board_list_del(struct rivafb_info *board_list,
struct rivafb_info *del_node)
{
struct rivafb_info *i_p = board_list;
if (board_list == del_node)
return del_node->next;
while (i_p->next != del_node)
i_p = i_p->next;
i_p->next = del_node->next;
return board_list;
}
/**
* rivafb_do_maximize -
* @info: pointer to fb_info object containing info for current riva board
* @rinfo: pointer to rivafb_info object containing info for current riva board
* @var:
* @v:
* @nom:
* @den:
*
......@@ -845,13 +987,13 @@ static void riva_load_video_mode(struct fb_info *info,
*
*
* CALLED FROM:
* rivafb_check_var()
* rivafb_set_var()
*/
static int rivafb_do_maximize(struct fb_info *info,
static int rivafb_do_maximize(struct rivafb_info *rinfo,
struct fb_var_screeninfo *var,
struct fb_var_screeninfo *v,
int nom, int den)
{
struct riva_par *par = (struct riva_par *) info->par;
static struct {
int xres, yres;
} modes[] = {
......@@ -865,12 +1007,12 @@ static int rivafb_do_maximize(struct fb_info *info,
int i;
/* use highest possible virtual resolution */
if (var->xres_virtual == -1 && var->yres_virtual == -1) {
if (v->xres_virtual == -1 && v->yres_virtual == -1) {
printk(KERN_WARNING PFX
"using maximum available virtual resolution\n");
for (i = 0; modes[i].xres != -1; i++) {
if (modes[i].xres * nom / den * modes[i].yres <
par->ram_amount / 2)
rinfo->ram_amount / 2)
break;
}
if (modes[i].xres == -1) {
......@@ -879,26 +1021,26 @@ static int rivafb_do_maximize(struct fb_info *info,
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
var->xres_virtual = modes[i].xres;
var->yres_virtual = modes[i].yres;
v->xres_virtual = modes[i].xres;
v->yres_virtual = modes[i].yres;
printk(KERN_INFO PFX
"virtual resolution set to maximum of %dx%d\n",
var->xres_virtual, var->yres_virtual);
} else if (var->xres_virtual == -1) {
var->xres_virtual = (par->ram_amount * den /
(nom * var->yres_virtual * 2)) & ~15;
v->xres_virtual, v->yres_virtual);
} else if (v->xres_virtual == -1) {
v->xres_virtual = (rinfo->ram_amount * den /
(nom * v->yres_virtual * 2)) & ~15;
printk(KERN_WARNING PFX
"setting virtual X resolution to %d\n", var->xres_virtual);
} else if (var->yres_virtual == -1) {
var->xres_virtual = (var->xres_virtual + 15) & ~15;
var->yres_virtual = par->ram_amount * den /
(nom * var->xres_virtual * 2);
"setting virtual X resolution to %d\n", v->xres_virtual);
} else if (v->yres_virtual == -1) {
v->xres_virtual = (v->xres_virtual + 15) & ~15;
v->yres_virtual = rinfo->ram_amount * den /
(nom * v->xres_virtual * 2);
printk(KERN_WARNING PFX
"setting virtual Y resolution to %d\n", var->yres_virtual);
"setting virtual Y resolution to %d\n", v->yres_virtual);
} else {
var->xres_virtual = (var->xres_virtual + 15) & ~15;
if (var->xres_virtual * nom / den * var->yres_virtual > par->ram_amount) {
v->xres_virtual = (v->xres_virtual + 15) & ~15;
if (v->xres_virtual * nom / den * v->yres_virtual > rinfo->ram_amount) {
printk(KERN_ERR PFX
"mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
var->xres, var->yres, var->bits_per_pixel);
......@@ -907,146 +1049,29 @@ static int rivafb_do_maximize(struct fb_info *info,
}
}
if (var->xres_virtual * nom / den >= 8192) {
if (v->xres_virtual * nom / den >= 8192) {
printk(KERN_WARNING PFX
"virtual X resolution (%d) is too high, lowering to %d\n",
var->xres_virtual, 8192 * den / nom - 16);
var->xres_virtual = 8192 * den / nom - 16;
v->xres_virtual, 8192 * den / nom - 16);
v->xres_virtual = 8192 * den / nom - 16;
}
if (var->xres_virtual < var->xres) {
if (v->xres_virtual < v->xres) {
printk(KERN_ERR PFX
"virtual X resolution (%d) is smaller than real\n", var->xres_virtual);
"virtual X resolution (%d) is smaller than real\n", v->xres_virtual);
return -EINVAL;
}
if (var->yres_virtual < var->yres) {
if (v->yres_virtual < v->yres) {
printk(KERN_ERR PFX
"virtual Y resolution (%d) is smaller than real\n", var->yres_virtual);
"virtual Y resolution (%d) is smaller than real\n", v->yres_virtual);
return -EINVAL;
}
return 0;
}
/* acceleration routines */
static inline void convert_bgcolor_16(u32 *col)
{
*col = ((*col & 0x00007C00) << 9)
| ((*col & 0x000003E0) << 6)
| ((*col & 0x0000001F) << 3)
| 0xFF000000;
}
inline void wait_for_idle(struct riva_par *par)
{
while (par->riva.Busy(&par->riva));
}
/* set copy ROP, no mask */
static void riva_setup_ROP(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Patt, 5);
par->riva.Patt->Shape = 0;
par->riva.Patt->Color0 = 0xffffffff;
par->riva.Patt->Color1 = 0xffffffff;
par->riva.Patt->Monochrome[0] = 0xffffffff;
par->riva.Patt->Monochrome[1] = 0xffffffff;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = 0xCC;
}
void riva_setup_accel(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Clip, 2);
par->riva.Clip->TopLeft = 0x0;
par->riva.Clip->WidthHeight = 0x80008000;
riva_setup_ROP(par);
wait_for_idle(par);
}
static inline void reverse_order(u32 *l)
{
u8 *a = (u8 *)l;
*a++ = byte_rev[*a];
/* *a++ = byte_rev[*a];
*a++ = byte_rev[*a];*/
*a = byte_rev[*a];
}
static void rivafb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = rect->rop ? 0x66 : 0xCC;
RIVA_FIFO_FREE(par->riva, Bitmap, 1);
if (info->fix.visual == FB_VISUAL_TRUECOLOR)
par->riva.Bitmap->Color1A = ((u32 *) (info->pseudo_palette))[rect->color];
else
par->riva.Bitmap->Color1A = rect->color;
RIVA_FIFO_FREE(par->riva, Bitmap, 2);
par->riva.Bitmap->UnclippedRectangle[0].TopLeft = (rect->dx << 16) | rect->dy;
par->riva.Bitmap->UnclippedRectangle[0].WidthHeight = (rect->width << 16) | rect->height;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = 0xCC; // back to COPY
}
static void rivafb_copyarea(struct fb_info *info, struct fb_copyarea *area)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_FIFO_FREE(par->riva, Blt, 3);
par->riva.Blt->TopLeftSrc = (area->sy << 16) | area->sx;
par->riva.Blt->TopLeftDst = (area->dy << 16) | area->dx;
par->riva.Blt->WidthHeight = (area->height << 16) | area->width;
}
static void rivafb_imageblit(struct fb_info *info, struct fb_image *image)
{
struct riva_par *par = (struct riva_par *) info->par;
volatile u32 *d;
int i, j, cnt;
u32 cdat2;
RIVA_FIFO_FREE(par->riva, Bitmap, 7);
par->riva.Bitmap->ClipE.TopLeft = (image->dy << 16) | (image->dx & 0xFFFF);
par->riva.Bitmap->ClipE.BottomRight = ((image->dy + image->height) << 16) | ((image->dx + image->width) & 0xffff);
if (info->var.green.length == 6)
convert_bgcolor_16(&image->bg_color);
if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
par->riva.Bitmap->Color0E = ((u32 *) (info->pseudo_palette))[image->bg_color];
par->riva.Bitmap->Color1E = ((u32 *) (info->pseudo_palette))[image->fg_color];
} else {
par->riva.Bitmap->Color0E = image->bg_color;
par->riva.Bitmap->Color1E = image->fg_color;
}
par->riva.Bitmap->WidthHeightInE = (image->height << 16) | 32;
par->riva.Bitmap->WidthHeightOutE = (image->height << 16) | 32;
par->riva.Bitmap->PointE = (image->dy << 16) | (image->dx & 0xFFFF);
d = &par->riva.Bitmap->MonochromeData01E;
for (i = image->height; i > 0; i -= 16) {
if (i >= 16)
cnt = 16;
else
cnt = i;
RIVA_FIFO_FREE(par->riva, Bitmap, cnt);
for (j = 0; j < cnt; j++) {
if (image->width <= 8)
cdat2 = *image->data++;
else
cdat2 = *((u16*)image->data)++;
reverse_order(&cdat2);
d[j] = cdat2;
}
}
}
/* ------------------------------------------------------------------------- *
*
......@@ -1065,7 +1090,10 @@ static void rivafb_imageblit(struct fb_info *info, struct fb_image *image)
* Length of color map
*
* CALLED FROM:
* riva_getcolreg()
* rivafb_setcolreg()
* rivafb_get_cmap()
* rivafb_set_cmap()
*/
static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
{
......@@ -1074,18 +1102,24 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
assert(var != NULL);
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8:
rc = 256; /* pseudocolor... 256 entries HW palette */
break;
#endif
#ifdef FBCON_HAS_CFB16
case 15:
rc = 15; /* fix for 15 bpp depths on Riva 128 based cards */
break;
case 16:
rc = 16; /* directcolor... 16 entries SW palette */
break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
#endif
#ifdef FBCON_HAS_CFB32
case 32:
rc = 16; /* directcolor... 16 entries SW palette */
break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
#endif
default:
/* should not occur */
break;
......@@ -1094,6 +1128,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
return rc;
}
/**
* riva_getcolreg
* @regno: register index
* @red: red component
* @green: green component
* @blue: blue component
* @transp: transparency
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Read a single color register and split it into colors/transparent.
* The return values must have a 16 bit magnitude.
*
* RETURNS:
* Return != 0 for invalid regno.
*
* CALLED FROM:
* rivafb_get_cmap()
* rivafb_switch()
* fbcmap.c:fb_get_cmap()
* fbgen.c:fbgen_get_cmap()
* fbgen.c:fbgen_switch()
*/
static int riva_getcolreg(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
if (regno >= riva_get_cmap_len(&rivainfo->currcon_display->var))
return 1;
*red = rivainfo->palette[regno].red;
*green = rivainfo->palette[regno].green;
*blue = rivainfo->palette[regno].blue;
*transp = 0;
return 0;
}
/**
* rivafb_setcolreg
* @regno: register index
......@@ -1101,7 +1175,7 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* @green: green component
* @blue: blue component
* @transp: transparency
* @info: pointer to fb_info object containing info for current riva board
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Set a single color register. The values supplied have a 16 bit
......@@ -1111,54 +1185,79 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* Return != 0 for invalid regno.
*
* CALLED FROM:
* rivafb_set_cmap()
* fbcmap.c:fb_set_cmap()
* fbgen.c:gen_get_cmap()
* fbgen.c:fbgen_get_cmap()
* fbgen.c:do_install_cmap()
* fbgen.c:fbgen_set_var()
* fbgen.c:fbgen_switch()
* fbgen.c:fbgen_blank()
* fbgen.c:fbgen_blank()
*/
static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_HW_INST *chip = &par->riva;
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
RIVA_HW_INST *chip = &rivainfo->riva;
struct display *p;
DPRINTK("ENTER\n");
if (regno >= riva_get_cmap_len(&info->var))
assert(rivainfo != NULL);
assert(rivainfo->currcon_display != NULL);
p = rivainfo->currcon_display;
if (regno >= riva_get_cmap_len(&p->var))
return -EINVAL;
if (info->var.grayscale) {
rivainfo->palette[regno].red = red;
rivainfo->palette[regno].green = green;
rivainfo->palette[regno].blue = blue;
if (p->var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue =
(red * 77 + green * 151 + blue * 28) >> 8;
}
switch (info->var.bits_per_pixel) {
switch (p->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8:
/* "transparent" stuff is completely ignored. */
riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
break;
#endif /* FBCON_HAS_CFB8 */
#ifdef FBCON_HAS_CFB16
case 16:
assert(regno < 16);
if (info->var.green.length == 5) {
if (p->var.green.length == 5) {
/* 0rrrrrgg gggbbbbb */
((u16 *)(info->pseudo_palette))[regno] =
rivainfo->con_cmap.cfb16[regno] =
((red & 0xf800) >> 1) |
((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
} else {
/* rrrrrggg gggbbbbb */
((u16 *)(info->pseudo_palette))[regno] =
rivainfo->con_cmap.cfb16[regno] =
((red & 0xf800) >> 0) |
((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11);
}
break;
#endif /* FBCON_HAS_CFB16 */
#ifdef FBCON_HAS_CFB32
case 32:
assert(regno < 16);
((u32 *)(info->pseudo_palette))[regno] =
rivainfo->con_cmap.cfb32[regno] =
((red & 0xff00) << 8) |
((green & 0xff00)) | ((blue & 0xff00) >> 8);
break;
#endif /* FBCON_HAS_CFB32 */
default:
/* do nothing */
break;
}
return 0;
}
......@@ -1170,58 +1269,177 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
*
* ------------------------------------------------------------------------- */
static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int rivafb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *p;
DPRINTK("ENTER\n");
assert(fix != NULL);
assert(info != NULL);
assert(rivainfo->drvr_name && rivainfo->drvr_name[0]);
assert(rivainfo->fb_base_phys > 0);
assert(rivainfo->ram_amount > 0);
p = (con < 0) ? rivainfo->info.disp : &fb_display[con];
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
sprintf(fix->id, "nVidia %s", rivainfo->drvr_name);
fix->smem_start = rivainfo->fb_base_phys;
fix->smem_len = rivainfo->ram_amount;
fix->type = p->type;
fix->type_aux = p->type_aux;
fix->visual = p->visual;
fix->xpanstep = 1;
fix->ypanstep = 1;
fix->ywrapstep = 0; /* FIXME: no ywrap for now */
fix->line_length = p->line_length;
fix->mmio_start = rivainfo->ctrl_base_phys;
fix->mmio_len = rivainfo->base0_region_size;
fix->smem_start = rivainfo->fb_base_phys;
fix->smem_len = rivainfo->base1_region_size;
switch (rivainfo->riva.Architecture) {
case NV_ARCH_03:
fix->accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04: /* riva_hw.c now doesn't distinguish between TNT & TNT2 */
fix->accel = FB_ACCEL_NV4;
break;
case NV_ARCH_10: /* FIXME: ID for GeForce */
fix->accel = FB_ACCEL_NV4;
break;
}
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(info != NULL);
assert(var != NULL);
*var = (con < 0) ? rivainfo->disp.var : fb_display[con].var;
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *dsp;
struct fb_var_screeninfo v;
int nom, den; /* translating from pixels->bytes */
int accel;
unsigned chgvar = 0;
switch (var->bits_per_pixel) {
DPRINTK("ENTER\n");
assert(info != NULL);
assert(var != NULL);
DPRINTK("Requested: %dx%dx%d\n", var->xres, var->yres,
var->bits_per_pixel);
DPRINTK(" virtual: %dx%d\n", var->xres_virtual,
var->yres_virtual);
DPRINTK(" offset: (%d,%d)\n", var->xoffset, var->yoffset);
DPRINTK("grayscale: %d\n", var->grayscale);
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
assert(dsp != NULL);
/* if var has changed, we should call changevar() later */
if (con >= 0) {
chgvar = ((dsp->var.xres != var->xres) ||
(dsp->var.yres != var->yres) ||
(dsp->var.xres_virtual != var->xres_virtual) ||
(dsp->var.yres_virtual != var->yres_virtual) ||
(dsp->var.accel_flags != var->accel_flags) ||
(dsp->var.bits_per_pixel != var->bits_per_pixel)
|| memcmp(&dsp->var.red, &var->red,
sizeof(var->red))
|| memcmp(&dsp->var.green, &var->green,
sizeof(var->green))
|| memcmp(&dsp->var.blue, &var->blue,
sizeof(var->blue)));
}
memcpy(&v, var, sizeof(v));
accel = v.accel_flags & FB_ACCELF_TEXT;
switch (v.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 1 ... 8:
var->bits_per_pixel = 8;
v.bits_per_pixel = 8;
nom = 1;
den = 1;
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
v.red.offset = 0;
v.red.length = 8;
v.green.offset = 0;
v.green.length = 8;
v.blue.offset = 0;
v.blue.length = 8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 9 ... 15:
var->green.length = 5;
v.green.length = 5;
/* fall through */
case 16:
var->bits_per_pixel = 16;
v.bits_per_pixel = 16;
nom = 2;
den = 1;
if (var->green.length == 5) {
if (v.green.length == 5) {
/* 0rrrrrgg gggbbbbb */
var->red.offset = 10;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 5;
var->blue.length = 5;
v.red.offset = 10;
v.green.offset = 5;
v.blue.offset = 0;
v.red.length = 5;
v.green.length = 5;
v.blue.length = 5;
} else {
/* rrrrrggg gggbbbbb */
var->red.offset = 11;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
v.red.offset = 11;
v.green.offset = 5;
v.blue.offset = 0;
v.red.length = 5;
v.green.length = 6;
v.blue.length = 5;
}
break;
#endif
#ifdef FBCON_HAS_CFB32
case 17 ... 32:
var->bits_per_pixel = 32;
v.bits_per_pixel = 32;
nom = 4;
den = 1;
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
v.red.offset = 16;
v.green.offset = 8;
v.blue.offset = 0;
v.red.length = 8;
v.green.length = 8;
v.blue.length = 8;
break;
#endif
default:
printk(KERN_ERR PFX
"mode %dx%dx%d rejected...color depth not supported.\n",
......@@ -1230,57 +1448,122 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return -EINVAL;
}
if (rivafb_do_maximize(info, var, nom, den) < 0)
if (rivafb_do_maximize(rivainfo, var, &v, nom, den) < 0)
return -EINVAL;
if (var->xoffset < 0)
var->xoffset = 0;
if (var->yoffset < 0)
var->yoffset = 0;
if (v.xoffset < 0)
v.xoffset = 0;
if (v.yoffset < 0)
v.yoffset = 0;
/* truncate xoffset and yoffset to maximum if too high */
if (var->xoffset > var->xres_virtual - var->xres)
var->xoffset = var->xres_virtual - var->xres - 1;
if (v.xoffset > v.xres_virtual - v.xres)
v.xoffset = v.xres_virtual - v.xres - 1;
if (var->yoffset > var->yres_virtual - var->yres)
var->yoffset = var->yres_virtual - var->yres - 1;
if (v.yoffset > v.yres_virtual - v.yres)
v.yoffset = v.yres_virtual - v.yres - 1;
var->red.msb_right =
var->green.msb_right =
var->blue.msb_right =
var->transp.offset = var->transp.length = var->transp.msb_right = 0;
var->accel_flags |= FB_ACCELF_TEXT;
v.red.msb_right =
v.green.msb_right =
v.blue.msb_right =
v.transp.offset = v.transp.length = v.transp.msb_right = 0;
switch (v.activate & FB_ACTIVATE_MASK) {
case FB_ACTIVATE_TEST:
DPRINTK("EXIT - FB_ACTIVATE_TEST\n");
return 0;
case FB_ACTIVATE_NXTOPEN: /* ?? */
case FB_ACTIVATE_NOW:
break; /* continue */
default:
DPRINTK("EXIT - unknown activation type\n");
return -EINVAL; /* unknown */
}
memcpy(&dsp->var, &v, sizeof(v));
if (chgvar) {
riva_set_dispsw(rivainfo, dsp);
if (accel) {
if (nomove)
dsp->scrollmode = SCROLL_YNOMOVE;
else
dsp->scrollmode = 0;
} else
dsp->scrollmode = SCROLL_YREDRAW;
if (info && info->changevar)
info->changevar(con);
}
rivafb_create_cursor(rivainfo, fontwidth(dsp), fontheight(dsp));
riva_load_video_mode(rivainfo, &v);
if (accel) riva_setup_accel(rivainfo);
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_set_par(struct fb_info *info)
static int rivafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *dsp;
switch (info->var.bits_per_pixel) {
case 8:
info->fix.line_length = info->var.xres_virtual;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
break;
case 16:
info->fix.line_length = info->var.xres_virtual * 2;
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
break;
case 32:
info->fix.line_length = info->var.xres_virtual * 4;
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
break;
}
/*
if (par->cursor) {
disp->dispsw.cursor = rivafb_cursor;
disp->dispsw.set_font = rivafb_set_font;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
assert(cmap != NULL);
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
if (con == info->currcon) { /* current console? */
int rc = fb_get_cmap(cmap, kspc, riva_getcolreg, info);
DPRINTK("EXIT - returning %d\n", rc);
return rc;
} else if (dsp->cmap.len) /* non default colormap? */
fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
else
fb_copy_cmap(fb_default_cmap
(riva_get_cmap_len(&dsp->var)), cmap,
kspc ? 0 : 2);
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *dsp;
unsigned int cmap_len;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
assert(cmap != NULL);
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
cmap_len = riva_get_cmap_len(&dsp->var);
if (dsp->cmap.len != cmap_len) {
int err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
if (err) {
DPRINTK("EXIT - returning %d\n", err);
return err;
}
}
rivafb_create_cursor(par, fontwidth(dsp), fontheight(dsp));
*/
if (con == info->currcon) { /* current console? */
int rc = fb_set_cmap(cmap, kspc, info);
DPRINTK("EXIT - returning %d\n", rc);
return rc;
} else
fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
DPRINTK("EXIT, returning 0\n");
riva_load_video_mode(info, &info->var);
riva_setup_accel(par);
return 0;
}
......@@ -1288,7 +1571,7 @@ static int rivafb_set_par(struct fb_info *info)
* rivafb_pan_display
* @var: standard kernel fb changeable data
* @con: TODO
* @info: pointer to fb_info object containing info for current riva board
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Pan (or wrap, depending on the `vmode' field) the display using the
......@@ -1300,58 +1583,132 @@ static int rivafb_set_par(struct fb_info *info)
static int rivafb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
struct display *dsp;
unsigned int base;
struct display *dsp;
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
if (var->xoffset > (var->xres_virtual - var->xres))
return -EINVAL;
if (var->yoffset > (var->yres_virtual - var->yres))
return -EINVAL;
dsp = (con < 0) ? info->disp : &fb_display[con];
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0
|| var->yoffset >= info->var.yres_virtual
|| var->yoffset >= dsp->var.yres_virtual
|| var->xoffset) return -EINVAL;
} else {
if (var->xoffset + info->var.xres > info->var.xres_virtual ||
var->yoffset + info->var.yres > info->var.yres_virtual)
if (var->xoffset + dsp->var.xres > dsp->var.xres_virtual ||
var->yoffset + dsp->var.yres > dsp->var.yres_virtual)
return -EINVAL;
}
base = var->yoffset * dsp->line_length + var->xoffset;
if (con == info->currcon)
par->riva.SetStartAddress(&par->riva, base);
if (con == info->currcon) {
rivainfo->riva.SetStartAddress(&rivainfo->riva, base);
}
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
dsp->var.xoffset = var->xoffset;
dsp->var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
info->var.vmode |= FB_VMODE_YWRAP;
dsp->var.vmode |= FB_VMODE_YWRAP;
else
info->var.vmode &= ~FB_VMODE_YWRAP;
dsp->var.vmode &= ~FB_VMODE_YWRAP;
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, int con, struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
/* no rivafb-specific ioctls */
DPRINTK("EXIT, returning -EINVAL\n");
return -EINVAL;
}
static int rivafb_rasterimg(struct fb_info *info, int start)
{
struct riva_par *par = (struct riva_par *) info->par;
struct rivafb_info *rinfo = (struct rivafb_info *)info;
wait_for_idle(par);
wait_for_idle(rinfo);
return 0;
}
static int rivafb_switch(int con, struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct fb_cmap *cmap;
struct display *dsp;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
if (info->currcon >= 0) {
/* Do we have to save the colormap? */
cmap = &(rivainfo->currcon_display->cmap);
DPRINTK("switch1: con = %d, cmap.len = %d\n",
info->currcon, cmap->len);
if (cmap->len) {
DPRINTK("switch1a: %p %p %p %p\n", cmap->red,
cmap->green, cmap->blue, cmap->transp);
fb_get_cmap(cmap, 1, riva_getcolreg, info);
}
}
info->currcon = con;
rivainfo->currcon_display = dsp;
rivafb_set_var(&dsp->var, con, info);
riva_set_dispsw(rivainfo, dsp);
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_updatevar(int con, struct fb_info *info)
{
int rc;
DPRINTK("ENTER\n");
rc = (con < 0) ? -EINVAL : rivafb_pan_display(&fb_display[con].var,
con, info);
DPRINTK("EXIT, returning %d\n", rc);
return rc;
}
static int rivafb_blank(int blank, struct fb_info *info)
{
struct riva_par *par = (struct riva_par *)info->par;
unsigned char tmp, vesa;
struct rivafb_info *rinfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(rinfo != NULL);
tmp = SEQin(par, 0x01) & ~0x20; /* screen on/off */
vesa = CRTCin(par, 0x1a) & ~0xc0; /* sync on/off */
tmp = SEQin(rinfo, 0x01) & ~0x20; /* screen on/off */
vesa = CRTCin(rinfo, 0x1a) & ~0xc0; /* sync on/off */
if (blank) {
tmp |= 0x20;
......@@ -1370,11 +1727,15 @@ static int rivafb_blank(int blank, struct fb_info *info)
}
}
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
SEQout(rinfo, 0x01, tmp);
CRTCout(rinfo, 0x1a, vesa);
DPRINTK("EXIT\n");
return 0;
}
/* ------------------------------------------------------------------------- *
*
* initialization helper functions
......@@ -1384,29 +1745,78 @@ static int rivafb_blank(int blank, struct fb_info *info)
/* kernel interface */
static struct fb_ops riva_fb_ops = {
owner: THIS_MODULE,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_set_var: gen_set_var,
fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap,
fb_check_var: rivafb_check_var,
fb_set_par: rivafb_set_par,
fb_get_fix: rivafb_get_fix,
fb_get_var: rivafb_get_var,
fb_set_var: rivafb_set_var,
fb_get_cmap: rivafb_get_cmap,
fb_set_cmap: rivafb_set_cmap,
fb_setcolreg: rivafb_setcolreg,
fb_pan_display: rivafb_pan_display,
fb_blank: rivafb_blank,
fb_fillrect: rivafb_fillrect,
fb_copyarea: rivafb_copyarea,
fb_imageblit: rivafb_imageblit,
fb_ioctl: rivafb_ioctl,
fb_rasterimg: rivafb_rasterimg,
};
static int __devinit riva_set_fbinfo(struct fb_info *info)
static int __devinit riva_init_disp_var(struct rivafb_info *rinfo)
{
#ifndef MODULE
if (mode_option)
fb_find_mode(&rinfo->disp.var, &rinfo->info, mode_option,
NULL, 0, NULL, 8);
#endif
return 0;
}
static int __devinit riva_init_disp(struct rivafb_info *rinfo)
{
struct fb_info *info;
struct display *disp;
DPRINTK("ENTER\n");
assert(rinfo != NULL);
info = &rinfo->info;
disp = &rinfo->disp;
disp->var = rivafb_default_var;
if (noaccel)
disp->var.accel_flags &= ~FB_ACCELF_TEXT;
else
disp->var.accel_flags |= FB_ACCELF_TEXT;
info->disp = disp;
/* FIXME: assure that disp->cmap is completely filled out */
rinfo->currcon_display = disp;
if ((riva_init_disp_var(rinfo)) < 0) {
DPRINTK("EXIT, returning -1\n");
return -1;
}
riva_set_dispsw(rinfo, disp);
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int __devinit riva_set_fbinfo(struct rivafb_info *rinfo)
{
strcpy(info->modename, rivafb_fix.id);
struct fb_info *info;
assert(rinfo != NULL);
info = &rinfo->info;
strcpy(info->modename, rinfo->drvr_name);
info->node = NODEV;
info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &riva_fb_ops;
info->fix = rivafb_fix;
info->screen_base = rinfo->fb_base;
/* FIXME: set monspecs to what??? */
info->display_fg = NULL;
......@@ -1415,21 +1825,12 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
info->fontname[sizeof(info->fontname) - 1] = 0;
info->changevar = NULL;
info->switch_con = gen_switch;
info->updatevar = gen_update_var;
info->switch_con = rivafb_switch;
info->updatevar = rivafb_updatevar;
#ifndef MODULE
if (mode_option) {
int err = fb_find_mode(&info->var, info, mode_option,
NULL, 0, NULL, 8);
if (!err || err == 4)
info->var = rivafb_default_var;
} else
#endif
info->var = rivafb_default_var;
fb_alloc_cmap(&info->cmap, riva_get_cmap_len(&info->var), 0);
if (riva_init_disp(rinfo) < 0) /* must be done last */
return -1;
gen_set_var(&info->var, -1, info);
return 0;
}
......@@ -1444,230 +1845,194 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
static int __devinit rivafb_init_one(struct pci_dev *pd,
const struct pci_device_id *ent)
{
struct rivafb_info *rinfo;
struct riva_chip_info *rci = &riva_chip_info[ent->driver_data];
struct riva_par *default_par;
struct fb_info *info;
int size;
assert(pd != NULL);
assert(rci != NULL);
size = sizeof(struct fb_info) + sizeof(struct display) + sizeof(u32) * 16;
info = kmalloc(size, GFP_KERNEL);
if (!info)
rinfo = kmalloc(sizeof(struct rivafb_info), GFP_KERNEL);
if (!rinfo)
goto err_out;
memset(info, 0, size);
default_par = kmalloc(sizeof(struct riva_par), GFP_KERNEL);
if (!default_par)
goto err_out;
memset(rinfo, 0, sizeof(struct rivafb_info));
memset(default_par, 0, sizeof(struct riva_par));
rinfo->drvr_name = rci->name;
rinfo->riva.Architecture = rci->arch_rev;
info->disp = (struct display *)(info + 1);
info->pseudo_palette = (void *)(info->disp + 1);
rinfo->pd = pd;
rinfo->base0_region_size = pci_resource_len(pd, 0);
rinfo->base1_region_size = pci_resource_len(pd, 1);
strcat(rivafb_fix.id, rci->name);
default_par->riva.Architecture = rci->arch_rev;
assert(rinfo->base0_region_size >= 0x00800000); /* from GGI */
assert(rinfo->base1_region_size >= 0x01000000); /* from GGI */
rivafb_fix.mmio_len = pci_resource_len(pd, 0);
rivafb_fix.smem_len = pci_resource_len(pd, 1);
rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0);
rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1);
assert(rivafb_fix.mmio_len >= 0x00800000); /* from GGI */
assert(rivafb_fix.smem_len >= 0x01000000); /* from GGI */
rivafb_fix.mmio_start = pci_resource_start(pd, 0);
rivafb_fix.smem_start = pci_resource_start(pd, 1);
if (!request_mem_region(rivafb_fix.mmio_start,
rivafb_fix.mmio_len, "rivafb")) {
if (!request_mem_region(rinfo->ctrl_base_phys,
rinfo->base0_region_size, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve MMIO region\n");
goto err_out_kfree;
}
default_par->ctrl_base = ioremap(rivafb_fix.mmio_start,
rivafb_fix.mmio_len);
if (!default_par->ctrl_base) {
if (!request_mem_region(rinfo->fb_base_phys,
rinfo->base1_region_size, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0;
}
rinfo->ctrl_base = ioremap(rinfo->ctrl_base_phys,
rinfo->base0_region_size);
if (!rinfo->ctrl_base) {
printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
goto err_out_free_base1;
}
default_par->riva.EnableIRQ = 0;
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base + 0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base + 0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base + 0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base + 0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base + 0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base + 0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base + 0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base + 0x00800000);
default_par->riva.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000);
default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000);
default_par->riva.PVIO = (U008 *)(default_par->ctrl_base + 0x000C0000);
default_par->riva.IO = (MISCin(default_par) & 0x01) ? 0x3D0 : 0x3B0;
switch (default_par->riva.Architecture) {
case NV_ARCH_03:
/*
* We have to map the full BASE_1 aperture for Riva128's
* because they use the PRAMIN set in "framebuffer" space
*/
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0;
rinfo->fb_base = ioremap(rinfo->fb_base_phys,
rinfo->base1_region_size);
if (!rinfo->fb_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
#ifdef CONFIG_MTRR
if (!nomtrr) {
rinfo->mtrr.vram = mtrr_add(rinfo->fb_base_phys,
rinfo->base1_region_size, MTRR_TYPE_WRCOMB, 1);
if (rinfo->mtrr.vram < 0) {
printk(KERN_ERR PFX "unable to setup MTRR\n");
} else {
rinfo->mtrr.vram_valid = 1;
/* let there be speed */
printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
}
}
#endif /* CONFIG_MTRR */
info->screen_base = ioremap(rivafb_fix.smem_start,
rivafb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
rinfo->riva.EnableIRQ = 0;
rinfo->riva.PRAMDAC = (unsigned *)(rinfo->ctrl_base + 0x00680000);
rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000);
rinfo->riva.PFIFO = (unsigned *)(rinfo->ctrl_base + 0x00002000);
rinfo->riva.PGRAPH = (unsigned *)(rinfo->ctrl_base + 0x00400000);
rinfo->riva.PEXTDEV = (unsigned *)(rinfo->ctrl_base + 0x00101000);
rinfo->riva.PTIMER = (unsigned *)(rinfo->ctrl_base + 0x00009000);
rinfo->riva.PMC = (unsigned *)(rinfo->ctrl_base + 0x00000000);
rinfo->riva.FIFO = (unsigned *)(rinfo->ctrl_base + 0x00800000);
rinfo->riva.PCIO = (U008 *)(rinfo->ctrl_base + 0x00601000);
rinfo->riva.PDIO = (U008 *)(rinfo->ctrl_base + 0x00681000);
rinfo->riva.PVIO = (U008 *)(rinfo->ctrl_base + 0x000C0000);
default_par->riva.PRAMIN = (unsigned *)(info->screen_base + 0x00C00000);
rivafb_fix.accel = FB_ACCEL_NV3;
rinfo->riva.IO = (MISCin(rinfo) & 0x01) ? 0x3D0 : 0x3B0;
switch (rinfo->riva.Architecture) {
case NV_ARCH_03:
rinfo->riva.PRAMIN = (unsigned *)(rinfo->fb_base + 0x00C00000);
break;
case NV_ARCH_04:
case NV_ARCH_10:
case NV_ARCH_20:
/* riva_hw.c now doesn't distinguish between TNT & TNT2 */
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base + 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base + 0x00710000);
rivafb_fix.accel = FB_ACCEL_NV4;
rinfo->riva.PCRTC = (unsigned *)(rinfo->ctrl_base + 0x00600000);
rinfo->riva.PRAMIN = (unsigned *)(rinfo->ctrl_base + 0x00710000);
break;
}
RivaGetConfig(&default_par->riva);
/* unlock io */
CRTCout(default_par, 0x11, 0xFF);/* vgaHWunlock()+riva unlock (0x7F) */
default_par->riva.LockUnlock(&default_par->riva, 0);
riva_save_state(default_par, &default_par->initial_state);
default_par->ram_amount = default_par->riva.RamAmountKBytes * 1024;
default_par->dclk_max = default_par->riva.MaxVClockFreqKHz * 1000;
RivaGetConfig(&rinfo->riva);
if (default_par->riva.Architecture != NV_ARCH_03) {
/*
* Now the _normal_ chipsets can just map the amount of real
* physical ram instead of the whole aperture
*/
rivafb_fix.smem_len = default_par->ram_amount;
/* back to normal */
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0;
}
assert(rinfo->pd != NULL);
info->screen_base = ioremap(rivafb_fix.smem_start,
rivafb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
}
/* unlock io */
CRTCout(rinfo, 0x11, 0xFF); /* vgaHWunlock() + riva unlock (0x7F) */
rinfo->riva.LockUnlock(&rinfo->riva, 0);
#ifdef CONFIG_MTRR
if (!nomtrr) {
default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start,
rivafb_fix.smem_len, MTRR_TYPE_WRCOMB, 1);
if (default_par->mtrr.vram < 0) {
printk(KERN_ERR PFX "unable to setup MTRR\n");
} else {
default_par->mtrr.vram_valid = 1;
/* let there be speed */
printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
}
}
#endif /* CONFIG_MTRR */
riva_save_state(rinfo, &rinfo->initial_state);
if (!nohwcursor) default_par->cursor = rivafb_init_cursor(info);
rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024;
rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000;
info->par = default_par;
if (!nohwcursor) rinfo->cursor = rivafb_init_cursor(rinfo);
if (riva_set_fbinfo(info) < 0) {
if (riva_set_fbinfo(rinfo) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n");
goto err_out_cursor;
}
if (register_framebuffer(info) < 0) {
if (register_framebuffer((struct fb_info *)rinfo) < 0) {
printk(KERN_ERR PFX
"error registering riva framebuffer\n");
goto err_out_load_state;
}
pci_set_drvdata(pd, info);
riva_boards = riva_board_list_add(riva_boards, rinfo);
pci_set_drvdata(pd, rinfo);
printk(KERN_INFO PFX
"PCI nVidia NV%x framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
default_par->riva.Architecture,
"PCI nVidia NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
rinfo->riva.Architecture,
RIVAFB_VERSION,
info->fix.id,
default_par->ram_amount / (1024 * 1024),
info->fix.smem_start);
rinfo->drvr_name,
rinfo->ram_amount / (1024 * 1024),
rinfo->fb_base_phys);
return 0;
err_out_load_state:
riva_load_state(default_par, &default_par->initial_state);
riva_load_state(rinfo, &rinfo->initial_state);
err_out_cursor:
rivafb_exit_cursor(default_par);
rivafb_exit_cursor(rinfo);
/* err_out_iounmap_fb: */
iounmap(info->screen_base);
iounmap(rinfo->fb_base);
err_out_iounmap_ctrl:
iounmap(default_par->ctrl_base);
iounmap(rinfo->ctrl_base);
err_out_free_base1:
release_mem_region(info->fix.smem_start, info->fix.smem_len);
release_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size);
err_out_free_base0:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
release_mem_region(rinfo->ctrl_base_phys, rinfo->base0_region_size);
err_out_kfree:
kfree(default_par);
kfree(info);
kfree(rinfo);
err_out:
return -ENODEV;
}
static void __devexit rivafb_remove_one(struct pci_dev *pd)
{
struct fb_info *board = pci_get_drvdata(pd);
struct riva_par *par = (struct riva_par *) board->par;
struct rivafb_info *board = pci_get_drvdata(pd);
if (!board)
return;
riva_load_state(par, &par->initial_state);
riva_boards = riva_board_list_del(riva_boards, board);
riva_load_state(board, &board->initial_state);
unregister_framebuffer(board);
unregister_framebuffer((struct fb_info *)board);
rivafb_exit_cursor(par);
rivafb_exit_cursor(board);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, board->fix.smem_start,
board->fix.smem_len);
if (board->mtrr.vram_valid)
mtrr_del(board->mtrr.vram, board->fb_base_phys,
board->base1_region_size);
#endif /* CONFIG_MTRR */
iounmap(par->ctrl_base);
iounmap(board->screen_base);
iounmap(board->ctrl_base);
iounmap(board->fb_base);
release_mem_region(board->fix.mmio_start,
board->fix.mmio_len);
release_mem_region(board->fix.smem_start,
board->fix.smem_len);
release_mem_region(board->ctrl_base_phys,
board->base0_region_size);
release_mem_region(board->fb_base_phys,
board->base1_region_size);
kfree(par);
kfree(board);
pci_set_drvdata(pd, NULL);
}
/* ------------------------------------------------------------------------- *
*
* initialization
......@@ -1698,6 +2063,10 @@ int __init rivafb_setup(char *options)
} else if (!strncmp(this_opt, "noblink", 7)) {
noblink = 1;
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
} else if (!strncmp(this_opt, "nomove", 6)) {
nomove = 1;
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
......@@ -1750,6 +2119,10 @@ module_exit(rivafb_exit);
MODULE_PARM(font, "s");
MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)");
MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)");
MODULE_PARM(nomove, "i");
MODULE_PARM_DESC(nomove, "Enables YSCROLL_NOMOVE (0 or 1=enabled) (default=0)");
MODULE_PARM(nohwcursor, "i");
MODULE_PARM_DESC(nohwcursor, "Disables hardware cursor (0 or 1=disabled) (default=0)");
MODULE_PARM(noblink, "i");
......
......@@ -1220,7 +1220,6 @@ static void CalcStateExt
state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
break;
case NV_ARCH_10:
case NV_ARCH_20:
nv10UpdateArbitrationSettings(VClk,
pixelDepth * 8,
&(state->arbitration0),
......@@ -1286,7 +1285,6 @@ static void UpdateFifoState
chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]);
break;
case NV_ARCH_10:
case NV_ARCH_20:
/*
* Initialize state for the RivaTriangle3D05 routines.
*/
......@@ -1395,7 +1393,6 @@ static void LoadStateExt
chip->PGRAPH[0x0000067C/4] = state->pitch3;
break;
case NV_ARCH_10:
case NV_ARCH_20:
LOAD_FIXED_STATE(nv10,PFIFO);
LOAD_FIXED_STATE(nv10,PRAMIN);
LOAD_FIXED_STATE(nv10,PGRAPH);
......@@ -1424,31 +1421,15 @@ static void LoadStateExt
chip->Tri03 = 0L;
break;
}
if (chip->Architecture == NV_ARCH_10) {
chip->PGRAPH[0x00000640/4] = state->offset0;
chip->PGRAPH[0x00000644/4] = state->offset1;
chip->PGRAPH[0x00000648/4] = state->offset2;
chip->PGRAPH[0x0000064C/4] = state->offset3;
chip->PGRAPH[0x00000670/4] = state->pitch0;
chip->PGRAPH[0x00000674/4] = state->pitch1;
chip->PGRAPH[0x00000678/4] = state->pitch2;
chip->PGRAPH[0x0000067C/4] = state->pitch3;
chip->PGRAPH[0x00000680/4] = state->pitch3;
} else {
chip->PGRAPH[0x00000820/4] = state->offset0;
chip->PGRAPH[0x00000824/4] = state->offset1;
chip->PGRAPH[0x00000828/4] = state->offset2;
chip->PGRAPH[0x0000082C/4] = state->offset3;
chip->PGRAPH[0x00000850/4] = state->pitch0;
chip->PGRAPH[0x00000854/4] = state->pitch1;
chip->PGRAPH[0x00000858/4] = state->pitch2;
chip->PGRAPH[0x0000085C/4] = state->pitch3;
chip->PGRAPH[0x00000860/4] = state->pitch3;
chip->PGRAPH[0x00000864/4] = state->pitch3;
chip->PGRAPH[0x000009A4/4] = chip->PFB[0x00000200/4];
chip->PGRAPH[0x000009A8/4] = chip->PFB[0x00000204/4];
}
chip->PGRAPH[0x00000640/4] = state->offset0;
chip->PGRAPH[0x00000644/4] = state->offset1;
chip->PGRAPH[0x00000648/4] = state->offset2;
chip->PGRAPH[0x0000064C/4] = state->offset3;
chip->PGRAPH[0x00000670/4] = state->pitch0;
chip->PGRAPH[0x00000674/4] = state->pitch1;
chip->PGRAPH[0x00000678/4] = state->pitch2;
chip->PGRAPH[0x0000067C/4] = state->pitch3;
chip->PGRAPH[0x00000680/4] = state->pitch3;
chip->PGRAPH[0x00000B00/4] = chip->PFB[0x00000240/4];
chip->PGRAPH[0x00000B04/4] = chip->PFB[0x00000244/4];
chip->PGRAPH[0x00000B08/4] = chip->PFB[0x00000248/4];
......@@ -1626,7 +1607,6 @@ static void UnloadStateExt
state->pitch3 = chip->PGRAPH[0x0000067C/4];
break;
case NV_ARCH_10:
case NV_ARCH_20:
state->offset0 = chip->PGRAPH[0x00000640/4];
state->offset1 = chip->PGRAPH[0x00000644/4];
state->offset2 = chip->PGRAPH[0x00000648/4];
......
......@@ -74,8 +74,6 @@ typedef unsigned int U032;
#define NV_ARCH_03 0x03
#define NV_ARCH_04 0x04
#define NV_ARCH_10 0x10
#define NV_ARCH_20 0x20
/***************************************************************************\
* *
* FIFO registers. *
......
......@@ -3,7 +3,6 @@
#include <linux/config.h>
#include <linux/fb.h>
#include <linux/timer.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb4.h>
#include <video/fbcon-cfb8.h>
......@@ -28,35 +27,58 @@ struct riva_regs {
RIVA_HW_STATE ext;
};
#define MAX_CURS 32
struct riva_cursor {
int enable;
int on;
int vbl_cnt;
int last_slice_moves, prev_slice_moves;
int blink_rate;
struct {
u16 x, y;
} pos, size;
unsigned short image[MAX_CURS*MAX_CURS];
struct timer_list *timer;
};
typedef struct {
unsigned char red, green, blue, transp;
} riva_cfb8_cmap_t;
struct rivafb_info;
struct rivafb_info {
struct fb_info info; /* kernel framebuffer info */
/* describes the state of a Riva board */
struct riva_par {
RIVA_HW_INST riva; /* interface to riva_hw.c */
const char *drvr_name; /* Riva hardware board type */
unsigned long ctrl_base_phys; /* physical control register base addr */
unsigned long fb_base_phys; /* physical framebuffer base addr */
caddr_t ctrl_base; /* virtual control register base addr */
caddr_t fb_base; /* virtual framebuffer base addr */
unsigned ram_amount; /* amount of RAM on card, in bytes */
unsigned dclk_max; /* max DCLK */
struct riva_regs initial_state; /* initial startup video mode */
struct riva_regs current_state;
struct display disp;
int currcon;
struct display *currcon_display;
struct rivafb_info *next;
struct pci_dev *pd; /* pointer to board's pci info */
unsigned base0_region_size; /* size of control register region */
unsigned base1_region_size; /* size of framebuffer region */
struct riva_cursor *cursor;
caddr_t ctrl_base; /* Virtual control register base addr */
struct display_switch dispsw;
riva_cfb8_cmap_t palette[256]; /* VGA DAC palette cache */
#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
union {
#ifdef FBCON_HAS_CFB16
u_int16_t cfb16[16];
#endif
#ifdef FBCON_HAS_CFB32
u_int32_t cfb32[16];
#endif
} con_cmap;
#endif /* FBCON_HAS_CFB16 | FBCON_HAS_CFB32 */
#ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr;
struct { int vram; int vram_valid; } mtrr;
#endif
};
......
......@@ -661,7 +661,7 @@ static struct sa1100fb_mach_info xp860_info __initdata = {
static struct sa1100fb_mach_info * __init
sa1100fb_get_machine_info(struct sa1100_par *par)
sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
{
struct sa1100fb_mach_info *inf = NULL;
......@@ -683,7 +683,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
#ifdef CONFIG_SA1100_H3XXX
if (machine_is_h3600()) {
inf = &h3600_info;
par->rgb[RGB_16] = &h3600_rgb_16;
fbi->rgb[RGB_16] = &h3600_rgb_16;
}
if (machine_is_h3100()) {
inf = &h3100_info;
......@@ -705,7 +705,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
#ifdef CONFIG_SA1100_FREEBIRD
if (machine_is_freebird()) {
inf = &freebird_info;
par->rgb[RGB_16] = &freebird_rgb16;
fbi->rgb[RGB_16] = &freebird_rgb16;
}
#endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
......@@ -758,10 +758,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
if (machine_is_stork()) {
#if STORK_TFT
inf = &stork_tft_info;
par->rgb[RGB_16] = &stork_tft_rgb_16;
fbi->rgb[RGB_16] = &stork_tft_rgb_16;
#else
inf = &stork_dstn_info;
par->rgb[RGB_16] = &stork_dstn_rgb_16;
fbi->rgb[RGB_16] = &stork_dstn_rgb_16;
#endif
}
#endif
......@@ -773,10 +773,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
return inf;
}
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *);
static void set_ctrlr_state(struct sa1100_par *par, u_int state);
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
static inline void sa1100fb_schedule_task(struct sa1100_par *par, u_int state)
static inline void sa1100fb_schedule_task(struct sa1100fb_info *fbi, u_int state)
{
unsigned long flags;
......@@ -789,18 +789,43 @@ static inline void sa1100fb_schedule_task(struct sa1100_par *par, u_int state)
* 2. When we are blanking, but immediately unblank before we have
* blanked. We do the "REENABLE" thing here as well, just to be sure.
*/
if (par->task_state == C_ENABLE && state == C_REENABLE)
if (fbi->task_state == C_ENABLE && state == C_REENABLE)
state = (u_int) -1;
if (par->task_state == C_DISABLE && state == C_ENABLE)
if (fbi->task_state == C_DISABLE && state == C_ENABLE)
state = C_REENABLE;
if (state != (u_int)-1) {
par->task_state = state;
schedule_task(&par->task);
fbi->task_state = state;
schedule_task(&fbi->task);
}
local_irq_restore(flags);
}
/*
* Get the VAR structure pointer for the specified console
*/
static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
{
return (con == info->currcon || con == -1) ? &info->var : &fb_display[con].var;
}
/*
* Get the DISPLAY structure pointer for the specified console
*/
static inline struct display *get_con_display(struct fb_info *info, int con)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
return (con < 0) ? fbi->fb.disp : &fb_display[con];
}
/*
* Get the CMAP pointer for the specified console
*/
static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
{
return (con == info->currcon || con == -1) ? &info->cmap : &fb_display[con].cmap;
}
static inline u_int
chan_to_field(u_int chan, struct fb_bitfield *bf)
{
......@@ -813,13 +838,19 @@ chan_to_field(u_int chan, struct fb_bitfield *bf)
* Convert bits-per-pixel to a hardware palette PBS value.
*/
static inline u_int
palette_pbs(int bpp)
palette_pbs(struct fb_var_screeninfo *var)
{
int ret = 0;
switch (bpp) {
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4: ret = 0 << 12; break;
#endif
#ifdef FBCON_HAS_CFB8
case 8: ret = 1 << 12; break;
#endif
#ifdef FBCON_HAS_CFB16
case 16: ret = 2 << 12; break;
#endif
}
return ret;
}
......@@ -828,18 +859,18 @@ static int
sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info)
{
struct sa1100_par *par = (struct sa1100_par *) info->par;
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
u_int val, ret = 1;
if (regno < par->palette_size) {
if (regno < fbi->palette_size) {
val = ((red >> 4) & 0xf00);
val |= ((green >> 8) & 0x0f0);
val |= ((blue >> 12) & 0x00f);
if (regno == 0)
val |= palette_pbs(info->var.bits_per_pixel);
val |= palette_pbs(&fbi->fb.var);
par->palette_cpu[regno] = val;
fbi->palette_cpu[regno] = val;
ret = 0;
}
return ret;
......@@ -849,6 +880,8 @@ static int
sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp = get_con_display(info, info->currcon);
u_int val;
int ret = 1;
......@@ -857,34 +890,33 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* rather than the register number. The register number
* is what you poke into the framebuffer to produce the
* colour you requested.
*
if (inverse) {
*/
if (disp->inverse) {
red = 0xffff - red;
green = 0xffff - green;
blue = 0xffff - blue;
}
*/
/*
* If greyscale is true, then we convert the RGB value
* to greyscale no mater what visual we are using.
*/
if (info->var.grayscale)
if (fbi->fb.var.grayscale)
red = green = blue = (19595 * red + 38470 * green +
7471 * blue) >> 16;
switch (info->fix.visual) {
switch (fbi->fb.disp->visual) {
case FB_VISUAL_TRUECOLOR:
/*
* 12 or 16-bit True Colour. We encode the RGB value
* according to the RGB bitfield information.
*/
if (regno < 16) {
u16 *pal = info->pseudo_palette;
u16 *pal = fbi->fb.pseudo_palette;
val = chan_to_field(red, &info->var.red);
val |= chan_to_field(green, &info->var.green);
val |= chan_to_field(blue, &info->var.blue);
val = chan_to_field(red, &fbi->fb.var.red);
val |= chan_to_field(green, &fbi->fb.var.green);
val |= chan_to_field(blue, &fbi->fb.var.blue);
pal[regno] = val;
ret = 0;
......@@ -931,20 +963,19 @@ sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
* bitfields, horizontal timing, vertical timing.
*/
static int
sa1100fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
sa1100fb_validate_var(struct fb_var_screeninfo *var,
struct sa1100fb_info *fbi)
{
struct sa1100_par *par = (struct sa1100_par *) info->par;
int rgbidx = RGB_16, ret = -EINVAL;
int ret = -EINVAL;
if (var->xres < MIN_XRES)
var->xres = MIN_XRES;
if (var->yres < MIN_YRES)
var->yres = MIN_YRES;
if (var->xres > par->max_xres)
var->xres = par->max_xres;
if (var->yres > par->max_yres)
var->yres = par->max_yres;
if (var->xres > fbi->max_xres)
var->xres = fbi->max_xres;
if (var->yres > fbi->max_yres)
var->yres = fbi->max_yres;
var->xres_virtual =
var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
var->yres_virtual =
......@@ -952,22 +983,23 @@ sa1100fb_check_var(struct fb_var_screeninfo *var,
DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
switch (var->bits_per_pixel) {
case 4: rgbidx = RGB_8; ret = 0; break;
case 8: rgbidx = RGB_8; ret = 0; break;
case 16: rgbidx = RGB_16; ret = 0; break;
#ifdef FBCON_HAS_CFB4
case 4: ret = 0; break;
#endif
#ifdef FBCON_HAS_CFB8
case 8: ret = 0; break;
#endif
#ifdef FBCON_HAS_CFB16
case 16: ret = 0; break;
#endif
default:
break;
}
var->red = par->rgb[rgbidx]->red;
var->green = par->rgb[rgbidx]->green;
var->blue = par->rgb[rgbidx]->blue;
var->transp = par->rgb[rgbidx]->transp;
#ifdef CONFIG_CPU_FREQ
printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
sa1100fb_display_dma_period(var),
cpufreq_get());
cpufreq_get(smp_processor_id()));
#endif
return ret;
......@@ -994,26 +1026,24 @@ static inline void sa1100fb_set_truecolor(u_int is_true_color)
}
}
static int
sa1100fb_set_par(struct fb_info *info)
static void
sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
{
struct sa1100_par *par = (struct sa1100_par *) info->par;
u_long palette_mem_size;
par->bpp = info->var.bits_per_pixel;
par->palette_size = par->bpp == 8 ? 256 : 16;
fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
palette_mem_size = par->palette_size * sizeof(u16);
palette_mem_size = fbi->palette_size * sizeof(u16);
DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
par->palette_cpu = (u16 *)(par->map_cpu + PAGE_SIZE - palette_mem_size);
par->palette_dma = par->map_dma + PAGE_SIZE - palette_mem_size;
fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
fb_set_cmap(&info->cmap, 1, info);
fb_set_cmap(&fbi->fb.cmap, 1, &fbi->fb);
/* Set board control register to handle new color depth */
sa1100fb_set_truecolor(info->var.bits_per_pixel >= 16);
sa1100fb_set_truecolor(var->bits_per_pixel >= 16);
#ifdef CONFIG_SA1100_OMNIMETER
#error Do we have to do this here? We already do it at init time.
......@@ -1021,31 +1051,210 @@ sa1100fb_set_par(struct fb_info *info)
SetLCDContrast(DefaultLCDContrast);
#endif
sa1100fb_activate_var(&info->var, info);
sa1100fb_activate_var(var, fbi);
fbi->palette_cpu[0] = (fbi->palette_cpu[0] &
0xcfff) | palette_pbs(var);
}
/*
* sa1100fb_set_var():
* Set the user defined part of the display for the specified console
*/
static int
sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
struct display *display = get_con_display(&fbi->fb, con);
int err, chgvar = 0, rgbidx;
DPRINTK("set_var\n");
/*
* Decode var contents into a par structure, adjusting any
* out of range values.
*/
err = sa1100fb_validate_var(var, fbi);
if (err)
return err;
if (var->activate & FB_ACTIVATE_TEST)
return 0;
if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
return -EINVAL;
if (dvar->xres != var->xres)
chgvar = 1;
if (dvar->yres != var->yres)
chgvar = 1;
if (dvar->xres_virtual != var->xres_virtual)
chgvar = 1;
if (dvar->yres_virtual != var->yres_virtual)
chgvar = 1;
if (dvar->bits_per_pixel != var->bits_per_pixel)
chgvar = 1;
if (con < 0)
chgvar = 0;
par->palette_cpu[0] = (par->palette_cpu[0] &
0xcfff) | palette_pbs(info->var.bits_per_pixel);
switch (info->var.bits_per_pixel) {
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4:
if (par->cmap_static)
info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
if (fbi->cmap_static)
display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
else
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
info->fix.line_length = info->var.xres / 2;
display->visual = FB_VISUAL_PSEUDOCOLOR;
display->line_length = var->xres / 2;
display->dispsw = &fbcon_cfb4;
rgbidx = RGB_8;
break;
#endif
#ifdef FBCON_HAS_CFB8
case 8:
if (par->cmap_static)
info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
if (fbi->cmap_static)
display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
else
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
info->fix.line_length = info->var.xres;
display->visual = FB_VISUAL_PSEUDOCOLOR;
display->line_length = var->xres;
display->dispsw = &fbcon_cfb8;
rgbidx = RGB_8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
info->fix.visual = FB_VISUAL_TRUECOLOR;
info->fix.line_length = info->var.xres * 2;
display->visual = FB_VISUAL_TRUECOLOR;
display->line_length = var->xres * 2;
display->dispsw = &fbcon_cfb16;
display->dispsw_data = fbi->fb.pseudo_palette;
rgbidx = RGB_16;
break;
#endif
default:
rgbidx = 0;
display->dispsw = &fbcon_dummy;
break;
}
display->next_line = display->line_length;
display->type = fbi->fb.fix.type;
display->type_aux = fbi->fb.fix.type_aux;
display->ypanstep = fbi->fb.fix.ypanstep;
display->ywrapstep = fbi->fb.fix.ywrapstep;
display->can_soft_blank = 1;
display->inverse = fbi->cmap_inverse;
*dvar = *var;
dvar->activate &= ~FB_ACTIVATE_ALL;
/*
* Copy the RGB parameters for this display
* from the machine specific parameters.
*/
dvar->red = fbi->rgb[rgbidx]->red;
dvar->green = fbi->rgb[rgbidx]->green;
dvar->blue = fbi->rgb[rgbidx]->blue;
dvar->transp = fbi->rgb[rgbidx]->transp;
DPRINTK("RGBT length = %d:%d:%d:%d\n",
dvar->red.length, dvar->green.length, dvar->blue.length,
dvar->transp.length);
DPRINTK("RGBT offset = %d:%d:%d:%d\n",
dvar->red.offset, dvar->green.offset, dvar->blue.offset,
dvar->transp.offset);
/*
* Update the old var. The fbcon drivers still use this.
* Once they are using fbi->fb.var, this can be dropped.
*/
display->var = *dvar;
/*
* If we are setting all the virtual consoles, also set the
* defaults used to create new consoles.
*/
if (var->activate & FB_ACTIVATE_ALL)
fbi->fb.disp->var = *dvar;
/*
* If the console has changed and the console has defined
* a changevar function, call that function.
*/
if (chgvar && info && fbi->fb.changevar)
fbi->fb.changevar(con);
/* If the current console is selected, activate the new var. */
if (con != fbi->fb.currcon)
return 0;
sa1100fb_hw_set_var(dvar, fbi);
return 0;
}
static int
__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct fb_cmap *dcmap = get_con_cmap(info, con);
int err = 0;
if (con == -1)
con = info->currcon;
/* no colormap allocated? (we always have "this" colour map allocated) */
if (con >= 0)
err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
if (!err && con == info->currcon)
err = fb_set_cmap(cmap, kspc, info);
if (!err)
fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
return err;
}
static int
sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct display *disp = get_con_display(info, con);
if (disp->visual == FB_VISUAL_TRUECOLOR ||
disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
return -EINVAL;
return __do_set_cmap(cmap, kspc, con, info);
}
static int
sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
{
struct display *display = get_con_display(info, con);
*fix = info->fix;
fix->line_length = display->line_length;
fix->visual = display->visual;
return 0;
}
static int
sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
*var = *get_con_var(info, con);
return 0;
}
static int
sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
{
struct fb_cmap *dcmap = get_con_cmap(info, con);
fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
return 0;
}
......@@ -1086,21 +1295,21 @@ sa1100fb_set_par(struct fb_info *info)
*/
static int sa1100fb_blank(int blank, struct fb_info *info)
{
struct sa1100_par *par = (struct sa1100_par *) info->par;
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
int i;
DPRINTK("sa1100fb_blank: blank=%d fix.id=%s\n", blank,
info->fix.id);
DPRINTK("sa1100fb_blank: blank=%d info->modename=%s\n", blank,
fbi->fb.modename);
switch (blank) {
case VESA_POWERDOWN:
case VESA_VSYNC_SUSPEND:
case VESA_HSYNC_SUSPEND:
if (info->disp->visual == FB_VISUAL_PSEUDOCOLOR ||
info->disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
for (i = 0; i < par->palette_size; i++)
if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
for (i = 0; i < fbi->palette_size; i++)
sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
sa1100fb_schedule_task(par, C_DISABLE);
sa1100fb_schedule_task(fbi, C_DISABLE);
if (sa1100fb_blank_helper)
sa1100fb_blank_helper(blank);
break;
......@@ -1108,30 +1317,83 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
case VESA_NO_BLANKING:
if (sa1100fb_blank_helper)
sa1100fb_blank_helper(blank);
if (info->disp->visual == FB_VISUAL_PSEUDOCOLOR ||
info->disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&info->cmap, 1, info);
sa1100fb_schedule_task(par, C_ENABLE);
if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&fbi->fb.cmap, 1, info);
sa1100fb_schedule_task(fbi, C_ENABLE);
}
return 0;
}
static struct fb_ops sa1100fb_ops = {
owner: THIS_MODULE,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_set_var: gen_set_var,
fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap,
fb_check_var: sa1100fb_check_var,
fb_set_par: sa1100fb_set_par,
fb_get_fix: sa1100fb_get_fix,
fb_get_var: sa1100fb_get_var,
fb_set_var: sa1100fb_set_var,
fb_get_cmap: sa1100fb_get_cmap,
fb_set_cmap: sa1100fb_set_cmap,
fb_setcolreg: sa1100fb_setcolreg,
fb_blank: sa1100fb_blank,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
};
/*
* sa1100fb_switch():
* Change to the specified console. Palette and video mode
* are changed to the console's stored parameters.
*
* Uh oh, this can be called from a tasklet (IRQ)
*/
static int sa1100fb_switch(int con, struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp;
struct fb_cmap *cmap;
DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
if (con == info->currcon)
return 0;
if (info->currcon >= 0) {
disp = fb_display + info->currcon;
/*
* Save the old colormap and video mode.
*/
disp->var = fbi->fb.var;
if (disp->cmap.len)
fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
}
info->currcon = con;
disp = fb_display + con;
/*
* Make sure that our colourmap contains 256 entries.
*/
fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
if (disp->cmap.len)
cmap = &disp->cmap;
else
cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
fbi->fb.var = disp->var;
fbi->fb.var.activate = FB_ACTIVATE_NOW;
sa1100fb_set_var(&fbi->fb.var, con, info);
return 0;
}
static int sa1100fb_updatevar(int con, struct fb_info *info)
{
DPRINTK("entered\n");
return 0;
}
/*
* Calculate the PCD value from the clock rate (in picoseconds).
* We take account of the PPCR clock setting.
......@@ -1141,7 +1403,7 @@ static inline int get_pcd(unsigned int pixclock)
unsigned int pcd;
if (pixclock) {
pcd = cpufreq_get() / 100;
pcd = cpufreq_get(0) / 100;
pcd *= pixclock;
pcd /= 10000000;
pcd += 1; /* make up for integer math truncations */
......@@ -1171,9 +1433,8 @@ static inline int get_pcd(unsigned int pixclock)
* Configures LCD Controller based on entries in var parameter. Settings are
* only written to the controller if changes were made.
*/
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
{
struct sa1100_par *par = (struct sa1100_par *) info->par;
struct sa1100fb_lcd_reg new_regs;
u_int half_screen_size, yres, pcd = get_pcd(var->pixclock);
u_long flags;
......@@ -1190,31 +1451,31 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
#if DEBUG_VAR
if (var->xres < 16 || var->xres > 1024)
printk(KERN_ERR "%s: invalid xres %d\n",
info->fix.id, var->xres);
fbi->fb.fix.id, var->xres);
if (var->hsync_len < 1 || var->hsync_len > 64)
printk(KERN_ERR "%s: invalid hsync_len %d\n",
info->fix.id, var->hsync_len);
fbi->fb.fix.id, var->hsync_len);
if (var->left_margin < 1 || var->left_margin > 255)
printk(KERN_ERR "%s: invalid left_margin %d\n",
info->fix.id, var->left_margin);
fbi->fb.fix.id, var->left_margin);
if (var->right_margin < 1 || var->right_margin > 255)
printk(KERN_ERR "%s: invalid right_margin %d\n",
info->fix.id, var->right_margin);
fbi->fb.fix.id, var->right_margin);
if (var->yres < 1 || var->yres > 1024)
printk(KERN_ERR "%s: invalid yres %d\n",
info->fix.id, var->yres);
fbi->fb.fix.id, var->yres);
if (var->vsync_len < 1 || var->vsync_len > 64)
printk(KERN_ERR "%s: invalid vsync_len %d\n",
info->fix.id, var->vsync_len);
fbi->fb.fix.id, var->vsync_len);
if (var->upper_margin < 0 || var->upper_margin > 255)
printk(KERN_ERR "%s: invalid upper_margin %d\n",
info->fix.id, var->upper_margin);
fbi->fb.fix.id, var->upper_margin);
if (var->lower_margin < 0 || var->lower_margin > 255)
printk(KERN_ERR "%s: invalid lower_margin %d\n",
info->fix.id, var->lower_margin);
fbi->fb.fix.id, var->lower_margin);
#endif
new_regs.lccr0 = par->lccr0 |
new_regs.lccr0 = fbi->lccr0 |
LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
......@@ -1229,7 +1490,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
* the YRES parameter.
*/
yres = var->yres;
if (par->lccr0 & LCCR0_Dual)
if (fbi->lccr0 & LCCR0_Dual)
yres /= 2;
new_regs.lccr2 =
......@@ -1238,7 +1499,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
LCCR2_BegFrmDel(var->upper_margin) +
LCCR2_EndFrmDel(var->lower_margin);
new_regs.lccr3 = par->lccr3 |
new_regs.lccr3 = fbi->lccr3 |
(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
LCCR3_ACBsCntOff;
......@@ -1256,23 +1517,23 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
/* Update shadow copy atomically */
local_irq_save(flags);
par->dbar1 = par->palette_dma;
par->dbar2 = par->screen_dma + half_screen_size;
fbi->dbar1 = fbi->palette_dma;
fbi->dbar2 = fbi->screen_dma + half_screen_size;
par->reg_lccr0 = new_regs.lccr0;
par->reg_lccr1 = new_regs.lccr1;
par->reg_lccr2 = new_regs.lccr2;
par->reg_lccr3 = new_regs.lccr3;
fbi->reg_lccr0 = new_regs.lccr0;
fbi->reg_lccr1 = new_regs.lccr1;
fbi->reg_lccr2 = new_regs.lccr2;
fbi->reg_lccr3 = new_regs.lccr3;
local_irq_restore(flags);
/*
* Only update the registers if the controller is enabled
* and something has changed.
*/
if ((LCCR0 != par->reg_lccr0) || (LCCR1 != par->reg_lccr1) ||
(LCCR2 != par->reg_lccr2) || (LCCR3 != par->reg_lccr3) ||
(DBAR1 != par->dbar1) || (DBAR2 != par->dbar2))
sa1100fb_schedule_task(par, C_REENABLE);
if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
(LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
(DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
sa1100fb_schedule_task(fbi, C_REENABLE);
return 0;
}
......@@ -1289,7 +1550,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
* Also, I'm expecting that the backlight stuff should
* be handled differently.
*/
static inline void sa1100fb_backlight_on(struct sa1100_par *par)
static inline void sa1100fb_backlight_on(struct sa1100fb_info *fbi)
{
DPRINTK("backlight on\n");
......@@ -1302,7 +1563,7 @@ static inline void sa1100fb_backlight_on(struct sa1100_par *par)
* Also, I'm expecting that the backlight stuff should
* be handled differently.
*/
static inline void sa1100fb_backlight_off(struct sa1100_par *par)
static inline void sa1100fb_backlight_off(struct sa1100fb_info *fbi)
{
DPRINTK("backlight off\n");
......@@ -1310,7 +1571,7 @@ static inline void sa1100fb_backlight_off(struct sa1100_par *par)
sa1100fb_backlight_power(0);
}
static inline void sa1100fb_power_up_lcd(struct sa1100_par *par)
static inline void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi)
{
DPRINTK("LCD power on\n");
......@@ -1325,7 +1586,7 @@ static inline void sa1100fb_power_up_lcd(struct sa1100_par *par)
#endif
}
static inline void sa1100fb_power_down_lcd(struct sa1100_par *par)
static inline void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
{
DPRINTK("LCD power off\n");
......@@ -1340,7 +1601,7 @@ static inline void sa1100fb_power_down_lcd(struct sa1100_par *par)
#endif
}
static void sa1100fb_setup_gpio(struct sa1100_par *par)
static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
{
u_int mask = 0;
......@@ -1356,12 +1617,12 @@ static void sa1100fb_setup_gpio(struct sa1100_par *par)
* clear LDD15 to 12 for 4 or 8bpp modes with active
* panels.
*/
if ((par->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
(par->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
(fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
if (par->bpp > 8 ||
(par->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
if (fbi->fb.var.bits_per_pixel > 8 ||
(fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
}
......@@ -1405,23 +1666,23 @@ static void sa1100fb_setup_gpio(struct sa1100_par *par)
}
}
static void sa1100fb_enable_controller(struct sa1100_par *par)
static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
{
DPRINTK("Enabling LCD controller\n");
/*
* Make sure the mode bits are present in the first palette entry
*/
par->palette_cpu[0] &= 0xcfff;
par->palette_cpu[0] |= palette_pbs(par->bpp);
fbi->palette_cpu[0] &= 0xcfff;
fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
/* Sequence from 11.7.10 */
LCCR3 = par->reg_lccr3;
LCCR2 = par->reg_lccr2;
LCCR1 = par->reg_lccr1;
LCCR0 = par->reg_lccr0 & ~LCCR0_LEN;
DBAR1 = par->dbar1;
DBAR2 = par->dbar2;
LCCR3 = fbi->reg_lccr3;
LCCR2 = fbi->reg_lccr2;
LCCR1 = fbi->reg_lccr1;
LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
DBAR1 = fbi->dbar1;
DBAR2 = fbi->dbar2;
LCCR0 |= LCCR0_LEN;
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
......@@ -1447,7 +1708,7 @@ static void sa1100fb_enable_controller(struct sa1100_par *par)
DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
}
static void sa1100fb_disable_controller(struct sa1100_par *par)
static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
{
DECLARE_WAITQUEUE(wait, current);
......@@ -1481,7 +1742,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par)
GPCR |= SHANNON_GPIO_DISP_EN;
}
add_wait_queue(&par->ctrlr_wait, &wait);
add_wait_queue(&fbi->ctrlr_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
LCSR = 0xffffffff; /* Clear LCD Status Register */
......@@ -1490,7 +1751,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par)
schedule_timeout(20 * HZ / 1000);
current->state = TASK_RUNNING;
remove_wait_queue(&par->ctrlr_wait, &wait);
remove_wait_queue(&fbi->ctrlr_wait, &wait);
}
/*
......@@ -1498,12 +1759,12 @@ static void sa1100fb_disable_controller(struct sa1100_par *par)
*/
static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct sa1100_par *par = dev_id;
struct sa1100fb_info *fbi = dev_id;
unsigned int lcsr = LCSR;
if (lcsr & LCSR_LDD) {
LCCR0 |= LCCR0_LDM;
wake_up(&par->ctrlr_wait);
wake_up(&fbi->ctrlr_wait);
}
LCSR = lcsr;
......@@ -1514,13 +1775,13 @@ static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
* sleep when disabling the LCD controller, or if we get two contending
* processes trying to alter state.
*/
static void set_ctrlr_state(struct sa1100_par *par, u_int state)
static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
{
u_int old_state;
down(&par->ctrlr_sem);
down(&fbi->ctrlr_sem);
old_state = par->state;
old_state = fbi->state;
switch (state) {
case C_DISABLE_CLKCHANGE:
......@@ -1529,8 +1790,8 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* controller is already disabled, then do nothing.
*/
if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
par->state = state;
sa1100fb_disable_controller(par);
fbi->state = state;
sa1100fb_disable_controller(fbi);
}
break;
......@@ -1540,12 +1801,12 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* Disable controller
*/
if (old_state != C_DISABLE) {
par->state = state;
fbi->state = state;
sa1100fb_backlight_off(par);
sa1100fb_backlight_off(fbi);
if (old_state != C_DISABLE_CLKCHANGE)
sa1100fb_disable_controller(par);
sa1100fb_power_down_lcd(par);
sa1100fb_disable_controller(fbi);
sa1100fb_power_down_lcd(fbi);
}
break;
......@@ -1555,8 +1816,8 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* do this if we were disabled for the clock change.
*/
if (old_state == C_DISABLE_CLKCHANGE) {
par->state = C_ENABLE;
sa1100fb_enable_controller(par);
fbi->state = C_ENABLE;
sa1100fb_enable_controller(fbi);
}
break;
......@@ -1567,9 +1828,9 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* registers.
*/
if (old_state == C_ENABLE) {
sa1100fb_disable_controller(par);
sa1100fb_setup_gpio(par);
sa1100fb_enable_controller(par);
sa1100fb_disable_controller(fbi);
sa1100fb_setup_gpio(fbi);
sa1100fb_enable_controller(fbi);
}
break;
......@@ -1589,15 +1850,15 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* turn on the backlight.
*/
if (old_state != C_ENABLE) {
par->state = C_ENABLE;
sa1100fb_setup_gpio(par);
sa1100fb_power_up_lcd(par);
sa1100fb_enable_controller(par);
sa1100fb_backlight_on(par);
fbi->state = C_ENABLE;
sa1100fb_setup_gpio(fbi);
sa1100fb_power_up_lcd(fbi);
sa1100fb_enable_controller(fbi);
sa1100fb_backlight_on(fbi);
}
break;
}
up(&par->ctrlr_sem);
up(&fbi->ctrlr_sem);
}
/*
......@@ -1606,12 +1867,10 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
*/
static void sa1100fb_task(void *dummy)
{
struct fb_info *info = dummy;
struct sa1100_par *par = (struct sa1100_par *) info->par;
struct sa1100fb_info *fbi = dummy;
u_int state = xchg(&fbi->task_state, -1);
u_int state = xchg(&par->task_state, -1);
set_ctrlr_state(par, state);
set_ctrlr_state(fbi, state);
}
#ifdef CONFIG_CPU_FREQ
......@@ -1620,7 +1879,7 @@ static void sa1100fb_task(void *dummy)
* This, together with the SDRAM bandwidth defines the slowest CPU
* frequency that can be selected.
*/
static unsigned int sa1100fb_min_dma_period(struct fb_info *info)
static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
{
unsigned int min_period = (unsigned int)-1;
int i;
......@@ -1631,13 +1890,13 @@ static unsigned int sa1100fb_min_dma_period(struct fb_info *info)
/*
* Do we own this display?
*/
if (fb_display[i].fb_info != info)
if (fb_display[i].fb_info != &fbi->fb)
continue;
/*
* Ok, calculate its DMA period
*/
period = sa1100fb_display_dma_period(&info->var);
period = sa1100fb_display_dma_period(get_con_var(&fbi->fb, i));
if (period < min_period)
min_period = period;
}
......@@ -1654,27 +1913,26 @@ static int
sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct fb_info *info = TO_INF(nb, clockchg);
struct sa1100_par *par = (struct sa1100_par *) info->par;
struct cpufreq_freqs *mm = data;
struct sa1100fb_info *fbi = TO_INF(nb, clockchg);
struct cpufreq_minmax *mm = data;
u_int pcd;
switch (val) {
case CPUFREQ_MINMAX:
printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
"new clock %d kHz\n", sa1100fb_min_dma_period(info),
mm->cur, mm->new);
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
mm->cur_freq, mm->new_freq);
/* todo: fill in min/max values */
break;
case CPUFREQ_PRECHANGE:
set_ctrlr_state(par, C_DISABLE_CLKCHANGE);
set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
break;
case CPUFREQ_POSTCHANGE:
pcd = get_pcd(info->var.pixclock);
par->reg_lccr3 = (par->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(par, C_ENABLE_CLKCHANGE);
pcd = get_pcd(fbi->fb.var.pixclock);
fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break;
}
return 0;
......@@ -1689,7 +1947,7 @@ sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
static int
sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
{
struct sa1100_par *par = pm_dev->data;
struct sa1100fb_info *fbi = pm_dev->data;
DPRINTK("pm_callback: %d\n", req);
......@@ -1698,10 +1956,10 @@ sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
if (state == 0) {
/* Enter D0. */
set_ctrlr_state(par, C_ENABLE_PM);
set_ctrlr_state(fbi, C_ENABLE_PM);
} else {
/* Enter D1-D3. Disable the LCD controller. */
set_ctrlr_state(par, C_DISABLE_PM);
set_ctrlr_state(fbi, C_DISABLE_PM);
}
}
DPRINTK("done\n");
......@@ -1717,142 +1975,133 @@ sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
* cache. Once this area is remapped, all virtual memory
* access to the video memory should occur at the new region.
*/
static int __init sa1100fb_map_video_memory(struct fb_info *info)
static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
{
struct sa1100_par *par= (struct sa1100_par *) info->par;
/*
* We reserve one page for the palette, plus the size
* of the framebuffer.
*/
par->map_size = PAGE_ALIGN(info->fix.smem_len + PAGE_SIZE);
par->map_cpu = consistent_alloc(GFP_KERNEL, par->map_size,
&par->map_dma);
if (par->map_cpu) {
info->screen_base = par->map_cpu + PAGE_SIZE;
par->screen_dma = par->map_dma + PAGE_SIZE;
info->fix.smem_start = par->screen_dma;
fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
&fbi->map_dma);
if (fbi->map_cpu) {
fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
fbi->fb.fix.smem_start = fbi->screen_dma;
}
return par->map_cpu ? 0 : -ENOMEM;
return fbi->map_cpu ? 0 : -ENOMEM;
}
/* Fake monspecs to fill in infonfo structure */
/* Fake monspecs to fill in fbinfo structure */
static struct fb_monspecs monspecs __initdata = {
30000, 70000, 50, 65, 0 /* Generic */
};
static struct fb_info * __init sa1100fb_init_fbinfo(void)
static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
{
struct sa1100fb_mach_info *inf;
struct fb_info *info;
struct sa1100_par *par;
struct sa1100fb_info *fbi;
info = kmalloc(sizeof(struct fb_info) + sizeof(struct display) +
fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(struct display) +
sizeof(u16) * 16, GFP_KERNEL);
if (!info)
if (!fbi)
return NULL;
memset(info, 0, sizeof(struct fb_info) + sizeof(struct display));
par = kmalloc(sizeof(struct sa1100_par), GFP_KERNEL);
memset(par, 0, sizeof(struct sa1100_par));
info->currcon = -1;
strcpy(info->fix.id, SA1100_NAME);
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.type_aux = 0;
info->fix.xpanstep = 0;
info->fix.ypanstep = 0;
info->fix.ywrapstep = 0;
info->fix.accel = FB_ACCEL_NONE;
info->var.nonstd = 0;
info->var.activate = FB_ACTIVATE_NOW;
info->var.height = -1;
info->var.width = -1;
info->var.accel_flags = 0;
info->var.vmode = FB_VMODE_NONINTERLACED;
strcpy(info->modename, info->fix.id);
strcpy(info->fontname, "Acorn8x8");
info->fbops = &sa1100fb_ops;
info->changevar = NULL;
info->switch_con = gen_switch;
info->updatevar = gen_update_var;
info->flags = FBINFO_FLAG_DEFAULT;
info->node = NODEV;
info->monspecs = monspecs;
info->currcon = -1;
info->disp = (struct display *)(info + 1);
info->pseudo_palette = (void *)(info->disp + 1);
info->par = par;
par->rgb[RGB_8] = &rgb_8;
par->rgb[RGB_16] = &def_rgb_16;
inf = sa1100fb_get_machine_info(par);
par->max_xres = inf->xres;
info->var.xres = inf->xres;
info->var.xres_virtual = inf->xres;
par->max_yres = inf->yres;
info->var.yres = inf->yres;
info->var.yres_virtual = inf->yres;
par->max_bpp = inf->bpp;
info->var.bits_per_pixel = inf->bpp;
info->var.pixclock = inf->pixclock;
info->var.hsync_len = inf->hsync_len;
info->var.left_margin = inf->left_margin;
info->var.right_margin = inf->right_margin;
info->var.vsync_len = inf->vsync_len;
info->var.upper_margin = inf->upper_margin;
info->var.lower_margin = inf->lower_margin;
info->var.sync = inf->sync;
info->var.grayscale = inf->cmap_greyscale;
par->cmap_inverse = inf->cmap_inverse;
par->cmap_static = inf->cmap_static;
par->lccr0 = inf->lccr0;
par->lccr3 = inf->lccr3;
par->state = C_DISABLE;
par->task_state = (u_char)-1;
info->fix.smem_len = par->max_xres * par->max_yres *
par->max_bpp / 8;
init_waitqueue_head(&par->ctrlr_wait);
INIT_TQUEUE(&par->task, sa1100fb_task, info);
init_MUTEX(&par->ctrlr_sem);
fb_alloc_cmap(&info->cmap, 256, 0);
return info;
memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
fbi->fb.currcon = -1;
strcpy(fbi->fb.fix.id, SA1100_NAME);
fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
fbi->fb.fix.type_aux = 0;
fbi->fb.fix.xpanstep = 0;
fbi->fb.fix.ypanstep = 0;
fbi->fb.fix.ywrapstep = 0;
fbi->fb.fix.accel = FB_ACCEL_NONE;
fbi->fb.var.nonstd = 0;
fbi->fb.var.activate = FB_ACTIVATE_NOW;
fbi->fb.var.height = -1;
fbi->fb.var.width = -1;
fbi->fb.var.accel_flags = 0;
fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
strcpy(fbi->fb.modename, SA1100_NAME);
strcpy(fbi->fb.fontname, "Acorn8x8");
fbi->fb.fbops = &sa1100fb_ops;
fbi->fb.changevar = NULL;
fbi->fb.switch_con = sa1100fb_switch;
fbi->fb.updatevar = sa1100fb_updatevar;
fbi->fb.flags = FBINFO_FLAG_DEFAULT;
fbi->fb.node = NODEV;
fbi->fb.monspecs = monspecs;
fbi->fb.currcon = -1;
fbi->fb.disp = (struct display *)(fbi + 1);
fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1);
fbi->rgb[RGB_8] = &rgb_8;
fbi->rgb[RGB_16] = &def_rgb_16;
inf = sa1100fb_get_machine_info(fbi);
fbi->max_xres = inf->xres;
fbi->fb.var.xres = inf->xres;
fbi->fb.var.xres_virtual = inf->xres;
fbi->max_yres = inf->yres;
fbi->fb.var.yres = inf->yres;
fbi->fb.var.yres_virtual = inf->yres;
fbi->max_bpp = inf->bpp;
fbi->fb.var.bits_per_pixel = inf->bpp;
fbi->fb.var.pixclock = inf->pixclock;
fbi->fb.var.hsync_len = inf->hsync_len;
fbi->fb.var.left_margin = inf->left_margin;
fbi->fb.var.right_margin = inf->right_margin;
fbi->fb.var.vsync_len = inf->vsync_len;
fbi->fb.var.upper_margin = inf->upper_margin;
fbi->fb.var.lower_margin = inf->lower_margin;
fbi->fb.var.sync = inf->sync;
fbi->fb.var.grayscale = inf->cmap_greyscale;
fbi->cmap_inverse = inf->cmap_inverse;
fbi->cmap_static = inf->cmap_static;
fbi->lccr0 = inf->lccr0;
fbi->lccr3 = inf->lccr3;
fbi->state = C_DISABLE;
fbi->task_state = (u_char)-1;
fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
fbi->max_bpp / 8;
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi);
init_MUTEX(&fbi->ctrlr_sem);
return fbi;
}
int __init sa1100fb_init(void)
{
struct fb_info *info;
struct sa1100_par *par;
struct sa1100fb_info *fbi;
int ret;
if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
return -EBUSY;
info = sa1100fb_init_fbinfo();
fbi = sa1100fb_init_fbinfo();
ret = -ENOMEM;
if (!info)
if (!fbi)
goto failed;
/* Initialize video memory */
ret = sa1100fb_map_video_memory(info);
ret = sa1100fb_map_video_memory(fbi);
if (ret)
goto failed;
ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT,
"LCD", info->par);
"LCD", fbi);
if (ret) {
printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
goto failed;
......@@ -1873,32 +2122,30 @@ int __init sa1100fb_init(void)
}
#endif
gen_set_var(&info->var, -1, info);
sa1100fb_set_var(&fbi->fb.var, -1, &fbi->fb);
ret = register_framebuffer(info);
ret = register_framebuffer(&fbi->fb);
if (ret < 0)
goto failed;
par = info->par;
#ifdef CONFIG_PM
/*
* Note that the console registers this as well, but we want to
* power down the display prior to sleeping.
*/
par->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback);
if (par->pm)
par->pm->data = par;
fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback);
if (fbi->pm)
fbi->pm->data = fbi;
#endif
#ifdef CONFIG_CPU_FREQ
info->clockchg.notifier_call = sa1100fb_clkchg_notifier;
cpufreq_register_notifier(&info->clockchg);
fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier;
cpufreq_register_notifier(&fbi->clockchg);
#endif
/*
* Ok, now enable the LCD controller
*/
set_ctrlr_state(par, C_ENABLE);
set_ctrlr_state(fbi, C_ENABLE);
/* This driver cannot be unloaded at the moment */
MOD_INC_USE_COUNT;
......@@ -1906,8 +2153,8 @@ int __init sa1100fb_init(void)
return 0;
failed:
if (info)
kfree(info);
if (fbi)
kfree(fbi);
release_mem_region(0xb0100000, 0x10000);
return ret;
}
......
......@@ -61,13 +61,13 @@ struct sa1100fb_lcd_reg {
#define RGB_16 (1)
#define NR_RGB 2
struct sa1100_par {
struct sa1100fb_info {
struct fb_info fb;
struct sa1100fb_rgb *rgb[NR_RGB];
u_int max_bpp;
u_int max_xres;
u_int max_yres;
u_int max_bpp;
u_int bpp;
/*
* These are the addresses we mapped
......@@ -86,13 +86,12 @@ struct sa1100_par {
dma_addr_t dbar1;
dma_addr_t dbar2;
u_int lccr0;
u_int lccr3;
u_int cmap_inverse:1,
cmap_static:1,
unused:30;
u_int lccr0;
u_int lccr3;
u_int reg_lccr0;
u_int reg_lccr1;
u_int reg_lccr2;
......@@ -103,14 +102,18 @@ struct sa1100_par {
struct semaphore ctrlr_sem;
wait_queue_head_t ctrlr_wait;
struct tq_struct task;
#ifdef CONFIG_PM
struct pm_dev *pm;
#endif
#ifdef CONFIG_CPU_FREQ
struct notifier_block clockchg;
#endif
};
#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
#define TO_INF(ptr,member) __type_entry(ptr, struct fb_info, member)
#define TO_INF(ptr,member) __type_entry(ptr,struct sa1100fb_info,member)
#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment