1 /*
2  * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /******************************************************************************
17  * @file     ck_eflash.c
18  * @brief    CSI Source File for Embedded Flash Driver
19  * @version  V1.0
20  * @date     02. June 2017
21  ******************************************************************************/
22 #include <stdio.h>
23 #include "drv_eflash.h"
24 #include "ck_eflash.h"
25 
26 
27 #define ERR_EFLASH(errno) (CSI_DRV_ERRNO_EFLASH_BASE | errno)
28 #define EFLASH_NULL_PARAM_CHK(para)                         \
29         do {                                        \
30             if (para == NULL) {                     \
31                 return ERR_EFLASH(EDRV_PARAMETER);   \
32             }                                       \
33         } while (0)
34 
35 typedef struct {
36     uint32_t base;
37     eflash_info eflashinfo;
38     eflash_event_cb_t cb;
39     eflash_status_t status;
40 } ck_eflash_priv_t;
41 
42 static ck_eflash_priv_t eflash_handle[CONFIG_EFLASH_NUM];
43 /* Driver Capabilities */
44 static const eflash_capabilities_t driver_capabilities = {
45     .event_ready = 1, /* event_ready */
46     .data_width = 2, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */
47     .erase_chip = 0  /* erase_chip */
48 };
49 
50 //
51 // Functions
52 //
53 
eflash_program_word(eflash_handle_t handle,uint32_t dstaddr,uint32_t * srcbuf,uint32_t len)54 static int32_t eflash_program_word(eflash_handle_t handle, uint32_t dstaddr, uint32_t *srcbuf, uint32_t len)
55 {
56     ck_eflash_priv_t *eflash_priv = handle;
57     uint32_t fbase = eflash_priv->base;
58     uint32_t i;
59 
60     for (i = 0; i < len; i++) {
61         *(volatile uint32_t *)(fbase + 0x04) = dstaddr;
62         *(volatile uint32_t *)(fbase + 0x1c) = *srcbuf;
63         *(volatile uint32_t *)(fbase + 0x18) = 1;
64         srcbuf++;
65         dstaddr += 4;
66     }
67 
68     return (i << 2);
69 }
70 
target_get_eflash_count(void)71 int32_t __attribute__((weak)) target_get_eflash_count(void)
72 {
73     return 0;
74 }
75 
target_get_eflash(int32_t idx,uint32_t * base,eflash_info * info)76 int32_t __attribute__((weak)) target_get_eflash(int32_t idx, uint32_t *base, eflash_info *info)
77 {
78     return NULL;
79 }
80 /**
81   \brief       get eflash handle count.
82   \return      eflash handle count
83 */
csi_eflash_get_instance_count(void)84 int32_t csi_eflash_get_instance_count(void)
85 {
86     return target_get_eflash_count();
87 }
88 
89 /**
90   \brief       Initialize EFLASH Interface. 1. Initializes the resources needed for the EFLASH interface 2.registers event callback function
91   \param[in]   idx  must not exceed return value of csi_eflash_get_instance_count()
92   \param[in]   cb_event  Pointer to \ref eflash_event_cb_t
93   \return      pointer to eflash handle
94 */
csi_eflash_initialize(int32_t idx,eflash_event_cb_t cb_event)95 eflash_handle_t csi_eflash_initialize(int32_t idx, eflash_event_cb_t cb_event)
96 {
97     if (idx < 0 || idx >= CONFIG_EFLASH_NUM) {
98         return NULL;
99     }
100 
101     /* obtain the eflash information */
102     uint32_t base = 0u;
103     eflash_info info;
104     int32_t real_idx = target_get_eflash(idx, &base, &info);
105 
106     if (real_idx != idx) {
107         return NULL;
108     }
109 
110     ck_eflash_priv_t *eflash_priv = &eflash_handle[idx];
111 
112     eflash_priv->base = base;
113     eflash_priv->eflashinfo.start = info.start;
114     eflash_priv->eflashinfo.end = info.end;
115     eflash_priv->eflashinfo.sector_count = info.sector_count;
116 
117     /* initialize the eflash context */
118     eflash_priv->cb = cb_event;
119     eflash_priv->status.busy = 0;
120     eflash_priv->status.error = 0U;
121     eflash_priv->eflashinfo.sector_size = EFLASH_SECTOR_SIZE;
122     eflash_priv->eflashinfo.page_size = EFLASH_PAGE_SIZE;
123     eflash_priv->eflashinfo.program_unit = EFLASH_PROGRAM_UINT;
124     eflash_priv->eflashinfo.erased_value = EFLASH_ERASED_VALUE;
125 
126     return (eflash_handle_t)eflash_priv;
127 }
128 
129 /**
130   \brief       De-initialize EFLASH Interface. stops operation and releases the software resources used by the interface
131   \param[in]   handle  eflash handle to operate.
132   \return      error code
133 */
csi_eflash_uninitialize(eflash_handle_t handle)134 int32_t csi_eflash_uninitialize(eflash_handle_t handle)
135 {
136     EFLASH_NULL_PARAM_CHK(handle);
137 
138     ck_eflash_priv_t *eflash_priv = handle;
139     eflash_priv->cb = NULL;
140 
141     return 0;
142 }
143 
144 /**
145   \brief       Get driver capabilities.
146   \param[in]   eflash handle to operate.
147   \return      \ref eflash_capabilities_t
148 */
csi_eflash_get_capabilities(eflash_handle_t handle)149 eflash_capabilities_t csi_eflash_get_capabilities(eflash_handle_t handle)
150 {
151     return driver_capabilities;
152 }
153 
154 /**
155   \brief       Read data from Flash.
156   \param[in]   handle  eflash handle to operate.
157   \param[in]   addr  Data address.
158   \param[out]  data  Pointer to a buffer storing the data read from Flash.
159   \param[in]   cnt   Number of data items to read.
160   \return      number of data items read or error code
161 */
csi_eflash_read(eflash_handle_t handle,uint32_t addr,void * data,uint32_t cnt)162 int32_t csi_eflash_read(eflash_handle_t handle, uint32_t addr, void *data, uint32_t cnt)
163 {
164     EFLASH_NULL_PARAM_CHK(handle);
165     EFLASH_NULL_PARAM_CHK(data);
166     EFLASH_NULL_PARAM_CHK(cnt);
167     if (!IS_EFLASH_ADDR(addr) || !(IS_EFLASH_ADDR(addr + cnt -1))) {
168         return ERR_EFLASH(EDRV_PARAMETER);
169     }
170 
171     volatile uint8_t *src_addr = (uint8_t *)addr;
172     ck_eflash_priv_t *eflash_priv = handle;
173 
174     if (eflash_priv->status.busy) {
175         return ERR_EFLASH(EDRV_BUSY);
176     }
177 
178     eflash_priv->status.error = 0U;
179 
180     int i;
181     for (i = 0; i < cnt; i++) {
182         *((uint8_t *)data + i) = *(src_addr + i);
183     }
184 
185     return i;
186 }
187 
188 /**
189   \brief       Program data to Flash.
190   \param[in]   handle  eflash handle to operate.
191   \param[in]   addr  Data address.
192   \param[in]   data  Pointer to a buffer containing the data to be programmed to Flash..
193   \param[in]   cnt   Number of data items to program.
194   \return      number of data items programmed or error code
195 */
csi_eflash_program(eflash_handle_t handle,uint32_t addr,const void * data,uint32_t cnt)196 int32_t csi_eflash_program(eflash_handle_t handle, uint32_t addr, const void *data, uint32_t cnt)
197 {
198     EFLASH_NULL_PARAM_CHK(handle);
199     EFLASH_NULL_PARAM_CHK(data);
200     EFLASH_NULL_PARAM_CHK(cnt);
201     if (!IS_EFLASH_ADDR(addr) || !(IS_EFLASH_ADDR(addr + cnt -1))) {
202         return ERR_EFLASH(EDRV_PARAMETER);
203     }
204 
205     ck_eflash_priv_t *eflash_priv = handle;
206 
207     if ((addr & 0x3) || ((uint32_t)data & 0x3) || (cnt & 0x3)) {
208         return ERR_EFLASH(EDRV_PARAMETER);
209     }
210 
211     if (eflash_priv->status.busy) {
212         return ERR_EFLASH(EDRV_BUSY);
213     }
214 
215     eflash_priv->status.busy = 1U;
216     eflash_priv->status.error = 0U;
217     uint32_t ret = eflash_program_word(handle, addr, (uint32_t *)data, cnt >> 2);
218     eflash_priv->status.busy = 0U;
219 
220     return ret;
221 }
222 
223 /**
224   \brief       Erase Flash Sector.
225   \param[in]   handle  eflash handle to operate.
226   \param[in]   addr  Sector address
227   \return      error code
228 */
csi_eflash_erase_sector(eflash_handle_t handle,uint32_t addr)229 int32_t csi_eflash_erase_sector(eflash_handle_t handle, uint32_t addr)
230 {
231     EFLASH_NULL_PARAM_CHK(handle);
232     if (!IS_EFLASH_ADDR(addr)) {
233         return ERR_EFLASH(EDRV_PARAMETER);
234     }
235 
236     addr = addr & ~(EFLASH_SECTOR_SIZE - 1);
237     ck_eflash_priv_t *eflash_priv = handle;
238     uint32_t fbase = eflash_priv->base;
239 
240     if (eflash_priv->status.busy) {
241         return ERR_EFLASH(EDRV_BUSY);
242     }
243 
244     eflash_priv->status.busy = 1U;
245     eflash_priv->status.error = 0U;
246     *(volatile uint32_t *)(fbase + 0x4) = addr;
247     *(volatile uint32_t *)(fbase + 0x10) = 0x1;
248     eflash_priv->status.busy = 0U;
249 
250     return 0;
251 }
252 
253 /**
254   \brief       Erase complete Flash.
255   \param[in]   handle  eflash handle to operate.
256   \return      error code
257 */
csi_eflash_erase_chip(eflash_handle_t handle)258 int32_t csi_eflash_erase_chip(eflash_handle_t handle)
259 {
260     EFLASH_NULL_PARAM_CHK(handle);
261 
262     return ERR_EFLASH(EDRV_UNSUPPORTED);
263 }
264 
265 /**
266   \brief       Get Flash information.
267   \param[in]   handle  eflash handle to operate.
268   \return      Pointer to Flash information \ref eflash_info
269 */
csi_eflash_get_info(eflash_handle_t handle)270 eflash_info *csi_eflash_get_info(eflash_handle_t handle)
271 {
272     ck_eflash_priv_t *eflash_priv = handle;
273     eflash_info *eflash_info = &(eflash_priv->eflashinfo);
274 
275     return eflash_info;
276 }
277 
278 /**
279   \brief       Get EFLASH status.
280   \param[in]   handle  eflash handle to operate.
281   \return      EFLASH status \ref eflash_status_t
282 */
csi_eflash_get_status(eflash_handle_t handle)283 eflash_status_t csi_eflash_get_status(eflash_handle_t handle)
284 {
285     ck_eflash_priv_t *eflash_priv = handle;
286 
287     return eflash_priv->status;
288 }
289