/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
 *
 * (C) COPYRIGHT 2018-2024 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.
 *
 */

#ifndef _KBASE_CSF_FIRMWARE_H_
#define _KBASE_CSF_FIRMWARE_H_

#include "device/mali_kbase_device.h"
#include <csf/mali_kbase_csf_registers.h>
#include <hw_access/mali_kbase_hw_access_regmap.h>
#include <uapi/gpu/arm/midgard/gpu/mali_kbase_gpu_regmap.h>

/*
 * PAGE_KERNEL_RO was only defined on 32bit ARM in 4.19 in:
 * Commit a3266bd49c721e2e0a71f352d83713fbd60caadb
 * Author: Luis R. Rodriguez <mcgrof@kernel.org>
 * Date:   Fri Aug 17 15:46:29 2018 -0700
 *
 * mm: provide a fallback for PAGE_KERNEL_RO for architectures
 *
 * Some architectures do not define certain PAGE_KERNEL_* flags, this is
 * either because:
 *
 * a) The way to implement some of these flags is *not yet ported*, or
 * b) The architecture *has no way* to describe them
 *
 * [snip]
 *
 * This can be removed once support of 32bit ARM kernels predating 4.19 is no
 * longer required.
 */
#ifndef PAGE_KERNEL_RO
#define PAGE_KERNEL_RO PAGE_KERNEL
#endif

/* Address space number to claim for the firmware. */
#define MCU_AS_NR 0
#define MCU_AS_BITMASK (1 << MCU_AS_NR)

/* Number of available Doorbells */
#define CSF_NUM_DOORBELL_MAX ((u8)64)

/* Offset to the first HW doorbell page */
#define CSF_HW_DOORBELL_PAGE_OFFSET ((u32)DOORBELLS_BASE)

/* Size of HW Doorbell page, used to calculate the offset to subsequent pages */
#define CSF_HW_DOORBELL_PAGE_SIZE ((u32)0x10000)

/* Doorbell 0 is used by the driver. */
#define CSF_KERNEL_DOORBELL_NR ((u32)0)

/* Offset of name inside a trace buffer entry in the firmware image */
#define TRACE_BUFFER_ENTRY_NAME_OFFSET (0x1C)

/* All implementations of the host interface with major version 0 must comply
 * with these restrictions:
 */
/* GLB_GROUP_NUM: At least 3 CSGs, but no more than 31 */
#define MIN_SUPPORTED_CSGS 3
#define MAX_SUPPORTED_CSGS 31
/* GROUP_STREAM_NUM: At least 8 CSs per CSG, but no more than 32 */
#define MIN_SUPPORTED_STREAMS_PER_GROUP 8
/* MAX_SUPPORTED_STREAMS_PER_GROUP: Maximum CSs per csg. */
#define MAX_SUPPORTED_STREAMS_PER_GROUP 32

struct kbase_device;

/**
 * struct kbase_csf_mapping - Memory mapping for CSF memory.
 * @phys:      Physical memory allocation used by the mapping.
 * @cpu_addr:  Starting CPU address for the mapping.
 * @va_reg:    GPU virtual address region for the mapping.
 * @num_pages: Size of the mapping, in memory pages.
 */
struct kbase_csf_mapping {
	struct tagged_addr *phys;
	void *cpu_addr;
	struct kbase_va_region *va_reg;
	unsigned int num_pages;
};

/**
 * struct kbase_csf_trace_buffers - List and state of firmware trace buffers.
 * @list:       List of trace buffers descriptors.
 * @mcu_rw:     Metadata for the MCU shared memory mapping used for
 *              GPU-readable,writable/CPU-writable variables.
 * @mcu_write:  Metadata for the MCU shared memory mapping used for
 *              GPU-writable/CPU-readable variables.
 */
struct kbase_csf_trace_buffers {
	struct list_head list;
	struct kbase_csf_mapping mcu_rw;
	struct kbase_csf_mapping mcu_write;
};

/**
 * struct kbase_csf_cmd_stream_info - CSI provided by the firmware.
 *
 * @kbdev: Address of the instance of a GPU platform device that implements
 *         this interface.
 * @features: Bit field of CS features (e.g. which types of jobs
 *            are supported). Bits 7:0 specify the number of work registers(-1).
 *            Bits 11:8 specify the number of scoreboard entries(-1).
 * @gid: CSG index to which the CSI is assigned.
 * @sid: CSI index.
 */
