mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support
@ 2017-02-24 14:24 Bastian Stender
  2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Bastian Stender @ 2017-02-24 14:24 UTC (permalink / raw)
  To: barebox; +Cc: Bastian Stender

Hi,

This patch set basically adds support for the Solomon SSD1307 OLED
controller family along with some framebuffer and console features
needed.

To enable opening and closing consoles regardless of stdin, stdout and
stderr the open and close methods were introduced. In combination with
the 2nd patch it is now possible to display text with
'echo -o <console device> abcdef'.

The 3rd patch adds a flush method for drivers using a virtual
framebuffer - like the SSD1307 OLED controller. It is called at
appropriate times. The 4th patch finally adds Solomon SSD1307 OLED
controller support.

Regards,
Bastian

Bastian Stender (4):
  console: replace set_active by open/close
  console: expose consoles in devfs
  fb: introduce flush for virtual framebuffer
  video: add support for Solomon SSD1307 OLED controller family

 commands/fbtest.c         |   1 +
 common/console.c          |  71 +++++-
 drivers/video/Kconfig     |   4 +
 drivers/video/Makefile    |   1 +
 drivers/video/fb.c        |  26 +++
 drivers/video/fbconsole.c |  31 ++-
 drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++
 include/console.h         |   6 +-
 include/fb.h              |   2 +
 net/netconsole.c          |  27 ++-
 10 files changed, 713 insertions(+), 25 deletions(-)
 create mode 100644 drivers/video/ssd1307fb.c

-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/4] console: replace set_active by open/close
  2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender
@ 2017-02-24 14:24 ` Bastian Stender
  2017-02-27  9:54   ` Sascha Hauer
  2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Bastian Stender @ 2017-02-24 14:24 UTC (permalink / raw)
  To: barebox; +Cc: Bastian Stender

Opening and closing consoles should be independent from setting them
active. This way it is possible to open e.g. a framebuffer console and
display text on it without showing stdout/stderr.

Signed-off-by: Bastian Stender <bst@pengutronix.de>
---
 common/console.c          | 19 +++++++++++++++----
 drivers/video/fbconsole.c | 28 ++++++++++++++++++----------
 include/console.h         |  3 ++-
 net/netconsole.c          | 27 +++++++++++++++++----------
 4 files changed, 52 insertions(+), 25 deletions(-)

diff --git a/common/console.c b/common/console.c
index 74ccfcfc3e..43890b3da8 100644
--- a/common/console.c
+++ b/common/console.c
@@ -71,10 +71,21 @@ int console_set_active(struct console_device *cdev, unsigned flag)
 	if (!flag && cdev->f_active && cdev->flush)
 		cdev->flush(cdev);
 
-	if (cdev->set_active) {
-		ret = cdev->set_active(cdev, flag);
-		if (ret)
-			return ret;
+	if (flag == cdev->f_active)
+		return 0;
+
+	if (!flag) {
+		if (cdev->close) {
+			ret = cdev->close(cdev);
+			if (ret)
+				return ret;
+		}
+	} else {
+		if (cdev->open) {
+			ret = cdev->open(cdev);
+			if (ret)
+				return ret;
+		}
 	}
 
 	cdev->f_active = flag;
diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c
index 693c21f547..64f7d7364e 100644
--- a/drivers/video/fbconsole.c
+++ b/drivers/video/fbconsole.c
@@ -365,21 +365,13 @@ static int setup_font(struct fbc_priv *priv)
 	return 0;
 }
 
-static int fbc_set_active(struct console_device *cdev, unsigned flags)
+static int fbc_open(struct console_device *cdev)
 {
 	struct fbc_priv *priv = container_of(cdev,
 					struct fbc_priv, cdev);
 	struct fb_info *fb = priv->fb;
 	int ret;
 
-	if (priv->active) {
-		fb_close(priv->sc);
-		priv->active = false;
-	}
-
-	if (!(flags & (CONSOLE_STDOUT | CONSOLE_STDERR)))
-		return 0;
-
 	ret = setup_font(priv);
 	if (ret)
 		return ret;
@@ -400,6 +392,21 @@ static int fbc_set_active(struct console_device *cdev, unsigned flags)
 	return 0;
 }
 
