xref: /rk3399_rockchip-uboot/tools/rknand.c (revision 87e4c6020eff05133e40ab8b7b0e37e6a2be37e4)
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, RKNAND_SECT_LEN);
67 
68 	ninfo.splpaddedsize = ROUND(ninfo.splsize, RKNAND_SECT_LEN);
69 
70 	ninfo.itersize = ninfo.pagesize * (ninfo.skippages + 1);
71 	ninfo.tplsplsize = ((ninfo.tplpaddedsize + ninfo.splpaddedsize) /
72 		     RKNAND_SECT_LEN) * ninfo.itersize;
73 }
74 
75 static void rknand_set_header(void *buf, struct stat *sbuf, int ifd,
76 			     struct image_tool_params *params)
77 {
78 	int sector, sploffset, splfd, ret;
79 
80 	ret = rkcommon_set_header(buf, ninfo.tplsize, ninfo.splsize, params);
81 	if (ret) {
82 		printf("Warning: TPL image is too large (size %#x) and will "
83 		       "not boot\n", ninfo.tplsize);
84 	}
85 
86 	if ((splfd = open(ninfo.splfile, O_RDONLY | O_BINARY)) < 0) {
87 		fprintf (stderr, "%s: Can't open %s: %s\n",
88 			params->cmdname, ninfo.splfile, strerror(errno));
89 		exit (EXIT_FAILURE);
90 	}
91 
92 	sploffset = RKNAND_SECT_LEN + ninfo.tplpaddedsize;
93 	if (read(splfd, buf + sploffset, ninfo.splsize) != ninfo.splsize) {
94 		fprintf (stderr, "%s: Read error on %s: %s\n",
95 			params->cmdname, ninfo.splfile, strerror(errno));
96 		exit (EXIT_FAILURE);
97 	}
98 	close(splfd);
99 
100 	if (rkcommon_need_rc4_spl(params))
101 		rkcommon_rc4_encode_spl(buf, sploffset, ninfo.splpaddedsize);
102 
103 	/*
104 	 * Spread the image out so we only use the first 2KB of each pagesize
105 	 * region. This is a feature of the NAND format required by the Rockchip
106 	 * boot ROM.
107 	 */
108 	for (sector = ninfo.tplsplsize / ninfo.itersize - 1; sector >= 0; sector--) {
109 		memmove(buf + sector * ninfo.itersize + ninfo.pagesize,
110 			buf + (sector + 1) * RKNAND_SECT_LEN, RKNAND_SECT_LEN);
111 
112 		if (sector < (ninfo.tplsplsize / ninfo.itersize - 1))
113 			memset(buf + sector * ninfo.itersize  + ninfo.pagesize +
114 			       RKNAND_SECT_LEN, 0xFF, ninfo.itersize -
115 			       RKNAND_SECT_LEN);
116 	}
117 	memset(buf + RKNAND_SECT_LEN, 0xFF, ninfo.pagesize - RKNAND_SECT_LEN);
118 	memset(buf + ninfo.tplsplsize - ninfo.pagesize + RKNAND_SECT_LEN, 0xFF,
119 	       ninfo.pagesize - RKNAND_SECT_LEN);
120 }
121 
122 static int rknand_check_image_type(uint8_t type)
123 {
124 	if (type == IH_TYPE_RKNAND)
125 		return EXIT_SUCCESS;
126 	else
127 		return EXIT_FAILURE;
128 }
129 
130 static int rknand_vrec_header(struct image_tool_params *params,
131 			     struct image_type_params *tparams)
132 {
133 	rknand_fill_ninfo(params);
134 	rkcommon_vrec_header(params, tparams, RKNAND_SECT_LEN);
135 
136 	return ninfo.tplsplsize - tparams->header_size - ninfo.tplsize;
137 }
138 
139 /*
140  * rknand parameters
141  */
142 U_BOOT_IMAGE_TYPE(
143 	rknand,
144 	"Rockchip NAND Boot Image support",
145 	0,
146 	NULL,
147 	rkcommon_check_params,
148 	rkcommon_verify_header,
149 	rkcommon_print_header,
150 	rknand_set_header,
151 	NULL,
152 	rknand_check_image_type,
153 	NULL,
154 	rknand_vrec_header
155 );
156