* [U-Boot] [PATCH] video: add cfb console driver for sunxi @ 2014-08-02 16:14 Luc Verhaegen 2014-08-04 8:39 ` Hans de Goede 2014-08-05 11:56 ` [U-Boot] " Hans de Goede 0 siblings, 2 replies; 18+ messages in thread From: Luc Verhaegen @ 2014-08-02 16:14 UTC (permalink / raw) To: u-boot This adds a fixed mode hdmi driver (lcd to be added in future) for the sunxi platform. Current config is such that 8MB is shaved off at the top of the RAM. Simplefb support is available for kernels that know how to use it. Signed-off-by: Luc Verhaegen <libv@skynet.be> --- arch/arm/include/asm/arch-sunxi/sunxi_display.h | 21 + board/sunxi/board.c | 14 + drivers/video/Makefile | 1 + drivers/video/sunxi_display.c | 639 +++++++++++++++++++++++ include/configs/sunxi-common.h | 34 ++ 5 files changed, 709 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/sunxi_display.h create mode 100644 drivers/video/sunxi_display.c diff --git a/arch/arm/include/asm/arch-sunxi/sunxi_display.h b/arch/arm/include/asm/arch-sunxi/sunxi_display.h new file mode 100644 index 0000000..4456778 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/sunxi_display.h @@ -0,0 +1,21 @@ +/* + * (C) Copyright 2014 Luc Verhaegen <libv@skynet.be> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation's version 2 and any + * later version the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _SUNXI_DISPLAY_H_ +#define _SUNXI_DISPLAY_H_ + +#ifdef CONFIG_VIDEO_DT_SIMPLEFB +void sunxi_simplefb_setup(void *blob); +#endif + +#endif /* _SUNXI_DISPLAY_H_ */ diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 2179e23..e819b12 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -26,6 +26,10 @@ #include <asm/io.h> #include <net.h> +#ifdef CONFIG_VIDEO +#include <asm/arch-sunxi/sunxi_display.h> +#endif + DECLARE_GLOBAL_DATA_PTR; /* add board specific code here */ @@ -185,3 +189,13 @@ int misc_init_r(void) return 0; } #endif + +#ifdef CONFIG_OF_BOARD_SETUP +void +ft_board_setup(void *blob, bd_t *bd) +{ +#ifdef CONFIG_VIDEO_DT_SIMPLEFB + sunxi_simplefb_setup(blob); +#endif +} +#endif /* CONFIG_OF_BOARD_SETUP */ diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 945f35d..9a25c84 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o obj-$(CONFIG_VIDEO_SED13806) += sed13806.o obj-$(CONFIG_VIDEO_SM501) += sm501.o obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o obj-$(CONFIG_VIDEO_TEGRA) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_FORMIKE) += formike.o diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c new file mode 100644 index 0000000..251fb67 --- /dev/null +++ b/drivers/video/sunxi_display.c @@ -0,0 +1,639 @@ +/* + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be> + * + * Display driver for Allwinner SoCs. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation's version 2 and any + * later version the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * This driver does nothing but HDMI at a fixed mode right now. At some + * point in the near future, LCD and VGA will be added. + * + * The display driver infrastructure in uboot does not immediately allow for + * modeline creation off of edid. The mode is therefor hardcoded to + * 1024x768 at 60Hz 32bpp. This is acceptable for most HDMI monitors, but far + * from ideal. If so desired, alter the modeline in video_hw_init() + */ + +#include <common.h> + +#include <asm/io.h> +#include <asm/global_data.h> +#include <video_fb.h> +#include <linux/fb.h> +#include <asm/arch-sunxi/sunxi_display.h> + +/* for simplefb */ +#ifdef CONFIG_OF_BOARD_SETUP +#include <libfdt.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_display { + GraphicDevice graphic_device[1]; + int enabled; +} sunxi_display[1]; + +/* + * Convenience functions to ease readability, and to provide an easy + * comparison with the sunxi kms driver. + */ +static unsigned int +sunxi_io_read(void *base, int offset) +{ + return readl(base + offset); +} + +static void +sunxi_io_write(void *base, int offset, unsigned int value) +{ + writel(value, base + offset); +} + +static void +sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask) +{ + unsigned int tmp = readl(base + offset); + + tmp &= ~mask; + tmp |= value & mask; + + writel(tmp, base + offset); +} + +/* + * CCMU regs: clocks. + */ +#define SUNXI_CCMU_PLL3_CFG 0x010 +#define SUNXI_CCMU_PLL5_CFG 0x020 +#define SUNXI_CCMU_PLL7_CFG 0x030 +#define SUNXI_CCMU_AHB_GATING1 0x064 +#define SUNXI_CCMU_DRAM_CLK_GATING 0x100 +#define SUNXI_DE_BE0_CLK 0x104 +#define SUNXI_LCDC0_CH0_CLK 0x118 +#define SUNXI_LCDC0_CH1_CLK 0x12C +#define SUNXI_CCMU_HDMI_CLK 0x150 + +/* + * DEBE regs. + * + * This is the entity that mixes and matches the different layers and inputs. + * Allwinner calls it the back-end, but i like composer better. + */ +#define SUNXI_COMP_MODE 0x800 +#define SUNXI_COMP_DISP_SIZE 0x808 +#define SUNXI_COMP_LAYER0_SIZE 0x810 +#define SUNXI_COMP_LAYER0_POS 0x820 +#define SUNXI_COMP_LAYER0_STRIDE 0x840 +#define SUNXI_COMP_LAYER0_ADDR_LOW 0X850 +#define SUNXI_COMP_LAYER_ADDR_HIGH 0X860 +#define SUNXI_COMP_REG_CTL 0X870 +#define SUNXI_COMP_LAYER0_ATTR0 0x890 +#define SUNXI_COMP_LAYER0_ATTR1 0x8a0 + +/* + * LCDC, what allwinner calls a CRTC, so timing controller and serializer. + */ +#define SUNXI_LCDC_ENABLE 0x000 +#define SUNXI_LCDC_INT0 0x004 +#define SUNXI_LCDC_INT1 0x008 +#define SUNXI_LCDC_TCON0_DOTCLOCK 0x044 +#define SUNXI_LCDC_TCON0_IO_TRI 0x08c +#define SUNXI_LCDC_TCON1_ENABLE 0x090 +#define SUNXI_LCDC_TCON1_TIMING_SRC 0x094 +#define SUNXI_LCDC_TCON1_TIMING_SCALE 0x098 +#define SUNXI_LCDC_TCON1_TIMING_OUT 0x09c +#define SUNXI_LCDC_TCON1_TIMING_H 0x0a0 +#define SUNXI_LCDC_TCON1_TIMING_V 0x0a4 +#define SUNXI_LCDC_TCON1_TIMING_SYNC 0x0a8 +#define SUNXI_LCDC_TCON1_IO_TRI 0x0f4 + +/* + * HDMI regs. + */ +#define SUNXI_HDMI_CTRL 0x004 +#define SUNXI_HDMI_INT_CTRL 0x008 +#define SUNXI_HDMI_HPD 0x00c +#define SUNXI_HDMI_VIDEO_CTRL 0x010 +#define SUNXI_HDMI_VIDEO_SIZE 0x014 +#define SUNXI_HDMI_VIDEO_BP 0x018 +#define SUNXI_HDMI_VIDEO_FP 0x01c +#define SUNXI_HDMI_VIDEO_SPW 0x020 +#define SUNXI_HDMI_VIDEO_POLARITY 0x024 +#define SUNXI_HDMI_TX_DRIVER0 0x200 +#define SUNXI_HDMI_TX_DRIVER1 0x204 +#define SUNXI_HDMI_TX_DRIVER2 0x208 +#define SUNXI_HDMI_TX_DRIVER3 0x20C + +static int +sunxi_hdmi_hpd_detect(void) +{ + void *ccmu = (void *) SUNXI_CCM_BASE; + void *hdmi = (void *) SUNXI_HDMI_BASE; + + /* set video pll1 to 300MHz */ + sunxi_io_write(ccmu, SUNXI_CCMU_PLL7_CFG, 0x8010D064); + + /* Set hdmi parent to video pll1 */ + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x01000000, 0x03000000); + + /* set ahb gating to pass */ + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x800, 0x800); + + /* clk on */ + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x80000000, 0x80000000); + + sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0x80000000); + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xA0800000); + + udelay(100); + + if (sunxi_io_read(hdmi, SUNXI_HDMI_HPD) & 0x01) + return 1; + + /* no need to keep these running. */ + sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0); + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0, 0x80000000); + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0, 0x800); + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL7_CFG, 0, 0x80000000); + + return 0; +} + +static int +sunxi_pll5_frequency(void) +{ + void *ccmu = (void *) SUNXI_CCM_BASE; + unsigned int pll5 = sunxi_io_read(ccmu, SUNXI_CCMU_PLL5_CFG); + int n, k, p; + + n = (pll5 >> 8) & 0x1F; + k = ((pll5 >> 4) & 0x03) + 1; + p = (pll5 >> 16) & 0x03; + + return (24000 * n * k) >> p; +} + +static void +sunxi_composer_init(void) +{ + void *ccmu = (void *) SUNXI_CCM_BASE; + void *composer = (void *) SUNXI_DE_BE0_BASE; + int pll5 = sunxi_pll5_frequency(); + int halve; + + if (pll5 < 300000) + halve = 0; + else + halve = 1; + + /* reset off */ + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x40000000, 0x40000000); + + /* set to pll5 */ + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x02000000, 0x03000000); + + if (halve) + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x01, 0x03); + else + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0, 0x03); + + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x1000, 0x1000); + sunxi_io_mask(ccmu, SUNXI_CCMU_DRAM_CLK_GATING, + 0x04000000, 0x04000000); + + /* enable */ + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x80000000, 0x80000000); + + /* engine bug, clear registers after reset. */ + { + /* + * Since uboot prototypes but never declares memset_io, we + * have to do this by hand. + */ + int i; + + for (i = 0x0800; i < 0x1000; i += 4) + sunxi_io_write(composer, i, 0); + } + + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x01, 0x01); +} + +static void +sunxi_composer_mode_set(struct fb_videomode *mode, unsigned int address) +{ + void *composer = (void *) SUNXI_DE_BE0_BASE; +#define SUNXI_FORMAT_XRGB8888 0x09 + unsigned int format = SUNXI_FORMAT_XRGB8888; + + /* enable */ + sunxi_io_write(composer, SUNXI_COMP_DISP_SIZE, + ((mode->yres - 1) << 16) | (mode->xres - 1)); + + sunxi_io_write(composer, SUNXI_COMP_LAYER0_SIZE, + ((mode->yres - 1) << 16) | (mode->xres - 1)); + sunxi_io_write(composer, SUNXI_COMP_LAYER0_STRIDE, mode->xres << 5); + sunxi_io_write(composer, SUNXI_COMP_LAYER0_ADDR_LOW, address << 3); + sunxi_io_mask(composer, SUNXI_COMP_LAYER_ADDR_HIGH, + address >> 29, 0xFF); + + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, format << 8, 0x0F00); + + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x04); + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x03); + + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x100, 0x100); +} + +static void +sunxi_lcdc_pll_set(int dotclock) +{ + void *ccmu = (void *) SUNXI_CCM_BASE; + int value, n, m, diff; + int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF; + int best_double = 0; + + if ((dotclock < 20000) || (dotclock > 400000)) { + printf("%s: Error: dotclock %d is out of range.\n", + __func__, dotclock); + return; + } + + for (m = 16; m > 0; m--) { + n = (m * dotclock) / 3000; + + if ((n > 9) && (n < 128)) { + value = (3000 * n) / m; + diff = value - dotclock; + if (diff < 0) + diff = -diff; + + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n = n; + best_double = 0; + } + } + + n++; + if ((n > 9) && (n < 128)) { + value = (3000 * n) / m; + diff = abs(value - dotclock); + if (diff < 0) + diff = -diff; + + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n = n; + best_double = 0; + } + } + + /* these are just duplicates. */ + if (!(m & 1)) + continue; + + n = (m * dotclock) / 6000; + if ((n > 63) && (n < 128)) { + value = (6000 * n) / m; + diff = abs(value - dotclock); + if (diff < 0) + diff = -diff; + + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n = n; + best_double = 1; + } + } + + n++; + if ((n > 63) && (n < 128)) { + value = (6000 * n) / m; + diff = abs(value - dotclock); + if (diff < 0) + diff = -diff; + + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n = n; + best_double = 1; + } + } + } + +#if 0 + if (best_double) + printf("dotclock: %06dkHz = %06dkHz: (2 * 3MHz * %d) / %d\n", + dotclock, (6000 * best_n) / best_m, best_n, best_m); + else + printf("dotclock: %06dkHz = %06dkHz: (3MHz * %d) / %d\n", + dotclock, (3000 * best_n) / best_m, best_n, best_m); +#endif + + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x80000000, 0x80000000); + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x8000, 0x8000); + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, best_n, 0x7F); + + if (best_double) + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, + 0x02000000, 0x03000000); + else + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, + 0, 0x03000000); + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, best_m - 1, 0x0F); + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800); + + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000); +} + +static void +sunxi_lcdc_init(void) +{ + void *ccmu = (void *) SUNXI_CCM_BASE; + void *lcdc = (void *) SUNXI_LCD0_BASE; + + /* Pll1 was already enabled in hpd detect. */ + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x01000000, 0x03000000); + + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x01000000, 0x03000000); + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800); + + /* just randomly set it@30MHz */ + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x09, 0x0F); + + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x40000000, 0x40000000); + + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x10, 0x10); + + /* toggle ch0 clock */ + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x80000000, 0x80000000); + while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH0_CLK) & 0x80000000) + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0, 0x80000000); + + /* toggle ch1 s1 & s2 clocks */ + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000); + while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK) & 0x80008000) + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x80008000); + + sunxi_io_write(lcdc, SUNXI_LCDC_ENABLE, 0); + + sunxi_io_write(lcdc, SUNXI_LCDC_INT0, 0); + sunxi_io_write(lcdc, SUNXI_LCDC_INT1, 0x20); + + /* + * disable tcon0 dot clock: + * This doesn't disable the dotclock, it just nulls the divider. + */ + sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_DOTCLOCK, 0xF0000000); + + /* all io lines disabled. */ + sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_IO_TRI, 0x0FFFFFFF); + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x0FFFFFFF); +} + +static void +sunxi_lcdc_mode_set(struct fb_videomode *mode) +{ + void *lcdc = (void *) SUNXI_LCD0_BASE; + int total; + + /* use tcon1 */ + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x01, 0x01); + + /* enabled, 0x1E start delay */ + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_ENABLE, 0x800001E0); + + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SRC, + ((mode->xres - 1) << 16) | (mode->yres - 1)); + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SCALE, + ((mode->xres - 1) << 16) | (mode->yres - 1)); + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_OUT, + ((mode->xres - 1) << 16) | (mode->yres - 1)); + + total = mode->left_margin + mode->xres + mode->right_margin + + mode->hsync_len; + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_H, + ((total - 1) << 16) | + (mode->hsync_len + mode->left_margin - 1)); + + total = mode->upper_margin + mode->yres + mode->lower_margin + + mode->vsync_len; + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_V, + ((total * 2) << 16) | + (mode->vsync_len + mode->upper_margin - 1)); + + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SYNC, + ((mode->hsync_len - 1) << 16) | (mode->vsync_len - 1)); + + sunxi_lcdc_pll_set(mode->pixclock); +} + +static void +sunxi_hdmi_mode_set(struct fb_videomode *mode) +{ + void *ccmu = (void *) SUNXI_CCM_BASE; + void *hdmi = (void *) SUNXI_HDMI_BASE; + int h, v, tmp; + + sunxi_io_write(hdmi, SUNXI_HDMI_INT_CTRL, 0xFFFFFFFF); + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x03FE0000); + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xDE000000, 0xDE000000); + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x00D8C820); + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER2, 0xD2000008); + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER3, 0); + + /* use video0 */ + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER3, 0, 0x00200000); + + tmp = sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK); + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER2, + ((tmp & 0x0F) + 1) << 4, 0xF0); + + if (tmp & 0x02000000) + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0, 0x40); + else + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x40, 0x40); + + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SIZE, + ((mode->yres - 1) << 16) | (mode->xres - 1)); + + h = mode->hsync_len + mode->left_margin; + v = mode->vsync_len + mode->upper_margin; + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_BP, ((v - 1) << 16) | (h - 1)); + + h = mode->right_margin; + v = mode->lower_margin; + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_FP, ((v - 1) << 16) | (h - 1)); + + h = mode->hsync_len; + v = mode->vsync_len; + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SPW, ((v - 1) << 16) | (h - 1)); + + if (mode->sync & FB_SYNC_HOR_HIGH_ACT) + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x01, 0x01); + else + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x01); + + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x02, 0x02); + else + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x02); +} + +static void +sunxi_engines_init(void) +{ + sunxi_composer_init(); + sunxi_lcdc_init(); +} + +static void +sunxi_mode_set(struct fb_videomode *mode, unsigned int address) +{ + void *composer = (void *) SUNXI_DE_BE0_BASE; + void *lcdc = (void *) SUNXI_LCD0_BASE; + void *hdmi = (void *) SUNXI_HDMI_BASE; + + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0, 0x80000000); + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0, 0x80000000); + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0, 0x02); + + sunxi_composer_mode_set(mode, address); + sunxi_lcdc_mode_set(mode); + sunxi_hdmi_mode_set(mode); + + sunxi_io_mask(composer, SUNXI_COMP_REG_CTL, 0x01, 0x01); + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x02, 0x02); + + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x80000000, 0x80000000); + sunxi_io_mask(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x00000000, 0x03000000); + + udelay(100); + + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0x80000000, 0x80000000); +} + +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB) +void +sunxi_simplefb_setup(void *blob) +{ + static GraphicDevice *graphic_device = sunxi_display->graphic_device; + const char *name = "simple-framebuffer"; + const char *format = "x8r8g8b8"; + fdt32_t cells[2]; + int offset, stride, ret; + + if (!sunxi_display->enabled) + return; + + offset = fdt_add_subnode(blob, 0, "framebuffer"); + if (offset < 0) { + printf("%s: add subnode failed", __func__); + return; + } + + ret = fdt_setprop(blob, offset, "compatible", name, strlen(name) + 1); + if (ret < 0) + return; + + stride = graphic_device->winSizeX * graphic_device->gdfBytesPP; + + cells[0] = cpu_to_fdt32(gd->fb_base); + cells[1] = cpu_to_fdt32(CONFIG_SUNXI_FB_SIZE); + ret = fdt_setprop(blob, offset, "reg", cells, sizeof(cells[0]) * 2); + if (ret < 0) + return; + + cells[0] = cpu_to_fdt32(graphic_device->winSizeX); + ret = fdt_setprop(blob, offset, "width", cells, sizeof(cells[0])); + if (ret < 0) + return; + + cells[0] = cpu_to_fdt32(graphic_device->winSizeY); + ret = fdt_setprop(blob, offset, "height", cells, sizeof(cells[0])); + if (ret < 0) + return; + + cells[0] = cpu_to_fdt32(stride); + ret = fdt_setprop(blob, offset, "stride", cells, sizeof(cells[0])); + if (ret < 0) + return; + + ret = fdt_setprop(blob, offset, "format", format, strlen(format) + 1); + if (ret < 0) + return; +} +#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */ + +void * +video_hw_init(void) +{ + static GraphicDevice *graphic_device = sunxi_display->graphic_device; + /* + * Vesa standard 1024x768 at 60 + * 65.0 1024 1032 1176 1344 768 771 777 806 -hsync -vsync + */ + struct fb_videomode mode = { + .name = "1024x768", + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 65000, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = 0, + .vmode = 0, + .flag = 0, + }; + int ret; + + memset(sunxi_display, 0, sizeof(struct sunxi_display)); + + printf("Reserved %dkB of RAM for Framebuffer.\n", + CONFIG_SUNXI_FB_SIZE >> 10); + gd->fb_base = gd->ram_top; + + ret = sunxi_hdmi_hpd_detect(); + if (!ret) + return NULL; + + printf("HDMI connected.\n"); + sunxi_display->enabled = 1; + + printf("Setting up a %s console.\n", mode.name); + sunxi_engines_init(); + sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE); + + /* + * These are the only members of this structure that are used. All the + * others are driver specific. There is nothing to decribe pitch or + * stride, but we are lucky with our hw. + */ + graphic_device->frameAdrs = gd->fb_base; + graphic_device->gdfIndex = GDF_32BIT_X888RGB; + graphic_device->gdfBytesPP = 4; + graphic_device->winSizeX = mode.xres; + graphic_device->winSizeY = mode.yres; + + return graphic_device; +} diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 8ab6429..89582b8 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -181,6 +181,40 @@ #define CONFIG_SUNXI_GPIO #define CONFIG_CMD_GPIO +/* Set this if you do not want a uboot fb console */ +#ifndef CONFIG_NO_VIDEO +#define CONFIG_VIDEO +#endif + +#ifdef CONFIG_VIDEO +/* + * The amount of RAM that is reserved for the FB. This will not show up as + * RAM to the kernel, but will be reclaimed by a KMS driver in future. + */ +#define CONFIG_SUNXI_FB_SIZE (8 << 20) + +/* Do we want to initialize a simple FB? */ +#define CONFIG_VIDEO_DT_SIMPLEFB + +#define CONFIG_VIDEO_SUNXI + +#define CONFIG_CFB_CONSOLE +/* allow both serial and cfb console. */ +#define CONFIG_CONSOLE_MUX +/* this is needed so the above will actually do something */ +#define CONFIG_SYS_CONSOLE_IS_IN_ENV +/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */ +#define CONFIG_VGA_AS_SINGLE_DEVICE + +#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF) + +/* To be able to hook simplefb into dt */ +#ifdef CONFIG_VIDEO_DT_SIMPLEFB +#define CONFIG_OF_BOARD_SETUP +#endif + +#endif /* CONFIG_VIDEO */ + /* Ethernet support */ #ifdef CONFIG_SUNXI_EMAC #define CONFIG_MII /* MII PHY management */ -- 1.7.7 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [U-Boot] [PATCH] video: add cfb console driver for sunxi 2014-08-02 16:14 [U-Boot] [PATCH] video: add cfb console driver for sunxi Luc Verhaegen @ 2014-08-04 8:39 ` Hans de Goede 2014-08-04 15:05 ` Luc Verhaegen 2014-08-05 11:56 ` [U-Boot] " Hans de Goede 1 sibling, 1 reply; 18+ messages in thread From: Hans de Goede @ 2014-08-04 8:39 UTC (permalink / raw) To: u-boot Hi Luc, On 08/02/2014 06:14 PM, Luc Verhaegen wrote: > This adds a fixed mode hdmi driver (lcd to be added in future) for the > sunxi platform. Current config is such that 8MB is shaved off at the top > of the RAM. Simplefb support is available for kernels that know how to > use it. > > Signed-off-by: Luc Verhaegen <libv@skynet.be> First of all many thanks for your work on this. ATM I don't have time to do a full review, but I don't expect there to be too many suprises when I do find the time. Really my only concern is the handover of the reserved memory, etc. to the kernel. We need to get a plan in place for that *before* this can be merged. Note I don't want to raise any artificial barriers here, I would love to see this merged ASAP. But I don't want to paint us in a corner where u-boot having hdmi console support makes it harder to get kms support in the kernel going. I think we can both agree on that. So I really want to see some plan how this will work in place before merging. Note just a plan, I don't expect kernel patches ready to be merged for this, just a good idea / sketch of how all the bits will fit together. In one of the threads about this there was some discussion about doing a "flicker free" handover. I agree with you that given that we will be fixed to 1024x768 in u-boot this won't be realistic. But in the light of that it would be nice if we could make it so that if none of the stdout and stderr variables point to vga we don't init the hdmi at all, this will avoid what ever is attached to first have to sync at 1024x768 and then at its native resolution when the kernel takes over, and this will also allow for an easy way to not steal the 8MB of memory for people who care about that (think headless server which is low on memory) Regards, Hans > --- > arch/arm/include/asm/arch-sunxi/sunxi_display.h | 21 + > board/sunxi/board.c | 14 + > drivers/video/Makefile | 1 + > drivers/video/sunxi_display.c | 639 +++++++++++++++++++++++ > include/configs/sunxi-common.h | 34 ++ > 5 files changed, 709 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/include/asm/arch-sunxi/sunxi_display.h > create mode 100644 drivers/video/sunxi_display.c > > diff --git a/arch/arm/include/asm/arch-sunxi/sunxi_display.h b/arch/arm/include/asm/arch-sunxi/sunxi_display.h > new file mode 100644 > index 0000000..4456778 > --- /dev/null > +++ b/arch/arm/include/asm/arch-sunxi/sunxi_display.h > @@ -0,0 +1,21 @@ > +/* > + * (C) Copyright 2014 Luc Verhaegen <libv@skynet.be> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation's version 2 and any > + * later version the License. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > +#ifndef _SUNXI_DISPLAY_H_ > +#define _SUNXI_DISPLAY_H_ > + > +#ifdef CONFIG_VIDEO_DT_SIMPLEFB > +void sunxi_simplefb_setup(void *blob); > +#endif > + > +#endif /* _SUNXI_DISPLAY_H_ */ > diff --git a/board/sunxi/board.c b/board/sunxi/board.c > index 2179e23..e819b12 100644 > --- a/board/sunxi/board.c > +++ b/board/sunxi/board.c > @@ -26,6 +26,10 @@ > #include <asm/io.h> > #include <net.h> > > +#ifdef CONFIG_VIDEO > +#include <asm/arch-sunxi/sunxi_display.h> > +#endif > + > DECLARE_GLOBAL_DATA_PTR; > > /* add board specific code here */ > @@ -185,3 +189,13 @@ int misc_init_r(void) > return 0; > } > #endif > + > +#ifdef CONFIG_OF_BOARD_SETUP > +void > +ft_board_setup(void *blob, bd_t *bd) > +{ > +#ifdef CONFIG_VIDEO_DT_SIMPLEFB > + sunxi_simplefb_setup(blob); > +#endif > +} > +#endif /* CONFIG_OF_BOARD_SETUP */ > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index 945f35d..9a25c84 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o > obj-$(CONFIG_VIDEO_SED13806) += sed13806.o > obj-$(CONFIG_VIDEO_SM501) += sm501.o > obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o > +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o > obj-$(CONFIG_VIDEO_TEGRA) += tegra.o > obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o > obj-$(CONFIG_FORMIKE) += formike.o > diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c > new file mode 100644 > index 0000000..251fb67 > --- /dev/null > +++ b/drivers/video/sunxi_display.c > @@ -0,0 +1,639 @@ > +/* > + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be> > + * > + * Display driver for Allwinner SoCs. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation's version 2 and any > + * later version the License. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +/* > + * This driver does nothing but HDMI at a fixed mode right now. At some > + * point in the near future, LCD and VGA will be added. > + * > + * The display driver infrastructure in uboot does not immediately allow for > + * modeline creation off of edid. The mode is therefor hardcoded to > + * 1024x768 at 60Hz 32bpp. This is acceptable for most HDMI monitors, but far > + * from ideal. If so desired, alter the modeline in video_hw_init() > + */ > + > +#include <common.h> > + > +#include <asm/io.h> > +#include <asm/global_data.h> > +#include <video_fb.h> > +#include <linux/fb.h> > +#include <asm/arch-sunxi/sunxi_display.h> > + > +/* for simplefb */ > +#ifdef CONFIG_OF_BOARD_SETUP > +#include <libfdt.h> > +#endif > + > +DECLARE_GLOBAL_DATA_PTR; > + > +struct sunxi_display { > + GraphicDevice graphic_device[1]; > + int enabled; > +} sunxi_display[1]; > + > +/* > + * Convenience functions to ease readability, and to provide an easy > + * comparison with the sunxi kms driver. > + */ > +static unsigned int > +sunxi_io_read(void *base, int offset) > +{ > + return readl(base + offset); > +} > + > +static void > +sunxi_io_write(void *base, int offset, unsigned int value) > +{ > + writel(value, base + offset); > +} > + > +static void > +sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask) > +{ > + unsigned int tmp = readl(base + offset); > + > + tmp &= ~mask; > + tmp |= value & mask; > + > + writel(tmp, base + offset); > +} > + > +/* > + * CCMU regs: clocks. > + */ > +#define SUNXI_CCMU_PLL3_CFG 0x010 > +#define SUNXI_CCMU_PLL5_CFG 0x020 > +#define SUNXI_CCMU_PLL7_CFG 0x030 > +#define SUNXI_CCMU_AHB_GATING1 0x064 > +#define SUNXI_CCMU_DRAM_CLK_GATING 0x100 > +#define SUNXI_DE_BE0_CLK 0x104 > +#define SUNXI_LCDC0_CH0_CLK 0x118 > +#define SUNXI_LCDC0_CH1_CLK 0x12C > +#define SUNXI_CCMU_HDMI_CLK 0x150 > + > +/* > + * DEBE regs. > + * > + * This is the entity that mixes and matches the different layers and inputs. > + * Allwinner calls it the back-end, but i like composer better. > + */ > +#define SUNXI_COMP_MODE 0x800 > +#define SUNXI_COMP_DISP_SIZE 0x808 > +#define SUNXI_COMP_LAYER0_SIZE 0x810 > +#define SUNXI_COMP_LAYER0_POS 0x820 > +#define SUNXI_COMP_LAYER0_STRIDE 0x840 > +#define SUNXI_COMP_LAYER0_ADDR_LOW 0X850 > +#define SUNXI_COMP_LAYER_ADDR_HIGH 0X860 > +#define SUNXI_COMP_REG_CTL 0X870 > +#define SUNXI_COMP_LAYER0_ATTR0 0x890 > +#define SUNXI_COMP_LAYER0_ATTR1 0x8a0 > + > +/* > + * LCDC, what allwinner calls a CRTC, so timing controller and serializer. > + */ > +#define SUNXI_LCDC_ENABLE 0x000 > +#define SUNXI_LCDC_INT0 0x004 > +#define SUNXI_LCDC_INT1 0x008 > +#define SUNXI_LCDC_TCON0_DOTCLOCK 0x044 > +#define SUNXI_LCDC_TCON0_IO_TRI 0x08c > +#define SUNXI_LCDC_TCON1_ENABLE 0x090 > +#define SUNXI_LCDC_TCON1_TIMING_SRC 0x094 > +#define SUNXI_LCDC_TCON1_TIMING_SCALE 0x098 > +#define SUNXI_LCDC_TCON1_TIMING_OUT 0x09c > +#define SUNXI_LCDC_TCON1_TIMING_H 0x0a0 > +#define SUNXI_LCDC_TCON1_TIMING_V 0x0a4 > +#define SUNXI_LCDC_TCON1_TIMING_SYNC 0x0a8 > +#define SUNXI_LCDC_TCON1_IO_TRI 0x0f4 > + > +/* > + * HDMI regs. > + */ > +#define SUNXI_HDMI_CTRL 0x004 > +#define SUNXI_HDMI_INT_CTRL 0x008 > +#define SUNXI_HDMI_HPD 0x00c > +#define SUNXI_HDMI_VIDEO_CTRL 0x010 > +#define SUNXI_HDMI_VIDEO_SIZE 0x014 > +#define SUNXI_HDMI_VIDEO_BP 0x018 > +#define SUNXI_HDMI_VIDEO_FP 0x01c > +#define SUNXI_HDMI_VIDEO_SPW 0x020 > +#define SUNXI_HDMI_VIDEO_POLARITY 0x024 > +#define SUNXI_HDMI_TX_DRIVER0 0x200 > +#define SUNXI_HDMI_TX_DRIVER1 0x204 > +#define SUNXI_HDMI_TX_DRIVER2 0x208 > +#define SUNXI_HDMI_TX_DRIVER3 0x20C > + > +static int > +sunxi_hdmi_hpd_detect(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *hdmi = (void *) SUNXI_HDMI_BASE; > + > + /* set video pll1 to 300MHz */ > + sunxi_io_write(ccmu, SUNXI_CCMU_PLL7_CFG, 0x8010D064); > + > + /* Set hdmi parent to video pll1 */ > + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x01000000, 0x03000000); > + > + /* set ahb gating to pass */ > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x800, 0x800); > + > + /* clk on */ > + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x80000000, 0x80000000); > + > + sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0x80000000); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xA0800000); > + > + udelay(100); > + > + if (sunxi_io_read(hdmi, SUNXI_HDMI_HPD) & 0x01) > + return 1; > + > + /* no need to keep these running. */ > + sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0); > + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0, 0x80000000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0, 0x800); > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL7_CFG, 0, 0x80000000); > + > + return 0; > +} > + > +static int > +sunxi_pll5_frequency(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + unsigned int pll5 = sunxi_io_read(ccmu, SUNXI_CCMU_PLL5_CFG); > + int n, k, p; > + > + n = (pll5 >> 8) & 0x1F; > + k = ((pll5 >> 4) & 0x03) + 1; > + p = (pll5 >> 16) & 0x03; > + > + return (24000 * n * k) >> p; > +} > + > +static void > +sunxi_composer_init(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *composer = (void *) SUNXI_DE_BE0_BASE; > + int pll5 = sunxi_pll5_frequency(); > + int halve; > + > + if (pll5 < 300000) > + halve = 0; > + else > + halve = 1; > + > + /* reset off */ > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x40000000, 0x40000000); > + > + /* set to pll5 */ > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x02000000, 0x03000000); > + > + if (halve) > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x01, 0x03); > + else > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0, 0x03); > + > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x1000, 0x1000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_DRAM_CLK_GATING, > + 0x04000000, 0x04000000); > + > + /* enable */ > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x80000000, 0x80000000); > + > + /* engine bug, clear registers after reset. */ > + { > + /* > + * Since uboot prototypes but never declares memset_io, we > + * have to do this by hand. > + */ > + int i; > + > + for (i = 0x0800; i < 0x1000; i += 4) > + sunxi_io_write(composer, i, 0); > + } > + > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x01, 0x01); > +} > + > +static void > +sunxi_composer_mode_set(struct fb_videomode *mode, unsigned int address) > +{ > + void *composer = (void *) SUNXI_DE_BE0_BASE; > +#define SUNXI_FORMAT_XRGB8888 0x09 > + unsigned int format = SUNXI_FORMAT_XRGB8888; > + > + /* enable */ > + sunxi_io_write(composer, SUNXI_COMP_DISP_SIZE, > + ((mode->yres - 1) << 16) | (mode->xres - 1)); > + > + sunxi_io_write(composer, SUNXI_COMP_LAYER0_SIZE, > + ((mode->yres - 1) << 16) | (mode->xres - 1)); > + sunxi_io_write(composer, SUNXI_COMP_LAYER0_STRIDE, mode->xres << 5); > + sunxi_io_write(composer, SUNXI_COMP_LAYER0_ADDR_LOW, address << 3); > + sunxi_io_mask(composer, SUNXI_COMP_LAYER_ADDR_HIGH, > + address >> 29, 0xFF); > + > + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, format << 8, 0x0F00); > + > + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x04); > + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x03); > + > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x100, 0x100); > +} > + > +static void > +sunxi_lcdc_pll_set(int dotclock) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + int value, n, m, diff; > + int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF; > + int best_double = 0; > + > + if ((dotclock < 20000) || (dotclock > 400000)) { > + printf("%s: Error: dotclock %d is out of range.\n", > + __func__, dotclock); > + return; > + } > + > + for (m = 16; m > 0; m--) { > + n = (m * dotclock) / 3000; > + > + if ((n > 9) && (n < 128)) { > + value = (3000 * n) / m; > + diff = value - dotclock; > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 0; > + } > + } > + > + n++; > + if ((n > 9) && (n < 128)) { > + value = (3000 * n) / m; > + diff = abs(value - dotclock); > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 0; > + } > + } > + > + /* these are just duplicates. */ > + if (!(m & 1)) > + continue; > + > + n = (m * dotclock) / 6000; > + if ((n > 63) && (n < 128)) { > + value = (6000 * n) / m; > + diff = abs(value - dotclock); > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 1; > + } > + } > + > + n++; > + if ((n > 63) && (n < 128)) { > + value = (6000 * n) / m; > + diff = abs(value - dotclock); > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 1; > + } > + } > + } > + > +#if 0 > + if (best_double) > + printf("dotclock: %06dkHz = %06dkHz: (2 * 3MHz * %d) / %d\n", > + dotclock, (6000 * best_n) / best_m, best_n, best_m); > + else > + printf("dotclock: %06dkHz = %06dkHz: (3MHz * %d) / %d\n", > + dotclock, (3000 * best_n) / best_m, best_n, best_m); > +#endif > + > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x80000000, 0x80000000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x8000, 0x8000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, best_n, 0x7F); > + > + if (best_double) > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, > + 0x02000000, 0x03000000); > + else > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, > + 0, 0x03000000); > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, best_m - 1, 0x0F); > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800); > + > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000); > +} > + > +static void > +sunxi_lcdc_init(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *lcdc = (void *) SUNXI_LCD0_BASE; > + > + /* Pll1 was already enabled in hpd detect. */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x01000000, 0x03000000); > + > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x01000000, 0x03000000); > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800); > + > + /* just randomly set it at 30MHz */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x09, 0x0F); > + > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x40000000, 0x40000000); > + > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x10, 0x10); > + > + /* toggle ch0 clock */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x80000000, 0x80000000); > + while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH0_CLK) & 0x80000000) > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0, 0x80000000); > + > + /* toggle ch1 s1 & s2 clocks */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000); > + while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK) & 0x80008000) > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x80008000); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_ENABLE, 0); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_INT0, 0); > + sunxi_io_write(lcdc, SUNXI_LCDC_INT1, 0x20); > + > + /* > + * disable tcon0 dot clock: > + * This doesn't disable the dotclock, it just nulls the divider. > + */ > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_DOTCLOCK, 0xF0000000); > + > + /* all io lines disabled. */ > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_IO_TRI, 0x0FFFFFFF); > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x0FFFFFFF); > +} > + > +static void > +sunxi_lcdc_mode_set(struct fb_videomode *mode) > +{ > + void *lcdc = (void *) SUNXI_LCD0_BASE; > + int total; > + > + /* use tcon1 */ > + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x01, 0x01); > + > + /* enabled, 0x1E start delay */ > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_ENABLE, 0x800001E0); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SRC, > + ((mode->xres - 1) << 16) | (mode->yres - 1)); > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SCALE, > + ((mode->xres - 1) << 16) | (mode->yres - 1)); > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_OUT, > + ((mode->xres - 1) << 16) | (mode->yres - 1)); > + > + total = mode->left_margin + mode->xres + mode->right_margin + > + mode->hsync_len; > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_H, > + ((total - 1) << 16) | > + (mode->hsync_len + mode->left_margin - 1)); > + > + total = mode->upper_margin + mode->yres + mode->lower_margin + > + mode->vsync_len; > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_V, > + ((total * 2) << 16) | > + (mode->vsync_len + mode->upper_margin - 1)); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SYNC, > + ((mode->hsync_len - 1) << 16) | (mode->vsync_len - 1)); > + > + sunxi_lcdc_pll_set(mode->pixclock); > +} > + > +static void > +sunxi_hdmi_mode_set(struct fb_videomode *mode) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *hdmi = (void *) SUNXI_HDMI_BASE; > + int h, v, tmp; > + > + sunxi_io_write(hdmi, SUNXI_HDMI_INT_CTRL, 0xFFFFFFFF); > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x03FE0000); > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xDE000000, 0xDE000000); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x00D8C820); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER2, 0xD2000008); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER3, 0); > + > + /* use video0 */ > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER3, 0, 0x00200000); > + > + tmp = sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK); > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER2, > + ((tmp & 0x0F) + 1) << 4, 0xF0); > + > + if (tmp & 0x02000000) > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0, 0x40); > + else > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x40, 0x40); > + > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SIZE, > + ((mode->yres - 1) << 16) | (mode->xres - 1)); > + > + h = mode->hsync_len + mode->left_margin; > + v = mode->vsync_len + mode->upper_margin; > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_BP, ((v - 1) << 16) | (h - 1)); > + > + h = mode->right_margin; > + v = mode->lower_margin; > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_FP, ((v - 1) << 16) | (h - 1)); > + > + h = mode->hsync_len; > + v = mode->vsync_len; > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SPW, ((v - 1) << 16) | (h - 1)); > + > + if (mode->sync & FB_SYNC_HOR_HIGH_ACT) > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x01, 0x01); > + else > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x01); > + > + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x02, 0x02); > + else > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x02); > +} > + > +static void > +sunxi_engines_init(void) > +{ > + sunxi_composer_init(); > + sunxi_lcdc_init(); > +} > + > +static void > +sunxi_mode_set(struct fb_videomode *mode, unsigned int address) > +{ > + void *composer = (void *) SUNXI_DE_BE0_BASE; > + void *lcdc = (void *) SUNXI_LCD0_BASE; > + void *hdmi = (void *) SUNXI_HDMI_BASE; > + > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0, 0x80000000); > + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0, 0x80000000); > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0, 0x02); > + > + sunxi_composer_mode_set(mode, address); > + sunxi_lcdc_mode_set(mode); > + sunxi_hdmi_mode_set(mode); > + > + sunxi_io_mask(composer, SUNXI_COMP_REG_CTL, 0x01, 0x01); > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x02, 0x02); > + > + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x80000000, 0x80000000); > + sunxi_io_mask(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x00000000, 0x03000000); > + > + udelay(100); > + > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0x80000000, 0x80000000); > +} > + > +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB) > +void > +sunxi_simplefb_setup(void *blob) > +{ > + static GraphicDevice *graphic_device = sunxi_display->graphic_device; > + const char *name = "simple-framebuffer"; > + const char *format = "x8r8g8b8"; > + fdt32_t cells[2]; > + int offset, stride, ret; > + > + if (!sunxi_display->enabled) > + return; > + > + offset = fdt_add_subnode(blob, 0, "framebuffer"); > + if (offset < 0) { > + printf("%s: add subnode failed", __func__); > + return; > + } > + > + ret = fdt_setprop(blob, offset, "compatible", name, strlen(name) + 1); > + if (ret < 0) > + return; > + > + stride = graphic_device->winSizeX * graphic_device->gdfBytesPP; > + > + cells[0] = cpu_to_fdt32(gd->fb_base); > + cells[1] = cpu_to_fdt32(CONFIG_SUNXI_FB_SIZE); > + ret = fdt_setprop(blob, offset, "reg", cells, sizeof(cells[0]) * 2); > + if (ret < 0) > + return; > + > + cells[0] = cpu_to_fdt32(graphic_device->winSizeX); > + ret = fdt_setprop(blob, offset, "width", cells, sizeof(cells[0])); > + if (ret < 0) > + return; > + > + cells[0] = cpu_to_fdt32(graphic_device->winSizeY); > + ret = fdt_setprop(blob, offset, "height", cells, sizeof(cells[0])); > + if (ret < 0) > + return; > + > + cells[0] = cpu_to_fdt32(stride); > + ret = fdt_setprop(blob, offset, "stride", cells, sizeof(cells[0])); > + if (ret < 0) > + return; > + > + ret = fdt_setprop(blob, offset, "format", format, strlen(format) + 1); > + if (ret < 0) > + return; > +} > +#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */ > + > +void * > +video_hw_init(void) > +{ > + static GraphicDevice *graphic_device = sunxi_display->graphic_device; > + /* > + * Vesa standard 1024x768 at 60 > + * 65.0 1024 1032 1176 1344 768 771 777 806 -hsync -vsync > + */ > + struct fb_videomode mode = { > + .name = "1024x768", > + .refresh = 60, > + .xres = 1024, > + .yres = 768, > + .pixclock = 65000, > + .left_margin = 160, > + .right_margin = 24, > + .upper_margin = 29, > + .lower_margin = 3, > + .hsync_len = 136, > + .vsync_len = 6, > + .sync = 0, > + .vmode = 0, > + .flag = 0, > + }; > + int ret; > + > + memset(sunxi_display, 0, sizeof(struct sunxi_display)); > + > + printf("Reserved %dkB of RAM for Framebuffer.\n", > + CONFIG_SUNXI_FB_SIZE >> 10); > + gd->fb_base = gd->ram_top; > + > + ret = sunxi_hdmi_hpd_detect(); > + if (!ret) > + return NULL; > + > + printf("HDMI connected.\n"); > + sunxi_display->enabled = 1; > + > + printf("Setting up a %s console.\n", mode.name); > + sunxi_engines_init(); > + sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE); > + > + /* > + * These are the only members of this structure that are used. All the > + * others are driver specific. There is nothing to decribe pitch or > + * stride, but we are lucky with our hw. > + */ > + graphic_device->frameAdrs = gd->fb_base; > + graphic_device->gdfIndex = GDF_32BIT_X888RGB; > + graphic_device->gdfBytesPP = 4; > + graphic_device->winSizeX = mode.xres; > + graphic_device->winSizeY = mode.yres; > + > + return graphic_device; > +} > diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h > index 8ab6429..89582b8 100644 > --- a/include/configs/sunxi-common.h > +++ b/include/configs/sunxi-common.h > @@ -181,6 +181,40 @@ > #define CONFIG_SUNXI_GPIO > #define CONFIG_CMD_GPIO > > +/* Set this if you do not want a uboot fb console */ > +#ifndef CONFIG_NO_VIDEO > +#define CONFIG_VIDEO > +#endif > + > +#ifdef CONFIG_VIDEO > +/* > + * The amount of RAM that is reserved for the FB. This will not show up as > + * RAM to the kernel, but will be reclaimed by a KMS driver in future. > + */ > +#define CONFIG_SUNXI_FB_SIZE (8 << 20) > + > +/* Do we want to initialize a simple FB? */ > +#define CONFIG_VIDEO_DT_SIMPLEFB > + > +#define CONFIG_VIDEO_SUNXI > + > +#define CONFIG_CFB_CONSOLE > +/* allow both serial and cfb console. */ > +#define CONFIG_CONSOLE_MUX > +/* this is needed so the above will actually do something */ > +#define CONFIG_SYS_CONSOLE_IS_IN_ENV > +/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */ > +#define CONFIG_VGA_AS_SINGLE_DEVICE > + > +#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF) > + > +/* To be able to hook simplefb into dt */ > +#ifdef CONFIG_VIDEO_DT_SIMPLEFB > +#define CONFIG_OF_BOARD_SETUP > +#endif > + > +#endif /* CONFIG_VIDEO */ > + > /* Ethernet support */ > #ifdef CONFIG_SUNXI_EMAC > #define CONFIG_MII /* MII PHY management */ > ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [PATCH] video: add cfb console driver for sunxi 2014-08-04 8:39 ` Hans de Goede @ 2014-08-04 15:05 ` Luc Verhaegen 2014-08-04 15:31 ` [U-Boot] [linux-sunxi] " Henrik Nordström 2014-08-05 21:03 ` Maxime Ripard 0 siblings, 2 replies; 18+ messages in thread From: Luc Verhaegen @ 2014-08-04 15:05 UTC (permalink / raw) To: u-boot On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote: > Hi Luc, > > First of all many thanks for your work on this. > > ATM I don't have time to do a full review, but I don't expect there > to be too many suprises when I do find the time. > > Really my only concern is the handover of the reserved memory, etc. to > the kernel. We need to get a plan in place for that *before* this can > be merged. Note I don't want to raise any artificial barriers here, > I would love to see this merged ASAP. But I don't want to paint us > in a corner where u-boot having hdmi console support makes it harder > to get kms support in the kernel going. I think we can both agree on that. > > So I really want to see some plan how this will work in place before merging. > Note just a plan, I don't expect kernel patches ready to be merged for this, > just a good idea / sketch of how all the bits will fit together. Memory is not the biggest worry. Some kernel code needs to claim clocks if the mode is to cleanly survive the start of the kernel. If not, there is no coming back until a proper display driver runs. If the simplefb driver claims these clocks, then the simplefb driver also must release these clocks, and this driver should then never be started again, so it should set the simplefb dt node status to "disabled". But that's not the full extent of this story. If we have a kms driver, then we need to claim these clocks, and set a proper mode on the hw. So the simplefb driver claiming these resources must've properly unclaimed them by then, _and_ have set the dt node to disabled. This kills your flicker-free right here unless there is a clean way for the kms driver to reclaim the clocks before the simplefb driver unclaims them. But... What do we do when u-boot sets up cfb, without setting up a simplefb node in the dt. Or what do we do when a simplefb node is set up, but no simplefb code is included in the kernel? Well, we then either need to claim the clocks, and make sure that nothing else touches the memory, or we need to cleanly disable the display engine. But which do we choose, do we keep the u-boot output forever, or do we sync off when the kernel starts? Suddenly, simplefb doesn't look as simple anymore. It's turned into quite the mess. Life is easy when you are called rpi, and you sweep everything under the videocore rug, and do everything behind the lesser cores back. But if you want to solve this properly, then you end up smearing bits of simplefb driver code all over the kernel tree. As for memory, that's closely tied into the clock code, as whatever code claims or disables the clocks for the display engine, that's also where the dt node gets set to disabled, and thus also where the memory either is added to some cma area directly, released from (upcoming) reserved memory, or forgotten. Simplefb at least gives us a nice handle on the location and size of the memory, so we can always find a workable solution. So i don't think the memory issue is as important. We already give the kernel a nice handle on that. How the kernel wishes to handle it in detail is then pretty much up to the kernel, and i expect the kernels behaviour to change when kms comes out and i have to think about dealing with simplefb. Clocks are quite a bit more crucial in this context. How the memory is handled needs to follow how the clocks are handled. > In one of the threads about this there was some discussion about doing a > "flicker free" handover. I agree with you that given that we will be fixed > to 1024x768 in u-boot this won't be realistic. But in the light of that > it would be nice if we could make it so that if none of the stdout and stderr > variables point to vga we don't init the hdmi at all, this will avoid > what ever is attached to first have to sync at 1024x768 and then at its > native resolution when the kernel takes over, and this will also allow > for an easy way to not steal the 8MB of memory for people who care about > that (think headless server which is low on memory) That's not how u-boot or the console code works. First off, this stdout/stderr variable setting, that's all handled after the driver has been loaded and an (extra) console device is created. The cfb console driver is created because of a build time config, but it is allowed to fail (in our case, because HPD says nothing is attached). Iirc, without iomux, the last created console driver is the one that gets stdout, stderr and stdin, so you lose the UART console. With iomux, you always need to load env for anything but the uart console to work. This means that you can have both cfb and uart working side by side, but you do not get anything on cfb unless the env is set as such. For a future spin of this patch, the logic around enabling this code will be swapped around. People will have to manually add VIDEO to their board config. There's just to many hairy cornercases and tough to answer "what if"s here, when you actually start thinking things through, to keep this as the default. Luc Verhaegen. ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-04 15:05 ` Luc Verhaegen @ 2014-08-04 15:31 ` Henrik Nordström 2014-08-04 16:53 ` Michal Suchanek 2014-08-04 17:28 ` Luc Verhaegen 2014-08-05 21:03 ` Maxime Ripard 1 sibling, 2 replies; 18+ messages in thread From: Henrik Nordström @ 2014-08-04 15:31 UTC (permalink / raw) To: u-boot m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen: > But... What do we do when u-boot sets up cfb, without setting up a > simplefb node in the dt. Or what do we do when a simplefb node is set > up, but no simplefb code is included in the kernel? Well, we then either > need to claim the clocks, and make sure that nothing else touches the > memory, or we need to cleanly disable the display engine. But which do > we choose, do we keep the u-boot output forever, or do we sync off when > the kernel starts? And what happens if we simply ignore it? Is there a risk of anything burning beyond software repair? If not, ignore it. There is no need to support all incompatible mixes even if it means some people will see strange fireworks on their screens when not following the software requirements. It's really no different from booting a kernel with wrong dt, or using a u-boot with wrong DRAM settings etc. An incompatible mix which is not meant to function properly. If you use a u-boot with this framebuffer support then you must also either use a kernel which supports being booted in such state, or make sure u-boot shuts things off before handing over to the kernel. If we can handle the situation gracefully in the kernel then fine, but it's by no means required, or even desired to spend any effort or even any serious thoughts on before compatible setups works. Regards Henrik ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-04 15:31 ` [U-Boot] [linux-sunxi] " Henrik Nordström @ 2014-08-04 16:53 ` Michal Suchanek 2014-08-04 21:26 ` Henrik Nordström 2014-08-04 17:28 ` Luc Verhaegen 1 sibling, 1 reply; 18+ messages in thread From: Michal Suchanek @ 2014-08-04 16:53 UTC (permalink / raw) To: u-boot On 4 August 2014 17:31, Henrik Nordstr?m <henrik@henriknordstrom.net> wrote: > m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen: >> But... What do we do when u-boot sets up cfb, without setting up a >> simplefb node in the dt. Or what do we do when a simplefb node is set >> up, but no simplefb code is included in the kernel? Well, we then either >> need to claim the clocks, and make sure that nothing else touches the >> memory, or we need to cleanly disable the display engine. But which do >> we choose, do we keep the u-boot output forever, or do we sync off when >> the kernel starts? > > And what happens if we simply ignore it? Is there a risk of anything > burning beyond software repair? If not, ignore it. There is no need to > support all incompatible mixes even if it means some people will see > strange fireworks on their screens when not following the software > requirements. > Then you have to define what is compatible. eg. you can define that if you do have simplefb in u-boot you should have it in kernel. If you do not have simplefb in kernel the fb memory may get reused and the clocks should get disabled as unused, eventually. Unless you set the debug option not to disable them. And KMS might eventually take over reprogramming or re-enabling the clocks again if you have it. Or as pointed out earlier you might find this unacceptable and even with simplefb compiled out the KMS driver would need enough simplefb logic to analyze the simplefb DT node and reuse the clocks and memory without reprogramming. With both simplefb and KMS you need the KMS driver to take over after simplefb. This is handled more or less gracefully with vesafb/offb/.. and whatever approach is used there might be of some use as example and the flicker-freeness of that approach as Linux standard. Thanks Michal ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-04 16:53 ` Michal Suchanek @ 2014-08-04 21:26 ` Henrik Nordström 0 siblings, 0 replies; 18+ messages in thread From: Henrik Nordström @ 2014-08-04 21:26 UTC (permalink / raw) To: u-boot m?n 2014-08-04 klockan 18:53 +0200 skrev Michal Suchanek: > Then you have to define what is compatible. Yes, and the part I responded to was odd unexpected combinations of u-boot only partially providing the right information (missing in DT) or kernel not having enabled support. Likewise there is the opposite situation which is also in the unsupported area, simplefb nodes in the DT but framebuffer not actually enabled by u-boot. Exact details on what needs to be provided in DT and how for glitch free handover from u-boot to KMS is a bit premature to dive into now. > eg. you can define that if you do have simplefb in u-boot you should > have it in kernel. Maybe. I am only saying that there is no need to try to cover all corner cases and odd/partial combinations. It's sufficient to cover two cases: all enabled, all disabled. In both u-boot, kernel and DT. (well, enabled in kernel but not in DT should be the same as disabled in kernel, so three cases). > If you do not have simplefb in kernel the fb memory may get reused and > the clocks should get disabled as unused, eventually. Unless you set > the debug option not to disable them. And KMS might eventually take > over reprogramming or re-enabling the clocks again if you have it. Memory would be lost today if the region is reserved in DT, but may eventually be reclaimed when support is available in kernel. And user should expect strange display effects as clock sources and eventually memory gets reprogrammed and/or repurposed without anything shutting off the disaplay engine. I do not see a problem here. My preferred solution to this problem is to have u-boot shut off (or not enable) the display engine before starting the kernel, and to provide a DT without simplefb nodes. Don't worry too much about this odd case in the kernel. > Or as pointed out earlier you might find this unacceptable and even > with simplefb compiled out the KMS driver would need enough simplefb > logic to analyze the simplefb DT node and reuse the clocks and memory > without reprogramming. Maybe, but glich free handover is not a primary or even high priority goal, or even what I really commented on. It's something that can be looked into when KMS is functional. And missing support should cause no more than a temporary display glitch until KMS have fully claimed and programed the display components. Likely on the same scale as KMS selecting another display mode. Regards Henrik ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-04 15:31 ` [U-Boot] [linux-sunxi] " Henrik Nordström 2014-08-04 16:53 ` Michal Suchanek @ 2014-08-04 17:28 ` Luc Verhaegen 2014-08-04 22:10 ` Henrik Nordström 1 sibling, 1 reply; 18+ messages in thread From: Luc Verhaegen @ 2014-08-04 17:28 UTC (permalink / raw) To: u-boot On Mon, Aug 04, 2014 at 05:31:36PM +0200, Henrik Nordstr?m wrote: > m?n 2014-08-04 klockan 17:05 +0200 skrev Luc Verhaegen: > > But... What do we do when u-boot sets up cfb, without setting up a > > simplefb node in the dt. Or what do we do when a simplefb node is set > > up, but no simplefb code is included in the kernel? Well, we then either > > need to claim the clocks, and make sure that nothing else touches the > > memory, or we need to cleanly disable the display engine. But which do > > we choose, do we keep the u-boot output forever, or do we sync off when > > the kernel starts? > > And what happens if we simply ignore it? Is there a risk of anything > burning beyond software repair? If not, ignore it. There is no need to > support all incompatible mixes even if it means some people will see > strange fireworks on their screens when not following the software > requirements. > > It's really no different from booting a kernel with wrong dt, or using a > u-boot with wrong DRAM settings etc. An incompatible mix which is not > meant to function properly. > > If you use a u-boot with this framebuffer support then you must also > either use a kernel which supports being booted in such state, or make > sure u-boot shuts things off before handing over to the kernel. > > If we can handle the situation gracefully in the kernel then fine, but > it's by no means required, or even desired to spend any effort or even > any serious thoughts on before compatible setups works. > > Regards > Henrik We can work around most situations gracefully in kernelspace. We should for instance never set a bad mode, and never show random memory content, as that is a total no-go. So some code will have to exist to cleanly disable the display engine (we're in luck, we only need to poke the ahb gating and some clocks). But if we can overlook some of the above, we also should just consider the memory lost until a kms driver kicks in, and ioremaps/whatevers it for its own use. How's this for the sunxi implementation of simplefb: * u-boot lists used clocks, to allow some code in simplefb.c to grab all clocks. This is necessary as the list of clocks might change with changed cfb-console driver functionality. * when the clocks get disabled, the existing display engine setup becomes useless. the dt simplefb node has its status set to disabled. The memory range info remains, none of the reserved ram is returned to system. This needs to happen in both simplefb.c and in clk-sunxi.c. * when the memory range gets mapped by the kms driver (currently, on sunxi-3.4 i just use the full disp driver reserved range directly) in a way that it will be released again at unload, the memory range info remains. This ensures that future kms driver reloads can still grab this memory. * when however the memory range gets mapped to cma globally, the memory range info is removed. It makes sense to add the clock handling and the disabling of the simple-framebuffer node in the actual simplefb driver. The memory handling should be considered platform specific behaviour for now, but perhaps dt reserved memory infrastructure can come to the rescue in future. Luc Verhaegen. ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-04 17:28 ` Luc Verhaegen @ 2014-08-04 22:10 ` Henrik Nordström 2014-08-05 20:55 ` Maxime Ripard 0 siblings, 1 reply; 18+ messages in thread From: Henrik Nordström @ 2014-08-04 22:10 UTC (permalink / raw) To: u-boot m?n 2014-08-04 klockan 19:28 +0200 skrev Luc Verhaegen: > We can work around most situations gracefully in kernelspace. We should > for instance never set a bad mode, and never show random memory content, > as that is a total no-go. So some code will have to exist to cleanly > disable the display engine (we're in luck, we only need to poke the ahb > gating and some clocks). I seriously don't worry about display mode corruption or showing random memory if people boot configurations/combinations which are not supported. > But if we can overlook some of the above, we also should just consider > the memory lost until a kms driver kicks in, and ioremaps/whatevers it > for its own use. If it in any way hinders development of the KMS driver then yes. > How's this for the sunxi implementation of simplefb: > * u-boot lists used clocks, to allow some code in simplefb.c to grab all > clocks. This is necessary as the list of clocks might change with > changed cfb-console driver functionality. Is this list of clocks in any way different from what KMS needs to use? > * when the clocks get disabled, the existing display engine setup > becomes useless. the dt simplefb node has its status set to disabled. > The memory range info remains, none of the reserved ram is returned > to system. This needs to happen in both simplefb.c and in clk-sunxi.c. Disabled by whom? > * when the memory range gets mapped by the kms driver (currently, on > sunxi-3.4 i just use the full disp driver reserved range directly) in > a way that it will be released again at unload, the memory range info > remains. This ensures that future kms driver reloads can still grab > this memory. Why do a KMS reload need to be able to grab the same memory again? The display is shut off when the KMS driver is unloaded, right? Or this only temporary? > * when however the memory range gets mapped to cma globally, the memory > range info is removed. > > It makes sense to add the clock handling and the disabling of the > simple-framebuffer node in the actual simplefb driver. The memory > handling should be considered platform specific behaviour for now, but > perhaps dt reserved memory infrastructure can come to the rescue in > future. Maybe, but people who need framebuffer in u-boot likley need it in kernel as well I would think, so I do not worry much about releasing the memory back to kernel for general purpose use if it has been reserved by u-boot. If you really have no use of the display then don't enable it in the first place (or make sure it's shut off). Including any memory reservations. Similar to PC BIOS settings for reserved (shared) memory on many IGP devices. You don't normally change such settings in kernel. If you want a different memory layout then shut down, change BIOS settings and boot again. Not a problem imho. (shut down, change u-boot & DT settings, boot again). Regards Henrik ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-04 22:10 ` Henrik Nordström @ 2014-08-05 20:55 ` Maxime Ripard 0 siblings, 0 replies; 18+ messages in thread From: Maxime Ripard @ 2014-08-05 20:55 UTC (permalink / raw) To: u-boot On Tue, Aug 05, 2014 at 12:10:30AM +0200, Henrik Nordstr?m wrote: > > How's this for the sunxi implementation of simplefb: > > * u-boot lists used clocks, to allow some code in simplefb.c to grab all > > clocks. This is necessary as the list of clocks might change with > > changed cfb-console driver functionality. > > Is this list of clocks in any way different from what KMS needs to use? Not really, but Luc haven't been using all the clocks that might be used by the KMS driver, and just uses a subset of it. > > * when the clocks get disabled, the existing display engine setup > > becomes useless. the dt simplefb node has its status set to disabled. > > The memory range info remains, none of the reserved ram is returned > > to system. This needs to happen in both simplefb.c and in clk-sunxi.c. > > Disabled by whom? Linux' clock framework. > > * when the memory range gets mapped by the kms driver (currently, on > > sunxi-3.4 i just use the full disp driver reserved range directly) in > > a way that it will be released again at unload, the memory range info > > remains. This ensures that future kms driver reloads can still grab > > this memory. > > Why do a KMS reload need to be able to grab the same memory again? The > display is shut off when the KMS driver is unloaded, right? Or this only > temporary? > > > * when however the memory range gets mapped to cma globally, the memory > > range info is removed. > > > > It makes sense to add the clock handling and the disabling of the > > simple-framebuffer node in the actual simplefb driver. The memory > > handling should be considered platform specific behaviour for now, but > > perhaps dt reserved memory infrastructure can come to the rescue in > > future. > > Maybe, but people who need framebuffer in u-boot likley need it in > kernel as well I would think, so I do not worry much about releasing the > memory back to kernel for general purpose use if it has been reserved by > u-boot. > > If you really have no use of the display then don't enable it in the > first place (or make sure it's shut off). Including any memory > reservations. > > Similar to PC BIOS settings for reserved (shared) memory on many IGP > devices. You don't normally change such settings in kernel. If you want > a different memory layout then shut down, change BIOS settings and boot > again. Not a problem imho. (shut down, change u-boot & DT settings, boot > again). Except that here, "change u-boot & DT settings" means "recompile u-boot and the DT, and flash the whole thing again to your system". Not really as painless as what you're suggesting. -- Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140805/5d94b6a5/attachment.pgp> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-04 15:05 ` Luc Verhaegen 2014-08-04 15:31 ` [U-Boot] [linux-sunxi] " Henrik Nordström @ 2014-08-05 21:03 ` Maxime Ripard 2014-08-05 21:37 ` Michal Suchanek 1 sibling, 1 reply; 18+ messages in thread From: Maxime Ripard @ 2014-08-05 21:03 UTC (permalink / raw) To: u-boot On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote: > On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote: > > Hi Luc, > > > > First of all many thanks for your work on this. > > > > ATM I don't have time to do a full review, but I don't expect there > > to be too many suprises when I do find the time. > > > > Really my only concern is the handover of the reserved memory, etc. to > > the kernel. We need to get a plan in place for that *before* this can > > be merged. Note I don't want to raise any artificial barriers here, > > I would love to see this merged ASAP. But I don't want to paint us > > in a corner where u-boot having hdmi console support makes it harder > > to get kms support in the kernel going. I think we can both agree on that. > > > > So I really want to see some plan how this will work in place before merging. > > Note just a plan, I don't expect kernel patches ready to be merged for this, > > just a good idea / sketch of how all the bits will fit together. > > Memory is not the biggest worry. > > Some kernel code needs to claim clocks if the mode is to cleanly survive > the start of the kernel. If not, there is no coming back until a proper > display driver runs. If the simplefb driver claims these clocks, then > the simplefb driver also must release these clocks, and this driver > should then never be started again, so it should set the simplefb dt > node status to "disabled". I'm probably missing a bit of context, but one thing I still don't get is why you're taking into account the simplefb <-> KMS handover. It's a case that shouldn't exist. By essence, simplefb has never been meant for that. It's been meant to have a temporary solution until a full-fledged driver is merged in the kernel. Which is exactly the case we're into. But once the KMS driver gone, I'd just expect simplefb to go away. -- Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140805/f83a7c6e/attachment.pgp> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-05 21:03 ` Maxime Ripard @ 2014-08-05 21:37 ` Michal Suchanek 2014-08-06 7:24 ` [U-Boot] [linux-sunxi] " Koen Kooi 2014-08-06 12:21 ` [U-Boot] [linux-sunxi] " Maxime Ripard 0 siblings, 2 replies; 18+ messages in thread From: Michal Suchanek @ 2014-08-05 21:37 UTC (permalink / raw) To: u-boot On 5 August 2014 23:03, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: > On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote: >> On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote: >> > Hi Luc, >> > >> > First of all many thanks for your work on this. >> > >> > ATM I don't have time to do a full review, but I don't expect there >> > to be too many suprises when I do find the time. >> > >> > Really my only concern is the handover of the reserved memory, etc. to >> > the kernel. We need to get a plan in place for that *before* this can >> > be merged. Note I don't want to raise any artificial barriers here, >> > I would love to see this merged ASAP. But I don't want to paint us >> > in a corner where u-boot having hdmi console support makes it harder >> > to get kms support in the kernel going. I think we can both agree on that. >> > >> > So I really want to see some plan how this will work in place before merging. >> > Note just a plan, I don't expect kernel patches ready to be merged for this, >> > just a good idea / sketch of how all the bits will fit together. >> >> Memory is not the biggest worry. >> >> Some kernel code needs to claim clocks if the mode is to cleanly survive >> the start of the kernel. If not, there is no coming back until a proper >> display driver runs. If the simplefb driver claims these clocks, then >> the simplefb driver also must release these clocks, and this driver >> should then never be started again, so it should set the simplefb dt >> node status to "disabled". > > I'm probably missing a bit of context, but one thing I still don't get > is why you're taking into account the simplefb <-> KMS handover. It's > a case that shouldn't exist. > > By essence, simplefb has never been meant for that. It's been meant to > have a temporary solution until a full-fledged driver is merged in the > kernel. Which is exactly the case we're into. It's a permanent temporary solution. Same as offb/vesafb/uefi and other unaccelerated drivers. It will be needed for platforms on which KMS is not (yet) fully supported or happens to break. Also how else do you express the fact that u-boot has left the display enabled other than generating the simplefb DT node? Note that the KMS driver will be probably unsuitable for early console while the simplefb driver can just write into the framebuffer set up by u-boot. Thanks Michal ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] [PATCH] video: add cfb console driver for sunxi 2014-08-05 21:37 ` Michal Suchanek @ 2014-08-06 7:24 ` Koen Kooi 2014-08-06 11:10 ` Hans de Goede 2014-08-06 12:21 ` [U-Boot] [linux-sunxi] " Maxime Ripard 1 sibling, 1 reply; 18+ messages in thread From: Koen Kooi @ 2014-08-06 7:24 UTC (permalink / raw) To: u-boot Op 5 aug. 2014, om 23:37 heeft Michal Suchanek <hramrach@gmail.com> het volgende geschreven: > On 5 August 2014 23:03, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: >> On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote: >>> On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote: >>>> Hi Luc, >>>> >>>> First of all many thanks for your work on this. >>>> >>>> ATM I don't have time to do a full review, but I don't expect there >>>> to be too many suprises when I do find the time. >>>> >>>> Really my only concern is the handover of the reserved memory, etc. to >>>> the kernel. We need to get a plan in place for that *before* this can >>>> be merged. Note I don't want to raise any artificial barriers here, >>>> I would love to see this merged ASAP. But I don't want to paint us >>>> in a corner where u-boot having hdmi console support makes it harder >>>> to get kms support in the kernel going. I think we can both agree on that. >>>> >>>> So I really want to see some plan how this will work in place before merging. >>>> Note just a plan, I don't expect kernel patches ready to be merged for this, >>>> just a good idea / sketch of how all the bits will fit together. >>> >>> Memory is not the biggest worry. >>> >>> Some kernel code needs to claim clocks if the mode is to cleanly survive >>> the start of the kernel. If not, there is no coming back until a proper >>> display driver runs. If the simplefb driver claims these clocks, then >>> the simplefb driver also must release these clocks, and this driver >>> should then never be started again, so it should set the simplefb dt >>> node status to "disabled". >> >> I'm probably missing a bit of context, but one thing I still don't get >> is why you're taking into account the simplefb <-> KMS handover. It's >> a case that shouldn't exist. >> >> By essence, simplefb has never been meant for that. It's been meant to >> have a temporary solution until a full-fledged driver is merged in the >> kernel. Which is exactly the case we're into. > > It's a permanent temporary solution. Same as offb/vesafb/uefi and > other unaccelerated drivers. It will be needed for platforms on which > KMS is not (yet) fully supported or happens to break. > > Also how else do you express the fact that u-boot has left the display > enabled other than generating the simplefb DT node? > > Note that the KMS driver will be probably unsuitable for early console > while the simplefb driver can just write into the framebuffer set up > by u-boot. Both simplefb and the potention sunxifb will be using the same kernel infrastructure and start printing at the same time, so your argument about simplefb being able to print 'earlier' is nonsense. ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] [PATCH] video: add cfb console driver for sunxi 2014-08-06 7:24 ` [U-Boot] [linux-sunxi] " Koen Kooi @ 2014-08-06 11:10 ` Hans de Goede 0 siblings, 0 replies; 18+ messages in thread From: Hans de Goede @ 2014-08-06 11:10 UTC (permalink / raw) To: u-boot Hi, On 08/06/2014 09:24 AM, Koen Kooi wrote: > > Op 5 aug. 2014, om 23:37 heeft Michal Suchanek <hramrach@gmail.com> het volgende geschreven: > >> On 5 August 2014 23:03, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: >>> On Mon, Aug 04, 2014 at 05:05:00PM +0200, Luc Verhaegen wrote: >>>> On Mon, Aug 04, 2014 at 10:39:13AM +0200, Hans de Goede wrote: >>>>> Hi Luc, >>>>> >>>>> First of all many thanks for your work on this. >>>>> >>>>> ATM I don't have time to do a full review, but I don't expect there >>>>> to be too many suprises when I do find the time. >>>>> >>>>> Really my only concern is the handover of the reserved memory, etc. to >>>>> the kernel. We need to get a plan in place for that *before* this can >>>>> be merged. Note I don't want to raise any artificial barriers here, >>>>> I would love to see this merged ASAP. But I don't want to paint us >>>>> in a corner where u-boot having hdmi console support makes it harder >>>>> to get kms support in the kernel going. I think we can both agree on that. >>>>> >>>>> So I really want to see some plan how this will work in place before merging. >>>>> Note just a plan, I don't expect kernel patches ready to be merged for this, >>>>> just a good idea / sketch of how all the bits will fit together. >>>> >>>> Memory is not the biggest worry. >>>> >>>> Some kernel code needs to claim clocks if the mode is to cleanly survive >>>> the start of the kernel. If not, there is no coming back until a proper >>>> display driver runs. If the simplefb driver claims these clocks, then >>>> the simplefb driver also must release these clocks, and this driver >>>> should then never be started again, so it should set the simplefb dt >>>> node status to "disabled". >>> >>> I'm probably missing a bit of context, but one thing I still don't get >>> is why you're taking into account the simplefb <-> KMS handover. It's >>> a case that shouldn't exist. >>> >>> By essence, simplefb has never been meant for that. It's been meant to >>> have a temporary solution until a full-fledged driver is merged in the >>> kernel. Which is exactly the case we're into. >> >> It's a permanent temporary solution. Same as offb/vesafb/uefi and >> other unaccelerated drivers. It will be needed for platforms on which >> KMS is not (yet) fully supported or happens to break. >> >> Also how else do you express the fact that u-boot has left the display >> enabled other than generating the simplefb DT node? >> >> Note that the KMS driver will be probably unsuitable for early console >> while the simplefb driver can just write into the framebuffer set up >> by u-boot. > > Both simplefb and the potention sunxifb will be using the same kernel infrastructure and start printing at the same time, so your argument about simplefb being able to print 'earlier' is nonsense. Distros typically build kms drivers as modules, since there can be many different gpus on a single platform (even for arm now that we have multi arm v7 support). So I think that having simplefb build in, and then having the kms driver taking over when it loads make sense, and this is also more or less how it works on x86. Regards, Hans ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-05 21:37 ` Michal Suchanek 2014-08-06 7:24 ` [U-Boot] [linux-sunxi] " Koen Kooi @ 2014-08-06 12:21 ` Maxime Ripard 1 sibling, 0 replies; 18+ messages in thread From: Maxime Ripard @ 2014-08-06 12:21 UTC (permalink / raw) To: u-boot On Tue, Aug 05, 2014 at 11:37:11PM +0200, Michal Suchanek wrote: > > I'm probably missing a bit of context, but one thing I still don't get > > is why you're taking into account the simplefb <-> KMS handover. It's > > a case that shouldn't exist. > > > > By essence, simplefb has never been meant for that. It's been meant to > > have a temporary solution until a full-fledged driver is merged in the > > kernel. Which is exactly the case we're into. > > It's a permanent temporary solution. Same as offb/vesafb/uefi and > other unaccelerated drivers. It will be needed for platforms on which > KMS is not (yet) fully supported or happens to break. Yeah, I get that part, but there's no handover in this case. > Also how else do you express the fact that u-boot has left the display > enabled other than generating the simplefb DT node? Just like timers, UARTs, i2c, ethernet, and any other controller that might be used by the OS: the OS should deal with it. We don't use a simplefb-equivalent for the PMIC, or for the GMAC, I don't see why we should use one here to deal with that issue. What resources are you afraid to waste here? clocks are reclaimed automatically, memory is not, but simplefb won't help, see our discussion on the othre thread about this patch. > Note that the KMS driver will be probably unsuitable for early console > while the simplefb driver can just write into the framebuffer set up > by u-boot. They both step in at the same time. simplefb is not a solution for that either. -- Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140806/ffcfa4aa/attachment.pgp> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [PATCH] video: add cfb console driver for sunxi 2014-08-02 16:14 [U-Boot] [PATCH] video: add cfb console driver for sunxi Luc Verhaegen 2014-08-04 8:39 ` Hans de Goede @ 2014-08-05 11:56 ` Hans de Goede 2014-08-05 20:47 ` [U-Boot] [linux-sunxi] " Maxime Ripard 2014-08-06 11:40 ` [U-Boot] " Luc Verhaegen 1 sibling, 2 replies; 18+ messages in thread From: Hans de Goede @ 2014-08-05 11:56 UTC (permalink / raw) To: u-boot Hi, On 08/02/2014 06:14 PM, Luc Verhaegen wrote: > This adds a fixed mode hdmi driver (lcd to be added in future) for the > sunxi platform. Current config is such that 8MB is shaved off at the top > of the RAM. Simplefb support is available for kernels that know how to > use it. I've been trying to follow all the discussion in this thread, and here is what I think we should do: 1) There has been some discussion about using this console-driver in u-boot without generating the simplefb dt node. This means yet another variation in how all the bits fit together, so I don't think we should do this. Note I realize that the original patch did not have a specific config option for this, but it was mentioned later in the thread. TL;DR: Enabling the console driver will always generate the simplefb dt node. 2) I think we can worry about what to do with the reserved memory\when not using simplefb (or when switching from simplefb to kms) later. For now lets focus on the issue with the clocks. 3) To me the issue with clocks seems simple, we should modify the devicetree binding for simplefb to support a clocks property, and modify the simplefb kernel code to get + prep_and_enable any clocks specified in the dt node. This means parsing enough of the dt to find the clocks to be able to specify phandles to them in the added node. I don't know how hard it will be to do this in u-boot, but IMHO it is simply the right thing to do, so this is how it should be done. If others agree that specifying the clocks in the simplefb dt node is the right way to ensure that the clocks don't get enabled I'm willing at taking a shot on coding this. Regards, Hans > > Signed-off-by: Luc Verhaegen <libv@skynet.be> > --- > arch/arm/include/asm/arch-sunxi/sunxi_display.h | 21 + > board/sunxi/board.c | 14 + > drivers/video/Makefile | 1 + > drivers/video/sunxi_display.c | 639 +++++++++++++++++++++++ > include/configs/sunxi-common.h | 34 ++ > 5 files changed, 709 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/include/asm/arch-sunxi/sunxi_display.h > create mode 100644 drivers/video/sunxi_display.c > > diff --git a/arch/arm/include/asm/arch-sunxi/sunxi_display.h b/arch/arm/include/asm/arch-sunxi/sunxi_display.h > new file mode 100644 > index 0000000..4456778 > --- /dev/null > +++ b/arch/arm/include/asm/arch-sunxi/sunxi_display.h > @@ -0,0 +1,21 @@ > +/* > + * (C) Copyright 2014 Luc Verhaegen <libv@skynet.be> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation's version 2 and any > + * later version the License. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > +#ifndef _SUNXI_DISPLAY_H_ > +#define _SUNXI_DISPLAY_H_ > + > +#ifdef CONFIG_VIDEO_DT_SIMPLEFB > +void sunxi_simplefb_setup(void *blob); > +#endif > + > +#endif /* _SUNXI_DISPLAY_H_ */ > diff --git a/board/sunxi/board.c b/board/sunxi/board.c > index 2179e23..e819b12 100644 > --- a/board/sunxi/board.c > +++ b/board/sunxi/board.c > @@ -26,6 +26,10 @@ > #include <asm/io.h> > #include <net.h> > > +#ifdef CONFIG_VIDEO > +#include <asm/arch-sunxi/sunxi_display.h> > +#endif > + > DECLARE_GLOBAL_DATA_PTR; > > /* add board specific code here */ > @@ -185,3 +189,13 @@ int misc_init_r(void) > return 0; > } > #endif > + > +#ifdef CONFIG_OF_BOARD_SETUP > +void > +ft_board_setup(void *blob, bd_t *bd) > +{ > +#ifdef CONFIG_VIDEO_DT_SIMPLEFB > + sunxi_simplefb_setup(blob); > +#endif > +} > +#endif /* CONFIG_OF_BOARD_SETUP */ > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index 945f35d..9a25c84 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o > obj-$(CONFIG_VIDEO_SED13806) += sed13806.o > obj-$(CONFIG_VIDEO_SM501) += sm501.o > obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o > +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o > obj-$(CONFIG_VIDEO_TEGRA) += tegra.o > obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o > obj-$(CONFIG_FORMIKE) += formike.o > diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c > new file mode 100644 > index 0000000..251fb67 > --- /dev/null > +++ b/drivers/video/sunxi_display.c > @@ -0,0 +1,639 @@ > +/* > + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be> > + * > + * Display driver for Allwinner SoCs. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation's version 2 and any > + * later version the License. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +/* > + * This driver does nothing but HDMI at a fixed mode right now. At some > + * point in the near future, LCD and VGA will be added. > + * > + * The display driver infrastructure in uboot does not immediately allow for > + * modeline creation off of edid. The mode is therefor hardcoded to > + * 1024x768 at 60Hz 32bpp. This is acceptable for most HDMI monitors, but far > + * from ideal. If so desired, alter the modeline in video_hw_init() > + */ > + > +#include <common.h> > + > +#include <asm/io.h> > +#include <asm/global_data.h> > +#include <video_fb.h> > +#include <linux/fb.h> > +#include <asm/arch-sunxi/sunxi_display.h> > + > +/* for simplefb */ > +#ifdef CONFIG_OF_BOARD_SETUP > +#include <libfdt.h> > +#endif > + > +DECLARE_GLOBAL_DATA_PTR; > + > +struct sunxi_display { > + GraphicDevice graphic_device[1]; > + int enabled; > +} sunxi_display[1]; > + > +/* > + * Convenience functions to ease readability, and to provide an easy > + * comparison with the sunxi kms driver. > + */ > +static unsigned int > +sunxi_io_read(void *base, int offset) > +{ > + return readl(base + offset); > +} > + > +static void > +sunxi_io_write(void *base, int offset, unsigned int value) > +{ > + writel(value, base + offset); > +} > + > +static void > +sunxi_io_mask(void *base, int offset, unsigned int value, unsigned int mask) > +{ > + unsigned int tmp = readl(base + offset); > + > + tmp &= ~mask; > + tmp |= value & mask; > + > + writel(tmp, base + offset); > +} > + > +/* > + * CCMU regs: clocks. > + */ > +#define SUNXI_CCMU_PLL3_CFG 0x010 > +#define SUNXI_CCMU_PLL5_CFG 0x020 > +#define SUNXI_CCMU_PLL7_CFG 0x030 > +#define SUNXI_CCMU_AHB_GATING1 0x064 > +#define SUNXI_CCMU_DRAM_CLK_GATING 0x100 > +#define SUNXI_DE_BE0_CLK 0x104 > +#define SUNXI_LCDC0_CH0_CLK 0x118 > +#define SUNXI_LCDC0_CH1_CLK 0x12C > +#define SUNXI_CCMU_HDMI_CLK 0x150 > + > +/* > + * DEBE regs. > + * > + * This is the entity that mixes and matches the different layers and inputs. > + * Allwinner calls it the back-end, but i like composer better. > + */ > +#define SUNXI_COMP_MODE 0x800 > +#define SUNXI_COMP_DISP_SIZE 0x808 > +#define SUNXI_COMP_LAYER0_SIZE 0x810 > +#define SUNXI_COMP_LAYER0_POS 0x820 > +#define SUNXI_COMP_LAYER0_STRIDE 0x840 > +#define SUNXI_COMP_LAYER0_ADDR_LOW 0X850 > +#define SUNXI_COMP_LAYER_ADDR_HIGH 0X860 > +#define SUNXI_COMP_REG_CTL 0X870 > +#define SUNXI_COMP_LAYER0_ATTR0 0x890 > +#define SUNXI_COMP_LAYER0_ATTR1 0x8a0 > + > +/* > + * LCDC, what allwinner calls a CRTC, so timing controller and serializer. > + */ > +#define SUNXI_LCDC_ENABLE 0x000 > +#define SUNXI_LCDC_INT0 0x004 > +#define SUNXI_LCDC_INT1 0x008 > +#define SUNXI_LCDC_TCON0_DOTCLOCK 0x044 > +#define SUNXI_LCDC_TCON0_IO_TRI 0x08c > +#define SUNXI_LCDC_TCON1_ENABLE 0x090 > +#define SUNXI_LCDC_TCON1_TIMING_SRC 0x094 > +#define SUNXI_LCDC_TCON1_TIMING_SCALE 0x098 > +#define SUNXI_LCDC_TCON1_TIMING_OUT 0x09c > +#define SUNXI_LCDC_TCON1_TIMING_H 0x0a0 > +#define SUNXI_LCDC_TCON1_TIMING_V 0x0a4 > +#define SUNXI_LCDC_TCON1_TIMING_SYNC 0x0a8 > +#define SUNXI_LCDC_TCON1_IO_TRI 0x0f4 > + > +/* > + * HDMI regs. > + */ > +#define SUNXI_HDMI_CTRL 0x004 > +#define SUNXI_HDMI_INT_CTRL 0x008 > +#define SUNXI_HDMI_HPD 0x00c > +#define SUNXI_HDMI_VIDEO_CTRL 0x010 > +#define SUNXI_HDMI_VIDEO_SIZE 0x014 > +#define SUNXI_HDMI_VIDEO_BP 0x018 > +#define SUNXI_HDMI_VIDEO_FP 0x01c > +#define SUNXI_HDMI_VIDEO_SPW 0x020 > +#define SUNXI_HDMI_VIDEO_POLARITY 0x024 > +#define SUNXI_HDMI_TX_DRIVER0 0x200 > +#define SUNXI_HDMI_TX_DRIVER1 0x204 > +#define SUNXI_HDMI_TX_DRIVER2 0x208 > +#define SUNXI_HDMI_TX_DRIVER3 0x20C > + > +static int > +sunxi_hdmi_hpd_detect(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *hdmi = (void *) SUNXI_HDMI_BASE; > + > + /* set video pll1 to 300MHz */ > + sunxi_io_write(ccmu, SUNXI_CCMU_PLL7_CFG, 0x8010D064); > + > + /* Set hdmi parent to video pll1 */ > + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x01000000, 0x03000000); > + > + /* set ahb gating to pass */ > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x800, 0x800); > + > + /* clk on */ > + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0x80000000, 0x80000000); > + > + sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0x80000000); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xA0800000); > + > + udelay(100); > + > + if (sunxi_io_read(hdmi, SUNXI_HDMI_HPD) & 0x01) > + return 1; > + > + /* no need to keep these running. */ > + sunxi_io_write(hdmi, SUNXI_HDMI_CTRL, 0); > + sunxi_io_mask(ccmu, SUNXI_CCMU_HDMI_CLK, 0, 0x80000000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0, 0x800); > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL7_CFG, 0, 0x80000000); > + > + return 0; > +} > + > +static int > +sunxi_pll5_frequency(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + unsigned int pll5 = sunxi_io_read(ccmu, SUNXI_CCMU_PLL5_CFG); > + int n, k, p; > + > + n = (pll5 >> 8) & 0x1F; > + k = ((pll5 >> 4) & 0x03) + 1; > + p = (pll5 >> 16) & 0x03; > + > + return (24000 * n * k) >> p; > +} > + > +static void > +sunxi_composer_init(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *composer = (void *) SUNXI_DE_BE0_BASE; > + int pll5 = sunxi_pll5_frequency(); > + int halve; > + > + if (pll5 < 300000) > + halve = 0; > + else > + halve = 1; > + > + /* reset off */ > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x40000000, 0x40000000); > + > + /* set to pll5 */ > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x02000000, 0x03000000); > + > + if (halve) > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x01, 0x03); > + else > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0, 0x03); > + > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x1000, 0x1000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_DRAM_CLK_GATING, > + 0x04000000, 0x04000000); > + > + /* enable */ > + sunxi_io_mask(ccmu, SUNXI_DE_BE0_CLK, 0x80000000, 0x80000000); > + > + /* engine bug, clear registers after reset. */ > + { > + /* > + * Since uboot prototypes but never declares memset_io, we > + * have to do this by hand. > + */ > + int i; > + > + for (i = 0x0800; i < 0x1000; i += 4) > + sunxi_io_write(composer, i, 0); > + } > + > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x01, 0x01); > +} > + > +static void > +sunxi_composer_mode_set(struct fb_videomode *mode, unsigned int address) > +{ > + void *composer = (void *) SUNXI_DE_BE0_BASE; > +#define SUNXI_FORMAT_XRGB8888 0x09 > + unsigned int format = SUNXI_FORMAT_XRGB8888; > + > + /* enable */ > + sunxi_io_write(composer, SUNXI_COMP_DISP_SIZE, > + ((mode->yres - 1) << 16) | (mode->xres - 1)); > + > + sunxi_io_write(composer, SUNXI_COMP_LAYER0_SIZE, > + ((mode->yres - 1) << 16) | (mode->xres - 1)); > + sunxi_io_write(composer, SUNXI_COMP_LAYER0_STRIDE, mode->xres << 5); > + sunxi_io_write(composer, SUNXI_COMP_LAYER0_ADDR_LOW, address << 3); > + sunxi_io_mask(composer, SUNXI_COMP_LAYER_ADDR_HIGH, > + address >> 29, 0xFF); > + > + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, format << 8, 0x0F00); > + > + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x04); > + sunxi_io_mask(composer, SUNXI_COMP_LAYER0_ATTR1, 0, 0x03); > + > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x100, 0x100); > +} > + > +static void > +sunxi_lcdc_pll_set(int dotclock) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + int value, n, m, diff; > + int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF; > + int best_double = 0; > + > + if ((dotclock < 20000) || (dotclock > 400000)) { > + printf("%s: Error: dotclock %d is out of range.\n", > + __func__, dotclock); > + return; > + } > + > + for (m = 16; m > 0; m--) { > + n = (m * dotclock) / 3000; > + > + if ((n > 9) && (n < 128)) { > + value = (3000 * n) / m; > + diff = value - dotclock; > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 0; > + } > + } > + > + n++; > + if ((n > 9) && (n < 128)) { > + value = (3000 * n) / m; > + diff = abs(value - dotclock); > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 0; > + } > + } > + > + /* these are just duplicates. */ > + if (!(m & 1)) > + continue; > + > + n = (m * dotclock) / 6000; > + if ((n > 63) && (n < 128)) { > + value = (6000 * n) / m; > + diff = abs(value - dotclock); > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 1; > + } > + } > + > + n++; > + if ((n > 63) && (n < 128)) { > + value = (6000 * n) / m; > + diff = abs(value - dotclock); > + if (diff < 0) > + diff = -diff; > + > + if (diff < best_diff) { > + best_diff = diff; > + best_m = m; > + best_n = n; > + best_double = 1; > + } > + } > + } > + > +#if 0 > + if (best_double) > + printf("dotclock: %06dkHz = %06dkHz: (2 * 3MHz * %d) / %d\n", > + dotclock, (6000 * best_n) / best_m, best_n, best_m); > + else > + printf("dotclock: %06dkHz = %06dkHz: (3MHz * %d) / %d\n", > + dotclock, (3000 * best_n) / best_m, best_n, best_m); > +#endif > + > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x80000000, 0x80000000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, 0x8000, 0x8000); > + sunxi_io_mask(ccmu, SUNXI_CCMU_PLL3_CFG, best_n, 0x7F); > + > + if (best_double) > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, > + 0x02000000, 0x03000000); > + else > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, > + 0, 0x03000000); > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, best_m - 1, 0x0F); > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800); > + > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000); > +} > + > +static void > +sunxi_lcdc_init(void) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *lcdc = (void *) SUNXI_LCD0_BASE; > + > + /* Pll1 was already enabled in hpd detect. */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x01000000, 0x03000000); > + > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x01000000, 0x03000000); > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x0800); > + > + /* just randomly set it at 30MHz */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x09, 0x0F); > + > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x40000000, 0x40000000); > + > + sunxi_io_mask(ccmu, SUNXI_CCMU_AHB_GATING1, 0x10, 0x10); > + > + /* toggle ch0 clock */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0x80000000, 0x80000000); > + while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH0_CLK) & 0x80000000) > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH0_CLK, 0, 0x80000000); > + > + /* toggle ch1 s1 & s2 clocks */ > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0x80008000, 0x80008000); > + while (sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK) & 0x80008000) > + sunxi_io_mask(ccmu, SUNXI_LCDC0_CH1_CLK, 0, 0x80008000); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_ENABLE, 0); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_INT0, 0); > + sunxi_io_write(lcdc, SUNXI_LCDC_INT1, 0x20); > + > + /* > + * disable tcon0 dot clock: > + * This doesn't disable the dotclock, it just nulls the divider. > + */ > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_DOTCLOCK, 0xF0000000); > + > + /* all io lines disabled. */ > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON0_IO_TRI, 0x0FFFFFFF); > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x0FFFFFFF); > +} > + > +static void > +sunxi_lcdc_mode_set(struct fb_videomode *mode) > +{ > + void *lcdc = (void *) SUNXI_LCD0_BASE; > + int total; > + > + /* use tcon1 */ > + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x01, 0x01); > + > + /* enabled, 0x1E start delay */ > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_ENABLE, 0x800001E0); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SRC, > + ((mode->xres - 1) << 16) | (mode->yres - 1)); > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SCALE, > + ((mode->xres - 1) << 16) | (mode->yres - 1)); > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_OUT, > + ((mode->xres - 1) << 16) | (mode->yres - 1)); > + > + total = mode->left_margin + mode->xres + mode->right_margin + > + mode->hsync_len; > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_H, > + ((total - 1) << 16) | > + (mode->hsync_len + mode->left_margin - 1)); > + > + total = mode->upper_margin + mode->yres + mode->lower_margin + > + mode->vsync_len; > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_V, > + ((total * 2) << 16) | > + (mode->vsync_len + mode->upper_margin - 1)); > + > + sunxi_io_write(lcdc, SUNXI_LCDC_TCON1_TIMING_SYNC, > + ((mode->hsync_len - 1) << 16) | (mode->vsync_len - 1)); > + > + sunxi_lcdc_pll_set(mode->pixclock); > +} > + > +static void > +sunxi_hdmi_mode_set(struct fb_videomode *mode) > +{ > + void *ccmu = (void *) SUNXI_CCM_BASE; > + void *hdmi = (void *) SUNXI_HDMI_BASE; > + int h, v, tmp; > + > + sunxi_io_write(hdmi, SUNXI_HDMI_INT_CTRL, 0xFFFFFFFF); > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x03FE0000); > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER0, 0xDE000000, 0xDE000000); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x00D8C820); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER2, 0xD2000008); > + sunxi_io_write(hdmi, SUNXI_HDMI_TX_DRIVER3, 0); > + > + /* use video0 */ > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER3, 0, 0x00200000); > + > + tmp = sunxi_io_read(ccmu, SUNXI_LCDC0_CH1_CLK); > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER2, > + ((tmp & 0x0F) + 1) << 4, 0xF0); > + > + if (tmp & 0x02000000) > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0, 0x40); > + else > + sunxi_io_mask(hdmi, SUNXI_HDMI_TX_DRIVER1, 0x40, 0x40); > + > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SIZE, > + ((mode->yres - 1) << 16) | (mode->xres - 1)); > + > + h = mode->hsync_len + mode->left_margin; > + v = mode->vsync_len + mode->upper_margin; > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_BP, ((v - 1) << 16) | (h - 1)); > + > + h = mode->right_margin; > + v = mode->lower_margin; > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_FP, ((v - 1) << 16) | (h - 1)); > + > + h = mode->hsync_len; > + v = mode->vsync_len; > + sunxi_io_write(hdmi, SUNXI_HDMI_VIDEO_SPW, ((v - 1) << 16) | (h - 1)); > + > + if (mode->sync & FB_SYNC_HOR_HIGH_ACT) > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x01, 0x01); > + else > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x01); > + > + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0x02, 0x02); > + else > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_POLARITY, 0, 0x02); > +} > + > +static void > +sunxi_engines_init(void) > +{ > + sunxi_composer_init(); > + sunxi_lcdc_init(); > +} > + > +static void > +sunxi_mode_set(struct fb_videomode *mode, unsigned int address) > +{ > + void *composer = (void *) SUNXI_DE_BE0_BASE; > + void *lcdc = (void *) SUNXI_LCD0_BASE; > + void *hdmi = (void *) SUNXI_HDMI_BASE; > + > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0, 0x80000000); > + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0, 0x80000000); > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0, 0x02); > + > + sunxi_composer_mode_set(mode, address); > + sunxi_lcdc_mode_set(mode); > + sunxi_hdmi_mode_set(mode); > + > + sunxi_io_mask(composer, SUNXI_COMP_REG_CTL, 0x01, 0x01); > + sunxi_io_mask(composer, SUNXI_COMP_MODE, 0x02, 0x02); > + > + sunxi_io_mask(lcdc, SUNXI_LCDC_ENABLE, 0x80000000, 0x80000000); > + sunxi_io_mask(lcdc, SUNXI_LCDC_TCON1_IO_TRI, 0x00000000, 0x03000000); > + > + udelay(100); > + > + sunxi_io_mask(hdmi, SUNXI_HDMI_VIDEO_CTRL, 0x80000000, 0x80000000); > +} > + > +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB) > +void > +sunxi_simplefb_setup(void *blob) > +{ > + static GraphicDevice *graphic_device = sunxi_display->graphic_device; > + const char *name = "simple-framebuffer"; > + const char *format = "x8r8g8b8"; > + fdt32_t cells[2]; > + int offset, stride, ret; > + > + if (!sunxi_display->enabled) > + return; > + > + offset = fdt_add_subnode(blob, 0, "framebuffer"); > + if (offset < 0) { > + printf("%s: add subnode failed", __func__); > + return; > + } > + > + ret = fdt_setprop(blob, offset, "compatible", name, strlen(name) + 1); > + if (ret < 0) > + return; > + > + stride = graphic_device->winSizeX * graphic_device->gdfBytesPP; > + > + cells[0] = cpu_to_fdt32(gd->fb_base); > + cells[1] = cpu_to_fdt32(CONFIG_SUNXI_FB_SIZE); > + ret = fdt_setprop(blob, offset, "reg", cells, sizeof(cells[0]) * 2); > + if (ret < 0) > + return; > + > + cells[0] = cpu_to_fdt32(graphic_device->winSizeX); > + ret = fdt_setprop(blob, offset, "width", cells, sizeof(cells[0])); > + if (ret < 0) > + return; > + > + cells[0] = cpu_to_fdt32(graphic_device->winSizeY); > + ret = fdt_setprop(blob, offset, "height", cells, sizeof(cells[0])); > + if (ret < 0) > + return; > + > + cells[0] = cpu_to_fdt32(stride); > + ret = fdt_setprop(blob, offset, "stride", cells, sizeof(cells[0])); > + if (ret < 0) > + return; > + > + ret = fdt_setprop(blob, offset, "format", format, strlen(format) + 1); > + if (ret < 0) > + return; > +} > +#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */ > + > +void * > +video_hw_init(void) > +{ > + static GraphicDevice *graphic_device = sunxi_display->graphic_device; > + /* > + * Vesa standard 1024x768 at 60 > + * 65.0 1024 1032 1176 1344 768 771 777 806 -hsync -vsync > + */ > + struct fb_videomode mode = { > + .name = "1024x768", > + .refresh = 60, > + .xres = 1024, > + .yres = 768, > + .pixclock = 65000, > + .left_margin = 160, > + .right_margin = 24, > + .upper_margin = 29, > + .lower_margin = 3, > + .hsync_len = 136, > + .vsync_len = 6, > + .sync = 0, > + .vmode = 0, > + .flag = 0, > + }; > + int ret; > + > + memset(sunxi_display, 0, sizeof(struct sunxi_display)); > + > + printf("Reserved %dkB of RAM for Framebuffer.\n", > + CONFIG_SUNXI_FB_SIZE >> 10); > + gd->fb_base = gd->ram_top; > + > + ret = sunxi_hdmi_hpd_detect(); > + if (!ret) > + return NULL; > + > + printf("HDMI connected.\n"); > + sunxi_display->enabled = 1; > + > + printf("Setting up a %s console.\n", mode.name); > + sunxi_engines_init(); > + sunxi_mode_set(&mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE); > + > + /* > + * These are the only members of this structure that are used. All the > + * others are driver specific. There is nothing to decribe pitch or > + * stride, but we are lucky with our hw. > + */ > + graphic_device->frameAdrs = gd->fb_base; > + graphic_device->gdfIndex = GDF_32BIT_X888RGB; > + graphic_device->gdfBytesPP = 4; > + graphic_device->winSizeX = mode.xres; > + graphic_device->winSizeY = mode.yres; > + > + return graphic_device; > +} > diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h > index 8ab6429..89582b8 100644 > --- a/include/configs/sunxi-common.h > +++ b/include/configs/sunxi-common.h > @@ -181,6 +181,40 @@ > #define CONFIG_SUNXI_GPIO > #define CONFIG_CMD_GPIO > > +/* Set this if you do not want a uboot fb console */ > +#ifndef CONFIG_NO_VIDEO > +#define CONFIG_VIDEO > +#endif > + > +#ifdef CONFIG_VIDEO > +/* > + * The amount of RAM that is reserved for the FB. This will not show up as > + * RAM to the kernel, but will be reclaimed by a KMS driver in future. > + */ > +#define CONFIG_SUNXI_FB_SIZE (8 << 20) > + > +/* Do we want to initialize a simple FB? */ > +#define CONFIG_VIDEO_DT_SIMPLEFB > + > +#define CONFIG_VIDEO_SUNXI > + > +#define CONFIG_CFB_CONSOLE > +/* allow both serial and cfb console. */ > +#define CONFIG_CONSOLE_MUX > +/* this is needed so the above will actually do something */ > +#define CONFIG_SYS_CONSOLE_IS_IN_ENV > +/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */ > +#define CONFIG_VGA_AS_SINGLE_DEVICE > + > +#define CONFIG_SYS_MEM_TOP_HIDE ((CONFIG_SUNXI_FB_SIZE + 0xFFF) & ~0xFFF) > + > +/* To be able to hook simplefb into dt */ > +#ifdef CONFIG_VIDEO_DT_SIMPLEFB > +#define CONFIG_OF_BOARD_SETUP > +#endif > + > +#endif /* CONFIG_VIDEO */ > + > /* Ethernet support */ > #ifdef CONFIG_SUNXI_EMAC > #define CONFIG_MII /* MII PHY management */ > ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [linux-sunxi] Re: [PATCH] video: add cfb console driver for sunxi 2014-08-05 11:56 ` [U-Boot] " Hans de Goede @ 2014-08-05 20:47 ` Maxime Ripard 2014-08-06 11:40 ` [U-Boot] " Luc Verhaegen 1 sibling, 0 replies; 18+ messages in thread From: Maxime Ripard @ 2014-08-05 20:47 UTC (permalink / raw) To: u-boot On Tue, Aug 05, 2014 at 01:56:36PM +0200, Hans de Goede wrote: > Hi, > > On 08/02/2014 06:14 PM, Luc Verhaegen wrote: > > This adds a fixed mode hdmi driver (lcd to be added in future) for the > > sunxi platform. Current config is such that 8MB is shaved off at the top > > of the RAM. Simplefb support is available for kernels that know how to > > use it. > > I've been trying to follow all the discussion in this thread, and here > is what I think we should do: > > 1) There has been some discussion about using this console-driver > in u-boot without generating the simplefb dt node. This means yet another > variation in how all the bits fit together, so I don't think we should do > this. Note I realize that the original patch did not have a specific > config option for this, but it was mentioned later in the thread. > TL;DR: Enabling the console driver will always generate the simplefb dt > node. Until we have a KMS driver, I agree. The DT generation part should probably be a separate patch though. It's probably going to generate enough discussion by itself to not slow done the driver itself. > 2) I think we can worry about what to do with the reserved memory\when not using simplefb > (or when switching from simplefb to kms) later. For now lets focus on the > issue with the clocks. > > 3) To me the issue with clocks seems simple, we should modify the > devicetree binding for simplefb to support a clocks property, and modify > the simplefb kernel code to get + prep_and_enable any clocks specified > in the dt node. > > This means parsing enough of the dt to find the clocks to be able to > specify phandles to them in the added node. I don't know how hard it will > be to do this in u-boot, but IMHO it is simply the right thing to do, so > this is how it should be done. > > If others agree that specifying the clocks in the simplefb dt node is > the right way to ensure that the clocks don't get enabled I'm willing > at taking a shot on coding this. Agreed. -- Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140805/db816222/attachment.pgp> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [PATCH] video: add cfb console driver for sunxi 2014-08-05 11:56 ` [U-Boot] " Hans de Goede 2014-08-05 20:47 ` [U-Boot] [linux-sunxi] " Maxime Ripard @ 2014-08-06 11:40 ` Luc Verhaegen 2014-08-07 9:28 ` Hans de Goede 1 sibling, 1 reply; 18+ messages in thread From: Luc Verhaegen @ 2014-08-06 11:40 UTC (permalink / raw) To: u-boot On Tue, Aug 05, 2014 at 01:56:36PM +0200, Hans de Goede wrote: > Hi, > > On 08/02/2014 06:14 PM, Luc Verhaegen wrote: > > This adds a fixed mode hdmi driver (lcd to be added in future) for the > > sunxi platform. Current config is such that 8MB is shaved off at the top > > of the RAM. Simplefb support is available for kernels that know how to > > use it. > > I've been trying to follow all the discussion in this thread, and here > is what I think we should do: > > 1) There has been some discussion about using this console-driver > in u-boot without generating the simplefb dt node. This means yet another > variation in how all the bits fit together, so I don't think we should do > this. Note I realize that the original patch did not have a specific > config option for this, but it was mentioned later in the thread. > TL;DR: Enabling the console driver will always generate the simplefb dt > node. When we do not claim clocks, we luckily cleanly disable hw, in our case. > 2) I think we can worry about what to do with the reserved memory\when not using simplefb > (or when switching from simplefb to kms) later. For now lets focus on the > issue with the clocks. Yes, this was the plan all along. > 3) To me the issue with clocks seems simple, we should modify the > devicetree binding for simplefb to support a clocks property, and modify > the simplefb kernel code to get + prep_and_enable any clocks specified > in the dt node. For me, an important part of this discussion was seemingly flawed way in which clocks are defined. I was of course not going to completely overturn the thinking here, but i had expected that people would've at least agreed that something was obviously awry, as there are several obvious indicators there. > This means parsing enough of the dt to find the clocks to be able to > specify phandles to them in the added node. I don't know how hard it will > be to do this in u-boot, but IMHO it is simply the right thing to do, so > this is how it should be done. No, you do not need to add nodes. This was never the case. &ahb_gates is never used like that. It is either used as <&ahb_gates bit> from the dt, or "ahb_bitname" from kernel code which directly references clocks, with the ahb_bitnames listed as part of ahb_gates in the "clock-output-names" property. This lack of symmetry is one very clear sign. The fact that only the kernel knows how to map the "clock-output-names" list, which is only defined in the dts, to bits only defined in the clk driver code in the kernel, that's another very clear sign. > If others agree that specifying the clocks in the simplefb dt node is > the right way to ensure that the clocks don't get enabled I'm willing > at taking a shot on coding this. I have been on it since last friday, when i started seeing the issues here, but haven't done much code til now, and am only uncovering many more inconsistencies. For instance, in the linux kernel, Documentation/devicetree/bindings/clock/clock-bindings.txt only adds to the confusion. Now trying to find a working solution from the kernel side, as i already manually inserted 6 u32s: {phandle, bit, phandle, bit, phandle, bit}. Wait and see how that pans out, but i know that this will not provide a proper or lasting solution, as the pairs of cells needed now will at one point need to be mixed with directly referenced clocks (pll3/pll7, which are currently not defined in dts yet). Luc Verhaegen. ^ permalink raw reply [flat|nested] 18+ messages in thread
* [U-Boot] [PATCH] video: add cfb console driver for sunxi 2014-08-06 11:40 ` [U-Boot] " Luc Verhaegen @ 2014-08-07 9:28 ` Hans de Goede 0 siblings, 0 replies; 18+ messages in thread From: Hans de Goede @ 2014-08-07 9:28 UTC (permalink / raw) To: u-boot Hi, On 08/06/2014 01:40 PM, Luc Verhaegen wrote: > On Tue, Aug 05, 2014 at 01:56:36PM +0200, Hans de Goede wrote: >> Hi, >> >> On 08/02/2014 06:14 PM, Luc Verhaegen wrote: >>> This adds a fixed mode hdmi driver (lcd to be added in future) for the >>> sunxi platform. Current config is such that 8MB is shaved off at the top >>> of the RAM. Simplefb support is available for kernels that know how to >>> use it. >> >> I've been trying to follow all the discussion in this thread, and here >> is what I think we should do: >> >> 1) There has been some discussion about using this console-driver >> in u-boot without generating the simplefb dt node. This means yet another >> variation in how all the bits fit together, so I don't think we should do >> this. Note I realize that the original patch did not have a specific >> config option for this, but it was mentioned later in the thread. >> TL;DR: Enabling the console driver will always generate the simplefb dt >> node. > > When we do not claim clocks, we luckily cleanly disable hw, in our case. > >> 2) I think we can worry about what to do with the reserved memory\when not using simplefb >> (or when switching from simplefb to kms) later. For now lets focus on the >> issue with the clocks. > > Yes, this was the plan all along. > >> 3) To me the issue with clocks seems simple, we should modify the >> devicetree binding for simplefb to support a clocks property, and modify >> the simplefb kernel code to get + prep_and_enable any clocks specified >> in the dt node. > > For me, an important part of this discussion was seemingly flawed way in > which clocks are defined. I was of course not going to completely > overturn the thinking here, but i had expected that people would've at > least agreed that something was obviously awry, as there are several > obvious indicators there. I think the way clocks are defined is fine, it works fine for all the other parts of the SoC we've added support for so far. I guess it may take some getting used too. Anyways I don't think having an extended discussion about how clocks are defined is useful, this is simply something which we are not going to change, so better get used to it. > >> This means parsing enough of the dt to find the clocks to be able to >> specify phandles to them in the added node. I don't know how hard it will >> be to do this in u-boot, but IMHO it is simply the right thing to do, so >> this is how it should be done. > > No, you do not need to add nodes. This was never the case. &ahb_gates > is never used like that. > > It is either used as <&ahb_gates bit> from the dt, or "ahb_bitname" > from kernel code which directly references clocks, with the > ahb_bitnames listed as part of ahb_gates in the "clock-output-names" > property. This lack of symmetry is one very clear sign. That is how the gates are modeled yes, but we don't want to insert direct refences to the gates into the generated simple-framebuffer devicetree node. Instead what should be done is add module clock nodes to the devicetree (in the dts file, not on the fly in u-boot), and then the uboot code should search for those (this is what I meant with parse the dtb) and then insert phandles to these into the generated simpe-framebuffer node. Note we will need multiple module-clocks node, one for lcd0 ch0 one for lcd0 ch1, etc. See for example the mmc0_clk node, and the usage of it in the mmc0 node. I think we don't need a module clock node for the hdmi encoder, as it seems the module clock register for it at address 1c20150 does not do anything, instead it seems the hdmi encoder is hooked up directly to pll 3 / 7 and has its own clock selection mechanism through one of the hdmi encoder registers. At least this is the conclusion I came to when working on dvi support, etc. in the sunxi-3.4 kernels. Regards, Hans ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2014-08-07 9:28 UTC | newest] Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-08-02 16:14 [U-Boot] [PATCH] video: add cfb console driver for sunxi Luc Verhaegen 2014-08-04 8:39 ` Hans de Goede 2014-08-04 15:05 ` Luc Verhaegen 2014-08-04 15:31 ` [U-Boot] [linux-sunxi] " Henrik Nordström 2014-08-04 16:53 ` Michal Suchanek 2014-08-04 21:26 ` Henrik Nordström 2014-08-04 17:28 ` Luc Verhaegen 2014-08-04 22:10 ` Henrik Nordström 2014-08-05 20:55 ` Maxime Ripard 2014-08-05 21:03 ` Maxime Ripard 2014-08-05 21:37 ` Michal Suchanek 2014-08-06 7:24 ` [U-Boot] [linux-sunxi] " Koen Kooi 2014-08-06 11:10 ` Hans de Goede 2014-08-06 12:21 ` [U-Boot] [linux-sunxi] " Maxime Ripard 2014-08-05 11:56 ` [U-Boot] " Hans de Goede 2014-08-05 20:47 ` [U-Boot] [linux-sunxi] " Maxime Ripard 2014-08-06 11:40 ` [U-Boot] " Luc Verhaegen 2014-08-07 9:28 ` Hans de Goede
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.