All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH] video: add cfb console driver for sunxi
@ 2014-08-02 16:14 Luc Verhaegen
  2014-08-04  8:39 ` Hans de Goede
  2014-08-05 11:56 ` [U-Boot] " Hans de Goede
  0 siblings, 2 replies; 18+ messages in thread
From: Luc Verhaegen @ 2014-08-02 16:14 UTC (permalink / raw)
  To: u-boot

This adds a fixed mode hdmi driver (lcd to be added in future) for the
sunxi platform. Current config is such that 8MB is shaved off at the top
of the RAM. Simplefb support is available for kernels that know how to
use it.

Signed-off-by: Luc Verhaegen <libv@skynet.be>
---
 arch/arm/include/asm/arch-sunxi/sunxi_display.h |   21 +
 board/sunxi/board.c                             |   14 +
 drivers/video/Makefile                          |    1 +
 drivers/video/sunxi_display.c                   |  639 +++++++++++++++++++++++
 include/configs/sunxi-common.h                  |   34 ++
 5 files changed, 709 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/arch-sunxi/sunxi_display.h
 create mode 100644 drivers/video/sunxi_display.c

diff --git a/arch/arm/include/asm/arch-sunxi/sunxi_display.h b/arch/arm/include/asm/arch-sunxi/sunxi_display.h
new file mode 100644
index 0000000..4456778
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/sunxi_display.h
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2014 Luc Verhaegen <libv@skynet.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation's version 2 and any
+ * later version the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _SUNXI_DISPLAY_H_
+#define _SUNXI_DISPLAY_H_
+
+#ifdef CONFIG_VIDEO_DT_SIMPLEFB
+void sunxi_simplefb_setup(void *blob);
+#endif
+
+#endif /* _SUNXI_DISPLAY_H_ */
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 2179e23..e819b12 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -26,6 +26,10 @@
 #include <asm/io.h>
 #include <net.h>
 
+#ifdef CONFIG_VIDEO
+#include <asm/arch-sunxi/sunxi_display.h>
+#endif
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /* add board specific code here */
@@ -185,3 +189,13 @@ int misc_init_r(void)
 	return 0;
 }
 #endif
+
+#ifdef CONFIG_OF_BOARD_SETUP
+void
+ft_board_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_VIDEO_DT_SIMPLEFB
+	sunxi_simplefb_setup(blob);
+#endif
+}
+#endif /* CONFIG_OF_BOARD_SETUP */
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 945f35d..9a25c84 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o
 obj-$(CONFIG_VIDEO_SED13806) += sed13806.o
 obj-$(CONFIG_VIDEO_SM501) += sm501.o
 obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
+obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o
 obj-$(CONFIG_VIDEO_TEGRA) += tegra.o
 obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
 obj-$(CONFIG_FORMIKE) += formike.o
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
new file mode 100644
index 0000000..251fb67
--- /dev/null
+++ b/drivers/video/sunxi_display.c
@@ -0,0 +1,639 @@
+/*
+ * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
+ *
+ * Display driver for Allwinner SoCs.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation's version 2 and any
+ * later version the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This driver does nothing but HDMI at a fixed mode right now. At some
+ * point in the near future, LCD and VGA will be added.
+ *
+ * The display driver infrastructure in uboot does not immediately allow for
+ * modeline creation off of edid. The mode is therefor hardcoded to
+ * 1024x768 at 60Hz 32bpp. This is acceptable for most HDMI monitors, but far
+ * from ideal. If so desired, alter the modeline in video_hw_init()
+ */
+
+#include <common.h>
+
+#include <asm/io.h>
+#include <asm/global_data.h>
+#include <video_fb.h>
+#include <linux/fb.h>
+#include <asm/arch-sunxi/sunxi_display.h>
+
+/* for simplefb */
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <libfdt.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sunxi_display {
+	GraphicDevice graphic_device[1];
+	int enabled;
+} sunxi_display[1];
+
+/*
+ * Convenience functions to ease readability, and to provide an easy
+ * comparison with the sunxi kms driver.
+ */
+static unsigned int
+sunxi_io_read(void *base, int offset)
+{
+	return readl(base + offset);
+}
+
+static void
+sunxi_io_write(void *base, int offset, unsigned int value)
+{
+	writel(value, base + offset);
+}
+
+static void
+sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask)
+{
+	unsigned int tmp = readl(base + offset);
+
+	tmp &= ~mask;
+	tmp |= value & mask;
+
+	writel(tmp, base + offset);
+}
+
+/*
+ * CCMU regs: clocks.
+ */
+#define SUNXI_CCMU_PLL3_CFG		0x010
+#define SUNXI_CCMU_PLL5_CFG		0x020
+#define SUNXI_CCMU_PLL7_CFG		0x030
+#define SUNXI_CCMU_AHB_GATING1		0x064
+#define SUNXI_CCMU_DRAM_CLK_GATING	0x100
+#define SUNXI_DE_BE0_CLK		0x104
+#define SUNXI_LCDC0_CH0_CLK		0x118
+#define SUNXI_LCDC0_CH1_CLK		0x12C
+#define SUNXI_CCMU_HDMI_CLK		0x150
+
+/*
+ * DEBE regs.
+ *
+ * This is the entity that mixes and matches the different layers and inputs.
+ * Allwinner calls it the back-end, but i like composer better.
+ */
+#define SUNXI_COMP_MODE			0x800
+#define SUNXI_COMP_DISP_SIZE		0x808
+#define SUNXI_COMP_LAYER0_SIZE		0x810
+#define SUNXI_COMP_LAYER0_POS		0x820
+#define SUNXI_COMP_LAYER0_STRIDE	0x840
+#define SUNXI_COMP_LAYER0_ADDR_LOW	0X850
+#define SUNXI_COMP_LAYER_ADDR_HIGH	0X860
+#define SUNXI_COMP_REG_CTL		0X870
+#define SUNXI_COMP_LAYER0_ATTR0		0x890
+#define SUNXI_COMP_LAYER0_ATTR1		0x8a0
+
+/*
+ * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
+ */
+#define SUNXI_LCDC_ENABLE		0x000
+#define SUNXI_LCDC_INT0			0x004
+#define SUNXI_LCDC_INT1			0x008
+#define SUNXI_LCDC_TCON0_DOTCLOCK	0x044
+#define SUNXI_LCDC_TCON0_IO_TRI		0x08c
+#define SUNXI_LCDC_TCON1_ENABLE		0x090
+#define SUNXI_LCDC_TCON1_TIMING_SRC	0x094
+#define SUNXI_LCDC_TCON1_TIMING_SCALE	0x098
+#define SUNXI_LCDC_TCON1_TIMING_OUT	0x09c
+#define SUNXI_LCDC_TCON1_TIMING_H	0x0a0
+#define SUNXI_LCDC_TCON1_TIMING_V	0x0a4
+#define SUNXI_LCDC_TCON1_TIMING_SYNC	0x0a8
+#define SUNXI_LCDC_TCON1_IO_TRI		0x0f4
+
+/*
+ * HDMI regs.
+ */
+#define SUNXI_HDMI_CTRL			0x004
+#define SUNXI_HDMI_INT_CTRL		0x008
+#define SUNXI_HDMI_HPD			0x00c
+#define SUNXI_HDMI_VIDEO_CTRL		0x010
+#define SUNXI_HDMI_VIDEO_SIZE		0x014
+#define SUNXI_HDMI_VIDEO_BP		0x018
+#define SUNXI_HDMI_VIDEO_FP		0x01c
+#define SUNXI_HDMI_VIDEO_SPW		0x020
+#define SUNXI_HDMI_VIDEO_POLARITY	0x024
+#define SUNXI_HDMI_TX_DRIVER0		0x200
+#define SUNXI_HDMI_TX_DRIVER1		0x204
+#define SUNXI_HDMI_TX_DRIVER2		0x208
+#define SUNXI_HDMI_TX_DRIVER3		0x20C
+
+static int
+sunxi_hdmi_hpd_detect(void)
+{
+	void *ccmu = (void *) SUNXI_CCM_BASE;
+	void *hdmi = (void *) SUNXI_HDMI_BASE;
+
+	/* set video pll1 to 300MHz */
+	sunxi_io_write(ccmu, SUNXI_CCMU_PLL7_CFG, 0x8010D064);
+
+	/* Set hdmi parent to video pll1 */
+	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x01000000, 0x03000000);
+
+	/* set ahb gating to pass */
+	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x800, 0x800);
+
+	/* clk on */
+	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x80000000, 0x80000000);
+
+	sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0x80000000);
+	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xA0800000);
+
+	udelay(100);
+
+	if (sunxi_io_read(hdmi, SUNXI_HDMI_HPD) & 0x01)
+		return 1;
+
+	/* no need to keep these running. */
+	sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0);
+	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0, 0x80000000);
+	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0, 0x800);
+	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL7_CFG, 0, 0x80000000);
+
+	return 0;
+}
+
+static int
+sunxi_pll5_frequency(void)
+{
+	void *ccmu = (void *) SUNXI_CCM_BASE;
+	unsigned int pll5 = sunxi_io_read(ccmu, SUNXI_CCMU_PLL5_CFG);
+	int n, k, p;
+
+	n = (pll5 >> 8) & 0x1F;
+	k = ((pll5 >> 4) & 0x03) + 1;
+	p = (pll5 >> 16) & 0x03;
+
+	return (24000 * n * k) >> p;
+}
+
+static void
+sunxi_composer_init(void)
+{
+	void *ccmu = (void *) SUNXI_CCM_BASE;
+	void *composer = (void *) SUNXI_DE_BE0_BASE;
+	int pll5 = sunxi_pll5_frequency();
+	int halve;
+
+	if (pll5 < 300000)
+		halve = 0;
+	else
+		halve = 1;
+
+	/* reset off */
+	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x40000000, 0x40000000);
+
+	/* set to pll5 */
+	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x02000000, 0x03000000);
+
+	if (halve)
+		sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x01, 0x03);
+	else
+		sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0, 0x03);
+
+	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x1000, 0x1000);
+	sunxi_io_mask(ccmu, SUNXI_CCMU_DRAM_CLK_GATING,
+		      0x04000000, 0x04000000);
+
+	/* enable */
+	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x80000000, 0x80000000);
+
+	/* engine bug, clear registers after reset. */
+	{
+		/*
+		 * Since uboot prototypes but never declares memset_io, we
+		 * have to do this by hand.
+		 */
+		int i;
+
+		for (i = 0x0800; i < 0x1000; i += 4)
+			sunxi_io_write(composer, i, 0);
+	}
+
+	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x01, 0x01);
+}
+
+static void
+sunxi_composer_mode_set(struct fb_videomode *mode, unsigned int address)
+{
+	void *composer = (void *) SUNXI_DE_BE0_BASE;
+#define SUNXI_FORMAT_XRGB8888 0x09
+	unsigned int format = SUNXI_FORMAT_XRGB8888;
+
+	/* enable */
+	sunxi_io_write(composer, SUNXI_COMP_DISP_SIZE,
+		       ((mode->yres - 1) << 16) | (mode->xres - 1));
+
+	sunxi_io_write(composer, SUNXI_COMP_LAYER0_SIZE,
+		       ((mode->yres - 1) << 16) | (mode->xres - 1));
+	sunxi_io_write(composer, SUNXI_COMP_LAYER0_STRIDE, mode->xres << 5);
+	sunxi_io_write(composer, SUNXI_COMP_LAYER0_ADDR_LOW, address << 3);
+	sunxi_io_mask(composer, SUNXI_COMP_LAYER_ADDR_HIGH,
+		      address >> 29, 0xFF);
+
+	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, format << 8, 0x0F00);
+
+	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x04);
+	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x03);
+
+	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x100, 0x100);
+}
+
+static void
+sunxi_lcdc_pll_set(int dotclock)
+{
+	void *ccmu = (void *) SUNXI_CCM_BASE;
+	int value, n, m, diff;
+	int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
+	int best_double = 0;
+
+	if ((dotclock < 20000) || (dotclock > 400000)) {
+		printf("%s: Error: dotclock %d is out of range.\n",
+		       __func__, dotclock);
+		return;
+	}
+
+	for (m = 16; m > 0; m--) {
+		n = (m * dotclock) / 3000;
+
+		if ((n > 9) && (n < 128)) {
+			value = (3000 * n) / m;
+			diff = value - dotclock;
+			if (diff < 0)
+				diff = -diff;
+
+			if (diff < best_diff) {
+				best_diff = diff;
+				best_m = m;
+				best_n = n;
+				best_double = 0;
+			}
+		}
+
+		n++;
+		if ((n > 9) && (n < 128)) {
+			value = (3000 * n) / m;
+			diff = abs(value - dotclock);
+			if (diff < 0)
+				diff = -diff;
+
+			if (diff < best_diff) {
+				best_diff = diff;
+				best_m = m;
+				best_n = n;
+				best_double = 0;
+			}
+		}
+
+		/* these are just duplicates. */
+		if (!(m & 1))
+			continue;
+
+		n = (m * dotclock) / 6000;
+		if ((n > 63) && (n < 128)) {
+			value = (6000 * n) / m;
+			diff = abs(value - dotclock);
+			if (diff < 0)
+				diff = -diff;
+
+			if (diff < best_diff) {
+				best_diff = diff;
+				best_m = m;
+				best_n = n;
+				best_double = 1;
+			}
+		}
+
+		n++;
+		if ((n > 63) && (n < 128)) {
+			value = (6000 * n) / m;
+			diff = abs(value - dotclock);
+			if (diff < 0)
+				diff = -diff;
+
+			if (diff < best_diff) {
+				best_diff = diff;
+				best_m = m;
+				best_n = n;
+				best_double = 1;
+			}
+		}
+	}
+
+#if 0
+	if (best_double)
+		printf("dotclock: %06dkHz = %06dkHz: (2 * 3MHz * %d) / %d\n",
+		       dotclock, (6000 * best_n) / best_m, best_n, best_m);
+	else
+		printf("dotclock: %06dkHz = %06dkHz: (3MHz * %d) / %d\n",
+		       dotclock, (3000 * best_n) / best_m, best_n, best_m);
+#endif
+
+	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x80000000, 0x80000000);
+	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x8000, 0x8000);
+	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, best_n, 0x7F);
+
+	if (best_double)
+		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK,
+			      0x02000000, 0x03000000);
+	else
+		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK,
+			      0, 0x03000000);
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, best_m - 1, 0x0F);
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800);
+
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000);
+}
+
+static void
+sunxi_lcdc_init(void)
+{
+	void *ccmu = (void *) SUNXI_CCM_BASE;
+	void *lcdc = (void *) SUNXI_LCD0_BASE;
+
+	/* Pll1 was already enabled in hpd detect. */
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x01000000, 0x03000000);
+
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x01000000, 0x03000000);
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800);
+
+	/* just randomly set it@30MHz */
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x09, 0x0F);
+
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x40000000, 0x40000000);
+
+	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x10, 0x10);
+
+	/* toggle ch0 clock */
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x80000000, 0x80000000);
+	while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH0_CLK) & 0x80000000)
+		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0, 0x80000000);
+
+	/* toggle ch1 s1 & s2 clocks */
+	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000);
+	while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK) & 0x80008000)
+		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x80008000);
+
+	sunxi_io_write(lcdc, SUNXI_LCDC_ENABLE, 0);
+
+	sunxi_io_write(lcdc, SUNXI_LCDC_INT0, 0);
+	sunxi_io_write(lcdc, SUNXI_LCDC_INT1, 0x20);
+
+	/*
+	 * disable tcon0 dot clock:
+	 * This doesn't disable the dotclock, it just nulls the divider.
+	 */
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_DOTCLOCK, 0xF0000000);
+
+	/* all io lines disabled. */
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_IO_TRI, 0x0FFFFFFF);
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x0FFFFFFF);
+}
+
+static void
+sunxi_lcdc_mode_set(struct fb_videomode *mode)
+{
+	void *lcdc = (void *) SUNXI_LCD0_BASE;
+	int total;
+
+	/* use tcon1 */
+	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x01, 0x01);
+
+	/* enabled, 0x1E start delay */
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_ENABLE, 0x800001E0);
+
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SRC,
+		       ((mode->xres - 1) << 16) | (mode->yres - 1));
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SCALE,
+		       ((mode->xres - 1) << 16) | (mode->yres - 1));
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_OUT,
+		       ((mode->xres - 1) << 16) | (mode->yres - 1));
+
+	total = mode->left_margin + mode->xres + mode->right_margin +
+		mode->hsync_len;
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_H,
+		       ((total - 1) << 16) |
+		       (mode->hsync_len + mode->left_margin - 1));
+
+	total = mode->upper_margin + mode->yres + mode->lower_margin +
+		mode->vsync_len;
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_V,
+		       ((total *  2) << 16) |
+		       (mode->vsync_len + mode->upper_margin - 1));
+
+	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SYNC,
+		       ((mode->hsync_len - 1) << 16) | (mode->vsync_len - 1));
+
+	sunxi_lcdc_pll_set(mode->pixclock);
+}
+
+static void
+sunxi_hdmi_mode_set(struct fb_videomode *mode)
+{
+	void *ccmu = (void *) SUNXI_CCM_BASE;
+	void *hdmi = (void *) SUNXI_HDMI_BASE;
+	int h, v, tmp;
+
+	sunxi_io_write(hdmi, SUNXI_HDMI_INT_CTRL, 0xFFFFFFFF);
+	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x03FE0000);
+	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xDE000000, 0xDE000000);
+	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x00D8C820);
+	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER2, 0xD2000008);
+	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER3, 0);
+
+	/* use video0 */
+	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER3, 0, 0x00200000);
+
+	tmp = sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK);
+	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER2,
+		      ((tmp & 0x0F) + 1) << 4, 0xF0);
+
+	if (tmp & 0x02000000)
+		sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0, 0x40);
+	else
+		sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x40, 0x40);
+
+	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SIZE,
+		       ((mode->yres - 1) << 16) | (mode->xres - 1));
+
+	h = mode->hsync_len + mode->left_margin;
+	v = mode->vsync_len + mode->upper_margin;
+	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_BP, ((v - 1) << 16) | (h - 1));
+
+	h = mode->right_margin;
+	v = mode->lower_margin;
+	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_FP, ((v - 1) << 16) | (h - 1));
+
+	h = mode->hsync_len;
+	v = mode->vsync_len;
+	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SPW, ((v - 1) << 16) | (h - 1));
+
+	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x01, 0x01);
+	else
+		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x01);
+
+	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x02, 0x02);
+	else
+		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x02);
+}
+
+static void
+sunxi_engines_init(void)
+{
+	sunxi_composer_init();
+	sunxi_lcdc_init();
+}
+
+static void
+sunxi_mode_set(struct fb_videomode *mode, unsigned int address)
+{
+	void *composer = (void *) SUNXI_DE_BE0_BASE;
+	void *lcdc = (void *) SUNXI_LCD0_BASE;
+	void *hdmi = (void *) SUNXI_HDMI_BASE;
+
+	sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0, 0x80000000);
+	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0, 0x80000000);
+	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0, 0x02);
+
+	sunxi_composer_mode_set(mode, address);
+	sunxi_lcdc_mode_set(mode);
+	sunxi_hdmi_mode_set(mode);
+
+	sunxi_io_mask(composer, SUNXI_COMP_REG_CTL, 0x01, 0x01);
+	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x02, 0x02);
+
+	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x80000000, 0x80000000);
+	sunxi_io_mask(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x00000000, 0x03000000);
+
+	udelay(100);
+
+	sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0x80000000, 0x80000000);
+}
+
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
+void
+sunxi_simplefb_setup(void *blob)
+{
+	static GraphicDevice *graphic_device = sunxi_display->graphic_device;
+	const char *name = "simple-framebuffer";
+	const char *format = "x8r8g8b8";
+	fdt32_t cells[2];
+	int offset, stride, ret;
+
+	if (!sunxi_display->enabled)
+		return;
+
+	offset = fdt_add_subnode(blob, 0, "framebuffer");
+	if (offset < 0) {
+		printf("%s: add subnode failed", __func__);
+		return;
+	}
+
+	ret = fdt_setprop(blob, offset, "compatible", name, strlen(name) + 1);
+	if (ret < 0)
+		return;
+
+	stride = graphic_device->winSizeX * graphic_device->gdfBytesPP;
+
+	cells[0] = cpu_to_fdt32(gd->fb_base);
+	cells[1] = cpu_to_fdt32(CONFIG_SUNXI_FB_SIZE);
+	ret = fdt_setprop(blob, offset, "reg", cells, sizeof(cells[0]) * 2);
+	if (ret < 0)
+		return;
+
+	cells[0] = cpu_to_fdt32(graphic_device->winSizeX);
+	ret = fdt_setprop(blob, offset, "width", cells, sizeof(cells[0]));
+	if (ret < 0)
+		return;
+
+	cells[0] = cpu_to_fdt32(graphic_device->winSizeY);
+	ret = fdt_setprop(blob, offset, "height", cells, sizeof(cells[0]));
+	if (ret < 0)
+		return;
+
+	cells[0] = cpu_to_fdt32(stride);
+	ret = fdt_setprop(blob, offset, "stride", cells, sizeof(cells[0]));
+	if (ret < 0)
+		return;
+
+	ret = fdt_setprop(blob, offset, "format", format, strlen(format) + 1);
+	if (ret < 0)
+		return;
+}
+#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
+
+void *
+video_hw_init(void)
+{
+	static GraphicDevice *graphic_device = sunxi_display->graphic_device;
+	/*
+	 * Vesa standard 1024x768 at 60
+	 * 65.0  1024 1032 1176 1344  768 771 777 806  -hsync -vsync
+	 */
+	struct fb_videomode mode = {
+		.name = "1024x768",
+		.refresh = 60,
+		.xres = 1024,
+		.yres = 768,
+		.pixclock = 65000,
+		.left_margin = 160,
+		.right_margin = 24,
+		.upper_margin = 29,
+		.lower_margin = 3,
+		.hsync_len = 136,
+		.vsync_len = 6,
+		.sync = 0,
+		.vmode = 0,
+		.flag = 0,
+	};
+	int ret;
+
+	memset(sunxi_display, 0, sizeof(struct sunxi_display));
+
+	printf("Reserved %dkB of RAM for Framebuffer.\n",
+	       CONFIG_SUNXI_FB_SIZE >> 10);
+	gd->fb_base = gd->ram_top;
+
+	ret = sunxi_hdmi_hpd_detect();
+	if (!ret)
+		return NULL;
+
+	printf("HDMI connected.\n");
+	sunxi_display->enabled = 1;
+
+	printf("Setting up a %s console.\n", mode.name);
+	sunxi_engines_init();
+	sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
+
+	/*
+	 * These are the only members of this structure that are used. All the
+	 * others are driver specific. There is nothing to decribe pitch or
+	 * stride, but we are lucky with our hw.
+	 */
+	graphic_device->frameAdrs = gd->fb_base;
+	graphic_device->gdfIndex = GDF_32BIT_X888RGB;
+	graphic_device->gdfBytesPP = 4;
+	graphic_device->winSizeX = mode.xres;
+	graphic_device->winSizeY = mode.yres;
+
+	return graphic_device;
+}
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 8ab6429..89582b8 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -181,6 +181,40 @@
 #define CONFIG_SUNXI_GPIO
 #define CONFIG_CMD_GPIO
 
