/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 */

#ifndef _MSM_VIDC_INTERNAL_H_
#define _MSM_VIDC_INTERNAL_H_

#include <linux/atomic.h>
#include <linux/list.h>
#include <linux/time.h>
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/kref.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-v4l2.h>
#include "msm_vidc.h"
#include <media/msm_media_info.h>
#include "vidc_hfi_api.h"
#include "vidc_hfi_helper.h"

#define MSM_VIDC_DRV_NAME "msm_vidc_driver"

/* kernel/msm-4.19 */
#define MSM_VIDC_VERSION     ((0 << 16) + (4 << 8) + 19)

#define MAX_DEBUGFS_NAME 50
#define DEFAULT_TIMEOUT 3
#define DEFAULT_HEIGHT 240
#define DEFAULT_WIDTH 320
#define MIN_SUPPORTED_WIDTH 32
#define MIN_SUPPORTED_HEIGHT 32
#define DEFAULT_FPS 30
#define MINIMUM_FPS 1
#define MAXIMUM_FPS 960
#define SINGLE_INPUT_BUFFER 1
#define SINGLE_OUTPUT_BUFFER 1
#define MAX_NUM_INPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME
#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME

#define MAX_SUPPORTED_INSTANCES 16
#define MAX_SUPPORTED_INSTANCES_24 24

/* Maintains the number of FTB's between each FBD over a window */
#define DCVS_FTB_WINDOW 16
/* Superframe can have maximum of 32 frames */
#define VIDC_SUPERFRAME_MAX 32
#define COLOR_RANGE_UNSPECIFIED (-1)

#define V4L2_EVENT_VIDC_BASE  10
#define INPUT_MPLANE V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
#define OUTPUT_MPLANE V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE

#define RATE_CONTROL_OFF (V4L2_MPEG_VIDEO_BITRATE_MODE_CQ + 1)
#define RATE_CONTROL_LOSSLESS (V4L2_MPEG_VIDEO_BITRATE_MODE_CQ + 2)
#define SYS_MSG_START HAL_SYS_INIT_DONE
#define SYS_MSG_END HAL_SYS_ERROR
#define SESSION_MSG_START HAL_SESSION_EVENT_CHANGE
#define SESSION_MSG_END HAL_SESSION_ERROR
#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)

#define MAX_NAME_LENGTH 64

#define DB_DISABLE_SLICE_BOUNDARY \
	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY

#define NUM_MBS_PER_SEC(__height, __width, __fps) \
	(NUM_MBS_PER_FRAME(__height, __width) * __fps)

#define NUM_MBS_PER_FRAME(__height, __width) \
	((ALIGN(__height, 16) / 16) * (ALIGN(__width, 16) / 16))

#define NUM_MBS_PER_FRAME_HEVC(__height, __width) \
	((ALIGN(__height, 32) / 32) * (ALIGN(__width, 32) / 32))

#define call_core_op(c, op, ...)			\
	(((c) && (c)->core_ops && (c)->core_ops->op) ? \
	((c)->core_ops->op(__VA_ARGS__)) : 0)

/*
 * Convert Q16 number into Integer and Fractional part upto 2 places.
 * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
 * Integer part =  105752 / 65536 = 1;
 * Reminder = 105752 * 0xFFFF = 40216; Last 16 bits.
 * Fractional part = 40216 * 100 / 65536 = 61;
 * Now convert to FP(1, 61, 100).
 */
#define Q16_INT(q) ((q) >> 16)
#define Q16_FRAC(q) ((((q) & 0xFFFF) * 100) >> 16)

struct msm_vidc_inst;

enum vidc_ports {
	INPUT_PORT,
	OUTPUT_PORT,
	MAX_PORT_NUM
};

enum vidc_core_state {
	VIDC_CORE_UNINIT = 0,
	VIDC_CORE_INIT,
	VIDC_CORE_INIT_DONE,
};

