| // SPDX-License-Identifier: BSD-3-Clause |
| /****************************************************************************** |
| * Copyright (C) 2012-2018 Cadence Design Systems, Inc. |
| * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ |
| * |
| * lpddr4.c |
| * |
| ***************************************************************************** |
| */ |
| #include "cps_drv_lpddr4.h" |
| #include "lpddr4_ctl_regs.h" |
| #include "lpddr4_if.h" |
| #include "lpddr4_private.h" |
| #include "lpddr4_sanity.h" |
| #include "lpddr4_structs_if.h" |
| |
| #define LPDDR4_CUSTOM_TIMEOUT_DELAY 100000000U |
| |
| /** |
| * Internal Function:Poll for status of interrupt received by the Controller. |
| * @param[in] pD Driver state info specific to this instance. |
| * @param[in] irqBit Interrupt status bit to be checked. |
| * @param[in] delay time delay. |
| * @return CDN_EOK on success (Interrupt status high). |
| * @return EIO on poll time out. |
| * @return EINVAL checking status was not successful. |
| */ |
| static uint32_t lpddr4_pollctlirq(const lpddr4_privatedata * pd, |
| lpddr4_ctlinterrupt irqbit, uint32_t delay) |
| { |
| |
| uint32_t result = 0U; |
| uint32_t timeout = 0U; |
| bool irqstatus = false; |
| |
| /* Loop until irqStatus found to be 1 or if value of 'result' !=CDN_EOK */ |
| do { |
| if (++timeout == delay) { |
| result = EIO; |
| break; |
| } |
| /* cps_delayns(10000000U); */ |
| result = lpddr4_checkctlinterrupt(pd, irqbit, &irqstatus); |
| } while ((irqstatus == false) && (result == (uint32_t) CDN_EOK)); |
| |
| return result; |
| } |
| |
| /** |
| * Internal Function:Poll for status of interrupt received by the PHY Independent Module. |
| * @param[in] pD Driver state info specific to this instance. |
| * @param[in] irqBit Interrupt status bit to be checked. |
| * @param[in] delay time delay. |
| * @return CDN_EOK on success (Interrupt status high). |
| * @return EIO on poll time out. |
| * @return EINVAL checking status was not successful. |
| */ |
| static uint32_t lpddr4_pollphyindepirq(const lpddr4_privatedata * pd, |
| lpddr4_phyindepinterrupt irqbit, |
| uint32_t delay) |
| { |
| |
| uint32_t result = 0U; |
| uint32_t timeout = 0U; |
| bool irqstatus = false; |
| |
| /* Loop until irqStatus found to be 1 or if value of 'result' !=CDN_EOK */ |
| do { |
| if (++timeout == delay) { |
| result = EIO; |
| break; |
| } |
| /* cps_delayns(10000000U); */ |
| result = lpddr4_checkphyindepinterrupt(pd, irqbit, &irqstatus); |
| } while ((irqstatus == false) && (result == (uint32_t) CDN_EOK)); |
| |
| return result; |
| } |
| |
| /** |
| * Internal Function:Trigger function to poll and Ack IRQs |
| * @param[in] pD Driver state info specific to this instance. |
| * @return CDN_EOK on success (Interrupt status high). |
| * @return EIO on poll time out. |
| * @return EINVAL checking status was not successful. |
| */ |
| static uint32_t lpddr4_pollandackirq(const lpddr4_privatedata * pd) |
| { |
| uint32_t result = 0U; |
| |
| /* Wait for PhyIndependent module to finish up ctl init sequence */ |
| result = |
| lpddr4_pollphyindepirq(pd, LPDDR4_PHY_INDEP_INIT_DONE_BIT, |
| LPDDR4_CUSTOM_TIMEOUT_DELAY); |
| |
| /* Ack to clear the PhyIndependent interrupt bit */ |
| if (result == (uint32_t) CDN_EOK) { |
| result = |
| lpddr4_ackphyindepinterrupt(pd, |
| LPDDR4_PHY_INDEP_INIT_DONE_BIT); |
| } |
| /* Wait for the CTL end of initialization */ |
| if (result == (uint32_t) CDN_EOK) { |
| result = |
| lpddr4_pollctlirq(pd, LPDDR4_MC_INIT_DONE, |
| LPDDR4_CUSTOM_TIMEOUT_DELAY); |
| } |
| /* Ack to clear the Ctl interrupt bit */ |
| if (result == (uint32_t) CDN_EOK) { |
| result = lpddr4_ackctlinterrupt(pd, LPDDR4_MC_INIT_DONE); |
| } |
| return result; |
| } |
| |
| /** |
| * Internal Function: Controller start sequence. |
| * @param[in] pD Driver state info specific to this instance. |
| * @return CDN_EOK on success. |
| * @return EINVAL starting controller was not successful. |
| */ |
| static uint32_t lpddr4_startsequencecontroller(const lpddr4_privatedata * pd) |
| { |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| lpddr4_infotype infotype; |
| |
| /* Set the PI_start to initiate leveling procedure */ |
| regval = |
| CPS_FLD_SET(LPDDR4__PI_START__FLD, |
| CPS_REG_READ(&(ctlregbase->LPDDR4__PI_START__REG))); |
| CPS_REG_WRITE((&(ctlregbase->LPDDR4__PI_START__REG)), regval); |
| |
| /* Set the Ctl_start */ |
| regval = |
| CPS_FLD_SET(LPDDR4__START__FLD, |
| CPS_REG_READ(&(ctlregbase->LPDDR4__START__REG))); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__START__REG), regval); |
| |
| if (pd->infohandler != NULL) { |
| /* If a handler is registered, call it with the relevant information type */ |
| infotype = LPDDR4_DRV_SOC_PLL_UPDATE; |
| pd->infohandler(pd, infotype); |
| } |
| |
| result = lpddr4_pollandackirq(pd); |
| |
| return result; |
| } |
| |
| /** |
| * Internal Function: To add the offset to given address. |
| * @param[in] addr Address to which the offset has to be added. |
| * @param[in] regOffset The offset |
| * @return regAddr The address value after the summation. |
| */ |
| static volatile uint32_t *lpddr4_addoffset(volatile uint32_t * addr, |
| uint32_t regoffset) |
| { |
| |
| volatile uint32_t *local_addr = addr; |
| /* Declaring as array to add the offset value. */ |
| volatile uint32_t *regaddr = &local_addr[regoffset]; |
| return regaddr; |
| } |
| |
| /** |
| * Checks configuration object. |
| * @param[in] config Driver/hardware configuration required. |
| * @param[out] configSize Size of memory allocations required. |
| * @return CDN_EOK on success (requirements structure filled). |
| * @return ENOTSUP if configuration cannot be supported due to driver/hardware constraints. |
| */ |
| uint32_t lpddr4_probe(const lpddr4_config * config, uint16_t * configsize) |
| { |
| uint32_t result; |
| |
| result = (uint32_t) (lpddr4_probesf(config, configsize)); |
| if (result == (uint32_t) CDN_EOK) { |
| *configsize = (uint16_t) (sizeof(lpddr4_privatedata)); |
| } |
| return result; |
| } |
| |
| /** |
| * Init function to be called after LPDDR4_probe() to set up the driver configuration. |
| * Memory should be allocated for drv_data (using the size determined using LPDDR4_probe) before |
| * calling this API, init_settings should be initialized with base addresses for PHY Independent Module, |
| * Controller and PHY before calling this function. |
| * If callbacks are required for interrupt handling, these should also be configured in init_settings. |
| * @param[in] pD Driver state info specific to this instance. |
| * @param[in] cfg Specifies driver/hardware configuration. |
| * @return CDN_EOK on success |
| * @return EINVAL if illegal/inconsistent values in cfg. |
| * @return ENOTSUP if hardware has an inconsistent configuration or doesn't support feature(s) |
| * required by 'config' parameters. |
| */ |
| uint32_t lpddr4_init(lpddr4_privatedata * pd, const lpddr4_config * cfg) |
| { |
| uint32_t result = 0U; |
| uint16_t productid = 0U; |
| uint32_t version[2] = { 0, 0 }; |
| |
| result = lpddr4_initsf(pd, cfg); |
| if (result == (uint32_t) CDN_EOK) { |
| /* Validate Magic number */ |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) cfg->ctlbase; |
| productid = (uint16_t) (CPS_FLD_READ(LPDDR4__CONTROLLER_ID__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__CONTROLLER_ID__REG)))); |
| version[0] = |
| (uint32_t) (CPS_FLD_READ |
| (LPDDR4__CONTROLLER_VERSION_0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__CONTROLLER_VERSION_0__REG)))); |
| version[1] = |
| (uint32_t) (CPS_FLD_READ |
| (LPDDR4__CONTROLLER_VERSION_1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__CONTROLLER_VERSION_1__REG)))); |
| if ((productid == PRODUCT_ID) && (version[0] == VERSION_0) |
| && (version[1] == VERSION_1)) { |
| /* Populating configuration data to pD */ |
| pd->ctlbase = ctlregbase; |
| pd->infohandler = |
| (lpddr4_infocallback) cfg->infohandler; |
| pd->ctlinterrupthandler = |
| (lpddr4_ctlcallback) cfg->ctlinterrupthandler; |
| pd->phyindepinterrupthandler = |
| (lpddr4_phyindepcallback) cfg-> |
| phyindepinterrupthandler; |
| } else { |
| /* Magic number validation failed - Driver doesn't support given IP version */ |
| result = (uint32_t) EOPNOTSUPP; |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Start the driver. |
| * @param[in] pD Driver state info specific to this instance. |
| */ |
| uint32_t lpddr4_start(const lpddr4_privatedata * pd) |
| { |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| |
| result = lpddr4_startsf(pd); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Enable PI as the initiator for DRAM */ |
| regval = |
| CPS_FLD_SET(LPDDR4__PI_INIT_LVL_EN__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__PI_INIT_LVL_EN__REG))); |
| regval = CPS_FLD_SET(LPDDR4__PI_NORMAL_LVL_SEQ__FLD, regval); |
| CPS_REG_WRITE((&(ctlregbase->LPDDR4__PI_INIT_LVL_EN__REG)), |
| regval); |
| |
| /* Start PI init sequence. */ |
| result = lpddr4_startsequencecontroller(pd); |
| } |
| return result; |
| } |
| |
| /** |
| * Read a register from the controller, PHY or PHY Independent Module |
| * @param[in] pD Driver state info specific to this instance. |
| * @param[in] cpp Indicates whether controller, PHY or PHY Independent Module register |
| * @param[in] regOffset Register offset |
| * @param[out] regValue Register value read |
| * @return CDN_EOK on success. |
| * @return EINVAL if regOffset if out of range or regValue is NULL |
| */ |
| uint32_t lpddr4_readreg(const lpddr4_privatedata * pd, lpddr4_regblock cpp, |
| uint32_t regoffset, uint32_t * regvalue) |
| { |
| uint32_t result = 0U; |
| |
| result = lpddr4_readregsf(pd, cpp, regvalue); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| if (cpp == LPDDR4_CTL_REGS) { |
| if (regoffset >= LPDDR4_CTL_REG_COUNT) { |
| /* Return if user provider invalid register number */ |
| result = EINVAL; |
| } else { |
| *regvalue = |
| CPS_REG_READ(lpddr4_addoffset |
| (&(ctlregbase->DENALI_CTL_0), |
| regoffset)); |
| } |
| } else if (cpp == LPDDR4_PHY_REGS) { |
| if (regoffset >= LPDDR4_PHY_REG_COUNT) { |
| /* Return if user provider invalid register number */ |
| result = EINVAL; |
| } else { |
| *regvalue = |
| CPS_REG_READ(lpddr4_addoffset |
| (&(ctlregbase->DENALI_PHY_0), |
| regoffset)); |
| } |
| |
| } else { |
| if (regoffset >= LPDDR4_PHY_INDEP_REG_COUNT) { |
| /* Return if user provider invalid register number */ |
| result = EINVAL; |
| } else { |
| *regvalue = |
| CPS_REG_READ(lpddr4_addoffset |
| (&(ctlregbase->DENALI_PI_0), |
| regoffset)); |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_writereg(const lpddr4_privatedata * pd, lpddr4_regblock cpp, |
| uint32_t regoffset, uint32_t regvalue) |
| { |
| uint32_t result = 0U; |
| |
| result = lpddr4_writeregsf(pd, cpp); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| if (cpp == LPDDR4_CTL_REGS) { |
| if (regoffset >= LPDDR4_CTL_REG_COUNT) { |
| /* Return if user provider invalid register number */ |
| result = EINVAL; |
| } else { |
| CPS_REG_WRITE(lpddr4_addoffset |
| (&(ctlregbase->DENALI_CTL_0), |
| regoffset), regvalue); |
| } |
| } else if (cpp == LPDDR4_PHY_REGS) { |
| if (regoffset >= LPDDR4_PHY_REG_COUNT) { |
| /* Return if user provider invalid register number */ |
| result = EINVAL; |
| } else { |
| CPS_REG_WRITE(lpddr4_addoffset |
| (&(ctlregbase->DENALI_PHY_0), |
| regoffset), regvalue); |
| } |
| } else { |
| if (regoffset >= LPDDR4_PHY_INDEP_REG_COUNT) { |
| /* Return if user provider invalid register number */ |
| result = EINVAL; |
| } else { |
| CPS_REG_WRITE(lpddr4_addoffset |
| (&(ctlregbase->DENALI_PI_0), |
| regoffset), regvalue); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| static uint32_t lpddr4_checkmmrreaderror(const lpddr4_privatedata * pd, |
| uint64_t * mmrvalue, |
| uint8_t * mrrstatus) |
| { |
| |
| uint64_t lowerdata; |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| uint32_t result = (uint32_t) CDN_EOK; |
| |
| /* Check if mode register read error interrupt occurred */ |
| if (lpddr4_pollctlirq(pd, LPDDR4_MRR_ERROR, 100) == 0U) { |
| /* Mode register read error interrupt, read MRR status register and return. */ |
| *mrrstatus = |
| (uint8_t) CPS_FLD_READ(LPDDR4__MRR_ERROR_STATUS__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__MRR_ERROR_STATUS__REG))); |
| *mmrvalue = 0; |
| result = EIO; |
| } else { |
| *mrrstatus = 0; |
| /* Mode register read was successful, read DATA */ |
| lowerdata = |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__PERIPHERAL_MRR_DATA_0__REG)); |
| *mmrvalue = |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__PERIPHERAL_MRR_DATA_1__REG)); |
| *mmrvalue = (uint64_t) ((*mmrvalue << WORD_SHIFT) | lowerdata); |
| /* Acknowledge MR_READ_DONE interrupt to clear it */ |
| result = lpddr4_ackctlinterrupt(pd, LPDDR4_MR_READ_DONE); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_getmmrregister(const lpddr4_privatedata * pd, |
| uint32_t readmoderegval, uint64_t * mmrvalue, |
| uint8_t * mmrstatus) |
| { |
| |
| uint32_t result = 0U; |
| uint32_t tdelay = 1000U; |
| uint32_t regval = 0U; |
| |
| result = lpddr4_getmmrregistersf(pd, mmrvalue, mmrstatus); |
| if (result == (uint32_t) CDN_EOK) { |
| |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Populate the calculated value to the register */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__READ_MODEREG__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__READ_MODEREG__REG)), |
| readmoderegval); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__READ_MODEREG__REG), regval); |
| |
| /* Wait until the Read is done */ |
| result = lpddr4_pollctlirq(pd, LPDDR4_MR_READ_DONE, tdelay); |
| } |
| if (result == (uint32_t) CDN_EOK) { |
| result = lpddr4_checkmmrreaderror(pd, mmrvalue, mmrstatus); |
| } |
| return result; |
| } |
| |
| static uint32_t lpddr4_writemmrregister(const lpddr4_privatedata * pd, |
| uint32_t writemoderegval) |
| { |
| |
| uint32_t result = (uint32_t) CDN_EOK; |
| uint32_t tdelay = 1000U; |
| uint32_t regval = 0U; |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Populate the calculated value to the register */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__WRITE_MODEREG__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__WRITE_MODEREG__REG)), |
| writemoderegval); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__WRITE_MODEREG__REG), regval); |
| |
| result = lpddr4_pollctlirq(pd, LPDDR4_MR_WRITE_DONE, tdelay); |
| |
| return result; |
| } |
| |
| uint32_t lpddr4_setmmrregister(const lpddr4_privatedata * pd, |
| uint32_t writemoderegval, uint8_t * mrwstatus) |
| { |
| uint32_t result = 0U; |
| |
| result = lpddr4_setmmrregistersf(pd, mrwstatus); |
| if (result == (uint32_t) CDN_EOK) { |
| |
| /* Function call to trigger Mode register write */ |
| result = lpddr4_writemmrregister(pd, writemoderegval); |
| |
| if (result == (uint32_t) CDN_EOK) { |
| result = |
| lpddr4_ackctlinterrupt(pd, LPDDR4_MR_WRITE_DONE); |
| } |
| /* Read the status of mode register write */ |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = |
| (lpddr4_ctlregs *) pd->ctlbase; |
| *mrwstatus = |
| (uint8_t) CPS_FLD_READ(LPDDR4__MRW_STATUS__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__MRW_STATUS__REG))); |
| if ((*mrwstatus) != 0U) { |
| result = EIO; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| uint32_t lpddr4_writectlconfig(const lpddr4_privatedata * pd, |
| const lpddr4_reginitdata * regvalues) |
| { |
| uint32_t result; |
| uint32_t regnum; |
| |
| result = lpddr4_writectlconfigsf(pd, regvalues); |
| if (result == (uint32_t) CDN_EOK) { |
| |
| /* Iterate through CTL register numbers. */ |
| for (regnum = 0; regnum < LPDDR4_CTL_REG_COUNT; regnum++) { |
| /* Check if the user has requested update */ |
| if (regvalues->updatectlreg[regnum]) { |
| result = |
| lpddr4_writereg(pd, LPDDR4_CTL_REGS, regnum, |
| (uint32_t) (regvalues-> |
| denalictlreg |
| [regnum])); |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_writephyindepconfig(const lpddr4_privatedata * pd, |
| const lpddr4_reginitdata * regvalues) |
| { |
| uint32_t result; |
| uint32_t regnum; |
| |
| result = lpddr4_writephyindepconfigsf(pd, regvalues); |
| if (result == (uint32_t) CDN_EOK) { |
| |
| /* Iterate through PHY Independent module register numbers. */ |
| for (regnum = 0; regnum < LPDDR4_PHY_INDEP_REG_COUNT; regnum++) { |
| /* Check if the user has requested update */ |
| if (regvalues->updatephyindepreg[regnum]) { |
| result = |
| lpddr4_writereg(pd, LPDDR4_PHY_INDEP_REGS, |
| regnum, |
| (uint32_t) (regvalues-> |
| denaliphyindepreg |
| [regnum])); |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_writephyconfig(const lpddr4_privatedata * pd, |
| const lpddr4_reginitdata * regvalues) |
| { |
| uint32_t result; |
| uint32_t regnum; |
| |
| result = lpddr4_writephyconfigsf(pd, regvalues); |
| if (result == (uint32_t) CDN_EOK) { |
| |
| /* Iterate through PHY register numbers. */ |
| for (regnum = 0; regnum < LPDDR4_PHY_REG_COUNT; regnum++) { |
| /* Check if the user has requested update */ |
| if (regvalues->updatephyreg[regnum]) { |
| result = |
| lpddr4_writereg(pd, LPDDR4_PHY_REGS, regnum, |
| (uint32_t) (regvalues-> |
| denaliphyreg |
| [regnum])); |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_readctlconfig(const lpddr4_privatedata * pd, |
| lpddr4_reginitdata * regvalues) |
| { |
| uint32_t result; |
| uint32_t regnum; |
| result = lpddr4_readctlconfigsf(pd, regvalues); |
| if (result == (uint32_t) CDN_EOK) { |
| /* Iterate through CTL register numbers. */ |
| for (regnum = 0; regnum < LPDDR4_CTL_REG_COUNT; regnum++) { |
| /* Check if the user has requested read (updateCtlReg=1) */ |
| if (regvalues->updatectlreg[regnum]) { |
| result = |
| lpddr4_readreg(pd, LPDDR4_CTL_REGS, regnum, |
| (uint32_t *) (®values-> |
| denalictlreg |
| [regnum])); |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_readphyindepconfig(const lpddr4_privatedata * pd, |
| lpddr4_reginitdata * regvalues) |
| { |
| uint32_t result; |
| uint32_t regnum; |
| |
| result = lpddr4_readphyindepconfigsf(pd, regvalues); |
| if (result == (uint32_t) CDN_EOK) { |
| /* Iterate through PHY Independent module register numbers. */ |
| for (regnum = 0; regnum < LPDDR4_PHY_INDEP_REG_COUNT; regnum++) { |
| /* Check if the user has requested read (updateCtlReg=1) */ |
| if (regvalues->updatephyindepreg[regnum]) { |
| result = |
| lpddr4_readreg(pd, LPDDR4_PHY_INDEP_REGS, |
| regnum, |
| (uint32_t *) (®values-> |
| denaliphyindepreg |
| [regnum])); |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_readphyconfig(const lpddr4_privatedata * pd, |
| lpddr4_reginitdata * regvalues) |
| { |
| uint32_t result; |
| uint32_t regnum; |
| |
| result = lpddr4_readphyconfigsf(pd, regvalues); |
| if (result == (uint32_t) CDN_EOK) { |
| /* Iterate through PHY register numbers. */ |
| for (regnum = 0; regnum < LPDDR4_PHY_REG_COUNT; regnum++) { |
| /* Check if the user has requested read (updateCtlReg=1) */ |
| if (regvalues->updatephyreg[regnum]) { |
| result = |
| lpddr4_readreg(pd, LPDDR4_PHY_REGS, regnum, |
| (uint32_t *) (®values-> |
| denaliphyreg |
| [regnum])); |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_getctlinterruptmask(const lpddr4_privatedata * pd, |
| uint64_t * mask) |
| { |
| uint32_t result = 0U; |
| uint64_t lowermask = 0U; |
| |
| result = lpddr4_getctlinterruptmasksf(pd, mask); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| /* Reading the lower mask register */ |
| lowermask = |
| (uint64_t) (CPS_FLD_READ |
| (LPDDR4__INT_MASK_0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__INT_MASK_0__REG)))); |
| /* Reading the upper mask register */ |
| *mask = |
| (uint64_t) (CPS_FLD_READ |
| (LPDDR4__INT_MASK_1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__INT_MASK_1__REG)))); |
| /* Concatenate both register informations */ |
| *mask = (uint64_t) ((*mask << WORD_SHIFT) | lowermask); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_setctlinterruptmask(const lpddr4_privatedata * pd, |
| const uint64_t * mask) |
| { |
| uint32_t result; |
| uint32_t regval = 0; |
| const uint64_t ui64one = 1ULL; |
| const uint32_t ui32irqcount = (uint32_t) LPDDR4_LOR_BITS + 1U; |
| |
| result = lpddr4_setctlinterruptmasksf(pd, mask); |
| if ((result == (uint32_t) CDN_EOK) && (ui32irqcount < 64U)) { |
| /* Return if the user given value is higher than the field width */ |
| if (*mask >= (ui64one << ui32irqcount)) { |
| result = EINVAL; |
| } |
| } |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Extracting the lower 32 bits and writing to lower mask register */ |
| regval = (uint32_t) (*mask & WORD_MASK); |
| regval = |
| CPS_FLD_WRITE(LPDDR4__INT_MASK_0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__INT_MASK_0__REG)), |
| regval); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__INT_MASK_0__REG), regval); |
| |
| /* Extracting the upper 32 bits and writing to upper mask register */ |
| regval = (uint32_t) ((*mask >> WORD_SHIFT) & WORD_MASK); |
| regval = |
| CPS_FLD_WRITE(LPDDR4__INT_MASK_1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__INT_MASK_1__REG)), |
| regval); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__INT_MASK_1__REG), regval); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_checkctlinterrupt(const lpddr4_privatedata * pd, |
| lpddr4_ctlinterrupt intr, bool * irqstatus) |
| { |
| uint32_t result; |
| uint32_t ctlirqstatus = 0; |
| uint32_t fieldshift = 0; |
| |
| /* NOTE:This function assume irq status is mentioned in NOT more than 2 registers. |
| * Value of 'interrupt' should be less than 64 */ |
| result = lpddr4_checkctlinterruptsf(pd, intr, irqstatus); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| if ((uint32_t) intr >= WORD_SHIFT) { |
| ctlirqstatus = |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__INT_STATUS_1__REG)); |
| /* Reduce the shift value as we are considering upper register */ |
| fieldshift = (uint32_t) intr - ((uint32_t) WORD_SHIFT); |
| } else { |
| ctlirqstatus = |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__INT_STATUS_0__REG)); |
| /* The shift value remains same for lower interrupt register */ |
| fieldshift = (uint32_t) intr; |
| } |
| |
| /* MISRA compliance (Shifting operation) check */ |
| if (fieldshift < WORD_SHIFT) { |
| if (((ctlirqstatus >> fieldshift) & BIT_MASK) > 0U) { |
| *irqstatus = true; |
| } else { |
| *irqstatus = false; |
| } |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_ackctlinterrupt(const lpddr4_privatedata * pd, |
| lpddr4_ctlinterrupt intr) |
| { |
| uint32_t result = 0; |
| uint32_t regval = 0; |
| uint32_t localinterrupt = (uint32_t) intr; |
| |
| /* NOTE:This function assume irq status is mentioned in NOT more than 2 registers. |
| * Value of 'interrupt' should be less than 64 */ |
| result = lpddr4_ackctlinterruptsf(pd, intr); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Check if the requested bit is in upper register */ |
| if (localinterrupt > WORD_SHIFT) { |
| localinterrupt = |
| (localinterrupt - (uint32_t) WORD_SHIFT); |
| regval = ((uint32_t) BIT_MASK << localinterrupt); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__INT_ACK_1__REG), |
| regval); |
| } else { |
| regval = ((uint32_t) BIT_MASK << localinterrupt); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__INT_ACK_0__REG), |
| regval); |
| } |
| } |
| |
| return result; |
| } |
| |
| uint32_t lpddr4_getphyindepinterruptmask(const lpddr4_privatedata * pd, |
| uint32_t * mask) |
| { |
| uint32_t result; |
| |
| result = lpddr4_getphyindepinterruptmsf(pd, mask); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| /* Reading mask register */ |
| *mask = |
| CPS_FLD_READ(LPDDR4__PI_INT_MASK__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__PI_INT_MASK__REG))); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_setphyindepinterruptmask(const lpddr4_privatedata * pd, |
| const uint32_t * mask) |
| { |
| uint32_t result; |
| uint32_t regval = 0; |
| const uint32_t ui32irqcount = |
| (uint32_t) LPDDR4_PHY_INDEP_DLL_LOCK_STATE_CHANGE_BIT + 1U; |
| |
| result = lpddr4_setphyindepinterruptmsf(pd, mask); |
| if ((result == (uint32_t) CDN_EOK) && (ui32irqcount < WORD_SHIFT)) { |
| /* Return if the user given value is higher than the field width */ |
| if (*mask >= (1U << ui32irqcount)) { |
| result = EINVAL; |
| } |
| } |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Writing to the user requested interrupt mask */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__PI_INT_MASK__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__PI_INT_MASK__REG)), |
| *mask); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__PI_INT_MASK__REG), regval); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_checkphyindepinterrupt(const lpddr4_privatedata * pd, |
| lpddr4_phyindepinterrupt intr, |
| bool * irqstatus) |
| { |
| uint32_t result = 0; |
| uint32_t phyindepirqstatus = 0; |
| |
| result = lpddr4_checkphyindepinterrupsf(pd, intr, irqstatus); |
| /* Confirming that the value of interrupt is less than register width */ |
| if ((result == (uint32_t) CDN_EOK) && ((uint32_t) intr < WORD_SHIFT)) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Reading the requested bit to check interrupt status */ |
| phyindepirqstatus = |
| CPS_REG_READ(&(ctlregbase->LPDDR4__PI_INT_STATUS__REG)); |
| *irqstatus = |
| (((phyindepirqstatus >> (uint32_t) intr) & BIT_MASK) > 0U); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_ackphyindepinterrupt(const lpddr4_privatedata * pd, |
| lpddr4_phyindepinterrupt intr) |
| { |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| uint32_t ui32shiftinterrupt = (uint32_t) intr; |
| |
| result = lpddr4_ackphyindepinterruptsf(pd, intr); |
| /* Confirming that the value of interrupt is less than register width */ |
| if ((result == (uint32_t) CDN_EOK) && (ui32shiftinterrupt < WORD_SHIFT)) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Write 1 to the requested bit to ACk the interrupt */ |
| regval = ((uint32_t) BIT_MASK << ui32shiftinterrupt); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__PI_INT_ACK__REG), regval); |
| } |
| |
| return result; |
| } |
| |
| /* Check for caTrainingError */ |
| static void lpddr4_checkcatrainingerror(lpddr4_ctlregs * ctlregbase, |
| lpddr4_debuginfo * debuginfo, |
| bool * errfoundptr) |
| { |
| |
| uint32_t regval; |
| uint32_t errbitmask = 0U; |
| uint32_t snum; |
| volatile uint32_t *regaddress; |
| |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__PHY_ADR_CALVL_OBS1_0__REG)); |
| errbitmask = (CA_TRAIN_RL) | (NIBBLE_MASK); |
| /* PHY_ADR_CALVL_OBS1[4] – Right found |
| PHY_ADR_CALVL_OBS1[5] – left found |
| both the above fields should be high and below field should be zero. |
| PHY_ADR_CALVL_OBS1[3:0] – calvl_state |
| */ |
| for (snum = 0U; snum < ASLICE_NUM; snum++) { |
| regval = CPS_REG_READ(regaddress); |
| if ((regval & errbitmask) != CA_TRAIN_RL) { |
| debuginfo->catraingerror = true; |
| *errfoundptr = true; |
| } |
| regaddress = |
| lpddr4_addoffset(regaddress, (uint32_t) SLICE_WIDTH); |
| } |
| } |
| |
| /* Check for wrLvlError */ |
| static void lpddr4_checkwrlvlerror(lpddr4_ctlregs * ctlregbase, |
| lpddr4_debuginfo * debuginfo, |
| bool * errfoundptr) |
| { |
| |
| uint32_t regval; |
| uint32_t errbitmask = 0U; |
| uint32_t snum; |
| volatile uint32_t *regaddress; |
| |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__PHY_WRLVL_ERROR_OBS_0__REG)); |
| /* PHY_WRLVL_ERROR_OBS_X[1:0] should be zero */ |
| errbitmask = (BIT_MASK << 1) | (BIT_MASK); |
| for (snum = 0U; snum < DSLICE_NUM; snum++) { |
| regval = CPS_REG_READ(regaddress); |
| if ((regval & errbitmask) != 0U) { |
| debuginfo->wrlvlerror = true; |
| *errfoundptr = true; |
| } |
| regaddress = |
| lpddr4_addoffset(regaddress, (uint32_t) SLICE_WIDTH); |
| } |
| } |
| |
| /* Check for GateLvlError */ |
| static void lpddr4_checkgatelvlerror(lpddr4_ctlregs * ctlregbase, |
| lpddr4_debuginfo * debuginfo, |
| bool * errfoundptr) |
| { |
| |
| uint32_t regval; |
| uint32_t errbitmask = 0U; |
| uint32_t snum; |
| volatile uint32_t *regaddress; |
| |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__PHY_GTLVL_STATUS_OBS_0__REG)); |
| /* PHY_GTLVL_STATUS_OBS[6] – gate_level min error |
| * PHY_GTLVL_STATUS_OBS[7] – gate_level max error |
| * All the above bit fields should be zero */ |
| errbitmask = GATE_LVL_ERROR_FIELDS; |
| for (snum = 0U; snum < DSLICE_NUM; snum++) { |
| regval = CPS_REG_READ(regaddress); |
| if ((regval & errbitmask) != 0U) { |
| debuginfo->gatelvlerror = true; |
| *errfoundptr = true; |
| } |
| regaddress = |
| lpddr4_addoffset(regaddress, (uint32_t) SLICE_WIDTH); |
| } |
| } |
| |
| /* Check for ReadLvlError */ |
| static void lpddr4_checkreadlvlerror(lpddr4_ctlregs * ctlregbase, |
| lpddr4_debuginfo * debuginfo, |
| bool * errfoundptr) |
| { |
| |
| uint32_t regval; |
| uint32_t errbitmask = 0U; |
| uint32_t snum; |
| volatile uint32_t *regaddress; |
| |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__PHY_RDLVL_STATUS_OBS_0__REG)); |
| /* PHY_RDLVL_STATUS_OBS[23:16] – failed bits : should be zero. |
| PHY_RDLVL_STATUS_OBS[31:28] – rdlvl_state : should be zero */ |
| errbitmask = READ_LVL_ERROR_FIELDS; |
| for (snum = 0U; snum < DSLICE_NUM; snum++) { |
| regval = CPS_REG_READ(regaddress); |
| if ((regval & errbitmask) != 0U) { |
| debuginfo->readlvlerror = true; |
| *errfoundptr = true; |
| } |
| regaddress = |
| lpddr4_addoffset(regaddress, (uint32_t) SLICE_WIDTH); |
| } |
| } |
| |
| /* Check for DqTrainingError */ |
| static void lpddr4_checkdqtrainingerror(lpddr4_ctlregs * ctlregbase, |
| lpddr4_debuginfo * debuginfo, |
| bool * errfoundptr) |
| { |
| |
| uint32_t regval; |
| uint32_t errbitmask = 0U; |
| uint32_t snum; |
| volatile uint32_t *regaddress; |
| |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__PHY_WDQLVL_STATUS_OBS_0__REG)); |
| /* PHY_WDQLVL_STATUS_OBS[26:18] should all be zero. */ |
| errbitmask = DQ_LVL_STATUS; |
| for (snum = 0U; snum < DSLICE_NUM; snum++) { |
| regval = CPS_REG_READ(regaddress); |
| if ((regval & errbitmask) != 0U) { |
| debuginfo->dqtrainingerror = true; |
| *errfoundptr = true; |
| } |
| regaddress = |
| lpddr4_addoffset(regaddress, (uint32_t) SLICE_WIDTH); |
| } |
| } |
| |
| /** |
| * Internal Function:For checking errors in training/levelling sequence. |
| * @param[in] pD Driver state info specific to this instance. |
| * @param[in] debugInfo pointer to debug information. |
| * @param[out] errFoundPtr pointer to return if error found. |
| * @return CDN_EOK on success (Interrupt status high). |
| * @return EINVAL checking or unmasking was not successful. |
| */ |
| static bool lpddr4_checklvlerrors(const lpddr4_privatedata * pd, |
| lpddr4_debuginfo * debuginfo, bool errfound) |
| { |
| |
| bool localerrfound = errfound; |
| |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| if (localerrfound == false) { |
| /* Check for ca training error */ |
| lpddr4_checkcatrainingerror(ctlregbase, debuginfo, |
| &localerrfound); |
| } |
| |
| if (localerrfound == false) { |
| /* Check for Write leveling error */ |
| lpddr4_checkwrlvlerror(ctlregbase, debuginfo, &localerrfound); |
| } |
| |
| if (localerrfound == false) { |
| /* Check for Gate leveling error */ |
| lpddr4_checkgatelvlerror(ctlregbase, debuginfo, &localerrfound); |
| } |
| |
| if (localerrfound == false) { |
| /* Check for Read leveling error */ |
| lpddr4_checkreadlvlerror(ctlregbase, debuginfo, &localerrfound); |
| } |
| |
| if (localerrfound == false) { |
| /* Check for DQ training error */ |
| lpddr4_checkdqtrainingerror(ctlregbase, debuginfo, |
| &localerrfound); |
| } |
| return localerrfound; |
| } |
| |
| static bool lpddr4_seterror(volatile uint32_t * reg, uint32_t errbitmask, |
| bool * errfoundptr, const uint32_t errorinfobits) |
| { |
| |
| uint32_t regval = 0U; |
| |
| /* Read the respective observation register */ |
| regval = CPS_REG_READ(reg); |
| /* Compare the error bit values */ |
| if ((regval & errbitmask) != errorinfobits) { |
| *errfoundptr = true; |
| } |
| return *errfoundptr; |
| } |
| |
| static void lpddr4_seterrors(lpddr4_ctlregs * ctlregbase, |
| lpddr4_debuginfo * debuginfo, bool * errfoundptr) |
| { |
| |
| uint32_t errbitmask = (BIT_MASK << 0x1U) | (BIT_MASK); |
| /* Check PLL observation registers for PLL lock errors */ |
| |
| debuginfo->pllerror = |
| lpddr4_seterror(&(ctlregbase->LPDDR4__PHY_PLL_OBS_0__REG), |
| errbitmask, errfoundptr, PLL_READY); |
| if (*errfoundptr == false) { |
| debuginfo->pllerror = |
| lpddr4_seterror(&(ctlregbase->LPDDR4__PHY_PLL_OBS_1__REG), |
| errbitmask, errfoundptr, PLL_READY); |
| } |
| |
| /* Check for IO Calibration errors */ |
| if (*errfoundptr == false) { |
| debuginfo->iocaliberror = |
| lpddr4_seterror(& |
| (ctlregbase-> |
| LPDDR4__PHY_CAL_RESULT_OBS_0__REG), |
| IO_CALIB_DONE, errfoundptr, IO_CALIB_DONE); |
| } |
| if (*errfoundptr == false) { |
| debuginfo->iocaliberror = |
| lpddr4_seterror(& |
| (ctlregbase-> |
| LPDDR4__PHY_CAL_RESULT2_OBS_0__REG), |
| IO_CALIB_DONE, errfoundptr, IO_CALIB_DONE); |
| } |
| if (*errfoundptr == false) { |
| debuginfo->iocaliberror = |
| lpddr4_seterror(& |
| (ctlregbase-> |
| LPDDR4__PHY_CAL_RESULT3_OBS_0__REG), |
| IO_CALIB_FIELD, errfoundptr, |
| IO_CALIB_STATE); |
| } |
| } |
| |
| static void lpddr4_setphysnapsettings(lpddr4_ctlregs * ctlregbase, |
| const bool errorfound) |
| { |
| |
| uint32_t snum = 0U; |
| volatile uint32_t *regaddress; |
| uint32_t regval = 0U; |
| |
| /* Setting SC_PHY_SNAP_OBS_REGS_x to get a snapshot */ |
| if (errorfound == false) { |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__SC_PHY_SNAP_OBS_REGS_0__REG)); |
| /* Iterate through each PHY Data Slice */ |
| for (snum = 0U; snum < DSLICE_NUM; snum++) { |
| regval = |
| CPS_FLD_SET(LPDDR4__SC_PHY_SNAP_OBS_REGS_0__FLD, |
| CPS_REG_READ(regaddress)); |
| CPS_REG_WRITE(regaddress, regval); |
| regaddress = |
| lpddr4_addoffset(regaddress, |
| (uint32_t) SLICE_WIDTH); |
| } |
| } |
| } |
| |
| static void lpddr4_setphyadrsnapsettings(lpddr4_ctlregs * ctlregbase, |
| const bool errorfound) |
| { |
| |
| uint32_t snum = 0U; |
| volatile uint32_t *regaddress; |
| uint32_t regval = 0U; |
| |
| /* Setting SC_PHY ADR_SNAP_OBS_REGS_x to get a snapshot */ |
| if (errorfound == false) { |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__SC_PHY_ADR_SNAP_OBS_REGS_0__REG)); |
| /* Iterate through each PHY Address Slice */ |
| for (snum = 0U; snum < ASLICE_NUM; snum++) { |
| regval = |
| CPS_FLD_SET(LPDDR4__SC_PHY_ADR_SNAP_OBS_REGS_0__FLD, |
| CPS_REG_READ(regaddress)); |
| CPS_REG_WRITE(regaddress, regval); |
| regaddress = |
| lpddr4_addoffset(regaddress, |
| (uint32_t) SLICE_WIDTH); |
| } |
| } |
| } |
| |
| static void lpddr4_setsettings(lpddr4_ctlregs * ctlregbase, |
| const bool errorfound) |
| { |
| |
| /* Calling functions to enable snap shots of OBS registers */ |
| lpddr4_setphysnapsettings(ctlregbase, errorfound); |
| lpddr4_setphyadrsnapsettings(ctlregbase, errorfound); |
| } |
| |
| static void lpddr4_setrxoffseterror(lpddr4_ctlregs * ctlregbase, |
| lpddr4_debuginfo * debuginfo, |
| bool * errorfound) |
| { |
| |
| volatile uint32_t *regaddress; |
| uint32_t snum = 0U; |
| uint32_t errbitmask = 0U; |
| uint32_t regval = 0U; |
| |
| /* Check for rxOffsetError */ |
| if (*errorfound == false) { |
| regaddress = |
| (volatile uint32_t |
| *)(&(ctlregbase->LPDDR4__PHY_RX_CAL_LOCK_OBS_0__REG)); |
| errbitmask = (RX_CAL_DONE) | (NIBBLE_MASK); |
| /* PHY_RX_CAL_LOCK_OBS_x[4] – RX_CAL_DONE : should be high |
| phy_rx_cal_lock_obs_x[3:0] – RX_CAL_STATE : should be zero. */ |
| for (snum = 0U; snum < DSLICE_NUM; snum++) { |
| regval = |
| CPS_FLD_READ(LPDDR4__PHY_RX_CAL_LOCK_OBS_0__FLD, |
| CPS_REG_READ(regaddress)); |
| if ((regval & errbitmask) != RX_CAL_DONE) { |
| debuginfo->rxoffseterror = true; |
| *errorfound = true; |
| } |
| regaddress = |
| lpddr4_addoffset(regaddress, |
| (uint32_t) SLICE_WIDTH); |
| } |
| } |
| } |
| |
| uint32_t lpddr4_getdebuginitinfo(const lpddr4_privatedata * pd, |
| lpddr4_debuginfo * debuginfo) |
| { |
| |
| uint32_t result = 0U; |
| bool errorfound = false; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_getdebuginitinfosf(pd, debuginfo); |
| if (result == (uint32_t) CDN_EOK) { |
| |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| lpddr4_seterrors(ctlregbase, debuginfo, &errorfound); |
| /* Function to setup Snap for OBS registers */ |
| lpddr4_setsettings(ctlregbase, errorfound); |
| /* Function to check for Rx offset error */ |
| lpddr4_setrxoffseterror(ctlregbase, debuginfo, &errorfound); |
| /* Function Check various levelling errors */ |
| errorfound = lpddr4_checklvlerrors(pd, debuginfo, errorfound); |
| } |
| |
| if (errorfound == true) { |
| result = (uint32_t) EPROTO; |
| } |
| |
| return result; |
| } |
| |
| static void readpdwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, uint32_t * cycles) |
| { |
| |
| /* Read the appropriate register, based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_PD_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_PD_WAKEUP_F0__REG))); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_PD_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_PD_WAKEUP_F1__REG))); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_PD_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_PD_WAKEUP_F2__REG))); |
| } |
| } |
| |
| static void readsrshortwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, uint32_t * cycles) |
| { |
| |
| /* Read the appropriate register, based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_SHORT_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_SHORT_WAKEUP_F0__REG))); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_SHORT_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_SHORT_WAKEUP_F1__REG))); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_SHORT_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_SHORT_WAKEUP_F2__REG))); |
| } |
| } |
| |
| static void readsrlongwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, uint32_t * cycles) |
| { |
| |
| /* Read the appropriate register, based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_LONG_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_WAKEUP_F0__REG))); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_LONG_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_WAKEUP_F1__REG))); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_LONG_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_WAKEUP_F2__REG))); |
| } |
| } |
| |
| static void readsrlonggatewakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, uint32_t * cycles) |
| { |
| |
| /* Read the appropriate register, based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F0__REG))); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F1__REG))); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F2__REG))); |
| } |
| } |
| |
| static void readsrdpshortwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, uint32_t * cycles) |
| { |
| |
| /* Read the appropriate register, based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SRPD_SHORT_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F0__REG))); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SRPD_SHORT_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F1__REG))); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SRPD_SHORT_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F2__REG))); |
| } |
| } |
| |
| static void readsrdplongwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, uint32_t * cycles) |
| { |
| |
| /* Read the appropriate register, based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SRPD_LONG_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F0__REG))); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SRPD_LONG_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F1__REG))); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| *cycles = |
| CPS_FLD_READ(LPDDR4__LPI_SRPD_LONG_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F2__REG))); |
| } |
| } |
| |
| static void readsrdplonggatewakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, |
| uint32_t * cycles) |
| { |
| |
| /* Read the appropriate register, based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| *cycles = |
| CPS_FLD_READ |
| (LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F0__REG))); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| *cycles = |
| CPS_FLD_READ |
| (LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F1__REG))); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| *cycles = |
| CPS_FLD_READ |
| (LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2__REG))); |
| } |
| |
| } |
| |
| static void lpddr4_readlpiwakeuptime(lpddr4_ctlregs * ctlregbase, |
| const lpddr4_lpiwakeupparam * |
| lpiwakeupparam, |
| const lpddr4_ctlfspnum * fspnum, |
| uint32_t * cycles) |
| { |
| |
| /* Iterate through each of the Wake up parameter type */ |
| if (*lpiwakeupparam == LPDDR4_LPI_PD_WAKEUP_FN) { |
| /* Calling appropriate function for register read */ |
| readpdwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SR_SHORT_WAKEUP_FN) { |
| readsrshortwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SR_LONG_WAKEUP_FN) { |
| readsrlongwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SR_LONG_MCCLK_GATE_WAKEUP_FN) { |
| readsrlonggatewakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SRPD_SHORT_WAKEUP_FN) { |
| readsrdpshortwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SRPD_LONG_WAKEUP_FN) { |
| readsrdplongwakeup(fspnum, ctlregbase, cycles); |
| } else { |
| /* Default function (sanity function already confirmed the variable value) */ |
| readsrdplonggatewakeup(fspnum, ctlregbase, cycles); |
| } |
| } |
| |
| uint32_t lpddr4_getlpiwakeuptime(const lpddr4_privatedata * pd, |
| const lpddr4_lpiwakeupparam * lpiwakeupparam, |
| const lpddr4_ctlfspnum * fspnum, |
| uint32_t * cycles) |
| { |
| |
| uint32_t result = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_getlpiwakeuptimesf(pd, lpiwakeupparam, fspnum, cycles); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| lpddr4_readlpiwakeuptime(ctlregbase, lpiwakeupparam, fspnum, |
| cycles); |
| } |
| return result; |
| } |
| |
| static void writepdwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, const uint32_t * cycles) |
| { |
| |
| uint32_t regval = 0U; |
| /* Write to appropriate register ,based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_PD_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_PD_WAKEUP_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__LPI_PD_WAKEUP_F0__REG), |
| regval); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_PD_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_PD_WAKEUP_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__LPI_PD_WAKEUP_F1__REG), |
| regval); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_PD_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_PD_WAKEUP_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__LPI_PD_WAKEUP_F2__REG), |
| regval); |
| } |
| } |
| |
| static void writesrshortwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, |
| const uint32_t * cycles) |
| { |
| |
| uint32_t regval = 0U; |
| /* Write to appropriate register ,based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_SHORT_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_SHORT_WAKEUP_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase->LPDDR4__LPI_SR_SHORT_WAKEUP_F0__REG), |
| regval); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_SHORT_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_SHORT_WAKEUP_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase->LPDDR4__LPI_SR_SHORT_WAKEUP_F1__REG), |
| regval); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_SHORT_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_SHORT_WAKEUP_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase->LPDDR4__LPI_SR_SHORT_WAKEUP_F2__REG), |
| regval); |
| } |
| } |
| |
| static void writesrlongwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, |
| const uint32_t * cycles) |
| { |
| |
| uint32_t regval = 0U; |
| /* Write to appropriate register ,based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_LONG_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_WAKEUP_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__LPI_SR_LONG_WAKEUP_F0__REG), |
| regval); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_LONG_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_WAKEUP_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__LPI_SR_LONG_WAKEUP_F1__REG), |
| regval); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_LONG_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_WAKEUP_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__LPI_SR_LONG_WAKEUP_F2__REG), |
| regval); |
| } |
| } |
| |
| static void writesrlonggatewakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, |
| const uint32_t * cycles) |
| { |
| |
| uint32_t regval = 0U; |
| /* Write to appropriate register ,based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F0__REG), |
| regval); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F1__REG), |
| regval); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SR_LONG_MCCLK_GATE_WAKEUP_F2__REG), |
| regval); |
| } |
| } |
| |
| static void writesrdpshortwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, |
| const uint32_t * cycles) |
| { |
| |
| uint32_t regval = 0U; |
| /* Write to appropriate register ,based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SRPD_SHORT_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F0__REG), regval); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SRPD_SHORT_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F1__REG), regval); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SRPD_SHORT_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_SHORT_WAKEUP_F2__REG), regval); |
| } |
| } |
| |
| static void writesrdplongwakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, |
| const uint32_t * cycles) |
| { |
| |
| uint32_t regval = 0U; |
| /* Write to appropriate register ,based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SRPD_LONG_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F0__REG), regval); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SRPD_LONG_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F1__REG), regval); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__LPI_SRPD_LONG_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_WAKEUP_F2__REG), regval); |
| } |
| } |
| |
| static void writesrdplonggatewakeup(const lpddr4_ctlfspnum * fspnum, |
| lpddr4_ctlregs * ctlregbase, |
| const uint32_t * cycles) |
| { |
| |
| uint32_t regval = 0U; |
| /* Write to appropriate register ,based on user given frequency. */ |
| if (*fspnum == LPDDR4_FSP_0) { |
| regval = |
| CPS_FLD_WRITE |
| (LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F0__REG), |
| regval); |
| } else if (*fspnum == LPDDR4_FSP_1) { |
| regval = |
| CPS_FLD_WRITE |
| (LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F1__REG), |
| regval); |
| } else { |
| /* Default register (sanity function already confirmed the variable value) */ |
| regval = |
| CPS_FLD_WRITE |
| (LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(& |
| (ctlregbase-> |
| LPDDR4__LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2__REG), |
| regval); |
| } |
| } |
| |
| static void lpddr4_writelpiwakeuptime(lpddr4_ctlregs * ctlregbase, |
| const lpddr4_lpiwakeupparam * |
| lpiwakeupparam, |
| const lpddr4_ctlfspnum * fspnum, |
| const uint32_t * cycles) |
| { |
| |
| /* Iterate through each of the Wake up parameter type */ |
| if (*lpiwakeupparam == LPDDR4_LPI_PD_WAKEUP_FN) { |
| /* Calling appropriate function for register write */ |
| writepdwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SR_SHORT_WAKEUP_FN) { |
| writesrshortwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SR_LONG_WAKEUP_FN) { |
| writesrlongwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SR_LONG_MCCLK_GATE_WAKEUP_FN) { |
| writesrlonggatewakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SRPD_SHORT_WAKEUP_FN) { |
| writesrdpshortwakeup(fspnum, ctlregbase, cycles); |
| } else if (*lpiwakeupparam == LPDDR4_LPI_SRPD_LONG_WAKEUP_FN) { |
| writesrdplongwakeup(fspnum, ctlregbase, cycles); |
| } else { |
| /* Default function (sanity function already confirmed the variable value) */ |
| writesrdplonggatewakeup(fspnum, ctlregbase, cycles); |
| } |
| } |
| |
| uint32_t lpddr4_setlpiwakeuptime(const lpddr4_privatedata * pd, |
| const lpddr4_lpiwakeupparam * lpiwakeupparam, |
| const lpddr4_ctlfspnum * fspnum, |
| const uint32_t * cycles) |
| { |
| uint32_t result = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_setlpiwakeuptimesf(pd, lpiwakeupparam, fspnum, cycles); |
| if (result == (uint32_t) CDN_EOK) { |
| /* Return if the user given value is higher than the field width */ |
| if (*cycles > NIBBLE_MASK) { |
| result = EINVAL; |
| } |
| } |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| lpddr4_writelpiwakeuptime(ctlregbase, lpiwakeupparam, fspnum, |
| cycles); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_geteccenable(const lpddr4_privatedata * pd, |
| lpddr4_eccenable * eccparam) |
| { |
| uint32_t result = 0U; |
| uint32_t fldval = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_geteccenablesf(pd, eccparam); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Reading the ECC_Enable field from the register. */ |
| fldval = |
| CPS_FLD_READ(LPDDR4__ECC_ENABLE__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__ECC_ENABLE__REG))); |
| switch (fldval) { |
| case 3: |
| *eccparam = LPDDR4_ECC_ERR_DETECT_CORRECT; |
| break; |
| case 2: |
| *eccparam = LPDDR4_ECC_ERR_DETECT; |
| break; |
| case 1: |
| *eccparam = LPDDR4_ECC_ENABLED; |
| break; |
| default: |
| /* Default ECC (Sanity function already confirmed the value to be in expected range.) */ |
| *eccparam = LPDDR4_ECC_DISABLED; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_seteccenable(const lpddr4_privatedata * pd, |
| const lpddr4_eccenable * eccparam) |
| { |
| |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_seteccenablesf(pd, eccparam); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Updating the ECC_Enable field based on the user given value. */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__ECC_ENABLE__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__ECC_ENABLE__REG)), |
| *eccparam); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__ECC_ENABLE__REG), regval); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_getreducmode(const lpddr4_privatedata * pd, |
| lpddr4_reducmode * mode) |
| { |
| uint32_t result = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_getreducmodesf(pd, mode); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| /* Read the value of reduc parameter. */ |
| if (CPS_FLD_READ |
| (LPDDR4__REDUC__FLD, |
| CPS_REG_READ(&(ctlregbase->LPDDR4__REDUC__REG))) == 0U) { |
| *mode = LPDDR4_REDUC_ON; |
| } else { |
| *mode = LPDDR4_REDUC_OFF; |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_setreducmode(const lpddr4_privatedata * pd, |
| const lpddr4_reducmode * mode) |
| { |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_setreducmodesf(pd, mode); |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| /* Setting to enable Half data path. */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__REDUC__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__REDUC__REG)), *mode); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__REDUC__REG), regval); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_getdbireadmode(const lpddr4_privatedata * pd, bool * on_off) |
| { |
| |
| uint32_t result = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_getdbireadmodesf(pd, on_off); |
| |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| /* Reading the field value from the register. */ |
| if (CPS_FLD_READ |
| (LPDDR4__RD_DBI_EN__FLD, |
| CPS_REG_READ(&(ctlregbase->LPDDR4__RD_DBI_EN__REG))) == |
| 0U) { |
| *on_off = false; |
| } else { |
| *on_off = true; |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_getdbiwritemode(const lpddr4_privatedata * pd, bool * on_off) |
| { |
| |
| uint32_t result = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_getdbireadmodesf(pd, on_off); |
| |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| /* Reading the field value from the register. */ |
| if (CPS_FLD_READ |
| (LPDDR4__WR_DBI_EN__FLD, |
| CPS_REG_READ(&(ctlregbase->LPDDR4__WR_DBI_EN__REG))) == |
| 0U) { |
| *on_off = false; |
| } else { |
| *on_off = true; |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_setdbimode(const lpddr4_privatedata * pd, |
| const lpddr4_dbimode * mode) |
| { |
| |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_setdbimodesf(pd, mode); |
| |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Updating the appropriate field value based on the user given mode */ |
| if (*mode == LPDDR4_DBI_RD_ON) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__RD_DBI_EN__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__RD_DBI_EN__REG)), |
| 1U); |
| } else if (*mode == LPDDR4_DBI_RD_OFF) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__RD_DBI_EN__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__RD_DBI_EN__REG)), |
| 0U); |
| } else if (*mode == LPDDR4_DBI_WR_ON) { |
| regval = |
| CPS_FLD_WRITE(LPDDR4__WR_DBI_EN__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__WR_DBI_EN__REG)), |
| 1U); |
| } else { |
| /* Default field (Sanity function already confirmed the value to be in expected range.) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__WR_DBI_EN__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__WR_DBI_EN__REG)), |
| 0U); |
| } |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__RD_DBI_EN__REG), regval); |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_getrefreshrate(const lpddr4_privatedata * pd, |
| const lpddr4_ctlfspnum * fspnum, |
| uint32_t * cycles) |
| { |
| uint32_t result = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_getrefreshratesf(pd, fspnum, cycles); |
| |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Selecting the appropriate register for the user requested Frequency */ |
| switch (*fspnum) { |
| case LPDDR4_FSP_2: |
| *cycles = |
| CPS_FLD_READ(LPDDR4__TREF_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__TREF_F2__REG))); |
| break; |
| case LPDDR4_FSP_1: |
| *cycles = |
| CPS_FLD_READ(LPDDR4__TREF_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__TREF_F1__REG))); |
| break; |
| default: |
| /* FSP_0 is considered as the default (sanity check already confirmed it as valid FSP) */ |
| *cycles = |
| CPS_FLD_READ(LPDDR4__TREF_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__TREF_F0__REG))); |
| break; |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_setrefreshrate(const lpddr4_privatedata * pd, |
| const lpddr4_ctlfspnum * fspnum, |
| const uint32_t * cycles) |
| { |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_setrefreshratesf(pd, fspnum, cycles); |
| |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| |
| /* Selecting the appropriate register for the user requested Frequency */ |
| switch (*fspnum) { |
| case LPDDR4_FSP_2: |
| regval = |
| CPS_FLD_WRITE(LPDDR4__TREF_F2__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__TREF_F2__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__TREF_F2__REG), |
| regval); |
| break; |
| case LPDDR4_FSP_1: |
| regval = |
| CPS_FLD_WRITE(LPDDR4__TREF_F1__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__TREF_F1__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__TREF_F1__REG), |
| regval); |
| break; |
| default: |
| /* FSP_0 is considered as the default (sanity check already confirmed it as valid FSP) */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__TREF_F0__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__TREF_F0__REG)), |
| *cycles); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__TREF_F0__REG), |
| regval); |
| break; |
| } |
| } |
| return result; |
| } |
| |
| uint32_t lpddr4_refreshperchipselect(const lpddr4_privatedata * pd, |
| const uint32_t trefinterval) |
| { |
| uint32_t result = 0U; |
| uint32_t regval = 0U; |
| |
| /* Calling Sanity Function to verify the input variables */ |
| result = lpddr4_refreshperchipselectsf(pd); |
| |
| if (result == (uint32_t) CDN_EOK) { |
| lpddr4_ctlregs *ctlregbase = (lpddr4_ctlregs *) pd->ctlbase; |
| /* Setting tref_interval parameter to enable/disable Refresh per chip select. */ |
| regval = |
| CPS_FLD_WRITE(LPDDR4__TREF_INTERVAL__FLD, |
| CPS_REG_READ(& |
| (ctlregbase-> |
| LPDDR4__TREF_INTERVAL__REG)), |
| trefinterval); |
| CPS_REG_WRITE(&(ctlregbase->LPDDR4__TREF_INTERVAL__REG), |
| regval); |
| } |
| return result; |
| } |