aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-xlnx/4.6/0001-drm-xilinx-Add-encoder-for-Digilent-boards.patch
blob: 1b78e9b921a862ec191c50ec59110df81f9612fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
From 9f144ae13de8a48eda11af4d5738338894ad92c6 Mon Sep 17 00:00:00 2001
From: Jason Wu <jason.wu.misc@gmail.com>
Date: Sun, 10 Apr 2016 13:14:13 +1000
Subject: [PATCH 1/3] drm: xilinx: Add encoder for Digilent boards

Add the dglnt_encoder driver that enables DRM support for the VGA and
HDMI output ports found on many Digilent boards.

Upstream-Status: Pending

Signed-off-by: Sam Bobrowicz <sbobrowicz@digilentinc.com>
Signed-off-by: Jason Wu <jason.wu.misc@gmail.com>
---
 .../bindings/drm/xilinx/dglnt_encoder.txt          |  23 +++
 drivers/gpu/drm/xilinx/Kconfig                     |   6 +
 drivers/gpu/drm/xilinx/Makefile                    |   1 +
 drivers/gpu/drm/xilinx/dglnt_encoder.c             | 217 +++++++++++++++++++++
 4 files changed, 247 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/xilinx/dglnt_encoder.txt
 create mode 100644 drivers/gpu/drm/xilinx/dglnt_encoder.c

diff --git a/Documentation/devicetree/bindings/drm/xilinx/dglnt_encoder.txt b/Documentation/devicetree/bindings/drm/xilinx/dglnt_encoder.txt
new file mode 100644
index 0000000000..242b24e482
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/xilinx/dglnt_encoder.txt
@@ -0,0 +1,23 @@
+Device-Tree bindings for Digilent DRM Encoder Slave
+
+This driver provides support for VGA and HDMI outputs on Digilent FPGA boards.
+The VGA or HDMI port must be connected to a Xilinx display pipeline via an
+axi2vid IP core.
+
+Required properties:
+ - compatible: Should be "digilent,drm-encoder".
+
+Optional properties:
+ - dglnt,edid-i2c: The I2C device connected to the DDC bus on the video
+                   connector. This is used to obtain the supported resolutions
+                   of an attached monitor. If not defined, then a default
+                   set of resolutions is used and the display will initialize
+                   to 720p. Note most VGA connectors on Digilent boards do
+                   not have the DDC bus routed out.
+
+Example:
+
+	encoder_0: digilent_encoder {
+		compatible = "digilent,drm-encoder";
+		dglnt,edid-i2c = <&i2c1>;
+	};
diff --git a/drivers/gpu/drm/xilinx/Kconfig b/drivers/gpu/drm/xilinx/Kconfig
index a713b17673..c32a4a679e 100644
--- a/drivers/gpu/drm/xilinx/Kconfig
+++ b/drivers/gpu/drm/xilinx/Kconfig
@@ -21,3 +21,9 @@ config DRM_XILINX_DP_SUB
 	select DRM_XILINX_DP
 	help
 	  DRM driver for Xilinx Display Port Subsystem.
+
+config DRM_DIGILENT_ENCODER
+   tristate "Digilent VGA/HDMI DRM Encoder Driver"
+   depends on DRM_XILINX
+   help
+     DRM slave encoder for Video-out on Digilent boards.
diff --git a/drivers/gpu/drm/xilinx/Makefile b/drivers/gpu/drm/xilinx/Makefile
index 705472c338..a571bd96cf 100644
--- a/drivers/gpu/drm/xilinx/Makefile
+++ b/drivers/gpu/drm/xilinx/Makefile
@@ -10,3 +10,4 @@ xilinx_drm-y += xilinx_cresample.o xilinx_osd.o xilinx_rgb2yuv.o xilinx_vtc.o
 obj-$(CONFIG_DRM_XILINX) += xilinx_drm.o
 obj-$(CONFIG_DRM_XILINX_DP) += xilinx_drm_dp.o
 obj-$(CONFIG_DRM_XILINX_DP_SUB) += xilinx_drm_dp_sub.o
