Source-Changes-HG archive

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

[src/trunk]: src/sys/arch Add support for LVDS output on tcon0. Tested with a...



details:   https://anonhg.NetBSD.org/src/rev/44e6449f20ec
branches:  trunk
changeset: 341652:44e6449f20ec
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Sun Nov 15 21:28:54 2015 +0000

description:
Add support for LVDS output on tcon0. Tested with a full HD LVDS display.
Other LCD interfaces not supported yet, mostly by lack of hardware.
The LVDS output and timings are set from the FEX script.

diffstat:

 sys/arch/arm/allwinner/awin_hdmi.c  |   12 +-
 sys/arch/arm/allwinner/awin_reg.h   |   44 +++-
 sys/arch/arm/allwinner/awin_tcon.c  |  405 ++++++++++++++++++++++++++++++-----
 sys/arch/arm/allwinner/awin_var.h   |    6 +-
 sys/arch/evbarm/awin/awin_machdep.c |   70 ++++-
 5 files changed, 444 insertions(+), 93 deletions(-)

diffs (truncated from 852 to 300 lines):

diff -r 241981f25a0e -r 44e6449f20ec sys/arch/arm/allwinner/awin_hdmi.c
--- a/sys/arch/arm/allwinner/awin_hdmi.c        Sun Nov 15 20:35:33 2015 +0000
+++ b/sys/arch/arm/allwinner/awin_hdmi.c        Sun Nov 15 21:28:54 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_hdmi.c,v 1.17 2015/10/25 20:54:19 bouyer Exp $ */
+/* $NetBSD: awin_hdmi.c,v 1.18 2015/11/15 21:28:54 bouyer Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -30,7 +30,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.17 2015/10/25 20:54:19 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.18 2015/11/15 21:28:54 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -580,13 +580,13 @@
 
        if (mode != NULL) {
                awin_hdmi_video_enable(sc, false);
-               awin_tcon_enable(sc->sc_tcon_unit, false);
+               awin_tcon1_enable(sc->sc_tcon_unit, false);
                delay(20000);
 
-               awin_tcon_set_videomode(sc->sc_tcon_unit, mode);
+               awin_tcon1_set_videomode(sc->sc_tcon_unit, mode);
                awin_hdmi_set_videomode(sc, mode, display_mode);
                awin_hdmi_set_audiomode(sc, mode, display_mode);
-               awin_tcon_enable(sc->sc_tcon_unit, true);
+               awin_tcon1_enable(sc->sc_tcon_unit, true);
                delay(20000);
                awin_hdmi_video_enable(sc, true);
        }
@@ -928,7 +928,7 @@
                awin_hdmi_read_edid(sc);
        } else {
                device_printf(sc->sc_dev, "display disconnected\n");
-               awin_tcon_set_videomode(sc->sc_tcon_unit, NULL);
+               awin_tcon1_set_videomode(sc->sc_tcon_unit, NULL);
        }
 
        sc->sc_connected = con;
diff -r 241981f25a0e -r 44e6449f20ec sys/arch/arm/allwinner/awin_reg.h
--- a/sys/arch/arm/allwinner/awin_reg.h Sun Nov 15 20:35:33 2015 +0000
+++ b/sys/arch/arm/allwinner/awin_reg.h Sun Nov 15 21:28:54 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_reg.h,v 1.83 2015/11/09 10:10:39 bouyer Exp $ */
+/* $NetBSD: awin_reg.h,v 1.84 2015/11/15 21:28:54 bouyer Exp $ */
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -1111,6 +1111,8 @@
 #define AWIN_CLK_DIV_RATIO_N           __BITS(17,16)
 #define AWIN_CLK_DIV_RATIO_M           __BITS(3,0)
 
+#define AWIN_LVDS_CLK_ENABLE           __BIT(0)
+
 #define AWIN_ISS_CLK_SRC_SEL           __BITS(17,16)
 
 #define AWIN_USB_CLK_USBPHY_ENABLE     __BIT(8)
@@ -1161,7 +1163,7 @@
 #define AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3 0
 #define AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7 1
 #define AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3_2X 2
