1/*	$NetBSD: omap3_dss.c,v 1.7 2022/09/27 06:36:43 skrll Exp $	*/
2
3/*
4 * Copyright (c) 2010 Michael Lorenz
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * A console driver for OMAP 3530's built-in video controller
30 * tested on beagleboard only so far
31 */
32
33#include "opt_wsdisplay_compat.h"
34
35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: omap3_dss.c,v 1.7 2022/09/27 06:36:43 skrll Exp $");
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/device.h>
42#include <sys/lwp.h>
43#include <sys/kauth.h>
44#include <sys/bus.h>
45
46#include <uvm/uvm_extern.h>
47
48#include <dev/videomode/videomode.h>
49#include <dev/videomode/edidvar.h>
50
51#include <dev/fdt/fdtvar.h>
52
53#include <arm/ti/omap3_dssreg.h>
54
55#include <dev/wscons/wsdisplayvar.h>
56#include <dev/wscons/wsconsio.h>
57#include <dev/wsfont/wsfont.h>
58#include <dev/rasops/rasops.h>
59#include <dev/wscons/wsdisplay_vconsvar.h>
60
61struct omapfb_softc {
62	device_t sc_dev;
63
64	bus_space_tag_t sc_iot;
65	bus_dma_tag_t sc_dmat;
66	bus_space_handle_t sc_regh;
67	bus_dmamap_t sc_dmamap;
68	bus_dma_segment_t sc_dmamem[1];
69	size_t sc_vramsize;
70
71	int sc_width, sc_height, sc_depth, sc_stride;
72	int sc_locked;
73	void *sc_fbaddr, *sc_vramaddr;
74
75	int sc_cursor_offset;
76	uint32_t *sc_cursor_img;
77	int sc_cursor_x, sc_cursor_y;
78	int sc_hot_x, sc_hot_y;
79	uint8_t sc_cursor_bitmap[8 * 64];
80	uint8_t sc_cursor_mask[8 * 64];
81	uint32_t sc_cursor_cmap[4];
82
83	bus_addr_t sc_fbhwaddr;
84	uint32_t *sc_clut;
85	uint32_t sc_dispc_config;
86	int sc_video_is_on;
87	struct vcons_screen sc_console_screen;
88	struct wsscreen_descr sc_defaultscreen_descr;
89	const struct wsscreen_descr *sc_screens[1];
90	struct wsscreen_list sc_screenlist;
91	struct vcons_data vd;
92	int sc_mode;
93	uint8_t sc_cmap_red[256], sc_cmap_green[256], sc_cmap_blue[256];
94	void (*sc_putchar)(void *, int, int, u_int, long);
95
96	uint8_t sc_edid_data[1024];
97	size_t sc_edid_size;
98};
99
100static int	omapfb_match(device_t, cfdata_t, void *);
101static void	omapfb_attach(device_t, device_t, void *);
102
103CFATTACH_DECL_NEW(omap3_dss, sizeof(struct omapfb_softc),
104    omapfb_match, omapfb_attach, NULL, NULL);
105
106static int	omapfb_ioctl(void *, void *, u_long, void *, int,
107			     struct lwp *);
108static paddr_t	omapfb_mmap(void *, void *, off_t, int);
109static void	omapfb_init_screen(void *, struct vcons_screen *, int, long *);
110
111static int	omapfb_putcmap(struct omapfb_softc *, struct wsdisplay_cmap *);
112static int 	omapfb_getcmap(struct omapfb_softc *, struct wsdisplay_cmap *);
113static void	omapfb_restore_palette(struct omapfb_softc *);
114static void 	omapfb_putpalreg(struct omapfb_softc *, int, uint8_t,
115			    uint8_t, uint8_t);
116
117static int	omapfb_set_depth(struct omapfb_softc *, int);
118static void	omapfb_set_video(struct omapfb_softc *, int);
119
120static void 	omapfb_move_cursor(struct omapfb_softc *, int, int);
121static int	omapfb_do_cursor(struct omapfb_softc *,
122		    struct wsdisplay_cursor *);
123
124#if NOMAPDMA > 0
125static void	omapfb_init(struct omapfb_softc *);
126static void	omapfb_wait_idle(struct omapfb_softc *);
127static void	omapfb_rectfill(struct omapfb_softc *, int, int, int, int,
128			    uint32_t);
129static void	omapfb_bitblt(struct omapfb_softc *, int, int, int, int, int,
130			    int, int);
131
132static void	omapfb_cursor(void *, int, int, int);
133static void	omapfb_putchar(void *, int, int, u_int, long);
134static void	omapfb_copycols(void *, int, int, int, int);
135static void	omapfb_erasecols(void *, int, int, int, long);
136static void	omapfb_copyrows(void *, int, int, int);
137static void	omapfb_eraserows(void *, int, int, long);
138#endif /* NOMAPDMA > 0 */
139
140struct wsdisplay_accessops omapfb_accessops = {
141	omapfb_ioctl,
142	omapfb_mmap,
143	NULL,	/* alloc_screen */
144	NULL,	/* free_screen */
145	NULL,	/* show_screen */
146	NULL, 	/* load_font */
147	NULL,	/* pollc */
148	NULL	/* scroll */
149};
150
151uint32_t venc_mode_ntsc[] = {
152	0x00000000, 0x00000001, 0x00008040, 0x00000359,
153	0x0000020c, 0x00000000, 0x043f2631, 0x00000000,
154	0x00000102, 0x0000016c, 0x0000012f, 0x00000043,
155	0x00000038, 0x00000007, 0x00000001, 0x00000038,
156	0x21f07c1f, 0x00000000, 0x01310011, 0x0000f003,
157	0x00000000, 0x069300f4, 0x0016020c, 0x00060107,
158	0x008e0350, 0x000f0359, 0x01a00000, 0x020701a0,
159	0x01ac0024, 0x020d01ac, 0x00000006, 0x03480078,
160	0x02060024, 0x0001008a, 0x01ac0106, 0x01060006,
161	0x00140001, 0x00010001, 0x00f90000, 0x0000000d,
162	0x00000000};
163
164extern const u_char rasops_cmap[768];
165
166static const struct device_compatible_entry compat_data[] = {
167	{ .compat = "ti,omap3-dss" },
168	DEVICE_COMPAT_EOL
169};
170
171static int omapfb_console_phandle = -1;
172
173static int
174omapfb_match(device_t parent, cfdata_t match, void *aux)
175{
176	struct fdt_attach_args * const faa = aux;
177
178	return of_compatible_match(faa->faa_phandle, compat_data);
179}
180
181static void
182omapfb_attach(device_t parent, device_t self, void *aux)
183{
184	struct omapfb_softc	*sc = device_private(self);
185	struct fdt_attach_args	*faa = aux;
186	const int		phandle = faa->faa_phandle;
187	struct rasops_info	*ri;
188	struct wsemuldisplaydev_attach_args aa;
189	prop_dictionary_t	dict;
190	prop_data_t		edid_data;
191	unsigned long		defattr;
192#ifdef WSDISPLAY_MULTICONS
193	bool			is_console = true;
194#else
195	bool			is_console = phandle == omapfb_console_phandle;
196#endif
197	uint32_t		sz, reg;
198	int			segs, i, j;
199	bus_addr_t		addr;
200	bus_size_t		size;
201
202	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
203		aprint_error(": couldn't get registers\n");
204		return;
205	}
206
207	sc->sc_dev = self;
208	sc->sc_iot = faa->faa_bst;
209	sc->sc_dmat = faa->faa_dmat;
210
211	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_regh) != 0) {
212		aprint_error(": couldn't map registers\n");
213		return;
214	}
215
216	aprint_naive("\n");
217	aprint_normal(": OMAP onboard video\n");
218
219	sc->sc_video_is_on = 1;
220
221	/*
222	 * XXX
223	 * different u-boot versions initialize the graphics controller in
224	 * different ways, so we look for the display resolution in a few
225	 * different places...
226	 */
227	sz = bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_SIZE);
228	if (sz == 0) {
229		sz = bus_space_read_4(sc->sc_iot, sc->sc_regh,
230		    OMAPFB_DISPC_SIZE_LCD);
231	}
232	if (sz == 0) {
233		sz = bus_space_read_4(sc->sc_iot, sc->sc_regh,
234		    OMAPFB_DISPC_SIZE_DIG);
235	}
236
237	/* ... and make sure it ends up where we need it */
238	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_SIZE, sz);
239
240	sc->sc_width = (sz & 0xfff) + 1;
241	sc->sc_height = ((sz & 0x0fff0000 ) >> 16) + 1;
242	sc->sc_depth = 16;
243	sc->sc_stride = sc->sc_width << 1;
244
245	if (sc->sc_width == 1 || sc->sc_height == 1) {
246		aprint_error_dev(self, "bogus display size, not attaching\n");
247		return;
248	}
249
250	printf("%s: firmware set up %d x %d\n", device_xname(self),
251	    sc->sc_width, sc->sc_height);
252#if 0
253	printf("DSS revision: %08x\n",
254	    bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DSS_REVISION));
255#endif
256	dict = device_properties(self);
257	edid_data = prop_dictionary_get(dict, "EDID");
258
259	if (edid_data != NULL) {
260		struct edid_info ei;
261
262		sc->sc_edid_size = uimin(prop_data_size(edid_data), 1024);
263		memset(sc->sc_edid_data, 0, sizeof(sc->sc_edid_data));
264		memcpy(sc->sc_edid_data, prop_data_value(edid_data), sc->sc_edid_size);
265
266		edid_parse(sc->sc_edid_data, &ei);
267		edid_print(&ei);
268	}
269
270	/* setup video DMA */
271	sc->sc_vramsize = (12 << 20) + PAGE_SIZE; /* 12MB + CLUT */
272
273	if (bus_dmamem_alloc(sc->sc_dmat, sc->sc_vramsize, 0, 0,
274	    sc->sc_dmamem, 1, &segs, BUS_DMA_NOWAIT) != 0) {
275		panic("boo!\n");
276		aprint_error_dev(sc->sc_dev,
277		    "failed to allocate video memory\n");
278		return;
279	}
280
281	if (bus_dmamem_map(sc->sc_dmat, sc->sc_dmamem, 1, sc->sc_vramsize,
282	    &sc->sc_vramaddr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0) {
283		aprint_error_dev(sc->sc_dev, "failed to map video RAM\n");
284		return;
285	}
286	sc->sc_fbaddr = (uint8_t *)sc->sc_vramaddr + PAGE_SIZE;
287	sc->sc_clut = sc->sc_vramaddr;
288
289	if (bus_dmamap_create(sc->sc_dmat, sc->sc_vramsize, 1, sc->sc_vramsize,
290	    0, BUS_DMA_NOWAIT, &sc->sc_dmamap) != 0) {
291		aprint_error_dev(sc->sc_dev, "failed to create DMA map\n");
292		return;
293	}
294
295	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_vramaddr,
296	    sc->sc_vramsize, NULL, BUS_DMA_NOWAIT) != 0) {
297		aprint_error_dev(sc->sc_dev, "failed to load DMA map\n");
298		return;
299	}
300
301	if (sc->sc_depth == 8) {
302		j = 0;
303		for (i = 0; i < 256; i++) {
304			sc->sc_cmap_red[i] = rasops_cmap[j];
305			sc->sc_cmap_green[i] = rasops_cmap[j + 1];
306			sc->sc_cmap_blue[i] = rasops_cmap[j + 2];
307			j += 3;
308		}
309	} else {
310		for (i = 0; i < 256; i++) {
311			sc->sc_cmap_red[i] = i;
312			sc->sc_cmap_green[i] = i;
313			sc->sc_cmap_blue[i] = i;
314		}
315	}
316	omapfb_restore_palette(sc);
317
318	/* now that we have video memory, stick it to the video controller */
319
320	reg = bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_SYSCONFIG);
321	reg &= ~(OMAP_DISPC_SYSC_STANDBY_MASK | OMAP_DISPC_SYSC_IDLE_MASK);
322	reg |= OMAP_DISPC_SYSC_SMART_STANDBY | OMAP_DISPC_SYSC_SMART_IDLE |
323	       OMAP_DISPC_SYSC_WAKEUP_ENABLE | OMAP_SYSCONF_AUTOIDLE;
324	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_SYSCONFIG, reg);
325
326	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DSS_SYSCONFIG,
327	    OMAP_SYSCONF_AUTOIDLE);
328
329	reg = OMAP_DISPC_CFG_TV_ALPHA_EN | OMAP_DISPC_CFG_LCD_ALPHA_EN;
330	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONFIG, reg);
331	sc->sc_dispc_config = reg;
332
333	/* we use overlay 1 for the console and X */
334	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GLOBAL_ALPHA,
335	    0x00ff00ff);
336	sc->sc_fbhwaddr = sc->sc_dmamem->ds_addr + PAGE_SIZE;
337	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_VID1_BASE_0,
338	    sc->sc_fbhwaddr);
339	bus_space_write_4(sc->sc_iot, sc->sc_regh,
340	    OMAPFB_DISPC_VID1_POSITION, 0);
341	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_VID1_SIZE,
342	    ((sc->sc_height - 1) << 16) | (sc->sc_width - 1));
343	bus_space_write_4(sc->sc_iot, sc->sc_regh,
344	    OMAPFB_DISPC_VID1_PICTURE_SIZE,
345	    ((sc->sc_height - 1) << 16) | (sc->sc_width - 1));
346	bus_space_write_4(sc->sc_iot, sc->sc_regh,
347	    OMAPFB_DISPC_VID1_ROW_INC, 1);
348	bus_space_write_4(sc->sc_iot, sc->sc_regh,
349	    OMAPFB_DISPC_VID1_PIXEL_INC, 1);
350	bus_space_write_4(sc->sc_iot, sc->sc_regh,
351	    OMAPFB_DISPC_VID1_PRELOAD, 0x60);
352	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_VID1_ATTRIBUTES,
353	    OMAP_VID_ATTR_ENABLE |
354	    OMAP_VID_ATTR_BURST_16x32 |
355	    OMAP_VID_ATTR_RGB16 |
356	    OMAP_VID_ATTR_REPLICATION);
357
358	/* turn off overlay 2 */
359	bus_space_write_4(sc->sc_iot, sc->sc_regh,
360	    OMAPFB_DISPC_VID2_ATTRIBUTES, 0);
361
362	/* initialize the gfx layer for use as hardware cursor */
363	sc->sc_cursor_cmap[0] = 0;
364	sc->sc_cursor_offset = (12 << 20) - (64 * 64 * 4);
365	sc->sc_cursor_img =
366	   (uint32_t *)((uint8_t *)sc->sc_fbaddr + sc->sc_cursor_offset);
367	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_BASE_0,
368	    sc->sc_fbhwaddr + sc->sc_cursor_offset);
369	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_TABLE_BASE,
370	    sc->sc_dmamem->ds_addr);
371	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_SIZE,
372	    0x003f003f);
373	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_POSITION,
374	    0x00100010);
375	bus_space_write_4(sc->sc_iot, sc->sc_regh,
376	    OMAPFB_DISPC_GFX_PRELOAD, 0x60);
377	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_ATTRIBUTES,
378	    /*OMAP_DISPC_ATTR_ENABLE |*/
379	    OMAP_DISPC_ATTR_BURST_16x32 |
380	    OMAP_DISPC_ATTR_ARGB32 |
381	    OMAP_DISPC_ATTR_REPLICATION);
382
383#if 0
384	printf("dss_control: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
385	    OMAPFB_DSS_CONTROL));
386	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DSS_CONTROL,
387	    /*OMAP_DSSCTRL_DISPC_CLK_SWITCH |*/
388	    OMAP_DSSCTRL_CLOCK_MODE |
389	    OMAP_DSSCTRL_VENC_CLOCK_4X |
390	    OMAP_DSSCTRL_DAC_DEMEN);
391#endif
392
393#if 0
394	/* VENC to NTSC mode */
395	int adr = OMAPFB_VENC_F_CONTROL;
396	for (i = 0; i < __arraycount(venc_mode_ntsc); i++) {
397		bus_space_write_4(sc->sc_iot, sc->sc_regh, adr,
398		    venc_mode_ntsc[i]);
399		adr += 4;
400	}
401	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_VENC_F_CONTROL,
402		    venc_mode_ntsc[0]);
403	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_VENC_SYNC_CTRL,
404		    venc_mode_ntsc[2]);
405
406	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_DEFAULT_COLOR_1,
407	    0x00ff0000);
408#endif
409
410	/* now we make sure the video output is actually running */
411	reg = bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL);
412	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL,
413	    reg | OMAP_DISPC_CTRL_GO_LCD | OMAP_DISPC_CTRL_GO_DIGITAL);
414
415#ifdef OMAPFB_DEBUG
416	printf("attr: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
417	    OMAPFB_DISPC_GFX_ATTRIBUTES));
418	printf("preload: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
419	    OMAPFB_DISPC_GFX_PRELOAD));
420	printf("config: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
421	    OMAPFB_DISPC_CONFIG));
422	printf("control: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
423	    OMAPFB_DISPC_CONTROL));
424	printf("dss_control: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
425	    OMAPFB_DSS_CONTROL));
426	printf("threshold: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
427	    OMAPFB_DISPC_GFX_FIFO_THRESH));
428	printf("GFX size: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
429	    OMAPFB_DISPC_GFX_SIZE));
430	printf("row inc: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
431	    OMAPFB_DISPC_GFX_ROW_INC));
432	printf("pixel inc: %08x\n", bus_space_read_4(sc->sc_iot, sc->sc_regh,
433	    OMAPFB_DISPC_GFX_PIXEL_INC));
434#endif
435
436	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
437		"default",
438		0, 0,
439		NULL,
440		8, 16,
441		WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
442		NULL
443	};
444	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
445	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
446	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
447	sc->sc_locked = 0;
448
449	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
450	    &omapfb_accessops);
451	sc->vd.init_screen = omapfb_init_screen;
452
453	/* init engine here */
454#if NOMAPDMA > 0
455	omapfb_init(sc);
456#endif
457
458	ri = &sc->sc_console_screen.scr_ri;
459	vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr);
460	sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
461#if NOMAPDMA > 0
462	omapfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
463	    ri->ri_devcmap[(defattr >> 16) & 0xff]);
464#endif
465	sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
466	sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
467	sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
468	sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
469
470	if (is_console)
471		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
472		    defattr);
473
474	vcons_replay_msgbuf(&sc->sc_console_screen);
475
476	aa.console = is_console;
477	aa.scrdata = &sc->sc_screenlist;
478	aa.accessops = &omapfb_accessops;
479	aa.accesscookie = &sc->vd;
480
481	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
482#ifdef OMAPFB_DEBUG
483#if NOMAPDMA > 0
484	omapfb_rectfill(sc, 100, 100, 100, 100, 0xe000);
485	omapfb_rectfill(sc, 100, 200, 100, 100, 0x01f8);
486	omapfb_rectfill(sc, 200, 100, 100, 100, 0x01f8);
487	omapfb_rectfill(sc, 200, 200, 100, 100, 0xe000);
488	omapfb_bitblt(sc, 100, 100, 400, 100, 200, 200, 0);
489	/* let's see if we can draw something */
490	printf("OMAPDMAC_CDAC: %08x\n", omapdma_read_ch_reg(0, OMAPDMAC_CDAC));
491	printf("OMAPDMAC_CSR: %08x\n", omapdma_read_ch_reg(0, OMAPDMAC_CSR));
492	printf("OMAPDMAC_CCR: %08x\n", omapdma_read_ch_reg(0, OMAPDMAC_CCR));
493#endif
494#endif
495}
496
497static int
498omapfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
499	struct lwp *l)
500{
501	struct vcons_data *vd = v;
502	struct omapfb_softc *sc = vd->cookie;
503	struct wsdisplay_fbinfo *wdf;
504	struct vcons_screen *ms = vd->active;
505
506	switch (cmd) {
507
508		case WSDISPLAYIO_GTYPE:
509			*(u_int *)data = WSDISPLAY_TYPE_OMAP3;
510			return 0;
511
512		case WSDISPLAYIO_GET_BUSID:
513			{
514				struct wsdisplayio_bus_id *busid;
515
516				busid = data;
517				busid->bus_type = WSDISPLAYIO_BUS_SOC;
518				return 0;
519			}
520
521		case WSDISPLAYIO_GINFO:
522			if (ms == NULL)
523				return ENODEV;
524			wdf = (void *)data;
525			wdf->height = ms->scr_ri.ri_height;
526			wdf->width = ms->scr_ri.ri_width;
527			wdf->depth = 32;
528			wdf->cmsize = 256;
529			return 0;
530
531		case WSDISPLAYIO_GETCMAP:
532			return omapfb_getcmap(sc,
533			    (struct wsdisplay_cmap *)data);
534
535		case WSDISPLAYIO_PUTCMAP:
536			return omapfb_putcmap(sc,
537			    (struct wsdisplay_cmap *)data);
538
539		case WSDISPLAYIO_LINEBYTES:
540			*(u_int *)data = sc->sc_width * 4;
541			return 0;
542
543		case WSDISPLAYIO_SMODE:
544			{
545				int new_mode = *(int*)data;
546
547				if (new_mode != sc->sc_mode) {
548					sc->sc_mode = new_mode;
549					if (new_mode == WSDISPLAYIO_MODE_EMUL) {
550						omapfb_set_depth(sc, 16);
551						vcons_redraw_screen(ms);
552					} else {
553						omapfb_set_depth(sc, 32);
554					}
555				}
556			}
557			return 0;
558
559		case WSDISPLAYIO_GET_FBINFO:
560			{
561				struct wsdisplayio_fbinfo *fbi = data;
562
563				fbi->fbi_width = sc->sc_width;
564				fbi->fbi_height = sc->sc_height;
565				fbi->fbi_stride = sc->sc_width << 2;
566				fbi->fbi_bitsperpixel = 32;
567				fbi->fbi_pixeltype = WSFB_RGB;
568				fbi->fbi_subtype.fbi_rgbmasks.red_offset = 16;
569				fbi->fbi_subtype.fbi_rgbmasks.red_size = 8;
570				fbi->fbi_subtype.fbi_rgbmasks.green_offset = 8;
571				fbi->fbi_subtype.fbi_rgbmasks.green_size = 8;
572				fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 0;
573				fbi->fbi_subtype.fbi_rgbmasks.blue_size = 8;
574				fbi->fbi_subtype.fbi_rgbmasks.alpha_offset = 0;
575				fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 0;
576				fbi->fbi_flags = 0;
577				fbi->fbi_fbsize = sc->sc_vramsize;
578				fbi->fbi_fboffset = 0;
579				fbi->fbi_flags = WSFB_VRAM_IS_RAM;
580
581			}
582			return 0;
583
584		case WSDISPLAYIO_GVIDEO:
585			{
586				int *on = data;
587				*on = sc->sc_video_is_on;
588			}
589			return 0;
590
591		case WSDISPLAYIO_SVIDEO:
592			{
593				int *on = data;
594				omapfb_set_video(sc, *on);
595			}
596			return 0;
597
598		case WSDISPLAYIO_GCURPOS:
599			{
600				struct wsdisplay_curpos *cp = (void *)data;
601
602				cp->x = sc->sc_cursor_x;
603				cp->y = sc->sc_cursor_y;
604			}
605			return 0;
606		case WSDISPLAYIO_SCURPOS:
607			{
608				struct wsdisplay_curpos *cp = (void *)data;
609
610				omapfb_move_cursor(sc, cp->x, cp->y);
611			}
612			return 0;
613		case WSDISPLAYIO_GCURMAX:
614			{
615				struct wsdisplay_curpos *cp = (void *)data;
616
617				cp->x = 64;
618				cp->y = 64;
619			}
620			return 0;
621		case WSDISPLAYIO_SCURSOR:
622			{
623				struct wsdisplay_cursor *cursor = (void *)data;
624
625				return omapfb_do_cursor(sc, cursor);
626			}
627	}
628	return EPASSTHROUGH;
629}
630
631static paddr_t
632omapfb_mmap(void *v, void *vs, off_t offset, int prot)
633{
634	paddr_t pa = -1;
635	struct vcons_data *vd = v;
636	struct omapfb_softc *sc = vd->cookie;
637
638	/* 'regular' framebuffer mmap()ing */
639	if (offset < sc->sc_vramsize) {
640		pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dmamem, 1,
641		    offset + PAGE_SIZE, prot, BUS_DMA_PREFETCHABLE);
642		return pa;
643	}
644	return pa;
645}
646
647static void
648omapfb_init_screen(void *cookie, struct vcons_screen *scr,
649    int existing, long *defattr)
650{
651	struct omapfb_softc *sc = cookie;
652	struct rasops_info *ri = &scr->scr_ri;
653
654	ri->ri_depth = sc->sc_depth;
655	ri->ri_width = sc->sc_width;
656	ri->ri_height = sc->sc_height;
657	ri->ri_stride = sc->sc_stride;
658	ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
659
660	ri->ri_bits = (char *)sc->sc_fbaddr;
661
662#if NOMAPDMA < 1
663	scr->scr_flags |= VCONS_DONT_READ;
664#endif
665
666	if (existing) {
667		ri->ri_flg |= RI_CLEAR;
668	}
669
670	rasops_init(ri, sc->sc_height / 8, sc->sc_width / 8);
671	ri->ri_caps = WSSCREEN_WSCOLORS;
672
673	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
674		    sc->sc_width / ri->ri_font->fontwidth);
675
676	ri->ri_hw = scr;
677
678#if NOMAPDMA > 0
679	ri->ri_ops.copyrows = omapfb_copyrows;
680	ri->ri_ops.copycols = omapfb_copycols;
681	ri->ri_ops.eraserows = omapfb_eraserows;
682	ri->ri_ops.erasecols = omapfb_erasecols;
683	ri->ri_ops.cursor = omapfb_cursor;
684	sc->sc_putchar = ri->ri_ops.putchar;
685	ri->ri_ops.putchar = omapfb_putchar;
686#endif
687}
688
689static int
690omapfb_putcmap(struct omapfb_softc *sc, struct wsdisplay_cmap *cm)
691{
692	u_char *r, *g, *b;
693	u_int index = cm->index;
694	u_int count = cm->count;
695	int i, error;
696	u_char rbuf[256], gbuf[256], bbuf[256];
697
698	if (cm->index >= 256 || cm->count > 256 ||
699	    (cm->index + cm->count) > 256)
700		return EINVAL;
701	error = copyin(cm->red, &rbuf[index], count);
702	if (error)
703		return error;
704	error = copyin(cm->green, &gbuf[index], count);
705	if (error)
706		return error;
707	error = copyin(cm->blue, &bbuf[index], count);
708	if (error)
709		return error;
710
711	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
712	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
713	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
714
715	r = &sc->sc_cmap_red[index];
716	g = &sc->sc_cmap_green[index];
717	b = &sc->sc_cmap_blue[index];
718
719	for (i = 0; i < count; i++) {
720		omapfb_putpalreg(sc, index, *r, *g, *b);
721		index++;
722		r++, g++, b++;
723	}
724	return 0;
725}
726
727static int
728omapfb_getcmap(struct omapfb_softc *sc, struct wsdisplay_cmap *cm)
729{
730	u_int index = cm->index;
731	u_int count = cm->count;
732	int error;
733
734	if (index >= 255 || count > 256 || index + count > 256)
735		return EINVAL;
736
737	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
738	if (error)
739		return error;
740	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
741	if (error)
742		return error;
743	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
744	if (error)
745		return error;
746
747	return 0;
748}
749
750static void
751omapfb_restore_palette(struct omapfb_softc *sc)
752{
753	int i;
754
755	for (i = 0; i < 256; i++) {
756		omapfb_putpalreg(sc, i, sc->sc_cmap_red[i],
757		    sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
758	}
759}
760
761static void
762omapfb_putpalreg(struct omapfb_softc *sc, int idx, uint8_t r, uint8_t g,
763    uint8_t b)
764{
765	uint32_t reg;
766
767	if ((idx < 0) || (idx > 255))
768		return;
769	/* whack the DAC */
770	reg = (r << 16) | (g << 8) | b;
771	sc->sc_clut[idx] = reg;
772}
773
774static int
775omapfb_set_depth(struct omapfb_softc *sc, int d)
776{
777	uint32_t reg;
778
779	reg = OMAP_VID_ATTR_ENABLE |
780	      OMAP_VID_ATTR_BURST_16x32 |
781	      OMAP_VID_ATTR_REPLICATION;
782	switch (d) {
783		case 16:
784			reg |= OMAP_VID_ATTR_RGB16;
785			break;
786		case 32:
787			reg |= OMAP_VID_ATTR_RGB24;
788			break;
789		default:
790			aprint_error_dev(sc->sc_dev,
791			    "unsupported depth (%d)\n", d);
792			return EINVAL;
793	}
794
795	bus_space_write_4(sc->sc_iot, sc->sc_regh,
796	    OMAPFB_DISPC_VID1_ATTRIBUTES, reg);
797
798	/*
799	 * now tell the video controller that we're done mucking around and
800	 * actually update its settings
801	 */
802	reg = bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL);
803	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL,
804	    reg | OMAP_DISPC_CTRL_GO_LCD | OMAP_DISPC_CTRL_GO_DIGITAL);
805
806	sc->sc_depth = d;
807	sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3);
808
809	/* clear the screen here */
810#if NOMAPDMA > 0
811	omapfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 0);
812#else
813	memset(sc->sc_fbaddr, 0, sc->sc_stride * sc->sc_height);
814#endif
815	return 0;
816}
817
818static void
819omapfb_set_video(struct omapfb_softc *sc, int on)
820{
821	uint32_t reg;
822
823	if (on == sc->sc_video_is_on)
824		return;
825	if (on) {
826		bus_space_write_4(sc->sc_iot, sc->sc_regh,
827		    OMAPFB_DISPC_CONFIG, sc->sc_dispc_config);
828		on = 1;
829	} else {
830		bus_space_write_4(sc->sc_iot, sc->sc_regh,
831		    OMAPFB_DISPC_CONFIG, sc->sc_dispc_config |
832		    OMAP_DISPC_CFG_VSYNC_GATED | OMAP_DISPC_CFG_HSYNC_GATED |
833		    OMAP_DISPC_CFG_PIXELCLK_GATED |
834		    OMAP_DISPC_CFG_PIXELDATA_GATED);
835	}
836
837	/*
838	 * now tell the video controller that we're done mucking around and
839	 * actually update its settings
840	 */
841	reg = bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL);
842	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL,
843	    reg | OMAP_DISPC_CTRL_GO_LCD | OMAP_DISPC_CTRL_GO_DIGITAL);
844
845	aprint_debug_dev(sc->sc_dev, "%s %08x\n", __func__,
846	    bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONFIG));
847	sc->sc_video_is_on = on;
848}
849
850#if NOMAPDMA > 0
851static void
852omapfb_init(struct omapfb_softc *sc)
853{
854	omapdma_write_ch_reg(0, OMAPDMAC_CLNK_CTRL, 0);
855	omapdma_write_ch_reg(0, OMAPDMAC_CICRI, 0);
856	omapdma_write_ch_reg(0, OMAPDMAC_CSDPI,
857	    CSDPI_SRC_BURST_64 | CSDPI_DST_BURST_64 |
858	    CSDPI_WRITE_POSTED | CSDPI_DATA_TYPE_16);
859}
860
861static void
862omapfb_wait_idle(struct omapfb_softc *sc)
863{
864	while ((omapdma_read_ch_reg(0, OMAPDMAC_CCR) & CCR_WR_ACTIVE) != 0);
865}
866
867static void
868omapfb_rectfill(struct omapfb_softc *sc, int x, int y, int wi, int he,
869     uint32_t colour)
870{
871	int bpp = sc->sc_depth >> 3;	/* bytes per pixel */
872	int width_in_bytes = wi * bpp;
873	uint32_t daddr;
874
875	daddr = sc->sc_fbhwaddr + sc->sc_stride * y + x * bpp;
876	omapfb_wait_idle(sc);
877
878	/*
879	 * stupid hardware
880	 * in 32bit mode the DMA controller always writes 0 into the upper
881	 * byte, so we can use this mode only if we actually want that
882	 */
883	if (((colour & 0xff00) == 0) &&
884	   (((daddr | width_in_bytes) & 3) == 0)) {
885		/*
886		 * everything is properly aligned so we can copy stuff in
887		 * 32bit chunks instead of pixel by pixel
888		 */
889		wi = wi >> 1;
890
891		/* just in case */
892		colour |= colour << 16;
893
894		omapdma_write_ch_reg(0, OMAPDMAC_CSDPI,
895		    CSDPI_SRC_BURST_64 | CSDPI_DST_BURST_64 |
896		    CSDPI_DST_PACKED | CSDPI_WRITE_POSTED_EXCEPT_LAST |
897		    CSDPI_DATA_TYPE_32);
898	} else {
899		omapdma_write_ch_reg(0, OMAPDMAC_CSDPI,
900		    CSDPI_SRC_BURST_64 | CSDPI_DST_BURST_64 |
901		    CSDPI_DST_PACKED | CSDPI_WRITE_POSTED_EXCEPT_LAST |
902		    CSDPI_DATA_TYPE_16);
903	}
904
905	omapdma_write_ch_reg(0, OMAPDMAC_CEN, wi);
906	omapdma_write_ch_reg(0, OMAPDMAC_CFN, he);
907	omapdma_write_ch_reg(0, OMAPDMAC_CDSA, daddr);
908	omapdma_write_ch_reg(0, OMAPDMAC_CCR,
909	    CCR_CONST_FILL_ENABLE | CCR_DST_AMODE_DOUBLE_INDEX |
910	    CCR_SRC_AMODE_CONST_ADDR);
911	omapdma_write_ch_reg(0, OMAPDMAC_CDEI, 1);
912	omapdma_write_ch_reg(0, OMAPDMAC_CDFI,
913	    (sc->sc_stride - width_in_bytes) + 1);
914	omapdma_write_ch_reg(0, OMAPDMAC_COLOR, colour);
915	omapdma_write_ch_reg(0, OMAPDMAC_CCR,
916	    CCR_CONST_FILL_ENABLE | CCR_DST_AMODE_DOUBLE_INDEX |
917	    CCR_SRC_AMODE_CONST_ADDR | CCR_ENABLE);
918}
919
920static void
921omapfb_bitblt(struct omapfb_softc *sc, int xs, int ys, int xd, int yd,
922    int wi, int he, int rop)
923{
924	int bpp = sc->sc_depth >> 3;	/* bytes per pixel */
925	int width_in_bytes = wi * bpp;
926
927	int hstep, vstep;
928	uint32_t saddr, daddr;
929
930	saddr = sc->sc_fbhwaddr + sc->sc_stride * ys + xs * bpp;
931	daddr = sc->sc_fbhwaddr + sc->sc_stride * yd + xd * bpp;
932
933	if (ys < yd) {
934		/* need to go vertically backwards */
935		vstep = 1 - (sc->sc_stride + width_in_bytes);
936		saddr += sc->sc_stride * (he - 1);
937		daddr += sc->sc_stride * (he - 1);
938	} else
939		vstep = (sc->sc_stride - width_in_bytes) + 1;
940	if ((xs < xd) && (ys == yd)) {
941		/*
942		 * need to go horizontally backwards, only needed if source
943		 * and destination pixels are on the same line
944		 */
945		hstep = 1 - (sc->sc_depth >> 2);
946		vstep = sc->sc_stride + bpp * (wi - 1) + 1;
947		saddr += bpp * (wi - 1);
948		daddr += bpp * (wi - 1);
949	} else
950		hstep = 1;
951
952	omapfb_wait_idle(sc);
953	if (((saddr | daddr | width_in_bytes) & 3) == 0) {
954		/*
955		 * everything is properly aligned so we can copy stuff in
956		 * 32bit chunks instead of pixel by pixel
957		 */
958		wi = wi >> 1;
959		omapdma_write_ch_reg(0, OMAPDMAC_CSDPI,
960		    CSDPI_SRC_BURST_64 | CSDPI_DST_BURST_64 |
961		    CSDPI_DST_PACKED | CSDPI_WRITE_POSTED_EXCEPT_LAST |
962		    CSDPI_DATA_TYPE_32);
963	} else {
964		omapdma_write_ch_reg(0, OMAPDMAC_CSDPI,
965		    CSDPI_SRC_BURST_64 | CSDPI_DST_BURST_64 |
966		    CSDPI_DST_PACKED | CSDPI_WRITE_POSTED_EXCEPT_LAST |
967		    CSDPI_DATA_TYPE_16);
968	}
969
970	omapdma_write_ch_reg(0, OMAPDMAC_CEN, wi);
971	omapdma_write_ch_reg(0, OMAPDMAC_CFN, he);
972	omapdma_write_ch_reg(0, OMAPDMAC_CSSA, saddr);
973	omapdma_write_ch_reg(0, OMAPDMAC_CDSA, daddr);
974	omapdma_write_ch_reg(0, OMAPDMAC_CCR,
975	    CCR_DST_AMODE_DOUBLE_INDEX |
976	    CCR_SRC_AMODE_DOUBLE_INDEX);
977	omapdma_write_ch_reg(0, OMAPDMAC_CSEI, hstep);
978	omapdma_write_ch_reg(0, OMAPDMAC_CSFI, vstep);
979	omapdma_write_ch_reg(0, OMAPDMAC_CDEI, hstep);
980	omapdma_write_ch_reg(0, OMAPDMAC_CDFI, vstep);
981	omapdma_write_ch_reg(0, OMAPDMAC_CCR,
982	    CCR_DST_AMODE_DOUBLE_INDEX |
983	    CCR_SRC_AMODE_DOUBLE_INDEX | CCR_ENABLE);
984}
985
986static void
987omapfb_cursor(void *cookie, int on, int row, int col)
988{
989	struct rasops_info *ri = cookie;
990	struct vcons_screen *scr = ri->ri_hw;
991	struct omapfb_softc *sc = scr->scr_cookie;
992	int pos;
993
994	pos = col + row * ri->ri_cols;
995	pos += vcons_offset_to_zero(scr);
996	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
997		if (ri->ri_flg & RI_CURSOR) {
998			omapfb_putchar(cookie, row, col, scr->scr_chars[pos],
999			    scr->scr_attrs[pos]);
1000			ri->ri_flg &= ~RI_CURSOR;
1001		}
1002		ri->ri_crow = row;
1003		ri->ri_ccol = col;
1004		if (on) {
1005			omapfb_putchar(cookie, row, col, scr->scr_chars[pos],
1006			    scr->scr_attrs[pos] ^ 0x0f0f0000);
1007			ri->ri_flg |= RI_CURSOR;
1008		}
1009	} else {
1010		scr->scr_ri.ri_crow = row;
1011		scr->scr_ri.ri_ccol = col;
1012		scr->scr_ri.ri_flg &= ~RI_CURSOR;
1013	}
1014}
1015
1016static void
1017omapfb_putchar(void *cookie, int row, int col, u_int c, long attr)
1018{
1019	struct rasops_info *ri = cookie;
1020	struct vcons_screen *scr = ri->ri_hw;
1021	struct omapfb_softc *sc = scr->scr_cookie;
1022
1023	if (c == 0x20) {
1024		uint32_t fg, bg, ul;
1025		rasops_unpack_attr(attr, &fg, &bg, &ul);
1026		omapfb_rectfill(sc,
1027		    ri->ri_xorigin + ri->ri_font->fontwidth * col,
1028		    ri->ri_yorigin + ri->ri_font->fontheight * row,
1029		    ri->ri_font->fontwidth,
1030		    ri->ri_font->fontheight,
1031		    ri->ri_devcmap[bg]);
1032		return;
1033	}
1034	omapfb_wait_idle(sc);
1035	sc->sc_putchar(cookie, row, col, c, attr);
1036}
1037
1038static void
1039omapfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1040{
1041	struct rasops_info *ri = cookie;
1042	struct vcons_screen *scr = ri->ri_hw;
1043	struct omapfb_softc *sc = scr->scr_cookie;
1044	int32_t xs, xd, y, width, height;
1045
1046	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1047		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1048		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1049		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1050		width = ri->ri_font->fontwidth * ncols;
1051		height = ri->ri_font->fontheight;
1052		omapfb_bitblt(sc, xs, y, xd, y, width, height, 12);
1053	}
1054}
1055
1056static void
1057omapfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1058{
1059	struct rasops_info *ri = cookie;
1060	struct vcons_screen *scr = ri->ri_hw;
1061	struct omapfb_softc *sc = scr->scr_cookie;
1062	int32_t x, y, width, height, fg, bg, ul;
1063
1064	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1065		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1066		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1067		width = ri->ri_font->fontwidth * ncols;
1068		height = ri->ri_font->fontheight;
1069		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1070
1071		omapfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1072	}
1073}
1074
1075static void
1076omapfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1077{
1078	struct rasops_info *ri = cookie;
1079	struct vcons_screen *scr = ri->ri_hw;
1080	struct omapfb_softc *sc = scr->scr_cookie;
1081	int32_t x, ys, yd, width, height;
1082
1083	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1084		x = ri->ri_xorigin;
1085		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1086		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1087		width = ri->ri_emuwidth;
1088		height = ri->ri_font->fontheight * nrows;
1089		omapfb_bitblt(sc, x, ys, x, yd, width, height, 12);
1090	}
1091}
1092
1093static void
1094omapfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1095{
1096	struct rasops_info *ri = cookie;
1097	struct vcons_screen *scr = ri->ri_hw;
1098	struct omapfb_softc *sc = scr->scr_cookie;
1099	int32_t x, y, width, height, fg, bg, ul;
1100
1101	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1102		x = ri->ri_xorigin;
1103		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1104		width = ri->ri_emuwidth;
1105		height = ri->ri_font->fontheight * nrows;
1106		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1107
1108		omapfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1109	}
1110}
1111#endif /* NOMAPDMA > 0 */
1112
1113static void
1114omapfb_move_cursor(struct omapfb_softc *sc, int x, int y)
1115{
1116	uint32_t pos, reg, addr;
1117	int xx, yy, wi = 64, he = 64;
1118
1119	/*
1120	 * we need to special case anything and everything where the cursor
1121	 * may be partially off screen
1122	 */
1123
1124	addr = sc->sc_fbhwaddr + sc->sc_cursor_offset;
1125	xx = x - sc->sc_hot_x;
1126	yy = y - sc->sc_hot_y;
1127
1128	/*
1129	 * if we're off to the top or left we need to shif the start address
1130	 * and shrink the gfx layer size
1131	 */
1132	if (xx < 0) {
1133		wi += xx;
1134		addr -= xx * 4;
1135		xx = 0;
1136	}
1137	if (yy < 0) {
1138		he += yy;
1139		addr -= yy * 64 * 4;
1140		yy = 0;
1141	}
1142	if (xx > (sc->sc_width - 64)) {
1143		wi -= (xx + 64 - sc->sc_width);
1144	}
1145	if (yy > (sc->sc_height - 64)) {
1146		he -= (yy + 64 - sc->sc_height);
1147	}
1148	pos = (yy << 16) | xx;
1149	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_BASE_0,
1150	    addr);
1151	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_POSITION,
1152	    pos);
1153	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_SIZE,
1154	    ((he - 1) << 16) | (wi - 1));
1155	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_GFX_ROW_INC,
1156	    (64 - wi) * 4 + 1);
1157	/*
1158	 * now tell the video controller that we're done mucking around and
1159	 * actually update its settings
1160	 */
1161	reg = bus_space_read_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL);
1162	bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL,
1163	    reg | OMAP_DISPC_CTRL_GO_LCD | OMAP_DISPC_CTRL_GO_DIGITAL);
1164}
1165
1166static int
1167omapfb_do_cursor(struct omapfb_softc * sc,
1168                           struct wsdisplay_cursor *cur)
1169{
1170	int whack = 0;
1171	int shape = 0;
1172
1173	if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1174		uint32_t attr = OMAP_DISPC_ATTR_BURST_16x32 |
1175				OMAP_DISPC_ATTR_ARGB32 |
1176				OMAP_DISPC_ATTR_REPLICATION;
1177
1178		if (cur->enable) attr |= OMAP_DISPC_ATTR_ENABLE;
1179		bus_space_write_4(sc->sc_iot, sc->sc_regh,
1180		    OMAPFB_DISPC_GFX_ATTRIBUTES, attr);
1181		whack = 1;
1182	}
1183	if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1184
1185		sc->sc_hot_x = cur->hot.x;
1186		sc->sc_hot_y = cur->hot.y;
1187		cur->which |= WSDISPLAY_CURSOR_DOPOS;
1188	}
1189	if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1190
1191		omapfb_move_cursor(sc, cur->pos.x, cur->pos.y);
1192	}
1193	if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1194		int i;
1195		uint32_t val;
1196
1197		for (i = 0; i < uimin(cur->cmap.count, 3); i++) {
1198			val = (cur->cmap.red[i] << 16 ) |
1199			      (cur->cmap.green[i] << 8) |
1200			      (cur->cmap.blue[i] ) |
1201			      0xff000000;
1202			sc->sc_cursor_cmap[i + cur->cmap.index + 2] = val;
1203		}
1204		shape = 1;
1205	}
1206	if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1207
1208		copyin(cur->mask, sc->sc_cursor_mask, 64 * 8);
1209		copyin(cur->image, sc->sc_cursor_bitmap, 64 * 8);
1210		shape = 1;
1211	}
1212	if (shape) {
1213		int i, j, idx;
1214		uint8_t mask;
1215
1216		for (i = 0; i < 64 * 8; i++) {
1217			mask = 0x01;
1218			for (j = 0; j < 8; j++) {
1219				idx = ((sc->sc_cursor_mask[i] & mask) ? 2 : 0) |
1220				    ((sc->sc_cursor_bitmap[i] & mask) ? 1 : 0);
1221				sc->sc_cursor_img[i * 8 + j] =
1222				    sc->sc_cursor_cmap[idx];
1223				mask = mask << 1;
1224			}
1225		}
1226	}
1227	if (whack) {
1228		uint32_t reg;
1229
1230		reg = bus_space_read_4(sc->sc_iot, sc->sc_regh,
1231		    OMAPFB_DISPC_CONTROL);
1232		bus_space_write_4(sc->sc_iot, sc->sc_regh, OMAPFB_DISPC_CONTROL,
1233		    reg | OMAP_DISPC_CTRL_GO_LCD | OMAP_DISPC_CTRL_GO_DIGITAL);
1234	}
1235	return 0;
1236
1237}
1238
1239static int
1240omapfb_console_match(int phandle)
1241{
1242	return of_compatible_match(phandle, compat_data);
1243}
1244
1245static void
1246omapfb_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
1247{
1248	omapfb_console_phandle = faa->faa_phandle;
1249}
1250
1251static const struct fdt_console omapfb_fdt_console = {
1252	.match = omapfb_console_match,
1253	.consinit = omapfb_console_consinit,
1254};
1255
1256FDT_CONSOLE(omapfb, &omapfb_fdt_console);
1257