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