exynos_drm_plane.c 6.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (C) 2011 Samsung Electronics Co.Ltd
 * Authors: Joonyoung Shim <jy0922.shim@samsung.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 */

#include "drmP.h"

#include "exynos_drm.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_encoder.h"
17 18
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
19

20 21
#define to_exynos_plane(x)	container_of(x, struct exynos_plane, base)

22 23 24 25 26 27
struct exynos_plane {
	struct drm_plane		base;
	struct exynos_drm_overlay	overlay;
	bool				enabled;
};

28 29
static const uint32_t formats[] = {
	DRM_FORMAT_XRGB8888,
30 31 32 33
	DRM_FORMAT_ARGB8888,
	DRM_FORMAT_NV12,
	DRM_FORMAT_NV12M,
	DRM_FORMAT_NV12MT,
34 35
};

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
			  struct drm_framebuffer *fb, int crtc_x, int crtc_y,
			  unsigned int crtc_w, unsigned int crtc_h,
			  uint32_t src_x, uint32_t src_y,
			  uint32_t src_w, uint32_t src_h)
{
	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
	unsigned int actual_w;
	unsigned int actual_h;
	int nr;
	int i;

	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);

	nr = exynos_drm_format_num_buffers(fb->pixel_format);
	for (i = 0; i < nr; i++) {
		struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);

		if (!buffer) {
			DRM_LOG_KMS("buffer is null\n");
			return -EFAULT;
		}

		overlay->dma_addr[i] = buffer->dma_addr;
		overlay->vaddr[i] = buffer->kvaddr;

		DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
				i, (unsigned long)overlay->vaddr[i],
				(unsigned long)overlay->dma_addr[i]);
	}

	actual_w = min((unsigned)(crtc->mode.hdisplay - crtc_x), crtc_w);
	actual_h = min((unsigned)(crtc->mode.vdisplay - crtc_y), crtc_h);

	/* set drm framebuffer data. */
	overlay->fb_x = src_x;
	overlay->fb_y = src_y;
	overlay->fb_width = fb->width;
	overlay->fb_height = fb->height;
	overlay->src_width = src_w;
	overlay->src_height = src_h;
	overlay->bpp = fb->bits_per_pixel;
	overlay->pitch = fb->pitches[0];
	overlay->pixel_format = fb->pixel_format;

	/* set overlay range to be displayed. */
	overlay->crtc_x = crtc_x;
	overlay->crtc_y = crtc_y;
	overlay->crtc_width = actual_w;
	overlay->crtc_height = actual_h;

	/* set drm mode data. */
	overlay->mode_width = crtc->mode.hdisplay;
	overlay->mode_height = crtc->mode.vdisplay;
	overlay->refresh = crtc->mode.vrefresh;
	overlay->scan_flag = crtc->mode.flags;

	DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
			overlay->crtc_x, overlay->crtc_y,
			overlay->crtc_width, overlay->crtc_height);

	exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);

	return 0;
}

void exynos_plane_commit(struct drm_plane *plane)
{
	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;

	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
			exynos_drm_encoder_plane_commit);

	exynos_plane->enabled = true;
}

114 115 116 117 118 119 120 121 122 123 124
static int
exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
		     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
		     unsigned int crtc_w, unsigned int crtc_h,
		     uint32_t src_x, uint32_t src_y,
		     uint32_t src_w, uint32_t src_h)
{
	int ret;

	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);

125 126 127
	ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
			crtc_w, crtc_h, src_x >> 16, src_y >> 16,
			src_w >> 16, src_h >> 16);
128 129 130
	if (ret < 0)
		return ret;

131 132
	plane->crtc = crtc;
	plane->fb = crtc->fb;
133

134
	exynos_plane_commit(plane);
135 136 137 138 139 140

	return 0;
}

static int exynos_disable_plane(struct drm_plane *plane)
{
141
	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
142 143 144 145 146 147 148 149
	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;

	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);

	if (!exynos_plane->enabled)
		return 0;

	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
150
			exynos_drm_encoder_plane_disable);
151 152 153 154 155 156 157 158 159

	exynos_plane->enabled = false;
	exynos_plane->overlay.zpos = DEFAULT_ZPOS;

	return 0;
}

static void exynos_plane_destroy(struct drm_plane *plane)
{
160
	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
161 162 163 164 165 166 167 168 169 170 171 172 173 174

	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);

	exynos_disable_plane(plane);
	drm_plane_cleanup(plane);
	kfree(exynos_plane);
}

static struct drm_plane_funcs exynos_plane_funcs = {
	.update_plane	= exynos_update_plane,
	.disable_plane	= exynos_disable_plane,
	.destroy	= exynos_plane_destroy,
};

175 176
struct drm_plane *exynos_plane_init(struct drm_device *dev,
				    unsigned int possible_crtcs, bool priv)
177 178
{
	struct exynos_plane *exynos_plane;
179
	int err;
180 181

	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
182 183 184 185
	if (!exynos_plane) {
		DRM_ERROR("failed to allocate plane\n");
		return NULL;
	}
186 187 188

	exynos_plane->overlay.zpos = DEFAULT_ZPOS;

189
	err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
190
			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
191 192 193 194 195 196 197 198
			      priv);
	if (err) {
		DRM_ERROR("failed to initialize plane\n");
		kfree(exynos_plane);
		return NULL;
	}

	return &exynos_plane->base;
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
}

int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
				struct drm_file *file_priv)
{
	struct drm_exynos_plane_set_zpos *zpos_req = data;
	struct drm_mode_object *obj;
	struct drm_plane *plane;
	struct exynos_plane *exynos_plane;
	int ret = 0;

	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);

	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;

	if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) {
		if (zpos_req->zpos != DEFAULT_ZPOS) {
			DRM_ERROR("zpos not within limits\n");
			return -EINVAL;
		}
	}

	mutex_lock(&dev->mode_config.mutex);

	obj = drm_mode_object_find(dev, zpos_req->plane_id,
			DRM_MODE_OBJECT_PLANE);
	if (!obj) {
		DRM_DEBUG_KMS("Unknown plane ID %d\n",
			      zpos_req->plane_id);
		ret = -EINVAL;
		goto out;
	}

	plane = obj_to_plane(obj);
234
	exynos_plane = to_exynos_plane(plane);
235 236 237 238 239 240 241

	exynos_plane->overlay.zpos = zpos_req->zpos;

out:
	mutex_unlock(&dev->mode_config.mutex);
	return ret;
}