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