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