[U-Boot] [PATCH 0/3] sunxi: video: Add support for TV (composite) output on H3/H5

This series implements support for composite output. Driver is implemented using DM video framework and heavily reuse code written for older SoCs. Additionally, driver also implements plug detection.
Patch 1 splits out code used for composite output from video driver for older SoCs.
Patch 2 adds needed changes in clock driver.
Patch 3 adds new driver for composite output.
Everything was tested on H3 (OrangePi 2) and H5 (OrangePi PC2) board. Since this series changes video driver for old SoCs, I would kindly ask that someone tests if everything still works as expected.
Last but not least - driver should work as-is, but to work reliably, following patch must also be applied: https://patchwork.ozlabs.org/patch/756736/
Best regards, Jernej
Jernej Skrabec (3): sunxi: video: Split out TVE code sunxi: Add clock support for TV encoder sunxi: video: Add H3/H5 TV out driver
arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 8 +- arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display.h | 107 ------------------ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 144 ++++++++++++++++++++++++ drivers/video/sunxi/Makefile | 4 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++-- drivers/video/sunxi/sunxi_display.c | 73 ++---------- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 88 +++++++++++++++ 10 files changed, 484 insertions(+), 183 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/tve.h create mode 100644 drivers/video/sunxi/sunxi_tve.c create mode 100644 drivers/video/sunxi/tve.c

