/* SPDX-License-Identifier: GPL-2.0 */
/*
 *
 * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU license.
 *
 * This program is distributed in the hope that 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you can access it online at
 * http://www.gnu.org/licenses/gpl-2.0.html.
 *
 */

/**
 * @file
 * Mali arbiter power manager state machine and APIs
 */

#ifndef _MALI_KBASE_ARBITER_PM_H_
#define _MALI_KBASE_ARBITER_PM_H_

#include "mali_kbase_arbif.h"

/**
 * enum kbase_vm_state - Current PM Arbitration state.
 *
 * @KBASE_VM_STATE_INITIALIZING: Special state before arbiter is initialized.
 * @KBASE_VM_STATE_INITIALIZING_WITH_GPU: Initialization after GPU
 *                                        has been granted.
 * @KBASE_VM_STATE_SUSPENDED: KBase is suspended by OS and GPU is not assigned.
 * @KBASE_VM_STATE_STOPPED: GPU is not assigned to KBase and is not required.
 * @KBASE_VM_STATE_STOPPED_GPU_REQUESTED: GPU is not assigned to KBase
 *                                        but a request has been made.
 * @KBASE_VM_STATE_STARTING: GPU is assigned and KBase is getting ready to run.
 * @KBASE_VM_STATE_IDLE: GPU is assigned but KBase has no work to do
 * @KBASE_VM_STATE_ACTIVE: GPU is assigned and KBase is busy using it
 * @KBASE_VM_STATE_SUSPEND_PENDING: OS is going into suspend mode.
 * @KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT: OS is going into suspend mode but GPU
 *                                         has already been requested.
 *                                         In this situation we must wait for
 *                                         the Arbiter to send a GRANTED message
 *                                         and respond immediately with
 *                                         a STOPPED message before entering
 *                                         the suspend mode.
 * @KBASE_VM_STATE_STOPPING_IDLE: Arbiter has sent a stopped message and there
 *                                is currently no work to do on the GPU.
 * @KBASE_VM_STATE_STOPPING_ACTIVE: Arbiter has sent a stopped message when
 *                                  KBase has work to do.
 */
enum kbase_vm_state {
	KBASE_VM_STATE_INITIALIZING,
	KBASE_VM_STATE_INITIALIZING_WITH_GPU,
	KBASE_VM_STATE_SUSPENDED,
	KBASE_VM_STATE_STOPPED,
	KBASE_VM_STATE_STOPPED_GPU_REQUESTED,
	KBASE_VM_STATE_STARTING,
	KBASE_VM_STATE_IDLE,
	KBASE_VM_STATE_ACTIVE,
	KBASE_VM_STATE_SUSPEND_PENDING,
	KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT,
	KBASE_VM_STATE_STOPPING_IDLE,
	KBASE_VM_STATE_STOPPING_ACTIVE
};

/**
 * kbase_arbiter_pm_early_init() - Initialize arbiter for VM Paravirtualized use
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 *
 * Initialize the arbiter and other required resources during the runtime
 * and request the GPU for the VM for the first time.
 *
 * Return: 0 if successful, otherwise a standard Linux error code
 */
int kbase_arbiter_pm_early_init(struct kbase_device *kbdev);

/**
 * kbase_arbiter_pm_early_term() - Shutdown arbiter and free resources.
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 *
 * Clean up all the resources
 */
void kbase_arbiter_pm_early_term(struct kbase_device *kbdev);

/**
 * kbase_arbiter_pm_release_interrupts() - Release the GPU interrupts
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 *
 * Releases interrupts and set the interrupt flag to false
 */
void kbase_arbiter_pm_release_interrupts(struct kbase_device *kbdev);

/**
 * kbase_arbiter_pm_install_interrupts() - Install the GPU interrupts
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 *
 * Install interrupts and set the interrupt_install flag to true.
 */
int kbase_arbiter_pm_install_interrupts(struct kbase_device *kbdev);

/**
 * kbase_arbiter_pm_vm_event() - Dispatch VM event to the state machine
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 *
 * The state machine function. Receives events and transitions states
 * according the event received and the current state
 */
void kbase_arbiter_pm_vm_event(struct kbase_device *kbdev,
	enum kbase_arbif_evt event);

/**
 * kbase_arbiter_pm_ctx_active_handle_suspend() - Handle suspend operation for
 *                                                arbitration mode
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 * @suspend_handler: The handler code for how to handle a suspend
 *                   that might occur
 *
 * This function handles a suspend event from the driver,
 * communicating with the arbiter and waiting synchronously for the GPU
 * to be granted again depending on the VM state.
 *
 * Return: 0 if success, 1 if failure due to system suspending/suspended
 */
int kbase_arbiter_pm_ctx_active_handle_suspend(struct kbase_device *kbdev,
	enum kbase_pm_suspend_handler suspend_handler);


/**
 * kbase_arbiter_pm_vm_stopped() - Handle stop event for the VM
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 *
 * This function handles a stop event for the VM.
 * It will update the VM state and forward the stop event to the driver.
 */
void kbase_arbiter_pm_vm_stopped(struct kbase_device *kbdev);

/**
 * kbase_arbiter_set_max_config() - Set the max config data in kbase device.
 * @kbdev: The kbase device structure for the device (must be a valid pointer).
 * @max_l2_slices: The maximum number of L2 slices.
 * @max_core_mask: The largest core mask.
 *
 * This function handles a stop event for the VM.
 * It will update the VM state and forward the stop event to the driver.
 */
void kbase_arbiter_set_max_config(struct kbase_device *kbdev,
				  uint32_t max_l2_slices,
				  uint32_t max_core_mask);

/**
 * kbase_arbiter_pm_gpu_assigned() - Determine if this VM has access to the GPU
 * @kbdev: The kbase device structure for the device (must be a valid pointer)
 *
 * Return: 0 if the VM does not have access, 1 if it does, and a negative number
 * if an error occurred
 */
int kbase_arbiter_pm_gpu_assigned(struct kbase_device *kbdev);

extern struct kbase_clk_rate_trace_op_conf arb_clk_rate_trace_ops;

/**
 * struct kbase_arbiter_freq - Holding the GPU clock frequency data retrieved
 * from arbiter
 * @arb_freq:      GPU clock frequency value
 * @arb_freq_lock: Mutex protecting access to arbfreq value
 * @nb:            Notifier block to receive rate change callbacks
 * @freq_updated:  Flag to indicate whether a frequency changed has just been
 *                 communicated to avoid "GPU_GRANTED when not expected" warning
 */
struct kbase_arbiter_freq {
	uint32_t arb_freq;
	struct mutex arb_freq_lock;
	struct notifier_block *nb;
	bool freq_updated;
};

/**
 * kbase_arbiter_pm_update_gpu_freq() - Update GPU frequency
 * @arb_freq: Pointer to GPU clock frequency data
 * @freq:     The new frequency
 *
 * Updates the GPU frequency and triggers any notifications
 */
void kbase_arbiter_pm_update_gpu_freq(struct kbase_arbiter_freq *arb_freq,
	uint32_t freq);

#endif /*_MALI_KBASE_ARBITER_PM_H_ */
