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