1bdcaa8d0Smrg/*
2bdcaa8d0Smrg * file vmodes.c
3bdcaa8d0Smrg *
4bdcaa8d0Smrg * Routines that handle mode setting.
5bdcaa8d0Smrg */
6bdcaa8d0Smrg
7bdcaa8d0Smrg#ifdef HAVE_CONFIG_H
8bdcaa8d0Smrg#include "config.h"
9bdcaa8d0Smrg#endif
10bdcaa8d0Smrg
11bdcaa8d0Smrg/*
12bdcaa8d0Smrg * includes
13bdcaa8d0Smrg */
14bdcaa8d0Smrg
15bdcaa8d0Smrg#include "rendition.h"
16bdcaa8d0Smrg#include "vmodes.h"
17bdcaa8d0Smrg#include "vos.h"
18bdcaa8d0Smrg#include "vramdac.h"
19bdcaa8d0Smrg#include "v1krisc.h"
20bdcaa8d0Smrg#include "v1kregs.h"
21bdcaa8d0Smrg#include "v2kregs.h"
22bdcaa8d0Smrg
23880c7e28Smrg#include <unistd.h>
24bdcaa8d0Smrg
25bdcaa8d0Smrg#undef DEBUG
26bdcaa8d0Smrg
27bdcaa8d0Smrg
28bdcaa8d0Smrg/*
29bdcaa8d0Smrg * defines
30bdcaa8d0Smrg */
31bdcaa8d0Smrg
32bdcaa8d0Smrg#define combineNMP(N, M, P) \
33bdcaa8d0Smrg    (((vu32)(M-2)<<10) | ((vu32)P<<8) | (vu32)(N-2))
34bdcaa8d0Smrg
35bdcaa8d0Smrg#define v2kcombineNMP(N, M, P) (((vu32)N<<13) | ((vu32)P<<9) | (vu32)M)
36bdcaa8d0Smrg
37bdcaa8d0Smrg/* defines for doubled clock */
38bdcaa8d0Smrg#define CLK_DOUBLE		1
39bdcaa8d0Smrg#define NO_CLK_DOUBLE	0
40bdcaa8d0Smrg
41bdcaa8d0Smrg/* video FIFO is set to 64 or 128 entries based on req.d bandwidth in bytes/s */
42bdcaa8d0Smrg#define FIFOSIZE_THRESH 	100000000 	 /* set thresh to 100MB/s */
43bdcaa8d0Smrg
44bdcaa8d0Smrg/* compute desired video FIFO size given total bandwidth in bytes/s. */
45bdcaa8d0Smrg#define FIFOSIZE(vclk, Bpp) (((vclk * Bpp) > FIFOSIZE_THRESH)  ? 128 : 64)
46bdcaa8d0Smrg
47bdcaa8d0Smrg/* Bt485A RAMDAC control bits */
48bdcaa8d0Smrg#define PALETTEDISABLE		0x10
49bdcaa8d0Smrg
50bdcaa8d0Smrg/* Hold memory refresh cycles until video blank */
51bdcaa8d0Smrg#define HOLD_MEMREFRESHCYCLE 0x2000
52bdcaa8d0Smrg
53bdcaa8d0Smrg/* memCtl bits [16..23] */
54bdcaa8d0Smrg#define DEFAULT_WREFRESH	0x330000
55bdcaa8d0Smrg
56bdcaa8d0Smrg/* Disable memory refresh cycles */
57bdcaa8d0Smrg#define DISABLE_MEMREFRESHCYCLE		0x8000
58bdcaa8d0Smrg
59bdcaa8d0Smrg#define CTL(ldbl, hsynchi, vsynchi) \
60bdcaa8d0Smrg  (((ldbl) ? CRTCCTL_LINEDOUBLE : 0) \
61bdcaa8d0Smrg  |((hsynchi) ? CRTCCTL_HSYNCHI : 0) \
62bdcaa8d0Smrg  |((vsynchi) ? CRTCCTL_VSYNCHI : 0) \
63bdcaa8d0Smrg  |(CRTCCTL_VSYNCENABLE | CRTCCTL_HSYNCENABLE))
64bdcaa8d0Smrg
65bdcaa8d0Smrg#define HORZ(fp, sy, bp, ac) \
66bdcaa8d0Smrg  (((((vu32)(((fp)>>3)-1))&7)<<21)|((((vu32)(((sy)>>3)-1))&0x1F)<<16)|((((vu32)(((bp)>>3)-1))&0x3f)<<9)|((((vu32)(((ac)>>3)-1))&0xff)))
67bdcaa8d0Smrg
68bdcaa8d0Smrg#define VERT(fp, sy, bp, ac) \
69bdcaa8d0Smrg  (((((vu32)(fp-1))&0x3f)<<20)|((((vu32)(sy-1))&0x7)<<17)|((((vu32)(bp-1))&0x3f)<<11)|((((vu32)(ac-1))&0x7ff)))
70bdcaa8d0Smrg
71bdcaa8d0Smrg#define HORZAC(crtchorz) \
72bdcaa8d0Smrg  (((((vu32)crtchorz)&CRTCHORZ_ACTIVE_MASK)+1)<<3)
73bdcaa8d0Smrg
74bdcaa8d0Smrg#define HORZBP(crtchorz) \
75bdcaa8d0Smrg  ((((((vu32)crtchorz)&CRTCHORZ_BACKPORCH_MASK)>>9)+1)<<3)
76bdcaa8d0Smrg
77bdcaa8d0Smrg#define HORZSY(crtchorz) \
78bdcaa8d0Smrg  ((((((vu32)crtchorz)&CRTCHORZ_SYNC_MASK)>>16)+1)<<3)
79bdcaa8d0Smrg
80bdcaa8d0Smrg#define HORZFP(crtchorz) \
81bdcaa8d0Smrg  ((((((vu32)crtchorz)&CRTCHORZ_FRONTPORCH_MASK)>>21)+1)<<3)
82bdcaa8d0Smrg
83bdcaa8d0Smrg#define VERTAC(crtcvert) \
84bdcaa8d0Smrg  ((((vu32)crtcvert)&CRTCVERT_ACTIVE_MASK)+1)
85bdcaa8d0Smrg
86bdcaa8d0Smrg#define VERTBP(crtcvert) \
87bdcaa8d0Smrg  (((((vu32)crtcvert)&CRTCVERT_BACKPORCH_MASK)>>11)+1)
88bdcaa8d0Smrg
89bdcaa8d0Smrg#define VERTSY(crtcvert) \
90bdcaa8d0Smrg  (((((vu32)crtcvert)&CRTCVERT_SYNC_MASK)>>17)+1)
91bdcaa8d0Smrg
92bdcaa8d0Smrg#define VERTFP(crtcvert) \
93bdcaa8d0Smrg  (((((vu32)crtcvert)&CRTCVERT_FRONTPORCH_MASK)>>20)+1)
94bdcaa8d0Smrg
95bdcaa8d0Smrg#define PCLK(N, M, P) (N),(M),(P)
96bdcaa8d0Smrg
97bdcaa8d0Smrg#define TIMING_MASK	(CRTCCTL_VIDEOFIFOSIZE128|CRTCCTL_LINEDOUBLE|\
98bdcaa8d0Smrg			         CRTCCTL_VSYNCHI|CRTCCTL_HSYNCHI|CRTCCTL_VSYNCENABLE|\
99bdcaa8d0Smrg                     CRTCCTL_HSYNCENABLE)
100bdcaa8d0Smrg
101bdcaa8d0Smrg/* addr&7 == 5, 6, 7 are bad */
102bdcaa8d0Smrg#define BADADDR(x)	(((x)&(((x)<<1)|((x)<<2)))&0x4)
103bdcaa8d0Smrg
104bdcaa8d0Smrg#define V1_MIN_VCO_FREQ  25
105bdcaa8d0Smrg#define V1_MAX_VCO_FREQ  135
106bdcaa8d0Smrg#define V1_REF_FREQ      14.318
107bdcaa8d0Smrg#define V1_MIN_PCF_FREQ  0.2
108bdcaa8d0Smrg#define V1_MAX_PCF_FREQ  5
109bdcaa8d0Smrg
110bdcaa8d0Smrg#define V2_MIN_VCO_FREQ  125
111bdcaa8d0Smrg#define V2_MAX_VCO_FREQ  250
112bdcaa8d0Smrg#define V2_REF_FREQ      14.31818 /* Eh, is this right? */
113bdcaa8d0Smrg#define V2_MIN_PCF_FREQ  1
114bdcaa8d0Smrg#define V2_MAX_PCF_FREQ  3
115bdcaa8d0Smrg
116bdcaa8d0Smrg
117bdcaa8d0Smrg
118bdcaa8d0Smrg/*
119bdcaa8d0Smrg * global data
120bdcaa8d0Smrg */
121bdcaa8d0Smrg
122bdcaa8d0Smrgstatic struct width_to_stride_t {
123bdcaa8d0Smrg    vu32 width8bpp;
124bdcaa8d0Smrg    vu8 stride0;
125bdcaa8d0Smrg    vu8 stride1;
126bdcaa8d0Smrg    vu16 chip;
127bdcaa8d0Smrg} width_to_stride_table[]={
128bdcaa8d0Smrg/*  {    0, 0, 0, V1000_DEVICE }, */
129bdcaa8d0Smrg    {    4, 4, 0, V1000_DEVICE },
130bdcaa8d0Smrg    {   16, 0, 1, V1000_DEVICE },
131bdcaa8d0Smrg    {   20, 4, 1, V1000_DEVICE },
132bdcaa8d0Smrg    {   32, 0, 2, V1000_DEVICE },
133bdcaa8d0Smrg    {   36, 4, 2, V1000_DEVICE },
134bdcaa8d0Smrg    {   64, 0, 3, V1000_DEVICE },
135bdcaa8d0Smrg    {   68, 4, 3, V1000_DEVICE },
136bdcaa8d0Smrg    {  128, 0, 4, V1000_DEVICE },
137bdcaa8d0Smrg    {  132, 4, 4, V1000_DEVICE },
138bdcaa8d0Smrg    {  256, 1, 0, V1000_DEVICE },
139bdcaa8d0Smrg    {  272, 1, 1, V1000_DEVICE },
140bdcaa8d0Smrg    {  288, 1, 2, V1000_DEVICE },
141bdcaa8d0Smrg    {  320, 1, 3, V1000_DEVICE },
142bdcaa8d0Smrg    {  384, 1, 4, V1000_DEVICE },
143bdcaa8d0Smrg    {  512, 2, 0, V1000_DEVICE },
144bdcaa8d0Smrg    {  528, 2, 1, V1000_DEVICE },
145bdcaa8d0Smrg    {  544, 2, 2, V1000_DEVICE },
146bdcaa8d0Smrg    {  576, 2, 3, V1000_DEVICE },
147bdcaa8d0Smrg    {  592, 6, 1, V2000_DEVICE },
148bdcaa8d0Smrg    {  608, 6, 2, V2000_DEVICE },
149bdcaa8d0Smrg    {  640, 2, 4, V1000_DEVICE },
150bdcaa8d0Smrg    {  704, 6, 4, V2000_DEVICE },
151bdcaa8d0Smrg    {  768, 5, 0, V2000_DEVICE },
152bdcaa8d0Smrg    {  784, 5, 1, V2000_DEVICE },
153bdcaa8d0Smrg    {  800, 5, 2, V2000_DEVICE },
154bdcaa8d0Smrg    {  832, 5, 3, V2000_DEVICE },
155bdcaa8d0Smrg    {  896, 5, 4, V2000_DEVICE },
156bdcaa8d0Smrg    { 1024, 3, 0, V1000_DEVICE },
157bdcaa8d0Smrg    { 1028, 4, 5, V1000_DEVICE },
158bdcaa8d0Smrg    { 1040, 3, 1, V1000_DEVICE },
159bdcaa8d0Smrg    { 1056, 3, 2, V1000_DEVICE },
160bdcaa8d0Smrg    { 1088, 3, 3, V1000_DEVICE },
161bdcaa8d0Smrg    { 1152, 3, 4, V1000_DEVICE },
162bdcaa8d0Smrg    { 1168, 7, 1, V2000_DEVICE },
163bdcaa8d0Smrg    { 1184, 7, 2, V2000_DEVICE },
164bdcaa8d0Smrg    { 1216, 7, 3, V2000_DEVICE },
165bdcaa8d0Smrg    { 1280, 1, 5, V1000_DEVICE },
166bdcaa8d0Smrg    { 1536, 2, 5, V1000_DEVICE },
167bdcaa8d0Smrg    { 1600, 6, 5, V2000_DEVICE },
168bdcaa8d0Smrg    { 1792, 5, 5, V2000_DEVICE },
169bdcaa8d0Smrg    { 2048, 0, 6, V1000_DEVICE },
170bdcaa8d0Smrg    { 2052, 4, 6, V1000_DEVICE },
171bdcaa8d0Smrg    { 2176, 7, 5, V2000_DEVICE },
172bdcaa8d0Smrg    { 2304, 1, 6, V1000_DEVICE },
173bdcaa8d0Smrg    { 2560, 2, 6, V1000_DEVICE },
174bdcaa8d0Smrg    { 2624, 6, 6, V2000_DEVICE },
175bdcaa8d0Smrg    { 2816, 5, 6, V2000_DEVICE },
176bdcaa8d0Smrg    { 3072, 3, 6, V1000_DEVICE },
177bdcaa8d0Smrg    { 3200, 7, 6, V2000_DEVICE },
178bdcaa8d0Smrg    { 4096, 0, 7, V1000_DEVICE },
179bdcaa8d0Smrg    { 4100, 4, 7, V1000_DEVICE },
180bdcaa8d0Smrg    { 4352, 1, 7, V1000_DEVICE },
181bdcaa8d0Smrg    { 4608, 2, 7, V1000_DEVICE },
182bdcaa8d0Smrg    { 4672, 6, 7, V2000_DEVICE },
183bdcaa8d0Smrg    { 4864, 5, 7, V2000_DEVICE },
184bdcaa8d0Smrg    { 5120, 3, 7, V1000_DEVICE },
185bdcaa8d0Smrg    { 5248, 7, 7, V2000_DEVICE },
186bdcaa8d0Smrg    {    0, 0, 0, 0 }
187bdcaa8d0Smrg};
188bdcaa8d0Smrg
189bdcaa8d0Smrgstruct V1000ClocksStr {
190bdcaa8d0Smrg    int h_size;
191bdcaa8d0Smrg    int pll_val;
192bdcaa8d0Smrg} V1000Clocks [] = {
193bdcaa8d0Smrg    { 72, 0x40000 }, /* For Textmode */
194bdcaa8d0Smrg    { 640, 0x2408 },   /*  31500  MHz */
195bdcaa8d0Smrg    { 800, 0x1583D },  /*  40000  MHz */
196bdcaa8d0Smrg    { 1024, 0x14823 }, /*  65000  MHz */
197bdcaa8d0Smrg    { 1280, 0x14414 }, /*  108000 MHz */
198bdcaa8d0Smrg    { 0, 0 }
199bdcaa8d0Smrg};
200bdcaa8d0Smrg
201bdcaa8d0Smrg/*
202bdcaa8d0Smrg * local function prototypes
203bdcaa8d0Smrg */
204bdcaa8d0Smrg
205880c7e28Smrgstatic void set_PLL(unsigned long iob, vu32 value);
206bdcaa8d0Smrgstatic double V1000CalcClock(double target, int *M, int *N, int *P);
207bdcaa8d0Smrgstatic double V2200CalcClock(double target, int *m, int *n, int *p);
208bdcaa8d0Smrg
209bdcaa8d0Smrg
210bdcaa8d0Smrg
211bdcaa8d0Smrg/*
212bdcaa8d0Smrg * functions
213bdcaa8d0Smrg */
214bdcaa8d0Smrg
215bdcaa8d0Smrgint
216bdcaa8d0Smrgverite_setmode(ScrnInfoPtr pScreenInfo, struct verite_modeinfo_t *mode)
217bdcaa8d0Smrg{
218bdcaa8d0Smrg    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
219bdcaa8d0Smrg
220bdcaa8d0Smrg    int tmp;
221bdcaa8d0Smrg    int doubleclock=0;
222bdcaa8d0Smrg    int M, N, P;
223bdcaa8d0Smrg    int iob=pRendition->board.io_base;
224bdcaa8d0Smrg
225bdcaa8d0Smrg#ifdef DEBUG
226bdcaa8d0Smrg    ErrorF ("Rendition: Debug verite_setmode called\n");
227bdcaa8d0Smrg#endif
228bdcaa8d0Smrg
229bdcaa8d0Smrg    /* switching to native mode */
230bdcaa8d0Smrg    verite_out8(iob+MODEREG, NATIVE_MODE|VESA_MODE);
231bdcaa8d0Smrg
232bdcaa8d0Smrg    /* flipping some bytes */
233bdcaa8d0Smrg    /* Must be something better to do than this -- FIX */
234bdcaa8d0Smrg    switch (mode->bitsperpixel) {
235bdcaa8d0Smrg    case 32:
236bdcaa8d0Smrg      verite_out8(iob+MEMENDIAN, MEMENDIAN_NO);
237bdcaa8d0Smrg      break;
238bdcaa8d0Smrg    case 16:
239bdcaa8d0Smrg      verite_out8(iob+MEMENDIAN, MEMENDIAN_HW);
240bdcaa8d0Smrg      break;
241bdcaa8d0Smrg    case 8:
242bdcaa8d0Smrg      verite_out8(iob+MEMENDIAN, MEMENDIAN_END);
243bdcaa8d0Smrg      break;
244bdcaa8d0Smrg    }
245bdcaa8d0Smrg
246bdcaa8d0Smrg    if (pRendition->board.chip != V1000_DEVICE) {
247bdcaa8d0Smrg      if(!pRendition->board.overclock_mem){
248bdcaa8d0Smrg	verite_out32(iob+SCLKPLL, 0xa484d);  /* mclk=110 sclk=50 */
249bdcaa8d0Smrg                                        /* M/N/P/P = 77/5/2/4 */
250bdcaa8d0Smrg      }
251bdcaa8d0Smrg      else{
252bdcaa8d0Smrg	xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG,
253bdcaa8d0Smrg		   (" *** OVERCLOCKING MEM/CLK mclk=125 sclk=60 ***\n"));
254bdcaa8d0Smrg	/* increase Mem/Sys clock on request */
255bdcaa8d0Smrg	verite_out32(iob+SCLKPLL, 0xa4854);  /* mclk=125 sclk=60 */
256bdcaa8d0Smrg                                        /* M/N/P/P = 84/5/2/4 */
257bdcaa8d0Smrg      }
258bdcaa8d0Smrg      usleep(500);
259bdcaa8d0Smrg    }
260bdcaa8d0Smrg
261bdcaa8d0Smrg    /* this has something to do with memory */
262bdcaa8d0Smrg    tmp=verite_in32(iob+DRAMCTL)&0xdfff;              /* reset bit 13 */
263bdcaa8d0Smrg    verite_out32(iob+DRAMCTL, tmp|0x330000);
264bdcaa8d0Smrg
265bdcaa8d0Smrg    /* program pixel clock */
266bdcaa8d0Smrg    if (pRendition->board.chip == V1000_DEVICE) {
267bdcaa8d0Smrg        if (110.0 < V1000CalcClock(mode->clock/1000.0, &M, &N, &P)) {
268bdcaa8d0Smrg            P++;
269bdcaa8d0Smrg            doubleclock=1;
270bdcaa8d0Smrg        }
271bdcaa8d0Smrg        set_PLL(iob, combineNMP(N, M, P));
272bdcaa8d0Smrg    }
273bdcaa8d0Smrg    else {
274bdcaa8d0Smrg	tmp = (~0x1800) & verite_in32(iob+DRAMCTL);
275bdcaa8d0Smrg        verite_out32(iob+DRAMCTL, tmp);
276bdcaa8d0Smrg        V2200CalcClock(mode->clock/1000.0, &M, &N, &P);
277bdcaa8d0Smrg        verite_out32(iob+PCLKPLL, v2kcombineNMP(N, M, P));
278bdcaa8d0Smrg    }
279bdcaa8d0Smrg    usleep(500);
280bdcaa8d0Smrg
281bdcaa8d0Smrg    /* init the ramdac */
282bdcaa8d0Smrg    verite_initdac(pScreenInfo, mode->bitsperpixel, doubleclock);
283bdcaa8d0Smrg
284bdcaa8d0Smrg    verite_out32(iob+CRTCHORZ, HORZ(mode->hsyncstart - mode->hdisplay,
285bdcaa8d0Smrg                               mode->hsyncend - mode->hsyncstart,
286bdcaa8d0Smrg                               mode->htotal - mode->hsyncend,
287bdcaa8d0Smrg                               mode->hdisplay));
288bdcaa8d0Smrg    verite_out32(iob+CRTCVERT, VERT(mode->vsyncstart-mode->vdisplay,
289bdcaa8d0Smrg                               mode->vsyncend-mode->vsyncstart,
290bdcaa8d0Smrg                               mode->vtotal-mode->vsyncend,
291bdcaa8d0Smrg                               mode->vdisplay));
292bdcaa8d0Smrg
293bdcaa8d0Smrg    /* fill in the mode parameters */
294bdcaa8d0Smrg    memcpy(&(pRendition->board.mode), mode, sizeof(struct verite_modeinfo_t));
295bdcaa8d0Smrg    pRendition->board.mode.fifosize=128;
296bdcaa8d0Smrg    pRendition->board.mode.pll_m=M;
297bdcaa8d0Smrg    pRendition->board.mode.pll_n=N;
298bdcaa8d0Smrg    pRendition->board.mode.pll_p=P;
299bdcaa8d0Smrg    pRendition->board.mode.doubleclock=doubleclock;
300bdcaa8d0Smrg    if (0 == pRendition->board.mode.virtualwidth)
301bdcaa8d0Smrg        pRendition->board.mode.virtualwidth=pRendition->board.mode.screenwidth;
302bdcaa8d0Smrg
303bdcaa8d0Smrg    pRendition->board.init=1;
304880c7e28Smrg    (*pScreenInfo->AdjustFrame)(ADJUST_FRAME_ARGS(pScreenInfo,
305880c7e28Smrg						  pScreenInfo->frameX0, pScreenInfo->frameY0));
306bdcaa8d0Smrg
307bdcaa8d0Smrg    /* Need to fix up syncs */
308bdcaa8d0Smrg
309bdcaa8d0Smrg    /* enable the display */
310bdcaa8d0Smrg    verite_out32(iob+CRTCCTL, CTL(0, mode->hsynchi, mode->vsynchi)
311bdcaa8d0Smrg                        |mode->pixelformat
312bdcaa8d0Smrg                        |CRTCCTL_VIDEOFIFOSIZE128
313bdcaa8d0Smrg                        |CRTCCTL_HSYNCENABLE
314bdcaa8d0Smrg                        |CRTCCTL_VSYNCENABLE
315bdcaa8d0Smrg                        |CRTCCTL_VIDEOENABLE);
316bdcaa8d0Smrg
317bdcaa8d0Smrg#ifdef DEBUG
318bdcaa8d0Smrg    ErrorF ("Interlace mode -> %d\n", mode->flags);
319bdcaa8d0Smrg    xf86sleep(10);ErrorF ("...Exit SetMode...\n");
320bdcaa8d0Smrg#endif
321bdcaa8d0Smrg
322bdcaa8d0Smrg   return 0;
323bdcaa8d0Smrg}
324bdcaa8d0Smrg
325bdcaa8d0Smrgstatic double
326bdcaa8d0Smrgverite_findtextclock(int width)
327bdcaa8d0Smrg{
328bdcaa8d0Smrg    int i = 0, val;
329bdcaa8d0Smrg    while ((val = V1000Clocks[i].h_size) > 0) {
330bdcaa8d0Smrg	if (val > width)
331bdcaa8d0Smrg	    break;
332bdcaa8d0Smrg	else
333bdcaa8d0Smrg	    i++;
334bdcaa8d0Smrg    }
335bdcaa8d0Smrg    if (i > 0) i--;
336bdcaa8d0Smrg    return V1000Clocks[i].pll_val;
337bdcaa8d0Smrg}
338bdcaa8d0Smrg
339bdcaa8d0Smrgvoid
340bdcaa8d0Smrgverite_save(ScrnInfoPtr pScreenInfo)
341bdcaa8d0Smrg{
342bdcaa8d0Smrg    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
343bdcaa8d0Smrg    int iob=pRendition->board.io_base;
344bdcaa8d0Smrg    RenditionRegPtr reg = &pRendition->saveRegs;
345bdcaa8d0Smrg
346bdcaa8d0Smrg    reg->memendian = verite_in8(iob+MEMENDIAN);
347bdcaa8d0Smrg    reg->mode = verite_in8(iob+MODEREG);
348bdcaa8d0Smrg    reg->sclkpll = verite_in32(iob+SCLKPLL);
349bdcaa8d0Smrg    reg->dramctl = verite_in32(iob+DRAMCTL);
350bdcaa8d0Smrg    reg->crtch = verite_in32(iob+CRTCHORZ);
351bdcaa8d0Smrg    reg->crtcv = verite_in32(iob+CRTCVERT);
352bdcaa8d0Smrg    /* clock */
353bdcaa8d0Smrg    if (V1000_DEVICE ==pRendition->board.chip) {
354bdcaa8d0Smrg	int width;
355bdcaa8d0Smrg	/*
356bdcaa8d0Smrg	 * I have no idea how to read back the clock from
357bdcaa8d0Smrg	 * V1000. Therefore we pick a VESA Mode clock from
358bdcaa8d0Smrg	 * a list for the width found.
359bdcaa8d0Smrg	 */
360bdcaa8d0Smrg	width = ((reg->crtch & 0xff) + 1) << 3;
361bdcaa8d0Smrg        reg->pclkpll = verite_findtextclock(width);
362bdcaa8d0Smrg	reg->plldev= verite_in8(iob+PLLDEV);
363bdcaa8d0Smrg    } else {
364bdcaa8d0Smrg	reg->pclkpll = verite_in32(iob+PCLKPLL);
365bdcaa8d0Smrg    }
366bdcaa8d0Smrg    /* initdac */
367bdcaa8d0Smrg    verite_out8(iob+MODEREG,NATIVE_MODE);
368bdcaa8d0Smrg    verite_savedac(pScreenInfo);
369bdcaa8d0Smrg    verite_out8(iob+MODEREG,reg->mode);
370bdcaa8d0Smrg
371bdcaa8d0Smrg    reg->vbasea = verite_in32(iob+FRAMEBASEA);
372bdcaa8d0Smrg    reg->crtcoff = verite_in32(iob+CRTCOFFSET);
373bdcaa8d0Smrg    reg->crtcctl = verite_in32(iob+CRTCCTL);
374bdcaa8d0Smrg}
375bdcaa8d0Smrg
376bdcaa8d0Smrgvoid
377bdcaa8d0Smrgverite_restore(ScrnInfoPtr pScreenInfo, RenditionRegPtr reg)
378bdcaa8d0Smrg{
379bdcaa8d0Smrg    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
380bdcaa8d0Smrg    int iob=pRendition->board.io_base;
381bdcaa8d0Smrg
382bdcaa8d0Smrg    verite_restoredac (pScreenInfo, reg);
383bdcaa8d0Smrg    /*
384bdcaa8d0Smrg     * If this is a Verite 1000, restore the MODEREG
385bdcaa8d0Smrg     * register now.  The MODEREG gets restored later
386bdcaa8d0Smrg     * for the Verite 2x00 because restoring it here
387bdcaa8d0Smrg     * has been confirmed to cause intermittent
388bdcaa8d0Smrg     * system locks.
389bdcaa8d0Smrg     */
390bdcaa8d0Smrg    if (pRendition->board.chip == V1000_DEVICE) {
391bdcaa8d0Smrg	verite_out32(iob+MODEREG,reg->mode);
392bdcaa8d0Smrg    }
393bdcaa8d0Smrg    verite_out8(iob+MEMENDIAN,reg->memendian);
394bdcaa8d0Smrg    verite_out32(iob+DRAMCTL,reg->dramctl);
395bdcaa8d0Smrg    verite_out32(iob+SCLKPLL,reg->sclkpll);
396bdcaa8d0Smrg    if (pRendition->board.chip == V1000_DEVICE) {
397bdcaa8d0Smrg	/* fixme */
398bdcaa8d0Smrg        set_PLL(iob, reg->pclkpll);
3990b661123Smrg	usleep(10000);
400bdcaa8d0Smrg    } else {
401bdcaa8d0Smrg	verite_out32(iob+PCLKPLL,reg->pclkpll);
402bdcaa8d0Smrg	/*
403bdcaa8d0Smrg	 * Need to wait 200uS for PLL to stabilize --
404bdcaa8d0Smrg	 * let's play it safe with 500
405bdcaa8d0Smrg	 */
4060b661123Smrg	usleep(10000);
407bdcaa8d0Smrg	/* wait until VBLANK */
408bdcaa8d0Smrg	while ((verite_in32(iob+CRTCSTATUS)&CRTCSTATUS_VERT_MASK) !=
409bdcaa8d0Smrg	       CRTCSTATUS_VERT_ACTIVE);
410bdcaa8d0Smrg	while ((verite_in32(iob+CRTCSTATUS)&CRTCSTATUS_VERT_MASK) ==
411bdcaa8d0Smrg	       CRTCSTATUS_VERT_ACTIVE);
412bdcaa8d0Smrg    }
413bdcaa8d0Smrg
414bdcaa8d0Smrg    /*
415bdcaa8d0Smrg     * If this is a Verite 2x00, restore the MODEREG
416bdcaa8d0Smrg     * register now.  The MODEREG register is restored
417bdcaa8d0Smrg     * earlier for the Verite 1000, but is restored
418bdcaa8d0Smrg     * here for the Verite 2x00 to prevent system
419bdcaa8d0Smrg     * locks.
420bdcaa8d0Smrg     */
421bdcaa8d0Smrg    if (pRendition->board.chip != V1000_DEVICE) {
422bdcaa8d0Smrg	verite_out32(iob+MODEREG,reg->mode);
423bdcaa8d0Smrg    }
424bdcaa8d0Smrg
425bdcaa8d0Smrg    verite_out32(iob+CRTCHORZ,reg->crtch);
426bdcaa8d0Smrg    verite_out32(iob+CRTCVERT,reg->crtcv);
427bdcaa8d0Smrg    verite_out32(iob+FRAMEBASEA, reg->vbasea);
428bdcaa8d0Smrg    verite_out32(iob+CRTCOFFSET,reg->crtcoff);
429bdcaa8d0Smrg    verite_out32(iob+CRTCCTL,reg->crtcctl);
430bdcaa8d0Smrg}
431bdcaa8d0Smrg
432bdcaa8d0Smrgvoid
433bdcaa8d0Smrgverite_setframebase(ScrnInfoPtr pScreenInfo, vu32 framebase)
434bdcaa8d0Smrg{
435bdcaa8d0Smrg    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
436bdcaa8d0Smrg
437bdcaa8d0Smrg    vu32 offset;
438bdcaa8d0Smrg
439bdcaa8d0Smrg    int iob=pRendition->board.io_base;
440bdcaa8d0Smrg    int swidth=pRendition->board.mode.screenwidth;
441bdcaa8d0Smrg    int vwidth=  pRendition->board.mode.virtualwidth;
442bdcaa8d0Smrg    int bytespp=pRendition->board.mode.bitsperpixel>>3;
443bdcaa8d0Smrg    int fifo_size=pRendition->board.mode.fifosize;
444bdcaa8d0Smrg
445bdcaa8d0Smrg#ifdef DEBUG
446bdcaa8d0Smrg    ErrorF( "Rendition: Debug verite_setframebase w=%d v=%d b=%d f=%d\n",
447bdcaa8d0Smrg        swidth, vwidth, bytespp, fifo_size);
448bdcaa8d0Smrg#endif
449bdcaa8d0Smrg
450bdcaa8d0Smrg    /* CRTCOFFSET */
451bdcaa8d0Smrg    offset=vwidth*bytespp               /* virtual width in bytes */
452bdcaa8d0Smrg          -swidth*bytespp               /* screen width in bytes */
453bdcaa8d0Smrg          +((swidth*bytespp)%fifo_size) /* width in bytes modulo fifo size */
454bdcaa8d0Smrg        ;
455bdcaa8d0Smrg
456bdcaa8d0Smrg    if (!(   framebase&7            /* framebase multiple of 8? */
457bdcaa8d0Smrg          || (swidth*bytespp)%128)) /* screenwidth multiple of fifo size */
458bdcaa8d0Smrg      offset+=fifo_size;            /* increment offset by fifosize */
459bdcaa8d0Smrg
460bdcaa8d0Smrg    /* wait for vertical retrace */
461bdcaa8d0Smrg#ifndef DEBUG
462bdcaa8d0Smrg    if (!pRendition->board.init) {
463bdcaa8d0Smrg        while ((verite_in32(iob+CRTCSTATUS) & CRTCSTATUS_VERT_MASK) !=
464bdcaa8d0Smrg               CRTCSTATUS_VERT_ACTIVE) ;
465bdcaa8d0Smrg        while ((verite_in32(iob+CRTCSTATUS) & CRTCSTATUS_VERT_MASK) ==
466bdcaa8d0Smrg               CRTCSTATUS_VERT_ACTIVE) ;
467bdcaa8d0Smrg    }
468bdcaa8d0Smrg    else
469bdcaa8d0Smrg        pRendition->board.init=0;
470bdcaa8d0Smrg#endif
471bdcaa8d0Smrg
472bdcaa8d0Smrg    /* framebase */
473bdcaa8d0Smrg    verite_out32(iob+FRAMEBASEA, framebase);
474bdcaa8d0Smrg
475bdcaa8d0Smrg    /* crtc offset */
476bdcaa8d0Smrg    verite_out32(iob+CRTCOFFSET, offset&0xffff);
477bdcaa8d0Smrg}
478bdcaa8d0Smrg
479bdcaa8d0Smrgint
480bdcaa8d0Smrgverite_getstride(ScrnInfoPtr pScreenInfo, int *width,
481bdcaa8d0Smrg		 vu16 *stride0, vu16 *stride1)
482bdcaa8d0Smrg{
483bdcaa8d0Smrg    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
484bdcaa8d0Smrg    int bytesperline;
485bdcaa8d0Smrg    int c = 0;
486bdcaa8d0Smrg
487bdcaa8d0Smrg    bytesperline
488bdcaa8d0Smrg	= pRendition->board.mode.virtualwidth
489bdcaa8d0Smrg	* (pRendition->board.mode.bitsperpixel >> 3);
490bdcaa8d0Smrg#ifdef DEBUG
491bdcaa8d0Smrg    ErrorF("RENDITION: %d bytes per line\n", bytesperline);
492bdcaa8d0Smrg#endif
493bdcaa8d0Smrg
494bdcaa8d0Smrg    /* for now, I implemented a linear search only, should be fixed <ml> */
495bdcaa8d0Smrg    while (0 != width_to_stride_table[c].width8bpp) {
496bdcaa8d0Smrg	if (width_to_stride_table[c].width8bpp == bytesperline
497bdcaa8d0Smrg	    && ((width_to_stride_table[c].chip == pRendition->board.chip)
498bdcaa8d0Smrg		|| (V2000_DEVICE == pRendition->board.chip))) {
499bdcaa8d0Smrg            *stride0 = width_to_stride_table[c].stride0;
500bdcaa8d0Smrg            *stride1 = width_to_stride_table[c].stride1;
501bdcaa8d0Smrg            return 1;
502bdcaa8d0Smrg        }
503bdcaa8d0Smrg        c++;
504bdcaa8d0Smrg    }
505bdcaa8d0Smrg    return 0;
506bdcaa8d0Smrg}
507bdcaa8d0Smrg
508bdcaa8d0Smrg/*
509bdcaa8d0Smrg * local functions
510bdcaa8d0Smrg */
511bdcaa8d0Smrg
512bdcaa8d0Smrg/*
513880c7e28Smrg * void set_PLL(unsigned long iob, vu32 value)
514bdcaa8d0Smrg *
515bdcaa8d0Smrg * Set PLL clock to desired frequency for the V1000.
516bdcaa8d0Smrg */
517bdcaa8d0Smrg
518bdcaa8d0Smrgvoid
519880c7e28Smrgset_PLL(unsigned long iob, vu32 value)
520bdcaa8d0Smrg{
521bdcaa8d0Smrg    vu32 ulD;
522bdcaa8d0Smrg    int b;
523bdcaa8d0Smrg
524bdcaa8d0Smrg    /* shift out the 20 serial bits */
525bdcaa8d0Smrg    for (b=19; b>=0; b--) {
526bdcaa8d0Smrg        ulD=(value>>b)&1;
527bdcaa8d0Smrg        verite_out8(iob+PLLDEV, (vu8)ulD);
528bdcaa8d0Smrg    }
529bdcaa8d0Smrg
530bdcaa8d0Smrg    /* read PLL device so the latch is filled with the previously
531bdcaa8d0Smrg     * written value */
532bdcaa8d0Smrg    (void)verite_in8(iob+PLLDEV);
533bdcaa8d0Smrg}
534bdcaa8d0Smrg
535bdcaa8d0Smrg
536bdcaa8d0Smrg
537bdcaa8d0Smrg/* Vxx00CalcClock -- finds PLL parameters to match target
538bdcaa8d0Smrg *                   frequency (in megahertz)
539bdcaa8d0Smrg *
540bdcaa8d0Smrg *                   Brute force, but takes less than a tenth
541bdcaa8d0Smrg *                   of a second and the function is only called
542bdcaa8d0Smrg *                   O(1) times during program execution.
543bdcaa8d0Smrg */
544bdcaa8d0Smrgstatic double
545bdcaa8d0SmrgV1000CalcClock(double target, int *M, int *N, int *P)
546bdcaa8d0Smrg{
547bdcaa8d0Smrg    double mindiff = 1e10;
548bdcaa8d0Smrg    double vco, pcf, diff, freq;
549bdcaa8d0Smrg    int mm, nn, pp;
550bdcaa8d0Smrg
551bdcaa8d0Smrg    for (pp=0; pp<4; pp++)
552bdcaa8d0Smrg        for (nn=1; nn<=129; nn++)
553bdcaa8d0Smrg            for (mm=1; mm<=129; mm++) {
554bdcaa8d0Smrg                vco=V1_REF_FREQ*2.0*mm/nn;
555bdcaa8d0Smrg                if ((vco<V1_MIN_VCO_FREQ) || (vco>V1_MAX_VCO_FREQ))
556bdcaa8d0Smrg                    continue;
557bdcaa8d0Smrg            	pcf = V1_REF_FREQ/nn;
558bdcaa8d0Smrg            	if ((pcf<V1_MIN_PCF_FREQ) || (pcf>V1_MAX_PCF_FREQ))
559bdcaa8d0Smrg                    continue;
560bdcaa8d0Smrg            	freq=vco/(1<<pp);
561bdcaa8d0Smrg            	diff=fabs(target-freq);
562bdcaa8d0Smrg            	if (diff < mindiff) {
563bdcaa8d0Smrg                    *M=mm;
564bdcaa8d0Smrg                    *N=nn;
565bdcaa8d0Smrg                    *P=pp;
566bdcaa8d0Smrg                    mindiff=diff;
567bdcaa8d0Smrg                }
568bdcaa8d0Smrg            }
569bdcaa8d0Smrg
570bdcaa8d0Smrg    vco=V1_REF_FREQ*2*(*M)/(*N);
571bdcaa8d0Smrg    pcf=V1_REF_FREQ/(*N);
572bdcaa8d0Smrg    freq=vco/(1<<(*P));
573bdcaa8d0Smrg
574bdcaa8d0Smrg#ifdef DEBUG
575bdcaa8d0Smrg    ErrorF(
576bdcaa8d0Smrg        "RENDITION: target=%f freq=%f vco=%f pcf=%f n=%d m=%d p=%d\n",
577bdcaa8d0Smrg        target, freq, vco, pcf, *N, *M, *P);
578bdcaa8d0Smrg#endif
579bdcaa8d0Smrg
580bdcaa8d0Smrg    return freq;
581bdcaa8d0Smrg}
582bdcaa8d0Smrg
583bdcaa8d0Smrg
584bdcaa8d0Smrg
585bdcaa8d0Smrgstatic double
586bdcaa8d0SmrgV2200CalcClock(double target, int *m, int *n, int *p)
587bdcaa8d0Smrg{
588bdcaa8d0Smrg    double mindiff = 1e10;
589bdcaa8d0Smrg    double vco, pcf, diff, freq;
590bdcaa8d0Smrg    int mm, nn, pp;
591bdcaa8d0Smrg
592bdcaa8d0Smrg    for (pp=1; pp<=0x0f; pp++)
593bdcaa8d0Smrg        for (nn=1; nn<=0x3f; nn++)
594bdcaa8d0Smrg            for (mm=1; mm<=0xff; mm++) {
595bdcaa8d0Smrg                vco = V2_REF_FREQ*mm/nn;
596bdcaa8d0Smrg                if ((vco < V2_MIN_VCO_FREQ) || (vco > V2_MAX_VCO_FREQ))
597bdcaa8d0Smrg                    continue;
598bdcaa8d0Smrg            	pcf = V2_REF_FREQ*mm/nn;
599bdcaa8d0Smrg                if ((vco < V2_MIN_VCO_FREQ) || (vco > V2_MAX_VCO_FREQ))
600bdcaa8d0Smrg                    continue;
601bdcaa8d0Smrg            	pcf = V2_REF_FREQ/nn;
602bdcaa8d0Smrg            	if ((pcf < V2_MIN_PCF_FREQ) || (pcf > V2_MAX_PCF_FREQ))
603bdcaa8d0Smrg                    continue;
604bdcaa8d0Smrg            	freq = vco/pp;
605bdcaa8d0Smrg            	diff = fabs(target-freq);
606bdcaa8d0Smrg            	if (diff < mindiff) {
607bdcaa8d0Smrg                    *m = mm; *n = nn; *p = pp;
608bdcaa8d0Smrg                    mindiff = diff;
609bdcaa8d0Smrg                }
610bdcaa8d0Smrg            }
611bdcaa8d0Smrg
612bdcaa8d0Smrg    vco = V2_REF_FREQ * *m / *n;
613bdcaa8d0Smrg    pcf = V2_REF_FREQ / *n;
614bdcaa8d0Smrg    freq = vco / *p;
615bdcaa8d0Smrg
616bdcaa8d0Smrg#ifdef DEBUG
617bdcaa8d0Smrg    ErrorF(
618bdcaa8d0Smrg        "RENDITION: target=%f freq=%f vco=%f pcf=%f n=%d m=%d p=%d\n",
619bdcaa8d0Smrg        target, freq, vco, pcf, *n, *m, *p);
620bdcaa8d0Smrg#endif
621bdcaa8d0Smrg
622bdcaa8d0Smrg    return freq;
623bdcaa8d0Smrg}
624bdcaa8d0Smrg
625bdcaa8d0Smrg
626bdcaa8d0Smrg/*
627bdcaa8d0Smrg * end of file vmodes.c
628bdcaa8d0Smrg */
629bdcaa8d0Smrg
630