mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 22:50:41 +00:00
bus: ti-sysc: Check for lost context in sysc_reinit_module()
There is no need to restore context if it was not lost. Let's add a new function sysc_check_context() to check for lost context. To make use of it, we need to save the sysconfig register status on enable and disable. Signed-off-by: Tony Lindgren <tony@atomide.com>
This commit is contained in:
parent
b3e9431854
commit
95ec14faac
@ -132,6 +132,7 @@ struct sysc {
|
|||||||
struct ti_sysc_cookie cookie;
|
struct ti_sysc_cookie cookie;
|
||||||
const char *name;
|
const char *name;
|
||||||
u32 revision;
|
u32 revision;
|
||||||
|
u32 sysconfig;
|
||||||
unsigned int reserved:1;
|
unsigned int reserved:1;
|
||||||
unsigned int enabled:1;
|
unsigned int enabled:1;
|
||||||
unsigned int needs_resume:1;
|
unsigned int needs_resume:1;
|
||||||
@ -1135,7 +1136,8 @@ set_midle:
|
|||||||
best_mode = fls(ddata->cfg.midlemodes) - 1;
|
best_mode = fls(ddata->cfg.midlemodes) - 1;
|
||||||
if (best_mode > SYSC_IDLE_MASK) {
|
if (best_mode > SYSC_IDLE_MASK) {
|
||||||
dev_err(dev, "%s: invalid midlemode\n", __func__);
|
dev_err(dev, "%s: invalid midlemode\n", __func__);
|
||||||
return -EINVAL;
|
error = -EINVAL;
|
||||||
|
goto save_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
|
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
|
||||||
@ -1153,13 +1155,16 @@ set_autoidle:
|
|||||||
sysc_write_sysconfig(ddata, reg);
|
sysc_write_sysconfig(ddata, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flush posted write */
|
error = 0;
|
||||||
sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
|
||||||
|
save_context:
|
||||||
|
/* Save context and flush posted write */
|
||||||
|
ddata->sysconfig = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||||
|
|
||||||
if (ddata->module_enable_quirk)
|
if (ddata->module_enable_quirk)
|
||||||
ddata->module_enable_quirk(ddata);
|
ddata->module_enable_quirk(ddata);
|
||||||
|
|
||||||
return 0;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
|
static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
|
||||||
@ -1216,8 +1221,10 @@ static int sysc_disable_module(struct device *dev)
|
|||||||
set_sidle:
|
set_sidle:
|
||||||
/* Set SIDLE mode */
|
/* Set SIDLE mode */
|
||||||
idlemodes = ddata->cfg.sidlemodes;
|
idlemodes = ddata->cfg.sidlemodes;
|
||||||
if (!idlemodes || regbits->sidle_shift < 0)
|
if (!idlemodes || regbits->sidle_shift < 0) {
|
||||||
return 0;
|
ret = 0;
|
||||||
|
goto save_context;
|
||||||
|
}
|
||||||
|
|
||||||
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) {
|
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) {
|
||||||
best_mode = SYSC_IDLE_FORCE;
|
best_mode = SYSC_IDLE_FORCE;
|
||||||
@ -1225,7 +1232,8 @@ set_sidle:
|
|||||||
ret = sysc_best_idle_mode(idlemodes, &best_mode);
|
ret = sysc_best_idle_mode(idlemodes, &best_mode);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: invalid sidlemode\n", __func__);
|
dev_err(dev, "%s: invalid sidlemode\n", __func__);
|
||||||
return ret;
|
ret = -EINVAL;
|
||||||
|
goto save_context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1236,10 +1244,13 @@ set_sidle:
|
|||||||
reg |= 1 << regbits->autoidle_shift;
|
reg |= 1 << regbits->autoidle_shift;
|
||||||
sysc_write_sysconfig(ddata, reg);
|
sysc_write_sysconfig(ddata, reg);
|
||||||
|
|
||||||
/* Flush posted write */
|
ret = 0;
|
||||||
sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
|
||||||
|
|
||||||
return 0;
|
save_context:
|
||||||
|
/* Save context and flush posted write */
|
||||||
|
ddata->sysconfig = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev,
|
static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev,
|
||||||
@ -1377,13 +1388,40 @@ err_allow_idle:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks if device context was lost. Assumes the sysconfig register value
|
||||||
|
* after lost context is different from the configured value. Only works for
|
||||||
|
* enabled devices.
|
||||||
|
*
|
||||||
|
* Eventually we may want to also add support to using the context lost
|
||||||
|
* registers that some SoCs have.
|
||||||
|
*/
|
||||||
|
static int sysc_check_context(struct sysc *ddata)
|
||||||
|
{
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
if (!ddata->enabled)
|
||||||
|
return -ENODATA;
|
||||||
|
|
||||||
|
reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||||
|
if (reg == ddata->sysconfig)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled)
|
static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled)
|
||||||
{
|
{
|
||||||
struct device *dev = ddata->dev;
|
struct device *dev = ddata->dev;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* Disable target module if it is enabled */
|
|
||||||
if (ddata->enabled) {
|
if (ddata->enabled) {
|
||||||
|
/* Nothing to do if enabled and context not lost */
|
||||||
|
error = sysc_check_context(ddata);
|
||||||
|
if (!error)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Disable target module if it is enabled */
|
||||||
error = sysc_runtime_suspend(dev);
|
error = sysc_runtime_suspend(dev);
|
||||||
if (error)
|
if (error)
|
||||||
dev_warn(dev, "reinit suspend failed: %i\n", error);
|
dev_warn(dev, "reinit suspend failed: %i\n", error);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user