vsp1_wpf.c 15.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2 3 4
/*
 * vsp1_wpf.c  --  R-Car VSP1 Write Pixel Formatter
 *
5
 * Copyright (C) 2013-2014 Renesas Electronics Corporation
6 7 8 9 10 11 12 13 14
 *
 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
 */

#include <linux/device.h>

#include <media/v4l2-subdev.h>

#include "vsp1.h"
15
#include "vsp1_dl.h"
16
#include "vsp1_pipe.h"
17 18 19
#include "vsp1_rwpf.h"
#include "vsp1_video.h"

20 21 22 23
#define WPF_GEN2_MAX_WIDTH			2048U
#define WPF_GEN2_MAX_HEIGHT			2048U
#define WPF_GEN3_MAX_WIDTH			8190U
#define WPF_GEN3_MAX_HEIGHT			8190U
24 25 26 27 28

/* -----------------------------------------------------------------------------
 * Device Access
 */

29
static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
30
				  struct vsp1_dl_body *dlb, u32 reg, u32 data)
31
{
32
	vsp1_dl_body_write(dlb, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
33 34
}

35 36 37 38 39 40 41 42 43
/* -----------------------------------------------------------------------------
 * Controls
 */

enum wpf_flip_ctrl {
	WPF_CTRL_VFLIP = 0,
	WPF_CTRL_HFLIP = 1,
};

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation)
{
	struct vsp1_video *video = wpf->video;
	struct v4l2_mbus_framefmt *sink_format;
	struct v4l2_mbus_framefmt *source_format;
	bool rotate;
	int ret = 0;

	/*
	 * Only consider the 0°/180° from/to 90°/270° modifications, the rest
	 * is taken care of by the flipping configuration.
	 */
	rotate = rotation == 90 || rotation == 270;
	if (rotate == wpf->flip.rotate)
		return 0;

	/* Changing rotation isn't allowed when buffers are allocated. */
	mutex_lock(&video->lock);

	if (vb2_is_busy(&video->queue)) {
		ret = -EBUSY;
		goto done;
	}

68 69 70 71
	sink_format = v4l2_subdev_state_get_format(wpf->entity.state,
						   RWPF_PAD_SINK);
	source_format = v4l2_subdev_state_get_format(wpf->entity.state,
						     RWPF_PAD_SOURCE);
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

	mutex_lock(&wpf->entity.lock);

	if (rotate) {
		source_format->width = sink_format->height;
		source_format->height = sink_format->width;
	} else {
		source_format->width = sink_format->width;
		source_format->height = sink_format->height;
	}

	wpf->flip.rotate = rotate;

	mutex_unlock(&wpf->entity.lock);

done:
	mutex_unlock(&video->lock);
	return ret;
}

92 93 94 95
static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct vsp1_rwpf *wpf =
		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
96
	unsigned int rotation;
97
	u32 flip = 0;
98
	int ret;
99

100 101 102 103 104 105 106 107 108 109 110 111 112 113
	/* Update the rotation. */
	rotation = wpf->flip.ctrls.rotate ? wpf->flip.ctrls.rotate->val : 0;
	ret = vsp1_wpf_set_rotation(wpf, rotation);
	if (ret < 0)
		return ret;

	/*
	 * Compute the flip value resulting from all three controls, with
	 * rotation by 180° flipping the image in both directions. Store the
	 * result in the pending flip field for the next frame that will be
	 * processed.
	 */
	if (wpf->flip.ctrls.vflip->val)
		flip |= BIT(WPF_CTRL_VFLIP);
114

115 116
	if (wpf->flip.ctrls.hflip && wpf->flip.ctrls.hflip->val)
		flip |= BIT(WPF_CTRL_HFLIP);
117

118 119 120 121 122 123
	if (rotation == 180 || rotation == 270)
		flip ^= BIT(WPF_CTRL_VFLIP) | BIT(WPF_CTRL_HFLIP);

	spin_lock_irq(&wpf->flip.lock);
	wpf->flip.pending = flip;
	spin_unlock_irq(&wpf->flip.lock);
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141

	return 0;
}

static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops = {
	.s_ctrl = vsp1_wpf_s_ctrl,
};

static int wpf_init_controls(struct vsp1_rwpf *wpf)
{
	struct vsp1_device *vsp1 = wpf->entity.vsp1;
	unsigned int num_flip_ctrls;

	spin_lock_init(&wpf->flip.lock);

	if (wpf->entity.index != 0) {
		/* Only WPF0 supports flipping. */
		num_flip_ctrls = 0;
142
	} else if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP)) {
143
		/*
144 145
		 * When horizontal flip is supported the WPF implements three
		 * controls (horizontal flip, vertical flip and rotation).
146
		 */
147
		num_flip_ctrls = 3;
148
	} else if (vsp1_feature(vsp1, VSP1_HAS_WPF_VFLIP)) {
149 150
		/*
		 * When only vertical flip is supported the WPF implements a
151 152 153 154 155 156 157 158 159 160 161
		 * single control (vertical flip).
		 */
		num_flip_ctrls = 1;
	} else {
		/* Otherwise flipping is not supported. */
		num_flip_ctrls = 0;
	}

	vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls);

	if (num_flip_ctrls >= 1) {
162
		wpf->flip.ctrls.vflip =
163 164 165 166
			v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
					  V4L2_CID_VFLIP, 0, 1, 1, 0);
	}

167 168
	if (num_flip_ctrls == 3) {
		wpf->flip.ctrls.hflip =
169 170
			v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
					  V4L2_CID_HFLIP, 0, 1, 1, 0);
171 172 173 174
		wpf->flip.ctrls.rotate =
			v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops,
					  V4L2_CID_ROTATE, 0, 270, 90, 0);
		v4l2_ctrl_cluster(3, &wpf->flip.ctrls.vflip);
175 176 177 178 179 180 181 182 183 184 185
	}

	if (wpf->ctrls.error) {
		dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
			wpf->entity.index);
		return wpf->ctrls.error;
	}

	return 0;
}

186
/* -----------------------------------------------------------------------------
187
 * VSP1 Entity Operations
188 189
 */

190
void vsp1_wpf_stop(struct vsp1_rwpf *wpf)
191 192
{
	struct vsp1_device *vsp1 = wpf->entity.vsp1;
193

194 195
	/*
	 * Write to registers directly when stopping the stream as there will be
196
	 * no pipeline run to apply the display list.
197
	 */
198 199 200 201
	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
	vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
		   VI6_WPF_SRCRPF, 0);
}
202

203 204 205 206 207 208 209
static void vsp1_wpf_destroy(struct vsp1_entity *entity)
{
	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);

	vsp1_dlm_destroy(wpf->dlm);
}

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf,
					 struct vsp1_dl_list *dl)
{
	unsigned int index = wpf->entity.index;
	struct vsp1_dl_list *dl_next;
	struct vsp1_dl_body *dlb;

	dl_next = vsp1_dl_list_get(wpf->dlm);
	if (!dl_next) {
		dev_err(wpf->entity.vsp1->dev,
			"Failed to obtain a dl list, disabling writeback\n");
		return -ENOMEM;
	}

	dlb = vsp1_dl_list_get_body0(dl_next);
	vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index), 0);
	vsp1_dl_list_add_chain(dl, dl_next);

	return 0;
}

231
static void wpf_configure_stream(struct vsp1_entity *entity,
232
				 struct v4l2_subdev_state *state,
233
				 struct vsp1_pipeline *pipe,
234
				 struct vsp1_dl_list *dl,
235
				 struct vsp1_dl_body *dlb)
