348 lines
8.9 KiB
C
348 lines
8.9 KiB
C
/* $Id: grf_cc.c,v 1.2 1993/08/02 18:33:32 mycroft Exp $ */
|
|
|
|
#include "grf.h"
|
|
#if NGRF > 0
|
|
|
|
/* Graphics routines for the AMIGA native custom chip set. */
|
|
|
|
#include "sys/param.h"
|
|
#include "sys/errno.h"
|
|
|
|
#include "grfioctl.h"
|
|
#include "grfvar.h"
|
|
#include "grf_ccreg.h"
|
|
|
|
#include "../include/cpu.h"
|
|
#include "../amiga/custom.h"
|
|
|
|
|
|
extern caddr_t CHIPMEMADDR;
|
|
extern caddr_t chipmem_steal ();
|
|
|
|
struct ccfb ccfb = {
|
|
DEF_DISP_WIDTH, DEF_DISP_HEIGHT, DEF_DISP_X, DEF_DISP_Y, DEF_DISP_Z,
|
|
0,
|
|
DEF_FB_WIDTH, DEF_FB_HEIGHT, DEF_FB_X, DEF_FB_Y, DEF_FB_Z,
|
|
DEF_COL0, DEF_COL1
|
|
};
|
|
|
|
/* Initialize one copper list. We'll need two to make a nice interlaced display. */
|
|
|
|
/* maximum size needed for a copper list (4 planes hires laced) */
|
|
#define COPENTS (4 * (2 * 4 + 2 + 1 + 2 + 2 + 2 + 16 * 1 + 1))
|
|
|
|
/* copper instructions */
|
|
#define MOVE(cl, reg, val) \
|
|
do { *cl++ = CUSTOM_OFS(reg); *cl++ = val; } while (0)
|
|
#define WAIT(cl, vp, hp, bfd, ve, he) \
|
|
do { *cl++ = ((vp & 0xff)<<8)|(hp & 0xfe)|1; \
|
|
*cl++ = (bfd<<15)|((ve & 0x7f)<<8)|(hp & 0xfe)|1; } while (0)
|
|
#define STOP(cl) \
|
|
do { *cl++ = 0xffff; *cl++ = 0xffff; } while (0)
|
|
|
|
static void
|
|
initcop (cop, othercop, shf, fb)
|
|
u_short *cop;
|
|
u_short *othercop;
|
|
int shf;
|
|
struct ccfb *fb;
|
|
{
|
|
long scrmem;
|
|
int i;
|
|
u_short c, strt, stop, *orig_cop = cop;
|
|
|
|
/* get PA of display area */
|
|
scrmem = (long) fb->fb - (long) CHIPMEMADDR;
|
|
|
|
othercop = (u_short *) ((long)othercop - (long) CHIPMEMADDR);
|
|
|
|
/* account for possible interlaced half-frame */
|
|
if (shf)
|
|
scrmem += fb->fb_width >> 3;
|
|
|
|
/* account for oversized framebuffers */
|
|
scrmem += (fb->fb_x >> 3) + (fb->fb_y * (fb->fb_width >> 3));
|
|
|
|
/* initialize bitplane pointers for all planes */
|
|
/* remember offset in copperlist to patch later */
|
|
if (! fb->bplstart_off)
|
|
fb->bplstart_off = cop - orig_cop;
|
|
for (i = 0; i < fb->disp_z; i++)
|
|
{
|
|
MOVE (cop, bplpth(i), scrmem >> 16);
|
|
MOVE (cop, bplptl(i), scrmem & 0xffff);
|
|
scrmem += (fb->fb_width >> 3) * fb->fb_height;
|
|
}
|
|
|
|
/* modulo is one line for interlaced displays, plus difference between
|
|
virtual and effective framebuffer size */
|
|
MOVE (cop, bpl1mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
|
|
MOVE (cop, bpl2mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
|
|
|
|
c = 0x8000 /* HIRES */
|
|
| ((fb->disp_z & 7) << 12) /* bitplane use */
|
|
| 0x0200 /* composite COLOR enable (whatever this is..) */
|
|
| 0x0004; /* LACE */
|
|
|
|
MOVE (cop, bplcon0, c);
|
|
|
|
/* these use pre-ECS register interpretation. Might want to go ECS ? */
|
|
strt = (((fb->disp_y >> 1) & 0xff)<<8) | ((fb->disp_x >> 1) & 0xff);
|
|
MOVE (cop, diwstrt, strt);
|
|
stop = (((((fb->disp_y + fb->disp_height + 1-shf)>>1) & 0xff)<<8)
|
|
| (((fb->disp_x + fb->disp_width)>>1) & 0xff));
|
|
MOVE (cop, diwstop, stop);
|
|
/* NOTE: default values for strt: 0x2c81, stop: 0xf4c1 */
|
|
|
|
/* these are from from HW-manual.. */
|
|
strt = ((strt & 0xff) - 9) >> 1;
|
|
MOVE (cop, ddfstrt, strt);
|
|
stop = strt + (((fb->disp_width >> 4) - 2) << 2);
|
|
MOVE (cop, ddfstop, stop);
|
|
|
|
/* setup interlaced display by constantly toggling between two copperlists */
|
|
MOVE (cop, cop1lch, (long)othercop >> 16);
|
|
MOVE (cop, cop1lcl, (long)othercop & 0xffff);
|
|
|
|
for (i = 0; i < (1 << fb->disp_z); i++)
|
|
MOVE (cop, color[i], fb->col[i]);
|
|
|
|
/* wait forever */
|
|
STOP (cop);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
dump_copperlist (cl)
|
|
u_int *cl;
|
|
{
|
|
while (*cl != 0xffffffff)
|
|
{
|
|
if (!(*cl & 0x00010000))
|
|
printf ("MOVE (%x, %x)\t", *cl & 0xffff, *cl >> 16);
|
|
else
|
|
printf ("WAIT (%d, %d, %d, %d, %d)\t", *cl >> 24, (*cl & 0x00fe0000)>>16,
|
|
(*cl & 0x8000)>> 15, (*cl & 0x7f00)>>8, (*cl & 0xfe));
|
|
cl++;
|
|
}
|
|
printf ("STOP ()\n");
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Initialize hardware.
|
|
* Must point g_display at a grfinfo structure describing the hardware.
|
|
* Returns 0 if hardware not present, non-zero ow.
|
|
*/
|
|
cc_init(gp, ad)
|
|
struct grf_softc *gp;
|
|
struct amiga_device *ad;
|
|
{
|
|
register struct ccfb *fb = &ccfb;
|
|
struct grfinfo *gi = &gp->g_display;
|
|
u_char *fbp, save;
|
|
int fboff, fbsize;
|
|
int s;
|
|
|
|
/* if already initialized, fail */
|
|
if (fb->fb)
|
|
return 0;
|
|
|
|
/* testing for the result is really redundant because chipmem_steal
|
|
panics if it runs out of memory.. */
|
|
fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z;
|
|
if (! (fb->fb = (u_char *) chipmem_steal (fbsize))
|
|
|| !(fb->cop1 = (u_short *) chipmem_steal (COPENTS))
|
|
|| !(fb->cop2 = (u_short *) chipmem_steal (COPENTS)))
|
|
return 0;
|
|
|
|
/* clear the display. bzero only likes regions up to 64k, so call multiple times */
|
|
for (fboff = 0; fboff < fbsize; fboff += 64*1024)
|
|
bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff);
|
|
|
|
initcop (fb->cop1, fb->cop2, 0, fb);
|
|
initcop (fb->cop2, fb->cop1, 1, fb);
|
|
|
|
/* Make sure no ex-sprites are streaking down the screen */
|
|
{
|
|
int i;
|
|
for(i = 0;i < 8;i++)
|
|
{
|
|
custom.spr[i].data = 0;
|
|
custom.spr[i].datb = 0;
|
|
}
|
|
}
|
|
|
|
/* start the new display */
|
|
/* disable these */
|
|
custom.dmacon = (DMAF_BLTDONE | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER
|
|
| DMAF_SPRITE | DMAF_DISK
|
|
| DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0);
|
|
/* enable these */
|
|
custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER;
|
|
|
|
#if 0
|
|
/* ok, this is a bit rough.. */
|
|
s = splhigh ();
|
|
/* load a first guess copperlist, verify later whether we got the right
|
|
one */
|
|
custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
|
|
custom.copjmp1 = 0;
|
|
/* reset VBL */
|
|
custom.intreq = INTF_VERTB;
|
|
/* wait for VBL */
|
|
while (! (custom.intreqr & INTF_VERTB)) ;
|
|
/* reset VBL */
|
|
custom.intreq = INTF_VERTB;
|
|
/* now, in a safe location, set correct copperlist based on longframe/shortframe
|
|
bit */
|
|
if (custom.vposr & 0x8000)
|
|
{
|
|
custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
|
|
custom.copjmp1 = 0; /* strobe it */
|
|
}
|
|
else
|
|
{
|
|
custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
|
|
custom.copjmp1 = 0;
|
|
}
|
|
/* wait for another VBL and reset int, then go back to previous int level */
|
|
while (! (custom.intreqr & INTF_VERTB)) ;
|
|
custom.intreq = INTF_VERTB;
|
|
splx (s);
|
|
#else
|
|
s = splhigh();
|
|
/* set up copper */
|
|
custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
|
|
custom.copjmp1 = 0;
|
|
|
|
/* reset vertical blank interrupt */
|
|
custom.intreq = INTF_VERTB;
|
|
|
|
/* wait for vertical blank interrupt */
|
|
while ((custom.intreqr & INTF_VERTB) != INTF_VERTB)
|
|
;
|
|
|
|
/* set bitplane pointers based on LOF/SHF bit */
|
|
if (custom.vposr & 0x8000)
|
|
{
|
|
custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
|
|
custom.copjmp1 = 0;
|
|
}
|
|
else
|
|
{
|
|
custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
|
|
custom.copjmp1 = 0;
|
|
}
|
|
splx (s);
|
|
#endif
|
|
|
|
/* tame the blitter. Copying one word onto itself should put it into
|
|
a consistent state. This is black magic... */
|
|
custom.bltapt =
|
|
custom.bltbpt =
|
|
custom.bltcpt =
|
|
custom.bltdpt = 0;
|
|
custom.bltamod =
|
|
custom.bltbmod =
|
|
custom.bltcmod =
|
|
custom.bltdmod = 0;
|
|
custom.bltafwm =
|
|
custom.bltalwn = 0xffff;
|
|
custom.bltcon0 = 0x09f0;
|
|
custom.bltcon1 = 0;
|
|
custom.bltsize = 1;
|
|
|
|
/* enable VBR interrupts. This is also done in the serial driver, but it
|
|
really belongs here.. */
|
|
custom.intena = INTF_SETCLR | INTF_VERTB;
|
|
|
|
#if 0
|
|
#ifdef DEBUG
|
|
/* prove the display is up.. */
|
|
for (fboff = 0; fboff < fbsize; fboff++)
|
|
{
|
|
fb->fb[fboff] = 0xff;
|
|
DELAY(10);
|
|
}
|
|
for (fboff = 0; fboff < fbsize; fboff++)
|
|
{
|
|
fb->fb[fboff] = 0;
|
|
DELAY(10);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
gi->gd_regaddr = (caddr_t) fb; /* XXX */
|
|
gi->gd_regsize = 0;
|
|
|
|
gi->gd_fbaddr = fb->fb - (u_char *) CHIPMEMADDR;
|
|
gi->gd_fbsize = fbsize;
|
|
|
|
gi->gd_colors = 1 << fb->fb_z;
|
|
gi->gd_planes = fb->fb_z;
|
|
|
|
gi->gd_fbwidth = fb->fb_width;
|
|
gi->gd_fbheight = fb->fb_height;
|
|
gi->gd_fbx = fb->fb_x;
|
|
gi->gd_fby = fb->fb_y;
|
|
gi->gd_dwidth = fb->disp_width;
|
|
gi->gd_dheight = fb->disp_height;
|
|
gi->gd_dx = fb->disp_x;
|
|
gi->gd_dy = fb->disp_y;
|
|
|
|
gp->g_regkva = 0; /* builtin */
|
|
gp->g_fbkva = fb->fb;
|
|
|
|
return(1);
|
|
}
|
|
|
|
cc_config(gp, di)
|
|
register struct grf_softc *gp;
|
|
struct grfdyninfo *di;
|
|
{
|
|
register struct ccfb *fb = &ccfb;
|
|
struct grfinfo *gi = &gp->g_display;
|
|
u_char *fbp, save;
|
|
int fboff, fbsize;
|
|
int s;
|
|
|
|
/* bottom missing... */
|
|
|
|
}
|
|
|
|
/*
|
|
* Change the mode of the display.
|
|
* Right now all we can do is grfon/grfoff.
|
|
* Return a UNIX error number or 0 for success.
|
|
*/
|
|
cc_mode(gp, cmd, arg)
|
|
register struct grf_softc *gp;
|
|
int cmd;
|
|
void *arg;
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case GM_GRFON:
|
|
custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER;
|
|
return 0;
|
|
|
|
case GM_GRFOFF:
|
|
custom.dmacon = DMAF_RASTER | DMAF_COPPER;
|
|
return 0;
|
|
|
|
case GM_GRFCONFIG:
|
|
return cc_config (gp, (struct grfdyninfo *) arg);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
#endif
|