+/* Set this if you do not want a uboot fb console */
+#ifndef CONFIG_NO_VIDEO
+#define CONFIG_VIDEO
+#endif
+
+#ifdef CONFIG_VIDEO
+/*
+ * The amount of RAM that is reserved for the FB. This will not show up as
+ * RAM to the kernel, but will be reclaimed by a KMS driver in future.
+ */
+#define CONFIG_SUNXI_FB_SIZE (8 << 20)
+
+/* Do we want to initialize a simple FB? */
+#define CONFIG_VIDEO_DT_SIMPLEFB
+
+#define CONFIG_VIDEO_SUNXI
+
+#define CONFIG_CFB_CONSOLE
+/* allow both serial and cfb console. */
+#define CONFIG_CONSOLE_MUX
+/* this is needed so the above will actually do something */
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV
+/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */
+#define CONFIG_VGA_AS_SINGLE_DEVICE
+
+#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF)
+
+/* To be able to hook simplefb into dt */
+#ifdef CONFIG_VIDEO_DT_SIMPLEFB
+#define CONFIG_OF_BOARD_SETUP
+#endif
+
+#endif /* CONFIG_VIDEO */
+
 /* Ethernet support */
 #ifdef CONFIG_SUNXI_EMAC
 #define CONFIG_MII			/* MII PHY management		*/
-- 
1.7.7

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH] video: add cfb console driver for sunxi
  2014-08-02 16:14 [U-Boot] [PATCH] video: add cfb console driver for sunxi Luc Verhaegen
