mdp4_crtc.c 18.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
 * 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/>.
 */

18 19 20
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_flip_work.h>
21
#include <drm/drm_mode.h>
22 23

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

struct mdp4_crtc {
	struct drm_crtc base;
	char name[8];
	int id;
	int ovlp;
	enum mdp4_dma dma;
	bool enabled;

	/* which mixer/encoder we route output to: */
	int mixer;

	struct {
		spinlock_t lock;
		bool stale;
		uint32_t width, height;
R
Rob Clark 已提交
40
		uint32_t x, y;
41 42 43 44 45 46 47 48 49 50 51 52 53

		/* next cursor to scan-out: */
		uint32_t next_iova;
		struct drm_gem_object *next_bo;

		/* current cursor being scanned out: */
		struct drm_gem_object *scanout_bo;
	} cursor;


	/* if there is a pending flip, these will be non-null: */
	struct drm_pending_vblank_event *event;

54 55 56 57 58
	/* Bits have been flushed at the last commit,
	 * used to decide if a vsync has happened since last commit.
	 */
	u32 flushed_mask;

R
Rob Clark 已提交
59 60 61 62
#define PENDING_CURSOR 0x1
#define PENDING_FLIP   0x2
	atomic_t pending;

63 64 65
	/* for unref'ing cursor bo's after scanout completes: */
	struct drm_flip_work unref_cursor_work;

R
Rob Clark 已提交
66 67
	struct mdp_irq vblank;
	struct mdp_irq err;
68 69 70 71 72 73
};
#define to_mdp4_crtc(x) container_of(x, struct mdp4_crtc, base)

static struct mdp4_kms *get_kms(struct drm_crtc *crtc)
{
	struct msm_drm_private *priv = crtc->dev->dev_private;
R
Rob Clark 已提交
74
	return to_mdp4_kms(to_mdp_kms(priv->kms));
75 76
}

R
Rob Clark 已提交
77
static void request_pending(struct drm_crtc *crtc, uint32_t pending)
78 79 80
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);

R
Rob Clark 已提交
81 82 83 84 85 86 87 88
	atomic_or(pending, &mdp4_crtc->pending);
	mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
}

static void crtc_flush(struct drm_crtc *crtc)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
89 90
	struct drm_plane *plane;
	uint32_t flush = 0;
R
Rob Clark 已提交
91

92
	drm_atomic_crtc_for_each_plane(plane, crtc) {
93 94
		enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
		flush |= pipe2flush(pipe_id);
R
Rob Clark 已提交
95
	}
96

R
Rob Clark 已提交
97 98 99 100
	flush |= ovlp2flush(mdp4_crtc->ovlp);

	DBG("%s: flush=%08x", mdp4_crtc->name, flush);

101 102
	mdp4_crtc->flushed_mask = flush;

R
Rob Clark 已提交
103 104 105
	mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
}

R
Rob Clark 已提交
106 107
/* if file!=NULL, this is preclose potential cancel-flip path */
static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
108 109 110 111 112 113 114 115 116
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct drm_device *dev = crtc->dev;
	struct drm_pending_vblank_event *event;
	unsigned long flags;

	spin_lock_irqsave(&dev->event_lock, flags);
	event = mdp4_crtc->event;
	if (event) {
117 118 119
		mdp4_crtc->event = NULL;
		DBG("%s: send event: %p", mdp4_crtc->name, event);
		drm_crtc_send_vblank_event(crtc, event);
120 121 122 123 124 125 126 127 128
	}
	spin_unlock_irqrestore(&dev->event_lock, flags);
}

static void unref_cursor_worker(struct drm_flip_work *work, void *val)
{
	struct mdp4_crtc *mdp4_crtc =
		container_of(work, struct mdp4_crtc, unref_cursor_work);
	struct mdp4_kms *mdp4_kms = get_kms(&mdp4_crtc->base);
129
	struct msm_kms *kms = &mdp4_kms->base.base;
130

131
	msm_gem_put_iova(val, kms->aspace);
132
	drm_gem_object_put_unlocked(val);
133 134 135 136 137 138 139 140 141 142 143 144
}

