1*28e0f377SHugues Fruchet /* SPDX-License-Identifier: GPL-2.0-or-later */
2*28e0f377SHugues Fruchet /*
3*28e0f377SHugues Fruchet * Driver for STM32 Digital Camera Memory Interface Pixel Processor
4*28e0f377SHugues Fruchet *
5*28e0f377SHugues Fruchet * Copyright (C) STMicroelectronics SA 2023
6*28e0f377SHugues Fruchet * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>
7*28e0f377SHugues Fruchet * Alain Volmat <alain.volmat@foss.st.com>
8*28e0f377SHugues Fruchet * for STMicroelectronics.
9*28e0f377SHugues Fruchet */
10*28e0f377SHugues Fruchet
11*28e0f377SHugues Fruchet #ifndef _DCMIPP_COMMON_H_
12*28e0f377SHugues Fruchet #define _DCMIPP_COMMON_H_
13*28e0f377SHugues Fruchet
14*28e0f377SHugues Fruchet #include <linux/interrupt.h>
15*28e0f377SHugues Fruchet #include <linux/slab.h>
16*28e0f377SHugues Fruchet #include <media/media-device.h>
17*28e0f377SHugues Fruchet #include <media/v4l2-device.h>
18*28e0f377SHugues Fruchet #include <media/v4l2-fwnode.h>
19*28e0f377SHugues Fruchet
20*28e0f377SHugues Fruchet #define DCMIPP_PDEV_NAME "dcmipp"
21*28e0f377SHugues Fruchet
22*28e0f377SHugues Fruchet #define DCMIPP_FRAME_MAX_WIDTH 4096
23*28e0f377SHugues Fruchet #define DCMIPP_FRAME_MAX_HEIGHT 2160
24*28e0f377SHugues Fruchet #define DCMIPP_FRAME_MIN_WIDTH 16
25*28e0f377SHugues Fruchet #define DCMIPP_FRAME_MIN_HEIGHT 16
26*28e0f377SHugues Fruchet
27*28e0f377SHugues Fruchet #define DCMIPP_FMT_WIDTH_DEFAULT 640
28*28e0f377SHugues Fruchet #define DCMIPP_FMT_HEIGHT_DEFAULT 480
29*28e0f377SHugues Fruchet
30*28e0f377SHugues Fruchet #define DCMIPP_COLORSPACE_DEFAULT V4L2_COLORSPACE_REC709
31*28e0f377SHugues Fruchet #define DCMIPP_YCBCR_ENC_DEFAULT V4L2_YCBCR_ENC_DEFAULT
32*28e0f377SHugues Fruchet #define DCMIPP_QUANTIZATION_DEFAULT V4L2_QUANTIZATION_DEFAULT
33*28e0f377SHugues Fruchet #define DCMIPP_XFER_FUNC_DEFAULT V4L2_XFER_FUNC_DEFAULT
34*28e0f377SHugues Fruchet
35*28e0f377SHugues Fruchet /**
36*28e0f377SHugues Fruchet * dcmipp_colorimetry_clamp() - Adjust colorimetry parameters
37*28e0f377SHugues Fruchet *
38*28e0f377SHugues Fruchet * @fmt: the pointer to struct v4l2_pix_format or
39*28e0f377SHugues Fruchet * struct v4l2_mbus_framefmt
40*28e0f377SHugues Fruchet *
41*28e0f377SHugues Fruchet * Entities must check if colorimetry given by the userspace is valid, if not
42*28e0f377SHugues Fruchet * then set them as DEFAULT
43*28e0f377SHugues Fruchet */
44*28e0f377SHugues Fruchet #define dcmipp_colorimetry_clamp(fmt) \
45*28e0f377SHugues Fruchet do { \
46*28e0f377SHugues Fruchet if ((fmt)->colorspace == V4L2_COLORSPACE_DEFAULT || \
47*28e0f377SHugues Fruchet (fmt)->colorspace > V4L2_COLORSPACE_DCI_P3) { \
48*28e0f377SHugues Fruchet (fmt)->colorspace = DCMIPP_COLORSPACE_DEFAULT; \
49*28e0f377SHugues Fruchet (fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT; \
50*28e0f377SHugues Fruchet (fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT; \
51*28e0f377SHugues Fruchet (fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT; \
52*28e0f377SHugues Fruchet } \
53*28e0f377SHugues Fruchet if ((fmt)->ycbcr_enc > V4L2_YCBCR_ENC_SMPTE240M) \
54*28e0f377SHugues Fruchet (fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT; \
55*28e0f377SHugues Fruchet if ((fmt)->quantization > V4L2_QUANTIZATION_LIM_RANGE) \
56*28e0f377SHugues Fruchet (fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT; \
57*28e0f377SHugues Fruchet if ((fmt)->xfer_func > V4L2_XFER_FUNC_SMPTE2084) \
58*28e0f377SHugues Fruchet (fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT; \
59*28e0f377SHugues Fruchet } while (0)
60*28e0f377SHugues Fruchet
61*28e0f377SHugues Fruchet /**
62*28e0f377SHugues Fruchet * struct dcmipp_ent_device - core struct that represents a node in the topology
63*28e0f377SHugues Fruchet *
64*28e0f377SHugues Fruchet * @ent: the pointer to struct media_entity for the node
65*28e0f377SHugues Fruchet * @pads: the list of pads of the node
66*28e0f377SHugues Fruchet * @bus: struct v4l2_mbus_config_parallel describing input bus
67*28e0f377SHugues Fruchet * @bus_type: type of input bus (parallel or BT656)
68*28e0f377SHugues Fruchet * @handler: irq handler dedicated to the subdev
69*28e0f377SHugues Fruchet * @handler_ret: value returned by the irq handler
70*28e0f377SHugues Fruchet * @thread_fn: threaded irq handler
71*28e0f377SHugues Fruchet *
72*28e0f377SHugues Fruchet * The DCMIPP provides a single IRQ line and a IRQ status registers for all
73*28e0f377SHugues Fruchet * subdevs, hence once the main irq handler (registered at probe time) is
74*28e0f377SHugues Fruchet * called, it will chain calls to the irq handler of each the subdevs of the
75*28e0f377SHugues Fruchet * pipelines, using the handler/handler_ret/thread_fn variables.
76*28e0f377SHugues Fruchet *
77*28e0f377SHugues Fruchet * Each node of the topology must create a dcmipp_ent_device struct.
78*28e0f377SHugues Fruchet * Depending on the node it will be of an instance of v4l2_subdev or
79*28e0f377SHugues Fruchet * video_device struct where both contains a struct media_entity.
80*28e0f377SHugues Fruchet * Those structures should embedded the dcmipp_ent_device struct through
81*28e0f377SHugues Fruchet * v4l2_set_subdevdata() and video_set_drvdata() respectivaly, allowing the
82*28e0f377SHugues Fruchet * dcmipp_ent_device struct to be retrieved from the corresponding struct
83*28e0f377SHugues Fruchet * media_entity
84*28e0f377SHugues Fruchet */
85*28e0f377SHugues Fruchet struct dcmipp_ent_device {
86*28e0f377SHugues Fruchet struct media_entity *ent;
87*28e0f377SHugues Fruchet struct media_pad *pads;
88*28e0f377SHugues Fruchet
89*28e0f377SHugues Fruchet /* Parallel input device */
90*28e0f377SHugues Fruchet struct v4l2_mbus_config_parallel bus;
91*28e0f377SHugues Fruchet enum v4l2_mbus_type bus_type;
92*28e0f377SHugues Fruchet irq_handler_t handler;
93*28e0f377SHugues Fruchet irqreturn_t handler_ret;
94*28e0f377SHugues Fruchet irq_handler_t thread_fn;
95*28e0f377SHugues Fruchet };
96*28e0f377SHugues Fruchet
97*28e0f377SHugues Fruchet /**
98*28e0f377SHugues Fruchet * dcmipp_pads_init - initialize pads
99*28e0f377SHugues Fruchet *
100*28e0f377SHugues Fruchet * @num_pads: number of pads to initialize
101*28e0f377SHugues Fruchet * @pads_flags: flags to use in each pad
102*28e0f377SHugues Fruchet *
103*28e0f377SHugues Fruchet * Helper functions to allocate/initialize pads
104*28e0f377SHugues Fruchet */
105*28e0f377SHugues Fruchet struct media_pad *dcmipp_pads_init(u16 num_pads,
106*28e0f377SHugues Fruchet const unsigned long *pads_flags);
107*28e0f377SHugues Fruchet
108*28e0f377SHugues Fruchet /**
109*28e0f377SHugues Fruchet * dcmipp_pads_cleanup - free pads
110*28e0f377SHugues Fruchet *
111*28e0f377SHugues Fruchet * @pads: pointer to the pads
112*28e0f377SHugues Fruchet *
113*28e0f377SHugues Fruchet * Helper function to free the pads initialized with dcmipp_pads_init
114*28e0f377SHugues Fruchet */
dcmipp_pads_cleanup(struct media_pad * pads)115*28e0f377SHugues Fruchet static inline void dcmipp_pads_cleanup(struct media_pad *pads)
116*28e0f377SHugues Fruchet {
117*28e0f377SHugues Fruchet kfree(pads);
118*28e0f377SHugues Fruchet }
119*28e0f377SHugues Fruchet
120*28e0f377SHugues Fruchet /**
121*28e0f377SHugues Fruchet * dcmipp_ent_sd_register - initialize and register a subdev node
122*28e0f377SHugues Fruchet *
123*28e0f377SHugues Fruchet * @ved: the dcmipp_ent_device struct to be initialize
124*28e0f377SHugues Fruchet * @sd: the v4l2_subdev struct to be initialize and registered
125*28e0f377SHugues Fruchet * @v4l2_dev: the v4l2 device to register the v4l2_subdev
126*28e0f377SHugues Fruchet * @name: name of the sub-device. Please notice that the name must be
127*28e0f377SHugues Fruchet * unique.
128*28e0f377SHugues Fruchet * @function: media entity function defined by MEDIA_ENT_F_* macros
129*28e0f377SHugues Fruchet * @num_pads: number of pads to initialize
130*28e0f377SHugues Fruchet * @pads_flag: flags to use in each pad
131*28e0f377SHugues Fruchet * @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops
132*28e0f377SHugues Fruchet * @sd_ops: pointer to &struct v4l2_subdev_ops.
133*28e0f377SHugues Fruchet * @handler: func pointer of the irq handler
134*28e0f377SHugues Fruchet * @thread_fn: func pointer of the threaded irq handler
135*28e0f377SHugues Fruchet *
136*28e0f377SHugues Fruchet * Helper function initialize and register the struct dcmipp_ent_device and
137*28e0f377SHugues Fruchet * struct v4l2_subdev which represents a subdev node in the topology
138*28e0f377SHugues Fruchet */
139*28e0f377SHugues Fruchet int dcmipp_ent_sd_register(struct dcmipp_ent_device *ved,
140*28e0f377SHugues Fruchet struct v4l2_subdev *sd,
141*28e0f377SHugues Fruchet struct v4l2_device *v4l2_dev,
142*28e0f377SHugues Fruchet const char *const name,
143*28e0f377SHugues Fruchet u32 function,
144*28e0f377SHugues Fruchet u16 num_pads,
145*28e0f377SHugues Fruchet const unsigned long *pads_flag,
146*28e0f377SHugues Fruchet const struct v4l2_subdev_internal_ops *sd_int_ops,
147*28e0f377SHugues Fruchet const struct v4l2_subdev_ops *sd_ops,
148*28e0f377SHugues Fruchet irq_handler_t handler,
149*28e0f377SHugues Fruchet irq_handler_t thread_fn);
150*28e0f377SHugues Fruchet
151*28e0f377SHugues Fruchet /**
152*28e0f377SHugues Fruchet * dcmipp_ent_sd_unregister - cleanup and unregister a subdev node
153*28e0f377SHugues Fruchet *
154*28e0f377SHugues Fruchet * @ved: the dcmipp_ent_device struct to be cleaned up
155*28e0f377SHugues Fruchet * @sd: the v4l2_subdev struct to be unregistered
156*28e0f377SHugues Fruchet *
157*28e0f377SHugues Fruchet * Helper function cleanup and unregister the struct dcmipp_ent_device and
158*28e0f377SHugues Fruchet * struct v4l2_subdev which represents a subdev node in the topology
159*28e0f377SHugues Fruchet */
160*28e0f377SHugues Fruchet void dcmipp_ent_sd_unregister(struct dcmipp_ent_device *ved,
161*28e0f377SHugues Fruchet struct v4l2_subdev *sd);
162*28e0f377SHugues Fruchet
163*28e0f377SHugues Fruchet #define reg_write(device, reg, val) \
164*28e0f377SHugues Fruchet (__reg_write((device)->dev, (device)->regs, (reg), (val)))
165*28e0f377SHugues Fruchet #define reg_read(device, reg) \
166*28e0f377SHugues Fruchet (__reg_read((device)->dev, (device)->regs, (reg)))
167*28e0f377SHugues Fruchet #define reg_set(device, reg, mask) \
168*28e0f377SHugues Fruchet (__reg_set((device)->dev, (device)->regs, (reg), (mask)))
169*28e0f377SHugues Fruchet #define reg_clear(device, reg, mask) \
170*28e0f377SHugues Fruchet (__reg_clear((device)->dev, (device)->regs, (reg), (mask)))
171*28e0f377SHugues Fruchet
__reg_read(struct device * dev,void __iomem * base,u32 reg)172*28e0f377SHugues Fruchet static inline u32 __reg_read(struct device *dev, void __iomem *base, u32 reg)
173*28e0f377SHugues Fruchet {
174*28e0f377SHugues Fruchet u32 val = readl_relaxed(base + reg);
175*28e0f377SHugues Fruchet
176*28e0f377SHugues Fruchet dev_dbg(dev, "RD 0x%x %#10.8x\n", reg, val);
177*28e0f377SHugues Fruchet return val;
178*28e0f377SHugues Fruchet }
179*28e0f377SHugues Fruchet
__reg_write(struct device * dev,void __iomem * base,u32 reg,u32 val)180*28e0f377SHugues Fruchet static inline void __reg_write(struct device *dev, void __iomem *base, u32 reg,
181*28e0f377SHugues Fruchet u32 val)
182*28e0f377SHugues Fruchet {
183*28e0f377SHugues Fruchet dev_dbg(dev, "WR 0x%x %#10.8x\n", reg, val);
184*28e0f377SHugues Fruchet writel_relaxed(val, base + reg);
185*28e0f377SHugues Fruchet }
186*28e0f377SHugues Fruchet
__reg_set(struct device * dev,void __iomem * base,u32 reg,u32 mask)187*28e0f377SHugues Fruchet static inline void __reg_set(struct device *dev, void __iomem *base, u32 reg,
188*28e0f377SHugues Fruchet u32 mask)
189*28e0f377SHugues Fruchet {
190*28e0f377SHugues Fruchet dev_dbg(dev, "SET 0x%x %#10.8x\n", reg, mask);
191*28e0f377SHugues Fruchet __reg_write(dev, base, reg, readl_relaxed(base + reg) | mask);
192*28e0f377SHugues Fruchet }
193*28e0f377SHugues Fruchet
__reg_clear(struct device * dev,void __iomem * base,u32 reg,u32 mask)194*28e0f377SHugues Fruchet static inline void __reg_clear(struct device *dev, void __iomem *base, u32 reg,
195*28e0f377SHugues Fruchet u32 mask)
196*28e0f377SHugues Fruchet {
197*28e0f377SHugues Fruchet dev_dbg(dev, "CLR 0x%x %#10.8x\n", reg, mask);
198*28e0f377SHugues Fruchet __reg_write(dev, base, reg, readl_relaxed(base + reg) & ~mask);
199*28e0f377SHugues Fruchet }
200*28e0f377SHugues Fruchet
201*28e0f377SHugues Fruchet /* DCMIPP subdev init / release entry points */
202*28e0f377SHugues Fruchet struct dcmipp_ent_device *dcmipp_inp_ent_init(struct device *dev,
203*28e0f377SHugues Fruchet const char *entity_name,
204*28e0f377SHugues Fruchet struct v4l2_device *v4l2_dev,
205*28e0f377SHugues Fruchet void __iomem *regs);
206*28e0f377SHugues Fruchet void dcmipp_inp_ent_release(struct dcmipp_ent_device *ved);
207*28e0f377SHugues Fruchet struct dcmipp_ent_device *
208*28e0f377SHugues Fruchet dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
209*28e0f377SHugues Fruchet struct v4l2_device *v4l2_dev, void __iomem *regs);
210*28e0f377SHugues Fruchet void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved);
211*28e0f377SHugues Fruchet struct dcmipp_ent_device *dcmipp_bytecap_ent_init(struct device *dev,
212*28e0f377SHugues Fruchet const char *entity_name,
213*28e0f377SHugues Fruchet struct v4l2_device *v4l2_dev,
214*28e0f377SHugues Fruchet void __iomem *regs);
215*28e0f377SHugues Fruchet void dcmipp_bytecap_ent_release(struct dcmipp_ent_device *ved);
216*28e0f377SHugues Fruchet
217*28e0f377SHugues Fruchet #endif
218