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