summaryrefslogtreecommitdiff
path: root/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
blob: 2810ebe9b5f75c3bb918ea5e7f6868c03d95b773 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * V4L2 Capture ISI subdev for i.MX8QXP/QM platform
 *
 * ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which
 * used to process image from camera sensor to memory or DC
 * Copyright 2019-2020 NXP
 */

#ifndef __MXC_ISI_CORE_H__
#define __MXC_ISI_CORE_H__

#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/videodev2.h>

#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-v4l2.h>

struct clk_bulk_data;
struct dentry;
struct device;
struct media_intf_devnode;
struct regmap;
struct v4l2_m2m_dev;

/* Pipeline pads */
#define MXC_ISI_PIPE_PAD_SINK		0
#define MXC_ISI_PIPE_PAD_SOURCE		1
#define MXC_ISI_PIPE_PADS_NUM		2

#define MXC_ISI_MIN_WIDTH		1U
#define MXC_ISI_MIN_HEIGHT		1U
#define MXC_ISI_MAX_WIDTH_UNCHAINED	2048U
#define MXC_ISI_MAX_WIDTH_CHAINED	4096U
#define MXC_ISI_MAX_HEIGHT		8191U

#define MXC_ISI_DEF_WIDTH		1920U
#define MXC_ISI_DEF_HEIGHT		1080U
#define MXC_ISI_DEF_MBUS_CODE_SINK	MEDIA_BUS_FMT_UYVY8_1X16
#define MXC_ISI_DEF_MBUS_CODE_SOURCE	MEDIA_BUS_FMT_YUV8_1X24
#define MXC_ISI_DEF_PIXEL_FORMAT	V4L2_PIX_FMT_YUYV
#define MXC_ISI_DEF_COLOR_SPACE		V4L2_COLORSPACE_SRGB
#define MXC_ISI_DEF_YCBCR_ENC		V4L2_YCBCR_ENC_601
#define MXC_ISI_DEF_QUANTIZATION	V4L2_QUANTIZATION_LIM_RANGE
#define MXC_ISI_DEF_XFER_FUNC		V4L2_XFER_FUNC_SRGB

#define MXC_ISI_DRIVER_NAME		"mxc-isi"
#define MXC_ISI_CAPTURE			"mxc-isi-cap"
#define MXC_ISI_M2M			"mxc-isi-m2m"
#define MXC_MAX_PLANES			3

struct mxc_isi_dev;
struct mxc_isi_m2m_ctx;

enum mxc_isi_buf_id {
	MXC_ISI_BUF1 = 0x0,
	MXC_ISI_BUF2,
};

enum mxc_isi_encoding {
	MXC_ISI_ENC_RAW,
	MXC_ISI_ENC_RGB,
	MXC_ISI_ENC_YUV,
};

enum mxc_isi_input_id {
	/* Inputs from the crossbar switch range from 0 to 15 */
	MXC_ISI_INPUT_MEM = 16,
};

enum mxc_isi_video_type {
	MXC_ISI_VIDEO_CAP = BIT(0),
	MXC_ISI_VIDEO_M2M_OUT = BIT(1),
	MXC_ISI_VIDEO_M2M_CAP = BIT(2),
};

struct mxc_isi_format_info {
	u32	mbus_code;
	u32	fourcc;
	enum mxc_isi_video_type type;
	u32	isi_in_format;
	u32	isi_out_format;
	u8	mem_planes;
	u8	color_planes;
	u8	depth[MXC_MAX_PLANES];
	u8	hsub;
	u8	vsub;
	enum mxc_isi_encoding encoding;
};

struct mxc_isi_bus_format_info {
	u32	mbus_code;
	u32	output;
	u32	pads;
	enum mxc_isi_encoding encoding;
};

struct mxc_isi_buffer {
	struct vb2_v4l2_buffer  v4l2_buf;
	struct list_head	list;
	dma_addr_t		dma_addrs[3];
	enum mxc_isi_buf_id	id;
	bool discard;
};

struct mxc_isi_reg {
	u32 offset;
	u32 mask;
};

struct mxc_isi_ier_reg {
	/* Overflow Y/U/V trigger enable*/
	struct mxc_isi_reg oflw_y_buf_en;
	struct mxc_isi_reg oflw_u_buf_en;
	struct mxc_isi_reg oflw_v_buf_en;

	/* Excess overflow Y/U/V trigger enable*/
	struct mxc_isi_reg excs_oflw_y_buf_en;
	struct mxc_isi_reg excs_oflw_u_buf_en;
	struct mxc_isi_reg excs_oflw_v_buf_en;

	/* Panic Y/U/V trigger enable*/
	struct mxc_isi_reg panic_y_buf_en;
	struct mxc_isi_reg panic_v_buf_en;
	struct mxc_isi_reg panic_u_buf_en;
};

struct mxc_isi_panic_thd {
	u32 mask;
	u32 offset;
	u32 threshold;
};

