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

#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/radix-tree.h>
#include <linux/clk.h>
#include <linux/msm-bus.h>
#include "msm_bus_core.h"

struct msm_bus_arb_ops arb_ops;

/**
 * msm_bus_scale_register_client() - Register the clients with the msm bus
 * driver
 * @pdata: Platform data of the client, containing src, dest, ab, ib.
 * Return non-zero value in case of success, 0 in case of failure.
 *
 * Client data contains the vectors specifying arbitrated bandwidth (ab)
 * and instantaneous bandwidth (ib) requested between a particular
 * src and dest.
 */
uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
{
	if (arb_ops.register_client)
		return arb_ops.register_client(pdata);
	pr_err("%s: Bus driver not ready.\n",
			__func__);
	return 0;
}
EXPORT_SYMBOL(msm_bus_scale_register_client);

/**
 * msm_bus_scale_client_update_request() - Update the request for bandwidth
 * from a particular client
 *
 * cl: Handle to the client
 * index: Index into the vector, to which the bw and clock values need to be
 * updated
 */
int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index)
{
	if (arb_ops.update_request)
		return arb_ops.update_request(cl, index);
	pr_err("%s: Bus driver not ready.\n",
			__func__);
	return -EPROBE_DEFER;
}
EXPORT_SYMBOL(msm_bus_scale_client_update_request);

/**
 * msm_bus_scale_client_update_context() - Update the context for a client
 * cl: Handle to the client
 * active_only: Bool to indicate dual context or active-only context.
 * ctx_idx: Voting index to be used when switching contexts.
 */
int msm_bus_scale_client_update_context(uint32_t cl, bool active_only,
							unsigned int ctx_idx)
{
	if (arb_ops.update_context)
		return arb_ops.update_context(cl, active_only, ctx_idx);

	return -EPROBE_DEFER;
}
EXPORT_SYMBOL(msm_bus_scale_client_update_context);

/**
 * msm_bus_scale_unregister_client() - Unregister the client from the bus driver
 * @cl: Handle to the client
 */
void msm_bus_scale_unregister_client(uint32_t cl)
{
	if (arb_ops.unregister_client)
		arb_ops.unregister_client(cl);
	else {
		pr_err("%s: Bus driver not ready.\n",
				__func__);
	}
}
EXPORT_SYMBOL(msm_bus_scale_unregister_client);

/**
 * msm_bus_scale_register() - Register the clients with the msm bus
 * driver
 *
 * @mas: Master ID
 * @slv: Slave ID
 * @name: descriptive name for this client
 * @active_only: Whether or not this bandwidth vote should only be
 *               effective while the application processor is active.
 *
 * Client data contains the vectors specifying arbitrated bandwidth (ab)
 * and instantaneous bandwidth (ib) requested between a particular
 * src and dest.
 */
struct msm_bus_client_handle*
msm_bus_scale_register(uint32_t mas, uint32_t slv, char *name, bool active_only)
{
	if (arb_ops.register_cl)
		return arb_ops.register_cl(mas, slv, name, active_only);
	pr_err("%s: Bus driver not ready.\n",
			__func__);
	return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(msm_bus_scale_register);

/**
 * msm_bus_scale_client_update_bw() - Update the request for bandwidth
 * from a particular client
 *
 * @cl: Handle to the client
 * @ab: Arbitrated bandwidth being requested
 * @ib: Instantaneous bandwidth being requested
 */
int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
{
	if (arb_ops.update_request)
		return arb_ops.update_bw(cl, ab, ib);
	pr_err("%s: Bus driver not ready.\n", __func__);
	return -EPROBE_DEFER;
}
EXPORT_SYMBOL(msm_bus_scale_update_bw);

/**
 * msm_bus_scale_change_context() - Update the context for a particular client
 * cl: Handle to the client
 * act_ab: The average bandwidth(AB) in Bytes/s to be used in active context.
 * act_ib: The instantaneous bandwidth(IB) in Bytes/s to be used in active
 *         context.
 * dual_ib: The average bandwidth(AB) in Bytes/s to be used in dual context.
 * dual_ab: The instantaneous bandwidth(IB) in Bytes/s to be used in dual
 *         context.
 */
int
msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
				u64 act_ib, u64 dual_ib, u64 dual_ab)
{
	if (arb_ops.update_context)
		return arb_ops.update_bw_context(cl, act_ab, act_ib,
							dual_ab, dual_ib);

	return -EPROBE_DEFER;
}
EXPORT_SYMBOL(msm_bus_scale_update_bw_context);

/**
 * msm_bus_scale_unregister() - Update the request for bandwidth
 * from a particular client
 *
 * cl: Handle to the client
 */
void msm_bus_scale_unregister(struct msm_bus_client_handle *cl)
{
	if (arb_ops.unregister)
		arb_ops.unregister(cl);
	else
		pr_err("%s: Bus driver not ready.\n",
				__func__);
}
EXPORT_SYMBOL(msm_bus_scale_unregister);

/**
 * msm_bus_scale_query_tcs_cmd() - Query for a list of TCS commands for
 * an aggregated votes of paths from a single usecase.
 *
 * tcs_usecase: pointer to client allocated memory blob
 * cl: Handle to the client
 * index: Index into the vector, to which the bw and clock values need to be
 * updated
 */
int msm_bus_scale_query_tcs_cmd(struct msm_bus_tcs_usecase *tcs_usecase,
					uint32_t cl, unsigned int index)
{
	if (arb_ops.query_usecase)
		return arb_ops.query_usecase(tcs_usecase, cl, index);
	pr_err("%s: Bus driver not ready.\n",
			__func__);
	return -EPROBE_DEFER;
}
EXPORT_SYMBOL(msm_bus_scale_query_tcs_cmd);

/**
 * msm_bus_scale_query_tcs_cmd_all() - Query for a list of TCS commands for
 * an aggregated vote of paths for all usecases registered by client
 *
 * tcs_handle: pointer to client allocated memory blob
 * cl: Handle to the client
 *
 */
int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle *tcs_handle,
					uint32_t cl)
{
	if (arb_ops.query_usecase)
		return arb_ops.query_usecase_all(tcs_handle, cl);
	pr_err("%s: Bus driver not ready.\n",
			__func__);
	return -EPROBE_DEFER;
}
EXPORT_SYMBOL(msm_bus_scale_query_tcs_cmd_all);
