1/*	$NetBSD: pm2fb.c,v 1.35 2022/09/25 17:52:25 thorpej Exp $	*/
2
3/*
4 * Copyright (c) 2009, 2012 Michael Lorenz
5 * 		 2014 Naruaki Etomi
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * A console driver for Permedia 2 graphics controllers
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: pm2fb.c,v 1.35 2022/09/25 17:52:25 thorpej Exp $");
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/device.h>
40#include <sys/lwp.h>
41#include <sys/kauth.h>
42#include <sys/atomic.h>
43
44#include <dev/videomode/videomode.h>
45
46#include <dev/pci/pcivar.h>
47#include <dev/pci/pcireg.h>
48#include <dev/pci/pcidevs.h>
49#include <dev/pci/pciio.h>
50#include <dev/pci/pm2reg.h>
51
52#include <dev/wscons/wsdisplayvar.h>
53#include <dev/wscons/wsconsio.h>
54#include <dev/wsfont/wsfont.h>
55#include <dev/rasops/rasops.h>
56#include <dev/wscons/wsdisplay_vconsvar.h>
57#include <dev/wscons/wsdisplay_glyphcachevar.h>
58#include <dev/pci/wsdisplay_pci.h>
59
60#include <dev/i2c/i2cvar.h>
61#include <dev/i2c/i2c_bitbang.h>
62#include <dev/i2c/ddcvar.h>
63#include <dev/videomode/videomode.h>
64#include <dev/videomode/edidvar.h>
65#include <dev/videomode/edidreg.h>
66
67#include "opt_pm2fb.h"
68
69#ifdef PM2FB_DEBUG
70#define DPRINTF aprint_error
71#else
72#define DPRINTF while (0) printf
73#endif
74
75#if BYTE_ORDER == LITTLE_ENDIAN
76/*
77 * XXX
78 * A temporary workaround for unaligned blits on little endian hardware.
79 * This makes pm2fb_bitblt() work well on little endian hardware to get
80 * scrolling right, but not much more. Unaligned blits ( as in, where the lower
81 * 2 bits of the source and destination X coordinates don't match ) are still
82 * wrong so the glyph cache is also disabled.
83 */
84#define BITBLT_LE_WORKAROUND
85#endif
86
87struct pm2fb_softc {
88	device_t sc_dev;
89
90	pci_chipset_tag_t sc_pc;
91	pcitag_t sc_pcitag;
92
93	bus_space_tag_t sc_memt;
94	bus_space_tag_t sc_iot;
95
96	bus_space_handle_t sc_regh;
97	bus_addr_t sc_fb, sc_reg;
98	bus_size_t sc_fbsize, sc_regsize;
99
100	int sc_width, sc_height, sc_depth, sc_stride;
101	int sc_locked;
102	struct vcons_screen sc_console_screen;
103	struct wsscreen_descr sc_defaultscreen_descr;
104	const struct wsscreen_descr *sc_screens[1];
105	struct wsscreen_list sc_screenlist;
106	struct vcons_data vd;
107	int sc_mode;
108	u_char sc_cmap_red[256];
109	u_char sc_cmap_green[256];
110	u_char sc_cmap_blue[256];
111	/* engine stuff */
112	uint32_t sc_pprod;
113	int sc_is_pm2;
114	/* i2c stuff */
115	struct i2c_controller sc_i2c;
116	uint8_t sc_edid_data[128];
117	struct edid_info sc_ei;
118	const struct videomode *sc_videomode;
119	glyphcache sc_gc;
120};
121
122static int	pm2fb_match(device_t, cfdata_t, void *);
123static void	pm2fb_attach(device_t, device_t, void *);
124
125CFATTACH_DECL_NEW(pm2fb, sizeof(struct pm2fb_softc),
126    pm2fb_match, pm2fb_attach, NULL, NULL);
127
128extern const u_char rasops_cmap[768];
129
130static int	pm2fb_ioctl(void *, void *, u_long, void *, int,
131			     struct lwp *);
132static paddr_t	pm2fb_mmap(void *, void *, off_t, int);
133static void	pm2fb_init_screen(void *, struct vcons_screen *, int, long *);
134
135static int	pm2fb_putcmap(struct pm2fb_softc *, struct wsdisplay_cmap *);
136static int 	pm2fb_getcmap(struct pm2fb_softc *, struct wsdisplay_cmap *);
137static void	pm2fb_init_palette(struct pm2fb_softc *);
138static int 	pm2fb_putpalreg(struct pm2fb_softc *, uint8_t, uint8_t,
139			    uint8_t, uint8_t);
140
141static void	pm2fb_init(struct pm2fb_softc *);
142static inline void pm2fb_wait(struct pm2fb_softc *, int);
143static void	pm2fb_flush_engine(struct pm2fb_softc *);
144static void	pm2fb_rectfill(struct pm2fb_softc *, int, int, int, int,
145			    uint32_t);
146static void	pm2fb_rectfill_a(void *, int, int, int, int, long);
147static void	pm2fb_bitblt(void *, int, int, int, int, int, int, int);
148
149static void	pm2fb_cursor(void *, int, int, int);
150static void	pm2fb_putchar(void *, int, int, u_int, long);
151static void	pm2fb_putchar_aa(void *, int, int, u_int, long);
152static void	pm2fb_copycols(void *, int, int, int, int);
153static void	pm2fb_erasecols(void *, int, int, int, long);
154static void	pm2fb_copyrows(void *, int, int, int);
155static void	pm2fb_eraserows(void *, int, int, long);
156
157struct wsdisplay_accessops pm2fb_accessops = {
158	pm2fb_ioctl,
159	pm2fb_mmap,
160	NULL,	/* alloc_screen */
161	NULL,	/* free_screen */
162	NULL,	/* show_screen */
163	NULL, 	/* load_font */
164	NULL,	/* pollc */
165	NULL	/* scroll */
166};
167
168/* I2C glue */
169static int pm2fb_i2c_send_start(void *, int);
170static int pm2fb_i2c_send_stop(void *, int);
171static int pm2fb_i2c_initiate_xfer(void *, i2c_addr_t, int);
172static int pm2fb_i2c_read_byte(void *, uint8_t *, int);
173static int pm2fb_i2c_write_byte(void *, uint8_t, int);
174
175/* I2C bitbang glue */
176static void pm2fb_i2cbb_set_bits(void *, uint32_t);
177static void pm2fb_i2cbb_set_dir(void *, uint32_t);
178static uint32_t pm2fb_i2cbb_read(void *);
179
180static void pm2_setup_i2c(struct pm2fb_softc *);
181
182static const struct i2c_bitbang_ops pm2fb_i2cbb_ops = {
183	pm2fb_i2cbb_set_bits,
184	pm2fb_i2cbb_set_dir,
185	pm2fb_i2cbb_read,
186	{
187		PM2_DD_SDA_IN,
188		PM2_DD_SCL_IN,
189		0,
190		0
191	}
192};
193
194/* mode setting stuff */
195static int pm2fb_set_pll(struct pm2fb_softc *, int);
196static int pm2vfb_set_pll(struct pm2fb_softc *, int);
197static uint8_t pm2fb_read_dac(struct pm2fb_softc *, int);
198static void pm2fb_write_dac(struct pm2fb_softc *, int, uint8_t);
199static void pm2fb_set_mode(struct pm2fb_softc *, const struct videomode *);
200
201const struct {
202	int vendor;
203	int product;
204	int flags;
205} pm2fb_pci_devices[] = {
206	{
207		PCI_VENDOR_3DLABS,
208		PCI_PRODUCT_3DLABS_PERMEDIA2V,
209		0
210	},
211	{
212		PCI_VENDOR_TI,
213		PCI_PRODUCT_TI_TVP4020,
214		1
215	},
216	{
217		0,
218		0,
219		0
220	}
221};
222
223/* this table is from xf86-video-glint */
224#define PARTPROD(a,b,c) (((a)<<6) | ((b)<<3) | (c))
225int partprodPermedia[] = {
226	-1,
227	PARTPROD(0,0,1), PARTPROD(0,1,1), PARTPROD(1,1,1), PARTPROD(1,1,2),
228	PARTPROD(1,2,2), PARTPROD(2,2,2), PARTPROD(1,2,3), PARTPROD(2,2,3),
229	PARTPROD(1,3,3), PARTPROD(2,3,3), PARTPROD(1,2,4), PARTPROD(3,3,3),
230	PARTPROD(1,3,4), PARTPROD(2,3,4),              -1, PARTPROD(3,3,4),
231	PARTPROD(1,4,4), PARTPROD(2,4,4),              -1, PARTPROD(3,4,4),
232	             -1, PARTPROD(2,3,5),              -1, PARTPROD(4,4,4),
233	PARTPROD(1,4,5), PARTPROD(2,4,5), PARTPROD(3,4,5),              -1,
234	             -1,              -1,              -1, PARTPROD(4,4,5),
235	PARTPROD(1,5,5), PARTPROD(2,5,5),              -1, PARTPROD(3,5,5),
236	             -1,              -1,              -1, PARTPROD(4,5,5),
237	             -1,              -1,              -1, PARTPROD(3,4,6),
238	             -1,              -1,              -1, PARTPROD(5,5,5),
239	PARTPROD(1,5,6), PARTPROD(2,5,6),              -1, PARTPROD(3,5,6),
240	             -1,              -1,              -1, PARTPROD(4,5,6),
241	             -1,              -1,              -1,              -1,
242	             -1,              -1,              -1, PARTPROD(5,5,6),
243	             -1,              -1,              -1,              -1,
244	             -1,              -1,              -1,              -1,
245	             -1,              -1,              -1,              -1,
246	             -1,              -1,              -1,              -1,
247	             -1,              -1,              -1,              -1,
248	             -1,              -1,              -1,              -1,
249	             -1,              -1,              -1,              -1,
250	             -1,              -1,              -1,              -1,
251	             -1,              -1,              -1,              -1,
252	             -1,              -1,              -1,              -1,
253	             -1,              -1,              -1,              -1,
254	             -1,              -1,              -1,              -1,
255	             -1,              -1,              -1,              -1,
256	             -1,              -1,              -1,              -1,
257	             -1,              -1,              -1,              -1,
258	             -1,              -1,              -1,              -1,
259		     0};
260
261static inline void
262pm2fb_wait(struct pm2fb_softc *sc, int slots)
263{
264	uint32_t reg;
265
266	do {
267		reg = bus_space_read_4(sc->sc_memt, sc->sc_regh,
268			PM2_INPUT_FIFO_SPACE);
269	} while (reg <= slots);
270}
271
272static void
273pm2fb_flush_engine(struct pm2fb_softc *sc)
274{
275
276	pm2fb_wait(sc, 2);
277
278	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_FILTER_MODE,
279	    PM2FLT_PASS_SYNC);
280	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SYNC, 0);
281	do {
282		while (bus_space_read_4(sc->sc_memt, sc->sc_regh,
283			PM2_OUTPUT_FIFO_WORDS) == 0);
284	} while (bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_OUTPUT_FIFO) !=
285	    PM2_SYNC_TAG);
286}
287
288static int
289pm2fb_match(device_t parent, cfdata_t match, void *aux)
290{
291	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
292	int i;
293
294	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
295		return 0;
296
297	for (i = 0; pm2fb_pci_devices[i].vendor; i++) {
298		if ((PCI_VENDOR(pa->pa_id) == pm2fb_pci_devices[i].vendor &&
299		     PCI_PRODUCT(pa->pa_id) == pm2fb_pci_devices[i].product))
300			return 100;
301	}
302
303	return (0);
304}
305
306static void
307pm2fb_attach(device_t parent, device_t self, void *aux)
308{
309	struct pm2fb_softc	*sc = device_private(self);
310	struct pci_attach_args	*pa = aux;
311	struct rasops_info	*ri;
312	struct wsemuldisplaydev_attach_args aa;
313	prop_dictionary_t	dict;
314	unsigned long		defattr;
315	bool			is_console = FALSE;
316	uint32_t		flags;
317	int			i;
318
319	sc->sc_pc = pa->pa_pc;
320	sc->sc_pcitag = pa->pa_tag;
321	sc->sc_memt = pa->pa_memt;
322	sc->sc_iot = pa->pa_iot;
323	sc->sc_dev = self;
324
325	for (i = 0; pm2fb_pci_devices[i].vendor; i++) {
326		if (PCI_PRODUCT(pa->pa_id) == pm2fb_pci_devices[i].product) {
327			sc->sc_is_pm2 = pm2fb_pci_devices[i].flags ;
328			break;
329		}
330	}
331
332	pci_aprint_devinfo(pa, NULL);
333
334	/*
335	 * fill in parameters from properties
336	 * if we can't get a usable mode via DDC2 we'll use this to pick one,
337	 * which is why we fill them in with some conservative values that
338	 * hopefully work as a last resort
339	 */
340	dict = device_properties(self);
341	if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) {
342		aprint_error("%s: no width property\n", device_xname(self));
343		sc->sc_width = 1024;
344	}
345	if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) {
346		aprint_error("%s: no height property\n", device_xname(self));
347		sc->sc_height = 768;
348	}
349	if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
350		aprint_error("%s: no depth property\n", device_xname(self));
351		sc->sc_depth = 8;
352	}
353
354	/*
355	 * don't look at the linebytes property - The Raptor firmware lies
356	 * about it. Get it from width * depth >> 3 instead.
357	 */
358
359	sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3);
360
361	prop_dictionary_get_bool(dict, "is_console", &is_console);
362
363	pci_mapreg_info(pa->pa_pc, pa->pa_tag, 0x14, PCI_MAPREG_TYPE_MEM,
364	    &sc->sc_fb, &sc->sc_fbsize, &flags);
365
366	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, 0,
367	    &sc->sc_memt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) {
368		aprint_error("%s: failed to map registers.\n",
369		    device_xname(sc->sc_dev));
370	}
371
372	/*
373	 * XXX yeah, casting the fb address to uint32_t is formally wrong
374	 * but as far as I know there are no PM2 with 64bit BARs
375	 */
376	aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self),
377	    (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
378
379	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
380		"default",
381		0, 0,
382		NULL,
383		8, 16,
384		WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
385		NULL
386	};
387	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
388	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
389	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
390	sc->sc_locked = 0;
391
392	pm2_setup_i2c(sc);
393
394	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
395	    &pm2fb_accessops);
396	sc->vd.init_screen = pm2fb_init_screen;
397
398	/* init engine here */
399	pm2fb_init(sc);
400
401	ri = &sc->sc_console_screen.scr_ri;
402
403	sc->sc_gc.gc_bitblt = pm2fb_bitblt;
404	sc->sc_gc.gc_rectfill = pm2fb_rectfill_a;
405	sc->sc_gc.gc_blitcookie = sc;
406	sc->sc_gc.gc_rop = 3;
407
408#ifdef PM2FB_DEBUG
409	/*
410	 * leave some room at the bottom of the screen for various blitter
411	 * tests and in order to make the glyph cache visible
412	 */
413	sc->sc_height -= 200;
414#endif
415
416	if (is_console) {
417		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
418		    &defattr);
419		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
420
421		pm2fb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
422		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
423		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
424		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
425		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
426		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
427
428		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
429			uimin(2047, (sc->sc_fbsize / sc->sc_stride))
430			 - sc->sc_height - 5,
431			sc->sc_width,
432			ri->ri_font->fontwidth,
433			ri->ri_font->fontheight,
434			defattr);
435		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
436		    defattr);
437		vcons_replay_msgbuf(&sc->sc_console_screen);
438	} else {
439		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
440			/* do some minimal setup to avoid weirdnesses later */
441			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
442			   &defattr);
443		} else
444			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
445		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
446			   uimin(2047, (sc->sc_fbsize / sc->sc_stride))
447			    - sc->sc_height - 5,
448			   sc->sc_width,
449			   ri->ri_font->fontwidth,
450			   ri->ri_font->fontheight,
451			   defattr);
452	}
453
454	pm2fb_init_palette(sc);
455
456	aa.console = is_console;
457	aa.scrdata = &sc->sc_screenlist;
458	aa.accessops = &pm2fb_accessops;
459	aa.accesscookie = &sc->vd;
460
461	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
462
463#ifdef PM2FB_DEBUG
464	/*
465	 * draw a pattern to check if pm2fb_bitblt() gets the alignment stuff
466	 * right
467	 */
468	pm2fb_rectfill(sc, 0, sc->sc_height, sc->sc_width, 200, 0xffffffff);
469	pm2fb_rectfill(sc, 0, sc->sc_height, 300, 10, 0);
470	pm2fb_rectfill(sc, 10, sc->sc_height, 200, 10, 0xe0e0e0e0);
471	for (i = 1; i < 20; i++) {
472		pm2fb_bitblt(sc, 0, sc->sc_height,
473			i, sc->sc_height + 10 * i,
474			300, 10, 3);
475		pm2fb_bitblt(sc, i, sc->sc_height,
476			400, sc->sc_height + 10 * i,
477			300, 10, 3);
478	}
479#endif
480}
481
482static int
483pm2fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
484	struct lwp *l)
485{
486	struct vcons_data *vd = v;
487	struct pm2fb_softc *sc = vd->cookie;
488	struct wsdisplay_fbinfo *wdf;
489	struct vcons_screen *ms = vd->active;
490
491	switch (cmd) {
492	case WSDISPLAYIO_GTYPE:
493		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
494		return 0;
495
496	/* PCI config read/write passthrough. */
497	case PCI_IOC_CFGREAD:
498	case PCI_IOC_CFGWRITE:
499		return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
500		    cmd, data, flag, l);
501
502	case WSDISPLAYIO_GET_BUSID:
503		return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
504		    sc->sc_pcitag, data);
505
506	case WSDISPLAYIO_GINFO:
507		if (ms == NULL)
508			return ENODEV;
509		wdf = (void *)data;
510		wdf->height = ms->scr_ri.ri_height;
511		wdf->width = ms->scr_ri.ri_width;
512		wdf->depth = ms->scr_ri.ri_depth;
513		wdf->cmsize = 256;
514		return 0;
515
516	case WSDISPLAYIO_GETCMAP:
517		return pm2fb_getcmap(sc,
518		    (struct wsdisplay_cmap *)data);
519
520	case WSDISPLAYIO_PUTCMAP:
521		return pm2fb_putcmap(sc,
522		    (struct wsdisplay_cmap *)data);
523
524	case WSDISPLAYIO_LINEBYTES:
525		*(u_int *)data = sc->sc_stride;
526		return 0;
527
528	case WSDISPLAYIO_SMODE: {
529		int new_mode = *(int*)data;
530		if (new_mode != sc->sc_mode) {
531			sc->sc_mode = new_mode;
532			if(new_mode == WSDISPLAYIO_MODE_EMUL) {
533				/* first set the video mode */
534				if (sc->sc_videomode != NULL) {
535					pm2fb_set_mode(sc, sc->sc_videomode);
536				}
537				/* then initialize the drawing engine */
538				pm2fb_init(sc);
539				pm2fb_init_palette(sc);
540				/* clean out the glyph cache */
541				glyphcache_wipe(&sc->sc_gc);
542				/* and redraw everything */
543				vcons_redraw_screen(ms);
544			} else
545				pm2fb_flush_engine(sc);
546		}
547		}
548		return 0;
549	case WSDISPLAYIO_GET_EDID: {
550		struct wsdisplayio_edid_info *d = data;
551		d->data_size = 128;
552		if (d->buffer_size < 128)
553			return EAGAIN;
554		return copyout(sc->sc_edid_data, d->edid_data, 128);
555	}
556
557	case WSDISPLAYIO_GET_FBINFO: {
558		struct wsdisplayio_fbinfo *fbi = data;
559		return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
560	}
561	}
562	return EPASSTHROUGH;
563}
564
565static paddr_t
566pm2fb_mmap(void *v, void *vs, off_t offset, int prot)
567{
568	struct vcons_data *vd = v;
569	struct pm2fb_softc *sc = vd->cookie;
570	paddr_t pa;
571
572	/* 'regular' framebuffer mmap()ing */
573	if (offset < sc->sc_fbsize) {
574		pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot,
575		    BUS_SPACE_MAP_LINEAR);
576		return pa;
577	}
578
579	/*
580	 * restrict all other mappings to processes with superuser privileges
581	 * or the kernel itself
582	 */
583	if (kauth_authorize_machdep(kauth_cred_get(),
584	    KAUTH_MACHDEP_UNMANAGEDMEM,
585	    NULL, NULL, NULL, NULL) != 0) {
586		aprint_normal("%s: mmap() rejected.\n",
587		    device_xname(sc->sc_dev));
588		return -1;
589	}
590
591	if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
592		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
593		    BUS_SPACE_MAP_LINEAR);
594		return pa;
595	}
596
597	if ((offset >= sc->sc_reg) &&
598	    (offset < (sc->sc_reg + sc->sc_regsize))) {
599		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
600		    BUS_SPACE_MAP_LINEAR);
601		return pa;
602	}
603	/* XXX 2nd fb BAR? */
604
605#ifdef PCI_MAGIC_IO_RANGE
606	/* allow mapping of IO space */
607	if ((offset >= PCI_MAGIC_IO_RANGE) &&
608	    (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
609		pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
610		    0, prot, BUS_SPACE_MAP_LINEAR);
611		return pa;
612	}
613#endif
614
615	return -1;
616}
617
618static void
619pm2fb_init_screen(void *cookie, struct vcons_screen *scr,
620    int existing, long *defattr)
621{
622	struct pm2fb_softc *sc = cookie;
623	struct rasops_info *ri = &scr->scr_ri;
624
625	ri->ri_depth = sc->sc_depth;
626	ri->ri_width = sc->sc_width;
627	ri->ri_height = sc->sc_height;
628	ri->ri_stride = sc->sc_stride;
629	ri->ri_flg = RI_CENTER;
630	if (sc->sc_depth == 8)
631		ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
632
633	rasops_init(ri, 0, 0);
634	ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_UNDERLINE;
635
636	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
637		    sc->sc_width / ri->ri_font->fontwidth);
638
639	ri->ri_hw = scr;
640	ri->ri_ops.copyrows = pm2fb_copyrows;
641	ri->ri_ops.copycols = pm2fb_copycols;
642	ri->ri_ops.cursor = pm2fb_cursor;
643	ri->ri_ops.eraserows = pm2fb_eraserows;
644	ri->ri_ops.erasecols = pm2fb_erasecols;
645	if (FONT_IS_ALPHA(ri->ri_font)) {
646		ri->ri_ops.putchar = pm2fb_putchar_aa;
647	} else
648		ri->ri_ops.putchar = pm2fb_putchar;
649}
650
651static int
652pm2fb_putcmap(struct pm2fb_softc *sc, struct wsdisplay_cmap *cm)
653{
654	u_char *r, *g, *b;
655	u_int index = cm->index;
656	u_int count = cm->count;
657	int i, error;
658	u_char rbuf[256], gbuf[256], bbuf[256];
659
660#ifdef PM2FB_DEBUG
661	aprint_debug("putcmap: %d %d\n",index, count);
662#endif
663	if (cm->index >= 256 || cm->count > 256 ||
664	    (cm->index + cm->count) > 256)
665		return EINVAL;
666	error = copyin(cm->red, &rbuf[index], count);
667	if (error)
668		return error;
669	error = copyin(cm->green, &gbuf[index], count);
670	if (error)
671		return error;
672	error = copyin(cm->blue, &bbuf[index], count);
673	if (error)
674		return error;
675
676	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
677	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
678	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
679
680	r = &sc->sc_cmap_red[index];
681	g = &sc->sc_cmap_green[index];
682	b = &sc->sc_cmap_blue[index];
683
684	for (i = 0; i < count; i++) {
685		pm2fb_putpalreg(sc, index, *r, *g, *b);
686		index++;
687		r++, g++, b++;
688	}
689	return 0;
690}
691
692static int
693pm2fb_getcmap(struct pm2fb_softc *sc, struct wsdisplay_cmap *cm)
694{
695	u_int index = cm->index;
696	u_int count = cm->count;
697	int error;
698
699	if (index >= 255 || count > 256 || index + count > 256)
700		return EINVAL;
701
702	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
703	if (error)
704		return error;
705	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
706	if (error)
707		return error;
708	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
709	if (error)
710		return error;
711
712	return 0;
713}
714
715static void
716pm2fb_init_palette(struct pm2fb_softc *sc)
717{
718	struct rasops_info *ri = &sc->sc_console_screen.scr_ri;
719	int i, j = 0;
720	uint8_t cmap[768];
721
722	rasops_get_cmap(ri, cmap, sizeof(cmap));
723	for (i = 0; i < 256; i++) {
724		sc->sc_cmap_red[i] = cmap[j];
725		sc->sc_cmap_green[i] = cmap[j + 1];
726		sc->sc_cmap_blue[i] = cmap[j + 2];
727		pm2fb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
728		j += 3;
729	}
730}
731
732static int
733pm2fb_putpalreg(struct pm2fb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
734    uint8_t b)
735{
736	bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_PAL_WRITE_IDX, idx);
737	bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, r);
738	bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, g);
739	bus_space_write_1(sc->sc_memt, sc->sc_regh, PM2_DAC_DATA, b);
740	return 0;
741}
742
743static uint8_t
744pm2fb_read_dac(struct pm2fb_softc *sc, int reg)
745{
746	if (sc->sc_is_pm2) {
747		bus_space_write_1(sc->sc_memt, sc->sc_regh,
748		    PM2_DAC_PAL_WRITE_IDX, reg);
749		return bus_space_read_1(sc->sc_memt, sc->sc_regh,
750		    PM2_DAC_INDEX_DATA);
751	} else {
752		bus_space_write_1(sc->sc_memt, sc->sc_regh,
753		    PM2V_DAC_INDEX_LOW, reg & 0xff);
754		bus_space_write_1(sc->sc_memt, sc->sc_regh,
755		    PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff);
756		return bus_space_read_1(sc->sc_memt, sc->sc_regh,
757		    PM2V_DAC_INDEX_DATA);
758	}
759}
760
761static void
762pm2fb_write_dac(struct pm2fb_softc *sc, int reg, uint8_t data)
763{
764	pm2fb_wait(sc, 3);
765	if (sc->sc_is_pm2) {
766		pm2fb_wait(sc, 2);
767		bus_space_write_1(sc->sc_memt, sc->sc_regh,
768		    PM2_DAC_PAL_WRITE_IDX, reg);
769		bus_space_write_1(sc->sc_memt, sc->sc_regh,
770		    PM2_DAC_INDEX_DATA, data);
771	} else {
772		pm2fb_wait(sc, 3);
773		bus_space_write_1(sc->sc_memt, sc->sc_regh,
774		    PM2V_DAC_INDEX_LOW, reg & 0xff);
775		bus_space_write_1(sc->sc_memt, sc->sc_regh,
776		    PM2V_DAC_INDEX_HIGH, (reg >> 8) & 0xff);
777		bus_space_write_1(sc->sc_memt, sc->sc_regh,
778		    PM2V_DAC_INDEX_DATA, data);
779	}
780}
781
782static void
783pm2fb_init(struct pm2fb_softc *sc)
784{
785	pm2fb_flush_engine(sc);
786
787	pm2fb_wait(sc, 9);
788	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_BASE, 0);
789	/* set aperture endianness */
790#if BYTE_ORDER == BIG_ENDIAN
791	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_APERTURE1_CONTROL,
792		PM2_AP_BYTESWAP | PM2_AP_HALFWORDSWAP);
793#else
794	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_APERTURE1_CONTROL, 0);
795#endif
796#if 0
797	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_BYPASS_MASK,
798		0xffffffff);
799	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_FB_WRITE_MASK,
800		0xffffffff);
801#endif
802	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HW_WRITEMASK,
803		0xffffffff);
804	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SW_WRITEMASK,
805		0xffffffff);
806	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_WRITE_MODE,
807		PM2WM_WRITE_EN);
808	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCREENSIZE,
809	    (sc->sc_height << 16) | sc->sc_width);
810	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MODE,
811	    PM2SC_SCREEN_EN);
812	pm2fb_wait(sc, 8);
813	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0);
814	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0);
815	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0);
816	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_COLOUR_MODE, 0);
817	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_ADDRESS_MODE, 0);
818	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_READ_MODE, 0);
819	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEX_LUT_MODE, 0);
820	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_YUV_MODE, 0);
821	pm2fb_wait(sc, 8);
822	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DEPTH_MODE, 0);
823	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DEPTH, 0);
824	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STENCIL_MODE, 0);
825	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STIPPLE_MODE, 0);
826	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ROP_MODE, 0);
827	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_WINDOW_ORIGIN, 0);
828#if 0
829	sc->sc_pprod = bus_space_read_4(sc->sc_memt, sc->sc_regh,
830	    PM2_FB_READMODE) &
831	    (PM2FB_PP0_MASK | PM2FB_PP1_MASK | PM2FB_PP2_MASK);
832#endif
833	sc->sc_pprod = partprodPermedia[sc->sc_stride >> 5];
834
835	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_FB_READMODE,
836	    sc->sc_pprod);
837	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_TEXMAP_FORMAT,
838	    sc->sc_pprod);
839	pm2fb_wait(sc, 9);
840	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DY, 1 << 16);
841	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DXDOM, 0);
842	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTXDOM, 0);
843	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTXSUB, 0);
844	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_STARTY, 0);
845	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_COUNT, 0);
846	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MINYX, 0);
847	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCISSOR_MAXYX,
848	    0x0fff0fff);
849	/*
850	 * another scissor we need to disable in order to blit into off-screen
851	 * memory
852	 */
853	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SCREENSIZE,
854	    0x0fff0fff);
855
856	switch(sc->sc_depth) {
857		case 8:
858			bus_space_write_4(sc->sc_memt, sc->sc_regh,
859			    PM2_RE_PIXEL_SIZE, PM2PS_8BIT);
860			break;
861		case 16:
862			bus_space_write_4(sc->sc_memt, sc->sc_regh,
863			    PM2_RE_PIXEL_SIZE, PM2PS_16BIT);
864			break;
865		case 32:
866			bus_space_write_4(sc->sc_memt, sc->sc_regh,
867			    PM2_RE_PIXEL_SIZE, PM2PS_32BIT);
868			break;
869	}
870	pm2fb_flush_engine(sc);
871	DPRINTF("pixel size: %08x\n",
872	    bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_RE_PIXEL_SIZE));
873}
874
875static void
876pm2fb_rectfill(struct pm2fb_softc *sc, int x, int y, int wi, int he,
877     uint32_t colour)
878{
879
880	pm2fb_wait(sc, 9);
881	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0);
882	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0);
883	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0);
884	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0);
885	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG,
886	    PM2RECFG_WRITE_EN);
887	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_BLOCK_COLOUR,
888	    colour);
889	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_START,
890	    (y << 16) | x);
891	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_SIZE,
892	    (he << 16) | wi);
893	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RENDER,
894	    PM2RE_RECTANGLE | PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL);
895}
896
897static void
898pm2fb_rectfill_a(void *cookie, int x, int y, int wi, int he, long attr)
899{
900	struct pm2fb_softc *sc = cookie;
901
902	pm2fb_rectfill(sc, x, y, wi, he,
903	    sc->vd.active->scr_ri.ri_devcmap[(attr >> 24 & 0xf)]);
904}
905
906static void
907pm2fb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
908    int wi, int he, int rop)
909{
910	struct pm2fb_softc *sc = cookie;
911	uint32_t dir = 0;
912	int rxd, rwi, rxdelta;
913
914	if (yd <= ys) {
915		dir |= PM2RE_INC_Y;
916	}
917	if (xd <= xs) {
918		dir |= PM2RE_INC_X;
919	}
920	pm2fb_wait(sc, 10);
921	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DDA_MODE, 0);
922	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0);
923	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE, 0);
924	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE, 0);
925	if (sc->sc_depth == 8) {
926		int adjust;
927		/*
928		 * use packed mode for some extra speed
929		 * this copies 32bit quantities even in 8 bit mode, so we need
930		 * to adjust for cases where the lower two bits in source and
931		 * destination X don't align, and/or where the width isn't a
932		 * multiple of 4
933		 */
934		if (rop == 3) {
935			bus_space_write_4(sc->sc_memt, sc->sc_regh,
936			    PM2_RE_CONFIG,
937			    PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN |
938			    PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6));
939		} else {
940			bus_space_write_4(sc->sc_memt, sc->sc_regh,
941			    PM2_RE_CONFIG,
942			    PM2RECFG_READ_SRC | PM2RECFG_READ_DST |
943			    PM2RECFG_WRITE_EN | PM2RECFG_PACKED |
944			    PM2RECFG_ROP_EN | (rop << 6));
945		}
946		rxd = xd >> 2;
947		rwi = (wi + 7) >> 2;
948		rxdelta = (xs & 0xffc) - (xd & 0xffc);
949		/* adjust for non-aligned x */
950#ifdef BITBLT_LE_WORKAROUND
951		/* I have no idea why this seems to work */
952		adjust = 1;
953#else
954		adjust = ((xd & 3) - (xs & 3));
955#endif
956		bus_space_write_4(sc->sc_memt, sc->sc_regh,
957		    PM2_RE_PACKEDDATA_LIMIT,
958		    (xd << 16) | (xd + wi) | (adjust << 29));
959
960	} else {
961		/* we're in 16 or 32bit mode */
962		if (rop == 3) {
963			bus_space_write_4(sc->sc_memt, sc->sc_regh,
964			    PM2_RE_CONFIG,
965			    PM2RECFG_READ_SRC | PM2RECFG_WRITE_EN |
966			    PM2RECFG_ROP_EN | PM2RECFG_PACKED | (rop << 6));
967		} else {
968			bus_space_write_4(sc->sc_memt, sc->sc_regh,
969			    PM2_RE_CONFIG,
970			    PM2RECFG_READ_SRC | PM2RECFG_READ_DST |
971			    PM2RECFG_WRITE_EN | PM2RECFG_PACKED |
972			    PM2RECFG_ROP_EN | (rop << 6));
973		}
974		rxd = xd;
975		rwi = wi;
976		rxdelta = xs - xd;
977	}
978	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_START,
979	    (yd << 16) | rxd);
980	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RECT_SIZE,
981	    (he << 16) | rwi);
982	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_SOURCE_DELTA,
983	    (((ys - yd) & 0xfff) << 16) | (rxdelta & 0xfff));
984	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_RENDER,
985	    PM2RE_RECTANGLE | dir);
986}
987
988static void
989pm2fb_cursor(void *cookie, int on, int row, int col)
990{
991	struct rasops_info *ri = cookie;
992	struct vcons_screen *scr = ri->ri_hw;
993	struct pm2fb_softc *sc = scr->scr_cookie;
994	int x, y, wi, he;
995
996	wi = ri->ri_font->fontwidth;
997	he = ri->ri_font->fontheight;
998
999	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1000		x = ri->ri_ccol * wi + ri->ri_xorigin;
1001		y = ri->ri_crow * he + ri->ri_yorigin;
1002		if (ri->ri_flg & RI_CURSOR) {
1003			pm2fb_bitblt(sc, x, y, x, y, wi, he, 12);
1004			ri->ri_flg &= ~RI_CURSOR;
1005		}
1006		ri->ri_crow = row;
1007		ri->ri_ccol = col;
1008		if (on) {
1009			x = ri->ri_ccol * wi + ri->ri_xorigin;
1010			y = ri->ri_crow * he + ri->ri_yorigin;
1011			pm2fb_bitblt(sc, x, y, x, y, wi, he, 12);
1012			ri->ri_flg |= RI_CURSOR;
1013		}
1014	} else {
1015		scr->scr_ri.ri_crow = row;
1016		scr->scr_ri.ri_ccol = col;
1017		scr->scr_ri.ri_flg &= ~RI_CURSOR;
1018	}
1019
1020}
1021
1022static void
1023pm2fb_putchar(void *cookie, int row, int col, u_int c, long attr)
1024{
1025	struct rasops_info *ri = cookie;
1026	struct wsdisplay_font *font = PICK_FONT(ri, c);
1027	struct vcons_screen *scr = ri->ri_hw;
1028	struct pm2fb_softc *sc = scr->scr_cookie;
1029	uint32_t mode;
1030
1031	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1032		void *data;
1033		uint32_t fg, bg;
1034		int uc, i;
1035		int x, y, wi, he;
1036
1037		wi = font->fontwidth;
1038		he = font->fontheight;
1039
1040		if (!CHAR_IN_FONT(c, font))
1041			return;
1042		bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1043		fg = ri->ri_devcmap[(attr >> 24) & 0xf];
1044		x = ri->ri_xorigin + col * wi;
1045		y = ri->ri_yorigin + row * he;
1046		if (c == 0x20) {
1047			pm2fb_rectfill(sc, x, y, wi, he, bg);
1048		} else {
1049			uc = c - font->firstchar;
1050			data = (uint8_t *)font->data + uc * ri->ri_fontscale;
1051
1052			mode = PM2RM_MASK_MIRROR;
1053#if BYTE_ORDER == LITTLE_ENDIAN
1054			switch (ri->ri_font->stride) {
1055				case 1:
1056					mode |= 4 << 7;
1057					break;
1058				case 2:
1059					mode |= 3 << 7;
1060					break;
1061			}
1062#else
1063			switch (ri->ri_font->stride) {
1064				case 1:
1065					mode |= 3 << 7;
1066					break;
1067				case 2:
1068					mode |= 2 << 7;
1069					break;
1070			}
1071#endif
1072			pm2fb_wait(sc, 8);
1073
1074			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1075			    PM2_RE_MODE, mode);
1076			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1077			    PM2_RE_CONFIG, PM2RECFG_WRITE_EN);
1078			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1079			    PM2_RE_BLOCK_COLOUR, bg);
1080			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1081			    PM2_RE_RECT_START, (y << 16) | x);
1082			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1083			    PM2_RE_RECT_SIZE, (he << 16) | wi);
1084			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1085			    PM2_RE_RENDER,
1086			    PM2RE_RECTANGLE |
1087			    PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL);
1088			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1089			    PM2_RE_BLOCK_COLOUR, fg);
1090			bus_space_write_4(sc->sc_memt, sc->sc_regh,
1091			    PM2_RE_RENDER,
1092			    PM2RE_RECTANGLE | PM2RE_SYNC_ON_MASK |
1093			    PM2RE_INC_X | PM2RE_INC_Y | PM2RE_FASTFILL);
1094
1095			pm2fb_wait(sc, he);
1096			switch (ri->ri_font->stride) {
1097			case 1: {
1098				uint8_t *data8 = data;
1099				uint32_t reg;
1100				for (i = 0; i < he; i++) {
1101					reg = *data8;
1102					bus_space_write_4(sc->sc_memt,
1103					    sc->sc_regh,
1104					    PM2_RE_BITMASK, reg);
1105					data8++;
1106				}
1107				break;
1108				}
1109			case 2: {
1110				uint16_t *data16 = data;
1111				uint32_t reg;
1112				for (i = 0; i < he; i++) {
1113					reg = *data16;
1114					bus_space_write_4(sc->sc_memt,
1115					    sc->sc_regh,
1116					    PM2_RE_BITMASK, reg);
1117					data16++;
1118				}
1119				break;
1120			}
1121			}
1122		}
1123		if (attr & 1)
1124			pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg);
1125	}
1126}
1127
1128static void
1129pm2fb_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
1130{
1131	struct rasops_info *ri = cookie;
1132	struct wsdisplay_font *font = PICK_FONT(ri, c);
1133	struct vcons_screen *scr = ri->ri_hw;
1134	struct pm2fb_softc *sc = scr->scr_cookie;
1135	uint32_t bg, fg, pixel, /*bg32,*/ fg32, aval;
1136	int i, x, y, wi, he;
1137	int r1, g1, b1, /*r0, g0, b0,*/ fgo/*, bgo*/;
1138	uint8_t *data8;
1139	int rv = GC_NOPE, cnt = 0;
1140
1141	if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1142		return;
1143
1144	if (!CHAR_IN_FONT(c, font))
1145		return;
1146
1147	wi = font->fontwidth;
1148	he = font->fontheight;
1149
1150	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1151	fg = ri->ri_devcmap[(attr >> 24) & 0xf];
1152	x = ri->ri_xorigin + col * wi;
1153	y = ri->ri_yorigin + row * he;
1154
1155	/* always blit the cell with the background colour */
1156	pm2fb_rectfill(sc, x, y, wi, he, bg);
1157
1158	/* if we draw a whitespace we're done here */
1159	if (c == 0x20) {
1160		if (attr & 1)
1161			pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg);
1162		return;
1163	}
1164
1165#ifdef BITBLT_LE_WORKAROUND
1166	rv = GC_NOPE;
1167#else
1168	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1169	if (rv == GC_OK)
1170		return;
1171#endif
1172
1173	data8 = WSFONT_GLYPH(c, font);
1174
1175	pm2fb_wait(sc, 7);
1176	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_MODE, 0);
1177	/*
1178	 * XXX
1179	 * we *chould* be able to get away without reading the framebuffer
1180	 * since our background colour is always constant, but for some reason
1181	 * that produces random, mostly black background
1182	 */
1183	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_CONFIG,
1184			    PM2RECFG_WRITE_EN | PM2RECFG_READ_DST);
1185
1186	/* enable alpha blending and R3G3B2 output */
1187	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_ALPHA_MODE,
1188			    PM2AL_ENABLE |
1189			    PM2AL_OP_SRC_IS_SRC_ALPHA |
1190			    PM2AL_OP_DST_IS_ONE_MINUS_SRC_ALPHA |
1191			    PM2AL_332F | PM2AL_RGB);
1192	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_RE_DITHER_MODE,
1193			    PM2DM_ENABLE |
1194			    PM2DM_332F | PM2DM_RGB);
1195
1196	/*
1197	 * we need the RGB colours here, so get offsets into rasops_cmap
1198	 */
1199	fgo = ((attr >> 24) & 0xf) * 3;
1200
1201	r1 = rasops_cmap[fgo];
1202	g1 = rasops_cmap[fgo + 1];
1203	b1 = rasops_cmap[fgo + 2];
1204
1205	fg32 = ( r1 << 16) | (g1 << 8) | b1;
1206
1207	bus_space_write_4(sc->sc_memt, sc->sc_regh,
1208			    PM2_RE_RECT_START, (y << 16) | x);
1209	bus_space_write_4(sc->sc_memt, sc->sc_regh,
1210			    PM2_RE_RECT_SIZE, (he << 16) | wi);
1211
1212	bus_space_write_4(sc->sc_memt, sc->sc_regh,
1213			    PM2_RE_RENDER,
1214			    PM2RE_RECTANGLE | PM2RE_SYNC_ON_HOST |
1215			    PM2RE_INC_X | PM2RE_INC_Y);
1216
1217	pm2fb_wait(sc, uimin(200, ri->ri_fontscale));
1218
1219	/*
1220	 * and now we just hammer the foreground colour and alpha values into
1221	 * the upload port
1222	 */
1223	for (i = 0; i < ri->ri_fontscale; i++) {
1224		aval = *data8;
1225		pixel = fg32 | (aval << 24);
1226		bus_space_write_4(sc->sc_memt, sc->sc_regh,
1227			    PM2_RE_COLOUR, pixel);
1228
1229		if (cnt > 190) {
1230			pm2fb_wait(sc, 200);
1231			cnt = 0;
1232		}
1233		data8++;
1234	}
1235	/*
1236	 * XXX
1237	 * occasionally characters end up in the cache only partially drawn
1238	 * apparently the blitter might end up grabbing them before they're
1239	 * completely flushed out into video memory
1240	 * so we let the pipeline drain a little bit before continuing
1241	 */
1242	pm2fb_wait(sc, 20);
1243
1244	if (rv == GC_ADD) {
1245		glyphcache_add(&sc->sc_gc, c, x, y);
1246	} else if (attr & 1)
1247		pm2fb_rectfill(sc, x, y + he - 2, wi, 1, fg);
1248}
1249
1250static void
1251pm2fb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1252{
1253	struct rasops_info *ri = cookie;
1254	struct vcons_screen *scr = ri->ri_hw;
1255	struct pm2fb_softc *sc = scr->scr_cookie;
1256	int32_t xs, xd, y, width, height;
1257
1258	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1259		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1260		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1261		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1262		width = ri->ri_font->fontwidth * ncols;
1263		height = ri->ri_font->fontheight;
1264		pm2fb_bitblt(sc, xs, y, xd, y, width, height, 3);
1265	}
1266}
1267
1268static void
1269pm2fb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1270{
1271	struct rasops_info *ri = cookie;
1272	struct vcons_screen *scr = ri->ri_hw;
1273	struct pm2fb_softc *sc = scr->scr_cookie;
1274	int32_t x, y, width, height, fg, bg, ul;
1275
1276	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1277		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1278		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1279		width = ri->ri_font->fontwidth * ncols;
1280		height = ri->ri_font->fontheight;
1281		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1282
1283		pm2fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1284	}
1285}
1286
1287static void
1288pm2fb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1289{
1290	struct rasops_info *ri = cookie;
1291	struct vcons_screen *scr = ri->ri_hw;
1292	struct pm2fb_softc *sc = scr->scr_cookie;
1293	int32_t x, ys, yd, width, height;
1294
1295	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1296		x = ri->ri_xorigin;
1297		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1298		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1299		width = ri->ri_emuwidth;
1300		height = ri->ri_font->fontheight*nrows;
1301		pm2fb_bitblt(sc, x, ys, x, yd, width, height, 3);
1302	}
1303}
1304
1305static void
1306pm2fb_eraserows(void *cookie, int row, int nrows, long fillattr)
1307{
1308	struct rasops_info *ri = cookie;
1309	struct vcons_screen *scr = ri->ri_hw;
1310	struct pm2fb_softc *sc = scr->scr_cookie;
1311	int32_t x, y, width, height, fg, bg, ul;
1312
1313	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1314		x = ri->ri_xorigin;
1315		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1316		width = ri->ri_emuwidth;
1317		height = ri->ri_font->fontheight * nrows;
1318		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1319
1320		pm2fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1321	}
1322}
1323
1324/*
1325 * Permedia2 can't blit outside of 2048x2048, so reject anything higher
1326 * max. dot clock is probably too high
1327 */
1328
1329#define MODE_IS_VALID(m) (((m)->hdisplay < 2048) && \
1330	((m)->dot_clock < 230000))
1331
1332static void
1333pm2_setup_i2c(struct pm2fb_softc *sc)
1334{
1335	int i;
1336#ifdef PM2FB_DEBUG
1337	int j;
1338#endif
1339
1340	/* Fill in the i2c tag */
1341	iic_tag_init(&sc->sc_i2c);
1342	sc->sc_i2c.ic_cookie = sc;
1343	sc->sc_i2c.ic_send_start = pm2fb_i2c_send_start;
1344	sc->sc_i2c.ic_send_stop = pm2fb_i2c_send_stop;
1345	sc->sc_i2c.ic_initiate_xfer = pm2fb_i2c_initiate_xfer;
1346	sc->sc_i2c.ic_read_byte = pm2fb_i2c_read_byte;
1347	sc->sc_i2c.ic_write_byte = pm2fb_i2c_write_byte;
1348
1349	DPRINTF("data: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh,
1350		PM2_DISPLAY_DATA));
1351
1352	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA, 0);
1353
1354	/* zero out the EDID buffer */
1355	memset(sc->sc_edid_data, 0, 128);
1356
1357	/* Some monitors don't respond first time */
1358	i = 0;
1359	while (sc->sc_edid_data[1] == 0 && i < 10) {
1360		ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, 128);
1361		i++;
1362	}
1363#ifdef PM2FB_DEBUG
1364	printf("i = %d\n", i);
1365	for (i = 0; i < 128; i += 16) {
1366		printf("%02x:", i);
1367		for (j = 0; j < 16; j++)
1368			printf(" %02x", sc->sc_edid_data[i + j]);
1369		printf("\n");
1370	}
1371#endif
1372
1373	if (edid_parse(&sc->sc_edid_data[0], &sc->sc_ei) != -1) {
1374#ifdef PM2FB_DEBUG
1375		edid_print(&sc->sc_ei);
1376#endif
1377
1378		/*
1379		 * Now pick a mode.
1380		 */
1381		if ((sc->sc_ei.edid_preferred_mode != NULL)) {
1382			struct videomode *m = sc->sc_ei.edid_preferred_mode;
1383			if (MODE_IS_VALID(m)) {
1384				sc->sc_videomode = m;
1385			} else {
1386				aprint_error_dev(sc->sc_dev,
1387				    "unable to use preferred mode\n");
1388			}
1389		}
1390		/*
1391		 * if we can't use the preferred mode go look for the
1392		 * best one we can support
1393		 */
1394		if (sc->sc_videomode == NULL) {
1395			struct videomode *m = sc->sc_ei.edid_modes;
1396
1397			sort_modes(sc->sc_ei.edid_modes,
1398			    &sc->sc_ei.edid_preferred_mode,
1399			    sc->sc_ei.edid_nmodes);
1400			if (sc->sc_videomode == NULL)
1401				for (int n = 0; n < sc->sc_ei.edid_nmodes; n++)
1402					if (MODE_IS_VALID(&m[n])) {
1403						sc->sc_videomode = &m[n];
1404						break;
1405					}
1406		}
1407	}
1408	if (sc->sc_videomode == NULL) {
1409		/* no EDID data? */
1410		sc->sc_videomode = pick_mode_by_ref(sc->sc_width,
1411		    sc->sc_height, 60);
1412	}
1413	if (sc->sc_videomode != NULL) {
1414		pm2fb_set_mode(sc, sc->sc_videomode);
1415	}
1416}
1417
1418/* I2C bitbanging */
1419static void pm2fb_i2cbb_set_bits(void *cookie, uint32_t bits)
1420{
1421	struct pm2fb_softc *sc = cookie;
1422	uint32_t out;
1423
1424	out = bits << 2;	/* bitmasks match the IN bits */
1425
1426	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA, out);
1427	delay(100);
1428}
1429
1430static void pm2fb_i2cbb_set_dir(void *cookie, uint32_t dir)
1431{
1432	/* Nothing to do */
1433}
1434
1435static uint32_t pm2fb_i2cbb_read(void *cookie)
1436{
1437	struct pm2fb_softc *sc = cookie;
1438	uint32_t bits;
1439
1440	bits = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_DISPLAY_DATA);
1441	return bits;
1442}
1443
1444/* higher level I2C stuff */
1445static int
1446pm2fb_i2c_send_start(void *cookie, int flags)
1447{
1448	return (i2c_bitbang_send_start(cookie, flags, &pm2fb_i2cbb_ops));
1449}
1450
1451static int
1452pm2fb_i2c_send_stop(void *cookie, int flags)
1453{
1454
1455	return (i2c_bitbang_send_stop(cookie, flags, &pm2fb_i2cbb_ops));
1456}
1457
1458static int
1459pm2fb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
1460{
1461
1462	return (i2c_bitbang_initiate_xfer(cookie, addr, flags,
1463	    &pm2fb_i2cbb_ops));
1464}
1465
1466static int
1467pm2fb_i2c_read_byte(void *cookie, uint8_t *valp, int flags)
1468{
1469	return (i2c_bitbang_read_byte(cookie, valp, flags, &pm2fb_i2cbb_ops));
1470}
1471
1472static int
1473pm2fb_i2c_write_byte(void *cookie, uint8_t val, int flags)
1474{
1475	return (i2c_bitbang_write_byte(cookie, val, flags, &pm2fb_i2cbb_ops));
1476}
1477
1478static int
1479pm2vfb_set_pll(struct pm2fb_softc *sc, int freq)
1480{
1481	int m, n, p, diff, out_freq, bm = 1, bn = 3, bp = 0,
1482	    bdiff = 1000000 /* , bfreq */;
1483	int fi;
1484	uint8_t temp;
1485
1486	for (m = 1; m < 128; m++) {
1487		for (n = 2 * m + 1; n < 256; n++) {
1488			fi = PM2_EXT_CLOCK_FREQ * n / m;
1489			for (p = 0; p < 2; p++) {
1490				out_freq = fi >> (p + 1);
1491				diff = abs(out_freq - freq);
1492				if (diff < bdiff) {
1493					bdiff = diff;
1494					/* bfreq = out_freq; */
1495					bm = m;
1496					bn = n;
1497					bp = p;
1498				}
1499			}
1500		}
1501	}
1502#if 0
1503	/*
1504	 * XXX
1505	 * output between switching modes and attaching a wsdisplay will
1506	 * go through firmware calls on sparc64 and potentially mess up
1507	 * our drawing engine state
1508	 */
1509	DPRINTF("best: %d kHz ( %d off ), %d %d %d\n", bfreq, bdiff, bm, bn, bp);
1510#endif
1511	temp = pm2fb_read_dac(sc, PM2V_DAC_CLOCK_CONTROL) & 0xfc;
1512	pm2fb_write_dac(sc, PM2V_DAC_CONTROL, 0);
1513	pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_M, bm);
1514	pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_N, bn);
1515	pm2fb_write_dac(sc, PM2V_DAC_CLOCK_A_P, bp);
1516	pm2fb_write_dac(sc, PM2V_DAC_CLOCK_CONTROL, temp | 3);
1517	return 0;
1518}
1519
1520static int
1521pm2fb_set_pll(struct pm2fb_softc *sc, int freq)
1522{
1523	uint8_t  reg, bm = 0, bn = 0, bp = 0;
1524	unsigned int  m, n, p, fi, diff, out_freq, bdiff = 1000000;
1525
1526	for (n = 2; n < 15; n++) {
1527		for (m = 2 ; m < 256; m++) {
1528			fi = PM2_EXT_CLOCK_FREQ * m / n;
1529			if (fi >= PM2_PLL_FREQ_MIN && fi <= PM2_PLL_FREQ_MAX) {
1530				for (p = 0; p < 5; p++) {
1531					out_freq = fi >> p;
1532					diff = abs(out_freq - freq);
1533					if (diff < bdiff) {
1534						bm = m;
1535						bn = n;
1536						bp = p;
1537						bdiff = diff;
1538					}
1539				}
1540			}
1541		}
1542	}
1543
1544	pm2fb_write_dac(sc, PM2_DAC_PIXELCLKA_M, bm);
1545	pm2fb_write_dac(sc, PM2_DAC_PIXELCLKA_N, bn);
1546	pm2fb_write_dac(sc, PM2_DAC_PIXELCLKA_P, (bp | 0x08));
1547
1548	do {
1549		reg = bus_space_read_1(sc->sc_memt, sc->sc_regh,
1550			PM2_DAC_INDEX_DATA);
1551	} while (reg == PCLK_LOCKED);
1552
1553	return 0;
1554}
1555
1556/*
1557 * most of the following was adapted from the xf86-video-glint driver's
1558 * pm2_dac.c (8bpp only)
1559 */
1560static void
1561pm2fb_set_dac(struct pm2fb_softc *sc, const struct videomode *mode)
1562{
1563	int t1, t2, t3, t4, stride;
1564	uint32_t vclk, tmp;
1565	uint8_t sync = 0;
1566
1567	t1 = mode->hsync_start - mode->hdisplay;
1568	t2 = mode->vsync_start - mode->vdisplay;
1569	t3 = mode->hsync_end - mode->hsync_start;
1570	t4 = mode->vsync_end - mode->vsync_start;
1571
1572	/* first round up to the next multiple of 32 */
1573	stride = (mode->hdisplay + 31) & ~31;
1574	/* then find the next bigger one that we have partial products for */
1575	while ((partprodPermedia[stride >> 5] == -1) && (stride < 2048)) {
1576		stride += 32;
1577	}
1578
1579	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HTOTAL,
1580	    ((mode->htotal) >> 2) - 1);
1581	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_END,
1582	    (t1 + t3) >> 2);
1583	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_START,
1584	    (t1 >> 2));
1585	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HBLANK_END,
1586	    (mode->htotal - mode->hdisplay) >> 2);
1587	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HGATE_END,
1588	    (mode->htotal - mode->hdisplay) >> 2);
1589	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_STRIDE,
1590	    stride >> 3);
1591
1592	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VTOTAL,
1593	    mode->vtotal - 2);
1594	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_END,
1595	    t2 + t4 - 1);
1596	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_START,
1597	    t2 - 1);
1598	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VBLANK_END,
1599	    mode->vtotal - mode->vdisplay);
1600	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VIDEO_CONTROL,
1601	    PM2_VC_VIDEO_ENABLE |
1602	    PM2_VC_HSYNC_ACT_HIGH | PM2_VC_VSYNC_ACT_HIGH);
1603
1604	vclk = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL);
1605	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL,
1606	    vclk & 0xfffffffc);
1607
1608	tmp = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_CHIP_CONFIG);
1609	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_CHIP_CONFIG,
1610	    tmp & 0xffffffdd);
1611
1612	pm2fb_write_dac(sc, PM2_DAC_MODE_CONTROL, MOC_BUFFERFRONT);
1613	pm2fb_set_pll(sc, mode->dot_clock);
1614
1615	sync = MC_PALETTE_8BIT;
1616
1617	if (!(mode->flags & VID_PHSYNC))
1618	    sync |= MC_HSYNC_INV;
1619	if (!(mode->flags & VID_PVSYNC))
1620	    sync |= MC_VSYNC_INV;
1621
1622	pm2fb_write_dac(sc, PM2_DAC_MISC_CONTROL, sync);
1623	pm2fb_write_dac(sc, PM2_DAC_COLOR_MODE,
1624	    CM_PALETTE | CM_GUI_ENABLE | CM_RGB);
1625
1626	sc->sc_width = mode->hdisplay;
1627	sc->sc_height = mode->vdisplay;
1628	sc->sc_depth = 8;
1629	sc->sc_stride = stride;
1630	aprint_normal_dev(sc->sc_dev, "pm2 using %d x %d in 8 bit, stride %d\n",
1631	    sc->sc_width, sc->sc_height, stride);
1632}
1633
1634/*
1635 * most of the following was adapted from the xf86-video-glint driver's
1636 * pm2v_dac.c
1637 */
1638static void
1639pm2vfb_set_dac(struct pm2fb_softc *sc, const struct videomode *mode)
1640{
1641	int t1, t2, t3, t4, stride;
1642	uint32_t vclk;
1643	uint8_t sync = 0;
1644
1645	t1 = mode->hsync_start - mode->hdisplay;
1646	t2 = mode->vsync_start - mode->vdisplay;
1647	t3 = mode->hsync_end - mode->hsync_start;
1648	t4 = mode->vsync_end - mode->vsync_start;
1649
1650	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HTOTAL,
1651	    ((mode->htotal) >> 3) - 1);
1652	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_END,
1653	    (t1 + t3) >> 3);
1654	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HSYNC_START,
1655	    (t1 >> 3) - 1);
1656	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HBLANK_END,
1657	    (mode->htotal - mode->hdisplay) >> 3);
1658	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_HGATE_END,
1659	    (mode->htotal - mode->hdisplay) >> 3);
1660
1661	/* first round up to the next multiple of 32 */
1662	stride = (mode->hdisplay + 31) & ~31;
1663	/* then find the next bigger one that we have partial products for */
1664	while ((partprodPermedia[stride >> 5] == -1) && (stride < 2048)) {
1665		stride += 32;
1666	}
1667	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_SCREEN_STRIDE,
1668	    stride >> 3);
1669
1670	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VTOTAL,
1671	    mode->vtotal - 1);
1672	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_END,
1673	    t2 + t4);
1674	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VSYNC_START,
1675	    t2);
1676	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VBLANK_END,
1677	    mode->vtotal - mode->vdisplay);
1678
1679	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VIDEO_CONTROL,
1680	    PM2_VC_VIDEO_ENABLE | PM2_VC_RAMDAC_64BIT |
1681	    PM2_VC_HSYNC_ACT_HIGH | PM2_VC_VSYNC_ACT_HIGH);
1682
1683	vclk = bus_space_read_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL);
1684	bus_space_write_4(sc->sc_memt, sc->sc_regh, PM2_VCLKCTL,
1685	    vclk & 0xfffffffc);
1686
1687	pm2vfb_set_pll(sc, mode->dot_clock / 2);
1688	pm2fb_write_dac(sc, PM2V_DAC_MISC_CONTROL, PM2V_DAC_8BIT);
1689
1690	if (mode->flags & VID_PHSYNC)
1691		sync |= PM2V_DAC_HSYNC_INV;
1692	if (mode->flags & VID_PVSYNC)
1693		sync |= PM2V_DAC_VSYNC_INV;
1694	pm2fb_write_dac(sc, PM2V_DAC_SYNC_CONTROL, sync);
1695
1696	pm2fb_write_dac(sc, PM2V_DAC_COLOR_FORMAT, PM2V_DAC_PALETTE);
1697	pm2fb_write_dac(sc, PM2V_DAC_PIXEL_SIZE, PM2V_PS_8BIT);
1698	sc->sc_width = mode->hdisplay;
1699	sc->sc_height = mode->vdisplay;
1700	sc->sc_depth = 8;
1701	sc->sc_stride = stride;
1702	aprint_normal_dev(sc->sc_dev, "pm2v using %d x %d in 8 bit, stride %d\n",
1703	    sc->sc_width, sc->sc_height, stride);
1704}
1705
1706static void
1707pm2fb_set_mode(struct pm2fb_softc *sc, const struct videomode *mode)
1708{
1709	if (sc->sc_is_pm2) {
1710		pm2fb_set_dac(sc, mode);
1711	} else {
1712		pm2vfb_set_dac(sc, mode);
1713	}
1714}
1715