From: Maciej W. Rozycki (macro@ds2.pg.gda.pl)
Date: Wed Aug 13 2003 - 13:51:57 CEST
On Tue, 12 Aug 2003, Maciej W. Rozycki wrote:
> > Anyway, the AA driver is appended as a diff against current linux-mips
> > CVS. I hope it doesn't deviate too much from whatever fbdev uses.
>
> Hmm, I can only see PMAG-A-specific changes here -- does it mean the
> driver now works as is with no changes to the generic fb code? If that is
> the case, I'll apply the patch to the MIPS CVS right now.
>
> One point to note -- iob() is a heavyweight barrier implying immediate
> draining of buffers. I don't think it's really needed here as the driver
> only needs to enforce ordering. Hence I'd change iob() to wmb() or mb()
> as appropriate and add a few missing rmb() calls. I can do that when
> applying the patch or please prepare an update.
I've looked at the patch and have changed the barriers as I deem
appropriate. But while doing this, I've noticed the code is insonsistent
in a few places -- has it been successfully verified on real hardware?
Here is an updated version. Martin, can you check it with your MX?
Maciej
-- + Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: macro@ds2.pg.gda.pl, PGP key available + patch-mips-2.4.21-20030811-mx-0 diff -up --recursive --new-file linux-mips-2.4.21-20030811.macro/Documentation/Configure.help linux-mips-2.4.21-20030811/Documentation/Configure.help --- linux-mips-2.4.21-20030811.macro/Documentation/Configure.help 2003-07-15 02:57:01.000000000 +0000 +++ linux-mips-2.4.21-20030811/Documentation/Configure.help 2003-08-12 22:36:16.000000000 +0000 @@ -4604,6 +4604,11 @@ CONFIG_FB_MAXINE DECstation series (Personal DECstation 5000/20, /25, /33, /50, Codename "Maxine"). +PMAG-AA TURBOchannel framebuffer support +CONFIG_FB_PMAG_AA + Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1) + used mainly in the MIPS-based DECstation series. + PMAG-BA TURBOchannel framebuffer support CONFIG_FB_PMAG_BA Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8) diff -up --recursive --new-file linux-mips-2.4.21-20030811.macro/drivers/video/Config.in linux-mips-2.4.21-20030811/drivers/video/Config.in --- linux-mips-2.4.21-20030811.macro/drivers/video/Config.in 2003-07-06 03:00:56.000000000 +0000 +++ linux-mips-2.4.21-20030811/drivers/video/Config.in 2003-08-12 20:55:11.000000000 +0000 @@ -218,6 +218,7 @@ if [ "$CONFIG_FB" = "y" ]; then tristate ' HD64461 Frame Buffer support' CONFIG_FB_HIT fi if [ "$CONFIG_DECSTATION" = "y" ]; then + dep_bool ' PMAG-AA TURBOchannel framebuffer support' CONFIG_FB_PMAG_AA $CONFIG_TC dep_bool ' PMAG-BA TURBOchannel framebuffer support' CONFIG_FB_PMAG_BA $CONFIG_TC dep_bool ' PMAGB-B TURBOchannel framebuffer support' CONFIG_FB_PMAGB_B $CONFIG_TC dep_bool ' Maxine (Personal DECstation) onboard framebuffer support' CONFIG_FB_MAXINE $CONFIG_TC @@ -297,7 +298,8 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \ - "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \ + "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_PMAG_AA" = "y" -o \ + "$CONFIG_FB_TX3912" = "y" -o \ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \ "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \ "$CONFIG_FB_INTEL" = "y" ]; then diff -up --recursive --new-file linux-mips-2.4.21-20030811.macro/drivers/video/Makefile linux-mips-2.4.21-20030811/drivers/video/Makefile --- linux-mips-2.4.21-20030811.macro/drivers/video/Makefile 2003-07-06 03:00:56.000000000 +0000 +++ linux-mips-2.4.21-20030811/drivers/video/Makefile 2003-08-12 20:55:11.000000000 +0000 @@ -81,6 +81,7 @@ obj-$(CONFIG_FB_TCX) += tcx obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o +obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o diff -up --recursive --new-file linux-mips-2.4.21-20030811.macro/drivers/video/bt431.h linux-mips-2.4.21-20030811/drivers/video/bt431.h --- linux-mips-2.4.21-20030811.macro/drivers/video/bt431.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-mips-2.4.21-20030811/drivers/video/bt431.h 2003-08-12 22:02:13.000000000 +0000 @@ -0,0 +1,229 @@ +/* + * linux/drivers/video/bt431.h + * + * Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ +#include <linux/types.h> +#include <asm/system.h> + +/* + * Bt431 cursor generator registers, 32-bit aligned. + * Two twin Bt431 are used on the DECstation's PMAG-AA. + */ +struct bt431_regs { + volatile u16 addr_lo; + u16 pad0; + volatile u16 addr_hi; + u16 pad1; + volatile u16 addr_cmap; + u16 pad2; + volatile u16 addr_reg; + u16 pad3; +}; + +static inline u16 bt431_set_value(u8 val) +{ + return ((val << 8) | (val & 0xff)) & 0xffff; +} + +static inline u8 bt431_get_value(u16 val) +{ + return val & 0xff; +} + +/* + * Additional registers addressed indirectly. + */ +#define BT431_REG_CMD 0x0000 +#define BT431_REG_CXLO 0x0001 +#define BT431_REG_CXHI 0x0002 +#define BT431_REG_CYLO 0x0003 +#define BT431_REG_CYHI 0x0004 +#define BT431_REG_WXLO 0x0005 +#define BT431_REG_WXHI 0x0006 +#define BT431_REG_WYLO 0x0007 +#define BT431_REG_WYHI 0x0008 +#define BT431_REG_WWLO 0x0009 +#define BT431_REG_WWHI 0x000a +#define BT431_REG_WHLO 0x000b +#define BT431_REG_WHHI 0x000c + +#define BT431_REG_CRAM_BASE 0x0000 +#define BT431_REG_CRAM_END 0x01ff + +/* + * Command register. + */ +#define BT431_CMD_CURS_ENABLE 0x40 +#define BT431_CMD_XHAIR_ENABLE 0x20 +#define BT431_CMD_OR_CURSORS 0x10 +#define BT431_CMD_AND_CURSORS 0x00 +#define BT431_CMD_1_1_MUX 0x00 +#define BT431_CMD_4_1_MUX 0x04 +#define BT431_CMD_5_1_MUX 0x08 +#define BT431_CMD_xxx_MUX 0x0c +#define BT431_CMD_THICK_1 0x00 +#define BT431_CMD_THICK_3 0x01 +#define BT431_CMD_THICK_5 0x02 +#define BT431_CMD_THICK_7 0x03 + +static inline void bt431_select_reg(struct bt431_regs *regs, int ir) +{ + mb(); + regs->addr_lo = bt431_set_value(ir & 0xff); + regs->addr_hi = bt431_set_value((ir >> 8) & 0xff); +} + +/* Autoincrement read/write. */ +static inline u8 bt431_read_reg_inc(struct bt431_regs *regs) +{ + mb(); + return bt431_get_value(regs->addr_reg); +} + +static inline void bt431_write_reg_inc(struct bt431_regs *regs, u8 value) +{ + mb(); + regs->addr_reg = bt431_set_value(value); +} + +static inline u8 bt431_read_reg(struct bt431_regs *regs, int ir) +{ + bt431_select_reg(regs, ir); + return bt431_read_reg_inc(regs); +} + +static inline void bt431_write_reg(struct bt431_regs *regs, int ir, u16 value) +{ + bt431_select_reg(regs, ir); + bt431_write_reg_inc(regs, value); +} + +/* Autoincremented read/write for the cursor map */ +static inline u16 bt431_read_cmap_inc(struct bt431_regs *regs) +{ + mb(); + return regs->addr_cmap; +} + +static inline void bt431_write_cmap_inc(struct bt431_regs *regs, u16 value) +{ + mb(); + regs->addr_cmap = value; +} + +static inline u16 bt431_read_cmap(struct bt431_regs *regs, int cr) +{ + bt431_select_reg(regs, cr); + return bt431_read_cmap_inc(regs); +} + +static inline void bt431_write_cmap(struct bt431_regs *regs, int cr, u16 value) +{ + bt431_select_reg(regs, cr); + bt431_write_cmap_inc(regs, value); +} + +static inline void bt431_enable_cursor(struct bt431_regs *regs) +{ +/* bt431_write_reg(regs, BT431_REG_CMD, + BT431_CMD_CURS_ENABLE | BT431_CMD_OR_CURSORS + | BT431_CMD_4_1_MUX | BT431_CMD_THICK_1); +*/ bt431_write_reg(regs, BT431_REG_CMD, BT431_CMD_CURS_ENABLE); +} + +static inline void bt431_erase_cursor(struct bt431_regs *regs) +{ + bt431_write_reg(regs, BT431_REG_CMD, BT431_CMD_4_1_MUX); +} + +static inline void bt431_position_cursor(struct bt431_regs *regs, u16 x, u16 y) +{ + /* + * Magic from the MACH sources. + * + * Cx = x + D + H - P + * P = 37 if 1:1, 52 if 4:1, 57 if 5:1 + * D = pixel skew between outdata and external data + * H = pixels between HSYNCH falling and active video + * + * Cy = y + V - 32 + * V = scanlines between HSYNCH falling, two or more + * clocks after VSYNCH falling, and active video + */ + x += 412 - 52; + y += 68 - 32; + + /* Use autoincrement. */ + bt431_select_reg(regs, BT431_REG_CXLO); + bt431_write_reg_inc(regs, x & 0xff); /* BT431_REG_CXLO */ + bt431_write_reg_inc(regs, (x >> 8) & 0x0f); /* BT431_REG_CXHI */ + bt431_write_reg_inc(regs, y & 0xff); /* BT431_REG_CYLO */ + bt431_write_reg_inc(regs, (y >> 8) & 0x0f); /* BT431_REG_CYHI */ +} + +/*u16 _bt431_default_cursor[64 * 8] = { + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0, +}; +*/ +static inline void bt431_load_cursor_sprite(struct bt431_regs *regs) +{ + int i; + + bt431_select_reg(regs, BT431_REG_CRAM_BASE); + for (i = 0; i < 64 * 8; i++) + bt431_write_cmap_inc(regs, ((i < 16 * 8) && (i % 8)) ? 0xffff : 0); +} + +static inline void bt431_init_cursor(struct bt431_regs *regs) +{ + bt431_write_reg(regs, BT431_REG_CMD, + BT431_CMD_CURS_ENABLE | BT431_CMD_OR_CURSORS + | BT431_CMD_4_1_MUX | BT431_CMD_THICK_1); + + /* home cursor */ +#if 0 + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_CXLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_CXHI */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_CYLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_CYHI */ +#endif + bt431_write_reg_inc(regs, 0x80); /* BT431_REG_CXLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_CXHI */ + bt431_write_reg_inc(regs, 0x80); /* BT431_REG_CYLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_CYHI */ + + /* no crosshair window */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXHI */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYHI */ +// bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWLO */ + bt431_write_reg_inc(regs, 0x01); /* BT431_REG_WWLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWHI */ +// bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHLO */ + bt431_write_reg_inc(regs, 0x01); /* BT431_REG_WHLO */ + bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHHI */ + + bt431_load_cursor_sprite(regs); +} diff -up --recursive --new-file linux-mips-2.4.21-20030811.macro/drivers/video/bt455.h linux-mips-2.4.21-20030811/drivers/video/bt455.h --- linux-mips-2.4.21-20030811.macro/drivers/video/bt455.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-mips-2.4.21-20030811/drivers/video/bt455.h 2003-08-12 22:33:55.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * linux/drivers/video/bt455.h + * + * Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ +#include <linux/types.h> +#include <asm/system.h> + +/* + * Bt455 byte-wide registers, 32-bit aligned. + */ +struct bt455_regs { + volatile u8 addr_cmap; + u8 pad0[3]; + volatile u8 addr_cmap_data; + u8 pad1[3]; + volatile u8 addr_clr; + u8 pad2[3]; + volatile u8 addr_ovly; + u8 pad3[3]; +}; + +static inline void bt455_select_reg(struct bt455_regs *regs, int ir) +{ + mb(); + regs->addr_cmap = ir & 0x0f; +} + +/* + * Read/write to a Bt455 color map register. + */ +static inline void bt455_read_cmap_entry(struct bt455_regs *regs, int cr, + u8* red, u8* green, u8* blue) +{ + bt455_select_reg(regs, cr); + + mb(); + *red = regs->addr_cmap_data & 0x0f; + rmb(); + *green = regs->addr_cmap_data & 0x0f; + rmb(); + *blue = regs->addr_cmap_data & 0x0f; +} + +static inline void bt455_write_cmap_entry(struct bt455_regs *regs, int cr, + u8 red, u8 green, u8 blue) +{ + bt455_select_reg(regs, cr); + + wmb(); + regs->addr_cmap_data = red & 0x0f; + wmb(); + regs->addr_cmap_data = green & 0x0f; + wmb(); + regs->addr_cmap_data = blue & 0x0f; +} + +static inline void bt455_write_ovly_entry(struct bt455_regs *regs, + u8 red, u8 green, u8 blue) +{ + mb(); + regs->addr_ovly = red & 0x0f; + wmb(); + regs->addr_ovly = green & 0x0f; + wmb(); + regs->addr_ovly = blue & 0x0f; +} + +static inline void bt455_set_cursor(struct bt455_regs *regs) +{ + mb(); + regs->addr_ovly = 0x0f; + wmb(); + regs->addr_ovly = 0x0f; + wmb(); + regs->addr_ovly = 0x0f; +} + +static inline void bt455_erase_cursor(struct bt455_regs *regs) +{ +// bt455_write_cmap_entry(regs, 8, 0x00, 0x00, 0x00); +// bt455_write_cmap_entry(regs, 9, 0x00, 0x00, 0x00); + bt455_write_cmap_entry(regs, 8, 0x03, 0x03, 0x03); + bt455_write_cmap_entry(regs, 9, 0x07, 0x07, 0x07); + + bt455_write_ovly_entry(regs, 0x09, 0x09, 0x09); +} diff -up --recursive --new-file linux-mips-2.4.21-20030811.macro/drivers/video/fbmem.c linux-mips-2.4.21-20030811/drivers/video/fbmem.c --- linux-mips-2.4.21-20030811.macro/drivers/video/fbmem.c 2003-07-06 03:00:57.000000000 +0000 +++ linux-mips-2.4.21-20030811/drivers/video/fbmem.c 2003-08-12 20:55:11.000000000 +0000 @@ -124,9 +124,10 @@ extern int sisfb_init(void); extern int sisfb_setup(char*); extern int stifb_init(void); extern int stifb_setup(char*); +extern int pmagaafb_init(void); extern int pmagbafb_init(void); extern int pmagbbfb_init(void); -extern void maxinefb_init(void); +extern int maxinefb_init(void); extern int tx3912fb_init(void); extern int radeonfb_init(void); extern int radeonfb_setup(char*); @@ -313,6 +314,9 @@ static struct { #ifdef CONFIG_FB_PVR2 { "pvr2", pvr2fb_init, pvr2fb_setup }, #endif +#ifdef CONFIG_FB_PMAG_AA + { "pmagaafb", pmagaafb_init, NULL }, +#endif #ifdef CONFIG_FB_PMAG_BA { "pmagbafb", pmagbafb_init, NULL }, #endif diff -up --recursive --new-file linux-mips-2.4.21-20030811.macro/drivers/video/pmag-aa-fb.c linux-mips-2.4.21-20030811/drivers/video/pmag-aa-fb.c --- linux-mips-2.4.21-20030811.macro/drivers/video/pmag-aa-fb.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-mips-2.4.21-20030811/drivers/video/pmag-aa-fb.c 2003-08-12 21:01:56.000000000 +0000 @@ -0,0 +1,339 @@ +/* + * linux/drivers/video/pmag-aa-fb.c + * Copyright 2002 Karsten Merker <merker@debian.org> + * + * PMAG-AA TurboChannel framebuffer card support ... derived from + * pmag-ba-fb.c, which is Copyright (C) 1999, 2000, 2001 by + * Michael Engel <engel@unix-ag.org>, Karsten Merker <merker@debian.org> + * and Harald Koerfgen <hkoerfg@web.de>, which itself is derived from + * "HP300 Topcat framebuffer support (derived from macfb of all things) + * Phil Blundell <philb@gnu.org> 1998" + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Version 0.01 2002/09/28 first try to get a PMAG-AA running + * + * 2003/02/24 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * Code cleanup. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/fb.h> + +#include <asm/bootinfo.h> +#include <asm/dec/machtype.h> +#include <asm/dec/tc.h> + +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb8.h> + +#include "bt455.h" +#include "bt431.h" + +/* Version information */ +#define DRIVER_VERSION "v0.02" +#define DRIVER_AUTHOR "Karsten Merker <merker@linuxtag.org>" +#define DRIVER_DESC "PMAG-AA Framebuffer Driver" + +/* + * Bt455 RAM DAC register base offset (rel. to TC slot base address). + */ +#define PMAG_AA_BT455_OFFSET 0x100000 + +/* + * Bt431 cursor generator offset (rel. to TC slot base address). + */ +#define PMAG_AA_BT431_OFFSET 0x180000 + +/* + * Begin of PMAG-AA framebuffer memory relative to TC slot address, + * resolution is 1280x1024x1 (8 bits deep, but only LSB is used). + */ +#define PMAG_AA_ONBOARD_FBMEM_OFFSET 0x200000 + +struct aafb_info { + struct fb_info info; + struct display disp; + struct bt455_regs *bt455; + struct bt431_regs *bt431; + unsigned long fb_start; + unsigned long fb_size; + unsigned long fb_line_length; +}; + +/* + * Max 3 TURBOchannel slots -> max 3 PMAG-AA. + */ +static struct aafb_info my_fb_info[3]; + +static struct aafb_par { +} current_par; + +static int currcon = 0; + +static void aafb_get_par(struct aafb_par *par) +{ + *par = current_par; +} + +static void aafb_encode_fix(struct fb_fix_screeninfo *fix, + struct aafb_par *par, struct aafb_info *info) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "PMAG-AA"); + + fix->smem_start = info->fb_start; + fix->smem_len = info->fb_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_MONO10; + fix->line_length = info->fb_line_length; + fix->accel = FB_ACCEL_NONE; +} + +static int aafb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct aafb_par par; + + aafb_get_par(&par); + aafb_encode_fix(fix, &par, (struct aafb_info *) info); + + return 0; +} + +static void aafb_set_disp(int con, struct fb_info *info) +{ + struct fb_fix_screeninfo fix; + struct display *disp = (con < 0) ? info->disp : (fb_display + con); + + aafb_get_fix(&fix, con, info); + + disp->screen_base = (char *) fix.smem_start; + disp->visual = fix.visual; + disp->type = fix.type; + disp->type_aux = fix.type_aux; + disp->ypanstep = fix.ypanstep; + disp->ywrapstep = fix.ywrapstep; +// disp->line_length = fix.line_length; + disp->next_line = fix.line_length; + disp->can_soft_blank = 1; + disp->inverse = 0; +// disp->scrollmode = SCROLL_YREDRAW; + disp->dispsw = &fbcon_cfb8; +} + +static int aafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + static u16 color[2] = {0x0000, 0x000f}; + static struct fb_cmap aafb_cmap = {0, 2, color, color, color, NULL}; + + fb_copy_cmap(&aafb_cmap, cmap, kspc ? 0 : 2); + return 0; +} + +static int aafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + return -EINVAL; +} + +static int aafb_switch(int con, struct fb_info *info) +{ + /* Set the current console. */ + currcon = con; + aafb_set_disp(con, info); + + return 0; +} + +static void aafb_encode_var(struct fb_var_screeninfo *var, + struct aafb_par *par) +{ + var->xres = 1280; + var->yres = 1024; + var->xres_virtual = 2048; + var->yres_virtual = 1024; + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = 8; + var->grayscale = 1; + var->red.offset = 0; + var->red.length = 0; + var->red.msb_right = 0; + var->green.offset = 0; + var->green.length = 1; + var->green.msb_right = 0; + var->blue.offset = 0; + var->blue.length = 0; + var->blue.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->nonstd = 0; + var->activate &= ~FB_ACTIVATE_MASK & FB_ACTIVATE_NOW; + var->accel_flags = 0; + var->sync = FB_SYNC_ON_GREEN; + var->vmode &= ~FB_VMODE_MASK & FB_VMODE_NONINTERLACED; +} + +static int aafb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if (con < 0) { + struct aafb_par par; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + aafb_get_par(&par); + aafb_encode_var(var, &par); + } else + *var = info->var; + + return 0; +} + +static int aafb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct aafb_par par; + + aafb_get_par(&par); + aafb_encode_var(var, &par); + info->var = *var; + + return 0; +} + +static int aafb_update_var(int con, struct fb_info *info) +{ + return 0; +} + +/* 0 unblanks, any other blanks. */ + +static void aafb_blank(int blank, struct fb_info *info) +{ + struct aafb_info *ip = (struct aafb_info *)info; + u8 val = blank ? 0x00 : 0x0f; + + bt455_write_cmap_entry(ip->bt455, 1, val, val, val); +} + +static struct fb_ops aafb_ops = { + owner:THIS_MODULE, + fb_get_fix:aafb_get_fix, + fb_get_var:aafb_get_var, + fb_set_var:aafb_set_var, + fb_get_cmap:aafb_get_cmap, + fb_set_cmap:aafb_set_cmap +}; + +static int __init init_one(int slot) +{ + unsigned long base_addr = get_tc_base_addr(slot); + struct aafb_info *ip = &my_fb_info[slot]; + + memset(ip, 0, sizeof(struct aafb_info)); + + /* + * Framebuffer display memory base address and friends. + */ + ip->bt455 = (struct bt455_regs *) (base_addr + PMAG_AA_BT455_OFFSET); + ip->bt431 = (struct bt431_regs *) (base_addr + PMAG_AA_BT431_OFFSET); + ip->fb_start = base_addr + PMAG_AA_ONBOARD_FBMEM_OFFSET; + ip->fb_size = 2048 * 1024; /* fb_fix_screeninfo.smem_length + seems to be physical */ + ip->fb_line_length = 2048; + + /* + * Configure the RAM DACs. + */ +// TODO +// bt455_erase_cursor(ip->bt455); +// bt455_set_cursor(ip->bt455); +// bt431_erase_cursor(ip->bt431); +// bt431_init_cursor(ip->bt431); +// bt431_position_cursor(ip->bt431, 16, 16); + + /* Init colormap. */ + bt455_write_cmap_entry(ip->bt455, 0, 0x00, 0x00, 0x00); + bt455_write_cmap_entry(ip->bt455, 1, 0x0f, 0x0f, 0x0f); + + /* + * Let there be consoles.. + */ + strcpy(ip->info.modename, "PMAG-AA"); + ip->info.node = -1; + ip->info.flags = FBINFO_FLAG_DEFAULT; + ip->info.fbops = &aafb_ops; + ip->info.disp = &ip->disp; + ip->info.changevar = NULL; + ip->info.switch_con = &aafb_switch; + ip->info.updatevar = &aafb_update_var; + ip->info.blank = &aafb_blank; + + aafb_set_disp(-1, &ip->info); + aafb_set_var(&ip->disp.var, -1, &ip->info); + + /* Clear the screen. */ + memset ((void *)ip->fb_start, 0, ip->fb_size); + + if (register_framebuffer(&ip->info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device in TC slot %d\n", + GET_FB_IDX(ip->info.node), ip->info.modename, slot); + + return 0; +} + +static int __exit exit_one(int slot) +{ + struct aafb_info *ip = &my_fb_info[slot]; + + if (unregister_framebuffer(&ip->info) < 0) + return -EINVAL; + + return 0; +} + +/* + * Initialise the framebuffer. + */ +int __init pmagaafb_init(void) +{ + int sid; + int found = 0; + + while ((sid = search_tc_card("PMAG-AA")) >= 0) { + found = 1; + claim_tc_card(sid); + init_one(sid); + } + + return found ? 0 : -ENODEV; +} + +static void __exit pmagaafb_exit(void) +{ + int sid; + + while ((sid = search_tc_card("PMAG-AA")) >= 0) { + exit_one(sid); + release_tc_card(sid); + } +} + +MODULE_LICENSE("GPL");
This archive was generated by hypermail 2.1.7 : Wed Aug 13 2003 - 17:08:01 CEST