@ 2014-08-04  8:39 ` Hans de Goede
  2014-08-04 15:05   ` Luc Verhaegen
  2014-08-05 11:56 ` [U-Boot] " Hans de Goede
  1 sibling, 1 reply; 18+ messages in thread
From: Hans de Goede @ 2014-08-04  8:39 UTC (permalink / raw)
  To: u-boot

Hi Luc,

On 08/02/2014 06:14 PM, Luc Verhaegen wrote:
> This adds a fixed mode hdmi driver (lcd to be added in future) for the
> sunxi platform. Current config is such that 8MB is shaved off at the top
> of the RAM. Simplefb support is available for kernels that know how to
> use it.
> 
> Signed-off-by: Luc Verhaegen <libv@skynet.be>

First of all many thanks for your work on this.

ATM I don't have time to do a full review, but I don't expect there
to be too many suprises when I do find the time.

Really my only concern is the handover of the reserved memory, etc. to
the kernel. We need to get a plan in place for that *before* this can
be merged. Note I don't want to raise any artificial barriers here,
I would love to see this merged ASAP. But I don't want to paint us
in a corner where u-boot having hdmi console support makes it harder
to get kms support in the kernel going. I think we can both agree on that.

So I really want to see some plan how this will work in place before merging.
Note just a plan, I don't expect kernel patches ready to be merged for this,
just a good idea / sketch of how all the bits will fit together.

In one of the threads about this there was some discussion about doing a
"flicker free" handover. I agree with you that given that we will be fixed
to 1024x768 in u-boot this won't be realistic. But in the light of that
it would be nice if we could make it so that if none of the stdout and stderr
variables point to vga we don't init the hdmi at all, this will avoid
what ever is attached to first have to sync at 1024x768 and then at its
native resolution when the kernel takes over, and this will also allow
for an easy way to not steal the 8MB of memory for people who care about
that (think headless server which is low on memory)

Regards,

Hans



> ---
>  arch/arm/include/asm/arch-sunxi/sunxi_display.h |   21 +
>  board/sunxi/board.c                             |   14 +
>  drivers/video/Makefile                          |    1 +
>  drivers/video/sunxi_display.c                   |  639 +++++++++++++++++++++++
>  include/configs/sunxi-common.h                  |   34 ++
>  5 files changed, 709 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/include/asm/arch-sunxi/sunxi_display.h
>  create mode 100644 drivers/video/sunxi_display.c
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/sunxi_display.h b/arch/arm/include/asm/arch-sunxi/sunxi_display.h
> new file mode 100644
> index 0000000..4456778
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/sunxi_display.h
> @@ -0,0 +1,21 @@
> +/*
> + * (C) Copyright 2014 Luc Verhaegen <libv@skynet.be>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation's version 2 and any
> + * later version the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef _SUNXI_DISPLAY_H_
> +#define _SUNXI_DISPLAY_H_
> +
> +#ifdef CONFIG_VIDEO_DT_SIMPLEFB
> +void sunxi_simplefb_setup(void *blob);
> +#endif
> +
> +#endif /* _SUNXI_DISPLAY_H_ */
> diff --git a/board/sunxi/board.c b/board/sunxi/board.c
> index 2179e23..e819b12 100644
> --- a/board/sunxi/board.c
> +++ b/board/sunxi/board.c
> @@ -26,6 +26,10 @@
>  #include <asm/io.h>
>  #include <net.h>
>  
> +#ifdef CONFIG_VIDEO
> +#include <asm/arch-sunxi/sunxi_display.h>
> +#endif
> +
>  DECLARE_GLOBAL_DATA_PTR;
>  
>  /* add board specific code here */
> @@ -185,3 +189,13 @@ int misc_init_r(void)
>  	return 0;
>  }
>  #endif
> +
> +#ifdef CONFIG_OF_BOARD_SETUP
> +void
> +ft_board_setup(void *blob, bd_t *bd)
> +{
> +#ifdef CONFIG_VIDEO_DT_SIMPLEFB
> +	sunxi_simplefb_setup(blob);
> +#endif
> +}
> +#endif /* CONFIG_OF_BOARD_SETUP */
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 945f35d..9a25c84 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o
>  obj-$(CONFIG_VIDEO_SED13806) += sed13806.o
>  obj-$(CONFIG_VIDEO_SM501) += sm501.o
>  obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
> +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o
>  obj-$(CONFIG_VIDEO_TEGRA) += tegra.o
>  obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
>  obj-$(CONFIG_FORMIKE) += formike.o
> diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
> new file mode 100644
> index 0000000..251fb67
> --- /dev/null
> +++ b/drivers/video/sunxi_display.c
> @@ -0,0 +1,639 @@
> +/*
> + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
> + *
> + * Display driver for Allwinner SoCs.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation's version 2 and any
> + * later version the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +/*
> + * This driver does nothing but HDMI at a fixed mode right now. At some
> + * point in the near future, LCD and VGA will be added.
> + *
> + * The display driver infrastructure in uboot does not immediately allow for
> + * modeline creation off of edid. The mode is therefor hardcoded to
> + * 1024x768 at 60Hz 32bpp. This is acceptable for most HDMI monitors, but far
> + * from ideal. If so desired, alter the modeline in video_hw_init()
> + */
> +
> +#include <common.h>
> +
> +#include <asm/io.h>
> +#include <asm/global_data.h>
> +#include <video_fb.h>
> +#include <linux/fb.h>
> +#include <asm/arch-sunxi/sunxi_display.h>
> +
> +/* for simplefb */
> +#ifdef CONFIG_OF_BOARD_SETUP
> +#include <libfdt.h>
> +#endif
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct sunxi_display {
> +	GraphicDevice graphic_device[1];
> +	int enabled;
> +} sunxi_display[1];
> +
> +/*
> + * Convenience functions to ease readability, and to provide an easy
> + * comparison with the sunxi kms driver.
> + */
> +static unsigned int
> +sunxi_io_read(void *base, int offset)
> +{
> +	return readl(base + offset);
> +}
> +
> +static void
> +sunxi_io_write(void *base, int offset, unsigned int value)
> +{
> +	writel(value, base + offset);
> +}
> +
> +static void
> +sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask)
> +{
> +	unsigned int tmp = readl(base + offset);
> +
> +	tmp &= ~mask;
> +	tmp |= value & mask;
> +
> +	writel(tmp, base + offset);
> +}
> +
> +/*
> + * CCMU regs: clocks.
> + */
> +#define SUNXI_CCMU_PLL3_CFG		0x010
> +#define SUNXI_CCMU_PLL5_CFG		0x020
> +#define SUNXI_CCMU_PLL7_CFG		0x030
> +#define SUNXI_CCMU_AHB_GATING1		0x064
> +#define SUNXI_CCMU_DRAM_CLK_GATING	0x100
> +#define SUNXI_DE_BE0_CLK		0x104
> +#define SUNXI_LCDC0_CH0_CLK		0x118
> +#define SUNXI_LCDC0_CH1_CLK		0x12C
> +#define SUNXI_CCMU_HDMI_CLK		0x150
> +
> +/*
> + * DEBE regs.
> + *
> + * This is the entity that mixes and matches the different layers and inputs.
> + * Allwinner calls it the back-end, but i like composer better.
> + */
> +#define SUNXI_COMP_MODE			0x800
> +#define SUNXI_COMP_DISP_SIZE		0x808
> +#define SUNXI_COMP_LAYER0_SIZE		0x810
> +#define SUNXI_COMP_LAYER0_POS		0x820
> +#define SUNXI_COMP_LAYER0_STRIDE	0x840
> +#define SUNXI_COMP_LAYER0_ADDR_LOW	0X850
> +#define SUNXI_COMP_LAYER_ADDR_HIGH	0X860
> +#define SUNXI_COMP_REG_CTL		0X870
> +#define SUNXI_COMP_LAYER0_ATTR0		0x890
> +#define SUNXI_COMP_LAYER0_ATTR1		0x8a0
> +
> +/*
> + * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
> + */
> +#define SUNXI_LCDC_ENABLE		0x000
> +#define SUNXI_LCDC_INT0			0x004
> +#define SUNXI_LCDC_INT1			0x008
> +#define SUNXI_LCDC_TCON0_DOTCLOCK	0x044
> +#define SUNXI_LCDC_TCON0_IO_TRI		0x08c
> +#define SUNXI_LCDC_TCON1_ENABLE		0x090
> +#define SUNXI_LCDC_TCON1_TIMING_SRC	0x094
> +#define SUNXI_LCDC_TCON1_TIMING_SCALE	0x098
> +#define SUNXI_LCDC_TCON1_TIMING_OUT	0x09c
> +#define SUNXI_LCDC_TCON1_TIMING_H	0x0a0
> +#define SUNXI_LCDC_TCON1_TIMING_V	0x0a4
> +#define SUNXI_LCDC_TCON1_TIMING_SYNC	0x0a8
> +#define SUNXI_LCDC_TCON1_IO_TRI		0x0f4
> +
> +/*
> + * HDMI regs.
> + */
> +#define SUNXI_HDMI_CTRL			0x004
> +#define SUNXI_HDMI_INT_CTRL		0x008
> +#define SUNXI_HDMI_HPD			0x00c
> +#define SUNXI_HDMI_VIDEO_CTRL		0x010
> +#define SUNXI_HDMI_VIDEO_SIZE		0x014
> +#define SUNXI_HDMI_VIDEO_BP		0x018
> +#define SUNXI_HDMI_VIDEO_FP		0x01c
> +#define SUNXI_HDMI_VIDEO_SPW		0x020
> +#define SUNXI_HDMI_VIDEO_POLARITY	0x024
> +#define SUNXI_HDMI_TX_DRIVER0		0x200
> +#define SUNXI_HDMI_TX_DRIVER1		0x204
> +#define SUNXI_HDMI_TX_DRIVER2		0x208
> +#define SUNXI_HDMI_TX_DRIVER3		0x20C
> +
> +static int
> +sunxi_hdmi_hpd_detect(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *hdmi = (void *) SUNXI_HDMI_BASE;
> +
> +	/* set video pll1 to 300MHz */
> +	sunxi_io_write(ccmu, SUNXI_CCMU_PLL7_CFG, 0x8010D064);
> +
> +	/* Set hdmi parent to video pll1 */
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x01000000, 0x03000000);
> +
> +	/* set ahb gating to pass */
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x800, 0x800);
> +
> +	/* clk on */
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x80000000, 0x80000000);
> +
> +	sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0x80000000);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xA0800000);
> +
> +	udelay(100);
> +
> +	if (sunxi_io_read(hdmi, SUNXI_HDMI_HPD) & 0x01)
> +		return 1;
> +
> +	/* no need to keep these running. */
> +	sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0, 0x80000000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0, 0x800);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL7_CFG, 0, 0x80000000);
> +
> +	return 0;
> +}
> +
> +static int
> +sunxi_pll5_frequency(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	unsigned int pll5 = sunxi_io_read(ccmu, SUNXI_CCMU_PLL5_CFG);
> +	int n, k, p;
> +
> +	n = (pll5 >> 8) & 0x1F;
> +	k = ((pll5 >> 4) & 0x03) + 1;
> +	p = (pll5 >> 16) & 0x03;
> +
> +	return (24000 * n * k) >> p;
> +}
> +
> +static void
> +sunxi_composer_init(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *composer = (void *) SUNXI_DE_BE0_BASE;
> +	int pll5 = sunxi_pll5_frequency();
> +	int halve;
> +
> +	if (pll5 < 300000)
> +		halve = 0;
> +	else
> +		halve = 1;
> +
> +	/* reset off */
> +	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x40000000, 0x40000000);
> +
> +	/* set to pll5 */
> +	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x02000000, 0x03000000);
> +
> +	if (halve)
> +		sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x01, 0x03);
> +	else
> +		sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0, 0x03);
> +
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x1000, 0x1000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_DRAM_CLK_GATING,
> +		      0x04000000, 0x04000000);
> +
> +	/* enable */
> +	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x80000000, 0x80000000);
> +
> +	/* engine bug, clear registers after reset. */
> +	{
> +		/*
> +		 * Since uboot prototypes but never declares memset_io, we
> +		 * have to do this by hand.
> +		 */
> +		int i;
> +
> +		for (i = 0x0800; i < 0x1000; i += 4)
> +			sunxi_io_write(composer, i, 0);
> +	}
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x01, 0x01);
> +}
> +
> +static void
> +sunxi_composer_mode_set(struct fb_videomode *mode, unsigned int address)
> +{
> +	void *composer = (void *) SUNXI_DE_BE0_BASE;
> +#define SUNXI_FORMAT_XRGB8888 0x09
> +	unsigned int format = SUNXI_FORMAT_XRGB8888;
> +
> +	/* enable */
> +	sunxi_io_write(composer, SUNXI_COMP_DISP_SIZE,
> +		       ((mode->yres - 1) << 16) | (mode->xres - 1));
> +
> +	sunxi_io_write(composer, SUNXI_COMP_LAYER0_SIZE,
> +		       ((mode->yres - 1) << 16) | (mode->xres - 1));
> +	sunxi_io_write(composer, SUNXI_COMP_LAYER0_STRIDE, mode->xres << 5);
> +	sunxi_io_write(composer, SUNXI_COMP_LAYER0_ADDR_LOW, address << 3);
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER_ADDR_HIGH,
> +		      address >> 29, 0xFF);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, format << 8, 0x0F00);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x04);
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x03);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x100, 0x100);
> +}
> +
> +static void
> +sunxi_lcdc_pll_set(int dotclock)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	int value, n, m, diff;
> +	int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
> +	int best_double = 0;
> +
> +	if ((dotclock < 20000) || (dotclock > 400000)) {
> +		printf("%s: Error: dotclock %d is out of range.\n",
> +		       __func__, dotclock);
> +		return;
> +	}
> +
> +	for (m = 16; m > 0; m--) {
> +		n = (m * dotclock) / 3000;
> +
> +		if ((n > 9) && (n < 128)) {
> +			value = (3000 * n) / m;
> +			diff = value - dotclock;
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 0;
> +			}
> +		}
> +
> +		n++;
> +		if ((n > 9) && (n < 128)) {
> +			value = (3000 * n) / m;
> +			diff = abs(value - dotclock);
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 0;
> +			}
> +		}
> +
> +		/* these are just duplicates. */
> +		if (!(m & 1))
> +			continue;
> +
> +		n = (m * dotclock) / 6000;
> +		if ((n > 63) && (n < 128)) {
> +			value = (6000 * n) / m;
> +			diff = abs(value - dotclock);
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 1;
> +			}
> +		}
> +
> +		n++;
> +		if ((n > 63) && (n < 128)) {
> +			value = (6000 * n) / m;
> +			diff = abs(value - dotclock);
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 1;
> +			}
> +		}
> +	}
> +
> +#if 0
> +	if (best_double)
> +		printf("dotclock: %06dkHz = %06dkHz: (2 * 3MHz * %d) / %d\n",
> +		       dotclock, (6000 * best_n) / best_m, best_n, best_m);
> +	else
> +		printf("dotclock: %06dkHz = %06dkHz: (3MHz * %d) / %d\n",
> +		       dotclock, (3000 * best_n) / best_m, best_n, best_m);
> +#endif
> +
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x80000000, 0x80000000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x8000, 0x8000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, best_n, 0x7F);
> +
> +	if (best_double)
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK,
> +			      0x02000000, 0x03000000);
> +	else
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK,
> +			      0, 0x03000000);
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, best_m - 1, 0x0F);
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800);
> +
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000);
> +}
> +
> +static void
> +sunxi_lcdc_init(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *lcdc = (void *) SUNXI_LCD0_BASE;
> +
> +	/* Pll1 was already enabled in hpd detect. */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x01000000, 0x03000000);
> +
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x01000000, 0x03000000);
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800);
> +
> +	/* just randomly set it at 30MHz */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x09, 0x0F);
> +
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x40000000, 0x40000000);
> +
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x10, 0x10);
> +
> +	/* toggle ch0 clock */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x80000000, 0x80000000);
> +	while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH0_CLK) & 0x80000000)
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0, 0x80000000);
> +
> +	/* toggle ch1 s1 & s2 clocks */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000);
> +	while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK) & 0x80008000)
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x80008000);
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_ENABLE, 0);
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_INT0, 0);
> +	sunxi_io_write(lcdc, SUNXI_LCDC_INT1, 0x20);
> +
> +	/*
> +	 * disable tcon0 dot clock:
> +	 * This doesn't disable the dotclock, it just nulls the divider.
> +	 */
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_DOTCLOCK, 0xF0000000);
> +
> +	/* all io lines disabled. */
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_IO_TRI, 0x0FFFFFFF);
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x0FFFFFFF);
> +}
> +
> +static void
> +sunxi_lcdc_mode_set(struct fb_videomode *mode)
> +{
> +	void *lcdc = (void *) SUNXI_LCD0_BASE;
> +	int total;
> +
> +	/* use tcon1 */
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x01, 0x01);
> +
> +	/* enabled, 0x1E start delay */
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_ENABLE, 0x800001E0);
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SRC,
> +		       ((mode->xres - 1) << 16) | (mode->yres - 1));
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SCALE,
> +		       ((mode->xres - 1) << 16) | (mode->yres - 1));
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_OUT,
> +		       ((mode->xres - 1) << 16) | (mode->yres - 1));
> +
> +	total = mode->left_margin + mode->xres + mode->right_margin +
> +		mode->hsync_len;
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_H,
> +		       ((total - 1) << 16) |
> +		       (mode->hsync_len + mode->left_margin - 1));
> +
> +	total = mode->upper_margin + mode->yres + mode->lower_margin +
> +		mode->vsync_len;
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_V,
> +		       ((total *  2) << 16) |
> +		       (mode->vsync_len + mode->upper_margin - 1));
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SYNC,
> +		       ((mode->hsync_len - 1) << 16) | (mode->vsync_len - 1));
> +
> +	sunxi_lcdc_pll_set(mode->pixclock);
> +}
> +
> +static void
> +sunxi_hdmi_mode_set(struct fb_videomode *mode)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *hdmi = (void *) SUNXI_HDMI_BASE;
> +	int h, v, tmp;
> +
> +	sunxi_io_write(hdmi, SUNXI_HDMI_INT_CTRL, 0xFFFFFFFF);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x03FE0000);
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xDE000000, 0xDE000000);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x00D8C820);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER2, 0xD2000008);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER3, 0);
> +
> +	/* use video0 */
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER3, 0, 0x00200000);
> +
> +	tmp = sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK);
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER2,
> +		      ((tmp & 0x0F) + 1) << 4, 0xF0);
> +
> +	if (tmp & 0x02000000)
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0, 0x40);
> +	else
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x40, 0x40);
> +
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SIZE,
> +		       ((mode->yres - 1) << 16) | (mode->xres - 1));
> +
> +	h = mode->hsync_len + mode->left_margin;
> +	v = mode->vsync_len + mode->upper_margin;
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_BP, ((v - 1) << 16) | (h - 1));
> +
> +	h = mode->right_margin;
> +	v = mode->lower_margin;
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_FP, ((v - 1) << 16) | (h - 1));
> +
> +	h = mode->hsync_len;
> +	v = mode->vsync_len;
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SPW, ((v - 1) << 16) | (h - 1));
> +
> +	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x01, 0x01);
> +	else
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x01);
> +
> +	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x02, 0x02);
> +	else
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x02);
> +}
> +
> +static void
> +sunxi_engines_init(void)
> +{
> +	sunxi_composer_init();
> +	sunxi_lcdc_init();
> +}
> +
> +static void
> +sunxi_mode_set(struct fb_videomode *mode, unsigned int address)
> +{
> +	void *composer = (void *) SUNXI_DE_BE0_BASE;
> +	void *lcdc = (void *) SUNXI_LCD0_BASE;
> +	void *hdmi = (void *) SUNXI_HDMI_BASE;
> +
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0, 0x80000000);
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0, 0x80000000);
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0, 0x02);
> +
> +	sunxi_composer_mode_set(mode, address);
> +	sunxi_lcdc_mode_set(mode);
> +	sunxi_hdmi_mode_set(mode);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_REG_CTL, 0x01, 0x01);
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x02, 0x02);
> +
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x80000000, 0x80000000);
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x00000000, 0x03000000);
> +
> +	udelay(100);
> +
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0x80000000, 0x80000000);
> +}
> +
> +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
> +void
> +sunxi_simplefb_setup(void *blob)
> +{
> +	static GraphicDevice *graphic_device = sunxi_display->graphic_device;
> +	const char *name = "simple-framebuffer";
> +	const char *format = "x8r8g8b8";
> +	fdt32_t cells[2];
> +	int offset, stride, ret;
> +
> +	if (!sunxi_display->enabled)
> +		return;
> +
> +	offset = fdt_add_subnode(blob, 0, "framebuffer");
> +	if (offset < 0) {
> +		printf("%s: add subnode failed", __func__);
> +		return;
> +	}
> +
> +	ret = fdt_setprop(blob, offset, "compatible", name, strlen(name) + 1);
> +	if (ret < 0)
> +		return;
> +
> +	stride = graphic_device->winSizeX * graphic_device->gdfBytesPP;
> +
> +	cells[0] = cpu_to_fdt32(gd->fb_base);
> +	cells[1] = cpu_to_fdt32(CONFIG_SUNXI_FB_SIZE);
> +	ret = fdt_setprop(blob, offset, "reg", cells, sizeof(cells[0]) * 2);
> +	if (ret < 0)
> +		return;
> +
> +	cells[0] = cpu_to_fdt32(graphic_device->winSizeX);
> +	ret = fdt_setprop(blob, offset, "width", cells, sizeof(cells[0]));
> +	if (ret < 0)
> +		return;
> +
> +	cells[0] = cpu_to_fdt32(graphic_device->winSizeY);
> +	ret = fdt_setprop(blob, offset, "height", cells, sizeof(cells[0]));
> +	if (ret < 0)
> +		return;
> +
> +	cells[0] = cpu_to_fdt32(stride);
> +	ret = fdt_setprop(blob, offset, "stride", cells, sizeof(cells[0]));
> +	if (ret < 0)
> +		return;
> +
> +	ret = fdt_setprop(blob, offset, "format", format, strlen(format) + 1);
> +	if (ret < 0)
> +		return;
> +}
> +#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
> +
> +void *
> +video_hw_init(void)
> +{
> +	static GraphicDevice *graphic_device = sunxi_display->graphic_device;
> +	/*
> +	 * Vesa standard 1024x768 at 60
> +	 * 65.0  1024 1032 1176 1344  768 771 777 806  -hsync -vsync
> +	 */
> +	struct fb_videomode mode = {
> +		.name = "1024x768",
> +		.refresh = 60,
> +		.xres = 1024,
> +		.yres = 768,
> +		.pixclock = 65000,
> +		.left_margin = 160,
> +		.right_margin = 24,
> +		.upper_margin = 29,
> +		.lower_margin = 3,
> +		.hsync_len = 136,
> +		.vsync_len = 6,
> +		.sync = 0,
> +		.vmode = 0,
> +		.flag = 0,
> +	};
> +	int ret;
> +
> +	memset(sunxi_display, 0, sizeof(struct sunxi_display));
> +
> +	printf("Reserved %dkB of RAM for Framebuffer.\n",
> +	       CONFIG_SUNXI_FB_SIZE >> 10);
> +	gd->fb_base = gd->ram_top;
> +
> +	ret = sunxi_hdmi_hpd_detect();
> +	if (!ret)
> +		return NULL;
> +
> +	printf("HDMI connected.\n");
> +	sunxi_display->enabled = 1;
> +
> +	printf("Setting up a %s console.\n", mode.name);
> +	sunxi_engines_init();
> +	sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
> +
> +	/*
> +	 * These are the only members of this structure that are used. All the
> +	 * others are driver specific. There is nothing to decribe pitch or
> +	 * stride, but we are lucky with our hw.
> +	 */
> +	graphic_device->frameAdrs = gd->fb_base;
> +	graphic_device->gdfIndex = GDF_32BIT_X888RGB;
> +	graphic_device->gdfBytesPP = 4;
> +	graphic_device->winSizeX = mode.xres;
> +	graphic_device->winSizeY = mode.yres;
> +
> +	return graphic_device;
> +}
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index 8ab6429..89582b8 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -181,6 +181,40 @@
>  #define CONFIG_SUNXI_GPIO
>  #define CONFIG_CMD_GPIO
>  
> +/* Set this if you do not want a uboot fb console */
> +#ifndef CONFIG_NO_VIDEO
> +#define CONFIG_VIDEO
> +#endif
> +
> +#ifdef CONFIG_VIDEO
> +/*
> + * The amount of RAM that is reserved for the FB. This will not show up as
> + * RAM to the kernel, but will be reclaimed by a KMS driver in future.
> + */
> +#define CONFIG_SUNXI_FB_SIZE (8 << 20)
> +
> +/* Do we want to initialize a simple FB? */
> +#define CONFIG_VIDEO_DT_SIMPLEFB
> +
> +#define CONFIG_VIDEO_SUNXI
> +
> +#define CONFIG_CFB_CONSOLE
> +/* allow both serial and cfb console. */
> +#define CONFIG_CONSOLE_MUX
> +/* this is needed so the above will actually do something */
> +#define CONFIG_SYS_CONSOLE_IS_IN_ENV
> +/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */
> +#define CONFIG_VGA_AS_SINGLE_DEVICE
> +
> +#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF)
> +
> +/* To be able to hook simplefb into dt */
> +#ifdef CONFIG_VIDEO_DT_SIMPLEFB
> +#define CONFIG_OF_BOARD_SETUP
> +#endif
> +
> +#endif /* CONFIG_VIDEO */
> +
>  /* Ethernet support */
>  #ifdef CONFIG_SUNXI_EMAC
>  #define CONFIG_MII			/* MII PHY management		*/
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH] video: add cfb console driver for sunxi
  2014-08-04  8:39 ` Hans de Goede
