rv1126-uboot/tools/rknand.c

156 lines
3.8 KiB
C

/*
* Copyright (c) 2017 Paweł Jarosz <paweljarosz3691@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include "imagetool.h"
#include <image.h>
#include <rc4.h>
#include "mkimage.h"
#include "rkcommon.h"
enum {
RKNAND_SECT_LEN = RK_BLK_SIZE * 4,
};
struct rknand_info {
uint32_t pagesize;
uint32_t skippages;
uint32_t tplsize;
uint32_t splsize;
uint32_t tplpaddedsize;
uint32_t splpaddedsize;
uint32_t itersize;
uint32_t tplsplsize;
char *tplfile;
char *splfile;
};
struct rknand_info ninfo;
static uint32_t rknand_get_file_size(char *filename)
{
int dfd;
struct stat sbuf;
dfd = open(filename, O_RDONLY | O_BINARY);
if (dfd < 0) {
fprintf(stderr, "Can't open %s: %s\n", filename, strerror(errno));
exit(EXIT_FAILURE);
}
if (fstat(dfd, &sbuf) < 0) {
fprintf(stderr, "Can't stat %s: %s\n", filename, strerror(errno));
exit(EXIT_FAILURE);
}
close(dfd);
return sbuf.st_size;
}
static void rknand_fill_ninfo(struct image_tool_params *params)
{
sscanf(params->extraparams, "%u,%u", &ninfo.pagesize, &ninfo.skippages);
ninfo.tplfile = params->datafile;
if ((ninfo.splfile = strchr(params->datafile, ':')) != NULL) {
*ninfo.splfile = '\0';
ninfo.splfile += 1;
}
ninfo.tplsize = rknand_get_file_size(ninfo.tplfile);
ninfo.splsize = rknand_get_file_size(ninfo.splfile);
ninfo.tplpaddedsize = ROUND(ninfo.tplsize, RKNAND_SECT_LEN);
ninfo.splpaddedsize = ROUND(ninfo.splsize, RKNAND_SECT_LEN);
ninfo.itersize = ninfo.pagesize * (ninfo.skippages + 1);
ninfo.tplsplsize = ((ninfo.tplpaddedsize + ninfo.splpaddedsize) /
RKNAND_SECT_LEN) * ninfo.itersize;
}
static void rknand_set_header(void *buf, struct stat *sbuf, int ifd,
struct image_tool_params *params)
{
int sector, sploffset, splfd, ret;
ret = rkcommon_set_header(buf, ninfo.tplsize, ninfo.splsize, params);
if (ret) {
printf("Warning: TPL image is too large (size %#x) and will "
"not boot\n", ninfo.tplsize);
}
if ((splfd = open(ninfo.splfile, O_RDONLY | O_BINARY)) < 0) {
fprintf (stderr, "%s: Can't open %s: %s\n",
params->cmdname, ninfo.splfile, strerror(errno));
exit (EXIT_FAILURE);
}
sploffset = RKNAND_SECT_LEN + ninfo.tplpaddedsize;
if (read(splfd, buf + sploffset, ninfo.splsize) != ninfo.splsize) {
fprintf (stderr, "%s: Read error on %s: %s\n",
params->cmdname, ninfo.splfile, strerror(errno));
exit (EXIT_FAILURE);
}
close(splfd);
if (rkcommon_need_rc4_spl(params))
rkcommon_rc4_encode_spl(buf, sploffset, ninfo.splpaddedsize);
/*
* Spread the image out so we only use the first 2KB of each pagesize
* region. This is a feature of the NAND format required by the Rockchip
* boot ROM.
*/
for (sector = ninfo.tplsplsize / ninfo.itersize - 1; sector >= 0; sector--) {
memmove(buf + sector * ninfo.itersize + ninfo.pagesize,
buf + (sector + 1) * RKNAND_SECT_LEN, RKNAND_SECT_LEN);
if (sector < (ninfo.tplsplsize / ninfo.itersize - 1))
memset(buf + sector * ninfo.itersize + ninfo.pagesize +
RKNAND_SECT_LEN, 0xFF, ninfo.itersize -
RKNAND_SECT_LEN);
}
memset(buf + RKNAND_SECT_LEN, 0xFF, ninfo.pagesize - RKNAND_SECT_LEN);
memset(buf + ninfo.tplsplsize - ninfo.pagesize + RKNAND_SECT_LEN, 0xFF,
ninfo.pagesize - RKNAND_SECT_LEN);
}
static int rknand_check_image_type(uint8_t type)
{
if (type == IH_TYPE_RKNAND)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
static int rknand_vrec_header(struct image_tool_params *params,
struct image_type_params *tparams)
{
rknand_fill_ninfo(params);
rkcommon_vrec_header(params, tparams, RKNAND_SECT_LEN);
return ninfo.tplsplsize - tparams->header_size - ninfo.tplsize;
}
/*
* rknand parameters
*/
U_BOOT_IMAGE_TYPE(
rknand,
"Rockchip NAND Boot Image support",
0,
NULL,
rkcommon_check_params,
rkcommon_verify_header,
rkcommon_print_header,
rknand_set_header,
NULL,
rknand_check_image_type,
NULL,
rknand_vrec_header
);