Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

video: add of helper for display timings/videomode

This adds support for reading display timings from DT into a struct
display_timings. The of_display_timing implementation supports multiple
subnodes. All children are read into an array, that can be queried.

If no native mode is specified, the first subnode will be used.

For cases where the graphics driver knows there can be only one
mode description or where the driver only supports one mode, a helper
function of_get_videomode is added, that gets a struct videomode from DT.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de>
Acked-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Afzal Mohammed <Afzal@ti.com>
Tested-by: Rob Clark <robclark@gmail.com>
Tested-by: Leela Krishna Amudala <leelakrishna.a@gmail.com>

+457
+109
Documentation/devicetree/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 + 38 + All the optional properties that are not bool follow the following logic: 39 + <1>: high active 40 + <0>: low active 41 + omitted: not used on hardware 42 + 43 + There are different ways of describing the capabilities of a display. The 44 + devicetree representation corresponds to the one commonly found in datasheets 45 + for displays. If a display supports multiple signal timings, the native-mode 46 + can be specified. 47 + 48 + The parameters are defined as: 49 + 50 + +----------+-------------------------------------+----------+-------+ 51 + | | ↑ | | | 52 + | | |vback_porch | | | 53 + | | ↓ | | | 54 + +----------#######################################----------+-------+ 55 + | # ↑ # | | 56 + | # | # | | 57 + | hback # | # hfront | hsync | 58 + | porch # | hactive # porch | len | 59 + |<-------->#<-------+--------------------------->#<-------->|<----->| 60 + | # | # | | 61 + | # |vactive # | | 62 + | # | # | | 63 + | # ↓ # | | 64 + +----------#######################################----------+-------+ 65 + | | ↑ | | | 66 + | | |vfront_porch | | | 67 + | | ↓ | | | 68 + +----------+-------------------------------------+----------+-------+ 69 + | | ↑ | | | 70 + | | |vsync_len | | | 71 + | | ↓ | | | 72 + +----------+-------------------------------------+----------+-------+ 73 + 74 + Example: 75 + 76 + display-timings { 77 + native-mode = <&timing0>; 78 + timing0: 1080p24 { 79 + /* 1920x1080p24 */ 80 + clock-frequency = <52000000>; 81 + hactive = <1920>; 82 + vactive = <1080>; 83 + hfront-porch = <25>; 84 + hback-porch = <25>; 85 + hsync-len = <25>; 86 + vback-porch = <2>; 87 + vfront-porch = <2>; 88 + vsync-len = <2>; 89 + hsync-active = <1>; 90 + }; 91 + }; 92 + 93 + Every required property also supports the use of ranges, so the commonly used 94 + datasheet description with minimum, typical and maximum values can be used. 95 + 96 + Example: 97 + 98 + timing1: timing { 99 + /* 1920x1080p24 */ 100 + clock-frequency = <148500000>; 101 + hactive = <1920>; 102 + vactive = <1080>; 103 + hsync-len = <0 44 60>; 104 + hfront-porch = <80 88 95>; 105 + hback-porch = <100 148 160>; 106 + vfront-porch = <0 4 6>; 107 + vback-porch = <0 36 50>; 108 + vsync-len = <0 5 6>; 109 + };
+15
drivers/video/Kconfig
··· 39 39 config VIDEOMODE 40 40 bool 41 41 42 + config OF_DISPLAY_TIMING 43 + bool "Enable device tree display timing support" 44 + depends on OF 45 + select DISPLAY_TIMING 46 + help 47 + helper to parse display timings from the devicetree 48 + 49 + config OF_VIDEOMODE 50 + bool "Enable device tree videomode support" 51 + depends on OF 52 + select VIDEOMODE 53 + select OF_DISPLAY_TIMING 54 + help 55 + helper to get videomodes from the devicetree 56 + 42 57 menuconfig FB 43 58 tristate "Support for frame buffer devices" 44 59 ---help---
+2
drivers/video/Makefile
··· 169 169 #video output switch sysfs driver 170 170 obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o 171 171 obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o 172 + obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o 172 173 obj-$(CONFIG_VIDEOMODE) += videomode.o 174 + obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
+239
drivers/video/of_display_timing.c
··· 1 + /* 2 + * OF helpers for parsing display timings 3 + * 4 + * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix 5 + * 6 + * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de> 7 + * 8 + * This file is released under the GPLv2 9 + */ 10 + #include <linux/export.h> 11 + #include <linux/of.h> 12 + #include <linux/slab.h> 13 + #include <video/display_timing.h> 14 + #include <video/of_display_timing.h> 15 + 16 + /** 17 + * parse_timing_property - parse timing_entry from device_node 18 + * @np: device_node with the property 19 + * @name: name of the property 20 + * @result: will be set to the return value 21 + * 22 + * DESCRIPTION: 23 + * Every display_timing can be specified with either just the typical value or 24 + * a range consisting of min/typ/max. This function helps handling this 25 + **/ 26 + static int parse_timing_property(struct device_node *np, const char *name, 27 + struct timing_entry *result) 28 + { 29 + struct property *prop; 30 + int length, cells, ret; 31 + 32 + prop = of_find_property(np, name, &length); 33 + if (!prop) { 34 + pr_err("%s: could not find property %s\n", 35 + of_node_full_name(np), name); 36 + return -EINVAL; 37 + } 38 + 39 + cells = length / sizeof(u32); 40 + if (cells == 1) { 41 + ret = of_property_read_u32(np, name, &result->typ); 42 + result->min = result->typ; 43 + result->max = result->typ; 44 + } else if (cells == 3) { 45 + ret = of_property_read_u32_array(np, name, &result->min, cells); 46 + } else { 47 + pr_err("%s: illegal timing specification in %s\n", 48 + of_node_full_name(np), name); 49 + return -EINVAL; 50 + } 51 + 52 + return ret; 53 + } 54 + 55 + /** 56 + * of_get_display_timing - parse display_timing entry from device_node 57 + * @np: device_node with the properties 58 + **/ 59 + static struct display_timing *of_get_display_timing(struct device_node *np) 60 + { 61 + struct display_timing *dt; 62 + u32 val = 0; 63 + int ret = 0; 64 + 65 + dt = kzalloc(sizeof(*dt), GFP_KERNEL); 66 + if (!dt) { 67 + pr_err("%s: could not allocate display_timing struct\n", 68 + of_node_full_name(np)); 69 + return NULL; 70 + } 71 + 72 + ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch); 73 + ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch); 74 + ret |= parse_timing_property(np, "hactive", &dt->hactive); 75 + ret |= parse_timing_property(np, "hsync-len", &dt->hsync_len); 76 + ret |= parse_timing_property(np, "vback-porch", &dt->vback_porch); 77 + ret |= parse_timing_property(np, "vfront-porch", &dt->vfront_porch); 78 + ret |= parse_timing_property(np, "vactive", &dt->vactive); 79 + ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len); 80 + ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock); 81 + 82 + dt->dmt_flags = 0; 83 + dt->data_flags = 0; 84 + if (!of_property_read_u32(np, "vsync-active", &val)) 85 + dt->dmt_flags |= val ? VESA_DMT_VSYNC_HIGH : 86 + VESA_DMT_VSYNC_LOW; 87 + if (!of_property_read_u32(np, "hsync-active", &val)) 88 + dt->dmt_flags |= val ? VESA_DMT_HSYNC_HIGH : 89 + VESA_DMT_HSYNC_LOW; 90 + if (!of_property_read_u32(np, "de-active", &val)) 91 + dt->data_flags |= val ? DISPLAY_FLAGS_DE_HIGH : 92 + DISPLAY_FLAGS_DE_LOW; 93 + if (!of_property_read_u32(np, "pixelclk-active", &val)) 94 + dt->data_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : 95 + DISPLAY_FLAGS_PIXDATA_NEGEDGE; 96 + 97 + if (of_property_read_bool(np, "interlaced")) 98 + dt->data_flags |= DISPLAY_FLAGS_INTERLACED; 99 + if (of_property_read_bool(np, "doublescan")) 100 + dt->data_flags |= DISPLAY_FLAGS_DOUBLESCAN; 101 + 102 + if (ret) { 103 + pr_err("%s: error reading timing properties\n", 104 + of_node_full_name(np)); 105 + kfree(dt); 106 + return NULL; 107 + } 108 + 109 + return dt; 110 + } 111 + 112 + /** 113 + * of_get_display_timings - parse all display_timing entries from a device_node 114 + * @np: device_node with the subnodes 115 + **/ 116 + struct display_timings *of_get_display_timings(struct device_node *np) 117 + { 118 + struct device_node *timings_np; 119 + struct device_node *entry; 120 + struct device_node *native_mode; 121 + struct display_timings *disp; 122 + 123 + if (!np) { 124 + pr_err("%s: no devicenode given\n", of_node_full_name(np)); 125 + return NULL; 126 + } 127 + 128 + timings_np = of_find_node_by_name(np, "display-timings"); 129 + if (!timings_np) { 130 + pr_err("%s: could not find display-timings node\n", 131 + of_node_full_name(np)); 132 + return NULL; 133 + } 134 + 135 + disp = kzalloc(sizeof(*disp), GFP_KERNEL); 136 + if (!disp) { 137 + pr_err("%s: could not allocate struct disp'\n", 138 + of_node_full_name(np)); 139 + goto dispfail; 140 + } 141 + 142 + entry = of_parse_phandle(timings_np, "native-mode", 0); 143 + /* assume first child as native mode if none provided */ 144 + if (!entry) 145 + entry = of_get_next_child(np, NULL); 146 + /* if there is no child, it is useless to go on */ 147 + if (!entry) { 148 + pr_err("%s: no timing specifications given\n", 149 + of_node_full_name(np)); 150 + goto entryfail; 151 + } 152 + 153 + pr_debug("%s: using %s as default timing\n", 154 + of_node_full_name(np), entry->name); 155 + 156 + native_mode = entry; 157 + 158 + disp->num_timings = of_get_child_count(timings_np); 159 + if (disp->num_timings == 0) { 160 + /* should never happen, as entry was already found above */ 161 + pr_err("%s: no timings specified\n", of_node_full_name(np)); 162 + goto entryfail; 163 + } 164 + 165 + disp->timings = kzalloc(sizeof(struct display_timing *) * 166 + disp->num_timings, GFP_KERNEL); 167 + if (!disp->timings) { 168 + pr_err("%s: could not allocate timings array\n", 169 + of_node_full_name(np)); 170 + goto entryfail; 171 + } 172 + 173 + disp->num_timings = 0; 174 + disp->native_mode = 0; 175 + 176 + for_each_child_of_node(timings_np, entry) { 177 + struct display_timing *dt; 178 + 179 + dt = of_get_display_timing(entry); 180 + if (!dt) { 181 + /* 182 + * to not encourage wrong devicetrees, fail in case of 183 + * an error 184 + */ 185 + pr_err("%s: error in timing %d\n", 186 + of_node_full_name(np), disp->num_timings + 1); 187 + goto timingfail; 188 + } 189 + 190 + if (native_mode == entry) 191 + disp->native_mode = disp->num_timings; 192 + 193 + disp->timings[disp->num_timings] = dt; 194 + disp->num_timings++; 195 + } 196 + of_node_put(timings_np); 197 + /* 198 + * native_mode points to the device_node returned by of_parse_phandle 199 + * therefore call of_node_put on it 200 + */ 201 + of_node_put(native_mode); 202 + 203 + pr_debug("%s: got %d timings. Using timing #%d as default\n", 204 + of_node_full_name(np), disp->num_timings, 205 + disp->native_mode + 1); 206 + 207 + return disp; 208 + 209 + timingfail: 210 + if (native_mode) 211 + of_node_put(native_mode); 212 + display_timings_release(disp); 213 + entryfail: 214 + kfree(disp); 215 + dispfail: 216 + of_node_put(timings_np); 217 + return NULL; 218 + } 219 + EXPORT_SYMBOL_GPL(of_get_display_timings); 220 + 221 + /** 222 + * of_display_timings_exist - check if a display-timings node is provided 223 + * @np: device_node with the timing 224 + **/ 225 + int of_display_timings_exist(struct device_node *np) 226 + { 227 + struct device_node *timings_np; 228 + 229 + if (!np) 230 + return -EINVAL; 231 + 232 + timings_np = of_parse_phandle(np, "display-timings", 0); 233 + if (!timings_np) 234 + return -EINVAL; 235 + 236 + of_node_put(timings_np); 237 + return 1; 238 + } 239 + EXPORT_SYMBOL_GPL(of_display_timings_exist);
+54
drivers/video/of_videomode.c
··· 1 + /* 2 + * generic videomode helper 3 + * 4 + * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix 5 + * 6 + * This file is released under the GPLv2 7 + */ 8 + #include <linux/errno.h> 9 + #include <linux/export.h> 10 + #include <linux/of.h> 11 + #include <video/display_timing.h> 12 + #include <video/of_display_timing.h> 13 + #include <video/of_videomode.h> 14 + #include <video/videomode.h> 15 + 16 + /** 17 + * of_get_videomode - get the videomode #<index> from devicetree 18 + * @np - devicenode with the display_timings 19 + * @vm - set to return value 20 + * @index - index into list of display_timings 21 + * (Set this to OF_USE_NATIVE_MODE to use whatever mode is 22 + * specified as native mode in the DT.) 23 + * 24 + * DESCRIPTION: 25 + * Get a list of all display timings and put the one 26 + * specified by index into *vm. This function should only be used, if 27 + * only one videomode is to be retrieved. A driver that needs to work 28 + * with multiple/all videomodes should work with 29 + * of_get_display_timings instead. 30 + **/ 31 + int of_get_videomode(struct device_node *np, struct videomode *vm, 32 + int index) 33 + { 34 + struct display_timings *disp; 35 + int ret; 36 + 37 + disp = of_get_display_timings(np); 38 + if (!disp) { 39 + pr_err("%s: no timings specified\n", of_node_full_name(np)); 40 + return -EINVAL; 41 + } 42 + 43 + if (index == OF_USE_NATIVE_MODE) 44 + index = disp->native_mode; 45 + 46 + ret = videomode_from_timing(disp, vm, index); 47 + if (ret) 48 + return ret; 49 + 50 + display_timings_release(disp); 51 + 52 + return 0; 53 + } 54 + EXPORT_SYMBOL_GPL(of_get_videomode);
+20
include/video/of_display_timing.h
··· 1 + /* 2 + * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de> 3 + * 4 + * display timings of helpers 5 + * 6 + * This file is released under the GPLv2 7 + */ 8 + 9 + #ifndef __LINUX_OF_DISPLAY_TIMING_H 10 + #define __LINUX_OF_DISPLAY_TIMING_H 11 + 12 + struct device_node; 13 + struct display_timings; 14 + 15 + #define OF_USE_NATIVE_MODE -1 16 + 17 + struct display_timings *of_get_display_timings(struct device_node *np); 18 + int of_display_timings_exist(struct device_node *np); 19 + 20 + #endif
+18
include/video/of_videomode.h
··· 1 + /* 2 + * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de> 3 + * 4 + * videomode of-helpers 5 + * 6 + * This file is released under the GPLv2 7 + */ 8 + 9 + #ifndef __LINUX_OF_VIDEOMODE_H 10 + #define __LINUX_OF_VIDEOMODE_H 11 + 12 + struct device_node; 13 + struct videomode; 14 + 15 + int of_get_videomode(struct device_node *np, struct videomode *vm, 16 + int index); 17 + 18 + #endif /* __LINUX_OF_VIDEOMODE_H */