chipsfb.c revision 1.5 1 /* $NetBSD: chipsfb.c,v 1.5 2006/10/27 06:14:17 macallan Exp $ */
2
3 /*
4 * Copyright (c) 2006 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 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * A console driver for Chips & Technologies 65550 graphics controllers
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: chipsfb.c,v 1.5 2006/10/27 06:14:17 macallan Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/callout.h>
43 #include <sys/lwp.h>
44 #include <sys/kauth.h>
45
46 #include <uvm/uvm_extern.h>
47 #include <machine/autoconf.h>
48
49 #if defined(macppc) || defined (sparc64) || defined(ofppc)
50 #define HAVE_OPENFIRMWARE
51 #endif
52
53 #ifdef HAVE_OPENFIRMWARE
54 #include <dev/ofw/openfirm.h>
55 #include <dev/ofw/ofw_pci.h>
56 #endif
57
58 #include <dev/videomode/videomode.h>
59
60 #include <dev/pci/pcivar.h>
61 #include <dev/pci/pcireg.h>
62 #include <dev/pci/pcidevs.h>
63 #include <dev/pci/pciio.h>
64 #include <dev/pci/chipsfbreg.h>
65
66 #include <dev/wscons/wsdisplayvar.h>
67 #include <dev/wscons/wsconsio.h>
68 #include <dev/wsfont/wsfont.h>
69 #include <dev/rasops/rasops.h>
70 #include <dev/wscons/wsdisplay_vconsvar.h>
71
72 #include <dev/i2c/i2cvar.h>
73 #include <dev/i2c/i2c_bitbang.h>
74 #include <dev/i2c/edidvar.h>
75
76 #include "opt_wsemul.h"
77 #include "opt_ofb.h"
78
79 /*
80 #define CHIPSFB_WAIT
81 */
82 struct chipsfb_softc {
83 struct device sc_dev;
84 pci_chipset_tag_t sc_pc;
85 pcitag_t sc_pcitag;
86
87 bus_space_tag_t sc_memt;
88 bus_space_tag_t sc_iot;
89 bus_space_handle_t sc_memh;
90
91 bus_space_tag_t sc_fbt;
92 bus_space_tag_t sc_ioregt;
93 bus_space_handle_t sc_fbh;
94 bus_space_handle_t sc_ioregh;
95 bus_addr_t sc_fb, sc_ioreg;
96 bus_size_t sc_fbsize, sc_ioregsize;
97
98 void *sc_ih;
99
100 size_t memsize;
101
102 int bits_per_pixel;
103 int width, height, linebytes;
104
105 int sc_mode;
106 uint32_t sc_bg;
107
108 u_char sc_cmap_red[256];
109 u_char sc_cmap_green[256];
110 u_char sc_cmap_blue[256];
111 int sc_dacw;
112
113 /* I2C stuff */
114 struct i2c_controller sc_i2c;
115 uint8_t sc_edid[1024];
116 int sc_edidbytes; /* number of bytes read from the monitor */
117
118 struct vcons_data vd;
119 };
120
121 static struct vcons_screen chipsfb_console_screen;
122
123 extern const u_char rasops_cmap[768];
124
125 static int chipsfb_match(struct device *, struct cfdata *, void *);
126 static void chipsfb_attach(struct device *, struct device *, void *);
127
128 CFATTACH_DECL(chipsfb, sizeof(struct chipsfb_softc), chipsfb_match,
129 chipsfb_attach, NULL, NULL);
130
131 static int chipsfb_is_console(struct pci_attach_args *);
132 static void chipsfb_init(struct chipsfb_softc *);
133
134 static void chipsfb_cursor(void *, int, int, int);
135 static void chipsfb_copycols(void *, int, int, int, int);
136 static void chipsfb_erasecols(void *, int, int, int, long);
137 static void chipsfb_copyrows(void *, int, int, int);
138 static void chipsfb_eraserows(void *, int, int, long);
139
140 #if 0
141 static int chipsfb_allocattr(void *, int, int, int, long *);
142 static void chipsfb_scroll(void *, void *, int);
143 static int chipsfb_load_font(void *, void *, struct wsdisplay_font *);
144 #endif
145
146 static int chipsfb_putcmap(struct chipsfb_softc *,
147 struct wsdisplay_cmap *);
148 static int chipsfb_getcmap(struct chipsfb_softc *,
149 struct wsdisplay_cmap *);
150 static int chipsfb_putpalreg(struct chipsfb_softc *, uint8_t, uint8_t,
151 uint8_t, uint8_t);
152
153 static void chipsfb_bitblt(struct chipsfb_softc *, int, int, int, int,
154 int, int, uint8_t);
155 static void chipsfb_rectfill(struct chipsfb_softc *, int, int, int, int,
156 int);
157 static void chipsfb_putchar(void *, int, int, u_int, long);
158 static void chipsfb_setup_mono(struct chipsfb_softc *, int, int, int,
159 int, uint32_t, uint32_t);
160 static void chipsfb_feed(struct chipsfb_softc *, int, uint8_t *);
161
162 #ifdef chipsfb_DEBUG
163 static void chipsfb_showpal(struct chipsfb_softc *);
164 #endif
165 static void chipsfb_restore_palette(struct chipsfb_softc *);
166
167 static void chipsfb_wait_idle(struct chipsfb_softc *);
168
169 static uint32_t chipsfb_probe_vram(struct chipsfb_softc *);
170
171 struct wsscreen_descr chipsfb_defaultscreen = {
172 "default",
173 0, 0,
174 NULL,
175 8, 16,
176 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
177 };
178
179 const struct wsscreen_descr *_chipsfb_scrlist[] = {
180 &chipsfb_defaultscreen,
181 /* XXX other formats, graphics screen? */
182 };
183
184 struct wsscreen_list chipsfb_screenlist = {
185 sizeof(_chipsfb_scrlist) / sizeof(struct wsscreen_descr *), _chipsfb_scrlist
186 };
187
188 static int chipsfb_ioctl(void *, void *, u_long, caddr_t, int,
189 struct lwp *);
190 static paddr_t chipsfb_mmap(void *, void *, off_t, int);
191 static void chipsfb_clearscreen(struct chipsfb_softc *);
192 static void chipsfb_init_screen(void *, struct vcons_screen *, int,
193 long *);
194
195
196 struct wsdisplay_accessops chipsfb_accessops = {
197 chipsfb_ioctl,
198 chipsfb_mmap,
199 NULL, /* load_font */
200 NULL, /* polls */
201 NULL, /* scroll */
202 };
203
204 /*
205 * Inline functions for getting access to register aperture.
206 */
207 static inline void
208 chipsfb_write32(struct chipsfb_softc *sc, uint32_t reg, uint32_t val)
209 {
210 bus_space_write_4(sc->sc_fbt, sc->sc_fbh, reg, val);
211 }
212
213 static inline uint32_t
214 chipsfb_read32(struct chipsfb_softc *sc, uint32_t reg)
215 {
216 return bus_space_read_4(sc->sc_fbt, sc->sc_fbh, reg);
217 }
218
219 static inline void
220 chipsfb_write_vga(struct chipsfb_softc *sc, uint32_t reg, uint8_t val)
221 {
222 bus_space_write_1(sc->sc_iot, sc->sc_ioregh, reg, val);
223 }
224
225 static inline uint8_t
226 chipsfb_read_vga(struct chipsfb_softc *sc, uint32_t reg)
227 {
228 return bus_space_read_1(sc->sc_iot, sc->sc_ioregh, reg);
229 }
230
231 static inline uint8_t
232 chipsfb_read_indexed(struct chipsfb_softc *sc, uint32_t reg, uint8_t index)
233 {
234
235 chipsfb_write_vga(sc, reg & 0xfffe, index);
236 return chipsfb_read_vga(sc, reg | 0x0001);
237 }
238
239 static inline void
240 chipsfb_write_indexed(struct chipsfb_softc *sc, uint32_t reg, uint8_t index,
241 uint8_t val)
242 {
243
244 chipsfb_write_vga(sc, reg & 0xfffe, index);
245 chipsfb_write_vga(sc, reg | 0x0001, val);
246 }
247
248 static void
249 chipsfb_wait_idle(struct chipsfb_softc *sc)
250 {
251
252 #ifdef CHIPSFB_DEBUG
253 chipsfb_write32(sc, CT_OFF_FB + (800 * 598) - 4, 0);
254 #endif
255
256 /* spin until the blitter is idle */
257 while ((chipsfb_read32(sc, CT_BLT_CONTROL) & BLT_IS_BUSY) != 0) {
258 }
259
260 #ifdef CHIPSFB_DEBUG
261 chipsfb_write32(sc, CT_OFF_FB + (800 * 598) - 4, 0xffffffff);
262 #endif
263 }
264
265 static int
266 chipsfb_match(struct device *parent, struct cfdata *match, void *aux)
267 {
268 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
269
270 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
271 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
272 return 0;
273 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CHIPS) &&
274 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CHIPS_65550))
275 return 100;
276 return 0;
277 }
278
279 static void
280 chipsfb_attach(struct device *parent, struct device *self, void *aux)
281 {
282 struct chipsfb_softc *sc = (void *)self;
283 struct pci_attach_args *pa = aux;
284 char devinfo[256];
285 struct wsemuldisplaydev_attach_args aa;
286 struct rasops_info *ri;
287 pcireg_t screg;
288 ulong defattr;
289 int console, width, height, node, i, j;
290 #ifdef HAVE_OPENFIRMWARE
291 int linebytes, depth;
292 #endif
293 uint32_t bg, fg, ul;
294
295 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
296 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
297 sc->sc_pc = pa->pa_pc;
298 sc->sc_pcitag = pa->pa_tag;
299 sc->sc_dacw = -1;
300
301 screg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PCI_COMMAND_STATUS_REG);
302 screg |= PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
303 pci_conf_write(sc->sc_pc, sc->sc_pcitag,PCI_COMMAND_STATUS_REG,screg);
304
305 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
306 printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
307
308 sc->sc_memt = pa->pa_memt;
309 sc->sc_iot = pa->pa_iot;
310
311 /* the framebuffer */
312 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM,
313 BUS_SPACE_MAP_LINEAR,
314 &sc->sc_fbt, &sc->sc_fbh, &sc->sc_fb, &sc->sc_fbsize)) {
315 printf("%s: failed to map the frame buffer.\n",
316 sc->sc_dev.dv_xname);
317 }
318
319 /* IO-mapped registers */
320 if (bus_space_map(sc->sc_iot, 0x0, PAGE_SIZE, 0, &sc->sc_ioregh) != 0) {
321 printf("%s: failed to map IO-mapped registers.\n",
322 sc->sc_dev.dv_xname);
323 }
324
325 sc->memsize = chipsfb_probe_vram(sc);
326 chipsfb_init(sc);
327
328 /* we should read these from the chip instead of depending on OF */
329 width = height = -1;
330
331 /* detect panel size */
332 width = chipsfb_read_indexed(sc, CT_FP_INDEX, FP_HSIZE_LSB);
333 width |= (chipsfb_read_indexed(sc, CT_FP_INDEX, FP_HORZ_OVERFLOW_1)
334 & 0x0f) << 8;
335 width = (width + 1) * 8;
336 height = chipsfb_read_indexed(sc, CT_FP_INDEX, FP_VSIZE_LSB);
337 height |= (chipsfb_read_indexed(sc, CT_FP_INDEX, FP_VERT_OVERFLOW_1)
338 & 0x0f) << 8;
339 height++;
340 printf("Panel size: %d x %d\n", width, height);
341
342 #ifdef HAVE_OPENFIRMWARE
343 if (OF_getprop(node, "width", &width, 4) != 4)
344 OF_interpret("screen-width", 1, &width);
345 if (OF_getprop(node, "height", &height, 4) != 4)
346 OF_interpret("screen-height", 1, &height);
347 if (OF_getprop(node, "linebytes", &linebytes, 4) != 4)
348 linebytes = width; /* XXX */
349 if (OF_getprop(node, "depth", &depth, 4) != 4)
350 depth = 8; /* XXX */
351
352 if (width == -1 || height == -1)
353 return;
354
355 sc->width = width;
356 sc->height = height;
357 sc->bits_per_pixel = depth;
358 sc->linebytes = linebytes;
359 printf("%s: initial resolution %dx%d, %d bit\n", sc->sc_dev.dv_xname,
360 sc->width, sc->height, sc->bits_per_pixel);
361 #endif
362
363 #ifdef notyet
364 /* XXX this should at least be configurable via kernel config */
365 chipsfb_set_videomode(sc, &videomode_list[16]);
366 #endif
367
368 vcons_init(&sc->vd, sc, &chipsfb_defaultscreen, &chipsfb_accessops);
369 sc->vd.init_screen = chipsfb_init_screen;
370
371 console = chipsfb_is_console(pa);
372
373 ri = &chipsfb_console_screen.scr_ri;
374 if (console) {
375 vcons_init_screen(&sc->vd, &chipsfb_console_screen, 1,
376 &defattr);
377 chipsfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
378
379 chipsfb_defaultscreen.textops = &ri->ri_ops;
380 chipsfb_defaultscreen.capabilities = ri->ri_caps;
381 chipsfb_defaultscreen.nrows = ri->ri_rows;
382 chipsfb_defaultscreen.ncols = ri->ri_cols;
383 wsdisplay_cnattach(&chipsfb_defaultscreen, ri, 0, 0, defattr);
384 } else {
385 /*
386 * since we're not the console we can postpone the rest
387 * until someone actually allocates a screen for us
388 */
389 #ifdef notyet
390 chipsfb_set_videomode(sc, &videomode_list[0]);
391 #endif
392 }
393
394 rasops_unpack_attr(defattr, &fg, &bg, &ul);
395 sc->sc_bg = ri->ri_devcmap[bg];
396 chipsfb_clearscreen(sc);
397
398 printf("%s: %d MB aperture, %d MB VRAM at 0x%08x\n",
399 sc->sc_dev.dv_xname, (u_int)(sc->sc_fbsize >> 20),
400 sc->memsize >> 20, (u_int)sc->sc_fb);
401 #ifdef chipsfb_DEBUG
402 printf("fb: %08lx\n", (ulong)ri->ri_bits);
403 #endif
404
405 j = 0;
406 for (i = 0; i < 256; i++) {
407 chipsfb_putpalreg(sc, i, rasops_cmap[j], rasops_cmap[j + 1],
408 rasops_cmap[j + 2]);
409 j += 3;
410 }
411
412 aa.console = console;
413 aa.scrdata = &chipsfb_screenlist;
414 aa.accessops = &chipsfb_accessops;
415 aa.accesscookie = &sc->vd;
416
417 config_found(self, &aa, wsemuldisplaydevprint);
418 }
419
420 static int
421 chipsfb_putpalreg(struct chipsfb_softc *sc, uint8_t index, uint8_t r,
422 uint8_t g, uint8_t b)
423 {
424
425 sc->sc_cmap_red[index] = r;
426 sc->sc_cmap_green[index] = g;
427 sc->sc_cmap_blue[index] = b;
428
429 chipsfb_write_vga(sc, CT_DACMASK, 0xff);
430 chipsfb_write_vga(sc, CT_WRITEINDEX, index);
431 chipsfb_write_vga(sc, CT_DACDATA, r);
432 chipsfb_write_vga(sc, CT_DACDATA, g);
433 chipsfb_write_vga(sc, CT_DACDATA, b);
434
435 return 0;
436 }
437
438 static int
439 chipsfb_putcmap(struct chipsfb_softc *sc, struct wsdisplay_cmap *cm)
440 {
441 u_char *r, *g, *b;
442 u_int index = cm->index;
443 u_int count = cm->count;
444 int i, error;
445 u_char rbuf[256], gbuf[256], bbuf[256];
446
447 #ifdef chipsfb_DEBUG
448 printf("putcmap: %d %d\n",index, count);
449 #endif
450 if (cm->index >= 256 || cm->count > 256 ||
451 (cm->index + cm->count) > 256)
452 return EINVAL;
453 error = copyin(cm->red, &rbuf[index], count);
454 if (error)
455 return error;
456 error = copyin(cm->green, &gbuf[index], count);
457 if (error)
458 return error;
459 error = copyin(cm->blue, &bbuf[index], count);
460 if (error)
461 return error;
462
463 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
464 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
465 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
466
467 r = &sc->sc_cmap_red[index];
468 g = &sc->sc_cmap_green[index];
469 b = &sc->sc_cmap_blue[index];
470
471 for (i = 0; i < count; i++) {
472 chipsfb_putpalreg(sc, index, *r, *g, *b);
473 index++;
474 r++, g++, b++;
475 }
476 return 0;
477 }
478
479 static int
480 chipsfb_getcmap(struct chipsfb_softc *sc, struct wsdisplay_cmap *cm)
481 {
482 u_int index = cm->index;
483 u_int count = cm->count;
484 int error;
485
486 if (index >= 255 || count > 256 || index + count > 256)
487 return EINVAL;
488
489 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
490 if (error)
491 return error;
492 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
493 if (error)
494 return error;
495 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
496 if (error)
497 return error;
498
499 return 0;
500 }
501
502 static int
503 chipsfb_is_console(struct pci_attach_args *pa)
504 {
505
506 #ifdef HAVE_OPENFIRMWARE
507 /* check if we're the /chosen console device */
508 int chosen, stdout, node, us;
509
510 us = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
511 chosen = OF_finddevice("/chosen");
512 OF_getprop(chosen, "stdout", &stdout, 4);
513 node = OF_instance_to_package(stdout);
514 return(us == node);
515 #else
516 /* XXX how do we know we're console on i386? */
517 return 1;
518 #endif
519 }
520
521 static void
522 chipsfb_clearscreen(struct chipsfb_softc *sc)
523 {
524 chipsfb_rectfill(sc, 0, 0, sc->width, sc->height, sc->sc_bg);
525 }
526
527 /*
528 * wsdisplay_emulops
529 */
530
531 static void
532 chipsfb_cursor(void *cookie, int on, int row, int col)
533 {
534 struct rasops_info *ri = cookie;
535 struct vcons_screen *scr = ri->ri_hw;
536 struct chipsfb_softc *sc = scr->scr_cookie;
537 int x, y, wi, he;
538
539 wi = ri->ri_font->fontwidth;
540 he = ri->ri_font->fontheight;
541
542 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
543 x = ri->ri_ccol * wi + ri->ri_xorigin;
544 y = ri->ri_crow * he + ri->ri_yorigin;
545 if (ri->ri_flg & RI_CURSOR) {
546 chipsfb_bitblt(sc, x, y, x, y, wi, he, ROP_NOT_DST);
547 ri->ri_flg &= ~RI_CURSOR;
548 }
549 ri->ri_crow = row;
550 ri->ri_ccol = col;
551 if (on) {
552 x = ri->ri_ccol * wi + ri->ri_xorigin;
553 y = ri->ri_crow * he + ri->ri_yorigin;
554 chipsfb_bitblt(sc, x, y, x, y, wi, he, ROP_NOT_DST);
555 ri->ri_flg |= RI_CURSOR;
556 }
557 } else {
558 ri->ri_flg &= ~RI_CURSOR;
559 ri->ri_crow = row;
560 ri->ri_ccol = col;
561 }
562 }
563
564 #if 0
565 int
566 chipsfb_mapchar(void *cookie, int uni, u_int *index)
567 {
568 return 0;
569 }
570 #endif
571
572 static void
573 chipsfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
574 {
575 struct rasops_info *ri = cookie;
576 struct vcons_screen *scr = ri->ri_hw;
577 struct chipsfb_softc *sc = scr->scr_cookie;
578 int32_t xs, xd, y, width, height;
579
580 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
581 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
582 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
583 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
584 width = ri->ri_font->fontwidth * ncols;
585 height = ri->ri_font->fontheight;
586 chipsfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY);
587 }
588 }
589
590 static void
591 chipsfb_erasecols(void *cookie, int row, int startcol, int ncols,
592 long fillattr)
593 {
594 struct rasops_info *ri = cookie;
595 struct vcons_screen *scr = ri->ri_hw;
596 struct chipsfb_softc *sc = scr->scr_cookie;
597 int32_t x, y, width, height, fg, bg, ul;
598
599 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
600 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
601 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
602 width = ri->ri_font->fontwidth * ncols;
603 height = ri->ri_font->fontheight;
604 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
605
606 chipsfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
607 }
608 }
609
610 static void
611 chipsfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
612 {
613 struct rasops_info *ri = cookie;
614 struct vcons_screen *scr = ri->ri_hw;
615 struct chipsfb_softc *sc = scr->scr_cookie;
616 int32_t x, ys, yd, width, height;
617
618 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
619 x = ri->ri_xorigin;
620 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
621 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
622 width = ri->ri_emuwidth;
623 height = ri->ri_font->fontheight * nrows;
624 chipsfb_bitblt(sc, x, ys, x, yd, width, height, ROP_COPY);
625 }
626 }
627
628 static void
629 chipsfb_eraserows(void *cookie, int row, int nrows, long fillattr)
630 {
631 struct rasops_info *ri = cookie;
632 struct vcons_screen *scr = ri->ri_hw;
633 struct chipsfb_softc *sc = scr->scr_cookie;
634 int32_t x, y, width, height, fg, bg, ul;
635
636 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
637 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
638 if ((row == 0) && (nrows == ri->ri_rows)) {
639 /* clear the whole screen */
640 chipsfb_rectfill(sc, 0, 0, ri->ri_width,
641 ri->ri_height, ri->ri_devcmap[bg]);
642 } else {
643 x = ri->ri_xorigin;
644 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
645 width = ri->ri_emuwidth;
646 height = ri->ri_font->fontheight * nrows;
647 chipsfb_rectfill(sc, x, y, width, height,
648 ri->ri_devcmap[bg]);
649 }
650 }
651 }
652
653 static void
654 chipsfb_bitblt(struct chipsfb_softc *sc, int xs, int ys, int xd, int yd,
655 int width, int height, uint8_t rop)
656 {
657 uint32_t src, dst, cmd = rop, stride, size;
658
659 cmd |= BLT_PAT_IS_SOLID;
660
661 /* we assume 8 bit for now */
662 src = xs + ys * sc->linebytes;
663 dst = xd + yd * sc->linebytes;
664
665 if (xs < xd) {
666 /* right-to-left operation */
667 cmd |= BLT_START_RIGHT;
668 src += width - 1;
669 dst += width - 1;
670 }
671
672 if (ys < yd) {
673 /* bottom-to-top operation */
674 cmd |= BLT_START_BOTTOM;
675 src += (height - 1) * sc->linebytes;
676 dst += (height - 1) * sc->linebytes;
677 }
678
679 stride = (sc->linebytes << 16) | sc->linebytes;
680 size = (height << 16) | width;
681
682 chipsfb_wait_idle(sc);
683 chipsfb_write32(sc, CT_BLT_STRIDE, stride);
684 chipsfb_write32(sc, CT_BLT_SRCADDR, src);
685 chipsfb_write32(sc, CT_BLT_DSTADDR, dst);
686 chipsfb_write32(sc, CT_BLT_CONTROL, cmd);
687 chipsfb_write32(sc, CT_BLT_SIZE, size);
688 #ifdef CHIPSFB_WAIT
689 chipsfb_wait_idle(sc);
690 #endif
691 }
692
693 static void
694 chipsfb_rectfill(struct chipsfb_softc *sc, int x, int y, int width,
695 int height, int colour)
696 {
697 uint32_t dst, cmd, stride, size;
698
699 cmd = BLT_PAT_IS_SOLID | BLT_PAT_IS_MONO | ROP_PAT;
700
701 /* we assume 8 bit for now */
702 dst = x + y * sc->linebytes;
703
704 stride = (sc->linebytes << 16) | sc->linebytes;
705 size = (height << 16) | width;
706
707 chipsfb_wait_idle(sc);
708 chipsfb_write32(sc, CT_BLT_STRIDE, stride);
709 chipsfb_write32(sc, CT_BLT_SRCADDR, dst);
710 chipsfb_write32(sc, CT_BLT_DSTADDR, dst);
711 chipsfb_write32(sc, CT_BLT_CONTROL, cmd);
712 chipsfb_write32(sc, CT_BLT_BG, colour);
713 chipsfb_write32(sc, CT_BLT_FG, colour);
714 chipsfb_write32(sc, CT_BLT_SIZE, size);
715 #ifdef CHIPSFB_WAIT
716 chipsfb_wait_idle(sc);
717 #endif
718 }
719
720 static void
721 chipsfb_putchar(void *cookie, int row, int col, u_int c, long attr)
722 {
723 struct rasops_info *ri = cookie;
724 struct vcons_screen *scr = ri->ri_hw;
725 struct chipsfb_softc *sc = scr->scr_cookie;
726
727 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
728 uint8_t *data;
729 int fg, bg, uc;
730 int x, y, wi, he;
731
732 wi = ri->ri_font->fontwidth;
733 he = ri->ri_font->fontheight;
734
735 if (!CHAR_IN_FONT(c, ri->ri_font))
736 return;
737 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf];
738 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf];
739 x = ri->ri_xorigin + col * wi;
740 y = ri->ri_yorigin + row * he;
741 if (c == 0x20) {
742 chipsfb_rectfill(sc, x, y, wi, he, bg);
743 } else {
744 uc = c-ri->ri_font->firstchar;
745 data = (uint8_t *)ri->ri_font->data + uc *
746 ri->ri_fontscale;
747 chipsfb_setup_mono(sc, x, y, wi, he, fg, bg);
748 chipsfb_feed(sc, ri->ri_font->stride * he, data);
749 }
750 }
751 }
752
753 static void
754 chipsfb_setup_mono(struct chipsfb_softc *sc, int xd, int yd, int width,
755 int height, uint32_t fg, uint32_t bg)
756 {
757 uint32_t dst, cmd, stride, size;
758
759 cmd = BLT_PAT_IS_SOLID | BLT_SRC_IS_CPU | BLT_SRC_IS_MONO | ROP_COPY;
760
761 /* we assume 8 bit for now */
762 dst = xd + yd * sc->linebytes;
763
764 stride = (sc->linebytes << 16);
765 size = (height << 16) | width;
766
767 chipsfb_wait_idle(sc);
768 chipsfb_write32(sc, CT_BLT_STRIDE, stride);
769 chipsfb_write32(sc, CT_BLT_EXPCTL, MONO_SRC_ALIGN_BYTE);
770 chipsfb_write32(sc, CT_BLT_DSTADDR, dst);
771 chipsfb_write32(sc, CT_BLT_SRCADDR, 0);
772 chipsfb_write32(sc, CT_BLT_CONTROL, cmd);
773 chipsfb_write32(sc, CT_BLT_BG, bg);
774 chipsfb_write32(sc, CT_BLT_FG, fg);
775 chipsfb_write32(sc, CT_BLT_SIZE, size);
776 }
777
778 static void
779 chipsfb_feed(struct chipsfb_softc *sc, int count, uint8_t *data)
780 {
781 int i;
782 uint32_t latch = 0, bork;
783 int shift = 0;
784
785 for (i = 0; i < count; i++) {
786 bork = data[i];
787 latch |= (bork << shift);
788 if (shift == 24) {
789 chipsfb_write32(sc, CT_OFF_DATA, latch);
790 latch = 0;
791 shift = 0;
792 } else
793 shift += 8;
794 }
795
796 if (shift != 0) {
797 chipsfb_write32(sc, CT_OFF_DATA, latch);
798 }
799
800 /* apparently the chip wants 64bit-aligned data or it won't go idle */
801 if ((count + 3) & 0x04) {
802 chipsfb_write32(sc, CT_OFF_DATA, 0);
803 }
804 #ifdef CHIPSFB_WAIT
805 chipsfb_wait_idle(sc);
806 #endif
807 }
808
809 #ifdef CHIPSFB_DEBUG
810 static void
811 chipsfb_showpal(struct chipsfb_softc *sc)
812 {
813 int i, x = 0;
814
815 for (i = 0; i < 16; i++) {
816 chipsfb_rectfill(sc, x, 0, 64, 64, i);
817 x += 64;
818 }
819 }
820 #endif
821
822 #if 0
823 static int
824 chipsfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
825 {
826
827 return 0;
828 }
829 #endif
830
831 static void
832 chipsfb_restore_palette(struct chipsfb_softc *sc)
833 {
834 int i;
835
836 for (i = 0; i < 256; i++) {
837 chipsfb_putpalreg(sc,
838 i,
839 sc->sc_cmap_red[i],
840 sc->sc_cmap_green[i],
841 sc->sc_cmap_blue[i]);
842 }
843 }
844
845 /*
846 * wsdisplay_accessops
847 */
848
849 static int
850 chipsfb_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
851 struct lwp *l)
852 {
853 struct vcons_data *vd = v;
854 struct chipsfb_softc *sc = vd->cookie;
855 struct wsdisplay_fbinfo *wdf;
856 struct vcons_screen *ms = vd->active;
857
858 switch (cmd) {
859 case WSDISPLAYIO_GTYPE:
860 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
861 return 0;
862
863 case WSDISPLAYIO_GINFO:
864 wdf = (void *)data;
865 wdf->height = ms->scr_ri.ri_height;
866 wdf->width = ms->scr_ri.ri_width;
867 wdf->depth = ms->scr_ri.ri_depth;
868 wdf->cmsize = 256;
869 return 0;
870
871 case WSDISPLAYIO_GETCMAP:
872 return chipsfb_getcmap(sc,
873 (struct wsdisplay_cmap *)data);
874
875 case WSDISPLAYIO_PUTCMAP:
876 return chipsfb_putcmap(sc,
877 (struct wsdisplay_cmap *)data);
878
879 /* PCI config read/write passthrough. */
880 case PCI_IOC_CFGREAD:
881 case PCI_IOC_CFGWRITE:
882 return (pci_devioctl(sc->sc_pc, sc->sc_pcitag,
883 cmd, data, flag, l));
884
885 case WSDISPLAYIO_SMODE:
886 {
887 int new_mode = *(int*)data;
888 if (new_mode != sc->sc_mode) {
889 sc->sc_mode = new_mode;
890 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
891 chipsfb_restore_palette(sc);
892 vcons_redraw_screen(ms);
893 }
894 }
895 }
896 return 0;
897 }
898 return EPASSTHROUGH;
899 }
900
901 static paddr_t
902 chipsfb_mmap(void *v, void *vs, off_t offset, int prot)
903 {
904 struct vcons_data *vd = v;
905 struct chipsfb_softc *sc = vd->cookie;
906 struct lwp *me;
907 paddr_t pa;
908
909 /* 'regular' framebuffer mmap()ing */
910 if (offset < sc->memsize) {
911 pa = bus_space_mmap(sc->sc_fbt, offset, 0, prot,
912 BUS_SPACE_MAP_LINEAR);
913 return pa;
914 }
915
916 /*
917 * restrict all other mappings to processes with superuser privileges
918 * or the kernel itself
919 */
920 me = curlwp;
921 if (me != NULL) {
922 if (kauth_authorize_generic(me->l_cred, KAUTH_GENERIC_ISSUSER,
923 NULL) != 0) {
924 printf("%s: mmap() rejected.\n", sc->sc_dev.dv_xname);
925 return -1;
926 }
927 }
928
929 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
930 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
931 BUS_SPACE_MAP_LINEAR);
932 return pa;
933 }
934
935 #ifdef macppc
936 /* allow mapping of IO space */
937 if ((offset >= 0xf2000000) && (offset < 0xf2800000)) {
938 pa = bus_space_mmap(sc->sc_iot, offset - 0xf2000000, 0, prot,
939 BUS_SPACE_MAP_LINEAR);
940 return pa;
941 }
942 #endif
943
944 #ifdef OFB_ALLOW_OTHERS
945 if (offset >= 0x80000000) {
946 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
947 BUS_SPACE_MAP_LINEAR);
948 return pa;
949 }
950 #endif
951 return -1;
952 }
953
954 static void
955 chipsfb_init_screen(void *cookie, struct vcons_screen *scr,
956 int existing, long *defattr)
957 {
958 struct chipsfb_softc *sc = cookie;
959 struct rasops_info *ri = &scr->scr_ri;
960
961 ri->ri_depth = sc->bits_per_pixel;
962 ri->ri_width = sc->width;
963 ri->ri_height = sc->height;
964 ri->ri_stride = sc->width;
965 ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
966
967 ri->ri_bits = bus_space_vaddr(sc->sc_fbt, sc->sc_fbh);
968
969 #ifdef CHIPSFB_DEBUG
970 printf("addr: %08lx\n", (ulong)ri->ri_bits);
971 #endif
972 if (existing) {
973 ri->ri_flg |= RI_CLEAR;
974 }
975
976 rasops_init(ri, sc->height/8, sc->width/8);
977 ri->ri_caps = WSSCREEN_WSCOLORS;
978
979 rasops_reconfig(ri, sc->height / ri->ri_font->fontheight,
980 sc->width / ri->ri_font->fontwidth);
981
982 ri->ri_hw = scr;
983 ri->ri_ops.copyrows = chipsfb_copyrows;
984 ri->ri_ops.copycols = chipsfb_copycols;
985 ri->ri_ops.eraserows = chipsfb_eraserows;
986 ri->ri_ops.erasecols = chipsfb_erasecols;
987 ri->ri_ops.cursor = chipsfb_cursor;
988 ri->ri_ops.putchar = chipsfb_putchar;
989 }
990
991 #if 0
992 int
993 chipsfb_load_font(void *v, void *cookie, struct wsdisplay_font *data)
994 {
995
996 return 0;
997 }
998 #endif
999
1000 static void
1001 chipsfb_init(struct chipsfb_softc *sc)
1002 {
1003
1004 chipsfb_wait_idle(sc);
1005
1006 chipsfb_write_indexed(sc, CT_CONF_INDEX, XR_IO_CONTROL,
1007 ENABLE_CRTC_EXT | ENABLE_ATTR_EXT);
1008 chipsfb_write_indexed(sc, CT_CONF_INDEX, XR_ADDR_MAPPING,
1009 ENABLE_LINEAR);
1010
1011 /* setup the blitter */
1012 }
1013
1014 static uint32_t
1015 chipsfb_probe_vram(struct chipsfb_softc *sc)
1016 {
1017 uint32_t ofs = 0x00080000; /* 512kB */
1018
1019 /*
1020 * advance in 0.5MB steps, see if we can read back what we wrote and
1021 * if what we wrote to 0 is left untouched. Max. fb size is 4MB so
1022 * we voluntarily stop there.
1023 */
1024 chipsfb_write32(sc, 0, 0xf0f0f0f0);
1025 chipsfb_write32(sc, ofs, 0x0f0f0f0f);
1026 while ((chipsfb_read32(sc, 0) == 0xf0f0f0f0) &&
1027 (chipsfb_read32(sc, ofs) == 0x0f0f0f0f) &&
1028 (ofs < 0x00400000)) {
1029
1030 ofs += 0x00080000;
1031 chipsfb_write32(sc, ofs, 0x0f0f0f0f);
1032 }
1033
1034 return ofs;
1035 }
1036