LCOV - code coverage report
Current view: top level - ipu4 - ipu6-isys-subdev.c (source / functions) Coverage Total Hit
Test: ipu4.info Lines: 38.9 % 131 51
Test Date: 2026-05-12 04:57:36 Functions: 50.0 % 14 7

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-only
       2              : /*
       3              :  * Copyright (C) 2013--2024 Intel Corporation
       4              :  */
       5              : 
       6              : #include <linux/bug.h>
       7              : #include <linux/device.h>
       8              : #include <linux/minmax.h>
       9              : 
      10              : #include <media/media-entity.h>
      11              : #include <media/mipi-csi2.h>
      12              : #include <media/v4l2-ctrls.h>
      13              : #include <media/v4l2-subdev.h>
      14              : 
      15              : #include "ipu6-bus.h"
      16              : #include "ipu6-isys.h"
      17              : #include "ipu6-isys-subdev.h"
      18              : 
      19              : #include "ipu4-compat.h"
      20              : 
      21            0 : unsigned int ipu6_isys_mbus_code_to_bpp(u32 code)
      22              : {
      23            0 :         switch (code) {
      24              :         case MEDIA_BUS_FMT_RGB888_1X24:
      25              :         case MEDIA_BUS_FMT_META_24:
      26              :                 return 24;
      27            0 :         case MEDIA_BUS_FMT_RGB565_1X16:
      28              :         case MEDIA_BUS_FMT_UYVY8_1X16:
      29              :         case MEDIA_BUS_FMT_YUYV8_1X16:
      30              :         case MEDIA_BUS_FMT_Y16_1X16:
      31              :         case MEDIA_BUS_FMT_META_16:
      32            0 :                 return 16;
      33            0 :         case MEDIA_BUS_FMT_SBGGR12_1X12:
      34              :         case MEDIA_BUS_FMT_SGBRG12_1X12:
      35              :         case MEDIA_BUS_FMT_SGRBG12_1X12:
      36              :         case MEDIA_BUS_FMT_SRGGB12_1X12:
      37              :         case MEDIA_BUS_FMT_Y12_1X12:
      38              :         case MEDIA_BUS_FMT_META_12:
      39            0 :                 return 12;
      40            0 :         case MEDIA_BUS_FMT_SBGGR10_1X10:
      41              :         case MEDIA_BUS_FMT_SGBRG10_1X10:
      42              :         case MEDIA_BUS_FMT_SGRBG10_1X10:
      43              :         case MEDIA_BUS_FMT_SRGGB10_1X10:
      44              :         case MEDIA_BUS_FMT_Y10_1X10:
      45              :         case MEDIA_BUS_FMT_META_10:
      46            0 :                 return 10;
      47              :         case MEDIA_BUS_FMT_SBGGR8_1X8:
      48              :         case MEDIA_BUS_FMT_SGBRG8_1X8:
      49              :         case MEDIA_BUS_FMT_SGRBG8_1X8:
      50              :         case MEDIA_BUS_FMT_SRGGB8_1X8:
      51              :         case MEDIA_BUS_FMT_Y8_1X8:
      52              :         case MEDIA_BUS_FMT_META_8:
      53              :                 return 8;
      54              :         default:
      55            0 :                 WARN_ON(1);
      56            0 :                 return 8;
      57              :         }
      58              : }
      59              : 
      60            1 : unsigned int ipu6_isys_mbus_code_to_mipi(u32 code)
      61              : {
      62            1 :         switch (code) {
      63              :         case MEDIA_BUS_FMT_RGB565_1X16:
      64              :                 return MIPI_CSI2_DT_RGB565;
      65            1 :         case MEDIA_BUS_FMT_RGB888_1X24:
      66            1 :                 return MIPI_CSI2_DT_RGB888;
      67            0 :         case MEDIA_BUS_FMT_UYVY8_1X16:
      68              :         case MEDIA_BUS_FMT_YUYV8_1X16:
      69            0 :                 return MIPI_CSI2_DT_YUV422_8B;
      70            0 :         case MEDIA_BUS_FMT_SBGGR16_1X16:
      71              :         case MEDIA_BUS_FMT_SGBRG16_1X16:
      72              :         case MEDIA_BUS_FMT_SGRBG16_1X16:
      73              :         case MEDIA_BUS_FMT_SRGGB16_1X16:
      74              :         case MEDIA_BUS_FMT_Y16_1X16:
      75            0 :                 return MIPI_CSI2_DT_RAW16;
      76            0 :         case MEDIA_BUS_FMT_SBGGR12_1X12:
      77              :         case MEDIA_BUS_FMT_SGBRG12_1X12:
      78              :         case MEDIA_BUS_FMT_SGRBG12_1X12:
      79              :         case MEDIA_BUS_FMT_SRGGB12_1X12:
      80              :         case MEDIA_BUS_FMT_Y12_1X12:
      81            0 :                 return MIPI_CSI2_DT_RAW12;
      82            0 :         case MEDIA_BUS_FMT_SBGGR10_1X10:
      83              :         case MEDIA_BUS_FMT_SGBRG10_1X10:
      84              :         case MEDIA_BUS_FMT_SGRBG10_1X10:
      85              :         case MEDIA_BUS_FMT_SRGGB10_1X10:
      86              :         case MEDIA_BUS_FMT_Y10_1X10:
      87            0 :                 return MIPI_CSI2_DT_RAW10;
      88            0 :         case MEDIA_BUS_FMT_SBGGR8_1X8:
      89              :         case MEDIA_BUS_FMT_SGBRG8_1X8:
      90              :         case MEDIA_BUS_FMT_SGRBG8_1X8:
      91              :         case MEDIA_BUS_FMT_SRGGB8_1X8:
      92              :         case MEDIA_BUS_FMT_Y8_1X8:
      93            0 :                 return MIPI_CSI2_DT_RAW8;
      94            0 :         case MEDIA_BUS_FMT_META_8:
      95              :         case MEDIA_BUS_FMT_META_10:
      96              :         case MEDIA_BUS_FMT_META_12:
      97              :         case MEDIA_BUS_FMT_META_16:
      98              :         case MEDIA_BUS_FMT_META_24:
      99            0 :                 return MIPI_CSI2_DT_EMBEDDED_8B;
     100              :         default:
     101              :                 /* return unavailable MIPI data type - 0x3f */
     102            0 :                 WARN_ON(1);
     103            0 :                 return 0x3f;
     104              :         }
     105              : }
     106              : 
     107            0 : bool ipu6_isys_is_bayer_format(u32 code)
     108              : {
     109            0 :         switch (code) {
     110              :         case MEDIA_BUS_FMT_SBGGR8_1X8:
     111              :         case MEDIA_BUS_FMT_SGBRG8_1X8:
     112              :         case MEDIA_BUS_FMT_SGRBG8_1X8:
     113              :         case MEDIA_BUS_FMT_SRGGB8_1X8:
     114              :         case MEDIA_BUS_FMT_SBGGR10_1X10:
     115              :         case MEDIA_BUS_FMT_SGBRG10_1X10:
     116              :         case MEDIA_BUS_FMT_SGRBG10_1X10:
     117              :         case MEDIA_BUS_FMT_SRGGB10_1X10:
     118              :         case MEDIA_BUS_FMT_SBGGR12_1X12:
     119              :         case MEDIA_BUS_FMT_SGBRG12_1X12:
     120              :         case MEDIA_BUS_FMT_SGRBG12_1X12:
     121              :         case MEDIA_BUS_FMT_SRGGB12_1X12:
     122              :         case MEDIA_BUS_FMT_SRGGB16_1X16:
     123              :         case MEDIA_BUS_FMT_SGRBG16_1X16:
     124              :         case MEDIA_BUS_FMT_SGBRG16_1X16:
     125              :         case MEDIA_BUS_FMT_SBGGR16_1X16:
     126              :                 return true;
     127            0 :         default:
     128            0 :                 return false;
     129              :         }
     130              : }
     131              : EXPORT_SYMBOL_NS_GPL(ipu6_isys_is_bayer_format, INTEL_IPU6);
     132              : 
     133            0 : u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y)
     134              : {
     135              :         static const u32 code_map[] = {
     136              :                 MEDIA_BUS_FMT_SRGGB8_1X8,
     137              :                 MEDIA_BUS_FMT_SGRBG8_1X8,
     138              :                 MEDIA_BUS_FMT_SGBRG8_1X8,
     139              :                 MEDIA_BUS_FMT_SBGGR8_1X8,
     140              :                 MEDIA_BUS_FMT_SRGGB10_1X10,
     141              :                 MEDIA_BUS_FMT_SGRBG10_1X10,
     142              :                 MEDIA_BUS_FMT_SGBRG10_1X10,
     143              :                 MEDIA_BUS_FMT_SBGGR10_1X10,
     144              :                 MEDIA_BUS_FMT_SRGGB12_1X12,
     145              :                 MEDIA_BUS_FMT_SGRBG12_1X12,
     146              :                 MEDIA_BUS_FMT_SGBRG12_1X12,
     147              :                 MEDIA_BUS_FMT_SBGGR12_1X12,
     148              :                 MEDIA_BUS_FMT_SRGGB16_1X16,
     149              :                 MEDIA_BUS_FMT_SGRBG16_1X16,
     150              :                 MEDIA_BUS_FMT_SGBRG16_1X16,
     151              :                 MEDIA_BUS_FMT_SBGGR16_1X16,
     152              :         };
     153              :         u32 i;
     154              : 
     155            0 :         for (i = 0; i < ARRAY_SIZE(code_map); i++)
     156            0 :                 if (code_map[i] == code)
     157              :                         break;
     158              : 
     159            0 :         if (WARN_ON(i == ARRAY_SIZE(code_map)))
     160            0 :                 return code;
     161              : 
     162            0 :         return code_map[i ^ (((y & 1) << 1) | (x & 1))];
     163              : }
     164              : EXPORT_SYMBOL_NS_GPL(ipu6_isys_convert_bayer_order, INTEL_IPU6);
     165              : 
     166            0 : int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
     167              :                              struct v4l2_subdev_state *state,
     168              :                              struct v4l2_subdev_format *format)
     169              : {
     170              :         struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
     171              :         struct v4l2_mbus_framefmt *fmt;
     172              :         struct v4l2_rect *crop;
     173            0 :         u32 code = asd->supported_codes[0];
     174            0 :         u32 other_pad, other_stream;
     175              :         unsigned int i;
     176              :         int ret;
     177              : 
     178              :         /* No transcoding, source and sink formats must match. */
     179            0 :         if ((sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SOURCE) &&
     180            0 :             sd->entity.num_pads > 1)
     181            0 :                 return v4l2_subdev_get_fmt(sd, state, format);
     182              : 
     183            0 :         format->format.width = clamp(format->format.width, IPU6_ISYS_MIN_WIDTH,
     184              :                                      IPU6_ISYS_MAX_WIDTH);
     185            0 :         format->format.height = clamp(format->format.height,
     186              :                                       IPU6_ISYS_MIN_HEIGHT,
     187              :                                       IPU6_ISYS_MAX_HEIGHT);
     188              : 
     189            0 :         for (i = 0; asd->supported_codes[i]; i++) {
     190            0 :                 if (asd->supported_codes[i] == format->format.code) {
     191              :                         code = asd->supported_codes[i];
     192              :                         break;
     193              :                 }
     194              :         }
     195            0 :         format->format.code = code;
     196            0 :         format->format.field = V4L2_FIELD_NONE;
     197              : 
     198              :         /* Store the format and propagate it to the source pad. */
     199            0 :         fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
     200            0 :         if (!fmt)
     201              :                 return -EINVAL;
     202              : 
     203            0 :         *fmt = format->format;
     204              : 
     205            0 :         if (!(sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SINK))
     206              :                 return 0;
     207              : 
     208              :         /* propagate format to following source pad */
     209            0 :         fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
     210              :                                                            format->stream);
     211            0 :         if (!fmt)
     212              :                 return -EINVAL;
     213              : 
     214            0 :         *fmt = format->format;
     215              : 
     216            0 :         ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
     217              :                                                     format->pad,
     218              :                                                     format->stream,
     219              :                                                     &other_pad,
     220              :                                                     &other_stream);
     221            0 :         if (ret)
     222              :                 return -EINVAL;
     223              : 
     224            0 :         crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream);
     225              :         /* reset crop */
     226            0 :         crop->left = 0;
     227            0 :         crop->top = 0;
     228            0 :         crop->width = fmt->width;
     229            0 :         crop->height = fmt->height;
     230              : 
     231            0 :         return 0;
     232              : }
     233              : 
     234            0 : int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
     235              :                                     struct v4l2_subdev_state *state,
     236              :                                     struct v4l2_subdev_mbus_code_enum *code)
     237              : {
     238              :         struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
     239            0 :         const u32 *supported_codes = asd->supported_codes;
     240              :         u32 index;
     241              : 
     242            0 :         for (index = 0; supported_codes[index]; index++) {
     243            0 :                 if (index == code->index) {
     244            0 :                         code->code = supported_codes[index];
     245            0 :                         return 0;
     246              :                 }
     247              :         }
     248              : 
     249              :         return -EINVAL;
     250              : }
     251              : 
     252            6 : static int subdev_set_routing(struct v4l2_subdev *sd,
     253              :                               struct v4l2_subdev_state *state,
     254              :                               struct v4l2_subdev_krouting *routing)
     255              : {
     256              :         static const struct v4l2_mbus_framefmt format = {
     257              :                 .width = 4096,
     258              :                 .height = 3072,
     259              :                 .code = MEDIA_BUS_FMT_SGRBG10_1X10,
     260              :                 .field = V4L2_FIELD_NONE,
     261              :         };
     262              :         int ret;
     263              : 
     264            6 :         ret = v4l2_subdev_routing_validate(sd, routing,
     265              :                                            V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
     266            6 :         if (ret)
     267              :                 return ret;
     268              : 
     269            6 :         return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
     270              : }
     271              : 
     272            2 : int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
     273              :                                  struct v4l2_mbus_framefmt *format)
     274              : {
     275              :         struct v4l2_mbus_framefmt *fmt;
     276              :         struct v4l2_subdev_state *state;
     277              : 
     278            2 :         if (!sd || !format)
     279              :                 return -EINVAL;
     280              : 
     281              :         state = v4l2_subdev_lock_and_get_active_state(sd);
     282            2 :         fmt = v4l2_subdev_state_get_format(state, pad, stream);
     283            2 :         if (fmt)
     284            2 :                 *format = *fmt;
     285              :         v4l2_subdev_unlock_state(state);
     286              : 
     287            2 :         return fmt ? 0 : -EINVAL;
     288              : }
     289              : 
     290            1 : int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
     291              :                                   struct v4l2_rect *crop)
     292              : {
     293              :         struct v4l2_subdev_state *state;
     294              :         struct v4l2_rect *rect;
     295              : 
     296            1 :         if (!sd || !crop)
     297              :                 return -EINVAL;
     298              : 
     299              :         state = v4l2_subdev_lock_and_get_active_state(sd);
     300            1 :         rect = v4l2_subdev_state_get_crop(state, pad, stream);
     301            1 :         if (rect)
     302            1 :                 *crop = *rect;
     303              :         v4l2_subdev_unlock_state(state);
     304              : 
     305            1 :         return rect ? 0 : -EINVAL;
     306              : }
     307              : 
     308            5 : u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
     309              : {
     310              :         struct v4l2_subdev_state *state;
     311              :         struct v4l2_subdev_route *routes;
     312              :         unsigned int i;
     313              :         u32 source_stream = 0;
     314              : 
     315              :         state = v4l2_subdev_lock_and_get_active_state(sd);
     316            5 :         if (!state)
     317              :                 return 0;
     318              : 
     319            5 :         routes = state->routing.routes;
     320            5 :         for (i = 0; i < state->routing.num_routes; i++) {
     321            5 :                 if (routes[i].source_pad == pad) {
     322            5 :                         source_stream = routes[i].source_stream;
     323            5 :                         break;
     324              :                 }
     325              :         }
     326              : 
     327              :         v4l2_subdev_unlock_state(state);
     328              : 
     329            5 :         return source_stream;
     330              : }
     331              : 
     332              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     333              : static // Only static if >=6.10, because ipu6-isys-csi2.c uses it before
     334              : #endif
     335            6 : int ipu6_isys_subdev_init_cfg(struct v4l2_subdev *sd,
     336              :                               struct v4l2_subdev_state *state)
     337              : {
     338            6 :         struct v4l2_subdev_route route = {
     339              :                 .sink_pad = 0,
     340              :                 .sink_stream = 0,
     341              :                 .source_pad = 1,
     342              :                 .source_stream = 0,
     343              :                 .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
     344              :         };
     345            6 :         struct v4l2_subdev_krouting routing = {
     346              :                 .num_routes = 1,
     347              :                 .routes = &route,
     348              :         };
     349              : 
     350            6 :         return subdev_set_routing(sd, state, &routing);
     351              : }
     352              : 
     353            0 : int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
     354              :                                  struct v4l2_subdev_state *state,
     355              :                                  enum v4l2_subdev_format_whence which,
     356              :                                  struct v4l2_subdev_krouting *routing)
     357              : {
     358            0 :         return subdev_set_routing(sd, state, routing);
     359              : }
     360              : 
     361              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     362              : static const struct v4l2_subdev_internal_ops ipu6_isys_subdev_internal_ops = {
     363              :         .init_state = ipu6_isys_subdev_init_cfg,
     364              : };
     365              : #endif
     366            6 : int ipu6_isys_subdev_init(struct ipu6_isys_subdev *asd,
     367              :                           const struct v4l2_subdev_ops *ops,
     368              :                           unsigned int nr_ctrls,
     369              :                           unsigned int num_sink_pads,
     370              :                           unsigned int num_source_pads)
     371              : {
     372            6 :         unsigned int num_pads = num_sink_pads + num_source_pads;
     373              :         unsigned int i;
     374              :         int ret;
     375              : 
     376            6 :         v4l2_subdev_init(&asd->sd, ops);
     377              : 
     378            6 :         asd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
     379              :                          V4L2_SUBDEV_FL_HAS_EVENTS |
     380              :                          V4L2_SUBDEV_FL_STREAMS;
     381            6 :         asd->sd.owner = THIS_MODULE;
     382              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     383            6 :         asd->sd.dev = &asd->isys->adev->auxdev.dev;
     384              : #endif
     385            6 :         asd->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
     386              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     387            6 :         asd->sd.internal_ops = &ipu6_isys_subdev_internal_ops;
     388              : #endif
     389            6 :         asd->pad = devm_kcalloc(&asd->isys->adev->auxdev.dev, num_pads,
     390              :                                 sizeof(*asd->pad), GFP_KERNEL);
     391            6 :         if (!asd->pad)
     392              :                 return -ENOMEM;
     393              : 
     394           12 :         for (i = 0; i < num_sink_pads; i++)
     395            6 :                 asd->pad[i].flags = MEDIA_PAD_FL_SINK |
     396              :                                     MEDIA_PAD_FL_MUST_CONNECT;
     397              : 
     398           30 :         for (i = num_sink_pads; i < num_pads; i++)
     399           24 :                 asd->pad[i].flags = MEDIA_PAD_FL_SOURCE;
     400              : 
     401            6 :         ret = media_entity_pads_init(&asd->sd.entity, num_pads, asd->pad);
     402            6 :         if (ret)
     403              :                 return ret;
     404              : 
     405            6 :         if (asd->ctrl_init) {
     406            0 :                 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, nr_ctrls);
     407            0 :                 if (ret)
     408            0 :                         goto out_media_entity_cleanup;
     409              : 
     410            0 :                 asd->ctrl_init(&asd->sd);
     411            0 :                 if (asd->ctrl_handler.error) {
     412              :                         ret = asd->ctrl_handler.error;
     413            0 :                         goto out_v4l2_ctrl_handler_free;
     414              :                 }
     415              : 
     416            0 :                 asd->sd.ctrl_handler = &asd->ctrl_handler;
     417              :         }
     418              : 
     419            6 :         asd->source = -1;
     420              : 
     421            6 :         return 0;
     422              : 
     423              : out_v4l2_ctrl_handler_free:
     424            0 :         v4l2_ctrl_handler_free(&asd->ctrl_handler);
     425              : 
     426              : out_media_entity_cleanup:
     427              :         media_entity_cleanup(&asd->sd.entity);
     428              : 
     429              :         return ret;
     430              : }
     431              : 
     432            0 : void ipu6_isys_subdev_cleanup(struct ipu6_isys_subdev *asd)
     433              : {
     434              :         media_entity_cleanup(&asd->sd.entity);
     435            0 :         v4l2_ctrl_handler_free(&asd->ctrl_handler);
     436            0 : }
        

Generated by: LCOV version 2.0-1