1 /* $NetBSD: s3c24x0_lcd.c,v 1.11 2014/03/10 04:25:51 htodd Exp $ */ 2 3 /* 4 * Copyright (c) 2004 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. The name of Genetec Corporation may not be used to endorse or 16 * promote products derived from this software without specific prior 17 * written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Support S3C24[10]0's integrated LCD controller. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: s3c24x0_lcd.c,v 1.11 2014/03/10 04:25:51 htodd Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/conf.h> 42 #include <sys/uio.h> 43 #include <sys/malloc.h> 44 #include <sys/kernel.h> /* for cold */ 45 46 #include <uvm/uvm_extern.h> 47 48 #include <dev/cons.h> 49 #include <dev/wscons/wsconsio.h> 50 #include <dev/wscons/wsdisplayvar.h> 51 #include <dev/wscons/wscons_callbacks.h> 52 #include <dev/rasops/rasops.h> 53 #include <dev/wsfont/wsfont.h> 54 55 #include <dev/hpc/hpcfbio.h> 56 57 #include <sys/bus.h> 58 #include <machine/cpu.h> 59 #include <arm/cpufunc.h> 60 61 #include <arm/s3c2xx0/s3c24x0var.h> 62 #include <arm/s3c2xx0/s3c24x0reg.h> 63 #include <arm/s3c2xx0/s3c24x0_lcd.h> 64 65 #include "wsdisplay.h" 66 67 int lcdintr(void *); 68 static void init_palette(struct s3c24x0_lcd_softc *, 69 struct s3c24x0_lcd_screen *); 70 71 #ifdef LCD_DEBUG 72 static void 73 dump_lcdcon(const char *title, bus_space_tag_t iot, bus_space_handle_t ioh) 74 { 75 int i; 76 77 printf("%s\n", title); 78 for(i=LCDC_LCDCON1; i <= LCDC_LCDSADDR3; i+=4) { 79 if (i%16 == 0) 80 printf("\n%03x: ", i); 81 printf("%08x ", bus_space_read_4(iot, ioh, i)); 82 } 83 84 printf("\n"); 85 } 86 87 void draw_test_pattern(struct s3c24x0_lcd_softc *, 88 struct s3c24x0_lcd_screen *scr); 89 90 #endif 91 92 void 93 s3c24x0_set_lcd_panel_info(struct s3c24x0_lcd_softc *sc, 94 const struct s3c24x0_lcd_panel_info *info) 95 { 96 bus_space_tag_t iot = sc->iot; 97 bus_space_handle_t ioh = sc->ioh; 98 uint32_t reg; 99 int clkval; 100 int tft = s3c24x0_lcd_panel_tft(info); 101 int hclk = s3c2xx0_softc->sc_hclk; 102 103 sc->panel_info = info; 104 105 /* Set LCDCON1. BPPMODE and ENVID are set later */ 106 if (tft) 107 clkval = (hclk / info->pixel_clock / 2) - 1; 108 else { 109 /* STN display */ 110 clkval = max(2, hclk / info->pixel_clock / 2); 111 } 112 113 reg = (info->lcdcon1 & ~LCDCON1_CLKVAL_MASK) | 114 (clkval << LCDCON1_CLKVAL_SHIFT); 115 reg &= ~LCDCON1_ENVID; 116 bus_space_write_4(iot, ioh, LCDC_LCDCON1, reg); 117 118 #if 0 119 printf("hclk=%d pixel clock=%d, clkval = %x lcdcon1=%x\n", 120 hclk, info->pixel_clock, clkval, reg); 121 #endif 122 123 bus_space_write_4(iot, ioh, LCDC_LCDCON2, info->lcdcon2); 124 bus_space_write_4(iot, ioh, LCDC_LCDCON3, info->lcdcon3); 125 bus_space_write_4(iot, ioh, LCDC_LCDCON4, info->lcdcon4); 126 bus_space_write_4(iot, ioh, LCDC_LCDCON5, info->lcdcon5); 127 bus_space_write_4(iot, ioh, LCDC_LPCSEL, info->lpcsel); 128 } 129 130 void 131 s3c24x0_lcd_attach_sub(struct s3c24x0_lcd_softc *sc, 132 struct s3c2xx0_attach_args *sa, 133 const struct s3c24x0_lcd_panel_info *panel_info) 134 { 135 bus_space_tag_t iot = sa->sa_iot; 136 bus_space_handle_t ioh; 137 int error; 138 139 sc->n_screens = 0; 140 LIST_INIT(&sc->screens); 141 142 /* map controller registers */ 143 error = bus_space_map(iot, sa->sa_addr, S3C24X0_LCDC_SIZE, 0, &ioh); 144 if (error) { 145 printf(": failed to map registers %d", error); 146 return; 147 } 148 149 sc->iot = iot; 150 sc->ioh = ioh; 151 sc->dma_tag = sa->sa_dmat; 152 153 #ifdef notyet 154 sc->ih = s3c24x0_intr_establish(sa->sa_intr, IPL_BIO, lcdintr, sc); 155 if (sc->ih == NULL) 156 printf("%s: unable to establish interrupt at irq %d", 157 device_xname(sc->dev), sa->sa_intr); 158 #endif 159 160 /* mask LCD interrupts */ 161 bus_space_write_4(iot, ioh, LCDC_LCDINTMSK, LCDINT_FICNT|LCDINT_FRSYN); 162 163 /* Initialize controller registers based on panel geometry*/ 164 s3c24x0_set_lcd_panel_info(sc, panel_info); 165 166 /* XXX: enable clock to LCD controller */ 167 } 168 169 170 #ifdef notyet 171 int 172 lcdintr(void *arg) 173 { 174 struct s3c24x0_lcd_softc *sc = arg; 175 bus_space_tag_t iot = sc->iot; 176 bus_space_handle_t ioh = sc->ioh; 177 178 static uint32_t status; 179 180 return 1; 181 } 182 #endif 183 184 int 185 s3c24x0_lcd_start_dma(struct s3c24x0_lcd_softc *sc, 186 struct s3c24x0_lcd_screen *scr) 187 { 188 bus_space_tag_t iot = sc->iot; 189 bus_space_handle_t ioh = sc->ioh; 190 const struct s3c24x0_lcd_panel_info *info = sc->panel_info; 191 int tft = s3c24x0_lcd_panel_tft(info); 192 int dual_panel = 193 (info->lcdcon1 & LCDCON1_PNRMODE_MASK) == LCDCON1_PNRMODE_DUALSTN4; 194 uint32_t lcdcon1, val; 195 paddr_t pa; 196 int depth = scr->depth; 197 int stride = scr->stride; 198 int panel_height = info->panel_height; 199 int panel_width = info->panel_width; 200 int offsize; 201 202 switch (depth) { 203 case 1: val = LCDCON1_BPPMODE_STN1; break; 204 case 2: val = LCDCON1_BPPMODE_STN2; break; 205 case 4: val = LCDCON1_BPPMODE_STN4; break; 206 case 8: val = LCDCON1_BPPMODE_STN8; break; 207 case 12: 208 if (tft) 209 return -1; 210 val = LCDCON1_BPPMODE_STN12; 211 break; 212 case 16: 213 if (!tft) 214 return -1; 215 val = LCDCON1_BPPMODE_TFT16; 216 break; 217 case 24: 218 if (!tft) 219 return -1; 220 val = LCDCON1_BPPMODE_TFT24; 221 break; 222 default: 223 return -1; 224 } 225 226 if (tft) 227 val |= LCDCON1_BPPMODE_TFTX; 228 229 lcdcon1 = bus_space_read_4(iot, ioh, LCDC_LCDCON1); 230 lcdcon1 &= ~(LCDCON1_BPPMODE_MASK|LCDCON1_ENVID); 231 lcdcon1 |= val; 232 bus_space_write_4(iot, ioh, LCDC_LCDCON1, lcdcon1); 233 234 /* Adjust LCDCON3.HOZVAL to meet with restriction */ 235 val = roundup(panel_width, 16 / depth); 236 bus_space_write_4(iot, ioh, LCDC_LCDCON3, 237 (info->lcdcon3 & ~LCDCON3_HOZVAL_MASK) | 238 (val - 1) << LCDCON3_HOZVAL_SHIFT); 239 240 pa = scr->segs[0].ds_addr; 241 bus_space_write_4(iot, ioh, LCDC_LCDSADDR1, pa >> 1); 242 243 if (dual_panel) { 244 /* XXX */ 245 } 246 else { 247 pa += stride * panel_height; 248 bus_space_write_4(iot, ioh, LCDC_LCDSADDR2, pa >> 1); 249 } 250 251 offsize = stride / sizeof (uint16_t) - (panel_width * depth / 16); 252 bus_space_write_4(iot, ioh, LCDC_LCDSADDR3, 253 (offsize << LCDSADDR3_OFFSIZE_SHIFT) | 254 (panel_width * depth / 16)); 255 256 /* set byte- or halfword- swap based on the depth */ 257 val = bus_space_read_4(iot, ioh, LCDC_LCDCON5); 258 val &= ~(LCDCON5_BSWP|LCDCON5_HWSWP); 259 switch(depth) { 260 case 2: 261 case 4: 262 case 8: 263 val |= LCDCON5_BSWP; 264 break; 265 case 16: 266 val |= LCDCON5_HWSWP; 267 break; 268 } 269 bus_space_write_4(iot, ioh, LCDC_LCDCON5, val); 270 271 272 init_palette(sc, scr); 273 274 #if 0 275 bus_space_write_4(iot, ioh, LCDC_TPAL, TPAL_TPALEN| 276 (0xff<<TPAL_BLUE_SHIFT)); 277 #endif 278 279 /* Enable LCDC */ 280 bus_space_write_4(iot, ioh, LCDC_LCDCON1, lcdcon1 | LCDCON1_ENVID); 281 282 sc->lcd_on = 1; 283 284 #ifdef LCD_DEBUG 285 dump_lcdcon(__func__, iot, ioh); 286 #endif 287 288 return 0; 289 } 290 291 void 292 s3c24x0_lcd_power(struct s3c24x0_lcd_softc *sc, int on) 293 { 294 bus_space_tag_t iot = sc->iot; 295 bus_space_handle_t ioh = sc->ioh; 296 uint32_t reg; 297 298 reg = bus_space_read_4(iot, ioh, LCDC_LCDCON5); 299 300 if (on) 301 reg |= LCDCON5_PWREN; 302 else 303 reg &= ~LCDCON5_PWREN; 304 305 bus_space_write_4(iot, ioh, LCDC_LCDCON5, reg); 306 } 307 308 struct s3c24x0_lcd_screen * 309 s3c24x0_lcd_new_screen(struct s3c24x0_lcd_softc *sc, 310 int virtual_width, int virtual_height, int depth) 311 { 312 struct s3c24x0_lcd_screen *scr = NULL; 313 bus_size_t size; 314 int error; 315 int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | 316 BUS_DMA_WRITE; 317 paddr_t align; 318 319 #if 0 /* Does this make any sense? */ 320 #ifdef DIAGNOSTIC 321 if (size > 1 << 22) { 322 aprint_error_dev(sc->dev, "too big screen size\n"); 323 return NULL; 324 } 325 #endif 326 #endif 327 328 switch (depth) { 329 case 1: case 2: case 4: case 8: 330 virtual_width = roundup(virtual_width, 16 / depth); 331 break; 332 case 16: 333 break; 334 case 12: case 24: 335 default: 336 aprint_error("%s: Unknown depth (%d)\n", 337 device_xname(sc->sc_dev), depth); 338 return NULL; 339 } 340 341 scr = malloc(sizeof *scr, M_DEVBUF, 342 M_ZERO | (cold ? M_NOWAIT : M_WAITOK)); 343 344 if (scr == NULL) 345 return NULL; 346 347 scr->nsegs = 0; 348 scr->depth = depth; 349 scr->stride = virtual_width * depth / 8; 350 scr->buf_size = size = scr->stride * virtual_height; 351 scr->buf_va = NULL; 352 353 /* calculate the alignment for LCD frame buffer. 354 the buffer can't across 4MB boundary */ 355 align = 1 << 20; 356 while (align < size) 357 align <<= 1; 358 359 printf("%s: Allocating LCD frame buffer of size %ld\n", 360 device_xname(sc->sc_dev), size); 361 362 error = bus_dmamem_alloc(sc->dma_tag, size, align, 0, 363 scr->segs, 1, &(scr->nsegs), busdma_flag); 364 365 if (error || scr->nsegs != 1) 366 goto bad; 367 368 error = bus_dmamem_map(sc->dma_tag, scr->segs, scr->nsegs, 369 size, (void **)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT); 370 if (error) 371 goto bad; 372 373 374 memset (scr->buf_va, 0, scr->buf_size); 375 376 /* map memory for DMA */ 377 if (bus_dmamap_create(sc->dma_tag, 1024*1024*2, 1, 378 1024*1024*2, 0, busdma_flag, &scr->dma)) 379 goto bad; 380 error = bus_dmamap_load(sc->dma_tag, scr->dma, 381 scr->buf_va, size, NULL, busdma_flag); 382 if (error) 383 goto bad; 384 385 LIST_INSERT_HEAD(&(sc->screens), scr, link); 386 sc->n_screens++; 387 388 #ifdef LCD_DEBUG 389 draw_test_pattern(sc, scr); 390 dump_lcdcon(__func__, sc->iot, sc->ioh); 391 #endif 392 return scr; 393 394 bad: 395 if (scr) { 396 if (scr->buf_va) 397 bus_dmamem_unmap(sc->dma_tag, scr->buf_va, size); 398 if (scr->nsegs) 399 bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs); 400 free(scr, M_DEVBUF); 401 } 402 return NULL; 403 } 404 405 406 #define _rgb(r,g,b) (((r)<<11) | ((g)<<5) | b) 407 #define rgb(r,g,b) _rgb((r)>>1,g,(b)>>1) 408 409 #define L 0x30 /* low intensity */ 410 #define H 0x3f /* hight intensity */ 411 412 static const uint16_t basic_color_map[] = { 413 rgb( 0, 0, 0), /* black */ 414 rgb( L, 0, 0), /* red */ 415 rgb( 0, L, 0), /* green */ 416 rgb( L, L, 0), /* brown */ 417 rgb( 0, 0, L), /* blue */ 418 rgb( L, 0, L), /* magenta */ 419 rgb( 0, L, L), /* cyan */ 420 _rgb(0x1c,0x38,0x1c), /* white */ 421 422 rgb( L, L, L), /* black */ 423 rgb( H, 0, 0), /* red */ 424 rgb( 0, H, 0), /* green */ 425 rgb( H, H, 0), /* brown */ 426 rgb( 0, 0, H), /* blue */ 427 rgb( H, 0, H), /* magenta */ 428 rgb( 0, H, H), /* cyan */ 429 rgb( H, H, H), /* white */ 430 }; 431 432 #define COLORMAP_LEN (sizeof basic_color_map / sizeof basic_color_map[0]) 433 434 #undef H 435 #undef L 436 437 static void 438 init_palette(struct s3c24x0_lcd_softc *sc, struct s3c24x0_lcd_screen *scr) 439 { 440 int depth = scr->depth; 441 bus_space_tag_t iot = sc->iot; 442 bus_space_handle_t ioh = sc->ioh; 443 int i; 444 445 i = 0; 446 447 switch(depth) { 448 default: 449 case 16: /* not using palette */ 450 return; 451 case 8: 452 while (i < COLORMAP_LEN) { 453 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4*i, 454 basic_color_map[i]); 455 ++i; 456 } 457 break; 458 case 4: 459 case 2: 460 /* XXX */ 461 break; 462 case 1: 463 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4 * i, 464 basic_color_map[i]); /* black */ 465 ++i; 466 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4 * i, 467 basic_color_map[7]); /* white */ 468 break; 469 } 470 471 #ifdef DIAGNOSTIC 472 /* Fill unused entries */ 473 for ( ; i < 256; ++i ) 474 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4 * i, 475 basic_color_map[1]); /* red */ 476 #endif 477 } 478 479 480 #if NWSDISPLAY > 0 481 482 static void 483 s3c24x0_lcd_stop_dma(struct s3c24x0_lcd_softc *sc) 484 { 485 /* Stop LCD output */ 486 bus_space_write_4(sc->iot, sc->ioh, LCDC_LCDCON1, 487 ~LCDCON1_ENVID & 488 bus_space_read_4(sc->iot, sc->ioh, LCDC_LCDCON1)); 489 490 491 sc->lcd_on = 0; 492 } 493 494 int 495 s3c24x0_lcd_show_screen(void *v, void *cookie, int waitok, 496 void (*cb)(void *, int, int), void *cbarg) 497 { 498 struct s3c24x0_lcd_softc *sc = v; 499 struct s3c24x0_lcd_screen *scr = cookie, *old; 500 501 /* XXX: make sure the clock is provided for LCD controller */ 502 503 old = sc->active; 504 if (old == scr && sc->lcd_on) 505 return 0; 506 507 if (old) 508 s3c24x0_lcd_stop_dma(sc); 509 510 s3c24x0_lcd_start_dma(sc, scr); 511 sc->active = scr; 512 s3c24x0_lcd_power(sc, 1); 513 514 /* XXX: callback */ 515 516 return 0; 517 } 518 519 int 520 s3c24x0_lcd_alloc_screen(void *v, const struct wsscreen_descr *_type, 521 void **cookiep, int *curxp, int *curyp, long *attrp) 522 { 523 struct s3c24x0_lcd_softc *sc = v; 524 struct s3c24x0_lcd_screen *scr; 525 const struct s3c24x0_wsscreen_descr *type = 526 (const struct s3c24x0_wsscreen_descr *)_type; 527 528 int width, height; 529 530 width = type->c.ncols * type->c.fontwidth; 531 height = type->c.nrows * type->c.fontwidth; 532 533 if (width < sc->panel_info->panel_width) 534 width = sc->panel_info->panel_width; 535 if (height < sc->panel_info->panel_height) 536 height = sc->panel_info->panel_height; 537 538 539 scr = s3c24x0_lcd_new_screen(sc, width, height, type->depth); 540 if (scr == NULL) 541 return -1; 542 543 /* 544 * initialize raster operation for this screen. 545 */ 546 scr->rinfo.ri_flg = 0; 547 scr->rinfo.ri_depth = type->depth; 548 scr->rinfo.ri_bits = scr->buf_va; 549 scr->rinfo.ri_width = width; 550 scr->rinfo.ri_height = height; 551 scr->rinfo.ri_stride = scr->stride; 552 553 if (type->c.fontwidth || type->c.fontheight) { 554 /* 555 * find a font with specified size 556 */ 557 int cookie; 558 559 wsfont_init(); 560 561 cookie = wsfont_find(NULL, type->c.fontwidth, 562 type->c.fontheight, 0, WSDISPLAY_FONTORDER_L2R, 563 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 564 565 if (cookie > 0) { 566 if (wsfont_lock(cookie, &scr->rinfo.ri_font)) 567 scr->rinfo.ri_wsfcookie = cookie; 568 } 569 } 570 571 rasops_init(&scr->rinfo, type->c.nrows, type->c.ncols); 572 573 (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 0, 0, 0, attrp); 574 575 if (type->c.nrows != scr->rinfo.ri_rows || 576 type->c.ncols != scr->rinfo.ri_cols) { 577 578 aprint_error("%s: can't allocate a screen with requested size:" 579 "%d x %d -> %d x %d\n", 580 device_xname(sc->sc_dev), 581 type->c.ncols, type->c.nrows, 582 scr->rinfo.ri_cols, scr->rinfo.ri_rows); 583 } 584 585 *cookiep = scr; 586 *curxp = 0; 587 *curyp = 0; 588 589 return 0; 590 } 591 592 593 void 594 s3c24x0_lcd_free_screen(void *v, void *cookie) 595 { 596 struct s3c24x0_lcd_softc *sc = v; 597 struct s3c24x0_lcd_screen *scr = cookie; 598 599 LIST_REMOVE(scr, link); 600 sc->n_screens--; 601 if (scr == sc->active) { 602 sc->active = NULL; 603 604 /* XXX: We need a good procedure to shutdown the LCD. */ 605 606 s3c24x0_lcd_stop_dma(sc); 607 s3c24x0_lcd_power(sc, 0); 608 } 609 610 if (scr->buf_va) 611 bus_dmamem_unmap(sc->dma_tag, scr->buf_va, scr->map_size); 612 613 if (scr->nsegs > 0) 614 bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs); 615 616 free(scr, M_DEVBUF); 617 } 618 619 int 620 s3c24x0_lcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 621 struct lwp *l) 622 { 623 struct s3c24x0_lcd_softc *sc = v; 624 struct wsdisplay_fbinfo *wsdisp_info; 625 struct s3c24x0_lcd_screen *scr; 626 627 628 switch (cmd) { 629 case WSDISPLAYIO_GTYPE: 630 *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */ 631 return 0; 632 633 case WSDISPLAYIO_GINFO: 634 wsdisp_info = (struct wsdisplay_fbinfo *)data; 635 636 wsdisp_info->height = sc->panel_info->panel_height; 637 wsdisp_info->width = sc->panel_info->panel_width; 638 wsdisp_info->depth = 16; /* XXX */ 639 wsdisp_info->cmsize = 0; 640 return 0; 641 642 case WSDISPLAYIO_LINEBYTES: 643 *(u_int *)data = sc->panel_info->panel_width * (16/8); 644 return 0; 645 646 case WSDISPLAYIO_GETCMAP: 647 case WSDISPLAYIO_PUTCMAP: 648 return EPASSTHROUGH; /* XXX Colormap */ 649 650 case WSDISPLAYIO_SVIDEO: 651 if (*(int *)data == WSDISPLAYIO_VIDEO_ON) { 652 scr = sc->active; 653 if (scr == NULL) 654 scr = LIST_FIRST(&sc->screens); 655 656 if (scr == NULL) 657 return ENXIO; 658 659 s3c24x0_lcd_show_screen(sc, scr, 1, NULL, NULL); 660 } 661 else { 662 s3c24x0_lcd_stop_dma(sc); 663 s3c24x0_lcd_power(sc, 0); 664 } 665 return 0; 666 667 case WSDISPLAYIO_GVIDEO: 668 *(u_int *)data = sc->lcd_on; 669 return 0; 670 671 /* XXX: Hack to support /usr/sbin/tpctl */ 672 case HPCFBIO_GCONF: 673 { 674 struct hpcfb_fbconf *fbconf = (struct hpcfb_fbconf*)data; 675 if (fbconf->hf_conf_index != 0 && 676 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) 677 return EINVAL; 678 679 fbconf->hf_nconfs = 1; 680 fbconf->hf_class = HPCFB_CLASS_RGBCOLOR; 681 strncpy(fbconf->hf_name, "S3C24X0 LCD", HPCFB_MAXNAMELEN); 682 strncpy(fbconf->hf_conf_name, "default", HPCFB_MAXNAMELEN); 683 fbconf->hf_height = sc->panel_info->panel_height; 684 fbconf->hf_width = sc->panel_info->panel_width; 685 fbconf->hf_baseaddr = 0x0; 686 fbconf->hf_offset = 0x0; 687 fbconf->hf_bytes_per_line = sc->panel_info->panel_width * (16/8); 688 fbconf->hf_nplanes = 0; 689 fbconf->hf_bytes_per_plane = 0; 690 fbconf->hf_pack_width = 16; 691 fbconf->hf_pixels_per_pack = 1; 692 fbconf->hf_pixel_width = 16; 693 694 fbconf->hf_access_flags = 0; 695 fbconf->hf_order_flags = HPCFB_REVORDER_WORD; 696 fbconf->hf_reg_offset = 0x0; 697 698 fbconf->hf_u.hf_rgb.hf_red_width = 5; 699 fbconf->hf_u.hf_rgb.hf_red_shift = 11; 700 fbconf->hf_u.hf_rgb.hf_green_width = 6; 701 fbconf->hf_u.hf_rgb.hf_green_shift = 5; 702 fbconf->hf_u.hf_rgb.hf_blue_width = 5; 703 fbconf->hf_u.hf_rgb.hf_blue_shift = 0; 704 705 fbconf->hf_ext_size = 0; 706 fbconf->hf_ext_data = NULL; 707 708 return 0; 709 } 710 711 case WSDISPLAYIO_GCURPOS: 712 case WSDISPLAYIO_SCURPOS: 713 case WSDISPLAYIO_GCURMAX: 714 case WSDISPLAYIO_GCURSOR: 715 case WSDISPLAYIO_SCURSOR: 716 return EPASSTHROUGH; /* XXX */ 717 } 718 719 return EPASSTHROUGH; 720 } 721 722 paddr_t 723 s3c24x0_lcd_mmap(void *v, void *vs, off_t offset, int prot) 724 { 725 struct s3c24x0_lcd_softc *sc = v; 726 struct s3c24x0_lcd_screen *screen = sc->active; /* ??? */ 727 paddr_t ret; 728 729 /* printf("s3c24x0_lcd_mmap: screen: %p, offset: %ld\n", screen, (long)offset);*/ 730 731 if (screen == NULL) 732 return -1; 733 734 ret = bus_dmamem_mmap(sc->dma_tag, screen->segs, screen->nsegs, 735 offset, prot, BUS_DMA_WAITOK|BUS_DMA_COHERENT); 736 /* printf("s3c24x0_lcd_mmap: ret: %lx\n", ret);*/ 737 return ret; 738 return -1; 739 } 740 741 742 static void 743 s3c24x0_lcd_cursor(void *cookie, int on, int row, int col) 744 { 745 struct s3c24x0_lcd_screen *scr = cookie; 746 747 (* scr->rinfo.ri_ops.cursor)(&scr->rinfo, on, row, col); 748 } 749 750 static int 751 s3c24x0_lcd_mapchar(void *cookie, int c, unsigned int *cp) 752 { 753 struct s3c24x0_lcd_screen *scr = cookie; 754 755 return (* scr->rinfo.ri_ops.mapchar)(&scr->rinfo, c, cp); 756 } 757 758 static void 759 s3c24x0_lcd_putchar(void *cookie, int row, int col, u_int uc, long attr) 760 { 761 struct s3c24x0_lcd_screen *scr = cookie; 762 763 (* scr->rinfo.ri_ops.putchar)(&scr->rinfo, 764 row, col, uc, attr); 765 } 766 767 static void 768 s3c24x0_lcd_copycols(void *cookie, int row, int src, int dst, int num) 769 { 770 struct s3c24x0_lcd_screen *scr = cookie; 771 772 (* scr->rinfo.ri_ops.copycols)(&scr->rinfo, 773 row, src, dst, num); 774 } 775 776 static void 777 s3c24x0_lcd_erasecols(void *cookie, int row, int col, int num, long attr) 778 { 779 struct s3c24x0_lcd_screen *scr = cookie; 780 781 (* scr->rinfo.ri_ops.erasecols)(&scr->rinfo, 782 row, col, num, attr); 783 } 784 785 static void 786 s3c24x0_lcd_copyrows(void *cookie, int src, int dst, int num) 787 { 788 struct s3c24x0_lcd_screen *scr = cookie; 789 790 (* scr->rinfo.ri_ops.copyrows)(&scr->rinfo, 791 src, dst, num); 792 } 793 794 static void 795 s3c24x0_lcd_eraserows(void *cookie, int row, int num, long attr) 796 { 797 struct s3c24x0_lcd_screen *scr = cookie; 798 799 (* scr->rinfo.ri_ops.eraserows)(&scr->rinfo, 800 row, num, attr); 801 } 802 803 static int 804 s3c24x0_lcd_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr) 805 { 806 struct s3c24x0_lcd_screen *scr = cookie; 807 808 return (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 809 fg, bg, flg, attr); 810 } 811 812 813 const struct wsdisplay_emulops s3c24x0_lcd_emulops = { 814 s3c24x0_lcd_cursor, 815 s3c24x0_lcd_mapchar, 816 s3c24x0_lcd_putchar, 817 s3c24x0_lcd_copycols, 818 s3c24x0_lcd_erasecols, 819 s3c24x0_lcd_copyrows, 820 s3c24x0_lcd_eraserows, 821 s3c24x0_lcd_alloc_attr 822 }; 823 824 #endif /* NWSDISPLAY > 0 */ 825