/* * 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. * * 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. */ 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 = DEVICE_REG32_R(DEVICE_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 = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_PDCTL(domain_num)); pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl, PSC_REG_VAL_PDCTL_NEXT_ON); DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PDCTL(domain_num), pdctl); } /* Set the next state for the module to enabled/disabled */ mdctl = DEVICE_REG32_R(DEVICE_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); DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num), mdctl); /* Trigger the enable */ ptcmd = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_PTCMD); ptcmd |= (u32)(1<<domain_num); DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd); /* Wait on the complete */ return psc_wait(domain_num); }
/* * FUNCTION PURPOSE: Wait for end of transitional state * * DESCRIPTION: 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. */ 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 = DEVICE_REG32_R(DEVICE_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; }
/* * FUNCTION PURPOSE: Set the reset isolation bit in mdctl * * 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. */ int psc_set_reset_iso(u32 mod_num) { u32 v; u32 mdctl; /* Set the reset isolation bit */ mdctl = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num)); mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, 1); DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num), mdctl); v = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCFG(mod_num)); if (PSC_REG_MDCFG_GET_RESET_ISO(v) == 1) return 0; return 1; }
/* * FUNCTION PURPOSE: Disable a power domain * * DESCRIPTION: The power domain is disabled */ int psc_disable_domain(u32 domain_num) { u32 pdctl; u32 ptcmd; pdctl = DEVICE_REG32_R(DEVICE_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); DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PDCTL(domain_num), pdctl); ptcmd = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_PTCMD); ptcmd |= (u32)(1 << domain_num); DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd); return psc_wait(domain_num); }
/******************************************************************************* * FUNCTION PURPOSE: Setup a mux value ******************************************************************************* * DESCRIPTION: Configures one of the 12 interrupt mux values. Original value * is lost. ******************************************************************************/ void hwIntctlRoute (uint32_t vector, uint32_t eventNum) { uint32_t muxp; uint32_t muxv; uint32_t base; if (vector > 3 && vector < 8) muxp = 1; else if (vector < 12) muxp = 2; else if (vector < 16) muxp = 3; else return; /* Invalid vector */ /* Which of the four events in each register (0-3) is determined by the the * two lsbs of the vector number. The least significant bit of the mux * valud (0, 8, 16, or 24) is found. */ base = (vector & 0x3) * 8; /* Read the active mux, overwrite the event num with the desired value */ muxv = DEVICE_REG32_R (DEVICE_INTCTL_BASE + INTCTL_REG_MUX(muxp)); muxv = BOOT_SET_BITFIELD (muxv, eventNum, base+7, base); DEVICE_REG32_W (DEVICE_INTCTL_BASE + INTCTL_REG_MUX(muxp), muxv); } /* hwIntctlRoute */
u32 psc_get_domain_num(u32 mod_num) { u32 domain_num; /* Get the power domain associated with the module number */ domain_num = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCFG(mod_num)); domain_num = PSC_REG_MDCFG_GET_PD(domain_num); return domain_num; }
/* * FUNCTION PURPOSE: Power up a module * * DESCRIPTION: Powers up the requested module and the associated power domain * if required. No action is taken it the module is already * powered up. * * 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) { u32 mdctl; /* Set the bit to apply reset */ mdctl = DEVICE_REG32_R(DEVICE_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); }
/************************************************************************************ * FUNCTION PURPOSE: Enable and configure serdes ************************************************************************************ * DESCRIPTION: The serdes is configured and enabled ************************************************************************************/ SINT16 hwSerdesConfig (UINT32 sBase, serdesConfig_t *scfg) { UINT32 reg; UINT32 regb; SINT32 i; /* If the serdes is already enabled and the new value does not match * the current value, the serdes is first disabled. Dont compare * the sleep value in the register, which can be toggled dynamically */ reg = DEVICE_REG32_R (sBase + SERDES_REG_CFG); reg = SERDES_SET_CFG_SLEEP(reg, 0); regb = SERDES_SET_CFG_SLEEP(scfg->cfg, 0); chipKickOpenSerdes(sBase); if ( (SERDES_GET_ENABLE(reg) == 1) && (SERDES_GET_ENABLE(scfg->cfg) == 1) && (reg != regb) ) { reg = SERDES_SET_ENABLE(reg, 0); DEVICE_REG32_W (sBase + SERDES_REG_CFG, reg); chipDelay32 (100); } /* Config register. After enable it takes upt to 350ns, or 200 cycles to * stabalize. Although these are serdes clock cycles the delay here is * in cpu cycles. The PLL status will be checked by the peripheral * using the PLL */ DEVICE_REG32_W (sBase + SERDES_REG_CFG, regb); chipDelay32 (200); /* Some devices have unreliable lock status bits. Add an extra delay * to allow the serdes to lock */ chipDelay32 (TARGET_SERDES_LOCK_DELAY); /* rx and tx config registers */ for (i = 0; i < scfg->nLanes; i++) { DEVICE_REG32_W (sBase + SERDES_REG_RX(i), scfg->rxCfg[i]); DEVICE_REG32_W (sBase + SERDES_REG_TX(i), scfg->txCfg[i]); } chipKickClosedSerdes(sBase); return (0); } /* hwSerdesConfig */
/* * FUNCTION PURPOSE: Power down a module * * DESCRIPTION: Powers down the requested module. * * Returns 0 on success, -1 on failure or timeout. */ int psc_disable_module(u32 mod_num) { u32 mdctl; /* Set the bit to apply reset */ mdctl = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num)); if ((mdctl & 0x3f) == 0) return 0; mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0); DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num), mdctl); return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE); }
/******************************************************************************************* * FUNCTION PURPOSE: Wait for a serdes lock on lane 0 ******************************************************************************************* * DESCRIPTION: Waits for a lock on lane 0. Doesn't trap if the lock is not found *******************************************************************************************/ SINT16 hwSerdesWaitLock (UINT32 statusBase) { UINT32 reg; UINT32 i; for (i = 0; i < 100; i++) { reg = DEVICE_REG32_R (statusBase); if (reg & 1) return (0); chipDelay32 (1000); } return (-1); } /* hwSerdesWaitLock */
/******************************************************************************************* * FUNCTION PURPOSE: Configure the gmac sliver ******************************************************************************************* * DESCRIPTION: The emac sliver is configured. *******************************************************************************************/ SINT16 hwGmacSlConfig (UINT16 port, hwGmacSlCfg_t *cfg) { UINT32 v; UINT32 i; SINT16 ret = GMACSL_RET_OK; if (port >= DEVICE_N_GMACSL_PORTS) return (GMACSL_RET_INVALID_PORT); if (cfg->maxRxLen > CPGMAC_REG_MAXLEN_LEN) { cfg->maxRxLen = CPGMAC_REG_MAXLEN_LEN; ret = GMACSL_RET_WARN_MAXLEN_TOO_BIG; } /* Must wait if the device is undergoing reset */ for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { v = DEVICE_REG32_R (DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); if ( (v & CPGMAC_REG_RESET_VAL_RESET_MASK) != CPGMAC_REG_RESET_VAL_RESET) break; } if (i == DEVICE_EMACSL_RESET_POLL_COUNT) return (GMACSL_RET_CONFIG_FAIL_RESET_ACTIVE); DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN, cfg->maxRxLen); DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL, cfg->ctl); return (ret); } /* hwGmacSlConfig */
/******************************************************************************************** * FUNCTION PURPOSE: Reset the the gmac sliver ******************************************************************************************** * DESCRIPTION: Soft reset is set and polled until clear, or until a timeout occurs ********************************************************************************************/ SINT16 hwGmacSlReset (UINT16 port) { UINT32 i; UINT32 v; if (port >= DEVICE_N_GMACSL_PORTS) return (GMACSL_RET_INVALID_PORT); /* Set the soft reset bit */ DEVICE_REG32_W (DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET, CPGMAC_REG_RESET_VAL_RESET); /* Wait for the bit to clear */ for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { v = DEVICE_REG32_R (DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); if ( (v & CPGMAC_REG_RESET_VAL_RESET_MASK) != CPGMAC_REG_RESET_VAL_RESET) return (GMACSL_RET_OK); } /* Timeout on the reset */ return (GMACSL_RET_WARN_RESET_INCOMPLETE); } /* hwGmacSlReset */