omap_plane.c 9.5 KB
Newer Older
1
/*
R
Rob Clark 已提交
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_helper.h>
21
#include <drm/drm_plane_helper.h>
22

23
#include "omap_dmm_tiler.h"
24
#include "omap_drv.h"
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

/* some hackery because omapdss has an 'enum omap_plane' (which would be
 * better named omap_plane_id).. and compiler seems unhappy about having
 * both a 'struct omap_plane' and 'enum omap_plane'
 */
#define omap_plane _omap_plane

/*
 * plane funcs
 */

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

struct omap_plane {
	struct drm_plane base;
40 41
	int id;  /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
	const char *name;
42

43 44
	uint32_t nformats;
	uint32_t formats[32];
45

46
	struct omap_drm_irq error_irq;
47
};
48

49 50 51 52 53 54 55 56
struct omap_plane_state {
	struct drm_plane_state base;

	unsigned int zorder;
};

static inline struct omap_plane_state *
to_omap_plane_state(struct drm_plane_state *state)
57
{
58 59 60
	return container_of(state, struct omap_plane_state, base);
}

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
static int omap_plane_prepare_fb(struct drm_plane *plane,
				 struct drm_framebuffer *fb,
				 const struct drm_plane_state *new_state)
{
	return omap_framebuffer_pin(fb);
}

static void omap_plane_cleanup_fb(struct drm_plane *plane,
				  struct drm_framebuffer *fb,
				  const struct drm_plane_state *old_state)
{
	omap_framebuffer_unpin(fb);
}

static void omap_plane_atomic_update(struct drm_plane *plane,
				     struct drm_plane_state *old_state)
77
{
78 79
	struct omap_plane *omap_plane = to_omap_plane(plane);
	struct drm_plane_state *state = plane->state;
80
	struct omap_plane_state *omap_state = to_omap_plane_state(state);
81 82
	struct omap_overlay_info info;
	struct omap_drm_window win;
83
	int ret;
84

85
	DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
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 114 115 116 117 118
	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;
	info.zorder = omap_state->zorder;

	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;

	switch (state->rotation & 0xf) {
	case BIT(DRM_ROTATE_90):
	case BIT(DRM_ROTATE_270):
		win.src_w = state->src_h >> 16;
		win.src_h = state->src_w >> 16;
		break;
	default:
		win.src_w = state->src_w >> 16;
		win.src_h = state->src_h >> 16;
		break;
	}
119

120
	/* update scanout: */
121
	omap_framebuffer_update_scanout(state->fb, &win, &info);
122

123 124 125 126 127
	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);
128

129
	dispc_ovl_set_channel_out(omap_plane->id,
130
				  omap_crtc_channel(state->crtc));
131

132
	/* and finally, update omapdss: */
133
	ret = dispc_ovl_setup(omap_plane->id, &info, false,
134
			      omap_crtc_timings(state->crtc), false);
135 136
	if (WARN_ON(ret)) {
		dispc_ovl_enable(omap_plane->id, false);
137
		return;
138
	}
139 140

	dispc_ovl_enable(omap_plane->id, true);
141 142 143 144
}

static void omap_plane_atomic_disable(struct drm_plane *plane,
				      struct drm_plane_state *old_state)
145
{
146
	struct omap_plane_state *omap_state = to_omap_plane_state(plane->state);
147
	struct omap_plane *omap_plane = to_omap_plane(plane);
148

149 150 151
	plane->state->rotation = BIT(DRM_ROTATE_0);
	omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
			   ? 0 : omap_plane->id;
152

153
	dispc_ovl_enable(omap_plane->id, false);
154 155
}

156 157 158 159 160 161 162
static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
	.prepare_fb = omap_plane_prepare_fb,
	.cleanup_fb = omap_plane_cleanup_fb,
	.atomic_update = omap_plane_atomic_update,
	.atomic_disable = omap_plane_atomic_disable,
};

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
static void omap_plane_reset(struct drm_plane *plane)
{
	struct omap_plane *omap_plane = to_omap_plane(plane);
	struct omap_plane_state *omap_state;

	if (plane->state && plane->state->fb)
		drm_framebuffer_unreference(plane->state->fb);

	kfree(plane->state);
	plane->state = NULL;

	omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
	if (omap_state == NULL)
		return;

	/*
	 * Set defaults depending on whether we are a primary or overlay
	 * plane.
	 */
	omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
			   ? 0 : omap_plane->id;
	omap_state->base.rotation = BIT(DRM_ROTATE_0);

	plane->state = &omap_state->base;
	plane->state->plane = plane;
}

