]> git.sur5r.net Git - u-boot/blobdiff - arch/arm/mach-keystone/psc.c
ARM: keystone2: psc: introduce function to hold and release module in reset.
[u-boot] / arch / arm / mach-keystone / psc.c
index 237e776e8790422dca0baad62732dd0b121bf8b3..ff042a6db2dd158272b9509aa47ead5b89ee5784 100644 (file)
 #include <asm/processor.h>
 #include <asm/arch/psc_defs.h>
 
+/**
+ * psc_delay() - delay for psc
+ *
+ * Return: 10
+ */
 int psc_delay(void)
 {
        udelay(10);
        return 10;
 }
 
-/*
- * FUNCTION PURPOSE: Wait for end of transitional state
- *
- * DESCRIPTION: Polls pstat for the selected domain and waits for transitions
- *              to be complete.
+/**
+ * psc_wait() - Wait for end of transitional state
+ * @domain_num: GPSC domain number
  *
- *              Since this is boot loader code it is *ASSUMED* that interrupts
- *              are disabled and no other core is mucking around with the psc
- *              at the same time.
+ * Polls pstat for the selected domain and waits for transitions to be complete.
+ * Since this is boot loader code it is *ASSUMED* that interrupts are disabled
+ * and no other core is mucking around with the psc at the same time.
  *
- *              Returns 0 when the domain is free. Returns -1 if a timeout
- *              occurred waiting for the completion.
+ * Return: 0 when the domain is free. Returns -1 if a timeout occurred waiting
+ * for the completion.
  */
 int psc_wait(u32 domain_num)
 {
@@ -59,6 +62,10 @@ int psc_wait(u32 domain_num)
        return 0;
 }
 
+/**
+ * psc_get_domain_num() - Get the domain number
+ * @mod_num:   LPSC module number
+ */
 u32 psc_get_domain_num(u32 mod_num)
 {
        u32 domain_num;
@@ -70,20 +77,19 @@ u32 psc_get_domain_num(u32 mod_num)
        return domain_num;
 }
 
-/*
- * FUNCTION PURPOSE: Power up/down a module
- *
- * DESCRIPTION: Powers up/down the requested module and the associated power
- *             domain if required. No action is taken it the module is
- *             already powered up/down.
+/**
+ * psc_set_state() - powers up/down a module
+ * @mod_num:   LPSC module number
+ * @state:     1 to enable, 0 to disable.
  *
- *              This only controls modules. The domain in which the module
- *              resides will be left in the power on state. Multiple modules
- *              can exist in a power domain, so powering down the domain based
- *              on a single module is not done.
+ * Powers up/down the requested module and the associated power domain if
+ * required. No action is taken it the module is already powered up/down.
+ * This only controls modules. The domain in which the module resides will
+ * be left in the power on state. Multiple modules can exist in a power
+ * domain, so powering down the domain based on a single module is not done.
  *
- *              Returns 0 on success, -1 if the module can't be powered up, or
- *              if there is a timeout waiting for the transition.
+ * Return: 0 on success, -1 if the module can't be powered up, or if there is a
+ * timeout waiting for the transition.
  */
 int psc_set_state(u32 mod_num, u32 state)
 {
@@ -136,15 +142,16 @@ int psc_set_state(u32 mod_num, u32 state)
        return psc_wait(domain_num);
 }
 
-/*
- * FUNCTION PURPOSE: Power up a module
+/**
+ * psc_enable_module() - power up a module
+ * @mod_num:   LPSC module number
+ *
+ * Powers up the requested module and the associated power domain
+ * if required. No action is taken it the module is already powered up.
  *
- * DESCRIPTION: Powers up the requested module and the associated power domain
- *              if required. No action is taken it the module is already
- *              powered up.
+ * Return: 0 on success, -1 if the module can't be powered up, or
+ * if there is a timeout waiting for the transition.
  *
- *              Returns 0 on success, -1 if the module can't be powered up, or
- *              if there is a timeout waiting for the transition.
  */
 int psc_enable_module(u32 mod_num)
 {
@@ -158,12 +165,11 @@ int psc_enable_module(u32 mod_num)
        return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_ON);
 }
 
-/*
- * FUNCTION PURPOSE: Power down a module
+/**
+ * psc_disable_module() - Power down a module
+ * @mod_num:   LPSC module number
  *
- * DESCRIPTION: Powers down the requested module.
- *
- *              Returns 0 on success, -1 on failure or timeout.
+ * Return: 0 on success, -1 on failure or timeout.
  */
 int psc_disable_module(u32 mod_num)
 {
@@ -179,13 +185,16 @@ int psc_disable_module(u32 mod_num)
        return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE);
 }
 
-/*
- * FUNCTION PURPOSE: Set the reset isolation bit in mdctl
+/**
+ * psc_set_reset_iso() - Set the reset isolation bit in mdctl
+ * @mod_num:   LPSC module number
+ *
+ * The reset isolation enable bit is set. The state of the module is not
+ * changed.
  *
- * DESCRIPTION: The reset isolation enable bit is set. The state of the module
- *              is not changed. Returns 0 if the module config showed that
- *              reset isolation is supported. Returns 1 otherwise. This is not
- *              an error, but setting the bit in mdctl has no effect.
+ * Return: 0 if the module config showed that reset isolation is supported.
+ * Returns 1 otherwise. This is not an error, but setting the bit in mdctl
+ * has no effect.
  */
 int psc_set_reset_iso(u32 mod_num)
 {
@@ -204,10 +213,9 @@ int psc_set_reset_iso(u32 mod_num)
        return 1;
 }
 
-/*
- * FUNCTION PURPOSE: Disable a power domain
- *
- * DESCRIPTION: The power domain is disabled
+/**
+ * psc_disable_domain() - Disable a power domain
+ * @domain_num: GPSC domain number
  */
 int psc_disable_domain(u32 domain_num)
 {
@@ -225,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;
+}