diff options
Diffstat (limited to 'drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c')
-rwxr-xr-x | drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c new file mode 100755 index 000000000000..4665f98cbbe4 --- /dev/null +++ b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c @@ -0,0 +1,279 @@ +/* + * + * (C) COPYRIGHT 2011-2016 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. + * + */ + + + +#include <linux/io.h> +#include <mali_kbase.h> +#include "mali_kbase_cpu_vexpress.h" + +#define HZ_IN_MHZ (1000000) + +#define CORETILE_EXPRESS_A9X4_SCC_START (0x100E2000) +#define MOTHERBOARD_SYS_CFG_START (0x10000000) +#define SYS_CFGDATA_OFFSET (0x000000A0) +#define SYS_CFGCTRL_OFFSET (0x000000A4) +#define SYS_CFGSTAT_OFFSET (0x000000A8) + +#define SYS_CFGCTRL_START_BIT_VALUE (1 << 31) +#define READ_REG_BIT_VALUE (0 << 30) +#define DCC_DEFAULT_BIT_VALUE (0 << 26) +#define SYS_CFG_OSC_FUNC_BIT_VALUE (1 << 20) +#define SITE_DEFAULT_BIT_VALUE (1 << 16) +#define BOARD_STACK_POS_DEFAULT_BIT_VALUE (0 << 12) +#define DEVICE_DEFAULT_BIT_VALUE (2 << 0) +#define SYS_CFG_COMPLETE_BIT_VALUE (1 << 0) +#define SYS_CFG_ERROR_BIT_VALUE (1 << 1) + +#define FEED_REG_BIT_MASK (0x0F) +#define FCLK_PA_DIVIDE_BIT_SHIFT (0x03) +#define FCLK_PB_DIVIDE_BIT_SHIFT (0x07) +#define FCLK_PC_DIVIDE_BIT_SHIFT (0x0B) +#define AXICLK_PA_DIVIDE_BIT_SHIFT (0x0F) +#define AXICLK_PB_DIVIDE_BIT_SHIFT (0x13) + +/* the following three values used for reading + * HBI value of the LogicTile daughterboard */ +#define VE_MOTHERBOARD_PERIPHERALS_SMB_CS7 (0x10000000) +#define VE_SYS_PROC_ID1_OFFSET (0x00000088) +#define VE_LOGIC_TILE_HBI_MASK (0x00000FFF) + +#define IS_SINGLE_BIT_SET(val, pos) (val&(1<<pos)) + +/** + * Values used for determining the GPU frequency based on the LogicTile type + * Used by the function kbase_get_platform_logic_tile_type + */ +#define VE_VIRTEX6_GPU_FREQ_MIN 5000 +#define VE_VIRTEX6_GPU_FREQ_MAX 5000 +#define VE_VIRTEX7_GPU_FREQ_MIN 40000 +#define VE_VIRTEX7_GPU_FREQ_MAX 40000 +#define VE_DEFAULT_GPU_FREQ_MIN 5000 +#define VE_DEFAULT_GPU_FREQ_MAX 5000 + + +#define CPU_CLOCK_SPEED_UNDEFINED (0) + +static u32 cpu_clock_speed = CPU_CLOCK_SPEED_UNDEFINED; + +static DEFINE_RAW_SPINLOCK(syscfg_lock); +/** + * kbase_get_vendor_specific_cpu_clock_speed -Retrieves the CPU clock speed + * @cpu_clock - the value of CPU clock speed in MHz + * + * Returns 0 on success, error code otherwise. + * + * The implementation is platform specific. +*/ +int kbase_get_vexpress_cpu_clock_speed(u32 *cpu_clock) +{ + int err = 0; + u32 reg_val = 0; + u32 osc2_value = 0; + u32 pa_divide = 0; + u32 pb_divide = 0; + u32 pc_divide = 0; + void __iomem *syscfg_reg = NULL; + void __iomem *scc_reg = NULL; + + if (CPU_CLOCK_SPEED_UNDEFINED != cpu_clock_speed) { + *cpu_clock = cpu_clock_speed; + return 0; + } + + /* Init the value in case something goes wrong */ + *cpu_clock = 0; + + /* Map CPU register into virtual memory */ + syscfg_reg = ioremap(MOTHERBOARD_SYS_CFG_START, 0x1000); + if (syscfg_reg == NULL) { + err = -EIO; + goto syscfg_reg_map_failed; + } + + scc_reg = ioremap(CORETILE_EXPRESS_A9X4_SCC_START, 0x1000); + if (scc_reg == NULL) { + err = -EIO; + goto scc_reg_map_failed; + } + + raw_spin_lock(&syscfg_lock); + + /* Read SYS regs - OSC2 */ + reg_val = readl(syscfg_reg + SYS_CFGCTRL_OFFSET); + + /* Check if there is any other undergoing request */ + if (reg_val & SYS_CFGCTRL_START_BIT_VALUE) { + err = -EBUSY; + goto ongoing_request; + } + /* Reset the CGFGSTAT reg */ + writel(0, (syscfg_reg + SYS_CFGSTAT_OFFSET)); + + writel(SYS_CFGCTRL_START_BIT_VALUE | READ_REG_BIT_VALUE | + DCC_DEFAULT_BIT_VALUE | + SYS_CFG_OSC_FUNC_BIT_VALUE | + SITE_DEFAULT_BIT_VALUE | + BOARD_STACK_POS_DEFAULT_BIT_VALUE | + DEVICE_DEFAULT_BIT_VALUE, + (syscfg_reg + SYS_CFGCTRL_OFFSET)); + /* Wait for the transaction to complete */ + while (!(readl(syscfg_reg + SYS_CFGSTAT_OFFSET) & + SYS_CFG_COMPLETE_BIT_VALUE)) + ; + /* Read SYS_CFGSTAT Register to get the status of submitted + * transaction */ + reg_val = readl(syscfg_reg + SYS_CFGSTAT_OFFSET); + + if (reg_val & SYS_CFG_ERROR_BIT_VALUE) { + /* Error while setting register */ + err = -EIO; + goto set_reg_error; + } + + osc2_value = readl(syscfg_reg + SYS_CFGDATA_OFFSET); + /* Read the SCC CFGRW0 register */ + reg_val = readl(scc_reg); + + /* + * Select the appropriate feed: + * CFGRW0[0] - CLKOB + * CFGRW0[1] - CLKOC + * CFGRW0[2] - FACLK (CLK)B FROM AXICLK PLL) + */ + /* Calculate the FCLK */ + if (IS_SINGLE_BIT_SET(reg_val, 0)) { + /* CFGRW0[0] - CLKOB */ + /* CFGRW0[6:3] */ + pa_divide = ((reg_val & (FEED_REG_BIT_MASK << + FCLK_PA_DIVIDE_BIT_SHIFT)) >> + FCLK_PA_DIVIDE_BIT_SHIFT); + /* CFGRW0[10:7] */ + pb_divide = ((reg_val & (FEED_REG_BIT_MASK << + FCLK_PB_DIVIDE_BIT_SHIFT)) >> + FCLK_PB_DIVIDE_BIT_SHIFT); + *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide + 1); + } else if (IS_SINGLE_BIT_SET(reg_val, 1)) { + /* CFGRW0[1] - CLKOC */ + /* CFGRW0[6:3] */ + pa_divide = ((reg_val & (FEED_REG_BIT_MASK << + FCLK_PA_DIVIDE_BIT_SHIFT)) >> + FCLK_PA_DIVIDE_BIT_SHIFT); + /* CFGRW0[14:11] */ + pc_divide = ((reg_val & (FEED_REG_BIT_MASK << + FCLK_PC_DIVIDE_BIT_SHIFT)) >> + FCLK_PC_DIVIDE_BIT_SHIFT); + *cpu_clock = osc2_value * (pa_divide + 1) / (pc_divide + 1); + } else if (IS_SINGLE_BIT_SET(reg_val, 2)) { + /* CFGRW0[2] - FACLK */ + /* CFGRW0[18:15] */ + pa_divide = ((reg_val & (FEED_REG_BIT_MASK << + AXICLK_PA_DIVIDE_BIT_SHIFT)) >> + AXICLK_PA_DIVIDE_BIT_SHIFT); + /* CFGRW0[22:19] */ + pb_divide = ((reg_val & (FEED_REG_BIT_MASK << + AXICLK_PB_DIVIDE_BIT_SHIFT)) >> + AXICLK_PB_DIVIDE_BIT_SHIFT); + *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide + 1); + } else { + err = -EIO; + } + +set_reg_error: +ongoing_request: + raw_spin_unlock(&syscfg_lock); + *cpu_clock /= HZ_IN_MHZ; + + if (!err) + cpu_clock_speed = *cpu_clock; + + iounmap(scc_reg); + +scc_reg_map_failed: + iounmap(syscfg_reg); + +syscfg_reg_map_failed: + + return err; +} + +/** + * kbase_get_platform_logic_tile_type - determines which LogicTile type + * is used by Versatile Express + * + * When platform_config build parameter is specified as vexpress, i.e., + * platform_config=vexpress, GPU frequency may vary dependent on the + * particular platform. The GPU frequency depends on the LogicTile type. + * + * This function determines which LogicTile type is used by the platform by + * reading the HBI value of the daughterboard which holds the LogicTile: + * + * 0x217 HBI0217 Virtex-6 + * 0x192 HBI0192 Virtex-5 + * 0x247 HBI0247 Virtex-7 + * + * Return: HBI value of the logic tile daughterboard, zero if not accessible + */ +static u32 kbase_get_platform_logic_tile_type(void) +{ + void __iomem *syscfg_reg = NULL; + u32 sys_procid1 = 0; + + syscfg_reg = ioremap(VE_MOTHERBOARD_PERIPHERALS_SMB_CS7 + VE_SYS_PROC_ID1_OFFSET, 4); + if (NULL != syscfg_reg) { + sys_procid1 = readl(syscfg_reg); + iounmap(syscfg_reg); + } + + return sys_procid1 & VE_LOGIC_TILE_HBI_MASK; +} + +u32 kbase_get_platform_min_freq(void) +{ + u32 ve_logic_tile = kbase_get_platform_logic_tile_type(); + + switch (ve_logic_tile) { + case 0x217: + /* Virtex 6, HBI0217 */ + return VE_VIRTEX6_GPU_FREQ_MIN; + case 0x247: + /* Virtex 7, HBI0247 */ + return VE_VIRTEX7_GPU_FREQ_MIN; + default: + /* all other logic tiles, i.e., Virtex 5 HBI0192 + * or unsuccessful reading from the platform - + * fall back to some default value */ + return VE_DEFAULT_GPU_FREQ_MIN; + } +} + +u32 kbase_get_platform_max_freq(void) +{ + u32 ve_logic_tile = kbase_get_platform_logic_tile_type(); + + switch (ve_logic_tile) { + case 0x217: + /* Virtex 6, HBI0217 */ + return VE_VIRTEX6_GPU_FREQ_MAX; + case 0x247: + /* Virtex 7, HBI0247 */ + return VE_VIRTEX7_GPU_FREQ_MAX; + default: + /* all other logic tiles, i.e., Virtex 5 HBI0192 + * or unsuccessful reading from the platform - + * fall back to some default value */ + return VE_DEFAULT_GPU_FREQ_MAX; + } +} |