1 /* $NetBSD: s3c24x0_lcd.c,v 1.16 2024/07/05 19:28:36 andvar 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.16 2024/07/05 19:28:36 andvar 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/kmem.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 = uimax(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 = kmem_zalloc(sizeof *scr, KM_SLEEP); 342 scr->nsegs = 0; 343 scr->depth = depth; 344 scr->stride = virtual_width * depth / 8; 345 scr->buf_size = size = scr->stride * virtual_height; 346 scr->buf_va = NULL; 347 348 /* calculate the alignment for LCD frame buffer. 349 the buffer can't across 4MB boundary */ 350 align = 1 << 20; 351 while (align < size) 352 align <<= 1; 353 354 printf("%s: Allocating LCD frame buffer of size %ld\n", 355 device_xname(sc->sc_dev), size); 356 357 error = bus_dmamem_alloc(sc->dma_tag, size, align, 0, 358 scr->segs, 1, &(scr->nsegs), busdma_flag); 359 360 if (error || scr->nsegs != 1) 361 goto bad; 362 363 error = bus_dmamem_map(sc->dma_tag, scr->segs, scr->nsegs, 364 size, (void **)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT); 365 if (error) 366 goto bad; 367 368 369 memset (scr->buf_va, 0, scr->buf_size); 370 371 /* map memory for DMA */ 372 if (bus_dmamap_create(sc->dma_tag, 1024*1024*2, 1, 373 1024*1024*2, 0, busdma_flag, &scr->dma)) 374 goto bad; 375 error = bus_dmamap_load(sc->dma_tag, scr->dma, 376 scr->buf_va, size, NULL, busdma_flag); 377 if (error) 378 goto bad; 379 380 LIST_INSERT_HEAD(&(sc->screens), scr, link); 381 sc->n_screens++; 382 383 #ifdef LCD_DEBUG 384 draw_test_pattern(sc, scr); 385 dump_lcdcon(__func__, sc->iot, sc->ioh); 386 #endif 387 return scr; 388 389 bad: 390 if (scr) { 391 if (scr->buf_va) 392 bus_dmamem_unmap(sc->dma_tag, scr->buf_va, size); 393 if (scr->nsegs) 394 bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs); 395 kmem_free(scr, sizeof(*scr)); 396 } 397 return NULL; 398 } 399 400 401 #define _rgb(r,g,b) (((r)<<11) | ((g)<<5) | b) 402 #define rgb(r,g,b) _rgb((r)>>1,g,(b)>>1) 403 404 #define L 0x30 /* low intensity */ 405 #define H 0x3f /* high intensity */ 406 407 static const uint16_t basic_color_map[] = { 408 rgb( 0, 0, 0), /* black */ 409 rgb( L, 0, 0), /* red */ 410 rgb( 0, L, 0), /* green */ 411 rgb( L, L, 0), /* brown */ 412 rgb( 0, 0, L), /* blue */ 413 rgb( L, 0, L), /* magenta */ 414 rgb( 0, L, L), /* cyan */ 415 _rgb(0x1c,0x38,0x1c), /* white */ 416 417 rgb( L, L, L), /* black */ 418 rgb( H, 0, 0), /* red */ 419 rgb( 0, H, 0), /* green */ 420 rgb( H, H, 0), /* brown */ 421 rgb( 0, 0, H), /* blue */ 422 rgb( H, 0, H), /* magenta */ 423 rgb( 0, H, H), /* cyan */ 424 rgb( H, H, H), /* white */ 425 }; 426 427 #define COLORMAP_LEN (sizeof basic_color_map / sizeof basic_color_map[0]) 428 429 #undef H 430 #undef L 431 432 static void 433 init_palette(struct s3c24x0_lcd_softc *sc, struct s3c24x0_lcd_screen *scr) 434 { 435 int depth = scr->depth; 436 bus_space_tag_t iot = sc->iot; 437 bus_space_handle_t ioh = sc->ioh; 438 int i; 439 440 i = 0; 441 442 switch(depth) { 443 default: 444 case 16: /* not using palette */ 445 return; 446 case 8: 447 while (i < COLORMAP_LEN) { 448 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4*i, 449 basic_color_map[i]); 450 ++i; 451 } 452 break; 453 case 4: 454 case 2: 455 /* XXX */ 456 break; 457 case 1: 458 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4 * i, 459 basic_color_map[i]); /* black */ 460 ++i; 461 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4 * i, 462 basic_color_map[7]); /* white */ 463 break; 464 } 465 466 #ifdef DIAGNOSTIC 467 /* Fill unused entries */ 468 for ( ; i < 256; ++i ) 469 bus_space_write_4(iot, ioh, LCDC_PALETTE + 4 * i, 470 basic_color_map[1]); /* red */ 471 #endif 472 } 473 474 475 #if NWSDISPLAY > 0 476 477 static void 478 s3c24x0_lcd_stop_dma(struct s3c24x0_lcd_softc *sc) 479 { 480 /* Stop LCD output */ 481 bus_space_write_4(sc->iot, sc->ioh, LCDC_LCDCON1, 482 ~LCDCON1_ENVID & 483 bus_space_read_4(sc->iot, sc->ioh, LCDC_LCDCON1)); 484 485 486 sc->lcd_on = 0; 487 } 488 489 int 490 s3c24x0_lcd_show_screen(void *v, void *cookie, int waitok, 491 void (*cb)(void *, int, int), void *cbarg) 492 { 493 struct s3c24x0_lcd_softc *sc = v; 494 struct s3c24x0_lcd_screen *scr = cookie, *old; 495 496 /* XXX: make sure the clock is provided for LCD controller */ 497 498 old = sc->active; 499 if (old == scr && sc->lcd_on) 500 return 0; 501 502 if (old) 503 s3c24x0_lcd_stop_dma(sc); 504 505 s3c24x0_lcd_start_dma(sc, scr); 506 sc->active = scr; 507 s3c24x0_lcd_power(sc, 1); 508 509 /* XXX: callback */ 510 511 return 0; 512 } 513 514 int 515 s3c24x0_lcd_alloc_screen(void *v, const struct wsscreen_descr *_type, 516 void **cookiep, int *curxp, int *curyp, long *attrp) 517 { 518 struct s3c24x0_lcd_softc *sc = v; 519 struct s3c24x0_lcd_screen *scr; 520 const struct s3c24x0_wsscreen_descr *type = 521 (const struct s3c24x0_wsscreen_descr *)_type; 522 523 int width, height; 524 525 width = type->c.ncols * type->c.fontwidth; 526 height = type->c.nrows * type->c.fontwidth; 527 528 if (width < sc->panel_info->panel_width) 529 width = sc->panel_info->panel_width; 530 if (height < sc->panel_info->panel_height) 531 height = sc->panel_info->panel_height; 532 533 534 scr = s3c24x0_lcd_new_screen(sc, width, height, type->depth); 535 if (scr == NULL) 536 return -1; 537 538 /* 539 * initialize raster operation for this screen. 540 */ 541 scr->rinfo.ri_flg = 0; 542 scr->rinfo.ri_depth = type->depth; 543 scr->rinfo.ri_bits = scr->buf_va; 544 scr->rinfo.ri_width = width; 545 scr->rinfo.ri_height = height; 546 scr->rinfo.ri_stride = scr->stride; 547 548 if (type->c.fontwidth || type->c.fontheight) { 549 /* 550 * find a font with specified size 551 */ 552 int cookie; 553 554 wsfont_init(); 555 556 cookie = wsfont_find(NULL, type->c.fontwidth, 557 type->c.fontheight, 0, WSDISPLAY_FONTORDER_L2R, 558 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 559 560 if (cookie > 0) { 561 if (wsfont_lock(cookie, &scr->rinfo.ri_font)) 562 scr->rinfo.ri_wsfcookie = cookie; 563 } 564 } 565 566 rasops_init(&scr->rinfo, type->c.nrows, type->c.ncols); 567 568 (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 0, 0, 0, attrp); 569 570 if (type->c.nrows != scr->rinfo.ri_rows || 571 type->c.ncols != scr->rinfo.ri_cols) { 572 573 aprint_error("%s: can't allocate a screen with requested size:" 574 "%d x %d -> %d x %d\n", 575 device_xname(sc->sc_dev), 576 type->c.ncols, type->c.nrows, 577 scr->rinfo.ri_cols, scr->rinfo.ri_rows); 578 } 579 580 *cookiep = scr; 581 *curxp = 0; 582 *curyp = 0; 583 584 return 0; 585 } 586 587 588 void 589 s3c24x0_lcd_free_screen(void *v, void *cookie) 590 { 591 struct s3c24x0_lcd_softc *sc = v; 592 struct s3c24x0_lcd_screen *scr = cookie; 593 594 LIST_REMOVE(scr, link); 595 sc->n_screens--; 596 if (scr == sc->active) { 597 sc->active = NULL; 598 599 /* XXX: We need a good procedure to shutdown the LCD. */ 600 601 s3c24x0_lcd_stop_dma(sc); 602 s3c24x0_lcd_power(sc, 0); 603 } 604 605 if (scr->buf_va) 606 bus_dmamem_unmap(sc->dma_tag, scr->buf_va, scr->map_size); 607 608 if (scr->nsegs > 0) 609 bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs); 610 611 kmem_free(scr, sizeof(*scr)); 612 } 613 614 int 615 s3c24x0_lcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 616 struct lwp *l) 617 { 618 struct s3c24x0_lcd_softc *sc = v; 619 struct wsdisplay_fbinfo *wsdisp_info; 620 struct s3c24x0_lcd_screen *scr; 621 622 623 switch (cmd) { 624 case WSDISPLAYIO_GTYPE: 625 *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */ 626 return 0; 627 628 case WSDISPLAYIO_GINFO: 629 wsdisp_info = (struct wsdisplay_fbinfo *)data; 630 631 wsdisp_info->height = sc->panel_info->panel_height; 632 wsdisp_info->width = sc->panel_info->panel_width; 633 wsdisp_info->depth = 16; /* XXX */ 634 wsdisp_info->cmsize = 0; 635 return 0; 636 637 case WSDISPLAYIO_LINEBYTES: 638 *(u_int *)data = sc->panel_info->panel_width * (16/8); 639 return 0; 640 641 case WSDISPLAYIO_GETCMAP: 642 case WSDISPLAYIO_PUTCMAP: 643 return EPASSTHROUGH; /* XXX Colormap */ 644 645 case WSDISPLAYIO_SVIDEO: 646 if (*(int *)data == WSDISPLAYIO_VIDEO_ON) { 647 scr = sc->active; 648 if (scr == NULL) 649 scr = LIST_FIRST(&sc->screens); 650 651 if (scr == NULL) 652 return ENXIO; 653 654 s3c24x0_lcd_show_screen(sc, scr, 1, NULL, NULL); 655 } 656 else { 657 s3c24x0_lcd_stop_dma(sc); 658 s3c24x0_lcd_power(sc, 0); 659 } 660 return 0; 661 662 case WSDISPLAYIO_GVIDEO: 663 *(u_int *)data = sc->lcd_on; 664 return 0; 665 666 /* XXX: Hack to support /usr/sbin/tpctl */ 667 case HPCFBIO_GCONF: 668 { 669 struct hpcfb_fbconf *fbconf = (struct hpcfb_fbconf*)data; 670 if (fbconf->hf_conf_index != 0 && 671 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) 672 return EINVAL; 673 674 fbconf->hf_nconfs = 1; 675 fbconf->hf_class = HPCFB_CLASS_RGBCOLOR; 676 strncpy(fbconf->hf_name, "S3C24X0 LCD", HPCFB_MAXNAMELEN); 677 strncpy(fbconf->hf_conf_name, "default", HPCFB_MAXNAMELEN); 678 fbconf->hf_height = sc->panel_info->panel_height; 679 fbconf->hf_width = sc->panel_info->panel_width; 680 fbconf->hf_baseaddr = 0x0; 681 fbconf->hf_offset = 0x0; 682 fbconf->hf_bytes_per_line = sc->panel_info->panel_width * (16/8); 683 fbconf->hf_nplanes = 0; 684 fbconf->hf_bytes_per_plane = 0; 685 fbconf->hf_pack_width = 16; 686 fbconf->hf_pixels_per_pack = 1; 687 fbconf->hf_pixel_width = 16; 688 689 fbconf->hf_access_flags = 0; 690 fbconf->hf_order_flags = HPCFB_REVORDER_WORD; 691 fbconf->hf_reg_offset = 0x0; 692 693 fbconf->hf_u.hf_rgb.hf_red_width = 5; 694 fbconf->hf_u.hf_rgb.hf_red_shift = 11; 695 fbconf->hf_u.hf_rgb.hf_green_width = 6; 696 fbconf->hf_u.hf_rgb.hf_green_shift = 5; 697 fbconf->hf_u.hf_rgb.hf_blue_width = 5; 698 fbconf->hf_u.hf_rgb.hf_blue_shift = 0; 699 700 fbconf->hf_ext_size = 0; 701 fbconf->hf_ext_data = NULL; 702 703 return 0; 704 } 705 706 case WSDISPLAYIO_GCURPOS: 707 case WSDISPLAYIO_SCURPOS: 708 case WSDISPLAYIO_GCURMAX: 709 case WSDISPLAYIO_GCURSOR: 710 case WSDISPLAYIO_SCURSOR: 711 return EPASSTHROUGH; /* XXX */ 712 } 713 714 return EPASSTHROUGH; 715 } 716 717 paddr_t 718 s3c24x0_lcd_mmap(void *v, void *vs, off_t offset, int prot) 719 { 720 struct s3c24x0_lcd_softc *sc = v; 721 struct s3c24x0_lcd_screen *screen = sc->active; /* ??? */ 722 paddr_t ret; 723 724 /* printf("s3c24x0_lcd_mmap: screen: %p, offset: %ld\n", screen, (long)offset);*/ 725 726 if (screen == NULL) 727 return -1; 728 729 ret = bus_dmamem_mmap(sc->dma_tag, screen->segs, screen->nsegs, 730 offset, prot, BUS_DMA_WAITOK|BUS_DMA_COHERENT); 731 /* printf("s3c24x0_lcd_mmap: ret: %lx\n", ret);*/ 732 return ret; 733 } 734 735 736 static void 737 s3c24x0_lcd_cursor(void *cookie, int on, int row, int col) 738 { 739 struct s3c24x0_lcd_screen *scr = cookie; 740 741 (* scr->rinfo.ri_ops.cursor)(&scr->rinfo, on, row, col); 742 } 743 744 static int 745 s3c24x0_lcd_mapchar(void *cookie, int c, unsigned int *cp) 746 { 747 struct s3c24x0_lcd_screen *scr = cookie; 748 749 return (* scr->rinfo.ri_ops.mapchar)(&scr->rinfo, c, cp); 750 } 751 752 static void 753 s3c24x0_lcd_putchar(void *cookie, int row, int col, u_int uc, long attr) 754 { 755 struct s3c24x0_lcd_screen *scr = cookie; 756 757 (* scr->rinfo.ri_ops.putchar)(&scr->rinfo, 758 row, col, uc, attr); 759 } 760 761 static void 762 s3c24x0_lcd_copycols(void *cookie, int row, int src, int dst, int num) 763 { 764 struct s3c24x0_lcd_screen *scr = cookie; 765 766 (* scr->rinfo.ri_ops.copycols)(&scr->rinfo, 767 row, src, dst, num); 768 } 769 770 static void 771 s3c24x0_lcd_erasecols(void *cookie, int row, int col, int num, long attr) 772 { 773 struct s3c24x0_lcd_screen *scr = cookie; 774 775 (* scr->rinfo.ri_ops.erasecols)(&scr->rinfo, 776 row, col, num, attr); 777 } 778 779 static void 780 s3c24x0_lcd_copyrows(void *cookie, int src, int dst, int num) 781 { 782 struct s3c24x0_lcd_screen *scr = cookie; 783 784 (* scr->rinfo.ri_ops.copyrows)(&scr->rinfo, 785 src, dst, num); 786 } 787 788 static void 789 s3c24x0_lcd_eraserows(void *cookie, int row, int num, long attr) 790 { 791 struct s3c24x0_lcd_screen *scr = cookie; 792 793 (* scr->rinfo.ri_ops.eraserows)(&scr->rinfo, 794 row, num, attr); 795 } 796 797 static int 798 s3c24x0_lcd_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr) 799 { 800 struct s3c24x0_lcd_screen *scr = cookie; 801 802 return (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 803 fg, bg, flg, attr); 804 } 805 806 807 const struct wsdisplay_emulops s3c24x0_lcd_emulops = { 808 s3c24x0_lcd_cursor, 809 s3c24x0_lcd_mapchar, 810 s3c24x0_lcd_putchar, 811 s3c24x0_lcd_copycols, 812 s3c24x0_lcd_erasecols, 813 s3c24x0_lcd_copyrows, 814 s3c24x0_lcd_eraserows, 815 s3c24x0_lcd_alloc_attr 816 }; 817 818 #endif /* NWSDISPLAY > 0 */ 819