struct kbase_csf_cmd_stream_info {
	struct kbase_device *kbdev;
	u32 features;
	u32 gid;
	u32 sid;
};

/**
 * struct kbase_csf_cmd_stream_group_info - CSG interface provided by the
 *                                          firmware.
 *
 * @kbdev: Address of the instance of a GPU platform device that implements
 *         this interface.
 * @features: Bit mask of features. Reserved bits should be 0, and should
 *            be ignored.
 * @gid: CSG index.
 * @suspend_size: Size in bytes for normal suspend buffer for the CSG
 * @protm_suspend_size: Size in bytes for protected mode suspend buffer
 *                      for the CSG.
 * @stream_num: Number of CSs in the CSG.
 * @stream_stride: Stride in bytes in JASID0 virtual address between
 *                 CS capability structures.
 * @streams: Address of an array of CS capability structures.
 */
struct kbase_csf_cmd_stream_group_info {
	struct kbase_device *kbdev;
	u32 features;
	u32 gid;
	u32 suspend_size;
	u32 protm_suspend_size;
	u32 stream_num;
	u32 stream_stride;
	struct kbase_csf_cmd_stream_info *streams;
};

/**
 * struct kbase_csf_global_iface - Global CSF interface
 *                                 provided by the firmware.
 *
 * @kbdev: Address of the instance of a GPU platform device that implements
 *         this interface.
 * @version: Bits 31:16 hold the major version number and 15:0 hold the minor
 *           version number. A higher minor version is backwards-compatible
 *           with a lower minor version for the same major version.
 * @features: Bit mask of features (e.g. whether certain types of job can
 *            be suspended). Reserved bits should be 0, and should be ignored.
 * @group_num: Number of CSGs supported.
 * @group_stride: Stride in bytes in JASID0 virtual address between
 *                CSG capability structures.
 * @prfcnt_size: Performance counters size.
 * @instr_features: Instrumentation features. (csf >= 1.1.0)
 * @groups: Address of an array of CSG capability structures.
 */
struct kbase_csf_global_iface {
	struct kbase_device *kbdev;
	u32 version;
	u32 features;
	u32 group_num;
	u32 group_stride;
	u32 prfcnt_size;
	u32 instr_features;
	struct kbase_csf_cmd_stream_group_info *groups;
};

/**
 * kbase_csf_ring_doorbell() - Ring the doorbell
 *
 * @kbdev:       An instance of the GPU platform device
 * @doorbell_nr: Index of the HW doorbell page
 */
void kbase_csf_ring_doorbell(struct kbase_device *kbdev, int doorbell_nr);

/**
 * kbase_csf_read_firmware_memory - Read a value in a GPU address
 *
 * @kbdev:     Device pointer
 * @gpu_addr:  GPU address to read
 * @value:     output pointer to which the read value will be written.
 *
 * This function read a value in a GPU address that belongs to
 * a private firmware memory region. The function assumes that the location
 * is not permanently mapped on the CPU address space, therefore it maps it
 * and then unmaps it to access it independently.
 */
void kbase_csf_read_firmware_memory(struct kbase_device *kbdev, u32 gpu_addr, u32 *value);

/**
 * kbase_csf_update_firmware_memory - Write a value in a GPU address
 *
 * @kbdev:     Device pointer
 * @gpu_addr:  GPU address to write
 * @value:     Value to write
 *
 * This function writes a given value in a GPU address that belongs to
 * a private firmware memory region. The function assumes that the destination
 * is not permanently mapped on the CPU address space, therefore it maps it
 * and then unmaps it to access it independently.
 */
void kbase_csf_update_firmware_memory(struct kbase_device *kbdev, u32 gpu_addr, u32 value);

/**
 * kbase_csf_read_firmware_memory_exe - Read a value in a GPU address in the
 *                                      region of its final execution location.
 *
 * @kbdev:     Device pointer
 * @gpu_addr:  GPU address to read
 * @value:     Output pointer to which the read value will be written
 *
 * This function read a value in a GPU address that belongs to a private loaded
 * firmware memory region based on its final execution location. The function
 * assumes that the location is not permanently mapped on the CPU address space,
 * therefore it maps it and then unmaps it to access it independently. This function
 * needs to be used when accessing firmware memory regions which will be moved to
 * their final execution location during firmware boot using an address based on the
 * final execution location.
 */
