[U-Boot] [PATCH v2 2/5] video_osd: Add ihs_video_out driver

Mario Six mario.six at gdsys.cc
Wed May 23 12:09:51 UTC 2018


Add a driver for IHS OSDs on IHS FPGAs.

Signed-off-by: Mario Six <mario.six at gdsys.cc>

---

v1 -> v2:
* Renamed x and y parameters to col and row
* Removed duplicate IHS_VIDEO_OUT definition
* Switched error return code of ihs_video_out_set_mem to E2BIG
* Dropped blank lines between dev_read_u32_default calls
* Documented members of ihs_video_out_priv
* Turned printfs into debugs
* Don't display OSD until something has been written to it
* Made the code a bit more readable
* Added binding file
* Expanded documentation and help
* Switched to display_enable
* Switched to regmap usage (instead of fpgamap uclass)
* Renamed 'dp_tx' property to 'video_tx'

---
 .../video/osd/gdsys,ihs_video_out.txt              |  22 ++
 drivers/video/Kconfig                              |   9 +
 drivers/video/Makefile                             |   1 +
 drivers/video/ihs_video_out.c                      | 277 +++++++++++++++++++++
 4 files changed, 309 insertions(+)
 create mode 100644 doc/device-tree-bindings/video/osd/gdsys,ihs_video_out.txt
 create mode 100644 drivers/video/ihs_video_out.c

diff --git a/doc/device-tree-bindings/video/osd/gdsys,ihs_video_out.txt b/doc/device-tree-bindings/video/osd/gdsys,ihs_video_out.txt
new file mode 100644
index 00000000000..464374613b8
--- /dev/null
+++ b/doc/device-tree-bindings/video/osd/gdsys,ihs_video_out.txt
@@ -0,0 +1,22 @@
+* Guntermann & Drunck Integrated Hardware Systems OSD
+
+Required properties:
+- compatible: "gdsys,ihs_video_out"
+- reg: Register base for the video registers
+- osd_base: Register base for the OSD registers
+- osd_buffer_base: Address of the OSD video memory
+- mode: The initial resolution and frequency: "1024_768_60", "720_400_70", or
+        "640_480_70"
+- clk_gen: phandle to the pixel clock generator
+- dp_tx: phandle to the display associated with the OSD
+
+Example:
+
+fpga0_video0 {
+	compatible = "gdsys,ihs_video_out";
+	reg = <0x100 0x40>;
+	osd_base = <0x180>;
+	osd_buffer_base = <0x1000>;
+	dp_tx = <&fpga0_dp_video0>;
+	clk_gen = <&fpga0_video0_clkgen>;
+};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 37be23d2fcc..4ca15174bb2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -666,4 +666,13 @@ config OSD
 	   This supports drivers that provide a OSD (on-screen display), which
 	   is a (usually text-oriented) graphics buffer to show information on
 	   a display.
+
+config IHS_VIDEO_OUT
+	bool "Enable IHS video out driver"
+	depends on OSD
+	help
+	  Enable support for the gdsys Integrated Hardware Systems (IHS) video
+	  out On-screen Display (OSD) used on gdsys FPGAs to control dynamic
+	  textual overlays of the display outputs.
+
 endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 1889c5a5208..44252b5989a 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -56,6 +56,7 @@ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
 obj-${CONFIG_VIDEO_STM32} += stm32/

 obj-${CONFIG_OSD} += video_osd-uclass.o
+obj-$(CONFIG_IHS_VIDEO_OUT) += ihs_video_out.o

 obj-y += bridge/
 obj-y += sunxi/