190 191 192
static void omap_plane_destroy(struct drm_plane *plane)
{
	struct omap_plane *omap_plane = to_omap_plane(plane);
193 194 195 196 197

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

	omap_irq_unregister(plane->dev, &omap_plane->error_irq);

198
	drm_plane_cleanup(plane);
199

200 201 202
	kfree(omap_plane);
}

203 204 205 206 207 208 209
/* 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;

210
	if (priv->has_dmm) {
211 212
		struct drm_property *prop = dev->mode_config.rotation_property;

213
		drm_object_attach_property(obj, prop, 0);
214
	}
215

216
	drm_object_attach_property(obj, priv->zorder_prop, 0);
217 218
}

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
static struct drm_plane_state *
omap_plane_atomic_duplicate_state(struct drm_plane *plane)
{
	struct omap_plane_state *state;
	struct omap_plane_state *copy;

	if (WARN_ON(!plane->state))
		return NULL;

	state = to_omap_plane_state(plane->state);
	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
	if (copy == NULL)
		return NULL;

	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);

	return &copy->base;
}

static void omap_plane_atomic_destroy_state(struct drm_plane *plane,
					    struct drm_plane_state *state)
{
	__drm_atomic_helper_plane_destroy_state(plane, state);
	kfree(to_omap_plane_state(state));
}

static int omap_plane_atomic_set_property(struct drm_plane *plane,
					  struct drm_plane_state *state,
					  struct drm_property *property,
					  uint64_t val)
249 250
{
	struct omap_drm_private *priv = plane->dev->dev_private;
251
	struct omap_plane_state *omap_state = to_omap_plane_state(state);
252

253 254 255
	if (property == priv->zorder_prop)
		omap_state->zorder = val;
	else
256
		return -EINVAL;
257

258 259
	return 0;
}
260

261 262 263 264 265 266 267 268 269 270 271 272 273
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;
	const struct omap_plane_state *omap_state =
		container_of(state, const struct omap_plane_state, base);

	if (property == priv->zorder_prop)
		*val = omap_state->zorder;
	else
		return -EINVAL;
274

275
	return 0;
276 277
}

278
static const struct drm_plane_funcs omap_plane_funcs = {
279 280
	.update_plane = drm_atomic_helper_update_plane,
	.disable_plane = drm_atomic_helper_disable_plane,
281
	.reset = omap_plane_reset,
282
	.destroy = omap_plane_destroy,
283 284 285 286 287
	.set_property = drm_atomic_helper_plane_set_property,
	.atomic_duplicate_state = omap_plane_atomic_duplicate_state,
	.atomic_destroy_state = omap_plane_atomic_destroy_state,
	.atomic_set_property = omap_plane_atomic_set_property,
	.atomic_get_property = omap_plane_atomic_get_property,
288 289
};

290 291 292 293
static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{
	struct omap_plane *omap_plane =
			container_of(irq, struct omap_plane, error_irq);
294 295
	DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
		irqstatus);
296 297 298
}

static const char *plane_names[] = {
299 300 301 302
	[OMAP_DSS_GFX] = "gfx",
	[OMAP_DSS_VIDEO1] = "vid1",
	[OMAP_DSS_VIDEO2] = "vid2",
	[OMAP_DSS_VIDEO3] = "vid3",
303 304 305
};

static const uint32_t error_irqs[] = {
306 307 308 309
	[OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
	[OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
	[OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
	[OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
310 311
};

312 313
/* initialize plane */
struct drm_plane *omap_plane_init(struct drm_device *dev,
314
		int id, enum drm_plane_type type)
315
{
316
	struct omap_drm_private *priv = dev->dev_private;
317
	struct drm_plane *plane;
318
	struct omap_plane *omap_plane;
319
	int ret;
320

321
	DBG("%s: type=%d", plane_names[id], type);
322

323
	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
324
	if (!omap_plane)
325
		return ERR_PTR(-ENOMEM);
326

327 328
	omap_plane->nformats = omap_framebuffer_get_formats(
			omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
329 330 331 332
			dss_feat_get_supported_color_modes(id));
	omap_plane->id = id;
	omap_plane->name = plane_names[id];

333 334
	plane = &omap_plane->base;

335 336 337 338
	omap_plane->error_irq.irqmask = error_irqs[id];
	omap_plane->error_irq.irq = omap_plane_error_irq;
	omap_irq_register(dev, &omap_plane->error_irq);

339 340 341 342 343
	ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
				       &omap_plane_funcs, omap_plane->formats,
				       omap_plane->nformats, type);
	if (ret < 0)
		goto error;
344

345 346
	drm_plane_helper_add(plane, &omap_plane_helper_funcs);

347 348
	omap_plane_install_properties(plane, &plane->base);

349
	return plane;
350 351 352 353 354

error:
	omap_irq_unregister(plane->dev, &omap_plane->error_irq);
	kfree(omap_plane);
	return NULL;
355
}