fdt: Add binding decode function for display-timings
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> Signed-off-by: Tom Warren <twarren@nvidia.com>
This commit is contained in:
parent
962f5caf60
commit
12e671142d
110
doc/device-tree-bindings/video/display-timing.txt
Normal file
110
doc/device-tree-bindings/video/display-timing.txt
Normal file
@ -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>;
|
||||
};
|
@ -802,6 +802,83 @@ 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);
|
||||
|
||||
/* Display timings from linux include/video/display_timing.h */
|
||||
enum display_flags {
|
||||
DISPLAY_FLAGS_HSYNC_LOW = 1 << 0,
|
||||
DISPLAY_FLAGS_HSYNC_HIGH = 1 << 1,
|
||||
DISPLAY_FLAGS_VSYNC_LOW = 1 << 2,
|
||||
DISPLAY_FLAGS_VSYNC_HIGH = 1 << 3,
|
||||
|
||||
/* data enable flag */
|
||||
DISPLAY_FLAGS_DE_LOW = 1 << 4,
|
||||
DISPLAY_FLAGS_DE_HIGH = 1 << 5,
|
||||
/* drive data on pos. edge */
|
||||
DISPLAY_FLAGS_PIXDATA_POSEDGE = 1 << 6,
|
||||
/* drive data on neg. edge */
|
||||
DISPLAY_FLAGS_PIXDATA_NEGEDGE = 1 << 7,
|
||||
DISPLAY_FLAGS_INTERLACED = 1 << 8,
|
||||
DISPLAY_FLAGS_DOUBLESCAN = 1 << 9,
|
||||
DISPLAY_FLAGS_DOUBLECLK = 1 << 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);
|
||||
/**
|
||||
* Set up the device tree ready for use
|
||||
*/
|
||||
|
92
lib/fdtdec.c
92
lib/fdtdec.c
@ -1037,6 +1037,98 @@ 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;
|
||||
}
|
||||
|
||||
int fdtdec_setup(void)
|
||||
{
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
|
Loading…
Reference in New Issue
Block a user