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