linux/drivers/media/platform/vsp1/vsp1_hgo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * vsp1_hgo.c  --  R-Car VSP1 Histogram Generator 1D
   4 *
   5 * Copyright (C) 2016 Renesas Electronics 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#include <media/videobuf2-vmalloc.h>
  15
  16#include "vsp1.h"
  17#include "vsp1_dl.h"
  18#include "vsp1_hgo.h"
  19
  20#define HGO_DATA_SIZE                           ((2 + 256) * 4)
  21
  22/* -----------------------------------------------------------------------------
  23 * Device Access
  24 */
  25
  26static inline u32 vsp1_hgo_read(struct vsp1_hgo *hgo, u32 reg)
  27{
  28        return vsp1_read(hgo->histo.entity.vsp1, reg);
  29}
  30
  31static inline void vsp1_hgo_write(struct vsp1_hgo *hgo,
  32                                  struct vsp1_dl_body *dlb, u32 reg, u32 data)
  33{
  34        vsp1_dl_body_write(dlb, reg, data);
  35}
  36
  37/* -----------------------------------------------------------------------------
  38 * Frame End Handler
  39 */
  40
  41void vsp1_hgo_frame_end(struct vsp1_entity *entity)
  42{
  43        struct vsp1_hgo *hgo = to_hgo(&entity->subdev);
  44        struct vsp1_histogram_buffer *buf;
  45        unsigned int i;
  46        size_t size;
  47        u32 *data;
  48
  49        buf = vsp1_histogram_buffer_get(&hgo->histo);
  50        if (!buf)
  51                return;
  52
  53        data = buf->addr;
  54
  55        if (hgo->num_bins == 256) {
  56                *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
  57                *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
  58
  59                for (i = 0; i < 256; ++i) {
  60                        vsp1_write(hgo->histo.entity.vsp1,
  61                                   VI6_HGO_EXT_HIST_ADDR, i);
  62                        *data++ = vsp1_hgo_read(hgo, VI6_HGO_EXT_HIST_DATA);
  63                }
  64
  65                size = (2 + 256) * sizeof(u32);
  66        } else if (hgo->max_rgb) {
  67                *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
  68                *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
  69
  70                for (i = 0; i < 64; ++i)
  71                        *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i));
  72
  73                size = (2 + 64) * sizeof(u32);
  74        } else {
  75                *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_MAXMIN);
  76                *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
  77                *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_MAXMIN);
  78
  79                *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_SUM);
  80                *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
  81                *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_SUM);
  82
  83                for (i = 0; i < 64; ++i) {
  84                        data[i] = vsp1_hgo_read(hgo, VI6_HGO_R_HISTO(i));
  85                        data[i+64] = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i));
  86                        data[i+128] = vsp1_hgo_read(hgo, VI6_HGO_B_HISTO(i));
  87                }
  88
  89                size = (6 + 64 * 3) * sizeof(u32);
  90        }
  91
  92        vsp1_histogram_buffer_complete(&hgo->histo, buf, size);
  93}
  94
  95/* -----------------------------------------------------------------------------
  96 * Controls
  97 */
  98
  99#define V4L2_CID_VSP1_HGO_MAX_RGB               (V4L2_CID_USER_BASE | 0x1001)
 100#define V4L2_CID_VSP1_HGO_NUM_BINS              (V4L2_CID_USER_BASE | 0x1002)
 101
 102static const struct v4l2_ctrl_config hgo_max_rgb_control = {
 103        .id = V4L2_CID_VSP1_HGO_MAX_RGB,
 104        .name = "Maximum RGB Mode",
 105        .type = V4L2_CTRL_TYPE_BOOLEAN,
 106        .min = 0,
 107        .max = 1,
 108        .def = 0,
 109        .step = 1,
 110        .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
 111};
 112
 113static const s64 hgo_num_bins[] = {
 114        64, 256,
 115};
 116
 117static const struct v4l2_ctrl_config hgo_num_bins_control = {
 118        .id = V4L2_CID_VSP1_HGO_NUM_BINS,
 119        .name = "Number of Bins",
 120        .type = V4L2_CTRL_TYPE_INTEGER_MENU,
 121        .min = 0,
 122        .max = 1,
 123        .def = 0,
 124        .qmenu_int = hgo_num_bins,
 125        .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
 126};
 127
 128/* -----------------------------------------------------------------------------
 129 * VSP1 Entity Operations
 130 */
 131
 132static void hgo_configure_stream(struct vsp1_entity *entity,
 133                                 struct vsp1_pipeline *pipe,
 134                                 struct vsp1_dl_list *dl,
 135                                 struct vsp1_dl_body *dlb)
 136{
 137        struct vsp1_hgo *hgo = to_hgo(&entity->subdev);
 138        struct v4l2_rect *compose;
 139        struct v4l2_rect *crop;
 140        unsigned int hratio;
 141        unsigned int vratio;
 142
 143        crop = vsp1_entity_get_pad_selection(entity, entity->config,
 144                                             HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
 145        compose = vsp1_entity_get_pad_selection(entity, entity->config,
 146                                                HISTO_PAD_SINK,
 147                                                V4L2_SEL_TGT_COMPOSE);
 148
 149        vsp1_hgo_write(hgo, dlb, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA);
 150
 151        vsp1_hgo_write(hgo, dlb, VI6_HGO_OFFSET,
 152                       (crop->left << VI6_HGO_OFFSET_HOFFSET_SHIFT) |
 153                       (crop->top << VI6_HGO_OFFSET_VOFFSET_SHIFT));
 154        vsp1_hgo_write(hgo, dlb, VI6_HGO_SIZE,
 155                       (crop->width << VI6_HGO_SIZE_HSIZE_SHIFT) |
 156                       (crop->height << VI6_HGO_SIZE_VSIZE_SHIFT));
 157
 158        mutex_lock(hgo->ctrls.handler.lock);
 159        hgo->max_rgb = hgo->ctrls.max_rgb->cur.val;
 160        if (hgo->ctrls.num_bins)
 161                hgo->num_bins = hgo_num_bins[hgo->ctrls.num_bins->cur.val];
 162        mutex_unlock(hgo->ctrls.handler.lock);
 163
 164        hratio = crop->width * 2 / compose->width / 3;
 165        vratio = crop->height * 2 / compose->height / 3;
 166        vsp1_hgo_write(hgo, dlb, VI6_HGO_MODE,
 167                       (hgo->num_bins == 256 ? VI6_HGO_MODE_STEP : 0) |
 168                       (hgo->max_rgb ? VI6_HGO_MODE_MAXRGB : 0) |
 169                       (hratio << VI6_HGO_MODE_HRATIO_SHIFT) |
 170                       (vratio << VI6_HGO_MODE_VRATIO_SHIFT));
 171}
 172
 173static const struct vsp1_entity_operations hgo_entity_ops = {
 174        .configure_stream = hgo_configure_stream,
 175        .destroy = vsp1_histogram_destroy,
 176};
 177
 178/* -----------------------------------------------------------------------------
 179 * Initialization and Cleanup
 180 */
 181
 182static const unsigned int hgo_mbus_formats[] = {
 183        MEDIA_BUS_FMT_AYUV8_1X32,
 184        MEDIA_BUS_FMT_ARGB8888_1X32,
 185        MEDIA_BUS_FMT_AHSV8888_1X32,
 186};
 187
 188struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
 189{
 190        struct vsp1_hgo *hgo;
 191        int ret;
 192
 193        hgo = devm_kzalloc(vsp1->dev, sizeof(*hgo), GFP_KERNEL);
 194        if (hgo == NULL)
 195                return ERR_PTR(-ENOMEM);
 196
 197        /* Initialize the control handler. */
 198        v4l2_ctrl_handler_init(&hgo->ctrls.handler,
 199                               vsp1->info->gen == 3 ? 2 : 1);
 200        hgo->ctrls.max_rgb = v4l2_ctrl_new_custom(&hgo->ctrls.handler,
 201                                                  &hgo_max_rgb_control, NULL);
 202        if (vsp1->info->gen == 3)
 203                hgo->ctrls.num_bins =
 204                        v4l2_ctrl_new_custom(&hgo->ctrls.handler,
 205                                             &hgo_num_bins_control, NULL);
 206
 207        hgo->max_rgb = false;
 208        hgo->num_bins = 64;
 209
 210        hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler;
 211
 212        /* Initialize the video device and queue for statistics data. */
 213        ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
 214                                  &hgo_entity_ops, hgo_mbus_formats,
 215                                  ARRAY_SIZE(hgo_mbus_formats),
 216                                  HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
 217        if (ret < 0) {
 218                vsp1_entity_destroy(&hgo->histo.entity);
 219                return ERR_PTR(ret);
 220        }
 221
 222        return hgo;
 223}
 224