gftfb.c revision 1.13 1 /* $NetBSD: gftfb.c,v 1.13 2024/04/01 09:48:58 macallan Exp $ */
2
3 /* $OpenBSD: sti_pci.c,v 1.7 2009/02/06 22:51:04 miod Exp $ */
4
5 /*
6 * Copyright (c) 2006, 2007 Miodrag Vallat.
7 ^ 2024 Michael Lorenz
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice, this permission notice, and the disclaimer below
12 * appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 /*
24 * a native driver for HP Visualize EG PCI graphics cards
25 * STI portions are from Miodrag Vallat's sti_pci.c
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kmem.h>
31 #include <sys/device.h>
32 #include <sys/mutex.h>
33
34 #include <dev/pci/pcivar.h>
35 #include <dev/pci/pcireg.h>
36 #include <dev/pci/pcidevs.h>
37 #include <dev/pci/pciio.h>
38
39 #include <dev/wscons/wsdisplayvar.h>
40 #include <dev/wscons/wsconsio.h>
41 #include <dev/wsfont/wsfont.h>
42 #include <dev/rasops/rasops.h>
43 #include <dev/wscons/wsdisplay_vconsvar.h>
44 #include <dev/pci/wsdisplay_pci.h>
45 #include <dev/wscons/wsdisplay_glyphcachevar.h>
46
47 #include <dev/ic/stireg.h>
48 #include <dev/ic/stivar.h>
49
50 #ifdef STIDEBUG
51 #define DPRINTF(s) do { \
52 if (stidebug) \
53 printf s; \
54 } while(0)
55
56 extern int stidebug;
57 #else
58 #define DPRINTF(s) /* */
59 #endif
60
61 int gftfb_match(device_t, cfdata_t, void *);
62 void gftfb_attach(device_t, device_t, void *);
63
64 struct gftfb_softc {
65 device_t sc_dev;
66 pci_chipset_tag_t sc_pc;
67 pcitag_t sc_tag;
68
69 /* stuff we need in order to use the STI ROM */
70 struct sti_softc sc_base;
71 struct sti_screen sc_scr;
72 bus_space_handle_t sc_romh;
73
74 int sc_width, sc_height;
75 int sc_locked;
76 struct vcons_screen sc_console_screen;
77 struct wsscreen_descr sc_defaultscreen_descr;
78 const struct wsscreen_descr *sc_screens[1];
79 struct wsscreen_list sc_screenlist;
80 struct vcons_data vd;
81 int sc_mode;
82 void (*sc_putchar)(void *, int, int, u_int, long);
83 u_char sc_cmap_red[256];
84 u_char sc_cmap_green[256];
85 u_char sc_cmap_blue[256];
86 kmutex_t sc_hwlock;
87 uint32_t sc_hwmode;
88 #define HW_FB 0
89 #define HW_FILL 1
90 #define HW_BLIT 2
91 uint32_t sc_rect_colour, sc_rect_height;
92 /* cursor stuff */
93 int sc_cursor_x, sc_cursor_y;
94 int sc_hot_x, sc_hot_y, sc_enabled;
95 int sc_video_on;
96 glyphcache sc_gc;
97 };
98
99 CFATTACH_DECL_NEW(gftfb, sizeof(struct gftfb_softc),
100 gftfb_match, gftfb_attach, NULL, NULL);
101
102 int gftfb_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int);
103 int gftfb_check_rom(struct gftfb_softc *, struct pci_attach_args *);
104 void gftfb_enable_rom(struct sti_softc *);
105 void gftfb_disable_rom(struct sti_softc *);
106 void gftfb_enable_rom_internal(struct gftfb_softc *);
107 void gftfb_disable_rom_internal(struct gftfb_softc *);
108
109 void gftfb_setup(struct gftfb_softc *);
110
111 #define ngle_bt458_write(memt, memh, r, v) \
112 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
113
114
115 /* XXX these really need to go into their own header */
116 int sti_pci_is_console(struct pci_attach_args *, bus_addr_t *);
117 int sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
118 bus_space_handle_t, bus_addr_t *, u_int);
119 int sti_screen_setup(struct sti_screen *, int);
120 void sti_describe_screen(struct sti_softc *, struct sti_screen *);
121
122 #define PCI_ROM_SIZE(mr) \
123 (PCI_MAPREG_ROM_ADDR(mr) & -PCI_MAPREG_ROM_ADDR(mr))
124
125 /* wsdisplay stuff */
126 static int gftfb_ioctl(void *, void *, u_long, void *, int,
127 struct lwp *);
128 static paddr_t gftfb_mmap(void *, void *, off_t, int);
129 static void gftfb_init_screen(void *, struct vcons_screen *, int, long *);
130
131 static int gftfb_putcmap(struct gftfb_softc *, struct wsdisplay_cmap *);
132 static int gftfb_getcmap(struct gftfb_softc *, struct wsdisplay_cmap *);
133 static void gftfb_restore_palette(struct gftfb_softc *);
134 static int gftfb_putpalreg(struct gftfb_softc *, uint8_t, uint8_t,
135 uint8_t, uint8_t);
136
137 static void gftfb_rectfill(struct gftfb_softc *, int, int, int, int,
138 uint32_t);
139 static void gftfb_bitblt(void *, int, int, int, int, int,
140 int, int);
141
142 static void gftfb_cursor(void *, int, int, int);
143 static void gftfb_putchar(void *, int, int, u_int, long);
144 static void gftfb_copycols(void *, int, int, int, int);
145 static void gftfb_erasecols(void *, int, int, int, long);
146 static void gftfb_copyrows(void *, int, int, int);
147 static void gftfb_eraserows(void *, int, int, long);
148
149 static void gftfb_move_cursor(struct gftfb_softc *, int, int);
150 static int gftfb_do_cursor(struct gftfb_softc *, struct wsdisplay_cursor *);
151
152 static void gftfb_set_video(struct gftfb_softc *, int);
153
154 struct wsdisplay_accessops gftfb_accessops = {
155 gftfb_ioctl,
156 gftfb_mmap,
157 NULL, /* alloc_screen */
158 NULL, /* free_screen */
159 NULL, /* show_screen */
160 NULL, /* load_font */
161 NULL, /* pollc */
162 NULL /* scroll */
163 };
164
165 #define BA(F,C,S,A,J,B,I) \
166 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
167
168 #define IBOvals(R,M,X,S,D,L,B,F) \
169 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
170
171 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
172 #define Otc04 2 /* Pixels in each longword transfer (4) */
173 #define Otc32 5 /* Pixels in each longword transfer (32) */
174 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
175 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
176 #define AddrLong 5 /* FB address is Long aligned (pixel) */
177 #define BINovly 0x2 /* 8 bit overlay */
178 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
179 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
180 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
181 #define BINattr 0xd /* Attribute Bitmap */
182 #define RopSrc 0x3
183 #define RopInv 0xc
184 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
185 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
186 #define DataDynamic 0 /* Data register reloaded by direct access */
187 #define MaskDynamic 1 /* Mask register reloaded by direct access */
188 #define MaskOtc 0 /* Mask contains Object Count valid bits */
189
190 static inline void gftfb_wait_fifo(struct gftfb_softc *, uint32_t);
191
192 int
193 gftfb_match(device_t parent, cfdata_t cf, void *aux)
194 {
195 struct pci_attach_args *paa = aux;
196
197 if (PCI_VENDOR(paa->pa_id) != PCI_VENDOR_HP)
198 return 0;
199
200 if (PCI_PRODUCT(paa->pa_id) == PCI_PRODUCT_HP_VISUALIZE_EG)
201 return 10; /* beat out sti at pci */
202
203 return 0;
204 }
205
206 void
207 gftfb_attach(device_t parent, device_t self, void *aux)
208 {
209 struct gftfb_softc *sc = device_private(self);
210 struct pci_attach_args *paa = aux;
211 struct sti_rom *rom;
212 struct rasops_info *ri;
213 struct wsemuldisplaydev_attach_args aa;
214 unsigned long defattr = 0;
215 int ret, is_console = 0;
216
217 sc->sc_dev = self;
218
219 sc->sc_pc = paa->pa_pc;
220 sc->sc_tag = paa->pa_tag;
221 sc->sc_base.sc_dev = self;
222 sc->sc_base.sc_enable_rom = gftfb_enable_rom;
223 sc->sc_base.sc_disable_rom = gftfb_disable_rom;
224
225 /* we can *not* be interrupted when doing colour map accesses */
226 mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH);
227
228 aprint_normal("\n");
229
230 if (gftfb_check_rom(sc, paa) != 0)
231 return;
232
233 ret = sti_pci_is_console(paa, sc->sc_base. bases);
234 if (ret != 0) {
235 sc->sc_base.sc_flags |= STI_CONSOLE;
236 is_console = 1;
237 }
238 rom = (struct sti_rom *)kmem_zalloc(sizeof(*rom), KM_SLEEP);
239 rom->rom_softc = &sc->sc_base;
240 ret = sti_rom_setup(rom, paa->pa_iot, paa->pa_memt, sc->sc_romh, sc->sc_base.bases, STI_CODEBASE_MAIN);
241 if (ret != 0) {
242 kmem_free(rom, sizeof(*rom));
243 return;
244 }
245
246 sc->sc_base.sc_rom = rom;
247
248 sc->sc_scr.scr_rom = sc->sc_base.sc_rom;
249 ret = sti_screen_setup(&sc->sc_scr, STI_FBMODE);
250
251 sc->sc_width = sc->sc_scr.scr_cfg.scr_width;
252 sc->sc_height = sc->sc_scr.scr_cfg.scr_height;
253 sc->sc_rect_colour = 0xf0000000;
254 sc->sc_rect_height = 0;
255
256 aprint_normal_dev(sc->sc_dev, "%s at %dx%d\n", sc->sc_scr.name,
257 sc->sc_width, sc->sc_height);
258 gftfb_setup(sc);
259
260 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
261 "default",
262 0, 0,
263 NULL,
264 8, 16,
265 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
266 WSSCREEN_RESIZE,
267 NULL
268 };
269
270 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
271 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
272 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
273 sc->sc_locked = 0;
274
275 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
276 &gftfb_accessops);
277 sc->vd.init_screen = gftfb_init_screen;
278 sc->vd.show_screen_cookie = &sc->sc_gc;
279 sc->vd.show_screen_cb = glyphcache_adapt;
280
281 ri = &sc->sc_console_screen.scr_ri;
282
283 sc->sc_gc.gc_bitblt = gftfb_bitblt;
284 sc->sc_gc.gc_blitcookie = sc;
285 sc->sc_gc.gc_rop = RopSrc;
286
287 if (is_console) {
288 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
289 &defattr);
290 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
291
292 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
293 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
294 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
295 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
296
297 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
298 sc->sc_scr.fbheight - sc->sc_height - 5,
299 sc->sc_scr.fbwidth,
300 ri->ri_font->fontwidth,
301 ri->ri_font->fontheight,
302 defattr);
303
304 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
305 defattr);
306
307 gftfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
308 ri->ri_devcmap[(defattr >> 16) & 0xff]);
309
310 vcons_replay_msgbuf(&sc->sc_console_screen);
311 } else {
312 /*
313 * since we're not the console we can postpone the rest
314 * until someone actually allocates a screen for us
315 */
316 if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
317 /* do some minimal setup to avoid weirdnesses later */
318 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
319 &defattr);
320 } else
321 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
322
323 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
324 sc->sc_scr.fbheight - sc->sc_height - 5,
325 sc->sc_scr.fbwidth,
326 ri->ri_font->fontwidth,
327 ri->ri_font->fontheight,
328 defattr);
329 }
330
331 gftfb_restore_palette(sc);
332
333 /* no suspend/resume support yet */
334 if (!pmf_device_register(sc->sc_dev, NULL, NULL))
335 aprint_error_dev(sc->sc_dev,
336 "couldn't establish power handler\n");
337
338 aa.console = is_console;
339 aa.scrdata = &sc->sc_screenlist;
340 aa.accessops = &gftfb_accessops;
341 aa.accesscookie = &sc->vd;
342
343 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
344 }
345
346 /*
347 * Grovel the STI ROM image.
348 */
349 int
350 gftfb_check_rom(struct gftfb_softc *spc, struct pci_attach_args *pa)
351 {
352 struct sti_softc *sc = &spc->sc_base;
353 pcireg_t address, mask;
354 bus_space_handle_t romh;
355 bus_size_t romsize, subsize, stiromsize;
356 bus_addr_t selected, offs, suboffs;
357 uint32_t tmp;
358 int i;
359 int rc;
360
361 /* sort of inline sti_pci_enable_rom(sc) */
362 address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM);
363 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM,
364 ~PCI_MAPREG_ROM_ENABLE);
365 mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM);
366 address |= PCI_MAPREG_ROM_ENABLE;
367 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, address);
368 sc->sc_flags |= STI_ROM_ENABLED;
369 /*
370 * Map the complete ROM for now.
371 */
372
373 romsize = PCI_ROM_SIZE(mask);
374 DPRINTF(("%s: mapping rom @ %lx for %lx\n", __func__,
375 (long)PCI_MAPREG_ROM_ADDR(address), (long)romsize));
376
377 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address), romsize,
378 0, &romh);
379 if (rc != 0) {
380 aprint_error_dev(sc->sc_dev, "can't map PCI ROM (%d)\n", rc);
381 goto fail2;
382 }
383
384 gftfb_disable_rom_internal(spc);
385 /*
386 * Iterate over the ROM images, pick the best candidate.
387 */
388
389 selected = (bus_addr_t)-1;
390 for (offs = 0; offs < romsize; offs += subsize) {
391 gftfb_enable_rom_internal(spc);
392 /*
393 * Check for a valid ROM header.
394 */
395 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0);
396 tmp = le32toh(tmp);
397 if (tmp != 0x55aa0000) {
398 gftfb_disable_rom_internal(spc);
399 if (offs == 0) {
400 aprint_error_dev(sc->sc_dev,
401 "invalid PCI ROM header signature (%08x)\n",
402 tmp);
403 rc = EINVAL;
404 }
405 break;
406 }
407
408 /*
409 * Check ROM type.
410 */
411 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4);
412 tmp = le32toh(tmp);
413 if (tmp != 0x00000001) { /* 1 == STI ROM */
414 gftfb_disable_rom_internal(spc);
415 if (offs == 0) {
416 aprint_error_dev(sc->sc_dev,
417 "invalid PCI ROM type (%08x)\n", tmp);
418 rc = EINVAL;
419 }
420 break;
421 }
422
423 subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
424 offs + 0x0c);
425 subsize <<= 9;
426
427 #ifdef STIDEBUG
428 gftfb_disable_rom_internal(spc);
429 DPRINTF(("ROM offset %08x size %08x type %08x",
430 (u_int)offs, (u_int)subsize, tmp));
431 gftfb_enable_rom_internal(spc);
432 #endif
433
434 /*
435 * Check for a valid ROM data structure.
436 * We do not need it except to know what architecture the ROM
437 * code is for.
438 */
439
440 suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
441 offs + 0x18);
442 tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0);
443 tmp = le32toh(tmp);
444 if (tmp != 0x50434952) { /* PCIR */
445 gftfb_disable_rom_internal(spc);
446 if (offs == 0) {
447 aprint_error_dev(sc->sc_dev, "invalid PCI data"
448 " signature (%08x)\n", tmp);
449 rc = EINVAL;
450 } else {
451 DPRINTF((" invalid PCI data signature %08x\n",
452 tmp));
453 continue;
454 }
455 }
456
457 tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14);
458 gftfb_disable_rom_internal(spc);
459 DPRINTF((" code %02x", tmp));
460
461 switch (tmp) {
462 #ifdef __hppa__
463 case 0x10:
464 if (selected == (bus_addr_t)-1)
465 selected = offs;
466 break;
467 #endif
468 #ifdef __i386__
469 case 0x00:
470 if (selected == (bus_addr_t)-1)
471 selected = offs;
472 break;
473 #endif
474 default:
475 #ifdef STIDEBUG
476 DPRINTF((" (wrong architecture)"));
477 #endif
478 break;
479 }
480 DPRINTF(("%s\n", selected == offs ? " -> SELECTED" : ""));
481 }
482
483 if (selected == (bus_addr_t)-1) {
484 if (rc == 0) {
485 aprint_error_dev(sc->sc_dev, "found no ROM with "
486 "correct microcode architecture\n");
487 rc = ENOEXEC;
488 }
489 goto fail;
490 }
491
492 /*
493 * Read the STI region BAR assignments.
494 */
495
496 gftfb_enable_rom_internal(spc);
497 offs = selected +
498 (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e);
499 for (i = 0; i < STI_REGION_MAX; i++) {
500 rc = gftfb_readbar(sc, pa, i,
501 bus_space_read_1(pa->pa_memt, romh, offs + i));
502 if (rc != 0)
503 goto fail;
504 }
505
506 /*
507 * Find out where the STI ROM itself lies, and its size.
508 */
509
510 offs = selected +
511 (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08);
512 stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh,
513 offs + 0x18);
514 stiromsize = le32toh(stiromsize);
515 gftfb_disable_rom_internal(spc);
516
517 /*
518 * Replace our mapping with a smaller mapping of only the area
519 * we are interested in.
520 */
521
522 DPRINTF(("remapping rom @ %lx for %lx\n",
523 (long)(PCI_MAPREG_ROM_ADDR(address) + offs), (long)stiromsize));
524 bus_space_unmap(pa->pa_memt, romh, romsize);
525 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address) + offs,
526 stiromsize, 0, &spc->sc_romh);
527 if (rc != 0) {
528 aprint_error_dev(sc->sc_dev, "can't map STI ROM (%d)\n",
529 rc);
530 goto fail2;
531 }
532 gftfb_disable_rom_internal(spc);
533 sc->sc_flags &= ~STI_ROM_ENABLED;
534
535 return 0;
536
537 fail:
538 bus_space_unmap(pa->pa_memt, romh, romsize);
539 fail2:
540 gftfb_disable_rom_internal(spc);
541
542 return rc;
543 }
544
545 /*
546 * Decode a BAR register.
547 */
548 int
549 gftfb_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region,
550 int bar)
551 {
552 bus_addr_t addr;
553 bus_size_t size;
554 uint32_t cf;
555 int rc;
556
557 if (bar == 0) {
558 sc->bases[region] = 0;
559 return (0);
560 }
561
562 #ifdef DIAGNOSTIC
563 if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) {
564 gftfb_disable_rom(sc);
565 printf("%s: unexpected bar %02x for region %d\n",
566 device_xname(sc->sc_dev), bar, region);
567 gftfb_enable_rom(sc);
568 }
569 #endif
570
571 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
572
573 rc = pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, PCI_MAPREG_TYPE(cf),
574 &addr, &size, NULL);
575
576 if (rc != 0) {
577 gftfb_disable_rom(sc);
578 aprint_error_dev(sc->sc_dev, "invalid bar %02x for region %d\n",
579 bar, region);
580 gftfb_enable_rom(sc);
581 return (rc);
582 }
583
584 sc->bases[region] = addr;
585 return (0);
586 }
587
588 /*
589 * Enable PCI ROM.
590 */
591 void
592 gftfb_enable_rom_internal(struct gftfb_softc *spc)
593 {
594 pcireg_t address;
595
596 KASSERT(spc != NULL);
597
598 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM);
599 address |= PCI_MAPREG_ROM_ENABLE;
600 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address);
601 }
602
603 void
604 gftfb_enable_rom(struct sti_softc *sc)
605 {
606 struct gftfb_softc *spc = device_private(sc->sc_dev);
607
608 if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
609 gftfb_enable_rom_internal(spc);
610 }
611 SET(sc->sc_flags, STI_ROM_ENABLED);
612 }
613
614 /*
615 * Disable PCI ROM.
616 */
617 void
618 gftfb_disable_rom_internal(struct gftfb_softc *spc)
619 {
620 pcireg_t address;
621
622 KASSERT(spc != NULL);
623
624 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM);
625 address &= ~PCI_MAPREG_ROM_ENABLE;
626 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address);
627 }
628
629 void
630 gftfb_disable_rom(struct sti_softc *sc)
631 {
632 struct gftfb_softc *spc = device_private(sc->sc_dev);
633
634 if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
635 gftfb_disable_rom_internal(spc);
636 }
637 CLR(sc->sc_flags, STI_ROM_ENABLED);
638 }
639
640 static inline void
641 gftfb_wait(struct gftfb_softc *sc)
642 {
643 struct sti_rom *rom = sc->sc_base.sc_rom;
644 bus_space_tag_t memt = rom->memt;
645 bus_space_handle_t memh = rom->regh[2];
646 uint8_t stat;
647
648 do {
649 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
650 if (stat == 0)
651 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
652 } while (stat != 0);
653 }
654
655 static inline void
656 gftfb_setup_fb(struct gftfb_softc *sc)
657 {
658 struct sti_rom *rom = sc->sc_base.sc_rom;
659 bus_space_tag_t memt = rom->memt;
660 bus_space_handle_t memh = rom->regh[2];
661
662 gftfb_wait(sc);
663 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0x13601000);
664 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x83000300);
665 gftfb_wait(sc);
666 bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
667 sc->sc_hwmode = HW_FB;
668 }
669
670 void
671 gftfb_setup(struct gftfb_softc *sc)
672 {
673 struct sti_rom *rom = sc->sc_base.sc_rom;
674 bus_space_tag_t memt = rom->memt;
675 bus_space_handle_t memh = rom->regh[2];
676 int i;
677
678 sc->sc_hwmode = HW_FB;
679 sc->sc_hot_x = 0;
680 sc->sc_hot_y = 0;
681 sc->sc_enabled = 0;
682 sc->sc_video_on = 1;
683
684 sc->sc_rect_colour = 0xf0000000;
685 sc->sc_rect_height = 0;
686
687 /* set Bt458 read mask register to all planes */
688 gftfb_wait(sc);
689 ngle_bt458_write(memt, memh, 0x08, 0x04);
690 ngle_bt458_write(memt, memh, 0x0a, 0xff);
691
692 gftfb_setup_fb(sc);
693
694 /* attr. planes */
695 gftfb_wait(sc);
696 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
697 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x23000302);
698 bus_space_write_stream_4(memt, memh, NGLE_REG_12, NGLE_ARTIST_CMAP0);
699 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
700
701 gftfb_wait(sc);
702 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x00000000);
703 bus_space_write_stream_4(memt, memh, NGLE_REG_9,
704 (sc->sc_scr.scr_cfg.scr_width << 16) | sc->sc_scr.scr_cfg.scr_height);
705 /*
706 * blit into offscreen memory to force flush previous - apparently
707 * some chips have a bug this works around
708 */
709 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x05000000);
710 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 0x00040001);
711
712 gftfb_wait(sc);
713 bus_space_write_stream_4(memt, memh, NGLE_REG_12, 0x00000000);
714
715 gftfb_setup_fb(sc);
716
717 /* make sure video output is enabled */
718 gftfb_wait(sc);
719 bus_space_write_stream_4(memt, memh, NGLE_REG_21,
720 bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000);
721 bus_space_write_stream_4(memt, memh, NGLE_REG_27,
722 bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000);
723
724 /* initialize cursor sprite */
725 gftfb_wait(sc);
726
727 /* cursor mask */
728 gftfb_wait(sc);
729 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
730 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
731 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A07000);
732 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
733 for (i = 0; i < 64; i++) {
734 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0xffffffff);
735 bus_space_write_stream_4(memt, memh, NGLE_REG_5, 0xffffffff);
736 }
737
738 /* cursor image */
739 gftfb_wait(sc);
740 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
741 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
742 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A06000);
743 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
744 for (i = 0; i < 64; i++) {
745 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0xff00ff00);
746 bus_space_write_stream_4(memt, memh, NGLE_REG_5, 0xff00ff00);
747 }
748
749 /* colour map */
750 gftfb_wait(sc);
751 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xBBE0F000);
752 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
753 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
754 gftfb_wait(sc);
755 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
756 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
757 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
758 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0x000000ff); /* BG */
759 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0x00ff0000); /* FG */
760 gftfb_wait(sc);
761 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0);
762 bus_space_write_stream_4(memt, memh, NGLE_REG_26, 0x80008004);
763 gftfb_setup_fb(sc);
764
765 gftfb_move_cursor(sc, 100, 100);
766
767 }
768
769 static int
770 gftfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
771 struct lwp *l)
772 {
773 struct vcons_data *vd = v;
774 struct gftfb_softc *sc = vd->cookie;
775 struct wsdisplay_fbinfo *wdf;
776 struct vcons_screen *ms = vd->active;
777
778 switch (cmd) {
779 case WSDISPLAYIO_GTYPE:
780 *(u_int *)data = WSDISPLAY_TYPE_STI;
781 return 0;
782
783 /* PCI config read/write passthrough. */
784 case PCI_IOC_CFGREAD:
785 case PCI_IOC_CFGWRITE:
786 return pci_devioctl(sc->sc_pc, sc->sc_tag,
787 cmd, data, flag, l);
788
789 case WSDISPLAYIO_GET_BUSID:
790 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
791 sc->sc_tag, data);
792
793 case WSDISPLAYIO_GINFO:
794 if (ms == NULL)
795 return ENODEV;
796 wdf = (void *)data;
797 wdf->height = ms->scr_ri.ri_height;
798 wdf->width = ms->scr_ri.ri_width;
799 wdf->depth = ms->scr_ri.ri_depth;
800 wdf->cmsize = 256;
801 return 0;
802
803 case WSDISPLAYIO_GETCMAP:
804 return gftfb_getcmap(sc,
805 (struct wsdisplay_cmap *)data);
806
807 case WSDISPLAYIO_PUTCMAP:
808 return gftfb_putcmap(sc,
809 (struct wsdisplay_cmap *)data);
810
811 case WSDISPLAYIO_LINEBYTES:
812 *(u_int *)data = 2048;
813 return 0;
814
815 case WSDISPLAYIO_SMODE: {
816 int new_mode = *(int*)data;
817 if (new_mode != sc->sc_mode) {
818 sc->sc_mode = new_mode;
819 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
820 gftfb_setup(sc);
821 gftfb_restore_palette(sc);
822 glyphcache_wipe(&sc->sc_gc);
823 gftfb_rectfill(sc, 0, 0, sc->sc_width,
824 sc->sc_height, ms->scr_ri.ri_devcmap[
825 (ms->scr_defattr >> 16) & 0xff]);
826 vcons_redraw_screen(ms);
827 gftfb_set_video(sc, 1);
828 }
829 }
830 }
831 return 0;
832
833 case WSDISPLAYIO_GET_FBINFO:
834 {
835 struct wsdisplayio_fbinfo *fbi = data;
836 int ret;
837
838 ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
839 fbi->fbi_fbsize = sc->sc_scr.fbheight * 2048;
840 return ret;
841 }
842
843 case WSDISPLAYIO_GCURPOS:
844 {
845 struct wsdisplay_curpos *cp = (void *)data;
846
847 cp->x = sc->sc_cursor_x;
848 cp->y = sc->sc_cursor_y;
849 }
850 return 0;
851
852 case WSDISPLAYIO_SCURPOS:
853 {
854 struct wsdisplay_curpos *cp = (void *)data;
855
856 gftfb_move_cursor(sc, cp->x, cp->y);
857 }
858 return 0;
859
860 case WSDISPLAYIO_GCURMAX:
861 {
862 struct wsdisplay_curpos *cp = (void *)data;
863
864 cp->x = 64;
865 cp->y = 64;
866 }
867 return 0;
868
869 case WSDISPLAYIO_SCURSOR:
870 {
871 struct wsdisplay_cursor *cursor = (void *)data;
872
873 return gftfb_do_cursor(sc, cursor);
874 }
875
876 case WSDISPLAYIO_SVIDEO:
877 gftfb_set_video(sc, *(int *)data);
878 return 0;
879 case WSDISPLAYIO_GVIDEO:
880 return sc->sc_video_on ?
881 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
882 }
883 return EPASSTHROUGH;
884 }
885
886 static paddr_t
887 gftfb_mmap(void *v, void *vs, off_t offset, int prot)
888 {
889 struct vcons_data *vd = v;
890 struct gftfb_softc *sc = vd->cookie;
891 struct sti_rom *rom = sc->sc_base.sc_rom;
892 paddr_t pa;
893
894 if (offset < 0 || offset >= sc->sc_scr.fblen)
895 return -1;
896
897 if (sc->sc_mode != WSDISPLAYIO_MODE_DUMBFB)
898 return -1;
899
900 pa = bus_space_mmap(rom->memt, sc->sc_scr.fbaddr, offset, prot,
901 BUS_SPACE_MAP_LINEAR);
902 return pa;
903 }
904
905 static void
906 gftfb_init_screen(void *cookie, struct vcons_screen *scr,
907 int existing, long *defattr)
908 {
909 struct gftfb_softc *sc = cookie;
910 struct rasops_info *ri = &scr->scr_ri;
911
912 ri->ri_depth = 8;
913 ri->ri_width = sc->sc_width;
914 ri->ri_height = sc->sc_height;
915 ri->ri_stride = 2048;
916 ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB |
917 RI_ENABLE_ALPHA | RI_PREFER_ALPHA;
918
919 ri->ri_bits = (void *)sc->sc_scr.fbaddr;
920 rasops_init(ri, 0, 0);
921 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
922 WSSCREEN_RESIZE;
923 scr->scr_flags |= VCONS_LOADFONT;
924
925 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
926 sc->sc_width / ri->ri_font->fontwidth);
927
928 ri->ri_hw = scr;
929 sc->sc_putchar = ri->ri_ops.putchar;
930 ri->ri_ops.copyrows = gftfb_copyrows;
931 ri->ri_ops.copycols = gftfb_copycols;
932 ri->ri_ops.eraserows = gftfb_eraserows;
933 ri->ri_ops.erasecols = gftfb_erasecols;
934 ri->ri_ops.cursor = gftfb_cursor;
935 ri->ri_ops.putchar = gftfb_putchar;
936 }
937
938 static int
939 gftfb_putcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm)
940 {
941 u_char *r, *g, *b;
942 u_int index = cm->index;
943 u_int count = cm->count;
944 int i, error;
945 u_char rbuf[256], gbuf[256], bbuf[256];
946
947 if (cm->index >= 256 || cm->count > 256 ||
948 (cm->index + cm->count) > 256)
949 return EINVAL;
950 error = copyin(cm->red, &rbuf[index], count);
951 if (error)
952 return error;
953 error = copyin(cm->green, &gbuf[index], count);
954 if (error)
955 return error;
956 error = copyin(cm->blue, &bbuf[index], count);
957 if (error)
958 return error;
959
960 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
961 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
962 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
963
964 r = &sc->sc_cmap_red[index];
965 g = &sc->sc_cmap_green[index];
966 b = &sc->sc_cmap_blue[index];
967
968 for (i = 0; i < count; i++) {
969 gftfb_putpalreg(sc, index, *r, *g, *b);
970 index++;
971 r++, g++, b++;
972 }
973 return 0;
974 }
975
976 static int
977 gftfb_getcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm)
978 {
979 u_int index = cm->index;
980 u_int count = cm->count;
981 int error;
982
983 if (index >= 255 || count > 256 || index + count > 256)
984 return EINVAL;
985
986 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
987 if (error)
988 return error;
989 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
990 if (error)
991 return error;
992 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
993 if (error)
994 return error;
995
996 return 0;
997 }
998
999 static void
1000 gftfb_restore_palette(struct gftfb_softc *sc)
1001 {
1002 uint8_t cmap[768];
1003 int i, j;
1004
1005 j = 0;
1006 rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap));
1007 for (i = 0; i < 256; i++) {
1008 sc->sc_cmap_red[i] = cmap[j];
1009 sc->sc_cmap_green[i] = cmap[j + 1];
1010 sc->sc_cmap_blue[i] = cmap[j + 2];
1011 gftfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
1012 j += 3;
1013 }
1014 }
1015
1016 static int
1017 gftfb_putpalreg(struct gftfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
1018 uint8_t b)
1019 {
1020 struct sti_rom *rom = sc->sc_base.sc_rom;
1021 bus_space_tag_t memt = rom->memt;
1022 bus_space_handle_t memh = rom->regh[2];
1023
1024 mutex_enter(&sc->sc_hwlock);
1025 gftfb_wait(sc);
1026 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1027 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
1028 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1029
1030 gftfb_wait(sc);
1031 bus_space_write_stream_4(memt, memh, NGLE_REG_3,
1032 0x400 | (idx << 2));
1033 bus_space_write_stream_4(memt, memh, NGLE_REG_4,
1034 (r << 16) | (g << 8) | b);
1035
1036 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400);
1037 bus_space_write_stream_4(memt, memh, NGLE_REG_26, 0x80000100);
1038 gftfb_setup_fb(sc);
1039 mutex_exit(&sc->sc_hwlock);
1040 return 0;
1041 }
1042
1043 static inline void
1044 gftfb_wait_fifo(struct gftfb_softc *sc, uint32_t slots)
1045 {
1046 struct sti_rom *rom = sc->sc_base.sc_rom;
1047 bus_space_tag_t memt = rom->memt;
1048 bus_space_handle_t memh = rom->regh[2];
1049 uint32_t reg;
1050
1051 do {
1052 reg = bus_space_read_stream_4(memt, memh, NGLE_REG_34);
1053 } while (reg < slots);
1054 }
1055
1056 static void
1057 gftfb_real_rectfill(struct gftfb_softc *sc, int x, int y, int wi, int he,
1058 uint32_t bg)
1059 {
1060 struct sti_rom *rom = sc->sc_base.sc_rom;
1061 bus_space_tag_t memt = rom->memt;
1062 bus_space_handle_t memh = rom->regh[2];
1063
1064 if (sc->sc_hwmode != HW_FILL) {
1065 gftfb_wait_fifo(sc, 4);
1066 /* transfer data */
1067 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
1068 /* plane mask */
1069 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xff);
1070 /* bitmap op */
1071 bus_space_write_stream_4(memt, memh, NGLE_REG_14,
1072 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0));
1073 /* dst bitmap access */
1074 bus_space_write_stream_4(memt, memh, NGLE_REG_11,
1075 BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0I, 0));
1076 sc->sc_hwmode = HW_FILL;
1077 }
1078 gftfb_wait_fifo(sc, 3);
1079 bus_space_write_stream_4(memt, memh, NGLE_REG_35, bg);
1080 /* dst XY */
1081 bus_space_write_stream_4(memt, memh, NGLE_REG_6, (x << 16) | y);
1082 /* len XY start */
1083 bus_space_write_stream_4(memt, memh, NGLE_REG_9, (wi << 16) | he);
1084
1085 }
1086
1087 static void
1088 gftfb_rectfill(struct gftfb_softc *sc, int x, int y, int wi, int he,
1089 uint32_t bg)
1090 {
1091 /*
1092 * For some reason my 4MB VisEG always draws rectangles at least 32
1093 * pixels wide - no idea why, the bitblt command doesn't have this
1094 * problem.
1095 * So, as a workaround, we draw a 50xFontHeight rectangle to the right
1096 * of the visible fb, keep track of the colour so we don't need to
1097 * redraw every time, and bitblt the portion we need
1098 */
1099 if (wi < 50) {
1100 if ((bg != sc->sc_rect_colour) ||
1101 (he > sc->sc_rect_height)) {
1102 gftfb_real_rectfill(sc, sc->sc_width + 10, 0, 50,
1103 he, bg);
1104 sc->sc_rect_colour = bg;
1105 sc->sc_rect_height = he;
1106 }
1107 gftfb_bitblt(sc, sc->sc_width + 10, 0, x, y, wi, he, RopSrc);
1108 } else
1109 gftfb_real_rectfill(sc, x, y, wi, he, bg);
1110 }
1111
1112 static void
1113 gftfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi,
1114 int he, int rop)
1115 {
1116 struct gftfb_softc *sc = cookie;
1117 struct sti_rom *rom = sc->sc_base.sc_rom;
1118 bus_space_tag_t memt = rom->memt;
1119 bus_space_handle_t memh = rom->regh[2];
1120
1121 if (sc->sc_hwmode != HW_BLIT) {
1122 gftfb_wait(sc);
1123 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0x13a01000);
1124 sc->sc_hwmode = HW_BLIT;
1125 }
1126 gftfb_wait_fifo(sc, 5);
1127 bus_space_write_stream_4(memt, memh, NGLE_REG_14, ((rop << 8) & 0xf00) | 0x23000000);
1128 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xff);
1129 bus_space_write_stream_4(memt, memh, NGLE_REG_24, (xs << 16) | ys);
1130 bus_space_write_stream_4(memt, memh, NGLE_REG_7, (wi << 16) | he);
1131 bus_space_write_stream_4(memt, memh, NGLE_REG_25, (xd << 16) | yd);
1132 }
1133
1134 static void
1135 gftfb_nuke_cursor(struct rasops_info *ri)
1136 {
1137 struct vcons_screen *scr = ri->ri_hw;
1138 struct gftfb_softc *sc = scr->scr_cookie;
1139 int wi, he, x, y;
1140
1141 if (ri->ri_flg & RI_CURSOR) {
1142 wi = ri->ri_font->fontwidth;
1143 he = ri->ri_font->fontheight;
1144 x = ri->ri_ccol * wi + ri->ri_xorigin;
1145 y = ri->ri_crow * he + ri->ri_yorigin;
1146 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
1147 ri->ri_flg &= ~RI_CURSOR;
1148 }
1149 }
1150
1151 static void
1152 gftfb_cursor(void *cookie, int on, int row, int col)
1153 {
1154 struct rasops_info *ri = cookie;
1155 struct vcons_screen *scr = ri->ri_hw;
1156 struct gftfb_softc *sc = scr->scr_cookie;
1157 int x, y, wi, he;
1158
1159 wi = ri->ri_font->fontwidth;
1160 he = ri->ri_font->fontheight;
1161
1162 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1163 if (on) {
1164 if (ri->ri_flg & RI_CURSOR) {
1165 gftfb_nuke_cursor(ri);
1166 }
1167 x = col * wi + ri->ri_xorigin;
1168 y = row * he + ri->ri_yorigin;
1169 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
1170 ri->ri_flg |= RI_CURSOR;
1171 }
1172 ri->ri_crow = row;
1173 ri->ri_ccol = col;
1174 } else
1175 {
1176 ri->ri_crow = row;
1177 ri->ri_ccol = col;
1178 ri->ri_flg &= ~RI_CURSOR;
1179 }
1180
1181 }
1182
1183 static void
1184 gftfb_putchar(void *cookie, int row, int col, u_int c, long attr)
1185 {
1186 struct rasops_info *ri = cookie;
1187 struct wsdisplay_font *font = PICK_FONT(ri, c);
1188 struct vcons_screen *scr = ri->ri_hw;
1189 struct gftfb_softc *sc = scr->scr_cookie;
1190 int x, y, wi, he, rv = GC_NOPE;
1191 uint32_t bg;
1192
1193 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1194 return;
1195
1196 if (!CHAR_IN_FONT(c, font))
1197 return;
1198
1199 if (row == ri->ri_crow && col == ri->ri_ccol) {
1200 ri->ri_flg &= ~RI_CURSOR;
1201 }
1202
1203 wi = font->fontwidth;
1204 he = font->fontheight;
1205
1206 x = ri->ri_xorigin + col * wi;
1207 y = ri->ri_yorigin + row * he;
1208
1209 bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1210
1211 if (c == 0x20) {
1212 gftfb_rectfill(sc, x, y, wi, he, bg);
1213 return;
1214 }
1215
1216 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1217 if (rv == GC_OK)
1218 return;
1219
1220 if (sc->sc_hwmode != HW_FB) gftfb_setup_fb(sc);
1221 sc->sc_putchar(cookie, row, col, c, attr);
1222
1223 if (rv == GC_ADD)
1224 glyphcache_add(&sc->sc_gc, c, x, y);
1225 }
1226
1227 static void
1228 gftfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1229 {
1230 struct rasops_info *ri = cookie;
1231 struct vcons_screen *scr = ri->ri_hw;
1232 struct gftfb_softc *sc = scr->scr_cookie;
1233 int32_t xs, xd, y, width, height;
1234
1235 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1236 if (ri->ri_crow == row &&
1237 (ri->ri_ccol >= srccol && ri->ri_ccol < (srccol + ncols)) &&
1238 (ri->ri_flg & RI_CURSOR)) {
1239 gftfb_nuke_cursor(ri);
1240 }
1241
1242 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1243 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1244 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1245 width = ri->ri_font->fontwidth * ncols;
1246 height = ri->ri_font->fontheight;
1247 gftfb_bitblt(sc, xs, y, xd, y, width, height, RopSrc);
1248 if (ri->ri_crow == row &&
1249 (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols)))
1250 ri->ri_flg &= ~RI_CURSOR;
1251 }
1252 }
1253
1254 static void
1255 gftfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1256 {
1257 struct rasops_info *ri = cookie;
1258 struct vcons_screen *scr = ri->ri_hw;
1259 struct gftfb_softc *sc = scr->scr_cookie;
1260 int32_t x, y, width, height, fg, bg, ul;
1261
1262 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1263 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1264 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1265 width = ri->ri_font->fontwidth * ncols;
1266 height = ri->ri_font->fontheight;
1267 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1268
1269 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1270 if (ri->ri_crow == row &&
1271 (ri->ri_ccol >= startcol && ri->ri_ccol < (startcol + ncols)))
1272 ri->ri_flg &= ~RI_CURSOR;
1273 }
1274 }
1275
1276 static void
1277 gftfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1278 {
1279 struct rasops_info *ri = cookie;
1280 struct vcons_screen *scr = ri->ri_hw;
1281 struct gftfb_softc *sc = scr->scr_cookie;
1282 int32_t x, ys, yd, width, height;
1283
1284 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1285 if ((ri->ri_crow >= srcrow && ri->ri_crow < (srcrow + nrows)) &&
1286 (ri->ri_flg & RI_CURSOR)) {
1287 gftfb_nuke_cursor(ri);
1288 }
1289 x = ri->ri_xorigin;
1290 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1291 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1292 width = ri->ri_emuwidth;
1293 height = ri->ri_font->fontheight * nrows;
1294 gftfb_bitblt(sc, x, ys, x, yd, width, height, RopSrc);
1295 if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows))
1296 ri->ri_flg &= ~RI_CURSOR;
1297 }
1298 }
1299
1300 static void
1301 gftfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1302 {
1303 struct rasops_info *ri = cookie;
1304 struct vcons_screen *scr = ri->ri_hw;
1305 struct gftfb_softc *sc = scr->scr_cookie;
1306 int32_t x, y, width, height, fg, bg, ul;
1307
1308 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1309 x = ri->ri_xorigin;
1310 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1311 width = ri->ri_emuwidth;
1312 height = ri->ri_font->fontheight * nrows;
1313 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1314
1315 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1316
1317 if (ri->ri_crow >= row && ri->ri_crow < (row + nrows))
1318 ri->ri_flg &= ~RI_CURSOR;
1319 }
1320 }
1321
1322 /*
1323 * cursor sprite handling
1324 * like most hw info, xf86 3.3 -> nglehdw.h was used as documentation
1325 * problem is, the PCI EG doesn't quite behave like an S9000_ID_ARTIST
1326 * the cursor position register bahaves like the one on HCRX while using
1327 * the same address as Artist, incuding the enable bit and weird handling
1328 * of negative coordinates. The rest of it, colour map, sprite image etc.,
1329 * behave like Artist.
1330 */
1331
1332 static void
1333 gftfb_move_cursor(struct gftfb_softc *sc, int x, int y)
1334 {
1335 struct sti_rom *rom = sc->sc_base.sc_rom;
1336 bus_space_tag_t memt = rom->memt;
1337 bus_space_handle_t memh = rom->regh[2];
1338 uint32_t pos;
1339
1340 sc->sc_cursor_x = x;
1341 x -= sc->sc_hot_x;
1342 sc->sc_cursor_y = y;
1343 y -= sc->sc_hot_y;
1344
1345 if (x < 0) x = 0x1000 - x;
1346 if (y < 0) y = 0x1000 - y;
1347 pos = (x << 16) | y;
1348 if (sc->sc_enabled) pos |= 0x80000000;
1349 gftfb_wait(sc);
1350 bus_space_write_stream_4(memt, memh, NGLE_REG_17, pos);
1351 bus_space_write_stream_4(memt, memh, NGLE_REG_18, 0x80);
1352 }
1353
1354 static int
1355 gftfb_do_cursor(struct gftfb_softc *sc, struct wsdisplay_cursor *cur)
1356 {
1357 struct sti_rom *rom = sc->sc_base.sc_rom;
1358 bus_space_tag_t memt = rom->memt;
1359 bus_space_handle_t memh = rom->regh[2];
1360
1361 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1362
1363 sc->sc_enabled = cur->enable;
1364 cur->which |= WSDISPLAY_CURSOR_DOPOS;
1365 }
1366 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1367
1368 sc->sc_hot_x = cur->hot.x;
1369 sc->sc_hot_y = cur->hot.y;
1370 cur->which |= WSDISPLAY_CURSOR_DOPOS;
1371 }
1372 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1373
1374 gftfb_move_cursor(sc, cur->pos.x, cur->pos.y);
1375 }
1376 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1377 uint32_t rgb;
1378 uint8_t r[2], g[2], b[2];
1379
1380 copyin(cur->cmap.blue, b, 2);
1381 copyin(cur->cmap.green, g, 2);
1382 copyin(cur->cmap.red, r, 2);
1383 mutex_enter(&sc->sc_hwlock);
1384 gftfb_wait(sc);
1385 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xBBE0F000);
1386 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
1387 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1388 gftfb_wait(sc);
1389 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
1390 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
1391 bus_space_write_stream_4(memt, memh, NGLE_REG_4, 0);
1392 rgb = (r[0] << 16) | (g[0] << 8) | b[0];
1393 bus_space_write_stream_4(memt, memh, NGLE_REG_4, rgb); /* BG */
1394 rgb = (r[1] << 16) | (g[1] << 8) | b[1];
1395 bus_space_write_stream_4(memt, memh, NGLE_REG_4, rgb); /* FG */
1396 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0);
1397 bus_space_write_stream_4(memt, memh, NGLE_REG_26, 0x80008004);
1398 gftfb_setup_fb(sc);
1399 mutex_exit(&sc->sc_hwlock);
1400
1401 }
1402 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1403 uint32_t buffer[128], latch, tmp;
1404 int i;
1405
1406 copyin(cur->mask, buffer, 512);
1407 gftfb_wait(sc);
1408 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
1409 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1410 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A07000);
1411 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
1412 for (i = 0; i < 128; i += 2) {
1413 latch = 0;
1414 tmp = buffer[i] & 0x80808080;
1415 latch |= tmp >> 7;
1416 tmp = buffer[i] & 0x40404040;
1417 latch |= tmp >> 5;
1418 tmp = buffer[i] & 0x20202020;
1419 latch |= tmp >> 3;
1420 tmp = buffer[i] & 0x10101010;
1421 latch |= tmp >> 1;
1422 tmp = buffer[i] & 0x08080808;
1423 latch |= tmp << 1;
1424 tmp = buffer[i] & 0x04040404;
1425 latch |= tmp << 3;
1426 tmp = buffer[i] & 0x02020202;
1427 latch |= tmp << 5;
1428 tmp = buffer[i] & 0x01010101;
1429 latch |= tmp << 7;
1430 bus_space_write_stream_4(memt, memh, NGLE_REG_4, latch);
1431 latch = 0;
1432 tmp = buffer[i + 1] & 0x80808080;
1433 latch |= tmp >> 7;
1434 tmp = buffer[i + 1] & 0x40404040;
1435 latch |= tmp >> 5;
1436 tmp = buffer[i + 1] & 0x20202020;
1437 latch |= tmp >> 3;
1438 tmp = buffer[i + 1] & 0x10101010;
1439 latch |= tmp >> 1;
1440 tmp = buffer[i + 1] & 0x08080808;
1441 latch |= tmp << 1;
1442 tmp = buffer[i + 1] & 0x04040404;
1443 latch |= tmp << 3;
1444 tmp = buffer[i + 1] & 0x02020202;
1445 latch |= tmp << 5;
1446 tmp = buffer[i + 1] & 0x01010101;
1447 latch |= tmp << 7;
1448 bus_space_write_stream_4(memt, memh, NGLE_REG_5, latch);
1449 }
1450
1451 copyin(cur->image, buffer, 512);
1452 gftfb_wait(sc);
1453 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x300);
1454 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
1455 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x28A06000);
1456 bus_space_write_stream_4(memt, memh, NGLE_REG_3, 0);
1457 for (i = 0; i < 128; i += 2) {
1458 latch = 0;
1459 tmp = buffer[i] & 0x80808080;
1460 latch |= tmp >> 7;
1461 tmp = buffer[i] & 0x40404040;
1462 latch |= tmp >> 5;
1463 tmp = buffer[i] & 0x20202020;
1464 latch |= tmp >> 3;
1465 tmp = buffer[i] & 0x10101010;
1466 latch |= tmp >> 1;
1467 tmp = buffer[i] & 0x08080808;
1468 latch |= tmp << 1;
1469 tmp = buffer[i] & 0x04040404;
1470 latch |= tmp << 3;
1471 tmp = buffer[i] & 0x02020202;
1472 latch |= tmp << 5;
1473 tmp = buffer[i] & 0x01010101;
1474 latch |= tmp << 7;
1475 bus_space_write_stream_4(memt, memh, NGLE_REG_4, latch);
1476 latch = 0;
1477 tmp = buffer[i + 1] & 0x80808080;
1478 latch |= tmp >> 7;
1479 tmp = buffer[i + 1] & 0x40404040;
1480 latch |= tmp >> 5;
1481 tmp = buffer[i + 1] & 0x20202020;
1482 latch |= tmp >> 3;
1483 tmp = buffer[i + 1] & 0x10101010;
1484 latch |= tmp >> 1;
1485 tmp = buffer[i + 1] & 0x08080808;
1486 latch |= tmp << 1;
1487 tmp = buffer[i + 1] & 0x04040404;
1488 latch |= tmp << 3;
1489 tmp = buffer[i + 1] & 0x02020202;
1490 latch |= tmp << 5;
1491 tmp = buffer[i + 1] & 0x01010101;
1492 latch |= tmp << 7;
1493 bus_space_write_stream_4(memt, memh, NGLE_REG_5, latch);
1494 }
1495 gftfb_setup_fb(sc);
1496 }
1497
1498 return 0;
1499 }
1500
1501 static void
1502 gftfb_set_video(struct gftfb_softc *sc, int on)
1503 {
1504 struct sti_rom *rom = sc->sc_base.sc_rom;
1505 bus_space_tag_t memt = rom->memt;
1506 bus_space_handle_t memh = rom->regh[2];
1507
1508 if (sc->sc_video_on == on)
1509 return;
1510
1511 sc->sc_video_on = on;
1512
1513 gftfb_wait(sc);
1514 if (on) {
1515 bus_space_write_stream_4(memt, memh, NGLE_REG_21,
1516 bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000);
1517 bus_space_write_stream_4(memt, memh, NGLE_REG_27,
1518 bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000);
1519 } else {
1520 bus_space_write_stream_4(memt, memh, NGLE_REG_21,
1521 bus_space_read_stream_4(memt, memh, NGLE_REG_21) & ~0x0a000000);
1522 bus_space_write_stream_4(memt, memh, NGLE_REG_27,
1523 bus_space_read_stream_4(memt, memh, NGLE_REG_27) & ~0x00800000);
1524 }
1525 }
1526