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