mixer.h 10.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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>
22
#include <linux/irqreturn.h>
23 24 25 26
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <media/v4l2-device.h>
27
#include <media/videobuf2-v4l2.h>
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

#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];
68
	/** internal code, driver dependent */
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
	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;
};

90 91 92 93 94 95 96 97 98 99 100
/** 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

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
/** 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 */
116
	struct vb2_v4l2_buffer vb;
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
	/** 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 */
148 149
	void (*fix_geometry)(struct mxr_layer *,
		enum mxr_geometry_stage, unsigned long);
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
};

/** 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,
230
	MXR_EVENT_TOP = 1,
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
};

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

/** releasing common video resources */
296
void mxr_release_video(struct mxr_device *mdev);
297 298 299 300

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,
301
	int idx, char *name, const struct mxr_layer_ops *ops);
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

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