diff options
Diffstat (limited to 'drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform')
6 files changed, 948 insertions, 0 deletions
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/default/mali_platform.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/default/mali_platform.c new file mode 100644 index 00000000000..36301a93a2c --- /dev/null +++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/default/mali_platform.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010-2011 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. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_platform.c + * Platform specific Mali driver functions for a default platform + */ +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_platform.h" + + +_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource) +{ + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type) +{ + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_powerdown(u32 cores) +{ + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_powerup(u32 cores) +{ + MALI_SUCCESS; +} + +void mali_gpu_utilization_handler(u32 utilization) +{ +} + +#if MALI_POWER_MGMT_TEST_SUITE +u32 pmu_get_power_up_down_info(void) +{ + return 4095; + +} +#endif diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali-runtimepm/mali_platform.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali-runtimepm/mali_platform.c new file mode 100644 index 00000000000..b8c47094177 --- /dev/null +++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali-runtimepm/mali_platform.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010-2011 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. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_platform.c + * Platform specific Mali driver functions for a default platform + */ +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_platform.h" +#include "mali_pmm.h" + +static int is_run_time = 0; +_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource) +{ + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type) +{ + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_powerdown(u32 cores) +{ + if(is_run_time == 1) + { + _mali_osk_pmm_dev_idle(); + is_run_time =0; + } + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_powerup(u32 cores) +{ + if(is_run_time == 0) + { + _mali_osk_pmm_dev_activate(); + is_run_time = 1; + } + MALI_SUCCESS; +} + +void mali_gpu_utilization_handler(u32 utilization) +{ +} + +#if MALI_POWER_MGMT_TEST_SUITE +u32 pmu_get_power_up_down_info(void) +{ + return 4095; + +} +#endif diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali400-pmu/mali_platform.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali400-pmu/mali_platform.c new file mode 100644 index 00000000000..cf95b8ae09e --- /dev/null +++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali400-pmu/mali_platform.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2010-2011 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. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_platform.c + * Platform specific Mali driver functions for Mali 400 PMU hardware + */ +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_platform.h" + +#if USING_MALI_PMM + +#include "mali_pmm.h" + +/* Internal test on/off */ +#define PMU_TEST 0 + +/** @brief PMU hardware info + */ +typedef struct platform_pmu +{ + u32 reg_base_addr; /**< PMU registers base address */ + u32 reg_size; /**< PMU registers size */ + const char *name; /**< PMU name */ + u32 irq_num; /**< PMU irq number */ + + mali_io_address reg_mapped; /**< IO-mapped pointer to registers */ +} platform_pmu_t; + +static platform_pmu_t *pmu_info = NULL; + +/** @brief Register layout for hardware PMU + */ +typedef enum { + PMU_REG_ADDR_MGMT_POWER_UP = 0x00, /*< Power up register */ + PMU_REG_ADDR_MGMT_POWER_DOWN = 0x04, /*< Power down register */ + PMU_REG_ADDR_MGMT_STATUS = 0x08, /*< Core sleep status register */ + PMU_REG_ADDR_MGMT_INT_MASK = 0x0C, /*< Interrupt mask register */ + PMU_REG_ADDR_MGMT_INT_RAWSTAT = 0x10, /*< Interrupt raw status register */ + PMU_REG_ADDR_MGMT_INT_STAT = 0x14, /*< Interrupt status register */ + PMU_REG_ADDR_MGMT_INT_CLEAR = 0x18, /*< Interrupt clear register */ + PMU_REG_ADDR_MGMT_SW_DELAY = 0x1C, /*< Software delay register */ + PMU_REG_ADDR_MGMT_MASTER_PWR_UP = 0x24, /*< Master power up register */ + PMU_REGISTER_ADDRESS_SPACE_SIZE = 0x28, /*< Size of register space */ +} pmu_reg_addr_mgmt_addr; + +/* Internal functions */ +u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address); +void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val); +mali_pmm_core_mask pmu_translate_cores_to_pmu(mali_pmm_core_mask cores); +#if PMU_TEST +void pmm_pmu_dump_regs( platform_pmu_t *pmu ); +void pmm_pmu_test( platform_pmu_t *pmu, u32 cores ); +#endif + +#endif /* USING_MALI_PMM */ + + +_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource) +{ +#if USING_MALI_PMM + if( resource == NULL ) + { + /* Nothing to set up for the system */ + } + else if( resource->type == PMU ) + { + if( (resource->base == 0) || + (resource->description == NULL) ) + { + /* NOTE: We currently don't care about any other resource settings */ + MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Missing PMU set up information\n")); + MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + } + + MALI_DEBUG_ASSERT( pmu_info == NULL ); + pmu_info = (platform_pmu_t *)_mali_osk_malloc(sizeof(*pmu_info)); + MALI_CHECK_NON_NULL( pmu_info, _MALI_OSK_ERR_NOMEM ); + + /* All values get 0 as default */ + _mali_osk_memset(pmu_info, 0, sizeof(*pmu_info)); + + pmu_info->reg_base_addr = resource->base; + pmu_info->reg_size = (u32)PMU_REGISTER_ADDRESS_SPACE_SIZE; + pmu_info->name = resource->description; + pmu_info->irq_num = resource->irq; + + if( _MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name) ) + { + MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not request register region (0x%08X - 0x%08X) for %s\n", + pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name)); + goto cleanup; + } + else + { + MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: request_mem_region: (0x%08X - 0x%08X) for %s\n", + pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name)); + } + + pmu_info->reg_mapped = _mali_osk_mem_mapioregion( pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name ); + + if( 0 == pmu_info->reg_mapped ) + { + MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not ioremap registers for %s .\n", pmu_info->name)); + _mali_osk_mem_unreqregion( pmu_info->reg_base_addr, pmu_info->reg_size ); + goto cleanup; + } + else + { + MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: ioremap_nocache: Internal ptr: (0x%08X - 0x%08X) for %s\n", + (u32) pmu_info->reg_mapped, + ((u32)pmu_info->reg_mapped)+ pmu_info->reg_size - 1, + pmu_info->name)); + } + + MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: Mapping registers to %s\n", pmu_info->name)); + +#if PMU_TEST + pmu_test(pmu_info, (MALI_PMM_CORE_GP)); + pmu_test(pmu_info, (MALI_PMM_CORE_GP|MALI_PMM_CORE_L2|MALI_PMM_CORE_PP0)); +#endif + + MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Initialized - %s\n", pmu_info->name) ); + } + else + { + /* Didn't expect a different resource */ + MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + } + + MALI_SUCCESS; + +cleanup: + _mali_osk_free(pmu_info); + pmu_info = NULL; + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + +#else + /* Nothing to do when not using PMM - as mali already on */ + MALI_SUCCESS; +#endif + +} + +_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type) +{ +#if USING_MALI_PMM + if( type == NULL ) + { + /* Nothing to tear down for the system */ + } + else if (*type == PMU) + { + if( pmu_info ) + { + _mali_osk_mem_unmapioregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->reg_mapped); + _mali_osk_mem_unreqregion(pmu_info->reg_base_addr, pmu_info->reg_size); + _mali_osk_free(pmu_info); + pmu_info = NULL; + + MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Terminated PMU\n") ); + } + } + else + { + /* Didn't expect a different resource */ + MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + } + + MALI_SUCCESS; + +#else + /* Nothing to do when not using PMM */ + MALI_SUCCESS; +#endif +} + +_mali_osk_errcode_t mali_platform_powerdown(u32 cores) +{ +#if USING_MALI_PMM + u32 stat; + u32 timeout; + u32 cores_pmu; + + MALI_DEBUG_ASSERT_POINTER(pmu_info); + MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */ + MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power down (0x%x)\n", cores) ); + + cores_pmu = pmu_translate_cores_to_pmu(cores); + pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_DOWN, cores_pmu ); + + /* Wait for cores to be powered down */ + timeout = 10; /* 10ms */ + do + { + /* Get status of sleeping cores */ + stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS ); + stat &= cores_pmu; + if( stat == cores_pmu ) break; /* All cores we wanted are now asleep */ + _mali_osk_time_ubusydelay(1000); /* 1ms */ + timeout--; + } while( timeout > 0 ); + + if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT); + + MALI_SUCCESS; + +#else + /* Nothing to do when not using PMM */ + MALI_SUCCESS; +#endif +} + +_mali_osk_errcode_t mali_platform_powerup(u32 cores) +{ +#if USING_MALI_PMM + u32 cores_pmu; + u32 stat; + u32 timeout; + + MALI_DEBUG_ASSERT_POINTER(pmu_info); + MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */ + MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power up (0x%x)\n", cores) ); + + /* Don't use interrupts - just poll status */ + pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_INT_MASK, 0 ); + cores_pmu = pmu_translate_cores_to_pmu(cores); + pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_UP, cores_pmu ); + + timeout = 10; /* 10ms */ + do + { + /* Get status of sleeping cores */ + stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS ); + stat &= cores_pmu; + if( stat == 0 ) break; /* All cores we wanted are now awake */ + _mali_osk_time_ubusydelay(1000); /* 1ms */ + timeout--; + } while( timeout > 0 ); + + if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT); + + MALI_SUCCESS; + +#else + /* Nothing to do when not using PMM */ + MALI_SUCCESS; +#endif +} + +void mali_gpu_utilization_handler(u32 utilization) +{ +} + +#if USING_MALI_PMM + +/***** INTERNAL *****/ + +/** @brief Internal PMU function to translate the cores bit mask + * into something the hardware PMU understands + * + * @param cores PMM cores bitmask + * @return PMU hardware cores bitmask + */ +u32 pmu_translate_cores_to_pmu(mali_pmm_core_mask cores) +{ + /* For Mali 400 PMU the cores mask is already the same as what + * the hardware PMU expects. + * For other hardware, some translation can be done here, by + * translating the MALI_PMM_CORE_* bits into specific hardware + * bits + */ + return cores; +} + +/** @brief Internal PMU function to read a PMU register + * + * @param pmu handle that identifies the PMU hardware + * @param relative_address relative PMU hardware address to read from + * @return 32-bit value that was read from the address + */ +u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address) +{ + u32 read_val; + + MALI_DEBUG_ASSERT_POINTER(pmu); + MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); + MALI_DEBUG_ASSERT(relative_address < pmu->reg_size); + + read_val = _mali_osk_mem_ioread32(pmu->reg_mapped, relative_address); + + MALI_DEBUG_PRINT( 5, ("PMU: reg_read: %s Addr:0x%04X Val:0x%08x\n", + pmu->name, relative_address, read_val)); + + return read_val; +} + +/** @brief Internal PMU function to write to a PMU register + * + * @param pmu handle that identifies the PMU hardware + * @param relative_address relative PMU hardware address to write to + * @param new_val new 32-bit value to write into the address + */ +void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val) +{ + MALI_DEBUG_ASSERT_POINTER(pmu); + MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); + MALI_DEBUG_ASSERT(relative_address < pmu->reg_size); + + MALI_DEBUG_PRINT( 5, ("PMU: reg_write: %s Addr:0x%04X Val:0x%08x\n", + pmu->name, relative_address, new_val)); + + _mali_osk_mem_iowrite32(pmu->reg_mapped, relative_address, new_val); +} + +#if MALI_POWER_MGMT_TEST_SUITE + +u32 pmu_get_power_up_down_info(void) +{ + return pmu_reg_read(pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS); +} + +#endif /* MALI_POWER_MGMT_TEST_SUITE */ + +#endif /* USING_MALI_PMM */ + + +#if USING_MALI_PMM && PMU_TEST + +/***** TEST *****/ + +void pmu_dump_regs( platform_pmu_t *pmu ) +{ + u32 addr; + for( addr = 0x0; addr < PMU_REGISTER_ADDRESS_SPACE_SIZE; addr += 0x4 ) + { + MALI_PRINT( ("PMU_REG: 0x%08x: 0x%04x\n", (addr + pmu->reg_base_addr), pmu_reg_read( pmu, addr ) ) ); + } +} + +/* This function is an internal test for the PMU without any Mali h/w interaction */ +void pmu_test( platform_pmu_t *pmu, u32 cores ) +{ + u32 stat; + u32 timeout; + + MALI_PRINT( ("PMU_TEST: Start\n") ); + + pmu_dump_regs( pmu ); + + MALI_PRINT( ("PMU_TEST: Power down cores: 0x%x\n", cores) ); + _mali_pmm_pmu_power_down( pmu, cores, MALI_TRUE ); + + stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS ); + MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == cores ? "SUCCESS" : "FAIL" ) ); + + pmu_dump_regs( pmu ); + + MALI_PRINT( ("PMU_TEST: Power up cores: 0x%x\n", cores) ); + _mali_pmm_pmu_power_up( pmu, cores, MALI_FALSE ); + + MALI_PRINT( ("PMU_TEST: Waiting for power up...\n") ); + timeout = 1000; /* 1 sec */ + while( !_mali_pmm_pmu_irq_power_up(pmu) && timeout > 0 ) + { + _mali_osk_time_ubusydelay(1000); /* 1ms */ + timeout--; + } + + MALI_PRINT( ("PMU_TEST: Waited %dms for interrupt\n", (1000-timeout)) ); + stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS ); + MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == 0 ? "SUCCESS" : "FAIL" ) ); + + _mali_pmm_pmu_irq_power_up_clear(pmu); + + pmu_dump_regs( pmu ); + + MALI_PRINT( ("PMU_TEST: Finish\n") ); +} +#endif /* USING_MALI_PMM && PMU_TEST */ diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali_platform.h b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali_platform.h new file mode 100644 index 00000000000..575c1fb6113 --- /dev/null +++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/mali_platform.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010-2011 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. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_platform.h + * Platform specific Mali driver functions + */ + +#include "mali_osk.h" + +#if USING_MALI_PMM +#include "mali_pmm.h" +#endif + +#if !USING_MALI_PMM +/* @brief System power up/down cores that can be passed into mali_platform_powerdown/up() */ +#define MALI_PLATFORM_SYSTEM 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Platform specific setup and initialisation of MALI + * + * This is called from the entrypoint of the driver to initialize the platform + * When using PMM, it is also called from the PMM start up to initialise the + * system PMU + * + * @param resource This is NULL when called on first driver start up, else it will + * be a pointer to a PMU resource + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource); + +/** @brief Platform specific deinitialisation of MALI + * + * This is called on the exit of the driver to terminate the platform + * When using PMM, it is also called from the PMM termination code to clean up the + * system PMU + * + * @param type This is NULL when called on driver exit, else it will + * be a pointer to a PMU resource type (not the full resource) + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type); + +/** @brief Platform specific powerdown sequence of MALI + * + * Called as part of platform init if there is no PMM support, else the + * PMM will call it. + * + * @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will + * be a mask of cores to power down based on the mali_pmm_core_id enum + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_platform_powerdown(u32 cores); + +/** @brief Platform specific powerup sequence of MALI + * + * Called as part of platform deinit if there is no PMM support, else the + * PMM will call it. + * + * @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will + * be a mask of cores to power down based on the mali_pmm_core_id enum + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_platform_powerup(u32 cores); + +/** @brief Platform specific handling of GPU utilization data + * + * When GPU utilization data is enabled, this function will be + * periodically called. + * + * @param utilization The workload utilization of the Mali GPU. 0 = no utilization, 256 = full utilization. + */ +void mali_gpu_utilization_handler(u32 utilization); + +#if USING_MALI_PMM +#if MALI_POWER_MGMT_TEST_SUITE +/** @brief function to get status of individual cores + * + * This function is used by power management test suite to get the status of powered up/down the number + * of cores + * @param utilization The workload utilization of the Mali GPU. 0 = no utilization, 256 = full utilization. + */ +u32 pmu_get_power_up_down_info(void); +#endif +#endif + +#ifdef __cplusplus +} +#endif diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/ux500/mali_platform.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/ux500/mali_platform.c new file mode 100644 index 00000000000..481e6e76c54 --- /dev/null +++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/ux500/mali_platform.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Mali related Ux500 platform initialization + * + * Author: Marta Lofstedt <marta.lofstedt@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL) version 2. + */ + +/** + * @file mali_platform.c + * Platform specific Mali driver functions for ST-Ericsson's Ux500 platforms + */ +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_platform.h" + +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/workqueue.h> + +#include <linux/mfd/dbx500-prcmu.h> + +#define MALI_HIGH_TO_LOW_LEVEL_UTILIZATION_LIMIT 64 +#define MALI_LOW_TO_HIGH_LEVEL_UTILIZATION_LIMIT 192 + +static int is_running; +static struct regulator *regulator; +static struct clk *clk_sga; +static u32 last_utilization; +static struct work_struct mali_utilization_work; +static struct workqueue_struct *mali_utilization_workqueue; + +/* Rationale behind the values for: +* MALI_HIGH_LEVEL_UTILIZATION_LIMIT and MALI_LOW_LEVEL_UTILIZATION_LIMIT +* When operating at half clock frequency a faster clock is requested when +* reaching 75% utilization. When operating at full clock frequency a slower +* clock is requested when reaching 25% utilization. There is a margin of 25% +* at the high range of the slow clock to avoid complete saturation of the +* hardware and there is some overlap to avoid an oscillating situation where +* the clock goes back and forth from high to low. +* +* Utilization on full speed clock +* 0 64 128 192 255 +* |---------------|---------------|---------------|---------------| +* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +* | ^ +* V | +* XXXXXXXXXXXXXXXXXXXXXXXXX +* 0 64 128 192 255 +* |-------|-------|-------|-------| +* Utilization on half speed clock +*/ +void mali_utilization_function(struct work_struct *ptr) +{ + /*By default, platform start with 50% APE OPP and 25% DDR OPP*/ + static u32 has_requested_low = 1; + + if (last_utilization > MALI_LOW_TO_HIGH_LEVEL_UTILIZATION_LIMIT) { + if (has_requested_low) { + MALI_DEBUG_PRINT(5, ("MALI GPU utilization: %u SIGNAL_HIGH\n", last_utilization)); + /*Request 100% APE_OPP.*/ + if (prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, "mali", 100)) { + MALI_DEBUG_PRINT(2, ("MALI 100% APE_OPP failed\n")); + return; + } + /* + * Since the utilization values will be reported higher + * if DDR_OPP is lowered, we also request 100% DDR_OPP. + */ + if (prcmu_qos_add_requirement(PRCMU_QOS_DDR_OPP, "mali", 100)) { + MALI_DEBUG_PRINT(2, ("MALI 100% DDR_OPP failed\n")); + return; + } + has_requested_low = 0; + } + } else { + if (last_utilization < MALI_HIGH_TO_LOW_LEVEL_UTILIZATION_LIMIT) { + if (!has_requested_low) { + /*Remove APE_OPP and DDR_OPP requests*/ + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "mali"); + prcmu_qos_remove_requirement(PRCMU_QOS_DDR_OPP, "mali"); + MALI_DEBUG_PRINT(5, ("MALI GPU utilization: %u SIGNAL_LOW\n", last_utilization)); + has_requested_low = 1; + } + } + } + MALI_DEBUG_PRINT(5, ("MALI GPU utilization: %u\n", last_utilization)); +} + +_mali_osk_errcode_t mali_platform_init(_mali_osk_resource_t *resource) +{ + is_running = 0; + last_utilization = 0; + + mali_utilization_workqueue = create_singlethread_workqueue("mali_utilization_workqueue"); + if (NULL == mali_utilization_workqueue) { + MALI_DEBUG_PRINT(2, ("%s: Failed to setup workqueue %s\n", __func__, "v-mali")); + goto error; + } + INIT_WORK(&mali_utilization_work, mali_utilization_function); + + regulator = regulator_get(NULL, "v-mali"); + if (IS_ERR(regulator)) { + MALI_DEBUG_PRINT(2, ("%s: Failed to get regulator %s\n", __func__, "v-mali")); + goto error; + } + + clk_sga = clk_get_sys("mali", NULL); + if (IS_ERR(clk_sga)) { + regulator_put(regulator); + MALI_DEBUG_PRINT(2, ("%s: Failed to get clock %s\n", __func__, "mali")); + goto error; + } + + MALI_SUCCESS; +error: + MALI_DEBUG_PRINT(1, ("SGA initialization failed.\n")); + MALI_ERROR(_MALI_OSK_ERR_FAULT); +} + +_mali_osk_errcode_t mali_platform_deinit(_mali_osk_resource_type_t *type) +{ + destroy_workqueue(mali_utilization_workqueue); + regulator_put(regulator); + clk_put(clk_sga); + MALI_DEBUG_PRINT(2, ("SGA terminated.\n")); + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_powerdown(u32 cores) +{ + if (is_running) { + clk_disable(clk_sga); + if (regulator) { + int ret = regulator_disable(regulator); + if (ret < 0) { + MALI_DEBUG_PRINT(2, ("%s: Failed to disable regulator %s\n", __func__, "v-mali")); + is_running = 0; + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + } + is_running = 0; + } + MALI_DEBUG_PRINT(4, ("mali_platform_powerdown is_running: %u cores: %u\n", is_running, cores)); + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_powerup(u32 cores) +{ + if (!is_running) { + int ret = regulator_enable(regulator); + if (ret < 0) { + MALI_DEBUG_PRINT(2, ("%s: Failed to enable regulator %s\n", __func__, "v-mali")); + goto error; + } + + ret = clk_enable(clk_sga); + if (ret < 0) { + regulator_disable(regulator); + MALI_DEBUG_PRINT(2, ("%s: Failed to enable clock %s\n", __func__, "mali")); + goto error; + } + is_running = 1; + } + MALI_DEBUG_PRINT(4, ("mali_platform_powerup is_running:%u cores: %u\n", is_running, cores)); + MALI_SUCCESS; +error: + MALI_DEBUG_PRINT(1, ("Failed to power up.\n")); + MALI_ERROR(_MALI_OSK_ERR_FAULT); +} + +void mali_gpu_utilization_handler(u32 utilization) +{ + last_utilization = utilization; + /* + * We should not cancel the potentially not yet run old work + * in favor of a new work. + * Since the utilization value will change, + * the mali_utilization_function will evaluate based on + * what is the utilization now and not on what it was + * when it was scheduled. + */ + queue_work(mali_utilization_workqueue, &mali_utilization_work); +} + + diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/ux500/ump_kernel_api_hwmem.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/ux500/ump_kernel_api_hwmem.c new file mode 100644 index 00000000000..b321b504839 --- /dev/null +++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/platform/ux500/ump_kernel_api_hwmem.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * Author: Magnus Wendt <magnus.wendt@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +#include "ump_kernel_types.h" +#include "mali_kernel_common.h" + +#include <linux/hwmem.h> +#include <linux/err.h> + + +/* The UMP kernel API for hwmem has been mapped so that + * ump_dd_handle == hwmem_alloc + * ump_secure_id == hwmem global name + * + * The current implementation is limited to contiguous memory + */ + +ump_secure_id ump_dd_secure_id_get(ump_dd_handle memh) +{ + int hwmem_name = hwmem_get_name((struct hwmem_alloc *) memh); + + if (unlikely(hwmem_name < 0)) { + MALI_DEBUG_PRINT(1, ("%s: Invalid Alloc 0x%x\n",__func__, memh)); + return UMP_INVALID_SECURE_ID; + } + + return (ump_secure_id)hwmem_name; +} + + + +ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id) +{ + struct hwmem_alloc *alloc; + enum hwmem_mem_type mem_type; + enum hwmem_access access; + + alloc = hwmem_resolve_by_name((int) secure_id); + + if (IS_ERR(alloc)) { + MALI_DEBUG_PRINT(1, ("%s: Invalid UMP id %d\n",__func__, secure_id)); + return UMP_DD_HANDLE_INVALID; + } + + hwmem_get_info(alloc, NULL, &mem_type, &access); + + if (unlikely((access & (HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE | HWMEM_ACCESS_IMPORT)) != + (HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE | HWMEM_ACCESS_IMPORT))) { + MALI_DEBUG_PRINT(1, ("%s: Access denied on UMP id %d, (access==%d)\n", + __func__, secure_id, access)); + hwmem_release(alloc); + return UMP_DD_HANDLE_INVALID; + } + + if (unlikely(HWMEM_MEM_CONTIGUOUS_SYS != mem_type)) { + MALI_DEBUG_PRINT(1, ("%s: UMP id %d is non-contiguous! (not supported)\n", + __func__, secure_id)); + hwmem_release(alloc); + return UMP_DD_HANDLE_INVALID; + } + + return (ump_dd_handle)alloc; +} + + + +unsigned long ump_dd_phys_block_count_get(ump_dd_handle memh) +{ + return 1; +} + + + +ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle memh, + ump_dd_physical_block * blocks, + unsigned long num_blocks) +{ + struct hwmem_mem_chunk hwmem_mem_chunk; + size_t hwmem_mem_chunk_length = 1; + + int hwmem_result; + struct hwmem_alloc *alloc = (struct hwmem_alloc *)memh; + + if (unlikely(blocks == NULL)) { + MALI_DEBUG_PRINT(1, ("%s: blocks == NULL\n",__func__)); + return UMP_DD_INVALID; + } + + if (unlikely(1 != num_blocks)) { + MALI_DEBUG_PRINT(1, ("%s: num_blocks == %d (!= 1)\n",__func__, num_blocks)); + return UMP_DD_INVALID; + } + + MALI_DEBUG_PRINT(5, ("Returning physical block information. Alloc: 0x%x\n", memh)); + + /* It might not look natural to pin here, but it matches the usage by the mali kernel module */ + hwmem_result = hwmem_pin(alloc, &hwmem_mem_chunk, &hwmem_mem_chunk_length); + + if (unlikely(hwmem_result < 0)) { + MALI_DEBUG_PRINT(1, ("%s: Pin failed. Alloc: 0x%x\n",__func__, memh)); + return UMP_DD_INVALID; + } + + blocks[0].addr = hwmem_mem_chunk.paddr; + blocks[0].size = hwmem_mem_chunk.size; + + hwmem_set_domain(alloc, HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE, + HWMEM_DOMAIN_SYNC, NULL); + + return UMP_DD_SUCCESS; +} + + + +ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle memh, + unsigned long index, + ump_dd_physical_block * block) +{ + if (unlikely(0 != index)) { + MALI_DEBUG_PRINT(1, ("%s: index == %d (!= 0)\n",__func__, index)); + return UMP_DD_INVALID; + } + return ump_dd_phys_blocks_get(memh, block, 1); +} + + + +unsigned long ump_dd_size_get(ump_dd_handle memh) +{ + struct hwmem_alloc *alloc = (struct hwmem_alloc *)memh; + int size; + + hwmem_get_info(alloc, &size, NULL, NULL); + + return size; +} + + + +void ump_dd_reference_add(ump_dd_handle memh) +{ + /* This is never called from tha mali kernel driver */ +} + + + +void ump_dd_reference_release(ump_dd_handle memh) +{ + struct hwmem_alloc *alloc = (struct hwmem_alloc *)memh; + + hwmem_unpin(alloc); + hwmem_release(alloc); + + return; +} |