summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/media/platform/s5p-tv/mixer.h
blob: 42cd2709c41cc1ad6118f2353d0c71ede8728020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
/*
 * Samsung TV Mixer driver
 *
 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
 *
 * Tomasz Stanislawski, <t.stanislaws@samsung.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundiation. either version 2 of the License,
 * or (at your option) any later version
 */

#ifndef SAMSUNG_MIXER_H
#define SAMSUNG_MIXER_H

#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
	#define DEBUG
#endif

#include <linux/fb.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-v4l2.h>

#include "regs-mixer.h"

/** maximum number of output interfaces */
#define MXR_MAX_OUTPUTS 2
/** maximum number of input interfaces (layers) */
#define MXR_MAX_LAYERS 3
#define MXR_DRIVER_NAME "s5p-mixer"
/** maximal number of planes for every layer */
#define MXR_MAX_PLANES	2

#define MXR_ENABLE 1
#define MXR_DISABLE 0

/** description of a macroblock for packed formats */
struct mxr_block {
	/** vertical number of pixels in macroblock */
	unsigned int width;
	/** horizontal number of pixels in macroblock */
	unsigned int height;
	/** size of block in bytes */
	unsigned int size;
};

/** description of supported format */
struct mxr_format {
	/** format name/mnemonic */
	const char *name;
	/** fourcc identifier */
	u32 fourcc;
	/** colorspace identifier */
	enum v4l2_colorspace colorspace;
	/** number of planes in image data */
	int num_planes;
	/** description of block for each plane */
	struct mxr_block plane[MXR_MAX_PLANES];
	/** number of subframes in image data */
	int num_subframes;
	/** specifies to which subframe belong given plane */
	int plane2subframe[MXR_MAX_PLANES];
	/** internal code, driver dependent */
	unsigned long cookie;
};

/** description of crop configuration for image */
struct mxr_crop {
	/** width of layer in pixels */
	unsigned int full_width;
	/** height of layer in pixels */
	unsigned int full_height;
	/** horizontal offset of first pixel to be displayed */
	unsigned int x_offset;
	/** vertical offset of first pixel to be displayed */
	unsigned int y_offset;
	/** width of displayed data in pixels */
	unsigned int width;
	/** height of displayed data in pixels */
	unsigned int height;
	/** indicate which fields are present in buffer */
	unsigned int field;
};

/** stages of geometry operations */
enum mxr_geometry_stage {
	MXR_GEOMETRY_SINK,
	MXR_GEOMETRY_COMPOSE,
	MXR_GEOMETRY_CROP,
	MXR_GEOMETRY_SOURCE,
};

/* flag indicating that offset should be 0 */
#define MXR_NO_OFFSET	0x80000000

/** description of transformation from source to destination image */
struct mxr_geometry {
	/** cropping for source image */
	struct mxr_crop src;
	/** cropping for destination image */
	struct mxr_crop dst;
	/** layer-dependant description of horizontal scaling */
	unsigned int x_ratio;
	/** layer-dependant description of vertical scaling */
	unsigned int y_ratio;
};

/** instance of a buffer */
struct mxr_buffer {
	/** common v4l buffer stuff -- must be first */
	struct vb2_v4l2_buffer vb;
	/** node for layer's lists */
	struct list_head	list;
};


/** internal states of layer */
enum mxr_layer_state {
	/** layers is not shown */
	MXR_LAYER_IDLE = 0,
	/** layer is shown */
	MXR_LAYER_STREAMING,
	/** state before STREAMOFF is finished */
	MXR_LAYER_STREAMING_FINISH,
};

/** forward declarations */
struct mxr_device;
struct mxr_layer;

/** callback for layers operation */
struct mxr_layer_ops {
	/* TODO: try to port it to subdev API */
	/** handler for resource release function */
	void (*release)(struct mxr_layer *);
	/** setting buffer to HW */
	void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
	/** setting format and geometry in HW */
	void (*format_set)(struct mxr_layer *);
	/** streaming stop/start */
	void (*stream_set)(struct mxr_layer *, int);
	/** adjusting geometry */
	void (*fix_geometry)(struct mxr_layer *,
		enum mxr_geometry_stage, unsigned long);
};

/** layer instance, a single window and content displayed on output */
struct mxr_layer {
	/** parent mixer device */
	struct mxr_device *mdev;
	/** layer index (unique identifier) */
	int idx;
	/** callbacks for layer methods */
	struct mxr_layer_ops ops;
	/** format array */
	const struct mxr_format **fmt_array;
	/** size of format array */
	unsigned long fmt_array_size;

	/** lock for protection of list and state fields */
	spinlock_t enq_slock;
	/** list for enqueued buffers */
	struct list_head enq_list;
	/** buffer currently owned by hardware in temporary registers */
	struct mxr_buffer *update_buf;
	/** buffer currently owned by hardware in shadow registers */
	struct mxr_buffer *shadow_buf;
	/** state of layer IDLE/STREAMING */
	enum mxr_layer_state state;

	/** mutex for protection of fields below */
	struct mutex mutex;
	/** handler for video node */
	struct video_device vfd;
	/** queue for output buffers */
	struct vb2_queue vb_queue;
	/** current image format */
	const struct mxr_format *fmt;
	/** current geometry of image */
	struct mxr_geometry geo;
};

