| /* Copyright 2014 Google LLC |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of Google LLC nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * fdt.c: Helper functions for getting data out of the device tree. |
| */ |
| |
| #include <arpa/inet.h> |
| #include <errno.h> |
| #include <inttypes.h> |
| #include <string.h> |
| |
| #include "lib/fdt.h" |
| #include "lib/file.h" |
| #include "lib/math.h" |
| #include "lib/string_builder.h" |
| |
| #include "mosys/alloc.h" |
| #include "mosys/globals.h" |
| #include "mosys/log.h" |
| #include "mosys/platform.h" |
| |
| #define FDT_ROOT "/proc/device-tree/" |
| /* FIXME: assume coreboot for now */ |
| #define FDT_RAM_CODE_PATH "firmware/coreboot/ram-code" |
| #define FDT_BOARD_ID_PATH "firmware/coreboot/board-id" |
| #define FDT_SKU_ID_PATH "firmware/coreboot/sku-id" |
| |
| #define LPDDR3_MFG_ID_PATH "lpddr3/manufacturer_id" |
| #define LPDDR3_REV_ID_PATH "lpddr3/revision_id" |
| |
| |
| /* returns number of bytes read or -1 to indicate error */ |
| static ssize_t fdt_read_node(const char *path, char *buf, size_t buf_sz) |
| { |
| ssize_t ret; |
| struct string_builder *sb; |
| |
| sb = new_string_builder(); |
| string_builder_strcat(sb, FDT_ROOT); |
| string_builder_strcat(sb, path); |
| |
| ret = read_file(string_builder_get_string(sb), buf, buf_sz, LOG_ERR); |
| |
| free_string_builder(sb); |
| return ret; |
| } |
| |
| static int fdt_get_uint32_val(const char *path, uint32_t *val) |
| { |
| /* Leave room for a null-terminator in the buffer */ |
| char buf[sizeof(*val) + 1]; |
| |
| if (fdt_read_node(path, buf, ARRAY_SIZE(buf)) < 0) |
| return -1; |
| |
| *val = ntohl(*(uint32_t *)buf); |
| return 0; |
| } |
| |
| int fdt_get_ram_code(uint32_t *ram_code) |
| { |
| if (fdt_get_uint32_val(FDT_RAM_CODE_PATH, ram_code) < 0) { |
| lprintf(LOG_ERR, "%s: Error when reading RAM code\n", __func__); |
| return -1; |
| } |
| |
| if (*ram_code == 0xffffffff) { |
| lprintf(LOG_ERR, "%s: ram_code is invalid.\n", __func__); |
| return -1; |
| } |
| |
| lprintf(LOG_DEBUG, "%s: ram_code: %u\n", __func__, *ram_code); |
| return 0; |
| } |
| |
| /* |
| * get_ram_manufacturer_id - Get RAM manufacturer id from device tree |
| * |
| * returns 0 to indicate success, <0 to indicate failure. |
| */ |
| |
| int fdt_get_ram_manufacturer_id(uint8_t *manufacturer_id) |
| { |
| uint32_t buf[2]; |
| |
| if (fdt_read_node(LPDDR3_MFG_ID_PATH, (char *)buf, sizeof(buf)) < sizeof(uint32_t)) { |
| lprintf(LOG_ERR, |
| "%s: Error when reading Manufacturer ID\n", |
| __func__); |
| return -1; |
| } |
| |
| *manufacturer_id = ntohl(buf[0]); |
| |
| lprintf(LOG_DEBUG, |
| "%s: manufacturer_id: %#02x\n", |
| __func__, |
| *manufacturer_id); |
| return 0; |
| } |
| |
| /* |
| * get_ram_revision_id - Get RAM revision id from device tree |
| * |
| * returns 0 to indicate success, <0 to indicate failure. |
| */ |
| |
| int fdt_get_ram_revision_id(uint8_t *revision_id1, uint8_t *revision_id2) |
| { |
| uint32_t buf[3]; |
| |
| if (fdt_read_node(LPDDR3_REV_ID_PATH, (char *)buf, sizeof(buf)) < sizeof(uint32_t) * 2) { |
| lprintf(LOG_ERR, |
| "%s: Error when reading Revision ID\n", |
| __func__); |
| return -1; |
| } |
| |
| *revision_id1 = ntohl(buf[0]); |
| *revision_id2 = ntohl(buf[1]); |
| |
| lprintf(LOG_DEBUG, |
| "%s: revision_id: %#02x %#02x\n", |
| __func__, |
| *revision_id1, |
| *revision_id2); |
| return 0; |
| } |
| |
| int fdt_get_board_id(uint32_t *board_id) |
| { |
| if (fdt_get_uint32_val(FDT_BOARD_ID_PATH, board_id) < 0) { |
| lprintf(LOG_ERR, "%s: Error when reading board ID\n", __func__); |
| return -1; |
| } |
| |
| if (*board_id == 0xffffffff) { |
| lprintf(LOG_ERR, "%s: board_id is invalid.\n", __func__); |
| return -1; |
| } |
| |
| lprintf(LOG_DEBUG, "%s: board_id: %u\n", __func__, *board_id); |
| return 0; |
| } |
| |
| /* Common sysinfo callbacks for almost all ARM devices. */ |
| static char *fdt_sysinfo_get_version(struct platform_intf *intf) |
| { |
| uint32_t board_id; |
| char board_id_str[16]; |
| |
| if (fdt_get_board_id(&board_id) < 0) |
| return NULL; |
| |
| snprintf(board_id_str, sizeof(board_id_str), "rev%u", board_id); |
| return mosys_strdup(board_id_str); |
| } |
| |
| struct sys_cb fdt_sysinfo_cb = { |
| .version = fdt_sysinfo_get_version, |
| }; |