lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Fri, 14 Aug 2015 16:50:19 +0100
From:	Srinivas Kandagatla <srinivas.kandagatla@...aro.org>
To:	Thierry Reding <thierry.reding@...il.com>,
	dri-devel@...ts.freedesktop.org
Cc:	David Airlie <airlied@...ux.ie>, linux-kernel@...r.kernel.org,
	linux-arm-msm@...r.kernel.org, robdclark@...il.com, bjorn@...o.se,
	Srinivas Kandagatla <srinivas.kandagatla@...aro.org>
Subject: [PATCH RFC 3/5] drm/panel: simple-panel: Add panel picker support.

This patch adds panel picker support to simple-panel.

The idea of panel picker is to select the correct panel timings if it
supports probing edid via DDC bus, edid contains manufacture ID
and Manufacturer product code, so it can match against the panel_picker
entries to get the correct panel timings.

>From DT point of view the panel picker uses generic compatible string
"panel-simple", keeping the panel specific compatible strings still
supported.

Panels can be static entry in the DT, but practically development boards
like IFC6410 where developers can connect any LVDS panel which makes it
difficult to maintian the dt support for those panels in dts file.
With this dynamic probing via panel picker makes it easy to support such
use-cases.
This patch also adds panel presence detection based, if there is no
panel detected or panel picker could not find the panel then the driver
would mark the panel DT node as disabled so that the drm driver would
be able to take right decision based on that panel node status.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@...aro.org>
---
 drivers/gpu/drm/panel/panel-simple.c | 83 +++++++++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index f94201b..6c503b2 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -32,6 +32,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
+#include <drm/drm_edid.h>
 
 #include <video/display_timing.h>
 #include <video/videomode.h>
@@ -70,6 +71,18 @@ struct panel_desc {
 	u32 bus_format;
 };
 
+#define PANEL_PICKER_ENTRY(vend, pid, pdesc) \
+		.vendor = vend, \
+		.product_id = (pid), \
+		.data = (pdesc)
+
+/* Panel picker entry with vendor and product id */
+struct panel_picker_entry {
+	char vendor[4]; /* Vendor string */
+	int product_id; /* product id field */
+	const struct panel_desc *data;
+};
+
 struct panel_simple {
 	struct drm_panel base;
 	bool prepared;
@@ -84,6 +97,8 @@ struct panel_simple {
 	struct gpio_desc *enable_gpio;
 };
 
+static const struct panel_desc *panel_picker_find_panel(struct edid *edid);
+
 static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
 {
 	return container_of(panel, struct panel_simple, base);
@@ -276,11 +291,28 @@ static const struct drm_panel_funcs panel_simple_funcs = {
 	.get_timings = panel_simple_get_timings,
 };
 
+static void __init simple_panel_node_disable(struct device_node *node)
+{
+	struct property *prop;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		return;
+
+	prop->name = "status";
+	prop->value = "disabled";
+	prop->length = strlen((char *)prop->value)+1;
+
+	of_update_property(node, prop);
+}
+
+
 static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 {
 	struct device_node *backlight, *ddc;
 	struct panel_simple *panel;
 	int err;
+	struct edid *edid;
 
 	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
 	if (!panel)
@@ -288,7 +320,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 
 	panel->enabled = false;
 	panel->prepared = false;
-	panel->desc = desc;
 
 	panel->supply = devm_regulator_get(dev, "power");
 	if (IS_ERR(panel->supply))
@@ -316,7 +347,25 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 		panel->ddc = of_find_i2c_adapter_by_node(ddc);
 		of_node_put(ddc);
 
-		if (!panel->ddc) {
+		if (panel->ddc) {
+			/* detect panel presence */
+			if (!drm_probe_ddc(panel->ddc)) {
+				err = -ENODEV;
+				goto nodev;
+			}
+
+			/* get panel from edid */
+			if (of_device_is_compatible(dev->of_node,
+						"panel-simple")) {
+				edid = drm_get_edid_early(panel->ddc);
+				if (edid) {
+					desc = panel_picker_find_panel(edid);
+				} else {
+					err = -ENODEV;
+					goto nodev;
+				}
+			}
+		} else {
 			err = -EPROBE_DEFER;
 			goto free_backlight;
 		}
@@ -325,6 +374,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 	drm_panel_init(&panel->base);
 	panel->base.dev = dev;
 	panel->base.funcs = &panel_simple_funcs;
+	panel->desc = desc;
 
 	err = drm_panel_add(&panel->base);
 	if (err < 0)
@@ -334,6 +384,10 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 
 	return 0;
 
+nodev:
+	/* mark the dt as disabled */
+	simple_panel_node_disable(dev->of_node);
+
 free_ddc:
 	if (panel->ddc)
 		put_device(&panel->ddc->dev);
@@ -1036,6 +1090,10 @@ static const struct panel_desc shelly_sca07010_bfn_lnn = {
 	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
 };
 
+static const struct panel_picker_entry panel_picker_list[] = {
+	{ PANEL_PICKER_ENTRY("AUO", 0x10dc, &auo_b101xtn01) },
+};
+
 static const struct of_device_id platform_of_match[] = {
 	{
 		.compatible = "ampire,am800480r3tmqwa1h",
@@ -1125,11 +1183,32 @@ static const struct of_device_id platform_of_match[] = {
 		.compatible = "shelly,sca07010-bfn-lnn",
 		.data = &shelly_sca07010_bfn_lnn,
 	}, {
+		/* Panel Picker Vendor ID and Product ID based Lookup */
+		.compatible = "panel-simple",
+	}, {
 		/* sentinel */
 	}
 };
 MODULE_DEVICE_TABLE(of, platform_of_match);
 
+static const struct panel_desc *panel_picker_find_panel(struct edid *edid)
+{
+	int i;
+	const struct panel_desc *desc = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(panel_picker_list); i++) {
+		const struct panel_picker_entry *vp = &panel_picker_list[i];
+
+		if (edid_vendor(edid, (char *)vp->vendor) &&
+				(EDID_PRODUCT_ID(edid) == vp->product_id)) {
+			desc = vp->data;
+			break;
+		}
+	}
+
+	return desc;
+}
+
 static int panel_simple_platform_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *id;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