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