uboot/tools/atmelimage.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2014
   4 * Andreas Bießmann <andreas@biessmann.org>
   5 */
   6
   7#include "imagetool.h"
   8#include "mkimage.h"
   9
  10#include <image.h>
  11
  12#define pr_err(fmt, args...) fprintf(stderr, "atmelimage Error: " fmt, ##args)
  13
  14static int atmel_check_image_type(uint8_t type)
  15{
  16        if (type == IH_TYPE_ATMELIMAGE)
  17                return EXIT_SUCCESS;
  18        else
  19                return EXIT_FAILURE;
  20}
  21
  22static uint32_t nand_pmecc_header[52];
  23
  24/*
  25 * A helper struct for parsing the mkimage -n parameter
  26 *
  27 * Keep in same order as the configs array!
  28 */
  29static struct pmecc_config {
  30        int use_pmecc;
  31        int sector_per_page;
  32        int spare_size;
  33        int ecc_bits;
  34        int sector_size;
  35        int ecc_offset;
  36} pmecc;
  37
  38/*
  39 * Strings used for configure the PMECC header via -n mkimage switch
  40 *
  41 * We estimate a coma separated list of key=value pairs. The mkimage -n
  42 * parameter argument should not contain any whitespace.
  43 *
  44 * Keep in same order as struct pmecc_config!
  45 */
  46static const char * const configs[] = {
  47        "usePmecc",
  48        "sectorPerPage",
  49        "spareSize",
  50        "eccBits",
  51        "sectorSize",
  52        "eccOffset"
  53};
  54
  55static int atmel_find_pmecc_parameter_in_token(const char *token)
  56{
  57        size_t pos;
  58        char *param;
  59
  60        debug("token: '%s'\n", token);
  61
  62        for (pos = 0; pos < ARRAY_SIZE(configs); pos++) {
  63                if (strncmp(token, configs[pos], strlen(configs[pos])) == 0) {
  64                        param = strstr(token, "=");
  65                        if (!param)
  66                                goto err;
  67
  68                        param++;
  69                        debug("\t%s parameter: '%s'\n", configs[pos], param);
  70
  71                        switch (pos) {
  72                        case 0:
  73                                pmecc.use_pmecc = strtol(param, NULL, 10);
  74                                return EXIT_SUCCESS;
  75                        case 1:
  76                                pmecc.sector_per_page = strtol(param, NULL, 10);
  77                                return EXIT_SUCCESS;
  78                        case 2:
  79                                pmecc.spare_size = strtol(param, NULL, 10);
  80                                return EXIT_SUCCESS;
  81                        case 3:
  82                                pmecc.ecc_bits = strtol(param, NULL, 10);
  83                                return EXIT_SUCCESS;
  84                        case 4:
  85                                pmecc.sector_size = strtol(param, NULL, 10);
  86                                return EXIT_SUCCESS;
  87                        case 5:
  88                                pmecc.ecc_offset = strtol(param, NULL, 10);
  89                                return EXIT_SUCCESS;
  90                        }
  91                }
  92        }
  93
  94err:
  95        pr_err("Could not find parameter in token '%s'\n", token);
  96        return EXIT_FAILURE;
  97}
  98
  99static int atmel_parse_pmecc_params(char *txt)
 100{
 101        char *token;
 102
 103        token = strtok(txt, ",");
 104        while (token != NULL) {
 105                if (atmel_find_pmecc_parameter_in_token(token))
 106                        return EXIT_FAILURE;
 107
 108                token = strtok(NULL, ",");
 109        }
 110
 111        return EXIT_SUCCESS;
 112}
 113
 114static int atmel_verify_header(unsigned char *ptr, int image_size,
 115                        struct image_tool_params *params)
 116{
 117        uint32_t *ints = (uint32_t *)ptr;
 118        size_t pos;
 119        size_t size = image_size;
 120
 121        /* check if we have an PMECC header attached */
 122        for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
 123                if (ints[pos] >> 28 != 0xC)
 124                        break;
 125
 126        if (pos == ARRAY_SIZE(nand_pmecc_header)) {
 127                ints += ARRAY_SIZE(nand_pmecc_header);
 128                size -= sizeof(nand_pmecc_header);
 129        }
 130
 131        /* check the seven interrupt vectors of binary */
 132        for (pos = 0; pos < 7; pos++) {
 133                debug("atmelimage: interrupt vector #%zu is 0x%08X\n", pos+1,
 134                      ints[pos]);
 135                /*
 136                 * all vectors except the 6'th one must contain valid
 137                 * LDR or B Opcode
 138                 */
 139                if (pos == 5)
 140                        /* 6'th vector has image size set, check later */
 141                        continue;
 142                if ((ints[pos] & 0xff000000) == 0xea000000)
 143                        /* valid B Opcode */
 144                        continue;
 145                if ((ints[pos] & 0xfffff000) == 0xe59ff000)
 146                        /* valid LDR (I=0, P=1, U=1, B=0, W=0, L=1) */
 147                        continue;
 148                /* ouch, one of the checks has missed ... */
 149                return 1;
 150        }
 151
 152        return ints[5] != cpu_to_le32(size);
 153}
 154
 155static void atmel_print_pmecc_header(const uint32_t word)
 156{
 157        int val;
 158
 159        printf("\t\tPMECC header\n");
 160
 161        printf("\t\t====================\n");
 162
 163        val = (word >> 18) & 0x1ff;
 164        printf("\t\teccOffset: %9i\n", val);
 165
 166        val = (((word >> 16) & 0x3) == 0) ? 512 : 1024;
 167        printf("\t\tsectorSize: %8i\n", val);
 168
 169        if (((word >> 13) & 0x7) <= 2)
 170                val = (2 << ((word >> 13) & 0x7));
 171        else
 172                val = (12 << (((word >> 13) & 0x7) - 3));
 173        printf("\t\teccBitReq: %9i\n", val);
 174
 175        val = (word >> 4) & 0x1ff;
 176        printf("\t\tspareSize: %9i\n", val);
 177
 178        val = (1 << ((word >> 1) & 0x3));
 179        printf("\t\tnbSectorPerPage: %3i\n", val);
 180
 181        printf("\t\tusePmecc: %10i\n", word & 0x1);
 182        printf("\t\t====================\n");
 183}
 184
 185static void atmel_print_header(const void *ptr)
 186{
 187        uint32_t *ints = (uint32_t *)ptr;
 188        size_t pos;
 189
 190        /* check if we have an PMECC header attached */
 191        for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
 192                if (ints[pos] >> 28 != 0xC)
 193                        break;
 194
 195        if (pos == ARRAY_SIZE(nand_pmecc_header)) {
 196                printf("Image Type:\tATMEL ROM-Boot Image with PMECC Header\n");
 197                atmel_print_pmecc_header(ints[0]);
 198                pos += 5;
 199        } else {
 200                printf("Image Type:\tATMEL ROM-Boot Image without PMECC Header\n");
 201                pos = 5;
 202        }
 203        printf("\t\t6'th vector has %u set\n", le32_to_cpu(ints[pos]));
 204}
 205
 206static void atmel_set_header(void *ptr, struct stat *sbuf, int ifd,
 207                                struct image_tool_params *params)
 208{
 209        /* just save the image size into 6'th interrupt vector */
 210        uint32_t *ints = (uint32_t *)ptr;
 211        size_t cnt;
 212        size_t pos = 5;
 213        size_t size = sbuf->st_size;
 214
 215        for (cnt = 0; cnt < ARRAY_SIZE(nand_pmecc_header); cnt++)
 216                if (ints[cnt] >> 28 != 0xC)
 217                        break;
 218
 219        if (cnt == ARRAY_SIZE(nand_pmecc_header)) {
 220                pos += ARRAY_SIZE(nand_pmecc_header);
 221                size -= sizeof(nand_pmecc_header);
 222        }
 223
 224        ints[pos] = cpu_to_le32(size);
 225}
 226
 227static int atmel_check_params(struct image_tool_params *params)
 228{
 229        if (strlen(params->imagename) > 0)
 230                if (atmel_parse_pmecc_params(params->imagename))
 231                        return EXIT_FAILURE;
 232
 233        return !(!params->eflag &&
 234                !params->fflag &&
 235                !params->xflag &&
 236                ((params->dflag && !params->lflag) ||
 237                 (params->lflag && !params->dflag)));
 238}
 239
 240static int atmel_vrec_header(struct image_tool_params *params,
 241                                struct image_type_params *tparams)
 242{
 243        uint32_t tmp;
 244        size_t pos;
 245
 246        if (strlen(params->imagename) == 0)
 247                return EXIT_SUCCESS;
 248
 249        tmp = 0xC << 28;
 250
 251        tmp |= (pmecc.ecc_offset & 0x1ff) << 18;
 252
 253        switch (pmecc.sector_size) {
 254        case 512:
 255                tmp |= 0 << 16;
 256                break;
 257        case 1024:
 258                tmp |= 1 << 16;
 259                break;
 260
 261        default:
 262                pr_err("Wrong sectorSize (%i) for PMECC header\n",
 263                       pmecc.sector_size);
 264                return EXIT_FAILURE;
 265        }
 266
 267        switch (pmecc.ecc_bits) {
 268        case 2:
 269                tmp |= 0 << 13;
 270                break;
 271        case 4:
 272                tmp |= 1 << 13;
 273                break;
 274        case 8:
 275                tmp |= 2 << 13;
 276                break;
 277        case 12:
 278                tmp |= 3 << 13;
 279                break;
 280        case 24:
 281                tmp |= 4 << 13;
 282                break;
 283
 284        default:
 285                pr_err("Wrong eccBits (%i) for PMECC header\n",
 286                       pmecc.ecc_bits);
 287                 return EXIT_FAILURE;
 288        }
 289
 290        tmp |= (pmecc.spare_size & 0x1ff) << 4;
 291
 292        switch (pmecc.sector_per_page) {
 293        case 1:
 294                tmp |= 0 << 1;
 295                break;
 296        case 2:
 297                tmp |= 1 << 1;
 298                break;
 299        case 4:
 300                tmp |= 2 << 1;
 301                break;
 302        case 8:
 303                tmp |= 3 << 1;
 304                break;
 305
 306        default:
 307                pr_err("Wrong sectorPerPage (%i) for PMECC header\n",
 308                       pmecc.sector_per_page);
 309                return EXIT_FAILURE;
 310        }
 311
 312        if (pmecc.use_pmecc)
 313                tmp |= 1;
 314
 315        for (pos = 0; pos < ARRAY_SIZE(nand_pmecc_header); pos++)
 316                nand_pmecc_header[pos] = tmp;
 317
 318        debug("PMECC header filled 52 times with 0x%08X\n", tmp);
 319
 320        tparams->header_size = sizeof(nand_pmecc_header);
 321        tparams->hdr = nand_pmecc_header;
 322
 323        return EXIT_SUCCESS;
 324}
 325
 326U_BOOT_IMAGE_TYPE(
 327        atmelimage,
 328        "ATMEL ROM-Boot Image support",
 329        0,
 330        NULL,
 331        atmel_check_params,
 332        atmel_verify_header,
 333        atmel_print_header,
 334        atmel_set_header,
 335        NULL,
 336        atmel_check_image_type,
 337        NULL,
 338        atmel_vrec_header
 339);
 340