1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-03-28     luobeihai    first version
9  */
10 
11 #include <board.h>
12 
13 #ifdef BSP_USING_SDRAM
14 #include "drv_sdram.h"
15 
16 #define DRV_DEBUG
17 #define LOG_TAG             "drv.sdram"
18 #include <drv_log.h>
19 
20 /* SDRAM GPIO Clock */
21 #define RCM_SDRAM_GPIO_PERIPH (RCM_APB2_PERIPH_AFIO  | \
22                                 RCM_APB2_PERIPH_GPIOB | \
23                                 RCM_APB2_PERIPH_GPIOC | \
24                                 RCM_APB2_PERIPH_GPIOD | \
25                                 RCM_APB2_PERIPH_GPIOE | \
26                                 RCM_APB2_PERIPH_GPIOF | \
27                                 RCM_APB2_PERIPH_GPIOG)
28 
29 /* SDRAM Peripheral Clock */
30 #define RCM_SDRAM_PERIPH (RCM_AHB_PERIPH_SMC)
31 
32 #ifdef RT_USING_MEMHEAP_AS_HEAP
33 static struct rt_memheap system_heap;
34 #endif
35 
36 /**
37  * @brief   SDRAM divider Number
38  */
39 typedef enum
40 {
41     RCM_DMC_DIV_1,
42     RCM_DMC_DIV_2,
43     RCM_DMC_DIV_4 = 3
44 } RCM_DMC_DIV_T;
45 
46 /**
47   * @brief  Configs the SDRAM clock prescaler
48   * @param  SDRAMDiv: Specifies the SDRAM clock prescaler from the DMC clock.
49   * @retval None
50   */
RCM_ConfigSDRAMCLK(RCM_DMC_DIV_T SDRAMDiv)51 static void RCM_ConfigSDRAMCLK(RCM_DMC_DIV_T SDRAMDiv)
52 {
53     RCM->CFG_B.SDRAMPSC = SDRAMDiv;
54 }
55 
56 /**
57   * @brief  sdram gpio init
58   * @param  None
59   * @retval None
60   */
SDRAM_GPIO_Init(void)61 static void SDRAM_GPIO_Init(void)
62 {
63     GPIO_Config_T gpioConfig;
64 
65     RCM_EnableAPB2PeriphClock(RCM_SDRAM_GPIO_PERIPH);
66 
67     /** SDRAM pins assignment */
68     /**
69      +-------------------------+--------------------------+--------------------------+
70      | PB10 <-> MMC_SDRAM_UDQM | PC10 <-> MMC_SDRAM_D8    | PD2  <-> MMC_SDRAM_D10   |
71      | PB11 <-> MMC_SDRAM_CKE  | PC11 <-> MMC_SDRAM_D9    | PD3  <-> MMC_SDRAM_D11   |
72      |                         |                          | PD4  <-> MMC_SDRAM_D12   |
73      |                         |                          | PD5  <-> MMC_SDRAM_D13   |
74      |                         |                          | PD6  <-> MMC_SDRAM_D14   |
75      +-------------------------+--------------------------+--------------------------+
76      | PE3  <-> MMC_SDRAM_D4   | PF0  <-> MMC_SDRAM_D7    | PG0  <-> MMC_SDRAM_A3    |
77      | PE5  <-> MMC_SDRAM_D5   | PF2  <-> MMC_SDRAM_NCS   | PG9  <-> MMC_SDRAM_D15   |
78      | PE6  <-> MMC_SDRAM_D6   | PF4  <-> MMC_SDRAM_NRAS  | PG12 <-> MMC_SDRAM_D0    |
79      | PE8  <-> MMC_SDRAM_A4   | PF5  <-> MMC_SDRAM_NCAS  | PG13 <-> MMC_SDRAM_D1    |
80      | PE9  <-> MMC_SDRAM_A5   | PF6  <-> MMC_SDRAM_NWE   | PG14 <-> MMC_SDRAM_D2    |
81      | PE10 <-> MMC_SDRAM_A6   | PF10 <-> MMC_SDRAM_LDQM  | PG15 <-> MMC_SDRAM_D3    |
82      | PE11 <-> MMC_SDRAM_A7   | PF11 <-> MMC_SDRAM_Bank  |                          |
83      | PE12 <-> MMC_SDRAM_A8   | PF12 <-> MMC_SDRAM_A10   |                          |
84      | PE13 <-> MMC_SDRAM_A9   | PF13 <-> MMC_SDRAM_A0    |                          |
85      | PE15 <-> MMC_SDRAM_CLK  | PF14 <-> MMC_SDRAM_A1    |                          |
86      |                         | PF15 <-> MMC_SDRAM_A2    |                          |
87      +-------------------------+--------------------------+--------------------------+
88     */
89 
90     gpioConfig.speed = GPIO_SPEED_50MHz;
91     gpioConfig.mode = GPIO_MODE_AF_PP;
92 
93     gpioConfig.pin = GPIO_PIN_10 | GPIO_PIN_11;
94     GPIO_Config(GPIOB, &gpioConfig);
95 
96     gpioConfig.pin = GPIO_PIN_10 | GPIO_PIN_11;
97     GPIO_Config(GPIOC, &gpioConfig);
98 
99     gpioConfig.pin = GPIO_PIN_2 | GPIO_PIN_3 |
100                      GPIO_PIN_4 | GPIO_PIN_5 |
101                      GPIO_PIN_6;
102     GPIO_Config(GPIOD, &gpioConfig);
103 
104     gpioConfig.pin = GPIO_PIN_3 | GPIO_PIN_5 |
105                      GPIO_PIN_6 | GPIO_PIN_8 |
106                      GPIO_PIN_9 | GPIO_PIN_10|
107                      GPIO_PIN_11 | GPIO_PIN_12 |
108                      GPIO_PIN_13 | GPIO_PIN_15 ;
109     GPIO_Config(GPIOE, &gpioConfig);
110 
111     gpioConfig.pin = GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_4 |
112                      GPIO_PIN_5 | GPIO_PIN_6 |
113                      GPIO_PIN_10 |GPIO_PIN_11 |
114                      GPIO_PIN_12 | GPIO_PIN_13|
115                      GPIO_PIN_14 | GPIO_PIN_15;
116     GPIO_Config(GPIOF, &gpioConfig);
117 
118     gpioConfig.pin = GPIO_PIN_0 | GPIO_PIN_9|
119                      GPIO_PIN_12 | GPIO_PIN_13 |
120                      GPIO_PIN_14 | GPIO_PIN_15;
121     GPIO_Config(GPIOG, &gpioConfig);
122 }
123 
124 /**
125   * @brief  sdram init
126   * @param  None
127   * @retval None
128   */
SDRAM_Init(void)129 static int SDRAM_Init(void)
130 {
131     int result = RT_EOK;
132 
133     DMC_Config_T dmc_init_config;
134     DMC_TimingConfig_T dmc_timing_config;
135 
136     /* Config the SDRAM clock prescaler */
137     RCM_ConfigSDRAMCLK(RCM_DMC_DIV_2);
138 
139     /* enable sdram clock */
140     RCM_EnableAHBPeriphClock(RCM_SDRAM_PERIPH);
141 
142     /* sdram gpio init */
143     SDRAM_GPIO_Init();
144 
145     /* dmc timing config */
146     dmc_timing_config.latencyCAS = DMC_CAS_LATENCY_3;        //!< Configure CAS latency period
147     dmc_timing_config.tARP       = DMC_AUTO_REFRESH_10;      //!< Configure auto refresh period
148     dmc_timing_config.tRAS       = DMC_RAS_MINIMUM_5;        //!< Configure line activation and precharging minimum time
149     dmc_timing_config.tCMD       = DMC_ATA_CMD_7;            //!< Configure active to active period
150     dmc_timing_config.tRCD       = DMC_DELAY_TIME_2;         //!< Configure RAS To CAS delay Time
151     dmc_timing_config.tRP        = DMC_PRECHARGE_2;          //!< Configure precharge period
152     dmc_timing_config.tWR        = DMC_NEXT_PRECHARGE_2;     //!< Configure time between the Last Data and The Next Precharge for write
153     dmc_timing_config.tXSR       = 6;                        //!< Configure XSR0
154     dmc_timing_config.tRFP       = 0xC3;                     //!< Configure refresh Cycle
155 
156 #if SDRAM_TARGET_BANK == 1
157     dmc_init_config.bankWidth     = DMC_BANK_WIDTH_1;        //!< Configure bank address width
158 #else
159     dmc_init_config.bankWidth     = DMC_BANK_WIDTH_2;        //!< Configure bank address width
160 #endif
161     dmc_init_config.clkPhase      = DMC_CLK_PHASE_REVERSE;   //!< Configure clock phase
162     dmc_init_config.rowWidth      = SDRAM_ROW_BITS;          //!< Configure row address width
163     dmc_init_config.colWidth      = SDRAM_COLUMN_BITS;       //!< Configure column address width
164     dmc_init_config.memorySize    = SDRAM_MEMORY_SIZE;
165     dmc_init_config.timing        = dmc_timing_config;
166 
167     DMC_Config(&dmc_init_config);
168     DMC_ConfigOpenBank(DMC_BANK_NUMBER_2);
169     DMC_EnableAccelerateModule();
170 
171     DMC_Enable();
172 
173     LOG_D("sdram clock: %d MHz\r\n", RCM_ReadSYSCLKFreq()/1000000/(RCM->CFG_B.SDRAMPSC + 1));
174     LOG_D("sdram init success, mapped at 0x%X, size is %d bytes, data width is %d", SDRAM_BANK_ADDR, SDRAM_SIZE, SDRAM_DATA_WIDTH);
175 
176 #ifdef RT_USING_MEMHEAP_AS_HEAP
177     /* If RT_USING_MEMHEAP_AS_HEAP is enabled, SDRAM is initialized to the heap */
178     rt_memheap_init(&system_heap, "sdram", (void *)SDRAM_BANK_ADDR, SDRAM_SIZE);
179 #endif
180 
181     return result;
182 }
183 INIT_BOARD_EXPORT(SDRAM_Init);
184 
185 #ifdef DRV_DEBUG
186 #ifdef FINSH_USING_MSH
sdram_test(void)187 int sdram_test(void)
188 {
189     int i = 0;
190     uint32_t start_time = 0, time_cast = 0;
191 #if SDRAM_DATA_WIDTH == 8
192     char data_width = 1;
193     uint8_t data = 0;
194 #elif SDRAM_DATA_WIDTH == 16
195     char data_width = 2;
196     uint16_t data = 0;
197 #else
198     char data_width = 4;
199     uint32_t data = 0;
200 #endif
201 
202     /* write data */
203     LOG_D("Writing the %ld bytes data, waiting....", SDRAM_SIZE);
204     start_time = rt_tick_get();
205     for (i = 0; i < SDRAM_SIZE / data_width; i++)
206     {
207 #if SDRAM_DATA_WIDTH == 8
208         *(__IO uint8_t *)(SDRAM_BANK_ADDR + i * data_width) = (uint8_t)(i % 100);
209 #elif SDRAM_DATA_WIDTH == 16
210         *(__IO uint16_t *)(SDRAM_BANK_ADDR + i * data_width) = (uint16_t)(i % 1000);
211 #else
212         *(__IO uint32_t *)(SDRAM_BANK_ADDR + i * data_width) = (uint32_t)(i % 1000);
213 #endif
214     }
215     time_cast = rt_tick_get() - start_time;
216     LOG_D("Write data success, total time: %d.%03dS.", time_cast / RT_TICK_PER_SECOND,
217           time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
218 
219     /* read data */
220     LOG_D("start Reading and verifying data, waiting....");
221     for (i = 0; i < SDRAM_SIZE / data_width; i++)
222     {
223 #if SDRAM_DATA_WIDTH == 8
224         data = *(__IO uint8_t *)(SDRAM_BANK_ADDR + i * data_width);
225         if (data != i % 100)
226         {
227             LOG_E("SDRAM test failed!");
228             break;
229         }
230 #elif SDRAM_DATA_WIDTH == 16
231         data = *(__IO uint16_t *)(SDRAM_BANK_ADDR + i * data_width);
232         if (data != i % 1000)
233         {
234             LOG_E("SDRAM test failed!");
235             break;
236         }
237 #else
238         data = *(__IO uint32_t *)(SDRAM_BANK_ADDR + i * data_width);
239         if (data != i % 1000)
240         {
241             LOG_E("SDRAM test failed!");
242             break;
243         }
244 #endif
245     }
246 
247     if (i >= SDRAM_SIZE / data_width)
248     {
249         LOG_D("SDRAM test success!");
250     }
251 
252     return RT_EOK;
253 }
254 MSH_CMD_EXPORT(sdram_test, sdram test)
255 #endif /* FINSH_USING_MSH */
256 #endif /* DRV_DEBUG */
257 #endif /* BSP_USING_SDRAM */
258