// SPDX-License-Identifier: GPL-2.0
/*
 * Support for Intel Camera Imaging ISP subsystem.
 * Copyright (c) 2010 - 2015, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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.
 */

#include "system_global.h"


#include "assert_support.h"
#include "platform_support.h"
#include "ia_css_isys.h"
#include "bitop_support.h"
#include "ia_css_pipeline.h"	/* ia_css_pipeline_get_pipe_io_status() */
#include "sh_css_internal.h"	/* sh_css_sp_pipeline_io_status
				 * SH_CSS_MAX_SP_THREADS
				 */
#include "csi_rx_rmgr.h"

static isys_csi_rx_rsrc_t  isys_csi_rx_rsrc[N_CSI_RX_BACKEND_ID];

void ia_css_isys_csi_rx_lut_rmgr_init(void)
{
	memset(isys_csi_rx_rsrc, 0, sizeof(isys_csi_rx_rsrc));
}

void ia_css_isys_csi_rx_lut_rmgr_uninit(void)
{
	memset(isys_csi_rx_rsrc, 0, sizeof(isys_csi_rx_rsrc));
}

bool ia_css_isys_csi_rx_lut_rmgr_acquire(
    csi_rx_backend_ID_t		backend,
    csi_mipi_packet_type_t		packet_type,
    csi_rx_backend_lut_entry_t	*entry)
{
	bool retval = false;
	u32 max_num_packets_of_type;
	u32 num_active_of_type;
	isys_csi_rx_rsrc_t *cur_rsrc = NULL;
	u16 i;

	assert(backend < N_CSI_RX_BACKEND_ID);
	assert((packet_type == CSI_MIPI_PACKET_TYPE_LONG) ||
	       (packet_type == CSI_MIPI_PACKET_TYPE_SHORT));
	assert(entry);

	if ((backend < N_CSI_RX_BACKEND_ID) && (entry)) {
		cur_rsrc = &isys_csi_rx_rsrc[backend];
		if (packet_type == CSI_MIPI_PACKET_TYPE_LONG) {
			max_num_packets_of_type = N_LONG_PACKET_LUT_ENTRIES[backend];
			num_active_of_type = cur_rsrc->num_long_packets;
		} else {
			max_num_packets_of_type = N_SHORT_PACKET_LUT_ENTRIES[backend];
			num_active_of_type = cur_rsrc->num_short_packets;
		}

		if (num_active_of_type < max_num_packets_of_type) {
			for (i = 0; i < max_num_packets_of_type; i++) {
				if (bitop_getbit(cur_rsrc->active_table, i) == 0) {
					bitop_setbit(cur_rsrc->active_table, i);

					if (packet_type == CSI_MIPI_PACKET_TYPE_LONG) {
						entry->long_packet_entry = i;
						entry->short_packet_entry = 0;
						cur_rsrc->num_long_packets++;
					} else {
						entry->long_packet_entry = 0;
						entry->short_packet_entry = i;
						cur_rsrc->num_short_packets++;
					}
					cur_rsrc->num_active++;
					retval = true;
					break;
				}
			}
		}
	}
	return retval;
}

void ia_css_isys_csi_rx_lut_rmgr_release(
    csi_rx_backend_ID_t		backend,
    csi_mipi_packet_type_t		packet_type,
    csi_rx_backend_lut_entry_t	*entry)
{
	u32 max_num_packets;
	isys_csi_rx_rsrc_t *cur_rsrc = NULL;
	u32 packet_entry = 0;

	assert(backend < N_CSI_RX_BACKEND_ID);
	assert(entry);
	assert((packet_type >= CSI_MIPI_PACKET_TYPE_LONG) ||
	       (packet_type <= CSI_MIPI_PACKET_TYPE_SHORT));

	if ((backend < N_CSI_RX_BACKEND_ID) && (entry)) {
		if (packet_type == CSI_MIPI_PACKET_TYPE_LONG) {
			max_num_packets = N_LONG_PACKET_LUT_ENTRIES[backend];
			packet_entry = entry->long_packet_entry;
		} else {
			max_num_packets = N_SHORT_PACKET_LUT_ENTRIES[backend];
			packet_entry = entry->short_packet_entry;
		}

		cur_rsrc = &isys_csi_rx_rsrc[backend];
		if ((packet_entry < max_num_packets) && (cur_rsrc->num_active > 0)) {
			if (bitop_getbit(cur_rsrc->active_table, packet_entry) == 1) {
				bitop_clearbit(cur_rsrc->active_table, packet_entry);

				if (packet_type == CSI_MIPI_PACKET_TYPE_LONG)
					cur_rsrc->num_long_packets--;
				else
					cur_rsrc->num_short_packets--;
				cur_rsrc->num_active--;
			}
		}
	}
}

int ia_css_isys_csi_rx_register_stream(
    enum mipi_port_id port,
    uint32_t isys_stream_id)
{
	int retval = -EINVAL;

	if ((port < N_INPUT_SYSTEM_CSI_PORT) &&
	    (isys_stream_id < SH_CSS_MAX_ISYS_CHANNEL_NODES)) {
		struct sh_css_sp_pipeline_io_status *pipe_io_status;

		pipe_io_status = ia_css_pipeline_get_pipe_io_status();
		if (bitop_getbit(pipe_io_status->active[port], isys_stream_id) == 0) {
			bitop_setbit(pipe_io_status->active[port], isys_stream_id);
			pipe_io_status->running[port] = 0;
			retval = 0;
		}
	}
	return retval;
}

int ia_css_isys_csi_rx_unregister_stream(
    enum mipi_port_id port,
    uint32_t isys_stream_id)
{
	int retval = -EINVAL;

	if ((port < N_INPUT_SYSTEM_CSI_PORT) &&
	    (isys_stream_id < SH_CSS_MAX_ISYS_CHANNEL_NODES)) {
		struct sh_css_sp_pipeline_io_status *pipe_io_status;

		pipe_io_status = ia_css_pipeline_get_pipe_io_status();
		if (bitop_getbit(pipe_io_status->active[port], isys_stream_id) == 1) {
			bitop_clearbit(pipe_io_status->active[port], isys_stream_id);
			retval = 0;
		}
	}
	return retval;
}
