123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- /*
- * vsp1_hgt.c -- R-Car VSP1 Histogram Generator 2D
- *
- * Copyright (C) 2016 Renesas Electronics Corporation
- *
- * Contact: Niklas Söderlund (niklas.soderlund@ragnatech.se)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
- #include <linux/device.h>
- #include <linux/gfp.h>
- #include <media/v4l2-subdev.h>
- #include <media/videobuf2-vmalloc.h>
- #include "vsp1.h"
- #include "vsp1_dl.h"
- #include "vsp1_hgt.h"
- #define HGT_DATA_SIZE ((2 + 6 * 32) * 4)
- /* -----------------------------------------------------------------------------
- * Device Access
- */
- static inline u32 vsp1_hgt_read(struct vsp1_hgt *hgt, u32 reg)
- {
- return vsp1_read(hgt->histo.entity.vsp1, reg);
- }
- static inline void vsp1_hgt_write(struct vsp1_hgt *hgt, struct vsp1_dl_list *dl,
- u32 reg, u32 data)
- {
- vsp1_dl_list_write(dl, reg, data);
- }
- /* -----------------------------------------------------------------------------
- * Frame End Handler
- */
- void vsp1_hgt_frame_end(struct vsp1_entity *entity)
- {
- struct vsp1_hgt *hgt = to_hgt(&entity->subdev);
- struct vsp1_histogram_buffer *buf;
- unsigned int m;
- unsigned int n;
- u32 *data;
- buf = vsp1_histogram_buffer_get(&hgt->histo);
- if (!buf)
- return;
- data = buf->addr;
- *data++ = vsp1_hgt_read(hgt, VI6_HGT_MAXMIN);
- *data++ = vsp1_hgt_read(hgt, VI6_HGT_SUM);
- for (m = 0; m < 6; ++m)
- for (n = 0; n < 32; ++n)
- *data++ = vsp1_hgt_read(hgt, VI6_HGT_HISTO(m, n));
- vsp1_histogram_buffer_complete(&hgt->histo, buf, HGT_DATA_SIZE);
- }
- /* -----------------------------------------------------------------------------
- * Controls
- */
- #define V4L2_CID_VSP1_HGT_HUE_AREAS (V4L2_CID_USER_BASE | 0x1001)
- static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl *ctrl)
- {
- const u8 *values = ctrl->p_new.p_u8;
- unsigned int i;
- /*
- * The hardware has constraints on the hue area boundaries beyond the
- * control min, max and step. The values must match one of the following
- * expressions.
- *
- * 0L <= 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U
- * 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U <= 0L
- *
- * Start by verifying the common part...
- */
- for (i = 1; i < (HGT_NUM_HUE_AREAS * 2) - 1; ++i) {
- if (values[i] > values[i+1])
- return -EINVAL;
- }
- /* ... and handle 0L separately. */
- if (values[0] > values[1] && values[11] > values[0])
- return -EINVAL;
- return 0;
- }
- static int hgt_hue_areas_s_ctrl(struct v4l2_ctrl *ctrl)
- {
- struct vsp1_hgt *hgt = container_of(ctrl->handler, struct vsp1_hgt,
- ctrls);
- memcpy(hgt->hue_areas, ctrl->p_new.p_u8, sizeof(hgt->hue_areas));
- return 0;
- }
- static const struct v4l2_ctrl_ops hgt_hue_areas_ctrl_ops = {
- .try_ctrl = hgt_hue_areas_try_ctrl,
- .s_ctrl = hgt_hue_areas_s_ctrl,
- };
- static const struct v4l2_ctrl_config hgt_hue_areas = {
- .ops = &hgt_hue_areas_ctrl_ops,
- .id = V4L2_CID_VSP1_HGT_HUE_AREAS,
- .name = "Boundary Values for Hue Area",
- .type = V4L2_CTRL_TYPE_U8,
- .min = 0,
- .max = 255,
- .def = 0,
- .step = 1,
- .dims = { 12 },
- };
- /* -----------------------------------------------------------------------------
- * VSP1 Entity Operations
- */
- static void hgt_configure(struct vsp1_entity *entity,
- struct vsp1_pipeline *pipe,
- struct vsp1_dl_list *dl,
- enum vsp1_entity_params params)
- {
- struct vsp1_hgt *hgt = to_hgt(&entity->subdev);
- struct v4l2_rect *compose;
- struct v4l2_rect *crop;
- unsigned int hratio;
- unsigned int vratio;
- u8 lower;
- u8 upper;
- unsigned int i;
- if (params != VSP1_ENTITY_PARAMS_INIT)
- return;
- crop = vsp1_entity_get_pad_selection(entity, entity->config,
- HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
- compose = vsp1_entity_get_pad_selection(entity, entity->config,
- HISTO_PAD_SINK,
- V4L2_SEL_TGT_COMPOSE);
- vsp1_hgt_write(hgt, dl, VI6_HGT_REGRST, VI6_HGT_REGRST_RCLEA);
- vsp1_hgt_write(hgt, dl, VI6_HGT_OFFSET,
- (crop->left << VI6_HGT_OFFSET_HOFFSET_SHIFT) |
- (crop->top << VI6_HGT_OFFSET_VOFFSET_SHIFT));
- vsp1_hgt_write(hgt, dl, VI6_HGT_SIZE,
- (crop->width << VI6_HGT_SIZE_HSIZE_SHIFT) |
- (crop->height << VI6_HGT_SIZE_VSIZE_SHIFT));
- mutex_lock(hgt->ctrls.lock);
- for (i = 0; i < HGT_NUM_HUE_AREAS; ++i) {
- lower = hgt->hue_areas[i*2 + 0];
- upper = hgt->hue_areas[i*2 + 1];
- vsp1_hgt_write(hgt, dl, VI6_HGT_HUE_AREA(i),
- (lower << VI6_HGT_HUE_AREA_LOWER_SHIFT) |
- (upper << VI6_HGT_HUE_AREA_UPPER_SHIFT));
- }
- mutex_unlock(hgt->ctrls.lock);
- hratio = crop->width * 2 / compose->width / 3;
- vratio = crop->height * 2 / compose->height / 3;
- vsp1_hgt_write(hgt, dl, VI6_HGT_MODE,
- (hratio << VI6_HGT_MODE_HRATIO_SHIFT) |
- (vratio << VI6_HGT_MODE_VRATIO_SHIFT));
- }
- static const struct vsp1_entity_operations hgt_entity_ops = {
- .configure = hgt_configure,
- .destroy = vsp1_histogram_destroy,
- };
- /* -----------------------------------------------------------------------------
- * Initialization and Cleanup
- */
- static const unsigned int hgt_mbus_formats[] = {
- MEDIA_BUS_FMT_AHSV8888_1X32,
- };
- struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1)
- {
- struct vsp1_hgt *hgt;
- int ret;
- hgt = devm_kzalloc(vsp1->dev, sizeof(*hgt), GFP_KERNEL);
- if (hgt == NULL)
- return ERR_PTR(-ENOMEM);
- /* Initialize the control handler. */
- v4l2_ctrl_handler_init(&hgt->ctrls, 1);
- v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL);
- hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls;
- /* Initialize the video device and queue for statistics data. */
- ret = vsp1_histogram_init(vsp1, &hgt->histo, VSP1_ENTITY_HGT, "hgt",
- &hgt_entity_ops, hgt_mbus_formats,
- ARRAY_SIZE(hgt_mbus_formats),
- HGT_DATA_SIZE, V4L2_META_FMT_VSP1_HGT);
- if (ret < 0) {
- vsp1_entity_destroy(&hgt->histo.entity);
- return ERR_PTR(ret);
- }
- v4l2_ctrl_handler_setup(&hgt->ctrls);
- return hgt;
- }
|