Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "../port/error.h"
8
 
9
#define	Image	IMAGE
10
#include <draw.h>
11
#include <memdraw.h>
12
#include <cursor.h>
13
#include "screen.h"
14
 
15
enum {
16
	PCIS3		= 0x5333,		/* PCI VID */
17
 
18
	SAVAGE3D	= 0x8A20,	/* PCI DID */
19
	SAVAGE3DMV	= 0x8A21,
20
	SAVAGE4		= 0x8A22,
21
	PROSAVAGEP	= 0x8A25,
22
	PROSAVAGEK	= 0x8A26,
23
	PROSAVAGE8	= 0x8D04,
24
	SAVAGEMXMV	= 0x8C10,
25
	SAVAGEMX	= 0x8C11,
26
	SAVAGEIXMV	= 0x8C12,
27
	SAVAGEIX	= 0x8C13,
28
	SUPERSAVAGEIXC16 = 0x8C2E,
29
	SAVAGE2000	= 0x9102,
30
 
31
	VIRGE		= 0x5631,
32
	VIRGEGX2	= 0x8A10,
33
	VIRGEDXGX	= 0x8A01,
34
	VIRGEVX		= 0x883D,
35
	VIRGEMX		= 0x8C01,
36
	VIRGEMXP	= 0x8C03,
37
 
38
	AURORA64VPLUS	= 0x8812,
39
};
40
 
41
/*
42
 * Savage4 et al. acceleration.
43
 *
44
 * This is based only on the Savage4 documentation.
45
 * It is expected to work on other Savage cards as well,
46
 * but has not been tried.
47
 * 
48
 * There are five ways to access the 2D graphics engine registers:
49
 * 	- Old MMIO non-packed format
50
 *	- Old MMIO packed format
51
 *	- New MMIO non-packed format
52
 *	- New MMIO packed format
53
 *	- Burst Command Interface (BCI)
54
 *
55
 * Of these, the manual hints that the first three are deprecated,
56
 * and it does not document any of those three well enough to use.
57
 * 
58
 * I have tried for many hours with no success to understand the BCI
59
 * interface well enough to use it.  It is not well documented, and the
60
 * XFree86 driver seems to completely contradict what little documentation
61
 * there is.
62
 *
63
 * This leaves the packed new MMIO.
64
 * The manual contradicts itself here, claming that the registers
65
 * start at 0x2008100 as well as at 0x0008100 from the base of the 
66
 * mmio segment.  Since the segment is only 512k, we assume that
67
 * the latter is the correct offset.
68
 *
69
 * According to the manual, only 16-bit reads of the 2D registers
70
 * are supported: 32-bit reads will return garbage in the upper word.
71
 * 32-bit writes must be enabled explicitly.
72
 * 
73
 * 32-bit reads of the status registers seem just fine.
74
 */
75
 
