mali_760_driver : rk_ext on arm_release_ver, from r5p0-02dev0.

This commit is contained in:
chenzhen
2014-12-15 14:43:41 +08:00
parent 4599043e5e
commit 4b2e73b447
17 changed files with 2298 additions and 14 deletions

View File

@@ -105,7 +105,6 @@ SRC := \
mali_kbase_utility.c \
mali_kbase_debug.c \
mali_kbase_trace_timeline.c \
mali_kbase_gpu_memory_debugfs.c \
mali_kbase_mem_linux.c \
mali_kbase_core_linux.c \
mali_kbase_sync.c \
@@ -116,6 +115,10 @@ SRC := \
mali_kbase_disjoint_events.c \
mali_kbase_gator_api.c
ifeq ($(CONFIG_DEBUG_FS),y)
SRC += mali_kbase_gpu_memory_debugfs.c
endif
ifeq ($(MALI_CUSTOMER_RELEASE),0)
SRC += \
mali_kbase_pm_ca_random.c \

View File

@@ -26,7 +26,6 @@
#define _KBASE_CONFIG_DEFAULTS_H_
/* Include mandatory definitions per platform */
#include <mali_kbase_config_platform.h>
/**
* Irq throttle. It is the minimum desired time in between two
@@ -37,7 +36,8 @@
* Attached value: number in micro seconds
*/
#define DEFAULT_IRQ_THROTTLE_TIME_US 20
#define GPU_FREQ_KHZ_MAX 500000
#define GPU_FREQ_KHZ_MIN 100000
/*** Begin Scheduling defaults ***/
/**

View File

@@ -98,6 +98,7 @@ EXPORT_SYMBOL(shared_kernel_test_data);
#endif /* MALI_UNIT_TEST */
#define KBASE_DRV_NAME "mali"
#define ROCKCHIP_VERSION 0x0b
static const char kbase_drv_name[] = KBASE_DRV_NAME;
@@ -748,6 +749,7 @@ copy_failed:
/* version buffer size check is made in compile time assert */
memcpy(get_version->version_buffer, KERNEL_SIDE_DDK_VERSION_STRING, sizeof(KERNEL_SIDE_DDK_VERSION_STRING));
get_version->version_string_size = sizeof(KERNEL_SIDE_DDK_VERSION_STRING);
get_version->rk_version = ROCKCHIP_VERSION;
break;
}
@@ -2846,7 +2848,6 @@ static int kbase_platform_device_probe(struct platform_device *pdev)
mali_error mali_err;
#endif /* CONFIG_MALI_NO_MALI */
#ifdef CONFIG_OF
#ifdef CONFIG_MALI_PLATFORM_FAKE
struct kbase_platform_config *config;
int attribute_count;
@@ -2857,7 +2858,6 @@ static int kbase_platform_device_probe(struct platform_device *pdev)
attribute_count * sizeof(config->attributes[0]));
if (err)
return err;
#endif /* CONFIG_MALI_PLATFORM_FAKE */
#endif /* CONFIG_OF */
kbdev = kbase_device_alloc();
@@ -3240,7 +3240,7 @@ static const struct dev_pm_ops kbase_pm_ops = {
#ifdef CONFIG_OF
static const struct of_device_id kbase_dt_ids[] = {
{ .compatible = "arm,malit6xx" },
{ .compatible = "arm,malit7xx" },
{ .compatible = "arm,mali-midgard" },
{ /* sentinel */ }
};
@@ -3263,11 +3263,17 @@ static struct platform_driver kbase_platform_driver = {
* anymore when using Device Tree.
*/
#ifdef CONFIG_OF
#if 0
module_platform_driver(kbase_platform_driver);
#else /* CONFIG_MALI_PLATFORM_FAKE */
extern int kbase_platform_early_init(void);
#else
static int __init rockchip_gpu_init_driver(void)
{
return platform_driver_register(&kbase_platform_driver);
}
late_initcall(rockchip_gpu_init_driver);
#endif
#else
#ifdef CONFIG_MALI_PLATFORM_FAKE
extern int kbase_platform_fake_register(void);
extern void kbase_platform_fake_unregister(void);

View File

@@ -629,6 +629,7 @@ struct kbase_device {
struct list_head entry;
struct device *dev;
unsigned int kbase_group_error;
struct miscdevice mdev;
u64 reg_start;
size_t reg_size;

View File

@@ -393,6 +393,7 @@ void kbase_report_gpu_fault(struct kbase_device *kbdev, int multiple)
address |= kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTADDRESS_LO), NULL);
dev_warn(kbdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx", status & 0xFF, kbase_exception_name(status), address);
kbdev->kbase_group_error++;
if (multiple)
dev_warn(kbdev->dev, "There were multiple GPU faults - some have not been reported\n");
}

View File

@@ -49,10 +49,13 @@ static int kbasep_gpu_memory_seq_show(struct seq_file *sfile, void *data)
list_for_each_entry(element, &kbdev->kctx_list, link) {
/* output the memory usage and cap for each kctx
* opened on this device */
ret = seq_printf(sfile, " %s-0x%p %10u\n", \
"kctx",
ret = seq_printf(sfile, " %s-0x%p %10u %10u %10u %10u\n", \
"kctx", \
element->kctx, \
atomic_read(&(element->kctx->used_pages)));
element->kctx->pid, \
atomic_read(&(element->kctx->osalloc.free_list_size)), \
atomic_read(&(element->kctx->used_pages)), \
atomic_read(&(element->kctx->nonmapped_pages)));
}
mutex_unlock(&kbdev->kctx_list_lock);
}

View File

@@ -362,6 +362,7 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done)
/* fall throught */
default:
dev_warn(kbdev->dev, "error detected from slot %d, job status 0x%08x (%s)", i, completion_code, kbase_exception_name(completion_code));
kbdev->kbase_group_error++;
}
}

View File

@@ -0,0 +1,62 @@
/*
*
* (C) COPYRIGHT 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 <mali_kbase.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <asm/cacheflush.h>
void kbase_sync_to_memory(phys_addr_t paddr, void *vaddr, size_t sz)
{
#ifdef CONFIG_ARM
__cpuc_flush_dcache_area(vaddr, sz);
outer_flush_range(paddr, paddr + sz);
#elif defined(CONFIG_ARM64)
/* TODO (MID64-46): There's no other suitable cache flush function for ARM64 */
flush_cache_all();
#elif defined(CONFIG_X86)
struct scatterlist scl = { 0, };
sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz, paddr & (PAGE_SIZE - 1));
dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_TO_DEVICE);
mb(); /* for outer_sync (if needed) */
#else
#error Implement cache maintenance for your architecture here
#endif
}
void kbase_sync_to_cpu(phys_addr_t paddr, void *vaddr, size_t sz)
{
#ifdef CONFIG_ARM
__cpuc_flush_dcache_area(vaddr, sz);
outer_flush_range(paddr, paddr + sz);
#elif defined(CONFIG_ARM64)
/* TODO (MID64-46): There's no other suitable cache flush function for ARM64 */
flush_cache_all();
#elif defined(CONFIG_X86)
struct scatterlist scl = { 0, };
sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz, paddr & (PAGE_SIZE - 1));
dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_FROM_DEVICE);
#else
#error Implement cache maintenance for your architecture here
#endif
}

View File

@@ -1650,10 +1650,12 @@ void kbase_mmu_interrupt_process(struct kbase_device *kbdev, struct kbase_contex
* We need to switch to UNMAPPED mode - but we do this in a
* worker so that we can sleep
*/
kbdev->kbase_group_error++;
KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&as->work_busfault));
INIT_WORK(&as->work_busfault, bus_fault_worker);
queue_work(as->pf_wq, &as->work_busfault);
} else {
kbdev->kbase_group_error++;
KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&as->work_pagefault));
INIT_WORK(&as->work_pagefault, page_fault_worker);
queue_work(as->pf_wq, &as->work_pagefault);

View File

@@ -257,18 +257,37 @@ static int kbase_fence_wait(struct kbase_jd_atom *katom)
static void kbase_fence_cancel_wait(struct kbase_jd_atom *katom)
{
if(!katom)
{
pr_err("katom null.forbiden return\n");
return;
}
if(!katom->fence)
{
pr_info("katom->fence null.may release out of order.so continue unfinished step\n");
/*
if return here,may result in infinite loop?
we need to delete dep_item[0] from kctx->waiting_soft_jobs?
jd_done_nolock function move the dep_item[0] to complete job list and then delete?
*/
goto finish_softjob;
}
if (sync_fence_cancel_async(katom->fence, &katom->sync_waiter) != 0) {
/* The wait wasn't cancelled - leave the cleanup for kbase_fence_wait_callback */
return;
}
/* Wait was cancelled - zap the atoms */
finish_softjob:
katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
kbase_finish_soft_job(katom);
if (jd_done_nolock(katom))
kbasep_js_try_schedule_head_ctx(katom->kctx->kbdev);
return;
}
#endif /* CONFIG_SYNC */
@@ -387,8 +406,10 @@ void kbase_finish_soft_job(struct kbase_jd_atom *katom)
break;
case BASE_JD_REQ_SOFT_FENCE_WAIT:
/* Release the reference to the fence object */
sync_fence_put(katom->fence);
katom->fence = NULL;
if(katom->fence) {
sync_fence_put(katom->fence);
katom->fence = NULL;
}
break;
#endif /* CONFIG_SYNC */
}

