1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <aos/hal/flash.h>
6 #include <vfsdev/flash_dev.h>
7 #include <devicevfs/devicevfs.h>
8 
9 #define PLATFORM_FLASH_NUM  HAL_PARTITION_MAX
10 // FLASH device node will be named with "/dev/flash<x>", where <x> is flash port id
11 #define FLASH_DEV_NAME_FORMAT "flash%d"
12 
hal_flash_init(hal_partition_t in_partition)13 __weak int32_t hal_flash_init(hal_partition_t in_partition) {
14     ddkc_warn("weak %s\r\n", __FUNCTION__);
15     return 0;
16 }
17 
18 #ifdef AOS_MCU_OTA_ADAPT
19 // temp usage
20 #define IOCTL_FLASH_BOOT_VALIDATE() \
21     if (in_partition == HAL_PARTITION_LITTLEFS) { \
22         ddkc_warn("fs is not allowed to access boot operations\r\n"); \
23     return -EINVAL; \
24     }
25 
26     extern int ota_set_user_bootinfo(void *param);
27     extern int ota_clear_reboot_count(void);
28     extern int ota_get_boot_type();
29 #endif
30 /*
31 offset set by lseek
32 */
flash_device_read(file_t * f,void * buffer,size_t size)33 ssize_t flash_device_read (file_t *f, void *buffer, size_t size) {
34     int ret;
35     ssize_t s = 0;
36     hal_partition_t in_partition = (hal_partition_t)f->node->i_arg;
37     size_t offset = f->offset;
38 
39     if (!buffer || !size) {
40         ddkc_warn("invalid flash:%d, offset:%d, buffer:%p or size:%d\r\n", in_partition, offset, buffer, size);
41         return -EINVAL;
42     }
43 
44     ddkc_dbg("f->offset:%d, buffer:%p, size:%d\r\n", f->offset, buffer, size);
45     ret = hal_flash_read(in_partition, &f->offset, buffer, size);
46     if(ret < 0){
47         return -1;
48     } else {
49         if ((f->offset - offset) != size) {
50             ddkc_err("hal_flash_write returns success, but offset is not set\r\n");
51         }
52     }
53     s = f->offset - offset;
54     ddkc_dbg("read return %d\r\n", s);
55     return s;
56 }
57 
58 /*
59 offset set by lseek
60 */
flash_device_write(file_t * f,const void * buffer,size_t size)61 ssize_t flash_device_write (file_t *f, const void *buffer, size_t size) {
62     int ret = 0;
63     ssize_t s = 0;
64     hal_partition_t in_partition = (hal_partition_t)f->node->i_arg;
65 	size_t offset = f->offset;
66 
67     if (!buffer || !size) {
68         ddkc_warn("invalid flash:%d, offset:%d, buffer:%p or size:%d\r\n", in_partition, offset, buffer, size);
69         return -EINVAL;
70     }
71 
72     ret = hal_flash_write(in_partition, &f->offset, buffer, size);
73     ddkc_dbg("f->offset:%d, ret:%d\r\n", f->offset, ret);
74 
75     if(ret < 0){
76         return -1;
77     } else {
78         if ((f->offset - offset) != size) {
79             ddkc_err("hal_flash_write returns success, but offset is not set\r\n");
80         }
81     }
82     s = f->offset - offset;
83     ddkc_dbg("write return %d\r\n", s);
84     return s;
85 }
86 
flash_device_lseek(file_t * f,int64_t off,int32_t whence)87 static uint32_t flash_device_lseek(file_t *f, int64_t off, int32_t whence){
88     ddkc_dbg("f->offset:%x, off:%llx, whence:%d\r\n", f->offset, off, whence);
89     switch (whence) {
90 	    case SEEK_CUR:
91 	        off = f->offset + off;
92 	        break;
93 	    /* case SEEK_END: break; */
94 	    case SEEK_SET:
95 	        f->offset = off;
96 	        break;
97     }
98 
99     return off;
100 }
101 
102 /*
103 offset set by lseek
104 */
flash_device_ioctl(file_t * f,int cmd,unsigned long arg)105 int flash_device_ioctl (file_t *f, int cmd, unsigned long arg) {
106     int ret = 0;
107     hal_partition_t in_partition = (hal_partition_t)f->node->i_arg;
108     uint32_t offset = f->offset;
109     uint32_t size ;
110     hal_logic_partition_t *partition;
111     hal_logic_partition_t p;
112 
113     if(!arg){
114         ddkc_warn("i_name:%s, flash:%d, cmd:%d, arg:0x%lx\r\n", f->node->i_name, in_partition, cmd, arg);
115     }
116 
117     switch (cmd) {
118         case IOC_FLASH_ERASE_FLASH:
119             if (!arg)
120                 return -EINVAL;
121             size = (uint32_t)arg;
122             ddkc_dbg("IOC_FLASH_ERASE_FLASH i_name:%s, flash:%d, cmd:%d, off_set:0x%x, size:0x%x\r\n", f->node->i_name, in_partition, cmd, offset, size);
123             ret = hal_flash_erase(in_partition,offset, size);
124             if (ret) {
125                 ddkc_warn("hal_flash_erase failed, ret:%d\r\n", ret);
126                 return -1;
127             }
128             break;
129         case IOC_FLASH_INFO_GET:
130             if (!arg)
131                 return -EINVAL;
132             partition = (hal_logic_partition_t *)arg;
133             ddkc_dbg("IOC_FLASH_INFO_GET i_name:%s, flash:%d, cmd:%d\r\n", f->node->i_name, in_partition, cmd);
134             ret = hal_flash_info_get(in_partition, &p);
135             if (ret) {
136                 ddkc_warn("hal_flash_info_get failed, ret:%d\r\n", ret);
137                 return -1;
138             }
139             p.partition_description = NULL;
140             aos_ipc_copy(partition, &p, sizeof(hal_logic_partition_t));
141             break;
142 
143         case IOC_FLASH_ENABLE_SECURE:
144             size = (uint32_t)arg;
145             ddkc_dbg("i_name:%s, flash:%d, cmd:%d, off_set:0x%x, size:0x%x\r\n", f->node->i_name, in_partition, cmd, offset, size);
146             ret = hal_flash_enable_secure(in_partition,offset, size);
147             if (ret) {
148                 ddkc_warn("hal_flash_enable_secure failed, ret:%d\r\n", ret);
149                 return -1;
150             }
151             break;
152 
153         case IOC_FLASH_DISABLE_SECURE:
154             size = (uint32_t)arg;
155             ddkc_dbg("IOC_FLASH_DISABLE_SECURE i_name:%s, flash:%d, cmd:%d, off_set:0x%x, size:0x%x\r\n", f->node->i_name, in_partition, cmd, offset, size);
156             ret = hal_flash_dis_secure(in_partition,offset, size);
157             if (ret) {
158                 ddkc_warn("hal_flash_dis_secure failed, ret:%d\r\n", ret);
159                 return -1;
160             }
161             break;
162 
163 #ifdef AOS_MCU_OTA_ADAPT
164         case IOC_FLASH_SET_BOOT_INFO:
165             IOCTL_FLASH_BOOT_VALIDATE();
166             ret = ota_set_user_bootinfo((void*)arg);
167             break;
168 
169         case IOC_FLASH_CLEAR_BOOT_COUNT:
170             IOCTL_FLASH_BOOT_VALIDATE();
171             ret = ota_clear_reboot_count();
172             break;
173 
174         case IOC_FLASH_GET_BOOT_TYPE:
175             IOCTL_FLASH_BOOT_VALIDATE();
176             ret = ota_get_boot_type();
177             break;
178 #endif
179         default:
180             break;
181     }
182 
183     return ret;
184 }
185 
flash_device_open(inode_t * node,file_t * f)186 int flash_device_open (inode_t *node, file_t *f) {
187     ddkc_dbg("open %s done\r\n", node->i_name);
188     return 0;
189 }
190 
flash_device_close(file_t * f)191 int flash_device_close (file_t *f) {
192     ddkc_dbg("close %s done\r\n", f->node->i_name);
193     return 0;
194 }
195 
196 
197 /************************** device ****************************/
198 
199 
200 subsys_file_ops_t flash_device_fops = {
201     .open = flash_device_open,
202     .close = flash_device_close,
203     .read = flash_device_read,
204     .write = flash_device_write,
205     .ioctl = flash_device_ioctl,
206     .poll = NULL,
207     .lseek = flash_device_lseek,
208 };
209 
flash_device_init(struct u_platform_device * pdev)210 int flash_device_init (struct u_platform_device *pdev) {
211     // make sure 0 is returned if init operation success
212     // or aos_dev_reg procedure will break and no device node will be registered
213     int ret = 0;
214     void *user_data = NULL;
215 
216     user_data = u_platform_get_user_data(pdev);
217 #if defined(USER_SPACE_DRIVER)
218     ret = hal_flash_init((hal_partition_t)user_data);
219     ddkc_info("%s hal_flash_init ret:%d\r\n", __func__, ret);
220 #else
221     ddkc_info("%s hal_flash_init USER_SPACE_DRIVER not defined\r\n", __func__);
222 #endif
223     return 0;
224 }
225 
flash_device_deinit(struct u_platform_device * pdev)226 int flash_device_deinit (struct u_platform_device *pdev) {
227     ddkc_info("%s\r\n", __func__);
228     return 0;
229 }
230 
flash_device_pm(struct u_platform_device * pdev,u_pm_ops_t state)231 int flash_device_pm (struct u_platform_device *pdev, u_pm_ops_t state) {
232     ddkc_info("%s\r\n", __func__);
233     return 0;
234 }
235 
236 struct subsys_drv flash_device_drv = {
237     .drv_name = "flash",
238     .init = flash_device_init,
239     .deinit = flash_device_deinit,
240     .pm = flash_device_pm,
241 };
242 
243 struct subsys_dev *g_flash_device_array[PLATFORM_FLASH_NUM];
244 
245 extern const size_t hal_partitions_amount;
246 extern const hal_logic_partition_t hal_partitions[];
247 
vfs_flash_drv_init(void)248 int vfs_flash_drv_init (void) {
249     int i = 0;
250     int j = 0;
251     int ret = 0;
252     int node_name_len = 0;
253     struct subsys_dev **ppsdev = NULL;
254 
255     ddkc_info("flash vfs driver init starts, hal_partitions_amount:%d\r\n", hal_partitions_amount);
256 
257     node_name_len = strlen(FLASH_DEV_NAME_FORMAT) + 1;
258 
259     memset(g_flash_device_array, 0, sizeof(g_flash_device_array));
260     ppsdev = g_flash_device_array;
261 
262     for (i = 0; i < hal_partitions_amount; i++) {
263         if(0 == hal_partitions[i].partition_length){
264             continue;
265         }
266 
267         *ppsdev = malloc(sizeof(struct subsys_dev) + node_name_len);
268 
269         if (!(*ppsdev)) {
270             ddkc_info("malloc for subsys_dev failed, \r\n");
271             goto err;
272         }
273 
274         memset(*ppsdev, 0, sizeof(struct subsys_dev) + node_name_len);
275 
276         (*ppsdev)->node_name = (char *)((*ppsdev) + 1);
277         snprintf((*ppsdev)->node_name, node_name_len, FLASH_DEV_NAME_FORMAT, i);
278 
279         (*ppsdev)->permission = 0;
280         // please refer to definitions in enum SUBSYS_BUS_TYPE
281         (*ppsdev)->type = BUS_TYPE_PLATFORM;
282         // user_data will be passed to open operation via node->i_arg
283         (*ppsdev)->user_data = (void *)i;
284 
285         ret = aos_dev_reg(*ppsdev, &flash_device_fops, &flash_device_drv);
286         if (ret) {
287             ddkc_err("aos_dev_reg for flash%d failed, ret:%d\r\n", i, ret);
288 
289             free(*ppsdev);
290             *ppsdev = NULL;
291 
292             goto err;
293         }
294 
295         ppsdev++;
296     }
297 
298     ddkc_dbg("flash vfs driver init finish, ret:%d\r\n", ret);
299     return 0;
300 
301 err:
302     ppsdev = g_flash_device_array;
303 
304     for (j = 0; j < i; j++) {
305         if (*ppsdev) {
306             aos_dev_unreg(*ppsdev);
307 
308             ddkc_info("free memory for flash%d\r\n", j);
309             free(*ppsdev);
310             *ppsdev = NULL;
311         }
312         ppsdev++;
313     }
314     ddkc_err("flash vfs driver init failed, ret:%d\r\n", ret);
315 
316     return ret;
317 }
318 
319 VFS_DRIVER_ENTRY(vfs_flash_drv_init)
320 
321