544 lines
17 KiB
C
Executable file
544 lines
17 KiB
C
Executable file
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <soc/samsung/cal-if.h>
|
|
#include <soc/samsung/exynos-profiler.h>
|
|
#include <soc/samsung/exynos-migov.h>
|
|
#include <soc/samsung/exynos-sci.h>
|
|
|
|
#include <soc/samsung/exynos-devfreq.h>
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
#include <soc/samsung/exynos-bcm_dbg.h>
|
|
#else
|
|
#include <soc/samsung/exynos-wow.h>
|
|
#endif
|
|
|
|
/* Result during profile time */
|
|
struct profile_result {
|
|
struct freq_cstate_result fc_result;
|
|
|
|
s32 cur_temp;
|
|
s32 avg_temp;
|
|
|
|
/* private data */
|
|
u64 *freq_stats[4];
|
|
u64 freq_stats0_sum;
|
|
u64 freq_stats_ratio;
|
|
u64 freq_stats0_avg;
|
|
u64 freq_stats1_sum;
|
|
int llc_status;
|
|
};
|
|
|
|
static struct profiler {
|
|
struct device_node *root;
|
|
|
|
int enabled;
|
|
|
|
s32 migov_id;
|
|
u32 cal_id;
|
|
u32 devfreq_type;
|
|
|
|
struct freq_table *table;
|
|
u32 table_cnt;
|
|
u32 dyn_pwr_coeff;
|
|
u32 st_pwr_coeff;
|
|
|
|
const char *tz_name; /* currently do not use in MIF */
|
|
struct thermal_zone_device *tz; /* currently do not use in MIF */
|
|
|
|
struct freq_cstate fc; /* latest time_in_state info */
|
|
struct freq_cstate_snapshot fc_snap[NUM_OF_USER]; /* previous time_in_state info */
|
|
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
u64 *freq_stats[4];
|
|
u64 *freq_stats_snap[4];
|
|
#else
|
|
struct exynos_wow_profile *prev_profile;
|
|
#endif
|
|
|
|
u32 cur_freq_idx; /* current freq_idx */
|
|
u32 max_freq_idx; /* current max_freq_idx */
|
|
u32 min_freq_idx; /* current min_freq_idx */
|
|
|
|
struct profile_result result[NUM_OF_USER];
|
|
|
|
struct kobject kobj;
|
|
|
|
struct exynos_devfreq_freq_infos freq_infos;
|
|
} profiler;
|
|
|
|
/************************************************************************
|
|
* HELPER *
|
|
************************************************************************/
|
|
|
|
static inline void calc_delta(u64 *result_table, u64 *prev_table, u64 *cur_table, int size)
|
|
{
|
|
int i;
|
|
u64 delta, cur;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
cur = cur_table[i];
|
|
delta = cur - prev_table[i];
|
|
result_table[i] = delta;
|
|
prev_table[i] = cur;
|
|
}
|
|
}
|
|
|
|
/************************************************************************
|
|
* SUPPORT-MIGOV *
|
|
************************************************************************/
|
|
u32 mifpro_get_table_cnt(s32 id)
|
|
{
|
|
return profiler.table_cnt;
|
|
}
|
|
|
|
u32 mifpro_get_freq_table(s32 id, u32 *table)
|
|
{
|
|
int idx;
|
|
for (idx = 0; idx < profiler.table_cnt; idx++)
|
|
table[idx] = profiler.table[idx].freq;
|
|
|
|
return idx;
|
|
}
|
|
|
|
u32 mifpro_get_max_freq(s32 id)
|
|
{
|
|
return exynos_pm_qos_request(profiler.freq_infos.pm_qos_class_max);
|
|
}
|
|
|
|
u32 mifpro_get_min_freq(s32 id)
|
|
{
|
|
return exynos_pm_qos_request(profiler.freq_infos.pm_qos_class);
|
|
}
|
|
|
|
u32 mifpro_get_freq(s32 id)
|
|
{
|
|
return profiler.result[MIGOV].fc_result.freq[ACTIVE];
|
|
}
|
|
|
|
void mifpro_get_power(s32 id, u64 *dyn_power, u64 *st_power)
|
|
{
|
|
*dyn_power = profiler.result[MIGOV].fc_result.dyn_power;
|
|
*st_power = profiler.result[MIGOV].fc_result.st_power;
|
|
}
|
|
|
|
void mifpro_get_power_change(s32 id, s32 freq_delta_ratio,
|
|
u32 *freq, u64 *dyn_power, u64 *st_power)
|
|
{
|
|
struct profile_result *result = &profiler.result[MIGOV];
|
|
struct freq_cstate_result *fc_result = &result->fc_result;
|
|
int flag = (STATE_SCALE_WO_SPARE | STATE_SCALE_CNT);
|
|
u64 dyn_power_backup;
|
|
|
|
get_power_change(profiler.table, profiler.table_cnt,
|
|
profiler.cur_freq_idx, profiler.min_freq_idx, profiler.max_freq_idx,
|
|
result->freq_stats[0], fc_result->time[CLK_OFF], freq_delta_ratio,
|
|
fc_result->profile_time, result->avg_temp, flag, dyn_power, st_power, freq);
|
|
|
|
dyn_power_backup = *dyn_power;
|
|
|
|
get_power_change(profiler.table, profiler.table_cnt,
|
|
profiler.cur_freq_idx, profiler.min_freq_idx, profiler.max_freq_idx,
|
|
fc_result->time[ACTIVE], fc_result->time[CLK_OFF], freq_delta_ratio,
|
|
fc_result->profile_time, result->avg_temp, flag, dyn_power, st_power, freq);
|
|
|
|
*dyn_power = dyn_power_backup;
|
|
}
|
|
|
|
u32 mifpro_get_active_pct(s32 id)
|
|
{
|
|
return profiler.result[MIGOV].fc_result.ratio[ACTIVE];
|
|
}
|
|
|
|
s32 mifpro_get_temp(s32 id)
|
|
{
|
|
return profiler.result[MIGOV].avg_temp;
|
|
}
|
|
void mifpro_set_margin(s32 id, s32 margin)
|
|
{
|
|
return;
|
|
}
|
|
|
|
u32 mifpro_update_profile(int user);
|
|
u32 mifpro_update_mode(s32 id, int mode)
|
|
{
|
|
int i;
|
|
|
|
if (profiler.enabled == 0 && mode == 1) {
|
|
struct freq_cstate *fc = &profiler.fc;
|
|
struct freq_cstate_snapshot *fc_snap = &profiler.fc_snap[MIGOV];
|
|
|
|
sync_fcsnap_with_cur(fc, fc_snap, profiler.table_cnt);
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
exynos_bcm_calc_enable(1);
|
|
#endif
|
|
|
|
profiler.enabled = mode;
|
|
|
|
exynos_devfreq_set_profile(profiler.devfreq_type, 1);
|
|
}
|
|
else if (profiler.enabled == 1 && mode == 0) {
|
|
exynos_devfreq_set_profile(profiler.devfreq_type, 0);
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
exynos_bcm_calc_enable(0);
|
|
#endif
|
|
profiler.enabled = mode;
|
|
|
|
// clear
|
|
for (i = 0; i < NUM_OF_CSTATE; i++) {
|
|
memset(profiler.result[MIGOV].fc_result.time[i], 0, sizeof(ktime_t) * profiler.table_cnt);
|
|
profiler.result[MIGOV].fc_result.ratio[i] = 0;
|
|
profiler.result[MIGOV].fc_result.freq[i] = 0;
|
|
memset(profiler.fc.time[i], 0, sizeof(ktime_t) * profiler.table_cnt);
|
|
memset(profiler.fc_snap[MIGOV].time[i], 0, sizeof(ktime_t) * profiler.table_cnt);
|
|
}
|
|
profiler.result[MIGOV].fc_result.dyn_power = 0;
|
|
profiler.result[MIGOV].fc_result.st_power = 0;
|
|
profiler.result[MIGOV].fc_result.profile_time = 0;
|
|
profiler.result[MIGOV].freq_stats0_sum = 0;
|
|
profiler.result[MIGOV].freq_stats0_avg = 0;
|
|
profiler.result[MIGOV].freq_stats1_sum = 0;
|
|
profiler.result[MIGOV].freq_stats_ratio = 0;
|
|
profiler.fc_snap[MIGOV].last_snap_time = 0;
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
for (i = 0; i < 4; i++) {
|
|
memset(profiler.freq_stats[i], 0, sizeof(u64) * profiler.table_cnt);
|
|
memset(profiler.freq_stats_snap[i], 0, sizeof(u64) * profiler.table_cnt);
|
|
memset(profiler.result[MIGOV].freq_stats[i], 0, sizeof(u64) * profiler.table_cnt);
|
|
|
|
}
|
|
|
|
#else
|
|
memset(profiler.prev_profile, 0, sizeof(struct exynos_wow_profile) * profiler.table_cnt);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
mifpro_update_profile(MIGOV);
|
|
|
|
return 0;
|
|
}
|
|
|
|
u64 mifpro_get_freq_stats0_sum(void) { return profiler.result[MIGOV].freq_stats0_sum; };
|
|
u64 mifpro_get_freq_stats1_sum(void) { return profiler.result[MIGOV].freq_stats1_sum; };
|
|
u64 mifpro_get_freq_stats0_avg(void) { return profiler.result[MIGOV].freq_stats0_avg; };
|
|
u64 mifpro_get_freq_stats_ratio(void) { return profiler.result[MIGOV].freq_stats_ratio; };
|
|
u64 mifpro_get_llc_status(void) { return profiler.result[MIGOV].llc_status; };
|
|
|
|
struct private_fn_mif mif_pd_fn = {
|
|
.get_stats0_sum = &mifpro_get_freq_stats0_sum,
|
|
.get_stats0_avg = &mifpro_get_freq_stats0_avg,
|
|
.get_stats1_sum = &mifpro_get_freq_stats1_sum,
|
|
.get_stats_ratio = &mifpro_get_freq_stats_ratio,
|
|
.get_llc_status = &mifpro_get_llc_status,
|
|
};
|
|
|
|
struct domain_fn mif_fn = {
|
|
.get_table_cnt = &mifpro_get_table_cnt,
|
|
.get_freq_table = &mifpro_get_freq_table,
|
|
.get_max_freq = &mifpro_get_max_freq,
|
|
.get_min_freq = &mifpro_get_min_freq,
|
|
.get_freq = &mifpro_get_freq,
|
|
.get_power = &mifpro_get_power,
|
|
.get_power_change = &mifpro_get_power_change,
|
|
.get_active_pct = &mifpro_get_active_pct,
|
|
.get_temp = &mifpro_get_temp,
|
|
.set_margin = &mifpro_set_margin,
|
|
.update_mode = &mifpro_update_mode,
|
|
};
|
|
|
|
/************************************************************************
|
|
* Gathering MIFFreq Information *
|
|
************************************************************************/
|
|
//ktime_t * exynos_stats_get_mif_time_in_state(void);
|
|
extern u64 exynos_bcm_get_ccnt(unsigned int idx);
|
|
u32 mifpro_update_profile(int user)
|
|
{
|
|
struct freq_cstate *fc = &profiler.fc;
|
|
struct freq_cstate_snapshot *fc_snap = &profiler.fc_snap[user];
|
|
struct freq_cstate_result *fc_result = &profiler.result[user].fc_result;
|
|
struct profile_result *result = &profiler.result[user];
|
|
int i;
|
|
u64 total_active_time = 0, freq_stats2_sum = 0, freq_stats3_sum = 0, diff_ccnt = 0;
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
u64 ccnt = 0;
|
|
static u64 prev_ccnt = 0;
|
|
#else
|
|
struct exynos_wow_profile *profile_in_state;
|
|
#endif
|
|
|
|
profiler.cur_freq_idx = get_idx_from_freq(profiler.table, profiler.table_cnt,
|
|
*(profiler.freq_infos.cur_freq), RELATION_LOW);
|
|
profiler.max_freq_idx = get_idx_from_freq(profiler.table, profiler.table_cnt,
|
|
exynos_pm_qos_request(profiler.freq_infos.pm_qos_class_max), RELATION_LOW);
|
|
profiler.min_freq_idx = get_idx_from_freq(profiler.table, profiler.table_cnt,
|
|
exynos_pm_qos_request(profiler.freq_infos.pm_qos_class), RELATION_HIGH);
|
|
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
// Update time in state and get tables from DVFS driver
|
|
exynos_devfreq_get_profile(profiler.devfreq_type, fc->time, profiler.freq_stats);
|
|
|
|
// calculate delta from previous status
|
|
make_snapshot_and_time_delta(fc, fc_snap, fc_result, profiler.table_cnt);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
calc_delta(result->freq_stats[i], profiler.freq_stats_snap[i], profiler.freq_stats[i], profiler.table_cnt);
|
|
// Call to calc power
|
|
compute_freq_cstate_result(profiler.table, fc_result, profiler.table_cnt,
|
|
profiler.cur_freq_idx, result->avg_temp);
|
|
|
|
ccnt = exynos_bcm_get_ccnt(0);
|
|
|
|
diff_ccnt = ccnt - prev_ccnt;
|
|
prev_ccnt = ccnt;
|
|
#else
|
|
profile_in_state = kzalloc(sizeof(struct exynos_wow_profile) * profiler.table_cnt, GFP_KERNEL);
|
|
|
|
exynos_devfreq_get_profile(profiler.devfreq_type, fc->time, profile_in_state);
|
|
|
|
// calculate delta from previous status
|
|
make_snapshot_and_time_delta(fc, fc_snap, fc_result, profiler.table_cnt);
|
|
|
|
// Call to calc power
|
|
compute_freq_cstate_result(profiler.table, fc_result, profiler.table_cnt,
|
|
profiler.cur_freq_idx, result->avg_temp);
|
|
|
|
// Calculate freq_stats array
|
|
for (i = 0; i < profiler.table_cnt; i++) {
|
|
result->freq_stats[0][i] = (profile_in_state[i].transfer_data - profiler.prev_profile[i].transfer_data) >> 20;
|
|
result->freq_stats[2][i] = (profile_in_state[i].nr_requests - profiler.prev_profile[i].nr_requests);
|
|
result->freq_stats[3][i] = (profile_in_state[i].mo_count - profiler.prev_profile[i].mo_count);
|
|
diff_ccnt += (profile_in_state[i].ccnt - profiler.prev_profile[i].ccnt);
|
|
}
|
|
memcpy(profiler.prev_profile, profile_in_state, sizeof(struct exynos_wow_profile) * profiler.table_cnt);
|
|
kfree(profile_in_state);
|
|
diff_ccnt /= 1000;
|
|
#endif
|
|
|
|
|
|
for (i = 0 ; i < profiler.table_cnt; i++)
|
|
fc->time[CLK_OFF][i] -= fc->time[ACTIVE][i];
|
|
result->freq_stats0_sum = 0;
|
|
result->freq_stats1_sum = 0;
|
|
fc_result->dyn_power = 0;
|
|
|
|
for (i = 0; i < profiler.table_cnt; i++) {
|
|
result->freq_stats0_sum += result->freq_stats[0][i];
|
|
result->freq_stats1_sum += result->freq_stats[1][i];
|
|
result->freq_stats0_avg += (result->freq_stats[0][i] << 40) / (profiler.table[i].freq / 1000);
|
|
total_active_time += fc_result->time[ACTIVE][i];
|
|
freq_stats2_sum += result->freq_stats[2][i];
|
|
freq_stats3_sum += result->freq_stats[3][i];
|
|
fc_result->dyn_power += ((result->freq_stats[0][i] * profiler.table[i].dyn_cost) / fc_result->profile_time);
|
|
}
|
|
|
|
result->freq_stats0_sum = result->freq_stats0_sum * 1000000000 / fc_result->profile_time;
|
|
result->freq_stats1_sum = result->freq_stats1_sum * 1000000000 / fc_result->profile_time;
|
|
result->freq_stats0_avg = result->freq_stats0_avg / total_active_time;
|
|
result->freq_stats_ratio = fc_result->profile_time * freq_stats3_sum / freq_stats2_sum / diff_ccnt;
|
|
result->llc_status = llc_get_en();
|
|
|
|
if (profiler.tz) {
|
|
int temp = get_temp(profiler.tz);
|
|
profiler.result[user].avg_temp = (temp + profiler.result[user].cur_temp) >> 1;
|
|
profiler.result[user].cur_temp = temp;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************
|
|
* INITIALIZATON *
|
|
************************************************************************/
|
|
/* Initialize profiler data */
|
|
static int register_export_fn(u32 *max_freq, u32 *min_freq, u32 *cur_freq)
|
|
{
|
|
struct exynos_devfreq_freq_infos *freq_infos = &profiler.freq_infos;
|
|
|
|
exynos_devfreq_get_freq_infos(profiler.devfreq_type, freq_infos);
|
|
|
|
// *max_freq = freq_infos->max_freq; /* get_org_max_freq(void) */
|
|
*max_freq = 3172000;
|
|
*min_freq = freq_infos->min_freq; /* get_org_min_freq(void) */
|
|
*cur_freq = *freq_infos->cur_freq; /* get_cur_freq(void) */
|
|
profiler.table_cnt = freq_infos->max_state; /* get_freq_table_cnt(void) */
|
|
/*
|
|
// 2020
|
|
profiler.fc.time[ACTIVE] = exynos_stats_get_mif_time_in_state();
|
|
|
|
// Olympus
|
|
profiler.fc.time[ACTIVE] = get_time_inf_freq(ACTIVE);
|
|
profiler.fc.time[CLKOFF] = get_time_in_freq(CLKOFF);
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_dt(struct device_node *dn)
|
|
{
|
|
int ret;
|
|
|
|
/* necessary data */
|
|
ret = of_property_read_u32(dn, "cal-id", &profiler.cal_id);
|
|
if (ret)
|
|
return -2;
|
|
|
|
/* un-necessary data */
|
|
ret = of_property_read_s32(dn, "migov-id", &profiler.migov_id);
|
|
if (ret)
|
|
profiler.migov_id = -1; /* Don't support migov */
|
|
|
|
ret = of_property_read_s32(dn, "devfreq-type", &profiler.devfreq_type);
|
|
if (ret)
|
|
profiler.devfreq_type = -1; /* Don't support migov */
|
|
|
|
of_property_read_u32(dn, "power-coefficient", &profiler.dyn_pwr_coeff);
|
|
of_property_read_u32(dn, "static-power-coefficient", &profiler.st_pwr_coeff);
|
|
// of_property_read_string(dn, "tz-name", &profiler.tz_name);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int init_profile_result(struct profile_result *result, int size)
|
|
{
|
|
int state;
|
|
|
|
if (init_freq_cstate_result(&result->fc_result, NUM_OF_CSTATE, size))
|
|
return -ENOMEM;
|
|
|
|
/* init private data */
|
|
for (state = 0; state < 4; state++) {
|
|
ktime_t *state_in_freq;
|
|
state_in_freq = alloc_state_in_freq(size);
|
|
if (!state_in_freq)
|
|
return -ENOMEM;
|
|
result->freq_stats[state] = state_in_freq;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_EXYNOS_DEBUG_INFO
|
|
static void show_profiler_info(void)
|
|
{
|
|
int idx;
|
|
|
|
pr_info("================ mif domain ================\n");
|
|
pr_info("min= %dKHz, max= %dKHz\n",
|
|
profiler.table[profiler.table_cnt - 1].freq, profiler.table[0].freq);
|
|
for (idx = 0; idx < profiler.table_cnt; idx++)
|
|
pr_info("lv=%3d freq=%8d volt=%8d dyn_cost=%5d st_cost=%5d\n",
|
|
idx, profiler.table[idx].freq, profiler.table[idx].volt,
|
|
profiler.table[idx].dyn_cost,
|
|
profiler.table[idx].st_cost);
|
|
if (profiler.tz_name)
|
|
pr_info("support temperature (tz_name=%s)\n", profiler.tz_name);
|
|
if (profiler.migov_id != -1)
|
|
pr_info("support migov domain(id=%d)\n", profiler.migov_id);
|
|
}
|
|
#endif
|
|
|
|
static int exynos_mif_profiler_probe(struct platform_device *pdev)
|
|
{
|
|
unsigned int org_max_freq, org_min_freq, cur_freq;
|
|
int ret, idx;
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
int i;
|
|
#endif
|
|
|
|
/* get node of device tree */
|
|
if (!pdev->dev.of_node) {
|
|
pr_err("mifpro: failed to get device treee\n");
|
|
return -EINVAL;
|
|
}
|
|
profiler.root = pdev->dev.of_node;
|
|
|
|
/* Parse data from Device Tree to init domain */
|
|
ret = parse_dt(profiler.root);
|
|
if (ret) {
|
|
pr_err("mifpro: failed to parse dt(ret: %d)\n", ret);
|
|
return -EINVAL;
|
|
}
|
|
|
|
register_export_fn(&org_max_freq, &org_min_freq, &cur_freq);
|
|
|
|
/* init freq table */
|
|
profiler.table = init_freq_table(NULL, profiler.table_cnt,
|
|
profiler.cal_id, org_max_freq, org_min_freq,
|
|
profiler.dyn_pwr_coeff, profiler.st_pwr_coeff,
|
|
PWR_COST_CVV, PWR_COST_CVV);
|
|
if (!profiler.table) {
|
|
pr_err("mifpro: failed to init freq_table\n");
|
|
return -EINVAL;
|
|
}
|
|
profiler.max_freq_idx = 0;
|
|
profiler.min_freq_idx = profiler.table_cnt - 1;
|
|
profiler.cur_freq_idx = get_idx_from_freq(profiler.table,
|
|
profiler.table_cnt, cur_freq, RELATION_HIGH);
|
|
|
|
if (init_freq_cstate(&profiler.fc, NUM_OF_CSTATE, profiler.table_cnt))
|
|
return -ENOMEM;
|
|
|
|
/* init snapshot & result table */
|
|
for (idx = 0; idx < NUM_OF_USER; idx++) {
|
|
if (init_freq_cstate_snapshot(&profiler.fc_snap[idx],
|
|
NUM_OF_CSTATE, profiler.table_cnt))
|
|
return -ENOMEM;
|
|
|
|
if (init_profile_result(&profiler.result[idx], profiler.table_cnt))
|
|
return -EINVAL;
|
|
#if defined(CONFIG_SOC_S5E9925_EVT0) || defined(CONFIG_SOC_S5E8825)
|
|
for (i = 0 ; i < 4; i++) {
|
|
profiler.freq_stats[i] = kzalloc(sizeof(u64) * profiler.table_cnt, GFP_KERNEL);
|
|
profiler.freq_stats_snap[i] = kzalloc(sizeof(u64) * profiler.table_cnt, GFP_KERNEL);
|
|
}
|
|
#else
|
|
profiler.prev_profile = kzalloc(sizeof(struct exynos_wow_profile) * profiler.table_cnt, GFP_KERNEL);
|
|
#endif
|
|
}
|
|
|
|
/* get thermal-zone to get temperature */
|
|
if (profiler.tz_name)
|
|
profiler.tz = init_temp(profiler.tz_name);
|
|
|
|
if (profiler.tz)
|
|
init_static_cost(profiler.table, profiler.table_cnt,
|
|
1, profiler.root, profiler.tz);
|
|
|
|
ret = exynos_migov_register_domain(MIGOV_MIF, &mif_fn, &mif_pd_fn);
|
|
|
|
#ifdef CONFIG_EXYNOS_DEBUG_INFO
|
|
show_profiler_info();
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct of_device_id exynos_mif_profiler_match[] = {
|
|
{
|
|
.compatible = "samsung,exynos-mif-profiler",
|
|
},
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, exynos_mif_profiler_match);
|
|
|
|
static struct platform_driver exynos_mif_profiler_driver = {
|
|
.probe = exynos_mif_profiler_probe,
|
|
.driver = {
|
|
.name = "exynos-mif-profiler",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = exynos_mif_profiler_match,
|
|
},
|
|
};
|
|
|
|
static int exynos_mif_profiler_init(void)
|
|
{
|
|
return platform_driver_register(&exynos_mif_profiler_driver);
|
|
}
|
|
late_initcall(exynos_mif_profiler_init);
|
|
|
|
MODULE_DESCRIPTION("Exynos MIF Profiler");
|
|
MODULE_LICENSE("GPL");
|