diff mbox series

[3/3,RFC] drm/exynos: Add basic i.MX8MM support code

Message ID 20201005134250.527153-3-marex@denx.de (mailing list archive)
State New, archived
Headers show
Series [1/3] drm/exynos: Init the DSIM PHY in samsung_dsim_enable() | expand

Commit Message

Marek Vasut Oct. 5, 2020, 1:42 p.m. UTC
This adds basic i.MX8MM glue code for the Samsung DSIM PHY.
There are still a couple of items which need to be sorted out
in drivers/gpu/drm/bridge/samsung-dsim.c before this can even
be merged, specifically:

- The dsi->out_bridge is not populated until samsung_dsim_host_attach()
  is called, however samsung_dsim_host_attach() is not called until the
  next bridge attaches and calls mipi_dsi_attach(), and that only happens
  after the DSIM calls drm_bridge_attach() on that next bridge.

- The samsung_dsim_bridge_mode_fixup() is needed for iMX8MM LCDIF to set
  the correct sync flags. This likely needs to be done in the glue code.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Guido Günther <agx@sigxcpu.org>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Michael Tretter <m.tretter@pengutronix.de>
Cc: NXP Linux Team <linux-imx@nxp.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-samsung-soc@vger.kernel.org
To: dri-devel@lists.freedesktop.org
--
NOTE: This depends on https://patchwork.kernel.org/project/dri-devel/list/?series=347439
---
 drivers/gpu/drm/bridge/Kconfig            |   6 +
 drivers/gpu/drm/bridge/Makefile           |   1 +
 drivers/gpu/drm/bridge/samsung-dsim-imx.c | 161 ++++++++++++++++++++++
 drivers/gpu/drm/bridge/samsung-dsim.c     |  25 +++-
 4 files changed, 192 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/bridge/samsung-dsim-imx.c

Comments

Michael Tretter Feb. 3, 2021, 7:53 p.m. UTC | #1
On Mon, 05 Oct 2020 15:42:50 +0200, Marek Vasut wrote:
> This adds basic i.MX8MM glue code for the Samsung DSIM PHY.
> There are still a couple of items which need to be sorted out
> in drivers/gpu/drm/bridge/samsung-dsim.c before this can even
> be merged, specifically:
> 
> - The dsi->out_bridge is not populated until samsung_dsim_host_attach()
>   is called, however samsung_dsim_host_attach() is not called until the
>   next bridge attaches and calls mipi_dsi_attach(), and that only happens
>   after the DSIM calls drm_bridge_attach() on that next bridge.

IMO, the DSIM behaves correctly by calling drm_bridge_attach() only after
samsung_dsim_host_attach() was called. At this point some DSI device has
appeared and told the DSI host that it is the next bridge in the pipeline.

Other DRI host bridges that I looked at behave the same. Either deferring the
bridge_attach until a DSI device has attached or even adding the bridge only
after a DSI device has attached. If a DSI device behaves differently, the DSI
device should be fixed to attach during probe instead of during bridge_attach.

