brintos

brintos / linux-shallow public Read only

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