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