* Re: [PATCH v10 0/6] of: add display helper
From: Steffen Trumtrar @ 2012-11-15 10:28 UTC (permalink / raw)
To: Thierry Reding
Cc: linux-fbdev, devicetree-discuss, dri-devel, Tomi Valkeinen,
Laurent Pinchart, kernel, Guennady Liakhovetski, linux-media
In-Reply-To: <20121115102411.GA17272@avionic-0098.mockup.avionic-design.de>
On Thu, Nov 15, 2012 at 11:24:11AM +0100, Thierry Reding wrote:
> On Thu, Nov 15, 2012 at 10:23:51AM +0100, Steffen Trumtrar wrote:
> > Hi!
> >
> > Changes since v9:
> > - don't leak memory when previous timings were correct
> > - CodingStyle fixes
> > - move blank lines around
> >
> > Regards,
> > Steffen
> >
> >
> > Steffen Trumtrar (6):
> > video: add display_timing and videomode
> > video: add of helper for videomode
> > 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 | 107 ++++++++++
> > drivers/gpu/drm/drm_modes.c | 70 +++++++
> > drivers/video/Kconfig | 19 ++
> > drivers/video/Makefile | 4 +
> > drivers/video/display_timing.c | 24 +++
> > drivers/video/fbmon.c | 86 ++++++++
> > drivers/video/of_display_timing.c | 212 ++++++++++++++++++++
> > drivers/video/of_videomode.c | 47 +++++
> > drivers/video/videomode.c | 45 +++++
> > include/drm/drmP.h | 12 ++
> > include/linux/display_timing.h | 69 +++++++
> > include/linux/fb.h | 12 ++
> > include/linux/of_display_timings.h | 20 ++
> > include/linux/of_videomode.h | 17 ++
> > include/linux/videomode.h | 40 ++++
> > 15 files changed, 784 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/video/display-timings.txt
> > create mode 100644 drivers/video/display_timing.c
> > create mode 100644 drivers/video/of_display_timing.c
> > create mode 100644 drivers/video/of_videomode.c
> > create mode 100644 drivers/video/videomode.c
> > create mode 100644 include/linux/display_timing.h
> > create mode 100644 include/linux/of_display_timings.h
> > create mode 100644 include/linux/of_videomode.h
> > create mode 100644 include/linux/videomode.h
>
> With the one change that I pointed out, the whole series:
>
Already fixed.
> Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de>
> Acked-by: Thierry Reding <thierry.reding@avionic-design.de>
\o/ Thanks
--
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 |
^ permalink raw reply
* [PATCH v11 0/6] of: add display helper
From: Steffen Trumtrar @ 2012-11-15 13:15 UTC (permalink / raw)
To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Tomi Valkeinen,
Laurent Pinchart, kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Steffen Trumtrar,
Guennady Liakhovetski, linux-media-u79uwXL29TY76Z2rM5mHXA
Hi!
Changes since v10:
- fix function name (drm_)display_mode_from_videomode
- add acked-by, reviewed-by, tested-by
Regards,
Steffen
Steffen Trumtrar (6):
video: add display_timing and videomode
video: add of helper for videomode
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 | 107 ++++++++++
drivers/gpu/drm/drm_modes.c | 70 +++++++
drivers/video/Kconfig | 19 ++
drivers/video/Makefile | 4 +
drivers/video/display_timing.c | 24 +++
drivers/video/fbmon.c | 86 ++++++++
drivers/video/of_display_timing.c | 212 ++++++++++++++++++++
drivers/video/of_videomode.c | 47 +++++
drivers/video/videomode.c | 45 +++++
include/drm/drmP.h | 12 ++
include/linux/display_timing.h | 69 +++++++
include/linux/fb.h | 12 ++
include/linux/of_display_timings.h | 20 ++
include/linux/of_videomode.h | 17 ++
include/linux/videomode.h | 40 ++++
15 files changed, 784 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/display-timings.txt
create mode 100644 drivers/video/display_timing.c
create mode 100644 drivers/video/of_display_timing.c
create mode 100644 drivers/video/of_videomode.c
create mode 100644 drivers/video/videomode.c
create mode 100644 include/linux/display_timing.h
create mode 100644 include/linux/of_display_timings.h
create mode 100644 include/linux/of_videomode.h
create mode 100644 include/linux/videomode.h
--
1.7.10.4
^ permalink raw reply
* [PATCH v11 1/6] video: add display_timing and videomode
From: Steffen Trumtrar @ 2012-11-15 13:15 UTC (permalink / raw)
To: devicetree-discuss
Cc: Steffen Trumtrar, Rob Herring, linux-fbdev, dri-devel,
Laurent Pinchart, Thierry Reding, Guennady Liakhovetski,
linux-media, Tomi Valkeinen, Stephen Warren, kernel
In-Reply-To: <1352985312-18178-1-git-send-email-s.trumtrar@pengutronix.de>
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>.
Also, add helper functions to convert from display timings to a generic videomode
structure. This videomode can then be converted to the corresponding subsystem
mode representation (e.g. fb_videomode).
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
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>
---
drivers/video/Kconfig | 6 ++++
drivers/video/Makefile | 2 ++
drivers/video/display_timing.c | 24 ++++++++++++++
drivers/video/videomode.c | 45 ++++++++++++++++++++++++++
include/linux/display_timing.h | 69 ++++++++++++++++++++++++++++++++++++++++
include/linux/videomode.h | 40 +++++++++++++++++++++++
6 files changed, 186 insertions(+)
create mode 100644 drivers/video/display_timing.c
create mode 100644 drivers/video/videomode.c
create mode 100644 include/linux/display_timing.h
create mode 100644 include/linux/videomode.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d08d799..2a23b18 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -33,6 +33,12 @@ config VIDEO_OUTPUT_CONTROL
This framework adds support for low-level control of the video
output switch.
+config DISPLAY_TIMING
+ bool
+
+config VIDEOMODE
+ bool
+
menuconfig FB
tristate "Support for frame buffer devices"
---help---
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 23e948e..fc30439 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -167,3 +167,5 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
#video output switch sysfs driver
obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
+obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
+obj-$(CONFIG_VIDEOMODE) += videomode.o
diff --git a/drivers/video/display_timing.c b/drivers/video/display_timing.c
new file mode 100644
index 0000000..ac9bbbc
--- /dev/null
+++ b/drivers/video/display_timing.c
@@ -0,0 +1,24 @@
+/*
+ * generic display timing functions
+ *
+ * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
+ *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/display_timing.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+
+void display_timings_release(struct display_timings *disp)
+{
+ if (disp->timings) {
+ unsigned int i;
+
+ for (i = 0; i < disp->num_timings; i++)
+ kfree(disp->timings[i]);
+ kfree(disp->timings);
+ }
+ kfree(disp);
+}
+EXPORT_SYMBOL_GPL(display_timings_release);
diff --git a/drivers/video/videomode.c b/drivers/video/videomode.c
new file mode 100644
index 0000000..087374a
--- /dev/null
+++ b/drivers/video/videomode.c
@@ -0,0 +1,45 @@
+/*
+ * generic display timing functions
+ *
+ * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
+ *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/display_timing.h>
+#include <linux/kernel.h>
+#include <linux/videomode.h>
+
+int videomode_from_timing(struct display_timings *disp, struct videomode *vm,
+ unsigned int index)
+{
+ struct display_timing *dt;
+
+ dt = display_timings_get(disp, index);
+ if (!dt)
+ 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->de = dt->de_pol_active;
+ vm->pixelclk_pol = dt->pixelclk_pol;
+
+ vm->interlaced = dt->interlaced;
+ vm->doublescan = dt->doublescan;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(videomode_from_timing);
diff --git a/include/linux/display_timing.h b/include/linux/display_timing.h
new file mode 100644
index 0000000..caee2a8
--- /dev/null
+++ b/include/linux/display_timing.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * description of display timings
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_DISPLAY_TIMINGS_H
+#define __LINUX_DISPLAY_TIMINGS_H
+
+#include <linux/types.h>
+
+struct timing_entry {
+ u32 min;
+ u32 typ;
+ u32 max;
+};
+
+struct display_timing {
+ struct timing_entry pixelclock;
+
+ struct timing_entry hactive;
+ struct timing_entry hfront_porch;
+ struct timing_entry hback_porch;
+ struct timing_entry hsync_len;
+
+ struct timing_entry vactive;
+ struct timing_entry vfront_porch;
+ struct timing_entry vback_porch;
+ struct timing_entry vsync_len;
+
+ unsigned int vsync_pol_active;
+ unsigned int hsync_pol_active;
+ unsigned int de_pol_active;
+ unsigned int pixelclk_pol;
+ bool interlaced;
+ bool doublescan;
+};
+
+struct display_timings {
+ unsigned int num_timings;
+ unsigned int native_mode;
+
+ struct display_timing **timings;
+};
+
+/*
+ * placeholder function until ranges are really needed
+ * the index parameter should then be used to select one of [min typ max]
+ */
+static inline u32 display_timing_get_value(struct timing_entry *te,
+ unsigned int index)
+{
+ return te->typ;
+}
+
+static inline struct display_timing *display_timings_get(struct display_timings *disp,
+ unsigned int index)
+{
+ if (disp->num_timings > index)
+ return disp->timings[index];
+ else
+ return NULL;
+}
+
+void display_timings_release(struct display_timings *disp);
+
+#endif
diff --git a/include/linux/videomode.h b/include/linux/videomode.h
new file mode 100644
index 0000000..704db7b
--- /dev/null
+++ b/include/linux/videomode.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * generic videomode description
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_VIDEOMODE_H
+#define __LINUX_VIDEOMODE_H
+
+#include <linux/display_timing.h>
+
+struct videomode {
+ u32 pixelclock;
+ u32 refreshrate;
+
+ u32 hactive;
+ u32 hfront_porch;
+ u32 hback_porch;
+ u32 hsync_len;
+
+ u32 vactive;
+ u32 vfront_porch;
+ u32 vback_porch;
+ u32 vsync_len;
+
+ u32 hah;
+ u32 vah;
+ u32 de;
+ u32 pixelclk_pol;
+
+ bool interlaced;
+ bool doublescan;
+};
+
+int videomode_from_timing(struct display_timings *disp, struct videomode *vm,
+ unsigned int index);
+
+#endif
--
1.7.10.4
^ permalink raw reply related
* [PATCH v11 2/6] video: add of helper for videomode
From: Steffen Trumtrar @ 2012-11-15 13:15 UTC (permalink / raw)
To: devicetree-discuss
Cc: Steffen Trumtrar, Philipp Zabel, Rob Herring, linux-fbdev,
dri-devel, Laurent Pinchart, Thierry Reding,
Guennady Liakhovetski, linux-media, Tomi Valkeinen,
Stephen Warren, kernel
In-Reply-To: <1352985312-18178-1-git-send-email-s.trumtrar@pengutronix.de>
This adds support for reading display timings from DT or/and convert one of those
timings to a videomode.
The of_display_timing implementation supports multiple children where each
property can have up to 3 values. All children are read into an array, that
can be queried.
of_get_videomode converts exactly one of that timings to a struct videomode.
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>
---
.../devicetree/bindings/video/display-timings.txt | 107 ++++++++++
drivers/video/Kconfig | 13 ++
drivers/video/Makefile | 2 +
drivers/video/of_display_timing.c | 212 ++++++++++++++++++++
drivers/video/of_videomode.c | 47 +++++
include/linux/of_display_timings.h | 20 ++
include/linux/of_videomode.h | 17 ++
7 files changed, 418 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/display-timings.txt
create mode 100644 drivers/video/of_display_timing.c
create mode 100644 drivers/video/of_videomode.c
create mode 100644 include/linux/of_display_timings.h
create mode 100644 include/linux/of_videomode.h
diff --git a/Documentation/devicetree/bindings/video/display-timings.txt b/Documentation/devicetree/bindings/video/display-timings.txt
new file mode 100644
index 0000000..a05cade
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/display-timings.txt
@@ -0,0 +1,107 @@
+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: 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-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-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 <min typ max>-tuples 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>;
+ };
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 2a23b18..a324457 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -39,6 +39,19 @@ config DISPLAY_TIMING
config VIDEOMODE
bool
+config OF_DISPLAY_TIMING
+ def_bool y
+ select DISPLAY_TIMING
+ help
+ helper to parse display timings from the devicetree
+
+config OF_VIDEOMODE
+ def_bool y
+ select VIDEOMODE
+ select OF_DISPLAY_TIMING
+ help
+ helper to get videomodes from the devicetree
+
menuconfig FB
tristate "Support for frame buffer devices"
---help---
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index fc30439..b936b00 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -168,4 +168,6 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
#video output switch sysfs driver
obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
+obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
obj-$(CONFIG_VIDEOMODE) += videomode.o
+obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c
new file mode 100644
index 0000000..b187f31
--- /dev/null
+++ b/drivers/video/of_display_timing.c
@@ -0,0 +1,212 @@
+/*
+ * OF helpers for parsing display timings
+ *
+ * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
+ *
+ * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ */
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/of_display_timings.h>
+
+/**
+ * parse_property - parse timing_entry from device_node
+ * @np: device_node with the property
+ * @name: name of the property
+ * @result: will be set to the return value
+ *
+ * DESCRIPTION:
+ * Every display_timing can be specified with either just the typical value or
+ * a range consisting of min/typ/max. This function helps handling this
+ **/
+static int parse_property(struct device_node *np, char *name,
+ struct timing_entry *result)
+{
+ struct property *prop;
+ int length, cells, ret;
+
+ 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(np, name, &result->typ);
+ result->min = result->typ;
+ result->max = result->typ;
+ } else if (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;
+ }
+
+ return ret;
+}
+
+/**
+ * of_get_display_timing - parse display_timing entry from device_node
+ * @np: device_node with the properties
+ **/
+static 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__);
+ kfree(dt);
+ return NULL;
+ }
+
+ return dt;
+}
+
+/**
+ * of_get_display_timings - parse all display_timing entries from a device_node
+ * @np: device_node with the subnodes
+ **/
+struct display_timings *of_get_display_timings(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);
+ if (!disp) {
+ pr_err("%s: could not allocate struct disp'\n", __func__);
+ goto dispfail;
+ }
+
+ 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 there is no child, it is useless to go on */
+ if (!entry) {
+ pr_err("%s: no timing specifications given\n", __func__);
+ goto entryfail;
+ }
+
+ pr_info("%s: using %s as default timing\n", __func__, entry->name);
+
+ native_mode = entry;
+
+ disp->num_timings = of_get_child_count(timings_np);
+ if (disp->num_timings = 0) {
+ /* should never happen, as entry was already found above */
+ pr_err("%s: no timings specified\n", __func__);
+ goto entryfail;
+ }
+
+ disp->timings = kzalloc(sizeof(struct display_timing *)*disp->num_timings,
+ GFP_KERNEL);
+ if (!disp->timings) {
+ pr_err("%s: could not allocate timings array\n", __func__);
+ goto entryfail;
+ }
+
+ 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);
+ goto timingfail;
+ }
+
+ if (native_mode = entry)
+ disp->native_mode = disp->num_timings;
+
+ disp->timings[disp->num_timings] = dt;
+ disp->num_timings++;
+ }
+ of_node_put(timings_np);
+ of_node_put(native_mode);
+
+ 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__);
+ display_timings_release(disp);
+ return NULL;
+ }
+ return disp;
+
+timingfail:
+ if (native_mode)
+ of_node_put(native_mode);
+ display_timings_release(disp);
+entryfail:
+ if (disp)
+ kfree(disp);
+dispfail:
+ of_node_put(timings_np);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(of_get_display_timings);
+
+/**
+ * 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;
+
+ if (!np)
+ return -EINVAL;
+
+ timings_np = of_parse_phandle(np, "display-timings", 0);
+ if (!timings_np)
+ return -EINVAL;
+
+ of_node_put(timings_np);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(of_display_timings_exists);
diff --git a/drivers/video/of_videomode.c b/drivers/video/of_videomode.c
new file mode 100644
index 0000000..7051701
--- /dev/null
+++ b/drivers/video/of_videomode.c
@@ -0,0 +1,47 @@
+/*
+ * generic videomode helper
+ *
+ * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
+ *
+ * This file is released under the GPLv2
+ */
+#include <linux/of.h>
+#include <linux/of_display_timings.h>
+#include <linux/of_videomode.h>
+#include <linux/export.h>
+
+/**
+ * of_get_videomode - get the videomode #<index> from devicetree
+ * @np - devicenode with the display_timings
+ * @vm - set to return value
+ * @index - index into list of display_timings
+ * DESCRIPTION:
+ * Get a list of all display timings and put the one
+ * specified by index into *vm. This function should only be used, if
+ * only one videomode is to be retrieved. A driver that needs to work
+ * with multiple/all videomodes should work with
+ * of_get_display_timings instead.
+ **/
+int of_get_videomode(struct device_node *np, struct videomode *vm, int index)
+{
+ struct display_timings *disp;
+ int ret;
+
+ disp = of_get_display_timings(np);
+ if (!disp) {
+ pr_err("%s: no timings specified\n", __func__);
+ return -EINVAL;
+ }
+
+ if (index = OF_USE_NATIVE_MODE)
+ index = disp->native_mode;
+
+ ret = videomode_from_timing(disp, vm, index);
+ if (ret)
+ return ret;
+
+ display_timings_release(disp);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_videomode);
diff --git a/include/linux/of_display_timings.h b/include/linux/of_display_timings.h
new file mode 100644
index 0000000..e18cf94
--- /dev/null
+++ b/include/linux/of_display_timings.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * display timings of helpers
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_DISPLAY_TIMINGS_H
+#define __LINUX_OF_DISPLAY_TIMINGS_H
+
+#include <linux/display_timing.h>
+#include <linux/of.h>
+
+#define OF_USE_NATIVE_MODE -1
+
+struct display_timings *of_get_display_timings(struct device_node *np);
+int of_display_timings_exists(struct device_node *np);
+
+#endif
diff --git a/include/linux/of_videomode.h b/include/linux/of_videomode.h
new file mode 100644
index 0000000..5bb7198
--- /dev/null
+++ b/include/linux/of_videomode.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * videomode of-helpers
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_VIDEOMODE_H
+#define __LINUX_OF_VIDEOMODE_H
+
+#include <linux/videomode.h>
+#include <linux/of.h>
+
+int of_get_videomode(struct device_node *np, struct videomode *vm, int index);
+
+#endif /* __LINUX_OF_VIDEOMODE_H */
--
1.7.10.4
^ permalink raw reply related
* [PATCH v11 3/6] fbmon: add videomode helpers
From: Steffen Trumtrar @ 2012-11-15 13:15 UTC (permalink / raw)
To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Tomi Valkeinen,
Laurent Pinchart, kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Steffen Trumtrar,
Guennady Liakhovetski, linux-media-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1352985312-18178-1-git-send-email-s.trumtrar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Add a function to convert from the generic videomode to a fb_videomode.
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
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>
---
drivers/video/fbmon.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fb.h | 6 ++++++
2 files changed, 52 insertions(+)
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index cef6557..247e079 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <video/edid.h>
+#include <linux/videomode.h>
#ifdef CONFIG_PPC_OF
#include <asm/prom.h>
#include <asm/pci-bridge.h>
@@ -1373,6 +1374,51 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
kfree(timings);
return err;
}
+
+#if IS_ENABLED(CONFIG_VIDEOMODE)
+int fb_videomode_from_videomode(struct videomode *vm,
+ struct fb_videomode *fbmode)
+{
+ unsigned int htotal, vtotal;
+
+ fbmode->xres = vm->hactive;
+ fbmode->left_margin = vm->hback_porch;
+ fbmode->right_margin = vm->hfront_porch;
+ fbmode->hsync_len = vm->hsync_len;
+
+ fbmode->yres = vm->vactive;
+ fbmode->upper_margin = vm->vback_porch;
+ fbmode->lower_margin = vm->vfront_porch;
+ fbmode->vsync_len = vm->vsync_len;
+
+ fbmode->pixclock = KHZ2PICOS(vm->pixelclock / 1000);
+
+ fbmode->sync = 0;
+ fbmode->vmode = 0;
+ if (vm->hah)
+ fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (vm->vah)
+ fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ if (vm->interlaced)
+ fbmode->vmode |= FB_VMODE_INTERLACED;
+ if (vm->doublescan)
+ fbmode->vmode |= FB_VMODE_DOUBLE;
+ if (vm->de)
+ fbmode->sync |= FB_SYNC_DATA_ENABLE_HIGH_ACT;
+ fbmode->flag = 0;
+
+ htotal = vm->hactive + vm->hfront_porch + vm->hback_porch +
+ vm->hsync_len;
+ vtotal = vm->vactive + vm->vfront_porch + vm->vback_porch +
+ vm->vsync_len;
+ fbmode->refresh = (vm->pixelclock * 1000) / (htotal * vtotal);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
+#endif
+
+
#else
int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
{
diff --git a/include/linux/fb.h b/include/linux/fb.h
index c7a9571..4024136 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -14,6 +14,7 @@
#include <linux/backlight.h>
#include <linux/slab.h>
#include <asm/io.h>
+#include <linux/videomode.h>
struct vm_area_struct;
struct fb_info;
@@ -714,6 +715,11 @@ extern void fb_destroy_modedb(struct fb_videomode *modedb);
extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb);
extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter);
+#if IS_ENABLED(CONFIG_VIDEOMODE)
+extern int fb_videomode_from_videomode(struct videomode *vm,
+ struct fb_videomode *fbmode);
+#endif
+
/* drivers/video/modedb.c */
#define VESA_MODEDB_SIZE 34
extern void fb_var_to_videomode(struct fb_videomode *mode,
--
1.7.10.4
^ permalink raw reply related
* [PATCH v11 4/6] fbmon: add of_videomode helpers
From: Steffen Trumtrar @ 2012-11-15 13:15 UTC (permalink / raw)
To: devicetree-discuss
Cc: Steffen Trumtrar, Rob Herring, linux-fbdev, dri-devel,
Laurent Pinchart, Thierry Reding, Guennady Liakhovetski,
linux-media, Tomi Valkeinen, Stephen Warren, kernel
In-Reply-To: <1352985312-18178-1-git-send-email-s.trumtrar@pengutronix.de>
Add helper to get fb_videomode from devicetree.
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
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>
---
drivers/video/fbmon.c | 42 +++++++++++++++++++++++++++++++++++++++++-
include/linux/fb.h | 6 ++++++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 247e079..9e8c5fa 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -31,7 +31,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <video/edid.h>
-#include <linux/videomode.h>
+#include <linux/of_videomode.h>
#ifdef CONFIG_PPC_OF
#include <asm/prom.h>
#include <asm/pci-bridge.h>
@@ -1418,6 +1418,46 @@ int fb_videomode_from_videomode(struct videomode *vm,
EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
#endif
+#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+static inline void dump_fb_videomode(struct fb_videomode *m)
+{
+ pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
+ m->xres, m->yres, m->refresh, m->pixclock, m->left_margin,
+ m->right_margin, m->upper_margin, m->lower_margin,
+ m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
+}
+
+/**
+ * of_get_fb_videomode - get a fb_videomode from devicetree
+ * @np: device_node with the timing specification
+ * @fb: will be set to the return value
+ * @index: index into the list of display timings in devicetree
+ *
+ * DESCRIPTION:
+ * 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_timings ond
+ * work with that instead.
+ */
+int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
+ unsigned int index)
+{
+ struct videomode vm;
+ int ret;
+
+ ret = of_get_videomode(np, &vm, index);
+ if (ret)
+ return ret;
+
+ fb_videomode_from_videomode(&vm, fb);
+
+ pr_info("%s: got %dx%d display mode from %s\n", __func__, vm.hactive,
+ vm.vactive, np->name);
+ dump_fb_videomode(fb);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_fb_videomode);
+#endif
#else
int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 4024136..dc8f693 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -15,6 +15,8 @@
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/videomode.h>
+#include <linux/of.h>
+#include <linux/of_videomode.h>
struct vm_area_struct;
struct fb_info;
@@ -715,6 +717,10 @@ extern void fb_destroy_modedb(struct fb_videomode *modedb);
extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb);
extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter);
+#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+extern int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
+ unsigned int index);
+#endif
#if IS_ENABLED(CONFIG_VIDEOMODE)
extern int fb_videomode_from_videomode(struct videomode *vm,
struct fb_videomode *fbmode);
--
1.7.10.4
^ permalink raw reply related
* [PATCH v11 5/6] drm_modes: add videomode helpers
From: Steffen Trumtrar @ 2012-11-15 13:15 UTC (permalink / raw)
To: devicetree-discuss
Cc: Steffen Trumtrar, Rob Herring, linux-fbdev, dri-devel,
Laurent Pinchart, Thierry Reding, Guennady Liakhovetski,
linux-media, Tomi Valkeinen, Stephen Warren, kernel
In-Reply-To: <1352985312-18178-1-git-send-email-s.trumtrar@pengutronix.de>
Add conversion from videomode to drm_display_mode
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
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>
---
drivers/gpu/drm/drm_modes.c | 37 +++++++++++++++++++++++++++++++++++++
include/drm/drmP.h | 6 ++++++
2 files changed, 43 insertions(+)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 59450f3..23d951a0 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -35,6 +35,7 @@
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
+#include <linux/videomode.h>
/**
* drm_mode_debug_printmodeline - debug print a mode
@@ -504,6 +505,42 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
}
EXPORT_SYMBOL(drm_gtf_mode);
+#if IS_ENABLED(CONFIG_VIDEOMODE)
+int drm_display_mode_from_videomode(struct videomode *vm,
+ struct drm_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);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
+#endif
+
/**
* drm_mode_set_name - set the name on a mode
* @mode: name will be set in this mode
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 3fd8280..341049c 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -56,6 +56,7 @@
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/videomode.h>
#if defined(__alpha__) || defined(__powerpc__)
#include <asm/pgtable.h> /* For pte_wrprotect */
#endif
@@ -1454,6 +1455,11 @@ extern struct drm_display_mode *
drm_mode_create_from_cmdline_mode(struct drm_device *dev,
struct drm_cmdline_mode *cmd);
+#if IS_ENABLED(CONFIG_VIDEOMODE)
+extern int drm_display_mode_from_videomode(struct videomode *vm,
+ struct drm_display_mode *dmode);
+#endif
+
/* Modesetting support */
extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
--
1.7.10.4
^ permalink raw reply related
* [PATCH v11 6/6] drm_modes: add of_videomode helpers
From: Steffen Trumtrar @ 2012-11-15 13:15 UTC (permalink / raw)
To: devicetree-discuss
Cc: Steffen Trumtrar, Rob Herring, linux-fbdev, dri-devel,
Laurent Pinchart, Thierry Reding, Guennady Liakhovetski,
linux-media, Tomi Valkeinen, Stephen Warren, kernel
In-Reply-To: <1352985312-18178-1-git-send-email-s.trumtrar@pengutronix.de>
Add helper to get drm_display_mode from devicetree.
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
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>
---
drivers/gpu/drm/drm_modes.c | 35 ++++++++++++++++++++++++++++++++++-
include/drm/drmP.h | 6 ++++++
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 23d951a0..5508037 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -35,7 +35,8 @@
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
-#include <linux/videomode.h>
+#include <linux/of.h>
+#include <linux/of_videomode.h>
/**
* drm_mode_debug_printmodeline - debug print a mode
@@ -541,6 +542,38 @@ int drm_display_mode_from_videomode(struct videomode *vm,
EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
#endif
+#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+/**
+ * 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
+ *
+ * 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_timings and
+ * work with that instead.
+ */
+int of_get_drm_display_mode(struct device_node *np,
+ struct drm_display_mode *dmode, unsigned int index)
+{
+ struct videomode vm;
+ int ret;
+
+ ret = of_get_videomode(np, &vm, index);
+ if (ret)
+ return ret;
+
+ drm_display_mode_from_videomode(&vm, dmode);
+
+ pr_info("%s: got %dx%d display mode from %s\n", __func__, vm.hactive,
+ vm.vactive, np->name);
+ drm_mode_debug_printmodeline(dmode);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
+#endif
+
/**
* drm_mode_set_name - set the name on a mode
* @mode: name will be set in this mode
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 341049c..ae132be 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -56,6 +56,7 @@
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/videomode.h>
#if defined(__alpha__) || defined(__powerpc__)
#include <asm/pgtable.h> /* For pte_wrprotect */
@@ -1459,6 +1460,11 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
extern int drm_display_mode_from_videomode(struct videomode *vm,
struct drm_display_mode *dmode);
#endif
+#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+extern int of_get_drm_display_mode(struct device_node *np,
+ struct drm_display_mode *dmode,
+ unsigned int index);
+#endif
/* Modesetting support */
extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
--
1.7.10.4
^ permalink raw reply related
* video: pull request for branch "cfa-10049-3.7-oled-driver"
From: Maxime Ripard @ 2012-11-15 15:32 UTC (permalink / raw)
To: linux-fbdev
Florian,
Since these patches have been around for a few months without any comment,
please pull the following branch.
Thanks,
Maxime
The following changes since commit 6f0c0580b70c89094b3422ba81118c7b959c7556:
Linux 3.7-rc2 (2012-10-20 12:11:32 -0700)
are available in the git repository at:
https://github.com/crystalfontz/cfa_10036_kernel.git cfa-10049-3.7-oled-driver
for you to fetch changes up to 353b74485bd80950b4beea1497fa234d3277e4e8:
video: Add support for the Solomon SSD1307 OLED Controller (2012-10-22 12:35:02 +0200)
----------------------------------------------------------------
Maxime Ripard (1):
video: Add support for the Solomon SSD1307 OLED Controller
.../devicetree/bindings/video/ssd1307fb.txt | 24 ++
drivers/video/Kconfig | 13 +
drivers/video/Makefile | 1 +
drivers/video/ssd1307fb.c | 407 ++++++++++++++++++++
4 files changed, 445 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/ssd1307fb.txt
create mode 100644 drivers/video/ssd1307fb.c
^ permalink raw reply
* [PATCH] video: Add support for the Solomon SSD1307 OLED Controller
From: Maxime Ripard @ 2012-11-15 15:32 UTC (permalink / raw)
To: linux-fbdev
This patch adds support for the Solomon SSD1307 OLED
controller found on the Crystalfontz CFA10036 board.
This controller can drive a display with a resolution up
to 128x39 and can operate over I2C or SPI.
The current driver has only been tested on the CFA-10036,
that is using this controller over I2C to driver a 96x16
OLED screen.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: Brian Lilly <brian@crystalfontz.com>
---
.../devicetree/bindings/video/ssd1307fb.txt | 24 ++
drivers/video/Kconfig | 13 +
drivers/video/Makefile | 1 +
drivers/video/ssd1307fb.c | 407 ++++++++++++++++++++
4 files changed, 445 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/ssd1307fb.txt
create mode 100644 drivers/video/ssd1307fb.c
diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
new file mode 100644
index 0000000..3d0060c
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt
@@ -0,0 +1,24 @@
+* Solomon SSD1307 Framebuffer Driver
+
+Required properties:
+ - compatible: Should be "solomon,ssd1307fb-<bus>". The only supported bus for
+ now is i2c.
+ - reg: Should contain address of the controller on the I2C bus. Most likely
+ 0x3c or 0x3d
+ - pwm: Should contain the pwm to use according to the OF device tree PWM
+ specification [0]
+ - reset-gpios: Should contain the GPIO used to reset the OLED display
+
+Optional properties:
+ - reset-active-low: Is the reset gpio is active on physical low?
+
+[0]: Documentation/devicetree/bindings/pwm/pwm.txt
+
+Examples:
+ssd1307: oled@3c {
+ compatible = "solomon,ssd1307fb-i2c";
+ reg = <0x3c>;
+ pwms = <&pwm 4 3000>;
+ reset-gpios = <&gpio2 7>;
+ reset-active-low;
+};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d08d799..294de9c 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2442,4 +2442,17 @@ config FB_SH_MOBILE_MERAM
Up to 4 memory channels can be configured, allowing 4 RGB or
2 YCbCr framebuffers to be configured.
+config FB_SSD1307
+ tristate "Solomon SSD1307 framebuffer support"
+ depends on FB && I2C
+ select FB_SYS_FOPS
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_DEFERRED_IO
+ select PWM
+ help
+ This driver implements support for the Solomon SSD1307
+ OLED controller over I2C.
+
endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 23e948e..768a137 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -161,6 +161,7 @@ obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o
obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
obj-$(CONFIG_FB_MXS) += mxsfb.o
+obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
new file mode 100644
index 0000000..ed18f19
--- /dev/null
+++ b/drivers/video/ssd1307fb.c
@@ -0,0 +1,407 @@
+/*
+ * Driver for the Solomon SSD1307 OLED controler
+ *
+ * Copyright 2012 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/uaccess.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pwm.h>
+#include <linux/delay.h>
+
+#define SSD1307FB_WIDTH 96
+#define SSD1307FB_HEIGHT 16
+
+#define SSD1307FB_DATA 0x40
+#define SSD1307FB_COMMAND 0x80
+
+#define SSD1307FB_CONTRAST 0x81
+#define SSD1307FB_SEG_REMAP_ON 0xa1
+#define SSD1307FB_DISPLAY_OFF 0xae
+#define SSD1307FB_DISPLAY_ON 0xaf
+#define SSD1307FB_START_PAGE_ADDRESS 0xb0
+
+struct ssd1307fb_par {
+ struct i2c_client *client;
+ struct fb_info *info;
+ struct pwm_device *pwm;
+ u32 pwm_period;
+ int reset;
+};
+
+static struct fb_fix_screeninfo ssd1307fb_fix __devinitdata = {
+ .id = "Solomon SSD1307",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_MONO10,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .line_length = SSD1307FB_WIDTH / 8,
+ .accel = FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo ssd1307fb_var __devinitdata = {
+ .xres = SSD1307FB_WIDTH,
+ .yres = SSD1307FB_HEIGHT,
+ .xres_virtual = SSD1307FB_WIDTH,
+ .yres_virtual = SSD1307FB_HEIGHT,
+ .bits_per_pixel = 1,
+};
+
+static int ssd1307fb_write_array(struct i2c_client *client, u8 type, u8* cmd, u32 len)
+{
+ u8 *buf;
+ int ret = 0;
+
+ buf = kzalloc(len + 1, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&client->dev, "Couldn't allocate sending buffer.\n");
+ return -ENOMEM;
+ }
+
+ buf[0] = type;
+ memcpy(buf + 1, cmd, len);
+
+ ret = i2c_master_send(client, buf, len + 1);
+ if (ret != len + 1) {
+ dev_err(&client->dev, "Couldn't send I2C command.\n");
+ goto error;
+ }
+
+error:
+ kfree(buf);
+ return ret;
+}
+
+static inline int ssd1307fb_write_cmd_array(struct i2c_client *client, u8* cmd, u32 len)
+{
+ return ssd1307fb_write_array(client, SSD1307FB_COMMAND, cmd, len);
+}
+
+static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
+{
+ return ssd1307fb_write_cmd_array(client, &cmd, 1);
+}
+
+static inline int ssd1307fb_write_data_array(struct i2c_client *client, u8* cmd, u32 len)
+{
+ return ssd1307fb_write_array(client, SSD1307FB_DATA, cmd, len);
+}
+
+static inline int ssd1307fb_write_data(struct i2c_client *client, u8 data)
+{
+ return ssd1307fb_write_data_array(client, &data, 1);
+}
+
+static void ssd1307fb_update_display(struct ssd1307fb_par *par)
+{
+ u8 *vmem = par->info->screen_base;
+ int i, j, k;
+
+ /*
+ * The screen is divided in pages, each having a height of 8
+ * pixels, and the width of the screen. When sending a byte of
+ * data to the controller, it gives the 8 bits for the current
+ * column. I.e, the first byte are the 8 bits of the first
+ * column, then the 8 bits for the second column, etc.
+ *
+ *
+ * Representation of the screen, assuming it is 5 bits
+ * wide. Each letter-number combination is a bit that controls
+ * one pixel.
+ *
+ * A0 A1 A2 A3 A4
+ * B0 B1 B2 B3 B4
+ * C0 C1 C2 C3 C4
+ * D0 D1 D2 D3 D4
+ * E0 E1 E2 E3 E4
+ * F0 F1 F2 F3 F4
+ * G0 G1 G2 G3 G4
+ * H0 H1 H2 H3 H4
+ *
+ * If you want to update this screen, you need to send 5 bytes:
+ * (1) A0 B0 C0 D0 E0 F0 G0 H0
+ * (2) A1 B1 C1 D1 E1 F1 G1 H1
+ * (3) A2 B2 C2 D2 E2 F2 G2 H2
+ * (4) A3 B3 C3 D3 E3 F3 G3 H3
+ * (5) A4 B4 C4 D4 E4 F4 G4 H4
+ */
+
+ for (i = 0; i < (SSD1307FB_HEIGHT / 8); i++) {
+ ssd1307fb_write_cmd(par->client, SSD1307FB_START_PAGE_ADDRESS + (i + 1));
+ ssd1307fb_write_cmd(par->client, 0x00);
+ ssd1307fb_write_cmd(par->client, 0x10);
+
+ for (j = 0; j < SSD1307FB_WIDTH; j++) {
+ u8 buf = 0;
+ for (k = 0; k < 8; k++) {
+ u32 page_length = SSD1307FB_WIDTH * i;
+ u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8;
+ u8 byte = *(vmem + index);
+ u8 bit = byte & (1 << (7 - (j % 8)));
+ bit = bit >> (7 - (j % 8));
+ buf |= bit << k;
+ }
+ ssd1307fb_write_data(par->client, buf);
+ }
+ }
+}
+
+
+static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ssd1307fb_par *par = info->par;
+ unsigned long total_size;
+ unsigned long p = *ppos;
+ u8 __iomem *dst;
+ int err = 0;
+
+ total_size = info->screen_size;
+
+ if (total_size = 0)
+ total_size = info->fix.smem_len;
+
+ if (p > total_size)
+ return -EFBIG;
+
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
+ }
+
+ if (count + p > total_size) {
+ if (!err)
+ err = -ENOSPC;
+
+ count = total_size - p;
+ }
+
+ dst = (void __force *) (info->screen_base + p);
+
+ if (copy_from_user(dst, buf, count))
+ err = -EFAULT;
+
+ if (!err)
+ *ppos += count;
+
+ ssd1307fb_update_display(par);
+
+ return (err) ? err : count;
+}
+
+static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct ssd1307fb_par *par = info->par;
+ sys_fillrect(info, rect);
+ ssd1307fb_update_display(par);
+}
+
+static void ssd1307fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+ struct ssd1307fb_par *par = info->par;
+ sys_copyarea(info, area);
+ ssd1307fb_update_display(par);
+}
+
+static void ssd1307fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct ssd1307fb_par *par = info->par;
+ sys_imageblit(info, image);
+ ssd1307fb_update_display(par);
+}
+
+static struct fb_ops ssd1307fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_read = fb_sys_read,
+ .fb_write = ssd1307fb_write,
+ .fb_fillrect = ssd1307fb_fillrect,
+ .fb_copyarea = ssd1307fb_copyarea,
+ .fb_imageblit = ssd1307fb_imageblit,
+};
+
+static void ssd1307fb_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ ssd1307fb_update_display(info->par);
+}
+
+static struct fb_deferred_io ssd1307fb_defio = {
+ .delay = HZ,
+ .deferred_io = ssd1307fb_deferred_io,
+};
+
+static int __devinit ssd1307fb_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct fb_info *info;
+ u32 vmem_size = SSD1307FB_WIDTH * SSD1307FB_HEIGHT / 8;
+ struct ssd1307fb_par *par;
+ u8 *vmem;
+ int ret;
+
+ if (!client->dev.of_node) {
+ dev_err(&client->dev, "No device tree data found!\n");
+ return -EINVAL;
+ }
+
+ info = framebuffer_alloc(sizeof(struct ssd1307fb_par), &client->dev);
+ if (!info) {
+ dev_err(&client->dev, "Couldn't allocate framebuffer.\n");
+ return -ENOMEM;
+ }
+
+ vmem = devm_kzalloc(&client->dev, vmem_size, GFP_KERNEL);
+ if (!vmem) {
+ dev_err(&client->dev, "Couldn't allocate graphical memory.\n");
+ ret = -ENOMEM;
+ goto fb_alloc_error;
+ }
+
+ info->fbops = &ssd1307fb_ops;
+ info->fix = ssd1307fb_fix;
+ info->fbdefio = &ssd1307fb_defio;
+
+ info->var = ssd1307fb_var;
+ info->var.red.length = 1;
+ info->var.red.offset = 0;
+ info->var.green.length = 1;
+ info->var.green.offset = 0;
+ info->var.blue.length = 1;
+ info->var.blue.offset = 0;
+
+ info->screen_base = (u8 __force __iomem *)vmem;
+ info->fix.smem_start = (unsigned long)vmem;
+ info->fix.smem_len = vmem_size;
+
+ fb_deferred_io_init(info);
+
+ par = info->par;
+ par->info = info;
+ par->client = client;
+
+ par->reset = of_get_named_gpio(client->dev.of_node,
+ "reset-gpios", 0);
+ if (!gpio_is_valid(par->reset)) {
+ ret = -EINVAL;
+ goto reset_oled_error;
+ }
+
+ ret = devm_gpio_request_one(&client->dev, par->reset,
+ GPIOF_OUT_INIT_HIGH,
+ "oled-reset");
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to request gpio %d: %d\n",
+ par->reset, ret);
+ goto reset_oled_error;
+ }
+
+ par->pwm = pwm_get(&client->dev, NULL);
+ if (IS_ERR(par->pwm)) {
+ dev_err(&client->dev, "Could not get PWM from device tree!\n");
+ ret = PTR_ERR(par->pwm);
+ goto pwm_error;
+ }
+
+ par->pwm_period = pwm_get_period(par->pwm);
+
+ dev_dbg(&client->dev, "Using PWM%d with a %dns period.\n", par->pwm->pwm, par->pwm_period);
+
+ ret = register_framebuffer(info);
+ if (ret) {
+ dev_err(&client->dev, "Couldn't register the framebuffer\n");
+ goto fbreg_error;
+ }
+
+ i2c_set_clientdata(client, info);
+
+ /* Reset the screen */
+ gpio_set_value(par->reset, 0);
+ udelay(4);
+ gpio_set_value(par->reset, 1);
+ udelay(4);
+
+ /* Enable the PWM */
+ pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
+ pwm_enable(par->pwm);
+
+ /* Map column 127 of the OLED to segment 0 */
+ ret = ssd1307fb_write_cmd(client, SSD1307FB_SEG_REMAP_ON);
+ if (ret < 0) {
+ dev_err(&client->dev, "Couldn't remap the screen.\n");
+ goto remap_error;
+ }
+
+ /* Turn on the display */
+ ret = ssd1307fb_write_cmd(client, SSD1307FB_DISPLAY_ON);
+ if (ret < 0) {
+ dev_err(&client->dev, "Couldn't turn the display on.\n");
+ goto remap_error;
+ }
+
+ dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size);
+
+ return 0;
+
+remap_error:
+ unregister_framebuffer(info);
+ pwm_disable(par->pwm);
+fbreg_error:
+ pwm_put(par->pwm);
+pwm_error:
+reset_oled_error:
+ fb_deferred_io_cleanup(info);
+fb_alloc_error:
+ framebuffer_release(info);
+ return ret;
+}
+
+static int __devexit ssd1307fb_remove(struct i2c_client *client)
+{
+ struct fb_info *info = i2c_get_clientdata(client);
+ struct ssd1307fb_par *par = info->par;
+
+ unregister_framebuffer(info);
+ pwm_disable(par->pwm);
+ pwm_put(par->pwm);
+ fb_deferred_io_cleanup(info);
+ framebuffer_release(info);
+
+ return 0;
+}
+
+static const struct i2c_device_id ssd1307fb_i2c_id[] = {
+ { "ssd1307fb", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id);
+
+static const struct of_device_id ssd1307fb_of_match[] = {
+ { .compatible = "solomon,ssd1307fb-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
+
+static struct i2c_driver ssd1307fb_driver = {
+ .probe = ssd1307fb_probe,
+ .remove = __devexit_p(ssd1307fb_remove),
+ .id_table = ssd1307fb_i2c_id,
+ .driver = {
+ .name = "ssd1307fb",
+ .of_match_table = of_match_ptr(ssd1307fb_of_match),
+ .owner = THIS_MODULE,
+ },
+};
+
+module_i2c_driver(ssd1307fb_driver);
+
+MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controler");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_LICENSE("GPL");
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v10 1/6] video: add display_timing and videomode
From: Grant Likely @ 2012-11-15 15:47 UTC (permalink / raw)
To: devicetree-discuss
Cc: linux-fbdev, dri-devel, Tomi Valkeinen, Laurent Pinchart, kernel,
Steffen Trumtrar, Guennady Liakhovetski, linux-media
In-Reply-To: <1352971437-29877-2-git-send-email-s.trumtrar@pengutronix.de>
On Thu, 15 Nov 2012 10:23:52 +0100, Steffen Trumtrar <s.trumtrar@pengutronix.de> wrote:
> 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>.
>
> Also, add helper functions to convert from display timings to a generic videomode
> structure. This videomode can then be converted to the corresponding subsystem
> mode representation (e.g. fb_videomode).
>
> Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
Hmmm... here's my thoughts as an outside reviewer. Correct me if I'm
making an incorrect assumption.
It looks to me that the purpose of this entire series is to decode video
timings from the device tree and (eventually) provide the data in the
form 'struct videomode'. Correct?
If so, then it looks over engineered. Creating new infrastructure to
allocate, maintain, and free a new 'struct display_timings' doesn't make
any sense when it is an intermediary data format that will never be used
by drivers.
Can the DT parsing code instead return a table of struct videomode?
But, wait... struct videomode is also a new structure. So it looks like
this series creates two new intermediary data structures;
display_timings and videomode. And at least as far as I can see in this
series struct fb_videomode is the only user.
g.
--
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.
^ permalink raw reply
* [PATCH 00/32] OMAPDSS: create compat layer
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
Hi,
This series is about improving omapdss API for omapdrm.
We have two separate, exclusive, users of omapdss: 1) omapfb + omap_vout and 2)
omapdrm. Because omapfb and omap_vout are independent drivers, we've built
layers in omapdss to manage the two simultaneous callers. These layers are not
needed for omapdrm, as omapdrm is the sole user of omapdss, and these layers in
fact only create trouble for omapdrm.
The simple option to improve omapdrm situation would be to copy the omapdss
code for omapdrm. We are trying to avoid this, as omapdss and the panel drivers
are quite a lot of code together, and most of the code would be used without
change.
Thus this series helps the situation by moving the omapdss code required by
omapfb + omap_vout to separate files, creating a distinct layer used only by
omapfb + omap_vout. We call this layer "compat layer". This compat layer then
uses the core omapdss driver to operate the hardware. omapdrm will use the core
omapdss directly, without any layers in between.
After this series, omapfb, omap_vout and omapdrm can all be compiled at the
same time. Obviously omapdrm and omapfb+omap_vout cannot be run at the same
time (the first one to start will "win"), so compiling them at the same time is
only sensible as modules for testing purposes. Normal users should only compile
one of those.
This series does not make omapdrm use the core omapdss API, that will happen in
a separate series for omapdrm.
The series is based on current omapdss master, and can also be found from:
git://gitorious.org/linux-omap-dss2/linux.git work/apply-test-9
Tomi
Tomi Valkeinen (32):
OMAPDSS: remove declarations for non-existing functions
OMAPDSS: DPI: fix crash with dpi_verify_dsi_pll()
OMAPDSS: don't WARN if there's no DSI device
OMAPDSS: DISPC: add no_framedone_tv feat
OMAPDSS: DISPC: use get_framedone_irq in disable_digit_out
OMAPDSS: DISPC: Remove blocking code from dispc_wb_enable()
OMAPDSS: cleanup WB enable/is_enabled functions
OMAPDSS: DISPC: use WARN_ON() in dispc_mgr_go
OMAPDSS: DISPC: pclk & lclk rates for writeback
OMAPDSS: DISPC: pass pclk to calc_core_clk()
OMAPDSS: DISPC: pass pclk & lclk to check_horiz_timing_omap3
OMAPDSS: DISPC: pass pclk & lclk to calc_scaling
OMAPDSS: DISPC: pass pclk & lclk to dispc_ovl_calc_scaling
OMAPDSS: create display-sysfs.c
OMAPDSS: add dss_get_core_pdev()
OMAPDSS: add omapdss_compat_init()
OMAPDSS: move ovl & ovl-mgr init to apply.c
OMAPDSS: move ovl-mgr function setup to apply.c
OMAPDSS: move ovl function setup to apply.c
OMAPDSS: add manager ops
OMAPDSS: manage framedone irq with mgr ops
OMAPDSS: move blocking mgr enable/disable to compat layer
OMAPDSS: move omap_dispc_wait_for_irq_interruptible_timeout to
dispc-compat.c
OMAPDSS: move irq handling to dispc-compat
OMAPDSS: DISPC: add dispc_ovl_check()
OMAPDSS: DPI: use dispc's check_timings
OMAPDSS: move display sysfs init to compat layer
OMAPDSS: separate compat files in the Makefile
OMAPDSS: export dss_mgr_ops functions
OMAPDSS: export dss_feat functions
OMAPDSS: export dispc functions
OMAPDSS: use omapdss_compat_init() in other drivers
drivers/media/platform/omap/omap_vout.c | 17 +-
drivers/staging/omapdrm/omap_drv.c | 11 +
drivers/video/omap2/dss/Makefile | 6 +-
drivers/video/omap2/dss/apply.c | 245 ++++++++-
drivers/video/omap2/dss/core.c | 13 +-
drivers/video/omap2/dss/dispc-compat.c | 667 +++++++++++++++++++++++
drivers/video/omap2/dss/dispc-compat.h | 30 ++
drivers/video/omap2/dss/dispc.c | 863 +++++-------------------------
drivers/video/omap2/dss/display-sysfs.c | 321 +++++++++++
drivers/video/omap2/dss/display.c | 285 +---------
drivers/video/omap2/dss/dpi.c | 4 +-
drivers/video/omap2/dss/dsi.c | 26 +-
drivers/video/omap2/dss/dss.h | 75 +--
drivers/video/omap2/dss/dss_features.c | 5 +
drivers/video/omap2/dss/dss_features.h | 4 -
drivers/video/omap2/dss/manager.c | 39 --
drivers/video/omap2/dss/output.c | 65 +++
drivers/video/omap2/dss/overlay.c | 17 -
drivers/video/omap2/dss/rfbi.c | 12 +-
drivers/video/omap2/omapfb/omapfb-main.c | 6 +
include/video/omapdss.h | 80 ++-
21 files changed, 1582 insertions(+), 1209 deletions(-)
create mode 100644 drivers/video/omap2/dss/dispc-compat.c
create mode 100644 drivers/video/omap2/dss/dispc-compat.h
create mode 100644 drivers/video/omap2/dss/display-sysfs.c
--
1.7.10.4
^ permalink raw reply
* [PATCH 01/32] OMAPDSS: remove declarations for non-existing functions
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
Remove dispc_mgr_is_channel_enabled() and dss_mgr_get_timings()
declarations, as the function doesn't exist.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dss.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 84a7f6a..8adf8be 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -197,7 +197,6 @@ void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config);
-const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr);
bool dss_ovl_is_enabled(struct omap_overlay *ovl);
int dss_ovl_enable(struct omap_overlay *ovl);
@@ -444,7 +443,6 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable);
bool dispc_mgr_is_enabled(enum omap_channel channel);
void dispc_mgr_enable_sync(enum omap_channel channel);
void dispc_mgr_disable_sync(enum omap_channel channel);
-bool dispc_mgr_is_channel_enabled(enum omap_channel channel);
void dispc_mgr_set_lcd_config(enum omap_channel channel,
const struct dss_lcd_mgr_config *config);
void dispc_mgr_set_timings(enum omap_channel channel,
--
1.7.10.4
^ permalink raw reply related
* [PATCH 02/32] OMAPDSS: DPI: fix crash with dpi_verify_dsi_pll()
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
If the DSI support has not been compiled in or the SoC doesn't have DSI
hardware, dpi_get_dsidev() returns NULL. This NULL is passed to
dpi_verify_dsi_pll() causing a crash. The bug was added with commit
0e8276ef75f5c7811b038d1d23b2b42c16efc5ac (OMAPDSS: DPI: always use DSI
PLL if available).
Fix this by checking if dsidev is NULL before calling
dpi_verify_dsi_pll().
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dpi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 1e103b3..c109fa6 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -412,7 +412,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
*/
dsidev = dpi_get_dsidev(dssdev->channel);
- if (dpi_verify_dsi_pll(dsidev)) {
+ if (dsidev && dpi_verify_dsi_pll(dsidev)) {
dsidev = NULL;
DSSWARN("DSI PLL not operational\n");
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 03/32] OMAPDSS: don't WARN if there's no DSI device
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
dsi_get_dsidev_from_id() gives a WARN if DSI support is not compiled in.
This warning is not right, as it's valid to call
dsi_get_dsidev_from_id() to see if there is DSI support or not.
Remove the WARN().
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dss.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 8adf8be..09d0651 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -382,8 +382,6 @@ static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
}
static inline struct platform_device *dsi_get_dsidev_from_id(int module)
{
- WARN("%s: DSI not compiled in, returning platform device as NULL\n",
- __func__);
return NULL;
}
#endif
--
1.7.10.4
^ permalink raw reply related
* [PATCH 04/32] OMAPDSS: DISPC: add no_framedone_tv feat
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
OMAP2/3 do not have FRAMEDONETV irq, but later omaps do. We currently
always return 0 from dispc_mgr_get_framedone_irq() for TV output to be
compatible with OMAP2/3.
This patch implements "no_framedone_tv" dispc-feature that is used in
dispc_mgr_get_framedone_irq to return either 0 for OMAP2/3, or the
correct IRQ number for FRAMEDONETV on OMAP4+.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 170c98c..2ec6470 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -100,6 +100,9 @@ struct dispc_features {
/* swap GFX & WB fifos */
bool gfx_fifo_workaround:1;
+
+ /* no DISPC_IRQ_FRAMEDONETV on this SoC */
+ bool no_framedone_tv:1;
};
#define DISPC_MAX_NR_FIFOS 5
@@ -187,7 +190,7 @@ static const struct {
[OMAP_DSS_CHANNEL_DIGIT] = {
.name = "DIGIT",
.vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
- .framedone_irq = 0,
+ .framedone_irq = DISPC_IRQ_FRAMEDONETV,
.sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
.reg_desc = {
[DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
@@ -539,6 +542,9 @@ u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
{
+ if (channel = OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
+ return 0;
+
return mgr_desc[channel].framedone_irq;
}
@@ -4085,6 +4091,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = {
.calc_scaling = dispc_ovl_calc_scaling_24xx,
.calc_core_clk = calc_core_clk_24xx,
.num_fifos = 3,
+ .no_framedone_tv = true,
};
static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
@@ -4097,6 +4104,7 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
.calc_scaling = dispc_ovl_calc_scaling_34xx,
.calc_core_clk = calc_core_clk_34xx,
.num_fifos = 3,
+ .no_framedone_tv = true,
};
static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
@@ -4109,6 +4117,7 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
.calc_scaling = dispc_ovl_calc_scaling_34xx,
.calc_core_clk = calc_core_clk_34xx,
.num_fifos = 3,
+ .no_framedone_tv = true,
};
static const struct dispc_features omap44xx_dispc_feats __initconst = {
--
1.7.10.4
^ permalink raw reply related
* [PATCH 05/32] OMAPDSS: DISPC: use get_framedone_irq in disable_digit_out
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
dispc_mgr_disable_digit_out() needs to wait until the DIGIT output is
turned off. This is done with either VSYNC irq on OMAP2/3 and
FRAMEDONETV on OMAP4+. It currently uses a rather hacky way to decide
what irq to use.
This patch changes dispc_mgr_disable_digit_out to use
dispc_mgr_get_framedone_irq to find out if there's framedone irq on this
SoC, and if not, uses VSYNC.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 2ec6470..0972bd3 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -2726,7 +2726,6 @@ static void dispc_mgr_enable_digit_out(void)
static void dispc_mgr_disable_digit_out(void)
{
DECLARE_COMPLETION_ONSTACK(framedone_compl);
- enum dss_hdmi_venc_clk_source_select src;
int r, i;
u32 irq_mask;
int num_irqs;
@@ -2734,18 +2733,20 @@ static void dispc_mgr_disable_digit_out(void)
if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) = false)
return;
- src = dss_get_hdmi_venc_clk_source();
-
/*
* When we disable the digit output, we need to wait for FRAMEDONE to
- * know that DISPC has finished with the output. For analog tv out we'll
- * use vsync, as omap2/3 don't have framedone for TV.
+ * know that DISPC has finished with the output.
*/
- if (src = DSS_HDMI_M_PCLK) {
- irq_mask = DISPC_IRQ_FRAMEDONETV;
- num_irqs = 1;
- } else {
+ irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
+ num_irqs = 1;
+
+ if (!irq_mask) {
+ /*
+ * omap 2/3 don't have framedone irq for TV, so we need to use
+ * vsyncs for this.
+ */
+
irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
/*
* We need to wait for both even and odd vsyncs. Note that this
--
1.7.10.4
^ permalink raw reply related
* [PATCH 06/32] OMAPDSS: DISPC: Remove blocking code from dispc_wb_enable()
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
WB will not be used with compat-mode, i.e. from omapfb. This means we
don't need the current complex dispc_wb_enable function, but can have a
simple register write version of the function.
This patch removes all the extra code from dispc_wb_enable()
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 35 ++---------------------------------
1 file changed, 2 insertions(+), 33 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 0972bd3..0dca3ff 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -2804,43 +2804,12 @@ void dispc_mgr_disable_sync(enum omap_channel channel)
void dispc_wb_enable(bool enable)
{
- enum omap_plane plane = OMAP_DSS_WB;
- struct completion frame_done_completion;
- bool is_on;
- int r;
- u32 irq;
-
- is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
- irq = DISPC_IRQ_FRAMEDONEWB;
-
- if (!enable && is_on) {
- init_completion(&frame_done_completion);
-
- r = omap_dispc_register_isr(dispc_mgr_disable_isr,
- &frame_done_completion, irq);
- if (r)
- DSSERR("failed to register FRAMEDONEWB isr\n");
- }
-
- REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
-
- if (!enable && is_on) {
- if (!wait_for_completion_timeout(&frame_done_completion,
- msecs_to_jiffies(100)))
- DSSERR("timeout waiting for FRAMEDONEWB\n");
-
- r = omap_dispc_unregister_isr(dispc_mgr_disable_isr,
- &frame_done_completion, irq);
- if (r)
- DSSERR("failed to unregister FRAMEDONEWB isr\n");
- }
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_WB), enable ? 1 : 0, 0, 0);
}
bool dispc_wb_is_enabled(void)
{
- enum omap_plane plane = OMAP_DSS_WB;
-
- return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
+ return REG_GET(DISPC_OVL_ATTRIBUTES(OMAP_DSS_WB), 0, 0);
}
static void dispc_lcd_enable_signal_polarity(bool act_high)
--
1.7.10.4
^ permalink raw reply related
* [PATCH 07/32] OMAPDSS: cleanup WB enable/is_enabled functions
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
Instead of doing direct register reads/writes, dispc_wb_enable() and
dispc_wb_is_enabled() functions can use the common overlay functions to
set and check the enable bit.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 0dca3ff..662bf56 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -2804,12 +2804,12 @@ void dispc_mgr_disable_sync(enum omap_channel channel)
void dispc_wb_enable(bool enable)
{
- REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_WB), enable ? 1 : 0, 0, 0);
+ dispc_ovl_enable(OMAP_DSS_WB, enable);
}
bool dispc_wb_is_enabled(void)
{
- return REG_GET(DISPC_OVL_ATTRIBUTES(OMAP_DSS_WB), 0, 0);
+ return dispc_ovl_enabled(OMAP_DSS_WB);
}
static void dispc_lcd_enable_signal_polarity(bool act_high)
--
1.7.10.4
^ permalink raw reply related
* [PATCH 08/32] OMAPDSS: DISPC: use WARN_ON() in dispc_mgr_go
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
dispc_mgr_go() should never be called with manager output disabled or if
the GO bit is already set. Change the current silent returns to
WARN_ONs.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 662bf56..e219eda 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -565,20 +565,8 @@ bool dispc_mgr_go_busy(enum omap_channel channel)
void dispc_mgr_go(enum omap_channel channel)
{
- bool enable_bit, go_bit;
-
- /* if the channel is not enabled, we don't need GO */
- enable_bit = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE) = 1;
-
- if (!enable_bit)
- return;
-
- go_bit = mgr_fld_read(channel, DISPC_MGR_FLD_GO) = 1;
-
- if (go_bit) {
- DSSERR("GO bit not down for channel %d\n", channel);
- return;
- }
+ WARN_ON(dispc_mgr_is_enabled(channel) = false);
+ WARN_ON(dispc_mgr_go_busy(channel));
DSSDBG("GO %s\n", mgr_desc[channel].name);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 09/32] OMAPDSS: DISPC: pclk & lclk rates for writeback
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
Change the dispc_plane_pclk_rate and dispc_plane_lclk_rate functions to
return 0 if the given plane is the writeback plane. The clocks are not
valid for WB, but returning 0 from these functions instead of running
into BUG() will simplify the code that uses these functions.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index e219eda..8f8d628 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -3226,14 +3226,24 @@ unsigned long dispc_core_clk_rate(void)
static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
{
- enum omap_channel channel = dispc_ovl_get_channel_out(plane);
+ enum omap_channel channel;
+
+ if (plane = OMAP_DSS_WB)
+ return 0;
+
+ channel = dispc_ovl_get_channel_out(plane);
return dispc_mgr_pclk_rate(channel);
}
static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
{
- enum omap_channel channel = dispc_ovl_get_channel_out(plane);
+ enum omap_channel channel;
+
+ if (plane = OMAP_DSS_WB)
+ return 0;
+
+ channel = dispc_ovl_get_channel_out(plane);
return dispc_mgr_lclk_rate(channel);
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 10/32] OMAPDSS: DISPC: pass pclk to calc_core_clk()
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
In order to make the scaling calculations independent of the current
hardware configuration (e.g. which manager is connected to this output),
we need to change the calc funcs to get all the variables needed for the
calculations via parameters.
This patch changes calc_core_clk() function to get pclk as a parameter.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 31 ++++++++++++-------------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 8f8d628..3025792 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -93,7 +93,7 @@ struct dispc_features {
enum omap_color_mode color_mode, bool *five_taps,
int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
- unsigned long (*calc_core_clk) (enum omap_plane plane,
+ unsigned long (*calc_core_clk) (unsigned long pclk,
u16 width, u16 height, u16 out_width, u16 out_height,
bool mem_to_mem);
u8 num_fifos;
@@ -2038,14 +2038,13 @@ static int check_horiz_timing_omap3(enum omap_plane plane,
return 0;
}
-static unsigned long calc_core_clk_five_taps(enum omap_plane plane,
+static unsigned long calc_core_clk_five_taps(unsigned long pclk,
const struct omap_video_timings *mgr_timings, u16 width,
u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode)
{
u32 core_clk = 0;
u64 tmp;
- unsigned long pclk = dispc_plane_pclk_rate(plane);
if (height <= out_height && width <= out_width)
return (unsigned long) pclk;
@@ -2079,22 +2078,19 @@ static unsigned long calc_core_clk_five_taps(enum omap_plane plane,
return core_clk;
}
-static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width,
+static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
{
- unsigned long pclk = dispc_plane_pclk_rate(plane);
-
if (height > out_height && width > out_width)
return pclk * 4;
else
return pclk * 2;
}
-static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width,
+static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
{
unsigned int hf, vf;
- unsigned long pclk = dispc_plane_pclk_rate(plane);
/*
* FIXME how to determine the 'A' factor
@@ -2117,11 +2113,9 @@ static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width,
return pclk * vf * hf;
}
-static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width,
+static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
{
- unsigned long pclk;
-
/*
* If the overlay/writeback is in mem to mem mode, there are no
* downscaling limitations with respect to pixel clock, return 1 as
@@ -2131,8 +2125,6 @@ static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width,
if (mem_to_mem)
return 1;
- pclk = dispc_plane_pclk_rate(plane);
-
if (width > out_width)
return DIV_ROUND_UP(pclk, out_width) * width;
else
@@ -2151,13 +2143,14 @@ static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane,
int min_factor = min(*decim_x, *decim_y);
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
*five_taps = false;
do {
in_height = DIV_ROUND_UP(height, *decim_y);
in_width = DIV_ROUND_UP(width, *decim_x);
- *core_clk = dispc.feat->calc_core_clk(plane, in_width,
+ *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
in_height, out_width, out_height, mem_to_mem);
error = (in_width > maxsinglelinewidth || !*core_clk ||
*core_clk > dispc_core_clk_rate());
@@ -2192,11 +2185,12 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
int min_factor = min(*decim_x, *decim_y);
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
do {
in_height = DIV_ROUND_UP(height, *decim_y);
in_width = DIV_ROUND_UP(width, *decim_x);
- *core_clk = calc_core_clk_five_taps(plane, mgr_timings,
+ *core_clk = calc_core_clk_five_taps(pclk, mgr_timings,
in_width, in_height, out_width, out_height, color_mode);
error = check_horiz_timing_omap3(plane, mgr_timings,
@@ -2208,7 +2202,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
in_height < out_height * 2)
*five_taps = false;
if (!*five_taps)
- *core_clk = dispc.feat->calc_core_clk(plane, in_width,
+ *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
in_height, out_width, out_height,
mem_to_mem);
@@ -2259,12 +2253,11 @@ static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane,
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
if (mem_to_mem) {
in_width_max = out_width * maxdownscale;
} else {
- unsigned long pclk = dispc_plane_pclk_rate(plane);
-
in_width_max = dispc_core_clk_rate() /
DIV_ROUND_UP(pclk, out_width);
}
@@ -2285,7 +2278,7 @@ static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane,
return -EINVAL;
}
- *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height,
+ *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height,
out_width, out_height, mem_to_mem);
return 0;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 11/32] OMAPDSS: DISPC: pass pclk & lclk to check_horiz_timing_omap3
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
In order to make the scaling calculations independent of the current
hardware configuration (e.g. which manager is connected to this output),
we need to change the calc funcs to get all the variables needed for the
calculations via parameters.
This patch changes check_horiz_timing_omap3() to get pclk and lclk as
parameters.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 3025792..cd3dec6 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -1989,7 +1989,7 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
* This function is used to avoid synclosts in OMAP3, because of some
* undocumented horizontal position and timing related limitations.
*/
-static int check_horiz_timing_omap3(enum omap_plane plane,
+static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
const struct omap_video_timings *t, u16 pos_x,
u16 width, u16 height, u16 out_width, u16 out_height)
{
@@ -1997,8 +1997,6 @@ static int check_horiz_timing_omap3(enum omap_plane plane,
unsigned long nonactive;
static const u8 limits[3] = { 8, 10, 20 };
u64 val, blank;
- unsigned long pclk = dispc_plane_pclk_rate(plane);
- unsigned long lclk = dispc_plane_lclk_rate(plane);
int i;
nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
@@ -2186,6 +2184,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
unsigned long pclk = dispc_plane_pclk_rate(plane);
+ unsigned long lclk = dispc_plane_lclk_rate(plane);
do {
in_height = DIV_ROUND_UP(height, *decim_y);
@@ -2193,7 +2192,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
*core_clk = calc_core_clk_five_taps(pclk, mgr_timings,
in_width, in_height, out_width, out_height, color_mode);
- error = check_horiz_timing_omap3(plane, mgr_timings,
+ error = check_horiz_timing_omap3(pclk, lclk, mgr_timings,
pos_x, in_width, in_height, out_width,
out_height);
@@ -2221,8 +2220,8 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
}
} while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
- if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height,
- out_width, out_height)){
+ if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width,
+ height, out_width, out_height)){
DSSERR("horizontal timing too tight\n");
return -EINVAL;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 12/32] OMAPDSS: DISPC: pass pclk & lclk to calc_scaling
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
In order to make the scaling calculations independent of the current
hardware configuration (e.g. which manager is connected to this output),
we need to change the calc funcs to get all the variables needed for the
calculations via parameters.
This patch changes calc_scaling to get pclk and lclk as parameters.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index cd3dec6..155085a 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -87,7 +87,7 @@ struct dispc_features {
u16 sw_max;
u16 vp_max;
u16 hp_max;
- int (*calc_scaling) (enum omap_plane plane,
+ int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
@@ -2129,7 +2129,7 @@ static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
return pclk;
}
-static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane,
+static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
@@ -2141,7 +2141,6 @@ static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane,
int min_factor = min(*decim_x, *decim_y);
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
- unsigned long pclk = dispc_plane_pclk_rate(plane);
*five_taps = false;
@@ -2171,7 +2170,7 @@ static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane,
return 0;
}
-static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
+static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
@@ -2183,8 +2182,6 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
int min_factor = min(*decim_x, *decim_y);
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
- unsigned long pclk = dispc_plane_pclk_rate(plane);
- unsigned long lclk = dispc_plane_lclk_rate(plane);
do {
in_height = DIV_ROUND_UP(height, *decim_y);
@@ -2239,7 +2236,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
return 0;
}
-static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane,
+static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
@@ -2252,7 +2249,6 @@ static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane,
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
- unsigned long pclk = dispc_plane_pclk_rate(plane);
if (mem_to_mem) {
in_width_max = out_width * maxdownscale;
@@ -2294,6 +2290,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
const int max_decim_limit = 16;
unsigned long core_clk = 0;
int decim_x, decim_y, ret;
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+ unsigned long lclk = dispc_plane_lclk_rate(plane);
if (width = out_width && height = out_height)
return 0;
@@ -2329,7 +2327,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
if (decim_y > *y_predecim || out_height > height * 8)
return -EINVAL;
- ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height,
+ ret = dispc.feat->calc_scaling(pclk, lclk, mgr_timings, width, height,
out_width, out_height, color_mode, five_taps,
x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
mem_to_mem);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 13/32] OMAPDSS: DISPC: pass pclk & lclk to dispc_ovl_calc_scaling
From: Tomi Valkeinen @ 2012-11-15 15:58 UTC (permalink / raw)
To: Archit Taneja, Rob Clark; +Cc: linux-omap, linux-fbdev, Tomi Valkeinen
In-Reply-To: <1352995120-3288-1-git-send-email-tomi.valkeinen@ti.com>
In order to make the scaling calculations independent of the current
hardware configuration (e.g. which manager is connected to this output),
we need to change the calc funcs to get all the variables needed for the
calculations via parameters.
This patch changes dispc_ovl_calc_scaling to get pclk and lclk as
parameters.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dispc.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 155085a..f30cdfc 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -2278,7 +2278,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
return 0;
}
-static int dispc_ovl_calc_scaling(enum omap_plane plane,
+static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
enum omap_overlay_caps caps,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
@@ -2290,8 +2290,6 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
const int max_decim_limit = 16;
unsigned long core_clk = 0;
int decim_x, decim_y, ret;
- unsigned long pclk = dispc_plane_pclk_rate(plane);
- unsigned long lclk = dispc_plane_lclk_rate(plane);
if (width = out_width && height = out_height)
return 0;
@@ -2299,7 +2297,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
if ((caps & OMAP_DSS_OVL_CAP_SCALE) = 0)
return -EINVAL;
- if (plane = OMAP_DSS_WB) {
+ if (mem_to_mem) {
*x_predecim = *y_predecim = 1;
} else {
*x_predecim = max_decim_limit;
@@ -2371,6 +2369,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
u16 in_width = width;
int x_predecim = 1, y_predecim = 1;
bool ilace = mgr_timings->interlace;
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+ unsigned long lclk = dispc_plane_lclk_rate(plane);
if (paddr = 0)
return -EINVAL;
@@ -2395,7 +2395,7 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
if (!dss_feat_color_mode_supported(plane, color_mode))
return -EINVAL;
- r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width,
+ r = dispc_ovl_calc_scaling(pclk, lclk, caps, mgr_timings, in_width,
in_height, out_width, out_height, color_mode,
&five_taps, &x_predecim, &y_predecim, pos_x,
rotation_type, mem_to_mem);
--
1.7.10.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox