Merge tag 'omap-for-v5.8/fixes-merge-window-signed' of git://git.kernel.org/pub/scm...
[platform/kernel/linux-rpi.git] / drivers / bus / ti-sysc.c
index 3affd18..bb54fb5 100644 (file)
@@ -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,18 +954,47 @@ 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;
 
        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 */
@@ -991,6 +1049,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 +1132,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;
 }
 
@@ -1488,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) {
@@ -1505,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:
@@ -1822,11 +1887,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 ||
@@ -1835,11 +1899,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);
 
@@ -1856,18 +1915,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);