diff mbox

[3/4] drm/omap: Add virtual plane DT parsing support

Message ID 20180302134804.3690-4-bparrot@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Benoit Parrot March 2, 2018, 1:48 p.m. UTC
Virtual planes are used to extend display size capability for display
larger than 2048 pixels by splitting the frame buffer equally between
two physical planes.

Here we are adding DT support to parse 'plane' child nodes which
describe how logical planes are mapped to physical plane(s) and
which crtc they are available on.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 drivers/gpu/drm/omapdrm/dss/dispc.c   | 110 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/omapdrm/dss/omapdss.h |  11 ++++
 2 files changed, 121 insertions(+)

Comments

Tomi Valkeinen March 14, 2018, 11:11 a.m. UTC | #1
Hi Benoit,

On 02/03/18 15:48, Benoit Parrot wrote:
> Virtual planes are used to extend display size capability for display
> larger than 2048 pixels by splitting the frame buffer equally between
> two physical planes.
> 
> Here we are adding DT support to parse 'plane' child nodes which
> describe how logical planes are mapped to physical plane(s) and
> which crtc they are available on.
> 
> Signed-off-by: Benoit Parrot <bparrot@ti.com>
> ---
>  drivers/gpu/drm/omapdrm/dss/dispc.c   | 110 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/omapdrm/dss/omapdss.h |  11 ++++
>  2 files changed, 121 insertions(+)
> 
> diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
> index 624dee22f46b..559b70d9762d 100644
> --- a/drivers/gpu/drm/omapdrm/dss/dispc.c
> +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
> @@ -4334,6 +4334,115 @@ static u32 dispc_get_memory_bandwidth_limit(void)
>  	return limit;
>  }
>  
> +static struct device_node *dispc_of_get_plane_by_id(struct device_node *node,
> +						    u32 id)
> +{
> +	struct device_node *plane;
> +
> +	for_each_child_of_node(node, plane) {
> +		u32 plane_id = 0;
> +
> +		if (of_node_cmp(plane->name, "plane") != 0)
> +			continue;
> +		of_property_read_u32(plane, "reg", &plane_id);
> +		if (id == plane_id)
> +			break;

I think the flow is more readable, if here you "return plane", and at
the end of the func "return NULL".

> +	}
> +
> +	return plane;
> +}
> +
> +static int dispc_parse_dt_plane_data(struct dispc_plane_mappings *plane)

You could rename the parameter to "map", for example. Using 'plane'
there is quite confusing.

