NetBSD/sys/arch/amiga/dev/grf_rt.c

1415 lines
38 KiB
C

/* $NetBSD: grf_rt.c,v 1.22 1995/02/23 19:14:46 chopps Exp $ */
/*
* Copyright (c) 1993 Markus Wild
* Copyright (c) 1993 Lutz Vieweg
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Lutz Vieweg.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "grfrt.h"
#if NGRFRT > 0
/* Graphics routines for the Retina board,
using the NCR 77C22E+ VGA controller. */
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/device.h>
#include <machine/cpu.h>
#include <amiga/amiga/device.h>
#include <amiga/dev/zbusvar.h>
#include <amiga/dev/grfioctl.h>
#include <amiga/dev/grfvar.h>
#include <amiga/dev/grf_rtreg.h>
int rt_ioctl __P((struct grf_softc *gp, u_long, void *));
/*
* marked true early so that retina_cnprobe() can tell if we are alive.
*/
int retina_inited;
/*
* This driver for the MacroSystem Retina board was only possible,
* because MacroSystem provided information about the pecularities
* of the board. THANKS! Competition in Europe among gfx board
* manufacturers is rather tough, so Lutz Vieweg, who wrote the
* initial driver, has made an agreement with MS not to document
* the driver source (see also his comment below).
* -> ALL comments after
* -> "/* -------------- START OF CODE -------------- * /"
* -> have been added by myself (mw) from studying the publically
* -> available "NCR 77C22E+" Data Manual
*/
/*
* This code offers low-level routines to access the Retina graphics-board
* manufactured by MS MacroSystem GmbH from within NetBSD for the Amiga.
*
* Thanks to MacroSystem for providing me with the neccessary information
* to create theese routines. The sparse documentation of this code
* results from the agreements between MS and me.
*/
extern unsigned char kernel_font_8x8_width, kernel_font_8x8_height;
extern unsigned char kernel_font_8x8_lo, kernel_font_8x8_hi;
extern unsigned char kernel_font_8x8[];
#define MDF_DBL 1
#define MDF_LACE 2
#define MDF_CLKDIV2 4
/* standard-palette definition */
unsigned char NCRStdPalette[16*3] = {
/* R G B */
0, 0, 0,
192,192,192,
128, 0, 0,
0,128, 0,
0, 0,128,
128,128, 0,
0,128,128,
128, 0,128,
64, 64, 64, /* the higher 8 colors have more intensity for */
255,255,255, /* compatibility with standard attributes */
255, 0, 0,
0,255, 0,
0, 0,255,
255,255, 0,
0,255,255,
255, 0,255
};
/* The following structures are examples for monitor-definitions. To make one
of your own, first use "DefineMonitor" and create the 8-bit monitor-mode of
your dreams. Then save it, and make a structure from the values provided in
the file DefineMonitor stored - the labels in the comment above the
structure definition show where to put what value.
Then you'll need to adapt your monitor-definition to the font you want to
use. Be FX the width of the font, then the following modifications have to
be applied to your values:
HBS = (HBS * 4) / FX
HSS = (HSS * 4) / FX
HSE = (HSE * 4) / FX
HBE = (HBE * 4) / FX
HT = (HT * 4) / FX
Make sure your maximum width (MW) and height (MH) are even multiples of
the fonts' width and height.
*/
#if 0
/* horizontal 31.5 kHz */
/* FQ FLG MW MH HBS HSS HSE HBE HT VBS VSS VSE VBE VT */
struct MonDef MON_640_512_60 = { 50000000, 28, 640, 512, 81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
/* Depth, PAL, TX, TY, XY,FontX, FontY, FontData, FLo, Fhi */
4, NCRStdPalette, 80, 64, 5120, 8, 8, kernel_font_8x8, 32, 255};
struct MonDef MON_640_480_62_G = { 50000000, 4, 640, 480, 161,171,184,196,195, 481, 484, 492, 502, 502,
8, NCRStdPalette,640,480, 5120, 8, 8, kernel_font_8x8, 32, 255};
/* Enter higher values here ^ ^ for panning! */
/* horizontal 38kHz */
struct MonDef MON_768_600_60 = { 75000000, 28, 768, 600, 97, 99,107,120,117, 601, 615, 625, 638, 638,
4, NCRStdPalette, 96, 75, 7200, 8, 8, kernel_font_8x8, 32, 255};
/* horizontal 64kHz */
struct MonDef MON_768_600_80 = { 50000000, 24, 768, 600, 97,104,112,122,119, 601, 606, 616, 628, 628,
4, NCRStdPalette, 96, 75, 7200, 8, 8, kernel_font_8x8, 32, 255};
struct MonDef MON_1024_768_80 = { 90000000, 24, 1024, 768, 129,130,141,172,169, 769, 770, 783, 804, 804,
4, NCRStdPalette,128, 96, 12288, 8, 8, kernel_font_8x8, 32, 255};
/* FQ FLG MW MH HBS HSS HSE HBE HT VBS VSS VSE VBE VT */
struct MonDef MON_1024_768_80_G = { 90000000, 0, 1024, 768, 257,258,280,344,343, 769, 770, 783, 804, 804,
8, NCRStdPalette, 1024, 768, 12288, 8, 8, kernel_font_8x8, 32, 255};
struct MonDef MON_1024_1024_59= { 90000000, 24, 1024,1024, 129,130,141,173,170,1025,1059,1076,1087,1087,
4, NCRStdPalette,128, 128, 16384, 8, 8, kernel_font_8x8, 32, 255};
/* WARNING: THE FOLLOWING MONITOR MODES EXCEED THE 90-MHz LIMIT THE PROCESSOR
HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)! */
struct MonDef MON_1280_1024_60= {110000000, 24, 1280,1024, 161,162,176,211,208,1025,1026,1043,1073,1073,
4, NCRStdPalette,160, 128, 20480, 8, 8, kernel_font_8x8, 32, 255};
struct MonDef MON_1280_1024_60_G= {110000000, 0, 1280,1024, 321,322,349,422,421,1025,1026,1043,1073,1073,
8, NCRStdPalette,1280,1024, 20480, 8, 8, kernel_font_8x8, 32, 255};
/* horizontal 75kHz */
struct MonDef MON_1280_1024_69= {120000000, 24, 1280,1024, 161,162,175,200,197,1025,1026,1043,1073,1073,
4, NCRStdPalette,160, 128, 20480, 8, 8, kernel_font_8x8, 32, 255};
#else
struct MonDef monitor_defs[] = {
/* horizontal 31.5 kHz */
{ 50000000, 28, 640, 512, 81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
4, NCRStdPalette, 80, 64, 5120, 8, 8, kernel_font_8x8, 32, 255},
/* horizontal 38kHz */
{ 75000000, 28, 768, 600, 97, 99,107,120,117, 601, 615, 625, 638, 638,
4, NCRStdPalette, 96, 75, 7200, 8, 8, kernel_font_8x8, 32, 255},
/* horizontal 64kHz */
{ 50000000, 24, 768, 600, 97,104,112,122,119, 601, 606, 616, 628, 628,
4, NCRStdPalette, 96, 75, 7200, 8, 8, kernel_font_8x8, 32, 255},
{ 90000000, 24, 1024, 768, 129,130,141,172,169, 769, 770, 783, 804, 804,
4, NCRStdPalette,128, 96, 12288, 8, 8, kernel_font_8x8, 32, 255},
/* GFX modes */
/* horizontal 31.5 kHz */
{ 50000000, 4, 640, 480, 161,171,184,196,195, 481, 484, 492, 502, 502,
8, NCRStdPalette,640, 480, 5120, 8, 8, kernel_font_8x8, 32, 255},
/* horizontal 64kHz */
{ 90000000, 0, 1024, 768, 257,258,280,344,343, 769, 770, 783, 804, 804,
8, NCRStdPalette, 1024, 768, 12288, 8, 8, kernel_font_8x8, 32, 255},
/* WARNING: THE FOLLOWING MONITOR MODES EXCEED THE 90-MHz LIMIT THE PROCESSOR
HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)! */
{110000000, 0, 1280,1024, 321,322,349,422,421,1025,1026,1043,1073,1073,
8, NCRStdPalette,1280,1024, 20480, 8, 8, kernel_font_8x8, 32, 255},
};
static const char *monitor_descr[] = {
"80x64 (640x512) 31.5kHz",
"96x75 (768x600) 38kHz",
"96x75 (768x600) 64kHz",
"128x96 (1024x768) 64kHz",
"GFX (640x480) 31.5kHz",
"GFX (1024x768) 64kHz",
"GFX (1280x1024) 64kHz ***EXCEEDS CHIP LIMIT!!!***",
};
int retina_mon_max = sizeof (monitor_defs)/sizeof (monitor_defs[0]);
/* patchable */
int retina_default_mon = 0;
int retina_default_gfx = 4;
#endif
static struct MonDef *current_mon;
/* -------------- START OF CODE -------------- */
static const long FQTab[16] =
{ 25175000, 28322000, 36000000, 65000000,
44900000, 50000000, 80000000, 75000000,
56644000, 63000000, 72000000, 130000000,
90000000, 100000000, 110000000, 120000000 };
/*--------------------------------------------------*/
/*--------------------------------------------------*/
#if 0
static struct MonDef *default_monitor = &DEFAULT_MONDEF;
#endif
/*
* used to query the retina to see if its alive (?)
*/
int
retina_alive(mdp)
struct MonDef *mdp;
{
short clksel;
for (clksel = 15; clksel; clksel--) {
if (FQTab[clksel] == mdp->FQ)
break;
}
if (clksel < 0)
return(0);
if (mdp->DEP != 4)
return(1);
if (mdp->FX == 4 || (mdp->FX >= 7 && mdp->FX <= 16))
return(1);
return(0);
}
static int
rt_load_mon(gp, md)
struct grf_softc *gp;
struct MonDef *md;
{
struct grfinfo *gi = &gp->g_display;
volatile unsigned char *ba;
volatile unsigned char *fb;
short FW, clksel, HDE, VDE;
for (clksel = 15; clksel; clksel--) {
if (FQTab[clksel] == md->FQ) break;
}
if (clksel < 0)
return(0);
ba = gp->g_regkva;;
fb = gp->g_fbkva;
FW = 0;
if (md->DEP == 4) {
switch (md->FX) {
case 4:
FW = 0;
break;
case 7:
FW = 1;
break;
case 8:
FW = 2;
break;
case 9:
FW = 3;
break;
case 10:
FW = 4;
break;
case 11:
FW = 5;
break;
case 12:
FW = 6;
break;
case 13:
FW = 7;
break;
case 14:
FW = 8;
break;
case 15:
FW = 9;
break;
case 16:
FW = 11;
break;
default:
return(0);
break;
};
}
if (md->DEP == 4) HDE = (md->MW+md->FX-1)/md->FX;
else HDE = (md->MW+3)/4;
VDE = md->MH-1;
/* hmm... */
fb[0x8000] = 0;
/* enable extension registers */
WSeq (ba, SEQ_ID_EXTENDED_ENABLE, 0x05);
#if 0
/* program the clock oscillator */
vgaw (ba, GREG_MISC_OUTPUT_W, 0xe3 | ((clksel & 3) * 0x04));
vgaw (ba, GREG_FEATURE_CONTROL_W, 0x00);
/* XXXX according to the NCR specs, this register should be set to 1
XXXX before doing the MISC_OUTPUT setting and CLOCKING_MODE
XXXX setting. */
WSeq (ba, SEQ_ID_RESET, 0x03);
WSeq (ba, SEQ_ID_CLOCKING_MODE, 0x01 | ((md->FLG & MDF_CLKDIV2)/ MDF_CLKDIV2 * 8));
WSeq (ba, SEQ_ID_MAP_MASK, 0x0f);
WSeq (ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
/* odd/even write select + extended memory */
WSeq (ba, SEQ_ID_MEMORY_MODE, 0x06);
/* XXXX I think this order of setting RESET is wrong... */
WSeq (ba, SEQ_ID_RESET, 0x01);
WSeq (ba, SEQ_ID_RESET, 0x03);
#else
WSeq (ba, SEQ_ID_RESET, 0x01);
/* set font width + rest of clocks */
WSeq (ba, SEQ_ID_EXT_CLOCK_MODE, 0x30 | (FW & 0x0f) | ((clksel & 4) / 4 * 0x40) );
/* another clock bit, plus hw stuff */
WSeq (ba, SEQ_ID_MISC_FEATURE_SEL, 0xf4 | (clksel & 8) );
/* program the clock oscillator */
vgaw (ba, GREG_MISC_OUTPUT_W, 0xe3 | ((clksel & 3) * 0x04));
vgaw (ba, GREG_FEATURE_CONTROL_W, 0x00);
WSeq (ba, SEQ_ID_CLOCKING_MODE, 0x01 | ((md->FLG & MDF_CLKDIV2)/ MDF_CLKDIV2 * 8));
WSeq (ba, SEQ_ID_MAP_MASK, 0x0f);
WSeq (ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
/* odd/even write select + extended memory */
WSeq (ba, SEQ_ID_MEMORY_MODE, 0x06);
WSeq (ba, SEQ_ID_RESET, 0x03);
#endif
/* monochrome cursor */
WSeq (ba, SEQ_ID_CURSOR_CONTROL, 0x00);
/* bank0 */
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, 0x00);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, 0x00);
WSeq (ba, SEQ_ID_DISP_OFF_HI , 0x00);
WSeq (ba, SEQ_ID_DISP_OFF_LO , 0x00);
/* bank0 */
WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, 0x00);
WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, 0x00);
/* 1M-chips + ena SEC + ena EMem + rw PrimA0/rw Sec/B0 */
WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
#if 0
/* set font width + rest of clocks */
WSeq (ba, SEQ_ID_EXT_CLOCK_MODE, 0x30 | (FW & 0x0f) | ((clksel & 4) / 4 * 0x40) );
#endif
if (md->DEP == 4) {
/* no ext-chain4 + no host-addr-bit-16 */
WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, 0x00);
/* no packed/nibble + no 256bit gfx format */
WSeq (ba, SEQ_ID_EXT_PIXEL_CNTL, 0x00);
}
else {
WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, 0x02);
/* 256bit gfx format */
WSeq (ba, SEQ_ID_EXT_PIXEL_CNTL, 0x01);
}
/* AT-interface */
WSeq (ba, SEQ_ID_BUS_WIDTH_FEEDB, 0x06);
/* see fg/bg color expansion */
WSeq (ba, SEQ_ID_COLOR_EXP_WFG, 0x01);
WSeq (ba, SEQ_ID_COLOR_EXP_WBG, 0x00);
WSeq (ba, SEQ_ID_EXT_RW_CONTROL, 0x00);
#if 0
/* another clock bit, plus hw stuff */
WSeq (ba, SEQ_ID_MISC_FEATURE_SEL, 0xf4 | (clksel & 8) );
#endif
/* don't tristate PCLK and PIX */
WSeq (ba, SEQ_ID_COLOR_KEY_CNTL, 0x40 );
/* reset CRC circuit */
WSeq (ba, SEQ_ID_CRC_CONTROL, 0x00 );
/* set RAS/CAS swap */
WSeq (ba, SEQ_ID_PERF_SELECT, 0x20);
WCrt (ba, CRT_ID_END_VER_RETR, (md->VSE & 0xf ) | 0x20);
WCrt (ba, CRT_ID_HOR_TOTAL, md->HT & 0xff);
WCrt (ba, CRT_ID_HOR_DISP_ENA_END, (HDE-1) & 0xff);
WCrt (ba, CRT_ID_START_HOR_BLANK, md->HBS & 0xff);
WCrt (ba, CRT_ID_END_HOR_BLANK, (md->HBE & 0x1f) | 0x80);
WCrt (ba, CRT_ID_START_HOR_RETR, md->HSS & 0xff);
WCrt (ba, CRT_ID_END_HOR_RETR, (md->HSE & 0x1f) | ((md->HBE & 0x20)/ 0x20 * 0x80));
WCrt (ba, CRT_ID_VER_TOTAL, (md->VT & 0xff));
WCrt (ba, CRT_ID_OVERFLOW, (( (md->VSS & 0x200) / 0x200 * 0x80)
| ((VDE & 0x200) / 0x200 * 0x40)
| ((md->VT & 0x200) / 0x200 * 0x20)
| 0x10
| ((md->VBS & 0x100) / 0x100 * 8 )
| ((md->VSS & 0x100) / 0x100 * 4 )
| ((VDE & 0x100) / 0x100 * 2 )
| ((md->VT & 0x100) / 0x100 )));
WCrt (ba, CRT_ID_PRESET_ROW_SCAN, 0x00);
if (md->DEP == 4) {
WCrt (ba, CRT_ID_MAX_SCAN_LINE, (( (md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
| 0x40
| ((md->VBS & 0x200)/0x200 * 0x20)
| ((md->FY-1) & 0x1f)));
}
else {
WCrt (ba, CRT_ID_MAX_SCAN_LINE, (( (md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
| 0x40
| ((md->VBS & 0x200)/0x200 * 0x20)
| (0 & 0x1f)));
}
WCrt (ba, CRT_ID_CURSOR_START, (md->FY & 0x1f) - 2);
WCrt (ba, CRT_ID_CURSOR_END, (md->FY & 0x1f) - 1);
WCrt (ba, CRT_ID_START_ADDR_HIGH, 0x00);
WCrt (ba, CRT_ID_START_ADDR_LOW, 0x00);
WCrt (ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
WCrt (ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
WCrt (ba, CRT_ID_START_VER_RETR, md->VSS & 0xff);
WCrt (ba, CRT_ID_END_VER_RETR, (md->VSE & 0x0f) | 0x80 | 0x20);
WCrt (ba, CRT_ID_VER_DISP_ENA_END, VDE & 0xff);
if (md->DEP == 4)
WCrt (ba, CRT_ID_OFFSET, (HDE / 2) & 0xff);
else
WCrt (ba, CRT_ID_OFFSET, (md->TX / 8) & 0xff);
WCrt (ba, CRT_ID_UNDERLINE_LOC, (md->FY-1) & 0x1f);
WCrt (ba, CRT_ID_START_VER_BLANK, md->VBS & 0xff);
WCrt (ba, CRT_ID_END_VER_BLANK, md->VBE & 0xff);
/* byte mode + wrap + select row scan counter + cms */
WCrt (ba, CRT_ID_MODE_CONTROL, 0xe3);
WCrt (ba, CRT_ID_LINE_COMPARE, 0xff);
/* enable extended end bits + those bits */
WCrt (ba, CRT_ID_EXT_HOR_TIMING1, ( 0x20
| ((md->FLG & MDF_LACE) / MDF_LACE * 0x10)
| ((md->HT & 0x100) / 0x100 * 0x01)
| (((HDE-1) & 0x100) / 0x100 * 0x02)
| ((md->HBS & 0x100) / 0x100 * 0x04)
| ((md->HSS & 0x100) / 0x100 * 0x08)));
if (md->DEP == 4)
WCrt (ba, CRT_ID_EXT_START_ADDR, (((HDE / 2) & 0x100)/0x100 * 16));
else
WCrt (ba, CRT_ID_EXT_START_ADDR, (((md->TX / 8) & 0x100)/0x100 * 16));
WCrt (ba, CRT_ID_EXT_HOR_TIMING2, ( ((md->HT & 0x200)/ 0x200 * 0x01)
| (((HDE-1) & 0x200)/ 0x200 * 0x02)
| ((md->HBS & 0x200)/ 0x200 * 0x04)
| ((md->HSS & 0x200)/ 0x200 * 0x08)
| ((md->HBE & 0xc0) / 0x40 * 0x10)
| ((md->HSE & 0x60) / 0x20 * 0x40)));
WCrt (ba, CRT_ID_EXT_VER_TIMING, ( ((md->VSE & 0x10) / 0x10 * 0x80)
| ((md->VBE & 0x300)/ 0x100 * 0x20)
| 0x10
| ((md->VSS & 0x400)/ 0x400 * 0x08)
| ((md->VBS & 0x400)/ 0x400 * 0x04)
| ((VDE & 0x400)/ 0x400 * 0x02)
| ((md->VT & 0x400)/ 0x400 * 0x01)));
WGfx (ba, GCT_ID_SET_RESET, 0x00);
WGfx (ba, GCT_ID_ENABLE_SET_RESET, 0x00);
WGfx (ba, GCT_ID_COLOR_COMPARE, 0x00);
WGfx (ba, GCT_ID_DATA_ROTATE, 0x00);
WGfx (ba, GCT_ID_READ_MAP_SELECT, 0x00);
WGfx (ba, GCT_ID_GRAPHICS_MODE, 0x00);
if (md->DEP == 4)
WGfx (ba, GCT_ID_MISC, 0x04);
else
WGfx (ba, GCT_ID_MISC, 0x05);
WGfx (ba, GCT_ID_COLOR_XCARE, 0xff);
WGfx (ba, GCT_ID_BITMASK, 0xff);
/* reset the Attribute Controller flipflop */
vgar (ba, GREG_STATUS1_R);
WAttr (ba, ACT_ID_PALETTE0, 0x00);
WAttr (ba, ACT_ID_PALETTE1, 0x01);
WAttr (ba, ACT_ID_PALETTE2, 0x02);
WAttr (ba, ACT_ID_PALETTE3, 0x03);
WAttr (ba, ACT_ID_PALETTE4, 0x04);
WAttr (ba, ACT_ID_PALETTE5, 0x05);
WAttr (ba, ACT_ID_PALETTE6, 0x06);
WAttr (ba, ACT_ID_PALETTE7, 0x07);
WAttr (ba, ACT_ID_PALETTE8, 0x08);
WAttr (ba, ACT_ID_PALETTE9, 0x09);
WAttr (ba, ACT_ID_PALETTE10, 0x0a);
WAttr (ba, ACT_ID_PALETTE11, 0x0b);
WAttr (ba, ACT_ID_PALETTE12, 0x0c);
WAttr (ba, ACT_ID_PALETTE13, 0x0d);
WAttr (ba, ACT_ID_PALETTE14, 0x0e);
WAttr (ba, ACT_ID_PALETTE15, 0x0f);
vgar (ba, GREG_STATUS1_R);
if (md->DEP == 4)
WAttr (ba, ACT_ID_ATTR_MODE_CNTL, 0x08);
else
WAttr (ba, ACT_ID_ATTR_MODE_CNTL, 0x09);
WAttr (ba, ACT_ID_OVERSCAN_COLOR, 0x00);
WAttr (ba, ACT_ID_COLOR_PLANE_ENA, 0x0f);
WAttr (ba, ACT_ID_HOR_PEL_PANNING, 0x00);
WAttr (ba, ACT_ID_COLOR_SELECT, 0x00);
vgar (ba, GREG_STATUS1_R);
/* I have *NO* idea what strobing reg-0x20 might do... */
vgaw (ba, ACT_ADDRESS_W, 0x20);
if (md->DEP == 4)
WCrt (ba, CRT_ID_MAX_SCAN_LINE, ( ((md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
| 0x40
| ((md->VBS & 0x200)/0x200 * 0x20)
| ((md->FY-1) & 0x1f)));
else
WCrt (ba, CRT_ID_MAX_SCAN_LINE, ( ((md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
| 0x40
| ((md->VBS & 0x200)/0x200 * 0x20)
| (0 & 0x1f)));
/* not it's time for guessing... */
vgaw (ba, VDAC_REG_D, 0x02);
/* if this does what I think it does, it selects DAC
register 0, and writes the palette in subsequent
registers, thus it works similar to the WD33C93
select/data mechanism */
vgaw (ba, VDAC_REG_SELECT, 0x00);
{
short x = 15;
const unsigned char * col = md->PAL;
do {
vgaw (ba, VDAC_REG_DATA, *col++);
vgaw (ba, VDAC_REG_DATA, *col++);
vgaw (ba, VDAC_REG_DATA, *col++);
} while (x--);
if (md->DEP != 4) {
short x = 256-17;
unsigned char col = 16;
do {
vgaw(ba, VDAC_REG_DATA, col);
vgaw(ba, VDAC_REG_DATA, col);
vgaw(ba, VDAC_REG_DATA, col);
col++;
} while (x--);
}
}
/* now load the font into maps 2 (and 3 for fonts wider than 8 pixels) */
if (md->DEP == 4) {
/* first set the whole font memory to a test-pattern, so we
can see if something that shouldn't be drawn IS drawn.. */
{
volatile unsigned char * c = fb;
long x;
Map(2);
for (x = 0; x < 65536; x++) {
*c++ = (x & 1)? 0xaa : 0x55;
}
}
{
volatile unsigned char * c = fb;
long x;
Map(3);
for (x = 0; x < 65536; x++) {
*c++ = (x & 1)? 0xaa : 0x55;
}
}
{
/* ok, now position at first defined character, and
copy over the images */
volatile unsigned char * c = fb + md->FLo * 32;
const unsigned char * f = md->FData;
unsigned short z;
Map(2);
for (z = md->FLo; z <= md->FHi; z++) {
short y = md->FY-1;
if (md->FX > 8){
do {
*c++ = *f;
f += 2;
} while (y--);
}
else {
do {
*c++ = *f++;
} while (y--);
}
c += 32-md->FY;
}
if (md->FX > 8) {
unsigned short z;
Map(3);
c = fb + md->FLo*32;
f = md->FData+1;
for (z = md->FLo; z <= md->FHi; z++) {
short y = md->FY-1;
do {
*c++ = *f;
f += 2;
} while (y--);
c += 32-md->FY;
}
}
}
}
/* select map 0 */
WGfx (ba, GCT_ID_READ_MAP_SELECT, 0);
if (md->DEP == 4)
/* allow writes into maps 0 and 1 */
WSeq (ba, SEQ_ID_MAP_MASK, 3);
else
/* allow writes into all maps */
WSeq (ba, SEQ_ID_MAP_MASK, 0x0f);
/* select extended chain4 addressing:
!A0/!A1 map 0 character to be displayed
!A1/ A1 map 1 attribute of that character
A0/!A1 map 2 not used (masked out, ignored)
A0/ A1 map 3 not used (masked out, ignored) */
WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02);
if (md->DEP == 4) {
/* position in display memory */
unsigned short * c = (unsigned short *) fb;
/* fill with blank, white on black */
const unsigned short fill_val = 0x2010;
short x = md->XY;
do {
*c = fill_val;
c += 2; } while (x--);
/* I won't comment this :-)) */
c = (unsigned short *) fb;
c += (md->TX-6)*2;
{
unsigned short init_msg[6] = {0x520a, 0x450b, 0x540c, 0x490d, 0x4e0e, 0x410f};
unsigned short * f = init_msg;
x = 5;
do {
*c = *f++;
c += 2;
} while (x--);
}
}
else if (md->DEP == 8) {
/* could clear the gfx screen here, but that's what the X server does anyway */
;
}
gp->g_data = (caddr_t)md;
gi->gd_regaddr = (caddr_t)ztwopa(ba);
gi->gd_regsize = 64*1024;
gi->gd_fbaddr = (caddr_t)ztwopa(fb);
#ifdef BANKEDDEVPAGER
gi->gd_fbsize = 4*1024*1024; /* XXX */
gi->gd_bank_size = 64*1024;
#else
gi->gd_fbsize = 64*1024; /* larger, but that's whats mappable */
#endif
gi->gd_colors = 1 << md->DEP;
gi->gd_planes = md->DEP;
gi->gd_fbwidth = md->MW;
gi->gd_fbheight = md->MH;
gi->gd_fbx = 0;
gi->gd_fby = 0;
gi->gd_dwidth = md->TX * md->FX;
gi->gd_dheight = md->TY * md->FY;
gi->gd_dx = 0;
gi->gd_dy = 0;
/* initialized, works, return 1 */
return(1);
}
int rt_mode __P((struct grf_softc *, int, void *, int , int));
void grfrtattach __P((struct device *, struct device *, void *));
int grfrtprint __P((void *, char *));
int grfrtmatch __P((struct device *, struct cfdata *, void *));
struct cfdriver grfrtcd = {
NULL, "grfrt", (cfmatch_t)grfrtmatch, grfrtattach,
DV_DULL, sizeof(struct grf_softc), NULL, 0 };
/*
* only used in console init
*/
static struct cfdata *cfdata;
/*
* we make sure to only init things once. this is somewhat
* tricky regarding the console.
*/
int
grfrtmatch(pdp, cfp, auxp)
struct device *pdp;
struct cfdata *cfp;
void *auxp;
{
#ifdef RETINACONSOLE
static int rtconunit = -1;
#endif
struct zbus_args *zap;
zap = auxp;
/*
* allow only one retina console
*/
if (amiga_realconfig == 0)
#ifdef RETINACONSOLE
if (rtconunit != -1)
#endif
return(0);
/*
* check that this is a retina board.
*/
if (zap->manid != 18260 || zap->prodid != 6)
return(0);
#ifdef RETINACONSOLE
if (amiga_realconfig == 0 || rtconunit != cfp->cf_unit) {
#endif
if ((unsigned)retina_default_mon >= retina_mon_max ||
monitor_defs[retina_default_mon].DEP == 8)
retina_default_mon = 0;
current_mon = monitor_defs + retina_default_mon;
if (retina_alive(current_mon) == 0)
return(0);
#ifdef RETINACONSOLE
if (amiga_realconfig == 0) {
rtconunit = cfp->cf_unit;
cfdata = cfp;
}
}
#endif
return(1);
}
/*
* attach to the grfbus (zbus)
*/
void
grfrtattach(pdp, dp, auxp)
struct device *pdp, *dp;
void *auxp;
{
static struct grf_softc congrf;
static int coninited;
struct zbus_args *zap;
struct grf_softc *gp;
zap = auxp;
if (dp == NULL)
gp = &congrf;
else
gp = (struct grf_softc *)dp;
if (dp != NULL && congrf.g_regkva != 0) {
/*
* we inited earlier just copy the info
* take care not to copy the device struct though.
*/
bcopy(&congrf.g_display, &gp->g_display,
(char *)&gp[1] - (char *)&gp->g_display);
} else {
gp->g_regkva = (volatile caddr_t)zap->va;
gp->g_fbkva = (volatile caddr_t)zap->va + 64 * 1024;
gp->g_unit = GRF_RETINAII_UNIT;
gp->g_flags = GF_ALIVE;
gp->g_mode = rt_mode;
gp->g_conpri = grfrt_cnprobe();
grfrt_iteinit(gp);
(void)rt_load_mon(gp, current_mon);
}
if (dp != NULL)
printf("\n");
/*
* attach grf
*/
amiga_config_found(cfdata, &gp->g_device, gp, grfrtprint);
}
int
grfrtprint(auxp, pnp)
void *auxp;
char *pnp;
{
if (pnp)
printf("grf%d at %s", ((struct grf_softc *)auxp)->g_unit,
pnp);
return(UNCONF);
}
static int
rt_getvmode (gp, vm)
struct grf_softc *gp;
struct grfvideo_mode *vm;
{
struct MonDef *md;
if (vm->mode_num && vm->mode_num > retina_mon_max)
return EINVAL;
if (! vm->mode_num)
vm->mode_num = (current_mon - monitor_defs) + 1;
md = monitor_defs + (vm->mode_num - 1);
strncpy (vm->mode_descr, monitor_descr + (vm->mode_num - 1),
sizeof (vm->mode_descr));
vm->pixel_clock = md->FQ;
vm->disp_width = md->MW;
vm->disp_height = md->MH;
vm->depth = md->DEP;
vm->hblank_start = md->HBS;
vm->hblank_stop = md->HBE;
vm->hsync_start = md->HSS;
vm->hsync_stop = md->HSE;
vm->htotal = md->HT;
vm->vblank_start = md->VBS;
vm->vblank_stop = md->VBE;
vm->vsync_start = md->VSS;
vm->vsync_stop = md->VSE;
vm->vtotal = md->VT;
return 0;
}
static int
rt_setvmode (gp, mode, txtonly)
struct grf_softc *gp;
unsigned mode;
int txtonly;
{
struct MonDef *md;
int error;
if (!mode || mode > retina_mon_max)
return EINVAL;
if (txtonly && monitor_defs[mode-1].DEP == 8)
return EINVAL;
current_mon = monitor_defs + (mode - 1);
error = rt_load_mon (gp, current_mon) ? 0 : EINVAL;
return error;
}
/*
* Change the mode of the display.
* Return a UNIX error number or 0 for success.
*/
int
rt_mode(gp, cmd, arg, a2, a3)
struct grf_softc *gp;
int cmd;
void *arg;
int a2, a3;
{
/* implement these later... */
switch (cmd)
{
case GM_GRFON:
rt_setvmode (gp, retina_default_gfx + 1, 0);
return 0;
case GM_GRFOFF:
rt_setvmode (gp, retina_default_mon + 1, 0);
return 0;
case GM_GRFCONFIG:
return 0;
case GM_GRFGETVMODE:
return rt_getvmode (gp, (struct grfvideo_mode *) arg);
case GM_GRFSETVMODE:
return rt_setvmode (gp, *(unsigned *) arg, 1);
case GM_GRFGETNUMVM:
*(int *)arg = retina_mon_max;
return 0;
#ifdef BANKEDDEVPAGER
case GM_GRFGETBANK:
*(int *)arg = rt_getbank (gp, a2, a3);
return 0;
case GM_GRFGETCURBANK:
*(int *)arg = rt_getcurbank (gp);
return 0;
case GM_GRFSETBANK:
return rt_setbank (gp, arg);
#endif
case GM_GRFIOCTL:
return rt_ioctl (gp, (u_long)arg, (void *)a2);
default:
break;
}
return EINVAL;
}
int
rt_ioctl (gp, cmd, data)
register struct grf_softc *gp;
u_long cmd;
void *data;
{
switch (cmd)
{
case GRFIOCGSPRITEPOS:
return rt_getspritepos (gp, (struct grf_position *) data);
case GRFIOCSSPRITEPOS:
return rt_setspritepos (gp, (struct grf_position *) data);
case GRFIOCSSPRITEINF:
return rt_setspriteinfo (gp, (struct grf_spriteinfo *) data);
case GRFIOCGSPRITEINF:
return rt_getspriteinfo (gp, (struct grf_spriteinfo *) data);
case GRFIOCGSPRITEMAX:
return rt_getspritemax (gp, (struct grf_position *) data);
case GRFIOCGETCMAP:
return rt_getcmap (gp, (struct grf_colormap *) data);
case GRFIOCPUTCMAP:
return rt_putcmap (gp, (struct grf_colormap *) data);
case GRFIOCBITBLT:
return rt_bitblt (gp, (struct grf_bitblt *) data);
}
return EINVAL;
}
#ifdef BANKEDDEVPAGER
/* Retina banks can overlap. Don't use this information (yet?), and
only switch 64k sized banks. */
int
rt_getbank (gp, offs, prot)
struct grf_softc *gp;
off_t offs;
int prot;
{
/* XXX */
if (offs < 0 || offs >= 4*1024*1024)
return -1;
else
return offs >> 16;
}
int
rt_getcurbank (gp)
struct grf_softc *gp;
{
struct grfinfo *gi = &gp->g_display;
volatile unsigned char *ba;
int bank;
ba = gp->g_regkva;
bank = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8);
/* bank register is multiple of 64 byte, make this multiple of 64k */
bank >>= 10;
return bank;
}
int
rt_setbank (gp, bank)
struct grf_softc *gp;
int bank;
{
volatile unsigned char *ba;
ba = gp->g_regkva;
/* bank register is multiple of 64 byte, make this multiple of 64k */
bank <<= 10;
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank);
bank >>= 8;
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank);
return 0;
}
#endif
int
rt_getcmap (gfp, cmap)
struct grf_softc *gfp;
struct grf_colormap *cmap;
{
volatile unsigned char *ba;
u_char red[256], green[256], blue[256], *rp, *gp, *bp;
short x;
int error;
if (cmap->count == 0 || cmap->index >= 256)
return 0;
if (cmap->index + cmap->count > 256)
cmap->count = 256 - cmap->index;
ba = gfp->g_regkva;
/* first read colors out of the chip, then copyout to userspace */
vgaw (ba, VDAC_REG_SELECT, cmap->index);
x = cmap->count - 1;
rp = red + cmap->index;
gp = green + cmap->index;
bp = blue + cmap->index;
do
{
*rp++ = vgar (ba, VDAC_REG_DATA);
*gp++ = vgar (ba, VDAC_REG_DATA);
*bp++ = vgar (ba, VDAC_REG_DATA);
}
while (x--);
if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
&& !(error = copyout (green + cmap->index, cmap->green, cmap->count))
&& !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
return 0;
return error;
}
int
rt_putcmap (gfp, cmap)
struct grf_softc *gfp;
struct grf_colormap *cmap;
{
volatile unsigned char *ba;
u_char red[256], green[256], blue[256], *rp, *gp, *bp;
short x;
int error;
if (cmap->count == 0 || cmap->index >= 256)
return 0;
if (cmap->index + cmap->count > 256)
cmap->count = 256 - cmap->index;
/* first copy the colors into kernelspace */
if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
&& !(error = copyin (cmap->green, green + cmap->index, cmap->count))
&& !(error = copyin (cmap->blue, blue + cmap->index, cmap->count)))
{
ba = gfp->g_regkva;
vgaw (ba, VDAC_REG_SELECT, cmap->index);
x = cmap->count - 1;
rp = red + cmap->index;
gp = green + cmap->index;
bp = blue + cmap->index;
do
{
vgaw (ba, VDAC_REG_DATA, *rp++);
vgaw (ba, VDAC_REG_DATA, *gp++);
vgaw (ba, VDAC_REG_DATA, *bp++);
}
while (x--);
return 0;
}
else
return error;
}
int
rt_getspritepos (gp, pos)
struct grf_softc *gp;
struct grf_position *pos;
{
volatile unsigned char *ba;
ba = gp->g_regkva;
pos->x = vgar (ba, SEQ_ID_CURSOR_X_LOC_LO) | (vgar (ba, SEQ_ID_CURSOR_X_LOC_HI) << 8);
pos->y = vgar (ba, SEQ_ID_CURSOR_Y_LOC_LO) | (vgar (ba, SEQ_ID_CURSOR_Y_LOC_HI) << 8);
return 0;
}
int
rt_setspritepos (gp, pos)
struct grf_softc *gp;
struct grf_position *pos;
{
volatile unsigned char *ba;
ba = gp->g_regkva;
vgaw (ba, SEQ_ID_CURSOR_X_LOC_LO, pos->x & 0xff);
vgaw (ba, SEQ_ID_CURSOR_X_LOC_HI, (pos->x >> 8) & 0x07);
vgaw (ba, SEQ_ID_CURSOR_Y_LOC_LO, pos->y & 0xff);
vgaw (ba, SEQ_ID_CURSOR_Y_LOC_HI, (pos->y >> 8) & 0x07);
return 0;
}
/* assume an at least 2M retina (XXX), sprite is last in memory.
According to the bogus docs, the cursor can be at most 128 lines
in height, and the x-hostspot can be placed at most at pos 31,
this gives width of a long */
#define SPRITE_ADDR (2*1024*1024 - 128*4)
int
rt_getspriteinfo (gp, info)
struct grf_softc *gp;
struct grf_spriteinfo *info;
{
volatile unsigned char *ba, *fb;
ba = gp->g_regkva;
fb = gp->g_fbkva;
if (info->set & GRFSPRSET_ENABLE)
info->enable = vgar (ba, SEQ_ID_CURSOR_CONTROL) & 0x01;
if (info->set & GRFSPRSET_POS)
rt_getspritepos (gp, &info->pos);
if (info->set & GRFSPRSET_HOT)
{
info->hot.x = vgar (ba, SEQ_ID_CURSOR_X_INDEX) & 0x1f;
info->hot.y = vgar (ba, SEQ_ID_CURSOR_Y_INDEX) & 0x7f;
}
if (info->set & GRFSPRSET_CMAP)
{
struct grf_colormap cmap;
int index;
cmap.index = 0;
cmap.count = 256;
rt_getcmap (gp, &cmap);
index = vgar (ba, SEQ_ID_CURSOR_COLOR0);
info->cmap.red[0] = cmap.red[index];
info->cmap.green[0] = cmap.green[index];
info->cmap.blue[0] = cmap.blue[index];
index = vgar (ba, SEQ_ID_CURSOR_COLOR1);
info->cmap.red[1] = cmap.red[index];
info->cmap.green[1] = cmap.green[index];
info->cmap.blue[1] = cmap.blue[index];
}
if (info->set & GRFSPRSET_SHAPE)
{
int saved_bank_lo = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO);
int saved_bank_hi = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI);
int last_bank = SPRITE_ADDR >> 6;
int last_bank_lo = last_bank & 0xff;
int last_bank_hi = last_bank >> 8;
u_char mask;
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, last_bank_lo);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, last_bank_hi);
copyout (fb, info->image, 128*4);
mask = RSeq (ba, SEQ_ID_CURSOR_PIXELMASK);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, saved_bank_lo);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, saved_bank_hi);
copyout (&mask, info->mask, 1);
info->size.x = 32; /* ??? */
info->size.y = (RSeq (ba, SEQ_ID_CURSOR_CONTROL) & 6) << 4;
}
}
int
rt_setspriteinfo (gp, info)
struct grf_softc *gp;
struct grf_spriteinfo *info;
{
volatile unsigned char *ba, *fb;
u_char control;
ba = gp->g_regkva;
fb = gp->g_fbkva;
control = vgar (ba, SEQ_ID_CURSOR_CONTROL);
if (info->set & GRFSPRSET_ENABLE)
{
if (info->enable)
control |= 1;
else
control &= ~1;
vgaw (ba, SEQ_ID_CURSOR_CONTROL, control);
}
if (info->set & GRFSPRSET_POS)
rt_setspritepos (gp, &info->pos);
if (info->set & GRFSPRSET_HOT)
{
vgaw (ba, SEQ_ID_CURSOR_X_INDEX, info->hot.x & 0x1f);
vgaw (ba, SEQ_ID_CURSOR_Y_INDEX, info->hot.y & 0x7f);
}
if (info->set & GRFSPRSET_CMAP)
{
/* hey cheat a bit here.. XXX */
vgaw (ba, SEQ_ID_CURSOR_COLOR0, 0);
vgaw (ba, SEQ_ID_CURSOR_COLOR1, 1);
}
if (info->set & GRFSPRSET_SHAPE)
{
int saved_bank_lo = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO);
int saved_bank_hi = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI);
int last_bank = SPRITE_ADDR >> 6;
int last_bank_lo = last_bank & 0xff;
int last_bank_hi = last_bank >> 8;
u_char mask;
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, last_bank_lo);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, last_bank_hi);
copyin (info->image, fb, 128*4);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, saved_bank_lo);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, saved_bank_hi);
copyin (info->mask, &mask, 1);
WSeq (ba, SEQ_ID_CURSOR_PIXELMASK, mask);
/* info->size.x = 32; *//* ??? */
info->size.y = (RSeq (ba, SEQ_ID_CURSOR_CONTROL) & 6) << 4;
control = (control & ~6) | ((info->size.y >> 4) & 6);
vgaw (ba, SEQ_ID_CURSOR_CONTROL, control);
/* sick intel bull-addressing.. */
WSeq (ba, SEQ_ID_CURSOR_STORE_LO, SPRITE_ADDR & 0x0f);
WSeq (ba, SEQ_ID_CURSOR_STORE_HI, 0);
WSeq (ba, SEQ_ID_CURSOR_ST_OFF_LO, (SPRITE_ADDR >> 4) & 0xff);
WSeq (ba, SEQ_ID_CURSOR_ST_OFF_HI, ((SPRITE_ADDR >> 4) >> 8) & 0xff);
}
return 0;
}
int
rt_getspritemax (gp, pos)
struct grf_softc *gp;
struct grf_position *pos;
{
pos->x = 32;
pos->y = 128;
return 0;
}
/*
* !!! THIS AREA UNDER CONSTRUCTION !!!
*/
int
rt_bitblt (gp, bb)
struct grf_softc *gp;
struct grf_bitblt *bb;
{
return EINVAL;
#if 0
volatile unsigned char *ba, *fb;
u_char control;
u_char saved_bank_lo;
u_char saved_bank_hi;
u_char src_bank_lo, src_bank_hi;
u_char dst_bank_lo, dst_bank_hi;
u_long src_offset, dst_offset;
u_short src_bank, dst_bank;
u_char *srcp, *dstp;
short x, y;
u_long tot;
ba = gp->g_regkva;
fb = gp->g_fbkva;
saved_bank_lo = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO);
saved_bank_hi = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI);
/* for now, only GRFBBcopy is supported, and only for depth 8. No
clipping is performed, either... */
if (bb->op != GRFBBcopy && gp->g_display.gd_planes != 8)
return EINVAL;
src_offset = op->src_x + op->src_y * gp->g_display.gd_fbwidth;
dst_offset = op->dst_x + op->dst_y * gp->g_display.gd_fbwidth;
tot = op->w * op->h;
/* set write mode 1, "[...] data in the read latches is written
to memory during CPU memory write cycles. [...]" */
WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1);
/* write to primary, read from secondary */
WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 );
if (src_offset < dst_offset)
{
/* start at end */
src_offset += tot;
dst_offset += tot;
}
src_bank_lo = (src_offset >> 6) & 0xff;
src_bank_hi = (src_offset >> 14) & 0xff;
dst_bank_lo = (dst_offset >> 6) & 0xff;
dst_bank_hi = (dst_offset >> 14) & 0xff;
while (tot)
{
WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, src_bank_lo);
WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, src_bank_hi);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, dst_bank_lo);
WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, dst_bank_hi);
if (src_offset < dst_offset)
{
}
else
{
}
}
#endif
}
#endif /* NGRF */