[PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit

CK Hu (胡俊光) ck.hu at mediatek.com
Thu Jul 24 01:36:45 PDT 2025


On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin at mediatek.com>
> 
> Introduces the top media device driver for the MediaTek ISP7X CAMSYS. The driver maintains the camera system, including sub-device management, DMA operations, and integration with the V4L2 framework. It handles request stream data, buffer management, MediaTek-specific features, pipeline management, streaming control, and error handling mechanisms. Additionally, it aggregates sub-drivers for the camera interface, raw, and yuv pipelines.
> 
> ---

[snip]

> +int mtk_cam_dequeue_req_frame(struct mtk_cam_ctx *ctx,
> +			      unsigned int dequeued_frame_seq_no,
> +			      int pipe_id)
> +{
> +	struct mtk_cam_request *req, *req_prev;
> +	struct mtk_cam_request_stream_data *s_data, *s_data_pipe;
> +	struct mtk_cam_request_stream_data *deq_s_data[RUNNING_JOB_DEPTH];
> +	struct mtk_raw_pipeline *pipe = ctx->pipe;
> +	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
> +	struct mtk_ae_debug_data ae_data;
> +	int buf_state;
> +	u32 dequeue_cnt, s_data_cnt, handled_cnt;
> +	bool del_job, del_req;
> +	bool unreliable = false;
> +	unsigned int done_status_latch;
> +
> +	memset(&ae_data, 0, sizeof(struct mtk_ae_debug_data));
> +	dequeue_cnt = 0;
> +	s_data_cnt = 0;
> +	spin_lock(&ctx->cam->running_job_lock);
> +	list_for_each_entry_safe(req, req_prev, &ctx->cam->running_job_list, list) {
> +		if (!(req->pipe_used & (1 << pipe_id)))
> +			continue;
> +
> +		s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0);
> +		if (!s_data) {
> +			dev_info(ctx->cam->dev,
> +				 "frame_seq:%d[ctx=%d,pipe=%d], de-queue request not found\n",
> +				 dequeued_frame_seq_no, ctx->stream_id, pipe_id);
> +			continue;
> +		}
> +
> +		if (s_data->frame_seq_no > dequeued_frame_seq_no)
> +			goto STOP_SCAN;
> +
> +		deq_s_data[s_data_cnt++] = s_data;
> +		if (s_data_cnt >= RUNNING_JOB_DEPTH) {
> +			dev_info(ctx->cam->dev,
> +				 "%s:%s:ctx(%d):pipe(%d):seq(%d/%d) dequeue s_data over local buffer cnt(%d)\n",
> +				 __func__, req->req.debug_str, ctx->stream_id, pipe_id,
> +				 s_data->frame_seq_no, dequeued_frame_seq_no,
> +				 s_data_cnt);
> +			goto STOP_SCAN;
> +		}
> +	}
> +
> +STOP_SCAN:
> +	spin_unlock(&ctx->cam->running_job_lock);
> +
> +	for (handled_cnt = 0; handled_cnt < s_data_cnt; handled_cnt++) {
> +		s_data = deq_s_data[handled_cnt];
> +		del_req = false;
> +		del_job = false;
> +		req = mtk_cam_s_data_get_req(s_data);
> +		if (!req) {
> +			dev_info(ctx->cam->dev,
> +				 "%s:ctx(%d):pipe(%d):seq(%d) req not found\n",
> +				 __func__, ctx->stream_id, pipe_id,
> +				 s_data->frame_seq_no);
> +			continue;
> +		}
> +
> +		spin_lock(&req->done_status_lock);
> +
> +		if (req->done_status & 1 << pipe_id) {
> +			/* already handled by another job done work */
> +			spin_unlock(&req->done_status_lock);
> +			continue;
> +		}
> +
> +		/* Check whether all pipelines of single ctx are done */
> +		req->done_status |= 1 << pipe_id;
> +		if ((req->done_status & ctx->streaming_pipe) ==
> +		    (req->pipe_used & ctx->streaming_pipe))
> +			del_job = true;
> +
> +		if ((req->done_status & ctx->cam->streaming_pipe) ==
> +		    (req->pipe_used & ctx->cam->streaming_pipe)) {
> +			if (MTK_CAM_REQ_STATE_RUNNING ==
> +			    atomic_cmpxchg(&req->state,
> +					   MTK_CAM_REQ_STATE_RUNNING,
> +					   MTK_CAM_REQ_STATE_DELETING))
> +				del_req = true;
> +		}
> +		done_status_latch = req->done_status;
> +		spin_unlock(&req->done_status_lock);
> +
> +		if (is_raw_subdev(pipe_id) && debug_ae) {
> +			mtk_cam_raw_dump_aa_info(ctx, &ae_data);
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d),metaout,size(%u,%u),AA(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)\n",
> +				__func__, req->req.debug_str, ctx->stream_id, pipe_id,
> +				dequeued_frame_seq_no, s_data->frame_seq_no,
> +				done_status_latch, req->pipe_used,
> +				ctx->streaming_pipe, ctx->cam->streaming_pipe,
> +				del_job, del_req,
> +				pipe->res_config.sink_fmt.width,
> +				pipe->res_config.sink_fmt.height,
> +				ae_data.obc_r1_sum[0], ae_data.obc_r1_sum[1],
> +				ae_data.obc_r1_sum[2], ae_data.obc_r1_sum[3],
> +				ae_data.obc_r2_sum[0], ae_data.obc_r2_sum[1],
> +				ae_data.obc_r2_sum[2], ae_data.obc_r2_sum[3],
> +				ae_data.obc_r3_sum[0], ae_data.obc_r3_sum[1],
> +				ae_data.obc_r3_sum[2], ae_data.obc_r3_sum[3],
> +				ae_data.aa_sum[0], ae_data.aa_sum[1],
> +				ae_data.aa_sum[2], ae_data.aa_sum[3],
> +				ae_data.ltm_sum[0], ae_data.ltm_sum[1],
> +				ae_data.ltm_sum[2], ae_data.ltm_sum[3]);

Add comment to describe what these information is and how to use these information to debug.

> +		} else {
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d)\n",
> +				dequeued_frame_seq_no, s_data->frame_seq_no,
> +				done_status_latch, req->pipe_used,
> +				ctx->streaming_pipe, ctx->cam->streaming_pipe,
> +				del_job, del_req);
> +		}
> +
> +		if (is_raw_subdev(pipe_id)) {
> +			mtk_cam_get_timestamp(ctx, s_data);
> +			mtk_cam_req_works_clean(s_data);
> +		}
> +
> +		if (del_job) {
> +			atomic_dec(&ctx->running_s_data_cnt);
> +			mtk_camsys_state_delete(ctx, sensor_ctrl, req);
> +
> +			/* release internal buffers */
> +			finish_cq_buf(s_data);
> +		}
> +
> +		if (del_req) {
> +			mtk_cam_del_req_from_running(ctx, req, pipe_id);
> +			dequeue_cnt++;
> +		}
> +
> +		/* release vb2 buffers of the pipe */
> +		s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, 0);
> +		if (!s_data_pipe) {
> +			dev_info(ctx->cam->dev,
> +				 "%s:%s:ctx(%d):pipe(%d):seq(%d) s_data_pipe not found\n",
> +				 __func__, req->req.debug_str, ctx->stream_id, pipe_id,
> +				 s_data->frame_seq_no);
> +			continue;
> +		}
> +
> +		if (s_data->frame_seq_no < dequeued_frame_seq_no) {
> +			buf_state = VB2_BUF_STATE_ERROR;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, time:%lld drop, ctx:%d\n",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no, s_data->timestamp,
> +				ctx->stream_id);
> +		} else if (s_data->state.estate == E_STATE_DONE_MISMATCH) {
> +			buf_state = VB2_BUF_STATE_ERROR;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, state done mismatch",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no);
> +		} else if (unreliable) {
> +			buf_state = VB2_BUF_STATE_ERROR;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, done (unreliable)",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no);
> +		} else {
> +			buf_state = VB2_BUF_STATE_DONE;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, done success",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no);
> +		}
> +
> +		if (mtk_cam_s_data_set_buf_state(s_data_pipe, buf_state)) {
> +			/* handle vb2_buffer_done */
> +			if (mtk_cam_req_put(req, pipe_id))
> +				dev_dbg(ctx->cam->dev,
> +					"%s:%s:pipe(%d) return request",
> +					__func__, req->req.debug_str, pipe_id);
> +		}
> +	}
> +
> +	return dequeue_cnt;
> +}
> +

