// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * Copyright (c) 2022 MediaTek Inc.
 */

#include <linux/module.h>

#include <linux/dvb/dmx2_mtk.h>

#include "mtk_dmx_io.h"
#include "mtk_dmx_rm.h"
#include "mtk_dmx_mediactrl.h"

#define SERIAL_CLK_RATE 8
#define CI_CLK_DIVIDE_RATE 10

int mtk_dmx_tso_in_config(struct mtk_msource_settings *src, int tso_index)
{
	struct demux_tso_input_cfg in_cfg = { 0 };

	switch (src->input_type) {
	case DMX_MC_INPUT_INTERNAL_FE:
		in_cfg.src_cfg.type = DEMUX_IO_TYPE_IN_DEMOD;
		in_cfg.tso_tsif_id = TSO_TSIF_1;
		break;
	case DMX_MC_INPUT_EXTERNAL_FE:
		in_cfg.src_cfg.type = DEMUX_IO_TYPE_EXT_DEMOD;
		in_cfg.tso_tsif_id = TSO_TSIF_1;
		break;
	case DMX_MC_INPUT_DRAM:
		in_cfg.src_cfg.type = DEMUX_IO_TYPE_MEM;
		in_cfg.tso_tsif_id = TSO_TSIF_5;
		break;
	default:
		MTK_DMX_ERR("invalid input type %d\n", src->input_type);
		return -EFAULT;
	}

	// @TODO: add TSO device node
	in_cfg.tso_eng_id = tso_index;
	in_cfg.src_cfg.port_type = (src->port_type == DMX_MC_PORT_PARALLEL) ?
	DEMUX_PORT_TYPE_PARALLEL : DEMUX_PORT_TYPE_SERIAL;
	in_cfg.src_cfg.port_num = src->port_num;
	mtk_dmx_io_tso_input_cfg(&in_cfg);
	return 0;
}

int mtk_dmx_tso_out_config(
		int tso_index,
		u32 rateKHz,
		bool bUseCi2Clk,
		bool isParallel,
		bool bClk_sample_inv)
{
	struct demux_tso_output_cfg out_cfg = { 0 };

	out_cfg.tso_eng_id = tso_index;
	out_cfg.out_format = DEMUX_OUT_FORMAT_CIPLUS;
	out_cfg.port_type = isParallel ? DEMUX_PORT_TYPE_PARALLEL : DEMUX_PORT_TYPE_SERIAL;
	out_cfg.bClk_sample_inv = bClk_sample_inv;
	out_cfg.isUsbCam = bUseCi2Clk;

	if (rateKHz == 0) {
		out_cfg.clk_cfg.bDefault = true;
		out_cfg.clk_cfg.out_clk = 0;
	} else {
		out_cfg.clk_cfg.bDefault = false;
		out_cfg.clk_cfg.out_clk = (isParallel ? rateKHz : (rateKHz*SERIAL_CLK_RATE));
//		out_cfg.clk_cfg.out_clk += out_cfg.clk_cfg.out_clk / CI_CLK_DIVIDE_RATE;/* removed for DM22TVSW-37219 */
	}
	mtk_dmx_io_tso_output_cfg(&out_cfg);

	return 0;
}

int mtk_dmx_tso_cilink_config(struct mtk_dmx_rm *rm, int cilink_index)
{
	struct demux_cilink_input_cfg in_cfg = { 0 };
	u16 cilink_num = mtk_dmx_rm_get_hwcap_by_id(rm, HWCAPS_TYPE_CILINK);

	if (cilink_index >= cilink_num) {
		MTK_DMX_ERR("index %d is invalid\n", cilink_index);
		return -EFAULT;
	}

	in_cfg.port_num = cilink_index;
	in_cfg.bEnable = true;
	in_cfg.type = DEMUX_IO_TYPE_TSO;
	mtk_dmx_io_set_cilink_input_cfg(&in_cfg);

	return 0;
}

void mtk_dmx_tso_feed(u16 eng, u64 paddr, u32 size)
{
	mtk_dmx_io_tso_feed_filein(eng, TSO_TSIF_5, paddr, size);
}

