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

#define pr_fmt(fmt) "dprx: " fmt

#include "mtk_srccap.h"
#include "hwreg_srccap_dprx_hdcp.h"

void mtk_dprx_hdcp_type_change_event(void *ptr)
{
	u8 index;
	enum dprx_hdcp_type hdcp_type;
	enum v4l2_srccap_input_source port;
	struct dprx_device *dev = (struct dprx_device *)ptr;
	struct mtk_srccap_dev *srccap_dev =
		container_of(dev, struct mtk_srccap_dev, dprx_dev);
	struct v4l2_event event = {0};
	struct dprx_info *info = dev->info;

	if (!info)
		return;

	for (port = V4L2_SRCCAP_INPUT_SOURCE_DPRX;
	     port < V4L2_SRCCAP_INPUT_SOURCE_DPRX + dev->input_count;
	     port++) {
		index = mtk_dprx_input_to_dprx_id(dev, port);
		hdcp_type = mtk_dprx_hdcp_get_type(dev, port);
		if (hdcp_type != info[index].hdcp_type) {
			info[index].hdcp_type = hdcp_type;

			event.type = V4L2_EVENT_CTRL;
			event.id = DPRX_EVENT_HDCP_TYPE_CHG;
			event.u.ctrl.changes = hdcp_type;
			event.u.ctrl.value = port;
			v4l2_event_queue(srccap_dev->vdev, &event);
		}
	}
}

void mtk_dprx_hdcp1x_status_change_event(void *ptr)
{
	struct dprx_device *dev = (struct dprx_device *)ptr;
	struct mtk_srccap_dev *srccap_dev =
		container_of(dev, struct mtk_srccap_dev, dprx_dev);
	struct v4l2_event event = {0};
	static u8 dbg_cnt = DPRX_NOT_READY_TASK_CNT;

	if (dbg_cnt--) {
		/* TODO: Currently just for test pass */
		event.type = V4L2_EVENT_CTRL;
		event.id = DPRX_EVENT_HDCP1X_STATUS_CHG;
		event.u.ctrl.changes = DPRX_EVENT_TYPE_HDCP1X_R0_PRIME_IRQ;
		event.u.ctrl.value = SRCCAP_INPUT_PORT_DPRX0;

		v4l2_event_queue(srccap_dev->vdev, &event);
	}
}

void mtk_dprx_hdcp2x_status_change_event(void *ptr)
{
	struct dprx_device *dev = (struct dprx_device *)ptr;
	struct mtk_srccap_dev *srccap_dev =
		container_of(dev, struct mtk_srccap_dev, dprx_dev);
	struct v4l2_event event = {0};
	static u8 dbg_cnt = DPRX_NOT_READY_TASK_CNT;

	if (dbg_cnt--) {
		/* TODO: Currently just for test pass */
		event.type = V4L2_EVENT_CTRL;
		event.id = DPRX_EVENT_HDCP2X_STATUS_CHG;
		event.u.ctrl.changes = DPRX_EVENT_TYPE_HDCP2X_READ_DONE;
		event.u.ctrl.value = SRCCAP_INPUT_PORT_DPRX0;

		v4l2_event_queue(srccap_dev->vdev, &event);
	}
}

enum dprx_hdcp_type mtk_dprx_hdcp_get_type(struct dprx_device *dev,
					   enum v4l2_srccap_input_source port)
{
	DPRx_ID dprx_id;
	DP_HDCP_STATE hw_hdcp_type;
	enum dprx_hdcp_type hdcp_type;

	if (!mtk_dprx_is_valid_input_port(dev, port))
		return DPRX_HDCP_NO_ENC;

	dprx_id = mtk_dprx_input_to_dprx_id(dev, port);

	hw_hdcp_type = KDrv_SRCCAP_DPRx_hdcp_check_hdcp_state(dprx_id);

	switch (hw_hdcp_type) {
	case DP_HDCP_1_4:
		hdcp_type = DPRX_HDCP_1_3; // actually dprx is hdcp 1_3
		break;
	case DP_HDCP_2_2:
		hdcp_type = DPRX_HDCP_2_2;
		break;
	case DP_HDCP_NO_ENCRYPTION:
	default:
		hdcp_type = DPRX_HDCP_NO_ENC;
	}

	return hdcp_type;
}