Newer SoCs use same TV encoder unit. Split it out so it can be reused with new DM video driver.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net ---
arch/arm/include/asm/arch-sunxi/display.h | 107 ------------------------ arch/arm/include/asm/arch-sunxi/tve.h | 131 ++++++++++++++++++++++++++++++ drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_display.c | 73 +++-------------- drivers/video/sunxi/tve.c | 86 ++++++++++++++++++++ 5 files changed, 230 insertions(+), 169 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/tve.h create mode 100644 drivers/video/sunxi/tve.c
diff --git a/arch/arm/include/asm/arch-sunxi/display.h b/arch/arm/include/asm/arch-sunxi/display.h index 93803addfb..e10197784e 100644 --- a/arch/arm/include/asm/arch-sunxi/display.h +++ b/arch/arm/include/asm/arch-sunxi/display.h @@ -225,52 +225,6 @@ struct sunxi_hdmi_reg { };
/* - * This is based on the A10s User Manual, and the A10s only supports - * composite video and not vga like the A10 / A20 does, still other - * than the removed vga out capability the tvencoder seems to be the same. - * "unknown#" registers are registers which are used in the A10 kernel code, - * but not documented in the A10s User Manual. - */ -struct sunxi_tve_reg { - u32 gctrl; /* 0x000 */ - u32 cfg0; /* 0x004 */ - u32 dac_cfg0; /* 0x008 */ - u32 filter; /* 0x00c */ - u32 chroma_freq; /* 0x010 */ - u32 porch_num; /* 0x014 */ - u32 unknown0; /* 0x018 */ - u32 line_num; /* 0x01c */ - u32 blank_black_level; /* 0x020 */ - u32 unknown1; /* 0x024, seems to be 1 byte per dac */ - u8 res0[0x08]; /* 0x028 */ - u32 auto_detect_en; /* 0x030 */ - u32 auto_detect_int_status; /* 0x034 */ - u32 auto_detect_status; /* 0x038 */ - u32 auto_detect_debounce; /* 0x03c */ - u32 csc_reg0; /* 0x040 */ - u32 csc_reg1; /* 0x044 */ - u32 csc_reg2; /* 0x048 */ - u32 csc_reg3; /* 0x04c */ - u8 res1[0xb0]; /* 0x050 */ - u32 color_burst; /* 0x100 */ - u32 vsync_num; /* 0x104 */ - u32 notch_freq; /* 0x108 */ - u32 cbr_level; /* 0x10c */ - u32 burst_phase; /* 0x110 */ - u32 burst_width; /* 0x114 */ - u32 unknown2; /* 0x118 */ - u32 sync_vbi_level; /* 0x11c */ - u32 white_level; /* 0x120 */ - u32 active_num; /* 0x124 */ - u32 chroma_bw_gain; /* 0x128 */ - u32 notch_width; /* 0x12c */ - u32 resync_num; /* 0x130 */ - u32 slave_para; /* 0x134 */ - u32 cfg1; /* 0x138 */ - u32 cfg2; /* 0x13c */ -}; - -/* * DE-FE register constants. */ #define SUNXI_DE_FE_WIDTH(x) (((x) - 1) << 0) @@ -394,67 +348,6 @@ struct sunxi_tve_reg { #define SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE (1 << 8) #define SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE (1 << 9)
-/* - * TVE register constants. - */ -#define SUNXI_TVE_GCTRL_ENABLE (1 << 0) -/* - * Select input 0 to disable dac, 1 - 4 to feed dac from tve0, 5 - 8 to feed - * dac from tve1. When using tve1 the mux value must be written to both tve0's - * and tve1's gctrl reg. - */ -#define SUNXI_TVE_GCTRL_DAC_INPUT_MASK(dac) (0xf << (((dac) + 1) * 4)) -#define SUNXI_TVE_GCTRL_DAC_INPUT(dac, sel) ((sel) << (((dac) + 1) * 4)) -#define SUNXI_TVE_CFG0_VGA 0x20000000 -#define SUNXI_TVE_CFG0_PAL 0x07030001 -#define SUNXI_TVE_CFG0_NTSC 0x07030000 -#define SUNXI_TVE_DAC_CFG0_VGA 0x403e1ac7 -#ifdef CONFIG_MACH_SUN5I -#define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x433f0009 -#else -#define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x403f0008 -#endif -#define SUNXI_TVE_FILTER_COMPOSITE 0x00000120 -#define SUNXI_TVE_CHROMA_FREQ_PAL_M 0x21e6efe3 -#define SUNXI_TVE_CHROMA_FREQ_PAL_NC 0x21f69446 -#define SUNXI_TVE_PORCH_NUM_PAL 0x008a0018 -#define SUNXI_TVE_PORCH_NUM_NTSC 0x00760020 -#define SUNXI_TVE_LINE_NUM_PAL 0x00160271 -#define SUNXI_TVE_LINE_NUM_NTSC 0x0016020d -#define SUNXI_TVE_BLANK_BLACK_LEVEL_PAL 0x00fc00fc -#define SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC 0x00f0011a -#define SUNXI_TVE_UNKNOWN1_VGA 0x00000000 -#define SUNXI_TVE_UNKNOWN1_COMPOSITE 0x18181818 -#define SUNXI_TVE_AUTO_DETECT_EN_DET_EN(dac) (1 << ((dac) + 0)) -#define SUNXI_TVE_AUTO_DETECT_EN_INT_EN(dac) (1 << ((dac) + 16)) -#define SUNXI_TVE_AUTO_DETECT_INT_STATUS(dac) (1 << ((dac) + 0)) -#define SUNXI_TVE_AUTO_DETECT_STATUS_SHIFT(dac) ((dac) * 8) -#define SUNXI_TVE_AUTO_DETECT_STATUS_MASK(dac) (3 << ((dac) * 8)) -#define SUNXI_TVE_AUTO_DETECT_STATUS_NONE 0 -#define SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED 1 -#define SUNXI_TVE_AUTO_DETECT_STATUS_SHORT_GND 3 -#define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(d) ((d) * 8) -#define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_MASK(d) (0xf << ((d) * 8)) -#define SUNXI_TVE_CSC_REG0_ENABLE (1 << 31) -#define SUNXI_TVE_CSC_REG0 0x08440832 -#define SUNXI_TVE_CSC_REG1 0x3b6dace1 -#define SUNXI_TVE_CSC_REG2 0x0e1d13dc -#define SUNXI_TVE_CSC_REG3 0x00108080 -#define SUNXI_TVE_COLOR_BURST_PAL_M 0x00000000 -#define SUNXI_TVE_CBR_LEVEL_PAL 0x00002828 -#define SUNXI_TVE_CBR_LEVEL_NTSC 0x0000004f -#define SUNXI_TVE_BURST_PHASE_NTSC 0x00000000 -#define SUNXI_TVE_BURST_WIDTH_COMPOSITE 0x0016447e -#define SUNXI_TVE_UNKNOWN2_PAL 0x0000e0e0 -#define SUNXI_TVE_UNKNOWN2_NTSC 0x0000a0a0 -#define SUNXI_TVE_SYNC_VBI_LEVEL_NTSC 0x001000f0 -#define SUNXI_TVE_ACTIVE_NUM_COMPOSITE 0x000005a0 -#define SUNXI_TVE_CHROMA_BW_GAIN_COMP 0x00000002 -#define SUNXI_TVE_NOTCH_WIDTH_COMPOSITE 0x00000101 -#define SUNXI_TVE_RESYNC_NUM_PAL 0x800d000c -#define SUNXI_TVE_RESYNC_NUM_NTSC 0x000e000c -#define SUNXI_TVE_SLAVE_PARA_COMPOSITE 0x00000000 - int sunxi_simplefb_setup(void *blob);
#endif /* _SUNXI_DISPLAY_H */ diff --git a/arch/arm/include/asm/arch-sunxi/tve.h b/arch/arm/include/asm/arch-sunxi/tve.h new file mode 100644 index 0000000000..41a14a68e4 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/tve.h @@ -0,0 +1,131 @@ +/* + * Sunxi TV encoder register and constant defines + * + * (C) Copyright 2014 Hans de Goede hdegoede@redhat.com + * (C) Copyright 2017 Jernej Skrabec jernej.skrabec@siol.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _TVE_H +#define _TVE_H + +enum tve_mode { + tve_mode_vga, + tve_mode_composite_pal, + tve_mode_composite_ntsc, + tve_mode_composite_pal_m, + tve_mode_composite_pal_nc, +}; + +/* + * This is based on the A10s User Manual, and the A10s only supports + * composite video and not vga like the A10 / A20 does, still other + * than the removed vga out capability the tvencoder seems to be the same. + * "unknown#" registers are registers which are used in the A10 kernel code, + * but not documented in the A10s User Manual. + */ +struct sunxi_tve_reg { + u32 gctrl; /* 0x000 */ + u32 cfg0; /* 0x004 */ + u32 dac_cfg0; /* 0x008 */ + u32 filter; /* 0x00c */ + u32 chroma_freq; /* 0x010 */ + u32 porch_num; /* 0x014 */ + u32 unknown0; /* 0x018 */ + u32 line_num; /* 0x01c */ + u32 blank_black_level; /* 0x020 */ + u32 unknown1; /* 0x024, seems to be 1 byte per dac */ + u8 res0[0x08]; /* 0x028 */ + u32 auto_detect_en; /* 0x030 */ + u32 auto_detect_int_status; /* 0x034 */ + u32 auto_detect_status; /* 0x038 */ + u32 auto_detect_debounce; /* 0x03c */ + u32 csc_reg0; /* 0x040 */ + u32 csc_reg1; /* 0x044 */ + u32 csc_reg2; /* 0x048 */ + u32 csc_reg3; /* 0x04c */ + u8 res1[0xb0]; /* 0x050 */ + u32 color_burst; /* 0x100 */ + u32 vsync_num; /* 0x104 */ + u32 notch_freq; /* 0x108 */ + u32 cbr_level; /* 0x10c */ + u32 burst_phase; /* 0x110 */ + u32 burst_width; /* 0x114 */ + u32 unknown2; /* 0x118 */ + u32 sync_vbi_level; /* 0x11c */ + u32 white_level; /* 0x120 */ + u32 active_num; /* 0x124 */ + u32 chroma_bw_gain; /* 0x128 */ + u32 notch_width; /* 0x12c */ + u32 resync_num; /* 0x130 */ + u32 slave_para; /* 0x134 */ + u32 cfg1; /* 0x138 */ + u32 cfg2; /* 0x13c */ +}; + +/* + * TVE register constants. + */ +#define SUNXI_TVE_GCTRL_ENABLE (1 << 0) +/* + * Select input 0 to disable dac, 1 - 4 to feed dac from tve0, 5 - 8 to feed + * dac from tve1. When using tve1 the mux value must be written to both tve0's + * and tve1's gctrl reg. + */ +#define SUNXI_TVE_GCTRL_DAC_INPUT_MASK(dac) (0xf << (((dac) + 1) * 4)) +#define SUNXI_TVE_GCTRL_DAC_INPUT(dac, sel) ((sel) << (((dac) + 1) * 4)) +#define SUNXI_TVE_CFG0_VGA 0x20000000 +#define SUNXI_TVE_CFG0_PAL 0x07030001 +#define SUNXI_TVE_CFG0_NTSC 0x07030000 +#define SUNXI_TVE_DAC_CFG0_VGA 0x403e1ac7 +#ifdef CONFIG_MACH_SUN5I +#define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x433f0009 +#else +#define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x403f0008 +#endif +#define SUNXI_TVE_FILTER_COMPOSITE 0x00000120 +#define SUNXI_TVE_CHROMA_FREQ_PAL_M 0x21e6efe3 +#define SUNXI_TVE_CHROMA_FREQ_PAL_NC 0x21f69446 +#define SUNXI_TVE_PORCH_NUM_PAL 0x008a0018 +#define SUNXI_TVE_PORCH_NUM_NTSC 0x00760020 +#define SUNXI_TVE_LINE_NUM_PAL 0x00160271 +#define SUNXI_TVE_LINE_NUM_NTSC 0x0016020d +#define SUNXI_TVE_BLANK_BLACK_LEVEL_PAL 0x00fc00fc +#define SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC 0x00f0011a +#define SUNXI_TVE_UNKNOWN1_VGA 0x00000000 +#define SUNXI_TVE_UNKNOWN1_COMPOSITE 0x18181818 +#define SUNXI_TVE_AUTO_DETECT_EN_DET_EN(dac) (1 << ((dac) + 0)) +#define SUNXI_TVE_AUTO_DETECT_EN_INT_EN(dac) (1 << ((dac) + 16)) +#define SUNXI_TVE_AUTO_DETECT_INT_STATUS(dac) (1 << ((dac) + 0)) +#define SUNXI_TVE_AUTO_DETECT_STATUS_SHIFT(dac) ((dac) * 8) +#define SUNXI_TVE_AUTO_DETECT_STATUS_MASK(dac) (3 << ((dac) * 8)) +#define SUNXI_TVE_AUTO_DETECT_STATUS_NONE 0 +#define SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED 1 +#define SUNXI_TVE_AUTO_DETECT_STATUS_SHORT_GND 3 +#define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(d) ((d) * 8) +#define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_MASK(d) (0xf << ((d) * 8)) +#define SUNXI_TVE_CSC_REG0_ENABLE (1 << 31) +#define SUNXI_TVE_CSC_REG0 0x08440832 +#define SUNXI_TVE_CSC_REG1 0x3b6dace1 +#define SUNXI_TVE_CSC_REG2 0x0e1d13dc +#define SUNXI_TVE_CSC_REG3 0x00108080 +#define SUNXI_TVE_COLOR_BURST_PAL_M 0x00000000 +#define SUNXI_TVE_CBR_LEVEL_PAL 0x00002828 +#define SUNXI_TVE_CBR_LEVEL_NTSC 0x0000004f +#define SUNXI_TVE_BURST_PHASE_NTSC 0x00000000 +#define SUNXI_TVE_BURST_WIDTH_COMPOSITE 0x0016447e +#define SUNXI_TVE_UNKNOWN2_PAL 0x0000e0e0 +#define SUNXI_TVE_UNKNOWN2_NTSC 0x0000a0a0 +#define SUNXI_TVE_SYNC_VBI_LEVEL_NTSC 0x001000f0 +#define SUNXI_TVE_ACTIVE_NUM_COMPOSITE 0x000005a0 +#define SUNXI_TVE_CHROMA_BW_GAIN_COMP 0x00000002 +#define SUNXI_TVE_NOTCH_WIDTH_COMPOSITE 0x00000101 +#define SUNXI_TVE_RESYNC_NUM_PAL 0x800d000c +#define SUNXI_TVE_RESYNC_NUM_NTSC 0x000e000c +#define SUNXI_TVE_SLAVE_PARA_COMPOSITE 0x00000000 + +void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode); +void tvencoder_enable(struct sunxi_tve_reg * const tve); + +#endif /* _TVE_H */ diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index b8afd892ad..dbaab61b59 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -5,5 +5,5 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o ../videomodes.o +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o tve.o ../videomodes.o obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index 92c9d06054..2ff50994b4 100644 --- a/drivers/video/sunxi/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -14,6 +14,7 @@ #include <asm/arch/gpio.h> #include <asm/arch/lcdc.h> #include <asm/arch/pwm.h> +#include <asm/arch/tve.h> #include <asm/global_data.h> #include <asm/gpio.h> #include <asm/io.h> @@ -929,63 +930,19 @@ static void sunxi_tvencoder_mode_set(void)
switch (sunxi_display.monitor) { case sunxi_monitor_vga: - writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | - SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | - SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl); - writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0); - writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0); - writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1); + tvencoder_mode_set(tve, tve_mode_vga); break; case sunxi_monitor_composite_pal_nc: - writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq); - /* Fall through */ + tvencoder_mode_set(tve, tve_mode_composite_pal_nc); + break; case sunxi_monitor_composite_pal: - writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | - SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | - SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) | - SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl); - writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0); - writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); - writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter); - writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num); - writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num); - writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level); - writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1); - writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level); - writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width); - writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2); - writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num); - writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain); - writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width); - writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num); - writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para); + tvencoder_mode_set(tve, tve_mode_composite_pal); break; case sunxi_monitor_composite_pal_m: - writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq); - writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst); - /* Fall through */ + tvencoder_mode_set(tve, tve_mode_composite_pal_m); + break; case sunxi_monitor_composite_ntsc: - writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | - SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | - SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) | - SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl); - writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0); - writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); - writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter); - writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num); - writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num); - writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level); - writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1); - writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level); - writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase); - writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width); - writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2); - writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level); - writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num); - writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain); - writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width); - writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num); - writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para); + tvencoder_mode_set(tve, tve_mode_composite_ntsc); break; case sunxi_monitor_none: case sunxi_monitor_dvi: @@ -995,14 +952,6 @@ static void sunxi_tvencoder_mode_set(void) } }
-static void sunxi_tvencoder_enable(void) -{ - struct sunxi_tve_reg * const tve = - (struct sunxi_tve_reg *)SUNXI_TVE0_BASE; - - setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE); -} - #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
static void sunxi_drc_init(void) @@ -1080,6 +1029,8 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, int __maybe_unused clk_div, clk_double; struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; + struct sunxi_tve_reg * const tve = + (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
switch (sunxi_display.monitor) { case sunxi_monitor_none: @@ -1134,7 +1085,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_tvencoder_mode_set(); sunxi_composer_enable(); lcdc_enable(lcdc, sunxi_display.depth); - sunxi_tvencoder_enable(); + tvencoder_enable(tve); #elif defined CONFIG_VIDEO_VGA_VIA_LCD sunxi_composer_mode_set(mode, address); sunxi_lcdc_tcon0_mode_set(mode, true); @@ -1153,7 +1104,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_tvencoder_mode_set(); sunxi_composer_enable(); lcdc_enable(lcdc, sunxi_display.depth); - sunxi_tvencoder_enable(); + tvencoder_enable(tve); #endif break; } diff --git a/drivers/video/sunxi/tve.c b/drivers/video/sunxi/tve.c new file mode 100644 index 0000000000..adea78a69a --- /dev/null +++ b/drivers/video/sunxi/tve.c @@ -0,0 +1,86 @@ +/* + * TV encoder driver for Allwinner SoCs. + * + * (C) Copyright 2013-2014 Luc Verhaegen libv@skynet.be + * (C) Copyright 2014-2015 Hans de Goede hdegoede@redhat.com + * (C) Copyright 2017 Jernej Skrabec jernej.skrabec@siol.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#include <asm/arch/tve.h> +#include <asm/io.h> + +void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) +{ + switch (mode) { + case tve_mode_vga: + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl); + writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0); + writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0); + writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1); + break; + case tve_mode_composite_pal_nc: + writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq); + /* Fall through */ + case tve_mode_composite_pal: + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) | + SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl); + writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0); + writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); + writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter); + writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num); + writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num); + writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, + &tve->blank_black_level); + writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1); + writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level); + writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width); + writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2); + writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num); + writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain); + writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width); + writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num); + writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para); + break; + case tve_mode_composite_pal_m: + writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq); + writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst); + /* Fall through */ + case tve_mode_composite_ntsc: + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) | + SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl); + writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0); + writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); + writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter); + writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num); + writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num); + writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, + &tve->blank_black_level); + writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1); + writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level); + writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase); + writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width); + writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2); + writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level); + writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num); + writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain); + writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width); + writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num); + writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para); + break; + } +} + +void tvencoder_enable(struct sunxi_tve_reg * const tve) +{ + setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE); +}

On 10 May 2017 at 10:46, Jernej Skrabec jernej.skrabec@siol.net wrote:
Newer SoCs use same TV encoder unit. Split it out so it can be reused with new DM video driver.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/display.h | 107 ------------------------ arch/arm/include/asm/arch-sunxi/tve.h | 131 ++++++++++++++++++++++++++++++ drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_display.c | 73 +++-------------- drivers/video/sunxi/tve.c | 86 ++++++++++++++++++++ 5 files changed, 230 insertions(+), 169 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/tve.h create mode 100644 drivers/video/sunxi/tve.c
Reviewed-by: Simon Glass sjg@chromium.org

On Wed, 10 May 2017 18:46:28 +0200 Jernej Skrabec jernej.skrabec@siol.net wrote:
Newer SoCs use same TV encoder unit. Split it out so it can be reused with new DM video driver.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/display.h | 107 ------------------------ arch/arm/include/asm/arch-sunxi/tve.h | 131 ++++++++++++++++++++++++++++++ drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_display.c | 73 +++-------------- drivers/video/sunxi/tve.c | 86 ++++++++++++++++++++ 5 files changed, 230 insertions(+), 169 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/tve.h create mode 100644 drivers/video/sunxi/tve.c
applied to u-boot-video/master, thanks!
-- Anatolij

This patch adds support for TV encoder clocks which will be used later.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net ---
arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index a44ea77576..dc011cc964 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -83,7 +83,8 @@ struct sunxi_ccm_reg { u32 lcd0_ch0_clk_cfg; /* 0x118 LCD0 CH0 module clock */ u32 lcd1_ch0_clk_cfg; /* 0x11c LCD1 CH0 module clock */ #endif - u32 reserved14[3]; + u32 tve_clk_cfg; /* 0x120 TVE module clock */ + u32 reserved14[2]; u32 lcd0_ch1_clk_cfg; /* 0x12c LCD0 CH1 module clock */ u32 lcd1_ch1_clk_cfg; /* 0x130 LCD1 CH1 module clock */ u32 csi0_clk_cfg; /* 0x134 CSI0 module clock */ @@ -299,6 +300,7 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_DE_BE0 12 #define AHB_GATE_OFFSET_DE 12 #define AHB_GATE_OFFSET_HDMI 11 +#define AHB_GATE_OFFSET_TVE 9 #ifndef CONFIG_SUNXI_DE2 #define AHB_GATE_OFFSET_LCD1 5 #define AHB_GATE_OFFSET_LCD0 4 @@ -404,6 +406,9 @@ struct sunxi_ccm_reg {
#define CCM_HDMI_SLOW_CTRL_DDC_GATE (1 << 31)
+#define CCM_TVE_CTRL_GATE (0x1 << 31) +#define CCM_TVE_CTRL_M(n) ((((n) - 1) & 0xf) << 0) + #if defined(CONFIG_MACH_SUN50I) #define MBUS_CLK_DEFAULT 0x81000002 /* PLL6x2 / 3 */ #elif defined(CONFIG_MACH_SUN8I) @@ -434,6 +439,7 @@ struct sunxi_ccm_reg { #define AHB_RESET_OFFSET_DE 12 #define AHB_RESET_OFFSET_HDMI 11 #define AHB_RESET_OFFSET_HDMI2 10 +#define AHB_RESET_OFFSET_TVE 9 #ifndef CONFIG_SUNXI_DE2 #define AHB_RESET_OFFSET_LCD1 5 #define AHB_RESET_OFFSET_LCD0 4

Hi Jernej,
On Wed, May 10, 2017 at 06:46:29PM +0200, Jernej Skrabec wrote:
This patch adds support for TV encoder clocks which will be used later.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index a44ea77576..dc011cc964 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -83,7 +83,8 @@ struct sunxi_ccm_reg { u32 lcd0_ch0_clk_cfg; /* 0x118 LCD0 CH0 module clock */ u32 lcd1_ch0_clk_cfg; /* 0x11c LCD1 CH0 module clock */ #endif
- u32 reserved14[3];
- u32 tve_clk_cfg; /* 0x120 TVE module clock */
- u32 reserved14[2];
Maybe we should protect that with a comment, or an ifdef, that this is only for the H3-generation SoCs?
Maxime

Hi Maxime,
Dne petek, 12. maj 2017 ob 17:47:17 CEST je Maxime Ripard napisal(a):
Hi Jernej,
On Wed, May 10, 2017 at 06:46:29PM +0200, Jernej Skrabec wrote:
This patch adds support for TV encoder clocks which will be used later.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index a44ea77576..dc011cc964 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -83,7 +83,8 @@ struct sunxi_ccm_reg {
u32 lcd0_ch0_clk_cfg; /* 0x118 LCD0 CH0 module clock */ u32 lcd1_ch0_clk_cfg; /* 0x11c LCD1 CH0 module clock */
#endif
- u32 reserved14[3];
- u32 tve_clk_cfg; /* 0x120 TVE module clock */
- u32 reserved14[2];
Maybe we should protect that with a comment, or an ifdef, that this is only for the H3-generation SoCs?
I vote for extending the comment, like: /* 0x120 H3/H5 TVE module clock */
Would that be ok?
Best regards, Jernej

On Fri, May 12, 2017 at 06:55:56PM +0200, Jernej Škrabec wrote:
Hi Maxime,
Dne petek, 12. maj 2017 ob 17:47:17 CEST je Maxime Ripard napisal(a):
Hi Jernej,
On Wed, May 10, 2017 at 06:46:29PM +0200, Jernej Skrabec wrote:
This patch adds support for TV encoder clocks which will be used later.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index a44ea77576..dc011cc964 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -83,7 +83,8 @@ struct sunxi_ccm_reg {
u32 lcd0_ch0_clk_cfg; /* 0x118 LCD0 CH0 module clock */ u32 lcd1_ch0_clk_cfg; /* 0x11c LCD1 CH0 module clock */
#endif
- u32 reserved14[3];
- u32 tve_clk_cfg; /* 0x120 TVE module clock */
- u32 reserved14[2];
Maybe we should protect that with a comment, or an ifdef, that this is only for the H3-generation SoCs?
I vote for extending the comment, like: /* 0x120 H3/H5 TVE module clock */
Would that be ok?
That works, thanks! Maxime

On Wed, 10 May 2017 18:46:29 +0200 Jernej Skrabec jernej.skrabec@siol.net wrote:
This patch adds support for TV encoder clocks which will be used later.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
applied to u-boot-video/master, with comment extended as discussed. Thanks!
-- Anatolij

This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net ---
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +- 7 files changed, 251 insertions(+), 17 deletions(-) create mode 100644 drivers/video/sunxi/sunxi_tve.c
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h index 6aa5e91ada..2419062d45 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h @@ -34,7 +34,9 @@ #define SUNXI_MS_BASE 0x01c07000 #define SUNXI_TVD_BASE 0x01c08000 #define SUNXI_CSI0_BASE 0x01c09000 +#ifndef CONFIG_MACH_SUNXI_H3_H5 #define SUNXI_TVE0_BASE 0x01c0a000 +#endif #define SUNXI_EMAC_BASE 0x01c0b000 #define SUNXI_LCD0_BASE 0x01c0C000 #define SUNXI_LCD1_BASE 0x01c0d000 @@ -161,10 +163,18 @@ defined(CONFIG_MACH_SUN50I) /* module sram */ #define SUNXI_SRAM_C_BASE 0x01d00000
+#ifndef CONFIG_MACH_SUN8I_H3 #define SUNXI_DE_FE0_BASE 0x01e00000 +#else +#define SUNXI_TVE0_BASE 0x01e00000 +#endif #define SUNXI_DE_FE1_BASE 0x01e20000 #define SUNXI_DE_BE0_BASE 0x01e60000 +#ifndef CONFIG_MACH_SUN50I_H5 #define SUNXI_DE_BE1_BASE 0x01e40000 +#else +#define SUNXI_TVE0_BASE 0x01e40000 +#endif #define SUNXI_MP_BASE 0x01e80000 #define SUNXI_AVG_BASE 0x01ea0000
diff --git a/arch/arm/include/asm/arch-sunxi/display2.h b/arch/arm/include/asm/arch-sunxi/display2.h index b5875f9605..359cacd90b 100644 --- a/arch/arm/include/asm/arch-sunxi/display2.h +++ b/arch/arm/include/asm/arch-sunxi/display2.h @@ -90,6 +90,23 @@ struct de_ui { u32 ovl_size; };
+struct de_csc { + u32 csc_ctl; + u8 res[0xc]; + u32 coef11; + u32 coef12; + u32 coef13; + u32 coef14; + u32 coef21; + u32 coef22; + u32 coef23; + u32 coef24; + u32 coef31; + u32 coef32; + u32 coef33; + u32 coef34; +}; + /* * DE register constants. */ diff --git a/arch/arm/include/asm/arch-sunxi/tve.h b/arch/arm/include/asm/arch-sunxi/tve.h index 41a14a68e4..ff34bbbc12 100644 --- a/arch/arm/include/asm/arch-sunxi/tve.h +++ b/arch/arm/include/asm/arch-sunxi/tve.h @@ -45,7 +45,9 @@ struct sunxi_tve_reg { u32 csc_reg1; /* 0x044 */ u32 csc_reg2; /* 0x048 */ u32 csc_reg3; /* 0x04c */ - u8 res1[0xb0]; /* 0x050 */ + u8 res1[0xa8]; /* 0x050 */ + u32 auto_detect_cfg0; /* 0x0f8 */ + u32 auto_detect_cfg1; /* 0x0fc */ u32 color_burst; /* 0x100 */ u32 vsync_num; /* 0x104 */ u32 notch_freq; /* 0x108 */ @@ -62,6 +64,10 @@ struct sunxi_tve_reg { u32 slave_para; /* 0x134 */ u32 cfg1; /* 0x138 */ u32 cfg2; /* 0x13c */ + u8 res2[0x1c4]; /* 0x140 */ + u32 calibration; /* 0x304 */ + u8 res3[0x4]; /* 0x308 */ + u32 unknown3; /* 0x30c */ };
/* @@ -79,12 +85,14 @@ struct sunxi_tve_reg { #define SUNXI_TVE_CFG0_PAL 0x07030001 #define SUNXI_TVE_CFG0_NTSC 0x07030000 #define SUNXI_TVE_DAC_CFG0_VGA 0x403e1ac7 -#ifdef CONFIG_MACH_SUN5I +#if defined(CONFIG_MACH_SUN5I) || defined(CONFIG_MACH_SUNXI_H3_H5) #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x433f0009 #else #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x403f0008 #endif +#define SUNXI_TVE_DAC_CFG0_DETECTION 0x433f0289 #define SUNXI_TVE_FILTER_COMPOSITE 0x00000120 +#define SUNXI_TVE_CHROMA_FREQ_PAL 0x2a098acb #define SUNXI_TVE_CHROMA_FREQ_PAL_M 0x21e6efe3 #define SUNXI_TVE_CHROMA_FREQ_PAL_NC 0x21f69446 #define SUNXI_TVE_PORCH_NUM_PAL 0x008a0018 @@ -105,6 +113,8 @@ struct sunxi_tve_reg { #define SUNXI_TVE_AUTO_DETECT_STATUS_SHORT_GND 3 #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(d) ((d) * 8) #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_MASK(d) (0xf << ((d) * 8)) +#define SUNXI_TVE_AUTO_DETECT_CFG0 0x00000280 +#define SUNXI_TVE_AUTO_DETECT_CFG1 0x028F00FF #define SUNXI_TVE_CSC_REG0_ENABLE (1 << 31) #define SUNXI_TVE_CSC_REG0 0x08440832 #define SUNXI_TVE_CSC_REG1 0x3b6dace1 @@ -124,6 +134,9 @@ struct sunxi_tve_reg { #define SUNXI_TVE_RESYNC_NUM_PAL 0x800d000c #define SUNXI_TVE_RESYNC_NUM_NTSC 0x000e000c #define SUNXI_TVE_SLAVE_PARA_COMPOSITE 0x00000000 +#define SUNXI_TVE_CALIBRATION_H3 0x02000c00 +#define SUNXI_TVE_CALIBRATION_H5 0x02850000 +#define SUNXI_TVE_UNKNOWN3_H5 0x00101110
void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode); void tvencoder_enable(struct sunxi_tve_reg * const tve); diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index dbaab61b59..1db82c53f0 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -6,4 +6,4 @@ #
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o tve.o ../videomodes.o -obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o sunxi_tve.o tve.o lcdc.o ../dw_hdmi.o diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 9a32c3a020..ee67764ac5 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -56,7 +56,7 @@ static void sunxi_de2_composer_init(void) }
static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, - int bpp, ulong address) + int bpp, ulong address, bool is_composite) { ulong de_mux_base = (mux == 0) ? SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE; @@ -72,6 +72,9 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, (struct de_ui *)(de_mux_base + SUNXI_DE2_MUX_CHAN_REGS + SUNXI_DE2_MUX_CHAN_SZ * 1); + struct de_csc * const de_csc_regs = + (struct de_csc *)(de_mux_base + + SUNXI_DE2_MUX_DCSC_REGS); u32 size = SUNXI_DE2_WH(mode->hactive.typ, mode->vactive.typ); int channel; u32 format; @@ -128,7 +131,27 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, writel(0, de_mux_base + SUNXI_DE2_MUX_PEAK_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_ASE_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_FCC_REGS); - writel(0, de_mux_base + SUNXI_DE2_MUX_DCSC_REGS); + + if (is_composite) { + /* set CSC coefficients */ + writel(0x107, &de_csc_regs->coef11); + writel(0x204, &de_csc_regs->coef12); + writel(0x64, &de_csc_regs->coef13); + writel(0x4200, &de_csc_regs->coef14); + writel(0x1f68, &de_csc_regs->coef21); + writel(0x1ed6, &de_csc_regs->coef22); + writel(0x1c2, &de_csc_regs->coef23); + writel(0x20200, &de_csc_regs->coef24); + writel(0x1c2, &de_csc_regs->coef31); + writel(0x1e87, &de_csc_regs->coef32); + writel(0x1fb7, &de_csc_regs->coef33); + writel(0x20200, &de_csc_regs->coef34); + + /* enable CSC unit */ + writel(1, &de_csc_regs->csc_ctl); + } else { + writel(0, &de_csc_regs->csc_ctl); + }
switch (bpp) { case 16: @@ -153,7 +176,7 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
static int sunxi_de2_init(struct udevice *dev, ulong fbbase, enum video_log2_bpp l2bpp, - struct udevice *disp, int mux) + struct udevice *disp, int mux, bool is_composite) { struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct display_timing timing; @@ -183,7 +206,7 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, }
sunxi_de2_composer_init(); - sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase); + sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase, is_composite);
ret = display_enable(disp, 1 << l2bpp, &timing); if (ret) { @@ -204,7 +227,6 @@ static int sunxi_de2_probe(struct udevice *dev) struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); struct udevice *disp; int ret; - int mux;
/* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC)) @@ -212,17 +234,31 @@ static int sunxi_de2_probe(struct udevice *dev)
ret = uclass_find_device_by_name(UCLASS_DISPLAY, "sunxi_dw_hdmi", &disp); + if (!ret) { + int mux; + if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) + mux = 0; + else + mux = 1; + + ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux, + false); + if (!ret) { + video_set_flush_dcache(dev, 1); + return 0; + } + } + + debug("%s: hdmi display not found (ret=%d)\n", __func__, ret); + + ret = uclass_find_device_by_name(UCLASS_DISPLAY, + "sunxi_tve", &disp); if (ret) { - debug("%s: hdmi display not found (ret=%d)\n", __func__, ret); + debug("%s: tv not found (ret=%d)\n", __func__, ret); return ret; }
- if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) - mux = 0; - else - mux = 1; - - ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux); + ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true); if (ret) return ret;
diff --git a/drivers/video/sunxi/sunxi_tve.c b/drivers/video/sunxi/sunxi_tve.c new file mode 100644 index 0000000000..95f54bbaf7 --- /dev/null +++ b/drivers/video/sunxi/sunxi_tve.c @@ -0,0 +1,156 @@ +/* + * Allwinner TVE driver + * + * (C) Copyright 2017 Jernej Skrabec jernej.skrabec@siol.net + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <display.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/lcdc.h> +#include <asm/arch/tve.h> + +static int sunxi_tve_get_plug_in_status(void) +{ + struct sunxi_tve_reg * const tve = + (struct sunxi_tve_reg *)SUNXI_TVE0_BASE; + u32 status; + + status = readl(&tve->auto_detect_status) & + SUNXI_TVE_AUTO_DETECT_STATUS_MASK(0); + + return status == SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED; +} + +static int sunxi_tve_wait_for_hpd(void) +{ + struct sunxi_tve_reg * const tve = + (struct sunxi_tve_reg *)SUNXI_TVE0_BASE; + ulong start; + + /* enable auto detection */ + writel(SUNXI_TVE_DAC_CFG0_DETECTION, &tve->dac_cfg0); + writel(SUNXI_TVE_AUTO_DETECT_CFG0, &tve->auto_detect_cfg0); + writel(SUNXI_TVE_AUTO_DETECT_CFG1, &tve->auto_detect_cfg1); + writel(9 << SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(0), + &tve->auto_detect_debounce); + writel(SUNXI_TVE_AUTO_DETECT_EN_DET_EN(0), &tve->auto_detect_en); + + start = get_timer(0); + do { + if (sunxi_tve_get_plug_in_status()) + return 0; + udelay(100); + } while (get_timer(start) < 300); + + return -1; +} + +static void sunxi_tve_lcdc_init(const struct display_timing *edid, int bpp) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_lcdc_reg * const lcdc = + (struct sunxi_lcdc_reg *)SUNXI_LCD1_BASE; + + /* Reset off */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD1); + + /* Clock on */ + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD1); + + lcdc_init(lcdc); + lcdc_tcon1_mode_set(lcdc, edid, false, true); + lcdc_enable(lcdc, bpp); +} + +static int sunxi_tve_read_timing(struct udevice *dev, + struct display_timing *timing) +{ + /* PAL resolution */ + timing->pixelclock.typ = 27000000; + + timing->hactive.typ = 720; + timing->hfront_porch.typ = 5; + timing->hback_porch.typ = 137; + timing->hsync_len.typ = 2; + + timing->vactive.typ = 576; + timing->vfront_porch.typ = 27; + timing->vback_porch.typ = 20; + timing->vsync_len.typ = 2; + + timing->flags = DISPLAY_FLAGS_INTERLACED; + + return 0; +} + +static int sunxi_tve_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *edid) +{ + struct sunxi_tve_reg * const tve = + (struct sunxi_tve_reg *)SUNXI_TVE0_BASE; + + sunxi_tve_lcdc_init(edid, panel_bpp); + + tvencoder_mode_set(tve, tve_mode_composite_pal); + tvencoder_enable(tve); + + return 0; +} + +static int sunxi_tve_probe(struct udevice *dev) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_tve_reg * const tve = + (struct sunxi_tve_reg *)SUNXI_TVE0_BASE; + int ret; + + /* make sure that clock is active */ + clock_set_pll10(432000000); + + /* Reset off */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_TVE); + + /* Clock on */ + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE); + writel(CCM_TVE_CTRL_GATE | CCM_TVE_CTRL_M(2), &ccm->tve_clk_cfg); + +#ifdef CONFIG_MACH_SUN50I_H5 + writel(SUNXI_TVE_CALIBRATION_H5, &tve->calibration); + writel(SUNXI_TVE_UNKNOWN3_H5, &tve->unknown3); +#else + writel(SUNXI_TVE_CALIBRATION_H3, &tve->calibration); +#endif + + ret = sunxi_tve_wait_for_hpd(); + if (ret < 0) { + debug("tve can not get hpd signal\n"); + return -1; + } + + return 0; +} + +static const struct dm_display_ops sunxi_tve_ops = { + .read_timing = sunxi_tve_read_timing, + .enable = sunxi_tve_enable, +}; + +U_BOOT_DRIVER(sunxi_tve) = { + .name = "sunxi_tve", + .id = UCLASS_DISPLAY, + .ops = &sunxi_tve_ops, + .probe = sunxi_tve_probe, +}; + +#ifdef CONFIG_MACH_SUNXI_H3_H5 +U_BOOT_DEVICE(sunxi_tve) = { + .name = "sunxi_tve" +}; +#endif diff --git a/drivers/video/sunxi/tve.c b/drivers/video/sunxi/tve.c index adea78a69a..ef99c111e3 100644 --- a/drivers/video/sunxi/tve.c +++ b/drivers/video/sunxi/tve.c @@ -25,8 +25,6 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1); break; case tve_mode_composite_pal_nc: - writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq); - /* Fall through */ case tve_mode_composite_pal: writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | @@ -35,6 +33,10 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0); writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter); + if (mode == tve_mode_composite_pal) + writel(SUNXI_TVE_CHROMA_FREQ_PAL, &tve->chroma_freq); + else + writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq); writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num); writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num); writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL,

