xref: /linux/drivers/gpu/drm/exynos/exynos_drm_plane.c (revision b43ab901d671e3e3cad425ea5e9a3c74e266dcdd)
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 "drmP.h"
13 
14 #include "exynos_drm.h"
15 #include "exynos_drm_crtc.h"
16 #include "exynos_drm_drv.h"
17 #include "exynos_drm_encoder.h"
18 
19 struct exynos_plane {
20 	struct drm_plane		base;
21 	struct exynos_drm_overlay	overlay;
22 	bool				enabled;
23 };
24 
25 static int
26 exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
27 		     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
28 		     unsigned int crtc_w, unsigned int crtc_h,
29 		     uint32_t src_x, uint32_t src_y,
30 		     uint32_t src_w, uint32_t src_h)
31 {
32 	struct exynos_plane *exynos_plane =
33 		container_of(plane, struct exynos_plane, base);
34 	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
35 	struct exynos_drm_crtc_pos pos;
36 	unsigned int x = src_x >> 16;
37 	unsigned int y = src_y >> 16;
38 	int ret;
39 
40 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
41 
42 	memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
43 	pos.crtc_x = crtc_x;
44 	pos.crtc_y = crtc_y;
45 	pos.crtc_w = crtc_w;
46 	pos.crtc_h = crtc_h;
47 
48 	pos.fb_x = x;
49 	pos.fb_y = y;
50 
51 	/* TODO: scale feature */
52 	ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos);
53 	if (ret < 0)
54 		return ret;
55 
56 	exynos_drm_fn_encoder(crtc, overlay,
57 			exynos_drm_encoder_crtc_mode_set);
58 	exynos_drm_fn_encoder(crtc, &overlay->zpos,
59 			exynos_drm_encoder_crtc_plane_commit);
60 
61 	exynos_plane->enabled = true;
62 
63 	return 0;
64 }
65 
66 static int exynos_disable_plane(struct drm_plane *plane)
67 {
68 	struct exynos_plane *exynos_plane =
69 		container_of(plane, struct exynos_plane, base);
70 	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
71 
72 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
73 
74 	if (!exynos_plane->enabled)
75 		return 0;
76 
77 	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
78 			exynos_drm_encoder_crtc_disable);
79 
80 	exynos_plane->enabled = false;
81 	exynos_plane->overlay.zpos = DEFAULT_ZPOS;
82 
83 	return 0;
84 }
85 
86 static void exynos_plane_destroy(struct drm_plane *plane)
87 {
88 	struct exynos_plane *exynos_plane =
89 		container_of(plane, struct exynos_plane, base);
90 
91 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
92 
93 	exynos_disable_plane(plane);
94 	drm_plane_cleanup(plane);
95 	kfree(exynos_plane);
96 }
97 
98 static struct drm_plane_funcs exynos_plane_funcs = {
99 	.update_plane	= exynos_update_plane,
100 	.disable_plane	= exynos_disable_plane,
101 	.destroy	= exynos_plane_destroy,
102 };
103 
104 int exynos_plane_init(struct drm_device *dev, unsigned int nr)
105 {
106 	struct exynos_plane *exynos_plane;
107 	uint32_t possible_crtcs;
108 
109 	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
110 	if (!exynos_plane)
111 		return -ENOMEM;
112 
113 	/* all CRTCs are available */
114 	possible_crtcs = (1 << MAX_CRTC) - 1;
115 
116 	exynos_plane->overlay.zpos = DEFAULT_ZPOS;
117 
118 	/* TODO: format */
119 	return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
120 			      &exynos_plane_funcs, NULL, 0, false);
121 }
122 
123 int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
124 				struct drm_file *file_priv)
125 {
126 	struct drm_exynos_plane_set_zpos *zpos_req = data;
127 	struct drm_mode_object *obj;
128 	struct drm_plane *plane;
129 	struct exynos_plane *exynos_plane;
130 	int ret = 0;
131 
132 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
133 
134 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
135 		return -EINVAL;
136 
137 	if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) {
138 		if (zpos_req->zpos != DEFAULT_ZPOS) {
139 			DRM_ERROR("zpos not within limits\n");
140 			return -EINVAL;
141 		}
142 	}
143 
144 	mutex_lock(&dev->mode_config.mutex);
145 
146 	obj = drm_mode_object_find(dev, zpos_req->plane_id,
147 			DRM_MODE_OBJECT_PLANE);
148 	if (!obj) {
149 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
150 			      zpos_req->plane_id);
151 		ret = -EINVAL;
152 		goto out;
153 	}
154 
155 	plane = obj_to_plane(obj);
156 	exynos_plane = container_of(plane, struct exynos_plane, base);
157 
158 	exynos_plane->overlay.zpos = zpos_req->zpos;
159 
160 out:
161 	mutex_unlock(&dev->mode_config.mutex);
162 	return ret;
163 }
164