Commit 12e671142daa5d4dce5961e6f573a8b740b16f88
Committed by
Tom Warren
1 parent
962f5caf60
Exists in
v2017.01-smarct4x
and in
34 other branches
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>
Showing 3 changed files with 279 additions and 0 deletions Side-by-side Diff
doc/device-tree-bindings/video/display-timing.txt
1 | +display-timing bindings | |
2 | +======================= | |
3 | + | |
4 | +display-timings node | |
5 | +-------------------- | |
6 | + | |
7 | +required properties: | |
8 | + - none | |
9 | + | |
10 | +optional properties: | |
11 | + - native-mode: The native mode for the display, in case multiple modes are | |
12 | + provided. When omitted, assume the first node is the native. | |
13 | + | |
14 | +timing subnode | |
15 | +-------------- | |
16 | + | |
17 | +required properties: | |
18 | + - hactive, vactive: display resolution | |
19 | + - hfront-porch, hback-porch, hsync-len: horizontal display timing parameters | |
20 | + in pixels | |
21 | + vfront-porch, vback-porch, vsync-len: vertical display timing parameters in | |
22 | + lines | |
23 | + - clock-frequency: display clock in Hz | |
24 | + | |
25 | +optional properties: | |
26 | + - hsync-active: hsync pulse is active low/high/ignored | |
27 | + - vsync-active: vsync pulse is active low/high/ignored | |
28 | + - de-active: data-enable pulse is active low/high/ignored | |
29 | + - pixelclk-active: with | |
30 | + - active high = drive pixel data on rising edge/ | |
31 | + sample data on falling edge | |
32 | + - active low = drive pixel data on falling edge/ | |
33 | + sample data on rising edge | |
34 | + - ignored = ignored | |
35 | + - interlaced (bool): boolean to enable interlaced mode | |
36 | + - doublescan (bool): boolean to enable doublescan mode | |
37 | + - doubleclk (bool): boolean to enable doubleclock mode | |
38 | + | |
39 | +All the optional properties that are not bool follow the following logic: | |
40 | + <1>: high active | |
41 | + <0>: low active | |
42 | + omitted: not used on hardware | |
43 | + | |
44 | +There are different ways of describing the capabilities of a display. The | |
45 | +devicetree representation corresponds to the one commonly found in datasheets | |
46 | +for displays. If a display supports multiple signal timings, the native-mode | |
47 | +can be specified. | |
48 | + | |
49 | +The parameters are defined as: | |
50 | + | |
51 | + +----------+-------------------------------------+----------+-------+ | |
52 | + | | โ | | | | |
53 | + | | |vback_porch | | | | |
54 | + | | โ | | | | |
55 | + +----------#######################################----------+-------+ | |
56 | + | # โ # | | | |
57 | + | # | # | | | |
58 | + | hback # | # hfront | hsync | | |
59 | + | porch # | hactive # porch | len | | |
60 | + |<-------->#<-------+--------------------------->#<-------->|<----->| | |
61 | + | # | # | | | |
62 | + | # |vactive # | | | |
63 | + | # | # | | | |
64 | + | # โ # | | | |
65 | + +----------#######################################----------+-------+ | |
66 | + | | โ | | | | |
67 | + | | |vfront_porch | | | | |
68 | + | | โ | | | | |
69 | + +----------+-------------------------------------+----------+-------+ | |
70 | + | | โ | | | | |
71 | + | | |vsync_len | | | | |
72 | + | | โ | | | | |
73 | + +----------+-------------------------------------+----------+-------+ | |
74 | + | |
75 | +Example: | |
76 | + | |
77 | + display-timings { | |
78 | + native-mode = <&timing0>; | |
79 | + timing0: 1080p24 { | |
80 | + /* 1920x1080p24 */ | |
81 | + clock-frequency = <52000000>; | |
82 | + hactive = <1920>; | |
83 | + vactive = <1080>; | |
84 | + hfront-porch = <25>; | |
85 | + hback-porch = <25>; | |
86 | + hsync-len = <25>; | |
87 | + vback-porch = <2>; | |
88 | + vfront-porch = <2>; | |
89 | + vsync-len = <2>; | |
90 | + hsync-active = <1>; | |
91 | + }; | |
92 | + }; | |
93 | + | |
94 | +Every required property also supports the use of ranges, so the commonly used | |
95 | +datasheet description with minimum, typical and maximum values can be used. | |
96 | + | |
97 | +Example: | |
98 | + | |
99 | + timing1: timing { | |
100 | + /* 1920x1080p24 */ | |
101 | + clock-frequency = <148500000>; | |
102 | + hactive = <1920>; | |
103 | + vactive = <1080>; | |
104 | + hsync-len = <0 44 60>; | |
105 | + hfront-porch = <80 88 95>; | |
106 | + hback-porch = <100 148 160>; | |
107 | + vfront-porch = <0 4 6>; | |
108 | + vback-porch = <0 36 50>; | |
109 | + vsync-len = <0 5 6>; | |
110 | + }; |
include/fdtdec.h
... | ... | @@ -802,6 +802,83 @@ |
802 | 802 | const char *mem_type, const char *suffix, |
803 | 803 | fdt_addr_t *basep, fdt_size_t *sizep); |
804 | 804 | |
805 | +/* Display timings from linux include/video/display_timing.h */ | |
806 | +enum display_flags { | |
807 | + DISPLAY_FLAGS_HSYNC_LOW = 1 << 0, | |
808 | + DISPLAY_FLAGS_HSYNC_HIGH = 1 << 1, | |
809 | + DISPLAY_FLAGS_VSYNC_LOW = 1 << 2, | |
810 | + DISPLAY_FLAGS_VSYNC_HIGH = 1 << 3, | |
811 | + | |
812 | + /* data enable flag */ | |
813 | + DISPLAY_FLAGS_DE_LOW = 1 << 4, | |
814 | + DISPLAY_FLAGS_DE_HIGH = 1 << 5, | |
815 | + /* drive data on pos. edge */ | |
816 | + DISPLAY_FLAGS_PIXDATA_POSEDGE = 1 << 6, | |
817 | + /* drive data on neg. edge */ | |
818 | + DISPLAY_FLAGS_PIXDATA_NEGEDGE = 1 << 7, | |
819 | + DISPLAY_FLAGS_INTERLACED = 1 << 8, | |
820 | + DISPLAY_FLAGS_DOUBLESCAN = 1 << 9, | |
821 | + DISPLAY_FLAGS_DOUBLECLK = 1 << 10, | |
822 | +}; | |
823 | + | |
824 | +/* | |
825 | + * A single signal can be specified via a range of minimal and maximal values | |
826 | + * with a typical value, that lies somewhere inbetween. | |
827 | + */ | |
828 | +struct timing_entry { | |
829 | + u32 min; | |
830 | + u32 typ; | |
831 | + u32 max; | |
832 | +}; | |
833 | + | |
834 | +/* | |
835 | + * Single "mode" entry. This describes one set of signal timings a display can | |
836 | + * have in one setting. This struct can later be converted to struct videomode | |
837 | + * (see include/video/videomode.h). As each timing_entry can be defined as a | |
838 | + * range, one struct display_timing may become multiple struct videomodes. | |
839 | + * | |
840 | + * Example: hsync active high, vsync active low | |
841 | + * | |
842 | + * Active Video | |
843 | + * Video ______________________XXXXXXXXXXXXXXXXXXXXXX_____________________ | |
844 | + * |<- sync ->|<- back ->|<----- active ----->|<- front ->|<- sync.. | |
845 | + * | | porch | | porch | | |
846 | + * | |
847 | + * HSync _|ยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏ|___________________________________________|ยฏยฏยฏยฏยฏยฏยฏยฏยฏ | |
848 | + * | |
849 | + * VSync ยฏ|__________|ยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏ|_________ | |
850 | + */ | |
851 | +struct display_timing { | |
852 | + struct timing_entry pixelclock; | |
853 | + | |
854 | + struct timing_entry hactive; /* hor. active video */ | |
855 | + struct timing_entry hfront_porch; /* hor. front porch */ | |
856 | + struct timing_entry hback_porch; /* hor. back porch */ | |
857 | + struct timing_entry hsync_len; /* hor. sync len */ | |
858 | + | |
859 | + struct timing_entry vactive; /* ver. active video */ | |
860 | + struct timing_entry vfront_porch; /* ver. front porch */ | |
861 | + struct timing_entry vback_porch; /* ver. back porch */ | |
862 | + struct timing_entry vsync_len; /* ver. sync len */ | |
863 | + | |
864 | + enum display_flags flags; /* display flags */ | |
865 | +}; | |
866 | + | |
867 | +/** | |
868 | + * fdtdec_decode_display_timing() - decode display timings | |
869 | + * | |
870 | + * Decode display timings from the supplied 'display-timings' node. | |
871 | + * See doc/device-tree-bindings/video/display-timing.txt for binding | |
872 | + * information. | |
873 | + * | |
874 | + * @param blob FDT blob | |
875 | + * @param node 'display-timing' node containing the timing subnodes | |
876 | + * @param index Index number to read (0=first timing subnode) | |
877 | + * @param config Place to put timings | |
878 | + * @return 0 if OK, -FDT_ERR_NOTFOUND if not found | |
879 | + */ | |
880 | +int fdtdec_decode_display_timing(const void *blob, int node, int index, | |
881 | + struct display_timing *config); | |
805 | 882 | /** |
806 | 883 | * Set up the device tree ready for use |
807 | 884 | */ |
lib/fdtdec.c
... | ... | @@ -1037,6 +1037,98 @@ |
1037 | 1037 | return 0; |
1038 | 1038 | } |
1039 | 1039 | |
1040 | +static int decode_timing_property(const void *blob, int node, const char *name, | |
1041 | + struct timing_entry *result) | |
1042 | +{ | |
1043 | + int length, ret = 0; | |
1044 | + const u32 *prop; | |
1045 | + | |
1046 | + prop = fdt_getprop(blob, node, name, &length); | |
1047 | + if (!prop) { | |
1048 | + debug("%s: could not find property %s\n", | |
1049 | + fdt_get_name(blob, node, NULL), name); | |
1050 | + return length; | |
1051 | + } | |
1052 | + | |
1053 | + if (length == sizeof(u32)) { | |
1054 | + result->typ = fdtdec_get_int(blob, node, name, 0); | |
1055 | + result->min = result->typ; | |
1056 | + result->max = result->typ; | |
1057 | + } else { | |
1058 | + ret = fdtdec_get_int_array(blob, node, name, &result->min, 3); | |
1059 | + } | |
1060 | + | |
1061 | + return ret; | |
1062 | +} | |
1063 | + | |
1064 | +int fdtdec_decode_display_timing(const void *blob, int parent, int index, | |
1065 | + struct display_timing *dt) | |
1066 | +{ | |
1067 | + int i, node, timings_node; | |
1068 | + u32 val = 0; | |
1069 | + int ret = 0; | |
1070 | + | |
1071 | + timings_node = fdt_subnode_offset(blob, parent, "display-timings"); | |
1072 | + if (timings_node < 0) | |
1073 | + return timings_node; | |
1074 | + | |
1075 | + for (i = 0, node = fdt_first_subnode(blob, timings_node); | |
1076 | + node > 0 && i != index; | |
1077 | + node = fdt_next_subnode(blob, node)) | |
1078 | + i++; | |
1079 | + | |
1080 | + if (node < 0) | |
1081 | + return node; | |
1082 | + | |
1083 | + memset(dt, 0, sizeof(*dt)); | |
1084 | + | |
1085 | + ret |= decode_timing_property(blob, node, "hback-porch", | |
1086 | + &dt->hback_porch); | |
1087 | + ret |= decode_timing_property(blob, node, "hfront-porch", | |
1088 | + &dt->hfront_porch); | |
1089 | + ret |= decode_timing_property(blob, node, "hactive", &dt->hactive); | |
1090 | + ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len); | |
1091 | + ret |= decode_timing_property(blob, node, "vback-porch", | |
1092 | + &dt->vback_porch); | |
1093 | + ret |= decode_timing_property(blob, node, "vfront-porch", | |
1094 | + &dt->vfront_porch); | |
1095 | + ret |= decode_timing_property(blob, node, "vactive", &dt->vactive); | |
1096 | + ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len); | |
1097 | + ret |= decode_timing_property(blob, node, "clock-frequency", | |
1098 | + &dt->pixelclock); | |
1099 | + | |
1100 | + dt->flags = 0; | |
1101 | + val = fdtdec_get_int(blob, node, "vsync-active", -1); | |
1102 | + if (val != -1) { | |
1103 | + dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH : | |
1104 | + DISPLAY_FLAGS_VSYNC_LOW; | |
1105 | + } | |
1106 | + val = fdtdec_get_int(blob, node, "hsync-active", -1); | |
1107 | + if (val != -1) { | |
1108 | + dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH : | |
1109 | + DISPLAY_FLAGS_HSYNC_LOW; | |
1110 | + } | |
1111 | + val = fdtdec_get_int(blob, node, "de-active", -1); | |
1112 | + if (val != -1) { | |
1113 | + dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH : | |
1114 | + DISPLAY_FLAGS_DE_LOW; | |
1115 | + } | |
1116 | + val = fdtdec_get_int(blob, node, "pixelclk-active", -1); | |
1117 | + if (val != -1) { | |
1118 | + dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : | |
1119 | + DISPLAY_FLAGS_PIXDATA_NEGEDGE; | |
1120 | + } | |
1121 | + | |
1122 | + if (fdtdec_get_bool(blob, node, "interlaced")) | |
1123 | + dt->flags |= DISPLAY_FLAGS_INTERLACED; | |
1124 | + if (fdtdec_get_bool(blob, node, "doublescan")) | |
1125 | + dt->flags |= DISPLAY_FLAGS_DOUBLESCAN; | |
1126 | + if (fdtdec_get_bool(blob, node, "doubleclk")) | |
1127 | + dt->flags |= DISPLAY_FLAGS_DOUBLECLK; | |
1128 | + | |
1129 | + return 0; | |
1130 | +} | |
1131 | + | |
1040 | 1132 | int fdtdec_setup(void) |
1041 | 1133 | { |
1042 | 1134 | #ifdef CONFIG_OF_CONTROL |