brintos

brintos / linux-shallow public Read only

0
0
Text · 9.7 KiB · 4f4fcb2 Raw
424 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * vimc-common.c Virtual Media Controller Driver4 *5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>6 */7 8#include <linux/init.h>9#include <linux/module.h>10 11#include <media/v4l2-ctrls.h>12 13#include "vimc-common.h"14 15/*16 * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code17 * in the scaler)18 */19static const struct vimc_pix_map vimc_pix_map_list[] = {20	/* TODO: add all missing formats */21 22	/* RGB formats */23	{24		.code = {25			MEDIA_BUS_FMT_BGR888_1X24,26			MEDIA_BUS_FMT_BGR888_3X827		},28		.pixelformat = V4L2_PIX_FMT_BGR24,29		.bpp = 3,30		.bayer = false,31	},32	{33		.code = {34			MEDIA_BUS_FMT_RGB888_1X24,35			MEDIA_BUS_FMT_RGB888_2X12_BE,36			MEDIA_BUS_FMT_RGB888_2X12_LE,37			MEDIA_BUS_FMT_RGB888_3X8,38			MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,39			MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,40			MEDIA_BUS_FMT_RGB888_1X32_PADHI,41			MEDIA_BUS_FMT_GBR888_1X2442		},43		.pixelformat = V4L2_PIX_FMT_RGB24,44		.bpp = 3,45		.bayer = false,46	},47	{48		.code = { MEDIA_BUS_FMT_ARGB8888_1X32 },49		.pixelformat = V4L2_PIX_FMT_ARGB32,50		.bpp = 4,51		.bayer = false,52	},53 54	/* Bayer formats */55	{56		.code = { MEDIA_BUS_FMT_SBGGR8_1X8 },57		.pixelformat = V4L2_PIX_FMT_SBGGR8,58		.bpp = 1,59		.bayer = true,60	},61	{62		.code = { MEDIA_BUS_FMT_SGBRG8_1X8 },63		.pixelformat = V4L2_PIX_FMT_SGBRG8,64		.bpp = 1,65		.bayer = true,66	},67	{68		.code = { MEDIA_BUS_FMT_SGRBG8_1X8 },69		.pixelformat = V4L2_PIX_FMT_SGRBG8,70		.bpp = 1,71		.bayer = true,72	},73	{74		.code = { MEDIA_BUS_FMT_SRGGB8_1X8 },75		.pixelformat = V4L2_PIX_FMT_SRGGB8,76		.bpp = 1,77		.bayer = true,78	},79	{80		.code = { MEDIA_BUS_FMT_SBGGR10_1X10 },81		.pixelformat = V4L2_PIX_FMT_SBGGR10,82		.bpp = 2,83		.bayer = true,84	},85	{86		.code = { MEDIA_BUS_FMT_SGBRG10_1X10 },87		.pixelformat = V4L2_PIX_FMT_SGBRG10,88		.bpp = 2,89		.bayer = true,90	},91	{92		.code = { MEDIA_BUS_FMT_SGRBG10_1X10 },93		.pixelformat = V4L2_PIX_FMT_SGRBG10,94		.bpp = 2,95		.bayer = true,96	},97	{98		.code = { MEDIA_BUS_FMT_SRGGB10_1X10 },99		.pixelformat = V4L2_PIX_FMT_SRGGB10,100		.bpp = 2,101		.bayer = true,102	},103 104	/* 10bit raw bayer a-law compressed to 8 bits */105	{106		.code = { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 },107		.pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,108		.bpp = 1,109		.bayer = true,110	},111	{112		.code = { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 },113		.pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,114		.bpp = 1,115		.bayer = true,116	},117	{118		.code = { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 },119		.pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,120		.bpp = 1,121		.bayer = true,122	},123	{124		.code = { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 },125		.pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,126		.bpp = 1,127		.bayer = true,128	},129 130	/* 10bit raw bayer DPCM compressed to 8 bits */131	{132		.code = { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },133		.pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,134		.bpp = 1,135		.bayer = true,136	},137	{138		.code = { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },139		.pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,140		.bpp = 1,141		.bayer = true,142	},143	{144		.code = { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },145		.pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,146		.bpp = 1,147		.bayer = true,148	},149	{150		.code = { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },151		.pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,152		.bpp = 1,153		.bayer = true,154	},155	{156		.code = { MEDIA_BUS_FMT_SBGGR12_1X12 },157		.pixelformat = V4L2_PIX_FMT_SBGGR12,158		.bpp = 2,159		.bayer = true,160	},161	{162		.code = { MEDIA_BUS_FMT_SGBRG12_1X12 },163		.pixelformat = V4L2_PIX_FMT_SGBRG12,164		.bpp = 2,165		.bayer = true,166	},167	{168		.code = { MEDIA_BUS_FMT_SGRBG12_1X12 },169		.pixelformat = V4L2_PIX_FMT_SGRBG12,170		.bpp = 2,171		.bayer = true,172	},173	{174		.code = { MEDIA_BUS_FMT_SRGGB12_1X12 },175		.pixelformat = V4L2_PIX_FMT_SRGGB12,176		.bpp = 2,177		.bayer = true,178	},179};180 181bool vimc_is_source(struct media_entity *ent)182{183	unsigned int i;184 185	for (i = 0; i < ent->num_pads; i++)186		if (ent->pads[i].flags & MEDIA_PAD_FL_SINK)187			return false;188	return true;189}190 191const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)192{193	if (i >= ARRAY_SIZE(vimc_pix_map_list))194		return NULL;195 196	return &vimc_pix_map_list[i];197}198 199u32 vimc_mbus_code_by_index(unsigned int index)200{201	unsigned int i, j;202 203	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {204		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {205			if (!vimc_pix_map_list[i].code[j])206				break;207 208			if (!index)209				return vimc_pix_map_list[i].code[j];210			index--;211		}212	}213	return 0;214}215 216const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)217{218	unsigned int i, j;219 220	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {221		for (j = 0; j < ARRAY_SIZE(vimc_pix_map_list[i].code); j++) {222			if (vimc_pix_map_list[i].code[j] == code)223				return &vimc_pix_map_list[i];224		}225	}226	return NULL;227}228 229const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)230{231	unsigned int i;232 233	for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {234		if (vimc_pix_map_list[i].pixelformat == pixelformat)235			return &vimc_pix_map_list[i];236	}237	return NULL;238}239 240static int vimc_get_pix_format(struct media_pad *pad,241			       struct v4l2_pix_format *fmt)242{243	if (is_media_entity_v4l2_subdev(pad->entity)) {244		struct v4l2_subdev *sd =245			media_entity_to_v4l2_subdev(pad->entity);246		struct v4l2_subdev_format sd_fmt = {247			.which = V4L2_SUBDEV_FORMAT_ACTIVE,248			.pad = pad->index,249		};250		const struct vimc_pix_map *pix_map;251		int ret;252 253		ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);254		if (ret)255			return ret;256 257		v4l2_fill_pix_format(fmt, &sd_fmt.format);258		pix_map = vimc_pix_map_by_code(sd_fmt.format.code);259		fmt->pixelformat = pix_map->pixelformat;260	} else if (is_media_entity_v4l2_video_device(pad->entity)) {261		struct video_device *vdev = container_of(pad->entity,262							 struct video_device,263							 entity);264		struct vimc_ent_device *ved = video_get_drvdata(vdev);265 266		if (!ved->vdev_get_format)267			return -ENOIOCTLCMD;268 269		ved->vdev_get_format(ved, fmt);270	} else {271		return -EINVAL;272	}273 274	return 0;275}276 277int vimc_vdev_link_validate(struct media_link *link)278{279	struct v4l2_pix_format source_fmt, sink_fmt;280	int ret;281 282	ret = vimc_get_pix_format(link->source, &source_fmt);283	if (ret)284		return ret;285 286	ret = vimc_get_pix_format(link->sink, &sink_fmt);287	if (ret)288		return ret;289 290	pr_info("vimc link validate: "291		"%s:src:%dx%d (0x%x, %d, %d, %d, %d) "292		"%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",293		/* src */294		link->source->entity->name,295		source_fmt.width, source_fmt.height,296		source_fmt.pixelformat, source_fmt.colorspace,297		source_fmt.quantization, source_fmt.xfer_func,298		source_fmt.ycbcr_enc,299		/* sink */300		link->sink->entity->name,301		sink_fmt.width, sink_fmt.height,302		sink_fmt.pixelformat, sink_fmt.colorspace,303		sink_fmt.quantization, sink_fmt.xfer_func,304		sink_fmt.ycbcr_enc);305 306	/* The width, height and pixelformat must match. */307	if (source_fmt.width != sink_fmt.width ||308	    source_fmt.height != sink_fmt.height ||309	    source_fmt.pixelformat != sink_fmt.pixelformat)310		return -EPIPE;311 312	/*313	 * The field order must match, or the sink field order must be NONE314	 * to support interlaced hardware connected to bridges that support315	 * progressive formats only.316	 */317	if (source_fmt.field != sink_fmt.field &&318	    sink_fmt.field != V4L2_FIELD_NONE)319		return -EPIPE;320 321	/*322	 * If colorspace is DEFAULT, then assume all the colorimetry is also323	 * DEFAULT, return 0 to skip comparing the other colorimetry parameters324	 */325	if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||326	    sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)327		return 0;328 329	/* Colorspace must match. */330	if (source_fmt.colorspace != sink_fmt.colorspace)331		return -EPIPE;332 333	/* Colorimetry must match if they are not set to DEFAULT */334	if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&335	    sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&336	    source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc)337		return -EPIPE;338 339	if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&340	    sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&341	    source_fmt.quantization != sink_fmt.quantization)342		return -EPIPE;343 344	if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&345	    sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&346	    source_fmt.xfer_func != sink_fmt.xfer_func)347		return -EPIPE;348 349	return 0;350}351 352static const struct media_entity_operations vimc_ent_sd_mops = {353	.link_validate = v4l2_subdev_link_validate,354};355 356int vimc_ent_sd_register(struct vimc_ent_device *ved,357			 struct v4l2_subdev *sd,358			 struct v4l2_device *v4l2_dev,359			 const char *const name,360			 u32 function,361			 u16 num_pads,362			 struct media_pad *pads,363			 const struct v4l2_subdev_internal_ops *int_ops,364			 const struct v4l2_subdev_ops *sd_ops)365{366	int ret;367 368	/* Fill the vimc_ent_device struct */369	ved->ent = &sd->entity;370 371	/* Initialize the subdev */372	v4l2_subdev_init(sd, sd_ops);373	sd->internal_ops = int_ops;374	sd->entity.function = function;375	sd->entity.ops = &vimc_ent_sd_mops;376	sd->owner = THIS_MODULE;377	strscpy(sd->name, name, sizeof(sd->name));378	v4l2_set_subdevdata(sd, ved);379 380	/* Expose this subdev to user space */381	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;382	if (sd->ctrl_handler)383		sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;384 385	/* Initialize the media entity */386	ret = media_entity_pads_init(&sd->entity, num_pads, pads);387	if (ret)388		return ret;389 390	/*391	 * Finalize the subdev initialization if it supports active states. Use392	 * the control handler lock as the state lock if available.393	 */394	if (int_ops && int_ops->init_state) {395		if (sd->ctrl_handler)396			sd->state_lock = sd->ctrl_handler->lock;397 398		ret = v4l2_subdev_init_finalize(sd);399		if (ret) {400			dev_err(v4l2_dev->dev,401				"%s: subdev initialization failed (err=%d)\n",402				name, ret);403			goto err_clean_m_ent;404		}405	}406 407	/* Register the subdev with the v4l2 and the media framework */408	ret = v4l2_device_register_subdev(v4l2_dev, sd);409	if (ret) {410		dev_err(v4l2_dev->dev,411			"%s: subdev register failed (err=%d)\n",412			name, ret);413		goto err_clean_sd;414	}415 416	return 0;417 418err_clean_sd:419	v4l2_subdev_cleanup(sd);420err_clean_m_ent:421	media_entity_cleanup(&sd->entity);422	return ret;423}424