diff options
Diffstat (limited to 'roms/u-boot/arch/arm/mach-keystone/psc.c')
-rw-r--r-- | roms/u-boot/arch/arm/mach-keystone/psc.c | 339 |
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; +} |