Home | History | Annotate | Line # | Download | only in dev
grf_cc.c revision 1.2
      1  1.2  mycroft /*	$Id: grf_cc.c,v 1.2 1993/08/02 18:33:32 mycroft Exp $ */
      2  1.2  mycroft 
      3  1.1       mw #include "grf.h"
      4  1.1       mw #if NGRF > 0
      5  1.1       mw 
      6  1.1       mw /* Graphics routines for the AMIGA native custom chip set. */
      7  1.1       mw 
      8  1.1       mw #include "sys/param.h"
      9  1.1       mw #include "sys/errno.h"
     10  1.1       mw 
     11  1.1       mw #include "grfioctl.h"
     12  1.1       mw #include "grfvar.h"
     13  1.1       mw #include "grf_ccreg.h"
     14  1.1       mw 
     15  1.1       mw #include "../include/cpu.h"
     16  1.1       mw #include "../amiga/custom.h"
     17  1.1       mw 
     18  1.1       mw 
     19  1.1       mw extern caddr_t CHIPMEMADDR;
     20  1.1       mw extern caddr_t chipmem_steal ();
     21  1.1       mw 
     22  1.1       mw struct ccfb ccfb = {
     23  1.1       mw 	DEF_DISP_WIDTH, DEF_DISP_HEIGHT, DEF_DISP_X, DEF_DISP_Y, DEF_DISP_Z,
     24  1.1       mw 	0,
     25  1.1       mw 	DEF_FB_WIDTH, DEF_FB_HEIGHT, DEF_FB_X, DEF_FB_Y, DEF_FB_Z,
     26  1.1       mw 	DEF_COL0, DEF_COL1
     27  1.1       mw };
     28  1.1       mw 
     29  1.1       mw /* Initialize one copper list.  We'll need two to make a nice interlaced display.  */
     30  1.1       mw 
     31  1.1       mw /* maximum size needed for a copper list (4 planes hires laced) */
     32  1.1       mw #define COPENTS (4 * (2 * 4 + 2 + 1 + 2 + 2 + 2 + 16 * 1 + 1))
     33  1.1       mw 
     34  1.1       mw /* copper instructions */
     35  1.1       mw #define MOVE(cl, reg, val)  \
     36  1.1       mw 	do { *cl++ = CUSTOM_OFS(reg); *cl++ = val; } while (0)
     37  1.1       mw #define WAIT(cl, vp, hp, bfd, ve, he) \
     38  1.1       mw 	do { *cl++ = ((vp & 0xff)<<8)|(hp & 0xfe)|1; \
     39  1.1       mw 	*cl++ = (bfd<<15)|((ve & 0x7f)<<8)|(hp & 0xfe)|1; } while (0)
     40  1.1       mw #define STOP(cl) \
     41  1.1       mw 	do { *cl++ = 0xffff; *cl++ = 0xffff; } while (0)
     42  1.1       mw 
     43  1.1       mw static void
     44  1.1       mw initcop (cop, othercop, shf, fb)
     45  1.1       mw 	u_short *cop;
     46  1.1       mw 	u_short *othercop;
     47  1.1       mw 	int	shf;
     48  1.1       mw 	struct ccfb *fb;
     49  1.1       mw {
     50  1.1       mw   long scrmem;
     51  1.1       mw   int i;
     52  1.1       mw   u_short c, strt, stop, *orig_cop = cop;
     53  1.1       mw 
     54  1.1       mw   /* get PA of display area */
     55  1.1       mw   scrmem = (long) fb->fb - (long) CHIPMEMADDR;
     56  1.1       mw 
     57  1.1       mw   othercop = (u_short *) ((long)othercop - (long) CHIPMEMADDR);
     58  1.1       mw 
     59  1.1       mw   /* account for possible interlaced half-frame */
     60  1.1       mw   if (shf)
     61  1.1       mw     scrmem += fb->fb_width >> 3;
     62  1.1       mw 
     63  1.1       mw   /* account for oversized framebuffers */
     64  1.1       mw   scrmem += (fb->fb_x >> 3) + (fb->fb_y * (fb->fb_width >> 3));
     65  1.1       mw 
     66  1.1       mw   /* initialize bitplane pointers for all planes */
     67  1.1       mw   /* remember offset in copperlist to patch later */
     68  1.1       mw   if (! fb->bplstart_off)
     69  1.1       mw     fb->bplstart_off = cop - orig_cop;
     70  1.1       mw   for (i = 0; i < fb->disp_z; i++)
     71  1.1       mw     {
     72  1.1       mw       MOVE (cop, bplpth(i), scrmem >> 16);
     73  1.1       mw       MOVE (cop, bplptl(i), scrmem & 0xffff);
     74  1.1       mw       scrmem += (fb->fb_width >> 3) * fb->fb_height;
     75  1.1       mw     }
     76  1.1       mw 
     77  1.1       mw   /* modulo is one line for interlaced displays, plus difference between
     78  1.1       mw      virtual and effective framebuffer size */
     79  1.1       mw   MOVE (cop, bpl1mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
     80  1.1       mw   MOVE (cop, bpl2mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
     81  1.1       mw 
     82  1.1       mw   c =   0x8000 				/* HIRES */
     83  1.1       mw       | ((fb->disp_z & 7) << 12)	/* bitplane use */
     84  1.1       mw       | 0x0200				/* composite COLOR enable (whatever this is..) */
     85  1.1       mw       | 0x0004;				/* LACE */
     86  1.1       mw 
     87  1.1       mw   MOVE (cop, bplcon0, c);
     88  1.1       mw 
     89  1.1       mw   /* these use pre-ECS register interpretation. Might want to go ECS ? */
     90  1.1       mw   strt = (((fb->disp_y >> 1) & 0xff)<<8) | ((fb->disp_x >> 1) & 0xff);
     91  1.1       mw   MOVE (cop, diwstrt, strt);
     92  1.1       mw   stop = (((((fb->disp_y + fb->disp_height + 1-shf)>>1) & 0xff)<<8)
     93  1.1       mw           | (((fb->disp_x + fb->disp_width)>>1) & 0xff));
     94  1.1       mw   MOVE (cop, diwstop, stop);
     95  1.1       mw   /* NOTE: default values for strt: 0x2c81, stop: 0xf4c1 */
     96  1.1       mw 
     97  1.1       mw   /* these are from from HW-manual.. */
     98  1.1       mw   strt = ((strt & 0xff) - 9) >> 1;
     99  1.1       mw   MOVE (cop, ddfstrt, strt);
    100  1.1       mw   stop = strt + (((fb->disp_width >> 4) - 2) << 2);
    101  1.1       mw   MOVE (cop, ddfstop, stop);
    102  1.1       mw 
    103  1.1       mw   /* setup interlaced display by constantly toggling between two copperlists */
    104  1.1       mw   MOVE (cop, cop1lch, (long)othercop >> 16);
    105  1.1       mw   MOVE (cop, cop1lcl, (long)othercop & 0xffff);
    106  1.1       mw 
    107  1.1       mw   for (i = 0; i < (1 << fb->disp_z); i++)
    108  1.1       mw     MOVE (cop, color[i], fb->col[i]);
    109  1.1       mw 
    110  1.1       mw   /* wait forever */
    111  1.1       mw   STOP (cop);
    112  1.1       mw }
    113  1.1       mw 
    114  1.1       mw 
    115  1.1       mw #ifdef DEBUG
    116  1.1       mw void
    117  1.1       mw dump_copperlist (cl)
    118  1.1       mw     u_int *cl;
    119  1.1       mw {
    120  1.1       mw   while (*cl != 0xffffffff)
    121  1.1       mw     {
    122  1.1       mw       if (!(*cl & 0x00010000))
    123  1.1       mw         printf ("MOVE (%x, %x)\t", *cl & 0xffff, *cl >> 16);
    124  1.1       mw       else
    125  1.1       mw         printf ("WAIT (%d, %d, %d, %d, %d)\t", *cl >> 24, (*cl & 0x00fe0000)>>16,
    126  1.1       mw 		(*cl & 0x8000)>> 15, (*cl & 0x7f00)>>8, (*cl & 0xfe));
    127  1.1       mw       cl++;
    128  1.1       mw     }
    129  1.1       mw   printf ("STOP ()\n");
    130  1.1       mw 
    131  1.1       mw }
    132  1.1       mw #endif
    133  1.1       mw 
    134  1.1       mw 
    135  1.1       mw /*
    136  1.1       mw  * Initialize hardware.
    137  1.1       mw  * Must point g_display at a grfinfo structure describing the hardware.
    138  1.1       mw  * Returns 0 if hardware not present, non-zero ow.
    139  1.1       mw  */
    140  1.1       mw cc_init(gp, ad)
    141  1.1       mw 	struct grf_softc *gp;
    142  1.1       mw 	struct amiga_device *ad;
    143  1.1       mw {
    144  1.1       mw   register struct ccfb *fb = &ccfb;
    145  1.1       mw   struct grfinfo *gi = &gp->g_display;
    146  1.1       mw   u_char *fbp, save;
    147  1.1       mw   int fboff, fbsize;
    148  1.1       mw   int s;
    149  1.1       mw 
    150  1.1       mw   /* if already initialized, fail */
    151  1.1       mw   if (fb->fb)
    152  1.1       mw     return 0;
    153  1.1       mw 
    154  1.1       mw   /* testing for the result is really redundant because chipmem_steal
    155  1.1       mw      panics if it runs out of memory.. */
    156  1.1       mw   fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z;
    157  1.1       mw   if (! (fb->fb = (u_char *) chipmem_steal (fbsize))
    158  1.1       mw       || !(fb->cop1 = (u_short *) chipmem_steal (COPENTS))
    159  1.1       mw       || !(fb->cop2 = (u_short *) chipmem_steal (COPENTS)))
    160  1.1       mw     return 0;
    161  1.1       mw 
    162  1.1       mw   /* clear the display. bzero only likes regions up to 64k, so call multiple times */
    163  1.1       mw   for (fboff = 0; fboff < fbsize; fboff += 64*1024)
    164  1.1       mw     bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff);
    165  1.1       mw 
    166  1.1       mw   initcop (fb->cop1, fb->cop2, 0, fb);
    167  1.1       mw   initcop (fb->cop2, fb->cop1, 1, fb);
    168  1.1       mw 
    169  1.1       mw   /* Make sure no ex-sprites are streaking down the screen */
    170  1.1       mw   {
    171  1.1       mw     int i;
    172  1.1       mw     for(i = 0;i < 8;i++)
    173  1.1       mw       {
    174  1.1       mw         custom.spr[i].data = 0;
    175  1.1       mw         custom.spr[i].datb = 0;
    176  1.1       mw       }
    177  1.1       mw   }
    178  1.1       mw 
    179  1.1       mw   /* start the new display */
    180  1.1       mw   /* disable these */
    181  1.1       mw   custom.dmacon  = (DMAF_BLTDONE | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER
    182  1.1       mw 		    | DMAF_SPRITE | DMAF_DISK
    183  1.1       mw  		    | DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0);
    184  1.1       mw   /* enable these */
    185  1.1       mw   custom.dmacon  = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER;
    186  1.1       mw 
    187  1.1       mw #if 0
    188  1.1       mw   /* ok, this is a bit rough.. */
    189  1.1       mw   s = splhigh ();
    190  1.1       mw   /* load a first guess copperlist, verify later whether we got the right
    191  1.1       mw      one */
    192  1.1       mw   custom.cop1lc  = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
    193  1.1       mw   custom.copjmp1 = 0;
    194  1.1       mw   /* reset VBL */
    195  1.1       mw   custom.intreq = INTF_VERTB;
    196  1.1       mw   /* wait for VBL */
    197  1.1       mw   while (! (custom.intreqr & INTF_VERTB)) ;
    198  1.1       mw   /* reset VBL */
    199  1.1       mw   custom.intreq = INTF_VERTB;
    200  1.1       mw   /* now, in a safe location, set correct copperlist based on longframe/shortframe
    201  1.1       mw      bit */
    202  1.1       mw   if (custom.vposr & 0x8000)
    203  1.1       mw     {
    204  1.1       mw       custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
    205  1.1       mw       custom.copjmp1 = 0;	/* strobe it */
    206  1.1       mw     }
    207  1.1       mw   else
    208  1.1       mw     {
    209  1.1       mw       custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
    210  1.1       mw       custom.copjmp1 = 0;
    211  1.1       mw     }
    212  1.1       mw   /* wait for another VBL and reset int, then go back to previous int level */
    213  1.1       mw   while (! (custom.intreqr & INTF_VERTB)) ;
    214  1.1       mw   custom.intreq = INTF_VERTB;
    215  1.1       mw   splx (s);
    216  1.1       mw #else
    217  1.1       mw   s = splhigh();
    218  1.1       mw   /* set up copper */
    219  1.1       mw   custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
    220  1.1       mw   custom.copjmp1 = 0;
    221  1.1       mw 
    222  1.1       mw   /* reset vertical blank interrupt */
    223  1.1       mw   custom.intreq = INTF_VERTB;
    224  1.1       mw 
    225  1.1       mw   /* wait for vertical blank interrupt */
    226  1.1       mw   while ((custom.intreqr & INTF_VERTB) != INTF_VERTB)
    227  1.1       mw 	;
    228  1.1       mw 
    229  1.1       mw   /* set bitplane pointers based on LOF/SHF bit */
    230  1.1       mw   if (custom.vposr & 0x8000)
    231  1.1       mw     {
    232  1.1       mw       custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
    233  1.1       mw       custom.copjmp1 = 0;
    234  1.1       mw     }
    235  1.1       mw   else
    236  1.1       mw     {
    237  1.1       mw       custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
    238  1.1       mw       custom.copjmp1 = 0;
    239  1.1       mw     }
    240  1.1       mw   splx (s);
    241  1.1       mw #endif
    242  1.1       mw 
    243  1.1       mw   /* tame the blitter. Copying one word onto itself should put it into
    244  1.1       mw      a consistent state. This is black magic... */
    245  1.1       mw   custom.bltapt =
    246  1.1       mw     custom.bltbpt =
    247  1.1       mw       custom.bltcpt =
    248  1.1       mw         custom.bltdpt = 0;
    249  1.1       mw   custom.bltamod =
    250  1.1       mw     custom.bltbmod =
    251  1.1       mw       custom.bltcmod =
    252  1.1       mw         custom.bltdmod = 0;
    253  1.1       mw   custom.bltafwm =
    254  1.1       mw     custom.bltalwn = 0xffff;
    255  1.1       mw   custom.bltcon0 = 0x09f0;
    256  1.1       mw   custom.bltcon1 = 0;
    257  1.1       mw   custom.bltsize = 1;
    258  1.1       mw 
    259  1.1       mw   /* enable VBR interrupts. This is also done in the serial driver, but it
    260  1.1       mw      really belongs here.. */
    261  1.1       mw   custom.intena = INTF_SETCLR | INTF_VERTB;
    262  1.1       mw 
    263  1.1       mw #if 0
    264  1.1       mw #ifdef DEBUG
    265  1.1       mw   /* prove the display is up.. */
    266  1.1       mw   for (fboff = 0; fboff < fbsize; fboff++)
    267  1.1       mw     {
    268  1.1       mw       fb->fb[fboff] = 0xff;
    269  1.1       mw       DELAY(10);
    270  1.1       mw     }
    271  1.1       mw   for (fboff = 0; fboff < fbsize; fboff++)
    272  1.1       mw     {
    273  1.1       mw       fb->fb[fboff] = 0;
    274  1.1       mw       DELAY(10);
    275  1.1       mw     }
    276  1.1       mw #endif
    277  1.1       mw #endif
    278  1.1       mw 
    279  1.1       mw   gi->gd_regaddr = (caddr_t) fb;	/* XXX */
    280  1.1       mw   gi->gd_regsize = 0;
    281  1.1       mw 
    282  1.1       mw   gi->gd_fbaddr  = fb->fb - (u_char *) CHIPMEMADDR;
    283  1.1       mw   gi->gd_fbsize  = fbsize;
    284  1.1       mw 
    285  1.1       mw   gi->gd_colors  = 1 << fb->fb_z;
    286  1.1       mw   gi->gd_planes  = fb->fb_z;
    287  1.1       mw 
    288  1.1       mw   gi->gd_fbwidth  = fb->fb_width;
    289  1.1       mw   gi->gd_fbheight = fb->fb_height;
    290  1.1       mw   gi->gd_fbx	  = fb->fb_x;
    291  1.1       mw   gi->gd_fby	  = fb->fb_y;
    292  1.1       mw   gi->gd_dwidth   = fb->disp_width;
    293  1.1       mw   gi->gd_dheight  = fb->disp_height;
    294  1.1       mw   gi->gd_dx	  = fb->disp_x;
    295  1.1       mw   gi->gd_dy	  = fb->disp_y;
    296  1.1       mw 
    297  1.1       mw   gp->g_regkva = 0;	/* builtin */
    298  1.1       mw   gp->g_fbkva  = fb->fb;
    299  1.1       mw 
    300  1.1       mw   return(1);
    301  1.1       mw }
    302  1.1       mw 
    303  1.1       mw cc_config(gp, di)
    304  1.1       mw 	register struct grf_softc *gp;
    305  1.1       mw 	struct grfdyninfo *di;
    306  1.1       mw {
    307  1.1       mw   register struct ccfb *fb = &ccfb;
    308  1.1       mw   struct grfinfo *gi = &gp->g_display;
    309  1.1       mw   u_char *fbp, save;
    310  1.1       mw   int fboff, fbsize;
    311  1.1       mw   int s;
    312  1.1       mw 
    313  1.1       mw   /* bottom missing... */
    314  1.1       mw 
    315  1.1       mw }
    316  1.1       mw 
    317  1.1       mw /*
    318  1.1       mw  * Change the mode of the display.
    319  1.1       mw  * Right now all we can do is grfon/grfoff.
    320  1.1       mw  * Return a UNIX error number or 0 for success.
    321  1.1       mw  */
    322  1.1       mw cc_mode(gp, cmd, arg)
    323  1.1       mw 	register struct grf_softc *gp;
    324  1.1       mw 	int cmd;
    325  1.1       mw 	void *arg;
    326  1.1       mw {
    327  1.1       mw   switch (cmd)
    328  1.1       mw     {
    329  1.1       mw     case GM_GRFON:
    330  1.1       mw       custom.dmacon  = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER;
    331  1.1       mw       return 0;
    332  1.1       mw 
    333  1.1       mw     case GM_GRFOFF:
    334  1.1       mw       custom.dmacon  = DMAF_RASTER | DMAF_COPPER;
    335  1.1       mw       return 0;
    336  1.1       mw 
    337  1.1       mw     case GM_GRFCONFIG:
    338  1.1       mw       return cc_config (gp, (struct grfdyninfo *) arg);
    339  1.1       mw 
    340  1.1       mw     default:
    341  1.1       mw       break;
    342  1.1       mw     }
    343  1.1       mw 
    344  1.1       mw   return EINVAL;
    345  1.1       mw }
    346  1.1       mw 
    347  1.1       mw #endif
    348