Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 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> |
Sachin Kamat | 5853d1a | 2013-02-07 02:55:54 -0300 | [diff] [blame] | 22 | #include <linux/irqreturn.h> |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 23 | #include <linux/kernel.h> |
| 24 | #include <linux/spinlock.h> |
| 25 | #include <linux/wait.h> |
| 26 | #include <media/v4l2-device.h> |
| 27 | #include <media/videobuf2-core.h> |
| 28 | |
| 29 | #include "regs-mixer.h" |
| 30 | |
| 31 | /** maximum number of output interfaces */ |
| 32 | #define MXR_MAX_OUTPUTS 2 |
| 33 | /** maximum number of input interfaces (layers) */ |
| 34 | #define MXR_MAX_LAYERS 3 |
| 35 | #define MXR_DRIVER_NAME "s5p-mixer" |
| 36 | /** maximal number of planes for every layer */ |
| 37 | #define MXR_MAX_PLANES 2 |
| 38 | |
| 39 | #define MXR_ENABLE 1 |
| 40 | #define MXR_DISABLE 0 |
| 41 | |
| 42 | /** description of a macroblock for packed formats */ |
| 43 | struct mxr_block { |
| 44 | /** vertical number of pixels in macroblock */ |
| 45 | unsigned int width; |
| 46 | /** horizontal number of pixels in macroblock */ |
| 47 | unsigned int height; |
| 48 | /** size of block in bytes */ |
| 49 | unsigned int size; |
| 50 | }; |
| 51 | |
| 52 | /** description of supported format */ |
| 53 | struct mxr_format { |
| 54 | /** format name/mnemonic */ |
| 55 | const char *name; |
| 56 | /** fourcc identifier */ |
| 57 | u32 fourcc; |
| 58 | /** colorspace identifier */ |
| 59 | enum v4l2_colorspace colorspace; |
| 60 | /** number of planes in image data */ |
| 61 | int num_planes; |
| 62 | /** description of block for each plane */ |
| 63 | struct mxr_block plane[MXR_MAX_PLANES]; |
| 64 | /** number of subframes in image data */ |
| 65 | int num_subframes; |
| 66 | /** specifies to which subframe belong given plane */ |
| 67 | int plane2subframe[MXR_MAX_PLANES]; |
Jonathan McCrohan | f58c91c | 2013-10-20 21:34:01 -0300 | [diff] [blame] | 68 | /** internal code, driver dependent */ |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 69 | unsigned long cookie; |
| 70 | }; |
| 71 | |
| 72 | /** description of crop configuration for image */ |
| 73 | struct mxr_crop { |
| 74 | /** width of layer in pixels */ |
| 75 | unsigned int full_width; |
| 76 | /** height of layer in pixels */ |
| 77 | unsigned int full_height; |
| 78 | /** horizontal offset of first pixel to be displayed */ |
| 79 | unsigned int x_offset; |
| 80 | /** vertical offset of first pixel to be displayed */ |
| 81 | unsigned int y_offset; |
| 82 | /** width of displayed data in pixels */ |
| 83 | unsigned int width; |
| 84 | /** height of displayed data in pixels */ |
| 85 | unsigned int height; |
| 86 | /** indicate which fields are present in buffer */ |
| 87 | unsigned int field; |
| 88 | }; |
| 89 | |
Tomasz Stanislawski | 0d066d3 | 2011-08-25 07:14:26 -0300 | [diff] [blame] | 90 | /** stages of geometry operations */ |
| 91 | enum mxr_geometry_stage { |
| 92 | MXR_GEOMETRY_SINK, |
| 93 | MXR_GEOMETRY_COMPOSE, |
| 94 | MXR_GEOMETRY_CROP, |
| 95 | MXR_GEOMETRY_SOURCE, |
| 96 | }; |
| 97 | |
| 98 | /* flag indicating that offset should be 0 */ |
| 99 | #define MXR_NO_OFFSET 0x80000000 |
| 100 | |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 101 | /** description of transformation from source to destination image */ |
| 102 | struct mxr_geometry { |
| 103 | /** cropping for source image */ |
| 104 | struct mxr_crop src; |
| 105 | /** cropping for destination image */ |
| 106 | struct mxr_crop dst; |
| 107 | /** layer-dependant description of horizontal scaling */ |
| 108 | unsigned int x_ratio; |
| 109 | /** layer-dependant description of vertical scaling */ |
| 110 | unsigned int y_ratio; |
| 111 | }; |
| 112 | |
| 113 | /** instance of a buffer */ |
| 114 | struct mxr_buffer { |
| 115 | /** common v4l buffer stuff -- must be first */ |
| 116 | struct vb2_buffer vb; |
| 117 | /** node for layer's lists */ |
| 118 | struct list_head list; |
| 119 | }; |
| 120 | |
| 121 | |
| 122 | /** internal states of layer */ |
| 123 | enum mxr_layer_state { |
| 124 | /** layers is not shown */ |
| 125 | MXR_LAYER_IDLE = 0, |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 126 | /** layer is shown */ |
| 127 | MXR_LAYER_STREAMING, |
| 128 | /** state before STREAMOFF is finished */ |
| 129 | MXR_LAYER_STREAMING_FINISH, |
| 130 | }; |
| 131 | |
| 132 | /** forward declarations */ |
| 133 | struct mxr_device; |
| 134 | struct mxr_layer; |
| 135 | |
| 136 | /** callback for layers operation */ |
| 137 | struct mxr_layer_ops { |
| 138 | /* TODO: try to port it to subdev API */ |
| 139 | /** handler for resource release function */ |
| 140 | void (*release)(struct mxr_layer *); |
| 141 | /** setting buffer to HW */ |
| 142 | void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *); |
| 143 | /** setting format and geometry in HW */ |
| 144 | void (*format_set)(struct mxr_layer *); |
| 145 | /** streaming stop/start */ |
| 146 | void (*stream_set)(struct mxr_layer *, int); |
| 147 | /** adjusting geometry */ |
Tomasz Stanislawski | 0d066d3 | 2011-08-25 07:14:26 -0300 | [diff] [blame] | 148 | void (*fix_geometry)(struct mxr_layer *, |
| 149 | enum mxr_geometry_stage, unsigned long); |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 150 | }; |
| 151 | |
| 152 | /** layer instance, a single window and content displayed on output */ |
| 153 | struct mxr_layer { |
| 154 | /** parent mixer device */ |
| 155 | struct mxr_device *mdev; |
| 156 | /** layer index (unique identifier) */ |
| 157 | int idx; |
| 158 | /** callbacks for layer methods */ |
| 159 | struct mxr_layer_ops ops; |
| 160 | /** format array */ |
| 161 | const struct mxr_format **fmt_array; |
| 162 | /** size of format array */ |
| 163 | unsigned long fmt_array_size; |
| 164 | |
| 165 | /** lock for protection of list and state fields */ |
| 166 | spinlock_t enq_slock; |
| 167 | /** list for enqueued buffers */ |
| 168 | struct list_head enq_list; |
| 169 | /** buffer currently owned by hardware in temporary registers */ |
| 170 | struct mxr_buffer *update_buf; |
| 171 | /** buffer currently owned by hardware in shadow registers */ |
| 172 | struct mxr_buffer *shadow_buf; |
| 173 | /** state of layer IDLE/STREAMING */ |
| 174 | enum mxr_layer_state state; |
| 175 | |
| 176 | /** mutex for protection of fields below */ |
| 177 | struct mutex mutex; |
| 178 | /** handler for video node */ |
| 179 | struct video_device vfd; |
| 180 | /** queue for output buffers */ |
| 181 | struct vb2_queue vb_queue; |
| 182 | /** current image format */ |
| 183 | const struct mxr_format *fmt; |
| 184 | /** current geometry of image */ |
| 185 | struct mxr_geometry geo; |
| 186 | }; |
| 187 | |
| 188 | /** description of mixers output interface */ |
| 189 | struct mxr_output { |
| 190 | /** name of output */ |
| 191 | char name[32]; |
| 192 | /** output subdev */ |
| 193 | struct v4l2_subdev *sd; |
| 194 | /** cookie used for configuration of registers */ |
| 195 | int cookie; |
| 196 | }; |
| 197 | |
| 198 | /** specify source of output subdevs */ |
| 199 | struct mxr_output_conf { |
| 200 | /** name of output (connector) */ |
| 201 | char *output_name; |
| 202 | /** name of module that generates output subdev */ |
| 203 | char *module_name; |
| 204 | /** cookie need for mixer HW */ |
| 205 | int cookie; |
| 206 | }; |
| 207 | |
| 208 | struct clk; |
| 209 | struct regulator; |
| 210 | |
| 211 | /** auxiliary resources used my mixer */ |
| 212 | struct mxr_resources { |
| 213 | /** interrupt index */ |
| 214 | int irq; |
| 215 | /** pointer to Mixer registers */ |
| 216 | void __iomem *mxr_regs; |
| 217 | /** pointer to Video Processor registers */ |
| 218 | void __iomem *vp_regs; |
| 219 | /** other resources, should used under mxr_device.mutex */ |
| 220 | struct clk *mixer; |
| 221 | struct clk *vp; |
| 222 | struct clk *sclk_mixer; |
| 223 | struct clk *sclk_hdmi; |
| 224 | struct clk *sclk_dac; |
| 225 | }; |
| 226 | |
| 227 | /* event flags used */ |
| 228 | enum mxr_devide_flags { |
| 229 | MXR_EVENT_VSYNC = 0, |
Tomasz Stanislawski | ef6a6dd | 2012-03-09 10:49:58 -0300 | [diff] [blame] | 230 | MXR_EVENT_TOP = 1, |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 231 | }; |
| 232 | |
| 233 | /** drivers instance */ |
| 234 | struct mxr_device { |
| 235 | /** master device */ |
| 236 | struct device *dev; |
| 237 | /** state of each layer */ |
| 238 | struct mxr_layer *layer[MXR_MAX_LAYERS]; |
| 239 | /** state of each output */ |
| 240 | struct mxr_output *output[MXR_MAX_OUTPUTS]; |
| 241 | /** number of registered outputs */ |
| 242 | int output_cnt; |
| 243 | |
| 244 | /* video resources */ |
| 245 | |
| 246 | /** V4L2 device */ |
| 247 | struct v4l2_device v4l2_dev; |
| 248 | /** context of allocator */ |
| 249 | void *alloc_ctx; |
| 250 | /** event wait queue */ |
| 251 | wait_queue_head_t event_queue; |
| 252 | /** state flags */ |
| 253 | unsigned long event_flags; |
| 254 | |
| 255 | /** spinlock for protection of registers */ |
| 256 | spinlock_t reg_slock; |
| 257 | |
| 258 | /** mutex for protection of fields below */ |
| 259 | struct mutex mutex; |
| 260 | /** number of entities depndant on output configuration */ |
| 261 | int n_output; |
| 262 | /** number of users that do streaming */ |
| 263 | int n_streamer; |
| 264 | /** index of current output */ |
| 265 | int current_output; |
| 266 | /** auxiliary resources used my mixer */ |
| 267 | struct mxr_resources res; |
| 268 | }; |
| 269 | |
| 270 | /** transform device structure into mixer device */ |
| 271 | static inline struct mxr_device *to_mdev(struct device *dev) |
| 272 | { |
| 273 | struct v4l2_device *vdev = dev_get_drvdata(dev); |
| 274 | return container_of(vdev, struct mxr_device, v4l2_dev); |
| 275 | } |
| 276 | |
| 277 | /** get current output data, should be called under mdev's mutex */ |
| 278 | static inline struct mxr_output *to_output(struct mxr_device *mdev) |
| 279 | { |
| 280 | return mdev->output[mdev->current_output]; |
| 281 | } |
| 282 | |
| 283 | /** get current output subdev, should be called under mdev's mutex */ |
| 284 | static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev) |
| 285 | { |
| 286 | struct mxr_output *out = to_output(mdev); |
| 287 | return out ? out->sd : NULL; |
| 288 | } |
| 289 | |
| 290 | /** forward declaration for mixer platform data */ |
| 291 | struct mxr_platform_data; |
| 292 | |
| 293 | /** acquiring common video resources */ |
Greg Kroah-Hartman | 4c62e97 | 2012-12-21 13:17:53 -0800 | [diff] [blame] | 294 | int mxr_acquire_video(struct mxr_device *mdev, |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 295 | struct mxr_output_conf *output_cont, int output_count); |
| 296 | |
| 297 | /** releasing common video resources */ |
Sachin Kamat | e6364a9 | 2012-03-12 03:13:34 -0300 | [diff] [blame] | 298 | void mxr_release_video(struct mxr_device *mdev); |
Tomasz Stanislawski | fef1c8d | 2011-02-02 05:40:08 -0300 | [diff] [blame] | 299 | |
| 300 | struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx); |
| 301 | struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx); |
| 302 | struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, |
| 303 | int idx, char *name, struct mxr_layer_ops *ops); |
| 304 | |
| 305 | void mxr_base_layer_release(struct mxr_layer *layer); |
| 306 | void mxr_layer_release(struct mxr_layer *layer); |
| 307 | |
| 308 | int mxr_base_layer_register(struct mxr_layer *layer); |
| 309 | void mxr_base_layer_unregister(struct mxr_layer *layer); |
| 310 | |
| 311 | unsigned long mxr_get_plane_size(const struct mxr_block *blk, |
| 312 | unsigned int width, unsigned int height); |
| 313 | |
| 314 | /** adds new consumer for mixer's power */ |
| 315 | int __must_check mxr_power_get(struct mxr_device *mdev); |
| 316 | /** removes consumer for mixer's power */ |
| 317 | void mxr_power_put(struct mxr_device *mdev); |
| 318 | /** add new client for output configuration */ |
| 319 | void mxr_output_get(struct mxr_device *mdev); |
| 320 | /** removes new client for output configuration */ |
| 321 | void mxr_output_put(struct mxr_device *mdev); |
| 322 | /** add new client for streaming */ |
| 323 | void mxr_streamer_get(struct mxr_device *mdev); |
| 324 | /** removes new client for streaming */ |
| 325 | void mxr_streamer_put(struct mxr_device *mdev); |
| 326 | /** returns format of data delivared to current output */ |
| 327 | void mxr_get_mbus_fmt(struct mxr_device *mdev, |
| 328 | struct v4l2_mbus_framefmt *mbus_fmt); |
| 329 | |
| 330 | /* Debug */ |
| 331 | |
| 332 | #define mxr_err(mdev, fmt, ...) dev_err(mdev->dev, fmt, ##__VA_ARGS__) |
| 333 | #define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__) |
| 334 | #define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__) |
| 335 | |
| 336 | #ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG |
| 337 | #define mxr_dbg(mdev, fmt, ...) dev_dbg(mdev->dev, fmt, ##__VA_ARGS__) |
| 338 | #else |
| 339 | #define mxr_dbg(mdev, fmt, ...) do { (void) mdev; } while (0) |
| 340 | #endif |
| 341 | |
| 342 | /* accessing Mixer's and Video Processor's registers */ |
| 343 | |
| 344 | void mxr_vsync_set_update(struct mxr_device *mdev, int en); |
| 345 | void mxr_reg_reset(struct mxr_device *mdev); |
| 346 | irqreturn_t mxr_irq_handler(int irq, void *dev_data); |
| 347 | void mxr_reg_s_output(struct mxr_device *mdev, int cookie); |
| 348 | void mxr_reg_streamon(struct mxr_device *mdev); |
| 349 | void mxr_reg_streamoff(struct mxr_device *mdev); |
| 350 | int mxr_reg_wait4vsync(struct mxr_device *mdev); |
| 351 | void mxr_reg_set_mbus_fmt(struct mxr_device *mdev, |
| 352 | struct v4l2_mbus_framefmt *fmt); |
| 353 | void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en); |
| 354 | void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr); |
| 355 | void mxr_reg_graph_format(struct mxr_device *mdev, int idx, |
| 356 | const struct mxr_format *fmt, const struct mxr_geometry *geo); |
| 357 | |
| 358 | void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en); |
| 359 | void mxr_reg_vp_buffer(struct mxr_device *mdev, |
| 360 | dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]); |
| 361 | void mxr_reg_vp_format(struct mxr_device *mdev, |
| 362 | const struct mxr_format *fmt, const struct mxr_geometry *geo); |
| 363 | void mxr_reg_dump(struct mxr_device *mdev); |
| 364 | |
| 365 | #endif /* SAMSUNG_MIXER_H */ |
| 366 | |