All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rob Herring <robh@kernel.org>
To: Liu Ying <victor.liu@nxp.com>
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-media@vger.kernel.org,
	airlied@linux.ie, daniel@ffwll.ch, shawnguo@kernel.org,
	s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, linux-imx@nxp.com, mchehab@kernel.org,
	a.hajda@samsung.com, narmstrong@baylibre.com,
	Laurent.pinchart@ideasonboard.com, jonas@kwiboo.se,
	jernej.skrabec@siol.net, kishon@ti.com, vkoul@kernel.org
Subject: Re: [PATCH 07/14] drm/bridge: imx: Add i.MX8qm/qxp display pixel link support
Date: Mon, 21 Dec 2020 15:29:55 -0700	[thread overview]
Message-ID: <20201221222955.GA652934@robh.at.kernel.org> (raw)
In-Reply-To: <1608199173-28760-8-git-send-email-victor.liu@nxp.com>

On Thu, Dec 17, 2020 at 05:59:26PM +0800, Liu Ying wrote:
> This patch adds a drm bridge driver for i.MX8qm/qxp display pixel link.
> The pixel link forms a standard asynchronous linkage between
> pixel sources(display controller or camera module) and pixel
> consumers(imaging or displays).  It consists of two distinct
> functions, a pixel transfer function and a control interface.
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/imx/Kconfig              |   8 +
>  drivers/gpu/drm/bridge/imx/Makefile             |   1 +
>  drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 411 ++++++++++++++++++++++++
>  3 files changed, 420 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> 
> diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
> index f1c91b6..4d1f027 100644
> --- a/drivers/gpu/drm/bridge/imx/Kconfig
> +++ b/drivers/gpu/drm/bridge/imx/Kconfig
> @@ -6,3 +6,11 @@ config DRM_IMX8QXP_PIXEL_COMBINER
>  	help
>  	  Choose this to enable pixel combiner found in
>  	  Freescale i.MX8qm/qxp processors.
> +
> +config DRM_IMX8QXP_PIXEL_LINK
> +	tristate "Freescale i.MX8QM/QXP display pixel link"
> +	depends on OF
> +	select DRM_KMS_HELPER
> +	help
> +	  Choose this to enable display pixel link found in
> +	  Freescale i.MX8qm/qxp processors.
> diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
> index 7d7c8d6..c15469f 100644
> --- a/drivers/gpu/drm/bridge/imx/Makefile
> +++ b/drivers/gpu/drm/bridge/imx/Makefile
> @@ -1 +1,2 @@
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
> +obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
> diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> new file mode 100644
> index 00000000..1af7467
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> @@ -0,0 +1,411 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright 2020 NXP
> + */
> +
> +#include <linux/firmware/imx/svc/misc.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_print.h>
> +
> +#include <dt-bindings/firmware/imx/rsrc.h>
> +
> +#define DRIVER_NAME		"imx8qxp-display-pixel-link"
> +#define PL_MAX_MST_ADDR		3
> +
> +struct imx8qxp_pixel_link {
> +	struct drm_bridge bridge;
> +	struct drm_bridge *next_bridge;
> +	struct device *dev;
> +	struct imx_sc_ipc *ipc_handle;
> +	int id;
> +	int stream_id;
> +	int dc_id;
> +	u32 sink_rsc;
> +	u32 mst_addr;
> +	u8 mst_addr_ctrl;
> +	u8 mst_en_ctrl;
> +	u8 mst_vld_ctrl;
> +	u8 sync_ctrl;
> +};
> +
> +#define DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(name)			\
> +static void								\
> +imx8qxp_pixel_link_enable_##name(struct imx8qxp_pixel_link *pl)		\
> +{									\
> +	int ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,	\
> +					  pl->name##_ctrl, true);	\
> +	if (ret)							\
> +		DRM_DEV_ERROR(pl->dev,					\
> +			"failed to enable DC%d stream%d pixel link "	\
> +			#name ": %d\n",	pl->dc_id, pl->stream_id, ret);	\
> +}
> +
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(mst_en)
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(mst_vld)
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(sync)
> +
> +#define DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(name)			\
> +static int								\
> +imx8qxp_pixel_link_disable_##name(struct imx8qxp_pixel_link *pl)	\
> +{									\
> +	int ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,	\
> +					  pl->name##_ctrl, false);	\
> +	if (ret)							\
> +		DRM_DEV_ERROR(pl->dev,					\
> +			"failed to disable DC%d stream%d pixel link "	\
> +			#name ": %d\n",	pl->dc_id, pl->stream_id, ret);	\
> +									\
> +	return ret;							\
> +}
> +
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(mst_en)
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(mst_vld)
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(sync)
> +
> +static void imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link *pl)
> +{
> +	int ret;
> +
> +	ret = imx_sc_misc_set_control(pl->ipc_handle,
> +				      pl->sink_rsc, pl->mst_addr_ctrl,
> +				      pl->mst_addr);
> +	if (ret)
> +		DRM_DEV_ERROR(pl->dev,
> +		    "failed to set DC%d stream%d pixel link mst addr(%u): %d\n",
> +		    pl->dc_id, pl->stream_id, pl->mst_addr, ret);
> +}
> +
> +static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
> +					    enum drm_bridge_attach_flags flags)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> +		DRM_DEV_ERROR(pl->dev,
> +			      "do not support creating a drm_connector\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!bridge->encoder) {
> +		DRM_DEV_ERROR(pl->dev, "missing encoder\n");
> +		return -ENODEV;
> +	}
> +
> +	return drm_bridge_attach(bridge->encoder,
> +				 pl->next_bridge, bridge,
> +				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +}
> +
> +static void
> +imx8qxp_pixel_link_bridge_mode_set(struct drm_bridge *bridge,
> +				   const struct drm_display_mode *mode,
> +				   const struct drm_display_mode *adjusted_mode)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_set_mst_addr(pl);
> +}
> +
> +static void imx8qxp_pixel_link_bridge_atomic_enable(struct drm_bridge *bridge,
> +			      struct drm_bridge_state *old_bridge_state)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_enable_mst_en(pl);
> +	imx8qxp_pixel_link_enable_mst_vld(pl);
> +	imx8qxp_pixel_link_enable_sync(pl);
> +}
> +
> +static void imx8qxp_pixel_link_bridge_atomic_disable(struct drm_bridge *bridge,
> +				struct drm_bridge_state *old_bridge_state)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_disable_mst_en(pl);
> +	imx8qxp_pixel_link_disable_mst_vld(pl);
> +	imx8qxp_pixel_link_disable_sync(pl);
> +}
> +
> +static const u32 imx8qxp_pixel_link_bus_output_fmts[] = {
> +	MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
> +	MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
> +};
> +
> +static bool imx8qxp_pixel_link_bus_output_fmt_supported(u32 fmt)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts); i++) {
> +		if (imx8qxp_pixel_link_bus_output_fmts[i] == fmt)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static u32 *
> +imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +
> +	if (!imx8qxp_pixel_link_bus_output_fmt_supported(output_fmt))
> +		return NULL;
> +
> +	*num_input_fmts = 1;
> +
> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> +	if (!input_fmts)
> +		return NULL;
> +
> +	input_fmts[0] = output_fmt;
> +
> +	return input_fmts;
> +}
> +
> +static u32 *
> +imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					unsigned int *num_output_fmts)
> +{
> +	*num_output_fmts = ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts);
> +	return kmemdup(imx8qxp_pixel_link_bus_output_fmts,
> +			sizeof(imx8qxp_pixel_link_bus_output_fmts), GFP_KERNEL);
> +}
> +
> +static const struct drm_bridge_funcs imx8qxp_pixel_link_bridge_funcs = {
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +	.attach			= imx8qxp_pixel_link_bridge_attach,
> +	.mode_set		= imx8qxp_pixel_link_bridge_mode_set,
> +	.atomic_enable		= imx8qxp_pixel_link_bridge_atomic_enable,
> +	.atomic_disable		= imx8qxp_pixel_link_bridge_atomic_disable,
> +	.atomic_get_input_bus_fmts =
> +			imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts,
> +	.atomic_get_output_bus_fmts =
> +			imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts,
> +};
> +
> +static struct drm_bridge *
> +imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
> +{
> +	struct device_node *np = pl->dev->of_node;
> +	struct device_node *port, *ep, *remote;
> +	struct of_endpoint endpoint;
> +	struct drm_bridge *next_bridge[2], *err_bridge;
> +	u32 port_id, vld_port_id;
> +	int port_cnt = 0, ep_cnt = 0;
> +	int bridge_sel = 0;	/* select the first next bridge by default */
> +	int ret;
> +
> +	for (port_id = 1; port_id <= PL_MAX_MST_ADDR + 1; port_id++) {
> +		port = of_graph_get_port_by_id(np, port_id);
> +		if (!port)
> +			continue;
> +
> +		if (of_device_is_available(port)) {
> +			port_cnt++;
> +			vld_port_id = port_id;
> +		}
> +
> +		of_node_put(port);
> +	}
> +
> +	/* check the number of available output ports */
> +	if (port_cnt == 0) {
> +		DRM_DEV_ERROR(pl->dev, "no available output port\n");
> +		return ERR_PTR(-ENODEV);
> +	} else if (port_cnt > 1) {
> +		DRM_DEV_ERROR(pl->dev, "invalid available output ports: %d\n",
> +								port_cnt);
> +		return ERR_PTR(-ENOTSUPP);
> +	}
> +
> +	port = of_graph_get_port_by_id(np, vld_port_id);
> +	if (!port) {
> +		DRM_DEV_ERROR(pl->dev, "failed to get output port\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	for_each_available_child_of_node(port, ep) {

for_each_endpoint_of_node

> +		/* 2 available endpoints at most */
> +		if (++ep_cnt > 2) {
> +			DRM_DEV_ERROR(pl->dev,
> +				      "invalid available endpoints: %d\n",
> +									ep_cnt);

Not really the kernel's job to validate the DT. Just get endpoints 0 and 
1 if those are the 2 you want.

> +			err_bridge = ERR_PTR(-ENOTSUPP);
> +			of_node_put(ep);
> +			goto err;
> +		}
> +
> +		ret = of_graph_parse_endpoint(ep, &endpoint);
> +		if (ret) {
> +			DRM_DEV_ERROR(pl->dev, "failed to parse endpoint: %d\n",
> +									ret);
> +			err_bridge = ERR_PTR(ret);
> +			of_node_put(ep);
> +			goto err;
> +		}
> +
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote || !of_device_is_available(remote)) {
> +			DRM_DEV_ERROR(pl->dev,
> +				      "endpoint%u has no available remote\n",
> +								endpoint.id);
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-ENODEV);
> +			goto err;
> +		} else if (!of_device_is_available(remote->parent)) {
> +			DRM_DEV_ERROR(pl->dev,
> +				"endpoint%u remote parent is not available\n",
> +								endpoint.id);
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-ENODEV);
> +			goto err;
> +		}