Hi Jernej,
The patch content looks fine, but there's a few things that would need to be addressed.
On Wed, May 10, 2017 at 06:46:30PM +0200, Jernej Skrabec wrote:
This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
7 files changed, 251 insertions(+), 17 deletions(-) create mode 100644 drivers/video/sunxi/sunxi_tve.c
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h index 6aa5e91ada..2419062d45 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h @@ -34,7 +34,9 @@ #define SUNXI_MS_BASE 0x01c07000 #define SUNXI_TVD_BASE 0x01c08000 #define SUNXI_CSI0_BASE 0x01c09000 +#ifndef CONFIG_MACH_SUNXI_H3_H5 #define SUNXI_TVE0_BASE 0x01c0a000 +#endif
This should be part of a seperate patch.
#define SUNXI_EMAC_BASE 0x01c0b000 #define SUNXI_LCD0_BASE 0x01c0C000 #define SUNXI_LCD1_BASE 0x01c0d000 @@ -161,10 +163,18 @@ defined(CONFIG_MACH_SUN50I) /* module sram */ #define SUNXI_SRAM_C_BASE 0x01d00000
+#ifndef CONFIG_MACH_SUN8I_H3 #define SUNXI_DE_FE0_BASE 0x01e00000 +#else +#define SUNXI_TVE0_BASE 0x01e00000 +#endif
This one should be in that other patch
#define SUNXI_DE_FE1_BASE 0x01e20000 #define SUNXI_DE_BE0_BASE 0x01e60000 +#ifndef CONFIG_MACH_SUN50I_H5 #define SUNXI_DE_BE1_BASE 0x01e40000 +#else +#define SUNXI_TVE0_BASE 0x01e40000 +#endif
And that one too.
#define SUNXI_MP_BASE 0x01e80000 #define SUNXI_AVG_BASE 0x01ea0000
diff --git a/arch/arm/include/asm/arch-sunxi/display2.h b/arch/arm/include/asm/arch-sunxi/display2.h index b5875f9605..359cacd90b 100644 --- a/arch/arm/include/asm/arch-sunxi/display2.h +++ b/arch/arm/include/asm/arch-sunxi/display2.h @@ -90,6 +90,23 @@ struct de_ui { u32 ovl_size; };
+struct de_csc {
- u32 csc_ctl;
- u8 res[0xc];
- u32 coef11;
- u32 coef12;
- u32 coef13;
- u32 coef14;
- u32 coef21;
- u32 coef22;
- u32 coef23;
- u32 coef24;
- u32 coef31;
- u32 coef32;
- u32 coef33;
- u32 coef34;
+};
This should be in another patch (let's call it patch 2)
/*
- DE register constants.
*/ diff --git a/arch/arm/include/asm/arch-sunxi/tve.h b/arch/arm/include/asm/arch-sunxi/tve.h index 41a14a68e4..ff34bbbc12 100644 --- a/arch/arm/include/asm/arch-sunxi/tve.h +++ b/arch/arm/include/asm/arch-sunxi/tve.h @@ -45,7 +45,9 @@ struct sunxi_tve_reg { u32 csc_reg1; /* 0x044 */ u32 csc_reg2; /* 0x048 */ u32 csc_reg3; /* 0x04c */
- u8 res1[0xb0]; /* 0x050 */
- u8 res1[0xa8]; /* 0x050 */
- u32 auto_detect_cfg0; /* 0x0f8 */
- u32 auto_detect_cfg1; /* 0x0fc */ u32 color_burst; /* 0x100 */ u32 vsync_num; /* 0x104 */ u32 notch_freq; /* 0x108 */
@@ -62,6 +64,10 @@ struct sunxi_tve_reg { u32 slave_para; /* 0x134 */ u32 cfg1; /* 0x138 */ u32 cfg2; /* 0x13c */
- u8 res2[0x1c4]; /* 0x140 */
- u32 calibration; /* 0x304 */
- u8 res3[0x4]; /* 0x308 */
- u32 unknown3; /* 0x30c */
And these yet another one (patch 3)
};
/* @@ -79,12 +85,14 @@ struct sunxi_tve_reg { #define SUNXI_TVE_CFG0_PAL 0x07030001 #define SUNXI_TVE_CFG0_NTSC 0x07030000 #define SUNXI_TVE_DAC_CFG0_VGA 0x403e1ac7 -#ifdef CONFIG_MACH_SUN5I +#if defined(CONFIG_MACH_SUN5I) || defined(CONFIG_MACH_SUNXI_H3_H5) #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x433f0009 #else #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x403f0008 #endif +#define SUNXI_TVE_DAC_CFG0_DETECTION 0x433f0289 #define SUNXI_TVE_FILTER_COMPOSITE 0x00000120 +#define SUNXI_TVE_CHROMA_FREQ_PAL 0x2a098acb #define SUNXI_TVE_CHROMA_FREQ_PAL_M 0x21e6efe3 #define SUNXI_TVE_CHROMA_FREQ_PAL_NC 0x21f69446 #define SUNXI_TVE_PORCH_NUM_PAL 0x008a0018 @@ -105,6 +113,8 @@ struct sunxi_tve_reg { #define SUNXI_TVE_AUTO_DETECT_STATUS_SHORT_GND 3 #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(d) ((d) * 8) #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_MASK(d) (0xf << ((d) * 8)) +#define SUNXI_TVE_AUTO_DETECT_CFG0 0x00000280 +#define SUNXI_TVE_AUTO_DETECT_CFG1 0x028F00FF #define SUNXI_TVE_CSC_REG0_ENABLE (1 << 31) #define SUNXI_TVE_CSC_REG0 0x08440832 #define SUNXI_TVE_CSC_REG1 0x3b6dace1 @@ -124,6 +134,9 @@ struct sunxi_tve_reg { #define SUNXI_TVE_RESYNC_NUM_PAL 0x800d000c #define SUNXI_TVE_RESYNC_NUM_NTSC 0x000e000c #define SUNXI_TVE_SLAVE_PARA_COMPOSITE 0x00000000 +#define SUNXI_TVE_CALIBRATION_H3 0x02000c00 +#define SUNXI_TVE_CALIBRATION_H5 0x02850000 +#define SUNXI_TVE_UNKNOWN3_H5 0x00101110
patch 3
void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode); void tvencoder_enable(struct sunxi_tve_reg * const tve); diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index dbaab61b59..1db82c53f0 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -6,4 +6,4 @@ #
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o tve.o ../videomodes.o -obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o sunxi_tve.o tve.o lcdc.o ../dw_hdmi.o diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 9a32c3a020..ee67764ac5 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -56,7 +56,7 @@ static void sunxi_de2_composer_init(void) }
static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
int bpp, ulong address)
int bpp, ulong address, bool is_composite)
{ ulong de_mux_base = (mux == 0) ? SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE;
patch 2
@@ -72,6 +72,9 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, (struct de_ui *)(de_mux_base + SUNXI_DE2_MUX_CHAN_REGS + SUNXI_DE2_MUX_CHAN_SZ * 1);
- struct de_csc * const de_csc_regs =
(struct de_csc *)(de_mux_base +
SUNXI_DE2_MUX_DCSC_REGS);
patch 2
u32 size = SUNXI_DE2_WH(mode->hactive.typ, mode->vactive.typ); int channel; u32 format; @@ -128,7 +131,27 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, writel(0, de_mux_base + SUNXI_DE2_MUX_PEAK_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_ASE_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_FCC_REGS);
- writel(0, de_mux_base + SUNXI_DE2_MUX_DCSC_REGS);
- if (is_composite) {
/* set CSC coefficients */
writel(0x107, &de_csc_regs->coef11);
writel(0x204, &de_csc_regs->coef12);
writel(0x64, &de_csc_regs->coef13);
writel(0x4200, &de_csc_regs->coef14);
writel(0x1f68, &de_csc_regs->coef21);
writel(0x1ed6, &de_csc_regs->coef22);
writel(0x1c2, &de_csc_regs->coef23);
writel(0x20200, &de_csc_regs->coef24);
writel(0x1c2, &de_csc_regs->coef31);
writel(0x1e87, &de_csc_regs->coef32);
writel(0x1fb7, &de_csc_regs->coef33);
writel(0x20200, &de_csc_regs->coef34);
/* enable CSC unit */
writel(1, &de_csc_regs->csc_ctl);
- } else {
writel(0, &de_csc_regs->csc_ctl);
- }
patch 2
switch (bpp) { case 16: @@ -153,7 +176,7 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
static int sunxi_de2_init(struct udevice *dev, ulong fbbase, enum video_log2_bpp l2bpp,
struct udevice *disp, int mux)
struct udevice *disp, int mux, bool is_composite)
{ struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct display_timing timing; @@ -183,7 +206,7 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, }
sunxi_de2_composer_init();
- sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase);
sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase, is_composite);
ret = display_enable(disp, 1 << l2bpp, &timing); if (ret) {
@@ -204,7 +227,6 @@ static int sunxi_de2_probe(struct udevice *dev) struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); struct udevice *disp; int ret;
int mux;
/* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC))
@@ -212,17 +234,31 @@ static int sunxi_de2_probe(struct udevice *dev)
ret = uclass_find_device_by_name(UCLASS_DISPLAY, "sunxi_dw_hdmi", &disp);
- if (!ret) {
int mux;
if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
mux = 0;
else
mux = 1;
ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
false);
if (!ret) {
video_set_flush_dcache(dev, 1);
return 0;
}
- }
- debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
- ret = uclass_find_device_by_name(UCLASS_DISPLAY,
if (ret) {"sunxi_tve", &disp);
debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
return ret; }debug("%s: tv not found (ret=%d)\n", __func__, ret);
- if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
mux = 0;
- else
mux = 1;
- ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux);
- ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true);
patch 2
if (ret) return ret;
diff --git a/drivers/video/sunxi/sunxi_tve.c b/drivers/video/sunxi/sunxi_tve.c new file mode 100644 index 0000000000..95f54bbaf7 --- /dev/null +++ b/drivers/video/sunxi/sunxi_tve.c @@ -0,0 +1,156 @@ +/*
- Allwinner TVE driver
- (C) Copyright 2017 Jernej Skrabec jernej.skrabec@siol.net
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <display.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/lcdc.h> +#include <asm/arch/tve.h>
+static int sunxi_tve_get_plug_in_status(void) +{
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- u32 status;
- status = readl(&tve->auto_detect_status) &
SUNXI_TVE_AUTO_DETECT_STATUS_MASK(0);
- return status == SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED;
+}
+static int sunxi_tve_wait_for_hpd(void) +{
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- ulong start;
- /* enable auto detection */
- writel(SUNXI_TVE_DAC_CFG0_DETECTION, &tve->dac_cfg0);
- writel(SUNXI_TVE_AUTO_DETECT_CFG0, &tve->auto_detect_cfg0);
- writel(SUNXI_TVE_AUTO_DETECT_CFG1, &tve->auto_detect_cfg1);
- writel(9 << SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(0),
&tve->auto_detect_debounce);
- writel(SUNXI_TVE_AUTO_DETECT_EN_DET_EN(0), &tve->auto_detect_en);
- start = get_timer(0);
- do {
if (sunxi_tve_get_plug_in_status())
return 0;
udelay(100);
- } while (get_timer(start) < 300);
- return -1;
+}
+static void sunxi_tve_lcdc_init(const struct display_timing *edid, int bpp) +{
- struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD1_BASE;
- /* Reset off */
- setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD1);
- /* Clock on */
- setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD1);
- lcdc_init(lcdc);
- lcdc_tcon1_mode_set(lcdc, edid, false, true);
- lcdc_enable(lcdc, bpp);
+}
+static int sunxi_tve_read_timing(struct udevice *dev,
struct display_timing *timing)
+{
- /* PAL resolution */
- timing->pixelclock.typ = 27000000;
- timing->hactive.typ = 720;
- timing->hfront_porch.typ = 5;
- timing->hback_porch.typ = 137;
- timing->hsync_len.typ = 2;
- timing->vactive.typ = 576;
- timing->vfront_porch.typ = 27;
- timing->vback_porch.typ = 20;
- timing->vsync_len.typ = 2;
- timing->flags = DISPLAY_FLAGS_INTERLACED;
- return 0;
+}
+static int sunxi_tve_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
+{
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- sunxi_tve_lcdc_init(edid, panel_bpp);
- tvencoder_mode_set(tve, tve_mode_composite_pal);
- tvencoder_enable(tve);
- return 0;
+}
+static int sunxi_tve_probe(struct udevice *dev) +{
- struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- int ret;
- /* make sure that clock is active */
- clock_set_pll10(432000000);
- /* Reset off */
- setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_TVE);
- /* Clock on */
- setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE);
- writel(CCM_TVE_CTRL_GATE | CCM_TVE_CTRL_M(2), &ccm->tve_clk_cfg);
+#ifdef CONFIG_MACH_SUN50I_H5
- writel(SUNXI_TVE_CALIBRATION_H5, &tve->calibration);
- writel(SUNXI_TVE_UNKNOWN3_H5, &tve->unknown3);
+#else
- writel(SUNXI_TVE_CALIBRATION_H3, &tve->calibration);
+#endif
- ret = sunxi_tve_wait_for_hpd();
- if (ret < 0) {
debug("tve can not get hpd signal\n");
return -1;
- }
- return 0;
+}
+static const struct dm_display_ops sunxi_tve_ops = {
- .read_timing = sunxi_tve_read_timing,
- .enable = sunxi_tve_enable,
+};
+U_BOOT_DRIVER(sunxi_tve) = {
- .name = "sunxi_tve",
- .id = UCLASS_DISPLAY,
- .ops = &sunxi_tve_ops,
- .probe = sunxi_tve_probe,
+};
+#ifdef CONFIG_MACH_SUNXI_H3_H5 +U_BOOT_DEVICE(sunxi_tve) = {
- .name = "sunxi_tve"
+}; +#endif
patch 3
diff --git a/drivers/video/sunxi/tve.c b/drivers/video/sunxi/tve.c index adea78a69a..ef99c111e3 100644 --- a/drivers/video/sunxi/tve.c +++ b/drivers/video/sunxi/tve.c @@ -25,8 +25,6 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1); break; case tve_mode_composite_pal_nc:
writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
case tve_mode_composite_pal: writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |/* Fall through */
@@ -35,6 +33,10 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0); writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
if (mode == tve_mode_composite_pal)
writel(SUNXI_TVE_CHROMA_FREQ_PAL, &tve->chroma_freq);
else
writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num); writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num); writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL,writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
And patch 3 as well.
Thanks! Maxime

