tdvfb.c revision 1.1 1 /* $NetBSD: tdvfb.c,v 1.1 2012/07/18 23:30:14 rkujawa Exp $ */
2
3 /*
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Radoslaw Kujawa.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
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.
29 */
30
31 /*
32 * A console driver for 3Dfx Voodoo2 (CVG).
33 *
34 * 3Dfx Glide 2.x source code, Linux driver by Ghozlane Toumi, and
35 * "Voodoo2 Graphics Engine for 3D Game Acceleration" document were used as
36 * reference. wscons attachment code based mostly on genfb by Michael
37 * Lorenz.
38 *
39 * This driver currently only support boards with ICS GENDAC (which seems to
40 * be most popular, however at least two different DACs were used with CVG).
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: tdvfb.c,v 1.1 2012/07/18 23:30:14 rkujawa Exp $");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/device.h>
50 #include <sys/endian.h>
51
52 #include <dev/pci/pcivar.h>
53 #include <dev/pci/pcireg.h>
54 #include <dev/pci/pcidevs.h>
55 #include <dev/pci/pciio.h>
56
57 #include <dev/pci/tdvfbreg.h>
58 #include <dev/pci/tdvfbvar.h>
59
60 #include <dev/videomode/videomode.h>
61
62 #include "opt_wsemul.h"
63 #include "opt_tdvfb.h"
64
65 #define MAXLOOP 4096
66
67 static int tdvfb_match(device_t, cfdata_t, void *);
68 static void tdvfb_attach(device_t, device_t, void *);
69
70 static uint32_t tdvfb_cvg_read(struct tdvfb_softc *sc, uint32_t reg);
71 static void tdvfb_cvg_write(struct tdvfb_softc *sc, uint32_t reg,
72 uint32_t val);
73 static void tdvfb_cvg_set(struct tdvfb_softc *sc, uint32_t reg,
74 uint32_t bits);
75 static void tdvfb_cvg_unset(struct tdvfb_softc *sc, uint32_t reg,
76 uint32_t bits);
77 static uint8_t tdvfb_cvg_dac_read(struct tdvfb_softc *sc, uint32_t reg);
78 void tdvfb_cvg_dac_write(struct tdvfb_softc *sc, uint32_t reg,
79 uint32_t val);
80 static void tdvfb_wait(struct tdvfb_softc *sc);
81
82 static bool tdvfb_init(struct tdvfb_softc *sc);
83 static void tdvfb_fbiinit_defaults(struct tdvfb_softc *sc);
84 static size_t tdvfb_mem_size(struct tdvfb_softc *sc);
85
86 static bool tdvfb_videomode_set(struct tdvfb_softc *sc);
87 static void tdvfb_videomode_dac(struct tdvfb_softc *sc);
88
89 static bool tdvfb_gendac_detect(struct tdvfb_softc *sc);
90 static struct tdvfb_dac_timing tdvfb_gendac_calc_pll(int freq);
91 static void tdvfb_gendac_set_cvg_timing(struct tdvfb_softc *sc,
92 struct tdvfb_dac_timing *timing);
93 static void tdvfb_gendac_set_vid_timing(struct tdvfb_softc *sc,
94 struct tdvfb_dac_timing *timing);
95
96 static void tdvfb_init_screen(void *cookie, struct vcons_screen *scr,
97 int existing, long *defattr);
98 static void tdvfb_init_palette(struct tdvfb_softc *sc);
99
100 CFATTACH_DECL_NEW(tdvfb, sizeof(struct tdvfb_softc),
101 tdvfb_match, tdvfb_attach, NULL, NULL);
102
103 static int
104 tdvfb_match(device_t parent, cfdata_t match, void *aux)
105 {
106 const struct pci_attach_args *pa = (const struct pci_attach_args *)aux;
107
108 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3DFX) &&
109 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DFX_VOODOO2))
110 return 100;
111
112 return 0;
113 }
114
115 static void
116 tdvfb_attach(device_t parent, device_t self, void *aux)
117 {
118 struct tdvfb_softc *sc = device_private(self);
119 struct wsemuldisplaydev_attach_args ws_aa;
120 struct rasops_info *ri;
121 const struct pci_attach_args *pa = aux;
122 pcireg_t screg;
123 bool console;
124 long defattr;
125
126 #ifdef TDVFB_CONSOLE
127 console = true;
128 #else
129 console = false;
130 #endif
131
132 sc->sc_pc = pa->pa_pc;
133 sc->sc_pcitag = pa->pa_tag;
134 sc->sc_dev = self;
135
136 screg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
137 PCI_COMMAND_STATUS_REG);
138 screg |= PCI_COMMAND_MEM_ENABLE;
139 pci_conf_write(sc->sc_pc, sc->sc_pcitag, PCI_COMMAND_STATUS_REG,
140 screg);
141
142 pci_aprint_devinfo(pa, NULL);
143
144 /* map the BAR */
145 if (pci_mapreg_map(pa, TDV_MM_BAR, PCI_MAPREG_TYPE_MEM, 0,
146 &sc->sc_cvgt, &sc->sc_cvgh, &sc->sc_cvg_pa, 0) != 0 ) {
147 aprint_error_dev(sc->sc_dev, "unable to map CVG BAR");
148 return;
149 }
150
151 /* Map the framebuffer. */
152 if (bus_space_subregion(sc->sc_cvgt, sc->sc_cvgh, TDV_OFF_FB,
153 TDV_FB_SIZE, &sc->sc_fbh)) {
154 aprint_error_dev(sc->sc_dev, "unable to map the framebuffer");
155 }
156
157 aprint_normal_dev(sc->sc_dev, "CVG at 0x%08x, fb at 0x%08x\n",
158 sc->sc_cvg_pa, sc->sc_cvg_pa + TDV_OFF_FB);
159
160 /* Do the low level setup. */
161 if (!tdvfb_init(sc)) {
162 aprint_error_dev(sc->sc_dev, "could not initialize CVG\n");
163 return;
164 }
165
166 /*
167 * The card is alive now, let's check how much framebuffer memory
168 * do we have.
169 */
170 sc->sc_memsize = tdvfb_mem_size(sc);
171
172 /* Select video mode, 800x600x60 by default... */
173 sc->sc_width = 800;
174 sc->sc_height = 600;
175 sc->sc_bpp = 32;
176 sc->sc_linebytes = 1024 * (sc->sc_bpp / 8);
177 sc->sc_videomode = pick_mode_by_ref(sc->sc_width, sc->sc_height, 60);
178
179 tdvfb_videomode_set(sc);
180
181 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
182 "default",
183 0, 0,
184 NULL,
185 8, 16,
186 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
187 NULL
188 };
189 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
190 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
191 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
192
193 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
194 &sc->sc_accessops);
195 sc->vd.init_screen = tdvfb_init_screen;
196
197 ri = &sc->sc_console_screen.scr_ri;
198
199 tdvfb_init_palette(sc);
200
201 if (console) {
202 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
203 &defattr);
204
205 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC |
206 VCONS_DONT_READ;
207 vcons_redraw_screen(&sc->sc_console_screen);
208
209 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
210 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
211 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
212 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
213
214 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
215 defattr);
216 vcons_replay_msgbuf(&sc->sc_console_screen);
217 } else if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
218 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
219 &defattr);
220 }
221
222 ws_aa.console = console;
223 ws_aa.scrdata = &sc->sc_screenlist;
224 ws_aa.accessops = &sc->sc_accessops;
225 ws_aa.accesscookie = &sc->vd;
226
227 config_found(sc->sc_dev, &ws_aa, wsemuldisplaydevprint);
228 }
229
230 static void
231 tdvfb_init_palette(struct tdvfb_softc *sc)
232 {
233 int i, j;
234
235 j = 0;
236 for (i = 0; i < 256; i++) {
237 sc->sc_cmap_red[i] = rasops_cmap[j];
238 sc->sc_cmap_green[i] = rasops_cmap[j + 1];
239 sc->sc_cmap_blue[i] = rasops_cmap[j + 2];
240 j += 3;
241 }
242 }
243
244 static void
245 tdvfb_init_screen(void *cookie, struct vcons_screen *scr, int existing,
246 long *defattr)
247 {
248 struct tdvfb_softc *sc = cookie;
249 struct rasops_info *ri = &scr->scr_ri;
250
251 wsfont_init();
252
253 ri->ri_depth = sc->sc_bpp;
254 ri->ri_width = sc->sc_width;
255 ri->ri_height = sc->sc_height;
256 ri->ri_stride = sc->sc_linebytes;
257 ri->ri_flg = RI_CENTER;
258 ri->ri_bits = (char *) bus_space_vaddr(sc->sc_cvgt, sc->sc_fbh);
259
260 scr->scr_flags |= VCONS_DONT_READ;
261
262 rasops_init(ri, 0, 0);
263 ri->ri_caps = WSSCREEN_WSCOLORS;
264 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
265 sc->sc_width / ri->ri_font->fontwidth);
266
267 ri->ri_hw = scr;
268 }
269
270 static bool
271 tdvfb_videomode_set(struct tdvfb_softc *sc)
272 {
273 uint32_t fbiinit1, fbiinit5, fbiinit6, lfbmode;
274 uint16_t vbackporch, vsyncon, vsyncoff;
275 uint16_t hbackporch, hsyncon, hsyncoff;
276 uint16_t yheight, xwidth;
277
278 yheight = sc->sc_videomode->vdisplay;
279 xwidth = sc->sc_videomode->hdisplay;
280
281 vbackporch = sc->sc_videomode->vtotal - sc->sc_videomode->vsync_end;
282 hbackporch = sc->sc_videomode->htotal - sc->sc_videomode->hsync_end;
283
284 vsyncon = sc->sc_videomode->vsync_end - sc->sc_videomode->vsync_start;
285 hsyncon = sc->sc_videomode->hsync_end - sc->sc_videomode->hsync_start;
286
287 vsyncoff = sc->sc_videomode->vtotal - vsyncon;
288 hsyncoff = sc->sc_videomode->htotal - hsyncon;
289 #ifdef TDVFB_DEBUG
290 aprint_normal_dev(sc->sc_dev,
291 "xy %d %d hbp %d vbp %d, hson %d, hsoff %d, vson %d, vsoff %d\n",
292 xwidth, yheight, hbackporch, vbackporch, hsyncon, hsyncoff,
293 vsyncon, vsyncoff);
294 #endif /* TDVFB_DEBUG */
295
296 sc->vid_timing = tdvfb_gendac_calc_pll(sc->sc_videomode->dot_clock);
297
298 sc->sc_x_tiles = (sc->sc_videomode->hdisplay + 63 ) / 64 * 2;
299
300 tdvfb_cvg_write(sc, TDV_OFF_NOPCMD, 0);
301 tdvfb_wait(sc);
302
303 /* enable writing to fbiinit regs, reset, disable DRAM refresh */
304 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
305 TDV_INITENABLE_EN_INIT);
306 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT1, TDV_FBIINIT1_VIDEO_RST);
307 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT0, TDV_FBIINIT0_FBI_RST |
308 TDV_FBIINIT0_FIFO_RST);
309 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT2, TDV_FBIINIT2_DRAM_REFR);
310 tdvfb_wait(sc);
311
312 /* program video timings into CVG */
313 tdvfb_cvg_write(sc, TDV_OFF_VDIMENSIONS, yheight << 16 | (xwidth - 1));
314 tdvfb_cvg_write(sc, TDV_OFF_BACKPORCH, vbackporch << 16 | (hbackporch-2));
315 tdvfb_cvg_write(sc, TDV_OFF_HSYNC, hsyncoff << 16 | (hsyncon - 1));
316 tdvfb_cvg_write(sc, TDV_OFF_VSYNC, vsyncoff << 16 | vsyncon);
317
318 tdvfb_videomode_dac(sc);
319
320 fbiinit1 = ((tdvfb_cvg_read(sc, TDV_OFF_FBIINIT1) &
321 TDV_FBIINIT1_VIDMASK) |
322 TDV_FBIINIT1_DR_DATA |
323 TDV_FBIINIT1_DR_BLANKING |
324 TDV_FBIINIT1_DR_HVSYNC |
325 TDV_FBIINIT1_DR_DCLK |
326 TDV_FBIINIT1_IN_VCLK_2X );
327
328 fbiinit1 |= ((sc->sc_x_tiles & 0x20) >> 5) << TDV_FBIINIT1_TILES_X_MSB |
329 ((sc->sc_x_tiles & 0x1e) >> 1) << TDV_FBIINIT1_TILES_X;
330 fbiinit6 = (sc->sc_x_tiles & 0x1) << TDV_FBIINIT6_TILES_X_LSB;
331
332 fbiinit1 |= TDV_FBIINIT1_VCLK_2X << TDV_FBIINIT1_VCLK_SRC;
333
334 fbiinit5 = tdvfb_cvg_read(sc, TDV_OFF_FBIINIT5) & TDV_FBIINIT5_VIDMASK;
335
336 if (sc->sc_videomode->flags & VID_PHSYNC)
337 fbiinit5 |= TDV_FBIINIT5_PHSYNC;
338 if (sc->sc_videomode->flags & VID_PVSYNC)
339 fbiinit5 |= TDV_FBIINIT5_PVSYNC;
340
341 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT1, fbiinit1);
342 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT6, fbiinit6);
343 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT5, fbiinit6);
344 tdvfb_wait(sc);
345
346 /* unreset, enable DRAM refresh */
347 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT1, TDV_FBIINIT1_VIDEO_RST);
348 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT0, TDV_FBIINIT0_FBI_RST |
349 TDV_FBIINIT0_FIFO_RST);
350 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT2, TDV_FBIINIT2_DRAM_REFR);
351 /* diable access to FBIINIT regs */
352 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
353 TDV_INITENABLE_EN_FIFO);
354 tdvfb_wait(sc);
355
356 lfbmode = TDV_LFBMODE_8888;
357
358 #if BYTE_ORDER == BIG_ENDIAN
359 lfbmode |= TDV_LFBMODE_BSW_WR | TDV_LFBMODE_BSW_RD;
360 #endif
361
362 tdvfb_cvg_write(sc, TDV_OFF_LFBMODE, lfbmode);
363
364 return true;
365 }
366
367 /*
368 * Update DAC parameters for selected video mode.
369 */
370 static void
371 tdvfb_videomode_dac(struct tdvfb_softc *sc)
372 {
373 uint32_t fbiinit2, fbiinit3;
374
375 /* remember current FBIINIT settings */
376 fbiinit2 = tdvfb_cvg_read(sc, TDV_OFF_FBIINIT2);
377 fbiinit3 = tdvfb_cvg_read(sc, TDV_OFF_FBIINIT3);
378
379 /* remap DAC */
380 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
381 TDV_INITENABLE_EN_INIT | TDV_INITENABLE_REMAPDAC);
382
383 tdvfb_cvg_dac_write(sc, TDV_GENDAC_CMD, TDV_GENDAC_CMD_16BITS);
384
385 tdvfb_gendac_set_vid_timing(sc, &(sc->vid_timing));
386
387 /* disable remapping */
388 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
389 TDV_INITENABLE_EN_INIT);
390 /* restore */
391 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT2, fbiinit2);
392 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT2, fbiinit3);
393 }
394
395 /*
396 * Check how much memory do we have. Actually, Voodoo1/2 has separate
397 * framebuffer and texture memory. This function only checks for framebuffer
398 * memory. Texture memory ramains unused.
399 */
400 static size_t
401 tdvfb_mem_size(struct tdvfb_softc *sc)
402 {
403 size_t mem_size;
404 uint32_t vram_test4, vram_test2;
405
406 bus_space_write_4(sc->sc_cvgt, sc->sc_fbh, 0, 0x11aabbaa);
407 bus_space_write_4(sc->sc_cvgt, sc->sc_fbh, 0x100000, 0x22aabbaa);
408 bus_space_write_4(sc->sc_cvgt, sc->sc_fbh, 0x200000, 0x44aabbaa);
409
410 vram_test4 = bus_space_read_4(sc->sc_cvgt, sc->sc_fbh, 0x400000);
411 vram_test2 = bus_space_read_4(sc->sc_cvgt, sc->sc_fbh, 0x200000);
412
413 if (vram_test4 == 0x44aabbaa)
414 mem_size = 4*1024*1024;
415 else if (vram_test2 == 0x22aabbaa) {
416 mem_size = 2*1024*1024;
417 } else
418 mem_size = 1*1024*1024;
419
420 return mem_size;
421 }
422
423 /* do the low level init of Voodoo board */
424 static bool
425 tdvfb_init(struct tdvfb_softc *sc)
426 {
427 /* undocumented - found in glide code */
428 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_VCLK_DISABLE_REG, 0);
429 /* allow write to hardware initialization registers */
430 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
431 TDV_INITENABLE_EN_INIT);
432
433 /* reset the board */
434 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT1, TDV_FBIINIT1_VIDEO_RST);
435 tdvfb_wait(sc);
436 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT0, TDV_FBIINIT0_FBI_RST |
437 TDV_FBIINIT0_FIFO_RST);
438 tdvfb_wait(sc);
439
440 /* disable video RAM refresh */
441 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT2, TDV_FBIINIT2_DRAM_REFR);
442 tdvfb_wait(sc);
443
444 /* on voodoo1 I had to read FBIINIT2 before remapping,
445 * otherwise weird things were happening, on v2 it works just fine */
446 /* tdvfb_cvg_read(sc, TDV_OFF_FBIINIT2); */
447
448 /* remap DAC */
449 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
450 TDV_INITENABLE_EN_INIT | TDV_INITENABLE_REMAPDAC);
451
452 /* detect supported DAC, TODO: we really should support other DACs */
453 if(!tdvfb_gendac_detect(sc)) {
454 aprint_error_dev(sc->sc_dev, "could not detect ICS GENDAC\n");
455 return false;
456 }
457
458 /* calculate PLL used to drive the CVG (graphics clock) */
459 sc->cvg_timing = tdvfb_gendac_calc_pll(TDV_CVG_CLK);
460
461 /* set PLL for gfx clock */
462 tdvfb_gendac_set_cvg_timing(sc, &(sc->cvg_timing));
463
464 /* don't remap the DAC anymore */
465 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
466 TDV_INITENABLE_EN_INIT | TDV_INITENABLE_EN_FIFO);
467
468 /* set FBIINIT registers to some default values that make sense */
469 tdvfb_fbiinit_defaults(sc);
470
471 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG,
472 TDV_INITENABLE_EN_FIFO);
473 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_VCLK_ENABLE_REG, 0);
474
475 return true;
476 }
477
478 static void
479 tdvfb_fbiinit_defaults(struct tdvfb_softc *sc)
480 {
481 uint32_t fbiinit0, fbiinit1, fbiinit2, fbiinit3, fbiinit4, fbiinit6;
482
483 fbiinit0 = TDV_FBIINIT0_VGA_PASS; /* disable VGA passthrough */
484 fbiinit1 = /*TDV_FBIINIT1_PCIWAIT |*/ /* one wait state for PCI write */
485 TDV_FBIINIT1_LFB_EN | /* enable lfb reads */
486 TDV_FBIINIT1_VIDEO_RST | /* video timing reset */
487 10 << TDV_FBIINIT1_TILES_X | /* tiles x/horizontal */
488 TDV_FBIINIT1_VCLK_2X << TDV_FBIINIT1_VCLK_SRC ;
489
490 fbiinit2 = TDV_FBIINIT2_SWB_ALG |/* swap buffer use DAC sync */
491 TDV_FBIINIT2_FAST_RAS | /* fast RAS read */
492 TDV_FBIINIT2_DRAM_OE | /* enable DRAM OE */
493 TDV_FBIINIT2_DRAM_REFR | /* enable DRAM refresh */
494 TDV_FBIINIT2_FIFO_RDA | /* FIFO read ahead */
495 TDV_FBIINIT2_DRAM_REF16 << TDV_FBIINIT2_DRAM_REFLD; /* 16 ms */
496
497 fbiinit3 = TDV_FBIINIT3_TREX_DIS; /* disable texture mapping */
498
499 fbiinit4 = /*TDV_FBIINIT4_PCIWAIT|*/ /* one wait state for PCI write */
500 TDV_FBIINIT4_LFB_RDA; /* lfb read ahead */
501
502 fbiinit6 = 0;
503 #ifdef TDVFB_DEBUG
504 aprint_normal("fbiinit: 0 %x, 1 %x, 2 %x, 3 %x, 4 %x, 6 %x\n",
505 fbiinit0, fbiinit1, fbiinit2, fbiinit3, fbiinit4, fbiinit6);
506 #endif /* TDVFB_DEBUG */
507 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT0, fbiinit0);
508 tdvfb_wait(sc);
509 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT1, fbiinit1);
510 tdvfb_wait(sc);
511 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT2, fbiinit2);
512 tdvfb_wait(sc);
513 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT3, fbiinit3);
514 tdvfb_wait(sc);
515 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT4, fbiinit4);
516 tdvfb_wait(sc);
517 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT6, fbiinit6);
518 tdvfb_wait(sc);
519 }
520
521 static void
522 tdvfb_gendac_set_vid_timing(struct tdvfb_softc *sc,
523 struct tdvfb_dac_timing *timing)
524 {
525 uint8_t pllreg;
526
527 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_CTRL);
528 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
529
530 /* write the timing for gfx clock into "slot" 0 */
531 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_0);
532 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->m);
533 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->n);
534 /* select "slot" 0 for output */
535 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_CTRL);
536 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA,
537 (pllreg & TDV_GENDAC_VIDPLLMASK) | TDV_GENDAC_PLL_VIDCLK |
538 TDV_GENDAC_PLL_VIDCLK0);
539 tdvfb_wait(sc);
540 tdvfb_wait(sc);
541 #ifdef TDVFB_DEBUG
542 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_0);
543 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
544 aprint_normal("vid read again: %d\n", pllreg);
545 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
546 aprint_normal("vid read again: %d\n", pllreg);
547 #endif /* TDVFB_DEBUG */
548 }
549
550 static void
551 tdvfb_gendac_set_cvg_timing(struct tdvfb_softc *sc,
552 struct tdvfb_dac_timing *timing)
553 {
554 uint8_t pllreg;
555
556 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_CTRL);
557 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
558
559 /* write the timing for gfx clock into "slot" A */
560 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_A);
561 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->m);
562 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->n);
563 /* select "slot" A for output */
564 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_CTRL);
565 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA,
566 (pllreg & TDV_GENDAC_CVGPLLMASK) | TDV_GENDAC_PLL_CVGCLKA);
567 #ifdef TDVFB_DEBUG
568 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_A);
569 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
570 aprint_normal("read again: %d\n", pllreg);
571 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
572 aprint_normal("read again: %d\n", pllreg);
573 #endif /* TDVFB_DEBUG */
574 tdvfb_wait(sc);
575 }
576
577 static struct tdvfb_dac_timing
578 tdvfb_gendac_calc_pll(int freq)
579 {
580 int n1, n2;
581 int m, mdbl;
582 int best_m, best_n1, best_error;
583 int fout;
584 struct tdvfb_dac_timing timing;
585
586 best_m = -1; best_n1 = -1;
587
588 /* select highest possible n2, check n2 * fCLK < TDV_GENDAC_MAXVCO */
589 for (n2 = TDV_GENDAC_MAX_N2; n2 >= TDV_GENDAC_MIN_N2; n2--) {
590 if ((freq * (1 << n2)) < TDV_GENDAC_MAXVCO)
591 break;
592 }
593
594 best_error = freq;
595
596 /*
597 * m+2 2^n2 * fOUT
598 * ---- = -----------
599 * n1+2 fREF
600 */
601 for (n1 = TDV_GENDAC_MIN_N1; n1 <= TDV_GENDAC_MAX_N1; n1++) {
602 /* loop mostly inspired by Linux driver */
603 mdbl = (2 * freq * (1 << n2)*(n1 + 2)) / TDV_GENDAC_REFFREQ - 4;
604 if (mdbl % 2)
605 m = mdbl/2+1;
606 else
607 m = mdbl/2;
608
609 if(m > TDV_GENDAC_MAX_M)
610 break;
611
612 fout = (TDV_GENDAC_REFFREQ * (m + 2)) / ((1 << n2) * (n1 + 2));
613 if ((abs(fout - freq) < best_error) && (m > 0)) {
614 best_n1 = n1;
615 best_m = m;
616 best_error = abs(fout - freq);
617 if (200*best_error < freq) break;
618 }
619
620 }
621
622 fout = (TDV_GENDAC_REFFREQ * (best_m + 2)) / ((1 << n2) * (best_n1 + 2));
623 timing.m = best_m;
624 timing.n = (n2 << 5) | best_n1;
625 timing.fout = fout;
626
627 #ifdef TDVFB_DEBUG
628 aprint_normal("tdvfb_gendac_calc_pll ret: m %d, n %d, fout %d kHz\n",
629 timing.m, timing.n, timing.fout);
630 #endif /* TDVFB_DEBUG */
631
632 return timing;
633 }
634
635 static bool
636 tdvfb_gendac_detect(struct tdvfb_softc *sc)
637 {
638 uint8_t m_f1, m_f7, m_fb;
639 uint8_t n_f1, n_f7, n_fb;
640
641 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, 0x1);
642 m_f1 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
643 n_f1 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
644 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, 0x7);
645 m_f7 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
646 n_f7 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
647 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, 0xB);
648 m_fb = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
649 n_fb = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA);
650
651 if( (m_f1 == TDV_GENDAC_DFLT_F1_M) &&
652 (n_f1 == TDV_GENDAC_DFLT_F1_N) &&
653 (m_f7 == TDV_GENDAC_DFLT_F7_M) &&
654 (n_f7 == TDV_GENDAC_DFLT_F7_N) &&
655 (n_fb == TDV_GENDAC_DFLT_FB_N) &&
656 (n_fb == TDV_GENDAC_DFLT_FB_N) ) {
657 aprint_normal_dev(sc->sc_dev, "ICS 5342 GENDAC\n");
658 return true;
659 }
660
661 return false;
662 }
663
664 static void
665 tdvfb_wait(struct tdvfb_softc *sc)
666 {
667 uint32_t x, cnt;
668 cnt = 0;
669 for (x = 0; x < MAXLOOP; x++) {
670 if (tdvfb_cvg_read(sc, TDV_OFF_STATUS) & TDV_STATUS_FBI_BUSY)
671 cnt = 0;
672 else
673 cnt++;
674
675 if (cnt >= 5) /* Voodoo2 specs suggest at least 3 */
676 break;
677 }
678
679 if (x == MAXLOOP)
680 /*
681 * The console probably isn't working now anyway, so maybe
682 * let's panic... At least it will drop into ddb if some other
683 * device a console.
684 */
685 panic("tdvfb is stuck!\n");
686 }
687
688 static uint32_t
689 tdvfb_cvg_read(struct tdvfb_softc *sc, uint32_t reg)
690 {
691 uint32_t rv;
692 rv = bus_space_read_4(sc->sc_cvgt, sc->sc_cvgh, reg);
693 #ifdef TDVFB_DEBUG
694 aprint_normal("cvg_read val %x from reg %x\n", rv, reg);
695 #endif /* TDVFB_DEBUG */
696 return rv;
697 }
698
699 static void
700 tdvfb_cvg_write(struct tdvfb_softc *sc, uint32_t reg, uint32_t val)
701 {
702 #ifdef TDVFB_DEBUG
703 aprint_normal("cvg_write val %x to reg %x\n", val, reg);
704 #endif /* TDVFB_DEBUG */
705 bus_space_write_4(sc->sc_cvgt, sc->sc_cvgh, reg, val);
706 }
707
708 static void
709 tdvfb_cvg_set(struct tdvfb_softc *sc, uint32_t reg, uint32_t bits)
710 {
711 uint32_t v;
712 v = tdvfb_cvg_read(sc, reg) | bits;
713 tdvfb_cvg_write(sc, reg, v);
714 }
715
716 static void
717 tdvfb_cvg_unset(struct tdvfb_softc *sc, uint32_t reg, uint32_t bits)
718 {
719 uint32_t v;
720 v = tdvfb_cvg_read(sc, reg) & ~bits;
721 tdvfb_cvg_write(sc, reg, v);
722 }
723
724 static uint8_t
725 tdvfb_cvg_dac_read(struct tdvfb_softc *sc, uint32_t reg)
726 {
727 uint32_t rv;
728
729 tdvfb_cvg_dac_write(sc, reg, TDV_DAC_DATA_READ);
730
731 rv = tdvfb_cvg_read(sc, TDV_OFF_DAC_READ);
732 #ifdef TDVFB_DEBUG
733 aprint_normal("cvg_dac_read val %x from reg %x\n", rv, reg);
734 #endif /* TDVFB_DEBUG */
735 return rv & 0xFF;
736 }
737
738 void
739 tdvfb_cvg_dac_write(struct tdvfb_softc *sc, uint32_t reg, uint32_t val)
740 {
741 uint32_t wreg;
742
743 wreg = ((reg & TDV_GENDAC_ADDRMASK) << 8) | val;
744
745 #ifdef TDVFB_DEBUG
746 aprint_normal("cvg_dac_write val %x to reg %x (%x)\n", val, reg,
747 wreg);
748 #endif /* TDVFB_DEBUG */
749
750 tdvfb_cvg_write(sc, TDV_OFF_DAC_DATA, wreg);
751 tdvfb_wait(sc);
752 }
753
754