gftfb.c revision 1.3 1 /* $NetBSD: gftfb.c,v 1.3 2024/02/20 11:37:43 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 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice, this permission notice, and the disclaimer below
11 * appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/kmem.h>
25 #include <sys/device.h>
26
27 #include <dev/pci/pcivar.h>
28 #include <dev/pci/pcireg.h>
29 #include <dev/pci/pcidevs.h>
30 #include <dev/pci/pciio.h>
31
32 #include <dev/wscons/wsdisplayvar.h>
33 #include <dev/wscons/wsconsio.h>
34 #include <dev/wsfont/wsfont.h>
35 #include <dev/rasops/rasops.h>
36 #include <dev/wscons/wsdisplay_vconsvar.h>
37 #include <dev/pci/wsdisplay_pci.h>
38 #include <dev/wscons/wsdisplay_glyphcachevar.h>
39
40 #include <dev/ic/stireg.h>
41 #include <dev/ic/stivar.h>
42
43 #ifdef STIDEBUG
44 #define DPRINTF(s) do { \
45 if (stidebug) \
46 printf s; \
47 } while(0)
48
49 extern int stidebug;
50 #else
51 #define DPRINTF(s) /* */
52 #endif
53
54 int gftfb_match(device_t, cfdata_t, void *);
55 void gftfb_attach(device_t, device_t, void *);
56
57 struct gftfb_softc {
58 device_t sc_dev;
59 pci_chipset_tag_t sc_pc;
60 pcitag_t sc_tag;
61
62 /* stuff we need in order to use the STI ROM */
63 struct sti_softc sc_base;
64 struct sti_screen sc_scr;
65 bus_space_handle_t sc_romh;
66
67 int sc_width, sc_height;
68 int sc_locked;
69 struct vcons_screen sc_console_screen;
70 struct wsscreen_descr sc_defaultscreen_descr;
71 const struct wsscreen_descr *sc_screens[1];
72 struct wsscreen_list sc_screenlist;
73 struct vcons_data vd;
74 int sc_mode;
75 void (*sc_putchar)(void *, int, int, u_int, long);
76 u_char sc_cmap_red[256];
77 u_char sc_cmap_green[256];
78 u_char sc_cmap_blue[256];
79 uint32_t sc_reg10;
80 glyphcache sc_gc;
81 };
82
83 CFATTACH_DECL_NEW(gftfb, sizeof(struct gftfb_softc),
84 gftfb_match, gftfb_attach, NULL, NULL);
85
86 int gftfb_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int);
87 int gftfb_check_rom(struct gftfb_softc *, struct pci_attach_args *);
88 void gftfb_enable_rom(struct sti_softc *);
89 void gftfb_disable_rom(struct sti_softc *);
90 void gftfb_enable_rom_internal(struct gftfb_softc *);
91 void gftfb_disable_rom_internal(struct gftfb_softc *);
92
93 void gftfb_setup(struct gftfb_softc *);
94
95 #define ngle_bt458_write(memt, memh, r, v) \
96 bus_space_write_stream_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
97
98
99 /* XXX these really need to go into their own header */
100 int sti_pci_is_console(struct pci_attach_args *, bus_addr_t *);
101 int sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
102 bus_space_handle_t, bus_addr_t *, u_int);
103 int sti_screen_setup(struct sti_screen *, int);
104 void sti_describe_screen(struct sti_softc *, struct sti_screen *);
105
106 #define PCI_ROM_SIZE(mr) \
107 (PCI_MAPREG_ROM_ADDR(mr) & -PCI_MAPREG_ROM_ADDR(mr))
108
109 /* wsdisplay stuff */
110 static int gftfb_ioctl(void *, void *, u_long, void *, int,
111 struct lwp *);
112 static paddr_t gftfb_mmap(void *, void *, off_t, int);
113 static void gftfb_init_screen(void *, struct vcons_screen *, int, long *);
114
115 static int gftfb_putcmap(struct gftfb_softc *, struct wsdisplay_cmap *);
116 static int gftfb_getcmap(struct gftfb_softc *, struct wsdisplay_cmap *);
117 static void gftfb_restore_palette(struct gftfb_softc *);
118 static int gftfb_putpalreg(struct gftfb_softc *, uint8_t, uint8_t,
119 uint8_t, uint8_t);
120
121 static void gftfb_rectfill(struct gftfb_softc *, int, int, int, int,
122 uint32_t);
123 static void gftfb_bitblt(void *, int, int, int, int, int,
124 int, int);
125
126 static void gftfb_cursor(void *, int, int, int);
127 static void gftfb_putchar(void *, int, int, u_int, long);
128 static void gftfb_copycols(void *, int, int, int, int);
129 static void gftfb_erasecols(void *, int, int, int, long);
130 static void gftfb_copyrows(void *, int, int, int);
131 static void gftfb_eraserows(void *, int, int, long);
132
133 struct wsdisplay_accessops gftfb_accessops = {
134 gftfb_ioctl,
135 gftfb_mmap,
136 NULL, /* alloc_screen */
137 NULL, /* free_screen */
138 NULL, /* show_screen */
139 NULL, /* load_font */
140 NULL, /* pollc */
141 NULL /* scroll */
142 };
143
144 #define BA(F,C,S,A,J,B,I) \
145 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
146
147 #define IBOvals(R,M,X,S,D,L,B,F) \
148 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
149
150 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
151 #define Otc04 2 /* Pixels in each longword transfer (4) */
152 #define Otc32 5 /* Pixels in each longword transfer (32) */
153 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
154 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
155 #define AddrLong 5 /* FB address is Long aligned (pixel) */
156 #define BINovly 0x2 /* 8 bit overlay */
157 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
158 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
159 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
160 #define BINattr 0xd /* Attribute Bitmap */
161 #define RopSrc 0x3
162 #define RopInv 0xc
163 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
164 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
165 #define DataDynamic 0 /* Data register reloaded by direct access */
166 #define MaskDynamic 1 /* Mask register reloaded by direct access */
167 #define MaskOtc 0 /* Mask contains Object Count valid bits */
168
169 int
170 gftfb_match(device_t parent, cfdata_t cf, void *aux)
171 {
172 struct pci_attach_args *paa = aux;
173
174 if (PCI_VENDOR(paa->pa_id) != PCI_VENDOR_HP)
175 return 0;
176
177 if (PCI_PRODUCT(paa->pa_id) == PCI_PRODUCT_HP_VISUALIZE_EG)
178 return 10; /* beat out sti at pci */
179
180 return 0;
181 }
182
183 void
184 gftfb_attach(device_t parent, device_t self, void *aux)
185 {
186 struct gftfb_softc *sc = device_private(self);
187 struct pci_attach_args *paa = aux;
188 struct sti_rom *rom;
189 struct rasops_info *ri;
190 struct wsemuldisplaydev_attach_args aa;
191 unsigned long defattr = 0;
192 int ret, is_console = 0, i, j;
193 uint8_t cmap[768];
194
195 sc->sc_dev = self;
196
197 sc->sc_pc = paa->pa_pc;
198 sc->sc_tag = paa->pa_tag;
199 sc->sc_base.sc_dev = self;
200 sc->sc_base.sc_enable_rom = gftfb_enable_rom;
201 sc->sc_base.sc_disable_rom = gftfb_disable_rom;
202
203 aprint_normal("\n");
204
205 if (gftfb_check_rom(sc, paa) != 0)
206 return;
207
208 ret = sti_pci_is_console(paa, sc->sc_base. bases);
209 if (ret != 0) {
210 sc->sc_base.sc_flags |= STI_CONSOLE;
211 is_console = 1;
212 }
213 rom = (struct sti_rom *)kmem_zalloc(sizeof(*rom), KM_SLEEP);
214 rom->rom_softc = &sc->sc_base;
215 ret = sti_rom_setup(rom, paa->pa_iot, paa->pa_memt, sc->sc_romh, sc->sc_base.bases, STI_CODEBASE_MAIN);
216 if (ret != 0) {
217 kmem_free(rom, sizeof(*rom));
218 return;
219 }
220
221 sc->sc_base.sc_rom = rom;
222
223 sc->sc_scr.scr_rom = sc->sc_base.sc_rom;
224 ret = sti_screen_setup(&sc->sc_scr, STI_FBMODE);
225
226 sc->sc_width = sc->sc_scr.scr_cfg.scr_width;
227 sc->sc_height = sc->sc_scr.scr_cfg.scr_height;
228
229 aprint_normal_dev(sc->sc_dev, "%s at %dx%d\n", sc->sc_scr.name,
230 sc->sc_width, sc->sc_height);
231 gftfb_setup(sc);
232
233 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
234 "default",
235 0, 0,
236 NULL,
237 8, 16,
238 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
239 WSSCREEN_RESIZE,
240 NULL
241 };
242
243 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
244 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
245 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
246 sc->sc_locked = 0;
247
248 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
249 &gftfb_accessops);
250 sc->vd.init_screen = gftfb_init_screen;
251 sc->vd.show_screen_cookie = &sc->sc_gc;
252 sc->vd.show_screen_cb = glyphcache_adapt;
253
254 ri = &sc->sc_console_screen.scr_ri;
255
256 sc->sc_gc.gc_bitblt = gftfb_bitblt;
257 sc->sc_gc.gc_blitcookie = sc;
258 sc->sc_gc.gc_rop = RopSrc;
259
260 if (is_console) {
261 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
262 &defattr);
263 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
264
265 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
266 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
267 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
268 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
269
270 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
271 sc->sc_scr.fbheight - sc->sc_height - 5,
272 sc->sc_width,
273 ri->ri_font->fontwidth,
274 ri->ri_font->fontheight,
275 defattr);
276
277 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
278 defattr);
279
280 gftfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
281 ri->ri_devcmap[(defattr >> 16) & 0xff]);
282
283 vcons_replay_msgbuf(&sc->sc_console_screen);
284 } else {
285 /*
286 * since we're not the console we can postpone the rest
287 * until someone actually allocates a screen for us
288 */
289 if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
290 /* do some minimal setup to avoid weirdnesses later */
291 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
292 &defattr);
293 } else
294 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
295
296 glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
297 sc->sc_scr.fbheight - sc->sc_height - 5,
298 sc->sc_width,
299 ri->ri_font->fontwidth,
300 ri->ri_font->fontheight,
301 defattr);
302 }
303
304 j = 0;
305 rasops_get_cmap(ri, cmap, sizeof(cmap));
306 for (i = 0; i < 256; i++) {
307 sc->sc_cmap_red[i] = cmap[j];
308 sc->sc_cmap_green[i] = cmap[j + 1];
309 sc->sc_cmap_blue[i] = cmap[j + 2];
310 gftfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
311 j += 3;
312 }
313
314 /* no suspend/resume support yet */
315 if (!pmf_device_register(sc->sc_dev, NULL, NULL))
316 aprint_error_dev(sc->sc_dev,
317 "couldn't establish power handler\n");
318
319 aa.console = is_console;
320 aa.scrdata = &sc->sc_screenlist;
321 aa.accessops = &gftfb_accessops;
322 aa.accesscookie = &sc->vd;
323
324 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
325 }
326
327 /*
328 * Grovel the STI ROM image.
329 */
330 int
331 gftfb_check_rom(struct gftfb_softc *spc, struct pci_attach_args *pa)
332 {
333 struct sti_softc *sc = &spc->sc_base;
334 pcireg_t address, mask;
335 bus_space_handle_t romh;
336 bus_size_t romsize, subsize, stiromsize;
337 bus_addr_t selected, offs, suboffs;
338 uint32_t tmp;
339 int i;
340 int rc;
341
342 /* sort of inline sti_pci_enable_rom(sc) */
343 address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM);
344 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM,
345 ~PCI_MAPREG_ROM_ENABLE);
346 mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM);
347 address |= PCI_MAPREG_ROM_ENABLE;
348 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, address);
349 sc->sc_flags |= STI_ROM_ENABLED;
350 /*
351 * Map the complete ROM for now.
352 */
353
354 romsize = PCI_ROM_SIZE(mask);
355 DPRINTF(("%s: mapping rom @ %lx for %lx\n", __func__,
356 (long)PCI_MAPREG_ROM_ADDR(address), (long)romsize));
357
358 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address), romsize,
359 0, &romh);
360 if (rc != 0) {
361 aprint_error_dev(sc->sc_dev, "can't map PCI ROM (%d)\n", rc);
362 goto fail2;
363 }
364
365 gftfb_disable_rom_internal(spc);
366 /*
367 * Iterate over the ROM images, pick the best candidate.
368 */
369
370 selected = (bus_addr_t)-1;
371 for (offs = 0; offs < romsize; offs += subsize) {
372 gftfb_enable_rom_internal(spc);
373 /*
374 * Check for a valid ROM header.
375 */
376 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0);
377 tmp = le32toh(tmp);
378 if (tmp != 0x55aa0000) {
379 gftfb_disable_rom_internal(spc);
380 if (offs == 0) {
381 aprint_error_dev(sc->sc_dev,
382 "invalid PCI ROM header signature (%08x)\n",
383 tmp);
384 rc = EINVAL;
385 }
386 break;
387 }
388
389 /*
390 * Check ROM type.
391 */
392 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4);
393 tmp = le32toh(tmp);
394 if (tmp != 0x00000001) { /* 1 == STI ROM */
395 gftfb_disable_rom_internal(spc);
396 if (offs == 0) {
397 aprint_error_dev(sc->sc_dev,
398 "invalid PCI ROM type (%08x)\n", tmp);
399 rc = EINVAL;
400 }
401 break;
402 }
403
404 subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
405 offs + 0x0c);
406 subsize <<= 9;
407
408 #ifdef STIDEBUG
409 gftfb_disable_rom_internal(spc);
410 DPRINTF(("ROM offset %08x size %08x type %08x",
411 (u_int)offs, (u_int)subsize, tmp));
412 gftfb_enable_rom_internal(spc);
413 #endif
414
415 /*
416 * Check for a valid ROM data structure.
417 * We do not need it except to know what architecture the ROM
418 * code is for.
419 */
420
421 suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
422 offs + 0x18);
423 tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0);
424 tmp = le32toh(tmp);
425 if (tmp != 0x50434952) { /* PCIR */
426 gftfb_disable_rom_internal(spc);
427 if (offs == 0) {
428 aprint_error_dev(sc->sc_dev, "invalid PCI data"
429 " signature (%08x)\n", tmp);
430 rc = EINVAL;
431 } else {
432 DPRINTF((" invalid PCI data signature %08x\n",
433 tmp));
434 continue;
435 }
436 }
437
438 tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14);
439 gftfb_disable_rom_internal(spc);
440 DPRINTF((" code %02x", tmp));
441
442 switch (tmp) {
443 #ifdef __hppa__
444 case 0x10:
445 if (selected == (bus_addr_t)-1)
446 selected = offs;
447 break;
448 #endif
449 #ifdef __i386__
450 case 0x00:
451 if (selected == (bus_addr_t)-1)
452 selected = offs;
453 break;
454 #endif
455 default:
456 #ifdef STIDEBUG
457 DPRINTF((" (wrong architecture)"));
458 #endif
459 break;
460 }
461 DPRINTF(("%s\n", selected == offs ? " -> SELECTED" : ""));
462 }
463
464 if (selected == (bus_addr_t)-1) {
465 if (rc == 0) {
466 aprint_error_dev(sc->sc_dev, "found no ROM with "
467 "correct microcode architecture\n");
468 rc = ENOEXEC;
469 }
470 goto fail;
471 }
472
473 /*
474 * Read the STI region BAR assignments.
475 */
476
477 gftfb_enable_rom_internal(spc);
478 offs = selected +
479 (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e);
480 for (i = 0; i < STI_REGION_MAX; i++) {
481 rc = gftfb_readbar(sc, pa, i,
482 bus_space_read_1(pa->pa_memt, romh, offs + i));
483 if (rc != 0)
484 goto fail;
485 }
486
487 /*
488 * Find out where the STI ROM itself lies, and its size.
489 */
490
491 offs = selected +
492 (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08);
493 stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh,
494 offs + 0x18);
495 stiromsize = le32toh(stiromsize);
496 gftfb_disable_rom_internal(spc);
497
498 /*
499 * Replace our mapping with a smaller mapping of only the area
500 * we are interested in.
501 */
502
503 DPRINTF(("remapping rom @ %lx for %lx\n",
504 (long)(PCI_MAPREG_ROM_ADDR(address) + offs), (long)stiromsize));
505 bus_space_unmap(pa->pa_memt, romh, romsize);
506 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address) + offs,
507 stiromsize, 0, &spc->sc_romh);
508 if (rc != 0) {
509 aprint_error_dev(sc->sc_dev, "can't map STI ROM (%d)\n",
510 rc);
511 goto fail2;
512 }
513 gftfb_disable_rom_internal(spc);
514 sc->sc_flags &= ~STI_ROM_ENABLED;
515
516 return 0;
517
518 fail:
519 bus_space_unmap(pa->pa_memt, romh, romsize);
520 fail2:
521 gftfb_disable_rom_internal(spc);
522
523 return rc;
524 }
525
526 /*
527 * Decode a BAR register.
528 */
529 int
530 gftfb_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region,
531 int bar)
532 {
533 bus_addr_t addr;
534 bus_size_t size;
535 uint32_t cf;
536 int rc;
537
538 if (bar == 0) {
539 sc->bases[region] = 0;
540 return (0);
541 }
542
543 #ifdef DIAGNOSTIC
544 if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) {
545 gftfb_disable_rom(sc);
546 printf("%s: unexpected bar %02x for region %d\n",
547 device_xname(sc->sc_dev), bar, region);
548 gftfb_enable_rom(sc);
549 }
550 #endif
551
552 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
553
554 rc = pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, PCI_MAPREG_TYPE(cf),
555 &addr, &size, NULL);
556
557 if (rc != 0) {
558 gftfb_disable_rom(sc);
559 aprint_error_dev(sc->sc_dev, "invalid bar %02x for region %d\n",
560 bar, region);
561 gftfb_enable_rom(sc);
562 return (rc);
563 }
564
565 sc->bases[region] = addr;
566 return (0);
567 }
568
569 /*
570 * Enable PCI ROM.
571 */
572 void
573 gftfb_enable_rom_internal(struct gftfb_softc *spc)
574 {
575 pcireg_t address;
576
577 KASSERT(spc != NULL);
578
579 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM);
580 address |= PCI_MAPREG_ROM_ENABLE;
581 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address);
582 }
583
584 void
585 gftfb_enable_rom(struct sti_softc *sc)
586 {
587 struct gftfb_softc *spc = device_private(sc->sc_dev);
588
589 if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
590 gftfb_enable_rom_internal(spc);
591 }
592 SET(sc->sc_flags, STI_ROM_ENABLED);
593 }
594
595 /*
596 * Disable PCI ROM.
597 */
598 void
599 gftfb_disable_rom_internal(struct gftfb_softc *spc)
600 {
601 pcireg_t address;
602
603 KASSERT(spc != NULL);
604
605 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM);
606 address &= ~PCI_MAPREG_ROM_ENABLE;
607 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_MAPREG_ROM, address);
608 }
609
610 void
611 gftfb_disable_rom(struct sti_softc *sc)
612 {
613 struct gftfb_softc *spc = device_private(sc->sc_dev);
614
615 if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
616 gftfb_disable_rom_internal(spc);
617 }
618 CLR(sc->sc_flags, STI_ROM_ENABLED);
619 }
620
621 static inline void
622 gftfb_wait(struct gftfb_softc *sc)
623 {
624 struct sti_rom *rom = sc->sc_base.sc_rom;
625 bus_space_tag_t memt = rom->memt;
626 bus_space_handle_t memh = rom->regh[2];
627 uint8_t stat;
628
629 do {
630 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
631 if (stat == 0)
632 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
633 } while (stat != 0);
634 }
635
636 static inline void
637 gftfb_setup_fb(struct gftfb_softc *sc)
638 {
639 struct sti_rom *rom = sc->sc_base.sc_rom;
640 bus_space_tag_t memt = rom->memt;
641 bus_space_handle_t memh = rom->regh[2];
642
643 gftfb_wait(sc);
644 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0x13601000);
645 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x83000300);
646 gftfb_wait(sc);
647 bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
648 }
649
650 void
651 gftfb_setup(struct gftfb_softc *sc)
652 {
653 struct sti_rom *rom = sc->sc_base.sc_rom;
654 bus_space_tag_t memt = rom->memt;
655 bus_space_handle_t memh = rom->regh[2];
656
657 sc->sc_reg10 = 0;
658
659 /* set Bt458 read mask register to all planes */
660 gftfb_wait(sc);
661 ngle_bt458_write(memt, memh, 0x08, 0x04);
662 ngle_bt458_write(memt, memh, 0x0a, 0xff);
663
664 gftfb_setup_fb(sc);
665
666 /* attr. planes */
667 gftfb_wait(sc);
668 bus_space_write_stream_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
669 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x23000302);
670 bus_space_write_stream_4(memt, memh, NGLE_REG_12, NGLE_ARTIST_CMAP0);
671 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
672
673 gftfb_wait(sc);
674 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x00000000);
675 bus_space_write_stream_4(memt, memh, NGLE_REG_9,
676 (sc->sc_scr.scr_cfg.scr_width << 16) | sc->sc_scr.scr_cfg.scr_height);
677 bus_space_write_stream_4(memt, memh, NGLE_REG_6, 0x05000000);
678 bus_space_write_stream_4(memt, memh, NGLE_REG_9, 0x00040001);
679
680 gftfb_wait(sc);
681 bus_space_write_stream_4(memt, memh, NGLE_REG_12, 0x00000000);
682
683 gftfb_setup_fb(sc);
684
685 gftfb_wait(sc);
686 bus_space_write_stream_4(memt, memh, NGLE_REG_21,
687 bus_space_read_stream_4(memt, memh, NGLE_REG_21) | 0x0a000000);
688 bus_space_write_stream_4(memt, memh, NGLE_REG_27,
689 bus_space_read_stream_4(memt, memh, NGLE_REG_27) | 0x00800000);
690 }
691
692 static int
693 gftfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
694 struct lwp *l)
695 {
696 struct vcons_data *vd = v;
697 struct gftfb_softc *sc = vd->cookie;
698 struct wsdisplay_fbinfo *wdf;
699 struct vcons_screen *ms = vd->active;
700
701 switch (cmd) {
702 case WSDISPLAYIO_GTYPE:
703 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
704 return 0;
705
706 /* PCI config read/write passthrough. */
707 case PCI_IOC_CFGREAD:
708 case PCI_IOC_CFGWRITE:
709 return pci_devioctl(sc->sc_pc, sc->sc_tag,
710 cmd, data, flag, l);
711
712 case WSDISPLAYIO_GET_BUSID:
713 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
714 sc->sc_tag, data);
715
716 case WSDISPLAYIO_GINFO:
717 if (ms == NULL)
718 return ENODEV;
719 wdf = (void *)data;
720 wdf->height = ms->scr_ri.ri_height;
721 wdf->width = ms->scr_ri.ri_width;
722 wdf->depth = ms->scr_ri.ri_depth;
723 wdf->cmsize = 256;
724 return 0;
725
726 case WSDISPLAYIO_GETCMAP:
727 return gftfb_getcmap(sc,
728 (struct wsdisplay_cmap *)data);
729
730 case WSDISPLAYIO_PUTCMAP:
731 return gftfb_putcmap(sc,
732 (struct wsdisplay_cmap *)data);
733
734 case WSDISPLAYIO_LINEBYTES:
735 *(u_int *)data = 2048;
736 return 0;
737
738 case WSDISPLAYIO_SMODE: {
739 int new_mode = *(int*)data;
740 if (new_mode != sc->sc_mode) {
741 sc->sc_mode = new_mode;
742 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
743 gftfb_setup(sc);
744 if (0) gftfb_restore_palette(sc);
745 glyphcache_wipe(&sc->sc_gc);
746 gftfb_rectfill(sc, 0, 0, sc->sc_width,
747 sc->sc_height, ms->scr_ri.ri_devcmap[
748 (ms->scr_defattr >> 16) & 0xff]);
749 vcons_redraw_screen(ms);
750 }
751 }
752 }
753 return 0;
754
755 case WSDISPLAYIO_GET_FBINFO:
756 {
757 struct wsdisplayio_fbinfo *fbi = data;
758
759 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
760 }
761 }
762 return EPASSTHROUGH;
763 }
764
765 static paddr_t
766 gftfb_mmap(void *v, void *vs, off_t offset, int prot)
767 {
768 struct vcons_data *vd = v;
769 struct gftfb_softc *sc = vd->cookie;
770 struct sti_rom *rom = sc->sc_base.sc_rom;
771 paddr_t pa;
772
773 if (offset < 0 || offset >= sc->sc_scr.fblen)
774 return -1;
775
776 if (sc->sc_mode != WSDISPLAYIO_MODE_DUMBFB)
777 return -1;
778
779 pa = bus_space_mmap(rom->memt, sc->sc_scr.fbaddr, offset, prot,
780 BUS_SPACE_MAP_LINEAR);
781 return pa;
782 }
783
784 static void
785 gftfb_init_screen(void *cookie, struct vcons_screen *scr,
786 int existing, long *defattr)
787 {
788 struct gftfb_softc *sc = cookie;
789 struct rasops_info *ri = &scr->scr_ri;
790
791 ri->ri_depth = 8;
792 ri->ri_width = sc->sc_width;
793 ri->ri_height = sc->sc_height;
794 ri->ri_stride = 2048;
795 ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB |
796 RI_ENABLE_ALPHA | RI_PREFER_ALPHA;
797
798 ri->ri_bits = (void *)sc->sc_scr.fbaddr;
799 rasops_init(ri, 0, 0);
800 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
801 WSSCREEN_RESIZE;
802 scr->scr_flags |= VCONS_LOADFONT;
803
804 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
805 sc->sc_width / ri->ri_font->fontwidth);
806
807 ri->ri_hw = scr;
808 sc->sc_putchar = ri->ri_ops.putchar;
809 ri->ri_ops.copyrows = gftfb_copyrows;
810 ri->ri_ops.copycols = gftfb_copycols;
811 ri->ri_ops.eraserows = gftfb_eraserows;
812 ri->ri_ops.erasecols = gftfb_erasecols;
813 ri->ri_ops.cursor = gftfb_cursor;
814 ri->ri_ops.putchar = gftfb_putchar;
815 }
816
817 static int
818 gftfb_putcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm)
819 {
820 u_char *r, *g, *b;
821 u_int index = cm->index;
822 u_int count = cm->count;
823 int i, error;
824 u_char rbuf[256], gbuf[256], bbuf[256];
825
826 if (cm->index >= 256 || cm->count > 256 ||
827 (cm->index + cm->count) > 256)
828 return EINVAL;
829 error = copyin(cm->red, &rbuf[index], count);
830 if (error)
831 return error;
832 error = copyin(cm->green, &gbuf[index], count);
833 if (error)
834 return error;
835 error = copyin(cm->blue, &bbuf[index], count);
836 if (error)
837 return error;
838
839 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
840 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
841 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
842
843 r = &sc->sc_cmap_red[index];
844 g = &sc->sc_cmap_green[index];
845 b = &sc->sc_cmap_blue[index];
846
847 for (i = 0; i < count; i++) {
848 gftfb_putpalreg(sc, index, *r, *g, *b);
849 index++;
850 r++, g++, b++;
851 }
852 return 0;
853 }
854
855 static int
856 gftfb_getcmap(struct gftfb_softc *sc, struct wsdisplay_cmap *cm)
857 {
858 u_int index = cm->index;
859 u_int count = cm->count;
860 int error;
861
862 if (index >= 255 || count > 256 || index + count > 256)
863 return EINVAL;
864
865 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
866 if (error)
867 return error;
868 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
869 if (error)
870 return error;
871 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
872 if (error)
873 return error;
874
875 return 0;
876 }
877
878 static void
879 gftfb_restore_palette(struct gftfb_softc *sc)
880 {
881 int i;
882
883 for (i = 0; i < 256; i++) {
884 gftfb_putpalreg(sc, i, sc->sc_cmap_red[i],
885 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
886 }
887 }
888
889 static int
890 gftfb_putpalreg(struct gftfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
891 uint8_t b)
892 {
893 struct sti_rom *rom = sc->sc_base.sc_rom;
894 bus_space_tag_t memt = rom->memt;
895 bus_space_handle_t memh = rom->regh[2];
896
897 gftfb_wait(sc);
898 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
899 bus_space_write_stream_4(memt, memh, NGLE_REG_14, 0x03000300);
900 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xffffffff);
901
902 gftfb_wait(sc);
903 bus_space_write_stream_4(memt, memh, NGLE_REG_3,
904 0x400 | (idx << 2));
905 bus_space_write_stream_4(memt, memh, NGLE_REG_4,
906 (r << 16) | (g << 8) | b);
907
908 bus_space_write_stream_4(memt, memh, NGLE_REG_2, 0x400);
909 bus_space_write_stream_4(memt, memh, NGLE_REG_26, 0x80000100);
910 gftfb_setup_fb(sc);
911 return 0;
912 }
913
914 static inline void
915 gftfb_wait_fifo(struct gftfb_softc *sc, uint32_t slots)
916 {
917 struct sti_rom *rom = sc->sc_base.sc_rom;
918 bus_space_tag_t memt = rom->memt;
919 bus_space_handle_t memh = rom->regh[2];
920 uint32_t reg;
921
922 do {
923 reg = bus_space_read_stream_4(memt, memh, NGLE_REG_34);
924 } while (reg < slots);
925 }
926
927 static void
928 gftfb_rectfill(struct gftfb_softc *sc, int x, int y, int wi, int he,
929 uint32_t bg)
930 {
931 struct sti_rom *rom = sc->sc_base.sc_rom;
932 bus_space_tag_t memt = rom->memt;
933 bus_space_handle_t memh = rom->regh[2];
934
935 gftfb_wait_fifo(sc, 5);
936 /* transfer data */
937 bus_space_write_stream_4(memt, memh, NGLE_REG_8, 0xffffffff);
938 bus_space_write_stream_4(memt, memh, NGLE_REG_35, bg);
939 /* plane mask */
940 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xff);
941 /* bitmap op */
942 bus_space_write_stream_4(memt, memh, NGLE_REG_14,
943 IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0));
944 /* dst bitmap access */
945 bus_space_write_stream_4(memt, memh, NGLE_REG_11,
946 BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0I, 0));
947 gftfb_wait_fifo(sc, 2);
948 /* dst XY */
949 bus_space_write_stream_4(memt, memh, NGLE_REG_6, (x << 16) | y);
950 /* len XY start */
951 bus_space_write_stream_4(memt, memh, NGLE_REG_9, (wi << 16) | he);
952
953 }
954
955
956 static void
957 gftfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi,
958 int he, int rop)
959 {
960 struct gftfb_softc *sc = cookie;
961 struct sti_rom *rom = sc->sc_base.sc_rom;
962 bus_space_tag_t memt = rom->memt;
963 bus_space_handle_t memh = rom->regh[2];
964
965 gftfb_wait(sc);
966 bus_space_write_stream_4(memt, memh, NGLE_REG_10, 0x13a01000);
967 gftfb_wait_fifo(sc, 5);
968 bus_space_write_stream_4(memt, memh, NGLE_REG_14, ((rop << 8) & 0xf00) | 0x23000000);
969 bus_space_write_stream_4(memt, memh, NGLE_REG_13, 0xff);
970 bus_space_write_stream_4(memt, memh, NGLE_REG_24, (xs << 16) | ys);
971 bus_space_write_stream_4(memt, memh, NGLE_REG_7, (wi << 16) | he);
972 bus_space_write_stream_4(memt, memh, NGLE_REG_25, (xd << 16) | yd);
973 }
974
975 static void
976 gftfb_cursor(void *cookie, int on, int row, int col)
977 {
978 struct rasops_info *ri = cookie;
979 struct vcons_screen *scr = ri->ri_hw;
980 struct gftfb_softc *sc = scr->scr_cookie;
981 int x, y, wi, he;
982
983 wi = ri->ri_font->fontwidth;
984 he = ri->ri_font->fontheight;
985
986 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
987 if (ri->ri_flg & RI_CURSOR) {
988 x = ri->ri_ccol * wi + ri->ri_xorigin;
989 y = ri->ri_crow * he + ri->ri_yorigin;
990 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
991 ri->ri_flg &= ~RI_CURSOR;
992 }
993 ri->ri_crow = row;
994 ri->ri_ccol = col;
995 if (on) {
996 x = ri->ri_ccol * wi + ri->ri_xorigin;
997 y = ri->ri_crow * he + ri->ri_yorigin;
998 gftfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
999 ri->ri_flg |= RI_CURSOR;
1000 }
1001 } else {
1002 scr->scr_ri.ri_crow = row;
1003 scr->scr_ri.ri_ccol = col;
1004 scr->scr_ri.ri_flg &= ~RI_CURSOR;
1005 }
1006
1007 }
1008
1009 static void
1010 gftfb_putchar(void *cookie, int row, int col, u_int c, long attr)
1011 {
1012 struct rasops_info *ri = cookie;
1013 struct wsdisplay_font *font = PICK_FONT(ri, c);
1014 struct vcons_screen *scr = ri->ri_hw;
1015 struct gftfb_softc *sc = scr->scr_cookie;
1016 int x, y, wi, he, rv = GC_NOPE;
1017 #if 0
1018 uint32_t bg;
1019 #endif
1020 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1021 return;
1022
1023 if (!CHAR_IN_FONT(c, font))
1024 return;
1025
1026 wi = font->fontwidth;
1027 he = font->fontheight;
1028
1029 x = ri->ri_xorigin + col * wi;
1030 y = ri->ri_yorigin + row * he;
1031 #if 0
1032 bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1033
1034 /* XXX
1035 * rectfill currently draws rectangles less than 32 pixels wide as
1036 * 32 pixels wide, no idea why. So until I figure that one out we
1037 * draw blanks by software
1038 * bitblt doesn't seem to have this problem
1039 */
1040 if (c == 0x20) {
1041 gftfb_rectfill(sc, x, y, wi, he, bg);
1042 return;
1043 }
1044 #endif
1045 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1046 if (rv == GC_OK)
1047 return;
1048
1049 gftfb_setup_fb(sc);
1050 sc->sc_putchar(cookie, row, col, c, attr);
1051
1052 if (rv == GC_ADD)
1053 glyphcache_add(&sc->sc_gc, c, x, y);
1054 }
1055
1056 static void
1057 gftfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1058 {
1059 struct rasops_info *ri = cookie;
1060 struct vcons_screen *scr = ri->ri_hw;
1061 struct gftfb_softc *sc = scr->scr_cookie;
1062 int32_t xs, xd, y, width, height;
1063
1064 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1065 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1066 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1067 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1068 width = ri->ri_font->fontwidth * ncols;
1069 height = ri->ri_font->fontheight;
1070 gftfb_bitblt(sc, xs, y, xd, y, width, height, RopSrc);
1071 }
1072 }
1073
1074 static void
1075 gftfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1076 {
1077 struct rasops_info *ri = cookie;
1078 struct vcons_screen *scr = ri->ri_hw;
1079 struct gftfb_softc *sc = scr->scr_cookie;
1080 int32_t x, y, width, height, fg, bg, ul;
1081
1082 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1083 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1084 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1085 width = ri->ri_font->fontwidth * ncols;
1086 height = ri->ri_font->fontheight;
1087 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1088
1089 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1090 }
1091 }
1092
1093 static void
1094 gftfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1095 {
1096 struct rasops_info *ri = cookie;
1097 struct vcons_screen *scr = ri->ri_hw;
1098 struct gftfb_softc *sc = scr->scr_cookie;
1099 int32_t x, ys, yd, width, height;
1100
1101 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1102 x = ri->ri_xorigin;
1103 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1104 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1105 width = ri->ri_emuwidth;
1106 height = ri->ri_font->fontheight * nrows;
1107 gftfb_bitblt(sc, x, ys, x, yd, width, height, RopSrc);
1108 }
1109 }
1110
1111 static void
1112 gftfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1113 {
1114 struct rasops_info *ri = cookie;
1115 struct vcons_screen *scr = ri->ri_hw;
1116 struct gftfb_softc *sc = scr->scr_cookie;
1117 int32_t x, y, width, height, fg, bg, ul;
1118
1119 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1120 x = ri->ri_xorigin;
1121 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1122 width = ri->ri_emuwidth;
1123 height = ri->ri_font->fontheight * nrows;
1124 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1125
1126 gftfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1127 }
1128 }
1129