Version:  2.0.40 2.2.26 2.4.37 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19

Linux/drivers/gpu/drm/exynos/exynos_drm_vidi.c

  1 /* exynos_drm_vidi.c
  2  *
  3  * Copyright (C) 2012 Samsung Electronics Co.Ltd
  4  * Authors:
  5  *      Inki Dae <inki.dae@samsung.com>
  6  *
  7  * This program is free software; you can redistribute  it and/or modify it
  8  * under  the terms of  the GNU General  Public License as published by the
  9  * Free Software Foundation;  either version 2 of the  License, or (at your
 10  * option) any later version.
 11  *
 12  */
 13 #include <drm/drmP.h>
 14 
 15 #include <linux/kernel.h>
 16 #include <linux/platform_device.h>
 17 #include <linux/component.h>
 18 
 19 #include <drm/exynos_drm.h>
 20 
 21 #include <drm/drm_edid.h>
 22 #include <drm/drm_crtc_helper.h>
 23 
 24 #include "exynos_drm_drv.h"
 25 #include "exynos_drm_crtc.h"
 26 #include "exynos_drm_encoder.h"
 27 #include "exynos_drm_vidi.h"
 28 
 29 /* vidi has totally three virtual windows. */
 30 #define WINDOWS_NR              3
 31 
 32 #define ctx_from_connector(c)   container_of(c, struct vidi_context, \
 33                                         connector)
 34 
 35 struct vidi_win_data {
 36         unsigned int            offset_x;
 37         unsigned int            offset_y;
 38         unsigned int            ovl_width;
 39         unsigned int            ovl_height;
 40         unsigned int            fb_width;
 41         unsigned int            fb_height;
 42         unsigned int            bpp;
 43         dma_addr_t              dma_addr;
 44         unsigned int            buf_offsize;
 45         unsigned int            line_size;      /* bytes */
 46         bool                    enabled;
 47 };
 48 
 49 struct vidi_context {
 50         struct exynos_drm_manager       manager;
 51         struct exynos_drm_display       display;
 52         struct platform_device          *pdev;
 53         struct drm_device               *drm_dev;
 54         struct drm_crtc                 *crtc;
 55         struct drm_encoder              *encoder;
 56         struct drm_connector            connector;
 57         struct vidi_win_data            win_data[WINDOWS_NR];
 58         struct edid                     *raw_edid;
 59         unsigned int                    clkdiv;
 60         unsigned int                    default_win;
 61         unsigned long                   irq_flags;
 62         unsigned int                    connected;
 63         bool                            vblank_on;
 64         bool                            suspended;
 65         bool                            direct_vblank;
 66         struct work_struct              work;
 67         struct mutex                    lock;
 68         int                             pipe;
 69 };
 70 
 71 static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
 72 {
 73         return container_of(m, struct vidi_context, manager);
 74 }
 75 
 76 static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
 77 {
 78         return container_of(d, struct vidi_context, display);
 79 }
 80 
 81 static const char fake_edid_info[] = {
 82         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
 83         0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
 84         0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
 85         0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 86         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
 87         0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
 88         0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
 89         0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
 90         0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 91         0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
 92         0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
 93         0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
 94         0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
 95         0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
 96         0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
 97         0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
 98         0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
 99         0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
100         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103         0x00, 0x00, 0x00, 0x06
104 };
105 
106 static void vidi_apply(struct exynos_drm_manager *mgr)
107 {
108         struct vidi_context *ctx = manager_to_vidi(mgr);
109         struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
110         struct vidi_win_data *win_data;
111         int i;
112 
113         for (i = 0; i < WINDOWS_NR; i++) {
114                 win_data = &ctx->win_data[i];
115                 if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
116                         mgr_ops->win_commit(mgr, i);
117         }
118 
119         if (mgr_ops && mgr_ops->commit)
120                 mgr_ops->commit(mgr);
121 }
122 
123 static void vidi_commit(struct exynos_drm_manager *mgr)
124 {
125         struct vidi_context *ctx = manager_to_vidi(mgr);
126 
127         if (ctx->suspended)
128                 return;
129 }
130 
131 static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
132 {
133         struct vidi_context *ctx = manager_to_vidi(mgr);
134 
135         if (ctx->suspended)
136                 return -EPERM;
137 
138         if (!test_and_set_bit(0, &ctx->irq_flags))
139                 ctx->vblank_on = true;
140 
141         ctx->direct_vblank = true;
142 
143         /*
144          * in case of page flip request, vidi_finish_pageflip function
145          * will not be called because direct_vblank is true and then
146          * that function will be called by manager_ops->win_commit callback
147          */
148         schedule_work(&ctx->work);
149 
150         return 0;
151 }
152 
153 static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
154 {
155         struct vidi_context *ctx = manager_to_vidi(mgr);
156 
157         if (ctx->suspended)
158                 return;
159 
160         if (test_and_clear_bit(0, &ctx->irq_flags))
161                 ctx->vblank_on = false;
162 }
163 
164 static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
165                         struct exynos_drm_overlay *overlay)
166 {
167         struct vidi_context *ctx = manager_to_vidi(mgr);
168         struct vidi_win_data *win_data;
169         int win;
170         unsigned long offset;
171 
172         if (!overlay) {
173                 DRM_ERROR("overlay is NULL\n");
174                 return;
175         }
176 
177         win = overlay->zpos;
178         if (win == DEFAULT_ZPOS)
179                 win = ctx->default_win;
180 
181         if (win < 0 || win >= WINDOWS_NR)
182                 return;
183 
184         offset = overlay->fb_x * (overlay->bpp >> 3);
185         offset += overlay->fb_y * overlay->pitch;
186 
187         DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
188 
189         win_data = &ctx->win_data[win];
190 
191         win_data->offset_x = overlay->crtc_x;
192         win_data->offset_y = overlay->crtc_y;
193         win_data->ovl_width = overlay->crtc_width;
194         win_data->ovl_height = overlay->crtc_height;
195         win_data->fb_width = overlay->fb_width;
196         win_data->fb_height = overlay->fb_height;
197         win_data->dma_addr = overlay->dma_addr[0] + offset;
198         win_data->bpp = overlay->bpp;
199         win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
200                                 (overlay->bpp >> 3);
201         win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
202 
203         /*
204          * some parts of win_data should be transferred to user side
205          * through specific ioctl.
206          */
207 
208         DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
209                         win_data->offset_x, win_data->offset_y);
210         DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
211                         win_data->ovl_width, win_data->ovl_height);
212         DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
213         DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
214                         overlay->fb_width, overlay->crtc_width);
215 }
216 
217 static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
218 {
219         struct vidi_context *ctx = manager_to_vidi(mgr);
220         struct vidi_win_data *win_data;
221         int win = zpos;
222 
223         if (ctx->suspended)
224                 return;
225 
226         if (win == DEFAULT_ZPOS)
227                 win = ctx->default_win;
228 
229         if (win < 0 || win >= WINDOWS_NR)
230                 return;
231 
232         win_data = &ctx->win_data[win];
233 
234         win_data->enabled = true;
235 
236         DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
237 
238         if (ctx->vblank_on)
239                 schedule_work(&ctx->work);
240 }
241 
242 static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
243 {
244         struct vidi_context *ctx = manager_to_vidi(mgr);
245         struct vidi_win_data *win_data;
246         int win = zpos;
247 
248         if (win == DEFAULT_ZPOS)
249                 win = ctx->default_win;
250 
251         if (win < 0 || win >= WINDOWS_NR)
252                 return;
253 
254         win_data = &ctx->win_data[win];
255         win_data->enabled = false;
256 
257         /* TODO. */
258 }
259 
260 static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
261 {
262         struct vidi_context *ctx = manager_to_vidi(mgr);
263 
264         DRM_DEBUG_KMS("%s\n", __FILE__);
265 
266         if (enable != false && enable != true)
267                 return -EINVAL;
268 
269         if (enable) {
270                 ctx->suspended = false;
271 
272                 /* if vblank was enabled status, enable it again. */
273                 if (test_and_clear_bit(0, &ctx->irq_flags))
274                         vidi_enable_vblank(mgr);
275 
276                 vidi_apply(mgr);
277         } else {
278                 ctx->suspended = true;
279         }
280 
281         return 0;
282 }
283 
284 static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
285 {
286         struct vidi_context *ctx = manager_to_vidi(mgr);
287 
288         DRM_DEBUG_KMS("%d\n", mode);
289 
290         mutex_lock(&ctx->lock);
291 
292         switch (mode) {
293         case DRM_MODE_DPMS_ON:
294                 vidi_power_on(mgr, true);
295                 break;
296         case DRM_MODE_DPMS_STANDBY:
297         case DRM_MODE_DPMS_SUSPEND:
298         case DRM_MODE_DPMS_OFF:
299                 vidi_power_on(mgr, false);
300                 break;
301         default:
302                 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
303                 break;
304         }
305 
306         mutex_unlock(&ctx->lock);
307 }
308 
309 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
310                         struct drm_device *drm_dev)
311 {
312         struct vidi_context *ctx = manager_to_vidi(mgr);
313         struct exynos_drm_private *priv = drm_dev->dev_private;
314 
315         mgr->drm_dev = ctx->drm_dev = drm_dev;
316         mgr->pipe = ctx->pipe = priv->pipe++;
317 
318         return 0;
319 }
320 
321 static struct exynos_drm_manager_ops vidi_manager_ops = {
322         .dpms = vidi_dpms,
323         .commit = vidi_commit,
324         .enable_vblank = vidi_enable_vblank,
325         .disable_vblank = vidi_disable_vblank,
326         .win_mode_set = vidi_win_mode_set,
327         .win_commit = vidi_win_commit,
328         .win_disable = vidi_win_disable,
329 };
330 
331 static void vidi_fake_vblank_handler(struct work_struct *work)
332 {
333         struct vidi_context *ctx = container_of(work, struct vidi_context,
334                                         work);
335 
336         if (ctx->pipe < 0)
337                 return;
338 
339         /* refresh rate is about 50Hz. */
340         usleep_range(16000, 20000);
341 
342         mutex_lock(&ctx->lock);
343 
344         if (ctx->direct_vblank) {
345                 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
346                 ctx->direct_vblank = false;
347                 mutex_unlock(&ctx->lock);
348                 return;
349         }
350 
351         mutex_unlock(&ctx->lock);
352 
353         exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
354 }
355 
356 static int vidi_show_connection(struct device *dev,
357                                 struct device_attribute *attr, char *buf)
358 {
359         struct vidi_context *ctx = dev_get_drvdata(dev);
360         int rc;
361 
362         mutex_lock(&ctx->lock);
363 
364         rc = sprintf(buf, "%d\n", ctx->connected);
365 
366         mutex_unlock(&ctx->lock);
367 
368         return rc;
369 }
370 
371 static int vidi_store_connection(struct device *dev,
372                                 struct device_attribute *attr,
373                                 const char *buf, size_t len)
374 {
375         struct vidi_context *ctx = dev_get_drvdata(dev);
376         int ret;
377 
378         ret = kstrtoint(buf, 0, &ctx->connected);
379         if (ret)
380                 return ret;
381 
382         if (ctx->connected > 1)
383                 return -EINVAL;
384 
385         /* use fake edid data for test. */
386         if (!ctx->raw_edid)
387                 ctx->raw_edid = (struct edid *)fake_edid_info;
388 
389         /* if raw_edid isn't same as fake data then it can't be tested. */
390         if (ctx->raw_edid != (struct edid *)fake_edid_info) {
391                 DRM_DEBUG_KMS("edid data is not fake data.\n");
392                 return -EINVAL;
393         }
394 
395         DRM_DEBUG_KMS("requested connection.\n");
396 
397         drm_helper_hpd_irq_event(ctx->drm_dev);
398 
399         return len;
400 }
401 
402 static DEVICE_ATTR(connection, 0644, vidi_show_connection,
403                         vidi_store_connection);
404 
405 int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
406                                 struct drm_file *file_priv)
407 {
408         struct vidi_context *ctx = NULL;
409         struct drm_encoder *encoder;
410         struct exynos_drm_display *display;
411         struct drm_exynos_vidi_connection *vidi = data;
412 
413         if (!vidi) {
414                 DRM_DEBUG_KMS("user data for vidi is null.\n");
415                 return -EINVAL;
416         }
417 
418         if (vidi->connection > 1) {
419                 DRM_DEBUG_KMS("connection should be 0 or 1.\n");
420                 return -EINVAL;
421         }
422 
423         list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
424                                                                 head) {
425                 display = exynos_drm_get_display(encoder);
426 
427                 if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
428                         ctx = display_to_vidi(display);
429                         break;
430                 }
431         }
432 
433         if (!ctx) {
434                 DRM_DEBUG_KMS("not found virtual device type encoder.\n");
435                 return -EINVAL;
436         }
437 
438         if (ctx->connected == vidi->connection) {
439                 DRM_DEBUG_KMS("same connection request.\n");
440                 return -EINVAL;
441         }
442 
443         if (vidi->connection) {
444                 struct edid *raw_edid  = (struct edid *)(uint32_t)vidi->edid;
445                 if (!drm_edid_is_valid(raw_edid)) {
446                         DRM_DEBUG_KMS("edid data is invalid.\n");
447                         return -EINVAL;
448                 }
449                 ctx->raw_edid = drm_edid_duplicate(raw_edid);
450                 if (!ctx->raw_edid) {
451                         DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
452                         return -ENOMEM;
453                 }
454         } else {
455                 /*
456                  * with connection = 0, free raw_edid
457                  * only if raw edid data isn't same as fake data.
458                  */
459                 if (ctx->raw_edid && ctx->raw_edid !=
460                                 (struct edid *)fake_edid_info) {
461                         kfree(ctx->raw_edid);
462                         ctx->raw_edid = NULL;
463                 }
464         }
465 
466         ctx->connected = vidi->connection;
467         drm_helper_hpd_irq_event(ctx->drm_dev);
468 
469         return 0;
470 }
471 
472 static enum drm_connector_status vidi_detect(struct drm_connector *connector,
473                         bool force)
474 {
475         struct vidi_context *ctx = ctx_from_connector(connector);
476 
477         /*
478          * connection request would come from user side
479          * to do hotplug through specific ioctl.
480          */
481         return ctx->connected ? connector_status_connected :
482                         connector_status_disconnected;
483 }
484 
485 static void vidi_connector_destroy(struct drm_connector *connector)
486 {
487 }
488 
489 static struct drm_connector_funcs vidi_connector_funcs = {
490         .dpms = drm_helper_connector_dpms,
491         .fill_modes = drm_helper_probe_single_connector_modes,
492         .detect = vidi_detect,
493         .destroy = vidi_connector_destroy,
494 };
495 
496 static int vidi_get_modes(struct drm_connector *connector)
497 {
498         struct vidi_context *ctx = ctx_from_connector(connector);
499         struct edid *edid;
500         int edid_len;
501 
502         /*
503          * the edid data comes from user side and it would be set
504          * to ctx->raw_edid through specific ioctl.
505          */
506         if (!ctx->raw_edid) {
507                 DRM_DEBUG_KMS("raw_edid is null.\n");
508                 return -EFAULT;
509         }
510 
511         edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
512         edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
513         if (!edid) {
514                 DRM_DEBUG_KMS("failed to allocate edid\n");
515                 return -ENOMEM;
516         }
517 
518         drm_mode_connector_update_edid_property(connector, edid);
519 
520         return drm_add_edid_modes(connector, edid);
521 }
522 
523 static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
524 {
525         struct vidi_context *ctx = ctx_from_connector(connector);
526 
527         return ctx->encoder;
528 }
529 
530 static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
531         .get_modes = vidi_get_modes,
532         .best_encoder = vidi_best_encoder,
533 };
534 
535 static int vidi_create_connector(struct exynos_drm_display *display,
536                                 struct drm_encoder *encoder)
537 {
538         struct vidi_context *ctx = display_to_vidi(display);
539         struct drm_connector *connector = &ctx->connector;
540         int ret;
541 
542         ctx->encoder = encoder;
543         connector->polled = DRM_CONNECTOR_POLL_HPD;
544 
545         ret = drm_connector_init(ctx->drm_dev, connector,
546                         &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
547         if (ret) {
548                 DRM_ERROR("Failed to initialize connector with drm\n");
549                 return ret;
550         }
551 
552         drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
553         drm_connector_register(connector);
554         drm_mode_connector_attach_encoder(connector, encoder);
555 
556         return 0;
557 }
558 
559 
560 static struct exynos_drm_display_ops vidi_display_ops = {
561         .create_connector = vidi_create_connector,
562 };
563 
564 static int vidi_bind(struct device *dev, struct device *master, void *data)
565 {
566         struct vidi_context *ctx = dev_get_drvdata(dev);
567         struct drm_device *drm_dev = data;
568         struct drm_crtc *crtc = ctx->crtc;
569         int ret;
570 
571         vidi_mgr_initialize(&ctx->manager, drm_dev);
572 
573         ret = exynos_drm_crtc_create(&ctx->manager);
574         if (ret) {
575                 DRM_ERROR("failed to create crtc.\n");
576                 return ret;
577         }
578 
579         ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
580         if (ret) {
581                 crtc->funcs->destroy(crtc);
582                 DRM_ERROR("failed to create encoder and connector.\n");
583                 return ret;
584         }
585 
586         return 0;
587 }
588 
589 
590 static void vidi_unbind(struct device *dev, struct device *master, void *data)
591 {
592 }
593 
594 static const struct component_ops vidi_component_ops = {
595         .bind   = vidi_bind,
596         .unbind = vidi_unbind,
597 };
598 
599 static int vidi_probe(struct platform_device *pdev)
600 {
601         struct vidi_context *ctx;
602         int ret;
603 
604         ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
605         if (!ctx)
606                 return -ENOMEM;
607 
608         ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
609         ctx->manager.ops = &vidi_manager_ops;
610         ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
611         ctx->display.ops = &vidi_display_ops;
612         ctx->default_win = 0;
613         ctx->pdev = pdev;
614 
615         ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
616                                         ctx->manager.type);
617         if (ret)
618                 return ret;
619 
620         ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
621                                         ctx->display.type);
622         if (ret)
623                 goto err_del_crtc_component;
624 
625         INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
626 
627         mutex_init(&ctx->lock);
628 
629         platform_set_drvdata(pdev, ctx);
630 
631         ret = device_create_file(&pdev->dev, &dev_attr_connection);
632         if (ret < 0) {
633                 DRM_ERROR("failed to create connection sysfs.\n");
634                 goto err_del_conn_component;
635         }
636 
637         ret = component_add(&pdev->dev, &vidi_component_ops);
638         if (ret)
639                 goto err_remove_file;
640 
641         return ret;
642 
643 err_remove_file:
644         device_remove_file(&pdev->dev, &dev_attr_connection);
645 err_del_conn_component:
646         exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
647 err_del_crtc_component:
648         exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
649 
650         return ret;
651 }
652 
653 static int vidi_remove(struct platform_device *pdev)
654 {
655         struct vidi_context *ctx = platform_get_drvdata(pdev);
656 
657         if (ctx->raw_edid != (struct edid *)fake_edid_info) {
658                 kfree(ctx->raw_edid);
659                 ctx->raw_edid = NULL;
660 
661                 return -EINVAL;
662         }
663 
664         component_del(&pdev->dev, &vidi_component_ops);
665         exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
666         exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
667 
668         return 0;
669 }
670 
671 struct platform_driver vidi_driver = {
672         .probe          = vidi_probe,
673         .remove         = vidi_remove,
674         .driver         = {
675                 .name   = "exynos-drm-vidi",
676                 .owner  = THIS_MODULE,
677         },
678 };
679 
680 int exynos_drm_probe_vidi(void)
681 {
682         struct platform_device *pdev;
683         int ret;
684 
685         pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
686         if (IS_ERR(pdev))
687                 return PTR_ERR(pdev);
688 
689         ret = platform_driver_register(&vidi_driver);
690         if (ret) {
691                 platform_device_unregister(pdev);
692                 return ret;
693         }
694 
695         return ret;
696 }
697 
698 static int exynos_drm_remove_vidi_device(struct device *dev, void *data)
699 {
700         platform_device_unregister(to_platform_device(dev));
701 
702         return 0;
703 }
704 
705 void exynos_drm_remove_vidi(void)
706 {
707         int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL,
708                                          exynos_drm_remove_vidi_device);
709         /* silence compiler warning */
710         (void)ret;
711 
712         platform_driver_unregister(&vidi_driver);
713 }
714 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us