Commit 12e671142daa5d4dce5961e6f573a8b740b16f88

Authored by Simon Glass
Committed by Tom Warren
1 parent 962f5caf60

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 + };
... ... @@ -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 */
... ... @@ -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