-#define AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7_2X 3
+#define AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7_2X 3 /* for lcd0ch0 this is pll6x2 */
 #define AWIN_LCDx_CH1_SCLK1_GATING     __BIT(15)
 #define AWIN_LCDx_CH1_SCLK1_SRC_SEL    __BIT(11)
 #define AWIN_LCDx_CH1_CLK_DIV_RATIO_M  __BITS(3,0)
@@ -1772,6 +1774,8 @@
 #define AWIN_TCON_GINT0_REG            0x0004
 #define AWIN_TCON_GINT1_REG            0x0008
 #define AWIN_TCON0_FRM_CTL_REG         0x0010
+#define AWIN_TCON0_FRM1_CTL_REG                0x0014
+#define AWIN_TCON0_FRM2_CTL_REG                0x002c
 #define AWIN_TCON0_CTL_REG             0x0040
 #define AWIN_TCON0_DCLK_REG            0x0044
 #define AWIN_TCON0_BASIC0_REG          0x0048
@@ -1806,6 +1810,8 @@
 #define AWIN_TCON_CMAP_EVEN0_REG       0x0198
 #define AWIN_TCON_CMAP_EVEN1_REG       0x019C
 #define AWIN_TCON_MUX_CTL_REG          0x0200 /* only in TCON0 */
+#define AWIN_TCON_LVDS_ANA0            0x220
+#define AWIN_TCON_LVDS_ANA1            0x224
 
 #define AWIN_TCON_GCTL_EN              __BIT(31)
 #define AWIN_TCON_GCTL_GAMMA_EN                __BIT(30)
@@ -1816,13 +1822,33 @@
 #define AWIN_TCON_GINT1_TCON0_LINENO   __BITS(27,16)
 #define AWIN_TCON_GINT1_TCON1_LINENO   __BITS(11,0)
 
-#define AWIN_TCON_CTL_EN               __BIT(31)
-#define AWIN_TCON_CTL_INTERLACE_EN     __BIT(20)
-#define AWIN_TCON_CTL_START_DELAY      __BITS(8,4)
-#define AWIN_TCON_CTL_SRC_SEL          __BITS(1,0)
-#define AWIN_TCON_CTL_SRC_SEL_DE0      0
-#define AWIN_TCON_CTL_SRC_SEL_DE1      1
-#define AWIN_TCON_CTL_SRC_SEL_BLUEDATA 2
+#define AWIN_TCON0_FRM_ENABLE          __BIT(31)
+#define AWIN_TCON0_FRM_R5BITS          __BIT(6)
+#define AWIN_TCON0_FRM_G5BITS          __BIT(5)
+#define AWIN_TCON0_FRM_B5BITS          __BIT(4)
+
+#define AWIN_TCONx_CTL_EN              __BIT(31)
+#define AWIN_TCON0_CTL0_IF             __BITS(25,24)
+#define AWIN_TCON0_CTL0_IF_HV          0
+#define AWIN_TCON0_CTL0_IF_8080                1
+#define AWIN_TCON0_CTL0_IF_TTL         2
+#define AWIN_TCON0_CTL_RG_SWAP         __BIT(23)
+#define AWIN_TCON0_CTL_TSTV            __BIT(22)
+#define AWIN_TCONx_CTL_INTERLACE_EN    __BIT(20)
+#define AWIN_TCONx_CTL_START_DELAY     __BITS(8,4)
+#define AWIN_TCONx_CTL_SRC_SEL         __BITS(1,0)
+#define AWIN_TCONx_CTL_SRC_SEL_DE0     0
+#define AWIN_TCONx_CTL_SRC_SEL_DE1     1
+#define AWIN_TCONx_CTL_SRC_SEL_BLUEDATA        2
+
+#define AWIN_TCON0_DCLK_DIV            __BITS(6,0)
+
+#define AWIN_TCON0_LVDS_IF_EN          __BIT(31)
+#define AWIN_TCON0_LVDS_IF_DUALCHAN    __BIT(30)
+#define AWIN_TCON0_LVDS_IF_DIR_REV     __BIT(28)
+#define AWIN_TCON0_LVDS_IF_MODE_JEIDA  __BIT(27)
+#define AWIN_TCON0_LVDS_IF_18BITS      __BIT(26)
+#define AWIN_TCON0_LVDS_IF_CORR_MODE1  __BIT(23)
 
 #define AWIN_TCON_IO_POL_IO2_INV       __BIT(26)
 #define AWIN_TCON_IO_POL_PVSYNC                __BIT(25)
