290 lines
8.0 KiB
C
290 lines
8.0 KiB
C
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
|
|
#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 */
|
|
|