summaryrefslogtreecommitdiff
path: root/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h
blob: 7a7cf43baf24dd2b3242a191d2d8d870d26b5f58 (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
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Driver for STM32 Digital Camera Memory Interface Pixel Processor
 *
 * Copyright (C) STMicroelectronics SA 2023
 * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>
 *          Alain Volmat <alain.volmat@foss.st.com>
 *          for STMicroelectronics.
 */

#ifndef _DCMIPP_COMMON_H_
#define _DCMIPP_COMMON_H_

#include <linux/interrupt.h>
#include <linux/slab.h>
#include <media/media-device.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>

#define DCMIPP_PDEV_NAME "dcmipp"

#define DCMIPP_FRAME_MAX_WIDTH 4096
#define DCMIPP_FRAME_MAX_HEIGHT 2160
#define DCMIPP_FRAME_MIN_WIDTH 16
#define DCMIPP_FRAME_MIN_HEIGHT 16

#define DCMIPP_FMT_WIDTH_DEFAULT  640
#define DCMIPP_FMT_HEIGHT_DEFAULT 480

#define DCMIPP_COLORSPACE_DEFAULT	V4L2_COLORSPACE_REC709
#define DCMIPP_YCBCR_ENC_DEFAULT	V4L2_YCBCR_ENC_DEFAULT
#define DCMIPP_QUANTIZATION_DEFAULT	V4L2_QUANTIZATION_DEFAULT
#define DCMIPP_XFER_FUNC_DEFAULT	V4L2_XFER_FUNC_DEFAULT

/**
 * dcmipp_colorimetry_clamp() - Adjust colorimetry parameters
 *
 * @fmt:		the pointer to struct v4l2_pix_format or
 *			struct v4l2_mbus_framefmt
 *
 * Entities must check if colorimetry given by the userspace is valid, if not
 * then set them as DEFAULT
 */
#define dcmipp_colorimetry_clamp(fmt)					\
do {									\
	if ((fmt)->colorspace == V4L2_COLORSPACE_DEFAULT ||		\
	    (fmt)->colorspace > V4L2_COLORSPACE_DCI_P3) {		\
		(fmt)->colorspace = DCMIPP_COLORSPACE_DEFAULT;		\
		(fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT;		\
		(fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT;	\
		(fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT;		\
	}								\
	if ((fmt)->ycbcr_enc > V4L2_YCBCR_ENC_SMPTE240M)		\
		(fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT;		\
	if ((fmt)->quantization > V4L2_QUANTIZATION_LIM_RANGE)		\
		(fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT;	\
	if ((fmt)->xfer_func > V4L2_XFER_FUNC_SMPTE2084)		\
		(fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT;		\
} while (0)

/**
 * struct dcmipp_ent_device - core struct that represents a node in the topology
 *
 * @ent:		the pointer to struct media_entity for the node
 * @pads:		the list of pads of the node
 * @bus:		struct v4l2_mbus_config_parallel describing input bus
 * @bus_type:		type of input bus (parallel or BT656)
 * @handler:		irq handler dedicated to the subdev
 * @handler_ret:	value returned by the irq handler
 * @thread_fn:		threaded irq handler
 *
 * The DCMIPP provides a single IRQ line and a IRQ status registers for all
 * subdevs, hence once the main irq handler (registered at probe time) is
 * called, it will chain calls to the irq handler of each the subdevs of the
 * pipelines, using the handler/handler_ret/thread_fn variables.
 *
 * Each node of the topology must create a dcmipp_ent_device struct.
 * Depending on the node it will be of an instance of v4l2_subdev or
 * video_device struct where both contains a struct media_entity.
 * Those structures should embedded the dcmipp_ent_device struct through
 * v4l2_set_subdevdata() and video_set_drvdata() respectivaly, allowing the
 * dcmipp_ent_device struct to be retrieved from the corresponding struct
 * media_entity
 */
struct dcmipp_ent_device {
	struct media_entity *ent;
	struct media_pad *pads;

	/* Parallel input device */
	struct v4l2_mbus_config_parallel bus;
	enum v4l2_mbus_type bus_type;
	irq_handler_t handler;
	irqreturn_t handler_ret;
	irq_handler_t thread_fn;
};

/**
 * dcmipp_pads_init - initialize pads
 *
 * @num_pads:	number of pads to initialize
 * @pads_flags:	flags to use in each pad
 *
 * Helper functions to allocate/initialize pads
 */
struct media_pad *dcmipp_pads_init(u16 num_pads,
				   const unsigned long *pads_flags);

/**
 * dcmipp_pads_cleanup - free pads
 *
 * @pads: pointer to the pads
 *
 * Helper function to free the pads initialized with dcmipp_pads_init
 */
static inline void dcmipp_pads_cleanup(struct media_pad *pads)
{
	kfree(pads);
}

/**
 * dcmipp_ent_sd_register - initialize and register a subdev node
 *
 * @ved:	the dcmipp_ent_device struct to be initialize
 * @sd:		the v4l2_subdev struct to be initialize and registered
 * @v4l2_dev:	the v4l2 device to register the v4l2_subdev
 * @name:	name of the sub-device. Please notice that the name must be
 *		unique.
 * @function:	media entity function defined by MEDIA_ENT_F_* macros
 * @num_pads:	number of pads to initialize
 * @pads_flag:	flags to use in each pad
 * @sd_int_ops:	pointer to &struct v4l2_subdev_internal_ops
 * @sd_ops:	pointer to &struct v4l2_subdev_ops.
 * @handler:	func pointer of the irq handler
 * @thread_fn:	func pointer of the threaded irq handler
 *
 * Helper function initialize and register the struct dcmipp_ent_device and
 * struct v4l2_subdev which represents a subdev node in the topology
 */
int dcmipp_ent_sd_register(struct dcmipp_ent_device *ved,
			   struct v4l2_subdev *sd,
			   struct v4l2_device *v4l2_dev,
			   const char *const name,
			   u32 function,
			   u16 num_pads,
			   const unsigned long *pads_flag,
			   const struct v4l2_subdev_internal_ops *sd_int_ops,
			   const struct v4l2_subdev_ops *sd_ops,
			   irq_handler_t handler,
			   irq_handler_t thread_fn);

/**
 * dcmipp_ent_sd_unregister - cleanup and unregister a subdev node
 *
 * @ved:	the dcmipp_ent_device struct to be cleaned up
 * @sd:		the v4l2_subdev struct to be unregistered
 *
 * Helper function cleanup and unregister the struct dcmipp_ent_device and
 * struct v4l2_subdev which represents a subdev node in the topology
 */
void dcmipp_ent_sd_unregister(struct dcmipp_ent_device *ved,
			      struct v4l2_subdev *sd);

#define reg_write(device, reg, val) \
	(__reg_write((device)->dev, (device)->regs, (reg), (val)))
#define reg_read(device, reg) \
	(__reg_read((device)->dev, (device)->regs, (reg)))
#define reg_set(device, reg, mask) \
	(__reg_set((device)->dev, (device)->regs, (reg), (mask)))
#define reg_clear(device, reg, mask) \
	(__reg_clear((device)->dev, (device)->regs, (reg), (mask)))

static inline u32 __reg_read(struct device *dev, void __iomem *base, u32 reg)
{
	u32 val = readl_relaxed(base + reg);

	dev_dbg(dev, "RD 0x%x %#10.8x\n", reg, val);
	return val;
}

static inline void __reg_write(struct device *dev, void __iomem *base, u32 reg,
			       u32 val)
{
	dev_dbg(dev, "WR 0x%x %#10.8x\n", reg, val);
	writel_relaxed(val, base + reg);
}

static inline void __reg_set(struct device *dev, void __iomem *base, u32 reg,
			     u32 mask)
{
	dev_dbg(dev, "SET 0x%x %#10.8x\n", reg, mask);
	__reg_write(dev, base, reg, readl_relaxed(base + reg) | mask);
}

static inline void __reg_clear(struct device *dev, void __iomem *base, u32 reg,
			       u32 mask)
{
	dev_dbg(dev, "CLR 0x%x %#10.8x\n", reg, mask);
	__reg_write(dev, base, reg, readl_relaxed(base + reg) & ~mask);
}

/* DCMIPP subdev init / release entry points */
struct dcmipp_ent_device *dcmipp_par_ent_init(struct device *dev,
					      const char *entity_name,
					      struct v4l2_device *v4l2_dev,
					      void __iomem *regs);
void dcmipp_par_ent_release(struct dcmipp_ent_device *ved);
struct dcmipp_ent_device *
dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
			 struct v4l2_device *v4l2_dev, void __iomem *regs);
void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved);
struct dcmipp_ent_device *dcmipp_bytecap_ent_init(struct device *dev,
						  const char *entity_name,
						  struct v4l2_device *v4l2_dev,
						  void __iomem *regs);
void dcmipp_bytecap_ent_release(struct dcmipp_ent_device *ved);

#endif