omap_plane.c 8.89 KB
Newer Older
1
/*
Rob Clark's avatar
Rob Clark committed
2
 * drivers/gpu/drm/omapdrm/omap_plane.c
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Copyright (C) 2011 Texas Instruments
 * Author: Rob Clark <rob.clark@linaro.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

20
#include <drm/drm_atomic.h>
21
#include <drm/drm_atomic_helper.h>
22
#include <drm/drm_plane_helper.h>
23

24
#include "omap_dmm_tiler.h"
25
#include "omap_drv.h"
26 27 28 29 30 31 32 33 34

/*
 * plane funcs
 */

#define to_omap_plane(x) container_of(x, struct omap_plane, base)

struct omap_plane {
	struct drm_plane base;
35
	enum omap_plane_id id;
36
	const char *name;
37

38 39 40
	uint32_t nformats;
	uint32_t formats[32];
};
41

42
static int omap_plane_prepare_fb(struct drm_plane *plane,
43
				 struct drm_plane_state *new_state)
44
{
45 46 47 48
	if (!new_state->fb)
		return 0;

	return omap_framebuffer_pin(new_state->fb);
49 50 51
}

static void omap_plane_cleanup_fb(struct drm_plane *plane,
52
				  struct drm_plane_state *old_state)
53
{
54 55
	if (old_state->fb)
		omap_framebuffer_unpin(old_state->fb);
56 57 58 59
}

static void omap_plane_atomic_update(struct drm_plane *plane,
				     struct drm_plane_state *old_state)
60
{
Tomi Valkeinen's avatar
Tomi Valkeinen committed
61
	struct omap_drm_private *priv = plane->dev->dev_private;
62 63
	struct omap_plane *omap_plane = to_omap_plane(plane);
	struct drm_plane_state *state = plane->state;
64 65
	struct omap_overlay_info info;
	struct omap_drm_window win;
66
	int ret;
67

68
	DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
69

70 71 72 73 74
	memset(&info, 0, sizeof(info));
	info.rotation_type = OMAP_DSS_ROT_DMA;
	info.rotation = OMAP_DSS_ROT_0;
	info.global_alpha = 0xff;
	info.mirror = 0;
75
	info.zorder = state->zpos;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

	memset(&win, 0, sizeof(win));
	win.rotation = state->rotation;
	win.crtc_x = state->crtc_x;
	win.crtc_y = state->crtc_y;
	win.crtc_w = state->crtc_w;
	win.crtc_h = state->crtc_h;

	/*
	 * src values are in Q16 fixed point, convert to integer.
	 * omap_framebuffer_update_scanout() takes adjusted src.
	 */
	win.src_x = state->src_x >> 16;
	win.src_y = state->src_y >> 16;

91
	if (drm_rotation_90_or_270(state->rotation)) {
92 93
		win.src_w = state->src_h >> 16;
		win.src_h = state->src_w >> 16;
94
	} else {
95 96 97
		win.src_w = state->src_w >> 16;
		win.src_h = state->src_h >> 16;
	}
98

99
	/* update scanout: */
100
	omap_framebuffer_update_scanout(state->fb, &win, &info);
101

102 103 104 105 106
	DBG("%dx%d -> %dx%d (%d)", info.width, info.height,
			info.out_width, info.out_height,
			info.screen_width);
	DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
			&info.paddr, &info.p_uv_addr);
107

Tomi Valkeinen's avatar
Tomi Valkeinen committed
108
	priv->dispc_ops->ovl_set_channel_out(omap_plane->id,
109
				  omap_crtc_channel(state->crtc));
110

111
	/* and finally, update omapdss: */
112
	ret = priv->dispc_ops->ovl_setup(omap_plane->id, &info,
113
			      omap_crtc_timings(state->crtc), false);
114 115 116
	if (ret) {
		dev_err(plane->dev->dev, "Failed to setup plane %s\n",
			omap_plane->name);
Tomi Valkeinen's avatar
Tomi Valkeinen committed
117
		priv->dispc_ops->ovl_enable(omap_plane->id, false);
118
		return;
119
	}
