platform: nvadsp: use smem for adsp freq update

Instead of using mailbox to communicate change in adsp cpu
freq, update it in adsp os args from ccplex-adsp shared
memory. This adsp freq update is needed by EDF scheduler
for scheduling EDF threads. The EDF scheduler gets
current adsp freq from shared memory instead of
scheduler callback.

However, for APE1 (i.e. chips = T21x), timer prescalar
must still be updated through mailbox each time adsp cpu
freq is changed.

Bug 200322504

Change-Id: I26f14f5c4f5c2369d67dfcd73dc6b9664df2ca26
Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
Reviewed-on: https://git-master/r/1512069
(cherry picked from commit 76e8a4c19de2fa5f0d91ebefac68aa0b864cb0eb)
Reviewed-on: https://git-master/r/1512864
(cherry picked from commit 3100911879f9ea9930a515f6d55257caefcef869)
Reviewed-on: https://git-master.nvidia.com/r/1517749
Reviewed-on: https://git-master.nvidia.com/r/1537334
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Nitin Kumbhar
2017-07-02 14:30:44 +05:30
committed by Laxman Dewangan
parent 5711c0800c
commit a3d5511dea
2 changed files with 87 additions and 53 deletions

View File

@@ -254,61 +254,11 @@ static struct adsp_dfs_policy dfs_policy = {
},
};
/*
* update_freq - update adsp freq and ask adsp to change timer as
* change in adsp freq.
* freq_khz - target frequency in KHz
* return - final freq got set.
* - 0, incase of error.
*
* Note - Policy->cur would be updated via rate
* change notifier, when freq is changed in hw
*
*/
static unsigned long update_freq(unsigned long freq_khz)
static int adsp_update_freq_handshake(unsigned long tfreq_hz, int index)
{
u32 efreq;
int index;
int ret;
unsigned long tfreq_hz, old_freq_khz;
enum adsp_dfs_reply reply;
struct nvadsp_mbox *mbx = &policy->mbox;
struct nvadsp_drv_data *drv = dev_get_drvdata(device);
tfreq_hz = adsp_get_target_freq(freq_khz * 1000, &index);
if (!tfreq_hz) {
dev_info(device, "unable get the target freq\n");
return 0;
}
old_freq_khz = policy->cur;
if ((tfreq_hz / 1000) == old_freq_khz) {
dev_dbg(device, "old and new target_freq is same\n");
return 0;
}
ret = adsp_clk_set_rate(policy, tfreq_hz);
if (ret) {
dev_err(device, "failed to set adsp freq:%luhz err:%d\n",
tfreq_hz, ret);
policy->update_freq_flag = false;
return 0;
}
efreq = adsp_to_emc_freq(tfreq_hz / 1000);
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
tegra_bwmgr_set_emc(drv->bwmgr, efreq * 1000,
TEGRA_BWMGR_SET_EMC_FLOOR);
} else {
ret = clk_set_rate(ape_emc_clk, efreq * 1000);
if (ret) {
dev_err(device, "failed to set ape.emc clk:%d\n", ret);
policy->update_freq_flag = false;
goto err_out;
}
}
enum adsp_dfs_reply reply;
int ret;
dev_dbg(device, "sending change in freq(hz):%lu\n", tfreq_hz);
/*
@@ -351,6 +301,84 @@ static unsigned long update_freq(unsigned long freq_khz)
__func__,
policy->update_freq_flag == true ? "ACK" : "NACK",
tfreq_hz);
err_out:
return ret;
}
/*
* update_freq - update adsp freq and ask adsp to change timer as
* change in adsp freq.
* freq_khz - target frequency in KHz
* return - final freq got set.
* - 0, incase of error.
*
* Note - Policy->cur would be updated via rate
* change notifier, when freq is changed in hw
*
*/
static unsigned long update_freq(unsigned long freq_khz)
{
struct nvadsp_drv_data *drv = dev_get_drvdata(device);
unsigned long tfreq_hz, old_freq_khz;
u32 efreq;
int index;
int ret;
tfreq_hz = adsp_get_target_freq(freq_khz * 1000, &index);
if (!tfreq_hz) {
dev_info(device, "unable get the target freq\n");
return 0;
}
old_freq_khz = policy->cur;
if ((tfreq_hz / 1000) == old_freq_khz) {
dev_dbg(device, "old and new target_freq is same\n");
return 0;
}
ret = adsp_clk_set_rate(policy, tfreq_hz);
if (ret) {
dev_err(device, "failed to set adsp freq:%luhz err:%d\n",
tfreq_hz, ret);
policy->update_freq_flag = false;
return 0;
}
efreq = adsp_to_emc_freq(tfreq_hz / 1000);
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
tegra_bwmgr_set_emc(drv->bwmgr, efreq * 1000,
TEGRA_BWMGR_SET_EMC_FLOOR);
} else {
ret = clk_set_rate(ape_emc_clk, efreq * 1000);
if (ret) {
dev_err(device, "failed to set ape.emc clk:%d\n", ret);
policy->update_freq_flag = false;
goto err_out;
}
}
/*
* On tegra > t210, as os_args->adsp_freq_hz is used to know adsp cpu
* clk rate and there is no need to set up timer prescalar. So skip
* communicating adsp cpu clk rate update to adspos using mbox
*/
if (!of_device_is_compatible(device->of_node, "nvidia,tegra210-adsp"))
policy->update_freq_flag = true;
else
adsp_update_freq_handshake(tfreq_hz, index);
/*
* Use os_args->adsp_freq_hz to update adsp cpu clk rate
* for adspos firmware, which uses this shared variable
* to get the clk rate for EDF, etc.
*/
if (policy->update_freq_flag) {
struct nvadsp_shared_mem *sm = drv->shared_adsp_os_data;
sm->os_args.adsp_freq_hz = tfreq_hz;
}
err_out:
if (!policy->update_freq_flag) {

View File

@@ -859,6 +859,10 @@ static int nvadsp_t210_set_clks_and_prescalar(struct nvadsp_drv_data *drv_data)
goto end;
drv_data->adsp_freq = adsp_freq / 1000; /* adsp_freq in KHz*/
drv_data->adsp_freq_hz = adsp_freq;
/* adspos uses os_args->adsp_freq_hz for EDF */
os_args->adsp_freq_hz = adsp_freq;
end:
dev_dbg(dev, "adsp cpu freq %luKHz\n",
@@ -897,6 +901,8 @@ static int nvadsp_set_adsp_clks(struct nvadsp_drv_data *drv_data)
drv_data->adsp_freq = adsp_freq / 1000; /* adsp_freq in KHz*/
drv_data->adsp_freq_hz = adsp_freq;
/* adspos uses os_args->adsp_freq_hz for EDF */
os_args->adsp_freq_hz = adsp_freq;
end:
dev_dbg(dev, "adsp cpu freq %luKHz\n",