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