ARM: keystone2: psc: introduce function to hold and release module in reset.
authorNishanth Menon <nm@ti.com>
Thu, 25 Feb 2016 18:53:44 +0000 (12:53 -0600)
committerTom Rini <trini@konsulko.com>
Mon, 14 Mar 2016 23:18:36 +0000 (19:18 -0400)
These are useful for modules that need to be held in reset and are
enabled for data to be loaded on to them. Typically these are
microcontrollers or other processing entities in the system.

Signed-off-by: Nishanth Menon <nm@ti.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
arch/arm/mach-keystone/include/mach/psc_defs.h
arch/arm/mach-keystone/psc.c

index 2202946..6e6e7fd 100644 (file)
@@ -56,6 +56,8 @@
 #define PSC_REG_MDSTAT_GET_STATUS(x)        BOOT_READ_BITFIELD((x), 5, 0)
 #define PSC_REG_MDSTAT_GET_LRSTZ(x)         BOOT_READ_BITFIELD((x), 8, 8)
 #define PSC_REG_MDSTAT_GET_LRSTDONE(x)      BOOT_READ_BITFIELD((x), 9, 9)
+#define PSC_REG_MDSTAT_GET_MRSTZ(x)         BOOT_READ_BITFIELD((x), 10, 10)
+#define PSC_REG_MDSTAT_GET_MRSTDONE(x)      BOOT_READ_BITFIELD((x), 11, 11)
 
 /* PDCTL states */
 #define PSC_REG_VAL_PDCTL_NEXT_ON           1
@@ -86,5 +88,7 @@ u32 psc_get_domain_num(u32 mod_num);
 int psc_enable_module(u32 mod_num);
 int psc_disable_module(u32 mod_num);
 int psc_disable_domain(u32 domain_num);
+int psc_module_keep_in_reset_enabled(u32 mod_num, bool gate_clocks);
+int psc_module_release_from_reset(u32 mod_num);
 
 #endif /* _PSC_DEFS_H_ */
index 8991e23..ff042a6 100644 (file)
@@ -233,3 +233,107 @@ int psc_disable_domain(u32 domain_num)
 
        return psc_wait(domain_num);
 }
+
+/**
+ * psc_module_keep_in_reset_enabled() - Keep module in enabled,in-reset state
+ * @mod_num:   LPSC module number
+ * @gate_clocks: Can the clocks be gated on this module?
+ *
+ * Enable the module, but do not release the module from local reset. This is
+ * necessary for many processor systems on keystone SoCs to allow for system
+ * initialization from a master processor prior to releasing the processor
+ * from reset.
+ */
+int psc_module_keep_in_reset_enabled(u32 mod_num, bool gate_clocks)
+{
+       u32 mdctl, ptcmd, mdstat;
+       u32 next_state;
+       int domain_num = psc_get_domain_num(mod_num);
+       int timeout = 100000;
+
+       /* Wait for any previous transitions to complete */
+       psc_wait(domain_num);
+       mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+       /* Should be set 0 to assert Local reset */
+       if ((mdctl & PSC_REG_MDCTL_SET_LRSTZ(mdctl, 1))) {
+               mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0);
+               __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+               /* Wait for transition to take place */
+               psc_wait(domain_num);
+       }
+
+       /* Clear Module reset */
+       mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+       next_state = gate_clocks ? PSC_REG_VAL_MDCTL_NEXT_OFF :
+                       PSC_REG_VAL_MDCTL_NEXT_ON;
+       mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, next_state);
+       __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+       /* Trigger PD transition */
+       ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
+       ptcmd |= (u32)(1 << domain_num);
+       __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
+       psc_wait(domain_num);
+
+       mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
+       while (timeout) {
+               mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
+
+               if (!(PSC_REG_MDSTAT_GET_STATUS(mdstat) & 0x30) &&
+                   PSC_REG_MDSTAT_GET_MRSTDONE(mdstat) &&
+                   PSC_REG_MDSTAT_GET_LRSTDONE(mdstat))
+                       break;
+               timeout--;
+       }
+
+       if (!timeout) {
+               printf("%s: Timedout waiting for mdstat(0x%08x) to change\n",
+                      __func__, mdstat);
+               return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+/**
+ * psc_module_release_from_reset() - Release the module from reset
+ * @mod_num:   LPSC module number
+ *
+ * This is the follow through for the command 'psc_module_keep_in_reset_enabled'
+ * Allowing the module to be released from reset once all required inits are
+ * complete for the module. Typically, this allows the processor module to start
+ * execution.
+ */
+int psc_module_release_from_reset(u32 mod_num)
+{
+       u32 mdctl, mdstat;
+       int domain_num = psc_get_domain_num(mod_num);
+       int timeout = 100000;
+
+       /* Wait for any previous transitions to complete */
+       psc_wait(domain_num);
+       mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+       /* Should be set to 1 to de-assert Local reset */
+       if ((mdctl & PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0))) {
+               mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 1);
+               __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+               /* Wait for transition to take place */
+               psc_wait(domain_num);
+       }
+       mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
+       while (timeout) {
+               mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
+
+               if (!(PSC_REG_MDSTAT_GET_STATUS(mdstat) & 0x30) &&
+                   PSC_REG_MDSTAT_GET_MRSTDONE(mdstat) &&
+                   PSC_REG_MDSTAT_GET_LRSTDONE(mdstat))
+                       break;
+               timeout--;
+       }
+
+       if (!timeout) {
+               printf("%s: Timedout waiting for mdstat(0x%08x) to change\n",
+                      __func__, mdstat);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}