[snip]

> +
> +void isp_composer_destroy_session(struct mtk_cam_ctx *ctx)

Only error case would call isp_composer_destroy_session().
In normal stop flow, it does not call isp_composer_destroy_session().
This would result in hang up in mtk_cam_stop_ctx().
It would wait compeletion but it would never complete because isp_composer_destroy_session() is not called.
Test your driver with stop flow and fix it.

> +{
> +	struct mtk_cam_device *cam = ctx->cam;
> +	struct mtkcam_ipi_event event;
> +	struct mtkcam_ipi_session_cookie *session = &event.cookie;
> +
> +	memset(&event, 0, sizeof(event));
> +	event.cmd_id = CAM_CMD_DESTROY_SESSION;
> +	session->session_id = ctx->stream_id;
> +	scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event,
> +		     sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT);
> +	dev_info(cam->dev, "IPI send id: %d\n", event.cmd_id);
> +}
> +

[snip]

> +void mtk_cam_apply_pending_dev_config(struct mtk_cam_request_stream_data *s_data)

mtk_cam_apply_pending_dev_config() is useless. Drop it.

> +{
> +	struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data;
> +	struct mtk_cam_ctx *ctx;
> +	char *debug_str = mtk_cam_s_data_get_dbg_str(s_data);
> +
> +	s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data);
> +	if (!s_raw_pipe_data)
> +		return;
> +
> +	ctx = mtk_cam_s_data_get_ctx(s_data);
> +	if (!ctx)
> +		return;
> +	ctx->pipe->feature_active = ctx->pipe->user_res.raw_res.feature;
> +	ctx->pipe->enabled_raw = s_raw_pipe_data->enabled_raw;
> +	ctx->used_raw_dev = s_raw_pipe_data->enabled_raw;
> +
> +	dev_info(ctx->cam->dev,
> +		 "%s:%s:pipe(%d):seq(%d):feature_active(0x%llx), ctx->pipe->user_res.raw_res.feature(%lld), enabled_raw(0x%x)\n",
> +		 __func__, debug_str, ctx->stream_id, s_data->frame_seq_no,
> +		 ctx->pipe->feature_active,
> +		 ctx->pipe->user_res.raw_res.feature,
> +		 ctx->pipe->enabled_raw);
> +}
> +