static void mdp4_crtc_destroy(struct drm_crtc *crtc)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);

	drm_crtc_cleanup(crtc);
	drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work);

	kfree(mdp4_crtc);
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
/* statically (for now) map planes to mixer stage (z-order): */
static const int idxs[] = {
		[VG1]  = 1,
		[VG2]  = 2,
		[RGB1] = 0,
		[RGB2] = 0,
		[RGB3] = 0,
		[VG3]  = 3,
		[VG4]  = 4,

};

/* setup mixer config, for which we need to consider all crtc's and
 * the planes attached to them
 *
 * TODO may possibly need some extra locking here
 */
static void setup_mixer(struct mdp4_kms *mdp4_kms)
163
{
164 165
	struct drm_mode_config *config = &mdp4_kms->dev->mode_config;
	struct drm_crtc *crtc;
166
	uint32_t mixer_cfg = 0;
R
Rob Clark 已提交
167
	static const enum mdp_mixer_stage_id stages[] = {
R
Rob Clark 已提交
168 169 170
			STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
	};

171 172 173
	list_for_each_entry(crtc, &config->crtc_list, head) {
		struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
		struct drm_plane *plane;
174

175
		drm_atomic_crtc_for_each_plane(plane, crtc) {
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
			enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
			int idx = idxs[pipe_id];
			mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
					pipe_id, stages[idx]);
		}
	}

	mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
}

static void blend_setup(struct drm_crtc *crtc)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
	struct drm_plane *plane;
	int i, ovlp = mdp4_crtc->ovlp;
	bool alpha[4]= { false, false, false, false };
193

194 195 196 197 198
	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);

199
	drm_atomic_crtc_for_each_plane(plane, crtc) {
200 201 202 203
		enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
		int idx = idxs[pipe_id];
		if (idx > 0) {
			const struct mdp_format *format =
R
Rob Clark 已提交
204
					to_mdp_format(msm_framebuffer_format(plane->fb));
205
			alpha[idx-1] = format->alpha_enable;
R
Rob Clark 已提交
206 207 208
		}
	}

209
	for (i = 0; i < 4; i++) {
R
Rob Clark 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
		uint32_t op;

		if (alpha[i]) {
			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_PIXEL) |
					MDP4_OVLP_STAGE_OP_BG_ALPHA(FG_PIXEL) |
					MDP4_OVLP_STAGE_OP_BG_INV_ALPHA;
		} else {
			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) |
					MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST);
		}

		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0xff);
		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0x00);
		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i), op);
		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 1);
225 226 227 228 229 230
		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW0(ovlp, i), 0);
		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW1(ovlp, i), 0);
		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(ovlp, i), 0);
		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
	}

231
	setup_mixer(mdp4_kms);
232 233
}

R
Rob Clark 已提交
234
static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
235 236 237 238
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
	enum mdp4_dma dma = mdp4_crtc->dma;
R
Rob Clark 已提交
239 240 241 242 243
	int ovlp = mdp4_crtc->ovlp;
	struct drm_display_mode *mode;

	if (WARN_ON(!crtc->state))
		return;
244

R
Rob Clark 已提交
245
	mode = &crtc->state->adjusted_mode;
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
			mdp4_crtc->name, mode->base.id, mode->name,
			mode->vrefresh, mode->clock,
			mode->hdisplay, mode->hsync_start,
			mode->hsync_end, mode->htotal,
			mode->vdisplay, mode->vsync_start,
			mode->vsync_end, mode->vtotal,
			mode->type, mode->flags);

	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma),
			MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) |
			MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay));

	/* take data from pipe: */
	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
262
	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), 0);
263 264 265 266 267 268 269 270
	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
			MDP4_DMA_DST_SIZE_WIDTH(0) |
			MDP4_DMA_DST_SIZE_HEIGHT(0));

	mdp4_write(mdp4_kms, REG_MDP4_OVLP_BASE(ovlp), 0);
	mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp),
			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
271
	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), 0);
272 273 274 275 276 277 278 279 280 281

	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);

	if (dma == DMA_E) {
		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000);
		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000);
		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
	}
}

282 283
static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc,
				     struct drm_crtc_state *old_state)
284 285
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
286 287
	struct mdp4_kms *mdp4_kms = get_kms(crtc);

