diff --git a/Makefile b/Makefile index 67da5c3..961f66e 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ fex2bin bin2fex: fexc ln -s $< $@ fexc: fexc.h script.h script.c \ + script_uboot.h script_uboot.c \ script_bin.h script_bin.c \ script_fex.h script_fex.c diff --git a/fexc.c b/fexc.c index 3306cd0..c325735 100644 --- a/fexc.c +++ b/fexc.c @@ -32,6 +32,7 @@ enum script_format { FEX_SCRIPT_FORMAT, BIN_SCRIPT_FORMAT, + UBOOT_HEADER_FORMAT, }; /* @@ -145,6 +146,8 @@ static inline int script_parse(enum script_format format, bin_close: close(in); }; break; + case UBOOT_HEADER_FORMAT: /* not valid input */ + ; } return ret; } @@ -153,21 +156,24 @@ static inline int script_generate(enum script_format format, struct script *script) { int ret = 0; - switch (format) { - case FEX_SCRIPT_FORMAT: { + static int (*text_gen[3]) (FILE *, const char *, struct script *) = { + [FEX_SCRIPT_FORMAT] = script_generate_fex, + [UBOOT_HEADER_FORMAT] = script_generate_uboot, + }; + + if (text_gen[format]) { FILE *out = stdout; if (!filename) filename = ""; else if ((out = fopen(filename, "w")) == NULL) { pr_err("%s: %s\n", filename, strerror(errno)); - break; + goto done; } - ret = script_generate_fex(out, filename, script); + ret = text_gen[format](out, filename, script); fclose(out); - }; break; - case BIN_SCRIPT_FORMAT: { + } else { int out = 1; /* stdout */ size_t sections, entries, bin_size; void *bin; @@ -176,7 +182,7 @@ static inline int script_generate(enum script_format format, filename = ""; else if ((out = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { pr_err("%s: %s\n", filename, strerror(errno)); - break; + goto done; } bin_size = script_bin_size(script, §ions, &entries); @@ -201,8 +207,8 @@ static inline int script_generate(enum script_format format, } free(bin); close(out); - }; break; } +done: return ret; } @@ -215,7 +221,7 @@ static inline void app_usage(const char *arg0, int mode) if (mode == 0) fputs("\ninfmt: fex, bin (default:fex)" - "\noutfmt: fex, bin (default:bin)\n", + "\noutfmt: fex, bin, uboot (default:bin)\n", stderr); } @@ -234,7 +240,7 @@ static inline int app_choose_mode(char *arg0) */ int main(int argc, char *argv[]) { - static const char *formats[] = { "fex", "bin", NULL }; + static const char *formats[] = { "fex", "bin", "uboot", NULL }; enum script_format infmt=FEX_SCRIPT_FORMAT; enum script_format outfmt=BIN_SCRIPT_FORMAT; const char *filename[] = { NULL /*stdin*/, NULL /*stdout*/}; @@ -246,8 +252,10 @@ int main(int argc, char *argv[]) int opt, ret = 1; int verbose = 0; - if (app_mode == 2) /* bin2fex */ - infmt = 1, outfmt = 0; + if (app_mode == 2) { /* bin2fex */ + infmt = BIN_SCRIPT_FORMAT; + outfmt = FEX_SCRIPT_FORMAT; + } while ((opt = getopt(argc, argv, opt_string)) != -1) { switch (opt) { @@ -257,7 +265,11 @@ int main(int argc, char *argv[]) if (strcmp(*f, optarg) == 0) break; } - if (!formats[infmt]) { + switch (infmt) { + case FEX_SCRIPT_FORMAT: + case BIN_SCRIPT_FORMAT: + break; + default: errf("%s: invalid format -- \"%s\"\n", argv[0], optarg); goto show_usage; diff --git a/fexc.h b/fexc.h index 2b33395..c5b32a9 100644 --- a/fexc.h +++ b/fexc.h @@ -25,5 +25,6 @@ #include "script.h" #include "script_bin.h" #include "script_fex.h" +#include "script_uboot.h" #endif diff --git a/pio.c b/pio.c index 8a39ee7..94bd005 100644 --- a/pio.c +++ b/pio.c @@ -1,3 +1,22 @@ +/* + * (C) Copyright 2011 Henrik Nordstrom + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + /* needs _BSD_SOURCE for htole and letoh */ #define _BSD_SOURCE @@ -14,8 +33,6 @@ #define PIO_REG_SIZE 0x228 /*0x300*/ #define PIO_PORT_SIZE 0x24 -#define errf(...) fprintf(stderr, __VA_ARGS__) - struct pio_status { int mul_sel; int pull; diff --git a/script.c b/script.c index 3950470..3a9c7e7 100644 --- a/script.c +++ b/script.c @@ -90,6 +90,26 @@ void script_section_delete(struct script_section *section) list_remove(§ion->sections); } +struct script_section *script_find_section(struct script *script, + const char *name) +{ + struct list_entry *o; + struct script_section *section; + + assert(script); + assert(name); + + for (o = list_first(&script->sections); o; + o = list_next(&script->sections, o)) { + section = container_of(o, struct script_section, sections); + + if (strcmp(section->name, name) == 0) + return section; + } + + return NULL; +} + /* */ static inline void script_entry_append(struct script_section *section, @@ -226,3 +246,23 @@ struct script_gpio_entry *script_gpio_entry_new(struct script_section *section, return entry; } + +struct script_entry *script_find_entry(struct script_section *section, + const char *name) +{ + struct list_entry *o; + struct script_entry *ep; + + assert(section); + assert(name); + + for (o = list_first(§ion->entries); o; + o = list_next(§ion->entries, o)) { + ep = container_of(o, struct script_entry, entries); + + if (strcmp(ep->name, name) == 0) + return ep; + } + + return NULL; +} diff --git a/script.h b/script.h index 1f7f199..0fa2134 100644 --- a/script.h +++ b/script.h @@ -86,6 +86,10 @@ struct script_section *script_section_new(struct script *script, /** deletes a section recursvely and removes it from the script */ void script_section_delete(struct script_section *section); +/** find existing section */ +struct script_section *script_find_section(struct script *script, + const char *name); + /** deletes an entry and removes it from the section */ void script_entry_delete(struct script_entry *entry); @@ -106,4 +110,7 @@ struct script_gpio_entry *script_gpio_entry_new(struct script_section *script, unsigned port, unsigned num, int32_t data[4]); +/** find existing entry in a giving section */ +struct script_entry *script_find_entry(struct script_section *section, + const char *name); #endif diff --git a/script_uboot.c b/script_uboot.c new file mode 100644 index 0000000..304c3a2 --- /dev/null +++ b/script_uboot.c @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2012 Alejandro Mery + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "common.h" + +#include +#include +#include + +#include "script.h" +#include "script_uboot.h" + +#define pr_info(...) errf("fexc-uboot: " __VA_ARGS__) +#define pr_err(...) errf("E: fexc-uboot: " __VA_ARGS__) + +#ifdef DEBUG +#define pr_debug(...) errf("D: fexc-uboot: " __VA_ARGS__) +#else +#define pr_debug(...) +#endif + +struct members { + const char *name; + const char *translation; + int mode; +}; +#define foreach_member(I, T) for (const struct members *I = T; \ + I < T+ARRAY_SIZE(T); I++) + +/* + */ +static inline void out_u32_member(FILE *out, const char *key, int hexa, + struct script_single_entry *val) +{ + const char *fmt; + if (hexa) + fmt = "\t.%s = %#x,\n"; + else + fmt = "\t.%s = %u,\n"; + + fprintf(out, fmt, key, val->value); +} + +static inline void out_gpio_member(FILE *out, const char *key, + struct script_gpio_entry *gpio) +{ + fprintf(out, "\t.%s = ", key); + + if (gpio->port == 0xffff) + fprintf(out, "GPIO_AXP_CFG(%u", gpio->port_num); + else + fprintf(out, "GPIO_CFG(%u, %u", gpio->port, gpio->port_num); + + for (const int *p = gpio->data, *pe = p+4; p != pe; p++) { + if (*p == -1) + fputs(", 0xff", out); + else + fprintf(out, ", %u", *p); + } + + fputs("),\n", out); +} + +static inline void out_null_member(FILE *out, const char *key) +{ + fprintf(out, "\t/* %s is NULL */\n", key); +} + +static inline int out_member(FILE *out, const char *key, int mode, + struct script_entry *ep) +{ + switch (ep->type) { + case SCRIPT_VALUE_TYPE_SINGLE_WORD: + out_u32_member(out, key, mode, + container_of(ep, struct script_single_entry, entry)); + break; + case SCRIPT_VALUE_TYPE_NULL: + out_null_member(out, key); + break; + case SCRIPT_VALUE_TYPE_GPIO: + out_gpio_member(out, key, + container_of(ep, struct script_gpio_entry, entry)); + break; + default: + return 0; + } + return 1; +} + +/* + * DRAM + */ +static struct members dram_members[] = { + { .name="dram_clock" }, + { .name="dram_clk", .translation="clock" }, + { .name="dram_type" }, + { .name="dram_rank_num" }, + { .name="dram_density" }, + { .name="dram_chip_density", .translation="density" }, + { .name="dram_io_width" }, + { .name="dram_bus_width" }, + { .name="dram_cas" }, + { .name="dram_zq" }, + { .name="dram_odt_en" }, + { .name="dram_size" }, + { .name="dram_tpr0", .mode=1 }, + { .name="dram_tpr1", .mode=1 }, + { .name="dram_tpr2", .mode=1 }, + { .name="dram_tpr3", .mode=1 }, + { .name="dram_tpr4", .mode=1 }, + { .name="dram_tpr5", .mode=1 }, + { .name="dram_emr1", .mode=1 }, + { .name="dram_emr2", .mode=1 }, + { .name="dram_emr3", .mode=1 }, +}; + +static int generate_dram_struct(FILE *out, struct script_section *sp) +{ + struct script_entry *ep; + const char *key; + int ret = 1; + + fprintf(out, "static struct dram_para dram_para = {\n"); + foreach_member(mp, dram_members) { + ep = script_find_entry(sp, mp->name); + if (!ep) + continue; + + key = (mp->translation) ? mp->translation : mp->name+5; + if (!out_member(out, key, mp->mode, ep)) { + pr_err("dram_para: %s: invalid field\n", ep->name); + ret = 0; + } + + } + fprintf(out, "};\n"); + fputs("\nint sunxi_dram_init(void)\n" + "{\n\treturn DRAMC_init(&dram_para);\n}\n", + out); + + return ret; +} + +/* + * PMU + */ +static struct members pmu_members[] = { + { .name = "pmu_used2" }, + { .name = "pmu_para" }, + { .name = "pmu_adpdet" }, + { .name = "pmu_shutdown_chgcur" }, + { .name = "pmu_shutdown_chgcur2" }, + { .name = "pmu_pwroff_vol" }, + { .name = "pmu_pwron_vol" }, +}; + +static int generate_pmu_struct(FILE *out, struct script_section *target, + struct script_section *pmu_para) +{ + struct list_entry *le; + struct script_section *sp; + struct script_entry *ep; + const char *key; + int ret = 1; + + fputs("\nstatic struct pmu_para pmu_para = {\n", out); + + sp = target; + for (le = list_first(&sp->entries); le; + le = list_next(&sp->entries, le)) { + ep = container_of(le, struct script_entry, entries); + + if (!out_member(out, ep->name, 0, ep)) { + pr_err("target: %s: invalid field\n", ep->name); + ret = 0; + } + } + + foreach_member(mp, pmu_members) { + ep = script_find_entry(pmu_para, mp->name); + if (!ep) + continue; + + key = (mp->translation) ? mp->translation : mp->name+4; + if (!out_member(out, key, mp->mode, ep)) { + pr_err("pmu_para: %s: invalid field\n", mp->name); + ret = 0; + } + } + + fputs("};\n", out); + fputs("\nint sunxi_pmu_init(void)\n" + "{\n\treturn PMU_init(&pmu_para);\n}\n", + out); + return ret; + + (void) pmu_para; +} + +int script_generate_uboot(FILE *out, const char *UNUSED(filename), + struct script *script) +{ + struct { + const char *name; + struct script_section *sp; + } sections[] = { + { "dram_para", NULL }, + { "target", NULL }, + { "pmu_para", NULL }, + }; + + for (unsigned i=0; i\n" + "#include \n" + "#include \n\n", + out); + + generate_dram_struct(out, sections[0].sp); + generate_pmu_struct(out, sections[1].sp, sections[2].sp); + + return 1; +} diff --git a/script_uboot.h b/script_uboot.h new file mode 100644 index 0000000..abfca14 --- /dev/null +++ b/script_uboot.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 Alejandro Mery + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef _SUBXI_TOOLS_SCRIPT_UBOOT_H +#define _SUBXI_TOOLS_SCRIPT_UBOOT_H + +int script_generate_uboot(FILE *out, const char *filename, struct script *script); + +#endif