236 237 238 239 240
{
	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
	struct vsp1_device *vsp1 = wpf->entity.vsp1;
	const struct v4l2_mbus_framefmt *source_format;
	const struct v4l2_mbus_framefmt *sink_format;
241
	unsigned int index = wpf->entity.index;
242 243 244
	unsigned int i;
	u32 outfmt = 0;
	u32 srcrpf = 0;
245
	int ret;
246

247 248
	sink_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
	source_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
249

250
	/* Format */
251
	if (!pipe->lif || wpf->writeback) {
252
		const struct v4l2_pix_format_mplane *format = &wpf->format;
253
		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
254 255 256

		outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;

257 258 259
		if (wpf->flip.rotate)
			outfmt |= VI6_WPF_OUTFMT_ROT;

260 261
		if (fmtinfo->alpha)
			outfmt |= VI6_WPF_OUTFMT_PXA;
262 263 264 265 266
		if (fmtinfo->swap_yc)
			outfmt |= VI6_WPF_OUTFMT_SPYCS;
		if (fmtinfo->swap_uv)
			outfmt |= VI6_WPF_OUTFMT_SPUVS;

267
		/* Destination stride and byte swapping. */
268
		vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_STRIDE_Y,
269 270
			       format->plane_fmt[0].bytesperline);
		if (format->num_planes > 1)
271
			vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_STRIDE_C,
272 273
				       format->plane_fmt[1].bytesperline);

274
		vsp1_wpf_write(wpf, dlb, VI6_WPF_DSWAP, fmtinfo->swap);
275

276
		if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) && index == 0)
277
			vsp1_wpf_write(wpf, dlb, VI6_WPF_ROT_CTRL,
278 279
				       VI6_WPF_ROT_CTRL_LN16 |
				       (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
280 281
	}

282
	if (sink_format->code != source_format->code)
283 284
		outfmt |= VI6_WPF_OUTFMT_CSC;

285
	wpf->outfmt = outfmt;
286

287
	vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(index),
288
			   VI6_DPR_WPF_FPORCH_FP_WPFN);
289

290
	/*
291
	 * Sources. If the pipeline has a single input and BRx is not used,
292 293 294 295 296 297
	 * configure it as the master layer. Otherwise configure all
	 * inputs as sub-layers and select the virtual RPF as the master
	 * layer.
	 */
	for (i = 0; i < vsp1->info->rpf_count; ++i) {
		struct vsp1_rwpf *input = pipe->inputs[i];
298

299 300
		if (!input)
			continue;
301

302
		srcrpf |= (!pipe->brx && pipe->num_inputs == 1)
303 304 305
			? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
			: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
	}
306

307 308
	if (pipe->brx)
		srcrpf |= pipe->brx->type == VSP1_ENTITY_BRU
309 310
			? VI6_WPF_SRCRPF_VIRACT_MST
			: VI6_WPF_SRCRPF_VIRACT2_MST;
311

312
	vsp1_wpf_write(wpf, dlb, VI6_WPF_SRCRPF, srcrpf);
313

314
	/* Enable interrupts. */
315 316
	vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(index), 0);
	vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(index),
317
			   VI6_WPF_IRQ_ENB_DFEE);
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334

	/*
	 * Configure writeback for display pipelines (the wpf writeback flag is
	 * never set for memory-to-memory pipelines). Start by adding a chained
	 * display list to disable writeback after a single frame, and process
	 * to enable writeback. If the display list allocation fails don't
	 * enable writeback as we wouldn't be able to safely disable it,
	 * resulting in possible memory corruption.
	 */
	if (wpf->writeback) {
		ret = wpf_configure_writeback_chain(wpf, dl);
		if (ret < 0)
			wpf->writeback = false;
	}

	vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index),
			   wpf->writeback ? VI6_WPF_WRBCK_CTRL_WBMD : 0);
335 336
}