diff --git a/drivers/video/ihs_video_out.c b/drivers/video/ihs_video_out.c
new file mode 100644
index 00000000000..3a870e22c2e
--- /dev/null
+++ b/drivers/video/ihs_video_out.c
@@ -0,0 +1,277 @@
+/*
+ * (C) Copyright 2017
+ * Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc
+ *
+ * based on the gdsys osd driver, which is
+ *
+ * (C) Copyright 2010
+ * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach at gdsys.de
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <display.h>
+#include <dm.h>
+#include <regmap.h>
+#include <video_osd.h>
+#include <asm/gpio.h>
+
+#define MAX_X_CHARS 53
+#define MAX_Y_CHARS 26
+#define MAX_VIDEOMEM_WIDTH (2 * 64)
+#define MAX_VIDEOMEM_HEIGHT (2 * 32)
+#define CHAR_WIDTH 12
+#define CHAR_HEIGHT 18
+
+struct ihs_video_out_regs {
+	u16 versions;
+	u16 features;
+	u16 control;
+	u16 xy_size;
+	u16 xy_scale;
+	u16 x_pos;
+	u16 y_pos;
+};
+
+#define ihs_video_out_set(map, member, val) \
+	regmap_range_set(map, 1, struct ihs_video_out_regs, member, val)
+
+#define ihs_video_out_get(map, member, valp) \
+	regmap_range_get(map, 1, struct ihs_video_out_regs, member, valp)
+
+enum {
+	CONTROL_FILTER_BLACK = (0 << 0),
+	CONTROL_FILTER_ORIGINAL = (1 << 0),
+	CONTROL_FILTER_DARKER = (2 << 0),
+	CONTROL_FILTER_GRAY = (3 << 0),
+
+	CONTROL_MODE_PASSTHROUGH = (0 << 3),
+	CONTROL_MODE_OSD = (1 << 3),
+	CONTROL_MODE_AUTO = (2 << 3),
+	CONTROL_MODE_OFF = (3 << 3),
+
+	CONTROL_ENABLE_OFF = (0 << 6),
+	CONTROL_ENABLE_ON = (1 << 6),
+};
+
+struct ihs_video_out_priv {
+	/* Register map for OSD device */
+	struct regmap *map;
+	/* Pointer to video memory */
+	u16 *vidmem;
+	/* Display width in text columns */
+	uint base_width;
+	/* Display height in text rows */
+	uint base_height;
+	/* x-resolution of the display in pixels */
+	uint res_x;
+	/* y-resolution of the display in pixels */
+	uint res_y;
+	/* OSD's sync mode (resolution + frequency) */
+	int sync_src;
+	/* The display port output for this OSD */
+	struct udevice *video_tx;
+	/* The pixel clock generator for the display */
+	struct udevice *clk_gen;
+};
+
+static const struct udevice_id ihs_video_out_ids[] = {
+	{ .compatible = "gdsys,ihs_video_out" },
+	{ }
+};
+
+static int set_control(struct udevice *dev, u16 value)
+{
+	struct ihs_video_out_priv *priv = dev_get_priv(dev);
+
+	if (priv->sync_src)
+		value |= ((priv->sync_src & 0x7) << 8);
+
+	ihs_video_out_set(priv->map, control, value);
+
+	return 0;
+}
+
+int ihs_video_out_get_info(struct udevice *dev, struct video_osd_info *info)
+{
+	struct ihs_video_out_priv *priv = dev_get_priv(dev);
+	u16 versions;
+
+	ihs_video_out_get(priv->map, versions, &versions);
+
+	info->width = priv->base_width;
+	info->height = priv->base_height;
+	info->major_version = versions / 100;
+	info->minor_version = versions % 100;
+
+	return 0;
+}
+
+int ihs_video_out_set_mem(struct udevice *dev, uint col, uint row, u8 *buf,
+			  size_t buflen, uint count)
+{
+	struct ihs_video_out_priv *priv = dev_get_priv(dev);
+	uint offset;
+	uint k, l;
+	u16 data;
+
+	for (l = 0; l < count; ++l) {
+		offset = row * priv->base_width + col + l * (buflen / 2);
+
+		for (k = 0; k < buflen / 2; ++k) {
+			if (offset + k >= priv->base_width * priv->base_height)
+				return -E2BIG;
+
+			data = buf[2 * k + 1] + 256 * buf[2 * k];
+			out_le16(priv->vidmem + offset + k, data);
+		}
+	}
+
+	set_control(dev, CONTROL_FILTER_ORIGINAL |
+			 CONTROL_MODE_OSD |
+			 CONTROL_ENABLE_ON);
+
+	return 0;
+}
+
+inline u16 div2_u16(u16 val)
+{
+	return (32767 * val) / 65535;
+}
+
+int ihs_video_out_set_size(struct udevice *dev, uint col, uint row)
+{
+	struct ihs_video_out_priv *priv = dev_get_priv(dev);
+
+	if (!col || col > 64 || col > MAX_X_CHARS ||
+	    !row || row > 32 || row > MAX_Y_CHARS) {
+		return -EINVAL;
+	}
+
+	ihs_video_out_set(priv->map, xy_size, ((col - 1) << 8) | (row - 1));
+	/* Center OSD on screen */
+	ihs_video_out_set(priv->map, x_pos,
+			  div2_u16(priv->res_x - CHAR_WIDTH * col));
+	ihs_video_out_set(priv->map, y_pos,
+			  div2_u16(priv->res_y - CHAR_HEIGHT * row));
+
+	return 0;
+}
+
+int ihs_video_out_print(struct udevice *dev, uint col, uint row, ulong color,
+			char *text)
+{
+	int res;
+	u8 buffer[MAX_VIDEOMEM_WIDTH];
+	uint k;
+	uint charcount = strlen(text);
+	uint len = min(charcount, (uint)(MAX_VIDEOMEM_WIDTH));
+
+	for (k = 0; k < len; ++k) {
+		buffer[2 * k] = text[k];
+		buffer[2 * k + 1] = color;
+	}
+
+	res = ihs_video_out_set_mem(dev, col, row, buffer, 2 * len, 1);
+
+	if (res < 0)
+		return res;
+
+	return 0;
+}
+
+static const struct video_osd_ops ihs_video_out_ops = {
+	.get_info = ihs_video_out_get_info,
+	.set_mem = ihs_video_out_set_mem,
+	.set_size = ihs_video_out_set_size,
+	.print = ihs_video_out_print,
+};
+
+int ihs_video_out_probe(struct udevice *dev)
+{
+	struct ihs_video_out_priv *priv = dev_get_priv(dev);
+	int len = 0;
+	struct ofnode_phandle_args phandle_args;
+	char *mode;
+	u16 features;
+	struct display_timing timing;
+
+	regmap_init_mem(dev_ofnode(dev), &priv->map);
+
+	/* Range with index 2 is video memory */
+	priv->vidmem = regmap_get_range(priv->map, 2);
+
+	mode = (char *)dev_read_prop(dev, "mode", &len);
+
+	if (!mode) {
+		debug("%s: Could not read mode property.\n", dev->name);
+		return -EINVAL;
+	}
+
+	if (!strcmp(mode, "1024_768_60")) {
+		priv->sync_src = 2;
+		priv->res_x = 1024;
+		priv->res_y = 768;
+		timing.hactive.typ = 1024;
+		timing.vactive.typ = 768;
+	} else if (!strcmp(mode, "720_400_70")) {
+		priv->sync_src = 1;
+		priv->res_x = 720;
+		priv->res_y = 400;
+		timing.hactive.typ = 720;
+		timing.vactive.typ = 400;
+	} else {
+		priv->sync_src = 0;
+		priv->res_x = 640;
+		priv->res_y = 480;
+		timing.hactive.typ = 640;
+		timing.vactive.typ = 480;
+	}
+
+	ihs_video_out_get(priv->map, features, &features);
+
+	set_control(dev, CONTROL_FILTER_ORIGINAL |
+			 CONTROL_MODE_OSD |
+			 CONTROL_ENABLE_OFF);
+
+	priv->base_width = ((features & 0x3f00) >> 8) + 1;
+	priv->base_height = (features & 0x001f) + 1;
+
+	if (dev_read_phandle_with_args(dev, "clk_gen", NULL, 0, 0,
+				       &phandle_args)) {
+		debug("%s: Could not get clk_gen node.\n", dev->name);
+		return -EINVAL;
+	}
+
+	if (uclass_get_device_by_ofnode(UCLASS_CLK, phandle_args.node,
+					&priv->clk_gen)) {
+		debug("%s: Could not get clk_gen dev.\n", dev->name);
+		return -EINVAL;
+	}
+
+	if (dev_read_phandle_with_args(dev, "video_tx", NULL, 0, 0,
+				       &phandle_args)) {
+		debug("%s: Could not get video_tx.\n", dev->name);
+		return -EINVAL;
+	}
+
+	if (uclass_get_device_by_ofnode(UCLASS_DISPLAY, phandle_args.node,
+					&priv->video_tx)) {
+		debug("%s: Could not get video_tx dev.\n", dev->name);
+		return -EINVAL;
+	}
+
+	display_enable(priv->video_tx, 8, &timing);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ihs_video_out_drv) = {
+	.name           = "ihs_video_out_drv",
+	.id             = UCLASS_VIDEO_OSD,
+	.ops		= &ihs_video_out_ops,
+	.of_match       = ihs_video_out_ids,
+	.probe          = ihs_video_out_probe,
+	.priv_auto_alloc_size = sizeof(struct ihs_video_out_priv),
+};
--
2.11.0



More information about the U-Boot mailing list