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