aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-tv
diff options
context:
space:
mode:
authorTomasz Stanislawski <t.stanislaws@samsung.com>2011-02-02 03:40:08 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:56:01 -0400
commitfef1c8d01847f05f01bf04dbae4409d72ed9a2cd (patch)
tree030cdac094e0cfd73aef91756861e326ef2b987d /drivers/media/video/s5p-tv
parent9a498400fede652a5ada51e74ae47bba99c7ed07 (diff)
[media] v4l: s5p-tv: add TV Mixer driver for Samsung S5P platform
Add driver for TV Mixer on Samsung platforms from S5P family. Mixer is responsible for merging images from three layers and passing result to the output. Drivers are using: - v4l2 framework - videobuf2 - runtime PM Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/s5p-tv')
-rw-r--r--drivers/media/video/s5p-tv/Kconfig16
-rw-r--r--drivers/media/video/s5p-tv/Makefile2
-rw-r--r--drivers/media/video/s5p-tv/mixer.h354
-rw-r--r--drivers/media/video/s5p-tv/mixer_drv.c487
-rw-r--r--drivers/media/video/s5p-tv/mixer_grp_layer.c185
-rw-r--r--drivers/media/video/s5p-tv/mixer_reg.c541
-rw-r--r--drivers/media/video/s5p-tv/mixer_video.c1006
-rw-r--r--drivers/media/video/s5p-tv/mixer_vp_layer.c211
-rw-r--r--drivers/media/video/s5p-tv/regs-mixer.h121
-rw-r--r--drivers/media/video/s5p-tv/regs-vp.h88
10 files changed, 3011 insertions, 0 deletions
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
index 9c1f6343f077..9c37dee7bc59 100644
--- a/drivers/media/video/s5p-tv/Kconfig
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -57,4 +57,20 @@ config VIDEO_SAMSUNG_S5P_SDO
57 subdev for use by other drivers. This driver requires 57 subdev for use by other drivers. This driver requires
58 hdmiphy driver to work correctly. 58 hdmiphy driver to work correctly.
59 59
60config VIDEO_SAMSUNG_S5P_MIXER
61 tristate "Samsung Mixer and Video Processor Driver"
62 depends on VIDEO_DEV && VIDEO_V4L2
63 depends on VIDEO_SAMSUNG_S5P_TV
64 select VIDEOBUF2_DMA_CONTIG
65 help
66 Say Y here if you want support for the Mixer in Samsung S5P SoCs.
67 This device produce image data to one of output interfaces.
68
69config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
70 bool "Enable debug for Mixer Driver"
71 depends on VIDEO_SAMSUNG_S5P_MIXER
72 default n
73 help
74 Enables debugging for Mixer driver.
75
60endif # VIDEO_SAMSUNG_S5P_TV 76endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
index c874d16be9fd..37e4c17663b4 100644
--- a/drivers/media/video/s5p-tv/Makefile
+++ b/drivers/media/video/s5p-tv/Makefile
@@ -12,4 +12,6 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
12s5p-hdmi-y += hdmi_drv.o 12s5p-hdmi-y += hdmi_drv.o
13obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o 13obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
14s5p-sdo-y += sdo_drv.o 14s5p-sdo-y += sdo_drv.o
15obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
16s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
15 17
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
new file mode 100644
index 000000000000..e2242243f63d
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer.h
@@ -0,0 +1,354 @@
1/*
2 * Samsung TV Mixer driver
3 *
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5 *
6 * Tomasz Stanislawski, <t.stanislaws@samsung.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
10 * by the Free Software Foundiation. either version 2 of the License,
11 * or (at your option) any later version
12 */
13
14#ifndef SAMSUNG_MIXER_H
15#define SAMSUNG_MIXER_H
16
17#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
18 #define DEBUG
19#endif
20
21#include <linux/fb.h>
22#include <linux/kernel.h>
23#include <linux/spinlock.h>
24#include <linux/wait.h>
25#include <media/v4l2-device.h>
26#include <media/videobuf2-core.h>
27
28#include "regs-mixer.h"
29
30/** maximum number of output interfaces */
31#define MXR_MAX_OUTPUTS 2
32/** maximum number of input interfaces (layers) */
33#define MXR_MAX_LAYERS 3
34#define MXR_DRIVER_NAME "s5p-mixer"
35/** maximal number of planes for every layer */
36#define MXR_MAX_PLANES 2
37
38#define MXR_ENABLE 1
39#define MXR_DISABLE 0
40
41/** description of a macroblock for packed formats */
42struct mxr_block {
43 /** vertical number of pixels in macroblock */
44 unsigned int width;
45 /** horizontal number of pixels in macroblock */
46 unsigned int height;
47 /** size of block in bytes */
48 unsigned int size;
49};
50
51/** description of supported format */
52struct mxr_format {
53 /** format name/mnemonic */
54 const char *name;
55 /** fourcc identifier */
56 u32 fourcc;
57 /** colorspace identifier */
58 enum v4l2_colorspace colorspace;
59 /** number of planes in image data */
60 int num_planes;
61 /** description of block for each plane */
62 struct mxr_block plane[MXR_MAX_PLANES];
63 /** number of subframes in image data */
64 int num_subframes;
65 /** specifies to which subframe belong given plane */
66 int plane2subframe[MXR_MAX_PLANES];
67 /** internal code, driver dependant */
68 unsigned long cookie;
69};
70
71/** description of crop configuration for image */
72struct mxr_crop {
73 /** width of layer in pixels */
74 unsigned int full_width;
75 /** height of layer in pixels */
76 unsigned int full_height;
77 /** horizontal offset of first pixel to be displayed */
78 unsigned int x_offset;
79 /** vertical offset of first pixel to be displayed */
80 unsigned int y_offset;
81 /** width of displayed data in pixels */
82 unsigned int width;
83 /** height of displayed data in pixels */
84 unsigned int height;
85 /** indicate which fields are present in buffer */
86 unsigned int field;
87};
88
89/** description of transformation from source to destination image */
90struct mxr_geometry {
91 /** cropping for source image */
92 struct mxr_crop src;
93 /** cropping for destination image */
94 struct mxr_crop dst;
95 /** layer-dependant description of horizontal scaling */
96 unsigned int x_ratio;
97 /** layer-dependant description of vertical scaling */
98 unsigned int y_ratio;
99};
100
101/** instance of a buffer */
102struct mxr_buffer {
103 /** common v4l buffer stuff -- must be first */
104 struct vb2_buffer vb;
105 /** node for layer's lists */
106 struct list_head list;
107};
108
109
110/** internal states of layer */
111enum mxr_layer_state {
112 /** layers is not shown */
113 MXR_LAYER_IDLE = 0,
114 /** state between STREAMON and hardware start */
115 MXR_LAYER_STREAMING_START,
116 /** layer is shown */
117 MXR_LAYER_STREAMING,
118 /** state before STREAMOFF is finished */
119 MXR_LAYER_STREAMING_FINISH,
120};
121
122/** forward declarations */
123struct mxr_device;
124struct mxr_layer;
125
126/** callback for layers operation */
127struct mxr_layer_ops {
128 /* TODO: try to port it to subdev API */
129 /** handler for resource release function */
130 void (*release)(struct mxr_layer *);
131 /** setting buffer to HW */
132 void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
133 /** setting format and geometry in HW */
134 void (*format_set)(struct mxr_layer *);
135 /** streaming stop/start */
136 void (*stream_set)(struct mxr_layer *, int);
137 /** adjusting geometry */
138 void (*fix_geometry)(struct mxr_layer *);
139};
140
141/** layer instance, a single window and content displayed on output */
142struct mxr_layer {
143 /** parent mixer device */
144 struct mxr_device *mdev;
145 /** layer index (unique identifier) */
146 int idx;
147 /** callbacks for layer methods */
148 struct mxr_layer_ops ops;
149 /** format array */
150 const struct mxr_format **fmt_array;
151 /** size of format array */
152 unsigned long fmt_array_size;
153
154 /** lock for protection of list and state fields */
155 spinlock_t enq_slock;
156 /** list for enqueued buffers */
157 struct list_head enq_list;
158 /** buffer currently owned by hardware in temporary registers */
159 struct mxr_buffer *update_buf;
160 /** buffer currently owned by hardware in shadow registers */
161 struct mxr_buffer *shadow_buf;
162 /** state of layer IDLE/STREAMING */
163 enum mxr_layer_state state;
164
165 /** mutex for protection of fields below */
166 struct mutex mutex;
167 /** handler for video node */
168 struct video_device vfd;
169 /** queue for output buffers */
170 struct vb2_queue vb_queue;
171 /** current image format */
172 const struct mxr_format *fmt;
173 /** current geometry of image */
174 struct mxr_geometry geo;
175};
176
177/** description of mixers output interface */
178struct mxr_output {
179 /** name of output */
180 char name[32];
181 /** output subdev */
182 struct v4l2_subdev *sd;
183 /** cookie used for configuration of registers */
184 int cookie;
185};
186
187/** specify source of output subdevs */
188struct mxr_output_conf {
189 /** name of output (connector) */
190 char *output_name;
191 /** name of module that generates output subdev */
192 char *module_name;
193 /** cookie need for mixer HW */
194 int cookie;
195};
196
197struct clk;
198struct regulator;
199
200/** auxiliary resources used my mixer */
201struct mxr_resources {
202 /** interrupt index */
203 int irq;
204 /** pointer to Mixer registers */
205 void __iomem *mxr_regs;
206 /** pointer to Video Processor registers */
207 void __iomem *vp_regs;
208 /** other resources, should used under mxr_device.mutex */
209 struct clk *mixer;
210 struct clk *vp;
211 struct clk *sclk_mixer;
212 struct clk *sclk_hdmi;
213 struct clk *sclk_dac;
214};
215
216/* event flags used */
217enum mxr_devide_flags {
218 MXR_EVENT_VSYNC = 0,
219};
220
221/** drivers instance */
222struct mxr_device {
223 /** master device */
224 struct device *dev;
225 /** state of each layer */
226 struct mxr_layer *layer[MXR_MAX_LAYERS];
227 /** state of each output */
228 struct mxr_output *output[MXR_MAX_OUTPUTS];
229 /** number of registered outputs */
230 int output_cnt;
231
232 /* video resources */
233
234 /** V4L2 device */
235 struct v4l2_device v4l2_dev;
236 /** context of allocator */
237 void *alloc_ctx;
238 /** event wait queue */
239 wait_queue_head_t event_queue;
240 /** state flags */
241 unsigned long event_flags;
242
243 /** spinlock for protection of registers */
244 spinlock_t reg_slock;
245
246 /** mutex for protection of fields below */
247 struct mutex mutex;
248 /** number of entities depndant on output configuration */
249 int n_output;
250 /** number of users that do streaming */
251 int n_streamer;
252 /** index of current output */
253 int current_output;
254 /** auxiliary resources used my mixer */
255 struct mxr_resources res;
256};
257
258/** transform device structure into mixer device */
259static inline struct mxr_device *to_mdev(struct device *dev)
260{
261 struct v4l2_device *vdev = dev_get_drvdata(dev);
262 return container_of(vdev, struct mxr_device, v4l2_dev);
263}
264
265/** get current output data, should be called under mdev's mutex */
266static inline struct mxr_output *to_output(struct mxr_device *mdev)
267{
268 return mdev->output[mdev->current_output];
269}
270
271/** get current output subdev, should be called under mdev's mutex */
272static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
273{
274 struct mxr_output *out = to_output(mdev);
275 return out ? out->sd : NULL;
276}
277
278/** forward declaration for mixer platform data */
279struct mxr_platform_data;
280
281/** acquiring common video resources */
282int __devinit mxr_acquire_video(struct mxr_device *mdev,
283 struct mxr_output_conf *output_cont, int output_count);
284
285/** releasing common video resources */
286void __devexit mxr_release_video(struct mxr_device *mdev);
287
288struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
289struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
290struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
291 int idx, char *name, struct mxr_layer_ops *ops);
292
293void mxr_base_layer_release(struct mxr_layer *layer);
294void mxr_layer_release(struct mxr_layer *layer);
295
296int mxr_base_layer_register(struct mxr_layer *layer);
297void mxr_base_layer_unregister(struct mxr_layer *layer);
298
299unsigned long mxr_get_plane_size(const struct mxr_block *blk,
300 unsigned int width, unsigned int height);
301
302/** adds new consumer for mixer's power */
303int __must_check mxr_power_get(struct mxr_device *mdev);
304/** removes consumer for mixer's power */
305void mxr_power_put(struct mxr_device *mdev);
306/** add new client for output configuration */
307void mxr_output_get(struct mxr_device *mdev);
308/** removes new client for output configuration */
309void mxr_output_put(struct mxr_device *mdev);
310/** add new client for streaming */
311void mxr_streamer_get(struct mxr_device *mdev);
312/** removes new client for streaming */
313void mxr_streamer_put(struct mxr_device *mdev);
314/** returns format of data delivared to current output */
315void mxr_get_mbus_fmt(struct mxr_device *mdev,
316 struct v4l2_mbus_framefmt *mbus_fmt);
317
318/* Debug */
319
320#define mxr_err(mdev, fmt, ...) dev_err(mdev->dev, fmt, ##__VA_ARGS__)
321#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
322#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
323
324#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
325 #define mxr_dbg(mdev, fmt, ...) dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
326#else
327 #define mxr_dbg(mdev, fmt, ...) do { (void) mdev; } while (0)
328#endif
329
330/* accessing Mixer's and Video Processor's registers */
331
332void mxr_vsync_set_update(struct mxr_device *mdev, int en);
333void mxr_reg_reset(struct mxr_device *mdev);
334irqreturn_t mxr_irq_handler(int irq, void *dev_data);
335void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
336void mxr_reg_streamon(struct mxr_device *mdev);
337void mxr_reg_streamoff(struct mxr_device *mdev);
338int mxr_reg_wait4vsync(struct mxr_device *mdev);
339void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
340 struct v4l2_mbus_framefmt *fmt);
341void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
342void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
343void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
344 const struct mxr_format *fmt, const struct mxr_geometry *geo);
345
346void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
347void mxr_reg_vp_buffer(struct mxr_device *mdev,
348 dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
349void mxr_reg_vp_format(struct mxr_device *mdev,
350 const struct mxr_format *fmt, const struct mxr_geometry *geo);
351void mxr_reg_dump(struct mxr_device *mdev);
352
353#endif /* SAMSUNG_MIXER_H */
354
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
new file mode 100644
index 000000000000..00643094b221
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_drv.c
@@ -0,0 +1,487 @@
1/*
2 * Samsung TV Mixer driver
3 *
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5 *
6 * Tomasz Stanislawski, <t.stanislaws@samsung.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
10 * by the Free Software Foundiation. either version 2 of the License,
11 * or (at your option) any later version
12 */
13
14#include "mixer.h"
15
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/io.h>
19#include <linux/interrupt.h>
20#include <linux/irq.h>
21#include <linux/fb.h>
22#include <linux/delay.h>
23#include <linux/pm_runtime.h>
24#include <linux/clk.h>
25
26MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
27MODULE_DESCRIPTION("Samsung MIXER");
28MODULE_LICENSE("GPL");
29
30/* --------- DRIVER PARAMETERS ---------- */
31
32static struct mxr_output_conf mxr_output_conf[] = {
33 {
34 .output_name = "S5P HDMI connector",
35 .module_name = "s5p-hdmi",
36 .cookie = 1,
37 },
38 {
39 .output_name = "S5P SDO connector",
40 .module_name = "s5p-sdo",
41 .cookie = 0,
42 },
43};
44
45void mxr_get_mbus_fmt(struct mxr_device *mdev,
46 struct v4l2_mbus_framefmt *mbus_fmt)
47{
48 struct v4l2_subdev *sd;
49 int ret;
50
51 mutex_lock(&mdev->mutex);
52 sd = to_outsd(mdev);
53 ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
54 WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
55 mutex_unlock(&mdev->mutex);
56}
57
58void mxr_streamer_get(struct mxr_device *mdev)
59{
60 mutex_lock(&mdev->mutex);
61 ++mdev->n_streamer;
62 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
63 if (mdev->n_streamer == 1) {
64 struct v4l2_subdev *sd = to_outsd(mdev);
65 struct v4l2_mbus_framefmt mbus_fmt;
66 struct mxr_resources *res = &mdev->res;
67 int ret;
68
69 if (to_output(mdev)->cookie == 0)
70 clk_set_parent(res->sclk_mixer, res->sclk_dac);
71 else
72 clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
73 mxr_reg_s_output(mdev, to_output(mdev)->cookie);
74
75 ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
76 WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
77 ret = v4l2_subdev_call(sd, video, s_stream, 1);
78 WARN(ret, "starting stream failed for output %s\n", sd->name);
79
80 mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
81 mxr_reg_streamon(mdev);
82 ret = mxr_reg_wait4vsync(mdev);
83 WARN(ret, "failed to get vsync (%d) from output\n", ret);
84 }
85 mutex_unlock(&mdev->mutex);
86 mxr_reg_dump(mdev);
87 /* FIXME: what to do when streaming fails? */
88}
89
90void mxr_streamer_put(struct mxr_device *mdev)
91{
92 mutex_lock(&mdev->mutex);
93 --mdev->n_streamer;
94 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
95 if (mdev->n_streamer == 0) {
96 int ret;
97 struct v4l2_subdev *sd = to_outsd(mdev);
98
99 mxr_reg_streamoff(mdev);
100 /* vsync applies Mixer setup */
101 ret = mxr_reg_wait4vsync(mdev);
102 WARN(ret, "failed to get vsync (%d) from output\n", ret);
103 ret = v4l2_subdev_call(sd, video, s_stream, 0);
104 WARN(ret, "stopping stream failed for output %s\n", sd->name);
105 }
106 WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
107 mdev->n_streamer);
108 mutex_unlock(&mdev->mutex);
109 mxr_reg_dump(mdev);
110}
111
112void mxr_output_get(struct mxr_device *mdev)
113{
114 mutex_lock(&mdev->mutex);
115 ++mdev->n_output;
116 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
117 /* turn on auxiliary driver */
118 if (mdev->n_output == 1)
119 v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
120 mutex_unlock(&mdev->mutex);
121}
122
123void mxr_output_put(struct mxr_device *mdev)
124{
125 mutex_lock(&mdev->mutex);
126 --mdev->n_output;
127 mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
128 /* turn on auxiliary driver */
129 if (mdev->n_output == 0)
130 v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
131 WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
132 mdev->n_output);
133 mutex_unlock(&mdev->mutex);
134}
135
136int mxr_power_get(struct mxr_device *mdev)
137{
138 int ret = pm_runtime_get_sync(mdev->dev);
139
140 /* returning 1 means that power is already enabled,
141 * so zero success be returned */
142 if (IS_ERR_VALUE(ret))
143 return ret;
144 return 0;
145}
146
147void mxr_power_put(struct mxr_device *mdev)
148{
149 pm_runtime_put_sync(mdev->dev);
150}
151
152/* --------- RESOURCE MANAGEMENT -------------*/
153
154static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
155 struct platform_device *pdev)
156{
157 struct resource *res;
158 int ret;
159
160 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
161 if (res == NULL) {
162 mxr_err(mdev, "get memory resource failed.\n");
163 ret = -ENXIO;
164 goto fail;
165 }
166
167 mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
168 if (mdev->res.mxr_regs == NULL) {
169 mxr_err(mdev, "register mapping failed.\n");
170 ret = -ENXIO;
171 goto fail;
172 }
173
174 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
175 if (res == NULL) {
176 mxr_err(mdev, "get memory resource failed.\n");
177 ret = -ENXIO;
178 goto fail_mxr_regs;
179 }
180
181 mdev->res.vp_regs = ioremap(res->start, resource_size(res));
182 if (mdev->res.vp_regs == NULL) {
183 mxr_err(mdev, "register mapping failed.\n");
184 ret = -ENXIO;
185 goto fail_mxr_regs;
186 }
187
188 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
189 if (res == NULL) {
190 mxr_err(mdev, "get interrupt resource failed.\n");
191 ret = -ENXIO;
192 goto fail_vp_regs;
193 }
194
195 ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
196 if (ret) {
197 mxr_err(mdev, "request interrupt failed.\n");
198 goto fail_vp_regs;
199 }
200 mdev->res.irq = res->start;
201
202 return 0;
203
204fail_vp_regs:
205 iounmap(mdev->res.vp_regs);
206
207fail_mxr_regs:
208 iounmap(mdev->res.mxr_regs);
209
210fail:
211 return ret;
212}
213
214static void mxr_release_plat_resources(struct mxr_device *mdev)
215{
216 free_irq(mdev->res.irq, mdev);
217 iounmap(mdev->res.vp_regs);
218 iounmap(mdev->res.mxr_regs);
219}
220
221static void mxr_release_clocks(struct mxr_device *mdev)
222{
223 struct mxr_resources *res = &mdev->res;
224
225 if (!IS_ERR_OR_NULL(res->sclk_dac))
226 clk_put(res->sclk_dac);
227 if (!IS_ERR_OR_NULL(res->sclk_hdmi))
228 clk_put(res->sclk_hdmi);
229 if (!IS_ERR_OR_NULL(res->sclk_mixer))
230 clk_put(res->sclk_mixer);
231 if (!IS_ERR_OR_NULL(res->vp))
232 clk_put(res->vp);
233 if (!IS_ERR_OR_NULL(res->mixer))
234 clk_put(res->mixer);
235}
236
237static int mxr_acquire_clocks(struct mxr_device *mdev)
238{
239 struct mxr_resources *res = &mdev->res;
240 struct device *dev = mdev->dev;
241
242 res->mixer = clk_get(dev, "mixer");
243 if (IS_ERR_OR_NULL(res->mixer)) {
244 mxr_err(mdev, "failed to get clock 'mixer'\n");
245 goto fail;
246 }
247 res->vp = clk_get(dev, "vp");
248 if (IS_ERR_OR_NULL(res->vp)) {
249 mxr_err(mdev, "failed to get clock 'vp'\n");
250 goto fail;
251 }
252 res->sclk_mixer = clk_get(dev, "sclk_mixer");
253 if (IS_ERR_OR_NULL(res->sclk_mixer)) {
254 mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
255 goto fail;
256 }
257 res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
258 if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
259 mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
260 goto fail;
261 }
262 res->sclk_dac = clk_get(dev, "sclk_dac");
263 if (IS_ERR_OR_NULL(res->sclk_dac)) {
264 mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
265 goto fail;
266 }
267
268 return 0;
269fail:
270 mxr_release_clocks(mdev);
271 return -ENODEV;
272}
273
274static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
275 struct platform_device *pdev)
276{
277 int ret;
278 ret = mxr_acquire_plat_resources(mdev, pdev);
279
280 if (ret)
281 goto fail;
282
283 ret = mxr_acquire_clocks(mdev);
284 if (ret)
285 goto fail_plat;
286
287 mxr_info(mdev, "resources acquired\n");
288 return 0;
289
290fail_plat:
291 mxr_release_plat_resources(mdev);
292fail:
293 mxr_err(mdev, "resources acquire failed\n");
294 return ret;
295}
296
297static void mxr_release_resources(struct mxr_device *mdev)
298{
299 mxr_release_clocks(mdev);
300 mxr_release_plat_resources(mdev);
301 memset(&mdev->res, 0, sizeof mdev->res);
302}
303
304static void mxr_release_layers(struct mxr_device *mdev)
305{
306 int i;
307
308 for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
309 if (mdev->layer[i])
310 mxr_layer_release(mdev->layer[i]);
311}
312
313static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
314 struct mxr_platform_data *pdata)
315{
316 mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
317 mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
318 mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
319
320 if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
321 mxr_err(mdev, "failed to acquire layers\n");
322 goto fail;
323 }
324
325 return 0;
326
327fail:
328 mxr_release_layers(mdev);
329 return -ENODEV;
330}
331
332/* ---------- POWER MANAGEMENT ----------- */
333
334static int mxr_runtime_resume(struct device *dev)
335{
336 struct mxr_device *mdev = to_mdev(dev);
337 struct mxr_resources *res = &mdev->res;
338
339 mxr_dbg(mdev, "resume - start\n");
340 mutex_lock(&mdev->mutex);
341 /* turn clocks on */
342 clk_enable(res->mixer);
343 clk_enable(res->vp);
344 clk_enable(res->sclk_mixer);
345 /* apply default configuration */
346 mxr_reg_reset(mdev);
347 mxr_dbg(mdev, "resume - finished\n");
348
349 mutex_unlock(&mdev->mutex);
350 return 0;
351}
352
353static int mxr_runtime_suspend(struct device *dev)
354{
355 struct mxr_device *mdev = to_mdev(dev);
356 struct mxr_resources *res = &mdev->res;
357 mxr_dbg(mdev, "suspend - start\n");
358 mutex_lock(&mdev->mutex);
359 /* turn clocks off */
360 clk_disable(res->sclk_mixer);
361 clk_disable(res->vp);
362 clk_disable(res->mixer);
363 mutex_unlock(&mdev->mutex);
364 mxr_dbg(mdev, "suspend - finished\n");
365 return 0;
366}
367
368static const struct dev_pm_ops mxr_pm_ops = {
369 .runtime_suspend = mxr_runtime_suspend,
370 .runtime_resume = mxr_runtime_resume,
371};
372
373/* --------- DRIVER INITIALIZATION ---------- */
374
375static int __devinit mxr_probe(struct platform_device *pdev)
376{
377 struct device *dev = &pdev->dev;
378 struct mxr_platform_data *pdata = dev->platform_data;
379 struct mxr_device *mdev;
380 int ret;
381
382 /* mdev does not exist yet so no mxr_dbg is used */
383 dev_info(dev, "probe start\n");
384
385 mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
386 if (!mdev) {
387 mxr_err(mdev, "not enough memory.\n");
388 ret = -ENOMEM;
389 goto fail;
390 }
391
392 /* setup pointer to master device */
393 mdev->dev = dev;
394
395 mutex_init(&mdev->mutex);
396 spin_lock_init(&mdev->reg_slock);
397 init_waitqueue_head(&mdev->event_queue);
398
399 /* acquire resources: regs, irqs, clocks, regulators */
400 ret = mxr_acquire_resources(mdev, pdev);
401 if (ret)
402 goto fail_mem;
403
404 /* configure resources for video output */
405 ret = mxr_acquire_video(mdev, mxr_output_conf,
406 ARRAY_SIZE(mxr_output_conf));
407 if (ret)
408 goto fail_resources;
409
410 /* configure layers */
411 ret = mxr_acquire_layers(mdev, pdata);
412 if (ret)
413 goto fail_video;
414
415 pm_runtime_enable(dev);
416
417 mxr_info(mdev, "probe successful\n");
418 return 0;
419
420fail_video:
421 mxr_release_video(mdev);
422
423fail_resources:
424 mxr_release_resources(mdev);
425
426fail_mem:
427 kfree(mdev);
428
429fail:
430 dev_info(dev, "probe failed\n");
431 return ret;
432}
433
434static int __devexit mxr_remove(struct platform_device *pdev)
435{
436 struct device *dev = &pdev->dev;
437 struct mxr_device *mdev = to_mdev(dev);
438
439 pm_runtime_disable(dev);
440
441 mxr_release_layers(mdev);
442 mxr_release_video(mdev);
443 mxr_release_resources(mdev);
444
445 kfree(mdev);
446
447 dev_info(dev, "remove sucessful\n");
448 return 0;
449}
450
451static struct platform_driver mxr_driver __refdata = {
452 .probe = mxr_probe,
453 .remove = __devexit_p(mxr_remove),
454 .driver = {
455 .name = MXR_DRIVER_NAME,
456 .owner = THIS_MODULE,
457 .pm = &mxr_pm_ops,
458 }
459};
460
461static int __init mxr_init(void)
462{
463 int i, ret;
464 static const char banner[] __initdata = KERN_INFO
465 "Samsung TV Mixer driver, "
466 "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
467 printk(banner);
468
469 /* Loading auxiliary modules */
470 for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
471 request_module(mxr_output_conf[i].module_name);
472
473 ret = platform_driver_register(&mxr_driver);
474 if (ret != 0) {
475 printk(KERN_ERR "registration of MIXER driver failed\n");
476 return -ENXIO;
477 }
478
479 return 0;
480}
481module_init(mxr_init);
482
483static void __exit mxr_exit(void)
484{
485 platform_driver_unregister(&mxr_driver);
486}
487module_exit(mxr_exit);
diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c
new file mode 100644
index 000000000000..58f0ba49580f
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c
@@ -0,0 +1,185 @@
1/*
2 * Samsung TV Mixer driver
3 *
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5 *
6 * Tomasz Stanislawski, <t.stanislaws@samsung.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
10 * by the Free Software Foundiation. either version 2 of the License,
11 * or (at your option) any later version
12 */
13
14#include "mixer.h"
15
16#include <media/videobuf2-dma-contig.h>
17
18/* FORMAT DEFINITIONS */
19
20static const struct mxr_format mxr_fb_fmt_rgb565 = {
21 .name = "RGB565",
22 .fourcc = V4L2_PIX_FMT_RGB565,
23 .colorspace = V4L2_COLORSPACE_SRGB,
24 .num_planes = 1,
25 .plane = {
26 { .width = 1, .height = 1, .size = 2 },
27 },
28 .num_subframes = 1,
29 .cookie = 4,
30};
31
32static const struct mxr_format mxr_fb_fmt_argb1555 = {
33 .name = "ARGB1555",
34 .num_planes = 1,
35 .fourcc = V4L2_PIX_FMT_RGB555,
36 .colorspace = V4L2_COLORSPACE_SRGB,
37 .plane = {
38 { .width = 1, .height = 1, .size = 2 },
39 },
40 .num_subframes = 1,
41 .cookie = 5,
42};
43
44static const struct mxr_format mxr_fb_fmt_argb4444 = {
45 .name = "ARGB4444",
46 .num_planes = 1,
47 .fourcc = V4L2_PIX_FMT_RGB444,
48 .colorspace = V4L2_COLORSPACE_SRGB,
49 .plane = {
50 { .width = 1, .height = 1, .size = 2 },
51 },
52 .num_subframes = 1,
53 .cookie = 6,
54};
55
56static const struct mxr_format mxr_fb_fmt_argb8888 = {
57 .name = "ARGB8888",
58 .fourcc = V4L2_PIX_FMT_BGR32,
59 .colorspace = V4L2_COLORSPACE_SRGB,
60 .num_planes = 1,
61 .plane = {
62 { .width = 1, .height = 1, .size = 4 },
63 },
64 .num_subframes = 1,
65 .cookie = 7,
66};
67
68static const struct mxr_format *mxr_graph_format[] = {
69 &mxr_fb_fmt_rgb565,
70 &mxr_fb_fmt_argb1555,
71 &mxr_fb_fmt_argb4444,
72 &mxr_fb_fmt_argb8888,
73};
74
75/* AUXILIARY CALLBACKS */
76
77static void mxr_graph_layer_release(struct mxr_layer *layer)
78{
79 mxr_base_layer_unregister(layer);
80 mxr_base_layer_release(layer);
81}
82
83static void mxr_graph_buffer_set(struct mxr_layer *layer,
84 struct mxr_buffer *buf)
85{
86 dma_addr_t addr = 0;
87
88 if (buf)
89 addr = vb2_dma_contig_plane_paddr(&buf->vb, 0);
90 mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
91}
92
93static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
94{
95 mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
96}
97
98static void mxr_graph_format_set(struct mxr_layer *layer)
99{
100 mxr_reg_graph_format(layer->mdev, layer->idx,
101 layer->fmt, &layer->geo);
102}
103
104static void mxr_graph_fix_geometry(struct mxr_layer *layer)
105{
106 struct mxr_geometry *geo = &layer->geo;
107
108 /* limit to boundary size */
109 geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
110 geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
111 geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
112 geo->src.width = min(geo->src.width, 2047U);
113 /* not possible to crop of Y axis */
114 geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
115 geo->src.height = geo->src.full_height - geo->src.y_offset;
116 /* limitting offset */
117 geo->src.x_offset = min(geo->src.x_offset,
118 geo->src.full_width - geo->src.width);
119
120 /* setting position in output */
121 geo->dst.width = min(geo->dst.width, geo->dst.full_width);
122 geo->dst.height = min(geo->dst.height, geo->dst.full_height);
123
124 /* Mixer supports only 1x and 2x scaling */
125 if (geo->dst.width >= 2 * geo->src.width) {
126 geo->x_ratio = 1;
127 geo->dst.width = 2 * geo->src.width;
128 } else {
129 geo->x_ratio = 0;
130 geo->dst.width = geo->src.width;
131 }
132
133 if (geo->dst.height >= 2 * geo->src.height) {
134 geo->y_ratio = 1;
135 geo->dst.height = 2 * geo->src.height;
136 } else {
137 geo->y_ratio = 0;
138 geo->dst.height = geo->src.height;
139 }
140
141 geo->dst.x_offset = min(geo->dst.x_offset,
142 geo->dst.full_width - geo->dst.width);
143 geo->dst.y_offset = min(geo->dst.y_offset,
144 geo->dst.full_height - geo->dst.height);
145}
146
147/* PUBLIC API */
148
149struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
150{
151 struct mxr_layer *layer;
152 int ret;
153 struct mxr_layer_ops ops = {
154 .release = mxr_graph_layer_release,
155 .buffer_set = mxr_graph_buffer_set,
156 .stream_set = mxr_graph_stream_set,
157 .format_set = mxr_graph_format_set,
158 .fix_geometry = mxr_graph_fix_geometry,
159 };
160 char name[32];
161
162 sprintf(name, "graph%d", idx);
163
164 layer = mxr_base_layer_create(mdev, idx, name, &ops);
165 if (layer == NULL) {
166 mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
167 goto fail;
168 }
169
170 layer->fmt_array = mxr_graph_format;
171 layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
172
173 ret = mxr_base_layer_register(layer);
174 if (ret)
175 goto fail_layer;
176
177 return layer;
178
179fail_layer:
180 mxr_base_layer_release(layer);
181
182fail:
183 return NULL;
184}
185
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c
new file mode 100644
index 000000000000..38dac672aa1c
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_reg.c
@@ -0,0 +1,541 @@
1/*
2 * Samsung TV Mixer driver
3 *
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5 *
6 * Tomasz Stanislawski, <t.stanislaws@samsung.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
10 * by the Free Software Foundiation. either version 2 of the License,
11 * or (at your option) any later version
12 */
13
14#include "mixer.h"
15#include "regs-mixer.h"
16#include "regs-vp.h"
17
18#include <linux/delay.h>
19
20/* Register access subroutines */
21
22static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
23{
24 return readl(mdev->res.vp_regs + reg_id);
25}
26
27static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
28{
29 writel(val, mdev->res.vp_regs + reg_id);
30}
31
32static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
33 u32 val, u32 mask)
34{
35 u32 old = vp_read(mdev, reg_id);
36
37 val = (val & mask) | (old & ~mask);
38 writel(val, mdev->res.vp_regs + reg_id);
39}
40
41static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
42{
43 return readl(mdev->res.mxr_regs + reg_id);
44}
45
46static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
47{
48 writel(val, mdev->res.mxr_regs + reg_id);
49}
50
51static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
52 u32 val, u32 mask)
53{
54 u32 old = mxr_read(mdev, reg_id);
55
56 val = (val & mask) | (old & ~mask);
57 writel(val, mdev->res.mxr_regs + reg_id);
58}
59
60void mxr_vsync_set_update(struct mxr_device *mdev, int en)
61{
62 /* block update on vsync */
63 mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
64 MXR_STATUS_SYNC_ENABLE);
65 vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
66}
67
68static void __mxr_reg_vp_reset(struct mxr_device *mdev)
69{
70 int tries = 100;
71
72 vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
73 for (tries = 100; tries; --tries) {
74 /* waiting until VP_SRESET_PROCESSING is 0 */
75 if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
76 break;
77 mdelay(10);
78 }
79 WARN(tries == 0, "failed to reset Video Processor\n");
80}
81
82static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
83
84void mxr_reg_reset(struct mxr_device *mdev)
85{
86 unsigned long flags;
87 u32 val; /* value stored to register */
88
89 spin_lock_irqsave(&mdev->reg_slock, flags);
90 mxr_vsync_set_update(mdev, MXR_DISABLE);
91
92 /* set output in RGB888 mode */
93 mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_YUV444);
94
95 /* 16 beat burst in DMA */
96 mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
97 MXR_STATUS_BURST_MASK);
98
99 /* setting default layer priority: layer1 > video > layer0
100 * because typical usage scenario would be
101 * layer0 - framebuffer
102 * video - video overlay
103 * layer1 - OSD
104 */
105 val = MXR_LAYER_CFG_GRP0_VAL(1);
106 val |= MXR_LAYER_CFG_VP_VAL(2);
107 val |= MXR_LAYER_CFG_GRP1_VAL(3);
108 mxr_write(mdev, MXR_LAYER_CFG, val);
109
110 /* use dark gray background color */
111 mxr_write(mdev, MXR_BG_COLOR0, 0x808080);
112 mxr_write(mdev, MXR_BG_COLOR1, 0x808080);
113 mxr_write(mdev, MXR_BG_COLOR2, 0x808080);
114
115 /* setting graphical layers */
116
117 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
118 val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */
119 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
120
121 /* the same configuration for both layers */
122 mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
123 mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
124
125 /* configuration of Video Processor Registers */
126 __mxr_reg_vp_reset(mdev);
127 mxr_reg_vp_default_filter(mdev);
128
129 /* enable all interrupts */
130 mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
131
132 mxr_vsync_set_update(mdev, MXR_ENABLE);
133 spin_unlock_irqrestore(&mdev->reg_slock, flags);
134}
135
136void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
137 const struct mxr_format *fmt, const struct mxr_geometry *geo)
138{
139 u32 val;
140 unsigned long flags;
141
142 spin_lock_irqsave(&mdev->reg_slock, flags);
143 mxr_vsync_set_update(mdev, MXR_DISABLE);
144
145 /* setup format */
146 mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx),
147 MXR_GRP_CFG_FORMAT_VAL(fmt->cookie), MXR_GRP_CFG_FORMAT_MASK);
148
149 /* setup geometry */
150 mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width);
151 val = MXR_GRP_WH_WIDTH(geo->src.width);
152 val |= MXR_GRP_WH_HEIGHT(geo->src.height);
153 val |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
154 val |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
155 mxr_write(mdev, MXR_GRAPHIC_WH(idx), val);
156
157 /* setup offsets in source image */
158 val = MXR_GRP_SXY_SX(geo->src.x_offset);
159 val |= MXR_GRP_SXY_SY(geo->src.y_offset);
160 mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val);
161
162 /* setup offsets in display image */
163 val = MXR_GRP_DXY_DX(geo->dst.x_offset);
164 val |= MXR_GRP_DXY_DY(geo->dst.y_offset);
165 mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val);
166
167 mxr_vsync_set_update(mdev, MXR_ENABLE);
168 spin_unlock_irqrestore(&mdev->reg_slock, flags);
169}
170
171void mxr_reg_vp_format(struct mxr_device *mdev,
172 const struct mxr_format *fmt, const struct mxr_geometry *geo)
173{
174 unsigned long flags;
175
176 spin_lock_irqsave(&mdev->reg_slock, flags);
177 mxr_vsync_set_update(mdev, MXR_DISABLE);
178
179 vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
180
181 /* setting size of input image */
182 vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
183 VP_IMG_VSIZE(geo->src.full_height));
184 /* chroma height has to reduced by 2 to avoid chroma distorions */
185 vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
186 VP_IMG_VSIZE(geo->src.full_height / 2));
187
188 vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
189 vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
190 vp_write(mdev, VP_SRC_H_POSITION,
191 VP_SRC_H_POSITION_VAL(geo->src.x_offset));
192 vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
193
194 vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
195 vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
196 if (geo->dst.field == V4L2_FIELD_INTERLACED) {
197 vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
198 vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
199 } else {
200 vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
201 vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
202 }
203
204 vp_write(mdev, VP_H_RATIO, geo->x_ratio);
205 vp_write(mdev, VP_V_RATIO, geo->y_ratio);
206
207 vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
208
209 mxr_vsync_set_update(mdev, MXR_ENABLE);
210 spin_unlock_irqrestore(&mdev->reg_slock, flags);
211
212}
213
214void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
215{
216 u32 val = addr ? ~0 : 0;
217 unsigned long flags;
218
219 spin_lock_irqsave(&mdev->reg_slock, flags);
220 mxr_vsync_set_update(mdev, MXR_DISABLE);
221
222 if (idx == 0)
223 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
224 else
225 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
226 mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr);
227
228 mxr_vsync_set_update(mdev, MXR_ENABLE);
229 spin_unlock_irqrestore(&mdev->reg_slock, flags);
230}
231
232void mxr_reg_vp_buffer(struct mxr_device *mdev,
233 dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
234{
235 u32 val = luma_addr[0] ? ~0 : 0;
236 unsigned long flags;
237
238 spin_lock_irqsave(&mdev->reg_slock, flags);
239 mxr_vsync_set_update(mdev, MXR_DISABLE);
240
241 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE);
242 vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
243 /* TODO: fix tiled mode */
244 vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
245 vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
246 vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
247 vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
248
249 mxr_vsync_set_update(mdev, MXR_ENABLE);
250 spin_unlock_irqrestore(&mdev->reg_slock, flags);
251}
252
253static void mxr_irq_layer_handle(struct mxr_layer *layer)
254{
255 struct list_head *head = &layer->enq_list;
256 struct mxr_buffer *done;
257
258 /* skip non-existing layer */
259 if (layer == NULL)
260 return;
261
262 spin_lock(&layer->enq_slock);
263 if (layer->state == MXR_LAYER_IDLE)
264 goto done;
265
266 done = layer->shadow_buf;
267 layer->shadow_buf = layer->update_buf;
268
269 if (list_empty(head)) {
270 if (layer->state != MXR_LAYER_STREAMING)
271 layer->update_buf = NULL;
272 } else {
273 struct mxr_buffer *next;
274 next = list_first_entry(head, struct mxr_buffer, list);
275 list_del(&next->list);
276 layer->update_buf = next;
277 }
278
279 layer->ops.buffer_set(layer, layer->update_buf);
280
281 if (done && done != layer->shadow_buf)
282 vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
283
284done:
285 spin_unlock(&layer->enq_slock);
286}
287
288irqreturn_t mxr_irq_handler(int irq, void *dev_data)
289{
290 struct mxr_device *mdev = dev_data;
291 u32 i, val;
292
293 spin_lock(&mdev->reg_slock);
294 val = mxr_read(mdev, MXR_INT_STATUS);
295
296 /* wake up process waiting for VSYNC */
297 if (val & MXR_INT_STATUS_VSYNC) {
298 set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
299 wake_up(&mdev->event_queue);
300 }
301
302 /* clear interrupts */
303 if (~val & MXR_INT_EN_VSYNC) {
304 /* vsync interrupt use different bit for read and clear */
305 val &= ~MXR_INT_EN_VSYNC;
306 val |= MXR_INT_CLEAR_VSYNC;
307 }
308 mxr_write(mdev, MXR_INT_STATUS, val);
309
310 spin_unlock(&mdev->reg_slock);
311 /* leave on non-vsync event */
312 if (~val & MXR_INT_CLEAR_VSYNC)
313 return IRQ_HANDLED;
314 for (i = 0; i < MXR_MAX_LAYERS; ++i)
315 mxr_irq_layer_handle(mdev->layer[i]);
316 return IRQ_HANDLED;
317}
318
319void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
320{
321 u32 val;
322
323 val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
324 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
325}
326
327void mxr_reg_streamon(struct mxr_device *mdev)
328{
329 unsigned long flags;
330
331 spin_lock_irqsave(&mdev->reg_slock, flags);
332 /* single write -> no need to block vsync update */
333
334 /* start MIXER */
335 mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
336
337 spin_unlock_irqrestore(&mdev->reg_slock, flags);
338}
339
340void mxr_reg_streamoff(struct mxr_device *mdev)
341{
342 unsigned long flags;
343
344 spin_lock_irqsave(&mdev->reg_slock, flags);
345 /* single write -> no need to block vsync update */
346
347 /* stop MIXER */
348 mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
349
350 spin_unlock_irqrestore(&mdev->reg_slock, flags);
351}
352
353int mxr_reg_wait4vsync(struct mxr_device *mdev)
354{
355 int ret;
356
357 clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
358 /* TODO: consider adding interruptible */
359 ret = wait_event_timeout(mdev->event_queue,
360 test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
361 msecs_to_jiffies(1000));
362 if (ret > 0)
363 return 0;
364 if (ret < 0)
365 return ret;
366 mxr_warn(mdev, "no vsync detected - timeout\n");
367 return -ETIME;
368}
369
370void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
371 struct v4l2_mbus_framefmt *fmt)
372{
373 u32 val = 0;
374 unsigned long flags;
375
376 spin_lock_irqsave(&mdev->reg_slock, flags);
377 mxr_vsync_set_update(mdev, MXR_DISABLE);
378
379 /* choosing between interlace and progressive mode */
380 if (fmt->field == V4L2_FIELD_INTERLACED)
381 val |= MXR_CFG_SCAN_INTERLACE;
382 else
383 val |= MXR_CFG_SCAN_PROGRASSIVE;
384
385 /* choosing between porper HD and SD mode */
386 if (fmt->height == 480)
387 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
388 else if (fmt->height == 576)
389 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
390 else if (fmt->height == 720)
391 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
392 else if (fmt->height == 1080)
393 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
394 else
395 WARN(1, "unrecognized mbus height %u!\n", fmt->height);
396
397 mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK);
398
399 val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
400 vp_write_mask(mdev, VP_MODE, val,
401 VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
402
403 mxr_vsync_set_update(mdev, MXR_ENABLE);
404 spin_unlock_irqrestore(&mdev->reg_slock, flags);
405}
406
407void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
408{
409 /* no extra actions need to be done */
410}
411
412void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
413{
414 /* no extra actions need to be done */
415}
416
417static const u8 filter_y_horiz_tap8[] = {
418 0, -1, -1, -1, -1, -1, -1, -1,
419 -1, -1, -1, -1, -1, 0, 0, 0,
420 0, 2, 4, 5, 6, 6, 6, 6,
421 6, 5, 5, 4, 3, 2, 1, 1,
422 0, -6, -12, -16, -18, -20, -21, -20,
423 -20, -18, -16, -13, -10, -8, -5, -2,
424 127, 126, 125, 121, 114, 107, 99, 89,
425 79, 68, 57, 46, 35, 25, 16, 8,
426};
427
428static const u8 filter_y_vert_tap4[] = {
429 0, -3, -6, -8, -8, -8, -8, -7,
430 -6, -5, -4, -3, -2, -1, -1, 0,
431 127, 126, 124, 118, 111, 102, 92, 81,
432 70, 59, 48, 37, 27, 19, 11, 5,
433 0, 5, 11, 19, 27, 37, 48, 59,
434 70, 81, 92, 102, 111, 118, 124, 126,
435 0, 0, -1, -1, -2, -3, -4, -5,
436 -6, -7, -8, -8, -8, -8, -6, -3,
437};
438
439static const u8 filter_cr_horiz_tap4[] = {
440 0, -3, -6, -8, -8, -8, -8, -7,
441 -6, -5, -4, -3, -2, -1, -1, 0,
442 127, 126, 124, 118, 111, 102, 92, 81,
443 70, 59, 48, 37, 27, 19, 11, 5,
444};
445
446static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
447 int reg_id, const u8 *data, unsigned int size)
448{
449 /* assure 4-byte align */
450 BUG_ON(size & 3);
451 for (; size; size -= 4, reg_id += 4, data += 4) {
452 u32 val = (data[0] << 24) | (data[1] << 16) |
453 (data[2] << 8) | data[3];
454 vp_write(mdev, reg_id, val);
455 }
456}
457
458static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
459{
460 mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
461 filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
462 mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
463 filter_y_vert_tap4, sizeof filter_y_vert_tap4);
464 mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
465 filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
466}
467
468static void mxr_reg_mxr_dump(struct mxr_device *mdev)
469{
470#define DUMPREG(reg_id) \
471do { \
472 mxr_dbg(mdev, #reg_id " = %08x\n", \
473 (u32)readl(mdev->res.mxr_regs + reg_id)); \
474} while (0)
475
476 DUMPREG(MXR_STATUS);
477 DUMPREG(MXR_CFG);
478 DUMPREG(MXR_INT_EN);
479 DUMPREG(MXR_INT_STATUS);
480
481 DUMPREG(MXR_LAYER_CFG);
482 DUMPREG(MXR_VIDEO_CFG);
483
484 DUMPREG(MXR_GRAPHIC0_CFG);
485 DUMPREG(MXR_GRAPHIC0_BASE);
486 DUMPREG(MXR_GRAPHIC0_SPAN);
487 DUMPREG(MXR_GRAPHIC0_WH);
488 DUMPREG(MXR_GRAPHIC0_SXY);
489 DUMPREG(MXR_GRAPHIC0_DXY);
490
491 DUMPREG(MXR_GRAPHIC1_CFG);
492 DUMPREG(MXR_GRAPHIC1_BASE);
493 DUMPREG(MXR_GRAPHIC1_SPAN);
494 DUMPREG(MXR_GRAPHIC1_WH);
495 DUMPREG(MXR_GRAPHIC1_SXY);
496 DUMPREG(MXR_GRAPHIC1_DXY);
497#undef DUMPREG
498}
499
500static void mxr_reg_vp_dump(struct mxr_device *mdev)
501{
502#define DUMPREG(reg_id) \
503do { \
504 mxr_dbg(mdev, #reg_id " = %08x\n", \
505 (u32) readl(mdev->res.vp_regs + reg_id)); \
506} while (0)
507
508
509 DUMPREG(VP_ENABLE);
510 DUMPREG(VP_SRESET);
511 DUMPREG(VP_SHADOW_UPDATE);
512 DUMPREG(VP_FIELD_ID);
513 DUMPREG(VP_MODE);
514 DUMPREG(VP_IMG_SIZE_Y);
515 DUMPREG(VP_IMG_SIZE_C);
516 DUMPREG(VP_PER_RATE_CTRL);
517 DUMPREG(VP_TOP_Y_PTR);
518 DUMPREG(VP_BOT_Y_PTR);
519 DUMPREG(VP_TOP_C_PTR);
520 DUMPREG(VP_BOT_C_PTR);
521 DUMPREG(VP_ENDIAN_MODE);
522 DUMPREG(VP_SRC_H_POSITION);
523 DUMPREG(VP_SRC_V_POSITION);
524 DUMPREG(VP_SRC_WIDTH);
525 DUMPREG(VP_SRC_HEIGHT);
526 DUMPREG(VP_DST_H_POSITION);
527 DUMPREG(VP_DST_V_POSITION);
528 DUMPREG(VP_DST_WIDTH);
529 DUMPREG(VP_DST_HEIGHT);
530 DUMPREG(VP_H_RATIO);
531 DUMPREG(VP_V_RATIO);
532
533#undef DUMPREG
534}
535
536void mxr_reg_dump(struct mxr_device *mdev)
537{
538 mxr_reg_mxr_dump(mdev);
539 mxr_reg_vp_dump(mdev);
540}
541
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
new file mode 100644
index 000000000000..43ac22f35bc7
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -0,0 +1,1006 @@
1/*
2 * Samsung TV Mixer driver
3 *
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5 *
6 * Tomasz Stanislawski, <t.stanislaws@samsung.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
10 * by the Free Software Foundation. either version 2 of the License,
11 * or (at your option) any later version
12 */
13
14#include "mixer.h"
15
16#include <media/v4l2-ioctl.h>
17#include <linux/videodev2.h>
18#include <linux/mm.h>
19#include <linux/version.h>
20#include <linux/timer.h>
21#include <media/videobuf2-dma-contig.h>
22
23static int find_reg_callback(struct device *dev, void *p)
24{
25 struct v4l2_subdev **sd = p;
26
27 *sd = dev_get_drvdata(dev);
28 /* non-zero value stops iteration */
29 return 1;
30}
31
32static struct v4l2_subdev *find_and_register_subdev(
33 struct mxr_device *mdev, char *module_name)
34{
35 struct device_driver *drv;
36 struct v4l2_subdev *sd = NULL;
37 int ret;
38
39 /* TODO: add waiting until probe is finished */
40 drv = driver_find(module_name, &platform_bus_type);
41 if (!drv) {
42 mxr_warn(mdev, "module %s is missing\n", module_name);
43 return NULL;
44 }
45 /* driver refcnt is increased, it is safe to iterate over devices */
46 ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
47 /* ret == 0 means that find_reg_callback was never executed */
48 if (sd == NULL) {
49 mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
50 goto done;
51 }
52 /* v4l2_device_register_subdev detects if sd is NULL */
53 ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
54 if (ret) {
55 mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
56 sd = NULL;
57 }
58
59done:
60 put_driver(drv);
61 return sd;
62}
63
64int __devinit mxr_acquire_video(struct mxr_device *mdev,
65 struct mxr_output_conf *output_conf, int output_count)
66{
67 struct device *dev = mdev->dev;
68 struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
69 int i;
70 int ret = 0;
71 struct v4l2_subdev *sd;
72
73 strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
74 /* prepare context for V4L2 device */
75 ret = v4l2_device_register(dev, v4l2_dev);
76 if (ret) {
77 mxr_err(mdev, "could not register v4l2 device.\n");
78 goto fail;
79 }
80
81 mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
82 if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
83 mxr_err(mdev, "could not acquire vb2 allocator\n");
84 goto fail_v4l2_dev;
85 }
86
87 /* registering outputs */
88 mdev->output_cnt = 0;
89 for (i = 0; i < output_count; ++i) {
90 struct mxr_output_conf *conf = &output_conf[i];
91 struct mxr_output *out;
92
93 sd = find_and_register_subdev(mdev, conf->module_name);
94 /* trying to register next output */
95 if (sd == NULL)
96 continue;
97 out = kzalloc(sizeof *out, GFP_KERNEL);
98 if (out == NULL) {
99 mxr_err(mdev, "no memory for '%s'\n",
100 conf->output_name);
101 ret = -ENOMEM;
102 /* registered subdevs are removed in fail_v4l2_dev */
103 goto fail_output;
104 }
105 strlcpy(out->name, conf->output_name, sizeof(out->name));
106 out->sd = sd;
107 out->cookie = conf->cookie;
108 mdev->output[mdev->output_cnt++] = out;
109 mxr_info(mdev, "added output '%s' from module '%s'\n",
110 conf->output_name, conf->module_name);
111 /* checking if maximal number of outputs is reached */
112 if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
113 break;
114 }
115
116 if (mdev->output_cnt == 0) {
117 mxr_err(mdev, "failed to register any output\n");
118 ret = -ENODEV;
119 /* skipping fail_output because there is nothing to free */
120 goto fail_vb2_allocator;
121 }
122
123 return 0;
124
125fail_output:
126 /* kfree is NULL-safe */
127 for (i = 0; i < mdev->output_cnt; ++i)
128 kfree(mdev->output[i]);
129 memset(mdev->output, 0, sizeof mdev->output);
130
131fail_vb2_allocator:
132 /* freeing allocator context */
133 vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
134
135fail_v4l2_dev:
136 /* NOTE: automatically unregister all subdevs */
137 v4l2_device_unregister(v4l2_dev);
138
139fail:
140 return ret;
141}
142
143void __devexit mxr_release_video(struct mxr_device *mdev)
144{
145 int i;
146
147 /* kfree is NULL-safe */
148 for (i = 0; i < mdev->output_cnt; ++i)
149 kfree(mdev->output[i]);
150
151 vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
152 v4l2_device_unregister(&mdev->v4l2_dev);
153}
154
155static int mxr_querycap(struct file *file, void *priv,
156 struct v4l2_capability *cap)
157{
158 struct mxr_layer *layer = video_drvdata(file);
159
160 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
161
162 strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
163 strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
164 sprintf(cap->bus_info, "%d", layer->idx);
165 cap->version = KERNEL_VERSION(0, 1, 0);
166 cap->capabilities = V4L2_CAP_STREAMING |
167 V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
168
169 return 0;
170}
171
172/* Geometry handling */
173static void mxr_layer_geo_fix(struct mxr_layer *layer)
174{
175 struct mxr_device *mdev = layer->mdev;
176 struct v4l2_mbus_framefmt mbus_fmt;
177
178 /* TODO: add some dirty flag to avoid unnecessary adjustments */
179 mxr_get_mbus_fmt(mdev, &mbus_fmt);
180 layer->geo.dst.full_width = mbus_fmt.width;
181 layer->geo.dst.full_height = mbus_fmt.height;
182 layer->geo.dst.field = mbus_fmt.field;
183 layer->ops.fix_geometry(layer);
184}
185
186static void mxr_layer_default_geo(struct mxr_layer *layer)
187{
188 struct mxr_device *mdev = layer->mdev;
189 struct v4l2_mbus_framefmt mbus_fmt;
190
191 memset(&layer->geo, 0, sizeof layer->geo);
192
193 mxr_get_mbus_fmt(mdev, &mbus_fmt);
194
195 layer->geo.dst.full_width = mbus_fmt.width;
196 layer->geo.dst.full_height = mbus_fmt.height;
197 layer->geo.dst.width = layer->geo.dst.full_width;
198 layer->geo.dst.height = layer->geo.dst.full_height;
199 layer->geo.dst.field = mbus_fmt.field;
200
201 layer->geo.src.full_width = mbus_fmt.width;
202 layer->geo.src.full_height = mbus_fmt.height;
203 layer->geo.src.width = layer->geo.src.full_width;
204 layer->geo.src.height = layer->geo.src.full_height;
205
206 layer->ops.fix_geometry(layer);
207}
208
209static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
210{
211 mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
212 geo->src.full_width, geo->src.full_height);
213 mxr_dbg(mdev, "src.size = (%u, %u)\n",
214 geo->src.width, geo->src.height);
215 mxr_dbg(mdev, "src.offset = (%u, %u)\n",
216 geo->src.x_offset, geo->src.y_offset);
217 mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
218 geo->dst.full_width, geo->dst.full_height);
219 mxr_dbg(mdev, "dst.size = (%u, %u)\n",
220 geo->dst.width, geo->dst.height);
221 mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
222 geo->dst.x_offset, geo->dst.y_offset);
223 mxr_dbg(mdev, "ratio = (%u, %u)\n",
224 geo->x_ratio, geo->y_ratio);
225}
226
227
228static const struct mxr_format *find_format_by_fourcc(
229 struct mxr_layer *layer, unsigned long fourcc);
230static const struct mxr_format *find_format_by_index(
231 struct mxr_layer *layer, unsigned long index);
232
233static int mxr_enum_fmt(struct file *file, void *priv,
234 struct v4l2_fmtdesc *f)
235{
236 struct mxr_layer *layer = video_drvdata(file);
237 struct mxr_device *mdev = layer->mdev;
238 const struct mxr_format *fmt;
239
240 mxr_dbg(mdev, "%s\n", __func__);
241 fmt = find_format_by_index(layer, f->index);
242 if (fmt == NULL)
243 return -EINVAL;
244
245 strlcpy(f->description, fmt->name, sizeof(f->description));
246 f->pixelformat = fmt->fourcc;
247
248 return 0;
249}
250
251static int mxr_s_fmt(struct file *file, void *priv,
252 struct v4l2_format *f)
253{
254 struct mxr_layer *layer = video_drvdata(file);
255 const struct mxr_format *fmt;
256 struct v4l2_pix_format_mplane *pix;
257 struct mxr_device *mdev = layer->mdev;
258 struct mxr_geometry *geo = &layer->geo;
259
260 mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
261
262 pix = &f->fmt.pix_mp;
263 fmt = find_format_by_fourcc(layer, pix->pixelformat);
264 if (fmt == NULL) {
265 mxr_warn(mdev, "not recognized fourcc: %08x\n",
266 pix->pixelformat);
267 return -EINVAL;
268 }
269 layer->fmt = fmt;
270 geo->src.full_width = pix->width;
271 geo->src.width = pix->width;
272 geo->src.full_height = pix->height;
273 geo->src.height = pix->height;
274 /* assure consistency of geometry */
275 mxr_layer_geo_fix(layer);
276 mxr_dbg(mdev, "width=%u height=%u span=%u\n",
277 geo->src.width, geo->src.height, geo->src.full_width);
278
279 return 0;
280}
281
282static unsigned int divup(unsigned int divident, unsigned int divisor)
283{
284 return (divident + divisor - 1) / divisor;
285}
286
287unsigned long mxr_get_plane_size(const struct mxr_block *blk,
288 unsigned int width, unsigned int height)
289{
290 unsigned int bl_width = divup(width, blk->width);
291 unsigned int bl_height = divup(height, blk->height);
292
293 return bl_width * bl_height * blk->size;
294}
295
296static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
297 const struct mxr_format *fmt, u32 width, u32 height)
298{
299 int i;
300
301 memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
302 for (i = 0; i < fmt->num_planes; ++i) {
303 struct v4l2_plane_pix_format *plane = planes
304 + fmt->plane2subframe[i];
305 const struct mxr_block *blk = &fmt->plane[i];
306 u32 bl_width = divup(width, blk->width);
307 u32 bl_height = divup(height, blk->height);
308 u32 sizeimage = bl_width * bl_height * blk->size;
309 u16 bytesperline = bl_width * blk->size / blk->height;
310
311 plane->sizeimage += sizeimage;
312 plane->bytesperline = max(plane->bytesperline, bytesperline);
313 }
314}
315
316static int mxr_g_fmt(struct file *file, void *priv,
317 struct v4l2_format *f)
318{
319 struct mxr_layer *layer = video_drvdata(file);
320 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
321
322 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
323
324 pix->width = layer->geo.src.full_width;
325 pix->height = layer->geo.src.full_height;
326 pix->field = V4L2_FIELD_NONE;
327 pix->pixelformat = layer->fmt->fourcc;
328 pix->colorspace = layer->fmt->colorspace;
329 mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
330
331 return 0;
332}
333
334static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
335 enum v4l2_buf_type type)
336{
337 switch (type) {
338 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
339 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
340 return &geo->dst;
341 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
342 return &geo->src;
343 default:
344 return NULL;
345 }
346}
347
348static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
349{
350 struct mxr_layer *layer = video_drvdata(file);
351 struct mxr_crop *crop;
352
353 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
354 crop = choose_crop_by_type(&layer->geo, a->type);
355 if (crop == NULL)
356 return -EINVAL;
357 mxr_layer_geo_fix(layer);
358 a->c.left = crop->x_offset;
359 a->c.top = crop->y_offset;
360 a->c.width = crop->width;
361 a->c.height = crop->height;
362 return 0;
363}
364
365static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
366{
367 struct mxr_layer *layer = video_drvdata(file);
368 struct mxr_crop *crop;
369
370 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
371 crop = choose_crop_by_type(&layer->geo, a->type);
372 if (crop == NULL)
373 return -EINVAL;
374 crop->x_offset = a->c.left;
375 crop->y_offset = a->c.top;
376 crop->width = a->c.width;
377 crop->height = a->c.height;
378 mxr_layer_geo_fix(layer);
379 return 0;
380}
381
382static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
383{
384 struct mxr_layer *layer = video_drvdata(file);
385 struct mxr_crop *crop;
386
387 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
388 crop = choose_crop_by_type(&layer->geo, a->type);
389 if (crop == NULL)
390 return -EINVAL;
391 mxr_layer_geo_fix(layer);
392 a->bounds.left = 0;
393 a->bounds.top = 0;
394 a->bounds.width = crop->full_width;
395 a->bounds.top = crop->full_height;
396 a->defrect = a->bounds;
397 /* setting pixel aspect to 1/1 */
398 a->pixelaspect.numerator = 1;
399 a->pixelaspect.denominator = 1;
400 return 0;
401}
402
403static int mxr_enum_dv_presets(struct file *file, void *fh,
404 struct v4l2_dv_enum_preset *preset)
405{
406 struct mxr_layer *layer = video_drvdata(file);
407 struct mxr_device *mdev = layer->mdev;
408 int ret;
409
410 /* lock protects from changing sd_out */
411 mutex_lock(&mdev->mutex);
412 ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
413 mutex_unlock(&mdev->mutex);
414
415 return ret ? -EINVAL : 0;
416}
417
418static int mxr_s_dv_preset(struct file *file, void *fh,
419 struct v4l2_dv_preset *preset)
420{
421 struct mxr_layer *layer = video_drvdata(file);
422 struct mxr_device *mdev = layer->mdev;
423 int ret;
424
425 /* lock protects from changing sd_out */
426 mutex_lock(&mdev->mutex);
427
428 /* preset change cannot be done while there is an entity
429 * dependant on output configuration
430 */
431 if (mdev->n_output > 0) {
432 mutex_unlock(&mdev->mutex);
433 return -EBUSY;
434 }
435
436 ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
437
438 mutex_unlock(&mdev->mutex);
439
440 /* any failure should return EINVAL according to V4L2 doc */
441 return ret ? -EINVAL : 0;
442}
443
444static int mxr_g_dv_preset(struct file *file, void *fh,
445 struct v4l2_dv_preset *preset)
446{
447 struct mxr_layer *layer = video_drvdata(file);
448 struct mxr_device *mdev = layer->mdev;
449 int ret;
450
451 /* lock protects from changing sd_out */
452 mutex_lock(&mdev->mutex);
453 ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
454 mutex_unlock(&mdev->mutex);
455
456 return ret ? -EINVAL : 0;
457}
458
459static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
460{
461 struct mxr_layer *layer = video_drvdata(file);
462 struct mxr_device *mdev = layer->mdev;
463 int ret;
464
465 /* lock protects from changing sd_out */
466 mutex_lock(&mdev->mutex);
467
468 /* standard change cannot be done while there is an entity
469 * dependant on output configuration
470 */
471 if (mdev->n_output > 0) {
472 mutex_unlock(&mdev->mutex);
473 return -EBUSY;
474 }
475
476 ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
477
478 mutex_unlock(&mdev->mutex);
479
480 return ret ? -EINVAL : 0;
481}
482
483static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
484{
485 struct mxr_layer *layer = video_drvdata(file);
486 struct mxr_device *mdev = layer->mdev;
487 int ret;
488
489 /* lock protects from changing sd_out */
490 mutex_lock(&mdev->mutex);
491 ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
492 mutex_unlock(&mdev->mutex);
493
494 return ret ? -EINVAL : 0;
495}
496
497static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
498{
499 struct mxr_layer *layer = video_drvdata(file);
500 struct mxr_device *mdev = layer->mdev;
501 struct mxr_output *out;
502 struct v4l2_subdev *sd;
503
504 if (a->index >= mdev->output_cnt)
505 return -EINVAL;
506 out = mdev->output[a->index];
507 BUG_ON(out == NULL);
508 sd = out->sd;
509 strlcpy(a->name, out->name, sizeof(a->name));
510
511 /* try to obtain supported tv norms */
512 v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
513 a->capabilities = 0;
514 if (sd->ops->video && sd->ops->video->s_dv_preset)
515 a->capabilities |= V4L2_OUT_CAP_PRESETS;
516 if (sd->ops->video && sd->ops->video->s_std_output)
517 a->capabilities |= V4L2_OUT_CAP_STD;
518 a->type = V4L2_OUTPUT_TYPE_ANALOG;
519
520 return 0;
521}
522
523static int mxr_s_output(struct file *file, void *fh, unsigned int i)
524{
525 struct video_device *vfd = video_devdata(file);
526 struct mxr_layer *layer = video_drvdata(file);
527 struct mxr_device *mdev = layer->mdev;
528 int ret = 0;
529
530 if (i >= mdev->output_cnt || mdev->output[i] == NULL)
531 return -EINVAL;
532
533 mutex_lock(&mdev->mutex);
534 if (mdev->n_output > 0) {
535 ret = -EBUSY;
536 goto done;
537 }
538 mdev->current_output = i;
539 vfd->tvnorms = 0;
540 v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
541 &vfd->tvnorms);
542 mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
543
544done:
545 mutex_unlock(&mdev->mutex);
546 return ret;
547}
548
549static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
550{
551 struct mxr_layer *layer = video_drvdata(file);
552 struct mxr_device *mdev = layer->mdev;
553
554 mutex_lock(&mdev->mutex);
555 *p = mdev->current_output;
556 mutex_unlock(&mdev->mutex);
557
558 return 0;
559}
560
561static int mxr_reqbufs(struct file *file, void *priv,
562 struct v4l2_requestbuffers *p)
563{
564 struct mxr_layer *layer = video_drvdata(file);
565
566 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
567 return vb2_reqbufs(&layer->vb_queue, p);
568}
569
570static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
571{
572 struct mxr_layer *layer = video_drvdata(file);
573
574 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
575 return vb2_querybuf(&layer->vb_queue, p);
576}
577
578static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
579{
580 struct mxr_layer *layer = video_drvdata(file);
581
582 mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
583 return vb2_qbuf(&layer->vb_queue, p);
584}
585
586static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
587{
588 struct mxr_layer *layer = video_drvdata(file);
589
590 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
591 return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
592}
593
594static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
595{
596 struct mxr_layer *layer = video_drvdata(file);
597
598 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
599 return vb2_streamon(&layer->vb_queue, i);
600}
601
602static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
603{
604 struct mxr_layer *layer = video_drvdata(file);
605
606 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
607 return vb2_streamoff(&layer->vb_queue, i);
608}
609
610static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
611 .vidioc_querycap = mxr_querycap,
612 /* format handling */
613 .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
614 .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
615 .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
616 /* buffer control */
617 .vidioc_reqbufs = mxr_reqbufs,
618 .vidioc_querybuf = mxr_querybuf,
619 .vidioc_qbuf = mxr_qbuf,
620 .vidioc_dqbuf = mxr_dqbuf,
621 /* Streaming control */
622 .vidioc_streamon = mxr_streamon,
623 .vidioc_streamoff = mxr_streamoff,
624 /* Preset functions */
625 .vidioc_enum_dv_presets = mxr_enum_dv_presets,
626 .vidioc_s_dv_preset = mxr_s_dv_preset,
627 .vidioc_g_dv_preset = mxr_g_dv_preset,
628 /* analog TV standard functions */
629 .vidioc_s_std = mxr_s_std,
630 .vidioc_g_std = mxr_g_std,
631 /* Output handling */
632 .vidioc_enum_output = mxr_enum_output,
633 .vidioc_s_output = mxr_s_output,
634 .vidioc_g_output = mxr_g_output,
635 /* Crop ioctls */
636 .vidioc_g_crop = mxr_g_crop,
637 .vidioc_s_crop = mxr_s_crop,
638 .vidioc_cropcap = mxr_cropcap,
639};
640
641static int mxr_video_open(struct file *file)
642{
643 struct mxr_layer *layer = video_drvdata(file);
644 struct mxr_device *mdev = layer->mdev;
645 int ret = 0;
646
647 mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
648 /* assure device probe is finished */
649 wait_for_device_probe();
650 /* creating context for file descriptor */
651 ret = v4l2_fh_open(file);
652 if (ret) {
653 mxr_err(mdev, "v4l2_fh_open failed\n");
654 return ret;
655 }
656
657 /* leaving if layer is already initialized */
658 if (!v4l2_fh_is_singular_file(file))
659 return 0;
660
661 /* FIXME: should power be enabled on open? */
662 ret = mxr_power_get(mdev);
663 if (ret) {
664 mxr_err(mdev, "power on failed\n");
665 goto fail_fh_open;
666 }
667
668 ret = vb2_queue_init(&layer->vb_queue);
669 if (ret != 0) {
670 mxr_err(mdev, "failed to initialize vb2 queue\n");
671 goto fail_power;
672 }
673 /* set default format, first on the list */
674 layer->fmt = layer->fmt_array[0];
675 /* setup default geometry */
676 mxr_layer_default_geo(layer);
677
678 return 0;
679
680fail_power:
681 mxr_power_put(mdev);
682
683fail_fh_open:
684 v4l2_fh_release(file);
685
686 return ret;
687}
688
689static unsigned int
690mxr_video_poll(struct file *file, struct poll_table_struct *wait)
691{
692 struct mxr_layer *layer = video_drvdata(file);
693
694 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
695
696 return vb2_poll(&layer->vb_queue, file, wait);
697}
698
699static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
700{
701 struct mxr_layer *layer = video_drvdata(file);
702
703 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
704
705 return vb2_mmap(&layer->vb_queue, vma);
706}
707
708static int mxr_video_release(struct file *file)
709{
710 struct mxr_layer *layer = video_drvdata(file);
711
712 mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
713 if (v4l2_fh_is_singular_file(file)) {
714 vb2_queue_release(&layer->vb_queue);
715 mxr_power_put(layer->mdev);
716 }
717 v4l2_fh_release(file);
718 return 0;
719}
720
721static const struct v4l2_file_operations mxr_fops = {
722 .owner = THIS_MODULE,
723 .open = mxr_video_open,
724 .poll = mxr_video_poll,
725 .mmap = mxr_video_mmap,
726 .release = mxr_video_release,
727 .unlocked_ioctl = video_ioctl2,
728};
729
730static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
731 unsigned int *nplanes, unsigned long sizes[],
732 void *alloc_ctxs[])
733{
734 struct mxr_layer *layer = vb2_get_drv_priv(vq);
735 const struct mxr_format *fmt = layer->fmt;
736 int i;
737 struct mxr_device *mdev = layer->mdev;
738 struct v4l2_plane_pix_format planes[3];
739
740 mxr_dbg(mdev, "%s\n", __func__);
741 /* checking if format was configured */
742 if (fmt == NULL)
743 return -EINVAL;
744 mxr_dbg(mdev, "fmt = %s\n", fmt->name);
745 mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
746 layer->geo.src.full_height);
747
748 *nplanes = fmt->num_subframes;
749 for (i = 0; i < fmt->num_subframes; ++i) {
750 alloc_ctxs[i] = layer->mdev->alloc_ctx;
751 sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
752 mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]);
753 }
754
755 if (*nbuffers == 0)
756 *nbuffers = 1;
757
758 return 0;
759}
760
761static void buf_queue(struct vb2_buffer *vb)
762{
763 struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
764 struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
765 struct mxr_device *mdev = layer->mdev;
766 unsigned long flags;
767 int must_start = 0;
768
769 spin_lock_irqsave(&layer->enq_slock, flags);
770 if (layer->state == MXR_LAYER_STREAMING_START) {
771 layer->state = MXR_LAYER_STREAMING;
772 must_start = 1;
773 }
774 list_add_tail(&buffer->list, &layer->enq_list);
775 spin_unlock_irqrestore(&layer->enq_slock, flags);
776 if (must_start) {
777 layer->ops.stream_set(layer, MXR_ENABLE);
778 mxr_streamer_get(mdev);
779 }
780
781 mxr_dbg(mdev, "queuing buffer\n");
782}
783
784static void wait_lock(struct vb2_queue *vq)
785{
786 struct mxr_layer *layer = vb2_get_drv_priv(vq);
787
788 mxr_dbg(layer->mdev, "%s\n", __func__);
789 mutex_lock(&layer->mutex);
790}
791
792static void wait_unlock(struct vb2_queue *vq)
793{
794 struct mxr_layer *layer = vb2_get_drv_priv(vq);
795
796 mxr_dbg(layer->mdev, "%s\n", __func__);
797 mutex_unlock(&layer->mutex);
798}
799
800static int start_streaming(struct vb2_queue *vq)
801{
802 struct mxr_layer *layer = vb2_get_drv_priv(vq);
803 struct mxr_device *mdev = layer->mdev;
804 unsigned long flags;
805
806 mxr_dbg(mdev, "%s\n", __func__);
807 /* block any changes in output configuration */
808 mxr_output_get(mdev);
809
810 /* update layers geometry */
811 mxr_layer_geo_fix(layer);
812 mxr_geometry_dump(mdev, &layer->geo);
813
814 layer->ops.format_set(layer);
815 /* enabling layer in hardware */
816 spin_lock_irqsave(&layer->enq_slock, flags);
817 layer->state = MXR_LAYER_STREAMING_START;
818 spin_unlock_irqrestore(&layer->enq_slock, flags);
819
820 return 0;
821}
822
823static void mxr_watchdog(unsigned long arg)
824{
825 struct mxr_layer *layer = (struct mxr_layer *) arg;
826 struct mxr_device *mdev = layer->mdev;
827 unsigned long flags;
828
829 mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
830
831 spin_lock_irqsave(&layer->enq_slock, flags);
832
833 if (layer->update_buf == layer->shadow_buf)
834 layer->update_buf = NULL;
835 if (layer->update_buf) {
836 vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
837 layer->update_buf = NULL;
838 }
839 if (layer->shadow_buf) {
840 vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
841 layer->shadow_buf = NULL;
842 }
843 spin_unlock_irqrestore(&layer->enq_slock, flags);
844}
845
846static int stop_streaming(struct vb2_queue *vq)
847{
848 struct mxr_layer *layer = vb2_get_drv_priv(vq);
849 struct mxr_device *mdev = layer->mdev;
850 unsigned long flags;
851 struct timer_list watchdog;
852 struct mxr_buffer *buf, *buf_tmp;
853
854 mxr_dbg(mdev, "%s\n", __func__);
855
856 spin_lock_irqsave(&layer->enq_slock, flags);
857
858 /* reset list */
859 layer->state = MXR_LAYER_STREAMING_FINISH;
860
861 /* set all buffer to be done */
862 list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
863 list_del(&buf->list);
864 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
865 }
866
867 spin_unlock_irqrestore(&layer->enq_slock, flags);
868
869 /* give 1 seconds to complete to complete last buffers */
870 setup_timer_on_stack(&watchdog, mxr_watchdog,
871 (unsigned long)layer);
872 mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
873
874 /* wait until all buffers are goes to done state */
875 vb2_wait_for_all_buffers(vq);
876
877 /* stop timer if all synchronization is done */
878 del_timer_sync(&watchdog);
879 destroy_timer_on_stack(&watchdog);
880
881 /* stopping hardware */
882 spin_lock_irqsave(&layer->enq_slock, flags);
883 layer->state = MXR_LAYER_IDLE;
884 spin_unlock_irqrestore(&layer->enq_slock, flags);
885
886 /* disabling layer in hardware */
887 layer->ops.stream_set(layer, MXR_DISABLE);
888 /* remove one streamer */
889 mxr_streamer_put(mdev);
890 /* allow changes in output configuration */
891 mxr_output_put(mdev);
892 return 0;
893}
894
895static struct vb2_ops mxr_video_qops = {
896 .queue_setup = queue_setup,
897 .buf_queue = buf_queue,
898 .wait_prepare = wait_unlock,
899 .wait_finish = wait_lock,
900 .start_streaming = start_streaming,
901 .stop_streaming = stop_streaming,
902};
903
904/* FIXME: try to put this functions to mxr_base_layer_create */
905int mxr_base_layer_register(struct mxr_layer *layer)
906{
907 struct mxr_device *mdev = layer->mdev;
908 int ret;
909
910 ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
911 if (ret)
912 mxr_err(mdev, "failed to register video device\n");
913 else
914 mxr_info(mdev, "registered layer %s as /dev/video%d\n",
915 layer->vfd.name, layer->vfd.num);
916 return ret;
917}
918
919void mxr_base_layer_unregister(struct mxr_layer *layer)
920{
921 video_unregister_device(&layer->vfd);
922}
923
924void mxr_layer_release(struct mxr_layer *layer)
925{
926 if (layer->ops.release)
927 layer->ops.release(layer);
928}
929
930void mxr_base_layer_release(struct mxr_layer *layer)
931{
932 kfree(layer);
933}
934
935static void mxr_vfd_release(struct video_device *vdev)
936{
937 printk(KERN_INFO "video device release\n");
938}
939
940struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
941 int idx, char *name, struct mxr_layer_ops *ops)
942{
943 struct mxr_layer *layer;
944
945 layer = kzalloc(sizeof *layer, GFP_KERNEL);
946 if (layer == NULL) {
947 mxr_err(mdev, "not enough memory for layer.\n");
948 goto fail;
949 }
950
951 layer->mdev = mdev;
952 layer->idx = idx;
953 layer->ops = *ops;
954
955 spin_lock_init(&layer->enq_slock);
956 INIT_LIST_HEAD(&layer->enq_list);
957 mutex_init(&layer->mutex);
958
959 layer->vfd = (struct video_device) {
960 .minor = -1,
961 .release = mxr_vfd_release,
962 .fops = &mxr_fops,
963 .ioctl_ops = &mxr_ioctl_ops,
964 };
965 strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
966 /* let framework control PRIORITY */
967 set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
968
969 video_set_drvdata(&layer->vfd, layer);
970 layer->vfd.lock = &layer->mutex;
971 layer->vfd.v4l2_dev = &mdev->v4l2_dev;
972
973 layer->vb_queue = (struct vb2_queue) {
974 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
975 .io_modes = VB2_MMAP | VB2_USERPTR,
976 .drv_priv = layer,
977 .buf_struct_size = sizeof(struct mxr_buffer),
978 .ops = &mxr_video_qops,
979 .mem_ops = &vb2_dma_contig_memops,
980 };
981
982 return layer;
983
984fail:
985 return NULL;
986}
987
988static const struct mxr_format *find_format_by_fourcc(
989 struct mxr_layer *layer, unsigned long fourcc)
990{
991 int i;
992
993 for (i = 0; i < layer->fmt_array_size; ++i)
994 if (layer->fmt_array[i]->fourcc == fourcc)
995 return layer->fmt_array[i];
996 return NULL;
997}
998
999static const struct mxr_format *find_format_by_index(
1000 struct mxr_layer *layer, unsigned long index)
1001{
1002 if (index >= layer->fmt_array_size)
1003 return NULL;
1004 return layer->fmt_array[index];
1005}
1006
diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c
new file mode 100644
index 000000000000..6950ed8ac1a0
--- /dev/null
+++ b/drivers/media/video/s5p-tv/mixer_vp_layer.c
@@ -0,0 +1,211 @@
1/*
2 * Samsung TV Mixer driver
3 *
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5 *
6 * Tomasz Stanislawski, <t.stanislaws@samsung.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
10 * by the Free Software Foundiation. either version 2 of the License,
11 * or (at your option) any later version
12 */
13
14#include "mixer.h"
15
16#include "regs-vp.h"
17
18#include <media/videobuf2-dma-contig.h>
19
20/* FORMAT DEFINITIONS */
21static const struct mxr_format mxr_fmt_nv12 = {
22 .name = "NV12",
23 .fourcc = V4L2_PIX_FMT_NV12,
24 .colorspace = V4L2_COLORSPACE_JPEG,
25 .num_planes = 2,
26 .plane = {
27 { .width = 1, .height = 1, .size = 1 },
28 { .width = 2, .height = 2, .size = 2 },
29 },
30 .num_subframes = 1,
31 .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
32};
33
34static const struct mxr_format mxr_fmt_nv21 = {
35 .name = "NV21",
36 .fourcc = V4L2_PIX_FMT_NV21,
37 .colorspace = V4L2_COLORSPACE_JPEG,
38 .num_planes = 2,
39 .plane = {
40 { .width = 1, .height = 1, .size = 1 },
41 { .width = 2, .height = 2, .size = 2 },
42 },
43 .num_subframes = 1,
44 .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
45};
46
47static const struct mxr_format mxr_fmt_nv12m = {
48 .name = "NV12 (mplane)",
49 .fourcc = V4L2_PIX_FMT_NV12M,
50 .colorspace = V4L2_COLORSPACE_JPEG,
51 .num_planes = 2,
52 .plane = {
53 { .width = 1, .height = 1, .size = 1 },
54 { .width = 2, .height = 2, .size = 2 },
55 },
56 .num_subframes = 2,
57 .plane2subframe = {0, 1},
58 .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
59};
60
61static const struct mxr_format mxr_fmt_nv12mt = {
62 .name = "NV12 tiled (mplane)",
63 .fourcc = V4L2_PIX_FMT_NV12MT,
64 .colorspace = V4L2_COLORSPACE_JPEG,
65 .num_planes = 2,
66 .plane = {
67 { .width = 128, .height = 32, .size = 4096 },
68 { .width = 128, .height = 32, .size = 2048 },
69 },
70 .num_subframes = 2,
71 .plane2subframe = {0, 1},
72 .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
73};
74
75static const struct mxr_format *mxr_video_format[] = {
76 &mxr_fmt_nv12,
77 &mxr_fmt_nv21,
78 &mxr_fmt_nv12m,
79 &mxr_fmt_nv12mt,
80};
81
82/* AUXILIARY CALLBACKS */
83
84static void mxr_vp_layer_release(struct mxr_layer *layer)
85{
86 mxr_base_layer_unregister(layer);
87 mxr_base_layer_release(layer);
88}
89
90static void mxr_vp_buffer_set(struct mxr_layer *layer,
91 struct mxr_buffer *buf)
92{
93 dma_addr_t luma_addr[2] = {0, 0};
94 dma_addr_t chroma_addr[2] = {0, 0};
95
96 if (buf == NULL) {
97 mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
98 return;
99 }
100 luma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 0);
101 if (layer->fmt->num_subframes == 2) {
102 chroma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 1);
103 } else {
104 /* FIXME: mxr_get_plane_size compute integer division,
105 * which is slow and should not be performed in interrupt */
106 chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
107 &layer->fmt->plane[0], layer->geo.src.full_width,
108 layer->geo.src.full_height);
109 }
110 if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
111 luma_addr[1] = luma_addr[0] + 0x40;
112 chroma_addr[1] = chroma_addr[0] + 0x40;
113 } else {
114 luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
115 chroma_addr[1] = chroma_addr[0];
116 }
117 mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
118}
119
120static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
121{
122 mxr_reg_vp_layer_stream(layer->mdev, en);
123}
124
125static void mxr_vp_format_set(struct mxr_layer *layer)
126{
127 mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
128}
129
130static void mxr_vp_fix_geometry(struct mxr_layer *layer)
131{
132 struct mxr_geometry *geo = &layer->geo;
133
134 /* align horizontal size to 8 pixels */
135 geo->src.full_width = ALIGN(geo->src.full_width, 8);
136 /* limit to boundary size */
137 geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
138 geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
139 geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
140 geo->src.width = min(geo->src.width, 2047U);
141 geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
142 geo->src.height = min(geo->src.height, 2047U);
143
144 /* setting size of output window */
145 geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
146 geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
147
148 /* ensure that scaling is in range 1/4x to 16x */
149 if (geo->src.width >= 4 * geo->dst.width)
150 geo->src.width = 4 * geo->dst.width;
151 if (geo->dst.width >= 16 * geo->src.width)
152 geo->dst.width = 16 * geo->src.width;
153 if (geo->src.height >= 4 * geo->dst.height)
154 geo->src.height = 4 * geo->dst.height;
155 if (geo->dst.height >= 16 * geo->src.height)
156 geo->dst.height = 16 * geo->src.height;
157
158 /* setting scaling ratio */
159 geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
160 geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
161
162 /* adjust offsets */
163 geo->src.x_offset = min(geo->src.x_offset,
164 geo->src.full_width - geo->src.width);
165 geo->src.y_offset = min(geo->src.y_offset,
166 geo->src.full_height - geo->src.height);
167 geo->dst.x_offset = min(geo->dst.x_offset,
168 geo->dst.full_width - geo->dst.width);
169 geo->dst.y_offset = min(geo->dst.y_offset,
170 geo->dst.full_height - geo->dst.height);
171}
172
173/* PUBLIC API */
174
175struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
176{
177 struct mxr_layer *layer;
178 int ret;
179 struct mxr_layer_ops ops = {
180 .release = mxr_vp_layer_release,
181 .buffer_set = mxr_vp_buffer_set,
182 .stream_set = mxr_vp_stream_set,
183 .format_set = mxr_vp_format_set,
184 .fix_geometry = mxr_vp_fix_geometry,
185 };
186 char name[32];
187
188 sprintf(name, "video%d", idx);
189
190 layer = mxr_base_layer_create(mdev, idx, name, &ops);
191 if (layer == NULL) {
192 mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
193 goto fail;
194 }
195
196 layer->fmt_array = mxr_video_format;
197 layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
198
199 ret = mxr_base_layer_register(layer);
200 if (ret)
201 goto fail_layer;
202
203 return layer;
204
205fail_layer:
206 mxr_base_layer_release(layer);
207
208fail:
209 return NULL;
210}
211
diff --git a/drivers/media/video/s5p-tv/regs-mixer.h b/drivers/media/video/s5p-tv/regs-mixer.h
new file mode 100644
index 000000000000..3c8442609c1a
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-mixer.h
@@ -0,0 +1,121 @@
1/*
2 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * Mixer register header file for Samsung Mixer driver
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11#ifndef SAMSUNG_REGS_MIXER_H
12#define SAMSUNG_REGS_MIXER_H
13
14/*
15 * Register part
16 */
17#define MXR_STATUS 0x0000
18#define MXR_CFG 0x0004
19#define MXR_INT_EN 0x0008
20#define MXR_INT_STATUS 0x000C
21#define MXR_LAYER_CFG 0x0010
22#define MXR_VIDEO_CFG 0x0014
23#define MXR_GRAPHIC0_CFG 0x0020
24#define MXR_GRAPHIC0_BASE 0x0024
25#define MXR_GRAPHIC0_SPAN 0x0028
26#define MXR_GRAPHIC0_SXY 0x002C
27#define MXR_GRAPHIC0_WH 0x0030
28#define MXR_GRAPHIC0_DXY 0x0034
29#define MXR_GRAPHIC0_BLANK 0x0038
30#define MXR_GRAPHIC1_CFG 0x0040
31#define MXR_GRAPHIC1_BASE 0x0044
32#define MXR_GRAPHIC1_SPAN 0x0048
33#define MXR_GRAPHIC1_SXY 0x004C
34#define MXR_GRAPHIC1_WH 0x0050
35#define MXR_GRAPHIC1_DXY 0x0054
36#define MXR_GRAPHIC1_BLANK 0x0058
37#define MXR_BG_CFG 0x0060
38#define MXR_BG_COLOR0 0x0064
39#define MXR_BG_COLOR1 0x0068
40#define MXR_BG_COLOR2 0x006C
41
42/* for parametrized access to layer registers */
43#define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20)
44#define MXR_GRAPHIC_BASE(i) (0x0024 + (i) * 0x20)
45#define MXR_GRAPHIC_SPAN(i) (0x0028 + (i) * 0x20)
46#define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20)
47#define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20)
48#define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20)
49
50/*
51 * Bit definition part
52 */
53
54/* generates mask for range of bits */
55#define MXR_MASK(high_bit, low_bit) \
56 (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
57
58#define MXR_MASK_VAL(val, high_bit, low_bit) \
59 (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
60
61/* bits for MXR_STATUS */
62#define MXR_STATUS_16_BURST (1 << 7)
63#define MXR_STATUS_BURST_MASK (1 << 7)
64#define MXR_STATUS_SYNC_ENABLE (1 << 2)
65#define MXR_STATUS_REG_RUN (1 << 0)
66
67/* bits for MXR_CFG */
68#define MXR_CFG_OUT_YUV444 (0 << 8)
69#define MXR_CFG_OUT_RGB888 (1 << 8)
70#define MXR_CFG_DST_SDO (0 << 7)
71#define MXR_CFG_DST_HDMI (1 << 7)
72#define MXR_CFG_DST_MASK (1 << 7)
73#define MXR_CFG_SCAN_HD_720 (0 << 6)
74#define MXR_CFG_SCAN_HD_1080 (1 << 6)
75#define MXR_CFG_GRP1_ENABLE (1 << 5)
76#define MXR_CFG_GRP0_ENABLE (1 << 4)
77#define MXR_CFG_VP_ENABLE (1 << 3)
78#define MXR_CFG_SCAN_INTERLACE (0 << 2)
79#define MXR_CFG_SCAN_PROGRASSIVE (1 << 2)
80#define MXR_CFG_SCAN_NTSC (0 << 1)
81#define MXR_CFG_SCAN_PAL (1 << 1)
82#define MXR_CFG_SCAN_SD (0 << 0)
83#define MXR_CFG_SCAN_HD (1 << 0)
84#define MXR_CFG_SCAN_MASK 0x47
85
86/* bits for MXR_GRAPHICn_CFG */
87#define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21)
88#define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20)
89#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
90#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
91#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)
92
93/* bits for MXR_GRAPHICn_WH */
94#define MXR_GRP_WH_H_SCALE(x) MXR_MASK_VAL(x, 28, 28)
95#define MXR_GRP_WH_V_SCALE(x) MXR_MASK_VAL(x, 12, 12)
96#define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16)
97#define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0)
98
99/* bits for MXR_GRAPHICn_SXY */
100#define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16)
101#define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0)
102
103/* bits for MXR_GRAPHICn_DXY */
104#define MXR_GRP_DXY_DX(x) MXR_MASK_VAL(x, 26, 16)
105#define MXR_GRP_DXY_DY(x) MXR_MASK_VAL(x, 10, 0)
106
107/* bits for MXR_INT_EN */
108#define MXR_INT_EN_VSYNC (1 << 11)
109#define MXR_INT_EN_ALL (0x0f << 8)
110
111/* bit for MXR_INT_STATUS */
112#define MXR_INT_CLEAR_VSYNC (1 << 11)
113#define MXR_INT_STATUS_VSYNC (1 << 0)
114
115/* bit for MXR_LAYER_CFG */
116#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
117#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
118#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
119
120#endif /* SAMSUNG_REGS_MIXER_H */
121
diff --git a/drivers/media/video/s5p-tv/regs-vp.h b/drivers/media/video/s5p-tv/regs-vp.h
new file mode 100644
index 000000000000..6c63984e11e8
--- /dev/null
+++ b/drivers/media/video/s5p-tv/regs-vp.h
@@ -0,0 +1,88 @@
1/*
2 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * Video processor register header file for Samsung Mixer driver
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef SAMSUNG_REGS_VP_H
13#define SAMSUNG_REGS_VP_H
14
15/*
16 * Register part
17 */
18
19#define VP_ENABLE 0x0000
20#define VP_SRESET 0x0004
21#define VP_SHADOW_UPDATE 0x0008
22#define VP_FIELD_ID 0x000C
23#define VP_MODE 0x0010
24#define VP_IMG_SIZE_Y 0x0014
25#define VP_IMG_SIZE_C 0x0018
26#define VP_PER_RATE_CTRL 0x001C
27#define VP_TOP_Y_PTR 0x0028
28#define VP_BOT_Y_PTR 0x002C
29#define VP_TOP_C_PTR 0x0030
30#define VP_BOT_C_PTR 0x0034
31#define VP_ENDIAN_MODE 0x03CC
32#define VP_SRC_H_POSITION 0x0044
33#define VP_SRC_V_POSITION 0x0048
34#define VP_SRC_WIDTH 0x004C
35#define VP_SRC_HEIGHT 0x0050
36#define VP_DST_H_POSITION 0x0054
37#define VP_DST_V_POSITION 0x0058
38#define VP_DST_WIDTH 0x005C
39#define VP_DST_HEIGHT 0x0060
40#define VP_H_RATIO 0x0064
41#define VP_V_RATIO 0x0068
42#define VP_POLY8_Y0_LL 0x006C
43#define VP_POLY4_Y0_LL 0x00EC
44#define VP_POLY4_C0_LL 0x012C
45
46/*
47 * Bit definition part
48 */
49
50/* generates mask for range of bits */
51
52#define VP_MASK(high_bit, low_bit) \
53 (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
54
55#define VP_MASK_VAL(val, high_bit, low_bit) \
56 (((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
57
58 /* VP_ENABLE */
59#define VP_ENABLE_ON (1 << 0)
60
61/* VP_SRESET */
62#define VP_SRESET_PROCESSING (1 << 0)
63
64/* VP_SHADOW_UPDATE */
65#define VP_SHADOW_UPDATE_ENABLE (1 << 0)
66
67/* VP_MODE */
68#define VP_MODE_NV12 (0 << 6)
69#define VP_MODE_NV21 (1 << 6)
70#define VP_MODE_LINE_SKIP (1 << 5)
71#define VP_MODE_MEM_LINEAR (0 << 4)
72#define VP_MODE_MEM_TILED (1 << 4)
73#define VP_MODE_FMT_MASK (5 << 4)
74#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
75#define VP_MODE_2D_IPC (1 << 1)
76
77/* VP_IMG_SIZE_Y */
78/* VP_IMG_SIZE_C */
79#define VP_IMG_HSIZE(x) VP_MASK_VAL(x, 29, 16)
80#define VP_IMG_VSIZE(x) VP_MASK_VAL(x, 13, 0)
81
82/* VP_SRC_H_POSITION */
83#define VP_SRC_H_POSITION_VAL(x) VP_MASK_VAL(x, 14, 4)
84
85/* VP_ENDIAN_MODE */
86#define VP_ENDIAN_MODE_LITTLE (1 << 0)
87
88#endif /* SAMSUNG_REGS_VP_H */