+static int fbc_close(struct console_device *cdev)
+{
+	struct fbc_priv *priv = container_of(cdev,
+					struct fbc_priv, cdev);
+
+	if (priv->active) {
+		fb_close(priv->sc);
+		priv->active = false;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static int set_font(struct param_d *p, void *vpriv)
 {
 	struct fbc_priv *priv = vpriv;
@@ -434,7 +441,8 @@ int register_fbconsole(struct fb_info *fb)
 	cdev->getc = fbc_getc;
 	cdev->devname = "fbconsole";
 	cdev->devid = DEVICE_ID_DYNAMIC;
-	cdev->set_active = fbc_set_active;
+	cdev->open = fbc_open;
+	cdev->close = fbc_close;
 
 	ret = console_register(cdev);
 	if (ret) {
diff --git a/include/console.h b/include/console.h
index 4b2f134a4c..53f6e47fcc 100644
--- a/include/console.h
+++ b/include/console.h
@@ -44,7 +44,8 @@ struct console_device {
 	int (*setbrg)(struct console_device *cdev, int baudrate);
 	void (*flush)(struct console_device *cdev);
 	int (*set_mode)(struct console_device *cdev, enum console_mode mode);
-	int (*set_active)(struct console_device *cdev, unsigned active);
+	int (*open)(struct console_device *cdev);
+	int (*close)(struct console_device *cdev);
 
 	char *devname;
 	int devid;
diff --git a/net/netconsole.c b/net/netconsole.c
index ce3c418798..ef8b1856b6 100644
--- a/net/netconsole.c
+++ b/net/netconsole.c
@@ -105,19 +105,11 @@ static void nc_putc(struct console_device *cdev, char c)
 	priv->busy = 0;
 }
 
-static int nc_set_active(struct console_device *cdev, unsigned flags)
+static int nc_open(struct console_device *cdev)
 {
 	struct nc_priv *priv = container_of(cdev,
 					struct nc_priv, cdev);
 
-	if (priv->con) {
-		net_unregister(priv->con);
-		priv->con = NULL;
-	}
-
-	if (!flags)
-		return 0;
-
 	if (!priv->port) {
 		pr_err("port not set\n");
 		return -EINVAL;
@@ -142,6 +134,20 @@ static int nc_set_active(struct console_device *cdev, unsigned flags)
 	return 0;
 }
 
+static int nc_close(struct console_device *cdev)
+{
+	struct nc_priv *priv = container_of(cdev,
+					struct nc_priv, cdev);
+
+	if (priv->con) {
+		net_unregister(priv->con);
+		priv->con = NULL;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static int netconsole_init(void)
 {
 	struct nc_priv *priv;
@@ -155,7 +161,8 @@ static int netconsole_init(void)
 	cdev->getc = nc_getc;
 	cdev->devname = "netconsole";
 	cdev->devid = DEVICE_ID_SINGLE;
-	cdev->set_active = nc_set_active;
+	cdev->open = nc_open;
+	cdev->close = nc_close;
 
 	g_priv = priv;
 
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/4] console: expose consoles in devfs
  2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender
  2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender
@ 2017-02-24 14:24 ` Bastian Stender
  2017-02-27  9:55   ` Sascha Hauer
  2017-02-24 14:25 ` [PATCH 3/4] fb: introduce flush for virtual framebuffer Bastian Stender
  2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender
  3 siblings, 1 reply; 15+ messages in thread
From: Bastian Stender @ 2017-02-24 14:24 UTC (permalink / raw)
  To: barebox; +Cc: Bastian Stender

This enables displaying text on e.g. a framebuffer console by issueing

	echo -o /dev/fbconsole0 abc123

Signed-off-by: Bastian Stender <bst@pengutronix.de>
---
 common/console.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/console.h |  3 +++
 2 files changed, 55 insertions(+)

diff --git a/common/console.c b/common/console.c
index 43890b3da8..dcd67afe20 100644
--- a/common/console.c
+++ b/common/console.c
@@ -243,6 +243,39 @@ static int __console_puts(struct console_device *cdev, const char *s)
 	return n;
 }
 
+static int fops_open(struct cdev *cdev, unsigned long flags)
+{
+	struct console_device *priv = cdev->priv;
+
+	return priv->open(priv);
+}
+
+static int fops_close(struct cdev *dev)
+{
+	struct console_device *priv = dev->priv;
+
+	return priv->close(priv);
+}
+
+static int fops_flush(struct cdev *dev)
+{
+	struct console_device *priv = dev->priv;
+
+	priv->flush(priv);
+
+	return 0;
+}
+
+static int fops_write(struct cdev* dev, const void* buf, size_t count,
+		      loff_t offset, ulong flags)
+{
+	struct console_device *priv = dev->priv;
+
+	priv->puts(priv, buf);
+
+	return 0;
+}
+
 int console_register(struct console_device *newcdev)
 {
 	struct device_d *dev = &newcdev->class_dev;
@@ -295,6 +328,25 @@ int console_register(struct console_device *newcdev)
 		console_set_active(newcdev, CONSOLE_STDIN |
 				CONSOLE_STDOUT | CONSOLE_STDERR);
 
+	/* expose console as device in fs */
+	newcdev->devfs.name = basprintf("%s%d", newcdev->class_dev.name,
+					newcdev->class_dev.id);
+	newcdev->devfs.priv = newcdev;
+	newcdev->devfs.dev = dev;
+	newcdev->devfs.ops = &newcdev->fops;
+	newcdev->devfs.flags = DEVFS_IS_CHARACTER_DEV;
+	newcdev->fops.open = fops_open;
+	newcdev->fops.close = fops_close;
+	newcdev->fops.flush = fops_flush;
+	newcdev->fops.write = fops_write;
+
+	ret = devfs_create(&newcdev->devfs);
+
+	if (ret) {
+		pr_err("device creation failed with %s\n", strerror(-ret));
+		return ret;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(console_register);
diff --git a/include/console.h b/include/console.h
index 53f6e47fcc..d9fa05c2ce 100644
--- a/include/console.h
+++ b/include/console.h
@@ -59,6 +59,9 @@ struct console_device {
 	unsigned int baudrate_param;
 
 	const char *linux_console_name;
+
+	struct cdev devfs;
+	struct file_operations fops;
 };
 
 int console_register(struct console_device *cdev);
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/4] fb: introduce flush for virtual framebuffer
  2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender
  2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender
  2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender
@ 2017-02-24 14:25 ` Bastian Stender
  2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender
  3 siblings, 0 replies; 15+ messages in thread
From: Bastian Stender @ 2017-02-24 14:25 UTC (permalink / raw)
  To: barebox; +Cc: Bastian Stender

Some drivers need an explicit sync method to flush the virtual
framebuffer to the display. It is called fb_flush().

fb_flush() gets called on fbc_putc, on fb_close and in the pattern cycle
in the fbtest command.

Signed-off-by: Bastian Stender <bst@pengutronix.de>
---
 commands/fbtest.c         |  1 +
 drivers/video/fb.c        | 26 ++++++++++++++++++++++++++
 drivers/video/fbconsole.c |  3 +++
 include/fb.h              |  2 ++
 4 files changed, 32 insertions(+)

diff --git a/commands/fbtest.c b/commands/fbtest.c
index bd0e140d07..ca6ec21991 100644
--- a/commands/fbtest.c
+++ b/commands/fbtest.c
@@ -169,6 +169,7 @@ static int do_fbtest(int argc, char *argv[])
 			pattern = patterns[i++ % ARRAY_SIZE(patterns)].func;
 			pattern(sc, color);
 			gu_screen_blit(sc);
+			fb_flush(sc->info);
 
 			start = get_time_ns();
 			while (!is_timeout(start, 2 * SECOND))
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index 4d2d3aa650..6b88f2df97 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -31,6 +31,30 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data)
 	return 0;
 }
 
+static int fb_close(struct cdev *cdev)
+{
+	struct fb_info *info = cdev->priv;
+
+	if (info->fbops->fb_flush)
+		info->fbops->fb_flush(info);
+	return 0;
+}
+
+static int fb_op_flush(struct cdev *cdev)
+{
+	struct fb_info *info = cdev->priv;
+
+	if (info->fbops->fb_flush)
+		info->fbops->fb_flush(info);
+	return 0;
+}
+
+void fb_flush(struct fb_info *info)
+{
+	if (info->fbops->fb_flush)
+		info->fbops->fb_flush(info);
+}
+
 static void fb_release_shadowfb(struct fb_info *info)
 {
 	free(info->screen_base_shadow);
@@ -199,6 +223,8 @@ static struct file_operations fb_ops = {
 	.memmap	= generic_memmap_rw,
 	.lseek	= dev_lseek_default,
 	.ioctl	= fb_ioctl,
+	.close  = fb_close,
+	.flush  = fb_op_flush,
 };
 
 static void fb_print_mode(struct fb_videomode *mode)
diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c
index 64f7d7364e..4cf8338ed8 100644
--- a/drivers/video/fbconsole.c
+++ b/drivers/video/fbconsole.c
@@ -292,6 +292,7 @@ static void fbc_putc(struct console_device *cdev, char c)
 {
 	struct fbc_priv *priv = container_of(cdev,
 					struct fbc_priv, cdev);
+	struct fb_info *fb = priv->fb;
 
 	if (priv->in_console)
 		return;
@@ -345,6 +346,8 @@ static void fbc_putc(struct console_device *cdev, char c)
 		break;
 	}
 	priv->in_console = 0;
+
+	fb_flush(fb);
 }
 
 static int setup_font(struct fbc_priv *priv)
diff --git a/include/fb.h b/include/fb.h
index b2a9c7152b..271b939968 100644
--- a/include/fb.h
+++ b/include/fb.h
@@ -86,6 +86,7 @@ struct fb_ops {
 	void (*fb_enable)(struct fb_info *info);
 	void (*fb_disable)(struct fb_info *info);
 	int (*fb_activate_var)(struct fb_info *info);
+	void (*fb_flush)(struct fb_info *info);
 };
 
 /*
@@ -152,6 +153,7 @@ int register_framebuffer(struct fb_info *info);
 
 int fb_enable(struct fb_info *info);
 int fb_disable(struct fb_info *info);
+void fb_flush(struct fb_info *info);
 
 #define FBIOGET_SCREENINFO	_IOR('F', 1, loff_t)
 #define	FBIO_ENABLE		_IO('F', 2)
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family
  2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender
                   ` (2 preceding siblings ...)
  2017-02-24 14:25 ` [PATCH 3/4] fb: introduce flush for virtual framebuffer Bastian Stender
@ 2017-02-24 14:25 ` Bastian Stender
  2017-02-24 16:10   ` Bastian Stender
  2017-02-27 10:08   ` Sascha Hauer
  3 siblings, 2 replies; 15+ messages in thread
From: Bastian Stender @ 2017-02-24 14:25 UTC (permalink / raw)
  To: barebox; +Cc: Bastian Stender

It was ported from linux v4.10. Like the kernel driver only
communication via I2C is supported.

It has only been tested with a SSD1306 and a 96x16 OLED display:

	&i2c0 {
		status = "okay";

		ssd1306: oled@3c {
			compatible = "solomon,ssd1306fb-i2c";
			reg = <0x3c>;
			reset-gpios = <&gpio1 1 0>;
			solomon,height = <16>;
			solomon,width = <96>;
			solomon,page-offset = <0>;
			solomon,com-invdir;
			solomon,com-seq;
		};

Signed-off-by: Bastian Stender <bst@pengutronix.de>
---
 drivers/video/Kconfig     |   4 +
 drivers/video/Makefile    |   1 +
 drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 574 insertions(+)
 create mode 100644 drivers/video/ssd1307fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8f31f5af74..50a876acb1 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE
 	select FONTS
 	prompt "framebuffer console support"
 
+config DRIVER_VIDEO_FB_SSD1307
+	bool "Solomon SSD1307 framebuffer support"
+	depends on PWM && I2C && GPIOLIB
+
 config VIDEO_VPL
 	depends on OFTREE
 	bool
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 1bf2e1f3ca..e23c9c37b6 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
 obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
 obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
 obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
+obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
new file mode 100644
index 0000000000..0dfdcc2232
--- /dev/null
+++ b/drivers/video/ssd1307fb.c
@@ -0,0 +1,569 @@
+/*
+ * Driver for the Solomon SSD1307 OLED controller family
+ *
+ * Supports:
+ *	- SSD1305 (untested)
+ *	- SSD1306
+ *	- SSD1307 (untested)
+ *	- SSD1309 (untested)
+ *
+ * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons
+ *
+ * Ported to barebox from linux v4.10
+ * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de>
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <fb.h>
+#include <i2c/i2c.h>
+#include <of_device.h>
+#include <gpio.h>
+#include <of_gpio.h>
+#include <printk.h>
+
+#define SSD1307FB_DATA			0x40
+#define SSD1307FB_COMMAND		0x80
+
+#define SSD1307FB_SET_ADDRESS_MODE	0x20
+#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
+#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL	(0x01)
+#define SSD1307FB_SET_ADDRESS_MODE_PAGE		(0x02)
+#define SSD1307FB_SET_COL_RANGE		0x21
+#define SSD1307FB_SET_PAGE_RANGE	0x22
+#define SSD1307FB_CONTRAST		0x81
+#define	SSD1307FB_CHARGE_PUMP		0x8d
+#define SSD1307FB_SEG_REMAP_ON		0xa1
+#define SSD1307FB_DISPLAY_OFF		0xae
+#define SSD1307FB_SET_MULTIPLEX_RATIO	0xa8
+#define SSD1307FB_DISPLAY_ON		0xaf
+#define SSD1307FB_START_PAGE_ADDRESS	0xb0
+#define SSD1307FB_SET_DISPLAY_OFFSET	0xd3
+#define	SSD1307FB_SET_CLOCK_FREQ	0xd5
+#define	SSD1307FB_SET_PRECHARGE_PERIOD	0xd9
+#define	SSD1307FB_SET_COM_PINS_CONFIG	0xda
+#define	SSD1307FB_SET_VCOMH		0xdb
+
+struct ssd1307fb_par;
+
+struct ssd1307fb_deviceinfo {
+	u32 default_vcomh;
+	u32 default_dclk_div;
+	u32 default_dclk_frq;
+	int need_chargepump;
+};
+
+struct ssd1307fb_par {
+	u32 com_invdir;
+	u32 com_lrremap;
+	u32 com_offset;
+	u32 com_seq;
+	u32 contrast;
+	u32 dclk_div;
+	u32 dclk_frq;
+	const struct ssd1307fb_deviceinfo *device_info;
+	struct i2c_client *client;
+	u32 height;
+	struct fb_info *info;
+	u32 page_offset;
+	u32 prechargep1;
+	u32 prechargep2;
+	int reset;
+	u32 seg_remap;
+	u32 vcomh;
+	u32 width;
+};
+
+struct ssd1307fb_array {
+	u8	type;
+	u8	data[0];
+};
+
+static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
+{
+	struct ssd1307fb_array *array;
+
+	array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL);
+	if (!array)
+		return NULL;
+
+	array->type = type;
+
+	return array;
+}
+
+static int ssd1307fb_write_array(struct i2c_client *client,
+				 struct ssd1307fb_array *array, u32 len)
+{
+	int ret;
+
+	len += sizeof(struct ssd1307fb_array);
+
+	ret = i2c_master_send(client, (u8 *)array, len);
+	if (ret != len) {
+		dev_err(&client->dev, "Couldn't send I2C command.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
+{
+	struct ssd1307fb_array *array;
+	int ret;
+
+	array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND);
+	if (!array)
+		return -ENOMEM;
+
+	array->data[0] = cmd;
+
+	ret = ssd1307fb_write_array(client, array, 1);
+	kfree(array);
+
+	return ret;
+}
+
+static void ssd1307fb_update_display(struct ssd1307fb_par *par)
+{
+	struct ssd1307fb_array *array;
+	u8 *vmem = par->info->screen_base;
+	int i, j, k;
+
+	array = ssd1307fb_alloc_array(par->width * par->height / 8,
+				      SSD1307FB_DATA);
+	if (!array)
+		return;
+
+	/*
+	 * 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 < (par->height / 8); i++) {
+		for (j = 0; j < par->width; j++) {
+			u32 array_idx = i * par->width + j;
+			array->data[array_idx] = 0;
+			for (k = 0; k < 8; k++) {
+				u32 page_length = par->width * i * 8;
+				u32 index = page_length + (par->width * k + j);
+				u8 byte = *(vmem + index);
+				/* convert to 1 bit per pixel */
+				u8 bit = byte > 0;
+				array->data[array_idx] |= bit << k;
+			}
+		}
+	}
+
+	ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
+	kfree(array);
+}
+
+static void ssd1307fb_enable(struct fb_info *info)
+{
+	struct ssd1307fb_par *par = info->priv;
+	ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
+}
+
+static void ssd1307fb_disable(struct fb_info *info)
+{
+	struct ssd1307fb_par *par = info->priv;
+	ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
+}
+
+static void ssd1307fb_flush(struct fb_info *info)
+{
+	struct ssd1307fb_par *par = info->priv;
+	ssd1307fb_update_display(par);
+}
+
+static struct fb_ops ssd1307fb_ops = {
+	.fb_enable	= ssd1307fb_enable,
+	.fb_disable	= ssd1307fb_disable,
+	.fb_flush	= ssd1307fb_flush,
+};
+
+static int ssd1307fb_init(struct ssd1307fb_par *par)
+{
+	int ret;
+	u32 precharge, dclk, com_invdir, compins;
+
+	/* Set initial contrast */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client, par->contrast);
+	if (ret < 0)
+		return ret;
+
+	/* Set segment re-map */
+	if (par->seg_remap) {
+		ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
+		if (ret < 0)
+			return ret;
+	};
+
+	/* Set COM direction */
+	com_invdir = 0xc0 | (par->com_invdir & 0x1) << 3;
+	ret = ssd1307fb_write_cmd(par->client,  com_invdir);
+	if (ret < 0)
+		return ret;
+
+	/* Set multiplex ratio value */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client, par->height - 1);
+	if (ret < 0)
+		return ret;
+
+	/* set display offset value */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client, par->com_offset);
+	if (ret < 0)
+		return ret;
+
+	/* Set clock frequency */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
+	if (ret < 0)
+		return ret;
+
+	dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4;
+	ret = ssd1307fb_write_cmd(par->client, dclk);
+	if (ret < 0)
+		return ret;
+
+	/* Set precharge period in number of ticks from the internal clock */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
+	if (ret < 0)
+		return ret;
+
+	precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
+	ret = ssd1307fb_write_cmd(par->client, precharge);
+	if (ret < 0)
+		return ret;
+
+	/* Set COM pins configuration */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
+	if (ret < 0)
+		return ret;
+
+	compins = 0x02 | !(par->com_seq & 0x1) << 4
+				   | (par->com_lrremap & 0x1) << 5;
+	ret = ssd1307fb_write_cmd(par->client, compins);
+	if (ret < 0)
+		return ret;
+
+	/* Set VCOMH */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client, par->vcomh);
+	if (ret < 0)
+		return ret;
+
+	/* Turn on the DC-DC Charge Pump */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client,
+		BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0));
+	if (ret < 0)
+		return ret;
+
+	/* Switch to horizontal addressing mode */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client,
+				  SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
+	if (ret < 0)
+		return ret;
+
+	/* Set column range */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client, 0x0);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client, par->width - 1);
+	if (ret < 0)
+		return ret;
+
+	/* Set page range */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client, 0x0);
+	if (ret < 0)
+		return ret;
+
+	ret = ssd1307fb_write_cmd(par->client,
+				  par->page_offset + (par->height / 8) - 1);
+	if (ret < 0)
+		return ret;
+
+	/* Turn on the display */
+	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
+	.default_vcomh = 0x34,
+	.default_dclk_div = 1,
+	.default_dclk_frq = 7,
+};
+
+static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
+	.default_vcomh = 0x20,
+	.default_dclk_div = 1,
+	.default_dclk_frq = 8,
+	.need_chargepump = 1,
+};
+
+static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
+	.default_vcomh = 0x20,
+	.default_dclk_div = 2,
+	.default_dclk_frq = 12,
+};
+
+static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = {
+	.default_vcomh = 0x34,
+	.default_dclk_div = 1,
+	.default_dclk_frq = 10,
+};
+
+static const struct of_device_id ssd1307fb_of_match[] = {
+	{
+		.compatible = "solomon,ssd1305fb-i2c",
+		.data = (void *)&ssd1307fb_ssd1305_deviceinfo,
+	},
+	{
+		.compatible = "solomon,ssd1306fb-i2c",
+		.data = (void *)&ssd1307fb_ssd1306_deviceinfo,
+	},
+	{
+		.compatible = "solomon,ssd1307fb-i2c",
+		.data = (void *)&ssd1307fb_ssd1307_deviceinfo,
+	},
+	{
+		.compatible = "solomon,ssd1309fb-i2c",
+		.data = (void *)&ssd1307fb_ssd1309_deviceinfo,
+	},
+	{},
+};
+
+static int ssd1307fb_probe(struct device_d *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct fb_info *info;
+	struct device_node *node = dev->device_node;
+	const struct of_device_id *match =
+		of_match_node(ssd1307fb_of_match, dev->device_node);
+	u32 vmem_size;
+	struct ssd1307fb_par *par;
+	struct ssd1307fb_array *array;
+	u8 *vmem;
+	int ret;
+	int i, j;
+
+	if (!node) {
+		dev_err(&client->dev, "No device tree data found!\n");
+		return -EINVAL;
+	}
+
+	info = xzalloc(sizeof(struct fb_info));
+	if (!info) {
+		dev_err(&client->dev, "Couldn't allocate framebuffer.\n");
+		return -ENOMEM;
+	}
+
+	par = info->priv;
+	par->info = info;
+	par->client = client;
+
+	par->device_info = (struct ssd1307fb_deviceinfo *)match->data;
+
+	par->reset = of_get_named_gpio(node,
+					 "reset-gpios", 0);
+	if (!gpio_is_valid(par->reset)) {
+		dev_err(&client->dev,
+			"Couldn't get named gpio 'reset-gpios' %d.\n",
+			par->reset);
+		ret = par->reset;
+		goto fb_alloc_error;
+	}
+
+	if (of_property_read_u32(node, "solomon,width", &par->width))
+		par->width = 96;
+
+	if (of_property_read_u32(node, "solomon,height", &par->height))
+		par->height = 16;
+
+	if (of_property_read_u32(node, "solomon,page-offset",
+				 &par->page_offset))
+		par->page_offset = 1;
+
+	if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset))
+		par->com_offset = 0;
+
+	if (of_property_read_u32(node, "solomon,prechargep1",
+				 &par->prechargep1))
+		par->prechargep1 = 2;
+
+	if (of_property_read_u32(node, "solomon,prechargep2",
+				 &par->prechargep2))
+		par->prechargep2 = 2;
+
+	par->seg_remap = !of_property_read_bool(node,
+						"solomon,segment-no-remap");
+	par->com_seq = of_property_read_bool(node, "solomon,com-seq");
+	par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap");
+	par->com_invdir = of_property_read_bool(node, "solomon,com-invdir");
+
+	par->contrast = 127;
+	par->vcomh = par->device_info->default_vcomh;
+
+	/* Setup display timing */
+	par->dclk_div = par->device_info->default_dclk_div;
+	par->dclk_frq = par->device_info->default_dclk_frq;
+
+	vmem_size = par->width * par->height;
+
+	vmem = malloc(vmem_size);
+	if (!vmem) {
+		dev_err(&client->dev, "Couldn't allocate graphical memory.\n");
+		ret = -ENOMEM;
+		goto fb_alloc_error;
+	}
+
+	info->fbops = &ssd1307fb_ops;
+	info->line_length = par->width;
+
+	info->xres = par->width;
+	info->yres = par->height;
+
+	/* emulate 8 bit per pixel */
+	info->bits_per_pixel = 8;
+
+	info->red.length = 3;
+	info->red.offset = 0;
+	info->green.length = 3;
+	info->green.offset = 0;
+	info->blue.length = 2;
+	info->blue.offset = 0;
+
+	info->screen_base = (u8 __force __iomem *)vmem;
+
+	ret = gpio_request_one(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;
+	}
+
+	i2c_set_clientdata(client, info);
+
+	/* Reset the screen */
+	gpio_set_value(par->reset, 0);
+	udelay(4);
+	gpio_set_value(par->reset, 1);
+	udelay(4);
+
+	ret = ssd1307fb_init(par);
+	if (ret)
+		goto reset_oled_error;
+
+	ret = register_framebuffer(info);
+	if (ret) {
+		dev_err(&client->dev, "Couldn't register the framebuffer\n");
+		goto panel_init_error;
+	}
+
+	/* clear display */
+	array = ssd1307fb_alloc_array(par->width * par->height / 8,
+				      SSD1307FB_DATA);
+	if (!array)
+		return -ENOMEM;
+
+	for (i = 0; i < (par->height / 8); i++) {
+		for (j = 0; j < par->width; j++) {
+			u32 array_idx = i * par->width + j;
+			array->data[array_idx] = 0;
+		}
+	}
+
+	ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
+	kfree(array);
+
+	dev_info(&client->dev,
+		 "ssd1307 framebuffer device registered, using %d bytes of video memory\n",
+		 vmem_size);
+
+	return 0;
+
+panel_init_error:
+reset_oled_error:
+fb_alloc_error:
+	free(info);
+	return ret;
+}
+
+static struct driver_d ssd1307fb_driver = {
+	.name = "ssd1307fb",
+	.probe = ssd1307fb_probe,
+	.of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match),
+};
+
+static int ssd1307_init(void)
+{
+	i2c_driver_register(&ssd1307fb_driver);
+	return 0;
+}
+
+device_initcall(ssd1307_init);
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family
  2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender
