blob: b320b3a21ad4f60e4efd373217861829cbdc363c [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Inki Daeb73d1232012-03-21 10:55:26 +09002/* exynos_drm_vidi.c
3 *
4 * Copyright (C) 2012 Samsung Electronics Co.Ltd
5 * Authors:
6 * Inki Dae <inki.dae@samsung.com>
Inki Daeb73d1232012-03-21 10:55:26 +09007 */
Inki Daeb73d1232012-03-21 10:55:26 +09008
Sam Ravnborg2bda34d72019-06-24 22:06:28 +09009#include <linux/component.h>
Inki Daeb73d1232012-03-21 10:55:26 +090010#include <linux/kernel.h>
Inki Daeb73d1232012-03-21 10:55:26 +090011#include <linux/platform_device.h>
Andrzej Hajda8574e922016-09-23 10:15:23 +020012#include <linux/timer.h>
Inki Daeb73d1232012-03-21 10:55:26 +090013
Gustavo Padovan4ea95262015-06-01 12:04:44 -030014#include <drm/drm_atomic_helper.h>
Daniel Vetterfcd70cd2019-01-17 22:03:34 +010015#include <drm/drm_edid.h>
16#include <drm/drm_probe_helper.h>
Sam Ravnborg2bda34d72019-06-24 22:06:28 +090017#include <drm/drm_vblank.h>
18#include <drm/exynos_drm.h>
Inki Daeb73d1232012-03-21 10:55:26 +090019
Inki Daeb73d1232012-03-21 10:55:26 +090020#include "exynos_drm_crtc.h"
Sam Ravnborg2bda34d72019-06-24 22:06:28 +090021#include "exynos_drm_drv.h"
Marek Szyprowski0488f502015-11-30 14:53:21 +010022#include "exynos_drm_fb.h"
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090023#include "exynos_drm_plane.h"
Mark Browne30655d2013-08-13 00:46:40 +010024#include "exynos_drm_vidi.h"
Inki Daeb73d1232012-03-21 10:55:26 +090025
Andrzej Hajda8574e922016-09-23 10:15:23 +020026/* VIDI uses fixed refresh rate of 50Hz */
27#define VIDI_REFRESH_TIME (1000 / 50)
28
Inki Daeb73d1232012-03-21 10:55:26 +090029/* vidi has totally three virtual windows. */
30#define WINDOWS_NR 3
31
Sean Paulce6cb552014-01-30 16:38:07 -050032#define ctx_from_connector(c) container_of(c, struct vidi_context, \
33 connector)
Inki Daeb73d1232012-03-21 10:55:26 +090034
Inki Daeb73d1232012-03-21 10:55:26 +090035struct vidi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -030036 struct drm_encoder encoder;
Sean Paul080be03d2014-02-19 21:02:55 +090037 struct drm_device *drm_dev;
Inki Daedf90a642019-04-15 16:35:08 +090038 struct device *dev;
Gustavo Padovan93bca242015-01-18 18:16:23 +090039 struct exynos_drm_crtc *crtc;
Sean Paulce6cb552014-01-30 16:38:07 -050040 struct drm_connector connector;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +090041 struct exynos_drm_plane planes[WINDOWS_NR];
Inki Daeb73d1232012-03-21 10:55:26 +090042 struct edid *raw_edid;
43 unsigned int clkdiv;
Inki Daeb73d1232012-03-21 10:55:26 +090044 unsigned int connected;
Inki Daeb73d1232012-03-21 10:55:26 +090045 bool suspended;
Andrzej Hajda8574e922016-09-23 10:15:23 +020046 struct timer_list timer;
Inki Daeb73d1232012-03-21 10:55:26 +090047 struct mutex lock;
48};
49
Gustavo Padovan2b8376c2015-08-15 12:14:08 -030050static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e)
Andrzej Hajda2f26bd72014-11-17 09:54:23 +010051{
Gustavo Padovancf67cc92015-08-11 17:38:06 +090052 return container_of(e, struct vidi_context, encoder);
Andrzej Hajda2f26bd72014-11-17 09:54:23 +010053}
54
Inki Daeb73d1232012-03-21 10:55:26 +090055static const char fake_edid_info[] = {
56 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
57 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
58 0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
59 0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
60 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
61 0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
62 0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
63 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
64 0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
65 0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
66 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
67 0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
68 0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
69 0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
70 0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
71 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
72 0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
73 0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x06
78};
79
Marek Szyprowskifbbb1e12015-08-31 00:53:57 +090080static const uint32_t formats[] = {
81 DRM_FORMAT_XRGB8888,
82 DRM_FORMAT_ARGB8888,
83 DRM_FORMAT_NV12,
84};
85
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +010086static const enum drm_plane_type vidi_win_types[WINDOWS_NR] = {
87 DRM_PLANE_TYPE_PRIMARY,
88 DRM_PLANE_TYPE_OVERLAY,
89 DRM_PLANE_TYPE_CURSOR,
90};
91
Gustavo Padovan93bca242015-01-18 18:16:23 +090092static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
Inki Daeb73d1232012-03-21 10:55:26 +090093{
Gustavo Padovan93bca242015-01-18 18:16:23 +090094 struct vidi_context *ctx = crtc->ctx;
Inki Daeb73d1232012-03-21 10:55:26 +090095
Inki Daeb73d1232012-03-21 10:55:26 +090096 if (ctx->suspended)
97 return -EPERM;
98
Andrzej Hajda8574e922016-09-23 10:15:23 +020099 mod_timer(&ctx->timer,
100 jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
Inki Dae291257c2012-09-19 11:02:43 +0900101
Inki Daeb73d1232012-03-21 10:55:26 +0900102 return 0;
103}
104
Gustavo Padovan93bca242015-01-18 18:16:23 +0900105static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
Inki Daeb73d1232012-03-21 10:55:26 +0900106{
Inki Daeb73d1232012-03-21 10:55:26 +0900107}
108
Gustavo Padovan1e1d1392015-08-03 14:39:36 +0900109static void vidi_update_plane(struct exynos_drm_crtc *crtc,
110 struct exynos_drm_plane *plane)
Inki Daeb73d1232012-03-21 10:55:26 +0900111{
Marek Szyprowski0488f502015-11-30 14:53:21 +0100112 struct drm_plane_state *state = plane->base.state;
Gustavo Padovan93bca242015-01-18 18:16:23 +0900113 struct vidi_context *ctx = crtc->ctx;
Marek Szyprowski0488f502015-11-30 14:53:21 +0100114 dma_addr_t addr;
Inki Daeb73d1232012-03-21 10:55:26 +0900115
Inki Daeb73d1232012-03-21 10:55:26 +0900116 if (ctx->suspended)
117 return;
118
Marek Szyprowski0488f502015-11-30 14:53:21 +0100119 addr = exynos_drm_fb_dma_addr(state->fb, 0);
Inki Daedf90a642019-04-15 16:35:08 +0900120 DRM_DEV_DEBUG_KMS(ctx->dev, "dma_addr = %pad\n", &addr);
Inki Daeb73d1232012-03-21 10:55:26 +0900121}
122
Inki Dae11f95482019-12-19 11:07:53 +0900123static void vidi_atomic_enable(struct exynos_drm_crtc *crtc)
Sean Paulaf65c802014-01-30 16:19:27 -0500124{
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300125 struct vidi_context *ctx = crtc->ctx;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900126
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300127 mutex_lock(&ctx->lock);
Sean Paulaf65c802014-01-30 16:19:27 -0500128
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300129 ctx->suspended = false;
Sean Paulaf65c802014-01-30 16:19:27 -0500130
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300131 mutex_unlock(&ctx->lock);
Andrzej Hajda8574e922016-09-23 10:15:23 +0200132
133 drm_crtc_vblank_on(&crtc->base);
Sean Paulaf65c802014-01-30 16:19:27 -0500134}
135
Inki Dae11f95482019-12-19 11:07:53 +0900136static void vidi_atomic_disable(struct exynos_drm_crtc *crtc)
Sean Paulaf65c802014-01-30 16:19:27 -0500137{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900138 struct vidi_context *ctx = crtc->ctx;
Sean Paulaf65c802014-01-30 16:19:27 -0500139
Andrzej Hajda8574e922016-09-23 10:15:23 +0200140 drm_crtc_vblank_off(&crtc->base);
141
Sean Paulaf65c802014-01-30 16:19:27 -0500142 mutex_lock(&ctx->lock);
143
Gustavo Padovan3cecda02015-06-01 12:04:55 -0300144 ctx->suspended = true;
Sean Paulaf65c802014-01-30 16:19:27 -0500145
146 mutex_unlock(&ctx->lock);
147}
148
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +0900149static const struct exynos_drm_crtc_ops vidi_crtc_ops = {
Inki Dae11f95482019-12-19 11:07:53 +0900150 .atomic_enable = vidi_atomic_enable,
151 .atomic_disable = vidi_atomic_disable,
Sean Paul1c6244c2014-01-30 16:19:02 -0500152 .enable_vblank = vidi_enable_vblank,
153 .disable_vblank = vidi_disable_vblank,
Gustavo Padovan9cc76102015-08-03 14:38:05 +0900154 .update_plane = vidi_update_plane,
Andrzej Hajdaa3922762017-03-14 09:27:56 +0100155 .atomic_flush = exynos_crtc_handle_event,
Inki Daeb73d1232012-03-21 10:55:26 +0900156};
157
Kees Cooke99e88a2017-10-16 14:43:17 -0700158static void vidi_fake_vblank_timer(struct timer_list *t)
Inki Daeb73d1232012-03-21 10:55:26 +0900159{
Kees Cooke99e88a2017-10-16 14:43:17 -0700160 struct vidi_context *ctx = from_timer(ctx, t, timer);
Inki Daeb73d1232012-03-21 10:55:26 +0900161
Andrzej Hajda8574e922016-09-23 10:15:23 +0200162 if (drm_crtc_handle_vblank(&ctx->crtc->base))
163 mod_timer(&ctx->timer,
164 jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
Inki Daeb73d1232012-03-21 10:55:26 +0900165}
166
Marek Szyprowskic5f2f0c2016-02-03 13:42:47 +0100167static ssize_t vidi_show_connection(struct device *dev,
Inki Daeb73d1232012-03-21 10:55:26 +0900168 struct device_attribute *attr, char *buf)
169{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100170 struct vidi_context *ctx = dev_get_drvdata(dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900171 int rc;
Inki Daeb73d1232012-03-21 10:55:26 +0900172
173 mutex_lock(&ctx->lock);
174
175 rc = sprintf(buf, "%d\n", ctx->connected);
176
177 mutex_unlock(&ctx->lock);
178
179 return rc;
180}
181
Marek Szyprowskic5f2f0c2016-02-03 13:42:47 +0100182static ssize_t vidi_store_connection(struct device *dev,
Inki Daeb73d1232012-03-21 10:55:26 +0900183 struct device_attribute *attr,
184 const char *buf, size_t len)
185{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100186 struct vidi_context *ctx = dev_get_drvdata(dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900187 int ret;
188
Inki Daeb73d1232012-03-21 10:55:26 +0900189 ret = kstrtoint(buf, 0, &ctx->connected);
190 if (ret)
191 return ret;
192
193 if (ctx->connected > 1)
194 return -EINVAL;
195
Inki Daed07d39d2012-06-27 16:00:56 +0900196 /* use fake edid data for test. */
197 if (!ctx->raw_edid)
198 ctx->raw_edid = (struct edid *)fake_edid_info;
199
Inki Daed7b84782012-06-27 16:16:26 +0900200 /* if raw_edid isn't same as fake data then it can't be tested. */
201 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
Inki Dae6be90052019-04-15 16:25:12 +0900202 DRM_DEV_DEBUG_KMS(dev, "edid data is not fake data.\n");
Inki Daed7b84782012-06-27 16:16:26 +0900203 return -EINVAL;
204 }
205
Inki Dae6be90052019-04-15 16:25:12 +0900206 DRM_DEV_DEBUG_KMS(dev, "requested connection.\n");
Inki Daeb73d1232012-03-21 10:55:26 +0900207
Sean Paul080be03d2014-02-19 21:02:55 +0900208 drm_helper_hpd_irq_event(ctx->drm_dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900209
210 return len;
211}
212
213static DEVICE_ATTR(connection, 0644, vidi_show_connection,
214 vidi_store_connection);
215
216int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
217 struct drm_file *file_priv)
218{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900219 struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900220 struct drm_exynos_vidi_connection *vidi = data;
221
Inki Daeb73d1232012-03-21 10:55:26 +0900222 if (!vidi) {
Inki Daedf90a642019-04-15 16:35:08 +0900223 DRM_DEV_DEBUG_KMS(ctx->dev,
Inki Dae6be90052019-04-15 16:25:12 +0900224 "user data for vidi is null.\n");
Inki Daeb73d1232012-03-21 10:55:26 +0900225 return -EINVAL;
226 }
227
Inki Daeb73d1232012-03-21 10:55:26 +0900228 if (vidi->connection > 1) {
Inki Daedf90a642019-04-15 16:35:08 +0900229 DRM_DEV_DEBUG_KMS(ctx->dev,
Inki Dae6be90052019-04-15 16:25:12 +0900230 "connection should be 0 or 1.\n");
Inki Daeb73d1232012-03-21 10:55:26 +0900231 return -EINVAL;
232 }
233
Inki Daeb73d1232012-03-21 10:55:26 +0900234 if (ctx->connected == vidi->connection) {
Inki Daedf90a642019-04-15 16:35:08 +0900235 DRM_DEV_DEBUG_KMS(ctx->dev,
Inki Dae6be90052019-04-15 16:25:12 +0900236 "same connection request.\n");
Inki Daeb73d1232012-03-21 10:55:26 +0900237 return -EINVAL;
238 }
239
Inki Daed3b62db2012-06-27 16:36:12 +0900240 if (vidi->connection) {
Marek Szyprowskic5f2f0c2016-02-03 13:42:47 +0100241 struct edid *raw_edid;
242
243 raw_edid = (struct edid *)(unsigned long)vidi->edid;
Seung-Woo Kime7808df2013-01-10 19:35:06 +0900244 if (!drm_edid_is_valid(raw_edid)) {
Inki Daedf90a642019-04-15 16:35:08 +0900245 DRM_DEV_DEBUG_KMS(ctx->dev,
Inki Dae6be90052019-04-15 16:25:12 +0900246 "edid data is invalid.\n");
Inki Daed3b62db2012-06-27 16:36:12 +0900247 return -EINVAL;
248 }
Jani Nikula4ddc7732013-09-27 15:08:29 +0300249 ctx->raw_edid = drm_edid_duplicate(raw_edid);
Inki Daed3b62db2012-06-27 16:36:12 +0900250 if (!ctx->raw_edid) {
Inki Daedf90a642019-04-15 16:35:08 +0900251 DRM_DEV_DEBUG_KMS(ctx->dev,
Inki Dae6be90052019-04-15 16:25:12 +0900252 "failed to allocate raw_edid.\n");
Inki Daed3b62db2012-06-27 16:36:12 +0900253 return -ENOMEM;
254 }
Inki Daed3b62db2012-06-27 16:36:12 +0900255 } else {
256 /*
257 * with connection = 0, free raw_edid
258 * only if raw edid data isn't same as fake data.
259 */
260 if (ctx->raw_edid && ctx->raw_edid !=
261 (struct edid *)fake_edid_info) {
262 kfree(ctx->raw_edid);
263 ctx->raw_edid = NULL;
264 }
265 }
Inki Daeb73d1232012-03-21 10:55:26 +0900266
267 ctx->connected = vidi->connection;
Sean Paul080be03d2014-02-19 21:02:55 +0900268 drm_helper_hpd_irq_event(ctx->drm_dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900269
270 return 0;
271}
272
Sean Paulce6cb552014-01-30 16:38:07 -0500273static enum drm_connector_status vidi_detect(struct drm_connector *connector,
274 bool force)
275{
276 struct vidi_context *ctx = ctx_from_connector(connector);
277
278 /*
279 * connection request would come from user side
280 * to do hotplug through specific ioctl.
281 */
282 return ctx->connected ? connector_status_connected :
283 connector_status_disconnected;
284}
285
286static void vidi_connector_destroy(struct drm_connector *connector)
287{
288}
289
Ville Syrjälä800ba2b2015-12-15 12:21:06 +0100290static const struct drm_connector_funcs vidi_connector_funcs = {
Sean Paulce6cb552014-01-30 16:38:07 -0500291 .fill_modes = drm_helper_probe_single_connector_modes,
292 .detect = vidi_detect,
293 .destroy = vidi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300294 .reset = drm_atomic_helper_connector_reset,
295 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
296 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Paulce6cb552014-01-30 16:38:07 -0500297};
298
299static int vidi_get_modes(struct drm_connector *connector)
300{
301 struct vidi_context *ctx = ctx_from_connector(connector);
302 struct edid *edid;
303 int edid_len;
304
305 /*
306 * the edid data comes from user side and it would be set
307 * to ctx->raw_edid through specific ioctl.
308 */
309 if (!ctx->raw_edid) {
Inki Daedf90a642019-04-15 16:35:08 +0900310 DRM_DEV_DEBUG_KMS(ctx->dev, "raw_edid is null.\n");
Sean Paulce6cb552014-01-30 16:38:07 -0500311 return -EFAULT;
312 }
313
314 edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
315 edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
316 if (!edid) {
Inki Daedf90a642019-04-15 16:35:08 +0900317 DRM_DEV_DEBUG_KMS(ctx->dev, "failed to allocate edid\n");
Sean Paulce6cb552014-01-30 16:38:07 -0500318 return -ENOMEM;
319 }
320
Daniel Vetterc555f022018-07-09 10:40:06 +0200321 drm_connector_update_edid_property(connector, edid);
Sean Paulce6cb552014-01-30 16:38:07 -0500322
323 return drm_add_edid_modes(connector, edid);
324}
325
Ville Syrjälä800ba2b2015-12-15 12:21:06 +0100326static const struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
Sean Paulce6cb552014-01-30 16:38:07 -0500327 .get_modes = vidi_get_modes,
Sean Paulce6cb552014-01-30 16:38:07 -0500328};
329
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300330static int vidi_create_connector(struct drm_encoder *encoder)
Sean Paulce6cb552014-01-30 16:38:07 -0500331{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300332 struct vidi_context *ctx = encoder_to_vidi(encoder);
Sean Paulce6cb552014-01-30 16:38:07 -0500333 struct drm_connector *connector = &ctx->connector;
334 int ret;
335
Sean Paulce6cb552014-01-30 16:38:07 -0500336 connector->polled = DRM_CONNECTOR_POLL_HPD;
337
338 ret = drm_connector_init(ctx->drm_dev, connector,
339 &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
340 if (ret) {
Inki Daedf90a642019-04-15 16:35:08 +0900341 DRM_DEV_ERROR(ctx->dev,
Inki Dae6f83d202019-04-15 14:24:36 +0900342 "Failed to initialize connector with drm\n");
Sean Paulce6cb552014-01-30 16:38:07 -0500343 return ret;
344 }
345
346 drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
Daniel Vettercde4c442018-07-09 10:40:07 +0200347 drm_connector_attach_encoder(connector, encoder);
Sean Paulce6cb552014-01-30 16:38:07 -0500348
349 return 0;
350}
351
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300352static void exynos_vidi_mode_set(struct drm_encoder *encoder,
353 struct drm_display_mode *mode,
354 struct drm_display_mode *adjusted_mode)
355{
356}
357
358static void exynos_vidi_enable(struct drm_encoder *encoder)
359{
360}
361
362static void exynos_vidi_disable(struct drm_encoder *encoder)
363{
364}
365
Ville Syrjälä800ba2b2015-12-15 12:21:06 +0100366static const struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300367 .mode_set = exynos_vidi_mode_set,
368 .enable = exynos_vidi_enable,
369 .disable = exynos_vidi_disable,
370};
371
Ville Syrjälä800ba2b2015-12-15 12:21:06 +0100372static const struct drm_encoder_funcs exynos_vidi_encoder_funcs = {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300373 .destroy = drm_encoder_cleanup,
374};
375
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900376static int vidi_bind(struct device *dev, struct device *master, void *data)
Inki Daef37cd5e2014-05-09 14:25:20 +0900377{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100378 struct vidi_context *ctx = dev_get_drvdata(dev);
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900379 struct drm_device *drm_dev = data;
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300380 struct drm_encoder *encoder = &ctx->encoder;
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900381 struct exynos_drm_plane *exynos_plane;
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100382 struct exynos_drm_plane_config plane_config = { 0 };
383 unsigned int i;
Andrzej Hajda1ca582f2017-08-24 15:33:51 +0200384 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900385
Andrzej Hajda29493902017-03-15 15:41:06 +0100386 ctx->drm_dev = drm_dev;
Joonyoung Shim0f04cf82015-01-30 16:43:01 +0900387
Marek Szyprowskifd2d2fc2015-11-30 14:53:25 +0100388 plane_config.pixel_formats = formats;
389 plane_config.num_pixel_formats = ARRAY_SIZE(formats);
390
391 for (i = 0; i < WINDOWS_NR; i++) {
392 plane_config.zpos = i;
393 plane_config.type = vidi_win_types[i];
394
Marek Szyprowski40bdfb02015-12-16 13:21:42 +0100395 ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
Andrzej Hajda2c826072017-03-15 15:41:05 +0100396 &plane_config);
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900397 if (ret)
398 return ret;
399 }
400
Gustavo Padovan5d3d0992015-10-12 22:07:48 +0900401 exynos_plane = &ctx->planes[DEFAULT_WIN];
Gustavo Padovan7ee14cd2015-04-03 21:03:40 +0900402 ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
Andrzej Hajdad6449512017-05-29 10:05:25 +0900403 EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx);
Gustavo Padovan93bca242015-01-18 18:16:23 +0900404 if (IS_ERR(ctx->crtc)) {
Inki Dae6f83d202019-04-15 14:24:36 +0900405 DRM_DEV_ERROR(dev, "failed to create crtc.\n");
Gustavo Padovan93bca242015-01-18 18:16:23 +0900406 return PTR_ERR(ctx->crtc);
Inki Daef37cd5e2014-05-09 14:25:20 +0900407 }
408
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300409 drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
Ville Syrjälä13a3d912015-12-09 16:20:18 +0200410 DRM_MODE_ENCODER_TMDS, NULL);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300411
412 drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
413
Andrzej Hajda1ca582f2017-08-24 15:33:51 +0200414 ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_VIDI);
415 if (ret < 0)
416 return ret;
417
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300418 ret = vidi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -0300419 if (ret) {
Inki Dae6f83d202019-04-15 14:24:36 +0900420 DRM_DEV_ERROR(dev, "failed to create connector ret = %d\n",
421 ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300422 drm_encoder_cleanup(encoder);
Inki Daef37cd5e2014-05-09 14:25:20 +0900423 return ret;
424 }
425
426 return 0;
427}
428
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900429
430static void vidi_unbind(struct device *dev, struct device *master, void *data)
431{
Andrzej Hajda8574e922016-09-23 10:15:23 +0200432 struct vidi_context *ctx = dev_get_drvdata(dev);
433
434 del_timer_sync(&ctx->timer);
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900435}
436
437static const struct component_ops vidi_component_ops = {
438 .bind = vidi_bind,
439 .unbind = vidi_unbind,
440};
441
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -0800442static int vidi_probe(struct platform_device *pdev)
Inki Daeb73d1232012-03-21 10:55:26 +0900443{
Inki Daeb73d1232012-03-21 10:55:26 +0900444 struct vidi_context *ctx;
Inki Daedf90a642019-04-15 16:35:08 +0900445 struct device *dev = &pdev->dev;
Inki Daeb73d1232012-03-21 10:55:26 +0900446 int ret;
447
Inki Daedf90a642019-04-15 16:35:08 +0900448 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
Inki Daeb73d1232012-03-21 10:55:26 +0900449 if (!ctx)
450 return -ENOMEM;
451
Inki Daedf90a642019-04-15 16:35:08 +0900452 ctx->dev = dev;
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900453
Kees Cooke99e88a2017-10-16 14:43:17 -0700454 timer_setup(&ctx->timer, vidi_fake_vblank_timer, 0);
Inki Daeb73d1232012-03-21 10:55:26 +0900455
Inki Daeb73d1232012-03-21 10:55:26 +0900456 mutex_init(&ctx->lock);
457
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100458 platform_set_drvdata(pdev, ctx);
Inki Daeb73d1232012-03-21 10:55:26 +0900459
Inki Daedf90a642019-04-15 16:35:08 +0900460 ret = device_create_file(dev, &dev_attr_connection);
Inki Daef37cd5e2014-05-09 14:25:20 +0900461 if (ret < 0) {
Inki Daedf90a642019-04-15 16:35:08 +0900462 DRM_DEV_ERROR(dev,
Inki Dae6f83d202019-04-15 14:24:36 +0900463 "failed to create connection sysfs.\n");
Andrzej Hajda86650402015-06-11 23:23:37 +0900464 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900465 }
Inki Daeb73d1232012-03-21 10:55:26 +0900466
Inki Daedf90a642019-04-15 16:35:08 +0900467 ret = component_add(dev, &vidi_component_ops);
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900468 if (ret)
469 goto err_remove_file;
470
471 return ret;
472
473err_remove_file:
Inki Daedf90a642019-04-15 16:35:08 +0900474 device_remove_file(dev, &dev_attr_connection);
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900475
476 return ret;
Inki Daeb73d1232012-03-21 10:55:26 +0900477}
478
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -0800479static int vidi_remove(struct platform_device *pdev)
Inki Daeb73d1232012-03-21 10:55:26 +0900480{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100481 struct vidi_context *ctx = platform_get_drvdata(pdev);
Inki Daeb73d1232012-03-21 10:55:26 +0900482
Inki Daed3b62db2012-06-27 16:36:12 +0900483 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
484 kfree(ctx->raw_edid);
485 ctx->raw_edid = NULL;
Inki Daef37cd5e2014-05-09 14:25:20 +0900486
487 return -EINVAL;
Inki Daed3b62db2012-06-27 16:36:12 +0900488 }
489
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900490 component_del(&pdev->dev, &vidi_component_ops);
Inki Dae1d50aa9c2014-11-24 14:55:41 +0900491
Inki Daeb73d1232012-03-21 10:55:26 +0900492 return 0;
493}
494
Inki Daeb73d1232012-03-21 10:55:26 +0900495struct platform_driver vidi_driver = {
496 .probe = vidi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -0800497 .remove = vidi_remove,
Inki Daeb73d1232012-03-21 10:55:26 +0900498 .driver = {
499 .name = "exynos-drm-vidi",
500 .owner = THIS_MODULE,
Inki Daeb73d1232012-03-21 10:55:26 +0900501 },
502};