| /* |
| * platform_gx.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #include <linux/platform_device.h> |
| #include <linux/version.h> |
| #include <linux/pm.h> |
| #include <linux/of.h> |
| #include <linux/module.h> /* kernel module definitions */ |
| #include <linux/ioport.h> /* request_mem_region */ |
| #include <linux/slab.h> |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29)) |
| #include <mach/register.h> |
| #include <mach/irqs.h> |
| #include <mach/io.h> |
| #endif |
| #include <asm/io.h> |
| #ifdef CONFIG_AMLOGIC_GPU_THERMAL |
| #include <linux/amlogic/gpu_cooling.h> |
| #include <linux/amlogic/gpucore_cooling.h> |
| //#include <linux/amlogic/aml_thermal_hw.h> |
| #include <linux/amlogic/meson_cooldev.h> |
| #endif |
| |
| #include "mali_scaling.h" |
| #include "mali_clock.h" |
| #include "meson_main2.h" |
| |
| /* |
| * For Meson 8 M2. |
| * |
| */ |
| static void mali_plat_preheat(void); |
| static mali_plat_info_t mali_plat_data = { |
| .bst_gpu = 210, /* threshold for boosting gpu. */ |
| .bst_pp = 160, /* threshold for boosting PP. */ |
| .have_switch = 1, |
| .limit_on = 1, |
| .plat_preheat = mali_plat_preheat, |
| }; |
| |
| static void mali_plat_preheat(void) |
| { |
| #ifndef CONFIG_MALI_DVFS |
| u32 pre_fs; |
| u32 clk, pp; |
| |
| if (get_mali_schel_mode() != MALI_PP_FS_SCALING) |
| return; |
| |
| get_mali_rt_clkpp(&clk, &pp); |
| pre_fs = mali_plat_data.def_clock + 1; |
| if (clk < pre_fs) |
| clk = pre_fs; |
| if (pp < mali_plat_data.sc_mpp) |
| pp = mali_plat_data.sc_mpp; |
| set_mali_rt_clkpp(clk, pp, 1); |
| #endif |
| } |
| |
| mali_plat_info_t* get_mali_plat_data(void) { |
| return &mali_plat_data; |
| } |
| |
| int get_mali_freq_level(int freq) |
| { |
| int i = 0, level = -1; |
| int mali_freq_num; |
| |
| if (freq < 0) |
| return level; |
| |
| mali_freq_num = mali_plat_data.dvfs_table_size - 1; |
| if (freq <= mali_plat_data.clk_sample[0]) |
| level = mali_freq_num-1; |
| else if (freq >= mali_plat_data.clk_sample[mali_freq_num - 1]) |
| level = 0; |
| else { |
| for (i=0; i<mali_freq_num - 1 ;i++) { |
| if (freq >= mali_plat_data.clk_sample[i] && freq <= mali_plat_data.clk_sample[i + 1]) { |
| level = i; |
| level = mali_freq_num-level - 1; |
| } |
| } |
| } |
| return level; |
| } |
| |
| unsigned int get_mali_max_level(void) |
| { |
| return mali_plat_data.dvfs_table_size - 1; |
| } |
| |
| int get_gpu_max_clk_level(void) |
| { |
| return mali_plat_data.cfg_clock; |
| } |
| |
| #ifdef CONFIG_AMLOGIC_GPU_THERMAL |
| static void set_limit_mali_freq(u32 idx) |
| { |
| if (mali_plat_data.limit_on == 0) |
| return; |
| if (idx > mali_plat_data.turbo_clock || idx < mali_plat_data.scale_info.minclk) |
| return; |
| if (idx > mali_plat_data.maxclk_sysfs) { |
| printk("idx > max freq\n"); |
| return; |
| } |
| mali_plat_data.scale_info.maxclk= idx; |
| revise_mali_rt(); |
| } |
| |
| static u32 get_limit_mali_freq(void) |
| { |
| return mali_plat_data.scale_info.maxclk; |
| } |
| |
| #ifdef CONFIG_DEVFREQ_THERMAL |
| static u32 get_mali_utilization(void) |
| { |
| #ifndef MESON_DRV_BRING |
| return 55; |
| #else |
| return (_mali_ukk_utilization_pp() * 100) / 256; |
| #endif |
| } |
| #endif |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_GPU_THERMAL |
| static u32 set_limit_pp_num(u32 num) |
| { |
| u32 ret = -1; |
| if (mali_plat_data.limit_on == 0) |
| goto quit; |
| if (num > mali_plat_data.cfg_pp || |
| num < mali_plat_data.scale_info.minpp) |
| goto quit; |
| |
| if (num > mali_plat_data.maxpp_sysfs) { |
| printk("pp > sysfs set pp\n"); |
| goto quit; |
| } |
| |
| mali_plat_data.scale_info.maxpp = num; |
| revise_mali_rt(); |
| ret = 0; |
| quit: |
| return ret; |
| } |
| #ifdef CONFIG_DEVFREQ_THERMAL |
| /* note: |
| * why return the config_pp which come from dts [num_of_pp] dirrectly |
| * 1. the return value only used for thermal, |
| * and we have not dynamic adjust the core num. |
| * 2. avoid influent the IC before T5. |
| * TODO: need improve it, if we add dynamic adjust the core num.*/ |
| static u32 mali_get_online_pp(void) |
| { |
| u32 fix_pp_num = mali_plat_data.cfg_pp; |
| |
| return fix_pp_num; |
| } |
| #endif |
| #endif |
| |
| int mali_meson_init_start(struct platform_device* ptr_plt_dev) |
| { |
| //dev_set_drvdata(&ptr_plt_dev->dev, &mali_plat_data); |
| mali_dt_info(ptr_plt_dev, &mali_plat_data); |
| mali_clock_init_clk_tree(ptr_plt_dev); |
| return 0; |
| } |
| |
| int mali_meson_init_finish(struct platform_device* ptr_plt_dev) |
| { |
| if (mali_core_scaling_init(&mali_plat_data) < 0) |
| return -1; |
| return 0; |
| } |
| |
| int mali_meson_uninit(struct platform_device* ptr_plt_dev) |
| { |
| mali_core_scaling_term(); |
| return 0; |
| } |
| |
| void mali_post_init(void) |
| { |
| #ifdef CONFIG_AMLOGIC_GPU_THERMAL |
| int err; |
| struct gpufreq_cooling_device *gcdev = NULL; |
| struct gpucore_cooling_device *gccdev = NULL; |
| |
| gcdev = gpufreq_cooling_alloc(); |
| register_gpu_freq_info(get_current_frequency); |
| if (IS_ERR(gcdev)) |
| printk("malloc gpu cooling buffer error!!\n"); |
| else if (!gcdev) |
| printk("system does not enable thermal driver\n"); |
| else { |
| gcdev->get_gpu_freq_level = get_mali_freq_level; |
| gcdev->get_gpu_max_level = get_mali_max_level; |
| gcdev->set_gpu_freq_idx = set_limit_mali_freq; |
| gcdev->get_gpu_current_max_level = get_limit_mali_freq; |
| #ifdef CONFIG_DEVFREQ_THERMAL |
| gcdev->get_gpu_freq = get_mali_freq; |
| gcdev->get_gpu_loading = get_mali_utilization; |
| gcdev->get_online_pp = mali_get_online_pp; |
| #endif |
| err = gpufreq_cooling_register(gcdev); |
| #ifdef CONFIG_DEVFREQ_THERMAL |
| meson_gcooldev_min_update(gcdev->cool_dev); |
| #endif |
| if (err < 0) |
| printk("register GPU cooling error\n"); |
| printk("gpu cooling register okay with err=%d\n",err); |
| } |
| |
| gccdev = gpucore_cooling_alloc(); |
| if (IS_ERR(gccdev)) |
| printk("malloc gpu core cooling buffer error!!\n"); |
| else if (!gccdev) |
| printk("system does not enable thermal driver\n"); |
| else { |
| gccdev->max_gpu_core_num=mali_plat_data.cfg_pp; |
| gccdev->set_max_pp_num=set_limit_pp_num; |
| err = (int)gpucore_cooling_register(gccdev); |
| #ifdef CONFIG_DEVFREQ_THERMAL |
| meson_gcooldev_min_update(gccdev->cool_dev); |
| #endif |
| if (err < 0) |
| printk("register GPU cooling error\n"); |
| printk("gpu core cooling register okay with err=%d\n",err); |
| } |
| #endif |
| } |