View File

@@ -343,6 +343,7 @@ struct kbase_uk_get_ddk_version {
char version_buffer[KBASE_GET_VERSION_BUFFER_SIZE];
u32 version_string_size;
u32 padding;
u32 rk_version;
};
struct kbase_uk_disjoint_query {

View File

@@ -0,0 +1,24 @@
#
# (C) COPYRIGHT 2012-2013 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.
#
#
ccflags-y += -I$(srctree)/drivers/staging/android
ifeq ($(CONFIG_MALI_MIDGARD),y)
obj-y += mali_kbase_config_rk.o
obj-y += mali_kbase_dvfs.o
obj-y += mali_kbase_platform.o
else ifeq ($(CONFIG_MALI_MIDGARD),m)
SRC += platform/rk/mali_kbase_config_rk.c
SRC += platform/rk/mali_kbase_dvfs.c
SRC += platform/rk/mali_kbase_platform.c
endif

View File

@@ -0,0 +1,349 @@
/*
*
* (C) COPYRIGHT 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/ioport.h>
#include <mali_kbase.h>
#include <mali_kbase_defs.h>
#include <mali_kbase_config.h>
#ifdef CONFIG_UMP
#include <linux/ump-common.h>
#endif /* CONFIG_UMP */
#include <platform/rk/mali_kbase_platform.h>
#include <platform/rk/mali_kbase_dvfs.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>
#include <linux/reboot.h>
int get_cpu_clock_speed(u32 *cpu_clock);
#define HZ_IN_MHZ (1000000)
#ifdef CONFIG_MALI_MIDGARD_RT_PM
#define RUNTIME_PM_DELAY_TIME 50
#endif
/* Versatile Express (VE) configuration defaults shared between config_attributes[]
* and config_attributes_hw_issue_8408[]. Settings are not shared for
* JS_HARD_STOP_TICKS_SS and JS_RESET_TICKS_SS.
*/
#define KBASE_VE_MEMORY_PER_PROCESS_LIMIT (512 * 1024 * 1024UL) /* 512MB */
#define KBASE_VE_MEMORY_OS_SHARED_MAX (2048 * 1024 * 1024UL) /* 768MB */
#define KBASE_VE_MEMORY_OS_SHARED_PERF_GPU KBASE_MEM_PERF_FAST/*KBASE_MEM_PERF_SLOW*/
#define KBASE_VE_GPU_FREQ_KHZ_MAX 500000
#define KBASE_VE_GPU_FREQ_KHZ_MIN 100000
#ifdef CONFIG_UMP
#define KBASE_VE_UMP_DEVICE UMP_DEVICE_Z_SHIFT
#endif /* CONFIG_UMP */
#define KBASE_VE_JS_SCHEDULING_TICK_NS_DEBUG 15000000u /* 15ms, an agressive tick for testing purposes. This will reduce performance significantly */
#define KBASE_VE_JS_SOFT_STOP_TICKS_DEBUG 1 /* between 15ms and 30ms before soft-stop a job */
#define KBASE_VE_JS_HARD_STOP_TICKS_SS_DEBUG 333 /* 5s before hard-stop */
#define KBASE_VE_JS_HARD_STOP_TICKS_SS_8401_DEBUG 2000 /* 30s before hard-stop, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) - for issue 8401 */
#define KBASE_VE_JS_HARD_STOP_TICKS_NSS_DEBUG 100000 /* 1500s (25mins) before NSS hard-stop */
#define KBASE_VE_JS_RESET_TICKS_SS_DEBUG 500 /* 45s before resetting GPU, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) */
#define KBASE_VE_JS_RESET_TICKS_SS_8401_DEBUG 3000 /* 7.5s before resetting GPU - for issue 8401 */
#define KBASE_VE_JS_RESET_TICKS_NSS_DEBUG 100166 /* 1502s before resetting GPU */
#define KBASE_VE_JS_SCHEDULING_TICK_NS 2500000000u /* 2.5s */
#define KBASE_VE_JS_SOFT_STOP_TICKS 1 /* 2.5s before soft-stop a job */
#define KBASE_VE_JS_HARD_STOP_TICKS_SS 2 /* 5s before hard-stop */
#define KBASE_VE_JS_HARD_STOP_TICKS_SS_8401 12 /* 30s before hard-stop, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) - for issue 8401 */
#define KBASE_VE_JS_HARD_STOP_TICKS_NSS 600 /* 1500s before NSS hard-stop */
#define KBASE_VE_JS_RESET_TICKS_SS 3 /* 7.5s before resetting GPU */
#define KBASE_VE_JS_RESET_TICKS_SS_8401 18 /* 45s before resetting GPU, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) - for issue 8401 */
#define KBASE_VE_JS_RESET_TICKS_NSS 601 /* 1502s before resetting GPU */
#define KBASE_VE_JS_RESET_TIMEOUT_MS 500 /* 3s before cancelling stuck jobs */
#define KBASE_VE_JS_CTX_TIMESLICE_NS 1000000 /* 1ms - an agressive timeslice for testing purposes (causes lots of scheduling out for >4 ctxs) */
#define KBASE_VE_SECURE_BUT_LOSS_OF_PERFORMANCE ((uintptr_t)MALI_FALSE) /* By default we prefer performance over security on r0p0-15dev0 and KBASE_CONFIG_ATTR_ earlier */
/*#define KBASE_VE_POWER_MANAGEMENT_CALLBACKS ((uintptr_t)&pm_callbacks)*/
#define KBASE_VE_CPU_SPEED_FUNC ((uintptr_t)&get_cpu_clock_speed)
static int mali_pm_notifier(struct notifier_block *nb,unsigned long event,void* cmd);
static struct notifier_block mali_pm_nb = {
.notifier_call = mali_pm_notifier
};
static int mali_reboot_notifier_event(struct notifier_block *this, unsigned long event, void *ptr)
{
pr_info("%s enter\n",__func__);
if (kbase_platform_dvfs_enable(false, MALI_DVFS_CURRENT_FREQ)!= MALI_TRUE)
return -EPERM;
pr_info("%s exit\n",__func__);
return NOTIFY_OK;
}
static struct notifier_block mali_reboot_notifier = {
.notifier_call = mali_reboot_notifier_event,
};
#ifndef CONFIG_OF
static kbase_io_resources io_resources = {
.job_irq_number = 68,
.mmu_irq_number = 69,
.gpu_irq_number = 70,
.io_memory_region = {
.start = 0xFC010000,
.end = 0xFC010000 + (4096 * 5) - 1}
};
#endif
int get_cpu_clock_speed(u32 *cpu_clock)
{
#if 0
struct clk *cpu_clk;
u32 freq = 0;
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
return 1;
freq = clk_get_rate(cpu_clk);
*cpu_clock = (freq / HZ_IN_MHZ);
#endif
return 0;
}
static int mali_pm_notifier(struct notifier_block *nb,unsigned long event,void* cmd)
{
int err = NOTIFY_OK;
switch (event) {
case PM_SUSPEND_PREPARE:
#ifdef CONFIG_MALI_MIDGARD_DVFS
/*
pr_info("%s,PM_SUSPEND_PREPARE\n",__func__);
*/
if (kbase_platform_dvfs_enable(false, p_mali_dvfs_infotbl[0].clock)!= MALI_TRUE)
err = NOTIFY_BAD;
#endif
break;
case PM_POST_SUSPEND:
#ifdef CONFIG_MALI_MIDGARD_DVFS
/*
pr_info("%s,PM_POST_SUSPEND\n",__func__);
*/
if (kbase_platform_dvfs_enable(true, p_mali_dvfs_infotbl[0].clock)!= MALI_TRUE)
err = NOTIFY_BAD;
#endif
break;
default:
break;
}
return err;
}
/*
rk3288 hardware specific initialization
*/
mali_bool kbase_platform_rk_init(struct kbase_device *kbdev)
{
if(MALI_ERROR_NONE == kbase_platform_init(kbdev))
{
if (register_pm_notifier(&mali_pm_nb)) {
return MALI_FALSE;
}
pr_info("%s,register_reboot_notifier\n",__func__);
register_reboot_notifier(&mali_reboot_notifier);
return MALI_TRUE;
}
return MALI_FALSE;
}
/*
rk3288 hardware specific termination
*/
void kbase_platform_rk_term(struct kbase_device *kbdev)
{
unregister_pm_notifier(&mali_pm_nb);
#ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
kbase_platform_remove_sysfs_file(kbdev->dev);
#endif /* CONFIG_MALI_MIDGARD_DEBUG_SYS */
kbase_platform_term(kbdev);
}
kbase_platform_funcs_conf platform_funcs = {
.platform_init_func = &kbase_platform_rk_init,
.platform_term_func = &kbase_platform_rk_term,
};
#ifdef CONFIG_MALI_MIDGARD_RT_PM
static int pm_callback_power_on(struct kbase_device *kbdev)
{
int result;
int ret_val;
struct device *dev = kbdev->dev;
struct rk_context *platform;
platform = (struct rk_context *)kbdev->platform_context;
if (pm_runtime_status_suspended(dev))
ret_val = 1;
else
ret_val = 0;
if(dev->power.disable_depth > 0) {
if(platform->cmu_pmu_status == 0)
kbase_platform_cmu_pmu_control(kbdev, 1);
return ret_val;
}
result = pm_runtime_resume(dev);
if (result < 0 && result == -EAGAIN)
kbase_platform_cmu_pmu_control(kbdev, 1);
else if (result < 0)
printk(KERN_ERR "pm_runtime_get_sync failed (%d)\n", result);
return ret_val;
}
static void pm_callback_power_off(struct kbase_device *kbdev)
{
struct device *dev = kbdev->dev;
pm_schedule_suspend(dev, RUNTIME_PM_DELAY_TIME);
}
mali_error kbase_device_runtime_init(struct kbase_device *kbdev)
{
pm_suspend_ignore_children(kbdev->dev, true);
pm_runtime_enable(kbdev->dev);
#ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
if (kbase_platform_create_sysfs_file(kbdev->dev))
return MALI_ERROR_FUNCTION_FAILED;
#endif /* CONFIG_MALI_MIDGARD_DEBUG_SYS */
return MALI_ERROR_NONE;
}
void kbase_device_runtime_disable(struct kbase_device *kbdev)
{
pm_runtime_disable(kbdev->dev);
}
static int pm_callback_runtime_on(struct kbase_device *kbdev)
{
#ifdef CONFIG_MALI_MIDGARD_DVFS
struct rk_context *platform = (struct rk_context *)kbdev->platform_context;
unsigned long flags;
unsigned int clock;
#endif
kbase_platform_power_on(kbdev);
kbase_platform_clock_on(kbdev);
#ifdef CONFIG_MALI_MIDGARD_DVFS
if (platform->dvfs_enabled) {
if(platform->gpu_in_touch) {
clock = p_mali_dvfs_infotbl[MALI_DVFS_STEP-1].clock;
spin_lock_irqsave(&platform->gpu_in_touch_lock, flags);
platform->gpu_in_touch = false;
spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags);
} else {
clock = MALI_DVFS_CURRENT_FREQ;
}
/*
pr_info("%s,clock = %d\n",__func__,clock);
*/
if (kbase_platform_dvfs_enable(true, clock)!= MALI_TRUE)
return -EPERM;
} else {
if (kbase_platform_dvfs_enable(false, MALI_DVFS_CURRENT_FREQ)!= MALI_TRUE)
return -EPERM;
}
#endif
return 0;
}
static void pm_callback_runtime_off(struct kbase_device *kbdev)
{
#ifdef CONFIG_MALI_MIDGARD_DVFS
struct rk_context *platform = (struct rk_context *)kbdev->platform_context;
unsigned long flags;
#endif
kbase_platform_clock_off(kbdev);
kbase_platform_power_off(kbdev);
#ifdef CONFIG_MALI_MIDGARD_DVFS
if (platform->dvfs_enabled)
{
/*printk("%s\n",__func__);*/
if (kbase_platform_dvfs_enable(false, p_mali_dvfs_infotbl[0].clock)!= MALI_TRUE)
printk("[err] disabling dvfs is faled\n");
spin_lock_irqsave(&platform->gpu_in_touch_lock, flags);
platform->gpu_in_touch = false;
spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags);
}
#endif
}
static kbase_pm_callback_conf pm_callbacks = {
.power_on_callback = pm_callback_power_on,
.power_off_callback = pm_callback_power_off,
#ifdef CONFIG_PM_RUNTIME
.power_runtime_init_callback = kbase_device_runtime_init,
.power_runtime_term_callback = kbase_device_runtime_disable,
.power_runtime_on_callback = pm_callback_runtime_on,
.power_runtime_off_callback = pm_callback_runtime_off,
#else /* CONFIG_PM_RUNTIME */
.power_runtime_init_callback = NULL,
.power_runtime_term_callback = NULL,
.power_runtime_on_callback = NULL,
.power_runtime_off_callback = NULL,
#endif /* CONFIG_PM_RUNTIME */
};
#endif
/* Please keep table config_attributes in sync with config_attributes_hw_issue_8408 */
static kbase_attribute config_attributes[] = {
#ifdef CONFIG_UMP
{
KBASE_CONFIG_ATTR_UMP_DEVICE,
KBASE_VE_UMP_DEVICE},
#endif /* CONFIG_UMP */
#ifdef CONFIG_MALI_MIDGARD_RT_PM
{
KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS,
(uintptr_t)&pm_callbacks},
#endif
{
KBASE_CONFIG_ATTR_PLATFORM_FUNCS,
(uintptr_t) &platform_funcs},
{
KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS,
KBASE_VE_JS_RESET_TIMEOUT_MS},
{
KBASE_CONFIG_ATTR_END,
0}
};
static kbase_platform_config rk_platform_config = {
.attributes = config_attributes,
#ifndef CONFIG_OF
.io_resources = &io_resources
#endif
};
#if 1
kbase_platform_config *kbase_get_platform_config(void)
{
return &rk_platform_config;
}
#endif
int kbase_platform_early_init(void)
{
/* Nothing needed at this stage */
return 0;
}