diff -r 241981f25a0e -r 44e6449f20ec sys/arch/arm/allwinner/awin_tcon.c
--- a/sys/arch/arm/allwinner/awin_tcon.c        Sun Nov 15 20:35:33 2015 +0000
+++ b/sys/arch/arm/allwinner/awin_tcon.c        Sun Nov 15 21:28:54 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_tcon.c,v 1.8 2015/11/03 19:28:28 bouyer Exp $ */
+/* $NetBSD: awin_tcon.c,v 1.9 2015/11/15 21:28:54 bouyer Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 #include "opt_allwinner.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_tcon.c,v 1.8 2015/11/03 19:28:28 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_tcon.c,v 1.9 2015/11/15 21:28:54 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -47,17 +47,37 @@
 
 #define DIVIDE(x,y)     (((x) + ((y) / 2)) / (y))
 
+struct awin_tcon_gpio {
+       const char *value;
+       const char *name;
+};
+
+
 struct awin_tcon_softc {
        device_t sc_dev;
        bus_space_tag_t sc_bst;
        bus_space_handle_t sc_bsh;
+       bus_space_handle_t sc_ch0clk_bsh;
        bus_space_handle_t sc_ch1clk_bsh;
        unsigned int sc_port;
        unsigned int sc_clk_pll;
        unsigned int sc_clk_div;
        bool sc_clk_dbl;
+       unsigned int sc_debe_unit;
+       unsigned int sc_output_type;
+#define OUTPUT_HDMI 0
+#define OUTPUT_LVDS 1
+       const char *sc_lcdpwr_pin_name;
+       struct awin_gpio_pindata sc_lcdpwr_pin;
+       const char *sc_lcdblk_pin_name;
+       struct awin_gpio_pindata sc_lcdblk_pin;
 };
 
+static const struct awin_gpio_pinset awin_lvds0_pinset = 
+       { 'D', AWIN_PIO_PD_LVDS0_FUNC, AWIN_PIO_PD_LVDS0_PINS};
+static const struct awin_gpio_pinset awin_lvds1_pinset = 
+       { 'D', AWIN_PIO_PD_LVDS1_FUNC, AWIN_PIO_PD_LVDS1_PINS};
+
 static bus_space_handle_t tcon_mux_bsh;
 static bool tcon_mux_inited = false;
 
@@ -69,8 +89,8 @@
 static int     awin_tcon_match(device_t, cfdata_t, void *);
 static void    awin_tcon_attach(device_t, device_t, void *);
 
-static void    awin_tcon_set_pll(struct awin_tcon_softc *,
-                                 const struct videomode *);
+static void    awin_tcon_set_pll(struct awin_tcon_softc *, int, int);
+static void    awin_tcon0_set_video(struct awin_tcon_softc *);
 
 static void
 awin_tcon_clear_reset(struct awinio_attach_args * const aio, int unit)
@@ -112,6 +132,8 @@
        struct awin_tcon_softc *sc = device_private(self);
        struct awinio_attach_args * const aio = aux;
        const struct awin_locators * const loc = &aio->aio_loc;
+       prop_dictionary_t cfg = device_properties(self);
+       const char *output;
 
        sc->sc_dev = self;
        sc->sc_bst = aio->aio_core_bst;
@@ -119,6 +141,8 @@
        bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
            loc->loc_offset, loc->loc_size, &sc->sc_bsh);
        bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh,
+           AWIN_LCD0_CH0_CLK_REG + (loc->loc_port * 4), 4, &sc->sc_ch0clk_bsh);
+       bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh,
            AWIN_LCD0_CH1_CLK_REG + (loc->loc_port * 4), 4, &sc->sc_ch1clk_bsh);
        if (!tcon_mux_inited) {
                /* the mux register is only in LCD0 */
@@ -129,6 +153,18 @@
                awin_tcon_clear_reset(aio, 0);
        }
 
