From 98ece19f247159a51003796ede7112fef2df5d7f Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 14 May 2020 10:37:18 +0300 Subject: soc: ti: omap-prm: use atomic iopoll instead of sleeping one The reset handling APIs for omap-prm can be invoked PM runtime which runs in atomic context. For this to work properly, switch to atomic iopoll version instead of the current which can sleep. Otherwise, this throws a "BUG: scheduling while atomic" warning. Issue is seen rather easily when CONFIG_PREEMPT is enabled. Signed-off-by: Tero Kristo Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- drivers/soc/ti/omap_prm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c index 96c6f777519c..c9b3f9ebf0bb 100644 --- a/drivers/soc/ti/omap_prm.c +++ b/drivers/soc/ti/omap_prm.c @@ -256,10 +256,10 @@ static int omap_reset_deassert(struct reset_controller_dev *rcdev, goto exit; /* wait for the status to be set */ - ret = readl_relaxed_poll_timeout(reset->prm->base + - reset->prm->data->rstst, - v, v & BIT(st_bit), 1, - OMAP_RESET_MAX_WAIT); + ret = readl_relaxed_poll_timeout_atomic(reset->prm->base + + reset->prm->data->rstst, + v, v & BIT(st_bit), 1, + OMAP_RESET_MAX_WAIT); if (ret) pr_err("%s: timedout waiting for %s:%lu\n", __func__, reset->prm->data->name, id); -- cgit v1.2.3 From 5ce8aee81be6c8bc19051d7c7b0d3cbb7ac5fc3f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 May 2020 06:49:29 -0700 Subject: bus: ti-sysc: Flush posted write on enable and disable Looks like we're missing flush of posted write after module enable and disable. I've seen occasional errors accessing various modules, and it is suspected that the lack of posted writes can also cause random reboots. The errors we can see are similar to the one below from spi for example: 44000000.ocp:L3 Custom Error: MASTER MPU TARGET L4CFG (Read): Data Access in User mode during Functional access ... mcspi_wait_for_reg_bit omap2_mcspi_transfer_one spi_transfer_one_message ... We also want to also flush posted write for disable. The clkctrl clock disable happens after module disable, and we don't want to have the module potentially stay active while we're trying to disable the clock. Fixes: d59b60564cbf ("bus: ti-sysc: Add generic enable/disable functions") Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index e5f5f48d69d2..369c97c3e0c0 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -991,6 +991,9 @@ set_autoidle: sysc_write_sysconfig(ddata, reg); } + /* Flush posted write */ + sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); + if (ddata->module_enable_quirk) ddata->module_enable_quirk(ddata); @@ -1071,6 +1074,9 @@ set_sidle: reg |= 1 << regbits->autoidle_shift; sysc_write_sysconfig(ddata, reg); + /* Flush posted write */ + sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); + return 0; } -- cgit v1.2.3 From d46f9fbec71997420e4fb83c04d9affdf423f879 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sun, 31 May 2020 12:37:54 -0700 Subject: 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: 7324a7a0d5e2 ("bus: ti-sysc: Implement display subsystem reset quirk") Reported-by: Faiz Abbas Cc: Laurent Pinchart Cc: Tomi Valkeinen Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 80 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 369c97c3e0c0..a3a2c269e9ad 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -221,6 +221,35 @@ static u32 sysc_read_sysstatus(struct sysc *ddata) 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, const char *name, const char *optfck_name) @@ -925,8 +954,34 @@ static int sysc_enable_module(struct device *dev) struct sysc *ddata; const struct sysc_regbits *regbits; u32 reg, idlemodes, best_mode; + int error; 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) return 0; @@ -1828,11 +1883,10 @@ static int sysc_legacy_init(struct sysc *ddata) */ static int sysc_reset(struct sysc *ddata) { - int sysc_offset, syss_offset, sysc_val, rstval, error = 0; - u32 sysc_mask, syss_done; + int sysc_offset, sysc_val, error; + u32 sysc_mask; sysc_offset = ddata->offsets[SYSC_SYSCONFIG]; - syss_offset = ddata->offsets[SYSC_SYSSTATUS]; if (ddata->legacy_mode || ddata->cap->regbits->srst_shift < 0 || @@ -1841,11 +1895,6 @@ static int sysc_reset(struct sysc *ddata) 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) ddata->pre_reset_quirk(ddata); @@ -1862,18 +1911,9 @@ static int sysc_reset(struct sysc *ddata) if (ddata->post_reset_quirk) ddata->post_reset_quirk(ddata); - /* Poll on reset status */ - 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); - } + error = sysc_wait_softreset(ddata); + if (error) + dev_warn(ddata->dev, "OCP softreset timed out\n"); if (ddata->reset_done_quirk) ddata->reset_done_quirk(ddata); -- cgit v1.2.3 From 08b91dd6e547467fad61a7c201ff71080d7ad65a Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sun, 31 May 2020 12:37:54 -0700 Subject: bus: ti-sysc: Ignore clockactivity unless specified as a quirk We must ignore the clockactivity bit for most modules and not set it unless specified for the module with SYSC_QUIRK_USE_CLOCKACT. Otherwise the interface clock can be automatically gated constantly causing unexpected performance issues. Fixes: ae9ae12e9daa ("bus: ti-sysc: Handle clockactivity for enable and disable") Cc: Laurent Pinchart Cc: Tomi Valkeinen Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index a3a2c269e9ad..4f640a635ded 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -988,10 +988,13 @@ static int sysc_enable_module(struct device *dev) regbits = ddata->cap->regbits; reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); - /* Set CLOCKACTIVITY, we only use it for ick */ + /* + * Set CLOCKACTIVITY, we only use it for ick. And we only configure it + * based on the SYSC_QUIRK_USE_CLOCKACT flag, not based on the hardware + * capabilities. See the old HWMOD_SET_DEFAULT_CLOCKACT flag. + */ if (regbits->clkact_shift >= 0 && - (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT || - ddata->cfg.sysc_val & BIT(regbits->clkact_shift))) + (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT)) reg |= SYSC_CLOCACT_ICK << regbits->clkact_shift; /* Set SIDLE mode */ -- cgit v1.2.3 From 085bc0e576a4bf53b67a917c54908f299a2fb949 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sun, 31 May 2020 12:37:54 -0700 Subject: bus: ti-sysc: Fix uninitialized framedonetv_irq We are currently only setting the framedonetv_irq disabled for the SoCs that don't have it. But we are never setting it enabled for the SoCs that have it. Let's initialized it to true by default. Fixes: 7324a7a0d5e2 ("bus: ti-sysc: Implement display subsystem reset quirk") Cc: Laurent Pinchart Cc: Tomi Valkeinen Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 4f640a635ded..db9541f38505 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -1552,7 +1552,7 @@ static u32 sysc_quirk_dispc(struct sysc *ddata, int dispc_offset, bool lcd_en, digit_en, lcd2_en = false, lcd3_en = false; const int lcd_en_mask = BIT(0), digit_en_mask = BIT(1); int manager_count; - bool framedonetv_irq; + bool framedonetv_irq = true; u32 val, irq_mask = 0; switch (sysc_soc->soc) { @@ -1569,6 +1569,7 @@ static u32 sysc_quirk_dispc(struct sysc *ddata, int dispc_offset, break; case SOC_AM4: manager_count = 1; + framedonetv_irq = false; break; case SOC_UNKNOWN: default: -- cgit v1.2.3 From 636338d7968e47c7f2e0b772a2a825ad932883fb Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 3 Jun 2020 15:02:20 -0700 Subject: bus: ti-sysc: Increase max softreset wait Otherwise we can get "OCP softreset timed out" warnings occasionally at least for i2c2 on omap4 now that we check the OCP softreset completed bit on enable. Reported-by: Merlijn Wajer Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index db9541f38505..6886bdd225b6 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -29,7 +29,7 @@ #define SOC_FLAG(match, flag) { .machine = match, .data = (void *)(flag), } -#define MAX_MODULE_SOFTRESET_WAIT 10000 +#define MAX_MODULE_SOFTRESET_WAIT 20000 enum sysc_soc { SOC_UNKNOWN, -- cgit v1.2.3 From e4a8fc054340f4df761f6a73335f8fdc0b7ac4fd Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 10 Jun 2020 15:31:54 -0700 Subject: Revert "bus: ti-sysc: Increase max softreset wait" This reverts commit 636338d7968e47c7f2e0b772a2a825ad932883fb. This patch is not a proper fixes the i2c2 timeouts are still happening in some cases. Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 6886bdd225b6..db9541f38505 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -29,7 +29,7 @@ #define SOC_FLAG(match, flag) { .machine = match, .data = (void *)(flag), } -#define MAX_MODULE_SOFTRESET_WAIT 20000 +#define MAX_MODULE_SOFTRESET_WAIT 10000 enum sysc_soc { SOC_UNKNOWN, -- cgit v1.2.3