[snip]

> +int mtk_cam_call_seninf_set_pixelmode(struct mtk_cam_ctx *ctx,
> +				      struct v4l2_subdev *sd,
> +				      int pad_id, int pixel_mode)

static int mtk_cam_call_seninf_set_pixelmode(...

pad_idx is always PAD_SRC_RAW0, so use PAD_SRC_RAW0 to replace pad_id. Drop pad_id.

> +{
> +	int ret;
> +
> +	ret = mtk_cam_seninf_set_pixelmode(sd, pad_id, pixel_mode);

mtk_cam_seninf_set_pixelmode() would always get PAD_SRC_RAW0 as pad_id,
so drop pad_id parameter of mtk_cam_seninf_set_pixelmode().

> +	dev_dbg(ctx->cam->dev,
> +		"%s:ctx(%d): seninf(%s): pad(%d), pixel_mode(%d)\n, ret(%d)",
> +		__func__, ctx->stream_id, sd->name, pad_id, pixel_mode,
> +		ret);
> +
> +	return ret;
> +}
> +
> +int mtk_cam_ctx_stream_on(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node)
> +{
> +	struct mtk_cam_device *cam = ctx->cam;
> +	struct device *dev;
> +	struct mtk_raw_device *raw_dev;
> +	int i, ret;
> +	int tgo_pxl_mode;
> +	unsigned int streaming_ctx_latch;
> +
> +	dev_dbg(cam->dev, "ctx %d stream on, streaming_pipe:0x%x\n",
> +		ctx->stream_id, ctx->streaming_pipe);
> +
> +	if (ctx->streaming) {
> +		dev_dbg(cam->dev, "ctx-%d is already streaming on\n", ctx->stream_id);
> +		return 0;
> +	}
> +
> +	for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++) {
> +		ret = v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 1);
> +		if (ret) {
> +			dev_info(cam->dev, "failed to stream on %s: %d\n",
> +				 ctx->pipe_subdevs[i]->name, ret);
> +			goto fail_pipe_off;
> +		}
> +	}
> +
> +	if (ctx->used_raw_num) {
> +		tgo_pxl_mode = ctx->pipe->res_config.tgo_pxl_mode;
> +
> +		ret = mtk_cam_dev_config(ctx);
> +		if (ret)
> +			goto fail_pipe_off;
> +		dev = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev);
> +		if (!dev) {
> +			dev_info(cam->dev, "streamon raw device not found\n");
> +			goto fail_pipe_off;
> +		}
> +		raw_dev = dev_get_drvdata(dev);
> +
> +		mtk_cam_call_seninf_set_pixelmode(ctx, ctx->seninf,
> +							PAD_SRC_RAW0,
> +							tgo_pxl_mode);
> +		mtk_cam_seninf_set_camtg(ctx->seninf, PAD_SRC_RAW0,
> +						pipeid_to_tgidx(raw_dev->id));

