1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * vsp1_iif.c -- R-Car VSP1 IIF (ISP Interface) 4 * 5 * Copyright (C) 2025 Ideas On Board Oy 6 * Copyright (C) 2025 Renesas Corporation 7 */ 8 9 #include "vsp1.h" 10 #include "vsp1_dl.h" 11 #include "vsp1_iif.h" 12 13 #define IIF_MIN_WIDTH 128U 14 #define IIF_MIN_HEIGHT 32U 15 #define IIF_MAX_WIDTH 5120U 16 #define IIF_MAX_HEIGHT 4096U 17 18 /* ----------------------------------------------------------------------------- 19 * Device Access 20 */ 21 22 static inline void vsp1_iif_write(struct vsp1_dl_body *dlb, u32 reg, u32 data) 23 { 24 vsp1_dl_body_write(dlb, reg, data); 25 } 26 27 /* ----------------------------------------------------------------------------- 28 * V4L2 Subdevice Operations 29 */ 30 31 static const unsigned int iif_codes[] = { 32 MEDIA_BUS_FMT_Y8_1X8, 33 MEDIA_BUS_FMT_Y10_1X10, 34 MEDIA_BUS_FMT_Y12_1X12, 35 MEDIA_BUS_FMT_Y16_1X16, 36 MEDIA_BUS_FMT_METADATA_FIXED 37 }; 38 39 static int iif_enum_mbus_code(struct v4l2_subdev *subdev, 40 struct v4l2_subdev_state *sd_state, 41 struct v4l2_subdev_mbus_code_enum *code) 42 { 43 return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, iif_codes, 44 ARRAY_SIZE(iif_codes)); 45 } 46 47 static int iif_enum_frame_size(struct v4l2_subdev *subdev, 48 struct v4l2_subdev_state *sd_state, 49 struct v4l2_subdev_frame_size_enum *fse) 50 { 51 return vsp1_subdev_enum_frame_size(subdev, sd_state, fse, 52 IIF_MIN_WIDTH, IIF_MIN_HEIGHT, 53 IIF_MAX_WIDTH, IIF_MAX_HEIGHT); 54 } 55 56 static int iif_set_format(struct v4l2_subdev *subdev, 57 struct v4l2_subdev_state *sd_state, 58 struct v4l2_subdev_format *fmt) 59 { 60 return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, iif_codes, 61 ARRAY_SIZE(iif_codes), 62 IIF_MIN_WIDTH, IIF_MIN_HEIGHT, 63 IIF_MAX_WIDTH, IIF_MAX_HEIGHT); 64 } 65 66 static const struct v4l2_subdev_pad_ops iif_pad_ops = { 67 .enum_mbus_code = iif_enum_mbus_code, 68 .enum_frame_size = iif_enum_frame_size, 69 .get_fmt = vsp1_subdev_get_pad_format, 70 .set_fmt = iif_set_format, 71 }; 72 73 static const struct v4l2_subdev_ops iif_ops = { 74 .pad = &iif_pad_ops, 75 }; 76 77 /* ----------------------------------------------------------------------------- 78 * VSP1 Entity Operations 79 */ 80 81 static void iif_configure_stream(struct vsp1_entity *entity, 82 struct v4l2_subdev_state *state, 83 struct vsp1_pipeline *pipe, 84 struct vsp1_dl_list *dl, 85 struct vsp1_dl_body *dlb) 86 { 87 vsp1_iif_write(dlb, VI6_IIF_CTRL, VI6_IIF_CTRL_CTRL); 88 } 89 90 static const struct vsp1_entity_operations iif_entity_ops = { 91 .configure_stream = iif_configure_stream, 92 }; 93 94 /* ----------------------------------------------------------------------------- 95 * Initialization and Cleanup 96 */ 97 98 struct vsp1_iif *vsp1_iif_create(struct vsp1_device *vsp1) 99 { 100 struct vsp1_iif *iif; 101 int ret; 102 103 iif = devm_kzalloc(vsp1->dev, sizeof(*iif), GFP_KERNEL); 104 if (!iif) 105 return ERR_PTR(-ENOMEM); 106 107 iif->entity.ops = &iif_entity_ops; 108 iif->entity.type = VSP1_ENTITY_IIF; 109 110 /* 111 * The IIF is never exposed to userspace, but media entity registration 112 * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to 113 * avoid triggering a WARN_ON(), the value won't be seen anywhere. 114 */ 115 ret = vsp1_entity_init(vsp1, &iif->entity, "iif", 3, &iif_ops, 116 MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); 117 if (ret < 0) 118 return ERR_PTR(ret); 119 120 return iif; 121 } 122