View File

@@ -0,0 +1,747 @@
/* drivers/gpu/t6xx/kbase/src/platform/manta/mali_kbase_dvfs.c
*
*
* Rockchip SoC Mali-T764 DVFS driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software FoundatIon.
*/
/**
* @file mali_kbase_dvfs.c
* DVFS
*/
#include <mali_kbase.h>
#include <mali_kbase_uku.h>
#include <mali_kbase_mem.h>
#include <mali_midg_regmap.h>
#include <mali_kbase_mem_linux.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/semaphore.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/cpufreq.h>
#include <linux/fb.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/rk_fb.h>
#include <linux/input.h>
#include <linux/rockchip/common.h>
#include <platform/rk/mali_kbase_platform.h>
#include <platform/rk/mali_kbase_dvfs.h>
#include <mali_kbase_gator.h>
#include <linux/rockchip/dvfs.h>
/***********************************************************/
/* This table and variable are using the check time share of GPU Clock */
/***********************************************************/
extern int rockchip_tsadc_get_temp(int chn);
#define gpu_temp_limit 110
#define gpu_temp_statis_time 1
#define level0_min 0
#define level0_max 70
#define levelf_max 100
static u32 div_dvfs = 0 ;
static mali_dvfs_info mali_dvfs_infotbl[] = {
{925000, 100000, 0, 70, 0},
{925000, 160000, 50, 65, 0},
{1025000, 266000, 60, 78, 0},
{1075000, 350000, 65, 75, 0},
{1125000, 400000, 70, 75, 0},
{1200000, 500000, 90, 100, 0},
};
mali_dvfs_info *p_mali_dvfs_infotbl = NULL;
unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl);
static struct cpufreq_frequency_table *mali_freq_table = NULL;
#ifdef CONFIG_MALI_MIDGARD_DVFS
typedef struct _mali_dvfs_status_type {
struct kbase_device *kbdev;
int step;
int utilisation;
u32 temperature;
u32 temperature_time;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
int upper_lock;
int under_lock;
#endif
} mali_dvfs_status;
static struct workqueue_struct *mali_dvfs_wq = 0;
spinlock_t mali_dvfs_spinlock;
struct mutex mali_set_clock_lock;
struct mutex mali_enable_clock_lock;
#ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
static void update_time_in_state(int level);
#endif
/*dvfs status*/
static mali_dvfs_status mali_dvfs_status_current;
#define LIMIT_FPS 60
#define LIMIT_FPS_POWER_SAVE 50
#ifdef CONFIG_MALI_MIDGARD_DVFS
static void gpufreq_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
mali_dvfs_status *dvfs_status;
struct rk_context *platform;
unsigned long flags;
if (type != EV_ABS)
return;
dvfs_status = &mali_dvfs_status_current;
platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
spin_lock_irqsave(&platform->gpu_in_touch_lock, flags);
platform->gpu_in_touch = true;
spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags);
}
static int gpufreq_input_connect(struct input_handler *handler,
struct input_dev *dev, const struct input_device_id *id)
{
struct input_handle *handle;
int error;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "gpufreq";
error = input_register_handle(handle);
if (error)
goto err2;
error = input_open_device(handle);
if (error)
goto err1;
pr_info("%s\n",__func__);
return 0;
err1:
input_unregister_handle(handle);
err2:
kfree(handle);
return error;
}
static void gpufreq_input_disconnect(struct input_handle *handle)
{
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
pr_info("%s\n",__func__);
}
static const struct input_device_id gpufreq_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_ABS) },
.absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
BIT_MASK(ABS_MT_POSITION_X) |
BIT_MASK(ABS_MT_POSITION_Y) },
},
{
.flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
.absbit = { [BIT_WORD(ABS_X)] =
BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
},
{ },
};
static struct input_handler gpufreq_input_handler = {
.event = gpufreq_input_event,
.connect = gpufreq_input_connect,
.disconnect = gpufreq_input_disconnect,
.name = "gpufreq",
.id_table = gpufreq_ids,
};
#endif
static void mali_dvfs_event_proc(struct work_struct *w)
{
unsigned long flags;
mali_dvfs_status *dvfs_status;
static int level_down_time = 0;
static int level_up_time = 0;
static u32 temp_tmp;
struct rk_context *platform;
u32 fps=0;
u32 fps_limit;
u32 policy;
mutex_lock(&mali_enable_clock_lock);
dvfs_status = &mali_dvfs_status_current;
if (!kbase_platform_dvfs_get_enable_status()) {
mutex_unlock(&mali_enable_clock_lock);
return;
}
platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
fps = rk_get_real_fps(0);
dvfs_status->temperature_time++;
temp_tmp += rockchip_tsadc_get_temp(1);
if(dvfs_status->temperature_time >= gpu_temp_statis_time) {
dvfs_status->temperature_time = 0;
dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
temp_tmp = 0;
}
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
/*
policy = rockchip_pm_get_policy();
*/
policy = ROCKCHIP_PM_POLICY_NORMAL;
if (ROCKCHIP_PM_POLICY_PERFORMANCE == policy) {
dvfs_status->step = MALI_DVFS_STEP - 1;
} else {
fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
/*
printk("policy : %d , fps_limit = %d\n",policy,fps_limit);
*/
/*give priority to temperature unless in performance mode */
if (dvfs_status->temperature > gpu_temp_limit) {
if(dvfs_status->step > 0)
dvfs_status->step--;
if(gpu_temp_statis_time > 1)
dvfs_status->temperature = 0;
/*
pr_info("decrease step for temperature over %d,next clock = %d\n",
gpu_temp_limit, mali_dvfs_infotbl[dvfs_status->step].clock);
*/
} else if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) &&
(dvfs_status->step < MALI_DVFS_STEP-1) && fps < fps_limit) {
level_up_time++;
if (level_up_time == MALI_DVFS_UP_TIME_INTERVAL) {
/*
printk("up,utilisation=%d,current clock=%d,fps = %d,temperature = %d",
dvfs_status->utilisation, mali_dvfs_infotbl[dvfs_status->step].clock,
fps,dvfs_status->temperature);
*/
dvfs_status->step++;
level_up_time = 0;
/*
printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
*/
BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
}
level_down_time = 0;
} else if ((dvfs_status->step > 0) &&
(dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) {
level_down_time++;
if (level_down_time==MALI_DVFS_DOWN_TIME_INTERVAL) {
/*
printk("down,utilisation=%d,current clock=%d,fps = %d,temperature = %d",
dvfs_status->utilisation,
mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature);
*/
BUG_ON(dvfs_status->step <= 0);
dvfs_status->step--;
level_down_time = 0;
/*
printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
*/
}
level_up_time = 0;
} else {
level_down_time = 0;
level_up_time = 0;
/*
printk("keep,utilisation=%d,current clock=%d,fps = %d,temperature = %d\n",
dvfs_status->utilisation,
mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature);
*/
}
}
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock))
dvfs_status->step = dvfs_status->upper_lock;
if (dvfs_status->under_lock > 0) {
if (dvfs_status->step < dvfs_status->under_lock)
dvfs_status->step = dvfs_status->under_lock;
}
#endif
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
mutex_unlock(&mali_enable_clock_lock);
}
static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation,
u32 util_gl_share_no_use,u32 util_cl_share_no_use[2])
{
unsigned long flags;
struct rk_context *platform;
BUG_ON(!kbdev);
platform = (struct rk_context *)kbdev->platform_context;
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
if (platform->time_tick < MALI_DVFS_UP_TIME_INTERVAL) {
platform->time_tick++;
platform->time_busy += kbdev->pm.metrics.time_busy;
platform->time_idle += kbdev->pm.metrics.time_idle;
} else {
platform->time_busy = kbdev->pm.metrics.time_busy;
platform->time_idle = kbdev->pm.metrics.time_idle;
platform->time_tick = 0;
}
if ((platform->time_tick == MALI_DVFS_UP_TIME_INTERVAL) &&
(platform->time_idle + platform->time_busy > 0))
platform->utilisation = (100 * platform->time_busy) /
(platform->time_idle + platform->time_busy);
mali_dvfs_status_current.utilisation = utilisation;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
/*add error handle here */
return MALI_TRUE;
}
int kbase_platform_dvfs_get_utilisation(void)
{
unsigned long flags;
int utilisation = 0;
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
utilisation = mali_dvfs_status_current.utilisation;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
return utilisation;
}
int kbase_platform_dvfs_get_enable_status(void)
{
struct kbase_device *kbdev;
unsigned long flags;
int enable;
kbdev = mali_dvfs_status_current.kbdev;
spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
enable = kbdev->pm.metrics.timer_active;
spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
return enable;
}
int kbase_platform_dvfs_enable(bool enable, int freq)
{
mali_dvfs_status *dvfs_status;
struct kbase_device *kbdev;
unsigned long flags;
struct rk_context *platform;
dvfs_status = &mali_dvfs_status_current;
kbdev = mali_dvfs_status_current.kbdev;
BUG_ON(kbdev == NULL);
platform = (struct rk_context *)kbdev->platform_context;
mutex_lock(&mali_enable_clock_lock);
if (enable != kbdev->pm.metrics.timer_active) {
if (enable) {
spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
kbdev->pm.metrics.timer_active = MALI_TRUE;
spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
hrtimer_start(&kbdev->pm.metrics.timer,
HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
HRTIMER_MODE_REL);
} else {
spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
kbdev->pm.metrics.timer_active = MALI_FALSE;
spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
hrtimer_cancel(&kbdev->pm.metrics.timer);
}
}
if (freq != MALI_DVFS_CURRENT_FREQ) {
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
platform->time_tick = 0;
platform->time_busy = 0;
platform->time_idle = 0;
platform->utilisation = 0;
dvfs_status->step = kbase_platform_dvfs_get_level(freq);
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
}
mutex_unlock(&mali_enable_clock_lock);
return MALI_TRUE;
}
#define dividend 7
#define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
static bool calculate_dvfs_max_min_threshold(u32 level)
{
u32 pre_level;
u32 tmp ;
if (0 == level) {
if ((MALI_DVFS_STEP-1) == level) {
mali_dvfs_infotbl[level].min_threshold = level0_min;
mali_dvfs_infotbl[level].max_threshold = levelf_max;
} else {
mali_dvfs_infotbl[level].min_threshold = level0_min;
mali_dvfs_infotbl[level].max_threshold = level0_max;
}
} else {
pre_level = level - 1;
if ((MALI_DVFS_STEP-1) == level) {
mali_dvfs_infotbl[level].max_threshold = levelf_max;
} else {
mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold +
div_dvfs;
}
mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold *
(mali_dvfs_infotbl[pre_level].clock/1000)) /
(mali_dvfs_infotbl[level].clock/1000);
tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
}
pr_info("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",
level,mali_dvfs_infotbl[level].clock, mali_dvfs_infotbl[level].min_threshold,
mali_dvfs_infotbl[level].max_threshold);
return MALI_TRUE;
}
int kbase_platform_dvfs_init(struct kbase_device *kbdev)
{
unsigned long flags;
/*default status
add here with the right function to get initilization value.
*/
struct rk_context *platform;
int i;
int rc;
platform = (struct rk_context *)kbdev->platform_context;
if (NULL == platform)
panic("oops");
mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
if (mali_freq_table == NULL) {
printk("mali freq table not assigned yet,use default\n");
goto not_assigned ;
} else {
/*recalculte step*/
MALI_DVFS_STEP = 0;
for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
MALI_DVFS_STEP++;
}
if(MALI_DVFS_STEP > 1)
div_dvfs = round_up(((levelf_max - level0_max)/(MALI_DVFS_STEP-1)),1);
printk("MALI_DVFS_STEP=%d,div_dvfs=%d\n",MALI_DVFS_STEP,div_dvfs);
for(i=0;i<MALI_DVFS_STEP;i++)
calculate_dvfs_max_min_threshold(i);
p_mali_dvfs_infotbl = mali_dvfs_infotbl;
}
not_assigned :
if (!mali_dvfs_wq)
mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
spin_lock_init(&mali_dvfs_spinlock);
mutex_init(&mali_set_clock_lock);
mutex_init(&mali_enable_clock_lock);
spin_lock_init(&platform->gpu_in_touch_lock);
rc = input_register_handler(&gpufreq_input_handler);
/*add a error handling here */
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
mali_dvfs_status_current.kbdev = kbdev;
mali_dvfs_status_current.utilisation = 0;
mali_dvfs_status_current.step = 0;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
mali_dvfs_status_current.upper_lock = -1;
mali_dvfs_status_current.under_lock = -1;
#endif
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
return MALI_TRUE;
}
void kbase_platform_dvfs_term(void)
{
if (mali_dvfs_wq)
destroy_workqueue(mali_dvfs_wq);
mali_dvfs_wq = NULL;
input_unregister_handler(&gpufreq_input_handler);
}
#endif /*CONFIG_MALI_MIDGARD_DVFS*/
int mali_get_dvfs_upper_locked_freq(void)
{
unsigned long flags;
int locked_level = -1;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
if (mali_dvfs_status_current.upper_lock >= 0)
locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
#endif
return locked_level;
}
int mali_get_dvfs_under_locked_freq(void)
{
unsigned long flags;
int locked_level = -1;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
if (mali_dvfs_status_current.under_lock >= 0)
locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
#endif
return locked_level;
}
int mali_get_dvfs_current_level(void)
{
unsigned long flags;
int current_level = -1;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
current_level = mali_dvfs_status_current.step;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
#endif
return current_level;
}
int mali_dvfs_freq_lock(int level)
{
unsigned long flags;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
if (mali_dvfs_status_current.under_lock >= 0 &&
mali_dvfs_status_current.under_lock > level) {
printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
return -1;
}
mali_dvfs_status_current.upper_lock = level;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
#endif
return 0;
}
void mali_dvfs_freq_unlock(void)
{
unsigned long flags;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
mali_dvfs_status_current.upper_lock = -1;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
#endif
printk(KERN_DEBUG "mali Upper Lock Unset\n");
}
int mali_dvfs_freq_under_lock(int level)
{
unsigned long flags;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
if (mali_dvfs_status_current.upper_lock >= 0 &&
mali_dvfs_status_current.upper_lock < level) {
printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
return -1;
}
mali_dvfs_status_current.under_lock = level;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
#endif
return 0;
}
void mali_dvfs_freq_under_unlock(void)
{
unsigned long flags;
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
spin_lock_irqsave(&mali_dvfs_spinlock, flags);
mali_dvfs_status_current.under_lock = -1;
spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
#endif
printk(KERN_DEBUG " mali clock Under Lock Unset\n");
}
void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq)
{
struct rk_context *platform;
if (!kbdev)
panic("oops");
platform = (struct rk_context *)kbdev->platform_context;
if (NULL == platform)
panic("oops");
if (!platform->mali_clk_node) {
printk("mali_clk_node not init\n");
return;
}
mali_dvfs_clk_set(platform->mali_clk_node,freq);
return;
}
int kbase_platform_dvfs_get_level(int freq)
{
int i;
for (i = 0; i < MALI_DVFS_STEP; i++) {
if (mali_dvfs_infotbl[i].clock == freq)
return i;
}
return -1;
}
void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level)
{
static int prev_level = -1;
if (level == prev_level)
return;
if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0))) {
printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
return ;
}
/*panic("invalid level");*/
#ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
if (mali_dvfs_status_current.upper_lock >= 0 &&
level > mali_dvfs_status_current.upper_lock)
level = mali_dvfs_status_current.upper_lock;
if (mali_dvfs_status_current.under_lock >= 0 &&
level < mali_dvfs_status_current.under_lock)
level = mali_dvfs_status_current.under_lock;
#endif
#ifdef CONFIG_MALI_MIDGARD_DVFS
mutex_lock(&mali_set_clock_lock);
#endif
kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
#if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
update_time_in_state(prev_level);
#endif
prev_level = level;
#ifdef CONFIG_MALI_MIDGARD_DVFS
mutex_unlock(&mali_set_clock_lock);
#endif
}
#ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
#ifdef CONFIG_MALI_MIDGARD_DVFS
static void update_time_in_state(int level)
{
u64 current_time;
static u64 prev_time=0;
if (level < 0)
return;
if (!kbase_platform_dvfs_get_enable_status())
return;
if (prev_time ==0)
prev_time=get_jiffies_64();
current_time = get_jiffies_64();
mali_dvfs_infotbl[level].time += current_time-prev_time;
prev_time = current_time;
}
#endif
ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct kbase_device *kbdev;
ssize_t ret = 0;
int i;
kbdev = dev_get_drvdata(dev);
#ifdef CONFIG_MALI_MIDGARD_DVFS
update_time_in_state(mali_dvfs_status_current.step);
#endif
if (!kbdev)
return -ENODEV;
for (i = 0; i < MALI_DVFS_STEP; i++)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
"%d %llu\n",
mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
if (ret < PAGE_SIZE - 1)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
else {
buf[PAGE_SIZE - 2] = '\n';
buf[PAGE_SIZE - 1] = '\0';
ret = PAGE_SIZE - 1;
}
return ret;
}
ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int i;
for (i = 0; i < MALI_DVFS_STEP; i++)
mali_dvfs_infotbl[i].time = 0;
printk(KERN_DEBUG "time_in_state value is reset complete.\n");
return count;
}
#endif