mtk_cam_seninf_set_camtg() parameter pad_id is always PAD_SRC_RAW0,
so use PAD_SRC_RAW0 to replace pad_id and drop pad_id parameter.

> +	}
> +
> +
> +	ret = v4l2_subdev_call(ctx->seninf, video, s_stream, 1);
> +	if (ret) {
> +		dev_info(cam->dev, "failed to stream on seninf %s:%d\n",
> +				ctx->seninf->name, ret);
> +		goto fail_pipe_off;
> +	}
> +
> +	if (ctx->used_raw_num) {
> +		mtk_cam_raw_initialize(raw_dev, 0);
> +		/* Twin */
> +		if (ctx->pipe->res_config.raw_num_used != 1) {
> +			struct mtk_raw_device *raw_dev_sub =
> +			get_sub_raw_dev(cam, ctx->pipe);
> +			mtk_cam_raw_initialize(raw_dev_sub, 1);
> +			if (ctx->pipe->res_config.raw_num_used == 3) {
> +				struct mtk_raw_device *raw_dev_sub2 =
> +					get_sub2_raw_dev(cam, ctx->pipe);
> +				mtk_cam_raw_initialize(raw_dev_sub2, 1);
> +			}
> +		}
> +	}
> +
> +	spin_lock(&ctx->streaming_lock);
> +
> +	streaming_ctx_latch = cam->streaming_ctx;
> +	ctx->streaming = true;
> +	cam->streaming_ctx |= 1 << ctx->stream_id;
> +	spin_unlock(&ctx->streaming_lock);
> +
> +	ret = mtk_camsys_ctrl_start(ctx);
> +	if (ret)
> +		goto fail_streaming_off;
> +
> +	mutex_lock(&cam->queue_lock);
> +	mtk_cam_dev_req_try_queue(cam);  /* request moved into working list */
> +	mutex_unlock(&cam->queue_lock);
> +	if (watchdog_scenario(ctx))
> +		mtk_ctx_watchdog_start(ctx, 4);
> +
> +	dev_dbg(cam->dev, "streamed on camsys ctx:%d\n", ctx->stream_id);
> +
> +	return 0;
> +
> +fail_streaming_off:
> +	spin_lock(&ctx->streaming_lock);
> +	ctx->streaming = false;
> +	cam->streaming_ctx &= ~(1 << ctx->stream_id);
> +	spin_unlock(&ctx->streaming_lock);
> +	v4l2_subdev_call(ctx->seninf, video, s_stream, 0);
> +fail_pipe_off:
> +	for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++)
> +		v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 0);
> +
> +	return ret;
> +}
> +

