888 lines
22 KiB
Diff
888 lines
22 KiB
Diff
From: David Miller <davem@davemloft.net>
|
|
To: sammy@sammy.net
|
|
Cc: linux-m68k@vger.kernel.org
|
|
Subject: Re: [PATCH] cg3/bw2: add Sun3/Sun3x support
|
|
|
|
From: Sam Creasey <sammy@sammy.net>
|
|
Date: Tue, 3 Apr 2007 10:32:35 -0400
|
|
|
|
> This patch (re) introduces support for the CG3 driver on Sun3, and for
|
|
> BW2 on Sun3x. It applies cleanly to both the m68k CVS tree and the
|
|
> vanilla tree.
|
|
>
|
|
> Signed-off-by: Sam Creasey <sammy@sammy.net>
|
|
|
|
If you guys want to share driver code with the Sparc port, please do
|
|
it properly.
|
|
|
|
I am not applying a pile of ifdef's that basically duplicate half of
|
|
the existing driver.
|
|
|
|
What you can do instead is to build a fake openprom device tree and
|
|
register those devices with the generic device subsystem, and then the
|
|
driver will mostly just work out of the box. It should be easy to
|
|
duplicate the arch/sparc64/kernel/prom.c and of_device.c code you
|
|
use as well as the driver interfaces in include/asm-sparc64/prom.h
|
|
and of_device.h
|
|
|
|
This way you don't need to shit all over the drivers adding hardcoded
|
|
register addresses and ad-hoc probing code. For special behaviors,
|
|
you can add openprom node properties that the driver can test for at
|
|
run time to guide behavior, again instead of ifdefs.
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
From sammy@sammy.net Tue Apr 3 16:47:32 2007
|
|
Date: Tue, 3 Apr 2007 10:32:35 -0400
|
|
From: Sam Creasey <sammy@sammy.net>
|
|
To: linux-m68k@vger.kernel.org, David S. Miller <davem@davemloft.net>
|
|
Subject: [PATCH] cg3/bw2: add Sun3/Sun3x support
|
|
|
|
This patch (re) introduces support for the CG3 driver on Sun3, and for
|
|
BW2 on Sun3x. It applies cleanly to both the m68k CVS tree and the
|
|
vanilla tree.
|
|
|
|
Signed-off-by: Sam Creasey <sammy@sammy.net>
|
|
|
|
---
|
|
drivers/video/Kconfig | 14 ++
|
|
drivers/video/Makefile | 1
|
|
drivers/video/bw2.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++--
|
|
drivers/video/cg3.c | 212 ++++++++++++++++++++++++++++++++++++++++++-
|
|
drivers/video/p4lib.c | 107 ++++++++++++++++++++++
|
|
drivers/video/p4lib.h | 56 +++++++++++
|
|
drivers/video/sbuslib.c | 13 ++
|
|
7 files changed, 616 insertions(+), 19 deletions(-)
|
|
|
|
--- linux-m68k-2.6.21.orig/drivers/video/Kconfig
|
|
+++ linux-m68k-2.6.21/drivers/video/Kconfig
|
|
@@ -600,6 +600,16 @@ config FB_GBE_MEM
|
|
This is the amount of memory reserved for the framebuffer,
|
|
which can be any value between 1MB and 8MB.
|
|
|
|
+config FB_SUN3
|
|
+ bool "Sun3 framebuffer support"
|
|
+ depends on (FB = y) && (SUN3 || SUN3X)
|
|
+ help
|
|
+ Support framebuffer devices on Sun3/3x. Note that if you say yes
|
|
+ here, any framebuffer drivers you select MUST be installed in the
|
|
+ target system, or be disabled on the command line. (e.g. if you
|
|
+ don't have a bw2, include video=bw2fb:off. If you don't have
|
|
+ a cg3, include video=cg3fb:off.)
|
|
+
|
|
config FB_SBUS
|
|
bool "SBUS and UPA framebuffers"
|
|
depends on (FB = y) && SPARC
|
|
@@ -608,7 +618,7 @@ config FB_SBUS
|
|
|
|
config FB_BW2
|
|
bool "BWtwo support"
|
|
- depends on (FB = y) && (SPARC && FB_SBUS)
|
|
+ depends on (FB = y) && ((SPARC && FB_SBUS) || (SUN3X && FB_SUN3))
|
|
select FB_CFB_FILLRECT
|
|
select FB_CFB_COPYAREA
|
|
select FB_CFB_IMAGEBLIT
|
|
@@ -617,7 +627,7 @@ config FB_BW2
|
|
|
|
config FB_CG3
|
|
bool "CGthree support"
|
|
- depends on (FB = y) && (SPARC && FB_SBUS)
|
|
+ depends on (FB = y) && ((SPARC && FB_SBUS) || (SUN3 && FB_SUN3))
|
|
select FB_CFB_FILLRECT
|
|
select FB_CFB_COPYAREA
|
|
select FB_CFB_IMAGEBLIT
|
|
--- linux-m68k-2.6.21.orig/drivers/video/Makefile
|
|
+++ linux-m68k-2.6.21/drivers/video/Makefile
|
|
@@ -106,6 +106,7 @@ obj-$(CONFIG_FB_VESA) += ves
|
|
obj-$(CONFIG_FB_IMAC) += imacfb.o
|
|
obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
|
|
obj-$(CONFIG_FB_OF) += offb.o
|
|
+obj-$(CONFIG_FB_SUN3) += p4lib.o
|
|
|
|
# the test framebuffer is last
|
|
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
|
|
--- linux-m68k-2.6.21.orig/drivers/video/bw2.c
|
|
+++ linux-m68k-2.6.21/drivers/video/bw2.c
|
|
@@ -20,18 +20,29 @@
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/oplib.h>
|
|
+#ifndef CONFIG_FB_SUN3
|
|
#include <asm/prom.h>
|
|
#include <asm/of_device.h>
|
|
+#endif
|
|
#include <asm/fbio.h>
|
|
|
|
#include "sbuslib.h"
|
|
|
|
+#ifdef CONFIG_FB_SUN3
|
|
+#ifdef CONFIG_SUN3
|
|
+#include <asm/sun3mmu.h>
|
|
+#endif
|
|
+#include <asm/machines.h>
|
|
+#include <asm/idprom.h>
|
|
+#include <asm/sbus.h>
|
|
+#include "p4lib.h"
|
|
+#endif
|
|
/*
|
|
* Local functions.
|
|
*/
|
|
-
|
|
+#ifndef CONFIG_FB_SUN3
|
|
static int bw2_blank(int, struct fb_info *);
|
|
-
|
|
+#endif
|
|
static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
|
|
static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
|
|
|
|
@@ -41,7 +52,11 @@ static int bw2_ioctl(struct fb_info *, u
|
|
|
|
static struct fb_ops bw2_ops = {
|
|
.owner = THIS_MODULE,
|
|
+#ifdef CONFIG_FB_SUN3
|
|
+ .fb_blank = NULL,
|
|
+#else
|
|
.fb_blank = bw2_blank,
|
|
+#endif
|
|
.fb_fillrect = cfb_fillrect,
|
|
.fb_copyarea = cfb_copyarea,
|
|
.fb_imageblit = cfb_imageblit,
|
|
@@ -53,7 +68,18 @@ static struct fb_ops bw2_ops = {
|
|
};
|
|
|
|
/* OBio addresses for the bwtwo registers */
|
|
+#ifdef CONFIG_FB_SUN3
|
|
+/* sun3 series */
|
|
+#define BWTWO_OBMEM_ADDR 0x1f000000
|
|
+#define BWTWO_OBMEM_ADDR_50 0x00100000
|
|
+#define BWTWO_OBMEM_ADDR_P4 0x1f300000
|
|
+#define BWTWO_OBMEM_ADDR_3X 0x50300000
|
|
+/* is this true for 3/50? */
|
|
+#define BWTWO_FB_OFFSET 0x100000
|
|
+#define BWTWO_OBMEM_HIGHRES_60 0x1f1c0000
|
|
+#else
|
|
#define BWTWO_REGISTER_OFFSET 0x400000
|
|
+#endif
|
|
|
|
struct bt_regs {
|
|
u32 addr;
|
|
@@ -108,8 +134,11 @@ struct bw2_regs {
|
|
|
|
struct bw2_par {
|
|
spinlock_t lock;
|
|
+#ifdef CONFIG_FB_SUN3
|
|
+ volatile u32 *regs;
|
|
+#else
|
|
struct bw2_regs __iomem *regs;
|
|
-
|
|
+#endif
|
|
u32 flags;
|
|
#define BW2_FLAG_BLANKED 0x00000001
|
|
|
|
@@ -118,6 +147,7 @@ struct bw2_par {
|
|
unsigned long fbsize;
|
|
};
|
|
|
|
+#ifndef CONFIG_FB_SUN3
|
|
/**
|
|
* bw2_blank - Optional function. Blanks the display.
|
|
* @blank_mode: the blank mode we want.
|
|
@@ -156,6 +186,7 @@ bw2_blank(int blank, struct fb_info *inf
|
|
|
|
return 0;
|
|
}
|
|
+#endif
|
|
|
|
static struct sbus_mmap_map bw2_mmap_map[] = {
|
|
{
|
|
@@ -198,6 +229,17 @@ static void __devinit bw2_init_fix(struc
|
|
info->fix.accel = FB_ACCEL_SUN_BWTWO;
|
|
}
|
|
|
|
+struct all_info {
|
|
+ struct fb_info info;
|
|
+ struct bw2_par par;
|
|
+};
|
|
+/* CONFIG_FB_SUN3 has a different implementation for the remaining
|
|
+ functions, since:
|
|
+ 1) No OpenProm
|
|
+ 2) Fixed frequency
|
|
+ 3) No support for multiple BWtwo's */
|
|
+#ifndef CONFIG_FB_SUN3
|
|
+
|
|
static u8 bw2regs_1600[] __devinitdata = {
|
|
0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
|
|
0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
|
|
@@ -279,11 +321,6 @@ static void __devinit bw2_do_default_mod
|
|
}
|
|
}
|
|
|
|
-struct all_info {
|
|
- struct fb_info info;
|
|
- struct bw2_par par;
|
|
-};
|
|
-
|
|
static int __devinit bw2_init_one(struct of_device *op)
|
|
{
|
|
struct device_node *dp = op->node;
|
|
@@ -397,6 +434,185 @@ static void __exit bw2_exit(void)
|
|
return of_unregister_driver(&bw2_driver);
|
|
}
|
|
|
|
+#else /* !CONFIG_FB_SUN3 */
|
|
+
|
|
+static struct all_info *bw2_all = NULL;
|
|
+
|
|
+static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
|
|
+ int *linebytes)
|
|
+{
|
|
+ int highres = 0;
|
|
+
|
|
+ if(idprom->id_machtype == (SM_SUN3|SM_3_260))
|
|
+ /* the 3/260 is allegedly always highres */
|
|
+ highres = 1;
|
|
+ if(idprom->id_machtype == (SM_SUN3|SM_3_60)) {
|
|
+#ifdef CONFIG_SUN3
|
|
+ /* we won't hit this unless running on a sun3 anyway */
|
|
+ volatile u32 *reg;
|
|
+ u32 il
|
|
+
|
|
+ reg = sun3_ioremap(BW2_OBMEM_HIGHRES_60, sizeof(u32),
|
|
+ SUN3_PAGE_TYPE_MEMORY);
|
|
+ i = *reg;
|
|
+ iounmap(reg);
|
|
+ if((i != -1) && (i& 0x80) == 0)
|
|
+ highres = 1;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ if(highres) {
|
|
+ info->var.xres = info->var.xres_virtual = 1600;
|
|
+ info->var.yres = info->var.yres_virtual = 1280;
|
|
+ *linebytes = 1600 / 8;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static int __devinit bw2_init_one(unsigned long phys_addr)
|
|
+{
|
|
+ struct all_info *all;
|
|
+ int linebytes, err, id;
|
|
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
|
|
+ if (!all)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ spin_lock_init(&all->par.lock);
|
|
+
|
|
+ all->par.physbase = phys_addr;
|
|
+
|
|
+#ifdef CONFIG_SUN3
|
|
+ all->par.regs = sun3_ioremap(phys_addr, sizeof(u32),
|
|
+ SUN3_PAGE_TYPE_MEMORY);
|
|
+#else
|
|
+ all->par.regs = ioremap_nocache(phys_addr, sizeof(u32));
|
|
+#endif
|
|
+ /* look for the p4 register, or assume we're OBIO if it's not found */
|
|
+ id = p4fb_get_id(all->par.regs);
|
|
+ printk("bwtwo: p4id %08x\n", id);
|
|
+
|
|
+ /* mutable memory address, probably save to say we've got an onboard fb */
|
|
+ if(id == -1) {
|
|
+ iounmap((void *)all->par.regs);
|
|
+ /* only currently supported on sun3. Perhaps someday sun4. */
|
|
+ if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3) {
|
|
+ kfree(all);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ p4fb_fill_var(&all->info.var, NULL, 1);
|
|
+ bw2_do_default_mode(&all->par, &all->info, &linebytes);
|
|
+ } else {
|
|
+ if(id != P4_ID_BW2) {
|
|
+ kfree(all);
|
|
+ iounmap((void *)all->par.regs);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ p4fb_fill_var(&all->info.var, (volatile u32 *)all->par.regs, 1);
|
|
+ }
|
|
+
|
|
+ linebytes = all->info.var.xres / 8;
|
|
+
|
|
+ all->info.var.red.length = all->info.var.green.length =
|
|
+ all->info.var.blue.length = all->info.var.bits_per_pixel;
|
|
+ all->info.var.red.offset = all->info.var.green.offset =
|
|
+ all->info.var.blue.offset = 0;
|
|
+
|
|
+ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
|
|
+
|
|
+ all->info.flags = FBINFO_DEFAULT;
|
|
+ all->info.fbops = &bw2_ops;
|
|
+
|
|
+ if(id == -1) {
|
|
+#ifdef CONFIG_SUN3
|
|
+ all->info.screen_base = sun3_ioremap(phys_addr,
|
|
+ all->par.fbsize,
|
|
+ SUN3_PAGE_TYPE_MEMORY);
|
|
+#else
|
|
+ all->info.screen_base = ioremap(phys_addr,
|
|
+ all->par.fbsize);
|
|
+#endif
|
|
+ } else {
|
|
+#ifdef CONFIG_SUN3
|
|
+ all->info.screen_base = sun3_ioremap(phys_addr + BWTWO_FB_OFFSET,
|
|
+ all->par.fbsize,
|
|
+ SUN3_PAGE_TYPE_MEMORY);
|
|
+#else
|
|
+ all->info.screen_base = ioremap(phys_addr + BWTWO_FB_OFFSET,
|
|
+ all->par.fbsize);
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ p4fb_video_enable(all->par.regs);
|
|
+
|
|
+ all->info.par = &all->par;
|
|
+
|
|
+ bw2_init_fix(&all->info, linebytes);
|
|
+
|
|
+ err= register_framebuffer(&all->info);
|
|
+ if (err < 0) {
|
|
+ iounmap((void *)all->par.regs);
|
|
+ iounmap((void *)all->info.screen_base);
|
|
+ kfree(all);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ bw2_all = all;
|
|
+
|
|
+ printk("%s: bwtwo at %lx\n",
|
|
+ all->info.fix.id, all->par.physbase);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __init bw2_init(void)
|
|
+{
|
|
+ if(fb_get_options("bw2fb", NULL))
|
|
+ return -ENODEV;
|
|
+
|
|
+ if(bw2_all != NULL)
|
|
+ return -ENODEV;
|
|
+
|
|
+ /* currently only sun3/80 P4 is supported/tested */
|
|
+ switch(idprom->id_machtype) {
|
|
+ case SM_SUN3X|SM_3_80:
|
|
+ case SM_SUN3X|SM_3_460:
|
|
+ return bw2_init_one(BWTWO_OBMEM_ADDR_3X);
|
|
+
|
|
+ case SM_SUN3|SM_3_50:
|
|
+ return bw2_init_one(BWTWO_OBMEM_ADDR_50);
|
|
+
|
|
+ case SM_SUN3|SM_3_160:
|
|
+ case SM_SUN3|SM_3_260:
|
|
+ case SM_SUN3|SM_3_110:
|
|
+ case SM_SUN3|SM_3_60:
|
|
+ return bw2_init_one(BWTWO_OBMEM_ADDR);
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return -ENODEV;
|
|
+}
|
|
+
|
|
+static void __exit bw2_exit(void)
|
|
+{
|
|
+ struct all_info *all = bw2_all;
|
|
+ if(bw2_all == NULL)
|
|
+ return;
|
|
+
|
|
+ unregister_framebuffer(&all->info);
|
|
+
|
|
+ iounmap((void *)all->par.regs);
|
|
+ iounmap((void *)all->info.screen_base);
|
|
+
|
|
+ kfree(all);
|
|
+
|
|
+ bw2_all = NULL;
|
|
+
|
|
+ return;
|
|
+}
|
|
+#endif /* CONFIG_FB_SUN3 */
|
|
|
|
module_init(bw2_init);
|
|
module_exit(bw2_exit);
|
|
--- linux-m68k-2.6.21.orig/drivers/video/cg3.c
|
|
+++ linux-m68k-2.6.21/drivers/video/cg3.c
|
|
@@ -20,12 +20,24 @@
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/oplib.h>
|
|
+#ifndef CONFIG_FB_SUN3
|
|
#include <asm/prom.h>
|
|
#include <asm/of_device.h>
|
|
+#endif
|
|
#include <asm/fbio.h>
|
|
|
|
#include "sbuslib.h"
|
|
|
|
+#ifdef CONFIG_FB_SUN3
|
|
+#ifdef CONFIG_SUN3
|
|
+#include <asm/sun3mmu.h>
|
|
+#endif
|
|
+#include <asm/machines.h>
|
|
+#include <asm/idprom.h>
|
|
+#include <asm/sbus.h>
|
|
+#include "p4lib.h"
|
|
+#endif
|
|
+
|
|
/*
|
|
* Local functions.
|
|
*/
|
|
@@ -108,8 +120,16 @@ struct cg3_regs {
|
|
};
|
|
|
|
/* Offset of interesting structures in the OBIO space */
|
|
-#define CG3_REGS_OFFSET 0x400000UL
|
|
-#define CG3_RAM_OFFSET 0x800000UL
|
|
+#ifdef CONFIG_SUN3
|
|
+#define CGFOUR_OBMEM_ADDR_60 0x1f000000
|
|
+#define CGFOUR_OBMEM_ADDR_110 0x1f300000
|
|
+#define CG3_REGS_OFFSET (-0x100000)
|
|
+#define CG3_RAM_OFFSET 0x500000UL
|
|
+#else
|
|
+#define CG3_REGS_OFFSET 0x400000UL
|
|
+#define CG3_RAM_OFFSET 0x800000UL
|
|
+#endif
|
|
+
|
|
|
|
struct cg3_par {
|
|
spinlock_t lock;
|
|
@@ -250,6 +270,18 @@ static int cg3_ioctl(struct fb_info *inf
|
|
* Initialisation
|
|
*/
|
|
|
|
+struct all_info {
|
|
+ struct fb_info info;
|
|
+ struct cg3_par par;
|
|
+};
|
|
+
|
|
+
|
|
+/* CONFIG_FB_SUN3 has a different implementation for the remaining
|
|
+ functions, since:
|
|
+ 1) No OpenProm
|
|
+ 2) Fixed frequency
|
|
+ 3) No support for multiple CGthree's */
|
|
+#ifndef CONFIG_FB_SUN3
|
|
static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
|
|
struct device_node *dp)
|
|
{
|
|
@@ -351,12 +383,8 @@ static void __devinit cg3_do_default_mod
|
|
regp = (u8 __iomem *)&par->regs->cmap.control;
|
|
sbus_writeb(p[1], regp);
|
|
}
|
|
-}
|
|
|
|
-struct all_info {
|
|
- struct fb_info info;
|
|
- struct cg3_par par;
|
|
-};
|
|
+}
|
|
|
|
static int __devinit cg3_init_one(struct of_device *op)
|
|
{
|
|
@@ -426,8 +454,8 @@ static int __devinit cg3_init_one(struct
|
|
|
|
dev_set_drvdata(&op->dev, all);
|
|
|
|
- printk("%s: cg3 at %lx:%lx\n",
|
|
- dp->full_name, all->par.which_io, all->par.physbase);
|
|
+ printk("%s: cg3 at %lx\n",
|
|
+ dp->full_name, all->par.physbase);
|
|
|
|
return 0;
|
|
}
|
|
@@ -488,6 +516,172 @@ static void __exit cg3_exit(void)
|
|
of_unregister_driver(&cg3_driver);
|
|
}
|
|
|
|
+#else /* !CONFIG_FB_SUN3 */
|
|
+static void
|
|
+cg3_init_fix(struct fb_info *info, int linebytes)
|
|
+{
|
|
+
|
|
+ strcpy(info->fix.id, "SUN3 CG3");
|
|
+
|
|
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
|
|
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
|
|
+
|
|
+ info->fix.line_length = linebytes;
|
|
+
|
|
+ info->fix.accel = FB_ACCEL_SUN_CGTHREE;
|
|
+}
|
|
+static void cg3_do_default_mode(struct cg3_par *par)
|
|
+{
|
|
+ /* kick up the sun3 -- 66hz prom mode only */
|
|
+ /* this also turns off the overlay in case it's really a cg4 */
|
|
+
|
|
+ par->regs->cmap.addr = 4;
|
|
+ par->regs->cmap.control = 0xff;
|
|
+ par->regs->cmap.addr = 5;
|
|
+ par->regs->cmap.control = 0;
|
|
+ par->regs->cmap.addr = 6;
|
|
+ par->regs->cmap.control = 0x40;
|
|
+ par->regs->cmap.addr = 7;
|
|
+ par->regs->cmap.control = 0;
|
|
+
|
|
+}
|
|
+
|
|
+/* The Sun3 version of this driver only supports one cgthree.
|
|
+ This really isn't an issue, because it also only supports
|
|
+ the 3/60 OBIO cg3, and not vme cards (of which there could be more
|
|
+ than one) */
|
|
+static struct all_info *cg3_all = NULL;
|
|
+
|
|
+static int __devinit cg3_init_one(unsigned long phys_addr)
|
|
+{
|
|
+ struct all_info *all;
|
|
+ int linebytes, err;
|
|
+ volatile u32 *p4reg = NULL;
|
|
+
|
|
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
|
|
+ if (!all)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ spin_lock_init(&all->par.lock);
|
|
+
|
|
+ all->par.physbase = phys_addr;
|
|
+
|
|
+#if 0
|
|
+ /* it would be nice to use p4 registers here, but it appears
|
|
+ * some P4 framebuffers don't actually have useful data.
|
|
+ * So we just plod along regardless */
|
|
+ p4reg = sun3_ioremap(all->par.physbase, sizeof(u32),
|
|
+ SUN3_PAGE_TYPE_MEMORY);
|
|
+ id = p4fb_get_id(p4reg);
|
|
+ printk("cg3: p4id %08x\n", *p4reg);
|
|
+
|
|
+ if(id != P4_ID_CG4) {
|
|
+ iounmap((void *)p4reg);
|
|
+ kfree(all);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+#endif
|
|
+ p4fb_fill_var(&all->info.var, p4reg, 8);
|
|
+ if(p4reg != NULL)
|
|
+ iounmap((void *)p4reg);
|
|
+
|
|
+ all->info.var.red.length = 8;
|
|
+ all->info.var.green.length = 8;
|
|
+ all->info.var.blue.length = 8;
|
|
+ linebytes = all->info.var.xres;
|
|
+
|
|
+ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
|
|
+
|
|
+ all->par.regs = (struct cg3_regs *)
|
|
+ sun3_ioremap(all->par.physbase + CG3_REGS_OFFSET,
|
|
+ sizeof(struct cg3_regs), SUN3_PAGE_TYPE_MEMORY);
|
|
+
|
|
+
|
|
+ all->info.flags = FBINFO_DEFAULT;
|
|
+ all->info.fbops = &cg3_ops;
|
|
+ all->info.screen_base = (char *)
|
|
+ sun3_ioremap(all->par.physbase + CG3_RAM_OFFSET,
|
|
+ all->par.fbsize, SUN3_PAGE_TYPE_MEMORY);
|
|
+ all->info.par = &all->par;
|
|
+
|
|
+ cg3_blank(0, &all->info);
|
|
+
|
|
+ cg3_do_default_mode(&all->par);
|
|
+
|
|
+ if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
|
|
+ kfree(all);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ fb_set_cmap(&all->info.cmap, &all->info);
|
|
+
|
|
+ cg3_init_fix(&all->info, linebytes);
|
|
+
|
|
+ err = register_framebuffer(&all->info);
|
|
+ if (err < 0) {
|
|
+ fb_dealloc_cmap(&all->info.cmap);
|
|
+ iounmap(all->par.regs);
|
|
+ iounmap(all->info.screen_base);
|
|
+ kfree(all);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ cg3_all = all;
|
|
+
|
|
+ printk("%s: cg3 at %lx\n",
|
|
+ all->info.fix.id, all->par.physbase);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __init cg3_init(void)
|
|
+{
|
|
+ if (fb_get_options("cg3fb", NULL))
|
|
+ return -ENODEV;
|
|
+
|
|
+ if(cg3_all != NULL)
|
|
+ return -ENODEV;
|
|
+
|
|
+ /* currently only sun3/60 P4 is supported/tested */
|
|
+ switch(idprom->id_machtype) {
|
|
+ case SM_SUN3|SM_3_60:
|
|
+ return cg3_init_one(CGFOUR_OBMEM_ADDR_60);
|
|
+
|
|
+ case SM_SUN3|SM_3_110:
|
|
+ /* 3/110 is a guess, no 3/110 to test on */
|
|
+ return cg3_init_one(CGFOUR_OBMEM_ADDR_110);
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return -ENODEV;
|
|
+}
|
|
+
|
|
+static void __exit cg3_exit(void)
|
|
+{
|
|
+ struct all_info *all = cg3_all;
|
|
+
|
|
+ if(cg3_all == NULL)
|
|
+ return;
|
|
+
|
|
+ unregister_framebuffer(&all->info);
|
|
+ fb_dealloc_cmap(&all->info.cmap);
|
|
+
|
|
+ iounmap(all->par.regs);
|
|
+ iounmap(all->info.screen_base);
|
|
+
|
|
+ kfree(all);
|
|
+
|
|
+ cg3_all = NULL;
|
|
+
|
|
+ return;
|
|
+
|
|
+}
|
|
+
|
|
+#endif /* CONFIG_FB_SUN3 */
|
|
+
|
|
module_init(cg3_init);
|
|
module_exit(cg3_exit);
|
|
|
|
--- /dev/null
|
|
+++ linux-m68k-2.6.21/drivers/video/p4lib.c
|
|
@@ -0,0 +1,107 @@
|
|
+/* p4lib.c: Helper library for Sun P4 framebuffer drivers
|
|
+ *
|
|
+ * Copyright (C) 2007 Sam Creasey (sammy@sammy.net)
|
|
+ */
|
|
+
|
|
+#include <linux/compat.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/types.h>
|
|
+
|
|
+#include <linux/fb.h>
|
|
+
|
|
+#include "p4lib.h"
|
|
+
|
|
+int p4fb_get_id(volatile u32 *p4reg)
|
|
+{
|
|
+
|
|
+#ifdef CONFIG_SUN3
|
|
+ /* this code makes the 3x cry, and it can't have onboard fb anyway */
|
|
+ u32 x, old;
|
|
+
|
|
+ /* attempt to read the id bit back from the p4 register, if
|
|
+ * we're able to modify the value, conclude there's no p4
|
|
+ * device there. This should enable us to determine if we're
|
|
+ * dealing with, for example, a builtin bw2 or a p4 bw2. */
|
|
+
|
|
+ old = *p4reg;
|
|
+ x = old & ~P4_CTRL_RESET;
|
|
+
|
|
+ *p4reg = x ^ P4_ID_MASK;
|
|
+ if((*p4reg ^ x) & P4_ID_MASK) {
|
|
+ /* we managed to change the type bits, not a p4 port */
|
|
+ *p4reg = old;
|
|
+ return -1;
|
|
+ }
|
|
+#endif
|
|
+ return ((*p4reg) & P4_ID_MASK) >> P4_ID_SHIFT;
|
|
+}
|
|
+
|
|
+int p4fb_get_res(volatile u32 *p4reg)
|
|
+{
|
|
+ return ((*p4reg) & P4_RES_MASK) >> P4_RES_SHIFT;
|
|
+}
|
|
+
|
|
+void p4fb_video_enable(volatile u32 *p4reg)
|
|
+{
|
|
+ u32 x;
|
|
+
|
|
+ x = *p4reg;
|
|
+ x &= ~(P4_CTRL_VIDEO_EN | P4_CTRL_INT);
|
|
+ x |= P4_CTRL_VIDEO_EN;
|
|
+ *p4reg = x;
|
|
+
|
|
+}
|
|
+
|
|
+/* This function basically assumes that p4fb_get_id returns a sane
|
|
+ * value for this card/instance. If this was not true, calling with
|
|
+ * NULL for p4reg will return the defaults */
|
|
+void p4fb_fill_var(struct fb_var_screeninfo *var, volatile u32 *p4reg, int bpp)
|
|
+{
|
|
+ memset(var, 0, sizeof(*var));
|
|
+
|
|
+ if(p4reg == NULL) {
|
|
+ var->xres = 1152;
|
|
+ var->yres = 900;
|
|
+ } else {
|
|
+ switch(p4fb_get_res(p4reg)) {
|
|
+ case P4_RES_1600X1280:
|
|
+ var->xres = 1600;
|
|
+ var->yres = 1280;
|
|
+ break;
|
|
+ case P4_RES_1152X900:
|
|
+ var->xres = 1152;
|
|
+ var->yres = 900;
|
|
+ break;
|
|
+ case P4_RES_1024X1024:
|
|
+ var->xres = 1024;
|
|
+ var->yres = 1024;
|
|
+ break;
|
|
+ case P4_RES_1280X1024:
|
|
+ var->xres = 1280;
|
|
+ var->yres = 1024;
|
|
+ break;
|
|
+ case P4_RES_1440X1440:
|
|
+ var->xres = 1440;
|
|
+ var->yres = 1400;
|
|
+ break;
|
|
+ case P4_RES_640X480:
|
|
+ var->xres = 640;
|
|
+ var->yres = 480;
|
|
+ break;
|
|
+ default:
|
|
+ /* this may or may not be the right thing to
|
|
+ * do here, but plod on anyway */
|
|
+ var->xres = 1152;
|
|
+ var->yres = 900;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ var->xres_virtual = var->xres;
|
|
+ var->yres_virtual = var->yres;
|
|
+ var->bits_per_pixel = bpp;
|
|
+}
|
|
+
|
|
+EXPORT_SYMBOL(p4fb_get_id);
|
|
+EXPORT_SYMBOL(p4fb_get_res);
|
|
+EXPORT_SYMBOL(p4fb_fill_var);
|
|
--- /dev/null
|
|
+++ linux-m68k-2.6.21/drivers/video/p4lib.h
|
|
@@ -0,0 +1,56 @@
|
|
+/* p4lib.h: helper functions for p4 framebuffers */
|
|
+
|
|
+#ifndef _P4LIB_H
|
|
+#define _P4LIB_H
|
|
+
|
|
+/* register defintions applicable to p4 framebuffers found on some
|
|
+ Sun3/3x machines (and some Sun4 machines, though these are not
|
|
+ currently supported or tested). These machines have a single 32bit
|
|
+ register at the start of the p4 address space.
|
|
+
|
|
+ The format of this register is as follows:
|
|
+
|
|
+ bit 31 : unused
|
|
+ bits 30-28: type
|
|
+ bits 27-24: resolution
|
|
+ bits 23-8: unused
|
|
+ bits 7-0: status/control
|
|
+
|
|
+ The CG8 may break this format, if that turns out to be true, I'll
|
|
+ fix once I have a CG8 to test against...
|
|
+*/
|
|
+
|
|
+/* control register, lower 8bits */
|
|
+#define P4_CTRL_DIAG 0x80 /* ??? */
|
|
+#define P4_CTRL_RBCLR 0x40 /* ??? */
|
|
+#define P4_CTRL_VIDEO_EN 0x20 /* enable video */
|
|
+#define P4_CTRL_SYNC 0x10 /* ??? */
|
|
+#define P4_CTRL_VTRACE 0x08 /* ??? */
|
|
+#define P4_CTRL_INT 0x04 /* read: int pending, write: clear int */
|
|
+#define P4_CTRL_INT_EN 0x02 /* enable interrupts */
|
|
+#define P4_CTRL_RESET 0x01 /* reset */
|
|
+
|
|
+/* framebuffer identification -- bits 31-28 */
|
|
+#define P4_ID_MASK 0x70000000
|
|
+#define P4_ID_SHIFT 24
|
|
+#define P4_ID_BW2 0x00
|
|
+#define P4_ID_CG4 0x40 /* supported in linux as a cg3 */
|
|
+#define P4_ID_CG6 0x60
|
|
+
|
|
+/* framebuffer resolution - bits 27-24 */
|
|
+#define P4_RES_MASK 0x0f000000
|
|
+#define P4_RES_SHIFT 24
|
|
+#define P4_RES_1600X1280 0x00
|
|
+#define P4_RES_1152X900 0x01 /* only tested resolution */
|
|
+#define P4_RES_1024X1024 0x02
|
|
+#define P4_RES_1280X1024 0x03
|
|
+#define P4_RES_1440X1440 0x04
|
|
+#define P4_RES_640X480 0x05
|
|
+
|
|
+/* actual helper functions */
|
|
+extern int p4fb_get_id(volatile u32 *p4reg);
|
|
+extern int p4fb_get_res(volatile u32 *p4reg);
|
|
+extern void p4fb_video_enable(volatile u32 *p4reg);
|
|
+extern void p4fb_fill_var(struct fb_var_screeninfo *var, volatile u32 *p4reg, int bpp);
|
|
+
|
|
+#endif /* P4LIB_H */
|
|
--- linux-m68k-2.6.21.orig/drivers/video/sbuslib.c
|
|
+++ linux-m68k-2.6.21/drivers/video/sbuslib.c
|
|
@@ -13,6 +13,10 @@
|
|
#include <asm/oplib.h>
|
|
#include <asm/fbio.h>
|
|
|
|
+#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
|
|
+#include <asm/uaccess.h>
|
|
+#endif
|
|
+
|
|
#include "sbuslib.h"
|
|
|
|
void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp)
|
|
@@ -21,6 +25,7 @@ void sbusfb_fill_var(struct fb_var_scree
|
|
|
|
var->xres = prom_getintdefault(prom_node, "width", 1152);
|
|
var->yres = prom_getintdefault(prom_node, "height", 900);
|
|
+
|
|
var->xres_virtual = var->xres;
|
|
var->yres_virtual = var->yres;
|
|
var->bits_per_pixel = bpp;
|
|
@@ -80,12 +85,20 @@ int sbusfb_mmap_helper(struct sbus_mmap_
|
|
}
|
|
if (page + map_size > size)
|
|
map_size = size - page;
|
|
+#if !defined(CONFIG_FB_SUN3)
|
|
r = io_remap_pfn_range(vma,
|
|
vma->vm_start + page,
|
|
MK_IOSPACE_PFN(iospace,
|
|
map_offset >> PAGE_SHIFT),
|
|
map_size,
|
|
vma->vm_page_prot);
|
|
+#else
|
|
+ r = io_remap_pfn_range(vma,
|
|
+ vma->vm_start + page,
|
|
+ map_offset, map_size,
|
|
+ vma->vm_page_prot);
|
|
+#endif
|
|
+
|
|
if (r)
|
|
return -EAGAIN;
|
|
page += map_size;
|