Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
  3 * Authors: Joonyoung Shim <jy0922.shim@samsung.com>
  4 *
  5 * This program is free software; you can redistribute  it and/or modify it
  6 * under  the terms of  the GNU General  Public License as published by the
  7 * Free Software Foundation;  either version 2 of the  License, or (at your
  8 * option) any later version.
  9 *
 10 */
 11
 12#include <drm/drmP.h>
 13
 14#include <drm/exynos_drm.h>
 15#include "exynos_drm_drv.h"
 16#include "exynos_drm_crtc.h"
 17#include "exynos_drm_fb.h"
 18#include "exynos_drm_gem.h"
 19#include "exynos_drm_plane.h"
 20
 21#define to_exynos_plane(x)	container_of(x, struct exynos_plane, base)
 22
 23struct exynos_plane {
 24	struct drm_plane		base;
 25	struct exynos_drm_overlay	overlay;
 26	bool				enabled;
 27};
 28
 29static const uint32_t formats[] = {
 30	DRM_FORMAT_XRGB8888,
 31	DRM_FORMAT_ARGB8888,
 32	DRM_FORMAT_NV12,
 33	DRM_FORMAT_NV12MT,
 34};
 35
 36/*
 37 * This function is to get X or Y size shown via screen. This needs length and
 38 * start position of CRTC.
 39 *
 40 *      <--- length --->
 41 * CRTC ----------------
 42 *      ^ start        ^ end
 43 *
 44 * There are six cases from a to f.
 45 *
 46 *             <----- SCREEN ----->
 47 *             0                 last
 48 *   ----------|------------------|----------
 49 * CRTCs
 50 * a -------
 51 *        b -------
 52 *        c --------------------------
 53 *                 d --------
 54 *                           e -------
 55 *                                  f -------
 56 */
 57static int exynos_plane_get_size(int start, unsigned length, unsigned last)
 58{
 59	int end = start + length;
 60	int size = 0;
 61
 62	if (start <= 0) {
 63		if (end > 0)
 64			size = min_t(unsigned, end, last);
 65	} else if (start <= last) {
 66		size = min_t(unsigned, last - start, length);
 67	}
 68
 69	return size;
 70}
 71
 72int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
 73			  struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 74			  unsigned int crtc_w, unsigned int crtc_h,
 75			  uint32_t src_x, uint32_t src_y,
 76			  uint32_t src_w, uint32_t src_h)
 77{
 78	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 79	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 80	unsigned int actual_w;
 81	unsigned int actual_h;
 82	int nr;
 83	int i;
 84
 85	nr = exynos_drm_fb_get_buf_cnt(fb);
 86	for (i = 0; i < nr; i++) {
 87		struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
 88
 89		if (!buffer) {
 90			DRM_DEBUG_KMS("buffer is null\n");
 91			return -EFAULT;
 92		}
 93
 94		overlay->dma_addr[i] = buffer->dma_addr;
 95
 96		DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
 97				i, (unsigned long)overlay->dma_addr[i]);
 98	}
 99
