Commit d46f9fbe authored by Tony Lindgren's avatar Tony Lindgren

bus: ti-sysc: Use optional clocks on for enable and wait for softreset bit

Some modules reset automatically when idled, and when re-enabled, we must
wait for the automatic OCP softreset to complete. And if optional clocks
are configured, we need to keep the clocks on while waiting for the reset
to complete.

Let's fix the issue by moving the OCP softreset code to a separate
function sysc_wait_softreset(), and call it also from sysc_enable_module()
with the optional clocks enabled.

This is based on what we're already doing for legacy platform data booting
in _enable_sysc().

Fixes: 7324a7a0 ("bus: ti-sysc: Implement display subsystem reset quirk")
Reported-by: default avatarFaiz Abbas <faiz_abbas@ti.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 0df12a01
...@@ -221,6 +221,35 @@ static u32 sysc_read_sysstatus(struct sysc *ddata) ...@@ -221,6 +221,35 @@ static u32 sysc_read_sysstatus(struct sysc *ddata)
return sysc_read(ddata, offset); return sysc_read(ddata, offset);
} }
/* Poll on reset status */
static int sysc_wait_softreset(struct sysc *ddata)
{
u32 sysc_mask, syss_done, rstval;
int syss_offset, error = 0;
syss_offset = ddata->offsets[SYSC_SYSSTATUS];
sysc_mask = BIT(ddata->cap->regbits->srst_shift);
if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
syss_done = 0;
else
syss_done = ddata->cfg.syss_mask;
if (syss_offset >= 0) {
error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval,
(rstval & ddata->cfg.syss_mask) ==
syss_done,
100, MAX_MODULE_SOFTRESET_WAIT);
} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval,
!(rstval & sysc_mask),
100, MAX_MODULE_SOFTRESET_WAIT);
}
return error;
}
static int sysc_add_named_clock_from_child(struct sysc *ddata, static int sysc_add_named_clock_from_child(struct sysc *ddata,
const char *name, const char *name,
const char *optfck_name) const char *optfck_name)
...@@ -925,8 +954,34 @@ static int sysc_enable_module(struct device *dev) ...@@ -925,8 +954,34 @@ static int sysc_enable_module(struct device *dev)
struct sysc *ddata; struct sysc *ddata;
const struct sysc_regbits *regbits; const struct sysc_regbits *regbits;
u32 reg, idlemodes, best_mode; u32 reg, idlemodes, best_mode;
int error;
ddata = dev_get_drvdata(dev); ddata = dev_get_drvdata(dev);
/*
* Some modules like DSS reset automatically on idle. Enable optional
* reset clocks and wait for OCP softreset to complete.
*/
if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET) {
error = sysc_enable_opt_clocks(ddata);
if (error) {
dev_err(ddata->dev,
"Optional clocks failed for enable: %i\n",
error);
return error;
}
}
error = sysc_wait_softreset(ddata);
if (error)
dev_warn(ddata->dev, "OCP softreset timed out\n");
if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET)
sysc_disable_opt_clocks(ddata);
/*
* Some subsystem private interconnects, like DSS top level module,
* need only the automatic OCP softreset handling with no sysconfig
* register bits to configure.
*/
if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV) if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
return 0; return 0;
...@@ -1828,11 +1883,10 @@ static int sysc_legacy_init(struct sysc *ddata) ...@@ -1828,11 +1883,10 @@ static int sysc_legacy_init(struct sysc *ddata)
*/ */
static int sysc_reset(struct sysc *ddata) static int sysc_reset(struct sysc *ddata)
{ {
int sysc_offset, syss_offset, sysc_val, rstval, error = 0; int sysc_offset, sysc_val, error;
u32 sysc_mask, syss_done; u32 sysc_mask;
sysc_offset = ddata->offsets[SYSC_SYSCONFIG]; sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
syss_offset = ddata->offsets[SYSC_SYSSTATUS];
if (ddata->legacy_mode || if (ddata->legacy_mode ||
ddata->cap->regbits->srst_shift < 0 || ddata->cap->regbits->srst_shift < 0 ||
...@@ -1841,11 +1895,6 @@ static int sysc_reset(struct sysc *ddata) ...@@ -1841,11 +1895,6 @@ static int sysc_reset(struct sysc *ddata)
sysc_mask = BIT(ddata->cap->regbits->srst_shift); sysc_mask = BIT(ddata->cap->regbits->srst_shift);
if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
syss_done = 0;
else
syss_done = ddata->cfg.syss_mask;
if (ddata->pre_reset_quirk) if (ddata->pre_reset_quirk)
ddata->pre_reset_quirk(ddata); ddata->pre_reset_quirk(ddata);
...@@ -1862,18 +1911,9 @@ static int sysc_reset(struct sysc *ddata) ...@@ -1862,18 +1911,9 @@ static int sysc_reset(struct sysc *ddata)
if (ddata->post_reset_quirk) if (ddata->post_reset_quirk)
ddata->post_reset_quirk(ddata); ddata->post_reset_quirk(ddata);
/* Poll on reset status */ error = sysc_wait_softreset(ddata);
if (syss_offset >= 0) { if (error)
error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval, dev_warn(ddata->dev, "OCP softreset timed out\n");
(rstval & ddata->cfg.syss_mask) ==
syss_done,
100, MAX_MODULE_SOFTRESET_WAIT);
} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval,
!(rstval & sysc_mask),
100, MAX_MODULE_SOFTRESET_WAIT);
}
if (ddata->reset_done_quirk) if (ddata->reset_done_quirk)
ddata->reset_done_quirk(ddata); ddata->reset_done_quirk(ddata);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment