1 /* $NetBSD: igsfb_subr.c,v 1.11 2009/11/18 06:10:50 macallan Exp $ */
4 * Copyright (c) 2002 Valeriy E. Ushakov
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * Integraphics Systems IGA 168x and CyberPro series.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: igsfb_subr.c,v 1.11 2009/11/18 06:10:50 macallan Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
44 #include <dev/wscons/wsdisplayvar.h>
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/rasops/rasops.h>
47 #include <dev/wscons/wsdisplay_vconsvar.h>
49 #include <dev/ic/igsfbreg.h>
50 #include <dev/ic/igsfbvar.h>
53 #define DPRINTF printf
55 #define DPRINTF while (0) printf
58 static void igsfb_init_seq(struct igsfb_devconfig
*);
59 static void igsfb_init_crtc(struct igsfb_devconfig
*);
60 static void igsfb_init_grfx(struct igsfb_devconfig
*);
61 static void igsfb_init_attr(struct igsfb_devconfig
*);
62 static void igsfb_init_ext(struct igsfb_devconfig
*);
63 static void igsfb_init_dac(struct igsfb_devconfig
*);
65 static void igsfb_freq_latch(struct igsfb_devconfig
*);
66 static void igsfb_video_on(struct igsfb_devconfig
*);
67 static void igsfb_calc_pll(int, int *, int *, int *, int, int, int, int);
75 igsfb_enable(bus_space_tag_t iot
, bus_addr_t iobase
, int ioflags
)
77 bus_space_handle_t vdoh
;
78 bus_space_handle_t vseh
;
79 bus_space_handle_t regh
;
82 ret
= bus_space_map(iot
, iobase
+ IGS_VDO
, 1, ioflags
, &vdoh
);
84 printf("unable to map VDO register\n");
88 ret
= bus_space_map(iot
, iobase
+ IGS_VSE
, 1, ioflags
, &vseh
);
90 printf("unable to map VSE register\n");
94 ret
= bus_space_map(iot
, iobase
+ IGS_REG_BASE
, IGS_REG_SIZE
, ioflags
,
97 printf("unable to map I/O registers\n");
102 * Start decoding i/o space accesses.
104 bus_space_write_1(iot
, vdoh
, 0, IGS_VDO_ENABLE
| IGS_VDO_SETUP
);
105 bus_space_write_1(iot
, vseh
, 0, IGS_VSE_ENABLE
);
106 bus_space_write_1(iot
, vdoh
, 0, IGS_VDO_ENABLE
);
109 * Start decoding memory space accesses (XXX: move out of here?
110 * we program this register in igsfb_init_ext).
111 * While here, enable coprocessor and select IGS_COP_BASE_B.
113 igs_ext_write(iot
, regh
, IGS_EXT_BIU_MISC_CTL
,
114 (IGS_EXT_BIU_LINEAREN
115 | IGS_EXT_BIU_COPREN
| IGS_EXT_BIU_COPASELB
));
117 bus_space_unmap(iot
, regh
, IGS_REG_SIZE
);
118 out2
: bus_space_unmap(iot
, vseh
, 1);
119 out1
: bus_space_unmap(iot
, vdoh
, 1);
126 * This is common for all video modes.
129 igsfb_init_seq(struct igsfb_devconfig
*dc
)
131 bus_space_tag_t iot
= dc
->dc_iot
;
132 bus_space_handle_t ioh
= dc
->dc_ioh
;
134 /* start messing with sequencer */
135 igs_seq_write(iot
, ioh
, IGS_SEQ_RESET
, 0);
137 igs_seq_write(iot
, ioh
, 1, 0x01); /* 8 dot clock */
138 igs_seq_write(iot
, ioh
, 2, 0x0f); /* enable all maps */
139 igs_seq_write(iot
, ioh
, 3, 0x00); /* character generator */
140 igs_seq_write(iot
, ioh
, 4, 0x0e); /* memory mode */
142 /* this selects color mode among other things */
143 bus_space_write_1(iot
, ioh
, IGS_MISC_OUTPUT_W
, 0xef);
145 /* normal sequencer operation */
146 igs_seq_write(iot
, ioh
, IGS_SEQ_RESET
,
147 IGS_SEQ_RESET_SYNC
| IGS_SEQ_RESET_ASYNC
);
152 * Init CRTC to 640x480 8bpp at 60Hz
155 igsfb_init_crtc(struct igsfb_devconfig
*dc
)
157 bus_space_tag_t iot
= dc
->dc_iot
;
158 bus_space_handle_t ioh
= dc
->dc_ioh
;
160 igs_crtc_write(iot
, ioh
, 0x00, 0x5f);
161 igs_crtc_write(iot
, ioh
, 0x01, 0x4f);
162 igs_crtc_write(iot
, ioh
, 0x02, 0x50);
163 igs_crtc_write(iot
, ioh
, 0x03, 0x80);
164 igs_crtc_write(iot
, ioh
, 0x04, 0x52);
165 igs_crtc_write(iot
, ioh
, 0x05, 0x9d);
166 igs_crtc_write(iot
, ioh
, 0x06, 0x0b);
167 igs_crtc_write(iot
, ioh
, 0x07, 0x3e);
169 /* next block is almost constant, only bit 6 in reg 9 differs */
170 igs_crtc_write(iot
, ioh
, 0x08, 0x00);
171 igs_crtc_write(iot
, ioh
, 0x09, 0x40); /* <- either 0x40 or 0x60 */
172 igs_crtc_write(iot
, ioh
, 0x0a, 0x00);
173 igs_crtc_write(iot
, ioh
, 0x0b, 0x00);
174 igs_crtc_write(iot
, ioh
, 0x0c, 0x00);
175 igs_crtc_write(iot
, ioh
, 0x0d, 0x00);
176 igs_crtc_write(iot
, ioh
, 0x0e, 0x00);
177 igs_crtc_write(iot
, ioh
, 0x0f, 0x00);
179 igs_crtc_write(iot
, ioh
, 0x10, 0xe9);
180 igs_crtc_write(iot
, ioh
, 0x11, 0x8b);
181 igs_crtc_write(iot
, ioh
, 0x12, 0xdf);
182 igs_crtc_write(iot
, ioh
, 0x13, 0x50);
183 igs_crtc_write(iot
, ioh
, 0x14, 0x00);
184 igs_crtc_write(iot
, ioh
, 0x15, 0xe6);
185 igs_crtc_write(iot
, ioh
, 0x16, 0x04);
186 igs_crtc_write(iot
, ioh
, 0x17, 0xc3);
188 igs_crtc_write(iot
, ioh
, 0x18, 0xff);
193 * Init graphics controller.
194 * This is common for all video modes.
197 igsfb_init_grfx(struct igsfb_devconfig
*dc
)
199 bus_space_tag_t iot
= dc
->dc_iot
;
200 bus_space_handle_t ioh
= dc
->dc_ioh
;
202 igs_grfx_write(iot
, ioh
, 0, 0x00);
203 igs_grfx_write(iot
, ioh
, 1, 0x00);
204 igs_grfx_write(iot
, ioh
, 2, 0x00);
205 igs_grfx_write(iot
, ioh
, 3, 0x00);
206 igs_grfx_write(iot
, ioh
, 4, 0x00);
207 igs_grfx_write(iot
, ioh
, 5, 0x60); /* SRMODE, MODE256 */
208 igs_grfx_write(iot
, ioh
, 6, 0x05); /* 64k @ a0000, GRAPHICS */
209 igs_grfx_write(iot
, ioh
, 7, 0x0f); /* color compare all */
210 igs_grfx_write(iot
, ioh
, 8, 0xff); /* bitmask = all bits mutable */
215 * Init attribute controller.
216 * This is common for all video modes.
219 igsfb_init_attr(struct igsfb_devconfig
*dc
)
221 bus_space_tag_t iot
= dc
->dc_iot
;
222 bus_space_handle_t ioh
= dc
->dc_ioh
;
225 igs_attr_flip_flop(iot
, ioh
); /* reset attr flip-flop to address */
227 for (i
= 0; i
< 16; ++i
) /* crt palette */
228 igs_attr_write(iot
, ioh
, i
, i
);
230 igs_attr_write(iot
, ioh
, 0x10, 0x01); /* select graphic mode */
231 igs_attr_write(iot
, ioh
, 0x11, 0x00); /* crt overscan color */
232 igs_attr_write(iot
, ioh
, 0x12, 0x0f); /* color plane enable */
233 igs_attr_write(iot
, ioh
, 0x13, 0x00);
234 igs_attr_write(iot
, ioh
, 0x14, 0x00);
239 * When done with ATTR controller, call this to unblank the screen.
242 igsfb_video_on(struct igsfb_devconfig
*dc
)
244 bus_space_tag_t iot
= dc
->dc_iot
;
245 bus_space_handle_t ioh
= dc
->dc_ioh
;
247 igs_attr_flip_flop(iot
, ioh
);
248 bus_space_write_1(iot
, ioh
, IGS_ATTR_IDX
, 0x20);
249 bus_space_write_1(iot
, ioh
, IGS_ATTR_IDX
, 0x20);
254 * Latch VCLK (b0/b1) and MCLK (b2/b3) values.
257 igsfb_freq_latch(struct igsfb_devconfig
*dc
)
259 bus_space_tag_t iot
= dc
->dc_iot
;
260 bus_space_handle_t ioh
= dc
->dc_ioh
;
262 bus_space_write_1(iot
, ioh
, IGS_EXT_IDX
, 0xb9);
263 bus_space_write_1(iot
, ioh
, IGS_EXT_PORT
, 0x80);
264 bus_space_write_1(iot
, ioh
, IGS_EXT_PORT
, 0x00);
269 igsfb_init_ext(struct igsfb_devconfig
*dc
)
271 bus_space_tag_t iot
= dc
->dc_iot
;
272 bus_space_handle_t ioh
= dc
->dc_ioh
;
273 int is_cyberpro
= (dc
->dc_id
>= 0x2000);
275 igs_ext_write(iot
, ioh
, 0x10, 0x10); /* IGS_EXT_START_ADDR enable */
276 igs_ext_write(iot
, ioh
, 0x12, 0x00); /* IGS_EXT_IRQ_CTL disable */
277 igs_ext_write(iot
, ioh
, 0x13, 0x00); /* MBZ for normal operation */
279 igs_ext_write(iot
, ioh
, 0x31, 0x00); /* segment write ptr */
280 igs_ext_write(iot
, ioh
, 0x32, 0x00); /* segment read ptr */
282 /* IGS_EXT_BIU_MISC_CTL: linearen, copren, copaselb, segon */
283 igs_ext_write(iot
, ioh
, 0x33, 0x1d);
285 /* sprite location */
286 igs_ext_write(iot
, ioh
, 0x50, 0x00);
287 igs_ext_write(iot
, ioh
, 0x51, 0x00);
288 igs_ext_write(iot
, ioh
, 0x52, 0x00);
289 igs_ext_write(iot
, ioh
, 0x53, 0x00);
290 igs_ext_write(iot
, ioh
, 0x54, 0x00);
291 igs_ext_write(iot
, ioh
, 0x55, 0x00);
292 igs_ext_write(iot
, ioh
, 0x56, 0x00); /* sprite control */
294 /* IGS_EXT_GRFX_MODE */
295 igs_ext_write(iot
, ioh
, 0x57, 0x01); /* raster fb */
298 igs_ext_write(iot
, ioh
, 0x58, 0x00);
299 igs_ext_write(iot
, ioh
, 0x59, 0x00);
300 igs_ext_write(iot
, ioh
, 0x5A, 0x00);
303 * Video memory size &c. We rely on firmware to program
304 * BUS_CTL(30), MEM_CTL1(71), MEM_CTL2(72) appropriately.
307 /* ext memory ctl0 */
308 igs_ext_write(iot
, ioh
, 0x70, 0x0B); /* enable fifo, seq */
310 /* ext hidden ctl1 */
311 igs_ext_write(iot
, ioh
, 0x73, 0x30); /* XXX: krups: 0x20 */
313 /* ext fifo control */
314 igs_ext_write(iot
, ioh
, 0x74, 0x10); /* XXX: krups: 0x1b */
315 igs_ext_write(iot
, ioh
, 0x75, 0x10); /* XXX: krups: 0x1e */
317 igs_ext_write(iot
, ioh
, 0x76, 0x00); /* ext seq. */
318 igs_ext_write(iot
, ioh
, 0x7A, 0xC8); /* ext. hidden ctl */
320 /* ext graphics ctl: GCEXTPATH. krups 1, nettrom 1, docs 3 */
321 igs_ext_write(iot
, ioh
, 0x90, 0x01);
323 if (is_cyberpro
) /* select normal vclk/mclk registers */
324 igs_ext_write(iot
, ioh
, 0xBF, 0x00);
326 igs_ext_write(iot
, ioh
, 0xB0, 0xD2); /* VCLK = 25.175MHz */
327 igs_ext_write(iot
, ioh
, 0xB1, 0xD3);
328 igs_ext_write(iot
, ioh
, 0xB2, 0xDB); /* MCLK = 75MHz*/
329 igs_ext_write(iot
, ioh
, 0xB3, 0x54);
330 igsfb_freq_latch(dc
);
333 igs_ext_write(iot
, ioh
, 0xF8, 0x04); /* XXX: ??? */
335 /* 640x480 8bpp at 60Hz */
336 igs_ext_write(iot
, ioh
, 0x11, 0x00);
337 igs_ext_write(iot
, ioh
, 0x77, 0x01); /* 8bpp, indexed */
338 igs_ext_write(iot
, ioh
, 0x14, 0x51);
339 igs_ext_write(iot
, ioh
, 0x15, 0x00);
344 igsfb_init_dac(struct igsfb_devconfig
*dc
)
346 bus_space_tag_t iot
= dc
->dc_iot
;
347 bus_space_handle_t ioh
= dc
->dc_ioh
;
350 /* RAMDAC address 2 select */
351 reg
= igs_ext_read(iot
, ioh
, IGS_EXT_SPRITE_CTL
);
352 igs_ext_write(iot
, ioh
, IGS_EXT_SPRITE_CTL
,
353 reg
| IGS_EXT_SPRITE_DAC_PEL
);
356 bus_space_write_1(iot
, ioh
, IGS_DAC_CMD
, 0x06);
359 igs_ext_write(iot
, ioh
, IGS_EXT_SPRITE_CTL
, reg
);
361 bus_space_write_1(iot
, ioh
, IGS_PEL_MASK
, 0xff);
366 igsfb_1024x768_8bpp_60Hz(struct igsfb_devconfig
*dc
)
368 bus_space_tag_t iot
= dc
->dc_iot
;
369 bus_space_handle_t ioh
= dc
->dc_ioh
;
371 igs_crtc_write(iot
, ioh
, 0x11, 0x00); /* write enable CRTC 0..7 */
373 igs_crtc_write(iot
, ioh
, 0x00, 0xa3);
374 igs_crtc_write(iot
, ioh
, 0x01, 0x7f);
375 igs_crtc_write(iot
, ioh
, 0x02, 0x7f); /* krups: 80 */
376 igs_crtc_write(iot
, ioh
, 0x03, 0x85); /* krups: 84 */
377 igs_crtc_write(iot
, ioh
, 0x04, 0x84); /* krups: 88 */
378 igs_crtc_write(iot
, ioh
, 0x05, 0x95); /* krups: 99 */
379 igs_crtc_write(iot
, ioh
, 0x06, 0x24);
380 igs_crtc_write(iot
, ioh
, 0x07, 0xfd);
382 /* next block is almost constant, only bit 6 in reg 9 differs */
383 igs_crtc_write(iot
, ioh
, 0x08, 0x00);
384 igs_crtc_write(iot
, ioh
, 0x09, 0x60); /* <- either 0x40 or 0x60 */
385 igs_crtc_write(iot
, ioh
, 0x0a, 0x00);
386 igs_crtc_write(iot
, ioh
, 0x0b, 0x00);
387 igs_crtc_write(iot
, ioh
, 0x0c, 0x00);
388 igs_crtc_write(iot
, ioh
, 0x0d, 0x00);
389 igs_crtc_write(iot
, ioh
, 0x0e, 0x00);
390 igs_crtc_write(iot
, ioh
, 0x0f, 0x00);
392 igs_crtc_write(iot
, ioh
, 0x10, 0x06);
393 igs_crtc_write(iot
, ioh
, 0x11, 0x8c);
394 igs_crtc_write(iot
, ioh
, 0x12, 0xff);
395 igs_crtc_write(iot
, ioh
, 0x13, 0x80); /* depends on BPP */
396 igs_crtc_write(iot
, ioh
, 0x14, 0x0f);
397 igs_crtc_write(iot
, ioh
, 0x15, 0x02);
398 igs_crtc_write(iot
, ioh
, 0x16, 0x21);
399 igs_crtc_write(iot
, ioh
, 0x17, 0xe3);
400 igs_crtc_write(iot
, ioh
, 0x18, 0xff);
402 igs_ext_write(iot
, ioh
, 0xB0, 0xE2); /* VCLK */
403 igs_ext_write(iot
, ioh
, 0xB1, 0x58);
405 /* XXX: hmm, krups does this */
406 igs_ext_write(iot
, ioh
, 0xB2, 0xE2); /* MCLK */
407 igs_ext_write(iot
, ioh
, 0xB3, 0x58);
409 igsfb_freq_latch(dc
);
411 igs_ext_write(iot
, ioh
, 0x11, 0x00);
412 igs_ext_write(iot
, ioh
, 0x77, 0x01); /* 8bpp, indexed */
413 igs_ext_write(iot
, ioh
, 0x14, 0x81);
414 igs_ext_write(iot
, ioh
, 0x15, 0x00);
419 dc
->dc_stride
= dc
->dc_width
;
424 * igs-video-init from krups prom
427 igsfb_hw_setup(struct igsfb_devconfig
*dc
)
429 const struct videomode
*mode
= NULL
;
440 while ((strcmp(dc
->dc_modestring
, videomode_list
[i
].name
) != 0) &&
441 ( i
< videomode_count
)) {
445 if (i
< videomode_count
) {
446 size
= videomode_list
[i
].hdisplay
* videomode_list
[i
].vdisplay
;
447 /* found a mode, now let's see if we can display it */
448 if ((videomode_list
[i
].dot_clock
<= IGS_MAX_CLOCK
) &&
449 (videomode_list
[i
].hdisplay
<= 2048) &&
450 (videomode_list
[i
].hdisplay
>= 320) &&
451 (videomode_list
[i
].vdisplay
<= 2048) &&
452 (videomode_list
[i
].vdisplay
>= 200) &&
453 (size
<= (dc
->dc_memsz
- 0x1000))) {
454 mode
= &videomode_list
[i
];
456 * now let's see which maximum depth we can support
459 d
= (dc
->dc_vmemsz
- 0x1000) / size
;
461 dc
->dc_maxdepth
= 32;
463 dc
->dc_maxdepth
= 16;
471 igsfb_set_mode(dc
, mode
, 8);
473 igsfb_1024x768_8bpp_60Hz(dc
);
481 igsfb_set_mode(struct igsfb_devconfig
*dc
, const struct videomode
*mode
,
484 bus_space_tag_t iot
= dc
->dc_iot
;
485 bus_space_handle_t ioh
= dc
->dc_ioh
;
486 int i
, m
, n
, p
, hoffset
, bytes_per_pixel
, memfetch
;
487 int vsync_start
, hsync_start
, vsync_end
, hsync_end
;
488 int vblank_start
, vblank_end
, hblank_start
, hblank_end
;
490 uint8_t vclk1
, vclk2
, vclk3
, overflow
, reg
, seq_mode
;
494 seq_mode
= IGS_EXT_SEQ_8BPP
;
497 seq_mode
= IGS_EXT_SEQ_15BPP
; /* 5-5-5 */
500 seq_mode
= IGS_EXT_SEQ_16BPP
; /* 5-6-5 */
503 seq_mode
= IGS_EXT_SEQ_24BPP
; /* 8-8-8 */
506 seq_mode
= IGS_EXT_SEQ_32BPP
;
509 aprint_error("igsfb: unsupported depth (%d), reverting"
510 " to 8 bit\n", depth
);
512 seq_mode
= IGS_EXT_SEQ_8BPP
;
514 bytes_per_pixel
= depth
>> 3;
516 hoffset
= (mode
->hdisplay
>> 3) * bytes_per_pixel
;
517 memfetch
= hoffset
+ 1;
518 overflow
= (((mode
->vtotal
- 2) & 0x400) >> 10) |
519 (((mode
->vdisplay
-1) & 0x400) >> 9) |
520 ((mode
->vsync_start
& 0x400) >> 8) |
521 ((mode
->vsync_start
& 0x400) >> 7) |
524 /* RAMDAC address 2 select */
525 reg
= igs_ext_read(iot
, ioh
, IGS_EXT_SPRITE_CTL
);
526 igs_ext_write(iot
, ioh
, IGS_EXT_SPRITE_CTL
,
527 reg
| IGS_EXT_SPRITE_DAC_PEL
);
531 bus_space_write_1(dc
->dc_iot
, dc
->dc_ioh
, IGS_DAC_CMD
, 0x06);
534 bus_space_write_1(dc
->dc_iot
, dc
->dc_ioh
, IGS_DAC_CMD
, 0x16);
537 igs_ext_write(iot
, ioh
, IGS_EXT_SPRITE_CTL
, reg
);
539 bus_space_write_1(iot
, ioh
, IGS_PEL_MASK
, 0xff);
541 igs_crtc_write(iot
, ioh
, 0x11, 0x00); /* write enable CRTC 0..7 */
543 hsync_start
= mode
->hsync_start
;
544 hsync_end
= mode
->hsync_end
;
546 hblank_start
= min(mode
->hsync_start
, mode
->hdisplay
);
547 hblank_end
= hsync_end
;
548 if ((hblank_end
- hblank_start
) >= 63 * 8) {
551 * H Blanking size must be < 63*8. Same remark as above.
553 hblank_start
= hblank_end
- 63 * 8;
556 vblank_start
= min(mode
->vsync_start
, mode
->vdisplay
);
557 vblank_end
= mode
->vsync_end
;
559 vsync_start
= mode
->vsync_start
;
560 vsync_end
= mode
->vsync_end
;
561 igs_crtc_write(iot
, ioh
, 0x00, (mode
->htotal
>> 3) - 5);
562 igs_crtc_write(iot
, ioh
, 0x01, (mode
->hdisplay
>> 3) - 1);
563 igs_crtc_write(iot
, ioh
, 0x02, (hblank_start
>> 3) - 1);
564 igs_crtc_write(iot
, ioh
, 0x03, 0x80 | (((hblank_end
>> 3) - 1) & 0x1f));
565 igs_crtc_write(iot
, ioh
, 0x04, hsync_start
>> 3);
566 igs_crtc_write(iot
, ioh
, 0x05, ((((hblank_end
>> 3) - 1) & 0x20) << 2)
567 | ((hsync_end
>> 3) & 0x1f));
568 igs_crtc_write(iot
, ioh
, 0x06, (mode
->vtotal
- 2) & 0xff);
569 igs_crtc_write(iot
, ioh
, 0x07,
570 ((vsync_start
& 0x200) >> 2) |
571 (((mode
->vdisplay
- 1) & 0x200) >> 3) |
572 (((mode
->vtotal
- 2) & 0x200) >> 4) |
574 (((vblank_start
- 1) & 0x100) >> 5) |
575 ((vsync_start
& 0x100) >> 6) |
576 (((mode
->vdisplay
- 1) & 0x100) >> 7) |
577 ((mode
->vtotal
& 0x100) >> 8));
579 igs_crtc_write(iot
, ioh
, 0x08, 0x00);
580 igs_crtc_write(iot
, ioh
, 0x09, 0x40 |
581 (((vblank_start
- 1) & 0x200) >> 4));
582 igs_crtc_write(iot
, ioh
, 0x0a, 0x00);
583 igs_crtc_write(iot
, ioh
, 0x0b, 0x00);
584 igs_crtc_write(iot
, ioh
, 0x0c, 0x00);
585 igs_crtc_write(iot
, ioh
, 0x0d, 0x00);
586 igs_crtc_write(iot
, ioh
, 0x0e, 0x00);
587 igs_crtc_write(iot
, ioh
, 0x0f, 0x00);
589 igs_crtc_write(iot
, ioh
, 0x10, vsync_start
& 0xff);
590 igs_crtc_write(iot
, ioh
, 0x11, (vsync_end
& 0x0f) | 0x20);
591 igs_crtc_write(iot
, ioh
, 0x12, (mode
->vdisplay
- 1) & 0xff);
592 igs_crtc_write(iot
, ioh
, 0x13, hoffset
& 0xff);
593 igs_crtc_write(iot
, ioh
, 0x14, 0x0f);
594 igs_crtc_write(iot
, ioh
, 0x15, (vblank_start
- 1) & 0xff);
595 igs_crtc_write(iot
, ioh
, 0x16, (vblank_end
- 1) & 0xff);
596 igs_crtc_write(iot
, ioh
, 0x17, 0xe3);
597 igs_crtc_write(iot
, ioh
, 0x18, 0xff);
599 for (i
= 0; i
< 0x10; i
++)
600 igs_attr_write(iot
, ioh
, i
, i
);
602 igs_attr_write(iot
, ioh
, 0x10, 0x01);
603 igs_attr_write(iot
, ioh
, 0x11, 0x00);
604 igs_attr_write(iot
, ioh
, 0x12, 0x0f);
605 igs_attr_write(iot
, ioh
, 0x13, 0x00);
607 igs_grfx_write(iot
, ioh
, 0x00, 0x00);
608 igs_grfx_write(iot
, ioh
, 0x01, 0x00);
609 igs_grfx_write(iot
, ioh
, 0x02, 0x00);
610 igs_grfx_write(iot
, ioh
, 0x03, 0x00);
611 igs_grfx_write(iot
, ioh
, 0x04, 0x00);
612 igs_grfx_write(iot
, ioh
, 0x05, 0x60);
613 igs_grfx_write(iot
, ioh
, 0x06, 0x05);
614 igs_grfx_write(iot
, ioh
, 0x07, 0x0f);
615 igs_grfx_write(iot
, ioh
, 0x08, 0xff);
617 /* crank up memory clock to 95MHz - needed for higher resolutions */
618 igs_ext_write(iot
, ioh
, IGS_EXT_MCLK0
, 0x91);
619 igs_ext_write(iot
, ioh
, IGS_EXT_MCLK1
, 0x6a);
620 igsfb_freq_latch(dc
);
622 igs_ext_write(iot
, ioh
, IGS_EXT_VOVFL
, overflow
);
623 igs_ext_write(iot
, ioh
, IGS_EXT_SEQ_MISC
, seq_mode
);
624 igs_ext_write(iot
, ioh
, 0x14, memfetch
& 0xff);
625 igs_ext_write(iot
, ioh
, 0x15,
626 ((memfetch
& 0x300) >> 8) | ((hoffset
& 0x300) >> 4));
628 /* finally set the dot clock */
629 igsfb_calc_pll(mode
->dot_clock
, &m
, &n
, &p
, 2047, 255, 7, IGS_MIN_VCO
);
630 DPRINTF("m: %x, n: %x, p: %x\n", m
, n
, p
);
632 vclk2
= (n
& 0x1f) | ((p
<< 6) & 0xc0) |
633 (mode
->dot_clock
> 180000 ? 0x20 : 0);
634 vclk3
= ((m
>> 8) & 0x7) | ((n
>> 2) & 0x38) | ((p
<< 4) & 0x40);
635 DPRINTF("clk: %02x %02x %02x\n", vclk1
, vclk2
, vclk3
);
636 igs_ext_write(iot
, ioh
, IGS_EXT_VCLK0
, vclk1
);
637 igs_ext_write(iot
, ioh
, IGS_EXT_VCLK1
, vclk2
);
638 igs_ext_write(iot
, ioh
, 0xBA, vclk3
);
639 igsfb_freq_latch(dc
);
640 DPRINTF("clock: %d\n", IGS_CLOCK(m
, n
, p
));
642 if (dc
->dc_id
> 0x2000) {
643 /* we have a blitter, so configure it as well */
644 bus_space_write_1(dc
->dc_iot
, dc
->dc_coph
, IGS_COP_MAP_FMT_REG
,
645 bytes_per_pixel
- 1);
646 bus_space_write_2(dc
->dc_iot
, dc
->dc_coph
,
647 IGS_COP_SRC_MAP_WIDTH_REG
, dc
->dc_width
- 1);
648 bus_space_write_2(dc
->dc_iot
, dc
->dc_coph
,
649 IGS_COP_DST_MAP_WIDTH_REG
, dc
->dc_width
- 1);
652 /* re-init the cursor data address too */
653 croffset
= dc
->dc_vmemsz
- IGS_CURSOR_DATA_SIZE
;
654 croffset
>>= 10; /* bytes -> kilobytes */
655 igs_ext_write(dc
->dc_iot
, dc
->dc_ioh
,
656 IGS_EXT_SPRITE_DATA_LO
, croffset
& 0xff);
657 igs_ext_write(dc
->dc_iot
, dc
->dc_ioh
,
658 IGS_EXT_SPRITE_DATA_HI
, (croffset
>> 8) & 0xf);
660 dc
->dc_width
= mode
->hdisplay
;
661 dc
->dc_height
= mode
->vdisplay
;
662 dc
->dc_depth
= depth
;
663 dc
->dc_stride
= dc
->dc_width
* (depth
>> 3);
670 igsfb_calc_pll(int target
, int *Mp
, int *Np
, int *Pp
, int maxM
, int maxN
,
671 int maxP
, int minVco
)
673 int M
, N
, P
, bestM
= 0, bestN
= 0;
678 * Compute correct P value to keep VCO in range
680 for (P
= 0; P
<= maxP
; P
++)
682 f_vco
= target
* IGS_SCALE(P
);
687 /* M = f_out / f_ref * ((N + 1) * IGS_SCALE(P)); */
689 for (N
= 1; N
<= maxN
; N
++)
691 M
= ((target
* (N
+ 1) * IGS_SCALE(P
) + (IGS_CLOCK_REF
/2)) +
692 IGS_CLOCK_REF
/2) / IGS_CLOCK_REF
- 1;
693 if (0 <= M
&& M
<= maxM
)
695 f_out
= IGS_CLOCK(M
,N
,P
);
696 err
= target
- f_out
;