100	actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
101	actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
102
103	if (crtc_x < 0) {
104		if (actual_w)
105			src_x -= crtc_x;
106		crtc_x = 0;
107	}
108
109	if (crtc_y < 0) {
110		if (actual_h)
111			src_y -= crtc_y;
112		crtc_y = 0;
113	}
114
115	/* set drm framebuffer data. */
116	overlay->fb_x = src_x;
117	overlay->fb_y = src_y;
118	overlay->fb_width = fb->width;
119	overlay->fb_height = fb->height;
120	overlay->src_width = src_w;
121	overlay->src_height = src_h;
122	overlay->bpp = fb->bits_per_pixel;
123	overlay->pitch = fb->pitches[0];
124	overlay->pixel_format = fb->pixel_format;
125
126	/* set overlay range to be displayed. */
127	overlay->crtc_x = crtc_x;
128	overlay->crtc_y = crtc_y;
129	overlay->crtc_width = actual_w;
130	overlay->crtc_height = actual_h;
131
132	/* set drm mode data. */
133	overlay->mode_width = crtc->mode.hdisplay;
134	overlay->mode_height = crtc->mode.vdisplay;
135	overlay->refresh = crtc->mode.vrefresh;
136	overlay->scan_flag = crtc->mode.flags;
137
138	DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
139			overlay->crtc_x, overlay->crtc_y,
140			overlay->crtc_width, overlay->crtc_height);
141
142	exynos_drm_crtc_plane_mode_set(crtc, overlay);
143
144	return 0;
145}
146
147void exynos_plane_commit(struct drm_plane *plane)
148{
149	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
150	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
151
152	exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
153}
154
155void exynos_plane_dpms(struct drm_plane *plane, int mode)
156{
157	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
158	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
159
160	if (mode == DRM_MODE_DPMS_ON) {
161		if (exynos_plane->enabled)
162			return;
163
164		exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
165		exynos_plane->enabled = true;
166	} else {
167		if (!exynos_plane->enabled)
168			return;
169
170		exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
171		exynos_plane->enabled = false;
172	}
173}
174
175static int
176exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
177		     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
178		     unsigned int crtc_w, unsigned int crtc_h,
179		     uint32_t src_x, uint32_t src_y,
180		     uint32_t src_w, uint32_t src_h)
181{
182	int ret;
183
184	ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
185			crtc_w, crtc_h, src_x >> 16, src_y >> 16,
186			src_w >> 16, src_h >> 16);
187	if (ret < 0)
188		return ret;
189
190	plane->crtc = crtc;
191
192	exynos_plane_commit(plane);
193	exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
194
195	return 0;
196}
197
198static int exynos_disable_plane(struct drm_plane *plane)
199{
200	exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
201
202	return 0;
203}
204
205static void exynos_plane_destroy(struct drm_plane *plane)
206{
207	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
208
209	exynos_disable_plane(plane);
210	drm_plane_cleanup(plane);
211	kfree(exynos_plane);
212}
213
214static int exynos_plane_set_property(struct drm_plane *plane,
215				     struct drm_property *property,
216				     uint64_t val)
217{
218	struct drm_device *dev = plane->dev;
219	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
220	struct exynos_drm_private *dev_priv = dev->dev_private;
221
222	if (property == dev_priv->plane_zpos_property) {
223		exynos_plane->overlay.zpos = val;
224		return 0;
225	}
226
227	return -EINVAL;
228}
229
230static struct drm_plane_funcs exynos_plane_funcs = {
231	.update_plane	= exynos_update_plane,
232	.disable_plane	= exynos_disable_plane,
233	.destroy	= exynos_plane_destroy,
234	.set_property	= exynos_plane_set_property,
235};
236
237static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
238{
239	struct drm_device *dev = plane->dev;
240	struct exynos_drm_private *dev_priv = dev->dev_private;
241	struct drm_property *prop;
242
243	prop = dev_priv->plane_zpos_property;
244	if (!prop) {
245		prop = drm_property_create_range(dev, 0, "zpos", 0,
246						 MAX_PLANE - 1);
247		if (!prop)
248			return;
249
250		dev_priv->plane_zpos_property = prop;
251	}
252
253	drm_object_attach_property(&plane->base, prop, 0);
254}
255
256struct drm_plane *exynos_plane_init(struct drm_device *dev,
257				    unsigned long possible_crtcs, bool priv)
258{
259	struct exynos_plane *exynos_plane;
260	int err;
261
262	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
263	if (!exynos_plane)
264		return NULL;
265
266	err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
267			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
268			      priv);
269	if (err) {
270		DRM_ERROR("failed to initialize plane\n");
271		kfree(exynos_plane);
272		return NULL;
273	}
274
275	if (priv)
276		exynos_plane->overlay.zpos = DEFAULT_ZPOS;
277	else
278		exynos_plane_attach_zpos_property(&exynos_plane->base);
279
280	return &exynos_plane->base;
281}