[PATCH 3/6] drivers: video: tidss: TIDSS video driver support for AM62x

Simon Glass sjg at chromium.org
Mon Jan 23 19:42:37 CET 2023


() aHi Nikhil,

On Mon, 23 Jan 2023 at 01:08, Nikhil M Jain <n-jain1 at ti.com> wrote:
>
> Added tidss video driver support which enables display
> on oldi panel using AM62x, it creates a simple pipeline
> framebuffer==>vidl1==>ovr1==>vp1==>oldi_panel and
> calculates clock rates for panel from panel node in
> device tree.
>
> To compile TIDSS when user sets CONFIG_VIDEO_TIDSS
> add rule in Makefile. Include tidss folder location
> in Kconfig.
>
> TIDSS is ported from linux kernel version 5.10.145
>
> Signed-off-by: Nikhil M Jain <n-jain1 at ti.com>
> ---
>  MAINTAINERS                      |   1 +
>  drivers/video/Kconfig            |   2 +
>  drivers/video/Makefile           |   1 +
>  drivers/video/tidss/Kconfig      |  18 +
>  drivers/video/tidss/Makefile     |  12 +
>  drivers/video/tidss/tidss_drv.c  | 960 +++++++++++++++++++++++++++++++
>  drivers/video/tidss/tidss_drv.h  | 152 +++++
>  drivers/video/tidss/tidss_regs.h | 292 ++++++++++
>  8 files changed, 1438 insertions(+)
>  create mode 100644 drivers/video/tidss/Kconfig
>  create mode 100644 drivers/video/tidss/Makefile
>  create mode 100644 drivers/video/tidss/tidss_drv.c
>  create mode 100644 drivers/video/tidss/tidss_drv.h
>  create mode 100644 drivers/video/tidss/tidss_regs.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b2de50ccfc..a577f3a1a3 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -644,6 +644,7 @@ F:  drivers/soc/ti/
>  F:     drivers/sysreset/sysreset-ti-sci.c
>  F:     drivers/thermal/ti-bandgap.c
>  F:     drivers/timer/omap-timer.c
> +F:     drivers/video/tidss/
>  F:     drivers/watchdog/omap_wdt.c
>  F:     include/linux/pruss_driver.h
>  F:     include/linux/soc/ti/
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 440b161b84..40465ebea7 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -634,6 +634,8 @@ config VIDEO_SANDBOX_SDL
>
>  source "drivers/video/stm32/Kconfig"
>
> +source "drivers/video/tidss/Kconfig"
> +
>  config VIDEO_TEGRA20
>         bool "Enable LCD support on Tegra20"
>         depends on OF_CONTROL
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 40a871d638..4c14cc2663 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -26,6 +26,7 @@ obj-${CONFIG_EXYNOS_FB} += exynos/
>  obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
>  obj-${CONFIG_VIDEO_STM32} += stm32/
>  obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
> +obj-${CONFIG_VIDEO_TIDSS} += tidss/
>
>  obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
>  obj-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o
> diff --git a/drivers/video/tidss/Kconfig b/drivers/video/tidss/Kconfig
> new file mode 100644
> index 0000000000..2a5e56ea4e
> --- /dev/null
> +++ b/drivers/video/tidss/Kconfig
> @@ -0,0 +1,18 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# (C) Copyright 2023 Texas Instruments Incorporated - https://www.ti.com/
> +# Nikhil M Jain, n-jain1 at ti.com
> +#
> +# based on the linux tidss driver, which is
> +#
> +# (C) Copyright 2018 Texas Instruments Incorporated - https://www.ti.com/
> +# Author: Tomi Valkeinen <tomi.valkeinen at ti.com>
> +
> +menuconfig VIDEO_TIDSS
> +       bool "Enable TIDSS video support"
> +       depends on VIDEO
> +       help
> +         TIDSS supports  video output options LVDS and
> +         DPI . This option enables these supports which can be used on
> +         devices which have OLDI or HDMI display connected.
> +
> diff --git a/drivers/video/tidss/Makefile b/drivers/video/tidss/Makefile
> new file mode 100644
> index 0000000000..f4f8c6c470
> --- /dev/null
> +++ b/drivers/video/tidss/Makefile
> @@ -0,0 +1,12 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# (C) Copyright 2023 Texas Instruments Incorporated - https://www.ti.com/
> +# Nikhil M Jain, n-jain1 at ti.com
> +#
> +# based on the linux tidss driver, which is
> +#
> +# (C) Copyright 2018 Texas Instruments Incorporated - https://www.ti.com/
> +# Author: Tomi Valkeinen <tomi.valkeinen at ti.com>
> +
> +
> +obj-${CONFIG_VIDEO_TIDSS} = tidss_drv.o
> diff --git a/drivers/video/tidss/tidss_drv.c b/drivers/video/tidss/tidss_drv.c
> new file mode 100644
> index 0000000000..5caa438edd
> --- /dev/null
> +++ b/drivers/video/tidss/tidss_drv.c
> @@ -0,0 +1,960 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) Copyright 2023 Texas Instruments Incorporated - https://www.ti.com/
> + * Nikhil M Jain, n-jain1 at ti.com
> + *
> + * based on the linux tidss driver, which is
> + *
> + * (C) Copyright 2018 Texas Instruments Incorporated - https://www.ti.com/
> + * Author: Tomi Valkeinen <tomi.valkeinen at ti.com>
> + */
> +
> +#include <dm.h>
> +#include <clk.h>
> +#include <log.h>
> +#include <video.h>
> +#include <errno.h>
> +#include <panel.h>
> +#include <reset.h>
> +#include <malloc.h>
> +#include <fdtdec.h>
> +#include <common.h>
> +#include <syscon.h>
> +#include <regmap.h>
> +#include <linux/iopoll.h>
> +#include <cpu_func.h>
> +#include <media_bus_format.h>

