c05564c4d8
Android 13
2938 lines
73 KiB
C
Executable file
2938 lines
73 KiB
C
Executable file
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include "mdla_debug.h"
|
|
#include "mdla.h"
|
|
#include "mdla_pmu.h"
|
|
#include "mdla_hw_reg.h"
|
|
#include "mdla_ioctl.h"
|
|
#include "mdla_trace.h"
|
|
#include "mdla_dvfs.h"
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
#ifndef MTK_MDLA_FPGA_PORTING
|
|
#define ENABLE_PMQOS
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/soc/mediatek/mtk-pm-qos.h>
|
|
#include "apu_dvfs.h"
|
|
#include <linux/regulator/consumer.h>
|
|
#include "vpu_dvfs.h"
|
|
#ifdef CONFIG_MTK_DEVINFO
|
|
#include <linux/nvmem-consumer.h>
|
|
#include <linux/slab.h>
|
|
#endif
|
|
#include "mtk_qos_bound.h"
|
|
#include <linux/pm_qos.h>
|
|
|
|
#ifdef MTK_PERF_OBSERVER
|
|
#include <mt-plat/mtk_perfobserver.h>
|
|
#endif
|
|
|
|
static uint32_t g_efuse_segment;
|
|
static inline uint32_t get_devinfo_with_index(int idx)
|
|
{
|
|
return g_efuse_segment;
|
|
}
|
|
|
|
/* opp, mW */
|
|
struct MDLA_OPP_INFO mdla_power_table[MDLA_OPP_NUM] = {
|
|
{MDLA_OPP_0, 688},
|
|
{MDLA_OPP_1, 611},
|
|
{MDLA_OPP_2, 544},
|
|
{MDLA_OPP_3, 400},
|
|
{MDLA_OPP_4, 392},
|
|
{MDLA_OPP_5, 360},
|
|
{MDLA_OPP_6, 346},
|
|
{MDLA_OPP_7, 297},
|
|
{MDLA_OPP_8, 274},
|
|
{MDLA_OPP_9, 192},
|
|
{MDLA_OPP_10, 164},
|
|
{MDLA_OPP_11, 144},
|
|
{MDLA_OPP_12, 109},
|
|
|
|
};
|
|
#define CMD_WAIT_TIME_MS (3 * 1000)
|
|
#define OPP_WAIT_TIME_MS (300)
|
|
#define PWR_KEEP_TIME_MS (500)
|
|
#define OPP_KEEP_TIME_MS (500)
|
|
#define POWER_ON_MAGIC (2)
|
|
#define OPPTYPE_VCORE (0)
|
|
#define OPPTYPE_DSPFREQ (1)
|
|
#define OPPTYPE_VVPU (2)
|
|
#define OPPTYPE_VMDLA (3)
|
|
|
|
/* clock */
|
|
static struct clk *clk_top_dsp_sel;
|
|
static struct clk *clk_top_dsp3_sel;
|
|
static struct clk *clk_top_ipu_if_sel;
|
|
static struct clk *clk_apu_mdla_apb_cg;
|
|
static struct clk *clk_apu_mdla_cg_b0;
|
|
static struct clk *clk_apu_mdla_cg_b1;
|
|
static struct clk *clk_apu_mdla_cg_b2;
|
|
static struct clk *clk_apu_mdla_cg_b3;
|
|
static struct clk *clk_apu_mdla_cg_b4;
|
|
static struct clk *clk_apu_mdla_cg_b5;
|
|
static struct clk *clk_apu_mdla_cg_b6;
|
|
static struct clk *clk_apu_mdla_cg_b7;
|
|
static struct clk *clk_apu_mdla_cg_b8;
|
|
static struct clk *clk_apu_mdla_cg_b9;
|
|
static struct clk *clk_apu_mdla_cg_b10;
|
|
static struct clk *clk_apu_mdla_cg_b11;
|
|
static struct clk *clk_apu_mdla_cg_b12;
|
|
static struct clk *clk_apu_conn_apu_cg;
|
|
static struct clk *clk_apu_conn_ahb_cg;
|
|
static struct clk *clk_apu_conn_axi_cg;
|
|
static struct clk *clk_apu_conn_isp_cg;
|
|
static struct clk *clk_apu_conn_cam_adl_cg;
|
|
static struct clk *clk_apu_conn_img_adl_cg;
|
|
static struct clk *clk_apu_conn_emi_26m_cg;
|
|
static struct clk *clk_apu_conn_vpu_udi_cg;
|
|
static struct clk *clk_apu_vcore_ahb_cg;
|
|
static struct clk *clk_apu_vcore_axi_cg;
|
|
static struct clk *clk_apu_vcore_adl_cg;
|
|
static struct clk *clk_apu_vcore_qos_cg;
|
|
static struct clk *clk_apu_vcore_qos_cg;
|
|
static struct clk *clk_top_clk26m;
|
|
static struct clk *clk_top_univpll_d3_d8;
|
|
static struct clk *clk_top_univpll_d3_d4;
|
|
static struct clk *clk_top_mainpll_d2_d4;
|
|
static struct clk *clk_top_univpll_d3_d2;
|
|
static struct clk *clk_top_mainpll_d2_d2;
|
|
static struct clk *clk_top_univpll_d2_d2;
|
|
static struct clk *clk_top_mainpll_d3;
|
|
static struct clk *clk_top_univpll_d3;
|
|
static struct clk *clk_top_mmpll_d7;
|
|
static struct clk *clk_top_mmpll_d6;
|
|
static struct clk *clk_top_adsppll_d5;
|
|
static struct clk *clk_top_tvdpll_ck;
|
|
static struct clk *clk_top_tvdpll_mainpll_d2_ck;
|
|
static struct clk *clk_top_univpll_d2;
|
|
static struct clk *clk_top_adsppll_d4;
|
|
static struct clk *clk_top_mainpll_d2;
|
|
static struct clk *clk_top_mmpll_d4;
|
|
|
|
|
|
|
|
/* mtcmos */
|
|
static struct clk *mtcmos_dis;
|
|
|
|
//static struct clk *mtcmos_vpu_vcore_dormant;
|
|
static struct clk *mtcmos_vpu_vcore_shutdown;
|
|
//static struct clk *mtcmos_vpu_conn_dormant;
|
|
static struct clk *mtcmos_vpu_conn_shutdown;
|
|
//static struct clk *mtcmos_vpu_core2_dormant;
|
|
static struct clk *mtcmos_vpu_core2_shutdown;
|
|
|
|
/* smi */
|
|
static struct clk *clk_mmsys_gals_ipu2mm;
|
|
static struct clk *clk_mmsys_gals_ipu12mm;
|
|
static struct clk *clk_mmsys_gals_comm0;
|
|
static struct clk *clk_mmsys_gals_comm1;
|
|
static struct clk *clk_mmsys_smi_common;
|
|
/* workqueue */
|
|
struct my_struct_t {
|
|
int core;
|
|
struct delayed_work my_work;
|
|
};
|
|
static struct workqueue_struct *wq;
|
|
static void mdla_power_counter_routine(struct work_struct *);
|
|
static struct my_struct_t power_counter_work[MTK_MDLA_USER];
|
|
|
|
/* static struct workqueue_struct *opp_wq; */
|
|
static void mdla_opp_keep_routine(struct work_struct *);
|
|
static DECLARE_DELAYED_WORK(opp_keep_work, mdla_opp_keep_routine);
|
|
|
|
|
|
/* power */
|
|
static struct mutex power_mutex[MTK_MDLA_USER];
|
|
static bool is_power_on[MTK_MDLA_USER];
|
|
static bool is_power_debug_lock;
|
|
static struct mutex power_counter_mutex[MTK_MDLA_USER];
|
|
static int power_counter[MTK_MDLA_USER];
|
|
static struct mutex opp_mutex;
|
|
static bool force_change_vcore_opp[MTK_MDLA_USER];
|
|
static bool force_change_vvpu_opp[MTK_MDLA_USER];
|
|
static bool force_change_vmdla_opp[MTK_MDLA_USER];
|
|
static bool force_change_dsp_freq[MTK_MDLA_USER];
|
|
static bool change_freq_first[MTK_MDLA_USER];
|
|
static bool opp_keep_flag;
|
|
static uint8_t max_vcore_opp;
|
|
//static uint8_t max_vvpu_opp;
|
|
static uint8_t max_vmdla_opp;
|
|
static uint8_t max_dsp_freq;
|
|
static struct mdla_lock_power lock_power[MDLA_OPP_PRIORIYY_NUM][MTK_MDLA_USER];
|
|
static uint8_t max_opp[MTK_MDLA_USER];
|
|
static uint8_t min_opp[MTK_MDLA_USER];
|
|
static uint8_t maxboost[MTK_MDLA_USER];
|
|
static uint8_t minboost[MTK_MDLA_USER];
|
|
static struct mutex power_lock_mutex;
|
|
|
|
/* dvfs */
|
|
static struct mdla_dvfs_opps opps;
|
|
#ifdef ENABLE_PMQOS
|
|
static struct mtk_pm_qos_request mdla_qos_bw_request[MTK_MDLA_USER];
|
|
static struct mtk_pm_qos_request mdla_qos_vcore_request[MTK_MDLA_USER];
|
|
static struct mtk_pm_qos_request mdla_qos_vvpu_request[MTK_MDLA_USER];
|
|
static struct mtk_pm_qos_request mdla_qos_vmdla_request[MTK_MDLA_USER];
|
|
#endif
|
|
|
|
/*regulator id*/
|
|
static struct regulator *vvpu_reg_id;
|
|
static struct regulator *vmdla_reg_id;
|
|
|
|
static int mdla_init_done;
|
|
static uint8_t segment_max_opp;
|
|
static uint8_t segment_index;
|
|
|
|
/* static function prototypes */
|
|
static int mdla_boot_up(int core);
|
|
static int mdla_shut_down(int core);
|
|
static bool mdla_update_lock_power_parameter
|
|
(struct mdla_lock_power *mdla_lock_power);
|
|
static bool mdla_update_unlock_power_parameter
|
|
(struct mdla_lock_power *mdla_lock_power);
|
|
static uint8_t mdla_boost_value_to_opp(uint8_t boost_value);
|
|
static int mdla_lock_set_power(struct mdla_lock_power *mdla_lock_power);
|
|
|
|
static inline int atf_vcore_cg_ctl(int state)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
arm_smccc_smc(MTK_SIP_KERNEL_APU_VCORE_CG_CTL
|
|
, state, 0, 0, 0, 0, 0, 0, &res);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int Map_MDLA_Freq_Table(int freq_opp)
|
|
{
|
|
int freq_value = 0;
|
|
|
|
switch (freq_opp) {
|
|
case 0:
|
|
default:
|
|
freq_value = 788;
|
|
break;
|
|
case 1:
|
|
freq_value = 700;
|
|
break;
|
|
case 2:
|
|
freq_value = 624;
|
|
break;
|
|
case 3:
|
|
freq_value = 606;
|
|
break;
|
|
case 4:
|
|
freq_value = 594;
|
|
break;
|
|
case 5:
|
|
freq_value = 546;
|
|
break;
|
|
case 6:
|
|
freq_value = 525;
|
|
break;
|
|
case 7:
|
|
freq_value = 450;
|
|
break;
|
|
case 8:
|
|
freq_value = 416;
|
|
break;
|
|
case 9:
|
|
freq_value = 364;
|
|
break;
|
|
case 10:
|
|
freq_value = 312;
|
|
break;
|
|
case 11:
|
|
freq_value = 273;
|
|
break;
|
|
case 12:
|
|
freq_value = 208;
|
|
break;
|
|
case 13:
|
|
freq_value = 137;
|
|
break;
|
|
case 14:
|
|
freq_value = 52;
|
|
break;
|
|
case 15:
|
|
freq_value = 26;
|
|
break;
|
|
}
|
|
|
|
return freq_value;
|
|
}
|
|
#if defined(MDLA_MET_READY)
|
|
void MDLA_MET_Events_Trace(bool enter, int core)
|
|
{
|
|
int vmdla_opp = 0;
|
|
int dsp_freq = 0, ipu_if_freq = 0, mdla_freq = 0;
|
|
|
|
if (enter) {
|
|
/* only read for debug purpose*/
|
|
/*mutex_lock(&opp_mutex);*/
|
|
vmdla_opp = opps.vmdla.index;
|
|
dsp_freq = Map_MDLA_Freq_Table(opps.dsp.index);
|
|
ipu_if_freq = Map_MDLA_Freq_Table(opps.ipu_if.index);
|
|
mdla_freq = Map_MDLA_Freq_Table(opps.mdlacore.index);
|
|
/*mutex_unlock(&opp_mutex);*/
|
|
mdla_met_event_enter(core, vmdla_opp, dsp_freq,
|
|
ipu_if_freq, mdla_freq);
|
|
} else {
|
|
mdla_met_event_leave(core);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int mdla_set_clock_source(struct clk *clk, uint8_t step)
|
|
{
|
|
struct clk *clk_src;
|
|
|
|
LOG_DBG("mdla scc(%d)", step);
|
|
/* set dsp frequency - 0:788 MHz, 1:700 MHz, 2:606 MHz, 3:594 MHz*/
|
|
/* set dsp frequency - 4:560 MHz, 5:525 MHz, 6:450 MHz, 7:416 MHz*/
|
|
/* set dsp frequency - 8:364 MHz, 9:312 MHz, 10:273 MH, 11:208 MH*/
|
|
/* set dsp frequency - 12:137 MHz, 13:104 MHz, 14:52 MHz, 15:26 MHz*/
|
|
|
|
switch (step) {
|
|
case 0:
|
|
clk_src = clk_top_mmpll_d4;
|
|
break;
|
|
case 1:
|
|
clk_src = clk_top_adsppll_d4;
|
|
break;
|
|
case 2:
|
|
clk_src = clk_top_univpll_d2;
|
|
break;
|
|
case 3:
|
|
clk_src = clk_top_tvdpll_mainpll_d2_ck;
|
|
break;
|
|
case 4:
|
|
clk_src = clk_top_tvdpll_ck;
|
|
break;
|
|
case 5:
|
|
clk_src = clk_top_mainpll_d2;
|
|
break;
|
|
case 6:
|
|
clk_src = clk_top_mmpll_d6;
|
|
break;
|
|
case 7:
|
|
clk_src = clk_top_mmpll_d7;
|
|
break;
|
|
case 8:
|
|
clk_src = clk_top_univpll_d3;
|
|
break;
|
|
case 9:
|
|
clk_src = clk_top_mainpll_d3;
|
|
break;
|
|
case 10:
|
|
clk_src = clk_top_univpll_d2_d2;
|
|
break;
|
|
case 11:
|
|
clk_src = clk_top_mainpll_d2_d2;
|
|
break;
|
|
case 12:
|
|
clk_src = clk_top_univpll_d3_d2;
|
|
break;
|
|
case 13:
|
|
clk_src = clk_top_mainpll_d2_d4;
|
|
break;
|
|
case 14:
|
|
clk_src = clk_top_univpll_d3_d8;
|
|
break;
|
|
case 15:
|
|
clk_src = clk_top_clk26m;
|
|
break;
|
|
default:
|
|
LOG_ERR("wrong freq step(%d)", step);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return clk_set_parent(clk, clk_src);
|
|
}
|
|
/*set CONN hf_fdsp_ck, VCORE hf_fipu_if_ck*/
|
|
static int mdla_if_set_clock_source(struct clk *clk, uint8_t step)
|
|
{
|
|
struct clk *clk_src;
|
|
|
|
LOG_DBG("mdla scc(%d)", step);
|
|
/* set dsp frequency - 0:624 MHz, 1:624 MHz, 2:606 MHz, 3:594 MHz*/
|
|
/* set dsp frequency - 4:560 MHz, 5:525 MHz, 6:450 MHz, 7:416 MHz*/
|
|
/* set dsp frequency - 8:364 MHz, 9:312 MHz, 10:273 MH, 11:208 MH*/
|
|
/* set dsp frequency - 12:137 MHz, 13:104 MHz, 14:52 MHz, 15:26 MHz*/
|
|
switch (step) {
|
|
case 0:
|
|
clk_src = clk_top_univpll_d2;/*624MHz*/
|
|
break;
|
|
case 1:
|
|
clk_src = clk_top_univpll_d2;/*624MHz*/
|
|
break;
|
|
case 2:
|
|
clk_src = clk_top_tvdpll_mainpll_d2_ck;
|
|
break;
|
|
case 3:
|
|
clk_src = clk_top_tvdpll_ck;
|
|
break;
|
|
case 4:
|
|
clk_src = clk_top_adsppll_d5;
|
|
break;
|
|
case 5:
|
|
clk_src = clk_top_mmpll_d6;
|
|
break;
|
|
case 6:
|
|
clk_src = clk_top_mmpll_d7;
|
|
break;
|
|
case 7:
|
|
clk_src = clk_top_univpll_d3;
|
|
break;
|
|
case 8:
|
|
clk_src = clk_top_mainpll_d3;
|
|
break;
|
|
case 9:
|
|
clk_src = clk_top_univpll_d2_d2;
|
|
break;
|
|
case 10:
|
|
clk_src = clk_top_mainpll_d2_d2;
|
|
break;
|
|
case 11:
|
|
clk_src = clk_top_univpll_d3_d2;
|
|
break;
|
|
case 12:
|
|
clk_src = clk_top_mainpll_d2_d4;
|
|
break;
|
|
case 13:
|
|
clk_src = clk_top_univpll_d3_d4;
|
|
break;
|
|
case 14:
|
|
clk_src = clk_top_univpll_d3_d8;
|
|
break;
|
|
case 15:
|
|
clk_src = clk_top_clk26m;
|
|
break;
|
|
default:
|
|
LOG_ERR("wrong freq step(%d)", step);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return clk_set_parent(clk, clk_src);
|
|
}
|
|
|
|
|
|
int mdla_get_bw(void)
|
|
{
|
|
struct qos_bound *bound = get_qos_bound();
|
|
int bw = 0;
|
|
|
|
bw = bound->stats[bound->idx].smibw_mon[QOS_SMIBM_MDLA];
|
|
|
|
mdla_dvfs_debug("[mdla] cmd bw=%d\n", bw);
|
|
|
|
return bw;
|
|
|
|
}
|
|
|
|
int mdla_get_lat(void)
|
|
{
|
|
struct qos_bound *bound = get_qos_bound();
|
|
int lat = 0;
|
|
|
|
lat = bound->stats[bound->idx].lat_mon[QOS_LAT_MDLA];
|
|
mdla_dvfs_debug("[mdla] cmd latency=%d\n", lat);
|
|
return lat;
|
|
}
|
|
|
|
int mdla_get_opp(void)
|
|
{
|
|
LOG_DBG("[mdla] mdlacore.index:%d\n", opps.mdlacore.index);
|
|
LOG_DBG("[mdla] opps.dsp.index:%d\n", opps.dsp.index);
|
|
return opps.dsp.index;
|
|
}
|
|
EXPORT_SYMBOL(mdla_get_opp);
|
|
|
|
int get_mdlacore_opp(void)
|
|
{
|
|
LOG_DBG("[mdla] get opp:%d\n", opps.mdlacore.index);
|
|
return opps.mdlacore.index;
|
|
}
|
|
EXPORT_SYMBOL(get_mdlacore_opp);
|
|
|
|
int get_mdla_platform_floor_opp(void)
|
|
{
|
|
return (MDLA_MAX_NUM_OPPS - 1);
|
|
}
|
|
EXPORT_SYMBOL(get_mdla_platform_floor_opp);
|
|
|
|
int get_mdla_ceiling_opp(void)
|
|
{
|
|
return max_opp[0];
|
|
}
|
|
EXPORT_SYMBOL(get_mdla_ceiling_opp);
|
|
|
|
int get_mdla_opp_to_freq(uint8_t step)
|
|
{
|
|
int freq = 0;
|
|
/* set dsp frequency - 0:788 MHz, 1:700 MHz, 2:606 MHz, 3:594 MHz*/
|
|
/* set dsp frequency - 4:560 MHz, 5:525 MHz, 6:450 MHz, 7:416 MHz*/
|
|
/* set dsp frequency - 8:364 MHz, 9:312 MHz, 10:273 MH, 11:208 MH*/
|
|
/* set dsp frequency - 12:137 MHz, 13:104 MHz, 14:52 MHz, 15:26 MHz*/
|
|
|
|
switch (step) {
|
|
case 0:
|
|
freq = 788;
|
|
break;
|
|
case 1:
|
|
freq = 700;
|
|
break;
|
|
case 2:
|
|
freq = 606;
|
|
break;
|
|
case 3:
|
|
freq = 594;
|
|
break;
|
|
case 4:
|
|
freq = 560;
|
|
break;
|
|
case 5:
|
|
freq = 525;
|
|
break;
|
|
case 6:
|
|
freq = 450;
|
|
break;
|
|
case 7:
|
|
freq = 416;
|
|
break;
|
|
case 8:
|
|
freq = 364;
|
|
break;
|
|
case 9:
|
|
freq = 312;
|
|
break;
|
|
case 10:
|
|
freq = 273;
|
|
break;
|
|
case 11:
|
|
freq = 208;
|
|
break;
|
|
case 12:
|
|
freq = 137;
|
|
break;
|
|
case 13:
|
|
freq = 104;
|
|
break;
|
|
case 14:
|
|
freq = 52;
|
|
break;
|
|
case 15:
|
|
freq = 26;
|
|
break;
|
|
|
|
default:
|
|
LOG_ERR("wrong freq step(%d)", step);
|
|
return -EINVAL;
|
|
}
|
|
return freq;
|
|
}
|
|
EXPORT_SYMBOL(get_mdla_opp_to_freq);
|
|
|
|
static void mdla_dsp_if_freq_check(int core, uint8_t vmdla_index)
|
|
{
|
|
uint8_t vpu0_opp;
|
|
uint8_t vpu1_opp;
|
|
uint8_t vvpu_opp;
|
|
#ifdef MTK_VPU_SUPPORT
|
|
vpu0_opp = get_vpu_dspcore_opp(0);
|
|
vpu1_opp = get_vpu_dspcore_opp(1);
|
|
if (vpu1_opp < vpu0_opp)
|
|
vvpu_opp = vpu1_opp;
|
|
else
|
|
vvpu_opp = vpu0_opp;
|
|
#else
|
|
vpu0_opp = 15;
|
|
vpu1_opp = 15;
|
|
vvpu_opp = 15;
|
|
#endif
|
|
mdla_dvfs_debug("[mdla] vpu0_opp %d, vpu1_opp %d, vvpu_opp %d\n",
|
|
vpu0_opp, vpu1_opp, vvpu_opp);
|
|
switch (vmdla_index) {
|
|
case 0:
|
|
opps.dsp.index = 0;
|
|
opps.ipu_if.index = 5;
|
|
break;
|
|
case 1:
|
|
opps.dsp.index = 0;
|
|
opps.ipu_if.index = 5;
|
|
break;
|
|
case 2:
|
|
opps.dsp.index = 0;
|
|
opps.ipu_if.index = 5;
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
opps.dsp.index = 5;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 5) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 7:
|
|
opps.dsp.index = 6;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 6) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 8:
|
|
opps.dsp.index = 7;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 7) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 9:
|
|
opps.dsp.index = 9;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 9) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 10:
|
|
opps.dsp.index = 10;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 10) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 11:
|
|
opps.dsp.index = 11;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 11) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 12:
|
|
opps.dsp.index = 12;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 12) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 13:
|
|
opps.dsp.index = 13;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 13) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 14:
|
|
opps.dsp.index = 14;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 14) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
case 15:
|
|
opps.dsp.index = 15;
|
|
opps.ipu_if.index = 9;
|
|
if (vvpu_opp <= 15) {
|
|
opps.dsp.index = vvpu_opp;
|
|
//opps.ipu_if.index = vvpu_opp;
|
|
}
|
|
break;
|
|
default:
|
|
LOG_ERR("wrong vmdla_index(%d)", vmdla_index);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
static void get_segment_from_efuse(void)
|
|
{
|
|
int segment = 0;
|
|
|
|
segment = get_devinfo_with_index(7) & 0xFF;
|
|
switch (segment) {
|
|
case 0x7://segment p90M 5mode
|
|
segment_max_opp = 0;
|
|
segment_index = SEGMENT_90M;
|
|
break;
|
|
case 0xE0://segment p90M 6mode 525M
|
|
segment_max_opp = 0;
|
|
segment_index = SEGMENT_90M;
|
|
break;
|
|
case 0x20://p95
|
|
case 0x4:
|
|
case 0x60:
|
|
case 0x6:
|
|
case 0x10:
|
|
case 0x8:
|
|
case 0x90:
|
|
case 0x9:
|
|
segment_max_opp = 0;
|
|
segment_index = SEGMENT_95;
|
|
break;
|
|
default: //segment p90
|
|
segment_max_opp = 0;
|
|
segment_index = SEGMENT_90;
|
|
break;
|
|
}
|
|
mdla_dvfs_debug("mdla segment_max_opp %d\n", segment_max_opp);
|
|
}
|
|
|
|
/* expected range, vmdla_index: 0~15 */
|
|
/* expected range, freq_index: 0~15 */
|
|
void mdla_opp_check(int core_s, uint8_t vmdla_index, uint8_t freq_index)
|
|
{
|
|
int i = 0;
|
|
bool freq_check = false;
|
|
int log_freq = 0, log_max_freq = 0;
|
|
//int get_vcore_opp = 0;
|
|
//int get_vvpu_opp = 0;
|
|
int get_vmdla_opp = 0;
|
|
unsigned int core = (unsigned int)core_s;
|
|
|
|
if (is_power_debug_lock) {
|
|
force_change_vcore_opp[core] = false;
|
|
force_change_vvpu_opp[core] = false;
|
|
force_change_vmdla_opp[core] = false;
|
|
force_change_dsp_freq[core] = false;
|
|
goto out;
|
|
}
|
|
|
|
log_freq = Map_MDLA_Freq_Table(freq_index);
|
|
|
|
mdla_dvfs_debug("opp_check + (%d/%d/%d), ori vmdla(%d)\n", core,
|
|
vmdla_index, freq_index, opps.vmdla.index);
|
|
|
|
mutex_lock(&opp_mutex);
|
|
change_freq_first[core] = false;
|
|
log_max_freq = Map_MDLA_Freq_Table(max_dsp_freq);
|
|
/*segment limitation*/
|
|
if (vmdla_index < opps.vmdla.opp_map[segment_max_opp])
|
|
vmdla_index = opps.vmdla.opp_map[segment_max_opp];
|
|
if (freq_index < segment_max_opp)
|
|
freq_index = segment_max_opp;
|
|
|
|
/* vmdla opp*/
|
|
get_vmdla_opp = mdla_get_hw_vmdla_opp(core);
|
|
|
|
if (vmdla_index < opps.vmdla.opp_map[max_opp[core]])
|
|
vmdla_index = opps.vmdla.opp_map[max_opp[core]];
|
|
if (vmdla_index > opps.vmdla.opp_map[min_opp[core]])
|
|
vmdla_index = opps.vmdla.opp_map[min_opp[core]];
|
|
if (freq_index < max_opp[core])
|
|
freq_index = max_opp[core];
|
|
if (freq_index > min_opp[core])
|
|
freq_index = min_opp[core];
|
|
mdla_dvfs_debug("opp_check + max_opp%d,min_opp%d,(%d/%d/%d),ori vmdla(%d)",
|
|
max_opp[core], min_opp[core], core,
|
|
vmdla_index, freq_index, opps.vmdla.index);
|
|
|
|
|
|
if (vmdla_index == 0xFF) {
|
|
|
|
mdla_dvfs_debug("no need, vmdla opp(%d), hw vore opp(%d)\n",
|
|
vmdla_index, get_vmdla_opp);
|
|
|
|
force_change_vmdla_opp[core] = false;
|
|
opps.vmdla.index = vmdla_index;
|
|
} else {
|
|
/* opp down, need change freq first*/
|
|
if (vmdla_index > get_vmdla_opp)
|
|
change_freq_first[core] = true;
|
|
|
|
if (vmdla_index < max_vmdla_opp) {
|
|
mdla_dvfs_debug("mdla bound vmdla opp(%d) to %d",
|
|
vmdla_index, max_vmdla_opp);
|
|
|
|
vmdla_index = max_vmdla_opp;
|
|
}
|
|
|
|
if (vmdla_index >= opps.count) {
|
|
LOG_ERR("wrong vmdla opp(%d), max(%d)",
|
|
vmdla_index, opps.count - 1);
|
|
|
|
} else if ((vmdla_index < opps.vmdla.index) ||
|
|
((vmdla_index > opps.vmdla.index) &&
|
|
(!opp_keep_flag))) {
|
|
opps.vmdla.index = vmdla_index;
|
|
force_change_vmdla_opp[core] = true;
|
|
freq_check = true;
|
|
}
|
|
}
|
|
|
|
/* dsp freq opp */
|
|
if (freq_index == 0xFF) {
|
|
mdla_dvfs_debug("no request, freq opp(%d)", freq_index);
|
|
force_change_dsp_freq[core] = false;
|
|
} else {
|
|
if (freq_index < max_dsp_freq) {
|
|
mdla_dvfs_debug("mdla bound dsp freq(%dMHz) to %dMHz",
|
|
log_freq, log_max_freq);
|
|
freq_index = max_dsp_freq;
|
|
}
|
|
|
|
if ((opps.mdlacore.index != freq_index) || (freq_check)) {
|
|
/* freq_check for all vcore adjust related operation
|
|
* in acceptable region
|
|
*/
|
|
|
|
/* vcore not change and dsp change */
|
|
//if ((force_change_vcore_opp[core] == false) &&
|
|
if ((force_change_vmdla_opp[core] == false) &&
|
|
(freq_index > opps.mdlacore.index) &&
|
|
(opp_keep_flag)) {
|
|
force_change_dsp_freq[core] = false;
|
|
mdla_dvfs_debug("%s(%d) %s (%d/%d_%d/%d)\n",
|
|
__func__,
|
|
core,
|
|
"dsp keep high",
|
|
force_change_vmdla_opp[core],
|
|
freq_index,
|
|
opps.mdlacore.index,
|
|
opp_keep_flag);
|
|
|
|
} else {
|
|
opps.mdlacore.index = freq_index;
|
|
/*To FIX*/
|
|
if (opps.vmdla.index == 1 &&
|
|
opps.mdlacore.index < 3) {
|
|
/* adjust 0~3 to 4~7 for real table
|
|
* if needed
|
|
*/
|
|
opps.mdlacore.index = 3;
|
|
}
|
|
if (opps.vmdla.index == 2 &&
|
|
opps.mdlacore.index < 9) {
|
|
/* adjust 0~3 to 4~7 for real table
|
|
* if needed
|
|
*/
|
|
opps.mdlacore.index = 9;
|
|
}
|
|
|
|
|
|
opps.dsp.index = 15;
|
|
opps.ipu_if.index = 15;
|
|
for (i = 0 ; i < MTK_MDLA_CORE ; i++) {
|
|
mdla_dvfs_debug("%s %s[%d].%s(%d->%d)\n",
|
|
__func__,
|
|
"opps.mdlacore",
|
|
core,
|
|
"index",
|
|
opps.mdlacore.index,
|
|
opps.dsp.index);
|
|
|
|
/* interface should be the max freq of
|
|
* mdla cores
|
|
*/
|
|
if ((opps.mdlacore.index <
|
|
opps.dsp.index) &&
|
|
(opps.mdlacore.index >=
|
|
max_dsp_freq)) {
|
|
mdla_dsp_if_freq_check(core,
|
|
opps.mdlacore.index);
|
|
|
|
}
|
|
}
|
|
force_change_dsp_freq[core] = true;
|
|
|
|
opp_keep_flag = true;
|
|
|
|
mod_delayed_work(wq, &opp_keep_work,
|
|
msecs_to_jiffies(OPP_KEEP_TIME_MS));
|
|
|
|
}
|
|
} else {
|
|
/* vcore not change & dsp not change */
|
|
mdla_dvfs_debug("opp_check(%d) vcore/dsp no change\n",
|
|
core);
|
|
|
|
opp_keep_flag = true;
|
|
|
|
|
|
mod_delayed_work(wq, &opp_keep_work,
|
|
msecs_to_jiffies(OPP_KEEP_TIME_MS));
|
|
}
|
|
}
|
|
mutex_unlock(&opp_mutex);
|
|
out:
|
|
mdla_dvfs_debug("%s(%d)(%d/%d_%d)(%d/%d)(%d.%d.%d)(%d/%d)(%d/%d/%d/%d)%d\n",
|
|
"opp_check",
|
|
core,
|
|
is_power_debug_lock,
|
|
vmdla_index,
|
|
freq_index,
|
|
opps.vmdla.index,
|
|
get_vmdla_opp,
|
|
opps.dsp.index,
|
|
opps.mdlacore.index,
|
|
opps.ipu_if.index,
|
|
max_vmdla_opp,
|
|
max_dsp_freq,
|
|
freq_check,
|
|
force_change_vmdla_opp[core],
|
|
force_change_dsp_freq[core],
|
|
change_freq_first[core],
|
|
opp_keep_flag);
|
|
}
|
|
EXPORT_SYMBOL(mdla_opp_check);
|
|
|
|
static bool mdla_change_opp(int core_s, int type)
|
|
{
|
|
#ifdef MTK_MDLA_FPGA_PORTING
|
|
mdla_dvfs_debug("[mdla_%d] %d Skip at FPGA", core, type);
|
|
|
|
return true;
|
|
#else
|
|
int ret = 0;
|
|
unsigned int core = (unsigned int)core_s;
|
|
|
|
|
|
switch (type) {
|
|
/* vcore opp */
|
|
case OPPTYPE_VCORE:
|
|
mdla_dvfs_debug("[mdla_%d] wait for changing vcore opp", core);
|
|
break;
|
|
/* dsp freq opp */
|
|
case OPPTYPE_DSPFREQ:
|
|
mutex_lock(&opp_mutex);
|
|
mdla_dvfs_debug("[mdla] %s setclksrc(%d/%d/%d)\n",
|
|
__func__,
|
|
opps.dsp.index,
|
|
opps.mdlacore.index,
|
|
opps.ipu_if.index);
|
|
|
|
ret = mdla_if_set_clock_source(clk_top_dsp_sel, opps.dsp.index);
|
|
if (ret) {
|
|
LOG_ERR("[mdla]fail to set dsp freq, %s=%d, %s=%d\n",
|
|
"step", opps.dsp.index,
|
|
"ret", ret);
|
|
goto out;
|
|
}
|
|
ret = mdla_if_set_clock_source(clk_top_ipu_if_sel,
|
|
opps.ipu_if.index);
|
|
if (ret) {
|
|
LOG_ERR("[mdla]%s, %s=%d, %s=%d\n",
|
|
"fail to set ipu_if freq",
|
|
"step", opps.ipu_if.index,
|
|
"ret", ret);
|
|
goto out;
|
|
}
|
|
ret = mdla_set_clock_source(clk_top_dsp3_sel,
|
|
opps.mdlacore.index);
|
|
if (ret) {
|
|
LOG_ERR("[mdla]%s%d freq, %s=%d, %s=%d\n",
|
|
"fail to set dsp_", opps.mdlacore.index,
|
|
"step", opps.dsp.index,
|
|
"ret", ret);
|
|
goto out;
|
|
}
|
|
|
|
|
|
|
|
force_change_dsp_freq[core] = false;
|
|
mutex_unlock(&opp_mutex);
|
|
|
|
#ifdef MTK_PERF_OBSERVER
|
|
{
|
|
struct pob_xpufreq_info pxi;
|
|
|
|
pxi.id = core;
|
|
pxi.opp = opps.mdlacore.index;
|
|
|
|
pob_xpufreq_update(POB_XPUFREQ_MDLA, &pxi);
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
/* vmdla opp */
|
|
case OPPTYPE_VMDLA:
|
|
mdla_dvfs_debug("[mdla_%d] wait for changing vmdla opp", core);
|
|
LOG_DBG("[mdla_%d] to do vmdla opp change", core);
|
|
mutex_lock(&opp_mutex);
|
|
mdla_trace_tag_begin("vcore:request");
|
|
#ifdef ENABLE_PMQOS
|
|
switch (opps.vmdla.index) {
|
|
case 0:
|
|
mtk_pm_qos_update_request(&mdla_qos_vcore_request[core],
|
|
VCORE_OPP_1);
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[core],
|
|
VVPU_OPP_0);
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[core],
|
|
VMDLA_OPP_0);
|
|
break;
|
|
case 1:
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[core],
|
|
VVPU_OPP_1);
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[core],
|
|
VMDLA_OPP_1);
|
|
mtk_pm_qos_update_request(&mdla_qos_vcore_request[core],
|
|
VCORE_OPP_2);
|
|
break;
|
|
case 2:
|
|
default:
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[core],
|
|
VMDLA_OPP_2);
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[core],
|
|
VVPU_OPP_2);
|
|
mtk_pm_qos_update_request(&mdla_qos_vcore_request[core],
|
|
VCORE_OPP_2);
|
|
break;
|
|
}
|
|
#else
|
|
ret = mmdvfs_set_fine_step(MMDVFS_SCEN_VPU_KERNEL,
|
|
opps.vcore.index);
|
|
#endif
|
|
mdla_trace_tag_end();
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to request vcore, step=%d\n",
|
|
core, opps.vcore.index);
|
|
goto out;
|
|
}
|
|
|
|
mdla_dvfs_debug("[mdla_%d] cgopp vmdla=%d\n",
|
|
core,
|
|
regulator_get_voltage(vmdla_reg_id));
|
|
|
|
force_change_vcore_opp[core] = false;
|
|
force_change_vvpu_opp[core] = false;
|
|
force_change_vmdla_opp[core] = false;
|
|
mutex_unlock(&opp_mutex);
|
|
//wake_up_interruptible(&waitq_do_core_executing);
|
|
break;
|
|
default:
|
|
mdla_dvfs_debug("unexpected type(%d)", type);
|
|
break;
|
|
}
|
|
|
|
out:
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
int32_t mdla_thermal_en_throttle_cb(uint8_t vcore_opp, uint8_t mdla_opp)
|
|
{
|
|
int i = 0;
|
|
int ret = 0;
|
|
int vmdla_opp_index = 0;
|
|
int mdla_freq_index = 0;
|
|
|
|
if (mdla_init_done != 1)
|
|
return ret;
|
|
|
|
if (mdla_opp < MDLA_MAX_NUM_OPPS) {
|
|
vmdla_opp_index = opps.vmdla.opp_map[mdla_opp];
|
|
mdla_freq_index = opps.dsp.opp_map[mdla_opp];
|
|
} else {
|
|
LOG_ERR("mdla_thermal_en wrong opp(%d)\n", mdla_opp);
|
|
return -1;
|
|
}
|
|
|
|
mdla_dvfs_debug("%s, opp(%d)->(%d/%d)\n",
|
|
__func__, mdla_opp, vmdla_opp_index, mdla_freq_index);
|
|
|
|
mutex_lock(&opp_mutex);
|
|
max_dsp_freq = mdla_freq_index;
|
|
max_vmdla_opp = vmdla_opp_index;
|
|
mutex_unlock(&opp_mutex);
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
mutex_lock(&opp_mutex);
|
|
|
|
/* force change for all core under thermal request */
|
|
opp_keep_flag = false;
|
|
|
|
mutex_unlock(&opp_mutex);
|
|
mdla_opp_check(i, vmdla_opp_index, mdla_freq_index);
|
|
}
|
|
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
if (force_change_dsp_freq[i]) {
|
|
/* force change freq while running */
|
|
switch (mdla_freq_index) {
|
|
case 0:
|
|
default:
|
|
LOG_INF("thermal force bound freq @788MHz\n");
|
|
break;
|
|
case 1:
|
|
LOG_INF("thermal force bound freq @ 700MHz\n");
|
|
break;
|
|
case 2:
|
|
LOG_INF("thermal force bound freq @624MHz\n");
|
|
break;
|
|
case 3:
|
|
LOG_INF("thermal force bound freq @606MHz\n");
|
|
break;
|
|
case 4:
|
|
LOG_INF("thermal force bound freq @594MHz\n");
|
|
break;
|
|
case 5:
|
|
LOG_INF("thermal force bound freq @546MHz\n");
|
|
break;
|
|
case 6:
|
|
LOG_INF("thermal force bound freq @525MHz\n");
|
|
break;
|
|
case 7:
|
|
LOG_INF("thermal force bound freq @450MHz\n");
|
|
break;
|
|
case 8:
|
|
LOG_INF("thermal force bound freq @416MHz\n");
|
|
break;
|
|
case 9:
|
|
LOG_INF("thermal force bound freq @364MHz\n");
|
|
break;
|
|
case 10:
|
|
LOG_INF("thermal force bound freq @312MHz\n");
|
|
break;
|
|
case 11:
|
|
LOG_INF("thermal force bound freq @273MHz\n");
|
|
break;
|
|
case 12:
|
|
LOG_INF("thermal force bound freq @208MHz\n");
|
|
break;
|
|
case 13:
|
|
LOG_INF("thermal force bound freq @137MHz\n");
|
|
break;
|
|
case 14:
|
|
LOG_INF("thermal force bound freq @52MHz\n");
|
|
break;
|
|
case 15:
|
|
LOG_INF("thermal force bound freq @26MHz\n");
|
|
break;
|
|
}
|
|
/*mdla_change_opp(i, OPPTYPE_DSPFREQ);*/
|
|
}
|
|
if (force_change_vmdla_opp[i]) {
|
|
/* vcore change should wait */
|
|
LOG_INF("thermal force bound vcore opp to %d\n",
|
|
vmdla_opp_index);
|
|
/* vcore only need to change one time from
|
|
* thermal request
|
|
*/
|
|
/*if (i == 0)*/
|
|
/* mdla_change_opp(i, OPPTYPE_VCORE);*/
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t mdla_thermal_dis_throttle_cb(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (mdla_init_done != 1)
|
|
return ret;
|
|
|
|
LOG_INF("%s +\n", __func__);
|
|
mutex_lock(&opp_mutex);
|
|
max_vcore_opp = 0;
|
|
max_vmdla_opp = 0;
|
|
max_dsp_freq = 0;
|
|
mutex_unlock(&opp_mutex);
|
|
LOG_INF("%s -\n", __func__);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mdla_prepare_regulator_and_clock(struct device *pdev)
|
|
{
|
|
int ret = 0;
|
|
/*enable Vmdla Vmdla*/
|
|
/*--Get regulator handle--*/
|
|
vvpu_reg_id = regulator_get(pdev, "vpu");
|
|
if (!vvpu_reg_id) {
|
|
ret = -ENOENT;
|
|
LOG_ERR("regulator_get vvpu_reg_id failed\n");
|
|
}
|
|
vmdla_reg_id = regulator_get(pdev, "VMDLA");
|
|
if (!vmdla_reg_id) {
|
|
ret = -ENOENT;
|
|
LOG_ERR("regulator_get vmdla_reg_id failed\n");
|
|
}
|
|
|
|
|
|
#ifdef MTK_MDLA_FPGA_PORTING
|
|
LOG_INF("%s skip at FPGA\n", __func__);
|
|
#else
|
|
#define PREPARE_MDLA_MTCMOS(clk) \
|
|
{ \
|
|
clk = devm_clk_get(pdev, #clk); \
|
|
if (IS_ERR(clk)) { \
|
|
ret = -ENOENT; \
|
|
LOG_ERR("can not find mtcmos: %s\n", #clk); \
|
|
} \
|
|
}
|
|
PREPARE_MDLA_MTCMOS(mtcmos_dis);
|
|
PREPARE_MDLA_MTCMOS(mtcmos_vpu_vcore_shutdown);
|
|
PREPARE_MDLA_MTCMOS(mtcmos_vpu_conn_shutdown);
|
|
PREPARE_MDLA_MTCMOS(mtcmos_vpu_core2_shutdown);
|
|
|
|
#undef PREPARE_MDLA_MTCMOS
|
|
|
|
#define PREPARE_MDLA_CLK(clk) \
|
|
{ \
|
|
clk = devm_clk_get(pdev, #clk); \
|
|
if (IS_ERR(clk)) { \
|
|
ret = -ENOENT; \
|
|
LOG_ERR("can not find clock: %s\n", #clk); \
|
|
} else if (clk_prepare(clk)) { \
|
|
ret = -EBADE; \
|
|
LOG_ERR("fail to prepare clock: %s\n", #clk); \
|
|
} \
|
|
}
|
|
|
|
PREPARE_MDLA_CLK(clk_mmsys_gals_ipu2mm);
|
|
PREPARE_MDLA_CLK(clk_mmsys_gals_ipu12mm);
|
|
PREPARE_MDLA_CLK(clk_mmsys_gals_comm0);
|
|
PREPARE_MDLA_CLK(clk_mmsys_gals_comm1);
|
|
PREPARE_MDLA_CLK(clk_mmsys_smi_common);
|
|
PREPARE_MDLA_CLK(clk_apu_vcore_ahb_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_vcore_axi_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_vcore_adl_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_vcore_qos_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_apu_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_ahb_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_axi_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_isp_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_cam_adl_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_img_adl_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_emi_26m_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_conn_vpu_udi_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_apb_cg);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b0);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b1);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b2);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b3);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b4);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b5);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b6);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b7);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b8);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b9);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b10);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b11);
|
|
PREPARE_MDLA_CLK(clk_apu_mdla_cg_b12);
|
|
PREPARE_MDLA_CLK(clk_top_dsp_sel);
|
|
PREPARE_MDLA_CLK(clk_top_dsp3_sel);
|
|
PREPARE_MDLA_CLK(clk_top_ipu_if_sel);
|
|
PREPARE_MDLA_CLK(clk_top_clk26m);
|
|
PREPARE_MDLA_CLK(clk_top_univpll_d3_d8);
|
|
PREPARE_MDLA_CLK(clk_top_univpll_d3_d4);
|
|
PREPARE_MDLA_CLK(clk_top_mainpll_d2_d4);
|
|
PREPARE_MDLA_CLK(clk_top_univpll_d3_d2);
|
|
PREPARE_MDLA_CLK(clk_top_mainpll_d2_d2);
|
|
PREPARE_MDLA_CLK(clk_top_univpll_d2_d2);
|
|
PREPARE_MDLA_CLK(clk_top_mainpll_d3);
|
|
PREPARE_MDLA_CLK(clk_top_univpll_d3);
|
|
PREPARE_MDLA_CLK(clk_top_mmpll_d7);
|
|
PREPARE_MDLA_CLK(clk_top_mmpll_d6);
|
|
PREPARE_MDLA_CLK(clk_top_adsppll_d5);
|
|
PREPARE_MDLA_CLK(clk_top_tvdpll_ck);
|
|
PREPARE_MDLA_CLK(clk_top_tvdpll_mainpll_d2_ck);
|
|
PREPARE_MDLA_CLK(clk_top_univpll_d2);
|
|
PREPARE_MDLA_CLK(clk_top_adsppll_d4);
|
|
PREPARE_MDLA_CLK(clk_top_mainpll_d2);
|
|
PREPARE_MDLA_CLK(clk_top_mmpll_d4);
|
|
|
|
#undef PREPARE_MDLA_CLK
|
|
|
|
#endif
|
|
return ret;
|
|
}
|
|
static int mdla_enable_regulator_and_clock(int core)
|
|
{
|
|
#ifdef MTK_MDLA_FPGA_PORTING
|
|
LOG_INF("%s skip at FPGA\n", __func__);
|
|
|
|
is_power_on[core] = true;
|
|
force_change_vcore_opp[core] = false;
|
|
force_change_vmdla_opp[core] = false;
|
|
force_change_dsp_freq[core] = false;
|
|
return 0;
|
|
#else
|
|
int ret = 0;
|
|
int ret1 = 0;
|
|
//int get_vcore_opp = 0;
|
|
int get_vmdla_opp = 0;
|
|
//bool adjust_vcore = false;
|
|
bool adjust_vmdla = false;
|
|
|
|
mdla_dvfs_debug("[mdla] bypass setvoltage\n");
|
|
mdla_dvfs_debug("[mdla_%d] en_rc + (%d)\n", core, is_power_debug_lock);
|
|
|
|
mdla_trace_tag_begin("%s");
|
|
|
|
/*--enable regulator--*/
|
|
ret1 = vvpu_regulator_set_mode(true);
|
|
udelay(100);//slew rate:rising10mV/us
|
|
mdla_dvfs_debug("enable vvpu ret:%d\n", ret1);
|
|
ret1 = vmdla_regulator_set_mode(true);
|
|
udelay(100);//slew rate:rising10mV/us
|
|
mdla_dvfs_debug("enable vmdla ret:%d\n", ret1);
|
|
vvpu_vmdla_vcore_checker();
|
|
get_vmdla_opp = mdla_get_hw_vmdla_opp(core);
|
|
adjust_vmdla = true;
|
|
|
|
mdla_trace_tag_begin("vcore:request");
|
|
//if (adjust_vcore) {
|
|
if (adjust_vmdla) {
|
|
mdla_dvfs_debug("[mdla_%d] adjust_vmdla", core);
|
|
LOG_DBG("[mdla_%d] en_rc to do vmdla opp change", core);
|
|
#ifdef ENABLE_PMQOS
|
|
switch (opps.vmdla.index) {
|
|
case 0:
|
|
mtk_pm_qos_update_request(&mdla_qos_vcore_request[core],
|
|
VCORE_OPP_1);
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[core],
|
|
VVPU_OPP_0);
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[core],
|
|
VMDLA_OPP_0);
|
|
break;
|
|
case 1:
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[core],
|
|
VVPU_OPP_1);
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[core],
|
|
VMDLA_OPP_1);
|
|
mtk_pm_qos_update_request(&mdla_qos_vcore_request[core],
|
|
VCORE_OPP_2);
|
|
break;
|
|
case 2:
|
|
default:
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[core],
|
|
VMDLA_OPP_2);
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[core],
|
|
VVPU_OPP_2);
|
|
mtk_pm_qos_update_request(&mdla_qos_vcore_request[core],
|
|
VCORE_OPP_2);
|
|
break;
|
|
}
|
|
#else
|
|
ret = mmdvfs_set_fine_step(MMDVFS_SCEN_VPU_KERNEL,
|
|
opps.vcore.index);
|
|
#endif
|
|
}
|
|
mdla_trace_tag_end();
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to request vcore, step=%d\n",
|
|
core, opps.vcore.index);
|
|
goto out;
|
|
}
|
|
mdla_dvfs_debug("[mdla_%d] adjust(%d,%d) result vmdla=%d\n",
|
|
core,
|
|
adjust_vmdla,
|
|
opps.vmdla.index,
|
|
regulator_get_voltage(vmdla_reg_id));
|
|
|
|
LOG_DBG("[mdla_%d] en_rc setmmdvfs(%d) done\n", core, opps.vcore.index);
|
|
|
|
|
|
mdla_dvfs_debug("[mdla_%d] adjust(%d,%d) result vmdla=%d\n",
|
|
core,
|
|
adjust_vmdla,
|
|
opps.vmdla.index,
|
|
regulator_get_voltage(vmdla_reg_id));
|
|
|
|
#define ENABLE_MDLA_MTCMOS(clk) \
|
|
{ \
|
|
if (clk != NULL) { \
|
|
if (clk_prepare_enable(clk)) \
|
|
LOG_ERR("fail to prepare&enable mtcmos:%s\n", #clk); \
|
|
} else { \
|
|
LOG_WRN("mtcmos not existed: %s\n", #clk); \
|
|
} \
|
|
}
|
|
|
|
#define ENABLE_MDLA_CLK(clk) \
|
|
{ \
|
|
if (clk != NULL) { \
|
|
if (clk_enable(clk)) \
|
|
LOG_ERR("fail to enable clock: %s\n", #clk); \
|
|
} else { \
|
|
LOG_WRN("clk not existed: %s\n", #clk); \
|
|
} \
|
|
}
|
|
/*move vcore cg ctl to atf*/
|
|
#define vcore_cg_ctl(poweron) \
|
|
atf_vcore_cg_ctl(poweron)
|
|
|
|
mdla_trace_tag_begin("clock:enable_source");
|
|
ENABLE_MDLA_CLK(clk_top_dsp_sel);
|
|
ENABLE_MDLA_CLK(clk_top_ipu_if_sel);
|
|
ENABLE_MDLA_CLK(clk_top_dsp3_sel);
|
|
mdla_trace_tag_end();
|
|
|
|
mdla_trace_tag_begin("mtcmos:enable");
|
|
ENABLE_MDLA_MTCMOS(mtcmos_dis);
|
|
ENABLE_MDLA_MTCMOS(mtcmos_vpu_vcore_shutdown);
|
|
ENABLE_MDLA_MTCMOS(mtcmos_vpu_conn_shutdown);
|
|
ENABLE_MDLA_MTCMOS(mtcmos_vpu_core2_shutdown);
|
|
|
|
mdla_trace_tag_end();
|
|
udelay(500);
|
|
|
|
mdla_trace_tag_begin("clock:enable");
|
|
ENABLE_MDLA_CLK(clk_mmsys_gals_ipu2mm);
|
|
ENABLE_MDLA_CLK(clk_mmsys_gals_ipu12mm);
|
|
ENABLE_MDLA_CLK(clk_mmsys_gals_comm0);
|
|
ENABLE_MDLA_CLK(clk_mmsys_gals_comm1);
|
|
ENABLE_MDLA_CLK(clk_mmsys_smi_common);
|
|
|
|
/*move vcore cg ctl to atf*/
|
|
vcore_cg_ctl(1);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_apu_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_ahb_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_axi_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_isp_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_cam_adl_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_img_adl_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_emi_26m_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_conn_vpu_udi_cg);
|
|
switch (core) {
|
|
case 0:
|
|
default:
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_apb_cg);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b0);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b1);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b2);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b3);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b4);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b5);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b6);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b7);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b8);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b9);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b10);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b11);
|
|
ENABLE_MDLA_CLK(clk_apu_mdla_cg_b12);
|
|
break;
|
|
}
|
|
mdla_trace_tag_end();
|
|
|
|
#undef ENABLE_MDLA_MTCMOS
|
|
#undef ENABLE_MDLA_CLK
|
|
|
|
mdla_dvfs_debug("[mdla_%d] en_rc setclksrc(%d/%d/%d)\n",
|
|
core,
|
|
opps.dsp.index,
|
|
opps.mdlacore.index,
|
|
opps.ipu_if.index);
|
|
|
|
ret = mdla_if_set_clock_source(clk_top_dsp_sel, opps.dsp.index);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to set dsp freq, step=%d, ret=%d\n",
|
|
core, opps.dsp.index, ret);
|
|
goto out;
|
|
}
|
|
|
|
ret = mdla_set_clock_source(clk_top_dsp3_sel, opps.mdlacore.index);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to set mdla freq, step=%d, ret=%d\n",
|
|
core, opps.mdlacore.index, ret);
|
|
goto out;
|
|
}
|
|
|
|
ret = mdla_if_set_clock_source(clk_top_ipu_if_sel, opps.ipu_if.index);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to set ipu_if freq, step=%d, ret=%d\n",
|
|
core, opps.ipu_if.index, ret);
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
mdla_trace_tag_end();
|
|
if (mdla_klog & MDLA_DBG_DVFS)
|
|
apu_get_power_info();
|
|
is_power_on[core] = true;
|
|
force_change_vcore_opp[core] = false;
|
|
force_change_vmdla_opp[core] = false;
|
|
force_change_dsp_freq[core] = false;
|
|
LOG_DBG("[mdla_%d] en_rc -\n", core);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
static int mdla_disable_regulator_and_clock(int core)
|
|
{
|
|
int ret = 0;
|
|
int ret1 = 0;
|
|
|
|
#ifdef MTK_MDLA_FPGA_PORTING
|
|
mdla_dvfs_debug("%s skip at FPGA\n", __func__);
|
|
|
|
is_power_on[core] = false;
|
|
if (!is_power_debug_lock)
|
|
opps.mdlacore.index = 7;
|
|
|
|
return ret;
|
|
#else
|
|
unsigned int smi_bus_vpu_value = 0x0;
|
|
|
|
/* check there is un-finished transaction in bus before
|
|
* turning off vpu power
|
|
*/
|
|
#ifdef MTK_VPU_SMI_DEBUG_ON
|
|
smi_bus_vpu_value = vpu_read_smi_bus_debug(core);
|
|
|
|
mdla_dvfs_debug("[vpu_%d] dis_rc 1 (0x%x)\n", core, smi_bus_vpu_value);
|
|
|
|
if ((int)smi_bus_vpu_value != 0) {
|
|
mdelay(1);
|
|
smi_bus_vpu_value = vpu_read_smi_bus_debug(core);
|
|
|
|
mdla_dvfs_debug("[vpu_%d] dis_rc again (0x%x)\n", core,
|
|
smi_bus_vpu_value);
|
|
|
|
if ((int)smi_bus_vpu_value != 0) {
|
|
smi_debug_bus_hanging_detect_ext2(0x1ff, 1, 0, 1);
|
|
vpu_aee_warn("VPU SMI CHECK",
|
|
"core_%d fail to check smi, value=%d\n",
|
|
core,
|
|
smi_bus_vpu_value);
|
|
}
|
|
}
|
|
#else
|
|
mdla_dvfs_debug("[mdla_%d] dis_rc + (0x%x)\n", core, smi_bus_vpu_value);
|
|
#endif
|
|
|
|
#define DISABLE_MDLA_CLK(clk) \
|
|
{ \
|
|
if (clk != NULL) { \
|
|
clk_disable(clk); \
|
|
} else { \
|
|
LOG_WRN("clk not existed: %s\n", #clk); \
|
|
} \
|
|
}
|
|
switch (core) {
|
|
case 0:
|
|
default:
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_apb_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b0);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b1);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b2);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b3);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b4);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b5);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b6);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b7);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b8);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b9);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b10);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b11);
|
|
DISABLE_MDLA_CLK(clk_apu_mdla_cg_b12);
|
|
break;
|
|
}
|
|
DISABLE_MDLA_CLK(clk_apu_conn_apu_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_conn_ahb_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_conn_axi_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_conn_isp_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_conn_cam_adl_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_conn_img_adl_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_conn_emi_26m_cg);
|
|
DISABLE_MDLA_CLK(clk_apu_conn_vpu_udi_cg);
|
|
DISABLE_MDLA_CLK(clk_mmsys_gals_ipu2mm);
|
|
DISABLE_MDLA_CLK(clk_mmsys_gals_ipu12mm);
|
|
DISABLE_MDLA_CLK(clk_mmsys_gals_comm0);
|
|
DISABLE_MDLA_CLK(clk_mmsys_gals_comm1);
|
|
DISABLE_MDLA_CLK(clk_mmsys_smi_common);
|
|
mdla_dvfs_debug("[mdla_%d] dis_rc flag4\n", core);
|
|
|
|
#define DISABLE_MDLA_MTCMOS(clk) \
|
|
{ \
|
|
if (clk != NULL) { \
|
|
clk_disable_unprepare(clk); \
|
|
} else { \
|
|
LOG_WRN("mtcmos not existed: %s\n", #clk); \
|
|
} \
|
|
}
|
|
DISABLE_MDLA_MTCMOS(mtcmos_vpu_core2_shutdown);
|
|
DISABLE_MDLA_MTCMOS(mtcmos_vpu_conn_shutdown);
|
|
DISABLE_MDLA_MTCMOS(mtcmos_vpu_vcore_shutdown);
|
|
DISABLE_MDLA_MTCMOS(mtcmos_dis);
|
|
|
|
|
|
DISABLE_MDLA_CLK(clk_top_dsp_sel);
|
|
DISABLE_MDLA_CLK(clk_top_ipu_if_sel);
|
|
DISABLE_MDLA_CLK(clk_top_dsp3_sel);
|
|
|
|
#undef DISABLE_MDLA_MTCMOS
|
|
#undef DISABLE_MDLA_CLK
|
|
#ifdef ENABLE_PMQOS
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[core], VMDLA_OPP_2);
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[core], VVPU_OPP_2);
|
|
mtk_pm_qos_update_request(&mdla_qos_vcore_request[core],
|
|
VCORE_OPP_UNREQ);
|
|
mdla_dvfs_debug("[mdla_%d]vvpu, vmdla unreq\n", core);
|
|
#else
|
|
ret = mmdvfs_set_fine_step(MMDVFS_SCEN_VPU_KERNEL,
|
|
MMDVFS_FINE_STEP_UNREQUEST);
|
|
#endif
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to unrequest vcore!\n", core);
|
|
goto out;
|
|
}
|
|
LOG_DBG("[mdla_%d] disable result vmdla=%d\n",
|
|
core, regulator_get_voltage(vmdla_reg_id));
|
|
out:
|
|
|
|
/*--disable regulator--*/
|
|
ret1 = vmdla_regulator_set_mode(false);
|
|
udelay(100);//slew rate:rising10mV/us
|
|
mdla_dvfs_debug("disable vmdla ret:%d\n", ret1);
|
|
ret1 = vvpu_regulator_set_mode(false);
|
|
udelay(100);//slew rate:rising10mV/us
|
|
mdla_dvfs_debug("disable vvpu ret:%d\n", ret1);
|
|
|
|
vvpu_vmdla_vcore_checker();
|
|
|
|
is_power_on[core] = false;
|
|
if (!is_power_debug_lock) {
|
|
opps.mdlacore.index = 15;
|
|
opps.dsp.index = 9;
|
|
opps.ipu_if.index = 9;
|
|
}
|
|
mdla_dvfs_debug("[mdla_%d] dis_rc -\n", core);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
static void mdla_unprepare_regulator_and_clock(void)
|
|
{
|
|
|
|
#ifdef MTK_MDLA_FPGA_PORTING
|
|
mdla_dvfs_debug("%s skip at FPGA\n", __func__);
|
|
#else
|
|
#define UNPREPARE_MDLA_CLK(clk) \
|
|
{ \
|
|
if (clk != NULL) { \
|
|
clk_unprepare(clk); \
|
|
clk = NULL; \
|
|
} \
|
|
}
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_apb_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b0);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b1);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b2);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b3);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b4);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b5);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b6);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b7);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b8);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b9);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b10);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b11);
|
|
UNPREPARE_MDLA_CLK(clk_apu_mdla_cg_b12);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_apu_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_ahb_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_axi_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_isp_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_cam_adl_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_img_adl_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_emi_26m_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_conn_vpu_udi_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_vcore_ahb_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_vcore_axi_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_vcore_adl_cg);
|
|
UNPREPARE_MDLA_CLK(clk_apu_vcore_qos_cg);
|
|
UNPREPARE_MDLA_CLK(clk_mmsys_gals_ipu2mm);
|
|
UNPREPARE_MDLA_CLK(clk_mmsys_gals_ipu12mm);
|
|
UNPREPARE_MDLA_CLK(clk_mmsys_gals_comm0);
|
|
UNPREPARE_MDLA_CLK(clk_mmsys_gals_comm1);
|
|
UNPREPARE_MDLA_CLK(clk_mmsys_smi_common);
|
|
UNPREPARE_MDLA_CLK(clk_top_dsp_sel);
|
|
UNPREPARE_MDLA_CLK(clk_top_dsp3_sel);
|
|
UNPREPARE_MDLA_CLK(clk_top_ipu_if_sel);
|
|
UNPREPARE_MDLA_CLK(clk_top_clk26m);
|
|
UNPREPARE_MDLA_CLK(clk_top_univpll_d3_d8);
|
|
UNPREPARE_MDLA_CLK(clk_top_univpll_d3_d4);
|
|
UNPREPARE_MDLA_CLK(clk_top_mainpll_d2_d4);
|
|
UNPREPARE_MDLA_CLK(clk_top_univpll_d3_d2);
|
|
UNPREPARE_MDLA_CLK(clk_top_mainpll_d2_d2);
|
|
UNPREPARE_MDLA_CLK(clk_top_univpll_d2_d2);
|
|
UNPREPARE_MDLA_CLK(clk_top_mainpll_d3);
|
|
UNPREPARE_MDLA_CLK(clk_top_univpll_d3);
|
|
UNPREPARE_MDLA_CLK(clk_top_mmpll_d7);
|
|
UNPREPARE_MDLA_CLK(clk_top_mmpll_d6);
|
|
UNPREPARE_MDLA_CLK(clk_top_adsppll_d5);
|
|
UNPREPARE_MDLA_CLK(clk_top_tvdpll_ck);
|
|
UNPREPARE_MDLA_CLK(clk_top_tvdpll_mainpll_d2_ck);
|
|
UNPREPARE_MDLA_CLK(clk_top_univpll_d2);
|
|
UNPREPARE_MDLA_CLK(clk_top_adsppll_d4);
|
|
UNPREPARE_MDLA_CLK(clk_top_mainpll_d2);
|
|
UNPREPARE_MDLA_CLK(clk_top_mmpll_d4);
|
|
|
|
|
|
|
|
#undef UNPREPARE_MDLA_CLK
|
|
#endif
|
|
}
|
|
|
|
int mdla_get_power(int core)
|
|
{
|
|
int ret = 0;
|
|
|
|
mdla_dvfs_debug("[mdla_%d/%d] gp +\n", core, power_counter[core]);
|
|
mutex_lock(&power_counter_mutex[core]);
|
|
power_counter[core]++;
|
|
ret = mdla_boot_up(core);
|
|
mdla_reset_lock(REASON_POWERON);
|
|
mutex_unlock(&power_counter_mutex[core]);
|
|
mdla_dvfs_debug("[mdla_%d/%d] gp + 2\n", core, power_counter[core]);
|
|
|
|
if (ret == POWER_ON_MAGIC) {
|
|
mutex_lock(&opp_mutex);
|
|
if (change_freq_first[core]) {
|
|
mdla_dvfs_debug("[mdla_%d] change freq first(%d)\n",
|
|
core, change_freq_first[core]);
|
|
/*mutex_unlock(&opp_mutex);*/
|
|
/*mutex_lock(&opp_mutex);*/
|
|
if (force_change_dsp_freq[core]) {
|
|
mutex_unlock(&opp_mutex);
|
|
/* force change freq while running */
|
|
mdla_dvfs_debug("mdla_%d force change dsp freq", core);
|
|
mdla_change_opp(core, OPPTYPE_DSPFREQ);
|
|
} else {
|
|
mutex_unlock(&opp_mutex);
|
|
}
|
|
|
|
mutex_lock(&opp_mutex);
|
|
//if (force_change_vcore_opp[core]) {
|
|
if (force_change_vmdla_opp[core]) {
|
|
mutex_unlock(&opp_mutex);
|
|
/* vcore change should wait */
|
|
mdla_dvfs_debug("mdla_%d force change vmdla opp", core);
|
|
//mdla_change_opp(core, OPPTYPE_VCORE);
|
|
mdla_change_opp(core, OPPTYPE_VMDLA);
|
|
} else {
|
|
mutex_unlock(&opp_mutex);
|
|
}
|
|
} else {
|
|
/*mutex_unlock(&opp_mutex);*/
|
|
/*mutex_lock(&opp_mutex);*/
|
|
//if (force_change_vcore_opp[core]) {
|
|
if (force_change_vmdla_opp[core]) {
|
|
mutex_unlock(&opp_mutex);
|
|
/* vcore change should wait */
|
|
mdla_dvfs_debug("mdla_%d force change vcore opp", core);
|
|
//mdla_change_opp(core, OPPTYPE_VCORE);
|
|
mdla_change_opp(core, OPPTYPE_VMDLA);
|
|
} else {
|
|
mutex_unlock(&opp_mutex);
|
|
}
|
|
|
|
mutex_lock(&opp_mutex);
|
|
if (force_change_dsp_freq[core]) {
|
|
mutex_unlock(&opp_mutex);
|
|
/* force change freq while running */
|
|
mdla_dvfs_debug("mdla_%d force change dsp freq", core);
|
|
mdla_change_opp(core, OPPTYPE_DSPFREQ);
|
|
} else {
|
|
mutex_unlock(&opp_mutex);
|
|
}
|
|
}
|
|
}
|
|
LOG_DBG("[mdla_%d/%d] gp -\n", core, power_counter[core]);
|
|
if (mdla_klog & MDLA_DBG_DVFS)
|
|
apu_get_power_info();
|
|
enable_apu_bw(0);
|
|
enable_apu_bw(1);
|
|
enable_apu_bw(2);
|
|
enable_apu_latency(0);
|
|
enable_apu_latency(1);
|
|
enable_apu_latency(2);
|
|
if (core == 0)
|
|
apu_power_count_enable(true, USER_MDLA);
|
|
else if (core == 1)
|
|
apu_power_count_enable(true, USER_EDMA);
|
|
if (ret == POWER_ON_MAGIC)
|
|
return 0;
|
|
else
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(mdla_get_power);
|
|
|
|
void mdla_put_power(int core)
|
|
{
|
|
mdla_dvfs_debug("[mdla_%d/%d] pp +\n", core, power_counter[core]);
|
|
mutex_lock(&power_counter_mutex[core]);
|
|
if (--power_counter[core] == 0)
|
|
mdla_shut_down(core);
|
|
|
|
mutex_unlock(&power_counter_mutex[core]);
|
|
LOG_DBG("[mdla_%d/%d] pp -\n", core, power_counter[core]);
|
|
}
|
|
EXPORT_SYMBOL(mdla_put_power);
|
|
|
|
static int mdla_set_power(struct mdla_power *power)
|
|
{
|
|
int ret = 0;
|
|
uint8_t vmdla_opp_index = 0xFF;
|
|
uint8_t dsp_freq_index = 0xFF;
|
|
uint8_t opp_step = 0;
|
|
|
|
opp_step = mdla_boost_value_to_opp(power->boost_value);
|
|
if (opp_step < MDLA_MAX_NUM_OPPS && opp_step >= 0) {
|
|
vmdla_opp_index = opps.vmdla.opp_map[opp_step];
|
|
dsp_freq_index = opps.mdlacore.opp_map[opp_step];
|
|
} else {
|
|
LOG_ERR("wrong opp step (%d)", opp_step);
|
|
ret = -1;
|
|
return ret;
|
|
}
|
|
mdla_opp_check(0, vmdla_opp_index, dsp_freq_index);
|
|
//user->power_opp = power->opp_step;
|
|
|
|
ret = mdla_get_power(0);
|
|
/* to avoid power leakage, power on/off need be paired */
|
|
mdla_put_power(0);
|
|
mdla_dvfs_debug("[mdla] %s -\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
static void mdla_power_counter_routine(struct work_struct *work)
|
|
{
|
|
int core = 0;
|
|
struct my_struct_t *my_work_core =
|
|
container_of(work, struct my_struct_t, my_work.work);
|
|
|
|
core = my_work_core->core;
|
|
mdla_dvfs_debug("mdla_%d counterR (%d)+\n", core, power_counter[core]);
|
|
|
|
mutex_lock(&power_counter_mutex[core]);
|
|
if (power_counter[core] == 0)
|
|
mdla_shut_down(core);
|
|
else
|
|
LOG_DBG("mdla_%d no need this time.\n", core);
|
|
mutex_unlock(&power_counter_mutex[core]);
|
|
|
|
mdla_dvfs_debug("mdla_%d counterR -", core);
|
|
}
|
|
int mdla_quick_suspend(int core_s)
|
|
{
|
|
unsigned int core = (unsigned int)core_s;
|
|
|
|
mdla_dvfs_debug("[mdla_%d] q_suspend +\n", core);
|
|
mutex_lock(&power_counter_mutex[core]);
|
|
//mdla_dvfs_debug("[mdla_%d] q_suspend (%d/%d)\n", core,
|
|
//power_counter[core], mdla_service_cores[core].state);
|
|
|
|
if (power_counter[core] == 0) {
|
|
mutex_unlock(&power_counter_mutex[core]);
|
|
|
|
mod_delayed_work(wq,
|
|
&(power_counter_work[core].my_work),
|
|
msecs_to_jiffies(0));
|
|
} else {
|
|
mutex_unlock(&power_counter_mutex[core]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void mdla_opp_keep_routine(struct work_struct *work)
|
|
{
|
|
mdla_dvfs_debug("%s flag (%d) +\n", __func__, opp_keep_flag);
|
|
mutex_lock(&opp_mutex);
|
|
opp_keep_flag = false;
|
|
mutex_unlock(&opp_mutex);
|
|
mdla_dvfs_debug("%s flag (%d) -\n", __func__, opp_keep_flag);
|
|
}
|
|
|
|
#ifdef CONFIG_MTK_DEVINFO
|
|
static int get_nvmem_cell_efuse(struct device *dev)
|
|
{
|
|
struct nvmem_cell *cell;
|
|
uint32_t *buf;
|
|
|
|
cell = nvmem_cell_get(dev, "efuse_segment");
|
|
if ((cell == NULL) || IS_ERR(cell)) {
|
|
LOG_ERR("[%s] nvmem_cell_get fail\n", __func__);
|
|
if (PTR_ERR(cell) == -EPROBE_DEFER)
|
|
return PTR_ERR(cell);
|
|
return -1;
|
|
}
|
|
|
|
buf = (uint32_t *)nvmem_cell_read(cell, NULL);
|
|
nvmem_cell_put(cell);
|
|
|
|
if (IS_ERR(buf)) {
|
|
LOG_ERR("[%s] nvmem_cell_read fail\n", __func__);
|
|
return PTR_ERR(buf);
|
|
}
|
|
|
|
g_efuse_segment = *buf;
|
|
kfree(buf);
|
|
|
|
return 0;
|
|
}
|
|
#endif // CONFIG_MTK_DEVINFO
|
|
|
|
int mdla_init_hw(int core, struct platform_device *pdev)
|
|
{
|
|
int ret, i, j;
|
|
//int param;
|
|
|
|
if (core == 0) {
|
|
//init_waitqueue_head(&cmd_wait);
|
|
//mutex_init(&lock_mutex);
|
|
//init_waitqueue_head(&lock_wait);
|
|
mutex_init(&opp_mutex);
|
|
//init_waitqueue_head(&waitq_change_vcore);
|
|
//init_waitqueue_head(&waitq_do_core_executing);
|
|
//is_locked = false;
|
|
max_vcore_opp = 0;
|
|
max_vmdla_opp = 0;
|
|
max_dsp_freq = 0;
|
|
opp_keep_flag = false;
|
|
//mdla_dev = device;
|
|
is_power_debug_lock = false;
|
|
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
mutex_init(&(power_mutex[i]));
|
|
mutex_init(&(power_counter_mutex[i]));
|
|
mutex_init(&power_lock_mutex);
|
|
power_counter[i] = 0;
|
|
power_counter_work[i].core = i;
|
|
is_power_on[i] = false;
|
|
force_change_vcore_opp[i] = false;
|
|
force_change_vmdla_opp[i] = false;
|
|
force_change_dsp_freq[i] = false;
|
|
change_freq_first[i] = false;
|
|
//exception_isr_check[i] = false;
|
|
|
|
INIT_DELAYED_WORK(&(power_counter_work[i].my_work),
|
|
mdla_power_counter_routine);
|
|
}
|
|
wq = create_workqueue("mdla_wq");
|
|
#define DEFINE_APU_STEP(step, m, v0, v1, v2, v3, \
|
|
v4, v5, v6, v7, v8, v9, \
|
|
v10, v11, v12, v13, v14, v15) \
|
|
{ \
|
|
opps.step.index = m - 1; \
|
|
opps.step.count = m; \
|
|
opps.step.values[0] = v0; \
|
|
opps.step.values[1] = v1; \
|
|
opps.step.values[2] = v2; \
|
|
opps.step.values[3] = v3; \
|
|
opps.step.values[4] = v4; \
|
|
opps.step.values[5] = v5; \
|
|
opps.step.values[6] = v6; \
|
|
opps.step.values[7] = v7; \
|
|
opps.step.values[8] = v8; \
|
|
opps.step.values[9] = v9; \
|
|
opps.step.values[10] = v10; \
|
|
opps.step.values[11] = v11; \
|
|
opps.step.values[12] = v12; \
|
|
opps.step.values[13] = v13; \
|
|
opps.step.values[14] = v14; \
|
|
opps.step.values[15] = v15; \
|
|
}
|
|
|
|
|
|
#define DEFINE_APU_OPP(i, v0, v1, v2, v3, v4, v5, v6) \
|
|
{ \
|
|
opps.vvpu.opp_map[i] = v0; \
|
|
opps.vmdla.opp_map[i] = v1; \
|
|
opps.dsp.opp_map[i] = v2; \
|
|
opps.dspcore[0].opp_map[i] = v3; \
|
|
opps.dspcore[1].opp_map[i] = v4; \
|
|
opps.ipu_if.opp_map[i] = v5; \
|
|
opps.mdlacore.opp_map[i] = v6; \
|
|
}
|
|
|
|
DEFINE_APU_STEP(vcore, 3, 825000,
|
|
725000, 650000, 0,
|
|
0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0);
|
|
DEFINE_APU_STEP(vvpu, 3, 825000,
|
|
725000, 650000, 0,
|
|
0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0);
|
|
DEFINE_APU_STEP(vmdla, 3, 825000,
|
|
725000, 650000, 0,
|
|
0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0);
|
|
DEFINE_APU_STEP(dsp, 16, 624000,
|
|
624000, 606000, 594000,
|
|
560000, 525000, 450000,
|
|
416000, 364000, 312000,
|
|
273000, 208000, 137000,
|
|
104000, 52000, 26000);
|
|
DEFINE_APU_STEP(dspcore[0], 16, 700000,
|
|
624000, 606000, 594000,
|
|
560000, 525000, 450000,
|
|
416000, 364000, 312000,
|
|
273000, 208000, 137000,
|
|
104000, 52000, 26000);
|
|
DEFINE_APU_STEP(dspcore[1], 16, 700000,
|
|
624000, 606000, 594000,
|
|
560000, 525000, 450000,
|
|
416000, 364000, 312000,
|
|
273000, 208000, 137000,
|
|
104000, 52000, 26000);
|
|
DEFINE_APU_STEP(mdlacore, 16, 788000,
|
|
700000, 624000, 606000,
|
|
594000, 546000, 525000,
|
|
450000, 416000, 364000,
|
|
312000, 273000, 208000,
|
|
137000, 52000, 26000);
|
|
DEFINE_APU_STEP(ipu_if, 16, 624000,
|
|
624000, 606000, 594000,
|
|
560000, 525000, 450000,
|
|
416000, 364000, 312000,
|
|
273000, 208000, 137000,
|
|
104000, 52000, 26000);
|
|
|
|
/* default freq */
|
|
DEFINE_APU_OPP(0, 0, 0, 0, 0, 0, 0, 0);
|
|
DEFINE_APU_OPP(1, 0, 0, 1, 1, 1, 1, 1);
|
|
DEFINE_APU_OPP(2, 0, 0, 2, 2, 2, 2, 2);
|
|
DEFINE_APU_OPP(3, 0, 1, 3, 3, 3, 3, 3);
|
|
DEFINE_APU_OPP(4, 0, 1, 4, 4, 4, 4, 4);
|
|
DEFINE_APU_OPP(5, 1, 1, 5, 5, 5, 5, 5);
|
|
DEFINE_APU_OPP(6, 1, 1, 6, 6, 6, 6, 6);
|
|
DEFINE_APU_OPP(7, 1, 1, 7, 7, 7, 7, 7);
|
|
DEFINE_APU_OPP(8, 1, 1, 8, 8, 8, 8, 8);
|
|
DEFINE_APU_OPP(9, 2, 2, 9, 9, 9, 9, 9);
|
|
DEFINE_APU_OPP(10, 2, 2, 10, 10, 10, 10, 10);
|
|
DEFINE_APU_OPP(11, 2, 2, 11, 11, 11, 11, 11);
|
|
DEFINE_APU_OPP(12, 2, 2, 12, 12, 12, 12, 12);
|
|
DEFINE_APU_OPP(13, 2, 2, 13, 13, 13, 13, 13);
|
|
DEFINE_APU_OPP(14, 2, 2, 14, 14, 14, 14, 14);
|
|
DEFINE_APU_OPP(15, 2, 2, 15, 15, 15, 15, 15);
|
|
|
|
|
|
/* default low opp */
|
|
opps.count = 16;
|
|
opps.index = 5; /* user space usage*/
|
|
opps.vcore.index = 1;
|
|
opps.vmdla.index = 1;
|
|
opps.dsp.index = 9;
|
|
opps.ipu_if.index = 9;
|
|
opps.mdlacore.index = 9;
|
|
#undef DEFINE_APU_OPP
|
|
#undef DEFINE_APU_STEP
|
|
ret = mdla_prepare_regulator_and_clock(&pdev->dev);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to prepare regulator or clk!\n",
|
|
core);
|
|
goto out;
|
|
}
|
|
|
|
/* pmqos */
|
|
#ifdef ENABLE_PMQOS
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
mtk_pm_qos_add_request(&mdla_qos_bw_request[i],
|
|
MTK_PM_QOS_MEMORY_EXT_BANDWIDTH,
|
|
PM_QOS_DEFAULT_VALUE);
|
|
|
|
mtk_pm_qos_add_request(&mdla_qos_vcore_request[i],
|
|
MTK_PM_QOS_VCORE_OPP,
|
|
MTK_PM_QOS_VCORE_OPP_DEFAULT_VALUE);
|
|
|
|
mtk_pm_qos_add_request(&mdla_qos_vmdla_request[i],
|
|
MTK_PM_QOS_VMDLA_OPP,
|
|
MTK_PM_QOS_VMDLA_OPP_DEFAULT_VALUE);
|
|
mtk_pm_qos_add_request(&mdla_qos_vvpu_request[i],
|
|
MTK_PM_QOS_VVPU_OPP,
|
|
MTK_PM_QOS_VVPU_OPP_DEFAULT_VALUE);
|
|
mtk_pm_qos_update_request(&mdla_qos_vvpu_request[i],
|
|
VVPU_OPP_2);
|
|
mtk_pm_qos_update_request(&mdla_qos_vmdla_request[i],
|
|
VMDLA_OPP_2);
|
|
}
|
|
mdla_dvfs_debug("[mdla]init vvpu, vmdla to opp2\n");
|
|
ret = vmdla_regulator_set_mode(true);
|
|
udelay(100);
|
|
mdla_dvfs_debug("vvpu set sleep mode ret=%d\n", ret);
|
|
ret = vmdla_regulator_set_mode(false);
|
|
mdla_dvfs_debug("vvpu set sleep mode ret=%d\n", ret);
|
|
udelay(100);
|
|
#endif
|
|
|
|
}
|
|
/*init mdla lock power struct*/
|
|
for (i = 0 ; i < MDLA_OPP_PRIORIYY_NUM ; i++) {
|
|
lock_power[i][0].core = 0;
|
|
lock_power[i][0].max_boost_value = 100;
|
|
lock_power[i][0].min_boost_value = 0;
|
|
lock_power[i][0].lock = false;
|
|
lock_power[i][0].priority = MDLA_OPP_NORMAL;
|
|
}
|
|
for (j = 0 ; j < MTK_MDLA_USER ; j++) {
|
|
min_opp[j] = MDLA_MAX_NUM_OPPS-1;
|
|
max_opp[j] = 0;
|
|
minboost[j] = 0;
|
|
maxboost[j] = 100;
|
|
}
|
|
#ifdef CONFIG_MTK_DEVINFO
|
|
get_nvmem_cell_efuse(&pdev->dev);
|
|
#endif
|
|
get_segment_from_efuse();
|
|
mdla_init_done = 1;
|
|
return 0;
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int mdla_uninit_hw(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
cancel_delayed_work(&(power_counter_work[i].my_work));
|
|
}
|
|
cancel_delayed_work(&opp_keep_work);
|
|
/* pmqos */
|
|
#ifdef ENABLE_PMQOS
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
mtk_pm_qos_remove_request(&mdla_qos_bw_request[i]);
|
|
mtk_pm_qos_remove_request(&mdla_qos_vcore_request[i]);
|
|
mtk_pm_qos_remove_request(&mdla_qos_vmdla_request[i]);
|
|
mtk_pm_qos_remove_request(&mdla_qos_vvpu_request[i]);
|
|
}
|
|
#endif
|
|
|
|
mdla_unprepare_regulator_and_clock();
|
|
if (wq) {
|
|
flush_workqueue(wq);
|
|
destroy_workqueue(wq);
|
|
wq = NULL;
|
|
}
|
|
mdla_init_done = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int mdla_boot_up(int core)
|
|
{
|
|
int ret = 0;
|
|
|
|
mdla_dvfs_debug("[mdla_%d] boot_up +\n", core);
|
|
mutex_lock(&power_mutex[core]);
|
|
mdla_dvfs_debug("[mdla_%d] is_power_on(%d)\n", core, is_power_on[core]);
|
|
if (is_power_on[core]) {
|
|
mutex_unlock(&power_mutex[core]);
|
|
//mutex_lock(&(mdla_service_cores[core].state_mutex));
|
|
//mdla_service_cores[core].state = VCT_BOOTUP;
|
|
//mutex_unlock(&(mdla_service_cores[core].state_mutex));
|
|
//wake_up_interruptible(&waitq_change_vcore);
|
|
mdla_dvfs_debug("[mdla_%d] already power on\n", core);
|
|
return POWER_ON_MAGIC;
|
|
}
|
|
mdla_dvfs_debug("[mdla_%d] boot_up flag2\n", core);
|
|
|
|
mdla_trace_tag_begin("%s", __func__);
|
|
//mutex_lock(&(mdla_service_cores[core].state_mutex));
|
|
//mdla_service_cores[core].state = VCT_BOOTUP;
|
|
//mutex_unlock(&(mdla_service_cores[core].state_mutex));
|
|
//wake_up_interruptible(&waitq_change_vcore);
|
|
|
|
ret = mdla_enable_regulator_and_clock(core);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to enable regulator or clock\n", core);
|
|
goto out;
|
|
}
|
|
#ifdef MET_POLLING_MODE
|
|
ret = mdla_profile_state_set(core, 1);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d] fail to mdla_profile_state_set 1\n", core);
|
|
goto out;
|
|
}
|
|
#endif
|
|
|
|
out:
|
|
mdla_trace_tag_end();
|
|
mutex_unlock(&power_mutex[core]);
|
|
|
|
#ifdef MTK_PERF_OBSERVER
|
|
if (!ret) {
|
|
struct pob_xpufreq_info pxi;
|
|
|
|
pxi.id = core;
|
|
pxi.opp = opps.mdlacore.index;
|
|
|
|
pob_xpufreq_update(POB_XPUFREQ_MDLA, &pxi);
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mdla_shut_down(int core)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (core == 0)
|
|
apu_power_count_enable(false, USER_MDLA);
|
|
else if (core == 1)
|
|
apu_power_count_enable(false, USER_EDMA);
|
|
apu_shut_down();
|
|
|
|
|
|
mdla_dvfs_debug("[mdla_%d] shutdown +\n", core);
|
|
mutex_lock(&power_mutex[core]);
|
|
if (!is_power_on[core]) {
|
|
mutex_unlock(&power_mutex[core]);
|
|
return 0;
|
|
}
|
|
#ifdef MET_POLLING_MODE
|
|
ret = mdla_profile_state_set(core, 0);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d] fail to mdla_profile_state_set 0\n", core);
|
|
goto out;
|
|
}
|
|
#endif
|
|
|
|
mdla_trace_tag_begin("%s", __func__);
|
|
mdla_dvfs_debug("[mdla_%d] mdla_disable_regulator_and_clock +\n", core);
|
|
ret = mdla_disable_regulator_and_clock(core);
|
|
if (ret) {
|
|
LOG_ERR("[mdla_%d]fail to disable regulator and clock\n", core);
|
|
goto out;
|
|
}
|
|
mdla_dvfs_debug("[mdla_%d] mdla_disable_regulator_and_clock -\n", core);
|
|
|
|
//wake_up_interruptible(&waitq_change_vcore);
|
|
out:
|
|
mdla_trace_tag_end();
|
|
mutex_unlock(&power_mutex[core]);
|
|
LOG_DBG("[mdla_%d] shutdown -\n", core);
|
|
|
|
#ifdef MTK_PERF_OBSERVER
|
|
if (!ret) {
|
|
struct pob_xpufreq_info pxi;
|
|
|
|
pxi.id = core;
|
|
pxi.opp = -1;
|
|
|
|
pob_xpufreq_update(POB_XPUFREQ_MDLA, &pxi);
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mdla_dump_opp_table(struct seq_file *s)
|
|
{
|
|
int i;
|
|
|
|
#define LINE_BAR " +-----+----------+----------+------------+-----------+-----------+\n"
|
|
mdla_print_seq(s, LINE_BAR);
|
|
mdla_print_seq(s, " |%-5s|%-10s|%-10s|%-10s|%-10s|%-12s|\n",
|
|
"OPP", "VVPU(uV)",
|
|
"VMDLA(uV)", "MDLA(KHz)", "DSP(KHz)",
|
|
"IPU_IF(KHz)");
|
|
mdla_print_seq(s, LINE_BAR);
|
|
|
|
for (i = 0; i < opps.count; i++) {
|
|
mdla_print_seq(s,
|
|
" |%-5d|[%d]%-7d|[%d]%-7d|[%d]%-7d|[%d]%-7d|[%d]%-9d\n",
|
|
i,
|
|
opps.vvpu.opp_map[i],
|
|
opps.vvpu.values[opps.vvpu.opp_map[i]],
|
|
opps.vmdla.opp_map[i],
|
|
opps.vmdla.values[opps.vmdla.opp_map[i]],
|
|
opps.mdlacore.opp_map[i],
|
|
opps.mdlacore.values[opps.mdlacore.opp_map[i]],
|
|
opps.dsp.opp_map[i],
|
|
opps.dsp.values[opps.dsp.opp_map[i]],
|
|
opps.ipu_if.opp_map[i],
|
|
opps.ipu_if.values[opps.ipu_if.opp_map[i]]);
|
|
}
|
|
|
|
mdla_print_seq(s, LINE_BAR);
|
|
#undef LINE_BAR
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mdla_dump_power(struct seq_file *s)
|
|
{
|
|
int vmdla_opp = 0;
|
|
|
|
vmdla_opp = mdla_get_hw_vmdla_opp(0);
|
|
|
|
|
|
mdla_print_seq(s, "%s(rw): %s[%d/%d]\n",
|
|
"dvfs_debug",
|
|
"vmdla", opps.vmdla.index, vmdla_opp);
|
|
mdla_print_seq(s, "dvfs_debug(rw): min/max opp[0][%d/%d]\n",
|
|
min_opp[0], max_opp[0]);
|
|
mdla_print_seq(s, "dvfs_debug(rw): min/max boost[0][%d/%d]\n",
|
|
minboost[0], maxboost[0]);
|
|
mdla_print_seq(s, "%s[%d], %s[%d], %s[%d]\n",
|
|
"dsp", opps.dsp.index,
|
|
"ipu_if", opps.ipu_if.index,
|
|
"mdla", opps.mdlacore.index);
|
|
|
|
|
|
mdla_print_seq(s, "is_power_debug_lock(rw): %d\n", is_power_debug_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mdla_set_power_parameter(uint8_t param, int argc, int *args)
|
|
{
|
|
int ret = 0;
|
|
unsigned int lv = 0;
|
|
|
|
switch (param) {
|
|
case MDLA_POWER_PARAM_FIX_OPP:
|
|
ret = (argc == 1) ? 0 : -EINVAL;
|
|
if (ret) {
|
|
LOG_ERR("invalid argument, expected:1, received:%d\n",
|
|
argc);
|
|
goto out;
|
|
}
|
|
switch (args[0]) {
|
|
case 0:
|
|
is_power_debug_lock = false;
|
|
break;
|
|
case 1:
|
|
is_power_debug_lock = true;
|
|
break;
|
|
default:
|
|
|
|
if (ret) {
|
|
LOG_ERR("invalid argument, received:%d\n",
|
|
(int)(args[0]));
|
|
goto out;
|
|
}
|
|
ret = -EINVAL;
|
|
goto out;
|
|
|
|
}
|
|
break;
|
|
case MDLA_POWER_PARAM_DVFS_DEBUG:
|
|
ret = (argc == 1) ? 0 : -EINVAL;
|
|
if (ret) {
|
|
LOG_ERR("invalid argument, expected:1, received:%d\n",
|
|
argc);
|
|
goto out;
|
|
}
|
|
|
|
lv = (unsigned int)args[0];
|
|
ret = lv >= opps.count;
|
|
if (ret) {
|
|
LOG_ERR("opp step(%d) is out-of-bound, count:%d\n",
|
|
(int)(args[0]), opps.count);
|
|
goto out;
|
|
}
|
|
LOG_ERR("@@test%d\n", argc);
|
|
|
|
opps.vcore.index = opps.vcore.opp_map[lv];
|
|
opps.vvpu.index = opps.vvpu.opp_map[lv];
|
|
opps.vmdla.index = opps.vmdla.opp_map[lv];
|
|
opps.dsp.index = opps.dsp.opp_map[lv];
|
|
opps.ipu_if.index = opps.ipu_if.opp_map[lv];
|
|
opps.mdlacore.index = opps.mdlacore.opp_map[lv];
|
|
|
|
is_power_debug_lock = true;
|
|
|
|
|
|
break;
|
|
case MDLA_POWER_PARAM_JTAG:
|
|
mdla_put_power(0);
|
|
break;
|
|
case MDLA_POWER_PARAM_LOCK:
|
|
ret = (argc == 1) ? 0 : -EINVAL;
|
|
if (ret) {
|
|
LOG_ERR("invalid argument, expected:1, received:%d\n",
|
|
argc);
|
|
goto out;
|
|
}
|
|
|
|
lv = (unsigned int)args[0];
|
|
ret = lv >= opps.count;
|
|
if (ret) {
|
|
LOG_ERR("opp step(%d) is out-of-bound, count:%d\n",
|
|
(int)(args[0]), opps.count);
|
|
goto out;
|
|
}
|
|
LOG_ERR("@@lock%d\n", argc);
|
|
|
|
opps.vcore.index = opps.vcore.opp_map[lv];
|
|
opps.vvpu.index = opps.vvpu.opp_map[lv];
|
|
opps.vmdla.index = opps.vmdla.opp_map[lv];
|
|
opps.dsp.index = opps.dsp.opp_map[lv];
|
|
opps.ipu_if.index = opps.ipu_if.opp_map[lv];
|
|
opps.mdlacore.index = opps.mdlacore.opp_map[lv];
|
|
|
|
|
|
mdla_opp_check(0, opps.dsp.index, opps.dsp.index);
|
|
//user->power_opp = power->opp_step;
|
|
|
|
ret = mdla_get_power(0);
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
case MDLA_POWER_HAL_CTL:
|
|
{
|
|
struct mdla_lock_power mdla_lock_power;
|
|
|
|
ret = (argc == 2) ? 0 : -EINVAL;
|
|
if (ret) {
|
|
LOG_ERR("invalid argument, expected:2, received:%d\n",
|
|
argc);
|
|
goto out;
|
|
}
|
|
|
|
if (args[0] > 100 || args[0] < 0) {
|
|
LOG_ERR("min boost(%d) is out-of-bound\n",
|
|
(int)(args[0]));
|
|
goto out;
|
|
}
|
|
if (args[1] > 100 || args[1] < 0) {
|
|
LOG_ERR("max boost(%d) is out-of-bound\n",
|
|
(int)(args[1]));
|
|
goto out;
|
|
}
|
|
mdla_lock_power.core = 1;
|
|
mdla_lock_power.lock = true;
|
|
mdla_lock_power.priority = MDLA_OPP_POWER_HAL;
|
|
mdla_lock_power.max_boost_value = args[1];
|
|
mdla_lock_power.min_boost_value = args[0];
|
|
mdla_dvfs_debug("[mdla]POWER_HAL_LOCK+core:%d, maxb:%d, minb:%d\n",
|
|
mdla_lock_power.core, mdla_lock_power.max_boost_value,
|
|
mdla_lock_power.min_boost_value);
|
|
ret = mdla_lock_set_power(&mdla_lock_power);
|
|
if (ret) {
|
|
LOG_ERR("[POWER_HAL_LOCK]failed, ret=%d\n", ret);
|
|
goto out;
|
|
}
|
|
break;
|
|
}
|
|
case MDLA_EARA_CTL:
|
|
{
|
|
struct mdla_lock_power mdla_lock_power;
|
|
|
|
ret = (argc == 2) ? 0 : -EINVAL;
|
|
if (ret) {
|
|
LOG_ERR("invalid argument, expected:3, received:%d\n",
|
|
argc);
|
|
goto out;
|
|
}
|
|
if (args[0] > 100 || args[0] < 0) {
|
|
LOG_ERR("min boost(%d) is out-of-bound\n",
|
|
(int)(args[0]));
|
|
goto out;
|
|
}
|
|
if (args[1] > 100 || args[1] < 0) {
|
|
LOG_ERR("max boost(%d) is out-of-bound\n",
|
|
(int)(args[1]));
|
|
goto out;
|
|
}
|
|
mdla_lock_power.core = 1;
|
|
mdla_lock_power.lock = true;
|
|
mdla_lock_power.priority = MDLA_OPP_EARA_QOS;
|
|
mdla_lock_power.max_boost_value = args[1];
|
|
mdla_lock_power.min_boost_value = args[0];
|
|
mdla_dvfs_debug("[mdla]EARA_LOCK+core:%d, maxb:%d, minb:%d\n",
|
|
mdla_lock_power.core, mdla_lock_power.max_boost_value,
|
|
mdla_lock_power.min_boost_value);
|
|
ret = mdla_lock_set_power(&mdla_lock_power);
|
|
if (ret) {
|
|
LOG_ERR("[POWER_HAL_LOCK]failed, ret=%d\n", ret);
|
|
goto out;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
LOG_ERR("unsupport the power parameter:%d\n", param);
|
|
break;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static uint8_t mdla_boost_value_to_opp(uint8_t boost_value)
|
|
{
|
|
int ret = 0;
|
|
/* set dsp frequency - 0:788 MHz, 1:700 MHz, 2:606 MHz, 3:594 MHz*/
|
|
/* set dsp frequency - 4:560 MHz, 5:525 MHz, 6:450 MHz, 7:416 MHz*/
|
|
/* set dsp frequency - 8:364 MHz, 9:312 MHz, 10:273 MH, 11:208 MH*/
|
|
/* set dsp frequency - 12:137 MHz, 13:104 MHz, 14:52 MHz, 15:26 MHz*/
|
|
uint32_t freq = 0;
|
|
uint32_t freq0 = opps.mdlacore.values[0];
|
|
uint32_t freq1 = opps.mdlacore.values[1];
|
|
uint32_t freq2 = opps.mdlacore.values[2];
|
|
uint32_t freq3 = opps.mdlacore.values[3];
|
|
uint32_t freq4 = opps.mdlacore.values[4];
|
|
uint32_t freq5 = opps.mdlacore.values[5];
|
|
uint32_t freq6 = opps.mdlacore.values[6];
|
|
uint32_t freq7 = opps.mdlacore.values[7];
|
|
uint32_t freq8 = opps.mdlacore.values[8];
|
|
uint32_t freq9 = opps.mdlacore.values[9];
|
|
uint32_t freq10 = opps.mdlacore.values[10];
|
|
uint32_t freq11 = opps.mdlacore.values[11];
|
|
uint32_t freq12 = opps.mdlacore.values[12];
|
|
uint32_t freq13 = opps.mdlacore.values[13];
|
|
uint32_t freq14 = opps.mdlacore.values[14];
|
|
uint32_t freq15 = opps.mdlacore.values[15];
|
|
|
|
if ((boost_value <= 100) && (boost_value >= 0))
|
|
freq = boost_value * freq0 / 100;
|
|
else
|
|
freq = freq0;
|
|
|
|
if (freq <= freq0 && freq > freq1)
|
|
ret = 0;
|
|
else if (freq <= freq1 && freq > freq2)
|
|
ret = 1;
|
|
else if (freq <= freq2 && freq > freq3)
|
|
ret = 2;
|
|
else if (freq <= freq3 && freq > freq4)
|
|
ret = 3;
|
|
else if (freq <= freq4 && freq > freq5)
|
|
ret = 4;
|
|
else if (freq <= freq5 && freq > freq6)
|
|
ret = 5;
|
|
else if (freq <= freq6 && freq > freq7)
|
|
ret = 6;
|
|
else if (freq <= freq7 && freq > freq8)
|
|
ret = 7;
|
|
else if (freq <= freq8 && freq > freq9)
|
|
ret = 8;
|
|
else if (freq <= freq9 && freq > freq10)
|
|
ret = 9;
|
|
else if (freq <= freq10 && freq > freq11)
|
|
ret = 10;
|
|
else if (freq <= freq11 && freq > freq12)
|
|
ret = 11;
|
|
else if (freq <= freq12 && freq > freq13)
|
|
ret = 12;
|
|
else if (freq <= freq13 && freq > freq14)
|
|
ret = 13;
|
|
else if (freq <= freq14 && freq > freq15)
|
|
ret = 14;
|
|
else
|
|
ret = 15;
|
|
|
|
mdla_dvfs_debug("%s opp %d\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
static bool mdla_update_lock_power_parameter
|
|
(struct mdla_lock_power *mdla_lock_power)
|
|
{
|
|
bool ret = true;
|
|
unsigned int i, core = 0xFFFFFFFF;
|
|
unsigned int priority = mdla_lock_power->priority;
|
|
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
if (mdla_lock_power->core == (0x1 << i)) {
|
|
core = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (core >= MTK_MDLA_USER) {
|
|
LOG_ERR("wrong core index (0x%x/%d/%d)",
|
|
mdla_lock_power->core, core, MTK_MDLA_USER);
|
|
ret = false;
|
|
return ret;
|
|
}
|
|
lock_power[priority][core].core = core;
|
|
lock_power[priority][core].max_boost_value =
|
|
mdla_lock_power->max_boost_value;
|
|
lock_power[priority][core].min_boost_value =
|
|
mdla_lock_power->min_boost_value;
|
|
lock_power[priority][core].lock = true;
|
|
lock_power[priority][core].priority =
|
|
mdla_lock_power->priority;
|
|
mdla_dvfs_debug("power_para core %d, maxboost:%d, minboost:%d pri%d\n",
|
|
lock_power[priority][core].core,
|
|
lock_power[priority][core].max_boost_value,
|
|
lock_power[priority][core].min_boost_value,
|
|
lock_power[priority][core].priority);
|
|
return ret;
|
|
}
|
|
static bool mdla_update_unlock_power_parameter
|
|
(struct mdla_lock_power *mdla_lock_power)
|
|
{
|
|
bool ret = true;
|
|
unsigned int i, core = 0xFFFFFFFF;
|
|
unsigned int priority = mdla_lock_power->priority;
|
|
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
if (mdla_lock_power->core == (0x1 << i)) {
|
|
core = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (core >= MTK_MDLA_USER) {
|
|
LOG_ERR("wrong core index (0x%x/%d/%d)",
|
|
mdla_lock_power->core, core, MTK_MDLA_USER);
|
|
ret = false;
|
|
return ret;
|
|
}
|
|
|
|
lock_power[priority][core].core =
|
|
mdla_lock_power->core;
|
|
lock_power[priority][core].max_boost_value =
|
|
mdla_lock_power->max_boost_value;
|
|
lock_power[priority][core].min_boost_value =
|
|
mdla_lock_power->min_boost_value;
|
|
lock_power[priority][core].lock = false;
|
|
lock_power[priority][core].priority =
|
|
mdla_lock_power->priority;
|
|
mdla_dvfs_debug("%s\n", __func__);
|
|
return ret;
|
|
}
|
|
uint8_t mdla_min_of(uint8_t value1, uint8_t value2)
|
|
{
|
|
if (value1 <= value2)
|
|
return value1;
|
|
else
|
|
return value2;
|
|
}
|
|
uint8_t mdla_max_of(uint8_t value1, uint8_t value2)
|
|
{
|
|
if (value1 <= value2)
|
|
return value2;
|
|
else
|
|
return value1;
|
|
}
|
|
|
|
bool mdla_update_max_opp(struct mdla_lock_power *mdla_lock_power)
|
|
{
|
|
bool ret = true;
|
|
unsigned int i, core = 0xFFFFFFFF;
|
|
uint8_t first_priority = MDLA_OPP_NORMAL;
|
|
uint8_t first_priority_max_boost_value = 100;
|
|
uint8_t first_priority_min_boost_value = 0;
|
|
uint8_t temp_max_boost_value = 100;
|
|
uint8_t temp_min_boost_value = 0;
|
|
bool lock = false;
|
|
uint8_t max_boost = 100;
|
|
uint8_t min_boost = 0;
|
|
uint8_t priority = MDLA_OPP_NORMAL;
|
|
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
if (mdla_lock_power->core == (0x1 << i)) {
|
|
core = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (core >= MTK_MDLA_USER) {
|
|
LOG_ERR("wrong core index (0x%x/%d/%d)",
|
|
mdla_lock_power->core, core, MTK_MDLA_USER);
|
|
ret = false;
|
|
return ret;
|
|
}
|
|
|
|
for (i = 0 ; i < MDLA_OPP_PRIORIYY_NUM ; i++) {
|
|
if (lock_power[i][core].lock == true
|
|
&& lock_power[i][core].priority < MDLA_OPP_NORMAL) {
|
|
first_priority = i;
|
|
first_priority_max_boost_value =
|
|
lock_power[i][core].max_boost_value;
|
|
first_priority_min_boost_value =
|
|
lock_power[i][core].min_boost_value;
|
|
break;
|
|
}
|
|
}
|
|
temp_max_boost_value = first_priority_max_boost_value;
|
|
temp_min_boost_value = first_priority_min_boost_value;
|
|
/*find final_max_boost_value*/
|
|
for (i = first_priority ; i < MDLA_OPP_PRIORIYY_NUM ; i++) {
|
|
lock = lock_power[i][core].lock;
|
|
max_boost = lock_power[i][core].max_boost_value;
|
|
min_boost = lock_power[i][core].min_boost_value;
|
|
priority = lock_power[i][core].priority;
|
|
if (lock == true) {
|
|
if (priority < MDLA_OPP_NORMAL &&
|
|
(((max_boost <= temp_max_boost_value) &&
|
|
(max_boost >= temp_min_boost_value)) ||
|
|
((min_boost <= temp_max_boost_value) &&
|
|
(min_boost >= temp_min_boost_value)) ||
|
|
((max_boost >= temp_max_boost_value) &&
|
|
(min_boost <= temp_min_boost_value)))) {
|
|
|
|
temp_max_boost_value =
|
|
mdla_min_of(temp_max_boost_value, max_boost);
|
|
temp_min_boost_value =
|
|
mdla_max_of(temp_min_boost_value, min_boost);
|
|
|
|
}
|
|
}
|
|
}
|
|
max_opp[core] = mdla_boost_value_to_opp(temp_max_boost_value);
|
|
min_opp[core] = mdla_boost_value_to_opp(temp_min_boost_value);
|
|
maxboost[core] = temp_max_boost_value;
|
|
minboost[core] = temp_min_boost_value;
|
|
mdla_dvfs_debug("final_min_boost_value:%d final_max_boost_value:%d\n",
|
|
temp_min_boost_value, temp_max_boost_value);
|
|
return ret;
|
|
}
|
|
|
|
static int mdla_lock_set_power(struct mdla_lock_power *mdla_lock_power)
|
|
{
|
|
int ret = -1;
|
|
unsigned int i, core = 0xFFFFFFFF;
|
|
|
|
mutex_lock(&power_lock_mutex);
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
if (mdla_lock_power->core == (0x1 << i)) {
|
|
core = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (core >= MTK_MDLA_USER) {
|
|
LOG_ERR("wrong core index (0x%x/%d/%d)",
|
|
mdla_lock_power->core, core, MTK_MDLA_USER);
|
|
ret = -1;
|
|
mutex_unlock(&power_lock_mutex);
|
|
return ret;
|
|
}
|
|
|
|
|
|
if (!mdla_update_lock_power_parameter(mdla_lock_power)) {
|
|
mutex_unlock(&power_lock_mutex);
|
|
return -1;
|
|
}
|
|
if (!mdla_update_max_opp(mdla_lock_power)) {
|
|
mutex_unlock(&power_lock_mutex);
|
|
return -1;
|
|
}
|
|
mutex_unlock(&power_lock_mutex);
|
|
return 0;
|
|
}
|
|
|
|
static int mdla_unlock_set_power(struct mdla_lock_power *mdla_lock_power)
|
|
{
|
|
int ret = -1;
|
|
unsigned int i, core = 0xFFFFFFFF;
|
|
|
|
mutex_lock(&power_lock_mutex);
|
|
for (i = 0 ; i < MTK_MDLA_USER ; i++) {
|
|
if (mdla_lock_power->core == (0x1 << i)) {
|
|
core = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (core >= MTK_MDLA_USER) {
|
|
LOG_ERR("wrong core index (0x%x/%d/%d)",
|
|
mdla_lock_power->core, core, MTK_MDLA_USER);
|
|
ret = false;
|
|
mutex_unlock(&power_lock_mutex);
|
|
return ret;
|
|
}
|
|
if (!mdla_update_unlock_power_parameter(mdla_lock_power)) {
|
|
mutex_unlock(&power_lock_mutex);
|
|
return -1;
|
|
}
|
|
if (!mdla_update_max_opp(mdla_lock_power)) {
|
|
mutex_unlock(&power_lock_mutex);
|
|
return -1;
|
|
}
|
|
mutex_unlock(&power_lock_mutex);
|
|
return ret;
|
|
|
|
}
|
|
//static __u8 mdla_get_first_priority_cmd(struct list_head *cmd_list)
|
|
//{
|
|
// struct command_entry *iter, *n;
|
|
// __u8 first_priority = MDLA_REQ_MAX_NUM_PRIORITY-1;
|
|
//
|
|
// if (!list_empty(cmd_list)) {
|
|
// list_for_each_entry_safe(iter, n, cmd_list, list) {
|
|
// if (iter->priority < first_priority)
|
|
// first_priority = iter->priority;
|
|
// }
|
|
// } else
|
|
// first_priority = 0;
|
|
//
|
|
//
|
|
// LOG_INF("%s:first_priority=%d\n", __func__, first_priority);
|
|
// return first_priority;
|
|
//}
|
|
|
|
long mdla_dvfs_ioctl(struct file *filp, unsigned int command,
|
|
unsigned long arg)
|
|
{
|
|
long retval = 0;
|
|
|
|
switch (command) {
|
|
case IOCTL_SET_POWER:
|
|
{
|
|
struct mdla_power power;
|
|
|
|
if (copy_from_user(&power, (void *) arg,
|
|
sizeof(struct mdla_power))) {
|
|
retval = -EFAULT;
|
|
return retval;
|
|
}
|
|
|
|
retval = mdla_set_power(&power);
|
|
LOG_INF("[SET_POWER] ret=%ld\n", retval);
|
|
return retval;
|
|
|
|
break;
|
|
}
|
|
|
|
case IOCTL_EARA_LOCK_POWER:
|
|
{
|
|
struct mdla_lock_power mdla_lock_power;
|
|
|
|
if (copy_from_user(&mdla_lock_power, (void *) arg,
|
|
sizeof(struct mdla_lock_power))) {
|
|
retval = -EFAULT;
|
|
return retval;
|
|
}
|
|
|
|
mdla_lock_power.lock = true;
|
|
mdla_lock_power.priority = MDLA_OPP_EARA_QOS;
|
|
LOG_INF("[mdla] IOCTL_EARA_LOCK_POWER +,maxboost:%d, minboost:%d\n",
|
|
mdla_lock_power.max_boost_value, mdla_lock_power.min_boost_value);
|
|
retval = mdla_lock_set_power(&mdla_lock_power);
|
|
return retval;
|
|
|
|
break;
|
|
}
|
|
case IOCTL_EARA_UNLOCK_POWER:
|
|
{
|
|
struct mdla_lock_power mdla_lock_power;
|
|
|
|
if (copy_from_user(&mdla_lock_power, (void *) arg,
|
|
sizeof(struct mdla_lock_power))) {
|
|
retval = -EFAULT;
|
|
return retval;
|
|
}
|
|
mdla_lock_power.lock = false;
|
|
mdla_lock_power.priority = MDLA_OPP_EARA_QOS;
|
|
LOG_INF("[mdla] IOCTL_EARA_UNLOCK_POWER +\n");
|
|
retval = mdla_unlock_set_power(&mdla_lock_power);
|
|
return retval;
|
|
|
|
break;
|
|
}
|
|
case IOCTL_POWER_HAL_LOCK_POWER:
|
|
{
|
|
struct mdla_lock_power mdla_lock_power;
|
|
|
|
if (copy_from_user(&mdla_lock_power, (void *) arg,
|
|
sizeof(struct mdla_lock_power))) {
|
|
retval = -EFAULT;
|
|
return retval;
|
|
}
|
|
mdla_lock_power.lock = true;
|
|
mdla_lock_power.priority = MDLA_OPP_POWER_HAL;
|
|
LOG_INF("[mdla] IOCTL_POWER_HAL_LOCK_POWER +, maxboost:%d, minboost:%d\n",
|
|
mdla_lock_power.max_boost_value, mdla_lock_power.min_boost_value);
|
|
retval = mdla_lock_set_power(&mdla_lock_power);
|
|
return retval;
|
|
|
|
break;
|
|
}
|
|
case IOCTL_POWER_HAL_UNLOCK_POWER:
|
|
{
|
|
struct mdla_lock_power mdla_lock_power;
|
|
|
|
if (copy_from_user(&mdla_lock_power, (void *) arg,
|
|
sizeof(struct mdla_lock_power))) {
|
|
retval = -EFAULT;
|
|
return retval;
|
|
}
|
|
mdla_lock_power.lock = false;
|
|
mdla_lock_power.priority = MDLA_OPP_POWER_HAL;
|
|
LOG_INF("[mdla] IOCTL_POWER_HAL_UNLOCK_POWER +\n");
|
|
retval = mdla_unlock_set_power(&mdla_lock_power);
|
|
return retval;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* command start: enable power & clock */
|
|
int mdla_dvfs_cmd_start(struct command_entry *ce)
|
|
{
|
|
int ret = 0;
|
|
uint8_t opp_step = 0;
|
|
uint8_t vmdla_opp_index = 0xFF;
|
|
uint8_t dsp_freq_index = 0xFF;
|
|
|
|
if (ce) {
|
|
opp_step = mdla_boost_value_to_opp(ce->boost_value);
|
|
vmdla_opp_index = opps.vmdla.opp_map[opp_step];
|
|
dsp_freq_index = opps.mdlacore.opp_map[opp_step];
|
|
|
|
mdla_opp_check(0, vmdla_opp_index, dsp_freq_index);
|
|
}
|
|
|
|
/* step1, enable clocks and boot-up if needed */
|
|
|
|
ret = mdla_get_power(0);
|
|
|
|
if (ret) {
|
|
apu_get_power_info();
|
|
LOG_ERR("[mdla] fail to get power!\n");
|
|
return ret;
|
|
}
|
|
#if defined(MDLA_MET_READY)
|
|
MDLA_MET_Events_Trace(1, 0);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
/* command end: save bandwidth info to command entry */
|
|
int mdla_dvfs_cmd_end_info(struct command_entry *ce)
|
|
{
|
|
int i; // TODO: remove me
|
|
|
|
if (ce == NULL)
|
|
return 0;
|
|
|
|
for (i = 0; i < 16; i++) // TODO: remove me
|
|
ce->bandwidth = i;
|
|
|
|
// TODO: Put bandwidth to ce->bandwidth.
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* command end: fifo empty, shutdown */
|
|
int mdla_dvfs_cmd_end_shutdown(void)
|
|
{
|
|
|
|
mdla_put_power(0);
|
|
#if defined(MDLA_MET_READY)
|
|
MDLA_MET_Events_Trace(0, 0);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|