drivers/media/platform/rockchip/rkvdec/rkvdec.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/rockchip/rkvdec/rkvdec.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/rockchip/rkvdec/rkvdec.c
Extension
.c
Size
51289 bytes
Lines
1917
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if ((j + 1) % row_length == 0) {
				row += 1;
				x_offset += 1;
			}
		}
	}
}

/*
 * VDPU383 needs a specific order:
 * The 8x8 flatten matrix is based on 4x4 blocks.
 * Each 4x4 block is written separately in order.
 *
 * Base data    =>  Transposed    VDPU383 transposed
 *
 * ABCDEFGH         AIQYaiqy      AIQYBJRZ
 * IJKLMNOP         BJRZbjrz      CKS0DLT1
 * QRSTUVWX         CKS0cks6      aiqybjrz
 * YZ012345     =>  DLT1dlt7      cks6dlt7
 * abcdefgh         EMU2emu8      EMU2FNV3
 * ijklmnop         FNV3fnv9      GOW4HPX5
 * qrstuvwx         GOW4gow#      emu8fnv9
 * yz6789#$         HPX5hpx$      gow#hpx$
 *
 * As the function reads block of 4x4 it can be used for both 4x4 and 8x8 matrices.
 *
 */
static void vdpu383_flatten_matrices(u8 *output, const u8 *input, int matrices, int row_length)
{
	u8 block;
	int i, j, matrix_offset, matrix_size, new_value, input_idx, line_offset, block_offset;

	matrix_size = row_length * row_length;
	for (i = 0; i < matrices; i++) {
		matrix_offset = i * matrix_size;
		for (j = 0; j < matrix_size; j++) {
			block = j / 16;
			line_offset = (j % 16) / 4;
			block_offset = (block & 1) * 32 + (block & 2) * 2;
			input_idx = ((j % 4) * row_length) + line_offset + block_offset;

			new_value = *(input + i * matrix_size + input_idx);

			output[matrix_offset + j] = new_value;
		}
	}
}

static void rkvdec_watchdog_func(struct work_struct *work)
{
	struct rkvdec_dev *rkvdec;
	struct rkvdec_ctx *ctx;

	rkvdec = container_of(to_delayed_work(work), struct rkvdec_dev,
			      watchdog_work);
	ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
	if (ctx) {
		dev_err(rkvdec->dev, "Frame processing timed out!\n");
		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
	}
}

/*
 * Some SoCs, like RK3588 have multiple identical VDPU cores, but the
 * kernel is currently missing support for multi-core handling. Exposing
 * separate devices for each core to userspace is bad, since that does
 * not allow scheduling tasks properly (and creates ABI). With this workaround
 * the driver will only probe for the first core and early exit for the other
 * cores. Once the driver gains multi-core support, the same technique
 * for detecting the first core can be used to cluster all cores together.
 */
static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
{
	struct device_node *node = NULL;
	const char *compatible;
	bool is_first_core;
	int ret;

	/* Intentionally ignores the fallback strings */
	ret = of_property_read_string(rkvdec->dev->of_node, "compatible", &compatible);
	if (ret)
		return ret;

	/* The first compatible and available node found is considered the main core */
	do {
		node = of_find_compatible_node(node, NULL, compatible);
		if (of_device_is_available(node))
			break;
	} while (node);

Annotation

Implementation Notes