> 
> - The samsung_dsim_bridge_mode_fixup() is needed for iMX8MM LCDIF to set
>   the correct sync flags. This likely needs to be done in the glue code.
> 
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Guido Günther <agx@sigxcpu.org>
> Cc: Jaehoon Chung <jh80.chung@samsung.com>
> Cc: Lucas Stach <l.stach@pengutronix.de>
> Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> Cc: Michael Tretter <m.tretter@pengutronix.de>
> Cc: NXP Linux Team <linux-imx@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-samsung-soc@vger.kernel.org
> To: dri-devel@lists.freedesktop.org
> --
> NOTE: This depends on https://patchwork.kernel.org/project/dri-devel/list/?series=347439
> ---
>  drivers/gpu/drm/bridge/Kconfig            |   6 +
>  drivers/gpu/drm/bridge/Makefile           |   1 +
>  drivers/gpu/drm/bridge/samsung-dsim-imx.c | 161 ++++++++++++++++++++++
>  drivers/gpu/drm/bridge/samsung-dsim.c     |  25 +++-
>  4 files changed, 192 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/bridge/samsung-dsim-imx.c
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 2d4459f78cdc..f97a8ebfcef1 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -129,6 +129,12 @@ config DRM_SAMSUNG_DSIM
>  	help
>  	  Samsung MIPI DSI bridge driver.
>  
> +config DRM_SAMSUNG_DSIM_IMX
> +	tristate "Samsung MIPI DSI bridge extras for NXP i.MX"
> +	depends on DRM_SAMSUNG_DSIM
> +	help
> +	  Samsung MIPI DSI bridge driver extras for NXP i.MX.
> +
>  config DRM_SIL_SII8620
>  	tristate "Silicon Image SII8620 HDMI/MHL bridge"
>  	depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index f7972d703c5d..61188a0cd052 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
>  obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
>  obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
>  obj-$(CONFIG_DRM_SAMSUNG_DSIM) += samsung-dsim.o
> +obj-$(CONFIG_DRM_SAMSUNG_DSIM_IMX) += samsung-dsim-imx.o
>  obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
>  obj-$(CONFIG_DRM_SII902X) += sii902x.o
>  obj-$(CONFIG_DRM_SII9234) += sii9234.o
> diff --git a/drivers/gpu/drm/bridge/samsung-dsim-imx.c b/drivers/gpu/drm/bridge/samsung-dsim-imx.c
> new file mode 100644
> index 000000000000..6c7307ce7eaf
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/samsung-dsim-imx.c
> @@ -0,0 +1,161 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * NXP i.MX8M SoC MIPI DSI driver
> + *
> + * Copyright (C) 2020 Marek Vasut <marex@denx.de>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#include <drm/bridge/samsung-dsim.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_simple_kms_helper.h>
> +
> +enum {
> +	DSI_PORT_IN,
> +	DSI_PORT_OUT
> +};
> +
> +struct imx_dsim_priv {
> +	struct samsung_dsim *dsi;
> +	struct drm_encoder encoder;
> +};
> +
> +static const unsigned int imx8mm_dsim_reg_values[] = {
> +	[RESET_TYPE] = DSIM_SWRST,
> +	[PLL_TIMER] = 500,
> +	[STOP_STATE_CNT] = 0xf,
> +	[PHYCTRL_ULPS_EXIT] = 0xaf,
> +	[PHYCTRL_VREG_LP] = 0,
> +	[PHYCTRL_SLEW_UP] = 0,
> +	[PHYTIMING_LPX] = 0x06,
> +	[PHYTIMING_HS_EXIT] = 0x0b,
> +	[PHYTIMING_CLK_PREPARE] = 0x07,
> +	[PHYTIMING_CLK_ZERO] = 0x26,
> +	[PHYTIMING_CLK_POST] = 0x0d,
> +	[PHYTIMING_CLK_TRAIL] = 0x08,
> +	[PHYTIMING_HS_PREPARE] = 0x08,
> +	[PHYTIMING_HS_ZERO] = 0x0d,
> +	[PHYTIMING_HS_TRAIL] = 0x0b,
> +};
> +
> +static int imx_dsim_host_attach(struct device *dev,
> +				  struct mipi_dsi_device *device)
> +{
> +	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +	struct drm_device *drm = dsi->encoder.dev;
> +
> +	if (drm->mode_config.poll_enabled)
> +		drm_kms_helper_hotplug_event(drm);
> +
> +	return 0;
> +}
> +
> +static int imx_dsim_host_detach(struct device *dev,
> +				  struct mipi_dsi_device *device)
> +{
> +	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +	struct drm_device *drm = dsi->encoder.dev;
> +
> +	if (drm->mode_config.poll_enabled)
> +		drm_kms_helper_hotplug_event(drm);
> +
> +	return 0;
> +}
> +
> +static const struct samsung_dsim_host_ops imx_dsim_host_ops = {
> +	.attach = imx_dsim_host_attach,
> +	.detach = imx_dsim_host_detach,
> +};
> +
> +static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = {
> +	.reg_ofs = EXYNOS5433_REG_OFS,
> +	.plltmr_reg = 0xa0,
> +	.has_clklane_stop = 1,
> +	.num_clks = 2,
> +	.max_freq = 2100,
> +	.wait_for_reset = 0,
> +	.num_bits_resol = 12,
> +	.reg_values = imx8mm_dsim_reg_values,
> +	.host_ops = &imx_dsim_host_ops,
> +};
> +
> +static const struct of_device_id imx_dsim_of_match[] = {
> +	{ .compatible = "fsl,imx8mm-mipi-dsim",
> +	  .data = &imx8mm_dsi_driver_data },
> +	{ }
> +};
> +
> +static int imx_dsim_probe(struct platform_device *pdev)
> +{
> +	struct imx_dsim_priv *dsi;
> +	struct device *dev = &pdev->dev;
> +
> +	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
> +	if (!dsi)
> +		return -ENOMEM;
> +	platform_set_drvdata(pdev, dsi);
> +
> +	dsi->dsi = samsung_dsim_probe(pdev);
> +	if (IS_ERR(dsi->dsi))
> +		return PTR_ERR(dsi->dsi);
> +
> +	pm_runtime_enable(dev);
> +
> +	return 0;
> +}
> +
> +static int imx_dsim_remove(struct platform_device *pdev)
> +{
> +	struct imx_dsim_priv *dsi = platform_get_drvdata(pdev);
> +
> +	pm_runtime_disable(&pdev->dev);
> +
> +	samsung_dsim_remove(dsi->dsi);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused imx_dsim_suspend(struct device *dev)
> +{
> +	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +
> +	return samsung_dsim_suspend(dsi->dsi);
> +}
> +
> +static int __maybe_unused imx_dsim_resume(struct device *dev)
> +{
> +	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +
> +	return samsung_dsim_resume(dsi->dsi);
> +}
> +
> +static const struct dev_pm_ops imx_dsim_pm_ops = {
> +	SET_RUNTIME_PM_OPS(imx_dsim_suspend, imx_dsim_resume, NULL)
> +	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> +				pm_runtime_force_resume)
> +};
> +
> +static struct platform_driver imx_dsim_driver = {
> +	.probe = imx_dsim_probe,
> +	.remove = imx_dsim_remove,
> +	.driver = {
> +		   .name = "imx-dsim-dsi",
> +		   .owner = THIS_MODULE,
> +		   .pm = &imx_dsim_pm_ops,
> +		   .of_match_table = imx_dsim_of_match,
> +	},
> +};
> +
> +module_platform_driver(imx_dsim_driver);
> +
> +MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
> +MODULE_DESCRIPTION("NXP i.MX8M SoC MIPI DSI");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
> index 42b49546dd00..12aeceb40450 100644
> --- a/drivers/gpu/drm/bridge/samsung-dsim.c
> +++ b/drivers/gpu/drm/bridge/samsung-dsim.c
> @@ -28,6 +28,7 @@
>  #include <drm/drm_bridge.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> @@ -1388,8 +1389,15 @@ static int samsung_dsim_bridge_attach(struct drm_bridge *bridge,
>  {
>  	struct samsung_dsim *dsi = bridge->driver_private;
>  	struct drm_encoder *encoder = bridge->encoder;
> +	struct device *dev = dsi->dev;
> +	struct device_node *np = dev->of_node;
>  	int ret;
>  
> +	ret = drm_of_find_panel_or_bridge(np, 1, 0,
> +					  &dsi->panel, &dsi->out_bridge);
> +	if (ret)
> +		return ret;
> +
>  	if (!dsi->out_bridge && !dsi->panel)
>  		return -EPROBE_DEFER;
>  
> @@ -1398,7 +1406,6 @@ static int samsung_dsim_bridge_attach(struct drm_bridge *bridge,
>  					bridge, flags);
>  		if (ret)
>  			return ret;
> -		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
>  	} else {
>  		ret = samsung_dsim_create_connector(dsi);
>  		if (ret)
> @@ -1456,18 +1463,31 @@ static void samsung_dsim_bridge_mode_set(struct drm_bridge *bridge,
>  	drm_mode_copy(&dsi->mode, adjusted_mode);
>  }
>  
> +static bool samsung_dsim_bridge_mode_fixup(struct drm_bridge *bridge,
> +					   const struct drm_display_mode *mode,
> +					   struct drm_display_mode *adjusted_mode)
> +{
> +	/* At least LCDIF + DSIM needs active low sync */
> +	adjusted_mode->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> +	adjusted_mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> +
> +	return true;
> +}
> +
>  static const struct drm_bridge_funcs samsung_dsim_bridge_funcs = {
>  	.attach = samsung_dsim_bridge_attach,
>  	.detach = samsung_dsim_bridge_detach,
>  	.enable = samsung_dsim_bridge_enable,
>  	.disable = samsung_dsim_bridge_disable,
>  	.mode_set = samsung_dsim_bridge_mode_set,
> +	.mode_fixup = samsung_dsim_bridge_mode_fixup,
>  };
>  
>  static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
>  				    struct mipi_dsi_device *device)
>  {
>  	struct samsung_dsim *dsi = host_to_dsi(host);
> +#if 0
>  	const struct samsung_dsim_host_ops *ops = dsi->driver_data->host_ops;
>  	struct drm_bridge *out_bridge;
>  
> @@ -1493,13 +1513,16 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
>  		if (ret)
>  			return ret;
>  	}
> +#endif
>  
>  	dsi->lanes = device->lanes;
>  	dsi->format = device->format;
>  	dsi->mode_flags = device->mode_flags;
>  
> +#if 0
>  	if (ops && ops->attach)
>  		ops->attach(dsi->dsi_host.dev, device);
> +#endif
>  
>  	return 0;
>  }
> -- 
> 2.28.0
> 
>
Adam Ford May 10, 2021, 2:12 p.m. UTC | #2
On Mon, Oct 5, 2020 at 8:48 AM Marek Vasut <marex@denx.de> wrote:
>
> This adds basic i.MX8MM glue code for the Samsung DSIM PHY.
> There are still a couple of items which need to be sorted out
> in drivers/gpu/drm/bridge/samsung-dsim.c before this can even
> be merged, specifically:
>
> - The dsi->out_bridge is not populated until samsung_dsim_host_attach()
>   is called, however samsung_dsim_host_attach() is not called until the
>   next bridge attaches and calls mipi_dsi_attach(), and that only happens
>   after the DSIM calls drm_bridge_attach() on that next bridge.
>
> - The samsung_dsim_bridge_mode_fixup() is needed for iMX8MM LCDIF to set
>   the correct sync flags. This likely needs to be done in the glue code.

