view fluid-mnf/flash.c @ 342:6ff231195905

fluid-mnf/serial.[ch]: beginning of Linux port
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 13 Mar 2020 05:39:37 +0000
parents 9cecc930d78f
children f89a20e7adc7
line wrap: on
line source

/******************************************************************************
 * FLUID (Flash Loader Utility Independent of Device)
 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
 *
 * Copyright Texas Instruments, 2001.
 * Mads Meisner-Jensen, mmj@ti.com.
 *
 * Flash device database and lookup
 *
 * $Id: flash.c 1.26 Wed, 30 Oct 2002 12:09:08 +0100 tsj $
 *
 ******************************************************************************/

#include "fluid.h"
#include "misc.h"
#include "flash.h"
#include "trace.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>


/******************************************************************************
 * Global, Static definitions
 ******************************************************************************/

const struct algorithm_s algorithms[] = {
    { ALGORITHM_AMD,        "amd" },
    { ALGORITHM_INTEL,      "intel" },
    { ALGORITHM_INTEL_BW,   "intel_bw" },
    { ALGORITHM_MITSUBISHI, "mitsubishi" },
    { ALGORITHM_SST,        "sst" },
    { 0,                    "unknown" }
};

struct manufact_s manufacturers[] = {
    { MANUFACT_AMD,        "AMD" },
    { MANUFACT_ATMEL,      "Atmel" },
    { MANUFACT_FUJITSU,    "Fujitsu" },
    { MANUFACT_INTEL,      "Intel" },
    { MANUFACT_MXIC,       "MXIC" },
    { MANUFACT_MITSUBISHI, "Mitsubishi" },
    { MANUFACT_SAMSUNG,    "Samsung" },
    { MANUFACT_SHARP,      "Sharp" },
    { MANUFACT_STM,        "STM" },
    { MANUFACT_SST,        "SST" },
    { MANUFACT_TOSHIBA,    "Toshiba" },
    { 0x00,                "Unknown" }
};


/******************************************************************************
 * Default Device Database
 ******************************************************************************/

struct memmap_s map_63x64_8x8 = {
    0,
    "63x64_8x8kB",
    63 + 8,
    {
        { 0x000000, 0x10000 }, { 0x010000, 0x10000 },
        { 0x020000, 0x10000 }, { 0x030000, 0x10000 },
        { 0x040000, 0x10000 }, { 0x050000, 0x10000 },
        { 0x060000, 0x10000 }, { 0x070000, 0x10000 },
        { 0x080000, 0x10000 }, { 0x090000, 0x10000 },
        { 0x0A0000, 0x10000 }, { 0x0B0000, 0x10000 },
        { 0x0C0000, 0x10000 }, { 0x0D0000, 0x10000 },
        { 0x0E0000, 0x10000 }, { 0x0F0000, 0x10000 },

        { 0x100000, 0x10000 }, { 0x110000, 0x10000 },
        { 0x120000, 0x10000 }, { 0x130000, 0x10000 },
        { 0x140000, 0x10000 }, { 0x150000, 0x10000 },
        { 0x160000, 0x10000 }, { 0x170000, 0x10000 },
        { 0x180000, 0x10000 }, { 0x190000, 0x10000 },
        { 0x1A0000, 0x10000 }, { 0x1B0000, 0x10000 },
        { 0x1C0000, 0x10000 }, { 0x1D0000, 0x10000 },
        { 0x1E0000, 0x10000 }, { 0x1F0000, 0x10000 },

        { 0x200000, 0x10000 }, { 0x210000, 0x10000 },
        { 0x220000, 0x10000 }, { 0x230000, 0x10000 },
        { 0x240000, 0x10000 }, { 0x250000, 0x10000 },
        { 0x260000, 0x10000 }, { 0x270000, 0x10000 },
        { 0x280000, 0x10000 }, { 0x290000, 0x10000 },
        { 0x2A0000, 0x10000 }, { 0x2B0000, 0x10000 },
        { 0x2C0000, 0x10000 }, { 0x2D0000, 0x10000 },
        { 0x2E0000, 0x10000 }, { 0x2F0000, 0x10000 },

        { 0x300000, 0x10000 }, { 0x310000, 0x10000 },
        { 0x320000, 0x10000 }, { 0x330000, 0x10000 },
        { 0x340000, 0x10000 }, { 0x350000, 0x10000 },
        { 0x360000, 0x10000 }, { 0x370000, 0x10000 },
        { 0x380000, 0x10000 }, { 0x390000, 0x10000 },
        { 0x3A0000, 0x10000 }, { 0x3B0000, 0x10000 },
        { 0x3C0000, 0x10000 }, { 0x3D0000, 0x10000 },
        { 0x3E0000, 0x10000 },

        { 0x3F0000, 0x02000 }, { 0x3F2000, 0x02000 },
        { 0x3F4000, 0x02000 }, { 0x3F6000, 0x02000 },
        { 0x3F8000, 0x02000 }, { 0x3FA000, 0x02000 },
        { 0x3FC000, 0x02000 }, { 0x3FE000, 0x02000 },
    }
};

