diff options
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/components/flash/mflash/lpc54s018m/mflash_drv.c')
-rw-r--r-- | lib/chibios-contrib/ext/mcux-sdk/components/flash/mflash/lpc54s018m/mflash_drv.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/components/flash/mflash/lpc54s018m/mflash_drv.c b/lib/chibios-contrib/ext/mcux-sdk/components/flash/mflash/lpc54s018m/mflash_drv.c new file mode 100644 index 000000000..5a058835c --- /dev/null +++ b/lib/chibios-contrib/ext/mcux-sdk/components/flash/mflash/lpc54s018m/mflash_drv.c | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * Copyright 2017-2020 NXP | ||
3 | * | ||
4 | * SPDX-License-Identifier: BSD-3-Clause | ||
5 | */ | ||
6 | |||
7 | #include <stdbool.h> | ||
8 | |||
9 | #include "mflash_drv.h" | ||
10 | |||
11 | #include "fsl_spifi.h" | ||
12 | #include "pin_mux.h" | ||
13 | |||
14 | /* Command ID */ | ||
15 | #define COMMAND_NUM (6) | ||
16 | #define READ (0) | ||
17 | #define PROGRAM_PAGE (1) | ||
18 | #define GET_STATUS (2) | ||
19 | #define ERASE_SECTOR (3) | ||
20 | #define WRITE_ENABLE (4) | ||
21 | #define WRITE_REGISTER (5) | ||
22 | |||
23 | /* Commands definition, taken from SPIFI demo */ | ||
24 | static spifi_command_t command[COMMAND_NUM] = { | ||
25 | /* read */ | ||
26 | {MFLASH_PAGE_SIZE, false, kSPIFI_DataInput, 1, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeAddrThreeBytes, 0x0B}, | ||
27 | /* program */ | ||
28 | {MFLASH_PAGE_SIZE, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeAddrThreeBytes, 0x2}, | ||
29 | /* status */ | ||
30 | {1, false, kSPIFI_DataInput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeOnly, 0x05}, | ||
31 | /* erase */ | ||
32 | {0, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeAddrThreeBytes, 0x20}, | ||
33 | /* write enable */ | ||
34 | {0, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeOnly, 0x06}, | ||
35 | /* write register */ | ||
36 | {4, false, kSPIFI_DataOutput, 0, kSPIFI_CommandAllSerial, kSPIFI_CommandOpcodeOnly, 0x01}}; | ||
37 | |||
38 | /* Wait until command finishes */ | ||
39 | static inline void mflash_drv_check_if_finish(void) | ||
40 | { | ||
41 | uint8_t val = 0; | ||
42 | do | ||
43 | { | ||
44 | SPIFI_SetCommand(MFLASH_SPIFI, &command[GET_STATUS]); | ||
45 | while ((MFLASH_SPIFI->STAT & SPIFI_STAT_INTRQ_MASK) == 0U) | ||
46 | { | ||
47 | } | ||
48 | val = SPIFI_ReadDataByte(MFLASH_SPIFI); | ||
49 | } while (val & 0x1); | ||
50 | } | ||
51 | |||
52 | /* return offset from sector */ | ||
53 | static void mflash_drv_read_mode(void) | ||
54 | { | ||
55 | /* Switch back to read mode */ | ||
56 | SPIFI_ResetCommand(MFLASH_SPIFI); | ||
57 | SPIFI_SetMemoryCommand(MFLASH_SPIFI, &command[READ]); | ||
58 | } | ||
59 | |||
60 | /* Initialize SPIFI & flash peripheral, | ||
61 | * cannot be invoked directly, requires calling wrapper in non XIP memory */ | ||
62 | static int32_t mflash_drv_init_internal(void) | ||
63 | { | ||
64 | /* NOTE: Multithread access is not supported for SRAM target. | ||
65 | * XIP target MUST be protected by disabling global interrupts | ||
66 | * since all ISR (and API that is used inside) is placed at XIP. | ||
67 | * It is necessary to place at least "mflash_drv_drv.o", "fsl_spifi.o" to SRAM */ | ||
68 | /* disable interrupts when running from XIP | ||
69 | * TODO: store/restore previous PRIMASK on stack to avoid | ||
70 | * failure in case of nested critical sections !! */ | ||
71 | uint32_t primask = __get_PRIMASK(); | ||
72 | |||
73 | __asm("cpsid i"); | ||
74 | |||
75 | spifi_config_t config = {0}; | ||
76 | |||
77 | #ifndef XIP_IMAGE | ||
78 | uint32_t sourceClockFreq; | ||
79 | BOARD_InitSPIFI(); | ||
80 | /* Reset peripheral */ | ||
81 | RESET_PeripheralReset(kSPIFI_RST_SHIFT_RSTn); | ||
82 | /* Set SPIFI clock source */ | ||
83 | CLOCK_AttachClk(kFRO_HF_to_SPIFI_CLK); | ||
84 | sourceClockFreq = CLOCK_GetSpifiClkFreq(); | ||
85 | /* Set the clock divider */ | ||
86 | CLOCK_SetClkDiv(kCLOCK_DivSpifiClk, sourceClockFreq / MFLASH_BAUDRATE, false); | ||
87 | /* Enable SPIFI clock */ | ||
88 | CLOCK_EnableClock(kCLOCK_Spifi); | ||
89 | #endif | ||
90 | |||
91 | SPIFI_GetDefaultConfig(&config); | ||
92 | config.dualMode = kSPIFI_DualMode; | ||
93 | #ifdef XIP_IMAGE | ||
94 | config.disablePrefetch = false; // true; | ||
95 | config.disableCachePrefech = false; // true; | ||
96 | #else | ||
97 | config.disablePrefetch = false; // true; | ||
98 | config.disableCachePrefech = false; // true; | ||
99 | #endif | ||
100 | |||
101 | /* Reset the Command register */ | ||
102 | SPIFI_ResetCommand(MFLASH_SPIFI); | ||
103 | |||
104 | /* Set time delay parameter */ | ||
105 | MFLASH_SPIFI->CTRL = SPIFI_CTRL_TIMEOUT(config.timeout) | SPIFI_CTRL_CSHIGH(config.csHighTime) | | ||
106 | SPIFI_CTRL_D_PRFTCH_DIS(config.disablePrefetch) | SPIFI_CTRL_MODE3(config.spiMode) | | ||
107 | SPIFI_CTRL_PRFTCH_DIS(config.disableCachePrefech) | SPIFI_CTRL_DUAL(config.dualMode) | | ||
108 | SPIFI_CTRL_RFCLK(config.isReadFullClockCycle) | SPIFI_CTRL_FBCLK(config.isFeedbackClock); | ||
109 | |||
110 | mflash_drv_read_mode(); | ||
111 | |||
112 | if (primask == 0) | ||
113 | { | ||
114 | __asm("cpsie i"); | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /* API - initialize 'mflash' - calling wrapper */ | ||
121 | int32_t mflash_drv_init(void) | ||
122 | { | ||
123 | return mflash_drv_init_internal(); | ||
124 | } | ||
125 | |||
126 | /* Erase single sector */ | ||
127 | static int32_t mflash_drv_sector_erase_internal(uint32_t sector_addr) | ||
128 | { | ||
129 | uint32_t primask = __get_PRIMASK(); | ||
130 | |||
131 | __asm("cpsid i"); | ||
132 | |||
133 | /* Reset the SPIFI to switch to command mode */ | ||
134 | SPIFI_ResetCommand(MFLASH_SPIFI); | ||
135 | |||
136 | /* Write enable */ | ||
137 | SPIFI_SetCommand(MFLASH_SPIFI, &command[WRITE_ENABLE]); | ||
138 | /* Set address */ | ||
139 | SPIFI_SetCommandAddress(MFLASH_SPIFI, sector_addr); | ||
140 | /* Erase sector */ | ||
141 | SPIFI_SetCommand(MFLASH_SPIFI, &command[ERASE_SECTOR]); | ||
142 | /* Check if finished */ | ||
143 | mflash_drv_check_if_finish(); | ||
144 | /* Switch to read mode to enable interrupts as soon ass possible */ | ||
145 | mflash_drv_read_mode(); | ||
146 | |||
147 | if (primask == 0) | ||
148 | { | ||
149 | __asm("cpsie i"); | ||
150 | } | ||
151 | |||
152 | /* Flush pipeline to allow pending interrupts take place */ | ||
153 | __ISB(); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /* API - Erase single sector - calling wrapper */ | ||
159 | int32_t mflash_drv_sector_erase(uint32_t sector_addr) | ||
160 | { | ||
161 | return mflash_drv_sector_erase_internal(sector_addr); | ||
162 | } | ||
163 | |||
164 | /* Page program */ | ||
165 | static int32_t mflash_drv_page_program_internal(uint32_t page_addr, const uint32_t *data) | ||
166 | { | ||
167 | uint32_t primask = __get_PRIMASK(); | ||
168 | |||
169 | __asm("cpsid i"); | ||
170 | |||
171 | /* Program page */ | ||
172 | SPIFI_ResetCommand(MFLASH_SPIFI); | ||
173 | SPIFI_SetCommand(MFLASH_SPIFI, &command[WRITE_ENABLE]); | ||
174 | SPIFI_SetCommandAddress(MFLASH_SPIFI, page_addr); | ||
175 | SPIFI_SetCommand(MFLASH_SPIFI, &command[PROGRAM_PAGE]); | ||
176 | |||
177 | /* Store 4B in each loop. Sector has always 4B alignment and size multiple of 4 */ | ||
178 | for (uint32_t i = 0; i < MFLASH_PAGE_SIZE / sizeof(data[0]); i++) | ||
179 | { | ||
180 | SPIFI_WriteData(MFLASH_SPIFI, data[i]); | ||
181 | } | ||
182 | |||
183 | mflash_drv_check_if_finish(); | ||
184 | /* Switch to read mode to enable interrupts as soon ass possible */ | ||
185 | mflash_drv_read_mode(); | ||
186 | |||
187 | if (primask == 0) | ||
188 | { | ||
189 | __asm("cpsie i"); | ||
190 | } | ||
191 | |||
192 | /* Flush pipeline to allow pending interrupts take place */ | ||
193 | __ISB(); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* API - Page program - calling wrapper */ | ||
199 | int32_t mflash_drv_page_program(uint32_t page_addr, uint32_t *data) | ||
200 | { | ||
201 | return mflash_drv_page_program_internal(page_addr, data); | ||
202 | } | ||
203 | |||
204 | /* API - Read data */ | ||
205 | int32_t mflash_drv_read(uint32_t addr, uint32_t *buffer, uint32_t len) | ||
206 | { | ||
207 | memcpy(buffer, (void *)addr, len); | ||
208 | return kStatus_Success; | ||
209 | } | ||
210 | |||
211 | /* API - Get pointer to FLASH region */ | ||
212 | void *mflash_drv_phys2log(uint32_t addr, uint32_t len) | ||
213 | { | ||
214 | /* FLASH is directly mapped in the address space */ | ||
215 | return (void *)(addr); | ||
216 | } | ||
217 | |||
218 | /* API - Get pointer to FLASH region */ | ||
219 | uint32_t mflash_drv_log2phys(void *ptr, uint32_t len) | ||
220 | { | ||
221 | /* FLASH is directly mapped in the address space */ | ||
222 | return ((uint32_t)ptr); | ||
223 | } | ||