76
/* 2D graphics engine registers for Savage4; others appear to be mostly the same */
77
enum {
78
	SubsystemStatus = 0x8504,	/* Subsystem Status: read only */
79
	  /* read only: whether we get interrupts on various events */
80
	  VsyncInt		= 1<<0,		/* vertical sync */
81
	  GeBusyInt		= 1<<1,		/* 2D graphics engine busy */
82
	  BfifoFullInt	= 1<<2,		/* BIU FIFO full */
83
	  BfifoEmptyInt	= 1<<3,		/* BIU FIFO empty */
84
	  CfifoFullInt	= 1<<4,		/* command FIFO full */
85
	  CfifoEmptyInt	= 1<<5,		/* command FIFO empty */
86
	  BciInt		= 1<<6, 	/* BCI */
87
	  LpbInt		= 1<<7, 	/* LPB */
88
	  CbHiInt		= 1<<16,	/* COB upper threshold */
89
	  CbLoInt		= 1<<17,	/* COB lower threshold */
90
 
91
	SubsystemCtl 	= 0x8504,	/* Subsystem Control: write only */
92
	  /* clear interrupts for various events */
93
	  VsyncClr		= 1<<0,
94
	  GeBusyClr		= 1<<1,
95
	  BfifoFullClr	= 1<<2,
96
	  BfifoEmptyClr	= 1<<3,
97
	  CfifoFullClr	= 1<<4,
98
	  CfifoEmptyClr	= 1<<5,
99
	  BciClr		= 1<<6,
100
	  LpbClr		= 1<<7,
101
	  CbHiClr		= 1<<16,
102
	  CbLoClr		= 1<<17,
103
 
104
	  /* enable interrupts for various events */
105
	  VsyncEna		= 1<<8,
106
	  Busy2DEna		= 1<<9,
107
	  BfifoFullEna	= 1<<10,
108
	  BfifoEmptyEna	= 1<<11,
109
	  CfifoFullEna	= 1<<12,
110
	  CfifoEmptyEna	= 1<<13,
111
	  SubsysBciEna	= 1<<14,
112
	  CbHiEna		= 1<<24,
113
	  CbLoEna		= 1<<25,
114
 
115
	  /* 2D graphics engine software reset */
116
	  GeSoftReset	= 1<<15,
117
 
118
	FifoStatus		= 0x8508,	/* FIFO status: read only */
119
	  CwbEmpty		= 1<<0,		/* command write buffer empty */
120
	  CrbEmpty		= 1<<1,		/* command read buffer empty */
121
	  CobEmpty		= 1<<2,		/* command overflow buffer empty */
122
	  CfifoEmpty	= 1<<3,		/* command FIFO empty */
123
	  CwbFull		= 1<<8,		/* command write buffer full */
124
	  CrbFull		= 1<<9,		/* command read buffer full */
125
	  CobFull		= 1<<10,	/* command overflow buffer full */
126
	  CfifoFull		= 1<<11,	/* command FIFO full */
127
 
128
	AdvFunCtl		= 0x850C,	/* Advanced Function Control: read/write */
129
	  GeEna			= 1<<0,	/* enable 2D/3D engine */
130
	  /*
131
	   * according to the manual, BigPixel should be
132
	   * set when bpp >= 8 (bpp != 4), and then CR50_5-4 are
133
	   * used to figure out bpp example.  however, it does bad things
134
	   * to the screen in 8bpp mode.
135
	   */
136
	  BigPixel		= 1<<2,		/* 8 or more bpp enhanced mode */
137
	  LaEna			= 1<<3,		/* linear addressing ena: or'ed with CR58_4 */
138
	  Mclk_2		= 0<<8,		/* 2D engine clock divide: MCLK/2 */
139
	  Mclk_4		= 1<<8,		/* " MCLK/4 */
140
	  Mclk			= 2<<8,		/* " MCLK */
141
	/* Mclk			= 3<<8,		/* " MCLK */
142
	  Ic33mhz		= 1<<16,	/* Internal clock 33 MHz (instead of 66) */
143
 
144
	WakeupReg		= 0x8510,	/* Wakeup: read/write */
145
	  WakeupBit		= 1<<0,	/* wake up: or'ed with 3C3_0 */
146
 
147
	SourceY			= 0x8100,	/* UL corner of bitblt source */
148
	SourceX			= 0x8102,	/* " */
149
	RectY			= 0x8100,	/* UL corner of rectangle fill */
150
	RectX			= 0x8102,	/* " */
151
	DestY			= 0x8108,	/* UL corner of bitblt dest */
152
	DestX			= 0x810A,	/* " */
153
	Height			= 0x8148,	/* bitblt, image xfer rectangle height */
154
	Width			= 0x814A, 	/* bitblt, image xfer rectangle width */
155
 
156
	StartY			= 0x8100,	/* Line draw: first point*/
157
	StartX			= 0x8102,	/* " */
158
	/*
159
	 * For line draws, the following must be programmed:
160
	 * axial step constant = 2*min(|dx|,|dy|)
161
	 * diagonal step constant = 2*[min(|dx|,|dy|) - max(|dx|,|dy|)]
162
	 * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy| - 1
163
	 *	[sic] when start X < end X
164
	 * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy|
165
	 *  [sic] when start X >= end X
166
	 */
167
	AxialStep		= 0x8108,
168
	DiagonalStep	= 0x810A,
169
	LineError		= 0x8110,
170
	MinorLength		= 0x8148,	/* pixel count along minor axis */
171
	MajorLength		= 0x814A,	/* pixel count along major axis */
172
 
173
	DrawCmd			= 0x8118,	/* Drawing Command: write only */
174
	  CmdMagic		= 0<<1,
175
	  AcrossPlane	= 1<<1,		/* across the plane mode */
176
	  LastPixelOff	= 1<<2,		/* last pixel of line or vector draw not drawn */
177
	  Radial		= 1<<3,		/* enable radial direction (else axial) */
178
	  DoDraw		= 1<<4,		/* draw pixels (else only move current pos) */
179
 
180
	  DrawRight		= 1<<5,		/* axial drawing direction: left to right */
181
	  /* DrawLeft		= 0<<5, */
182
	  MajorY		= 1<<6,
183
	  /* MajorX		= 0<<6, */
184
	  DrawDown		= 1<<7,
185
	  /* DrawUp		= 0<<7, */
186
	  Degree0		= 0<<5,		/* drawing direction when Radial */
187
	  Degree45		= 1<<5,
188
		/* ... */
189
	  Degree315		= 7<<5,
190
 
191
	  UseCPUData	= 1<<8,
192
 
193
	  /* image write bus transfer width */
194
	  Bus8			= 0<<9,
195
	  Bus16			= 1<<9,
196
	  /*
197
	   * in Bus32 mode, doubleword bits beyond the image rect width are
198
	   * discarded.  each line starts on a new doubleword.
199
	   * Bus32AP is intended for across-the-plane mode and
200
	   * rounds to byte boundaries instead.
201
	   */
202
	  Bus32			= 2<<9,
203
	  Bus32AP		= 3<<9,
204
 
205
	  CmdNop		= 0<<13,	/* nop */
206
	  CmdLine		= 1<<13,	/* draw line */
207
	  CmdFill		= 2<<13,	/* fill rectangle */
208
	  CmdBitblt		= 6<<13,	/* bitblt */
209
	  CmdPatblt		= 7<<13,	/* 8x8 pattern blt */
210
 
211
	  SrcGBD		= 0<<16,
212
	  SrcPBD		= 1<<16,
213
	  SrcSBD		= 2<<16,
214
 
215
	  DstGBD		= 0<<18,
216
	  DstPBD		= 1<<18,
217
	  DstSBD		= 2<<18,
218
 
219
	/* color sources, controls */
220
	BgColor			= 0x8120,	/* Background Color: read/write */
221
	FgColor			= 0x8124,	/* Foreground Color: read/write */
222
	BitplaneWmask	= 0x8128,	/* Bitplane Write Mask: read/write */
223
	BitplaneRmask	= 0x812C,	/* Bitplane Read Mask: read/write */
224
	CmpColor		= 0x8130,	/* Color Compare: read/write */
225
	BgMix			= 0x8134,
226
	FgMix			= 0x8136,
227
	  MixNew		= 7,
228
	  SrcBg			= 0<<5,
229
	  SrcFg			= 1<<5,
230
	  SrcCPU		= 2<<5,
231
	  SrcDisp		= 3<<5,
232
 
233
	/* clipping rectangle */
234
	TopScissors		= 0x8138,	/* Top Scissors: write only */
235
	LeftScissors	= 0x813A,	/* Left Scissors: write only */
236
	BottomScissors	= 0x813C,	/* Bottom Scissors: write only */
237
	RightScissors	= 0x813E,	/* Right Scissors: write only */
238
 
239
	/*
240
	 * Registers with Magic were indirectly accessed in older modes.
241
	 * It is not clear whether the Magic is necessary.
242
	 * In the older modes, writes to these registers were pipelined,
243
	 * so that you had to issue an engine command and wait for engine
244
	 * idle before reading a write back.  It is not clear if this is
245
	 * still the case either.
246
	 */
247
	PixCtl			= 0x8140,	/* Pixel Control: write only */
248
	  PixMagic		= 0xA<<12,
249
	  PixMixFg		= 0<<6,		/* foreground mix register always */
250
	  PixMixCPU		= 2<<6,		/* CPU data determines mix register */
251
	  PixMixDisp	= 3<<6,		/* display data determines mix register */
252
 
253
	MfMisc2Ctl		= 0x8142,	/* Multifunction Control Misc. 2: write only */
254
	  MfMisc2Magic	= 0xD<<12,
255
	  DstShift		= 0,		/* 3 bits: destination base address in MB */
256
	  SrcShift		= 4,		/* 3 bits: source base address in MB */
257
	  WaitFifoEmpty	= 2<<8,		/* wait for write FIFO empty between draws */
258
 
259
	MfMiscCtl		= 0x8144,	/* Multifunction Control Misc: write only */
260
	  MfMiscMagic	= 0xE<<12,
261
	  UseHighBits	= 1<<4,		/* select upper 16 bits for 32-bit reg access */
262
	  ClipInvert	= 1<<5,		/* only touch pixels outside clip rectangle */
263
	  SkipSame		= 0<<6,		/* ignore pixels with color CmpColor */
264
	  SkipDifferent	= 1<<7,		/* ignore pixels not color CmpColor */
265
	  CmpEna		= 1<<8,		/* enable color compare */
266
	  W32Ena		= 1<<9,		/* enable 32-bit register write */
267
	  ClipDis		= 1<<11,	/* disable clipping */
268
 
269
	/*
270
	 * The bitmap descriptor 1 registers contain the starting
271
	 * address of the bitmap (in bytes).
272
	 * The bitmap descriptor 2 registesr contain stride (in pixels)
273
	 * in the lower 16 bits, depth (in bits) in the next 8 bits,
274
	 * and whether block write is disabled.
275
	 */
276
	GBD1			= 0x8168,	/* Global Bitmap Descriptor 1: read/write */
277
	GBD2			= 0x816C,	/* Global Bitmap Descriptor 2: read/write */
278
	  /* GBD2-only bits */
279
	  BDS64			= 1<<0,		/* bitmap descriptor size 64 bits */
280
	  GBDBciEna		= 1<<3,		/* BCI enable */
281
	  /* generic BD2 bits */
282
	  BlockWriteDis	= 1<<28,
283
	  StrideShift	= 0,
284
	  DepthShift	= 16,
285
 
286
	PBD1			= 0x8170,	/* Primary Bitmap Descriptor: read/write */
287
	PBD2			= 0x8174,
288
	SBD1			= 0x8178,	/* Secondary Bitmap Descriptor: read/write */
289
	SBD2			= 0x817C,
290
};
291
 