/*
 * Do not change the enum values unless
 * you know what you are doing
 */
enum instance_state {
	MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
	MSM_VIDC_CORE_INIT,
	MSM_VIDC_CORE_INIT_DONE,
	MSM_VIDC_OPEN,
	MSM_VIDC_OPEN_DONE,
	MSM_VIDC_LOAD_RESOURCES,
	MSM_VIDC_LOAD_RESOURCES_DONE,
	MSM_VIDC_START,
	MSM_VIDC_START_DONE,
	MSM_VIDC_STOP,
	MSM_VIDC_STOP_DONE,
	MSM_VIDC_RELEASE_RESOURCES,
	MSM_VIDC_RELEASE_RESOURCES_DONE,
	MSM_VIDC_CLOSE,
	MSM_VIDC_CLOSE_DONE,
	MSM_VIDC_CORE_UNINIT,
	MSM_VIDC_CORE_INVALID
};

struct buf_info {
	struct list_head list;
	struct vb2_buffer *buf;
};

struct msm_vidc_list {
	struct list_head list;
	struct mutex lock;
};

static inline void INIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist)
{
	mutex_init(&mlist->lock);
	INIT_LIST_HEAD(&mlist->list);
}

static inline void DEINIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist)
{
	mutex_destroy(&mlist->lock);
}

enum buffer_owner {
	DRIVER,
	FIRMWARE,
	CLIENT,
	MAX_OWNER
};

struct vidc_freq_data {
	struct list_head list;
	u32 device_addr;
	unsigned long freq;
	bool turbo;
};

struct vidc_input_cr_data {
	struct list_head list;
	u32 index;
	u32 input_cr;
};

struct recon_buf {
	struct list_head list;
	u32 buffer_index;
	u32 CR;
	u32 CF;
};

struct eos_buf {
	struct list_head list;
	struct msm_smem smem;
	u32 is_queued;
};

struct internal_buf {
	struct list_head list;
	enum hal_buffer buffer_type;
	struct msm_smem smem;
	enum buffer_owner buffer_ownership;
	bool mark_remove;
};

struct msm_vidc_csc_coeff {
	u32 *vpe_csc_custom_matrix_coeff;
	u32 *vpe_csc_custom_bias_coeff;
	u32 *vpe_csc_custom_limit_coeff;
};

struct msm_vidc_buf_data {
	struct list_head list;
	u32 index;
	u32 input_tag;
	u32 input_tag2;
};

struct msm_vidc_window_data {
	struct list_head list;
	u32 frame_size;
	u32 etb_count;
};

struct msm_vidc_common_data {
	char key[128];
	int value;
};

struct msm_vidc_codec_data {
	u32 fourcc;
	enum session_type session_type;
	int vpp_cycles;
	int vsp_cycles;
	int low_power_cycles;
};

struct msm_vidc_codec_capability {
	enum hal_capability capability_type;
	enum hal_domain domains;
	enum hal_video_codec codecs;
	u32 min;
	u32 max;
	u32 step_size;
	u32 default_value;
};

struct msm_vidc_codec {
	enum hal_domain domain;
	enum hal_video_codec codec;
};

enum efuse_purpose {
	SKU_VERSION = 0,
};

enum sku_version {
	SKU_VERSION_0 = 0,
	SKU_VERSION_1,
	SKU_VERSION_2,
};

struct msm_vidc_efuse_data {
	u32 start_address;
	u32 size;
	u32 mask;
	u32 shift;
	enum efuse_purpose purpose;
};

enum vpu_version {
	VPU_VERSION_AR50 = 1,
	VPU_VERSION_IRIS1,
	VPU_VERSION_IRIS2,
	VPU_VERSION_IRIS2_1,
	VPU_VERSION_AR50_LITE,
};

struct msm_vidc_ubwc_config_data {
	struct {
		u32 max_channel_override : 1;
		u32 mal_length_override : 1;
		u32 hb_override : 1;
		u32 bank_swzl_level_override : 1;
		u32 bank_spreading_override : 1;
		u32 reserved : 27;
	} override_bit_info;

	u32 max_channels;
	u32 mal_length;
	u32 highest_bank_bit;
	u32 bank_swzl_level;
	u32 bank_spreading;
};

struct msm_vidc_platform_data {
	struct msm_vidc_common_data *common_data;
	unsigned int common_data_length;
	struct msm_vidc_codec_data *codec_data;
	unsigned int codec_data_length;
	struct msm_vidc_codec *codecs;
	uint32_t codecs_count;
	struct msm_vidc_codec_capability *codec_caps;
	uint32_t codec_caps_count;
	struct msm_vidc_csc_coeff csc_data;
	struct msm_vidc_efuse_data *efuse_data;
	unsigned int efuse_data_length;
	unsigned int sku_version;
	uint32_t vpu_ver;
	uint32_t num_vpp_pipes;
	struct msm_vidc_ubwc_config_data *ubwc_config;
	uint32_t max_inst_count;
};

struct msm_vidc_format_desc {
	char name[MAX_NAME_LENGTH];
	u8 description[32];
	u32 fourcc;
};

struct msm_vidc_format {
	char name[MAX_NAME_LENGTH];
	u8 description[32];
	u32 count_min;
	u32 count_min_host;
	u32 count_actual;
	struct v4l2_format v4l2_fmt;
};

struct msm_vidc_format_constraint {
	u32 fourcc;
	u32 num_planes;
	u32 y_max_stride;
	u32 y_buffer_alignment;
	u32 uv_max_stride;
	u32 uv_buffer_alignment;
};

struct log_cookie {
	u32 used;
	u32 session_type;
	u32 codec_type;
	char name[20];
};

struct msm_vidc_drv {
	struct mutex lock;
	struct list_head cores;
	int num_cores;
	struct dentry *debugfs_root;
	int thermal_level;
	u32 sku_version;
	struct log_cookie *ctxt;
	u32 num_ctxt;
};

struct msm_video_device {
	int type;
	struct video_device vdev;
};

struct session_prop {
	u32 fps;
	u32 bitrate;
	bool bframe_changed;
	u32 extradata_ctrls;
};

struct buf_queue {
	struct vb2_queue vb2_bufq;
	struct mutex lock;
};

enum profiling_points {
	SYS_INIT = 0,
	SESSION_INIT,
	LOAD_RESOURCES,
	FRAME_PROCESSING,
	FW_IDLE,
	MAX_PROFILING_POINTS,
};

struct buf_count {
	int etb;
	int ftb;
	int fbd;
	int ebd;
};

struct batch_mode {
	bool enable;
	u32 size;
};

enum dcvs_flags {
	MSM_VIDC_DCVS_INCR = BIT(0),
	MSM_VIDC_DCVS_DECR = BIT(1),
};

struct clock_data {
	int buffer_counter;
	int min_threshold;
	int nom_threshold;
	int max_threshold;
	bool dcvs_mode;
	u32 dcvs_window;
	unsigned long bitrate;
	unsigned long min_freq;
	unsigned long curr_freq;
	u32 vpss_cycles;
	u32 ise_cycles;
	u32 ddr_bw;
	u32 sys_cache_bw;
	u32 operating_rate;
	struct msm_vidc_codec_data *entry;
	u32 core_id;
	u32 dpb_fourcc;
	u32 opb_fourcc;
	u32 work_mode;
	bool low_latency_mode;
	bool is_legacy_cbr;
	u32 work_route;
	u32 dcvs_flags;
	u32 frame_rate;
};