struct memmap_s *memmaps = &map_63x64_8x8;

// Default B-Sample device
struct device_s device_fujitsu_dl323t = {
    0,
    ALGORITHM_AMD,
    MANUFACT_FUJITSU,
    0x2250,
    "MBM29DL323DT",
    0,
    0,
    &map_63x64_8x8
};

// Default C-Sample device
struct device_s device_amd_dl322t = {
    &device_fujitsu_dl323t, // link to next (previous) device defintion
    ALGORITHM_AMD,
    MANUFACT_AMD,
    0x2255,
    "Am29DL322DT",
    0,
    0,
    &map_63x64_8x8
};

struct device_s *devices = &device_amd_dl322t;


/******************************************************************************
 * Device file reading and parsing
 ******************************************************************************/

#define INBUF_SIZE 1024

static char inbuf[INBUF_SIZE];
static char *pin;
static FILE *fp;
static int  linenum;

static char string[1024];
static int  length;
static int  number;

enum ParserTokens {
    TOKEN_EOF,
    TOKEN_STRING,
    TOKEN_NUMBER,
    TOKEN_KEYWORD
};

enum ParserKeywords {
    KEYWORD_NONE,
    KEYWORD_DEVICE,
    KEYWORD_MEMMAP
};

void parser_error(int error)
{
    fprintf(stderr, "At line %d, ", linenum);
    main_fatal(error);
}

void file_read_devices(char *filename)
{
    int token, i, n = 0;
    struct device_s *device;
    struct memmap_s *memmap;

    flowf(BLABBER, "Reading '%s': ", filename);

    // First look for file in current directory. Then look for it in the
    // directory where the fluid executable was found.
    if ((fp = fopen(filename, "rt")) == NULL)
    {
        char buf[256];

        if (pathname_make(buf, sizeof(buf), argv_0, filename) < 0)
            main_fatal(E_BUFFER);

        flowf(DEBUG, "(looking for '%s') ", buf);

        if ((fp = fopen(buf, "rt")) == NULL) {
            fprintf(stderr, "WARNING: file '%s' not found. Using default device database.\n", filename);
            return;
        }
    }

    devices = (struct device_s *) 0;
    memmaps = (struct memmap_s *) 0;

    pin = inbuf;
    inbuf[0] = '\n';
    linenum = 0;

    // Each loop represents one block/statement of the file
    while ((token = get_keyword()) != E_PARSER_EOF) {
        switch (token) {
        case KEYWORD_MEMMAP:
            tr(TrBegin|TrParser, "keyword: memmap {\n");
            if ((token = get_string()) < 0)
                parser_error(token);

            if ((memmap = malloc(sizeof(struct memmap_s) + length + 1)) == NULL)
                parser_error(E_MEMORY);
            memmap->name = (char *) memmap + sizeof(struct memmap_s);
            strcpy(memmap->name, string);

            if ((token = get_token()) != '{')
                parser_error(E_PARSER_SYNTAX);

            i = 0;
            while ((token = get_token()) == TOKEN_NUMBER)
            {
                memmap->sectors[i].addr = number;

                if ((token = get_number()) < 0)
                    parser_error(token);
                memmap->sectors[i].size = number;

                i++;
            }
            if (token != '}')
                parser_error(E_PARSER_END_BRACE);

            memmap->size = i;

            // Append to linked list
            memmap->next = memmaps;
            memmaps = memmap;

            tr(TrEnd|TrParser, "}\n");
            break;

        case KEYWORD_DEVICE:
            tr(TrBegin|TrParser, "keyword: device {\n");
            if ((token = get_string()) < 0)
                parser_error(token);
            if ((device = malloc(sizeof(struct device_s) + length + 1)) == NULL)
                parser_error(E_MEMORY);
            device->name = (char *) device + sizeof(struct device_s);
            strcpy(device->name, string);

            if ((token = get_number()) < 0)
                parser_error(token);
            device->manufacturer_id = number;

            if ((token = get_number()) < 0)
                parser_error(token);
            device->device_id = number;

            if ((token = get_string()) < 0)
                parser_error(token);
            device->algorithm_id = algorithm_id_lookup_by_name(string);
            if (device->algorithm_id == 0)
                parser_error(E_PARSER_ALGORITHM);

            if ((token = get_string()) < 0)
                parser_error(token);
            device->memmap = memmap_lookup_by_name(string);
            if (device->memmap == 0)
                parser_error(E_PARSER_MEMMAP);

            // Append to linked list
            device->next = devices;
            devices = device;

            tr(TrEnd|TrParser, "}\n");
            break;
        default:
            parser_error(E_PARSER_KEYWORD);
        }
        n++;
    }

    flowf(BLABBER, "(%d blocks read) ok.\n", n);
}