@ 2014-08-04 15:05   ` Luc Verhaegen
  2014-08-04 15:31     ` [U-Boot] [linux-sunxi] " Henrik Nordström
  2014-08-05 21:03     ` Maxime Ripard
  0 siblings, 2 replies; 18+ messages in thread
From: Luc Verhaegen @ 2014-08-04 15:05 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote:
> Hi Luc,
> 
> First of all many thanks for your work on this.
> 
> ATM I don't have time to do a full review, but I don't expect there
> to be too many suprises when I do find the time.
> 
> Really my only concern is the handover of the reserved memory, etc. to
> the kernel. We need to get a plan in place for that *before* this can
> be merged. Note I don't want to raise any artificial barriers here,
> I would love to see this merged ASAP. But I don't want to paint us
> in a corner where u-boot having hdmi console support makes it harder
> to get kms support in the kernel going. I think we can both agree on that.
>
> So I really want to see some plan how this will work in place before merging.
> Note just a plan, I don't expect kernel patches ready to be merged for this,
> just a good idea / sketch of how all the bits will fit together.

Memory is not the biggest worry.

Some kernel code needs to claim clocks if the mode is to cleanly survive 
the start of the kernel. If not, there is no coming back until a proper 
display driver runs. If the simplefb driver claims these clocks, then 
the simplefb driver also must release these clocks, and this driver 
should then never be started again, so it should set the simplefb dt 
node status to "disabled".

But that's not the full extent of this story. If we have a kms driver, 
then we need to claim these clocks, and set a proper mode on the hw. So 
the simplefb driver claiming these resources must've properly unclaimed 
them by then, _and_ have set the dt node to disabled. This kills your 
flicker-free right here unless there is a clean way for the kms driver 
to reclaim the clocks before the simplefb driver unclaims them.

But... What do we do when u-boot sets up cfb, without setting up a
simplefb node in the dt. Or what do we do when a simplefb node is set 
up, but no simplefb code is included in the kernel? Well, we then either 
need to claim the clocks, and make sure that nothing else touches the 
memory, or we need to cleanly disable the display engine. But which do 
we choose, do we keep the u-boot output forever, or do we sync off when 
the kernel starts?

Suddenly, simplefb doesn't look as simple anymore. It's turned into 
quite the mess. Life is easy when you are called rpi, and you sweep 
everything under the videocore rug, and do everything behind the lesser 
cores back. But if you want to solve this properly, then you end up 
smearing bits of simplefb driver code all over the kernel tree.

As for memory, that's closely tied into the clock code, as whatever code
claims or disables the clocks for the display engine, that's also where 
the dt node gets set to disabled, and thus also where the memory either 
is added to some cma area directly, released from (upcoming) reserved 
memory, or forgotten. Simplefb at least gives us a nice handle on the 
location and size of the memory, so we can always find a workable 
solution.

So i don't think the memory issue is as important. We already give the
kernel a nice handle on that. How the kernel wishes to handle it in 
detail is then pretty much up to the kernel, and i expect the kernels 
behaviour to change when kms comes out and i have to think about dealing 
with simplefb.

Clocks are quite a bit more crucial in this context. How the memory 
is handled needs to follow how the clocks are handled.

> In one of the threads about this there was some discussion about doing a
> "flicker free" handover. I agree with you that given that we will be fixed
> to 1024x768 in u-boot this won't be realistic. But in the light of that
> it would be nice if we could make it so that if none of the stdout and stderr
> variables point to vga we don't init the hdmi at all, this will avoid
> what ever is attached to first have to sync at 1024x768 and then at its
> native resolution when the kernel takes over, and this will also allow
> for an easy way to not steal the 8MB of memory for people who care about
> that (think headless server which is low on memory)

That's not how u-boot or the console code works.

First off, this stdout/stderr variable setting, that's all handled after 
the driver has been loaded and an (extra) console device is created. The 
cfb console driver is created because of a build time config, but it is 
allowed to fail (in our case, because HPD says nothing is attached).

Iirc, without iomux, the last created console driver is the one that 
gets stdout, stderr and stdin, so you lose the UART console. With iomux, 
you always need to load env for anything but the uart console to work. 
This means that you can have both cfb and uart working side by side, but 
you do not get anything on cfb unless the env is set as such.

For a future spin of this patch, the logic around enabling this code 
will be swapped around. People will have to manually add VIDEO to their 
board config. There's just to many hairy cornercases and tough to answer 
"what if"s here, when you actually start thinking things through, to 
keep this as the default.

Luc Verhaegen.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-04 15:05   ` Luc Verhaegen
@ 2014-08-04 15:31     ` Henrik Nordström
  2014-08-04 16:53       ` Michal Suchanek
  2014-08-04 17:28       ` Luc Verhaegen
  2014-08-05 21:03     ` Maxime Ripard
  1 sibling, 2 replies; 18+ messages in thread
From: Henrik Nordström @ 2014-08-04 15:31 UTC (permalink / raw)
  To: u-boot

m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen:
> But... What do we do when u-boot sets up cfb, without setting up a
> simplefb node in the dt. Or what do we do when a simplefb node is set 
> up, but no simplefb code is included in the kernel? Well, we then either 
> need to claim the clocks, and make sure that nothing else touches the 
> memory, or we need to cleanly disable the display engine. But which do 
> we choose, do we keep the u-boot output forever, or do we sync off when 
> the kernel starts?

And what happens if we simply ignore it? Is there a risk of anything
burning beyond software repair? If not, ignore it. There is no need to
support all incompatible mixes even if it means some people will see
strange fireworks on their screens when not following the software
requirements.

It's really no different from booting a kernel with wrong dt, or using a
u-boot with wrong DRAM settings etc. An incompatible mix which is not
meant to function properly.

If you use a u-boot with this framebuffer support then you must also
either use a kernel which supports being booted in such state, or make
sure u-boot shuts things off before handing over to the kernel.

If we can handle the situation gracefully in the kernel then fine, but
it's by no means required, or even desired to spend any effort or even
any serious thoughts on before compatible setups works.

Regards
Henrik

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-04 15:31     ` [U-Boot] [linux-sunxi] " Henrik Nordström
@ 2014-08-04 16:53       ` Michal Suchanek
  2014-08-04 21:26         ` Henrik Nordström
  2014-08-04 17:28       ` Luc Verhaegen
  1 sibling, 1 reply; 18+ messages in thread
From: Michal Suchanek @ 2014-08-04 16:53 UTC (permalink / raw)
  To: u-boot

On 4 August 2014 17:31, Henrik Nordstr?m <henrik@henriknordstrom.net> wrote:
> m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen:
>> But... What do we do when u-boot sets up cfb, without setting up a
>> simplefb node in the dt. Or what do we do when a simplefb node is set
>> up, but no simplefb code is included in the kernel? Well, we then either
>> need to claim the clocks, and make sure that nothing else touches the
>> memory, or we need to cleanly disable the display engine. But which do
>> we choose, do we keep the u-boot output forever, or do we sync off when
>> the kernel starts?
>
> And what happens if we simply ignore it? Is there a risk of anything
> burning beyond software repair? If not, ignore it. There is no need to
> support all incompatible mixes even if it means some people will see
> strange fireworks on their screens when not following the software
> requirements.
>

Then you have to define what is compatible.

eg. you can define that if you do have simplefb in u-boot you should
have it in kernel.

If you do not have simplefb in kernel the fb memory may get reused and
the clocks should get disabled as unused, eventually. Unless you set
the debug option not to disable them. And KMS might eventually take
over reprogramming or re-enabling the clocks again if you have it.

Or as pointed out earlier you might find this unacceptable and even
with simplefb compiled out the KMS driver would need enough simplefb
logic to analyze the simplefb DT node and reuse the clocks and memory
without reprogramming.

With both simplefb and KMS you need the KMS driver to take over after
simplefb. This is handled more or less gracefully with vesafb/offb/..
and whatever approach is used there might be of some use as example
and the flicker-freeness of that approach as Linux standard.

Thanks

Michal

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-04 15:31     ` [U-Boot] [linux-sunxi] " Henrik Nordström
  2014-08-04 16:53       ` Michal Suchanek
@ 2014-08-04 17:28       ` Luc Verhaegen
  2014-08-04 22:10         ` Henrik Nordström
  1 sibling, 1 reply; 18+ messages in thread
From: Luc Verhaegen @ 2014-08-04 17:28 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 04, 2014 at 05:31:36PM +0200, Henrik Nordstr?m wrote:
> m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen:
> > But... What do we do when u-boot sets up cfb, without setting up a
> > simplefb node in the dt. Or what do we do when a simplefb node is set 
> > up, but no simplefb code is included in the kernel? Well, we then either 
> > need to claim the clocks, and make sure that nothing else touches the 
> > memory, or we need to cleanly disable the display engine. But which do 
> > we choose, do we keep the u-boot output forever, or do we sync off when 
> > the kernel starts?
> 
> And what happens if we simply ignore it? Is there a risk of anything
> burning beyond software repair? If not, ignore it. There is no need to
> support all incompatible mixes even if it means some people will see
> strange fireworks on their screens when not following the software
> requirements.
> 
> It's really no different from booting a kernel with wrong dt, or using a
> u-boot with wrong DRAM settings etc. An incompatible mix which is not
> meant to function properly.
> 
> If you use a u-boot with this framebuffer support then you must also
> either use a kernel which supports being booted in such state, or make
> sure u-boot shuts things off before handing over to the kernel.
> 
> If we can handle the situation gracefully in the kernel then fine, but
> it's by no means required, or even desired to spend any effort or even
> any serious thoughts on before compatible setups works.
> 
> Regards
> Henrik

We can work around most situations gracefully in kernelspace. We should 
for instance never set a bad mode, and never show random memory content, 
as that is a total no-go. So some code will have to exist to cleanly 
disable the display engine (we're in luck, we only need to poke the ahb 
gating and some clocks).

But if we can overlook some of the above, we also should just consider 
the memory lost until a kms driver kicks in, and ioremaps/whatevers it 
for its own use.

How's this for the sunxi implementation of simplefb:
* u-boot lists used clocks, to allow some code in simplefb.c to grab all 
  clocks. This is necessary as the list of clocks might change with 
  changed cfb-console driver functionality.
* when the clocks get disabled, the existing display engine setup 
  becomes useless. the dt simplefb node has its status set to disabled. 
  The memory range info remains, none of the reserved ram is returned 
  to system. This needs to happen in both simplefb.c and in clk-sunxi.c.
* when the memory range gets mapped by the kms driver (currently, on 
  sunxi-3.4 i just use the full disp driver reserved range directly) in 
  a way that it will be released again at unload, the memory range info 
  remains. This ensures that future kms driver reloads can still grab 
  this memory.
* when however the memory range gets mapped to cma globally, the memory 
  range info is removed.

It makes sense to add the clock handling and the disabling of the
simple-framebuffer node in the actual simplefb driver. The memory 
handling should be considered platform specific behaviour for now, but 
perhaps dt reserved memory infrastructure can come to the rescue in 
future.

Luc Verhaegen.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-04 16:53       ` Michal Suchanek
@ 2014-08-04 21:26         ` Henrik Nordström
  0 siblings, 0 replies; 18+ messages in thread
From: Henrik Nordström @ 2014-08-04 21:26 UTC (permalink / raw)
  To: u-boot

m?n 2014-08-04 klockan 18:53 +0200 skrev Michal Suchanek:

> Then you have to define what is compatible.

Yes, and the part I responded to was odd unexpected combinations of
u-boot only partially providing the right information (missing in DT) or
kernel not having enabled support.

Likewise there is the opposite situation which is also in the
unsupported area, simplefb nodes in the DT but framebuffer not actually
enabled by u-boot.

Exact details on what needs to be provided in DT and how for glitch free
handover from u-boot to KMS is a bit premature to dive into now.

> eg. you can define that if you do have simplefb in u-boot you should
> have it in kernel.

Maybe. I am only saying that there is no need to try to cover all corner
cases and odd/partial combinations. It's sufficient to cover two cases:
all enabled, all disabled. In both u-boot, kernel and DT. (well, enabled
in kernel but not in DT should be the same as disabled in kernel, so
three cases).

> If you do not have simplefb in kernel the fb memory may get reused and
> the clocks should get disabled as unused, eventually. Unless you set
> the debug option not to disable them. And KMS might eventually take
> over reprogramming or re-enabling the clocks again if you have it.

Memory would be lost today if the region is reserved in DT, but may
eventually be reclaimed when support is available in kernel. And user
should expect strange display effects as clock sources and eventually
memory gets reprogrammed and/or repurposed without anything shutting off
the disaplay engine. I do not see a problem here.

My preferred solution to this problem is to have u-boot shut off (or not
enable) the display engine before starting the kernel, and to provide a
DT without simplefb nodes. Don't worry too much about this odd case in
the kernel.

> Or as pointed out earlier you might find this unacceptable and even
> with simplefb compiled out the KMS driver would need enough simplefb
> logic to analyze the simplefb DT node and reuse the clocks and memory
> without reprogramming.

Maybe, but glich free handover is not a primary or even high priority
goal, or even what I really commented on.

It's something that can be looked into when KMS is functional. And
missing support should cause no more than a temporary display glitch
until KMS have fully claimed and programed the display components.
Likely on the same scale as KMS selecting another display mode.

Regards
Henrik

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-04 17:28       ` Luc Verhaegen
@ 2014-08-04 22:10         ` Henrik Nordström
  2014-08-05 20:55           ` Maxime Ripard
  0 siblings, 1 reply; 18+ messages in thread
From: Henrik Nordström @ 2014-08-04 22:10 UTC (permalink / raw)
  To: u-boot

m?n 2014-08-04 klockan 19:28 +0200 skrev Luc Verhaegen:

> We can work around most situations gracefully in kernelspace. We should 
> for instance never set a bad mode, and never show random memory content, 
> as that is a total no-go. So some code will have to exist to cleanly 
> disable the display engine (we're in luck, we only need to poke the ahb 
> gating and some clocks).

I seriously don't worry about display mode corruption or showing random
memory if people boot configurations/combinations which are not
supported.

> But if we can overlook some of the above, we also should just consider 
> the memory lost until a kms driver kicks in, and ioremaps/whatevers it 
> for its own use.

If it in any way hinders development of the KMS driver then yes.

> How's this for the sunxi implementation of simplefb:
> * u-boot lists used clocks, to allow some code in simplefb.c to grab all 
>   clocks. This is necessary as the list of clocks might change with 
>   changed cfb-console driver functionality.

Is this list of clocks in any way different from what KMS needs to use?

> * when the clocks get disabled, the existing display engine setup 
>   becomes useless. the dt simplefb node has its status set to disabled. 
>   The memory range info remains, none of the reserved ram is returned 
>   to system. This needs to happen in both simplefb.c and in clk-sunxi.c.

Disabled by whom?

> * when the memory range gets mapped by the kms driver (currently, on 
>   sunxi-3.4 i just use the full disp driver reserved range directly) in 
>   a way that it will be released again at unload, the memory range info 
>   remains. This ensures that future kms driver reloads can still grab 
>   this memory.

Why do a KMS reload need to be able to grab the same memory again? The
display is shut off when the KMS driver is unloaded, right? Or this only
temporary?

> * when however the memory range gets mapped to cma globally, the memory 
>   range info is removed.
> 
> It makes sense to add the clock handling and the disabling of the
> simple-framebuffer node in the actual simplefb driver. The memory 
> handling should be considered platform specific behaviour for now, but 
> perhaps dt reserved memory infrastructure can come to the rescue in 
> future.

Maybe, but people who need framebuffer in u-boot likley need it in
kernel as well I would think, so I do not worry much about releasing the
memory back to kernel for general purpose use if it has been reserved by
u-boot.

If you really have no use of the display then don't enable it in the
first place (or make sure it's shut off). Including any memory
reservations.

Similar to PC BIOS settings for reserved (shared) memory on many IGP
devices. You don't normally change such settings in kernel. If you want
a different memory layout then shut down, change BIOS settings and boot
again. Not a problem imho. (shut down, change u-boot & DT settings, boot
again).

Regards
Henrik

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH] video: add cfb console driver for sunxi
  2014-08-02 16:14 [U-Boot] [PATCH] video: add cfb console driver for sunxi Luc Verhaegen
  2014-08-04  8:39 ` Hans de Goede
@ 2014-08-05 11:56 ` Hans de Goede
  2014-08-05 20:47   ` [U-Boot] [linux-sunxi] " Maxime Ripard
  2014-08-06 11:40   ` [U-Boot] " Luc Verhaegen
  1 sibling, 2 replies; 18+ messages in thread
From: Hans de Goede @ 2014-08-05 11:56 UTC (permalink / raw)
  To: u-boot

Hi,

On 08/02/2014 06:14 PM, Luc Verhaegen wrote:
> This adds a fixed mode hdmi driver (lcd to be added in future) for the
> sunxi platform. Current config is such that 8MB is shaved off at the top
> of the RAM. Simplefb support is available for kernels that know how to
> use it.

I've been trying to follow all the discussion in this thread, and here
is what I think we should do:

1) There has been some discussion about using this console-driver
in u-boot without generating the simplefb dt node. This means yet another
variation in how all the bits fit together, so I don't think we should do
this. Note I realize that the original patch did not have a specific
config option for this, but it was mentioned later in the thread.
TL;DR: Enabling the console driver will always generate the simplefb dt
node.

2) I think we can worry about what to do with the reserved memory\when not using simplefb
(or when switching from simplefb to kms) later. For now lets focus on the
issue with the clocks.

3) To me the issue with clocks seems simple, we should modify the
devicetree binding for simplefb to support a clocks property, and modify
the simplefb kernel code to get + prep_and_enable any clocks specified
in the dt node.

This means parsing enough of the dt to find the clocks to be able to
specify phandles to them in the added node. I don't know how hard it will
be to do this in u-boot, but IMHO it is simply the right thing to do, so
this is how it should be done.

If others agree that specifying the clocks in the simplefb dt node is
the right way to ensure that the clocks don't get enabled I'm willing
at taking a shot on coding this.

Regards,

Hans



> 
> Signed-off-by: Luc Verhaegen <libv@skynet.be>
> ---
>  arch/arm/include/asm/arch-sunxi/sunxi_display.h |   21 +
>  board/sunxi/board.c                             |   14 +
>  drivers/video/Makefile                          |    1 +
>  drivers/video/sunxi_display.c                   |  639 +++++++++++++++++++++++
>  include/configs/sunxi-common.h                  |   34 ++
>  5 files changed, 709 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/include/asm/arch-sunxi/sunxi_display.h
>  create mode 100644 drivers/video/sunxi_display.c
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/sunxi_display.h b/arch/arm/include/asm/arch-sunxi/sunxi_display.h
> new file mode 100644
> index 0000000..4456778
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-sunxi/sunxi_display.h
> @@ -0,0 +1,21 @@
> +/*
> + * (C) Copyright 2014 Luc Verhaegen <libv@skynet.be>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation's version 2 and any
> + * later version the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef _SUNXI_DISPLAY_H_
> +#define _SUNXI_DISPLAY_H_
> +
> +#ifdef CONFIG_VIDEO_DT_SIMPLEFB
> +void sunxi_simplefb_setup(void *blob);
> +#endif
> +
> +#endif /* _SUNXI_DISPLAY_H_ */
> diff --git a/board/sunxi/board.c b/board/sunxi/board.c
> index 2179e23..e819b12 100644
> --- a/board/sunxi/board.c
> +++ b/board/sunxi/board.c
> @@ -26,6 +26,10 @@
>  #include <asm/io.h>
>  #include <net.h>
>  
> +#ifdef CONFIG_VIDEO
> +#include <asm/arch-sunxi/sunxi_display.h>
> +#endif
> +
>  DECLARE_GLOBAL_DATA_PTR;
>  
>  /* add board specific code here */
> @@ -185,3 +189,13 @@ int misc_init_r(void)
>  	return 0;
>  }
>  #endif
> +
> +#ifdef CONFIG_OF_BOARD_SETUP
> +void
> +ft_board_setup(void *blob, bd_t *bd)
> +{
> +#ifdef CONFIG_VIDEO_DT_SIMPLEFB
> +	sunxi_simplefb_setup(blob);
> +#endif
> +}
> +#endif /* CONFIG_OF_BOARD_SETUP */
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 945f35d..9a25c84 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o
>  obj-$(CONFIG_VIDEO_SED13806) += sed13806.o
>  obj-$(CONFIG_VIDEO_SM501) += sm501.o
>  obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
> +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o
>  obj-$(CONFIG_VIDEO_TEGRA) += tegra.o
>  obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
>  obj-$(CONFIG_FORMIKE) += formike.o
> diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
> new file mode 100644
> index 0000000..251fb67
> --- /dev/null
> +++ b/drivers/video/sunxi_display.c
> @@ -0,0 +1,639 @@
> +/*
> + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
> + *
> + * Display driver for Allwinner SoCs.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation's version 2 and any
> + * later version the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +/*
> + * This driver does nothing but HDMI at a fixed mode right now. At some
> + * point in the near future, LCD and VGA will be added.
> + *
> + * The display driver infrastructure in uboot does not immediately allow for
> + * modeline creation off of edid. The mode is therefor hardcoded to
> + * 1024x768 at 60Hz 32bpp. This is acceptable for most HDMI monitors, but far
> + * from ideal. If so desired, alter the modeline in video_hw_init()
> + */
> +
> +#include <common.h>
> +
> +#include <asm/io.h>
> +#include <asm/global_data.h>
> +#include <video_fb.h>
> +#include <linux/fb.h>
> +#include <asm/arch-sunxi/sunxi_display.h>
> +
> +/* for simplefb */
> +#ifdef CONFIG_OF_BOARD_SETUP
> +#include <libfdt.h>
> +#endif
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct sunxi_display {
> +	GraphicDevice graphic_device[1];
> +	int enabled;
> +} sunxi_display[1];
> +
> +/*
> + * Convenience functions to ease readability, and to provide an easy
> + * comparison with the sunxi kms driver.
> + */
> +static unsigned int
> +sunxi_io_read(void *base, int offset)
> +{
> +	return readl(base + offset);
> +}
> +
> +static void
> +sunxi_io_write(void *base, int offset, unsigned int value)
> +{
> +	writel(value, base + offset);
> +}
> +
> +static void
> +sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask)
> +{
> +	unsigned int tmp = readl(base + offset);
> +
> +	tmp &= ~mask;
> +	tmp |= value & mask;
> +
> +	writel(tmp, base + offset);
> +}
> +
> +/*
> + * CCMU regs: clocks.
> + */
> +#define SUNXI_CCMU_PLL3_CFG		0x010
> +#define SUNXI_CCMU_PLL5_CFG		0x020
> +#define SUNXI_CCMU_PLL7_CFG		0x030
> +#define SUNXI_CCMU_AHB_GATING1		0x064
> +#define SUNXI_CCMU_DRAM_CLK_GATING	0x100
> +#define SUNXI_DE_BE0_CLK		0x104
> +#define SUNXI_LCDC0_CH0_CLK		0x118
> +#define SUNXI_LCDC0_CH1_CLK		0x12C
> +#define SUNXI_CCMU_HDMI_CLK		0x150
> +
> +/*
> + * DEBE regs.
> + *
> + * This is the entity that mixes and matches the different layers and inputs.
> + * Allwinner calls it the back-end, but i like composer better.
> + */
> +#define SUNXI_COMP_MODE			0x800
> +#define SUNXI_COMP_DISP_SIZE		0x808
> +#define SUNXI_COMP_LAYER0_SIZE		0x810
> +#define SUNXI_COMP_LAYER0_POS		0x820
> +#define SUNXI_COMP_LAYER0_STRIDE	0x840
> +#define SUNXI_COMP_LAYER0_ADDR_LOW	0X850
> +#define SUNXI_COMP_LAYER_ADDR_HIGH	0X860
> +#define SUNXI_COMP_REG_CTL		0X870
> +#define SUNXI_COMP_LAYER0_ATTR0		0x890
> +#define SUNXI_COMP_LAYER0_ATTR1		0x8a0
> +
> +/*
> + * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
> + */
> +#define SUNXI_LCDC_ENABLE		0x000
> +#define SUNXI_LCDC_INT0			0x004
> +#define SUNXI_LCDC_INT1			0x008
> +#define SUNXI_LCDC_TCON0_DOTCLOCK	0x044
> +#define SUNXI_LCDC_TCON0_IO_TRI		0x08c
> +#define SUNXI_LCDC_TCON1_ENABLE		0x090
> +#define SUNXI_LCDC_TCON1_TIMING_SRC	0x094
> +#define SUNXI_LCDC_TCON1_TIMING_SCALE	0x098
> +#define SUNXI_LCDC_TCON1_TIMING_OUT	0x09c
> +#define SUNXI_LCDC_TCON1_TIMING_H	0x0a0
> +#define SUNXI_LCDC_TCON1_TIMING_V	0x0a4
> +#define SUNXI_LCDC_TCON1_TIMING_SYNC	0x0a8
> +#define SUNXI_LCDC_TCON1_IO_TRI		0x0f4
> +
> +/*
> + * HDMI regs.
> + */
> +#define SUNXI_HDMI_CTRL			0x004
> +#define SUNXI_HDMI_INT_CTRL		0x008
> +#define SUNXI_HDMI_HPD			0x00c
> +#define SUNXI_HDMI_VIDEO_CTRL		0x010
> +#define SUNXI_HDMI_VIDEO_SIZE		0x014
> +#define SUNXI_HDMI_VIDEO_BP		0x018
> +#define SUNXI_HDMI_VIDEO_FP		0x01c
> +#define SUNXI_HDMI_VIDEO_SPW		0x020
> +#define SUNXI_HDMI_VIDEO_POLARITY	0x024
> +#define SUNXI_HDMI_TX_DRIVER0		0x200
> +#define SUNXI_HDMI_TX_DRIVER1		0x204
> +#define SUNXI_HDMI_TX_DRIVER2		0x208
> +#define SUNXI_HDMI_TX_DRIVER3		0x20C
> +
> +static int
> +sunxi_hdmi_hpd_detect(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *hdmi = (void *) SUNXI_HDMI_BASE;
> +
> +	/* set video pll1 to 300MHz */
> +	sunxi_io_write(ccmu, SUNXI_CCMU_PLL7_CFG, 0x8010D064);
> +
> +	/* Set hdmi parent to video pll1 */
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x01000000, 0x03000000);
> +
> +	/* set ahb gating to pass */
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x800, 0x800);
> +
> +	/* clk on */
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x80000000, 0x80000000);
> +
> +	sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0x80000000);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xA0800000);
> +
> +	udelay(100);
> +
> +	if (sunxi_io_read(hdmi, SUNXI_HDMI_HPD) & 0x01)
> +		return 1;
> +
> +	/* no need to keep these running. */
> +	sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0, 0x80000000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0, 0x800);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL7_CFG, 0, 0x80000000);
> +
> +	return 0;
> +}
> +
> +static int
> +sunxi_pll5_frequency(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	unsigned int pll5 = sunxi_io_read(ccmu, SUNXI_CCMU_PLL5_CFG);
> +	int n, k, p;
> +
> +	n = (pll5 >> 8) & 0x1F;
> +	k = ((pll5 >> 4) & 0x03) + 1;
> +	p = (pll5 >> 16) & 0x03;
> +
> +	return (24000 * n * k) >> p;
> +}
> +
> +static void
> +sunxi_composer_init(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *composer = (void *) SUNXI_DE_BE0_BASE;
> +	int pll5 = sunxi_pll5_frequency();
> +	int halve;
> +
> +	if (pll5 < 300000)
> +		halve = 0;
> +	else
> +		halve = 1;
> +
> +	/* reset off */
> +	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x40000000, 0x40000000);
> +
> +	/* set to pll5 */
> +	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x02000000, 0x03000000);
> +
> +	if (halve)
> +		sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x01, 0x03);
> +	else
> +		sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0, 0x03);
> +
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x1000, 0x1000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_DRAM_CLK_GATING,
> +		      0x04000000, 0x04000000);
> +
> +	/* enable */
> +	sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x80000000, 0x80000000);
> +
> +	/* engine bug, clear registers after reset. */
> +	{
> +		/*
> +		 * Since uboot prototypes but never declares memset_io, we
> +		 * have to do this by hand.
> +		 */
> +		int i;
> +
> +		for (i = 0x0800; i < 0x1000; i += 4)
> +			sunxi_io_write(composer, i, 0);
> +	}
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x01, 0x01);
> +}
> +
> +static void
> +sunxi_composer_mode_set(struct fb_videomode *mode, unsigned int address)
> +{
> +	void *composer = (void *) SUNXI_DE_BE0_BASE;
> +#define SUNXI_FORMAT_XRGB8888 0x09
> +	unsigned int format = SUNXI_FORMAT_XRGB8888;
> +
> +	/* enable */
> +	sunxi_io_write(composer, SUNXI_COMP_DISP_SIZE,
> +		       ((mode->yres - 1) << 16) | (mode->xres - 1));
> +
> +	sunxi_io_write(composer, SUNXI_COMP_LAYER0_SIZE,
> +		       ((mode->yres - 1) << 16) | (mode->xres - 1));
> +	sunxi_io_write(composer, SUNXI_COMP_LAYER0_STRIDE, mode->xres << 5);
> +	sunxi_io_write(composer, SUNXI_COMP_LAYER0_ADDR_LOW, address << 3);
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER_ADDR_HIGH,
> +		      address >> 29, 0xFF);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, format << 8, 0x0F00);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x04);
> +	sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x03);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x100, 0x100);
> +}
> +
> +static void
> +sunxi_lcdc_pll_set(int dotclock)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	int value, n, m, diff;
> +	int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
> +	int best_double = 0;
> +
> +	if ((dotclock < 20000) || (dotclock > 400000)) {
> +		printf("%s: Error: dotclock %d is out of range.\n",
> +		       __func__, dotclock);
> +		return;
> +	}
> +
> +	for (m = 16; m > 0; m--) {
> +		n = (m * dotclock) / 3000;
> +
> +		if ((n > 9) && (n < 128)) {
> +			value = (3000 * n) / m;
> +			diff = value - dotclock;
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 0;
> +			}
> +		}
> +
> +		n++;
> +		if ((n > 9) && (n < 128)) {
> +			value = (3000 * n) / m;
> +			diff = abs(value - dotclock);
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 0;
> +			}
> +		}
> +
> +		/* these are just duplicates. */
> +		if (!(m & 1))
> +			continue;
> +
> +		n = (m * dotclock) / 6000;
> +		if ((n > 63) && (n < 128)) {
> +			value = (6000 * n) / m;
> +			diff = abs(value - dotclock);
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 1;
> +			}
> +		}
> +
> +		n++;
> +		if ((n > 63) && (n < 128)) {
> +			value = (6000 * n) / m;
> +			diff = abs(value - dotclock);
> +			if (diff < 0)
> +				diff = -diff;
> +
> +			if (diff < best_diff) {
> +				best_diff = diff;
> +				best_m = m;
> +				best_n = n;
> +				best_double = 1;
> +			}
> +		}
> +	}
> +
> +#if 0
> +	if (best_double)
> +		printf("dotclock: %06dkHz = %06dkHz: (2 * 3MHz * %d) / %d\n",
> +		       dotclock, (6000 * best_n) / best_m, best_n, best_m);
> +	else
> +		printf("dotclock: %06dkHz = %06dkHz: (3MHz * %d) / %d\n",
> +		       dotclock, (3000 * best_n) / best_m, best_n, best_m);
> +#endif
> +
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x80000000, 0x80000000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x8000, 0x8000);
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, best_n, 0x7F);
> +
> +	if (best_double)
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK,
> +			      0x02000000, 0x03000000);
> +	else
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK,
> +			      0, 0x03000000);
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, best_m - 1, 0x0F);
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800);
> +
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000);
> +}
> +
> +static void
> +sunxi_lcdc_init(void)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *lcdc = (void *) SUNXI_LCD0_BASE;
> +
> +	/* Pll1 was already enabled in hpd detect. */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x01000000, 0x03000000);
> +
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x01000000, 0x03000000);
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800);
> +
> +	/* just randomly set it at 30MHz */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x09, 0x0F);
> +
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x40000000, 0x40000000);
> +
> +	sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x10, 0x10);
> +
> +	/* toggle ch0 clock */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x80000000, 0x80000000);
> +	while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH0_CLK) & 0x80000000)
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0, 0x80000000);
> +
> +	/* toggle ch1 s1 & s2 clocks */
> +	sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000);
> +	while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK) & 0x80008000)
> +		sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x80008000);
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_ENABLE, 0);
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_INT0, 0);
> +	sunxi_io_write(lcdc, SUNXI_LCDC_INT1, 0x20);
> +
> +	/*
> +	 * disable tcon0 dot clock:
> +	 * This doesn't disable the dotclock, it just nulls the divider.
> +	 */
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_DOTCLOCK, 0xF0000000);
> +
> +	/* all io lines disabled. */
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_IO_TRI, 0x0FFFFFFF);
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x0FFFFFFF);
> +}
> +
> +static void
> +sunxi_lcdc_mode_set(struct fb_videomode *mode)
> +{
> +	void *lcdc = (void *) SUNXI_LCD0_BASE;
> +	int total;
> +
> +	/* use tcon1 */
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x01, 0x01);
> +
> +	/* enabled, 0x1E start delay */
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_ENABLE, 0x800001E0);
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SRC,
> +		       ((mode->xres - 1) << 16) | (mode->yres - 1));
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SCALE,
> +		       ((mode->xres - 1) << 16) | (mode->yres - 1));
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_OUT,
> +		       ((mode->xres - 1) << 16) | (mode->yres - 1));
> +
> +	total = mode->left_margin + mode->xres + mode->right_margin +
> +		mode->hsync_len;
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_H,
> +		       ((total - 1) << 16) |
> +		       (mode->hsync_len + mode->left_margin - 1));
> +
> +	total = mode->upper_margin + mode->yres + mode->lower_margin +
> +		mode->vsync_len;
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_V,
> +		       ((total *  2) << 16) |
> +		       (mode->vsync_len + mode->upper_margin - 1));
> +
> +	sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SYNC,
> +		       ((mode->hsync_len - 1) << 16) | (mode->vsync_len - 1));
> +
> +	sunxi_lcdc_pll_set(mode->pixclock);
> +}
> +
> +static void
> +sunxi_hdmi_mode_set(struct fb_videomode *mode)
> +{
> +	void *ccmu = (void *) SUNXI_CCM_BASE;
> +	void *hdmi = (void *) SUNXI_HDMI_BASE;
> +	int h, v, tmp;
> +
> +	sunxi_io_write(hdmi, SUNXI_HDMI_INT_CTRL, 0xFFFFFFFF);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x03FE0000);
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xDE000000, 0xDE000000);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x00D8C820);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER2, 0xD2000008);
> +	sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER3, 0);
> +
> +	/* use video0 */
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER3, 0, 0x00200000);
> +
> +	tmp = sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK);
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER2,
> +		      ((tmp & 0x0F) + 1) << 4, 0xF0);
> +
> +	if (tmp & 0x02000000)
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0, 0x40);
> +	else
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x40, 0x40);
> +
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SIZE,
> +		       ((mode->yres - 1) << 16) | (mode->xres - 1));
> +
> +	h = mode->hsync_len + mode->left_margin;
> +	v = mode->vsync_len + mode->upper_margin;
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_BP, ((v - 1) << 16) | (h - 1));
> +
> +	h = mode->right_margin;
> +	v = mode->lower_margin;
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_FP, ((v - 1) << 16) | (h - 1));
> +
> +	h = mode->hsync_len;
> +	v = mode->vsync_len;
> +	sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SPW, ((v - 1) << 16) | (h - 1));
> +
> +	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x01, 0x01);
> +	else
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x01);
> +
> +	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x02, 0x02);
> +	else
> +		sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x02);
> +}
> +
> +static void
> +sunxi_engines_init(void)
> +{
> +	sunxi_composer_init();
> +	sunxi_lcdc_init();
> +}
> +
> +static void
> +sunxi_mode_set(struct fb_videomode *mode, unsigned int address)
> +{
> +	void *composer = (void *) SUNXI_DE_BE0_BASE;
> +	void *lcdc = (void *) SUNXI_LCD0_BASE;
> +	void *hdmi = (void *) SUNXI_HDMI_BASE;
> +
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0, 0x80000000);
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0, 0x80000000);
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0, 0x02);
> +
> +	sunxi_composer_mode_set(mode, address);
> +	sunxi_lcdc_mode_set(mode);
> +	sunxi_hdmi_mode_set(mode);
> +
> +	sunxi_io_mask(composer, SUNXI_COMP_REG_CTL, 0x01, 0x01);
> +	sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x02, 0x02);
> +
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x80000000, 0x80000000);
> +	sunxi_io_mask(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x00000000, 0x03000000);
> +
> +	udelay(100);
> +
> +	sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0x80000000, 0x80000000);
> +}
> +
> +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
> +void
> +sunxi_simplefb_setup(void *blob)
> +{
> +	static GraphicDevice *graphic_device = sunxi_display->graphic_device;
> +	const char *name = "simple-framebuffer";
> +	const char *format = "x8r8g8b8";
> +	fdt32_t cells[2];
> +	int offset, stride, ret;
> +
> +	if (!sunxi_display->enabled)
> +		return;
> +
> +	offset = fdt_add_subnode(blob, 0, "framebuffer");
> +	if (offset < 0) {
> +		printf("%s: add subnode failed", __func__);
> +		return;
> +	}
> +
> +	ret = fdt_setprop(blob, offset, "compatible", name, strlen(name) + 1);
> +	if (ret < 0)
> +		return;
> +
> +	stride = graphic_device->winSizeX * graphic_device->gdfBytesPP;
> +
> +	cells[0] = cpu_to_fdt32(gd->fb_base);
> +	cells[1] = cpu_to_fdt32(CONFIG_SUNXI_FB_SIZE);
> +	ret = fdt_setprop(blob, offset, "reg", cells, sizeof(cells[0]) * 2);
> +	if (ret < 0)
> +		return;
> +
> +	cells[0] = cpu_to_fdt32(graphic_device->winSizeX);
> +	ret = fdt_setprop(blob, offset, "width", cells, sizeof(cells[0]));
> +	if (ret < 0)
> +		return;
> +
> +	cells[0] = cpu_to_fdt32(graphic_device->winSizeY);
> +	ret = fdt_setprop(blob, offset, "height", cells, sizeof(cells[0]));
> +	if (ret < 0)
> +		return;
> +
> +	cells[0] = cpu_to_fdt32(stride);
> +	ret = fdt_setprop(blob, offset, "stride", cells, sizeof(cells[0]));
> +	if (ret < 0)
> +		return;
> +
> +	ret = fdt_setprop(blob, offset, "format", format, strlen(format) + 1);
> +	if (ret < 0)
> +		return;
> +}
> +#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
> +
> +void *
> +video_hw_init(void)
> +{
> +	static GraphicDevice *graphic_device = sunxi_display->graphic_device;
> +	/*
> +	 * Vesa standard 1024x768 at 60
> +	 * 65.0  1024 1032 1176 1344  768 771 777 806  -hsync -vsync
> +	 */
> +	struct fb_videomode mode = {
> +		.name = "1024x768",
> +		.refresh = 60,
> +		.xres = 1024,
> +		.yres = 768,
> +		.pixclock = 65000,
> +		.left_margin = 160,
> +		.right_margin = 24,
> +		.upper_margin = 29,
> +		.lower_margin = 3,
> +		.hsync_len = 136,
> +		.vsync_len = 6,
> +		.sync = 0,
> +		.vmode = 0,
> +		.flag = 0,
> +	};
> +	int ret;
> +
> +	memset(sunxi_display, 0, sizeof(struct sunxi_display));
> +
> +	printf("Reserved %dkB of RAM for Framebuffer.\n",
> +	       CONFIG_SUNXI_FB_SIZE >> 10);
> +	gd->fb_base = gd->ram_top;
> +
> +	ret = sunxi_hdmi_hpd_detect();
> +	if (!ret)
> +		return NULL;
> +
> +	printf("HDMI connected.\n");
> +	sunxi_display->enabled = 1;
> +
> +	printf("Setting up a %s console.\n", mode.name);
> +	sunxi_engines_init();
> +	sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
> +
> +	/*
> +	 * These are the only members of this structure that are used. All the
> +	 * others are driver specific. There is nothing to decribe pitch or
> +	 * stride, but we are lucky with our hw.
> +	 */
> +	graphic_device->frameAdrs = gd->fb_base;
> +	graphic_device->gdfIndex = GDF_32BIT_X888RGB;
> +	graphic_device->gdfBytesPP = 4;
> +	graphic_device->winSizeX = mode.xres;
> +	graphic_device->winSizeY = mode.yres;
> +
> +	return graphic_device;
> +}
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index 8ab6429..89582b8 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -181,6 +181,40 @@
>  #define CONFIG_SUNXI_GPIO
>  #define CONFIG_CMD_GPIO
>  
> +/* Set this if you do not want a uboot fb console */
> +#ifndef CONFIG_NO_VIDEO
> +#define CONFIG_VIDEO
> +#endif
> +
> +#ifdef CONFIG_VIDEO
> +/*
> + * The amount of RAM that is reserved for the FB. This will not show up as
> + * RAM to the kernel, but will be reclaimed by a KMS driver in future.
> + */
> +#define CONFIG_SUNXI_FB_SIZE (8 << 20)
> +
> +/* Do we want to initialize a simple FB? */
> +#define CONFIG_VIDEO_DT_SIMPLEFB
> +
> +#define CONFIG_VIDEO_SUNXI
> +
> +#define CONFIG_CFB_CONSOLE
> +/* allow both serial and cfb console. */
> +#define CONFIG_CONSOLE_MUX
> +/* this is needed so the above will actually do something */
> +#define CONFIG_SYS_CONSOLE_IS_IN_ENV
> +/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */
> +#define CONFIG_VGA_AS_SINGLE_DEVICE
> +
> +#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF)
> +
> +/* To be able to hook simplefb into dt */
> +#ifdef CONFIG_VIDEO_DT_SIMPLEFB
> +#define CONFIG_OF_BOARD_SETUP
> +#endif
> +
> +#endif /* CONFIG_VIDEO */
> +
>  /* Ethernet support */
>  #ifdef CONFIG_SUNXI_EMAC
>  #define CONFIG_MII			/* MII PHY management		*/
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-05 11:56 ` [U-Boot] " Hans de Goede
@ 2014-08-05 20:47   ` Maxime Ripard
  2014-08-06 11:40   ` [U-Boot] " Luc Verhaegen
  1 sibling, 0 replies; 18+ messages in thread