Since you asked for an RFC, I
I applied Michael's series and this series to 5.12 since we are so
close on having the blk-clk and the power domain stuff working.  I
also tried your patch for the ti-sn65dsi83 and the adv7511 on the
Beacon imx8mm development kit.

In both the HDMI bridge and LVDS bridge, I am able to get the modetest
and drmdevice to return data that looks valid.  The resolution and
refresh look correct, but I am not able to can an actual image to
generate out to either the LVDS or the HDMI.  I am able to get the
image to appear using the NXP kernel with the ADV7511 HDMI bridge, so
that leads me to believe there might be something wrong with either
LCDIF or the Samsung DSIM layer code.  I am guess it's the Samsung
DSIM stuff since the LCDIF has been around for a while.

I am not particularly well versed in the video world, but if you have
something you'd like me to try, i am willing to try it.

adam

>
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Guido Günther <agx@sigxcpu.org>
> Cc: Jaehoon Chung <jh80.chung@samsung.com>
> Cc: Lucas Stach <l.stach@pengutronix.de>
> Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> Cc: Michael Tretter <m.tretter@pengutronix.de>
> Cc: NXP Linux Team <linux-imx@nxp.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-samsung-soc@vger.kernel.org
> To: dri-devel@lists.freedesktop.org
> --
> NOTE: This depends on https://patchwork.kernel.org/project/dri-devel/list/?series=347439
> ---
>  drivers/gpu/drm/bridge/Kconfig            |   6 +
>  drivers/gpu/drm/bridge/Makefile           |   1 +
>  drivers/gpu/drm/bridge/samsung-dsim-imx.c | 161 ++++++++++++++++++++++
>  drivers/gpu/drm/bridge/samsung-dsim.c     |  25 +++-
>  4 files changed, 192 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/bridge/samsung-dsim-imx.c
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 2d4459f78cdc..f97a8ebfcef1 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -129,6 +129,12 @@ config DRM_SAMSUNG_DSIM
>         help
>           Samsung MIPI DSI bridge driver.
>
> +config DRM_SAMSUNG_DSIM_IMX
> +       tristate "Samsung MIPI DSI bridge extras for NXP i.MX"
> +       depends on DRM_SAMSUNG_DSIM
> +       help
> +         Samsung MIPI DSI bridge driver extras for NXP i.MX.
> +
>  config DRM_SIL_SII8620
>         tristate "Silicon Image SII8620 HDMI/MHL bridge"
>         depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index f7972d703c5d..61188a0cd052 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
>  obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
>  obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
>  obj-$(CONFIG_DRM_SAMSUNG_DSIM) += samsung-dsim.o
> +obj-$(CONFIG_DRM_SAMSUNG_DSIM_IMX) += samsung-dsim-imx.o
>  obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
>  obj-$(CONFIG_DRM_SII902X) += sii902x.o
>  obj-$(CONFIG_DRM_SII9234) += sii9234.o
> diff --git a/drivers/gpu/drm/bridge/samsung-dsim-imx.c b/drivers/gpu/drm/bridge/samsung-dsim-imx.c
> new file mode 100644
> index 000000000000..6c7307ce7eaf
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/samsung-dsim-imx.c
> @@ -0,0 +1,161 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * NXP i.MX8M SoC MIPI DSI driver
> + *
> + * Copyright (C) 2020 Marek Vasut <marex@denx.de>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#include <drm/bridge/samsung-dsim.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_simple_kms_helper.h>
> +
> +enum {
> +       DSI_PORT_IN,
> +       DSI_PORT_OUT
> +};
> +
> +struct imx_dsim_priv {
> +       struct samsung_dsim *dsi;
> +       struct drm_encoder encoder;
> +};
> +
> +static const unsigned int imx8mm_dsim_reg_values[] = {
> +       [RESET_TYPE] = DSIM_SWRST,
> +       [PLL_TIMER] = 500,
> +       [STOP_STATE_CNT] = 0xf,
> +       [PHYCTRL_ULPS_EXIT] = 0xaf,
> +       [PHYCTRL_VREG_LP] = 0,
> +       [PHYCTRL_SLEW_UP] = 0,
> +       [PHYTIMING_LPX] = 0x06,
> +       [PHYTIMING_HS_EXIT] = 0x0b,
> +       [PHYTIMING_CLK_PREPARE] = 0x07,
> +       [PHYTIMING_CLK_ZERO] = 0x26,
> +       [PHYTIMING_CLK_POST] = 0x0d,
> +       [PHYTIMING_CLK_TRAIL] = 0x08,
> +       [PHYTIMING_HS_PREPARE] = 0x08,
> +       [PHYTIMING_HS_ZERO] = 0x0d,
> +       [PHYTIMING_HS_TRAIL] = 0x0b,
> +};
> +
> +static int imx_dsim_host_attach(struct device *dev,
> +                                 struct mipi_dsi_device *device)
> +{
> +       struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +       struct drm_device *drm = dsi->encoder.dev;
> +
> +       if (drm->mode_config.poll_enabled)
> +               drm_kms_helper_hotplug_event(drm);
> +
> +       return 0;
> +}
> +
> +static int imx_dsim_host_detach(struct device *dev,
> +                                 struct mipi_dsi_device *device)
> +{
> +       struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +       struct drm_device *drm = dsi->encoder.dev;
> +
> +       if (drm->mode_config.poll_enabled)
> +               drm_kms_helper_hotplug_event(drm);
> +
> +       return 0;
> +}
> +
> +static const struct samsung_dsim_host_ops imx_dsim_host_ops = {
> +       .attach = imx_dsim_host_attach,
> +       .detach = imx_dsim_host_detach,
> +};
> +
> +static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = {
> +       .reg_ofs = EXYNOS5433_REG_OFS,
> +       .plltmr_reg = 0xa0,
> +       .has_clklane_stop = 1,
> +       .num_clks = 2,
> +       .max_freq = 2100,
> +       .wait_for_reset = 0,
> +       .num_bits_resol = 12,
> +       .reg_values = imx8mm_dsim_reg_values,
> +       .host_ops = &imx_dsim_host_ops,
> +};
> +
> +static const struct of_device_id imx_dsim_of_match[] = {
> +       { .compatible = "fsl,imx8mm-mipi-dsim",
> +         .data = &imx8mm_dsi_driver_data },
> +       { }
> +};
> +
> +static int imx_dsim_probe(struct platform_device *pdev)
> +{
> +       struct imx_dsim_priv *dsi;
> +       struct device *dev = &pdev->dev;
> +
> +       dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
> +       if (!dsi)
> +               return -ENOMEM;
> +       platform_set_drvdata(pdev, dsi);
> +
> +       dsi->dsi = samsung_dsim_probe(pdev);
> +       if (IS_ERR(dsi->dsi))
> +               return PTR_ERR(dsi->dsi);
> +
> +       pm_runtime_enable(dev);
> +
> +       return 0;
> +}
> +
> +static int imx_dsim_remove(struct platform_device *pdev)
> +{
> +       struct imx_dsim_priv *dsi = platform_get_drvdata(pdev);
> +
> +       pm_runtime_disable(&pdev->dev);
> +
> +       samsung_dsim_remove(dsi->dsi);
> +
> +       return 0;
> +}
> +
> +static int __maybe_unused imx_dsim_suspend(struct device *dev)
> +{
> +       struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +
> +       return samsung_dsim_suspend(dsi->dsi);
> +}
> +
> +static int __maybe_unused imx_dsim_resume(struct device *dev)
> +{
> +       struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
> +
> +       return samsung_dsim_resume(dsi->dsi);
> +}
> +
> +static const struct dev_pm_ops imx_dsim_pm_ops = {
> +       SET_RUNTIME_PM_OPS(imx_dsim_suspend, imx_dsim_resume, NULL)
> +       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> +                               pm_runtime_force_resume)
> +};
> +
> +static struct platform_driver imx_dsim_driver = {
> +       .probe = imx_dsim_probe,
> +       .remove = imx_dsim_remove,
> +       .driver = {
> +                  .name = "imx-dsim-dsi",
> +                  .owner = THIS_MODULE,
> +                  .pm = &imx_dsim_pm_ops,
> +                  .of_match_table = imx_dsim_of_match,
> +       },
> +};
> +
> +module_platform_driver(imx_dsim_driver);
> +
> +MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
> +MODULE_DESCRIPTION("NXP i.MX8M SoC MIPI DSI");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
> index 42b49546dd00..12aeceb40450 100644
> --- a/drivers/gpu/drm/bridge/samsung-dsim.c
> +++ b/drivers/gpu/drm/bridge/samsung-dsim.c
> @@ -28,6 +28,7 @@
>  #include <drm/drm_bridge.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> @@ -1388,8 +1389,15 @@ static int samsung_dsim_bridge_attach(struct drm_bridge *bridge,
>  {
>         struct samsung_dsim *dsi = bridge->driver_private;
>         struct drm_encoder *encoder = bridge->encoder;
> +       struct device *dev = dsi->dev;
> +       struct device_node *np = dev->of_node;
>         int ret;
>
> +       ret = drm_of_find_panel_or_bridge(np, 1, 0,
> +                                         &dsi->panel, &dsi->out_bridge);
> +       if (ret)
> +               return ret;
> +
>         if (!dsi->out_bridge && !dsi->panel)
>                 return -EPROBE_DEFER;
>
> @@ -1398,7 +1406,6 @@ static int samsung_dsim_bridge_attach(struct drm_bridge *bridge,
>                                         bridge, flags);
>                 if (ret)
>                         return ret;
> -               list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
>         } else {
>                 ret = samsung_dsim_create_connector(dsi);
>                 if (ret)
> @@ -1456,18 +1463,31 @@ static void samsung_dsim_bridge_mode_set(struct drm_bridge *bridge,
>         drm_mode_copy(&dsi->mode, adjusted_mode);
>  }
>
> +static bool samsung_dsim_bridge_mode_fixup(struct drm_bridge *bridge,
> +                                          const struct drm_display_mode *mode,
> +                                          struct drm_display_mode *adjusted_mode)
> +{
> +       /* At least LCDIF + DSIM needs active low sync */
> +       adjusted_mode->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
> +       adjusted_mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
> +
> +       return true;
> +}
> +
>  static const struct drm_bridge_funcs samsung_dsim_bridge_funcs = {
>         .attach = samsung_dsim_bridge_attach,
>         .detach = samsung_dsim_bridge_detach,
>         .enable = samsung_dsim_bridge_enable,
>         .disable = samsung_dsim_bridge_disable,
>         .mode_set = samsung_dsim_bridge_mode_set,
> +       .mode_fixup = samsung_dsim_bridge_mode_fixup,
>  };
>
>  static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
>                                     struct mipi_dsi_device *device)
>  {
>         struct samsung_dsim *dsi = host_to_dsi(host);
> +#if 0
>         const struct samsung_dsim_host_ops *ops = dsi->driver_data->host_ops;
>         struct drm_bridge *out_bridge;
>
> @@ -1493,13 +1513,16 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
>                 if (ret)
>                         return ret;
>         }
> +#endif
>
>         dsi->lanes = device->lanes;
>         dsi->format = device->format;
>         dsi->mode_flags = device->mode_flags;
>
> +#if 0
>         if (ops && ops->attach)
>                 ops->attach(dsi->dsi_host.dev, device);
> +#endif
>
>         return 0;
>  }
> --
> 2.28.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Tim Harvey May 10, 2021, 4:20 p.m. UTC | #3
On Mon, May 10, 2021 at 7:12 AM Adam Ford <aford173@gmail.com> wrote:
>
> On Mon, Oct 5, 2020 at 8:48 AM Marek Vasut <marex@denx.de> wrote:
> >
> > This adds basic i.MX8MM glue code for the Samsung DSIM PHY.
> > There are still a couple of items which need to be sorted out
> > in drivers/gpu/drm/bridge/samsung-dsim.c before this can even
> > be merged, specifically:
> >
> > - The dsi->out_bridge is not populated until samsung_dsim_host_attach()
> >   is called, however samsung_dsim_host_attach() is not called until the
> >   next bridge attaches and calls mipi_dsi_attach(), and that only happens
> >   after the DSIM calls drm_bridge_attach() on that next bridge.
> >
> > - The samsung_dsim_bridge_mode_fixup() is needed for iMX8MM LCDIF to set
> >   the correct sync flags. This likely needs to be done in the glue code.
>
> Since you asked for an RFC, I
> I applied Michael's series and this series to 5.12 since we are so
> close on having the blk-clk and the power domain stuff working.  I
> also tried your patch for the ti-sn65dsi83 and the adv7511 on the
> Beacon imx8mm development kit.
>
> In both the HDMI bridge and LVDS bridge, I am able to get the modetest
> and drmdevice to return data that looks valid.  The resolution and
> refresh look correct, but I am not able to can an actual image to
> generate out to either the LVDS or the HDMI.  I am able to get the
> image to appear using the NXP kernel with the ADV7511 HDMI bridge, so
> that leads me to believe there might be something wrong with either
> LCDIF or the Samsung DSIM layer code.  I am guess it's the Samsung
> DSIM stuff since the LCDIF has been around for a while.
>
> I am not particularly well versed in the video world, but if you have
> something you'd like me to try, i am willing to try it.
>

