Annotation of sys/arch/arm/s3c2xx0/s3c24x0_lcd.c, Revision 1.1
1.1 ! nbrk 1: /* $NetBSD: s3c24x0_lcd.c,v 1.5 2007/03/04 05:59:38 christos 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.5 2007/03/04 05:59:38 christos 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 <machine/bus.h>
! 56: #include <machine/cpu.h>
! 57: #include <arm/cpufunc.h>
! 58:
! 59: #include <arm/s3c2xx0/s3c24x0var.h>
! 60: #include <arm/s3c2xx0/s3c24x0reg.h>
! 61: #include <arm/s3c2xx0/s3c24x0_lcd.h>
! 62:
! 63: #include "wsdisplay.h"
! 64:
! 65: int lcdintr(void *);
! 66: static void init_palette(struct s3c24x0_lcd_softc *,
! 67: struct s3c24x0_lcd_screen *);
! 68:
! 69: #ifdef LCD_DEBUG
! 70: static void
! 71: dump_lcdcon(const char *title, bus_space_tag_t iot, bus_space_handle_t ioh)
! 72: {
! 73: int i;
! 74:
! 75: printf("%s\n", title);
! 76: for(i=LCDC_LCDCON1; i <= LCDC_LCDSADDR3; i+=4) {
! 77: if (i%16 == 0)
! 78: printf("\n%03x: ", i);
! 79: printf("%08x ", bus_space_read_4(iot, ioh, i));
! 80: }
! 81:
! 82: printf("\n");
! 83: }
! 84:
! 85: void draw_test_pattern(struct s3c24x0_lcd_softc *,
! 86: struct s3c24x0_lcd_screen *scr);
! 87:
! 88: #endif
! 89:
! 90: void
! 91: s3c24x0_set_lcd_panel_info(struct s3c24x0_lcd_softc *sc,
! 92: const struct s3c24x0_lcd_panel_info *info)
! 93: {
! 94: bus_space_tag_t iot = sc->iot;
! 95: bus_space_handle_t ioh = sc->ioh;
! 96: uint32_t reg;
! 97: int clkval;
! 98: int tft = s3c24x0_lcd_panel_tft(info);
! 99: int hclk = s3c2xx0_softc->sc_hclk;
! 100:
! 101: sc->panel_info = info;
! 102:
! 103: /* Set LCDCON1. BPPMODE and ENVID are set later */
! 104: if (tft)
! 105: clkval = (hclk / info->pixel_clock / 2) - 1;
! 106: else {
! 107: /* STN display */
! 108: clkval = max(2, hclk / info->pixel_clock / 2);
! 109: }
! 110:
! 111: reg = (info->lcdcon1 & ~LCDCON1_CLKVAL_MASK) |
! 112: (clkval << LCDCON1_CLKVAL_SHIFT);
! 113: reg &= ~LCDCON1_ENVID;
! 114: bus_space_write_4(iot, ioh, LCDC_LCDCON1, reg);
! 115:
! 116: #if 0
! 117: printf("hclk=%d pixel clock=%d, clkval = %x lcdcon1=%x\n",
! 118: hclk, info->pixel_clock, clkval, reg);
! 119: #endif
! 120:
! 121: bus_space_write_4(iot, ioh, LCDC_LCDCON2, info->lcdcon2);
! 122: bus_space_write_4(iot, ioh, LCDC_LCDCON3, info->lcdcon3);
! 123: bus_space_write_4(iot, ioh, LCDC_LCDCON4, info->lcdcon4);
! 124: bus_space_write_4(iot, ioh, LCDC_LCDCON5, info->lcdcon5);
! 125: bus_space_write_4(iot, ioh, LCDC_LPCSEL, info->lpcsel);
! 126: }
! 127:
! 128: void
! 129: s3c24x0_lcd_attach_sub(struct s3c24x0_lcd_softc *sc,
! 130: struct s3c2xx0_attach_args *sa,
! 131: const struct s3c24x0_lcd_panel_info *panel_info)
! 132: {
! 133: bus_space_tag_t iot = sa->sa_iot;
! 134: bus_space_handle_t ioh;
! 135: int error;
! 136:
! 137: sc->n_screens = 0;
! 138: LIST_INIT(&sc->screens);
! 139:
! 140: /* map controller registers */
! 141: error = bus_space_map(iot, sa->sa_addr, S3C24X0_LCDC_SIZE, 0, &ioh);
! 142: if (error) {
! 143: printf(": failed to map registers %d", error);
! 144: return;
! 145: }
! 146:
! 147: sc->iot = iot;
! 148: sc->ioh = ioh;
! 149: sc->dma_tag = sa->sa_dmat;
! 150:
! 151: #ifdef notyet
! 152: sc->ih = s3c24x0_intr_establish(sa->sa_intr, IPL_BIO, lcdintr, sc);
! 153: if (sc->ih == NULL)
! 154: printf("%s: unable to establish interrupt at irq %d",
! 155: sc->dev.dv_xname, sa->sa_intr);
! 156: #endif
! 157:
! 158: /* mask LCD interrupts */
! 159: bus_space_write_4(iot, ioh, LCDC_LCDINTMSK, LCDINT_FICNT|LCDINT_FRSYN);
! 160:
! 161: /* Initialize controller registers based on panel geometry*/
! 162: s3c24x0_set_lcd_panel_info(sc, panel_info);
! 163:
! 164: /* XXX: enable clock to LCD controller */
! 165: }
! 166:
! 167:
! 168: #ifdef notyet
! 169: int
! 170: lcdintr(void *arg)
! 171: {
! 172: struct s3c24x0_lcd_softc *sc = arg;
! 173: bus_space_tag_t iot = sc->iot;
! 174: bus_space_handle_t ioh = sc->ioh;
! 175:
! 176: static uint32_t status;
! 177:
! 178: return 1;
! 179: }
! 180: #endif
! 181:
! 182: int
! 183: s3c24x0_lcd_start_dma(struct s3c24x0_lcd_softc *sc,
! 184: struct s3c24x0_lcd_screen *scr)
! 185: {
! 186: bus_space_tag_t iot = sc->iot;
! 187: bus_space_handle_t ioh = sc->ioh;
! 188: const struct s3c24x0_lcd_panel_info *info = sc->panel_info;
! 189: int tft = s3c24x0_lcd_panel_tft(info);
! 190: int dual_panel =
! 191: (info->lcdcon1 & LCDCON1_PNRMODE_MASK) == LCDCON1_PNRMODE_DUALSTN4;
! 192: uint32_t lcdcon1, val;
! 193: paddr_t pa;
! 194: int depth = scr->depth;
! 195: int stride = scr->stride;
! 196: int panel_height = info->panel_height;
! 197: int panel_width = info->panel_width;
! 198: int offsize;
! 199:
! 200: switch (depth) {
! 201: case 1: val = LCDCON1_BPPMODE_STN1; break;
! 202: case 2: val = LCDCON1_BPPMODE_STN2; break;
! 203: case 4: val = LCDCON1_BPPMODE_STN4; break;
! 204: case 8: val = LCDCON1_BPPMODE_STN8; break;
! 205: case 12:
! 206: if (tft)
! 207: return -1;
! 208: val = LCDCON1_BPPMODE_STN12;
! 209: break;
! 210: case 16:
! 211: if (!tft)
! 212: return -1;
! 213: val = LCDCON1_BPPMODE_TFT16;
! 214: break;
! 215: case 24:
! 216: if (!tft)
! 217: return -1;
! 218: val = LCDCON1_BPPMODE_TFT24;
! 219: break;
! 220: default:
! 221: return -1;
! 222: }
! 223:
! 224: if (tft)
! 225: val |= LCDCON1_BPPMODE_TFTX;
! 226:
! 227: lcdcon1 = bus_space_read_4(iot, ioh, LCDC_LCDCON1);
! 228: lcdcon1 &= ~(LCDCON1_BPPMODE_MASK|LCDCON1_ENVID);
! 229: lcdcon1 |= val;
! 230: bus_space_write_4(iot, ioh, LCDC_LCDCON1, lcdcon1);
! 231:
! 232: /* Adjust LCDCON3.HOZVAL to meet with restriction */
! 233: val = roundup(panel_width, 16 / depth);
! 234: bus_space_write_4(iot, ioh, LCDC_LCDCON3,
! 235: (info->lcdcon3 & ~LCDCON3_HOZVAL_MASK) |
! 236: (val - 1) << LCDCON3_HOZVAL_SHIFT);
! 237:
! 238: pa = scr->segs[0].ds_addr;
! 239: bus_space_write_4(iot, ioh, LCDC_LCDSADDR1, pa >> 1);
! 240:
! 241: if (dual_panel) {
! 242: /* XXX */
! 243: }
! 244: else {
! 245: pa += stride * panel_height;
! 246: bus_space_write_4(iot, ioh, LCDC_LCDSADDR2, pa >> 1);
! 247: }
! 248:
! 249: offsize = stride / sizeof (uint16_t) - (panel_width * depth / 16);
! 250: bus_space_write_4(iot, ioh, LCDC_LCDSADDR3,
! 251: (offsize << LCDSADDR3_OFFSIZE_SHIFT) |
! 252: (panel_width * depth / 16));
! 253:
! 254: /* set byte- or halfword- swap based on the depth */
! 255: val = bus_space_read_4(iot, ioh, LCDC_LCDCON5);
! 256: val &= ~(LCDCON5_BSWP|LCDCON5_HWSWP);
! 257: switch(depth) {
! 258: case 2:
! 259: case 4:
! 260: case 8:
! 261: val |= LCDCON5_BSWP;
! 262: break;
! 263: case 16:
! 264: val |= LCDCON5_HWSWP;
! 265: break;
! 266: }
! 267: bus_space_write_4(iot, ioh, LCDC_LCDCON5, val);
! 268:
! 269:
! 270: init_palette(sc, scr);
! 271:
! 272: #if 0
! 273: bus_space_write_4(iot, ioh, LCDC_TPAL, TPAL_TPALEN|
! 274: (0xff<<TPAL_BLUE_SHIFT));
! 275: #endif
! 276:
! 277: /* Enable LCDC */
! 278: bus_space_write_4(iot, ioh, LCDC_LCDCON1, lcdcon1 | LCDCON1_ENVID);
! 279:
! 280: sc->lcd_on = 1;
! 281:
! 282: #ifdef LCD_DEBUG
! 283: dump_lcdcon(__FUNCTION__, iot, ioh);
! 284: #endif
! 285:
! 286: return 0;
! 287: }
! 288:
! 289: void
! 290: s3c24x0_lcd_power(struct s3c24x0_lcd_softc *sc, int on)
! 291: {
! 292: bus_space_tag_t iot = sc->iot;
! 293: bus_space_handle_t ioh = sc->ioh;
! 294: uint32_t reg;
! 295:
! 296: reg = bus_space_read_4(iot, ioh, LCDC_LCDCON5);
! 297:
! 298: if (on)
! 299: reg |= LCDCON5_PWREN;
! 300: else
! 301: reg &= ~LCDCON5_PWREN;
! 302:
! 303: bus_space_write_4(iot, ioh, LCDC_LCDCON5, reg);
! 304: }
! 305:
! 306: struct s3c24x0_lcd_screen *
! 307: s3c24x0_lcd_new_screen(struct s3c24x0_lcd_softc *sc,
! 308: int virtual_width, int virtual_height, int depth)
! 309: {
! 310: struct s3c24x0_lcd_screen *scr = NULL;
! 311: int width, height;
! 312: bus_size_t size;
! 313: int error, pallet_size;
! 314: int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
! 315: BUS_DMA_WRITE;
! 316: paddr_t align;
! 317: const struct s3c24x0_lcd_panel_info *panel_info = sc->panel_info;
! 318:
! 319:
! 320: #ifdef DIAGNOSTIC
! 321: if (size > 1 << 22) {
! 322: aprint_error("%s: too big screen size\n", sc->dev.dv_xname);
! 323: return NULL;
! 324: }
! 325: #endif
! 326:
! 327: width = panel_info->panel_width;
! 328: height = panel_info->panel_height;
! 329: pallet_size = 0;
! 330:
! 331: switch (depth) {
! 332: case 1: case 2: case 4: case 8:
! 333: virtual_width = roundup(virtual_width, 16 / depth);
! 334: break;
! 335: case 16:
! 336: break;
! 337: case 12: case 24:
! 338: default:
! 339: aprint_error("%s: Unknown depth (%d)\n",
! 340: sc->dev.dv_xname, depth);
! 341: return NULL;
! 342: }
! 343:
! 344: scr = malloc(sizeof *scr, M_DEVBUF,
! 345: M_ZERO | (cold ? M_NOWAIT : M_WAITOK));
! 346:
! 347: if (scr == NULL)
! 348: return NULL;
! 349:
! 350: scr->nsegs = 0;
! 351: scr->depth = depth;
! 352: scr->stride = virtual_width * depth / 8;
! 353: scr->buf_size = size = scr->stride * virtual_height;
! 354: scr->buf_va = NULL;
! 355:
! 356: /* calculate the alignment for LCD frame buffer.
! 357: the buffer can't across 4MB boundary */
! 358: align = 1 << 20;
! 359: while (align < size)
! 360: align <<= 1;
! 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(__FUNCTION__, 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);
! 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: sc->dev.dv_xname,
! 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_GETCMAP:
! 643: case WSDISPLAYIO_PUTCMAP:
! 644: return EPASSTHROUGH; /* XXX Colormap */
! 645:
! 646: case WSDISPLAYIO_SVIDEO:
! 647: if (*(int *)data == WSDISPLAYIO_VIDEO_ON) {
! 648: scr = sc->active;
! 649: if (scr == NULL)
! 650: scr = LIST_FIRST(&sc->screens);
! 651:
! 652: if (scr == NULL)
! 653: return ENXIO;
! 654:
! 655: s3c24x0_lcd_show_screen(sc, scr, 1, NULL, NULL);
! 656: }
! 657: else {
! 658: s3c24x0_lcd_stop_dma(sc);
! 659: s3c24x0_lcd_power(sc, 0);
! 660: }
! 661: return 0;
! 662:
! 663: case WSDISPLAYIO_GVIDEO:
! 664: *(u_int *)data = sc->lcd_on;
! 665: return 0;
! 666:
! 667: case WSDISPLAYIO_GCURPOS:
! 668: case WSDISPLAYIO_SCURPOS:
! 669: case WSDISPLAYIO_GCURMAX:
! 670: case WSDISPLAYIO_GCURSOR:
! 671: case WSDISPLAYIO_SCURSOR:
! 672: return EPASSTHROUGH; /* XXX */
! 673: }
! 674:
! 675: return EPASSTHROUGH;
! 676: }
! 677:
! 678: paddr_t
! 679: s3c24x0_lcd_mmap(void *v, void *vs, off_t offset, int prot)
! 680: {
! 681: struct s3c24x0_lcd_softc *sc = v;
! 682: struct s3c24x0_lcd_screen *screen = sc->active; /* ??? */
! 683:
! 684: if (screen == NULL)
! 685: return -1;
! 686:
! 687: return bus_dmamem_mmap(sc->dma_tag, screen->segs, screen->nsegs,
! 688: offset, prot, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
! 689: return -1;
! 690: }
! 691:
! 692:
! 693: static void
! 694: s3c24x0_lcd_cursor(void *cookie, int on, int row, int col)
! 695: {
! 696: struct s3c24x0_lcd_screen *scr = cookie;
! 697:
! 698: (* scr->rinfo.ri_ops.cursor)(&scr->rinfo, on, row, col);
! 699: }
! 700:
! 701: static int
! 702: s3c24x0_lcd_mapchar(void *cookie, int c, unsigned int *cp)
! 703: {
! 704: struct s3c24x0_lcd_screen *scr = cookie;
! 705:
! 706: return (* scr->rinfo.ri_ops.mapchar)(&scr->rinfo, c, cp);
! 707: }
! 708:
! 709: static void
! 710: s3c24x0_lcd_putchar(void *cookie, int row, int col, u_int uc, long attr)
! 711: {
! 712: struct s3c24x0_lcd_screen *scr = cookie;
! 713:
! 714: (* scr->rinfo.ri_ops.putchar)(&scr->rinfo,
! 715: row, col, uc, attr);
! 716: }
! 717:
! 718: static void
! 719: s3c24x0_lcd_copycols(void *cookie, int row, int src, int dst, int num)
! 720: {
! 721: struct s3c24x0_lcd_screen *scr = cookie;
! 722:
! 723: (* scr->rinfo.ri_ops.copycols)(&scr->rinfo,
! 724: row, src, dst, num);
! 725: }
! 726:
! 727: static void
! 728: s3c24x0_lcd_erasecols(void *cookie, int row, int col, int num, long attr)
! 729: {
! 730: struct s3c24x0_lcd_screen *scr = cookie;
! 731:
! 732: (* scr->rinfo.ri_ops.erasecols)(&scr->rinfo,
! 733: row, col, num, attr);
! 734: }
! 735:
! 736: static void
! 737: s3c24x0_lcd_copyrows(void *cookie, int src, int dst, int num)
! 738: {
! 739: struct s3c24x0_lcd_screen *scr = cookie;
! 740:
! 741: (* scr->rinfo.ri_ops.copyrows)(&scr->rinfo,
! 742: src, dst, num);
! 743: }
! 744:
! 745: static void
! 746: s3c24x0_lcd_eraserows(void *cookie, int row, int num, long attr)
! 747: {
! 748: struct s3c24x0_lcd_screen *scr = cookie;
! 749:
! 750: (* scr->rinfo.ri_ops.eraserows)(&scr->rinfo,
! 751: row, num, attr);
! 752: }
! 753:
! 754: static int
! 755: s3c24x0_lcd_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr)
! 756: {
! 757: struct s3c24x0_lcd_screen *scr = cookie;
! 758:
! 759: return (* scr->rinfo.ri_ops.allocattr)(&scr->rinfo,
! 760: fg, bg, flg, attr);
! 761: }
! 762:
! 763:
! 764: const struct wsdisplay_emulops s3c24x0_lcd_emulops = {
! 765: s3c24x0_lcd_cursor,
! 766: s3c24x0_lcd_mapchar,
! 767: s3c24x0_lcd_putchar,
! 768: s3c24x0_lcd_copycols,
! 769: s3c24x0_lcd_erasecols,
! 770: s3c24x0_lcd_copyrows,
! 771: s3c24x0_lcd_eraserows,
! 772: s3c24x0_lcd_alloc_attr
! 773: };
! 774:
! 775: #endif /* NWSDISPLAY > 0 */
CVSweb