bus: ti-sysc: Add parsing of module capabilities
authorTony Lindgren <tony@atomide.com>
Fri, 15 Dec 2017 17:41:23 +0000 (09:41 -0800)
committerTony Lindgren <tony@atomide.com>
Thu, 21 Dec 2017 15:28:54 +0000 (07:28 -0800)
We need to configure the interconnect target module based on the
device three configuration.

Let's also add a new quirk for SYSC_QUIRK_RESET_STATUS to indicate
that the SYSCONFIG reset bit changes after the reset is done.

Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/bus/ti-sysc.c
include/linux/platform_data/ti-sysc.h

index 0906124..2c62985 100644 (file)
@@ -39,6 +39,9 @@ enum sysc_clocks {
 
 static const char * const clock_names[] = { "fck", "ick", };
 
+#define SYSC_IDLEMODE_MASK             3
+#define SYSC_CLOCKACTIVITY_MASK                3
+
 /**
  * struct sysc - TI sysc interconnect target module registers and capabilities
  * @dev: struct device pointer
@@ -517,6 +520,91 @@ static int sysc_init_module(struct sysc *ddata)
        return 0;
 }
 
+static int sysc_init_sysc_mask(struct sysc *ddata)
+{
+       struct device_node *np = ddata->dev->of_node;
+       int error;
+       u32 val;
+
+       error = of_property_read_u32(np, "ti,sysc-mask", &val);
+       if (error)
+               return 0;
+
+       if (val)
+               ddata->cfg.sysc_val = val & ddata->cap->sysc_mask;
+       else
+               ddata->cfg.sysc_val = ddata->cap->sysc_mask;
+
+       return 0;
+}
+
+static int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes,
+                             const char *name)
+{
+       struct device_node *np = ddata->dev->of_node;
+       struct property *prop;
+       const __be32 *p;
+       u32 val;
+
+       of_property_for_each_u32(np, name, prop, p, val) {
+               if (val >= SYSC_NR_IDLEMODES) {
+                       dev_err(ddata->dev, "invalid idlemode: %i\n", val);
+                       return -EINVAL;
+               }
+               *idlemodes |=  (1 << val);
+       }
+
+       return 0;
+}
+
+static int sysc_init_idlemodes(struct sysc *ddata)
+{
+       int error;
+
+       error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes,
+                                  "ti,sysc-midle");
+       if (error)
+               return error;
+
+       error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes,
+                                  "ti,sysc-sidle");
+       if (error)
+               return error;
+
+       return 0;
+}
+
+/*
+ * Only some devices on omap4 and later have SYSCONFIG reset done
+ * bit. We can detect this if there is no SYSSTATUS at all, or the
+ * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers
+ * have multiple bits for the child devices like OHCI and EHCI.
+ * Depends on SYSC being parsed first.
+ */
+static int sysc_init_syss_mask(struct sysc *ddata)
+{
+       struct device_node *np = ddata->dev->of_node;
+       int error;
+       u32 val;
+
+       error = of_property_read_u32(np, "ti,syss-mask", &val);
+       if (error) {
+               if ((ddata->cap->type == TI_SYSC_OMAP4 ||
+                    ddata->cap->type == TI_SYSC_OMAP4_TIMER) &&
+                   (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
+                       ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
+
+               return 0;
+       }
+
+       if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
+               ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
+
+       ddata->cfg.syss_mask = val;
+
+       return 0;
+}
+
 /* Device tree configured quirks */
 struct sysc_dts_quirk {
        const char *name;
@@ -820,6 +908,18 @@ static int sysc_probe(struct platform_device *pdev)
        if (error)
                goto unprepare;
 
+       error = sysc_init_sysc_mask(ddata);
+       if (error)
+               goto unprepare;
+
+       error = sysc_init_idlemodes(ddata);
+       if (error)
+               goto unprepare;
+
+       error = sysc_init_syss_mask(ddata);
+       if (error)
+               goto unprepare;
+
        pm_runtime_enable(ddata->dev);
 
        error = sysc_init_module(ddata);
index 28e5a61..1be3563 100644 (file)
@@ -41,6 +41,7 @@ struct sysc_regbits {
        s8 emufree_shift;
 };
 
+#define SYSC_QUIRK_RESET_STATUS                BIT(7)
 #define SYSC_QUIRK_NO_IDLE_ON_INIT     BIT(6)
 #define SYSC_QUIRK_NO_RESET_ON_INIT    BIT(5)
 #define SYSC_QUIRK_OPT_CLKS_NEEDED     BIT(4)
@@ -49,6 +50,8 @@ struct sysc_regbits {
 #define SYSC_QUIRK_UNCACHED            BIT(1)
 #define SYSC_QUIRK_USE_CLOCKACT                BIT(0)
 
+#define SYSC_NR_IDLEMODES              4
+
 /**
  * struct sysc_capabilities - capabilities for an interconnect target module
  *
@@ -65,10 +68,17 @@ struct sysc_capabilities {
 
 /**
  * struct sysc_config - configuration for an interconnect target module
+ * @sysc_val: configured value for sysc register
+ * @midlemodes: bitmask of supported master idle modes
+ * @sidlemodes: bitmask of supported master idle modes
  * @srst_udelay: optional delay needed after OCP soft reset
  * @quirks: bitmask of enabled quirks
  */
 struct sysc_config {
+       u32 sysc_val;
+       u32 syss_mask;
+       u8 midlemodes;
+       u8 sidlemodes;
        u8 srst_udelay;
        u32 quirks;
 };