aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/exynos/tv/mixer.h
blob: 0a17942f517db9902bc615696361145ab865be2d (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
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
/*
 * 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_EXYNOS_MIXER_DEBUG
	#define DEBUG
#endif

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

#include "regs-mixer.h"

#define INT_LOCK_TV 267200

/** maximum number of output interfaces */
#define MXR_MAX_OUTPUTS 2

/** There are 2 mixers after EXYNOS5250 */
#define MXR_SUB_MIXER0		0
#define MXR_SUB_MIXER1		1
/** maximum number of sub-mixers */
#if defined(CONFIG_ARCH_EXYNOS4)
#define MXR_MAX_SUB_MIXERS	1
#else
#define MXR_MAX_SUB_MIXERS	2
#endif

/** each sub-mixer supports 1 video layer and 2 graphic layers */
#define MXR_LAYER_VIDEO		0
#define MXR_LAYER_GRP0		1
#define MXR_LAYER_GRP1		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

/* mixer pad definitions */
#define MXR_PAD_SINK_GSCALER	0
#define MXR_PAD_SINK_GRP0	1
#define MXR_PAD_SINK_GRP1	2
#define MXR_PAD_SOURCE_GSCALER	3
#define MXR_PAD_SOURCE_GRP0	4
#define MXR_PAD_SOURCE_GRP1	5
#define MXR_PADS_NUM		6
/** 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 dependant */
	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;
};

/** 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_buffer	vb;
	/** node for layer's lists */
	struct list_head	list;
};

/** TV graphic layer pipeline state */
enum mxr_pipeline_state {
	/** graphic layer is not shown */
	MXR_PIPELINE_IDLE = 0,
	/** state between STREAMON and hardware start */
	MXR_PIPELINE_STREAMING_START,
	/** graphic layer is shown */
	MXR_PIPELINE_STREAMING,
	/** state before STREAMOFF is finished */
	MXR_PIPELINE_STREAMING_FINISH,
};

/** TV graphic layer pipeline structure for streaming media data */
struct mxr_pipeline {
	struct media_pipeline pipe;
	enum mxr_pipeline_state state;

	/** starting point on pipeline */
	struct mxr_layer *layer;
};

/** 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_layer_type {
	MXR_LAYER_TYPE_VIDEO = 0,
	MXR_LAYER_TYPE_GRP = 1,
};

struct mxr_layer_en {
	int graph0;
	int graph1;
	int graph2;
	int graph3;
};

/** 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;
	/** layer type */
	enum mxr_layer_type type;
	/** minor number of mixer layer as video device */
	int minor;
	/** 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;

	/** 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;

	/** index of current mixer path : MXR_SUB_MIXERx*/
	int cur_mxr;
	/** source pad of mixer input */
	struct media_pad pad;
	/** pipeline structure for streaming TV graphic layer */
	struct mxr_pipeline pipe;

	/** enable per layer blending for each layer */
	int layer_blend_en;
	/** alpha value for per layer blending */
	u32 layer_alpha;
	/** enable per pixel blending */
	int pixel_blend_en;
	/** enable chromakey */
	int chroma_en;
	/** value for chromakey */
	u32 chroma_val;
	/** priority for each layer */
	u8 prio;
};

/** 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;
#if defined(CONFIG_ARCH_EXYNOS4)
	/** pointer to Video Processor registers */
	void __iomem *vp_regs;
	/** other resources, should used under mxr_device.mutex */
	struct clk *vp;
#endif
#if defined(CONFIG_CPU_EXYNOS4210)
	struct clk *sclk_dac;
#endif
	struct clk *sclk_mixer;
	struct clk *mixer;
	struct clk *sclk_hdmi;
};

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

/** videobuf2 context of mixer */
struct mxr_vb2 {
	const struct vb2_mem_ops *ops;
	void *(*init)(struct mxr_device *mdev);
	void (*cleanup)(void *alloc_ctx);

	unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);

	int (*resume)(void *alloc_ctx);
	void (*suspend)(void *alloc_ctx);

	int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
	void (*set_cacheable)(void *alloc_ctx, bool cacheable);
};

/** sub-mixer 0,1 drivers instance */
struct sub_mxr_device {
	/** state of each layer */
	struct mxr_layer *layer[MXR_MAX_LAYERS];