Rewrite all this in terms of of_graph_get_remote_node(). It takes care 
of of_device_is_available checking for you.

> +
> +		next_bridge[ep_cnt - 1] = of_drm_find_bridge(remote);
> +		if (!next_bridge[ep_cnt - 1]) {
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-EPROBE_DEFER);
> +			goto err;
> +		}
> +
> +		/* specially select the next bridge with companion PXL2DPI */
> +		if (of_find_property(remote, "fsl,companion-pxl2dpi", NULL))
> +			bridge_sel = ep_cnt - 1;
> +
> +		of_node_put(remote);
> +	}
> +
> +	pl->mst_addr = vld_port_id - 1;
> +
> +	of_node_put(port);
> +
> +	return next_bridge[bridge_sel];
> +err:
> +	of_node_put(port);
> +
> +	return err_bridge;
> +}
> +
> +static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
> +{
> +	struct imx8qxp_pixel_link *pl;
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	int ret;
> +
> +	pl = devm_kzalloc(dev, sizeof(*pl), GFP_KERNEL);
> +	if (!pl)
> +		return -ENOMEM;
> +
> +	ret = imx_scu_get_handle(&pl->ipc_handle);
> +	if (ret) {
> +		if (ret != -EPROBE_DEFER)
> +			DRM_DEV_ERROR(dev, "failed to get SCU ipc handle: %d\n",
> +									ret);
> +		return ret;
> +	}
> +
> +	pl->id = of_alias_get_id(np, "dc_pl");

What's this needed for? I doubt aliases is the right thing to use here.

Rob

WARNING: multiple messages have this Message-ID (diff)
From: Rob Herring <robh@kernel.org>
To: Liu Ying <victor.liu@nxp.com>
Cc: devicetree@vger.kernel.org, jernej.skrabec@siol.net,
	Laurent.pinchart@ideasonboard.com, kernel@pengutronix.de,
	narmstrong@baylibre.com, airlied@linux.ie, festevam@gmail.com,
	s.hauer@pengutronix.de, jonas@kwiboo.se,
	linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	kishon@ti.com, a.hajda@samsung.com, vkoul@kernel.org,
	linux-imx@nxp.com, daniel@ffwll.ch, mchehab@kernel.org,
	shawnguo@kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-media@vger.kernel.org
Subject: Re: [PATCH 07/14] drm/bridge: imx: Add i.MX8qm/qxp display pixel link support
Date: Mon, 21 Dec 2020 15:29:55 -0700	[thread overview]
Message-ID: <20201221222955.GA652934@robh.at.kernel.org> (raw)
In-Reply-To: <1608199173-28760-8-git-send-email-victor.liu@nxp.com>

On Thu, Dec 17, 2020 at 05:59:26PM +0800, Liu Ying wrote:
> This patch adds a drm bridge driver for i.MX8qm/qxp display pixel link.
> The pixel link forms a standard asynchronous linkage between
> pixel sources(display controller or camera module) and pixel
> consumers(imaging or displays).  It consists of two distinct
> functions, a pixel transfer function and a control interface.
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/imx/Kconfig              |   8 +
>  drivers/gpu/drm/bridge/imx/Makefile             |   1 +
>  drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 411 ++++++++++++++++++++++++
>  3 files changed, 420 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> 
> diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
> index f1c91b6..4d1f027 100644
> --- a/drivers/gpu/drm/bridge/imx/Kconfig
> +++ b/drivers/gpu/drm/bridge/imx/Kconfig
> @@ -6,3 +6,11 @@ config DRM_IMX8QXP_PIXEL_COMBINER
>  	help
>  	  Choose this to enable pixel combiner found in
>  	  Freescale i.MX8qm/qxp processors.
> +
> +config DRM_IMX8QXP_PIXEL_LINK
> +	tristate "Freescale i.MX8QM/QXP display pixel link"
> +	depends on OF
> +	select DRM_KMS_HELPER
> +	help
> +	  Choose this to enable display pixel link found in
> +	  Freescale i.MX8qm/qxp processors.
> diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
> index 7d7c8d6..c15469f 100644
> --- a/drivers/gpu/drm/bridge/imx/Makefile
> +++ b/drivers/gpu/drm/bridge/imx/Makefile
> @@ -1 +1,2 @@
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
> +obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
> diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> new file mode 100644
> index 00000000..1af7467
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> @@ -0,0 +1,411 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright 2020 NXP
> + */
> +
> +#include <linux/firmware/imx/svc/misc.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_print.h>
> +
> +#include <dt-bindings/firmware/imx/rsrc.h>
> +
> +#define DRIVER_NAME		"imx8qxp-display-pixel-link"
> +#define PL_MAX_MST_ADDR		3
> +
> +struct imx8qxp_pixel_link {
> +	struct drm_bridge bridge;
> +	struct drm_bridge *next_bridge;
> +	struct device *dev;
> +	struct imx_sc_ipc *ipc_handle;
> +	int id;
> +	int stream_id;
> +	int dc_id;
> +	u32 sink_rsc;
> +	u32 mst_addr;
> +	u8 mst_addr_ctrl;
> +	u8 mst_en_ctrl;
> +	u8 mst_vld_ctrl;
> +	u8 sync_ctrl;
> +};
> +
> +#define DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(name)			\
> +static void								\
> +imx8qxp_pixel_link_enable_##name(struct imx8qxp_pixel_link *pl)		\
> +{									\
> +	int ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,	\
> +					  pl->name##_ctrl, true);	\
> +	if (ret)							\
> +		DRM_DEV_ERROR(pl->dev,					\
> +			"failed to enable DC%d stream%d pixel link "	\
> +			#name ": %d\n",	pl->dc_id, pl->stream_id, ret);	\
> +}
> +
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(mst_en)
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(mst_vld)
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(sync)
> +
> +#define DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(name)			\
> +static int								\
> +imx8qxp_pixel_link_disable_##name(struct imx8qxp_pixel_link *pl)	\
> +{									\
> +	int ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,	\
> +					  pl->name##_ctrl, false);	\
> +	if (ret)							\
> +		DRM_DEV_ERROR(pl->dev,					\
> +			"failed to disable DC%d stream%d pixel link "	\
> +			#name ": %d\n",	pl->dc_id, pl->stream_id, ret);	\
> +									\
> +	return ret;							\
> +}
> +
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(mst_en)
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(mst_vld)
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(sync)
> +
> +static void imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link *pl)
> +{
> +	int ret;
> +
> +	ret = imx_sc_misc_set_control(pl->ipc_handle,
> +				      pl->sink_rsc, pl->mst_addr_ctrl,
> +				      pl->mst_addr);
> +	if (ret)
> +		DRM_DEV_ERROR(pl->dev,
> +		    "failed to set DC%d stream%d pixel link mst addr(%u): %d\n",
> +		    pl->dc_id, pl->stream_id, pl->mst_addr, ret);
> +}
> +
> +static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
> +					    enum drm_bridge_attach_flags flags)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> +		DRM_DEV_ERROR(pl->dev,
> +			      "do not support creating a drm_connector\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!bridge->encoder) {
> +		DRM_DEV_ERROR(pl->dev, "missing encoder\n");
> +		return -ENODEV;
> +	}
> +
> +	return drm_bridge_attach(bridge->encoder,
> +				 pl->next_bridge, bridge,
> +				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +}
> +
> +static void
> +imx8qxp_pixel_link_bridge_mode_set(struct drm_bridge *bridge,
> +				   const struct drm_display_mode *mode,
> +				   const struct drm_display_mode *adjusted_mode)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_set_mst_addr(pl);
> +}
> +
> +static void imx8qxp_pixel_link_bridge_atomic_enable(struct drm_bridge *bridge,
> +			      struct drm_bridge_state *old_bridge_state)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_enable_mst_en(pl);
> +	imx8qxp_pixel_link_enable_mst_vld(pl);
> +	imx8qxp_pixel_link_enable_sync(pl);
> +}
> +
> +static void imx8qxp_pixel_link_bridge_atomic_disable(struct drm_bridge *bridge,
> +				struct drm_bridge_state *old_bridge_state)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_disable_mst_en(pl);
> +	imx8qxp_pixel_link_disable_mst_vld(pl);
> +	imx8qxp_pixel_link_disable_sync(pl);
> +}
> +
> +static const u32 imx8qxp_pixel_link_bus_output_fmts[] = {
> +	MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
> +	MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
> +};
> +
> +static bool imx8qxp_pixel_link_bus_output_fmt_supported(u32 fmt)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts); i++) {
> +		if (imx8qxp_pixel_link_bus_output_fmts[i] == fmt)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static u32 *
> +imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +
> +	if (!imx8qxp_pixel_link_bus_output_fmt_supported(output_fmt))
> +		return NULL;
> +
> +	*num_input_fmts = 1;
> +
> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> +	if (!input_fmts)
> +		return NULL;
> +
> +	input_fmts[0] = output_fmt;
> +
> +	return input_fmts;
> +}
> +
> +static u32 *
> +imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					unsigned int *num_output_fmts)
> +{
> +	*num_output_fmts = ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts);
> +	return kmemdup(imx8qxp_pixel_link_bus_output_fmts,
> +			sizeof(imx8qxp_pixel_link_bus_output_fmts), GFP_KERNEL);
> +}
> +
> +static const struct drm_bridge_funcs imx8qxp_pixel_link_bridge_funcs = {
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +	.attach			= imx8qxp_pixel_link_bridge_attach,
> +	.mode_set		= imx8qxp_pixel_link_bridge_mode_set,
> +	.atomic_enable		= imx8qxp_pixel_link_bridge_atomic_enable,
> +	.atomic_disable		= imx8qxp_pixel_link_bridge_atomic_disable,
> +	.atomic_get_input_bus_fmts =
> +			imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts,
> +	.atomic_get_output_bus_fmts =
> +			imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts,
> +};
> +
> +static struct drm_bridge *
> +imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
> +{
> +	struct device_node *np = pl->dev->of_node;
> +	struct device_node *port, *ep, *remote;
> +	struct of_endpoint endpoint;
> +	struct drm_bridge *next_bridge[2], *err_bridge;
> +	u32 port_id, vld_port_id;
> +	int port_cnt = 0, ep_cnt = 0;
> +	int bridge_sel = 0;	/* select the first next bridge by default */
> +	int ret;
> +
> +	for (port_id = 1; port_id <= PL_MAX_MST_ADDR + 1; port_id++) {
> +		port = of_graph_get_port_by_id(np, port_id);
> +		if (!port)
> +			continue;
> +
> +		if (of_device_is_available(port)) {
> +			port_cnt++;
> +			vld_port_id = port_id;
> +		}
> +
> +		of_node_put(port);
> +	}
> +
> +	/* check the number of available output ports */
> +	if (port_cnt == 0) {
> +		DRM_DEV_ERROR(pl->dev, "no available output port\n");
> +		return ERR_PTR(-ENODEV);
> +	} else if (port_cnt > 1) {
> +		DRM_DEV_ERROR(pl->dev, "invalid available output ports: %d\n",
> +								port_cnt);
> +		return ERR_PTR(-ENOTSUPP);
> +	}
> +
> +	port = of_graph_get_port_by_id(np, vld_port_id);
> +	if (!port) {
> +		DRM_DEV_ERROR(pl->dev, "failed to get output port\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	for_each_available_child_of_node(port, ep) {

for_each_endpoint_of_node

> +		/* 2 available endpoints at most */
> +		if (++ep_cnt > 2) {
> +			DRM_DEV_ERROR(pl->dev,
> +				      "invalid available endpoints: %d\n",
> +									ep_cnt);

Not really the kernel's job to validate the DT. Just get endpoints 0 and 
1 if those are the 2 you want.

> +			err_bridge = ERR_PTR(-ENOTSUPP);
> +			of_node_put(ep);
> +			goto err;
> +		}
> +
> +		ret = of_graph_parse_endpoint(ep, &endpoint);
> +		if (ret) {
> +			DRM_DEV_ERROR(pl->dev, "failed to parse endpoint: %d\n",
> +									ret);
> +			err_bridge = ERR_PTR(ret);
> +			of_node_put(ep);
> +			goto err;
> +		}
> +
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote || !of_device_is_available(remote)) {
> +			DRM_DEV_ERROR(pl->dev,
> +				      "endpoint%u has no available remote\n",
> +								endpoint.id);
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-ENODEV);
> +			goto err;
> +		} else if (!of_device_is_available(remote->parent)) {
> +			DRM_DEV_ERROR(pl->dev,
> +				"endpoint%u remote parent is not available\n",
> +								endpoint.id);
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-ENODEV);
> +			goto err;
> +		}

