315 lines
7.8 KiB
C
Executable File
315 lines
7.8 KiB
C
Executable File
#include "pmucal_cpu.h"
|
|
#ifdef CONFIG_FLEXPMU
|
|
#include "pmucal_powermode.h"
|
|
#endif
|
|
#include "pmucal_rae.h"
|
|
|
|
#ifdef CONFIG_FLEXPMU
|
|
unsigned int cpu_inform_c2;
|
|
unsigned int cpu_inform_cpd;
|
|
#endif
|
|
|
|
/**
|
|
* pmucal_cpu_enable - enables a core.
|
|
* exposed to PWRCAL interface.
|
|
*
|
|
* @cpu: cpu core index.
|
|
*
|
|
* Returns 0 on success. Otherwise, negative error code.
|
|
*/
|
|
int pmucal_cpu_enable(unsigned int cpu)
|
|
{
|
|
int ret;
|
|
|
|
if (cpu >= pmucal_cpu_list_size) {
|
|
pr_err("%s core index(%d) is out of supported range (0~%d).\n",
|
|
PMUCAL_PREFIX, cpu, pmucal_cpu_list_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!pmucal_cpu_list[cpu].on) {
|
|
pr_err("%s there is no sequence element for core(%d) power-on.\n",
|
|
PMUCAL_PREFIX, cpu);
|
|
return -ENOENT;
|
|
}
|
|
#ifdef CONFIG_FLEXPMU
|
|
pmucal_powermode_hint_clear();
|
|
#endif
|
|
ret = pmucal_rae_handle_seq(pmucal_cpu_list[cpu].on,
|
|
pmucal_cpu_list[cpu].num_on);
|
|
if (ret) {
|
|
pr_err("%s %s: error on handling enable sequence. (cpu : %d)\n",
|
|
PMUCAL_PREFIX, __func__, cpu);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pmucal_cpu_disable - disables a core.
|
|
* exposed to PWRCAL interface.
|
|
*
|
|
* @cpu: cpu core index.
|
|
*
|
|
* Returns 0 on success. Otherwise, negative error code.
|
|
*/
|
|
int pmucal_cpu_disable(unsigned int cpu)
|
|
{
|
|
int ret;
|
|
|
|
if (cpu >= pmucal_cpu_list_size) {
|
|
pr_err("%s core index(%d) is out of supported range (0~%d).\n",
|
|
PMUCAL_PREFIX, cpu, pmucal_cpu_list_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!pmucal_cpu_list[cpu].off) {
|
|
pr_err("%s there is no sequence element for core(%d) power-off.\n",
|
|
PMUCAL_PREFIX, cpu);
|
|
return -ENOENT;
|
|
}
|
|
#ifdef CONFIG_FLEXPMU
|
|
pmucal_powermode_hint(cpu_inform_c2);
|
|
#endif
|
|
|
|
ret = pmucal_rae_handle_seq(pmucal_cpu_list[cpu].off,
|
|
pmucal_cpu_list[cpu].num_off);
|
|
if (ret) {
|
|
pr_err("%s %s: error on handling disable sequence. (cpu : %d)\n",
|
|
PMUCAL_PREFIX, __func__, cpu);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pmucal_cpu_is_enabled - checks whether a core is enabled or not.
|
|
* exposed to PWRCAL interface.
|
|
*
|
|
* @cpu: cpu core index.
|
|
*
|
|
* Returns 1 when the core is enabled, 0 when the core is disabled.
|
|
* Otherwise, negative error code.
|
|
*/
|
|
int pmucal_cpu_is_enabled(unsigned int cpu)
|
|
{
|
|
int i;
|
|
|
|
if (cpu >= pmucal_cpu_list_size) {
|
|
pr_err("%s core index(%d) is out of supported range (0~%d).\n",
|
|
PMUCAL_PREFIX, cpu, pmucal_cpu_list_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!pmucal_cpu_list[cpu].status) {
|
|
pr_err("%s there is no sequence element for core(%d) status.\n",
|
|
PMUCAL_PREFIX, cpu);
|
|
return -ENOENT;
|
|
}
|
|
|
|
pmucal_rae_handle_seq(pmucal_cpu_list[cpu].status,
|
|
pmucal_cpu_list[cpu].num_status);
|
|
|
|
for (i = 0; i < pmucal_cpu_list[cpu].num_status; i++) {
|
|
if (pmucal_cpu_list[cpu].status[i].value !=
|
|
pmucal_cpu_list[cpu].status[i].mask)
|
|
break;
|
|
}
|
|
|
|
if (i == pmucal_cpu_list[cpu].num_status)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pmucal_cpu_cluster_enable - enables a cluster.
|
|
* exposed to PWRCAL interface.
|
|
*
|
|
* @cluster: cpu cluster index.
|
|
*
|
|
* Returns 0 on success. Otherwise, negative error code.
|
|
*/
|
|
int pmucal_cpu_cluster_enable(unsigned int cluster)
|
|
{
|
|
int ret;
|
|
|
|
if (cluster >= pmucal_cluster_list_size) {
|
|
pr_err("%s cluster index(%d) is out of supported range (0~%d).\n",
|
|
PMUCAL_PREFIX, cluster, pmucal_cluster_list_size);
|
|
return -EINVAL;
|
|
}
|
|
#ifdef CONFIG_FLEXPMU
|
|
pmucal_powermode_hint_clear();
|
|
#endif
|
|
|
|
if (pmucal_cluster_list[cluster].num_on) {
|
|
ret = pmucal_rae_handle_seq(pmucal_cluster_list[cluster].on,
|
|
pmucal_cluster_list[cluster].num_on);
|
|
if (ret) {
|
|
pr_err("%s %s: error on handling enable sequence. (cluster : %d)\n",
|
|
PMUCAL_PREFIX, __func__, cluster);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pmucal_cpu_cluster_disable - disables a cluster.
|
|
* exposed to PWRCAL interface.
|
|
*
|
|
* @cluster: cpu cluster index.
|
|
*
|
|
* Returns 0 on success. Otherwise, negative error code.
|
|
*/
|
|
int pmucal_cpu_cluster_disable(unsigned int cluster)
|
|
{
|
|
int ret;
|
|
|
|
if (cluster >= pmucal_cluster_list_size) {
|
|
pr_err("%s cluster index(%d) is out of supported range (0~%d).\n",
|
|
PMUCAL_PREFIX, cluster, pmucal_cluster_list_size);
|
|
return -EINVAL;
|
|
}
|
|
#ifdef CONFIG_FLEXPMU
|
|
pmucal_powermode_hint(cpu_inform_cpd);
|
|
#endif
|
|
|
|
if (pmucal_cluster_list[cluster].num_off) {
|
|
ret = pmucal_rae_handle_seq(pmucal_cluster_list[cluster].off,
|
|
pmucal_cluster_list[cluster].num_off);
|
|
if (ret) {
|
|
pr_err("%s %s: error on handling disable sequence. (cluster : %d)\n",
|
|
PMUCAL_PREFIX, __func__, cluster);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pmucal_cpu_cluster_is_enabled - checks whether a cluster is enabled or not.
|
|
* exposed to PWRCAL interface.
|
|
*
|
|
* @cluster: cpu cluster index.
|
|
*
|
|
* Returns 1 when the cluster is enabled, 0 when disabled.
|
|
* Otherwise, negative error code.
|
|
*/
|
|
int pmucal_cpu_cluster_is_enabled(unsigned int cluster)
|
|
{
|
|
int i;
|
|
|
|
if (cluster >= pmucal_cluster_list_size) {
|
|
pr_err("%s cluster index(%d) is out of supported range (0~%d).\n",
|
|
PMUCAL_PREFIX, cluster, pmucal_cluster_list_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!pmucal_cluster_list[cluster].status) {
|
|
pr_err("%s there is no sequence element for cluster(%d) status.\n",
|
|
PMUCAL_PREFIX, cluster);
|
|
return -ENOENT;
|
|
}
|
|
|
|
pmucal_rae_handle_seq(pmucal_cluster_list[cluster].status,
|
|
pmucal_cluster_list[cluster].num_status);
|
|
|
|
for (i = 0; i < pmucal_cluster_list[cluster].num_status; i++) {
|
|
if (pmucal_cluster_list[cluster].status[i].value !=
|
|
pmucal_cluster_list[cluster].status[i].mask)
|
|
break;
|
|
}
|
|
|
|
if (i == pmucal_cluster_list[cluster].num_status)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pmucal_cpu_init - Init function of PMUCAL CPU common logic.
|
|
* exposed to PWRCAL interface.
|
|
*
|
|
* Returns 0 on success. Otherwise, negative error code.
|
|
*/
|
|
int __init pmucal_cpu_init(void)
|
|
{
|
|
int ret = 0, i;
|
|
|
|
if (!pmucal_cpu_list_size || !pmucal_cluster_list_size) {
|
|
pr_err("%s %s: there is no cpu/cluster list. aborting init...\n",
|
|
PMUCAL_PREFIX, __func__);
|
|
return -ENOENT;
|
|
}
|
|
|
|
/* convert physical base address to virtual addr */
|
|
for (i = 0; i < pmucal_cpu_list_size; i++) {
|
|
/* skip non-existing cores */
|
|
if (!pmucal_cpu_list[i].num_on && !pmucal_cpu_list[i].num_off && !pmucal_cpu_list[i].num_status)
|
|
continue;
|
|
|
|
ret = pmucal_rae_phy2virt(pmucal_cpu_list[i].on,
|
|
pmucal_cpu_list[i].num_on);
|
|
if (ret) {
|
|
pr_err("%s %s: error on PA2VA conversion. seq:enable, core_id:%d. aborting init...\n",
|
|
PMUCAL_PREFIX, __func__, i);
|
|
goto out;
|
|
}
|
|
|
|
ret = pmucal_rae_phy2virt(pmucal_cpu_list[i].off,
|
|
pmucal_cpu_list[i].num_off);
|
|
if (ret) {
|
|
pr_err("%s %s: error on PA2VA conversion. seq:disable, core_id:%d. aborting init...\n",
|
|
PMUCAL_PREFIX, __func__, i);
|
|
goto out;
|
|
}
|
|
|
|
ret = pmucal_rae_phy2virt(pmucal_cpu_list[i].status,
|
|
pmucal_cpu_list[i].num_status);
|
|
if (ret) {
|
|
pr_err("%s %s: error on PA2VA conversion. seq:status, core_id:%d. aborting init...\n",
|
|
PMUCAL_PREFIX, __func__, i);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < pmucal_cluster_list_size; i++) {
|
|
/* skip non-existing clusters */
|
|
if (!pmucal_cluster_list[i].num_on && !pmucal_cluster_list[i].num_off && !pmucal_cluster_list[i].num_status)
|
|
continue;
|
|
|
|
ret = pmucal_rae_phy2virt(pmucal_cluster_list[i].on,
|
|
pmucal_cluster_list[i].num_on);
|
|
if (ret) {
|
|
pr_err("%s %s: error on PA2VA conversion. seq:enable, cluster_id:%d. aborting init...\n",
|
|
PMUCAL_PREFIX, __func__, i);
|
|
goto out;
|
|
}
|
|
|
|
ret = pmucal_rae_phy2virt(pmucal_cluster_list[i].off,
|
|
pmucal_cluster_list[i].num_off);
|
|
if (ret) {
|
|
pr_err("%s %s: error on PA2VA conversion. seq:disable, cluster_id:%d. aborting init...\n",
|
|
PMUCAL_PREFIX, __func__, i);
|
|
goto out;
|
|
}
|
|
|
|
ret = pmucal_rae_phy2virt(pmucal_cluster_list[i].status,
|
|
pmucal_cluster_list[i].num_status);
|
|
if (ret) {
|
|
pr_err("%s %s: error on PA2VA conversion. seq:status, cluster_id:%d. aborting init...\n",
|
|
PMUCAL_PREFIX, __func__, i);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|