On 05/11/2024 07:55, Dikshita Agarwal wrote: > Implement reqbuf IOCTL op and vb2_queue_setup vb2 op in the driver with > necessary hooks. > > Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx> > --- > drivers/media/platform/qcom/iris/Makefile | 7 +- > drivers/media/platform/qcom/iris/iris_buffer.c | 119 +++++++++++++++++++++ > drivers/media/platform/qcom/iris/iris_buffer.h | 107 ++++++++++++++++++ > drivers/media/platform/qcom/iris/iris_core.h | 6 ++ > drivers/media/platform/qcom/iris/iris_hfi_common.h | 3 + > .../platform/qcom/iris/iris_hfi_gen1_command.c | 40 +++++++ > .../platform/qcom/iris/iris_hfi_gen1_defines.h | 47 +++++++- > .../platform/qcom/iris/iris_hfi_gen1_response.c | 79 +++++++++++++- > drivers/media/platform/qcom/iris/iris_hfi_gen2.h | 5 + > .../platform/qcom/iris/iris_hfi_gen2_command.c | 105 ++++++++++++++++++ > .../platform/qcom/iris/iris_hfi_gen2_defines.h | 34 ++++++ > .../platform/qcom/iris/iris_hfi_gen2_packet.c | 39 +++++++ > .../platform/qcom/iris/iris_hfi_gen2_packet.h | 7 ++ > .../platform/qcom/iris/iris_hfi_gen2_response.c | 108 ++++++++++++++++++- > drivers/media/platform/qcom/iris/iris_instance.h | 22 ++++ > .../platform/qcom/iris/iris_platform_common.h | 5 + > .../platform/qcom/iris/iris_platform_sm8550.c | 6 ++ > drivers/media/platform/qcom/iris/iris_probe.c | 2 + > drivers/media/platform/qcom/iris/iris_utils.c | 51 +++++++++ > drivers/media/platform/qcom/iris/iris_utils.h | 38 +++++++ > drivers/media/platform/qcom/iris/iris_vb2.c | 74 +++++++++++++ > drivers/media/platform/qcom/iris/iris_vb2.h | 12 +++ > drivers/media/platform/qcom/iris/iris_vdec.c | 58 ++++++++++ > drivers/media/platform/qcom/iris/iris_vdec.h | 14 +++ > drivers/media/platform/qcom/iris/iris_vidc.c | 81 ++++++++++++++ > drivers/media/platform/qcom/iris/iris_vpu_buffer.c | 19 ++++ > drivers/media/platform/qcom/iris/iris_vpu_buffer.h | 15 +++ > 27 files changed, 1095 insertions(+), 8 deletions(-) > > diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile > index a5f290a8c4af..48ab264b7906 100644 > --- a/drivers/media/platform/qcom/iris/Makefile > +++ b/drivers/media/platform/qcom/iris/Makefile > @@ -1,4 +1,5 @@ > -iris-objs += iris_core.o \ > +iris-objs += iris_buffer.o \ > + iris_core.o \ > iris_firmware.o \ > iris_hfi_common.o \ > iris_hfi_gen1_command.o \ > @@ -10,9 +11,13 @@ iris-objs += iris_core.o \ > iris_platform_sm8550.o \ > iris_probe.o \ > iris_resources.o \ > + iris_utils.o \ > iris_vidc.o \ > + iris_vb2.o \ > + iris_vdec.o \ > iris_vpu2.o \ > iris_vpu3.o \ > + iris_vpu_buffer.o \ > iris_vpu_common.o \ > > obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o > diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c > new file mode 100644 > index 000000000000..48bc5c2c343c > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_buffer.c > @@ -0,0 +1,119 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include <media/v4l2-mem2mem.h> > + > +#include "iris_buffer.h" > +#include "iris_instance.h" > + > +#define PIXELS_4K 4096 > +#define MAX_WIDTH 4096 > +#define MAX_HEIGHT 2304 > +#define Y_STRIDE_ALIGN 128 > +#define UV_STRIDE_ALIGN 128 > +#define Y_SCANLINE_ALIGN 32 > +#define UV_SCANLINE_ALIGN 16 > +#define UV_SCANLINE_ALIGN_QC08C 32 > +#define META_STRIDE_ALIGNED 64 > +#define META_SCANLINE_ALIGNED 16 > +#define NUM_MBS_4K (DIV_ROUND_UP(MAX_WIDTH, 16) * DIV_ROUND_UP(MAX_HEIGHT, 16)) > + > +/* > + * NV12: > + * YUV 4:2:0 image with a plane of 8 bit Y samples followed > + * by an interleaved U/V plane containing 8 bit 2x2 subsampled > + * colour difference samples. > + * > + * <-Y/UV_Stride (aligned to 128)-> > + * <------- Width -------> > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | y_scanlines (aligned to 32) > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | > + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | > + * . . . . . . . . . . . . . . . . | > + * . . . . . . . . . . . . . . . . | > + * . . . . . . . . . . . . . . . . | > + * . . . . . . . . . . . . . . . . V > + * U V U V U V U V U V U V . . . . ^ > + * U V U V U V U V U V U V . . . . | > + * U V U V U V U V U V U V . . . . | > + * U V U V U V U V U V U V . . . . uv_scanlines (aligned to 16) > + * . . . . . . . . . . . . . . . . | > + * . . . . . . . . . . . . . . . . V > + * . . . . . . . . . . . . . . . . --> Buffer size aligned to 4K > + * > + * y_stride : Width aligned to 128 > + * uv_stride : Width aligned to 128 > + * y_scanlines: Height aligned to 32 > + * uv_scanlines: Height/2 aligned to 16 > + * Total size = align((y_stride * y_scanlines > + * + uv_stride * uv_scanlines , 4096) > + * > + * Note: All the alignments are hardware requirements. > + */ > +static u32 iris_output_buffer_size_nv12(struct iris_inst *inst) > +{ > + u32 y_plane, uv_plane, y_stride, uv_stride, y_scanlines, uv_scanlines; > + struct v4l2_format *f = inst->fmt_dst; > + > + y_stride = ALIGN(f->fmt.pix_mp.width, Y_STRIDE_ALIGN); > + uv_stride = ALIGN(f->fmt.pix_mp.width, UV_STRIDE_ALIGN); > + y_scanlines = ALIGN(f->fmt.pix_mp.height, Y_SCANLINE_ALIGN); > + uv_scanlines = ALIGN((f->fmt.pix_mp.height + 1) >> 1, UV_SCANLINE_ALIGN); > + y_plane = y_stride * y_scanlines; > + uv_plane = uv_stride * uv_scanlines; > + > + return ALIGN(y_plane + uv_plane, PIXELS_4K); > +} > + > +static u32 iris_input_buffer_size(struct iris_inst *inst) > +{ > + struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; > + u32 base_res_mbs = NUM_MBS_4K; > + u32 frame_size, num_mbs; > + u32 div_factor = 2; > + > + num_mbs = iris_get_mbpf(inst); > + if (num_mbs > NUM_MBS_4K) { > + div_factor = 4; > + base_res_mbs = caps->max_mbpf; > + } > + > + /* > + * frame_size = YUVsize / div_factor > + * where YUVsize = resolution_in_MBs * MBs_in_pixel * 3 / 2 > + */ > + frame_size = base_res_mbs * (16 * 16) * 3 / 2 / div_factor; > + > + return ALIGN(frame_size, PIXELS_4K); > +} > + > +int iris_get_buffer_size(struct iris_inst *inst, > + enum iris_buffer_type buffer_type) > +{ > + switch (buffer_type) { > + case BUF_INPUT: > + return iris_input_buffer_size(inst); > + case BUF_OUTPUT: > + return iris_output_buffer_size_nv12(inst); > + default: > + return 0; > + } > +} > + > +void iris_vb2_queue_error(struct iris_inst *inst) > +{ > + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; > + struct vb2_queue *q; > + > + q = v4l2_m2m_get_src_vq(m2m_ctx); > + vb2_queue_error(q); > + q = v4l2_m2m_get_dst_vq(m2m_ctx); > + vb2_queue_error(q); > +} > diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h > new file mode 100644 > index 000000000000..98844e89e0e3 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_buffer.h > @@ -0,0 +1,107 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef _IRIS_BUFFER_H_ > +#define _IRIS_BUFFER_H_ > + > +#include <media/videobuf2-v4l2.h> > + > +struct iris_inst; > + > +#define to_iris_buffer(ptr) container_of(ptr, struct iris_buffer, vb2) > + > +/** > + * enum iris_buffer_type > + * > + * BUF_INPUT: input buffer to the iris hardware > + * BUF_OUTPUT: output buffer from the iris hardware > + * BUF_BIN: buffer to store intermediate bin data > + * BUF_ARP: buffer for auto register programming > + * BUF_COMV: buffer to store colocated motion vectors > + * BUF_NON_COMV: buffer to hold config data for HW > + * BUF_LINE: buffer to store decoding/encoding context data for HW > + * BUF_DPB: buffer to store display picture buffers for reference > + * BUF_PERSIST: buffer to store session context data > + * BUF_SCRATCH_1: buffer to store decoding/encoding context data for HW > + */ > +enum iris_buffer_type { > + BUF_INPUT = 1, > + BUF_OUTPUT, > + BUF_BIN, > + BUF_ARP, > + BUF_COMV, > + BUF_NON_COMV, > + BUF_LINE, > + BUF_DPB, > + BUF_PERSIST, > + BUF_SCRATCH_1, > + BUF_TYPE_MAX, > +}; > + > +/* > + * enum iris_buffer_attributes > + * > + * BUF_ATTR_DEFERRED: buffer queued by client but not submitted to firmware. > + * BUF_ATTR_PENDING_RELEASE: buffers requested to be released from firmware. > + * BUF_ATTR_QUEUED: buffers submitted to firmware. > + * BUF_ATTR_DEQUEUED: buffers received from firmware. > + * BUF_ATTR_BUFFER_DONE: buffers sent back to vb2. > + */ > +enum iris_buffer_attributes { > + BUF_ATTR_DEFERRED = BIT(0), > + BUF_ATTR_PENDING_RELEASE = BIT(1), > + BUF_ATTR_QUEUED = BIT(2), > + BUF_ATTR_DEQUEUED = BIT(3), > + BUF_ATTR_BUFFER_DONE = BIT(4), > +}; > + > +/** > + * struct iris_buffer > + * > + * @vb2: v4l2 vb2 buffer > + * @list: list head for the iris_buffers structure > + * @inst: iris instance structure > + * @type: enum for type of iris buffer > + * @index: identifier for the iris buffer > + * @fd: file descriptor of the buffer > + * @buffer_size: accessible buffer size in bytes starting from addr_offset > + * @data_offset: accessible buffer offset from base address > + * @data_size: data size in bytes > + * @device_addr: device address of the buffer > + * @kvaddr: kernel virtual address of the buffer > + * @dma_attrs: dma attributes > + * @flags: buffer flags. It is represented as bit masks. > + * @timestamp: timestamp of the buffer in nano seconds (ns) > + * @attr: enum for iris buffer attributes > + */ > +struct iris_buffer { > + struct vb2_v4l2_buffer vb2; > + struct list_head list; > + struct iris_inst *inst; > + enum iris_buffer_type type; > + u32 index; > + int fd; > + size_t buffer_size; > + u32 data_offset; > + size_t data_size; > + dma_addr_t device_addr; > + void *kvaddr; > + unsigned long dma_attrs; > + u32 flags; /* V4L2_BUF_FLAG_* */ > + u64 timestamp; > + enum iris_buffer_attributes attr; > +}; > + > +struct iris_buffers { > + struct list_head list; > + u32 min_count; > + u32 actual_count; > + u32 size; > +}; > + > +int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); > +void iris_vb2_queue_error(struct iris_inst *inst); > + > +#endif > diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h > index ae3523aa6a9b..578166d196f6 100644 > --- a/drivers/media/platform/qcom/iris/iris_core.h > +++ b/drivers/media/platform/qcom/iris/iris_core.h > @@ -34,6 +34,8 @@ struct icc_info { > * @v4l2_dev: a holder for v4l2 device structure > * @vdev_dec: iris video device structure for decoder > * @iris_v4l2_file_ops: iris v4l2 file ops > + * @iris_v4l2_ioctl_ops: iris v4l2 ioctl ops > + * @vb2_ops: iris vb2 ops > * @icc_tbl: table of iris interconnects > * @icc_count: count of iris interconnects > * @pmdomain_tbl: table of iris power domains > @@ -60,6 +62,7 @@ struct icc_info { > * @core_init_done: structure of signal completion for system response > * @intr_status: interrupt status > * @sys_error_handler: a delayed work for handling system fatal error > + * @instances: a list_head of all instances > */ > > struct iris_core { > @@ -69,6 +72,8 @@ struct iris_core { > struct v4l2_device v4l2_dev; > struct video_device *vdev_dec; > const struct v4l2_file_operations *iris_v4l2_file_ops; > + const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops; > + const struct vb2_ops *iris_vb2_ops; > struct icc_bulk_data *icc_tbl; > u32 icc_count; > struct dev_pm_domain_list *pmdomain_tbl; > @@ -95,6 +100,7 @@ struct iris_core { > struct completion core_init_done; > u32 intr_status; > struct delayed_work sys_error_handler; > + struct list_head instances; > }; > > int iris_core_init(struct iris_core *core); > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h > index e050b1ae90fe..f59ce97d5b7e 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h > @@ -9,6 +9,7 @@ > #include <linux/types.h> > #include <media/v4l2-device.h> > > +struct iris_inst; > struct iris_core; > > enum hfi_packet_port_type { > @@ -47,6 +48,8 @@ struct iris_hfi_command_ops { > int (*sys_image_version)(struct iris_core *core); > int (*sys_interframe_powercollapse)(struct iris_core *core); > int (*sys_pc_prep)(struct iris_core *core); > + int (*session_open)(struct iris_inst *inst); > + int (*session_close)(struct iris_inst *inst); > }; > > struct iris_hfi_response_ops { > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c > index b2e76d1dcbf7..7ee69c5223ce 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c > @@ -66,11 +66,51 @@ static int iris_hfi_gen1_sys_pc_prep(struct iris_core *core) > return iris_hfi_queue_cmd_write_locked(core, &pkt, pkt.hdr.size); > } > > +static int iris_hfi_gen1_session_open(struct iris_inst *inst) > +{ > + struct hfi_session_open_pkt packet; > + int ret; > + > + packet.shdr.hdr.size = sizeof(struct hfi_session_open_pkt); > + packet.shdr.hdr.pkt_type = HFI_CMD_SYS_SESSION_INIT; > + packet.shdr.session_id = inst->session_id; > + packet.session_domain = HFI_SESSION_TYPE_DEC; > + packet.session_codec = HFI_VIDEO_CODEC_H264; > + > + reinit_completion(&inst->completion); > + > + ret = iris_hfi_queue_cmd_write(inst->core, &packet, packet.shdr.hdr.size); > + if (ret) > + return ret; > + > + return iris_wait_for_session_response(inst); > +} > + > +static void iris_hfi_gen1_packet_session_cmd(struct iris_inst *inst, > + struct hfi_session_pkt *packet, > + u32 ptype) > +{ > + packet->shdr.hdr.size = sizeof(*packet); > + packet->shdr.hdr.pkt_type = ptype; > + packet->shdr.session_id = inst->session_id; > +} > + > +static int iris_hfi_gen1_session_close(struct iris_inst *inst) > +{ > + struct hfi_session_pkt packet; > + > + iris_hfi_gen1_packet_session_cmd(inst, &packet, HFI_CMD_SYS_SESSION_END); > + > + return iris_hfi_queue_cmd_write(inst->core, &packet, packet.shdr.hdr.size); > +} > + > static const struct iris_hfi_command_ops iris_hfi_gen1_command_ops = { > .sys_init = iris_hfi_gen1_sys_init, > .sys_image_version = iris_hfi_gen1_sys_image_version, > .sys_interframe_powercollapse = iris_hfi_gen1_sys_interframe_powercollapse, > .sys_pc_prep = iris_hfi_gen1_sys_pc_prep, > + .session_open = iris_hfi_gen1_session_open, > + .session_close = iris_hfi_gen1_session_close, > }; > > void iris_hfi_gen1_command_ops_init(struct iris_core *core) > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h > index 991d5a5dc792..da52e497b74a 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h > @@ -9,19 +9,34 @@ > #include <linux/types.h> > > #define HFI_VIDEO_ARCH_OX 0x1 > + > +#define HFI_SESSION_TYPE_DEC 2 > + > +#define HFI_VIDEO_CODEC_H264 0x00000002 > + > #define HFI_ERR_NONE 0x0 > > #define HFI_CMD_SYS_INIT 0x10001 > #define HFI_CMD_SYS_PC_PREP 0x10002 > #define HFI_CMD_SYS_SET_PROPERTY 0x10005 > #define HFI_CMD_SYS_GET_PROPERTY 0x10006 > +#define HFI_CMD_SYS_SESSION_INIT 0x10007 > +#define HFI_CMD_SYS_SESSION_END 0x10008 > > -#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 > -#define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 > +#define HFI_ERR_SESSION_UNSUPPORTED_SETTING 0x1008 > +#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE 0x1010 > +#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR 0x1012 > +#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED 0x1013 > > #define HFI_EVENT_SYS_ERROR 0x1 > +#define HFI_EVENT_SESSION_ERROR 0x2 > + > +#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 > +#define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 > > #define HFI_MSG_SYS_INIT 0x20001 > +#define HFI_MSG_SYS_SESSION_INIT 0x20006 > +#define HFI_MSG_SYS_SESSION_END 0x20007 > #define HFI_MSG_SYS_COV 0x20009 > #define HFI_MSG_SYS_PROPERTY_INFO 0x2000a > > @@ -32,6 +47,21 @@ struct hfi_pkt_hdr { > u32 pkt_type; > }; > > +struct hfi_session_hdr_pkt { > + struct hfi_pkt_hdr hdr; > + u32 session_id; > +}; > + > +struct hfi_session_open_pkt { > + struct hfi_session_hdr_pkt shdr; > + u32 session_domain; > + u32 session_codec; > +}; > + > +struct hfi_session_pkt { > + struct hfi_session_hdr_pkt shdr; > +}; > + > struct hfi_sys_init_pkt { > struct hfi_pkt_hdr hdr; > u32 arch_type; > @@ -54,7 +84,7 @@ struct hfi_sys_pc_prep_pkt { > }; > > struct hfi_msg_event_notify_pkt { > - struct hfi_pkt_hdr hdr; > + struct hfi_session_hdr_pkt shdr; > u32 event_id; > u32 event_data1; > u32 event_data2; > @@ -68,6 +98,17 @@ struct hfi_msg_sys_init_done_pkt { > u32 data[]; > }; > > +struct hfi_msg_session_hdr_pkt { > + struct hfi_session_hdr_pkt shdr; > + u32 error_type; > +}; > + > +struct hfi_msg_session_init_done_pkt { > + struct hfi_msg_session_hdr_pkt shdr; > + u32 num_properties; > + u32 data[]; > +}; > + > struct hfi_msg_sys_property_info_pkt { > struct hfi_pkt_hdr hdr; > u32 num_properties; > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c > index 78fefa4176f9..18ba5f67dd36 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c > @@ -13,13 +13,54 @@ iris_hfi_gen1_sys_event_notify(struct iris_core *core, void *packet) > struct hfi_msg_event_notify_pkt *pkt = packet; > > if (pkt->event_id == HFI_EVENT_SYS_ERROR) > - dev_err(core->dev, "sys error (type: %x, data1:%x, data2:%x)\n", > - pkt->event_id, pkt->event_data1, pkt->event_data2); > + dev_err(core->dev, "sys error (type: %x, session id:%x, data1:%x, data2:%x)\n", > + pkt->event_id, pkt->shdr.session_id, pkt->event_data1, > + pkt->event_data2); > > core->state = IRIS_CORE_ERROR; > schedule_delayed_work(&core->sys_error_handler, msecs_to_jiffies(10)); > } > > +static void > +iris_hfi_gen1_event_session_error(struct iris_inst *inst, struct hfi_msg_event_notify_pkt *pkt) > +{ > + switch (pkt->event_data1) { > + /* non fatal session errors */ > + case HFI_ERR_SESSION_INVALID_SCALE_FACTOR: > + case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE: > + case HFI_ERR_SESSION_UNSUPPORTED_SETTING: > + case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED: > + dev_dbg(inst->core->dev, "session error: event id:%x, session id:%x\n", > + pkt->event_data1, pkt->shdr.session_id); > + break; > + /* fatal session errors */ > + default: > + /* > + * firmware fills event_data2 as an additional information about the > + * hfi command for which session error has ouccured. > + */ > + dev_err(inst->core->dev, > + "session error for command: %x, event id:%x, session id:%x\n", > + pkt->event_data2, pkt->event_data1, > + pkt->shdr.session_id); > + iris_vb2_queue_error(inst); > + break; > + } > +} > + > +static void iris_hfi_gen1_session_event_notify(struct iris_inst *inst, void *packet) > +{ > + struct hfi_msg_event_notify_pkt *pkt = packet; > + > + switch (pkt->event_id) { > + case HFI_EVENT_SESSION_ERROR: > + iris_hfi_gen1_event_session_error(inst, pkt); > + break; > + default: > + break; > + } > +} > + > static void iris_hfi_gen1_sys_init_done(struct iris_core *core, void *packet) > { > struct hfi_msg_sys_init_done_pkt *pkt = packet; > @@ -99,6 +140,14 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = { > .pkt = HFI_MSG_SYS_PROPERTY_INFO, > .pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt), > }, > + { > + .pkt = HFI_MSG_SYS_SESSION_INIT, > + .pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt), > + }, > + { > + .pkt = HFI_MSG_SYS_SESSION_END, > + .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt), > + }, > }; > > static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response) > @@ -106,6 +155,8 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response > struct hfi_pkt_hdr *hdr = (struct hfi_pkt_hdr *)response; > const struct iris_hfi_gen1_response_pkt_info *pkt_info; > struct device *dev = core->dev; > + struct hfi_session_pkt *pkt; > + struct iris_inst *inst; > bool found = false; > u32 i; > > @@ -132,9 +183,31 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response > iris_hfi_gen1_sys_property_info(core, hdr); > break; > case HFI_MSG_EVENT_NOTIFY: > - iris_hfi_gen1_sys_event_notify(core, hdr); > + pkt = (struct hfi_session_pkt *)hdr; > + inst = iris_get_instance(core, pkt->shdr.session_id); > + if (inst) { > + mutex_lock(&inst->lock); > + iris_hfi_gen1_session_event_notify(inst, hdr); > + mutex_unlock(&inst->lock); > + } else { > + iris_hfi_gen1_sys_event_notify(core, hdr); > + } > + > break; > default: > + pkt = (struct hfi_session_pkt *)hdr; > + inst = iris_get_instance(core, pkt->shdr.session_id); > + if (!inst) { > + dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n", > + pkt->shdr.session_id, > + pkt_info ? pkt_info->pkt : 0); > + return; > + } > + > + mutex_lock(&inst->lock); > + complete(&inst->completion); > + mutex_unlock(&inst->lock); > + > break; > } > } > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h > index 6ec83984fda9..76f0c9032a92 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.h > @@ -10,13 +10,18 @@ > > struct iris_core; > > +#define to_iris_inst_hfi_gen2(ptr) \ > + container_of(ptr, struct iris_inst_hfi_gen2, inst) > + > /** > * struct iris_inst_hfi_gen2 - holds per video instance parameters for hfi_gen2 > * > * @inst: pointer to iris_instance structure > + * @packet: HFI packet > */ > struct iris_inst_hfi_gen2 { > struct iris_inst inst; > + struct iris_hfi_header *packet; > }; > > void iris_hfi_gen2_command_ops_init(struct iris_core *core); > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c > index f8cb1177ef54..a08e844bb4bb 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c > @@ -85,11 +85,116 @@ static int iris_hfi_gen2_sys_pc_prep(struct iris_core *core) > return ret; > } > > +static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) > +{ > + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + u32 codec = HFI_CODEC_DECODE_AVC; > + > + iris_hfi_gen2_packet_session_property(inst, > + HFI_PROP_CODEC, > + HFI_HOST_FLAGS_NONE, > + HFI_PORT_NONE, > + HFI_PAYLOAD_U32_ENUM, > + &codec, > + sizeof(u32)); > + > + return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet, > + inst_hfi_gen2->packet->size); > +} > + > +static int iris_hfi_gen2_session_set_default_header(struct iris_inst *inst) > +{ > + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + u32 default_header = false; > + > + iris_hfi_gen2_packet_session_property(inst, > + HFI_PROP_DEC_DEFAULT_HEADER, > + HFI_HOST_FLAGS_NONE, > + HFI_PORT_BITSTREAM, > + HFI_PAYLOAD_U32, > + &default_header, > + sizeof(u32)); > + > + return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet, > + inst_hfi_gen2->packet->size); > +} > + > +static int iris_hfi_gen2_session_open(struct iris_inst *inst) > +{ > + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + int ret; > + > + inst_hfi_gen2->packet = kzalloc(4096, GFP_KERNEL); > + if (!inst_hfi_gen2->packet) > + return -ENOMEM; > + > + iris_hfi_gen2_packet_session_command(inst, > + HFI_CMD_OPEN, > + HFI_HOST_FLAGS_RESPONSE_REQUIRED | > + HFI_HOST_FLAGS_INTR_REQUIRED, > + HFI_PORT_NONE, > + 0, > + HFI_PAYLOAD_U32, > + &inst->session_id, > + sizeof(u32)); > + > + ret = iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet, > + inst_hfi_gen2->packet->size); > + if (ret) > + goto fail_free_packet; > + > + ret = iris_hfi_gen2_session_set_codec(inst); > + if (ret) > + goto fail_free_packet; > + > + ret = iris_hfi_gen2_session_set_default_header(inst); > + if (ret) > + goto fail_free_packet; > + > + return 0; > + > +fail_free_packet: > + kfree(inst_hfi_gen2->packet); > + inst_hfi_gen2->packet = NULL; > + > + return ret; > +} > + > +static int iris_hfi_gen2_session_close(struct iris_inst *inst) > +{ > + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + int ret; > + > + if (!inst_hfi_gen2->packet) > + return -EINVAL; > + > + iris_hfi_gen2_packet_session_command(inst, > + HFI_CMD_CLOSE, > + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | > + HFI_HOST_FLAGS_INTR_REQUIRED | > + HFI_HOST_FLAGS_NON_DISCARDABLE), > + HFI_PORT_NONE, > + inst->session_id, > + HFI_PAYLOAD_NONE, > + NULL, > + 0); > + > + ret = iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet, > + inst_hfi_gen2->packet->size); > + > + kfree(inst_hfi_gen2->packet); > + inst_hfi_gen2->packet = NULL; > + > + return ret; > +} > + > static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops = { > .sys_init = iris_hfi_gen2_sys_init, > .sys_image_version = iris_hfi_gen2_sys_image_version, > .sys_interframe_powercollapse = iris_hfi_gen2_sys_interframe_powercollapse, > .sys_pc_prep = iris_hfi_gen2_sys_pc_prep, > + .session_open = iris_hfi_gen2_session_open, > + .session_close = iris_hfi_gen2_session_close, > }; > > void iris_hfi_gen2_command_ops_init(struct iris_core *core) > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h > index 4104479c7251..18cc9365ab75 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h > @@ -13,6 +13,8 @@ > #define HFI_CMD_BEGIN 0x01000000 > #define HFI_CMD_INIT 0x01000001 > #define HFI_CMD_POWER_COLLAPSE 0x01000002 > +#define HFI_CMD_OPEN 0x01000003 > +#define HFI_CMD_CLOSE 0x01000004 > #define HFI_CMD_END 0x01FFFFFF > > #define HFI_PROP_BEGIN 0x03000000 > @@ -25,12 +27,44 @@ > #define HFI_PROP_UBWC_BANK_SWZL_LEVEL2 0x03000007 > #define HFI_PROP_UBWC_BANK_SWZL_LEVEL3 0x03000008 > #define HFI_PROP_UBWC_BANK_SPREADING 0x03000009 > +#define HFI_PROP_CODEC 0x03000100 > +#define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 > #define HFI_PROP_END 0x03FFFFFF > > +#define HFI_SESSION_ERROR_BEGIN 0x04000000 > +#define HFI_ERROR_UNKNOWN_SESSION 0x04000001 > +#define HFI_ERROR_MAX_SESSIONS 0x04000002 > +#define HFI_ERROR_FATAL 0x04000003 > +#define HFI_ERROR_INVALID_STATE 0x04000004 > +#define HFI_ERROR_INSUFFICIENT_RESOURCES 0x04000005 > +#define HFI_ERROR_BUFFER_NOT_SET 0x04000006 > +#define HFI_SESSION_ERROR_END 0x04FFFFFF > + > #define HFI_SYSTEM_ERROR_BEGIN 0x05000000 > #define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001 > #define HFI_SYSTEM_ERROR_END 0x05FFFFFF > > +enum hfi_codec_type { > + HFI_CODEC_DECODE_AVC = 1, > + HFI_CODEC_ENCODE_AVC = 2, > +}; > + > +enum hfi_buffer_type { > + HFI_BUFFER_BITSTREAM = 0x00000001, > + HFI_BUFFER_RAW = 0x00000002, > + HFI_BUFFER_METADATA = 0x00000003, > + HFI_BUFFER_SUBCACHE = 0x00000004, > + HFI_BUFFER_PARTIAL_DATA = 0x00000005, > + HFI_BUFFER_DPB = 0x00000006, > + HFI_BUFFER_BIN = 0x00000007, > + HFI_BUFFER_LINE = 0x00000008, > + HFI_BUFFER_ARP = 0x00000009, > + HFI_BUFFER_COMV = 0x0000000A, > + HFI_BUFFER_NON_COMV = 0x0000000B, > + HFI_BUFFER_PERSIST = 0x0000000C, > + HFI_BUFFER_VPSS = 0x0000000D, > +}; > + > enum hfi_packet_firmware_flags { > HFI_FW_FLAGS_SUCCESS = 0x00000001, > HFI_FW_FLAGS_INFORMATION = 0x00000002, > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c > index 510d44408b41..739b2ce5bfae 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c > @@ -143,6 +143,45 @@ void iris_hfi_gen2_packet_image_version(struct iris_core *core, struct iris_hfi_ > NULL, 0); > } > > +void iris_hfi_gen2_packet_session_command(struct iris_inst *inst, u32 pkt_type, > + u32 flags, u32 port, u32 session_id, > + u32 payload_type, void *payload, > + u32 payload_size) > +{ > + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + struct iris_core *core = inst->core; > + > + iris_hfi_gen2_create_header(inst_hfi_gen2->packet, session_id, core->header_id++); > + > + iris_hfi_gen2_create_packet(inst_hfi_gen2->packet, > + pkt_type, > + flags, > + payload_type, > + port, > + core->packet_id++, > + payload, > + payload_size); > +} > + > +void iris_hfi_gen2_packet_session_property(struct iris_inst *inst, > + u32 pkt_type, u32 flags, u32 port, > + u32 payload_type, void *payload, u32 payload_size) > +{ > + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); > + struct iris_core *core = inst->core; > + > + iris_hfi_gen2_create_header(inst_hfi_gen2->packet, inst->session_id, core->header_id++); > + > + iris_hfi_gen2_create_packet(inst_hfi_gen2->packet, > + pkt_type, > + flags, > + payload_type, > + port, > + core->packet_id++, > + payload, > + payload_size); > +} > + > void iris_hfi_gen2_packet_sys_interframe_powercollapse(struct iris_core *core, > struct iris_hfi_header *hdr) > { > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h > index 163295783b7d..120592322e78 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h > @@ -63,6 +63,13 @@ struct iris_hfi_packet { > > void iris_hfi_gen2_packet_sys_init(struct iris_core *core, struct iris_hfi_header *hdr); > void iris_hfi_gen2_packet_image_version(struct iris_core *core, struct iris_hfi_header *hdr); > +void iris_hfi_gen2_packet_session_command(struct iris_inst *inst, u32 pkt_type, > + u32 flags, u32 port, u32 session_id, > + u32 payload_type, void *payload, > + u32 payload_size); > +void iris_hfi_gen2_packet_session_property(struct iris_inst *inst, > + u32 pkt_type, u32 flags, u32 port, > + u32 payload_type, void *payload, u32 payload_size); > void iris_hfi_gen2_packet_sys_interframe_powercollapse(struct iris_core *core, > struct iris_hfi_header *hdr); > void iris_hfi_gen2_packet_sys_pc_prep(struct iris_core *core, struct iris_hfi_header *hdr); > diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c > index 007e4a7b6782..a7d8c5ff7f2f 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c > @@ -14,6 +14,17 @@ struct iris_hfi_gen2_core_hfi_range { > int (*handle)(struct iris_core *core, struct iris_hfi_packet *pkt); > }; > > +struct iris_hfi_gen2_inst_hfi_range { > + u32 begin; > + u32 end; > + int (*handle)(struct iris_inst *inst, struct iris_hfi_packet *pkt); > +}; > + > +struct iris_hfi_gen2_packet_handle { > + enum hfi_buffer_type type; > + int (*handle)(struct iris_inst *inst, struct iris_hfi_packet *pkt); > +}; > + > static int iris_hfi_gen2_validate_packet(u8 *response_pkt, u8 *core_resp_pkt) > { > u8 *response_limit = core_resp_pkt + IFACEQ_CORE_PKT_SIZE; > @@ -55,6 +66,42 @@ static int iris_hfi_gen2_validate_hdr_packet(struct iris_core *core, struct iris > return 0; > } > > +static int iris_hfi_gen2_handle_session_error(struct iris_inst *inst, > + struct iris_hfi_packet *pkt) > +{ > + struct iris_core *core = inst->core; > + char *error; > + > + switch (pkt->type) { > + case HFI_ERROR_MAX_SESSIONS: > + error = "exceeded max sessions"; > + break; > + case HFI_ERROR_UNKNOWN_SESSION: > + error = "unknown session id"; > + break; > + case HFI_ERROR_INVALID_STATE: > + error = "invalid operation for current state"; > + break; > + case HFI_ERROR_INSUFFICIENT_RESOURCES: > + error = "insufficient resources"; > + break; > + case HFI_ERROR_BUFFER_NOT_SET: > + error = "internal buffers not set"; > + break; > + case HFI_ERROR_FATAL: > + error = "fatal error"; > + break; > + default: > + error = "unknown"; > + break; > + } > + > + dev_err(core->dev, "session error received %#x: %s\n", pkt->type, error); > + iris_vb2_queue_error(inst); > + > + return 0; > +} > + > static int iris_hfi_gen2_handle_system_error(struct iris_core *core, > struct iris_hfi_packet *pkt) > { > @@ -79,6 +126,22 @@ static int iris_hfi_gen2_handle_system_init(struct iris_core *core, > return 0; > } > > +static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst, > + struct iris_hfi_packet *pkt) > +{ > + int ret = 0; > + > + switch (pkt->type) { > + case HFI_CMD_CLOSE: > + complete(&inst->completion); > + break; > + default: > + break; > + } > + > + return ret; > +} > + > static int iris_hfi_gen2_handle_image_version_property(struct iris_core *core, > struct iris_hfi_packet *pkt) > { > @@ -152,6 +215,46 @@ static int iris_hfi_gen2_handle_system_response(struct iris_core *core, > return 0; > } > > +static int iris_hfi_gen2_handle_session_response(struct iris_core *core, > + struct iris_hfi_header *hdr) > +{ > + struct iris_hfi_packet *packet; > + struct iris_inst *inst; > + int ret = 0; > + u32 i, j; > + u8 *pkt; > + static const struct iris_hfi_gen2_inst_hfi_range range[] = { > + {HFI_SESSION_ERROR_BEGIN, HFI_SESSION_ERROR_END, > + iris_hfi_gen2_handle_session_error}, > + {HFI_CMD_BEGIN, HFI_CMD_END, > + iris_hfi_gen2_handle_session_command }, > + }; > + > + inst = iris_get_instance(core, hdr->session_id); > + if (!inst) > + return -EINVAL; > + > + mutex_lock(&inst->lock); > + > + pkt = (u8 *)((u8 *)hdr + sizeof(*hdr)); > + for (i = 0; i < ARRAY_SIZE(range); i++) { > + pkt = (u8 *)((u8 *)hdr + sizeof(*hdr)); > + for (j = 0; j < hdr->num_packets; j++) { > + packet = (struct iris_hfi_packet *)pkt; > + if (packet->flags & HFI_FW_FLAGS_SESSION_ERROR) > + iris_hfi_gen2_handle_session_error(inst, packet); > + > + if (packet->type > range[i].begin && packet->type < range[i].end) > + ret = range[i].handle(inst, packet); > + pkt += packet->size; > + } > + } > + > + mutex_unlock(&inst->lock); > + > + return ret; > +} > + > static int iris_hfi_gen2_handle_response(struct iris_core *core, void *response) > { > struct iris_hfi_header *hdr = (struct iris_hfi_header *)response; > @@ -161,7 +264,10 @@ static int iris_hfi_gen2_handle_response(struct iris_core *core, void *response) > if (ret) > return iris_hfi_gen2_handle_system_error(core, NULL); > > - return iris_hfi_gen2_handle_system_response(core, hdr); > + if (!hdr->session_id) > + return iris_hfi_gen2_handle_system_response(core, hdr); > + else > + return iris_hfi_gen2_handle_session_response(core, hdr); > } > > static void iris_hfi_gen2_flush_debug_queue(struct iris_core *core, u8 *packet) > diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h > index 63cb9d70166f..bb43119af352 100644 > --- a/drivers/media/platform/qcom/iris/iris_instance.h > +++ b/drivers/media/platform/qcom/iris/iris_instance.h > @@ -6,24 +6,46 @@ > #ifndef _IRIS_INSTANCE_H_ > #define _IRIS_INSTANCE_H_ > > +#include <media/v4l2-ctrls.h> > + > +#include "iris_buffer.h" > #include "iris_core.h" > +#include "iris_utils.h" > > /** > * struct iris_inst - holds per video instance parameters > * > + * @list: used for attach an instance to the core > * @core: pointer to core structure > + * @session_id: id of current video session > * @ctx_q_lock: lock to serialize queues related ioctls > * @lock: lock to seralise forward and reverse threads > * @fh: reference of v4l2 file handler > + * @fmt_src: structure of v4l2_format for source > + * @fmt_dst: structure of v4l2_format for destination > + * @crop: structure of crop info > + * @completions: structure of signal completions > + * @buffers: array of different iris buffers > + * @fw_min_count: minimnum count of buffers needed by fw > + * @once_per_session_set: boolean to set once per session property > * @m2m_dev: a reference to m2m device structure > * @m2m_ctx: a reference to m2m context structure > */ > > struct iris_inst { > + struct list_head list; > struct iris_core *core; > + u32 session_id; > struct mutex ctx_q_lock;/* lock to serialize queues related ioctls */ > struct mutex lock; /* lock to serialize forward and reverse threads */ > struct v4l2_fh fh; > + struct v4l2_format *fmt_src; > + struct v4l2_format *fmt_dst; > + struct iris_hfi_rect_desc crop; > + struct completion completion; > + struct iris_buffers buffers[BUF_TYPE_MAX]; > + u32 fw_min_count; > + bool once_per_session_set; > struct v4l2_m2m_dev *m2m_dev; > struct v4l2_m2m_ctx *m2m_ctx; > }; > diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h > index ff11d28e853b..e345667dfbf2 100644 > --- a/drivers/media/platform/qcom/iris/iris_platform_common.h > +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h > @@ -42,6 +42,9 @@ struct ubwc_config_data { > u32 bank_spreading; > }; > > +struct platform_inst_caps { > + u32 max_mbpf; > +}; > struct iris_core_power { > u64 clk_freq; > u64 icc_bw; > @@ -71,11 +74,13 @@ struct iris_platform_data { > u64 dma_mask; > const char *fwname; > u32 pas_id; > + struct platform_inst_caps *inst_caps; > struct tz_cp_config *tz_cp_config_data; > u32 core_arch; > u32 hw_response_timeout; > struct ubwc_config_data *ubwc_config; > u32 num_vpp_pipe; > + u32 max_session_count; > }; > > #endif > diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > index b4c730c58558..bc4769732aad 100644 > --- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > @@ -10,6 +10,10 @@ > > #define VIDEO_ARCH_LX 1 > > +static struct platform_inst_caps platform_inst_cap_sm8550 = { > + .max_mbpf = (8192 * 4352) / 256, > +}; > + > static void iris_set_sm8550_preset_registers(struct iris_core *core) > { > writel(0x0, core->reg_base + 0xB0088); > @@ -68,9 +72,11 @@ struct iris_platform_data sm8550_data = { > .dma_mask = GENMASK(31, 29) - 1, > .fwname = "qcom/vpu/vpu30_p4.mbn", > .pas_id = IRIS_PAS_ID, > + .inst_caps = &platform_inst_cap_sm8550, > .tz_cp_config_data = &tz_cp_config_sm8550, > .core_arch = VIDEO_ARCH_LX, > .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, > .ubwc_config = &ubwc_config_sm8550, > .num_vpp_pipe = 4, > + .max_session_count = 16, > }; > diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c > index 0a2e03105360..ee0d1cd5732f 100644 > --- a/drivers/media/platform/qcom/iris/iris_probe.c > +++ b/drivers/media/platform/qcom/iris/iris_probe.c > @@ -142,6 +142,7 @@ static int iris_register_video_device(struct iris_core *core) > strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); > vdev->release = video_device_release; > vdev->fops = core->iris_v4l2_file_ops; > + vdev->ioctl_ops = core->iris_v4l2_ioctl_ops; > vdev->vfl_dir = VFL_DIR_M2M; > vdev->v4l2_dev = &core->v4l2_dev; > vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; > @@ -208,6 +209,7 @@ static int iris_probe(struct platform_device *pdev) > if (!core->response_packet) > return -ENOMEM; > > + INIT_LIST_HEAD(&core->instances); > INIT_DELAYED_WORK(&core->sys_error_handler, iris_sys_error_handler); > > core->reg_base = devm_platform_ioremap_resource(pdev, 0); > diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c > new file mode 100644 > index 000000000000..499088b126f6 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_utils.c > @@ -0,0 +1,51 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include <linux/pm_runtime.h> > + > +#include "iris_instance.h" > +#include "iris_utils.h" > + > +int iris_get_mbpf(struct iris_inst *inst) > +{ > + struct v4l2_format *inp_f = inst->fmt_src; > + u32 height = max(inp_f->fmt.pix_mp.height, inst->crop.height); > + u32 width = max(inp_f->fmt.pix_mp.width, inst->crop.width); > + > + return NUM_MBS_PER_FRAME(height, width); > +} > + > +int iris_wait_for_session_response(struct iris_inst *inst) > +{ > + struct iris_core *core = inst->core; > + u32 hw_response_timeout_val; > + int ret; > + > + hw_response_timeout_val = core->iris_platform_data->hw_response_timeout; > + > + mutex_unlock(&inst->lock); > + ret = wait_for_completion_timeout(&inst->completion, > + msecs_to_jiffies(hw_response_timeout_val)); > + mutex_lock(&inst->lock); > + if (!ret) > + return -ETIMEDOUT; > + > + return 0; > +} > + > +struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id) > +{ > + struct iris_inst *inst = NULL; > + > + mutex_lock(&core->lock); > + list_for_each_entry(inst, &core->instances, list) { > + if (inst->session_id == session_id) > + goto done; > + } > + > +done: > + mutex_unlock(&core->lock); > + return inst; > +} > diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h > new file mode 100644 > index 000000000000..1c1e109d9b5b > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_utils.h > @@ -0,0 +1,38 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef _IRIS_UTILS_H_ > +#define _IRIS_UTILS_H_ > + > +struct iris_core; > +#include "iris_buffer.h" > + > +struct iris_hfi_rect_desc { > + u32 left; > + u32 top; > + u32 width; > + u32 height; > +}; > + > +#define NUM_MBS_PER_FRAME(height, width) \ > + (DIV_ROUND_UP(height, 16) * DIV_ROUND_UP(width, 16)) > + > +static inline enum iris_buffer_type iris_v4l2_type_to_driver(u32 type) > +{ > + switch (type) { > + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: > + return BUF_INPUT; > + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: > + return BUF_OUTPUT; > + default: > + return -EINVAL; > + } > +} > + > +int iris_get_mbpf(struct iris_inst *inst); > +struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id); > +int iris_wait_for_session_response(struct iris_inst *inst); > + > +#endif > diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c > new file mode 100644 > index 000000000000..61033f95cdba > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_vb2.c > @@ -0,0 +1,74 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include "iris_buffer.h" > +#include "iris_instance.h" > +#include "iris_vb2.h" > +#include "iris_vpu_buffer.h" > + > +int iris_vb2_queue_setup(struct vb2_queue *q, > + unsigned int *num_buffers, unsigned int *num_planes, > + unsigned int sizes[], struct device *alloc_devs[]) > +{ > + enum iris_buffer_type buffer_type = 0; > + struct iris_buffers *buffers; > + struct iris_inst *inst; > + struct iris_core *core; > + struct v4l2_format *f; > + int ret = 0; > + > + inst = vb2_get_drv_priv(q); > + > + mutex_lock(&inst->lock); > + > + core = inst->core; > + f = V4L2_TYPE_IS_OUTPUT(q->type) ? inst->fmt_src : inst->fmt_dst; > + > + if (*num_planes) { > + if (*num_planes != f->fmt.pix_mp.num_planes || > + sizes[0] < f->fmt.pix_mp.plane_fmt[0].sizeimage) > + ret = -EINVAL; > + goto unlock; > + } > + > + buffer_type = iris_v4l2_type_to_driver(q->type); > + if (buffer_type == -EINVAL) { Can this ever fail? > + ret = -EINVAL; > + goto unlock; > + } > + > + if (!inst->once_per_session_set) { > + inst->once_per_session_set = true; > + > + ret = core->hfi_ops->session_open(inst); > + if (ret) { > + ret = -EINVAL; > + dev_err(core->dev, "session open failed\n"); > + goto unlock; > + } > + } > + > + buffers = &inst->buffers[buffer_type]; > + if (!buffers) { This definitely can never fail. > + ret = -EINVAL; > + goto unlock; > + } > + > + buffers->min_count = iris_vpu_buf_count(inst, buffer_type); > + buffers->actual_count = *num_buffers; Don't mirror the number of buffers in actual_count, instead just always ask for the number of buffers using vb2_get_num_buffers(). This code is wrong anyway, since actual_count isn't updated if more buffers are added using VIDIOC_CREATEBUFS. > + *num_planes = 1; > + > + buffers->size = iris_get_buffer_size(inst, buffer_type); > + > + if (sizes[0] < buffers->size) { > + f->fmt.pix_mp.plane_fmt[0].sizeimage = buffers->size; Isn't this something that is set in VIDIOC_S_FMT? Can what iris_get_buffer_size returns here be different from what VIDIOC_S_FMT does? This is weird code, I don't think it belong in queue_setup. If iris_get_buffer_size can really give a different result, then it needs to be explained carefully, since that would be unexpected and possibly non-compliant. > + sizes[0] = f->fmt.pix_mp.plane_fmt[0].sizeimage; > + } > + > +unlock: > + mutex_unlock(&inst->lock); > + > + return ret; > +} > diff --git a/drivers/media/platform/qcom/iris/iris_vb2.h b/drivers/media/platform/qcom/iris/iris_vb2.h > new file mode 100644 > index 000000000000..78157a97b86e > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_vb2.h > @@ -0,0 +1,12 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef _IRIS_VB2_H_ > +#define _IRIS_VB2_H_ > + > +int iris_vb2_queue_setup(struct vb2_queue *q, > + unsigned int *num_buffers, unsigned int *num_planes, > + unsigned int sizes[], struct device *alloc_devs[]); > +#endif > diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c > new file mode 100644 > index 000000000000..7d1ef31c7c44 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_vdec.c > @@ -0,0 +1,58 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include "iris_buffer.h" > +#include "iris_instance.h" > +#include "iris_vdec.h" > +#include "iris_vpu_buffer.h" > + > +#define DEFAULT_WIDTH 320 > +#define DEFAULT_HEIGHT 240 > + > +void iris_vdec_inst_init(struct iris_inst *inst) > +{ > + struct v4l2_format *f; > + > + inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); > + inst->fmt_dst = kzalloc(sizeof(*inst->fmt_dst), GFP_KERNEL); > + > + inst->fw_min_count = MIN_BUFFERS; > + > + f = inst->fmt_src; > + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; > + f->fmt.pix_mp.width = DEFAULT_WIDTH; > + f->fmt.pix_mp.height = DEFAULT_HEIGHT; > + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; > + f->fmt.pix_mp.num_planes = 1; > + f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; > + f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); > + f->fmt.pix_mp.field = V4L2_FIELD_NONE; > + inst->buffers[BUF_INPUT].min_count = iris_vpu_buf_count(inst, BUF_INPUT); > + inst->buffers[BUF_INPUT].actual_count = inst->buffers[BUF_INPUT].min_count; > + inst->buffers[BUF_INPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; > + > + f = inst->fmt_dst; > + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; > + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; > + f->fmt.pix_mp.width = ALIGN(DEFAULT_WIDTH, 128); > + f->fmt.pix_mp.height = ALIGN(DEFAULT_HEIGHT, 32); > + f->fmt.pix_mp.num_planes = 1; > + f->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(DEFAULT_WIDTH, 128); > + f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); > + f->fmt.pix_mp.field = V4L2_FIELD_NONE; > + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; > + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; > + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; > + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; > + inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); > + inst->buffers[BUF_OUTPUT].actual_count = inst->buffers[BUF_OUTPUT].min_count; > + inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; > +} > + > +void iris_vdec_inst_deinit(struct iris_inst *inst) > +{ > + kfree(inst->fmt_dst); > + kfree(inst->fmt_src); > +} > diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h > new file mode 100644 > index 000000000000..0324d7f796dd > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_vdec.h > @@ -0,0 +1,14 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef _IRIS_VDEC_H_ > +#define _IRIS_VDEC_H_ > + > +struct iris_inst; > + > +void iris_vdec_inst_init(struct iris_inst *inst); > +void iris_vdec_inst_deinit(struct iris_inst *inst); > + > +#endif > diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c > index b8654e73f516..ab3b63171c1d 100644 > --- a/drivers/media/platform/qcom/iris/iris_vidc.c > +++ b/drivers/media/platform/qcom/iris/iris_vidc.c > @@ -9,6 +9,9 @@ > > #include "iris_vidc.h" > #include "iris_instance.h" > +#include "iris_vdec.h" > +#include "iris_vb2.h" > +#include "iris_vpu_buffer.h" > #include "iris_platform_common.h" > > #define IRIS_DRV_NAME "iris_driver" > @@ -28,6 +31,38 @@ static void iris_v4l2_fh_deinit(struct iris_inst *inst) > v4l2_fh_exit(&inst->fh); > } > > +static void iris_add_session(struct iris_inst *inst) > +{ > + struct iris_core *core = inst->core; > + struct iris_inst *iter; > + u32 count = 0; > + > + mutex_lock(&core->lock); > + > + list_for_each_entry(iter, &core->instances, list) > + count++; > + > + if (count < core->iris_platform_data->max_session_count) > + list_add_tail(&inst->list, &core->instances); > + > + mutex_unlock(&core->lock); > +} > + > +static void iris_remove_session(struct iris_inst *inst) > +{ > + struct iris_core *core = inst->core; > + struct iris_inst *iter, *temp; > + > + mutex_lock(&core->lock); > + list_for_each_entry_safe(iter, temp, &core->instances, list) { > + if (iter->session_id == inst->session_id) { > + list_del_init(&iter->list); > + break; > + } > + } > + mutex_unlock(&core->lock); > +} > + > static inline struct iris_inst *iris_get_inst(struct file *filp, void *fh) > { > return container_of(filp->private_data, struct iris_inst, fh); > @@ -59,7 +94,10 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ > src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; > src_vq->io_modes = VB2_MMAP | VB2_DMABUF; > src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; > + src_vq->ops = inst->core->iris_vb2_ops; > src_vq->drv_priv = inst; > + src_vq->buf_struct_size = sizeof(struct iris_buffer); > + src_vq->min_reqbufs_allocation = MIN_BUFFERS; > src_vq->dev = inst->core->dev; > src_vq->lock = &inst->ctx_q_lock; > ret = vb2_queue_init(src_vq); > @@ -69,7 +107,10 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ > dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; > dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; > dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; > + dst_vq->ops = inst->core->iris_vb2_ops; > dst_vq->drv_priv = inst; > + dst_vq->buf_struct_size = sizeof(struct iris_buffer); > + dst_vq->min_reqbufs_allocation = MIN_BUFFERS; > dst_vq->dev = inst->core->dev; > dst_vq->lock = &inst->ctx_q_lock; > > @@ -100,8 +141,11 @@ int iris_open(struct file *filp) > return -ENOMEM; > > inst->core = core; > + inst->session_id = hash32_ptr(inst); > > + mutex_init(&inst->lock); > mutex_init(&inst->ctx_q_lock); > + init_completion(&inst->completion); > > iris_v4l2_fh_init(inst); > > @@ -117,6 +161,10 @@ int iris_open(struct file *filp) > goto fail_m2m_release; > } > > + iris_vdec_inst_init(inst); > + > + iris_add_session(inst); > + > inst->fh.m2m_ctx = inst->m2m_ctx; > filp->private_data = &inst->fh; > > @@ -127,19 +175,42 @@ int iris_open(struct file *filp) > fail_v4l2_fh_deinit: > iris_v4l2_fh_deinit(inst); > mutex_destroy(&inst->ctx_q_lock); > + mutex_destroy(&inst->lock); > kfree(inst); > > return ret; > } > > +static void iris_session_close(struct iris_inst *inst) > +{ > + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; > + bool wait_for_response = true; > + int ret; > + > + reinit_completion(&inst->completion); > + > + ret = hfi_ops->session_close(inst); > + if (ret) > + wait_for_response = false; > + > + if (wait_for_response) > + iris_wait_for_session_response(inst); > +} > + > int iris_close(struct file *filp) > { > struct iris_inst *inst = iris_get_inst(filp, NULL); > > v4l2_m2m_ctx_release(inst->m2m_ctx); > v4l2_m2m_release(inst->m2m_dev); > + mutex_lock(&inst->lock); > + iris_vdec_inst_deinit(inst); > + iris_session_close(inst); > iris_v4l2_fh_deinit(inst); > + iris_remove_session(inst); > + mutex_unlock(&inst->lock); > mutex_destroy(&inst->ctx_q_lock); > + mutex_destroy(&inst->lock); > kfree(inst); > filp->private_data = NULL; > > @@ -155,7 +226,17 @@ static struct v4l2_file_operations iris_v4l2_file_ops = { > .mmap = v4l2_m2m_fop_mmap, > }; > > +static const struct vb2_ops iris_vb2_ops = { > + .queue_setup = iris_vb2_queue_setup, > +}; > + > +static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { > + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, > +}; > + > void iris_init_ops(struct iris_core *core) > { > core->iris_v4l2_file_ops = &iris_v4l2_file_ops; > + core->iris_vb2_ops = &iris_vb2_ops; > + core->iris_v4l2_ioctl_ops = &iris_v4l2_ioctl_ops; > } > diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c > new file mode 100644 > index 000000000000..2402a33723ab > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c > @@ -0,0 +1,19 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include "iris_instance.h" > +#include "iris_vpu_buffer.h" > + > +int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type) > +{ > + switch (buffer_type) { > + case BUF_INPUT: > + return MIN_BUFFERS; > + case BUF_OUTPUT: > + return inst->fw_min_count; > + default: > + return 0; > + } > +} > diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h > new file mode 100644 > index 000000000000..f0f974cebd8a > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h > @@ -0,0 +1,15 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef _IRIS_VPU_BUFFER_H_ > +#define _IRIS_VPU_BUFFER_H_ > + > +struct iris_inst; > + > +#define MIN_BUFFERS 4 > + > +int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type); > + > +#endif > Regards, Hans