[snip]

> +static int mtk_cam_master_bound(struct v4l2_async_notifier *notifier,
> +				struct v4l2_subdev *subdev,
> +				struct v4l2_async_connection *asc)
> +{
> +	struct mtk_cam_device *cam_dev =
> +		container_of(notifier, struct mtk_cam_device, notifier);
> +	struct mtk_raw *raw = &cam_dev->raw;
> +	struct device *cam = cam_dev->dev;
> +	struct device *dev = subdev->dev;
> +
> +	dev_info(cam, "cmasys | %s trigger %s\n", subdev->name, __func__);
> +
> +	if (strcmp(dev_driver_string(dev), "seninf") == 0) {
> +		dev_dbg(cam, "%s@(seninf) done\n", __func__);
> +	} else if (strcmp(dev_driver_string(dev), "mtk-cam raw") == 0) {
> +		struct mtk_raw_device *raw_dev = dev_get_drvdata(dev);
> +
> +		raw_dev->cam = cam_dev;
> +		raw->devs[raw_dev->id] = dev;

raw_dev->id is never set, so raw_dev->id is always 0.
Does this driver support only one raw?
If this driver support only one raw, remove all code related to multiple raw.
One example is changing raw->devs[] to raw->dev, and

raw->dev = dev;

And pipeline number is equal to the raw number.
If raw number is one, imply there is only one pipeline.
If only one pipeline, it's not necessary to have pipe id to identify pipeline.

> +		raw->cam_dev = cam_dev->dev;
> +		dev_dbg(cam, "%s@(mtk-cam raw) done\n", __func__);
> +	} else if (strcmp(dev_driver_string(dev), "mtk-cam yuv") == 0) {
> +		struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev);
> +
> +		raw->yuvs[yuv_dev->id] = dev;

yuv_dev->id is never set, so yuv_dev->id is always 0.
Does this driver support only one yuv?
If this driver support only one yuv, remove all code related to multiple yuv.
One example is changing raw->yuvs[] to raw->yuv, and

raw->yuv = dev;

> +		dev_dbg(cam, "%s@(mtk-cam yuv) done\n", __func__);
> +	} else {
> +		dev_warn(cam, "%s got unrecongized device\n", __func__);
> +	}
> +
> +	return 0;
> +}
> +

[snip]

> +
> +#define SENSOR_FMT_MASK			0xFFFF
> +
> +/* flags of mtk_cam_request */
> +#define MTK_CAM_REQ_FLAG_SENINF_IMMEDIATE_UPDATE	BIT(1)
> +
> +/* flags of mtk_cam_request_stream_data */
> +#define MTK_CAM_REQ_S_DATA_FLAG_TG_FLASH		BIT(0)

MTK_CAM_REQ_S_DATA_FLAG_TG_FLASH is useless. Drop it.

> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT	BIT(1)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SINK_FMT_UPDATE		BIT(2)
> +
> +/* Apply sensor mode and the timing is 1 vsync before */
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1	BIT(3)

MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1 is useless. Drop it.

> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN		BIT(4)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN		BIT(5)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE	BIT(6)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE	BIT(7)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED	BIT(8)

MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED is useless. Drop it.

> +
> +struct mtk_cam_working_buf {
> +	void *va;
> +	dma_addr_t iova;
> +	dma_addr_t scp_addr;
> +	unsigned int size;
> +};
> +

