Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH 0/5] OMAPFB: use dma_alloc instead of omap's vram
From: Tony Lindgren @ 2012-11-20 22:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50A5E801.3000100@ti.com>

* Tomi Valkeinen <tomi.valkeinen@ti.com> [121115 23:17]:
> 
> I added your acks, and pushed:
> 
> git://gitorious.org/linux-omap-dss2/linux.git 3.8/vram-conversion
> 
> It's based on -rc4 as my other branches are based on that.

OK thanks!

Tony

^ permalink raw reply

* Re: [PATCHv9 0/3] Runtime Interpreted Power Sequences
From: Grant Likely @ 2012-11-20 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1353149747-31871-1-git-send-email-acourbot@nvidia.com>

On Sat, 17 Nov 2012 19:55:44 +0900, Alexandre Courbot <acourbot@nvidia.com> wrote:
> Apologies for sending two patchsets in two days - the main purpose
> of this new revision is to add the linux-arm-kernel list to the
> audience. A few suggestions from v8 have also been added.

Just to be clear from my previous reply, don't merge this series. The DT
binding is not good.

g.

^ permalink raw reply

* Re: [PATCHv9 1/3] Runtime Interpreted Power Sequences
From: Grant Likely @ 2012-11-20 21:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1353149747-31871-2-git-send-email-acourbot@nvidia.com>

On Sat, 17 Nov 2012 19:55:45 +0900, Alexandre Courbot <acourbot@nvidia.com> wrote:
> Some device drivers (e.g. panel or backlights) need to follow precise
> sequences for powering on and off, involving GPIOs, regulators, PWMs
> and other power-related resources, with a defined powering order and
> delays to respect between steps. These sequences are device-specific,
> and do not belong to a particular driver - therefore they have been
> performed by board-specific hook functions so far.

I must be honest, this series really makes me nervous...

> With the advent of the device tree and of ARM kernels that are not
> board-tied, we cannot rely on these board-specific hooks anymore but

This isn't strictly true. It is still perfectly fine to have board
specific code when necessary. However, there is strong encouragement to
enable that code in device drivers as much as possible and new board
files need to have very strong justification.

> need a way to implement these sequences in a portable manner. This patch
> introduces a simple interpreter that can execute such power sequences
> encoded either as platform data or within the device tree. It also
> introduces first support for regulator, GPIO and PWM resources.

This is where I start getting nervous. Up to now I've strongly resisted
adding any kind of interpreted code to the device tree. The model is to
identify hardware, but require the driver to know how to control it. (as
compared to ACPI which is entirely designed around executable
bytecode).

While the power sequences described here certainly cannot be confused
with a Turing complete bytecode, it is a step in that direction. Plus,
there will always be that new use case that needs just a "little new
feature" to make this work for that too. Without thinking about how to
handle that ahead of time is just asking for something to turn into a
maintenance nightmare. It's just as important to specify what the limits
of this approach are and when to punt to real driver code to handle a
device.

> +Power Sequences Steps
> +---------------------
> +Steps of a sequence describe an action to be performed on a resource. They
> +always include a "type" property which indicates what kind of resource this
> +step works on. Depending on the resource type, additional properties are defined
> +to control the action to be performed.
> +
> +"delay" type required properties:
> +  - delay: delay to wait (in microseconds)
> +
> +"regulator" type required properties:
> +  - id: name of the regulator to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"pwm" type required properties:
> +  - id: name of the PWM to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"gpio" type required properties:
> +  - gpio: phandle of the GPIO to use.
> +  - value: value this GPIO should take. Must be 0 or 1.
> +
> +Example
> +-------
> +Here are example sequences declared within a backlight device that use all the
> +supported resources types:
> +
> +	backlight {
> +		compatible = "pwm-backlight";
> +		...
> +
> +		/* resources used by the power sequences */
> +		pwms = <&pwm 2 5000000>;
> +		pwm-names = "backlight";
> +		power-supply = <&backlight_reg>;
> +
> +		power-sequences {
> +			power-on {
> +				step0 {
> +					type = "regulator";
> +					id = "power";
> +					enable;
> +				};
> +				step1 {
> +					type = "delay";
> +					delay = <10000>;
> +				};
> +				step2 {
> +					type = "pwm";
> +					id = "backlight";
> +					enable;
> +				};
> +				step3 {
> +					type = "gpio";
> +					gpio = <&gpio 28 0>;
> +					value = <1>;
> +				};
> +			};
> +
> +			power-off {
> +				step0 {
> +					type = "gpio";
> +					gpio = <&gpio 28 0>;
> +					value = <0>;
> +				};
> +				step1 {
> +					type = "pwm";
> +					id = "backlight";
> +					disable;
> +				};
> +				step2 {
> +					type = "delay";
> +					delay = <10000>;
> +				};
> +				step3 {
> +					type = "regulator";
> +					id = "power";
> +					disable;
> +				};
> +			};
> +		};
> +	};

I think this will get very verbose in a hurry. Already this simple
example is 45 lines long. Using the device tree structure to encode the
language doesn't look like a very good fit. Not to mention that the
order of operations is entirely based on the node name. Want to insert
an operation between step0 and step1? Need to rename step1, step2, and
step3 to do so.

This implementation also isn't very consistent. The gpio is referenced
with a phandle in step3/step0, but the regulator and pwm are referenced
by id.

As an alternative, what about something like the following?

	backlight {
		compatible = "pwm-backlight";
		...

		/* resources used by the power sequences */
		pwms = <&pwm 2 5000000>;
		pwm-names = "backlight";
		regulators = <&backlight_reg>;
		gpios = <&gpio 28 0>;

		power-on-sequence = "r0e;d10000m;p0e;g0s";
		power-off-sequence = "g0c;p0d;d10000m;r0d";
	};

I'm thinking about the scripts as trivial-to-parse ascii strings that
have a very simple set of commands. The commands use resources already
defined in the node. ie. 'g0' refers to the first entry in the gpios
property. 'r0' for the regulator, 'p0' for the pwms, 'd' means delay. By
no means take this as the format to use, it is just an example off the
top of my head, but it is already way easier to work with than putting
each command into a node.

The trick is still to define a syntax that doesn't fall apart when it
needs to be extended. I would also like to get opinions on whether or
not conditionals or loops should be supported (ie. loop waiting for a
status to change). If they should then we need to be a lot more careful
about the design (and due to my aforementioned nervousness, somebody may
need to get me therapy).

(Mitch, I'll let you make the argument for using Forth here. To be
honest, I'm not keen on defining any kind of new language, however
simple, but neither am I keen to pull in Forth).

