Skip to content

Commit d46f9fb

Browse files
committed
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: 7324a7a ("bus: ti-sysc: Implement display subsystem reset quirk") Reported-by: Faiz Abbas <[email protected]> Cc: Laurent Pinchart <[email protected]> Cc: Tomi Valkeinen <[email protected]> Signed-off-by: Tony Lindgren <[email protected]>
1 parent 0df12a0 commit d46f9fb

File tree

1 file changed

+60
-20
lines changed

1 file changed

+60
-20
lines changed

drivers/bus/ti-sysc.c

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,35 @@ static u32 sysc_read_sysstatus(struct sysc *ddata)
221221
return sysc_read(ddata, offset);
222222
}
223223

224+
/* Poll on reset status */
225+
static int sysc_wait_softreset(struct sysc *ddata)
226+
{
227+
u32 sysc_mask, syss_done, rstval;
228+
int syss_offset, error = 0;
229+
230+
syss_offset = ddata->offsets[SYSC_SYSSTATUS];
231+
sysc_mask = BIT(ddata->cap->regbits->srst_shift);
232+
233+
if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
234+
syss_done = 0;
235+
else
236+
syss_done = ddata->cfg.syss_mask;
237+
238+
if (syss_offset >= 0) {
239+
error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval,
240+
(rstval & ddata->cfg.syss_mask) ==
241+
syss_done,
242+
100, MAX_MODULE_SOFTRESET_WAIT);
243+
244+
} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
245+
error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval,
246+
!(rstval & sysc_mask),
247+
100, MAX_MODULE_SOFTRESET_WAIT);
248+
}
249+
250+
return error;
251+
}
252+
224253
static int sysc_add_named_clock_from_child(struct sysc *ddata,
225254
const char *name,
226255
const char *optfck_name)
@@ -925,8 +954,34 @@ static int sysc_enable_module(struct device *dev)
925954
struct sysc *ddata;
926955
const struct sysc_regbits *regbits;
927956
u32 reg, idlemodes, best_mode;
957+
int error;
928958

929959
ddata = dev_get_drvdata(dev);
960+
961+
/*
962+
* Some modules like DSS reset automatically on idle. Enable optional
963+
* reset clocks and wait for OCP softreset to complete.
964+
*/
965+
if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET) {
966+
error = sysc_enable_opt_clocks(ddata);
967+
if (error) {
968+
dev_err(ddata->dev,
969+
"Optional clocks failed for enable: %i\n",
970+
error);
971+
return error;
972+
}
973+
}
974+
error = sysc_wait_softreset(ddata);
975+
if (error)
976+
dev_warn(ddata->dev, "OCP softreset timed out\n");
977+
if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET)
978+
sysc_disable_opt_clocks(ddata);
979+
980+
/*
981+
* Some subsystem private interconnects, like DSS top level module,
982+
* need only the automatic OCP softreset handling with no sysconfig
983+
* register bits to configure.
984+
*/
930985
if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
931986
return 0;
932987

@@ -1828,11 +1883,10 @@ static int sysc_legacy_init(struct sysc *ddata)
18281883
*/
18291884
static int sysc_reset(struct sysc *ddata)
18301885
{
1831-
int sysc_offset, syss_offset, sysc_val, rstval, error = 0;
1832-
u32 sysc_mask, syss_done;
1886+
int sysc_offset, sysc_val, error;
1887+
u32 sysc_mask;
18331888

18341889
sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
1835-
syss_offset = ddata->offsets[SYSC_SYSSTATUS];
18361890

18371891
if (ddata->legacy_mode ||
18381892
ddata->cap->regbits->srst_shift < 0 ||
@@ -1841,11 +1895,6 @@ static int sysc_reset(struct sysc *ddata)
18411895

18421896
sysc_mask = BIT(ddata->cap->regbits->srst_shift);
18431897

1844-
if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
1845-
syss_done = 0;
1846-
else
1847-
syss_done = ddata->cfg.syss_mask;
1848-
18491898
if (ddata->pre_reset_quirk)
18501899
ddata->pre_reset_quirk(ddata);
18511900

@@ -1862,18 +1911,9 @@ static int sysc_reset(struct sysc *ddata)
18621911
if (ddata->post_reset_quirk)
18631912
ddata->post_reset_quirk(ddata);
18641913

1865-
/* Poll on reset status */
1866-
if (syss_offset >= 0) {
1867-
error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval,
1868-
(rstval & ddata->cfg.syss_mask) ==
1869-
syss_done,
1870-
100, MAX_MODULE_SOFTRESET_WAIT);
1871-
1872-
} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
1873-
error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval,
1874-
!(rstval & sysc_mask),
1875-
100, MAX_MODULE_SOFTRESET_WAIT);
1876-
}
1914+
error = sysc_wait_softreset(ddata);
1915+
if (error)
1916+
dev_warn(ddata->dev, "OCP softreset timed out\n");
18771917

18781918
if (ddata->reset_done_quirk)
18791919
ddata->reset_done_quirk(ddata);

0 commit comments

Comments
 (0)