From: Maxime Ripard @ 2014-08-05 20:47 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 05, 2014 at 01:56:36PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 08/02/2014 06:14 PM, Luc Verhaegen wrote:
> > This adds a fixed mode hdmi driver (lcd to be added in future) for the
> > sunxi platform. Current config is such that 8MB is shaved off at the top
> > of the RAM. Simplefb support is available for kernels that know how to
> > use it.
> 
> I've been trying to follow all the discussion in this thread, and here
> is what I think we should do:
> 
> 1) There has been some discussion about using this console-driver
> in u-boot without generating the simplefb dt node. This means yet another
> variation in how all the bits fit together, so I don't think we should do
> this. Note I realize that the original patch did not have a specific
> config option for this, but it was mentioned later in the thread.
> TL;DR: Enabling the console driver will always generate the simplefb dt
> node.

Until we have a KMS driver, I agree.

The DT generation part should probably be a separate patch
though. It's probably going to generate enough discussion by itself to
not slow done the driver itself.

> 2) I think we can worry about what to do with the reserved memory\when not using simplefb
> (or when switching from simplefb to kms) later. For now lets focus on the
> issue with the clocks.
> 
> 3) To me the issue with clocks seems simple, we should modify the
> devicetree binding for simplefb to support a clocks property, and modify
> the simplefb kernel code to get + prep_and_enable any clocks specified
> in the dt node.
> 
> This means parsing enough of the dt to find the clocks to be able to
> specify phandles to them in the added node. I don't know how hard it will
> be to do this in u-boot, but IMHO it is simply the right thing to do, so
> this is how it should be done.
> 
> If others agree that specifying the clocks in the simplefb dt node is
> the right way to ensure that the clocks don't get enabled I'm willing
> at taking a shot on coding this.

Agreed.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140805/db816222/attachment.pgp>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-04 22:10         ` Henrik Nordström
@ 2014-08-05 20:55           ` Maxime Ripard
  0 siblings, 0 replies; 18+ messages in thread
From: Maxime Ripard @ 2014-08-05 20:55 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 05, 2014 at 12:10:30AM +0200, Henrik Nordstr?m wrote:
> > How's this for the sunxi implementation of simplefb:
> > * u-boot lists used clocks, to allow some code in simplefb.c to grab all 
> >   clocks. This is necessary as the list of clocks might change with 
> >   changed cfb-console driver functionality.
> 
> Is this list of clocks in any way different from what KMS needs to use?

Not really, but Luc haven't been using all the clocks that might be
used by the KMS driver, and just uses a subset of it.

> > * when the clocks get disabled, the existing display engine setup 
> >   becomes useless. the dt simplefb node has its status set to disabled. 
> >   The memory range info remains, none of the reserved ram is returned 
> >   to system. This needs to happen in both simplefb.c and in clk-sunxi.c.
> 
> Disabled by whom?

Linux' clock framework.

