xref: /rk3399_rockchip-uboot/tools/rknand.c (revision 05b25c8bf30a77beb555abb8f65e78bd2f21b5de)
1 /*
2  * Copyright (c) 2017 Paweł Jarosz <paweljarosz3691@gmail.com>
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include "imagetool.h"
8 #include <image.h>
9 #include <rc4.h>
10 #include "mkimage.h"
11 #include "rkcommon.h"
12 
13 enum {
14 	RKNAND_SECT_LEN = RK_BLK_SIZE * 4,
15 };
16 
17 struct rknand_info {
18 	uint32_t pagesize;
19 	uint32_t skippages;
20 	uint32_t tplsize;
21 	uint32_t splsize;
22 	uint32_t tplpaddedsize;
23 	uint32_t splpaddedsize;
24 	uint32_t itersize;
25 	uint32_t tplsplsize;
26 	char *tplfile;
27 	char *splfile;
28 };
29 
30 struct rknand_info ninfo;
31 
32 static uint32_t rknand_get_file_size(char *filename)
33 {
34 	int dfd;
35 	struct stat sbuf;
36 
37 	dfd = open(filename, O_RDONLY | O_BINARY);
38 	if (dfd < 0) {
39 		fprintf(stderr, "Can't open %s: %s\n", filename, strerror(errno));
40 		exit(EXIT_FAILURE);
41 	}
42 
43 	if (fstat(dfd, &sbuf) < 0) {
44 		fprintf(stderr, "Can't stat %s: %s\n", filename, strerror(errno));
45 		exit(EXIT_FAILURE);
46 	}
47 
48 	close(dfd);
49 
50 	return sbuf.st_size;
51 }
52 
53 static void rknand_fill_ninfo(struct image_tool_params *params)
54 {
55 	sscanf(params->extraparams, "%u,%u", &ninfo.pagesize, &ninfo.skippages);
56 
57 	ninfo.tplfile = params->datafile;
58 	if ((ninfo.splfile = strchr(params->datafile, ':')) != NULL) {
59 		*ninfo.splfile = '\0';
60 		ninfo.splfile += 1;
61 	}
62 
63 	ninfo.tplsize = rknand_get_file_size(ninfo.tplfile);
64 	ninfo.splsize = rknand_get_file_size(ninfo.splfile);
65 
66 	ninfo.tplpaddedsize = ROUND(ninfo.tplsize +
67 		(rkcommon_spl_is_boot0(params) ? 0 : 4), RKNAND_SECT_LEN);
68 
69 	ninfo.splpaddedsize = ROUND(ninfo.splsize, RKNAND_SECT_LEN);
70 
71 	ninfo.itersize = ninfo.pagesize * (ninfo.skippages + 1);
72 	ninfo.tplsplsize = ((ninfo.tplpaddedsize + ninfo.splpaddedsize) /
73 		     RKNAND_SECT_LEN) * ninfo.itersize;
74 }
75 
76 static void rknand_set_header(void *buf, struct stat *sbuf, int ifd,
77 			     struct image_tool_params *params)
78 {
79 	int sector, sploffset, splfd, ret;
80 
81 	ret = rkcommon_set_header(buf, ninfo.tplsize, ninfo.splsize, params);
82 	if (ret) {
83 		printf("Warning: TPL image is too large (size %#x) and will "
84 		       "not boot\n", ninfo.tplsize);
85 	}
86 
87 	if ((splfd = open(ninfo.splfile, O_RDONLY | O_BINARY)) < 0) {
88 		fprintf (stderr, "%s: Can't open %s: %s\n",
89 			params->cmdname, ninfo.splfile, strerror(errno));
90 		exit (EXIT_FAILURE);
91 	}
92 
93 	sploffset = RKNAND_SECT_LEN + ninfo.tplpaddedsize;
94 	if (read(splfd, buf + sploffset, ninfo.splsize) != ninfo.splsize) {
95 		fprintf (stderr, "%s: Read error on %s: %s\n",
96 			params->cmdname, ninfo.splfile, strerror(errno));
97 		exit (EXIT_FAILURE);
98 	}
99 	close(splfd);
100 
101 	if (rkcommon_need_rc4_spl(params))
102 		rkcommon_rc4_encode_spl(buf, sploffset, ninfo.splpaddedsize);
103 
104 	/*
105 	 * Spread the image out so we only use the first 2KB of each pagesize
106 	 * region. This is a feature of the NAND format required by the Rockchip
107 	 * boot ROM.
108 	 */
109 	for (sector = ninfo.tplsplsize / ninfo.itersize - 1; sector >= 0; sector--) {
110 		memmove(buf + sector * ninfo.itersize + ninfo.pagesize,
111 			buf + (sector + 1) * RKNAND_SECT_LEN, RKNAND_SECT_LEN);
112 
113 		if (sector < (ninfo.tplsplsize / ninfo.itersize - 1))
114 			memset(buf + sector * ninfo.itersize  + ninfo.pagesize +
115 			       RKNAND_SECT_LEN, 0xFF, ninfo.itersize -
116 			       RKNAND_SECT_LEN);
117 	}
118 	memset(buf + RKNAND_SECT_LEN, 0xFF, ninfo.pagesize - RKNAND_SECT_LEN);
119 	memset(buf + ninfo.tplsplsize - ninfo.pagesize + RKNAND_SECT_LEN, 0xFF,
120 	       ninfo.pagesize - RKNAND_SECT_LEN);
121 }
122 
123 static int rknand_check_image_type(uint8_t type)
124 {
125 	if (type == IH_TYPE_RKNAND)
126 		return EXIT_SUCCESS;
127 	else
128 		return EXIT_FAILURE;
129 }
130 
131 static int rknand_vrec_header(struct image_tool_params *params,
132 			     struct image_type_params *tparams)
133 {
134 	rknand_fill_ninfo(params);
135 	rkcommon_vrec_header(params, tparams, RKNAND_SECT_LEN);
136 
137 	return ninfo.tplsplsize - tparams->header_size - ninfo.tplsize;
138 }
139 
140 /*
141  * rknand parameters
142  */
143 U_BOOT_IMAGE_TYPE(
144 	rknand,
145 	"Rockchip NAND Boot Image support",
146 	0,
147 	NULL,
148 	rkcommon_check_params,
149 	rkcommon_verify_header,
150 	rkcommon_print_header,
151 	rknand_set_header,
152 	NULL,
153 	rknand_check_image_type,
154 	NULL,
155 	rknand_vrec_header
156 );
157