1 /*
2  * Copyright (C) STMicroelectronics SA 2014
3  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4  *          Fabien Dessenne <fabien.dessenne@st.com>
5  *          for STMicroelectronics.
6  * License terms:  GNU General Public License (GPL), version 2
7  */
8 
9 #include <linux/clk.h>
10 
11 #include <drm/drmP.h>
12 #include <drm/drm_atomic.h>
13 #include <drm/drm_atomic_helper.h>
14 #include <drm/drm_crtc_helper.h>
15 #include <drm/drm_plane_helper.h>
16 
17 #include "sti_compositor.h"
18 #include "sti_drm_drv.h"
19 #include "sti_drm_crtc.h"
20 #include "sti_vtg.h"
21 
sti_drm_crtc_dpms(struct drm_crtc * crtc,int mode)22 static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
23 {
24 	DRM_DEBUG_KMS("\n");
25 }
26 
sti_drm_crtc_prepare(struct drm_crtc * crtc)27 static void sti_drm_crtc_prepare(struct drm_crtc *crtc)
28 {
29 	struct sti_mixer *mixer = to_sti_mixer(crtc);
30 	struct device *dev = mixer->dev;
31 	struct sti_compositor *compo = dev_get_drvdata(dev);
32 
33 	mixer->enabled = true;
34 
35 	/* Prepare and enable the compo IP clock */
36 	if (mixer->id == STI_MIXER_MAIN) {
37 		if (clk_prepare_enable(compo->clk_compo_main))
38 			DRM_INFO("Failed to prepare/enable compo_main clk\n");
39 	} else {
40 		if (clk_prepare_enable(compo->clk_compo_aux))
41 			DRM_INFO("Failed to prepare/enable compo_aux clk\n");
42 	}
43 
44 	sti_mixer_clear_all_layers(mixer);
45 }
46 
sti_drm_crtc_commit(struct drm_crtc * crtc)47 static void sti_drm_crtc_commit(struct drm_crtc *crtc)
48 {
49 	struct sti_mixer *mixer = to_sti_mixer(crtc);
50 	struct device *dev = mixer->dev;
51 	struct sti_compositor *compo = dev_get_drvdata(dev);
52 	struct sti_layer *layer;
53 
54 	if ((!mixer || !compo)) {
55 		DRM_ERROR("Can not find mixer or compositor)\n");
56 		return;
57 	}
58 
59 	/* get GDP which is reserved to the CRTC FB */
60 	layer = to_sti_layer(crtc->primary);
61 	if (layer)
62 		sti_layer_commit(layer);
63 	else
64 		DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n");
65 
66 	/* Enable layer on mixer */
67 	if (sti_mixer_set_layer_status(mixer, layer, true))
68 		DRM_ERROR("Can not enable layer at mixer\n");
69 
70 	drm_crtc_vblank_on(crtc);
71 }
72 
sti_drm_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)73 static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
74 				    const struct drm_display_mode *mode,
75 				    struct drm_display_mode *adjusted_mode)
76 {
77 	/* accept the provided drm_display_mode, do not fix it up */
78 	return true;
79 }
80 
81 static int
sti_drm_crtc_mode_set(struct drm_crtc * crtc,struct drm_display_mode * mode)82 sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
83 {
84 	struct sti_mixer *mixer = to_sti_mixer(crtc);
85 	struct device *dev = mixer->dev;
86 	struct sti_compositor *compo = dev_get_drvdata(dev);
87 	struct clk *clk;
88 	int rate = mode->clock * 1000;
89 	int res;
90 
91 	DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
92 		      crtc->base.id, sti_mixer_to_str(mixer),
93 		      mode->base.id, mode->name);
94 
95 	DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
96 		      mode->vrefresh, mode->clock,
97 		      mode->hdisplay,
98 		      mode->hsync_start, mode->hsync_end,
99 		      mode->htotal,
100 		      mode->vdisplay,
101 		      mode->vsync_start, mode->vsync_end,
102 		      mode->vtotal, mode->type, mode->flags);
103 
104 	/* Set rate and prepare/enable pixel clock */
105 	if (mixer->id == STI_MIXER_MAIN)
106 		clk = compo->clk_pix_main;
107 	else
108 		clk = compo->clk_pix_aux;
109 
110 	res = clk_set_rate(clk, rate);
111 	if (res < 0) {
112 		DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
113 		return -EINVAL;
114 	}
115 	if (clk_prepare_enable(clk)) {
116 		DRM_ERROR("Failed to prepare/enable pix clk\n");
117 		return -EINVAL;
118 	}
119 
120 	sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
121 			compo->vtg_main : compo->vtg_aux, &crtc->mode);
122 
123 	res = sti_mixer_active_video_area(mixer, &crtc->mode);
124 	if (res) {
125 		DRM_ERROR("Can not set active video area\n");
126 		return -EINVAL;
127 	}
128 
129 	return res;
130 }
131 
sti_drm_crtc_disable(struct drm_crtc * crtc)132 static void sti_drm_crtc_disable(struct drm_crtc *crtc)
133 {
134 	struct sti_mixer *mixer = to_sti_mixer(crtc);
135 	struct device *dev = mixer->dev;
136 	struct sti_compositor *compo = dev_get_drvdata(dev);
137 
138 	if (!mixer->enabled)
139 		return;
140 
141 	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
142 
143 	/* Disable Background */
144 	sti_mixer_set_background_status(mixer, false);
145 
146 	drm_crtc_vblank_off(crtc);
147 
148 	/* Disable pixel clock and compo IP clocks */
149 	if (mixer->id == STI_MIXER_MAIN) {
150 		clk_disable_unprepare(compo->clk_pix_main);
151 		clk_disable_unprepare(compo->clk_compo_main);
152 	} else {
153 		clk_disable_unprepare(compo->clk_pix_aux);
154 		clk_disable_unprepare(compo->clk_compo_aux);
155 	}
156 
157 	mixer->enabled = false;
158 }
159 
160 static void
sti_drm_crtc_mode_set_nofb(struct drm_crtc * crtc)161 sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
162 {
163 	sti_drm_crtc_prepare(crtc);
164 	sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
165 }
166 
sti_drm_atomic_begin(struct drm_crtc * crtc)167 static void sti_drm_atomic_begin(struct drm_crtc *crtc)
168 {
169 	struct sti_mixer *mixer = to_sti_mixer(crtc);
170 
171 	if (crtc->state->event) {
172 		crtc->state->event->pipe = drm_crtc_index(crtc);
173 
174 		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
175 
176 		mixer->pending_event = crtc->state->event;
177 		crtc->state->event = NULL;
178 	}
179 }
180 
sti_drm_atomic_flush(struct drm_crtc * crtc)181 static void sti_drm_atomic_flush(struct drm_crtc *crtc)
182 {
183 }
184 
185 static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
186 	.dpms = sti_drm_crtc_dpms,
187 	.prepare = sti_drm_crtc_prepare,
188 	.commit = sti_drm_crtc_commit,
189 	.mode_fixup = sti_drm_crtc_mode_fixup,
190 	.mode_set = drm_helper_crtc_mode_set,
191 	.mode_set_nofb = sti_drm_crtc_mode_set_nofb,
192 	.mode_set_base = drm_helper_crtc_mode_set_base,
193 	.disable = sti_drm_crtc_disable,
194 	.atomic_begin = sti_drm_atomic_begin,
195 	.atomic_flush = sti_drm_atomic_flush,
196 };
197 
sti_drm_crtc_destroy(struct drm_crtc * crtc)198 static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
199 {
200 	DRM_DEBUG_KMS("\n");
201 	drm_crtc_cleanup(crtc);
202 }
203 
sti_drm_crtc_set_property(struct drm_crtc * crtc,struct drm_property * property,uint64_t val)204 static int sti_drm_crtc_set_property(struct drm_crtc *crtc,
205 				     struct drm_property *property,
206 				     uint64_t val)
207 {
208 	DRM_DEBUG_KMS("\n");
209 	return 0;
210 }
211 
sti_drm_crtc_vblank_cb(struct notifier_block * nb,unsigned long event,void * data)212 int sti_drm_crtc_vblank_cb(struct notifier_block *nb,
213 			   unsigned long event, void *data)
214 {
215 	struct drm_device *drm_dev;
216 	struct sti_compositor *compo =
217 		container_of(nb, struct sti_compositor, vtg_vblank_nb);
218 	int *crtc = data;
219 	unsigned long flags;
220 	struct sti_drm_private *priv;
221 
222 	drm_dev = compo->mixer[*crtc]->drm_crtc.dev;
223 	priv = drm_dev->dev_private;
224 
225 	if ((event != VTG_TOP_FIELD_EVENT) &&
226 	    (event != VTG_BOTTOM_FIELD_EVENT)) {
227 		DRM_ERROR("unknown event: %lu\n", event);
228 		return -EINVAL;
229 	}
230 
231 	drm_handle_vblank(drm_dev, *crtc);
232 
233 	spin_lock_irqsave(&drm_dev->event_lock, flags);
234 	if (compo->mixer[*crtc]->pending_event) {
235 		drm_send_vblank_event(drm_dev, -1,
236 				compo->mixer[*crtc]->pending_event);
237 		drm_vblank_put(drm_dev, *crtc);
238 		compo->mixer[*crtc]->pending_event = NULL;
239 	}
240 	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
241 
242 	return 0;
243 }
244 
sti_drm_crtc_enable_vblank(struct drm_device * dev,int crtc)245 int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
246 {
247 	struct sti_drm_private *dev_priv = dev->dev_private;
248 	struct sti_compositor *compo = dev_priv->compo;
249 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
250 
251 	if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ?
252 			compo->vtg_main : compo->vtg_aux,
253 			vtg_vblank_nb, crtc)) {
254 		DRM_ERROR("Cannot register VTG notifier\n");
255 		return -EINVAL;
256 	}
257 
258 	return 0;
259 }
260 EXPORT_SYMBOL(sti_drm_crtc_enable_vblank);
261 
sti_drm_crtc_disable_vblank(struct drm_device * dev,int crtc)262 void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
263 {
264 	struct sti_drm_private *priv = dev->dev_private;
265 	struct sti_compositor *compo = priv->compo;
266 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
267 
268 	DRM_DEBUG_DRIVER("\n");
269 
270 	if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ?
271 			compo->vtg_main : compo->vtg_aux, vtg_vblank_nb))
272 		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
273 
274 	/* free the resources of the pending requests */
275 	if (compo->mixer[crtc]->pending_event) {
276 		drm_vblank_put(dev, crtc);
277 		compo->mixer[crtc]->pending_event = NULL;
278 	}
279 }
280 EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
281 
282 static struct drm_crtc_funcs sti_crtc_funcs = {
283 	.set_config = drm_atomic_helper_set_config,
284 	.page_flip = drm_atomic_helper_page_flip,
285 	.destroy = sti_drm_crtc_destroy,
286 	.set_property = sti_drm_crtc_set_property,
287 	.reset = drm_atomic_helper_crtc_reset,
288 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
289 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
290 };
291 
sti_drm_crtc_is_main(struct drm_crtc * crtc)292 bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
293 {
294 	struct sti_mixer *mixer = to_sti_mixer(crtc);
295 
296 	if (mixer->id == STI_MIXER_MAIN)
297 		return true;
298 
299 	return false;
300 }
301 EXPORT_SYMBOL(sti_drm_crtc_is_main);
302 
sti_drm_crtc_init(struct drm_device * drm_dev,struct sti_mixer * mixer,struct drm_plane * primary,struct drm_plane * cursor)303 int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
304 		struct drm_plane *primary, struct drm_plane *cursor)
305 {
306 	struct drm_crtc *crtc = &mixer->drm_crtc;
307 	int res;
308 
309 	res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
310 			&sti_crtc_funcs);
311 	if (res) {
312 		DRM_ERROR("Can not initialze CRTC\n");
313 		return -EINVAL;
314 	}
315 
316 	drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
317 
318 	DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
319 			 crtc->base.id, sti_mixer_to_str(mixer));
320 
321 	return 0;
322 }
323