linux/drivers/media/platform/vsp1/vsp1_lut.c
<<
>>
Prefs
   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_pad_config *cfg,
 103                              struct v4l2_subdev_mbus_code_enum *code)
 104{
 105        return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lut_codes,
 106                                          ARRAY_SIZE(lut_codes));
 107}
 108
 109static int lut_enum_frame_size(struct v4l2_subdev *subdev,
 110                               struct v4l2_subdev_pad_config *cfg,
 111                               struct v4l2_subdev_frame_size_enum *fse)
 112{
 113        return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE,
 114                                           LUT_MIN_SIZE, LUT_MAX_SIZE,
 115                                           LUT_MAX_SIZE);
 116}
 117
 118static int lut_set_format(struct v4l2_subdev *subdev,
 119                          struct v4l2_subdev_pad_config *cfg,
 120                          struct v4l2_subdev_format *fmt)
 121{
 122        return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lut_codes,
 123                                          ARRAY_SIZE(lut_codes),
 124                                          LUT_MIN_SIZE, LUT_MIN_SIZE,
 125                                          LUT_MAX_SIZE, LUT_MAX_SIZE);
 126}
 127
 128/* -----------------------------------------------------------------------------
 129 * V4L2 Subdevice Operations
 130 */
 131
 132static const struct v4l2_subdev_pad_ops lut_pad_ops = {
 133        .init_cfg = vsp1_entity_init_cfg,
 134        .enum_mbus_code = lut_enum_mbus_code,
 135        .enum_frame_size = lut_enum_frame_size,
 136        .get_fmt = vsp1_subdev_get_pad_format,
 137        .set_fmt = lut_set_format,
 138};
 139
 140static const struct v4l2_subdev_ops lut_ops = {
 141        .pad    = &lut_pad_ops,
 142};
 143
 144/* -----------------------------------------------------------------------------
 145 * VSP1 Entity Operations
 146 */
 147
 148static void lut_configure_stream(struct vsp1_entity *entity,
 149                                 struct vsp1_pipeline *pipe,
 150                                 struct vsp1_dl_list *dl,
 151                                 struct vsp1_dl_body *dlb)
 152{
 153        struct vsp1_lut *lut = to_lut(&entity->subdev);
 154
 155        vsp1_lut_write(lut, dlb, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
 156}
 157
 158static void lut_configure_frame(struct vsp1_entity *entity,
 159                                struct vsp1_pipeline *pipe,
 160                                struct vsp1_dl_list *dl,
 161                                struct vsp1_dl_body *dlb)
 162{
 163        struct vsp1_lut *lut = to_lut(&entity->subdev);
 164        struct vsp1_dl_body *lut_dlb;
 165        unsigned long flags;
 166
 167        spin_lock_irqsave(&lut->lock, flags);
 168        lut_dlb = lut->lut;
 169        lut->lut = NULL;
 170        spin_unlock_irqrestore(&lut->lock, flags);
 171
 172        if (lut_dlb) {
 173                vsp1_dl_list_add_body(dl, lut_dlb);
 174
 175                /* Release our local reference. */
 176                vsp1_dl_body_put(lut_dlb);
 177        }
 178}
 179
 180static void lut_destroy(struct vsp1_entity *entity)
 181{
 182        struct vsp1_lut *lut = to_lut(&entity->subdev);
 183
 184        vsp1_dl_body_pool_destroy(lut->pool);
 185}
 186
 187static const struct vsp1_entity_operations lut_entity_ops = {
 188        .configure_stream = lut_configure_stream,
 189        .configure_frame = lut_configure_frame,
 190        .destroy = lut_destroy,
 191};
 192
 193/* -----------------------------------------------------------------------------
 194 * Initialization and Cleanup
 195 */
 196
 197struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 198{
 199        struct vsp1_lut *lut;
 200        int ret;
 201
 202        lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
 203        if (lut == NULL)
 204                return ERR_PTR(-ENOMEM);
 205
 206        spin_lock_init(&lut->lock);
 207
 208        lut->entity.ops = &lut_entity_ops;
 209        lut->entity.type = VSP1_ENTITY_LUT;
 210
 211        ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops,
 212                               MEDIA_ENT_F_PROC_VIDEO_LUT);
 213        if (ret < 0)
 214                return ERR_PTR(ret);
 215
 216        /*
 217         * Pre-allocate a body pool, with 3 bodies allowing a userspace update
 218         * before the hardware has committed a previous set of tables, handling
 219         * both the queued and pending dl entries.
 220         */
 221        lut->pool = vsp1_dl_body_pool_create(vsp1, 3, LUT_SIZE, 0);
 222        if (!lut->pool)
 223                return ERR_PTR(-ENOMEM);
 224
 225        /* Initialize the control handler. */
 226        v4l2_ctrl_handler_init(&lut->ctrls, 1);
 227        v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL);
 228
 229        lut->entity.subdev.ctrl_handler = &lut->ctrls;
 230
 231        if (lut->ctrls.error) {
 232                dev_err(vsp1->dev, "lut: failed to initialize controls\n");
 233                ret = lut->ctrls.error;
 234                vsp1_entity_destroy(&lut->entity);
 235                return ERR_PTR(ret);
 236        }
 237
 238        v4l2_ctrl_handler_setup(&lut->ctrls);
 239
 240        return lut;
 241}
 242