pm3fb.c revision 1.7 1 /*
2 * Copyright (c) 2015 Naruaki Etomi
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 /*
27 * A console driver for Permedia 3 graphics controllers
28 * most of the following was adapted from the xf86-video-glint driver's
29 * pm3_accel.c, pm3_dac.c and pm2fb framebuffer console driver
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
36 #include <sys/malloc.h>
37 #include <sys/lwp.h>
38 #include <sys/kauth.h>
39 #include <sys/atomic.h>
40
41 #include <dev/videomode/videomode.h>
42
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pcidevs.h>
46 #include <dev/pci/pciio.h>
47 #include <dev/pci/pm3reg.h>
48
49 #include <dev/wscons/wsdisplayvar.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wsfont/wsfont.h>
52 #include <dev/rasops/rasops.h>
53 #include <dev/wscons/wsdisplay_vconsvar.h>
54 #include <dev/pci/wsdisplay_pci.h>
55
56 #include <dev/i2c/i2cvar.h>
57 #include <dev/i2c/i2c_bitbang.h>
58 #include <dev/i2c/ddcvar.h>
59 #include <dev/videomode/videomode.h>
60 #include <dev/videomode/edidvar.h>
61 #include <dev/videomode/edidreg.h>
62
63 struct pm3fb_softc {
64 device_t sc_dev;
65
66 pci_chipset_tag_t sc_pc;
67 pcitag_t sc_pcitag;
68
69 bus_space_tag_t sc_memt;
70 bus_space_tag_t sc_iot;
71
72 bus_space_handle_t sc_regh;
73 bus_addr_t sc_fb, sc_reg;
74 bus_size_t sc_fbsize, sc_regsize;
75
76 int sc_width, sc_height, sc_depth, sc_stride;
77 int sc_locked;
78 struct vcons_screen sc_console_screen;
79 struct wsscreen_descr sc_defaultscreen_descr;
80 const struct wsscreen_descr *sc_screens[1];
81 struct wsscreen_list sc_screenlist;
82 struct vcons_data vd;
83 int sc_mode;
84 u_char sc_cmap_red[256];
85 u_char sc_cmap_green[256];
86 u_char sc_cmap_blue[256];
87 /* i2c stuff */
88 struct i2c_controller sc_i2c;
89 uint8_t sc_edid_data[128];
90 struct edid_info sc_ei;
91 const struct videomode *sc_videomode;
92 };
93
94 static int pm3fb_match(device_t, cfdata_t, void *);
95 static void pm3fb_attach(device_t, device_t, void *);
96
97 CFATTACH_DECL_NEW(pm3fb, sizeof(struct pm3fb_softc),
98 pm3fb_match, pm3fb_attach, NULL, NULL);
99
100 extern const u_char rasops_cmap[768];
101
102 static int pm3fb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
103 static paddr_t pm3fb_mmap(void *, void *, off_t, int);
104 static void pm3fb_init_screen(void *, struct vcons_screen *, int, long *);
105
106 static int pm3fb_putcmap(struct pm3fb_softc *, struct wsdisplay_cmap *);
107 static int pm3fb_getcmap(struct pm3fb_softc *, struct wsdisplay_cmap *);
108 static void pm3fb_init_palette(struct pm3fb_softc *);
109 static int pm3fb_putpalreg(struct pm3fb_softc *, uint8_t, uint8_t, uint8_t, uint8_t);
110
111 static void pm3fb_init(struct pm3fb_softc *);
112 static inline void pm3fb_wait(struct pm3fb_softc *, int);
113 static void pm3fb_flush_engine(struct pm3fb_softc *);
114 static void pm3fb_rectfill(struct pm3fb_softc *, int, int, int, int, uint32_t);
115 static void pm3fb_bitblt(void *, int, int, int, int, int, int, int);
116
117 static void pm3fb_cursor(void *, int, int, int);
118 static void pm3fb_putchar(void *, int, int, u_int, long);
119 static void pm3fb_copycols(void *, int, int, int, int);
120 static void pm3fb_erasecols(void *, int, int, int, long);
121 static void pm3fb_copyrows(void *, int, int, int);
122 static void pm3fb_eraserows(void *, int, int, long);
123
124 struct wsdisplay_accessops pm3fb_accessops = {
125 pm3fb_ioctl,
126 pm3fb_mmap,
127 NULL, /* alloc_screen */
128 NULL, /* free_screen */
129 NULL, /* show_screen */
130 NULL, /* load_font */
131 NULL, /* pollc */
132 NULL /* scroll */
133 };
134
135 /* I2C glue */
136 static int pm3fb_i2c_send_start(void *, int);
137 static int pm3fb_i2c_send_stop(void *, int);
138 static int pm3fb_i2c_initiate_xfer(void *, i2c_addr_t, int);
139 static int pm3fb_i2c_read_byte(void *, uint8_t *, int);
140 static int pm3fb_i2c_write_byte(void *, uint8_t, int);
141
142 /* I2C bitbang glue */
143 static void pm3fb_i2cbb_set_bits(void *, uint32_t);
144 static void pm3fb_i2cbb_set_dir(void *, uint32_t);
145 static uint32_t pm3fb_i2cbb_read(void *);
146
147 static void pm3_setup_i2c(struct pm3fb_softc *);
148
149 static const struct i2c_bitbang_ops pm3fb_i2cbb_ops = {
150 pm3fb_i2cbb_set_bits,
151 pm3fb_i2cbb_set_dir,
152 pm3fb_i2cbb_read,
153 {
154 PM3_DD_SDA_IN,
155 PM3_DD_SCL_IN,
156 0,
157 0
158 }
159 };
160
161 /* mode setting stuff */
162 static int pm3fb_set_pll(struct pm3fb_softc *, int);
163 static void pm3fb_write_dac(struct pm3fb_softc *, int, uint8_t);
164 static void pm3fb_set_mode(struct pm3fb_softc *, const struct videomode *);
165
166 static inline void
167 pm3fb_wait(struct pm3fb_softc *sc, int slots)
168 {
169 uint32_t reg;
170
171 do {
172 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh,
173 PM3_INPUT_FIFO_SPACE);
174 } while (reg <= slots);
175 }
176
177 static void
178 pm3fb_flush_engine(struct pm3fb_softc *sc)
179 {
180
181 pm3fb_wait(sc, 2);
182 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FILTER_MODE, PM3_FM_PASS_SYNC);
183 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SYNC, 0);
184
185 do {
186 while (bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_OUTPUT_FIFO_WORDS) == 0);
187 } while (bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_OUTPUT_FIFO) !=
188 PM3_SYNC_TAG);
189 }
190
191 static int
192 pm3fb_match(device_t parent, cfdata_t match, void *aux)
193 {
194 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
195
196 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
197 return 0;
198 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_3DLABS)
199 return 0;
200
201 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DLABS_PERMEDIA3)
202 return 100;
203 return (0);
204 }
205
206 static void
207 pm3fb_attach(device_t parent, device_t self, void *aux)
208 {
209 struct pm3fb_softc *sc = device_private(self);
210 struct pci_attach_args *pa = aux;
211 struct rasops_info *ri;
212 struct wsemuldisplaydev_attach_args aa;
213 prop_dictionary_t dict;
214 unsigned long defattr;
215 bool is_console;
216 uint32_t flags;
217
218 sc->sc_pc = pa->pa_pc;
219 sc->sc_pcitag = pa->pa_tag;
220 sc->sc_memt = pa->pa_memt;
221 sc->sc_iot = pa->pa_iot;
222 sc->sc_dev = self;
223
224 pci_aprint_devinfo(pa, NULL);
225
226 /*
227 * fill in parameters from properties
228 * if we can't get a usable mode via DDC2 we'll use this to pick one,
229 * which is why we fill them in with some conservative values that
230 * hopefully work as a last resort
231 */
232 dict = device_properties(self);
233 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) {
234 aprint_error("%s: no width property\n", device_xname(self));
235 sc->sc_width = 1280;
236 }
237 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) {
238 aprint_error("%s: no height property\n", device_xname(self));
239 sc->sc_height = 1024;
240 }
241 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
242 aprint_error("%s: no depth property\n", device_xname(self));
243 sc->sc_depth = 8;
244 }
245
246 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3);
247
248 prop_dictionary_get_bool(dict, "is_console", &is_console);
249
250 pci_mapreg_info(pa->pa_pc, pa->pa_tag, 0x14, PCI_MAPREG_TYPE_MEM,
251 &sc->sc_fb, &sc->sc_fbsize, &flags);
252
253 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0,
254 &sc->sc_memt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) {
255 aprint_error("%s: failed to map registers.\n",
256 device_xname(sc->sc_dev));
257 }
258
259 /*
260 * Permedia 3 always return 64MB fbsize
261 * 16 MB should be enough -- more just wastes map entries
262 */
263 if (sc->sc_fbsize != 0)
264 sc->sc_fbsize = (16 << 20);
265
266 /*
267 * Some Power Mac G4 model could not initialize these registers,
268 * Power Mac G4 (Mirrored Drive Doors), for example
269 */
270 #if defined(__powerpc__)
271 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOCALMEMCAPS, 0x02e311B8);
272 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOCALMEMTIMINGS, 0x07424905);
273 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOCALMEMCONTROL, 0x0c000003);
274 #endif
275
276 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self),
277 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
278
279 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
280 "default",
281 0, 0,
282 NULL,
283 8, 16,
284 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
285 NULL
286 };
287
288 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
289 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
290 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
291 sc->sc_locked = 0;
292
293 pm3_setup_i2c(sc);
294
295 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
296 &pm3fb_accessops);
297
298 sc->vd.init_screen = pm3fb_init_screen;
299
300 /* init engine here */
301 pm3fb_init(sc);
302
303 ri = &sc->sc_console_screen.scr_ri;
304
305 if (is_console) {
306 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
307 &defattr);
308 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
309
310 pm3fb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
311 ri->ri_devcmap[(defattr >> 16) & 0xff]);
312 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
313 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
314 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
315 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
316
317 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
318 defattr);
319 vcons_replay_msgbuf(&sc->sc_console_screen);
320 } else {
321 if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
322 /* do some minimal setup to avoid weirdnesses later */
323 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
324 &defattr);
325 }
326 }
327
328 pm3fb_init_palette(sc);
329
330 aa.console = is_console;
331 aa.scrdata = &sc->sc_screenlist;
332 aa.accessops = &pm3fb_accessops;
333 aa.accesscookie = &sc->vd;
334
335 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
336 }
337
338 static int
339 pm3fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
340 struct lwp *l)
341 {
342 struct vcons_data *vd = v;
343 struct pm3fb_softc *sc = vd->cookie;
344 struct wsdisplay_fbinfo *wdf;
345 struct vcons_screen *ms = vd->active;
346
347 switch (cmd) {
348 case WSDISPLAYIO_GTYPE:
349 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
350 return 0;
351
352 /* PCI config read/write passthrough. */
353 case PCI_IOC_CFGREAD:
354 case PCI_IOC_CFGWRITE:
355 return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
356 cmd, data, flag, l);
357
358 case WSDISPLAYIO_GET_BUSID:
359 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
360 sc->sc_pcitag, data);
361
362 case WSDISPLAYIO_GINFO:
363 if (ms == NULL)
364 return ENODEV;
365 wdf = (void *)data;
366 wdf->height = ms->scr_ri.ri_height;
367 wdf->width = ms->scr_ri.ri_width;
368 wdf->depth = ms->scr_ri.ri_depth;
369 wdf->cmsize = 256;
370 return 0;
371
372 case WSDISPLAYIO_GETCMAP:
373 return pm3fb_getcmap(sc,
374 (struct wsdisplay_cmap *)data);
375
376 case WSDISPLAYIO_PUTCMAP:
377 return pm3fb_putcmap(sc,
378 (struct wsdisplay_cmap *)data);
379
380 case WSDISPLAYIO_LINEBYTES:
381 *(u_int *)data = sc->sc_stride;
382 return 0;
383
384 case WSDISPLAYIO_SMODE: {
385 int new_mode = *(int*)data;
386 if (new_mode != sc->sc_mode) {
387 sc->sc_mode = new_mode;
388 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
389 /* first set the video mode */
390 if (sc->sc_videomode != NULL) {
391 pm3fb_set_mode(sc, sc->sc_videomode);
392 }
393 /* then initialize the drawing engine */
394 pm3fb_init(sc);
395 pm3fb_init_palette(sc);
396 vcons_redraw_screen(ms);
397 } else
398 pm3fb_flush_engine(sc);
399 }
400 }
401 return 0;
402 case WSDISPLAYIO_GET_EDID: {
403 struct wsdisplayio_edid_info *d = data;
404 d->data_size = 128;
405 if (d->buffer_size < 128)
406 return EAGAIN;
407 return copyout(sc->sc_edid_data, d->edid_data, 128);
408 }
409
410 case WSDISPLAYIO_GET_FBINFO: {
411 struct wsdisplayio_fbinfo *fbi = data;
412 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
413 }
414 }
415 return EPASSTHROUGH;
416 }
417
418 static paddr_t
419 pm3fb_mmap(void *v, void *vs, off_t offset, int prot)
420 {
421 struct vcons_data *vd = v;
422 struct pm3fb_softc *sc = vd->cookie;
423 paddr_t pa;
424
425 /* 'regular' framebuffer mmap()ing */
426 if (offset < sc->sc_fbsize) {
427 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot,
428 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
429 return pa;
430 }
431
432 /*
433 * restrict all other mappings to processes with superuser privileges
434 * or the kernel itself
435 */
436 if (kauth_authorize_machdep(kauth_cred_get(),
437 KAUTH_MACHDEP_UNMANAGEDMEM,
438 NULL, NULL, NULL, NULL) != 0) {
439 aprint_normal("%s: mmap() rejected.\n",
440 device_xname(sc->sc_dev));
441 return -1;
442 }
443
444 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
445 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
446 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
447 return pa;
448 }
449
450 if ((offset >= sc->sc_reg) &&
451 (offset < (sc->sc_reg + sc->sc_regsize))) {
452 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
453 BUS_SPACE_MAP_LINEAR);
454 return pa;
455 }
456
457 #ifdef PCI_MAGIC_IO_RANGE
458 /* allow mapping of IO space */
459 if ((offset >= PCI_MAGIC_IO_RANGE) &&
460 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
461 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
462 0, prot, BUS_SPACE_MAP_LINEAR);
463 return pa;
464 }
465 #endif
466 return -1;
467 }
468
469 static void
470 pm3fb_init_screen(void *cookie, struct vcons_screen *scr,
471 int existing, long *defattr)
472 {
473 struct pm3fb_softc *sc = cookie;
474 struct rasops_info *ri = &scr->scr_ri;
475
476 ri->ri_depth = sc->sc_depth;
477 ri->ri_width = sc->sc_width;
478 ri->ri_height = sc->sc_height;
479 ri->ri_stride = sc->sc_stride;
480 ri->ri_flg = RI_CENTER;
481 if (sc->sc_depth == 8)
482 ri->ri_flg |= RI_8BIT_IS_RGB;
483
484 rasops_init(ri, 0, 0);
485 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_UNDERLINE;
486
487 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
488 sc->sc_width / ri->ri_font->fontwidth);
489
490 ri->ri_hw = scr;
491 ri->ri_ops.copyrows = pm3fb_copyrows;
492 ri->ri_ops.copycols = pm3fb_copycols;
493 ri->ri_ops.cursor = pm3fb_cursor;
494 ri->ri_ops.eraserows = pm3fb_eraserows;
495 ri->ri_ops.erasecols = pm3fb_erasecols;
496 ri->ri_ops.putchar = pm3fb_putchar;
497 }
498
499 static int
500 pm3fb_putcmap(struct pm3fb_softc *sc, struct wsdisplay_cmap *cm)
501 {
502 u_char *r, *g, *b;
503 u_int index = cm->index;
504 u_int count = cm->count;
505 int i, error;
506 u_char rbuf[256], gbuf[256], bbuf[256];
507
508 if (cm->index >= 256 || cm->count > 256 ||
509 (cm->index + cm->count) > 256)
510 return EINVAL;
511 error = copyin(cm->red, &rbuf[index], count);
512 if (error)
513 return error;
514 error = copyin(cm->green, &gbuf[index], count);
515 if (error)
516 return error;
517 error = copyin(cm->blue, &bbuf[index], count);
518 if (error)
519 return error;
520
521 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
522 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
523 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
524
525 r = &sc->sc_cmap_red[index];
526 g = &sc->sc_cmap_green[index];
527 b = &sc->sc_cmap_blue[index];
528
529 for (i = 0; i < count; i++) {
530 pm3fb_putpalreg(sc, index, *r, *g, *b);
531 index++;
532 r++, g++, b++;
533 }
534 return 0;
535 }
536
537 static int
538 pm3fb_getcmap(struct pm3fb_softc *sc, struct wsdisplay_cmap *cm)
539 {
540 u_int index = cm->index;
541 u_int count = cm->count;
542 int error;
543
544 if (index >= 255 || count > 256 || index + count > 256)
545 return EINVAL;
546
547 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
548 if (error)
549 return error;
550 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
551 if (error)
552 return error;
553 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
554 if (error)
555 return error;
556
557 return 0;
558 }
559
560 static void
561 pm3fb_init_palette(struct pm3fb_softc *sc)
562 {
563 struct rasops_info *ri = &sc->sc_console_screen.scr_ri;
564 int i, j = 0;
565 uint8_t cmap[768];
566
567 rasops_get_cmap(ri, cmap, sizeof(cmap));
568
569 for (i = 0; i < 256; i++) {
570 sc->sc_cmap_red[i] = cmap[j];
571 sc->sc_cmap_green[i] = cmap[j + 1];
572 sc->sc_cmap_blue[i] = cmap[j + 2];
573 pm3fb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
574 j += 3;
575 }
576 }
577
578 static int
579 pm3fb_putpalreg(struct pm3fb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, uint8_t b)
580 {
581
582 pm3fb_wait(sc, 4);
583 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_WRITE_IDX, idx);
584 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_DATA, r);
585 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_DATA, g);
586 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_PAL_DATA, b);
587 return 0;
588 }
589
590 static void
591 pm3fb_write_dac(struct pm3fb_softc *sc, int reg, uint8_t data)
592 {
593
594 pm3fb_wait(sc, 3);
595 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_INDEX_LOW, reg & 0xff);
596 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_INDEX_HIGH, (reg >> 8) & 0xff);
597 bus_space_write_1(sc->sc_memt, sc->sc_regh, PM3_DAC_INDEX_DATA, data);
598 }
599
600 static void
601 pm3fb_init(struct pm3fb_softc *sc)
602 {
603
604 pm3fb_wait(sc, 16);
605 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_DESTREAD_MODE, 0);
606 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_DESTREAD_ENABLES, 0);
607 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_SOURCEREAD_MODE, 0);
608 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LB_WRITE_MODE, 0);
609 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FILTER_MODE, PM3_FM_PASS_SYNC);
610 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STATISTIC_MODE, 0);
611 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DELTA_MODE, 0);
612 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RASTERIZER_MODE, 0);
613 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCISSOR_MODE, 0);
614 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LINESTIPPLE_MODE, 0);
615 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_AREASTIPPLE_MODE, 0);
616 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_GID_MODE, 0);
617 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DEPTH_MODE, 0);
618 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STENCIL_MODE, 0);
619 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STENCIL_DATA, 0);
620 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_COLORDDA_MODE, 0);
621
622 pm3fb_wait(sc, 16);
623 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREADDRESS_MODE, 0);
624 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREINDEX_MODE0, 0);
625 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREINDEX_MODE1, 0);
626 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREREAD_MODE, 0);
627 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXELLUT_MODE, 0);
628 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTUREFILTER_MODE, 0);
629 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITE_MODE, 0);
630 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOLOR_MODE, 0);
631 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITECOLOR_MODE1, 0);
632 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITEALPHA_MODE1, 0);
633 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITECOLOR_MODE0, 0);
634 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_TEXTURECOMPOSITEALPHA_MODE0, 0);
635 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FOG_MODE, 0);
636 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CHROMATEST_MODE, 0);
637 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ALPHATEST_MODE, 0);
638 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ANTIALIAS_MODE, 0);
639
640 pm3fb_wait(sc, 16);
641 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_YUV_MODE, 0);
642 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ALPHABLENDCOLOR_MODE, 0);
643 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ALPHABLENDALPHA_MODE, 0);
644 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DITHER_MODE, 0);
645 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_LOGICALOP_MODE, 0);
646 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_ROUTER_MODE, 0);
647 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_WINDOW, 0);
648 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D, 0);
649 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SPANCOLORMASK, 0xffffffff);
650 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_XBIAS, 0);
651 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_YBIAS, 0);
652 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DELTACONTROL, 0);
653 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_BITMASKPATTERN, 0xffffffff);
654 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_ENABLE,
655 PM3_FBDESTREAD_SET(0xff, 0xff, 0xff));
656 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_BUFFERADDRESS0, 0);
657
658 pm3fb_wait(sc, 16);
659 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_BUFFEROFFSET0, 0);
660 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBDESTREAD_BUFFERWIDTH0,
661 PM3_FBDESTREAD_BUFFERWIDTH_WIDTH(sc->sc_stride));
662 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FB_DESTREAD_MODE,
663 PM3_FBDRM_ENABLE | PM3_FBDRM_ENABLE0);
664 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFERADDRESS, 0);
665 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFEROFFSET, 0);
666 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFERWIDTH,
667 PM3_FBSOURCEREAD_BUFFERWIDTH_WIDTH(sc->sc_stride));
668 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_MODE,
669 PM3_FBSOURCEREAD_MODE_BLOCKING | PM3_FBSOURCEREAD_MODE_ENABLE);
670 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_PIXEL_SIZE, PM3_PS_8BIT);
671 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOFTWAREWRITEMASK, 0xffffffff);
672 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBHARDWAREWRITEMASK, 0xffffffff);
673 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITE_MODE,
674 PM3_FBWRITEMODE_WRITEENABLE | PM3_FBWRITEMODE_OPAQUESPAN | PM3_FBWRITEMODE_ENABLE0);
675 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITEBUFFERADDRESS0, 0);
676 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITEBUFFEROFFSET0, 0);
677 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBWRITEBUFFERWIDTH0,
678 PM3_FBWRITEBUFFERWIDTH_WIDTH(sc->sc_stride));
679 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SIZEOF_FRAMEBUFFER, 4095);
680 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DITHER_MODE, PM3_CF_TO_DIM_CF(4));
681 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DXDOM, 0);
682
683 pm3fb_wait(sc, 6);
684 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DXSUB, 0);
685 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DY, 1 << 16);
686 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STARTXDOM, 0);
687 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STARTXSUB, 0);
688 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_STARTY, 0);
689 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_COUNT, 0);
690 }
691
692 static void
693 pm3fb_rectfill(struct pm3fb_softc *sc, int x, int y, int wi, int he,
694 uint32_t colour)
695 {
696 pm3fb_wait(sc, 4);
697
698 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D,
699 PM3_CONFIG2D_USECONSTANTSOURCE | PM3_CONFIG2D_FOREGROUNDROP_ENABLE |
700 (PM3_CONFIG2D_FOREGROUNDROP(0x3)) | PM3_CONFIG2D_FBWRITE_ENABLE);
701
702 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FOREGROUNDCOLOR, colour);
703
704 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RECTANGLEPOSITION,
705 (((y) & 0xffff) << 16) | ((x) & 0xffff) );
706
707 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RENDER2D,
708 PM3_RENDER2D_XPOSITIVE | PM3_RENDER2D_YPOSITIVE |
709 PM3_RENDER2D_OPERATION_NORMAL | PM3_RENDER2D_SPANOPERATION |
710 (((he) & 0x0fff) << 16) | ((wi) & 0x0fff));
711
712 #ifdef PM3FB_DEBUG
713 pm3fb_flush_engine(sc);
714 #endif
715 }
716
717 static void
718 pm3fb_bitblt(void *cookie, int srcx, int srcy, int dstx, int dsty,
719 int width, int height, int rop)
720 {
721 struct pm3fb_softc *sc = cookie;
722 int x_align, offset_x, offset_y;
723 uint32_t dir = 0;
724
725 offset_x = srcx - dstx;
726 offset_y = srcy - dsty;
727
728 if (dsty <= srcy) {
729 dir |= PM3_RENDER2D_YPOSITIVE;
730 }
731
732 if (dstx <= srcx) {
733 dir |= PM3_RENDER2D_XPOSITIVE;
734 }
735
736 x_align = (srcx & 0x1f);
737
738 pm3fb_wait(sc, 6);
739
740 if (rop == 3){
741 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D,
742 PM3_CONFIG2D_USERSCISSOR_ENABLE | PM3_CONFIG2D_FOREGROUNDROP_ENABLE | PM3_CONFIG2D_BLOCKING |
743 PM3_CONFIG2D_FOREGROUNDROP(rop) | PM3_CONFIG2D_FBWRITE_ENABLE);
744 } else {
745 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CONFIG2D,
746 PM3_CONFIG2D_USERSCISSOR_ENABLE | PM3_CONFIG2D_FOREGROUNDROP_ENABLE | PM3_CONFIG2D_BLOCKING |
747 PM3_CONFIG2D_FOREGROUNDROP(rop) | PM3_CONFIG2D_FBWRITE_ENABLE | PM3_CONFIG2D_FBDESTREAD_ENABLE);
748 }
749
750 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCISSORMINXY,
751 ((dsty & 0x0fff) << 16) | (dstx & 0x0fff));
752
753 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCISSORMAXXY,
754 (((dsty + height) & 0x0fff) << 16) | ((dstx + width) & 0x0fff));
755
756 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FBSOURCEREAD_BUFFEROFFSET,
757 (((offset_y) & 0xffff) << 16) | ((offset_x) & 0xffff));
758
759 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RECTANGLEPOSITION,
760 (((dsty) & 0xffff) << 16) | ((dstx - x_align) & 0xffff));
761
762 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RENDER2D,
763 dir |
764 PM3_RENDER2D_OPERATION_NORMAL | PM3_RENDER2D_SPANOPERATION | PM3_RENDER2D_FBSOURCEREADENABLE |
765 (((height) & 0x0fff) << 16) | ((width + x_align) & 0x0fff));
766
767 #ifdef PM3FB_DEBUG
768 pm3fb_flush_engine(sc);
769 #endif
770 }
771
772 static void
773 pm3fb_cursor(void *cookie, int on, int row, int col)
774 {
775 struct rasops_info *ri = cookie;
776 struct vcons_screen *scr = ri->ri_hw;
777 struct pm3fb_softc *sc = scr->scr_cookie;
778 int x, y, wi, he;
779
780 wi = ri->ri_font->fontwidth;
781 he = ri->ri_font->fontheight;
782
783 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
784 x = ri->ri_ccol * wi + ri->ri_xorigin;
785 y = ri->ri_crow * he + ri->ri_yorigin;
786 if (ri->ri_flg & RI_CURSOR) {
787 pm3fb_bitblt(sc, x, y, x, y, wi, he, 12);
788 ri->ri_flg &= ~RI_CURSOR;
789 }
790 ri->ri_crow = row;
791 ri->ri_ccol = col;
792 if (on) {
793 x = ri->ri_ccol * wi + ri->ri_xorigin;
794 y = ri->ri_crow * he + ri->ri_yorigin;
795 pm3fb_bitblt(sc, x, y, x, y, wi, he, 12);
796 ri->ri_flg |= RI_CURSOR;
797 }
798 } else {
799 scr->scr_ri.ri_crow = row;
800 scr->scr_ri.ri_ccol = col;
801 scr->scr_ri.ri_flg &= ~RI_CURSOR;
802 }
803 }
804
805 static void
806 pm3fb_putchar(void *cookie, int row, int col, u_int c, long attr)
807 {
808 struct rasops_info *ri = cookie;
809 struct wsdisplay_font *font = PICK_FONT(ri, c);
810 struct vcons_screen *scr = ri->ri_hw;
811 struct pm3fb_softc *sc = scr->scr_cookie;
812 uint32_t mode;
813
814 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
815 void *data;
816 uint32_t fg, bg;
817 int uc, i;
818 int x, y, wi, he;
819
820 wi = font->fontwidth;
821 he = font->fontheight;
822
823 if (!CHAR_IN_FONT(c, font))
824 return;
825
826 bg = ri->ri_devcmap[(attr >> 16) & 0xf];
827 fg = ri->ri_devcmap[(attr >> 24) & 0xf];
828 x = ri->ri_xorigin + col * wi;
829 y = ri->ri_yorigin + row * he;
830 if (c == 0x20) {
831 pm3fb_rectfill(sc, x, y, wi, he, bg);
832 } else {
833 uc = c - font->firstchar;
834 data = (uint8_t *)font->data + uc * ri->ri_fontscale;
835 mode = PM3_RM_MASK_MIRROR;
836
837 #if BYTE_ORDER == LITTLE_ENDIAN
838 switch (ri->ri_font->stride) {
839 case 1:
840 mode |= 4 << 7;
841 break;
842 case 2:
843 mode |= 3 << 7;
844 break;
845 }
846 #else
847 switch (ri->ri_font->stride) {
848 case 1:
849 mode |= 3 << 7;
850 break;
851 case 2:
852 mode |= 2 << 7;
853 break;
854 }
855 #endif
856 pm3fb_wait(sc, 8);
857 bus_space_write_4(sc->sc_memt, sc->sc_regh,
858 PM3_FOREGROUNDCOLOR, fg);
859 bus_space_write_4(sc->sc_memt, sc->sc_regh,
860 PM3_BACKGROUNDCOLOR, bg);
861
862 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_RASTERIZER_MODE, mode);
863
864 bus_space_write_4(sc->sc_memt, sc->sc_regh,
865 PM3_CONFIG2D,
866 PM3_CONFIG2D_USERSCISSOR_ENABLE |
867 PM3_CONFIG2D_USECONSTANTSOURCE |
868 PM3_CONFIG2D_FOREGROUNDROP_ENABLE |
869 PM3_CONFIG2D_FOREGROUNDROP(0x03) |
870 PM3_CONFIG2D_OPAQUESPAN |
871 PM3_CONFIG2D_FBWRITE_ENABLE);
872
873 bus_space_write_4(sc->sc_memt, sc->sc_regh,
874 PM3_SCISSORMINXY, ((y & 0x0fff) << 16) | (x & 0x0fff));
875
876 bus_space_write_4(sc->sc_memt, sc->sc_regh,
877 PM3_SCISSORMAXXY, (((y + he) & 0x0fff) << 16) | ((x + wi) & 0x0fff));
878
879 bus_space_write_4(sc->sc_memt, sc->sc_regh,
880 PM3_RECTANGLEPOSITION, (((y) & 0xffff)<<16) | ((x) & 0xffff));
881
882 bus_space_write_4(sc->sc_memt, sc->sc_regh,
883 PM3_RENDER2D,
884 PM3_RENDER2D_XPOSITIVE |
885 PM3_RENDER2D_YPOSITIVE |
886 PM3_RENDER2D_OPERATION_SYNCONBITMASK |
887 PM3_RENDER2D_SPANOPERATION |
888 ((wi) & 0x0fff) | (((he) & 0x0fff) << 16));
889
890 pm3fb_wait(sc, he);
891
892 switch (ri->ri_font->stride) {
893 case 1: {
894 uint8_t *data8 = data;
895 uint32_t reg;
896 for (i = 0; i < he; i++) {
897 reg = *data8;
898 bus_space_write_4(sc->sc_memt,
899 sc->sc_regh,
900 PM3_BITMASKPATTERN, reg);
901 data8++;
902 }
903 break;
904 }
905 case 2: {
906 uint16_t *data16 = data;
907 uint32_t reg;
908 for (i = 0; i < he; i++) {
909 reg = *data16;
910 bus_space_write_4(sc->sc_memt,
911 sc->sc_regh,
912 PM3_BITMASKPATTERN, reg);
913 data16++;
914 }
915 break;
916 }
917 }
918 }
919 }
920 }
921
922 static void
923 pm3fb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
924 {
925 struct rasops_info *ri = cookie;
926 struct vcons_screen *scr = ri->ri_hw;
927 struct pm3fb_softc *sc = scr->scr_cookie;
928 int32_t xs, xd, y, width, height;
929
930 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
931 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
932 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
933 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
934 width = ri->ri_font->fontwidth * ncols;
935 height = ri->ri_font->fontheight;
936 pm3fb_bitblt(sc, xs, y, xd, y, width, height, 3);
937 }
938 }
939
940 static void
941 pm3fb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
942 {
943 struct rasops_info *ri = cookie;
944 struct vcons_screen *scr = ri->ri_hw;
945 struct pm3fb_softc *sc = scr->scr_cookie;
946 int32_t x, y, width, height, fg, bg, ul;
947
948 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
949 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
950 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
951 width = ri->ri_font->fontwidth * ncols;
952 height = ri->ri_font->fontheight;
953 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
954
955 pm3fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
956 }
957 }
958
959 static void
960 pm3fb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
961 {
962 struct rasops_info *ri = cookie;
963 struct vcons_screen *scr = ri->ri_hw;
964 struct pm3fb_softc *sc = scr->scr_cookie;
965 int32_t x, ys, yd, width, height;
966
967 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
968 x = ri->ri_xorigin;
969 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
970 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
971 width = ri->ri_emuwidth;
972 height = ri->ri_font->fontheight*nrows;
973 pm3fb_bitblt(sc, x, ys, x, yd, width, height, 3);
974 }
975 }
976
977 static void
978 pm3fb_eraserows(void *cookie, int row, int nrows, long fillattr)
979 {
980 struct rasops_info *ri = cookie;
981 struct vcons_screen *scr = ri->ri_hw;
982 struct pm3fb_softc *sc = scr->scr_cookie;
983 int32_t x, y, width, height, fg, bg, ul;
984
985 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
986 x = ri->ri_xorigin;
987 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
988 width = ri->ri_emuwidth;
989 height = ri->ri_font->fontheight * nrows;
990 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
991
992 pm3fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
993 }
994 }
995
996 /* should be enough */
997 #define MODE_IS_VALID(m) (((m)->hdisplay < 2048))
998
999 static void
1000 pm3_setup_i2c(struct pm3fb_softc *sc)
1001 {
1002 int i;
1003
1004 /* Fill in the i2c tag */
1005 iic_tag_init(&sc->sc_i2c);
1006 sc->sc_i2c.ic_cookie = sc;
1007 sc->sc_i2c.ic_send_start = pm3fb_i2c_send_start;
1008 sc->sc_i2c.ic_send_stop = pm3fb_i2c_send_stop;
1009 sc->sc_i2c.ic_initiate_xfer = pm3fb_i2c_initiate_xfer;
1010 sc->sc_i2c.ic_read_byte = pm3fb_i2c_read_byte;
1011 sc->sc_i2c.ic_write_byte = pm3fb_i2c_write_byte;
1012 sc->sc_i2c.ic_exec = NULL;
1013
1014 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DISPLAY_DATA, 0);
1015
1016 /* zero out the EDID buffer */
1017 memset(sc->sc_edid_data, 0, 128);
1018
1019 /* Some monitors don't respond first time */
1020 i = 0;
1021 while (sc->sc_edid_data[1] == 0 && i < 10) {
1022 ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128);
1023 i++;
1024 }
1025
1026 if (edid_parse(&sc->sc_edid_data[0], &sc->sc_ei) != -1) {
1027 /*
1028 * Now pick a mode.
1029 */
1030 if ((sc->sc_ei.edid_preferred_mode != NULL)) {
1031 struct videomode *m = sc->sc_ei.edid_preferred_mode;
1032 if (MODE_IS_VALID(m)) {
1033 sc->sc_videomode = m;
1034 } else {
1035 aprint_error_dev(sc->sc_dev,
1036 "unable to use preferred mode\n");
1037 }
1038 }
1039 /*
1040 * if we can't use the preferred mode go look for the
1041 * best one we can support
1042 */
1043 if (sc->sc_videomode == NULL) {
1044 struct videomode *m = sc->sc_ei.edid_modes;
1045
1046 sort_modes(sc->sc_ei.edid_modes,
1047 &sc->sc_ei.edid_preferred_mode,
1048 sc->sc_ei.edid_nmodes);
1049 if (sc->sc_videomode == NULL)
1050 for (int n = 0; n < sc->sc_ei.edid_nmodes; n++)
1051 if (MODE_IS_VALID(&m[n])) {
1052 sc->sc_videomode = &m[n];
1053 break;
1054 }
1055 }
1056 }
1057 if (sc->sc_videomode == NULL) {
1058 /* no EDID data? */
1059 sc->sc_videomode = pick_mode_by_ref(sc->sc_width,
1060 sc->sc_height, 60);
1061 }
1062 if (sc->sc_videomode != NULL) {
1063 pm3fb_set_mode(sc, sc->sc_videomode);
1064 }
1065 }
1066
1067 /* I2C bitbanging */
1068 static void pm3fb_i2cbb_set_bits(void *cookie, uint32_t bits)
1069 {
1070 struct pm3fb_softc *sc = cookie;
1071 uint32_t out;
1072
1073 out = bits << 2; /* bitmasks match the IN bits */
1074
1075 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_DISPLAY_DATA, out);
1076 delay(100);
1077 }
1078
1079 static void pm3fb_i2cbb_set_dir(void *cookie, uint32_t dir)
1080 {
1081 /* Nothing to do */
1082 }
1083
1084 static uint32_t pm3fb_i2cbb_read(void *cookie)
1085 {
1086 struct pm3fb_softc *sc = cookie;
1087 uint32_t bits;
1088
1089 bits = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_DISPLAY_DATA);
1090 return bits;
1091 }
1092
1093 /* higher level I2C stuff */
1094 static int
1095 pm3fb_i2c_send_start(void *cookie, int flags)
1096 {
1097
1098 return (i2c_bitbang_send_start(cookie, flags, &pm3fb_i2cbb_ops));
1099 }
1100
1101 static int
1102 pm3fb_i2c_send_stop(void *cookie, int flags)
1103 {
1104
1105 return (i2c_bitbang_send_stop(cookie, flags, &pm3fb_i2cbb_ops));
1106 }
1107
1108 static int
1109 pm3fb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
1110 {
1111
1112 return (i2c_bitbang_initiate_xfer(cookie, addr, flags,
1113 &pm3fb_i2cbb_ops));
1114 }
1115
1116 static int
1117 pm3fb_i2c_read_byte(void *cookie, uint8_t *valp, int flags)
1118 {
1119
1120 return (i2c_bitbang_read_byte(cookie, valp, flags, &pm3fb_i2cbb_ops));
1121 }
1122
1123 static int
1124 pm3fb_i2c_write_byte(void *cookie, uint8_t val, int flags)
1125 {
1126 return (i2c_bitbang_write_byte(cookie, val, flags, &pm3fb_i2cbb_ops));
1127 }
1128
1129 static int
1130 pm3fb_set_pll(struct pm3fb_softc *sc, int freq)
1131 {
1132 uint8_t bf = 0, bpre = 0, bpost = 0;
1133 int count;
1134 unsigned long feedback, prescale, postscale, IntRef, VCO, out_freq, diff, VCOlow, VCOhigh, bdiff = 1000000;
1135
1136 freq *= 10; /* convert into 100Hz units */
1137
1138 for (postscale = 0; postscale <= 5; postscale++) {
1139 /*
1140 * It is pointless going through the main loop if all values of
1141 * prescale produce an VCO outside the acceptable range
1142 */
1143 prescale = 1;
1144 feedback = (prescale * (1UL << postscale) * freq) / (2 * PM3_EXT_CLOCK_FREQ);
1145 VCOlow = (2 * PM3_EXT_CLOCK_FREQ * feedback) / prescale;
1146 if (VCOlow > PM3_VCO_FREQ_MAX)
1147 continue;
1148
1149 prescale = 255;
1150 feedback = (prescale * (1UL << postscale) * freq) / (2 * PM3_EXT_CLOCK_FREQ);
1151 VCOhigh = (2 * PM3_EXT_CLOCK_FREQ * feedback) / prescale;
1152 if (VCOhigh < PM3_VCO_FREQ_MIN)
1153 continue;
1154
1155 for (prescale = 1; prescale <= 255; prescale++) {
1156 IntRef = PM3_EXT_CLOCK_FREQ / prescale;
1157 if (IntRef < PM3_INTREF_MIN || IntRef > PM3_INTREF_MAX) {
1158 if (IntRef > PM3_INTREF_MAX) {
1159 /*
1160 * Hopefully we will get into range as the prescale
1161 * value increases
1162 */
1163 continue;
1164 } else {
1165 /*
1166 * already below minimum and it will only get worse
1167 * move to the next postscale value
1168 */
1169 break;
1170 }
1171 }
1172
1173 feedback = (prescale * (1UL << postscale) * freq) / (2 * PM3_EXT_CLOCK_FREQ);
1174
1175 if (feedback > 255) {
1176 /*
1177 * prescale, feedbackscale & postscale registers
1178 * are only 8 bits wide
1179 */
1180 break;
1181 } else if (feedback == 255) {
1182 count = 1;
1183 } else {
1184 count = 2;
1185 }
1186
1187 do {
1188 VCO = (2 * PM3_EXT_CLOCK_FREQ * feedback) / prescale;
1189 if (VCO >= PM3_VCO_FREQ_MIN && VCO <= PM3_VCO_FREQ_MAX) {
1190 out_freq = VCO / (1UL << postscale);
1191 diff = abs(out_freq - freq);
1192 if (diff < bdiff) {
1193 bdiff = diff;
1194 bf = feedback;
1195 bpre = prescale;
1196 bpost = postscale;
1197 if (diff == 0)
1198 goto out;
1199 }
1200 }
1201 feedback++;
1202 } while (--count >= 0);
1203 }
1204 }
1205 out:
1206 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_CLOCK0_PRE_SCALE, bpre);
1207 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_CLOCK0_FEEDBACK_SCALE, bf);
1208 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_CLOCK0_POST_SCALE, bpost);
1209 return 0;
1210 }
1211
1212 static void
1213 pm3fb_set_mode(struct pm3fb_softc *sc, const struct videomode *mode)
1214 {
1215 int t1, t2, t3, t4, stride;
1216 uint32_t vclk, tmp1;
1217 uint8_t sync = 0;
1218
1219 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_BYPASS_MASK, 0xffffffff);
1220 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_APERTURE1_CONTROL, 0x00000000);
1221 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_APERTURE2_CONTROL, 0x00000000);
1222 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FIFODISCONNECT, 0x00000007);
1223
1224 t1 = mode->hsync_start - mode->hdisplay;
1225 t2 = mode->vsync_start - mode->vdisplay;
1226 t3 = mode->hsync_end - mode->hsync_start;
1227 t4 = mode->vsync_end - mode->vsync_start;
1228 stride = (mode->hdisplay + 31) & ~31;
1229
1230 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_TOTAL,
1231 ((mode->htotal - 1) >> 4));
1232 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_SYNC_END,
1233 (t1 + t3) >> 4);
1234 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_SYNC_START,
1235 (t1 >> 4));
1236 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_BLANK_END,
1237 (mode->htotal - mode->hdisplay) >> 4);
1238 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_HORIZ_GATE_END,
1239 (mode->htotal - mode->hdisplay) >> 4);
1240 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCREEN_STRIDE,
1241 (stride >> 4));
1242
1243 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1244 PM3_VERT_TOTAL, mode->vtotal - 1);
1245 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1246 PM3_VERT_SYNC_END, t2 + t4 - 1);
1247 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1248 PM3_VERT_SYNC_START, t2 - 1);
1249 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1250 PM3_VERT_BLANK_END, mode->vtotal - mode->vdisplay);
1251
1252 /*8bpp*/
1253 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1254 PM3_BYAPERTURE1MODE, PM3_BYAPERTUREMODE_PIXELSIZE_8BIT);
1255 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1256 PM3_BYAPERTURE2MODE, PM3_BYAPERTUREMODE_PIXELSIZE_8BIT);
1257 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_VIDEO_CONTROL,
1258 (PM3_VC_ENABLE | PM3_VC_HSC_ACTIVE_HIGH | PM3_VC_VSC_ACTIVE_HIGH | PM3_VC_PIXELSIZE_8BIT));
1259
1260 vclk = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_V_CLOCK_CTL);
1261 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_V_CLOCK_CTL, (vclk & 0xFFFFFFFC));
1262 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_SCREEN_BASE, 0x0);
1263
1264 tmp1 = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM3_CHIP_CONFIG);
1265 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_CHIP_CONFIG, tmp1 & 0xFFFFFFFD);
1266
1267 pm3fb_set_pll(sc, mode->dot_clock);
1268
1269 if (mode->flags & VID_PHSYNC)
1270 sync |= PM3_SC_HSYNC_ACTIVE_HIGH;
1271 if (mode->flags & VID_PVSYNC)
1272 sync |= PM3_SC_VSYNC_ACTIVE_HIGH;
1273
1274 bus_space_write_4(sc->sc_memt, sc->sc_regh,
1275 PM3_RD_PM3_INDEX_CONTROL, PM3_INCREMENT_DISABLE);
1276 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_SYNC_CONTROL, sync);
1277 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_DAC_CONTROL, 0x00);
1278
1279 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_PIXEL_SIZE, PM3_DACPS_8BIT);
1280 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_COLOR_FORMAT,
1281 (PM3_CF_ORDER_BGR | PM3_CF_VISUAL_256_COLOR));
1282 pm3fb_write_dac(sc, PM3_RAMDAC_CMD_MISC_CONTROL, PM3_MC_DAC_SIZE_8BIT);
1283
1284 bus_space_write_4(sc->sc_memt, sc->sc_regh, PM3_FIFOCONTROL, 0x00000905);
1285
1286 sc->sc_width = mode->hdisplay;
1287 sc->sc_height = mode->vdisplay;
1288 sc->sc_depth = 8;
1289 sc->sc_stride = stride;
1290 aprint_normal_dev(sc->sc_dev, "pm3 using %d x %d in 8 bit, stride %d\n",
1291 sc->sc_width, sc->sc_height, stride);
1292 }
1293