1 /**
2  * @file xmc_fce.c
3  * @date 2019-03-30
4  *
5  * @cond
6  *********************************************************************************************************************
7  * XMClib v2.1.24 - XMC Peripheral Driver Library
8  *
9  * Copyright (c) 2015-2019, Infineon Technologies AG
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
13  * following conditions are met:
14  *
15  * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
16  * disclaimer.
17  *
18  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
19  * disclaimer in the documentation and/or other materials provided with the distribution.
20  *
21  * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes with
33  * Infineon Technologies AG dave@infineon.com).
34  *********************************************************************************************************************
35  *
36  * Change History
37  * --------------
38  *
39  * 2015-02-20:
40  *     - Initial <br>
41  *
42  * 2015-06-20:
43  *     - Removed GetDriverVersion API
44  *
45  * 2017-12-14:
46  *     - XMC_FCE_CalculateCRC8()
47  *       Ensure 32bit access to IR register
48  *     - XMC_FCE_CalculateCRC16()
49  *       Ensure 32bit access to IR register
50  *       Remove restriction on data source allignment
51  *     - XMC_FCE_CalculateCRC32()
52  *       Ensure 32bit access to IR register
53  *       Remove restriction on data source allignment
54  *
55  * 2019-03-30:
56  *     - Added XMC_FCE_CalculateCRC16Ex() and XMC_FCE_CalculateCRC32Ex()
57  *
58  * @endcond
59  *
60  */
61 
62 /**********************************************************************************************************************
63  * HEADER FILES
64  *********************************************************************************************************************/
65 #include <xmc_fce.h>
66 
67 #if defined (FCE)
68 #include <xmc_scu.h>
69 
70 /*******************************************************************************
71  * API IMPLEMENTATION
72  *********************************************************************************************************************/
73 
74 /*
75  * Initialize the FCE peripheral:
76  * Update FCE configuration and initialize seed value
77  */
XMC_FCE_Init(const XMC_FCE_t * const engine)78 XMC_FCE_STATUS_t XMC_FCE_Init(const XMC_FCE_t *const engine)
79 {
80   engine->kernel_ptr->CFG = engine->fce_cfg_update.regval;
81   engine->kernel_ptr->CRC = engine->seedvalue;
82 
83   return XMC_FCE_STATUS_OK;
84 }
85 
86 /* Disable FCE */
XMC_FCE_Disable(void)87 void XMC_FCE_Disable(void)
88 {
89   FCE->CLC |= (uint32_t)FCE_CLC_DISR_Msk;
90 
91   XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_FCE);
92 
93 #if defined(CLOCK_GATING_SUPPORTED)
94   XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_FCE);
95 #endif
96 
97 }
98 
99 /* Enable FCE */
XMC_FCE_Enable(void)100 void XMC_FCE_Enable(void)
101 {
102 #if defined(CLOCK_GATING_SUPPORTED)
103   XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_FCE);
104 #endif
105 
106   XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_FCE);
107 
108   FCE->CLC &= (uint32_t)~FCE_CLC_DISR_Msk;
109 }
110 
111 /* Calculate and return the SAE J1850 CRC8 checksum */
XMC_FCE_CalculateCRC8(const XMC_FCE_t * const engine,const uint8_t * data,uint32_t length,uint8_t * result)112 XMC_FCE_STATUS_t XMC_FCE_CalculateCRC8(const XMC_FCE_t *const engine,
113                                        const uint8_t *data,
114 									   uint32_t length,
115 									   uint8_t *result)
116 {
117   XMC_FCE_STATUS_t status = XMC_FCE_STATUS_OK;
118 
119   XMC_ASSERT("XMC_FCE_CalculateCRC8: Wrong FCE kernel used", (engine -> kernel_ptr == XMC_FCE_CRC8));
120 
121   if (length == 0UL)
122   {
123     status = XMC_FCE_STATUS_ERROR;
124   }
125   else
126   {
127     while (0UL != length)
128     {
129       engine->kernel_ptr->IR = (uint32_t)*data;
130       data++;
131       length -= 1U;
132     }
133 
134     *result = (uint8_t)engine->kernel_ptr->CRC;
135   }
136 
137   return status;
138 }
139 
140 /* Calculate and return calculated CCITT CRC16 checksum */
XMC_FCE_CalculateCRC16(const XMC_FCE_t * const engine,const uint16_t * data,uint32_t length,uint16_t * result)141 XMC_FCE_STATUS_t XMC_FCE_CalculateCRC16(const XMC_FCE_t *const engine,
142                                         const uint16_t *data,
143 										uint32_t length,
144 										uint16_t *result)
145 {
146   XMC_FCE_STATUS_t status = XMC_FCE_STATUS_OK;
147 
148   XMC_ASSERT("XMC_FCE_CalculateCRC16: Wrong FCE kernel used", (engine -> kernel_ptr == XMC_FCE_CRC16));
149   XMC_ASSERT("XMC_FCE_CalculateCRC16: Length field is empty", (length != 0));
150   XMC_ASSERT("XMC_FCE_CalculateCRC16: Length is not aligned", ((length & 0x1U) == 0));
151 
152   /* Check length is a multiple of 2 */
153   if ((length == 0) || ((length & 0x1U) != 0U))
154   {
155     status = XMC_FCE_STATUS_ERROR;
156   }
157   else
158   {
159     while (0UL != length)
160     {
161       engine->kernel_ptr->IR = (uint32_t)*data;
162       data++;
163       length -= 2U;
164     }
165 
166     *result = (uint16_t)engine->kernel_ptr->CRC;
167   }
168 
169   return status;
170 }
171 
XMC_FCE_CalculateCRC16Ex(const XMC_FCE_t * const engine,const uint8_t * data,uint32_t length,uint16_t * const result)172 XMC_FCE_STATUS_t XMC_FCE_CalculateCRC16Ex(const XMC_FCE_t *const engine,
173                                           const uint8_t *data,
174 										                      uint32_t length,
175 										                      uint16_t *const result)
176 {
177   XMC_FCE_STATUS_t status = XMC_FCE_STATUS_OK;
178 
179   XMC_ASSERT("XMC_FCE_CalculateCRC16: Wrong FCE kernel used", (engine -> kernel_ptr == XMC_FCE_CRC16));
180   XMC_ASSERT("XMC_FCE_CalculateCRC16: Length field is empty", (length != 0));
181   XMC_ASSERT("XMC_FCE_CalculateCRC16: Length is not aligned", ((length & 0x1U) == 0));
182 
183   /* Check length is a multiple of 2 */
184   if ((length == 0) || ((length & 0x1U) != 0U))
185   {
186     status = XMC_FCE_STATUS_ERROR;
187   }
188   else
189   {
190     const uint16_t *p = (const uint16_t *)data;
191     while (0UL != length)
192     {
193       engine->kernel_ptr->IR = __REV16(*p);
194       ++p;
195       length -= 2U;
196     }
197 
198     *result = (uint16_t)engine->kernel_ptr->CRC;
199   }
200 
201   return status;
202 }
203 
204 /* Calculate and return the IEEE 802.3 Ethernet CRC32 checksum */
XMC_FCE_CalculateCRC32(const XMC_FCE_t * const engine,const uint32_t * data,uint32_t length,uint32_t * result)205 XMC_FCE_STATUS_t XMC_FCE_CalculateCRC32(const XMC_FCE_t *const engine,
206                                         const uint32_t *data,
207 										uint32_t length,
208 										uint32_t *result)
209 {
210   XMC_FCE_STATUS_t status = XMC_FCE_STATUS_OK;
211 
212   XMC_ASSERT("XMC_FCE_CalculateCRC32: Wrong FCE kernel used", ((engine->kernel_ptr == XMC_FCE_CRC32_0) ||
213                                                                (engine->kernel_ptr == XMC_FCE_CRC32_1)));
214   XMC_ASSERT("XMC_FCE_CalculateCRC32: Length field is empty", (length != 0));
215   XMC_ASSERT("XMC_FCE_CalculateCRC32: Length is not aligned", ((length & 0x3U) == 0));
216 
217   /* Check length is a multiple of 4 */
218   if ((length == 0) || ((length & 0x3U) != 0U))
219   {
220     status = XMC_FCE_STATUS_ERROR;
221   }
222   else
223   {
224     while (0UL != length)
225     {
226       engine->kernel_ptr->IR = *data;
227       data++;
228       length -= 4U;
229     }
230 
231     *result = engine->kernel_ptr->CRC;
232   }
233 
234   return status;
235 }
236 
237 /* Calculate and return the IEEE 802.3 Ethernet CRC32 checksum */
XMC_FCE_CalculateCRC32Ex(const XMC_FCE_t * const engine,const uint8_t * data,uint32_t length,uint32_t * const result)238 XMC_FCE_STATUS_t XMC_FCE_CalculateCRC32Ex(const XMC_FCE_t *const engine,
239                                           const uint8_t *data,
240 										                      uint32_t length,
241 										                      uint32_t *const result)
242 {
243   XMC_FCE_STATUS_t status = XMC_FCE_STATUS_OK;
244 
245   XMC_ASSERT("XMC_FCE_CalculateCRC32: Wrong FCE kernel used", ((engine->kernel_ptr == XMC_FCE_CRC32_0) ||
246                                                                (engine->kernel_ptr == XMC_FCE_CRC32_1)));
247   XMC_ASSERT("XMC_FCE_CalculateCRC32: Length field is empty", (length != 0));
248   XMC_ASSERT("XMC_FCE_CalculateCRC32: Length is not aligned", ((length & 0x3U) == 0));
249 
250   /* Check length is a multiple of 4 */
251   if ((length == 0) || ((length & 0x3U) != 0U))
252   {
253     status = XMC_FCE_STATUS_ERROR;
254   }
255   else
256   {
257     const uint32_t *p = (const uint32_t *)data;
258     while (0UL != length)
259     {
260       engine->kernel_ptr->IR = __REV(*p);
261       ++p;
262       length -= 4U;
263     }
264 
265     *result = engine->kernel_ptr->CRC;
266   }
267 
268   return status;
269 }
270 
271 /* Trigger mismatch in the CRC registers */
XMC_FCE_TriggerMismatch(const XMC_FCE_t * const engine,XMC_FCE_CTR_TEST_t test)272 void XMC_FCE_TriggerMismatch(const XMC_FCE_t *const engine, XMC_FCE_CTR_TEST_t test)
273 {
274   /* Create a 0 to 1 transition and clear to 0 once it is done */
275   engine->kernel_ptr->CTR &= ~((uint32_t)test);
276   engine->kernel_ptr->CTR |= (uint32_t)test;
277   engine->kernel_ptr->CTR &= ~((uint32_t)test);
278 }
279 
280 /* Change endianness of 16-bit input buffer */
XMC_FCE_LittleEndian16bit(uint8_t * inbuffer,uint16_t * outbuffer,uint16_t length)281 void XMC_FCE_LittleEndian16bit(uint8_t* inbuffer, uint16_t* outbuffer, uint16_t length)
282 {
283   uint16_t counter = 0U;
284   uint16_t bytecounter = 0U;
285 
286   if ((length & 0x01U)  == 0)
287   {
288     for (counter = 0U; counter < (length >> 1); counter++)
289     {
290       outbuffer[counter] = 0U;
291     }
292 
293     outbuffer[counter] = 0U;
294     counter = 0U;
295 
296     while (length)
297     {
298       outbuffer[counter] = ((uint16_t)((uint16_t)inbuffer[bytecounter] << 8U) |
299                             (inbuffer[bytecounter + 1U]));
300       counter += 1U;
301       bytecounter += 2U;
302       length -= 2U;
303     }
304   }
305 }
306 
307 /* Change endianness of 32-bit input buffer */
XMC_FCE_LittleEndian32bit(uint8_t * inbuffer,uint32_t * outbuffer,uint16_t length)308 void XMC_FCE_LittleEndian32bit(uint8_t* inbuffer, uint32_t* outbuffer, uint16_t length)
309 {
310   uint16_t counter = 0U;
311   uint16_t bytecounter = 0U;
312 
313   if ((length & 0x03U) == 0)
314   {
315     for (counter = 0U; counter < (length >> 2U); counter++)
316     {
317       outbuffer[counter] = 0U;
318     }
319 
320     outbuffer[counter] = 0U;
321     counter = 0U;
322 
323     while (length)
324     {
325       outbuffer[counter] = ((uint32_t)inbuffer[bytecounter]      << 24U) |
326                            ((uint32_t)inbuffer[bytecounter + 1U] << 16U) |
327                            ((uint32_t)inbuffer[bytecounter + 2U] <<  8U) |
328                            (inbuffer[bytecounter + 3U]);
329       counter += 1U;
330       bytecounter += 4U;
331       length -= 4U;
332     }
333   }
334 }
335 
336 #endif
337