[BACK]Return to pxa2x0_lcd.c CVS log [TXT][DIR] Up to [local] / sys / arch / arm / xscale

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