1 /*
2  * Copyright (c) 2021 Telink Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT telink_b91_flash_controller
8 #define FLASH_SIZE DT_REG_SIZE(DT_INST(0, soc_nv_flash))
9 
10 #include "flash.h"
11 #include <device.h>
12 #include <drivers/flash.h>
13 
14 
15 /* driver data structure */
16 struct flash_b91_data {
17 	struct k_sem write_lock;
18 };
19 
20 /* driver parameters structure */
21 static const struct flash_parameters flash_b91_parameters = {
22 	.write_block_size = DT_PROP(DT_INST(0, soc_nv_flash), write_block_size),
23 	.erase_value = 0xff,
24 };
25 
26 
27 /* Check for correct offset and length */
flash_b91_is_range_valid(off_t offset,size_t len)28 static bool flash_b91_is_range_valid(off_t offset, size_t len)
29 {
30 	/* check for min value */
31 	if ((offset < 0) || (len < 1)) {
32 		return false;
33 	}
34 
35 	/* check for max value */
36 	if ((offset + len) > FLASH_SIZE) {
37 		return false;
38 	}
39 
40 	return true;
41 }
42 
43 /* API implementation: driver initialization */
flash_b91_init(const struct device * dev)44 static int flash_b91_init(const struct device *dev)
45 {
46 	struct flash_b91_data *dev_data = dev->data;
47 
48 	k_sem_init(&dev_data->write_lock, 1, 1);
49 
50 	return 0;
51 }
52 
53 /* API implementation: erase */
flash_b91_erase(const struct device * dev,off_t offset,size_t len)54 static int flash_b91_erase(const struct device *dev, off_t offset, size_t len)
55 {
56 	int page_nums = len / PAGE_SIZE;
57 	struct flash_b91_data *dev_data = dev->data;
58 
59 	/* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
60 	if (!len) {
61 		return 0;
62 	}
63 
64 	/* check for valid range */
65 	if (!flash_b91_is_range_valid(offset, len)) {
66 		return -EINVAL;
67 	}
68 
69 	/* Erase can be done only by pages */
70 	if (((offset % PAGE_SIZE) != 0) || ((len % PAGE_SIZE) != 0)) {
71 		return -EINVAL;
72 	}
73 
74 	/* take semaphore */
75 	if (k_sem_take(&dev_data->write_lock, K_NO_WAIT)) {
76 		return -EACCES;
77 	}
78 
79 	/* erase flash page by page */
80 	for (int i = 0; i < page_nums; i++) {
81 		flash_erase_page(offset);
82 		offset += PAGE_SIZE;
83 	}
84 
85 	/* release semaphore */
86 	k_sem_give(&dev_data->write_lock);
87 
88 	return 0;
89 }
90 
91 /* API implementation: write */
flash_b91_write(const struct device * dev,off_t offset,const void * data,size_t len)92 static int flash_b91_write(const struct device *dev, off_t offset,
93 			   const void *data, size_t len)
94 {
95 	struct flash_b91_data *dev_data = dev->data;
96 
97 	/* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
98 	if (!len) {
99 		return 0;
100 	}
101 
102 	/* check for valid range */
103 	if (!flash_b91_is_range_valid(offset, len)) {
104 		return -EINVAL;
105 	}
106 
107 	/* take semaphore */
108 	if (k_sem_take(&dev_data->write_lock, K_NO_WAIT)) {
109 		return -EACCES;
110 	}
111 
112 	/* write flash */
113 	flash_write_page(offset, len, (unsigned char *)data);
114 
115 	/* release semaphore */
116 	k_sem_give(&dev_data->write_lock);
117 
118 	return 0;
119 }
120 
121 /* API implementation: read */
flash_b91_read(const struct device * dev,off_t offset,void * data,size_t len)122 static int flash_b91_read(const struct device *dev, off_t offset,
123 			  void *data, size_t len)
124 {
125 	ARG_UNUSED(dev);
126 
127 	/* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
128 	if (!len) {
129 		return 0;
130 	}
131 
132 	/* check for valid range */
133 	if (!flash_b91_is_range_valid(offset, len)) {
134 		return -EINVAL;
135 	}
136 
137 	/* read flash */
138 	flash_read_page(offset, len, (unsigned char *)data);
139 
140 	return 0;
141 }
142 
143 /* API implementation: get_parameters */
144 static const struct flash_parameters *
flash_b91_get_parameters(const struct device * dev)145 flash_b91_get_parameters(const struct device *dev)
146 {
147 	ARG_UNUSED(dev);
148 
149 	return &flash_b91_parameters;
150 }
151 
152 /* API implementation: page_layout */
153 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
154 static const struct flash_pages_layout dev_layout = {
155 	.pages_count = FLASH_SIZE / PAGE_SIZE,
156 	.pages_size = PAGE_SIZE,
157 };
158 
flash_b91_pages_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)159 static void flash_b91_pages_layout(const struct device *dev,
160 				   const struct flash_pages_layout **layout,
161 				   size_t *layout_size)
162 {
163 	*layout = &dev_layout;
164 	*layout_size = 1;
165 }
166 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
167 
168 static struct flash_b91_data flash_data;
169 
170 static const struct flash_driver_api flash_b91_api = {
171 	.erase = flash_b91_erase,
172 	.write = flash_b91_write,
173 	.read = flash_b91_read,
174 	.get_parameters = flash_b91_get_parameters,
175 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
176 	.page_layout = flash_b91_pages_layout,
177 #endif
178 };
179 
180 /* Driver registration */
181 DEVICE_DT_INST_DEFINE(0, flash_b91_init,
182 		      NULL, &flash_data, NULL, POST_KERNEL,
183 		      CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &flash_b91_api);
184