> +Platform Data Format
> +--------------------
> +All relevant data structures for declaring power sequences are located in
> +include/linux/power_seq.h.

Hmm... If sequences are switched to a string instead, then platform_data
should also use it. The power sequence data structures can be created at
runtime by parsing the string.

g.

^ permalink raw reply

* Re: [PATCHv7] video: Add support for the Solomon SSD1307 OLED Controller
From: Andrew Morton @ 2012-11-20 19:43 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1353421237-4100-1-git-send-email-maxime.ripard@free-electrons.com>

On Tue, 20 Nov 2012 15:20:37 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> 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.

Looks OK to my little eye.  I merged it into -mm.  If this
patch (or a variant of it) turns up in linux-next (via Florian's
tree) then I shall autodrop it again.

^ permalink raw reply

* Re: [PATCH v12 0/6] of: add display helper
From: Thierry Reding @ 2012-11-20 19:35 UTC (permalink / raw)
  To: Robert Schwebel
  Cc: Laurent Pinchart, Steffen Trumtrar, devicetree-discuss,
	Rob Herring, linux-fbdev, dri-devel, Guennady Liakhovetski,
	linux-media, Tomi Valkeinen, Stephen Warren, kernel,
	Florian Tobias Schandinat, David Airlie
In-Reply-To: <20121120181129.GI23204@pengutronix.de>

[-- Attachment #1: Type: text/plain, Size: 1128 bytes --]

On Tue, Nov 20, 2012 at 07:11:29PM +0100, Robert Schwebel wrote:
> On Tue, Nov 20, 2012 at 05:13:19PM +0100, Laurent Pinchart wrote:
> > On Tuesday 20 November 2012 16:54:50 Steffen Trumtrar wrote:
> > > Hi!
> > > 
> > > Changes since v11:
> > > 	- make pointers const where applicable
> > > 	- add reviewed-by Laurent Pinchart
> > 
> > Looks good to me.
> > 
> > Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > Through which tree do you plan to push this ?
> 
> We have no idea yet, and none of the people on Cc: have volunteered
> so far... what do you think?

The customary approach would be to take the patches through separate
trees, but I think this particular series is sufficiently interwoven to
warrant taking them all through one tree. However the least that we
should do is collect Acked-by's from the other tree maintainers.

Given that most of the patches modify files in drivers/video, Florian's
fbdev tree would be the most obvious candidate, right? If Florian agrees
to take the patches, all we would need is David's Acked-by.

How does that sound?

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v12 0/6] of: add display helper
From: Robert Schwebel @ 2012-11-20 18:11 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Steffen Trumtrar, devicetree-discuss, Rob Herring, linux-fbdev,
	dri-devel, Thierry Reding, Guennady Liakhovetski, linux-media,
	Tomi Valkeinen, Stephen Warren, kernel, Florian Tobias Schandinat,
	David Airlie
In-Reply-To: <1501232.SOApmW1MhU@avalon>

On Tue, Nov 20, 2012 at 05:13:19PM +0100, Laurent Pinchart wrote:
> On Tuesday 20 November 2012 16:54:50 Steffen Trumtrar wrote:
> > Hi!
> > 
> > Changes since v11:
> > 	- make pointers const where applicable
> > 	- add reviewed-by Laurent Pinchart
> 
> Looks good to me.
> 
> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> Through which tree do you plan to push this ?

We have no idea yet, and none of the people on Cc: have volunteered
so far... what do you think?

rsc
-- 
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

* Re: [PATCH v12 0/6] of: add display helper
From: Laurent Pinchart @ 2012-11-20 16:13 UTC (permalink / raw)
  To: Steffen Trumtrar
  Cc: devicetree-discuss, Rob Herring, linux-fbdev, dri-devel,
	Thierry Reding, Guennady Liakhovetski, linux-media,
	Tomi Valkeinen, Stephen Warren, kernel, Florian Tobias Schandinat,
	David Airlie
In-Reply-To: <1353426896-6045-1-git-send-email-s.trumtrar@pengutronix.de>

On Tuesday 20 November 2012 16:54:50 Steffen Trumtrar wrote:
> Hi!
> 
> Changes since v11:
> 	- make pointers const where applicable
> 	- add reviewed-by Laurent Pinchart

Looks good to me.

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Through which tree do you plan to push this ?

> 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                  |  216 +++++++++++++++++
>  drivers/video/of_videomode.c                       |   48 +++++
>  drivers/video/videomode.c                          |   46 +++++
>  include/drm/drmP.h                                 |   12 ++
>  include/linux/display_timing.h                     |   70 +++++++
>  include/linux/fb.h                                 |   13 ++
>  include/linux/of_display_timings.h                 |   20 ++
>  include/linux/of_videomode.h                       |   18 ++
>  include/linux/videomode.h                          |   40 ++++
>  15 files changed, 793 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
-- 
Regards,

Laurent Pinchart


^ permalink raw reply

* Re: [PATCH] video console: add a driver for lcd2s character display
From: Arnd Bergmann @ 2012-11-20 16:11 UTC (permalink / raw)
  To: Lars Poeschel
  Cc: Lars Poeschel, FlorianSchandinat, mathieu.poirier, linux-fbdev,
	linux-kernel
In-Reply-To: <201211201521.33726.poeschel@lemonage.de>

On Tuesday 20 November 2012, Lars Poeschel wrote:
> > 
> > It's better to define the struct consw as a preinitialized
> > 'static const' object, rather than dynamically setting each
> > member.
> 
> I could not find a place to store the drivers private data inside the struct 
> vc_data. I wanted to have the struct consw inside the drivers private data 
> (struct lcd2s_data) to be able to container_of to the drivers private data in 
> the consw.con_* functions. This makes it possible to use more than one actual 
> lcd2s display with the same driver. Otherwise I have to store the struct 
> i2c_client somewhere statically and the driver can control only one display 
> and has to forbid to be probed a second time. Or am I wrong somewhere ?

I believe you can only have one device anyway, because of the way you
register using "take_over_console(&data->consw, LCD2S_FIRST, LCD2S_LAST, 1);"

Whichever lcd2s was last registered gets VC 8 and 9. This is not nice, but
I think it's similar to how all the other VC work. They consequently don't
store per-device data at all, but just have global variables for device
specific data. We generally discourage this behaviour for device drivers,
but I woulnd't expect you to change the way that VC works, so you can just
do the same here.

Things would be different if this was a "console" driver rather than a "vc"
driver.

	Arnd

^ permalink raw reply

