blob: c214a8b60409d9639ba3a238645b286a763fdab6 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0 */
/*
* GXP power management.
*
* Copyright (C) 2021 Google LLC
*/
#ifndef __GXP_PM_H__
#define __GXP_PM_H__
#include <soc/google/exynos_pm_qos.h>
#include "gxp-internal.h"
#define AUR_DVFS_MIN_RATE 178000
static const uint aur_power_state2rate[] = {
0, /* AUR_OFF */
178000, /* AUR_UUD */
373000, /* AUR_SUD */
750000, /* AUR_UD */
1160000, /* AUR_NOM */
178000, /* AUR_READY */
268000, /* AUR_UUD_PLUS */
560000, /* AUR_SUD_PLUS */
975000, /* AUR_UD_PLUS */
};
enum aur_power_state {
AUR_OFF = 0,
AUR_UUD = 1,
AUR_SUD = 2,
AUR_UD = 3,
AUR_NOM = 4,
AUR_READY = 5,
AUR_UUD_PLUS = 6,
AUR_SUD_PLUS = 7,
AUR_UD_PLUS = 8,
};
enum aur_memory_power_state {
AUR_MEM_UNDEFINED = 0,
AUR_MEM_MIN = 1,
AUR_MEM_VERY_LOW = 2,
AUR_MEM_LOW = 3,
AUR_MEM_HIGH = 4,
AUR_MEM_VERY_HIGH = 5,
AUR_MEM_MAX = 6,
};
enum aur_power_cmu_mux_state {
AUR_CMU_MUX_LOW = 0,
AUR_CMU_MUX_NORMAL = 1,
};
#define AUR_NUM_POWER_STATE (AUR_MAX_ALLOW_STATE + 1)
#define AUR_NUM_MEMORY_POWER_STATE (AUR_MAX_ALLOW_MEMORY_STATE + 1)
#define AUR_INIT_DVFS_STATE AUR_UUD
/*
* These macros mean the maximum valid enum value of aur_power_state and
* aur_memory_power_state, not necessarily the state with the maximum power
* level.
*/
#define AUR_MAX_ALLOW_STATE AUR_UD_PLUS
#define AUR_MAX_ALLOW_MEMORY_STATE AUR_MEM_MAX
#define AUR_NUM_POWER_STATE_WORKER 4
struct gxp_pm_device_ops {
int (*pre_blk_powerup)(struct gxp_dev *gxp);
int (*post_blk_powerup)(struct gxp_dev *gxp);
int (*pre_blk_poweroff)(struct gxp_dev *gxp);
int (*post_blk_poweroff)(struct gxp_dev *gxp);
};
struct gxp_set_acpm_state_work {
struct work_struct work;
struct gxp_dev *gxp;
unsigned long state;
unsigned long prev_state;
bool low_clkmux;
bool prev_low_clkmux;
bool using;
};
struct gxp_req_pm_qos_work {
struct work_struct work;
struct gxp_dev *gxp;
s32 int_val;
s32 mif_val;
bool using;
};
struct gxp_power_manager {
struct gxp_dev *gxp;
struct mutex pm_lock;
uint pwr_state_req_count[AUR_NUM_POWER_STATE];
uint low_clkmux_pwr_state_req_count[AUR_NUM_POWER_STATE];
uint mem_pwr_state_req_count[AUR_NUM_MEMORY_POWER_STATE];
/*
* Last set CLKMUX state by asynchronous request handler.
* If a core is booting, we shouldn't change clock mux state. This is
* the expected state to set after all cores booting are finished.
* Otherwise, it's the real state of CLKMUX.
*/
bool curr_low_clkmux;
/* Last requested clock mux state */
bool last_scheduled_low_clkmux;
int curr_state;
int curr_memory_state;
struct gxp_pm_device_ops *ops;
struct gxp_set_acpm_state_work
set_acpm_state_work[AUR_NUM_POWER_STATE_WORKER];
/* Serializes searching for an open worker in set_acpm_state_work[] */
struct mutex set_acpm_state_work_lock;
uint last_set_acpm_state_worker;
struct gxp_req_pm_qos_work req_pm_qos_work[AUR_NUM_POWER_STATE_WORKER];
uint last_req_pm_qos_worker;
/* Serializes searching for an open worker in req_pm_qos_work[] */
struct mutex req_pm_qos_work_lock;
struct workqueue_struct *wq;
/* INT/MIF requests for memory bandwidth */
struct exynos_pm_qos_request int_min;
struct exynos_pm_qos_request mif_min;
int force_mux_normal_count;
/* Max frequency that the thermal driver/ACPM will allow in Hz */
unsigned long thermal_limit;
u64 blk_switch_count;
};
/**
* gxp_pm_blk_on() - Turn on the power for BLK_AUR
* @gxp: The GXP device to turn on
*
* Return:
* * 0 - BLK ON successfully
* * -ENODEV - Cannot find PM interface
*/
int gxp_pm_blk_on(struct gxp_dev *gxp);
/**
* gxp_pm_blk_off() - Turn off the power for BLK_AUR
* @gxp: The GXP device to turn off
*
* Return:
* * 0 - BLK OFF successfully
* * -ENODEV - Cannot find PM interface
* * -EBUSY - Wakelock is held, blk is still busy
*/
int gxp_pm_blk_off(struct gxp_dev *gxp);
/**
* gxp_pm_get_blk_state() - Get the blk power state
* @gxp: The GXP device to sample state
*
* Return:
* * state - State number represented in kHZ, or 0 if OFF
*/
int gxp_pm_get_blk_state(struct gxp_dev *gxp);
/**
* gxp_pm_get_blk_switch_count() - Get the blk switch count number
* @gxp: The GXP device to switch the blk
*
* Return:
* * count - Switch count number after the module initialization.
*/
int gxp_pm_get_blk_switch_count(struct gxp_dev *gxp);
/**
* gxp_pm_core_on() - Turn on a core on GXP device
* @gxp: The GXP device to operate
* @core: The core ID to turn on
* @verbose: A boolean flag to indicate whether to print the log
*
* Return:
* * 0 - Core on process finished successfully
* * -ETIMEDOUT - Core on process timed-out.
*/
int gxp_pm_core_on(struct gxp_dev *gxp, uint core, bool verbose);
/**
* gxp_pm_core_off() - Turn off a core on GXP device
* @gxp: The GXP device to operate
* @core: The core ID to turn off
*
* Return:
* * 0 - Core off process finished successfully
*/
int gxp_pm_core_off(struct gxp_dev *gxp, uint core);
/**
* gxp_pm_init() - API for initialize PM interface for GXP, should only be
* called once per probe
* @gxp: The GXP device to operate
*
* Return:
* * 0 - Initialization finished successfully
* * -ENOMEM - Cannot get memory to finish init.
*/
int gxp_pm_init(struct gxp_dev *gxp);
/**
* gxp_pm_destroy() - API for removing
* the power management interface
* @gxp: The GXP device to operate
*
* Return:
* * 0 - Remove finished successfully
*/
int gxp_pm_destroy(struct gxp_dev *gxp);
/**
* gxp_pm_blk_set_rate_acpm() - API for setting the block-level DVFS rate.
* This function can be called at any point after block power on.
* @gxp: The GXP device to operate
* @rate: Rate number in khz that need to be set.
* Supported rate is in aur_power_state2rate,
* if experiment is needed for unsupported rate
* please refer to Lassen's ECT table.
*
* Return:
* * 0 - Set finished successfully
* * Other - Set rate encounter issue in exynos_acpm_set_rate
*/
int gxp_pm_blk_set_rate_acpm(struct gxp_dev *gxp, unsigned long rate);
/**
* gxp_pm_blk_get_state_acpm() - API for getting
* the current DVFS state of the Aurora block.
* @gxp: The GXP device to operate
*
* Return:
* * State - State number in Khz from ACPM
*/
int gxp_pm_blk_get_state_acpm(struct gxp_dev *gxp);
/**
* gxp_pm_update_requested_power_states() - API for a GXP client to vote for a
* requested power state and a requested memory power state.
* @gxp: The GXP device to operate.
* @origin_state: An existing old requested state, will be cleared. If this is
* the first vote, pass AUR_OFF.
* @origin_requested_low_clkmux: Specify whether the existing vote was requested with
* low frequency CLKMUX flag.
* @requested_state: The new requested state.
* @requested_low_clkmux: Specify whether the new vote is requested with low frequency
* CLKMUX flag. Will take no effect if the @requested state is
* AUR_OFF.
* @origin_mem_state: An existing old requested state, will be cleared. If this is
* the first vote, pass AUR_MEM_UNDEFINED.
* @requested_mem_state: The new requested state.
*
* Return:
* * 0 - Voting registered
* * -EINVAL - Invalid original state or requested state
*/
int gxp_pm_update_requested_power_states(
struct gxp_dev *gxp, enum aur_power_state origin_state,
bool origin_requested_low_clkmux, enum aur_power_state requested_state,
bool requested_low_clkmux, enum aur_memory_power_state origin_mem_state,
enum aur_memory_power_state requested_mem_state);
/*
* gxp_pm_force_clkmux_normal() - Force PLL_CON0_NOC_USER and PLL_CON0_PLL_AUR MUX
* switch to the normal state. This is required to guarantee LPM works when the core
* is starting the firmware.
*/
void gxp_pm_force_clkmux_normal(struct gxp_dev *gxp);
/*
* gxp_pm_resume_clkmux() - Check PLL_CON0_NOC_USER and PLL_CON0_PLL_AUR MUX state
* modified by gxp_pm_force_clkmux_normal(). If the current vote is requested with low
* frequency CLKMUX flag, should set the MUX state to AUR_CMU_MUX_LOW.
*/
void gxp_pm_resume_clkmux(struct gxp_dev *gxp);
/**
* gxp_pm_set_thermal_limit() - Notify the power manager of a thermal limit
* @gxp: The GXP device the limit is set for
* @thermal_limit: The highest frequency, in Hz, the thermal limit allows
*
* The power management code will only use this information for logging.
*/
void gxp_pm_set_thermal_limit(struct gxp_dev *gxp, unsigned long thermal_limit);
#endif /* __GXP_PM_H__ */