337 338
static void wpf_configure_frame(struct vsp1_entity *entity,
				struct vsp1_pipeline *pipe,
339 340
				struct vsp1_dl_list *dl,
				struct vsp1_dl_body *dlb)
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
{
	const unsigned int mask = BIT(WPF_CTRL_VFLIP)
				| BIT(WPF_CTRL_HFLIP);
	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
	unsigned long flags;
	u32 outfmt;

	spin_lock_irqsave(&wpf->flip.lock, flags);
	wpf->flip.active = (wpf->flip.active & ~mask)
			 | (wpf->flip.pending & mask);
	spin_unlock_irqrestore(&wpf->flip.lock, flags);

	outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt;

	if (wpf->flip.active & BIT(WPF_CTRL_VFLIP))
		outfmt |= VI6_WPF_OUTFMT_FLP;
	if (wpf->flip.active & BIT(WPF_CTRL_HFLIP))
		outfmt |= VI6_WPF_OUTFMT_HFLP;

360
	vsp1_wpf_write(wpf, dlb, VI6_WPF_OUTFMT, outfmt);
361 362 363 364
}

static void wpf_configure_partition(struct vsp1_entity *entity,
				    struct vsp1_pipeline *pipe,
365
				    const struct vsp1_partition *partition,
366 367
				    struct vsp1_dl_list *dl,
				    struct vsp1_dl_body *dlb)
368 369 370 371 372 373 374 375
{
	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
	struct vsp1_device *vsp1 = wpf->entity.vsp1;
	struct vsp1_rwpf_memory mem = wpf->mem;
	const struct v4l2_pix_format_mplane *format = &wpf->format;
	const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
	unsigned int width;
	unsigned int height;
376
	unsigned int left;
377 378 379 380 381
	unsigned int offset;
	unsigned int flip;
	unsigned int i;

	/*
382 383
	 * Cropping. The partition algorithm can split the image into multiple
	 * slices.
384
	 */
385 386 387
	width = partition->wpf.width;
	left = partition->wpf.left;
	height = partition->wpf.height;
388

389
	vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
390 391
		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
		       (width << VI6_WPF_SZCLIP_SIZE_SHIFT));
392
	vsp1_wpf_write(wpf, dlb, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
393 394 395
		       (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
		       (height << VI6_WPF_SZCLIP_SIZE_SHIFT));

396 397 398 399 400
	/*
	 * For display pipelines without writeback enabled there's no memory
	 * address to configure, return now.
	 */
	if (pipe->lif && !wpf->writeback)
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
		return;

	/*
	 * Update the memory offsets based on flipping configuration.
	 * The destination addresses point to the locations where the
	 * VSP starts writing to memory, which can be any corner of the
	 * image depending on the combination of flipping and rotation.
	 */

	/*
	 * First take the partition left coordinate into account.
	 * Compute the offset to order the partitions correctly on the
	 * output based on whether flipping is enabled. Consider
	 * horizontal flipping when rotation is disabled but vertical
	 * flipping when rotation is enabled, as rotating the image
	 * switches the horizontal and vertical directions. The offset
	 * is applied horizontally or vertically accordingly.
	 */
	flip = wpf->flip.active;

	if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate)
422
		offset = format->width - left - width;
423
	else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate)
424
		offset = format->height - left - width;
425
	else
426
		offset = left;
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

	for (i = 0; i < format->num_planes; ++i) {
		unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
		unsigned int vsub = i > 0 ? fmtinfo->vsub : 1;

		if (wpf->flip.rotate)
			mem.addr[i] += offset / vsub
				     * format->plane_fmt[i].bytesperline;
		else
			mem.addr[i] += offset / hsub
				     * fmtinfo->bpp[i] / 8;
	}

	if (flip & BIT(WPF_CTRL_VFLIP)) {
		/*
		 * When rotating the output (after rotation) image
		 * height is equal to the partition width (before
		 * rotation). Otherwise it is equal to the output
		 * image height.
		 */
		if (wpf->flip.rotate)
448
			height = width;
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
		else
			height = format->height;

		mem.addr[0] += (height - 1)
			     * format->plane_fmt[0].bytesperline;

		if (format->num_planes > 1) {
			offset = (height / fmtinfo->vsub - 1)
			       * format->plane_fmt[1].bytesperline;
			mem.addr[1] += offset;
			mem.addr[2] += offset;
		}
	}

	if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) {
		unsigned int hoffset = max(0, (int)format->width - 16);

		/*
		 * Compute the output coordinate. The partition
		 * horizontal (left) offset becomes a vertical offset.
		 */
		for (i = 0; i < format->num_planes; ++i) {
			unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;

			mem.addr[i] += hoffset / hsub
				     * fmtinfo->bpp[i] / 8;
		}
	}

	/*
479
	 * On Gen3+ hardware the SPUVS bit has no effect on 3-planar
480 481
	 * formats. Swap the U and V planes manually in that case.
	 */
