cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vsp1_sru.c (10438B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * vsp1_sru.c  --  R-Car VSP1 Super Resolution Unit
      4 *
      5 * Copyright (C) 2013 Renesas Corporation
      6 *
      7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
      8 */
      9
     10#include <linux/device.h>
     11#include <linux/gfp.h>
     12
     13#include <media/v4l2-subdev.h>
     14
     15#include "vsp1.h"
     16#include "vsp1_dl.h"
     17#include "vsp1_pipe.h"
     18#include "vsp1_sru.h"
     19
     20#define SRU_MIN_SIZE				4U
     21#define SRU_MAX_SIZE				8190U
     22
     23/* -----------------------------------------------------------------------------
     24 * Device Access
     25 */
     26
     27static inline void vsp1_sru_write(struct vsp1_sru *sru,
     28				  struct vsp1_dl_body *dlb, u32 reg, u32 data)
     29{
     30	vsp1_dl_body_write(dlb, reg, data);
     31}
     32
     33/* -----------------------------------------------------------------------------
     34 * Controls
     35 */
     36
     37#define V4L2_CID_VSP1_SRU_INTENSITY		(V4L2_CID_USER_BASE | 0x1001)
     38
     39struct vsp1_sru_param {
     40	u32 ctrl0;
     41	u32 ctrl2;
     42};
     43
     44#define VI6_SRU_CTRL0_PARAMS(p0, p1)			\
     45	(((p0) << VI6_SRU_CTRL0_PARAM0_SHIFT) |		\
     46	 ((p1) << VI6_SRU_CTRL0_PARAM1_SHIFT))
     47
     48#define VI6_SRU_CTRL2_PARAMS(p6, p7, p8)		\
     49	(((p6) << VI6_SRU_CTRL2_PARAM6_SHIFT) |		\
     50	 ((p7) << VI6_SRU_CTRL2_PARAM7_SHIFT) |		\
     51	 ((p8) << VI6_SRU_CTRL2_PARAM8_SHIFT))
     52
     53static const struct vsp1_sru_param vsp1_sru_params[] = {
     54	{
     55		.ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
     56		.ctrl2 = VI6_SRU_CTRL2_PARAMS(24, 40, 255),
     57	}, {
     58		.ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
     59		.ctrl2 = VI6_SRU_CTRL2_PARAMS(8, 16, 255),
     60	}, {
     61		.ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
     62		.ctrl2 = VI6_SRU_CTRL2_PARAMS(36, 60, 255),
     63	}, {
     64		.ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
     65		.ctrl2 = VI6_SRU_CTRL2_PARAMS(12, 27, 255),
     66	}, {
     67		.ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
     68		.ctrl2 = VI6_SRU_CTRL2_PARAMS(48, 80, 255),
     69	}, {
     70		.ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
     71		.ctrl2 = VI6_SRU_CTRL2_PARAMS(16, 36, 255),
     72	},
     73};
     74
     75static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
     76{
     77	struct vsp1_sru *sru =
     78		container_of(ctrl->handler, struct vsp1_sru, ctrls);
     79
     80	switch (ctrl->id) {
     81	case V4L2_CID_VSP1_SRU_INTENSITY:
     82		sru->intensity = ctrl->val;
     83		break;
     84	}
     85
     86	return 0;
     87}
     88
     89static const struct v4l2_ctrl_ops sru_ctrl_ops = {
     90	.s_ctrl = sru_s_ctrl,
     91};
     92
     93static const struct v4l2_ctrl_config sru_intensity_control = {
     94	.ops = &sru_ctrl_ops,
     95	.id = V4L2_CID_VSP1_SRU_INTENSITY,
     96	.name = "Intensity",
     97	.type = V4L2_CTRL_TYPE_INTEGER,
     98	.min = 1,
     99	.max = 6,
    100	.def = 1,
    101	.step = 1,
    102};
    103
    104/* -----------------------------------------------------------------------------
    105 * V4L2 Subdevice Operations
    106 */
    107
    108static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
    109			      struct v4l2_subdev_state *sd_state,
    110			      struct v4l2_subdev_mbus_code_enum *code)
    111{
    112	static const unsigned int codes[] = {
    113		MEDIA_BUS_FMT_ARGB8888_1X32,
    114		MEDIA_BUS_FMT_AYUV8_1X32,
    115	};
    116
    117	return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, codes,
    118					  ARRAY_SIZE(codes));
    119}
    120
    121static int sru_enum_frame_size(struct v4l2_subdev *subdev,
    122			       struct v4l2_subdev_state *sd_state,
    123			       struct v4l2_subdev_frame_size_enum *fse)
    124{
    125	struct vsp1_sru *sru = to_sru(subdev);
    126	struct v4l2_subdev_state *config;
    127	struct v4l2_mbus_framefmt *format;
    128	int ret = 0;
    129
    130	config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
    131					    fse->which);
    132	if (!config)
    133		return -EINVAL;
    134
    135	format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
    136
    137	mutex_lock(&sru->entity.lock);
    138
    139	if (fse->index || fse->code != format->code) {
    140		ret = -EINVAL;
    141		goto done;
    142	}
    143
    144	if (fse->pad == SRU_PAD_SINK) {
    145		fse->min_width = SRU_MIN_SIZE;
    146		fse->max_width = SRU_MAX_SIZE;
    147		fse->min_height = SRU_MIN_SIZE;
    148		fse->max_height = SRU_MAX_SIZE;
    149	} else {
    150		fse->min_width = format->width;
    151		fse->min_height = format->height;
    152		if (format->width <= SRU_MAX_SIZE / 2 &&
    153		    format->height <= SRU_MAX_SIZE / 2) {
    154			fse->max_width = format->width * 2;
    155			fse->max_height = format->height * 2;
    156		} else {
    157			fse->max_width = format->width;
    158			fse->max_height = format->height;
    159		}
    160	}
    161
    162done:
    163	mutex_unlock(&sru->entity.lock);
    164	return ret;
    165}
    166
    167static void sru_try_format(struct vsp1_sru *sru,
    168			   struct v4l2_subdev_state *sd_state,
    169			   unsigned int pad, struct v4l2_mbus_framefmt *fmt)
    170{
    171	struct v4l2_mbus_framefmt *format;
    172	unsigned int input_area;
    173	unsigned int output_area;
    174
    175	switch (pad) {
    176	case SRU_PAD_SINK:
    177		/* Default to YUV if the requested format is not supported. */
    178		if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
    179		    fmt->code != MEDIA_BUS_FMT_AYUV8_1X32)
    180			fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
    181
    182		fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE);
    183		fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE);
    184		break;
    185
    186	case SRU_PAD_SOURCE:
    187		/* The SRU can't perform format conversion. */
    188		format = vsp1_entity_get_pad_format(&sru->entity, sd_state,
    189						    SRU_PAD_SINK);
    190		fmt->code = format->code;
    191
    192		/*
    193		 * We can upscale by 2 in both direction, but not independently.
    194		 * Compare the input and output rectangles areas (avoiding
    195		 * integer overflows on the output): if the requested output
    196		 * area is larger than 1.5^2 the input area upscale by two,
    197		 * otherwise don't scale.
    198		 */
    199		input_area = format->width * format->height;
    200		output_area = min(fmt->width, SRU_MAX_SIZE)
    201			    * min(fmt->height, SRU_MAX_SIZE);
    202
    203		if (fmt->width <= SRU_MAX_SIZE / 2 &&
    204		    fmt->height <= SRU_MAX_SIZE / 2 &&
    205		    output_area > input_area * 9 / 4) {
    206			fmt->width = format->width * 2;
    207			fmt->height = format->height * 2;
    208		} else {
    209			fmt->width = format->width;
    210			fmt->height = format->height;
    211		}
    212		break;
    213	}
    214
    215	fmt->field = V4L2_FIELD_NONE;
    216	fmt->colorspace = V4L2_COLORSPACE_SRGB;
    217}
    218
    219static int sru_set_format(struct v4l2_subdev *subdev,
    220			  struct v4l2_subdev_state *sd_state,
    221			  struct v4l2_subdev_format *fmt)
    222{
    223	struct vsp1_sru *sru = to_sru(subdev);
    224	struct v4l2_subdev_state *config;
    225	struct v4l2_mbus_framefmt *format;
    226	int ret = 0;
    227
    228	mutex_lock(&sru->entity.lock);
    229
    230	config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
    231					    fmt->which);
    232	if (!config) {
    233		ret = -EINVAL;
    234		goto done;
    235	}
    236
    237	sru_try_format(sru, config, fmt->pad, &fmt->format);
    238
    239	format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad);
    240	*format = fmt->format;
    241
    242	if (fmt->pad == SRU_PAD_SINK) {
    243		/* Propagate the format to the source pad. */
    244		format = vsp1_entity_get_pad_format(&sru->entity, config,
    245						    SRU_PAD_SOURCE);
    246		*format = fmt->format;
    247
    248		sru_try_format(sru, config, SRU_PAD_SOURCE, format);
    249	}
    250
    251done:
    252	mutex_unlock(&sru->entity.lock);
    253	return ret;
    254}
    255
    256static const struct v4l2_subdev_pad_ops sru_pad_ops = {
    257	.init_cfg = vsp1_entity_init_cfg,
    258	.enum_mbus_code = sru_enum_mbus_code,
    259	.enum_frame_size = sru_enum_frame_size,
    260	.get_fmt = vsp1_subdev_get_pad_format,
    261	.set_fmt = sru_set_format,
    262};
    263
    264static const struct v4l2_subdev_ops sru_ops = {
    265	.pad    = &sru_pad_ops,
    266};
    267
    268/* -----------------------------------------------------------------------------
    269 * VSP1 Entity Operations
    270 */
    271
    272static void sru_configure_stream(struct vsp1_entity *entity,
    273				 struct vsp1_pipeline *pipe,
    274				 struct vsp1_dl_list *dl,
    275				 struct vsp1_dl_body *dlb)
    276{
    277	const struct vsp1_sru_param *param;
    278	struct vsp1_sru *sru = to_sru(&entity->subdev);
    279	struct v4l2_mbus_framefmt *input;
    280	struct v4l2_mbus_framefmt *output;
    281	u32 ctrl0;
    282
    283	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
    284					   SRU_PAD_SINK);
    285	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
    286					    SRU_PAD_SOURCE);
    287
    288	if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
    289		ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
    290		      | VI6_SRU_CTRL0_PARAM4;
    291	else
    292		ctrl0 = VI6_SRU_CTRL0_PARAM3;
    293
    294	if (input->width != output->width)
    295		ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
    296
    297	param = &vsp1_sru_params[sru->intensity - 1];
    298
    299	ctrl0 |= param->ctrl0;
    300
    301	vsp1_sru_write(sru, dlb, VI6_SRU_CTRL0, ctrl0);
    302	vsp1_sru_write(sru, dlb, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
    303	vsp1_sru_write(sru, dlb, VI6_SRU_CTRL2, param->ctrl2);
    304}
    305
    306static unsigned int sru_max_width(struct vsp1_entity *entity,
    307				  struct vsp1_pipeline *pipe)
    308{
    309	struct vsp1_sru *sru = to_sru(&entity->subdev);
    310	struct v4l2_mbus_framefmt *input;
    311	struct v4l2_mbus_framefmt *output;
    312
    313	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
    314					   SRU_PAD_SINK);
    315	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
    316					    SRU_PAD_SOURCE);
    317
    318	/*
    319	 * The maximum input width of the SRU is 288 input pixels, but 32
    320	 * pixels are reserved to support overlapping partition windows when
    321	 * scaling.
    322	 */
    323	if (input->width != output->width)
    324		return 512;
    325	else
    326		return 256;
    327}
    328
    329static void sru_partition(struct vsp1_entity *entity,
    330			  struct vsp1_pipeline *pipe,
    331			  struct vsp1_partition *partition,
    332			  unsigned int partition_idx,
    333			  struct vsp1_partition_window *window)
    334{
    335	struct vsp1_sru *sru = to_sru(&entity->subdev);
    336	struct v4l2_mbus_framefmt *input;
    337	struct v4l2_mbus_framefmt *output;
    338
    339	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
    340					   SRU_PAD_SINK);
    341	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
    342					    SRU_PAD_SOURCE);
    343
    344	/* Adapt if SRUx2 is enabled. */
    345	if (input->width != output->width) {
    346		window->width /= 2;
    347		window->left /= 2;
    348	}
    349
    350	partition->sru = *window;
    351}
    352
    353static const struct vsp1_entity_operations sru_entity_ops = {
    354	.configure_stream = sru_configure_stream,
    355	.max_width = sru_max_width,
    356	.partition = sru_partition,
    357};
    358
    359/* -----------------------------------------------------------------------------
    360 * Initialization and Cleanup
    361 */
    362
    363struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
    364{
    365	struct vsp1_sru *sru;
    366	int ret;
    367
    368	sru = devm_kzalloc(vsp1->dev, sizeof(*sru), GFP_KERNEL);
    369	if (sru == NULL)
    370		return ERR_PTR(-ENOMEM);
    371
    372	sru->entity.ops = &sru_entity_ops;
    373	sru->entity.type = VSP1_ENTITY_SRU;
    374
    375	ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops,
    376			       MEDIA_ENT_F_PROC_VIDEO_SCALER);
    377	if (ret < 0)
    378		return ERR_PTR(ret);
    379
    380	/* Initialize the control handler. */
    381	v4l2_ctrl_handler_init(&sru->ctrls, 1);
    382	v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
    383
    384	sru->intensity = 1;
    385
    386	sru->entity.subdev.ctrl_handler = &sru->ctrls;
    387
    388	if (sru->ctrls.error) {
    389		dev_err(vsp1->dev, "sru: failed to initialize controls\n");
    390		ret = sru->ctrls.error;
    391		vsp1_entity_destroy(&sru->entity);
    392		return ERR_PTR(ret);
    393	}
    394
    395	return sru;
    396}