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

267 lines
6.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 "pm_flash.h"
#include "pm_mtd.h"
#define MAX_PARTS 32 /* Flash max partition number*/
#define MAX_MTD_PARTITION (MAX_PARTS)
#define TMP_READ_BUF_SIZE 512
#define MTD_INFO_DEV "/proc/mtd"
static xmedia_char *skip_space(xmedia_char *line)
{
xmedia_char *p = line;
while (*p == ' ' || *p == '\t') {
p++;
}
return p;
}
static xmedia_char *get_word(xmedia_char *line, xmedia_char *value)
{
xmedia_char *p = line;
p = skip_space(p);
while (*p != '\t' && *p != ' ' && *p != '\n' && *p != 0) {
*value++ = *p++;
}
*value = 0;
return p;
}
static xmedia_u32 file_name_start(xmedia_char *name)
{
xmedia_u32 size = 0;
if (name) {
size = strlen(name);
if (size == 0)
return size;
while (size--) {
if (name[size] == '/')
return size + 1;
}
}
return size;
}
static xmedia_s32 get_dname_from_pname(struct flash_part_dev *part_dev)
{
FILE *fd;
xmedia_char *buff;
xmedia_s32 ret = -1;
xmedia_s32 i = 0;
xmedia_char *p;
xmedia_char devname[FLASH_NAME_LEN];
xmedia_char tmp[32];
buff = (xmedia_char *)malloc(TMP_READ_BUF_SIZE);
if (buff == XMEDIA_NULL)
return XMEDIA_ERRCODE_NOT_ENOUGH_MEMORY;
fd = fopen(MTD_INFO_DEV, "r");
if (fd) {
if (NULL == fgets(buff, TMP_READ_BUF_SIZE, fd)) {//skip first line
fclose(fd);
goto ERR_END;
}
for (i = 0; i < MAX_MTD_PARTITION; i++) {
if (fgets(buff, TMP_READ_BUF_SIZE, fd) == NULL) {
break;
}
p = &buff[0];
p = get_word(p, devname);
p = get_word(p, tmp);
part_dev->part.size = (xmedia_u32)strtoull(tmp, NULL, 16);
p = get_word(p, tmp);
part_dev->part.block_size = (xmedia_u32)strtoull(tmp, NULL, 16);
p = get_word(p, tmp);
if (strncmp(&tmp[1], part_dev->part.partname, strlen(part_dev->part.partname)) == 0){
/* delete ':' */
devname[strlen(devname) - 1] = 0;
strncpy(part_dev->part.devname + file_name_start(part_dev->part.devname), devname, FLASH_NAME_LEN);
printf("use new devname: %s\n", part_dev->part.devname);
ret = XMEDIA_SUCCESS;
break;
}
}
fclose(fd);
}
ERR_END:
free(buff);
return ret;
}
static xmedia_s32 spi_read(struct flash_part_dev *part_dev, xmedia_u32 addr, xmedia_u32 size, xmedia_char *buf)
{
/* check addr and size */
if (addr > part_dev->flash.part_size || addr + size > part_dev->flash.part_size)
return XMEDIA_ERRCODE_INVALID_PARAM;
lseek(part_dev->part_fd, addr, SEEK_SET);
return read(part_dev->part_fd, buf, size);
}
static xmedia_s32 spi_write(struct flash_part_dev *part_dev, xmedia_u32 addr, xmedia_u32 size, xmedia_char *buf)
{
xmedia_u32 page_mask = part_dev->flash.page_size - 1;
if ((addr & page_mask) || (size & page_mask)) {
return XMEDIA_ERRCODE_INVALID_PARAM;
}
/* check addr and size */
if (addr > part_dev->flash.part_size || addr + size > part_dev->flash.part_size)
return XMEDIA_ERRCODE_INVALID_PARAM;
lseek(part_dev->part_fd, addr, SEEK_SET);
return write(part_dev->part_fd, buf, size);
}
static xmedia_s32 spi_erase(struct flash_part_dev *part_dev, xmedia_u32 addr, xmedia_u32 size)
{
xmedia_u32 block_mask = part_dev->flash.block_size - 1;
struct erase_info_user64 eraseinfo;
xmedia_s32 ret;
if ((addr & block_mask) || (size & block_mask)) {
return XMEDIA_ERRCODE_INVALID_PARAM;
}
/* check addr and size */
if (addr > part_dev->flash.part_size || addr + size > part_dev->flash.part_size)
return XMEDIA_ERRCODE_INVALID_PARAM;
eraseinfo.start = addr;
eraseinfo.length = size;
ret = ioctl(part_dev->part_fd, MEMERASE64, &eraseinfo);
if (ret != 0) {
PM_USR_TRACE(MODULE_DBG_ERR, "%s erase error ret:%d\n", __func__, ret);
return XMEDIA_ERRCODE_INVALID_PARAM;
}
return XMEDIA_SUCCESS;
}
static xmedia_s32 spi_open(struct flash_part_dev *part_dev, unsigned int flag)
{
if (part_dev->part.partname[0] != 0)
get_dname_from_pname(part_dev);
part_dev->part_fd = open(part_dev->part.devname, flag);
return part_dev->part_fd;
}
static xmedia_s32 spi_close(struct flash_part_dev *part_dev)
{
close(part_dev->part_fd);
part_dev->part_fd = -1;
return XMEDIA_SUCCESS;
}
static xmedia_s32 spi_init(struct flash_part_dev *part_dev)
{
struct mtd_info_user mtdinfo;
xmedia_s32 ret;
ret = ioctl(part_dev->part_fd, MEMGETINFO, &mtdinfo);
if (ret != 0) {
PM_USR_TRACE(MODULE_DBG_ERR, "%s mem get info error ret:%d\n", __func__, ret);
return XMEDIA_ERRCODE_INVALID_PARAM;
}
part_dev->flash.block_size = mtdinfo.erasesize;
part_dev->flash.page_size = mtdinfo.writesize;
part_dev->flash.oob_size = mtdinfo.oobsize;
part_dev->flash.part_size = mtdinfo.size;
return XMEDIA_SUCCESS;
}
static xmedia_s32 spi_getinfo(struct flash_part_dev *part_dev)
{
xmedia_s32 ret = -1;
xmedia_s32 i = 0;
xmedia_char *buff;
FILE *fd;
xmedia_char *p;
xmedia_char tmp[32];
buff = (xmedia_char *)malloc(TMP_READ_BUF_SIZE);
if (buff == XMEDIA_NULL)
return XMEDIA_ERRCODE_NOT_ENOUGH_MEMORY;
fd = fopen(MTD_INFO_DEV, "r");
if (fd) {
if (NULL == fgets(buff, TMP_READ_BUF_SIZE, fd)) {//skip first line
fclose(fd);
goto ERR_END;
}
for (i = 0; i < MAX_MTD_PARTITION; i++) {
if (fgets(buff, TMP_READ_BUF_SIZE, fd) == NULL) {
break;
}
p = &buff[0];
p = get_word(p, tmp);
if (strncmp(tmp, &part_dev->part.devname[5], strlen(&part_dev->part.devname[5])) == 0) {
p = get_word(p, tmp);
part_dev->part.size = (xmedia_u32)strtoull(tmp, NULL, 16);
p = get_word(p, tmp);
part_dev->part.block_size = (xmedia_u32)strtoull(tmp, NULL, 16);
p = get_word(p, tmp);
strncpy(part_dev->part.partname, &tmp[1], FLASH_NAME_LEN);
ret = XMEDIA_SUCCESS;
break;
}
}
fclose(fd);
}
ERR_END:
free(buff);
return ret;
}
static struct flash_opt spi_opt = {
.read = spi_read,
.write = spi_write,
.erase = spi_erase,
.init = spi_init,
.open = spi_open,
.close = spi_close,
.get_info = spi_getinfo,
};
struct flash_opt *get_spi_opt(void)
{
return &spi_opt;
}