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 <[email protected]>
> ---
> 
>  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 <[email protected]>
> + *
> + * 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);
> -             /* 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

Attachment: signature.asc
Description: PGP signature

_______________________________________________
U-Boot mailing list
[email protected]
https://lists.denx.de/listinfo/u-boot

Reply via email to