| /* |
| * Copyright (c) 2025 Renesas Electronics Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(renesas_ra_crc, CONFIG_CRC_LOG_LEVEL); |
| |
| #include <errno.h> |
| #include <zephyr/drivers/crc.h> |
| |
| #include <soc.h> |
| #include "r_crc.h" |
| #include "rp_crc.h" |
| |
| #define DT_DRV_COMPAT renesas_ra_crc |
| #define DEFAULT_NUM_BYTES (4U) |
| #define DEFAULT_SEED_VALUE (0x00000000) |
| |
| struct crc_renesas_ra_cfg { |
| const struct device *clock_dev; |
| const struct clock_control_ra_subsys_cfg clock_id; |
| }; |
| |
| struct crc_renesas_ra_data { |
| struct st_crc_instance_ctrl ctrl; |
| struct st_crc_input_t input_data; |
| struct st_crc_cfg crc_config; |
| struct k_sem sem; |
| bool flag_crc_updated; |
| }; |
| |
| static void crc_lock(const struct device *dev) |
| { |
| struct crc_renesas_ra_data *data = dev->data; |
| |
| k_sem_take(&data->sem, K_FOREVER); |
| } |
| |
| static void crc_unlock(const struct device *dev) |
| { |
| struct crc_renesas_ra_data *data = dev->data; |
| |
| k_sem_give(&data->sem); |
| } |
| |
| static int crc_set_config(const struct device *dev, struct crc_ctx *ctx) |
| { |
| fsp_err_t err; |
| struct crc_renesas_ra_data *data = dev->data; |
| crc_cfg_t const *const crc_cfg = &data->crc_config; |
| |
| data->crc_config.bit_order = (ctx->reversed & CRC_FLAG_REVERSE_OUTPUT) |
| ? CRC_BIT_ORDER_LMS_LSB |
| : CRC_BIT_ORDER_LMS_MSB; |
| |
| switch (ctx->type) { |
| case CRC8: { |
| if ((ctx->polynomial != CRC8_POLY) && (ctx->polynomial != CRC8_REFLECT_POLY)) { |
| return -EINVAL; |
| } |
| |
| data->crc_config.polynomial = CRC_POLYNOMIAL_CRC_8; |
| break; |
| } |
| case CRC16: { |
| if (ctx->polynomial != CRC16_POLY) { |
| return -EINVAL; |
| } |
| |
| data->crc_config.polynomial = CRC_POLYNOMIAL_CRC_16; |
| break; |
| } |
| case CRC16_CCITT: { |
| if (ctx->polynomial != CRC16_CCITT_POLY) { |
| return -EINVAL; |
| } |
| |
| data->crc_config.polynomial = CRC_POLYNOMIAL_CRC_CCITT; |
| break; |
| } |
| case CRC32_C: { |
| if (ctx->polynomial != CRC32C_POLY) { |
| return -EINVAL; |
| } |
| |
| data->crc_config.polynomial = CRC_POLYNOMIAL_CRC_32C; |
| break; |
| } |
| case CRC32_IEEE: { |
| if (ctx->polynomial != CRC32_IEEE_POLY) { |
| return -EINVAL; |
| } |
| |
| data->crc_config.polynomial = CRC_POLYNOMIAL_CRC_32; |
| break; |
| } |
| default: |
| return -ENOTSUP; |
| } |
| |
| err = RP_CRC_Reconfigure(&data->ctrl, crc_cfg); |
| |
| if (err != FSP_SUCCESS) { |
| ctx->state = CRC_STATE_IDLE; |
| crc_unlock(dev); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static int crc_renesas_ra_begin(const struct device *dev, struct crc_ctx *ctx) |
| { |
| int ret; |
| |
| crc_lock(dev); |
| |
| ret = crc_set_config(dev, ctx); |
| if (ret != 0) { |
| crc_unlock(dev); |
| return ret; |
| } |
| |
| ctx->state = CRC_STATE_IN_PROGRESS; |
| |
| return 0; |
| } |
| |
| static int crc_renesas_ra_update(const struct device *dev, struct crc_ctx *ctx, const void *buffer, |
| size_t bufsize) |
| { |
| struct crc_renesas_ra_data *data = dev->data; |
| fsp_err_t err; |
| uint32_t init_val; |
| |
| /* Ensure CRC calculation has been initialized by crc_begin() */ |
| if (ctx->state == CRC_STATE_IDLE) { |
| return -EINVAL; |
| } |
| |
| switch (ctx->type) { |
| case CRC8: |
| __fallthrough; |
| case CRC16: |
| __fallthrough; |
| case CRC16_CCITT: { |
| if (ctx->type == CRC8) { |
| init_val = (data->flag_crc_updated ? ctx->result : ctx->seed) & 0xFF; |
| } else { |
| init_val = (data->flag_crc_updated ? ctx->result : ctx->seed) & 0xFFFF; |
| } |
| |
| data->input_data.num_bytes = bufsize; |
| data->input_data.crc_seed = init_val; |
| data->input_data.p_input_buffer = (uint8_t *)buffer; |
| |
| err = R_CRC_Calculate(&data->ctrl, &data->input_data, &ctx->result); |
| if (err != FSP_SUCCESS) { |
| ctx->state = CRC_STATE_IDLE; |
| crc_unlock(dev); |
| return -EINVAL; |
| } |
| break; |
| } |
| default: { |
| init_val = (data->flag_crc_updated ? ctx->result : ctx->seed) & 0xFFFFFFFF; |
| |
| if ((bufsize % 4) != 0) { |
| ctx->state = CRC_STATE_IDLE; |
| crc_unlock(dev); |
| return -ENOTSUP; |
| } |
| |
| data->input_data.num_bytes = bufsize; |
| data->input_data.crc_seed = init_val; |
| data->input_data.p_input_buffer = (uint8_t *)buffer; |
| |
| err = R_CRC_Calculate(&data->ctrl, &data->input_data, &ctx->result); |
| if (err != FSP_SUCCESS) { |
| ctx->state = CRC_STATE_IDLE; |
| crc_unlock(dev); |
| return -EINVAL; |
| } |
| |
| if (ctx->type == CRC32_IEEE) { |
| ctx->result = (crc_result_t)~ctx->result; |
| } |
| break; |
| } |
| } |
| |
| data->flag_crc_updated = true; |
| |
| return 0; |
| } |
| |
| static int crc_renesas_ra_finish(const struct device *dev, struct crc_ctx *ctx) |
| { |
| struct crc_renesas_ra_data *data = dev->data; |
| |
| if (ctx->state == CRC_STATE_IDLE) { |
| return -EINVAL; |
| } |
| |
| ctx->state = CRC_STATE_IDLE; |
| |
| data->flag_crc_updated = false; |
| |
| crc_unlock(dev); |
| |
| return 0; |
| } |
| |
| static int crc_ra_init(const struct device *dev) |
| { |
| int ret; |
| fsp_err_t err; |
| const struct crc_renesas_ra_cfg *cfg = dev->config; |
| struct crc_renesas_ra_data *data = dev->data; |
| crc_cfg_t const *const crc_cfg = &data->crc_config; |
| |
| if (!device_is_ready(cfg->clock_dev)) { |
| LOG_ERR("CRC: Clock control device not ready"); |
| return -ENODEV; |
| } |
| |
| ret = clock_control_on(cfg->clock_dev, (clock_control_subsys_t)&cfg->clock_id); |
| if (ret < 0) { |
| LOG_ERR("CRC: Clock control device could not initialize"); |
| return -EIO; |
| } |
| |
| err = R_CRC_Open(&data->ctrl, crc_cfg); |
| if (err != FSP_SUCCESS) { |
| return -EINVAL; |
| } |
| |
| k_sem_init(&data->sem, 1, 1); |
| |
| return 0; |
| } |
| |
| static DEVICE_API(crc, crc_renesas_ra_driver_api) = { |
| .begin = crc_renesas_ra_begin, |
| .update = crc_renesas_ra_update, |
| .finish = crc_renesas_ra_finish, |
| }; |
| |
| #define CRC_RA_INIT_CFG(idx) \ |
| static const struct crc_renesas_ra_cfg crc_renesas_ra_cfg_##idx = { \ |
| .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_DRV_INST(idx))), \ |
| .clock_id = \ |
| { \ |
| .mstp = DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(idx), 0, mstp), \ |
| .stop_bit = DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(idx), 0, stop_bit), \ |
| }, \ |
| }; |
| |
| #define CRC_RA_INIT(idx) \ |
| CRC_RA_INIT_CFG(idx); \ |
| \ |
| static struct crc_renesas_ra_data crc_renesas_ra_data_##idx = { \ |
| .input_data = \ |
| { \ |
| .num_bytes = DEFAULT_NUM_BYTES, \ |
| .crc_seed = DEFAULT_SEED_VALUE, \ |
| .p_input_buffer = NULL, \ |
| }, \ |
| .crc_config = \ |
| { \ |
| .bit_order = CRC_BIT_ORDER_LMS_LSB, \ |
| .polynomial = CRC_POLYNOMIAL_CRC_32, \ |
| }, \ |
| .flag_crc_updated = false, \ |
| }; \ |
| \ |
| DEVICE_DT_INST_DEFINE(idx, crc_ra_init, NULL, &crc_renesas_ra_data_##idx, \ |
| &crc_renesas_ra_cfg_##idx, POST_KERNEL, \ |
| CONFIG_CRC_DRIVER_INIT_PRIORITY, &crc_renesas_ra_driver_api); |
| |
| DT_INST_FOREACH_STATUS_OKAY(CRC_RA_INIT) |