/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2023-2024 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ IMPORTANT: THIS FILE IS USED BY OR GENERATED BY the LATTICE PROPELâ„¢ DEVELOPMENT SUITE, WHICH INCLUDES PROPEL BUILDER AND PROPEL SDK. Lattice grants permission to use this code pursuant to the terms of the Lattice Propel License Agreement. DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ ================================================================== */ #include "lpddr4_nexus.h" #include #include #include #include static lpddr4 *lpddr4_inst; /** * @brief : lpddr4_write32 - This API is used to write data to a specific register. * @param : base_address - base address of a LPDDR IP. * offset - address offset of a specific register. * val - value to be written into specific register. * @return : Value written to register. */ unsigned int lpddr4_write32(unsigned int base_address, unsigned int offset, unsigned int val){ volatile unsigned int *const reg = (unsigned int*) (base_address + offset); *reg = val; return *reg; } /** * @brief : lpddr4_read32 - This API is used to read data to a specific register. * @param : base_address - base address of a LPDDR IP. * offset - address offset of a specific register. * @return : Value read from register. */ unsigned int lpddr4_read32(unsigned int base_address, unsigned int offset){ volatile unsigned int *const reg = (unsigned int*) (base_address + offset); return *reg; } /** * @brief : lpddr4_init - This API is used to initialize LPDDR IP. * This will start the initialization and training sequence of the LPDDR4 SDRAM device. * After all sequence steps are complete, the control of the PHY is transferred to the Memory Controller * and the user can now start accessing the LPDDR4 memory through the data interface. * Note: This API must be called at bootup time/BSP initialization phase if user wants to use external LPDDR4 SDRAM. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * base_address [In] - base address of a LPDDR IP (from sys_platform.h) * @return : Success or Training error codes. */ LPDDR_RET lpddr4_init(lpddr4 *instance_ptr, unsigned int base_addr){ LPDDR_RET ret = NO_FAIL; volatile status_reg_t sts_reg; volatile clk_chng_t clk_chng_reg; if(instance_ptr == IS_NULL){ return FAILURE; } instance_ptr->lpddr4_base_address=base_addr; lpddr4_inst=instance_ptr; lpddr4_inst->lpddr4_base_address=instance_ptr->lpddr4_base_address; /* Waiting until PLL is locked */ do{ clk_chng_reg=(clk_chng_t)lpddr4_read32(lpddr4_inst->lpddr4_base_address,CLK_CHANGE_REG); }while((clk_chng_reg.reg & PLL_LOCK_BIT) != PLL_LOCK_BIT); printf("\r\nINFO: DDR PLL Locked"); /* Set LPDDR4 training sequence parameters */ lpddr4_write32(lpddr4_inst->lpddr4_base_address,TRN_OP_REG,TRN_EN); /* Bring LPDDR out of reset to start training sequence */ lpddr4_write32(lpddr4_inst->lpddr4_base_address,RESET_REG,OUT_OF_RESET); /* Reading LPDDR4 Status register */ sts_reg = (status_reg_t)lpddr4_read32(lpddr4_inst->lpddr4_base_address,STATUS_REG); while((sts_reg.reg & LPDDR_ERR_DONE_BITS) != LPDDR_DONE_BITS){ sts_reg = (status_reg_t)lpddr4_read32(lpddr4_inst->lpddr4_base_address,STATUS_REG); //printf("\r\nINFO:DDR status = %x\n", sts_reg); if(sts_reg.fields.cbt_err == 1){ printf("\r\nErr:LPDDR CBT_FAIL ocurred\n"); return CBT_FAIL; } if(sts_reg.fields.write_lvl_err == 1){ printf("\r\nErr:LPDDR WR_LVL_FAIL ocurred\n"); return WR_LVL_FAIL; } if(sts_reg.fields.read_trn_err == 1){ printf("\r\nErr:LPDDR RD_TRN_FAIL ocurred\n"); return RD_TRN_FAIL; } if(sts_reg.fields.write_trn_err == 1){ printf("\r\nErr:LPDDR WR_TRN_FAIL ocurred\n"); return WR_TRN_FAIL; } } printf("\r\nINFO: LPDDR4 training complete; LPDDR4 training status = %x \r\nINFO: LPDDR4 initialized successfully\n", sts_reg); return ret; } /** * @brief : lpddr4_GetFeatureControlReg - This API is used to read Feature Control Register (FEATURE_CTRL_REG). * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * reg_data [Out] - Value read from register. * @return : Success or Failure. */ unsigned int lpddr4_GetFeatureControlReg(lpddr4 *InstancePtr, unsigned int *reg_data){ if (InstancePtr == IS_NULL) return FAILURE; *reg_data = lpddr4_read32(InstancePtr->lpddr4_base_address, FEATURE_CTRL_REG); return SUCCESS; } /** * @brief : lpddr4_GetSettingReg - This API is used to read Settings Register (SETTINGS_REG). * User set this reg in GUI, only can read here. * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * reg_data [Out] - Value read from register. * @return : Success or Failure. */ unsigned int lpddr4_GetSettingReg(lpddr4 *InstancePtr, unsigned int *reg_data){ if (InstancePtr == IS_NULL) return FAILURE; *reg_data = lpddr4_read32(InstancePtr->lpddr4_base_address, SETTINGS_REG); return SUCCESS; } /** * @brief : lpddr4_TemperatureChangeInterruptEnable - This API is used to enable temperature change interrupt. * The Memory Controller periodically reads MR4(Mode Register 4) and according to the 'Temperature Check Period' attribute, * This interrupt bit asserts when MR4 indicates a temperature change, and the refresh rate is not equal to 1x refresh. * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * @return : Success or Failure. */ unsigned int lpddr4_TemperatureChangeInterruptEnable(lpddr4 *InstancePtr){ if (InstancePtr == IS_NULL) return FAILURE; int_enable_reg_t en_reg; en_reg = (int_enable_reg_t)lpddr4_read32(InstancePtr->lpddr4_base_address, INT_ENABLE_REG); en_reg.fields.temp_change_int=1; lpddr4_write32(InstancePtr->lpddr4_base_address,INT_ENABLE_REG,en_reg.reg); return SUCCESS; } /** * @brief : lpddr4_TemperatureChangeInterruptDisable - This API is used to disable temperature change interrupt. * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * @return : Success or Failure. */ unsigned int lpddr4_TemperatureChangeInterruptDisable(lpddr4 *InstancePtr){ if (InstancePtr == IS_NULL) return FAILURE; int_enable_reg_t en_reg; en_reg = (int_enable_reg_t)lpddr4_read32(InstancePtr->lpddr4_base_address, INT_ENABLE_REG); en_reg.fields.temp_change_int=0; lpddr4_write32(InstancePtr->lpddr4_base_address,INT_ENABLE_REG,en_reg.reg); return SUCCESS; } /** * @brief : lpddr4_TrainingErrorInterruptEnable - This API is used to enable training error interrupt. * This Interrupt bit asserts when the Training Engine encounters an error during training. The * user should read STATUS_REG to determine the specific error. * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * @return : Success or Failure. */ unsigned int lpddr4_TrainingErrorInterruptEnable(lpddr4 *InstancePtr){ if (InstancePtr == IS_NULL) return FAILURE; int_enable_reg_t en_reg; en_reg = (int_enable_reg_t)lpddr4_read32(InstancePtr->lpddr4_base_address, INT_ENABLE_REG); en_reg.fields.trn_err_en=1; lpddr4_write32(InstancePtr->lpddr4_base_address,INT_ENABLE_REG,en_reg.reg); return SUCCESS; } /** * @brief : lpddr4_TrainingErrorInterruptDisable - This API is used to disable training error interrupt. * In this case, The user can poll STATUS_REG to determine the specific error. * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * @return : Success or Failure. */ unsigned int lpddr4_TrainingErrorInterruptDisable(lpddr4 *InstancePtr){ if (InstancePtr == IS_NULL) return FAILURE; int_enable_reg_t en_reg; en_reg = (int_enable_reg_t)lpddr4_read32(InstancePtr->lpddr4_base_address, INT_ENABLE_REG); en_reg.fields.trn_err_en=0; lpddr4_write32(InstancePtr->lpddr4_base_address,INT_ENABLE_REG,en_reg.reg); return SUCCESS; } /** * @brief : lpddr4_TrainingDoneInterruptEnable - This API is used to enable training done interrupt. * This Interrupt bit asserts when initialization and training is completed successfully. * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * @return : Success or Failure. */ unsigned int lpddr4_TrainingDoneInterruptEnable(lpddr4 *InstancePtr){ if (InstancePtr == IS_NULL) return FAILURE; int_enable_reg_t en_reg; en_reg =(int_enable_reg_t)lpddr4_read32(InstancePtr->lpddr4_base_address, INT_ENABLE_REG); en_reg.fields.trn_done_en=1; lpddr4_write32(InstancePtr->lpddr4_base_address,INT_ENABLE_REG,en_reg.reg); return SUCCESS; } /** * @brief : lpddr4_TrainingDoneInterruptDisable - This API is used to disable training done interrupt. * In this case, The user can poll STATUS_REG. * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * @return : Success or Failure. */ unsigned int lpddr4_TrainingDoneInterruptDisable(lpddr4 *InstancePtr){ if (InstancePtr == IS_NULL) return FAILURE; int_enable_reg_t en_reg; en_reg =(int_enable_reg_t)lpddr4_read32(InstancePtr->lpddr4_base_address, INT_ENABLE_REG); en_reg.fields.trn_done_en=0; lpddr4_write32(InstancePtr->lpddr4_base_address,INT_ENABLE_REG,en_reg.reg); return SUCCESS; } /** * @brief : lpddr4_GetTrainingOperationReg - This API is used to read Training Operation Register (TRN_OP_REG). * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * reg_data [Out] - Value read from register. * @return : Success or Failure. */ unsigned int lpddr4_GetTrainingOperationReg(lpddr4 *InstancePtr, unsigned int *reg_data){ if (InstancePtr == IS_NULL) return FAILURE; *reg_data = lpddr4_read32(InstancePtr->lpddr4_base_address, TRN_OP_REG); return SUCCESS; } /** * @brief : lpddr4_GetStatusReg - This API is used to read Status Register (STATUS_REG). * Refer IP user guide for a register description. * @param : instance_ptr [In] - Handle of the lpddr4 structure. * reg_data [Out] - Value read from register. * @return : Success or Failure. */ unsigned int lpddr4_GetStatusReg(lpddr4 *InstancePtr, unsigned int *reg_data){ if (InstancePtr == IS_NULL) return FAILURE; *reg_data = lpddr4_read32(InstancePtr->lpddr4_base_address, STATUS_REG); return SUCCESS; }