292
/* mastered data transfer registers */
293
 
294
/* configuration/status registers */
295
enum {
296
	XStatus0			= 0x48C00,	/* Status Word 0: read only */
297
	  /* rev. A silicon differs from rev. B; use AltStatus0 */
298
	  CBEMaskA		= 0x1FFFF,	/* filled command buffer entries */
299
	  CBEShiftA		= 0,
300
	  BciIdleA		= 1<<17,	/* BCI idle */
301
	  Ge3IdleA		= 1<<18,	/* 3D engine idle */
302
	  Ge2IdleA		= 1<<19,	/* 2D engine idle */
303
	  McpIdleA		= 1<<20,	/* motion compensation processor idle */
304
	  MeIdleA		= 1<<22,	/* master engine idle */
305
	  PfPendA		= 1<<23,	/* page flip pending */
306
 
307
	  CBEMaskB		= 0x1FFFFF,
308
	  CBEShiftB		= 0,
309
	  BciIdleB		= 1<<25,
310
	  Ge3IdleB		= 1<<26,
311
	  Ge2IdleB		= 1<<27,
312
	  McpIdleB		= 1<<28,
313
	  MeIdleB		= 1<<30,
314
	  PfPendB		= 1<<31,
315
 
316
	AltStatus0		= 0x48C60,	/* Alternate Status Word 0: read only */
317
	  CBEMask		= 0x1FFFF,
318
	  CBEShift		= 0,
319
	  /* the Savage4 manual says bits 17..23 for these, like Status0 */
320
	  /* empirically, they are bits 21..26 */
321
	  BciIdle		= 1<<21,
322
	  Ge3Idle		= 1<<22,
323
	  Ge2Idle		= 1<<23,
324
	  McpIdle		= 1<<24,
325
	  MeIdle		= 1<<25,
326
	  PfPend		= 1<<26,
327
 
328
	XStatus1			= 0x48C04,	/* Status Word 1: read only */
329
	  /* contains event tag 1, event tag 0, both 16 bits */
330
 
331
	XStatus2			= 0x48C08,	/* Status Word 2: read only */
332
	  ScanMask		= 0x3FF,	/* current scan line */
333
	  ScanShift		= 0,
334
	  VRTMask		= 0x7F100,	/* vert retrace count */
335
	  VRTShift		= 11,
336
 
337
	CbThresh		= 0x48C10,	/* Command Buffer Thresholds: read/write */
338
	CobOff			= 0x48C14,	/* Command Overflow Buffer: read/write */
339
 
340
	CobPtr			= 0x48C18,	/* Command Overflow Buffer Pointers: read/write */
341
	  CobEna		= 1<<2,		/* command overflow buffer enable */
342
	  CobBciEna		= 1<<3,		/* BCI function enable */
343
	  CbeMask		= 0xFFFF8000,	/* no. of entries in command buffer */
344
	  CbeShift		= 15,
345
 
346
	AltStatus1		= 0x48C64,	/* Alternate Status Word 1: read onnly */
347
	  /* contains current texture surface tag, vertex buffer tag */
348
 
349
};
350
 
