xref: /netbsd-src/sys/arch/arm/ti/omap3_dss.c (revision f82ca6eefb335bf699131a4ebe4cc00c8911db8a)
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 
61 struct 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 
100 static int	omapfb_match(device_t, cfdata_t, void *);
101 static void	omapfb_attach(device_t, device_t, void *);
102 
103 CFATTACH_DECL_NEW(omap3_dss, sizeof(struct omapfb_softc),
104     omapfb_match, omapfb_attach, NULL, NULL);
105 
106 static int	omapfb_ioctl(void *, void *, u_long, void *, int,
107 			     struct lwp *);
108 static paddr_t	omapfb_mmap(void *, void *, off_t, int);
109 static void	omapfb_init_screen(void *, struct vcons_screen *, int, long *);
110 
111 static int	omapfb_putcmap(struct omapfb_softc *, struct wsdisplay_cmap *);
112 static int 	omapfb_getcmap(struct omapfb_softc *, struct wsdisplay_cmap *);
113 static void	omapfb_restore_palette(struct omapfb_softc *);
114 static void 	omapfb_putpalreg(struct omapfb_softc *, int, uint8_t,
115 			    uint8_t, uint8_t);
116 
117 static int	omapfb_set_depth(struct omapfb_softc *, int);
118 static void	omapfb_set_video(struct omapfb_softc *, int);
119 
120 static void 	omapfb_move_cursor(struct omapfb_softc *, int, int);
121 static int	omapfb_do_cursor(struct omapfb_softc *,
122 		    struct wsdisplay_cursor *);
123 
124 #if NOMAPDMA > 0
125 static void	omapfb_init(struct omapfb_softc *);
126 static void	omapfb_wait_idle(struct omapfb_softc *);
127 static void	omapfb_rectfill(struct omapfb_softc *, int, int, int, int,
128 			    uint32_t);
129 static void	omapfb_bitblt(struct omapfb_softc *, int, int, int, int, int,
130 			    int, int);
131 
132 static void	omapfb_cursor(void *, int, int, int);
133 static void	omapfb_putchar(void *, int, int, u_int, long);
134 static void	omapfb_copycols(void *, int, int, int, int);
135 static void	omapfb_erasecols(void *, int, int, int, long);
136 static void	omapfb_copyrows(void *, int, int, int);
137 static void	omapfb_eraserows(void *, int, int, long);
138 #endif /* NOMAPDMA > 0 */
139 
140 struct 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 
151 uint32_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 
164 extern const u_char rasops_cmap[768];
165 
166 static const struct device_compatible_entry compat_data[] = {
167 	{ .compat = "ti,omap3-dss" },
168 	DEVICE_COMPAT_EOL
169 };
170 
171 static int omapfb_console_phandle = -1;
172 
173 static int
omapfb_match(device_t parent,cfdata_t match,void * aux)174 omapfb_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 
181 static void
omapfb_attach(device_t parent,device_t self,void * aux)182 omapfb_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 
497 static int
omapfb_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)498 omapfb_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 
631 static paddr_t
omapfb_mmap(void * v,void * vs,off_t offset,int prot)632 omapfb_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 
647 static void
omapfb_init_screen(void * cookie,struct vcons_screen * scr,int existing,long * defattr)648 omapfb_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 
689 static int
omapfb_putcmap(struct omapfb_softc * sc,struct wsdisplay_cmap * cm)690 omapfb_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 
727 static int
omapfb_getcmap(struct omapfb_softc * sc,struct wsdisplay_cmap * cm)728 omapfb_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 
750 static void
omapfb_restore_palette(struct omapfb_softc * sc)751 omapfb_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 
761 static void
omapfb_putpalreg(struct omapfb_softc * sc,int idx,uint8_t r,uint8_t g,uint8_t b)762 omapfb_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 
774 static int
omapfb_set_depth(struct omapfb_softc * sc,int d)775 omapfb_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 
818 static void
omapfb_set_video(struct omapfb_softc * sc,int on)819 omapfb_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
851 static void
omapfb_init(struct omapfb_softc * sc)852 omapfb_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 
861 static void
omapfb_wait_idle(struct omapfb_softc * sc)862 omapfb_wait_idle(struct omapfb_softc *sc)
863 {
864 	while ((omapdma_read_ch_reg(0, OMAPDMAC_CCR) & CCR_WR_ACTIVE) != 0);
865 }
866 
867 static void
omapfb_rectfill(struct omapfb_softc * sc,int x,int y,int wi,int he,uint32_t colour)868 omapfb_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 
920 static void
omapfb_bitblt(struct omapfb_softc * sc,int xs,int ys,int xd,int yd,int wi,int he,int rop)921 omapfb_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 
986 static void
omapfb_cursor(void * cookie,int on,int row,int col)987 omapfb_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 
1016 static void
omapfb_putchar(void * cookie,int row,int col,u_int c,long attr)1017 omapfb_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 
1038 static void
omapfb_copycols(void * cookie,int row,int srccol,int dstcol,int ncols)1039 omapfb_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 
1056 static void
omapfb_erasecols(void * cookie,int row,int startcol,int ncols,long fillattr)1057 omapfb_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 
1075 static void
omapfb_copyrows(void * cookie,int srcrow,int dstrow,int nrows)1076 omapfb_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 
1093 static void
omapfb_eraserows(void * cookie,int row,int nrows,long fillattr)1094 omapfb_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 
1113 static void
omapfb_move_cursor(struct omapfb_softc * sc,int x,int y)1114 omapfb_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 
1166 static int
omapfb_do_cursor(struct omapfb_softc * sc,struct wsdisplay_cursor * cur)1167 omapfb_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 
1239 static int
omapfb_console_match(int phandle)1240 omapfb_console_match(int phandle)
1241 {
1242 	return of_compatible_match(phandle, compat_data);
1243 }
1244 
1245 static void
omapfb_console_consinit(struct fdt_attach_args * faa,u_int uart_freq)1246 omapfb_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
1247 {
1248 	omapfb_console_phandle = faa->faa_phandle;
1249 }
1250 
1251 static const struct fdt_console omapfb_fdt_console = {
1252 	.match = omapfb_console_match,
1253 	.consinit = omapfb_console_consinit,
1254 };
1255 
1256 FDT_CONSOLE(omapfb, &omapfb_fdt_console);
1257