]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/eflash/ck_eflash.c
Introduce a port for T-HEAD CK802. A simple demo for T-HEAD CB2201 is also included.
[freertos] / FreeRTOS / Demo / T-HEAD_CB2201_CDK / csi / csi_driver / csky / common / eflash / ck_eflash.c
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
23 #include <stdio.h>
24 #include <string.h>
25 #include "csi_core.h"
26 #include "drv_eflash.h"
27 #include "ck_eflash.h"
28
29
30 #define ERR_EFLASH(errno) (CSI_DRV_ERRNO_EFLASH_BASE | errno)
31 #define EFLASH_NULL_PARAM_CHK(para)                         \
32     do {                                        \
33         if (para == NULL) {                     \
34             return ERR_EFLASH(EDRV_PARAMETER);   \
35         }                                       \
36     } while (0)
37
38 typedef struct {
39     uint32_t base;
40     eflash_info_t eflashinfo;
41     eflash_event_cb_t cb;
42     eflash_status_t status;
43 } ck_eflash_priv_t;
44
45 extern int32_t target_get_eflash_count(void);
46 extern int32_t target_get_eflash(int32_t idx, uint32_t *base, eflash_info_t *info);
47
48 static ck_eflash_priv_t eflash_handle[CONFIG_EFLASH_NUM];
49 /* Driver Capabilities */
50 static const eflash_capabilities_t driver_capabilities = {
51     .event_ready = 1, /* event_ready */
52     .data_width = 2, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */
53     .erase_chip = 0  /* erase_chip */
54 };
55
56 //
57 // Functions
58 //
59
60 static int32_t eflash_program_word(eflash_handle_t handle, uint32_t dstaddr, uint32_t *srcbuf, uint32_t len)
61 {
62     ck_eflash_priv_t *eflash_priv = handle;
63     uint32_t fbase = eflash_priv->base;
64     uint32_t i;
65
66     for (i = 0; i < len; i++) {
67         *(volatile uint32_t *)(fbase + 0x04) = dstaddr;
68         *(volatile uint32_t *)(fbase + 0x1c) = *srcbuf;
69         *(volatile uint32_t *)(fbase + 0x18) = 1;
70         srcbuf++;
71         dstaddr += 4;
72     }
73
74     return (i << 2);
75 }
76
77
78 #ifdef CONFIG_CHIP_CH2201
79 static uint32_t context[EFLASH_SECTOR_SIZE >> 2] = {0x0};
80 static int32_t eflash_verify(eflash_handle_t handle, uint32_t addr, const void *data, uint32_t cnt)
81 {
82     uint32_t i;
83     uint8_t error_flag = 1;
84
85     uint8_t *block_addr = (uint8_t *)(addr & ~(EFLASH_SECTOR_SIZE - 1));
86     uint32_t pre_offset = addr - (uint32_t)block_addr;
87     uint32_t pre_count = (cnt > (EFLASH_SECTOR_SIZE - pre_offset)) ? (EFLASH_SECTOR_SIZE - pre_offset) : cnt;
88
89     uint8_t *p = NULL;
90     uint8_t *dst = NULL;
91
92     p = (uint8_t *)data;
93     dst = (uint8_t *)addr;
94     uint32_t len = cnt;
95     volatile uint8_t verify_count = 100;
96
97     while (error_flag) {
98         for (i = 0; i < pre_count; i++) {
99             if (*((uint8_t *)dst + i) != *((uint8_t *)p + i)) {
100                 *(volatile uint32_t *) 0x50004000 = 'E';        /* for debug */
101                 *(volatile uint32_t *) 0x50004000 = 'E';
102                 *(volatile uint32_t *) 0x50004000 = 'E';
103                 *(volatile uint32_t *) 0x50004000 = 'E';
104                 *(volatile uint32_t *) 0x50004000 = '\n';
105                 memcpy(context, block_addr, EFLASH_SECTOR_SIZE);
106                 memcpy((uint8_t *)context + pre_offset, p, pre_count);
107                 csi_eflash_erase_sector(handle, (uint32_t)dst);
108                 eflash_program_word(handle, (uint32_t)block_addr, context, EFLASH_SECTOR_SIZE >> 2);
109                 break;
110             }
111         }
112
113         if (i == pre_count || !(verify_count--)) {
114             error_flag = 0;
115         }
116     }
117
118     if (!verify_count) {
119         return ERR_EFLASH(EDRV_TIMEOUT);
120     }
121     verify_count = 100;
122
123     error_flag = 1;
124     p += pre_count;
125     dst += pre_count;
126     len -= pre_count;
127
128     while (len >= EFLASH_SECTOR_SIZE) {
129         while (error_flag) {
130             for (i = 0; i < EFLASH_SECTOR_SIZE; i++) {
131                 if (*((uint8_t *)dst + i) != *((uint8_t *)p + i)) {
132                     *(volatile uint32_t *) 0x50004000 = 'E';        /* for debug */
133                     *(volatile uint32_t *) 0x50004000 = 'E';
134                     *(volatile uint32_t *) 0x50004000 = 'E';
135                     *(volatile uint32_t *) 0x50004000 = 'E';
136                     *(volatile uint32_t *) 0x50004000 = '\n';
137                     memcpy((uint8_t *)context, p, EFLASH_SECTOR_SIZE);
138                     csi_eflash_erase_sector(handle, (uint32_t)dst);
139                     eflash_program_word(handle, (uint32_t)dst, context, EFLASH_SECTOR_SIZE >> 2);
140                     break;
141                 }
142             }
143
144             if (i == EFLASH_SECTOR_SIZE || !(verify_count--)) {
145                 error_flag = 0;
146             }
147         }
148
149         if (!verify_count) {
150             return ERR_EFLASH(EDRV_TIMEOUT);
151         }
152
153         verify_count = 100;
154
155         error_flag = 1;
156         dst += EFLASH_SECTOR_SIZE;
157         p += EFLASH_SECTOR_SIZE;
158         len -= EFLASH_SECTOR_SIZE;
159     }
160
161     if (len > 0) {
162         while (error_flag) {
163             for (i = 0; i < len; i++) {
164                 if (*((uint8_t *)dst + i) != *((uint8_t *)p + i)) {
165                     *(volatile uint32_t *) 0x50004000 = 'E';        /* for debug */
166                     *(volatile uint32_t *) 0x50004000 = 'E';
167                     *(volatile uint32_t *) 0x50004000 = 'E';
168                     *(volatile uint32_t *) 0x50004000 = 'E';
169                     *(volatile uint32_t *) 0x50004000 = '\n';
170                     memcpy(context, dst, EFLASH_SECTOR_SIZE);
171                     memcpy((uint8_t *)context + i, p + i, len - i);
172                     csi_eflash_erase_sector(handle, (uint32_t)dst);
173                     eflash_program_word(handle, (uint32_t)dst, context, EFLASH_SECTOR_SIZE >> 2);
174                     break;
175                 }
176             }
177
178             if (i == len || !(verify_count--)) {
179                 error_flag = 0;
180             }
181         }
182
183         if (!verify_count) {
184             return ERR_EFLASH(EDRV_TIMEOUT);
185         }
186
187         verify_count = 100;
188     }
189
190     return 0;
191 }
192 #endif
193
194 /**
195   \brief       Initialize EFLASH Interface. 1. Initializes the resources needed for the EFLASH interface 2.registers event callback function
196   \param[in]   idx device id
197   \param[in]   cb_event  Pointer to \ref eflash_event_cb_t
198   \return      pointer to eflash handle
199 */
200 eflash_handle_t csi_eflash_initialize(int32_t idx, eflash_event_cb_t cb_event)
201 {
202     if (idx < 0 || idx >= CONFIG_EFLASH_NUM) {
203         return NULL;
204     }
205
206     /* obtain the eflash information */
207     uint32_t base = 0u;
208     eflash_info_t info;
209     int32_t real_idx = target_get_eflash(idx, &base, &info);
210
211     if (real_idx != idx) {
212         return NULL;
213     }
214
215     ck_eflash_priv_t *eflash_priv = &eflash_handle[idx];
216
217     eflash_priv->base = base;
218     eflash_priv->eflashinfo.start = info.start;
219     eflash_priv->eflashinfo.end = info.end;
220     eflash_priv->eflashinfo.sector_count = info.sector_count;
221
222     /* initialize the eflash context */
223     eflash_priv->cb = cb_event;
224     eflash_priv->status.busy = 0;
225     eflash_priv->status.error = 0U;
226     eflash_priv->eflashinfo.sector_size = EFLASH_SECTOR_SIZE;
227     eflash_priv->eflashinfo.page_size = EFLASH_PAGE_SIZE;
228     eflash_priv->eflashinfo.program_unit = EFLASH_PROGRAM_UINT;
229     eflash_priv->eflashinfo.erased_value = EFLASH_ERASED_VALUE;
230
231     return (eflash_handle_t)eflash_priv;
232 }
233
234 /**
235   \brief       De-initialize EFLASH Interface. stops operation and releases the software resources used by the interface
236   \param[in]   handle  eflash handle to operate.
237   \return      error code
238 */
239 int32_t csi_eflash_uninitialize(eflash_handle_t handle)
240 {
241     EFLASH_NULL_PARAM_CHK(handle);
242
243     ck_eflash_priv_t *eflash_priv = handle;
244     eflash_priv->cb = NULL;
245
246     return 0;
247 }
248
249 /**
250   \brief       Get driver capabilities.
251   \param[in]   idx device id
252   \return      \ref eflash_capabilities_t
253 */
254 eflash_capabilities_t csi_eflash_get_capabilities(eflash_handle_t handle)
255 {
256     return driver_capabilities;
257 }
258
259 /**
260   \brief       Read data from Flash.
261   \param[in]   handle  eflash handle to operate.
262   \param[in]   addr  Data address.
263   \param[out]  data  Pointer to a buffer storing the data read from Flash.
264   \param[in]   cnt   Number of data items to read.
265   \return      number of data items read or error code
266 */
267 int32_t csi_eflash_read(eflash_handle_t handle, uint32_t addr, void *data, uint32_t cnt)
268 {
269     EFLASH_NULL_PARAM_CHK(handle);
270     EFLASH_NULL_PARAM_CHK(data);
271     EFLASH_NULL_PARAM_CHK(cnt);
272
273     volatile uint8_t *src_addr = (uint8_t *)addr;
274     ck_eflash_priv_t *eflash_priv = handle;
275
276     if (eflash_priv->eflashinfo.start > addr || eflash_priv->eflashinfo.end < addr || eflash_priv->eflashinfo.start > (addr + cnt - 1) || eflash_priv->eflashinfo.end < (addr + cnt - 1)) {
277         return ERR_EFLASH(EDRV_PARAMETER);
278     }
279
280     if (eflash_priv->status.busy) {
281         return ERR_EFLASH(EDRV_BUSY);
282     }
283
284     eflash_priv->status.error = 0U;
285
286     int i;
287
288     for (i = 0; i < cnt; i++) {
289         *((uint8_t *)data + i) = *(src_addr + i);
290     }
291
292     return i;
293 }
294
295 /**
296   \brief       Program data to Flash.
297   \param[in]   handle  eflash handle to operate.
298   \param[in]   addr  Data address.
299   \param[in]   data  Pointer to a buffer containing the data to be programmed to Flash..
300   \param[in]   cnt   Number of data items to program.
301   \return      number of data items programmed or error code
302 */
303 int32_t csi_eflash_program(eflash_handle_t handle, uint32_t addr, const void *data, uint32_t cnt)
304 {
305     EFLASH_NULL_PARAM_CHK(handle);
306     EFLASH_NULL_PARAM_CHK(data);
307     EFLASH_NULL_PARAM_CHK(cnt);
308
309     ck_eflash_priv_t *eflash_priv = handle;
310
311     if (eflash_priv->eflashinfo.start > addr || eflash_priv->eflashinfo.end < addr || eflash_priv->eflashinfo.start > (addr + cnt - 1) || eflash_priv->eflashinfo.end < (addr + cnt - 1)) {
312         return ERR_EFLASH(EDRV_PARAMETER);
313     }
314
315     uint32_t cur = 0;
316     uint32_t pad_buf;
317
318     if (addr & 0x3) {
319         return ERR_EFLASH(EDRV_PARAMETER);
320     }
321
322     if (eflash_priv->status.busy) {
323         return ERR_EFLASH(EDRV_BUSY);
324     }
325
326     eflash_priv->status.busy = 1U;
327     eflash_priv->status.error = 0U;
328
329     if (((uint32_t)data & 0x3) == 0) {
330         cur = cnt - (cnt & 0x3);
331         eflash_program_word(handle, addr, (uint32_t *)data, cur >> 2);
332     } else {
333         uint8_t *buffer_b = (uint8_t *)data;
334
335         for (; cur < cnt - 3; cur += 4, buffer_b += 4) {
336             pad_buf = buffer_b[0] | (buffer_b[1] << 8) | (buffer_b[2] << 16) | (buffer_b[3] << 24);
337             eflash_program_word(handle, addr + cur, &pad_buf, 1);
338         }
339     }
340
341     if (cur < cnt) {
342         pad_buf = *((volatile uint32_t *)(addr + cur));
343         uint8_t *pad = (uint8_t *)&pad_buf;
344         uint8_t *buff = (uint8_t *)data;
345         uint8_t i;
346
347         for (i = 0; i < (cnt - cur); i++) {
348             pad[i] = buff[cur + i];
349         }
350
351         eflash_program_word(handle, addr + cur, &pad_buf, 1);
352     }
353
354
355     eflash_priv->status.busy = 0U;
356 #ifdef CONFIG_CHIP_CH2201
357     eflash_verify(handle, addr, data, cnt);
358 #endif
359
360     return cnt;
361 }
362
363 /**
364   \brief       Erase Flash Sector.
365   \param[in]   handle  eflash handle to operate.
366   \param[in]   addr  Sector address
367   \return      error code
368 */
369 int32_t csi_eflash_erase_sector(eflash_handle_t handle, uint32_t addr)
370 {
371     EFLASH_NULL_PARAM_CHK(handle);
372
373     ck_eflash_priv_t *eflash_priv = handle;
374
375     if (eflash_priv->eflashinfo.start > addr || eflash_priv->eflashinfo.end < addr) {
376         return ERR_EFLASH(EDRV_PARAMETER);
377     }
378
379
380     addr = addr & ~(EFLASH_SECTOR_SIZE - 1);
381     uint32_t fbase = eflash_priv->base;
382
383     if (eflash_priv->status.busy) {
384         return ERR_EFLASH(EDRV_BUSY);
385     }
386
387     eflash_priv->status.busy = 1U;
388     eflash_priv->status.error = 0U;
389     *(volatile uint32_t *)(fbase + 0x4) = addr;
390     *(volatile uint32_t *)(fbase + 0x10) = 0x1;
391     eflash_priv->status.busy = 0U;
392
393     return 0;
394 }
395
396 /**
397   \brief       Erase complete Flash.
398   \param[in]   handle  eflash handle to operate.
399   \return      error code
400 */
401 int32_t csi_eflash_erase_chip(eflash_handle_t handle)
402 {
403     EFLASH_NULL_PARAM_CHK(handle);
404
405     return ERR_EFLASH(EDRV_UNSUPPORTED);
406 }
407
408 /**
409   \brief       Get Flash information.
410   \param[in]   handle  eflash handle to operate.
411   \return      Pointer to Flash information \ref eflash_info_t
412 */
413 eflash_info_t *csi_eflash_get_info(eflash_handle_t handle)
414 {
415     if (handle == NULL) {
416         return NULL;
417     }
418
419     ck_eflash_priv_t *eflash_priv = handle;
420     eflash_info_t *eflash_info = &(eflash_priv->eflashinfo);
421
422     return eflash_info;
423 }
424
425 /**
426   \brief       Get EFLASH status.
427   \param[in]   handle  eflash handle to operate.
428   \return      EFLASH status \ref eflash_status_t
429 */
430 eflash_status_t csi_eflash_get_status(eflash_handle_t handle)
431 {
432     if (handle == NULL) {
433         eflash_status_t ret;
434         memset(&ret, 0, sizeof(eflash_status_t));
435         return ret;
436     }
437
438     ck_eflash_priv_t *eflash_priv = handle;
439
440     return eflash_priv->status;
441 }