@ 2017-02-24 16:10   ` Bastian Stender
  2017-02-27 10:08   ` Sascha Hauer
  1 sibling, 0 replies; 15+ messages in thread
From: Bastian Stender @ 2017-02-24 16:10 UTC (permalink / raw)
  To: barebox

On 02/24/2017 03:25 PM, Bastian Stender wrote:
> It was ported from linux v4.10. Like the kernel driver only
> communication via I2C is supported.
>
> It has only been tested with a SSD1306 and a 96x16 OLED display:
>
> 	&i2c0 {
> 		status = "okay";
>
> 		ssd1306: oled@3c {
> 			compatible = "solomon,ssd1306fb-i2c";
> 			reg = <0x3c>;
> 			reset-gpios = <&gpio1 1 0>;
> 			solomon,height = <16>;
> 			solomon,width = <96>;
> 			solomon,page-offset = <0>;
> 			solomon,com-invdir;
> 			solomon,com-seq;
> 		};
>
> Signed-off-by: Bastian Stender <bst@pengutronix.de>
> ---
>  drivers/video/Kconfig     |   4 +
>  drivers/video/Makefile    |   1 +
>  drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 574 insertions(+)
>  create mode 100644 drivers/video/ssd1307fb.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 8f31f5af74..50a876acb1 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE
>  	select FONTS
>  	prompt "framebuffer console support"
>
> +config DRIVER_VIDEO_FB_SSD1307
> +	bool "Solomon SSD1307 framebuffer support"
> +	depends on PWM && I2C && GPIOLIB

Oops, it actually does not depend on PWM. Only the SSD1307 needs PWM, 
but I did not port that part as I have no way to test it. I should 
probably mention that.

> +
>  config VIDEO_VPL
>  	depends on OFTREE
>  	bool
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 1bf2e1f3ca..e23c9c37b6 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
>  obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
>  obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
>  obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
> +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
> diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
> new file mode 100644
> index 0000000000..0dfdcc2232
> --- /dev/null
> +++ b/drivers/video/ssd1307fb.c
> @@ -0,0 +1,569 @@
> +/*
> + * Driver for the Solomon SSD1307 OLED controller family
> + *
> + * Supports:
> + *	- SSD1305 (untested)
> + *	- SSD1306
> + *	- SSD1307 (untested)

Remove that for now.

> + *	- SSD1309 (untested)
> + *
> + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons
> + *
> + * Ported to barebox from linux v4.10
> + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de>
> + *
> + * Licensed under the GPLv2 or later.
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <fb.h>
> +#include <i2c/i2c.h>
> +#include <of_device.h>
> +#include <gpio.h>
> +#include <of_gpio.h>
> +#include <printk.h>
> +
> +#define SSD1307FB_DATA			0x40
> +#define SSD1307FB_COMMAND		0x80
> +
> +#define SSD1307FB_SET_ADDRESS_MODE	0x20
> +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
> +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL	(0x01)
> +#define SSD1307FB_SET_ADDRESS_MODE_PAGE		(0x02)
> +#define SSD1307FB_SET_COL_RANGE		0x21
> +#define SSD1307FB_SET_PAGE_RANGE	0x22
> +#define SSD1307FB_CONTRAST		0x81
> +#define	SSD1307FB_CHARGE_PUMP		0x8d
> +#define SSD1307FB_SEG_REMAP_ON		0xa1
> +#define SSD1307FB_DISPLAY_OFF		0xae
> +#define SSD1307FB_SET_MULTIPLEX_RATIO	0xa8
> +#define SSD1307FB_DISPLAY_ON		0xaf
> +#define SSD1307FB_START_PAGE_ADDRESS	0xb0
> +#define SSD1307FB_SET_DISPLAY_OFFSET	0xd3
> +#define	SSD1307FB_SET_CLOCK_FREQ	0xd5
> +#define	SSD1307FB_SET_PRECHARGE_PERIOD	0xd9
> +#define	SSD1307FB_SET_COM_PINS_CONFIG	0xda
> +#define	SSD1307FB_SET_VCOMH		0xdb
> +
> +struct ssd1307fb_par;
> +
> +struct ssd1307fb_deviceinfo {
> +	u32 default_vcomh;
> +	u32 default_dclk_div;
> +	u32 default_dclk_frq;
> +	int need_chargepump;
> +};
> +
> +struct ssd1307fb_par {
> +	u32 com_invdir;
> +	u32 com_lrremap;
> +	u32 com_offset;
> +	u32 com_seq;
> +	u32 contrast;
> +	u32 dclk_div;
> +	u32 dclk_frq;
> +	const struct ssd1307fb_deviceinfo *device_info;
> +	struct i2c_client *client;
> +	u32 height;
> +	struct fb_info *info;
> +	u32 page_offset;
> +	u32 prechargep1;
> +	u32 prechargep2;
> +	int reset;
> +	u32 seg_remap;
> +	u32 vcomh;
> +	u32 width;
> +};
> +
> +struct ssd1307fb_array {
> +	u8	type;
> +	u8	data[0];
> +};
> +
> +static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
> +{
> +	struct ssd1307fb_array *array;
> +
> +	array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL);
> +	if (!array)
> +		return NULL;
> +
> +	array->type = type;
> +
> +	return array;
> +}
> +
> +static int ssd1307fb_write_array(struct i2c_client *client,
> +				 struct ssd1307fb_array *array, u32 len)
> +{
> +	int ret;
> +
> +	len += sizeof(struct ssd1307fb_array);
> +
> +	ret = i2c_master_send(client, (u8 *)array, len);
> +	if (ret != len) {
> +		dev_err(&client->dev, "Couldn't send I2C command.\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
> +{
> +	struct ssd1307fb_array *array;
> +	int ret;
> +
> +	array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	array->data[0] = cmd;
> +
> +	ret = ssd1307fb_write_array(client, array, 1);
> +	kfree(array);
> +
> +	return ret;
> +}
> +
> +static void ssd1307fb_update_display(struct ssd1307fb_par *par)
> +{
> +	struct ssd1307fb_array *array;
> +	u8 *vmem = par->info->screen_base;
> +	int i, j, k;
> +
> +	array = ssd1307fb_alloc_array(par->width * par->height / 8,
> +				      SSD1307FB_DATA);
> +	if (!array)
> +		return;
> +
> +	/*
> +	 * 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 < (par->height / 8); i++) {
> +		for (j = 0; j < par->width; j++) {
> +			u32 array_idx = i * par->width + j;
> +			array->data[array_idx] = 0;
> +			for (k = 0; k < 8; k++) {
> +				u32 page_length = par->width * i * 8;
> +				u32 index = page_length + (par->width * k + j);
> +				u8 byte = *(vmem + index);
> +				/* convert to 1 bit per pixel */
> +				u8 bit = byte > 0;
> +				array->data[array_idx] |= bit << k;
> +			}
> +		}
> +	}
> +
> +	ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
> +	kfree(array);
> +}
> +
> +static void ssd1307fb_enable(struct fb_info *info)
> +{
> +	struct ssd1307fb_par *par = info->priv;
> +	ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
> +}
> +
> +static void ssd1307fb_disable(struct fb_info *info)
> +{
> +	struct ssd1307fb_par *par = info->priv;
> +	ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
> +}
> +
> +static void ssd1307fb_flush(struct fb_info *info)
> +{
> +	struct ssd1307fb_par *par = info->priv;
> +	ssd1307fb_update_display(par);
> +}
> +
> +static struct fb_ops ssd1307fb_ops = {
> +	.fb_enable	= ssd1307fb_enable,
> +	.fb_disable	= ssd1307fb_disable,
> +	.fb_flush	= ssd1307fb_flush,
> +};
> +
> +static int ssd1307fb_init(struct ssd1307fb_par *par)
> +{
> +	int ret;
> +	u32 precharge, dclk, com_invdir, compins;
> +
> +	/* Set initial contrast */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client, par->contrast);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set segment re-map */
> +	if (par->seg_remap) {
> +		ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
> +		if (ret < 0)
> +			return ret;
> +	};
> +
> +	/* Set COM direction */
> +	com_invdir = 0xc0 | (par->com_invdir & 0x1) << 3;
> +	ret = ssd1307fb_write_cmd(par->client,  com_invdir);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set multiplex ratio value */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client, par->height - 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* set display offset value */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client, par->com_offset);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set clock frequency */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
> +	if (ret < 0)
> +		return ret;
> +
> +	dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4;
> +	ret = ssd1307fb_write_cmd(par->client, dclk);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set precharge period in number of ticks from the internal clock */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
> +	if (ret < 0)
> +		return ret;
> +
> +	precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
> +	ret = ssd1307fb_write_cmd(par->client, precharge);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set COM pins configuration */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
> +	if (ret < 0)
> +		return ret;
> +
> +	compins = 0x02 | !(par->com_seq & 0x1) << 4
> +				   | (par->com_lrremap & 0x1) << 5;
> +	ret = ssd1307fb_write_cmd(par->client, compins);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set VCOMH */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client, par->vcomh);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Turn on the DC-DC Charge Pump */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client,
> +		BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0));
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Switch to horizontal addressing mode */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client,
> +				  SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set column range */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client, 0x0);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client, par->width - 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Set page range */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client, 0x0);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ssd1307fb_write_cmd(par->client,
> +				  par->page_offset + (par->height / 8) - 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Turn on the display */
> +	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
> +	.default_vcomh = 0x34,
> +	.default_dclk_div = 1,
> +	.default_dclk_frq = 7,
> +};
> +
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
> +	.default_vcomh = 0x20,
> +	.default_dclk_div = 1,
> +	.default_dclk_frq = 8,
> +	.need_chargepump = 1,
> +};
> +
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
> +	.default_vcomh = 0x20,
> +	.default_dclk_div = 2,
> +	.default_dclk_frq = 12,
> +};

