[PATCH v5 12/17] drm/meson: add support for MIPI-DSI transceiver
Nicolas Belin
nbelin at baylibre.com
Wed May 31 02:22:42 PDT 2023
Le mar. 30 mai 2023 à 09:38, Neil Armstrong
<neil.armstrong at linaro.org> a écrit :
>
> The Amlogic G12A/G12B/SM1 SoCs embeds a Synopsys DW-MIPI-DSI transceiver
> (ver 1.21a), with a custom glue managing the IP resets, clock and data
> inputs similar to the DW-HDMI Glue on other Amlogic SoCs.
>
> This adds support for the Glue managing the transceiver, mimicing the init
> flow provided by Amlogic to setup the ENCL encoder, the glue, the transceiver,
> the digital D-PHY and the Analog PHY in the proper way.
>
> An optional "MEAS" clock can be enabled to measure the delay between each
> vsync feeding the DW-MIPI-DSI transceiver.
>
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> Reviewed-by: Jagan Teki <jagan at amarulasolutions.com>
> Signed-off-by: Neil Armstrong <neil.armstrong at linaro.org>
> ---
> drivers/gpu/drm/meson/Kconfig | 7 +
> drivers/gpu/drm/meson/Makefile | 1 +
> drivers/gpu/drm/meson/meson_dw_mipi_dsi.c | 352 ++++++++++++++++++++++++++++++
> drivers/gpu/drm/meson/meson_dw_mipi_dsi.h | 160 ++++++++++++++
> 4 files changed, 520 insertions(+)
>
> diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
> index 823909da87db..615fdd0ce41b 100644
> --- a/drivers/gpu/drm/meson/Kconfig
> +++ b/drivers/gpu/drm/meson/Kconfig
> @@ -17,3 +17,10 @@ config DRM_MESON_DW_HDMI
> default y if DRM_MESON
> select DRM_DW_HDMI
> imply DRM_DW_HDMI_I2S_AUDIO
> +
> +config DRM_MESON_DW_MIPI_DSI
> + tristate "MIPI DSI Synopsys Controller support for Amlogic Meson Display"
> + depends on DRM_MESON
> + default y if DRM_MESON
> + select DRM_DW_MIPI_DSI
> + select GENERIC_PHY_MIPI_DPHY
> diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
> index 833e18c20603..43071bdbd4b9 100644
> --- a/drivers/gpu/drm/meson/Makefile
> +++ b/drivers/gpu/drm/meson/Makefile
> @@ -6,3 +6,4 @@ meson-drm-y += meson_encoder_hdmi.o meson_encoder_dsi.o
>
> obj-$(CONFIG_DRM_MESON) += meson-drm.o
> obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
> +obj-$(CONFIG_DRM_MESON_DW_MIPI_DSI) += meson_dw_mipi_dsi.o
> diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c
> new file mode 100644
> index 000000000000..dd505ac37976
> --- /dev/null
> +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c
> @@ -0,0 +1,352 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2021 BayLibre, SAS
> + * Author: Neil Armstrong <narmstrong at baylibre.com>
> + * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/reset.h>
> +#include <linux/phy/phy.h>
> +#include <linux/bitfield.h>
> +
> +#include <video/mipi_display.h>
> +
> +#include <drm/bridge/dw_mipi_dsi.h>
> +#include <drm/drm_mipi_dsi.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_print.h>
> +
> +#include "meson_drv.h"
> +#include "meson_dw_mipi_dsi.h"
> +#include "meson_registers.h"
> +#include "meson_venc.h"
> +
> +#define DRIVER_NAME "meson-dw-mipi-dsi"
> +#define DRIVER_DESC "Amlogic Meson MIPI-DSI DRM driver"
> +
> +struct meson_dw_mipi_dsi {
> + struct meson_drm *priv;
> + struct device *dev;
> + void __iomem *base;
> + struct phy *phy;
> + union phy_configure_opts phy_opts;
> + struct dw_mipi_dsi *dmd;
> + struct dw_mipi_dsi_plat_data pdata;
> + struct mipi_dsi_device *dsi_device;
> + const struct drm_display_mode *mode;
> + struct clk *bit_clk;
> + struct clk *px_clk;
> + struct reset_control *top_rst;
> +};
> +
> +#define encoder_to_meson_dw_mipi_dsi(x) \
> + container_of(x, struct meson_dw_mipi_dsi, encoder)
> +
> +static void meson_dw_mipi_dsi_hw_init(struct meson_dw_mipi_dsi *mipi_dsi)
> +{
> + /* Software reset */
> + writel_bits_relaxed(MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR |
> + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING,
> + MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR |
> + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING,
> + mipi_dsi->base + MIPI_DSI_TOP_SW_RESET);
> + writel_bits_relaxed(MIPI_DSI_TOP_SW_RESET_DWC | MIPI_DSI_TOP_SW_RESET_INTR |
> + MIPI_DSI_TOP_SW_RESET_DPI | MIPI_DSI_TOP_SW_RESET_TIMING,
> + 0, mipi_dsi->base + MIPI_DSI_TOP_SW_RESET);
> +
> + /* Enable clocks */
> + writel_bits_relaxed(MIPI_DSI_TOP_CLK_SYSCLK_EN | MIPI_DSI_TOP_CLK_PIXCLK_EN,
> + MIPI_DSI_TOP_CLK_SYSCLK_EN | MIPI_DSI_TOP_CLK_PIXCLK_EN,
> + mipi_dsi->base + MIPI_DSI_TOP_CLK_CNTL);
> +
> + /* Take memory out of power down */
> + writel_relaxed(0, mipi_dsi->base + MIPI_DSI_TOP_MEM_PD);
> +}
> +
> +static int dw_mipi_dsi_phy_init(void *priv_data)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = priv_data;
> + unsigned int dpi_data_format, venc_data_width;
> + int ret;
> +
> + /* Set the bit clock rate to hs_clk_rate */
> + ret = clk_set_rate(mipi_dsi->bit_clk,
> + mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate);
> + if (ret) {
> + dev_err(mipi_dsi->dev, "Failed to set DSI Bit clock rate %lu (ret %d)\n",
> + mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate, ret);
> + return ret;
> + }
> +
> + /* Make sure the rate of the bit clock is not modified by someone else */
> + ret = clk_rate_exclusive_get(mipi_dsi->bit_clk);
> + if (ret) {
> + dev_err(mipi_dsi->dev,
> + "Failed to set the exclusivity on the bit clock rate (ret %d)\n", ret);
> + return ret;
> + }
> +
> + ret = clk_set_rate(mipi_dsi->px_clk, mipi_dsi->mode->clock * 1000);
> +
> + if (ret) {
> + dev_err(mipi_dsi->dev, "Failed to set DSI Pixel clock rate %u (%d)\n",
> + mipi_dsi->mode->clock * 1000, ret);
> + return ret;
> + }
> +
> + switch (mipi_dsi->dsi_device->format) {
> + case MIPI_DSI_FMT_RGB888:
> + dpi_data_format = DPI_COLOR_24BIT;
> + venc_data_width = VENC_IN_COLOR_24B;
> + break;
> + case MIPI_DSI_FMT_RGB666:
> + dpi_data_format = DPI_COLOR_18BIT_CFG_2;
> + venc_data_width = VENC_IN_COLOR_18B;
> + break;
> + case MIPI_DSI_FMT_RGB666_PACKED:
> + case MIPI_DSI_FMT_RGB565:
> + return -EINVAL;
> + };
> +
> + /* Configure color format for DPI register */
> + writel_relaxed(FIELD_PREP(MIPI_DSI_TOP_DPI_COLOR_MODE, dpi_data_format) |
> + FIELD_PREP(MIPI_DSI_TOP_IN_COLOR_MODE, venc_data_width) |
> + FIELD_PREP(MIPI_DSI_TOP_COMP2_SEL, 2) |
> + FIELD_PREP(MIPI_DSI_TOP_COMP1_SEL, 1) |
> + FIELD_PREP(MIPI_DSI_TOP_COMP0_SEL, 0),
> + mipi_dsi->base + MIPI_DSI_TOP_CNTL);
> +
> + return phy_configure(mipi_dsi->phy, &mipi_dsi->phy_opts);
> +}
> +
> +static void dw_mipi_dsi_phy_power_on(void *priv_data)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = priv_data;
> +
> + if (phy_power_on(mipi_dsi->phy))
> + dev_warn(mipi_dsi->dev, "Failed to power on PHY\n");
> +}
> +
> +static void dw_mipi_dsi_phy_power_off(void *priv_data)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = priv_data;
> +
> + if (phy_power_off(mipi_dsi->phy))
> + dev_warn(mipi_dsi->dev, "Failed to power off PHY\n");
> +
> + /* Remove the exclusivity on the bit clock rate */
> + clk_rate_exclusive_put(mipi_dsi->bit_clk);
> +}
> +
> +static int
> +dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
> + unsigned long mode_flags, u32 lanes, u32 format,
> + unsigned int *lane_mbps)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = priv_data;
> + int bpp;
> +
> + mipi_dsi->mode = mode;
> +
> + bpp = mipi_dsi_pixel_format_to_bpp(mipi_dsi->dsi_device->format);
> +
> + phy_mipi_dphy_get_default_config(mode->clock * 1000,
> + bpp, mipi_dsi->dsi_device->lanes,
> + &mipi_dsi->phy_opts.mipi_dphy);
> +
> + *lane_mbps = DIV_ROUND_UP(mipi_dsi->phy_opts.mipi_dphy.hs_clk_rate, USEC_PER_SEC);
> +
> + return 0;
> +}
> +
> +static int
> +dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
> + struct dw_mipi_dsi_dphy_timing *timing)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = priv_data;
> +
> + switch (mipi_dsi->mode->hdisplay) {
> + case 240:
> + case 768:
> + case 1920:
> + case 2560:
> + timing->clk_lp2hs = 23;
> + timing->clk_hs2lp = 38;
> + timing->data_lp2hs = 15;
> + timing->data_hs2lp = 9;
> + break;
> +
> + default:
> + timing->clk_lp2hs = 37;
> + timing->clk_hs2lp = 135;
> + timing->data_lp2hs = 50;
> + timing->data_hs2lp = 3;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +dw_mipi_dsi_get_esc_clk_rate(void *priv_data, unsigned int *esc_clk_rate)
> +{
> + *esc_clk_rate = 4; /* Mhz */
> +
> + return 0;
> +}
> +
> +static const struct dw_mipi_dsi_phy_ops meson_dw_mipi_dsi_phy_ops = {
> + .init = dw_mipi_dsi_phy_init,
> + .power_on = dw_mipi_dsi_phy_power_on,
> + .power_off = dw_mipi_dsi_phy_power_off,
> + .get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
> + .get_timing = dw_mipi_dsi_phy_get_timing,
> + .get_esc_clk_rate = dw_mipi_dsi_get_esc_clk_rate,
> +};
> +
> +static int meson_dw_mipi_dsi_host_attach(void *priv_data,
> + struct mipi_dsi_device *device)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = priv_data;
> + int ret;
> +
> + mipi_dsi->dsi_device = device;
> +
> + switch (device->format) {
> + case MIPI_DSI_FMT_RGB888:
> + break;
> + case MIPI_DSI_FMT_RGB666:
> + break;
> + case MIPI_DSI_FMT_RGB666_PACKED:
> + case MIPI_DSI_FMT_RGB565:
> + dev_err(mipi_dsi->dev, "invalid pixel format %d\n", device->format);
> + return -EINVAL;
> + };
> +
> + ret = phy_init(mipi_dsi->phy);
> + if (ret)
> + return ret;
> +
> + meson_dw_mipi_dsi_hw_init(mipi_dsi);
> +
> + return 0;
> +}
> +
> +static int meson_dw_mipi_dsi_host_detach(void *priv_data,
> + struct mipi_dsi_device *device)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = priv_data;
> +
> + if (device == mipi_dsi->dsi_device)
> + mipi_dsi->dsi_device = NULL;
> + else
> + return -EINVAL;
> +
> + return phy_exit(mipi_dsi->phy);
> +}
> +
> +static const struct dw_mipi_dsi_host_ops meson_dw_mipi_dsi_host_ops = {
> + .attach = meson_dw_mipi_dsi_host_attach,
> + .detach = meson_dw_mipi_dsi_host_detach,
> +};
> +
> +static int meson_dw_mipi_dsi_probe(struct platform_device *pdev)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi;
> + struct device *dev = &pdev->dev;
> +
> + mipi_dsi = devm_kzalloc(dev, sizeof(*mipi_dsi), GFP_KERNEL);
> + if (!mipi_dsi)
> + return -ENOMEM;
> +
> + mipi_dsi->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(mipi_dsi->base))
> + return PTR_ERR(mipi_dsi->base);
> +
> + mipi_dsi->phy = devm_phy_get(dev, "dphy");
> + if (IS_ERR(mipi_dsi->phy))
> + return dev_err_probe(dev, PTR_ERR(mipi_dsi->phy),
> + "failed to get mipi dphy\n");
> +
> + mipi_dsi->bit_clk = devm_clk_get_enabled(dev, "bit");
> + if (IS_ERR(mipi_dsi->bit_clk)) {
> + int ret = PTR_ERR(mipi_dsi->bit_clk);
> +
> + /* TOFIX GP0 on some platforms fails to lock in early boot, defer probe */
> + if (ret == -EIO)
> + ret = -EPROBE_DEFER;
> +
> + return dev_err_probe(dev, ret, "Unable to get enabled bit_clk\n");
> + }
> +
> + mipi_dsi->px_clk = devm_clk_get_enabled(dev, "px");
> + if (IS_ERR(mipi_dsi->px_clk))
> + return dev_err_probe(dev, PTR_ERR(mipi_dsi->px_clk),
> + "Unable to get enabled px_clk\n");
> +
> + /*
> + * We use a TOP reset signal because the APB reset signal
> + * is handled by the TOP control registers.
> + */
> + mipi_dsi->top_rst = devm_reset_control_get_exclusive(dev, "top");
> + if (IS_ERR(mipi_dsi->top_rst))
> + return dev_err_probe(dev, PTR_ERR(mipi_dsi->top_rst),
> + "Unable to get reset control\n");
> +
> + reset_control_assert(mipi_dsi->top_rst);
> + usleep_range(10, 20);
> + reset_control_deassert(mipi_dsi->top_rst);
> +
> + /* MIPI DSI Controller */
> +
> + mipi_dsi->dev = dev;
> + mipi_dsi->pdata.base = mipi_dsi->base;
> + mipi_dsi->pdata.max_data_lanes = 4;
> + mipi_dsi->pdata.phy_ops = &meson_dw_mipi_dsi_phy_ops;
> + mipi_dsi->pdata.host_ops = &meson_dw_mipi_dsi_host_ops;
> + mipi_dsi->pdata.priv_data = mipi_dsi;
> + platform_set_drvdata(pdev, mipi_dsi);
> +
> + mipi_dsi->dmd = dw_mipi_dsi_probe(pdev, &mipi_dsi->pdata);
> + if (IS_ERR(mipi_dsi->dmd))
> + return dev_err_probe(dev, PTR_ERR(mipi_dsi->dmd),
> + "Failed to probe dw_mipi_dsi\n");
> +
> + return 0;
> +}
> +
> +static int meson_dw_mipi_dsi_remove(struct platform_device *pdev)
> +{
> + struct meson_dw_mipi_dsi *mipi_dsi = platform_get_drvdata(pdev);
> +
> + dw_mipi_dsi_remove(mipi_dsi->dmd);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id meson_dw_mipi_dsi_of_table[] = {
> + { .compatible = "amlogic,meson-g12a-dw-mipi-dsi", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, meson_dw_mipi_dsi_of_table);
> +
> +static struct platform_driver meson_dw_mipi_dsi_platform_driver = {
> + .probe = meson_dw_mipi_dsi_probe,
> + .remove = meson_dw_mipi_dsi_remove,
> + .driver = {
> + .name = DRIVER_NAME,
> + .of_match_table = meson_dw_mipi_dsi_of_table,
> + },
> +};
> +module_platform_driver(meson_dw_mipi_dsi_platform_driver);
> +
> +MODULE_AUTHOR("Neil Armstrong <narmstrong at baylibre.com>");
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.h b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.h
> new file mode 100644
> index 000000000000..e1bd6b85d6a3
> --- /dev/null
> +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.h
> @@ -0,0 +1,160 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2020 BayLibre, SAS
> + * Author: Neil Armstrong <narmstrong at baylibre.com>
> + * Copyright (C) 2018 Amlogic, Inc. All rights reserved.
> + */
> +
> +#ifndef __MESON_DW_MIPI_DSI_H
> +#define __MESON_DW_MIPI_DSI_H
> +
> +/* Top-level registers */
> +/* [31: 4] Reserved. Default 0.
> + * [3] RW timing_rst_n: Default 1.
> + * 1=Assert SW reset of timing feature. 0=Release reset.
> + * [2] RW dpi_rst_n: Default 1.
> + * 1=Assert SW reset on mipi_dsi_host_dpi block. 0=Release reset.
> + * [1] RW intr_rst_n: Default 1.
> + * 1=Assert SW reset on mipi_dsi_host_intr block. 0=Release reset.
> + * [0] RW dwc_rst_n: Default 1.
> + * 1=Assert SW reset on IP core. 0=Release reset.
> + */
> +#define MIPI_DSI_TOP_SW_RESET 0x3c0
> +
> +#define MIPI_DSI_TOP_SW_RESET_DWC BIT(0)
> +#define MIPI_DSI_TOP_SW_RESET_INTR BIT(1)
> +#define MIPI_DSI_TOP_SW_RESET_DPI BIT(2)
> +#define MIPI_DSI_TOP_SW_RESET_TIMING BIT(3)
> +
> +/* [31: 5] Reserved. Default 0.
> + * [4] RW manual_edpihalt: Default 0.
> + * 1=Manual suspend VencL; 0=do not suspend VencL.
> + * [3] RW auto_edpihalt_en: Default 0.
> + * 1=Enable IP's edpihalt signal to suspend VencL;
> + * 0=IP's edpihalt signal does not affect VencL.
> + * [2] RW clock_freerun: Apply to auto-clock gate only. Default 0.
> + * 0=Default, use auto-clock gating to save power;
> + * 1=use free-run clock, disable auto-clock gating, for debug mode.
> + * [1] RW enable_pixclk: A manual clock gate option, due to DWC IP does not
> + * have auto-clock gating. 1=Enable pixclk. Default 0.
> + * [0] RW enable_sysclk: A manual clock gate option, due to DWC IP does not
> + * have auto-clock gating. 1=Enable sysclk. Default 0.
> + */
> +#define MIPI_DSI_TOP_CLK_CNTL 0x3c4
> +
> +#define MIPI_DSI_TOP_CLK_SYSCLK_EN BIT(0)
> +#define MIPI_DSI_TOP_CLK_PIXCLK_EN BIT(1)
> +
> +/* [31:24] Reserved. Default 0.
> + * [23:20] RW dpi_color_mode: Define DPI pixel format. Default 0.
> + * 0=16-bit RGB565 config 1;
> + * 1=16-bit RGB565 config 2;
> + * 2=16-bit RGB565 config 3;
> + * 3=18-bit RGB666 config 1;
> + * 4=18-bit RGB666 config 2;
> + * 5=24-bit RGB888;
> + * 6=20-bit YCbCr 4:2:2;
> + * 7=24-bit YCbCr 4:2:2;
> + * 8=16-bit YCbCr 4:2:2;
> + * 9=30-bit RGB;
> + * 10=36-bit RGB;
> + * 11=12-bit YCbCr 4:2:0.
> + * [19] Reserved. Default 0.
> + * [18:16] RW in_color_mode: Define VENC data width. Default 0.
> + * 0=30-bit pixel;
> + * 1=24-bit pixel;
> + * 2=18-bit pixel, RGB666;
> + * 3=16-bit pixel, RGB565.
> + * [15:14] RW chroma_subsample: Define method of chroma subsampling. Default 0.
> + * Applicable to YUV422 or YUV420 only.
> + * 0=Use even pixel's chroma;
> + * 1=Use odd pixel's chroma;
> + * 2=Use averaged value between even and odd pair.
> + * [13:12] RW comp2_sel: Select which component to be Cr or B: Default 2.
> + * 0=comp0; 1=comp1; 2=comp2.
> + * [11:10] RW comp1_sel: Select which component to be Cb or G: Default 1.
> + * 0=comp0; 1=comp1; 2=comp2.
> + * [9: 8] RW comp0_sel: Select which component to be Y or R: Default 0.
> + * 0=comp0; 1=comp1; 2=comp2.
> + * [7] Reserved. Default 0.
> + * [6] RW de_pol: Default 0.
> + * If DE input is active low, set to 1 to invert to active high.
> + * [5] RW hsync_pol: Default 0.
> + * If HS input is active low, set to 1 to invert to active high.
> + * [4] RW vsync_pol: Default 0.
> + * If VS input is active low, set to 1 to invert to active high.
> + * [3] RW dpicolorm: Signal to IP. Default 0.
> + * [2] RW dpishutdn: Signal to IP. Default 0.
> + * [1] Reserved. Default 0.
> + * [0] Reserved. Default 0.
> + */
> +#define MIPI_DSI_TOP_CNTL 0x3c8
> +
> +/* VENC data width */
> +#define VENC_IN_COLOR_30B 0x0
> +#define VENC_IN_COLOR_24B 0x1
> +#define VENC_IN_COLOR_18B 0x2
> +#define VENC_IN_COLOR_16B 0x3
> +
> +/* DPI pixel format */
> +#define DPI_COLOR_16BIT_CFG_1 0
> +#define DPI_COLOR_16BIT_CFG_2 1
> +#define DPI_COLOR_16BIT_CFG_3 2
> +#define DPI_COLOR_18BIT_CFG_1 3
> +#define DPI_COLOR_18BIT_CFG_2 4
> +#define DPI_COLOR_24BIT 5
> +#define DPI_COLOR_20BIT_YCBCR_422 6
> +#define DPI_COLOR_24BIT_YCBCR_422 7
> +#define DPI_COLOR_16BIT_YCBCR_422 8
> +#define DPI_COLOR_30BIT 9
> +#define DPI_COLOR_36BIT 10
> +#define DPI_COLOR_12BIT_YCBCR_420 11
> +
> +#define MIPI_DSI_TOP_DPI_COLOR_MODE GENMASK(23, 20)
> +#define MIPI_DSI_TOP_IN_COLOR_MODE GENMASK(18, 16)
> +#define MIPI_DSI_TOP_CHROMA_SUBSAMPLE GENMASK(15, 14)
> +#define MIPI_DSI_TOP_COMP2_SEL GENMASK(13, 12)
> +#define MIPI_DSI_TOP_COMP1_SEL GENMASK(11, 10)
> +#define MIPI_DSI_TOP_COMP0_SEL GENMASK(9, 8)
> +#define MIPI_DSI_TOP_DE_INVERT BIT(6)
> +#define MIPI_DSI_TOP_HSYNC_INVERT BIT(5)
> +#define MIPI_DSI_TOP_VSYNC_INVERT BIT(4)
> +#define MIPI_DSI_TOP_DPICOLORM BIT(3)
> +#define MIPI_DSI_TOP_DPISHUTDN BIT(2)
> +
> +#define MIPI_DSI_TOP_SUSPEND_CNTL 0x3cc
> +#define MIPI_DSI_TOP_SUSPEND_LINE 0x3d0
> +#define MIPI_DSI_TOP_SUSPEND_PIX 0x3d4
> +#define MIPI_DSI_TOP_MEAS_CNTL 0x3d8
> +/* [0] R stat_edpihalt: edpihalt signal from IP. Default 0. */
> +#define MIPI_DSI_TOP_STAT 0x3dc
> +#define MIPI_DSI_TOP_MEAS_STAT_TE0 0x3e0
> +#define MIPI_DSI_TOP_MEAS_STAT_TE1 0x3e4
> +#define MIPI_DSI_TOP_MEAS_STAT_VS0 0x3e8
> +#define MIPI_DSI_TOP_MEAS_STAT_VS1 0x3ec
> +/* [31:16] RW intr_stat/clr. Default 0.
> + * For each bit, read as this interrupt level status,
> + * write 1 to clear.
> + * [31:22] Reserved
> + * [ 21] stat/clr of eof interrupt
> + * [ 21] vde_fall interrupt
> + * [ 19] stat/clr of de_rise interrupt
> + * [ 18] stat/clr of vs_fall interrupt
> + * [ 17] stat/clr of vs_rise interrupt
> + * [ 16] stat/clr of dwc_edpite interrupt
> + * [15: 0] RW intr_enable. Default 0.
> + * For each bit, 1=enable this interrupt, 0=disable.
> + * [15: 6] Reserved
> + * [ 5] eof interrupt
> + * [ 4] de_fall interrupt
> + * [ 3] de_rise interrupt
> + * [ 2] vs_fall interrupt
> + * [ 1] vs_rise interrupt
> + * [ 0] dwc_edpite interrupt
> + */
> +#define MIPI_DSI_TOP_INTR_CNTL_STAT 0x3f0
> +// 31: 2 Reserved. Default 0.
> +// 1: 0 RW mem_pd. Default 3.
> +#define MIPI_DSI_TOP_MEM_PD 0x3f4
> +
> +#endif /* __MESON_DW_MIPI_DSI_H */
>
> --
> 2.34.1
>
Reviewed-by: Nicolas Belin <nbelin at baylibre.com>
Tested-by: Nicolas Belin <nbelin at baylibre.com> # on Khadas VIM3 + TS050 Panel
Thanks,
Nicolas
More information about the linux-arm-kernel
mailing list