aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/arch/arm/mach-keystone/psc.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/arch/arm/mach-keystone/psc.c')
-rw-r--r--roms/u-boot/arch/arm/mach-keystone/psc.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/mach-keystone/psc.c b/roms/u-boot/arch/arm/mach-keystone/psc.c
new file mode 100644
index 000000000..145aff8ac
--- /dev/null
+++ b/roms/u-boot/arch/arm/mach-keystone/psc.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Keystone: PSC configuration module
+ *
+ * (C) Copyright 2012-2014
+ * Texas Instruments Incorporated, <www.ti.com>
+ */
+
+#include <common.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#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;
+}
+
+/**
+ * psc_wait() - Wait for end of transitional state
+ * @domain_num: GPSC domain number
+ *
+ * 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.
+ *
+ * Return: 0 when the domain is free. Returns -1 if a timeout occurred waiting
+ * for the completion.
+ */
+int psc_wait(u32 domain_num)
+{
+ u32 retry;
+ u32 ptstat;
+
+ /*
+ * Do nothing if the power domain is in transition. This should never
+ * happen since the boot code is the only software accesses psc.
+ * It's still remotely possible that the hardware state machines
+ * initiate transitions.
+ * Don't trap if the domain (or a module in this domain) is
+ * stuck in transition.
+ */
+ retry = 0;
+
+ do {
+ ptstat = __raw_readl(KS2_PSC_BASE + PSC_REG_PSTAT);
+ ptstat = ptstat & (1 << domain_num);
+ } while ((ptstat != 0) && ((retry += psc_delay()) <
+ PSC_PTSTAT_TIMEOUT_LIMIT));
+
+ if (retry >= PSC_PTSTAT_TIMEOUT_LIMIT)
+ return -1;
+
+ 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;
+
+ /* Get the power domain associated with the module number */
+ domain_num = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
+ domain_num = PSC_REG_MDCFG_GET_PD(domain_num);
+
+ return domain_num;
+}
+
+/**
+ * psc_set_state() - powers up/down a module
+ * @mod_num: LPSC module number
+ * @state: 1 to enable, 0 to disable.
+ *
+ * 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.
+ *
+ * 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)
+{
+ u32 domain_num;
+ u32 pdctl;
+ u32 mdctl;
+ u32 ptcmd;
+ u32 reset_iso;
+ u32 v;
+
+ /*
+ * Get the power domain associated with the module number, and reset
+ * isolation functionality
+ */
+ v = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
+ domain_num = PSC_REG_MDCFG_GET_PD(v);
+ reset_iso = PSC_REG_MDCFG_GET_RESET_ISO(v);
+
+ /* Wait for the status of the domain/module to be non-transitional */
+ if (psc_wait(domain_num) != 0)
+ return -1;
+
+ /*
+ * Perform configuration even if the current status matches the
+ * existing state
+ *
+ * Set the next state of the power domain to on. It's OK if the domain
+ * is always on. This code will not ever power down a domain, so no
+ * change is made if the new state is power down.
+ */
+ if (state == PSC_REG_VAL_MDCTL_NEXT_ON) {
+ pdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
+ pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl,
+ PSC_REG_VAL_PDCTL_NEXT_ON);
+ __raw_writel(pdctl, KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
+ }
+
+ /* Set the next state for the module to enabled/disabled */
+ mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+ mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, state);
+ mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, reset_iso);
+ __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+
+ /* Trigger the enable */
+ ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
+ ptcmd |= (u32)(1<<domain_num);
+ __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
+
+ /* Wait on the complete */
+ return psc_wait(domain_num);
+}
+
+/**
+ * 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.
+ *
+ * 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_enable_module(u32 mod_num)
+{
+ u32 mdctl;
+
+ /* Set the bit to apply reset */
+ mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+ if ((mdctl & 0x3f) == PSC_REG_VAL_MDSTAT_STATE_ON)
+ return 0;
+
+ return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_ON);
+}
+
+/**
+ * psc_disable_module() - Power down a module
+ * @mod_num: LPSC module number
+ *
+ * Return: 0 on success, -1 on failure or timeout.
+ */
+int psc_disable_module(u32 mod_num)
+{
+ u32 mdctl;
+
+ /* Set the bit to apply reset */
+ mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+ if ((mdctl & 0x3f) == 0)
+ return 0;
+ mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0);
+ __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+
+ return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE);
+}
+
+/**
+ * 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.
+ *
+ * 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)
+{
+ u32 v;
+ u32 mdctl;
+
+ /* Set the reset isolation bit */
+ mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+ mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, 1);
+ __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
+
+ v = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
+ if (PSC_REG_MDCFG_GET_RESET_ISO(v) == 1)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * psc_disable_domain() - Disable a power domain
+ * @domain_num: GPSC domain number
+ */
+int psc_disable_domain(u32 domain_num)
+{
+ u32 pdctl;
+ u32 ptcmd;
+
+ pdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
+ pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
+ pdctl = PSC_REG_PDCTL_SET_PDMODE(pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
+ __raw_writel(pdctl, KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
+
+ ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
+ ptcmd |= (u32)(1 << domain_num);
+ __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
+
+ 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;
+}