config FB_TCX
bool "TCX (SS4/SS5 only) support"
- depends on FB_SBUS && SPARC32
+ depends on FB_SBUS
help
This is the frame buffer device driver for the TCX 24/8bit frame
buffer.
obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
# One by one these are being converted over to the new APIs
-#obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
#obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
cfbfillrect.o
obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
cfbfillrect.o
+obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
+ cfbfillrect.o
# Files generated that shall be removed upon make clean
clean-files := promcon_tbl.c
extern int cg14_setup(char*);
extern int p9100_init(void);
extern int p9100_setup(char*);
+extern int tcx_init(void);
+extern int tcx_setup(char*);
static struct {
const char *name;
#ifdef CONFIG_FB_P9100
{ "p9100", p9100_init, p9100_setup },
#endif
+#ifdef CONFIG_FB_TCX
+ { "tcx", tcx_init, tcx_setup },
+#endif
/*
* Generic drivers that are used as fallbacks
--- /dev/null
+/* tcx.c: TCX frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int tcx_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int tcx_set_par(struct fb_info *);
+static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned,
+ unsigned, struct fb_info *);
+static int tcx_blank(int, struct fb_info *);
+
+static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ * Frame buffer operations
+ */
+
+static struct fb_ops tcx_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = tcx_check_var,
+ .fb_set_par = tcx_set_par,
+ .fb_setcolreg = tcx_setcolreg,
+ .fb_blank = tcx_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = tcx_mmap,
+ .fb_cursor = soft_cursor,
+};
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT 16
+#define TCX_THC_MISC_REV_MASK 15
+#define TCX_THC_MISC_VSYNC_DIS (1 << 25)
+#define TCX_THC_MISC_HSYNC_DIS (1 << 24)
+#define TCX_THC_MISC_RESET (1 << 12)
+#define TCX_THC_MISC_VIDEO (1 << 10)
+#define TCX_THC_MISC_SYNC (1 << 9)
+#define TCX_THC_MISC_VSYNC (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB (1 << 7)
+#define TCX_THC_MISC_CURS_RES (1 << 6)
+#define TCX_THC_MISC_INT_ENAB (1 << 5)
+#define TCX_THC_MISC_INT (1 << 4)
+#define TCX_THC_MISC_INIT 0x9f
+#define TCX_THC_REV_REV_SHIFT 20
+#define TCX_THC_REV_REV_MASK 15
+#define TCX_THC_REV_MINREV_SHIFT 28
+#define TCX_THC_REV_MINREV_MASK 15
+
+/* The contents are unknown */
+struct tcx_tec {
+ volatile u32 tec_matrix;
+ volatile u32 tec_clip;
+ volatile u32 tec_vdc;
+};
+
+struct tcx_thc {
+ volatile u32 thc_rev;
+ u32 thc_pad0[511];
+ volatile u32 thc_hs; /* hsync timing */
+ volatile u32 thc_hsdvs;
+ volatile u32 thc_hd;
+ volatile u32 thc_vs; /* vsync timing */
+ volatile u32 thc_vd;
+ volatile u32 thc_refresh;
+ volatile u32 thc_misc;
+ u32 thc_pad1[56];
+ volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */
+ volatile u32 thc_cursmask[32]; /* cursor mask bits */
+ volatile u32 thc_cursbits[32]; /* what to show where mask enabled */
+};
+
+struct bt_regs {
+ volatile u32 addr;
+ volatile u32 color_map;
+ volatile u32 control;
+ volatile u32 cursor;
+};
+
+#define TCX_MMAP_ENTRIES 14
+
+struct tcx_par {
+ spinlock_t lock;
+ struct bt_regs *bt;
+ struct tcx_thc *thc;
+ struct tcx_tec *tec;
+ volatile u32 *cplane;
+
+ u32 flags;
+#define TCX_FLAG_BLANKED 0x00000001
+
+ unsigned long physbase;
+ unsigned long fbsize;
+
+ struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES];
+ int lowdepth;
+
+ struct sbus_dev *sdev;
+ struct list_head list;
+};
+
+/* Reset control plane so that WID is 8-bit plane. */
+static void __tcx_set_control_plane (struct tcx_par *par)
+{
+ volatile u32 *p, *pend;
+
+ if (par->lowdepth)
+ return;
+
+ p = par->cplane;
+ if (p == NULL)
+ return;
+ for (pend = p + par->fbsize; p < pend; p++) {
+ u32 tmp = sbus_readl(p);
+
+ tmp &= 0xffffff;
+ sbus_writel(tmp, p);
+ }
+}
+
+static void tcx_reset (struct fb_info *info)
+{
+ struct tcx_par *par = (struct tcx_par *) info->par;
+ unsigned long flags;
+
+ spin_lock_irqsave(&par->lock, flags);
+ __tcx_set_control_plane(par);
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ * tcx_check_var - Optional function. Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int tcx_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ if (var->bits_per_pixel != 8)
+ return -EINVAL;
+
+ if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+ return -EINVAL;
+ if (var->nonstd)
+ return -EINVAL;
+ if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+
+ if (var->xres != info->var.xres || var->yres != info->var.yres)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * tcx_set_par - Optional function. Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tcx_set_par(struct fb_info *info)
+{
+ return 0;
+}
+
+/**
+ * tcx_setcolreg - Optional function. Sets a color register.
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
+ */
+static int tcx_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ struct tcx_par *par = (struct tcx_par *) info->par;
+ struct bt_regs *bt = par->bt;
+ unsigned long flags;
+
+ if (regno >= 256)
+ return 1;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ sbus_writel(regno << 24, &bt->addr);
+ sbus_writel(red << 24, &bt->color_map);
+ sbus_writel(green << 24, &bt->color_map);
+ sbus_writel(blue << 24, &bt->color_map);
+
+ spin_unlock_irqrestore(&par->lock, flags);
+
+ return 0;
+}
+
+/**
+ * tcx_blank - Optional function. Blanks the display.
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tcx_blank(int blank, struct fb_info *info)
+{
+ struct tcx_par *par = (struct tcx_par *) info->par;
+ struct tcx_thc *thc = par->thc;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ val = sbus_readl(&thc->thc_misc);
+
+ switch (blank) {
+ case 0: /* Unblanking */
+ val &= ~(TCX_THC_MISC_VSYNC_DIS |
+ TCX_THC_MISC_HSYNC_DIS);
+ val |= TCX_THC_MISC_VIDEO;
+ par->flags &= ~TCX_FLAG_BLANKED;
+ break;
+
+ case 1: /* Normal blanking */
+ val &= ~TCX_THC_MISC_VIDEO;
+ par->flags |= TCX_FLAG_BLANKED;
+ break;
+
+ case 2: /* VESA blank (vsync off) */
+ val |= TCX_THC_MISC_VSYNC_DIS;
+ break;
+ case 3: /* VESA blank (hsync off) */
+ val |= TCX_THC_MISC_HSYNC_DIS;
+ break;
+
+ case 4: /* Poweroff */
+ break;
+ };
+
+ sbus_writel(val, &thc->thc_misc);
+
+ spin_unlock_irqrestore(&par->lock, flags);
+
+ return 0;
+}
+
+static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = {
+ { TCX_RAM8BIT, 0, SBUS_MMAP_FBSIZE(1) },
+ { TCX_RAM24BIT, 0, SBUS_MMAP_FBSIZE(4) },
+ { TCX_UNK3, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_UNK4, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_CONTROLPLANE, 0, SBUS_MMAP_FBSIZE(4) },
+ { TCX_UNK6, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_UNK7, 0, SBUS_MMAP_FBSIZE(8) },
+ { TCX_TEC, 0, PAGE_SIZE },
+ { TCX_BTREGS, 0, PAGE_SIZE },
+ { TCX_THC, 0, PAGE_SIZE },
+ { TCX_DHC, 0, PAGE_SIZE },
+ { TCX_ALT, 0, PAGE_SIZE },
+ { TCX_UNK2, 0, 0x20000 },
+ { 0, 0, 0 }
+};
+
+static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+ struct tcx_par *par = (struct tcx_par *)info->par;
+
+ return sbusfb_mmap_helper(par->mmap_map,
+ par->physbase, par->fbsize,
+ par->sdev->reg_addrs[0].which_io,
+ vma);
+}
+
+/*
+ * Initialisation
+ */
+
+static void
+tcx_init_fix(struct fb_info *info, int linebytes)
+{
+ struct tcx_par *par = (struct tcx_par *)info->par;
+ const char *tcx_name;
+
+ if (par->lowdepth)
+ tcx_name = "TCX8";
+ else
+ tcx_name = "TCX24";
+
+ strncpy(info->fix.id, tcx_name, sizeof(info->fix.id) - 1);
+ info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+ info->fix.line_length = linebytes;
+
+ info->fix.accel = FB_ACCEL_SUN_TCX;
+}
+
+struct all_info {
+ struct fb_info info;
+ struct tcx_par par;
+ struct list_head list;
+};
+static LIST_HEAD(tcx_list);
+
+static void tcx_init_one(struct sbus_dev *sdev)
+{
+ struct all_info *all;
+ int linebytes, i;
+
+ all = kmalloc(sizeof(*all), GFP_KERNEL);
+ if (!all) {
+ printk(KERN_ERR "tcx: Cannot allocate memory.\n");
+ return;
+ }
+ memset(all, 0, sizeof(*all));
+
+ INIT_LIST_HEAD(&all->list);
+
+ spin_lock_init(&all->par.lock);
+ all->par.sdev = sdev;
+
+ all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit");
+
+ sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+
+ linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+ all->info.var.xres);
+ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+ all->par.tec = (struct tcx_tec *)
+ sbus_ioremap(&sdev->resource[7], 0,
+ sizeof(struct tcx_tec), "tcx tec");
+ all->par.thc = (struct tcx_thc *)
+ sbus_ioremap(&sdev->resource[9], 0,
+ sizeof(struct tcx_thc), "tcx thc");
+ all->par.bt = (struct bt_regs *)
+ sbus_ioremap(&sdev->resource[8], 0,
+ sizeof(struct bt_regs), "tcx dac");
+ memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map));
+ if (!all->par.lowdepth) {
+ all->par.cplane = (volatile u32 *)
+ sbus_ioremap(&sdev->resource[4], 0,
+ all->par.fbsize * sizeof(u32), "tcx cplane");
+ } else {
+ all->par.mmap_map[1].size = SBUS_MMAP_EMPTY;
+ all->par.mmap_map[4].size = SBUS_MMAP_EMPTY;
+ all->par.mmap_map[5].size = SBUS_MMAP_EMPTY;
+ all->par.mmap_map[6].size = SBUS_MMAP_EMPTY;
+ }
+
+ all->par.physbase = 0;
+ for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
+ int j;
+
+ switch (i) {
+ case 10:
+ j = 12;
+ break;
+
+ case 11: case 12:
+ j = i - 1;
+ break;
+
+ default:
+ j = i;
+ break;
+ };
+ all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr;
+ }
+
+ all->info.node = NODEV;
+ all->info.flags = FBINFO_FLAG_DEFAULT;
+ all->info.fbops = &tcx_ops;
+#ifdef CONFIG_SPARC32
+ all->info.screen_base = (char *)
+ prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+ if (!all->info.screen_base)
+ all->info.screen_base = (char *)
+ sbus_ioremap(&sdev->resource[0], 0,
+ all->par.fbsize, "tcx ram");
+ all->info.currcon = -1;
+ all->info.par = &all->par;
+
+ /* Initialize brooktree DAC. */
+ sbus_writel(0x04 << 24, &all->par.bt->addr); /* color planes */
+ sbus_writel(0xff << 24, &all->par.bt->control);
+ sbus_writel(0x05 << 24, &all->par.bt->addr);
+ sbus_writel(0x00 << 24, &all->par.bt->control);
+ sbus_writel(0x06 << 24, &all->par.bt->addr); /* overlay plane */
+ sbus_writel(0x73 << 24, &all->par.bt->control);
+ sbus_writel(0x07 << 24, &all->par.bt->addr);
+ sbus_writel(0x00 << 24, &all->par.bt->control);
+
+ tcx_reset(&all->info);
+
+ tcx_blank(0, &all->info);
+
+ if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+ printk(KERN_ERR "tcx: Could not allocate color map.\n");
+ kfree(all);
+ return;
+ }
+
+ tcx_set_par(&all->info);
+ tcx_init_fix(&all->info, linebytes);
+
+ if (register_framebuffer(&all->info) < 0) {
+ printk(KERN_ERR "tcx: Could not register framebuffer.\n");
+ fb_dealloc_cmap(&all->info.cmap);
+ kfree(all);
+ return;
+ }
+
+ list_add(&all->list, &tcx_list);
+
+ printk("tcx: %s at %lx:%lx, %s\n",
+ sdev->prom_name,
+ (long) sdev->reg_addrs[0].which_io,
+ (long) sdev->reg_addrs[0].phys_addr,
+ all->par.lowdepth ? "8-bit only" : "24-bit depth");
+}
+
+int __init tcx_init(void)
+{
+ struct sbus_bus *sbus;
+ struct sbus_dev *sdev;
+
+ for_all_sbusdev(sdev, sbus) {
+ if (!strcmp(sdev->prom_name, "tcx"))
+ tcx_init_one(sdev);
+ }
+
+ return 0;
+}
+
+void __exit tcx_exit(void)
+{
+ struct list_head *pos, *tmp;
+
+ list_for_each_safe(pos, tmp, &tcx_list) {
+ struct all_info *all = list_entry(pos, typeof(*all), list);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+ kfree(all);
+ }
+}
+
+int __init
+tcx_setup(char *arg)
+{
+ /* No cmdline options yet... */
+ return 0;
+}
+
+#ifdef MODULE
+module_init(tcx_init);
+module_exit(tcx_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for TCX chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
+++ /dev/null
-/* $Id: tcxfb.c,v 1.13 2001/09/19 00:04:33 davem Exp $
- * tcxfb.c: TCX 24/8bit frame buffer driver
- *
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-#include <asm/io.h>
-#include <asm/sbus.h>
-
-#include <video/fbcon-cfb8.h>
-
-/* THC definitions */
-#define TCX_THC_MISC_REV_SHIFT 16
-#define TCX_THC_MISC_REV_MASK 15
-#define TCX_THC_MISC_VSYNC_DIS (1 << 25)
-#define TCX_THC_MISC_HSYNC_DIS (1 << 24)
-#define TCX_THC_MISC_RESET (1 << 12)
-#define TCX_THC_MISC_VIDEO (1 << 10)
-#define TCX_THC_MISC_SYNC (1 << 9)
-#define TCX_THC_MISC_VSYNC (1 << 8)
-#define TCX_THC_MISC_SYNC_ENAB (1 << 7)
-#define TCX_THC_MISC_CURS_RES (1 << 6)
-#define TCX_THC_MISC_INT_ENAB (1 << 5)
-#define TCX_THC_MISC_INT (1 << 4)
-#define TCX_THC_MISC_INIT 0x9f
-#define TCX_THC_REV_REV_SHIFT 20
-#define TCX_THC_REV_REV_MASK 15
-#define TCX_THC_REV_MINREV_SHIFT 28
-#define TCX_THC_REV_MINREV_MASK 15
-
-/* The contents are unknown */
-struct tcx_tec {
- volatile u32 tec_matrix;
- volatile u32 tec_clip;
- volatile u32 tec_vdc;
-};
-
-struct tcx_thc {
- volatile u32 thc_rev;
- u32 thc_pad0[511];
- volatile u32 thc_hs; /* hsync timing */
- volatile u32 thc_hsdvs;
- volatile u32 thc_hd;
- volatile u32 thc_vs; /* vsync timing */
- volatile u32 thc_vd;
- volatile u32 thc_refresh;
- volatile u32 thc_misc;
- u32 thc_pad1[56];
- volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */
- volatile u32 thc_cursmask[32]; /* cursor mask bits */
- volatile u32 thc_cursbits[32]; /* what to show where mask enabled */
-};
-
-static struct sbus_mmap_map tcx_mmap_map[] = {
- { TCX_RAM8BIT, 0, SBUS_MMAP_FBSIZE(1) },
- { TCX_RAM24BIT, 0, SBUS_MMAP_FBSIZE(4) },
- { TCX_UNK3, 0, SBUS_MMAP_FBSIZE(8) },
- { TCX_UNK4, 0, SBUS_MMAP_FBSIZE(8) },
- { TCX_CONTROLPLANE, 0, SBUS_MMAP_FBSIZE(4) },
- { TCX_UNK6, 0, SBUS_MMAP_FBSIZE(8) },
- { TCX_UNK7, 0, SBUS_MMAP_FBSIZE(8) },
- { TCX_TEC, 0, PAGE_SIZE },
- { TCX_BTREGS, 0, PAGE_SIZE },
- { TCX_THC, 0, PAGE_SIZE },
- { TCX_DHC, 0, PAGE_SIZE },
- { TCX_ALT, 0, PAGE_SIZE },
- { TCX_UNK2, 0, 0x20000 },
- { 0, 0, 0 }
-};
-
-static void __tcx_set_control_plane (struct fb_info_sbusfb *fb)
-{
- u32 *p, *pend;
-
- p = fb->s.tcx.cplane;
- if (p == NULL)
- return;
- for (pend = p + fb->type.fb_size; p < pend; p++) {
- u32 tmp = sbus_readl(p);
-
- tmp &= 0xffffff;
- sbus_writel(tmp, p);
- }
-}
-
-static void tcx_switch_from_graph (struct fb_info_sbusfb *fb)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&fb->lock, flags);
-
- /* Reset control plane to 8bit mode if necessary */
- if (fb->open && fb->mmaped)
- __tcx_set_control_plane (fb);
-
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
-{
- struct bt_regs *bt = fb->s.tcx.bt;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&fb->lock, flags);
- sbus_writel(index << 24, &bt->addr);
- for (i = index; count--; i++){
- sbus_writel(fb->color_map CM(i,0) << 24, &bt->color_map);
- sbus_writel(fb->color_map CM(i,1) << 24, &bt->color_map);
- sbus_writel(fb->color_map CM(i,2) << 24, &bt->color_map);
- }
- sbus_writel(0, &bt->addr);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_restore_palette (struct fb_info_sbusfb *fb)
-{
- struct bt_regs *bt = fb->s.tcx.bt;
- unsigned long flags;
-
- spin_lock_irqsave(&fb->lock, flags);
- sbus_writel(0, &bt->addr);
- sbus_writel(0xffffffff, &bt->color_map);
- sbus_writel(0xffffffff, &bt->color_map);
- sbus_writel(0xffffffff, &bt->color_map);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
-{
- struct bt_regs *bt = fb->s.tcx.bt;
- unsigned long flags;
-
- spin_lock_irqsave(&fb->lock, flags);
-
- /* Note the 2 << 24 is different from cg6's 1 << 24 */
- sbus_writel(2 << 24, &bt->addr);
- sbus_writel(red[0] << 24, &bt->cursor);
- sbus_writel(green[0] << 24, &bt->cursor);
- sbus_writel(blue[0] << 24, &bt->cursor);
- sbus_writel(3 << 24, &bt->addr);
- sbus_writel(red[1] << 24, &bt->cursor);
- sbus_writel(green[1] << 24, &bt->cursor);
- sbus_writel(blue[1] << 24, &bt->cursor);
- sbus_writel(0, &bt->addr);
-
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Set cursor shape */
-static void tcx_setcurshape (struct fb_info_sbusfb *fb)
-{
- struct tcx_thc *thc = fb->s.tcx.thc;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&fb->lock, flags);
- for (i = 0; i < 32; i++){
- sbus_writel(fb->cursor.bits[0][i], &thc->thc_cursmask[i]);
- sbus_writel(fb->cursor.bits[1][i], &thc->thc_cursbits[i]);
- }
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Load cursor information */
-static void tcx_setcursor (struct fb_info_sbusfb *fb)
-{
- struct cg_cursor *c = &fb->cursor;
- unsigned long flags;
- unsigned int v;
-
- spin_lock_irqsave(&fb->lock, flags);
- if (c->enable)
- v = ((c->cpos.fbx - c->chot.fbx) << 16)
- |((c->cpos.fby - c->chot.fby) & 0xffff);
- else
- /* Magic constant to turn off the cursor */
- v = ((65536-32) << 16) | (65536-32);
- sbus_writel(v, &fb->s.tcx.thc->thc_cursxy);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int tcx_blank (struct fb_info_sbusfb *fb)
-{
- unsigned long flags;
- u32 tmp;
-
- spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.tcx.thc->thc_misc);
- tmp &= ~TCX_THC_MISC_VIDEO;
- /* This should put us in power-save */
- tmp |= TCX_THC_MISC_VSYNC_DIS;
- tmp |= TCX_THC_MISC_HSYNC_DIS;
- sbus_writel(tmp, &fb->s.tcx.thc->thc_misc);
- spin_unlock_irqrestore(&fb->lock, flags);
- return 0;
-}
-
-static int tcx_unblank (struct fb_info_sbusfb *fb)
-{
- unsigned long flags;
- u32 tmp;
-
- spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.tcx.thc->thc_misc);
- tmp &= ~TCX_THC_MISC_VSYNC_DIS;
- tmp &= ~TCX_THC_MISC_HSYNC_DIS;
- tmp |= TCX_THC_MISC_VIDEO;
- sbus_writel(tmp, &fb->s.tcx.thc->thc_misc);
- spin_unlock_irqrestore(&fb->lock, flags);
- return 0;
-}
-
-static void tcx_reset (struct fb_info_sbusfb *fb)
-{
- unsigned long flags;
- u32 tmp;
-
- spin_lock_irqsave(&fb->lock, flags);
- if (fb->open && fb->mmaped)
- __tcx_set_control_plane(fb);
-
- /* Turn off stuff in the Transform Engine. */
- sbus_writel(0, &fb->s.tcx.tec->tec_matrix);
- sbus_writel(0, &fb->s.tcx.tec->tec_clip);
- sbus_writel(0, &fb->s.tcx.tec->tec_vdc);
-
- /* Enable cursor in Brooktree DAC. */
- sbus_writel(0x06 << 24, &fb->s.tcx.bt->addr);
- tmp = sbus_readl(&fb->s.tcx.bt->control);
- tmp |= 0x03 << 24;
- sbus_writel(tmp, &fb->s.tcx.bt->control);
- spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
-{
- fb->info.screen_base += (y_margin - fb->y_margin) * p->fb_info->fix.line_length + (x_margin - fb->x_margin);
-}
-
-static char idstring[60] __initdata = { 0 };
-
-char __init *tcxfb_init(struct fb_info_sbusfb *fb)
-{
- struct fb_fix_screeninfo *fix = &fb->info.fix;
- struct display *disp = &fb->disp;
- struct fbtype *type = &fb->type;
- struct sbus_dev *sdev = fb->sbdp;
- unsigned long phys = sdev->reg_addrs[0].phys_addr;
- int lowdepth, i, j;
-
-#ifndef FBCON_HAS_CFB8
- return NULL;
-#endif
-
- lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit");
-
- if (lowdepth) {
- strcpy(fb->info.modename, "TCX8");
- strcpy(fix->id, "TCX8");
- } else {
- strcpy(fb->info.modename, "TCX24");
- strcpy(fix->id, "TCX24");
- }
- fix->line_length = fb->info.var.xres_virtual;
- fix->accel = FB_ACCEL_SUN_TCX;
-
- disp->scrollmode = SCROLL_YREDRAW;
- if (!fb->info.screen_base) {
- fb->info.screen_base = (char *)
- sbus_ioremap(&sdev->resource[0], 0,
- type->fb_size, "tcx ram");
- }
- fb->info.screen_base += fix->line_length * fb->y_margin + fb->x_margin;
- fb->s.tcx.tec = (struct tcx_tec *)
- sbus_ioremap(&sdev->resource[7], 0,
- sizeof(struct tcx_tec), "tcx tec");
- fb->s.tcx.thc = (struct tcx_thc *)
- sbus_ioremap(&sdev->resource[9], 0,
- sizeof(struct tcx_thc), "tcx thc");
- fb->s.tcx.bt = (struct bt_regs *)
- sbus_ioremap(&sdev->resource[8], 0,
- sizeof(struct bt_regs), "tcx dac");
- if (!lowdepth) {
- fb->s.tcx.cplane = (u32 *)
- sbus_ioremap(&sdev->resource[4], 0,
- type->fb_size * sizeof(u32), "tcx cplane");
- type->fb_depth = 24;
- fb->switch_from_graph = tcx_switch_from_graph;
- } else {
- /* As there can be one tcx in a machine only, we can write directly into
- tcx_mmap_map */
- tcx_mmap_map[1].size = SBUS_MMAP_EMPTY;
- tcx_mmap_map[4].size = SBUS_MMAP_EMPTY;
- tcx_mmap_map[5].size = SBUS_MMAP_EMPTY;
- tcx_mmap_map[6].size = SBUS_MMAP_EMPTY;
- }
- fb->dispsw = fbcon_cfb8;
-
- fb->margins = tcx_margins;
- fb->loadcmap = tcx_loadcmap;
- if (prom_getbool (fb->prom_node, "hw-cursor")) {
- fb->setcursor = tcx_setcursor;
- fb->setcursormap = tcx_setcursormap;
- fb->setcurshape = tcx_setcurshape;
- }
- fb->restore_palette = tcx_restore_palette;
- fb->blank = tcx_blank;
- fb->unblank = tcx_unblank;
- fb->reset = tcx_reset;
-
- fb->physbase = 0;
- for (i = 0; i < 13; i++) {
- /* tcx_mmap_map has to be sorted by voff, while
- order of phys registers from PROM differs a little
- bit. Here is the correction */
- switch (i) {
- case 10: j = 12; break;
- case 11:
- case 12: j = i - 1; break;
- default: j = i; break;
- }
- tcx_mmap_map[i].poff = fb->sbdp->reg_addrs[j].phys_addr;
- }
- fb->mmap_map = tcx_mmap_map;
-
- /* Initialize Brooktree DAC */
- sbus_writel(0x04 << 24, &fb->s.tcx.bt->addr); /* color planes */
- sbus_writel(0xff << 24, &fb->s.tcx.bt->control);
- sbus_writel(0x05 << 24, &fb->s.tcx.bt->addr);
- sbus_writel(0x00 << 24, &fb->s.tcx.bt->control);
- sbus_writel(0x06 << 24, &fb->s.tcx.bt->addr); /* overlay plane */
- sbus_writel(0x73 << 24, &fb->s.tcx.bt->control);
- sbus_writel(0x07 << 24, &fb->s.tcx.bt->addr);
- sbus_writel(0x00 << 24, &fb->s.tcx.bt->control);
-
- sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s",
- fb->iospace, phys,
- ((sbus_readl(&fb->s.tcx.thc->thc_rev) >> TCX_THC_REV_REV_SHIFT) &
- TCX_THC_REV_REV_MASK),
- ((sbus_readl(&fb->s.tcx.thc->thc_rev) >> TCX_THC_REV_MINREV_SHIFT) &
- TCX_THC_REV_MINREV_MASK),
- lowdepth ? "8-bit only" : "24-bit depth");
-
- tcx_reset(fb);
-
- return idstring;
-}
-
-MODULE_LICENSE("GPL");