351
struct {
352
	ulong idletimeout;
353
	ulong tostatw[16];
354
} savagestats;
355
 
356
enum {
357
	Maxloop = 1<<20
358
};
359
 
360
static void
361
savagewaitidle(VGAscr *scr)
362
{
363
	long x;
364
	ulong *statw, mask, goal;
365
 
366
	switch(scr->id){
367
	case SAVAGE4:
368
	case PROSAVAGEP:
369
	case PROSAVAGEK:
370
	case PROSAVAGE8:
371
		/* wait for engine idle and FIFO empty */
372
		statw = (ulong*)((uchar*)scr->mmio+AltStatus0);
373
		mask = CBEMask | Ge2Idle;
374
		goal = Ge2Idle;
375
		break;
376
	/* case SAVAGEMXMV: ? */
377
	/* case SAVAGEMX: ? */
378
	/* case SAVAGEIX: ? */
379
	case SUPERSAVAGEIXC16:
380
	case SAVAGEIXMV:
381
	case SAVAGEMXMV:
382
		/* wait for engine idle and FIFO empty */
383
		statw = (ulong*)((uchar*)scr->mmio+XStatus0);
384
		mask = CBEMaskA | Ge2IdleA;
385
		goal = Ge2IdleA;
386
		break;
387
	default:
388
		/* 
389
		 * best we can do: can't print or we'll call ourselves.
390
		 * savageinit is supposed to not let this happen.
391
		 */	
392
		return;
393
	}
394
 
395
	for(x=0; x<Maxloop; x++)
396
		if((*statw & mask) == goal)
397
			return;
398
 
399
	savagestats.tostatw[savagestats.idletimeout++&15] = *statw;
400
	savagestats.tostatw[savagestats.idletimeout++&15] = (ulong)statw;
401
}
402
 