在 2017-05-13 00:06,Maxime Ripard 写道:
Hi Jernej,
The patch content looks fine, but there's a few things that would need to be addressed.
On Wed, May 10, 2017 at 06:46:30PM +0200, Jernej Skrabec wrote:
This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
7 files changed, 251 insertions(+), 17 deletions(-) create mode 100644 drivers/video/sunxi/sunxi_tve.c
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h index 6aa5e91ada..2419062d45 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h @@ -34,7 +34,9 @@ #define SUNXI_MS_BASE 0x01c07000 #define SUNXI_TVD_BASE 0x01c08000 #define SUNXI_CSI0_BASE 0x01c09000 +#ifndef CONFIG_MACH_SUNXI_H3_H5 #define SUNXI_TVE0_BASE 0x01c0a000 +#endif
This should be part of a seperate patch.
#define SUNXI_EMAC_BASE 0x01c0b000 #define SUNXI_LCD0_BASE 0x01c0C000 #define SUNXI_LCD1_BASE 0x01c0d000 @@ -161,10 +163,18 @@ defined(CONFIG_MACH_SUN50I) /* module sram */ #define SUNXI_SRAM_C_BASE 0x01d00000
+#ifndef CONFIG_MACH_SUN8I_H3 #define SUNXI_DE_FE0_BASE 0x01e00000 +#else +#define SUNXI_TVE0_BASE 0x01e00000 +#endif
This one should be in that other patch
#define SUNXI_DE_FE1_BASE 0x01e20000 #define SUNXI_DE_BE0_BASE 0x01e60000 +#ifndef CONFIG_MACH_SUN50I_H5 #define SUNXI_DE_BE1_BASE 0x01e40000 +#else +#define SUNXI_TVE0_BASE 0x01e40000 +#endif
And that one too.
#define SUNXI_MP_BASE 0x01e80000 #define SUNXI_AVG_BASE 0x01ea0000
diff --git a/arch/arm/include/asm/arch-sunxi/display2.h b/arch/arm/include/asm/arch-sunxi/display2.h index b5875f9605..359cacd90b 100644 --- a/arch/arm/include/asm/arch-sunxi/display2.h +++ b/arch/arm/include/asm/arch-sunxi/display2.h @@ -90,6 +90,23 @@ struct de_ui { u32 ovl_size; };
+struct de_csc {
- u32 csc_ctl;
- u8 res[0xc];
- u32 coef11;
- u32 coef12;
- u32 coef13;
- u32 coef14;
- u32 coef21;
- u32 coef22;
- u32 coef23;
- u32 coef24;
- u32 coef31;
- u32 coef32;
- u32 coef33;
- u32 coef34;
+};
This should be in another patch (let's call it patch 2)
/*
- DE register constants.
*/ diff --git a/arch/arm/include/asm/arch-sunxi/tve.h b/arch/arm/include/asm/arch-sunxi/tve.h index 41a14a68e4..ff34bbbc12 100644 --- a/arch/arm/include/asm/arch-sunxi/tve.h +++ b/arch/arm/include/asm/arch-sunxi/tve.h @@ -45,7 +45,9 @@ struct sunxi_tve_reg { u32 csc_reg1; /* 0x044 */ u32 csc_reg2; /* 0x048 */ u32 csc_reg3; /* 0x04c */
- u8 res1[0xb0]; /* 0x050 */
- u8 res1[0xa8]; /* 0x050 */
- u32 auto_detect_cfg0; /* 0x0f8 */
- u32 auto_detect_cfg1; /* 0x0fc */ u32 color_burst; /* 0x100 */ u32 vsync_num; /* 0x104 */ u32 notch_freq; /* 0x108 */
@@ -62,6 +64,10 @@ struct sunxi_tve_reg { u32 slave_para; /* 0x134 */ u32 cfg1; /* 0x138 */ u32 cfg2; /* 0x13c */
- u8 res2[0x1c4]; /* 0x140 */
- u32 calibration; /* 0x304 */
- u8 res3[0x4]; /* 0x308 */
- u32 unknown3; /* 0x30c */
And these yet another one (patch 3)
};
/* @@ -79,12 +85,14 @@ struct sunxi_tve_reg { #define SUNXI_TVE_CFG0_PAL 0x07030001 #define SUNXI_TVE_CFG0_NTSC 0x07030000 #define SUNXI_TVE_DAC_CFG0_VGA 0x403e1ac7 -#ifdef CONFIG_MACH_SUN5I +#if defined(CONFIG_MACH_SUN5I) || defined(CONFIG_MACH_SUNXI_H3_H5) #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x433f0009 #else #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x403f0008 #endif +#define SUNXI_TVE_DAC_CFG0_DETECTION 0x433f0289 #define SUNXI_TVE_FILTER_COMPOSITE 0x00000120 +#define SUNXI_TVE_CHROMA_FREQ_PAL 0x2a098acb #define SUNXI_TVE_CHROMA_FREQ_PAL_M 0x21e6efe3 #define SUNXI_TVE_CHROMA_FREQ_PAL_NC 0x21f69446 #define SUNXI_TVE_PORCH_NUM_PAL 0x008a0018 @@ -105,6 +113,8 @@ struct sunxi_tve_reg { #define SUNXI_TVE_AUTO_DETECT_STATUS_SHORT_GND 3 #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(d) ((d) * 8) #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_MASK(d) (0xf << ((d) * 8)) +#define SUNXI_TVE_AUTO_DETECT_CFG0 0x00000280 +#define SUNXI_TVE_AUTO_DETECT_CFG1 0x028F00FF #define SUNXI_TVE_CSC_REG0_ENABLE (1 << 31) #define SUNXI_TVE_CSC_REG0 0x08440832 #define SUNXI_TVE_CSC_REG1 0x3b6dace1 @@ -124,6 +134,9 @@ struct sunxi_tve_reg { #define SUNXI_TVE_RESYNC_NUM_PAL 0x800d000c #define SUNXI_TVE_RESYNC_NUM_NTSC 0x000e000c #define SUNXI_TVE_SLAVE_PARA_COMPOSITE 0x00000000 +#define SUNXI_TVE_CALIBRATION_H3 0x02000c00 +#define SUNXI_TVE_CALIBRATION_H5 0x02850000 +#define SUNXI_TVE_UNKNOWN3_H5 0x00101110
patch 3
void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode); void tvencoder_enable(struct sunxi_tve_reg * const tve); diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index dbaab61b59..1db82c53f0 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -6,4 +6,4 @@ #
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o tve.o ../videomodes.o -obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o sunxi_tve.o tve.o lcdc.o ../dw_hdmi.o diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 9a32c3a020..ee67764ac5 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -56,7 +56,7 @@ static void sunxi_de2_composer_init(void) }
static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
int bpp, ulong address)
int bpp, ulong address, bool is_composite)
{ ulong de_mux_base = (mux == 0) ? SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE;
patch 2
@@ -72,6 +72,9 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, (struct de_ui *)(de_mux_base + SUNXI_DE2_MUX_CHAN_REGS + SUNXI_DE2_MUX_CHAN_SZ * 1);
- struct de_csc * const de_csc_regs =
(struct de_csc *)(de_mux_base +
SUNXI_DE2_MUX_DCSC_REGS);
patch 2
u32 size = SUNXI_DE2_WH(mode->hactive.typ, mode->vactive.typ); int channel; u32 format; @@ -128,7 +131,27 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, writel(0, de_mux_base + SUNXI_DE2_MUX_PEAK_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_ASE_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_FCC_REGS);
- writel(0, de_mux_base + SUNXI_DE2_MUX_DCSC_REGS);
- if (is_composite) {
/* set CSC coefficients */
writel(0x107, &de_csc_regs->coef11);
writel(0x204, &de_csc_regs->coef12);
writel(0x64, &de_csc_regs->coef13);
writel(0x4200, &de_csc_regs->coef14);
writel(0x1f68, &de_csc_regs->coef21);
writel(0x1ed6, &de_csc_regs->coef22);
writel(0x1c2, &de_csc_regs->coef23);
writel(0x20200, &de_csc_regs->coef24);
writel(0x1c2, &de_csc_regs->coef31);
writel(0x1e87, &de_csc_regs->coef32);
writel(0x1fb7, &de_csc_regs->coef33);
writel(0x20200, &de_csc_regs->coef34);
/* enable CSC unit */
writel(1, &de_csc_regs->csc_ctl);
- } else {
writel(0, &de_csc_regs->csc_ctl);
- }
patch 2
switch (bpp) { case 16: @@ -153,7 +176,7 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
static int sunxi_de2_init(struct udevice *dev, ulong fbbase, enum video_log2_bpp l2bpp,
struct udevice *disp, int mux)
struct udevice *disp, int mux, bool is_composite)
{ struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct display_timing timing; @@ -183,7 +206,7 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, }
sunxi_de2_composer_init();
- sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase);
sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase, is_composite);
ret = display_enable(disp, 1 << l2bpp, &timing); if (ret) {
@@ -204,7 +227,6 @@ static int sunxi_de2_probe(struct udevice *dev) struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); struct udevice *disp; int ret;
int mux;
/* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC))
@@ -212,17 +234,31 @@ static int sunxi_de2_probe(struct udevice *dev)
ret = uclass_find_device_by_name(UCLASS_DISPLAY, "sunxi_dw_hdmi", &disp);
- if (!ret) {
int mux;
if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
mux = 0;
else
mux = 1;
ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
false);
if (!ret) {
video_set_flush_dcache(dev, 1);
return 0;
}
- }
- debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
- ret = uclass_find_device_by_name(UCLASS_DISPLAY,
if (ret) {"sunxi_tve", &disp);
debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
return ret; }debug("%s: tv not found (ret=%d)\n", __func__, ret);
- if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
mux = 0;
- else
mux = 1;
- ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux);
- ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true);
patch 2
if (ret) return ret;
diff --git a/drivers/video/sunxi/sunxi_tve.c b/drivers/video/sunxi/sunxi_tve.c new file mode 100644 index 0000000000..95f54bbaf7 --- /dev/null +++ b/drivers/video/sunxi/sunxi_tve.c @@ -0,0 +1,156 @@ +/*
- Allwinner TVE driver
- (C) Copyright 2017 Jernej Skrabec jernej.skrabec@siol.net
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <display.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/lcdc.h> +#include <asm/arch/tve.h>
+static int sunxi_tve_get_plug_in_status(void) +{
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- u32 status;
- status = readl(&tve->auto_detect_status) &
SUNXI_TVE_AUTO_DETECT_STATUS_MASK(0);
- return status == SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED;
So TVE is now capable of hpd checking, right?
Is is a feature that exists in A10/A13/A20 or is it new in H3?
+}
+static int sunxi_tve_wait_for_hpd(void) +{
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- ulong start;
- /* enable auto detection */
- writel(SUNXI_TVE_DAC_CFG0_DETECTION, &tve->dac_cfg0);
- writel(SUNXI_TVE_AUTO_DETECT_CFG0, &tve->auto_detect_cfg0);
- writel(SUNXI_TVE_AUTO_DETECT_CFG1, &tve->auto_detect_cfg1);
- writel(9 << SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(0),
&tve->auto_detect_debounce);
- writel(SUNXI_TVE_AUTO_DETECT_EN_DET_EN(0), &tve->auto_detect_en);
- start = get_timer(0);
- do {
if (sunxi_tve_get_plug_in_status())
return 0;
udelay(100);
- } while (get_timer(start) < 300);
- return -1;
+}
+static void sunxi_tve_lcdc_init(const struct display_timing *edid, int bpp) +{
- struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD1_BASE;
- /* Reset off */
- setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD1);
- /* Clock on */
- setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD1);
- lcdc_init(lcdc);
- lcdc_tcon1_mode_set(lcdc, edid, false, true);
- lcdc_enable(lcdc, bpp);
+}
+static int sunxi_tve_read_timing(struct udevice *dev,
struct display_timing *timing)
+{
- /* PAL resolution */
- timing->pixelclock.typ = 27000000;
- timing->hactive.typ = 720;
- timing->hfront_porch.typ = 5;
- timing->hback_porch.typ = 137;
- timing->hsync_len.typ = 2;
- timing->vactive.typ = 576;
- timing->vfront_porch.typ = 27;
- timing->vback_porch.typ = 20;
- timing->vsync_len.typ = 2;
- timing->flags = DISPLAY_FLAGS_INTERLACED;
- return 0;
+}
+static int sunxi_tve_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
+{
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- sunxi_tve_lcdc_init(edid, panel_bpp);
- tvencoder_mode_set(tve, tve_mode_composite_pal);
- tvencoder_enable(tve);
- return 0;
+}
+static int sunxi_tve_probe(struct udevice *dev) +{
- struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
- int ret;
- /* make sure that clock is active */
- clock_set_pll10(432000000);
- /* Reset off */
- setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_TVE);
- /* Clock on */
- setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE);
- writel(CCM_TVE_CTRL_GATE | CCM_TVE_CTRL_M(2), &ccm->tve_clk_cfg);
+#ifdef CONFIG_MACH_SUN50I_H5
- writel(SUNXI_TVE_CALIBRATION_H5, &tve->calibration);
- writel(SUNXI_TVE_UNKNOWN3_H5, &tve->unknown3);
+#else
- writel(SUNXI_TVE_CALIBRATION_H3, &tve->calibration);
+#endif
- ret = sunxi_tve_wait_for_hpd();
- if (ret < 0) {
debug("tve can not get hpd signal\n");
return -1;
- }
- return 0;
+}
+static const struct dm_display_ops sunxi_tve_ops = {
- .read_timing = sunxi_tve_read_timing,
- .enable = sunxi_tve_enable,
+};
+U_BOOT_DRIVER(sunxi_tve) = {
- .name = "sunxi_tve",
- .id = UCLASS_DISPLAY,
- .ops = &sunxi_tve_ops,
- .probe = sunxi_tve_probe,
+};
+#ifdef CONFIG_MACH_SUNXI_H3_H5 +U_BOOT_DEVICE(sunxi_tve) = {
- .name = "sunxi_tve"
+}; +#endif
patch 3
diff --git a/drivers/video/sunxi/tve.c b/drivers/video/sunxi/tve.c index adea78a69a..ef99c111e3 100644 --- a/drivers/video/sunxi/tve.c +++ b/drivers/video/sunxi/tve.c @@ -25,8 +25,6 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1); break; case tve_mode_composite_pal_nc:
writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
case tve_mode_composite_pal: writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |/* Fall through */
@@ -35,6 +33,10 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0); writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
if (mode == tve_mode_composite_pal)
writel(SUNXI_TVE_CHROMA_FREQ_PAL, &tve->chroma_freq);
else
writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num); writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num); writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL,writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
And patch 3 as well.
Thanks! Maxime
-- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com