/** description of mixers output interface */
struct mxr_output {
	/** name of output */
	char name[32];
	/** output subdev */
	struct v4l2_subdev *sd;
	/** cookie used for configuration of registers */
	int cookie;
};

/** specify source of output subdevs */
struct mxr_output_conf {
	/** name of output (connector) */
	char *output_name;
	/** name of module that generates output subdev */
	char *module_name;
	/** cookie need for mixer HW */
	int cookie;
};

struct clk;
struct regulator;

/** auxiliary resources used my mixer */
struct mxr_resources {
	/** interrupt index */
	int irq;
	/** pointer to Mixer registers */
	void __iomem *mxr_regs;
	/** pointer to Video Processor registers */
	void __iomem *vp_regs;
	/** other resources, should used under mxr_device.mutex */
	struct clk *mixer;
	struct clk *vp;
	struct clk *sclk_mixer;
	struct clk *sclk_hdmi;
	struct clk *sclk_dac;
};

/* event flags used  */
enum mxr_devide_flags {
	MXR_EVENT_VSYNC = 0,
	MXR_EVENT_TOP = 1,
};

/** drivers instance */
struct mxr_device {
	/** master device */
	struct device *dev;
	/** state of each layer */
	struct mxr_layer *layer[MXR_MAX_LAYERS];
	/** state of each output */
	struct mxr_output *output[MXR_MAX_OUTPUTS];
	/** number of registered outputs */
	int output_cnt;

	/* video resources */

	/** V4L2 device */
	struct v4l2_device v4l2_dev;
	/** context of allocator */
	void *alloc_ctx;
	/** event wait queue */
	wait_queue_head_t event_queue;
	/** state flags */
	unsigned long event_flags;

	/** spinlock for protection of registers */
	spinlock_t reg_slock;

	/** mutex for protection of fields below */
	struct mutex mutex;
	/** number of entities depndant on output configuration */
	int n_output;
	/** number of users that do streaming */
	int n_streamer;
	/** index of current output */
	int current_output;
	/** auxiliary resources used my mixer */
	struct mxr_resources res;
};

/** transform device structure into mixer device */
static inline struct mxr_device *to_mdev(struct device *dev)
{
	struct v4l2_device *vdev = dev_get_drvdata(dev);
	return container_of(vdev, struct mxr_device, v4l2_dev);
}

/** get current output data, should be called under mdev's mutex */
static inline struct mxr_output *to_output(struct mxr_device *mdev)
{
	return mdev->output[mdev->current_output];
}

/** get current output subdev, should be called under mdev's mutex */
static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
{
	struct mxr_output *out = to_output(mdev);
	return out ? out->sd : NULL;
}

/** forward declaration for mixer platform data */
struct mxr_platform_data;

/** acquiring common video resources */
int mxr_acquire_video(struct mxr_device *mdev,
	struct mxr_output_conf *output_cont, int output_count);

/** releasing common video resources */
void mxr_release_video(struct mxr_device *mdev);

struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
	int idx, char *name, struct mxr_layer_ops *ops);

void mxr_base_layer_release(struct mxr_layer *layer);
void mxr_layer_release(struct mxr_layer *layer);

int mxr_base_layer_register(struct mxr_layer *layer);
void mxr_base_layer_unregister(struct mxr_layer *layer);

unsigned long mxr_get_plane_size(const struct mxr_block *blk,
	unsigned int width, unsigned int height);

/** adds new consumer for mixer's power */
int __must_check mxr_power_get(struct mxr_device *mdev);
/** removes consumer for mixer's power */
void mxr_power_put(struct mxr_device *mdev);
/** add new client for output configuration */
void mxr_output_get(struct mxr_device *mdev);
/** removes new client for output configuration */
void mxr_output_put(struct mxr_device *mdev);
/** add new client for streaming */
void mxr_streamer_get(struct mxr_device *mdev);
/** removes new client for streaming */
void mxr_streamer_put(struct mxr_device *mdev);
/** returns format of data delivared to current output */
void mxr_get_mbus_fmt(struct mxr_device *mdev,
	struct v4l2_mbus_framefmt *mbus_fmt);

/* Debug */

#define mxr_err(mdev, fmt, ...)  dev_err(mdev->dev, fmt, ##__VA_ARGS__)
#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)

#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
	#define mxr_dbg(mdev, fmt, ...)  dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
#else
	#define mxr_dbg(mdev, fmt, ...)  do { (void) mdev; } while (0)
#endif

/* accessing Mixer's and Video Processor's registers */

void mxr_vsync_set_update(struct mxr_device *mdev, int en);
void mxr_reg_reset(struct mxr_device *mdev);
irqreturn_t mxr_irq_handler(int irq, void *dev_data);
void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
void mxr_reg_streamon(struct mxr_device *mdev);
void mxr_reg_streamoff(struct mxr_device *mdev);
int mxr_reg_wait4vsync(struct mxr_device *mdev);
void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
	struct v4l2_mbus_framefmt *fmt);
void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
	const struct mxr_format *fmt, const struct mxr_geometry *geo);

void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
void mxr_reg_vp_buffer(struct mxr_device *mdev,
	dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
void mxr_reg_vp_format(struct mxr_device *mdev,
	const struct mxr_format *fmt, const struct mxr_geometry *geo);
void mxr_reg_dump(struct mxr_device *mdev);

#endif /* SAMSUNG_MIXER_H */