void kbase_csf_read_firmware_memory_exe(struct kbase_device *kbdev, u32 gpu_addr, u32 *value);

/**
 * kbase_csf_update_firmware_memory_exe - Write a value in a GPU address in the
 *                                        region of its final execution location.
 *
 * @kbdev:     Device pointer
 * @gpu_addr:  GPU address to write
 * @value:     Value to write
 *
 * This function writes a value in a GPU address that belongs to a private loaded
 * firmware memory region based on its final execution location. The function
 * assumes that the location is not permanently mapped on the CPU address space,
 * therefore it maps it and then unmaps it to access it independently. This function
 * needs to be used when accessing firmware memory regions which will be moved to
 * their final execution location during firmware boot using an address based on the
 * final execution location.
 */
void kbase_csf_update_firmware_memory_exe(struct kbase_device *kbdev, u32 gpu_addr, u32 value);

/**
 * kbase_csf_firmware_early_init() - Early initialization for the firmware.
 * @kbdev: Kbase device
 *
 * Initialize resources related to the firmware. Must be called at kbase probe.
 *
 * Return: 0 if successful, negative error code on failure
 */
int kbase_csf_firmware_early_init(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_early_term() - Terminate resources related to the firmware
 *                                   after the firmware unload has been done.
 *
 * @kbdev: Device pointer
 *
 * This should be called only when kbase probe fails or gets rmmoded.
 */
void kbase_csf_firmware_early_term(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_late_init() - Late initialization for the firmware.
 * @kbdev: Kbase device
 *
 * Initialize resources related to the firmware. But must be called after
 * backend late init is done. Must be used at probe time only.
 *
 * Return: 0 if successful, negative error code on failure
 */
int kbase_csf_firmware_late_init(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_load_init() - Load the firmware for the CSF MCU
 * @kbdev: Kbase device
 *
 * Request the firmware from user space and load it into memory.
 *
 * Return: 0 if successful, negative error code on failure
 */
int kbase_csf_firmware_load_init(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_unload_term() - Unload the firmware
 * @kbdev: Kbase device
 *
 * Frees the memory allocated by kbase_csf_firmware_load_init()
 */
void kbase_csf_firmware_unload_term(struct kbase_device *kbdev);

#if IS_ENABLED(CONFIG_MALI_CORESIGHT)
/**
 * kbase_csf_firmware_mcu_register_write - Write to MCU register
 *
 * @kbdev:    Instance of a gpu platform device that implements a csf interface.
 * @reg_addr: Register address to write into
 * @reg_val:  Value to be written
 *
 * Write a desired value to a register in MCU address space.
 *
 * return: 0 on success, or negative on failure.
 */
int kbase_csf_firmware_mcu_register_write(struct kbase_device *const kbdev, u32 const reg_addr,
					  u32 const reg_val);
/**
 * kbase_csf_firmware_mcu_register_read - Read from MCU register
 *
 * @kbdev:    Instance of a gpu platform device that implements a csf interface.
 * @reg_addr: Register address to read from
 * @reg_val:  Value as present in reg_addr register
 *
 * Read a value from MCU address space.
 *
 * return: 0 on success, or negative on failure.
 */
int kbase_csf_firmware_mcu_register_read(struct kbase_device *const kbdev, u32 const reg_addr,
					 u32 *reg_val);

/**
 * kbase_csf_firmware_mcu_register_poll - Poll MCU register
 *
 * @kbdev:    Instance of a gpu platform device that implements a csf interface.
 * @reg_addr: Register address to read from
 * @val_mask: Value to mask the read value for comparison
 * @reg_val:  Value to be compared against
 *
 * Continue to read a value from MCU address space until it matches given mask and value.
 *
 * return: 0 on success, or negative on failure.
 */
int kbase_csf_firmware_mcu_register_poll(struct kbase_device *const kbdev, u32 const reg_addr,
					 u32 const val_mask, u32 const reg_val);
#endif /* IS_ENABLED(CONFIG_MALI_CORESIGHT) */

/**
 * kbase_csf_firmware_ping - Send the ping request to firmware.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * The function sends the ping request to firmware.
 */
void kbase_csf_firmware_ping(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_ping_wait - Send the ping request to firmware and waits.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 * @wait_timeout_ms: Timeout to get the acknowledgment for PING request from FW.
 *
 * The function sends the ping request to firmware and waits to confirm it is
 * alive.
 *
 * Return: 0 on success, or negative on failure.
 */
int kbase_csf_firmware_ping_wait(struct kbase_device *kbdev, unsigned int wait_timeout_ms);

/**
 * kbase_csf_firmware_set_timeout - Set a hardware endpoint progress timeout.
 *
 * @kbdev:   Instance of a GPU platform device that implements a CSF interface.
 * @timeout: The maximum number of GPU cycles that is allowed to elapse
 *           without forward progress before the driver terminates a GPU
 *           command queue group.
 *
 * Configures the progress timeout value used by the firmware to decide
 * when to report that a task is not making progress on an endpoint.
 *
 * Return: 0 on success,
 *         -ENODEV on unresponsive MCU,
 *         or negative error code on other failure.
 */
int kbase_csf_firmware_set_timeout(struct kbase_device *kbdev, u64 timeout);

/**
 * kbase_csf_enter_protected_mode - Send the Global request to firmware to
 *                                  enter protected mode.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * The function must be called with kbdev->csf.scheduler.interrupt_lock held
 * and it does not wait for the protected mode entry to complete.
 *
 * Return: 0 on success, -ENODEV if MCU is unresponsive.
 */
int kbase_csf_enter_protected_mode(struct kbase_device *kbdev);

/**
 * kbase_csf_wait_protected_mode_enter - Wait for the completion of PROTM_ENTER
 *                                       Global request sent to firmware.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * This function needs to be called after kbase_csf_enter_protected_mode() to
 * wait for the GPU to actually enter protected mode. GPU reset is triggered if
 * the wait is unsuccessful.
 *
 * Return: 0 on success, or negative on failure.
 */
int kbase_csf_wait_protected_mode_enter(struct kbase_device *kbdev);

static inline bool kbase_csf_firmware_mcu_halted(struct kbase_device *kbdev)
{
#if IS_ENABLED(CONFIG_MALI_NO_MALI)
	return true;
#else
	return (kbase_reg_read32(kbdev, GPU_CONTROL_ENUM(MCU_STATUS)) == MCU_STATUS_VALUE_HALT);
#endif /* CONFIG_MALI_NO_MALI */
}

/**
 * kbase_csf_firmware_mcu_halt_req_complete - Check if the MCU Halt request is complete
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * This function needs to be called after Halt request has been sent to the FW.
 *
 * Return: true if the Halt request is complete, otherwise false.
 */
bool kbase_csf_firmware_mcu_halt_req_complete(struct kbase_device *kbdev);


/**
 * kbase_csf_firmware_trigger_mcu_halt - Send the Global request to firmware to
 *                                       halt its operation and bring itself
 *                                       into a known internal state for warm
 *                                       boot later.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_firmware_trigger_mcu_halt(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_enable_mcu - Send the command to enable MCU
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_firmware_enable_mcu(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_disable_mcu - Send the command to disable MCU
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_firmware_disable_mcu(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_disable_mcu_wait - Wait for the MCU to reach disabled status.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_firmware_disable_mcu_wait(struct kbase_device *kbdev);

/**
 * kbase_csf_stop_firmware_and_wait - Disable firmware and wait for the MCU to reach
 *                                    disabled status.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_stop_firmware_and_wait(struct kbase_device *kbdev);

#ifdef KBASE_PM_RUNTIME
/**
 * kbase_csf_firmware_trigger_mcu_sleep - Send the command to put MCU in sleep
 *                                        state.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_firmware_trigger_mcu_sleep(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_is_mcu_in_sleep - Check if sleep request has completed
 *                                      and MCU has halted.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * Return: true if sleep request has completed, otherwise false.
 */
bool kbase_csf_firmware_is_mcu_in_sleep(struct kbase_device *kbdev);

#endif


/**
 * kbase_csf_firmware_trigger_reload() - Trigger the reboot of MCU firmware, for
 *                                       the cold boot case firmware image would
 *                                       be reloaded from filesystem into memory.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_firmware_trigger_reload(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_reload_completed - The reboot of MCU firmware has
 *                                       completed.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 */
void kbase_csf_firmware_reload_completed(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_global_reinit - Send the Global configuration requests
 *                                    after the reboot of MCU firmware.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 * @core_mask: Mask of the enabled shader cores.
 */
void kbase_csf_firmware_global_reinit(struct kbase_device *kbdev, u64 core_mask);

/**
 * kbase_csf_firmware_global_reinit_complete - Check the Global configuration
 *                      requests, sent after the reboot of MCU firmware, have
 *                      completed or not.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * Return: true if the Global configuration requests completed otherwise false.
 */
bool kbase_csf_firmware_global_reinit_complete(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_update_core_attr - Send the Global configuration request
 *                                       to update the requested core attribute
 *                                       changes.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 * @update_core_pwroff_timer: If true, signal the firmware needs to update
 *                            the MCU power-off timer value.
 * @update_core_mask:         If true, need to do the core_mask update with
 *                            the supplied core_mask value.
 * @core_mask:                New core mask value if update_core_mask is true,
 *                            otherwise unused.
 */
void kbase_csf_firmware_update_core_attr(struct kbase_device *kbdev, bool update_core_pwroff_timer,
					 bool update_core_mask, u64 core_mask);

/**
 * kbase_csf_firmware_core_attr_updated - Check the Global configuration
 *                  request has completed or not, that was sent to update
 *                  the core attributes.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * Return: true if the Global configuration request to update the core
 *         attributes has completed, otherwise false.
 */
bool kbase_csf_firmware_core_attr_updated(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_get_glb_iface - Request the global control block of CSF
 *                                      interface capabilities
 *
 * @kbdev:                 Kbase device.
 * @group_data:            Pointer where to store all the group data
 *                         (sequentially).
 * @max_group_num:         The maximum number of groups to be read.
 *                         Can be 0, in which case group_data is unused.
 * @stream_data:           Pointer where to store all the CS data
 *                         (sequentially).
 * @max_total_stream_num:  The maximum number of CSs to be read.
 *                         Can be 0, in which case stream_data is unused.
 * @glb_version:           Where to store the global interface version.
 * @features:              Where to store a bit mask of features (e.g.
 *                         whether certain types of job can be suspended).
 * @group_num:             Where to store the number of CSGs
 *                         supported.
 * @prfcnt_size:           Where to store the size of CSF performance counters,
 *                         in bytes. Bits 31:16 hold the size of firmware
 *                         performance counter data and 15:0 hold the size of
 *                         hardware performance counter data.
 * @instr_features:        Instrumentation features. Bits 7:4 hold the max size
 *                         of events. Bits 3:0 hold the offset update rate.
 *                         (csf >= 1,1,0)
 *
 * Return: Total number of CSs, summed across all groups.
 */
u32 kbase_csf_firmware_get_glb_iface(struct kbase_device *kbdev,
				     struct basep_cs_group_control *group_data, u32 max_group_num,
				     struct basep_cs_stream_control *stream_data,
				     u32 max_total_stream_num, u32 *glb_version, u32 *features,
				     u32 *group_num, u32 *prfcnt_size, u32 *instr_features);

/**
 * kbase_csf_firmware_get_timeline_metadata - Get CSF firmware header timeline
 *                                            metadata content
 *
 * @kbdev:        Kbase device.
 * @name:         Name of the metadata which metadata content to be returned.
 * @size:         Metadata size if specified metadata found.
 *
 * Return: The firmware timeline metadata content which match @p name.
 */
const char *kbase_csf_firmware_get_timeline_metadata(struct kbase_device *kbdev, const char *name,
						     size_t *size);

/**
 * kbase_csf_firmware_mcu_shared_mapping_init - Allocate and map MCU shared memory.
 *
 * @kbdev:              Kbase device the memory mapping shall belong to.
 * @num_pages:          Number of memory pages to map.
 * @cpu_map_properties: Either PROT_READ or PROT_WRITE.
 * @gpu_map_properties: Either KBASE_REG_GPU_RD or KBASE_REG_GPU_WR.
 * @csf_mapping:        Object where to write metadata for the memory mapping.
 *
 * This helper function allocates memory and maps it on both the CPU
 * and the GPU address spaces. Most of the properties of the mapping
 * are implicit and will be automatically determined by the function,
 * e.g. whether memory is cacheable.
 *
 * The client is only expected to specify whether the mapping is readable
 * or writable in the CPU and the GPU address spaces; any other flag
 * will be ignored by the function.
 *
 * Return: 0 if success, or an error code on failure.
 */
int kbase_csf_firmware_mcu_shared_mapping_init(struct kbase_device *kbdev, unsigned int num_pages,
					       unsigned long cpu_map_properties,
					       unsigned long gpu_map_properties,
					       struct kbase_csf_mapping *csf_mapping);

/**
 * kbase_csf_firmware_mcu_shared_mapping_term - Unmap and free MCU shared memory.
 *
 * @kbdev:       Device pointer.
 * @csf_mapping: Metadata of the memory mapping to terminate.
 */
void kbase_csf_firmware_mcu_shared_mapping_term(struct kbase_device *kbdev,
						struct kbase_csf_mapping *csf_mapping);

#ifdef CONFIG_MALI_DEBUG
extern bool fw_debug;
#endif

static inline long kbase_csf_timeout_in_jiffies(const unsigned int msecs)
{
#ifdef CONFIG_MALI_DEBUG
	return (fw_debug ? MAX_SCHEDULE_TIMEOUT : (long)msecs_to_jiffies(msecs));
#else
	return (long)msecs_to_jiffies(msecs);
#endif
}

/**
 * kbase_csf_firmware_enable_gpu_idle_timer() - Activate the idle hysteresis
 *                                              monitoring operation
 *
 * @kbdev: Kbase device structure
 *
 * Program the firmware interface with its configured hysteresis count value
 * and enable the firmware to act on it. The Caller is
 * assumed to hold the kbdev->csf.scheduler.interrupt_lock.
 *
 * Return: -ENODEV on unresponsive MCU, 0 otherwise.
 */
int kbase_csf_firmware_enable_gpu_idle_timer(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_disable_gpu_idle_timer() - Disable the idle time
 *                                             hysteresis monitoring operation
 *
 * @kbdev: Kbase device structure
 *
 * Program the firmware interface to disable the idle hysteresis timer. The
 * Caller is assumed to hold the kbdev->csf.scheduler.interrupt_lock.
 *
 * Return: -ENODEV on unresponsive MCU, 0 otherwise.
 */
int kbase_csf_firmware_disable_gpu_idle_timer(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_get_gpu_idle_hysteresis_time - Get the firmware GPU idle
 *                                               detection hysteresis duration
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * Return: the internally recorded hysteresis (nominal) value.
 */
u64 kbase_csf_firmware_get_gpu_idle_hysteresis_time(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_set_gpu_idle_hysteresis_time - Set the firmware GPU idle
 *                                               detection hysteresis duration
 *
 * @kbdev:  Instance of a GPU platform device that implements a CSF interface.
 * @dur_ns: The duration value (unit: nanoseconds) for the configuring
 *          hysteresis field for GPU idle detection
 *
 * The supplied value will be recorded internally without any change. But the
 * actual field value will be subject to hysteresis source frequency scaling
 * and maximum value limiting. The default source will be SYSTEM_TIMESTAMP
 * counter. But in case the platform is not able to supply it, the GPU
 * CYCLE_COUNTER source will be used as an alternative. Bit-31 on the
 * returned value is the source configuration flag, and it is set to '1'
 * when CYCLE_COUNTER alternative source is used.
 *
 * Return: the actual internally configured hysteresis field value.
 */
u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev, u64 dur_ns);

/**
 * kbase_csf_firmware_get_mcu_core_pwroff_time - Get the MCU shader Core power-off
 *                                               time value
 *
 * @kbdev:   Instance of a GPU platform device that implements a CSF interface.
 *
 * Return: the internally recorded MCU shader Core power-off (nominal) timeout value. The unit
 *         of the value is in micro-seconds.
 */
u64 kbase_csf_firmware_get_mcu_core_pwroff_time(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_set_mcu_core_pwroff_time - Set the MCU shader Core power-off
 *                                               time value
 *
 * @kbdev:   Instance of a GPU platform device that implements a CSF interface.
 * @dur_ns:  The duration value (unit: nanoseconds) for configuring MCU
 *           core power-off timer, when the shader cores' power
 *           transitions are delegated to the MCU (normal operational
 *           mode)
 *
 * The supplied value will be recorded internally without any change. But the
 * actual field value will be subject to core power-off timer source frequency
 * scaling and maximum value limiting. The default source will be
 * SYSTEM_TIMESTAMP counter. But in case the platform is not able to supply it,
 * the GPU CYCLE_COUNTER source will be used as an alternative. Bit-31 on the
 * returned value is the source configuration flag, and it is set to '1'
 * when CYCLE_COUNTER alternative source is used.
 *
 * The configured MCU shader Core power-off timer will only have effect when the host
 * driver has delegated the shader cores' power management to MCU.
 *
 * Return: the actual internal core power-off timer value in register defined
 *         format.
 */
u32 kbase_csf_firmware_set_mcu_core_pwroff_time(struct kbase_device *kbdev, u64 dur_ns);

/**
 * kbase_csf_firmware_reset_mcu_core_pwroff_time - Reset the MCU shader Core power-off
 *                                               time value
 *
 * @kbdev:   Instance of a GPU platform device that implements a CSF interface.
 *
 * Sets the MCU Shader Core power-off time value to the default.
 *
 * The configured MCU shader Core power-off timer will only have effect when the host
 * driver has delegated the shader cores' power management to MCU.
 *
 * Return: the actual internal core power-off timer value in register defined
 *         format.
 */
u32 kbase_csf_firmware_reset_mcu_core_pwroff_time(struct kbase_device *kbdev);

/**
 * kbase_csf_interface_version - Helper function to build the full firmware
 *                               interface version in a format compatible with
 *                               GLB_VERSION register
 *
 * @major:     major version of csf interface
 * @minor:     minor version of csf interface
 * @patch:     patch version of csf interface
 *
 * Return: firmware interface version
 */
static inline u32 kbase_csf_interface_version(u32 major, u32 minor, u32 patch)
{
	return ((major << GLB_VERSION_MAJOR_SHIFT) | (minor << GLB_VERSION_MINOR_SHIFT) |
		(patch << GLB_VERSION_PATCH_SHIFT));
}

/**
 * kbase_csf_trigger_firmware_config_update - Send a firmware config update.
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * Any changes done to firmware configuration entry or tracebuffer entry
 * requires a GPU silent reset to reflect the configuration changes
 * requested, but if Firmware.header.entry.bit(30) is set then we can request a
 * FIRMWARE_CONFIG_UPDATE rather than doing a silent reset.
 *
 * Return: 0 if success, or negative error code on failure.
 */
int kbase_csf_trigger_firmware_config_update(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_req_core_dump - Request a firmware core dump
 *
 * @kbdev: Instance of a GPU platform device that implements a CSF interface.
 *
 * Request a firmware core dump and wait for for firmware to acknowledge.
 * Firmware will enter infinite loop after the firmware core dump is created.
 *
 * Return: 0 if success,
 *         -ENODEV on unresponsive MCU,
 *         or negative error code on other failure.
 */
int kbase_csf_firmware_req_core_dump(struct kbase_device *const kbdev);

#ifdef KBASE_PM_RUNTIME

/**
 * kbase_csf_firmware_soi_update - Update FW Sleep-on-Idle config
 *
 * @kbdev: Device pointer
 *
 * This function reconfigures the FW Sleep-on-Idle configuration if necessary.
 */
void kbase_csf_firmware_soi_update(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_glb_idle_timer_update - Update GLB_IDLE timer config
 *
 * @kbdev: Device pointer
 *
 * This function reconfigures the GLB_IDLE timer configuration if necessary.
 */
void kbase_csf_firmware_glb_idle_timer_update(struct kbase_device *kbdev);

/**
 * kbase_csf_firmware_soi_disable_on_scheduler_suspend - Disable FW Sleep-on-Idle config
 *                                                       on scheduler suspension
 *
 * @kbdev: Device pointer
 *
 * Return: 0 on success, otherwise failure
 */
int kbase_csf_firmware_soi_disable_on_scheduler_suspend(struct kbase_device *kbdev);

#endif /* KBASE_PM_RUNTIME */


#endif