403
static int
404
savagefill(VGAscr *scr, Rectangle r, ulong sval)
405
{
406
	uchar *mmio;
407
 
408
	mmio = (uchar*)scr->mmio;
409
 
410
	*(ulong*)(mmio+FgColor) = sval;
411
	*(ulong*)(mmio+BgColor) = sval;
412
	*(ulong*)(mmio+BgMix) = SrcFg|MixNew;
413
	*(ulong*)(mmio+FgMix) = SrcFg|MixNew;
414
	*(ushort*)(mmio+RectY) = r.min.y;
415
	*(ushort*)(mmio+RectX) = r.min.x;
416
	*(ushort*)(mmio+Width) = Dx(r)-1;
417
	*(ushort*)(mmio+Height) = Dy(r)-1;
418
	*(ulong*)(mmio+DrawCmd) = CmdMagic | DoDraw | CmdFill | DrawRight | DrawDown;
419
	savagewaitidle(scr);
420
	return 1;
421
}
422
 
423
static int
424
savagescroll(VGAscr *scr, Rectangle r, Rectangle sr)
425
{
426
	uchar *mmio;
427
	ulong cmd;
428
	Point dp, sp;
429
 
430
	cmd = CmdMagic | DoDraw | CmdBitblt | SrcPBD | DstGBD;
431
 
432
	if(r.min.x <= sr.min.x){
433
		cmd |= DrawRight;
434
		dp.x = r.min.x;
435
		sp.x = sr.min.x;
436
	}else{
437
		dp.x = r.max.x-1;
438
		sp.x = sr.max.x-1;
439
	}
440
 
441
	if(r.min.y <= sr.min.y){
442
		cmd |= DrawDown;
443
		dp.y = r.min.y;
444
		sp.y = sr.min.y;
445
	}else{
446
		dp.y = r.max.y-1;
447
		sp.y = sr.max.y-1;
448
	}
449
 
450
	mmio = (uchar*)scr->mmio;
451
 
452
	*(ushort*)(mmio+SourceX) = sp.x;
453
	*(ushort*)(mmio+SourceY) = sp.y;
454
	*(ushort*)(mmio+DestX) = dp.x;
455
	*(ushort*)(mmio+DestY) = dp.y;
456
	*(ushort*)(mmio+Width) = Dx(r)-1;
457
	*(ushort*)(mmio+Height) = Dy(r)-1;
458
	*(ulong*)(mmio+BgMix) = SrcDisp|MixNew;
459
	*(ulong*)(mmio+FgMix) = SrcDisp|MixNew;
460
	*(ulong*)(mmio+DrawCmd) = cmd;
461
	savagewaitidle(scr);
462
	return 1;
463
}
464
 
