Skip to contentSkip to conversation

video: add cfb console driver for sunxi

PATCH New Luc Verhaegen 6 participants 18 messages Aug 2, 2014 – Aug 7, 2014

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

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.

---
 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
arch/arm/include/asm/arch-sunxi/sunxi_display.h new file +21 -0
new file mode 100644
index 0000000..4456778
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2014 Luc Verhaegen <[email protected]>
+ *
+ * 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_ */
board/sunxi/board.c +14 -0
index 2179e23..e819b12 100644
@@ -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 */
drivers/video/Makefile +1 -0
index 945f35d..9a25c84 100644
@@ -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
drivers/video/sunxi_display.c new file +639 -0

639 lines not on this page · raw message

include/configs/sunxi-common.h +34 -0
index 8ab6429..89582b8 100644
@@ -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		*/
Signature · 1 line
1.7.7
#1 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

Hi Luc,

Quoted 6 lines · Luc Verhaegen

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.

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

Quoted 769 lines
---
 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
arch/arm/include/asm/arch-sunxi/sunxi_display.h new file +21 -0
new file mode 100644
index 0000000..4456778
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2014 Luc Verhaegen <[email protected]>
+ *
+ * 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_ */
board/sunxi/board.c +14 -0
index 2179e23..e819b12 100644
@@ -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 */
drivers/video/Makefile +1 -0
index 945f35d..9a25c84 100644
@@ -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
drivers/video/sunxi_display.c new file +639 -0
new file mode 100644
index 0000000..251fb67
@@ -0,0 +1,639 @@
+/*
+ * (C) Copyright 2013-2014 Luc Verhaegen <[email protected]>
+ *
+ * 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;
+}
include/configs/sunxi-common.h +34 -0
index 8ab6429..89582b8 100644
@@ -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		*/
#2 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

Quoted 14 lines · Hans de Goede

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.

Quoted 3 lines

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.

Quoted 9 lines

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.

#3 lore raw

m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen:

Quoted 7 lines

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

#4 lore raw
Quoted 9 lines · Henrik Nordstr?m

m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen:

Quoted 7 lines

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?

Quoted 6 lines

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

#5 lore raw

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

Quoted 1 line

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.

Quoted 2 lines

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).

Quoted 4 lines

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.

Quoted 4 lines

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

#6 lore raw
In reply to Henrik Nordström
Quoted 23 lines · Henrik Nordstr?m

m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen:

Quoted 7 lines

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.

Quoted 6 lines

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.

#7 lore raw

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

Quoted 5 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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?

Quoted 4 lines

* 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?

Quoted 5 lines

* 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?

Quoted 8 lines

* 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

#8 lore raw
Quoted 6 lines · Henrik Nordstr?m
Quoted 4 lines

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.

Quoted 6 lines
Quoted 4 lines

* 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.

Quoted 28 lines
Quoted 5 lines

* 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?

Quoted 8 lines

* 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.

Quoted 5 lines

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.

Signature · 10 lines
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>
#9 lore raw
In reply to Luc Verhaegen
Quoted 19 lines · Luc Verhaegen
Quoted 14 lines · Hans de Goede

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.

Quoted 3 lines

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.

Quoted 8 lines

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.

Signature · 10 lines
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>
#10 lore raw
Quoted 29 lines · Maxime Ripard
Quoted 19 lines · Luc Verhaegen
Quoted 14 lines · Hans de Goede

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.

Quoted 3 lines

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.

Quoted 8 lines

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".

Quoted 7 lines

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

#11 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

Op 5 aug. 2014, om 23:37 heeft Michal Suchanek <[email protected]> het volgende geschreven:

Quoted 42 lines · Maxime Ripard
Quoted 29 lines · Luc Verhaegen
Quoted 19 lines · Hans de Goede
Quoted 14 lines

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.

Quoted 3 lines

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.

Quoted 8 lines

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".

Quoted 7 lines

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.

Quoted 6 lines

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.

#12 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

Hi,

Quoted 45 lines · Koen Kooi

Op 5 aug. 2014, om 23:37 heeft Michal Suchanek <[email protected]> het volgende geschreven:

Quoted 42 lines · Maxime Ripard
Quoted 29 lines · Luc Verhaegen
Quoted 19 lines · Hans de Goede
Quoted 14 lines

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.

Quoted 3 lines

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.

Quoted 8 lines

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".

Quoted 7 lines

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.

Quoted 8 lines
Quoted 6 lines

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

#13 lore raw
In reply to Michal Suchanek
Quoted 11 lines · Michal Suchanek
Quoted 7 lines

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.

Quoted 2 lines

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.

Quoted 3 lines

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.

Signature · 10 lines
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>
#14 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

In reply to Luc Verhaegen

Hi,

Quoted 4 lines · Luc Verhaegen

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

Quoted 771 lines
---
 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
arch/arm/include/asm/arch-sunxi/sunxi_display.h new file +21 -0
new file mode 100644
index 0000000..4456778
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2014 Luc Verhaegen <[email protected]>
+ *
+ * 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_ */
board/sunxi/board.c +14 -0
index 2179e23..e819b12 100644
@@ -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 */
drivers/video/Makefile +1 -0
index 945f35d..9a25c84 100644
@@ -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
drivers/video/sunxi_display.c new file +639 -0
new file mode 100644
index 0000000..251fb67
@@ -0,0 +1,639 @@
+/*
+ * (C) Copyright 2013-2014 Luc Verhaegen <[email protected]>
+ *
+ * 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;
+}
include/configs/sunxi-common.h +34 -0
index 8ab6429..89582b8 100644
@@ -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		*/
#15 lore raw
Quoted 11 lines · Hans de Goede

Hi,

Quoted 4 lines · Luc Verhaegen

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:

Quoted 7 lines

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.

Quoted 9 lines

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.

Quoted 8 lines

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.

Signature · 10 lines
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>
#16 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

In reply to Hans de Goede
Quoted 11 lines · Hans de Goede

Hi,

Quoted 4 lines · Luc Verhaegen

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:

Quoted 7 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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.

#17 lore raw

PATCH 1/1 video: add cfb console driver for sunxi

Hi,

Quoted 33 lines · Luc Verhaegen
Quoted 11 lines · Hans de Goede

Hi,

Quoted 4 lines · Luc Verhaegen

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:

Quoted 7 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 5 lines

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.

Quoted 6 lines
Quoted 5 lines

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.

Quoted 7 lines

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