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