Rewrite all this in terms of of_graph_get_remote_node(). It takes care 
of of_device_is_available checking for you.

> +
> +		next_bridge[ep_cnt - 1] = of_drm_find_bridge(remote);
> +		if (!next_bridge[ep_cnt - 1]) {
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-EPROBE_DEFER);
> +			goto err;
> +		}
> +
> +		/* specially select the next bridge with companion PXL2DPI */
> +		if (of_find_property(remote, "fsl,companion-pxl2dpi", NULL))
> +			bridge_sel = ep_cnt - 1;
> +
> +		of_node_put(remote);
> +	}
> +
> +	pl->mst_addr = vld_port_id - 1;
> +
> +	of_node_put(port);
> +
> +	return next_bridge[bridge_sel];
> +err:
> +	of_node_put(port);
> +
> +	return err_bridge;
> +}
> +
> +static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
> +{
> +	struct imx8qxp_pixel_link *pl;
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	int ret;
> +
> +	pl = devm_kzalloc(dev, sizeof(*pl), GFP_KERNEL);
> +	if (!pl)
> +		return -ENOMEM;
> +
> +	ret = imx_scu_get_handle(&pl->ipc_handle);
> +	if (ret) {
> +		if (ret != -EPROBE_DEFER)
> +			DRM_DEV_ERROR(dev, "failed to get SCU ipc handle: %d\n",
> +									ret);
> +		return ret;
> +	}
> +
> +	pl->id = of_alias_get_id(np, "dc_pl");

What's this needed for? I doubt aliases is the right thing to use here.

Rob

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Rob Herring <robh@kernel.org>
To: Liu Ying <victor.liu@nxp.com>
Cc: devicetree@vger.kernel.org, jernej.skrabec@siol.net,
	Laurent.pinchart@ideasonboard.com, kernel@pengutronix.de,
	narmstrong@baylibre.com, airlied@linux.ie,
	s.hauer@pengutronix.de, jonas@kwiboo.se,
	linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	kishon@ti.com, a.hajda@samsung.com, vkoul@kernel.org,
	linux-imx@nxp.com, mchehab@kernel.org, shawnguo@kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-media@vger.kernel.org
Subject: Re: [PATCH 07/14] drm/bridge: imx: Add i.MX8qm/qxp display pixel link support
Date: Mon, 21 Dec 2020 15:29:55 -0700	[thread overview]
Message-ID: <20201221222955.GA652934@robh.at.kernel.org> (raw)
In-Reply-To: <1608199173-28760-8-git-send-email-victor.liu@nxp.com>

On Thu, Dec 17, 2020 at 05:59:26PM +0800, Liu Ying wrote:
> This patch adds a drm bridge driver for i.MX8qm/qxp display pixel link.
> The pixel link forms a standard asynchronous linkage between
> pixel sources(display controller or camera module) and pixel
> consumers(imaging or displays).  It consists of two distinct
> functions, a pixel transfer function and a control interface.
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/imx/Kconfig              |   8 +
>  drivers/gpu/drm/bridge/imx/Makefile             |   1 +
>  drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 411 ++++++++++++++++++++++++
>  3 files changed, 420 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> 
> diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig
> index f1c91b6..4d1f027 100644
> --- a/drivers/gpu/drm/bridge/imx/Kconfig
> +++ b/drivers/gpu/drm/bridge/imx/Kconfig
> @@ -6,3 +6,11 @@ config DRM_IMX8QXP_PIXEL_COMBINER
>  	help
>  	  Choose this to enable pixel combiner found in
>  	  Freescale i.MX8qm/qxp processors.
> +
> +config DRM_IMX8QXP_PIXEL_LINK
> +	tristate "Freescale i.MX8QM/QXP display pixel link"
> +	depends on OF
> +	select DRM_KMS_HELPER
> +	help
> +	  Choose this to enable display pixel link found in
> +	  Freescale i.MX8qm/qxp processors.
> diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile
> index 7d7c8d6..c15469f 100644
> --- a/drivers/gpu/drm/bridge/imx/Makefile
> +++ b/drivers/gpu/drm/bridge/imx/Makefile
> @@ -1 +1,2 @@
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
> +obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
> diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> new file mode 100644
> index 00000000..1af7467
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
> @@ -0,0 +1,411 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright 2020 NXP
> + */
> +
> +#include <linux/firmware/imx/svc/misc.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_print.h>
> +
> +#include <dt-bindings/firmware/imx/rsrc.h>
> +
> +#define DRIVER_NAME		"imx8qxp-display-pixel-link"
> +#define PL_MAX_MST_ADDR		3
> +
> +struct imx8qxp_pixel_link {
> +	struct drm_bridge bridge;
> +	struct drm_bridge *next_bridge;
> +	struct device *dev;
> +	struct imx_sc_ipc *ipc_handle;
> +	int id;
> +	int stream_id;
> +	int dc_id;
> +	u32 sink_rsc;
> +	u32 mst_addr;
> +	u8 mst_addr_ctrl;
> +	u8 mst_en_ctrl;
> +	u8 mst_vld_ctrl;
> +	u8 sync_ctrl;
> +};
> +
> +#define DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(name)			\
> +static void								\
> +imx8qxp_pixel_link_enable_##name(struct imx8qxp_pixel_link *pl)		\
> +{									\
> +	int ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,	\
> +					  pl->name##_ctrl, true);	\
> +	if (ret)							\
> +		DRM_DEV_ERROR(pl->dev,					\
> +			"failed to enable DC%d stream%d pixel link "	\
> +			#name ": %d\n",	pl->dc_id, pl->stream_id, ret);	\
> +}
> +
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(mst_en)
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(mst_vld)
> +DEFINE_IMX8QXP_PIXEL_LINK_ENABLE_CTRL(sync)
> +
> +#define DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(name)			\
> +static int								\
> +imx8qxp_pixel_link_disable_##name(struct imx8qxp_pixel_link *pl)	\
> +{									\
> +	int ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,	\
> +					  pl->name##_ctrl, false);	\
> +	if (ret)							\
> +		DRM_DEV_ERROR(pl->dev,					\
> +			"failed to disable DC%d stream%d pixel link "	\
> +			#name ": %d\n",	pl->dc_id, pl->stream_id, ret);	\
> +									\
> +	return ret;							\
> +}
> +
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(mst_en)
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(mst_vld)
> +DEFINE_IMX8QXP_PIXEL_LINK_DISABLE_CTRL(sync)
> +
> +static void imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link *pl)
> +{
> +	int ret;
> +
> +	ret = imx_sc_misc_set_control(pl->ipc_handle,
> +				      pl->sink_rsc, pl->mst_addr_ctrl,
> +				      pl->mst_addr);
> +	if (ret)
> +		DRM_DEV_ERROR(pl->dev,
> +		    "failed to set DC%d stream%d pixel link mst addr(%u): %d\n",
> +		    pl->dc_id, pl->stream_id, pl->mst_addr, ret);
> +}
> +
> +static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
> +					    enum drm_bridge_attach_flags flags)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> +		DRM_DEV_ERROR(pl->dev,
> +			      "do not support creating a drm_connector\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!bridge->encoder) {
> +		DRM_DEV_ERROR(pl->dev, "missing encoder\n");
> +		return -ENODEV;
> +	}
> +
> +	return drm_bridge_attach(bridge->encoder,
> +				 pl->next_bridge, bridge,
> +				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +}
> +
> +static void
> +imx8qxp_pixel_link_bridge_mode_set(struct drm_bridge *bridge,
> +				   const struct drm_display_mode *mode,
> +				   const struct drm_display_mode *adjusted_mode)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_set_mst_addr(pl);
> +}
> +
> +static void imx8qxp_pixel_link_bridge_atomic_enable(struct drm_bridge *bridge,
> +			      struct drm_bridge_state *old_bridge_state)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_enable_mst_en(pl);
> +	imx8qxp_pixel_link_enable_mst_vld(pl);
> +	imx8qxp_pixel_link_enable_sync(pl);
> +}
> +
> +static void imx8qxp_pixel_link_bridge_atomic_disable(struct drm_bridge *bridge,
> +				struct drm_bridge_state *old_bridge_state)
> +{
> +	struct imx8qxp_pixel_link *pl = bridge->driver_private;
> +
> +	imx8qxp_pixel_link_disable_mst_en(pl);
> +	imx8qxp_pixel_link_disable_mst_vld(pl);
> +	imx8qxp_pixel_link_disable_sync(pl);
> +}
> +
> +static const u32 imx8qxp_pixel_link_bus_output_fmts[] = {
> +	MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
> +	MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
> +};
> +
> +static bool imx8qxp_pixel_link_bus_output_fmt_supported(u32 fmt)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts); i++) {
> +		if (imx8qxp_pixel_link_bus_output_fmts[i] == fmt)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static u32 *
> +imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +
> +	if (!imx8qxp_pixel_link_bus_output_fmt_supported(output_fmt))
> +		return NULL;
> +
> +	*num_input_fmts = 1;
> +
> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> +	if (!input_fmts)
> +		return NULL;
> +
> +	input_fmts[0] = output_fmt;
> +
> +	return input_fmts;
> +}
> +
> +static u32 *
> +imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					unsigned int *num_output_fmts)
> +{
> +	*num_output_fmts = ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts);
> +	return kmemdup(imx8qxp_pixel_link_bus_output_fmts,
> +			sizeof(imx8qxp_pixel_link_bus_output_fmts), GFP_KERNEL);
> +}
> +
> +static const struct drm_bridge_funcs imx8qxp_pixel_link_bridge_funcs = {
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +	.attach			= imx8qxp_pixel_link_bridge_attach,
> +	.mode_set		= imx8qxp_pixel_link_bridge_mode_set,
> +	.atomic_enable		= imx8qxp_pixel_link_bridge_atomic_enable,
> +	.atomic_disable		= imx8qxp_pixel_link_bridge_atomic_disable,
> +	.atomic_get_input_bus_fmts =
> +			imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts,
> +	.atomic_get_output_bus_fmts =
> +			imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts,
> +};
> +
> +static struct drm_bridge *
> +imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
> +{
> +	struct device_node *np = pl->dev->of_node;
> +	struct device_node *port, *ep, *remote;
> +	struct of_endpoint endpoint;
> +	struct drm_bridge *next_bridge[2], *err_bridge;
> +	u32 port_id, vld_port_id;
> +	int port_cnt = 0, ep_cnt = 0;
> +	int bridge_sel = 0;	/* select the first next bridge by default */
> +	int ret;
> +
> +	for (port_id = 1; port_id <= PL_MAX_MST_ADDR + 1; port_id++) {
> +		port = of_graph_get_port_by_id(np, port_id);
> +		if (!port)
> +			continue;
> +
> +		if (of_device_is_available(port)) {
> +			port_cnt++;
> +			vld_port_id = port_id;
> +		}
> +
> +		of_node_put(port);
> +	}
> +
> +	/* check the number of available output ports */
> +	if (port_cnt == 0) {
> +		DRM_DEV_ERROR(pl->dev, "no available output port\n");
> +		return ERR_PTR(-ENODEV);
> +	} else if (port_cnt > 1) {
> +		DRM_DEV_ERROR(pl->dev, "invalid available output ports: %d\n",
> +								port_cnt);
> +		return ERR_PTR(-ENOTSUPP);
> +	}
> +
> +	port = of_graph_get_port_by_id(np, vld_port_id);
> +	if (!port) {
> +		DRM_DEV_ERROR(pl->dev, "failed to get output port\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	for_each_available_child_of_node(port, ep) {

for_each_endpoint_of_node

> +		/* 2 available endpoints at most */
> +		if (++ep_cnt > 2) {
> +			DRM_DEV_ERROR(pl->dev,
> +				      "invalid available endpoints: %d\n",
> +									ep_cnt);

Not really the kernel's job to validate the DT. Just get endpoints 0 and 
1 if those are the 2 you want.

> +			err_bridge = ERR_PTR(-ENOTSUPP);
> +			of_node_put(ep);
> +			goto err;
> +		}
> +
> +		ret = of_graph_parse_endpoint(ep, &endpoint);
> +		if (ret) {
> +			DRM_DEV_ERROR(pl->dev, "failed to parse endpoint: %d\n",
> +									ret);
> +			err_bridge = ERR_PTR(ret);
> +			of_node_put(ep);
> +			goto err;
> +		}
> +
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote || !of_device_is_available(remote)) {
> +			DRM_DEV_ERROR(pl->dev,
> +				      "endpoint%u has no available remote\n",
> +								endpoint.id);
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-ENODEV);
> +			goto err;
> +		} else if (!of_device_is_available(remote->parent)) {
> +			DRM_DEV_ERROR(pl->dev,
> +				"endpoint%u remote parent is not available\n",
> +								endpoint.id);
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-ENODEV);
> +			goto err;
> +		}

