#include #include #include #include #include #include #include #include #include #include #include #include "xmedia_type.h" #include "pm_flash.h" #include "pm_ddr.h" #include "xmedia_cipher.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define SHA256_SUPPORT static const xmedia_char nand_ddr_param_part[] = "/dev/mtd2"; static const xmedia_char spi_ddr_param_part[] = "/dev/mtd2"; static const xmedia_char emmc_ddr_param_part[] = "/dev/mmcblk0p2"; static const xmedia_char ddr_param_part_name[] = "ddr_param"; static const xmedia_char *ddr_param_dev_name[PM_FLASH_TYPE_MAX] = {spi_ddr_param_part, nand_ddr_param_part, emmc_ddr_param_part}; xmedia_u32 checksum(xmedia_u8 *data, size_t length) { xmedia_u32 sum = 0; size_t i; for (i = 0; i < length; i++) { sum += data[i]; } return sum; } xmedia_s32 hash_calc(xmedia_u8 *data, size_t length, xmedia_u8 *result) { xmedia_handle handle; xmedia_cipher_hash_attr hash_attr; xmedia_s32 ret = XMEDIA_SUCCESS; ret = xmedia_cipher_init(); if (ret != XMEDIA_SUCCESS) { PM_USR_TRACE(MODULE_DBG_ERR, "cipher init err\n"); return ret; } memset(&hash_attr, 0, sizeof(xmedia_cipher_hash_attr)); hash_attr.type = XMEDIA_CIPHER_HASH_TYPE_SHA256; ret = xmedia_cipher_hash_init(&hash_attr, &handle); if (ret != XMEDIA_SUCCESS) { xmedia_cipher_exit(); PM_USR_TRACE(MODULE_DBG_ERR, "cipher hash init err\n"); return ret; } ret = xmedia_cipher_hash_update(handle, data, length); if (ret != XMEDIA_SUCCESS) { xmedia_cipher_exit(); PM_USR_TRACE(MODULE_DBG_ERR, "cipher hash update err\n"); return ret; } ret = xmedia_cipher_hash_final(handle, result); xmedia_cipher_exit(); return ret; } static struct flash_part_dev *ddr_param_part_init(void) { struct flash_part_dev *ddr_param_dev; xmedia_s32 ret; ddr_param_dev = alloc_flash_part(); if (ddr_param_dev == XMEDIA_NULL) { PM_USR_TRACE(MODULE_DBG_ERR, "alloc part dev err\n"); return XMEDIA_NULL; } memcpy(ddr_param_dev->part.devname, ddr_param_dev_name[ddr_param_dev->part.flash_type], strlen(ddr_param_dev_name[ddr_param_dev->part.flash_type])); memcpy(ddr_param_dev->part.partname, ddr_param_part_name, strlen(ddr_param_part_name)); ret = flash_open(ddr_param_dev, ACCESS_RD); if (ret != XMEDIA_SUCCESS) { PM_USR_TRACE(MODULE_DBG_ERR, "open part:%s err\n", ddr_param_dev->part.devname); free_flash_part(ddr_param_dev); return XMEDIA_NULL; } ret = flash_init(ddr_param_dev); if (ret != XMEDIA_SUCCESS) { PM_USR_TRACE(MODULE_DBG_ERR, "flash init err ret = %d\n", ret); goto ERR_RET; } memset(ddr_param_dev->part.partname, 0, FLASH_NAME_LEN); ret = flash_get_info(ddr_param_dev); if (ret != XMEDIA_SUCCESS) { PM_USR_TRACE(MODULE_DBG_ERR, "flash get info err ret = %d\n", ret); goto ERR_RET; } if (strncmp(ddr_param_dev->part.partname, ddr_param_part_name, strlen(ddr_param_part_name)) != 0) { PM_USR_TRACE(MODULE_DBG_ERR, "mtd part name(%s) err\n", ddr_param_dev->part.partname); goto ERR_RET; } return ddr_param_dev; ERR_RET: ddr_param_dev->part_opt->close(ddr_param_dev); free_flash_part(ddr_param_dev); return XMEDIA_NULL; } static xmedia_s32 ddr_param_part_deinit(struct flash_part_dev *part_dev) { flash_close(part_dev); free_flash_part(part_dev); return XMEDIA_SUCCESS; } static xmedia_s32 ddr_param_get(struct lpds_param *lpds_parm) { return xmedia_pm_get_ddr_param(lpds_parm); } #define RAM_OFF_CHECK_FILE "/sys/module/pm/parameters/ram_power_off" #define RAM_OFF_ENABLE_FLAG "Y" #define RAM_OFF_FLAG_SIZE (1) xmedia_bool is_ram_off_str(void) { xmedia_char buf[8]; xmedia_s32 fd; xmedia_u32 size = sizeof(buf); fd = open(RAM_OFF_CHECK_FILE, O_RDWR | O_SYNC); if (fd < 0) { PM_USR_TRACE(MODULE_DBG_ERR, "open %s err, ret:%d \n", RAM_OFF_CHECK_FILE, fd); return XMEDIA_FALSE; } size = read(fd, buf, size); if (size <= 0) { close(fd); PM_USR_TRACE(MODULE_DBG_ERR, "%s get ram off flag err\n", __func__); return XMEDIA_FALSE; } close(fd); if (strncmp(buf, RAM_OFF_ENABLE_FLAG, RAM_OFF_FLAG_SIZE) == 0) return XMEDIA_TRUE; else return XMEDIA_FALSE; } xmedia_s32 ddr_param_check_and_save(void) { struct flash_part_dev *ddr_param_dev; xmedia_char *buff; xmedia_s32 ret; struct lpds_param *lpds_parm; xmedia_u32 size; xmedia_u32 block_mask; #ifndef SHA256_SUPPORT xmedia_u32 checksum32; #else xmedia_u8 ddr_hash[HASH_SIZE_PER_BYTE]; #endif struct timespec ts; struct ddr_calib_data *p_ddr_param; PM_USR_TRACE(MODULE_DBG_INFO, "ram power off str\n"); ddr_param_dev = ddr_param_part_init(); if (ddr_param_dev == XMEDIA_NULL) { PM_USR_TRACE(MODULE_DBG_ERR, "%s init err\n", __func__); return XMEDIA_ERRCODE_OPEN_FAILED; } block_mask = (~(ddr_param_dev->flash.block_size - 1)); /* For nand, we must update the whole block to update the * bad flag/empty flag/ecc to the OOB region, which the FMC * boot mode need. If not, the FMC can not read the correct * ddr_param data in bootrom/auxcode stage.*/ if (ddr_param_dev->flash.flash_type == PM_FLASH_TYPE_NAND) size = ((sizeof(struct lpds_param) + ddr_param_dev->flash.block_size - 1) & (~(ddr_param_dev->flash.block_size - 1))); else size = ((sizeof(struct lpds_param) + ddr_param_dev->flash.page_size - 1) & (~(ddr_param_dev->flash.page_size - 1))); buff = (xmedia_char *)malloc(size); if (buff == XMEDIA_NULL) { PM_USR_TRACE(MODULE_DBG_ERR, "%s out of mem\n", __func__); ret = XMEDIA_ERRCODE_NOT_ENOUGH_MEMORY; goto DEINIT_RET; } if (flash_read(ddr_param_dev, 0, size, buff) != size) { PM_USR_TRACE(MODULE_DBG_ERR, "%s flash read error\n", __func__); ret = XMEDIA_ERRCODE_COPY_DATA_ERROR; goto FREE_RET; } clock_gettime(CLOCK_REALTIME, &ts); lpds_parm = (struct lpds_param *)buff; p_ddr_param = (struct ddr_calib_data *)lpds_parm->ddr_calib; #ifdef SHA256_SUPPORT ret = hash_calc(lpds_parm->ddr_calib + sizeof(xmedia_u32), (sizeof(struct ddr_calib_data) - sizeof(xmedia_u32)), ddr_hash); if (ret) { PM_USR_TRACE(MODULE_DBG_ERR, "%s hash calc error ret=%d\n", __func__, ret); ret = XMEDIA_ERRCODE_NOT_SUPPORT; goto FREE_RET; } if (memcmp(ddr_hash, lpds_parm->ddr_hash, HASH_SIZE_PER_BYTE) != 0 || (ts.tv_sec - p_ddr_param->time_sec >= DDR_PARAM_UPDATE_CYCLE)) { #else checksum32 = checksum(lpds_parm->ddr_calib + sizeof(xmedia_u32), (sizeof(struct ddr_calib_data) - sizeof(xmedia_u32))); if (checksum32 != *((xmedia_u32 *)lpds_parm->ddr_calib) || (ts.tv_sec - p_ddr_param->time_sec >= DDR_PARAM_UPDATE_CYCLE)) { #endif /* * ddr param in flah is error * save new training result */ PM_USR_TRACE(MODULE_DBG_ERR, "ddr paramter err or too old, update now\n"); PM_USR_TRACE(MODULE_DBG_ERR, "now time %lu s save time %u s \n", ts.tv_sec, p_ddr_param->time_sec); ret = ddr_param_get(lpds_parm); if (ret != XMEDIA_SUCCESS) { PM_USR_TRACE(MODULE_DBG_ERR, "%s read ddr param error ret=%d\n", __func__, ret); goto FREE_RET; } p_ddr_param->time_sec = ts.tv_sec; /* calc checksum */ #ifdef SHA256_SUPPORT ret = hash_calc(lpds_parm->ddr_calib + sizeof(xmedia_u32), (sizeof(struct ddr_calib_data) - sizeof(xmedia_u32)), lpds_parm->ddr_hash); if (ret) { PM_USR_TRACE(MODULE_DBG_ERR, "%s hash calc for save error ret=%d\n", __func__, ret); ret = XMEDIA_ERRCODE_NOT_SUPPORT; goto FREE_RET; } #else *((xmedia_u32 *)lpds_parm->ddr_calib) = checksum(lpds_parm->ddr_calib + sizeof(xmedia_u32), (sizeof(struct ddr_calib_data) - sizeof(xmedia_u32))); #endif /* erase first */ ret = flash_erase(ddr_param_dev, 0, (size + (ddr_param_dev->flash.block_size - 1)) & block_mask); if (ret != XMEDIA_SUCCESS) { PM_USR_TRACE(MODULE_DBG_ERR, "%s erase error ret=%d\n", __func__, ret); ret = XMEDIA_ERRCODE_NOT_SUPPORT; goto FREE_RET; } /* write */ if (flash_write(ddr_param_dev, 0, size, buff) != size) { PM_USR_TRACE(MODULE_DBG_ERR, "%s write error ret=%d\n", __func__, ret); ret = XMEDIA_ERRCODE_NOT_SUPPORT; goto FREE_RET; } } ret = XMEDIA_SUCCESS; FREE_RET: free(buff); DEINIT_RET: ddr_param_part_deinit(ddr_param_dev); return ret; } #ifdef __cplusplus } #endif /* __cplusplus */