465
static void
466
savageblank(VGAscr*, int blank)
467
{
468
	uchar seqD;
469
 
470
	/*
471
	 * Will handle DPMS to monitor
472
	 */
473
	vgaxo(Seqx, 8, vgaxi(Seqx,8)|0x06);
474
	seqD = vgaxi(Seqx, 0xD);
475
	seqD &= 0x03;
476
	if(blank)
477
		seqD |= 0x50;
478
	vgaxo(Seqx, 0xD, seqD);
479
 
480
	/*
481
	 * Will handle LCD
482
	 */
483
	if(blank)
484
		vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) & ~0x10);
485
	else
486
		vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) | 0x10);
487
}
488
 
489
 
490
void
491
savageinit(VGAscr *scr)
492
{
493
	uchar *mmio;
494
	ulong bd;
495
 
496
	/* if you add chip IDs here be sure to update savagewaitidle */
497
	switch(scr->id){
498
	case SAVAGE4:
499
	case PROSAVAGEP:
500
	case PROSAVAGEK:
501
	case PROSAVAGE8:
502
	case SAVAGEIXMV:
503
	case SUPERSAVAGEIXC16:
504
	case SAVAGEMXMV:
505
		break;
506
	default:
507
		print("unknown savage %.4lux\n", scr->id);
508
		return;
509
	}
510
 
511
	mmio = (uchar*)scr->mmio;
512
	if(mmio == nil) {
513
		print("savageinit: no mmio\n");
514
		return;
515
	}
516
 
517
	/* 2D graphics engine software reset */
518
	*(ushort*)(mmio+SubsystemCtl) = GeSoftReset;
519
	delay(2);
520
	*(ushort*)(mmio+SubsystemCtl) = 0;
521
	savagewaitidle(scr);
522
 
523
	/* disable BCI as much as possible */
524
	*(ushort*)(mmio+CobPtr) &= ~CobBciEna;
525
	*(ushort*)(mmio+GBD2) &= ~GBDBciEna;
526
	savagewaitidle(scr);
527
 
528
	/* enable 32-bit writes, disable clipping */
529
	*(ushort*)(mmio+MfMiscCtl) = MfMiscMagic|W32Ena|ClipDis;
530
	savagewaitidle(scr);
531
 
532
	/* enable all read, write planes */
533
	*(ulong*)(mmio+BitplaneRmask) = ~0;
534
	*(ulong*)(mmio+BitplaneWmask) = ~0;
535
	savagewaitidle(scr);
536
 
537
	/* turn on linear access, 2D engine */
538
	*(ulong*)(mmio+AdvFunCtl) |= GeEna|LaEna;
539
	savagewaitidle(scr);
540
 
541
	/* set bitmap descriptors */
542
	bd = (scr->gscreen->depth<<DepthShift) |
543
		(Dx(scr->gscreen->r)<<StrideShift) | BlockWriteDis
544
		| BDS64;
545
 
546
	*(ulong*)(mmio+GBD1) = 0;
547
	*(ulong*)(mmio+GBD2) = bd;
548
 
549
	*(ulong*)(mmio+PBD1) = 0;
550
	*(ulong*)(mmio+PBD2) = bd;
551
 
552
	*(ulong*)(mmio+SBD1) = 0;
553
	*(ulong*)(mmio+SBD2) = bd;
554
 
555
	/*
556
	 * For some reason, the GBD needs to get programmed twice,
557
	 * once before the PBD, SBD, and once after.
558
	 * This empirically makes it get set right.
559
	 * I would like to better understand the ugliness
560
	 * going on here.
561
	 */
562
	*(ulong*)(mmio+GBD1) = 0;
563
	*(ulong*)(mmio+GBD2) = bd;
564
	*(ushort*)(mmio+GBD2+2) = bd>>16;
565
	savagewaitidle(scr);
566
 
567
	scr->fill = savagefill;
568
	scr->scroll = savagescroll;
569
	scr->blank = savageblank;
570
	hwblank = 0;
571
}