View File

@@ -0,0 +1,69 @@
/* drivers/gpu/midgard/platform/rk/mali_kbase_dvfs.h
*
* Rockchip SoC Mali-T764 DVFS driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software FoundatIon.
*/
/**
* @file mali_kbase_dvfs.h
* DVFS
*/
#ifndef _KBASE_DVFS_H_
#define _KBASE_DVFS_H_
/* Frequency that DVFS clock frequency decisions should be made */
#define KBASE_PM_DVFS_FREQUENCY 100
#define MALI_DVFS_KEEP_STAY_CNT 10
#define MALI_DVFS_UP_TIME_INTERVAL 1
#define MALI_DVFS_DOWN_TIME_INTERVAL 2
#define MALI_DVFS_CURRENT_FREQ 0
#if 0
#define MALI_DVFS_BL_CONFIG_FREQ 500
#define MALI_DVFS_START_FREQ 400
#endif
typedef struct _mali_dvfs_info {
unsigned int voltage;
unsigned int clock;
int min_threshold;
int max_threshold;
unsigned long long time;
} mali_dvfs_info;
#define MALI_KHZ 1000
extern mali_dvfs_info *p_mali_dvfs_infotbl;
extern unsigned int MALI_DVFS_STEP;
#ifdef CONFIG_MALI_MIDGARD_DVFS
#define CONFIG_MALI_MIDGARD_FREQ_LOCK
#endif
void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq);
void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level);
int kbase_platform_dvfs_get_level(int freq);
#ifdef CONFIG_MALI_MIDGARD_DVFS
int kbase_platform_dvfs_init(struct kbase_device *dev);
void kbase_platform_dvfs_term(void);
/*int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation);*/
/*int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation,u32 util_gl_share, u32 util_cl_share[2]);*/
int kbase_platform_dvfs_get_enable_status(void);
int kbase_platform_dvfs_enable(bool enable, int freq);
int kbase_platform_dvfs_get_utilisation(void);
#endif
int mali_get_dvfs_current_level(void);
int mali_get_dvfs_upper_locked_freq(void);
int mali_get_dvfs_under_locked_freq(void);
int mali_dvfs_freq_lock(int level);
void mali_dvfs_freq_unlock(void);
int mali_dvfs_freq_under_lock(int level);
void mali_dvfs_freq_under_unlock(void);
ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
#endif /* _KBASE_DVFS_H_ */