120

Tomi Valkeinen's avatar
Tomi Valkeinen committed
121
	priv->dispc_ops->ovl_enable(omap_plane->id, true);
122 123 124 125
}

static void omap_plane_atomic_disable(struct drm_plane *plane,
				      struct drm_plane_state *old_state)
126
{
Tomi Valkeinen's avatar
Tomi Valkeinen committed
127
	struct omap_drm_private *priv = plane->dev->dev_private;
128
	struct omap_plane *omap_plane = to_omap_plane(plane);
129

130
	plane->state->rotation = DRM_MODE_ROTATE_0;
131
	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
132
			   ? 0 : omap_plane->id;
133

Tomi Valkeinen's avatar
Tomi Valkeinen committed
134
	priv->dispc_ops->ovl_enable(omap_plane->id, false);
135 136
}

137 138 139 140 141
static int omap_plane_atomic_check(struct drm_plane *plane,
				   struct drm_plane_state *state)
{
	struct drm_crtc_state *crtc_state;

142
	if (!state->fb)
143 144
		return 0;

145 146 147 148 149 150 151 152
	/* crtc should only be NULL when disabling (i.e., !state->fb) */
	if (WARN_ON(!state->crtc))
		return 0;

	crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
	/* we should have a crtc state if the plane is attached to a crtc */
	if (WARN_ON(!crtc_state))
		return 0;
153

154 155 156
	if (!crtc_state->enable)
		return 0;

157 158 159 160 161 162 163 164 165
	if (state->crtc_x < 0 || state->crtc_y < 0)
		return -EINVAL;

	if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
		return -EINVAL;

	if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
		return -EINVAL;

166
	if (state->rotation != DRM_MODE_ROTATE_0 &&
167 168
	    !omap_framebuffer_supports_rotation(state->fb))
		return -EINVAL;
169

170 171 172
	return 0;
}

173 174 175
static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
	.prepare_fb = omap_plane_prepare_fb,
	.cleanup_fb = omap_plane_cleanup_fb,
176
	.atomic_check = omap_plane_atomic_check,
177 178 179 180
	.atomic_update = omap_plane_atomic_update,
	.atomic_disable = omap_plane_atomic_disable,
};

181 182 183
static void omap_plane_destroy(struct drm_plane *plane)
{
	struct omap_plane *omap_plane = to_omap_plane(plane);
184 185 186

	DBG("%s", omap_plane->name);

187
	drm_plane_cleanup(plane);
188

189 190 191
	kfree(omap_plane);
}