On Sat, May 13, 2017 at 11:02 PM, icenowy@aosc.io wrote:
在 2017-05-13 00:06,Maxime Ripard 写道:
Hi Jernej,
The patch content looks fine, but there's a few things that would need to be addressed.
On Wed, May 10, 2017 at 06:46:30PM +0200, Jernej Skrabec wrote:
This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
7 files changed, 251 insertions(+), 17 deletions(-) create mode 100644 drivers/video/sunxi/sunxi_tve.c
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h index 6aa5e91ada..2419062d45 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h @@ -34,7 +34,9 @@ #define SUNXI_MS_BASE 0x01c07000 #define SUNXI_TVD_BASE 0x01c08000 #define SUNXI_CSI0_BASE 0x01c09000 +#ifndef CONFIG_MACH_SUNXI_H3_H5 #define SUNXI_TVE0_BASE 0x01c0a000 +#endif
This should be part of a seperate patch.
#define SUNXI_EMAC_BASE 0x01c0b000 #define SUNXI_LCD0_BASE 0x01c0C000 #define SUNXI_LCD1_BASE 0x01c0d000 @@ -161,10 +163,18 @@ defined(CONFIG_MACH_SUN50I) /* module sram */ #define SUNXI_SRAM_C_BASE 0x01d00000
+#ifndef CONFIG_MACH_SUN8I_H3 #define SUNXI_DE_FE0_BASE 0x01e00000 +#else +#define SUNXI_TVE0_BASE 0x01e00000 +#endif
This one should be in that other patch
#define SUNXI_DE_FE1_BASE 0x01e20000 #define SUNXI_DE_BE0_BASE 0x01e60000 +#ifndef CONFIG_MACH_SUN50I_H5 #define SUNXI_DE_BE1_BASE 0x01e40000 +#else +#define SUNXI_TVE0_BASE 0x01e40000 +#endif
And that one too.
#define SUNXI_MP_BASE 0x01e80000 #define SUNXI_AVG_BASE 0x01ea0000
diff --git a/arch/arm/include/asm/arch-sunxi/display2.h b/arch/arm/include/asm/arch-sunxi/display2.h index b5875f9605..359cacd90b 100644 --- a/arch/arm/include/asm/arch-sunxi/display2.h +++ b/arch/arm/include/asm/arch-sunxi/display2.h @@ -90,6 +90,23 @@ struct de_ui { u32 ovl_size; };
+struct de_csc {
u32 csc_ctl;
u8 res[0xc];
u32 coef11;
u32 coef12;
u32 coef13;
u32 coef14;
u32 coef21;
u32 coef22;
u32 coef23;
u32 coef24;
u32 coef31;
u32 coef32;
u32 coef33;
u32 coef34;
+};
This should be in another patch (let's call it patch 2)
/*
- DE register constants.
*/ diff --git a/arch/arm/include/asm/arch-sunxi/tve.h b/arch/arm/include/asm/arch-sunxi/tve.h index 41a14a68e4..ff34bbbc12 100644 --- a/arch/arm/include/asm/arch-sunxi/tve.h +++ b/arch/arm/include/asm/arch-sunxi/tve.h @@ -45,7 +45,9 @@ struct sunxi_tve_reg { u32 csc_reg1; /* 0x044 */ u32 csc_reg2; /* 0x048 */ u32 csc_reg3; /* 0x04c */
u8 res1[0xb0]; /* 0x050 */
u8 res1[0xa8]; /* 0x050 */
u32 auto_detect_cfg0; /* 0x0f8 */
u32 auto_detect_cfg1; /* 0x0fc */ u32 color_burst; /* 0x100 */ u32 vsync_num; /* 0x104 */ u32 notch_freq; /* 0x108 */
@@ -62,6 +64,10 @@ struct sunxi_tve_reg { u32 slave_para; /* 0x134 */ u32 cfg1; /* 0x138 */ u32 cfg2; /* 0x13c */
u8 res2[0x1c4]; /* 0x140 */
u32 calibration; /* 0x304 */
u8 res3[0x4]; /* 0x308 */
u32 unknown3; /* 0x30c */
And these yet another one (patch 3)
};
/* @@ -79,12 +85,14 @@ struct sunxi_tve_reg { #define SUNXI_TVE_CFG0_PAL 0x07030001 #define SUNXI_TVE_CFG0_NTSC 0x07030000 #define SUNXI_TVE_DAC_CFG0_VGA 0x403e1ac7 -#ifdef CONFIG_MACH_SUN5I +#if defined(CONFIG_MACH_SUN5I) || defined(CONFIG_MACH_SUNXI_H3_H5) #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x433f0009 #else #define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x403f0008 #endif +#define SUNXI_TVE_DAC_CFG0_DETECTION 0x433f0289 #define SUNXI_TVE_FILTER_COMPOSITE 0x00000120 +#define SUNXI_TVE_CHROMA_FREQ_PAL 0x2a098acb #define SUNXI_TVE_CHROMA_FREQ_PAL_M 0x21e6efe3 #define SUNXI_TVE_CHROMA_FREQ_PAL_NC 0x21f69446 #define SUNXI_TVE_PORCH_NUM_PAL 0x008a0018 @@ -105,6 +113,8 @@ struct sunxi_tve_reg { #define SUNXI_TVE_AUTO_DETECT_STATUS_SHORT_GND 3 #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(d) ((d) * 8) #define SUNXI_TVE_AUTO_DETECT_DEBOUNCE_MASK(d) (0xf << ((d) * 8)) +#define SUNXI_TVE_AUTO_DETECT_CFG0 0x00000280 +#define SUNXI_TVE_AUTO_DETECT_CFG1 0x028F00FF #define SUNXI_TVE_CSC_REG0_ENABLE (1 << 31) #define SUNXI_TVE_CSC_REG0 0x08440832 #define SUNXI_TVE_CSC_REG1 0x3b6dace1 @@ -124,6 +134,9 @@ struct sunxi_tve_reg { #define SUNXI_TVE_RESYNC_NUM_PAL 0x800d000c #define SUNXI_TVE_RESYNC_NUM_NTSC 0x000e000c #define SUNXI_TVE_SLAVE_PARA_COMPOSITE 0x00000000 +#define SUNXI_TVE_CALIBRATION_H3 0x02000c00 +#define SUNXI_TVE_CALIBRATION_H5 0x02850000 +#define SUNXI_TVE_UNKNOWN3_H5 0x00101110
patch 3
void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode); void tvencoder_enable(struct sunxi_tve_reg * const tve); diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index dbaab61b59..1db82c53f0 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -6,4 +6,4 @@ #
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o tve.o ../videomodes.o -obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o sunxi_tve.o tve.o lcdc.o ../dw_hdmi.o diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 9a32c3a020..ee67764ac5 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -56,7 +56,7 @@ static void sunxi_de2_composer_init(void) }
static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
int bpp, ulong address)
int bpp, ulong address, bool is_composite)
{ ulong de_mux_base = (mux == 0) ? SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE;
patch 2
@@ -72,6 +72,9 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, (struct de_ui *)(de_mux_base + SUNXI_DE2_MUX_CHAN_REGS + SUNXI_DE2_MUX_CHAN_SZ * 1);
struct de_csc * const de_csc_regs =
(struct de_csc *)(de_mux_base +
SUNXI_DE2_MUX_DCSC_REGS);
patch 2
u32 size = SUNXI_DE2_WH(mode->hactive.typ, mode->vactive.typ); int channel; u32 format;
@@ -128,7 +131,27 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, writel(0, de_mux_base + SUNXI_DE2_MUX_PEAK_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_ASE_REGS); writel(0, de_mux_base + SUNXI_DE2_MUX_FCC_REGS);
writel(0, de_mux_base + SUNXI_DE2_MUX_DCSC_REGS);
if (is_composite) {
/* set CSC coefficients */
writel(0x107, &de_csc_regs->coef11);
writel(0x204, &de_csc_regs->coef12);
writel(0x64, &de_csc_regs->coef13);
writel(0x4200, &de_csc_regs->coef14);
writel(0x1f68, &de_csc_regs->coef21);
writel(0x1ed6, &de_csc_regs->coef22);
writel(0x1c2, &de_csc_regs->coef23);
writel(0x20200, &de_csc_regs->coef24);
writel(0x1c2, &de_csc_regs->coef31);
writel(0x1e87, &de_csc_regs->coef32);
writel(0x1fb7, &de_csc_regs->coef33);
writel(0x20200, &de_csc_regs->coef34);
/* enable CSC unit */
writel(1, &de_csc_regs->csc_ctl);
} else {
writel(0, &de_csc_regs->csc_ctl);
}
patch 2
switch (bpp) { case 16:
@@ -153,7 +176,7 @@ static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
static int sunxi_de2_init(struct udevice *dev, ulong fbbase, enum video_log2_bpp l2bpp,
struct udevice *disp, int mux)
struct udevice *disp, int mux, bool
is_composite) { struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct display_timing timing; @@ -183,7 +206,7 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, }
sunxi_de2_composer_init();
sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase);
sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase,
is_composite);
ret = display_enable(disp, 1 << l2bpp, &timing); if (ret) {
@@ -204,7 +227,6 @@ static int sunxi_de2_probe(struct udevice *dev) struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); struct udevice *disp; int ret;
int mux; /* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC))
@@ -212,17 +234,31 @@ static int sunxi_de2_probe(struct udevice *dev)
ret = uclass_find_device_by_name(UCLASS_DISPLAY, "sunxi_dw_hdmi", &disp);
if (!ret) {
int mux;
if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
mux = 0;
else
mux = 1;
ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp,
mux,
false);
if (!ret) {
video_set_flush_dcache(dev, 1);
return 0;
}
}
debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
"sunxi_tve", &disp); if (ret) {
debug("%s: hdmi display not found (ret=%d)\n", __func__,
ret);
debug("%s: tv not found (ret=%d)\n", __func__, ret); return ret; }
if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
mux = 0;
else
mux = 1;
ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux);
ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1,
true);
patch 2
if (ret) return ret;
diff --git a/drivers/video/sunxi/sunxi_tve.c b/drivers/video/sunxi/sunxi_tve.c new file mode 100644 index 0000000000..95f54bbaf7 --- /dev/null +++ b/drivers/video/sunxi/sunxi_tve.c @@ -0,0 +1,156 @@ +/*
- Allwinner TVE driver
- (C) Copyright 2017 Jernej Skrabec jernej.skrabec@siol.net
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <display.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/lcdc.h> +#include <asm/arch/tve.h>
+static int sunxi_tve_get_plug_in_status(void) +{
struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
u32 status;
status = readl(&tve->auto_detect_status) &
SUNXI_TVE_AUTO_DETECT_STATUS_MASK(0);
return status == SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED;
So TVE is now capable of hpd checking, right?
Is is a feature that exists in A10/A13/A20 or is it new in H3?
AFAIK this is also available in the earlier SoCs. Maxime mentioned that it was unreliable though.
ChenYu
+}
+static int sunxi_tve_wait_for_hpd(void) +{
struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
ulong start;
/* enable auto detection */
writel(SUNXI_TVE_DAC_CFG0_DETECTION, &tve->dac_cfg0);
writel(SUNXI_TVE_AUTO_DETECT_CFG0, &tve->auto_detect_cfg0);
writel(SUNXI_TVE_AUTO_DETECT_CFG1, &tve->auto_detect_cfg1);
writel(9 << SUNXI_TVE_AUTO_DETECT_DEBOUNCE_SHIFT(0),
&tve->auto_detect_debounce);
writel(SUNXI_TVE_AUTO_DETECT_EN_DET_EN(0), &tve->auto_detect_en);
start = get_timer(0);
do {
if (sunxi_tve_get_plug_in_status())
return 0;
udelay(100);
} while (get_timer(start) < 300);
return -1;
+}
+static void sunxi_tve_lcdc_init(const struct display_timing *edid, int bpp) +{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD1_BASE;
/* Reset off */
setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD1);
/* Clock on */
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD1);
lcdc_init(lcdc);
lcdc_tcon1_mode_set(lcdc, edid, false, true);
lcdc_enable(lcdc, bpp);
+}
+static int sunxi_tve_read_timing(struct udevice *dev,
struct display_timing *timing)
+{
/* PAL resolution */
timing->pixelclock.typ = 27000000;
timing->hactive.typ = 720;
timing->hfront_porch.typ = 5;
timing->hback_porch.typ = 137;
timing->hsync_len.typ = 2;
timing->vactive.typ = 576;
timing->vfront_porch.typ = 27;
timing->vback_porch.typ = 20;
timing->vsync_len.typ = 2;
timing->flags = DISPLAY_FLAGS_INTERLACED;
return 0;
+}
+static int sunxi_tve_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
+{
struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
sunxi_tve_lcdc_init(edid, panel_bpp);
tvencoder_mode_set(tve, tve_mode_composite_pal);
tvencoder_enable(tve);
return 0;
+}
+static int sunxi_tve_probe(struct udevice *dev) +{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
int ret;
/* make sure that clock is active */
clock_set_pll10(432000000);
/* Reset off */
setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_TVE);
/* Clock on */
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE);
writel(CCM_TVE_CTRL_GATE | CCM_TVE_CTRL_M(2), &ccm->tve_clk_cfg);
+#ifdef CONFIG_MACH_SUN50I_H5
writel(SUNXI_TVE_CALIBRATION_H5, &tve->calibration);
writel(SUNXI_TVE_UNKNOWN3_H5, &tve->unknown3);
+#else
writel(SUNXI_TVE_CALIBRATION_H3, &tve->calibration);
+#endif
ret = sunxi_tve_wait_for_hpd();
if (ret < 0) {
debug("tve can not get hpd signal\n");
return -1;
}
return 0;
+}
+static const struct dm_display_ops sunxi_tve_ops = {
.read_timing = sunxi_tve_read_timing,
.enable = sunxi_tve_enable,
+};
+U_BOOT_DRIVER(sunxi_tve) = {
.name = "sunxi_tve",
.id = UCLASS_DISPLAY,
.ops = &sunxi_tve_ops,
.probe = sunxi_tve_probe,
+};
+#ifdef CONFIG_MACH_SUNXI_H3_H5 +U_BOOT_DEVICE(sunxi_tve) = {
.name = "sunxi_tve"
+}; +#endif
patch 3
diff --git a/drivers/video/sunxi/tve.c b/drivers/video/sunxi/tve.c index adea78a69a..ef99c111e3 100644 --- a/drivers/video/sunxi/tve.c +++ b/drivers/video/sunxi/tve.c @@ -25,8 +25,6 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1); break; case tve_mode_composite_pal_nc:
writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
/* Fall through */ case tve_mode_composite_pal: writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
@@ -35,6 +33,10 @@ void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode) writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0); writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
if (mode == tve_mode_composite_pal)
writel(SUNXI_TVE_CHROMA_FREQ_PAL,
&tve->chroma_freq);
else
writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC,
&tve->chroma_freq); writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num); writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num); writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL,
And patch 3 as well.
Thanks! Maxime
-- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
-- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout.

