/* SPDX-License-Identifier: GPL-3.0-or-later */ /* * Copyright (C) 2023, Ferass El Hafidi */ #include #include #include #include #include #include #include "acsbaby.h" #include "parse.h" #include "timing.h" acs_t parse_acs_footer(const int fildes, const uint16_t acs_offset) { acs_t acs_footer; unsigned char buffer[16]; /* Seek to the ACS footer */ if (lseek(fildes, acs_offset, SEEK_SET) == -1) err(errno, "%s", "can't seek to ACS footer"); /* Read an entry */ if (read(fildes, &buffer, 16) == -1) /* Each entry is 16 bytes long */ err(errno, "%s", "can't read ACS footer"); /* Check for the "acs__" magic word */ if (strncmp((char *)buffer, "acs__", 5)) errx(EINVAL, "%s", "invalid file"); /* Parse the "acs__" entry */ acs_footer.chip_type = (uint8_t)buffer[5]; /* * The version is actually 2 bytes long but since it's never going to * exceed 1 byte we just parse 1 byte. */ acs_footer.version = (uint8_t)buffer[6]; acs_footer.size = (uint16_t)((buffer[8] << 2) + buffer[9]); /* Read all other entries */ for (int i = 1; i <= 3; i++) { /* Seek to the next entry */ if (lseek(fildes, acs_offset + i * 0x10, SEEK_SET) == -1) err(errno, "%s", "can't seek to next ACS entry"); if (read(fildes, &buffer, 16) == -1) err(errno, "%s", "can't read ACS entry"); /* * This is where we hit into complex bitwise usage. * That's normal; we're just parsing addresses and sizes as * `uint16_t`s and `uint32_t`s but the acs.bin is little * endian (which means that the bytes are stored in * reverse-byte sequence) so we need to reverse back to have * the right byte sequence. */ if (!strncmp((char *)buffer, "ddrs_", 5)) { acs_footer.ddrs.version = (uint8_t)buffer[5]; acs_footer.ddrs.size = (uint16_t)((buffer[7] << 8) + buffer[6]); acs_footer.ddrs.address = (uint32_t)((((buffer[11] << 8) + buffer[10]) << 16) + ((buffer[9] << 8) + buffer[8])); } else if (!strncmp((char *)buffer, "ddrt_", 5)) { acs_footer.ddrt.version = (uint8_t)buffer[5]; acs_footer.ddrt.size = (uint16_t)((buffer[7] << 8) + buffer[6]); acs_footer.ddrt.address = (uint32_t)((( (buffer[11] << 8) + buffer[10]) << 16) + ((buffer[9] << 8) + buffer[8])); } else if (!strncmp((char *)buffer, "pll__", 5)) { acs_footer.pll.version = (uint8_t)buffer[5]; acs_footer.pll.size = (uint16_t)((buffer[7] << 8) | (buffer[6] & 0xFF)); acs_footer.pll.address = (uint32_t)((((buffer[11] << 8) + buffer[10]) << 16) + ((buffer[9] << 8) + buffer[8])); } else errx(EINVAL, "%s", "no valid ACS entry found"); } return acs_footer; } ddrs_t parse_ddrs(const int fildes, const acs_t acs_footer, const uint16_t diff_offset) { uint16_t offset = acs_footer.ddrs.address - diff_offset; ddrs_t ddr_settings; /* Seek to the ddrs_ structure */ if (lseek(fildes, offset, SEEK_SET) == -1) err(errno, "%s", "can't seek to ddrs_ structure"); /* Read */ read(fildes, &ddr_settings, acs_footer.ddrs.size); return ddr_settings; } void parse_ddrt(const int fildes, const acs_t acs_footer, const uint16_t diff_offset, ddrt_t ddr_timings[7]) { uint16_t offset = acs_footer.ddrt.address - diff_offset; /* Seek to the ddrt_ structure */ if (lseek(fildes, offset, SEEK_SET) == -1) err(errno, "%s", "can't seek to ddrt_ structure"); /* Read */ for (int i = 0; i < 7; i++) { read(fildes, &ddr_timings[i], acs_footer.ddrt.size / 7); } } pll_t parse_pll(const int fildes, const acs_t acs_footer, const uint16_t diff_offset) { uint16_t offset = acs_footer.pll.address - diff_offset; pll_t pll_settings; /* Seek to the ddrt_ structure */ if (lseek(fildes, offset, SEEK_SET) == -1) err(errno, "%s", "can't seek to pll__ structure"); read(fildes, &pll_settings, acs_footer.pll.size); return pll_settings; }