1*6edb685aSTomi Valkeinen // SPDX-License-Identifier: GPL-2.0-only 2*6edb685aSTomi Valkeinen /* 3*6edb685aSTomi Valkeinen * RP1 Camera Front End Driver 4*6edb685aSTomi Valkeinen * 5*6edb685aSTomi Valkeinen * Copyright (c) 2021-2024 Raspberry Pi Ltd. 6*6edb685aSTomi Valkeinen * Copyright (c) 2023-2024 Ideas on Board Oy 7*6edb685aSTomi Valkeinen */ 8*6edb685aSTomi Valkeinen 9*6edb685aSTomi Valkeinen #include <linux/clk.h> 10*6edb685aSTomi Valkeinen #include <linux/debugfs.h> 11*6edb685aSTomi Valkeinen #include <linux/delay.h> 12*6edb685aSTomi Valkeinen #include <linux/device.h> 13*6edb685aSTomi Valkeinen #include <linux/dma-mapping.h> 14*6edb685aSTomi Valkeinen #include <linux/err.h> 15*6edb685aSTomi Valkeinen #include <linux/fwnode.h> 16*6edb685aSTomi Valkeinen #include <linux/init.h> 17*6edb685aSTomi Valkeinen #include <linux/interrupt.h> 18*6edb685aSTomi Valkeinen #include <linux/io.h> 19*6edb685aSTomi Valkeinen #include <linux/lcm.h> 20*6edb685aSTomi Valkeinen #include <linux/math.h> 21*6edb685aSTomi Valkeinen #include <linux/module.h> 22*6edb685aSTomi Valkeinen #include <linux/platform_device.h> 23*6edb685aSTomi Valkeinen #include <linux/pm_runtime.h> 24*6edb685aSTomi Valkeinen #include <linux/property.h> 25*6edb685aSTomi Valkeinen #include <linux/seq_file.h> 26*6edb685aSTomi Valkeinen #include <linux/slab.h> 27*6edb685aSTomi Valkeinen #include <linux/uaccess.h> 28*6edb685aSTomi Valkeinen #include <linux/videodev2.h> 29*6edb685aSTomi Valkeinen 30*6edb685aSTomi Valkeinen #include <media/v4l2-async.h> 31*6edb685aSTomi Valkeinen #include <media/v4l2-common.h> 32*6edb685aSTomi Valkeinen #include <media/v4l2-ctrls.h> 33*6edb685aSTomi Valkeinen #include <media/v4l2-dev.h> 34*6edb685aSTomi Valkeinen #include <media/v4l2-device.h> 35*6edb685aSTomi Valkeinen #include <media/v4l2-event.h> 36*6edb685aSTomi Valkeinen #include <media/v4l2-fwnode.h> 37*6edb685aSTomi Valkeinen #include <media/v4l2-ioctl.h> 38*6edb685aSTomi Valkeinen #include <media/v4l2-mc.h> 39*6edb685aSTomi Valkeinen #include <media/videobuf2-dma-contig.h> 40*6edb685aSTomi Valkeinen 41*6edb685aSTomi Valkeinen #include <linux/media/raspberrypi/pisp_fe_config.h> 42*6edb685aSTomi Valkeinen #include <linux/media/raspberrypi/pisp_fe_statistics.h> 43*6edb685aSTomi Valkeinen 44*6edb685aSTomi Valkeinen #include "cfe-fmts.h" 45*6edb685aSTomi Valkeinen #include "cfe.h" 46*6edb685aSTomi Valkeinen #include "csi2.h" 47*6edb685aSTomi Valkeinen #include "pisp-fe.h" 48*6edb685aSTomi Valkeinen 49*6edb685aSTomi Valkeinen #define CREATE_TRACE_POINTS 50*6edb685aSTomi Valkeinen #include "cfe-trace.h" 51*6edb685aSTomi Valkeinen 52*6edb685aSTomi Valkeinen #define CFE_MODULE_NAME "rp1-cfe" 53*6edb685aSTomi Valkeinen #define CFE_VERSION "1.0" 54*6edb685aSTomi Valkeinen 55*6edb685aSTomi Valkeinen #define cfe_dbg(cfe, fmt, arg...) dev_dbg(&(cfe)->pdev->dev, fmt, ##arg) 56*6edb685aSTomi Valkeinen #define cfe_info(cfe, fmt, arg...) dev_info(&(cfe)->pdev->dev, fmt, ##arg) 57*6edb685aSTomi Valkeinen #define cfe_err(cfe, fmt, arg...) dev_err(&(cfe)->pdev->dev, fmt, ##arg) 58*6edb685aSTomi Valkeinen 59*6edb685aSTomi Valkeinen /* MIPICFG registers */ 60*6edb685aSTomi Valkeinen #define MIPICFG_CFG 0x004 61*6edb685aSTomi Valkeinen #define MIPICFG_INTR 0x028 62*6edb685aSTomi Valkeinen #define MIPICFG_INTE 0x02c 63*6edb685aSTomi Valkeinen #define MIPICFG_INTF 0x030 64*6edb685aSTomi Valkeinen #define MIPICFG_INTS 0x034 65*6edb685aSTomi Valkeinen 66*6edb685aSTomi Valkeinen #define MIPICFG_CFG_SEL_CSI BIT(0) 67*6edb685aSTomi Valkeinen 68*6edb685aSTomi Valkeinen #define MIPICFG_INT_CSI_DMA BIT(0) 69*6edb685aSTomi Valkeinen #define MIPICFG_INT_CSI_HOST BIT(2) 70*6edb685aSTomi Valkeinen #define MIPICFG_INT_PISP_FE BIT(4) 71*6edb685aSTomi Valkeinen 72*6edb685aSTomi Valkeinen #define BPL_ALIGNMENT 16 73*6edb685aSTomi Valkeinen #define MAX_BYTESPERLINE 0xffffff00 74*6edb685aSTomi Valkeinen #define MAX_BUFFER_SIZE 0xffffff00 75*6edb685aSTomi Valkeinen /* 76*6edb685aSTomi Valkeinen * Max width is therefore determined by the max stride divided by the number of 77*6edb685aSTomi Valkeinen * bits per pixel. 78*6edb685aSTomi Valkeinen * 79*6edb685aSTomi Valkeinen * However, to avoid overflow issues let's use a 16k maximum. This lets us 80*6edb685aSTomi Valkeinen * calculate 16k * 16k * 4 with 32bits. If we need higher maximums, a careful 81*6edb685aSTomi Valkeinen * review and adjustment of the code is needed so that it will deal with 82*6edb685aSTomi Valkeinen * overflows correctly. 83*6edb685aSTomi Valkeinen */ 84*6edb685aSTomi Valkeinen #define MAX_WIDTH 16384 85*6edb685aSTomi Valkeinen #define MAX_HEIGHT MAX_WIDTH 86*6edb685aSTomi Valkeinen /* Define a nominal minimum image size */ 87*6edb685aSTomi Valkeinen #define MIN_WIDTH 16 88*6edb685aSTomi Valkeinen #define MIN_HEIGHT 16 89*6edb685aSTomi Valkeinen 90*6edb685aSTomi Valkeinen #define MIN_META_WIDTH 4 91*6edb685aSTomi Valkeinen #define MIN_META_HEIGHT 1 92*6edb685aSTomi Valkeinen 93*6edb685aSTomi Valkeinen const struct v4l2_mbus_framefmt cfe_default_format = { 94*6edb685aSTomi Valkeinen .width = 640, 95*6edb685aSTomi Valkeinen .height = 480, 96*6edb685aSTomi Valkeinen .code = MEDIA_BUS_FMT_SRGGB10_1X10, 97*6edb685aSTomi Valkeinen .field = V4L2_FIELD_NONE, 98*6edb685aSTomi Valkeinen .colorspace = V4L2_COLORSPACE_RAW, 99*6edb685aSTomi Valkeinen .ycbcr_enc = V4L2_YCBCR_ENC_601, 100*6edb685aSTomi Valkeinen .quantization = V4L2_QUANTIZATION_FULL_RANGE, 101*6edb685aSTomi Valkeinen .xfer_func = V4L2_XFER_FUNC_NONE, 102*6edb685aSTomi Valkeinen }; 103*6edb685aSTomi Valkeinen 104*6edb685aSTomi Valkeinen enum node_ids { 105*6edb685aSTomi Valkeinen /* CSI2 HW output nodes first. */ 106*6edb685aSTomi Valkeinen CSI2_CH0, 107*6edb685aSTomi Valkeinen CSI2_CH1, 108*6edb685aSTomi Valkeinen CSI2_CH2, 109*6edb685aSTomi Valkeinen CSI2_CH3, 110*6edb685aSTomi Valkeinen /* FE only nodes from here on. */ 111*6edb685aSTomi Valkeinen FE_OUT0, 112*6edb685aSTomi Valkeinen FE_OUT1, 113*6edb685aSTomi Valkeinen FE_STATS, 114*6edb685aSTomi Valkeinen FE_CONFIG, 115*6edb685aSTomi Valkeinen NUM_NODES 116*6edb685aSTomi Valkeinen }; 117*6edb685aSTomi Valkeinen 118*6edb685aSTomi Valkeinen struct node_description { 119*6edb685aSTomi Valkeinen enum node_ids id; 120*6edb685aSTomi Valkeinen const char *name; 121*6edb685aSTomi Valkeinen unsigned int caps; 122*6edb685aSTomi Valkeinen unsigned int pad_flags; 123*6edb685aSTomi Valkeinen unsigned int link_pad; 124*6edb685aSTomi Valkeinen }; 125*6edb685aSTomi Valkeinen 126*6edb685aSTomi Valkeinen /* Must match the ordering of enum ids */ 127*6edb685aSTomi Valkeinen static const struct node_description node_desc[NUM_NODES] = { 128*6edb685aSTomi Valkeinen [CSI2_CH0] = { 129*6edb685aSTomi Valkeinen .name = "csi2-ch0", 130*6edb685aSTomi Valkeinen .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, 131*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, 132*6edb685aSTomi Valkeinen .link_pad = CSI2_PAD_FIRST_SOURCE + 0 133*6edb685aSTomi Valkeinen }, 134*6edb685aSTomi Valkeinen /* 135*6edb685aSTomi Valkeinen * At the moment the main userspace component (libcamera) doesn't 136*6edb685aSTomi Valkeinen * support metadata with video nodes that support both video and 137*6edb685aSTomi Valkeinen * metadata. So for the time being this node is set to only support 138*6edb685aSTomi Valkeinen * V4L2_CAP_META_CAPTURE. 139*6edb685aSTomi Valkeinen */ 140*6edb685aSTomi Valkeinen [CSI2_CH1] = { 141*6edb685aSTomi Valkeinen .name = "csi2-ch1", 142*6edb685aSTomi Valkeinen .caps = V4L2_CAP_META_CAPTURE, 143*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, 144*6edb685aSTomi Valkeinen .link_pad = CSI2_PAD_FIRST_SOURCE + 1 145*6edb685aSTomi Valkeinen }, 146*6edb685aSTomi Valkeinen [CSI2_CH2] = { 147*6edb685aSTomi Valkeinen .name = "csi2-ch2", 148*6edb685aSTomi Valkeinen .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, 149*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, 150*6edb685aSTomi Valkeinen .link_pad = CSI2_PAD_FIRST_SOURCE + 2 151*6edb685aSTomi Valkeinen }, 152*6edb685aSTomi Valkeinen [CSI2_CH3] = { 153*6edb685aSTomi Valkeinen .name = "csi2-ch3", 154*6edb685aSTomi Valkeinen .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, 155*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, 156*6edb685aSTomi Valkeinen .link_pad = CSI2_PAD_FIRST_SOURCE + 3 157*6edb685aSTomi Valkeinen }, 158*6edb685aSTomi Valkeinen [FE_OUT0] = { 159*6edb685aSTomi Valkeinen .name = "fe-image0", 160*6edb685aSTomi Valkeinen .caps = V4L2_CAP_VIDEO_CAPTURE, 161*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, 162*6edb685aSTomi Valkeinen .link_pad = FE_OUTPUT0_PAD 163*6edb685aSTomi Valkeinen }, 164*6edb685aSTomi Valkeinen [FE_OUT1] = { 165*6edb685aSTomi Valkeinen .name = "fe-image1", 166*6edb685aSTomi Valkeinen .caps = V4L2_CAP_VIDEO_CAPTURE, 167*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, 168*6edb685aSTomi Valkeinen .link_pad = FE_OUTPUT1_PAD 169*6edb685aSTomi Valkeinen }, 170*6edb685aSTomi Valkeinen [FE_STATS] = { 171*6edb685aSTomi Valkeinen .name = "fe-stats", 172*6edb685aSTomi Valkeinen .caps = V4L2_CAP_META_CAPTURE, 173*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, 174*6edb685aSTomi Valkeinen .link_pad = FE_STATS_PAD 175*6edb685aSTomi Valkeinen }, 176*6edb685aSTomi Valkeinen [FE_CONFIG] = { 177*6edb685aSTomi Valkeinen .name = "fe-config", 178*6edb685aSTomi Valkeinen .caps = V4L2_CAP_META_OUTPUT, 179*6edb685aSTomi Valkeinen .pad_flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT, 180*6edb685aSTomi Valkeinen .link_pad = FE_CONFIG_PAD 181*6edb685aSTomi Valkeinen }, 182*6edb685aSTomi Valkeinen }; 183*6edb685aSTomi Valkeinen 184*6edb685aSTomi Valkeinen #define is_fe_node(node) (((node)->id) >= FE_OUT0) 185*6edb685aSTomi Valkeinen #define is_csi2_node(node) (!is_fe_node(node)) 186*6edb685aSTomi Valkeinen 187*6edb685aSTomi Valkeinen #define node_supports_image_output(node) \ 188*6edb685aSTomi Valkeinen (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_CAPTURE) 189*6edb685aSTomi Valkeinen #define node_supports_meta_output(node) \ 190*6edb685aSTomi Valkeinen (node_desc[(node)->id].caps & V4L2_CAP_META_CAPTURE) 191*6edb685aSTomi Valkeinen #define node_supports_image_input(node) \ 192*6edb685aSTomi Valkeinen (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_OUTPUT) 193*6edb685aSTomi Valkeinen #define node_supports_meta_input(node) \ 194*6edb685aSTomi Valkeinen (node_desc[(node)->id].caps & V4L2_CAP_META_OUTPUT) 195*6edb685aSTomi Valkeinen #define node_supports_image(node) \ 196*6edb685aSTomi Valkeinen (node_supports_image_output(node) || node_supports_image_input(node)) 197*6edb685aSTomi Valkeinen #define node_supports_meta(node) \ 198*6edb685aSTomi Valkeinen (node_supports_meta_output(node) || node_supports_meta_input(node)) 199*6edb685aSTomi Valkeinen 200*6edb685aSTomi Valkeinen #define is_image_output_node(node) \ 201*6edb685aSTomi Valkeinen ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 202*6edb685aSTomi Valkeinen #define is_image_input_node(node) \ 203*6edb685aSTomi Valkeinen ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 204*6edb685aSTomi Valkeinen #define is_image_node(node) \ 205*6edb685aSTomi Valkeinen (is_image_output_node(node) || is_image_input_node(node)) 206*6edb685aSTomi Valkeinen #define is_meta_output_node(node) \ 207*6edb685aSTomi Valkeinen ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_CAPTURE) 208*6edb685aSTomi Valkeinen #define is_meta_input_node(node) \ 209*6edb685aSTomi Valkeinen ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_OUTPUT) 210*6edb685aSTomi Valkeinen #define is_meta_node(node) \ 211*6edb685aSTomi Valkeinen (is_meta_output_node(node) || is_meta_input_node(node)) 212*6edb685aSTomi Valkeinen 213*6edb685aSTomi Valkeinen /* To track state across all nodes. */ 214*6edb685aSTomi Valkeinen #define NODE_REGISTERED BIT(0) 215*6edb685aSTomi Valkeinen #define NODE_ENABLED BIT(1) 216*6edb685aSTomi Valkeinen #define NODE_STREAMING BIT(2) 217*6edb685aSTomi Valkeinen #define FS_INT BIT(3) 218*6edb685aSTomi Valkeinen #define FE_INT BIT(4) 219*6edb685aSTomi Valkeinen #define NUM_STATES 5 220*6edb685aSTomi Valkeinen 221*6edb685aSTomi Valkeinen struct cfe_buffer { 222*6edb685aSTomi Valkeinen struct vb2_v4l2_buffer vb; 223*6edb685aSTomi Valkeinen struct list_head list; 224*6edb685aSTomi Valkeinen }; 225*6edb685aSTomi Valkeinen 226*6edb685aSTomi Valkeinen struct cfe_config_buffer { 227*6edb685aSTomi Valkeinen struct cfe_buffer buf; 228*6edb685aSTomi Valkeinen struct pisp_fe_config config; 229*6edb685aSTomi Valkeinen }; 230*6edb685aSTomi Valkeinen 231*6edb685aSTomi Valkeinen static inline struct cfe_buffer *to_cfe_buffer(struct vb2_buffer *vb) 232*6edb685aSTomi Valkeinen { 233*6edb685aSTomi Valkeinen return container_of(vb, struct cfe_buffer, vb.vb2_buf); 234*6edb685aSTomi Valkeinen } 235*6edb685aSTomi Valkeinen 236*6edb685aSTomi Valkeinen static inline 237*6edb685aSTomi Valkeinen struct cfe_config_buffer *to_cfe_config_buffer(struct cfe_buffer *buf) 238*6edb685aSTomi Valkeinen { 239*6edb685aSTomi Valkeinen return container_of(buf, struct cfe_config_buffer, buf); 240*6edb685aSTomi Valkeinen } 241*6edb685aSTomi Valkeinen 242*6edb685aSTomi Valkeinen struct cfe_node { 243*6edb685aSTomi Valkeinen /* Node id */ 244*6edb685aSTomi Valkeinen enum node_ids id; 245*6edb685aSTomi Valkeinen /* Pointer pointing to current v4l2_buffer */ 246*6edb685aSTomi Valkeinen struct cfe_buffer *cur_frm; 247*6edb685aSTomi Valkeinen /* Pointer pointing to next v4l2_buffer */ 248*6edb685aSTomi Valkeinen struct cfe_buffer *next_frm; 249*6edb685aSTomi Valkeinen /* Used to store current pixel format */ 250*6edb685aSTomi Valkeinen struct v4l2_format vid_fmt; 251*6edb685aSTomi Valkeinen /* Used to store current meta format */ 252*6edb685aSTomi Valkeinen struct v4l2_format meta_fmt; 253*6edb685aSTomi Valkeinen /* Buffer queue used in video-buf */ 254*6edb685aSTomi Valkeinen struct vb2_queue buffer_queue; 255*6edb685aSTomi Valkeinen /* Queue of filled frames */ 256*6edb685aSTomi Valkeinen struct list_head dma_queue; 257*6edb685aSTomi Valkeinen /* lock used to access this structure */ 258*6edb685aSTomi Valkeinen struct mutex lock; 259*6edb685aSTomi Valkeinen /* Identifies video device for this channel */ 260*6edb685aSTomi Valkeinen struct video_device video_dev; 261*6edb685aSTomi Valkeinen /* Pointer to the parent handle */ 262*6edb685aSTomi Valkeinen struct cfe_device *cfe; 263*6edb685aSTomi Valkeinen /* Media pad for this node */ 264*6edb685aSTomi Valkeinen struct media_pad pad; 265*6edb685aSTomi Valkeinen /* Frame-start counter */ 266*6edb685aSTomi Valkeinen unsigned int fs_count; 267*6edb685aSTomi Valkeinen /* Timestamp of the current buffer */ 268*6edb685aSTomi Valkeinen u64 ts; 269*6edb685aSTomi Valkeinen }; 270*6edb685aSTomi Valkeinen 271*6edb685aSTomi Valkeinen struct cfe_device { 272*6edb685aSTomi Valkeinen struct dentry *debugfs; 273*6edb685aSTomi Valkeinen struct kref kref; 274*6edb685aSTomi Valkeinen 275*6edb685aSTomi Valkeinen /* peripheral base address */ 276*6edb685aSTomi Valkeinen void __iomem *mipi_cfg_base; 277*6edb685aSTomi Valkeinen 278*6edb685aSTomi Valkeinen struct clk *clk; 279*6edb685aSTomi Valkeinen 280*6edb685aSTomi Valkeinen /* V4l2 device */ 281*6edb685aSTomi Valkeinen struct v4l2_device v4l2_dev; 282*6edb685aSTomi Valkeinen struct media_device mdev; 283*6edb685aSTomi Valkeinen struct media_pipeline pipe; 284*6edb685aSTomi Valkeinen 285*6edb685aSTomi Valkeinen /* IRQ lock for node state and DMA queues */ 286*6edb685aSTomi Valkeinen spinlock_t state_lock; 287*6edb685aSTomi Valkeinen bool job_ready; 288*6edb685aSTomi Valkeinen bool job_queued; 289*6edb685aSTomi Valkeinen 290*6edb685aSTomi Valkeinen /* parent device */ 291*6edb685aSTomi Valkeinen struct platform_device *pdev; 292*6edb685aSTomi Valkeinen /* subdevice async Notifier */ 293*6edb685aSTomi Valkeinen struct v4l2_async_notifier notifier; 294*6edb685aSTomi Valkeinen 295*6edb685aSTomi Valkeinen /* Source sub device */ 296*6edb685aSTomi Valkeinen struct v4l2_subdev *source_sd; 297*6edb685aSTomi Valkeinen /* Source subdev's pad */ 298*6edb685aSTomi Valkeinen u32 source_pad; 299*6edb685aSTomi Valkeinen 300*6edb685aSTomi Valkeinen struct cfe_node node[NUM_NODES]; 301*6edb685aSTomi Valkeinen DECLARE_BITMAP(node_flags, NUM_STATES * NUM_NODES); 302*6edb685aSTomi Valkeinen 303*6edb685aSTomi Valkeinen struct csi2_device csi2; 304*6edb685aSTomi Valkeinen struct pisp_fe_device fe; 305*6edb685aSTomi Valkeinen 306*6edb685aSTomi Valkeinen int fe_csi2_channel; 307*6edb685aSTomi Valkeinen 308*6edb685aSTomi Valkeinen /* Mask of enabled streams */ 309*6edb685aSTomi Valkeinen u64 streams_mask; 310*6edb685aSTomi Valkeinen }; 311*6edb685aSTomi Valkeinen 312*6edb685aSTomi Valkeinen static inline bool is_fe_enabled(struct cfe_device *cfe) 313*6edb685aSTomi Valkeinen { 314*6edb685aSTomi Valkeinen return cfe->fe_csi2_channel != -1; 315*6edb685aSTomi Valkeinen } 316*6edb685aSTomi Valkeinen 317*6edb685aSTomi Valkeinen static inline struct cfe_device *to_cfe_device(struct v4l2_device *v4l2_dev) 318*6edb685aSTomi Valkeinen { 319*6edb685aSTomi Valkeinen return container_of(v4l2_dev, struct cfe_device, v4l2_dev); 320*6edb685aSTomi Valkeinen } 321*6edb685aSTomi Valkeinen 322*6edb685aSTomi Valkeinen static inline u32 cfg_reg_read(struct cfe_device *cfe, u32 offset) 323*6edb685aSTomi Valkeinen { 324*6edb685aSTomi Valkeinen return readl(cfe->mipi_cfg_base + offset); 325*6edb685aSTomi Valkeinen } 326*6edb685aSTomi Valkeinen 327*6edb685aSTomi Valkeinen static inline void cfg_reg_write(struct cfe_device *cfe, u32 offset, u32 val) 328*6edb685aSTomi Valkeinen { 329*6edb685aSTomi Valkeinen writel(val, cfe->mipi_cfg_base + offset); 330*6edb685aSTomi Valkeinen } 331*6edb685aSTomi Valkeinen 332*6edb685aSTomi Valkeinen static bool check_state(struct cfe_device *cfe, unsigned long state, 333*6edb685aSTomi Valkeinen unsigned int node_id) 334*6edb685aSTomi Valkeinen { 335*6edb685aSTomi Valkeinen unsigned long bit; 336*6edb685aSTomi Valkeinen 337*6edb685aSTomi Valkeinen for_each_set_bit(bit, &state, sizeof(state)) { 338*6edb685aSTomi Valkeinen if (!test_bit(bit + (node_id * NUM_STATES), cfe->node_flags)) 339*6edb685aSTomi Valkeinen return false; 340*6edb685aSTomi Valkeinen } 341*6edb685aSTomi Valkeinen 342*6edb685aSTomi Valkeinen return true; 343*6edb685aSTomi Valkeinen } 344*6edb685aSTomi Valkeinen 345*6edb685aSTomi Valkeinen static void set_state(struct cfe_device *cfe, unsigned long state, 346*6edb685aSTomi Valkeinen unsigned int node_id) 347*6edb685aSTomi Valkeinen { 348*6edb685aSTomi Valkeinen unsigned long bit; 349*6edb685aSTomi Valkeinen 350*6edb685aSTomi Valkeinen for_each_set_bit(bit, &state, sizeof(state)) 351*6edb685aSTomi Valkeinen set_bit(bit + (node_id * NUM_STATES), cfe->node_flags); 352*6edb685aSTomi Valkeinen } 353*6edb685aSTomi Valkeinen 354*6edb685aSTomi Valkeinen static void clear_state(struct cfe_device *cfe, unsigned long state, 355*6edb685aSTomi Valkeinen unsigned int node_id) 356*6edb685aSTomi Valkeinen { 357*6edb685aSTomi Valkeinen unsigned long bit; 358*6edb685aSTomi Valkeinen 359*6edb685aSTomi Valkeinen for_each_set_bit(bit, &state, sizeof(state)) 360*6edb685aSTomi Valkeinen clear_bit(bit + (node_id * NUM_STATES), cfe->node_flags); 361*6edb685aSTomi Valkeinen } 362*6edb685aSTomi Valkeinen 363*6edb685aSTomi Valkeinen static bool test_any_node(struct cfe_device *cfe, unsigned long cond) 364*6edb685aSTomi Valkeinen { 365*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 366*6edb685aSTomi Valkeinen if (check_state(cfe, cond, i)) 367*6edb685aSTomi Valkeinen return true; 368*6edb685aSTomi Valkeinen } 369*6edb685aSTomi Valkeinen 370*6edb685aSTomi Valkeinen return false; 371*6edb685aSTomi Valkeinen } 372*6edb685aSTomi Valkeinen 373*6edb685aSTomi Valkeinen static bool test_all_nodes(struct cfe_device *cfe, unsigned long precond, 374*6edb685aSTomi Valkeinen unsigned long cond) 375*6edb685aSTomi Valkeinen { 376*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 377*6edb685aSTomi Valkeinen if (check_state(cfe, precond, i)) { 378*6edb685aSTomi Valkeinen if (!check_state(cfe, cond, i)) 379*6edb685aSTomi Valkeinen return false; 380*6edb685aSTomi Valkeinen } 381*6edb685aSTomi Valkeinen } 382*6edb685aSTomi Valkeinen 383*6edb685aSTomi Valkeinen return true; 384*6edb685aSTomi Valkeinen } 385*6edb685aSTomi Valkeinen 386*6edb685aSTomi Valkeinen static int mipi_cfg_regs_show(struct seq_file *s, void *data) 387*6edb685aSTomi Valkeinen { 388*6edb685aSTomi Valkeinen struct cfe_device *cfe = s->private; 389*6edb685aSTomi Valkeinen int ret; 390*6edb685aSTomi Valkeinen 391*6edb685aSTomi Valkeinen ret = pm_runtime_resume_and_get(&cfe->pdev->dev); 392*6edb685aSTomi Valkeinen if (ret) 393*6edb685aSTomi Valkeinen return ret; 394*6edb685aSTomi Valkeinen 395*6edb685aSTomi Valkeinen #define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", cfg_reg_read(cfe, reg)) 396*6edb685aSTomi Valkeinen DUMP(MIPICFG_CFG); 397*6edb685aSTomi Valkeinen DUMP(MIPICFG_INTR); 398*6edb685aSTomi Valkeinen DUMP(MIPICFG_INTE); 399*6edb685aSTomi Valkeinen DUMP(MIPICFG_INTF); 400*6edb685aSTomi Valkeinen DUMP(MIPICFG_INTS); 401*6edb685aSTomi Valkeinen #undef DUMP 402*6edb685aSTomi Valkeinen 403*6edb685aSTomi Valkeinen pm_runtime_put(&cfe->pdev->dev); 404*6edb685aSTomi Valkeinen 405*6edb685aSTomi Valkeinen return 0; 406*6edb685aSTomi Valkeinen } 407*6edb685aSTomi Valkeinen 408*6edb685aSTomi Valkeinen DEFINE_SHOW_ATTRIBUTE(mipi_cfg_regs); 409*6edb685aSTomi Valkeinen 410*6edb685aSTomi Valkeinen /* Format setup functions */ 411*6edb685aSTomi Valkeinen const struct cfe_fmt *find_format_by_code(u32 code) 412*6edb685aSTomi Valkeinen { 413*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { 414*6edb685aSTomi Valkeinen if (formats[i].code == code) 415*6edb685aSTomi Valkeinen return &formats[i]; 416*6edb685aSTomi Valkeinen } 417*6edb685aSTomi Valkeinen 418*6edb685aSTomi Valkeinen return NULL; 419*6edb685aSTomi Valkeinen } 420*6edb685aSTomi Valkeinen 421*6edb685aSTomi Valkeinen const struct cfe_fmt *find_format_by_pix(u32 pixelformat) 422*6edb685aSTomi Valkeinen { 423*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { 424*6edb685aSTomi Valkeinen if (formats[i].fourcc == pixelformat) 425*6edb685aSTomi Valkeinen return &formats[i]; 426*6edb685aSTomi Valkeinen } 427*6edb685aSTomi Valkeinen 428*6edb685aSTomi Valkeinen return NULL; 429*6edb685aSTomi Valkeinen } 430*6edb685aSTomi Valkeinen 431*6edb685aSTomi Valkeinen static const struct cfe_fmt *find_format_by_code_and_fourcc(u32 code, 432*6edb685aSTomi Valkeinen u32 fourcc) 433*6edb685aSTomi Valkeinen { 434*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { 435*6edb685aSTomi Valkeinen if (formats[i].code == code && formats[i].fourcc == fourcc) 436*6edb685aSTomi Valkeinen return &formats[i]; 437*6edb685aSTomi Valkeinen } 438*6edb685aSTomi Valkeinen 439*6edb685aSTomi Valkeinen return NULL; 440*6edb685aSTomi Valkeinen } 441*6edb685aSTomi Valkeinen 442*6edb685aSTomi Valkeinen /* 443*6edb685aSTomi Valkeinen * Given the mbus code, find the 16 bit remapped code. Returns 0 if no remap 444*6edb685aSTomi Valkeinen * possible. 445*6edb685aSTomi Valkeinen */ 446*6edb685aSTomi Valkeinen u32 cfe_find_16bit_code(u32 code) 447*6edb685aSTomi Valkeinen { 448*6edb685aSTomi Valkeinen const struct cfe_fmt *cfe_fmt; 449*6edb685aSTomi Valkeinen 450*6edb685aSTomi Valkeinen cfe_fmt = find_format_by_code(code); 451*6edb685aSTomi Valkeinen 452*6edb685aSTomi Valkeinen if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_16BIT]) 453*6edb685aSTomi Valkeinen return 0; 454*6edb685aSTomi Valkeinen 455*6edb685aSTomi Valkeinen cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_16BIT]); 456*6edb685aSTomi Valkeinen if (!cfe_fmt) 457*6edb685aSTomi Valkeinen return 0; 458*6edb685aSTomi Valkeinen 459*6edb685aSTomi Valkeinen return cfe_fmt->code; 460*6edb685aSTomi Valkeinen } 461*6edb685aSTomi Valkeinen 462*6edb685aSTomi Valkeinen /* 463*6edb685aSTomi Valkeinen * Given the mbus code, find the 8 bit compressed code. Returns 0 if no remap 464*6edb685aSTomi Valkeinen * possible. 465*6edb685aSTomi Valkeinen */ 466*6edb685aSTomi Valkeinen u32 cfe_find_compressed_code(u32 code) 467*6edb685aSTomi Valkeinen { 468*6edb685aSTomi Valkeinen const struct cfe_fmt *cfe_fmt; 469*6edb685aSTomi Valkeinen 470*6edb685aSTomi Valkeinen cfe_fmt = find_format_by_code(code); 471*6edb685aSTomi Valkeinen 472*6edb685aSTomi Valkeinen if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_COMPRESSED]) 473*6edb685aSTomi Valkeinen return 0; 474*6edb685aSTomi Valkeinen 475*6edb685aSTomi Valkeinen cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_COMPRESSED]); 476*6edb685aSTomi Valkeinen if (!cfe_fmt) 477*6edb685aSTomi Valkeinen return 0; 478*6edb685aSTomi Valkeinen 479*6edb685aSTomi Valkeinen return cfe_fmt->code; 480*6edb685aSTomi Valkeinen } 481*6edb685aSTomi Valkeinen 482*6edb685aSTomi Valkeinen static void cfe_calc_vid_format_size_bpl(struct cfe_device *cfe, 483*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt, 484*6edb685aSTomi Valkeinen struct v4l2_format *f) 485*6edb685aSTomi Valkeinen { 486*6edb685aSTomi Valkeinen unsigned int min_bytesperline; 487*6edb685aSTomi Valkeinen 488*6edb685aSTomi Valkeinen v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2, 489*6edb685aSTomi Valkeinen &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, 0); 490*6edb685aSTomi Valkeinen 491*6edb685aSTomi Valkeinen min_bytesperline = 492*6edb685aSTomi Valkeinen ALIGN((f->fmt.pix.width * fmt->depth) >> 3, BPL_ALIGNMENT); 493*6edb685aSTomi Valkeinen 494*6edb685aSTomi Valkeinen if (f->fmt.pix.bytesperline > min_bytesperline && 495*6edb685aSTomi Valkeinen f->fmt.pix.bytesperline <= MAX_BYTESPERLINE) 496*6edb685aSTomi Valkeinen f->fmt.pix.bytesperline = 497*6edb685aSTomi Valkeinen ALIGN(f->fmt.pix.bytesperline, BPL_ALIGNMENT); 498*6edb685aSTomi Valkeinen else 499*6edb685aSTomi Valkeinen f->fmt.pix.bytesperline = min_bytesperline; 500*6edb685aSTomi Valkeinen 501*6edb685aSTomi Valkeinen f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 502*6edb685aSTomi Valkeinen 503*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u img_size:%u\n", __func__, 504*6edb685aSTomi Valkeinen &f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height, 505*6edb685aSTomi Valkeinen f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); 506*6edb685aSTomi Valkeinen } 507*6edb685aSTomi Valkeinen 508*6edb685aSTomi Valkeinen static void cfe_calc_meta_format_size_bpl(struct cfe_device *cfe, 509*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt, 510*6edb685aSTomi Valkeinen struct v4l2_format *f) 511*6edb685aSTomi Valkeinen { 512*6edb685aSTomi Valkeinen v4l_bound_align_image(&f->fmt.meta.width, MIN_META_WIDTH, MAX_WIDTH, 2, 513*6edb685aSTomi Valkeinen &f->fmt.meta.height, MIN_META_HEIGHT, MAX_HEIGHT, 514*6edb685aSTomi Valkeinen 0, 0); 515*6edb685aSTomi Valkeinen 516*6edb685aSTomi Valkeinen f->fmt.meta.bytesperline = (f->fmt.meta.width * fmt->depth) >> 3; 517*6edb685aSTomi Valkeinen f->fmt.meta.buffersize = f->fmt.meta.height * f->fmt.pix.bytesperline; 518*6edb685aSTomi Valkeinen 519*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u buf_size:%u\n", __func__, 520*6edb685aSTomi Valkeinen &f->fmt.meta.dataformat, f->fmt.meta.width, f->fmt.meta.height, 521*6edb685aSTomi Valkeinen f->fmt.meta.bytesperline, f->fmt.meta.buffersize); 522*6edb685aSTomi Valkeinen } 523*6edb685aSTomi Valkeinen 524*6edb685aSTomi Valkeinen static void cfe_schedule_next_csi2_job(struct cfe_device *cfe) 525*6edb685aSTomi Valkeinen { 526*6edb685aSTomi Valkeinen struct cfe_buffer *buf; 527*6edb685aSTomi Valkeinen dma_addr_t addr; 528*6edb685aSTomi Valkeinen 529*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { 530*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 531*6edb685aSTomi Valkeinen unsigned int stride, size; 532*6edb685aSTomi Valkeinen 533*6edb685aSTomi Valkeinen if (!check_state(cfe, NODE_STREAMING, i)) 534*6edb685aSTomi Valkeinen continue; 535*6edb685aSTomi Valkeinen 536*6edb685aSTomi Valkeinen buf = list_first_entry(&node->dma_queue, struct cfe_buffer, 537*6edb685aSTomi Valkeinen list); 538*6edb685aSTomi Valkeinen node->next_frm = buf; 539*6edb685aSTomi Valkeinen list_del(&buf->list); 540*6edb685aSTomi Valkeinen 541*6edb685aSTomi Valkeinen trace_cfe_csi2_schedule(node->id, &buf->vb.vb2_buf); 542*6edb685aSTomi Valkeinen 543*6edb685aSTomi Valkeinen if (is_meta_node(node)) { 544*6edb685aSTomi Valkeinen size = node->meta_fmt.fmt.meta.buffersize; 545*6edb685aSTomi Valkeinen /* We use CSI2_CH_CTRL_PACK_BYTES, so stride == 0 */ 546*6edb685aSTomi Valkeinen stride = 0; 547*6edb685aSTomi Valkeinen } else { 548*6edb685aSTomi Valkeinen size = node->vid_fmt.fmt.pix.sizeimage; 549*6edb685aSTomi Valkeinen stride = node->vid_fmt.fmt.pix.bytesperline; 550*6edb685aSTomi Valkeinen } 551*6edb685aSTomi Valkeinen 552*6edb685aSTomi Valkeinen addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); 553*6edb685aSTomi Valkeinen csi2_set_buffer(&cfe->csi2, node->id, addr, stride, size); 554*6edb685aSTomi Valkeinen } 555*6edb685aSTomi Valkeinen } 556*6edb685aSTomi Valkeinen 557*6edb685aSTomi Valkeinen static void cfe_schedule_next_pisp_job(struct cfe_device *cfe) 558*6edb685aSTomi Valkeinen { 559*6edb685aSTomi Valkeinen struct vb2_buffer *vb2_bufs[FE_NUM_PADS] = { 0 }; 560*6edb685aSTomi Valkeinen struct cfe_config_buffer *config_buf; 561*6edb685aSTomi Valkeinen struct cfe_buffer *buf; 562*6edb685aSTomi Valkeinen 563*6edb685aSTomi Valkeinen for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { 564*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 565*6edb685aSTomi Valkeinen 566*6edb685aSTomi Valkeinen if (!check_state(cfe, NODE_STREAMING, i)) 567*6edb685aSTomi Valkeinen continue; 568*6edb685aSTomi Valkeinen 569*6edb685aSTomi Valkeinen buf = list_first_entry(&node->dma_queue, struct cfe_buffer, 570*6edb685aSTomi Valkeinen list); 571*6edb685aSTomi Valkeinen 572*6edb685aSTomi Valkeinen trace_cfe_fe_schedule(node->id, &buf->vb.vb2_buf); 573*6edb685aSTomi Valkeinen 574*6edb685aSTomi Valkeinen node->next_frm = buf; 575*6edb685aSTomi Valkeinen vb2_bufs[node_desc[i].link_pad] = &buf->vb.vb2_buf; 576*6edb685aSTomi Valkeinen list_del(&buf->list); 577*6edb685aSTomi Valkeinen } 578*6edb685aSTomi Valkeinen 579*6edb685aSTomi Valkeinen config_buf = to_cfe_config_buffer(cfe->node[FE_CONFIG].next_frm); 580*6edb685aSTomi Valkeinen pisp_fe_submit_job(&cfe->fe, vb2_bufs, &config_buf->config); 581*6edb685aSTomi Valkeinen } 582*6edb685aSTomi Valkeinen 583*6edb685aSTomi Valkeinen static bool cfe_check_job_ready(struct cfe_device *cfe) 584*6edb685aSTomi Valkeinen { 585*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 586*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 587*6edb685aSTomi Valkeinen 588*6edb685aSTomi Valkeinen if (!check_state(cfe, NODE_ENABLED, i)) 589*6edb685aSTomi Valkeinen continue; 590*6edb685aSTomi Valkeinen 591*6edb685aSTomi Valkeinen if (list_empty(&node->dma_queue)) 592*6edb685aSTomi Valkeinen return false; 593*6edb685aSTomi Valkeinen } 594*6edb685aSTomi Valkeinen 595*6edb685aSTomi Valkeinen return true; 596*6edb685aSTomi Valkeinen } 597*6edb685aSTomi Valkeinen 598*6edb685aSTomi Valkeinen static void cfe_prepare_next_job(struct cfe_device *cfe) 599*6edb685aSTomi Valkeinen { 600*6edb685aSTomi Valkeinen trace_cfe_prepare_next_job(is_fe_enabled(cfe)); 601*6edb685aSTomi Valkeinen 602*6edb685aSTomi Valkeinen cfe->job_queued = true; 603*6edb685aSTomi Valkeinen cfe_schedule_next_csi2_job(cfe); 604*6edb685aSTomi Valkeinen if (is_fe_enabled(cfe)) 605*6edb685aSTomi Valkeinen cfe_schedule_next_pisp_job(cfe); 606*6edb685aSTomi Valkeinen 607*6edb685aSTomi Valkeinen /* Flag if another job is ready after this. */ 608*6edb685aSTomi Valkeinen cfe->job_ready = cfe_check_job_ready(cfe); 609*6edb685aSTomi Valkeinen } 610*6edb685aSTomi Valkeinen 611*6edb685aSTomi Valkeinen static void cfe_process_buffer_complete(struct cfe_node *node, 612*6edb685aSTomi Valkeinen enum vb2_buffer_state state) 613*6edb685aSTomi Valkeinen { 614*6edb685aSTomi Valkeinen trace_cfe_buffer_complete(node->id, &node->cur_frm->vb); 615*6edb685aSTomi Valkeinen 616*6edb685aSTomi Valkeinen node->cur_frm->vb.sequence = node->fs_count - 1; 617*6edb685aSTomi Valkeinen vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); 618*6edb685aSTomi Valkeinen } 619*6edb685aSTomi Valkeinen 620*6edb685aSTomi Valkeinen static void cfe_queue_event_sof(struct cfe_node *node) 621*6edb685aSTomi Valkeinen { 622*6edb685aSTomi Valkeinen struct v4l2_event event = { 623*6edb685aSTomi Valkeinen .type = V4L2_EVENT_FRAME_SYNC, 624*6edb685aSTomi Valkeinen .u.frame_sync.frame_sequence = node->fs_count - 1, 625*6edb685aSTomi Valkeinen }; 626*6edb685aSTomi Valkeinen 627*6edb685aSTomi Valkeinen v4l2_event_queue(&node->video_dev, &event); 628*6edb685aSTomi Valkeinen } 629*6edb685aSTomi Valkeinen 630*6edb685aSTomi Valkeinen static void cfe_sof_isr(struct cfe_node *node) 631*6edb685aSTomi Valkeinen { 632*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 633*6edb685aSTomi Valkeinen bool matching_fs = true; 634*6edb685aSTomi Valkeinen 635*6edb685aSTomi Valkeinen trace_cfe_frame_start(node->id, node->fs_count); 636*6edb685aSTomi Valkeinen 637*6edb685aSTomi Valkeinen /* 638*6edb685aSTomi Valkeinen * If the sensor is producing unexpected frame event ordering over a 639*6edb685aSTomi Valkeinen * sustained period of time, guard against the possibility of coming 640*6edb685aSTomi Valkeinen * here and orphaning the cur_frm if it's not been dequeued already. 641*6edb685aSTomi Valkeinen * Unfortunately, there is not enough hardware state to tell if this 642*6edb685aSTomi Valkeinen * may have occurred. 643*6edb685aSTomi Valkeinen */ 644*6edb685aSTomi Valkeinen if (WARN(node->cur_frm, "%s: [%s] Orphanded frame at seq %u\n", 645*6edb685aSTomi Valkeinen __func__, node_desc[node->id].name, node->fs_count)) 646*6edb685aSTomi Valkeinen cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR); 647*6edb685aSTomi Valkeinen 648*6edb685aSTomi Valkeinen node->cur_frm = node->next_frm; 649*6edb685aSTomi Valkeinen node->next_frm = NULL; 650*6edb685aSTomi Valkeinen node->fs_count++; 651*6edb685aSTomi Valkeinen 652*6edb685aSTomi Valkeinen node->ts = ktime_get_ns(); 653*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 654*6edb685aSTomi Valkeinen if (!check_state(cfe, NODE_STREAMING, i) || i == node->id) 655*6edb685aSTomi Valkeinen continue; 656*6edb685aSTomi Valkeinen /* 657*6edb685aSTomi Valkeinen * This checks if any other node has seen a FS. If yes, use the 658*6edb685aSTomi Valkeinen * same timestamp, eventually across all node buffers. 659*6edb685aSTomi Valkeinen */ 660*6edb685aSTomi Valkeinen if (cfe->node[i].fs_count >= node->fs_count) 661*6edb685aSTomi Valkeinen node->ts = cfe->node[i].ts; 662*6edb685aSTomi Valkeinen /* 663*6edb685aSTomi Valkeinen * This checks if all other node have seen a matching FS. If 664*6edb685aSTomi Valkeinen * yes, we can flag another job to be queued. 665*6edb685aSTomi Valkeinen */ 666*6edb685aSTomi Valkeinen if (matching_fs && cfe->node[i].fs_count != node->fs_count) 667*6edb685aSTomi Valkeinen matching_fs = false; 668*6edb685aSTomi Valkeinen } 669*6edb685aSTomi Valkeinen 670*6edb685aSTomi Valkeinen if (matching_fs) 671*6edb685aSTomi Valkeinen cfe->job_queued = false; 672*6edb685aSTomi Valkeinen 673*6edb685aSTomi Valkeinen if (node->cur_frm) 674*6edb685aSTomi Valkeinen node->cur_frm->vb.vb2_buf.timestamp = node->ts; 675*6edb685aSTomi Valkeinen 676*6edb685aSTomi Valkeinen set_state(cfe, FS_INT, node->id); 677*6edb685aSTomi Valkeinen clear_state(cfe, FE_INT, node->id); 678*6edb685aSTomi Valkeinen 679*6edb685aSTomi Valkeinen if (is_image_output_node(node)) 680*6edb685aSTomi Valkeinen cfe_queue_event_sof(node); 681*6edb685aSTomi Valkeinen } 682*6edb685aSTomi Valkeinen 683*6edb685aSTomi Valkeinen static void cfe_eof_isr(struct cfe_node *node) 684*6edb685aSTomi Valkeinen { 685*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 686*6edb685aSTomi Valkeinen 687*6edb685aSTomi Valkeinen trace_cfe_frame_end(node->id, node->fs_count - 1); 688*6edb685aSTomi Valkeinen 689*6edb685aSTomi Valkeinen if (node->cur_frm) 690*6edb685aSTomi Valkeinen cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE); 691*6edb685aSTomi Valkeinen 692*6edb685aSTomi Valkeinen node->cur_frm = NULL; 693*6edb685aSTomi Valkeinen set_state(cfe, FE_INT, node->id); 694*6edb685aSTomi Valkeinen clear_state(cfe, FS_INT, node->id); 695*6edb685aSTomi Valkeinen } 696*6edb685aSTomi Valkeinen 697*6edb685aSTomi Valkeinen static irqreturn_t cfe_isr(int irq, void *dev) 698*6edb685aSTomi Valkeinen { 699*6edb685aSTomi Valkeinen struct cfe_device *cfe = dev; 700*6edb685aSTomi Valkeinen bool sof[NUM_NODES] = { 0 }, eof[NUM_NODES] = { 0 }; 701*6edb685aSTomi Valkeinen u32 sts; 702*6edb685aSTomi Valkeinen 703*6edb685aSTomi Valkeinen sts = cfg_reg_read(cfe, MIPICFG_INTS); 704*6edb685aSTomi Valkeinen 705*6edb685aSTomi Valkeinen if (sts & MIPICFG_INT_CSI_DMA) 706*6edb685aSTomi Valkeinen csi2_isr(&cfe->csi2, sof, eof); 707*6edb685aSTomi Valkeinen 708*6edb685aSTomi Valkeinen if (sts & MIPICFG_INT_PISP_FE) 709*6edb685aSTomi Valkeinen pisp_fe_isr(&cfe->fe, sof + CSI2_NUM_CHANNELS, 710*6edb685aSTomi Valkeinen eof + CSI2_NUM_CHANNELS); 711*6edb685aSTomi Valkeinen 712*6edb685aSTomi Valkeinen spin_lock(&cfe->state_lock); 713*6edb685aSTomi Valkeinen 714*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 715*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 716*6edb685aSTomi Valkeinen 717*6edb685aSTomi Valkeinen /* 718*6edb685aSTomi Valkeinen * The check_state(NODE_STREAMING) is to ensure we do not loop 719*6edb685aSTomi Valkeinen * over the CSI2_CHx nodes when the FE is active since they 720*6edb685aSTomi Valkeinen * generate interrupts even though the node is not streaming. 721*6edb685aSTomi Valkeinen */ 722*6edb685aSTomi Valkeinen if (!check_state(cfe, NODE_STREAMING, i) || !(sof[i] || eof[i])) 723*6edb685aSTomi Valkeinen continue; 724*6edb685aSTomi Valkeinen 725*6edb685aSTomi Valkeinen /* 726*6edb685aSTomi Valkeinen * There are 3 cases where we could get FS + FE_ACK at 727*6edb685aSTomi Valkeinen * the same time: 728*6edb685aSTomi Valkeinen * 1) FE of the current frame, and FS of the next frame. 729*6edb685aSTomi Valkeinen * 2) FS + FE of the same frame. 730*6edb685aSTomi Valkeinen * 3) FE of the current frame, and FS + FE of the next 731*6edb685aSTomi Valkeinen * frame. To handle this, see the sof handler below. 732*6edb685aSTomi Valkeinen * 733*6edb685aSTomi Valkeinen * (1) is handled implicitly by the ordering of the FE and FS 734*6edb685aSTomi Valkeinen * handlers below. 735*6edb685aSTomi Valkeinen */ 736*6edb685aSTomi Valkeinen if (eof[i]) { 737*6edb685aSTomi Valkeinen /* 738*6edb685aSTomi Valkeinen * The condition below tests for (2). Run the FS handler 739*6edb685aSTomi Valkeinen * first before the FE handler, both for the current 740*6edb685aSTomi Valkeinen * frame. 741*6edb685aSTomi Valkeinen */ 742*6edb685aSTomi Valkeinen if (sof[i] && !check_state(cfe, FS_INT, i)) { 743*6edb685aSTomi Valkeinen cfe_sof_isr(node); 744*6edb685aSTomi Valkeinen sof[i] = false; 745*6edb685aSTomi Valkeinen } 746*6edb685aSTomi Valkeinen 747*6edb685aSTomi Valkeinen cfe_eof_isr(node); 748*6edb685aSTomi Valkeinen } 749*6edb685aSTomi Valkeinen 750*6edb685aSTomi Valkeinen if (sof[i]) { 751*6edb685aSTomi Valkeinen /* 752*6edb685aSTomi Valkeinen * The condition below tests for (3). In such cases, we 753*6edb685aSTomi Valkeinen * come in here with FS flag set in the node state from 754*6edb685aSTomi Valkeinen * the previous frame since it only gets cleared in 755*6edb685aSTomi Valkeinen * cfe_eof_isr(). Handle the FE for the previous 756*6edb685aSTomi Valkeinen * frame first before the FS handler for the current 757*6edb685aSTomi Valkeinen * frame. 758*6edb685aSTomi Valkeinen */ 759*6edb685aSTomi Valkeinen if (check_state(cfe, FS_INT, node->id) && 760*6edb685aSTomi Valkeinen !check_state(cfe, FE_INT, node->id)) { 761*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] Handling missing previous FE interrupt\n", 762*6edb685aSTomi Valkeinen __func__, node_desc[node->id].name); 763*6edb685aSTomi Valkeinen cfe_eof_isr(node); 764*6edb685aSTomi Valkeinen } 765*6edb685aSTomi Valkeinen 766*6edb685aSTomi Valkeinen cfe_sof_isr(node); 767*6edb685aSTomi Valkeinen } 768*6edb685aSTomi Valkeinen 769*6edb685aSTomi Valkeinen if (!cfe->job_queued && cfe->job_ready) 770*6edb685aSTomi Valkeinen cfe_prepare_next_job(cfe); 771*6edb685aSTomi Valkeinen } 772*6edb685aSTomi Valkeinen 773*6edb685aSTomi Valkeinen spin_unlock(&cfe->state_lock); 774*6edb685aSTomi Valkeinen 775*6edb685aSTomi Valkeinen return IRQ_HANDLED; 776*6edb685aSTomi Valkeinen } 777*6edb685aSTomi Valkeinen 778*6edb685aSTomi Valkeinen /* 779*6edb685aSTomi Valkeinen * Stream helpers 780*6edb685aSTomi Valkeinen */ 781*6edb685aSTomi Valkeinen 782*6edb685aSTomi Valkeinen static int cfe_get_vc_dt_fallback(struct cfe_device *cfe, u8 *vc, u8 *dt) 783*6edb685aSTomi Valkeinen { 784*6edb685aSTomi Valkeinen struct v4l2_subdev_state *state; 785*6edb685aSTomi Valkeinen struct v4l2_mbus_framefmt *fmt; 786*6edb685aSTomi Valkeinen const struct cfe_fmt *cfe_fmt; 787*6edb685aSTomi Valkeinen 788*6edb685aSTomi Valkeinen state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); 789*6edb685aSTomi Valkeinen 790*6edb685aSTomi Valkeinen fmt = v4l2_subdev_state_get_format(state, CSI2_PAD_SINK, 0); 791*6edb685aSTomi Valkeinen if (!fmt) 792*6edb685aSTomi Valkeinen return -EINVAL; 793*6edb685aSTomi Valkeinen 794*6edb685aSTomi Valkeinen cfe_fmt = find_format_by_code(fmt->code); 795*6edb685aSTomi Valkeinen if (!cfe_fmt) 796*6edb685aSTomi Valkeinen return -EINVAL; 797*6edb685aSTomi Valkeinen 798*6edb685aSTomi Valkeinen *vc = 0; 799*6edb685aSTomi Valkeinen *dt = cfe_fmt->csi_dt; 800*6edb685aSTomi Valkeinen 801*6edb685aSTomi Valkeinen return 0; 802*6edb685aSTomi Valkeinen } 803*6edb685aSTomi Valkeinen 804*6edb685aSTomi Valkeinen static int cfe_get_vc_dt(struct cfe_device *cfe, unsigned int channel, u8 *vc, 805*6edb685aSTomi Valkeinen u8 *dt) 806*6edb685aSTomi Valkeinen { 807*6edb685aSTomi Valkeinen struct v4l2_mbus_frame_desc remote_desc; 808*6edb685aSTomi Valkeinen struct v4l2_subdev_state *state; 809*6edb685aSTomi Valkeinen u32 sink_stream; 810*6edb685aSTomi Valkeinen unsigned int i; 811*6edb685aSTomi Valkeinen int ret; 812*6edb685aSTomi Valkeinen 813*6edb685aSTomi Valkeinen state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); 814*6edb685aSTomi Valkeinen 815*6edb685aSTomi Valkeinen ret = v4l2_subdev_routing_find_opposite_end(&state->routing, 816*6edb685aSTomi Valkeinen CSI2_PAD_FIRST_SOURCE + channel, 0, NULL, &sink_stream); 817*6edb685aSTomi Valkeinen if (ret) 818*6edb685aSTomi Valkeinen return ret; 819*6edb685aSTomi Valkeinen 820*6edb685aSTomi Valkeinen ret = v4l2_subdev_call(cfe->source_sd, pad, get_frame_desc, 821*6edb685aSTomi Valkeinen cfe->source_pad, &remote_desc); 822*6edb685aSTomi Valkeinen if (ret == -ENOIOCTLCMD) { 823*6edb685aSTomi Valkeinen cfe_dbg(cfe, "source does not support get_frame_desc, use fallback\n"); 824*6edb685aSTomi Valkeinen return cfe_get_vc_dt_fallback(cfe, vc, dt); 825*6edb685aSTomi Valkeinen } else if (ret) { 826*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to get frame descriptor\n"); 827*6edb685aSTomi Valkeinen return ret; 828*6edb685aSTomi Valkeinen } 829*6edb685aSTomi Valkeinen 830*6edb685aSTomi Valkeinen if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { 831*6edb685aSTomi Valkeinen cfe_err(cfe, "Frame descriptor does not describe CSI-2 link"); 832*6edb685aSTomi Valkeinen return -EINVAL; 833*6edb685aSTomi Valkeinen } 834*6edb685aSTomi Valkeinen 835*6edb685aSTomi Valkeinen for (i = 0; i < remote_desc.num_entries; i++) { 836*6edb685aSTomi Valkeinen if (remote_desc.entry[i].stream == sink_stream) 837*6edb685aSTomi Valkeinen break; 838*6edb685aSTomi Valkeinen } 839*6edb685aSTomi Valkeinen 840*6edb685aSTomi Valkeinen if (i == remote_desc.num_entries) { 841*6edb685aSTomi Valkeinen cfe_err(cfe, "Stream %u not found in remote frame desc\n", 842*6edb685aSTomi Valkeinen sink_stream); 843*6edb685aSTomi Valkeinen return -EINVAL; 844*6edb685aSTomi Valkeinen } 845*6edb685aSTomi Valkeinen 846*6edb685aSTomi Valkeinen *vc = remote_desc.entry[i].bus.csi2.vc; 847*6edb685aSTomi Valkeinen *dt = remote_desc.entry[i].bus.csi2.dt; 848*6edb685aSTomi Valkeinen 849*6edb685aSTomi Valkeinen return 0; 850*6edb685aSTomi Valkeinen } 851*6edb685aSTomi Valkeinen 852*6edb685aSTomi Valkeinen static int cfe_start_channel(struct cfe_node *node) 853*6edb685aSTomi Valkeinen { 854*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 855*6edb685aSTomi Valkeinen struct v4l2_subdev_state *state; 856*6edb685aSTomi Valkeinen struct v4l2_mbus_framefmt *source_fmt; 857*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 858*6edb685aSTomi Valkeinen unsigned long flags; 859*6edb685aSTomi Valkeinen bool start_fe; 860*6edb685aSTomi Valkeinen int ret; 861*6edb685aSTomi Valkeinen 862*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 863*6edb685aSTomi Valkeinen 864*6edb685aSTomi Valkeinen start_fe = is_fe_enabled(cfe) && 865*6edb685aSTomi Valkeinen test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); 866*6edb685aSTomi Valkeinen 867*6edb685aSTomi Valkeinen state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); 868*6edb685aSTomi Valkeinen 869*6edb685aSTomi Valkeinen if (start_fe) { 870*6edb685aSTomi Valkeinen unsigned int width, height; 871*6edb685aSTomi Valkeinen u8 vc, dt; 872*6edb685aSTomi Valkeinen 873*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: %s using csi2 channel %d\n", __func__, 874*6edb685aSTomi Valkeinen node_desc[FE_OUT0].name, cfe->fe_csi2_channel); 875*6edb685aSTomi Valkeinen 876*6edb685aSTomi Valkeinen ret = cfe_get_vc_dt(cfe, cfe->fe_csi2_channel, &vc, &dt); 877*6edb685aSTomi Valkeinen if (ret) 878*6edb685aSTomi Valkeinen return ret; 879*6edb685aSTomi Valkeinen 880*6edb685aSTomi Valkeinen source_fmt = v4l2_subdev_state_get_format(state, 881*6edb685aSTomi Valkeinen node_desc[cfe->fe_csi2_channel].link_pad); 882*6edb685aSTomi Valkeinen fmt = find_format_by_code(source_fmt->code); 883*6edb685aSTomi Valkeinen 884*6edb685aSTomi Valkeinen width = source_fmt->width; 885*6edb685aSTomi Valkeinen height = source_fmt->height; 886*6edb685aSTomi Valkeinen 887*6edb685aSTomi Valkeinen /* Must have a valid CSI2 datatype. */ 888*6edb685aSTomi Valkeinen WARN_ON(!fmt->csi_dt); 889*6edb685aSTomi Valkeinen 890*6edb685aSTomi Valkeinen /* 891*6edb685aSTomi Valkeinen * Start the associated CSI2 Channel as well. 892*6edb685aSTomi Valkeinen * 893*6edb685aSTomi Valkeinen * Must write to the ADDR register to latch the ctrl values 894*6edb685aSTomi Valkeinen * even if we are connected to the front end. Once running, 895*6edb685aSTomi Valkeinen * this is handled by the CSI2 AUTO_ARM mode. 896*6edb685aSTomi Valkeinen */ 897*6edb685aSTomi Valkeinen csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel, 898*6edb685aSTomi Valkeinen CSI2_MODE_FE_STREAMING, 899*6edb685aSTomi Valkeinen true, false, width, height, vc, dt); 900*6edb685aSTomi Valkeinen csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1); 901*6edb685aSTomi Valkeinen pisp_fe_start(&cfe->fe); 902*6edb685aSTomi Valkeinen } 903*6edb685aSTomi Valkeinen 904*6edb685aSTomi Valkeinen if (is_csi2_node(node)) { 905*6edb685aSTomi Valkeinen unsigned int width = 0, height = 0; 906*6edb685aSTomi Valkeinen u8 vc, dt; 907*6edb685aSTomi Valkeinen 908*6edb685aSTomi Valkeinen ret = cfe_get_vc_dt(cfe, node->id, &vc, &dt); 909*6edb685aSTomi Valkeinen if (ret) { 910*6edb685aSTomi Valkeinen if (start_fe) { 911*6edb685aSTomi Valkeinen csi2_stop_channel(&cfe->csi2, 912*6edb685aSTomi Valkeinen cfe->fe_csi2_channel); 913*6edb685aSTomi Valkeinen pisp_fe_stop(&cfe->fe); 914*6edb685aSTomi Valkeinen } 915*6edb685aSTomi Valkeinen 916*6edb685aSTomi Valkeinen return ret; 917*6edb685aSTomi Valkeinen } 918*6edb685aSTomi Valkeinen 919*6edb685aSTomi Valkeinen u32 mode = CSI2_MODE_NORMAL; 920*6edb685aSTomi Valkeinen 921*6edb685aSTomi Valkeinen source_fmt = v4l2_subdev_state_get_format(state, 922*6edb685aSTomi Valkeinen node_desc[node->id].link_pad); 923*6edb685aSTomi Valkeinen fmt = find_format_by_code(source_fmt->code); 924*6edb685aSTomi Valkeinen 925*6edb685aSTomi Valkeinen /* Must have a valid CSI2 datatype. */ 926*6edb685aSTomi Valkeinen WARN_ON(!fmt->csi_dt); 927*6edb685aSTomi Valkeinen 928*6edb685aSTomi Valkeinen if (is_image_output_node(node)) { 929*6edb685aSTomi Valkeinen u32 pixfmt; 930*6edb685aSTomi Valkeinen 931*6edb685aSTomi Valkeinen width = source_fmt->width; 932*6edb685aSTomi Valkeinen height = source_fmt->height; 933*6edb685aSTomi Valkeinen 934*6edb685aSTomi Valkeinen pixfmt = node->vid_fmt.fmt.pix.pixelformat; 935*6edb685aSTomi Valkeinen 936*6edb685aSTomi Valkeinen if (pixfmt == fmt->remap[CFE_REMAP_16BIT]) { 937*6edb685aSTomi Valkeinen mode = CSI2_MODE_REMAP; 938*6edb685aSTomi Valkeinen } else if (pixfmt == fmt->remap[CFE_REMAP_COMPRESSED]) { 939*6edb685aSTomi Valkeinen mode = CSI2_MODE_COMPRESSED; 940*6edb685aSTomi Valkeinen csi2_set_compression(&cfe->csi2, node->id, 941*6edb685aSTomi Valkeinen CSI2_COMPRESSION_DELTA, 0, 942*6edb685aSTomi Valkeinen 0); 943*6edb685aSTomi Valkeinen } 944*6edb685aSTomi Valkeinen } 945*6edb685aSTomi Valkeinen /* Unconditionally start this CSI2 channel. */ 946*6edb685aSTomi Valkeinen csi2_start_channel(&cfe->csi2, node->id, 947*6edb685aSTomi Valkeinen mode, 948*6edb685aSTomi Valkeinen /* Auto arm */ 949*6edb685aSTomi Valkeinen false, 950*6edb685aSTomi Valkeinen /* Pack bytes */ 951*6edb685aSTomi Valkeinen is_meta_node(node) ? true : false, 952*6edb685aSTomi Valkeinen width, height, vc, dt); 953*6edb685aSTomi Valkeinen } 954*6edb685aSTomi Valkeinen 955*6edb685aSTomi Valkeinen spin_lock_irqsave(&cfe->state_lock, flags); 956*6edb685aSTomi Valkeinen if (cfe->job_ready && test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) 957*6edb685aSTomi Valkeinen cfe_prepare_next_job(cfe); 958*6edb685aSTomi Valkeinen spin_unlock_irqrestore(&cfe->state_lock, flags); 959*6edb685aSTomi Valkeinen 960*6edb685aSTomi Valkeinen return 0; 961*6edb685aSTomi Valkeinen } 962*6edb685aSTomi Valkeinen 963*6edb685aSTomi Valkeinen static void cfe_stop_channel(struct cfe_node *node, bool fe_stop) 964*6edb685aSTomi Valkeinen { 965*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 966*6edb685aSTomi Valkeinen 967*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] fe_stop %u\n", __func__, 968*6edb685aSTomi Valkeinen node_desc[node->id].name, fe_stop); 969*6edb685aSTomi Valkeinen 970*6edb685aSTomi Valkeinen if (fe_stop) { 971*6edb685aSTomi Valkeinen csi2_stop_channel(&cfe->csi2, cfe->fe_csi2_channel); 972*6edb685aSTomi Valkeinen pisp_fe_stop(&cfe->fe); 973*6edb685aSTomi Valkeinen } 974*6edb685aSTomi Valkeinen 975*6edb685aSTomi Valkeinen if (is_csi2_node(node)) 976*6edb685aSTomi Valkeinen csi2_stop_channel(&cfe->csi2, node->id); 977*6edb685aSTomi Valkeinen } 978*6edb685aSTomi Valkeinen 979*6edb685aSTomi Valkeinen static void cfe_return_buffers(struct cfe_node *node, 980*6edb685aSTomi Valkeinen enum vb2_buffer_state state) 981*6edb685aSTomi Valkeinen { 982*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 983*6edb685aSTomi Valkeinen struct cfe_buffer *buf, *tmp; 984*6edb685aSTomi Valkeinen unsigned long flags; 985*6edb685aSTomi Valkeinen 986*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 987*6edb685aSTomi Valkeinen 988*6edb685aSTomi Valkeinen spin_lock_irqsave(&cfe->state_lock, flags); 989*6edb685aSTomi Valkeinen list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) { 990*6edb685aSTomi Valkeinen list_del(&buf->list); 991*6edb685aSTomi Valkeinen trace_cfe_return_buffer(node->id, buf->vb.vb2_buf.index, 2); 992*6edb685aSTomi Valkeinen vb2_buffer_done(&buf->vb.vb2_buf, state); 993*6edb685aSTomi Valkeinen } 994*6edb685aSTomi Valkeinen 995*6edb685aSTomi Valkeinen if (node->cur_frm) { 996*6edb685aSTomi Valkeinen trace_cfe_return_buffer(node->id, 997*6edb685aSTomi Valkeinen node->cur_frm->vb.vb2_buf.index, 0); 998*6edb685aSTomi Valkeinen vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); 999*6edb685aSTomi Valkeinen } 1000*6edb685aSTomi Valkeinen if (node->next_frm && node->cur_frm != node->next_frm) { 1001*6edb685aSTomi Valkeinen trace_cfe_return_buffer(node->id, 1002*6edb685aSTomi Valkeinen node->next_frm->vb.vb2_buf.index, 1); 1003*6edb685aSTomi Valkeinen vb2_buffer_done(&node->next_frm->vb.vb2_buf, state); 1004*6edb685aSTomi Valkeinen } 1005*6edb685aSTomi Valkeinen 1006*6edb685aSTomi Valkeinen node->cur_frm = NULL; 1007*6edb685aSTomi Valkeinen node->next_frm = NULL; 1008*6edb685aSTomi Valkeinen spin_unlock_irqrestore(&cfe->state_lock, flags); 1009*6edb685aSTomi Valkeinen } 1010*6edb685aSTomi Valkeinen 1011*6edb685aSTomi Valkeinen /* 1012*6edb685aSTomi Valkeinen * vb2 ops 1013*6edb685aSTomi Valkeinen */ 1014*6edb685aSTomi Valkeinen 1015*6edb685aSTomi Valkeinen static int cfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, 1016*6edb685aSTomi Valkeinen unsigned int *nplanes, unsigned int sizes[], 1017*6edb685aSTomi Valkeinen struct device *alloc_devs[]) 1018*6edb685aSTomi Valkeinen { 1019*6edb685aSTomi Valkeinen struct cfe_node *node = vb2_get_drv_priv(vq); 1020*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1021*6edb685aSTomi Valkeinen unsigned int size = is_image_node(node) ? 1022*6edb685aSTomi Valkeinen node->vid_fmt.fmt.pix.sizeimage : 1023*6edb685aSTomi Valkeinen node->meta_fmt.fmt.meta.buffersize; 1024*6edb685aSTomi Valkeinen 1025*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, 1026*6edb685aSTomi Valkeinen node->buffer_queue.type); 1027*6edb685aSTomi Valkeinen 1028*6edb685aSTomi Valkeinen if (vq->max_num_buffers + *nbuffers < 3) 1029*6edb685aSTomi Valkeinen *nbuffers = 3 - vq->max_num_buffers; 1030*6edb685aSTomi Valkeinen 1031*6edb685aSTomi Valkeinen if (*nplanes) { 1032*6edb685aSTomi Valkeinen if (sizes[0] < size) { 1033*6edb685aSTomi Valkeinen cfe_err(cfe, "sizes[0] %i < size %u\n", sizes[0], size); 1034*6edb685aSTomi Valkeinen return -EINVAL; 1035*6edb685aSTomi Valkeinen } 1036*6edb685aSTomi Valkeinen size = sizes[0]; 1037*6edb685aSTomi Valkeinen } 1038*6edb685aSTomi Valkeinen 1039*6edb685aSTomi Valkeinen *nplanes = 1; 1040*6edb685aSTomi Valkeinen sizes[0] = size; 1041*6edb685aSTomi Valkeinen 1042*6edb685aSTomi Valkeinen return 0; 1043*6edb685aSTomi Valkeinen } 1044*6edb685aSTomi Valkeinen 1045*6edb685aSTomi Valkeinen static int cfe_buffer_prepare(struct vb2_buffer *vb) 1046*6edb685aSTomi Valkeinen { 1047*6edb685aSTomi Valkeinen struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); 1048*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1049*6edb685aSTomi Valkeinen struct cfe_buffer *buf = to_cfe_buffer(vb); 1050*6edb685aSTomi Valkeinen unsigned long size; 1051*6edb685aSTomi Valkeinen 1052*6edb685aSTomi Valkeinen trace_cfe_buffer_prepare(node->id, vb); 1053*6edb685aSTomi Valkeinen 1054*6edb685aSTomi Valkeinen size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage : 1055*6edb685aSTomi Valkeinen node->meta_fmt.fmt.meta.buffersize; 1056*6edb685aSTomi Valkeinen if (vb2_plane_size(vb, 0) < size) { 1057*6edb685aSTomi Valkeinen cfe_err(cfe, "data will not fit into plane (%lu < %lu)\n", 1058*6edb685aSTomi Valkeinen vb2_plane_size(vb, 0), size); 1059*6edb685aSTomi Valkeinen return -EINVAL; 1060*6edb685aSTomi Valkeinen } 1061*6edb685aSTomi Valkeinen 1062*6edb685aSTomi Valkeinen vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); 1063*6edb685aSTomi Valkeinen 1064*6edb685aSTomi Valkeinen if (node->id == FE_CONFIG) { 1065*6edb685aSTomi Valkeinen struct cfe_config_buffer *b = to_cfe_config_buffer(buf); 1066*6edb685aSTomi Valkeinen void *addr = vb2_plane_vaddr(vb, 0); 1067*6edb685aSTomi Valkeinen 1068*6edb685aSTomi Valkeinen memcpy(&b->config, addr, sizeof(struct pisp_fe_config)); 1069*6edb685aSTomi Valkeinen return pisp_fe_validate_config(&cfe->fe, &b->config, 1070*6edb685aSTomi Valkeinen &cfe->node[FE_OUT0].vid_fmt, 1071*6edb685aSTomi Valkeinen &cfe->node[FE_OUT1].vid_fmt); 1072*6edb685aSTomi Valkeinen } 1073*6edb685aSTomi Valkeinen 1074*6edb685aSTomi Valkeinen return 0; 1075*6edb685aSTomi Valkeinen } 1076*6edb685aSTomi Valkeinen 1077*6edb685aSTomi Valkeinen static void cfe_buffer_queue(struct vb2_buffer *vb) 1078*6edb685aSTomi Valkeinen { 1079*6edb685aSTomi Valkeinen struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); 1080*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1081*6edb685aSTomi Valkeinen struct cfe_buffer *buf = to_cfe_buffer(vb); 1082*6edb685aSTomi Valkeinen unsigned long flags; 1083*6edb685aSTomi Valkeinen bool schedule_now; 1084*6edb685aSTomi Valkeinen 1085*6edb685aSTomi Valkeinen spin_lock_irqsave(&cfe->state_lock, flags); 1086*6edb685aSTomi Valkeinen 1087*6edb685aSTomi Valkeinen list_add_tail(&buf->list, &node->dma_queue); 1088*6edb685aSTomi Valkeinen 1089*6edb685aSTomi Valkeinen if (!cfe->job_ready) 1090*6edb685aSTomi Valkeinen cfe->job_ready = cfe_check_job_ready(cfe); 1091*6edb685aSTomi Valkeinen 1092*6edb685aSTomi Valkeinen schedule_now = !cfe->job_queued && cfe->job_ready && 1093*6edb685aSTomi Valkeinen test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); 1094*6edb685aSTomi Valkeinen 1095*6edb685aSTomi Valkeinen trace_cfe_buffer_queue(node->id, vb, schedule_now); 1096*6edb685aSTomi Valkeinen 1097*6edb685aSTomi Valkeinen if (schedule_now) 1098*6edb685aSTomi Valkeinen cfe_prepare_next_job(cfe); 1099*6edb685aSTomi Valkeinen 1100*6edb685aSTomi Valkeinen spin_unlock_irqrestore(&cfe->state_lock, flags); 1101*6edb685aSTomi Valkeinen } 1102*6edb685aSTomi Valkeinen 1103*6edb685aSTomi Valkeinen static s64 cfe_get_source_link_freq(struct cfe_device *cfe) 1104*6edb685aSTomi Valkeinen { 1105*6edb685aSTomi Valkeinen struct v4l2_subdev_state *state; 1106*6edb685aSTomi Valkeinen s64 link_freq; 1107*6edb685aSTomi Valkeinen u32 bpp; 1108*6edb685aSTomi Valkeinen 1109*6edb685aSTomi Valkeinen state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); 1110*6edb685aSTomi Valkeinen 1111*6edb685aSTomi Valkeinen /* 1112*6edb685aSTomi Valkeinen * v4l2_get_link_freq() uses V4L2_CID_LINK_FREQ first, and falls back 1113*6edb685aSTomi Valkeinen * to V4L2_CID_PIXEL_RATE if V4L2_CID_LINK_FREQ is not available. 1114*6edb685aSTomi Valkeinen * 1115*6edb685aSTomi Valkeinen * With multistream input there is no single pixel rate, and thus we 1116*6edb685aSTomi Valkeinen * cannot use V4L2_CID_PIXEL_RATE, so we pass 0 as the bpp which 1117*6edb685aSTomi Valkeinen * causes v4l2_get_link_freq() to return an error if it falls back to 1118*6edb685aSTomi Valkeinen * V4L2_CID_PIXEL_RATE. 1119*6edb685aSTomi Valkeinen */ 1120*6edb685aSTomi Valkeinen 1121*6edb685aSTomi Valkeinen if (state->routing.num_routes == 1) { 1122*6edb685aSTomi Valkeinen struct v4l2_subdev_route *route = &state->routing.routes[0]; 1123*6edb685aSTomi Valkeinen struct v4l2_mbus_framefmt *source_fmt; 1124*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 1125*6edb685aSTomi Valkeinen 1126*6edb685aSTomi Valkeinen source_fmt = v4l2_subdev_state_get_format(state, 1127*6edb685aSTomi Valkeinen route->sink_pad, 1128*6edb685aSTomi Valkeinen route->sink_stream); 1129*6edb685aSTomi Valkeinen 1130*6edb685aSTomi Valkeinen fmt = find_format_by_code(source_fmt->code); 1131*6edb685aSTomi Valkeinen if (!fmt) 1132*6edb685aSTomi Valkeinen return -EINVAL; 1133*6edb685aSTomi Valkeinen 1134*6edb685aSTomi Valkeinen bpp = fmt->depth; 1135*6edb685aSTomi Valkeinen } else { 1136*6edb685aSTomi Valkeinen bpp = 0; 1137*6edb685aSTomi Valkeinen } 1138*6edb685aSTomi Valkeinen 1139*6edb685aSTomi Valkeinen link_freq = v4l2_get_link_freq(cfe->source_sd->ctrl_handler, bpp, 1140*6edb685aSTomi Valkeinen 2 * cfe->csi2.dphy.active_lanes); 1141*6edb685aSTomi Valkeinen if (link_freq < 0) 1142*6edb685aSTomi Valkeinen cfe_err(cfe, "failed to get link freq for subdev '%s'\n", 1143*6edb685aSTomi Valkeinen cfe->source_sd->name); 1144*6edb685aSTomi Valkeinen 1145*6edb685aSTomi Valkeinen return link_freq; 1146*6edb685aSTomi Valkeinen } 1147*6edb685aSTomi Valkeinen 1148*6edb685aSTomi Valkeinen static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count) 1149*6edb685aSTomi Valkeinen { 1150*6edb685aSTomi Valkeinen struct v4l2_mbus_config mbus_config = { 0 }; 1151*6edb685aSTomi Valkeinen struct cfe_node *node = vb2_get_drv_priv(vq); 1152*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1153*6edb685aSTomi Valkeinen struct v4l2_subdev_state *state; 1154*6edb685aSTomi Valkeinen struct v4l2_subdev_route *route; 1155*6edb685aSTomi Valkeinen s64 link_freq; 1156*6edb685aSTomi Valkeinen int ret; 1157*6edb685aSTomi Valkeinen 1158*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1159*6edb685aSTomi Valkeinen 1160*6edb685aSTomi Valkeinen if (!check_state(cfe, NODE_ENABLED, node->id)) { 1161*6edb685aSTomi Valkeinen cfe_err(cfe, "%s node link is not enabled.\n", 1162*6edb685aSTomi Valkeinen node_desc[node->id].name); 1163*6edb685aSTomi Valkeinen ret = -EINVAL; 1164*6edb685aSTomi Valkeinen goto err_streaming; 1165*6edb685aSTomi Valkeinen } 1166*6edb685aSTomi Valkeinen 1167*6edb685aSTomi Valkeinen ret = pm_runtime_resume_and_get(&cfe->pdev->dev); 1168*6edb685aSTomi Valkeinen if (ret < 0) { 1169*6edb685aSTomi Valkeinen cfe_err(cfe, "pm_runtime_resume_and_get failed\n"); 1170*6edb685aSTomi Valkeinen goto err_streaming; 1171*6edb685aSTomi Valkeinen } 1172*6edb685aSTomi Valkeinen 1173*6edb685aSTomi Valkeinen /* When using the Frontend, we must enable the FE_CONFIG node. */ 1174*6edb685aSTomi Valkeinen if (is_fe_enabled(cfe) && 1175*6edb685aSTomi Valkeinen !check_state(cfe, NODE_ENABLED, cfe->node[FE_CONFIG].id)) { 1176*6edb685aSTomi Valkeinen cfe_err(cfe, "FE enabled, but FE_CONFIG node is not\n"); 1177*6edb685aSTomi Valkeinen ret = -EINVAL; 1178*6edb685aSTomi Valkeinen goto err_pm_put; 1179*6edb685aSTomi Valkeinen } 1180*6edb685aSTomi Valkeinen 1181*6edb685aSTomi Valkeinen ret = media_pipeline_start(&node->pad, &cfe->pipe); 1182*6edb685aSTomi Valkeinen if (ret < 0) { 1183*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to start media pipeline: %d\n", ret); 1184*6edb685aSTomi Valkeinen goto err_pm_put; 1185*6edb685aSTomi Valkeinen } 1186*6edb685aSTomi Valkeinen 1187*6edb685aSTomi Valkeinen state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); 1188*6edb685aSTomi Valkeinen 1189*6edb685aSTomi Valkeinen clear_state(cfe, FS_INT | FE_INT, node->id); 1190*6edb685aSTomi Valkeinen set_state(cfe, NODE_STREAMING, node->id); 1191*6edb685aSTomi Valkeinen node->fs_count = 0; 1192*6edb685aSTomi Valkeinen 1193*6edb685aSTomi Valkeinen ret = cfe_start_channel(node); 1194*6edb685aSTomi Valkeinen if (ret) 1195*6edb685aSTomi Valkeinen goto err_unlock_state; 1196*6edb685aSTomi Valkeinen 1197*6edb685aSTomi Valkeinen if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { 1198*6edb685aSTomi Valkeinen cfe_dbg(cfe, "Streaming on hold, as all nodes are not set to streaming yet\n"); 1199*6edb685aSTomi Valkeinen v4l2_subdev_unlock_state(state); 1200*6edb685aSTomi Valkeinen return 0; 1201*6edb685aSTomi Valkeinen } 1202*6edb685aSTomi Valkeinen 1203*6edb685aSTomi Valkeinen cfg_reg_write(cfe, MIPICFG_CFG, MIPICFG_CFG_SEL_CSI); 1204*6edb685aSTomi Valkeinen cfg_reg_write(cfe, MIPICFG_INTE, 1205*6edb685aSTomi Valkeinen MIPICFG_INT_CSI_DMA | MIPICFG_INT_PISP_FE); 1206*6edb685aSTomi Valkeinen 1207*6edb685aSTomi Valkeinen ret = v4l2_subdev_call(cfe->source_sd, pad, get_mbus_config, 0, 1208*6edb685aSTomi Valkeinen &mbus_config); 1209*6edb685aSTomi Valkeinen if (ret < 0 && ret != -ENOIOCTLCMD) { 1210*6edb685aSTomi Valkeinen cfe_err(cfe, "g_mbus_config failed\n"); 1211*6edb685aSTomi Valkeinen goto err_clear_inte; 1212*6edb685aSTomi Valkeinen } 1213*6edb685aSTomi Valkeinen 1214*6edb685aSTomi Valkeinen cfe->csi2.dphy.active_lanes = mbus_config.bus.mipi_csi2.num_data_lanes; 1215*6edb685aSTomi Valkeinen if (!cfe->csi2.dphy.active_lanes) 1216*6edb685aSTomi Valkeinen cfe->csi2.dphy.active_lanes = cfe->csi2.dphy.max_lanes; 1217*6edb685aSTomi Valkeinen if (cfe->csi2.dphy.active_lanes > cfe->csi2.dphy.max_lanes) { 1218*6edb685aSTomi Valkeinen cfe_err(cfe, "Device has requested %u data lanes, which is >%u configured in DT\n", 1219*6edb685aSTomi Valkeinen cfe->csi2.dphy.active_lanes, cfe->csi2.dphy.max_lanes); 1220*6edb685aSTomi Valkeinen ret = -EINVAL; 1221*6edb685aSTomi Valkeinen goto err_clear_inte; 1222*6edb685aSTomi Valkeinen } 1223*6edb685aSTomi Valkeinen 1224*6edb685aSTomi Valkeinen link_freq = cfe_get_source_link_freq(cfe); 1225*6edb685aSTomi Valkeinen if (link_freq < 0) 1226*6edb685aSTomi Valkeinen goto err_clear_inte; 1227*6edb685aSTomi Valkeinen 1228*6edb685aSTomi Valkeinen cfe->csi2.dphy.dphy_rate = div_s64(link_freq * 2, 1000000); 1229*6edb685aSTomi Valkeinen csi2_open_rx(&cfe->csi2); 1230*6edb685aSTomi Valkeinen 1231*6edb685aSTomi Valkeinen cfe->streams_mask = 0; 1232*6edb685aSTomi Valkeinen 1233*6edb685aSTomi Valkeinen for_each_active_route(&state->routing, route) 1234*6edb685aSTomi Valkeinen cfe->streams_mask |= BIT_ULL(route->sink_stream); 1235*6edb685aSTomi Valkeinen 1236*6edb685aSTomi Valkeinen ret = v4l2_subdev_enable_streams(cfe->source_sd, cfe->source_pad, 1237*6edb685aSTomi Valkeinen cfe->streams_mask); 1238*6edb685aSTomi Valkeinen if (ret) { 1239*6edb685aSTomi Valkeinen cfe_err(cfe, "stream on failed in subdev\n"); 1240*6edb685aSTomi Valkeinen goto err_disable_cfe; 1241*6edb685aSTomi Valkeinen } 1242*6edb685aSTomi Valkeinen 1243*6edb685aSTomi Valkeinen cfe_dbg(cfe, "Streaming enabled\n"); 1244*6edb685aSTomi Valkeinen 1245*6edb685aSTomi Valkeinen v4l2_subdev_unlock_state(state); 1246*6edb685aSTomi Valkeinen 1247*6edb685aSTomi Valkeinen return 0; 1248*6edb685aSTomi Valkeinen 1249*6edb685aSTomi Valkeinen err_disable_cfe: 1250*6edb685aSTomi Valkeinen csi2_close_rx(&cfe->csi2); 1251*6edb685aSTomi Valkeinen err_clear_inte: 1252*6edb685aSTomi Valkeinen cfg_reg_write(cfe, MIPICFG_INTE, 0); 1253*6edb685aSTomi Valkeinen 1254*6edb685aSTomi Valkeinen cfe_stop_channel(node, 1255*6edb685aSTomi Valkeinen is_fe_enabled(cfe) && test_all_nodes(cfe, NODE_ENABLED, 1256*6edb685aSTomi Valkeinen NODE_STREAMING)); 1257*6edb685aSTomi Valkeinen err_unlock_state: 1258*6edb685aSTomi Valkeinen v4l2_subdev_unlock_state(state); 1259*6edb685aSTomi Valkeinen media_pipeline_stop(&node->pad); 1260*6edb685aSTomi Valkeinen err_pm_put: 1261*6edb685aSTomi Valkeinen pm_runtime_put(&cfe->pdev->dev); 1262*6edb685aSTomi Valkeinen err_streaming: 1263*6edb685aSTomi Valkeinen cfe_return_buffers(node, VB2_BUF_STATE_QUEUED); 1264*6edb685aSTomi Valkeinen clear_state(cfe, NODE_STREAMING, node->id); 1265*6edb685aSTomi Valkeinen 1266*6edb685aSTomi Valkeinen return ret; 1267*6edb685aSTomi Valkeinen } 1268*6edb685aSTomi Valkeinen 1269*6edb685aSTomi Valkeinen static void cfe_stop_streaming(struct vb2_queue *vq) 1270*6edb685aSTomi Valkeinen { 1271*6edb685aSTomi Valkeinen struct cfe_node *node = vb2_get_drv_priv(vq); 1272*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1273*6edb685aSTomi Valkeinen unsigned long flags; 1274*6edb685aSTomi Valkeinen bool fe_stop; 1275*6edb685aSTomi Valkeinen 1276*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1277*6edb685aSTomi Valkeinen 1278*6edb685aSTomi Valkeinen spin_lock_irqsave(&cfe->state_lock, flags); 1279*6edb685aSTomi Valkeinen fe_stop = is_fe_enabled(cfe) && 1280*6edb685aSTomi Valkeinen test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); 1281*6edb685aSTomi Valkeinen 1282*6edb685aSTomi Valkeinen cfe->job_ready = false; 1283*6edb685aSTomi Valkeinen clear_state(cfe, NODE_STREAMING, node->id); 1284*6edb685aSTomi Valkeinen spin_unlock_irqrestore(&cfe->state_lock, flags); 1285*6edb685aSTomi Valkeinen 1286*6edb685aSTomi Valkeinen cfe_stop_channel(node, fe_stop); 1287*6edb685aSTomi Valkeinen 1288*6edb685aSTomi Valkeinen if (!test_any_node(cfe, NODE_STREAMING)) { 1289*6edb685aSTomi Valkeinen struct v4l2_subdev_state *state; 1290*6edb685aSTomi Valkeinen int ret; 1291*6edb685aSTomi Valkeinen 1292*6edb685aSTomi Valkeinen state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); 1293*6edb685aSTomi Valkeinen 1294*6edb685aSTomi Valkeinen ret = v4l2_subdev_disable_streams(cfe->source_sd, 1295*6edb685aSTomi Valkeinen cfe->source_pad, 1296*6edb685aSTomi Valkeinen cfe->streams_mask); 1297*6edb685aSTomi Valkeinen if (ret) 1298*6edb685aSTomi Valkeinen cfe_err(cfe, "stream disable failed in subdev\n"); 1299*6edb685aSTomi Valkeinen 1300*6edb685aSTomi Valkeinen v4l2_subdev_unlock_state(state); 1301*6edb685aSTomi Valkeinen 1302*6edb685aSTomi Valkeinen csi2_close_rx(&cfe->csi2); 1303*6edb685aSTomi Valkeinen 1304*6edb685aSTomi Valkeinen cfg_reg_write(cfe, MIPICFG_INTE, 0); 1305*6edb685aSTomi Valkeinen 1306*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: Streaming disabled\n", __func__); 1307*6edb685aSTomi Valkeinen } 1308*6edb685aSTomi Valkeinen 1309*6edb685aSTomi Valkeinen media_pipeline_stop(&node->pad); 1310*6edb685aSTomi Valkeinen 1311*6edb685aSTomi Valkeinen /* Clear all queued buffers for the node */ 1312*6edb685aSTomi Valkeinen cfe_return_buffers(node, VB2_BUF_STATE_ERROR); 1313*6edb685aSTomi Valkeinen 1314*6edb685aSTomi Valkeinen pm_runtime_put(&cfe->pdev->dev); 1315*6edb685aSTomi Valkeinen } 1316*6edb685aSTomi Valkeinen 1317*6edb685aSTomi Valkeinen static const struct vb2_ops cfe_video_qops = { 1318*6edb685aSTomi Valkeinen .wait_prepare = vb2_ops_wait_prepare, 1319*6edb685aSTomi Valkeinen .wait_finish = vb2_ops_wait_finish, 1320*6edb685aSTomi Valkeinen .queue_setup = cfe_queue_setup, 1321*6edb685aSTomi Valkeinen .buf_prepare = cfe_buffer_prepare, 1322*6edb685aSTomi Valkeinen .buf_queue = cfe_buffer_queue, 1323*6edb685aSTomi Valkeinen .start_streaming = cfe_start_streaming, 1324*6edb685aSTomi Valkeinen .stop_streaming = cfe_stop_streaming, 1325*6edb685aSTomi Valkeinen }; 1326*6edb685aSTomi Valkeinen 1327*6edb685aSTomi Valkeinen /* 1328*6edb685aSTomi Valkeinen * v4l2 ioctl ops 1329*6edb685aSTomi Valkeinen */ 1330*6edb685aSTomi Valkeinen 1331*6edb685aSTomi Valkeinen static int cfe_querycap(struct file *file, void *priv, 1332*6edb685aSTomi Valkeinen struct v4l2_capability *cap) 1333*6edb685aSTomi Valkeinen { 1334*6edb685aSTomi Valkeinen strscpy(cap->driver, CFE_MODULE_NAME, sizeof(cap->driver)); 1335*6edb685aSTomi Valkeinen strscpy(cap->card, CFE_MODULE_NAME, sizeof(cap->card)); 1336*6edb685aSTomi Valkeinen 1337*6edb685aSTomi Valkeinen cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE | 1338*6edb685aSTomi Valkeinen V4L2_CAP_META_OUTPUT; 1339*6edb685aSTomi Valkeinen 1340*6edb685aSTomi Valkeinen return 0; 1341*6edb685aSTomi Valkeinen } 1342*6edb685aSTomi Valkeinen 1343*6edb685aSTomi Valkeinen static int cfe_enum_fmt_vid_cap(struct file *file, void *priv, 1344*6edb685aSTomi Valkeinen struct v4l2_fmtdesc *f) 1345*6edb685aSTomi Valkeinen { 1346*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1347*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1348*6edb685aSTomi Valkeinen unsigned int i, j; 1349*6edb685aSTomi Valkeinen 1350*6edb685aSTomi Valkeinen if (!node_supports_image_output(node)) 1351*6edb685aSTomi Valkeinen return -EINVAL; 1352*6edb685aSTomi Valkeinen 1353*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1354*6edb685aSTomi Valkeinen 1355*6edb685aSTomi Valkeinen for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) { 1356*6edb685aSTomi Valkeinen if (f->mbus_code && formats[i].code != f->mbus_code) 1357*6edb685aSTomi Valkeinen continue; 1358*6edb685aSTomi Valkeinen 1359*6edb685aSTomi Valkeinen if (formats[i].flags & CFE_FORMAT_FLAG_META_OUT || 1360*6edb685aSTomi Valkeinen formats[i].flags & CFE_FORMAT_FLAG_META_CAP) 1361*6edb685aSTomi Valkeinen continue; 1362*6edb685aSTomi Valkeinen 1363*6edb685aSTomi Valkeinen if (is_fe_node(node) && 1364*6edb685aSTomi Valkeinen !(formats[i].flags & CFE_FORMAT_FLAG_FE_OUT)) 1365*6edb685aSTomi Valkeinen continue; 1366*6edb685aSTomi Valkeinen 1367*6edb685aSTomi Valkeinen if (j == f->index) { 1368*6edb685aSTomi Valkeinen f->pixelformat = formats[i].fourcc; 1369*6edb685aSTomi Valkeinen f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1370*6edb685aSTomi Valkeinen return 0; 1371*6edb685aSTomi Valkeinen } 1372*6edb685aSTomi Valkeinen j++; 1373*6edb685aSTomi Valkeinen } 1374*6edb685aSTomi Valkeinen 1375*6edb685aSTomi Valkeinen return -EINVAL; 1376*6edb685aSTomi Valkeinen } 1377*6edb685aSTomi Valkeinen 1378*6edb685aSTomi Valkeinen static int cfe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) 1379*6edb685aSTomi Valkeinen { 1380*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1381*6edb685aSTomi Valkeinen 1382*6edb685aSTomi Valkeinen if (!node_supports_image(node)) 1383*6edb685aSTomi Valkeinen return -EINVAL; 1384*6edb685aSTomi Valkeinen 1385*6edb685aSTomi Valkeinen *f = node->vid_fmt; 1386*6edb685aSTomi Valkeinen 1387*6edb685aSTomi Valkeinen return 0; 1388*6edb685aSTomi Valkeinen } 1389*6edb685aSTomi Valkeinen 1390*6edb685aSTomi Valkeinen static int cfe_validate_fmt_vid_cap(struct cfe_node *node, 1391*6edb685aSTomi Valkeinen struct v4l2_format *f) 1392*6edb685aSTomi Valkeinen { 1393*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1394*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 1395*6edb685aSTomi Valkeinen 1396*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 pix %p4cc\n", __func__, 1397*6edb685aSTomi Valkeinen node_desc[node->id].name, f->fmt.pix.width, f->fmt.pix.height, 1398*6edb685aSTomi Valkeinen &f->fmt.pix.pixelformat); 1399*6edb685aSTomi Valkeinen 1400*6edb685aSTomi Valkeinen if (!node_supports_image_output(node)) 1401*6edb685aSTomi Valkeinen return -EINVAL; 1402*6edb685aSTomi Valkeinen 1403*6edb685aSTomi Valkeinen /* 1404*6edb685aSTomi Valkeinen * Default to a format that works for both CSI2 and FE. 1405*6edb685aSTomi Valkeinen */ 1406*6edb685aSTomi Valkeinen fmt = find_format_by_pix(f->fmt.pix.pixelformat); 1407*6edb685aSTomi Valkeinen if (!fmt) 1408*6edb685aSTomi Valkeinen fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); 1409*6edb685aSTomi Valkeinen 1410*6edb685aSTomi Valkeinen f->fmt.pix.pixelformat = fmt->fourcc; 1411*6edb685aSTomi Valkeinen 1412*6edb685aSTomi Valkeinen if (is_fe_node(node) && fmt->remap[CFE_REMAP_16BIT]) { 1413*6edb685aSTomi Valkeinen f->fmt.pix.pixelformat = fmt->remap[CFE_REMAP_16BIT]; 1414*6edb685aSTomi Valkeinen fmt = find_format_by_pix(f->fmt.pix.pixelformat); 1415*6edb685aSTomi Valkeinen } 1416*6edb685aSTomi Valkeinen 1417*6edb685aSTomi Valkeinen f->fmt.pix.field = V4L2_FIELD_NONE; 1418*6edb685aSTomi Valkeinen 1419*6edb685aSTomi Valkeinen cfe_calc_vid_format_size_bpl(cfe, fmt, f); 1420*6edb685aSTomi Valkeinen 1421*6edb685aSTomi Valkeinen return 0; 1422*6edb685aSTomi Valkeinen } 1423*6edb685aSTomi Valkeinen 1424*6edb685aSTomi Valkeinen static int cfe_s_fmt_vid_cap(struct file *file, void *priv, 1425*6edb685aSTomi Valkeinen struct v4l2_format *f) 1426*6edb685aSTomi Valkeinen { 1427*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1428*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1429*6edb685aSTomi Valkeinen struct vb2_queue *q = &node->buffer_queue; 1430*6edb685aSTomi Valkeinen int ret; 1431*6edb685aSTomi Valkeinen 1432*6edb685aSTomi Valkeinen if (vb2_is_busy(q)) 1433*6edb685aSTomi Valkeinen return -EBUSY; 1434*6edb685aSTomi Valkeinen 1435*6edb685aSTomi Valkeinen ret = cfe_validate_fmt_vid_cap(node, f); 1436*6edb685aSTomi Valkeinen if (ret) 1437*6edb685aSTomi Valkeinen return ret; 1438*6edb685aSTomi Valkeinen 1439*6edb685aSTomi Valkeinen node->vid_fmt = *f; 1440*6edb685aSTomi Valkeinen 1441*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: Set %ux%u, V4L2 pix %p4cc\n", __func__, 1442*6edb685aSTomi Valkeinen node->vid_fmt.fmt.pix.width, node->vid_fmt.fmt.pix.height, 1443*6edb685aSTomi Valkeinen &node->vid_fmt.fmt.pix.pixelformat); 1444*6edb685aSTomi Valkeinen 1445*6edb685aSTomi Valkeinen return 0; 1446*6edb685aSTomi Valkeinen } 1447*6edb685aSTomi Valkeinen 1448*6edb685aSTomi Valkeinen static int cfe_try_fmt_vid_cap(struct file *file, void *priv, 1449*6edb685aSTomi Valkeinen struct v4l2_format *f) 1450*6edb685aSTomi Valkeinen { 1451*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1452*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1453*6edb685aSTomi Valkeinen 1454*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1455*6edb685aSTomi Valkeinen 1456*6edb685aSTomi Valkeinen return cfe_validate_fmt_vid_cap(node, f); 1457*6edb685aSTomi Valkeinen } 1458*6edb685aSTomi Valkeinen 1459*6edb685aSTomi Valkeinen static int cfe_enum_fmt_meta(struct file *file, void *priv, 1460*6edb685aSTomi Valkeinen struct v4l2_fmtdesc *f) 1461*6edb685aSTomi Valkeinen { 1462*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1463*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1464*6edb685aSTomi Valkeinen 1465*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1466*6edb685aSTomi Valkeinen 1467*6edb685aSTomi Valkeinen if (!node_supports_meta(node)) 1468*6edb685aSTomi Valkeinen return -EINVAL; 1469*6edb685aSTomi Valkeinen 1470*6edb685aSTomi Valkeinen switch (node->id) { 1471*6edb685aSTomi Valkeinen case CSI2_CH0...CSI2_CH3: 1472*6edb685aSTomi Valkeinen f->flags = V4L2_FMT_FLAG_META_LINE_BASED; 1473*6edb685aSTomi Valkeinen 1474*6edb685aSTomi Valkeinen switch (f->index) { 1475*6edb685aSTomi Valkeinen case 0: 1476*6edb685aSTomi Valkeinen f->pixelformat = V4L2_META_FMT_GENERIC_8; 1477*6edb685aSTomi Valkeinen return 0; 1478*6edb685aSTomi Valkeinen case 1: 1479*6edb685aSTomi Valkeinen f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_10; 1480*6edb685aSTomi Valkeinen return 0; 1481*6edb685aSTomi Valkeinen case 2: 1482*6edb685aSTomi Valkeinen f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_12; 1483*6edb685aSTomi Valkeinen return 0; 1484*6edb685aSTomi Valkeinen default: 1485*6edb685aSTomi Valkeinen return -EINVAL; 1486*6edb685aSTomi Valkeinen } 1487*6edb685aSTomi Valkeinen default: 1488*6edb685aSTomi Valkeinen break; 1489*6edb685aSTomi Valkeinen } 1490*6edb685aSTomi Valkeinen 1491*6edb685aSTomi Valkeinen if (f->index != 0) 1492*6edb685aSTomi Valkeinen return -EINVAL; 1493*6edb685aSTomi Valkeinen 1494*6edb685aSTomi Valkeinen switch (node->id) { 1495*6edb685aSTomi Valkeinen case FE_STATS: 1496*6edb685aSTomi Valkeinen f->pixelformat = V4L2_META_FMT_RPI_FE_STATS; 1497*6edb685aSTomi Valkeinen return 0; 1498*6edb685aSTomi Valkeinen case FE_CONFIG: 1499*6edb685aSTomi Valkeinen f->pixelformat = V4L2_META_FMT_RPI_FE_CFG; 1500*6edb685aSTomi Valkeinen return 0; 1501*6edb685aSTomi Valkeinen default: 1502*6edb685aSTomi Valkeinen return -EINVAL; 1503*6edb685aSTomi Valkeinen } 1504*6edb685aSTomi Valkeinen } 1505*6edb685aSTomi Valkeinen 1506*6edb685aSTomi Valkeinen static int cfe_validate_fmt_meta(struct cfe_node *node, struct v4l2_format *f) 1507*6edb685aSTomi Valkeinen { 1508*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1509*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 1510*6edb685aSTomi Valkeinen 1511*6edb685aSTomi Valkeinen switch (node->id) { 1512*6edb685aSTomi Valkeinen case CSI2_CH0...CSI2_CH3: 1513*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 meta %p4cc\n", __func__, 1514*6edb685aSTomi Valkeinen node_desc[node->id].name, f->fmt.meta.width, 1515*6edb685aSTomi Valkeinen f->fmt.meta.height, &f->fmt.meta.dataformat); 1516*6edb685aSTomi Valkeinen break; 1517*6edb685aSTomi Valkeinen case FE_STATS: 1518*6edb685aSTomi Valkeinen case FE_CONFIG: 1519*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] %u bytes, V4L2 meta %p4cc\n", __func__, 1520*6edb685aSTomi Valkeinen node_desc[node->id].name, f->fmt.meta.buffersize, 1521*6edb685aSTomi Valkeinen &f->fmt.meta.dataformat); 1522*6edb685aSTomi Valkeinen break; 1523*6edb685aSTomi Valkeinen default: 1524*6edb685aSTomi Valkeinen return -EINVAL; 1525*6edb685aSTomi Valkeinen } 1526*6edb685aSTomi Valkeinen 1527*6edb685aSTomi Valkeinen if (!node_supports_meta(node)) 1528*6edb685aSTomi Valkeinen return -EINVAL; 1529*6edb685aSTomi Valkeinen 1530*6edb685aSTomi Valkeinen switch (node->id) { 1531*6edb685aSTomi Valkeinen case CSI2_CH0...CSI2_CH3: 1532*6edb685aSTomi Valkeinen fmt = find_format_by_pix(f->fmt.meta.dataformat); 1533*6edb685aSTomi Valkeinen if (!fmt || !(fmt->flags & CFE_FORMAT_FLAG_META_CAP)) 1534*6edb685aSTomi Valkeinen fmt = find_format_by_pix(V4L2_META_FMT_GENERIC_CSI2_10); 1535*6edb685aSTomi Valkeinen 1536*6edb685aSTomi Valkeinen f->fmt.meta.dataformat = fmt->fourcc; 1537*6edb685aSTomi Valkeinen 1538*6edb685aSTomi Valkeinen cfe_calc_meta_format_size_bpl(cfe, fmt, f); 1539*6edb685aSTomi Valkeinen 1540*6edb685aSTomi Valkeinen return 0; 1541*6edb685aSTomi Valkeinen case FE_STATS: 1542*6edb685aSTomi Valkeinen f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_STATS; 1543*6edb685aSTomi Valkeinen f->fmt.meta.buffersize = sizeof(struct pisp_statistics); 1544*6edb685aSTomi Valkeinen return 0; 1545*6edb685aSTomi Valkeinen case FE_CONFIG: 1546*6edb685aSTomi Valkeinen f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_CFG; 1547*6edb685aSTomi Valkeinen f->fmt.meta.buffersize = sizeof(struct pisp_fe_config); 1548*6edb685aSTomi Valkeinen return 0; 1549*6edb685aSTomi Valkeinen default: 1550*6edb685aSTomi Valkeinen return -EINVAL; 1551*6edb685aSTomi Valkeinen } 1552*6edb685aSTomi Valkeinen } 1553*6edb685aSTomi Valkeinen 1554*6edb685aSTomi Valkeinen static int cfe_g_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) 1555*6edb685aSTomi Valkeinen { 1556*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1557*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1558*6edb685aSTomi Valkeinen 1559*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1560*6edb685aSTomi Valkeinen 1561*6edb685aSTomi Valkeinen if (!node_supports_meta(node)) 1562*6edb685aSTomi Valkeinen return -EINVAL; 1563*6edb685aSTomi Valkeinen 1564*6edb685aSTomi Valkeinen *f = node->meta_fmt; 1565*6edb685aSTomi Valkeinen 1566*6edb685aSTomi Valkeinen return 0; 1567*6edb685aSTomi Valkeinen } 1568*6edb685aSTomi Valkeinen 1569*6edb685aSTomi Valkeinen static int cfe_s_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) 1570*6edb685aSTomi Valkeinen { 1571*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1572*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1573*6edb685aSTomi Valkeinen struct vb2_queue *q = &node->buffer_queue; 1574*6edb685aSTomi Valkeinen int ret; 1575*6edb685aSTomi Valkeinen 1576*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1577*6edb685aSTomi Valkeinen 1578*6edb685aSTomi Valkeinen if (vb2_is_busy(q)) 1579*6edb685aSTomi Valkeinen return -EBUSY; 1580*6edb685aSTomi Valkeinen 1581*6edb685aSTomi Valkeinen if (!node_supports_meta(node)) 1582*6edb685aSTomi Valkeinen return -EINVAL; 1583*6edb685aSTomi Valkeinen 1584*6edb685aSTomi Valkeinen ret = cfe_validate_fmt_meta(node, f); 1585*6edb685aSTomi Valkeinen if (ret) 1586*6edb685aSTomi Valkeinen return ret; 1587*6edb685aSTomi Valkeinen 1588*6edb685aSTomi Valkeinen node->meta_fmt = *f; 1589*6edb685aSTomi Valkeinen 1590*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: Set %p4cc\n", __func__, 1591*6edb685aSTomi Valkeinen &node->meta_fmt.fmt.meta.dataformat); 1592*6edb685aSTomi Valkeinen 1593*6edb685aSTomi Valkeinen return 0; 1594*6edb685aSTomi Valkeinen } 1595*6edb685aSTomi Valkeinen 1596*6edb685aSTomi Valkeinen static int cfe_try_fmt_meta(struct file *file, void *priv, 1597*6edb685aSTomi Valkeinen struct v4l2_format *f) 1598*6edb685aSTomi Valkeinen { 1599*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1600*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1601*6edb685aSTomi Valkeinen 1602*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); 1603*6edb685aSTomi Valkeinen return cfe_validate_fmt_meta(node, f); 1604*6edb685aSTomi Valkeinen } 1605*6edb685aSTomi Valkeinen 1606*6edb685aSTomi Valkeinen static int cfe_enum_framesizes(struct file *file, void *priv, 1607*6edb685aSTomi Valkeinen struct v4l2_frmsizeenum *fsize) 1608*6edb685aSTomi Valkeinen { 1609*6edb685aSTomi Valkeinen struct cfe_node *node = video_drvdata(file); 1610*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1611*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 1612*6edb685aSTomi Valkeinen 1613*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s [%s]\n", __func__, node_desc[node->id].name); 1614*6edb685aSTomi Valkeinen 1615*6edb685aSTomi Valkeinen if (fsize->index > 0) 1616*6edb685aSTomi Valkeinen return -EINVAL; 1617*6edb685aSTomi Valkeinen 1618*6edb685aSTomi Valkeinen /* check for valid format */ 1619*6edb685aSTomi Valkeinen fmt = find_format_by_pix(fsize->pixel_format); 1620*6edb685aSTomi Valkeinen if (!fmt) { 1621*6edb685aSTomi Valkeinen cfe_dbg(cfe, "Invalid pixel code: %x\n", fsize->pixel_format); 1622*6edb685aSTomi Valkeinen return -EINVAL; 1623*6edb685aSTomi Valkeinen } 1624*6edb685aSTomi Valkeinen 1625*6edb685aSTomi Valkeinen /* TODO: Do we have limits on the step_width? */ 1626*6edb685aSTomi Valkeinen 1627*6edb685aSTomi Valkeinen fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 1628*6edb685aSTomi Valkeinen fsize->stepwise.min_width = MIN_WIDTH; 1629*6edb685aSTomi Valkeinen fsize->stepwise.max_width = MAX_WIDTH; 1630*6edb685aSTomi Valkeinen fsize->stepwise.step_width = 2; 1631*6edb685aSTomi Valkeinen fsize->stepwise.min_height = MIN_HEIGHT; 1632*6edb685aSTomi Valkeinen fsize->stepwise.max_height = MAX_HEIGHT; 1633*6edb685aSTomi Valkeinen fsize->stepwise.step_height = 1; 1634*6edb685aSTomi Valkeinen 1635*6edb685aSTomi Valkeinen return 0; 1636*6edb685aSTomi Valkeinen } 1637*6edb685aSTomi Valkeinen 1638*6edb685aSTomi Valkeinen static int cfe_vb2_ioctl_reqbufs(struct file *file, void *priv, 1639*6edb685aSTomi Valkeinen struct v4l2_requestbuffers *p) 1640*6edb685aSTomi Valkeinen { 1641*6edb685aSTomi Valkeinen struct video_device *vdev = video_devdata(file); 1642*6edb685aSTomi Valkeinen struct cfe_node *node = video_get_drvdata(vdev); 1643*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1644*6edb685aSTomi Valkeinen int ret; 1645*6edb685aSTomi Valkeinen 1646*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, 1647*6edb685aSTomi Valkeinen p->type); 1648*6edb685aSTomi Valkeinen 1649*6edb685aSTomi Valkeinen if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 1650*6edb685aSTomi Valkeinen p->type != V4L2_BUF_TYPE_META_CAPTURE && 1651*6edb685aSTomi Valkeinen p->type != V4L2_BUF_TYPE_META_OUTPUT) 1652*6edb685aSTomi Valkeinen return -EINVAL; 1653*6edb685aSTomi Valkeinen 1654*6edb685aSTomi Valkeinen ret = vb2_queue_change_type(vdev->queue, p->type); 1655*6edb685aSTomi Valkeinen if (ret) 1656*6edb685aSTomi Valkeinen return ret; 1657*6edb685aSTomi Valkeinen 1658*6edb685aSTomi Valkeinen return vb2_ioctl_reqbufs(file, priv, p); 1659*6edb685aSTomi Valkeinen } 1660*6edb685aSTomi Valkeinen 1661*6edb685aSTomi Valkeinen static int cfe_vb2_ioctl_create_bufs(struct file *file, void *priv, 1662*6edb685aSTomi Valkeinen struct v4l2_create_buffers *p) 1663*6edb685aSTomi Valkeinen { 1664*6edb685aSTomi Valkeinen struct video_device *vdev = video_devdata(file); 1665*6edb685aSTomi Valkeinen struct cfe_node *node = video_get_drvdata(vdev); 1666*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1667*6edb685aSTomi Valkeinen int ret; 1668*6edb685aSTomi Valkeinen 1669*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, 1670*6edb685aSTomi Valkeinen p->format.type); 1671*6edb685aSTomi Valkeinen 1672*6edb685aSTomi Valkeinen if (p->format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 1673*6edb685aSTomi Valkeinen p->format.type != V4L2_BUF_TYPE_META_CAPTURE && 1674*6edb685aSTomi Valkeinen p->format.type != V4L2_BUF_TYPE_META_OUTPUT) 1675*6edb685aSTomi Valkeinen return -EINVAL; 1676*6edb685aSTomi Valkeinen 1677*6edb685aSTomi Valkeinen ret = vb2_queue_change_type(vdev->queue, p->format.type); 1678*6edb685aSTomi Valkeinen if (ret) 1679*6edb685aSTomi Valkeinen return ret; 1680*6edb685aSTomi Valkeinen 1681*6edb685aSTomi Valkeinen return vb2_ioctl_create_bufs(file, priv, p); 1682*6edb685aSTomi Valkeinen } 1683*6edb685aSTomi Valkeinen 1684*6edb685aSTomi Valkeinen static int cfe_subscribe_event(struct v4l2_fh *fh, 1685*6edb685aSTomi Valkeinen const struct v4l2_event_subscription *sub) 1686*6edb685aSTomi Valkeinen { 1687*6edb685aSTomi Valkeinen struct cfe_node *node = video_get_drvdata(fh->vdev); 1688*6edb685aSTomi Valkeinen 1689*6edb685aSTomi Valkeinen switch (sub->type) { 1690*6edb685aSTomi Valkeinen case V4L2_EVENT_FRAME_SYNC: 1691*6edb685aSTomi Valkeinen if (!node_supports_image_output(node)) 1692*6edb685aSTomi Valkeinen break; 1693*6edb685aSTomi Valkeinen 1694*6edb685aSTomi Valkeinen return v4l2_event_subscribe(fh, sub, 2, NULL); 1695*6edb685aSTomi Valkeinen case V4L2_EVENT_SOURCE_CHANGE: 1696*6edb685aSTomi Valkeinen if (!node_supports_image_output(node) && 1697*6edb685aSTomi Valkeinen !node_supports_meta_output(node)) 1698*6edb685aSTomi Valkeinen break; 1699*6edb685aSTomi Valkeinen 1700*6edb685aSTomi Valkeinen return v4l2_event_subscribe(fh, sub, 4, NULL); 1701*6edb685aSTomi Valkeinen } 1702*6edb685aSTomi Valkeinen 1703*6edb685aSTomi Valkeinen return v4l2_ctrl_subscribe_event(fh, sub); 1704*6edb685aSTomi Valkeinen } 1705*6edb685aSTomi Valkeinen 1706*6edb685aSTomi Valkeinen static const struct v4l2_ioctl_ops cfe_ioctl_ops = { 1707*6edb685aSTomi Valkeinen .vidioc_querycap = cfe_querycap, 1708*6edb685aSTomi Valkeinen .vidioc_enum_fmt_vid_cap = cfe_enum_fmt_vid_cap, 1709*6edb685aSTomi Valkeinen .vidioc_g_fmt_vid_cap = cfe_g_fmt, 1710*6edb685aSTomi Valkeinen .vidioc_s_fmt_vid_cap = cfe_s_fmt_vid_cap, 1711*6edb685aSTomi Valkeinen .vidioc_try_fmt_vid_cap = cfe_try_fmt_vid_cap, 1712*6edb685aSTomi Valkeinen 1713*6edb685aSTomi Valkeinen .vidioc_enum_fmt_meta_cap = cfe_enum_fmt_meta, 1714*6edb685aSTomi Valkeinen .vidioc_g_fmt_meta_cap = cfe_g_fmt_meta, 1715*6edb685aSTomi Valkeinen .vidioc_s_fmt_meta_cap = cfe_s_fmt_meta, 1716*6edb685aSTomi Valkeinen .vidioc_try_fmt_meta_cap = cfe_try_fmt_meta, 1717*6edb685aSTomi Valkeinen 1718*6edb685aSTomi Valkeinen .vidioc_enum_fmt_meta_out = cfe_enum_fmt_meta, 1719*6edb685aSTomi Valkeinen .vidioc_g_fmt_meta_out = cfe_g_fmt_meta, 1720*6edb685aSTomi Valkeinen .vidioc_s_fmt_meta_out = cfe_s_fmt_meta, 1721*6edb685aSTomi Valkeinen .vidioc_try_fmt_meta_out = cfe_try_fmt_meta, 1722*6edb685aSTomi Valkeinen 1723*6edb685aSTomi Valkeinen .vidioc_enum_framesizes = cfe_enum_framesizes, 1724*6edb685aSTomi Valkeinen 1725*6edb685aSTomi Valkeinen .vidioc_reqbufs = cfe_vb2_ioctl_reqbufs, 1726*6edb685aSTomi Valkeinen .vidioc_create_bufs = cfe_vb2_ioctl_create_bufs, 1727*6edb685aSTomi Valkeinen .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 1728*6edb685aSTomi Valkeinen .vidioc_querybuf = vb2_ioctl_querybuf, 1729*6edb685aSTomi Valkeinen .vidioc_qbuf = vb2_ioctl_qbuf, 1730*6edb685aSTomi Valkeinen .vidioc_dqbuf = vb2_ioctl_dqbuf, 1731*6edb685aSTomi Valkeinen .vidioc_expbuf = vb2_ioctl_expbuf, 1732*6edb685aSTomi Valkeinen .vidioc_streamon = vb2_ioctl_streamon, 1733*6edb685aSTomi Valkeinen .vidioc_streamoff = vb2_ioctl_streamoff, 1734*6edb685aSTomi Valkeinen 1735*6edb685aSTomi Valkeinen .vidioc_subscribe_event = cfe_subscribe_event, 1736*6edb685aSTomi Valkeinen .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1737*6edb685aSTomi Valkeinen }; 1738*6edb685aSTomi Valkeinen 1739*6edb685aSTomi Valkeinen static void cfe_notify(struct v4l2_subdev *sd, unsigned int notification, 1740*6edb685aSTomi Valkeinen void *arg) 1741*6edb685aSTomi Valkeinen { 1742*6edb685aSTomi Valkeinen struct cfe_device *cfe = to_cfe_device(sd->v4l2_dev); 1743*6edb685aSTomi Valkeinen 1744*6edb685aSTomi Valkeinen switch (notification) { 1745*6edb685aSTomi Valkeinen case V4L2_DEVICE_NOTIFY_EVENT: 1746*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 1747*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 1748*6edb685aSTomi Valkeinen 1749*6edb685aSTomi Valkeinen if (check_state(cfe, NODE_REGISTERED, i)) 1750*6edb685aSTomi Valkeinen continue; 1751*6edb685aSTomi Valkeinen 1752*6edb685aSTomi Valkeinen v4l2_event_queue(&node->video_dev, arg); 1753*6edb685aSTomi Valkeinen } 1754*6edb685aSTomi Valkeinen break; 1755*6edb685aSTomi Valkeinen default: 1756*6edb685aSTomi Valkeinen break; 1757*6edb685aSTomi Valkeinen } 1758*6edb685aSTomi Valkeinen } 1759*6edb685aSTomi Valkeinen 1760*6edb685aSTomi Valkeinen /* cfe capture driver file operations */ 1761*6edb685aSTomi Valkeinen static const struct v4l2_file_operations cfe_fops = { 1762*6edb685aSTomi Valkeinen .owner = THIS_MODULE, 1763*6edb685aSTomi Valkeinen .open = v4l2_fh_open, 1764*6edb685aSTomi Valkeinen .release = vb2_fop_release, 1765*6edb685aSTomi Valkeinen .poll = vb2_fop_poll, 1766*6edb685aSTomi Valkeinen .unlocked_ioctl = video_ioctl2, 1767*6edb685aSTomi Valkeinen .mmap = vb2_fop_mmap, 1768*6edb685aSTomi Valkeinen }; 1769*6edb685aSTomi Valkeinen 1770*6edb685aSTomi Valkeinen static int cfe_video_link_validate(struct media_link *link) 1771*6edb685aSTomi Valkeinen { 1772*6edb685aSTomi Valkeinen struct video_device *vd = container_of(link->sink->entity, 1773*6edb685aSTomi Valkeinen struct video_device, entity); 1774*6edb685aSTomi Valkeinen struct cfe_node *node = container_of(vd, struct cfe_node, video_dev); 1775*6edb685aSTomi Valkeinen struct cfe_device *cfe = node->cfe; 1776*6edb685aSTomi Valkeinen struct v4l2_mbus_framefmt *source_fmt; 1777*6edb685aSTomi Valkeinen struct v4l2_subdev_state *state; 1778*6edb685aSTomi Valkeinen struct v4l2_subdev *source_sd; 1779*6edb685aSTomi Valkeinen int ret = 0; 1780*6edb685aSTomi Valkeinen 1781*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: [%s] link \"%s\":%u -> \"%s\":%u\n", __func__, 1782*6edb685aSTomi Valkeinen node_desc[node->id].name, 1783*6edb685aSTomi Valkeinen link->source->entity->name, link->source->index, 1784*6edb685aSTomi Valkeinen link->sink->entity->name, link->sink->index); 1785*6edb685aSTomi Valkeinen 1786*6edb685aSTomi Valkeinen if (!media_entity_remote_source_pad_unique(link->sink->entity)) { 1787*6edb685aSTomi Valkeinen cfe_err(cfe, "video node %s pad not connected\n", vd->name); 1788*6edb685aSTomi Valkeinen return -ENOTCONN; 1789*6edb685aSTomi Valkeinen } 1790*6edb685aSTomi Valkeinen 1791*6edb685aSTomi Valkeinen source_sd = media_entity_to_v4l2_subdev(link->source->entity); 1792*6edb685aSTomi Valkeinen 1793*6edb685aSTomi Valkeinen state = v4l2_subdev_lock_and_get_active_state(source_sd); 1794*6edb685aSTomi Valkeinen 1795*6edb685aSTomi Valkeinen source_fmt = v4l2_subdev_state_get_format(state, link->source->index); 1796*6edb685aSTomi Valkeinen if (!source_fmt) { 1797*6edb685aSTomi Valkeinen ret = -EINVAL; 1798*6edb685aSTomi Valkeinen goto out; 1799*6edb685aSTomi Valkeinen } 1800*6edb685aSTomi Valkeinen 1801*6edb685aSTomi Valkeinen if (is_image_output_node(node)) { 1802*6edb685aSTomi Valkeinen struct v4l2_pix_format *pix_fmt = &node->vid_fmt.fmt.pix; 1803*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 1804*6edb685aSTomi Valkeinen 1805*6edb685aSTomi Valkeinen if (source_fmt->width != pix_fmt->width || 1806*6edb685aSTomi Valkeinen source_fmt->height != pix_fmt->height) { 1807*6edb685aSTomi Valkeinen cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n", 1808*6edb685aSTomi Valkeinen pix_fmt->width, pix_fmt->height, 1809*6edb685aSTomi Valkeinen source_fmt->width, source_fmt->height); 1810*6edb685aSTomi Valkeinen ret = -EINVAL; 1811*6edb685aSTomi Valkeinen goto out; 1812*6edb685aSTomi Valkeinen } 1813*6edb685aSTomi Valkeinen 1814*6edb685aSTomi Valkeinen fmt = find_format_by_code_and_fourcc(source_fmt->code, 1815*6edb685aSTomi Valkeinen pix_fmt->pixelformat); 1816*6edb685aSTomi Valkeinen if (!fmt) { 1817*6edb685aSTomi Valkeinen cfe_err(cfe, "Format mismatch!\n"); 1818*6edb685aSTomi Valkeinen ret = -EINVAL; 1819*6edb685aSTomi Valkeinen goto out; 1820*6edb685aSTomi Valkeinen } 1821*6edb685aSTomi Valkeinen } else if (is_csi2_node(node) && is_meta_output_node(node)) { 1822*6edb685aSTomi Valkeinen struct v4l2_meta_format *meta_fmt = &node->meta_fmt.fmt.meta; 1823*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 1824*6edb685aSTomi Valkeinen 1825*6edb685aSTomi Valkeinen if (source_fmt->width != meta_fmt->width || 1826*6edb685aSTomi Valkeinen source_fmt->height != meta_fmt->height) { 1827*6edb685aSTomi Valkeinen cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n", 1828*6edb685aSTomi Valkeinen meta_fmt->width, meta_fmt->height, 1829*6edb685aSTomi Valkeinen source_fmt->width, source_fmt->height); 1830*6edb685aSTomi Valkeinen ret = -EINVAL; 1831*6edb685aSTomi Valkeinen goto out; 1832*6edb685aSTomi Valkeinen } 1833*6edb685aSTomi Valkeinen 1834*6edb685aSTomi Valkeinen fmt = find_format_by_code_and_fourcc(source_fmt->code, 1835*6edb685aSTomi Valkeinen meta_fmt->dataformat); 1836*6edb685aSTomi Valkeinen if (!fmt) { 1837*6edb685aSTomi Valkeinen cfe_err(cfe, "Format mismatch!\n"); 1838*6edb685aSTomi Valkeinen ret = -EINVAL; 1839*6edb685aSTomi Valkeinen goto out; 1840*6edb685aSTomi Valkeinen } 1841*6edb685aSTomi Valkeinen } 1842*6edb685aSTomi Valkeinen 1843*6edb685aSTomi Valkeinen out: 1844*6edb685aSTomi Valkeinen v4l2_subdev_unlock_state(state); 1845*6edb685aSTomi Valkeinen 1846*6edb685aSTomi Valkeinen return ret; 1847*6edb685aSTomi Valkeinen } 1848*6edb685aSTomi Valkeinen 1849*6edb685aSTomi Valkeinen static const struct media_entity_operations cfe_media_entity_ops = { 1850*6edb685aSTomi Valkeinen .link_validate = cfe_video_link_validate, 1851*6edb685aSTomi Valkeinen }; 1852*6edb685aSTomi Valkeinen 1853*6edb685aSTomi Valkeinen static int cfe_video_link_notify(struct media_link *link, u32 flags, 1854*6edb685aSTomi Valkeinen unsigned int notification) 1855*6edb685aSTomi Valkeinen { 1856*6edb685aSTomi Valkeinen struct media_device *mdev = link->graph_obj.mdev; 1857*6edb685aSTomi Valkeinen struct cfe_device *cfe = container_of(mdev, struct cfe_device, mdev); 1858*6edb685aSTomi Valkeinen struct media_entity *fe = &cfe->fe.sd.entity; 1859*6edb685aSTomi Valkeinen struct media_entity *csi2 = &cfe->csi2.sd.entity; 1860*6edb685aSTomi Valkeinen unsigned long lock_flags; 1861*6edb685aSTomi Valkeinen 1862*6edb685aSTomi Valkeinen if (notification != MEDIA_DEV_NOTIFY_POST_LINK_CH) 1863*6edb685aSTomi Valkeinen return 0; 1864*6edb685aSTomi Valkeinen 1865*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: %s[%u] -> %s[%u] 0x%x", __func__, 1866*6edb685aSTomi Valkeinen link->source->entity->name, link->source->index, 1867*6edb685aSTomi Valkeinen link->sink->entity->name, link->sink->index, flags); 1868*6edb685aSTomi Valkeinen 1869*6edb685aSTomi Valkeinen spin_lock_irqsave(&cfe->state_lock, lock_flags); 1870*6edb685aSTomi Valkeinen 1871*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 1872*6edb685aSTomi Valkeinen if (link->sink->entity != &cfe->node[i].video_dev.entity && 1873*6edb685aSTomi Valkeinen link->source->entity != &cfe->node[i].video_dev.entity) 1874*6edb685aSTomi Valkeinen continue; 1875*6edb685aSTomi Valkeinen 1876*6edb685aSTomi Valkeinen if (link->flags & MEDIA_LNK_FL_ENABLED) 1877*6edb685aSTomi Valkeinen set_state(cfe, NODE_ENABLED, i); 1878*6edb685aSTomi Valkeinen else 1879*6edb685aSTomi Valkeinen clear_state(cfe, NODE_ENABLED, i); 1880*6edb685aSTomi Valkeinen 1881*6edb685aSTomi Valkeinen break; 1882*6edb685aSTomi Valkeinen } 1883*6edb685aSTomi Valkeinen 1884*6edb685aSTomi Valkeinen spin_unlock_irqrestore(&cfe->state_lock, lock_flags); 1885*6edb685aSTomi Valkeinen 1886*6edb685aSTomi Valkeinen if (link->source->entity != csi2) 1887*6edb685aSTomi Valkeinen return 0; 1888*6edb685aSTomi Valkeinen if (link->sink->entity != fe) 1889*6edb685aSTomi Valkeinen return 0; 1890*6edb685aSTomi Valkeinen if (link->sink->index != 0) 1891*6edb685aSTomi Valkeinen return 0; 1892*6edb685aSTomi Valkeinen 1893*6edb685aSTomi Valkeinen cfe->fe_csi2_channel = -1; 1894*6edb685aSTomi Valkeinen if (link->flags & MEDIA_LNK_FL_ENABLED) { 1895*6edb685aSTomi Valkeinen if (link->source->index == node_desc[CSI2_CH0].link_pad) 1896*6edb685aSTomi Valkeinen cfe->fe_csi2_channel = CSI2_CH0; 1897*6edb685aSTomi Valkeinen else if (link->source->index == node_desc[CSI2_CH1].link_pad) 1898*6edb685aSTomi Valkeinen cfe->fe_csi2_channel = CSI2_CH1; 1899*6edb685aSTomi Valkeinen else if (link->source->index == node_desc[CSI2_CH2].link_pad) 1900*6edb685aSTomi Valkeinen cfe->fe_csi2_channel = CSI2_CH2; 1901*6edb685aSTomi Valkeinen else if (link->source->index == node_desc[CSI2_CH3].link_pad) 1902*6edb685aSTomi Valkeinen cfe->fe_csi2_channel = CSI2_CH3; 1903*6edb685aSTomi Valkeinen } 1904*6edb685aSTomi Valkeinen 1905*6edb685aSTomi Valkeinen if (is_fe_enabled(cfe)) 1906*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: Found CSI2:%d -> FE:0 link\n", __func__, 1907*6edb685aSTomi Valkeinen cfe->fe_csi2_channel); 1908*6edb685aSTomi Valkeinen else 1909*6edb685aSTomi Valkeinen cfe_dbg(cfe, "%s: Unable to find CSI2:x -> FE:0 link\n", 1910*6edb685aSTomi Valkeinen __func__); 1911*6edb685aSTomi Valkeinen 1912*6edb685aSTomi Valkeinen return 0; 1913*6edb685aSTomi Valkeinen } 1914*6edb685aSTomi Valkeinen 1915*6edb685aSTomi Valkeinen static const struct media_device_ops cfe_media_device_ops = { 1916*6edb685aSTomi Valkeinen .link_notify = cfe_video_link_notify, 1917*6edb685aSTomi Valkeinen }; 1918*6edb685aSTomi Valkeinen 1919*6edb685aSTomi Valkeinen static void cfe_release(struct kref *kref) 1920*6edb685aSTomi Valkeinen { 1921*6edb685aSTomi Valkeinen struct cfe_device *cfe = container_of(kref, struct cfe_device, kref); 1922*6edb685aSTomi Valkeinen 1923*6edb685aSTomi Valkeinen media_device_cleanup(&cfe->mdev); 1924*6edb685aSTomi Valkeinen 1925*6edb685aSTomi Valkeinen kfree(cfe); 1926*6edb685aSTomi Valkeinen } 1927*6edb685aSTomi Valkeinen 1928*6edb685aSTomi Valkeinen static void cfe_put(struct cfe_device *cfe) 1929*6edb685aSTomi Valkeinen { 1930*6edb685aSTomi Valkeinen kref_put(&cfe->kref, cfe_release); 1931*6edb685aSTomi Valkeinen } 1932*6edb685aSTomi Valkeinen 1933*6edb685aSTomi Valkeinen static void cfe_get(struct cfe_device *cfe) 1934*6edb685aSTomi Valkeinen { 1935*6edb685aSTomi Valkeinen kref_get(&cfe->kref); 1936*6edb685aSTomi Valkeinen } 1937*6edb685aSTomi Valkeinen 1938*6edb685aSTomi Valkeinen static void cfe_node_release(struct video_device *vdev) 1939*6edb685aSTomi Valkeinen { 1940*6edb685aSTomi Valkeinen struct cfe_node *node = video_get_drvdata(vdev); 1941*6edb685aSTomi Valkeinen 1942*6edb685aSTomi Valkeinen cfe_put(node->cfe); 1943*6edb685aSTomi Valkeinen } 1944*6edb685aSTomi Valkeinen 1945*6edb685aSTomi Valkeinen static int cfe_register_node(struct cfe_device *cfe, int id) 1946*6edb685aSTomi Valkeinen { 1947*6edb685aSTomi Valkeinen struct video_device *vdev; 1948*6edb685aSTomi Valkeinen const struct cfe_fmt *fmt; 1949*6edb685aSTomi Valkeinen struct vb2_queue *q; 1950*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[id]; 1951*6edb685aSTomi Valkeinen int ret; 1952*6edb685aSTomi Valkeinen 1953*6edb685aSTomi Valkeinen node->cfe = cfe; 1954*6edb685aSTomi Valkeinen node->id = id; 1955*6edb685aSTomi Valkeinen 1956*6edb685aSTomi Valkeinen if (node_supports_image(node)) { 1957*6edb685aSTomi Valkeinen if (node_supports_image_output(node)) 1958*6edb685aSTomi Valkeinen node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1959*6edb685aSTomi Valkeinen else 1960*6edb685aSTomi Valkeinen node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 1961*6edb685aSTomi Valkeinen 1962*6edb685aSTomi Valkeinen fmt = find_format_by_code(cfe_default_format.code); 1963*6edb685aSTomi Valkeinen if (!fmt) { 1964*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to find format code\n"); 1965*6edb685aSTomi Valkeinen return -EINVAL; 1966*6edb685aSTomi Valkeinen } 1967*6edb685aSTomi Valkeinen 1968*6edb685aSTomi Valkeinen node->vid_fmt.fmt.pix.pixelformat = fmt->fourcc; 1969*6edb685aSTomi Valkeinen v4l2_fill_pix_format(&node->vid_fmt.fmt.pix, 1970*6edb685aSTomi Valkeinen &cfe_default_format); 1971*6edb685aSTomi Valkeinen 1972*6edb685aSTomi Valkeinen ret = cfe_validate_fmt_vid_cap(node, &node->vid_fmt); 1973*6edb685aSTomi Valkeinen if (ret) 1974*6edb685aSTomi Valkeinen return ret; 1975*6edb685aSTomi Valkeinen } 1976*6edb685aSTomi Valkeinen 1977*6edb685aSTomi Valkeinen if (node_supports_meta(node)) { 1978*6edb685aSTomi Valkeinen if (node_supports_meta_output(node)) 1979*6edb685aSTomi Valkeinen node->meta_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; 1980*6edb685aSTomi Valkeinen else 1981*6edb685aSTomi Valkeinen node->meta_fmt.type = V4L2_BUF_TYPE_META_OUTPUT; 1982*6edb685aSTomi Valkeinen 1983*6edb685aSTomi Valkeinen ret = cfe_validate_fmt_meta(node, &node->meta_fmt); 1984*6edb685aSTomi Valkeinen if (ret) 1985*6edb685aSTomi Valkeinen return ret; 1986*6edb685aSTomi Valkeinen } 1987*6edb685aSTomi Valkeinen 1988*6edb685aSTomi Valkeinen mutex_init(&node->lock); 1989*6edb685aSTomi Valkeinen 1990*6edb685aSTomi Valkeinen q = &node->buffer_queue; 1991*6edb685aSTomi Valkeinen q->type = node_supports_image(node) ? node->vid_fmt.type : 1992*6edb685aSTomi Valkeinen node->meta_fmt.type; 1993*6edb685aSTomi Valkeinen q->io_modes = VB2_MMAP | VB2_DMABUF; 1994*6edb685aSTomi Valkeinen q->drv_priv = node; 1995*6edb685aSTomi Valkeinen q->ops = &cfe_video_qops; 1996*6edb685aSTomi Valkeinen q->mem_ops = &vb2_dma_contig_memops; 1997*6edb685aSTomi Valkeinen q->buf_struct_size = id == FE_CONFIG ? sizeof(struct cfe_config_buffer) 1998*6edb685aSTomi Valkeinen : sizeof(struct cfe_buffer); 1999*6edb685aSTomi Valkeinen q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 2000*6edb685aSTomi Valkeinen q->lock = &node->lock; 2001*6edb685aSTomi Valkeinen q->min_queued_buffers = 1; 2002*6edb685aSTomi Valkeinen q->dev = &cfe->pdev->dev; 2003*6edb685aSTomi Valkeinen 2004*6edb685aSTomi Valkeinen ret = vb2_queue_init(q); 2005*6edb685aSTomi Valkeinen if (ret) { 2006*6edb685aSTomi Valkeinen cfe_err(cfe, "vb2_queue_init() failed\n"); 2007*6edb685aSTomi Valkeinen return ret; 2008*6edb685aSTomi Valkeinen } 2009*6edb685aSTomi Valkeinen 2010*6edb685aSTomi Valkeinen INIT_LIST_HEAD(&node->dma_queue); 2011*6edb685aSTomi Valkeinen 2012*6edb685aSTomi Valkeinen vdev = &node->video_dev; 2013*6edb685aSTomi Valkeinen vdev->release = cfe_node_release; 2014*6edb685aSTomi Valkeinen vdev->fops = &cfe_fops; 2015*6edb685aSTomi Valkeinen vdev->ioctl_ops = &cfe_ioctl_ops; 2016*6edb685aSTomi Valkeinen vdev->entity.ops = &cfe_media_entity_ops; 2017*6edb685aSTomi Valkeinen vdev->v4l2_dev = &cfe->v4l2_dev; 2018*6edb685aSTomi Valkeinen vdev->vfl_dir = (node_supports_image_output(node) || 2019*6edb685aSTomi Valkeinen node_supports_meta_output(node)) ? 2020*6edb685aSTomi Valkeinen VFL_DIR_RX : 2021*6edb685aSTomi Valkeinen VFL_DIR_TX; 2022*6edb685aSTomi Valkeinen vdev->queue = q; 2023*6edb685aSTomi Valkeinen vdev->lock = &node->lock; 2024*6edb685aSTomi Valkeinen vdev->device_caps = node_desc[id].caps; 2025*6edb685aSTomi Valkeinen vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; 2026*6edb685aSTomi Valkeinen 2027*6edb685aSTomi Valkeinen /* Define the device names */ 2028*6edb685aSTomi Valkeinen snprintf(vdev->name, sizeof(vdev->name), "%s-%s", CFE_MODULE_NAME, 2029*6edb685aSTomi Valkeinen node_desc[id].name); 2030*6edb685aSTomi Valkeinen 2031*6edb685aSTomi Valkeinen video_set_drvdata(vdev, node); 2032*6edb685aSTomi Valkeinen node->pad.flags = node_desc[id].pad_flags; 2033*6edb685aSTomi Valkeinen media_entity_pads_init(&vdev->entity, 1, &node->pad); 2034*6edb685aSTomi Valkeinen 2035*6edb685aSTomi Valkeinen if (!node_supports_image(node)) { 2036*6edb685aSTomi Valkeinen v4l2_disable_ioctl(&node->video_dev, 2037*6edb685aSTomi Valkeinen VIDIOC_ENUM_FRAMEINTERVALS); 2038*6edb685aSTomi Valkeinen v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES); 2039*6edb685aSTomi Valkeinen } 2040*6edb685aSTomi Valkeinen 2041*6edb685aSTomi Valkeinen ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 2042*6edb685aSTomi Valkeinen if (ret) { 2043*6edb685aSTomi Valkeinen cfe_err(cfe, "Unable to register video device %s\n", 2044*6edb685aSTomi Valkeinen vdev->name); 2045*6edb685aSTomi Valkeinen return ret; 2046*6edb685aSTomi Valkeinen } 2047*6edb685aSTomi Valkeinen 2048*6edb685aSTomi Valkeinen cfe_info(cfe, "Registered [%s] node id %d as /dev/video%u\n", 2049*6edb685aSTomi Valkeinen vdev->name, id, vdev->num); 2050*6edb685aSTomi Valkeinen 2051*6edb685aSTomi Valkeinen /* 2052*6edb685aSTomi Valkeinen * Acquire a reference to cfe, which will be released when the video 2053*6edb685aSTomi Valkeinen * device will be unregistered and userspace will have closed all open 2054*6edb685aSTomi Valkeinen * file handles. 2055*6edb685aSTomi Valkeinen */ 2056*6edb685aSTomi Valkeinen cfe_get(cfe); 2057*6edb685aSTomi Valkeinen set_state(cfe, NODE_REGISTERED, id); 2058*6edb685aSTomi Valkeinen 2059*6edb685aSTomi Valkeinen return 0; 2060*6edb685aSTomi Valkeinen } 2061*6edb685aSTomi Valkeinen 2062*6edb685aSTomi Valkeinen static void cfe_unregister_nodes(struct cfe_device *cfe) 2063*6edb685aSTomi Valkeinen { 2064*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 2065*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 2066*6edb685aSTomi Valkeinen 2067*6edb685aSTomi Valkeinen if (check_state(cfe, NODE_REGISTERED, i)) { 2068*6edb685aSTomi Valkeinen clear_state(cfe, NODE_REGISTERED, i); 2069*6edb685aSTomi Valkeinen video_unregister_device(&node->video_dev); 2070*6edb685aSTomi Valkeinen } 2071*6edb685aSTomi Valkeinen } 2072*6edb685aSTomi Valkeinen } 2073*6edb685aSTomi Valkeinen 2074*6edb685aSTomi Valkeinen static int cfe_link_node_pads(struct cfe_device *cfe) 2075*6edb685aSTomi Valkeinen { 2076*6edb685aSTomi Valkeinen struct media_pad *remote_pad; 2077*6edb685aSTomi Valkeinen int ret; 2078*6edb685aSTomi Valkeinen 2079*6edb685aSTomi Valkeinen /* Source -> CSI2 */ 2080*6edb685aSTomi Valkeinen 2081*6edb685aSTomi Valkeinen ret = v4l2_create_fwnode_links_to_pad(cfe->source_sd, 2082*6edb685aSTomi Valkeinen &cfe->csi2.pad[CSI2_PAD_SINK], 2083*6edb685aSTomi Valkeinen MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); 2084*6edb685aSTomi Valkeinen 2085*6edb685aSTomi Valkeinen if (ret) { 2086*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to create links to the source: %d\n", ret); 2087*6edb685aSTomi Valkeinen return ret; 2088*6edb685aSTomi Valkeinen } 2089*6edb685aSTomi Valkeinen 2090*6edb685aSTomi Valkeinen remote_pad = media_pad_remote_pad_unique(&cfe->csi2.pad[CSI2_PAD_SINK]); 2091*6edb685aSTomi Valkeinen if (IS_ERR(remote_pad)) { 2092*6edb685aSTomi Valkeinen ret = PTR_ERR(remote_pad); 2093*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to get unique remote source pad: %d\n", 2094*6edb685aSTomi Valkeinen ret); 2095*6edb685aSTomi Valkeinen return ret; 2096*6edb685aSTomi Valkeinen } 2097*6edb685aSTomi Valkeinen 2098*6edb685aSTomi Valkeinen cfe->source_pad = remote_pad->index; 2099*6edb685aSTomi Valkeinen 2100*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { 2101*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 2102*6edb685aSTomi Valkeinen 2103*6edb685aSTomi Valkeinen if (!check_state(cfe, NODE_REGISTERED, i)) 2104*6edb685aSTomi Valkeinen continue; 2105*6edb685aSTomi Valkeinen 2106*6edb685aSTomi Valkeinen /* CSI2 channel # -> /dev/video# */ 2107*6edb685aSTomi Valkeinen ret = media_create_pad_link(&cfe->csi2.sd.entity, 2108*6edb685aSTomi Valkeinen node_desc[i].link_pad, 2109*6edb685aSTomi Valkeinen &node->video_dev.entity, 0, 0); 2110*6edb685aSTomi Valkeinen if (ret) 2111*6edb685aSTomi Valkeinen return ret; 2112*6edb685aSTomi Valkeinen 2113*6edb685aSTomi Valkeinen if (node_supports_image(node)) { 2114*6edb685aSTomi Valkeinen /* CSI2 channel # -> FE Input */ 2115*6edb685aSTomi Valkeinen ret = media_create_pad_link(&cfe->csi2.sd.entity, 2116*6edb685aSTomi Valkeinen node_desc[i].link_pad, 2117*6edb685aSTomi Valkeinen &cfe->fe.sd.entity, 2118*6edb685aSTomi Valkeinen FE_STREAM_PAD, 0); 2119*6edb685aSTomi Valkeinen if (ret) 2120*6edb685aSTomi Valkeinen return ret; 2121*6edb685aSTomi Valkeinen } 2122*6edb685aSTomi Valkeinen } 2123*6edb685aSTomi Valkeinen 2124*6edb685aSTomi Valkeinen for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { 2125*6edb685aSTomi Valkeinen struct cfe_node *node = &cfe->node[i]; 2126*6edb685aSTomi Valkeinen struct media_entity *src, *dst; 2127*6edb685aSTomi Valkeinen unsigned int src_pad, dst_pad; 2128*6edb685aSTomi Valkeinen 2129*6edb685aSTomi Valkeinen if (node_desc[i].pad_flags & MEDIA_PAD_FL_SINK) { 2130*6edb685aSTomi Valkeinen /* FE -> /dev/video# */ 2131*6edb685aSTomi Valkeinen src = &cfe->fe.sd.entity; 2132*6edb685aSTomi Valkeinen src_pad = node_desc[i].link_pad; 2133*6edb685aSTomi Valkeinen dst = &node->video_dev.entity; 2134*6edb685aSTomi Valkeinen dst_pad = 0; 2135*6edb685aSTomi Valkeinen } else { 2136*6edb685aSTomi Valkeinen /* /dev/video# -> FE */ 2137*6edb685aSTomi Valkeinen dst = &cfe->fe.sd.entity; 2138*6edb685aSTomi Valkeinen dst_pad = node_desc[i].link_pad; 2139*6edb685aSTomi Valkeinen src = &node->video_dev.entity; 2140*6edb685aSTomi Valkeinen src_pad = 0; 2141*6edb685aSTomi Valkeinen } 2142*6edb685aSTomi Valkeinen 2143*6edb685aSTomi Valkeinen ret = media_create_pad_link(src, src_pad, dst, dst_pad, 0); 2144*6edb685aSTomi Valkeinen if (ret) 2145*6edb685aSTomi Valkeinen return ret; 2146*6edb685aSTomi Valkeinen } 2147*6edb685aSTomi Valkeinen 2148*6edb685aSTomi Valkeinen return 0; 2149*6edb685aSTomi Valkeinen } 2150*6edb685aSTomi Valkeinen 2151*6edb685aSTomi Valkeinen static int cfe_probe_complete(struct cfe_device *cfe) 2152*6edb685aSTomi Valkeinen { 2153*6edb685aSTomi Valkeinen int ret; 2154*6edb685aSTomi Valkeinen 2155*6edb685aSTomi Valkeinen cfe->v4l2_dev.notify = cfe_notify; 2156*6edb685aSTomi Valkeinen 2157*6edb685aSTomi Valkeinen for (unsigned int i = 0; i < NUM_NODES; i++) { 2158*6edb685aSTomi Valkeinen ret = cfe_register_node(cfe, i); 2159*6edb685aSTomi Valkeinen if (ret) { 2160*6edb685aSTomi Valkeinen cfe_err(cfe, "Unable to register video node %u.\n", i); 2161*6edb685aSTomi Valkeinen goto unregister; 2162*6edb685aSTomi Valkeinen } 2163*6edb685aSTomi Valkeinen } 2164*6edb685aSTomi Valkeinen 2165*6edb685aSTomi Valkeinen ret = cfe_link_node_pads(cfe); 2166*6edb685aSTomi Valkeinen if (ret) { 2167*6edb685aSTomi Valkeinen cfe_err(cfe, "Unable to link node pads.\n"); 2168*6edb685aSTomi Valkeinen goto unregister; 2169*6edb685aSTomi Valkeinen } 2170*6edb685aSTomi Valkeinen 2171*6edb685aSTomi Valkeinen ret = v4l2_device_register_subdev_nodes(&cfe->v4l2_dev); 2172*6edb685aSTomi Valkeinen if (ret) { 2173*6edb685aSTomi Valkeinen cfe_err(cfe, "Unable to register subdev nodes.\n"); 2174*6edb685aSTomi Valkeinen goto unregister; 2175*6edb685aSTomi Valkeinen } 2176*6edb685aSTomi Valkeinen 2177*6edb685aSTomi Valkeinen return 0; 2178*6edb685aSTomi Valkeinen 2179*6edb685aSTomi Valkeinen unregister: 2180*6edb685aSTomi Valkeinen cfe_unregister_nodes(cfe); 2181*6edb685aSTomi Valkeinen return ret; 2182*6edb685aSTomi Valkeinen } 2183*6edb685aSTomi Valkeinen 2184*6edb685aSTomi Valkeinen static int cfe_async_bound(struct v4l2_async_notifier *notifier, 2185*6edb685aSTomi Valkeinen struct v4l2_subdev *subdev, 2186*6edb685aSTomi Valkeinen struct v4l2_async_connection *asd) 2187*6edb685aSTomi Valkeinen { 2188*6edb685aSTomi Valkeinen struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); 2189*6edb685aSTomi Valkeinen 2190*6edb685aSTomi Valkeinen if (cfe->source_sd) { 2191*6edb685aSTomi Valkeinen cfe_err(cfe, "Rejecting subdev %s (Already set!!)", 2192*6edb685aSTomi Valkeinen subdev->name); 2193*6edb685aSTomi Valkeinen return 0; 2194*6edb685aSTomi Valkeinen } 2195*6edb685aSTomi Valkeinen 2196*6edb685aSTomi Valkeinen cfe->source_sd = subdev; 2197*6edb685aSTomi Valkeinen 2198*6edb685aSTomi Valkeinen cfe_dbg(cfe, "Using source %s for capture\n", subdev->name); 2199*6edb685aSTomi Valkeinen 2200*6edb685aSTomi Valkeinen return 0; 2201*6edb685aSTomi Valkeinen } 2202*6edb685aSTomi Valkeinen 2203*6edb685aSTomi Valkeinen static int cfe_async_complete(struct v4l2_async_notifier *notifier) 2204*6edb685aSTomi Valkeinen { 2205*6edb685aSTomi Valkeinen struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); 2206*6edb685aSTomi Valkeinen 2207*6edb685aSTomi Valkeinen return cfe_probe_complete(cfe); 2208*6edb685aSTomi Valkeinen } 2209*6edb685aSTomi Valkeinen 2210*6edb685aSTomi Valkeinen static const struct v4l2_async_notifier_operations cfe_async_ops = { 2211*6edb685aSTomi Valkeinen .bound = cfe_async_bound, 2212*6edb685aSTomi Valkeinen .complete = cfe_async_complete, 2213*6edb685aSTomi Valkeinen }; 2214*6edb685aSTomi Valkeinen 2215*6edb685aSTomi Valkeinen static int cfe_register_async_nf(struct cfe_device *cfe) 2216*6edb685aSTomi Valkeinen { 2217*6edb685aSTomi Valkeinen struct platform_device *pdev = cfe->pdev; 2218*6edb685aSTomi Valkeinen struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; 2219*6edb685aSTomi Valkeinen struct fwnode_handle *local_ep_fwnode; 2220*6edb685aSTomi Valkeinen struct v4l2_async_connection *asd; 2221*6edb685aSTomi Valkeinen int ret; 2222*6edb685aSTomi Valkeinen 2223*6edb685aSTomi Valkeinen local_ep_fwnode = fwnode_graph_get_endpoint_by_id(pdev->dev.fwnode, 0, 2224*6edb685aSTomi Valkeinen 0, 0); 2225*6edb685aSTomi Valkeinen if (!local_ep_fwnode) { 2226*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to find local endpoint fwnode\n"); 2227*6edb685aSTomi Valkeinen return -ENODEV; 2228*6edb685aSTomi Valkeinen } 2229*6edb685aSTomi Valkeinen 2230*6edb685aSTomi Valkeinen /* Parse the local endpoint and validate its configuration. */ 2231*6edb685aSTomi Valkeinen ret = v4l2_fwnode_endpoint_parse(local_ep_fwnode, &ep); 2232*6edb685aSTomi Valkeinen if (ret) { 2233*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to find remote endpoint fwnode\n"); 2234*6edb685aSTomi Valkeinen goto err_put_local_fwnode; 2235*6edb685aSTomi Valkeinen } 2236*6edb685aSTomi Valkeinen 2237*6edb685aSTomi Valkeinen for (unsigned int lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; 2238*6edb685aSTomi Valkeinen lane++) { 2239*6edb685aSTomi Valkeinen if (ep.bus.mipi_csi2.data_lanes[lane] != lane + 1) { 2240*6edb685aSTomi Valkeinen cfe_err(cfe, "Data lanes reordering not supported\n"); 2241*6edb685aSTomi Valkeinen ret = -EINVAL; 2242*6edb685aSTomi Valkeinen goto err_put_local_fwnode; 2243*6edb685aSTomi Valkeinen } 2244*6edb685aSTomi Valkeinen } 2245*6edb685aSTomi Valkeinen 2246*6edb685aSTomi Valkeinen cfe->csi2.dphy.max_lanes = ep.bus.mipi_csi2.num_data_lanes; 2247*6edb685aSTomi Valkeinen cfe->csi2.bus_flags = ep.bus.mipi_csi2.flags; 2248*6edb685aSTomi Valkeinen 2249*6edb685aSTomi Valkeinen /* Initialize and register the async notifier. */ 2250*6edb685aSTomi Valkeinen v4l2_async_nf_init(&cfe->notifier, &cfe->v4l2_dev); 2251*6edb685aSTomi Valkeinen cfe->notifier.ops = &cfe_async_ops; 2252*6edb685aSTomi Valkeinen 2253*6edb685aSTomi Valkeinen asd = v4l2_async_nf_add_fwnode_remote(&cfe->notifier, local_ep_fwnode, 2254*6edb685aSTomi Valkeinen struct v4l2_async_connection); 2255*6edb685aSTomi Valkeinen if (IS_ERR(asd)) { 2256*6edb685aSTomi Valkeinen ret = PTR_ERR(asd); 2257*6edb685aSTomi Valkeinen cfe_err(cfe, "Error adding subdevice: %d\n", ret); 2258*6edb685aSTomi Valkeinen goto err_put_local_fwnode; 2259*6edb685aSTomi Valkeinen } 2260*6edb685aSTomi Valkeinen 2261*6edb685aSTomi Valkeinen ret = v4l2_async_nf_register(&cfe->notifier); 2262*6edb685aSTomi Valkeinen if (ret) { 2263*6edb685aSTomi Valkeinen cfe_err(cfe, "Error registering async notifier: %d\n", ret); 2264*6edb685aSTomi Valkeinen goto err_nf_cleanup; 2265*6edb685aSTomi Valkeinen } 2266*6edb685aSTomi Valkeinen 2267*6edb685aSTomi Valkeinen fwnode_handle_put(local_ep_fwnode); 2268*6edb685aSTomi Valkeinen 2269*6edb685aSTomi Valkeinen return 0; 2270*6edb685aSTomi Valkeinen 2271*6edb685aSTomi Valkeinen err_nf_cleanup: 2272*6edb685aSTomi Valkeinen v4l2_async_nf_cleanup(&cfe->notifier); 2273*6edb685aSTomi Valkeinen err_put_local_fwnode: 2274*6edb685aSTomi Valkeinen fwnode_handle_put(local_ep_fwnode); 2275*6edb685aSTomi Valkeinen 2276*6edb685aSTomi Valkeinen return ret; 2277*6edb685aSTomi Valkeinen } 2278*6edb685aSTomi Valkeinen 2279*6edb685aSTomi Valkeinen static int cfe_probe(struct platform_device *pdev) 2280*6edb685aSTomi Valkeinen { 2281*6edb685aSTomi Valkeinen struct cfe_device *cfe; 2282*6edb685aSTomi Valkeinen char debugfs_name[32]; 2283*6edb685aSTomi Valkeinen int ret; 2284*6edb685aSTomi Valkeinen 2285*6edb685aSTomi Valkeinen cfe = kzalloc(sizeof(*cfe), GFP_KERNEL); 2286*6edb685aSTomi Valkeinen if (!cfe) 2287*6edb685aSTomi Valkeinen return -ENOMEM; 2288*6edb685aSTomi Valkeinen 2289*6edb685aSTomi Valkeinen platform_set_drvdata(pdev, cfe); 2290*6edb685aSTomi Valkeinen 2291*6edb685aSTomi Valkeinen kref_init(&cfe->kref); 2292*6edb685aSTomi Valkeinen cfe->pdev = pdev; 2293*6edb685aSTomi Valkeinen cfe->fe_csi2_channel = -1; 2294*6edb685aSTomi Valkeinen spin_lock_init(&cfe->state_lock); 2295*6edb685aSTomi Valkeinen 2296*6edb685aSTomi Valkeinen cfe->csi2.base = devm_platform_ioremap_resource(pdev, 0); 2297*6edb685aSTomi Valkeinen if (IS_ERR(cfe->csi2.base)) { 2298*6edb685aSTomi Valkeinen dev_err(&pdev->dev, "Failed to get dma io block\n"); 2299*6edb685aSTomi Valkeinen ret = PTR_ERR(cfe->csi2.base); 2300*6edb685aSTomi Valkeinen goto err_cfe_put; 2301*6edb685aSTomi Valkeinen } 2302*6edb685aSTomi Valkeinen 2303*6edb685aSTomi Valkeinen cfe->csi2.dphy.base = devm_platform_ioremap_resource(pdev, 1); 2304*6edb685aSTomi Valkeinen if (IS_ERR(cfe->csi2.dphy.base)) { 2305*6edb685aSTomi Valkeinen dev_err(&pdev->dev, "Failed to get host io block\n"); 2306*6edb685aSTomi Valkeinen ret = PTR_ERR(cfe->csi2.dphy.base); 2307*6edb685aSTomi Valkeinen goto err_cfe_put; 2308*6edb685aSTomi Valkeinen } 2309*6edb685aSTomi Valkeinen 2310*6edb685aSTomi Valkeinen cfe->mipi_cfg_base = devm_platform_ioremap_resource(pdev, 2); 2311*6edb685aSTomi Valkeinen if (IS_ERR(cfe->mipi_cfg_base)) { 2312*6edb685aSTomi Valkeinen dev_err(&pdev->dev, "Failed to get mipi cfg io block\n"); 2313*6edb685aSTomi Valkeinen ret = PTR_ERR(cfe->mipi_cfg_base); 2314*6edb685aSTomi Valkeinen goto err_cfe_put; 2315*6edb685aSTomi Valkeinen } 2316*6edb685aSTomi Valkeinen 2317*6edb685aSTomi Valkeinen cfe->fe.base = devm_platform_ioremap_resource(pdev, 3); 2318*6edb685aSTomi Valkeinen if (IS_ERR(cfe->fe.base)) { 2319*6edb685aSTomi Valkeinen dev_err(&pdev->dev, "Failed to get pisp fe io block\n"); 2320*6edb685aSTomi Valkeinen ret = PTR_ERR(cfe->fe.base); 2321*6edb685aSTomi Valkeinen goto err_cfe_put; 2322*6edb685aSTomi Valkeinen } 2323*6edb685aSTomi Valkeinen 2324*6edb685aSTomi Valkeinen ret = platform_get_irq(pdev, 0); 2325*6edb685aSTomi Valkeinen if (ret <= 0) { 2326*6edb685aSTomi Valkeinen dev_err(&pdev->dev, "No IRQ resource\n"); 2327*6edb685aSTomi Valkeinen ret = -EINVAL; 2328*6edb685aSTomi Valkeinen goto err_cfe_put; 2329*6edb685aSTomi Valkeinen } 2330*6edb685aSTomi Valkeinen 2331*6edb685aSTomi Valkeinen ret = devm_request_irq(&pdev->dev, ret, cfe_isr, 0, "rp1-cfe", cfe); 2332*6edb685aSTomi Valkeinen if (ret) { 2333*6edb685aSTomi Valkeinen dev_err(&pdev->dev, "Unable to request interrupt\n"); 2334*6edb685aSTomi Valkeinen ret = -EINVAL; 2335*6edb685aSTomi Valkeinen goto err_cfe_put; 2336*6edb685aSTomi Valkeinen } 2337*6edb685aSTomi Valkeinen 2338*6edb685aSTomi Valkeinen ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 2339*6edb685aSTomi Valkeinen if (ret) { 2340*6edb685aSTomi Valkeinen dev_err(&pdev->dev, "DMA enable failed\n"); 2341*6edb685aSTomi Valkeinen goto err_cfe_put; 2342*6edb685aSTomi Valkeinen } 2343*6edb685aSTomi Valkeinen 2344*6edb685aSTomi Valkeinen /* TODO: Enable clock only when running. */ 2345*6edb685aSTomi Valkeinen cfe->clk = devm_clk_get(&pdev->dev, NULL); 2346*6edb685aSTomi Valkeinen if (IS_ERR(cfe->clk)) 2347*6edb685aSTomi Valkeinen return dev_err_probe(&pdev->dev, PTR_ERR(cfe->clk), 2348*6edb685aSTomi Valkeinen "clock not found\n"); 2349*6edb685aSTomi Valkeinen 2350*6edb685aSTomi Valkeinen cfe->mdev.dev = &pdev->dev; 2351*6edb685aSTomi Valkeinen cfe->mdev.ops = &cfe_media_device_ops; 2352*6edb685aSTomi Valkeinen strscpy(cfe->mdev.model, CFE_MODULE_NAME, sizeof(cfe->mdev.model)); 2353*6edb685aSTomi Valkeinen strscpy(cfe->mdev.serial, "", sizeof(cfe->mdev.serial)); 2354*6edb685aSTomi Valkeinen snprintf(cfe->mdev.bus_info, sizeof(cfe->mdev.bus_info), "platform:%s", 2355*6edb685aSTomi Valkeinen dev_name(&pdev->dev)); 2356*6edb685aSTomi Valkeinen 2357*6edb685aSTomi Valkeinen media_device_init(&cfe->mdev); 2358*6edb685aSTomi Valkeinen 2359*6edb685aSTomi Valkeinen cfe->v4l2_dev.mdev = &cfe->mdev; 2360*6edb685aSTomi Valkeinen 2361*6edb685aSTomi Valkeinen ret = v4l2_device_register(&pdev->dev, &cfe->v4l2_dev); 2362*6edb685aSTomi Valkeinen if (ret) { 2363*6edb685aSTomi Valkeinen cfe_err(cfe, "Unable to register v4l2 device.\n"); 2364*6edb685aSTomi Valkeinen goto err_cfe_put; 2365*6edb685aSTomi Valkeinen } 2366*6edb685aSTomi Valkeinen 2367*6edb685aSTomi Valkeinen snprintf(debugfs_name, sizeof(debugfs_name), "rp1-cfe:%s", 2368*6edb685aSTomi Valkeinen dev_name(&pdev->dev)); 2369*6edb685aSTomi Valkeinen cfe->debugfs = debugfs_create_dir(debugfs_name, NULL); 2370*6edb685aSTomi Valkeinen debugfs_create_file("regs", 0440, cfe->debugfs, cfe, 2371*6edb685aSTomi Valkeinen &mipi_cfg_regs_fops); 2372*6edb685aSTomi Valkeinen 2373*6edb685aSTomi Valkeinen /* Enable the block power domain */ 2374*6edb685aSTomi Valkeinen pm_runtime_enable(&pdev->dev); 2375*6edb685aSTomi Valkeinen 2376*6edb685aSTomi Valkeinen ret = pm_runtime_resume_and_get(&cfe->pdev->dev); 2377*6edb685aSTomi Valkeinen if (ret) 2378*6edb685aSTomi Valkeinen goto err_runtime_disable; 2379*6edb685aSTomi Valkeinen 2380*6edb685aSTomi Valkeinen cfe->csi2.v4l2_dev = &cfe->v4l2_dev; 2381*6edb685aSTomi Valkeinen ret = csi2_init(&cfe->csi2, cfe->debugfs); 2382*6edb685aSTomi Valkeinen if (ret) { 2383*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to init csi2 (%d)\n", ret); 2384*6edb685aSTomi Valkeinen goto err_runtime_put; 2385*6edb685aSTomi Valkeinen } 2386*6edb685aSTomi Valkeinen 2387*6edb685aSTomi Valkeinen cfe->fe.v4l2_dev = &cfe->v4l2_dev; 2388*6edb685aSTomi Valkeinen ret = pisp_fe_init(&cfe->fe, cfe->debugfs); 2389*6edb685aSTomi Valkeinen if (ret) { 2390*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to init pisp fe (%d)\n", ret); 2391*6edb685aSTomi Valkeinen goto err_csi2_uninit; 2392*6edb685aSTomi Valkeinen } 2393*6edb685aSTomi Valkeinen 2394*6edb685aSTomi Valkeinen cfe->mdev.hw_revision = cfe->fe.hw_revision; 2395*6edb685aSTomi Valkeinen ret = media_device_register(&cfe->mdev); 2396*6edb685aSTomi Valkeinen if (ret < 0) { 2397*6edb685aSTomi Valkeinen cfe_err(cfe, "Unable to register media-controller device.\n"); 2398*6edb685aSTomi Valkeinen goto err_pisp_fe_uninit; 2399*6edb685aSTomi Valkeinen } 2400*6edb685aSTomi Valkeinen 2401*6edb685aSTomi Valkeinen ret = cfe_register_async_nf(cfe); 2402*6edb685aSTomi Valkeinen if (ret) { 2403*6edb685aSTomi Valkeinen cfe_err(cfe, "Failed to connect subdevs\n"); 2404*6edb685aSTomi Valkeinen goto err_media_unregister; 2405*6edb685aSTomi Valkeinen } 2406*6edb685aSTomi Valkeinen 2407*6edb685aSTomi Valkeinen pm_runtime_put(&cfe->pdev->dev); 2408*6edb685aSTomi Valkeinen 2409*6edb685aSTomi Valkeinen return 0; 2410*6edb685aSTomi Valkeinen 2411*6edb685aSTomi Valkeinen err_media_unregister: 2412*6edb685aSTomi Valkeinen media_device_unregister(&cfe->mdev); 2413*6edb685aSTomi Valkeinen err_pisp_fe_uninit: 2414*6edb685aSTomi Valkeinen pisp_fe_uninit(&cfe->fe); 2415*6edb685aSTomi Valkeinen err_csi2_uninit: 2416*6edb685aSTomi Valkeinen csi2_uninit(&cfe->csi2); 2417*6edb685aSTomi Valkeinen err_runtime_put: 2418*6edb685aSTomi Valkeinen pm_runtime_put(&cfe->pdev->dev); 2419*6edb685aSTomi Valkeinen err_runtime_disable: 2420*6edb685aSTomi Valkeinen pm_runtime_disable(&pdev->dev); 2421*6edb685aSTomi Valkeinen debugfs_remove(cfe->debugfs); 2422*6edb685aSTomi Valkeinen v4l2_device_unregister(&cfe->v4l2_dev); 2423*6edb685aSTomi Valkeinen err_cfe_put: 2424*6edb685aSTomi Valkeinen cfe_put(cfe); 2425*6edb685aSTomi Valkeinen 2426*6edb685aSTomi Valkeinen return ret; 2427*6edb685aSTomi Valkeinen } 2428*6edb685aSTomi Valkeinen 2429*6edb685aSTomi Valkeinen static void cfe_remove(struct platform_device *pdev) 2430*6edb685aSTomi Valkeinen { 2431*6edb685aSTomi Valkeinen struct cfe_device *cfe = platform_get_drvdata(pdev); 2432*6edb685aSTomi Valkeinen 2433*6edb685aSTomi Valkeinen debugfs_remove(cfe->debugfs); 2434*6edb685aSTomi Valkeinen 2435*6edb685aSTomi Valkeinen v4l2_async_nf_unregister(&cfe->notifier); 2436*6edb685aSTomi Valkeinen v4l2_async_nf_cleanup(&cfe->notifier); 2437*6edb685aSTomi Valkeinen 2438*6edb685aSTomi Valkeinen media_device_unregister(&cfe->mdev); 2439*6edb685aSTomi Valkeinen cfe_unregister_nodes(cfe); 2440*6edb685aSTomi Valkeinen 2441*6edb685aSTomi Valkeinen pisp_fe_uninit(&cfe->fe); 2442*6edb685aSTomi Valkeinen csi2_uninit(&cfe->csi2); 2443*6edb685aSTomi Valkeinen 2444*6edb685aSTomi Valkeinen pm_runtime_disable(&pdev->dev); 2445*6edb685aSTomi Valkeinen 2446*6edb685aSTomi Valkeinen v4l2_device_unregister(&cfe->v4l2_dev); 2447*6edb685aSTomi Valkeinen 2448*6edb685aSTomi Valkeinen cfe_put(cfe); 2449*6edb685aSTomi Valkeinen } 2450*6edb685aSTomi Valkeinen 2451*6edb685aSTomi Valkeinen static int cfe_runtime_suspend(struct device *dev) 2452*6edb685aSTomi Valkeinen { 2453*6edb685aSTomi Valkeinen struct platform_device *pdev = to_platform_device(dev); 2454*6edb685aSTomi Valkeinen struct cfe_device *cfe = platform_get_drvdata(pdev); 2455*6edb685aSTomi Valkeinen 2456*6edb685aSTomi Valkeinen clk_disable_unprepare(cfe->clk); 2457*6edb685aSTomi Valkeinen 2458*6edb685aSTomi Valkeinen return 0; 2459*6edb685aSTomi Valkeinen } 2460*6edb685aSTomi Valkeinen 2461*6edb685aSTomi Valkeinen static int cfe_runtime_resume(struct device *dev) 2462*6edb685aSTomi Valkeinen { 2463*6edb685aSTomi Valkeinen struct platform_device *pdev = to_platform_device(dev); 2464*6edb685aSTomi Valkeinen struct cfe_device *cfe = platform_get_drvdata(pdev); 2465*6edb685aSTomi Valkeinen int ret; 2466*6edb685aSTomi Valkeinen 2467*6edb685aSTomi Valkeinen ret = clk_prepare_enable(cfe->clk); 2468*6edb685aSTomi Valkeinen if (ret) { 2469*6edb685aSTomi Valkeinen dev_err(dev, "Unable to enable clock\n"); 2470*6edb685aSTomi Valkeinen return ret; 2471*6edb685aSTomi Valkeinen } 2472*6edb685aSTomi Valkeinen 2473*6edb685aSTomi Valkeinen return 0; 2474*6edb685aSTomi Valkeinen } 2475*6edb685aSTomi Valkeinen 2476*6edb685aSTomi Valkeinen static const struct dev_pm_ops cfe_pm_ops = { 2477*6edb685aSTomi Valkeinen SET_RUNTIME_PM_OPS(cfe_runtime_suspend, cfe_runtime_resume, NULL) 2478*6edb685aSTomi Valkeinen SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 2479*6edb685aSTomi Valkeinen pm_runtime_force_resume) 2480*6edb685aSTomi Valkeinen }; 2481*6edb685aSTomi Valkeinen 2482*6edb685aSTomi Valkeinen static const struct of_device_id cfe_of_match[] = { 2483*6edb685aSTomi Valkeinen { .compatible = "raspberrypi,rp1-cfe" }, 2484*6edb685aSTomi Valkeinen { /* sentinel */ }, 2485*6edb685aSTomi Valkeinen }; 2486*6edb685aSTomi Valkeinen MODULE_DEVICE_TABLE(of, cfe_of_match); 2487*6edb685aSTomi Valkeinen 2488*6edb685aSTomi Valkeinen static struct platform_driver cfe_driver = { 2489*6edb685aSTomi Valkeinen .probe = cfe_probe, 2490*6edb685aSTomi Valkeinen .remove = cfe_remove, 2491*6edb685aSTomi Valkeinen .driver = { 2492*6edb685aSTomi Valkeinen .name = CFE_MODULE_NAME, 2493*6edb685aSTomi Valkeinen .of_match_table = cfe_of_match, 2494*6edb685aSTomi Valkeinen .pm = &cfe_pm_ops, 2495*6edb685aSTomi Valkeinen }, 2496*6edb685aSTomi Valkeinen }; 2497*6edb685aSTomi Valkeinen 2498*6edb685aSTomi Valkeinen module_platform_driver(cfe_driver); 2499*6edb685aSTomi Valkeinen 2500*6edb685aSTomi Valkeinen MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>"); 2501*6edb685aSTomi Valkeinen MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>"); 2502*6edb685aSTomi Valkeinen MODULE_DESCRIPTION("Raspberry Pi RP1 Camera Front End driver"); 2503*6edb685aSTomi Valkeinen MODULE_LICENSE("GPL"); 2504*6edb685aSTomi Valkeinen MODULE_VERSION(CFE_VERSION); 2505