diff mbox

[U-Boot,v3,02/25] fdt: Add binding decode function for display-timings

Message ID 1423666338-6946-3-git-send-email-sjg@chromium.org
State Superseded
Delegated to: Tom Warren
Headers show

Commit Message

Simon Glass Feb. 11, 2015, 2:51 p.m. UTC
This is useful for display parameters. Add a simple decode function to read
from this device tree node.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 doc/device-tree-bindings/video/display-timing.txt | 110 ++++++++++++++++++++++
 include/fdtdec.h                                  |  80 ++++++++++++++++
 lib/fdtdec.c                                      |  92 ++++++++++++++++++
 3 files changed, 282 insertions(+)
 create mode 100644 doc/device-tree-bindings/video/display-timing.txt
diff mbox

Patch

diff --git a/doc/device-tree-bindings/video/display-timing.txt b/doc/device-tree-bindings/video/display-timing.txt
new file mode 100644
index 0000000..e1d4a0b
--- /dev/null
+++ b/doc/device-tree-bindings/video/display-timing.txt
@@ -0,0 +1,110 @@ 
+display-timing bindings
+=======================
+
+display-timings node
+--------------------
+
+required properties:
+ - none
+
+optional properties:
+ - native-mode: The native mode for the display, in case multiple modes are
+		provided. When omitted, assume the first node is the native.
+
+timing subnode
+--------------
+
+required properties:
+ - hactive, vactive: display resolution
+ - hfront-porch, hback-porch, hsync-len: horizontal display timing parameters
+   in pixels
+   vfront-porch, vback-porch, vsync-len: vertical display timing parameters in
+   lines
+ - clock-frequency: display clock in Hz
+
+optional properties:
+ - hsync-active: hsync pulse is active low/high/ignored
+ - vsync-active: vsync pulse is active low/high/ignored
+ - de-active: data-enable pulse is active low/high/ignored
+ - pixelclk-active: with
+			- active high = drive pixel data on rising edge/
+					sample data on falling edge
+			- active low  = drive pixel data on falling edge/
+					sample data on rising edge
+			- ignored     = ignored
+ - interlaced (bool): boolean to enable interlaced mode
+ - doublescan (bool): boolean to enable doublescan mode
+ - doubleclk (bool): boolean to enable doubleclock mode
+
+All the optional properties that are not bool follow the following logic:
+    <1>: high active
+    <0>: low active
+    omitted: not used on hardware
+
+There are different ways of describing the capabilities of a display. The
+devicetree representation corresponds to the one commonly found in datasheets
+for displays. If a display supports multiple signal timings, the native-mode
+can be specified.
+
+The parameters are defined as:
+
+  +----------+-------------------------------------+----------+-------+
+  |          |        ↑                            |          |       |
+  |          |        |vback_porch                 |          |       |
+  |          |        ↓                            |          |       |
+  +----------#######################################----------+-------+
+  |          #        ↑                            #          |       |
+  |          #        |                            #          |       |
+  |  hback   #        |                            #  hfront  | hsync |
+  |   porch  #        |       hactive              #  porch   |  len  |
+  |<-------->#<-------+--------------------------->#<-------->|<----->|
+  |          #        |                            #          |       |
+  |          #        |vactive                     #          |       |
+  |          #        |                            #          |       |
+  |          #        ↓                            #          |       |
+  +----------#######################################----------+-------+
+  |          |        ↑                            |          |       |
+  |          |        |vfront_porch                |          |       |
+  |          |        ↓                            |          |       |
+  +----------+-------------------------------------+----------+-------+
+  |          |        ↑                            |          |       |
+  |          |        |vsync_len                   |          |       |
+  |          |        ↓                            |          |       |
+  +----------+-------------------------------------+----------+-------+
+
+Example:
+
+	display-timings {
+		native-mode = <&timing0>;
+		timing0: 1080p24 {
+			/* 1920x1080p24 */
+			clock-frequency = <52000000>;
+			hactive = <1920>;
+			vactive = <1080>;
+			hfront-porch = <25>;
+			hback-porch = <25>;
+			hsync-len = <25>;
+			vback-porch = <2>;
+			vfront-porch = <2>;
+			vsync-len = <2>;
+			hsync-active = <1>;
+		};
+	};
+
+Every required property also supports the use of ranges, so the commonly used
+datasheet description with minimum, typical and maximum values can be used.
+
+Example:
+
+	timing1: timing {
+		/* 1920x1080p24 */
+		clock-frequency = <148500000>;
+		hactive = <1920>;
+		vactive = <1080>;
+		hsync-len = <0 44 60>;
+		hfront-porch = <80 88 95>;
+		hback-porch = <100 148 160>;
+		vfront-porch = <0 4 6>;
+		vback-porch = <0 36 50>;
+		vsync-len = <0 5 6>;
+	};
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 231eed7..4b0ebfb 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -777,4 +777,84 @@  int fdt_get_named_resource(const void *fdt, int node, const char *property,
 int fdtdec_decode_memory_region(const void *blob, int node,
 				const char *mem_type, const char *suffix,
 				fdt_addr_t *basep, fdt_size_t *sizep);
+
+#define BIT(pos)	(1U << pos)
+
+/* Display timings from linux include/video/display_timing.h */
+enum display_flags {
+	DISPLAY_FLAGS_HSYNC_LOW		= BIT(0),
+	DISPLAY_FLAGS_HSYNC_HIGH	= BIT(1),
+	DISPLAY_FLAGS_VSYNC_LOW		= BIT(2),
+	DISPLAY_FLAGS_VSYNC_HIGH	= BIT(3),
+
+	/* data enable flag */
+	DISPLAY_FLAGS_DE_LOW		= BIT(4),
+	DISPLAY_FLAGS_DE_HIGH		= BIT(5),
+	/* drive data on pos. edge */
+	DISPLAY_FLAGS_PIXDATA_POSEDGE	= BIT(6),
+	/* drive data on neg. edge */
+	DISPLAY_FLAGS_PIXDATA_NEGEDGE	= BIT(7),
+	DISPLAY_FLAGS_INTERLACED	= BIT(8),
+	DISPLAY_FLAGS_DOUBLESCAN	= BIT(9),
+	DISPLAY_FLAGS_DOUBLECLK		= BIT(10),
+};
+
+/*
+ * A single signal can be specified via a range of minimal and maximal values
+ * with a typical value, that lies somewhere inbetween.
+ */
+struct timing_entry {
+	u32 min;
+	u32 typ;
+	u32 max;
+};
+
+/*
+ * Single "mode" entry. This describes one set of signal timings a display can
+ * have in one setting. This struct can later be converted to struct videomode
+ * (see include/video/videomode.h). As each timing_entry can be defined as a
+ * range, one struct display_timing may become multiple struct videomodes.
+ *
+ * Example: hsync active high, vsync active low
+ *
+ *				    Active Video
+ * Video  ______________________XXXXXXXXXXXXXXXXXXXXXX_____________________
+ *	  |<- sync ->|<- back ->|<----- active ----->|<- front ->|<- sync..
+ *	  |	     |	 porch  |		     |	 porch	 |
+ *
+ * HSync _|¯¯¯¯¯¯¯¯¯¯|___________________________________________|¯¯¯¯¯¯¯¯¯
+ *
+ * VSync ¯|__________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|_________
+ */
+struct display_timing {
+	struct timing_entry pixelclock;
+
+	struct timing_entry hactive;		/* hor. active video */
+	struct timing_entry hfront_porch;	/* hor. front porch */
+	struct timing_entry hback_porch;	/* hor. back porch */
+	struct timing_entry hsync_len;		/* hor. sync len */
+
+	struct timing_entry vactive;		/* ver. active video */
+	struct timing_entry vfront_porch;	/* ver. front porch */
+	struct timing_entry vback_porch;	/* ver. back porch */
+	struct timing_entry vsync_len;		/* ver. sync len */
+
+	enum display_flags flags;		/* display flags */
+};
+
+/**
+ * fdtdec_decode_display_timing() - decode display timings
+ *
+ * Decode display timings from the supplied 'display-timings' node.
+ * See doc/device-tree-bindings/video/display-timing.txt for binding
+ * information.
+ *
+ * @param blob		FDT blob
+ * @param node		'display-timing' node containing the timing subnodes
+ * @param index		Index number to read (0=first timing subnode)
+ * @param config	Place to put timings
+ * @return 0 if OK, -FDT_ERR_NOTFOUND if not found
+ */
+int fdtdec_decode_display_timing(const void *blob, int node, int index,
+				 struct display_timing *config);
 #endif
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 5bf8f29..4755ca0 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1033,4 +1033,96 @@  int fdtdec_decode_memory_region(const void *blob, int config_node,
 
 	return 0;
 }
+
+static int decode_timing_property(const void *blob, int node, const char *name,
+				  struct timing_entry *result)
+{
+	int length, ret = 0;
+	const u32 *prop;
+
+	prop = fdt_getprop(blob, node, name, &length);
+	if (!prop) {
+		debug("%s: could not find property %s\n",
+		      fdt_get_name(blob, node, NULL), name);
+		return length;
+	}
+
+	if (length == sizeof(u32)) {
+		result->typ = fdtdec_get_int(blob, node, name, 0);
+		result->min = result->typ;
+		result->max = result->typ;
+	} else {
+		ret = fdtdec_get_int_array(blob, node, name, &result->min, 3);
+	}
+
+	return ret;
+}
+
+int fdtdec_decode_display_timing(const void *blob, int parent, int index,
+				 struct display_timing *dt)
+{
+	int i, node, timings_node;
+	u32 val = 0;
+	int ret = 0;
+
+	timings_node = fdt_subnode_offset(blob, parent, "display-timings");
+	if (timings_node < 0)
+		return timings_node;
+
+	for (i = 0, node = fdt_first_subnode(blob, timings_node);
+	     node > 0 && i != index;
+	     node = fdt_next_subnode(blob, node))
+		i++;
+
+	if (node < 0)
+		return node;
+
+	memset(dt, 0, sizeof(*dt));
+
+	ret |= decode_timing_property(blob, node, "hback-porch",
+				      &dt->hback_porch);
+	ret |= decode_timing_property(blob, node, "hfront-porch",
+				      &dt->hfront_porch);
+	ret |= decode_timing_property(blob, node, "hactive", &dt->hactive);
+	ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len);
+	ret |= decode_timing_property(blob, node, "vback-porch",
+				      &dt->vback_porch);
+	ret |= decode_timing_property(blob, node, "vfront-porch",
+				      &dt->vfront_porch);
+	ret |= decode_timing_property(blob, node, "vactive", &dt->vactive);
+	ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len);
+	ret |= decode_timing_property(blob, node, "clock-frequency",
+				      &dt->pixelclock);
+
+	dt->flags = 0;
+	val = fdtdec_get_int(blob, node, "vsync-active", -1);
+	if (val != -1) {
+		dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
+				DISPLAY_FLAGS_VSYNC_LOW;
+	}
+	val = fdtdec_get_int(blob, node, "hsync-active", -1);
+	if (val != -1) {
+		dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
+				DISPLAY_FLAGS_HSYNC_LOW;
+	}
+	val = fdtdec_get_int(blob, node, "de-active", -1);
+	if (val != -1) {
+		dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
+				DISPLAY_FLAGS_DE_LOW;
+	}
+	val = fdtdec_get_int(blob, node, "pixelclk-active", -1);
+	if (val != -1) {
+		dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
+				DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+	}
+
+	if (fdtdec_get_bool(blob, node, "interlaced"))
+		dt->flags |= DISPLAY_FLAGS_INTERLACED;
+	if (fdtdec_get_bool(blob, node, "doublescan"))
+		dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+	if (fdtdec_get_bool(blob, node, "doubleclk"))
+		dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
+
+	return 0;
+}
 #endif