123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- /*
- * Keystone: PSC configuration module
- *
- * (C) Copyright 2012-2014
- * Texas Instruments Incorporated, <www.ti.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- #include <common.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;
- }
|