View File

@@ -0,0 +1,944 @@
/* drivers/gpu/t6xx/kbase/src/platform/rk/mali_kbase_platform.c
*
* Rockchip SoC Mali-T764 platform-dependent codes
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software FoundatIon.
*/
/**
* @file mali_kbase_platform.c
* Platform-dependent init.
*/
#include <mali_kbase.h>
#include <mali_kbase_pm.h>
#include <mali_kbase_uku.h>
#include <mali_kbase_mem.h>
#include <mali_midg_regmap.h>
#include <mali_kbase_mem_linux.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/semaphore.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fb.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <platform/rk/mali_kbase_platform.h>
#include <platform/rk/mali_kbase_dvfs.h>
#include <mali_kbase_gator.h>
#include <linux/rockchip/dvfs.h>
#define MALI_T7XX_DEFAULT_CLOCK 100000
static int mali_clk_status = 0;
static int mali_pd_status = 0;
u32 kbase_group_error = 0;
static struct kobject *rk_gpu;
int mali_dvfs_clk_set(struct dvfs_node *node,unsigned long rate)
{
int ret = 0;
if(!node)
{
printk("clk_get_dvfs_node error \r\n");
ret = -1;
}
ret = dvfs_clk_set_rate(node,rate * MALI_KHZ);
if(ret)
{
printk("dvfs_clk_set_rate error \r\n");
}
return ret;
}
static int kbase_platform_power_clock_init(struct kbase_device *kbdev)
{
/*struct device *dev = kbdev->dev;*/
struct rk_context *platform;
platform = (struct rk_context *)kbdev->platform_context;
if (NULL == platform)
panic("oops");
/* enable mali t760 powerdomain*/
platform->mali_pd = clk_get(NULL,"pd_gpu");
if(IS_ERR_OR_NULL(platform->mali_pd))
{
platform->mali_pd = NULL;
printk(KERN_ERR "%s, %s(): failed to get [platform->mali_pd]\n", __FILE__, __func__);
goto out;
}
else
{
clk_prepare_enable(platform->mali_pd);
printk("mali pd enabled\n");
}
mali_pd_status = 1;
/* enable mali t760 clock */
platform->mali_clk_node = clk_get_dvfs_node("clk_gpu");
if (IS_ERR_OR_NULL(platform->mali_clk_node))
{
platform->mali_clk_node = NULL;
printk(KERN_ERR "%s, %s(): failed to get [platform->mali_clk_node]\n", __FILE__, __func__);
goto out;
}
else
{
dvfs_clk_prepare_enable(platform->mali_clk_node);
printk("clk enabled\n");
}
mali_dvfs_clk_set(platform->mali_clk_node,MALI_T7XX_DEFAULT_CLOCK);
mali_clk_status = 1;
return 0;
out:
if(platform->mali_pd)
clk_put(platform->mali_pd);
return -EPERM;
}
int kbase_platform_clock_off(struct kbase_device *kbdev)
{
struct rk_context *platform;
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
if (mali_clk_status == 0)
return 0;
if((platform->mali_clk_node))
dvfs_clk_disable_unprepare(platform->mali_clk_node);
mali_clk_status = 0;
return 0;
}
int kbase_platform_clock_on(struct kbase_device *kbdev)
{
struct rk_context *platform;
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
if (mali_clk_status == 1)
return 0;
if(platform->mali_clk_node)
dvfs_clk_prepare_enable(platform->mali_clk_node);
mali_clk_status = 1;
return 0;
}
int kbase_platform_is_power_on(void)
{
return mali_pd_status;
}
/*turn on power domain*/
int kbase_platform_power_on(struct kbase_device *kbdev)
{
struct rk_context *platform;
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
if (mali_pd_status == 1)
return 0;
#if 1
if(platform->mali_pd)
clk_prepare_enable(platform->mali_pd);
#endif
mali_pd_status = 1;
KBASE_TIMELINE_GPU_POWER(kbdev, 1);
return 0;
}
/*turn off power domain*/
int kbase_platform_power_off(struct kbase_device *kbdev)
{
struct rk_context *platform;
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
if (mali_pd_status== 0)
return 0;
#if 1
if(platform->mali_pd)
clk_disable_unprepare(platform->mali_pd);
#endif
mali_pd_status = 0;
KBASE_TIMELINE_GPU_POWER(kbdev, 0);
return 0;
}
int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control)
{
unsigned long flags;
struct rk_context *platform;
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
spin_lock_irqsave(&platform->cmu_pmu_lock, flags);
/* off */
if (control == 0)
{
if (platform->cmu_pmu_status == 0)
{
spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
return 0;
}
if (kbase_platform_power_off(kbdev))
panic("failed to turn off mali power domain\n");
if (kbase_platform_clock_off(kbdev))
panic("failed to turn off mali clock\n");
platform->cmu_pmu_status = 0;
printk("turn off mali power \n");
}
else
{
/* on */
if (platform->cmu_pmu_status == 1)
{
spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
return 0;
}
if (kbase_platform_power_on(kbdev))
panic("failed to turn on mali power domain\n");
if (kbase_platform_clock_on(kbdev))
panic("failed to turn on mali clock\n");
platform->cmu_pmu_status = 1;
printk(KERN_ERR "turn on mali power\n");
}
spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
return 0;
}
static ssize_t error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
ssize_t ret;
ret = scnprintf(buf, PAGE_SIZE, "%d\n", kbdev->kbase_group_error);
return ret;
}
static DEVICE_ATTR(error_count, S_IRUGO, error_count_show, NULL);
#ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
static ssize_t show_clock(struct device *dev, struct device_attribute *attr, char *buf)
{
struct kbase_device *kbdev;
struct rk_context *platform;
ssize_t ret = 0;
unsigned int clkrate;
int i ;
kbdev = dev_get_drvdata(dev);
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
if (!platform->mali_clk_node)
{
printk("mali_clk_node not init\n");
return -ENODEV;
}
clkrate = dvfs_clk_get_rate(platform->mali_clk_node);
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Current clk mali = %dMhz", clkrate / 1000000);
/* To be revised */
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings:");
for(i=0;i<MALI_DVFS_STEP;i++)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ",p_mali_dvfs_infotbl[i].clock/1000);
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Mhz");
if (ret < PAGE_SIZE - 1)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
else {
buf[PAGE_SIZE - 2] = '\n';
buf[PAGE_SIZE - 1] = '\0';
ret = PAGE_SIZE - 1;
}
return ret;
}
static ssize_t set_clock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct kbase_device *kbdev;
struct rk_context *platform;
unsigned int tmp = 0, freq = 0;
kbdev = dev_get_drvdata(dev);
tmp = 0;
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
if (!platform->mali_clk_node)
return -ENODEV;
#if 0
if (sysfs_streq("500", buf)) {
freq = 500;
} else if (sysfs_streq("400", buf)) {
freq = 400;
} else if (sysfs_streq("350", buf)) {
freq = 350;
} else if (sysfs_streq("266", buf)) {
freq = 266;
} else if (sysfs_streq("160", buf)) {
freq = 160;
} else if (sysfs_streq("100", buf)) {
freq = 100;
} else {
dev_err(dev, "set_clock: invalid value\n");
return -ENOENT;
}
#endif
freq = simple_strtoul(buf, NULL, 10);
kbase_platform_dvfs_set_level(kbdev, kbase_platform_dvfs_get_level(freq));
return count;
}
static ssize_t show_fbdev(struct device *dev, struct device_attribute *attr, char *buf)
{
struct kbase_device *kbdev;
ssize_t ret = 0;
int i;
kbdev = dev_get_drvdata(dev);
if (!kbdev)
return -ENODEV;
for (i = 0; i < num_registered_fb; i++)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "fb[%d] xres=%d, yres=%d, addr=0x%lx\n", i, registered_fb[i]->var.xres, registered_fb[i]->var.yres, registered_fb[i]->fix.smem_start);
if (ret < PAGE_SIZE - 1)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
else {
buf[PAGE_SIZE - 2] = '\n';
buf[PAGE_SIZE - 1] = '\0';
ret = PAGE_SIZE - 1;
}
return ret;
}
typedef enum {
L1_I_tag_RAM = 0x00,
L1_I_data_RAM = 0x01,
L1_I_BTB_RAM = 0x02,
L1_I_GHB_RAM = 0x03,
L1_I_TLB_RAM = 0x04,
L1_I_indirect_predictor_RAM = 0x05,
L1_D_tag_RAM = 0x08,
L1_D_data_RAM = 0x09,
L1_D_load_TLB_array = 0x0A,
L1_D_store_TLB_array = 0x0B,
L2_tag_RAM = 0x10,
L2_data_RAM = 0x11,
L2_snoop_tag_RAM = 0x12,
L2_data_ECC_RAM = 0x13,
L2_dirty_RAM = 0x14,
L2_TLB_RAM = 0x18
} RAMID_type;
static inline void asm_ramindex_mrc(u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
{
u32 val;
if (DL1Data0) {
asm volatile ("mrc p15, 0, %0, c15, c1, 0" : "=r" (val));
*DL1Data0 = val;
}
if (DL1Data1) {
asm volatile ("mrc p15, 0, %0, c15, c1, 1" : "=r" (val));
*DL1Data1 = val;
}
if (DL1Data2) {
asm volatile ("mrc p15, 0, %0, c15, c1, 2" : "=r" (val));
*DL1Data2 = val;
}
if (DL1Data3) {
asm volatile ("mrc p15, 0, %0, c15, c1, 3" : "=r" (val));
*DL1Data3 = val;
}
}
static inline void asm_ramindex_mcr(u32 val)
{
asm volatile ("mcr p15, 0, %0, c15, c4, 0" : : "r" (val));
asm volatile ("dsb");
asm volatile ("isb");
}
static void get_tlb_array(u32 val, u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
{
asm_ramindex_mcr(val);
asm_ramindex_mrc(DL1Data0, DL1Data1, DL1Data2, DL1Data3);
}
static RAMID_type ramindex = L1_D_load_TLB_array;
static ssize_t show_dtlb(struct device *dev, struct device_attribute *attr, char *buf)
{
struct kbase_device *kbdev;
ssize_t ret = 0;
int entries, ways;
u32 DL1Data0 = 0, DL1Data1 = 0, DL1Data2 = 0, DL1Data3 = 0;
kbdev = dev_get_drvdata(dev);
if (!kbdev)
return -ENODEV;
/* L1-I tag RAM */
if (ramindex == L1_I_tag_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L1-I data RAM */
else if (ramindex == L1_I_data_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L1-I BTB RAM */
else if (ramindex == L1_I_BTB_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L1-I GHB RAM */
else if (ramindex == L1_I_GHB_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L1-I TLB RAM */
else if (ramindex == L1_I_TLB_RAM) {
printk(KERN_DEBUG "L1-I TLB RAM\n");
for (entries = 0; entries < 32; entries++) {
get_tlb_array((((u8) ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, NULL);
printk(KERN_DEBUG "entries[%d], DL1Data0=%08x, DL1Data1=%08x DL1Data2=%08x\n", entries, DL1Data0, DL1Data1 & 0xffff, 0x0);
}
}
/* L1-I indirect predictor RAM */
else if (ramindex == L1_I_indirect_predictor_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L1-D tag RAM */
else if (ramindex == L1_D_tag_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L1-D data RAM */
else if (ramindex == L1_D_data_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L1-D load TLB array */
else if (ramindex == L1_D_load_TLB_array) {
printk(KERN_DEBUG "L1-D load TLB array\n");
for (entries = 0; entries < 32; entries++) {
get_tlb_array((((u8) ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
printk(KERN_DEBUG "entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f);
}
}
/* L1-D store TLB array */
else if (ramindex == L1_D_store_TLB_array) {
printk(KERN_DEBUG "\nL1-D store TLB array\n");
for (entries = 0; entries < 32; entries++) {
get_tlb_array((((u8) ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
printk(KERN_DEBUG "entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f);
}
}
/* L2 tag RAM */
else if (ramindex == L2_tag_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L2 data RAM */
else if (ramindex == L2_data_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L2 snoop tag RAM */
else if (ramindex == L2_snoop_tag_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L2 data ECC RAM */
else if (ramindex == L2_data_ECC_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L2 dirty RAM */
else if (ramindex == L2_dirty_RAM)
printk(KERN_DEBUG "Not implemented yet\n");
/* L2 TLB array */
else if (ramindex == L2_TLB_RAM) {
printk(KERN_DEBUG "\nL2 TLB array\n");
for (ways = 0; ways < 4; ways++) {
for (entries = 0; entries < 512; entries++) {
get_tlb_array((ramindex << 24) + (ways << 18) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
printk(KERN_DEBUG "ways[%d]:entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", ways, entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3);
}
}
} else {
}
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Succeeded...\n");
if (ret < PAGE_SIZE - 1)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
else {
buf[PAGE_SIZE - 2] = '\n';
buf[PAGE_SIZE - 1] = '\0';
ret = PAGE_SIZE - 1;
}
return ret;
}
static ssize_t set_dtlb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct kbase_device *kbdev;
kbdev = dev_get_drvdata(dev);
if (!kbdev)
return -ENODEV;
if (sysfs_streq("L1_I_tag_RAM", buf)) {
ramindex = L1_I_tag_RAM;
} else if (sysfs_streq("L1_I_data_RAM", buf)) {
ramindex = L1_I_data_RAM;
} else if (sysfs_streq("L1_I_BTB_RAM", buf)) {
ramindex = L1_I_BTB_RAM;
} else if (sysfs_streq("L1_I_GHB_RAM", buf)) {
ramindex = L1_I_GHB_RAM;
} else if (sysfs_streq("L1_I_TLB_RAM", buf)) {
ramindex = L1_I_TLB_RAM;
} else if (sysfs_streq("L1_I_indirect_predictor_RAM", buf)) {
ramindex = L1_I_indirect_predictor_RAM;
} else if (sysfs_streq("L1_D_tag_RAM", buf)) {
ramindex = L1_D_tag_RAM;
} else if (sysfs_streq("L1_D_data_RAM", buf)) {
ramindex = L1_D_data_RAM;
} else if (sysfs_streq("L1_D_load_TLB_array", buf)) {
ramindex = L1_D_load_TLB_array;
} else if (sysfs_streq("L1_D_store_TLB_array", buf)) {
ramindex = L1_D_store_TLB_array;
} else if (sysfs_streq("L2_tag_RAM", buf)) {
ramindex = L2_tag_RAM;
} else if (sysfs_streq("L2_data_RAM", buf)) {
ramindex = L2_data_RAM;
} else if (sysfs_streq("L2_snoop_tag_RAM", buf)) {
ramindex = L2_snoop_tag_RAM;
} else if (sysfs_streq("L2_data_ECC_RAM", buf)) {
ramindex = L2_data_ECC_RAM;
} else if (sysfs_streq("L2_dirty_RAM", buf)) {
ramindex = L2_dirty_RAM;
} else if (sysfs_streq("L2_TLB_RAM", buf)) {
ramindex = L2_TLB_RAM;
} else {
printk(KERN_DEBUG "Invalid value....\n\n");
printk(KERN_DEBUG "Available options are one of below\n");
printk(KERN_DEBUG "L1_I_tag_RAM, L1_I_data_RAM, L1_I_BTB_RAM\n");
printk(KERN_DEBUG "L1_I_GHB_RAM, L1_I_TLB_RAM, L1_I_indirect_predictor_RAM\n");
printk(KERN_DEBUG "L1_D_tag_RAM, L1_D_data_RAM, L1_D_load_TLB_array, L1_D_store_TLB_array\n");
printk(KERN_DEBUG "L2_tag_RAM, L2_data_RAM, L2_snoop_tag_RAM, L2_data_ECC_RAM\n");
printk(KERN_DEBUG "L2_dirty_RAM, L2_TLB_RAM\n");
}
return count;
}
static ssize_t show_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
{
struct kbase_device *kbdev;
struct rk_context *platform;
ssize_t ret = 0;
unsigned int clkrate;
kbdev = dev_get_drvdata(dev);
if (!kbdev)
return -ENODEV;
platform = (struct rk_context *)kbdev->platform_context;
if (!platform)
return -ENODEV;
clkrate = dvfs_clk_get_rate(platform->mali_clk_node);
#ifdef CONFIG_MALI_MIDGARD_DVFS
if (kbase_platform_dvfs_get_enable_status())
ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is on\nutilisation:%d\ncurrent clock:%dMhz", kbase_platform_dvfs_get_utilisation(),clkrate/1000000);
else
ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is off,clock:%dMhz",clkrate/1000000);
#else
ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled");
#endif
if (ret < PAGE_SIZE - 1)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
else {
buf[PAGE_SIZE - 2] = '\n';
buf[PAGE_SIZE - 1] = '\0';
ret = PAGE_SIZE - 1;
}
return ret;
}
static ssize_t set_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
#ifdef CONFIG_MALI_MIDGARD_DVFS
struct rk_context *platform;
#endif
if (!kbdev)
return -ENODEV;
#ifdef CONFIG_MALI_MIDGARD_DVFS
platform = (struct rk_context *)kbdev->platform_context;
if (sysfs_streq("off", buf)) {
/*kbase_platform_dvfs_enable(false, MALI_DVFS_BL_CONFIG_FREQ);*/
kbase_platform_dvfs_enable(false, p_mali_dvfs_infotbl[MALI_DVFS_STEP-1].clock);
platform->dvfs_enabled = false;
} else if (sysfs_streq("on", buf)) {
/*kbase_platform_dvfs_enable(true, MALI_DVFS_START_FREQ);*/
kbase_platform_dvfs_enable(true, p_mali_dvfs_infotbl[0].clock);
platform->dvfs_enabled = true;
} else {
printk(KERN_DEBUG "invalid val -only [on, off] is accepted\n");
}
#else
printk(KERN_DEBUG "mali DVFS is disabled\n");
#endif
return count;
}
static ssize_t show_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
{
struct kbase_device *kbdev;
ssize_t ret = 0;
int i;
#ifdef CONFIG_MALI_MIDGARD_DVFS
int locked_level = -1;
#endif
kbdev = dev_get_drvdata(dev);
if (!kbdev)
return -ENODEV;
#ifdef CONFIG_MALI_MIDGARD_DVFS
locked_level = mali_get_dvfs_upper_locked_freq();
if (locked_level > 0)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Current Upper Lock Level = %dMhz", locked_level);
else
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Unset the Upper Lock Level");
/*ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings : 400, 350,266, 160, 100, If you want to unlock : 600 or off");*/
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings :");
for(i=0;i<MALI_DVFS_STEP;i++)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ",p_mali_dvfs_infotbl[i].clock/1000);
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Mhz");
ret += snprintf(buf + ret, PAGE_SIZE - ret, ", If you want to unlock : off");
#else
ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set");
#endif
if (ret < PAGE_SIZE - 1)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
else {
buf[PAGE_SIZE - 2] = '\n';
buf[PAGE_SIZE - 1] = '\0';
ret = PAGE_SIZE - 1;
}
return ret;
}
static ssize_t set_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct kbase_device *kbdev;
int i;
unsigned int freq;
kbdev = dev_get_drvdata(dev);
freq = 0;
if (!kbdev)
return -ENODEV;
freq = simple_strtoul(buf, NULL, 10);
#ifdef CONFIG_MALI_MIDGARD_DVFS
if (sysfs_streq("off", buf))
{
mali_dvfs_freq_unlock();
}
else
{
for(i=0;i<MALI_DVFS_STEP;i++)
{
if (p_mali_dvfs_infotbl[i].clock == freq)
{
mali_dvfs_freq_lock(i);
break;
}
if(i==MALI_DVFS_STEP)
{
dev_err(dev, "set_clock: invalid value\n");
return -ENOENT;
}
}
}
#else /* CONFIG_MALI_MIDGARD_DVFS */
printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
#endif
return count;
}
static ssize_t show_under_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
{
struct kbase_device *kbdev;
ssize_t ret = 0;
int i;
#ifdef CONFIG_MALI_MIDGARD_DVFS
int locked_level = -1;
#endif
kbdev = dev_get_drvdata(dev);
if (!kbdev)
return -ENODEV;
#ifdef CONFIG_MALI_MIDGARD_DVFS
locked_level = mali_get_dvfs_under_locked_freq();
if (locked_level > 0)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Current Under Lock Level = %dMhz", locked_level);
else
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Unset the Under Lock Level");
/*ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings : 600, 400, 350,266, 160, If you want to unlock : 100 or off");*/
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings :");
for(i=0;i<MALI_DVFS_STEP;i++)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ",p_mali_dvfs_infotbl[i].clock/1000);
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Mhz");
ret += snprintf(buf + ret, PAGE_SIZE - ret, ", If you want to unlock : off");
#else
ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set");
#endif
if (ret < PAGE_SIZE - 1)
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
else {
buf[PAGE_SIZE - 2] = '\n';
buf[PAGE_SIZE - 1] = '\0';
ret = PAGE_SIZE - 1;
}
return ret;
}
static ssize_t set_under_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int i;
unsigned int freq;
struct kbase_device *kbdev;
kbdev = dev_get_drvdata(dev);
freq = 0;
if (!kbdev)
return -ENODEV;
#ifdef CONFIG_MALI_MIDGARD_DVFS
if (sysfs_streq("off", buf))
{
mali_dvfs_freq_unlock();
}
else
{
for(i=0;i<MALI_DVFS_STEP;i++)
{
if (p_mali_dvfs_infotbl[i].clock == freq)
{
mali_dvfs_freq_lock(i);
break;
}
if(i==MALI_DVFS_STEP)
{
dev_err(dev, "set_clock: invalid value\n");
return -ENOENT;
}
}
}
#else /* CONFIG_MALI_MIDGARD_DVFS */
printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
#endif
return count;
}
/** The sysfs file @c clock, fbdev.
*
* This is used for obtaining information about the mali t6xx operating clock & framebuffer address,
*/
DEVICE_ATTR(clock, S_IRUGO | S_IWUSR, show_clock, set_clock);
DEVICE_ATTR(fbdev, S_IRUGO, show_fbdev, NULL);
DEVICE_ATTR(dtlb, S_IRUGO | S_IWUSR, show_dtlb, set_dtlb);
DEVICE_ATTR(dvfs, S_IRUGO | S_IWUSR, show_dvfs, set_dvfs);
DEVICE_ATTR(dvfs_upper_lock, S_IRUGO | S_IWUSR, show_upper_lock_dvfs, set_upper_lock_dvfs);
DEVICE_ATTR(dvfs_under_lock, S_IRUGO | S_IWUSR, show_under_lock_dvfs, set_under_lock_dvfs);
DEVICE_ATTR(time_in_state, S_IRUGO | S_IWUSR, show_time_in_state, set_time_in_state);
int kbase_platform_create_sysfs_file(struct device *dev)
{
if (device_create_file(dev, &dev_attr_clock)) {
dev_err(dev, "Couldn't create sysfs file [clock]\n");
goto out;
}
if (device_create_file(dev, &dev_attr_fbdev)) {
dev_err(dev, "Couldn't create sysfs file [fbdev]\n");
goto out;
}
if (device_create_file(dev, &dev_attr_dtlb)) {
dev_err(dev, "Couldn't create sysfs file [dtlb]\n");
goto out;
}
if (device_create_file(dev, &dev_attr_dvfs)) {
dev_err(dev, "Couldn't create sysfs file [dvfs]\n");
goto out;
}
if (device_create_file(dev, &dev_attr_dvfs_upper_lock)) {
dev_err(dev, "Couldn't create sysfs file [dvfs_upper_lock]\n");
goto out;
}
if (device_create_file(dev, &dev_attr_dvfs_under_lock)) {
dev_err(dev, "Couldn't create sysfs file [dvfs_under_lock]\n");
goto out;
}
if (device_create_file(dev, &dev_attr_time_in_state)) {
dev_err(dev, "Couldn't create sysfs file [time_in_state]\n");
goto out;
}
return 0;
out:
return -ENOENT;
}
void kbase_platform_remove_sysfs_file(struct device *dev)
{
device_remove_file(dev, &dev_attr_clock);
device_remove_file(dev, &dev_attr_fbdev);
device_remove_file(dev, &dev_attr_dtlb);
device_remove_file(dev, &dev_attr_dvfs);
device_remove_file(dev, &dev_attr_dvfs_upper_lock);
device_remove_file(dev, &dev_attr_dvfs_under_lock);
device_remove_file(dev, &dev_attr_time_in_state);
}
#endif /* CONFIG_MALI_MIDGARD_DEBUG_SYS */
mali_error kbase_platform_init(struct kbase_device *kbdev)
{
struct rk_context *platform;
int ret;
platform = kmalloc(sizeof(struct rk_context), GFP_KERNEL);
if (NULL == platform)
return MALI_ERROR_OUT_OF_MEMORY;
kbdev->platform_context = (void *)platform;
platform->cmu_pmu_status = 0;
#ifdef CONFIG_MALI_MIDGARD_DVFS
platform->utilisation = 0;
platform->time_busy = 0;
platform->time_idle = 0;
platform->time_tick = 0;
platform->dvfs_enabled = true;
#endif
rk_gpu = kobject_create_and_add("rk_gpu", NULL);
if (!rk_gpu)
return MALI_ERROR_FUNCTION_FAILED;
ret = sysfs_create_file(rk_gpu, &dev_attr_error_count.attr);
if(ret)
return MALI_ERROR_FUNCTION_FAILED;
spin_lock_init(&platform->cmu_pmu_lock);
if (kbase_platform_power_clock_init(kbdev))
goto clock_init_fail;
#ifdef CONFIG_MALI_MIDGARD_DVFS
kbase_platform_dvfs_init(kbdev);
#endif /* CONFIG_MALI_MIDGARD_DVFS */
/* Enable power */
kbase_platform_cmu_pmu_control(kbdev, 1);
return MALI_ERROR_NONE;
clock_init_fail:
kfree(platform);
return MALI_ERROR_FUNCTION_FAILED;
}
void kbase_platform_term(struct kbase_device *kbdev)
{
struct rk_context *platform;
platform = (struct rk_context *)kbdev->platform_context;
#ifdef CONFIG_MALI_MIDGARD_DVFS
kbase_platform_dvfs_term();
#endif /* CONFIG_MALI_MIDGARD_DVFS */
/* Disable power */
kbase_platform_cmu_pmu_control(kbdev, 0);
kfree(kbdev->platform_context);
kbdev->platform_context = 0;
return;
}

View File

@@ -0,0 +1,50 @@
/* drivers/gpu/t6xx/kbase/src/platform/rk/mali_kbase_platform.h
* Rockchip SoC Mali-T764 platform-dependent codes
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software FoundatIon.
*/
/**
* @file mali_kbase_platform.h
* Platform-dependent init
*/
#ifndef _KBASE_PLATFORM_H_
#define _KBASE_PLATFORM_H_
struct rk_context {
/** Indicator if system clock to mail-t604 is active */
int cmu_pmu_status;
/** cmd & pmu lock */
spinlock_t cmu_pmu_lock;
struct clk *mali_pd;
struct dvfs_node * mali_clk_node;
#ifdef CONFIG_MALI_MIDGARD_DVFS
/*To calculate utilization for x sec */
int time_tick;
int utilisation;
u32 time_busy;
u32 time_idle;
bool dvfs_enabled;
bool gpu_in_touch;
spinlock_t gpu_in_touch_lock;
#endif
};
int mali_dvfs_clk_set(struct dvfs_node * node,unsigned long rate);
/* All things that are needed for the Linux port. */
int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control);
int kbase_platform_create_sysfs_file(struct device *dev);
void kbase_platform_remove_sysfs_file(struct device *dev);
int kbase_platform_is_power_on(void);
mali_error kbase_platform_init(struct kbase_device *kbdev);
void kbase_platform_term(struct kbase_device *kbdev);
int kbase_platform_clock_on(struct kbase_device *kbdev);
int kbase_platform_clock_off(struct kbase_device *kbdev);
int kbase_platform_power_off(struct kbase_device *kbdev);
int kbase_platform_power_on(struct kbase_device *kbdev);
#endif /* _KBASE_PLATFORM_H_ */