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