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 /******************************************************************************
18  * @file     ck_crc.c
19  * @brief    CSI Source File for CRC Driver
20  * @version  V1.0
21  * @date     02. June 2017
22  ******************************************************************************/
23 #include <stdio.h>
24 #include "drv_crc.h"
25 #include "ck_crc.h"
26 
27 #define ERR_CRC(errno) (CSI_DRV_ERRNO_CRC_BASE | errno)
28 #define CRC_NULL_PARAM_CHK(para)                         \
29         do {                                        \
30             if (para == NULL) {                     \
31                 return ERR_CRC(EDRV_PARAMETER);   \
32             }                                       \
33         } while (0)
34 
35 typedef struct {
36     uint32_t base;
37     crc_event_cb_t cb;
38     crc_status_t status;
39 } ck_crc_priv_t;
40 
41 
42 static ck_crc_priv_t crc_handle[CONFIG_CRC_NUM];
43 /* Driver Capabilities */
44 static const crc_capabilities_t driver_capabilities = {
45     .ROHC = 1, /* ROHC mode */
46     .MAXIM = 1, /* MAXIM mode */
47     .X25 = 1, /* X25 mode */
48     .CCITT = 1, /* CCITT mode */
49     .USB = 1, /* USB mode */
50     .IBM = 1, /* IBM mode */
51     .MODBUS = 1  /* MODBUS mode */
52 };
53 
54 //
55 // Functions
56 //
57 
58 static ck_crc_reg_t *crc_reg = NULL;
59 
crc_set_mode(crc_mode_e mode,crc_standard_crc_e standard)60 static int32_t crc_set_mode(crc_mode_e mode, crc_standard_crc_e standard)
61 {
62     if (mode == CRC_MODE_CRC16) {
63         switch (standard) {
64             case CRC_STANDARD_CRC_MODBUS:
65                 crc_reg->CRC_SEL = 0x0;
66                 crc_reg->CRC_INIT = 0xffff;
67                 break;
68 
69             case CRC_STANDARD_CRC_IBM:
70                 crc_reg->CRC_SEL = 0x0;
71                 crc_reg->CRC_INIT = 0x0;
72                 break;
73 
74             case CRC_STANDARD_CRC_MAXIM:
75                 crc_reg->CRC_SEL = 0x4;
76                 crc_reg->CRC_INIT = 0x0;
77                 break;
78 
79             case CRC_STANDARD_CRC_USB:
80                 crc_reg->CRC_SEL = 0x4;
81                 crc_reg->CRC_INIT = 0xffff;
82                 break;
83 
84             case CRC_STANDARD_CRC_CCITT:
85                 crc_reg->CRC_SEL = 0x1;
86                 crc_reg->CRC_INIT = 0x0;
87                 break;
88 
89             case CRC_STANDARD_CRC_X25:
90                 crc_reg->CRC_SEL = 0x5;
91                 crc_reg->CRC_INIT = 0xffff;
92                 break;
93 
94             default:
95                 return ERR_CRC(EDRV_PARAMETER);
96         }
97     } else if (mode == CRC_MODE_CRC8) {
98         switch (standard) {
99             case CRC_STANDARD_CRC_MAXIM:
100                 crc_reg->CRC_SEL = 0x2;
101                 crc_reg->CRC_INIT = 0x0;
102                 break;
103 
104             case CRC_STANDARD_CRC_ROHC:
105                 crc_reg->CRC_SEL = 0x3;
106                 crc_reg->CRC_INIT = 0xff;
107                 break;
108 
109             default:
110                 return ERR_CRC(EDRV_PARAMETER);
111         }
112     } else {
113         return ERR_CRC(EDRV_PARAMETER);
114     }
115 
116     return 0;
117 }
118 
crc_set_data(uint32_t data)119 static int32_t crc_set_data(uint32_t data)
120 {
121     crc_reg->CRC_DATA = data;
122     return 0;
123 }
124 
crc_get_data(uint32_t * data)125 static int32_t crc_get_data(uint32_t *data)
126 {
127     *data = crc_reg->CRC_DATA;
128     return 0;
129 }
130 
target_get_crc_count(void)131 int32_t __attribute__((weak)) target_get_crc_count(void)
132 {
133     return 0;
134 }
135 
target_get_crc(int32_t idx,uint32_t * base)136 int32_t __attribute__((weak)) target_get_crc(int32_t idx, uint32_t *base)
137 {
138     return NULL;
139 }
140 
141 /**
142   \brief       get crc handle count.
143   \return      crc handle count
144 */
csi_crc_get_instance_count(void)145 int32_t csi_crc_get_instance_count(void)
146 {
147     return target_get_crc_count();
148 }
149 
150 /**
151   \brief       Initialize CRC Interface. 1. Initializes the resources needed for the CRC interface 2.registers event callback function
152   \param[in]   idx must not exceed return value of csi_crc_get_handle_count()
153   \param[in]   cb_event  Pointer to \ref crc_event_cb_t
154   \return      return crc handle if success
155 */
csi_crc_initialize(int32_t idx,crc_event_cb_t cb_event)156 crc_handle_t csi_crc_initialize(int32_t idx, crc_event_cb_t cb_event)
157 {
158     if (idx < 0 || idx >= CONFIG_CRC_NUM) {
159         return NULL;
160     }
161 
162     /* obtain the crc information */
163     uint32_t base = 0u;
164     int32_t real_idx = target_get_crc(idx, &base);
165 
166     if (real_idx != idx) {
167         return NULL;
168     }
169 
170     ck_crc_priv_t *crc_priv = &crc_handle[idx];
171     crc_reg = (ck_crc_reg_t *)(crc_priv->base);
172 
173     crc_priv->base = base;
174     crc_priv->cb = cb_event;
175     crc_priv->status.busy = 0;
176 
177     return (crc_handle_t)crc_priv;
178 }
179 
180 /**
181   \brief       De-initialize CRC Interface. stops operation and releases the software resources used by the interface
182   \param[in]   handle  crc handle to operate.
183   \return      error code
184 */
csi_crc_uninitialize(crc_handle_t handle)185 int32_t csi_crc_uninitialize(crc_handle_t handle)
186 {
187     CRC_NULL_PARAM_CHK(handle);
188 
189     ck_crc_priv_t *crc_priv = handle;
190     crc_priv->cb = NULL;
191 
192     return 0;
193 }
194 
195 /**
196   \brief       Get driver capabilities.
197   \param[in]   handle crc handle to operate.
198   \return      \ref crc_capabilities_t
199 */
csi_crc_get_capabilities(crc_handle_t handle)200 crc_capabilities_t csi_crc_get_capabilities(crc_handle_t handle)
201 {
202     return driver_capabilities;
203 }
204 
205 /**
206   \brief       config crc mode.
207   \param[in]   handle  crc handle to operate.
208   \param[in]   mode      \ref crc_mode_e
209   \param[in]   standard  \ref crc_standard_crc_e
210   \return      error code
211 */
csi_crc_config(crc_handle_t handle,crc_mode_e mode,crc_standard_crc_e standard)212 int32_t csi_crc_config(crc_handle_t handle, crc_mode_e mode, crc_standard_crc_e standard)
213 {
214     CRC_NULL_PARAM_CHK(handle);
215 
216     /* set the crc mode */
217     uint32_t ret = crc_set_mode(mode, standard);
218 
219     return ret;
220 }
221 
222 /**
223   \brief       calculate crc.
224   \param[in]   handle  crc handle to operate.
225   \param[in]   in      Pointer to the input data
226   \param[out]  out     Pointer to the result.
227   \param[in]   len     intpu data len.
228   \return      error code
229 */
csi_crc_calculate(crc_handle_t handle,const void * in,void * out,uint32_t len)230 int32_t csi_crc_calculate(crc_handle_t handle, const void *in, void *out, uint32_t len)
231 {
232     CRC_NULL_PARAM_CHK(handle);
233     CRC_NULL_PARAM_CHK(in);
234     CRC_NULL_PARAM_CHK(out);
235     if (len <= 0) {
236         return ERR_CRC(EDRV_PARAMETER);
237     }
238 
239     ck_crc_priv_t *crc_priv = handle;
240     crc_reg = (ck_crc_reg_t *)(crc_priv->base);
241 
242     crc_priv->status.busy = 1;
243 
244     /* put the data int the register */
245     uint8_t cur;
246     uint8_t *p = (uint8_t *)in;
247     for (cur=0; cur<len - 3; cur += 4, p+=4) {
248         crc_set_data(p[0]
249                     | (p[1] << 8)
250                     | (p[2] << 16)
251                     | (p[3] << 24));
252     }
253     uint32_t data = 0;
254     uint8_t i;
255     if (cur < len) {
256         for (i=0; i<len-cur; i++) {
257             data |= (p[cur + i] << (i*8));
258         }
259         crc_set_data(data);
260     }
261 
262     crc_get_data((uint32_t *)out);
263     crc_priv->status.busy = 0;
264 
265     return 0;
266 }
267 
268 /**
269   \brief       Get CRC status.
270   \param[in]   handle  crc handle to operate.
271   \return      CRC status \ref crc_status_t
272 */
csi_crc_get_status(crc_handle_t handle)273 crc_status_t csi_crc_get_status(crc_handle_t handle)
274 {
275     ck_crc_priv_t *crc_priv = handle;
276     return crc_priv->status;
277 }
278