On Sat, May 13, 2017 at 11:14:00PM +0800, Chen-Yu Tsai wrote:
+static int sunxi_tve_get_plug_in_status(void) +{
struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
u32 status;
status = readl(&tve->auto_detect_status) &
SUNXI_TVE_AUTO_DETECT_STATUS_MASK(0);
return status == SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED;
So TVE is now capable of hpd checking, right?
Is is a feature that exists in A10/A13/A20 or is it new in H3?
AFAIK this is also available in the earlier SoCs. Maxime mentioned that it was unreliable though.
This was supposed to be there, but those registers were undocumented. It would be nice to try to see if it works.
Maxime

Hi,
Dne ponedeljek, 15. maj 2017 ob 08:31:22 CEST je Maxime Ripard napisal(a):
On Sat, May 13, 2017 at 11:14:00PM +0800, Chen-Yu Tsai wrote:
+static int sunxi_tve_get_plug_in_status(void) +{
struct sunxi_tve_reg * const tve =
(struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
u32 status;
status = readl(&tve->auto_detect_status) &
SUNXI_TVE_AUTO_DETECT_STATUS_MASK(0);
return status == SUNXI_TVE_AUTO_DETECT_STATUS_CONNECTED;
So TVE is now capable of hpd checking, right?
Is is a feature that exists in A10/A13/A20 or is it new in H3?
AFAIK this is also available in the earlier SoCs. Maxime mentioned that it was unreliable though.
This was supposed to be there, but those registers were undocumented. It would be nice to try to see if it works.
AFAIK, H3 and newer SoCs with TV out have two additional registers for hot plug detection. Here are named SUNXI_TVE_AUTO_DETECT_CFG0 and SUNXI_TVE_AUTO_DETECT_CFG1 and they are somewhat explained in R40 manual.
I'm not sure if this changes reliability a lot or not.
Best regards, Jernej

Hi,
On 12 May 2017 at 10:06, Maxime Ripard maxime.ripard@free-electrons.com wrote:
Hi Jernej,
The patch content looks fine, but there's a few things that would need to be addressed.
On Wed, May 10, 2017 at 06:46:30PM +0200, Jernej Skrabec wrote:
This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
That name is reserved for actual uclasses.
Regards, Simon

On Sun, May 14, 2017 at 09:03:19PM -0600, Simon Glass wrote:
Hi,
On 12 May 2017 at 10:06, Maxime Ripard maxime.ripard@free-electrons.com wrote:
Hi Jernej,
The patch content looks fine, but there's a few things that would need to be addressed.
On Wed, May 10, 2017 at 06:46:30PM +0200, Jernej Skrabec wrote:
This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
That name is reserved for actual uclasses.
Ok. How are the driver-part usually called?
Thanks, Maxime

Hi,
Dne ponedeljek, 15. maj 2017 ob 08:11:55 CEST je Maxime Ripard napisal(a):
On Sun, May 14, 2017 at 09:03:19PM -0600, Simon Glass wrote:
Hi,
On 12 May 2017 at 10:06, Maxime Ripard maxime.ripard@free-electrons.com
wrote:
Hi Jernej,
The patch content looks fine, but there's a few things that would need to be addressed.
On Wed, May 10, 2017 at 06:46:30PM +0200, Jernej Skrabec wrote:
This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
That name is reserved for actual uclasses.
Ok. How are the driver-part usually called?
I wanted to suggest that common part should be renamed to tve_common.c, but Anatolij already merged the patch.
Best regards, Jernej

Hi,
On Mon, 15 May 2017 21:47:57 +0200 Jernej Škrabec jernej.skrabec@siol.net wrote: ...
++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
That name is reserved for actual uclasses.
Ok. How are the driver-part usually called?
I wanted to suggest that common part should be renamed to tve_common.c, but Anatolij already merged the patch.
I'm ok with renaming it to tve_common.c. If no one has any objections, please send a renaming patch and base the rework of patch 3/3 on it. Thanks!
-- Anatolij

Hi Maxime,
On 15 May 2017 at 00:11, Maxime Ripard maxime.ripard@free-electrons.com wrote:
On Sun, May 14, 2017 at 09:03:19PM -0600, Simon Glass wrote:
Hi,
On 12 May 2017 at 10:06, Maxime Ripard maxime.ripard@free-electrons.com wrote:
Hi Jernej,
The patch content looks fine, but there's a few things that would need to be addressed.
On Wed, May 10, 2017 at 06:46:30PM +0200, Jernej Skrabec wrote:
This commit adds support for TV (composite) output.
Signed-off-by: Jernej Skrabec jernej.skrabec@siol.net
arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 10 ++ arch/arm/include/asm/arch-sunxi/display2.h | 17 +++ arch/arm/include/asm/arch-sunxi/tve.h | 17 ++- drivers/video/sunxi/Makefile | 2 +- drivers/video/sunxi/sunxi_de2.c | 60 ++++++++--- drivers/video/sunxi/sunxi_tve.c | 156 ++++++++++++++++++++++++++++ drivers/video/sunxi/tve.c | 6 +-
The difference between sunxi_tve and tve is not really obvious. What about calling sunxi_tve tve-uclass, or something like that?
That name is reserved for actual uclasses.
Ok. How are the driver-part usually called?
Well, something without the word 'uclass', and ideally using underscores instead of hyphens.
Regards, Simon
participants (7)
-
Anatolij Gustschin
-
Chen-Yu Tsai
-
icenowy@aosc.io
-
Jernej Skrabec
-
Jernej Škrabec
-
Maxime Ripard
-
Simon Glass