struct vidc_bus_vote_data {
	u32 sid;
	enum hal_domain domain;
	enum hal_video_codec codec;
	enum hal_uncompressed_format color_formats[2];
	int num_formats; /* 1 = DPB-OPB unified; 2 = split */
	int input_height, input_width, bitrate;
	int output_height, output_width;
	int rotation;
	int compression_ratio;
	int complexity_factor;
	int input_cr;
	unsigned int lcu_size;
	unsigned int fps;
	enum msm_vidc_power_mode power_mode;
	u32 work_mode;
	bool use_sys_cache;
	bool b_frames_enabled;
	unsigned long calc_bw_ddr;
	unsigned long calc_bw_llcc;
};

struct profile_data {
	int start;
	int stop;
	int cumulative;
	char name[64];
	int sampling;
	int average;
};

struct msm_vidc_debug {
	struct profile_data pdata[MAX_PROFILING_POINTS];
	int profile;
	int samples;
};

enum msm_vidc_modes {
	VIDC_SECURE = BIT(0),
	VIDC_TURBO = BIT(1),
	VIDC_THUMBNAIL = BIT(2),
	VIDC_LOW_POWER = BIT(3),
};

struct msm_vidc_core_ops {
	unsigned long (*calc_freq)(struct msm_vidc_inst *inst, u32 filled_len);
	int (*decide_work_route)(struct msm_vidc_inst *inst);
	int (*decide_work_mode)(struct msm_vidc_inst *inst);
	int (*decide_core_and_power_mode)(struct msm_vidc_inst *inst);
	int (*calc_bw)(struct vidc_bus_vote_data *vidc_data);
};

struct msm_vidc_core {
	struct list_head list;
	struct mutex lock;
	int id;
	struct hfi_device *device;
	struct msm_vidc_platform_data *platform_data;
	struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
	struct v4l2_device v4l2_dev;
	struct list_head instances;
	struct dentry *debugfs_root;
	enum vidc_core_state state;
	struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
	enum msm_vidc_hfi_type hfi_type;
	struct msm_vidc_platform_resources resources;
	struct msm_vidc_capability *capabilities;
	struct delayed_work fw_unload_work;
	struct work_struct ssr_work;
	struct workqueue_struct *vidc_core_workq;
	enum hal_ssr_trigger_type ssr_type;
	bool smmu_fault_handled;
	bool trigger_ssr;
	unsigned long min_freq;
	unsigned long curr_freq;
	struct msm_vidc_core_ops *core_ops;
};

struct msm_vidc_inst;
struct msm_vidc_inst_smem_ops {
	int (*smem_map_dma_buf)(struct msm_vidc_inst *inst,
		struct msm_smem *smem);
	int (*smem_unmap_dma_buf)(struct msm_vidc_inst *inst,
		struct msm_smem *smem);
};

