lineage_kernel_xcoverpro/drivers/soc/samsung/cal-if/pmucal_local.c

241 lines
5.9 KiB
C
Executable File

#include "pmucal_local.h"
#include "pmucal_rae.h"
#ifndef PWRCAL_TARGET_LINUX
struct pmucal_pd *pmucal_blkpwr_list[PMUCAL_NUM_PDS];
#endif
/**
* pmucal_local_enable - enables a power domain.
* exposed to PWRCAL interface.
*
* @pd_id: power domain index.
*
* Returns 0 on success. Otherwise, negative error code.
*/
int pmucal_local_enable(unsigned int pd_id)
{
int ret;
dbg_snapshot_pmu(pd_id, __func__, DSS_FLAG_IN);
if (pd_id >= pmucal_pd_list_size) {
pr_err("%s pd index(%d) is out of supported range (0~%d).\n",
PMUCAL_PREFIX, pd_id, pmucal_pd_list_size);
return -EINVAL;
}
if (!pmucal_pd_list[pd_id].on) {
pr_err("%s there is no sequence element for pd(%d) power-on.\n",
PMUCAL_PREFIX, pd_id);
return -ENOENT;
}
ret = pmucal_rae_handle_seq(pmucal_pd_list[pd_id].on,
pmucal_pd_list[pd_id].num_on);
if (ret) {
pr_err("%s %s: error on handling enable sequence. (pd_id : %d)\n",
PMUCAL_PREFIX, __func__, pd_id);
return ret;
}
if (pmucal_pd_list[pd_id].need_smc) {
ret = exynos_pd_tz_restore(pmucal_pd_list[pd_id].need_smc);
if (ret) {
pr_err("%s %s: DTZPC restore smc error. (pd_id : %d)\n",
PMUCAL_PREFIX, __func__, pd_id);
return ret;
}
}
ret = pmucal_rae_restore_seq(pmucal_pd_list[pd_id].save,
pmucal_pd_list[pd_id].num_save);
if (ret) {
pr_err("%s %s: error on handling restore sequence. (pd_id : %d)\n",
PMUCAL_PREFIX, __func__, pd_id);
return ret;
}
dbg_snapshot_pmu(pd_id, __func__, DSS_FLAG_OUT);
return 0;
}
/**
* pmucal_local_disable - disables a power domain.
* exposed to PWRCAL interface.
*
* @pd_id: power domain index.
*
* Returns 0 on success. Otherwise, negative error code.
*/
int pmucal_local_disable(unsigned int pd_id)
{
int ret, i;
dbg_snapshot_pmu(pd_id, __func__, DSS_FLAG_IN);
if (pd_id >= pmucal_pd_list_size) {
pr_err("%s pd index(%d) is out of supported range (0~%d).\n",
PMUCAL_PREFIX, pd_id, pmucal_pd_list_size);
return -EINVAL;
}
if (!pmucal_pd_list[pd_id].off) {
pr_err("%s there is no sequence element for pd(%d) power-off.\n",
PMUCAL_PREFIX, pd_id);
return -ENOENT;
}
pmucal_rae_save_seq(pmucal_pd_list[pd_id].save,
pmucal_pd_list[pd_id].num_save);
if (pmucal_pd_list[pd_id].need_smc) {
ret = exynos_pd_tz_save(pmucal_pd_list[pd_id].need_smc);
if (ret) {
pr_err("%s %s: DTZPC save smc error. (pd_id : %d)\n",
PMUCAL_PREFIX, __func__, pd_id);
return ret;
}
}
ret = pmucal_rae_handle_seq(pmucal_pd_list[pd_id].off,
pmucal_pd_list[pd_id].num_off);
if (ret) {
pr_err("%s %s: error on handling disable sequence. (pd_id : %d)\n",
PMUCAL_PREFIX, __func__, pd_id);
for (i = 0; i < pmucal_pd_list[pd_id].num_save; i++) {
pr_err("%s[0x%x] = 0x%x\n", pmucal_pd_list[pd_id].save[i].sfr_name,
pmucal_pd_list[pd_id].save[i].offset,
pmucal_pd_list[pd_id].save[i].value);
}
return ret;
}
dbg_snapshot_pmu(pd_id, __func__, DSS_FLAG_OUT);
return 0;
}
/**
* pmucal_local_is_enabled - checks whether a power domain is enabled or not.
* exposed to PWRCAL interface.
*
* @pd_id: power domain index.
*
* Returns 1 when the pd is enabled, 0 when disabled.
* Otherwise, negative error code.
*/
int pmucal_local_is_enabled(unsigned int pd_id)
{
int i;
dbg_snapshot_pmu(pd_id, __func__, DSS_FLAG_IN);
if (pd_id >= pmucal_pd_list_size) {
pr_err("%s pd index(%d) is out of supported range (0~%d).\n",
PMUCAL_PREFIX, pd_id, pmucal_pd_list_size);
return -EINVAL;
}
if (!pmucal_pd_list[pd_id].status) {
pr_err("%s there is no sequence element for pd(%d) status.\n",
PMUCAL_PREFIX, pd_id);
return -ENOENT;
}
pmucal_rae_handle_seq(pmucal_pd_list[pd_id].status,
pmucal_pd_list[pd_id].num_status);
for (i = 0; i < pmucal_pd_list[pd_id].num_status; i++) {
if (pmucal_pd_list[pd_id].status[i].value !=
pmucal_pd_list[pd_id].status[i].mask)
break;
}
dbg_snapshot_pmu(pd_id, __func__, DSS_FLAG_OUT);
if (i == pmucal_pd_list[pd_id].num_status)
return 1;
else
return 0;
}
void pmucal_local_set_smc_id(unsigned int pd_id, unsigned int need_smc)
{
if (need_smc) {
if (pd_id >= pmucal_pd_list_size) {
pr_err("%s pd index(%d) is out of supported range (0~%d).\n",
PMUCAL_PREFIX, pd_id, pmucal_pd_list_size);
return;
}
pmucal_pd_list[pd_id].need_smc = need_smc;
}
}
/**
* pmucal_local_init - Init function of PMUCAL LOCAL common logic.
* exposed to PWRCAL interface.
*
* Returns 0 on success. Otherwise, negative error code.
*/
int __init pmucal_local_init(void)
{
int ret = 0, i;
if (!pmucal_pd_list_size) {
pr_err("%s %s: there is no pd list. aborting init...\n",
PMUCAL_PREFIX, __func__);
return -ENOENT;
}
/* convert physical base address to virtual addr */
for (i = 0; i < pmucal_pd_list_size; i++) {
/* skip non-existing pd */
if (!pmucal_pd_list[i].num_on && !pmucal_pd_list[i].num_off && !pmucal_pd_list[i].num_status)
continue;
ret = pmucal_rae_phy2virt(pmucal_pd_list[i].on,
pmucal_pd_list[i].num_on);
if (ret) {
pr_err("%s %s: error on PA2VA conversion. seq:on, pd_id:%d. aborting init...\n",
PMUCAL_PREFIX, __func__, i);
goto out;
}
ret = pmucal_rae_phy2virt(pmucal_pd_list[i].save,
pmucal_pd_list[i].num_save);
if (ret) {
pr_err("%s %s: error on PA2VA conversion. seq:save, pd_id:%d. aborting init...\n",
PMUCAL_PREFIX, __func__, i);
goto out;
}
ret = pmucal_rae_phy2virt(pmucal_pd_list[i].off,
pmucal_pd_list[i].num_off);
if (ret) {
pr_err("%s %s: error on PA2VA conversion. seq:off, pd_id:%d. aborting init...\n",
PMUCAL_PREFIX, __func__, i);
goto out;
}
ret = pmucal_rae_phy2virt(pmucal_pd_list[i].status,
pmucal_pd_list[i].num_status);
if (ret) {
pr_err("%s %s: error on PA2VA conversion. seq:status, pd_id:%d. aborting init...\n",
PMUCAL_PREFIX, __func__, i);
goto out;
}
#ifndef PWRCAL_TARGET_LINUX
pmucal_blkpwr_list[i] = pmucal_pd_list + i;
#endif
}
out:
return ret;
}