288
	DBG("%s", mdp4_crtc->name);
289 290 291 292

	if (WARN_ON(!mdp4_crtc->enabled))
		return;

293 294 295
	/* Disable/save vblank irq handling before power is disabled */
	drm_crtc_vblank_off(crtc);

296 297 298 299
	mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
	mdp4_disable(mdp4_kms);

	mdp4_crtc->enabled = false;
300 301
}

302 303
static void mdp4_crtc_atomic_enable(struct drm_crtc *crtc,
				    struct drm_crtc_state *old_state)
304
{
305 306 307 308 309 310 311 312 313
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);

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

	if (WARN_ON(mdp4_crtc->enabled))
		return;

	mdp4_enable(mdp4_kms);
314 315 316 317

	/* Restore vblank irq handling after power is enabled */
	drm_crtc_vblank_on(crtc);

318 319
	mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);

320
	crtc_flush(crtc);
321 322

	mdp4_crtc->enabled = true;
323 324
}

R
Rob Clark 已提交
325 326
static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
327
{
R
Rob Clark 已提交
328 329 330
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	DBG("%s: check", mdp4_crtc->name);
	// TODO anything else to check?
R
Rob Clark 已提交
331
	return 0;
332 333
}

334 335
static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc,
				   struct drm_crtc_state *old_crtc_state)
336
{
R
Rob Clark 已提交
337 338
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	DBG("%s: begin", mdp4_crtc->name);
339 340
}

341 342
static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc,
				   struct drm_crtc_state *old_crtc_state)
343 344 345
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct drm_device *dev = crtc->dev;
R
Rob Clark 已提交
346
	unsigned long flags;
347

348
	DBG("%s: event: %p", mdp4_crtc->name, crtc->state->event);
349

R
Rob Clark 已提交
350
	WARN_ON(mdp4_crtc->event);
351

R
Rob Clark 已提交
352
	spin_lock_irqsave(&dev->event_lock, flags);
R
Rob Clark 已提交
353
	mdp4_crtc->event = crtc->state->event;
R
Rob Clark 已提交
354 355
	spin_unlock_irqrestore(&dev->event_lock, flags);

R
Rob Clark 已提交
356 357 358
	blend_setup(crtc);
	crtc_flush(crtc);
	request_pending(crtc, PENDING_FLIP);
359 360 361 362 363 364 365 366 367 368 369 370 371
}

#define CURSOR_WIDTH 64
#define CURSOR_HEIGHT 64

/* called from IRQ to update cursor related registers (if needed).  The
 * cursor registers, other than x/y position, appear not to be double
 * buffered, and changing them other than from vblank seems to trigger
 * underflow.
 */
static void update_cursor(struct drm_crtc *crtc)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
R
Rob Clark 已提交
372
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
373
	struct msm_kms *kms = &mdp4_kms->base.base;
374 375 376 377 378 379 380
	enum mdp4_dma dma = mdp4_crtc->dma;
	unsigned long flags;

	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
	if (mdp4_crtc->cursor.stale) {
		struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo;
		struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo;
R
Rob Clark 已提交
381
		uint64_t iova = mdp4_crtc->cursor.next_iova;
382 383 384

		if (next_bo) {
			/* take a obj ref + iova ref when we start scanning out: */
385
			drm_gem_object_get(next_bo);
386
			msm_gem_get_iova(next_bo, kms->aspace, &iova);
387 388 389 390 391 392 393 394 395 396 397

			/* enable cursor: */
			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_SIZE(dma),
					MDP4_DMA_CURSOR_SIZE_WIDTH(mdp4_crtc->cursor.width) |
					MDP4_DMA_CURSOR_SIZE_HEIGHT(mdp4_crtc->cursor.height));
			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), iova);
			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma),
					MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB) |
					MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN);
		} else {
			/* disable cursor: */
398 399
			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma),
					mdp4_kms->blank_cursor_iova);
400 401 402 403 404 405 406 407 408
		}

		/* and drop the iova ref + obj rev when done scanning out: */
		if (prev_bo)
			drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, prev_bo);

		mdp4_crtc->cursor.scanout_bo = next_bo;
		mdp4_crtc->cursor.stale = false;
	}
