summaryrefslogtreecommitdiffstats
path: root/scripts/imx/imx.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-01-25 14:10:20 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2016-02-02 15:41:04 +0100
commit64dca713e5c85146932656b6c399cc402a8da4e6 (patch)
tree6c3f0747cce2ffd8fb81eb8a2c9f99243d7bcb98 /scripts/imx/imx.c
parent2cc35fe5de5f8e1fd3d933f88f6994d4ce8e0b5b (diff)
downloadbarebox-64dca713e5c85146932656b6c399cc402a8da4e6.tar.gz
barebox-64dca713e5c85146932656b6c399cc402a8da4e6.tar.xz
scripts: imx: move config file parser to separate file
To make the config parser usable by imx-usb-loader also move it to a separate file. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'scripts/imx/imx.c')
-rw-r--r--scripts/imx/imx.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c
new file mode 100644
index 0000000000..53f2bd1eae
--- /dev/null
+++ b/scripts/imx/imx.c
@@ -0,0 +1,338 @@
+/*
+ * (C) Copyright 2016 Sascha Hauer, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <linux/kernel.h>
+
+#include "imx.h"
+
+#define MAXARGS 5
+
+static int parse_line(char *line, char *argv[])
+{
+ int nargs = 0;
+
+ while (nargs < MAXARGS) {
+
+ /* skip any white space */
+ while ((*line == ' ') || (*line == '\t'))
+ ++line;
+
+ if (*line == '\0') /* end of line, no more args */
+ argv[nargs] = NULL;
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+ return nargs;
+ }
+
+ argv[nargs++] = line; /* begin of argument string */
+
+ /* find end of string */
+ while (*line && (*line != ' ') && (*line != '\t'))
+ ++line;
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+ return nargs;
+ }
+
+ *line++ = '\0'; /* terminate current arg */
+ }
+
+ printf("** Too many args (max. %d) **\n", MAXARGS);
+
+ return nargs;
+}
+
+struct command {
+ const char *name;
+ int (*parse)(struct config_data *data, int argc, char *argv[]);
+};
+
+static const char *check_cmds[] = {
+ "while_all_bits_clear", /* while ((*address & mask) == 0); */
+ "while_all_bits_set" , /* while ((*address & mask) == mask); */
+ "while_any_bit_clear", /* while ((*address & mask) != mask); */
+ "while_any_bit_set", /* while ((*address & mask) != 0); */
+};
+
+static void do_cmd_check_usage(void)
+{
+ fprintf(stderr,
+ "usage: check <width> <cmd> <addr> <mask>\n"
+ "<width> access width in bytes [1|2|4]\n"
+ "with <cmd> one of:\n"
+ "while_all_bits_clear: while ((*addr & mask) == 0)\n"
+ "while_all_bits_set: while ((*addr & mask) == mask)\n"
+ "while_any_bit_clear: while ((*addr & mask) != mask)\n"
+ "while_any_bit_set: while ((*addr & mask) != 0)\n");
+}
+
+static int do_cmd_check(struct config_data *data, int argc, char *argv[])
+{
+ uint32_t addr, mask, cmd;
+ int i, width;
+ const char *scmd;
+
+ if (argc < 5) {
+ do_cmd_check_usage();
+ return -EINVAL;
+ }
+
+ if (!data->check)
+ return -ENOSYS;
+
+ width = strtoul(argv[1], NULL, 0) >> 3;
+ scmd = argv[2];
+ addr = strtoul(argv[3], NULL, 0);
+ mask = strtoul(argv[4], NULL, 0);
+
+ switch (width) {
+ case 1:
+ case 2:
+ case 4:
+ break;
+ default:
+ fprintf(stderr, "illegal width %d\n", width);
+ return -EINVAL;
+ };
+
+ for (i = 0; i < ARRAY_SIZE(check_cmds); i++) {
+ if (!strcmp(scmd, check_cmds[i]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(check_cmds)) {
+ do_cmd_check_usage();
+ return -EINVAL;
+ }
+
+ cmd = (TAG_CHECK << 24) | (i << 3) | width | ((sizeof(uint32_t) * 3) << 8);
+
+ return data->check(data, cmd, addr, mask);
+}
+
+static int do_cmd_write_mem(struct config_data *data, int argc, char *argv[])
+{
+ uint32_t addr, val, width;
+ char *end;
+
+ if (argc != 4) {
+ fprintf(stderr, "usage: wm [8|16|32] <addr> <val>\n");
+ return -EINVAL;
+ }
+
+ width = strtoul(argv[1], &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "illegal width token \"%s\"\n", argv[1]);
+ return -EINVAL;
+ }
+
+ addr = strtoul(argv[2], &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "illegal address token \"%s\"\n", argv[2]);
+ return -EINVAL;
+ }
+
+ val = strtoul(argv[3], &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "illegal value token \"%s\"\n", argv[3]);
+ return -EINVAL;
+ }
+
+ width >>= 3;
+
+ switch (width) {
+ case 1:
+ case 2:
+ case 4:
+ break;
+ default:
+ fprintf(stderr, "illegal width %d\n", width);
+ return -EINVAL;
+ };
+
+ return data->write_mem(data, addr, val, width);
+}
+
+static int do_loadaddr(struct config_data *data, int argc, char *argv[])
+{
+ if (argc < 2)
+ return -EINVAL;
+
+ data->image_load_addr = strtoul(argv[1], NULL, 0);
+
+ return 0;
+}
+
+static int do_dcd_offset(struct config_data *data, int argc, char *argv[])
+{
+ if (argc < 2)
+ return -EINVAL;
+
+ data->image_dcd_offset = strtoul(argv[1], NULL, 0);
+
+ return 0;
+}
+
+struct soc_type {
+ char *name;
+ int header_version;
+ int cpu_type;
+};
+
+static struct soc_type socs[] = {
+ { .name = "imx25", .header_version = 1, .cpu_type = 25},
+ { .name = "imx35", .header_version = 1, .cpu_type = 35 },
+ { .name = "imx51", .header_version = 1, .cpu_type = 51 },
+ { .name = "imx53", .header_version = 2, .cpu_type = 53 },
+ { .name = "imx6", .header_version = 2, .cpu_type = 6 },
+};
+
+static int do_soc(struct config_data *data, int argc, char *argv[])
+{
+ char *soc;
+ int i;
+
+ if (argc < 2)
+ return -EINVAL;
+
+ soc = argv[1];
+
+ for (i = 0; i < ARRAY_SIZE(socs); i++) {
+ if (!strcmp(socs[i].name, soc)) {
+ data->header_version = socs[i].header_version;
+ data->cpu_type = socs[i].cpu_type;
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "unkown SoC type \"%s\". Known SoCs are:\n", soc);
+ for (i = 0; i < ARRAY_SIZE(socs); i++)
+ fprintf(stderr, "%s ", socs[i].name);
+ fprintf(stderr, "\n");
+
+ return -EINVAL;
+}
+
+struct command cmds[] = {
+ {
+ .name = "wm",
+ .parse = do_cmd_write_mem,
+ }, {
+ .name = "check",
+ .parse = do_cmd_check,
+ }, {
+ .name = "loadaddr",
+ .parse = do_loadaddr,
+ }, {
+ .name = "dcdofs",
+ .parse = do_dcd_offset,
+ }, {
+ .name = "soc",
+ .parse = do_soc,
+ },
+};
+
+static char *readcmd(struct config_data *data, FILE *f)
+{
+ static char *buf;
+ char *str;
+ ssize_t ret;
+
+ if (!buf) {
+ buf = malloc(4096);
+ if (!buf)
+ return NULL;
+ }
+
+ str = buf;
+ *str = 0;
+
+ while (1) {
+ ret = fread(str, 1, 1, f);
+ if (!ret)
+ return strlen(buf) ? buf : NULL;
+
+ if (*str == '\n' || *str == ';') {
+ *str = 0;
+ return buf;
+ }
+
+ str++;
+ }
+}
+
+int parse_config(struct config_data *data, const char *filename)
+{
+ FILE *f;
+ int lineno = 0;
+ char *line = NULL, *tmp;
+ char *argv[MAXARGS];
+ int nargs, i, ret = 0;
+
+ f = fopen(filename, "r");
+ if (!f) {
+ fprintf(stderr, "Error: %s - Can't open DCD file\n", filename);
+ exit(1);
+ }
+
+ while (1) {
+ line = readcmd(data, f);
+ if (!line)
+ break;
+
+ lineno++;
+
+ tmp = strchr(line, '#');
+ if (tmp)
+ *tmp = 0;
+
+ nargs = parse_line(line, argv);
+ if (!nargs)
+ continue;
+
+ ret = -ENOENT;
+
+ for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+ if (!strcmp(cmds[i].name, argv[0])) {
+ ret = cmds[i].parse(data, nargs, argv);
+ if (ret) {
+ fprintf(stderr, "error in line %d: %s\n",
+ lineno, strerror(-ret));
+ goto cleanup;
+ }
+ break;
+ }
+ }
+
+ if (ret == -ENOENT) {
+ fprintf(stderr, "no such command: %s\n", argv[0]);
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ fclose(f);
+ return ret;
+}