Add display_timing structure and the according helper functions. This allows
the description of a display via its supported timing parameters.
Every timing parameter can be specified as a single value or a range
<min typ max>.
Signed-off-by: Steffen Trumtrar <redacted>
---
drivers/video/Kconfig | 5 +++
drivers/video/Makefile | 1 +
drivers/video/display_timing.c | 24 ++++++++++++++
include/linux/display_timing.h | 69 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 99 insertions(+)
create mode 100644 drivers/video/display_timing.c
create mode 100644 include/linux/display_timing.h
@@ -0,0 +1,69 @@+/*+*Copyright2012SteffenTrumtrar<s.trumtrar@pengutronix.de>+*+*descriptionofdisplaytimings+*+*ThisfileisreleasedundertheGPLv2+*/++#ifndef __LINUX_DISPLAY_TIMINGS_H+#define __LINUX_DISPLAY_TIMINGS_H++#include<linux/types.h>++structtiming_entry{+u32min;+u32typ;+u32max;+};++structdisplay_timing{+structtiming_entrypixelclock;++structtiming_entryhactive;+structtiming_entryhfront_porch;+structtiming_entryhback_porch;+structtiming_entryhsync_len;++structtiming_entryvactive;+structtiming_entryvfront_porch;+structtiming_entryvback_porch;+structtiming_entryvsync_len;++unsignedintvsync_pol_active;+unsignedinthsync_pol_active;+unsignedintde_pol_active;+unsignedintpixelclk_pol;+boolinterlaced;+booldoublescan;+};++structdisplay_timings{+unsignedintnum_timings;+unsignedintnative_mode;++structdisplay_timing**timings;+};++/* placeholder function until ranges are really needed */+staticinlineu32display_timing_get_value(structtiming_entry*te,intindex)+{+returnte->typ;+}++staticinlinestructdisplay_timing*display_timings_get(structdisplay_timings*disp,+intindex)+{+structdisplay_timing*dt;++if(disp->num_timings>index){+dt=disp->timings[index];+returndt;+}else+returnNULL;+}++voidtimings_release(structdisplay_timings*disp);+voiddisplay_timings_release(structdisplay_timings*disp);++#endif
@@ -0,0 +1,139 @@+display-timings 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.++timings-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: displayclock 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-inverted : pixelclock is inverted/non-inverted/ignored+ - interlaced (bool)+ - doublescan (bool)++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++struct display_timing+===================++ +----------+---------------------------------------------+----------+-------++ | | ↑ | | |+ | | |vback_porch | | |+ | | ↓ | | |+ +----------###############################################----------+-------++ | # ↑ # | |+ | # | # | |+ | hback # | # hfront | hsync |+ | porch # | hactive # porch | len |+ |<-------->#<---------------+--------------------------->#<-------->|<----->|+ | # | # | |+ | # |vactive # | |+ | # | # | |+ | # ↓ # | |+ +----------###############################################----------+-------++ | | ↑ | | |+ | | |vfront_porch | | |+ | | ↓ | | |+ +----------+---------------------------------------------+----------+-------++ | | ↑ | | |+ | | |vsync_len | | |+ | | ↓ | | |+ +----------+---------------------------------------------+----------+-------++++Example:++ display-timings {+ native-mode = <&timing0>;+ timing0: 1920p24 {+ /* 1920x1080p24 */+ clock = <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 <min typ max>-tuples can be used.++Example:++ timing1: timing {+ /* 1920x1080p24 */+ clock = <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>;+ };+++Usage in backend+================++A backend driver may choose to use the display-timings directly and convert the timing+ranges to a suitable mode. Or it may just use the conversion of the display timings+to the required mode via the generic videomode struct.++ dtb+ |+ | of_get_display_timing_list+ ↓+ struct display_timings+ |+ | videomode_from_timing+ ↓+ --- struct videomode ---+ | |+ videomode_to_displaymode | | videomode_to_fb_videomode+ ↓ ↓+ drm_display_mode fb_videomode++The functions of_get_fb_videomode and of_get_display_mode are provided+to conveniently get the respective mode representation from the devicetree.++Conversion to videomode+=======================++As device drivers normally work with some kind of video mode, the timings can be+converted (may be just a simple copying of the typical value) to a generic videomode+structure which then can be converted to the according mode used by the backend.
@@ -0,0 +1,185 @@+/*+*OFhelpersforparsingdisplaytimings+*+*Copyright(c)2012SteffenTrumtrar<s.trumtrar@pengutronix.de>,Pengutronix+*+*basedonof_videomode.cbySaschaHauer<s.hauer@pengutronix.de>+*+*ThisfileisreleasedundertheGPLv2+*/+#include<linux/of.h>+#include<linux/slab.h>+#include<linux/export.h>+#include<linux/of_display_timings.h>++/**+*parse_property-parsetiming_entryfromdevice_node+*@np:device_nodewiththeproperty+*@name:nameoftheproperty+*@result:willbesettothereturnvalue+*+*DESCRIPTION:+*Everydisplay_timingcanbespecifiedwitheitherjustthetypicalvalueor+*arangeconsistingofmin/typ/max.Thisfunctionhelpshandlingthis+**/+staticintparse_property(structdevice_node*np,char*name,+structtiming_entry*result)+{+structproperty*prop;+intlength;+intcells;+intret;++prop=of_find_property(np,name,&length);+if(!prop){+pr_err("%s: could not find property %s\n",__func__,name);+return-EINVAL;+}++cells=length/sizeof(u32);+if(cells==1){+ret=of_property_read_u32_array(np,name,&result->typ,cells);+result->min=result->typ;+result->max=result->typ;+}elseif(cells==3){+ret=of_property_read_u32_array(np,name,&result->min,cells);+}else{+pr_err("%s: illegal timing specification in %s\n",__func__,name);+return-EINVAL;+}++returnret;+}++/**+*of_get_display_timing-parsedisplay_timingentryfromdevice_node+*@np:device_nodewiththeproperties+**/+structdisplay_timing*of_get_display_timing(structdevice_node*np)+{+structdisplay_timing*dt;+intret=0;++dt=kzalloc(sizeof(*dt),GFP_KERNEL);+if(!dt){+pr_err("%s: could not allocate display_timing struct\n",__func__);+returnNULL;+}++ret|=parse_property(np,"hback-porch",&dt->hback_porch);+ret|=parse_property(np,"hfront-porch",&dt->hfront_porch);+ret|=parse_property(np,"hactive",&dt->hactive);+ret|=parse_property(np,"hsync-len",&dt->hsync_len);+ret|=parse_property(np,"vback-porch",&dt->vback_porch);+ret|=parse_property(np,"vfront-porch",&dt->vfront_porch);+ret|=parse_property(np,"vactive",&dt->vactive);+ret|=parse_property(np,"vsync-len",&dt->vsync_len);+ret|=parse_property(np,"clock-frequency",&dt->pixelclock);++of_property_read_u32(np,"vsync-active",&dt->vsync_pol_active);+of_property_read_u32(np,"hsync-active",&dt->hsync_pol_active);+of_property_read_u32(np,"de-active",&dt->de_pol_active);+of_property_read_u32(np,"pixelclk-inverted",&dt->pixelclk_pol);+dt->interlaced=of_property_read_bool(np,"interlaced");+dt->doublescan=of_property_read_bool(np,"doublescan");++if(ret){+pr_err("%s: error reading timing properties\n",__func__);+returnNULL;+}++returndt;+}+EXPORT_SYMBOL_GPL(of_get_display_timing);++/**+*of_get_display_timing_list-parsealldisplay_timingentriesfromadevice_node+*@np:device_nodewiththesubnodes+**/+structdisplay_timings*of_get_display_timing_list(structdevice_node*np)+{+structdevice_node*timings_np;+structdevice_node*entry;+structdevice_node*native_mode;+structdisplay_timings*disp;++if(!np){+pr_err("%s: no devicenode given\n",__func__);+returnNULL;+}++timings_np=of_find_node_by_name(np,"display-timings");+if(!timings_np){+pr_err("%s: could not find display-timings node\n",__func__);+returnNULL;+}++disp=kzalloc(sizeof(*disp),GFP_KERNEL);++entry=of_parse_phandle(timings_np,"native-mode",0);+/* assume first child as native mode if none provided */+if(!entry)+entry=of_get_next_child(np,NULL);+if(!entry){+pr_err("%s: no timing specifications given\n",__func__);+returnNULL;+}++pr_info("%s: using %s as default timing\n",__func__,entry->name);++native_mode=entry;++disp->num_timings=of_get_child_count(timings_np);+disp->timings=kzalloc(sizeof(structdisplay_timing*)*disp->num_timings,+GFP_KERNEL);+disp->num_timings=0;+disp->native_mode=0;++for_each_child_of_node(timings_np,entry){+structdisplay_timing*dt;++dt=of_get_display_timing(entry);+if(!dt){+/* to not encourage wrong devicetrees, fail in case of an error */+pr_err("%s: error in timing %d\n",__func__,disp->num_timings+1);+returnNULL;+}++if(native_mode==entry)+disp->native_mode=disp->num_timings;++disp->timings[disp->num_timings]=dt;+disp->num_timings++;+}+of_node_put(timings_np);++if(disp->num_timings>0)+pr_info("%s: got %d timings. Using timing #%d as default\n",__func__,+disp->num_timings,disp->native_mode+1);+else{+pr_err("%s: no valid timings specified\n",__func__);+returnNULL;+}+returndisp;+}+EXPORT_SYMBOL_GPL(of_get_display_timing_list);++/**+*of_display_timings_exists-checkifadisplay-timingsnodeisprovided+*@np:device_nodewiththetiming+**/+intof_display_timings_exists(structdevice_node*np)+{+structdevice_node*timings_np;+structdevice_node*default_np;++if(!np)+return-EINVAL;++timings_np=of_parse_phandle(np,"display-timings",0);+if(!timings_np)+return-EINVAL;++return-EINVAL;+}+EXPORT_SYMBOL_GPL(of_display_timings_exists);
Get videomode from devicetree in a format appropriate for the
backend. drm_display_mode and fb_videomode are supported atm.
Uses the display signal timings from of_display_timings
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Steffen Trumtrar <redacted>
---
drivers/of/Kconfig | 6 ++++++
drivers/of/Makefile | 1 +
drivers/of/of_videomode.c | 47 ++++++++++++++++++++++++++++++++++++++++++
include/linux/of_videomode.h | 15 ++++++++++++++
4 files changed, 69 insertions(+)
create mode 100644 drivers/of/of_videomode.c
create mode 100644 include/linux/of_videomode.h
@@ -0,0 +1,44 @@+/*+*genericdisplaytimingfunctions+*+*Copyright(c)2012SteffenTrumtrar<s.trumtrar@pengutronix.de>,Pengutronix+*+*ThisfileisreleasedundertheGPLv2+*/++#include<linux/kernel.h>+#include<linux/export.h>+#include<linux/errno.h>+#include<linux/display_timing.h>+#include<linux/videomode.h>++intvideomode_from_timing(structdisplay_timings*disp,structvideomode*vm,+intindex)+{+structdisplay_timing*dt=NULL;++dt=display_timings_get(disp,index);+if(!dt){+pr_err("%s: no signal timings found\n",__func__);+return-EINVAL;+}++vm->pixelclock=display_timing_get_value(&dt->pixelclock,0);+vm->hactive=display_timing_get_value(&dt->hactive,0);+vm->hfront_porch=display_timing_get_value(&dt->hfront_porch,0);+vm->hback_porch=display_timing_get_value(&dt->hback_porch,0);+vm->hsync_len=display_timing_get_value(&dt->hsync_len,0);++vm->vactive=display_timing_get_value(&dt->vactive,0);+vm->vfront_porch=display_timing_get_value(&dt->vfront_porch,0);+vm->vback_porch=display_timing_get_value(&dt->vback_porch,0);+vm->vsync_len=display_timing_get_value(&dt->vsync_len,0);++vm->vah=dt->vsync_pol_active;+vm->hah=dt->hsync_pol_active;+vm->interlaced=dt->interlaced;+vm->doublescan=dt->doublescan;++return0;+}+EXPORT_SYMBOL_GPL(videomode_from_timing);
Add a function to convert from the generic videomode to a fb_videomode.
Signed-off-by: Steffen Trumtrar <redacted>
---
drivers/video/fbmon.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/fb.h | 2 ++
2 files changed, 38 insertions(+)
@@ -504,6 +505,41 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,}EXPORT_SYMBOL(drm_gtf_mode);+#if IS_ENABLED(CONFIG_VIDEOMODE)+intvideomode_to_display_mode(structvideomode*vm,structdrm_display_mode*dmode)+{+dmode->hdisplay=vm->hactive;+dmode->hsync_start=dmode->hdisplay+vm->hfront_porch;+dmode->hsync_end=dmode->hsync_start+vm->hsync_len;+dmode->htotal=dmode->hsync_end+vm->hback_porch;++dmode->vdisplay=vm->vactive;+dmode->vsync_start=dmode->vdisplay+vm->vfront_porch;+dmode->vsync_end=dmode->vsync_start+vm->vsync_len;+dmode->vtotal=dmode->vsync_end+vm->vback_porch;++dmode->clock=vm->pixelclock/1000;++dmode->flags=0;+if(vm->hah)+dmode->flags|=DRM_MODE_FLAG_PHSYNC;+else+dmode->flags|=DRM_MODE_FLAG_NHSYNC;+if(vm->vah)+dmode->flags|=DRM_MODE_FLAG_PVSYNC;+else+dmode->flags|=DRM_MODE_FLAG_NVSYNC;+if(vm->interlaced)+dmode->flags|=DRM_MODE_FLAG_INTERLACE;+if(vm->doublescan)+dmode->flags|=DRM_MODE_FLAG_DBLSCAN;+drm_mode_set_name(dmode);++return0;+}+EXPORT_SYMBOL_GPL(videomode_to_display_mode);+#endif+/***drm_mode_set_name-setthenameonamode*@mode:namewillbesetinthismode
Hi Steffen,
On Wed, Oct 31, 2012 at 14:58:05, Steffen Trumtrar wrote:
quoted hunk
Add a function to convert from the generic videomode to a fb_videomode.
Signed-off-by: Steffen Trumtrar <redacted>
---
drivers/video/fbmon.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/fb.h | 2 ++
2 files changed, 38 insertions(+)
--
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Prakash!
On Wed, Oct 31, 2012 at 03:30:03PM +0000, Manjunathappa, Prakash wrote:
Hi Steffen,
On Wed, Oct 31, 2012 at 14:58:05, Steffen Trumtrar wrote:
quoted
Add a function to convert from the generic videomode to a fb_videomode.
Signed-off-by: Steffen Trumtrar <redacted>
---
drivers/video/fbmon.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/fb.h | 2 ++
2 files changed, 38 insertions(+)
Hi Steffen,
Thanks for the patch.
As we'll need a v8 anyway due to the comment on patch 5/8, here are a couple
of other small comments.
On Wednesday 31 October 2012 10:28:01 Steffen Trumtrar wrote:
quoted hunk
Add display_timing structure and the according helper functions. This allows
the description of a display via its supported timing parameters.
Every timing parameter can be specified as a single value or a range
<min typ max>.
Signed-off-by: Steffen Trumtrar <redacted>
---
drivers/video/Kconfig | 5 +++
drivers/video/Makefile | 1 +
drivers/video/display_timing.c | 24 ++++++++++++++
include/linux/display_timing.h | 69 +++++++++++++++++++++++++++++++++++++
4 files changed, 99 insertions(+)
create mode 100644 drivers/video/display_timing.c
create mode 100644 include/linux/display_timing.h
@@ -0,0 +1,69 @@+/*+*Copyright2012SteffenTrumtrar<s.trumtrar@pengutronix.de>+*+*descriptionofdisplaytimings+*+*ThisfileisreleasedundertheGPLv2+*/++#ifndef __LINUX_DISPLAY_TIMINGS_H+#define __LINUX_DISPLAY_TIMINGS_H++#include<linux/types.h>++structtiming_entry{+u32min;+u32typ;+u32max;+};++structdisplay_timing{+structtiming_entrypixelclock;++structtiming_entryhactive;+structtiming_entryhfront_porch;+structtiming_entryhback_porch;+structtiming_entryhsync_len;++structtiming_entryvactive;+structtiming_entryvfront_porch;+structtiming_entryvback_porch;+structtiming_entryvsync_len;++unsignedintvsync_pol_active;+unsignedinthsync_pol_active;+unsignedintde_pol_active;+unsignedintpixelclk_pol;+boolinterlaced;+booldoublescan;+};++structdisplay_timings{+unsignedintnum_timings;+unsignedintnative_mode;++structdisplay_timing**timings;+};++/* placeholder function until ranges are really needed */+staticinlineu32display_timing_get_value(structtiming_entry*te,int
Hi Steffen,
One more comment.
On Wednesday 31 October 2012 10:28:01 Steffen Trumtrar wrote:
quoted hunk
Add display_timing structure and the according helper functions. This allows
the description of a display via its supported timing parameters.
Every timing parameter can be specified as a single value or a range
<min typ max>.
Signed-off-by: Steffen Trumtrar <redacted>
---
drivers/video/Kconfig | 5 +++
drivers/video/Makefile | 1 +
drivers/video/display_timing.c | 24 ++++++++++++++
include/linux/display_timing.h | 69 +++++++++++++++++++++++++++++++++++++
4 files changed, 99 insertions(+)
create mode 100644 drivers/video/display_timing.c
create mode 100644 include/linux/display_timing.h
Pengutronix + *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/slab.h>
+#include <linux/display_timing.h>
+
+void timings_release(struct display_timings *disp)
+{
+ int i;
+
+ for (i = 0; i < disp->num_timings; i++)
+ kfree(disp->timings[i]);
+}
This function doesn't seem to be called externally, you can make it static.
@@ -0,0 +1,69 @@+/*+*Copyright2012SteffenTrumtrar<s.trumtrar@pengutronix.de>+*+*descriptionofdisplaytimings+*+*ThisfileisreleasedundertheGPLv2+*/++#ifndef __LINUX_DISPLAY_TIMINGS_H+#define __LINUX_DISPLAY_TIMINGS_H++#include<linux/types.h>++structtiming_entry{+u32min;+u32typ;+u32max;+};++structdisplay_timing{+structtiming_entrypixelclock;++structtiming_entryhactive;+structtiming_entryhfront_porch;+structtiming_entryhback_porch;+structtiming_entryhsync_len;++structtiming_entryvactive;+structtiming_entryvfront_porch;+structtiming_entryvback_porch;+structtiming_entryvsync_len;++unsignedintvsync_pol_active;+unsignedinthsync_pol_active;+unsignedintde_pol_active;+unsignedintpixelclk_pol;+boolinterlaced;+booldoublescan;+};++structdisplay_timings{+unsignedintnum_timings;+unsignedintnative_mode;++structdisplay_timing**timings;+};++/* placeholder function until ranges are really needed */+staticinlineu32display_timing_get_value(structtiming_entry*te,int
Shouldn't this option should be automatically selected through a select
statement in other options that depend on it instead of manually selected ?
Same for the DISPLAY_TIMING option in 1/8.
There's so little code here, do you think it would be a good idea to merge
patches 1/8 and 4/8 and have a single Kconfig option ?
quoted hunk
+ help
+ Say Y here, to use the generic videomode helpers. This allows
+ converting from display timings to fb_videomode and drm_display_mode
+
menuconfig FB
tristate "Support for frame buffer devices"
---help---
Pengutronix + *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/display_timing.h>
+#include <linux/videomode.h>
As in 1/8, I try to keep #include's sorted alphabetically, but I won't push
for it here either :-)
+ dt = display_timings_get(disp, index);
+ if (!dt) {
+ pr_err("%s: no signal timings found\n", __func__);
I wonder whether this really deserves a pr_err() here. Would this be a caller
bug, or can there be valid use cases where this function would return an error
?
From: Stephen Warren <hidden> Date: 2012-11-01 17:52:19
On 10/31/2012 03:28 AM, Steffen Trumtrar wrote:
Patch description? The patch defines the DT binding as well, which isn't
mentioned in the patch subject.
Everything before this point in the binding docs looks reasonable to me.
Everything after this point is Linux-specific/internal implementation
detail, and hence shouldn't be in the binding document.
I only read the DT binding.
On Wed, Oct 31, 2012 at 10:28:03AM +0100, Steffen Trumtrar wrote:
[...]
+config OF_VIDEOMODE
+ def_bool y
+ depends on VIDEOMODE
+ help
+ helper to get videomodes from the devicetree
+
I think patches 3 and 4 need to be swapped, since patch 4 introduces the
VIDEOMODE Kconfig symbol (as well as the videomode.h helper) that patch
3 uses.
Thierry
@@ -0,0 +1,139 @@+display-timings 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.++timings-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: displayclock 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-inverted : pixelclock is inverted/non-inverted/ignored+ - interlaced (bool)+ - doublescan (bool)++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++struct display_timing+===================++ +----------+---------------------------------------------+----------+-------++ | | ↑ | | |+ | | |vback_porch | | |+ | | ↓ | | |+ +----------###############################################----------+-------++ | # ↑ # | |+ | # | # | |+ | hback # | # hfront | hsync |+ | porch # | hactive # porch | len |+ |<-------->#<---------------+--------------------------->#<-------->|<----->|+ | # | # | |+ | # |vactive # | |+ | # | # | |+ | # ↓ # | |+ +----------###############################################----------+-------++ | | ↑ | | |+ | | |vfront_porch | | |+ | | ↓ | | |+ +----------+---------------------------------------------+----------+-------++ | | ↑ | | |+ | | |vsync_len | | |+ | | ↓ | | |+ +----------+---------------------------------------------+----------+-------++++Example:++ display-timings {+ native-mode = <&timing0>;+ timing0: 1920p24 {+ /* 1920x1080p24 */+ clock = <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 <min typ max>-tuples can be used.++Example:++ timing1: timing {+ /* 1920x1080p24 */+ clock = <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>;+ };+++Usage in backend+================++A backend driver may choose to use the display-timings directly and convert the timing+ranges to a suitable mode. Or it may just use the conversion of the display timings+to the required mode via the generic videomode struct.++ dtb+ |+ | of_get_display_timing_list+ ↓+ struct display_timings+ |+ | videomode_from_timing+ ↓+ --- struct videomode ---+ | |+ videomode_to_displaymode | | videomode_to_fb_videomode+ ↓ ↓+ drm_display_mode fb_videomode++The functions of_get_fb_videomode and of_get_display_mode are provided+to conveniently get the respective mode representation from the devicetree.++Conversion to videomode+=======================++As device drivers normally work with some kind of video mode, the timings can be+converted (may be just a simple copying of the typical value) to a generic videomode+structure which then can be converted to the according mode used by the backend.
@@ -0,0 +1,185 @@+/*+*OFhelpersforparsingdisplaytimings+*+*Copyright(c)2012SteffenTrumtrar<s.trumtrar@pengutronix.de>,Pengutronix+*+*basedonof_videomode.cbySaschaHauer<s.hauer@pengutronix.de>+*+*ThisfileisreleasedundertheGPLv2+*/+#include<linux/of.h>+#include<linux/slab.h>+#include<linux/export.h>+#include<linux/of_display_timings.h>++/**+*parse_property-parsetiming_entryfromdevice_node+*@np:device_nodewiththeproperty+*@name:nameoftheproperty+*@result:willbesettothereturnvalue+*+*DESCRIPTION:+*Everydisplay_timingcanbespecifiedwitheitherjustthetypicalvalueor+*arangeconsistingofmin/typ/max.Thisfunctionhelpshandlingthis+**/+staticintparse_property(structdevice_node*np,char*name,+structtiming_entry*result)+{+structproperty*prop;+intlength;+intcells;+intret;++prop=of_find_property(np,name,&length);+if(!prop){+pr_err("%s: could not find property %s\n",__func__,name);+return-EINVAL;+}++cells=length/sizeof(u32);+if(cells==1){+ret=of_property_read_u32_array(np,name,&result->typ,cells);
As you are reading only one vaue, you can use of_property_read_u32 instead.
You are considering only min element, what about typ and max elements?
+ } else {
+ pr_err("%s: illegal timing specification in %s\n", __func__, name);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * of_get_display_timing - parse display_timing entry from device_node
+ * @np: device_node with the properties
+ **/
+struct display_timing *of_get_display_timing(struct device_node *np)
+{
+ struct display_timing *dt;
+ int ret = 0;
+
+ dt = kzalloc(sizeof(*dt), GFP_KERNEL);
+ if (!dt) {
+ pr_err("%s: could not allocate display_timing struct\n", __func__);
+ return NULL;
+ }
+
+ ret |= parse_property(np, "hback-porch", &dt->hback_porch);
+ ret |= parse_property(np, "hfront-porch", &dt->hfront_porch);
+ ret |= parse_property(np, "hactive", &dt->hactive);
+ ret |= parse_property(np, "hsync-len", &dt->hsync_len);
+ ret |= parse_property(np, "vback-porch", &dt->vback_porch);
+ ret |= parse_property(np, "vfront-porch", &dt->vfront_porch);
+ ret |= parse_property(np, "vactive", &dt->vactive);
+ ret |= parse_property(np, "vsync-len", &dt->vsync_len);
+ ret |= parse_property(np, "clock-frequency", &dt->pixelclock);
+
+ of_property_read_u32(np, "vsync-active", &dt->vsync_pol_active);
+ of_property_read_u32(np, "hsync-active", &dt->hsync_pol_active);
+ of_property_read_u32(np, "de-active", &dt->de_pol_active);
+ of_property_read_u32(np, "pixelclk-inverted", &dt->pixelclk_pol);
+ dt->interlaced = of_property_read_bool(np, "interlaced");
+ dt->doublescan = of_property_read_bool(np, "doublescan");
+
+ if (ret) {
+ pr_err("%s: error reading timing properties\n", __func__);
+ return NULL;
+ }
+
+ return dt;
+}
+EXPORT_SYMBOL_GPL(of_get_display_timing);
+
+/**
+ * of_get_display_timing_list - parse all display_timing entries from a device_node
+ * @np: device_node with the subnodes
+ **/
+struct display_timings *of_get_display_timing_list(struct device_node *np)
+{
+ struct device_node *timings_np;
+ struct device_node *entry;
+ struct device_node *native_mode;
+ struct display_timings *disp;
+
+ if (!np) {
+ pr_err("%s: no devicenode given\n", __func__);
+ return NULL;
+ }
+
+ timings_np = of_find_node_by_name(np, "display-timings");
+ if (!timings_np) {
+ pr_err("%s: could not find display-timings node\n", __func__);
+ return NULL;
+ }
+
+ disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+
+ entry = of_parse_phandle(timings_np, "native-mode", 0);
+ /* assume first child as native mode if none provided */
+ if (!entry)
+ entry = of_get_next_child(np, NULL);
+ if (!entry) {
+ pr_err("%s: no timing specifications given\n", __func__);
+ return NULL;
+ }
+
+ pr_info("%s: using %s as default timing\n", __func__, entry->name);
+
+ native_mode = entry;
+
+ disp->num_timings = of_get_child_count(timings_np);
+ disp->timings = kzalloc(sizeof(struct display_timing *)*disp->num_timings,
+ GFP_KERNEL);
+ disp->num_timings = 0;
+ disp->native_mode = 0;
+
+ for_each_child_of_node(timings_np, entry) {
+ struct display_timing *dt;
+
+ dt = of_get_display_timing(entry);
+ if (!dt) {
+ /* to not encourage wrong devicetrees, fail in case of an error */
+ pr_err("%s: error in timing %d\n", __func__, disp->num_timings+1);
+ return NULL;
+ }
+
+ if (native_mode == entry)
+ disp->native_mode = disp->num_timings;
+
+ disp->timings[disp->num_timings] = dt;
+ disp->num_timings++;
+ }
+ of_node_put(timings_np);
+
+ if (disp->num_timings > 0)
+ pr_info("%s: got %d timings. Using timing #%d as default\n", __func__,
+ disp->num_timings , disp->native_mode + 1);
+ else {
+ pr_err("%s: no valid timings specified\n", __func__);
+ return NULL;
+ }
+ return disp;
+}
+EXPORT_SYMBOL_GPL(of_get_display_timing_list);
+
+/**
+ * of_display_timings_exists - check if a display-timings node is provided
+ * @np: device_node with the timing
+ **/
+int of_display_timings_exists(struct device_node *np)
+{
+ struct device_node *timings_np;
+ struct device_node *default_np;
+
+ if (!np)
+ return -EINVAL;
+
+ timings_np = of_parse_phandle(np, "display-timings", 0);
+ if (!timings_np)
+ return -EINVAL;
+
+ return -EINVAL;
Here it should return success instead of -EINVAL.
And one query.. are the binding properties names and "display-timings"
node structure template finalized..?
Best Wishes,
Leela Krishna Amudala.
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
You are considering only min element, what about typ and max elements?
I start at the address of result->min and read three u32-values, therefore all
three (min,typ,max) are filled with values.
quoted
+
+/**
+ * of_display_timings_exists - check if a display-timings node is provided
+ * @np: device_node with the timing
+ **/
+int of_display_timings_exists(struct device_node *np)
+{
+ struct device_node *timings_np;
+ struct device_node *default_np;
+
+ if (!np)
+ return -EINVAL;
+
+ timings_np = of_parse_phandle(np, "display-timings", 0);
+ if (!timings_np)
+ return -EINVAL;
+
+ return -EINVAL;
Here it should return success instead of -EINVAL.
Yes.
And one query.. are the binding properties names and "display-timings"
node structure template finalized..?
I sure hope so. There actually is one error in the examples though.
The property clock is called clock-frequency. I included it correctly
at the top of display-timings.txt, but overlooked it in the examples.
Regards,
Steffen
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
On Wed, Oct 31, 2012 at 10:28:08AM +0100, Steffen Trumtrar wrote:
[...]
+/**
+ * of_get_drm_display_mode - get a drm_display_mode from devicetree
+ * @np: device_node with the timing specification
+ * @dmode: will be set to the return value
+ * @index: index into the list of display timings in devicetree
+ *
+ * DESCRIPTION:
I don't think this is necessary.
+ * This function is expensive and should only be used, if only one mode is to be
+ * read from DT. To get multiple modes start with of_get_display_timing_list ond
You probably meant "and" at the end of this line. Also I'm not even sure
that we should be exposing this function, but rather provide a helper
which automatically adds the parsed modes to a DRM connector object.
Thierry
"pixelclk-inverted" property of the panel is not percolated fb_videomode.
Please let me know if I am missing something.
The next version is almost finished. Only thing I'm missing is this.
And I actually do not know which flag would represent an inverted pixelclock
in fb_videomode. Does anybody have any idea what I have to do here?
if (vm->pixelclk_pol)
fbmode->sync = ???
That's as far as I have come and I don't see a flag that seems right.
Is this even a valid property of fb_videomode?
Regards,
Steffen
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
On Thu, Nov 08, 2012 at 03:35:47PM -0600, Rob Herring wrote:
On 10/31/2012 04:28 AM, Steffen Trumtrar wrote:
quoted
Hi!
Finally, v7 of the series.
Changes since v6:
- get rid of some empty lines etc.
- move functions to their subsystems
- split of_ from non-of_ functions
- add at least some kerneldoc to some functions
Regards,
Steffen
Steffen Trumtrar (8):
video: add display_timing struct and helpers
of: add helper to parse display timings
of: add generic videomode description
video: add videomode helpers
fbmon: add videomode helpers
fbmon: add of_videomode helpers
drm_modes: add videomode helpers
drm_modes: add of_videomode helpers
.../devicetree/bindings/video/display-timings.txt | 139 +++++++++++++++
drivers/gpu/drm/drm_modes.c | 78 +++++++++
drivers/of/Kconfig | 12 ++
drivers/of/Makefile | 2 +
drivers/of/of_display_timings.c | 185 ++++++++++++++++++++
drivers/of/of_videomode.c | 47 +++++
Not sure why you moved this, but please move this back to drivers/video.
We're trying to move subsystem specific pieces out of drivers/of.
Rob
Hm, the of_xxx part always was in drivers/of, but I can move that. No problem.
Regards,
Steffen
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |