/** * @file fee_eeprom.c * * Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. * * Description: * * Revision History: * ----------------- */ #include #include #include #include #include #include #include #include static struct list_node g_fee_list; static struct fee_eeprom *fee_get_dev(const char *fee_name) { struct fee_eeprom *fee_eeprom; /* matches nodes based on name */ list_for_every_entry(&g_fee_list, fee_eeprom, struct fee_eeprom, node) { if (!strcmp(fee_name, fee_eeprom->fee_name)) { return fee_eeprom; } } return NULL; } static int fee_eeprom_check(struct fee_config_eeprom *fee_con) { struct disk_dev_info *disk_dev = fee_con->disk_dev; /* check whether the Flash capacity is supported */ uint16_t pe_ratio = ROUNDUP(fee_con->eeprom_pe_cycles, disk_dev->pe_cycles) / disk_dev->pe_cycles; uint16_t size_avg = fee_con->eeprom_align_size * FEE_EEPROM_SIZE_AVG; disk_size_t target_size = fee_con->eeprom_size * pe_ratio + (fee_con->eeprom_size / size_avg) * pe_ratio * sizeof(struct fee_record_info); if (target_size > disk_dev->size) { ssdk_printf(SSDK_CRIT, "fee eeprom target_size %llx actual size %llx,space size does not meet the requirements\n", target_size, disk_dev->size); return -1; } ssdk_printf(SSDK_INFO, "fee eeprom target_size %llx actual size %llx\n", target_size, disk_dev->size); return 0; } int fee_register_eeprom(struct fee_eeprom *fee) { int ret = 0; struct fee_dev *fee_dev = &fee->fee_dev; struct fee_config_eeprom *fee_con = &fee->fee_con; fee->fee_name = fee_con->fee_name; ssdk_printf(SSDK_INFO, "register fee eeprom device %s\n", fee->fee_name); if (NULL != fee_get_dev(fee->fee_name)) { ssdk_printf(SSDK_CRIT, "fee devicve %s already registered\n", fee->fee_name); return -1; } /* check the configuration */ ret = fee_eeprom_check(fee_con); if (ret) { ssdk_printf(SSDK_CRIT, "register fee eeprom device %s\n error", fee->fee_name); return -1; } /* insert node */ list_add_tail(&g_fee_list, &fee->node); fee_dev->disk_dev = fee_con->disk_dev; fee_dev->block_length = fee_con->eeprom_align_size; fee_dev->block_number = fee_con->eeprom_size / fee_dev->block_length; fee_dev->page_mode = FEE_PAGE_EEPROM; fee_dev->block_addr_mask = fee_con->block_addr_mask; fee_dev->block_addr_size = fee_con->block_addr_size; ret = fee_init(fee_dev); if (ret) { ssdk_printf(SSDK_CRIT, "fee eeprom %s init faild\n", fee->fee_name); goto error; } return ret; error: if (list_in_list(&fee->node)) list_delete(&fee->node); return ret; } int fee_unregister_eeprom(struct fee_eeprom *fee) { int ret = 0; struct fee_dev *fee_dev = &fee->fee_dev; ssdk_printf(SSDK_INFO, "unregiste fee eeprom device %s\n", fee->fee_name); fee->fee_name = NULL; /* remove nodes */ if (list_in_list(&fee->node)) list_delete(&fee->node); fee_exit(fee_dev); return ret; } int fee_read_eeprom(const char *fee_name, uint32_t addr, uint8_t *data_buffer, uint16_t length) { int ret = 0; struct fee_eeprom *fee = fee_get_dev(fee_name); if (NULL == fee) { ssdk_printf(SSDK_CRIT, "no fee devicve %s\n", fee_name); return -1; } ssdk_printf(SSDK_INFO, "read fee eeprom device %s addr:%x length:%x\n", fee->fee_name, addr, length); struct fee_dev *fee_dev = &fee->fee_dev; struct fee_config_eeprom *fee_con = &fee->fee_con; if (!IS_ALIGNED(addr, fee_dev->block_length)) { ssdk_printf(SSDK_CRIT, "fee_read eeprom addr %d not aligned to record_length %d\n", addr, fee_dev->block_length); return -1; } uint16_t block_number = addr / fee_dev->block_length; if (!IS_ALIGNED(length, fee_dev->block_length)) { ssdk_printf(SSDK_CRIT, "fee_read eeprom length %d not aligned to record_length %d\n", length, fee_dev->block_length); return -1; } if ((addr + length) > fee_con->eeprom_size) { ssdk_printf(SSDK_CRIT, "fee_read eeprom addr %d length %d more than eeprom capacity %d\n", addr, length, fee_con->eeprom_size); return -1; } ret = fee_read_record_multiple(fee_dev, block_number, data_buffer, length); if (ret) { ssdk_printf(SSDK_CRIT, "fee_read_record_multiple fee_name %s addr %d error\n", fee_name, addr); return -1; } return ret; } int fee_write_eeprom(const char *fee_name, uint32_t addr, const uint8_t *data_buffer, uint16_t length) { int ret = 0; struct fee_eeprom *fee = fee_get_dev(fee_name); if (NULL == fee) { ssdk_printf(SSDK_CRIT, "no fee devicve %s\n", fee_name); return -1; } struct fee_dev *fee_dev = &fee->fee_dev; struct fee_config_eeprom *fee_con = &fee->fee_con; ssdk_printf(SSDK_INFO, "write fee eeprom device %s addr:%x length:%x\n", fee->fee_name, addr, length); if (!IS_ALIGNED(addr, fee_dev->block_length)) { ssdk_printf(SSDK_CRIT, "fee_write eeprom addr %d not aligned to record_length %d\n", addr, fee_dev->block_length); return -1; } uint16_t block_number = addr / fee_dev->block_length; if (!IS_ALIGNED(length, fee_dev->block_length)) { ssdk_printf(SSDK_CRIT, "fee_write eeprom length %d not aligned to record_length %d\n", length, fee_dev->block_length); return -1; } if ((addr + length) > fee_con->eeprom_size) { ssdk_printf(SSDK_CRIT, "fee_write eeprom addr %d length %d more than eeprom capacity %d\n", addr, length, fee_con->eeprom_size); return -1; } ret = fee_write_record_multiple(fee_dev, block_number, (uint8_t *)data_buffer, length); if (ret) { ssdk_printf(SSDK_CRIT, "fee_write_record_multiple fee_name %s addr %d error\n", fee_name, addr); return -1; } return ret; } int fee_init_eeprom(void) { ssdk_printf(SSDK_INFO, "fee eeprom init\n"); /* disk list node init */ list_initialize(&g_fee_list); return 0; } int fee_exit_eeprom(void) { ssdk_printf(SSDK_INFO, "fee eeprom exit\n"); /* disk list node init */ return 0; }