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