summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/bus/ti-sysc.c72
-rw-r--r--include/linux/platform_data/ti-sysc.h1
2 files changed, 55 insertions, 18 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index f00997eea207..f4a048430cd1 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -153,6 +153,26 @@ static u32 sysc_read_revision(struct sysc *ddata)
return sysc_read(ddata, offset);
}
+static u32 sysc_read_sysconfig(struct sysc *ddata)
+{
+ int offset = ddata->offsets[SYSC_SYSCONFIG];
+
+ if (offset < 0)
+ return 0;
+
+ return sysc_read(ddata, offset);
+}
+
+static u32 sysc_read_sysstatus(struct sysc *ddata)
+{
+ int offset = ddata->offsets[SYSC_SYSSTATUS];
+
+ if (offset < 0)
+ return 0;
+
+ return sysc_read(ddata, offset);
+}
+
static int sysc_add_named_clock_from_child(struct sysc *ddata,
const char *name,
const char *optfck_name)
@@ -1369,34 +1389,49 @@ static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
return reset_control_deassert(ddata->rsts);
}
+/*
+ * Note that the caller must ensure the interconnect target module is enabled
+ * before calling reset. Otherwise reset will not complete.
+ */
static int sysc_reset(struct sysc *ddata)
{
- int offset = ddata->offsets[SYSC_SYSCONFIG];
- int val;
+ int sysc_offset, syss_offset, sysc_val, rstval, quirks, error = 0;
+ u32 sysc_mask, syss_done;
+
+ sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
+ syss_offset = ddata->offsets[SYSC_SYSSTATUS];
+ quirks = ddata->cfg.quirks;
- if (ddata->legacy_mode || offset < 0 ||
+ if (ddata->legacy_mode || sysc_offset < 0 ||
+ ddata->cap->regbits->srst_shift < 0 ||
ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
return 0;
- /*
- * Currently only support reset status in sysstatus.
- * Warn and return error in all other cases
- */
- if (!ddata->cfg.syss_mask) {
- dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n");
- return -EINVAL;
- }
+ sysc_mask = BIT(ddata->cap->regbits->srst_shift);
- val = sysc_read(ddata, offset);
- val |= (0x1 << ddata->cap->regbits->srst_shift);
- sysc_write(ddata, offset, val);
+ if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
+ syss_done = 0;
+ else
+ syss_done = ddata->cfg.syss_mask;
+
+ sysc_val = sysc_read_sysconfig(ddata);
+ sysc_val |= sysc_mask;
+ sysc_write(ddata, sysc_offset, sysc_val);
/* Poll on reset status */
- offset = ddata->offsets[SYSC_SYSSTATUS];
+ 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 readl_poll_timeout(ddata->module_va + offset, val,
- (val & ddata->cfg.syss_mask) == 0x0,
- 100, MAX_MODULE_SOFTRESET_WAIT);
+ return error;
}
/*
@@ -2099,6 +2134,7 @@ static const struct sysc_capabilities sysc_dra7_mcan = {
.type = TI_SYSC_DRA7_MCAN,
.sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET,
.regbits = &sysc_regbits_dra7_mcan,
+ .mod_quirks = SYSS_QUIRK_RESETDONE_INVERTED,
};
static int sysc_init_pdata(struct sysc *ddata)
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
index 6626fd31e309..8822e99ff813 100644
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -47,6 +47,7 @@ struct sysc_regbits {
s8 emufree_shift;
};
+#define SYSS_QUIRK_RESETDONE_INVERTED BIT(14)
#define SYSC_QUIRK_SWSUP_MSTANDBY BIT(13)
#define SYSC_QUIRK_SWSUP_SIDLE_ACT BIT(12)
#define SYSC_QUIRK_SWSUP_SIDLE BIT(11)