* [PATCH v12 6/6] drm_modes: add of_videomode helpers
From: Steffen Trumtrar @ 2012-11-20 15:54 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA, David Airlie,
	Florian Tobias Schandinat,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Tomi Valkeinen,
	Laurent Pinchart, kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Steffen Trumtrar,
	Guennady Liakhovetski, linux-media-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1353426896-6045-1-git-send-email-s.trumtrar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

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>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 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 0073b27..04feef8 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(const 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(const 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 de2f6cf..377280f 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(const struct videomode *vm,
 					   struct drm_display_mode *dmode);
 #endif
+#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+extern int of_get_drm_display_mode(const 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

* [PATCH v12 5/6] drm_modes: add videomode helpers
From: Steffen Trumtrar @ 2012-11-20 15:54 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,
	Florian Tobias Schandinat, David Airlie
In-Reply-To: <1353426896-6045-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>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 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..0073b27 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(const 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..de2f6cf 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(const 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 v12 4/6] fbmon: add of_videomode helpers
From: Steffen Trumtrar @ 2012-11-20 15:54 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,
	Florian Tobias Schandinat, David Airlie
In-Reply-To: <1353426896-6045-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>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/fbmon.c |   42 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/fb.h    |    7 +++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index c1939a6..16c353c 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(const struct videomode *vm,
 EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
 #endif
 
+#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+static inline void dump_fb_videomode(const 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(const 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 920cbe3..41b5e49 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,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_OF_VIDEOMODE)
+extern int of_get_fb_videomode(const struct device_node *np,
+			       struct fb_videomode *fb,
+			       unsigned int index);
+#endif
 #if IS_ENABLED(CONFIG_VIDEOMODE)
 extern int fb_videomode_from_videomode(const struct videomode *vm,
 				       struct fb_videomode *fbmode);
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH v12 3/6] fbmon: add videomode helpers
From: Steffen Trumtrar @ 2012-11-20 15:54 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA, David Airlie,
	Florian Tobias Schandinat,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Tomi Valkeinen,
	Laurent Pinchart, kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Steffen Trumtrar,
	Guennady Liakhovetski, linux-media-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1353426896-6045-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>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 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..c1939a6 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(const 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..920cbe3 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(const 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 v12 2/6] video: add of helper for videomode
From: Steffen Trumtrar @ 2012-11-20 15:54 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, Florian Tobias Schandinat, David Airlie
In-Reply-To: <1353426896-6045-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>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../devicetree/bindings/video/display-timings.txt  |  107 ++++++++++
 drivers/video/Kconfig                              |   13 ++
 drivers/video/Makefile                             |    2 +
 drivers/video/of_display_timing.c                  |  216 ++++++++++++++++++++
 drivers/video/of_videomode.c                       |   48 +++++
 include/linux/of_display_timings.h                 |   20 ++
 include/linux/of_videomode.h                       |   18 ++
 7 files changed, 424 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..807fedd 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -39,6 +39,19 @@ config DISPLAY_TIMING
 config VIDEOMODE
        bool
 
+config OF_DISPLAY_TIMING
+	bool "Enable OF display timing support"
+	select DISPLAY_TIMING
+	help
+	  helper to parse display timings from the devicetree
+
+config OF_VIDEOMODE
+	bool "Enable OF videomode support"
+	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..3eb731f
--- /dev/null
+++ b/drivers/video/of_display_timing.c
@@ -0,0 +1,216 @@
+/*
+ * 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(const struct device_node *np, const 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(const 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(const 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(const 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..c573f92
--- /dev/null
+++ b/drivers/video/of_videomode.c
@@ -0,0 +1,48 @@
+/*
+ * 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(const 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..2b4fa0a
--- /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(const struct device_node *np);
+int of_display_timings_exists(const 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..4de5fcc
--- /dev/null
+++ b/include/linux/of_videomode.h
@@ -0,0 +1,18 @@
+/*
+ * 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(const struct device_node *np, struct videomode *vm,
+		     int index);
+
+#endif /* __LINUX_OF_VIDEOMODE_H */
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH v12 1/6] video: add display_timing and videomode
From: Steffen Trumtrar @ 2012-11-20 15:54 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,
	Florian Tobias Schandinat, David Airlie
In-Reply-To: <1353426896-6045-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>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/Kconfig          |    6 ++++
 drivers/video/Makefile         |    2 ++
 drivers/video/display_timing.c |   24 ++++++++++++++
 drivers/video/videomode.c      |   46 ++++++++++++++++++++++++++
 include/linux/display_timing.h |   70 ++++++++++++++++++++++++++++++++++++++++
 include/linux/videomode.h      |   40 +++++++++++++++++++++++
 6 files changed, 188 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..e24f879
--- /dev/null
+++ b/drivers/video/videomode.c
@@ -0,0 +1,46 @@
+/*
+ * 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(const 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..d5bf03f
--- /dev/null
+++ b/include/linux/display_timing.h
@@ -0,0 +1,70 @@
+/*
+ * 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(const struct timing_entry *te,
+					   unsigned int index)
+{
+	return te->typ;
+}
+
+static inline struct display_timing *display_timings_get(const 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..5d3e796
--- /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(const struct display_timings *disp,
+			  struct videomode *vm, unsigned int index);
+
+#endif
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH v12 0/6] of: add display helper
From: Steffen Trumtrar @ 2012-11-20 15:54 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,
	Florian Tobias Schandinat, David Airlie

Hi!

Changes since v11:
	- make pointers const where applicable
	- add reviewed-by Laurent Pinchart

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                  |  216 ++++++++++++++++++++
 drivers/video/of_videomode.c                       |   48 +++++
 drivers/video/videomode.c                          |   46 +++++
 include/drm/drmP.h                                 |   12 ++
 include/linux/display_timing.h                     |   70 +++++++
 include/linux/fb.h                                 |   13 ++
 include/linux/of_display_timings.h                 |   20 ++
 include/linux/of_videomode.h                       |   18 ++
 include/linux/videomode.h                          |   40 ++++
 15 files changed, 793 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

* Re: [PATCH 0/5] OMAPFB: use dma_alloc instead of omap's vram
From: Tomi Valkeinen @ 2012-11-20 15:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121119220443.GD18567@atomide.com>

[-- Attachment #1: Type: text/plain, Size: 833 bytes --]

On 2012-11-20 00:04, Tony Lindgren wrote:

>> Should we enable CMA by default in omap2plus_defconfig? And perhaps on
>> omap1 also?
> 
> Yes if that's now needed for DSS.

DSS works fine without CMA, at least for small displays, and when fb
allocation is done at boot time. So it's not a strict "need".

I'm not sure how easily FB allocations start to fail without CMA, and
how much CMA helps.

I'm not even sure what's the default DMA pool size on OMAP... If it's
the one set with "coherent_pool" kernel parameter, then the default
seems to be 256K, which is quite small for video use. For CMA the
default global area is 16M. Both can, of course, be changed with boot
params or kernel config (at least for CMA).

But I think it makes sense to have CMA by default even if non-CMA kernel
would work.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 897 bytes --]

^ permalink raw reply

* Re: [PATCH 0/2] OMAPDSS: DISPC: Update manager size limits for OMAP5
From: Tomi Valkeinen @ 2012-11-20 14:54 UTC (permalink / raw)
  To: Archit Taneja; +Cc: linux-fbdev, linux-omap
In-Reply-To: <1352881216-7490-1-git-send-email-archit@ti.com>

[-- Attachment #1: Type: text/plain, Size: 754 bytes --]

On 2012-11-14 10:20, Archit Taneja wrote:
> Manager width and height can go up to 4K on OMAP5. Make manager width and height
> register field offsets and maximum limits as dispc_features. Create a new
> dispc_feature struct for OMAP5 which highlights this difference.
> 
> Archit Taneja (2):
>   OMAPDSS: Add overlay manager width and height limits as a dispc
>     feature
>   OMAPDSS: Add a dispc_features struct for OMAP5
> 
>  drivers/video/omap2/dss/dispc.c        |   47 +++++++++++++++++++++++++++++---
>  drivers/video/omap2/dss/dss_features.c |    8 ------
>  drivers/video/omap2/dss/dss_features.h |    2 --
>  3 files changed, 43 insertions(+), 14 deletions(-)
> 

Thanks, looks fine. I'll apply to omapdss tree.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 897 bytes --]

^ permalink raw reply

* Re: [PATCHv9 1/3] Runtime Interpreted Power Sequences
From: Tomi Valkeinen @ 2012-11-20 14:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1353149747-31871-2-git-send-email-acourbot@nvidia.com>

[-- Attachment #1: Type: text/plain, Size: 1623 bytes --]

Hi,

On 2012-11-17 12:55, Alexandre Courbot wrote:

A few questions after looking at the documentation:

> +Example
> +-------
> +Here are example sequences declared within a backlight device that use all the
> +supported resources types:
> +
> +	backlight {
> +		compatible = "pwm-backlight";
> +		...
> +
> +		/* resources used by the power sequences */
> +		pwms = <&pwm 2 5000000>;
> +		pwm-names = "backlight";
> +		power-supply = <&backlight_reg>;
> +
> +		power-sequences {
> +			power-on {
> +				step0 {
> +					type = "regulator";
> +					id = "power";
> +					enable;
> +				};
> +				step1 {
> +					type = "delay";
> +					delay = <10000>;
> +				};
> +				step2 {
> +					type = "pwm";
> +					id = "backlight";
> +					enable;
> +				};
> +				step3 {
> +					type = "gpio";
> +					gpio = <&gpio 28 0>;
> +					value = <1>;
> +				};
> +			};

I guess there's a reason, but the above looks a bit inconsistent. For
gpio you define the gpio resource inside the step. For power and pwm the
resource is defined before the steps. Why wouldn't "pwm = <&pwm 2
5000000>;" work in step2?

> +When a power sequence is run, its steps is executed one after the other until
> +one step fails or the end of the sequence is reached.

The document doesn't give any hint of what the driver should do if
running the power sequence fails. Run the "opposite" power sequence?
Will that work for all resources? I'm mainly thinking of a case where
each enable of the resource should be matched by a disable, i.e. you
can't call disable if no enable was called.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 897 bytes --]

^ permalink raw reply

* Re: [PATCH] video console: add a driver for lcd2s character display
From: Lars Poeschel @ 2012-11-20 14:21 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Lars Poeschel, FlorianSchandinat, mathieu.poirier, linux-fbdev,
	linux-kernel
In-Reply-To: <201211201325.57883.arnd@arndb.de>

On Tuesday 20 November 2012 at 14:25:57, Arnd Bergmann wrote:
> On Tuesday 20 November 2012, Lars Poeschel wrote:
> > From: Lars Poeschel <poeschel@lemonage.de>
> > 
> > This driver allows to use a lcd2s 20x4 character display as
> > a linux console output device.
> > 
> > Signed-off-by: Lars Poeschel <poeschel@lemonage.de>
> 
> The driver looks nice overall, but I found two style issues:

Thank you for your feedback.

> > +static int __devinit lcd2s_i2c_probe(struct i2c_client *i2c,
> > +				const struct i2c_device_id *id)
> > +{
> > +	struct lcd2s_data *data;
> > +
> > +	if (!i2c_check_functionality(i2c->adapter,
> > +			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
> > +		return -EIO;
> > +	data = devm_kzalloc(&i2c->dev, sizeof(struct lcd2s_data), 
GFP_KERNEL);
> > +	if (!data)
> > +		return -ENOMEM;
> > +
> > +	data->i2c = i2c;
> > +	data->consw.owner		= THIS_MODULE;
> > +	data->consw.con_startup		= lcd2s_startup;
> > +	data->consw.con_init		= lcd2s_init;
> > +	data->consw.con_deinit		= lcd2s_deinit;
> > +	data->consw.con_clear		= lcd2s_clear;
> > +	data->consw.con_putc		= lcd2s_putc;
> > +	data->consw.con_putcs		= lcd2s_putcs;
> > +	data->consw.con_cursor		= lcd2s_cursor;
> > +	data->consw.con_scroll		= lcd2s_scroll;
> > +	data->consw.con_bmove		= lcd2s_bmove;
> > +	data->consw.con_switch		= lcd2s_switch;
> > +	data->consw.con_blank		= lcd2s_blank;
> > +	data->consw.con_set_palette	= lcd2s_set_palette;
> > +	data->consw.con_scrolldelta	= lcd2s_scrolldelta;
> > +
> > +	i2c_set_clientdata(i2c, data);
> > +
> > +	take_over_console(&data->consw, LCD2S_FIRST, LCD2S_LAST, 1);
> > +
> > +	return 0;
> > +}
> 
> It's better to define the struct consw as a preinitialized
> 'static const' object, rather than dynamically setting each
> member.

I could not find a place to store the drivers private data inside the struct 
vc_data. I wanted to have the struct consw inside the drivers private data 
(struct lcd2s_data) to be able to container_of to the drivers private data in 
the consw.con_* functions. This makes it possible to use more than one actual 
lcd2s display with the same driver. Otherwise I have to store the struct 
i2c_client somewhere statically and the driver can control only one display 
and has to forbid to be probed a second time. Or am I wrong somewhere ?

Lars

^ permalink raw reply

* [PATCHv7] video: Add support for the Solomon SSD1307 OLED Controller
From: Maxime Ripard @ 2012-11-20 14:20 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                              |   15 +
 drivers/video/Makefile                             |    1 +
 drivers/video/ssd1307fb.c                          |  396 ++++++++++++++++++++
 4 files changed, 436 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..48a7676 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2442,4 +2442,19 @@ 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
+	depends on OF
+	depends on GENERIC_GPIO
+	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..9e46633
--- /dev/null
+++ b/drivers/video/ssd1307fb.c
@@ -0,0 +1,396 @@
+/*
+ * 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;
+
+	total_size = info->fix.smem_len;
+
+	if (p > total_size)
+		return -EINVAL;
+
+	if (count + p > total_size)
+		count = total_size - p;
+
+	if (!count)
+		return -EINVAL;
+
+	dst = (void __force *) (info->screen_base + p);
+
+	if (copy_from_user(dst, buf, count))
+		return -EFAULT;
+
+	ssd1307fb_update_display(par);
+
+	*ppos += count;
+
+	return 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] video console: add a driver for lcd2s character display
From: Arnd Bergmann @ 2012-11-20 13:25 UTC (permalink / raw)
  To: Lars Poeschel
  Cc: FlorianSchandinat, poeschel, mathieu.poirier, linux-fbdev,
	linux-kernel
In-Reply-To: <1353416206-3243-1-git-send-email-larsi@wh2.tu-dresden.de>

On Tuesday 20 November 2012, Lars Poeschel wrote:
> From: Lars Poeschel <poeschel@lemonage.de>
> 
> This driver allows to use a lcd2s 20x4 character display as
> a linux console output device.
> 
> Signed-off-by: Lars Poeschel <poeschel@lemonage.de>

The driver looks nice overall, but I found two style issues:

> +static int __devinit lcd2s_i2c_probe(struct i2c_client *i2c,
> +				const struct i2c_device_id *id)
> +{
> +	struct lcd2s_data *data;
> +
> +	if (!i2c_check_functionality(i2c->adapter,
> +			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
> +		return -EIO;
> +	data = devm_kzalloc(&i2c->dev, sizeof(struct lcd2s_data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->i2c = i2c;
> +	data->consw.owner		= THIS_MODULE;
> +	data->consw.con_startup		= lcd2s_startup;
> +	data->consw.con_init		= lcd2s_init;
> +	data->consw.con_deinit		= lcd2s_deinit;
> +	data->consw.con_clear		= lcd2s_clear;
> +	data->consw.con_putc		= lcd2s_putc;
> +	data->consw.con_putcs		= lcd2s_putcs;
> +	data->consw.con_cursor		= lcd2s_cursor;
> +	data->consw.con_scroll		= lcd2s_scroll;
> +	data->consw.con_bmove		= lcd2s_bmove;
> +	data->consw.con_switch		= lcd2s_switch;
> +	data->consw.con_blank		= lcd2s_blank;
> +	data->consw.con_set_palette	= lcd2s_set_palette;
> +	data->consw.con_scrolldelta	= lcd2s_scrolldelta;
> +
> +	i2c_set_clientdata(i2c, data);
> +
> +	take_over_console(&data->consw, LCD2S_FIRST, LCD2S_LAST, 1);
> +
> +	return 0;
> +}

It's better to define the struct consw as a preinitialized
'static const' object, rather than dynamically setting each
member.

> +static struct i2c_driver lcd2s_i2c_driver = {
> +	.driver = {
> +		.name = "lcd2s",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = lcd2s_i2c_probe,
> +	.remove = __devexit_p(lcd2s_i2c_remove),
> +	.id_table = lcd2s_i2c_id,
> +};
> +
> +static int __init lcd2s_modinit(void)
> +{
> +	int ret = 0;
> +
> +	ret = i2c_add_driver(&lcd2s_i2c_driver);
> +	if (ret != 0)
> +		pr_err("Failed to register lcd2s driver\n");
> +
> +	return ret;
> +}
> +module_init(lcd2s_modinit)
> +
> +static void __exit lcd2s_exit(void)
> +{
> +	i2c_del_driver(&lcd2s_i2c_driver);
> +}
> +module_exit(lcd2s_exit)

Here, you can use module_i2c_driver.

	Arnd


^ permalink raw reply

* Re: [PATCH] video: da8xx-fb: clk_get on connection id fck
From: Sekhar Nori @ 2012-11-20 13:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1353415261-30080-1-git-send-email-prakash.pm@ti.com>

On 11/20/2012 6:11 PM, Manjunathappa wrote:
> do clk_get on connection id "fck" to support OMAP based
> platforms having multiple clocks for module. Without this
> driver change clk_get fails on am335x.
> 
> This patch is based on the discussion in community
> http://marc.info/?l=linux-kernel&m\x135166018907827&w=2
> 
> Signed-off-by: Manjunathappa <prakash.pm@ti.com>
> Cc: Vaibhav Hiremath <hvaibhav@ti.com>

For the mach-davinci changes:

Acked-by: Sekhar Nori <nsekhar@ti.com>

Florian,

I assume you will want to take this through your tree?

Thanks,
Sekhar

^ permalink raw reply

* [PATCH] video console: add a driver for lcd2s character display
From: Lars Poeschel @ 2012-11-20 12:56 UTC (permalink / raw)
  To: FlorianSchandinat
  Cc: poeschel, mathieu.poirier, arnd, linux-fbdev, linux-kernel

From: Lars Poeschel <poeschel@lemonage.de>

This driver allows to use a lcd2s 20x4 character display as
a linux console output device.

Signed-off-by: Lars Poeschel <poeschel@lemonage.de>
---
 drivers/video/console/Kconfig    |   10 +
 drivers/video/console/Makefile   |    1 +
 drivers/video/console/lcd2scon.c |  396 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 407 insertions(+)
 create mode 100644 drivers/video/console/lcd2scon.c

diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index e2c96d0..44fc3bf 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -129,6 +129,16 @@ config STI_CONSOLE
           machines.  Say Y here to build support for it into your kernel.
           The alternative is to use your primary serial port as a console.
 
+config LCD2S_CONSOLE
+        tristate "lcd2s 20x4 character display over I2C console"
+        depends on I2C
+        default n
+        help
+          This is a driver that lets you use the lcd2s 20x4 character display
+          from modtronix engineering as a console output device. The display
+          is a simple single color character display. You have to connect it
+          to an I2C bus.
+
 config FONTS
 	bool "Select compiled-in fonts"
 	depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index a862e91..74d5993 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -23,6 +23,7 @@ font-objs += $(font-objs-y)
 obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
 obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
 obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o font.o
+obj-$(CONFIG_LCD2S_CONSOLE)       += lcd2scon.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
 obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o
diff --git a/drivers/video/console/lcd2scon.c b/drivers/video/console/lcd2scon.c
new file mode 100644
index 0000000..0d967ba
--- /dev/null
+++ b/drivers/video/console/lcd2scon.c
@@ -0,0 +1,396 @@
+/*
+ *  console driver for LCD2S 4x20 character displays connected through i2c.
+ *
+ *  This is a driver allowing you to use a LCD2S 4x20 from modtronix
+ *  engineering as console output device.
+ *
+ *  (C) 2012 by Lemonage Software GmbH
+ *  Author: Lars Poeschel <poeschel@lemonage.de>
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console_struct.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include <linux/i2c.h>
+
+#define LCD2S_CMD_CUR_BLINK_OFF		0x10
+#define LCD2S_CMD_CUR_UL_OFF		0x11
+#define LCD2S_CMD_DISPLAY_OFF		0x12
+#define LCD2S_CMD_CUR_BLINK_ON		0x18
+#define LCD2S_CMD_CUR_UL_ON		0x19
+#define LCD2S_CMD_DISPLAY_ON		0x1a
+#define LCD2S_CMD_BACKLIGHT_OFF		0x20
+#define LCD2S_CMD_BACKLIGHT_ON		0x28
+#define LCD2S_CMD_WRITE			0x80
+#define LCD2S_CMD_SHIFT_UP		0x87
+#define LCD2S_CMD_SHIFT_DOWN		0x88
+#define LCD2S_CMD_CUR_ADDR		0x89
+#define LCD2S_CMD_CUR_POS		0x8a
+#define LCD2S_CMD_CUR_RESET		0x8b
+#define LCD2S_CMD_CLEAR			0x8c
+
+#define LCD2S_FIRST			8
+#define LCD2S_LAST			9
+
+#define LCD2S_ROWS			4
+#define LCD2S_COLS			20
+
+struct lcd2s_data {
+	struct i2c_client *i2c;
+	struct consw consw;
+	int row;
+	int col;
+	unsigned int cur_blink:1;
+	unsigned int cur_ul:1;
+};
+
+#define consw_to_lcd2s_data(x)	container_of(x, struct lcd2s_data, consw)
+
+static void lcd2s_set_cursor(struct lcd2s_data *lcd2s, int row, int col)
+{
+	u8 buf[] = { LCD2S_CMD_CUR_POS, row + 1, col + 1};
+
+	if (row = lcd2s->row && col = lcd2s->col)
+		return;
+
+	i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+	lcd2s->row = row;
+	lcd2s->col = col;
+}
+
+static void lcd2s_reset_cursor(struct lcd2s_data *lcd2s)
+{
+	i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_RESET);
+	lcd2s->row = 0;
+	lcd2s->col = 0;
+}
+
+static void lcd2s_increase_cursor(struct lcd2s_data *lcd2s,
+	struct vc_data *con, int inc)
+{
+	lcd2s->col += inc;
+	if ((lcd2s->col / con->vc_cols) >= 1) {
+		lcd2s->row += (lcd2s->col / con->vc_cols);
+		lcd2s->col %= con->vc_cols;
+	}
+}
+
+static void lcd2s_cursor_ul_on(struct lcd2s_data *lcd2s)
+{
+	if (!lcd2s->cur_ul) {
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_UL_ON);
+		lcd2s->cur_ul = 1;
+	}
+}
+
+static void lcd2s_cursor_ul_off(struct lcd2s_data *lcd2s)
+{
+	if (lcd2s->cur_ul) {
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_UL_OFF);
+		lcd2s->cur_ul = 0;
+	}
+}
+
+static void lcd2s_cursor_blink_on(struct lcd2s_data *lcd2s)
+{
+	if (!lcd2s->cur_blink) {
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_BLINK_ON);
+		lcd2s->cur_blink = 1;
+	}
+}
+
+static void lcd2s_cursor_blink_off(struct lcd2s_data *lcd2s)
+{
+	if (lcd2s->cur_blink) {
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CUR_BLINK_OFF);
+		lcd2s->cur_blink = 0;
+	}
+}
+
+static const char *lcd2s_startup(void)
+{
+	return "lcd2s console";
+}
+
+
+/*
+ * init is set if console is currently allocated during init
+ */
+static void lcd2s_init(struct vc_data *con, int init)
+{
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+
+	lcd2s->cur_blink = 0;
+	lcd2s->cur_ul = 0;
+
+	/* turn display on */
+	i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_DISPLAY_ON);
+	i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_BACKLIGHT_ON);
+	i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CLEAR);
+	lcd2s_cursor_ul_on(lcd2s);
+	lcd2s_reset_cursor(lcd2s);
+
+	con->vc_can_do_color = 0;
+	con->vc_hi_font_mask = 0;
+
+	if (init) {
+		con->vc_rows = LCD2S_ROWS;
+		con->vc_cols = LCD2S_COLS;
+	} else
+		vc_resize(con, LCD2S_COLS, LCD2S_ROWS);
+}
+
+static void lcd2s_deinit(struct vc_data *con)
+{
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+
+	i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_DISPLAY_OFF);
+	i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_BACKLIGHT_OFF);
+	lcd2s_cursor_blink_off(lcd2s);
+	lcd2s_cursor_ul_off(lcd2s);
+}
+
+static void lcd2s_clear(struct vc_data *con, int s_row, int s_col,
+			int height, int width)
+{
+	u8 buf[width];
+	int i;
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+
+	if (width <= 0 || height <= 0)
+		return;
+
+	/* if the whole display is to clear, we have a single command */
+	if (s_col = 0 && s_row = 0 &&
+		height >= con->vc_rows - 1 && width >= con->vc_cols - 1) {
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_CLEAR);
+		return;
+	}
+
+	for (i = 0; i <= width; i++)
+		buf[i] = ' ';
+
+	for (i = s_col; i <= height; i++) {
+		lcd2s_set_cursor(lcd2s, s_row, i);
+		i2c_master_send(lcd2s->i2c, buf, width);
+	}
+}
+
+static void lcd2s_putc(struct vc_data *con, int data, int row, int col)
+{
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+	u8 buf[] = {LCD2S_CMD_WRITE, data};
+
+	lcd2s_set_cursor(lcd2s, row, col);
+
+	i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+	lcd2s_increase_cursor(lcd2s, con, 1);
+}
+
+static void lcd2s_putcs(struct vc_data *con, const unsigned short *buf,
+			int len, int row, int col)
+{
+	u8 *i2c_buf;
+	int i;
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+
+	i2c_buf = kzalloc(len + 1, GFP_KERNEL);
+	if (!i2c_buf)
+		return;
+
+	lcd2s_set_cursor(lcd2s, row, col);
+
+	i2c_buf[0] = LCD2S_CMD_WRITE;
+	for (i = 0; i < len ; i++)
+		i2c_buf[i + 1] = buf[i];
+
+	i2c_master_send(lcd2s->i2c, i2c_buf, len + 1);
+	kfree(i2c_buf);
+	lcd2s_increase_cursor(lcd2s, con, len);
+}
+
+static void lcd2s_cursor(struct vc_data *con, int mode)
+{
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+
+	switch (mode) {
+	case CM_ERASE:
+		lcd2s_cursor_blink_off(lcd2s);
+		lcd2s_cursor_ul_off(lcd2s);
+		break;
+	case CM_MOVE:
+	case CM_DRAW:
+		lcd2s_set_cursor(lcd2s, con->vc_y, con->vc_x);
+
+		switch (con->vc_cursor_type & CUR_HWMASK) {
+		case CUR_UNDERLINE:
+			lcd2s_cursor_ul_on(lcd2s);
+			lcd2s_cursor_blink_off(lcd2s);
+			break;
+		case CUR_NONE:
+			lcd2s_cursor_blink_off(lcd2s);
+			lcd2s_cursor_ul_off(lcd2s);
+			break;
+		default:
+			lcd2s_cursor_blink_on(lcd2s);
+			lcd2s_cursor_ul_off(lcd2s);
+			break;
+		}
+		break;
+	}
+}
+
+static int lcd2s_scroll(struct vc_data *con, int top, int bot,
+			int dir, int lines)
+{
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+
+	/* we can only scroll the whole display */
+	if (top = 0 && bot = con->vc_rows) {
+		while (lines--) {
+			switch (dir) {
+			case SM_UP:
+				i2c_smbus_write_byte(lcd2s->i2c,
+					LCD2S_CMD_SHIFT_UP);
+				break;
+			case SM_DOWN:
+				i2c_smbus_write_byte(lcd2s->i2c,
+					LCD2S_CMD_SHIFT_DOWN);
+				break;
+			}
+		}
+		return 0;
+	}
+	return 1;
+}
+
+static void lcd2s_bmove(struct vc_data *conp, int s_row, int s_col,
+			int d_row, int d_col, int height, int width)
+{
+}
+
+static int lcd2s_switch(struct vc_data *con)
+{
+	return 1;
+}
+
+static int lcd2s_blank(struct vc_data *con, int blank, int mode_switch)
+{
+	struct lcd2s_data *lcd2s = consw_to_lcd2s_data(con->vc_sw);
+
+	switch (blank) {
+	case 0:		/* unblank */
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_DISPLAY_ON);
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_BACKLIGHT_ON);
+		break;
+	case 1:		/* normal blanking */
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_DISPLAY_OFF);
+		i2c_smbus_write_byte(lcd2s->i2c, LCD2S_CMD_BACKLIGHT_OFF);
+		break;
+	}
+	return 0;
+}
+
+static int lcd2s_set_palette(struct vc_data *con, unsigned char *table)
+{
+	return -EINVAL;
+}
+
+static int lcd2s_scrolldelta(struct vc_data *con, int lines)
+{
+	return 0;
+}
+
+static int __devinit lcd2s_i2c_probe(struct i2c_client *i2c,
+				const struct i2c_device_id *id)
+{
+	struct lcd2s_data *data;
+
+	if (!i2c_check_functionality(i2c->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+		return -EIO;
+	data = devm_kzalloc(&i2c->dev, sizeof(struct lcd2s_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->i2c = i2c;
+	data->consw.owner		= THIS_MODULE;
+	data->consw.con_startup		= lcd2s_startup;
+	data->consw.con_init		= lcd2s_init;
+	data->consw.con_deinit		= lcd2s_deinit;
+	data->consw.con_clear		= lcd2s_clear;
+	data->consw.con_putc		= lcd2s_putc;
+	data->consw.con_putcs		= lcd2s_putcs;
+	data->consw.con_cursor		= lcd2s_cursor;
+	data->consw.con_scroll		= lcd2s_scroll;
+	data->consw.con_bmove		= lcd2s_bmove;
+	data->consw.con_switch		= lcd2s_switch;
+	data->consw.con_blank		= lcd2s_blank;
+	data->consw.con_set_palette	= lcd2s_set_palette;
+	data->consw.con_scrolldelta	= lcd2s_scrolldelta;
+
+	i2c_set_clientdata(i2c, data);
+
+	take_over_console(&data->consw, LCD2S_FIRST, LCD2S_LAST, 1);
+
+	return 0;
+}
+
+static __devexit int lcd2s_i2c_remove(struct i2c_client *i2c)
+{
+	struct lcd2s_data *data = i2c_get_clientdata(i2c);
+
+	/* unregister from console subsystem */
+	unregister_con_driver(&data->consw);
+	return 0;
+}
+
+static const struct i2c_device_id lcd2s_i2c_id[] = {
+	{ "lcd2s", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lcd2s_i2c_id);
+
+static struct i2c_driver lcd2s_i2c_driver = {
+	.driver = {
+		.name = "lcd2s",
+		.owner = THIS_MODULE,
+	},
+	.probe = lcd2s_i2c_probe,
+	.remove = __devexit_p(lcd2s_i2c_remove),
+	.id_table = lcd2s_i2c_id,
+};
+
+static int __init lcd2s_modinit(void)
+{
+	int ret = 0;
+
+	ret = i2c_add_driver(&lcd2s_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register lcd2s driver\n");
+
+	return ret;
+}
+module_init(lcd2s_modinit)
+
+static void __exit lcd2s_exit(void)
+{
+	i2c_del_driver(&lcd2s_i2c_driver);
+}
+module_exit(lcd2s_exit)
+
+MODULE_DESCRIPTION("LCD2S character display console driver");
+MODULE_AUTHOR("Lars Poeschel");
+MODULE_LICENSE("GPL");
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH] video: da8xx-fb: clk_get on connection id fck
From: Manjunathappa @ 2012-11-20 12:53 UTC (permalink / raw)
  To: linux-arm-kernel

do clk_get on connection id "fck" to support OMAP based
platforms having multiple clocks for module. Without this
driver change clk_get fails on am335x.

This patch is based on the discussion in community
http://marc.info/?l=linux-kernel&m\x135166018907827&w=2

Signed-off-by: Manjunathappa <prakash.pm@ti.com>
Cc: Vaibhav Hiremath <hvaibhav@ti.com>
---
 arch/arm/mach-davinci/da830.c     |    2 +-
 arch/arm/mach-davinci/da850.c     |    2 +-
 arch/arm/mach-davinci/pm_domain.c |    1 +
 drivers/video/da8xx-fb.c          |    2 +-
 4 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index deee5c2..ee8504f 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -408,7 +408,7 @@ static struct clk_lookup da830_clks[] = {
 	CLK(NULL,		"pwm2",		&pwm2_clk),
 	CLK("eqep.0",		NULL,		&eqep0_clk),
 	CLK("eqep.1",		NULL,		&eqep1_clk),
-	CLK("da8xx_lcdc.0",	NULL,		&lcdc_clk),
+	CLK("da8xx_lcdc.0",	"fck",		&lcdc_clk),
 	CLK("davinci-mcasp.0",	NULL,		&mcasp0_clk),
 	CLK("davinci-mcasp.1",	NULL,		&mcasp1_clk),
 	CLK("davinci-mcasp.2",	NULL,		&mcasp2_clk),
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index b44dc84..bc75bdd 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -389,7 +389,7 @@ static struct clk_lookup da850_clks[] = {
 	CLK(NULL,		"rmii",		&rmii_clk),
 	CLK("davinci_emac.1",	NULL,		&emac_clk),
 	CLK("davinci-mcasp.0",	NULL,		&mcasp_clk),
-	CLK("da8xx_lcdc.0",	NULL,		&lcdc_clk),
+	CLK("da8xx_lcdc.0",	"fck",		&lcdc_clk),
 	CLK("davinci_mmc.0",	NULL,		&mmcsd0_clk),
 	CLK("davinci_mmc.1",	NULL,		&mmcsd1_clk),
 	CLK(NULL,		"aemif",	&aemif_clk),
diff --git a/arch/arm/mach-davinci/pm_domain.c b/arch/arm/mach-davinci/pm_domain.c
index 00946e2..c90250e 100644
--- a/arch/arm/mach-davinci/pm_domain.c
+++ b/arch/arm/mach-davinci/pm_domain.c
@@ -53,6 +53,7 @@ static struct dev_pm_domain davinci_pm_domain = {
 
 static struct pm_clk_notifier_block platform_bus_notifier = {
 	.pm_domain = &davinci_pm_domain,
+	.con_ids = { "fck", NULL, },
 };
 
 static int __init davinci_pm_runtime_init(void)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index f0f21c8..bb68533 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -1248,7 +1248,7 @@ static int __devinit fb_probe(struct platform_device *device)
 		goto err_request_mem;
 	}
 
-	fb_clk = clk_get(&device->dev, NULL);
+	fb_clk = clk_get(&device->dev, "fck");
 	if (IS_ERR(fb_clk)) {
 		dev_err(&device->dev, "Can not get device clock\n");
 		ret = -ENODEV;
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH 2/2] video: exynos-mipi-dsi: Adding DT support to exynos mipi driver
From: Shaik Ameer Basha @ 2012-11-20 11:48 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1352547285-12302-3-git-send-email-shaik.ameer@samsung.com>

Hi Donghwa Lee,

On Tue, Nov 20, 2012 at 7:42 AM, Donghwa Lee <dh09.lee@samsung.com> wrote:
> On 10 Nov, 2012 20:34, Shaik Ameer Basha wrote:
>
>> This patch adds the DT support for the exynos mipi-dsi driver.
>> for DT support mipi device node should supply the following
>> information to the mipi-dsi driver.
>> 1] dsim_config information
>> 2] d-phy setting information
>> 3] lcd poweron, reset information
>> 4] fb_videomode information
>> [...]
>
>>
>
>> diff --git a/include/video/exynos_mipi_dsim.h b/include/video/exynos_mipi_dsim.h
>> index 772c770..6d9b01d 100644
>> --- a/include/video/exynos_mipi_dsim.h
>> +++ b/include/video/exynos_mipi_dsim.h
>> @@ -230,6 +230,7 @@ struct mipi_dsim_device {
>>       struct mipi_dsim_master_ops     *master_ops;
>>       struct mipi_dsim_lcd_device     *dsim_lcd_dev;
>>       struct mipi_dsim_lcd_driver     *dsim_lcd_drv;
>> +     struct mipi_dsim_phy_config     *dsim_phy_config;
>>
>>       unsigned int                    state;
>>       unsigned int                    data_lane;
>> @@ -295,6 +296,32 @@ struct mipi_dsim_master_ops {
>>  };
>>
>>  /*
>> + * phy node structure for mipi-dsim.
>> + *
>> + * @reg_enable_dphy  : base address to memory mapped D-PHY enable register
>> + * @ctrlbit_enable_dphy : control bit for enabling D-PHY
>> + * @reg_reset_dsim   : base address to memory mapped DSIM reset register
>> + * @ctrlbit_reset_dsim       : control bit for resetting DSIM
>> + */
>> +struct mipi_dsim_phy_config_type1 {
>> +     void __iomem    *reg_enable_dphy;
>> +     int             ctrlbit_enable_dphy;
>> +     void __iomem    *reg_reset_dsim;
>> +     int             ctrlbit_reset_dsim;
>> +};
>> +
>> +enum mipi_dsim_phy_config_type {
>> +     MIPI_DSIM_PHY_CONFIG_TYPE1,
>> +};
>> +
>> +struct mipi_dsim_phy_config {
>> +     enum mipi_dsim_phy_config_type type;
>> +     union {
>> +             struct mipi_dsim_phy_config_type1 phy_cfg_type1;
>> +     };
>> +};
>> +
>> +/*
>>   * device structure for mipi-dsi based lcd panel.
>>   *
>>   * @name: name of the device to use with this device, or an
>
>
> Hi,
>
> Does mipi-phy-type1 means MIPI_PHYx_CONTROL register of PMU?
> If so, why did you define only 'type1'? Even if you do not use 'type0'
> on your case, should be defined 'type0' in the 'mipi_dsim_phy_config_type'?

Yes, you are right.
Sorry, I should have used 'type0' as you mentioned.

>
> And Is it correct to access to the PMU registers directly in the mipi
> dsi driver to control mipi-phyx?

As the current way of controlling PHY (i.e., through callbacks from
platform data) is not acceptable,
I had only two options to choose,
1] Controlling PHY in the mipi-dsi driver itself
2] To create a seperate PHY driver for mipi-dsi.

Currently I implemented the first method to removing the PHY related
callbacks from platform data.

I thought, there should not be any issue with directly controlling PMU
registers from mipi-dsi driver.
Please suggest any better implementation for solving this problem.


Thanks,
Shaik Ameer Basha

>
> Thanks,
> Donghwa Lee
> --
> 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

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox