Commit 84e17ada authored by Dikshita Agarwal's avatar Dikshita Agarwal Committed by Hans Verkuil
Browse files

media: iris: add support for dynamic resolution change



Handle the response sent by the firmware, when a source change is
detected. Read the subscribed parameter to get the changed values. Raise
the source change event to the client and update the instance sub-state.

Mark the last buffer from before the source change with the
V4L2_BUF_FLAG_LAST flag and return to the client.

Reviewed-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Tested-by: Stefan Schmidt <stefan.schmidt@linaro.org> # x1e80100 (Dell XPS 13 9345)
Reviewed-by: default avatarStefan Schmidt <stefan.schmidt@linaro.org>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-HDK
Signed-off-by: default avatarDikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
parent 17f2a485
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -10,6 +10,70 @@
#include "iris_hfi_common.h"
#include "iris_vpu_common.h"

u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries)
{
	switch (hfi_primaries) {
	case HFI_PRIMARIES_RESERVED:
		return V4L2_COLORSPACE_DEFAULT;
	case HFI_PRIMARIES_BT709:
		return V4L2_COLORSPACE_REC709;
	case HFI_PRIMARIES_BT470_SYSTEM_M:
		return V4L2_COLORSPACE_470_SYSTEM_M;
	case HFI_PRIMARIES_BT470_SYSTEM_BG:
		return V4L2_COLORSPACE_470_SYSTEM_BG;
	case HFI_PRIMARIES_BT601_525:
		return V4L2_COLORSPACE_SMPTE170M;
	case HFI_PRIMARIES_SMPTE_ST240M:
		return V4L2_COLORSPACE_SMPTE240M;
	case HFI_PRIMARIES_BT2020:
		return V4L2_COLORSPACE_BT2020;
	case V4L2_COLORSPACE_DCI_P3:
		return HFI_PRIMARIES_SMPTE_RP431_2;
	default:
		return V4L2_COLORSPACE_DEFAULT;
	}
}

u32 iris_hfi_get_v4l2_transfer_char(u32 hfi_characterstics)
{
	switch (hfi_characterstics) {
	case HFI_TRANSFER_RESERVED:
		return V4L2_XFER_FUNC_DEFAULT;
	case HFI_TRANSFER_BT709:
		return V4L2_XFER_FUNC_709;
	case HFI_TRANSFER_SMPTE_ST240M:
		return V4L2_XFER_FUNC_SMPTE240M;
	case HFI_TRANSFER_SRGB_SYCC:
		return V4L2_XFER_FUNC_SRGB;
	case HFI_TRANSFER_SMPTE_ST2084_PQ:
		return V4L2_XFER_FUNC_SMPTE2084;
	default:
		return V4L2_XFER_FUNC_DEFAULT;
	}
}

u32 iris_hfi_get_v4l2_matrix_coefficients(u32 hfi_coefficients)
{
	switch (hfi_coefficients) {
	case HFI_MATRIX_COEFF_RESERVED:
		return V4L2_YCBCR_ENC_DEFAULT;
	case HFI_MATRIX_COEFF_BT709:
		return V4L2_YCBCR_ENC_709;
	case HFI_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625:
		return V4L2_YCBCR_ENC_XV601;
	case HFI_MATRIX_COEFF_BT601_525_BT1358_525_OR_625:
		return V4L2_YCBCR_ENC_601;
	case HFI_MATRIX_COEFF_SMPTE_ST240:
		return V4L2_YCBCR_ENC_SMPTE240M;
	case HFI_MATRIX_COEFF_BT2020_NON_CONSTANT:
		return V4L2_YCBCR_ENC_BT2020;
	case HFI_MATRIX_COEFF_BT2020_CONSTANT:
		return V4L2_YCBCR_ENC_BT2020_CONST_LUM;
	default:
		return V4L2_YCBCR_ENC_DEFAULT;
	}
}

int iris_hfi_core_init(struct iris_core *core)
{
	const struct iris_hfi_command_ops *hfi_ops = core->hfi_ops;
+3 −0
Original line number Diff line number Diff line
@@ -138,6 +138,9 @@ struct hfi_subscription_params {
	u32	level;
};

u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries);
u32 iris_hfi_get_v4l2_transfer_char(u32 hfi_characterstics);
u32 iris_hfi_get_v4l2_matrix_coefficients(u32 hfi_coefficients);
int iris_hfi_core_init(struct iris_core *core);
int iris_hfi_pm_suspend(struct iris_core *core);
int iris_hfi_pm_resume(struct iris_core *core);
+82 −0
Original line number Diff line number Diff line
@@ -44,18 +44,28 @@
#define HFI_EVENT_SYS_ERROR				0x1
#define HFI_EVENT_SESSION_ERROR				0x2