Rewrite all this in terms of of_graph_get_remote_node(). It takes care 
of of_device_is_available checking for you.

> +
> +		next_bridge[ep_cnt - 1] = of_drm_find_bridge(remote);
> +		if (!next_bridge[ep_cnt - 1]) {
> +			of_node_put(remote);
> +			of_node_put(ep);
> +			err_bridge = ERR_PTR(-EPROBE_DEFER);
> +			goto err;
> +		}
> +
> +		/* specially select the next bridge with companion PXL2DPI */
> +		if (of_find_property(remote, "fsl,companion-pxl2dpi", NULL))
> +			bridge_sel = ep_cnt - 1;
> +
> +		of_node_put(remote);
> +	}
> +
> +	pl->mst_addr = vld_port_id - 1;
> +
> +	of_node_put(port);
> +
> +	return next_bridge[bridge_sel];
> +err:
> +	of_node_put(port);
> +
> +	return err_bridge;
> +}
> +
> +static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
> +{
> +	struct imx8qxp_pixel_link *pl;
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	int ret;
> +
> +	pl = devm_kzalloc(dev, sizeof(*pl), GFP_KERNEL);
> +	if (!pl)
> +		return -ENOMEM;
> +
> +	ret = imx_scu_get_handle(&pl->ipc_handle);
> +	if (ret) {
> +		if (ret != -EPROBE_DEFER)
> +			DRM_DEV_ERROR(dev, "failed to get SCU ipc handle: %d\n",
> +									ret);
> +		return ret;
> +	}
> +
> +	pl->id = of_alias_get_id(np, "dc_pl");

What's this needed for? I doubt aliases is the right thing to use here.

Rob
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2020-12-21 22:30 UTC|newest]

