blob: c779648882ab584fa262969211726f30da73a460 [file] [log] [blame]
Laurent Pinchart989af882013-07-10 12:03:30 -03001/*
2 * vsp1_lut.c -- R-Car VSP1 Look-Up Table
3 *
4 * Copyright (C) 2013 Renesas 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#include <linux/vsp1.h>
17
18#include <media/v4l2-subdev.h>
19
20#include "vsp1.h"
Laurent Pinchart5e8dbbf2015-11-22 20:29:25 -020021#include "vsp1_dl.h"
Laurent Pinchart989af882013-07-10 12:03:30 -030022#include "vsp1_lut.h"
23
24#define LUT_MIN_SIZE 4U
25#define LUT_MAX_SIZE 8190U
26
27/* -----------------------------------------------------------------------------
28 * Device Access
29 */
30
Laurent Pinchart5e8dbbf2015-11-22 20:29:25 -020031static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl,
32 u32 reg, u32 data)
Laurent Pinchart989af882013-07-10 12:03:30 -030033{
Laurent Pinchart5e8dbbf2015-11-22 20:29:25 -020034 vsp1_dl_list_write(dl, reg, data);
Laurent Pinchart989af882013-07-10 12:03:30 -030035}
36
37/* -----------------------------------------------------------------------------
38 * V4L2 Subdevice Core Operations
39 */
40
Laurent Pinchart7b905f02015-11-17 13:10:26 -020041static void lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config)
Laurent Pinchart989af882013-07-10 12:03:30 -030042{
43 memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut,
44 sizeof(config->lut));
45}
46
47static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
48{
49 struct vsp1_lut *lut = to_lut(subdev);
50
51 switch (cmd) {
52 case VIDIOC_VSP1_LUT_CONFIG:
Laurent Pinchart7b905f02015-11-17 13:10:26 -020053 lut_set_table(lut, arg);
Laurent Pinchart989af882013-07-10 12:03:30 -030054 return 0;
55
56 default:
57 return -ENOIOCTLCMD;
58 }
59}
60
61/* -----------------------------------------------------------------------------
Laurent Pinchart989af882013-07-10 12:03:30 -030062 * V4L2 Subdevice Pad Operations
63 */
64
65static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
Hans Verkuilf7234132015-03-04 01:47:54 -080066 struct v4l2_subdev_pad_config *cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -030067 struct v4l2_subdev_mbus_code_enum *code)
68{
69 static const unsigned int codes[] = {
Boris BREZILLON27ffaeb2014-11-10 14:28:31 -030070 MEDIA_BUS_FMT_ARGB8888_1X32,
71 MEDIA_BUS_FMT_AHSV8888_1X32,
72 MEDIA_BUS_FMT_AYUV8_1X32,
Laurent Pinchart989af882013-07-10 12:03:30 -030073 };
Laurent Pinchart989af882013-07-10 12:03:30 -030074
Laurent Pinchart6ad9ba92016-02-24 20:25:42 -030075 return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
76 ARRAY_SIZE(codes));
Laurent Pinchart989af882013-07-10 12:03:30 -030077}
78
79static int lut_enum_frame_size(struct v4l2_subdev *subdev,
Hans Verkuilf7234132015-03-04 01:47:54 -080080 struct v4l2_subdev_pad_config *cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -030081 struct v4l2_subdev_frame_size_enum *fse)
82{
Laurent Pinchart076e8342016-02-24 20:25:42 -030083 return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE,
84 LUT_MIN_SIZE, LUT_MAX_SIZE,
85 LUT_MAX_SIZE);
Laurent Pinchart989af882013-07-10 12:03:30 -030086}
87
Laurent Pinchart1bd0a1b2015-11-01 15:18:32 -020088static int lut_set_format(struct v4l2_subdev *subdev,
89 struct v4l2_subdev_pad_config *cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -030090 struct v4l2_subdev_format *fmt)
91{
92 struct vsp1_lut *lut = to_lut(subdev);
Laurent Pincharte790c3c2015-11-15 19:14:22 -020093 struct v4l2_subdev_pad_config *config;
Laurent Pinchart989af882013-07-10 12:03:30 -030094 struct v4l2_mbus_framefmt *format;
95
Laurent Pincharte790c3c2015-11-15 19:14:22 -020096 config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which);
97 if (!config)
98 return -EINVAL;
99
Laurent Pinchart989af882013-07-10 12:03:30 -0300100 /* Default to YUV if the requested format is not supported. */
Boris BREZILLON27ffaeb2014-11-10 14:28:31 -0300101 if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
102 fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
103 fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
104 fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
Laurent Pinchart989af882013-07-10 12:03:30 -0300105
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200106 format = vsp1_entity_get_pad_format(&lut->entity, config, fmt->pad);
Laurent Pinchart989af882013-07-10 12:03:30 -0300107
108 if (fmt->pad == LUT_PAD_SOURCE) {
109 /* The LUT output format can't be modified. */
110 fmt->format = *format;
111 return 0;
112 }
113
114 format->width = clamp_t(unsigned int, fmt->format.width,
115 LUT_MIN_SIZE, LUT_MAX_SIZE);
116 format->height = clamp_t(unsigned int, fmt->format.height,
117 LUT_MIN_SIZE, LUT_MAX_SIZE);
118 format->field = V4L2_FIELD_NONE;
119 format->colorspace = V4L2_COLORSPACE_SRGB;
120
121 fmt->format = *format;
122
123 /* Propagate the format to the source pad. */
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200124 format = vsp1_entity_get_pad_format(&lut->entity, config,
125 LUT_PAD_SOURCE);
Laurent Pinchart989af882013-07-10 12:03:30 -0300126 *format = fmt->format;
127
128 return 0;
129}
130
131/* -----------------------------------------------------------------------------
132 * V4L2 Subdevice Operations
133 */
134
135static struct v4l2_subdev_core_ops lut_core_ops = {
136 .ioctl = lut_ioctl,
137};
138
Laurent Pinchart989af882013-07-10 12:03:30 -0300139static struct v4l2_subdev_pad_ops lut_pad_ops = {
Laurent Pinchart0efdf0f2015-11-15 20:09:08 -0200140 .init_cfg = vsp1_entity_init_cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -0300141 .enum_mbus_code = lut_enum_mbus_code,
142 .enum_frame_size = lut_enum_frame_size,
Laurent Pinchart3f557222016-02-24 21:10:13 -0300143 .get_fmt = vsp1_subdev_get_pad_format,
Laurent Pinchart989af882013-07-10 12:03:30 -0300144 .set_fmt = lut_set_format,
145};
146
147static struct v4l2_subdev_ops lut_ops = {
148 .core = &lut_core_ops,
Laurent Pinchart989af882013-07-10 12:03:30 -0300149 .pad = &lut_pad_ops,
150};
151
152/* -----------------------------------------------------------------------------
Laurent Pinchart7b905f02015-11-17 13:10:26 -0200153 * VSP1 Entity Operations
154 */
155
Laurent Pinchart83dd0192016-01-14 14:17:32 -0200156static void lut_configure(struct vsp1_entity *entity,
157 struct vsp1_pipeline *pipe,
158 struct vsp1_dl_list *dl)
Laurent Pinchart7b905f02015-11-17 13:10:26 -0200159{
160 struct vsp1_lut *lut = to_lut(&entity->subdev);
161
Laurent Pinchart5e8dbbf2015-11-22 20:29:25 -0200162 vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
Laurent Pinchart7b905f02015-11-17 13:10:26 -0200163}
164
165static const struct vsp1_entity_operations lut_entity_ops = {
166 .configure = lut_configure,
167};
168
169/* -----------------------------------------------------------------------------
Laurent Pinchart989af882013-07-10 12:03:30 -0300170 * Initialization and Cleanup
171 */
172
173struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
174{
Laurent Pinchart989af882013-07-10 12:03:30 -0300175 struct vsp1_lut *lut;
176 int ret;
177
178 lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
179 if (lut == NULL)
180 return ERR_PTR(-ENOMEM);
181
Laurent Pinchart7b905f02015-11-17 13:10:26 -0200182 lut->entity.ops = &lut_entity_ops;
Laurent Pinchart989af882013-07-10 12:03:30 -0300183 lut->entity.type = VSP1_ENTITY_LUT;
Laurent Pinchart989af882013-07-10 12:03:30 -0300184
Laurent Pinchart823329d2015-11-15 19:42:01 -0200185 ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops);
Laurent Pinchart989af882013-07-10 12:03:30 -0300186 if (ret < 0)
187 return ERR_PTR(ret);
188
Laurent Pinchart989af882013-07-10 12:03:30 -0300189 return lut;
190}