gffb.c revision 1.28 1 /* $NetBSD: gffb.c,v 1.28 2025/10/06 07:51:44 macallan Exp $ */
2
3 /*
4 * Copyright (c) 2013 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, should work on other hardware as long as
31 * something sets up a usable graphics mode and sets the right device properties
32 * This driver should work with all NV1x hardware but so far it's been tested
33 * only on NV11 / GeForce2 MX. Needs testing with more hardware and if
34 * successful, PCI IDs need to be added to gffb_match()
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: gffb.c,v 1.28 2025/10/06 07:51:44 macallan Exp $");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/device.h>
44 #include <sys/lwp.h>
45 #include <sys/kauth.h>
46 #include <sys/atomic.h>
47
48 #include <dev/pci/pcivar.h>
49 #include <dev/pci/pcireg.h>
50 #include <dev/pci/pcidevs.h>
51 #include <dev/pci/pciio.h>
52 #include <dev/pci/gffbreg.h>
53
54 #include <dev/wscons/wsdisplayvar.h>
55 #include <dev/wscons/wsconsio.h>
56 #include <dev/wsfont/wsfont.h>
57 #include <dev/rasops/rasops.h>
58 #include <dev/wscons/wsdisplay_vconsvar.h>
59 #include <dev/pci/wsdisplay_pci.h>
60 #include <dev/wscons/wsdisplay_glyphcachevar.h>
61
62 #include "opt_gffb.h"
63 #include "opt_vcons.h"
64
65 #ifdef GFFB_DEBUG
66 #define DPRINTF printf
67 #else
68 #define DPRINTF while(0) printf
69 #endif
70
71 struct gffb_softc {
72 device_t sc_dev;
73
74 pci_chipset_tag_t sc_pc;
75 pcitag_t sc_pcitag;
76
77 bus_space_tag_t sc_memt;
78 bus_space_tag_t sc_iot;
79
80 bus_space_handle_t sc_regh, sc_fbh;
81 bus_addr_t sc_fb, sc_reg;
82 bus_size_t sc_fbsize, sc_regsize;
83 uint8_t *sc_fbaddr;
84 size_t sc_vramsize;
85 uint32_t sc_fboffset;
86
87 int sc_width, sc_height, sc_depth, sc_stride;
88 int sc_locked, sc_accel, sc_mobile, sc_video, sc_bl_level;
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, sc_arch;
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 uint32_t sc_rop;
100 void (*sc_putchar)(void *, int, int, u_int, long);
101 kmutex_t sc_lock;
102 glyphcache sc_gc;
103 };
104
105 static int gffb_match(device_t, cfdata_t, void *);
106 static void gffb_attach(device_t, device_t, void *);
107
108 CFATTACH_DECL_NEW(gffb, sizeof(struct gffb_softc),
109 gffb_match, gffb_attach, NULL, NULL);
110
111 static int gffb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
112 static paddr_t gffb_mmap(void *, void *, off_t, int);
113 static void gffb_init_screen(void *, struct vcons_screen *, int, long *);
114
115 static int gffb_putcmap(struct gffb_softc *, struct wsdisplay_cmap *);
116 static int gffb_getcmap(struct gffb_softc *, struct wsdisplay_cmap *);
117 static void gffb_restore_palette(struct gffb_softc *);
118 static int gffb_putpalreg(struct gffb_softc *, uint8_t, uint8_t,
119 uint8_t, uint8_t);
120 static void gffb_setvideo(struct gffb_softc *, int);
121 static int gffb_get_backlight(struct gffb_softc *);
122 static void gffb_set_backlight(struct gffb_softc *, int);
123 static void gffb_brightness_up(device_t);
124 static void gffb_brightness_down(device_t);
125
126 static void gffb_init(struct gffb_softc *);
127
128 static void gffb_make_room(struct gffb_softc *, int);
129 static void gffb_sync(struct gffb_softc *);
130
131 static void gffb_rectfill(struct gffb_softc *, int, int, int, int,
132 uint32_t);
133 static void gffb_bitblt(void *, int, int, int, int, int, int, int);
134 static void gffb_rop(struct gffb_softc *, int);
135
136 static void gffb_cursor(void *, int, int, int);
137 static void gffb_putchar(void *, int, int, u_int, long);
138 static void gffb_copycols(void *, int, int, int, int);
139 static void gffb_erasecols(void *, int, int, int, long);
140 static void gffb_copyrows(void *, int, int, int);
141 static void gffb_eraserows(void *, int, int, long);
142
143 #define GFFB_READ_4(o) bus_space_read_stream_4(sc->sc_memt, sc->sc_regh, (o))
144 #define GFFB_READ_1(o) bus_space_read_1(sc->sc_memt, sc->sc_regh, (o))
145 #define GFFB_WRITE_4(o, v) bus_space_write_stream_4(sc->sc_memt, sc->sc_regh, (o), (v))
146 #define GFFB_WRITE_1(o, v) bus_space_write_1(sc->sc_memt, sc->sc_regh, (o), (v))
147
148 struct wsdisplay_accessops gffb_accessops = {
149 gffb_ioctl,
150 gffb_mmap,
151 NULL, /* alloc_screen */
152 NULL, /* free_screen */
153 NULL, /* show_screen */
154 NULL, /* load_font */
155 NULL, /* pollc */
156 NULL /* scroll */
157 };
158
159 static void
160 gffb_write_crtc(struct gffb_softc *sc, int head, uint8_t reg, uint8_t val)
161 {
162 if (head == 0) {
163 GFFB_WRITE_1(GFFB_PCIO0 + 0x3d4, reg);
164 GFFB_WRITE_1(GFFB_PCIO0 + 0x3d5, val);
165 } else {
166 GFFB_WRITE_1(GFFB_PCIO1 + 0x3d4, reg);
167 GFFB_WRITE_1(GFFB_PCIO1 + 0x3d5, val);
168 }
169 }
170
171 static uint8_t
172 gffb_read_crtc(struct gffb_softc *sc, int head, uint8_t reg)
173 {
174 if (head == 0) {
175 GFFB_WRITE_1(GFFB_PCIO0 + 0x3d4, reg);
176 return GFFB_READ_1(GFFB_PCIO0 + 0x3d5);
177 } else {
178 GFFB_WRITE_1(GFFB_PCIO1 + 0x3d4, reg);
179 return GFFB_READ_1(GFFB_PCIO1 + 0x3d5);
180 }
181 }
182
183 static int
184 gffb_match(device_t parent, cfdata_t match, void *aux)
185 {
186 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
187
188 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
189 return 0;
190 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NVIDIA)
191 return 0;
192
193 /* only cards tested on so far - likely needs a list */
194 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GEFORCE2MX)
195 return 100;
196 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GEFORCE_6800U)
197 return 100;
198 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GF_FXGO5200)
199 return 100;
200 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_GF_FX5200U)
201 return 100;
202 return (0);
203 }
204
205 static void
206 gffb_attach(device_t parent, device_t self, void *aux)
207 {
208 struct gffb_softc *sc = device_private(self);
209 struct pci_attach_args *pa = aux;
210 struct rasops_info *ri;
211 bus_space_tag_t tag;
212 struct wsemuldisplaydev_attach_args aa;
213 prop_dictionary_t dict;
214 unsigned long defattr;
215 pcireg_t reg;
216 bool is_console = FALSE;
217 uint32_t addr;
218 int i, j, f;
219 uint8_t cmap[768];
220
221 sc->sc_pc = pa->pa_pc;
222 sc->sc_pcitag = pa->pa_tag;
223 sc->sc_memt = pa->pa_memt;
224 sc->sc_iot = pa->pa_iot;
225 sc->sc_dev = self;
226
227 sc->sc_mobile = 0;
228 sc->sc_video = 0;
229
230 /* first, see what kind of chip we've got */
231 reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PCI_ID_REG);
232 switch (PCI_PRODUCT(reg)) {
233 case PCI_PRODUCT_NVIDIA_GEFORCE2MX:
234 sc->sc_accel = true;
235 sc->sc_arch = 10;
236 break;
237 case PCI_PRODUCT_NVIDIA_GEFORCE_6800U:
238 sc->sc_accel = false;
239 sc->sc_arch = 40;
240 break;
241 case PCI_PRODUCT_NVIDIA_GF_FXGO5200:
242 sc->sc_mobile = 1;
243 /* FALLTHROUGH */
244 case PCI_PRODUCT_NVIDIA_GF_FX5200U:
245 sc->sc_accel = true;
246 sc->sc_arch = 30;
247 break;
248 default:
249 sc->sc_accel = false;
250 sc->sc_arch = 0;
251 }
252
253 pci_aprint_devinfo(pa, NULL);
254 DPRINTF("%s accel %d arch %d\n", __func__, sc->sc_accel, sc->sc_arch);
255 /* fill in parameters from properties */
256 dict = device_properties(self);
257 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) {
258 aprint_error("%s: no width property\n", device_xname(self));
259 return;
260 }
261 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) {
262 aprint_error("%s: no height property\n", device_xname(self));
263 return;
264 }
265
266 #ifdef GLYPHCACHE_DEBUG
267 /* leave some visible VRAM unused so we can see the glyph cache */
268 sc->sc_height -= 300;
269 #endif
270
271 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
272 aprint_error("%s: no depth property\n", device_xname(self));
273 return;
274 }
275 if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) {
276 aprint_error("%s: no linebytes property\n",
277 device_xname(self));
278 return;
279 }
280
281 /*
282 * on !2MX we need to use the firmware's offset - for some reason
283 * register writes to anything other than the DACs go wrong
284 */
285 sc->sc_fboffset = 0;
286 if (prop_dictionary_get_uint32(dict, "address", &addr)) {
287 sc->sc_fboffset = addr & 0x000fffff; /* XXX */
288 }
289 DPRINTF("%s: fboffset %8x\n", __func__, sc->sc_fboffset);
290 prop_dictionary_get_bool(dict, "is_console", &is_console);
291
292 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0,
293 &tag, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) {
294 aprint_error("%s: failed to map registers.\n",
295 device_xname(sc->sc_dev));
296 }
297 /*
298 * first thing we need to make sure register access uses host byte order
299 * so we can recycle as much of xf86-video-nv as possible
300 */
301 #if BYTE_ORDER == BIG_ENDIAN
302 uint32_t mreg = GFFB_READ_4(GFFB_PMC + 4);
303 if ((mreg & 0x01000001) == 0) {
304 GFFB_WRITE_4(GFFB_PMC + 4, 0x01000001);
305 }
306 #endif
307 sc->sc_vramsize = GFFB_READ_4(GFFB_VRAM) & 0xfff00000;
308
309 /* don't map more VRAM than we actually have */
310 if (pci_mapreg_info(sc->sc_pc, sc->sc_pcitag,
311 0x14, PCI_MAPREG_TYPE_MEM, &sc->sc_fb, &sc->sc_fbsize, &f)) {
312 aprint_error("%s: can't find the framebuffer?!\n",
313 device_xname(sc->sc_dev));
314 }
315 if (sc->sc_vramsize == 0) sc->sc_vramsize = sc->sc_fbsize;
316
317 /* don't map (much) more than we actually need */
318 if (bus_space_map(sc->sc_memt, sc->sc_fb, 0x1000000,
319 BUS_SPACE_MAP_PREFETCHABLE | BUS_SPACE_MAP_LINEAR,
320 &sc->sc_fbh)) {
321 aprint_error("%s: failed to map the framebuffer.\n",
322 device_xname(sc->sc_dev));
323 }
324 sc->sc_fbaddr = bus_space_vaddr(tag, sc->sc_fbh);
325
326 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self),
327 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
328 aprint_normal_dev(sc->sc_dev, "%d MB video memory\n",
329 (int)(sc->sc_vramsize >> 20));
330
331 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
332 "default",
333 0, 0,
334 NULL,
335 8, 16,
336 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_RESIZE,
337 NULL
338 };
339 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
340 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
341 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
342 sc->sc_locked = 0;
343
344 #ifdef GFFB_DEBUG
345 printf("put: %08x\n", GFFB_READ_4(GFFB_FIFO_PUT));
346 printf("get: %08x\n", GFFB_READ_4(GFFB_FIFO_GET));
347 #endif
348
349 /*
350 * we don't have hardware synchronization so we need a lock to serialize
351 * access to the DMA buffer between normal and kernel output
352 * actually it might be enough to use atomic ops on sc_current, sc_free
353 * etc. but for now we'll play it safe
354 * XXX we will probably deadlock if we take an interrupt while sc_lock
355 * is held and then try to printf()
356 */
357 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
358
359 /* init engine here */
360 gffb_init(sc);
361 gffb_setvideo(sc, 1);
362
363 if (sc->sc_mobile) {
364 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP,
365 gffb_brightness_up, TRUE);
366 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN,
367 gffb_brightness_down, TRUE);
368 }
369
370 #ifdef GFFB_DEBUG
371 printf("put: %08x\n", GFFB_READ_4(GFFB_FIFO_PUT));
372 printf("get: %08x\n", GFFB_READ_4(GFFB_FIFO_GET));
373 #endif
374 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
375 &gffb_accessops);
376 sc->vd.init_screen = gffb_init_screen;
377
378
379 ri = &sc->sc_console_screen.scr_ri;
380
381 if (sc->sc_accel) {
382 sc->sc_gc.gc_bitblt = gffb_bitblt;
383 sc->sc_gc.gc_blitcookie = sc;
384 sc->sc_gc.gc_rop = 0xcc;
385 sc->vd.show_screen_cookie = &sc->sc_gc;
386 sc->vd.show_screen_cb = glyphcache_adapt;
387 }
388
389 if (is_console) {
390 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
391 &defattr);
392 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
393
394 if (sc->sc_accel) {
395 gffb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
396 ri->ri_devcmap[(defattr >> 16) & 0xf]);
397 } else {
398 memset(sc->sc_fbaddr + sc->sc_fboffset,
399 ri->ri_devcmap[(defattr >> 16) & 0xf],
400 sc->sc_stride * sc->sc_height);
401 }
402 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
403 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
404 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
405 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
406
407 if (sc->sc_accel)
408 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
409 (0x800000 / sc->sc_stride) - sc->sc_height - 5,
410 sc->sc_width,
411 ri->ri_font->fontwidth,
412 ri->ri_font->fontheight,
413 defattr);
414
415 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
416 defattr);
417 vcons_replay_msgbuf(&sc->sc_console_screen);
418 } else {
419 /*
420 * since we're not the console we can postpone the rest
421 * until someone actually allocates a screen for us
422 */
423 if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
424 /* do some minimal setup to avoid weirdnesses later */
425 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
426 &defattr);
427 } else
428 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
429
430 if (sc->sc_accel)
431 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
432 (0x800000 / sc->sc_stride) - sc->sc_height - 5,
433 sc->sc_width,
434 ri->ri_font->fontwidth,
435 ri->ri_font->fontheight,
436 defattr);
437 }
438
439 j = 0;
440 rasops_get_cmap(ri, cmap, sizeof(cmap));
441 for (i = 0; i < 256; i++) {
442 sc->sc_cmap_red[i] = cmap[j];
443 sc->sc_cmap_green[i] = cmap[j + 1];
444 sc->sc_cmap_blue[i] = cmap[j + 2];
445 gffb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
446 j += 3;
447 }
448
449 /* no suspend/resume support yet */
450 if (!pmf_device_register(sc->sc_dev, NULL, NULL))
451 aprint_error_dev(sc->sc_dev,
452 "couldn't establish power handler\n");
453
454 aa.console = is_console;
455 aa.scrdata = &sc->sc_screenlist;
456 aa.accessops = &gffb_accessops;
457 aa.accesscookie = &sc->vd;
458
459 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
460 }
461
462 static int
463 gffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
464 {
465 struct vcons_data *vd = v;
466 struct gffb_softc *sc = vd->cookie;
467 struct wsdisplay_fbinfo *wdf;
468 struct vcons_screen *ms = vd->active;
469 struct wsdisplay_param *param;
470
471 switch (cmd) {
472 case WSDISPLAYIO_GTYPE:
473 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
474 return 0;
475
476 /* PCI config read/write passthrough. */
477 case PCI_IOC_CFGREAD:
478 case PCI_IOC_CFGWRITE:
479 return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
480 cmd, data, flag, l);
481
482 case WSDISPLAYIO_GET_BUSID:
483 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
484 sc->sc_pcitag, data);
485
486 case WSDISPLAYIO_GINFO:
487 if (ms == NULL)
488 return ENODEV;
489 wdf = (void *)data;
490 wdf->height = ms->scr_ri.ri_height;
491 wdf->width = ms->scr_ri.ri_width;
492 wdf->depth = ms->scr_ri.ri_depth;
493 wdf->cmsize = 256;
494 return 0;
495
496 case WSDISPLAYIO_GETCMAP:
497 return gffb_getcmap(sc,
498 (struct wsdisplay_cmap *)data);
499
500 case WSDISPLAYIO_PUTCMAP:
501 return gffb_putcmap(sc,
502 (struct wsdisplay_cmap *)data);
503
504 case WSDISPLAYIO_LINEBYTES:
505 *(u_int *)data = sc->sc_stride;
506 return 0;
507
508 case WSDISPLAYIO_SMODE: {
509 int new_mode = *(int*)data;
510 if (new_mode != sc->sc_mode) {
511 sc->sc_mode = new_mode;
512 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
513 gffb_init(sc);
514 gffb_restore_palette(sc);
515 if (sc->sc_accel) {
516 glyphcache_wipe(&sc->sc_gc);
517 gffb_rectfill(sc, 0, 0, sc->sc_width,
518 sc->sc_height, ms->scr_ri.ri_devcmap[
519 (ms->scr_defattr >> 16) & 0xf]);
520 } else {
521 memset(sc->sc_fbaddr + sc->sc_fboffset,
522 ms->scr_ri.ri_devcmap[
523 (ms->scr_defattr >> 16) & 0xf],
524 sc->sc_stride * sc->sc_height);
525 }
526 vcons_redraw_screen(ms);
527 }
528 }
529 }
530 return 0;
531
532 case WSDISPLAYIO_GET_EDID: {
533 struct wsdisplayio_edid_info *d = data;
534 return wsdisplayio_get_edid(sc->sc_dev, d);
535 }
536
537 case WSDISPLAYIO_GET_FBINFO: {
538 struct wsdisplayio_fbinfo *fbi = data;
539 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
540 }
541
542 case WSDISPLAYIO_GETPARAM:
543 param = (struct wsdisplay_param *)data;
544 if (sc->sc_mobile == 0)
545 return EPASSTHROUGH;
546 switch (param->param) {
547
548 case WSDISPLAYIO_PARAM_BRIGHTNESS:
549 param->min = 0;
550 param->max = 255;
551 param->curval = sc->sc_bl_level;
552 return 0;
553
554 case WSDISPLAYIO_PARAM_BACKLIGHT:
555 param->min = 0;
556 param->max = 1;
557 param->curval = sc->sc_video;
558 return 0;
559 }
560 return EPASSTHROUGH;
561
562 case WSDISPLAYIO_SETPARAM:
563 param = (struct wsdisplay_param *)data;
564 if (sc->sc_mobile == 0)
565 return EPASSTHROUGH;
566 switch (param->param) {
567
568 case WSDISPLAYIO_PARAM_BRIGHTNESS:
569 gffb_set_backlight(sc, param->curval);
570 return 0;
571
572 case WSDISPLAYIO_PARAM_BACKLIGHT:
573 gffb_setvideo(sc, param->curval);
574 return 0;
575 }
576 return EPASSTHROUGH;
577
578 case WSDISPLAYIO_GVIDEO:
579 if (sc->sc_video)
580 *(int *)data = WSDISPLAYIO_VIDEO_ON;
581 else
582 *(int *)data = WSDISPLAYIO_VIDEO_OFF;
583 return 0;
584
585 case WSDISPLAYIO_SVIDEO:
586 gffb_setvideo(sc, *(int *)data == WSDISPLAYIO_VIDEO_ON);
587 return 0;
588 }
589 return EPASSTHROUGH;
590 }
591
592 static paddr_t
593 gffb_mmap(void *v, void *vs, off_t offset, int prot)
594 {
595 struct vcons_data *vd = v;
596 struct gffb_softc *sc = vd->cookie;
597 paddr_t pa;
598
599 /* 'regular' framebuffer mmap()ing */
600 if (offset < sc->sc_vramsize) {
601 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset + 0x2000,
602 0, prot, BUS_SPACE_MAP_LINEAR);
603 return pa;
604 }
605
606 /*
607 * restrict all other mappings to processes with superuser privileges
608 * or the kernel itself
609 */
610 if (kauth_authorize_machdep(kauth_cred_get(),
611 KAUTH_MACHDEP_UNMANAGEDMEM,
612 NULL, NULL, NULL, NULL) != 0) {
613 aprint_normal("%s: mmap() rejected.\n",
614 device_xname(sc->sc_dev));
615 return -1;
616 }
617
618 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
619 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
620 BUS_SPACE_MAP_LINEAR);
621 return pa;
622 }
623
624 if ((offset >= sc->sc_reg) &&
625 (offset < (sc->sc_reg + sc->sc_regsize))) {
626 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
627 BUS_SPACE_MAP_LINEAR);
628 return pa;
629 }
630
631 #ifdef PCI_MAGIC_IO_RANGE
632 /* allow mapping of IO space */
633 if ((offset >= PCI_MAGIC_IO_RANGE) &&
634 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
635 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
636 0, prot, BUS_SPACE_MAP_LINEAR);
637 return pa;
638 }
639 #endif
640
641 return -1;
642 }
643
644 static void
645 gffb_init_screen(void *cookie, struct vcons_screen *scr,
646 int existing, long *defattr)
647 {
648 struct gffb_softc *sc = cookie;
649 struct rasops_info *ri = &scr->scr_ri;
650
651 ri->ri_depth = sc->sc_depth;
652 ri->ri_width = sc->sc_width;
653 ri->ri_height = sc->sc_height;
654 ri->ri_stride = sc->sc_stride;
655 if (sc->sc_depth == 8)
656 ri->ri_bits = sc->sc_fbaddr + sc->sc_fboffset;
657 ri->ri_flg = RI_CENTER;
658 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
659
660 rasops_init(ri, 0, 0);
661 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_RESIZE;
662 scr->scr_flags |= VCONS_LOADFONT;
663
664 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
665 sc->sc_width / ri->ri_font->fontwidth);
666
667 ri->ri_hw = scr;
668
669 if (sc->sc_accel) {
670 sc->sc_putchar = ri->ri_ops.putchar;
671 ri->ri_ops.copyrows = gffb_copyrows;
672 ri->ri_ops.copycols = gffb_copycols;
673 ri->ri_ops.eraserows = gffb_eraserows;
674 ri->ri_ops.erasecols = gffb_erasecols;
675 ri->ri_ops.cursor = gffb_cursor;
676 ri->ri_ops.putchar = gffb_putchar;
677 } else {
678 scr->scr_flags |= VCONS_DONT_READ;
679 }
680 }
681
682 static int
683 gffb_putcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm)
684 {
685 u_char *r, *g, *b;
686 u_int index = cm->index;
687 u_int count = cm->count;
688 int i, error;
689 u_char rbuf[256], gbuf[256], bbuf[256];
690
691 #ifdef GFFB_DEBUG
692 aprint_debug("putcmap: %d %d\n",index, count);
693 #endif
694 if (cm->index >= 256 || cm->count > 256 ||
695 (cm->index + cm->count) > 256)
696 return EINVAL;
697 error = copyin(cm->red, &rbuf[index], count);
698 if (error)
699 return error;
700 error = copyin(cm->green, &gbuf[index], count);
701 if (error)
702 return error;
703 error = copyin(cm->blue, &bbuf[index], count);
704 if (error)
705 return error;
706
707 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
708 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
709 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
710
711 r = &sc->sc_cmap_red[index];
712 g = &sc->sc_cmap_green[index];
713 b = &sc->sc_cmap_blue[index];
714
715 for (i = 0; i < count; i++) {
716 gffb_putpalreg(sc, index, *r, *g, *b);
717 index++;
718 r++, g++, b++;
719 }
720 return 0;
721 }
722
723 static int
724 gffb_getcmap(struct gffb_softc *sc, struct wsdisplay_cmap *cm)
725 {
726 u_int index = cm->index;
727 u_int count = cm->count;
728 int error;
729
730 if (index >= 255 || count > 256 || index + count > 256)
731 return EINVAL;
732
733 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
734 if (error)
735 return error;
736 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
737 if (error)
738 return error;
739 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
740 if (error)
741 return error;
742
743 return 0;
744 }
745
746 static void
747 gffb_restore_palette(struct gffb_softc *sc)
748 {
749 int i;
750
751 for (i = 0; i < (1 << sc->sc_depth); i++) {
752 gffb_putpalreg(sc, i, sc->sc_cmap_red[i],
753 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
754 }
755 }
756
757 static int
758 gffb_putpalreg(struct gffb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
759 uint8_t b)
760 {
761 /* port 0 */
762 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_IW, idx);
763 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_D, r);
764 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_D, g);
765 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_D, b);
766
767 /* port 1 */
768 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_IW, idx);
769 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_D, r);
770 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_D, g);
771 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_D, b);
772
773 return 0;
774 }
775
776 static void
777 gffb_setvideo(struct gffb_softc *sc, int on)
778 {
779 uint8_t reg0, reg1;
780
781 if (sc->sc_video == on)
782 return;
783
784 reg0 = gffb_read_crtc(sc, 0, 0x1a) & 0x3f;
785 reg1 = gffb_read_crtc(sc, 1, 0x1a) & 0x3f;
786
787 if (!on) {
788 reg0 |= 0xc0;
789 reg1 |= 0xc0;
790 }
791
792 gffb_write_crtc(sc, 0, 0x1a, reg0);
793 gffb_write_crtc(sc, 1, 0x1a, reg1);
794
795 sc->sc_video = on;
796
797 if(sc->sc_mobile) {
798 gffb_set_backlight(sc, sc->sc_bl_level);
799 }
800 }
801
802 static void
803 gffb_dma_kickoff(struct gffb_softc *sc)
804 {
805 volatile uint32_t junk;
806 if (sc->sc_current != sc->sc_put) {
807 sc->sc_put = sc->sc_current;
808 bus_space_barrier(sc->sc_memt, sc->sc_fbh, 0, 0x1000000,
809 BUS_SPACE_BARRIER_WRITE);
810 junk = *sc->sc_fbaddr;
811 __USE(junk);
812 GFFB_WRITE_4(GFFB_FIFO_PUT, sc->sc_put);
813 bus_space_barrier(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT, 4,
814 BUS_SPACE_BARRIER_WRITE);
815 }
816 }
817
818 static void
819 gffb_dmanext(struct gffb_softc *sc, uint32_t data)
820 {
821 bus_space_write_stream_4(sc->sc_memt, sc->sc_fbh, sc->sc_current, data);
822 sc->sc_current += 4;
823 }
824
825 static void
826 gffb_dmastart(struct gffb_softc *sc, uint32_t tag, int size)
827 {
828 if(sc->sc_free <= (size << 2))
829 gffb_make_room(sc, size);
830 gffb_dmanext(sc, ((size) << 18) | (tag));
831 sc->sc_free -= ((size + 1) << 2);
832 }
833
834 /*
835 * from xf86_video_nv/nv_xaa.c:
836 * There is a HW race condition with videoram command buffers.
837 * You can't jump to the location of your put offset. We write put
838 * at the jump offset + SKIPS dwords with noop padding in between
839 * to solve this problem
840 */
841
842 #define SKIPS 8
843
844 static void
845 gffb_make_room(struct gffb_softc *sc, int size)
846 {
847 uint32_t get;
848
849 size = (size + 1) << 2; /* slots -> offset */
850
851 while (sc->sc_free < size) {
852 get = GFFB_READ_4(GFFB_FIFO_GET);
853
854 if (sc->sc_put >= get) {
855 sc->sc_free = 0x2000 - sc->sc_current;
856 if (sc->sc_free < size) {
857 gffb_dmanext(sc, 0x20000000);
858 if(get <= (SKIPS << 2)) {
859 if (sc->sc_put <= (SKIPS << 2)) {
860 /* corner case - will be idle */
861 GFFB_WRITE_4(GFFB_FIFO_PUT,
862 (SKIPS + 1) << 2);
863 }
864 do {
865 get =GFFB_READ_4(GFFB_FIFO_GET);
866 } while (get <= (SKIPS << 2));
867 }
868 GFFB_WRITE_4(GFFB_FIFO_PUT, SKIPS << 2);
869 sc->sc_current = sc->sc_put = (SKIPS << 2);
870 sc->sc_free = get - ((SKIPS + 1) << 2);
871 }
872 } else
873 sc->sc_free = get - sc->sc_current - 4;
874 }
875 }
876
877 static void
878 gffb_sync(struct gffb_softc *sc)
879 {
880 int bail;
881 int i;
882
883 /*
884 * if there are commands in the buffer make sure the chip is actually
885 * trying to run them
886 */
887 gffb_dma_kickoff(sc);
888
889 /* now wait for the command buffer to drain... */
890 bail = 100000000;
891 while ((GFFB_READ_4(GFFB_FIFO_GET) != sc->sc_put) && (bail > 0)) {
892 bail--;
893 }
894 if (bail == 0) {
895 printf("FIFO isn't moving\n");
896 goto crap;
897 }
898
899 /* ... and for the engine to go idle */
900 bail = 100000000;
901 while((GFFB_READ_4(GFFB_BUSY) != 0) && (bail > 0)) {
902 bail--;
903 }
904 if (bail == 0) goto crap;
905 return;
906 crap:
907 /* if we time out fill the buffer with NOPs and cross fingers */
908 DPRINTF("GET %08x\n", GFFB_READ_4(GFFB_FIFO_GET));
909 sc->sc_put = 0;
910 sc->sc_current = 0;
911 for (i = 0; i < 0x2000; i += 4)
912 bus_space_write_stream_4(sc->sc_memt, sc->sc_fbh, i, 0);
913 aprint_error_dev(sc->sc_dev, "DMA lockup\n");
914 }
915
916 static int
917 gffb_get_backlight(struct gffb_softc *sc)
918 {
919 uint32_t pmc;
920 pmc = (GFFB_READ_4(GFFB_PMC + 0x10F0) & 0x7FFF0000) >> 16;
921 pmc = (pmc - GFFB_BL_MIN) * 256 / (GFFB_BL_MAX - GFFB_BL_MIN);
922 return pmc;
923 }
924
925 static void
926 gffb_set_backlight(struct gffb_softc *sc, int level)
927 {
928 uint32_t pmc = GFFB_READ_4(GFFB_PMC + 0x10F0) & 0x0000ffff;
929 uint32_t bl, pcrt;
930
931 if (level < 0) level = 0;
932 if (level > 255) level = 255;
933
934 pcrt = GFFB_READ_4(GFFB_CRTC0 + 0x081C) & 0xFFFFFFFC;
935 bl = (level * (GFFB_BL_MAX - GFFB_BL_MIN) / 256) + GFFB_BL_MIN;
936 pmc |= bl << 16;
937 if (sc->sc_video && (level > 0)) {
938 pcrt |= 0x1;
939 pmc |= 0x80000000;
940 }
941 GFFB_WRITE_4(GFFB_PMC + 0x10F0, pmc);
942 GFFB_WRITE_4(GFFB_CRTC0 + 0x081C, pcrt);
943 DPRINTF("%s: %d %08x %08x\n", __func__, level, pmc, pcrt);
944 sc->sc_bl_level = level;
945 }
946
947 static void
948 gffb_brightness_up(device_t dev)
949 {
950 struct gffb_softc *sc = device_private(dev);
951
952 sc->sc_video = 1;
953 gffb_set_backlight(sc, sc->sc_bl_level + 8);
954 }
955
956 static void
957 gffb_brightness_down(device_t dev)
958 {
959 struct gffb_softc *sc = device_private(dev);
960
961 gffb_set_backlight(sc, sc->sc_bl_level - 8);
962 }
963
964 void
965 gffb_init(struct gffb_softc *sc)
966 {
967 int i;
968 uint32_t foo;
969
970 if (!sc->sc_accel) return;
971 DPRINTF("%s offset %08x %08x\n", __func__,
972 GFFB_READ_4(GFFB_CRTC0 + GFFB_DISPLAYSTART),
973 GFFB_READ_4(GFFB_CRTC1 + GFFB_DISPLAYSTART));
974
975 sc->sc_fboffset = 0x2000;
976
977 if (sc->sc_mobile) {
978 sc->sc_bl_level = gffb_get_backlight(sc);
979 }
980
981 /* init display start */
982 GFFB_WRITE_4(GFFB_CRTC0 + GFFB_DISPLAYSTART, sc->sc_fboffset);
983 GFFB_WRITE_4(GFFB_CRTC1 + GFFB_DISPLAYSTART, sc->sc_fboffset);
984
985 /* make sure we do 8bit per channel */
986 GFFB_WRITE_1(GFFB_PDIO0 + GFFB_PEL_MASK, 0xff);
987 GFFB_WRITE_1(GFFB_PDIO1 + GFFB_PEL_MASK, 0xff);
988
989 /* DMA stuff. A whole lot of magic number voodoo from xf86-video-nv */
990 GFFB_WRITE_4(GFFB_PMC + 0x140, 0);
991 GFFB_WRITE_4(GFFB_PMC + 0x200, 0xffff00ff);
992 GFFB_WRITE_4(GFFB_PMC + 0x200, 0xffffffff);
993 GFFB_WRITE_4(GFFB_PTIMER + 0x800, 8);
994 GFFB_WRITE_4(GFFB_PTIMER + 0x840, 3);
995 GFFB_WRITE_4(GFFB_PTIMER + 0x500, 0);
996 GFFB_WRITE_4(GFFB_PTIMER + 0x400, 0xffffffff);
997 for (i = 0; i < 8; i++) {
998 GFFB_WRITE_4(GFFB_PFB + 0x0240 + (i * 0x10), 0);
999 GFFB_WRITE_4(GFFB_PFB + 0x0244 + (i * 0x10),
1000 sc->sc_vramsize - 1);
1001 }
1002
1003 GFFB_WRITE_4(GFFB_PRAMIN, 0x80000010);
1004 GFFB_WRITE_4(GFFB_PRAMIN + 0x04, 0x80011201);
1005 GFFB_WRITE_4(GFFB_PRAMIN + 0x08, 0x80000011);
1006 GFFB_WRITE_4(GFFB_PRAMIN + 0x0c, 0x80011202);
1007 GFFB_WRITE_4(GFFB_PRAMIN + 0x10, 0x80000012);
1008 GFFB_WRITE_4(GFFB_PRAMIN + 0x14, 0x80011203);
1009 GFFB_WRITE_4(GFFB_PRAMIN + 0x18, 0x80000013);
1010 GFFB_WRITE_4(GFFB_PRAMIN + 0x1c, 0x80011204);
1011 GFFB_WRITE_4(GFFB_PRAMIN + 0x20, 0x80000014);
1012 GFFB_WRITE_4(GFFB_PRAMIN + 0x24, 0x80011205);
1013 GFFB_WRITE_4(GFFB_PRAMIN + 0x28, 0x80000015);
1014 GFFB_WRITE_4(GFFB_PRAMIN + 0x2c, 0x80011206);
1015 GFFB_WRITE_4(GFFB_PRAMIN + 0x30, 0x80000016);
1016 GFFB_WRITE_4(GFFB_PRAMIN + 0x34, 0x80011207);
1017 GFFB_WRITE_4(GFFB_PRAMIN + 0x38, 0x80000017);
1018 GFFB_WRITE_4(GFFB_PRAMIN + 0x3c, 0x80011208);
1019 GFFB_WRITE_4(GFFB_PRAMIN + 0x2000, 0x00003000);
1020 GFFB_WRITE_4(GFFB_PRAMIN + 0x2004, sc->sc_vramsize - 1);
1021 GFFB_WRITE_4(GFFB_PRAMIN + 0x2008, 0x00000002);
1022 GFFB_WRITE_4(GFFB_PRAMIN + 0x200c, 0x00000002);
1023 GFFB_WRITE_4(GFFB_PRAMIN + 0x2010, 0x01008062); /* nv10+ */
1024 GFFB_WRITE_4(GFFB_PRAMIN + 0x2014, 0);
1025 GFFB_WRITE_4(GFFB_PRAMIN + 0x2018, 0x12001200);
1026 GFFB_WRITE_4(GFFB_PRAMIN + 0x201c, 0);
1027 GFFB_WRITE_4(GFFB_PRAMIN + 0x2020, 0x01008043);
1028 GFFB_WRITE_4(GFFB_PRAMIN + 0x2024, 0);
1029 GFFB_WRITE_4(GFFB_PRAMIN + 0x2028, 0);
1030 GFFB_WRITE_4(GFFB_PRAMIN + 0x202c, 0);
1031 GFFB_WRITE_4(GFFB_PRAMIN + 0x2030, 0x01008044);
1032 GFFB_WRITE_4(GFFB_PRAMIN + 0x2034, 0x00000002);
1033 GFFB_WRITE_4(GFFB_PRAMIN + 0x2038, 0);
1034 GFFB_WRITE_4(GFFB_PRAMIN + 0x203c, 0);
1035 GFFB_WRITE_4(GFFB_PRAMIN + 0x2040, 0x01008019);
1036 GFFB_WRITE_4(GFFB_PRAMIN + 0x2044, 0);
1037 GFFB_WRITE_4(GFFB_PRAMIN + 0x2048, 0);
1038 GFFB_WRITE_4(GFFB_PRAMIN + 0x204c, 0);
1039 GFFB_WRITE_4(GFFB_PRAMIN + 0x2050, 0x0100a05c);
1040 GFFB_WRITE_4(GFFB_PRAMIN + 0x2054, 0);
1041 GFFB_WRITE_4(GFFB_PRAMIN + 0x2058, 0);
1042 GFFB_WRITE_4(GFFB_PRAMIN + 0x205c, 0);
1043 /* XXX 0x0100805f if !WaitVSynvPossible */
1044 GFFB_WRITE_4(GFFB_PRAMIN + 0x2060, 0x0100805f);
1045 GFFB_WRITE_4(GFFB_PRAMIN + 0x2064, 0);
1046 GFFB_WRITE_4(GFFB_PRAMIN + 0x2068, 0x12001200);
1047 GFFB_WRITE_4(GFFB_PRAMIN + 0x206c, 0);
1048 GFFB_WRITE_4(GFFB_PRAMIN + 0x2070, 0x0100804a);
1049 GFFB_WRITE_4(GFFB_PRAMIN + 0x2074, 0x00000002);
1050 GFFB_WRITE_4(GFFB_PRAMIN + 0x2078, 0);
1051 GFFB_WRITE_4(GFFB_PRAMIN + 0x207c, 0);
1052 GFFB_WRITE_4(GFFB_PRAMIN + 0x2080, 0x01018077);
1053 GFFB_WRITE_4(GFFB_PRAMIN + 0x2084, 0);
1054 GFFB_WRITE_4(GFFB_PRAMIN + 0x2088, 0x12001200);
1055 GFFB_WRITE_4(GFFB_PRAMIN + 0x208c, 0);
1056 GFFB_WRITE_4(GFFB_PRAMIN + 0x2090, 0x00003002);
1057 GFFB_WRITE_4(GFFB_PRAMIN + 0x2094, 0x00007fff);
1058 /* command buffer start with some flag in the lower bits */
1059 GFFB_WRITE_4(GFFB_PRAMIN + 0x2098, sc->sc_vramsize | 0x00000002);
1060 GFFB_WRITE_4(GFFB_PRAMIN + 0x209c, 0x00000002);
1061 #if BYTE_ORDER == BIG_ENDIAN
1062 GFFB_WRITE_4(GFFB_PRAMIN + 0x2010, 0x01088062);
1063 GFFB_WRITE_4(GFFB_PRAMIN + 0x2020, 0x01088043);
1064 GFFB_WRITE_4(GFFB_PRAMIN + 0x2030, 0x01088044);
1065 GFFB_WRITE_4(GFFB_PRAMIN + 0x2040, 0x01088019);
1066 GFFB_WRITE_4(GFFB_PRAMIN + 0x2050, 0x0108a05c);
1067 GFFB_WRITE_4(GFFB_PRAMIN + 0x2060, 0x0108805f);
1068 GFFB_WRITE_4(GFFB_PRAMIN + 0x2070, 0x0108804a);
1069 GFFB_WRITE_4(GFFB_PRAMIN + 0x2080, 0x01098077);
1070 GFFB_WRITE_4(GFFB_PRAMIN + 0x2034, 0x00000001);
1071 GFFB_WRITE_4(GFFB_PRAMIN + 0x2074, 0x00000001);
1072 #endif
1073 /* PGRAPH setup */
1074 GFFB_WRITE_4(GFFB_PGRAPH + 0x0080, 0xFFFFFFFF);
1075 GFFB_WRITE_4(GFFB_PGRAPH + 0x0080, 0x00000000);
1076
1077 GFFB_WRITE_4(GFFB_PGRAPH + 0x0140, 0x00000000);
1078 GFFB_WRITE_4(GFFB_PGRAPH + 0x0100, 0xFFFFFFFF);
1079 GFFB_WRITE_4(GFFB_PGRAPH + 0x0144, 0x10010100);
1080 GFFB_WRITE_4(GFFB_PGRAPH + 0x0714, 0xFFFFFFFF);
1081 GFFB_WRITE_4(GFFB_PGRAPH + 0x0720, 0x00000001);
1082 /*
1083 * xf86_video_nv does this in two writes,
1084 * not sure if they can be combined
1085 */
1086 foo = GFFB_READ_4(GFFB_PGRAPH + 0x0710);
1087 foo &= 0x0007ff00;
1088 foo |= 0x00020100;
1089 GFFB_WRITE_4(GFFB_PGRAPH + 0x0710, foo);
1090
1091 /* NV_ARCH_10 */
1092 if(sc->sc_arch == 10) {
1093 GFFB_WRITE_4(GFFB_PGRAPH + 0x0084, 0x00118700);
1094 GFFB_WRITE_4(GFFB_PGRAPH + 0x0088, 0x24E00810);
1095 GFFB_WRITE_4(GFFB_PGRAPH + 0x008C, 0x55DE0030);
1096
1097 for(i = 0; i < 128; i += 4) {
1098 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B00 + i,
1099 GFFB_READ_4(GFFB_PFB + 0x0240 + i));
1100 }
1101
1102 GFFB_WRITE_4(GFFB_PGRAPH + 0x640, 0);
1103 GFFB_WRITE_4(GFFB_PGRAPH + 0x644, 0);
1104 GFFB_WRITE_4(GFFB_PGRAPH + 0x684, sc->sc_vramsize - 1);
1105 GFFB_WRITE_4(GFFB_PGRAPH + 0x688, sc->sc_vramsize - 1);
1106
1107 GFFB_WRITE_4(GFFB_PGRAPH + 0x0810, 0x00000000);
1108 GFFB_WRITE_4(GFFB_PGRAPH + 0x0608, 0xFFFFFFFF);
1109 } else {
1110 /* nv30 */
1111 GFFB_WRITE_4(GFFB_PGRAPH + 0x0084, 0x40108700);
1112 GFFB_WRITE_4(GFFB_PGRAPH + 0x0890, 0x00140000);
1113 GFFB_WRITE_4(GFFB_PGRAPH + 0x008C, 0xf00e0431);
1114 GFFB_WRITE_4(GFFB_PGRAPH + 0x0090, 0x00008000);
1115 GFFB_WRITE_4(GFFB_PGRAPH + 0x0610, 0xf04b1f36);
1116 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B80, 0x1002d888);
1117 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B88, 0x62ff007f);
1118
1119 for (i = 0; i < 128; i += 4) {
1120 GFFB_WRITE_4(GFFB_PGRAPH + 0x0900 + i,
1121 GFFB_READ_4(GFFB_PFB + 0x0240 + i));
1122 GFFB_WRITE_4(GFFB_PGRAPH + 0x6900 + i,
1123 GFFB_READ_4(GFFB_PFB + 0x0240 + i));
1124 }
1125
1126 GFFB_WRITE_4(GFFB_PGRAPH + 0x09A4,
1127 GFFB_READ_4(GFFB_PFB + 0x0200));
1128 GFFB_WRITE_4(GFFB_PGRAPH + 0x09A8,
1129 GFFB_READ_4(GFFB_PFB + 0x0204));
1130 GFFB_WRITE_4(GFFB_PGRAPH + 0x0750, 0x00EA0000);
1131 GFFB_WRITE_4(GFFB_PGRAPH + 0x0754,
1132 GFFB_READ_4(GFFB_PFB + 0x0200));
1133 GFFB_WRITE_4(GFFB_PGRAPH + 0x0750, 0x00EA0004);
1134 GFFB_WRITE_4(GFFB_PGRAPH + 0x0754,
1135 GFFB_READ_4(GFFB_PFB + 0x0204));
1136
1137 GFFB_WRITE_4(GFFB_PGRAPH + 0x0820, 0);
1138 GFFB_WRITE_4(GFFB_PGRAPH + 0x0824, 0);
1139 GFFB_WRITE_4(GFFB_PGRAPH + 0x0864, sc->sc_vramsize - 1);
1140 GFFB_WRITE_4(GFFB_PGRAPH + 0x0868, sc->sc_vramsize - 1);
1141
1142 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B20, 0x00000000);
1143 GFFB_WRITE_4(GFFB_PGRAPH + 0x0B04, 0xFFFFFFFF);
1144 }
1145
1146 /* PFIFO setup */
1147 GFFB_WRITE_4(GFFB_PGRAPH + 0x053C, 0);
1148 GFFB_WRITE_4(GFFB_PGRAPH + 0x0540, 0);
1149 GFFB_WRITE_4(GFFB_PGRAPH + 0x0544, 0x00007FFF);
1150 GFFB_WRITE_4(GFFB_PGRAPH + 0x0548, 0x00007FFF);
1151
1152 GFFB_WRITE_4(GFFB_PFIFO + 0x0500, 0);
1153 GFFB_WRITE_4(GFFB_PFIFO + 0x0504, 0x00000001);
1154 GFFB_WRITE_4(GFFB_PFIFO + 0x1200, 0);
1155 GFFB_WRITE_4(GFFB_PFIFO + 0x1250, 0);
1156 GFFB_WRITE_4(GFFB_PFIFO + 0x1204, 0x00000100); /* different on nv40 */
1157 GFFB_WRITE_4(GFFB_PFIFO + 0x1240, 0);
1158 GFFB_WRITE_4(GFFB_PFIFO + 0x1244, 0);
1159 GFFB_WRITE_4(GFFB_PFIFO + 0x122c, 0x00001209); /* different on nv40 */
1160 GFFB_WRITE_4(GFFB_PFIFO + 0x1000, 0);
1161 GFFB_WRITE_4(GFFB_PFIFO + 0x1050, 0);
1162 GFFB_WRITE_4(GFFB_PFIFO + 0x0210, 0x03000100);
1163 GFFB_WRITE_4(GFFB_PFIFO + 0x0214, 0x00000110);
1164 GFFB_WRITE_4(GFFB_PFIFO + 0x0218, 0x00000112);
1165 GFFB_WRITE_4(GFFB_PFIFO + 0x050c, 0x0000ffff);
1166 GFFB_WRITE_4(GFFB_PFIFO + 0x1258, 0x0000ffff);
1167 GFFB_WRITE_4(GFFB_PFIFO + 0x0140, 0);
1168 GFFB_WRITE_4(GFFB_PFIFO + 0x0100, 0xffffffff);
1169 GFFB_WRITE_4(GFFB_PFIFO + 0x1054, 0x00000001);
1170 GFFB_WRITE_4(GFFB_PFIFO + 0x1230, 0);
1171 GFFB_WRITE_4(GFFB_PFIFO + 0x1280, 0);
1172 #if BYTE_ORDER == BIG_ENDIAN
1173 GFFB_WRITE_4(GFFB_PFIFO + 0x1224, 0x800f0078);
1174 #else
1175 GFFB_WRITE_4(GFFB_PFIFO + 0x1224, 0x000f0078);
1176 #endif
1177 GFFB_WRITE_4(GFFB_PFIFO + 0x1220, 0x00000001);
1178 GFFB_WRITE_4(GFFB_PFIFO + 0x1200, 0x00000001);
1179 GFFB_WRITE_4(GFFB_PFIFO + 0x1250, 0x00000001);
1180 GFFB_WRITE_4(GFFB_PFIFO + 0x1254, 0x00000001);
1181 GFFB_WRITE_4(GFFB_PFIFO + 0x0500, 0x00000001);
1182
1183 GFFB_WRITE_4(GFFB_PMC + 0x8704, 1);
1184 GFFB_WRITE_4(GFFB_PMC + 0x8140, 0);
1185 GFFB_WRITE_4(GFFB_PMC + 0x8920, 0);
1186 GFFB_WRITE_4(GFFB_PMC + 0x8924, 0);
1187 GFFB_WRITE_4(GFFB_PMC + 0x8908, sc->sc_vramsize - 1);
1188 GFFB_WRITE_4(GFFB_PMC + 0x890C, sc->sc_vramsize - 1);
1189 GFFB_WRITE_4(GFFB_PMC + 0x1588, 0);
1190
1191 __asm("eieio; sync;");
1192 GFFB_WRITE_4(GFFB_FIFO_GET, 0);
1193 GFFB_WRITE_4(GFFB_CMDSTART, 0x00000002);
1194 sc->sc_put = 0;
1195 sc->sc_current = 0;
1196 sc->sc_free = 0x2000;
1197
1198 for(i = 0; i < SKIPS; i++)
1199 gffb_dmanext(sc, 0);
1200
1201 gffb_dmanext(sc, 0x00040000);
1202 gffb_dmanext(sc, 0x80000010);
1203 gffb_dmanext(sc, 0x00042000);
1204 gffb_dmanext(sc, 0x80000011);
1205 gffb_dmanext(sc, 0x00044000);
1206 gffb_dmanext(sc, 0x80000012);
1207 gffb_dmanext(sc, 0x00046000);
1208 gffb_dmanext(sc, 0x80000013);
1209 gffb_dmanext(sc, 0x00048000);
1210 gffb_dmanext(sc, 0x80000014);
1211 gffb_dmanext(sc, 0x0004A000);
1212 gffb_dmanext(sc, 0x80000015);
1213 gffb_dmanext(sc, 0x0004C000);
1214 gffb_dmanext(sc, 0x80000016);
1215 gffb_dmanext(sc, 0x0004E000);
1216 gffb_dmanext(sc, 0x80000017);
1217 sc->sc_free = 0x2000 - sc->sc_current;
1218
1219 gffb_dmastart(sc, SURFACE_FORMAT, 4);
1220 gffb_dmanext(sc, SURFACE_FORMAT_DEPTH8);
1221 gffb_dmanext(sc, sc->sc_stride | (sc->sc_stride << 16));
1222 gffb_dmanext(sc, sc->sc_fboffset); /* src offset */
1223 gffb_dmanext(sc, sc->sc_fboffset); /* dst offset */
1224
1225 gffb_dmastart(sc, RECT_FORMAT, 1);
1226 gffb_dmanext(sc, RECT_FORMAT_DEPTH8);
1227
1228 gffb_dmastart(sc, PATTERN_FORMAT, 1);
1229 gffb_dmanext(sc, PATTERN_FORMAT_DEPTH8);
1230
1231 gffb_dmastart(sc, PATTERN_COLOR_0, 4);
1232 gffb_dmanext(sc, 0xffffffff);
1233 gffb_dmanext(sc, 0xffffffff);
1234 gffb_dmanext(sc, 0xffffffff);
1235 gffb_dmanext(sc, 0xffffffff);
1236
1237 gffb_dmastart(sc, ROP_SET, 1);
1238 gffb_dmanext(sc, 0xcc);
1239 sc->sc_rop = 0xcc;
1240 DPRINTF("put %x current %x\n", sc->sc_put, sc->sc_current);
1241
1242 gffb_dma_kickoff(sc);
1243 DPRINTF("put %x current %x\n", sc->sc_put, sc->sc_current);
1244 #ifdef GFFB_DEBUG
1245 printf("put: %08x\n", GFFB_READ_4(GFFB_FIFO_PUT));
1246 printf("get: %08x\n", GFFB_READ_4(GFFB_FIFO_GET));
1247 #endif
1248 gffb_sync(sc);
1249 DPRINTF("put %x current %x\n", sc->sc_put, sc->sc_current);
1250 }
1251
1252 static void
1253 gffb_rop(struct gffb_softc *sc, int rop)
1254 {
1255 if (rop == sc->sc_rop)
1256 return;
1257 sc->sc_rop = rop;
1258 gffb_dmastart(sc, ROP_SET, 1);
1259 gffb_dmanext(sc, rop);
1260 }
1261
1262 static void
1263 gffb_rectfill(struct gffb_softc *sc, int x, int y, int wi, int he,
1264 uint32_t colour)
1265 {
1266 if (!sc->sc_accel) return;
1267 mutex_enter(&sc->sc_lock);
1268 gffb_rop(sc, 0xcc);
1269
1270 gffb_dmastart(sc, RECT_SOLID_COLOR, 1);
1271 gffb_dmanext(sc, colour);
1272
1273 gffb_dmastart(sc, RECT_SOLID_RECTS(0), 2);
1274 gffb_dmanext(sc, (x << 16) | y);
1275 gffb_dmanext(sc, (wi << 16) | he);
1276 gffb_dma_kickoff(sc);
1277 mutex_exit(&sc->sc_lock);
1278 }
1279
1280 static void
1281 gffb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
1282 int wi, int he, int rop)
1283 {
1284 struct gffb_softc *sc = cookie;
1285
1286 if (!sc->sc_accel) return;
1287 mutex_enter(&sc->sc_lock);
1288
1289 gffb_rop(sc, rop);
1290
1291 gffb_dmastart(sc, BLIT_POINT_SRC, 3);
1292 gffb_dmanext(sc, (ys << 16) | xs);
1293 gffb_dmanext(sc, (yd << 16) | xd);
1294 gffb_dmanext(sc, (he << 16) | wi);
1295 gffb_dma_kickoff(sc);
1296 mutex_exit(&sc->sc_lock);
1297 }
1298
1299 static void
1300 gffb_cursor(void *cookie, int on, int row, int col)
1301 {
1302 struct rasops_info *ri = cookie;
1303 struct vcons_screen *scr = ri->ri_hw;
1304 struct gffb_softc *sc = scr->scr_cookie;
1305 int x, y, wi, he;
1306
1307 wi = ri->ri_font->fontwidth;
1308 he = ri->ri_font->fontheight;
1309
1310 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1311 x = ri->ri_ccol * wi + ri->ri_xorigin;
1312 y = ri->ri_crow * he + ri->ri_yorigin;
1313 if (ri->ri_flg & RI_CURSOR) {
1314 gffb_bitblt(sc, x, y, x, y, wi, he, 0x33);
1315 ri->ri_flg &= ~RI_CURSOR;
1316 }
1317 ri->ri_crow = row;
1318 ri->ri_ccol = col;
1319 if (on) {
1320 x = ri->ri_ccol * wi + ri->ri_xorigin;
1321 y = ri->ri_crow * he + ri->ri_yorigin;
1322 gffb_bitblt(sc, x, y, x, y, wi, he, 0x33);
1323 ri->ri_flg |= RI_CURSOR;
1324 }
1325 } else {
1326 scr->scr_ri.ri_crow = row;
1327 scr->scr_ri.ri_ccol = col;
1328 scr->scr_ri.ri_flg &= ~RI_CURSOR;
1329 }
1330
1331 }
1332
1333 static void
1334 gffb_putchar(void *cookie, int row, int col, u_int c, long attr)
1335 {
1336 struct rasops_info *ri = cookie;
1337 struct wsdisplay_font *font = PICK_FONT(ri, c);
1338 struct vcons_screen *scr = ri->ri_hw;
1339 struct gffb_softc *sc = scr->scr_cookie;
1340 int x, y, wi, he, rv = GC_NOPE;
1341 uint32_t bg;
1342
1343 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1344 return;
1345
1346 if (!CHAR_IN_FONT(c, font))
1347 return;
1348
1349 wi = font->fontwidth;
1350 he = font->fontheight;
1351
1352 x = ri->ri_xorigin + col * wi;
1353 y = ri->ri_yorigin + row * he;
1354 bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1355
1356 if (c == 0x20) {
1357 gffb_rectfill(sc, x, y, wi, he, bg);
1358 return;
1359 }
1360 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1361 if (rv == GC_OK)
1362 return;
1363
1364 /*
1365 * Use gffb_sync to wait for the engine to become idle before
1366 * we start scribbling into VRAM -- we wouldn't want to stomp on
1367 * a scroll in progress or a prior glyphcache_add that hasn't
1368 * completed yet on the GPU.
1369 */
1370 mutex_enter(&sc->sc_lock);
1371 gffb_sync(sc);
1372 sc->sc_putchar(cookie, row, col, c, attr);
1373 mutex_exit(&sc->sc_lock);
1374
1375 /*
1376 * If glyphcache_try asked us to, cache the newly written
1377 * character. This will issue a gffb_bitblt which will wait
1378 * for our CPU writes to the framebuffer in VRAM to complete
1379 * before triggering GPU reads from the framebuffer in VRAM.
1380 */
1381 if (rv == GC_ADD) {
1382 glyphcache_add(&sc->sc_gc, c, x, y);
1383 }
1384 }
1385
1386 static void
1387 gffb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1388 {
1389 struct rasops_info *ri = cookie;
1390 struct vcons_screen *scr = ri->ri_hw;
1391 struct gffb_softc *sc = scr->scr_cookie;
1392 int32_t xs, xd, y, width, height;
1393
1394 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1395 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1396 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1397 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1398 width = ri->ri_font->fontwidth * ncols;
1399 height = ri->ri_font->fontheight;
1400 gffb_bitblt(sc, xs, y, xd, y, width, height, 0xcc);
1401 }
1402 }
1403
1404 static void
1405 gffb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1406 {
1407 struct rasops_info *ri = cookie;
1408 struct vcons_screen *scr = ri->ri_hw;
1409 struct gffb_softc *sc = scr->scr_cookie;
1410 int32_t x, y, width, height, fg, bg, ul;
1411
1412 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1413 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1414 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1415 width = ri->ri_font->fontwidth * ncols;
1416 height = ri->ri_font->fontheight;
1417 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1418
1419 gffb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1420 }
1421 }
1422
1423 static void
1424 gffb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1425 {
1426 struct rasops_info *ri = cookie;
1427 struct vcons_screen *scr = ri->ri_hw;
1428 struct gffb_softc *sc = scr->scr_cookie;
1429 int32_t x, ys, yd, width, height;
1430
1431 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1432 x = ri->ri_xorigin;
1433 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1434 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1435 width = ri->ri_emuwidth;
1436 height = ri->ri_font->fontheight * nrows;
1437 gffb_bitblt(sc, x, ys, x, yd, width, height, 0xcc);
1438 }
1439 }
1440
1441 static void
1442 gffb_eraserows(void *cookie, int row, int nrows, long fillattr)
1443 {
1444 struct rasops_info *ri = cookie;
1445 struct vcons_screen *scr = ri->ri_hw;
1446 struct gffb_softc *sc = scr->scr_cookie;
1447 int32_t x, y, width, height, fg, bg, ul;
1448
1449 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1450 x = ri->ri_xorigin;
1451 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1452 width = ri->ri_emuwidth;
1453 height = ri->ri_font->fontheight * nrows;
1454 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1455
1456 gffb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1457 }
1458 }
1459