1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. 4 * Author: James.Qian.Wang <james.qian.wang@arm.com> 5 * 6 */ 7 #include <linux/clk.h> 8 #include <linux/pm_runtime.h> 9 #include <linux/spinlock.h> 10 11 #include <drm/drm_atomic.h> 12 #include <drm/drm_atomic_helper.h> 13 #include <drm/drm_crtc_helper.h> 14 #include <drm/drm_plane_helper.h> 15 #include <drm/drm_print.h> 16 #include <drm/drm_vblank.h> 17 18 #include "komeda_dev.h" 19 #include "komeda_kms.h" 20 21 void komeda_crtc_handle_event(struct komeda_crtc *kcrtc, 22 struct komeda_events *evts) 23 { 24 struct drm_crtc *crtc = &kcrtc->base; 25 u32 events = evts->pipes[kcrtc->master->id]; 26 27 if (events & KOMEDA_EVENT_VSYNC) 28 drm_crtc_handle_vblank(crtc); 29 30 /* will handle it together with the write back support */ 31 if (events & KOMEDA_EVENT_EOW) 32 DRM_DEBUG("EOW.\n"); 33 34 /* will handle it with crtc->flush */ 35 if (events & KOMEDA_EVENT_FLIP) 36 DRM_DEBUG("FLIP Done.\n"); 37 } 38 39 struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = { 40 }; 41 42 static const struct drm_crtc_funcs komeda_crtc_funcs = { 43 }; 44 45 int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, 46 struct komeda_dev *mdev) 47 { 48 struct komeda_crtc *crtc; 49 struct komeda_pipeline *master; 50 char str[16]; 51 int i; 52 53 kms->n_crtcs = 0; 54 55 for (i = 0; i < mdev->n_pipelines; i++) { 56 crtc = &kms->crtcs[kms->n_crtcs]; 57 master = mdev->pipelines[i]; 58 59 crtc->master = master; 60 crtc->slave = NULL; 61 62 if (crtc->slave) 63 sprintf(str, "pipe-%d", crtc->slave->id); 64 else 65 sprintf(str, "None"); 66 67 DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n", 68 kms->n_crtcs, master->id, str, 69 master->of_output_dev ? 70 master->of_output_dev->full_name : "None"); 71 72 kms->n_crtcs++; 73 } 74 75 return 0; 76 } 77 78 static struct drm_plane * 79 get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc) 80 { 81 struct komeda_plane *kplane; 82 struct drm_plane *plane; 83 84 drm_for_each_plane(plane, &kms->base) { 85 if (plane->type != DRM_PLANE_TYPE_PRIMARY) 86 continue; 87 88 kplane = to_kplane(plane); 89 /* only master can be primary */ 90 if (kplane->layer->base.pipeline == crtc->master) 91 return plane; 92 } 93 94 return NULL; 95 } 96 97 static int komeda_crtc_add(struct komeda_kms_dev *kms, 98 struct komeda_crtc *kcrtc) 99 { 100 struct drm_crtc *crtc = &kcrtc->base; 101 int err; 102 103 err = drm_crtc_init_with_planes(&kms->base, crtc, 104 get_crtc_primary(kms, kcrtc), NULL, 105 &komeda_crtc_funcs, NULL); 106 if (err) 107 return err; 108 109 drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs); 110 drm_crtc_vblank_reset(crtc); 111 112 crtc->port = kcrtc->master->of_output_port; 113 114 return 0; 115 } 116 117 int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev) 118 { 119 int i, err; 120 121 for (i = 0; i < kms->n_crtcs; i++) { 122 err = komeda_crtc_add(kms, &kms->crtcs[i]); 123 if (err) 124 return err; 125 } 126 127 return 0; 128 } 129