Please sort those and put the linux one below

> +
> +#include <asm/io.h>
> +#include <asm/cache.h>
> +#include <asm/utils.h>
> +#include <asm/bitops.h>
> +
> +#include <linux/bug.h>
> +
> +#include <dm/devres.h>
> +#include <dm/of_access.h>
> +#include <dm/device_compat.h>
> +#include <dm/device-internal.h>
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +
> +#include "tidss_drv.h"
> +#include "tidss_regs.h"
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/* Panel parameters */
> +enum {
> +       LCD_MAX_WIDTH           = 1920,
> +       LCD_MAX_HEIGHT          = 1200,
> +       LCD_MAX_LOG2_BPP        = VIDEO_BPP32,
> +};
> +
> +static const u16 *dss_common_regmap;
> +
> +static const u16 tidss_am62x_common_regs[DSS_COMMON_REG_TABLE_LEN] = {
> +       [DSS_REVISION_OFF] =                    0x4,
> +       [DSS_SYSCONFIG_OFF] =                   0x8,
> +       [DSS_SYSSTATUS_OFF] =                   0x20,
> +       [DSS_IRQ_EOI_OFF] =                     0x24,
> +       [DSS_IRQSTATUS_RAW_OFF] =               0x28,
> +       [DSS_IRQSTATUS_OFF] =                   0x2c,
> +       [DSS_IRQENABLE_SET_OFF] =               0x30,
> +       [DSS_IRQENABLE_CLR_OFF] =               0x40,
> +       [DSS_VID_IRQENABLE_OFF] =               0x44,
> +       [DSS_VID_IRQSTATUS_OFF] =               0x58,
> +       [DSS_VP_IRQENABLE_OFF] =                0x70,
> +       [DSS_VP_IRQSTATUS_OFF] =                0x7c,
> +
> +       [WB_IRQENABLE_OFF] =                    0x88,
> +       [WB_IRQSTATUS_OFF] =                    0x8c,
> +
> +       [DSS_GLOBAL_MFLAG_ATTRIBUTE_OFF] =      0x90,
> +       [DSS_GLOBAL_OUTPUT_ENABLE_OFF] =        0x94,
> +       [DSS_GLOBAL_BUFFER_OFF] =               0x98,
> +       [DSS_CBA_CFG_OFF] =                     0x9c,
> +       [DSS_DBG_CONTROL_OFF] =         0xa0,
> +       [DSS_DBG_STATUS_OFF] =          0xa4,
> +       [DSS_CLKGATING_DISABLE_OFF] =           0xa8,
> +       [DSS_SECURE_DISABLE_OFF] =              0xac,
> +};
> +
[..]

