Files
gk-sdk/source/gmp/usr/pm/pm_ddr.c
T

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 */