Remove this too.

> +
> +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = {
> +	.default_vcomh = 0x34,
> +	.default_dclk_div = 1,
> +	.default_dclk_frq = 10,
> +};
> +
> +static const struct of_device_id ssd1307fb_of_match[] = {
> +	{
> +		.compatible = "solomon,ssd1305fb-i2c",
> +		.data = (void *)&ssd1307fb_ssd1305_deviceinfo,
> +	},
> +	{
> +		.compatible = "solomon,ssd1306fb-i2c",
> +		.data = (void *)&ssd1307fb_ssd1306_deviceinfo,
> +	},
> +	{
> +		.compatible = "solomon,ssd1307fb-i2c",
> +		.data = (void *)&ssd1307fb_ssd1307_deviceinfo,
> +	},

Remove this too.

> +	{
> +		.compatible = "solomon,ssd1309fb-i2c",
> +		.data = (void *)&ssd1307fb_ssd1309_deviceinfo,
> +	},
> +	{},
> +};
> +
> +static int ssd1307fb_probe(struct device_d *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct fb_info *info;
> +	struct device_node *node = dev->device_node;
> +	const struct of_device_id *match =
> +		of_match_node(ssd1307fb_of_match, dev->device_node);
> +	u32 vmem_size;
> +	struct ssd1307fb_par *par;
> +	struct ssd1307fb_array *array;
> +	u8 *vmem;
> +	int ret;
> +	int i, j;
> +
> +	if (!node) {
> +		dev_err(&client->dev, "No device tree data found!\n");
> +		return -EINVAL;
> +	}
> +
> +	info = xzalloc(sizeof(struct fb_info));
> +	if (!info) {
> +		dev_err(&client->dev, "Couldn't allocate framebuffer.\n");
> +		return -ENOMEM;
> +	}
> +
> +	par = info->priv;
> +	par->info = info;
> +	par->client = client;
> +
> +	par->device_info = (struct ssd1307fb_deviceinfo *)match->data;
> +
> +	par->reset = of_get_named_gpio(node,
> +					 "reset-gpios", 0);
> +	if (!gpio_is_valid(par->reset)) {
> +		dev_err(&client->dev,
> +			"Couldn't get named gpio 'reset-gpios' %d.\n",
> +			par->reset);
> +		ret = par->reset;
> +		goto fb_alloc_error;
> +	}
> +
> +	if (of_property_read_u32(node, "solomon,width", &par->width))
> +		par->width = 96;
> +
> +	if (of_property_read_u32(node, "solomon,height", &par->height))
> +		par->height = 16;
> +
> +	if (of_property_read_u32(node, "solomon,page-offset",
> +				 &par->page_offset))
> +		par->page_offset = 1;
> +
> +	if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset))
> +		par->com_offset = 0;
> +
> +	if (of_property_read_u32(node, "solomon,prechargep1",
> +				 &par->prechargep1))
> +		par->prechargep1 = 2;
> +
> +	if (of_property_read_u32(node, "solomon,prechargep2",
> +				 &par->prechargep2))
> +		par->prechargep2 = 2;
> +
> +	par->seg_remap = !of_property_read_bool(node,
> +						"solomon,segment-no-remap");
> +	par->com_seq = of_property_read_bool(node, "solomon,com-seq");
> +	par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap");
> +	par->com_invdir = of_property_read_bool(node, "solomon,com-invdir");
> +
> +	par->contrast = 127;
> +	par->vcomh = par->device_info->default_vcomh;
> +
> +	/* Setup display timing */
> +	par->dclk_div = par->device_info->default_dclk_div;
> +	par->dclk_frq = par->device_info->default_dclk_frq;
> +
> +	vmem_size = par->width * par->height;
> +
> +	vmem = malloc(vmem_size);
> +	if (!vmem) {
> +		dev_err(&client->dev, "Couldn't allocate graphical memory.\n");
> +		ret = -ENOMEM;
> +		goto fb_alloc_error;
> +	}
> +
> +	info->fbops = &ssd1307fb_ops;
> +	info->line_length = par->width;
> +
> +	info->xres = par->width;
> +	info->yres = par->height;
> +
> +	/* emulate 8 bit per pixel */
> +	info->bits_per_pixel = 8;
> +
> +	info->red.length = 3;
> +	info->red.offset = 0;
> +	info->green.length = 3;
> +	info->green.offset = 0;
> +	info->blue.length = 2;
> +	info->blue.offset = 0;
> +
> +	info->screen_base = (u8 __force __iomem *)vmem;
> +
> +	ret = gpio_request_one(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;
> +	}
> +
> +	i2c_set_clientdata(client, info);
> +
> +	/* Reset the screen */
> +	gpio_set_value(par->reset, 0);
> +	udelay(4);
> +	gpio_set_value(par->reset, 1);
> +	udelay(4);
> +
> +	ret = ssd1307fb_init(par);
> +	if (ret)
> +		goto reset_oled_error;
> +
> +	ret = register_framebuffer(info);
> +	if (ret) {
> +		dev_err(&client->dev, "Couldn't register the framebuffer\n");
> +		goto panel_init_error;
> +	}
> +
> +	/* clear display */
> +	array = ssd1307fb_alloc_array(par->width * par->height / 8,
> +				      SSD1307FB_DATA);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < (par->height / 8); i++) {
> +		for (j = 0; j < par->width; j++) {
> +			u32 array_idx = i * par->width + j;
> +			array->data[array_idx] = 0;
> +		}
> +	}
> +
> +	ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
> +	kfree(array);
> +
> +	dev_info(&client->dev,
> +		 "ssd1307 framebuffer device registered, using %d bytes of video memory\n",
> +		 vmem_size);
> +
> +	return 0;
> +
> +panel_init_error:
> +reset_oled_error:
> +fb_alloc_error:
> +	free(info);
> +	return ret;
> +}
> +
> +static struct driver_d ssd1307fb_driver = {
> +	.name = "ssd1307fb",
> +	.probe = ssd1307fb_probe,
> +	.of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match),
> +};
> +
> +static int ssd1307_init(void)
> +{
> +	i2c_driver_register(&ssd1307fb_driver);
> +	return 0;
> +}
> +
> +device_initcall(ssd1307_init);
>

