/*
   forward-passthrough.h - example passthrough driver for SoftLab-NSK Forward boards

   Copyright (C) 2017 - 2023 Konstantin Oblaukhov <oblaukhov@sl.iae.nsk.su>

   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 Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef FORWARD_PASSTHROUGH_H
#define FORWARD_PASSTHROUGH_H

#include "forward.h"
#include "forward-irq.h"

#define FORWARD_PASSTHROUGH_MAX_BUFFERS 8

struct forward_passthrough;
struct forward_passthrough_dev_ops;

extern struct forward_passthrough_dev_ops fd788_ops;

/**
 * struct forward_passthrough_format - video format (video timings) description
 * @pixelclock: pixel clock aka mode, in Hz, not including /1.001, e.g. 74250000 for 1080i50
 * @m: video mode with reduced pixel clock (not frame-rate!), aka drop-frame, aka i59.94/p29.97
 * @interlaced: interlaced video
 * @total_width: full frame width, including hanc, e.g. 2640 for 1080i50
 * @total_height: full frame height (both fields), including vanc, e.g. 1125 for 1080i50
 * @width: visible frame width, e.g. 1920 for 1080i50
 * @height: visible frame height (both fields), e.g. 1080 for 1080i50
 * @field_switch: line number at which field switched to, e.g. {1124, 562} for 1080i50
 * @topVBIs: number of vanc lines before active video, e.g. {20, 20} for 1080i50
 * @bottomVBIs: number of vanc lines after active video, e.g. {3, 2} for 1080i50
 * @vpid: SDI payload identification (VPID)
 * @size: size (in bytes) of field
 */
struct forward_passthrough_format {
	u64 pixelclock;
	bool m;
	bool interlaced;
	int total_width;
	int total_height;
	int width;
	int height;
	int field_switch[2];
	int topVBIs[2];
	int bottomVBIs[2];
	u32 vpid;
	u32 size[2];
	u32 raw_size[2];
};

/**
 *  Standard video formats
 */
enum {
	FORWARD_FORMAT_HD_1080I50 = 0,
	FORWARD_FORMAT_HD_1080I60 = 1,
	FORWARD_FORMAT_HD_1080I59 = 2,
	FORWARD_FORMAT_SD_576I50 = 3,
	FORWARD_FORMAT_SD_480I59 = 4,
	FORWARD_FORMAT_HD_720P50 = 5,
	FORWARD_FORMAT_HD_720P60 = 6,
	FORWARD_FORMAT_HD_720P59 = 7,
	FORWARD_FORMAT_HD_1080P25 = 8,
	FORWARD_FORMAT_HD_1080P30 = 9,
	FORWARD_FORMAT_HD_1080P29 = 10,
	FORWARD_FORMAT_HD_1080P24 = 11,
	FORWARD_FORMAT_HD_1080P23 = 12,
	FORWARD_FORMAT_3G_1080P50 = 13,
	FORWARD_FORMAT_3G_1080P60 = 14,
	FORWARD_FORMAT_3G_1080P59 = 15,
	FORWARD_FORMAT_6G_2160P25 = 16,
	FORWARD_FORMAT_6G_2160P30 = 17,
	FORWARD_FORMAT_6G_2160P29 = 18,
	FORWARD_FORMAT_12G_2160P50 = 19,
	FORWARD_FORMAT_12G_2160P60 = 20,
	FORWARD_FORMAT_12G_2160P59 = 21,
};

extern const struct forward_passthrough_format forward_passthrough_formats[];

/**
 * struct forward_passthrough_io - represents passthrough channel pair
 * @pass: pointer to parent
 * @lock: mutex
 * @in_index: input IO number
 * @out_index: output IO number
 * @configured: channel is configured (= input is present and output configured to same mode as input)
 * @streaming: passthrough enabled
 * @format: channel format
 * @v_buffer_size: video buffer size (= field size page aligned)
 * @a_in_buffer_size: audio input buffer size, page aligned
 * @a_out_buffer_size: audio output buffer size, page aligned
 * @a_out_groups: number of audio groups, 1-4 (4-16 channels)
 * @v_in_buffers: input video buffers
 * @v_out_buffers: output video buffers
 * @a_in_buffers: input audio buffers
 * @a_out_buffer: output audio buffer
 * @a_in_decode_buffers: temporary buffers, needed by input audio decoder
 * @a_in_decoded_buffers: decoded input audio, for two fields
 * @a_in_decoded_size: decoded input audio size (in 32-bit words)
 * @last_in_buffers: last received buffer, for two fields
 * @last_in_hw_timestamp: hardware timestamp of last received frame, needed for genlock
 * @no_input_signal: no signal presented on input
 */