#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES   0x1000001
#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES 0x1000002
#define HFI_EVENT_SESSION_SEQUENCE_CHANGED			   0x1000003

#define HFI_BUFFERFLAG_TIMESTAMPINVALID			0x00000100

#define HFI_FLUSH_OUTPUT				0x1000002
#define HFI_FLUSH_OUTPUT2				0x1000003
#define HFI_FLUSH_ALL					0x1000004

#define HFI_INDEX_EXTRADATA_INPUT_CROP			0x0700000e

#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL				0x201001
#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO	0x201002
#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE				0x201008
#define HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL				0x20100c

#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS		0x202001

#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER	0x1200001
#define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS		0x120300e
#define HFI_PROPERTY_CONFIG_VDEC_ENTROPY		0x1204004

#define HFI_BUFFER_INPUT				0x1
#define HFI_BUFFER_OUTPUT				0x2
@@ -69,11 +79,15 @@

#define HFI_PROPERTY_PARAM_FRAME_SIZE			0x1001
#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT	0x1003
#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT	0x1005
#define HFI_PROPERTY_PARAM_WORK_MODE			0x1015
#define HFI_PROPERTY_PARAM_WORK_ROUTE			0x1017
#define HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE		0x2002

#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM		0x1003001
#define HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH		0x1003007
#define HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT		0x1003009
#define HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE		0x100300a
#define HFI_CORE_ID_1					1
#define HFI_COLOR_FORMAT_NV12				0x02
#define HFI_COLOR_FORMAT_NV12_UBWC			0x8002
@@ -249,6 +263,11 @@ struct hfi_enable {
	u32 enable;
};

struct hfi_profile_level {
	u32 profile;
	u32 level;
};

struct hfi_framesize {
	u32 buffer_type;
	u32 width;
@@ -267,6 +286,37 @@ struct hfi_video_work_route {
	u32 video_work_route;
};

struct hfi_bit_depth {
	u32 buffer_type;
	u32 bit_depth;
};

struct hfi_pic_struct {
	u32 progressive_only;
};

struct hfi_colour_space {
	u32 colour_space;
};

struct hfi_extradata_input_crop {
	u32 size;
	u32 version;
	u32 port_index;
	u32 left;
	u32 top;
	u32 width;
	u32 height;
};

struct hfi_dpb_counts {
	u32 max_dpb_count;
	u32 max_ref_frames;
	u32 max_dec_buffering;
	u32 max_reorder_frames;
	u32 fw_min_count;
};

struct hfi_uncompressed_format_select {
	u32 buffer_type;
	u32 format;
@@ -301,6 +351,38 @@ struct hfi_multi_stream {
	u32 enable;
};

struct hfi_buffer_requirements {
	u32 type;
	u32 size;
	u32 region_size;
	u32 hold_count;
	u32 count_min;
	u32 count_actual;
	u32 contiguous;
	u32 alignment;
};

struct hfi_event_data {
	u32 error;
	u32 height;
	u32 width;
	u32 event_type;
	u32 packet_buffer;
	u32 extradata_buffer;
	u32 tag;
	u32 profile;
	u32 level;
	u32 bit_depth;
	u32 pic_struct;
	u32 colour_space;
	u32 entropy_mode;
	u32 buf_count;
	struct {
		u32 left, top;
		u32 width, height;
	} input_crop;
};

struct hfi_msg_session_empty_buffer_done_pkt {
	struct hfi_msg_session_hdr_pkt shdr;
	u32 offset;
+208 −0
Original line number Diff line number Diff line
@@ -3,11 +3,216 @@
 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#include <linux/bitfield.h>
#include <media/v4l2-mem2mem.h>

#include "iris_hfi_gen1.h"
#include "iris_hfi_gen1_defines.h"
#include "iris_instance.h"
#include "iris_vdec.h"
#include "iris_vpu_buffer.h"

static void iris_hfi_gen1_read_changed_params(struct iris_inst *inst,
					      struct hfi_msg_event_notify_pkt *pkt)
{
	struct v4l2_pix_format_mplane *pixmp_ip = &inst->fmt_src->fmt.pix_mp;
	struct v4l2_pix_format_mplane *pixmp_op = &inst->fmt_dst->fmt.pix_mp;
	u32 num_properties_changed = pkt->event_data2;
	u8 *data_ptr = (u8 *)&pkt->ext_event_data[0];
	u32 primaries, matrix_coeff, transfer_char;
	struct hfi_dpb_counts *iris_vpu_dpb_count;
	struct hfi_profile_level *profile_level;
	struct hfi_buffer_requirements *bufreq;
	struct hfi_extradata_input_crop *crop;
	struct hfi_colour_space *colour_info;
	struct iris_core *core = inst->core;
	u32 colour_description_present_flag;
	u32 video_signal_type_present_flag;
	struct hfi_event_data event = {0};
	struct hfi_bit_depth *pixel_depth;
	struct hfi_pic_struct *pic_struct;
	struct hfi_framesize *frame_sz;
	struct vb2_queue *dst_q;
	struct v4l2_ctrl *ctrl;
	u32 full_range, ptype;

