
() aHi Nikhil,
On Mon, 23 Jan 2023 at 01:08, Nikhil M Jain n-jain1@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@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@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@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@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@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@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@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@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@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