diff mbox series

[4.4.y-cip,5/9] drm: rcar-du: Support panels connected directly to the DPAD outputs

Message ID 20200728104330.6182-6-biju.das.jz@bp.renesas.com (mailing list archive)
State Accepted
Delegated to: Nobuhiro Iwamatsu
Headers show
Series Add LCD Panel support for RZ/G1E board | expand

Commit Message

Biju Das July 28, 2020, 10:43 a.m. UTC
The DPAD outputs can be connected directly to a panel. To support this
use case, detect whether the entities connected to the DU DPAD outputs
are panels based on the number of ports of their DT node, and retrieve
the corresponding type of DRM objects.

This patch is based on the commit 73eb5476df72
("Support panels connected directly to the DPAD outputs") and
commit 56c5dd00f8db ("drm/rcar-du: Split LVDS encoder and connector")

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 drivers/gpu/drm/rcar-du/Makefile          |   1 +
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c |  36 ++++++++
 drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c  | 105 ++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h  |  22 +++++
 4 files changed, 164 insertions(+)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h
diff mbox series

Patch

diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 05de1c4097af..51b7ccc66cb7 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -4,6 +4,7 @@  rcar-du-drm-y := rcar_du_crtc.o \
 		 rcar_du_group.o \
 		 rcar_du_kms.o \
 		 rcar_du_lvdscon.o \
+		 rcar_du_rgbcon.o \
 		 rcar_du_plane.o \
 		 rcar_du_vgacon.o
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index d0ae1e8009c6..c407fd4c98ce 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -16,6 +16,7 @@ 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
 
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
@@ -23,6 +24,7 @@ 
 #include "rcar_du_hdmienc.h"
 #include "rcar_du_kms.h"
 #include "rcar_du_lvdscon.h"
+#include "rcar_du_rgbcon.h"
 #include "rcar_du_lvdsenc.h"
 #include "rcar_du_vgacon.h"
 
@@ -42,6 +44,26 @@  rcar_du_connector_best_encoder(struct drm_connector *connector)
  * Encoder
  */
 
+static unsigned int rcar_du_encoder_count_ports(struct device_node *node)
+{
+	struct device_node *ports;
+	struct device_node *port;
+	unsigned int num_ports = 0;
+
+	ports = of_get_child_by_name(node, "ports");
+	if (!ports)
+		ports = of_node_get(node);
+
+	for_each_child_of_node(ports, port) {
+		if (of_node_name_eq(port, "port"))
+			num_ports++;
+	}
+
+	of_node_put(ports);
+
+	return num_ports;
+}
+
 static void rcar_du_encoder_disable(struct drm_encoder *encoder)
 {
 	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
@@ -127,6 +149,7 @@  int rcar_du_encoder_init(struct rcar_du_device *rcdu,
 {
 	struct rcar_du_encoder *renc;
 	struct drm_encoder *encoder;
+	struct drm_panel *panel;
 	unsigned int encoder_type;
 	int ret;
 
@@ -193,6 +216,19 @@  int rcar_du_encoder_init(struct rcar_du_device *rcdu,
 		ret = rcar_du_hdmi_connector_init(rcdu, renc);
 		break;
 
+	case DRM_MODE_ENCODER_NONE:
+		if ((output == RCAR_DU_OUTPUT_DPAD0 ||
+		     output == RCAR_DU_OUTPUT_DPAD1) &&
+		    rcar_du_encoder_count_ports(con_node) == 1) {
+			panel = of_drm_find_panel(con_node);
+			if (!panel)
+				ret = -EPROBE_DEFER;
+			else
+				ret = rcar_du_rgb_connector_init(rcdu, renc,
+								 panel);
+		}
+		break;
+
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c
new file mode 100644
index 000000000000..f62073e65f03
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c
@@ -0,0 +1,105 @@ 
+/*
+ * rcar_du_rgbcon.c  --  R-Car Display Unit RGB Connector
+ *
+ * Copyright (C) 2013-2020 Renesas Electronics Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include "rcar_du_drv.h"
+#include "rcar_du_encoder.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_rgbcon.h"
+
+struct rcar_du_rgb_connector {
+	struct rcar_du_connector connector;
+	struct drm_panel *drmpanel;
+};
+
+#define to_rcar_rgb_connector(c) \
+	container_of(c, struct rcar_du_rgb_connector, connector.connector)
+
+static int rcar_du_rgb_connector_get_modes(struct drm_connector *connector)
+{
+	struct rcar_du_rgb_connector *rgbcon =
+		to_rcar_rgb_connector(connector);
+
+	return drm_panel_get_modes(rgbcon->drmpanel);
+}
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+	.get_modes = rcar_du_rgb_connector_get_modes,
+	.best_encoder = rcar_du_connector_best_encoder,
+};
+
+static enum drm_connector_status
+rcar_du_rgb_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void rcar_du_rgb_connector_destroy(struct drm_connector *connector)
+{
+	struct rcar_du_rgb_connector *rgbcon =
+		to_rcar_rgb_connector(connector);
+
+	drm_panel_detach(rgbcon->drmpanel);
+	drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = rcar_du_rgb_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = rcar_du_rgb_connector_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+int rcar_du_rgb_connector_init(struct rcar_du_device *rcdu,
+			       struct rcar_du_encoder *renc,
+			       struct drm_panel *drmpanel)
+{
+	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
+	struct rcar_du_rgb_connector *rgbcon;
+	struct drm_connector *connector;
+	int ret;
+
+	rgbcon = devm_kzalloc(rcdu->dev, sizeof(*rgbcon), GFP_KERNEL);
+	if (!rgbcon)
+		return -ENOMEM;
+
+	rgbcon->drmpanel = drmpanel;
+	connector = &rgbcon->connector.connector;
+	ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
+				 DRM_MODE_CONNECTOR_DPI);
+	if (ret < 0)
+		return ret;
+
+	drm_connector_helper_add(connector, &connector_helper_funcs);
+
+	connector->dpms = DRM_MODE_DPMS_OFF;
+	drm_object_property_set_value(&connector->base,
+				      rcdu->ddev->mode_config.dpms_property,
+				      DRM_MODE_DPMS_OFF);
+
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
+	if (ret < 0)
+		return ret;
+
+	drm_panel_attach(rgbcon->drmpanel, connector);
+	rgbcon->connector.encoder = renc;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h
new file mode 100644
index 000000000000..b3bfad52f589
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h
@@ -0,0 +1,22 @@ 
+/*
+ * rcar_du_rgbcon.h  --  R-Car Display Unit RGB Connector
+ *
+ * Copyright (C) 2013-2020 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_RGBCON_H__
+#define __RCAR_DU_RGBCON_H__
+
+struct rcar_du_device;
+struct rcar_du_encoder;
+
+int rcar_du_rgb_connector_init(struct rcar_du_device *rcdu,
+			       struct rcar_du_encoder *renc,
+			       struct drm_panel *drmpanel);
+
+#endif /* __RCAR_DU_RGBCON_H__ */