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_lut.c (5884B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * vsp1_lut.c  --  R-Car VSP1 Look-Up Table
      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_lut.h"
     18
     19#define LUT_MIN_SIZE				4U
     20#define LUT_MAX_SIZE				8190U
     21
     22#define LUT_SIZE				256
     23
     24/* -----------------------------------------------------------------------------
     25 * Device Access
     26 */
     27
     28static inline void vsp1_lut_write(struct vsp1_lut *lut,
     29				  struct vsp1_dl_body *dlb, u32 reg, u32 data)
     30{
     31	vsp1_dl_body_write(dlb, reg, data);
     32}
     33
     34/* -----------------------------------------------------------------------------
     35 * Controls
     36 */
     37
     38#define V4L2_CID_VSP1_LUT_TABLE			(V4L2_CID_USER_BASE | 0x1001)
     39
     40static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl)
     41{
     42	struct vsp1_dl_body *dlb;
     43	unsigned int i;
     44
     45	dlb = vsp1_dl_body_get(lut->pool);
     46	if (!dlb)
     47		return -ENOMEM;
     48
     49	for (i = 0; i < LUT_SIZE; ++i)
     50		vsp1_dl_body_write(dlb, VI6_LUT_TABLE + 4 * i,
     51				       ctrl->p_new.p_u32[i]);
     52
     53	spin_lock_irq(&lut->lock);
     54	swap(lut->lut, dlb);
     55	spin_unlock_irq(&lut->lock);
     56
     57	vsp1_dl_body_put(dlb);
     58	return 0;
     59}
     60
     61static int lut_s_ctrl(struct v4l2_ctrl *ctrl)
     62{
     63	struct vsp1_lut *lut =
     64		container_of(ctrl->handler, struct vsp1_lut, ctrls);
     65
     66	switch (ctrl->id) {
     67	case V4L2_CID_VSP1_LUT_TABLE:
     68		lut_set_table(lut, ctrl);
     69		break;
     70	}
     71
     72	return 0;
     73}
     74
     75static const struct v4l2_ctrl_ops lut_ctrl_ops = {
     76	.s_ctrl = lut_s_ctrl,
     77};
     78
     79static const struct v4l2_ctrl_config lut_table_control = {
     80	.ops = &lut_ctrl_ops,
     81	.id = V4L2_CID_VSP1_LUT_TABLE,
     82	.name = "Look-Up Table",
     83	.type = V4L2_CTRL_TYPE_U32,
     84	.min = 0x00000000,
     85	.max = 0x00ffffff,
     86	.step = 1,
     87	.def = 0,
     88	.dims = { LUT_SIZE },
     89};
     90
     91/* -----------------------------------------------------------------------------
     92 * V4L2 Subdevice Pad Operations
     93 */
     94
     95static const unsigned int lut_codes[] = {
     96	MEDIA_BUS_FMT_ARGB8888_1X32,
     97	MEDIA_BUS_FMT_AHSV8888_1X32,
     98	MEDIA_BUS_FMT_AYUV8_1X32,
     99};
    100
    101static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
    102			      struct v4l2_subdev_state *sd_state,
    103			      struct v4l2_subdev_mbus_code_enum *code)
    104{
    105	return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, lut_codes,
    106					  ARRAY_SIZE(lut_codes));
    107}
    108
    109static int lut_enum_frame_size(struct v4l2_subdev *subdev,
    110			       struct v4l2_subdev_state *sd_state,
    111			       struct v4l2_subdev_frame_size_enum *fse)
    112{
    113	return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
    114					   LUT_MIN_SIZE,
    115					   LUT_MIN_SIZE, LUT_MAX_SIZE,
    116					   LUT_MAX_SIZE);
    117}
    118
    119static int lut_set_format(struct v4l2_subdev *subdev,
    120			  struct v4l2_subdev_state *sd_state,
    121			  struct v4l2_subdev_format *fmt)
    122{
    123	return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, lut_codes,
    124					  ARRAY_SIZE(lut_codes),
    125					  LUT_MIN_SIZE, LUT_MIN_SIZE,
    126					  LUT_MAX_SIZE, LUT_MAX_SIZE);
    127}
    128
    129/* -----------------------------------------------------------------------------
    130 * V4L2 Subdevice Operations
    131 */
    132
    133static const struct v4l2_subdev_pad_ops lut_pad_ops = {
    134	.init_cfg = vsp1_entity_init_cfg,
    135	.enum_mbus_code = lut_enum_mbus_code,
    136	.enum_frame_size = lut_enum_frame_size,
    137	.get_fmt = vsp1_subdev_get_pad_format,
    138	.set_fmt = lut_set_format,
    139};
    140
    141static const struct v4l2_subdev_ops lut_ops = {
    142	.pad    = &lut_pad_ops,
    143};
    144
    145/* -----------------------------------------------------------------------------
    146 * VSP1 Entity Operations
    147 */
    148
    149static void lut_configure_stream(struct vsp1_entity *entity,
    150				 struct vsp1_pipeline *pipe,
    151				 struct vsp1_dl_list *dl,
    152				 struct vsp1_dl_body *dlb)
    153{
    154	struct vsp1_lut *lut = to_lut(&entity->subdev);
    155
    156	vsp1_lut_write(lut, dlb, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
    157}
    158
    159static void lut_configure_frame(struct vsp1_entity *entity,
    160				struct vsp1_pipeline *pipe,
    161				struct vsp1_dl_list *dl,
    162				struct vsp1_dl_body *dlb)
    163{
    164	struct vsp1_lut *lut = to_lut(&entity->subdev);
    165	struct vsp1_dl_body *lut_dlb;
    166	unsigned long flags;
    167
    168	spin_lock_irqsave(&lut->lock, flags);
    169	lut_dlb = lut->lut;
    170	lut->lut = NULL;
    171	spin_unlock_irqrestore(&lut->lock, flags);
    172
    173	if (lut_dlb) {
    174		vsp1_dl_list_add_body(dl, lut_dlb);
    175
    176		/* Release our local reference. */
    177		vsp1_dl_body_put(lut_dlb);
    178	}
    179}
    180
    181static void lut_destroy(struct vsp1_entity *entity)
    182{
    183	struct vsp1_lut *lut = to_lut(&entity->subdev);
    184
    185	vsp1_dl_body_pool_destroy(lut->pool);
    186}
    187
    188static const struct vsp1_entity_operations lut_entity_ops = {
    189	.configure_stream = lut_configure_stream,
    190	.configure_frame = lut_configure_frame,
    191	.destroy = lut_destroy,
    192};
    193
    194/* -----------------------------------------------------------------------------
    195 * Initialization and Cleanup
    196 */
    197
    198struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
    199{
    200	struct vsp1_lut *lut;
    201	int ret;
    202
    203	lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
    204	if (lut == NULL)
    205		return ERR_PTR(-ENOMEM);
    206
    207	spin_lock_init(&lut->lock);
    208
    209	lut->entity.ops = &lut_entity_ops;
    210	lut->entity.type = VSP1_ENTITY_LUT;
    211
    212	ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops,
    213			       MEDIA_ENT_F_PROC_VIDEO_LUT);
    214	if (ret < 0)
    215		return ERR_PTR(ret);
    216
    217	/*
    218	 * Pre-allocate a body pool, with 3 bodies allowing a userspace update
    219	 * before the hardware has committed a previous set of tables, handling
    220	 * both the queued and pending dl entries.
    221	 */
    222	lut->pool = vsp1_dl_body_pool_create(vsp1, 3, LUT_SIZE, 0);
    223	if (!lut->pool)
    224		return ERR_PTR(-ENOMEM);
    225
    226	/* Initialize the control handler. */
    227	v4l2_ctrl_handler_init(&lut->ctrls, 1);
    228	v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL);
    229
    230	lut->entity.subdev.ctrl_handler = &lut->ctrls;
    231
    232	if (lut->ctrls.error) {
    233		dev_err(vsp1->dev, "lut: failed to initialize controls\n");
    234		ret = lut->ctrls.error;
    235		vsp1_entity_destroy(&lut->entity);
    236		return ERR_PTR(ret);
    237	}
    238
    239	v4l2_ctrl_handler_setup(&lut->ctrls);
    240
    241	return lut;
    242}