1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2012-10-21     prife        the first version
9  */
10 
11 #include <rtdevice.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include "sst25vfxx_mtd.h"
16 
17 #ifdef RT_USING_MTD_NOR
18 #define NOR_SIM "nor.bin"
19 /* JEDEC Manufacturer's ID */
20 #define MF_ID           (0xBF)
21 /* JEDEC Device ID : Memory Type */
22 #define MT_ID           (0x25)
23 /* JEDEC Device ID: Memory Capacity */
24 #define MC_ID_SST25VF016               (0x41)
25 #define MC_ID_SST25VF032               (0x4A)
26 #define MC_ID_SST25VF064               (0x4B)
27 
28 #define BLOCK_SIZE   (64*1024)
29 
30 
31 #define SST25_MTD(device)       ((struct sst25_mtd*)(device))
32 struct sst25_mtd
33 {
34     struct rt_mtd_nor_device parent;
35     FILE *file;
36 };
37 static struct sst25_mtd _sst25_mtd;
38 
39 static struct rt_mutex flash_lock;
40 
41 /* RT-Thread MTD device interface */
sst25vfxx_read_id(struct rt_mtd_nor_device * device)42 static rt_uint32_t sst25vfxx_read_id(struct rt_mtd_nor_device *device)
43 {
44     rt_uint8_t id_recv[3] = {MF_ID, MT_ID, MC_ID_SST25VF016};
45 
46     return (id_recv[0] << 16) | (id_recv[1] << 8) | id_recv[2];
47 }
48 
sst25vfxx_read(struct rt_mtd_nor_device * device,rt_off_t position,rt_uint8_t * data,rt_size_t size)49 static int sst25vfxx_read(struct rt_mtd_nor_device *device, rt_off_t position, rt_uint8_t *data, rt_size_t size)
50 {
51     struct sst25_mtd *sst25;
52     int result;
53 
54     sst25 = SST25_MTD(device);
55     RT_ASSERT(sst25 != RT_NULL);
56 
57     result = rt_mutex_take(&flash_lock, RT_WAITING_FOREVER);
58     if (result == -RT_ETIMEOUT)
59     {
60         rt_kprintf("Take mutex time out.\n");
61         return result;
62     }
63     else if (result == -RT_ERROR)
64     {
65         rt_kprintf("Take mutex error.\n");
66         return result;
67     }
68 
69     fseek(sst25->file, position, SEEK_SET);
70     result = fread(data, size, 1, sst25->file);
71     if (result < 0)
72         rt_kprintf("sst read error.\n");
73 
74     rt_mutex_release(&flash_lock);
75     return size;
76 }
77 
sst25vfxx_write(struct rt_mtd_nor_device * device,rt_off_t position,const rt_uint8_t * data,rt_size_t size)78 static int sst25vfxx_write(struct rt_mtd_nor_device *device, rt_off_t position,
79                            const rt_uint8_t *data, rt_size_t size)
80 {
81     struct sst25_mtd *sst25;
82     int result;
83 
84     sst25 = SST25_MTD(device);
85     RT_ASSERT(sst25 != RT_NULL);
86 
87     result = rt_mutex_take(&flash_lock, RT_WAITING_FOREVER);
88     if (result == -RT_ETIMEOUT)
89     {
90         rt_kprintf("Take mutex time out.\n");
91         return result;
92     }
93     else if (result == -RT_ERROR)
94     {
95         rt_kprintf("Take mutex error.\n");
96         return result;
97     }
98 
99     fseek(sst25->file, position, SEEK_SET);
100     result = fwrite(data, size, 1, sst25->file);
101     if (result < 0)
102         rt_kprintf("sst write error.\n");
103 
104     rt_mutex_release(&flash_lock);
105     return size;
106 }
107 
108 static char block_buffer[BLOCK_SIZE];
sst25vfxx_erase_block(struct rt_mtd_nor_device * device,rt_off_t offset,rt_uint32_t length)109 static rt_err_t sst25vfxx_erase_block(struct rt_mtd_nor_device *device, rt_off_t offset, rt_uint32_t length)
110 {
111     struct sst25_mtd *sst25;
112     int result;
113 
114     sst25 = SST25_MTD(device);
115 
116     RT_ASSERT(sst25 != RT_NULL);
117 
118     result = rt_mutex_take(&flash_lock, RT_WAITING_FOREVER);
119     if (result == -RT_ETIMEOUT)
120     {
121         rt_kprintf("Take mutex time out.\n");
122         return -RT_ETIMEOUT;
123     }
124     else if (result == -RT_ERROR)
125     {
126         rt_kprintf("Take mutex error.\n");
127         return -RT_ERROR;
128     }
129 
130     memset(block_buffer, 0xFF, BLOCK_SIZE);
131     fseek(sst25->file, offset, SEEK_SET);
132 
133     result = fwrite(block_buffer, BLOCK_SIZE, 1, sst25->file);
134     if (result < 0)
135         rt_kprintf("sst write error.\n");
136 
137     rt_mutex_release(&flash_lock);
138     return RT_EOK;
139 }
140 
141 const static struct rt_mtd_nor_driver_ops sst25vfxx_mtd_ops =
142 {
143     sst25vfxx_read_id,
144     sst25vfxx_read,
145     sst25vfxx_write,
146     sst25vfxx_erase_block,
147 };
sst25vfxx_hw_init(struct sst25_mtd * mtd)148 static rt_err_t sst25vfxx_hw_init(struct sst25_mtd *mtd)
149 {
150     mtd = mtd;
151     return RT_EOK;
152 }
153 
154 /**
155  * SST25vfxx API
156  */
sst25vfxx_mtd_init(const char * nor_name,rt_uint32_t block_start,rt_uint32_t block_end)157 rt_err_t sst25vfxx_mtd_init(const char *nor_name,
158                             rt_uint32_t block_start,
159                             rt_uint32_t block_end)
160 {
161     rt_uint32_t id, total_block;
162     struct sst25_mtd *sst25;
163     struct rt_mtd_nor_device *mtd;
164 
165 
166     sst25 = &_sst25_mtd;
167     mtd = &(sst25->parent);
168 
169     /* set page size and block size */
170     mtd->block_size = 64 * 1024; /* 64kByte */
171     mtd->ops = &sst25vfxx_mtd_ops;
172 
173     /* initialize mutex */
174     if (rt_mutex_init(&flash_lock, nor_name, RT_IPC_FLAG_PRIO) != RT_EOK)
175     {
176         rt_kprintf("init sd lock mutex failed\n");
177     }
178 
179     /* initialize flash */
180     id = sst25vfxx_read_id(mtd);
181     switch (id & 0xff)
182     {
183     case MC_ID_SST25VF016:
184         total_block = (16 * 1024 * 1024 / 8) / mtd->block_size;
185         break;
186     case MC_ID_SST25VF032:
187         total_block = (32 * 1024 * 1024 / 8) / mtd->block_size;
188         break;
189     case MC_ID_SST25VF064:
190         total_block = (64 * 1024 * 1024 / 8) / mtd->block_size;
191         break;
192     default:
193         rt_kprintf("SST25 detection error, id: %x\n", id);
194         return -RT_ERROR;
195     }
196 
197     if ((block_end == RT_UINT32_MAX) || (block_end == 0))
198     {
199         block_end = total_block;
200     }
201     else if (block_end > total_block)
202     {
203         rt_kprintf("SST25 total block: %d, out of block\n", total_block);
204         return -RT_ERROR;
205     }
206 
207     mtd->block_start = block_start;
208     mtd->block_end   = block_end;
209 
210     /* open nor file, if not exist, then create it  */
211     sst25->file = fopen(NOR_SIM, "rb+");
212     if (sst25->file == NULL)
213     {
214         rt_uint32_t i;
215         /* create a file to simulate nor */
216         sst25->file = fopen(NOR_SIM, "wb+");
217 
218         memset(block_buffer, 0xFF, sizeof(block_buffer));
219         for (i = 0; i < total_block; i++)
220         {
221             fseek(sst25->file, i * BLOCK_SIZE, SEEK_SET);
222             fwrite(block_buffer, BLOCK_SIZE, 1, sst25->file);
223         }
224     }
225 
226     fseek(sst25->file, 0, SEEK_SET);
227 
228     /* initialize hardware */
229     sst25vfxx_hw_init(&_sst25_mtd);
230 
231     /* register MTD device */
232     rt_mtd_nor_register_device("nor", mtd);
233 
234     return RT_EOK;
235 }
236 
237 #ifdef RT_USING_FINSH
238 #include <finsh.h>
nor_erase(void)239 void nor_erase(void)
240 {
241     rt_uint32_t index;
242     struct rt_mtd_nor_device *mtd;
243 
244     mtd = RT_MTD_NOR_DEVICE(&_sst25_mtd);
245     for (index = mtd->block_start; index < mtd->block_end; index ++)
246     {
247         sst25vfxx_erase_block(mtd, index * mtd->block_size, BLOCK_SIZE);
248     }
249 }
250 FINSH_FUNCTION_EXPORT(nor_erase, erase all block in SPI flash);
251 #endif
252 
253 #endif
254