struct forward_passthrough_io {
	struct forward_passthrough *pass;
	struct mutex lock;

	int in_index, out_index;
	bool raw;
	bool configured;
	bool streaming;
	struct forward_passthrough_format format;
	size_t v_buffer_size, a_in_buffer_size, a_out_buffer_size;
	int a_out_groups;
	void *v_in_buffers[FORWARD_PASSTHROUGH_MAX_BUFFERS],
		*v_out_buffers[FORWARD_PASSTHROUGH_MAX_BUFFERS];
	void *a_in_buffers[FORWARD_PASSTHROUGH_MAX_BUFFERS];
	void *a_out_buffer;
	void *a_in_decode_buffers[2];
	uint32_t *a_in_decoded_buffers[2];
	int a_in_decoded_size[2];
	int last_in_buffers[2];
	u32 last_in_hw_timestamp;
	u32 last_a_wr_ptr;
	bool no_input_signal;
};

/**
 * struct forward_passthrough - represents passthrough driver
 * @dev: pointer to parent
 * @ops: device-specific functions
 * @io: IO channels
 * @master: genlock master channel
 * @analog_master: analog input is used as genlock master
 * @thread: worker thread
 */
struct forward_passthrough {
	struct forward_dev *dev;
	const struct forward_passthrough_dev_ops *ops;

	struct forward_passthrough_io *io;
	struct forward_passthrough_io *master;
	bool analog_master;
	bool genlocked;

	struct task_struct *threads[FORWARD_MAX_IO / 2];
	struct task_struct *gl_thread;
};

/**
 * struct forward_passthrough - board-specific functions
 * @irq_mask: get irq mask for channel
 * @irq_info_in: get irq info for input, returns buffer numbers and audio data count
 * @irq_info_out: get irq info for output, returns buffer numbers and current audio pointer
 * @region_info: get DMA region information
 * @buffer_map_address: get DMA buffer address
 * @update_io_state: query input & output state
 * @configure_io: query input video format and setup output video formats
 * @configure_genlock: setup genlock
 * @genlock_irq_mask: get irq mask for genlock controller
 * @genlock_irq_info: get irq info for genlock controller
 * @genlock_offset: shift output
 * @toggle_streaming: start/stop capture and playback
 * @update_meta: update output meta-data (vpid, etc)
 * @num_io: number of IO channels
 * @num_in_buffers: number of input buffers
 * @num_out_buffers: number of output buffers
 * @video_buffer_size: video buffer size
 * @audio_buffer_size: audio buffer size
 */
struct forward_passthrough_dev_ops {
	u32 (*irq_mask)(struct forward_passthrough_io *io);
	bool (*irq_info_in)(struct forward_passthrough_io *io, u32 irq, int *prev, int *cur,
			    int *next, u32 *in_a_size);
	bool (*irq_info_out)(struct forward_passthrough_io *io, u32 irq, int *prev, int *cur,
			     int *next, u32 *a_ptr);

	void (*region_info)(struct forward_passthrough_io *io, bool out, u32 *v_address,
			    size_t *v_size, u32 *a_address, size_t *a_size);
	bool (*buffer_map_address)(struct forward_passthrough_io *io, int buffer, bool out,
				   u32 *video, u32 *audio);

	void (*update_io_state)(struct forward_passthrough_io *io);
	void (*configure_io)(struct forward_passthrough_io *io);

	void (*configure_genlock)(struct forward_passthrough_io *io, bool analog);
	u32 (*genlock_irq_mask)(struct forward_passthrough_io *io);
	bool (*genlock_irq_info)(struct forward_passthrough_io *io, u32 irq, bool *field,
				 s32 *gl_offset);
	void (*genlock_offset)(struct forward_passthrough_io *io, s32 offset);
	void (*toggle_streaming)(struct forward_passthrough_io *io, bool in_enable,
				 bool out_enable);

	void (*update_meta)(struct forward_passthrough_io *io);

	int num_io;
	int num_in_buffers, num_out_buffers;
	size_t video_buffer_size, audio_buffer_size;
};

/**
 * forward_passthrough_format_guess() - find standard video format using some known parameters
 */
bool forward_passthrough_format_guess(u64 pixel_clk, bool interlaced, int width, int height,
				      int active_width, int active_height, u64 real_pixelclk,
				      struct forward_passthrough_format *fmt);

/**
 * forward_passthrough_decode_hanc() - decode input HANC from board, extract audio and
 */
void forward_passthrough_decode_hanc(struct forward_passthrough_io *io, int field, u16 *buffer,
				     size_t size);

#endif