R
Rob Clark 已提交
409 410 411 412 413

	mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma),
			MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) |
			MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y));

414 415 416 417 418 419 420 421 422
	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
}

static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
		struct drm_file *file_priv, uint32_t handle,
		uint32_t width, uint32_t height)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
423
	struct msm_kms *kms = &mdp4_kms->base.base;
424 425 426
	struct drm_device *dev = crtc->dev;
	struct drm_gem_object *cursor_bo, *old_bo;
	unsigned long flags;
R
Rob Clark 已提交
427
	uint64_t iova;
428 429 430 431 432 433 434 435
	int ret;

	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
		dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
		return -EINVAL;
	}

	if (handle) {
436
		cursor_bo = drm_gem_object_lookup(file_priv, handle);
437 438 439 440 441 442 443
		if (!cursor_bo)
			return -ENOENT;
	} else {
		cursor_bo = NULL;
	}

	if (cursor_bo) {
444
		ret = msm_gem_get_iova(cursor_bo, kms->aspace, &iova);
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
		if (ret)
			goto fail;
	} else {
		iova = 0;
	}

	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
	old_bo = mdp4_crtc->cursor.next_bo;
	mdp4_crtc->cursor.next_bo   = cursor_bo;
	mdp4_crtc->cursor.next_iova = iova;
	mdp4_crtc->cursor.width     = width;
	mdp4_crtc->cursor.height    = height;
	mdp4_crtc->cursor.stale     = true;
	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);

	if (old_bo) {
		/* drop our previous reference: */
462
		drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, old_bo);
463 464
	}

R
Rob Clark 已提交
465 466
	request_pending(crtc, PENDING_CURSOR);

467 468 469
	return 0;

fail:
470
	drm_gem_object_put_unlocked(cursor_bo);
471 472 473 474 475 476
	return ret;
}

static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
R
Rob Clark 已提交
477
	unsigned long flags;
478

R
Rob Clark 已提交
479 480 481 482 483 484 485
	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
	mdp4_crtc->cursor.x = x;
	mdp4_crtc->cursor.y = y;
	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);

	crtc_flush(crtc);
	request_pending(crtc, PENDING_CURSOR);
486 487 488 489 490

	return 0;
}

static const struct drm_crtc_funcs mdp4_crtc_funcs = {
R
Rob Clark 已提交
491
	.set_config = drm_atomic_helper_set_config,
492
	.destroy = mdp4_crtc_destroy,
R
Rob Clark 已提交
493
	.page_flip = drm_atomic_helper_page_flip,
494 495
	.cursor_set = mdp4_crtc_cursor_set,
	.cursor_move = mdp4_crtc_cursor_move,
R
Rob Clark 已提交
496 497 498
	.reset = drm_atomic_helper_crtc_reset,
	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
499 500 501
};

static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
R
Rob Clark 已提交
502 503 504 505
	.mode_set_nofb = mdp4_crtc_mode_set_nofb,
	.atomic_check = mdp4_crtc_atomic_check,
	.atomic_begin = mdp4_crtc_atomic_begin,
	.atomic_flush = mdp4_crtc_atomic_flush,
506
	.atomic_enable = mdp4_crtc_atomic_enable,
507
	.atomic_disable = mdp4_crtc_atomic_disable,
508 509
};

R
Rob Clark 已提交
510
static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
511 512 513 514
{
	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank);
	struct drm_crtc *crtc = &mdp4_crtc->base;
	struct msm_drm_private *priv = crtc->dev->dev_private;
R
Rob Clark 已提交
515
	unsigned pending;
516

R
Rob Clark 已提交
517
	mdp_irq_unregister(&get_kms(crtc)->base, &mdp4_crtc->vblank);
518

R
Rob Clark 已提交
519 520 521 522 523 524 525 526 527 528
	pending = atomic_xchg(&mdp4_crtc->pending, 0);

	if (pending & PENDING_FLIP) {
		complete_flip(crtc, NULL);
	}

	if (pending & PENDING_CURSOR) {
		update_cursor(crtc);
		drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq);
	}
529 530
}

