3e45a979f08d11b3106d6022ee53409a42b494db
1 /******************************************************************************\r
2 * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com\r
3 *\r
4 * Redistribution and use in source and binary forms, with or without\r
5 * modification, are permitted provided that the following conditions\r
6 * are met:\r
7 *\r
8 * Redistributions of source code must retain the above copyright\r
9 * notice, this list of conditions and the following disclaimer.\r
10 *\r
11 * Redistributions in binary form must reproduce the above copyright\r
12 * notice, this list of conditions and the following disclaimer in the\r
13 * documentation and/or other materials provided with the\r
14 * distribution.\r
15 *\r
16 * Neither the name of Texas Instruments Incorporated nor the names of\r
17 * its contributors may be used to endorse or promote products derived\r
18 * from this software without specific prior written permission.\r
19 *\r
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
31 *\r
32 *****************************************************************************/\r
33 \r
34 /** \file board_ddr.c\r
35 *\r
36 * \brief This file used to configure the DDR timing parameters.\r
37 *\r
38 */\r
39 \r
40 #include <string.h>\r
41 #include <soc.h>\r
42 #include "board_ddr.h"\r
43 #include "board_ddrRegInit.h"\r
44 \r
45 /* Global variables */\r
46 static LPDDR4_Config gBoardDdrCfg;\r
47 static LPDDR4_PrivateData gBoardDdrPd;\r
48 \r
49 /* Local function prototypes */\r
50 static int32_t emif_ConfigureECC(void);\r
51 \r
52 #ifndef SIM_BUILD\r
53 /**\r
54 * \brief Set DDR PLL to bypass, efectively 20MHz or 19.2MHz (on silicon).\r
55 *\r
56 * \return none\r
57 */\r
58 static void Board_DDRSetPLLExtBypass(void)\r
59 {\r
60 \r
61 uint32_t addrOffset = 0x00000000;\r
62 uint32_t baseAddr = CSL_PLL0_CFG_BASE;\r
63 uint32_t regVal;\r
64 uint32_t fieldVal;\r
65 uint32_t regAddr;\r
66 \r
67 fieldVal = 1;\r
68 regAddr = (baseAddr + addrOffset + (DDR_PLL_INDEX * 0x1000) + CSL_MAIN_PLL_MMR_CFG_PLL0_CTRL);\r
69 regVal = HW_RD_REG32(regAddr);\r
70 regVal |= (fieldVal << 31);\r
71 HW_WR_REG32(regAddr, regVal);\r
72 \r
73 }\r
74 \r
75 #endif /* SIM_BUILD */\r
76 \r
77 /**\r
78 * \brief Set DDR PLL clock value\r
79 *\r
80 * \return BOARD_SOK in case of success or appropriate error code\r
81 */\r
82 static Board_STATUS Board_DDRSetPLLClock(void)\r
83 {\r
84 Board_STATUS status = BOARD_SOK;\r
85 \r
86 status = Board_PLLInit(TISCI_DEV_DDR16SS0,\r
87 TISCI_DEV_DDR16SS0_DDRSS_DDR_PLL_CLK,\r
88 DDRSS_PLL_FREQUENCY_1);\r
89 if(status != BOARD_SOK)\r
90 {\r
91 BOARD_DEBUG_LOG("Failed to Set the DDR PLL Clock Frequency\n");\r
92 }\r
93 \r
94 return status;\r
95 }\r
96 \r
97 /**\r
98 * \brief Controls the DDR PLL clock change sequence during inits\r
99 *\r
100 * \return None\r
101 */\r
102 static void Board_DDRChangeFreqAck(void)\r
103 {\r
104 \r
105 /* Configure PLL Clock */\r
106 Board_DDRSetPLLClock();\r
107 \r
108 BOARD_DEBUG_LOG("--->>> DDR PLL clock configured ... <<<---\n");\r
109 }\r
110 \r
111 /**\r
112 * \brief Function to handle the configuration requests from DDR lib\r
113 *\r
114 * \return None\r
115 */\r
116 static void Board_DDRInfoHandler(const LPDDR4_PrivateData *pd, LPDDR4_InfoType infotype)\r
117 {\r
118 if (infotype == LPDDR4_DRV_SOC_PLL_UPDATE)\r
119 {\r
120 Board_DDRChangeFreqAck();\r
121 }\r
122 }\r
123 \r
124 /**\r
125 * \brief DDR probe function\r
126 *\r
127 * \return BOARD_SOK in case of success or appropriate error code\r
128 */\r
129 static Board_STATUS Board_DDRProbe(void)\r
130 {\r
131 uint32_t status = 0U;\r
132 uint16_t configsize = 0U;\r
133 \r
134 status = LPDDR4_Probe(&gBoardDdrCfg, &configsize);\r
135 \r
136 if ((status != 0) || (configsize != sizeof(LPDDR4_PrivateData)) ||\r
137 (configsize > BOARD_DDR_SRAM_MAX))\r
138 {\r
139 BOARD_DEBUG_LOG("Board_DDRProbe: FAIL\n");\r
140 return BOARD_FAIL;\r
141 }\r
142 else\r
143 {\r
144 BOARD_DEBUG_LOG("Board_DDRProbe: PASS\n");\r
145 }\r
146 \r
147 return BOARD_SOK;\r
148 }\r
149 \r
150 /**\r
151 * \brief DDR driver initialization function\r
152 *\r
153 * \return BOARD_SOK in case of success or appropriate error code\r
154 */\r
155 static Board_STATUS Board_DDRInitDrv(void)\r
156 {\r
157 uint32_t status = 0U;\r
158 \r
159 if ((sizeof(gBoardDdrPd) != sizeof(LPDDR4_PrivateData)) ||\r
160 (sizeof(gBoardDdrPd) > BOARD_DDR_SRAM_MAX))\r
161 {\r
162 BOARD_DEBUG_LOG("Board_DDRInitDrv: FAIL\n");\r
163 return BOARD_FAIL;\r
164 }\r
165 \r
166 gBoardDdrCfg.ctlBase = (struct LPDDR4_CtlRegs_s *)BOARD_DDR_CTL_CFG_BASE;\r
167 gBoardDdrCfg.infoHandler = (LPDDR4_InfoCallback) Board_DDRInfoHandler;\r
168 \r
169 status = LPDDR4_Init(&gBoardDdrPd, &gBoardDdrCfg);\r
170 \r
171 if ((status > 0U) ||\r
172 (gBoardDdrPd.ctlBase != (struct LPDDR4_CtlRegs_s *)gBoardDdrCfg.ctlBase) ||\r
173 (gBoardDdrPd.ctlInterruptHandler != gBoardDdrCfg.ctlInterruptHandler) ||\r
174 (gBoardDdrPd.phyIndepInterruptHandler != gBoardDdrCfg.phyIndepInterruptHandler))\r
175 {\r
176 BOARD_DEBUG_LOG("Board_DDRInitDrv: FAIL\n");\r
177 return BOARD_FAIL;\r
178 }\r
179 else\r
180 {\r
181 BOARD_DEBUG_LOG("Board_DDRInitDrv: PASS\n");\r
182 }\r
183 \r
184 return BOARD_SOK;\r
185 }\r
186 \r
187 /**\r
188 * \brief DDR registers initialization function\r
189 *\r
190 * \return BOARD_SOK in case of success or appropriate error code\r
191 */\r
192 static Board_STATUS Board_DDRHWRegInit(void)\r
193 {\r
194 uint32_t status = 0U;\r
195 \r
196 /* VBUSM2AXI Control Register sdram_idx, region_idx 0x11 --> 0x0F = log2(connected SDRAM size) - 16 */\r
197 HW_WR_REG32((CSL_DDR16SS0_SS_CFG_BASE + CSL_EMIF_SSCFG_V2A_CTL_REG),\r
198 (0xFU << CSL_EMIF_SSCFG_V2A_CTL_REG_SDRAM_IDX_SHIFT)\r
199 | (0xFU << CSL_EMIF_SSCFG_V2A_CTL_REG_REGION_IDX_SHIFT)); \r
200 \r
201 \r
202 status = LPDDR4_WriteCtlConfig(&gBoardDdrPd,\r
203 DDRSS_ctlReg,\r
204 DDRSS_ctlRegNum,\r
205 (uint16_t)DDRSS_CTL_REG_INIT_COUNT);\r
206 if (!status)\r
207 {\r
208 status = LPDDR4_WritePhyIndepConfig(&gBoardDdrPd,\r
209 DDRSS_phyIndepReg,\r
210 DDRSS_phyIndepRegNum,\r
211 (uint16_t)DDRSS_PHY_INDEP_REG_INIT_COUNT);\r
212 }\r
213 if (!status)\r
214 {\r
215 status = LPDDR4_WritePhyConfig(&gBoardDdrPd,\r
216 DDRSS_phyReg,\r
217 DDRSS_phyRegNum,\r
218 (uint16_t)DDRSS_PHY_REG_INIT_COUNT);\r
219 }\r
220 \r
221 if (status)\r
222 {\r
223 BOARD_DEBUG_LOG(" ERROR: Board_DDRHWRegInit failed!!\n");\r
224 return BOARD_FAIL;\r
225 }\r
226 return BOARD_SOK;\r
227 }\r
228 \r
229 /**\r
230 * \brief DDR start function\r
231 *\r
232 * \return BOARD_SOK in case of success or appropriate error code\r
233 */\r
234 static Board_STATUS Board_DDRStart(void)\r
235 {\r
236 uint32_t status = 0U;\r
237 uint32_t regval = 0U;\r
238 uint32_t offset = 0U;\r
239 \r
240 offset = BOARD_DDR_CTL_REG_OFFSET;\r
241 \r
242 status = LPDDR4_ReadReg(&gBoardDdrPd, LPDDR4_CTL_REGS, offset, ®val);\r
243 if ((status > 0U) || ((regval & 0x1U) != 0U))\r
244 {\r
245 BOARD_DEBUG_LOG("Board_DDRStart: FAIL\n");\r
246 return BOARD_FAIL;\r
247 }\r
248 \r
249 status = LPDDR4_Start(&gBoardDdrPd);\r
250 if (status > 0U)\r
251 {\r
252 BOARD_DEBUG_LOG("Board_DDRStart: FAIL\n");\r
253 return BOARD_FAIL;\r
254 }\r
255 \r
256 status = LPDDR4_ReadReg(&gBoardDdrPd, LPDDR4_CTL_REGS, offset, ®val);\r
257 if ((status > 0U) || ((regval & 0x1U) != 1U))\r
258 {\r
259 BOARD_DEBUG_LOG("Board_DDRStart: FAIL\n");\r
260 return BOARD_FAIL;\r
261 }\r
262 else\r
263 {\r
264 BOARD_DEBUG_LOG("LPDDR4_Start: PASS\n");\r
265 }\r
266 \r
267 return BOARD_SOK;\r
268 }\r
269 \r
270 /**\r
271 * \brief Configures DDR ECC\r
272 *\r
273 * Invokes EMIF CSL APIs to configure ECC and Primes the memory\r
274 *\r
275 * \return BOARD_SOK in case of success or appropriate error code\r
276 *\r
277 */\r
278 /* Refer EMIF ECC Configuration Section in TRM */\r
279 static Board_STATUS emif_ConfigureECC(void)\r
280 {\r
281 Board_STATUS status = BOARD_SOK;\r
282 int32_t cslResult = CSL_PASS;\r
283 CSL_EmifConfig emifCfg;\r
284 uintptr_t memPtr;\r
285 \r
286 BOARD_DEBUG_LOG("\r\n Configuring ECC");\r
287 \r
288 memset(&emifCfg, 0, sizeof(emifCfg));\r
289 \r
290 emifCfg.bEnableMemoryECC = true;\r
291 emifCfg.bReadModifyWriteEnable = true;\r
292 emifCfg.bECCCheck = true;\r
293 emifCfg.bWriteAlloc = true;\r
294 emifCfg.ECCThreshold = 1U;\r
295 emifCfg.pMemEccCfg.startAddr[0] = BOARD_DDR_START_ADDR-BOARD_SOC_DDR_START_ADDR;\r
296 emifCfg.pMemEccCfg.endAddr[0] = BOARD_DDR_ECC_END_ADDR-BOARD_SOC_DDR_START_ADDR;\r
297 cslResult = CSL_emifConfig((CSL_emif_sscfgRegs *)CSL_DDR16SS0_SS_CFG_BASE,\r
298 &emifCfg);\r
299 \r
300 if (cslResult != CSL_PASS)\r
301 {\r
302 BOARD_DEBUG_LOG("\r\n CSL_emifConfig Failed");\r
303 status = BOARD_FAIL;\r
304 }\r
305 \r
306 /* Prime the memory */\r
307 if ( status == BOARD_SOK )\r
308 {\r
309 /* Prime memory with known pattern */\r
310 for (memPtr = BOARD_DDR_START_ADDR; memPtr < BOARD_DDR_ECC_END_ADDR; memPtr += 4)\r
311 {\r
312 *((volatile uint32_t *) memPtr) = memPtr;\r
313 }\r
314 \r
315 /* Make sure the write is complete by writeback */\r
316 CacheP_wbInv((const void *)BOARD_DDR_START_ADDR, BOARD_DDR_ECC_END_ADDR-BOARD_DDR_START_ADDR);\r
317 \r
318 /* Clears ECC errors */\r
319 CSL_emifClearAllECCErrors((CSL_emif_sscfgRegs *)CSL_DDR16SS0_SS_CFG_BASE);\r
320 }\r
321 \r
322 return status;\r
323 }\r
324 \r
325 /**\r
326 * \brief DDR4 Initialization function\r
327 *\r
328 * Initializes the DDR timing parameters. Sets the DDR timing parameters\r
329 * based in the DDR PLL controller configuration done by the board library.\r
330 * Any changes to DDR PLL requires change to DDR timing.\r
331 *\r
332 * \param void\r
333 *\r
334 * \return BOARD_SOK in case of success or appropriate error code\r
335 *\r
336 */\r
337 Board_STATUS Board_DDRInit(Bool eccEnable)\r
338 {\r
339 Board_STATUS status = BOARD_SOK;\r
340 #ifndef SIM_BUILD\r
341 /* PLL should be bypassed while configuring the DDR */\r
342 Board_DDRSetPLLExtBypass();\r
343 #endif /* SIM_BUILD */\r
344 /* Partition5 lockkey0 */\r
345 HW_WR_REG32((CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_LOCK5_KICK0),\r
346 KICK0_UNLOCK);\r
347 /* Partition5 lockkey1 */\r
348 HW_WR_REG32((CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_LOCK5_KICK1),\r
349 KICK1_UNLOCK);\r
350 \r
351 status = Board_DDRProbe();\r
352 if(status != BOARD_SOK)\r
353 {\r
354 return status;\r
355 }\r
356 \r
357 status = Board_DDRInitDrv();\r
358 if(status != BOARD_SOK)\r
359 {\r
360 return status;\r
361 }\r
362 \r
363 status = Board_DDRHWRegInit();\r
364 if(status != BOARD_SOK)\r
365 {\r
366 return status;\r
367 }\r
368 \r
369 status = Board_DDRStart();\r
370 if(status != BOARD_SOK)\r
371 {\r
372 return status;\r
373 }\r
374 \r
375 if (eccEnable == TRUE)\r
376 {\r
377 status = emif_ConfigureECC();\r
378 }\r
379 \r
380 return status;\r
381 }\r