	do {
		ptype = *((u32 *)data_ptr);
		switch (ptype) {
		case HFI_PROPERTY_PARAM_FRAME_SIZE:
			data_ptr += sizeof(u32);
			frame_sz = (struct hfi_framesize *)data_ptr;
			event.width = frame_sz->width;
			event.height = frame_sz->height;
			data_ptr += sizeof(*frame_sz);
			break;
		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
			data_ptr += sizeof(u32);
			profile_level = (struct hfi_profile_level *)data_ptr;
			event.profile = profile_level->profile;
			event.level = profile_level->level;
			data_ptr += sizeof(*profile_level);
			break;
		case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH:
			data_ptr += sizeof(u32);
			pixel_depth = (struct hfi_bit_depth *)data_ptr;
			event.bit_depth = pixel_depth->bit_depth;
			data_ptr += sizeof(*pixel_depth);
			break;
		case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT:
			data_ptr += sizeof(u32);
			pic_struct = (struct hfi_pic_struct *)data_ptr;
			event.pic_struct = pic_struct->progressive_only;
			data_ptr += sizeof(*pic_struct);
			break;
		case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE:
			data_ptr += sizeof(u32);
			colour_info = (struct hfi_colour_space *)data_ptr;
			event.colour_space = colour_info->colour_space;
			data_ptr += sizeof(*colour_info);
			break;
		case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
			data_ptr += sizeof(u32);
			event.entropy_mode = *(u32 *)data_ptr;
			data_ptr += sizeof(u32);
			break;
		case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
			data_ptr += sizeof(u32);
			bufreq = (struct hfi_buffer_requirements *)data_ptr;
			event.buf_count = bufreq->count_min;
			data_ptr += sizeof(*bufreq);
			break;
		case HFI_INDEX_EXTRADATA_INPUT_CROP:
			data_ptr += sizeof(u32);
			crop = (struct hfi_extradata_input_crop *)data_ptr;
			event.input_crop.left = crop->left;
			event.input_crop.top = crop->top;
			event.input_crop.width = crop->width;
			event.input_crop.height = crop->height;
			data_ptr += sizeof(*crop);
			break;
		case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS:
			data_ptr += sizeof(u32);
			iris_vpu_dpb_count = (struct hfi_dpb_counts *)data_ptr;
			event.buf_count = iris_vpu_dpb_count->fw_min_count;
			data_ptr += sizeof(*iris_vpu_dpb_count);
			break;
		default:
			break;
		}
		num_properties_changed--;
	} while (num_properties_changed > 0);

	pixmp_ip->width = event.width;
	pixmp_ip->height = event.height;

	pixmp_op->width = ALIGN(event.width, 128);
	pixmp_op->height = ALIGN(event.height, 32);
	pixmp_op->plane_fmt[0].bytesperline = ALIGN(event.width, 128);
	pixmp_op->plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT);

	matrix_coeff =  FIELD_GET(GENMASK(7, 0), event.colour_space);
	transfer_char = FIELD_GET(GENMASK(15, 8), event.colour_space);
	primaries = FIELD_GET(GENMASK(23, 16), event.colour_space);
	colour_description_present_flag = FIELD_GET(GENMASK(24, 24), event.colour_space);
	full_range = FIELD_GET(GENMASK(25, 25), event.colour_space);
	video_signal_type_present_flag = FIELD_GET(GENMASK(29, 29), event.colour_space);

	pixmp_op->colorspace = V4L2_COLORSPACE_DEFAULT;
	pixmp_op->xfer_func = V4L2_XFER_FUNC_DEFAULT;
	pixmp_op->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
	pixmp_op->quantization = V4L2_QUANTIZATION_DEFAULT;

	if (video_signal_type_present_flag) {
		pixmp_op->quantization =
			full_range ?
			V4L2_QUANTIZATION_FULL_RANGE :
			V4L2_QUANTIZATION_LIM_RANGE;
		if (colour_description_present_flag) {
			pixmp_op->colorspace =
				iris_hfi_get_v4l2_color_primaries(primaries);
			pixmp_op->xfer_func =
				iris_hfi_get_v4l2_transfer_char(transfer_char);
			pixmp_op->ycbcr_enc =
				iris_hfi_get_v4l2_matrix_coefficients(matrix_coeff);
		}
	}

