/** * @file hg_crc.c * @author LeonLeeV * @brief * @version * TXW80X; TXW81X; TXW82X * @date 2023-08-02 * * @copyright Copyright (c) 2023 * */ #include "typesdef.h" #include "list.h" #include "errno.h" #include "dev.h" #include "devid.h" #include "osal/string.h" #include "osal/semaphore.h" #include "osal/mutex.h" #include "osal/irq.h" #include "dev/crc/hg_crc.h" #include "hg_crc_hw.h" struct hgcrc_config { uint32 poly; uint32 poly_bits; uint32 init_val; uint32 xor_out; char ref_in; char ref_out; }; static const struct hgcrc_config tcpip_chksum = { .init_val = 0x0, .xor_out = 0x0, .poly = 0x0, .poly_bits = 0, .ref_in = 1, .ref_out = 1, }; static const struct hgcrc_config crc5_usb = { .init_val = 0x1f, .xor_out = 0x1f, .poly = 0x14, .poly_bits = 5, .ref_in = 1, .ref_out = 1, }; static const struct hgcrc_config crc7_mmc = { .init_val = 0x0, .xor_out = 0x0, .poly = 0x48, .poly_bits = 7, .ref_in = 0, .ref_out = 0, }; static const struct hgcrc_config crc8_maxim = { .init_val = 0x0, .xor_out = 0x0, .poly = 0x8C, .poly_bits = 8, .ref_in = 1, .ref_out = 1, }; static const struct hgcrc_config crc8 = { .init_val = 0x0, .xor_out = 0x0, .poly = 0xE0, .poly_bits = 8, .ref_in = 0, .ref_out = 0, }; static const struct hgcrc_config crc16 = { .init_val = 0x0, .xor_out = 0x0, .poly = 0xA001, .poly_bits = 16, .ref_in = 1, .ref_out = 1, }; static const struct hgcrc_config crc16_ccitt = { .init_val = 0x0, .xor_out = 0x0, .poly = 0x8408, .poly_bits = 16, .ref_in = 1, .ref_out = 1, }; static const struct hgcrc_config crc16_modbus = { .init_val = 0xFFFF, .xor_out = 0x0, .poly = 0xA001, .poly_bits = 16, .ref_in = 1, .ref_out = 1, }; static const struct hgcrc_config crc32_winrar = { .init_val = 0xFFFFFFFF, .xor_out = 0xFFFFFFFF, .poly = 0xEDB88320, .poly_bits = 32, .ref_in = 1, .ref_out = 1, }; static const struct hgcrc_config *hgcrc_cfg[CRC_TYPE_MAX] = { [CRC_TYPE_TCPIP_CHKSUM] = &tcpip_chksum, [CRC_TYPE_CRC5_USB] = &crc5_usb, [CRC_TYPE_CRC7_MMC] = &crc7_mmc, [CRC_TYPE_CRC8_MAXIM] = &crc8_maxim, [CRC_TYPE_CRC8] = &crc8, [CRC_TYPE_CRC16] = &crc16, [CRC_TYPE_CRC16_CCITT] = &crc16_ccitt, [CRC_TYPE_CRC16_MODBUS] = &crc16_modbus, [CRC_TYPE_CRC32_WINRAR] = &crc32_winrar, }; static void hg_crc_irq_handler(void *data) { struct hg_crc *crc = (struct hg_crc *)data; struct hg_crc_hw *hw = (struct hg_crc_hw *)crc->hw; hw->CRC_KST = LL_CRC_KST_DMA_PENDING_CLR; os_sema_up(&crc->done); } /** * CRC len 512KB for TXW81x/TXW82X» 64KB for TXW80x */ static int32 hg_crc_calc_continue(struct crc_dev *crc, struct crc_dev_req *req, uint32 *crc_value) { int32 tmo = 2000; int32 ret = 0; struct hg_crc *dev = (struct hg_crc *)crc; struct hg_crc_hw *hw = (struct hg_crc_hw *)dev->hw; hw->CRC_INIT = hw->CRC_OUT ^ hw->CRC_INV; /* kick */ #if defined(TXW80X) hw->DMA_ADDR = (uint32)req->data & 0x00FFFFFF; #else hw->DMA_ADDR = (uint32)req->data; #endif hw->DMA_LEN = req->len; ret = os_sema_down(&dev->done, tmo); *crc_value = hw->CRC_OUT; return ret > 0 ? RET_OK : RET_ERR; } int32 hg_crc5_usb_calc_nonos(struct crc_dev *crc, struct crc_dev_req *req, uint32 *crc_value, uint32 flags) { uint32 cfg_reg; struct hg_crc *dev = (struct hg_crc *)crc; struct hg_crc_hw *hw = (struct hg_crc_hw *)dev->hw; hw->CRC_CFG &= ~ LL_CRC_CFG_INT_EN; cfg_reg = LL_CRC_CFG_POLY_BITS(5) | LL_CRC_CFG_DMAWAIT_CLOCK(5); cfg_reg |= LL_CRC_CFG_BIT_ORDER_RIGHT; /* config */ hw->CRC_INIT = 0x1f; hw->CRC_INV = 0x1f; hw->CRC_POLY = 0x14; hw->CRC_CFG = cfg_reg; /* kick */ #if defined(TXW80X) hw->DMA_ADDR = (uint32)req->data & 0x00FFFFFF; #else hw->DMA_ADDR = (uint32)req->data; #endif hw->DMA_LEN = req->len; while(!(hw->CRC_STA & LL_CRC_STA_DMA_PENDING)); hw->CRC_KST = LL_CRC_KST_DMA_PENDING_CLR; *crc_value = hw->CRC_OUT; hw->CRC_CFG |= LL_CRC_CFG_INT_EN; return 0; } int32 hg_crc8_calc_nonos(struct crc_dev *crc, struct crc_dev_req *req, uint32 *crc_value, uint32 flags) { uint32 cfg_reg; struct hg_crc *dev = (struct hg_crc *)crc; struct hg_crc_hw *hw = (struct hg_crc_hw *)dev->hw; hw->CRC_CFG &= ~ LL_CRC_CFG_INT_EN; cfg_reg = LL_CRC_CFG_POLY_BITS(8) | LL_CRC_CFG_DMAWAIT_CLOCK(5); cfg_reg |= LL_CRC_CFG_BIT_ORDER_LEFT; /* config */ hw->CRC_INIT = 0x0; hw->CRC_INV = 0x0; hw->CRC_POLY = 0xE0; hw->CRC_CFG = cfg_reg; /* kick */ #if defined(TXW80X) hw->DMA_ADDR = (uint32)req->data & 0x00FFFFFF; #else hw->DMA_ADDR = (uint32)req->data; #endif hw->DMA_LEN = req->len; while(!(hw->CRC_STA & LL_CRC_STA_DMA_PENDING)); hw->CRC_KST = LL_CRC_KST_DMA_PENDING_CLR; *crc_value = hw->CRC_OUT; hw->CRC_CFG |= LL_CRC_CFG_INT_EN; return 0; } /** * CRC len 512KB for TXW81x/TXW82X£» 64KB for TXW80x */ static int32 hg_crc_calc(struct crc_dev *crc, struct crc_dev_req *req, uint32 *crc_value, uint32 flags) { int32 ret = 0; uint32 cfg_reg = 0; struct hg_crc *dev = (struct hg_crc *)crc; struct hg_crc_hw *hw = (struct hg_crc_hw *)dev->hw; const struct hgcrc_config *p_cfg; if (req == NULL || req->data == NULL || req->len == 0 || req->type >= CRC_TYPE_MAX) { os_printf(KERN_ERR"%s ARG err\r\n", __FUNCTION__); return -EINVAL; } if ((CRC_TYPE_TCPIP_CHKSUM == req->type) && (req->len < 4)) { os_printf(KERN_ERR"%s not support\r\n", __FUNCTION__); return -ENOTSUP; } if ((dev->flags & BIT(HGCRC_FLAGS_SUSPEND))) { os_printf(KERN_ERR"%s at suspend\r\n", __FUNCTION__); return -ENOTSUP; } p_cfg = hgcrc_cfg[req->type]; if (p_cfg == NULL) { os_printf(KERN_ERR"%s not support\r\n", __FUNCTION__); return -ENOTSUP; } os_mutex_lock(&dev->lock, osWaitForever); os_sema_eat(&dev->done); sysctrl_crc_reset(); if (0 == p_cfg->poly_bits) { cfg_reg = LL_CRC_CFG_INT_EN | LL_CRC_CFG_TCP_MODE_EN | LL_CRC_CFG_DMAWAIT_CLOCK(5); } else { cfg_reg = LL_CRC_CFG_INT_EN | LL_CRC_CFG_POLY_BITS(p_cfg->poly_bits) | LL_CRC_CFG_DMAWAIT_CLOCK(5); if (p_cfg->ref_in) { cfg_reg |= LL_CRC_CFG_BIT_ORDER_RIGHT; } else { cfg_reg |= LL_CRC_CFG_BIT_ORDER_LEFT; } } /* config */ hw->CRC_INV = p_cfg->xor_out; hw->CRC_INIT = p_cfg->init_val; if (flags & CRC_DEV_FLAGS_CONTINUE_CALC) { hw->CRC_INIT = p_cfg->xor_out ^ req->crc_last; } hw->CRC_POLY = p_cfg->poly; hw->CRC_CFG = cfg_reg; /* kick */ #ifdef PSRAM_HEAP if (req->flag) { ; } else if (CRC_TYPE_TCPIP_CHKSUM == req->type) { sys_dcache_clean_range_unaligned((uint32_t *)req->data, req->len); } else { sys_dcache_clean_range((uint32_t *)req->data, req->len); } #endif #if defined(TXW80X) hw->DMA_ADDR = (uint32)req->data & 0x00FFFFFF; #else hw->DMA_ADDR = (uint32)req->data; #endif hw->DMA_LEN = req->len; ret = os_sema_down(&dev->done, 2000); if (!ret) { os_printf(KERN_ERR"%s timeout\r\n", __FUNCTION__); } *crc_value = hw->CRC_OUT; os_mutex_unlock(&dev->lock); return ret > 0 ? RET_OK : RET_ERR; } void hg_crc_test_printf(struct crc_dev *crc) { uint8_t src[64]; for (int i = 0;i<64;i++) src[i] = 99+i; struct crc_dev_req req = { .type = CRC_TYPE_CRC32_WINRAR, .data = src, .len = 64, }; uint32 crc_val = 0; hg_crc_calc(crc, &req, &crc_val, 0); _os_printf("crc r: 0x%08x\r\n", crc_val); if (crc_val != 0x81efdc25) { _os_printf("crc lp err\r\n"); } } #ifdef CONFIG_SLEEP //#define HGCRC_SLEEP_TEST(dev) hg_crc_test_printf(dev) #define HGCRC_SLEEP_TEST(dev) int32 hg_crc_suspend(struct dev_obj *dev) { int32 ret = 0; struct hg_crc *crc = (struct hg_crc *)dev; struct hg_crc_hw *hw = (struct hg_crc_hw *)crc->hw; if ((crc->flags & BIT(HGCRC_FLAGS_SUSPEND))) { return RET_OK; } HGCRC_SLEEP_TEST(dev); ret = os_mutex_lock(&crc->lock, osWaitForever); if (ret < 0) { return ret; } irq_disable(crc->irq_num); crc->flags |= BIT(HGCRC_FLAGS_SUSPEND); /* register backup ?*/ sysctrl_crc_clk_close(); return RET_OK; } int32 hg_crc_resume(struct dev_obj *dev) { int32 ret = 0; struct hg_crc *crc = (struct hg_crc *)dev; struct hg_crc_hw *hw = (struct hg_crc_hw *)crc->hw; if ((crc->flags & BIT(HGCRC_FLAGS_SUSPEND))) { ret = os_mutex_unlock(&crc->lock); if (ret < 0) { return ret; } sysctrl_crc_clk_open(); sysctrl_crc_reset(); /* register recovery ?*/ crc->flags &= ~ BIT(HGCRC_FLAGS_SUSPEND); irq_enable(crc->irq_num); HGCRC_SLEEP_TEST(dev); } return RET_OK; } #endif static const struct crc_hal_ops crc_ops = { .calc = hg_crc_calc, #ifdef CONFIG_SLEEP .ops.suspend = hg_crc_suspend, .ops.resume = hg_crc_resume, #endif }; __init int32 hg_crc_attach(uint32 dev_id, struct hg_crc *crc) { struct hg_crc_hw *hw = (struct hg_crc_hw *)crc->hw; crc->dev.dev.ops = (const struct devobj_ops *)&crc_ops; crc->flags = 0; os_mutex_init(&crc->lock); os_sema_init(&crc->done, 0); sysctrl_crc_clk_open(); sysctrl_crc_reset(); request_irq(crc->irq_num, hg_crc_irq_handler, crc); hw->CRC_CFG |= LL_CRC_CFG_INT_EN; irq_enable(crc->irq_num); dev_register(dev_id, (struct dev_obj *)crc); return RET_OK; }