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