Thread overview: 108+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-17  9:59 [PATCH 00/14] Add some DRM bridge drivers support for i.MX8qm/qxp SoCs Liu Ying
2020-12-17  9:59 ` Liu Ying
2020-12-17  9:59 ` Liu Ying
2020-12-17  9:59 ` [PATCH 01/14] phy: Add LVDS configuration options Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 02/14] media: uapi: Add some RGB bus formats for i.MX8qm/qxp pixel combiner Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 03/14] media: docs: " Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 04/14] dt-bindings: display: bridge: Add i.MX8qm/qxp pixel combiner binding Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17 18:50   ` Rob Herring
2020-12-17 18:50     ` Rob Herring
2020-12-17 18:50     ` Rob Herring
2020-12-18  1:45     ` Liu Ying
2020-12-18  1:45       ` Liu Ying
2020-12-18  1:45       ` Liu Ying
2020-12-18 22:42       ` Rob Herring
2020-12-18 22:42         ` Rob Herring
2020-12-18 22:42         ` Rob Herring
2020-12-19  4:15         ` Liu Ying
2020-12-19  4:15           ` Liu Ying
2020-12-19  4:15           ` Liu Ying
2020-12-21 17:02           ` Rob Herring
2020-12-21 17:02             ` Rob Herring
2020-12-21 17:02             ` Rob Herring
2020-12-22  2:44             ` Liu Ying
2020-12-22  2:44               ` Liu Ying
2020-12-22  2:44               ` Liu Ying
2020-12-21 22:07   ` Rob Herring
2020-12-21 22:07     ` Rob Herring
2020-12-21 22:07     ` Rob Herring
2020-12-22  2:59     ` Liu Ying
2020-12-22  2:59       ` Liu Ying
2020-12-22  2:59       ` Liu Ying
2020-12-17  9:59 ` [PATCH 05/14] drm/bridge: imx: Add i.MX8qm/qxp pixel combiner support Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 06/14] dt-bindings: display: bridge: Add i.MX8qm/qxp display pixel link binding Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-21 22:31   ` Rob Herring
2020-12-21 22:31     ` Rob Herring
2020-12-21 22:31     ` Rob Herring
2020-12-22  3:08     ` Liu Ying
2020-12-22  3:08       ` Liu Ying
2020-12-22  3:08       ` Liu Ying
2020-12-22  7:09   ` Laurent Pinchart
2020-12-22  7:09     ` Laurent Pinchart
2020-12-22  7:09     ` Laurent Pinchart
2020-12-22  9:12     ` Liu Ying
2020-12-22  9:12       ` Liu Ying
2020-12-22  9:12       ` Liu Ying
2020-12-17  9:59 ` [PATCH 07/14] drm/bridge: imx: Add i.MX8qm/qxp display pixel link support Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-21 22:29   ` Rob Herring [this message]
2020-12-21 22:29     ` Rob Herring
2020-12-21 22:29     ` Rob Herring
2020-12-22  9:47     ` Liu Ying
2020-12-22  9:47       ` Liu Ying
2020-12-22  9:47       ` Liu Ying
2020-12-17  9:59 ` [PATCH 08/14] dt-bindings: display: bridge: Add i.MX8qxp pixel link to DPI binding Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 09/14] drm/bridge: imx: Add i.MX8qxp pixel link to DPI support Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 10/14] drm/bridge: imx: Add LDB driver helper support Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 11/14] dt-bindings: display: bridge: Add i.MX8qm/qxp LVDS display bridge binding Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-21 22:33   ` Rob Herring
2020-12-21 22:33     ` Rob Herring
2020-12-21 22:33     ` Rob Herring
2020-12-22  3:48     ` Liu Ying
2020-12-22  3:48       ` Liu Ying
2020-12-22  3:48       ` Liu Ying
2020-12-22  7:36   ` Laurent Pinchart
2020-12-22  7:36     ` Laurent Pinchart
2020-12-22  7:36     ` Laurent Pinchart
2020-12-22  7:49     ` Laurent Pinchart
2020-12-22  7:49       ` Laurent Pinchart
2020-12-22  7:49       ` Laurent Pinchart
2020-12-22  8:27       ` Liu Ying
2020-12-22  8:27         ` Liu Ying
2020-12-22  8:27         ` Liu Ying
2020-12-22  9:00     ` Liu Ying
2020-12-22  9:00       ` Liu Ying
2020-12-22  9:00       ` Liu Ying
2020-12-17  9:59 ` [PATCH 12/14] drm/bridge: imx: Add LDB support for i.MX8qxp Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-22  9:52   ` Liu Ying
2020-12-22  9:52     ` Liu Ying
2020-12-22  9:52     ` Liu Ying
2020-12-17  9:59 ` [PATCH 13/14] drm/bridge: imx: Add LDB support for i.MX8qm Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59 ` [PATCH 14/14] MAINTAINERS: add maintainer for DRM bridge drivers for i.MX SoCs Liu Ying
2020-12-17  9:59   ` Liu Ying
2020-12-17  9:59   ` Liu Ying

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201221222955.GA652934@robh.at.kernel.org \
    --to=robh@kernel.org \
    --cc=Laurent.pinchart@ideasonboard.com \
    --cc=a.hajda@samsung.com \
    --cc=airlied@linux.ie \
    --cc=daniel@ffwll.ch \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=festevam@gmail.com \
    --cc=jernej.skrabec@siol.net \
    --cc=jonas@kwiboo.se \
    --cc=kernel@pengutronix.de \
    --cc=kishon@ti.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=narmstrong@baylibre.com \
    --cc=s.hauer@pengutronix.de \
    --cc=shawnguo@kernel.org \
    --cc=victor.liu@nxp.com \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.