Home | History | Annotate | Line # | Download | only in xscale
pxa2x0_lcd.c revision 1.13
      1 /* $NetBSD: pxa2x0_lcd.c,v 1.13 2006/04/12 19:38:22 jmmv Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2002  Genetec Corporation.  All rights reserved.
      5  * Written by Hiroyuki Bessho for Genetec Corporation.
      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  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed for the NetBSD Project by
     18  *	Genetec Corporation.
     19  * 4. The name of Genetec Corporation may not be used to endorse or
     20  *    promote products derived from this software without specific prior
     21  *    written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
     27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     33  * POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 /*
     37  * Support PXA2[15]0's integrated LCD controller.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: pxa2x0_lcd.c,v 1.13 2006/04/12 19:38:22 jmmv Exp $");
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/conf.h>
     46 #include <sys/uio.h>
     47 #include <sys/malloc.h>
     48 #include <sys/kernel.h>			/* for cold */
     49 
     50 #include <uvm/uvm_extern.h>
     51 
     52 #include <dev/cons.h>
     53 #include <dev/wscons/wsconsio.h>
     54 #include <dev/wscons/wsdisplayvar.h>
     55 #include <dev/wscons/wscons_callbacks.h>
     56 #include <dev/rasops/rasops.h>
     57 #include <dev/wsfont/wsfont.h>
     58 
     59 #include <machine/bus.h>
     60 #include <machine/cpu.h>
     61 #include <arm/cpufunc.h>
     62 
     63 #include <arm/xscale/pxa2x0cpu.h>
     64 #include <arm/xscale/pxa2x0var.h>
     65 #include <arm/xscale/pxa2x0reg.h>
     66 #include <arm/xscale/pxa2x0_lcd.h>
     67 #include <arm/xscale/pxa2x0_gpio.h>
     68 
     69 #include "wsdisplay.h"
     70 
     71 int lcdintr(void *);
     72 
     73 void
     74 pxa2x0_lcd_geometry(struct pxa2x0_lcd_softc *sc,
     75     const struct lcd_panel_geometry *info)
     76 {
     77 	int lines;
     78 	bus_space_tag_t iot = sc->iot;
     79 	bus_space_handle_t ioh = sc->ioh;
     80 	uint32_t ccr0;
     81 
     82 	sc->geometry = info;
     83 
     84 	ccr0 = LCCR0_IMASK;
     85 	if (info->panel_info & LCDPANEL_ACTIVE)
     86 		ccr0 |= LCCR0_PAS;	/* active mode */
     87 	if ((info->panel_info & (LCDPANEL_DUAL|LCDPANEL_ACTIVE))
     88 	    == LCDPANEL_DUAL)
     89 		ccr0 |= LCCR0_SDS; /* dual panel */
     90 	if (info->panel_info & LCDPANEL_MONOCHROME)
     91 		ccr0 |= LCCR0_CMS;
     92 	bus_space_write_4(iot, ioh, LCDC_LCCR0, ccr0);
     93 
     94 	bus_space_write_4(iot, ioh, LCDC_LCCR1,
     95 	    (info->panel_width-1)
     96 	    | ((info->hsync_pulse_width-1)<<10)
     97 	    | ((info->end_line_wait-1)<<16)
     98 	    | ((info->beg_line_wait-1)<<24));
     99 
    100 	if (info->panel_info & LCDPANEL_DUAL)
    101 		lines = info->panel_height/2 + info->extra_lines;
    102 	else
    103 		lines = info->panel_height + info->extra_lines;
    104 
    105 	bus_space_write_4(iot, ioh, LCDC_LCCR2,
    106 	    (lines-1)
    107 	    | (info->vsync_pulse_width<<10)
    108 	    | (info->end_frame_wait<<16)
    109 	    | (info->beg_frame_wait<<24));
    110 
    111 	bus_space_write_4(iot, ioh, LCDC_LCCR3,
    112 	    (info->pixel_clock_div<<0)
    113 	    | (info->ac_bias << 8)
    114 	    | ((info->panel_info &
    115 		(LCDPANEL_VSP|LCDPANEL_HSP|LCDPANEL_PCP|LCDPANEL_OEP))
    116 		<<20)
    117 	    | (4 << 24) /* 16bpp */
    118 	    | ((info->panel_info & LCDPANEL_DPC) ? (1<<27) : 0)
    119 	    );
    120 }
    121 
    122 void
    123 pxa2x0_lcd_attach_sub(struct pxa2x0_lcd_softc *sc,
    124     struct pxaip_attach_args *pxa, const struct lcd_panel_geometry *geom)
    125 {
    126 	bus_space_tag_t iot = pxa->pxa_iot;
    127 	bus_space_handle_t ioh;
    128 	int error, nldd;
    129 
    130 	sc->n_screens = 0;
    131 	LIST_INIT(&sc->screens);
    132 
    133 	/* map controller registers */
    134 	error = bus_space_map(iot, PXA2X0_LCDC_BASE,
    135 			       PXA2X0_LCDC_SIZE, 0, &ioh);
    136 	if (error) {
    137 		printf(": failed to map registers %d", error);
    138 		return;
    139 	}
    140 
    141 	sc->iot = iot;
    142 	sc->ioh = ioh;
    143 	sc->dma_tag = &pxa2x0_bus_dma_tag;
    144 
    145 	sc->ih = pxa2x0_intr_establish(17, IPL_BIO, lcdintr, sc);
    146 	if (sc->ih == NULL)
    147 		printf("%s: unable to establish interrupt at irq %d",
    148 		    sc->dev.dv_xname, 17);
    149 
    150 	/* Initialize LCD controller */
    151 
    152 	/* enable clock */
    153 	pxa2x0_clkman_config(CKEN_LCD, 1);
    154 
    155 	bus_space_write_4(iot, ioh, LCDC_LCCR0, LCCR0_IMASK);
    156 
    157 	/*
    158 	 * setup GP[77:58] for LCD
    159 	 */
    160 	/* Always use [FLP]CLK, ACBIAS */
    161 	pxa2x0_gpio_set_function(74, GPIO_ALT_FN_2_OUT);
    162 	pxa2x0_gpio_set_function(75, GPIO_ALT_FN_2_OUT);
    163 	pxa2x0_gpio_set_function(76, GPIO_ALT_FN_2_OUT);
    164 	pxa2x0_gpio_set_function(77, GPIO_ALT_FN_2_OUT);
    165 
    166 	if ((geom->panel_info & LCDPANEL_ACTIVE) ||
    167 	    ((geom->panel_info & (LCDPANEL_MONOCHROME|LCDPANEL_DUAL)) ==
    168 	    LCDPANEL_DUAL)) {
    169 		/* active and color dual panel need L_DD[15:0] */
    170 		nldd = 16;
    171 	} else
    172 	if ((geom->panel_info & LCDPANEL_DUAL) ||
    173 	    !(geom->panel_info & LCDPANEL_MONOCHROME)) {
    174 		/* dual or color need L_DD[7:0] */
    175 		nldd = 8;
    176 	} else {
    177 		/* Otherwise just L_DD[3:0] */
    178 		nldd = 4;
    179 	}
    180 
    181 	if (CPU_IS_PXA270 && nldd==16) {
    182 		pxa2x0_gpio_set_function(86, GPIO_ALT_FN_2_OUT);
    183 		pxa2x0_gpio_set_function(87, GPIO_ALT_FN_2_OUT);
    184 	}
    185 	while (nldd--)
    186 		pxa2x0_gpio_set_function(58 + nldd, GPIO_ALT_FN_2_OUT);
    187 
    188 	pxa2x0_lcd_geometry(sc, geom);
    189 }
    190 
    191 
    192 int
    193 lcdintr(void *arg)
    194 {
    195 	struct pxa2x0_lcd_softc *sc = arg;
    196 	bus_space_tag_t iot = sc->iot;
    197 	bus_space_handle_t ioh = sc->ioh;
    198 
    199 	static uint32_t status;
    200 
    201 	status = bus_space_read_4(iot, ioh, LCDC_LCSR);
    202 	/* Clear stickey status bits */
    203 	bus_space_write_4(iot, ioh, LCDC_LCSR, status);
    204 
    205 	return 1;
    206 }
    207 
    208 void
    209 pxa2x0_lcd_start_dma(struct pxa2x0_lcd_softc *sc,
    210     struct pxa2x0_lcd_screen *scr)
    211 {
    212 	uint32_t tmp;
    213 	bus_space_tag_t iot = sc->iot;
    214 	bus_space_handle_t ioh = sc->ioh;
    215 	int val, save;
    216 
    217 	save = disable_interrupts(I32_bit);
    218 
    219 	switch (scr->depth) {
    220 	case 1: val = 0; break;
    221 	case 2: val = 1; break;
    222 	case 4: val = 2; break;
    223 	case 8: val = 3; break;
    224 	case 16: val = 4; break;
    225 	case 18: val = 5; break;
    226 	case 24: val = 33; break;
    227 	default:
    228 		val = 4; break;
    229 	}
    230 
    231 	tmp = bus_space_read_4(iot, ioh, LCDC_LCCR3);
    232 	if (CPU_IS_PXA270)
    233 		bus_space_write_4(iot, ioh, LCDC_LCCR3,
    234 		  (tmp & ~(LCCR3_BPP|(1<<29))) | (val << LCCR3_BPP_SHIFT));
    235 	else
    236 		bus_space_write_4(iot, ioh, LCDC_LCCR3,
    237 		    (tmp & ~LCCR3_BPP) | (val << LCCR3_BPP_SHIFT));
    238 
    239 	bus_space_write_4(iot, ioh, LCDC_FDADR0,
    240 	    scr->depth >= 16 ? scr->dma_desc_pa :
    241 	    scr->dma_desc_pa + 2 * sizeof (struct lcd_dma_descriptor));
    242 	bus_space_write_4(iot, ioh, LCDC_FDADR1,
    243 	    scr->dma_desc_pa + 1 * sizeof (struct lcd_dma_descriptor));
    244 
    245 	/* clear status */
    246 	bus_space_write_4(iot, ioh, LCDC_LCSR, 0);
    247 
    248 	delay(1000);			/* ??? */
    249 
    250 	/* Enable LCDC */
    251 	tmp = bus_space_read_4(iot, ioh, LCDC_LCCR0);
    252 	/*tmp &= ~LCCR0_SFM;*/
    253 	bus_space_write_4(iot, ioh, LCDC_LCCR0, tmp | LCCR0_ENB);
    254 
    255 	restore_interrupts(save);
    256 
    257 }
    258 
    259 
    260 #if NWSDISPLAY > 0
    261 static void
    262 pxa2x0_lcd_stop_dma(struct pxa2x0_lcd_softc *sc)
    263 {
    264 	/* Stop LCD DMA after current frame */
    265 	bus_space_write_4(sc->iot, sc->ioh, LCDC_LCCR0,
    266 	    LCCR0_DIS |
    267 	    bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0));
    268 
    269 	/* wait for disabling done.
    270 	   XXX: use interrupt. */
    271 	while (LCCR0_ENB &
    272 	    bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0))
    273 		;
    274 
    275 	bus_space_write_4(sc->iot, sc->ioh, LCDC_LCCR0,
    276 	    ~LCCR0_DIS &
    277 	    bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0));
    278 }
    279 #endif
    280 
    281 #define _rgb(r,g,b)	(((r)<<11) | ((g)<<5) | b)
    282 #define rgb(r,g,b)	_rgb((r)>>1,g,(b)>>1)
    283 
    284 #define L	0x1f			/* low intensity */
    285 #define H	0x3f			/* hight intensity */
    286 
    287 static uint16_t basic_color_map[] = {
    288 	rgb(	0,   0,   0),		/* black */
    289 	rgb(	L,   0,   0),		/* red */
    290 	rgb(	0,   L,   0),		/* green */
    291 	rgb(	L,   L,   0),		/* brown */
    292 	rgb(	0,   0,   L),		/* blue */
    293 	rgb(	L,   0,   L),		/* magenta */
    294 	rgb(	0,   L,   L),		/* cyan */
    295 	_rgb(0x1c,0x38,0x1c),		/* white */
    296 
    297 	rgb(	L,   L,   L),		/* black */
    298 	rgb(	H,   0,   0),		/* red */
    299 	rgb(	0,   H,   0),		/* green */
    300 	rgb(	H,   H,   0),		/* brown */
    301 	rgb(	0,   0,   H),		/* blue */
    302 	rgb(	H,   0,   H),		/* magenta */
    303 	rgb(	0,   H,   H),		/* cyan */
    304 	rgb(	H,   H,   H)
    305 };
    306 
    307 #undef H
    308 #undef L
    309 
    310 static void
    311 init_pallet(uint16_t *buf, int depth)
    312 {
    313 	int i;
    314 
    315 	/* convert RGB332 to RGB565 */
    316 	switch (depth) {
    317 	case 8:
    318 	case 4:
    319 #if 0
    320 		for (i=0; i <= 255; ++i) {
    321 			buf[i] = ((9 * ((i>>5) & 0x07)) <<11) |
    322 			    ((9 * ((i>>2) & 0x07)) << 5) |
    323 			    ((21 * (i & 0x03))/2);
    324 		}
    325 #else
    326 		memcpy(buf, basic_color_map, sizeof basic_color_map);
    327 		for (i=16; i < (1<<depth); ++i)
    328 			buf[i] = 0xffff;
    329 #endif
    330 		break;
    331 	case 16:
    332 		/* pallet is not needed */
    333 		break;
    334 	default:
    335 		/* other depths are not supported */
    336 		break;
    337 	}
    338 }
    339 
    340 struct pxa2x0_lcd_screen *
    341 pxa2x0_lcd_new_screen(struct pxa2x0_lcd_softc *sc,
    342     int depth)
    343 {
    344 	struct pxa2x0_lcd_screen *scr = NULL;
    345 	int width, height;
    346 	bus_size_t size;
    347 	int error, pallet_size;
    348 	int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
    349 	struct lcd_dma_descriptor *desc;
    350 	paddr_t buf_pa, desc_pa;
    351 
    352 	width = sc->geometry->panel_width;
    353 	height = sc->geometry->panel_height;
    354 	pallet_size = 0;
    355 
    356 	switch (depth) {
    357 	case 1:
    358 	case 2:
    359 	case 4:
    360 	case 8:
    361 		pallet_size = (1<<depth) * sizeof (uint16_t);
    362 		/* FALLTHROUGH */
    363 	case 16:
    364 		size = roundup(width,4)*depth/8 * height;
    365 		break;
    366 	case 18:
    367 	case 24:
    368 		size = roundup(width,4) * 4 * height;
    369 		break;
    370 	case 19:
    371 	case 25:
    372 		printf("%s: Not supported depth (%d)\n", sc->dev.dv_xname, depth);
    373 		return NULL;
    374 	default:
    375 		printf("%s: Unknown depth (%d)\n", sc->dev.dv_xname, depth);
    376 		return NULL;
    377 	}
    378 
    379 	scr = malloc(sizeof *scr, M_DEVBUF,
    380 	    M_ZERO | (cold ? M_NOWAIT : M_WAITOK));
    381 
    382 	if (scr == NULL)
    383 		return NULL;
    384 
    385 	scr->nsegs = 0;
    386 	scr->depth = depth;
    387 	scr->buf_size = size;
    388 	scr->buf_va = NULL;
    389 	size = roundup(size,16) + 3 * sizeof (struct lcd_dma_descriptor)
    390 	    + pallet_size;
    391 
    392 	error = bus_dmamem_alloc(sc->dma_tag, size, 16, 0,
    393 	    scr->segs, 1, &(scr->nsegs), busdma_flag);
    394 
    395 	if (error || scr->nsegs != 1) {
    396 		/* XXX:
    397 		 * Actually we can handle nsegs>1 case by means
    398 		 * of multiple DMA descriptors for a panel.  It
    399 		 * will make code here a bit hairly.
    400 		 */
    401 		goto bad;
    402 	}
    403 
    404 	error = bus_dmamem_map(sc->dma_tag, scr->segs, scr->nsegs,
    405 	    size, (caddr_t *)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT);
    406 	if (error)
    407 		goto bad;
    408 
    409 
    410 	memset (scr->buf_va, 0, scr->buf_size);
    411 
    412 	/* map memory for DMA */
    413 	if (bus_dmamap_create(sc->dma_tag, 1024*1024*2, 1,
    414 	    1024*1024*2, 0,  busdma_flag, &scr->dma))
    415 		goto bad;
    416 	error = bus_dmamap_load(sc->dma_tag, scr->dma,
    417 	    scr->buf_va, size, NULL, busdma_flag);
    418 	if (error) {
    419 		goto bad;
    420 	}
    421 
    422 	buf_pa = scr->segs[0].ds_addr;
    423 	desc_pa = buf_pa + roundup(size, PAGE_SIZE) - 3*sizeof *desc;
    424 
    425 	/* make descriptors at the top of mapped memory */
    426 	desc = (struct lcd_dma_descriptor *)(
    427 		(caddr_t)(scr->buf_va) + roundup(size, PAGE_SIZE) -
    428 			  3*sizeof *desc);
    429 
    430 	desc[0].fdadr = desc_pa;
    431 	desc[0].fsadr = buf_pa;
    432 	desc[0].ldcmd = scr->buf_size;
    433 
    434 	if (pallet_size) {
    435 		init_pallet((uint16_t *)((char *)desc - pallet_size), depth);
    436 
    437 		desc[2].fdadr = desc_pa; /* chain to panel 0 */
    438 		desc[2].fsadr = desc_pa - pallet_size;
    439 		desc[2].ldcmd = pallet_size | LDCMD_PAL;
    440 	}
    441 
    442 	if (sc->geometry->panel_info & LCDPANEL_DUAL) {
    443 		/* Dual panel */
    444 		desc[1].fdadr = desc_pa + sizeof *desc;
    445 		desc[1].fsadr = buf_pa + scr->buf_size/2;
    446 		desc[0].ldcmd = desc[1].ldcmd = scr->buf_size/2;
    447 
    448 	}
    449 
    450 #if 0
    451 	desc[0].ldcmd |= LDCMD_SOFINT;
    452 	desc[1].ldcmd |= LDCMD_SOFINT;
    453 #endif
    454 
    455 	scr->dma_desc = desc;
    456 	scr->dma_desc_pa = desc_pa;
    457 	scr->map_size = size;		/* used when unmap this. */
    458 
    459 	LIST_INSERT_HEAD(&(sc->screens), scr, link);
    460 	sc->n_screens++;
    461 
    462 	return scr;
    463 
    464  bad:
    465 	if (scr) {
    466 		if (scr->buf_va)
    467 			bus_dmamem_unmap(sc->dma_tag, scr->buf_va, size);
    468 		if (scr->nsegs)
    469 			bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs);
    470 		free(scr, M_DEVBUF);
    471 	}
    472 	return NULL;
    473 }
    474 
    475 
    476 #if NWSDISPLAY > 0
    477 
    478 /*
    479  * Initialize struct wsscreen_descr based on values calculated by
    480  * raster operation subsystem.
    481  */
    482 int
    483 pxa2x0_lcd_setup_wsscreen(struct pxa2x0_wsscreen_descr *descr,
    484     const struct lcd_panel_geometry *geom,
    485     const char *fontname)
    486 {
    487 	int width = geom->panel_width;
    488 	int height = geom->panel_height;
    489 	int cookie = -1;
    490 	struct rasops_info rinfo;
    491 
    492 	memset(&rinfo, 0, sizeof rinfo);
    493 
    494 	if (fontname) {
    495 		wsfont_init();
    496 		cookie = wsfont_find(fontname, 0, 0, 0,
    497 		    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R);
    498 		if (cookie < 0 ||
    499 		    wsfont_lock(cookie, &rinfo.ri_font))
    500 			return -1;
    501 	}
    502 	else {
    503 		/* let rasops_init() choose any font */
    504 	}
    505 
    506 	/* let rasops_init calculate # of cols and rows in character */
    507 	rinfo.ri_flg = 0;
    508 	rinfo.ri_depth = descr->depth;
    509 	rinfo.ri_bits = NULL;
    510 	rinfo.ri_width = width;
    511 	rinfo.ri_height = height;
    512 	rinfo.ri_stride = width * rinfo.ri_depth / 8;
    513 #ifdef	CPU_XSCALE_PXA270
    514 	if (rinfo.ri_depth > 16) rinfo.ri_stride = width * 4;
    515 #endif
    516 	rinfo.ri_wsfcookie = cookie;
    517 
    518 	rasops_init(&rinfo, 100, 100);
    519 
    520 	descr->c.nrows = rinfo.ri_rows;
    521 	descr->c.ncols = rinfo.ri_cols;
    522 	descr->c.capabilities = rinfo.ri_caps;
    523 
    524 	return cookie;
    525 }
    526 
    527 
    528 int
    529 pxa2x0_lcd_show_screen(void *v, void *cookie, int waitok,
    530     void (*cb)(void *, int, int), void *cbarg)
    531 {
    532 	struct pxa2x0_lcd_softc *sc = v;
    533 	struct pxa2x0_lcd_screen *scr = cookie, *old;
    534 
    535 	old = sc->active;
    536 	if (old == scr)
    537 		return 0;
    538 
    539 	if (old)
    540 		pxa2x0_lcd_stop_dma(sc);
    541 
    542 	pxa2x0_lcd_start_dma(sc, scr);
    543 
    544 	sc->active = scr;
    545 	return 0;
    546 }
    547 
    548 int
    549 pxa2x0_lcd_alloc_screen(void *v, const struct wsscreen_descr *_type,
    550     void **cookiep, int *curxp, int *curyp, long *attrp)
    551 {
    552 	struct pxa2x0_lcd_softc *sc = v;
    553 	struct pxa2x0_lcd_screen *scr;
    554 	const struct pxa2x0_wsscreen_descr *type =
    555 		(const struct pxa2x0_wsscreen_descr *)_type;
    556 
    557 	scr = pxa2x0_lcd_new_screen(sc, type->depth);
    558 	if (scr == NULL)
    559 		return -1;
    560 
    561 	/*
    562 	 * initialize raster operation for this screen.
    563 	 */
    564 	scr->rinfo.ri_flg = 0;
    565 	scr->rinfo.ri_depth = type->depth;
    566 	scr->rinfo.ri_bits = scr->buf_va;
    567 	scr->rinfo.ri_width = sc->geometry->panel_width;
    568 	scr->rinfo.ri_height = sc->geometry->panel_height;
    569 	scr->rinfo.ri_stride = scr->rinfo.ri_width * scr->rinfo.ri_depth / 8;
    570 #ifdef CPU_XSCALE_PXA270
    571 	if (scr->rinfo.ri_depth > 16)
    572 		scr->rinfo.ri_stride = scr->rinfo.ri_width * 4;
    573 #endif
    574 	scr->rinfo.ri_wsfcookie = -1;	/* XXX */
    575 
    576 	rasops_init(&scr->rinfo, type->c.nrows, type->c.ncols);
    577 
    578 	(* scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 0, 0, 0, attrp);
    579 
    580 	*cookiep = scr;
    581 	*curxp = 0;
    582 	*curyp = 0;
    583 
    584 	return 0;
    585 }
    586 
    587 
    588 void
    589 pxa2x0_lcd_free_screen(void *v, void *cookie)
    590 {
    591 	struct pxa2x0_lcd_softc *sc = v;
    592 	struct pxa2x0_lcd_screen *scr = cookie;
    593 
    594 	LIST_REMOVE(scr, link);
    595 	sc->n_screens--;
    596 	if (scr == sc->active) {
    597 		/* at first, we need to stop LCD DMA */
    598 		sc->active = NULL;
    599 
    600 		printf("lcd_free on active screen\n");
    601 
    602 		pxa2x0_lcd_stop_dma(sc);
    603 	}
    604 
    605 	if (scr->buf_va)
    606 		bus_dmamem_unmap(sc->dma_tag, scr->buf_va, scr->map_size);
    607 
    608 	if (scr->nsegs > 0)
    609 		bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs);
    610 
    611 	free(scr, M_DEVBUF);
    612 }
    613 
    614 int
    615 pxa2x0_lcd_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
    616 	struct lwp *l)
    617 {
    618 	struct pxa2x0_lcd_softc *sc = v;
    619 	struct wsdisplay_fbinfo *wsdisp_info;
    620 	uint32_t ccr0;
    621 
    622 	switch (cmd) {
    623 	case WSDISPLAYIO_GTYPE:
    624 		*(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */
    625 		return 0;
    626 
    627 	case WSDISPLAYIO_GINFO:
    628 		wsdisp_info = (struct wsdisplay_fbinfo *)data;
    629 
    630 		wsdisp_info->height = sc->geometry->panel_height;
    631 		wsdisp_info->width = sc->geometry->panel_width;
    632 		wsdisp_info->depth = sc->active->depth;
    633 		wsdisp_info->cmsize = 0;
    634 		return 0;
    635 
    636 	case WSDISPLAYIO_GETCMAP:
    637 	case WSDISPLAYIO_PUTCMAP:
    638 		return EPASSTHROUGH;	/* XXX Colormap */
    639 
    640 	case WSDISPLAYIO_SVIDEO:
    641 		if (*(int *)data == WSDISPLAYIO_VIDEO_ON) {
    642 		  /* turn it on */
    643 		}
    644 		else {
    645 		  /* start LCD shutdown */
    646 		  /* sleep until interrupt */
    647 		}
    648 		return 0;
    649 
    650 	case WSDISPLAYIO_GVIDEO:
    651 		ccr0 = bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0);
    652 		*(u_int *)data = (ccr0 & (LCCR0_ENB|LCCR0_DIS)) == LCCR0_ENB ?
    653 		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
    654 		return 0;
    655 
    656 
    657 
    658 	case WSDISPLAYIO_GCURPOS:
    659 	case WSDISPLAYIO_SCURPOS:
    660 	case WSDISPLAYIO_GCURMAX:
    661 	case WSDISPLAYIO_GCURSOR:
    662 	case WSDISPLAYIO_SCURSOR:
    663 		return EPASSTHROUGH;	/* XXX */
    664 	}
    665 
    666 	return EPASSTHROUGH;
    667 }
    668 
    669 paddr_t
    670 pxa2x0_lcd_mmap(void *v, void *vs, off_t offset, int prot)
    671 {
    672 	struct pxa2x0_lcd_softc *sc = v;
    673 	struct pxa2x0_lcd_screen *screen = sc->active;  /* ??? */
    674 
    675 	if (screen == NULL)
    676 		return -1;
    677 
    678 	return bus_dmamem_mmap(sc->dma_tag, screen->segs, screen->nsegs,
    679 	    offset, prot, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
    680 	return -1;
    681 }
    682 
    683 
    684 static void
    685 pxa2x0_lcd_cursor(void *cookie, int on, int row, int col)
    686 {
    687 	struct pxa2x0_lcd_screen *scr = cookie;
    688 
    689 	(* scr->rinfo.ri_ops.cursor)(&scr->rinfo, on, row, col);
    690 }
    691 
    692 static int
    693 pxa2x0_lcd_mapchar(void *cookie, int c, unsigned int *cp)
    694 {
    695 	struct pxa2x0_lcd_screen *scr = cookie;
    696 
    697 	return (* scr->rinfo.ri_ops.mapchar)(&scr->rinfo, c, cp);
    698 }
    699 
    700 static void
    701 pxa2x0_lcd_putchar(void *cookie, int row, int col, u_int uc, long attr)
    702 {
    703 	struct pxa2x0_lcd_screen *scr = cookie;
    704 
    705 	(* scr->rinfo.ri_ops.putchar)(&scr->rinfo,
    706 	    row, col, uc, attr);
    707 }
    708 
    709 static void
    710 pxa2x0_lcd_copycols(void *cookie, int row, int src, int dst, int num)
    711 {
    712 	struct pxa2x0_lcd_screen *scr = cookie;
    713 
    714 	(* scr->rinfo.ri_ops.copycols)(&scr->rinfo,
    715 	    row, src, dst, num);
    716 }
    717 
    718 static void
    719 pxa2x0_lcd_erasecols(void *cookie, int row, int col, int num, long attr)
    720 {
    721 	struct pxa2x0_lcd_screen *scr = cookie;
    722 
    723 	(* scr->rinfo.ri_ops.erasecols)(&scr->rinfo,
    724 	    row, col, num, attr);
    725 }
    726 
    727 static void
    728 pxa2x0_lcd_copyrows(void *cookie, int src, int dst, int num)
    729 {
    730 	struct pxa2x0_lcd_screen *scr = cookie;
    731 
    732 	(* scr->rinfo.ri_ops.copyrows)(&scr->rinfo,
    733 	    src, dst, num);
    734 }
    735 
    736 static void
    737 pxa2x0_lcd_eraserows(void *cookie, int row, int num, long attr)
    738 {
    739 	struct pxa2x0_lcd_screen *scr = cookie;
    740 
    741 	(* scr->rinfo.ri_ops.eraserows)(&scr->rinfo,
    742 	    row, num, attr);
    743 }
    744 
    745 static int
    746 pxa2x0_lcd_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr)
    747 {
    748 	struct pxa2x0_lcd_screen *scr = cookie;
    749 
    750 	return (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo,
    751 	    fg, bg, flg, attr);
    752 }
    753 
    754 
    755 const struct wsdisplay_emulops pxa2x0_lcd_emulops = {
    756 	pxa2x0_lcd_cursor,
    757 	pxa2x0_lcd_mapchar,
    758 	pxa2x0_lcd_putchar,
    759 	pxa2x0_lcd_copycols,
    760 	pxa2x0_lcd_erasecols,
    761 	pxa2x0_lcd_copyrows,
    762 	pxa2x0_lcd_eraserows,
    763 	pxa2x0_lcd_alloc_attr
    764 };
    765 
    766 #endif /* NWSDISPLAY > 0 */
    767