struct mxc_isi_set_thd {
	struct mxc_isi_panic_thd panic_set_thd_y;
	struct mxc_isi_panic_thd panic_set_thd_u;
	struct mxc_isi_panic_thd panic_set_thd_v;
};

struct mxc_gasket_ops {
	void (*enable)(struct mxc_isi_dev *isi,
		       const struct v4l2_mbus_frame_desc *fd,
		       const struct v4l2_mbus_framefmt *fmt,
		       const unsigned int port);
	void (*disable)(struct mxc_isi_dev *isi, const unsigned int port);
};

enum model {
	MXC_ISI_IMX8MN,
	MXC_ISI_IMX8MP,
	MXC_ISI_IMX93,
};

struct mxc_isi_plat_data {
	enum model model;
	unsigned int num_ports;
	unsigned int num_channels;
	unsigned int reg_offset;
	const struct mxc_isi_ier_reg  *ier_reg;
	const struct mxc_isi_set_thd *set_thd;
	const struct mxc_gasket_ops *gasket_ops;
	const struct clk_bulk_data *clks;
	unsigned int num_clks;
	bool buf_active_reverse;
	bool has_36bit_dma;
};

struct mxc_isi_dma_buffer {
	size_t				size;
	void				*addr;
	dma_addr_t			dma;
};

struct mxc_isi_input {
	unsigned int			enable_count;
};

struct mxc_isi_crossbar {
	struct mxc_isi_dev		*isi;

	unsigned int			num_sinks;
	unsigned int			num_sources;
	struct mxc_isi_input		*inputs;

	struct v4l2_subdev		sd;
	struct media_pad		*pads;
};

struct mxc_isi_video {
	struct mxc_isi_pipe		*pipe;

	struct video_device		vdev;
	struct media_pad		pad;

	/* Protects is_streaming, and the vdev and vb2_q operations */
	struct mutex			lock;
	bool				is_streaming;

	struct v4l2_pix_format_mplane	pix;
	const struct mxc_isi_format_info *fmtinfo;

	struct {
		struct v4l2_ctrl_handler handler;
		unsigned int		alpha;
		bool			hflip;
		bool			vflip;
	} ctrls;

	struct vb2_queue		vb2_q;
	struct mxc_isi_buffer		buf_discard[3];
	struct list_head		out_pending;
	struct list_head		out_active;
	struct list_head		out_discard;
	u32				frame_count;
	/* Protects out_pending, out_active, out_discard and frame_count */
	spinlock_t			buf_lock;

	struct mxc_isi_dma_buffer	discard_buffer[MXC_MAX_PLANES];
};

typedef void(*mxc_isi_pipe_irq_t)(struct mxc_isi_pipe *, u32);

struct mxc_isi_pipe {
	struct mxc_isi_dev		*isi;
	u32				id;
	void __iomem			*regs;

	struct media_pipeline		pipe;

	struct v4l2_subdev		sd;
	struct media_pad		pads[MXC_ISI_PIPE_PADS_NUM];

	struct mxc_isi_video		video;

	/*
	 * Protects use_count, irq_handler, res_available, res_acquired,
	 * chained_res, and the CHNL_CTRL register.
	 */
	struct mutex			lock;
	unsigned int			use_count;
	mxc_isi_pipe_irq_t		irq_handler;

#define MXC_ISI_CHANNEL_RES_LINE_BUF	BIT(0)
#define MXC_ISI_CHANNEL_RES_OUTPUT_BUF	BIT(1)
	u8				available_res;
	u8				acquired_res;
	u8				chained_res;
	bool				chained;
};

struct mxc_isi_m2m {
	struct mxc_isi_dev		*isi;
	struct mxc_isi_pipe		*pipe;

	struct media_pad		pad;
	struct video_device		vdev;
	struct media_intf_devnode	*intf;
	struct v4l2_m2m_dev		*m2m_dev;

	/* Protects last_ctx, usage_count and chained_count */
	struct mutex			lock;

	struct mxc_isi_m2m_ctx		*last_ctx;
	int				usage_count;
	int				chained_count;
};

struct mxc_isi_dev {
	struct device			*dev;

	const struct mxc_isi_plat_data	*pdata;

	void __iomem			*regs;
	struct clk_bulk_data		*clks;
	struct regmap			*gasket;

	struct mxc_isi_crossbar		crossbar;
	struct mxc_isi_pipe		*pipes;
	struct mxc_isi_m2m		m2m;

	struct media_device		media_dev;
	struct v4l2_device		v4l2_dev;
	struct v4l2_async_notifier	notifier;

	struct dentry			*debugfs_root;
};

extern const struct mxc_gasket_ops mxc_imx8_gasket_ops;
extern const struct mxc_gasket_ops mxc_imx93_gasket_ops;