If anybody is confident enough to port the pwm parts or can actually 
test this, we can add SSD1307 compatability again.

I will send a reworked version of this patch, but for now I'll wait for 
some more review.

Regards,
Bastian

-- 
Pengutronix e.K.
Industrial Linux Solutions
http://www.pengutronix.de/
Peiner Str. 6-8, 31137 Hildesheim, Germany
Amtsgericht Hildesheim, HRA 2686

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] console: replace set_active by open/close
  2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender
@ 2017-02-27  9:54   ` Sascha Hauer
  2017-02-27 15:56     ` [PATCH v2] " Bastian Stender
  0 siblings, 1 reply; 15+ messages in thread
From: Sascha Hauer @ 2017-02-27  9:54 UTC (permalink / raw)
  To: Bastian Stender; +Cc: barebox

On Fri, Feb 24, 2017 at 03:24:58PM +0100, Bastian Stender wrote:
> Opening and closing consoles should be independent from setting them
> active. This way it is possible to open e.g. a framebuffer console and
> display text on it without showing stdout/stderr.
> 
> Signed-off-by: Bastian Stender <bst@pengutronix.de>
> ---
>  common/console.c          | 19 +++++++++++++++----
>  drivers/video/fbconsole.c | 28 ++++++++++++++++++----------
>  include/console.h         |  3 ++-
>  net/netconsole.c          | 27 +++++++++++++++++----------
>  4 files changed, 52 insertions(+), 25 deletions(-)
> 
> diff --git a/common/console.c b/common/console.c
> index 74ccfcfc3e..43890b3da8 100644
> --- a/common/console.c
> +++ b/common/console.c
> @@ -71,10 +71,21 @@ int console_set_active(struct console_device *cdev, unsigned flag)
>  	if (!flag && cdev->f_active && cdev->flush)
>  		cdev->flush(cdev);
>  
> -	if (cdev->set_active) {
> -		ret = cdev->set_active(cdev, flag);
> -		if (ret)
> -			return ret;
> +	if (flag == cdev->f_active)
> +		return 0;
> +
> +	if (!flag) {
> +		if (cdev->close) {
> +			ret = cdev->close(cdev);
> +			if (ret)
> +				return ret;
> +		}
> +	} else {
> +		if (cdev->open) {
> +			ret = cdev->open(cdev);
> +			if (ret)
> +				return ret;
> +		}
>  	}

instead of calling into cdev->open/close directly here I would prefer
console_open() / console_close() functions which get called here.
In these functions you can call the driver hooks on first open and last
close.

Sascha

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

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] console: expose consoles in devfs
  2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender
@ 2017-02-27  9:55   ` Sascha Hauer
  2017-02-27 16:01     ` [PATCH v2] " Bastian Stender
  0 siblings, 1 reply; 15+ messages in thread
From: Sascha Hauer @ 2017-02-27  9:55 UTC (permalink / raw)
  To: Bastian Stender; +Cc: barebox

On Fri, Feb 24, 2017 at 03:24:59PM +0100, Bastian Stender wrote:
> This enables displaying text on e.g. a framebuffer console by issueing
> 
> 	echo -o /dev/fbconsole0 abc123
> 
> Signed-off-by: Bastian Stender <bst@pengutronix.de>
> ---
>  common/console.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/console.h |  3 +++
>  2 files changed, 55 insertions(+)
> 
> diff --git a/common/console.c b/common/console.c
> index 43890b3da8..dcd67afe20 100644
> --- a/common/console.c
> +++ b/common/console.c
> @@ -243,6 +243,39 @@ static int __console_puts(struct console_device *cdev, const char *s)
>  	return n;
>  }
>  
> +static int fops_open(struct cdev *cdev, unsigned long flags)
> +{
> +	struct console_device *priv = cdev->priv;
> +
> +	return priv->open(priv);
> +}

You do not check if this hook exists in the driver, but this will be
solved when you follow what I suggested in 1/4.

Sascha


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

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family
  2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender
  2017-02-24 16:10   ` Bastian Stender
@ 2017-02-27 10:08   ` Sascha Hauer
  2017-02-27 15:45     ` Bastian Stender
  1 sibling, 1 reply; 15+ messages in thread
From: Sascha Hauer @ 2017-02-27 10:08 UTC (permalink / raw)
  To: Bastian Stender; +Cc: barebox

On Fri, Feb 24, 2017 at 03:25:01PM +0100, Bastian Stender wrote:
> It was ported from linux v4.10. Like the kernel driver only
> communication via I2C is supported.
> 
> It has only been tested with a SSD1306 and a 96x16 OLED display:
> 
> 	&i2c0 {
> 		status = "okay";
> 
> 		ssd1306: oled@3c {
> 			compatible = "solomon,ssd1306fb-i2c";
> 			reg = <0x3c>;
> 			reset-gpios = <&gpio1 1 0>;
> 			solomon,height = <16>;
> 			solomon,width = <96>;
> 			solomon,page-offset = <0>;
> 			solomon,com-invdir;
> 			solomon,com-seq;
> 		};
> 
> Signed-off-by: Bastian Stender <bst@pengutronix.de>
> ---
>  drivers/video/Kconfig     |   4 +
>  drivers/video/Makefile    |   1 +
>  drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 574 insertions(+)
>  create mode 100644 drivers/video/ssd1307fb.c
> 
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 8f31f5af74..50a876acb1 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE
>  	select FONTS
>  	prompt "framebuffer console support"
>  
> +config DRIVER_VIDEO_FB_SSD1307
> +	bool "Solomon SSD1307 framebuffer support"
> +	depends on PWM && I2C && GPIOLIB
> +
>  config VIDEO_VPL
>  	depends on OFTREE
>  	bool
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 1bf2e1f3ca..e23c9c37b6 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
>  obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
>  obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
>  obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
> +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
> diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
> new file mode 100644
> index 0000000000..0dfdcc2232
> --- /dev/null
> +++ b/drivers/video/ssd1307fb.c
> @@ -0,0 +1,569 @@
> +/*
> + * Driver for the Solomon SSD1307 OLED controller family
> + *
> + * Supports:
> + *	- SSD1305 (untested)
> + *	- SSD1306
> + *	- SSD1307 (untested)
> + *	- SSD1309 (untested)
> + *
> + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons
> + *
> + * Ported to barebox from linux v4.10
> + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de>
> + *
> + * Licensed under the GPLv2 or later.
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <fb.h>
> +#include <i2c/i2c.h>
> +#include <of_device.h>
> +#include <gpio.h>
> +#include <of_gpio.h>
> +#include <printk.h>
> +
> +#define SSD1307FB_DATA			0x40
> +#define SSD1307FB_COMMAND		0x80
> +
> +#define SSD1307FB_SET_ADDRESS_MODE	0x20
> +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
> +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL	(0x01)
> +#define SSD1307FB_SET_ADDRESS_MODE_PAGE		(0x02)
> +#define SSD1307FB_SET_COL_RANGE		0x21
> +#define SSD1307FB_SET_PAGE_RANGE	0x22
> +#define SSD1307FB_CONTRAST		0x81
> +#define	SSD1307FB_CHARGE_PUMP		0x8d
> +#define SSD1307FB_SEG_REMAP_ON		0xa1
> +#define SSD1307FB_DISPLAY_OFF		0xae
> +#define SSD1307FB_SET_MULTIPLEX_RATIO	0xa8
> +#define SSD1307FB_DISPLAY_ON		0xaf
> +#define SSD1307FB_START_PAGE_ADDRESS	0xb0
> +#define SSD1307FB_SET_DISPLAY_OFFSET	0xd3
> +#define	SSD1307FB_SET_CLOCK_FREQ	0xd5
> +#define	SSD1307FB_SET_PRECHARGE_PERIOD	0xd9
> +#define	SSD1307FB_SET_COM_PINS_CONFIG	0xda
> +#define	SSD1307FB_SET_VCOMH		0xdb

please consistently use spaces after #define

> +
> +struct ssd1307fb_par;

Unnecessary.

> +
> +struct ssd1307fb_deviceinfo {
> +	u32 default_vcomh;
> +	u32 default_dclk_div;
> +	u32 default_dclk_frq;
> +	int need_chargepump;
> +};
> +

[...]

> +static int ssd1307fb_probe(struct device_d *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct fb_info *info;
> +	struct device_node *node = dev->device_node;
> +	const struct of_device_id *match =
> +		of_match_node(ssd1307fb_of_match, dev->device_node);
> +	u32 vmem_size;
> +	struct ssd1307fb_par *par;
> +	struct ssd1307fb_array *array;
> +	u8 *vmem;
> +	int ret;
> +	int i, j;
> +
> +	if (!node) {
> +		dev_err(&client->dev, "No device tree data found!\n");
> +		return -EINVAL;
> +	}
> +
> +	info = xzalloc(sizeof(struct fb_info));
> +	if (!info) {
> +		dev_err(&client->dev, "Couldn't allocate framebuffer.\n");
> +		return -ENOMEM;
> +	}

xzalloc always returns succesfully, no need to check.

> +
> +	par = info->priv;
> +	par->info = info;
> +	par->client = client;
> +
> +	par->device_info = (struct ssd1307fb_deviceinfo *)match->data;
> +
> +	par->reset = of_get_named_gpio(node,
> +					 "reset-gpios", 0);
> +	if (!gpio_is_valid(par->reset)) {
> +		dev_err(&client->dev,
> +			"Couldn't get named gpio 'reset-gpios' %d.\n",
> +			par->reset);
> +		ret = par->reset;
> +		goto fb_alloc_error;
> +	}

Is this gpio really mandatory?

> +
> +	if (of_property_read_u32(node, "solomon,width", &par->width))
> +		par->width = 96;
> +
> +	if (of_property_read_u32(node, "solomon,height", &par->height))
> +		par->height = 16;

These defaults only work for you. You should bail out with an error if
the devicetree does not contain values for these instead.

Sascha

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

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family
  2017-02-27 10:08   ` Sascha Hauer
