blob: 44803abee5742140d7aaaf34a7a0789bebb88165 [file] [log] [blame]
/*
*
* (C) COPYRIGHT 2010-2017 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 licence.
*
* 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.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Base kernel Power Management hardware control
*/
#include <mali_kbase.h>
#include <mali_kbase_config_defaults.h>
#include <mali_midg_regmap.h>
#if defined(CONFIG_MALI_GATOR_SUPPORT)
#include <mali_kbase_gator.h>
#endif
#include <mali_kbase_tlstream.h>
#include <mali_kbase_pm.h>
#include <mali_kbase_config_defaults.h>
#include <mali_kbase_smc.h>
#include <mali_kbase_hwaccess_jm.h>
#include <mali_kbase_ctx_sched.h>
#include <backend/gpu/mali_kbase_cache_policy_backend.h>
#include <backend/gpu/mali_kbase_device_internal.h>
#include <backend/gpu/mali_kbase_irq_internal.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
#include <linux/of.h>
#if MALI_MOCK_TEST
#define MOCKABLE(function) function##_original
#else
#define MOCKABLE(function) function
#endif /* MALI_MOCK_TEST */
/**
* enum kbasep_pm_action - Actions that can be performed on a core.
*
* This enumeration is private to the file. Its values are set to allow
* core_type_to_reg() function, which decodes this enumeration, to be simpler
* and more efficient.
*
* @ACTION_PRESENT: The cores that are present
* @ACTION_READY: The cores that are ready
* @ACTION_PWRON: Power on the cores specified
* @ACTION_PWROFF: Power off the cores specified
* @ACTION_PWRTRANS: The cores that are transitioning
* @ACTION_PWRACTIVE: The cores that are active
*/
enum kbasep_pm_action {
ACTION_PRESENT = 0,
ACTION_READY = (SHADER_READY_LO - SHADER_PRESENT_LO),
ACTION_PWRON = (SHADER_PWRON_LO - SHADER_PRESENT_LO),
ACTION_PWROFF = (SHADER_PWROFF_LO - SHADER_PRESENT_LO),
ACTION_PWRTRANS = (SHADER_PWRTRANS_LO - SHADER_PRESENT_LO),
ACTION_PWRACTIVE = (SHADER_PWRACTIVE_LO - SHADER_PRESENT_LO)
};
static u64 kbase_pm_get_state(
struct kbase_device *kbdev,
enum kbase_pm_core_type core_type,
enum kbasep_pm_action action);
/**
* core_type_to_reg - Decode a core type and action to a register.
*
* Given a core type (defined by kbase_pm_core_type) and an action (defined
* by kbasep_pm_action) this function will return the register offset that
* will perform the action on the core type. The register returned is the _LO
* register and an offset must be applied to use the _HI register.
*
* @core_type: The type of core
* @action: The type of action
*
* Return: The register offset of the _LO register that performs an action of
* type @action on a core of type @core_type.
*/
static u32 core_type_to_reg(enum kbase_pm_core_type core_type,
enum kbasep_pm_action action)
{
#ifdef CONFIG_MALI_CORESTACK
if (core_type == KBASE_PM_CORE_STACK) {
switch (action) {
case ACTION_PRESENT:
return STACK_PRESENT_LO;
case ACTION_READY:
return STACK_READY_LO;
case ACTION_PWRON:
return STACK_PWRON_LO;
case ACTION_PWROFF:
return STACK_PWROFF_LO;
case ACTION_PWRTRANS:
return STACK_PWRTRANS_LO;
default:
BUG();
}
}
#endif /* CONFIG_MALI_CORESTACK */
return (u32)core_type + (u32)action;
}
#ifdef CONFIG_ARM64
static void mali_cci_flush_l2(struct kbase_device *kbdev)
{
const u32 mask = CLEAN_CACHES_COMPLETED | RESET_COMPLETED;
u32 loops = KBASE_CLEAN_CACHE_MAX_LOOPS;
u32 raw;
/*
* Note that we don't take the cache flush mutex here since
* we expect to be the last user of the L2, all other L2 users
* would have dropped their references, to initiate L2 power
* down, L2 power down being the only valid place for this
* to be called from.
*/
kbase_reg_write(kbdev,
GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_CLEAN_INV_CACHES,
NULL);
raw = kbase_reg_read(kbdev,
GPU_CONTROL_REG(GPU_IRQ_RAWSTAT),
NULL);
/* Wait for cache flush to complete before continuing, exit on
* gpu resets or loop expiry. */
while (((raw & mask) == 0) && --loops) {
raw = kbase_reg_read(kbdev,
GPU_CONTROL_REG(GPU_IRQ_RAWSTAT),
NULL);
}
}
#endif
/**
* kbase_pm_invoke - Invokes an action on a core set
*
* This function performs the action given by @action on a set of cores of a
* type given by @core_type. It is a static function used by
* kbase_pm_transition_core_type()
*
* @kbdev: The kbase device structure of the device
* @core_type: The type of core that the action should be performed on
* @cores: A bit mask of cores to perform the action on (low 32 bits)
* @action: The action to perform on the cores
*/
static void kbase_pm_invoke(struct kbase_device *kbdev,
enum kbase_pm_core_type core_type,
u64 cores,
enum kbasep_pm_action action)
{
u32 reg;
u32 lo = cores & 0xFFFFFFFF;
u32 hi = (cores >> 32) & 0xFFFFFFFF;
lockdep_assert_held(&kbdev->hwaccess_lock);
reg = core_type_to_reg(core_type, action);
KBASE_DEBUG_ASSERT(reg);
#if defined(CONFIG_MALI_GATOR_SUPPORT)
if (cores) {
if (action == ACTION_PWRON)
kbase_trace_mali_pm_power_on(core_type, cores);
else if (action == ACTION_PWROFF)
kbase_trace_mali_pm_power_off(core_type, cores);
}
#endif
if (cores) {
u64 state = kbase_pm_get_state(kbdev, core_type, ACTION_READY);
if (action == ACTION_PWRON)
state |= cores;
else if (action == ACTION_PWROFF)
state &= ~cores;
KBASE_TLSTREAM_AUX_PM_STATE(core_type, state);
}
/* Tracing */
if (cores) {
if (action == ACTION_PWRON)
switch (core_type) {
case KBASE_PM_CORE_SHADER:
KBASE_TRACE_ADD(kbdev, PM_PWRON, NULL, NULL, 0u,
lo);
break;
case KBASE_PM_CORE_TILER:
KBASE_TRACE_ADD(kbdev, PM_PWRON_TILER, NULL,
NULL, 0u, lo);
break;
case KBASE_PM_CORE_L2:
KBASE_TRACE_ADD(kbdev, PM_PWRON_L2, NULL, NULL,
0u, lo);
break;
default:
break;
}
else if (action == ACTION_PWROFF)
switch (core_type) {
case KBASE_PM_CORE_SHADER:
KBASE_TRACE_ADD(kbdev, PM_PWROFF, NULL, NULL,
0u, lo);
break;
case KBASE_PM_CORE_TILER:
KBASE_TRACE_ADD(kbdev, PM_PWROFF_TILER, NULL,
NULL, 0u, lo);
break;
case KBASE_PM_CORE_L2:
KBASE_TRACE_ADD(kbdev, PM_PWROFF_L2, NULL, NULL,
0u, lo);
/* disable snoops before L2 is turned off */
kbase_pm_cache_snoop_disable(kbdev);
break;
default:
break;
}
}
if (lo != 0)
kbase_reg_write(kbdev, GPU_CONTROL_REG(reg), lo, NULL);
if (hi != 0)
kbase_reg_write(kbdev, GPU_CONTROL_REG(reg + 4), hi, NULL);
}
/**
* kbase_pm_get_state - Get information about a core set
*
* This function gets information (chosen by @action) about a set of cores of
* a type given by @core_type. It is a static function used by
* kbase_pm_get_active_cores(), kbase_pm_get_trans_cores() and
* kbase_pm_get_ready_cores().
*
* @kbdev: The kbase device structure of the device
* @core_type: The type of core that the should be queried
* @action: The property of the cores to query
*
* Return: A bit mask specifying the state of the cores
*/
static u64 kbase_pm_get_state(struct kbase_device *kbdev,
enum kbase_pm_core_type core_type,
enum kbasep_pm_action action)
{
u32 reg;
u32 lo, hi;
reg = core_type_to_reg(core_type, action);
KBASE_DEBUG_ASSERT(reg);
lo = kbase_reg_read(kbdev, GPU_CONTROL_REG(reg), NULL);
hi = kbase_reg_read(kbdev, GPU_CONTROL_REG(reg + 4), NULL);
return (((u64) hi) << 32) | ((u64) lo);
}
void kbasep_pm_init_core_use_bitmaps(struct kbase_device *kbdev)
{
kbdev->shader_inuse_bitmap = 0;
kbdev->shader_needed_bitmap = 0;
kbdev->shader_available_bitmap = 0;
kbdev->tiler_available_bitmap = 0;
kbdev->l2_users_count = 0;
kbdev->l2_available_bitmap = 0;
kbdev->tiler_needed_cnt = 0;
kbdev->tiler_inuse_cnt = 0;
memset(kbdev->shader_needed_cnt, 0, sizeof(kbdev->shader_needed_cnt));
}
/**
* kbase_pm_get_present_cores - Get the cores that are present
*
* @kbdev: Kbase device
* @type: The type of cores to query
*
* Return: Bitmask of the cores that are present
*/
u64 kbase_pm_get_present_cores(struct kbase_device *kbdev,
enum kbase_pm_core_type type)
{
KBASE_DEBUG_ASSERT(kbdev != NULL);
switch (type) {
case KBASE_PM_CORE_L2:
return kbdev->gpu_props.props.raw_props.l2_present;
case KBASE_PM_CORE_SHADER:
return kbdev->gpu_props.props.raw_props.shader_present;
case KBASE_PM_CORE_TILER:
return kbdev->gpu_props.props.raw_props.tiler_present;
case KBASE_PM_CORE_STACK:
return kbdev->gpu_props.props.raw_props.stack_present;
default:
break;
}
KBASE_DEBUG_ASSERT(0);
return 0;
}
KBASE_EXPORT_TEST_API(kbase_pm_get_present_cores);
/**
* kbase_pm_get_active_cores - Get the cores that are "active"
* (busy processing work)
*
* @kbdev: Kbase device
* @type: The type of cores to query
*
* Return: Bitmask of cores that are active
*/
u64 kbase_pm_get_active_cores(struct kbase_device *kbdev,
enum kbase_pm_core_type type)
{
return kbase_pm_get_state(kbdev, type, ACTION_PWRACTIVE);
}
KBASE_EXPORT_TEST_API(kbase_pm_get_active_cores);
/**
* kbase_pm_get_trans_cores - Get the cores that are transitioning between
* power states
*
* @kbdev: Kbase device
* @type: The type of cores to query
*
* Return: Bitmask of cores that are transitioning
*/
u64 kbase_pm_get_trans_cores(struct kbase_device *kbdev,
enum kbase_pm_core_type type)
{
return kbase_pm_get_state(kbdev, type, ACTION_PWRTRANS);
}
KBASE_EXPORT_TEST_API(kbase_pm_get_trans_cores);
/**
* kbase_pm_get_ready_cores - Get the cores that are powered on
*
* @kbdev: Kbase device
* @type: The type of cores to query
*
* Return: Bitmask of cores that are ready (powered on)
*/
u64 kbase_pm_get_ready_cores(struct kbase_device *kbdev,
enum kbase_pm_core_type type)
{
u64 result;
result = kbase_pm_get_state(kbdev, type, ACTION_READY);
switch (type) {
case KBASE_PM_CORE_SHADER:
KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED, NULL, NULL, 0u,
(u32) result);
break;
case KBASE_PM_CORE_TILER:
KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED_TILER, NULL, NULL, 0u,
(u32) result);
break;
case KBASE_PM_CORE_L2:
KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED_L2, NULL, NULL, 0u,
(u32) result);
break;
default:
break;
}
return result;
}
KBASE_EXPORT_TEST_API(kbase_pm_get_ready_cores);
/**
* kbase_pm_transition_core_type - Perform power transitions for a particular
* core type.
*
* This function will perform any available power transitions to make the actual
* hardware state closer to the desired state. If a core is currently
* transitioning then changes to the power state of that call cannot be made
* until the transition has finished. Cores which are not present in the
* hardware are ignored if they are specified in the desired_state bitmask,
* however the return value will always be 0 in this case.
*
* @kbdev: The kbase device
* @type: The core type to perform transitions for
* @desired_state: A bit mask of the desired state of the cores
* @in_use: A bit mask of the cores that are currently running
* jobs. These cores have to be kept powered up because
* there are jobs running (or about to run) on them.
* @available: Receives a bit mask of the cores that the job
* scheduler can use to submit jobs to. May be NULL if
* this is not needed.
* @powering_on: Bit mask to update with cores that are
* transitioning to a power-on state.
*
* Return: true if the desired state has been reached, false otherwise
*/
static bool kbase_pm_transition_core_type(struct kbase_device *kbdev,
enum kbase_pm_core_type type,
u64 desired_state,
u64 in_use,
u64 * const available,
u64 *powering_on)
{
u64 present;
u64 ready;
u64 trans;
u64 powerup;
u64 powerdown;
u64 powering_on_trans;
u64 desired_state_in_use;
lockdep_assert_held(&kbdev->hwaccess_lock);
/* Get current state */
present = kbase_pm_get_present_cores(kbdev, type);
trans = kbase_pm_get_trans_cores(kbdev, type);
ready = kbase_pm_get_ready_cores(kbdev, type);
/* mask off ready from trans in case transitions finished between the
* register reads */
trans &= ~ready;
if (trans) /* Do not progress if any cores are transitioning */
return false;
powering_on_trans = trans & *powering_on;
*powering_on = powering_on_trans;
if (available != NULL)
*available = (ready | powering_on_trans) & desired_state;
/* Update desired state to include the in-use cores. These have to be
* kept powered up because there are jobs running or about to run on
* these cores
*/
desired_state_in_use = desired_state | in_use;
/* Update state of whether l2 caches are powered */
if (type == KBASE_PM_CORE_L2) {
if ((ready == present) && (desired_state_in_use == ready) &&
(trans == 0)) {
/* All are ready, none will be turned off, and none are
* transitioning */
kbdev->pm.backend.l2_powered = 1;
/*
* Ensure snoops are enabled after L2 is powered up,
* note that kbase keeps track of the snoop state, so
* safe to repeatedly call.
*/
kbase_pm_cache_snoop_enable(kbdev);
if (kbdev->l2_users_count > 0) {
/* Notify any registered l2 cache users
* (optimized out when no users waiting) */
wake_up(&kbdev->pm.backend.l2_powered_wait);
}
} else
kbdev->pm.backend.l2_powered = 0;
}
if (desired_state == ready && (trans == 0))
return true;
/* Restrict the cores to those that are actually present */
powerup = desired_state_in_use & present;
powerdown = (~desired_state_in_use) & present;
/* Restrict to cores that are not already in the desired state */
powerup &= ~ready;
powerdown &= ready;
/* Don't transition any cores that are already transitioning, except for
* Mali cores that support the following case:
*
* If the SHADER_PWRON or TILER_PWRON registers are written to turn on
* a core that is currently transitioning to power off, then this is
* remembered and the shader core is automatically powered up again once
* the original transition completes. Once the automatic power on is
* complete any job scheduled on the shader core should start.
*/
powerdown &= ~trans;
if (kbase_hw_has_feature(kbdev,
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS))
if (KBASE_PM_CORE_SHADER == type || KBASE_PM_CORE_TILER == type)
trans = powering_on_trans; /* for exception cases, only
* mask off cores in power on
* transitions */
powerup &= ~trans;
/* Perform transitions if any */
kbase_pm_invoke(kbdev, type, powerup, ACTION_PWRON);
#if !PLATFORM_POWER_DOWN_ONLY
kbase_pm_invoke(kbdev, type, powerdown, ACTION_PWROFF);
#endif
/* Recalculate cores transitioning on, and re-evaluate our state */
powering_on_trans |= powerup;
*powering_on = powering_on_trans;
if (available != NULL)
*available = (ready | powering_on_trans) & desired_state;
return false;
}
KBASE_EXPORT_TEST_API(kbase_pm_transition_core_type);
/**
* get_desired_cache_status - Determine which caches should be on for a
* particular core state
*
* This function takes a bit mask of the present caches and the cores (or
* caches) that are attached to the caches that will be powered. It then
* computes which caches should be turned on to allow the cores requested to be
* powered up.
*
* @present: The bit mask of present caches
* @cores_powered: A bit mask of cores (or L2 caches) that are desired to
* be powered
* @tilers_powered: The bit mask of tilers that are desired to be powered
*
* Return: A bit mask of the caches that should be turned on
*/
static u64 get_desired_cache_status(u64 present, u64 cores_powered,
u64 tilers_powered)
{
u64 desired = 0;
while (present) {
/* Find out which is the highest set bit */
u64 bit = fls64(present) - 1;
u64 bit_mask = 1ull << bit;
/* Create a mask which has all bits from 'bit' upwards set */
u64 mask = ~(bit_mask - 1);
/* If there are any cores powered at this bit or above (that
* haven't previously been processed) then we need this core on
*/
if (cores_powered & mask)
desired |= bit_mask;
/* Remove bits from cores_powered and present */
cores_powered &= ~mask;
present &= ~bit_mask;
}
/* Power up the required L2(s) for the tiler */
if (tilers_powered)
desired |= 1;
return desired;
}
KBASE_EXPORT_TEST_API(get_desired_cache_status);
#ifdef CONFIG_MALI_CORESTACK
u64 kbase_pm_core_stack_mask(u64 cores)
{
u64 stack_mask = 0;
size_t const MAX_CORE_ID = 31;
size_t const NUM_CORES_PER_STACK = 4;
size_t i;
for (i = 0; i <= MAX_CORE_ID; ++i) {
if (test_bit(i, (unsigned long *)&cores)) {
/* Every core which ID >= 16 is filled to stacks 4-7
* instead of 0-3 */
size_t const stack_num = (i >= 16) ?
(i % NUM_CORES_PER_STACK) + 4 :
(i % NUM_CORES_PER_STACK);
set_bit(stack_num, (unsigned long *)&stack_mask);
}
}
return stack_mask;
}
#endif /* CONFIG_MALI_CORESTACK */
bool
MOCKABLE(kbase_pm_check_transitions_nolock) (struct kbase_device *kbdev)
{
bool cores_are_available = false;
bool in_desired_state = true;
u64 desired_l2_state;
#ifdef CONFIG_MALI_CORESTACK
u64 desired_stack_state;
u64 stacks_powered;
#endif /* CONFIG_MALI_CORESTACK */
u64 cores_powered;
u64 tilers_powered;
u64 tiler_available_bitmap;
u64 tiler_transitioning_bitmap;
u64 shader_available_bitmap;
u64 shader_ready_bitmap;
u64 shader_transitioning_bitmap;
u64 l2_available_bitmap;
u64 prev_l2_available_bitmap;
u64 l2_inuse_bitmap;
KBASE_DEBUG_ASSERT(NULL != kbdev);
lockdep_assert_held(&kbdev->hwaccess_lock);
spin_lock(&kbdev->pm.backend.gpu_powered_lock);
if (kbdev->pm.backend.gpu_powered == false) {
spin_unlock(&kbdev->pm.backend.gpu_powered_lock);
if (kbdev->pm.backend.desired_shader_state == 0 &&
kbdev->pm.backend.desired_tiler_state == 0)
return true;
return false;
}
/* Trace that a change-state is being requested, and that it took
* (effectively) no time to start it. This is useful for counting how
* many state changes occurred, in a way that's backwards-compatible
* with processing the trace data */
kbase_timeline_pm_send_event(kbdev,
KBASE_TIMELINE_PM_EVENT_CHANGE_GPU_STATE);
kbase_timeline_pm_handle_event(kbdev,
KBASE_TIMELINE_PM_EVENT_CHANGE_GPU_STATE);
/* If any cores are already powered then, we must keep the caches on */
shader_transitioning_bitmap = kbase_pm_get_trans_cores(kbdev,
KBASE_PM_CORE_SHADER);
cores_powered = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_SHADER);
cores_powered |= kbdev->pm.backend.desired_shader_state;
#ifdef CONFIG_MALI_CORESTACK
/* Work out which core stacks want to be powered */
desired_stack_state = kbase_pm_core_stack_mask(cores_powered);
stacks_powered = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_STACK) |
desired_stack_state;
#endif /* CONFIG_MALI_CORESTACK */
/* Work out which tilers want to be powered */
tiler_transitioning_bitmap = kbase_pm_get_trans_cores(kbdev,
KBASE_PM_CORE_TILER);
tilers_powered = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_TILER);
tilers_powered |= kbdev->pm.backend.desired_tiler_state;
/* If there are l2 cache users registered, keep all l2s powered even if
* all other cores are off. */
if (kbdev->l2_users_count > 0)
cores_powered |= kbdev->gpu_props.props.raw_props.l2_present;
desired_l2_state = get_desired_cache_status(
kbdev->gpu_props.props.raw_props.l2_present,
cores_powered, tilers_powered);
l2_inuse_bitmap = get_desired_cache_status(
kbdev->gpu_props.props.raw_props.l2_present,
cores_powered | shader_transitioning_bitmap,
tilers_powered | tiler_transitioning_bitmap);
#ifdef CONFIG_MALI_CORESTACK
if (stacks_powered)
desired_l2_state |= 1;
#endif /* CONFIG_MALI_CORESTACK */
/* If any l2 cache is on, then enable l2 #0, for use by job manager */
if (0 != desired_l2_state)
desired_l2_state |= 1;
prev_l2_available_bitmap = kbdev->l2_available_bitmap;
in_desired_state &= kbase_pm_transition_core_type(kbdev,
KBASE_PM_CORE_L2, desired_l2_state, l2_inuse_bitmap,
&l2_available_bitmap,
&kbdev->pm.backend.powering_on_l2_state);
if (kbdev->l2_available_bitmap != l2_available_bitmap)
KBASE_TIMELINE_POWER_L2(kbdev, l2_available_bitmap);
kbdev->l2_available_bitmap = l2_available_bitmap;
#ifdef CONFIG_MALI_CORESTACK
if (in_desired_state) {
in_desired_state &= kbase_pm_transition_core_type(kbdev,
KBASE_PM_CORE_STACK, desired_stack_state, 0,
&kbdev->stack_available_bitmap,
&kbdev->pm.backend.powering_on_stack_state);
}
#endif /* CONFIG_MALI_CORESTACK */
if (in_desired_state) {
in_desired_state &= kbase_pm_transition_core_type(kbdev,
KBASE_PM_CORE_TILER,
kbdev->pm.backend.desired_tiler_state,
0, &tiler_available_bitmap,
&kbdev->pm.backend.powering_on_tiler_state);
in_desired_state &= kbase_pm_transition_core_type(kbdev,
KBASE_PM_CORE_SHADER,
kbdev->pm.backend.desired_shader_state,
kbdev->shader_inuse_bitmap,
&shader_available_bitmap,
&kbdev->pm.backend.powering_on_shader_state);
if (kbdev->shader_available_bitmap != shader_available_bitmap) {
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL,
NULL, 0u,
(u32) shader_available_bitmap);
KBASE_TIMELINE_POWER_SHADER(kbdev,
shader_available_bitmap);
}
kbdev->shader_available_bitmap = shader_available_bitmap;
if (kbdev->tiler_available_bitmap != tiler_available_bitmap) {
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER,
NULL, NULL, 0u,
(u32) tiler_available_bitmap);
KBASE_TIMELINE_POWER_TILER(kbdev,
tiler_available_bitmap);
}
kbdev->tiler_available_bitmap = tiler_available_bitmap;
} else if ((l2_available_bitmap &
kbdev->gpu_props.props.raw_props.tiler_present) !=
kbdev->gpu_props.props.raw_props.tiler_present) {
tiler_available_bitmap = 0;
if (kbdev->tiler_available_bitmap != tiler_available_bitmap)
KBASE_TIMELINE_POWER_TILER(kbdev,
tiler_available_bitmap);
kbdev->tiler_available_bitmap = tiler_available_bitmap;
}
/* State updated for slow-path waiters */
kbdev->pm.backend.gpu_in_desired_state = in_desired_state;
shader_ready_bitmap = kbase_pm_get_ready_cores(kbdev,
KBASE_PM_CORE_SHADER);
shader_transitioning_bitmap = kbase_pm_get_trans_cores(kbdev,
KBASE_PM_CORE_SHADER);
/* Determine whether the cores are now available (even if the set of
* available cores is empty). Note that they can be available even if
* we've not finished transitioning to the desired state */
if ((kbdev->shader_available_bitmap &
kbdev->pm.backend.desired_shader_state)
== kbdev->pm.backend.desired_shader_state &&
(kbdev->tiler_available_bitmap &
kbdev->pm.backend.desired_tiler_state)
== kbdev->pm.backend.desired_tiler_state) {
cores_are_available = true;
KBASE_TRACE_ADD(kbdev, PM_CORES_AVAILABLE, NULL, NULL, 0u,
(u32)(kbdev->shader_available_bitmap &
kbdev->pm.backend.desired_shader_state));
KBASE_TRACE_ADD(kbdev, PM_CORES_AVAILABLE_TILER, NULL, NULL, 0u,
(u32)(kbdev->tiler_available_bitmap &
kbdev->pm.backend.desired_tiler_state));
/* Log timelining information about handling events that power
* up cores, to match up either with immediate submission either
* because cores already available, or from PM IRQ */
if (!in_desired_state)
kbase_timeline_pm_send_event(kbdev,
KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED);
}
if (in_desired_state) {
KBASE_DEBUG_ASSERT(cores_are_available);
#if defined(CONFIG_MALI_GATOR_SUPPORT)
kbase_trace_mali_pm_status(KBASE_PM_CORE_L2,
kbase_pm_get_ready_cores(kbdev,
KBASE_PM_CORE_L2));
kbase_trace_mali_pm_status(KBASE_PM_CORE_SHADER,
kbase_pm_get_ready_cores(kbdev,
KBASE_PM_CORE_SHADER));
kbase_trace_mali_pm_status(KBASE_PM_CORE_TILER,
kbase_pm_get_ready_cores(kbdev,
KBASE_PM_CORE_TILER));
#ifdef CONFIG_MALI_CORESTACK
kbase_trace_mali_pm_status(KBASE_PM_CORE_STACK,
kbase_pm_get_ready_cores(kbdev,
KBASE_PM_CORE_STACK));
#endif /* CONFIG_MALI_CORESTACK */
#endif
KBASE_TLSTREAM_AUX_PM_STATE(
KBASE_PM_CORE_L2,
kbase_pm_get_ready_cores(
kbdev, KBASE_PM_CORE_L2));
KBASE_TLSTREAM_AUX_PM_STATE(
KBASE_PM_CORE_SHADER,
kbase_pm_get_ready_cores(
kbdev, KBASE_PM_CORE_SHADER));
KBASE_TLSTREAM_AUX_PM_STATE(
KBASE_PM_CORE_TILER,
kbase_pm_get_ready_cores(
kbdev,
KBASE_PM_CORE_TILER));
#ifdef CONFIG_MALI_CORESTACK
KBASE_TLSTREAM_AUX_PM_STATE(
KBASE_PM_CORE_STACK,
kbase_pm_get_ready_cores(
kbdev,
KBASE_PM_CORE_STACK));
#endif /* CONFIG_MALI_CORESTACK */
KBASE_TRACE_ADD(kbdev, PM_DESIRED_REACHED, NULL, NULL,
kbdev->pm.backend.gpu_in_desired_state,
(u32)kbdev->pm.backend.desired_shader_state);
KBASE_TRACE_ADD(kbdev, PM_DESIRED_REACHED_TILER, NULL, NULL, 0u,
(u32)kbdev->pm.backend.desired_tiler_state);
/* Log timelining information for synchronous waiters */
kbase_timeline_pm_send_event(kbdev,
KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED);
/* Wake slow-path waiters. Job scheduler does not use this. */
KBASE_TRACE_ADD(kbdev, PM_WAKE_WAITERS, NULL, NULL, 0u, 0);
wake_up(&kbdev->pm.backend.gpu_in_desired_state_wait);
}
spin_unlock(&kbdev->pm.backend.gpu_powered_lock);
/* kbase_pm_ca_update_core_status can cause one-level recursion into
* this function, so it must only be called once all changes to kbdev
* have been committed, and after the gpu_powered_lock has been
* dropped. */
if (kbdev->shader_ready_bitmap != shader_ready_bitmap ||
kbdev->shader_transitioning_bitmap != shader_transitioning_bitmap) {
kbdev->shader_ready_bitmap = shader_ready_bitmap;
kbdev->shader_transitioning_bitmap =
shader_transitioning_bitmap;
kbase_pm_ca_update_core_status(kbdev, shader_ready_bitmap,
shader_transitioning_bitmap);
}
/* The core availability policy is not allowed to keep core group 0
* turned off (unless it was changing the l2 power state) */
if (!((shader_ready_bitmap | shader_transitioning_bitmap) &
kbdev->gpu_props.props.coherency_info.group[0].core_mask) &&
(prev_l2_available_bitmap == desired_l2_state) &&
!(kbase_pm_ca_get_core_mask(kbdev) &
kbdev->gpu_props.props.coherency_info.group[0].core_mask))
BUG();
/* The core availability policy is allowed to keep core group 1 off,
* but all jobs specifically targeting CG1 must fail */
if (!((shader_ready_bitmap | shader_transitioning_bitmap) &
kbdev->gpu_props.props.coherency_info.group[1].core_mask) &&
!(kbase_pm_ca_get_core_mask(kbdev) &
kbdev->gpu_props.props.coherency_info.group[1].core_mask))
kbdev->pm.backend.cg1_disabled = true;
else
kbdev->pm.backend.cg1_disabled = false;
return cores_are_available;
}
KBASE_EXPORT_TEST_API(kbase_pm_check_transitions_nolock);
/* Timeout for kbase_pm_check_transitions_sync when wait_event_killable has
* aborted due to a fatal signal. If the time spent waiting has exceeded this
* threshold then there is most likely a hardware issue. */
#define PM_TIMEOUT (5*HZ) /* 5s */
void kbase_pm_check_transitions_sync(struct kbase_device *kbdev)
{
unsigned long flags;
unsigned long timeout;
bool cores_are_available;
int ret;
/* Force the transition to be checked and reported - the cores may be
* 'available' (for job submission) but not fully powered up. */
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
cores_are_available = kbase_pm_check_transitions_nolock(kbdev);
/* Don't need 'cores_are_available', because we don't return anything */
CSTD_UNUSED(cores_are_available);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
timeout = jiffies + PM_TIMEOUT;
/* Wait for cores */
ret = wait_event_killable(kbdev->pm.backend.gpu_in_desired_state_wait,
kbdev->pm.backend.gpu_in_desired_state);
if (ret < 0 && time_after(jiffies, timeout)) {
dev_err(kbdev->dev, "Power transition timed out unexpectedly\n");
dev_err(kbdev->dev, "Desired state :\n");
dev_err(kbdev->dev, "\tShader=%016llx\n",
kbdev->pm.backend.desired_shader_state);
dev_err(kbdev->dev, "\tTiler =%016llx\n",
kbdev->pm.backend.desired_tiler_state);
dev_err(kbdev->dev, "Current state :\n");
dev_err(kbdev->dev, "\tShader=%08x%08x\n",
kbase_reg_read(kbdev,
GPU_CONTROL_REG(SHADER_READY_HI), NULL),
kbase_reg_read(kbdev,
GPU_CONTROL_REG(SHADER_READY_LO),
NULL));
dev_err(kbdev->dev, "\tTiler =%08x%08x\n",
kbase_reg_read(kbdev,
GPU_CONTROL_REG(TILER_READY_HI), NULL),
kbase_reg_read(kbdev,
GPU_CONTROL_REG(TILER_READY_LO), NULL));
dev_err(kbdev->dev, "\tL2 =%08x%08x\n",
kbase_reg_read(kbdev,
GPU_CONTROL_REG(L2_READY_HI), NULL),
kbase_reg_read(kbdev,
GPU_CONTROL_REG(L2_READY_LO), NULL));
dev_err(kbdev->dev, "Cores transitioning :\n");
dev_err(kbdev->dev, "\tShader=%08x%08x\n",
kbase_reg_read(kbdev, GPU_CONTROL_REG(
SHADER_PWRTRANS_HI), NULL),
kbase_reg_read(kbdev, GPU_CONTROL_REG(
SHADER_PWRTRANS_LO), NULL));
dev_err(kbdev->dev, "\tTiler =%08x%08x\n",
kbase_reg_read(kbdev, GPU_CONTROL_REG(
TILER_PWRTRANS_HI), NULL),
kbase_reg_read(kbdev, GPU_CONTROL_REG(
TILER_PWRTRANS_LO), NULL));
dev_err(kbdev->dev, "\tL2 =%08x%08x\n",
kbase_reg_read(kbdev, GPU_CONTROL_REG(
L2_PWRTRANS_HI), NULL),
kbase_reg_read(kbdev, GPU_CONTROL_REG(
L2_PWRTRANS_LO), NULL));
#if KBASE_GPU_RESET_EN
dev_err(kbdev->dev, "Sending reset to GPU - all running jobs will be lost\n");
if (kbase_prepare_to_reset_gpu(kbdev))
kbase_reset_gpu(kbdev);
#endif /* KBASE_GPU_RESET_EN */
} else {
/* Log timelining information that a change in state has
* completed */
kbase_timeline_pm_handle_event(kbdev,
KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED);
}
}
KBASE_EXPORT_TEST_API(kbase_pm_check_transitions_sync);
void kbase_pm_enable_interrupts(struct kbase_device *kbdev)
{
unsigned long flags;
KBASE_DEBUG_ASSERT(NULL != kbdev);
/*
* Clear all interrupts,
* and unmask them all.
*/
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), GPU_IRQ_REG_ALL,
NULL);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), GPU_IRQ_REG_ALL,
NULL);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), 0xFFFFFFFF,
NULL);
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), 0xFFFFFFFF, NULL);
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), 0xFFFFFFFF, NULL);
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0xFFFFFFFF, NULL);
}
KBASE_EXPORT_TEST_API(kbase_pm_enable_interrupts);
void kbase_pm_disable_interrupts_nolock(struct kbase_device *kbdev)
{
KBASE_DEBUG_ASSERT(NULL != kbdev);
/*
* Mask all interrupts,
* and clear them all.
*/
lockdep_assert_held(&kbdev->hwaccess_lock);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), 0, NULL);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), GPU_IRQ_REG_ALL,
NULL);
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), 0, NULL);
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), 0xFFFFFFFF,
NULL);
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0, NULL);
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), 0xFFFFFFFF, NULL);
}
void kbase_pm_disable_interrupts(struct kbase_device *kbdev)
{
unsigned long flags;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbase_pm_disable_interrupts_nolock(kbdev);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
}
KBASE_EXPORT_TEST_API(kbase_pm_disable_interrupts);
/*
* pmu layout:
* 0x0000: PMU TAG (RO) (0xCAFECAFE)
* 0x0004: PMU VERSION ID (RO) (0x00000000)
* 0x0008: CLOCK ENABLE (RW) (31:1 SBZ, 0 CLOCK STATE)
*/
void kbase_pm_clock_on(struct kbase_device *kbdev, bool is_resume)
{
bool reset_required = is_resume;
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
unsigned long flags;
KBASE_DEBUG_ASSERT(NULL != kbdev);
lockdep_assert_held(&js_devdata->runpool_mutex);
lockdep_assert_held(&kbdev->pm.lock);
if (kbdev->pm.backend.gpu_powered) {
/* Already turned on */
if (kbdev->poweroff_pending)
kbase_pm_enable_interrupts(kbdev);
kbdev->poweroff_pending = false;
KBASE_DEBUG_ASSERT(!is_resume);
return;
}
kbdev->poweroff_pending = false;
KBASE_TRACE_ADD(kbdev, PM_GPU_ON, NULL, NULL, 0u, 0u);
if (is_resume && kbdev->pm.backend.callback_power_resume) {
kbdev->pm.backend.callback_power_resume(kbdev);
return;
} else if (kbdev->pm.backend.callback_power_on) {
kbdev->pm.backend.callback_power_on(kbdev);
/* If your platform properly keeps the GPU state you may use the
* return value of the callback_power_on function to
* conditionally reset the GPU on power up. Currently we are
* conservative and always reset the GPU. */
reset_required = true;
}
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags);
kbdev->pm.backend.gpu_powered = true;
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags);
if (reset_required) {
/* GPU state was lost, reset GPU to ensure it is in a
* consistent state */
kbase_pm_init_hw(kbdev, PM_ENABLE_IRQS);
}
mutex_lock(&kbdev->mmu_hw_mutex);
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbase_ctx_sched_restore_all_as(kbdev);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
mutex_unlock(&kbdev->mmu_hw_mutex);
/* Lastly, enable the interrupts */
kbase_pm_enable_interrupts(kbdev);
}
KBASE_EXPORT_TEST_API(kbase_pm_clock_on);
bool kbase_pm_clock_off(struct kbase_device *kbdev, bool is_suspend)
{
unsigned long flags;
KBASE_DEBUG_ASSERT(NULL != kbdev);
lockdep_assert_held(&kbdev->pm.lock);
/* ASSERT that the cores should now be unavailable. No lock needed. */
KBASE_DEBUG_ASSERT(kbdev->shader_available_bitmap == 0u);
kbdev->poweroff_pending = true;
if (!kbdev->pm.backend.gpu_powered) {
/* Already turned off */
if (is_suspend && kbdev->pm.backend.callback_power_suspend)
kbdev->pm.backend.callback_power_suspend(kbdev);
return true;
}
KBASE_TRACE_ADD(kbdev, PM_GPU_OFF, NULL, NULL, 0u, 0u);
/* Disable interrupts. This also clears any outstanding interrupts */
kbase_pm_disable_interrupts(kbdev);
/* Ensure that any IRQ handlers have finished */
kbase_synchronize_irqs(kbdev);
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags);
if (atomic_read(&kbdev->faults_pending)) {
/* Page/bus faults are still being processed. The GPU can not
* be powered off until they have completed */
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock,
flags);
return false;
}
kbase_pm_cache_snoop_disable(kbdev);
/* The GPU power may be turned off from this point */
kbdev->pm.backend.gpu_powered = false;
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags);
if (is_suspend && kbdev->pm.backend.callback_power_suspend)
kbdev->pm.backend.callback_power_suspend(kbdev);
else if (kbdev->pm.backend.callback_power_off)
kbdev->pm.backend.callback_power_off(kbdev);
return true;
}
KBASE_EXPORT_TEST_API(kbase_pm_clock_off);
struct kbasep_reset_timeout_data {
struct hrtimer timer;
bool timed_out;
struct kbase_device *kbdev;
};
void kbase_pm_reset_done(struct kbase_device *kbdev)
{
KBASE_DEBUG_ASSERT(kbdev != NULL);
kbdev->pm.backend.reset_done = true;
wake_up(&kbdev->pm.backend.reset_done_wait);
}
/**
* kbase_pm_wait_for_reset - Wait for a reset to happen
*
* Wait for the %RESET_COMPLETED IRQ to occur, then reset the waiting state.
*
* @kbdev: Kbase device
*/
static void kbase_pm_wait_for_reset(struct kbase_device *kbdev)
{
lockdep_assert_held(&kbdev->pm.lock);
wait_event(kbdev->pm.backend.reset_done_wait,
(kbdev->pm.backend.reset_done));
kbdev->pm.backend.reset_done = false;
}
KBASE_EXPORT_TEST_API(kbase_pm_reset_done);
static enum hrtimer_restart kbasep_reset_timeout(struct hrtimer *timer)
{
struct kbasep_reset_timeout_data *rtdata =
container_of(timer, struct kbasep_reset_timeout_data, timer);
rtdata->timed_out = 1;
/* Set the wait queue to wake up kbase_pm_init_hw even though the reset
* hasn't completed */
kbase_pm_reset_done(rtdata->kbdev);
return HRTIMER_NORESTART;
}
static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev)
{
struct device_node *np = kbdev->dev->of_node;
u32 jm_values[4];
const u32 gpu_id = kbdev->gpu_props.props.raw_props.gpu_id;
const u32 prod_id = (gpu_id & GPU_ID_VERSION_PRODUCT_ID) >>
GPU_ID_VERSION_PRODUCT_ID_SHIFT;
const u32 major = (gpu_id & GPU_ID_VERSION_MAJOR) >>
GPU_ID_VERSION_MAJOR_SHIFT;
kbdev->hw_quirks_sc = 0;
/* Needed due to MIDBASE-1494: LS_PAUSEBUFFER_DISABLE. See PRLAM-8443.
* and needed due to MIDGLES-3539. See PRLAM-11035 */
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8443) ||
kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_11035))
kbdev->hw_quirks_sc |= SC_LS_PAUSEBUFFER_DISABLE;
/* Needed due to MIDBASE-2054: SDC_DISABLE_OQ_DISCARD. See PRLAM-10327.
*/
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10327))
kbdev->hw_quirks_sc |= SC_SDC_DISABLE_OQ_DISCARD;
#ifdef CONFIG_MALI_PRFCNT_SET_SECONDARY
/* Enable alternative hardware counter selection if configured. */
if (!GPU_ID_IS_NEW_FORMAT(prod_id))
kbdev->hw_quirks_sc |= SC_ALT_COUNTERS;
#endif
/* Needed due to MIDBASE-2795. ENABLE_TEXGRD_FLAGS. See PRLAM-10797. */
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10797))
kbdev->hw_quirks_sc |= SC_ENABLE_TEXGRD_FLAGS;
if (!kbase_hw_has_issue(kbdev, GPUCORE_1619)) {
if (prod_id < 0x750 || prod_id == 0x6956) /* T60x, T62x, T72x */
kbdev->hw_quirks_sc |= SC_LS_ATTR_CHECK_DISABLE;
else if (prod_id >= 0x750 && prod_id <= 0x880) /* T76x, T8xx */
kbdev->hw_quirks_sc |= SC_LS_ALLOW_ATTR_TYPES;
}
if (!kbdev->hw_quirks_sc)
kbdev->hw_quirks_sc = kbase_reg_read(kbdev,
GPU_CONTROL_REG(SHADER_CONFIG), NULL);
kbdev->hw_quirks_tiler = kbase_reg_read(kbdev,
GPU_CONTROL_REG(TILER_CONFIG), NULL);
/* Set tiler clock gate override if required */
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_T76X_3953))
kbdev->hw_quirks_tiler |= TC_CLOCK_GATE_OVERRIDE;
/* Limit the GPU bus bandwidth if the platform needs this. */
kbdev->hw_quirks_mmu = kbase_reg_read(kbdev,
GPU_CONTROL_REG(L2_MMU_CONFIG), NULL);
/* Limit read & write ID width for AXI */
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) {
kbdev->hw_quirks_mmu &= ~(L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS);
kbdev->hw_quirks_mmu |= (DEFAULT_3BIT_ARID_LIMIT & 0x7) <<
L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS_SHIFT;
kbdev->hw_quirks_mmu &= ~(L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES);
kbdev->hw_quirks_mmu |= (DEFAULT_3BIT_AWID_LIMIT & 0x7) <<
L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES_SHIFT;
} else {
kbdev->hw_quirks_mmu &= ~(L2_MMU_CONFIG_LIMIT_EXTERNAL_READS);
kbdev->hw_quirks_mmu |= (DEFAULT_ARID_LIMIT & 0x3) <<
L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT;
kbdev->hw_quirks_mmu &= ~(L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES);
kbdev->hw_quirks_mmu |= (DEFAULT_AWID_LIMIT & 0x3) <<
L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT;
}
if (kbdev->system_coherency == COHERENCY_ACE) {
/* Allow memory configuration disparity to be ignored, we
* optimize the use of shared memory and thus we expect
* some disparity in the memory configuration */
kbdev->hw_quirks_mmu |= L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY;
}
kbdev->hw_quirks_jm = 0;
/* Only for T86x/T88x-based products after r2p0 */
if (prod_id >= 0x860 && prod_id <= 0x880 && major >= 2) {
if (of_property_read_u32_array(np,
"jm_config",
&jm_values[0],
ARRAY_SIZE(jm_values))) {
/* Entry not in device tree, use defaults */
jm_values[0] = 0;
jm_values[1] = 0;
jm_values[2] = 0;
jm_values[3] = JM_MAX_JOB_THROTTLE_LIMIT;
}
/* Limit throttle limit to 6 bits*/
if (jm_values[3] > JM_MAX_JOB_THROTTLE_LIMIT) {
dev_dbg(kbdev->dev, "JOB_THROTTLE_LIMIT supplied in device tree is too large. Limiting to MAX (63).");
jm_values[3] = JM_MAX_JOB_THROTTLE_LIMIT;
}
/* Aggregate to one integer. */
kbdev->hw_quirks_jm |= (jm_values[0] ?
JM_TIMESTAMP_OVERRIDE : 0);
kbdev->hw_quirks_jm |= (jm_values[1] ?
JM_CLOCK_GATE_OVERRIDE : 0);
kbdev->hw_quirks_jm |= (jm_values[2] ?
JM_JOB_THROTTLE_ENABLE : 0);
kbdev->hw_quirks_jm |= (jm_values[3] <<
JM_JOB_THROTTLE_LIMIT_SHIFT);
} else if (GPU_ID_IS_NEW_FORMAT(prod_id) &&
(GPU_ID2_MODEL_MATCH_VALUE(prod_id) ==
GPU_ID2_PRODUCT_TMIX)) {
/* Only for tMIx */
u32 coherency_features;
coherency_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(COHERENCY_FEATURES), NULL);
/* (COHERENCY_ACE_LITE | COHERENCY_ACE) was incorrectly
* documented for tMIx so force correct value here.
*/
if (coherency_features ==
COHERENCY_FEATURE_BIT(COHERENCY_ACE)) {
kbdev->hw_quirks_jm |=
(COHERENCY_ACE_LITE | COHERENCY_ACE) <<
JM_FORCE_COHERENCY_FEATURES_SHIFT;
}
}
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_TLS_HASHING))
kbdev->hw_quirks_sc |= SC_TLS_HASH_ENABLE;
if (!kbdev->hw_quirks_jm)
kbdev->hw_quirks_jm = kbase_reg_read(kbdev,
GPU_CONTROL_REG(JM_CONFIG), NULL);
#ifdef CONFIG_MALI_CORESTACK
#define MANUAL_POWER_CONTROL ((u32)(1 << 8))
kbdev->hw_quirks_jm |= MANUAL_POWER_CONTROL;
#endif /* CONFIG_MALI_CORESTACK */
}
static void kbase_pm_hw_issues_apply(struct kbase_device *kbdev)
{
kbase_reg_write(kbdev, GPU_CONTROL_REG(SHADER_CONFIG),
kbdev->hw_quirks_sc, NULL);
kbase_reg_write(kbdev, GPU_CONTROL_REG(TILER_CONFIG),
kbdev->hw_quirks_tiler, NULL);
kbase_reg_write(kbdev, GPU_CONTROL_REG(L2_MMU_CONFIG),
kbdev->hw_quirks_mmu, NULL);
kbase_reg_write(kbdev, GPU_CONTROL_REG(JM_CONFIG),
kbdev->hw_quirks_jm, NULL);
}
void kbase_pm_cache_snoop_enable(struct kbase_device *kbdev)
{
if ((kbdev->current_gpu_coherency_mode == COHERENCY_ACE) &&
!kbdev->cci_snoop_enabled) {
#ifdef CONFIG_ARM64
if (kbdev->snoop_enable_smc != 0)
kbase_invoke_smc_fid(kbdev->snoop_enable_smc, 0, 0, 0);
#endif /* CONFIG_ARM64 */
dev_dbg(kbdev->dev, "MALI - CCI Snoops - Enabled\n");
kbdev->cci_snoop_enabled = true;
}
}
void kbase_pm_cache_snoop_disable(struct kbase_device *kbdev)
{
if (kbdev->cci_snoop_enabled) {
#ifdef CONFIG_ARM64
if (kbdev->snoop_disable_smc != 0) {
mali_cci_flush_l2(kbdev);
kbase_invoke_smc_fid(kbdev->snoop_disable_smc, 0, 0, 0);
}
#endif /* CONFIG_ARM64 */
dev_dbg(kbdev->dev, "MALI - CCI Snoops Disabled\n");
kbdev->cci_snoop_enabled = false;
}
}
static int kbase_pm_do_reset(struct kbase_device *kbdev)
{
struct kbasep_reset_timeout_data rtdata;
KBASE_TRACE_ADD(kbdev, CORE_GPU_SOFT_RESET, NULL, NULL, 0u, 0);
KBASE_TLSTREAM_JD_GPU_SOFT_RESET(kbdev);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_SOFT_RESET, NULL);
/* Unmask the reset complete interrupt only */
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), RESET_COMPLETED,
NULL);
/* Initialize a structure for tracking the status of the reset */
rtdata.kbdev = kbdev;
rtdata.timed_out = 0;
/* Create a timer to use as a timeout on the reset */
hrtimer_init_on_stack(&rtdata.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
rtdata.timer.function = kbasep_reset_timeout;
hrtimer_start(&rtdata.timer, HR_TIMER_DELAY_MSEC(RESET_TIMEOUT),
HRTIMER_MODE_REL);
/* Wait for the RESET_COMPLETED interrupt to be raised */
kbase_pm_wait_for_reset(kbdev);
if (rtdata.timed_out == 0) {
/* GPU has been reset */
hrtimer_cancel(&rtdata.timer);
destroy_hrtimer_on_stack(&rtdata.timer);
return 0;
}
/* No interrupt has been received - check if the RAWSTAT register says
* the reset has completed */
if (kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), NULL) &
RESET_COMPLETED) {
/* The interrupt is set in the RAWSTAT; this suggests that the
* interrupts are not getting to the CPU */
dev_err(kbdev->dev, "Reset interrupt didn't reach CPU. Check interrupt assignments.\n");
/* If interrupts aren't working we can't continue. */
destroy_hrtimer_on_stack(&rtdata.timer);
return -EINVAL;
}
/* The GPU doesn't seem to be responding to the reset so try a hard
* reset */
dev_err(kbdev->dev, "Failed to soft-reset GPU (timed out after %d ms), now attempting a hard reset\n",
RESET_TIMEOUT);
KBASE_TRACE_ADD(kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_HARD_RESET, NULL);
/* Restart the timer to wait for the hard reset to complete */
rtdata.timed_out = 0;
hrtimer_start(&rtdata.timer, HR_TIMER_DELAY_MSEC(RESET_TIMEOUT),
HRTIMER_MODE_REL);
/* Wait for the RESET_COMPLETED interrupt to be raised */
kbase_pm_wait_for_reset(kbdev);
if (rtdata.timed_out == 0) {
/* GPU has been reset */
hrtimer_cancel(&rtdata.timer);
destroy_hrtimer_on_stack(&rtdata.timer);
return 0;
}
destroy_hrtimer_on_stack(&rtdata.timer);
dev_err(kbdev->dev, "Failed to hard-reset the GPU (timed out after %d ms)\n",
RESET_TIMEOUT);
return -EINVAL;
}
static int kbasep_protected_mode_enable(struct protected_mode_device *pdev)
{
struct kbase_device *kbdev = pdev->data;
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_SET_PROTECTED_MODE, NULL);
return 0;
}
static int kbasep_protected_mode_disable(struct protected_mode_device *pdev)
{
struct kbase_device *kbdev = pdev->data;
lockdep_assert_held(&kbdev->pm.lock);
return kbase_pm_do_reset(kbdev);
}
struct protected_mode_ops kbase_native_protected_ops = {
.protected_mode_enable = kbasep_protected_mode_enable,
.protected_mode_disable = kbasep_protected_mode_disable
};
int kbase_pm_init_hw(struct kbase_device *kbdev, unsigned int flags)
{
unsigned long irq_flags;
int err;
bool resume_vinstr = false;
KBASE_DEBUG_ASSERT(NULL != kbdev);
lockdep_assert_held(&kbdev->pm.lock);
/* Ensure the clock is on before attempting to access the hardware */
if (!kbdev->pm.backend.gpu_powered) {
if (kbdev->pm.backend.callback_power_on)
kbdev->pm.backend.callback_power_on(kbdev);
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock,
irq_flags);
kbdev->pm.backend.gpu_powered = true;
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock,
irq_flags);
}
/* Ensure interrupts are off to begin with, this also clears any
* outstanding interrupts */
kbase_pm_disable_interrupts(kbdev);
/* Ensure cache snoops are disabled before reset. */
kbase_pm_cache_snoop_disable(kbdev);
/* Prepare for the soft-reset */
kbdev->pm.backend.reset_done = false;
/* The cores should be made unavailable due to the reset */
spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags);
if (kbdev->shader_available_bitmap != 0u)
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL,
NULL, 0u, (u32)0u);
if (kbdev->tiler_available_bitmap != 0u)
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER,
NULL, NULL, 0u, (u32)0u);
kbdev->shader_available_bitmap = 0u;
kbdev->tiler_available_bitmap = 0u;
kbdev->l2_available_bitmap = 0u;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags);
/* Soft reset the GPU */
if (kbdev->protected_mode_support)
err = kbdev->protected_ops->protected_mode_disable(
kbdev->protected_dev);
else
err = kbase_pm_do_reset(kbdev);
spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags);
if (kbdev->protected_mode)
resume_vinstr = true;
kbdev->protected_mode = false;
kbase_ipa_model_use_configured_locked(kbdev);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags);
if (err)
goto exit;
if (flags & PM_HW_ISSUES_DETECT)
kbase_pm_hw_issues_detect(kbdev);
kbase_pm_hw_issues_apply(kbdev);
kbase_cache_set_coherency_mode(kbdev, kbdev->system_coherency);
/* Sanity check protected mode was left after reset */
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE)) {
u32 gpu_status = kbase_reg_read(kbdev,
GPU_CONTROL_REG(GPU_STATUS), NULL);
WARN_ON(gpu_status & GPU_STATUS_PROTECTED_MODE_ACTIVE);
}
/* If cycle counter was in use re-enable it, enable_irqs will only be
* false when called from kbase_pm_powerup */
if (kbdev->pm.backend.gpu_cycle_counter_requests &&
(flags & PM_ENABLE_IRQS)) {
/* enable interrupts as the L2 may have to be powered on */
kbase_pm_enable_interrupts(kbdev);
kbase_pm_request_l2_caches(kbdev);
/* Re-enable the counters if we need to */
spin_lock_irqsave(
&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
irq_flags);
if (kbdev->pm.backend.gpu_cycle_counter_requests)
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_CYCLE_COUNT_START, NULL);
spin_unlock_irqrestore(
&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
irq_flags);
spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags);
kbase_pm_release_l2_caches(kbdev);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags);
kbase_pm_disable_interrupts(kbdev);
}
if (flags & PM_ENABLE_IRQS)
kbase_pm_enable_interrupts(kbdev);
exit:
/* If GPU is leaving protected mode resume vinstr operation. */
if (kbdev->vinstr_ctx && resume_vinstr)
kbase_vinstr_resume(kbdev->vinstr_ctx);
return err;
}
/**
* kbase_pm_request_gpu_cycle_counter_do_request - Request cycle counters
*
* Increase the count of cycle counter users and turn the cycle counters on if
* they were previously off
*
* This function is designed to be called by
* kbase_pm_request_gpu_cycle_counter() or
* kbase_pm_request_gpu_cycle_counter_l2_is_on() only
*
* When this function is called the l2 cache must be on and the l2 cache users
* count must have been incremented by a call to (
* kbase_pm_request_l2_caches() or kbase_pm_request_l2_caches_l2_on() )
*
* @kbdev: The kbase device structure of the device
*/
static void
kbase_pm_request_gpu_cycle_counter_do_request(struct kbase_device *kbdev)
{
unsigned long flags;
spin_lock_irqsave(&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
flags);
++kbdev->pm.backend.gpu_cycle_counter_requests;
if (1 == kbdev->pm.backend.gpu_cycle_counter_requests)
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_CYCLE_COUNT_START, NULL);
spin_unlock_irqrestore(
&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
flags);
}
void kbase_pm_request_gpu_cycle_counter(struct kbase_device *kbdev)
{
KBASE_DEBUG_ASSERT(kbdev != NULL);
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered);
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests <
INT_MAX);
kbase_pm_request_l2_caches(kbdev);
kbase_pm_request_gpu_cycle_counter_do_request(kbdev);
}
KBASE_EXPORT_TEST_API(kbase_pm_request_gpu_cycle_counter);
void kbase_pm_request_gpu_cycle_counter_l2_is_on(struct kbase_device *kbdev)
{
KBASE_DEBUG_ASSERT(kbdev != NULL);
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered);
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests <
INT_MAX);
kbase_pm_request_l2_caches_l2_is_on(kbdev);
kbase_pm_request_gpu_cycle_counter_do_request(kbdev);
}
KBASE_EXPORT_TEST_API(kbase_pm_request_gpu_cycle_counter_l2_is_on);
void kbase_pm_release_gpu_cycle_counter_nolock(struct kbase_device *kbdev)
{
unsigned long flags;
KBASE_DEBUG_ASSERT(kbdev != NULL);
lockdep_assert_held(&kbdev->hwaccess_lock);
spin_lock_irqsave(&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
flags);
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests > 0);
--kbdev->pm.backend.gpu_cycle_counter_requests;
if (0 == kbdev->pm.backend.gpu_cycle_counter_requests)
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_CYCLE_COUNT_STOP, NULL);
spin_unlock_irqrestore(
&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
flags);
kbase_pm_release_l2_caches(kbdev);
}
void kbase_pm_release_gpu_cycle_counter(struct kbase_device *kbdev)
{
unsigned long flags;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbase_pm_release_gpu_cycle_counter_nolock(kbdev);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
}
KBASE_EXPORT_TEST_API(kbase_pm_release_gpu_cycle_counter);