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