mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-21 22:51:37 +00:00
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
3 changed files with 279 additions and 0 deletions
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,
|
const char *mem_type, const char *suffix,
|
||||||
fdt_addr_t *basep, fdt_size_t *sizep);
|
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
|
* 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;
|
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)
|
int fdtdec_setup(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_OF_CONTROL
|
#ifdef CONFIG_OF_CONTROL
|
||||||
|
|
Loading…
Add table
Reference in a new issue