struct msm_vidc_inst {
	struct list_head list;
	struct mutex sync_lock, lock;
	struct msm_vidc_core *core;
	enum session_type session_type;
	void *session;
	u32 sid;
	struct session_prop prop;
	enum instance_state state;
	struct msm_vidc_format fmts[MAX_PORT_NUM];
	struct buf_queue bufq[MAX_PORT_NUM];
	struct msm_vidc_list input_crs;
	struct msm_vidc_list scratchbufs;
	struct msm_vidc_list persistbufs;
	struct msm_vidc_list pending_getpropq;
	struct msm_vidc_list outputbufs;
	struct msm_vidc_list refbufs;
	struct msm_vidc_list eosbufs;
	struct msm_vidc_list registeredbufs;
	struct msm_vidc_list cvpbufs;
	struct msm_vidc_list etb_data;
	struct msm_vidc_list fbd_data;
	struct msm_vidc_list window_data;
	struct msm_vidc_list client_data;
	struct buffer_requirements buff_req;
	struct vidc_frame_data superframe_data[VIDC_SUPERFRAME_MAX];
	struct v4l2_ctrl_handler ctrl_handler;
	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
	struct v4l2_fh event_handler;
	struct msm_smem *extradata_handle;
	bool in_reconfig;
	struct dentry *debugfs_root;
	void *priv;
	struct msm_vidc_debug debug;
	struct buf_count count;
	struct clock_data clk_data;
	struct vidc_bus_vote_data bus_data;
	enum msm_vidc_modes flags;
	struct msm_vidc_capability capability;
	u32 buffer_size_limit;
	enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
	enum multi_stream stream_output_mode;
	struct v4l2_ctrl **ctrls;
	u32 num_ctrls;
	int bit_depth;
	struct kref kref;
	bool in_flush;
	bool out_flush;
	u32 pic_struct;
	u32 colour_space;
	u32 profile;
	u32 level;
	u32 entropy_mode;
	u32 rc_type;
	u32 hybrid_hp;
	u32 layer_bitrate;
	u32 client_set_ctrls;
	bool static_rotation_flip_enabled;
	struct internal_buf *dpb_extra_binfo;
	struct msm_vidc_codec_data *codec_data;
	bool hdr10_sei_enabled;
	struct hal_hdr10_pq_sei hdr10_sei_params;
	struct batch_mode batch;
	struct delayed_work batch_work;
	struct msm_vidc_inst_smem_ops *smem_ops;
	int (*buffer_size_calculators)(struct msm_vidc_inst *inst);
	bool all_intra;
	bool is_perf_eligible_session;
	u32 max_filled_len;
	int full_range;
	u64 last_qbuf_time_ns;
	bool active;
	bool supported;
};

extern struct msm_vidc_drv *vidc_driver;

struct msm_vidc_ctrl {
	u32 id;
	char name[MAX_NAME_LENGTH];
	enum v4l2_ctrl_type type;
	s64 minimum;
	s64 maximum;
	s64 default_value;
	u32 step;
	u32 menu_skip_mask;
	u32 flags;
	const char * const *qmenu;
};

void handle_cmd_response(enum hal_command_response cmd, void *data);
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
	enum hal_ssr_trigger_type type);
int msm_vidc_noc_error_info(struct msm_vidc_core *core);
int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);

enum msm_vidc_flags {
	MSM_VIDC_FLAG_DEFERRED            = BIT(0),
	MSM_VIDC_FLAG_RBR_PENDING         = BIT(1),
	MSM_VIDC_FLAG_QUEUED              = BIT(2),
};

struct msm_vidc_buffer {
	struct list_head list;
	struct kref kref;
	struct msm_smem smem[VIDEO_MAX_PLANES];
	struct vb2_v4l2_buffer vvb;
	enum msm_vidc_flags flags;
};

struct msm_vidc_cvp_buffer {
	struct list_head list;
	struct msm_smem smem;
	struct msm_cvp_buffer buf;
};

void msm_comm_handle_thermal_event(void);
int msm_smem_alloc(size_t size, u32 align, u32 flags,
	enum hal_buffer buffer_type, int map_kernel,
	void  *res, u32 session_type, struct msm_smem *smem, u32 sid);
int msm_smem_free(struct msm_smem *smem, u32 sid);

struct context_bank_info *msm_smem_get_context_bank(u32 session_type,
	bool is_secure, struct msm_vidc_platform_resources *res,
	enum hal_buffer buffer_type, u32 sid);
int msm_smem_map_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem);
int msm_smem_unmap_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem);
struct dma_buf *msm_smem_get_dma_buf(int fd, u32 sid);
void msm_smem_put_dma_buf(void *dma_buf, u32 sid);
int msm_smem_cache_operations(struct dma_buf *dbuf,
	enum smem_cache_ops cache_op, unsigned long offset,
	unsigned long size, u32 sid);
void msm_vidc_fw_unload_handler(struct work_struct *work);
void msm_vidc_ssr_handler(struct work_struct *work);
/*
 * XXX: normally should be in msm_vidc.h, but that's meant for public APIs,
 * whereas this is private
 */
int msm_vidc_destroy(struct msm_vidc_inst *inst);
void *vidc_get_drv_data(struct device *dev);
#endif
