235 lines
5.3 KiB
C
235 lines
5.3 KiB
C
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/memory_alloc.h>
|
|
#include <mach/memory.h>
|
|
#include <mach/scm.h>
|
|
#include <mach/msm_dcvs_scm.h>
|
|
#include <trace/events/mpdcvs_trace.h>
|
|
|
|
#define DCVS_CMD_REGISTER_CORE 2
|
|
#define DCVS_CMD_SET_ALGO_PARAM 3
|
|
#define DCVS_CMD_EVENT 4
|
|
#define DCVS_CMD_INIT 5
|
|
#define DCVS_CMD_SET_POWER_PARAM 6
|
|
|
|
struct scm_register_core {
|
|
uint32_t core_id;
|
|
phys_addr_t core_param_phy;
|
|
};
|
|
|
|
struct scm_algo {
|
|
uint32_t core_id;
|
|
phys_addr_t algo_phy;
|
|
};
|
|
|
|
struct scm_init {
|
|
uint32_t phy;
|
|
uint32_t size;
|
|
};
|
|
|
|
struct scm_pwr_param {
|
|
uint32_t core_id;
|
|
phys_addr_t pwr_param_phy;
|
|
phys_addr_t freq_phy;
|
|
phys_addr_t coeffs_phy;
|
|
};
|
|
|
|
struct msm_algo_param {
|
|
enum msm_dcvs_algo_param_type type;
|
|
union {
|
|
struct msm_dcvs_algo_param dcvs_param;
|
|
struct msm_mpd_algo_param mpd_param;
|
|
} u;
|
|
};
|
|
|
|
int msm_dcvs_scm_init(size_t size)
|
|
{
|
|
int ret = 0;
|
|
struct scm_init init;
|
|
uint32_t p = 0;
|
|
|
|
/* Allocate word aligned non-cacheable memory */
|
|
p = allocate_contiguous_ebi_nomap(size, 4);
|
|
if (!p)
|
|
return -ENOMEM;
|
|
|
|
init.phy = p;
|
|
init.size = size;
|
|
|
|
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_INIT,
|
|
&init, sizeof(init), NULL, 0);
|
|
|
|
/* Not freed if the initialization succeeds */
|
|
if (ret)
|
|
free_contiguous_memory_by_paddr(p);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_dcvs_scm_init);
|
|
|
|
int msm_dcvs_scm_register_core(uint32_t core_id,
|
|
struct msm_dcvs_core_param *param)
|
|
{
|
|
int ret = 0;
|
|
struct scm_register_core reg_data;
|
|
struct msm_dcvs_core_param *p = NULL;
|
|
|
|
p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_core_param)), GFP_KERNEL);
|
|
if (!p)
|
|
return -ENOMEM;
|
|
|
|
memcpy(p, param, sizeof(struct msm_dcvs_core_param));
|
|
|
|
reg_data.core_id = core_id;
|
|
reg_data.core_param_phy = virt_to_phys(p);
|
|
|
|
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_REGISTER_CORE,
|
|
®_data, sizeof(reg_data), NULL, 0);
|
|
|
|
kfree(p);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_dcvs_scm_register_core);
|
|
|
|
int msm_dcvs_scm_set_algo_params(uint32_t core_id,
|
|
struct msm_dcvs_algo_param *param)
|
|
{
|
|
int ret = 0;
|
|
struct scm_algo algo;
|
|
struct msm_algo_param *p = NULL;
|
|
|
|
p = kzalloc(PAGE_ALIGN(sizeof(struct msm_algo_param)), GFP_KERNEL);
|
|
if (!p)
|
|
return -ENOMEM;
|
|
|
|
p->type = MSM_DCVS_ALGO_DCVS_PARAM;
|
|
memcpy(&p->u.dcvs_param, param, sizeof(struct msm_dcvs_algo_param));
|
|
|
|
algo.core_id = core_id;
|
|
algo.algo_phy = virt_to_phys(p);
|
|
|
|
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
|
|
&algo, sizeof(algo), NULL, 0);
|
|
|
|
kfree(p);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_dcvs_scm_set_algo_params);
|
|
|
|
int msm_mpd_scm_set_algo_params(struct msm_mpd_algo_param *param)
|
|
{
|
|
int ret = 0;
|
|
struct scm_algo algo;
|
|
struct msm_algo_param *p = NULL;
|
|
|
|
p = kzalloc(PAGE_ALIGN(sizeof(struct msm_algo_param)), GFP_KERNEL);
|
|
if (!p)
|
|
return -ENOMEM;
|
|
|
|
p->type = MSM_DCVS_ALGO_MPD_PARAM;
|
|
memcpy(&p->u.mpd_param, param, sizeof(struct msm_mpd_algo_param));
|
|
|
|
algo.core_id = 0;
|
|
algo.algo_phy = virt_to_phys(p);
|
|
|
|
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
|
|
&algo, sizeof(algo), NULL, 0);
|
|
|
|
kfree(p);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_mpd_scm_set_algo_params);
|
|
|
|
int msm_dcvs_scm_set_power_params(uint32_t core_id,
|
|
struct msm_dcvs_power_params *pwr_param,
|
|
struct msm_dcvs_freq_entry *freq_entry,
|
|
struct msm_dcvs_energy_curve_coeffs *coeffs)
|
|
{
|
|
int ret = 0;
|
|
struct scm_pwr_param pwr;
|
|
struct msm_dcvs_power_params *pwrt = NULL;
|
|
struct msm_dcvs_freq_entry *freqt = NULL;
|
|
struct msm_dcvs_energy_curve_coeffs *coefft = NULL;
|
|
|
|
pwrt = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_power_params)),
|
|
GFP_KERNEL);
|
|
if (!pwrt)
|
|
return -ENOMEM;
|
|
|
|
freqt = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_freq_entry)
|
|
* pwr_param->num_freq),
|
|
GFP_KERNEL);
|
|
if (!freqt) {
|
|
kfree(pwrt);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
coefft = kzalloc(PAGE_ALIGN(
|
|
sizeof(struct msm_dcvs_energy_curve_coeffs)),
|
|
GFP_KERNEL);
|
|
if (!coefft) {
|
|
kfree(pwrt);
|
|
kfree(freqt);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(pwrt, pwr_param, sizeof(struct msm_dcvs_power_params));
|
|
memcpy(freqt, freq_entry,
|
|
sizeof(struct msm_dcvs_freq_entry)*pwr_param->num_freq);
|
|
memcpy(coefft, coeffs, sizeof(struct msm_dcvs_energy_curve_coeffs));
|
|
|
|
pwr.core_id = core_id;
|
|
pwr.pwr_param_phy = virt_to_phys(pwrt);
|
|
pwr.freq_phy = virt_to_phys(freqt);
|
|
pwr.coeffs_phy = virt_to_phys(coefft);
|
|
|
|
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_POWER_PARAM,
|
|
&pwr, sizeof(pwr), NULL, 0);
|
|
|
|
kfree(pwrt);
|
|
kfree(freqt);
|
|
kfree(coefft);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_dcvs_scm_set_power_params);
|
|
|
|
int msm_dcvs_scm_event(uint32_t core_id,
|
|
enum msm_dcvs_scm_event event_id,
|
|
uint32_t param0, uint32_t param1,
|
|
uint32_t *ret0, uint32_t *ret1)
|
|
{
|
|
int ret = -EINVAL;
|
|
|
|
if (!ret0 || !ret1)
|
|
return ret;
|
|
|
|
ret = scm_call_atomic4_3(SCM_SVC_DCVS, DCVS_CMD_EVENT,
|
|
core_id, event_id, param0, param1, ret0, ret1);
|
|
|
|
trace_msm_dcvs_scm_event(core_id, (int)event_id, param0, param1,
|
|
*ret0, *ret1);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(msm_dcvs_scm_event);
|