aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-07-10 11:03:30 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2013-12-11 06:25:20 -0500
commit989af88339db26345e23271dae1089d949c4a0f1 (patch)
tree76f13427804b04acc5e7ee0de2ef73db885f76f3
parenta626e64e0bee4fb26848dbed92223dde488f3d93 (diff)
[media] v4l: vsp1: Add LUT support
The Look-Up Table looks up values in 8-bit indexed tables separately for each color component. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/platform/vsp1/Makefile4
-rw-r--r--drivers/media/platform/vsp1/vsp1.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c11
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.c252
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.h38
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h1
-rw-r--r--include/linux/platform_data/vsp1.h3
-rw-r--r--include/uapi/linux/vsp1.h34
10 files changed, 344 insertions, 3 deletions
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile
index 45621cb8b2a6..151cecd0ea25 100644
--- a/drivers/media/platform/vsp1/Makefile
+++ b/drivers/media/platform/vsp1/Makefile
@@ -1,6 +1,6 @@
1vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o 1vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o
2vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o 2vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
3vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_sru.o 3vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o
4vsp1-y += vsp1_uds.o 4vsp1-y += vsp1_sru.o vsp1_uds.o
5 5
6obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o 6obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 2ab13f53b2a4..94d1b02680c5 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -30,6 +30,7 @@ struct device;
30struct vsp1_platform_data; 30struct vsp1_platform_data;
31struct vsp1_hsit; 31struct vsp1_hsit;
32struct vsp1_lif; 32struct vsp1_lif;
33struct vsp1_lut;
33struct vsp1_rwpf; 34struct vsp1_rwpf;
34struct vsp1_sru; 35struct vsp1_sru;
35struct vsp1_uds; 36struct vsp1_uds;
@@ -52,6 +53,7 @@ struct vsp1_device {
52 struct vsp1_hsit *hsi; 53 struct vsp1_hsit *hsi;
53 struct vsp1_hsit *hst; 54 struct vsp1_hsit *hst;
54 struct vsp1_lif *lif; 55 struct vsp1_lif *lif;
56 struct vsp1_lut *lut;
55 struct vsp1_rwpf *rpf[VPS1_MAX_RPF]; 57 struct vsp1_rwpf *rpf[VPS1_MAX_RPF];
56 struct vsp1_sru *sru; 58 struct vsp1_sru *sru;
57 struct vsp1_uds *uds[VPS1_MAX_UDS]; 59 struct vsp1_uds *uds[VPS1_MAX_UDS];
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 6f8295128704..0df0a994e575 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -22,6 +22,7 @@
22#include "vsp1.h" 22#include "vsp1.h"
23#include "vsp1_hsit.h" 23#include "vsp1_hsit.h"
24#include "vsp1_lif.h" 24#include "vsp1_lif.h"
25#include "vsp1_lut.h"
25#include "vsp1_rwpf.h" 26#include "vsp1_rwpf.h"
26#include "vsp1_sru.h" 27#include "vsp1_sru.h"
27#include "vsp1_uds.h" 28#include "vsp1_uds.h"
@@ -180,6 +181,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
180 list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); 181 list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
181 } 182 }
182 183
184 if (vsp1->pdata->features & VSP1_HAS_LUT) {
185 vsp1->lut = vsp1_lut_create(vsp1);
186 if (IS_ERR(vsp1->lut)) {
187 ret = PTR_ERR(vsp1->lut);
188 goto done;
189 }
190
191 list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
192 }
193
183 for (i = 0; i < vsp1->pdata->rpf_count; ++i) { 194 for (i = 0; i < vsp1->pdata->rpf_count; ++i) {
184 struct vsp1_rwpf *rpf; 195 struct vsp1_rwpf *rpf;
185 196
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index b11e5a6ffe04..0226e47df6d9 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -126,6 +126,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
126 { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE }, 126 { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE },
127 { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE }, 127 { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE },
128 { VI6_DPR_NODE_LIF, 0 }, 128 { VI6_DPR_NODE_LIF, 0 },
129 { VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE },
129 { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) }, 130 { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) },
130 { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) }, 131 { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) },
131 { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, 132 { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) },
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 08e44801ec9d..e152798d7f38 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -23,6 +23,7 @@ enum vsp1_entity_type {
23 VSP1_ENTITY_HSI, 23 VSP1_ENTITY_HSI,
24 VSP1_ENTITY_HST, 24 VSP1_ENTITY_HST,
25 VSP1_ENTITY_LIF, 25 VSP1_ENTITY_LIF,
26 VSP1_ENTITY_LUT,
26 VSP1_ENTITY_RPF, 27 VSP1_ENTITY_RPF,
27 VSP1_ENTITY_SRU, 28 VSP1_ENTITY_SRU,
28 VSP1_ENTITY_UDS, 29 VSP1_ENTITY_UDS,
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
new file mode 100644
index 000000000000..4e9dc7c86ef8
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -0,0 +1,252 @@
1/*
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"
21#include "vsp1_lut.h"
22
23#define LUT_MIN_SIZE 4U
24#define LUT_MAX_SIZE 8190U
25
26/* -----------------------------------------------------------------------------
27 * Device Access
28 */
29
30static inline u32 vsp1_lut_read(struct vsp1_lut *lut, u32 reg)
31{
32 return vsp1_read(lut->entity.vsp1, reg);
33}
34
35static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
36{
37 vsp1_write(lut->entity.vsp1, reg, data);
38}
39
40/* -----------------------------------------------------------------------------
41 * V4L2 Subdevice Core Operations
42 */
43
44static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config)
45{
46 memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut,
47 sizeof(config->lut));
48}
49
50static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
51{
52 struct vsp1_lut *lut = to_lut(subdev);
53
54 switch (cmd) {
55 case VIDIOC_VSP1_LUT_CONFIG:
56 lut_configure(lut, arg);
57 return 0;
58
59 default:
60 return -ENOIOCTLCMD;
61 }
62}
63
64/* -----------------------------------------------------------------------------
65 * V4L2 Subdevice Video Operations
66 */
67
68static int lut_s_stream(struct v4l2_subdev *subdev, int enable)
69{
70 struct vsp1_lut *lut = to_lut(subdev);
71
72 if (!enable)
73 return 0;
74
75 vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
76
77 return 0;
78}
79
80/* -----------------------------------------------------------------------------
81 * V4L2 Subdevice Pad Operations
82 */
83
84static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
85 struct v4l2_subdev_fh *fh,
86 struct v4l2_subdev_mbus_code_enum *code)
87{
88 static const unsigned int codes[] = {
89 V4L2_MBUS_FMT_ARGB8888_1X32,
90 V4L2_MBUS_FMT_AHSV8888_1X32,
91 V4L2_MBUS_FMT_AYUV8_1X32,
92 };
93 struct v4l2_mbus_framefmt *format;
94
95 if (code->pad == LUT_PAD_SINK) {
96 if (code->index >= ARRAY_SIZE(codes))
97 return -EINVAL;
98
99 code->code = codes[code->index];
100 } else {
101 /* The LUT can't perform format conversion, the sink format is
102 * always identical to the source format.
103 */
104 if (code->index)
105 return -EINVAL;
106
107 format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK);
108 code->code = format->code;
109 }
110
111 return 0;
112}
113
114static int lut_enum_frame_size(struct v4l2_subdev *subdev,
115 struct v4l2_subdev_fh *fh,
116 struct v4l2_subdev_frame_size_enum *fse)
117{
118 struct v4l2_mbus_framefmt *format;
119
120 format = v4l2_subdev_get_try_format(fh, fse->pad);
121
122 if (fse->index || fse->code != format->code)
123 return -EINVAL;
124
125 if (fse->pad == LUT_PAD_SINK) {
126 fse->min_width = LUT_MIN_SIZE;
127 fse->max_width = LUT_MAX_SIZE;
128 fse->min_height = LUT_MIN_SIZE;
129 fse->max_height = LUT_MAX_SIZE;
130 } else {
131 /* The size on the source pad are fixed and always identical to
132 * the size on the sink pad.
133 */
134 fse->min_width = format->width;
135 fse->max_width = format->width;
136 fse->min_height = format->height;
137 fse->max_height = format->height;
138 }
139
140 return 0;
141}
142
143static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
144 struct v4l2_subdev_format *fmt)
145{
146 struct vsp1_lut *lut = to_lut(subdev);
147
148 fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad,
149 fmt->which);
150
151 return 0;
152}
153
154static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
155 struct v4l2_subdev_format *fmt)
156{
157 struct vsp1_lut *lut = to_lut(subdev);
158 struct v4l2_mbus_framefmt *format;
159
160 /* Default to YUV if the requested format is not supported. */
161 if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
162 fmt->format.code != V4L2_MBUS_FMT_AHSV8888_1X32 &&
163 fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
164 fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
165
166 format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad,
167 fmt->which);
168
169 if (fmt->pad == LUT_PAD_SOURCE) {
170 /* The LUT output format can't be modified. */
171 fmt->format = *format;
172 return 0;
173 }
174
175 format->width = clamp_t(unsigned int, fmt->format.width,
176 LUT_MIN_SIZE, LUT_MAX_SIZE);
177 format->height = clamp_t(unsigned int, fmt->format.height,
178 LUT_MIN_SIZE, LUT_MAX_SIZE);
179 format->field = V4L2_FIELD_NONE;
180 format->colorspace = V4L2_COLORSPACE_SRGB;
181
182 fmt->format = *format;
183
184 /* Propagate the format to the source pad. */
185 format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE,
186 fmt->which);
187 *format = fmt->format;
188
189 return 0;
190}
191
192/* -----------------------------------------------------------------------------
193 * V4L2 Subdevice Operations
194 */
195
196static struct v4l2_subdev_core_ops lut_core_ops = {
197 .ioctl = lut_ioctl,
198};
199
200static struct v4l2_subdev_video_ops lut_video_ops = {
201 .s_stream = lut_s_stream,
202};
203
204static struct v4l2_subdev_pad_ops lut_pad_ops = {
205 .enum_mbus_code = lut_enum_mbus_code,
206 .enum_frame_size = lut_enum_frame_size,
207 .get_fmt = lut_get_format,
208 .set_fmt = lut_set_format,
209};
210
211static struct v4l2_subdev_ops lut_ops = {
212 .core = &lut_core_ops,
213 .video = &lut_video_ops,
214 .pad = &lut_pad_ops,
215};
216
217/* -----------------------------------------------------------------------------
218 * Initialization and Cleanup
219 */
220
221struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
222{
223 struct v4l2_subdev *subdev;
224 struct vsp1_lut *lut;
225 int ret;
226
227 lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
228 if (lut == NULL)
229 return ERR_PTR(-ENOMEM);
230
231 lut->entity.type = VSP1_ENTITY_LUT;
232 lut->entity.id = VI6_DPR_NODE_LUT;
233
234 ret = vsp1_entity_init(vsp1, &lut->entity, 2);
235 if (ret < 0)
236 return ERR_PTR(ret);
237
238 /* Initialize the V4L2 subdev. */
239 subdev = &lut->entity.subdev;
240 v4l2_subdev_init(subdev, &lut_ops);
241
242 subdev->entity.ops = &vsp1_media_ops;
243 subdev->internal_ops = &vsp1_subdev_internal_ops;
244 snprintf(subdev->name, sizeof(subdev->name), "%s lut",
245 dev_name(vsp1->dev));
246 v4l2_set_subdevdata(subdev, lut);
247 subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
248
249 vsp1_entity_init_formats(subdev, NULL);
250
251 return lut;
252}
diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h
new file mode 100644
index 000000000000..f92ffb867350
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_lut.h
@@ -0,0 +1,38 @@
1/*
2 * vsp1_lut.h -- 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#ifndef __VSP1_LUT_H__
14#define __VSP1_LUT_H__
15
16#include <media/media-entity.h>
17#include <media/v4l2-subdev.h>
18
19#include "vsp1_entity.h"
20
21struct vsp1_device;
22
23#define LUT_PAD_SINK 0
24#define LUT_PAD_SOURCE 1
25
26struct vsp1_lut {
27 struct vsp1_entity entity;
28 u32 lut[256];
29};
30
31static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev)
32{
33 return container_of(subdev, struct vsp1_lut, entity.subdev);
34}
35
36struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1);
37
38#endif /* __VSP1_LUT_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 530cc61cfcd5..28650806c20f 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -425,6 +425,7 @@
425 */ 425 */
426 426
427#define VI6_LUT_CTRL 0x2800 427#define VI6_LUT_CTRL 0x2800
428#define VI6_LUT_CTRL_EN (1 << 0)
428 429
429/* ----------------------------------------------------------------------------- 430/* -----------------------------------------------------------------------------
430 * CLU Control Registers 431 * CLU Control Registers
diff --git a/include/linux/platform_data/vsp1.h b/include/linux/platform_data/vsp1.h
index 27c0ede1a53f..63170e2614b3 100644
--- a/include/linux/platform_data/vsp1.h
+++ b/include/linux/platform_data/vsp1.h
@@ -14,7 +14,8 @@
14#define __PLATFORM_VSP1_H__ 14#define __PLATFORM_VSP1_H__
15 15
16#define VSP1_HAS_LIF (1 << 0) 16#define VSP1_HAS_LIF (1 << 0)
17#define VSP1_HAS_SRU (1 << 1) 17#define VSP1_HAS_LUT (1 << 1)
18#define VSP1_HAS_SRU (1 << 2)
18 19
19struct vsp1_platform_data { 20struct vsp1_platform_data {
20 unsigned int features; 21 unsigned int features;
diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h
new file mode 100644
index 000000000000..e18858f6e865
--- /dev/null
+++ b/include/uapi/linux/vsp1.h
@@ -0,0 +1,34 @@
1/*
2 * vsp1.h
3 *
4 * Renesas R-Car VSP1 - User-space API
5 *
6 * Copyright (C) 2013 Renesas Corporation
7 *
8 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __VSP1_USER_H__
16#define __VSP1_USER_H__
17
18#include <linux/types.h>
19#include <linux/videodev2.h>
20
21/*
22 * Private IOCTLs
23 *
24 * VIDIOC_VSP1_LUT_CONFIG - Configure the lookup table
25 */
26
27#define VIDIOC_VSP1_LUT_CONFIG \
28 _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config)
29
30struct vsp1_lut_config {
31 u32 lut[256];
32};
33
34#endif /* __VSP1_USER_H__ */