1 | /* |
2 | * Copyright 2017-2020 NXP |
3 | * All rights reserved. |
4 | * |
5 | * SPDX-License-Identifier: BSD-3-Clause |
6 | */ |
7 | |
8 | #include "fsl_semc.h" |
9 | |
10 | /******************************************************************************* |
11 | * Definitions |
12 | ******************************************************************************/ |
13 | |
14 | /* Component ID definition, used by tools. */ |
15 | #ifndef FSL_COMPONENT_ID |
16 | #define FSL_COMPONENT_ID "platform.drivers.semc" |
17 | #endif |
18 | |
19 | /*! @brief Define macros for SEMC driver. */ |
20 | #define SEMC_IPCOMMANDDATASIZEBYTEMAX (4U) |
21 | #define SEMC_IPCOMMANDMAGICKEY (0xA55A) |
22 | #if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U) |
23 | #define SEMC_IOCR_PINMUXBITWIDTH (0x4UL) |
24 | #else |
25 | #define SEMC_IOCR_PINMUXBITWIDTH (0x3UL) |
26 | #endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */ |
27 | #define SEMC_IOCR_NAND_CE (4UL) |
28 | #define SEMC_IOCR_NOR_CE (5UL) |
29 | #define SEMC_IOCR_NOR_CE_A8 (2UL) |
30 | #define SEMC_IOCR_PSRAM_CE (6UL) |
31 | #define SEMC_IOCR_PSRAM_CE_A8 (3UL) |
32 | #define SEMC_IOCR_DBI_CSX (7UL) |
33 | #define SEMC_IOCR_DBI_CSX_A8 (4UL) |
34 | #define SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE (24U) |
35 | #define SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX (28U) |
36 | #define SEMC_BMCR0_TYPICAL_WQOS (5U) |
37 | #define SEMC_BMCR0_TYPICAL_WAGE (8U) |
38 | #define SEMC_BMCR0_TYPICAL_WSH (0x40U) |
39 | #define SEMC_BMCR0_TYPICAL_WRWS (0x10U) |
40 | #define SEMC_BMCR1_TYPICAL_WQOS (5U) |
41 | #define SEMC_BMCR1_TYPICAL_WAGE (8U) |
42 | #define SEMC_BMCR1_TYPICAL_WPH (0x60U) |
43 | #define SEMC_BMCR1_TYPICAL_WBR (0x40U) |
44 | #define SEMC_BMCR1_TYPICAL_WRWS (0x24U) |
45 | #define SEMC_STARTADDRESS (0x80000000UL) |
46 | #define SEMC_ENDADDRESS (0xDFFFFFFFUL) |
47 | #define SEMC_BR_MEMSIZE_MIN (4U) |
48 | #define SEMC_BR_MEMSIZE_OFFSET (2U) |
49 | #define SEMC_BR_MEMSIZE_MAX (4UL * 1024UL * 1024UL) |
50 | #define SEMC_SDRAM_MODESETCAL_OFFSET (4U) |
51 | #define SEMC_BR_REG_NUM (9U) |
52 | #define SEMC_BYTE_NUMBIT (8U) |
53 | /******************************************************************************* |
54 | * Prototypes |
55 | ******************************************************************************/ |
56 | /*! |
57 | * @brief Get instance number for SEMC module. |
58 | * |
59 | * @param base SEMC peripheral base address |
60 | */ |
61 | static uint32_t SEMC_GetInstance(SEMC_Type *base); |
62 | |
63 | /*! |
64 | * @brief Covert the input memory size to internal register set value. |
65 | * |
66 | * @param base SEMC peripheral base address |
67 | * @param size_kbytes SEMC memory size in unit of kbytes. |
68 | * @param sizeConverted SEMC converted memory size to 0 ~ 0x1F. |
69 | * @return Execution status. |
70 | */ |
71 | static status_t SEMC_CovertMemorySize(SEMC_Type *base, uint32_t size_kbytes, uint8_t *sizeConverted); |
72 | |
73 | /*! |
74 | * @brief Covert the external timing nanosecond to internal clock cycle. |
75 | * |
76 | * @param time_ns SEMC external time interval in unit of nanosecond. |
77 | * @param clkSrc_Hz SEMC clock source frequency. |
78 | * @return The changed internal clock cycle. |
79 | */ |
80 | static uint8_t SEMC_ConvertTiming(uint32_t time_ns, uint32_t clkSrc_Hz); |
81 | |
82 | /*! |
83 | * @brief Configure IP command. |
84 | * |
85 | * @param base SEMC peripheral base address. |
86 | * @param size_bytes SEMC IP command data size. |
87 | * @return Execution status. |
88 | */ |
89 | static status_t SEMC_ConfigureIPCommand(SEMC_Type *base, uint8_t size_bytes); |
90 | |
91 | /*! |
92 | * @brief Check if the IP command has finished. |
93 | * |
94 | * @param base SEMC peripheral base address. |
95 | * @return Execution status. |
96 | */ |
97 | static status_t SEMC_IsIPCommandDone(SEMC_Type *base); |
98 | |
99 | /******************************************************************************* |
100 | * Variables |
101 | ******************************************************************************/ |
102 | |
103 | #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
104 | /*! @brief Pointers to SEMC clocks for each instance. */ |
105 | static const clock_ip_name_t s_semcClock[FSL_FEATURE_SOC_SEMC_COUNT] = SEMC_CLOCKS; |
106 | #if (defined(SEMC_EXSC_CLOCKS)) |
107 | static const clock_ip_name_t s_semcExtClock[FSL_FEATURE_SOC_SEMC_COUNT] = SEMC_EXSC_CLOCKS; |
108 | #endif /* SEMC_EXSC_CLOCKS */ |
109 | #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
110 | |
111 | /*! @brief Pointers to SEMC bases for each instance. */ |
112 | static SEMC_Type *const s_semcBases[] = SEMC_BASE_PTRS; |
113 | /******************************************************************************* |
114 | * Code |
115 | ******************************************************************************/ |
116 | static uint32_t SEMC_GetInstance(SEMC_Type *base) |
117 | { |
118 | uint32_t instance; |
119 | |
120 | /* Find the instance index from base address mappings. */ |
121 | for (instance = 0; instance < ARRAY_SIZE(s_semcBases); instance++) |
122 | { |
123 | if (s_semcBases[instance] == base) |
124 | { |
125 | break; |
126 | } |
127 | } |
128 | |
129 | assert(instance < ARRAY_SIZE(s_semcBases)); |
130 | |
131 | return instance; |
132 | } |
133 | |
134 | static status_t SEMC_CovertMemorySize(SEMC_Type *base, uint32_t size_kbytes, uint8_t *sizeConverted) |
135 | { |
136 | assert(sizeConverted != NULL); |
137 | uint32_t memsize; |
138 | status_t status = kStatus_Success; |
139 | |
140 | if ((size_kbytes < SEMC_BR_MEMSIZE_MIN) || (size_kbytes > SEMC_BR_MEMSIZE_MAX)) |
141 | { |
142 | status = kStatus_SEMC_InvalidMemorySize; |
143 | } |
144 | else |
145 | { |
146 | *sizeConverted = 0U; |
147 | memsize = size_kbytes / 8U; |
148 | while (memsize != 0x00U) |
149 | { |
150 | memsize >>= 1U; |
151 | (*sizeConverted)++; |
152 | } |
153 | } |
154 | |
155 | return status; |
156 | } |
157 | |
158 | static uint8_t SEMC_ConvertTiming(uint32_t time_ns, uint32_t clkSrc_Hz) |
159 | { |
160 | assert(clkSrc_Hz != 0x00U); |
161 | |
162 | uint8_t clockCycles = 0; |
163 | uint32_t tClk_ps; |
164 | |
165 | clkSrc_Hz /= 1000000U; |
166 | /* Using ps for high resolution */ |
167 | tClk_ps = 1000000U / clkSrc_Hz; |
168 | |
169 | while (tClk_ps * clockCycles < time_ns * 1000U) |
170 | { |
171 | clockCycles++; |
172 | } |
173 | |
174 | return (clockCycles == 0x00U) ? clockCycles : (clockCycles - 0x01U); |
175 | } |
176 | |
177 | static status_t SEMC_ConfigureIPCommand(SEMC_Type *base, uint8_t size_bytes) |
178 | { |
179 | status_t status = kStatus_Success; |
180 | |
181 | if ((size_bytes > SEMC_IPCOMMANDDATASIZEBYTEMAX) || (size_bytes == 0x00U)) |
182 | { |
183 | status = kStatus_SEMC_InvalidIpcmdDataSize; |
184 | } |
185 | else |
186 | { |
187 | /* Set data size. */ |
188 | /* Note: It is better to set data size as the device data port width when transferring |
189 | * device command data. But for device memory data transfer, it can be set freely. |
190 | * Note: If the data size is greater than data port width, for example, datsz = 4, data port = 16bit, |
191 | * then the 4-byte data transfer will be split into two 2-byte transfers, the slave address |
192 | * will be switched automatically according to connected device type*/ |
193 | base->IPCR1 = SEMC_IPCR1_DATSZ(size_bytes); |
194 | /* Clear data size. */ |
195 | base->IPCR2 = 0; |
196 | /* Set data size. */ |
197 | if (size_bytes < 4U) |
198 | { |
199 | base->IPCR2 |= SEMC_IPCR2_BM3_MASK; |
200 | } |
201 | if (size_bytes < 3U) |
202 | { |
203 | base->IPCR2 |= SEMC_IPCR2_BM2_MASK; |
204 | } |
205 | if (size_bytes < 2U) |
206 | { |
207 | base->IPCR2 |= SEMC_IPCR2_BM1_MASK; |
208 | } |
209 | } |
210 | |
211 | return status; |
212 | } |
213 | |
214 | static status_t SEMC_IsIPCommandDone(SEMC_Type *base) |
215 | { |
216 | status_t status = kStatus_Success; |
217 | |
218 | /* Poll status bit till command is done*/ |
219 | while ((base->INTR & (uint32_t)SEMC_INTR_IPCMDDONE_MASK) == 0x00U) |
220 | { |
221 | }; |
222 | |
223 | /* Clear status bit */ |
224 | base->INTR |= SEMC_INTR_IPCMDDONE_MASK; |
225 | |
226 | /* Check error status */ |
227 | if ((base->INTR & (uint32_t)SEMC_INTR_IPCMDERR_MASK) != 0x00U) |
228 | { |
229 | base->INTR |= SEMC_INTR_IPCMDERR_MASK; |
230 | status = kStatus_SEMC_IpCommandExecutionError; |
231 | } |
232 | |
233 | return status; |
234 | } |
235 | |
236 | /*! |
237 | * brief Gets the SEMC default basic configuration structure. |
238 | * |
239 | * The purpose of this API is to get the default SEMC |
240 | * configure structure for SEMC_Init(). User may use the initialized |
241 | * structure unchanged in SEMC_Init(), or modify some fields of the |
242 | * structure before calling SEMC_Init(). |
243 | * Example: |
244 | code |
245 | semc_config_t config; |
246 | SEMC_GetDefaultConfig(&config); |
247 | endcode |
248 | * param config The SEMC configuration structure pointer. |
249 | */ |
250 | void SEMC_GetDefaultConfig(semc_config_t *config) |
251 | { |
252 | assert(config != NULL); |
253 | |
254 | /* Initializes the configure structure to zero. */ |
255 | (void)memset(config, 0, sizeof(*config)); |
256 | |
257 | config->queueWeight.queueaEnable = true; |
258 | semc_queuea_weight_struct_t *queueaWeight = &(config->queueWeight.queueaWeight.queueaConfig); |
259 | config->queueWeight.queuebEnable = true; |
260 | semc_queueb_weight_struct_t *queuebWeight = &(config->queueWeight.queuebWeight.queuebConfig); |
261 | |
262 | /* Get default settings. */ |
263 | config->dqsMode = kSEMC_Loopbackinternal; |
264 | config->cmdTimeoutCycles = 0xFF; |
265 | config->busTimeoutCycles = 0x1F; |
266 | |
267 | queueaWeight->qos = SEMC_BMCR0_TYPICAL_WQOS; |
268 | queueaWeight->aging = SEMC_BMCR0_TYPICAL_WAGE; |
269 | queueaWeight->slaveHitSwith = SEMC_BMCR0_TYPICAL_WSH; |
270 | queueaWeight->slaveHitNoswitch = SEMC_BMCR0_TYPICAL_WRWS; |
271 | queuebWeight->qos = SEMC_BMCR1_TYPICAL_WQOS; |
272 | queuebWeight->aging = SEMC_BMCR1_TYPICAL_WAGE; |
273 | queuebWeight->slaveHitSwith = SEMC_BMCR1_TYPICAL_WRWS; |
274 | queuebWeight->weightPagehit = SEMC_BMCR1_TYPICAL_WPH; |
275 | queuebWeight->bankRotation = SEMC_BMCR1_TYPICAL_WBR; |
276 | } |
277 | |
278 | /*! |
279 | * brief Initializes SEMC. |
280 | * This function ungates the SEMC clock and initializes SEMC. |
281 | * This function must be called before calling any other SEMC driver functions. |
282 | * |
283 | * param base SEMC peripheral base address. |
284 | * param configure The SEMC configuration structure pointer. |
285 | */ |
286 | void SEMC_Init(SEMC_Type *base, semc_config_t *configure) |
287 | { |
288 | assert(configure != NULL); |
289 | |
290 | uint8_t index = 0; |
291 | |
292 | #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
293 | /* Un-gate sdram controller clock. */ |
294 | CLOCK_EnableClock(s_semcClock[SEMC_GetInstance(base)]); |
295 | #if (defined(SEMC_EXSC_CLOCKS)) |
296 | CLOCK_EnableClock(s_semcExtClock[SEMC_GetInstance(base)]); |
297 | #endif /* SEMC_EXSC_CLOCKS */ |
298 | #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
299 | |
300 | /* Initialize all BR to zero due to the default base address set. */ |
301 | for (index = 0; index < SEMC_BR_REG_NUM; index++) |
302 | { |
303 | base->BR[index] = 0; |
304 | } |
305 | |
306 | /* Software reset for SEMC internal logical . */ |
307 | base->MCR = SEMC_MCR_SWRST_MASK; |
308 | while ((base->MCR & (uint32_t)SEMC_MCR_SWRST_MASK) != 0x00U) |
309 | { |
310 | } |
311 | |
312 | /* Configure, disable module first. */ |
313 | base->MCR |= SEMC_MCR_MDIS_MASK | SEMC_MCR_BTO(configure->busTimeoutCycles) | |
314 | SEMC_MCR_CTO(configure->cmdTimeoutCycles) | SEMC_MCR_DQSMD(configure->dqsMode); |
315 | |
316 | if (configure->queueWeight.queueaEnable == true) |
317 | { |
318 | /* Configure Queue A for AXI bus access to SDRAM, NAND, NOR, SRAM and DBI slaves.*/ |
319 | base->BMCR0 = (uint32_t)(configure->queueWeight.queueaWeight.queueaValue); |
320 | } |
321 | else |
322 | { |
323 | base->BMCR0 = 0x00U; |
324 | } |
325 | |
326 | if (configure->queueWeight.queuebEnable == true) |
327 | { |
328 | /* Configure Queue B for AXI bus access to SDRAM slave. */ |
329 | base->BMCR1 = (uint32_t)(configure->queueWeight.queuebWeight.queuebValue); |
330 | } |
331 | else |
332 | { |
333 | base->BMCR1 = 0x00U; |
334 | } |
335 | |
336 | /* Enable SEMC. */ |
337 | base->MCR &= ~SEMC_MCR_MDIS_MASK; |
338 | } |
339 | |
340 | /*! |
341 | * brief Deinitializes the SEMC module and gates the clock. |
342 | * This function gates the SEMC clock. As a result, the SEMC |
343 | * module doesn't work after calling this function. |
344 | * |
345 | * param base SEMC peripheral base address. |
346 | */ |
347 | void SEMC_Deinit(SEMC_Type *base) |
348 | { |
349 | /* Disable module. Check there is no pending command before disable module. */ |
350 | while ((base->STS0 & (uint32_t)SEMC_STS0_IDLE_MASK) == 0x00U) |
351 | { |
352 | ; |
353 | } |
354 | |
355 | base->MCR |= SEMC_MCR_MDIS_MASK | SEMC_MCR_SWRST_MASK; |
356 | |
357 | #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
358 | /* Disable SDRAM clock. */ |
359 | CLOCK_DisableClock(s_semcClock[SEMC_GetInstance(base)]); |
360 | #if (defined(SEMC_EXSC_CLOCKS)) |
361 | CLOCK_DisableClock(s_semcExtClock[SEMC_GetInstance(base)]); |
362 | #endif /* SEMC_EXSC_CLOCKS */ |
363 | #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
364 | } |
365 | |
366 | /*! |
367 | * brief Configures SDRAM controller in SEMC. |
368 | * |
369 | * param base SEMC peripheral base address. |
370 | * param cs The chip selection. |
371 | * param config The sdram configuration. |
372 | * param clkSrc_Hz The SEMC clock frequency. |
373 | */ |
374 | status_t SEMC_ConfigureSDRAM(SEMC_Type *base, semc_sdram_cs_t cs, semc_sdram_config_t *config, uint32_t clkSrc_Hz) |
375 | { |
376 | assert(config != NULL); |
377 | assert(clkSrc_Hz > 0x00U); |
378 | assert(config->refreshBurstLen > 0x00U); |
379 | |
380 | uint8_t memsize; |
381 | status_t result = kStatus_Success; |
382 | uint16_t prescale = (uint16_t)(config->tPrescalePeriod_Ns / 16U / (1000000000U / clkSrc_Hz)); |
383 | uint32_t refresh; |
384 | uint32_t urgentRef; |
385 | uint32_t idle; |
386 | uint32_t mode; |
387 | uint32_t timing; |
388 | |
389 | if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) |
390 | { |
391 | return kStatus_SEMC_InvalidBaseAddress; |
392 | } |
393 | |
394 | if (config->csxPinMux == kSEMC_MUXA8) |
395 | { |
396 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
397 | } |
398 | |
399 | if (prescale > 256U) |
400 | { |
401 | return kStatus_SEMC_InvalidTimerSetting; |
402 | } |
403 | |
404 | refresh = config->refreshPeriod_nsPerRow / config->tPrescalePeriod_Ns; |
405 | urgentRef = config->refreshUrgThreshold / config->tPrescalePeriod_Ns; |
406 | idle = config->tIdleTimeout_Ns / config->tPrescalePeriod_Ns; |
407 | |
408 | uint32_t iocReg = base->IOCR & (~(SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->csxPinMux)); |
409 | |
410 | /* Base control. */ |
411 | result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); |
412 | if (result != kStatus_Success) |
413 | { |
414 | return result; |
415 | } |
416 | |
417 | base->BR[cs] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; |
418 | |
419 | #if defined(FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT) && (FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT) |
420 | if (kSEMC_SdramColunm_8bit == config->columnAddrBitNum) |
421 | { |
422 | base->SDRAMCR0 = SEMC_SDRAMCR0_PS(config->portSize) | SEMC_SDRAMCR0_BL(config->burstLen) | |
423 | SEMC_SDRAMCR0_COL8(true) | SEMC_SDRAMCR0_CL(config->casLatency); |
424 | } |
425 | else |
426 | #endif /* FSL_FEATURE_SEMC_SDRAM_SUPPORT_COLUMN_ADDRESS_8BIT */ |
427 | { |
428 | base->SDRAMCR0 = SEMC_SDRAMCR0_PS(config->portSize) | SEMC_SDRAMCR0_BL(config->burstLen) | |
429 | SEMC_SDRAMCR0_COL(config->columnAddrBitNum) | SEMC_SDRAMCR0_CL(config->casLatency); |
430 | } |
431 | |
432 | /* IOMUX setting. */ |
433 | if (cs != kSEMC_SDRAM_CS0) |
434 | { |
435 | base->IOCR = iocReg | ((uint32_t)cs << (uint32_t)config->csxPinMux); |
436 | } |
437 | |
438 | base->IOCR &= ~SEMC_IOCR_MUX_A8_MASK; |
439 | |
440 | #if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) |
441 | uint32_t tempDelayChain = base->DCCR; |
442 | |
443 | tempDelayChain &= ~(SEMC_DCCR_SDRAMVAL_MASK | SEMC_DCCR_SDRAMEN_MASK); |
444 | /* Configure delay chain. */ |
445 | base->DCCR = tempDelayChain | SEMC_DCCR_SDRAMVAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_SDRAMEN_MASK; |
446 | #endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */ |
447 | |
448 | timing = SEMC_SDRAMCR1_PRE2ACT(SEMC_ConvertTiming(config->tPrecharge2Act_Ns, clkSrc_Hz)); |
449 | timing |= SEMC_SDRAMCR1_ACT2RW(SEMC_ConvertTiming(config->tAct2ReadWrite_Ns, clkSrc_Hz)); |
450 | timing |= SEMC_SDRAMCR1_RFRC(SEMC_ConvertTiming(config->tRefreshRecovery_Ns, clkSrc_Hz)); |
451 | timing |= SEMC_SDRAMCR1_WRC(SEMC_ConvertTiming(config->tWriteRecovery_Ns, clkSrc_Hz)); |
452 | timing |= SEMC_SDRAMCR1_CKEOFF(SEMC_ConvertTiming(config->tCkeOff_Ns, clkSrc_Hz)); |
453 | timing |= SEMC_SDRAMCR1_ACT2PRE(SEMC_ConvertTiming(config->tAct2Prechage_Ns, clkSrc_Hz)); |
454 | /* SDRAMCR1 timing setting. */ |
455 | base->SDRAMCR1 = timing; |
456 | |
457 | timing = SEMC_SDRAMCR2_SRRC(SEMC_ConvertTiming(config->tSelfRefRecovery_Ns, clkSrc_Hz)); |
458 | timing |= SEMC_SDRAMCR2_REF2REF(SEMC_ConvertTiming(config->tRefresh2Refresh_Ns, clkSrc_Hz)); |
459 | timing |= SEMC_SDRAMCR2_ACT2ACT(SEMC_ConvertTiming(config->tAct2Act_Ns, clkSrc_Hz)) | SEMC_SDRAMCR2_ITO(idle); |
460 | /* SDRAMCR2 timing setting. */ |
461 | base->SDRAMCR2 = timing; |
462 | |
463 | /* SDRAMCR3 timing setting. */ |
464 | base->SDRAMCR3 = SEMC_SDRAMCR3_REBL((uint32_t)config->refreshBurstLen - 1UL) | |
465 | /* N * 16 * 1s / clkSrc_Hz = config->tPrescalePeriod_Ns */ |
466 | SEMC_SDRAMCR3_PRESCALE(prescale) | SEMC_SDRAMCR3_RT(refresh - 1UL) | SEMC_SDRAMCR3_UT(urgentRef); |
467 | |
468 | SEMC->IPCR1 = 0x2U; |
469 | SEMC->IPCR2 = 0U; |
470 | |
471 | result = |
472 | SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_Prechargeall, 0, NULL); |
473 | if (result != kStatus_Success) |
474 | { |
475 | return result; |
476 | } |
477 | result = |
478 | SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_AutoRefresh, 0, NULL); |
479 | if (result != kStatus_Success) |
480 | { |
481 | return result; |
482 | } |
483 | result = |
484 | SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_AutoRefresh, 0, NULL); |
485 | if (result != kStatus_Success) |
486 | { |
487 | return result; |
488 | } |
489 | /* Mode setting value. */ |
490 | mode = (uint32_t)config->burstLen | (((uint32_t)config->casLatency) << SEMC_SDRAM_MODESETCAL_OFFSET); |
491 | result = |
492 | SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_Modeset, mode, NULL); |
493 | if (result != kStatus_Success) |
494 | { |
495 | return result; |
496 | } |
497 | /* Enables refresh */ |
498 | base->SDRAMCR3 |= SEMC_SDRAMCR3_REN_MASK; |
499 | |
500 | return kStatus_Success; |
501 | } |
502 | |
503 | /*! |
504 | * brief Configures NAND controller in SEMC. |
505 | * |
506 | * param base SEMC peripheral base address. |
507 | * param config The nand configuration. |
508 | * param clkSrc_Hz The SEMC clock frequency. |
509 | */ |
510 | status_t SEMC_ConfigureNAND(SEMC_Type *base, semc_nand_config_t *config, uint32_t clkSrc_Hz) |
511 | { |
512 | assert(config != NULL); |
513 | assert(config->timingConfig != NULL); |
514 | |
515 | uint8_t memsize; |
516 | status_t result; |
517 | uint32_t timing; |
518 | |
519 | if ((config->axiAddress < SEMC_STARTADDRESS) || (config->axiAddress > SEMC_ENDADDRESS)) |
520 | { |
521 | return kStatus_SEMC_InvalidBaseAddress; |
522 | } |
523 | |
524 | if (config->cePinMux == kSEMC_MUXRDY) |
525 | { |
526 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
527 | } |
528 | |
529 | /* Disable SEMC module during configuring control registers. */ |
530 | base->MCR |= SEMC_MCR_MDIS_MASK; |
531 | |
532 | uint32_t iocReg = |
533 | base->IOCR & (~((SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->cePinMux) | SEMC_IOCR_MUX_RDY_MASK)); |
534 | |
535 | /* Base control. */ |
536 | if (config->rdyactivePolarity == kSEMC_RdyActivehigh) |
537 | { |
538 | base->MCR |= SEMC_MCR_WPOL1_MASK; |
539 | } |
540 | else |
541 | { |
542 | base->MCR &= ~SEMC_MCR_WPOL1_MASK; |
543 | } |
544 | result = SEMC_CovertMemorySize(base, config->axiMemsize_kbytes, &memsize); |
545 | if (result != kStatus_Success) |
546 | { |
547 | return result; |
548 | } |
549 | base->BR[4] = (config->axiAddress & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; |
550 | |
551 | result = SEMC_CovertMemorySize(base, config->ipgMemsize_kbytes, &memsize); |
552 | if (result != kStatus_Success) |
553 | { |
554 | return result; |
555 | } |
556 | base->BR[8] = (config->ipgAddress & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; |
557 | |
558 | /* IOMUX setting. */ |
559 | if ((uint32_t)config->cePinMux != 0x00U) |
560 | { |
561 | base->IOCR = iocReg | (SEMC_IOCR_NAND_CE << (uint32_t)config->cePinMux); |
562 | } |
563 | else |
564 | { |
565 | base->IOCR = iocReg | (1UL << (uint32_t)config->cePinMux); |
566 | } |
567 | |
568 | base->NANDCR0 = SEMC_NANDCR0_PS(config->portSize) | SEMC_NANDCR0_BL(config->burstLen) | |
569 | SEMC_NANDCR0_EDO(config->edoModeEnabled) | SEMC_NANDCR0_COL(config->columnAddrBitNum); |
570 | |
571 | timing = SEMC_NANDCR1_CES(SEMC_ConvertTiming(config->timingConfig->tCeSetup_Ns, clkSrc_Hz)); |
572 | timing |= SEMC_NANDCR1_CEH(SEMC_ConvertTiming(config->timingConfig->tCeHold_Ns, clkSrc_Hz)); |
573 | timing |= SEMC_NANDCR1_WEL(SEMC_ConvertTiming(config->timingConfig->tWeLow_Ns, clkSrc_Hz)); |
574 | timing |= SEMC_NANDCR1_WEH(SEMC_ConvertTiming(config->timingConfig->tWeHigh_Ns, clkSrc_Hz)); |
575 | timing |= SEMC_NANDCR1_REL(SEMC_ConvertTiming(config->timingConfig->tReLow_Ns, clkSrc_Hz)); |
576 | timing |= SEMC_NANDCR1_REH(SEMC_ConvertTiming(config->timingConfig->tReHigh_Ns, clkSrc_Hz)); |
577 | timing |= SEMC_NANDCR1_TA(SEMC_ConvertTiming(config->timingConfig->tTurnAround_Ns, clkSrc_Hz)); |
578 | timing |= SEMC_NANDCR1_CEITV(SEMC_ConvertTiming(config->timingConfig->tCeInterval_Ns, clkSrc_Hz)); |
579 | /* NANDCR1 timing setting. */ |
580 | base->NANDCR1 = timing; |
581 | |
582 | timing = SEMC_NANDCR2_TWHR(SEMC_ConvertTiming(config->timingConfig->tWehigh2Relow_Ns, clkSrc_Hz)); |
583 | timing |= SEMC_NANDCR2_TRHW(SEMC_ConvertTiming(config->timingConfig->tRehigh2Welow_Ns, clkSrc_Hz)); |
584 | timing |= SEMC_NANDCR2_TADL(SEMC_ConvertTiming(config->timingConfig->tAle2WriteStart_Ns, clkSrc_Hz)); |
585 | timing |= SEMC_NANDCR2_TRR(SEMC_ConvertTiming(config->timingConfig->tReady2Relow_Ns, clkSrc_Hz)); |
586 | timing |= SEMC_NANDCR2_TWB(SEMC_ConvertTiming(config->timingConfig->tWehigh2Busy_Ns, clkSrc_Hz)); |
587 | |
588 | /* NANDCR2 timing setting. */ |
589 | base->NANDCR2 = timing; |
590 | |
591 | /* NANDCR3 timing setting. */ |
592 | base->NANDCR3 = (uint32_t)config->arrayAddrOption; |
593 | |
594 | /* Enables SEMC module after configuring control registers completely. */ |
595 | base->MCR &= ~SEMC_MCR_MDIS_MASK; |
596 | |
597 | return kStatus_Success; |
598 | } |
599 | |
600 | /*! |
601 | * brief Configures NOR controller in SEMC. |
602 | * |
603 | * param base SEMC peripheral base address. |
604 | * param config The nor configuration. |
605 | * param clkSrc_Hz The SEMC clock frequency. |
606 | */ |
607 | status_t SEMC_ConfigureNOR(SEMC_Type *base, semc_nor_config_t *config, uint32_t clkSrc_Hz) |
608 | { |
609 | assert(config != NULL); |
610 | |
611 | uint8_t memsize; |
612 | status_t result; |
613 | uint32_t timing; |
614 | |
615 | if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) |
616 | { |
617 | return kStatus_SEMC_InvalidBaseAddress; |
618 | } |
619 | |
620 | uint32_t iocReg = base->IOCR & (~(SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->cePinMux)); |
621 | uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ? |
622 | (SEMC_IOCR_NOR_CE - 1U) : |
623 | ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_NOR_CE_A8 : SEMC_IOCR_NOR_CE); |
624 | |
625 | /* IOMUX setting. */ |
626 | base->IOCR = iocReg | (muxCe << (uint32_t)config->cePinMux); |
627 | /* Address bit setting. */ |
628 | if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE) |
629 | { |
630 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1U)) |
631 | { |
632 | /* Address bit 24 (A24) */ |
633 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX0_MASK; |
634 | if (config->cePinMux == kSEMC_MUXCSX0) |
635 | { |
636 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
637 | } |
638 | } |
639 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 2U)) |
640 | { |
641 | /* Address bit 25 (A25) */ |
642 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX1_MASK; |
643 | if (config->cePinMux == kSEMC_MUXCSX1) |
644 | { |
645 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
646 | } |
647 | } |
648 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 3U)) |
649 | { |
650 | /* Address bit 26 (A26) */ |
651 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX2_MASK; |
652 | if (config->cePinMux == kSEMC_MUXCSX2) |
653 | { |
654 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
655 | } |
656 | } |
657 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 4U)) |
658 | { |
659 | if (config->addr27 == kSEMC_NORA27_MUXCSX3) |
660 | { |
661 | /* Address bit 27 (A27) */ |
662 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX3_MASK; |
663 | } |
664 | else if (config->addr27 == kSEMC_NORA27_MUXRDY) |
665 | { |
666 | base->IOCR |= SEMC_IOCR_MUX_RDY_MASK; |
667 | } |
668 | else |
669 | { |
670 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
671 | } |
672 | if (config->cePinMux == kSEMC_MUXCSX3) |
673 | { |
674 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
675 | } |
676 | } |
677 | if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX) |
678 | { |
679 | return kStatus_SEMC_InvalidAddressPortWidth; |
680 | } |
681 | } |
682 | |
683 | /* Base control. */ |
684 | if (config->rdyactivePolarity == kSEMC_RdyActivehigh) |
685 | { |
686 | base->MCR |= SEMC_MCR_WPOL0_MASK; |
687 | } |
688 | else |
689 | { |
690 | base->MCR &= ~SEMC_MCR_WPOL0_MASK; |
691 | } |
692 | result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); |
693 | if (result != kStatus_Success) |
694 | { |
695 | return result; |
696 | } |
697 | base->BR[5] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; |
698 | base->NORCR0 = SEMC_NORCR0_PS(config->portSize) | SEMC_NORCR0_BL(config->burstLen) | |
699 | SEMC_NORCR0_AM(config->addrMode) | SEMC_NORCR0_ADVP(config->advActivePolarity) | |
700 | SEMC_NORCR0_COL(config->columnAddrBitNum); |
701 | |
702 | #if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) |
703 | uint32_t tempDelayChain = base->DCCR; |
704 | |
705 | tempDelayChain &= ~(SEMC_DCCR_NORVAL_MASK | SEMC_DCCR_NOREN_MASK); |
706 | /* Configure delay chain. */ |
707 | base->DCCR = tempDelayChain | SEMC_DCCR_NORVAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_NOREN_MASK; |
708 | #endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */ |
709 | |
710 | timing = SEMC_NORCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz)); |
711 | timing |= SEMC_NORCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz)); |
712 | timing |= SEMC_NORCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz)); |
713 | timing |= SEMC_NORCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz)); |
714 | timing |= SEMC_NORCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz)); |
715 | timing |= SEMC_NORCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz)); |
716 | timing |= SEMC_NORCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz)); |
717 | timing |= SEMC_NORCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz)); |
718 | |
719 | /* NORCR1 timing setting. */ |
720 | base->NORCR1 = timing; |
721 | |
722 | timing = SEMC_NORCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz)); |
723 | #if defined(FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) |
724 | timing |= SEMC_NORCR2_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz)); |
725 | #endif /* FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME */ |
726 | #if defined(FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) |
727 | timing |= SEMC_NORCR2_WDH(SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz)); |
728 | #endif /* FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME */ |
729 | timing |= SEMC_NORCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz)); |
730 | timing |= SEMC_NORCR2_AWDH((uint32_t)SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz) + 0x01UL); |
731 | #if defined(FSL_FEATURE_SEMC_HAS_NOR_LC_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_LC_TIME) |
732 | timing |= SEMC_NORCR2_LC(config->latencyCount); |
733 | #endif |
734 | #if defined(FSL_FEATURE_SEMC_HAS_NOR_RD_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_RD_TIME) |
735 | timing |= SEMC_NORCR2_RD((uint32_t)config->readCycle - 0x01UL); |
736 | #endif |
737 | |
738 | /* NORCR2 timing setting. */ |
739 | base->NORCR2 = timing; |
740 | |
741 | return SEMC_ConfigureIPCommand(base, ((uint8_t)config->portSize + 1U)); |
742 | } |
743 | |
744 | /*! |
745 | * brief Configures SRAM controller in SEMC, which can be used only for specific chip selection CS0. |
746 | * |
747 | * param base SEMC peripheral base address. |
748 | * param config The sram configuration. |
749 | * param clkSrc_Hz The SEMC clock frequency. |
750 | */ |
751 | status_t SEMC_ConfigureSRAM(SEMC_Type *base, semc_sram_config_t *config, uint32_t clkSrc_Hz) |
752 | { |
753 | return SEMC_ConfigureSRAMWithChipSelection(base, kSEMC_SRAM_CS0, config, clkSrc_Hz); |
754 | } |
755 | |
756 | /*! |
757 | * brief Configures SRAM controller in SEMC, which can be used up to four chip selections CS0/CS1/CS2/CS3.. |
758 | * |
759 | * param base SEMC peripheral base address. |
760 | * param cs The chip selection. |
761 | * param config The sram configuration. |
762 | * param clkSrc_Hz The SEMC clock frequency. |
763 | */ |
764 | status_t SEMC_ConfigureSRAMWithChipSelection(SEMC_Type *base, |
765 | semc_sram_cs_t cs, |
766 | semc_sram_config_t *config, |
767 | uint32_t clkSrc_Hz) |
768 | { |
769 | assert(config != NULL); |
770 | |
771 | uint32_t tempBRVal; |
772 | uint32_t timing; |
773 | uint8_t memsize; |
774 | status_t result = kStatus_Success; |
775 | |
776 | if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) |
777 | { |
778 | return kStatus_SEMC_InvalidBaseAddress; |
779 | } |
780 | |
781 | uint32_t iocReg = base->IOCR & (~(SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->cePinMux)); |
782 | |
783 | uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ? |
784 | (SEMC_IOCR_PSRAM_CE - 1U) : |
785 | ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_PSRAM_CE_A8 : SEMC_IOCR_PSRAM_CE); |
786 | |
787 | /* IOMUX setting. */ |
788 | base->IOCR = iocReg | (muxCe << (uint32_t)config->cePinMux); |
789 | /* Address bit setting. */ |
790 | if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE) |
791 | { |
792 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1U)) |
793 | { |
794 | /* Address bit 24 (A24) */ |
795 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX0_MASK; |
796 | if (config->cePinMux == kSEMC_MUXCSX0) |
797 | { |
798 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
799 | } |
800 | } |
801 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 2U)) |
802 | { |
803 | /* Address bit 25 (A25) */ |
804 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX1_MASK; |
805 | if (config->cePinMux == kSEMC_MUXCSX1) |
806 | { |
807 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
808 | } |
809 | } |
810 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 3U)) |
811 | { |
812 | /* Address bit 26 (A26) */ |
813 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX2_MASK; |
814 | if (config->cePinMux == kSEMC_MUXCSX2) |
815 | { |
816 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
817 | } |
818 | } |
819 | if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 4U)) |
820 | { |
821 | if (config->addr27 == kSEMC_NORA27_MUXCSX3) |
822 | { |
823 | /* Address bit 27 (A27) */ |
824 | base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX3_MASK; |
825 | } |
826 | else if (config->addr27 == kSEMC_NORA27_MUXRDY) |
827 | { |
828 | base->IOCR |= SEMC_IOCR_MUX_RDY_MASK; |
829 | } |
830 | else |
831 | { |
832 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
833 | } |
834 | |
835 | if (config->cePinMux == kSEMC_MUXCSX3) |
836 | { |
837 | return kStatus_SEMC_InvalidSwPinmuxSelection; |
838 | } |
839 | } |
840 | if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX) |
841 | { |
842 | return kStatus_SEMC_InvalidAddressPortWidth; |
843 | } |
844 | } |
845 | /* Base control. */ |
846 | result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); |
847 | if (result != kStatus_Success) |
848 | { |
849 | return result; |
850 | } |
851 | |
852 | tempBRVal = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; |
853 | |
854 | uint32_t tempCtrlVal; |
855 | |
856 | switch (cs) |
857 | { |
858 | case kSEMC_SRAM_CS0: |
859 | base->BR[6] = tempBRVal; |
860 | break; |
861 | #if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U) |
862 | case kSEMC_SRAM_CS1: |
863 | base->BR9 = tempBRVal; |
864 | break; |
865 | case kSEMC_SRAM_CS2: |
866 | base->BR10 = tempBRVal; |
867 | break; |
868 | case kSEMC_SRAM_CS3: |
869 | base->BR11 = tempBRVal; |
870 | break; |
871 | #endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */ |
872 | default: |
873 | assert(NULL); |
874 | break; |
875 | } |
876 | |
877 | /* PSRAM0 SRAMCRx timing setting. */ |
878 | if (kSEMC_SRAM_CS0 == cs) |
879 | { |
880 | #if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U) |
881 | /* Ready/wait(WAITEN and WAITSP) feature is only for async mode. */ |
882 | if (kSEMC_AsyncMode == config->syncMode) |
883 | { |
884 | tempCtrlVal = SEMC_SRAMCR0_PS(config->portSize) | |
885 | #if defined(SEMC_SRAMCR4_SYNCEN_MASK) && (SEMC_SRAMCR4_SYNCEN_MASK) |
886 | SEMC_SRAMCR4_SYNCEN(config->syncMode) | |
887 | #endif /* SEMC_SRAMCR4_SYNCEN_MASK */ |
888 | #if defined(SEMC_SRAMCR0_WAITEN_MASK) && (SEMC_SRAMCR0_WAITEN_MASK) |
889 | SEMC_SRAMCR0_WAITEN(config->waitEnable) | |
890 | #endif /* SEMC_SRAMCR0_WAITEN_MASK */ |
891 | #if defined(SEMC_SRAMCR0_WAITSP_MASK) && (SEMC_SRAMCR0_WAITSP_MASK) |
892 | SEMC_SRAMCR0_WAITSP(config->waitSample) | |
893 | #endif /* SEMC_SRAMCR0_WAITSP_MASK */ |
894 | SEMC_SRAMCR0_BL(config->burstLen) | SEMC_SRAMCR0_AM(config->addrMode) | |
895 | SEMC_SRAMCR0_ADVP(config->advActivePolarity) | |
896 | #if defined(SEMC_SRAMCR4_ADVH_MASK) && (SEMC_SRAMCR4_ADVH_MASK) |
897 | SEMC_SRAMCR4_ADVH(config->advLevelCtrl) | |
898 | #endif /* SEMC_SRAMCR4_ADVH_MASK */ |
899 | SEMC_SRAMCR0_COL_MASK; |
900 | } |
901 | else |
902 | #endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */ |
903 | { |
904 | tempCtrlVal = SEMC_SRAMCR0_PS(config->portSize) | |
905 | #if defined(SEMC_SRAMCR4_SYNCEN_MASK) && (SEMC_SRAMCR4_SYNCEN_MASK) |
906 | SEMC_SRAMCR4_SYNCEN(config->syncMode) | |
907 | #endif /* SEMC_SRAMCR4_SYNCEN_MASK */ |
908 | SEMC_SRAMCR0_BL(config->burstLen) | SEMC_SRAMCR0_AM(config->addrMode) | |
909 | SEMC_SRAMCR0_ADVP(config->advActivePolarity) | |
910 | #if defined(SEMC_SRAMCR4_ADVH_MASK) && (SEMC_SRAMCR4_ADVH_MASK) |
911 | SEMC_SRAMCR4_ADVH(config->advLevelCtrl) | |
912 | #endif /* SEMC_SRAMCR4_ADVH_MASK */ |
913 | SEMC_SRAMCR0_COL_MASK; |
914 | } |
915 | |
916 | base->SRAMCR0 = tempCtrlVal; |
917 | } |
918 | #if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U) |
919 | /* PSRAM1~PSRAM3 SRAMCRx timing setting. */ |
920 | else |
921 | { |
922 | /* Ready/wait(WAITEN and WAITSP) feature is only for async mode. */ |
923 | if (kSEMC_AsyncMode == config->syncMode) |
924 | { |
925 | tempCtrlVal = SEMC_SRAMCR4_PS(config->portSize) | SEMC_SRAMCR4_SYNCEN(config->syncMode) | |
926 | SEMC_SRAMCR4_WAITEN(config->waitEnable) | SEMC_SRAMCR4_WAITSP(config->waitSample) | |
927 | SEMC_SRAMCR4_BL(config->burstLen) | SEMC_SRAMCR4_AM(config->addrMode) | |
928 | SEMC_SRAMCR4_ADVP(config->advActivePolarity) | SEMC_SRAMCR4_ADVH(config->advLevelCtrl) | |
929 | SEMC_SRAMCR4_COL_MASK; |
930 | } |
931 | else |
932 | { |
933 | tempCtrlVal = SEMC_SRAMCR4_PS(config->portSize) | SEMC_SRAMCR4_SYNCEN(config->syncMode) | |
934 | SEMC_SRAMCR4_BL(config->burstLen) | SEMC_SRAMCR4_AM(config->addrMode) | |
935 | SEMC_SRAMCR4_ADVP(config->advActivePolarity) | SEMC_SRAMCR4_ADVH(config->advLevelCtrl) | |
936 | SEMC_SRAMCR4_COL_MASK; |
937 | } |
938 | |
939 | base->SRAMCR4 = tempCtrlVal; |
940 | } |
941 | #endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */ |
942 | |
943 | #if defined(FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) && (FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL) |
944 | uint32_t tempDelayChain = base->DCCR; |
945 | |
946 | /* Configure delay chain. */ |
947 | switch (cs) |
948 | { |
949 | case kSEMC_SRAM_CS0: |
950 | tempDelayChain &= ~(SEMC_DCCR_SRAM0VAL_MASK | SEMC_DCCR_SRAM0EN_MASK); |
951 | base->DCCR = |
952 | tempDelayChain | SEMC_DCCR_SRAM0VAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_SRAM0EN_MASK; |
953 | break; |
954 | #if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U) |
955 | case kSEMC_SRAM_CS1: |
956 | SUPPRESS_FALL_THROUGH_WARNING(); |
957 | case kSEMC_SRAM_CS2: |
958 | SUPPRESS_FALL_THROUGH_WARNING(); |
959 | case kSEMC_SRAM_CS3: |
960 | tempDelayChain &= ~(SEMC_DCCR_SRAMXVAL_MASK | SEMC_DCCR_SRAMXEN_MASK); |
961 | base->DCCR = |
962 | tempDelayChain | SEMC_DCCR_SRAMXVAL((uint32_t)config->delayChain - 0x01U) | SEMC_DCCR_SRAMXEN_MASK; |
963 | break; |
964 | #endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */ |
965 | default: |
966 | assert(NULL); |
967 | break; |
968 | } |
969 | #endif /* FSL_FEATURE_SEMC_HAS_DELAY_CHAIN_CONTROL */ |
970 | |
971 | if (kSEMC_SRAM_CS0 == cs) |
972 | { |
973 | timing = SEMC_SRAMCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz)); |
974 | timing |= SEMC_SRAMCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz)); |
975 | timing |= SEMC_SRAMCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz)); |
976 | timing |= SEMC_SRAMCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz)); |
977 | timing |= SEMC_SRAMCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz)); |
978 | timing |= SEMC_SRAMCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz)); |
979 | timing |= SEMC_SRAMCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz)); |
980 | timing |= SEMC_SRAMCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz)); |
981 | |
982 | /* SRAMCR1 timing setting. */ |
983 | base->SRAMCR1 = timing; |
984 | |
985 | timing = 0x00U; |
986 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME) |
987 | timing |= SEMC_SRAMCR2_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz)); |
988 | #endif |
989 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME) |
990 | timing |= SEMC_SRAMCR2_WDH((uint32_t)SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz) + 1UL); |
991 | #endif |
992 | timing |= SEMC_SRAMCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz)); |
993 | timing |= SEMC_SRAMCR2_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz)); |
994 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME) |
995 | timing |= SEMC_SRAMCR2_LC(config->latencyCount); |
996 | #endif |
997 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME) |
998 | timing |= SEMC_SRAMCR2_RD((uint32_t)config->readCycle - 1UL); |
999 | #endif |
1000 | timing |= SEMC_SRAMCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz)); |
1001 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME) |
1002 | timing |= SEMC_SRAMCR2_RDH((uint32_t)SEMC_ConvertTiming(config->readHoldTime_Ns, clkSrc_Hz) + 0x01U); |
1003 | #endif /* FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME */ |
1004 | |
1005 | /* SRAMCR2 timing setting. */ |
1006 | base->SRAMCR2 = timing; |
1007 | } |
1008 | #if defined(FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT) && (FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT > 0x01U) |
1009 | else |
1010 | { |
1011 | timing = SEMC_SRAMCR5_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz)); |
1012 | timing |= SEMC_SRAMCR5_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz)); |
1013 | timing |= SEMC_SRAMCR5_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz)); |
1014 | timing |= SEMC_SRAMCR5_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz)); |
1015 | timing |= SEMC_SRAMCR5_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz)); |
1016 | timing |= SEMC_SRAMCR5_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz)); |
1017 | timing |= SEMC_SRAMCR5_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz)); |
1018 | timing |= SEMC_SRAMCR5_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz)); |
1019 | |
1020 | /* SRAMCR5 timing setting. */ |
1021 | base->SRAMCR5 = timing; |
1022 | |
1023 | timing = 0x00U; |
1024 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDS_TIME) |
1025 | timing = SEMC_SRAMCR6_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz)); |
1026 | #endif |
1027 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_WDH_TIME) |
1028 | timing |= SEMC_SRAMCR6_WDH((uint32_t)SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz) + 1UL); |
1029 | #endif |
1030 | timing |= SEMC_SRAMCR6_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz)); |
1031 | timing |= SEMC_SRAMCR6_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz)); |
1032 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_LC_TIME) |
1033 | timing |= SEMC_SRAMCR6_LC(config->latencyCount); |
1034 | #endif |
1035 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RD_TIME) |
1036 | timing |= SEMC_SRAMCR6_RD((uint32_t)config->readCycle - 1UL); |
1037 | #endif |
1038 | timing |= SEMC_SRAMCR6_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz)); |
1039 | #if defined(FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME) && (FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME) |
1040 | timing |= SEMC_SRAMCR6_RDH((uint32_t)SEMC_ConvertTiming(config->readHoldTime_Ns, clkSrc_Hz) + 0x01U); |
1041 | #endif /* FSL_FEATURE_SEMC_HAS_SRAM_RDH_TIME */ |
1042 | |
1043 | /* SRAMCR6 timing setting. */ |
1044 | base->SRAMCR6 = timing; |
1045 | } |
1046 | #endif /* FSL_FEATURE_SEMC_SUPPORT_SRAM_COUNT */ |
1047 | |
1048 | return result; |
1049 | } |
1050 | |
1051 | /*! |
1052 | * brief Configures DBI controller in SEMC. |
1053 | * |
1054 | * param base SEMC peripheral base address. |
1055 | * param config The dbi configuration. |
1056 | * param clkSrc_Hz The SEMC clock frequency. |
1057 | */ |
1058 | status_t SEMC_ConfigureDBI(SEMC_Type *base, semc_dbi_config_t *config, uint32_t clkSrc_Hz) |
1059 | { |
1060 | assert(config != NULL); |
1061 | |
1062 | uint8_t memsize; |
1063 | status_t result; |
1064 | uint32_t timing; |
1065 | |
1066 | if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) |
1067 | { |
1068 | return kStatus_SEMC_InvalidBaseAddress; |
1069 | } |
1070 | |
1071 | uint32_t iocReg = base->IOCR & (~(SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->csxPinMux)); |
1072 | uint32_t muxCsx = (config->csxPinMux == kSEMC_MUXRDY) ? |
1073 | (SEMC_IOCR_DBI_CSX - 1U) : |
1074 | ((config->csxPinMux == kSEMC_MUXA8) ? SEMC_IOCR_DBI_CSX_A8 : SEMC_IOCR_DBI_CSX); |
1075 | |
1076 | /* IOMUX setting. */ |
1077 | base->IOCR = iocReg | (muxCsx << (uint32_t)config->csxPinMux); |
1078 | /* Base control. */ |
1079 | result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); |
1080 | if (result != kStatus_Success) |
1081 | { |
1082 | return result; |
1083 | } |
1084 | base->BR[7] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; |
1085 | |
1086 | /* DBICR0 timing setting. */ |
1087 | base->DBICR0 = |
1088 | SEMC_DBICR0_PS(config->portSize) | SEMC_DBICR0_BL(config->burstLen) | SEMC_DBICR0_COL(config->columnAddrBitNum); |
1089 | |
1090 | timing = SEMC_DBICR1_CES(SEMC_ConvertTiming(config->tCsxSetup_Ns, clkSrc_Hz)); |
1091 | timing |= SEMC_DBICR1_CEH(SEMC_ConvertTiming(config->tCsxHold_Ns, clkSrc_Hz)); |
1092 | timing |= SEMC_DBICR1_WEL(SEMC_ConvertTiming(config->tWexLow_Ns, clkSrc_Hz)); |
1093 | timing |= SEMC_DBICR1_WEH(SEMC_ConvertTiming(config->tWexHigh_Ns, clkSrc_Hz)); |
1094 | timing |= SEMC_DBICR1_REL(SEMC_ConvertTiming(config->tRdxLow_Ns, clkSrc_Hz)); |
1095 | timing |= SEMC_DBICR1_REH(SEMC_ConvertTiming(config->tRdxHigh_Ns, clkSrc_Hz)); |
1096 | #if defined(SEMC_DBICR1_CEITV_MASK) |
1097 | timing |= SEMC_DBICR1_CEITV(SEMC_ConvertTiming(config->tCsxInterval_Ns, clkSrc_Hz)); |
1098 | #endif /* SEMC_DBICR1_CEITV_MASK */ |
1099 | |
1100 | /* DBICR1 timing setting. */ |
1101 | base->DBICR1 = timing; |
1102 | |
1103 | #if defined(SEMC_DBICR2_CEITV_MASK) |
1104 | timing = SEMC_DBICR2_CEITV(SEMC_ConvertTiming(config->tCsxInterval_Ns, clkSrc_Hz)); |
1105 | |
1106 | /* DBICR2 timing setting. */ |
1107 | base->DBICR2 = timing; |
1108 | #endif /* SEMC_DBICR2_CEITV_MASK */ |
1109 | |
1110 | return SEMC_ConfigureIPCommand(base, ((uint8_t)config->portSize + 1U)); |
1111 | } |
1112 | |
1113 | /*! |
1114 | * brief SEMC IP command access. |
1115 | * |
1116 | * param base SEMC peripheral base address. |
1117 | * param type SEMC memory type. refer to "semc_mem_type_t" |
1118 | * param address SEMC device address. |
1119 | * param command SEMC IP command. |
1120 | * For NAND device, we should use the SEMC_BuildNandIPCommand to get the right nand command. |
1121 | * For NOR/DBI device, take refer to "semc_ipcmd_nor_dbi_t". |
1122 | * For SRAM device, take refer to "semc_ipcmd_sram_t". |
1123 | * For SDRAM device, take refer to "semc_ipcmd_sdram_t". |
1124 | * param write Data for write access. |
1125 | * param read Data pointer for read data out. |
1126 | */ |
1127 | status_t SEMC_SendIPCommand( |
1128 | SEMC_Type *base, semc_mem_type_t type, uint32_t address, uint32_t command, uint32_t write, uint32_t *read) |
1129 | { |
1130 | uint32_t cmdMode; |
1131 | bool readCmd = false; |
1132 | bool writeCmd = false; |
1133 | status_t result; |
1134 | |
1135 | /* Clear status bit */ |
1136 | base->INTR |= SEMC_INTR_IPCMDDONE_MASK; |
1137 | /* Set address. */ |
1138 | base->IPCR0 = address; |
1139 | |
1140 | /* Check command mode. */ |
1141 | cmdMode = (uint32_t)command & 0x0FU; |
1142 | switch (type) |
1143 | { |
1144 | case kSEMC_MemType_NAND: |
1145 | readCmd = (cmdMode == (uint32_t)kSEMC_NANDCM_CommandAddressRead) || |
1146 | (cmdMode == (uint32_t)kSEMC_NANDCM_CommandRead) || (cmdMode == (uint32_t)kSEMC_NANDCM_Read); |
1147 | writeCmd = (cmdMode == (uint32_t)kSEMC_NANDCM_CommandAddressWrite) || |
1148 | (cmdMode == (uint32_t)kSEMC_NANDCM_CommandWrite) || (cmdMode == (uint32_t)kSEMC_NANDCM_Write); |
1149 | break; |
1150 | case kSEMC_MemType_NOR: |
1151 | case kSEMC_MemType_8080: |
1152 | readCmd = (cmdMode == (uint32_t)kSEMC_NORDBICM_Read); |
1153 | writeCmd = (cmdMode == (uint32_t)kSEMC_NORDBICM_Write); |
1154 | break; |
1155 | case kSEMC_MemType_SRAM: |
1156 | readCmd = (cmdMode == (uint32_t)kSEMC_SRAMCM_ArrayRead) || (cmdMode == (uint32_t)kSEMC_SRAMCM_RegRead); |
1157 | writeCmd = (cmdMode == (uint32_t)kSEMC_SRAMCM_ArrayWrite) || (cmdMode == (uint32_t)kSEMC_SRAMCM_RegWrite); |
1158 | break; |
1159 | case kSEMC_MemType_SDRAM: |
1160 | readCmd = (cmdMode == (uint32_t)kSEMC_SDRAMCM_Read); |
1161 | writeCmd = (cmdMode == (uint32_t)kSEMC_SDRAMCM_Write) || (cmdMode == (uint32_t)kSEMC_SDRAMCM_Modeset); |
1162 | break; |
1163 | default: |
1164 | assert(false); |
1165 | break; |
1166 | } |
1167 | |
1168 | if (writeCmd) |
1169 | { |
1170 | /* Set data. */ |
1171 | base->IPTXDAT = write; |
1172 | } |
1173 | |
1174 | /* Set command code. */ |
1175 | base->IPCMD = command | SEMC_IPCMD_KEY(SEMC_IPCOMMANDMAGICKEY); |
1176 | /* Wait for command done. */ |
1177 | result = SEMC_IsIPCommandDone(base); |
1178 | if (result != kStatus_Success) |
1179 | { |
1180 | return result; |
1181 | } |
1182 | |
1183 | if (readCmd) |
1184 | { |
1185 | /* Get the read data */ |
1186 | *read = base->IPRXDAT; |
1187 | } |
1188 | |
1189 | return kStatus_Success; |
1190 | } |
1191 | |
1192 | /*! |
1193 | * brief SEMC NAND device memory write through IP command. |
1194 | * |
1195 | * param base SEMC peripheral base address. |
1196 | * param address SEMC NAND device address. |
1197 | * param data Data for write access. |
1198 | * param size_bytes Data length. |
1199 | */ |
1200 | status_t SEMC_IPCommandNandWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) |
1201 | { |
1202 | assert(data != NULL); |
1203 | |
1204 | status_t result = kStatus_Success; |
1205 | uint16_t ipCmd; |
1206 | uint32_t tempData = 0; |
1207 | |
1208 | /* Write command built */ |
1209 | ipCmd = SEMC_BuildNandIPCommand(0, kSEMC_NANDAM_ColumnRow, kSEMC_NANDCM_Write); |
1210 | while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) |
1211 | { |
1212 | /* Configure IP command data size. */ |
1213 | (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); |
1214 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, *(uint32_t *)(void *)data, NULL); |
1215 | if (result != kStatus_Success) |
1216 | { |
1217 | break; |
1218 | } |
1219 | |
1220 | data += SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1221 | size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1222 | } |
1223 | |
1224 | if ((result == kStatus_Success) && (size_bytes != 0x00U)) |
1225 | { |
1226 | (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes); |
1227 | |
1228 | while (size_bytes != 0x00U) |
1229 | { |
1230 | size_bytes--; |
1231 | tempData <<= SEMC_BYTE_NUMBIT; |
1232 | tempData |= data[size_bytes]; |
1233 | } |
1234 | |
1235 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, tempData, NULL); |
1236 | } |
1237 | |
1238 | return result; |
1239 | } |
1240 | |
1241 | /*! |
1242 | * brief SEMC NAND device memory read through IP command. |
1243 | * |
1244 | * param base SEMC peripheral base address. |
1245 | * param address SEMC NAND device address. |
1246 | * param data Data pointer for data read out. |
1247 | * param size_bytes Data length. |
1248 | */ |
1249 | status_t SEMC_IPCommandNandRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) |
1250 | { |
1251 | assert(data != NULL); |
1252 | |
1253 | status_t result = kStatus_Success; |
1254 | uint16_t ipCmd; |
1255 | uint32_t tempData = 0; |
1256 | |
1257 | /* Configure IP command data size. */ |
1258 | (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); |
1259 | /* Read command built */ |
1260 | ipCmd = SEMC_BuildNandIPCommand(0, kSEMC_NANDAM_ColumnRow, kSEMC_NANDCM_Read); |
1261 | |
1262 | while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) |
1263 | { |
1264 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, 0, (uint32_t *)(void *)data); |
1265 | if (result != kStatus_Success) |
1266 | { |
1267 | break; |
1268 | } |
1269 | |
1270 | data += SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1271 | size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1272 | } |
1273 | |
1274 | if ((result == kStatus_Success) && (size_bytes != 0x00U)) |
1275 | { |
1276 | (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes); |
1277 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, 0, &tempData); |
1278 | |
1279 | while (size_bytes != 0x00U) |
1280 | { |
1281 | size_bytes--; |
1282 | *(data + size_bytes) = (uint8_t)((tempData >> (SEMC_BYTE_NUMBIT * size_bytes)) & 0xFFU); |
1283 | } |
1284 | } |
1285 | |
1286 | return result; |
1287 | } |
1288 | |
1289 | /*! |
1290 | * brief SEMC NOR device memory read through IP command. |
1291 | * |
1292 | * param base SEMC peripheral base address. |
1293 | * param address SEMC NOR device address. |
1294 | * param data Data pointer for data read out. |
1295 | * param size_bytes Data length. |
1296 | */ |
1297 | status_t SEMC_IPCommandNorRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) |
1298 | { |
1299 | assert(data != NULL); |
1300 | |
1301 | uint32_t tempData = 0; |
1302 | status_t result = kStatus_Success; |
1303 | uint8_t dataSize = (uint8_t)base->NORCR0 & SEMC_NORCR0_PS_MASK; |
1304 | |
1305 | /* Configure IP command data size. */ |
1306 | (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); |
1307 | |
1308 | while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) |
1309 | { |
1310 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint32_t)kSEMC_NORDBICM_Read, 0, |
1311 | (uint32_t *)(void *)data); |
1312 | if (result != kStatus_Success) |
1313 | { |
1314 | break; |
1315 | } |
1316 | |
1317 | data += SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1318 | size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1319 | } |
1320 | |
1321 | if ((result == kStatus_Success) && (size_bytes != 0x00U)) |
1322 | { |
1323 | (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes); |
1324 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Read, 0, &tempData); |
1325 | while (size_bytes != 0x00U) |
1326 | { |
1327 | size_bytes--; |
1328 | *(data + size_bytes) = (uint8_t)((tempData >> (SEMC_BYTE_NUMBIT * size_bytes)) & 0xFFU); |
1329 | } |
1330 | } |
1331 | |
1332 | (void)SEMC_ConfigureIPCommand(base, dataSize); |
1333 | return result; |
1334 | } |
1335 | |
1336 | /*! |
1337 | * brief SEMC NOR device memory write through IP command. |
1338 | * |
1339 | * param base SEMC peripheral base address. |
1340 | * param address SEMC NOR device address. |
1341 | * param data Data for write access. |
1342 | * param size_bytes Data length. |
1343 | */ |
1344 | status_t SEMC_IPCommandNorWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) |
1345 | { |
1346 | assert(data != NULL); |
1347 | |
1348 | uint32_t tempData = 0; |
1349 | status_t result = kStatus_Success; |
1350 | uint8_t dataSize = (uint8_t)base->NORCR0 & SEMC_NORCR0_PS_MASK; |
1351 | |
1352 | /* Write command built */ |
1353 | while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) |
1354 | { |
1355 | /* Configure IP command data size. */ |
1356 | (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); |
1357 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Write, |
1358 | *(uint32_t *)(void *)data, NULL); |
1359 | if (result != kStatus_Success) |
1360 | { |
1361 | break; |
1362 | } |
1363 | size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1364 | data += SEMC_IPCOMMANDDATASIZEBYTEMAX; |
1365 | } |
1366 | |
1367 | if ((result == kStatus_Success) && (size_bytes != 0x00U)) |
1368 | { |
1369 | (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes); |
1370 | |
1371 | while (size_bytes != 0x00U) |
1372 | { |
1373 | tempData |= ((uint32_t) * (data + size_bytes - 1U) << ((size_bytes - 1U) * SEMC_BYTE_NUMBIT)); |
1374 | size_bytes--; |
1375 | } |
1376 | |
1377 | result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Write, tempData, NULL); |
1378 | } |
1379 | (void)SEMC_ConfigureIPCommand(base, dataSize); |
1380 | |
1381 | return result; |
1382 | } |
1383 | |