Adam,

Try the patches Frieder had to make for his display from his git here:
https://github.com/fschrempf/linux/commits/v5.10-mx8mm-graphics.

I found I needed these for the display I have:
drm/exynos: Fix DE polarity for usage with LCDIF encoder
drm/exynos: Fix PLL PMS offset for P value bitfield

Best regards,

Tim
diff mbox series

Patch

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 2d4459f78cdc..f97a8ebfcef1 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -129,6 +129,12 @@  config DRM_SAMSUNG_DSIM
 	help
 	  Samsung MIPI DSI bridge driver.
 
+config DRM_SAMSUNG_DSIM_IMX
+	tristate "Samsung MIPI DSI bridge extras for NXP i.MX"
+	depends on DRM_SAMSUNG_DSIM
+	help
+	  Samsung MIPI DSI bridge driver extras for NXP i.MX.
+
 config DRM_SIL_SII8620
 	tristate "Silicon Image SII8620 HDMI/MHL bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index f7972d703c5d..61188a0cd052 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -9,6 +9,7 @@  obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
 obj-$(CONFIG_DRM_SAMSUNG_DSIM) += samsung-dsim.o
+obj-$(CONFIG_DRM_SAMSUNG_DSIM_IMX) += samsung-dsim-imx.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
 obj-$(CONFIG_DRM_SII902X) += sii902x.o
 obj-$(CONFIG_DRM_SII9234) += sii9234.o