+obj-$(CONFIG_DRM_DIGILENT_ENCODER) += dglnt_encoder.o
diff --git a/drivers/gpu/drm/xilinx/dglnt_encoder.c b/drivers/gpu/drm/xilinx/dglnt_encoder.c
new file mode 100644
index 0000000000..26a23986f9
--- /dev/null
+++ b/drivers/gpu/drm/xilinx/dglnt_encoder.c
@@ -0,0 +1,217 @@
+/*
+ * dglnt_encoder.c - DRM slave encoder for Video-out on Digilent boards
+ *
+ * Copyright (C) 2015 Digilent
+ * Author: Sam Bobrowicz <sbobrowicz@digilentinc.com>
+ *
+ * Based on udl_encoder.c and udl_connector.c, Copyright (C) 2012 Red Hat.
+ * Also based on xilinx_drm_dp.c, Copyright (C) 2014 Xilinx, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define DGLNT_ENC_MAX_FREQ 150000
+#define DGLNT_ENC_MAX_H 1920
+#define DGLNT_ENC_MAX_V 1080
+#define DGLNT_ENC_PREF_H 1280
+#define DGLNT_ENC_PREF_V 720
+
+struct dglnt_encoder {
+	struct drm_encoder *encoder;
+	struct i2c_adapter *i2c_bus;
+	bool i2c_present;
+};
+
+static inline struct dglnt_encoder *to_dglnt_encoder(
+					struct drm_encoder *encoder)
+{
+	return to_encoder_slave(encoder)->slave_priv;
+}
+
+static bool dglnt_mode_fixup(struct drm_encoder *encoder,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void dglnt_encoder_mode_set(struct drm_encoder *encoder,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void
+dglnt_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void dglnt_encoder_save(struct drm_encoder *encoder)
+{
+}
+
+static void dglnt_encoder_restore(struct drm_encoder *encoder)
+{
+}
+
+static int dglnt_encoder_mode_valid(struct drm_encoder *encoder,
+				struct drm_display_mode *mode)
+{
+	if (mode &&
+		!(mode->flags & ((DRM_MODE_FLAG_INTERLACE |
+			DRM_MODE_FLAG_DBLCLK) | DRM_MODE_FLAG_3D_MASK)) &&
+		(mode->clock <= DGLNT_ENC_MAX_FREQ) &&
+		(mode->hdisplay <= DGLNT_ENC_MAX_H) &&
+		(mode->vdisplay <= DGLNT_ENC_MAX_V))
+		return MODE_OK;
+	return MODE_BAD;
+}
+
+static int dglnt_encoder_get_modes(struct drm_encoder *encoder,
+				struct drm_connector *connector)
+{
+	struct dglnt_encoder *dglnt = to_dglnt_encoder(encoder);
+	struct edid *edid;
+	int num_modes = 0;
+
+	if (dglnt->i2c_present) {
+		edid = drm_get_edid(connector, dglnt->i2c_bus);
+		drm_mode_connector_update_edid_property(connector, edid);
+		if (edid) {
+			num_modes = drm_add_edid_modes(connector, edid);
+			kfree(edid);
+		}
+	} else {
+		num_modes = drm_add_modes_noedid(connector, DGLNT_ENC_MAX_H,
+						DGLNT_ENC_MAX_V);
+		drm_set_preferred_mode(connector, DGLNT_ENC_PREF_H,
+					DGLNT_ENC_PREF_V);
+	}
+	return num_modes;
+}
+
+static enum drm_connector_status dglnt_encoder_detect(
+					struct drm_encoder *encoder,
+					struct drm_connector *connector)
+{
+	struct dglnt_encoder *dglnt = to_dglnt_encoder(encoder);
+
+	if (dglnt->i2c_present) {
+		if (drm_probe_ddc(dglnt->i2c_bus))
+			return connector_status_connected;
+		return connector_status_disconnected;
+	} else
+		return connector_status_unknown;
+}
+
+static struct drm_encoder_slave_funcs dglnt_encoder_slave_funcs = {
+	.dpms			= dglnt_encoder_dpms,
+	.save			= dglnt_encoder_save,
+	.restore		= dglnt_encoder_restore,
+	.mode_fixup		= dglnt_mode_fixup,
+	.mode_valid		= dglnt_encoder_mode_valid,
+	.mode_set		= dglnt_encoder_mode_set,
+	.detect			= dglnt_encoder_detect,
+	.get_modes		= dglnt_encoder_get_modes,
+};
+
+static int dglnt_encoder_encoder_init(struct platform_device *pdev,
+				struct drm_device *dev,
+				struct drm_encoder_slave *encoder)
+{
+	struct dglnt_encoder *dglnt = platform_get_drvdata(pdev);
+	struct device_node *sub_node;
+
+	encoder->slave_priv = dglnt;
+	encoder->slave_funcs = &dglnt_encoder_slave_funcs;
+
+	dglnt->encoder = &encoder->base;
+
+	/* get i2c adapter for edid */
+	dglnt->i2c_present = false;
+	sub_node = of_parse_phandle(pdev->dev.of_node, "dglnt,edid-i2c", 0);
+	if (sub_node) {
+		dglnt->i2c_bus = of_find_i2c_adapter_by_node(sub_node);
+		if (!dglnt->i2c_bus)
+			DRM_INFO("failed to get the edid i2c adapter, using default modes\n");
+		else
+			dglnt->i2c_present = true;
+		of_node_put(sub_node);
+	}
+
+	return 0;
+}
+
+static int dglnt_encoder_probe(struct platform_device *pdev)
+{
+	struct dglnt_encoder *dglnt;
+
+	dglnt = devm_kzalloc(&pdev->dev, sizeof(*dglnt), GFP_KERNEL);
+	if (!dglnt)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, dglnt);
+
+	return 0;
+}
+
+static int dglnt_encoder_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id dglnt_encoder_of_match[] = {
+	{ .compatible = "digilent,drm-encoder", },
+	{ /* end of table */ },
+};
+MODULE_DEVICE_TABLE(of, dglnt_encoder_of_match);
+
+static struct drm_platform_encoder_driver dglnt_encoder_driver = {
+	.platform_driver = {
+		.probe			= dglnt_encoder_probe,
+		.remove			= dglnt_encoder_remove,
+		.driver			= {
+			.owner		= THIS_MODULE,
+			.name		= "dglnt-drm-enc",
+			.of_match_table	= dglnt_encoder_of_match,
+		},
+	},
+
+	.encoder_init = dglnt_encoder_encoder_init,
+};
+
+static int __init dglnt_encoder_init(void)
+{
+	return platform_driver_register(&dglnt_encoder_driver.platform_driver);
+}
+
+static void __exit dglnt_encoder_exit(void)
+{
+	platform_driver_unregister(&dglnt_encoder_driver.platform_driver);
+}
+
+module_init(dglnt_encoder_init);
+module_exit(dglnt_encoder_exit);
+
+MODULE_AUTHOR("Digilent, Inc.");
+MODULE_DESCRIPTION("DRM slave encoder for Video-out on Digilent boards");
+MODULE_LICENSE("GPL v2");
-- 
2.10.2