Annotation of sys/arch/arm/xscale/pxa2x0_lcd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pxa2x0_lcd.c,v 1.22 2007/05/27 16:12:11 matthieu Exp $ */
! 2: /* $NetBSD: pxa2x0_lcd.c,v 1.8 2003/10/03 07:24:05 bsh Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2002 Genetec Corporation. All rights reserved.
! 6: * Written by Hiroyuki Bessho for Genetec Corporation.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed for the NetBSD Project by
! 19: * Genetec Corporation.
! 20: * 4. The name of Genetec Corporation may not be used to endorse or
! 21: * promote products derived from this software without specific prior
! 22: * written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 26: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 27: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
! 28: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 29: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 30: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 31: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 32: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 33: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 34: * POSSIBILITY OF SUCH DAMAGE.
! 35: */
! 36:
! 37: /*
! 38: * Support PXA2[15]0's integrated LCD controller.
! 39: */
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/conf.h>
! 44: #include <sys/uio.h>
! 45: #include <sys/malloc.h>
! 46: #include <sys/kernel.h> /* for cold */
! 47:
! 48: #include <uvm/uvm_extern.h>
! 49:
! 50: #include <dev/cons.h>
! 51:
! 52: #include <dev/wscons/wsconsio.h>
! 53: #include <dev/wscons/wsdisplayvar.h>
! 54: #include <dev/rasops/rasops.h>
! 55:
! 56: #include <machine/bus.h>
! 57: #include <machine/cpu.h>
! 58: #include <arm/cpufunc.h>
! 59:
! 60: #include <arm/xscale/pxa2x0var.h>
! 61: #include <arm/xscale/pxa2x0reg.h>
! 62: #include <arm/xscale/pxa2x0_lcd.h>
! 63: #include <arm/xscale/pxa2x0_gpio.h>
! 64:
! 65: /*
! 66: * Console variables. These are necessary since console is setup very early,
! 67: * before devices get attached.
! 68: */
! 69: struct {
! 70: bus_space_tag_t iot;
! 71: bus_space_handle_t ioh;
! 72: bus_dma_tag_t dma_tag;
! 73: const struct lcd_panel_geometry *geometry;
! 74: struct pxa2x0_lcd_screen scr;
! 75: } pxa2x0_lcd_console;
! 76:
! 77: int lcdintr(void *);
! 78: void pxa2x0_lcd_geometry(bus_space_tag_t, bus_space_handle_t,
! 79: const struct lcd_panel_geometry *);
! 80: void pxa2x0_lcd_initialize(bus_space_tag_t, bus_space_handle_t,
! 81: const struct lcd_panel_geometry *, void (*)(u_int, int));
! 82: int pxa2x0_lcd_new_screen(struct pxa2x0_lcd_softc *,
! 83: struct pxa2x0_lcd_screen *, int);
! 84: void pxa2x0_lcd_setup_console(struct pxa2x0_lcd_softc *,
! 85: const struct pxa2x0_wsscreen_descr *);
! 86: void pxa2x0_lcd_setup_rasops(struct rasops_info *,
! 87: struct pxa2x0_wsscreen_descr *,
! 88: const struct lcd_panel_geometry *);
! 89: void pxa2x0_lcd_start_dma(bus_space_tag_t, bus_space_handle_t,
! 90: struct pxa2x0_lcd_screen *);
! 91: void pxa2x0_lcd_stop_dma(bus_space_tag_t, bus_space_handle_t);
! 92:
! 93: /*
! 94: * Setup display geometry parameters.
! 95: */
! 96: void
! 97: pxa2x0_lcd_geometry(bus_space_tag_t iot, bus_space_handle_t ioh,
! 98: const struct lcd_panel_geometry *info)
! 99: {
! 100: int lines;
! 101: uint32_t ccr0;
! 102:
! 103: ccr0 = LCCR0_IMASK;
! 104: if (info->panel_info & LCDPANEL_ACTIVE)
! 105: ccr0 |= LCCR0_PAS; /* active mode */
! 106: if ((info->panel_info & (LCDPANEL_DUAL | LCDPANEL_ACTIVE))
! 107: == LCDPANEL_DUAL)
! 108: ccr0 |= LCCR0_SDS; /* dual panel */
! 109: if (info->panel_info & LCDPANEL_MONOCHROME)
! 110: ccr0 |= LCCR0_CMS;
! 111: /* XXX - Zaurus C3000 */
! 112: ccr0 |= LCCR0_LDDALT |
! 113: LCCR0_OUC |
! 114: LCCR0_CMDIM |
! 115: LCCR0_RDSTM;
! 116:
! 117: bus_space_write_4(iot, ioh, LCDC_LCCR0, ccr0);
! 118:
! 119: bus_space_write_4(iot, ioh, LCDC_LCCR1,
! 120: (info->panel_width - 1)
! 121: | ((info->hsync_pulse_width - 1) << 10)
! 122: | ((info->end_line_wait - 1) << 16)
! 123: | ((info->beg_line_wait - 1) << 24));
! 124:
! 125: if (info->panel_info & LCDPANEL_DUAL)
! 126: lines = info->panel_height / 2 + info->extra_lines;
! 127: else
! 128: lines = info->panel_height + info->extra_lines;
! 129:
! 130: bus_space_write_4(iot, ioh, LCDC_LCCR2,
! 131: (lines - 1)
! 132: | (info->vsync_pulse_width << 10)
! 133: | (info->end_frame_wait << 16)
! 134: | (info->beg_frame_wait << 24));
! 135:
! 136: bus_space_write_4(iot, ioh, LCDC_LCCR3,
! 137: (info->pixel_clock_div << 0)
! 138: | (info->ac_bias << 8)
! 139: | ((info->panel_info &
! 140: (LCDPANEL_VSP | LCDPANEL_HSP | LCDPANEL_PCP | LCDPANEL_OEP))
! 141: << 20)
! 142: | (4 << 24) /* 16bpp */
! 143: | ((info->panel_info & LCDPANEL_DPC) ? (1 << 27) : 0)
! 144: );
! 145: }
! 146:
! 147: /*
! 148: * Initialize the LCD controller.
! 149: */
! 150: void
! 151: pxa2x0_lcd_initialize(bus_space_tag_t iot, bus_space_handle_t ioh,
! 152: const struct lcd_panel_geometry *geom, void (*clkman)(u_int, int))
! 153: {
! 154: int nldd;
! 155: u_int32_t lccr0, lscr;
! 156:
! 157: /* Check if LCD is enabled before programming, it should not
! 158: * be enabled while it is being reprogrammed, therefore disable
! 159: * it first.
! 160: */
! 161: lccr0 = bus_space_read_4(iot, ioh, LCDC_LCCR0);
! 162: if (lccr0 & LCCR0_ENB) {
! 163: lccr0 |= LCCR0_LDM;
! 164: bus_space_write_4(iot, ioh, LCDC_LCCR0, lccr0);
! 165: lccr0 = bus_space_read_4(iot, ioh, LCDC_LCCR0); /* paranoia */
! 166: lccr0 |= LCCR0_DIS;
! 167: bus_space_write_4(iot, ioh, LCDC_LCCR0, lccr0);
! 168: do {
! 169: lscr = bus_space_read_4(iot, ioh, LCDC_LCSR);
! 170: } while (!(lscr & LCSR_LDD));
! 171: }
! 172:
! 173: /* enable clock */
! 174: (*clkman)(CKEN_LCD, 1);
! 175:
! 176: bus_space_write_4(iot, ioh, LCDC_LCCR0, LCCR0_IMASK);
! 177:
! 178: /*
! 179: * setup GP[77:58] for LCD
! 180: */
! 181: /* Always use [FLP]CLK, ACBIAS */
! 182: pxa2x0_gpio_set_function(74, GPIO_ALT_FN_2_OUT);
! 183: pxa2x0_gpio_set_function(75, GPIO_ALT_FN_2_OUT);
! 184: pxa2x0_gpio_set_function(76, GPIO_ALT_FN_2_OUT);
! 185: pxa2x0_gpio_set_function(77, GPIO_ALT_FN_2_OUT);
! 186:
! 187: if ((geom->panel_info & LCDPANEL_ACTIVE) ||
! 188: ((geom->panel_info & (LCDPANEL_MONOCHROME|LCDPANEL_DUAL)) ==
! 189: LCDPANEL_DUAL)) {
! 190: /* active and color dual panel need L_DD[15:0] */
! 191: nldd = 16;
! 192: } else if ((geom->panel_info & LCDPANEL_DUAL) ||
! 193: !(geom->panel_info & LCDPANEL_MONOCHROME)) {
! 194: /* dual or color need L_DD[7:0] */
! 195: nldd = 8;
! 196: } else {
! 197: /* Otherwise just L_DD[3:0] */
! 198: nldd = 4;
! 199: }
! 200:
! 201: while (nldd--)
! 202: pxa2x0_gpio_set_function(58 + nldd, GPIO_ALT_FN_2_OUT);
! 203:
! 204: pxa2x0_lcd_geometry(iot, ioh, geom);
! 205: }
! 206:
! 207: /*
! 208: * Common driver attachment code.
! 209: */
! 210: void
! 211: pxa2x0_lcd_attach_sub(struct pxa2x0_lcd_softc *sc,
! 212: struct pxaip_attach_args *pxa, struct pxa2x0_wsscreen_descr *descr,
! 213: const struct lcd_panel_geometry *geom, int console)
! 214: {
! 215: bus_space_tag_t iot;
! 216: bus_space_handle_t ioh;
! 217: int error;
! 218:
! 219: sc->n_screens = 0;
! 220: LIST_INIT(&sc->screens);
! 221:
! 222: /* map controller registers if not console */
! 223: if (console != 0) {
! 224: iot = pxa2x0_lcd_console.iot;
! 225: ioh = pxa2x0_lcd_console.ioh;
! 226: } else {
! 227: iot = pxa->pxa_iot;
! 228: error = bus_space_map(iot, PXA2X0_LCDC_BASE, PXA2X0_LCDC_SIZE,
! 229: 0, &ioh);
! 230: if (error) {
! 231: printf(": failed to map registers %d", error);
! 232: return;
! 233: }
! 234: }
! 235:
! 236: sc->iot = iot;
! 237: sc->ioh = ioh;
! 238: sc->dma_tag = &pxa2x0_bus_dma_tag;
! 239:
! 240: sc->ih = pxa2x0_intr_establish(17, IPL_BIO, lcdintr, sc,
! 241: sc->dev.dv_xname);
! 242: if (sc->ih == NULL)
! 243: printf("%s: unable to establish interrupt at irq %d",
! 244: sc->dev.dv_xname, 17);
! 245:
! 246: sc->geometry = geom;
! 247:
! 248: if (console != 0) {
! 249: /* complete console attachment */
! 250: pxa2x0_lcd_setup_console(sc, descr);
! 251: } else {
! 252: struct rasops_info dummy;
! 253:
! 254: pxa2x0_lcd_initialize(iot, ioh, geom, pxa2x0_clkman_config);
! 255:
! 256: /*
! 257: * Initialize a dummy rasops_info to compute fontsize and
! 258: * the screen size in chars.
! 259: */
! 260: bzero(&dummy, sizeof(dummy));
! 261: pxa2x0_lcd_setup_rasops(&dummy, descr, geom);
! 262: }
! 263: }
! 264:
! 265: /*
! 266: * Interrupt handler.
! 267: */
! 268: int
! 269: lcdintr(void *arg)
! 270: {
! 271: struct pxa2x0_lcd_softc *sc = arg;
! 272: bus_space_tag_t iot = sc->iot;
! 273: bus_space_handle_t ioh = sc->ioh;
! 274:
! 275: static uint32_t status;
! 276:
! 277: status = bus_space_read_4(iot, ioh, LCDC_LCSR);
! 278: /* Clear sticky status bits */
! 279: bus_space_write_4(iot, ioh, LCDC_LCSR, status);
! 280:
! 281: return 1;
! 282: }
! 283:
! 284: /*
! 285: * Enable DMA to cause the display to be refreshed periodically.
! 286: * This brings the screen to life...
! 287: */
! 288: void
! 289: pxa2x0_lcd_start_dma(bus_space_tag_t iot, bus_space_handle_t ioh,
! 290: struct pxa2x0_lcd_screen *scr)
! 291: {
! 292: uint32_t tmp;
! 293: int val, save;
! 294:
! 295: save = disable_interrupts(I32_bit);
! 296:
! 297: switch (scr->depth) {
! 298: case 1: val = 0; break;
! 299: case 2: val = 1; break;
! 300: case 4: val = 2; break;
! 301: case 8: val = 3; break;
! 302: case 16:
! 303: /* FALLTHROUGH */
! 304: default:
! 305: val = 4; break;
! 306: }
! 307:
! 308: tmp = bus_space_read_4(iot, ioh, LCDC_LCCR3);
! 309: bus_space_write_4(iot, ioh, LCDC_LCCR3,
! 310: (tmp & ~LCCR3_BPP) | (val << LCCR3_BPP_SHIFT));
! 311:
! 312: bus_space_write_4(iot, ioh, LCDC_FDADR0,
! 313: scr->depth == 16 ? scr->dma_desc_pa :
! 314: scr->dma_desc_pa + 2 * sizeof (struct lcd_dma_descriptor));
! 315: bus_space_write_4(iot, ioh, LCDC_FDADR1,
! 316: scr->dma_desc_pa + 1 * sizeof (struct lcd_dma_descriptor));
! 317:
! 318: /* clear status */
! 319: bus_space_write_4(iot, ioh, LCDC_LCSR, 0);
! 320:
! 321: delay(1000); /* ??? */
! 322:
! 323: /* Enable LCDC */
! 324: tmp = bus_space_read_4(iot, ioh, LCDC_LCCR0);
! 325: /*tmp &= ~LCCR0_SFM;*/
! 326: bus_space_write_4(iot, ioh, LCDC_LCCR0, tmp | LCCR0_ENB);
! 327:
! 328: restore_interrupts(save);
! 329: }
! 330:
! 331: /*
! 332: * Disable screen refresh.
! 333: */
! 334: void
! 335: pxa2x0_lcd_stop_dma(bus_space_tag_t iot, bus_space_handle_t ioh)
! 336: {
! 337:
! 338: /* Stop LCD DMA after current frame */
! 339: bus_space_write_4(iot, ioh, LCDC_LCCR0,
! 340: LCCR0_DIS |
! 341: bus_space_read_4(iot, ioh, LCDC_LCCR0));
! 342:
! 343: /* wait for disabling done.
! 344: XXX: use interrupt. */
! 345: while (LCCR0_ENB &
! 346: bus_space_read_4(iot, ioh, LCDC_LCCR0))
! 347: ;
! 348:
! 349: bus_space_write_4(iot, ioh, LCDC_LCCR0,
! 350: ~LCCR0_DIS &
! 351: bus_space_read_4(iot, ioh, LCDC_LCCR0));
! 352: }
! 353:
! 354: #define _rgb(r,g,b) (((r)<<11) | ((g)<<5) | b)
! 355: #define rgb(r,g,b) _rgb((r)>>1,g,(b)>>1)
! 356:
! 357: #define L 0x1f /* low intensity */
! 358: #define H 0x3f /* high intensity */
! 359:
! 360: static uint16_t basic_color_map[] = {
! 361: rgb( 0, 0, 0), /* black */
! 362: rgb( L, 0, 0), /* red */
! 363: rgb( 0, L, 0), /* green */
! 364: rgb( L, L, 0), /* brown */
! 365: rgb( 0, 0, L), /* blue */
! 366: rgb( L, 0, L), /* magenta */
! 367: rgb( 0, L, L), /* cyan */
! 368: rgb( 0x31,0x31,0x31), /* white */
! 369:
! 370: rgb( L, L, L), /* black */
! 371: rgb( H, 0, 0), /* red */
! 372: rgb( 0, H, 0), /* green */
! 373: rgb( H, H, 0), /* brown */
! 374: rgb( 0, 0, H), /* blue */
! 375: rgb( H, 0, H), /* magenta */
! 376: rgb( 0, H, H), /* cyan */
! 377: rgb( H, H, H)
! 378: };
! 379:
! 380: #undef H
! 381: #undef L
! 382:
! 383: static void
! 384: init_palette(uint16_t *buf, int depth)
! 385: {
! 386: int i;
! 387:
! 388: /* convert RGB332 to RGB565 */
! 389: switch (depth) {
! 390: case 8:
! 391: case 4:
! 392: #if 0
! 393: for (i = 0; i <= 255; ++i) {
! 394: buf[i] = ((9 * ((i >> 5) & 0x07)) << 11) |
! 395: ((9 * ((i >> 2) & 0x07)) << 5) |
! 396: ((21 * (i & 0x03)) / 2);
! 397: }
! 398: #else
! 399: memcpy(buf, basic_color_map, sizeof basic_color_map);
! 400: for (i = 16; i < (1 << depth); ++i)
! 401: buf[i] = 0xffff;
! 402: #endif
! 403: break;
! 404: case 16:
! 405: /* palette is not needed */
! 406: break;
! 407: default:
! 408: /* other depths are not supported */
! 409: break;
! 410: }
! 411: }
! 412:
! 413: /*
! 414: * Create and initialize a new screen buffer.
! 415: */
! 416: int
! 417: pxa2x0_lcd_new_screen(struct pxa2x0_lcd_softc *sc,
! 418: struct pxa2x0_lcd_screen *scr, int depth)
! 419: {
! 420: bus_space_tag_t iot;
! 421: bus_space_handle_t ioh;
! 422: bus_dma_tag_t dma_tag;
! 423: const struct lcd_panel_geometry *geometry;
! 424: int width, height;
! 425: bus_size_t size;
! 426: int error, palette_size;
! 427: int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
! 428: struct lcd_dma_descriptor *desc;
! 429: paddr_t buf_pa, desc_pa;
! 430:
! 431: if (sc != NULL) {
! 432: iot = sc->iot;
! 433: ioh = sc->ioh;
! 434: dma_tag = sc->dma_tag;
! 435: geometry = sc->geometry;
! 436: } else {
! 437: /* We are creating the console screen. */
! 438: iot = pxa2x0_lcd_console.iot;
! 439: ioh = pxa2x0_lcd_console.ioh;
! 440: dma_tag = pxa2x0_lcd_console.dma_tag;
! 441: geometry = pxa2x0_lcd_console.geometry;
! 442: }
! 443:
! 444: width = geometry->panel_width;
! 445: height = geometry->panel_height;
! 446: palette_size = 0;
! 447:
! 448: switch (depth) {
! 449: case 1:
! 450: case 2:
! 451: case 4:
! 452: case 8:
! 453: palette_size = (1 << depth) * sizeof (uint16_t);
! 454: /* FALLTHROUGH */
! 455: case 16:
! 456: size = roundup(width, 4) * depth / 8 * height;
! 457: break;
! 458: default:
! 459: printf("%s: Unknown depth (%d)\n",
! 460: sc != NULL ? sc->dev.dv_xname : "console", depth);
! 461: return (EINVAL);
! 462: }
! 463:
! 464: bzero(scr, sizeof *scr);
! 465:
! 466: scr->nsegs = 0;
! 467: scr->depth = depth;
! 468: scr->buf_size = size;
! 469: scr->buf_va = NULL;
! 470: size = roundup(size, 16) + 3 * sizeof (struct lcd_dma_descriptor)
! 471: + palette_size;
! 472:
! 473: error = bus_dmamem_alloc(dma_tag, size, 16, 0,
! 474: scr->segs, 1, &(scr->nsegs), busdma_flag);
! 475: if (error != 0 || scr->nsegs != 1) {
! 476: /* XXX: Actually we can handle nsegs > 1 case by means
! 477: of multiple DMA descriptors for a panel. It would
! 478: make code here a bit hairy */
! 479: if (error == 0)
! 480: error = E2BIG;
! 481: goto bad;
! 482: }
! 483:
! 484: error = bus_dmamem_map(dma_tag, scr->segs, scr->nsegs,
! 485: size, (caddr_t *)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT);
! 486: if (error != 0)
! 487: goto bad;
! 488:
! 489: memset(scr->buf_va, 0, scr->buf_size);
! 490:
! 491: /* map memory for DMA */
! 492: if (bus_dmamap_create(dma_tag, 1024 * 1024 * 2, 1,
! 493: 1024 * 1024 * 2, 0, busdma_flag, &scr->dma))
! 494: goto bad;
! 495: error = bus_dmamap_load(dma_tag, scr->dma,
! 496: scr->buf_va, size, NULL, busdma_flag);
! 497: if (error != 0) {
! 498: goto bad;
! 499: }
! 500:
! 501: buf_pa = scr->segs[0].ds_addr;
! 502: desc_pa = buf_pa + roundup(size, PAGE_SIZE) - 3 * sizeof *desc;
! 503:
! 504: /* make descriptors at the top of mapped memory */
! 505: desc = (struct lcd_dma_descriptor *)
! 506: ((caddr_t)(scr->buf_va) + roundup(size, PAGE_SIZE) -
! 507: 3 * sizeof *desc);
! 508:
! 509: desc[0].fdadr = desc_pa;
! 510: desc[0].fsadr = buf_pa;
! 511: desc[0].ldcmd = scr->buf_size;
! 512:
! 513: if (palette_size) {
! 514: init_palette((uint16_t *)((char *)desc - palette_size), depth);
! 515:
! 516: desc[2].fdadr = desc_pa; /* chain to panel 0 */
! 517: desc[2].fsadr = desc_pa - palette_size;
! 518: desc[2].ldcmd = palette_size | LDCMD_PAL;
! 519: }
! 520:
! 521: if (geometry->panel_info & LCDPANEL_DUAL) {
! 522: /* Dual panel */
! 523: desc[1].fdadr = desc_pa + sizeof *desc;
! 524: desc[1].fsadr = buf_pa + scr->buf_size / 2;
! 525: desc[0].ldcmd = desc[1].ldcmd = scr->buf_size / 2;
! 526:
! 527: }
! 528:
! 529: #if 0
! 530: desc[0].ldcmd |= LDCMD_SOFINT;
! 531: desc[1].ldcmd |= LDCMD_SOFINT;
! 532: #endif
! 533:
! 534: scr->dma_desc = desc;
! 535: scr->dma_desc_pa = desc_pa;
! 536: scr->map_size = size; /* used when unmap this. */
! 537:
! 538: if (sc != NULL) {
! 539: LIST_INSERT_HEAD(&(sc->screens), scr, link);
! 540: sc->n_screens++;
! 541: }
! 542:
! 543: return (0);
! 544:
! 545: bad:
! 546: if (scr->buf_va)
! 547: bus_dmamem_unmap(dma_tag, scr->buf_va, size);
! 548: if (scr->nsegs)
! 549: bus_dmamem_free(dma_tag, scr->segs, scr->nsegs);
! 550: return (error);
! 551: }
! 552:
! 553: /*
! 554: * Initialize rasops for a screen, as well as struct wsscreen_descr if this
! 555: * is the first screen creation.
! 556: */
! 557: void
! 558: pxa2x0_lcd_setup_rasops(struct rasops_info *rinfo,
! 559: struct pxa2x0_wsscreen_descr *descr,
! 560: const struct lcd_panel_geometry *geom)
! 561: {
! 562:
! 563: rinfo->ri_flg = descr->flags;
! 564: rinfo->ri_depth = descr->depth;
! 565: rinfo->ri_width = geom->panel_width;
! 566: rinfo->ri_height = geom->panel_height;
! 567: rinfo->ri_stride = rinfo->ri_width * rinfo->ri_depth / 8;
! 568: #ifdef notyet
! 569: rinfo->ri_wsfcookie = -1; /* XXX */
! 570: #endif
! 571:
! 572: /* swap B and R */
! 573: if (descr->depth == 16) {
! 574: rinfo->ri_rnum = 5;
! 575: rinfo->ri_rpos = 11;
! 576: rinfo->ri_gnum = 6;
! 577: rinfo->ri_gpos = 5;
! 578: rinfo->ri_bnum = 5;
! 579: rinfo->ri_bpos = 0;
! 580: }
! 581:
! 582: if (descr->c.nrows == 0) {
! 583: /* get rasops to compute screen size the first time */
! 584: rasops_init(rinfo, 100, 100);
! 585: } else
! 586: #ifndef __zaurus__
! 587: rasops_init(rinfo, descr->c.nrows, descr->c.ncols);
! 588: #else
! 589: /* XXX swap rows/cols for second call because of rotation */
! 590: rasops_init(rinfo, descr->c.ncols, descr->c.nrows);
! 591: #endif
! 592:
! 593: descr->c.nrows = rinfo->ri_rows;
! 594: descr->c.ncols = rinfo->ri_cols;
! 595: descr->c.capabilities = rinfo->ri_caps;
! 596: descr->c.textops = &rinfo->ri_ops;
! 597: }
! 598:
! 599: /*
! 600: * Early console attachment.
! 601: * This initializes the LCD, then creates and displays a screen buffer.
! 602: * This screen will be accounted for in the softc when the lcd device attaches.
! 603: */
! 604: int
! 605: pxa2x0_lcd_cnattach(struct pxa2x0_wsscreen_descr *descr,
! 606: const struct lcd_panel_geometry *geom, void (*clkman)(u_int, int))
! 607: {
! 608: struct rasops_info *ri;
! 609: long defattr;
! 610: int error;
! 611:
! 612: /* map controller registers */
! 613: pxa2x0_lcd_console.iot = &pxa2x0_bs_tag;
! 614: error = bus_space_map(pxa2x0_lcd_console.iot,
! 615: PXA2X0_LCDC_BASE, PXA2X0_LCDC_SIZE, 0, &pxa2x0_lcd_console.ioh);
! 616: if (error != 0)
! 617: return (error);
! 618:
! 619: pxa2x0_lcd_console.dma_tag = &pxa2x0_bus_dma_tag;
! 620: pxa2x0_lcd_console.geometry = geom;
! 621:
! 622: pxa2x0_lcd_initialize(pxa2x0_lcd_console.iot, pxa2x0_lcd_console.ioh,
! 623: pxa2x0_lcd_console.geometry, clkman);
! 624:
! 625: error = pxa2x0_lcd_new_screen(NULL, &pxa2x0_lcd_console.scr,
! 626: descr->depth);
! 627: if (error != 0)
! 628: return (error);
! 629:
! 630: ri = &pxa2x0_lcd_console.scr.rinfo;
! 631: ri->ri_hw = (void *)&pxa2x0_lcd_console.scr;
! 632: ri->ri_bits = pxa2x0_lcd_console.scr.buf_va;
! 633: pxa2x0_lcd_setup_rasops(ri, descr, pxa2x0_lcd_console.geometry);
! 634:
! 635: /* assumes 16 bpp */
! 636: ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
! 637:
! 638: pxa2x0_lcd_start_dma(pxa2x0_lcd_console.iot, pxa2x0_lcd_console.ioh,
! 639: &pxa2x0_lcd_console.scr);
! 640:
! 641: wsdisplay_cnattach(&descr->c, ri, ri->ri_ccol, ri->ri_crow, defattr);
! 642:
! 643: return (0);
! 644: }
! 645:
! 646: /*
! 647: * Do the necessary accounting to bring the console variables in the softc.
! 648: */
! 649: void
! 650: pxa2x0_lcd_setup_console(struct pxa2x0_lcd_softc *sc,
! 651: const struct pxa2x0_wsscreen_descr *descr)
! 652: {
! 653: struct pxa2x0_lcd_screen *scr = &pxa2x0_lcd_console.scr;
! 654:
! 655: /*
! 656: * Register the console screen as if it had been created
! 657: * when the lcd device attached.
! 658: */
! 659: LIST_INSERT_HEAD(&(sc->screens), &pxa2x0_lcd_console.scr, link);
! 660: sc->n_screens++;
! 661: sc->active = scr;
! 662: }
! 663:
! 664: /*
! 665: * wsdisplay accessops
! 666: */
! 667:
! 668: int
! 669: pxa2x0_lcd_show_screen(void *v, void *cookie, int waitok,
! 670: void (*cb)(void *, int, int), void *cbarg)
! 671: {
! 672: struct pxa2x0_lcd_softc *sc = v;
! 673: struct rasops_info *ri = cookie;
! 674: struct pxa2x0_lcd_screen *scr = ri->ri_hw, *old;
! 675:
! 676: old = sc->active;
! 677: if (old == scr)
! 678: return 0;
! 679:
! 680: if (old)
! 681: pxa2x0_lcd_stop_dma(sc->iot, sc->ioh);
! 682:
! 683: pxa2x0_lcd_start_dma(sc->iot, sc->ioh, scr);
! 684:
! 685: sc->active = scr;
! 686: return 0;
! 687: }
! 688:
! 689: int
! 690: pxa2x0_lcd_alloc_screen(void *v, const struct wsscreen_descr *_type,
! 691: void **cookiep, int *curxp, int *curyp, long *attrp)
! 692: {
! 693: struct pxa2x0_lcd_softc *sc = v;
! 694: struct pxa2x0_lcd_screen *scr;
! 695: struct rasops_info *ri;
! 696: struct pxa2x0_wsscreen_descr *type =
! 697: (struct pxa2x0_wsscreen_descr *)_type;
! 698: int error;
! 699:
! 700: scr = malloc(sizeof *scr, M_DEVBUF, (cold ? M_NOWAIT : M_WAITOK));
! 701: if (scr == NULL)
! 702: return (ENOMEM);
! 703:
! 704: error = pxa2x0_lcd_new_screen(sc, scr, type->depth);
! 705: if (error != 0) {
! 706: free(scr, M_DEVBUF);
! 707: return (error);
! 708: }
! 709:
! 710: /*
! 711: * initialize raster operation for this screen.
! 712: */
! 713: ri = &scr->rinfo;
! 714: ri->ri_hw = (void *)scr;
! 715: ri->ri_bits = scr->buf_va;
! 716: pxa2x0_lcd_setup_rasops(ri, type, sc->geometry);
! 717:
! 718: /* assumes 16 bpp */
! 719: ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
! 720:
! 721: *cookiep = ri;
! 722: *curxp = 0;
! 723: *curyp = 0;
! 724:
! 725: return 0;
! 726: }
! 727:
! 728: void
! 729: pxa2x0_lcd_free_screen(void *v, void *cookie)
! 730: {
! 731: struct pxa2x0_lcd_softc *sc = v;
! 732: struct rasops_info *ri = cookie;
! 733: struct pxa2x0_lcd_screen *scr = ri->ri_hw;
! 734:
! 735: LIST_REMOVE(scr, link);
! 736: sc->n_screens--;
! 737: if (scr == sc->active) {
! 738: /* at first, we need to stop LCD DMA */
! 739: sc->active = NULL;
! 740:
! 741: #ifdef DEBUG
! 742: printf("lcd_free on active screen\n");
! 743: #endif
! 744:
! 745: pxa2x0_lcd_stop_dma(sc->iot, sc->ioh);
! 746: }
! 747:
! 748: if (scr->buf_va)
! 749: bus_dmamem_unmap(sc->dma_tag, scr->buf_va, scr->map_size);
! 750:
! 751: if (scr->nsegs > 0)
! 752: bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs);
! 753:
! 754: free(scr, M_DEVBUF);
! 755: }
! 756:
! 757: int
! 758: pxa2x0_lcd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
! 759: {
! 760: struct pxa2x0_lcd_softc *sc = v;
! 761: struct wsdisplay_fbinfo *wsdisp_info;
! 762: struct pxa2x0_lcd_screen *scr = sc->active; /* ??? */
! 763:
! 764: switch (cmd) {
! 765: case WSDISPLAYIO_GTYPE:
! 766: *(u_int *)data = WSDISPLAY_TYPE_PXALCD; /* XXX */
! 767: break;
! 768:
! 769: case WSDISPLAYIO_GINFO:
! 770: wsdisp_info = (struct wsdisplay_fbinfo *)data;
! 771:
! 772: wsdisp_info->height = sc->geometry->panel_height;
! 773: wsdisp_info->width = sc->geometry->panel_width;
! 774: wsdisp_info->depth = 16; /* XXX */
! 775: wsdisp_info->cmsize = 0;
! 776: break;
! 777:
! 778: case WSDISPLAYIO_GETSUPPORTEDDEPTH:
! 779: *(u_int *)data = WSDISPLAYIO_DEPTH_16;
! 780: break;
! 781:
! 782: case WSDISPLAYIO_GETCMAP:
! 783: case WSDISPLAYIO_PUTCMAP:
! 784: return EINVAL; /* XXX Colormap */
! 785:
! 786: case WSDISPLAYIO_SVIDEO:
! 787: case WSDISPLAYIO_GVIDEO:
! 788: break;
! 789:
! 790: case WSDISPLAYIO_GCURPOS:
! 791: case WSDISPLAYIO_SCURPOS:
! 792: case WSDISPLAYIO_GCURMAX:
! 793: case WSDISPLAYIO_GCURSOR:
! 794: case WSDISPLAYIO_SCURSOR:
! 795: default:
! 796: return -1; /* not implemented */
! 797:
! 798: case WSDISPLAYIO_LINEBYTES:
! 799: *(u_int *)data = scr->rinfo.ri_stride;
! 800: break;
! 801: }
! 802: return (0);
! 803: }
! 804:
! 805: paddr_t
! 806: pxa2x0_lcd_mmap(void *v, off_t offset, int prot)
! 807: {
! 808: struct pxa2x0_lcd_softc *sc = v;
! 809: struct pxa2x0_lcd_screen *screen = sc->active; /* ??? */
! 810:
! 811: if ((offset & PAGE_MASK) != 0)
! 812: return (-1);
! 813:
! 814: if (screen == NULL)
! 815: return (-1);
! 816:
! 817: if (offset < 0 ||
! 818: offset >= screen->rinfo.ri_stride * screen->rinfo.ri_height)
! 819: return (-1);
! 820:
! 821: return (bus_dmamem_mmap(sc->dma_tag, screen->segs, screen->nsegs,
! 822: offset, prot, BUS_DMA_WAITOK | BUS_DMA_COHERENT));
! 823: }
! 824:
! 825: void
! 826: pxa2x0_lcd_suspend(struct pxa2x0_lcd_softc *sc)
! 827: {
! 828:
! 829: if (sc->active != NULL) {
! 830: pxa2x0_lcd_stop_dma(sc->iot, sc->ioh);
! 831:
! 832: pxa2x0_clkman_config(CKEN_LCD, 0);
! 833: }
! 834: }
! 835:
! 836: void
! 837: pxa2x0_lcd_resume(struct pxa2x0_lcd_softc *sc)
! 838: {
! 839:
! 840: if (sc->active != NULL) {
! 841: pxa2x0_lcd_initialize(sc->iot, sc->ioh, sc->geometry,
! 842: pxa2x0_clkman_config);
! 843: pxa2x0_lcd_start_dma(sc->iot, sc->ioh, sc->active);
! 844: }
! 845: }
! 846:
! 847: void
! 848: pxa2x0_lcd_power(int why, void *v)
! 849: {
! 850: struct pxa2x0_lcd_softc *sc = v;
! 851:
! 852: switch (why) {
! 853: case PWR_SUSPEND:
! 854: case PWR_STANDBY:
! 855: pxa2x0_lcd_suspend(sc);
! 856: break;
! 857:
! 858: case PWR_RESUME:
! 859: pxa2x0_lcd_resume(sc);
! 860: break;
! 861: }
! 862: }
CVSweb