diff --git a/drivers/gpu/drm/bridge/samsung-dsim-imx.c b/drivers/gpu/drm/bridge/samsung-dsim-imx.c
new file mode 100644
index 000000000000..6c7307ce7eaf
--- /dev/null
+++ b/drivers/gpu/drm/bridge/samsung-dsim-imx.c
@@ -0,0 +1,161 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NXP i.MX8M SoC MIPI DSI driver
+ *
+ * Copyright (C) 2020 Marek Vasut <marex@denx.de>
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/bridge/samsung-dsim.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+enum {
+	DSI_PORT_IN,
+	DSI_PORT_OUT
+};
+
+struct imx_dsim_priv {
+	struct samsung_dsim *dsi;
+	struct drm_encoder encoder;
+};
+
+static const unsigned int imx8mm_dsim_reg_values[] = {
+	[RESET_TYPE] = DSIM_SWRST,
+	[PLL_TIMER] = 500,
+	[STOP_STATE_CNT] = 0xf,
+	[PHYCTRL_ULPS_EXIT] = 0xaf,
+	[PHYCTRL_VREG_LP] = 0,
+	[PHYCTRL_SLEW_UP] = 0,
+	[PHYTIMING_LPX] = 0x06,
+	[PHYTIMING_HS_EXIT] = 0x0b,
+	[PHYTIMING_CLK_PREPARE] = 0x07,
+	[PHYTIMING_CLK_ZERO] = 0x26,
+	[PHYTIMING_CLK_POST] = 0x0d,
+	[PHYTIMING_CLK_TRAIL] = 0x08,
+	[PHYTIMING_HS_PREPARE] = 0x08,
+	[PHYTIMING_HS_ZERO] = 0x0d,
+	[PHYTIMING_HS_TRAIL] = 0x0b,
+};
+
+static int imx_dsim_host_attach(struct device *dev,
+				  struct mipi_dsi_device *device)
+{
+	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
+	struct drm_device *drm = dsi->encoder.dev;
+
+	if (drm->mode_config.poll_enabled)
+		drm_kms_helper_hotplug_event(drm);
+
+	return 0;
+}
+
+static int imx_dsim_host_detach(struct device *dev,
+				  struct mipi_dsi_device *device)
+{
+	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
+	struct drm_device *drm = dsi->encoder.dev;
+
+	if (drm->mode_config.poll_enabled)
+		drm_kms_helper_hotplug_event(drm);
+
+	return 0;
+}
+
+static const struct samsung_dsim_host_ops imx_dsim_host_ops = {
+	.attach = imx_dsim_host_attach,
+	.detach = imx_dsim_host_detach,
+};
+
+static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = {
+	.reg_ofs = EXYNOS5433_REG_OFS,
+	.plltmr_reg = 0xa0,
+	.has_clklane_stop = 1,
+	.num_clks = 2,
+	.max_freq = 2100,
+	.wait_for_reset = 0,
+	.num_bits_resol = 12,
+	.reg_values = imx8mm_dsim_reg_values,
+	.host_ops = &imx_dsim_host_ops,
+};
+
+static const struct of_device_id imx_dsim_of_match[] = {
+	{ .compatible = "fsl,imx8mm-mipi-dsim",
+	  .data = &imx8mm_dsi_driver_data },
+	{ }
+};
+
+static int imx_dsim_probe(struct platform_device *pdev)
+{
+	struct imx_dsim_priv *dsi;
+	struct device *dev = &pdev->dev;
+
+	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, dsi);
+
+	dsi->dsi = samsung_dsim_probe(pdev);
+	if (IS_ERR(dsi->dsi))
+		return PTR_ERR(dsi->dsi);
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int imx_dsim_remove(struct platform_device *pdev)
+{
+	struct imx_dsim_priv *dsi = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+
+	samsung_dsim_remove(dsi->dsi);
+
+	return 0;
+}
+
+static int __maybe_unused imx_dsim_suspend(struct device *dev)
+{
+	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
+
+	return samsung_dsim_suspend(dsi->dsi);
+}
+
+static int __maybe_unused imx_dsim_resume(struct device *dev)
+{
+	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);
+
+	return samsung_dsim_resume(dsi->dsi);
+}
+
+static const struct dev_pm_ops imx_dsim_pm_ops = {
+	SET_RUNTIME_PM_OPS(imx_dsim_suspend, imx_dsim_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver imx_dsim_driver = {
+	.probe = imx_dsim_probe,
+	.remove = imx_dsim_remove,
+	.driver = {
+		   .name = "imx-dsim-dsi",
+		   .owner = THIS_MODULE,
+		   .pm = &imx_dsim_pm_ops,
+		   .of_match_table = imx_dsim_of_match,
+	},
+};
+
+module_platform_driver(imx_dsim_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("NXP i.MX8M SoC MIPI DSI");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
index 42b49546dd00..12aeceb40450 100644
--- a/drivers/gpu/drm/bridge/samsung-dsim.c
+++ b/drivers/gpu/drm/bridge/samsung-dsim.c
@@ -28,6 +28,7 @@ 
 #include <drm/drm_bridge.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
@@ -1388,8 +1389,15 @@  static int samsung_dsim_bridge_attach(struct drm_bridge *bridge,
 {
 	struct samsung_dsim *dsi = bridge->driver_private;
 	struct drm_encoder *encoder = bridge->encoder;
+	struct device *dev = dsi->dev;
+	struct device_node *np = dev->of_node;
 	int ret;
 
+	ret = drm_of_find_panel_or_bridge(np, 1, 0,
+					  &dsi->panel, &dsi->out_bridge);
+	if (ret)
+		return ret;
+
 	if (!dsi->out_bridge && !dsi->panel)
 		return -EPROBE_DEFER;
 
@@ -1398,7 +1406,6 @@  static int samsung_dsim_bridge_attach(struct drm_bridge *bridge,
 					bridge, flags);
 		if (ret)
 			return ret;
-		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
 	} else {
 		ret = samsung_dsim_create_connector(dsi);
 		if (ret)
@@ -1456,18 +1463,31 @@  static void samsung_dsim_bridge_mode_set(struct drm_bridge *bridge,
 	drm_mode_copy(&dsi->mode, adjusted_mode);
 }
 
+static bool samsung_dsim_bridge_mode_fixup(struct drm_bridge *bridge,
+					   const struct drm_display_mode *mode,
+					   struct drm_display_mode *adjusted_mode)
+{
+	/* At least LCDIF + DSIM needs active low sync */
+	adjusted_mode->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
+	adjusted_mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
+
+	return true;
+}
+
 static const struct drm_bridge_funcs samsung_dsim_bridge_funcs = {
 	.attach = samsung_dsim_bridge_attach,
 	.detach = samsung_dsim_bridge_detach,
 	.enable = samsung_dsim_bridge_enable,
 	.disable = samsung_dsim_bridge_disable,
 	.mode_set = samsung_dsim_bridge_mode_set,
+	.mode_fixup = samsung_dsim_bridge_mode_fixup,
 };
 
 static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
 				    struct mipi_dsi_device *device)
 {
 	struct samsung_dsim *dsi = host_to_dsi(host);
+#if 0
 	const struct samsung_dsim_host_ops *ops = dsi->driver_data->host_ops;
 	struct drm_bridge *out_bridge;
 
@@ -1493,13 +1513,16 @@  static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
 		if (ret)
 			return ret;
 	}
+#endif
 
 	dsi->lanes = device->lanes;
 	dsi->format = device->format;
 	dsi->mode_flags = device->mode_flags;
 
+#if 0
 	if (ops && ops->attach)
 		ops->attach(dsi->dsi_host.dev, device);
+#endif
 
 	return 0;
 }