+       if (prop_dictionary_get_cstring_nocopy(cfg, "output", &output)) {
+               if (strcmp(output, "hdmi") == 0) {
+                       sc->sc_output_type = OUTPUT_HDMI;
+               } else if (strcmp(output, "lvds") == 0) {
+                       sc->sc_output_type = OUTPUT_LVDS;
+               } else {
+                       panic("tcon: wrong mode %s", output);
+               }
+       } else {
+               sc->sc_output_type = OUTPUT_HDMI; /* default */
+       }
+
        aprint_naive("\n");
        aprint_normal(": LCD/TV timing controller (TCON%d)\n", loc->loc_port);
        switch (sc->sc_port) {
@@ -152,17 +188,25 @@
        TCON_WRITE(sc, AWIN_TCON_GCTL_REG, 0);
        TCON_WRITE(sc, AWIN_TCON_GINT0_REG, 0);
        TCON_WRITE(sc, AWIN_TCON_GINT1_REG,
-           __SHIFTIN(0x20, AWIN_TCON_GINT1_TCON1_LINENO));
+           __SHIFTIN(0x20, AWIN_TCON_GINT1_TCON0_LINENO));
        TCON_WRITE(sc, AWIN_TCON0_DCLK_REG, 0xf0000000);
+       TCON_WRITE(sc, AWIN_TCON0_CTL_REG, 0);
        TCON_WRITE(sc, AWIN_TCON0_IO_TRI_REG, 0xffffffff);
+       TCON_WRITE(sc, AWIN_TCON1_CTL_REG, 0);
        TCON_WRITE(sc, AWIN_TCON1_IO_TRI_REG, 0xffffffff);
+       if (sc->sc_output_type == OUTPUT_LVDS) {
+               awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
+                   AWIN_LVDS_CLK_REG, AWIN_LVDS_CLK_ENABLE, 0);
+               awin_tcon0_set_video(sc);
+       }
 }
 
 static void
-awin_tcon_calc_pll(int f_ref, int f_out, int *pm, int *pn)
+awin_tcon_calc_pll(int f_ref, int f_out, int min_m, int *pm, int *pn)
 {
        int best = 1000000;
-       for (int m = 1; m <= 15; m++) {
+       KASSERT(min_m > 0);
+       for (int m = min_m; m <= 15; m++) {
                for (int n = 9; n <= 127; n++) {
                        int f_cur = (n * f_ref) / m;
                        int diff = f_out - f_cur;
@@ -176,13 +220,13 @@
 }
 
 static void
-awin_tcon_set_pll(struct awin_tcon_softc *sc, const struct videomode *mode)
+awin_tcon_set_pll(struct awin_tcon_softc *sc, int dclk, int min_div)
 {
        int n = 0, m = 0, n2 = 0, m2 = 0;
        bool dbl = false;
 
-       awin_tcon_calc_pll(3000, mode->dot_clock, &m, &n);
-       awin_tcon_calc_pll(6000, mode->dot_clock, &m2, &n2);
+       awin_tcon_calc_pll(3000, dclk, min_div, &m, &n);
+       awin_tcon_calc_pll(6000, dclk, min_div, &m2, &n2);
 
        int f_single = m ? (n * 3000) / m : 0;
        int f_double = m2 ? (n2 * 6000) / m2 : 0;
@@ -195,42 +239,83 @@
 
        if (n == 0 || m == 0) {
                device_printf(sc->sc_dev, "couldn't set pll to %d Hz\n",
-                   mode->dot_clock * 1000);
+                   dclk * 1000);
                sc->sc_clk_div = 0;
                return;
        }
 
 #ifdef AWIN_TCON_DEBUG
-       device_printf(sc->sc_dev, "pll n=%d m=%d dbl=%c freq=%d\n", n, m,
-           dbl ? 'Y' : 'N', n * 3000000);
+       device_printf(sc->sc_dev, "ch%d pll%d n=%d m=%d dbl=%c freq=%d\n",
+           (sc->sc_output_type == OUTPUT_HDMI) ? 1 : 0,
+           sc->sc_clk_pll, n, m, dbl ? 'Y' : 'N', n * 3000000);
 #endif
 
        switch(sc->sc_clk_pll) {
        case 3:



Home | Main Index | Thread Index | Old Index