	pixmp_ip->colorspace = pixmp_op->colorspace;
	pixmp_ip->xfer_func = pixmp_op->xfer_func;
	pixmp_ip->ycbcr_enc = pixmp_op->ycbcr_enc;
	pixmp_ip->quantization = pixmp_op->quantization;

	if (event.input_crop.width > 0 && event.input_crop.height > 0) {
		inst->crop.left = event.input_crop.left;
		inst->crop.top = event.input_crop.top;
		inst->crop.width = event.input_crop.width;
		inst->crop.height = event.input_crop.height;
	} else {
		inst->crop.left = 0;
		inst->crop.top = 0;
		inst->crop.width = event.width;
		inst->crop.height = event.height;
	}

	inst->fw_min_count = event.buf_count;
	inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT);
	inst->buffers[BUF_OUTPUT].size = pixmp_op->plane_fmt[0].sizeimage;
	ctrl = v4l2_ctrl_find(&inst->ctrl_handler, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
	if (ctrl)
		v4l2_ctrl_s_ctrl(ctrl, inst->buffers[BUF_OUTPUT].min_count);

	dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx);
	dst_q->min_reqbufs_allocation = inst->buffers[BUF_OUTPUT].min_count;

	if (event.bit_depth || !event.pic_struct) {
		dev_err(core->dev, "unsupported content, bit depth: %x, pic_struct = %x\n",
			event.bit_depth, event.pic_struct);
		iris_inst_change_state(inst, IRIS_INST_ERROR);
	}
}

static void iris_hfi_gen1_event_seq_changed(struct iris_inst *inst,
					    struct hfi_msg_event_notify_pkt *pkt)
{
	struct hfi_session_flush_pkt flush_pkt;
	u32 num_properties_changed;
	int ret;

	ret = iris_inst_sub_state_change_drc(inst);
	if (ret)
		return;

	switch (pkt->event_data1) {
	case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
	case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
		break;
	default:
		iris_inst_change_state(inst, IRIS_INST_ERROR);
		return;
	}

	num_properties_changed = pkt->event_data2;
	if (!num_properties_changed) {
		iris_inst_change_state(inst, IRIS_INST_ERROR);
		return;
	}

	iris_hfi_gen1_read_changed_params(inst, pkt);

	if (inst->state != IRIS_INST_ERROR) {
		reinit_completion(&inst->flush_completion);

		flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt);
		flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH;
		flush_pkt.shdr.session_id = inst->session_id;
		flush_pkt.flush_type = HFI_FLUSH_OUTPUT;
		iris_hfi_queue_cmd_write(inst->core, &flush_pkt, flush_pkt.shdr.hdr.size);
	}

	iris_vdec_src_change(inst);
	iris_inst_sub_state_change_drc_last(inst);
}

static void
iris_hfi_gen1_sys_event_notify(struct iris_core *core, void *packet)
@@ -66,6 +271,9 @@ static void iris_hfi_gen1_session_event_notify(struct iris_inst *inst, void *pac
	case HFI_EVENT_SESSION_ERROR:
		iris_hfi_gen1_event_session_error(inst, pkt);
		break;
	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
		iris_hfi_gen1_event_seq_changed(inst, pkt);
		break;
	default:
		break;
	}
+4 −0
Original line number Diff line number Diff line
@@ -19,8 +19,11 @@
#define HFI_CMD_STOP				0x01000006
#define HFI_CMD_BUFFER				0x01000009
#define HFI_CMD_SUBSCRIBE_MODE			0x0100000B
#define HFI_CMD_SETTINGS_CHANGE			0x0100000C
#define HFI_CMD_END				0x01FFFFFF

#define HFI_BITMASK_BITSTREAM_WIDTH		0xffff0000
#define HFI_BITMASK_BITSTREAM_HEIGHT		0x0000ffff
#define HFI_BITMASK_FRAME_MBS_ONLY_FLAG		0x00000001

#define HFI_PROP_BEGIN				0x03000000
@@ -75,6 +78,7 @@
#define HFI_INFO_UNSUPPORTED			0x06000001
#define HFI_INFO_DATA_CORRUPT			0x06000002
#define HFI_INFO_BUFFER_OVERFLOW		0x06000004
#define HFI_INFO_HFI_FLAG_PSC_LAST		0x06000007
#define HFI_INFORMATION_END			0x06FFFFFF

enum hfi_property_mode_type {
Loading