• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_crtc_helper.h>
13 
14 #include "sti_compositor.h"
15 #include "sti_drm_drv.h"
16 #include "sti_drm_crtc.h"
17 #include "sti_vtg.h"
18 
sti_drm_crtc_dpms(struct drm_crtc * crtc,int mode)19 static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
20 {
21 	DRM_DEBUG_KMS("\n");
22 }
23 
sti_drm_crtc_prepare(struct drm_crtc * crtc)24 static void sti_drm_crtc_prepare(struct drm_crtc *crtc)
25 {
26 	struct sti_mixer *mixer = to_sti_mixer(crtc);
27 	struct device *dev = mixer->dev;
28 	struct sti_compositor *compo = dev_get_drvdata(dev);
29 
30 	compo->enable = true;
31 
32 	/* Prepare and enable the compo IP clock */
33 	if (mixer->id == STI_MIXER_MAIN) {
34 		if (clk_prepare_enable(compo->clk_compo_main))
35 			DRM_INFO("Failed to prepare/enable compo_main clk\n");
36 	} else {
37 		if (clk_prepare_enable(compo->clk_compo_aux))
38 			DRM_INFO("Failed to prepare/enable compo_aux clk\n");
39 	}
40 }
41 
sti_drm_crtc_commit(struct drm_crtc * crtc)42 static void sti_drm_crtc_commit(struct drm_crtc *crtc)
43 {
44 	struct sti_mixer *mixer = to_sti_mixer(crtc);
45 	struct device *dev = mixer->dev;
46 	struct sti_compositor *compo = dev_get_drvdata(dev);
47 	struct sti_layer *layer;
48 
49 	if ((!mixer || !compo)) {
50 		DRM_ERROR("Can not find mixer or compositor)\n");
51 		return;
52 	}
53 
54 	/* get GDP which is reserved to the CRTC FB */
55 	layer = to_sti_layer(crtc->primary);
56 	if (layer)
57 		sti_layer_commit(layer);
58 	else
59 		DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n");
60 
61 	/* Enable layer on mixer */
62 	if (sti_mixer_set_layer_status(mixer, layer, true))
63 		DRM_ERROR("Can not enable layer at mixer\n");
64 }
65 
sti_drm_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)66 static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
67 				    const struct drm_display_mode *mode,
68 				    struct drm_display_mode *adjusted_mode)
69 {
70 	/* accept the provided drm_display_mode, do not fix it up */
71 	return true;
72 }
73 
74 static int
sti_drm_crtc_mode_set(struct drm_crtc * crtc,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode,int x,int y,struct drm_framebuffer * old_fb)75 sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
76 		      struct drm_display_mode *adjusted_mode, int x, int y,
77 		      struct drm_framebuffer *old_fb)
78 {
79 	struct sti_mixer *mixer = to_sti_mixer(crtc);
80 	struct device *dev = mixer->dev;
81 	struct sti_compositor *compo = dev_get_drvdata(dev);
82 	struct sti_layer *layer;
83 	struct clk *clk;
84 	int rate = mode->clock * 1000;
85 	int res;
86 	unsigned int w, h;
87 
88 	DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n",
89 		      crtc->base.id, sti_mixer_to_str(mixer),
90 		      crtc->primary->fb->base.id, mode->base.id, mode->name);
91 
92 	DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
93 		      mode->vrefresh, mode->clock,
94 		      mode->hdisplay,
95 		      mode->hsync_start, mode->hsync_end,
96 		      mode->htotal,
97 		      mode->vdisplay,
98 		      mode->vsync_start, mode->vsync_end,
99 		      mode->vtotal, mode->type, mode->flags);
100 
101 	/* Set rate and prepare/enable pixel clock */
102 	if (mixer->id == STI_MIXER_MAIN)
103 		clk = compo->clk_pix_main;
104 	else
105 		clk = compo->clk_pix_aux;
106 
107 	res = clk_set_rate(clk, rate);
108 	if (res < 0) {
109 		DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
110 		return -EINVAL;
111 	}
112 	if (clk_prepare_enable(clk)) {
113 		DRM_ERROR("Failed to prepare/enable pix clk\n");
114 		return -EINVAL;
115 	}
116 
117 	sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
118 			compo->vtg_main : compo->vtg_aux, &crtc->mode);
119 
120 	/* a GDP is reserved to the CRTC FB */
121 	layer = to_sti_layer(crtc->primary);
122 	if (!layer) {
123 		DRM_ERROR("Can not find GDP0)\n");
124 		return -EINVAL;
125 	}
126 
127 	/* copy the mode data adjusted by mode_fixup() into crtc->mode
128 	 * so that hardware can be set to proper mode
129 	 */
130 	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
131 
132 	res = sti_mixer_set_layer_depth(mixer, layer);
133 	if (res) {
134 		DRM_ERROR("Can not set layer depth\n");
135 		return -EINVAL;
136 	}
137 	res = sti_mixer_active_video_area(mixer, &crtc->mode);
138 	if (res) {
139 		DRM_ERROR("Can not set active video area\n");
140 		return -EINVAL;
141 	}
142 
143 	w = crtc->primary->fb->width - x;
144 	h = crtc->primary->fb->height - y;
145 
146 	return sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode,
147 			mixer->id, 0, 0, w, h, x, y, w, h);
148 }
149 
sti_drm_crtc_mode_set_base(struct drm_crtc * crtc,int x,int y,struct drm_framebuffer * old_fb)150 static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
151 				      struct drm_framebuffer *old_fb)
152 {
153 	struct sti_mixer *mixer = to_sti_mixer(crtc);
154 	struct sti_layer *layer;
155 	unsigned int w, h;
156 	int ret;
157 
158 	DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n",
159 		      crtc->base.id, sti_mixer_to_str(mixer),
160 		      crtc->primary->fb->base.id, x, y);
161 
162 	/* GDP is reserved to the CRTC FB */
163 	layer = to_sti_layer(crtc->primary);
164 	if (!layer) {
165 		DRM_ERROR("Can not find GDP0)\n");
166 		ret = -EINVAL;
167 		goto out;
168 	}
169 
170 	w = crtc->primary->fb->width - crtc->x;
171 	h = crtc->primary->fb->height - crtc->y;
172 
173 	ret = sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode,
174 				mixer->id, 0, 0, w, h,
175 				crtc->x, crtc->y, w, h);
176 	if (ret) {
177 		DRM_ERROR("Can not prepare layer\n");
178 		goto out;
179 	}
180 
181 	sti_drm_crtc_commit(crtc);
182 out:
183 	return ret;
184 }
185 
sti_drm_crtc_load_lut(struct drm_crtc * crtc)186 static void sti_drm_crtc_load_lut(struct drm_crtc *crtc)
187 {
188 	/* do nothing */
189 }
190 
sti_drm_crtc_disable(struct drm_crtc * crtc)191 static void sti_drm_crtc_disable(struct drm_crtc *crtc)
192 {
193 	struct sti_mixer *mixer = to_sti_mixer(crtc);
194 	struct device *dev = mixer->dev;
195 	struct sti_compositor *compo = dev_get_drvdata(dev);
196 	struct sti_layer *layer;
197 
198 	if (!compo->enable)
199 		return;
200 
201 	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
202 
203 	/* Disable Background */
204 	sti_mixer_set_background_status(mixer, false);
205 
206 	/* Disable GDP */
207 	layer = to_sti_layer(crtc->primary);
208 	if (!layer) {
209 		DRM_ERROR("Cannot find GDP0\n");
210 		return;
211 	}
212 
213 	/* Disable layer at mixer level */
214 	if (sti_mixer_set_layer_status(mixer, layer, false))
215 		DRM_ERROR("Can not disable %s layer at mixer\n",
216 				sti_layer_to_str(layer));
217 
218 	/* Wait a while to be sure that a Vsync event is received */
219 	msleep(WAIT_NEXT_VSYNC_MS);
220 
221 	/* Then disable layer itself */
222 	sti_layer_disable(layer);
223 
224 	drm_vblank_off(crtc->dev, mixer->id);
225 
226 	/* Disable pixel clock and compo IP clocks */
227 	if (mixer->id == STI_MIXER_MAIN) {
228 		clk_disable_unprepare(compo->clk_pix_main);
229 		clk_disable_unprepare(compo->clk_compo_main);
230 	} else {
231 		clk_disable_unprepare(compo->clk_pix_aux);
232 		clk_disable_unprepare(compo->clk_compo_aux);
233 	}
234 
235 	compo->enable = false;
236 }
237 
238 static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
239 	.dpms = sti_drm_crtc_dpms,
240 	.prepare = sti_drm_crtc_prepare,
241 	.commit = sti_drm_crtc_commit,
242 	.mode_fixup = sti_drm_crtc_mode_fixup,
243 	.mode_set = sti_drm_crtc_mode_set,
244 	.mode_set_base = sti_drm_crtc_mode_set_base,
245 	.load_lut = sti_drm_crtc_load_lut,
246 	.disable = sti_drm_crtc_disable,
247 };
248 
sti_drm_crtc_page_flip(struct drm_crtc * crtc,struct drm_framebuffer * fb,struct drm_pending_vblank_event * event,uint32_t page_flip_flags)249 static int sti_drm_crtc_page_flip(struct drm_crtc *crtc,
250 				  struct drm_framebuffer *fb,
251 				  struct drm_pending_vblank_event *event,
252 				  uint32_t page_flip_flags)
253 {
254 	struct drm_device *drm_dev = crtc->dev;
255 	struct drm_framebuffer *old_fb;
256 	struct sti_mixer *mixer = to_sti_mixer(crtc);
257 	unsigned long flags;
258 	int ret;
259 
260 	DRM_DEBUG_KMS("fb %d --> fb %d\n",
261 			crtc->primary->fb->base.id, fb->base.id);
262 
263 	mutex_lock(&drm_dev->struct_mutex);
264 
265 	old_fb = crtc->primary->fb;
266 	crtc->primary->fb = fb;
267 	ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
268 	if (ret) {
269 		DRM_ERROR("failed\n");
270 		crtc->primary->fb = old_fb;
271 		goto out;
272 	}
273 
274 	if (event) {
275 		event->pipe = mixer->id;
276 
277 		ret = drm_vblank_get(drm_dev, event->pipe);
278 		if (ret) {
279 			DRM_ERROR("Cannot get vblank\n");
280 			goto out;
281 		}
282 
283 		spin_lock_irqsave(&drm_dev->event_lock, flags);
284 		if (mixer->pending_event) {
285 			drm_vblank_put(drm_dev, event->pipe);
286 			ret = -EBUSY;
287 		} else {
288 			mixer->pending_event = event;
289 		}
290 		spin_unlock_irqrestore(&drm_dev->event_lock, flags);
291 	}
292 out:
293 	mutex_unlock(&drm_dev->struct_mutex);
294 	return ret;
295 }
296 
sti_drm_crtc_destroy(struct drm_crtc * crtc)297 static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
298 {
299 	DRM_DEBUG_KMS("\n");
300 	drm_crtc_cleanup(crtc);
301 }
302 
sti_drm_crtc_set_property(struct drm_crtc * crtc,struct drm_property * property,uint64_t val)303 static int sti_drm_crtc_set_property(struct drm_crtc *crtc,
304 				     struct drm_property *property,
305 				     uint64_t val)
306 {
307 	DRM_DEBUG_KMS("\n");
308 	return 0;
309 }
310 
sti_drm_crtc_vblank_cb(struct notifier_block * nb,unsigned long event,void * data)311 int sti_drm_crtc_vblank_cb(struct notifier_block *nb,
312 			   unsigned long event, void *data)
313 {
314 	struct drm_device *drm_dev;
315 	struct sti_compositor *compo =
316 		container_of(nb, struct sti_compositor, vtg_vblank_nb);
317 	int *crtc = data;
318 	unsigned long flags;
319 	struct sti_drm_private *priv;
320 
321 	drm_dev = compo->mixer[*crtc]->drm_crtc.dev;
322 	priv = drm_dev->dev_private;
323 
324 	if ((event != VTG_TOP_FIELD_EVENT) &&
325 	    (event != VTG_BOTTOM_FIELD_EVENT)) {
326 		DRM_ERROR("unknown event: %lu\n", event);
327 		return -EINVAL;
328 	}
329 
330 	drm_handle_vblank(drm_dev, *crtc);
331 
332 	spin_lock_irqsave(&drm_dev->event_lock, flags);
333 	if (compo->mixer[*crtc]->pending_event) {
334 		drm_send_vblank_event(drm_dev, -1,
335 				compo->mixer[*crtc]->pending_event);
336 		drm_vblank_put(drm_dev, *crtc);
337 		compo->mixer[*crtc]->pending_event = NULL;
338 	}
339 	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
340 
341 	return 0;
342 }
343 
sti_drm_crtc_enable_vblank(struct drm_device * dev,int crtc)344 int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
345 {
346 	struct sti_drm_private *dev_priv = dev->dev_private;
347 	struct sti_compositor *compo = dev_priv->compo;
348 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
349 
350 	if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ?
351 			compo->vtg_main : compo->vtg_aux,
352 			vtg_vblank_nb, crtc)) {
353 		DRM_ERROR("Cannot register VTG notifier\n");
354 		return -EINVAL;
355 	}
356 
357 	return 0;
358 }
359 EXPORT_SYMBOL(sti_drm_crtc_enable_vblank);
360 
sti_drm_crtc_disable_vblank(struct drm_device * dev,int crtc)361 void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
362 {
363 	struct sti_drm_private *priv = dev->dev_private;
364 	struct sti_compositor *compo = priv->compo;
365 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
366 	unsigned long flags;
367 
368 	DRM_DEBUG_DRIVER("\n");
369 
370 	if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ?
371 			compo->vtg_main : compo->vtg_aux, vtg_vblank_nb))
372 		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
373 
374 	/* free the resources of the pending requests */
375 	spin_lock_irqsave(&dev->event_lock, flags);
376 	if (compo->mixer[crtc]->pending_event) {
377 		drm_vblank_put(dev, crtc);
378 		compo->mixer[crtc]->pending_event = NULL;
379 	}
380 	spin_unlock_irqrestore(&dev->event_lock, flags);
381 
382 }
383 EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
384 
385 static struct drm_crtc_funcs sti_crtc_funcs = {
386 	.set_config = drm_crtc_helper_set_config,
387 	.page_flip = sti_drm_crtc_page_flip,
388 	.destroy = sti_drm_crtc_destroy,
389 	.set_property = sti_drm_crtc_set_property,
390 };
391 
sti_drm_crtc_is_main(struct drm_crtc * crtc)392 bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
393 {
394 	struct sti_mixer *mixer = to_sti_mixer(crtc);
395 
396 	if (mixer->id == STI_MIXER_MAIN)
397 		return true;
398 
399 	return false;
400 }
401 
sti_drm_crtc_init(struct drm_device * drm_dev,struct sti_mixer * mixer,struct drm_plane * primary,struct drm_plane * cursor)402 int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
403 		struct drm_plane *primary, struct drm_plane *cursor)
404 {
405 	struct drm_crtc *crtc = &mixer->drm_crtc;
406 	int res;
407 
408 	res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
409 			&sti_crtc_funcs);
410 	if (res) {
411 		DRM_ERROR("Can not initialze CRTC\n");
412 		return -EINVAL;
413 	}
414 
415 	drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
416 
417 	DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
418 			 crtc->base.id, sti_mixer_to_str(mixer));
419 
420 	return 0;
421 }
422