diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_vidi.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_vidi.c | 150 |
1 files changed, 92 insertions, 58 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 50faf913e574..45899fb63272 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/component.h> | ||
17 | 18 | ||
18 | #include <drm/exynos_drm.h> | 19 | #include <drm/exynos_drm.h> |
19 | 20 | ||
@@ -28,7 +29,6 @@ | |||
28 | /* vidi has totally three virtual windows. */ | 29 | /* vidi has totally three virtual windows. */ |
29 | #define WINDOWS_NR 3 | 30 | #define WINDOWS_NR 3 |
30 | 31 | ||
31 | #define get_vidi_mgr(dev) platform_get_drvdata(to_platform_device(dev)) | ||
32 | #define ctx_from_connector(c) container_of(c, struct vidi_context, \ | 32 | #define ctx_from_connector(c) container_of(c, struct vidi_context, \ |
33 | connector) | 33 | connector) |
34 | 34 | ||
@@ -47,11 +47,13 @@ struct vidi_win_data { | |||
47 | }; | 47 | }; |
48 | 48 | ||
49 | struct vidi_context { | 49 | struct vidi_context { |
50 | struct exynos_drm_manager manager; | ||
51 | struct exynos_drm_display display; | ||
52 | struct platform_device *pdev; | ||
50 | struct drm_device *drm_dev; | 53 | struct drm_device *drm_dev; |
51 | struct drm_crtc *crtc; | 54 | struct drm_crtc *crtc; |
52 | struct drm_encoder *encoder; | 55 | struct drm_encoder *encoder; |
53 | struct drm_connector connector; | 56 | struct drm_connector connector; |
54 | struct exynos_drm_subdrv subdrv; | ||
55 | struct vidi_win_data win_data[WINDOWS_NR]; | 57 | struct vidi_win_data win_data[WINDOWS_NR]; |
56 | struct edid *raw_edid; | 58 | struct edid *raw_edid; |
57 | unsigned int clkdiv; | 59 | unsigned int clkdiv; |
@@ -66,6 +68,16 @@ struct vidi_context { | |||
66 | int pipe; | 68 | int pipe; |
67 | }; | 69 | }; |
68 | 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 | |||
69 | static const char fake_edid_info[] = { | 81 | static const char fake_edid_info[] = { |
70 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05, | 82 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05, |
71 | 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, | 83 | 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, |
@@ -93,7 +105,7 @@ static const char fake_edid_info[] = { | |||
93 | 105 | ||
94 | static void vidi_apply(struct exynos_drm_manager *mgr) | 106 | static void vidi_apply(struct exynos_drm_manager *mgr) |
95 | { | 107 | { |
96 | struct vidi_context *ctx = mgr->ctx; | 108 | struct vidi_context *ctx = manager_to_vidi(mgr); |
97 | struct exynos_drm_manager_ops *mgr_ops = mgr->ops; | 109 | struct exynos_drm_manager_ops *mgr_ops = mgr->ops; |
98 | struct vidi_win_data *win_data; | 110 | struct vidi_win_data *win_data; |
99 | int i; | 111 | int i; |
@@ -110,7 +122,7 @@ static void vidi_apply(struct exynos_drm_manager *mgr) | |||
110 | 122 | ||
111 | static void vidi_commit(struct exynos_drm_manager *mgr) | 123 | static void vidi_commit(struct exynos_drm_manager *mgr) |
112 | { | 124 | { |
113 | struct vidi_context *ctx = mgr->ctx; | 125 | struct vidi_context *ctx = manager_to_vidi(mgr); |
114 | 126 | ||
115 | if (ctx->suspended) | 127 | if (ctx->suspended) |
116 | return; | 128 | return; |
@@ -118,7 +130,7 @@ static void vidi_commit(struct exynos_drm_manager *mgr) | |||
118 | 130 | ||
119 | static int vidi_enable_vblank(struct exynos_drm_manager *mgr) | 131 | static int vidi_enable_vblank(struct exynos_drm_manager *mgr) |
120 | { | 132 | { |
121 | struct vidi_context *ctx = mgr->ctx; | 133 | struct vidi_context *ctx = manager_to_vidi(mgr); |
122 | 134 | ||
123 | if (ctx->suspended) | 135 | if (ctx->suspended) |
124 | return -EPERM; | 136 | return -EPERM; |
@@ -140,7 +152,7 @@ static int vidi_enable_vblank(struct exynos_drm_manager *mgr) | |||
140 | 152 | ||
141 | static void vidi_disable_vblank(struct exynos_drm_manager *mgr) | 153 | static void vidi_disable_vblank(struct exynos_drm_manager *mgr) |
142 | { | 154 | { |
143 | struct vidi_context *ctx = mgr->ctx; | 155 | struct vidi_context *ctx = manager_to_vidi(mgr); |
144 | 156 | ||
145 | if (ctx->suspended) | 157 | if (ctx->suspended) |
146 | return; | 158 | return; |
@@ -152,7 +164,7 @@ static void vidi_disable_vblank(struct exynos_drm_manager *mgr) | |||
152 | static void vidi_win_mode_set(struct exynos_drm_manager *mgr, | 164 | static void vidi_win_mode_set(struct exynos_drm_manager *mgr, |
153 | struct exynos_drm_overlay *overlay) | 165 | struct exynos_drm_overlay *overlay) |
154 | { | 166 | { |
155 | struct vidi_context *ctx = mgr->ctx; | 167 | struct vidi_context *ctx = manager_to_vidi(mgr); |
156 | struct vidi_win_data *win_data; | 168 | struct vidi_win_data *win_data; |
157 | int win; | 169 | int win; |
158 | unsigned long offset; | 170 | unsigned long offset; |
@@ -204,7 +216,7 @@ static void vidi_win_mode_set(struct exynos_drm_manager *mgr, | |||
204 | 216 | ||
205 | static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) | 217 | static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) |
206 | { | 218 | { |
207 | struct vidi_context *ctx = mgr->ctx; | 219 | struct vidi_context *ctx = manager_to_vidi(mgr); |
208 | struct vidi_win_data *win_data; | 220 | struct vidi_win_data *win_data; |
209 | int win = zpos; | 221 | int win = zpos; |
210 | 222 | ||
@@ -229,7 +241,7 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) | |||
229 | 241 | ||
230 | static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) | 242 | static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) |
231 | { | 243 | { |
232 | struct vidi_context *ctx = mgr->ctx; | 244 | struct vidi_context *ctx = manager_to_vidi(mgr); |
233 | struct vidi_win_data *win_data; | 245 | struct vidi_win_data *win_data; |
234 | int win = zpos; | 246 | int win = zpos; |
235 | 247 | ||
@@ -247,7 +259,7 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) | |||
247 | 259 | ||
248 | static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) | 260 | static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) |
249 | { | 261 | { |
250 | struct vidi_context *ctx = mgr->ctx; | 262 | struct vidi_context *ctx = manager_to_vidi(mgr); |
251 | 263 | ||
252 | DRM_DEBUG_KMS("%s\n", __FILE__); | 264 | DRM_DEBUG_KMS("%s\n", __FILE__); |
253 | 265 | ||
@@ -271,7 +283,7 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) | |||
271 | 283 | ||
272 | static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) | 284 | static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) |
273 | { | 285 | { |
274 | struct vidi_context *ctx = mgr->ctx; | 286 | struct vidi_context *ctx = manager_to_vidi(mgr); |
275 | 287 | ||
276 | DRM_DEBUG_KMS("%d\n", mode); | 288 | DRM_DEBUG_KMS("%d\n", mode); |
277 | 289 | ||
@@ -297,7 +309,7 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) | |||
297 | static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, | 309 | static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, |
298 | struct drm_device *drm_dev) | 310 | struct drm_device *drm_dev) |
299 | { | 311 | { |
300 | struct vidi_context *ctx = mgr->ctx; | 312 | struct vidi_context *ctx = manager_to_vidi(mgr); |
301 | struct exynos_drm_private *priv = drm_dev->dev_private; | 313 | struct exynos_drm_private *priv = drm_dev->dev_private; |
302 | 314 | ||
303 | mgr->drm_dev = ctx->drm_dev = drm_dev; | 315 | mgr->drm_dev = ctx->drm_dev = drm_dev; |
@@ -316,11 +328,6 @@ static struct exynos_drm_manager_ops vidi_manager_ops = { | |||
316 | .win_disable = vidi_win_disable, | 328 | .win_disable = vidi_win_disable, |
317 | }; | 329 | }; |
318 | 330 | ||
319 | static struct exynos_drm_manager vidi_manager = { | ||
320 | .type = EXYNOS_DISPLAY_TYPE_VIDI, | ||
321 | .ops = &vidi_manager_ops, | ||
322 | }; | ||
323 | |||
324 | static void vidi_fake_vblank_handler(struct work_struct *work) | 331 | static void vidi_fake_vblank_handler(struct work_struct *work) |
325 | { | 332 | { |
326 | struct vidi_context *ctx = container_of(work, struct vidi_context, | 333 | struct vidi_context *ctx = container_of(work, struct vidi_context, |
@@ -349,9 +356,8 @@ static void vidi_fake_vblank_handler(struct work_struct *work) | |||
349 | static int vidi_show_connection(struct device *dev, | 356 | static int vidi_show_connection(struct device *dev, |
350 | struct device_attribute *attr, char *buf) | 357 | struct device_attribute *attr, char *buf) |
351 | { | 358 | { |
359 | struct vidi_context *ctx = dev_get_drvdata(dev); | ||
352 | int rc; | 360 | int rc; |
353 | struct exynos_drm_manager *mgr = get_vidi_mgr(dev); | ||
354 | struct vidi_context *ctx = mgr->ctx; | ||
355 | 361 | ||
356 | mutex_lock(&ctx->lock); | 362 | mutex_lock(&ctx->lock); |
357 | 363 | ||
@@ -366,8 +372,7 @@ static int vidi_store_connection(struct device *dev, | |||
366 | struct device_attribute *attr, | 372 | struct device_attribute *attr, |
367 | const char *buf, size_t len) | 373 | const char *buf, size_t len) |
368 | { | 374 | { |
369 | struct exynos_drm_manager *mgr = get_vidi_mgr(dev); | 375 | struct vidi_context *ctx = dev_get_drvdata(dev); |
370 | struct vidi_context *ctx = mgr->ctx; | ||
371 | int ret; | 376 | int ret; |
372 | 377 | ||
373 | ret = kstrtoint(buf, 0, &ctx->connected); | 378 | ret = kstrtoint(buf, 0, &ctx->connected); |
@@ -420,7 +425,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, | |||
420 | display = exynos_drm_get_display(encoder); | 425 | display = exynos_drm_get_display(encoder); |
421 | 426 | ||
422 | if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) { | 427 | if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) { |
423 | ctx = display->ctx; | 428 | ctx = display_to_vidi(display); |
424 | break; | 429 | break; |
425 | } | 430 | } |
426 | } | 431 | } |
@@ -530,7 +535,7 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { | |||
530 | static int vidi_create_connector(struct exynos_drm_display *display, | 535 | static int vidi_create_connector(struct exynos_drm_display *display, |
531 | struct drm_encoder *encoder) | 536 | struct drm_encoder *encoder) |
532 | { | 537 | { |
533 | struct vidi_context *ctx = display->ctx; | 538 | struct vidi_context *ctx = display_to_vidi(display); |
534 | struct drm_connector *connector = &ctx->connector; | 539 | struct drm_connector *connector = &ctx->connector; |
535 | int ret; | 540 | int ret; |
536 | 541 | ||
@@ -556,27 +561,22 @@ static struct exynos_drm_display_ops vidi_display_ops = { | |||
556 | .create_connector = vidi_create_connector, | 561 | .create_connector = vidi_create_connector, |
557 | }; | 562 | }; |
558 | 563 | ||
559 | static struct exynos_drm_display vidi_display = { | 564 | static int vidi_bind(struct device *dev, struct device *master, void *data) |
560 | .type = EXYNOS_DISPLAY_TYPE_VIDI, | ||
561 | .ops = &vidi_display_ops, | ||
562 | }; | ||
563 | |||
564 | static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | ||
565 | { | 565 | { |
566 | struct exynos_drm_manager *mgr = get_vidi_mgr(dev); | 566 | struct vidi_context *ctx = dev_get_drvdata(dev); |
567 | struct vidi_context *ctx = mgr->ctx; | 567 | struct drm_device *drm_dev = data; |
568 | struct drm_crtc *crtc = ctx->crtc; | 568 | struct drm_crtc *crtc = ctx->crtc; |
569 | int ret; | 569 | int ret; |
570 | 570 | ||
571 | vidi_mgr_initialize(mgr, drm_dev); | 571 | vidi_mgr_initialize(&ctx->manager, drm_dev); |
572 | 572 | ||
573 | ret = exynos_drm_crtc_create(&vidi_manager); | 573 | ret = exynos_drm_crtc_create(&ctx->manager); |
574 | if (ret) { | 574 | if (ret) { |
575 | DRM_ERROR("failed to create crtc.\n"); | 575 | DRM_ERROR("failed to create crtc.\n"); |
576 | return ret; | 576 | return ret; |
577 | } | 577 | } |
578 | 578 | ||
579 | ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display); | 579 | ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display); |
580 | if (ret) { | 580 | if (ret) { |
581 | crtc->funcs->destroy(crtc); | 581 | crtc->funcs->destroy(crtc); |
582 | DRM_ERROR("failed to create encoder and connector.\n"); | 582 | DRM_ERROR("failed to create encoder and connector.\n"); |
@@ -586,9 +586,18 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) | |||
586 | return 0; | 586 | return 0; |
587 | } | 587 | } |
588 | 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 | |||
589 | static int vidi_probe(struct platform_device *pdev) | 599 | static int vidi_probe(struct platform_device *pdev) |
590 | { | 600 | { |
591 | struct exynos_drm_subdrv *subdrv; | ||
592 | struct vidi_context *ctx; | 601 | struct vidi_context *ctx; |
593 | int ret; | 602 | int ret; |
594 | 603 | ||
@@ -596,40 +605,54 @@ static int vidi_probe(struct platform_device *pdev) | |||
596 | if (!ctx) | 605 | if (!ctx) |
597 | return -ENOMEM; | 606 | return -ENOMEM; |
598 | 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; | ||
599 | ctx->default_win = 0; | 612 | ctx->default_win = 0; |
613 | ctx->pdev = pdev; | ||
600 | 614 | ||
601 | INIT_WORK(&ctx->work, vidi_fake_vblank_handler); | 615 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, |
602 | 616 | ctx->manager.type); | |
603 | vidi_manager.ctx = ctx; | 617 | if (ret) |
604 | vidi_display.ctx = ctx; | 618 | return ret; |
605 | 619 | ||
606 | mutex_init(&ctx->lock); | 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; | ||
607 | 624 | ||
608 | platform_set_drvdata(pdev, &vidi_manager); | 625 | INIT_WORK(&ctx->work, vidi_fake_vblank_handler); |
609 | 626 | ||
610 | subdrv = &ctx->subdrv; | 627 | mutex_init(&ctx->lock); |
611 | subdrv->dev = &pdev->dev; | ||
612 | subdrv->probe = vidi_subdrv_probe; | ||
613 | 628 | ||
614 | ret = exynos_drm_subdrv_register(subdrv); | 629 | platform_set_drvdata(pdev, ctx); |
615 | if (ret < 0) { | ||
616 | dev_err(&pdev->dev, "failed to register drm vidi device\n"); | ||
617 | return ret; | ||
618 | } | ||
619 | 630 | ||
620 | ret = device_create_file(&pdev->dev, &dev_attr_connection); | 631 | ret = device_create_file(&pdev->dev, &dev_attr_connection); |
621 | if (ret < 0) { | 632 | if (ret < 0) { |
622 | exynos_drm_subdrv_unregister(subdrv); | 633 | DRM_ERROR("failed to create connection sysfs.\n"); |
623 | DRM_INFO("failed to create connection sysfs.\n"); | 634 | goto err_del_conn_component; |
624 | } | 635 | } |
625 | 636 | ||
626 | return 0; | 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; | ||
627 | } | 651 | } |
628 | 652 | ||
629 | static int vidi_remove(struct platform_device *pdev) | 653 | static int vidi_remove(struct platform_device *pdev) |
630 | { | 654 | { |
631 | struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); | 655 | struct vidi_context *ctx = platform_get_drvdata(pdev); |
632 | struct vidi_context *ctx = mgr->ctx; | ||
633 | 656 | ||
634 | if (ctx->raw_edid != (struct edid *)fake_edid_info) { | 657 | if (ctx->raw_edid != (struct edid *)fake_edid_info) { |
635 | kfree(ctx->raw_edid); | 658 | kfree(ctx->raw_edid); |
@@ -638,6 +661,10 @@ static int vidi_remove(struct platform_device *pdev) | |||
638 | return -EINVAL; | 661 | return -EINVAL; |
639 | } | 662 | } |
640 | 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 | |||
641 | return 0; | 668 | return 0; |
642 | } | 669 | } |
643 | 670 | ||
@@ -668,12 +695,19 @@ int exynos_drm_probe_vidi(void) | |||
668 | return ret; | 695 | return ret; |
669 | } | 696 | } |
670 | 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 | |||
671 | void exynos_drm_remove_vidi(void) | 705 | void exynos_drm_remove_vidi(void) |
672 | { | 706 | { |
673 | struct vidi_context *ctx = vidi_manager.ctx; | 707 | int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL, |
674 | struct exynos_drm_subdrv *subdrv = &ctx->subdrv; | 708 | exynos_drm_remove_vidi_device); |
675 | struct platform_device *pdev = to_platform_device(subdrv->dev); | 709 | /* silence compiler warning */ |
710 | (void)ret; | ||
676 | 711 | ||
677 | platform_driver_unregister(&vidi_driver); | 712 | platform_driver_unregister(&vidi_driver); |
678 | platform_device_unregister(pdev); | ||
679 | } | 713 | } |