pxa2x0_lcd.c revision 1.14 1 /* $NetBSD: pxa2x0_lcd.c,v 1.14 2006/12/16 03:39:05 ober 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.14 2006/12/16 03:39:05 ober 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 /*
72 * Console variables. These are necessary since console is setup very early,
73 * before devices get attached.
74 */
75 struct {
76 bus_space_tag_t iot;
77 bus_space_handle_t ioh;
78 bus_dma_tag_t dma_tag;
79 const struct lcd_panel_geometry *geometry;
80 struct pxa2x0_lcd_screen scr;
81 } pxa2x0_lcd_console;
82
83 int lcdintr(void *);
84 void pxa2x0_lcd_initialize(struct pxa2x0_lcd_softc *sc,
85 const struct lcd_panel_geometry *geom);
86 void pxa2x0_lcd_setup_console(struct pxa2x0_lcd_softc *sc,
87 const struct pxa2x0_wsscreen_descr *descr);
88 void pxa2x0_lcd_setup_rasops(struct rasops_info *rinfo,
89 struct pxa2x0_wsscreen_descr *descr,
90 const struct lcd_panel_geometry *geom);
91
92 void
93 pxa2x0_lcd_geometry(struct pxa2x0_lcd_softc *sc,
94 const struct lcd_panel_geometry *info)
95 {
96 bus_space_tag_t iot;
97 bus_space_handle_t ioh;
98 uint32_t ccr0;
99 int lines;
100
101 if (sc != NULL) {
102 iot = sc->iot;
103 ioh = sc->ioh;
104 sc->geometry = info;
105 } else {
106 iot = pxa2x0_lcd_console.iot;
107 ioh = pxa2x0_lcd_console.ioh;
108 pxa2x0_lcd_console.geometry = info;
109 }
110
111 ccr0 = LCCR0_IMASK;
112 if (info->panel_info & LCDPANEL_ACTIVE)
113 ccr0 |= LCCR0_PAS; /* active mode */
114 if ((info->panel_info & (LCDPANEL_DUAL|LCDPANEL_ACTIVE))
115 == LCDPANEL_DUAL)
116 ccr0 |= LCCR0_SDS; /* dual panel */
117 if (info->panel_info & LCDPANEL_MONOCHROME)
118 ccr0 |= LCCR0_CMS;
119 bus_space_write_4(iot, ioh, LCDC_LCCR0, ccr0);
120
121 bus_space_write_4(iot, ioh, LCDC_LCCR1,
122 (info->panel_width-1)
123 | ((info->hsync_pulse_width-1)<<10)
124 | ((info->end_line_wait-1)<<16)
125 | ((info->beg_line_wait-1)<<24));
126
127 if (info->panel_info & LCDPANEL_DUAL)
128 lines = info->panel_height/2 + info->extra_lines;
129 else
130 lines = info->panel_height + info->extra_lines;
131
132 bus_space_write_4(iot, ioh, LCDC_LCCR2,
133 (lines-1)
134 | (info->vsync_pulse_width<<10)
135 | (info->end_frame_wait<<16)
136 | (info->beg_frame_wait<<24));
137
138 bus_space_write_4(iot, ioh, LCDC_LCCR3,
139 (info->pixel_clock_div<<0)
140 | (info->ac_bias << 8)
141 | ((info->panel_info &
142 (LCDPANEL_VSP|LCDPANEL_HSP|LCDPANEL_PCP|LCDPANEL_OEP))
143 <<20)
144 | (4 << 24) /* 16bpp */
145 | ((info->panel_info & LCDPANEL_DPC) ? (1<<27) : 0)
146 );
147 }
148
149 /*
150 * Initialize the LCD controller.
151 */
152 void
153 pxa2x0_lcd_initialize(struct pxa2x0_lcd_softc *sc,
154 const struct lcd_panel_geometry *geom)
155 {
156 bus_space_tag_t iot;
157 bus_space_handle_t ioh;
158 uint32_t lccr0, lscr;
159 int nldd;
160
161 if (sc != NULL) {
162 iot = sc->iot;
163 ioh = sc->ioh;
164 } else {
165 iot = pxa2x0_lcd_console.iot;
166 ioh = pxa2x0_lcd_console.ioh;
167 }
168
169 /* Check if LCD is enabled before programming, it should not
170 * be enabled while it is being reprogrammed, therefore disable
171 * it first.
172 */
173 lccr0 = bus_space_read_4(iot, ioh, LCDC_LCCR0);
174 if (lccr0 & LCCR0_ENB) {
175 lccr0 |= LCCR0_LDM;
176 bus_space_write_4(iot, ioh, LCDC_LCCR0, lccr0);
177 lccr0 = bus_space_read_4(iot, ioh, LCDC_LCCR0); /* paranoia */
178 lccr0 |= LCCR0_DIS;
179 bus_space_write_4(iot, ioh, LCDC_LCCR0, lccr0);
180 do {
181 lscr = bus_space_read_4(iot, ioh, LCDC_LCSR);
182 } while (!(lscr & LCSR_LDD));
183 }
184
185 /* enable clock */
186 pxa2x0_clkman_config(CKEN_LCD, 1);
187
188 bus_space_write_4(iot, ioh, LCDC_LCCR0, LCCR0_IMASK);
189
190 /*
191 * setup GP[77:58] for LCD
192 */
193 /* Always use [FLP]CLK, ACBIAS */
194 pxa2x0_gpio_set_function(74, GPIO_ALT_FN_2_OUT);
195 pxa2x0_gpio_set_function(75, GPIO_ALT_FN_2_OUT);
196 pxa2x0_gpio_set_function(76, GPIO_ALT_FN_2_OUT);
197 pxa2x0_gpio_set_function(77, GPIO_ALT_FN_2_OUT);
198
199 if ((geom->panel_info & LCDPANEL_ACTIVE) ||
200 ((geom->panel_info & (LCDPANEL_MONOCHROME|LCDPANEL_DUAL)) ==
201 LCDPANEL_DUAL)) {
202 /* active and color dual panel need L_DD[15:0] */
203 nldd = 16;
204 } else if ((geom->panel_info & LCDPANEL_DUAL) ||
205 !(geom->panel_info & LCDPANEL_MONOCHROME)) {
206 /* dual or color need L_DD[7:0] */
207 nldd = 8;
208 } else {
209 /* Otherwise just L_DD[3:0] */
210 nldd = 4;
211 }
212
213 if (CPU_IS_PXA270 && nldd==16) {
214 pxa2x0_gpio_set_function(86, GPIO_ALT_FN_2_OUT);
215 pxa2x0_gpio_set_function(87, GPIO_ALT_FN_2_OUT);
216 }
217
218 while (nldd--)
219 pxa2x0_gpio_set_function(58 + nldd, GPIO_ALT_FN_2_OUT);
220
221 pxa2x0_lcd_geometry(sc, geom);
222 }
223
224 /*
225 * Common driver attachment code.
226 */
227 void
228 pxa2x0_lcd_attach_sub(struct pxa2x0_lcd_softc *sc,
229 struct pxaip_attach_args *pxa, struct pxa2x0_wsscreen_descr *descr,
230 const struct lcd_panel_geometry *geom, int console)
231 {
232 bus_space_tag_t iot = pxa->pxa_iot;
233 bus_space_handle_t ioh;
234 int error;
235
236 sc->n_screens = 0;
237 LIST_INIT(&sc->screens);
238
239 /* map controller registers */
240 if (console) {
241 iot = pxa2x0_lcd_console.iot;
242 ioh = pxa2x0_lcd_console.ioh;
243 } else {
244 error = bus_space_map(iot, PXA2X0_LCDC_BASE,
245 PXA2X0_LCDC_SIZE, 0, &ioh);
246 if (error) {
247 printf(": failed to map registers %d", error);
248 return;
249 }
250 }
251
252 sc->iot = iot;
253 sc->ioh = ioh;
254 sc->dma_tag = &pxa2x0_bus_dma_tag;
255
256 sc->ih = pxa2x0_intr_establish(17, IPL_BIO, lcdintr, sc);
257 if (sc->ih == NULL)
258 printf("%s: unable to establish interrupt at irq %d",
259 sc->dev.dv_xname, 17);
260
261 if (console != 0) {
262 /* complete console attachment */
263 pxa2x0_lcd_setup_console(sc, descr);
264 } else {
265 struct rasops_info dummy;
266
267 pxa2x0_lcd_initialize(sc, geom);
268
269 /*
270 * Initialize a dummy rasops_info to compute fontsize and
271 * the screen size in chars.
272 */
273 memset(&dummy, 0, sizeof(dummy));
274 pxa2x0_lcd_setup_rasops(&dummy, descr, geom);
275 }
276 }
277
278 /*
279 * Interrupt handler.
280 */
281 int
282 lcdintr(void *arg)
283 {
284 struct pxa2x0_lcd_softc *sc = arg;
285 bus_space_tag_t iot = sc->iot;
286 bus_space_handle_t ioh = sc->ioh;
287
288 static uint32_t status;
289
290 status = bus_space_read_4(iot, ioh, LCDC_LCSR);
291 /* Clear stickey status bits */
292 bus_space_write_4(iot, ioh, LCDC_LCSR, status);
293
294 return 1;
295 }
296
297 /*
298 * Enable DMA to cause the display to be refreshed periodically.
299 * This brings the screen to life...
300 */
301 void
302 pxa2x0_lcd_start_dma(struct pxa2x0_lcd_softc *sc,
303 struct pxa2x0_lcd_screen *scr)
304 {
305 bus_space_tag_t iot;
306 bus_space_handle_t ioh;
307 uint32_t tmp;
308 int val, save;
309
310 if (sc != NULL) {
311 iot = sc->iot;
312 ioh = sc->ioh;
313 } else {
314 iot = pxa2x0_lcd_console.iot;
315 ioh = pxa2x0_lcd_console.ioh;
316 }
317
318 save = disable_interrupts(I32_bit);
319
320 switch (scr->depth) {
321 case 1: val = 0; break;
322 case 2: val = 1; break;
323 case 4: val = 2; break;
324 case 8: val = 3; break;
325 case 16: val = 4; break;
326 case 18: val = 5; break;
327 case 24: val = 33; break;
328 default:
329 val = 4; break;
330 }
331
332 tmp = bus_space_read_4(iot, ioh, LCDC_LCCR3);
333 if (CPU_IS_PXA270)
334 bus_space_write_4(iot, ioh, LCDC_LCCR3,
335 (tmp & ~(LCCR3_BPP|(1<<29))) | (val << LCCR3_BPP_SHIFT));
336 else
337 bus_space_write_4(iot, ioh, LCDC_LCCR3,
338 (tmp & ~LCCR3_BPP) | (val << LCCR3_BPP_SHIFT));
339
340 bus_space_write_4(iot, ioh, LCDC_FDADR0,
341 scr->depth >= 16 ? scr->dma_desc_pa :
342 scr->dma_desc_pa + 2 * sizeof (struct lcd_dma_descriptor));
343 bus_space_write_4(iot, ioh, LCDC_FDADR1,
344 scr->dma_desc_pa + 1 * sizeof (struct lcd_dma_descriptor));
345
346 /* clear status */
347 bus_space_write_4(iot, ioh, LCDC_LCSR, 0);
348
349 delay(1000); /* ??? */
350
351 /* Enable LCDC */
352 tmp = bus_space_read_4(iot, ioh, LCDC_LCCR0);
353 /*tmp &= ~LCCR0_SFM;*/
354 bus_space_write_4(iot, ioh, LCDC_LCCR0, tmp | LCCR0_ENB);
355
356 restore_interrupts(save);
357 }
358
359 #if NWSDISPLAY > 0
360 /*
361 * Disable screen refresh.
362 */
363 static void
364 pxa2x0_lcd_stop_dma(struct pxa2x0_lcd_softc *sc)
365 {
366 /* Stop LCD DMA after current frame */
367 bus_space_write_4(sc->iot, sc->ioh, LCDC_LCCR0,
368 LCCR0_DIS |
369 bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0));
370
371 /* wait for disabling done.
372 XXX: use interrupt. */
373 while (LCCR0_ENB &
374 bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0))
375 ;
376
377 bus_space_write_4(sc->iot, sc->ioh, LCDC_LCCR0,
378 ~LCCR0_DIS &
379 bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0));
380 }
381 #endif
382
383 #define _rgb(r,g,b) (((r)<<11) | ((g)<<5) | b)
384 #define rgb(r,g,b) _rgb((r)>>1,g,(b)>>1)
385
386 #define L 0x1f /* low intensity */
387 #define H 0x3f /* hight intensity */
388
389 static uint16_t basic_color_map[] = {
390 rgb( 0, 0, 0), /* black */
391 rgb( L, 0, 0), /* red */
392 rgb( 0, L, 0), /* green */
393 rgb( L, L, 0), /* brown */
394 rgb( 0, 0, L), /* blue */
395 rgb( L, 0, L), /* magenta */
396 rgb( 0, L, L), /* cyan */
397 _rgb(0x1c,0x38,0x1c), /* white */
398
399 rgb( L, L, L), /* black */
400 rgb( H, 0, 0), /* red */
401 rgb( 0, H, 0), /* green */
402 rgb( H, H, 0), /* brown */
403 rgb( 0, 0, H), /* blue */
404 rgb( H, 0, H), /* magenta */
405 rgb( 0, H, H), /* cyan */
406 rgb( H, H, H)
407 };
408
409 #undef H
410 #undef L
411
412 static void
413 init_pallet(uint16_t *buf, int depth)
414 {
415 int i;
416
417 /* convert RGB332 to RGB565 */
418 switch (depth) {
419 case 8:
420 case 4:
421 #if 0
422 for (i=0; i <= 255; ++i) {
423 buf[i] = ((9 * ((i>>5) & 0x07)) <<11) |
424 ((9 * ((i>>2) & 0x07)) << 5) |
425 ((21 * (i & 0x03))/2);
426 }
427 #else
428 memcpy(buf, basic_color_map, sizeof basic_color_map);
429 for (i=16; i < (1<<depth); ++i)
430 buf[i] = 0xffff;
431 #endif
432 break;
433 case 16:
434 /* pallet is not needed */
435 break;
436 default:
437 /* other depths are not supported */
438 break;
439 }
440 }
441
442 /*
443 * Create and initialize a new screen buffer.
444 */
445 int
446 pxa2x0_lcd_new_screen(struct pxa2x0_lcd_softc *sc,
447 struct pxa2x0_lcd_screen *scr,
448 int depth)
449 {
450 bus_space_tag_t iot;
451 bus_space_handle_t ioh;
452 bus_dma_tag_t dma_tag;
453 const struct lcd_panel_geometry *geometry;
454 int width, height;
455 bus_size_t size;
456 int error, pallet_size;
457 int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
458 struct lcd_dma_descriptor *desc;
459 paddr_t buf_pa, desc_pa;
460
461 if (sc != NULL) {
462 iot = sc->iot;
463 ioh = sc->ioh;
464 dma_tag = sc->dma_tag;
465 geometry = sc->geometry;
466 } else {
467 /* We are creating the console screen. */
468 iot = pxa2x0_lcd_console.iot;
469 ioh = pxa2x0_lcd_console.ioh;
470 dma_tag = pxa2x0_lcd_console.dma_tag;
471 geometry = pxa2x0_lcd_console.geometry;
472 }
473
474 width = geometry->panel_width;
475 height = geometry->panel_height;
476 pallet_size = 0;
477
478 switch (depth) {
479 case 1:
480 case 2:
481 case 4:
482 case 8:
483 pallet_size = (1<<depth) * sizeof (uint16_t);
484 /* FALLTHROUGH */
485 case 16:
486 size = roundup(width,4)*depth/8 * height;
487 break;
488 case 18:
489 case 24:
490 size = roundup(width,4) * 4 * height;
491 break;
492 case 19:
493 case 25:
494 printf("%s: Not supported depth (%d)\n",
495 sc ? sc->dev.dv_xname : "console",
496 depth);
497 return EINVAL;
498 default:
499 printf("%s: Unknown depth (%d)\n",
500 sc ? sc->dev.dv_xname : "console", depth);
501 return EINVAL;
502 }
503
504 memset(scr, 0, sizeof(*scr));
505
506 scr->nsegs = 0;
507 scr->depth = depth;
508 scr->buf_size = size;
509 scr->buf_va = NULL;
510 size = roundup(size,16) + 3 * sizeof (struct lcd_dma_descriptor)
511 + pallet_size;
512
513 error = bus_dmamem_alloc(sc->dma_tag, size, 16, 0,
514 scr->segs, 1, &(scr->nsegs), busdma_flag);
515
516 if (error || scr->nsegs != 1) {
517 /* XXX:
518 * Actually we can handle nsegs>1 case by means
519 * of multiple DMA descriptors for a panel. It
520 * will make code here a bit hairly.
521 */
522 if (error == 0)
523 error = E2BIG;
524 goto bad;
525 }
526
527 error = bus_dmamem_map(sc->dma_tag, scr->segs, scr->nsegs,
528 size, (caddr_t *)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT);
529 if (error)
530 goto bad;
531
532 memset (scr->buf_va, 0, scr->buf_size);
533
534 /* map memory for DMA */
535 if (bus_dmamap_create(sc->dma_tag, 1024*1024*2, 1,
536 1024*1024*2, 0, busdma_flag, &scr->dma))
537 goto bad;
538 error = bus_dmamap_load(sc->dma_tag, scr->dma,
539 scr->buf_va, size, NULL, busdma_flag);
540 if (error) {
541 goto bad;
542 }
543
544 buf_pa = scr->segs[0].ds_addr;
545 desc_pa = buf_pa + roundup(size, PAGE_SIZE) - 3*sizeof *desc;
546
547 /* make descriptors at the top of mapped memory */
548 desc = (struct lcd_dma_descriptor *)(
549 (caddr_t)(scr->buf_va) + roundup(size, PAGE_SIZE) -
550 3*sizeof *desc);
551
552 desc[0].fdadr = desc_pa;
553 desc[0].fsadr = buf_pa;
554 desc[0].ldcmd = scr->buf_size;
555
556 if (pallet_size) {
557 init_pallet((uint16_t *)((char *)desc - pallet_size), depth);
558
559 desc[2].fdadr = desc_pa; /* chain to panel 0 */
560 desc[2].fsadr = desc_pa - pallet_size;
561 desc[2].ldcmd = pallet_size | LDCMD_PAL;
562 }
563
564 if (sc->geometry->panel_info & LCDPANEL_DUAL) {
565 /* Dual panel */
566 desc[1].fdadr = desc_pa + sizeof *desc;
567 desc[1].fsadr = buf_pa + scr->buf_size/2;
568 desc[0].ldcmd = desc[1].ldcmd = scr->buf_size/2;
569
570 }
571
572 #if 0
573 desc[0].ldcmd |= LDCMD_SOFINT;
574 desc[1].ldcmd |= LDCMD_SOFINT;
575 #endif
576
577 scr->dma_desc = desc;
578 scr->dma_desc_pa = desc_pa;
579 scr->map_size = size; /* used when unmap this. */
580
581 LIST_INSERT_HEAD(&(sc->screens), scr, link);
582 sc->n_screens++;
583
584 return 0;
585
586 bad:
587 if (scr) {
588 if (scr->buf_va)
589 bus_dmamem_unmap(sc->dma_tag, scr->buf_va, size);
590 if (scr->nsegs)
591 bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs);
592 }
593 return error;
594 }
595
596 /*
597 * Initialize rasops for a screen, as well as struct wsscreen_descr if this
598 * is the first screen creation.
599 */
600 void
601 pxa2x0_lcd_setup_rasops(struct rasops_info *rinfo,
602 struct pxa2x0_wsscreen_descr *descr,
603 const struct lcd_panel_geometry *geom)
604 {
605
606 rinfo->ri_flg = descr->flags;
607 rinfo->ri_depth = descr->depth;
608 rinfo->ri_width = geom->panel_width;
609 rinfo->ri_height = geom->panel_height;
610 rinfo->ri_stride = rinfo->ri_width * rinfo->ri_depth / 8;
611 #ifdef notyet
612 rinfo->ri_wsfcookie = -1; /* XXX */
613 #endif
614
615 /* swap B and R */
616 if (descr->depth == 16) {
617 rinfo->ri_rnum = 5;
618 rinfo->ri_rpos = 11;
619 rinfo->ri_gnum = 6;
620 rinfo->ri_gpos = 5;
621 rinfo->ri_bnum = 5;
622 rinfo->ri_bpos = 0;
623 }
624
625 if (descr->c.nrows == 0) {
626 /* get rasops to compute screen size the first time */
627 rasops_init(rinfo, 100, 100);
628 } else
629 #ifndef zaurus /* XXX */
630 rasops_init(rinfo, descr->c.nrows, descr->c.ncols);
631 #else
632 /* XXX swap rows/cols for second call because of rotation */
633 rasops_init(rinfo, descr->c.ncols, descr->c.nrows);
634 #endif /* XXX */
635
636 descr->c.nrows = rinfo->ri_rows;
637 descr->c.ncols = rinfo->ri_cols;
638 descr->c.capabilities = rinfo->ri_caps;
639 descr->c.textops = &rinfo->ri_ops;
640 }
641
642 /*
643 * Early console attachment.
644 * This initializes the LCD, then creates and displays a screen buffer.
645 * This screen will be accounted for in the softc when the lcd device attaches.
646 */
647 int
648 pxa2x0_lcd_cnattach(struct pxa2x0_wsscreen_descr *descr,
649 const struct lcd_panel_geometry *geom)
650 {
651 struct rasops_info *ri;
652 long defattr;
653 int error;
654
655 /* map controller registers */
656 pxa2x0_lcd_console.iot = &pxa2x0_bs_tag;
657 error = bus_space_map(pxa2x0_lcd_console.iot,
658 PXA2X0_LCDC_BASE, PXA2X0_LCDC_SIZE, 0, &pxa2x0_lcd_console.ioh);
659 if (error)
660 return error;
661
662 pxa2x0_lcd_console.dma_tag = &pxa2x0_bus_dma_tag;
663 pxa2x0_lcd_console.geometry = geom;
664
665 pxa2x0_lcd_initialize(NULL, pxa2x0_lcd_console.geometry);
666
667 error = pxa2x0_lcd_new_screen(NULL, &pxa2x0_lcd_console.scr,
668 descr->depth);
669 if (error)
670 return error;
671
672 ri = &pxa2x0_lcd_console.scr.rinfo;
673 ri->ri_hw = (void *)&pxa2x0_lcd_console.scr;
674 ri->ri_bits = pxa2x0_lcd_console.scr.buf_va;
675 pxa2x0_lcd_setup_rasops(ri, descr, pxa2x0_lcd_console.geometry);
676
677 /* assumes 16 bpp */
678 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
679
680 pxa2x0_lcd_start_dma(NULL, &pxa2x0_lcd_console.scr);
681
682 wsdisplay_cnattach(&descr->c, ri, ri->ri_ccol, ri->ri_crow, defattr);
683
684 return 0;
685 }
686
687 /*
688 * Do the necessary accounting to bring the console variables in the softc.
689 */
690 void
691 pxa2x0_lcd_setup_console(struct pxa2x0_lcd_softc *sc,
692 const struct pxa2x0_wsscreen_descr *descr)
693 {
694 struct pxa2x0_lcd_screen *scr = &pxa2x0_lcd_console.scr;
695
696 /*
697 * Register the console screen as if it had been created
698 * when the lcd device attached.
699 */
700 LIST_INSERT_HEAD(&(sc->screens), &pxa2x0_lcd_console.scr, link);
701 sc->n_screens++;
702 sc->active = scr;
703 }
704
705 /*
706 * Power management
707 */
708 void
709 pxa2x0_lcd_suspend(struct pxa2x0_lcd_softc *sc)
710 {
711
712 if (sc->active != NULL) {
713 pxa2x0_lcd_stop_dma(sc);
714 pxa2x0_clkman_config(CKEN_LCD, 0);
715 }
716 }
717
718 void
719 pxa2x0_lcd_resume(struct pxa2x0_lcd_softc *sc)
720 {
721
722 if (sc->active != NULL) {
723 pxa2x0_lcd_initialize(sc, sc->geometry);
724 pxa2x0_lcd_start_dma(sc, sc->active);
725 }
726 }
727
728 void
729 pxa2x0_lcd_power(int why, void *v)
730 {
731 struct pxa2x0_lcd_softc *sc = v;
732
733 switch (why) {
734 case PWR_SUSPEND:
735 case PWR_STANDBY:
736 pxa2x0_lcd_suspend(sc);
737 break;
738
739 case PWR_RESUME:
740 pxa2x0_lcd_resume(sc);
741 break;
742 }
743 }
744
745 #if NWSDISPLAY > 0
746 /*
747 * Initialize struct wsscreen_descr based on values calculated by
748 * raster operation subsystem.
749 */
750 int
751 pxa2x0_lcd_setup_wsscreen(struct pxa2x0_wsscreen_descr *descr,
752 const struct lcd_panel_geometry *geom,
753 const char *fontname)
754 {
755 int width = geom->panel_width;
756 int height = geom->panel_height;
757 int cookie = -1;
758 struct rasops_info rinfo;
759
760 memset(&rinfo, 0, sizeof rinfo);
761
762 if (fontname) {
763 wsfont_init();
764 cookie = wsfont_find(fontname, 0, 0, 0,
765 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R);
766 if (cookie < 0 ||
767 wsfont_lock(cookie, &rinfo.ri_font))
768 return -1;
769 }
770 else {
771 /* let rasops_init() choose any font */
772 }
773
774 /* let rasops_init calculate # of cols and rows in character */
775 rinfo.ri_flg = 0;
776 rinfo.ri_depth = descr->depth;
777 rinfo.ri_bits = NULL;
778 rinfo.ri_width = width;
779 rinfo.ri_height = height;
780 rinfo.ri_stride = width * rinfo.ri_depth / 8;
781 #ifdef CPU_XSCALE_PXA270
782 if (rinfo.ri_depth > 16) rinfo.ri_stride = width * 4;
783 #endif
784 rinfo.ri_wsfcookie = cookie;
785
786 rasops_init(&rinfo, 100, 100);
787
788 descr->c.nrows = rinfo.ri_rows;
789 descr->c.ncols = rinfo.ri_cols;
790 descr->c.capabilities = rinfo.ri_caps;
791
792 return cookie;
793 }
794
795 int
796 pxa2x0_lcd_show_screen(void *v, void *cookie, int waitok,
797 void (*cb)(void *, int, int), void *cbarg)
798 {
799 struct pxa2x0_lcd_softc *sc = v;
800 struct pxa2x0_lcd_screen *scr = cookie, *old;
801
802 old = sc->active;
803 if (old == scr)
804 return 0;
805
806 if (old)
807 pxa2x0_lcd_stop_dma(sc);
808
809 pxa2x0_lcd_start_dma(sc, scr);
810
811 sc->active = scr;
812 return 0;
813 }
814
815 int
816 pxa2x0_lcd_alloc_screen(void *v, const struct wsscreen_descr *_type,
817 void **cookiep, int *curxp, int *curyp, long *attrp)
818 {
819 struct pxa2x0_lcd_softc *sc = v;
820 struct pxa2x0_lcd_screen *scr;
821 const struct pxa2x0_wsscreen_descr *type =
822 (const struct pxa2x0_wsscreen_descr *)_type;
823 int error;
824
825 scr = malloc(sizeof *scr, M_DEVBUF, (cold ? M_NOWAIT : M_WAITOK));
826 if (scr == NULL)
827 return (ENOMEM);
828
829 error = pxa2x0_lcd_new_screen(sc, scr, type->depth);
830 if (error != 0) {
831 free(scr, M_DEVBUF);
832 return (error);
833 }
834
835 /*
836 * initialize raster operation for this screen.
837 */
838 scr->rinfo.ri_flg = 0;
839 scr->rinfo.ri_depth = type->depth;
840 scr->rinfo.ri_bits = scr->buf_va;
841 scr->rinfo.ri_width = sc->geometry->panel_width;
842 scr->rinfo.ri_height = sc->geometry->panel_height;
843 scr->rinfo.ri_stride = scr->rinfo.ri_width * scr->rinfo.ri_depth / 8;
844 #ifdef CPU_XSCALE_PXA270
845 if (scr->rinfo.ri_depth > 16)
846 scr->rinfo.ri_stride = scr->rinfo.ri_width * 4;
847 #endif
848 scr->rinfo.ri_wsfcookie = -1; /* XXX */
849
850 rasops_init(&scr->rinfo, type->c.nrows, type->c.ncols);
851
852 (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 0, 0, 0, attrp);
853
854 *cookiep = scr;
855 *curxp = 0;
856 *curyp = 0;
857
858 return 0;
859 }
860
861 void
862 pxa2x0_lcd_free_screen(void *v, void *cookie)
863 {
864 struct pxa2x0_lcd_softc *sc = v;
865 struct pxa2x0_lcd_screen *scr = cookie;
866
867 LIST_REMOVE(scr, link);
868 sc->n_screens--;
869 if (scr == sc->active) {
870 /* at first, we need to stop LCD DMA */
871 sc->active = NULL;
872
873 printf("lcd_free on active screen\n");
874
875 pxa2x0_lcd_stop_dma(sc);
876 }
877
878 if (scr->buf_va)
879 bus_dmamem_unmap(sc->dma_tag, scr->buf_va, scr->map_size);
880
881 if (scr->nsegs > 0)
882 bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs);
883
884 free(scr, M_DEVBUF);
885 }
886
887 int
888 pxa2x0_lcd_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
889 struct lwp *l)
890 {
891 struct pxa2x0_lcd_softc *sc = v;
892 struct wsdisplay_fbinfo *wsdisp_info;
893 uint32_t ccr0;
894
895 switch (cmd) {
896 case WSDISPLAYIO_GTYPE:
897 *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */
898 return 0;
899
900 case WSDISPLAYIO_GINFO:
901 wsdisp_info = (struct wsdisplay_fbinfo *)data;
902
903 wsdisp_info->height = sc->geometry->panel_height;
904 wsdisp_info->width = sc->geometry->panel_width;
905 wsdisp_info->depth = sc->active->depth;
906 wsdisp_info->cmsize = 0;
907 return 0;
908
909 case WSDISPLAYIO_GETCMAP:
910 case WSDISPLAYIO_PUTCMAP:
911 return EPASSTHROUGH; /* XXX Colormap */
912
913 case WSDISPLAYIO_SVIDEO:
914 if (*(int *)data == WSDISPLAYIO_VIDEO_ON) {
915 /* turn it on */
916 }
917 else {
918 /* start LCD shutdown */
919 /* sleep until interrupt */
920 }
921 return 0;
922
923 case WSDISPLAYIO_GVIDEO:
924 ccr0 = bus_space_read_4(sc->iot, sc->ioh, LCDC_LCCR0);
925 *(u_int *)data = (ccr0 & (LCCR0_ENB|LCCR0_DIS)) == LCCR0_ENB ?
926 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
927 return 0;
928
929 case WSDISPLAYIO_GCURPOS:
930 case WSDISPLAYIO_SCURPOS:
931 case WSDISPLAYIO_GCURMAX:
932 case WSDISPLAYIO_GCURSOR:
933 case WSDISPLAYIO_SCURSOR:
934 return EPASSTHROUGH; /* XXX */
935 }
936
937 return EPASSTHROUGH;
938 }
939
940 paddr_t
941 pxa2x0_lcd_mmap(void *v, void *vs, off_t offset, int prot)
942 {
943 struct pxa2x0_lcd_softc *sc = v;
944 struct pxa2x0_lcd_screen *screen = sc->active; /* ??? */
945
946 if (screen == NULL)
947 return -1;
948
949 return bus_dmamem_mmap(sc->dma_tag, screen->segs, screen->nsegs,
950 offset, prot, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
951 return -1;
952 }
953
954
955 static void
956 pxa2x0_lcd_cursor(void *cookie, int on, int row, int col)
957 {
958 struct pxa2x0_lcd_screen *scr = cookie;
959
960 (* scr->rinfo.ri_ops.cursor)(&scr->rinfo, on, row, col);
961 }
962
963 static int
964 pxa2x0_lcd_mapchar(void *cookie, int c, unsigned int *cp)
965 {
966 struct pxa2x0_lcd_screen *scr = cookie;
967
968 return (* scr->rinfo.ri_ops.mapchar)(&scr->rinfo, c, cp);
969 }
970
971 static void
972 pxa2x0_lcd_putchar(void *cookie, int row, int col, u_int uc, long attr)
973 {
974 struct pxa2x0_lcd_screen *scr = cookie;
975
976 (* scr->rinfo.ri_ops.putchar)(&scr->rinfo,
977 row, col, uc, attr);
978 }
979
980 static void
981 pxa2x0_lcd_copycols(void *cookie, int row, int src, int dst, int num)
982 {
983 struct pxa2x0_lcd_screen *scr = cookie;
984
985 (* scr->rinfo.ri_ops.copycols)(&scr->rinfo,
986 row, src, dst, num);
987 }
988
989 static void
990 pxa2x0_lcd_erasecols(void *cookie, int row, int col, int num, long attr)
991 {
992 struct pxa2x0_lcd_screen *scr = cookie;
993
994 (* scr->rinfo.ri_ops.erasecols)(&scr->rinfo,
995 row, col, num, attr);
996 }
997
998 static void
999 pxa2x0_lcd_copyrows(void *cookie, int src, int dst, int num)
1000 {
1001 struct pxa2x0_lcd_screen *scr = cookie;
1002
1003 (* scr->rinfo.ri_ops.copyrows)(&scr->rinfo,
1004 src, dst, num);
1005 }
1006
1007 static void
1008 pxa2x0_lcd_eraserows(void *cookie, int row, int num, long attr)
1009 {
1010 struct pxa2x0_lcd_screen *scr = cookie;
1011
1012 (* scr->rinfo.ri_ops.eraserows)(&scr->rinfo,
1013 row, num, attr);
1014 }
1015
1016 static int
1017 pxa2x0_lcd_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr)
1018 {
1019 struct pxa2x0_lcd_screen *scr = cookie;
1020
1021 return (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo,
1022 fg, bg, flg, attr);
1023 }
1024
1025
1026 const struct wsdisplay_emulops pxa2x0_lcd_emulops = {
1027 pxa2x0_lcd_cursor,
1028 pxa2x0_lcd_mapchar,
1029 pxa2x0_lcd_putchar,
1030 pxa2x0_lcd_copycols,
1031 pxa2x0_lcd_erasecols,
1032 pxa2x0_lcd_copyrows,
1033 pxa2x0_lcd_eraserows,
1034 pxa2x0_lcd_alloc_attr
1035 };
1036
1037 #endif /* NWSDISPLAY > 0 */
1038