Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/s3c2xx0 Support S3C24X0's on-chip LCD controller.



details:   https://anonhg.NetBSD.org/src/rev/7457d0b410b1
branches:  trunk
changeset: 558512:7457d0b410b1
user:      bsh <bsh%NetBSD.org@localhost>
date:      Sat Feb 14 07:12:50 2004 +0000

description:
Support S3C24X0's on-chip LCD controller.

lcd driver can be configured with or without wsdisplay.
With wsdisplay, it supports text mode using rasops in 8bpp or 16bpp.
Without it, users only can mmap(2) the framebuffer.

XXX: 1-, 2-, 4-, or 24- bpp mode is not supported yet.
XXX: S3C24x0's LCD controller can have virtual screen which is bigger
     than actual LCD panel. Our wsdisplay framework doesn't have
     features to utilize it.

diffstat:

 sys/arch/arm/s3c2xx0/s3c24x0_lcd.c |  774 +++++++++++++++++++++++++++++++++++++
 sys/arch/arm/s3c2xx0/s3c24x0_lcd.h |  123 +++++
 2 files changed, 897 insertions(+), 0 deletions(-)

diffs (truncated from 905 to 300 lines):

diff -r bda76fdf9491 -r 7457d0b410b1 sys/arch/arm/s3c2xx0/s3c24x0_lcd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/s3c2xx0/s3c24x0_lcd.c        Sat Feb 14 07:12:50 2004 +0000
@@ -0,0 +1,774 @@
+/* $NetBSD: s3c24x0_lcd.c,v 1.1 2004/02/14 07:12:50 bsh Exp $ */
+
+/*
+ * Copyright (c) 2004  Genetec Corporation.  All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Genetec Corporation may not be used to endorse or 
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Support S3C24[10]0's integrated LCD controller.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: s3c24x0_lcd.c,v 1.1 2004/02/14 07:12:50 bsh Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>                        /* for cold */
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/cons.h> 
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h> 
+#include <dev/wscons/wscons_callbacks.h>
+#include <dev/rasops/rasops.h>
+#include <dev/wsfont/wsfont.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <arm/cpufunc.h>
+
+#include <arm/s3c2xx0/s3c24x0var.h>
+#include <arm/s3c2xx0/s3c24x0reg.h>
+#include <arm/s3c2xx0/s3c24x0_lcd.h>
+
+#include "wsdisplay.h"
+
+int lcdintr(void *);
+static void init_palette(struct s3c24x0_lcd_softc *,
+    struct s3c24x0_lcd_screen *);
+
+#ifdef LCD_DEBUG
+static void
+dump_lcdcon(const char *title, bus_space_tag_t iot, bus_space_handle_t ioh)
+{
+       int i;
+
+       printf("%s\n", title);
+       for(i=LCDC_LCDCON1; i <= LCDC_LCDSADDR3; i+=4) {
+               if (i%16 == 0)
+                       printf("\n%03x: ", i);
+               printf("%08x ", bus_space_read_4(iot, ioh, i));
+       }
+
+       printf("\n");
+}
+
+void draw_test_pattern(struct s3c24x0_lcd_softc *,
+           struct s3c24x0_lcd_screen *scr);
+
+#endif
+
+void
+s3c24x0_set_lcd_panel_info(struct s3c24x0_lcd_softc *sc,
+    const struct s3c24x0_lcd_panel_info *info)
+{
+       bus_space_tag_t iot = sc->iot;
+       bus_space_handle_t ioh = sc->ioh;
+       uint32_t reg;
+       int clkval;
+       int tft = s3c24x0_lcd_panel_tft(info);
+       int hclk = s3c2xx0_softc->sc_hclk;
+
+       sc->panel_info = info;
+
+       /* Set LCDCON1. BPPMODE and ENVID are set later */
+       if (tft)
+               clkval = (hclk / info->pixel_clock  / 2) - 1;
+       else {
+               /* STN display */
+               clkval = max(2, hclk / info->pixel_clock / 2);
+       }
+
+       reg =  (info->lcdcon1 & ~LCDCON1_CLKVAL_MASK) |
+               (clkval << LCDCON1_CLKVAL_SHIFT);
+       reg &= ~LCDCON1_ENVID;
+       bus_space_write_4(iot, ioh, LCDC_LCDCON1, reg);
+
+#if 0
+       printf("hclk=%d pixel clock=%d, clkval = %x lcdcon1=%x\n",
+           hclk, info->pixel_clock, clkval, reg);
+#endif
+
+       bus_space_write_4(iot, ioh, LCDC_LCDCON2, info->lcdcon2);
+       bus_space_write_4(iot, ioh, LCDC_LCDCON3, info->lcdcon3);
+       bus_space_write_4(iot, ioh, LCDC_LCDCON4, info->lcdcon4);
+       bus_space_write_4(iot, ioh, LCDC_LCDCON5, info->lcdcon5);
+       bus_space_write_4(iot, ioh, LCDC_LPCSEL, info->lpcsel);
+}
+
+void
+s3c24x0_lcd_attach_sub(struct s3c24x0_lcd_softc *sc, 
+    struct s3c2xx0_attach_args *sa,
+    const struct s3c24x0_lcd_panel_info *panel_info)
+{
+       bus_space_tag_t iot = sa->sa_iot;
+       bus_space_handle_t ioh;
+       int error;
+
+       sc->n_screens = 0;
+       LIST_INIT(&sc->screens);
+
+       /* map controller registers */
+       error = bus_space_map(iot, sa->sa_addr, S3C24X0_LCDC_SIZE, 0, &ioh);
+       if (error) {
+               printf(": failed to map registers %d", error);
+               return;
+       }
+
+       sc->iot = iot;
+       sc->ioh = ioh;
+       sc->dma_tag = sa->sa_dmat;
+
+#ifdef notyet
+       sc->ih = s3c24x0_intr_establish(sa->sa_intr, IPL_BIO, lcdintr, sc);
+       if (sc->ih == NULL)
+               printf("%s: unable to establish interrupt at irq %d",
+                   sc->dev.dv_xname, sa->sa_intr);
+#endif
+
+       /* mask LCD interrupts */
+       bus_space_write_4(iot, ioh, LCDC_LCDINTMSK, LCDINT_FICNT|LCDINT_FRSYN);
+
+       /* Initialize controller registers based on panel geometry*/
+       s3c24x0_set_lcd_panel_info(sc, panel_info);
+
+       /* XXX: enable clock to LCD controller */
+}
+
+
+#ifdef notyet
+int
+lcdintr(void *arg)
+{
+       struct s3c24x0_lcd_softc *sc = arg;
+       bus_space_tag_t iot = sc->iot;
+       bus_space_handle_t ioh = sc->ioh;
+
+       static uint32_t status;
+
+       return 1;
+}
+#endif
+
+int
+s3c24x0_lcd_start_dma(struct s3c24x0_lcd_softc *sc,
+    struct s3c24x0_lcd_screen *scr)
+{
+       bus_space_tag_t iot = sc->iot;
+       bus_space_handle_t ioh = sc->ioh;
+       const struct s3c24x0_lcd_panel_info *info = sc->panel_info;
+       int tft = s3c24x0_lcd_panel_tft(info);
+       int dual_panel = 
+           (info->lcdcon1 & LCDCON1_PNRMODE_MASK) == LCDCON1_PNRMODE_DUALSTN4;
+       uint32_t lcdcon1, val;
+       paddr_t pa;
+       int depth = scr->depth;
+       int stride = scr->stride;
+       int panel_height = info->panel_height;
+       int panel_width = info->panel_width;
+       int offsize;
+
+       switch (depth) {
+       case 1: val = LCDCON1_BPPMODE_STN1; break;
+       case 2: val = LCDCON1_BPPMODE_STN2; break;
+       case 4: val = LCDCON1_BPPMODE_STN4; break;
+       case 8: val = LCDCON1_BPPMODE_STN8; break;
+       case 12: 
+               if (tft)
+                       return -1;
+               val = LCDCON1_BPPMODE_STN12;
+               break;
+       case 16:
+               if (!tft)
+                       return -1;      
+               val = LCDCON1_BPPMODE_TFT16;
+               break;
+       case 24:
+               if (!tft)
+                       return -1;
+               val = LCDCON1_BPPMODE_TFT24;
+               break;
+       default:
+               return -1;
+       }
+
+       if (tft)
+               val |= LCDCON1_BPPMODE_TFTX;
+
+       lcdcon1 = bus_space_read_4(iot, ioh, LCDC_LCDCON1);
+       lcdcon1 &= ~(LCDCON1_BPPMODE_MASK|LCDCON1_ENVID);
+       lcdcon1 |= val;
+       bus_space_write_4(iot, ioh, LCDC_LCDCON1, lcdcon1);
+
+       /* Adjust LCDCON3.HOZVAL to meet with restriction */
+       val = roundup(panel_width, 16 / depth);
+       bus_space_write_4(iot, ioh, LCDC_LCDCON3,
+           (info->lcdcon3 & ~LCDCON3_HOZVAL_MASK) |
+           (val - 1) << LCDCON3_HOZVAL_SHIFT);
+
+       pa = scr->segs[0].ds_addr;
+       bus_space_write_4(iot, ioh, LCDC_LCDSADDR1, pa >> 1);
+
+       if (dual_panel) {
+               /* XXX */
+       }
+       else {
+               pa += stride * panel_height;
+               bus_space_write_4(iot, ioh, LCDC_LCDSADDR2, pa >> 1);
+       }
+
+       offsize = stride / sizeof (uint16_t) - (panel_width * depth / 16);
+       bus_space_write_4(iot, ioh, LCDC_LCDSADDR3,
+           (offsize << LCDSADDR3_OFFSIZE_SHIFT) |
+           (panel_width * depth / 16));
+
+       /* set byte- or halfword- swap based on the depth */
+       val = bus_space_read_4(iot, ioh, LCDC_LCDCON5);
+       val &= ~(LCDCON5_BSWP|LCDCON5_HWSWP);
+       switch(depth) {
+       case 2:
+       case 4:
+       case 8:
+               val |= LCDCON5_BSWP;
+               break;
+       case 16:
+               val |= LCDCON5_HWSWP;
+               break;
+       }
+       bus_space_write_4(iot, ioh, LCDC_LCDCON5, val);
+
+
+       init_palette(sc, scr);
+
+#if 0
+       bus_space_write_4(iot, ioh, LCDC_TPAL, TPAL_TPALEN|
+           (0xff<<TPAL_BLUE_SHIFT));
+#endif
+
+       /* Enable LCDC */
+       bus_space_write_4(iot, ioh, LCDC_LCDCON1, lcdcon1 | LCDCON1_ENVID);
+
+       sc->lcd_on = 1;
+
+#ifdef LCD_DEBUG
+       dump_lcdcon(__FUNCTION__, iot, ioh);
+#endif
+
+       return 0;
+}
+
+void
+s3c24x0_lcd_power(struct s3c24x0_lcd_softc *sc, int on)
+{
+       bus_space_tag_t iot = sc->iot;
+       bus_space_handle_t ioh = sc->ioh;
+       uint32_t reg;
+
+       reg = bus_space_read_4(iot, ioh, LCDC_LCDCON5);



Home | Main Index | Thread Index | Old Index