> +static u32 FLD_MASK(u32 start, u32 end)
> +{
> +       return ((1 << (start - end + 1)) - 1) << end;
> +}

Is this like GENMASK etc.? Please use lower case for function names
and add comments as to what on earth these do :-)

> +
> +static u32 FLD_VAL(u32 val, u32 start, u32 end)
> +{
> +       return (val << end) & FLD_MASK(start, end);
> +}
> +
> +static u32 FLD_GET(u32 val, u32 start, u32 end)
> +{
> +       return (val & FLD_MASK(start, end)) >> end;
> +}
> +
> +static u32 FLD_MOD(u32 orig, u32 val, u32 start, u32 end)
> +{
> +       return (orig & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end);
> +}
> +
> +__maybe_unused
> +static u32 REG_GET(struct tidss_drv_priv *priv, u32 idx, u32 start, u32 end)
> +{
> +       return FLD_GET(dss_read(priv, idx), start, end);
> +}
> +
> +static void REG_FLD_MOD(struct tidss_drv_priv *priv, u32 idx, u32 val,
> +                       u32 start, u32 end)
> +{
> +       dss_write(priv, idx, FLD_MOD(dss_read(priv, idx), val,
> +                                    start, end));
> +}
> +
> +static u32 VID_REG_GET(struct tidss_drv_priv *priv, u32 hw_plane, u32 idx,
> +                      u32 start, u32 end)
> +{
> +       return FLD_GET(dss_vid_read(priv, hw_plane, idx), start, end);
> +}
> +
> +static void VID_REG_FLD_MOD(struct tidss_drv_priv *priv, u32 hw_plane, u32 idx,
> +                           u32 val, u32 start, u32 end)
> +{
> +       dss_vid_write(priv, hw_plane, idx,
> +                     FLD_MOD(dss_vid_read(priv, hw_plane, idx),
> +                             val, start, end));
> +}
> +
> +__maybe_unused
> +static u32 VP_REG_GET(struct tidss_drv_priv *priv, u32 vp, u32 idx,
> +                     u32 start, u32 end)
> +{
> +       return FLD_GET(dss_vp_read(priv, vp, idx), start, end);
> +}
> +
> +static void VP_REG_FLD_MOD(struct tidss_drv_priv *priv, u32 vp, u32 idx, u32 val,
> +                          u32 start, u32 end)
> +{
> +       dss_vp_write(priv, vp, idx, FLD_MOD(dss_vp_read(priv, vp, idx),
> +                                           val, start, end));
> +}
> +
> +__maybe_unused
> +static u32 OVR_REG_GET(struct tidss_drv_priv *priv, u32 ovr, u32 idx,
> +                      u32 start, u32 end)
> +{
> +       return FLD_GET(dss_ovr_read(priv, ovr, idx), start, end);
> +}
> +
> +static void OVR_REG_FLD_MOD(struct tidss_drv_priv *priv, u32 ovr, u32 idx,
> +                           u32 val, u32 start, u32 end)

Why all the u32? You should be able to use natural types like uint

> +{
> +       dss_ovr_write(priv, ovr, idx, FLD_MOD(dss_ovr_read(priv, ovr, idx),
> +                                             val, start, end));
> +}
> +

[..]

> +
> +int tidss_drv_init(struct tidss_drv_priv *priv)

Should not export functions. What is this for?