int mxc_isi_crossbar_init(struct mxc_isi_dev *isi);
void mxc_isi_crossbar_cleanup(struct mxc_isi_crossbar *xbar);
int mxc_isi_crossbar_register(struct mxc_isi_crossbar *xbar);
void mxc_isi_crossbar_unregister(struct mxc_isi_crossbar *xbar);

const struct mxc_isi_bus_format_info *
mxc_isi_bus_format_by_code(u32 code, unsigned int pad);
const struct mxc_isi_bus_format_info *
mxc_isi_bus_format_by_index(unsigned int index, unsigned int pad);
const struct mxc_isi_format_info *
mxc_isi_format_by_fourcc(u32 fourcc, enum mxc_isi_video_type type);
const struct mxc_isi_format_info *
mxc_isi_format_enum(unsigned int index, enum mxc_isi_video_type type);
const struct mxc_isi_format_info *
mxc_isi_format_try(struct mxc_isi_pipe *pipe, struct v4l2_pix_format_mplane *pix,
		   enum mxc_isi_video_type type);

int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id);
void mxc_isi_pipe_cleanup(struct mxc_isi_pipe *pipe);
int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe,
			 mxc_isi_pipe_irq_t irq_handler);
void mxc_isi_pipe_release(struct mxc_isi_pipe *pipe);
int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe);
void mxc_isi_pipe_disable(struct mxc_isi_pipe *pipe);

int mxc_isi_video_register(struct mxc_isi_pipe *pipe,
			   struct v4l2_device *v4l2_dev);
void mxc_isi_video_unregister(struct mxc_isi_pipe *pipe);
void mxc_isi_video_suspend(struct mxc_isi_pipe *pipe);
int mxc_isi_video_resume(struct mxc_isi_pipe *pipe);
int mxc_isi_video_queue_setup(const struct v4l2_pix_format_mplane *format,
			      const struct mxc_isi_format_info *info,
			      unsigned int *num_buffers,
			      unsigned int *num_planes, unsigned int sizes[]);
void mxc_isi_video_buffer_init(struct vb2_buffer *vb2, dma_addr_t dma_addrs[3],
			       const struct mxc_isi_format_info *info,
			       const struct v4l2_pix_format_mplane *pix);
int mxc_isi_video_buffer_prepare(struct mxc_isi_dev *isi, struct vb2_buffer *vb2,
				 const struct mxc_isi_format_info *info,
				 const struct v4l2_pix_format_mplane *pix);

#ifdef CONFIG_VIDEO_IMX8_ISI_M2M
int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev);
int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi);
#else
static inline int mxc_isi_m2m_register(struct mxc_isi_dev *isi,
				       struct v4l2_device *v4l2_dev)
{
	return 0;
}
static inline int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
{
	return 0;
}
#endif

int mxc_isi_channel_acquire(struct mxc_isi_pipe *pipe,
			    mxc_isi_pipe_irq_t irq_handler, bool bypass);
void mxc_isi_channel_release(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_get(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_put(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_enable(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_disable(struct mxc_isi_pipe *pipe);
int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass);
void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe);

void mxc_isi_channel_config(struct mxc_isi_pipe *pipe,
			    enum mxc_isi_input_id input,
			    const struct v4l2_area *in_size,
			    const struct v4l2_area *scale,
			    const struct v4l2_rect *crop,
			    enum mxc_isi_encoding in_encoding,
			    enum mxc_isi_encoding out_encoding);

void mxc_isi_channel_set_input_format(struct mxc_isi_pipe *pipe,
				      const struct mxc_isi_format_info *info,
				      const struct v4l2_pix_format_mplane *format);
void mxc_isi_channel_set_output_format(struct mxc_isi_pipe *pipe,
				       const struct mxc_isi_format_info *info,
				       struct v4l2_pix_format_mplane *format);
void mxc_isi_channel_m2m_start(struct mxc_isi_pipe *pipe);

void mxc_isi_channel_set_alpha(struct mxc_isi_pipe *pipe, u8 alpha);
void mxc_isi_channel_set_flip(struct mxc_isi_pipe *pipe, bool hflip, bool vflip);

void mxc_isi_channel_set_inbuf(struct mxc_isi_pipe *pipe, dma_addr_t dma_addr);
void mxc_isi_channel_set_outbuf(struct mxc_isi_pipe *pipe,
				const dma_addr_t dma_addrs[3],
				enum mxc_isi_buf_id buf_id);

u32 mxc_isi_channel_irq_status(struct mxc_isi_pipe *pipe, bool clear);
void mxc_isi_channel_irq_clear(struct mxc_isi_pipe *pipe);

#if IS_ENABLED(CONFIG_DEBUG_FS)
void mxc_isi_debug_init(struct mxc_isi_dev *isi);
void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi);
#else
static inline void mxc_isi_debug_init(struct mxc_isi_dev *isi)
{
}
static inline void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi)
{
}
#endif

#endif /* __MXC_ISI_CORE_H__ */