@ 2017-02-27 15:45     ` Bastian Stender
  2017-02-28  7:57       ` Sascha Hauer
  0 siblings, 1 reply; 15+ messages in thread
From: Bastian Stender @ 2017-02-27 15:45 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On 02/27/2017 11:08 AM, Sascha Hauer wrote:
> On Fri, Feb 24, 2017 at 03:25:01PM +0100, Bastian Stender wrote:
>> It was ported from linux v4.10. Like the kernel driver only
>> communication via I2C is supported.
>>
>> It has only been tested with a SSD1306 and a 96x16 OLED display:
>>
>> 	&i2c0 {
>> 		status = "okay";
>>
>> 		ssd1306: oled@3c {
>> 			compatible = "solomon,ssd1306fb-i2c";
>> 			reg = <0x3c>;
>> 			reset-gpios = <&gpio1 1 0>;
>> 			solomon,height = <16>;
>> 			solomon,width = <96>;
>> 			solomon,page-offset = <0>;
>> 			solomon,com-invdir;
>> 			solomon,com-seq;
>> 		};
>>
>> Signed-off-by: Bastian Stender <bst@pengutronix.de>
>> ---
>>  drivers/video/Kconfig     |   4 +
>>  drivers/video/Makefile    |   1 +
>>  drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 574 insertions(+)
>>  create mode 100644 drivers/video/ssd1307fb.c
>>
>> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
>> index 8f31f5af74..50a876acb1 100644
>> --- a/drivers/video/Kconfig
>> +++ b/drivers/video/Kconfig
>> @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE
>>  	select FONTS
>>  	prompt "framebuffer console support"
>>
>> +config DRIVER_VIDEO_FB_SSD1307
>> +	bool "Solomon SSD1307 framebuffer support"
>> +	depends on PWM && I2C && GPIOLIB
>> +
>>  config VIDEO_VPL
>>  	depends on OFTREE
>>  	bool
>> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
>> index 1bf2e1f3ca..e23c9c37b6 100644
>> --- a/drivers/video/Makefile
>> +++ b/drivers/video/Makefile
>> @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
>>  obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
>>  obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
>>  obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
>> +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
>> diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
>> new file mode 100644
>> index 0000000000..0dfdcc2232
>> --- /dev/null
>> +++ b/drivers/video/ssd1307fb.c
>> @@ -0,0 +1,569 @@
>> +/*
>> + * Driver for the Solomon SSD1307 OLED controller family
>> + *
>> + * Supports:
>> + *	- SSD1305 (untested)
>> + *	- SSD1306
>> + *	- SSD1307 (untested)
>> + *	- SSD1309 (untested)
>> + *
>> + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons
>> + *
>> + * Ported to barebox from linux v4.10
>> + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de>
>> + *
>> + * Licensed under the GPLv2 or later.
>> + */
>> +
>> +#include <common.h>
>> +#include <init.h>
>> +#include <fb.h>
>> +#include <i2c/i2c.h>
>> +#include <of_device.h>
>> +#include <gpio.h>
>> +#include <of_gpio.h>
>> +#include <printk.h>
>> +
>> +#define SSD1307FB_DATA			0x40
>> +#define SSD1307FB_COMMAND		0x80
>> +
>> +#define SSD1307FB_SET_ADDRESS_MODE	0x20
>> +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
>> +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL	(0x01)
>> +#define SSD1307FB_SET_ADDRESS_MODE_PAGE		(0x02)
>> +#define SSD1307FB_SET_COL_RANGE		0x21
>> +#define SSD1307FB_SET_PAGE_RANGE	0x22
>> +#define SSD1307FB_CONTRAST		0x81
>> +#define	SSD1307FB_CHARGE_PUMP		0x8d
>> +#define SSD1307FB_SEG_REMAP_ON		0xa1
>> +#define SSD1307FB_DISPLAY_OFF		0xae
>> +#define SSD1307FB_SET_MULTIPLEX_RATIO	0xa8
>> +#define SSD1307FB_DISPLAY_ON		0xaf
>> +#define SSD1307FB_START_PAGE_ADDRESS	0xb0
>> +#define SSD1307FB_SET_DISPLAY_OFFSET	0xd3
>> +#define	SSD1307FB_SET_CLOCK_FREQ	0xd5
>> +#define	SSD1307FB_SET_PRECHARGE_PERIOD	0xd9
>> +#define	SSD1307FB_SET_COM_PINS_CONFIG	0xda
>> +#define	SSD1307FB_SET_VCOMH		0xdb
>
> please consistently use spaces after #define

Will do.

>
>> +
>> +struct ssd1307fb_par;
>
> Unnecessary.

Ok.

>
>> +
>> +struct ssd1307fb_deviceinfo {
>> +	u32 default_vcomh;
>> +	u32 default_dclk_div;
>> +	u32 default_dclk_frq;
>> +	int need_chargepump;
>> +};
>> +
>
> [...]
>
>> +static int ssd1307fb_probe(struct device_d *dev)
>> +{
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct fb_info *info;
>> +	struct device_node *node = dev->device_node;
>> +	const struct of_device_id *match =
>> +		of_match_node(ssd1307fb_of_match, dev->device_node);
>> +	u32 vmem_size;
>> +	struct ssd1307fb_par *par;
>> +	struct ssd1307fb_array *array;
>> +	u8 *vmem;
>> +	int ret;
>> +	int i, j;
>> +
>> +	if (!node) {
>> +		dev_err(&client->dev, "No device tree data found!\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	info = xzalloc(sizeof(struct fb_info));
>> +	if (!info) {
>> +		dev_err(&client->dev, "Couldn't allocate framebuffer.\n");
>> +		return -ENOMEM;
>> +	}
>
> xzalloc always returns succesfully, no need to check.

Ok.

>
>> +
>> +	par = info->priv;
>> +	par->info = info;
>> +	par->client = client;
>> +
>> +	par->device_info = (struct ssd1307fb_deviceinfo *)match->data;
>> +
>> +	par->reset = of_get_named_gpio(node,
>> +					 "reset-gpios", 0);
>> +	if (!gpio_is_valid(par->reset)) {
>> +		dev_err(&client->dev,
>> +			"Couldn't get named gpio 'reset-gpios' %d.\n",
>> +			par->reset);
>> +		ret = par->reset;
>> +		goto fb_alloc_error;
>> +	}
>
> Is this gpio really mandatory?


This is the corresponding snippet from the kernel in 
drivers/video/fbdev/ssd1307fb.c, line 564 ff. (v4.10):

     par->reset = of_get_named_gpio(client->dev.of_node,
                                  "reset-gpios", 0);
     if (!gpio_is_valid(par->reset)) {
         ret = -EINVAL;
         goto fb_alloc_error;
     }

"reset-gpios" is one of the required properties, see

   Documentation/devicetree/bindings/display/ssd1307fb.txt

or in barebox:

   dts/Bindings/display/ssd1307fb.txt

>
>> +
>> +	if (of_property_read_u32(node, "solomon,width", &par->width))
>> +		par->width = 96;
>> +
>> +	if (of_property_read_u32(node, "solomon,height", &par->height))
>> +		par->height = 16;
>
> These defaults only work for you. You should bail out with an error if
> the devicetree does not contain values for these instead.

This part was ported 1:1 from linux. As solomon,width and solomon,height 
are required properties also, should I bail out nonetheless?

Regards,
Bastian

-- 
Pengutronix e.K.
Industrial Linux Solutions
http://www.pengutronix.de/
Peiner Str. 6-8, 31137 Hildesheim, Germany
Amtsgericht Hildesheim, HRA 2686

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2] console: replace set_active by open/close
  2017-02-27  9:54   ` Sascha Hauer
@ 2017-02-27 15:56     ` Bastian Stender
  2017-02-28  7:41       ` Sascha Hauer
  0 siblings, 1 reply; 15+ messages in thread
From: Bastian Stender @ 2017-02-27 15:56 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Bastian Stender

Opening and closing consoles should be independent from setting them
active. This way it is possible to open e.g. a framebuffer console and
display text on it without showing stdout/stderr.

Signed-off-by: Bastian Stender <bst@pengutronix.de>
---
 common/console.c          | 31 +++++++++++++++++++++++++++++--
 drivers/video/fbconsole.c | 28 ++++++++++++++++++----------
 include/console.h         |  9 ++++++++-
 net/netconsole.c          | 27 +++++++++++++++++----------
 4 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/common/console.c b/common/console.c
index 74ccfcfc3e..3ff32b8327 100644
--- a/common/console.c
+++ b/common/console.c
@@ -59,6 +59,26 @@ static struct kfifo __console_output_fifo;
 static struct kfifo *console_input_fifo = &__console_input_fifo;
 static struct kfifo *console_output_fifo = &__console_output_fifo;
 
+int console_open(struct console_device *cdev)
+{
+	if (cdev->open && !(cdev-> flags & FLAG_CONSOLE_OPEN)) {
+		cdev->flags |= FLAG_CONSOLE_OPEN;
+		return cdev->open(cdev);
+	}
+
+	return 0;
+}
+
+int console_close(struct console_device *cdev)
+{
+	if (cdev->close && cdev-> flags & FLAG_CONSOLE_OPEN) {
+		cdev->flags &= ~FLAG_CONSOLE_OPEN;
+		return cdev->close(cdev);
+	}
+
+	return 0;
+}
+
 int console_set_active(struct console_device *cdev, unsigned flag)
 {
 	int ret, i;
@@ -71,8 +91,15 @@ int console_set_active(struct console_device *cdev, unsigned flag)
 	if (!flag && cdev->f_active && cdev->flush)
 		cdev->flush(cdev);
 
-	if (cdev->set_active) {
-		ret = cdev->set_active(cdev, flag);
+	if (flag == cdev->f_active)
+		return 0;
+
+	if (!flag) {
+		ret = console_close(cdev);
+		if (ret)
+			return ret;
+	} else {
+		ret = console_open(cdev);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c
index 693c21f547..64f7d7364e 100644
--- a/drivers/video/fbconsole.c
+++ b/drivers/video/fbconsole.c
@@ -365,21 +365,13 @@ static int setup_font(struct fbc_priv *priv)
 	return 0;
 }
 
-static int fbc_set_active(struct console_device *cdev, unsigned flags)
+static int fbc_open(struct console_device *cdev)
 {
 	struct fbc_priv *priv = container_of(cdev,
 					struct fbc_priv, cdev);
 	struct fb_info *fb = priv->fb;
 	int ret;
 
-	if (priv->active) {
-		fb_close(priv->sc);
-		priv->active = false;
-	}
-
-	if (!(flags & (CONSOLE_STDOUT | CONSOLE_STDERR)))
-		return 0;
-
 	ret = setup_font(priv);
 	if (ret)
 		return ret;
@@ -400,6 +392,21 @@ static int fbc_set_active(struct console_device *cdev, unsigned flags)
 	return 0;
 }
 
+static int fbc_close(struct console_device *cdev)
+{
+	struct fbc_priv *priv = container_of(cdev,
+					struct fbc_priv, cdev);
+
+	if (priv->active) {
+		fb_close(priv->sc);
+		priv->active = false;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static int set_font(struct param_d *p, void *vpriv)
 {
 	struct fbc_priv *priv = vpriv;
@@ -434,7 +441,8 @@ int register_fbconsole(struct fb_info *fb)
 	cdev->getc = fbc_getc;
 	cdev->devname = "fbconsole";
 	cdev->devid = DEVICE_ID_DYNAMIC;
-	cdev->set_active = fbc_set_active;
+	cdev->open = fbc_open;
+	cdev->close = fbc_close;
 
 	ret = console_register(cdev);
 	if (ret) {
diff --git a/include/console.h b/include/console.h
index 4b2f134a4c..85e15cad67 100644
--- a/include/console.h
+++ b/include/console.h
@@ -28,6 +28,8 @@
 #define CONSOLE_STDOUT          (1 << 1)
 #define CONSOLE_STDERR          (1 << 2)
 
+#define FLAG_CONSOLE_OPEN       (1 << 0)
+
 enum console_mode {
 	CONSOLE_MODE_NORMAL,
 	CONSOLE_MODE_RS485,
@@ -44,7 +46,8 @@ struct console_device {
 	int (*setbrg)(struct console_device *cdev, int baudrate);
 	void (*flush)(struct console_device *cdev);
 	int (*set_mode)(struct console_device *cdev, enum console_mode mode);
-	int (*set_active)(struct console_device *cdev, unsigned active);
+	int (*open)(struct console_device *cdev);
+	int (*close)(struct console_device *cdev);
 
 	char *devname;
 	int devid;
@@ -54,6 +57,8 @@ struct console_device {
 	unsigned char f_active;
 	char active[4];
 
+	unsigned flags;
+
 	unsigned int baudrate;
 	unsigned int baudrate_param;
 
@@ -75,6 +80,8 @@ extern int barebox_loglevel;
 
 struct console_device *console_get_first_active(void);
 
+int console_open(struct console_device *cdev);
+int console_close(struct console_device *cdev);
 int console_set_active(struct console_device *cdev, unsigned active);
 unsigned console_get_active(struct console_device *cdev);
 int console_set_baudrate(struct console_device *cdev, unsigned baudrate);
diff --git a/net/netconsole.c b/net/netconsole.c
index ce3c418798..ef8b1856b6 100644
--- a/net/netconsole.c
+++ b/net/netconsole.c
@@ -105,19 +105,11 @@ static void nc_putc(struct console_device *cdev, char c)
 	priv->busy = 0;
 }
 
-static int nc_set_active(struct console_device *cdev, unsigned flags)
+static int nc_open(struct console_device *cdev)
 {
 	struct nc_priv *priv = container_of(cdev,
 					struct nc_priv, cdev);
 
-	if (priv->con) {
-		net_unregister(priv->con);
-		priv->con = NULL;
-	}
-
-	if (!flags)
-		return 0;
-
 	if (!priv->port) {
 		pr_err("port not set\n");
 		return -EINVAL;
@@ -142,6 +134,20 @@ static int nc_set_active(struct console_device *cdev, unsigned flags)
 	return 0;
 }
 
+static int nc_close(struct console_device *cdev)
+{
+	struct nc_priv *priv = container_of(cdev,
+					struct nc_priv, cdev);
+
+	if (priv->con) {
+		net_unregister(priv->con);
+		priv->con = NULL;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static int netconsole_init(void)
 {
 	struct nc_priv *priv;
@@ -155,7 +161,8 @@ static int netconsole_init(void)
 	cdev->getc = nc_getc;
 	cdev->devname = "netconsole";
 	cdev->devid = DEVICE_ID_SINGLE;
-	cdev->set_active = nc_set_active;
+	cdev->open = nc_open;
+	cdev->close = nc_close;
 
 	g_priv = priv;
 
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2] console: expose consoles in devfs
  2017-02-27  9:55   ` Sascha Hauer
@ 2017-02-27 16:01     ` Bastian Stender
  2017-02-28  7:50       ` Sascha Hauer
  0 siblings, 1 reply; 15+ messages in thread
From: Bastian Stender @ 2017-02-27 16:01 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Bastian Stender

This enables displaying text on e.g. a framebuffer console by issueing

	echo -o /dev/fbconsole0 abc123

Signed-off-by: Bastian Stender <bst@pengutronix.de>
---
 common/console.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/console.h |  3 +++
 2 files changed, 55 insertions(+)

diff --git a/common/console.c b/common/console.c
index 3ff32b8327..bde4c08414 100644
--- a/common/console.c
+++ b/common/console.c
@@ -259,6 +259,39 @@ static int __console_puts(struct console_device *cdev, const char *s)
 	return n;
 }
 
+static int fops_open(struct cdev *cdev, unsigned long flags)
+{
+	struct console_device *priv = cdev->priv;
+
+	return console_open(priv);
+}
+
+static int fops_close(struct cdev *dev)
+{
+	struct console_device *priv = dev->priv;
+
+	return console_close(priv);
+}
+
+static int fops_flush(struct cdev *dev)
+{
+	struct console_device *priv = dev->priv;
+
+	priv->flush(priv);
+
+	return 0;
+}
+
+static int fops_write(struct cdev* dev, const void* buf, size_t count,
+		      loff_t offset, ulong flags)
+{
+	struct console_device *priv = dev->priv;
+
+	priv->puts(priv, buf);
+
+	return 0;
+}
+
 int console_register(struct console_device *newcdev)
 {
 	struct device_d *dev = &newcdev->class_dev;
@@ -311,6 +344,25 @@ int console_register(struct console_device *newcdev)
 		console_set_active(newcdev, CONSOLE_STDIN |
 				CONSOLE_STDOUT | CONSOLE_STDERR);
 
+	/* expose console as device in fs */
+	newcdev->devfs.name = basprintf("%s%d", newcdev->class_dev.name,
+					newcdev->class_dev.id);
+	newcdev->devfs.priv = newcdev;
+	newcdev->devfs.dev = dev;
+	newcdev->devfs.ops = &newcdev->fops;
+	newcdev->devfs.flags = DEVFS_IS_CHARACTER_DEV;
+	newcdev->fops.open = fops_open;
+	newcdev->fops.close = fops_close;
+	newcdev->fops.flush = fops_flush;
+	newcdev->fops.write = fops_write;
+
+	ret = devfs_create(&newcdev->devfs);
+
+	if (ret) {
+		pr_err("device creation failed with %s\n", strerror(-ret));
+		return ret;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(console_register);
diff --git a/include/console.h b/include/console.h
index 85e15cad67..68edc3aaf1 100644
--- a/include/console.h
+++ b/include/console.h
@@ -63,6 +63,9 @@ struct console_device {
 	unsigned int baudrate_param;
 
 	const char *linux_console_name;
+
+	struct cdev devfs;
+	struct file_operations fops;
 };
 
 int console_register(struct console_device *cdev);
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] console: replace set_active by open/close
  2017-02-27 15:56     ` [PATCH v2] " Bastian Stender
@ 2017-02-28  7:41       ` Sascha Hauer
  0 siblings, 0 replies; 15+ messages in thread
From: Sascha Hauer @ 2017-02-28  7:41 UTC (permalink / raw)
  To: Bastian Stender; +Cc: barebox

On Mon, Feb 27, 2017 at 04:56:16PM +0100, Bastian Stender wrote:
> Opening and closing consoles should be independent from setting them
> active. This way it is possible to open e.g. a framebuffer console and
> display text on it without showing stdout/stderr.
> 
> Signed-off-by: Bastian Stender <bst@pengutronix.de>
> ---
>  common/console.c          | 31 +++++++++++++++++++++++++++++--
>  drivers/video/fbconsole.c | 28 ++++++++++++++++++----------
>  include/console.h         |  9 ++++++++-
>  net/netconsole.c          | 27 +++++++++++++++++----------
>  4 files changed, 72 insertions(+), 23 deletions(-)
> 
> diff --git a/common/console.c b/common/console.c
> index 74ccfcfc3e..3ff32b8327 100644
> --- a/common/console.c
> +++ b/common/console.c
> @@ -59,6 +59,26 @@ static struct kfifo __console_output_fifo;
>  static struct kfifo *console_input_fifo = &__console_input_fifo;
>  static struct kfifo *console_output_fifo = &__console_output_fifo;
>  
> +int console_open(struct console_device *cdev)
> +{
> +	if (cdev->open && !(cdev-> flags & FLAG_CONSOLE_OPEN)) {
> +		cdev->flags |= FLAG_CONSOLE_OPEN;
> +		return cdev->open(cdev);
> +	}

What if cdev->open() fails? In this case the flag is still set, but the
console is not opened. Also please set the FLAG_CONSOLE_OPEN independent
of the presence of the cdev->open() hook.

> diff --git a/include/console.h b/include/console.h
> index 4b2f134a4c..85e15cad67 100644
> --- a/include/console.h
> +++ b/include/console.h
> @@ -28,6 +28,8 @@
>  #define CONSOLE_STDOUT          (1 << 1)
>  #define CONSOLE_STDERR          (1 << 2)
>  
> +#define FLAG_CONSOLE_OPEN       (1 << 0)
> +
>  enum console_mode {
>  	CONSOLE_MODE_NORMAL,
>  	CONSOLE_MODE_RS485,
> @@ -44,7 +46,8 @@ struct console_device {
>  	int (*setbrg)(struct console_device *cdev, int baudrate);
>  	void (*flush)(struct console_device *cdev);
>  	int (*set_mode)(struct console_device *cdev, enum console_mode mode);
> -	int (*set_active)(struct console_device *cdev, unsigned active);
> +	int (*open)(struct console_device *cdev);
> +	int (*close)(struct console_device *cdev);
>  
>  	char *devname;
>  	int devid;
> @@ -54,6 +57,8 @@ struct console_device {
>  	unsigned char f_active;
>  	char active[4];
>  
> +	unsigned flags;
> +

Flags often have the problem that you do not know which flag define
belong to which flag field in which structure. One thing we can do is
to add the flag #defines directly above the struct member they belong to
in the source code.
In this case here we should use a counter rather than flags. Consider
two users opening the console at the same time. Now when one of the
users closes the console, it must still remain opened for the other
user.

Sascha


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

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] console: expose consoles in devfs
  2017-02-27 16:01     ` [PATCH v2] " Bastian Stender
@ 2017-02-28  7:50       ` Sascha Hauer
  0 siblings, 0 replies; 15+ messages in thread
From: Sascha Hauer @ 2017-02-28  7:50 UTC (permalink / raw)
  To: Bastian Stender; +Cc: barebox

On Mon, Feb 27, 2017 at 05:01:08PM +0100, Bastian Stender wrote:
> This enables displaying text on e.g. a framebuffer console by issueing
> 
> 	echo -o /dev/fbconsole0 abc123
> 
> Signed-off-by: Bastian Stender <bst@pengutronix.de>
> ---
>  common/console.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/console.h |  3 +++
>  2 files changed, 55 insertions(+)
> 
> diff --git a/common/console.c b/common/console.c
> index 3ff32b8327..bde4c08414 100644
> --- a/common/console.c
> +++ b/common/console.c
> @@ -259,6 +259,39 @@ static int __console_puts(struct console_device *cdev, const char *s)
>  	return n;
>  }
>  
> +static int fops_open(struct cdev *cdev, unsigned long flags)
> +{
> +	struct console_device *priv = cdev->priv;
> +
> +	return console_open(priv);
> +}
> +
> +static int fops_close(struct cdev *dev)
> +{
> +	struct console_device *priv = dev->priv;
> +
> +	return console_close(priv);
> +}
> +
> +static int fops_flush(struct cdev *dev)
> +{
> +	struct console_device *priv = dev->priv;
> +
> +	priv->flush(priv);

cdev->flush() is optional, you have to test for presence before using
it.

When you have to resend patches from a series, please resend the whole
series. Scanning different mail threads to find the newest version of
the patches can get cumbersome quite fast.

Sascha

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

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family
  2017-02-27 15:45     ` Bastian Stender
@ 2017-02-28  7:57       ` Sascha Hauer
  0 siblings, 0 replies; 15+ messages in thread
From: Sascha Hauer @ 2017-02-28  7:57 UTC (permalink / raw)
  To: Bastian Stender; +Cc: barebox

On Mon, Feb 27, 2017 at 04:45:43PM +0100, Bastian Stender wrote:
> On 02/27/2017 11:08 AM, Sascha Hauer wrote:
> > On Fri, Feb 24, 2017 at 03:25:01PM +0100, Bastian Stender wrote:
> > > It was ported from linux v4.10. Like the kernel driver only
> > > communication via I2C is supported.
> > > 
> > > It has only been tested with a SSD1306 and a 96x16 OLED display:
> > > 
> > > 	&i2c0 {
> > > 		status = "okay";
> > > 
> > > 		ssd1306: oled@3c {
> > > 			compatible = "solomon,ssd1306fb-i2c";
> > > 			reg = <0x3c>;
> > > 			reset-gpios = <&gpio1 1 0>;
> > > 			solomon,height = <16>;
> > > 			solomon,width = <96>;
> > > 			solomon,page-offset = <0>;
> > > 			solomon,com-invdir;
> > > 			solomon,com-seq;
> > > 		};
> > > 
> > > Signed-off-by: Bastian Stender <bst@pengutronix.de>
> > > ---
> > >  drivers/video/Kconfig     |   4 +
> > >  drivers/video/Makefile    |   1 +
> > >  drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 574 insertions(+)
> > >  create mode 100644 drivers/video/ssd1307fb.c
> > > 
> > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > > index 8f31f5af74..50a876acb1 100644
> > > --- a/drivers/video/Kconfig
> > > +++ b/drivers/video/Kconfig
> > > @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE
> > >  	select FONTS
> > >  	prompt "framebuffer console support"
> > > 
> > > +config DRIVER_VIDEO_FB_SSD1307
> > > +	bool "Solomon SSD1307 framebuffer support"
> > > +	depends on PWM && I2C && GPIOLIB
> > > +
> > >  config VIDEO_VPL
> > >  	depends on OFTREE
> > >  	bool
> > > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> > > index 1bf2e1f3ca..e23c9c37b6 100644
> > > --- a/drivers/video/Makefile
> > > +++ b/drivers/video/Makefile
> > > @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
> > >  obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
> > >  obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
> > >  obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
> > > +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
> > > diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
> > > new file mode 100644
> > > index 0000000000..0dfdcc2232
> > > --- /dev/null
> > > +++ b/drivers/video/ssd1307fb.c
> > > @@ -0,0 +1,569 @@
> > > +/*
> > > + * Driver for the Solomon SSD1307 OLED controller family
> > > + *
> > > + * Supports:
> > > + *	- SSD1305 (untested)
> > > + *	- SSD1306
> > > + *	- SSD1307 (untested)
> > > + *	- SSD1309 (untested)
> > > + *
> > > + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons
> > > + *
> > > + * Ported to barebox from linux v4.10
> > > + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de>
> > > + *
> > > + * Licensed under the GPLv2 or later.
> > > + */
> > > +
> > > +#include <common.h>
> > > +#include <init.h>
> > > +#include <fb.h>
> > > +#include <i2c/i2c.h>
> > > +#include <of_device.h>
> > > +#include <gpio.h>
> > > +#include <of_gpio.h>
> > > +#include <printk.h>
> > > +
> > > +#define SSD1307FB_DATA			0x40
> > > +#define SSD1307FB_COMMAND		0x80
> > > +
> > > +#define SSD1307FB_SET_ADDRESS_MODE	0x20
> > > +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
> > > +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL	(0x01)
> > > +#define SSD1307FB_SET_ADDRESS_MODE_PAGE		(0x02)
> > > +#define SSD1307FB_SET_COL_RANGE		0x21
> > > +#define SSD1307FB_SET_PAGE_RANGE	0x22
> > > +#define SSD1307FB_CONTRAST		0x81
> > > +#define	SSD1307FB_CHARGE_PUMP		0x8d
> > > +#define SSD1307FB_SEG_REMAP_ON		0xa1
> > > +#define SSD1307FB_DISPLAY_OFF		0xae
> > > +#define SSD1307FB_SET_MULTIPLEX_RATIO	0xa8
> > > +#define SSD1307FB_DISPLAY_ON		0xaf
> > > +#define SSD1307FB_START_PAGE_ADDRESS	0xb0
> > > +#define SSD1307FB_SET_DISPLAY_OFFSET	0xd3
> > > +#define	SSD1307FB_SET_CLOCK_FREQ	0xd5
> > > +#define	SSD1307FB_SET_PRECHARGE_PERIOD	0xd9
> > > +#define	SSD1307FB_SET_COM_PINS_CONFIG	0xda
> > > +#define	SSD1307FB_SET_VCOMH		0xdb
> > 
> > please consistently use spaces after #define
> 
> Will do.
> 
> > 
> > > +
> > > +struct ssd1307fb_par;
> > 
> > Unnecessary.
> 
> Ok.
> 
> > 
> > > +
> > > +struct ssd1307fb_deviceinfo {
> > > +	u32 default_vcomh;
> > > +	u32 default_dclk_div;
> > > +	u32 default_dclk_frq;
> > > +	int need_chargepump;
> > > +};
> > > +
> > 
> > [...]
> > 
> > > +static int ssd1307fb_probe(struct device_d *dev)
> > > +{
> > > +	struct i2c_client *client = to_i2c_client(dev);
> > > +	struct fb_info *info;
> > > +	struct device_node *node = dev->device_node;
> > > +	const struct of_device_id *match =
> > > +		of_match_node(ssd1307fb_of_match, dev->device_node);
> > > +	u32 vmem_size;
> > > +	struct ssd1307fb_par *par;
> > > +	struct ssd1307fb_array *array;
> > > +	u8 *vmem;
> > > +	int ret;
> > > +	int i, j;
> > > +
> > > +	if (!node) {
> > > +		dev_err(&client->dev, "No device tree data found!\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	info = xzalloc(sizeof(struct fb_info));
> > > +	if (!info) {
> > > +		dev_err(&client->dev, "Couldn't allocate framebuffer.\n");
> > > +		return -ENOMEM;
> > > +	}
> > 
> > xzalloc always returns succesfully, no need to check.
> 
> Ok.
> 
> > 
> > > +
> > > +	par = info->priv;
> > > +	par->info = info;
> > > +	par->client = client;
> > > +
> > > +	par->device_info = (struct ssd1307fb_deviceinfo *)match->data;
> > > +
> > > +	par->reset = of_get_named_gpio(node,
> > > +					 "reset-gpios", 0);
> > > +	if (!gpio_is_valid(par->reset)) {
> > > +		dev_err(&client->dev,
> > > +			"Couldn't get named gpio 'reset-gpios' %d.\n",
> > > +			par->reset);
> > > +		ret = par->reset;
> > > +		goto fb_alloc_error;
> > > +	}
> > 
> > Is this gpio really mandatory?
> 
> 
> This is the corresponding snippet from the kernel in
> drivers/video/fbdev/ssd1307fb.c, line 564 ff. (v4.10):
> 
>     par->reset = of_get_named_gpio(client->dev.of_node,
>                                  "reset-gpios", 0);
>     if (!gpio_is_valid(par->reset)) {
>         ret = -EINVAL;
>         goto fb_alloc_error;
>     }
> 
> "reset-gpios" is one of the required properties, see
> 
>   Documentation/devicetree/bindings/display/ssd1307fb.txt
> 
> or in barebox:
> 
>   dts/Bindings/display/ssd1307fb.txt

Ok.

> 
> > 
> > > +
> > > +	if (of_property_read_u32(node, "solomon,width", &par->width))
> > > +		par->width = 96;
> > > +
> > > +	if (of_property_read_u32(node, "solomon,height", &par->height))
> > > +		par->height = 16;
> > 
> > These defaults only work for you. You should bail out with an error if
> > the devicetree does not contain values for these instead.
> 
> This part was ported 1:1 from linux. As solomon,width and solomon,height are
> required properties also, should I bail out nonetheless?

Yes, please. The resolution of the framebuffer must be explicitly given
in the device tree. If it's not then the user gets a better clue what's
wrong when the driver does not successfully probe.

Sascha

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

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-02-28  7:58 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender
2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender
2017-02-27  9:54   ` Sascha Hauer
2017-02-27 15:56     ` [PATCH v2] " Bastian Stender
2017-02-28  7:41       ` Sascha Hauer
2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender
2017-02-27  9:55   ` Sascha Hauer
2017-02-27 16:01     ` [PATCH v2] " Bastian Stender
2017-02-28  7:50       ` Sascha Hauer
2017-02-24 14:25 ` [PATCH 3/4] fb: introduce flush for virtual framebuffer Bastian Stender
2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender
2017-02-24 16:10   ` Bastian Stender
2017-02-27 10:08   ` Sascha Hauer
2017-02-27 15:45     ` Bastian Stender
2017-02-28  7:57       ` Sascha Hauer

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