1 /*
2  * Copyright (c) 2015 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 /*
9  * COPYRIGHT(c) 2015 STMicroelectronics
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *   1. Redistributions of source code must retain the above copyright notice,
14  *      this list of conditions and the following disclaimer.
15  *   2. Redistributions in binary form must reproduce the above copyright notice,
16  *      this list of conditions and the following disclaimer in the documentation
17  *      and/or other materials provided with the distribution.
18  *   3. Neither the name of STMicroelectronics nor the names of its contributors
19  *      may be used to endorse or promote products derived from this software
20  *      without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  ******************************************************************************
34  */
35 
36 #include <lk/err.h>
37 #include <lk/debug.h>
38 #include <lk/trace.h>
39 #include <target.h>
40 #include <lk/compiler.h>
41 #include <dev/gpio.h>
42 #include <platform/stm32.h>
43 #include <platform/sdram.h>
44 
45 /*
46  * sdram initialization sequence, taken from
47  * STM32Cube_FW_F7_V1.1.0/Drivers/BSP
48  */
49 
50 /**
51   * @brief  SDRAM status structure definition
52   */
53 #define   SDRAM_OK         ((uint8_t)0x00)
54 #define   SDRAM_ERROR      ((uint8_t)0x01)
55 
56 /* SDRAM refresh counter (100Mhz SD clock) */
57 #define REFRESH_COUNT      ((uint32_t)0x0603)
58 
59 #define SDRAM_TIMEOUT      ((uint32_t)0xFFFF)
60 
61 /* DMA definitions for SDRAM DMA transfer */
62 #define __DMAx_CLK_ENABLE                 __HAL_RCC_DMA2_CLK_ENABLE
63 #define __DMAx_CLK_DISABLE                __HAL_RCC_DMA2_CLK_DISABLE
64 #define SDRAM_DMAx_CHANNEL                DMA_CHANNEL_0
65 #define SDRAM_DMAx_STREAM                 DMA2_Stream0
66 #define SDRAM_DMAx_IRQn                   DMA2_Stream0_IRQn
67 #define SDRAM_DMAx_IRQHandler             DMA2_Stream0_IRQHandler
68 
69 /**
70   * @brief  FMC SDRAM Mode definition register defines
71   */
72 #define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
73 #define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
74 #define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
75 #define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
76 #define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
77 #define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
78 #define SDRAM_MODEREG_CAS_LATENCY_1              ((uint16_t)0x0010)
79 #define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
80 #define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
81 #define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
82 #define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
83 #define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)
84 
85 static SDRAM_HandleTypeDef sdramHandle;
86 
87 /**
88   * @brief  Programs the SDRAM device.
89   * @param  RefreshCount: SDRAM refresh counter value
90   * @retval None
91   */
BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount,uint32_t CasLatency)92 static void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount,
93         uint32_t CasLatency) {
94     __IO uint32_t tmpmrd = 0;
95     FMC_SDRAM_CommandTypeDef Command;
96 
97     /* Step 1: Configure a clock configuration enable command */
98     Command.CommandMode            = FMC_SDRAM_CMD_CLK_ENABLE;
99     Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
100     Command.AutoRefreshNumber      = 1;
101     Command.ModeRegisterDefinition = 0;
102 
103     /* Send the command */
104     HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
105 
106     /* Step 2: Insert 100 us minimum delay */
107     spin(1000);
108 
109     /* Step 3: Configure a PALL (precharge all) command */
110     Command.CommandMode            = FMC_SDRAM_CMD_PALL;
111     Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
112     Command.AutoRefreshNumber      = 1;
113     Command.ModeRegisterDefinition = 0;
114 
115     /* Send the command */
116     HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
117 
118     /* Step 4: Configure an Auto Refresh command */
119     Command.CommandMode            = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
120     Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
121     Command.AutoRefreshNumber      = 8;
122     Command.ModeRegisterDefinition = 0;
123 
124     /* Send the command */
125     HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
126 
127     /* Step 5: Program the external memory mode register */
128     tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |\
129              SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |\
130              SDRAM_MODEREG_OPERATING_MODE_STANDARD |\
131              SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
132 
133     tmpmrd |= CasLatency;
134 
135     Command.CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;
136     Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
137     Command.AutoRefreshNumber      = 1;
138     Command.ModeRegisterDefinition = tmpmrd;
139 
140     /* Send the command */
141     HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
142 
143     /* Step 6: Set the refresh rate counter */
144     /* Set the device refresh rate */
145     HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount);
146 }
147 
GetMemoryWidth(sdram_config_t * config)148 static uint32_t GetMemoryWidth(sdram_config_t *config) {
149     switch (config->bus_width) {
150         case SDRAM_BUS_WIDTH_8 :
151             return FMC_SDRAM_MEM_BUS_WIDTH_8;
152         case SDRAM_BUS_WIDTH_16 :
153             return FMC_SDRAM_MEM_BUS_WIDTH_16;
154         case SDRAM_BUS_WIDTH_32 :
155             return FMC_SDRAM_MEM_BUS_WIDTH_32;
156     }
157     return 0;
158 }
159 
GetColumnBitsNumber(sdram_config_t * config)160 static uint32_t GetColumnBitsNumber(sdram_config_t *config) {
161     switch (config->col_bits_num) {
162         case SDRAM_COLUMN_BITS_8 :
163             return FMC_SDRAM_COLUMN_BITS_NUM_8;
164         case SDRAM_COLUMN_BITS_9 :
165             return FMC_SDRAM_COLUMN_BITS_NUM_9;
166         case SDRAM_COLUMN_BITS_10 :
167             return FMC_SDRAM_COLUMN_BITS_NUM_10;
168         case SDRAM_COLUMN_BITS_11 :
169             return FMC_SDRAM_COLUMN_BITS_NUM_11;
170     }
171     return 0;
172 }
173 
GetCasLatencyFMC(sdram_config_t * config)174 static uint32_t GetCasLatencyFMC(sdram_config_t *config) {
175     switch (config->cas_latency) {
176         case SDRAM_CAS_LATENCY_1 :
177             return FMC_SDRAM_CAS_LATENCY_1;
178         case SDRAM_CAS_LATENCY_2 :
179             return FMC_SDRAM_CAS_LATENCY_2;
180         case SDRAM_CAS_LATENCY_3 :
181             return FMC_SDRAM_CAS_LATENCY_3;
182     }
183     return 0;
184 }
185 
GetCasLatencyModeReg(sdram_config_t * config)186 static uint32_t GetCasLatencyModeReg(sdram_config_t *config) {
187     switch (config->cas_latency) {
188         case SDRAM_CAS_LATENCY_1 :
189             return SDRAM_MODEREG_CAS_LATENCY_1;
190         case SDRAM_CAS_LATENCY_2 :
191             return SDRAM_MODEREG_CAS_LATENCY_2;
192         case SDRAM_CAS_LATENCY_3 :
193             return SDRAM_MODEREG_CAS_LATENCY_3;
194     }
195     return 0;
196 }
197 
198 /**
199   * @brief  Initializes the SDRAM device.
200   * @retval SDRAM status
201   */
stm32_sdram_init(sdram_config_t * config)202 uint8_t stm32_sdram_init(sdram_config_t *config) {
203     static uint8_t sdramstatus = SDRAM_ERROR;
204     static DMA_HandleTypeDef dma_handle;
205 
206     /* SDRAM device configuration */
207     sdramHandle.Instance = FMC_SDRAM_DEVICE;
208 
209     /* Timing configuration for 100Mhz as SDRAM clock frequency (System clock is up to 200Mhz) */
210     FMC_SDRAM_TimingTypeDef Timing;
211     Timing.LoadToActiveDelay    = 2;
212     Timing.ExitSelfRefreshDelay = 7;
213     Timing.SelfRefreshTime      = 4;
214     Timing.RowCycleDelay        = 7;
215     Timing.WriteRecoveryTime    = 2;
216     Timing.RPDelay              = 2;
217     Timing.RCDDelay             = 2;
218 
219     sdramHandle.Init.SDBank             = FMC_SDRAM_BANK1;
220     sdramHandle.Init.ColumnBitsNumber   = GetColumnBitsNumber(config);
221     sdramHandle.Init.RowBitsNumber      = FMC_SDRAM_ROW_BITS_NUM_12;
222     sdramHandle.Init.MemoryDataWidth    = GetMemoryWidth(config);
223     sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
224     sdramHandle.Init.CASLatency         = GetCasLatencyFMC(config);
225     sdramHandle.Init.WriteProtection    = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
226     sdramHandle.Init.SDClockPeriod      = FMC_SDRAM_CLOCK_PERIOD_2;
227     sdramHandle.Init.ReadBurst          = FMC_SDRAM_RBURST_ENABLE;
228     sdramHandle.Init.ReadPipeDelay      = FMC_SDRAM_RPIPE_DELAY_0;
229 
230     /* Enable FMC clock */
231     __HAL_RCC_FMC_CLK_ENABLE();
232 
233     /* Enable chosen DMAx clock */
234     __DMAx_CLK_ENABLE();
235 
236     /* SDRAM GPIO initialization */
237     stm_sdram_GPIO_init();
238 
239     /* Configure common DMA parameters */
240     dma_handle.Init.Channel             = SDRAM_DMAx_CHANNEL;
241     dma_handle.Init.Direction           = DMA_MEMORY_TO_MEMORY;
242     dma_handle.Init.PeriphInc           = DMA_PINC_ENABLE;
243     dma_handle.Init.MemInc              = DMA_MINC_ENABLE;
244     dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
245     dma_handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
246     dma_handle.Init.Mode                = DMA_NORMAL;
247     dma_handle.Init.Priority            = DMA_PRIORITY_HIGH;
248     dma_handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
249     dma_handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
250     dma_handle.Init.MemBurst            = DMA_MBURST_SINGLE;
251     dma_handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;
252 
253     dma_handle.Instance = SDRAM_DMAx_STREAM;
254 
255     /* Associate the DMA handle */
256     __HAL_LINKDMA(&sdramHandle, hdma, dma_handle);
257 
258     /* Deinitialize the stream for new transfer */
259     HAL_DMA_DeInit(&dma_handle);
260 
261     /* Configure the DMA stream */
262     HAL_DMA_Init(&dma_handle);
263 
264 #if 0
265     /* NVIC configuration for DMA transfer complete interrupt */
266     HAL_NVIC_SetPriority(SDRAM_DMAx_IRQn, 5, 0);
267     HAL_NVIC_EnableIRQ(SDRAM_DMAx_IRQn);
268 #endif
269 
270     if (HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK) {
271         sdramstatus = SDRAM_ERROR;
272     } else {
273         sdramstatus = SDRAM_OK;
274     }
275 
276     /* SDRAM initialization sequence */
277     BSP_SDRAM_Initialization_sequence(REFRESH_COUNT,
278                                       GetCasLatencyModeReg(config));
279 
280     return sdramstatus;
281 }
282 
283 
284