R
Rob Clark 已提交
531
static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
532 533 534 535 536 537 538
{
	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, err);
	struct drm_crtc *crtc = &mdp4_crtc->base;
	DBG("%s: error: %08x", mdp4_crtc->name, irqstatus);
	crtc_flush(crtc);
}

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
static void mdp4_crtc_wait_for_flush_done(struct drm_crtc *crtc)
{
	struct drm_device *dev = crtc->dev;
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
	int ret;

	ret = drm_crtc_vblank_get(crtc);
	if (ret)
		return;

	ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue,
		!(mdp4_read(mdp4_kms, REG_MDP4_OVERLAY_FLUSH) &
			mdp4_crtc->flushed_mask),
		msecs_to_jiffies(50));
	if (ret <= 0)
		dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp4_crtc->id);

	mdp4_crtc->flushed_mask = 0;

	drm_crtc_vblank_put(crtc);
}

562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	return mdp4_crtc->vblank.irqmask;
}

/* set dma config, ie. the format the encoder wants. */
void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config)
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);

	mdp4_write(mdp4_kms, REG_MDP4_DMA_CONFIG(mdp4_crtc->dma), config);
}

/* set interface for routing crtc->encoder: */
578
void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
{
	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
	struct mdp4_kms *mdp4_kms = get_kms(crtc);
	uint32_t intf_sel;

	intf_sel = mdp4_read(mdp4_kms, REG_MDP4_DISP_INTF_SEL);

	switch (mdp4_crtc->dma) {
	case DMA_P:
		intf_sel &= ~MDP4_DISP_INTF_SEL_PRIM__MASK;
		intf_sel |= MDP4_DISP_INTF_SEL_PRIM(intf);
		break;
	case DMA_S:
		intf_sel &= ~MDP4_DISP_INTF_SEL_SEC__MASK;
		intf_sel |= MDP4_DISP_INTF_SEL_SEC(intf);
		break;
	case DMA_E:
		intf_sel &= ~MDP4_DISP_INTF_SEL_EXT__MASK;
		intf_sel |= MDP4_DISP_INTF_SEL_EXT(intf);
		break;
	}

	if (intf == INTF_DSI_VIDEO) {
		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD;
		intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO;
	} else if (intf == INTF_DSI_CMD) {
		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO;
		intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD;
	}

609 610
	mdp4_crtc->mixer = mixer;

611 612 613 614 615 616 617
	blend_setup(crtc);

	DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel);

	mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel);
}

618 619 620 621 622 623 624 625 626
void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc)
{
	/* wait_for_flush_done is the only case for now.
	 * Later we will have command mode CRTC to wait for
	 * other event.
	 */
	mdp4_crtc_wait_for_flush_done(crtc);
}

627 628 629 630 631 632 633 634 635 636 637 638 639
static const char *dma_names[] = {
		"DMA_P", "DMA_S", "DMA_E",
};

/* initialize crtc */
struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
		struct drm_plane *plane, int id, int ovlp_id,
		enum mdp4_dma dma_id)
{
	struct drm_crtc *crtc = NULL;
	struct mdp4_crtc *mdp4_crtc;

	mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL);
640 641
	if (!mdp4_crtc)
		return ERR_PTR(-ENOMEM);
642 643 644

	crtc = &mdp4_crtc->base;

R
Rob Clark 已提交
645
	mdp4_crtc->id = id;
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660

	mdp4_crtc->ovlp = ovlp_id;
	mdp4_crtc->dma = dma_id;

	mdp4_crtc->vblank.irqmask = dma2irq(mdp4_crtc->dma);
	mdp4_crtc->vblank.irq = mdp4_crtc_vblank_irq;

	mdp4_crtc->err.irqmask = dma2err(mdp4_crtc->dma);
	mdp4_crtc->err.irq = mdp4_crtc_err_irq;

	snprintf(mdp4_crtc->name, sizeof(mdp4_crtc->name), "%s:%d",
			dma_names[dma_id], ovlp_id);

	spin_lock_init(&mdp4_crtc->cursor.lock);

661
	drm_flip_work_init(&mdp4_crtc->unref_cursor_work,
662 663
			"unref cursor", unref_cursor_worker);

664 665
	drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs,
				  NULL);
666
	drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
667
	plane->crtc = crtc;
668 669 670

	return crtc;
}