> +{
> +	struct platform_device *pdev = dispc.pdev;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *ep;
> +	struct property *prop;
> +	const __be32 *cur;
> +	u32 v;
> +	u32 num_ovls = dispc_get_num_ovls();
> +	unsigned long int hw_plane_mask = (1 << num_ovls) - 1;

u32?

> +	u32 num_planes;
> +	int i, index;
> +
> +	if (!np)
> +		return 0;
> +
> +	for (i = 0; i < num_ovls; i++) {
> +		ep = dispc_of_get_plane_by_id(np, i);
> +		if (!ep)
> +			break;
> +		if (!of_property_read_bool(ep, "hw-planes")) {
> +			dev_err(&pdev->dev,
> +				"malformed plane node: hw-planes missing.\n");
> +			return -EINVAL;
> +		}
> +
> +		index = 0;
> +		of_property_for_each_u32(ep, "hw-planes", prop, cur, v) {
> +			if (v >= num_ovls) {
> +				dev_err(&pdev->dev,
> +					"hw-planes property: '%d' out-of-range.\n",
> +					v);
> +				return -EINVAL;
> +			}
> +			if (!(hw_plane_mask & BIT_MASK(v))) {
> +				dev_err(&pdev->dev,
> +					"hw-planes property: '%d' used more than once.\n",
> +					v);
> +				return -EINVAL;
> +			}
> +			clear_bit(v, &hw_plane_mask);

Why do you use hw_plane_mask this way? It feels inverse to me, usually
one sets a bit when something is there. And e.g. crtc_mask here is used
the other way.

> +
> +			if (index == 0) {
> +				plane->plane[i].main_id = v;
> +			} else if (index == 1) {
> +				plane->plane[i].aux_id = v;
> +				plane->plane[i].is_virtual = true;
> +			} else if (index > 1) {
> +				dev_err(&pdev->dev,
> +					"hw-planes property: more than 2 values specified.\n");
> +				return -EINVAL;
> +			}
> +			index++;
> +		}
> +
> +		of_property_for_each_u32(ep, "hw-crtcs", prop, cur, v) {
> +			if (v >= num_ovls) {

This should check against num_ovl_mgrs.

> +				dev_err(&pdev->dev,
> +					"hw-crtcs property: '%d' out-of-range.\n",
> +					v);
> +				return -EINVAL;
> +			}
> +			plane->plane[i].crtc_mask |= 1 << v;
> +		}
> +	}
> +
> +	num_planes = i;
> +
> +	if (num_planes) {
> +		dev_dbg(&pdev->dev, "Plane definitions found from DT:");
> +		for (i = 0; i < num_planes; i++) {
> +			if (plane->plane[i].is_virtual) {
> +				dev_dbg(&pdev->dev,
> +					"plane%d: virtual hw-planes: %d, %d crtc_mask: 0x%04x",
> +					i, plane->plane[i].main_id,
> +					plane->plane[i].aux_id,
> +					plane->plane[i].crtc_mask);
> +			} else {
> +				dev_dbg(&pdev->dev,
> +					"plane%d: hw-planes: %d crtc_mask: 0x%04x",
> +					i, plane->plane[i].main_id,
> +					plane->plane[i].crtc_mask);
> +			}
> +		}
> +	}
> +
> +	plane->num_planes = num_planes;
> +
> +	return 0;
> +}
> +
>  /*
>   * Workaround for errata i734 in DSS dispc
>   *  - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
> @@ -4525,6 +4634,7 @@ static const struct dispc_ops dispc_ops = {
>  	.ovl_enable = dispc_ovl_enable,
>  	.ovl_setup = dispc_ovl_setup,
>  	.ovl_get_color_modes = dispc_ovl_get_color_modes,
> +	.get_plane_mapping = dispc_parse_dt_plane_data,
>  };
>  
>  /* DISPC HW IP initialisation */
> diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
> index f8f83e826a56..b8c9b30bf5ed 100644
> --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
> +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
> @@ -637,6 +637,16 @@ void omapdss_set_is_initialized(bool set);
>  struct device_node *dss_of_port_get_parent_device(struct device_node *port);
>  u32 dss_of_port_get_port_number(struct device_node *port);
>  
> +struct dispc_plane_mappings {
> +	struct {
> +		u32 main_id;
> +		u32 aux_id;
> +		u32 crtc_mask;
> +		bool	is_virtual;

is_virtual has a tab whereas the others don't.

 Tomi
diff mbox

Patch

diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index 624dee22f46b..559b70d9762d 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -4334,6 +4334,115 @@  static u32 dispc_get_memory_bandwidth_limit(void)
 	return limit;
 }
 
+static struct device_node *dispc_of_get_plane_by_id(struct device_node *node,
+						    u32 id)
+{
+	struct device_node *plane;
+
+	for_each_child_of_node(node, plane) {
+		u32 plane_id = 0;
+
+		if (of_node_cmp(plane->name, "plane") != 0)
+			continue;
+		of_property_read_u32(plane, "reg", &plane_id);
+		if (id == plane_id)
+			break;
+	}
+
+	return plane;
+}
+
+static int dispc_parse_dt_plane_data(struct dispc_plane_mappings *plane)
+{
+	struct platform_device *pdev = dispc.pdev;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *ep;
+	struct property *prop;
+	const __be32 *cur;
+	u32 v;
+	u32 num_ovls = dispc_get_num_ovls();
+	unsigned long int hw_plane_mask = (1 << num_ovls) - 1;
+	u32 num_planes;
+	int i, index;
+
+	if (!np)
+		return 0;
+
+	for (i = 0; i < num_ovls; i++) {
+		ep = dispc_of_get_plane_by_id(np, i);
+		if (!ep)
+			break;
+		if (!of_property_read_bool(ep, "hw-planes")) {
+			dev_err(&pdev->dev,
+				"malformed plane node: hw-planes missing.\n");
+			return -EINVAL;
+		}
+
+		index = 0;
+		of_property_for_each_u32(ep, "hw-planes", prop, cur, v) {
+			if (v >= num_ovls) {
+				dev_err(&pdev->dev,
+					"hw-planes property: '%d' out-of-range.\n",
+					v);
+				return -EINVAL;
+			}
+			if (!(hw_plane_mask & BIT_MASK(v))) {
+				dev_err(&pdev->dev,
+					"hw-planes property: '%d' used more than once.\n",
+					v);
+				return -EINVAL;
+			}
+			clear_bit(v, &hw_plane_mask);
+
+			if (index == 0) {
+				plane->plane[i].main_id = v;
+			} else if (index == 1) {
+				plane->plane[i].aux_id = v;
+				plane->plane[i].is_virtual = true;
+			} else if (index > 1) {
+				dev_err(&pdev->dev,
+					"hw-planes property: more than 2 values specified.\n");
+				return -EINVAL;
+			}
+			index++;
+		}
+
+		of_property_for_each_u32(ep, "hw-crtcs", prop, cur, v) {
+			if (v >= num_ovls) {
+				dev_err(&pdev->dev,
+					"hw-crtcs property: '%d' out-of-range.\n",
+					v);
+				return -EINVAL;
+			}
+			plane->plane[i].crtc_mask |= 1 << v;
+		}
+	}
+
+	num_planes = i;
+
+	if (num_planes) {
+		dev_dbg(&pdev->dev, "Plane definitions found from DT:");
+		for (i = 0; i < num_planes; i++) {
+			if (plane->plane[i].is_virtual) {
+				dev_dbg(&pdev->dev,
+					"plane%d: virtual hw-planes: %d, %d crtc_mask: 0x%04x",
+					i, plane->plane[i].main_id,
+					plane->plane[i].aux_id,
+					plane->plane[i].crtc_mask);
+			} else {
+				dev_dbg(&pdev->dev,
+					"plane%d: hw-planes: %d crtc_mask: 0x%04x",
+					i, plane->plane[i].main_id,
+					plane->plane[i].crtc_mask);
+			}
+		}
+	}
+
+	plane->num_planes = num_planes;
+
+	return 0;
+}
+
 /*
  * Workaround for errata i734 in DSS dispc
  *  - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
@@ -4525,6 +4634,7 @@  static const struct dispc_ops dispc_ops = {
 	.ovl_enable = dispc_ovl_enable,
 	.ovl_setup = dispc_ovl_setup,
 	.ovl_get_color_modes = dispc_ovl_get_color_modes,
+	.get_plane_mapping = dispc_parse_dt_plane_data,
 };
 
 /* DISPC HW IP initialisation */
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index f8f83e826a56..b8c9b30bf5ed 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -637,6 +637,16 @@  void omapdss_set_is_initialized(bool set);
 struct device_node *dss_of_port_get_parent_device(struct device_node *port);
 u32 dss_of_port_get_port_number(struct device_node *port);
 
+struct dispc_plane_mappings {
+	struct {
+		u32 main_id;
+		u32 aux_id;
+		u32 crtc_mask;
+		bool	is_virtual;
+	} plane[4];
+	u32 num_planes;
+};
+
 struct dss_mgr_ops {
 	int (*connect)(enum omap_channel channel,
 		struct omap_dss_device *dst);
@@ -719,6 +729,7 @@  struct dispc_ops {
 			enum omap_channel channel);
 
 	const u32 *(*ovl_get_color_modes)(enum omap_plane_id plane);
+	int (*get_plane_mapping)(struct dispc_plane_mappings *plane);
 };
 
 void dispc_set_ops(const struct dispc_ops *o);