/******************************************************************************* * File Name : amt630hv120_crc.c * Author : Sim * Date First Issued : 12/28/2022 * Description : This file provides all the CRC firmware functions. ******************************************************************************** * History: * 12/28/2022: V0.1 *******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "chip.h" #include "crc.h" #define CRC_CTL_WIDTH32_START (1 << 10) #define CRC_CTL_WIDTH16_START (1 << 9) #define CRC_CTL_WIDTH8_START (1 << 8) #define CRC_CTL_INIT_EN (1 << 6) #define CRC_CTL_VECTMASK (3 << 2) #define CRC_CTL_VECT32 (0 << 2) #define CRC_CTL_VECT16 (1 << 2) #define CRC_CTL_VECT8 (2 << 2) static u32 c_poly8_g = 0x0000008e; static u32 c_poly16_g = 0x00008810; static u32 c_poly32_g = 0x82608edb; typedef union { u8 *buf8; u16 *buf16; u32 *buf32; } CrcDataBuf; typedef struct { volatile u32 EN; volatile u32 CTRL; volatile u32 DATA; volatile u32 INIT; volatile u32 RET; } CRC_TypeDef; #define CRC ((CRC_TypeDef*)REGS_CRC_BASE) typedef u32 (*crc_algo)(const void *buf, u32 len, u32 init, CrcPoly polyopt, CrcDataWidth widthopt); static u32 crc_soft(const void *buf, u32 len, u32 init, CrcPoly polyopt, CrcDataWidth widthopt) { CrcDataBuf tmpbuf; u8 tmpbit; u32 tmp = init; u32 result; int i; u32 poly = c_poly32_g; u32 width = 32; u32 shift = 31; if (widthopt == CRC_DATA_WIDTH8) { tmpbuf.buf8 = (u8*)buf; width = 8; } else if (widthopt == CRC_DATA_WIDTH16) { assert((((u32)buf | len) & 1) == 0); tmpbuf.buf16 = (u16*)buf; width = 16; len /= 2; } else if (widthopt == CRC_DATA_WIDTH32) { assert((((u32)buf | len) & 3) == 0); tmpbuf.buf32 = (u32*)buf; width = 32; len /= 4; } if (polyopt == CRC_POLY8) { poly = c_poly8_g; shift = 7; } else if (polyopt == CRC_POLY16) { poly = c_poly16_g; shift = 15; } else if (polyopt == CRC_POLY32) { poly = c_poly32_g; shift = 31; } while (len--) { for (i = 0; i < width; i++) { if (widthopt == CRC_DATA_WIDTH8) tmpbit = ((tmp >> shift) ^ (*tmpbuf.buf8 >> i)) & 1; else if (widthopt == CRC_DATA_WIDTH16) tmpbit = ((tmp >> shift) ^ (*tmpbuf.buf16 >> i)) & 1; else if (widthopt == CRC_DATA_WIDTH32) tmpbit = ((tmp >> shift) ^ (*tmpbuf.buf32 >> i)) & 1; if (tmpbit) { result = ((((tmp << 1) >> 1) ^ ((poly << 1) >> 1)) << 1) | 1; } else { result = tmp << 1; } tmp = result; } if (widthopt == CRC_DATA_WIDTH8) tmpbuf.buf8++; else if (widthopt == CRC_DATA_WIDTH16) tmpbuf.buf16++; else if (widthopt == CRC_DATA_WIDTH32) tmpbuf.buf32++; } return result; } u32 CRC_Calc(const void *buf, u32 len, u32 init, CrcPoly polyopt, CrcDataWidth widthopt) { CrcDataBuf tmpbuf; u32 result; int i; if (widthopt == CRC_DATA_WIDTH8) { tmpbuf.buf8 = (u8*)buf; } else if (widthopt == CRC_DATA_WIDTH16) { assert((((u32)buf | len) & 1) == 0); tmpbuf.buf16 = (u16*)buf; len /= 2; } else if (widthopt == CRC_DATA_WIDTH32) { assert((((u32)buf | len) & 3) == 0); tmpbuf.buf32 = (u32*)buf; len /= 4; } // if (sema_take(SEMA_GATE_CRC, portMAX_DELAY) != pdPASS) { // return 0xffffffff; // } CRC->INIT = init; CRC->CTRL |= CRC_CTL_INIT_EN; CRC->CTRL &= ~CRC_CTL_INIT_EN; CRC->CTRL &= ~CRC_CTL_VECTMASK; if (polyopt == CRC_POLY8) CRC->CTRL |= CRC_CTL_VECT8; else if (polyopt == CRC_POLY16) CRC->CTRL |= CRC_CTL_VECT16; else if (polyopt == CRC_POLY32) CRC->CTRL |= CRC_CTL_VECT32; if (widthopt == CRC_DATA_WIDTH8) CRC->CTRL |= CRC_CTL_WIDTH8_START; else if (widthopt == CRC_DATA_WIDTH16) CRC->CTRL |= CRC_CTL_WIDTH16_START; if (widthopt == CRC_DATA_WIDTH32) CRC->CTRL |= CRC_CTL_WIDTH32_START; for (i = 0; i < len; i++) { if (widthopt == CRC_DATA_WIDTH8) CRC->DATA = tmpbuf.buf8[i]; else if (widthopt == CRC_DATA_WIDTH16) CRC->DATA = tmpbuf.buf16[i]; else if (widthopt == CRC_DATA_WIDTH32) CRC->DATA = tmpbuf.buf32[i]; } udelay(10); result = CRC->RET; if (widthopt == CRC_DATA_WIDTH8) CRC->CTRL &= ~CRC_CTL_WIDTH8_START; else if (widthopt == CRC_DATA_WIDTH16) CRC->CTRL &= ~CRC_CTL_WIDTH16_START; if (widthopt == CRC_DATA_WIDTH32) CRC->CTRL &= ~CRC_CTL_WIDTH32_START; // sema_give(SEMA_GATE_CRC); return result; } static u32 crc_align(const void *buf, u32 len, u32 init, CrcPoly polyopt, int hardaccel) { const u32 *buf32; const u8 *buf8; u32 leftsize = len; u32 size; u32 align; u32 crc = init; crc_algo algo; if (hardaccel) algo = CRC_Calc; else algo = crc_soft; align = (u32)buf & 3; size = 4 - align; size = size > leftsize ? leftsize : size; if (align) { crc = algo(buf, size, init, polyopt, CRC_DATA_WIDTH8); leftsize -= size; buf32 = (u32*)((u8*)buf + size); } else { buf32 = (u32*)buf; } if (leftsize == 0) return crc; align = leftsize & 3; size = leftsize & ~3; if (size) crc = algo(buf32, size, crc, polyopt, CRC_DATA_WIDTH32); buf8 = (u8*)buf32 + size; if (align) crc = algo(buf8, align, crc, polyopt, CRC_DATA_WIDTH8); return crc; } u32 xcrc32(const void *buf, u32 len, u32 init, CrcSel hardaccel) { return crc_align(buf, len, init, CRC_POLY32, hardaccel); } u16 xcrc16(const void *buf, u32 len, u32 init, CrcSel hardaccel) { return crc_align(buf, len, init, CRC_POLY16, hardaccel) & 0xffff; } u16 xcrc8(const void *buf, u32 len, u32 init, CrcSel hardaccel) { return crc_align(buf, len, init, CRC_POLY8, hardaccel) & 0xff; }