482
	if (vsp1->info->gen >= 3 && format->num_planes == 3 &&
483 484 485
	    fmtinfo->swap_uv)
		swap(mem.addr[1], mem.addr[2]);

486 487 488
	vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
	vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
	vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
489 490 491 492 493 494

	/*
	 * Writeback operates in single-shot mode and lasts for a single frame,
	 * reset the writeback flag to false for the next frame.
	 */
	wpf->writeback = false;
495 496
}

497
static unsigned int wpf_max_width(struct vsp1_entity *entity,
498
				  struct v4l2_subdev_state *state,
499 500 501 502 503 504 505
				  struct vsp1_pipeline *pipe)
{
	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);

	return wpf->flip.rotate ? 256 : wpf->max_width;
}

506
static void wpf_partition(struct vsp1_entity *entity,
507
			  struct v4l2_subdev_state *state,
508 509 510
			  struct vsp1_pipeline *pipe,
			  struct vsp1_partition *partition,
			  unsigned int partition_idx,
511
			  struct v4l2_rect *window)
512 513 514 515
{
	partition->wpf = *window;
}

516 517
static const struct vsp1_entity_operations wpf_entity_ops = {
	.destroy = vsp1_wpf_destroy,
518 519 520
	.configure_stream = wpf_configure_stream,
	.configure_frame = wpf_configure_frame,
	.configure_partition = wpf_configure_partition,
521
	.max_width = wpf_max_width,
522
	.partition = wpf_partition,
523 524 525 526 527 528 529 530 531
};

/* -----------------------------------------------------------------------------
 * Initialization and Cleanup
 */

struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
{
	struct vsp1_rwpf *wpf;
532
	char name[6];
533 534 535 536 537 538
	int ret;

	wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
	if (wpf == NULL)
		return ERR_PTR(-ENOMEM);

539 540 541 542 543 544 545
	if (vsp1->info->gen == 2) {
		wpf->max_width = WPF_GEN2_MAX_WIDTH;
		wpf->max_height = WPF_GEN2_MAX_HEIGHT;
	} else {
		wpf->max_width = WPF_GEN3_MAX_WIDTH;
		wpf->max_height = WPF_GEN3_MAX_HEIGHT;
	}
546

547
	wpf->entity.ops = &wpf_entity_ops;
548 549 550
	wpf->entity.type = VSP1_ENTITY_WPF;
	wpf->entity.index = index;

551
	sprintf(name, "wpf.%u", index);
552
	ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &vsp1_rwpf_subdev_ops,
553
			       MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
554 555 556
	if (ret < 0)
		return ERR_PTR(ret);

557
	/* Initialize the display list manager. */
558
	wpf->dlm = vsp1_dlm_create(vsp1, index, 64);
559 560 561
	if (!wpf->dlm) {
		ret = -ENOMEM;
		goto error;
562 563
	}

564
	/* Initialize the control handler. */
565
	ret = wpf_init_controls(wpf);
566
	if (ret < 0) {
567 568 569 570 571
		dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
			index);
		goto error;
	}

572 573
	v4l2_ctrl_handler_setup(&wpf->ctrls);

574 575
	return wpf;

576 577
error:
	vsp1_entity_destroy(&wpf->entity);
578 579
	return ERR_PTR(ret);
}