[snip]

> 
> +
> +struct mtk_cam_req_feature {
> +	int raw_feature;

raw_feature is useless. Drop it.

> +	bool switch_prev_frame_done;

switch_prev_frame_done is useless. Drop it.

> +	bool switch_curr_setting_done;

switch_curr_setting_done is useless. Drop it.

> +	bool switch_done;

switch_done is useless. Drop it.

> +};
> +
> +struct mtk_cam_sensor_work {
> +	struct kthread_work work;
> +	atomic_t is_queued;
> +};
> +
> +/*
> + * struct mtk_cam_request_stream_data - per stream members of a request
> + *
> + * @pad_fmt: pad format configurtion for sensor switch.
> + * @frame_params: The frame info. & address info. of enabled DMA nodes.
> + * @frame_work: work queue entry for frame transmission to SCP.
> + * @working_buf: command queue buffer associated to this request
> + * @deque_list_node: the entry node of s_data for deque
> + * @cleanup_list_node: the entry node of s_data for cleanup
> + *
> + */
> +struct mtk_cam_request_stream_data {
> +	u32 index;
> +	struct mtk_cam_request *req;
> +	struct mtk_cam_ctx *ctx;
> +	u32 pipe_id;
> +	u32 frame_seq_no;
> +	u32 flags;
> +	unsigned long raw_dmas;

raw_dmas is useless. Drop it.

> +	u64 timestamp;
> +	u64 timestamp_mono;
> +	atomic_t buf_state; /* default: -1 */
> +	struct mtk_cam_buffer *bufs[MTK_RAW_TOTAL_NODES];
> +	struct v4l2_subdev *sensor;
> +	struct media_request_object *sensor_hdl_obj;  /* for complete only */
> +	struct media_request_object *raw_hdl_obj;  /* for complete only */
> +	struct v4l2_subdev_format seninf_fmt;
> +	struct v4l2_subdev_format pad_fmt[MTK_RAW_PIPELINE_PADS_NUM];
> +	struct v4l2_rect pad_selection[MTK_RAW_PIPELINE_PADS_NUM];
> +	struct v4l2_format vdev_fmt[MTK_RAW_TOTAL_NODES];
> +	struct v4l2_selection vdev_selection[MTK_RAW_TOTAL_NODES];
> +	struct mtkcam_ipi_frame_param frame_params;
> +	struct mtk_cam_sensor_work sensor_work;
> +	struct mtk_cam_req_work seninf_s_fmt_work;

seninf_s_fmt_work is useless. Drop it.

> +	struct mtk_cam_req_work frame_work;

You queue this work from mtk_cam_dev_req_enqueue().
I think the frame work job could be done in mtk_cam_dev_req_enqueue().
So it's not necessary to queue the job to work queue.
Drop frame_work.

> +	struct mtk_cam_req_work meta1_done_work;

You queue this work from irq thread.
I think the meta1 done job could be done in irq thread.
So it's not necessary to queue the job to work queue.
Drop meta1_done_work.

> +	struct mtk_cam_req_work frame_done_work;

You queue this work from irq thread.
I think the frame done job could be done in irq thread.
So it's not necessary to queue the job to work queue.
Drop frame_done_work.

> +	struct mtk_camsys_ctrl_state state;
> +	struct mtk_cam_working_buf_entry *working_buf;
> +	unsigned int no_frame_done_cnt;

no_frame_done_cnt is useless. Drop it.

> +	atomic_t seninf_dump_state;

seninf_dump_state is useless. Drop it.

> +	struct mtk_cam_req_feature feature;

mtk_cam_req_feature is empty. Drop feature.

> +	struct list_head deque_list_node;
> +	struct list_head cleanup_list_node;
> +	atomic_t first_setting_check;
> +};
> +
> +struct mtk_cam_req_pipe {
> +	int s_data_num;

s_data_num is only set in mtk_cam_req_p_data_init().
mtk_cam_req_p_data_init() is only called in mtk_cam_req_get_pipe_used() with s_data_num = 1.
So s_data_num is always 1.
Use 1 to replace s_data_num and drop s_data_num.

> +	int req_seq;

req_seq is useless. Drop it.

> +	struct mtk_cam_request_stream_data s_data[MTK_CAM_REQ_MAX_S_DATA];

After previous drop. struct mtk_cam_req_pipe include only one structure. This is weird.
So drop struct mtk_cam_req_pipe and use struct mtk_cam_request_stream_data directly.

> +};
> +
> +enum mtk_cam_request_state {
> +	MTK_CAM_REQ_STATE_PENDING,
> +	MTK_CAM_REQ_STATE_RUNNING,
> +	MTK_CAM_REQ_STATE_DELETING,
> +	MTK_CAM_REQ_STATE_COMPLETE,
> +	MTK_CAM_REQ_STATE_CLEANUP,
> +	NR_OF_MTK_CAM_REQ_STATE,
> +};
> +

