1 /* exynos_drm_crtc.c
2  *
3  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4  * Authors:
5  *	Inki Dae <inki.dae@samsung.com>
6  *	Joonyoung Shim <jy0922.shim@samsung.com>
7  *	Seung-Woo Kim <sw0312.kim@samsung.com>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26  * OTHER DEALINGS IN THE SOFTWARE.
27  */
28 
29 #include "drmP.h"
30 #include "drm_crtc_helper.h"
31 
32 #include "exynos_drm_drv.h"
33 #include "exynos_drm_crtc.h"
34 #include "exynos_drm_fb.h"
35 #include "exynos_drm_encoder.h"
36 #include "exynos_drm_gem.h"
37 #include "exynos_drm_plane.h"
38 
39 #define to_exynos_crtc(x)	container_of(x, struct exynos_drm_crtc,\
40 				drm_crtc)
41 
42 /*
43  * Exynos specific crtc structure.
44  *
45  * @drm_crtc: crtc object.
46  * @drm_plane: pointer of private plane object for this crtc
47  * @pipe: a crtc index created at load() with a new crtc object creation
48  *	and the crtc object would be set to private->crtc array
49  *	to get a crtc object corresponding to this pipe from private->crtc
50  *	array when irq interrupt occured. the reason of using this pipe is that
51  *	drm framework doesn't support multiple irq yet.
52  *	we can refer to the crtc to current hardware interrupt occured through
53  *	this pipe value.
54  * @dpms: store the crtc dpms value
55  */
56 struct exynos_drm_crtc {
57 	struct drm_crtc			drm_crtc;
58 	struct drm_plane		*plane;
59 	unsigned int			pipe;
60 	unsigned int			dpms;
61 };
62 
63 static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
64 {
65 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
66 	struct exynos_drm_overlay *overlay =
67 		get_exynos_drm_overlay(exynos_crtc->plane);
68 
69 	exynos_drm_fn_encoder(crtc, overlay,
70 			exynos_drm_encoder_crtc_mode_set);
71 	exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit);
72 }
73 
74 int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
75 			      struct drm_framebuffer *fb,
76 			      struct drm_display_mode *mode,
77 			      struct exynos_drm_crtc_pos *pos)
78 {
79 	struct exynos_drm_gem_buf *buffer;
80 	unsigned int actual_w;
81 	unsigned int actual_h;
82 	int nr = exynos_drm_format_num_buffers(fb->pixel_format);
83 	int i;
84 
85 	for (i = 0; i < nr; i++) {
86 		buffer = exynos_drm_fb_buffer(fb, i);
87 		if (!buffer) {
88 			DRM_LOG_KMS("buffer is null\n");
89 			return -EFAULT;
90 		}
91 
92 		overlay->dma_addr[i] = buffer->dma_addr;
93 		overlay->vaddr[i] = buffer->kvaddr;
94 
95 		DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
96 				i, (unsigned long)overlay->vaddr[i],
97 				(unsigned long)overlay->dma_addr[i]);
98 	}
99 
100 	actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
101 	actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
102 
103 	/* set drm framebuffer data. */
104 	overlay->fb_x = pos->fb_x;
105 	overlay->fb_y = pos->fb_y;
106 	overlay->fb_width = fb->width;
107 	overlay->fb_height = fb->height;
108 	overlay->src_width = pos->src_w;
109 	overlay->src_height = pos->src_h;
110 	overlay->bpp = fb->bits_per_pixel;
111 	overlay->pitch = fb->pitches[0];
112 	overlay->pixel_format = fb->pixel_format;
113 
114 	/* set overlay range to be displayed. */
115 	overlay->crtc_x = pos->crtc_x;
116 	overlay->crtc_y = pos->crtc_y;
117 	overlay->crtc_width = actual_w;
118 	overlay->crtc_height = actual_h;
119 
120 	/* set drm mode data. */
121 	overlay->mode_width = mode->hdisplay;
122 	overlay->mode_height = mode->vdisplay;
123 	overlay->refresh = mode->vrefresh;
124 	overlay->scan_flag = mode->flags;
125 
126 	DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
127 			overlay->crtc_x, overlay->crtc_y,
128 			overlay->crtc_width, overlay->crtc_height);
129 
130 	return 0;
131 }
132 
133 static int exynos_drm_crtc_update(struct drm_crtc *crtc)
134 {
135 	struct exynos_drm_crtc *exynos_crtc;
136 	struct exynos_drm_overlay *overlay;
137 	struct exynos_drm_crtc_pos pos;
138 	struct drm_display_mode *mode = &crtc->mode;
139 	struct drm_framebuffer *fb = crtc->fb;
140 
141 	if (!mode || !fb)
142 		return -EINVAL;
143 
144 	exynos_crtc = to_exynos_crtc(crtc);
145 	overlay = get_exynos_drm_overlay(exynos_crtc->plane);
146 
147 	memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
148 
149 	/* it means the offset of framebuffer to be displayed. */
150 	pos.fb_x = crtc->x;
151 	pos.fb_y = crtc->y;
152 
153 	/* OSD position to be displayed. */
154 	pos.crtc_x = 0;
155 	pos.crtc_y = 0;
156 	pos.crtc_w = fb->width - crtc->x;
157 	pos.crtc_h = fb->height - crtc->y;
158 	pos.src_w = pos.crtc_w;
159 	pos.src_h = pos.crtc_h;
160 
161 	return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
162 }
163 
164 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
165 {
166 	struct drm_device *dev = crtc->dev;
167 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
168 
169 	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
170 
171 	if (exynos_crtc->dpms == mode) {
172 		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
173 		return;
174 	}
175 
176 	mutex_lock(&dev->struct_mutex);
177 
178 	switch (mode) {
179 	case DRM_MODE_DPMS_ON:
180 		exynos_drm_fn_encoder(crtc, &mode,
181 				exynos_drm_encoder_crtc_dpms);
182 		exynos_crtc->dpms = mode;
183 		break;
184 	case DRM_MODE_DPMS_STANDBY:
185 	case DRM_MODE_DPMS_SUSPEND:
186 	case DRM_MODE_DPMS_OFF:
187 		exynos_drm_fn_encoder(crtc, &mode,
188 				exynos_drm_encoder_crtc_dpms);
189 		exynos_crtc->dpms = mode;
190 		break;
191 	default:
192 		DRM_ERROR("unspecified mode %d\n", mode);
193 		break;
194 	}
195 
196 	mutex_unlock(&dev->struct_mutex);
197 }
198 
199 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
200 {
201 	DRM_DEBUG_KMS("%s\n", __FILE__);
202 
203 	/* drm framework doesn't check NULL. */
204 }
205 
206 static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
207 {
208 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
209 
210 	DRM_DEBUG_KMS("%s\n", __FILE__);
211 
212 	/*
213 	 * when set_crtc is requested from user or at booting time,
214 	 * crtc->commit would be called without dpms call so if dpms is
215 	 * no power on then crtc->dpms should be called
216 	 * with DRM_MODE_DPMS_ON for the hardware power to be on.
217 	 */
218 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
219 		int mode = DRM_MODE_DPMS_ON;
220 
221 		/*
222 		 * enable hardware(power on) to all encoders hdmi connected
223 		 * to current crtc.
224 		 */
225 		exynos_drm_crtc_dpms(crtc, mode);
226 		/*
227 		 * enable dma to all encoders connected to current crtc and
228 		 * lcd panel.
229 		 */
230 		exynos_drm_fn_encoder(crtc, &mode,
231 					exynos_drm_encoder_dpms_from_crtc);
232 	}
233 
234 	exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit);
235 }
236 
237 static bool
238 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
239 			    const struct drm_display_mode *mode,
240 			    struct drm_display_mode *adjusted_mode)
241 {
242 	DRM_DEBUG_KMS("%s\n", __FILE__);
243 
244 	/* drm framework doesn't check NULL */
245 	return true;
246 }
247 
248 static int
249 exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
250 			  struct drm_display_mode *adjusted_mode, int x, int y,
251 			  struct drm_framebuffer *old_fb)
252 {
253 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
254 	struct exynos_drm_overlay *overlay =
255 		get_exynos_drm_overlay(exynos_crtc->plane);
256 	int pipe = exynos_crtc->pipe;
257 	int ret;
258 
259 	DRM_DEBUG_KMS("%s\n", __FILE__);
260 
261 	/*
262 	 * copy the mode data adjusted by mode_fixup() into crtc->mode
263 	 * so that hardware can be seet to proper mode.
264 	 */
265 	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
266 
267 	ret = exynos_drm_crtc_update(crtc);
268 	if (ret)
269 		return ret;
270 
271 	exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_crtc_mode_set);
272 	exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
273 
274 	return 0;
275 }
276 
277 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
278 					  struct drm_framebuffer *old_fb)
279 {
280 	int ret;
281 
282 	DRM_DEBUG_KMS("%s\n", __FILE__);
283 
284 	ret = exynos_drm_crtc_update(crtc);
285 	if (ret)
286 		return ret;
287 
288 	exynos_drm_crtc_apply(crtc);
289 
290 	return ret;
291 }
292 
293 static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
294 {
295 	DRM_DEBUG_KMS("%s\n", __FILE__);
296 	/* drm framework doesn't check NULL */
297 }
298 
299 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
300 	.dpms		= exynos_drm_crtc_dpms,
301 	.prepare	= exynos_drm_crtc_prepare,
302 	.commit		= exynos_drm_crtc_commit,
303 	.mode_fixup	= exynos_drm_crtc_mode_fixup,
304 	.mode_set	= exynos_drm_crtc_mode_set,
305 	.mode_set_base	= exynos_drm_crtc_mode_set_base,
306 	.load_lut	= exynos_drm_crtc_load_lut,
307 };
308 
309 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
310 				      struct drm_framebuffer *fb,
311 				      struct drm_pending_vblank_event *event)
312 {
313 	struct drm_device *dev = crtc->dev;
314 	struct exynos_drm_private *dev_priv = dev->dev_private;
315 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
316 	struct drm_framebuffer *old_fb = crtc->fb;
317 	int ret = -EINVAL;
318 
319 	DRM_DEBUG_KMS("%s\n", __FILE__);
320 
321 	mutex_lock(&dev->struct_mutex);
322 
323 	if (event) {
324 		/*
325 		 * the pipe from user always is 0 so we can set pipe number
326 		 * of current owner to event.
327 		 */
328 		event->pipe = exynos_crtc->pipe;
329 
330 		ret = drm_vblank_get(dev, exynos_crtc->pipe);
331 		if (ret) {
332 			DRM_DEBUG("failed to acquire vblank counter\n");
333 			list_del(&event->base.link);
334 
335 			goto out;
336 		}
337 
338 		list_add_tail(&event->base.link,
339 				&dev_priv->pageflip_event_list);
340 
341 		crtc->fb = fb;
342 		ret = exynos_drm_crtc_update(crtc);
343 		if (ret) {
344 			crtc->fb = old_fb;
345 			drm_vblank_put(dev, exynos_crtc->pipe);
346 			list_del(&event->base.link);
347 
348 			goto out;
349 		}
350 
351 		/*
352 		 * the values related to a buffer of the drm framebuffer
353 		 * to be applied should be set at here. because these values
354 		 * first, are set to shadow registers and then to
355 		 * real registers at vsync front porch period.
356 		 */
357 		exynos_drm_crtc_apply(crtc);
358 	}
359 out:
360 	mutex_unlock(&dev->struct_mutex);
361 	return ret;
362 }
363 
364 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
365 {
366 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
367 	struct exynos_drm_private *private = crtc->dev->dev_private;
368 
369 	DRM_DEBUG_KMS("%s\n", __FILE__);
370 
371 	private->crtc[exynos_crtc->pipe] = NULL;
372 
373 	drm_crtc_cleanup(crtc);
374 	kfree(exynos_crtc);
375 }
376 
377 static struct drm_crtc_funcs exynos_crtc_funcs = {
378 	.set_config	= drm_crtc_helper_set_config,
379 	.page_flip	= exynos_drm_crtc_page_flip,
380 	.destroy	= exynos_drm_crtc_destroy,
381 };
382 
383 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
384 {
385 	struct exynos_drm_crtc *exynos_crtc;
386 	struct exynos_drm_private *private = dev->dev_private;
387 	struct drm_crtc *crtc;
388 
389 	DRM_DEBUG_KMS("%s\n", __FILE__);
390 
391 	exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
392 	if (!exynos_crtc) {
393 		DRM_ERROR("failed to allocate exynos crtc\n");
394 		return -ENOMEM;
395 	}
396 
397 	exynos_crtc->pipe = nr;
398 	exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
399 	exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
400 	if (!exynos_crtc->plane) {
401 		kfree(exynos_crtc);
402 		return -ENOMEM;
403 	}
404 
405 	crtc = &exynos_crtc->drm_crtc;
406 
407 	private->crtc[nr] = crtc;
408 
409 	drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
410 	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
411 
412 	return 0;
413 }
414 
415 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
416 {
417 	struct exynos_drm_private *private = dev->dev_private;
418 	struct exynos_drm_crtc *exynos_crtc =
419 		to_exynos_crtc(private->crtc[crtc]);
420 
421 	DRM_DEBUG_KMS("%s\n", __FILE__);
422 
423 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
424 		return -EPERM;
425 
426 	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
427 			exynos_drm_enable_vblank);
428 
429 	return 0;
430 }
431 
432 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
433 {
434 	struct exynos_drm_private *private = dev->dev_private;
435 	struct exynos_drm_crtc *exynos_crtc =
436 		to_exynos_crtc(private->crtc[crtc]);
437 
438 	DRM_DEBUG_KMS("%s\n", __FILE__);
439 
440 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
441 		return;
442 
443 	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
444 			exynos_drm_disable_vblank);
445 }
446