gffb.c revision 1.2 1 /* $NetBSD: gffb.c,v 1.2 2013/10/02 16:35:38 macallan Exp $ */
2
3 /*
4 * Copyright (c) 2007, 2012 Michael Lorenz
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * A console driver for nvidia geforce graphics controllers
30 * tested on macppc only so far
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: gffb.c,v 1.2 2013/10/02 16:35:38 macallan Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/lwp.h>
42 #include <sys/kauth.h>
43 #include <sys/atomic.h>
44
45 #include <dev/videomode/videomode.h>
46
47 #include <dev/pci/pcivar.h>
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcidevs.h>
50 #include <dev/pci/pciio.h>
51 #include <dev/pci/gffbreg.h>
52
53 #include <dev/wscons/wsdisplayvar.h>
54 #include <dev/wscons/wsconsio.h>
55 #include <dev/wsfont/wsfont.h>
56 #include <dev/rasops/rasops.h>
57 #include <dev/wscons/wsdisplay_vconsvar.h>
58 #include <dev/pci/wsdisplay_pci.h>
59 #include <dev/wscons/wsdisplay_glyphcachevar.h>
60
61 #include <dev/i2c/i2cvar.h>
62
63 #include "opt_gffb.h"
64 #include "opt_vcons.h"
65
66 #ifdef GFFB_DEBUG
67 #define DPRINTF printf
68 #else
69 #define DPRINTF while(0) printf
70 #endif
71
72 struct gffb_softc {
73 device_t sc_dev;
74
75 pci_chipset_tag_t sc_pc;
76 pcitag_t sc_pcitag;
77
78 bus_space_tag_t sc_memt;
79 bus_space_tag_t sc_iot;
80
81 bus_space_handle_t sc_regh, sc_fbh;
82 bus_addr_t sc_fb, sc_reg;
83 bus_size_t sc_fbsize, sc_regsize;
84 uint8_t *sc_fbaddr;
85 size_t sc_vramsize;
86
87 int sc_width, sc_height, sc_depth, sc_stride;
88 int sc_locked;
89 struct vcons_screen sc_console_screen;
90 struct wsscreen_descr sc_defaultscreen_descr;
91 const struct wsscreen_descr *sc_screens[1];
92 struct wsscreen_list sc_screenlist;
93 struct vcons_data vd;
94 int sc_mode;
95 u_char sc_cmap_red[256];
96 u_char sc_cmap_green[256];
97 u_char sc_cmap_blue[256];
98 int sc_put, sc_current, sc_free;
99 glyphcache sc_gc;
100 };
101
102 static int gffb_match(device_t, cfdata_t, void *);
103 static void gffb_attach(device_t, device_t, void *);
104
105 CFATTACH_DECL_NEW(gffb, sizeof(struct gffb_softc),
106 gffb_match, gffb_attach, NULL, NULL);
107
108 static int gffb_ioctl(void *, void *, u_long, void *, int,
109 struct lwp *);
110 static paddr_t gffb_mmap(void *, void *, off_t, int);
111 static void gffb_init_screen(void *, struct vcons_screen *, int, long *);
112
113 static int gffb_putcmap(struct gffb_softc *, struct wsdisplay_cmap *);
114 static int gffb_getcmap(struct gffb_softc *, struct wsdisplay_cmap *);
115 static void gffb_restore_palette(struct gffb_softc *);
116 static int gffb_putpalreg(struct gffb_softc *, uint8_t, uint8_t,
117 uint8_t, uint8_t);
118
119 static void gffb_init(struct gffb_softc *);
120
121 static void gffb_make_room(struct gffb_softc *, int);
122
123 #if notyet
124 static void gffb_flush_engine(struct gffb_softc *);
125 static void gffb_rectfill(struct gffb_softc *, int, int, int, int,
126 uint32_t);
127 static void gffb_bitblt(void *, int, int, int, int, int,
128 int, int);
129
130 static void gffb_cursor(void *, int, int, int);
131 static void gffb_putchar(void *, int, int, u_int, long);
132 static void gffb_putchar_aa(void *, int, int, u_int, long);
133 static void gffb_copycols(void *, int, int, int, int);
134 static void gffb_erasecols(void *, int, int, int, long);
135 static void gffb_copyrows(void *, int, int, int);
136 static void gffb_eraserows(void *, int, int, long);
137 #endif /* notyet */
138
139 struct wsdisplay_accessops gffb_accessops = {
140 gffb_ioctl,
141 gffb_mmap,
142 NULL, /* alloc_screen */
143 NULL, /* free_screen */
144 NULL, /* show_screen */
145 NULL, /* load_font */
146 NULL, /* pollc */
147 NULL /* scroll */
148 };
149
150 static int
151 gffb_match(device_t parent, cfdata_t match, void *aux)
152 {
153 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
154
155 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
156 return 0;
157 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NVIDIA)
158 return 0;
159
160 /* only card tested on so far - likely need a list */
161 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GEFORCE2MX)
162 return 100;
163 return (0);
164 }
165
166 static void
167 gffb_attach(device_t parent, device_t self, void *aux)
168 {
169 struct gffb_softc *sc = device_private(self);
170 struct pci_attach_args *pa = aux;
171 struct rasops_info *ri;
172 bus_space_tag_t tag;
173 struct wsemuldisplaydev_attach_args aa;
174 prop_dictionary_t dict;
175 unsigned long defattr;
176 bool is_console;
177 int i, j;
178 uint8_t cmap[768];
179
180 sc->sc_pc = pa->pa_pc;
181 sc->sc_pcitag = pa->pa_tag;
182 sc->sc_memt = pa->pa_memt;
183 sc->sc_iot = pa->pa_iot;
184 sc->sc_dev = self;
185
186 pci_aprint_devinfo(pa, NULL);
187
188 /* fill in parameters from properties */
189 dict = device_properties(self);
190 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) {
191 aprint_error("%s: no width property\n", device_xname(self));
192 return;
193 }
194 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) {
195 aprint_error("%s: no height property\n", device_xname(self));
196 return;
197 }
198
199 #ifdef GLYPHCACHE_DEBUG
200 /* leave some visible VRAM unused so we can see the glyph cache */
201 sc->sc_height -= 200;
202 #endif
203
204 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
205 aprint_error("%s: no depth property\n", device_xname(self));
206 return;
207 }
208 if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) {
209 aprint_error("%s: no linebytes property\n",
210 device_xname(self));
211 return;
212 }
213
214 prop_dictionary_get_bool(dict, "is_console", &is_console);
215
216 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM,
217 BUS_SPACE_MAP_PREFETCHABLE | BUS_SPACE_MAP_LINEAR,
218 &tag, &sc->sc_fbh, &sc->sc_fb, &sc->sc_fbsize)) {
219 aprint_error("%s: failed to map the framebuffer.\n",
220 device_xname(sc->sc_dev));
221 }
222 sc->sc_fbaddr = bus_space_vaddr(tag, sc->sc_fbh);
223
224 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0,
225 &tag, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) {
226 aprint_error("%s: failed to map registers.\n",
227 device_xname(sc->sc_dev));
228 }
229
230 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self),
231 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
232
233 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
234 "default",
235 0, 0,
236 NULL,
237 8, 16,
238 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
239 NULL
240 };
241 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
242 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
243 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
244 sc->sc_locked = 0;
245
246 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
247 &gffb_accessops);
248 sc->vd.init_screen = gffb_init_screen;
249
250 sc->sc_vramsize = bus_space_read_4(sc->sc_memt, sc->sc_regh,
251 GFFB_VRAM) & 0xfff00000;
252
253 printf("vram: %d MB\n", sc->sc_vramsize >> 20);
254 printf("put: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT));
255 printf("get: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET));
256 /* init engine here */
257 gffb_init(sc);
258 printf("put: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT));
259 printf("get: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET));
260
261 ri = &sc->sc_console_screen.scr_ri;
262
263 #if notyet
264 sc->sc_gc.gc_bitblt = gffb_bitblt;
265 sc->sc_gc.gc_blitcookie = sc;
266 sc->sc_gc.gc_rop = R128_ROP3_S;
267 #endif
268
269 if (is_console) {
270 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
271 &defattr);
272 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
273
274 #if notyet
275 gffb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
276 ri->ri_devcmap[(defattr >> 16) & 0xff]);
277 #else
278 memset(sc->sc_fbaddr + 0x2000,
279 ri->ri_devcmap[(defattr >> 16) & 0xff],
280 sc->sc_height * sc->sc_stride);
281 #endif
282 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
283 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
284 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
285 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
286 #if notyet
287 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
288 (0x800000 / sc->sc_stride) - sc->sc_height - 5,
289 sc->sc_width,
290 ri->ri_font->fontwidth,
291 ri->ri_font->fontheight,
292 defattr);
293 #endif
294 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
295 defattr);
296 vcons_replay_msgbuf(&sc->sc_console_screen);
297 } else {
298 /*
299 * since we're not the console we can postpone the rest
300 * until someone actually allocates a screen for us
301 */
302 if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
303 /* do some minimal setup to avoid weirdnesses later */
304 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
305 &defattr);
306 } else
307 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
308 #if notyet
309 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
310 (0x800000 / sc->sc_stride) - sc->sc_height - 5,
311 sc->sc_width,
312 ri->ri_font->fontwidth,
313 ri->ri_font->fontheight,
314 defattr);
315 #endif
316 }
317
318 j = 0;
319 rasops_get_cmap(ri, cmap, sizeof(cmap));
320 for (i = 0; i < 256; i++) {
321 sc->sc_cmap_red[i] = cmap[j];
322 sc->sc_cmap_green[i] = cmap[j + 1];
323 sc->sc_cmap_blue[i] = cmap[j + 2];
324 gffb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
325 j += 3;
326 }
327
328 /* no suspend/resume support yet */
329 pmf_device_register(sc->sc_dev, NULL, NULL);
330
331 aa.console = is_console;
332 aa.scrdata = &sc->sc_screenlist;
333 aa.accessops = &gffb_accessops;
334 aa.accesscookie = &sc->vd;
335
336 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
337 }
338
339 static int
340 gffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
341 struct lwp *l)
342 {
343 struct vcons_data *vd = v;
344 struct gffb_softc *sc = vd->cookie;
345 struct wsdisplay_fbinfo *wdf;
346 struct vcons_screen *ms = vd->active;
347
348 switch (cmd) {
349 case WSDISPLAYIO_GTYPE:
350 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
351 return 0;
352
353 /* PCI config read/write passthrough. */
354 case PCI_IOC_CFGREAD:
355 case PCI_IOC_CFGWRITE:
356 return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
357 cmd, data, flag, l);
358
359 case WSDISPLAYIO_GET_BUSID:
360 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
361 sc->sc_pcitag, data);
362
363 case WSDISPLAYIO_GINFO:
364 if (ms == NULL)
365 return ENODEV;
366 wdf = (void *)data;
367 wdf->height = ms->scr_ri.ri_height;
368 wdf->width = ms->scr_ri.ri_width;
369 wdf->depth = ms->scr_ri.ri_depth;
370 wdf->cmsize = 256;
371 return 0;
372
373 case WSDISPLAYIO_GETCMAP:
374 return gffb_getcmap(sc,
375 (struct wsdisplay_cmap *)data);
376
377 case WSDISPLAYIO_PUTCMAP:
378 return gffb_putcmap(sc,
379 (struct wsdisplay_cmap *)data);
380
381 case WSDISPLAYIO_LINEBYTES:
382 *(u_int *)data = sc->sc_stride;
383 return 0;
384
385 case WSDISPLAYIO_SMODE: {
386 int new_mode = *(int*)data;
387 if (new_mode != sc->sc_mode) {
388 sc->sc_mode = new_mode;
389 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
390 gffb_init(sc);
391 gffb_restore_palette(sc);
392 #if notyet
393 glyphcache_wipe(&sc->sc_gc);
394 gffb_rectfill(sc, 0, 0, sc->sc_width,
395 sc->sc_height, ms->scr_ri.ri_devcmap[
396 (ms->scr_defattr >> 16) & 0xff]);
397 #endif
398 vcons_redraw_screen(ms);
399 }
400 }
401 }
402 return 0;
403 #if notyet
404 case WSDISPLAYIO_GET_EDID: {
405 struct wsdisplayio_edid_info *d = data;
406 return wsdisplayio_get_edid(sc->sc_dev, d);
407 }
408 #endif
409 }
410 return EPASSTHROUGH;
411 }
412
413 static paddr_t
414 gffb_mmap(void *v, void *vs, off_t offset, int prot)
415 {
416 struct vcons_data *vd = v;
417 struct gffb_softc *sc = vd->cookie;
418 paddr_t pa;
419
420 /* 'regular' framebuffer mmap()ing */
421 if (offset < sc->sc_fbsize) {
422 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset + 0x2000,
423 0, prot, BUS_SPACE_MAP_LINEAR);
424 return pa;
425 }
426
427 /*
428 * restrict all other mappings to processes with superuser privileges
429 * or the kernel itself
430 */
431 if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM,
432 NULL, NULL, NULL, NULL) != 0) {
433 aprint_normal("%s: mmap() rejected.\n",
434 device_xname(sc->sc_dev));
435 return -1;
436 }
437
438 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
439 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
440 BUS_SPACE_MAP_LINEAR);
441 return pa;
442 }
443
444 if ((offset >= sc->sc_reg) &&
445 (offset < (sc->sc_reg + sc->sc_regsize))) {
446 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
447 BUS_SPACE_MAP_LINEAR);
448 return pa;
449 }
450
451 #ifdef PCI_MAGIC_IO_RANGE
452 /* allow mapping of IO space */
453 if ((offset >= PCI_MAGIC_IO_RANGE) &&
454 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
455 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
456 0, prot, BUS_SPACE_MAP_LINEAR);
457 return pa;
458 }
459 #endif
460
461 #ifdef OFB_ALLOW_OTHERS
462 if (offset >= 0x80000000) {
463 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
464 BUS_SPACE_MAP_LINEAR);
465 return pa;
466 }
467 #endif
468 return -1;
469 }
470
471 static void
472 gffb_init_screen(void *cookie, struct vcons_screen *scr,
473 int existing, long *defattr)
474 {
475 struct gffb_softc *sc = cookie;
476 struct rasops_info *ri = &scr->scr_ri;
477
478 ri->ri_depth = sc->sc_depth;
479 ri->ri_width = sc->sc_width;
480 ri->ri_height = sc->sc_height;
481 ri->ri_stride = sc->sc_stride;
482 ri->ri_bits = sc->sc_fbaddr + 0x2000;
483 ri->ri_flg = RI_CENTER;
484 if (sc->sc_depth == 8)
485 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
486
487 rasops_init(ri, 0, 0);
488 ri->ri_caps = WSSCREEN_WSCOLORS;
489 scr->scr_flags |= VCONS_DONT_READ;
490
491 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
492 sc->sc_width / ri->ri_font->fontwidth);
493
494 ri->ri_hw = scr;
495 #if notyet
496 ri->ri_ops.copyrows = gffb_copyrows;
497 ri->ri_ops.copycols = gffb_copycols;
498 ri->ri_ops.eraserows = gffb_eraserows;
499 ri->ri_ops.erasecols = gffb_erasecols;
500 ri->ri_ops.cursor = gffb_cursor;
501 if (FONT_IS_ALPHA(ri->ri_font)) {
502 ri->ri_ops.putchar = gffb_putchar_aa;
503 } else
504 ri->ri_ops.putchar = gffb_putchar;
505 #endif
506 }
507
508 static int
509 gffb_putcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm)
510 {
511 u_char *r, *g, *b;
512 u_int index = cm->index;
513 u_int count = cm->count;
514 int i, error;
515 u_char rbuf[256], gbuf[256], bbuf[256];
516
517 #ifdef R128FB_DEBUG
518 aprint_debug("putcmap: %d %d\n",index, count);
519 #endif
520 if (cm->index >= 256 || cm->count > 256 ||
521 (cm->index + cm->count) > 256)
522 return EINVAL;
523 error = copyin(cm->red, &rbuf[index], count);
524 if (error)
525 return error;
526 error = copyin(cm->green, &gbuf[index], count);
527 if (error)
528 return error;
529 error = copyin(cm->blue, &bbuf[index], count);
530 if (error)
531 return error;
532
533 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
534 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
535 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
536
537 r = &sc->sc_cmap_red[index];
538 g = &sc->sc_cmap_green[index];
539 b = &sc->sc_cmap_blue[index];
540
541 for (i = 0; i < count; i++) {
542 gffb_putpalreg(sc, index, *r, *g, *b);
543 index++;
544 r++, g++, b++;
545 }
546 return 0;
547 }
548
549 static int
550 gffb_getcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm)
551 {
552 u_int index = cm->index;
553 u_int count = cm->count;
554 int error;
555
556 if (index >= 255 || count > 256 || index + count > 256)
557 return EINVAL;
558
559 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
560 if (error)
561 return error;
562 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
563 if (error)
564 return error;
565 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
566 if (error)
567 return error;
568
569 return 0;
570 }
571
572 static void
573 gffb_restore_palette(struct gffb_softc *sc)
574 {
575 int i;
576
577 for (i = 0; i < (1 << sc->sc_depth); i++) {
578 gffb_putpalreg(sc, i, sc->sc_cmap_red[i],
579 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
580 }
581 }
582
583 static int
584 gffb_putpalreg(struct gffb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
585 uint8_t b)
586 {
587 /* port 0 */
588 bus_space_write_1(sc->sc_memt, sc->sc_regh,
589 GFFB_PDIO0 + GFFB_PEL_IW, idx);
590 bus_space_write_1(sc->sc_memt, sc->sc_regh,
591 GFFB_PDIO0 + GFFB_PEL_D, r);
592 bus_space_write_1(sc->sc_memt, sc->sc_regh,
593 GFFB_PDIO0 + GFFB_PEL_D, g);
594 bus_space_write_1(sc->sc_memt, sc->sc_regh,
595 GFFB_PDIO0 + GFFB_PEL_D, b);
596
597 /* port 1 */
598 bus_space_write_1(sc->sc_memt, sc->sc_regh,
599 GFFB_PDIO1 + GFFB_PEL_IW, idx);
600 bus_space_write_1(sc->sc_memt, sc->sc_regh,
601 GFFB_PDIO1 + GFFB_PEL_D, r);
602 bus_space_write_1(sc->sc_memt, sc->sc_regh,
603 GFFB_PDIO1 + GFFB_PEL_D, g);
604 bus_space_write_1(sc->sc_memt, sc->sc_regh,
605 GFFB_PDIO1 + GFFB_PEL_D, b);
606
607 return 0;
608 }
609
610
611 static void
612 gffb_dma_kickoff(struct gffb_softc *sc)
613 {
614 volatile uint8_t scratch;
615
616 if(sc->sc_current != sc->sc_put) {
617 sc->sc_put = sc->sc_current;
618 membar_sync();
619 scratch = *sc->sc_fbaddr;
620 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT,
621 sc->sc_put);
622 }
623 }
624
625 static void
626 gffb_dmanext(struct gffb_softc *sc, uint32_t data)
627 {
628 bus_space_write_stream_4(sc->sc_memt, sc->sc_fbh, sc->sc_current, data);
629 sc->sc_current += 4;
630 }
631
632 static void
633 gffb_dmastart(struct gffb_softc *sc, uint32_t tag, int size)
634 {
635 if(sc->sc_free <= (size << 2))
636 gffb_make_room(sc, size);
637 gffb_dmanext(sc, ((size) << 18) | (tag));
638 sc->sc_free -= ((size + 1) << 2);
639 }
640
641 /*
642 * from xf86_video_nv/nv_xaa.c:
643 * There is a HW race condition with videoram command buffers.
644 * You can't jump to the location of your put offset. We write put
645 * at the jump offset + SKIPS dwords with noop padding in between
646 * to solve this problem
647 */
648
649 #define SKIPS 8
650
651 static void
652 gffb_make_room(struct gffb_softc *sc, int size)
653 {
654 uint32_t get;
655
656 size = (size + 1) << 2; /* slots -> offset */
657
658 while (sc->sc_free < size) {
659 get = bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET);
660
661 if (sc->sc_put >= get) {
662 sc->sc_free = 0x2000 - sc->sc_current;
663 if (sc->sc_free < size) {
664 gffb_dmanext(sc, 0x20000000);
665 if(get <= SKIPS) {
666 if (sc->sc_put <= SKIPS) {
667 /* corner case - will be idle */
668 bus_space_write_4(sc->sc_memt,
669 sc->sc_regh, GFFB_FIFO_PUT,
670 SKIPS + 1);
671 }
672 do {
673 get = bus_space_read_4(
674 sc->sc_memt, sc->sc_regh,
675 GFFB_FIFO_GET);
676 } while (get <= SKIPS);
677 }
678 bus_space_write_4(sc->sc_memt, sc->sc_regh,
679 GFFB_FIFO_PUT, SKIPS);
680 sc->sc_current = sc->sc_put = SKIPS;
681 sc->sc_free = get - (SKIPS + 1);
682 }
683 } else
684 sc->sc_free = get - sc->sc_current - 1;
685 }
686 }
687
688 static void
689 gffb_sync(struct gffb_softc *sc)
690 {
691 int bail;
692
693 bail = 100000;
694 while ((bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET) !=
695 sc->sc_put) && (bail > 0)) {
696 bail--;
697 delay(1);
698 }
699 if (bail == 0) printf("DMA timed out\n");
700
701 bail = 100000;
702 while((bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_BUSY) != 0) &&
703 (bail > 0)) {
704 bail--;
705 delay(1);
706 }
707 if (bail == 0) printf("engine timed out\n");
708 }
709
710 static void
711 gffb_init(struct gffb_softc *sc)
712 {
713 int i;
714
715 /* init display start */
716 bus_space_write_4(sc->sc_memt, sc->sc_regh,
717 GFFB_CRTC0 + GFFB_DISPLAYSTART, 0x2000);
718 bus_space_write_4(sc->sc_memt, sc->sc_regh,
719 GFFB_CRTC1 + GFFB_DISPLAYSTART, 0x2000);
720 bus_space_write_1(sc->sc_memt, sc->sc_regh,
721 GFFB_PDIO0 + GFFB_PEL_MASK, 0xff);
722 bus_space_write_1(sc->sc_memt, sc->sc_regh,
723 GFFB_PDIO1 + GFFB_PEL_MASK, 0xff);
724
725 /* DMA stuff. A whole lot of magic number voodoo from xf86-video-nv */
726 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PMC + 0x140, 0);
727 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PMC + 0x200, 0xffff00ff);
728 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PMC + 0x200, 0xffffffff);
729 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x800, 8);
730 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x840, 3);
731 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x500, 0);
732 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PTIMER + 0x400, 0xffffffff);
733 for (i = 0; i < 8; i++) {
734 bus_space_write_4(sc->sc_memt, sc->sc_regh,
735 GFFB_PMC + 0x240 + (i * 0x10), 0);
736 bus_space_write_4(sc->sc_memt, sc->sc_regh,
737 GFFB_PMC + 0x244 + (i * 0x10), sc->sc_vramsize - 1);
738 }
739 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN, 0x80000010);
740 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x04, 0x80011201);
741 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x08, 0x80000011);
742 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x0c, 0x80011202);
743 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x10, 0x80000012);
744 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x14, 0x80011203);
745 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x18, 0x80000013);
746 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x1c, 0x80011204);
747 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x20, 0x80000014);
748 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x24, 0x80011205);
749 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x28, 0x80000015);
750 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2c, 0x80011206);
751 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x30, 0x80000016);
752 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x34, 0x80011207);
753 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x38, 0x80000017);
754 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x3c, 0x80011208);
755 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2000, 0x00003000);
756 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2004, sc->sc_vramsize - 1);
757 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2008, 0x00000002);
758 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x200c, 0x00000002);
759 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2010, 0x01008042); /* different for nv40 */
760 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2014, 0);
761 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2018, 0x12001200);
762 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x201c, 0);
763 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2020, 0x01008043);
764 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2024, 0);
765 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2028, 0);
766 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x202c, 0);
767 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2030, 0x01008044);
768 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2034, 0x00000002);
769 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2038, 0);
770 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x203c, 0);
771 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2040, 0x01008019);
772 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2044, 0);
773 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2048, 0);
774 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x204c, 0);
775 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2050, 0x0100a05c);
776 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2054, 0);
777 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2058, 0);
778 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x205c, 0);
779 /* XXX 0x0100805f if !WaitVSynvPossible */
780 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2060, 0x0100809f);
781 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2064, 0);
782 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2068, 0x12001200);
783 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x206c, 0);
784 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2070, 0x0100804a);
785 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2074, 0x00000002);
786 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2078, 0);
787 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x207c, 0);
788 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2080, 0x01018077);
789 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2084, 0);
790 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2088, 0x12001200);
791 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x208c, 0);
792 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2090, 0x00003002);
793 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2094, 0x00007fff);
794 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2098, 0x00000002); /* start of command buffer? */
795 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x209c, 0x00000002);
796 /* __BIG_ENDIAN part? */
797 /* PGRAPH setup */
798 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0500, 0);
799 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0504, 0x00000001);
800 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1200, 0);
801 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1250, 0);
802 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1204, 0x00000100); /* different on nv40 */
803 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1240, 0);
804 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1244, 0);
805 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x122c, 0x00001209); /* different on nv40 */
806 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1000, 0);
807 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1050, 0);
808 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0210, 0x03000100);
809 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0214, 0x00000110);
810 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0218, 0x00000112);
811 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x050c, 0x0000ffff);
812 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1258, 0x0000ffff);
813 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0140, 0);
814 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0100, 0xffffffff);
815 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1054, 0x00000001);
816 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1230, 0);
817 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1280, 0);
818 #if BYTE_ORDER == BIG_ENDIAN
819 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1224, 0x800f0078);
820 #else
821 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1224, 0x000f0078);
822 #endif
823 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1220, 0x00000001);
824 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1200, 0x00000001);
825 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1250, 0x00000001);
826 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1254, 0x00000001);
827 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0500, 0x00000001);
828
829 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_CMDSTART, 0x00000002);
830 bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET, 0);
831 sc->sc_put = 0;
832 sc->sc_current = 0;
833 sc->sc_free = 0x2000;
834
835 for(i = 0; i < SKIPS; i++)
836 gffb_dmanext(sc, 0);
837
838 gffb_dmanext(sc, 0x00040000);
839 gffb_dmanext(sc, 0x80000010);
840 gffb_dmanext(sc, 0x00042000);
841 gffb_dmanext(sc, 0x80000011);
842 gffb_dmanext(sc, 0x00044000);
843 gffb_dmanext(sc, 0x80000012);
844 gffb_dmanext(sc, 0x00046000);
845 gffb_dmanext(sc, 0x80000013);
846 gffb_dmanext(sc, 0x00048000);
847 gffb_dmanext(sc, 0x80000014);
848 gffb_dmanext(sc, 0x0004A000);
849 gffb_dmanext(sc, 0x80000015);
850 gffb_dmanext(sc, 0x0004C000);
851 gffb_dmanext(sc, 0x80000016);
852 gffb_dmanext(sc, 0x0004E000);
853 gffb_dmanext(sc, 0x80000017);
854 sc->sc_free = 0x2000 - sc->sc_current;
855
856 gffb_dmastart(sc, SURFACE_FORMAT, 4);
857 gffb_dmanext(sc, SURFACE_FORMAT_DEPTH8);
858 gffb_dmanext(sc, sc->sc_stride | (sc->sc_stride << 16));
859 gffb_dmanext(sc, 0);
860 gffb_dmanext(sc, 0);
861
862 gffb_dmastart(sc, RECT_FORMAT, 1);
863 gffb_dmanext(sc, RECT_FORMAT_DEPTH8);
864
865 gffb_dmastart(sc, ROP_SET, 1);
866 gffb_dmanext(sc, 0xcc);
867
868 gffb_dma_kickoff(sc);
869 gffb_sync(sc);
870 printf("put %x current %x\n", sc->sc_put, sc->sc_current);
871 }
872
873