[snip]

> +
> +struct mtk_cam_img_working_buf_pool {

In patch [9/13], I says img working buf related things are useless.
Drop them.

> +	struct mtk_cam_ctx *ctx;
> +	struct dma_buf *working_img_buf_dmabuf;
> +	void *working_img_buf_va;
> +	dma_addr_t working_img_buf_iova;
> +	dma_addr_t working_img_buf_scp_addr;
> +	unsigned int working_img_buf_size;
> +	struct mtk_cam_img_working_buf_entry img_working_buf[CAM_IMG_BUF_NUM];
> +	struct mtk_cam_working_buf_list cam_freeimglist;
> +};
> +

[snip]

> +
> +struct mtk_cam_device {
> +	struct device *dev;
> +
> +	struct platform_device *clks_pdev;
> +	struct v4l2_device v4l2_dev;
> +	struct v4l2_async_notifier notifier;
> +	struct media_device media_dev;
> +	void __iomem *base;
> +
> +	struct mtk_scp *scp;
> +	struct device *smem_dev;
> +	struct rproc *rproc_handle;
> +
> +	unsigned int composer_cnt;
> +
> +	unsigned int num_seninf_devices;

num_seninf_devices is useless. Drop it.

> +	unsigned int num_raw_devices;
> +
> +	/* raw_pipe controller subdev */
> +	struct mtk_raw raw;
> +	struct mutex queue_lock; /* protect queue request */
> +
> +	unsigned int max_stream_num;
> +	unsigned int streaming_ctx;
> +	unsigned int streaming_pipe;
> +	struct mtk_cam_ctx *ctxs;
> +
> +	/* request related */
> +	struct list_head pending_job_list;
> +	spinlock_t pending_job_lock; /* protect pending_job_list */
> +	struct list_head running_job_list;
> +	unsigned int running_job_count;
> +	spinlock_t running_job_lock; /* protect running_job_list */
> +
> +	/* standard v4l2 buffer control */
> +	struct list_head dma_pending;
> +	spinlock_t dma_pending_lock; /* protect dma_pending_list */
> +	struct list_head dma_processing;

If you don't know how to merge all buffer list together,
you may try merge dma_pending and dma_processing first.
The merged name may be dma_buf_list.
And the buffer has a flag 'processing' to indicate it's processing or not.

> +	spinlock_t dma_processing_lock; /* protect dma_processing_list and dma_processing_count */
> +	unsigned int dma_processing_count;
> +
> +	struct workqueue_struct *debug_wq;

debug_wq is useless. Drop it.

> +	struct workqueue_struct *debug_exception_wq;

debug_exception_wq is useless. Drop it.

Regards,
CK

> +};
> +
> +static inline struct mtk_cam_request_stream_data*
> +mtk_cam_ctrl_state_to_req_s_data(struct mtk_camsys_ctrl_state *state)
> +{
> +	return container_of(state, struct mtk_cam_request_stream_data, state);
> +}
> +




More information about the linux-arm-kernel mailing list