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