Module Name: src
Committed By: bouyer
Date: Sun Oct 25 20:54:19 UTC 2015
Modified Files:
src/sys/arch/arm/allwinner: awin_board.c awin_debe.c awin_hdmi.c
awin_reg.h awin_tcon.c awin_var.h
src/sys/arch/evbarm/awin: awin_machdep.c
Log Message:
Snapshot of work in progress on support for multiple display outputs.
The display configuration comes from the fex script as defined
in http://linux-sunxi.org/Fex_Guide, section disp_init.
There is some code to convert lcd0_para/lcd1_para to properties but
it's not used yet.
At this time only mode 0 (debe0->tcon0->hdmi) works.
debe0->tcon1->hdmi and debe1->tcon0->hdmi both gives a valid HDMI
signal but completely blank screen. AWIN_TCON1_BLUEDATA gives a blue screen
in both cases so tcon1->hdmi works. I suspect that, for some reason
setups other than debe0->tcon0 are not configured properly, and
the tcon is reading all-1 bits instead of the expected debe output.
To generate a diff of this commit:
cvs rdiff -u -r1.39 -r1.40 src/sys/arch/arm/allwinner/awin_board.c
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/arm/allwinner/awin_debe.c \
src/sys/arch/arm/allwinner/awin_hdmi.c
cvs rdiff -u -r1.80 -r1.81 src/sys/arch/arm/allwinner/awin_reg.h
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/allwinner/awin_tcon.c
cvs rdiff -u -r1.36 -r1.37 src/sys/arch/arm/allwinner/awin_var.h
cvs rdiff -u -r1.43 -r1.44 src/sys/arch/evbarm/awin/awin_machdep.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/allwinner/awin_board.c
diff -u src/sys/arch/arm/allwinner/awin_board.c:1.39 src/sys/arch/arm/allwinner/awin_board.c:1.40
--- src/sys/arch/arm/allwinner/awin_board.c:1.39 Sat Oct 17 15:30:14 2015
+++ src/sys/arch/arm/allwinner/awin_board.c Sun Oct 25 20:54:19 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_board.c,v 1.39 2015/10/17 15:30:14 bouyer Exp $ */
+/* $NetBSD: awin_board.c,v 1.40 2015/10/25 20:54:19 bouyer Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -36,7 +36,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: awin_board.c,v 1.39 2015/10/17 15:30:14 bouyer Exp $");
+__KERNEL_RCSID(1, "$NetBSD: awin_board.c,v 1.40 2015/10/25 20:54:19 bouyer Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -920,6 +920,43 @@ awin_pll3_set_rate(uint32_t rate)
}
}
+void
+awin_pll7_set_rate(uint32_t rate)
+{
+ const uint32_t ocfg = CCM_READ4(AWIN_PLL7_CFG_REG);
+
+ uint32_t ncfg = ocfg;
+ if (rate == 0) {
+ ncfg &= ~AWIN_PLL_CFG_ENABLE;
+ } else {
+ if (awin_chip_id() == AWIN_CHIP_ID_A31) {
+ unsigned int m = 8;
+ unsigned int n = rate / (AWIN_REF_FREQ / m);
+ ncfg |= AWIN_A31_PLL7_CFG_MODE_SEL;
+ ncfg &= ~AWIN_A31_PLL7_CFG_FACTOR_N;
+ ncfg |= __SHIFTIN(n - 1, AWIN_A31_PLL7_CFG_FACTOR_N);
+ ncfg &= ~AWIN_A31_PLL7_CFG_PREDIV_M;
+ ncfg |= __SHIFTIN(m - 1, AWIN_A31_PLL7_CFG_PREDIV_M);
+ } else {
+ unsigned int m = rate / 3000000;
+ ncfg |= AWIN_PLL7_MODE_SEL;
+ ncfg &= ~AWIN_PLL7_FACTOR_M;
+ ncfg |= __SHIFTIN(m, AWIN_PLL7_FACTOR_M);
+ }
+ ncfg |= AWIN_PLL_CFG_ENABLE;
+ }
+
+ if (ncfg != ocfg) {
+ CCM_WRITE4(AWIN_PLL7_CFG_REG, ncfg);
+
+ if (awin_chip_id() == AWIN_CHIP_ID_A31) {
+ do {
+ ncfg = CCM_READ4(AWIN_PLL7_CFG_REG);
+ } while ((ncfg & AWIN_A31_PLL7_CFG_LOCK) == 0);
+ }
+ }
+}
+
uint32_t
awin_pll5x_get_rate(void)
{
Index: src/sys/arch/arm/allwinner/awin_debe.c
diff -u src/sys/arch/arm/allwinner/awin_debe.c:1.16 src/sys/arch/arm/allwinner/awin_debe.c:1.17
--- src/sys/arch/arm/allwinner/awin_debe.c:1.16 Fri Oct 9 07:23:33 2015
+++ src/sys/arch/arm/allwinner/awin_debe.c Sun Oct 25 20:54:19 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_debe.c,v 1.16 2015/10/09 07:23:33 bouyer Exp $ */
+/* $NetBSD: awin_debe.c,v 1.17 2015/10/25 20:54:19 bouyer Exp $ */
/*-
* Copyright (c) 2014 Jared D. McNeill <[email protected]>
@@ -37,7 +37,7 @@
#define AWIN_DEBE_CURMAX 64
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_debe.c,v 1.16 2015/10/09 07:23:33 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_debe.c,v 1.17 2015/10/25 20:54:19 bouyer Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -249,8 +249,8 @@ awin_debe_attach(device_t parent, device
#endif
#ifdef AWIN_DEBE_FWINIT
- awin_debe_set_videomode(&mode);
- awin_debe_enable(true);
+ awin_debe_set_videomode(device_unit(self), &mode);
+ awin_debe_enable(device_unit(self), true);
#endif
}
@@ -443,13 +443,13 @@ awin_debe_set_cursor(struct awin_debe_so
}
void
-awin_debe_enable(bool enable)
+awin_debe_enable(int unit, bool enable)
{
struct awin_debe_softc *sc;
device_t dev;
uint32_t val;
- dev = device_find_by_driver_unit("awindebe", 0);
+ dev = device_find_by_driver_unit("awindebe", unit);
if (dev == NULL) {
printf("DEBE: no driver found\n");
return;
@@ -472,13 +472,13 @@ awin_debe_enable(bool enable)
}
void
-awin_debe_set_videomode(const struct videomode *mode)
+awin_debe_set_videomode(int unit, const struct videomode *mode)
{
struct awin_debe_softc *sc;
device_t dev;
uint32_t val;
- dev = device_find_by_driver_unit("awindebe", 0);
+ dev = device_find_by_driver_unit("awindebe", unit);
if (dev == NULL) {
printf("DEBE: no driver found\n");
return;
Index: src/sys/arch/arm/allwinner/awin_hdmi.c
diff -u src/sys/arch/arm/allwinner/awin_hdmi.c:1.16 src/sys/arch/arm/allwinner/awin_hdmi.c:1.17
--- src/sys/arch/arm/allwinner/awin_hdmi.c:1.16 Sat Jul 25 15:19:54 2015
+++ src/sys/arch/arm/allwinner/awin_hdmi.c Sun Oct 25 20:54:19 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_hdmi.c,v 1.16 2015/07/25 15:19:54 jmcneill Exp $ */
+/* $NetBSD: awin_hdmi.c,v 1.17 2015/10/25 20:54:19 bouyer Exp $ */
/*-
* Copyright (c) 2014 Jared D. McNeill <[email protected]>
@@ -29,10 +29,8 @@
#include "opt_allwinner.h"
#include "opt_ddb.h"
-#define AWIN_HDMI_PLL 3 /* PLL7 or PLL3 */
-
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.16 2015/07/25 15:19:54 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_hdmi.c,v 1.17 2015/10/25 20:54:19 bouyer Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -72,6 +70,9 @@ struct awin_hdmi_softc {
#define DISPLAY_MODE_AUTO 0
#define DISPLAY_MODE_HDMI 1
#define DISPLAY_MODE_DVI 2
+
+ int sc_tcon_unit;
+ unsigned int sc_tcon_pll;
uint32_t sc_ver;
unsigned int sc_i2c_blklen;
@@ -141,30 +142,39 @@ awin_hdmi_attach(device_t parent, device
const struct awin_locators * const loc = &aio->aio_loc;
prop_dictionary_t cfg = device_properties(self);
uint32_t ver, clk;
+ int8_t tcon_unit = -1;
sc->sc_dev = self;
sc->sc_bst = aio->aio_core_bst;
bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
loc->loc_offset, loc->loc_size, &sc->sc_bsh);
-#if AWIN_HDMI_PLL == 3
- awin_pll3_enable();
-#elif AWIN_HDMI_PLL == 7
- awin_pll7_enable();
-#else
-#error AWIN_HDMI_PLL must be 3 or 7
-#endif
+ if (prop_dictionary_get_int8(cfg, "tcon_unit", &tcon_unit)) {
+ sc->sc_tcon_unit = tcon_unit;
+ } else {
+ sc->sc_tcon_unit = 0; /* default value */
+ }
+ sc->sc_tcon_pll = awin_tcon_get_clk_pll(sc->sc_tcon_unit);
+ switch (sc->sc_tcon_pll) {
+ case 3:
+ awin_pll3_enable();
+ clk =
+ __SHIFTIN(AWIN_HDMI_CLK_SRC_SEL_PLL3, AWIN_HDMI_CLK_SRC_SEL);
+ break;
+ case 7:
+ awin_pll7_enable();
+ clk =
+ __SHIFTIN(AWIN_HDMI_CLK_SRC_SEL_PLL7, AWIN_HDMI_CLK_SRC_SEL);
+ break;
+ default:
+ panic("awin_hdmi pll");
+ }
if (awin_chip_id() == AWIN_CHIP_ID_A31) {
awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
AWIN_A31_AHB_RESET1_REG, AWIN_A31_AHB_RESET1_HDMI_RST, 0);
}
-#if AWIN_HDMI_PLL == 3
- clk = __SHIFTIN(AWIN_HDMI_CLK_SRC_SEL_PLL3, AWIN_HDMI_CLK_SRC_SEL);
-#else
- clk = __SHIFTIN(AWIN_HDMI_CLK_SRC_SEL_PLL7, AWIN_HDMI_CLK_SRC_SEL);
-#endif
clk |= AWIN_CLK_ENABLE;
if (awin_chip_id() == AWIN_CHIP_ID_A31) {
clk |= AWIN_A31_HDMI_CLK_DDC_GATING;
@@ -181,6 +191,10 @@ awin_hdmi_attach(device_t parent, device
aprint_naive("\n");
aprint_normal(": HDMI %d.%d\n", vmaj, vmin);
+ if (tcon_unit >= 0) {
+ aprint_verbose_dev(self, ": using TCON%d, pll%d\n",
+ sc->sc_tcon_unit, sc->sc_tcon_pll);
+ }
sc->sc_ver = ver;
sc->sc_i2c_blklen = 16;
@@ -479,12 +493,16 @@ awin_hdmi_enable(struct awin_hdmi_softc
HDMI_WRITE(sc, AWIN_HDMI_PAD_CTRL0_REG, 0x7e80000f);
HDMI_WRITE(sc, AWIN_HDMI_PAD_CTRL1_REG, 0x01ded030);
}
-#if AWIN_HDMI_PLL == 7
- HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (1<<21));
-#elif AWIN_HDMI_PLL == 3
- HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (0<<21));
-#endif
-
+ switch(sc->sc_tcon_pll) {
+ case 3:
+ HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (0<<21));
+ break;
+ case 7:
+ HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (1<<21));
+ break;
+ default:
+ panic("awin_hdmi pll");
+ }
delay(1000);
}
@@ -562,16 +580,13 @@ awin_hdmi_read_edid(struct awin_hdmi_sof
if (mode != NULL) {
awin_hdmi_video_enable(sc, false);
- awin_tcon_enable(false);
+ awin_tcon_enable(sc->sc_tcon_unit, false);
delay(20000);
- awin_debe_set_videomode(mode);
- awin_tcon_set_videomode(mode);
+ awin_tcon_set_videomode(sc->sc_tcon_unit, mode);
awin_hdmi_set_videomode(sc, mode, display_mode);
awin_hdmi_set_audiomode(sc, mode, display_mode);
- awin_debe_enable(true);
- delay(20000);
- awin_tcon_enable(true);
+ awin_tcon_enable(sc->sc_tcon_unit, true);
delay(20000);
awin_hdmi_video_enable(sc, true);
}
@@ -715,8 +730,8 @@ awin_hdmi_set_videomode(struct awin_hdmi
HDMI_WRITE(sc, AWIN_HDMI_INT_STATUS_REG, 0xffffffff);
- u_int clk_div = awin_tcon_get_clk_div();
- bool clk_dbl = awin_tcon_get_clk_dbl();
+ u_int clk_div = awin_tcon_get_clk_div(sc->sc_tcon_unit);
+ bool clk_dbl = awin_tcon_get_clk_dbl(sc->sc_tcon_unit);
#ifdef AWIN_HDMI_DEBUG
device_printf(sc->sc_dev, "dot_clock: %d\n", mode->dot_clock);
@@ -747,11 +762,16 @@ awin_hdmi_set_videomode(struct awin_hdmi
HDMI_WRITE(sc, AWIN_HDMI_PAD_CTRL0_REG, pad_ctrl0);
HDMI_WRITE(sc, AWIN_HDMI_PAD_CTRL1_REG, pad_ctrl1);
HDMI_WRITE(sc, AWIN_HDMI_PLL_CTRL_REG, pll_ctrl);
-#if AWIN_HDMI_PLL == 7
- HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (1<<21));
-#elif AWIN_HDMI_PLL == 3
- HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (0<<21));
-#endif
+ switch(sc->sc_tcon_pll) {
+ case 3:
+ HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (0<<21));
+ break;
+ case 7:
+ HDMI_WRITE(sc, AWIN_HDMI_PLL_DBG0_REG, (1<<21));
+ break;
+ default:
+ panic("awin_hdmi pll");
+ }
val = HDMI_READ(sc, AWIN_HDMI_VID_CTRL_REG);
val &= ~AWIN_HDMI_VID_CTRL_HDMI_MODE;
@@ -908,7 +928,7 @@ awin_hdmi_hpd(struct awin_hdmi_softc *sc
awin_hdmi_read_edid(sc);
} else {
device_printf(sc->sc_dev, "display disconnected\n");
- awin_tcon_set_videomode(NULL);
+ awin_tcon_set_videomode(sc->sc_tcon_unit, NULL);
}
sc->sc_connected = con;
Index: src/sys/arch/arm/allwinner/awin_reg.h
diff -u src/sys/arch/arm/allwinner/awin_reg.h:1.80 src/sys/arch/arm/allwinner/awin_reg.h:1.81
--- src/sys/arch/arm/allwinner/awin_reg.h:1.80 Sat Oct 17 15:30:14 2015
+++ src/sys/arch/arm/allwinner/awin_reg.h Sun Oct 25 20:54:19 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_reg.h,v 1.80 2015/10/17 15:30:14 bouyer Exp $ */
+/* $NetBSD: awin_reg.h,v 1.81 2015/10/25 20:54:19 bouyer Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -1161,7 +1161,7 @@ struct awin_mmc_idma_descriptor {
#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_PLL6_2 3
+#define AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7_2X 3
#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)
@@ -1804,7 +1804,7 @@ struct awin_mmc_idma_descriptor {
#define AWIN_TCON_CMAP_ODD1_REG 0x0194
#define AWIN_TCON_CMAP_EVEN0_REG 0x0198
#define AWIN_TCON_CMAP_EVEN1_REG 0x019C
-#define AWIN_TCON_MUX_CTL_REG 0x0200
+#define AWIN_TCON_MUX_CTL_REG 0x0200 /* only in TCON0 */
#define AWIN_TCON_GCTL_EN __BIT(31)
#define AWIN_TCON_GCTL_GAMMA_EN __BIT(30)
Index: src/sys/arch/arm/allwinner/awin_tcon.c
diff -u src/sys/arch/arm/allwinner/awin_tcon.c:1.5 src/sys/arch/arm/allwinner/awin_tcon.c:1.6
--- src/sys/arch/arm/allwinner/awin_tcon.c:1.5 Fri Nov 14 00:31:54 2014
+++ src/sys/arch/arm/allwinner/awin_tcon.c Sun Oct 25 20:54:19 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_tcon.c,v 1.5 2014/11/14 00:31:54 jmcneill Exp $ */
+/* $NetBSD: awin_tcon.c,v 1.6 2015/10/25 20:54:19 bouyer Exp $ */
/*-
* Copyright (c) 2014 Jared D. McNeill <[email protected]>
@@ -29,7 +29,7 @@
#include "opt_allwinner.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_tcon.c,v 1.5 2014/11/14 00:31:54 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_tcon.c,v 1.6 2015/10/25 20:54:19 bouyer Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -53,10 +53,15 @@ struct awin_tcon_softc {
bus_space_handle_t sc_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;
};
+static bus_space_handle_t tcon_mux_bsh;
+static bool tcon_mux_inited = false;
+
#define TCON_READ(sc, reg) \
bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
#define TCON_WRITE(sc, reg, val) \
@@ -68,6 +73,25 @@ static void awin_tcon_attach(device_t, d
static void awin_tcon_set_pll(struct awin_tcon_softc *,
const struct videomode *);
+static void
+awin_tcon_clear_reset(struct awinio_attach_args * const aio, int unit)
+{
+ KASSERT(unit == 0 || unit == 1);
+ if (awin_chip_id() == AWIN_CHIP_ID_A31) {
+ awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
+ AWIN_A31_AHB_RESET1_REG,
+ AWIN_A31_AHB_RESET1_LCD0_RST << unit,
+ 0);
+ } else {
+ awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
+ AWIN_LCD0_CH0_CLK_REG + (unit * 4),
+ AWIN_LCDx_CH0_CLK_LCDx_RST, 0);
+ }
+
+ awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
+ AWIN_AHB_GATING1_REG, AWIN_AHB_GATING1_LCD0 << unit, 0);
+}
+
CFATTACH_DECL_NEW(awin_tcon, sizeof(struct awin_tcon_softc),
awin_tcon_match, awin_tcon_attach, NULL, NULL);
@@ -89,6 +113,8 @@ awin_tcon_attach(device_t parent, device
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);
+ int8_t debe_unit = -1;
sc->sc_dev = self;
sc->sc_bst = aio->aio_core_bst;
@@ -97,26 +123,44 @@ awin_tcon_attach(device_t parent, device
loc->loc_offset, loc->loc_size, &sc->sc_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 */
+ bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
+ AWIN_LCD0_OFFSET + AWIN_TCON_MUX_CTL_REG, 4, &tcon_mux_bsh);
+ tcon_mux_inited = true;
+ /* always enable tcon0, the mux is there */
+ awin_tcon_clear_reset(aio, 0);
+ }
- aprint_naive("\n");
- aprint_normal(": LCD/TV timing controller (TCON%d)\n", loc->loc_port);
-
- awin_pll3_enable();
-
- if (awin_chip_id() == AWIN_CHIP_ID_A31) {
- awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
- AWIN_A31_AHB_RESET1_REG,
- AWIN_A31_AHB_RESET1_LCD0_RST << loc->loc_port,
- 0);
+ if (prop_dictionary_get_int8(cfg, "debe_unit", &debe_unit)) {
+ sc->sc_debe_unit = debe_unit;
} else {
- awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
- AWIN_LCD0_CH0_CLK_REG + (loc->loc_port * 4),
- AWIN_LCDx_CH0_CLK_LCDx_RST, 0);
+ sc->sc_debe_unit = 0; /* default value */
}
- awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
- AWIN_AHB_GATING1_REG, AWIN_AHB_GATING1_LCD0 << loc->loc_port, 0);
+
+
+ aprint_naive("\n");
+ aprint_normal(": LCD/TV timing controller (TCON%d)\n", loc->loc_port);
+ switch (sc->sc_port) {
+ case 0:
+ awin_pll3_enable();
+ sc->sc_clk_pll = 3;
+ break;
+ case 1:
+ awin_pll7_enable();
+ sc->sc_clk_pll = 7;
+ break;
+ default:
+ panic("awin_tcon port\n");
+ }
+ if (debe_unit >= 0) {
+ aprint_verbose_dev(self, ": using DEBE%d, pll%d\n",
+ sc->sc_debe_unit, sc->sc_clk_pll);
+ }
+ awin_tcon_clear_reset(aio, sc->sc_port);
+
TCON_WRITE(sc, AWIN_TCON_GCTL_REG, 0);
TCON_WRITE(sc, AWIN_TCON_GINT0_REG, 0);
TCON_WRITE(sc, AWIN_TCON_GINT1_REG,
@@ -173,37 +217,57 @@ awin_tcon_set_pll(struct awin_tcon_softc
dbl ? 'Y' : 'N', n * 3000000);
#endif
- awin_pll3_set_rate(n * 3000000);
-
- awin_reg_set_clear(sc->sc_bst, sc->sc_ch1clk_bsh, 0,
- AWIN_CLK_OUT_ENABLE |
- AWIN_LCDx_CH1_SCLK1_GATING |
- __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3_2X :
- AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3,
- AWIN_LCDx_CHx_CLK_SRC_SEL) |
- __SHIFTIN(m - 1, AWIN_LCDx_CH1_CLK_DIV_RATIO_M),
- AWIN_LCDx_CH1_CLK_DIV_RATIO_M |
- AWIN_LCDx_CHx_CLK_SRC_SEL |
- AWIN_LCDx_CH1_SCLK1_SRC_SEL);
+ switch(sc->sc_clk_pll) {
+ case 3:
+ awin_pll3_set_rate(n * 3000000);
+ awin_reg_set_clear(sc->sc_bst, sc->sc_ch1clk_bsh, 0,
+ AWIN_CLK_OUT_ENABLE |
+ AWIN_LCDx_CH1_SCLK1_GATING |
+ __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3_2X :
+ AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3,
+ AWIN_LCDx_CHx_CLK_SRC_SEL) |
+ __SHIFTIN(m - 1, AWIN_LCDx_CH1_CLK_DIV_RATIO_M),
+ AWIN_LCDx_CH1_CLK_DIV_RATIO_M |
+ AWIN_LCDx_CHx_CLK_SRC_SEL |
+ AWIN_LCDx_CH1_SCLK1_SRC_SEL);
+ break;
+ case 7:
+ awin_pll7_set_rate(n * 3000000);
+ awin_reg_set_clear(sc->sc_bst, sc->sc_ch1clk_bsh, 0,
+ AWIN_CLK_OUT_ENABLE |
+ AWIN_LCDx_CH1_SCLK1_GATING |
+ __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7_2X :
+ AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7,
+ AWIN_LCDx_CHx_CLK_SRC_SEL) |
+ __SHIFTIN(m - 1, AWIN_LCDx_CH1_CLK_DIV_RATIO_M),
+ AWIN_LCDx_CH1_CLK_DIV_RATIO_M |
+ AWIN_LCDx_CHx_CLK_SRC_SEL |
+ AWIN_LCDx_CH1_SCLK1_SRC_SEL);
+ break;
+ default:
+ panic("awin_tcon pll");
+ }
sc->sc_clk_div = m;
sc->sc_clk_dbl = dbl;
}
void
-awin_tcon_enable(bool enable)
+awin_tcon_enable(int unit, bool enable)
{
struct awin_tcon_softc *sc;
device_t dev;
uint32_t val;
- dev = device_find_by_driver_unit("awintcon", 0);
+ dev = device_find_by_driver_unit("awintcon", unit);
if (dev == NULL) {
- printf("TCON: no driver found\n");
+ printf("TCON%d: no driver found\n", unit);
return;
}
sc = device_private(dev);
+ awin_debe_enable(sc->sc_debe_unit, enable);
+ delay(20000);
val = TCON_READ(sc, AWIN_TCON_GCTL_REG);
if (enable) {
val |= AWIN_TCON_GCTL_EN;
@@ -219,22 +283,46 @@ awin_tcon_enable(bool enable)
val |= 0x03000000;
}
TCON_WRITE(sc, AWIN_TCON1_IO_TRI_REG, val);
+
+ KASSERT(tcon_mux_inited);
+ val = bus_space_read_4(sc->sc_bst, tcon_mux_bsh, 0);
+#ifdef AWIN_TCON_DEBUG
+ printf("awin_tcon_enable(%d) val 0x%x", unit, val);
+#endif
+ val &= ~ AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC;
+ if (unit == 0) {
+ val |= __SHIFTIN(AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC_LCDC0_TCON1,
+ AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC);
+ } else if (unit == 1) {
+ val |= __SHIFTIN(AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC_LCDC1_TCON1,
+ AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC);
+ }
+#ifdef AWIN_TCON_DEBUG
+ printf(" -> 0x%x", val);
+#endif
+ bus_space_write_4(sc->sc_bst, tcon_mux_bsh, 0, val);
+#ifdef AWIN_TCON_DEBUG
+ printf(": 0x%" PRIxBSH " 0x%" PRIxBSH " 0x%x 0x%x\n", sc->sc_bsh,
+ tcon_mux_bsh, bus_space_read_4(sc->sc_bst, tcon_mux_bsh, 0),
+ TCON_READ(sc, AWIN_TCON_MUX_CTL_REG));
+#endif
}
void
-awin_tcon_set_videomode(const struct videomode *mode)
+awin_tcon_set_videomode(int unit, const struct videomode *mode)
{
struct awin_tcon_softc *sc;
device_t dev;
uint32_t val;
- dev = device_find_by_driver_unit("awintcon", 0);
+ dev = device_find_by_driver_unit("awintcon", unit);
if (dev == NULL) {
- printf("TCON: no driver found\n");
+ printf("TCON%d: no driver found\n", unit);
return;
}
sc = device_private(dev);
+ awin_debe_set_videomode(sc->sc_debe_unit, mode);
if (mode) {
const u_int interlace_p = !!(mode->flags & VID_INTERLACE);
const u_int phsync_p = !!(mode->flags & VID_PHSYNC);
@@ -252,17 +340,33 @@ awin_tcon_set_videomode(const struct vid
val |= AWIN_TCON_GCTL_IO_MAP_SEL;
TCON_WRITE(sc, AWIN_TCON_GCTL_REG, val);
+ val = TCON_READ(sc, AWIN_TCON0_CTL_REG);
+ val &= ~0x00400003;
+ if (sc->sc_debe_unit == 0) {
+ val |= __SHIFTIN(AWIN_TCON_CTL_SRC_SEL_DE0,
+ AWIN_TCON_CTL_SRC_SEL);
+ } else {
+ val |= __SHIFTIN(AWIN_TCON_CTL_SRC_SEL_DE1,
+ AWIN_TCON_CTL_SRC_SEL);
+ }
+ TCON_WRITE(sc, AWIN_TCON0_CTL_REG, val);
+
/* enable */
val = AWIN_TCON_CTL_EN;
if (interlace_p)
val |= AWIN_TCON_CTL_INTERLACE_EN;
val |= __SHIFTIN(start_delay, AWIN_TCON_CTL_START_DELAY);
-#ifdef AWIN_TCON_BLUEDATA
+#ifdef AWIN_TCON1_BLUEDATA
val |= __SHIFTIN(AWIN_TCON_CTL_SRC_SEL_BLUEDATA,
AWIN_TCON_CTL_SRC_SEL);
#else
- val |= __SHIFTIN(AWIN_TCON_CTL_SRC_SEL_DE0,
- AWIN_TCON_CTL_SRC_SEL);
+ if (sc->sc_debe_unit == 0) {
+ val |= __SHIFTIN(AWIN_TCON_CTL_SRC_SEL_DE0,
+ AWIN_TCON_CTL_SRC_SEL);
+ } else {
+ val |= __SHIFTIN(AWIN_TCON_CTL_SRC_SEL_DE1,
+ AWIN_TCON_CTL_SRC_SEL);
+ }
#endif
TCON_WRITE(sc, AWIN_TCON1_CTL_REG, val);
@@ -308,6 +412,14 @@ awin_tcon_set_videomode(const struct vid
/* Setup LCDx CH1 PLL */
awin_tcon_set_pll(sc, mode);
+#if 0
+{
+ int i;
+ for (i = 0; i < 0x800; i += 4) {
+ printf("TCON 0x%04x: 0x%08x\n", i, TCON_READ(sc, i));
+ }
+}
+#endif
} else {
/* disable */
val = TCON_READ(sc, AWIN_TCON1_CTL_REG);
@@ -317,14 +429,30 @@ awin_tcon_set_videomode(const struct vid
}
unsigned int
-awin_tcon_get_clk_div(void)
+awin_tcon_get_clk_pll(int unit)
+{
+ struct awin_tcon_softc *sc;
+ device_t dev;
+
+ dev = device_find_by_driver_unit("awintcon", unit);
+ if (dev == NULL) {
+ printf("TCON%d: no driver found\n", unit);
+ return 0;
+ }
+ sc = device_private(dev);
+
+ return sc->sc_clk_pll;
+}
+
+unsigned int
+awin_tcon_get_clk_div(int unit)
{
struct awin_tcon_softc *sc;
device_t dev;
- dev = device_find_by_driver_unit("awintcon", 0);
+ dev = device_find_by_driver_unit("awintcon", unit);
if (dev == NULL) {
- printf("TCON: no driver found\n");
+ printf("TCON%d: no driver found\n", unit);
return 0;
}
sc = device_private(dev);
@@ -333,14 +461,14 @@ awin_tcon_get_clk_div(void)
}
bool
-awin_tcon_get_clk_dbl(void)
+awin_tcon_get_clk_dbl(int unit)
{
struct awin_tcon_softc *sc;
device_t dev;
- dev = device_find_by_driver_unit("awintcon", 0);
+ dev = device_find_by_driver_unit("awintcon", unit);
if (dev == NULL) {
- printf("TCON: no driver found\n");
+ printf("TCON%d: no driver found\n", unit);
return 0;
}
sc = device_private(dev);
Index: src/sys/arch/arm/allwinner/awin_var.h
diff -u src/sys/arch/arm/allwinner/awin_var.h:1.36 src/sys/arch/arm/allwinner/awin_var.h:1.37
--- src/sys/arch/arm/allwinner/awin_var.h:1.36 Sat Oct 17 15:30:14 2015
+++ src/sys/arch/arm/allwinner/awin_var.h Sun Oct 25 20:54:19 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_var.h,v 1.36 2015/10/17 15:30:14 bouyer Exp $ */
+/* $NetBSD: awin_var.h,v 1.37 2015/10/25 20:54:19 bouyer Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -108,6 +108,7 @@ void awin_pll3_enable(void);
void awin_pll6_enable(void);
void awin_pll7_enable(void);
void awin_pll3_set_rate(uint32_t);
+void awin_pll7_set_rate(uint32_t);
uint32_t awin_pll5x_get_rate(void);
uint32_t awin_pll6_get_rate(void);
uint32_t awin_periph0_get_rate(void);
@@ -136,12 +137,13 @@ int awin_dma_transfer(void *, paddr_t, p
void awin_dma_halt(void *);
struct videomode;
-unsigned int awin_tcon_get_clk_div(void);
-bool awin_tcon_get_clk_dbl(void);
-void awin_tcon_set_videomode(const struct videomode *);
-void awin_tcon_enable(bool);
-void awin_debe_set_videomode(const struct videomode *);
-void awin_debe_enable(bool);
+unsigned int awin_tcon_get_clk_pll(int);
+unsigned int awin_tcon_get_clk_div(int);
+bool awin_tcon_get_clk_dbl(int);
+void awin_tcon_set_videomode(int, const struct videomode *);
+void awin_tcon_enable(int, bool);
+void awin_debe_set_videomode(int, const struct videomode *);
+void awin_debe_enable(int, bool);
int awin_debe_ioctl(device_t, u_long, void *);
int awin_mp_ioctl(device_t, u_long, void *);
void awin_mp_setbase(device_t, paddr_t, size_t);
Index: src/sys/arch/evbarm/awin/awin_machdep.c
diff -u src/sys/arch/evbarm/awin/awin_machdep.c:1.43 src/sys/arch/evbarm/awin/awin_machdep.c:1.44
--- src/sys/arch/evbarm/awin/awin_machdep.c:1.43 Wed Oct 21 09:25:16 2015
+++ src/sys/arch/evbarm/awin/awin_machdep.c Sun Oct 25 20:54:19 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_machdep.c,v 1.43 2015/10/21 09:25:16 jmcneill Exp $ */
+/* $NetBSD: awin_machdep.c,v 1.44 2015/10/25 20:54:19 bouyer Exp $ */
/*
* Machine dependent functions for kernel setup for TI OSK5912 board.
@@ -125,7 +125,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_machdep.c,v 1.43 2015/10/21 09:25:16 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_machdep.c,v 1.44 2015/10/25 20:54:19 bouyer Exp $");
#include "opt_machdep.h"
#include "opt_ddb.h"
@@ -260,6 +260,10 @@ static void awin_device_register(device_
#ifdef AWIN_SYSCONFIG
static void awin_gpio_sysconfig(prop_dictionary_t);
+static void awin_display_sysconfig(prop_dictionary_t);
+static void awin_hdmi_sysconfig(prop_dictionary_t);
+static void awin_tcon_sysconfig(device_t, prop_dictionary_t);
+static void awin_tcon_lcd_sysconfig(const char *, prop_dictionary_t);
#endif
#if NCOM > 0
@@ -673,6 +677,11 @@ awin_device_register(device_t self, void
#elif AWIN_board == AWIN_bpi || AWIN_board == AWIN_olimexlime2
prop_dictionary_set_bool(dict, "no-awe", true);
#endif
+#ifdef AWIN_SYSCONFIG
+ if (awin_sysconfig_p) {
+ awin_display_sysconfig(dict);
+ }
+#endif
return;
}
@@ -934,4 +943,217 @@ awin_gpio_sysconfig(prop_dictionary_t di
}
}
}
+
+/* see which display devices needs to be disabled */
+
+static void
+awin_display_sysconfig(prop_dictionary_t dict)
+{
+ bool hdmi_used = false;
+ int screen0_type, screen1_type;
+
+ switch(awin_sysconfig_get_int("disp_init", "disp_init_enable")) {
+ case -1:
+ return;
+ case 0:
+ prop_dictionary_set_bool(dict, "no-awindebe-0", true);
+ prop_dictionary_set_bool(dict, "no-awindebe-1", true);
+ prop_dictionary_set_bool(dict, "no-awintcon-0", true);
+ prop_dictionary_set_bool(dict, "no-awintcon-1", true);
+ prop_dictionary_set_bool(dict, "no-awinhdmi", true);
+ prop_dictionary_set_bool(dict, "no-awinhdmiaudio", true);
+ return;
+ default:
+ break;
+ }
+ screen0_type = awin_sysconfig_get_int("disp_init", "screen0_output_type");
+ screen1_type = awin_sysconfig_get_int("disp_init", "screen1_output_type");
+ switch(awin_sysconfig_get_int("disp_init", "disp_mode")) {
+ case 0:
+ /* screen0, fb0 */
+ prop_dictionary_set_bool(dict, "no-awindebe-1", true);
+ prop_dictionary_set_bool(dict, "no-awintcon-1", true);
+ hdmi_used = (screen0_type == 3);
+ break;
+ case 1:
+ /* screen1, fb0 */
+ prop_dictionary_set_bool(dict, "no-awindebe-1", true);
+ prop_dictionary_set_bool(dict, "no-awintcon-0", true);
+ hdmi_used = (screen1_type == 3);
+ break;
+ case 2:
+ /* dual-head; all tcon and debe used */
+ hdmi_used = (screen0_type == 3 || screen1_type == 3);
+ break;
+ case 3:
+ /* xinerama */
+ case 4:
+ /* clone */
+ prop_dictionary_set_bool(dict, "no-awindebe-1", true);
+ hdmi_used = (screen0_type == 3 || screen1_type == 3);
+ break;
+ default:
+ return;
+ }
+ if (!hdmi_used) {
+ prop_dictionary_set_bool(dict, "no-awinhdmi", true);
+ prop_dictionary_set_bool(dict, "no-awinhdmiaudio", true);
+ }
+
+}
+
+static void
+awin_hdmi_sysconfig(prop_dictionary_t dict)
+{
+ int type;
+
+ if (awin_sysconfig_get_int("disp_init", "disp_mode") != 1) {
+ /* tcon0 enabled, try tcon0 first */
+ type =
+ awin_sysconfig_get_int("disp_init", "screen0_output_type");
+ if (type < 0)
+ return;
+ if (type == 3) {
+ prop_dictionary_set_int8(dict, "tcon_unit", 0);
+ return;
+ }
+ }
+ /* either tcon0 is not enabled, or not in hdmi mode. try tcon1 */
+ type = awin_sysconfig_get_int("disp_init", "screen1_output_type");
+ if (type == 3) {
+ prop_dictionary_set_int8(dict, "tcon_unit", 1);
+ return;
+ }
+ /*
+ * all other cases, including failure to get screen1_output_type
+ * Note that this should not happen as HDMI should have been
+ * disabled in this case.
+ */
+ prop_dictionary_set_int8(dict, "tcon_unit", -1);
+}
+
+static void
+awin_tcon_sysconfig(device_t self, prop_dictionary_t dict)
+{
+ int mode = awin_sysconfig_get_int("disp_init", "disp_mode");
+ int type;
+
+ if (device_unit(self) == 0) {
+ if (mode < 0)
+ return;
+
+ prop_dictionary_set_int8(dict, "debe_unit", 0);
+ type = awin_sysconfig_get_int("disp_init", "screen0_output_type");
+ if (type == 1) {
+ /* LCD/LVDS output */
+ awin_tcon_lcd_sysconfig("lcd0_para", dict);
+ return;
+ }
+ if (type == 3) {
+ prop_dictionary_set_cstring(dict, "output", "hdmi");
+ return;
+ }
+ /* unsupported mode */
+ return;
+ }
+ if (device_unit(self) == 1) {
+ switch (mode) {
+ case 0:
+ /* only mode where tcon1 is not used */
+ return;
+ case 2:
+ prop_dictionary_set_int8(dict, "debe_unit", 1);
+ break;
+ default:
+ prop_dictionary_set_int8(dict, "debe_unit", 0);
+ break;
+ }
+ type = awin_sysconfig_get_int("disp_init", "screen1_output_type");
+ if (type == 1) {
+ /* LCD/LVDS output */
+ awin_tcon_lcd_sysconfig("lcd1_para", dict);
+ return;
+ }
+ if (type == 3) {
+ prop_dictionary_set_cstring(dict, "output", "hdmi");
+ return;
+ }
+ /* unsupported mode */
+ return;
+ }
+}
+
+static void
+awin_tcon_lcd_sysconfig(const char *key, prop_dictionary_t dict)
+{
+ static const char *lcdtimings[] = {
+ "lcd_x",
+ "lcd_y",
+ "lcd_dclk_freq",
+ "lcd_hbp",
+ "lcd_ht",
+ "lcd_vbp",
+ "lcd_vt",
+ "lcd_hv_hspw",
+ "lcd_io_cfg0",
+ };
+ static const char *lcdgpio[] = {
+ "lcdd0",
+ "lcdd1",
+ "lcdd2",
+ "lcdd3",
+ "lcdd4",
+ "lcdd5",
+ "lcdd6",
+ "lcdd7",
+ "lcdd8",
+ "lcdd9",
+ "lcdd10",
+ "lcdd11",
+ "lcdd12",
+ "lcdd13",
+ "lcdd14",
+ "lcdd15",
+ "lcdd16",
+ "lcdd17",
+ "lcdd18",
+ "lcdd19",
+ "lcdd20",
+ "lcdd21",
+ "lcdd22",
+ "lcdd23",
+ "lcdclk",
+ "lcdde",
+ "lcdhsync",
+ "lcdvsync"
+ };
+ unsigned int n;
+ const char *cfg;
+
+ for (n = 0; n < __arraycount(lcdtimings); n++) {
+ int value = awin_sysconfig_get_int( key, lcdtimings[n]);
+ if (value >= 0) {
+ prop_dictionary_set_int32(dict, lcdtimings[n], value);
+ }
+ }
+ if (awin_sysconfig_get_int(key, "lcd_bl_en_used") == 1) {
+ cfg = awin_sysconfig_get_gpio(key, "lcd_bl_en");
+ if (cfg != NULL) {
+ prop_dictionary_set_cstring(dict, "lcd_bl_en", cfg);
+ }
+ }
+ if (awin_sysconfig_get_int(key, "lcd_power_used") == 1) {
+ cfg = awin_sysconfig_get_gpio(key, "lcd_power");
+ if (cfg != NULL) {
+ prop_dictionary_set_cstring(dict, "lcd_bl_en", cfg);
+ }
+ }
+ for (n = 0; n < __arraycount(lcdgpio); n++) {
+ cfg = awin_sysconfig_get_string(key, lcdgpio[n]);
+ if (cfg != NULL) {
+ prop_dictionary_set_cstring(dict, lcdgpio[n], cfg);
+ }
+ }
+
+}
#endif