int get_next_line(void)
{
    int result;

    result = (fgets(inbuf, INBUF_SIZE, fp) != NULL);

    pin = inbuf;
    linenum++;

    tr(TrParser, "get_next_line() (%d) %d ", result);

    return result;
}

int get_token(void)
{
    char *pin_start, *pin_end;
    int whitespace;

    {
        char tmp[8];
        for (whitespace = 0; whitespace < 7; whitespace++)
            tmp[whitespace] = (pin[whitespace] < ' ' ? '.' : pin[whitespace]);
        tmp[7] = 0;
        tr(TrParser, "get_token() ('%s...')", tmp);
    }

    whitespace = 1;

    while (whitespace)
    {
        if (*pin == ' ' || *pin == '\t' || *pin == '\n') {
            // Skip white-space
            tr(TrParser, " skip white-space {");
            while (*pin == ' ' || *pin == '\t' || *pin == '\n')
            {
                while (*pin == ' ' || *pin == '\t')
                    pin++;

                // If end of line, read the next line
                if (*pin == '\n') {
                    if (get_next_line() == 0)
                        return TOKEN_EOF;
                }
            }
            tr(TrCont|TrParser, "}");
        }
        else if (pin[0] == '/' && pin[1] == '*') {
            // Skip comment
            tr(TrParser, " skip comment {");
            while (pin[0] != '*' || pin[1] != '/')
            {
                while ((pin[0] != '*' || pin[1] != '/') && *pin != '\n')
                    pin++;

                // If end of line, read the next line
                if (*pin == '\n') {
                    if (get_next_line() == 0)
                        return TOKEN_EOF;
                }
                else {
                    pin += 2;
                    break;
                }
            }
            tr(TrCont|TrParser, "}");
        }
        else {
            whitespace = 0;
        }
    }

    {
        char tmp[8];
        for (whitespace = 0; whitespace < 7; whitespace++)
            tmp[whitespace] = (pin[whitespace] < ' ' ? '.' : pin[whitespace]);
        tmp[7] = 0;
        tr(TrCont|TrParser, " ('%s...')\n", tmp);
    }

    // See if token is a string
    if (isalpha(*pin) || *pin == '_') {
        pin_start = pin;
        while (isalnum(*pin) || *pin == '_')
            pin++;
        length = pin - pin_start;
        strncpy(string, pin_start, length);
        string[length] = 0;
        return TOKEN_STRING;
    }

    // See if token is a number
    if (isdigit(*pin)) {
        number = (int) strtol(pin, &pin_end, 0);
        pin = pin_end;
        if (*pin_end == 'k') {
            number *= 1024;
            pin++;
        }
        return TOKEN_NUMBER;
    }

    // Token is a character
    return *pin++;
}

int get_keyword(void)
{
    int token;

    token = get_token();
    tr(TrParser, "get_keyword() (%d) ", token);

    if (token == TOKEN_EOF)
        return E_PARSER_EOF;

    if (token != TOKEN_STRING)
        return E_PARSER_KEYWORD;

    if (strcmp("memmap", string) == 0)
        token = KEYWORD_MEMMAP;
    else if (strcmp("device", string) == 0)
        token = KEYWORD_DEVICE;
    else
        token = E_PARSER_KEYWORD;

    tr(TrCont|TrParser, "%d\n", token);
    return token;
}

int get_string(void)
{
    int token;

    token = get_token();
    tr(TrParser, "get_string() (%d) ", token);

    if (token == TOKEN_EOF)
        return E_PARSER_EOF;

    if (token != TOKEN_STRING)
        return E_PARSER_STRING;

    tr(TrCont|TrParser, "'%s'\n", string);
    return 0;
}

