1 /*
2 * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-02-24 CDT first version
9 * 2024-02-20 CDT modify exclk clock max frequency to 40MHz for HC32F4A0
10 * add t_rcd_p/t_rfc_p/t_rp_p configuration
11 * 2024-12-24 CDT modify sample clock to EXMC_DMC_SAMPLE_CLK_EXTCLK for HC32F4A0
12 */
13
14
15 /*******************************************************************************
16 * Include files
17 ******************************************************************************/
18 #include <rtthread.h>
19
20
21 #if defined(BSP_USING_EXMC)
22 #if defined(BSP_USING_SDRAM)
23
24 #include "drv_sdram.h"
25 #include "board_config.h"
26 #include "sdram_port.h"
27
28 /*******************************************************************************
29 * Local type definitions ('typedef')
30 ******************************************************************************/
31
32 /*******************************************************************************
33 * Local pre-processor symbols/macros ('#define')
34 ******************************************************************************/
35 //#define DRV_DEBUG
36 #define LOG_TAG "drv.sdram"
37 #include <drv_log.h>
38
39 /*******************************************************************************
40 * Global variable definitions (declared in header file with 'extern')
41 ******************************************************************************/
42 #if defined (BSP_USING_SDRAM)
43 rt_err_t rt_hw_board_sdram_init(void);
44 #endif
45
46 /*******************************************************************************
47 * Local function prototypes ('static')
48 ******************************************************************************/
49
50 /*******************************************************************************
51 * Local variable definitions ('static')
52 ******************************************************************************/
53 #ifdef RT_USING_MEMHEAP_AS_HEAP
54 static struct rt_memheap _system_heap;
55 #endif
56
57 /*******************************************************************************
58 * Function implementation - global ('extern') and local ('static')
59 ******************************************************************************/
60
61 /**
62 * @brief SDRAM initialization sequence.
63 * @param [in] chip The command chip number.
64 * @param [in] md_reg_value The SDRAM mode register value
65 * @retval None
66 */
_sdram_initialization_sequence(rt_uint32_t chip,rt_uint32_t md_reg_value)67 static void _sdram_initialization_sequence(rt_uint32_t chip, rt_uint32_t md_reg_value)
68 {
69 /* SDRAM initialization sequence:
70 CMD NOP->PrechargeAll->AutoRefresh->AutoRefresh->MdRegConfig->NOP */
71 (void)EXMC_DMC_SetCommand(chip, 0UL, EXMC_DMC_CMD_NOP, 0UL);
72 (void)EXMC_DMC_SetCommand(chip, 0UL, EXMC_DMC_CMD_PRECHARGE_ALL, 0UL);
73 (void)EXMC_DMC_SetCommand(chip, 0UL, EXMC_DMC_CMD_AUTO_REFRESH, 0UL);
74 (void)EXMC_DMC_SetCommand(chip, 0UL, EXMC_DMC_CMD_AUTO_REFRESH, 0UL);
75 (void)EXMC_DMC_SetCommand(chip, 0UL, EXMC_DMC_CMD_MDREG_CONFIG, md_reg_value);
76 (void)EXMC_DMC_SetCommand(chip, 0UL, EXMC_DMC_CMD_NOP, 0UL);
77 }
78
79 /**
80 * @brief verify clock frequency.
81 * @retval result
82 */
_sdram_verify_clock_frequency(void)83 static rt_int32_t _sdram_verify_clock_frequency(void)
84 {
85 rt_int32_t ret = RT_EOK;
86
87 #if defined (HC32F4A0) || defined (HC32F4A8)
88 /* EXCLK max frequency for SDRAM */
89 if (CLK_GetBusClockFreq(CLK_BUS_EXCLK) > EXMC_EXCLK_DMC_MAX_FREQ)
90 {
91 ret = -RT_ERROR;
92 }
93 #endif
94
95 return ret;
96 }
97
98 /**
99 * @brief SDRAM initialization.
100 * @param None
101 * @retval result
102 */
_sdram_init(void)103 static rt_int32_t _sdram_init(void)
104 {
105 rt_uint32_t md_reg_value;
106 stc_exmc_dmc_init_t stcDmcInit;
107 stc_exmc_dmc_chip_config_t stcCsConfig;
108
109 /* verify SDRAM clock frequency */
110 if (_sdram_verify_clock_frequency() != RT_EOK)
111 {
112 LOG_E("EXMC clock frequency is over limit for SDRAM!");
113 return -RT_ERROR;
114 }
115
116 /* initialization SDRAM port.*/
117 rt_hw_board_sdram_init();
118
119 /* enable DMC clock */
120 FCG_Fcg3PeriphClockCmd(FCG3_PERIPH_DMC, ENABLE);
121
122 /* enable DMC. */
123 EXMC_DMC_Cmd(ENABLE);
124
125 /* configure DMC width && refresh period & chip & timing. */
126 (void)EXMC_DMC_StructInit(&stcDmcInit);
127 #if defined (HC32F4A0)
128 stcDmcInit.u32SampleClock = EXMC_DMC_SAMPLE_CLK_EXTCLK;
129 #endif
130 stcDmcInit.u32RefreshPeriod = SDRAM_REFRESH_COUNT;
131 stcDmcInit.u32ColumnBitsNumber = SDRAM_COLUMN_BITS;
132 stcDmcInit.u32RowBitsNumber = SDRAM_ROW_BITS;
133 stcDmcInit.u32MemBurst = SDRAM_BURST_LENGTH;
134 stcDmcInit.u32AutoRefreshChips = EXMC_DMC_AUTO_REFRESH_4CHIPS;
135 stcDmcInit.stcTimingConfig.u8CASL = SDRAM_CAS_LATENCY;
136 stcDmcInit.stcTimingConfig.u8DQSS = 0U;
137 stcDmcInit.stcTimingConfig.u8MRD = SDRAM_TMDR;
138 stcDmcInit.stcTimingConfig.u8RAS = SDRAM_TRAS;
139 stcDmcInit.stcTimingConfig.u8RC = SDRAM_TRC;
140 stcDmcInit.stcTimingConfig.u8RCD_B = SDRAM_TRCD_B;
141 stcDmcInit.stcTimingConfig.u8RCD_P = SDRAM_TRCD_P;
142 stcDmcInit.stcTimingConfig.u8RFC_B = SDRAM_TRFC_B;
143 stcDmcInit.stcTimingConfig.u8RFC_P = SDRAM_TRFC_P;
144 stcDmcInit.stcTimingConfig.u8RP_B = SDRAM_TRP_B;
145 stcDmcInit.stcTimingConfig.u8RP_P = SDRAM_TRP_P;
146 stcDmcInit.stcTimingConfig.u8RRD = SDRAM_TRRD;
147 stcDmcInit.stcTimingConfig.u8WR = SDRAM_TWR;
148 stcDmcInit.stcTimingConfig.u8WTR = SDRAM_TWTR;
149 stcDmcInit.stcTimingConfig.u8XP = SDRAM_TXP;
150 stcDmcInit.stcTimingConfig.u8XSR = SDRAM_TXSR;
151 stcDmcInit.stcTimingConfig.u8ESR = SDRAM_TESR;
152 (void)EXMC_DMC_Init(&stcDmcInit);
153
154 /* configure DMC address space. */
155 stcCsConfig.u32AddrMatch = (SDRAM_BANK_ADDR >> 24);
156 stcCsConfig.u32AddrMask = EXMC_DMC_ADDR_MASK_128MB;
157 stcCsConfig.u32AddrDecodeMode = EXMC_DMC_CS_DECODE_ROWBANKCOL;
158 (void)EXMC_DMC_ChipConfig(SDRAM_CHIP, &stcCsConfig);
159
160 /* SDRAM initialization sequence. */
161 md_reg_value = (SDRAM_MODEREG_BURST_TYPE | SDRAM_MODEREG_WRITEBURST_MODE | SDRAM_MODEREG_OPERATING_MODE);
162 if (2U == stcDmcInit.stcTimingConfig.u8CASL)
163 {
164 md_reg_value |= SDRAM_MODEREG_CAS_LATENCY_2;
165 }
166 else
167 {
168 md_reg_value |= SDRAM_MODEREG_CAS_LATENCY_3;
169 }
170
171 if (EXMC_DMC_BURST_1BEAT == stcDmcInit.u32MemBurst)
172 {
173 md_reg_value |= SDRAM_MODEREG_BURST_LENGTH_1;
174 }
175 else if (EXMC_DMC_BURST_2BEAT == stcDmcInit.u32MemBurst)
176 {
177 md_reg_value |= SDRAM_MODEREG_BURST_LENGTH_2;
178 }
179 else if (EXMC_DMC_BURST_4BEAT == stcDmcInit.u32MemBurst)
180 {
181 md_reg_value |= SDRAM_MODEREG_BURST_LENGTH_4;
182 }
183 else
184 {
185 md_reg_value |= SDRAM_MODEREG_BURST_LENGTH_8;
186 }
187
188 _sdram_initialization_sequence(SDRAM_CHIP, md_reg_value);
189
190 /* switch state from configure to ready */
191 EXMC_DMC_SetState(EXMC_DMC_CTRL_STATE_GO);
192 EXMC_DMC_SetState(EXMC_DMC_CTRL_STATE_WAKEUP);
193 EXMC_DMC_SetState(EXMC_DMC_CTRL_STATE_GO);
194
195 return RT_EOK;
196 }
197
rt_hw_sdram_init(void)198 int rt_hw_sdram_init(void)
199 {
200 rt_int32_t ret;
201
202 ret = _sdram_init();
203 if (RT_EOK != ret)
204 {
205 LOG_E("SDRAM init failed!");
206 return -RT_ERROR;
207 }
208
209 #ifdef RT_USING_MEMHEAP_AS_HEAP
210 /* If RT_USING_MEMHEAP_AS_HEAP is enabled, SDRAM is initialized to the heap */
211 rt_memheap_init(&_system_heap, "sdram", (void *)SDRAM_BANK_ADDR, SDRAM_SIZE);
212 #endif
213
214 return ret;
215 }
216 INIT_BOARD_EXPORT(rt_hw_sdram_init);
217
218 #ifdef DRV_DEBUG
219 #ifdef FINSH_USING_MSH
_sdram_test(void)220 static int _sdram_test(void)
221 {
222 rt_uint32_t i;
223 rt_uint32_t start_time;
224 rt_uint32_t time_cast;
225 #if SDRAM_DATA_WIDTH == EXMC_DMC_MEMORY_WIDTH_16BIT
226 const char data_width = 2;
227 rt_uint16_t data = 0;
228 #else
229 char data_width = 4;
230 rt_uint32_t data = 0;
231 #endif
232
233 /* write data */
234 LOG_D("writing the %ld bytes data, waiting....", SDRAM_SIZE);
235 start_time = rt_tick_get();
236 for (i = 0; i < SDRAM_SIZE / data_width; i++)
237 {
238 #if SDRAM_DATA_WIDTH == EXMC_DMC_MEMORY_WIDTH_16BIT
239 *(__IO uint16_t *)(SDRAM_BANK_ADDR + i * data_width) = (uint16_t)(i % 1000);
240 #else
241 *(__IO uint32_t *)(SDRAM_BANK_ADDR + i * data_width) = (uint32_t)(i % 1000);
242 #endif
243 }
244 time_cast = rt_tick_get() - start_time;
245 LOG_D("write data success, total time: %d.%03dS.", time_cast / RT_TICK_PER_SECOND,
246 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
247
248 /* read data */
249 LOG_D("start reading and verifying data, waiting....");
250 for (i = 0; i < SDRAM_SIZE / data_width; i++)
251 {
252 #if SDRAM_DATA_WIDTH == EXMC_DMC_MEMORY_WIDTH_16BIT
253 data = *(__IO uint16_t *)(SDRAM_BANK_ADDR + i * data_width);
254 if (data != i % 1000)
255 {
256 LOG_E("SDRAM test failed!");
257 break;
258 }
259 #else
260 data = *(__IO uint32_t *)(SDRAM_BANK_ADDR + i * data_width);
261 if (data != i % 1000)
262 {
263 LOG_E("SDRAM test failed!");
264 break;
265 }
266 #endif
267 }
268
269 if (i >= SDRAM_SIZE / data_width)
270 {
271 LOG_D("SDRAM test success!");
272 }
273
274 return RT_EOK;
275 }
276 MSH_CMD_EXPORT(_sdram_test, sdram test)
277 #endif /* FINSH_USING_MSH */
278 #endif /* DRV_DEBUG */
279 #endif /* BSP_USING_SDRAM */
280 #endif /* BSP_USING_EXMC */
281