/* SPDX-License-Identifier: GPL-3.0-or-later */ /* * Copyright (C) 2023, Ferass El Hafidi */ #include #include #include #include #include #include #include #include "acsbaby.h" #include "parse.h" #include "timing.h" #include "util.h" int print_usage(char *); int main(int argc, char *argv[]) { int argument, fildes; uint16_t acs_offset, diff_offset; char buffer[4096], *format = "readable", *type = "unspecified", *argv0 = strdup(argv[0]); while ((argument = getopt(argc, argv, "f:t:o:")) != -1) { if (argument == '?') return print_usage(argv0); else if (argument == 'f' && optarg != NULL) format = strdup(optarg); else if (argument == 't' && optarg != NULL) { if (strcmp("u-boot", optarg) && strcmp("acs", optarg) && strcmp("bl2", optarg)) return print_usage(argv0); type = strdup(optarg); } else if (argument == 'o' && optarg != NULL) { /* Check if it's a hexadecimal (prefixed by '0x') */ if (strncmp("0x", optarg, 2)) return print_usage(argv0); acs_offset = (uint16_t)strtol(optarg, NULL, 16); } } argc -= optind; argv += optind; if (argc < 1) return print_usage(argv0); /* Open the file */ fildes = open(argv[0], O_RDONLY); if (fildes == -1) err(errno, "can't open file"); if (!strcmp(type, "unspecified")) { /* * Try figuring out the binary we have if it isn't * explicitely set. */ if (read(fildes, &buffer, 32) == -1) err(errno, "%s", "can't read"); /* Check for the "@AML" magic word (in a signed u-boot.bin) */ if (buffer[16] == '@' && buffer[17] == 'A' && buffer[18] == 'M' && buffer[19] == 'L') type = "u-boot"; /* Check for the "Built :" string (in acs.bin) */ else if (buffer[16] == 'B' && buffer[17] == 'u' && buffer[18] == 'i' && buffer[19] == 'l' && buffer[20] == 't' && buffer[21] == ' ' && buffer[22] == ':') type = "acs"; /* Assume it's a BL2 binary */ else type = "bl2"; } /* Find the offset where we have the ACS footer */ if (!strcmp(type, "u-boot")) { if (!acs_offset) { warnx("type is \"u-boot\" but no offset is specified, " "using 0xa4e0"); /* * Nit: this offset (found in a p201 u-boot.bin) is * different from the offset in my KII Pro eMMC backup. * TODO: Maybe automatically detect the offset? */ acs_offset = 0xa4e0; } } else if (!strcmp(type, "bl2") && !acs_offset) acs_offset = 0x92e0; else if (!strcmp(type, "acs") && !acs_offset) acs_offset = 0x330; /* Parse the footer */ acs_t acs_footer = parse_acs_footer(fildes, acs_offset); if (!strcmp("acs", type)) diff_offset = 0; else errx(EINVAL, "types other than \"acs\" aren't supported yet"); /* Check versions */ if (acs_footer.version != 1 || acs_footer.ddrs.version != 3 || acs_footer.ddrt.version != 2 || acs_footer.pll.version != 1) errx(0, "one or multiple entries have an unsupported version;" "not parsing structures" ); /* Parse "ddrs_" */ ddrs_t ddr_settings = parse_ddrs(fildes, acs_footer, diff_offset); /* Parse "ddrt_" */ ddrt_t ddr_timings[7]; /* "ddrt_" is an array. */ parse_ddrt(fildes, acs_footer, diff_offset, ddr_timings); /* Parse "pll__" */ pll_t pll_settings = parse_pll(fildes, acs_footer, diff_offset); /* Print */ if (!strcmp(format, "readable")) { printf( "This is a %s.bin binary.\n", type ); printf( "\"acs__\":\n" "\tVersion: 0x%x\n" "\tSize: 0x%x\n" "\tChip type: 0x%x\n", acs_footer.version, acs_footer.size, acs_footer.chip_type ); printf( "\"ddrs_\":\n" "\tVersion: 0x%x\n" "\tSize: 0x%x\n" "\tAddress in memory: 0x%x\n", acs_footer.ddrs.version, acs_footer.ddrs.size, acs_footer.ddrs.address ); printf( "\"ddrt_\":\n" "\tVersion: 0x%x\n" "\tSize: 0x%x\n" "\tAddress in memory: 0x%x\n", acs_footer.ddrt.version, acs_footer.ddrt.size, acs_footer.ddrt.address ); printf( "\"pll__\":\n" "\tVersion: 0x%x\n" "\tSize: 0x%x\n" "\tAddress in memory: 0x%x\n", acs_footer.pll.version, acs_footer.pll.size, acs_footer.pll.address ); } else if (!strcmp(format, "c")) { printf( "/**************************************" "****************************************\n" " * arch/arm/cpu/armv8/gxb/firmware/acs/acs.c\n" " * Generated by ACSBaby. PLEASE DO NOT MODIFY\n" " * Date: %s\n" /* Date */ " **************************************" "***************************************/\n" "#include \n" "#include \n" "#include \"timing.c\"\n\n" "struct acs_setting __acs_set = {\n" "\t.acs_magic = \"acs__\",\n" "\t.chip_type = 0x%x,\n" "\t.version = %d,\n" "\t.acs_set_length = 0x%x,\n\n" /* "ddrs_" entry */ "\t.ddr_magic = \"ddrs_\",\n" "\t.ddr_set_version = %d,\n" "\t.ddr_set_length = 0x%x,\n" "\t.ddr_set_addr = (unsigned long)" "(&__ddr_setting),\n\n" /* "ddrt_" entry */ "\t.ddrt_magic = \"ddrt_\",\n" "\t.ddrt_set_version = %d,\n" "\t.ddrt_set_length = 0x%x,\n" "\t.ddrt_set_addr = (unsigned long)" "(&__ddr_timming),\n\n" /* "pll__" entry */ "\t.pll_magic = \"pll__\",\n" "\t.pll_set_version = %d,\n" "\t.pll_set_length = 0x%x,\n" "\t.pll_set_addr = (unsigned long)" "(&__pll_setting),\n};\n", get_date(), acs_footer.chip_type, acs_footer.version, acs_footer.size, acs_footer.ddrs.version, acs_footer.ddrs.size, acs_footer.ddrt.version, acs_footer.ddrt.size, acs_footer.pll.version, acs_footer.pll.size ); printf( "/**************************************" "****************************************\n" " * board/amlogic//firmware/timing.c\n" " * Generated by ACSBaby. PLEASE DO NOT MODIFY\n" " * Date: %s\n" /* Date */ " **************************************" "***************************************/\n" "#include \n" "#include \n", get_date() ); } else return print_usage(argv0); print_ddr_settings(ddr_settings, format); print_ddr_timings(ddr_timings, format); print_pll_settings(pll_settings, format); return 0; } int print_usage(char *name) { printf( "ACSBaby: Parse Amlogic DDR settings.\n" "Usage: %s [-f c|readable] [-t acs|bl2|u-boot] " "[-o offset] file\n", name ); return 1; }