> > * when the memory range gets mapped by the kms driver (currently, on 
> >   sunxi-3.4 i just use the full disp driver reserved range directly) in 
> >   a way that it will be released again at unload, the memory range info 
> >   remains. This ensures that future kms driver reloads can still grab 
> >   this memory.
> 
> Why do a KMS reload need to be able to grab the same memory again? The
> display is shut off when the KMS driver is unloaded, right? Or this only
> temporary?
> 
> > * when however the memory range gets mapped to cma globally, the memory 
> >   range info is removed.
> > 
> > It makes sense to add the clock handling and the disabling of the
> > simple-framebuffer node in the actual simplefb driver. The memory 
> > handling should be considered platform specific behaviour for now, but 
> > perhaps dt reserved memory infrastructure can come to the rescue in 
> > future.
> 
> Maybe, but people who need framebuffer in u-boot likley need it in
> kernel as well I would think, so I do not worry much about releasing the
> memory back to kernel for general purpose use if it has been reserved by
> u-boot.
> 
> If you really have no use of the display then don't enable it in the
> first place (or make sure it's shut off). Including any memory
> reservations.
> 
> Similar to PC BIOS settings for reserved (shared) memory on many IGP
> devices. You don't normally change such settings in kernel. If you want
> a different memory layout then shut down, change BIOS settings and boot
> again. Not a problem imho. (shut down, change u-boot & DT settings, boot
> again).

Except that here, "change u-boot & DT settings" means "recompile
u-boot and the DT, and flash the whole thing again to your
system". Not really as painless as what you're suggesting.


-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140805/5d94b6a5/attachment.pgp>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-04 15:05   ` Luc Verhaegen
  2014-08-04 15:31     ` [U-Boot] [linux-sunxi] " Henrik Nordström
@ 2014-08-05 21:03     ` Maxime Ripard
  2014-08-05 21:37       ` Michal Suchanek
  1 sibling, 1 reply; 18+ messages in thread
From: Maxime Ripard @ 2014-08-05 21:03 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote:
> On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote:
> > Hi Luc,
> > 
> > First of all many thanks for your work on this.
> > 
> > ATM I don't have time to do a full review, but I don't expect there
> > to be too many suprises when I do find the time.
> > 
> > Really my only concern is the handover of the reserved memory, etc. to
> > the kernel. We need to get a plan in place for that *before* this can
> > be merged. Note I don't want to raise any artificial barriers here,
> > I would love to see this merged ASAP. But I don't want to paint us
> > in a corner where u-boot having hdmi console support makes it harder
> > to get kms support in the kernel going. I think we can both agree on that.
> >
> > So I really want to see some plan how this will work in place before merging.
> > Note just a plan, I don't expect kernel patches ready to be merged for this,
> > just a good idea / sketch of how all the bits will fit together.
> 
> Memory is not the biggest worry.
> 
> Some kernel code needs to claim clocks if the mode is to cleanly survive 
> the start of the kernel. If not, there is no coming back until a proper 
> display driver runs. If the simplefb driver claims these clocks, then 
> the simplefb driver also must release these clocks, and this driver 
> should then never be started again, so it should set the simplefb dt 
> node status to "disabled".

I'm probably missing a bit of context, but one thing I still don't get
is why you're taking into account the simplefb <-> KMS handover. It's
a case that shouldn't exist.

By essence, simplefb has never been meant for that. It's been meant to
have a temporary solution until a full-fledged driver is merged in the
kernel. Which is exactly the case we're into.

But once the KMS driver gone, I'd just expect simplefb to go away.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140805/f83a7c6e/attachment.pgp>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-05 21:03     ` Maxime Ripard
@ 2014-08-05 21:37       ` Michal Suchanek
  2014-08-06  7:24         ` [U-Boot] [linux-sunxi] " Koen Kooi
  2014-08-06 12:21         ` [U-Boot] [linux-sunxi] " Maxime Ripard
  0 siblings, 2 replies; 18+ messages in thread
From: Michal Suchanek @ 2014-08-05 21:37 UTC (permalink / raw)
  To: u-boot

On 5 August 2014 23:03, Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote:
>> On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote:
>> > Hi Luc,
>> >
>> > First of all many thanks for your work on this.
>> >
>> > ATM I don't have time to do a full review, but I don't expect there
>> > to be too many suprises when I do find the time.
>> >
>> > Really my only concern is the handover of the reserved memory, etc. to
>> > the kernel. We need to get a plan in place for that *before* this can
>> > be merged. Note I don't want to raise any artificial barriers here,
>> > I would love to see this merged ASAP. But I don't want to paint us
>> > in a corner where u-boot having hdmi console support makes it harder
>> > to get kms support in the kernel going. I think we can both agree on that.
>> >
>> > So I really want to see some plan how this will work in place before merging.
>> > Note just a plan, I don't expect kernel patches ready to be merged for this,
>> > just a good idea / sketch of how all the bits will fit together.
>>
>> Memory is not the biggest worry.
>>
>> Some kernel code needs to claim clocks if the mode is to cleanly survive
>> the start of the kernel. If not, there is no coming back until a proper
>> display driver runs. If the simplefb driver claims these clocks, then
>> the simplefb driver also must release these clocks, and this driver
>> should then never be started again, so it should set the simplefb dt
>> node status to "disabled".
>
> I'm probably missing a bit of context, but one thing I still don't get
> is why you're taking into account the simplefb <-> KMS handover. It's
> a case that shouldn't exist.
>
> By essence, simplefb has never been meant for that. It's been meant to
> have a temporary solution until a full-fledged driver is merged in the
> kernel. Which is exactly the case we're into.

It's a permanent temporary solution. Same as offb/vesafb/uefi and
other unaccelerated drivers. It will be needed for platforms on which
KMS is not (yet) fully supported or happens to break.

Also how else do you express the fact that u-boot has left the display
enabled other than generating the simplefb DT node?

Note that the KMS driver will be probably unsuitable for early console
while the simplefb driver can just write into the framebuffer set up
by u-boot.

Thanks

Michal

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] [PATCH] video: add cfb console driver for sunxi
  2014-08-05 21:37       ` Michal Suchanek
@ 2014-08-06  7:24         ` Koen Kooi
  2014-08-06 11:10           ` Hans de Goede
  2014-08-06 12:21         ` [U-Boot] [linux-sunxi] " Maxime Ripard
  1 sibling, 1 reply; 18+ messages in thread
From: Koen Kooi @ 2014-08-06  7:24 UTC (permalink / raw)
  To: u-boot


Op 5 aug. 2014, om 23:37 heeft Michal Suchanek <hramrach@gmail.com> het volgende geschreven:

> On 5 August 2014 23:03, Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
>> On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote:
>>> On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote:
>>>> Hi Luc,
>>>> 
>>>> First of all many thanks for your work on this.
>>>> 
>>>> ATM I don't have time to do a full review, but I don't expect there
>>>> to be too many suprises when I do find the time.
>>>> 
>>>> Really my only concern is the handover of the reserved memory, etc. to
>>>> the kernel. We need to get a plan in place for that *before* this can
>>>> be merged. Note I don't want to raise any artificial barriers here,
>>>> I would love to see this merged ASAP. But I don't want to paint us
>>>> in a corner where u-boot having hdmi console support makes it harder
>>>> to get kms support in the kernel going. I think we can both agree on that.
>>>> 
>>>> So I really want to see some plan how this will work in place before merging.
>>>> Note just a plan, I don't expect kernel patches ready to be merged for this,
>>>> just a good idea / sketch of how all the bits will fit together.
>>> 
>>> Memory is not the biggest worry.
>>> 
>>> Some kernel code needs to claim clocks if the mode is to cleanly survive
>>> the start of the kernel. If not, there is no coming back until a proper
>>> display driver runs. If the simplefb driver claims these clocks, then
>>> the simplefb driver also must release these clocks, and this driver
>>> should then never be started again, so it should set the simplefb dt
>>> node status to "disabled".
>> 
>> I'm probably missing a bit of context, but one thing I still don't get
>> is why you're taking into account the simplefb <-> KMS handover. It's
>> a case that shouldn't exist.
>> 
>> By essence, simplefb has never been meant for that. It's been meant to
>> have a temporary solution until a full-fledged driver is merged in the
>> kernel. Which is exactly the case we're into.
> 
> It's a permanent temporary solution. Same as offb/vesafb/uefi and
> other unaccelerated drivers. It will be needed for platforms on which
> KMS is not (yet) fully supported or happens to break.
> 
> Also how else do you express the fact that u-boot has left the display
> enabled other than generating the simplefb DT node?
> 
> Note that the KMS driver will be probably unsuitable for early console
> while the simplefb driver can just write into the framebuffer set up
> by u-boot.

Both simplefb and the potention sunxifb will be using the same kernel infrastructure and start printing at the same time, so your argument about simplefb being able to print 'earlier' is nonsense.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] [PATCH] video: add cfb console driver for sunxi
  2014-08-06  7:24         ` [U-Boot] [linux-sunxi] " Koen Kooi
@ 2014-08-06 11:10           ` Hans de Goede
  0 siblings, 0 replies; 18+ messages in thread
From: Hans de Goede @ 2014-08-06 11:10 UTC (permalink / raw)
  To: u-boot

Hi,

On 08/06/2014 09:24 AM, Koen Kooi wrote:
> 
> Op 5 aug. 2014, om 23:37 heeft Michal Suchanek <hramrach@gmail.com> het volgende geschreven:
> 
>> On 5 August 2014 23:03, Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
>>> On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote:
>>>> On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote:
>>>>> Hi Luc,
>>>>>
>>>>> First of all many thanks for your work on this.
>>>>>
>>>>> ATM I don't have time to do a full review, but I don't expect there
>>>>> to be too many suprises when I do find the time.
>>>>>
>>>>> Really my only concern is the handover of the reserved memory, etc. to
>>>>> the kernel. We need to get a plan in place for that *before* this can
>>>>> be merged. Note I don't want to raise any artificial barriers here,
>>>>> I would love to see this merged ASAP. But I don't want to paint us
>>>>> in a corner where u-boot having hdmi console support makes it harder
>>>>> to get kms support in the kernel going. I think we can both agree on that.
>>>>>
>>>>> So I really want to see some plan how this will work in place before merging.
>>>>> Note just a plan, I don't expect kernel patches ready to be merged for this,
>>>>> just a good idea / sketch of how all the bits will fit together.
>>>>
>>>> Memory is not the biggest worry.
>>>>
>>>> Some kernel code needs to claim clocks if the mode is to cleanly survive
>>>> the start of the kernel. If not, there is no coming back until a proper
>>>> display driver runs. If the simplefb driver claims these clocks, then
>>>> the simplefb driver also must release these clocks, and this driver
>>>> should then never be started again, so it should set the simplefb dt
>>>> node status to "disabled".
>>>
>>> I'm probably missing a bit of context, but one thing I still don't get
>>> is why you're taking into account the simplefb <-> KMS handover. It's
>>> a case that shouldn't exist.
>>>
>>> By essence, simplefb has never been meant for that. It's been meant to
>>> have a temporary solution until a full-fledged driver is merged in the
>>> kernel. Which is exactly the case we're into.
>>
>> It's a permanent temporary solution. Same as offb/vesafb/uefi and
>> other unaccelerated drivers. It will be needed for platforms on which
>> KMS is not (yet) fully supported or happens to break.
>>
>> Also how else do you express the fact that u-boot has left the display
>> enabled other than generating the simplefb DT node?
>>
>> Note that the KMS driver will be probably unsuitable for early console
>> while the simplefb driver can just write into the framebuffer set up
>> by u-boot.
> 
> Both simplefb and the potention sunxifb will be using the same kernel infrastructure and start printing at the same time, so your argument about simplefb being able to print 'earlier' is nonsense.

Distros typically build kms drivers as modules, since there can be many
different gpus on a single platform (even for arm now that we have
multi arm v7 support).

So I think that having simplefb build in, and then having the kms
driver taking over when it loads make sense, and this is also
more or less how it works on x86.

Regards,

Hans

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH] video: add cfb console driver for sunxi
  2014-08-05 11:56 ` [U-Boot] " Hans de Goede
  2014-08-05 20:47   ` [U-Boot] [linux-sunxi] " Maxime Ripard
@ 2014-08-06 11:40   ` Luc Verhaegen
  2014-08-07  9:28     ` Hans de Goede
  1 sibling, 1 reply; 18+ messages in thread
From: Luc Verhaegen @ 2014-08-06 11:40 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 05, 2014 at 01:56:36PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 08/02/2014 06:14 PM, Luc Verhaegen wrote:
> > This adds a fixed mode hdmi driver (lcd to be added in future) for the
> > sunxi platform. Current config is such that 8MB is shaved off at the top
> > of the RAM. Simplefb support is available for kernels that know how to
> > use it.
> 
> I've been trying to follow all the discussion in this thread, and here
> is what I think we should do:
> 
> 1) There has been some discussion about using this console-driver
> in u-boot without generating the simplefb dt node. This means yet another
> variation in how all the bits fit together, so I don't think we should do
> this. Note I realize that the original patch did not have a specific
> config option for this, but it was mentioned later in the thread.
> TL;DR: Enabling the console driver will always generate the simplefb dt
> node.

When we do not claim clocks, we luckily cleanly disable hw, in our case.

> 2) I think we can worry about what to do with the reserved memory\when not using simplefb
> (or when switching from simplefb to kms) later. For now lets focus on the
> issue with the clocks.

Yes, this was the plan all along.

> 3) To me the issue with clocks seems simple, we should modify the
> devicetree binding for simplefb to support a clocks property, and modify
> the simplefb kernel code to get + prep_and_enable any clocks specified
> in the dt node.

For me, an important part of this discussion was seemingly flawed way in 
which clocks are defined. I was of course not going to completely 
overturn the thinking here, but i had expected that people would've at 
least agreed that something was obviously awry, as there are several 
obvious indicators there.

> This means parsing enough of the dt to find the clocks to be able to
> specify phandles to them in the added node. I don't know how hard it will
> be to do this in u-boot, but IMHO it is simply the right thing to do, so
> this is how it should be done.

No, you do not need to add nodes. This was never the case. &ahb_gates 
is never used like that.

It is either used as <&ahb_gates bit> from the dt, or "ahb_bitname" 
from kernel code which directly references clocks, with the 
ahb_bitnames listed as part of ahb_gates in the "clock-output-names" 
property. This lack of symmetry is one very clear sign.

The fact that only the kernel knows how to map the "clock-output-names" 
list, which is only defined in the dts, to bits only defined in the clk 
driver code in the kernel, that's another very clear sign.

> If others agree that specifying the clocks in the simplefb dt node is
> the right way to ensure that the clocks don't get enabled I'm willing
> at taking a shot on coding this.

I have been on it since last friday, when i started seeing the issues 
here, but haven't done much code til now, and am only uncovering many 
more inconsistencies.

For instance, in the linux kernel, 
Documentation/devicetree/bindings/clock/clock-bindings.txt only adds to 
the confusion.

Now trying to find a working solution from the kernel side, as i already 
manually inserted 6 u32s: {phandle, bit, phandle, bit, phandle, bit}.
Wait and see how that pans out, but i know that this will not provide a 
proper or lasting solution, as the pairs of cells needed now will at one 
point need to be mixed with directly referenced clocks (pll3/pll7, which 
are currently not defined in dts yet).

Luc Verhaegen.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi
  2014-08-05 21:37       ` Michal Suchanek
  2014-08-06  7:24         ` [U-Boot] [linux-sunxi] " Koen Kooi
@ 2014-08-06 12:21         ` Maxime Ripard
  1 sibling, 0 replies; 18+ messages in thread
From: Maxime Ripard @ 2014-08-06 12:21 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 05, 2014 at 11:37:11PM +0200, Michal Suchanek wrote:
> > I'm probably missing a bit of context, but one thing I still don't get
> > is why you're taking into account the simplefb <-> KMS handover. It's
> > a case that shouldn't exist.
> >
> > By essence, simplefb has never been meant for that. It's been meant to
> > have a temporary solution until a full-fledged driver is merged in the
> > kernel. Which is exactly the case we're into.
> 
> It's a permanent temporary solution. Same as offb/vesafb/uefi and
> other unaccelerated drivers. It will be needed for platforms on which
> KMS is not (yet) fully supported or happens to break.

Yeah, I get that part, but there's no handover in this case.

> Also how else do you express the fact that u-boot has left the display
> enabled other than generating the simplefb DT node?

Just like timers, UARTs, i2c, ethernet, and any other controller that
might be used by the OS: the OS should deal with it.

We don't use a simplefb-equivalent for the PMIC, or for the GMAC, I
don't see why we should use one here to deal with that issue.

What resources are you afraid to waste here? clocks are reclaimed
automatically, memory is not, but simplefb won't help, see our
discussion on the othre thread about this patch.

> Note that the KMS driver will be probably unsuitable for early console
> while the simplefb driver can just write into the framebuffer set up
> by u-boot.

They both step in at the same time. simplefb is not a solution for
that either.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140806/ffcfa4aa/attachment.pgp>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH] video: add cfb console driver for sunxi
  2014-08-06 11:40   ` [U-Boot] " Luc Verhaegen
@ 2014-08-07  9:28     ` Hans de Goede
  0 siblings, 0 replies; 18+ messages in thread
From: Hans de Goede @ 2014-08-07  9:28 UTC (permalink / raw)
  To: u-boot

Hi,

On 08/06/2014 01:40 PM, Luc Verhaegen wrote:
> On Tue, Aug 05, 2014 at 01:56:36PM +0200, Hans de Goede wrote:
>> Hi,
>>
>> On 08/02/2014 06:14 PM, Luc Verhaegen wrote:
>>> This adds a fixed mode hdmi driver (lcd to be added in future) for the
>>> sunxi platform. Current config is such that 8MB is shaved off at the top
>>> of the RAM. Simplefb support is available for kernels that know how to
>>> use it.
>>
>> I've been trying to follow all the discussion in this thread, and here
>> is what I think we should do:
>>
>> 1) There has been some discussion about using this console-driver
>> in u-boot without generating the simplefb dt node. This means yet another
>> variation in how all the bits fit together, so I don't think we should do
>> this. Note I realize that the original patch did not have a specific
>> config option for this, but it was mentioned later in the thread.
>> TL;DR: Enabling the console driver will always generate the simplefb dt
>> node.
> 
> When we do not claim clocks, we luckily cleanly disable hw, in our case.
> 
>> 2) I think we can worry about what to do with the reserved memory\when not using simplefb
>> (or when switching from simplefb to kms) later. For now lets focus on the
>> issue with the clocks.
> 
> Yes, this was the plan all along.
> 
>> 3) To me the issue with clocks seems simple, we should modify the
>> devicetree binding for simplefb to support a clocks property, and modify
>> the simplefb kernel code to get + prep_and_enable any clocks specified
>> in the dt node.
> 
> For me, an important part of this discussion was seemingly flawed way in 
> which clocks are defined. I was of course not going to completely 
> overturn the thinking here, but i had expected that people would've at 
> least agreed that something was obviously awry, as there are several 
> obvious indicators there.

I think the way clocks are defined is fine, it works fine for all
the other parts of the SoC we've added support for so far. I guess
it may take some getting used too.

Anyways I don't think having an extended discussion about how clocks
are defined is useful, this is simply something which we are not
going to change, so better get used to it.

> 
>> This means parsing enough of the dt to find the clocks to be able to
>> specify phandles to them in the added node. I don't know how hard it will
>> be to do this in u-boot, but IMHO it is simply the right thing to do, so
>> this is how it should be done.
> 
> No, you do not need to add nodes. This was never the case. &ahb_gates 
> is never used like that.
> 
> It is either used as <&ahb_gates bit> from the dt, or "ahb_bitname" 
> from kernel code which directly references clocks, with the 
> ahb_bitnames listed as part of ahb_gates in the "clock-output-names" 
> property. This lack of symmetry is one very clear sign.

That is how the gates are modeled yes, but we don't want to insert
direct refences to the gates into the generated simple-framebuffer
devicetree node. Instead what should be done is add module clock
nodes to the devicetree (in the dts file, not on the fly in u-boot),
and then the uboot code should search for those (this is what I meant
with parse the dtb) and then insert phandles to these into the
generated simpe-framebuffer node.

Note we will need multiple module-clocks node, one for lcd0 ch0 one for lcd0
ch1, etc. See for example the mmc0_clk node, and the usage of it in the mmc0
node. I think we don't need a module clock node for the hdmi encoder,
as it seems the module clock register for it at address 1c20150 does not do
anything, instead it seems the hdmi encoder is hooked up
directly to pll 3 / 7 and has its own clock selection mechanism through
one of the hdmi encoder registers. At least this is the conclusion I
came to when working on dvi support, etc. in the sunxi-3.4 kernels.

Regards,

Hans

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2014-08-07  9:28 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-02 16:14 [U-Boot] [PATCH] video: add cfb console driver for sunxi Luc Verhaegen
2014-08-04  8:39 ` Hans de Goede
2014-08-04 15:05   ` Luc Verhaegen
2014-08-04 15:31     ` [U-Boot] [linux-sunxi] " Henrik Nordström
2014-08-04 16:53       ` Michal Suchanek
2014-08-04 21:26         ` Henrik Nordström
2014-08-04 17:28       ` Luc Verhaegen
2014-08-04 22:10         ` Henrik Nordström
2014-08-05 20:55           ` Maxime Ripard
2014-08-05 21:03     ` Maxime Ripard
2014-08-05 21:37       ` Michal Suchanek
2014-08-06  7:24         ` [U-Boot] [linux-sunxi] " Koen Kooi
2014-08-06 11:10           ` Hans de Goede
2014-08-06 12:21         ` [U-Boot] [linux-sunxi] " Maxime Ripard
2014-08-05 11:56 ` [U-Boot] " Hans de Goede
2014-08-05 20:47   ` [U-Boot] [linux-sunxi] " Maxime Ripard
2014-08-06 11:40   ` [U-Boot] " Luc Verhaegen
2014-08-07  9:28     ` Hans de Goede

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.