int get_number(void)
{
    int token;

    token = get_token();
    tr(TrParser, "get_number() (%d) ", token);

    if (token == TOKEN_EOF)
        return E_PARSER_EOF;

    if (token != TOKEN_NUMBER)
        return E_PARSER_NUMBER;

    tr(TrCont|TrParser, "0x%X\n", number);
    return 0;
}


/******************************************************************************
 * Functions
 ******************************************************************************/

// Estimate the time taken for erasure and programming of the flash
// device. <bytes> is the number of bytes to program.
int time_compute(struct device_s *device,
                 int sectors, int bytes, int chunks,
                 int *time_erase, int *time_program, int *time_transfer)
{
    int te =  0; // sector erase time in milli seconds
    int tp = 16; // 16-bit word program time in micro seconds
    int tdt, tco, trp;

    switch (device->algorithm_id) {
    case ALGORITHM_AMD:        te =  700; break;
    case ALGORITHM_INTEL:      te =  800; break;
    case ALGORITHM_INTEL_BW:   te = 1300; break;
    case ALGORITHM_MITSUBISHI: te =   40; break;
    case ALGORITHM_SST:        te =   20; break;
    }
    *time_erase   = te * sectors;

    // Data transmission time: with 12 bytes per chunk
    tdt = (bytes + 12 * chunks) / (arg_uart_baudrate / 10) * 1000;

    // Communication overhead time: 2 waits of 10ms per chunk.
    tco = chunks * 2 * 10;

    *time_transfer = tdt + tco;

    // Raw programming time:
    *time_program = trp = (bytes / 2) * tp / 1000;

    tr(TrUtility, "tdt = %d\n", tdt);
    tr(TrUtility, "tco = %d\n", tco);
    tr(TrUtility, "trp = %d\n", trp);

    return *time_erase + *time_transfer;
}

void device_print(struct device_s *device, char format)
{
    int device_size =
        (device->memmap->sectors[device->memmap->size - 1].addr +
         device->memmap->sectors[device->memmap->size - 1].size) /
        (1024 * 1024 / 8);

    if (format == 'l') {
        printf("%s %s (0x%02X, 0x%04X). %dMb in %d sectors, %s algorithm",
               manufacturer_name_lookup_by_id(device->manufacturer_id),
               device->name,
               device->manufacturer_id,
               device->device_id,
               device_size,
               device->memmap->size,
               algorithm_name_lookup_by_id(device->algorithm_id));
    }
    else if (format == 's') {
        printf("(0x%02X, 0x%04X) %s %s",
               device->manufacturer_id,
               device->device_id,
               manufacturer_name_lookup_by_id(device->manufacturer_id),
               device->name);
    }
}

void devices_list(void)
{
    struct device_s *device = devices;

    while (device != NULL) {
        device_print(device, 'l');
        putchar('\n');
        device = device->next;
    }
}

struct device_s *device_lookup_by_id(int m, int d)
{
    struct device_s *device = devices;

    while (device != NULL) {
        if ((m & 0xFF) == device->manufacturer_id && d == device->device_id)
            return device;
        device = device->next;
    }
    return (struct device_s *) 0;
}

struct device_s *device_lookup_by_name(char *name)
{
    struct device_s *device = devices;

    while (device != NULL) {
        if (strcmp(name, device->name) == 0)
            return device;
        device = device->next;
    }
    return (struct device_s *) 0;

}

struct memmap_s *memmap_lookup_by_name(char *name)
{
    struct memmap_s *memmap = memmaps;

    while (memmap != NULL) {
        if (strcmp(name, memmap->name) == 0)
            return memmap;
        memmap = memmap->next;
    }
    return (struct memmap_s *) 0;
}

char *manufacturer_name_lookup_by_id(int id)
{
    int i = 0;

    while (manufacturers[i].id != 0) {
        if (manufacturers[i].id == id)
            return manufacturers[i].name;
        i++;
    }

    return manufacturers[i].name;
}

int manufacturer_id_lookup_by_name(char *name)
{
    int i = 0;

    while (manufacturers[i].id != 0) {
        if (strcmp(manufacturers[i].name, name) == 0)
            return manufacturers[i].id;
        i++;
    }

    return 0;
}

char *algorithm_name_lookup_by_id(int id)
{
    int i = 0;

    while (algorithms[i].id != 0) {
        if (algorithms[i].id == id)
            return algorithms[i].name;
        i++;
    }

    return algorithms[i].name;
}

int algorithm_id_lookup_by_name(char *name)
{
    int i = 0;

    while (algorithms[i].id != 0) {
        if (strcmp(algorithms[i].name, name) == 0)
            return algorithms[i].id;
        i++;
    }

    return 0;
}