1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-05-06 onelife Initial creation by using USART module
9 */
10
11 /***************************************************************************//**
12 * @addtogroup efm32
13 * @{
14 ******************************************************************************/
15
16 /* Includes ------------------------------------------------------------------*/
17 #include "board.h"
18 #include "drv_usart.h"
19 #include "dev_sflash.h"
20
21 #if defined(EFM32_USING_SFLASH)
22 /* Private typedef -------------------------------------------------------------*/
23 typedef struct
24 {
25 rt_uint8_t code;
26 rt_uint32_t address:24;
27 rt_uint32_t dummy:8;
28 } sflash_instruction;
29
30 /* Private define --------------------------------------------------------------*/
31 /* Private macro --------------------------------------------------------------*/
32 #ifdef EFM32_SFLASH_DEBUG
33 #define sflash_debug(format,args...) rt_kprintf(format, ##args)
34 #else
35 #define sflash_debug(format,args...)
36 #endif
37
38 /* Private constants -----------------------------------------------------------*/
39 static rt_uint8_t sflash_inst_code_tbl[] =
40 {
41 /* Instruction only */
42 SFLASH_INST_CODE_WREN,
43 SFLASH_INST_CODE_WRDI,
44 SFLASH_INST_CODE_RDID_L,
45 SFLASH_INST_CODE_RDID_S,
46 SFLASH_INST_CODE_RDSR,
47 SFLASH_INST_CODE_WRSR,
48 SFLASH_INST_CODE_BE,
49 SFLASH_INST_CODE_DP,
50 SFLASH_INST_CODE_RDP,
51 /* Instruction and address */
52 SFLASH_INST_CODE_WRLR,
53 SFLASH_INST_CODE_RDLR,
54 SFLASH_INST_CODE_READ,
55 SFLASH_INST_CODE_POTP,
56 SFLASH_INST_CODE_PP,
57 SFLASH_INST_CODE_DIFP,
58 SFLASH_INST_CODE_SSE,
59 SFLASH_INST_CODE_SE,
60 /* Instruction, address and dummy read */
61 SFLASH_INST_CODE_READ_F,
62 SFLASH_INST_CODE_DOFR,
63 SFLASH_INST_CODE_ROTP
64 };
65 static rt_uint16_t sflash_data_len_tbl[] =
66 {
67 /* Instruction only */
68 SFLASH_REPLY_LEN_WREN,
69 SFLASH_REPLY_LEN_WRDI,
70 SFLASH_REPLY_LEN_RDID_L,
71 SFLASH_REPLY_LEN_RDID_S,
72 SFLASH_REPLY_LEN_RDSR,
73 SFLASH_REPLY_LEN_WRSR,
74 SFLASH_REPLY_LEN_BE,
75 SFLASH_REPLY_LEN_DP,
76 SFLASH_REPLY_LEN_RDP,
77 /* Instruction and address */
78 SFLASH_REPLY_LEN_WRLR,
79 SFLASH_REPLY_LEN_RDLR,
80 SFLASH_REPLY_LEN_READ,
81 SFLASH_REPLY_LEN_POTP,
82 SFLASH_REPLY_LEN_PP,
83 SFLASH_REPLY_LEN_DIFP,
84 SFLASH_REPLY_LEN_SSE,
85 SFLASH_REPLY_LEN_SE,
86 /* Instruction, address and dummy read */
87 SFLASH_REPLY_LEN_READ_F,
88 SFLASH_REPLY_LEN_DOFR,
89 SFLASH_REPLY_LEN_ROTP
90 };
91 static rt_bool_t sflash_read_inst_tbl[] =
92 {
93 /* Instruction only */
94 false,
95 false,
96 true,
97 true,
98 true,
99 false,
100 false,
101 false,
102 false,
103 /* Instruction and address */
104 false,
105 true,
106 true,
107 false,
108 false,
109 false,
110 false,
111 false,
112 /* Instruction, address and dummy read */
113 true,
114 true,
115 true
116 };
117
118 /* Private variables ------------------------------------------------------------*/
119 static rt_device_t sFlash = RT_NULL;
120 static rt_bool_t sFlashAutoCs = true;
121
122 /* Private function prototypes ---------------------------------------------------*/
123 /* Private functions ------------------------------------------------------------*/
124 /******************************************************************//**
125 * @brief
126 * Initialize the SPI Flash
127 *
128 * @details
129 *
130 * @note
131 *
132 * @return
133 * Error code
134 *********************************************************************/
efm_spiFlash_init(void)135 rt_err_t efm_spiFlash_init(void)
136 {
137 struct efm32_usart_device_t *usart;
138
139 usart = (struct efm32_usart_device_t *)(sFlash->user_data);
140
141 #if defined(EFM32_GXXX_DK)
142 /* Enable SPI access to Flash */
143 DVK_writeRegister(BC_SPI_CFG, 0);
144 #endif
145
146 do
147 {
148 /* Find SPI device */
149 sFlash = rt_device_find(SFLASH_USING_DEVICE_NAME);
150 if (sFlash == RT_NULL)
151 {
152 sflash_debug("SFLASH: Can't find device %s!\n",
153 SFLASH_USING_DEVICE_NAME);
154 break;
155 }
156 sflash_debug("SFLASH: Find device %s\n", SFLASH_USING_DEVICE_NAME);
157
158 /* Config chip slect pin */
159 if (!(usart->state & USART_STATE_AUTOCS))
160 {
161 GPIO_PinModeSet(SFLASH_CS_PORT, SFLASH_CS_PIN, gpioModePushPull, 1);
162 sFlashAutoCs = false;
163 }
164
165 /* Open SPI device */
166 if (sFlash->open(sFlash, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
167 {
168 break;
169 }
170
171 return RT_EOK;
172 } while(0);
173
174 sflash_debug("SFLASH: Init failed!\n");
175 return -RT_ERROR;
176 }
177
178 /******************************************************************//**
179 * @brief
180 * De-initialize the SPI Flash
181 *
182 * @details
183 *
184 * @note
185 *
186 * @return
187 * Error code
188 *********************************************************************/
efm_spiFlash_deinit(void)189 rt_err_t efm_spiFlash_deinit(void)
190 {
191 do
192 {
193 if (sFlash == RT_NULL)
194 {
195 sflash_debug("SFLASH: Already deinit!\n");
196 break;
197 }
198
199 /* Close SPI device */
200 if (sFlash->close(sFlash) != RT_EOK)
201 {
202 break;
203 }
204 sFlash = RT_NULL;
205 sflash_debug("SFLASH: Close device %s\n", SFLASH_USING_DEVICE_NAME);
206
207 return RT_EOK;
208 } while(0);
209
210 sflash_debug("SFLASH: Deinit failed!\n");
211 return -RT_ERROR;
212 }
213
214 /******************************************************************//**
215 * @brief
216 * Set/Clear chip select
217 *
218 * @details
219 *
220 * @note
221 *
222 * @param[in] enable
223 * Chip select pin setting
224 *********************************************************************/
efm_spiFlash_cs(rt_uint8_t enable)225 static void efm_spiFlash_cs(rt_uint8_t enable)
226 {
227 if (!sFlashAutoCs)
228 {
229 if (enable)
230 {
231 GPIO_PinOutClear(SFLASH_CS_PORT, SFLASH_CS_PIN);
232 }
233 else
234 {
235 GPIO_PinOutSet(SFLASH_CS_PORT, SFLASH_CS_PIN);
236 }
237 }
238 }
239
240 /******************************************************************//**
241 * @brief
242 * Execute a command
243 *
244 * @details
245 *
246 * @note
247 *
248 * @param[in] command
249 * SPI Flash instruction
250 *
251 * @param[in] address
252 * Memory address
253 *
254 * @param[in] buffer
255 * Poniter to the read/write buffer
256 *
257 * @param[in] size
258 * Buffer size in byte
259 *
260 * @return
261 * Number of read/written bytes
262 *********************************************************************/
efm_spiFlash_cmd(enum sflash_inst_type_t command,rt_uint32_t address,rt_uint8_t * buffer,rt_uint32_t size)263 rt_uint32_t efm_spiFlash_cmd(
264 enum sflash_inst_type_t command,
265 rt_uint32_t address,
266 rt_uint8_t *buffer,
267 rt_uint32_t size)
268 {
269 RT_ASSERT(sFlash != RT_NULL);
270
271 sflash_instruction *inst;
272 rt_uint8_t *inst_buf;
273 rt_uint8_t inst_len, head_len;
274 rt_uint32_t data_len;
275
276 sflash_debug("SFLASH: Inst %x\n", sflash_inst_code_tbl[command]);
277 if (sflash_data_len_tbl[command] && !size)
278 {
279 sflash_debug("SFLASH: No data!\n");
280 return 0x00;
281 }
282
283 data_len = (sflash_data_len_tbl[command] < size)? \
284 sflash_data_len_tbl[command] : size;
285 if (data_len && (buffer == RT_NULL))
286 {
287 sflash_debug("SFLASH: No buffer specified!\n");
288 return 0x00;
289 }
290
291 /* Allocate memory for write buffer */
292 if (sflash_read_inst_tbl[command])
293 {
294 inst_buf = rt_malloc(6 + 4);
295 inst = (sflash_instruction *)(inst_buf + 1);
296 head_len = 1;
297 }
298 else
299 {
300 inst_buf = rt_malloc(5 + data_len);
301 inst = (sflash_instruction *)inst_buf;
302 head_len = 0;
303 }
304
305 /* Fill in instruction */
306 inst->code = sflash_inst_code_tbl[command];
307 if (command >= sflash_inst_wrlr)
308 {
309 /* MSB first */
310 inst->address = ((address & 0x000000FF) << 16) | \
311 (address & 0x0000FF00) | \
312 ((address & 0x00FF0000) >> 16);
313 if (command >= sflash_inst_read_f)
314 {
315 inst->dummy = 0x00;
316 inst_len = 5;
317 }
318 else
319 {
320 inst_len = 4;
321 }
322 }
323 else
324 {
325 inst_len = 1;
326 }
327 head_len += inst_len;
328
329 /* Fill in data and send the buffer */
330 if (sflash_read_inst_tbl[command])
331 {
332 rt_off_t skip;
333
334 inst_buf[0] = inst_len;
335 *(rt_uint8_t **)(inst_buf + head_len) = buffer;
336 if (command == sflash_inst_read)
337 {
338 skip = SFLASH_SPI_READ_SKIP;
339 }
340 else
341 {
342 skip = SFLASH_SPI_COMMAND_SKIP;
343 }
344
345 efm_spiFlash_cs(1);
346 if (sFlash->read(sFlash, skip, inst_buf, \
347 (data_len == size)? data_len - 1 : data_len) == 0)
348 {
349 sflash_debug("SFLASH: Read failed!\n");
350 return 0x00;
351 }
352 efm_spiFlash_cs(0);
353 buffer[data_len] = 0x00;
354 sflash_debug("SFLASH: Read %d bytes data to 0x%x\n", data_len, buffer);
355 }
356 else
357 {
358 if (data_len)
359 {
360 rt_memcpy((inst_buf + head_len), buffer, data_len);
361 }
362
363 efm_spiFlash_cs(1);
364 if (sFlash->write(sFlash, EFM32_NO_DATA, inst_buf, \
365 head_len + data_len) == 0)
366 {
367 sflash_debug("SFLASH: Write failed!\n");
368 return 0x00;
369 }
370 efm_spiFlash_cs(0);
371 sflash_debug("SFLASH: Write %d/%d bytes data\n", data_len, \
372 head_len + data_len);
373 }
374
375 /* Free the buffer */
376 rt_free(inst_buf);
377 return data_len;
378 }
379
380 /*********************************************************************
381 * Export to FINSH
382 *********************************************************************/
383 #ifdef RT_USING_FINSH
384 #include <finsh.h>
385
list_sflash(void)386 void list_sflash(void)
387 {
388 rt_uint8_t buf[4];
389
390 efm_spiFlash_cmd(sflash_inst_rdid_s, EFM32_NO_DATA, buf, sizeof(buf));
391
392 rt_kprintf(" spi flash on %s\n", SFLASH_USING_DEVICE_NAME);
393 rt_kprintf(" ------------------------------\n");
394 rt_kprintf(" Manufacturer ID:\t%x\n", buf[0]);
395 rt_kprintf(" Memory type:\t\t%x\n", buf[1]);
396 rt_kprintf(" Memory capacity:\t%x\n", buf[2]);
397 }
398 FINSH_FUNCTION_EXPORT(list_sflash, list the SPI Flash.)
399 #endif
400
401 #endif /* defined(EFM32_USING_SFLASH) */
402
403 /******************************************************************//**
404 * @}
405 *********************************************************************/
406