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