> +{
> +       dss_plane_init(priv);
> +       dss_vp_init(priv);
> +       return 0;
> +}
> +
> +static int tidss_drv_probe(struct udevice *dev)
> +{
> +       struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
> +       struct video_priv *uc_priv = dev_get_uclass_priv(dev);
> +       struct tidss_drv_priv *priv = dev_get_priv(dev);
> +       struct udevice *panel = NULL;
> +       struct display_timing timings;
> +       unsigned int i;
> +       int ret = 0;
> +       const char *mode;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;

It is already allocated by driver model - see dev_get_priv() above.

> +
> +       priv->dev = dev;
> +
> +       priv->feat = &dss_am625_feats;
> +
> +    /*
> +     * set your plane format based on your bmp image
> +     * Supported 24bpp and 32bpp bmpimages
> +     */
> +
> +       priv->pixel_format = DSS_FORMAT_XRGB8888;
> +

[..]

> +static int tidss_ofdata_to_platdata(struct udevice *dev)
> +{
> +       ofnode node;
> +
> +       node = ofnode_by_compatible(ofnode_null(), "ti,am625-dss");

What is going on here? Drivers should be discovered by having a
driver. Please drop this code.

> +
> +       if (!ofnode_valid(node)) {
> +               dev_err(dev, "missing 'ti,am625-dss' node\n");
> +               return -ENXIO;
> +       }
> +
> +       return 0;
> +}
> +
> +U_BOOT_DRIVER(tidss_drv) = {
> +       .name = "tidss_drv",
> +       .id = UCLASS_VIDEO,
> +       .of_match = tidss_drv_ids,
> +       .bind = tidss_drv_bind,
> +       .of_to_plat = tidss_ofdata_to_platdata,
> +       .probe = tidss_drv_probe,
> +       .remove = tidss_drv_remove,
> +       .priv_auto = sizeof(struct tidss_drv_priv),
> +       .flags = DM_FLAG_OS_PREPARE,
> +};
> diff --git a/drivers/video/tidss/tidss_drv.h b/drivers/video/tidss/tidss_drv.h
> new file mode 100644
> index 0000000000..669c6d642e
> --- /dev/null
> +++ b/drivers/video/tidss/tidss_drv.h
> @@ -0,0 +1,152 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) Copyright 2023 Texas Instruments Incorporated - https://www.ti.com/
> + * Nikhil M Jain, n-jain1 at ti.com
> + *
> + * based on the linux tidss driver, which is
> + *
> + * (C) Copyright 2018 Texas Instruments Incorporated - https://www.ti.com/
> + * Author: Tomi Valkeinen <tomi.valkeinen at ti.com>
> + */
> +
> +#ifndef __TIDSS_DRV_H__
> +#define __TIDSS_DRV_H__
> +
> +#include <media_bus_format.h>
> +
> +#define TIDSS_MAX_PORTS 4
> +#define TIDSS_MAX_PLANES 4
> +
> +enum dss_vp_bus_type {
> +       DSS_VP_DPI,             /* DPI output */
> +       DSS_VP_OLDI,            /* OLDI (LVDS) output */
> +       DSS_VP_INTERNAL,        /* SoC internal routing */
> +       DSS_VP_MAX_BUS_TYPE,
> +};
> +
> +enum dss_oldi_modes {
> +       OLDI_MODE_OFF,                          /* OLDI turned off / tied off in IP. */
> +       OLDI_SINGLE_LINK_SINGLE_MODE,           /* Single Output over OLDI 0. */
> +       OLDI_SINGLE_LINK_DUPLICATE_MODE,        /* Duplicate Output over OLDI 0 and 1. */
> +       OLDI_DUAL_LINK,                         /* Combined Output over OLDI 0 and 1. */
> +};
> +
> +struct dss_features_scaling {
> +       u32 in_width_max_5tap_rgb;
> +       u32 in_width_max_3tap_rgb;
> +       u32 in_width_max_5tap_yuv;
> +       u32 in_width_max_3tap_yuv;
> +       u32 upscale_limit;
> +       u32 downscale_limit_5tap;
> +       u32 downscale_limit_3tap;
> +       u32 xinc_max;
> +};
> +
> +enum tidss_gamma_type { TIDSS_GAMMA_8BIT, TIDSS_GAMMA_10BIT };
> +
> +enum dss_subrevision {
> +       DSS_K2G,
> +       DSS_AM65X,
> +       DSS_J721E,
> +       DSS_AM625,
> +};
> +
> +struct tidss_vp_feat {
> +       struct tidss_vp_color_feat {
> +               u32 gamma_size;
> +               enum tidss_gamma_type gamma_type;
> +               bool has_ctm;
> +       } color;
> +};
> +
> +struct tidss_scale_coefs {
> +       s16 c2[16];
> +       s16 c1[16];
> +       u16 c0[9];
> +};
> +
> +struct dss_color_lut {
> +       /*
> +        * Data is U0.16 fixed point format.
> +        */
> +       __u16 red;
> +       __u16 green;
> +       __u16 blue;
> +       __u16 reserved;
> +};
> +
> +struct dss_vp_data {
> +       u32 *gamma_table;
> +};
> +
> +struct dss_features {
> +       int min_pclk_khz;
> +       int max_pclk_khz[DSS_VP_MAX_BUS_TYPE];
> +
> +       struct dss_features_scaling scaling;
> +
> +       enum dss_subrevision subrev;
> +
> +       const char *common;
> +       const u16 *common_regs;
> +       u32 num_vps;
> +       const char *vp_name[TIDSS_MAX_PORTS]; /* Should match dt reg names */
> +       const char *ovr_name[TIDSS_MAX_PORTS]; /* Should match dt reg names */
> +       const char *vpclk_name[TIDSS_MAX_PORTS]; /* Should match dt clk names */
> +       const enum dss_vp_bus_type vp_bus_type[TIDSS_MAX_PORTS];
> +       struct tidss_vp_feat vp_feat;
> +       u32 num_planes;
> +       const char *vid_name[TIDSS_MAX_PLANES]; /* Should match dt reg names */
> +       bool vid_lite[TIDSS_MAX_PLANES];
> +       u32 vid_order[TIDSS_MAX_PLANES];
> +};
> +
> +enum dss_oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 };
> +
> +struct dss_bus_format {
> +       u32 bus_fmt;
> +       u32 data_width;
> +       bool is_oldi_fmt;
> +       enum dss_oldi_mode_reg_val oldi_mode_reg_val;
> +};
> +
> +static struct dss_bus_format dss_bus_formats[] = {
> +       { MEDIA_BUS_FMT_RGB444_1X12,            12, false, 0 },
> +       { MEDIA_BUS_FMT_RGB565_1X16,            16, false, 0 },
> +       { MEDIA_BUS_FMT_RGB666_1X18,            18, false, 0 },
> +       { MEDIA_BUS_FMT_RGB888_1X24,            24, false, 0 },
> +       { MEDIA_BUS_FMT_RGB101010_1X30,         30, false, 0 },
> +       { MEDIA_BUS_FMT_RGB121212_1X36,         36, false, 0 },
> +       { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,      18, true, SPWG_18 },
> +       { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,      24, true, SPWG_24 },
> +       { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,     24, true, JEIDA_24 },
> +};
> +
> +struct tidss_drv_priv {
> +       struct udevice *dev;
> +       void __iomem *base_common;
> +       void __iomem *base_vid[TIDSS_MAX_PLANES];
> +       void __iomem *base_ovr[TIDSS_MAX_PORTS];
> +       void __iomem *base_vp[TIDSS_MAX_PORTS];
> +       struct regmap *oldi_io_ctrl;
> +
> +       struct clk vp_clk[TIDSS_MAX_PORTS];
> +
> +       const struct dss_features *feat;
> +
> +       struct clk fclk;
> +
> +       bool is_enabled;
> +
> +       struct dss_vp_data vp_data[TIDSS_MAX_PORTS];
> +
> +       enum dss_oldi_modes oldi_mode;
> +
> +       struct dss_bus_format *bus_format;
> +
> +       u32 pixel_format;
> +
> +       u32 memory_bandwidth_limit;
> +};

Please comment this structure and drop the extra blank lines. This is
not Linux :-)

> +
> +#endif


More information about the U-Boot mailing list