* Low level Frame buffer driver for HP workstations with
* STI (standard text interface) video firmware.
*
- * Copyright (C) 2001-2004 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
* Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
*
* Based on:
#undef DEBUG_STIFB_REGS /* debug sti register accesses */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include "sticore.h"
/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
-#ifdef __LP64__
- #define REGION_BASE(fb_info, index) \
- (fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000)
-#else
- #define REGION_BASE(fb_info, index) \
- fb_info->sti->glob_cfg->region_ptrs[index]
-#endif
+#define REGION_BASE(fb_info, index) \
+ F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
#define NGLEDEVDEPROM_CRT_REGION 1
+#define NR_PALETTE 256
+
typedef struct {
__s32 video_config_reg;
__s32 misc_video_start;
ngle_rom_t ngle_rom;
struct sti_struct *sti;
int deviceSpecificConfig;
+ u32 pseudo_palette[16];
};
-static int __initdata bpp = 8; /* parameter from modprobe */
-static int __initdata stifb_force_bpp[MAX_STI_ROMS];
+static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
/* ------------------- chipset specific functions -------------------------- */
#define REG_44 0x210030
#define REG_45 0x210034
-#define READ_BYTE(fb,reg) __raw_readb((fb)->info.fix.mmio_start + (reg))
-#define READ_WORD(fb,reg) __raw_readl((fb)->info.fix.mmio_start + (reg))
+#define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
+#define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
#ifndef DEBUG_STIFB_REGS
# define DEBUG_OFF()
# define DEBUG_ON()
-# define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->info.fix.mmio_start + (reg))
-# define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->info.fix.mmio_start + (reg))
+# define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
+# define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
#else
static int debug_on = 1;
# define DEBUG_OFF() debug_on=0
# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
__FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
- __raw_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+ gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
__FUNCTION__, reg, value, READ_WORD(fb,reg)); \
- __raw_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+ gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
#endif /* DEBUG_STIFB_REGS */
#define IS_888_DEVICE(fb) \
(!(IS_24_DEVICE(fb)))
-#define GET_FIFO_SLOTS(fb, cnt, numslots) \
-{ while (cnt < numslots) \
+#define GET_FIFO_SLOTS(fb, cnt, numslots) \
+{ while (cnt < numslots) \
cnt = READ_WORD(fb, REG_34); \
- cnt -= numslots; \
+ cnt -= numslots; \
}
#define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
SETUP_HW(fb);
WRITE_BYTE(1, fb, REG_16b1);
- fb_memset(fb->info.fix.smem_start, 0xff,
+ fb_memset((void*)fb->info.fix.smem_start, 0xff,
fb->info.var.yres*fb->info.fix.line_length);
CRX24_SET_OVLY_MASK(fb);
/* ------------------- driver specific functions --------------------------- */
-#define TMPBUFLEN 2048
-
-static ssize_t
-stifb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
- char tmpbuf[TMPBUFLEN];
-
- if (!info || ! info->screen_base)
- return -ENODEV;
-
- if (p >= info->fix.smem_len)
- return 0;
- if (count >= info->fix.smem_len)
- count = info->fix.smem_len;
- if (count + p > info->fix.smem_len)
- count = info->fix.smem_len - p;
- if (count > sizeof(tmpbuf))
- count = sizeof(tmpbuf);
- if (count) {
- char *base_addr;
-
- base_addr = info->screen_base;
- memcpy_fromio(&tmpbuf, base_addr+p, count);
- count -= copy_to_user(buf, &tmpbuf, count);
- if (!count)
- return -EFAULT;
- *ppos += count;
- }
- return count;
-}
-
-static ssize_t
-stifb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
- unsigned long p = *ppos;
- size_t c;
- int err;
- char tmpbuf[TMPBUFLEN];
-
- if (!info || !info->screen_base)
- return -ENODEV;
-
- if (p > info->fix.smem_len)
- return -ENOSPC;
- if (count >= info->fix.smem_len)
- count = info->fix.smem_len;
- err = 0;
- if (count + p > info->fix.smem_len) {
- count = info->fix.smem_len - p;
- err = -ENOSPC;
- }
-
- p += (unsigned long)info->screen_base;
- c = count;
- while (c) {
- int len = c > sizeof(tmpbuf) ? sizeof(tmpbuf) : c;
- err = -EFAULT;
- if (copy_from_user(&tmpbuf, buf, len))
- break;
- memcpy_toio(p, &tmpbuf, len);
- c -= len;
- p += len;
- buf += len;
- *ppos += len;
- }
- if (count-c)
- return (count-c);
- return err;
-}
-
static int
stifb_setcolreg(u_int regno, u_int red, u_int green,
u_int blue, u_int transp, struct fb_info *info)
struct stifb_info *fb = (struct stifb_info *) info;
u32 color;
- if (regno >= 256) /* no. of hw registers */
+ if (regno >= NR_PALETTE)
return 1;
red >>= 8;
DEBUG_OFF();
START_IMAGE_COLORMAP_ACCESS(fb);
-
- if (fb->info.var.grayscale) {
+
+ if (unlikely(fb->info.var.grayscale)) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
color = ((red * 77) +
(green * 151) +
(blue));
}
+ if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ struct fb_var_screeninfo *var = &fb->info.var;
+ if (regno < 16)
+ ((u32 *)fb->info.pseudo_palette)[regno] =
+ regno << var->red.offset |
+ regno << var->green.offset |
+ regno << var->blue.offset;
+ }
+
WRITE_IMAGE_COLOR(fb, regno, color);
-
+
if (fb->id == S9000_ID_HCRX) {
NgleLutBltCtl lutBltCtl;
case S9000_ID_HCRX:
HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
break;
- case S9000_ID_A1659A:; /* fall through */
- case S9000_ID_TIMBER:;
- case CRX24_OVERLAY_PLANES:;
+ case S9000_ID_A1659A: /* fall through */
+ case S9000_ID_TIMBER:
+ case CRX24_OVERLAY_PLANES:
default:
ENABLE_DISABLE_DISPLAY(fb, enable);
break;
static struct fb_ops stifb_ops = {
.owner = THIS_MODULE,
- .fb_read = stifb_read,
- .fb_write = stifb_write,
.fb_setcolreg = stifb_setcolreg,
.fb_blank = stifb_blank,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
- .fb_cursor = soft_cursor,
};
*/
int __init
-stifb_init_fb(struct sti_struct *sti, int force_bpp)
+stifb_init_fb(struct sti_struct *sti, int bpp_pref)
{
struct fb_fix_screeninfo *fix;
struct fb_var_screeninfo *var;
char *dev_name;
int bpp, xres, yres;
- fb = kmalloc(sizeof(*fb), GFP_ATOMIC);
+ fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
if (!fb) {
printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
return -ENODEV;
info = &fb->info;
/* set struct to a known state */
- memset(fb, 0, sizeof(*fb));
fix = &info->fix;
var = &info->var;
case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
/* FIXME: TomCat supports two heads:
* fb.iobase = REGION_BASE(fb_info,3);
- * fb.screen_base = (void*) REGION_BASE(fb_info,2);
+ * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
* for now we only support the left one ! */
xres = fb->ngle_rom.x_size_visible;
yres = fb->ngle_rom.y_size_visible;
memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
if ((fb->sti->regions_phys[0] & 0xfc000000) ==
(fb->sti->regions_phys[2] & 0xfc000000))
- sti_rom_address = fb->sti->regions_phys[0];
+ sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
else
- sti_rom_address = fb->sti->regions_phys[1];
-#ifdef __LP64__
- sti_rom_address |= 0xffffffff00000000;
-#endif
- fb->deviceSpecificConfig = __raw_readl(sti_rom_address);
+ sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
+
+ fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
if (IS_24_DEVICE(fb)) {
- if (force_bpp == 8 || force_bpp == 32)
- bpp = force_bpp;
+ if (bpp_pref == 8 || bpp_pref == 32)
+ bpp = bpp_pref;
else
bpp = 32;
} else
case 1:
fix->type = FB_TYPE_PLANES; /* well, sort of */
fix->visual = FB_VISUAL_MONO10;
+ var->red.length = var->green.length = var->blue.length = 1;
break;
case 8:
fix->type = FB_TYPE_PACKED_PIXELS;
break;
case 32:
fix->type = FB_TYPE_PACKED_PIXELS;
- fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->visual = FB_VISUAL_DIRECTCOLOR;
var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
var->blue.offset = 0;
var->green.offset = 8;
strcpy(fix->id, "stifb");
info->fbops = &stifb_ops;
- info->screen_base = (void*) REGION_BASE(fb,1);
- info->flags = FBINFO_FLAG_DEFAULT;
- info->currcon = -1;
+ info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
+ info->screen_size = fix->smem_len;
+ info->flags = FBINFO_DEFAULT;
+ info->pseudo_palette = &fb->pseudo_palette;
/* This has to been done !!! */
- fb_alloc_cmap(&info->cmap, 256, 0);
+ fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
stifb_init_display(fb);
if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
out_err2:
release_mem_region(fix->smem_start, fix->smem_len);
out_err1:
+ iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
out_err0:
kfree(fb);
static int stifb_disabled __initdata;
+int __init
+stifb_setup(char *options);
+
int __init
stifb_init(void)
{
struct sti_struct *sti;
+ struct sti_struct *def_sti;
int i;
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("stifb", &option))
+ return -ENODEV;
+ stifb_setup(option);
+#endif
if (stifb_disabled) {
printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
return -ENXIO;
}
- for (i = 1; i < MAX_STI_ROMS; i++) {
+ def_sti = sti_get_rom(0);
+ if (def_sti) {
+ for (i = 1; i <= MAX_STI_ROMS; i++) {
+ sti = sti_get_rom(i);
+ if (!sti)
+ break;
+ if (sti == def_sti) {
+ stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
+ break;
+ }
+ }
+ }
+
+ for (i = 1; i <= MAX_STI_ROMS; i++) {
sti = sti_get_rom(i);
if (!sti)
break;
- if (bpp > 0)
- stifb_force_bpp[i] = bpp;
- stifb_init_fb(sti, stifb_force_bpp[i]);
+ if (sti == def_sti)
+ continue;
+ stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
}
return 0;
}
struct sti_struct *sti;
int i;
- for (i = 1; i < MAX_STI_ROMS; i++) {
+ for (i = 1; i <= MAX_STI_ROMS; i++) {
sti = sti_get_rom(i);
if (!sti)
break;
unregister_framebuffer(sti->info);
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ if (info->screen_base)
+ iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
kfree(info);
}
int i;
if (!options || !*options)
- return 0;
+ return 1;
if (strncmp(options, "off", 3) == 0) {
stifb_disabled = 1;
if (strncmp(options, "bpp", 3) == 0) {
options += 3;
for (i = 0; i < MAX_STI_ROMS; i++) {
- if (*options++ == ':') {
- stifb_force_bpp[i] = simple_strtoul(options, &options, 10);
- bpp = -1;
- } else
+ if (*options++ != ':')
break;
+ stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
}
}
- return 0;
+ return 1;
}
__setup("stifb=", stifb_setup);
-#ifdef MODULE
module_init(stifb_init);
-#endif
module_exit(stifb_cleanup);
MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
MODULE_LICENSE("GPL v2");
-
-MODULE_PARM(bpp, "i");
-MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)");
-