Home | History | Annotate | Line # | Download | only in ti
      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