	/** use of each sub mixer */
	int use;
	/** use of local path gscaler to mixer */
	int local;
	/** for mixer as sub-device */
	struct v4l2_subdev sd;
	/** mixer's pads : 3 sink pad, 3 source pad */
	struct media_pad pads[MXR_PADS_NUM];
	/** format info of mixer's pads */
	struct v4l2_mbus_framefmt mbus_fmt[MXR_PADS_NUM];
	/** crop info of mixer's pads */
	struct v4l2_rect crop[MXR_PADS_NUM];
};

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

	/* video resources */

	/** videbuf2 context */
	const struct mxr_vb2 *vb2;
	/** 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;
	/** mutex for protection of streamer */
	struct mutex s_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;

	/** number of G-Scaler linked to mixer0 */
	int mxr0_gsc;
	/** number of G-Scaler linked to mixer1 */
	int mxr1_gsc;
	/** media entity link setup flags */
	unsigned long flags;

	/** entity info which transfers media data to mixer subdev */
	enum mxr_data_from mxr_data_from;

	/** count of sub-mixers */
	struct sub_mxr_device sub_mxr[MXR_MAX_SUB_MIXERS];

	/** enabled layer number **/
	struct mxr_layer_en layer_en;
	/** frame packing flag **/
	int frame_packing;
};

#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
extern const struct mxr_vb2 mxr_vb2_cma;
#elif defined(CONFIG_VIDEOBUF2_ION)
extern const struct mxr_vb2 mxr_vb2_ion;
#endif

/** transform device structure into mixer device */
static inline struct mxr_device *to_mdev(struct device *dev)
{
	return dev_get_drvdata(dev);
}

/** transform subdev structure into mixer device */
static inline struct mxr_device *sd_to_mdev(struct v4l2_subdev *sd)
{
	struct sub_mxr_device *sub_mxr =
		container_of(sd, struct sub_mxr_device, sd);
	return sub_mxr->layer[MXR_LAYER_GRP0]->mdev;
}

/** transform subdev structure into sub mixer device */
static inline struct sub_mxr_device *sd_to_sub_mxr(struct v4l2_subdev *sd)
{
	return container_of(sd, struct sub_mxr_device, sd);
}

/** transform entity structure into sub mixer device */
static inline struct sub_mxr_device *entity_to_sub_mxr(struct media_entity *me)
{
	struct v4l2_subdev *sd;

	sd = container_of(me, struct v4l2_subdev, entity);
	return container_of(sd, struct sub_mxr_device, sd);
}

/** transform entity structure into sub mixer device */
static inline struct mxr_device *sub_mxr_to_mdev(struct sub_mxr_device *sub_mxr)
{
	int idx;

	if (!strcmp(sub_mxr->sd.name, "s5p-mixer0"))
		idx = MXR_SUB_MIXER0;
	else
		idx = MXR_SUB_MIXER1;

	return container_of(sub_mxr, struct mxr_device, sub_mxr[idx]);
}

/** 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 __devinit mxr_acquire_video(struct mxr_device *mdev,
	struct mxr_output_conf *output_cont, int output_count);

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

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

const struct mxr_format *find_format_by_fourcc(
	struct mxr_layer *layer, unsigned long fourcc);

void mxr_base_layer_release(struct mxr_layer *layer);
void mxr_layer_release(struct mxr_layer *layer);
void mxr_layer_geo_fix(struct mxr_layer *layer);
void mxr_layer_default_geo(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);
/** 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_EXYNOS_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_layer_sync(struct mxr_device *mdev, int en);
void mxr_vsync_set_update(struct mxr_device *mdev, int en);
void mxr_reg_reset(struct mxr_device *mdev);
void mxr_reg_set_layer_prio(struct mxr_device *mdev);
void mxr_reg_set_layer_blend(struct mxr_device *mdev, int sub_mxr, int num,
		int en);
void mxr_reg_layer_alpha(struct mxr_device *mdev, int sub_mxr, int num, u32 a);
void mxr_reg_set_pixel_blend(struct mxr_device *mdev, int sub_mxr, int num,
		int en);
void mxr_reg_set_colorkey(struct mxr_device *mdev, int sub_mxr, int num, int en);
void mxr_reg_colorkey_val(struct mxr_device *mdev, int sub_mxr, int num, u32 v);
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_local_path_clear(struct mxr_device *mdev);
void mxr_reg_local_path_set(struct mxr_device *mdev, int mxr0_gsc, int mxr1_gsc,
		u32 flags);
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_video_layer_stream(struct mxr_device *mdev, int idx, int en);
void mxr_reg_video_geo(struct mxr_device *mdev, int cur_mxr, int idx,
		const struct mxr_geometry *geo);

#if defined(CONFIG_ARCH_EXYNOS4)
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);
#endif
void mxr_reg_dump(struct mxr_device *mdev);

#endif /* SAMSUNG_MIXER_H */