192 193 194 195 196 197 198
/* helper to install properties which are common to planes and crtcs */
void omap_plane_install_properties(struct drm_plane *plane,
		struct drm_mode_object *obj)
{
	struct drm_device *dev = plane->dev;
	struct omap_drm_private *priv = dev->dev_private;

199
	if (priv->has_dmm) {
200 201
		if (!plane->rotation_property)
			drm_plane_create_rotation_property(plane,
202 203 204 205
							   DRM_MODE_ROTATE_0,
							   DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
							   DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
							   DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
206 207 208 209

		/* Attach the rotation property also to the crtc object */
		if (plane->rotation_property && obj != &plane->base)
			drm_object_attach_property(obj, plane->rotation_property,
210
						   DRM_MODE_ROTATE_0);
211
	}
212

213
	drm_object_attach_property(obj, priv->zorder_prop, 0);
214 215
}

216 217 218 219
static void omap_plane_reset(struct drm_plane *plane)
{
	struct omap_plane *omap_plane = to_omap_plane(plane);

220 221
	drm_atomic_helper_plane_reset(plane);
	if (!plane->state)
222 223 224
		return;

	/*
225
	 * Set the zpos default depending on whether we are a primary or overlay
226 227
	 * plane.
	 */
228 229
	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
			   ? 0 : omap_plane->id;
230 231
}

232 233 234 235
static int omap_plane_atomic_set_property(struct drm_plane *plane,
					  struct drm_plane_state *state,
					  struct drm_property *property,
					  uint64_t val)
236 237 238
{
	struct omap_drm_private *priv = plane->dev->dev_private;

239
	if (property == priv->zorder_prop)
240
		state->zpos = val;
241
	else
242
		return -EINVAL;
243

244 245
	return 0;
}
246

247 248 249 250 251 252 253 254
static int omap_plane_atomic_get_property(struct drm_plane *plane,
					  const struct drm_plane_state *state,
					  struct drm_property *property,
					  uint64_t *val)
{
	struct omap_drm_private *priv = plane->dev->dev_private;

	if (property == priv->zorder_prop)
255
		*val = state->zpos;
256 257
	else
		return -EINVAL;
258

259
	return 0;
260 261
}

262
static const struct drm_plane_funcs omap_plane_funcs = {
263 264
	.update_plane = drm_atomic_helper_update_plane,
	.disable_plane = drm_atomic_helper_disable_plane,
265
	.reset = omap_plane_reset,
266
	.destroy = omap_plane_destroy,
267
	.set_property = drm_atomic_helper_plane_set_property,
268 269
	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
270 271
	.atomic_set_property = omap_plane_atomic_set_property,
	.atomic_get_property = omap_plane_atomic_get_property,
272 273
};

274
static const char *plane_id_to_name[] = {
275 276 277 278
	[OMAP_DSS_GFX] = "gfx",
	[OMAP_DSS_VIDEO1] = "vid1",
	[OMAP_DSS_VIDEO2] = "vid2",
	[OMAP_DSS_VIDEO3] = "vid3",
279 280
};

281 282 283 284 285 286 287
static const enum omap_plane_id plane_idx_to_id[] = {
	OMAP_DSS_GFX,
	OMAP_DSS_VIDEO1,
	OMAP_DSS_VIDEO2,
	OMAP_DSS_VIDEO3,
};

288 289
/* initialize plane */
struct drm_plane *omap_plane_init(struct drm_device *dev,
290
		int idx, enum drm_plane_type type,
291
		u32 possible_crtcs)
292
{
Tomi Valkeinen's avatar
Tomi Valkeinen committed
293
	struct omap_drm_private *priv = dev->dev_private;
294
	unsigned int num_planes = priv->dispc_ops->get_num_ovls();
295
	struct drm_plane *plane;
296
	struct omap_plane *omap_plane;
297
	enum omap_plane_id id;
298
	int ret;
299

300 301 302 303 304 305
	if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id)))
		return ERR_PTR(-EINVAL);

	id = plane_idx_to_id[idx];

	DBG("%s: type=%d", plane_id_to_name[id], type);
306

307
	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
308
	if (!omap_plane)
309
		return ERR_PTR(-ENOMEM);
310

311 312
	omap_plane->nformats = omap_framebuffer_get_formats(
			omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
Tomi Valkeinen's avatar
Tomi Valkeinen committed
313
			priv->dispc_ops->ovl_get_color_modes(id));
314
	omap_plane->id = id;
315
	omap_plane->name = plane_id_to_name[id];
316

317 318
	plane = &omap_plane->base;

319
	ret = drm_universal_plane_init(dev, plane, possible_crtcs,
320
				       &omap_plane_funcs, omap_plane->formats,
321
				       omap_plane->nformats, type, NULL);
322 323
	if (ret < 0)
		goto error;
324

325 326
	drm_plane_helper_add(plane, &omap_plane_helper_funcs);

327
	omap_plane_install_properties(plane, &plane->base);
328
	drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
329

330
	return plane;
331 332

error:
333 334 335
	dev_err(dev->dev, "%s(): could not create plane: %s\n",
		__func__, plane_id_to_name[id]);

336 337
	kfree(omap_plane);
	return NULL;
338
}