Hello Brian Norris,
I'd like you to do a code review. Please visit
https://review.coreboot.org/22493
to review the following change.
Change subject: file: add new helper functions to grok FDT nodes ......................................................................
file: add new helper functions to grok FDT nodes
This file is intended to help find SPI devices using the FDT. Here's how it works:
Under /proc/device-tree there is a node called "aliases" where each file is a device name with an instance (e.g. "spi0"). The content of the file is the controller's memory-mapped address.
That info can be used to find the appropriate node directory to search under /proc/device-tree, where we can recursively search for "compatible" nodes and scan for the matching user-provided compatible string.
For SPI devices, we need to look for the matching "compatible" node and then read the corresponding "reg" node to obtain chip- select number.
BUG=chrome-os-partner:43453 BRANCH=none TEST=reads now work on danger without specifying a SPI device Signed-off-by: David Hendricks dhendrix@chromium.org
Change-Id: I1f771bcca61de71daa54e358e058723d3fd37079 Reviewed-on: https://chromium-review.googlesource.com/310072 Commit-Ready: David Hendricks dhendrix@chromium.org Tested-by: David Hendricks dhendrix@chromium.org Reviewed-by: Brian Norris briannorris@chromium.org --- M file.c M file.h 2 files changed, 160 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/93/22493/1
diff --git a/file.c b/file.c index 24ded2a..3b9abdf 100644 --- a/file.c +++ b/file.c @@ -1,5 +1,5 @@ /* - * Copyright 2012, The Chromium OS Authors + * Copyright 2015, The Chromium OS Authors * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,16 +34,21 @@
#include <dirent.h> #include <errno.h> +#include <glob.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <arpa/inet.h> #include <sys/fcntl.h> #include <sys/stat.h> #include <sys/types.h>
#include "flash.h" + +#define FDT_ROOT "/proc/device-tree" +#define FDT_ALIASES "/proc/device-tree/aliases"
/* returns 1 if string if found, 0 if not, and <0 to indicate error */ static int find_string(const char *path, const char *str) @@ -171,3 +176,155 @@ closedir(dp); return ret; } + +/* + * do_fdt_find_spi_nor_flash - Search FDT via procfs for SPI NOR flash + * + * @prefix: Prefix of alias, for example "spi" will match spi*. + * @compat: String to look for in "compatible" node + * + * This function attempt to match FDT aliases with devices that have the given + * compatible string. + * + * Example: If prefix is "spi" and compat is "jedec,spi-nor" then this function + * will read the device descriptors in every alias beginning with "spi" and + * search their respective devicetree nodes for "compatible" files containing + * the string "jedec,spi-nor". + * + * returns 0 to indicate NOR flash has been found, <0 to indicate error + */ +static int do_fdt_find_spi_nor_flash(const char *prefix, + const char *compat, unsigned int *bus, uint32_t *cs) +{ + DIR *dp; + struct dirent *d; + struct stat s; + int found = 0; + + if ((dp = opendir(FDT_ALIASES)) == NULL) + return -1; + + /* + * This loop will go thru the aliases sub-directory and kick-off a + * recursive search thru matching devicetree nodes. + */ + while (!found && (d = readdir(dp))) { + char node[PATH_MAX]; + char pattern[PATH_MAX]; + char alias[64]; + int i, fd, len; + glob_t pglob; + + /* allow partial match */ + if (strncmp(prefix, d->d_name, strlen(prefix))) + continue; + + sprintf(node, "%s/%s", FDT_ALIASES, d->d_name); + if (stat(node, &s) < 0) { + msg_pdbg("%s: Error stat'ing %s: %s\n", + __func__, node, strerror(errno)); + continue; + } + + if (!S_ISREG(s.st_mode)) + continue; + + fd = open(node, O_RDONLY); + if (fd < 0) { + msg_perr("Could not open %s\n", d->d_name); + continue; + } + + /* devicetree strings and files aren't always terminated */ + len = read(fd, alias, sizeof(alias) - 1); + if (len < 0) { + msg_perr("Could not read %s\n", d->d_name); + close(fd); + continue; + } + alias[len] = '\0'; + close(fd); + + /* We expect something in the form "/<type>@<address>", for + example "/spi@ff110000" */ + if (alias[0] != '/') + continue; + + snprintf(node, sizeof(node), "%s%s", FDT_ROOT, alias); + + /* + * Descend into this node's directory. According to the DT + * specification, the SPI device node will be a subnode of + * the bus node. Thus, we need to look for: + * <path-to-spi-bus-node>/.../compatible + */ + sprintf(pattern, "%s/*/compatible", node); + msg_pspew("Scanning glob pattern "%s"\n", pattern); + i = glob(pattern, 0, NULL, &pglob); + if (i == GLOB_NOSPACE) + goto err_out; + else if (i != 0) + continue; + + /* + * For chip-select, look at the "reg" file located in + * the same sub-directory as the "compatible" file. + */ + for (i = 0; i < pglob.gl_pathc; i++) { + char *reg_path; + + if (!find_string(pglob.gl_pathv[i], compat)) + continue; + + reg_path = strdup(pglob.gl_pathv[i]); + if (!reg_path) { + globfree(&pglob); + goto err_out; + } + + sprintf(strstr(reg_path, "compatible"), "reg"); + fd = open(reg_path, O_RDONLY); + if (fd < 0) { + msg_gerr("Cannot open "%s"\n", reg_path); + free(reg_path); + continue; + } + + /* value is a 32-bit big-endian unsigned in FDT. */ + if (read(fd, cs, 4) != 4) { + msg_gerr("Cannot read "%s"\n", reg_path); + free(reg_path); + close(fd); + continue; + } + + *cs = ntohl(*cs); + found = 1; + free(reg_path); + close(fd); + } + + if (found) { + /* Extract bus from the alias filename. */ + if (sscanf(d->d_name, "spi%u", bus) != 1) { + msg_gerr("Unexpected format: "d->d_name"\n"); + found = 0; + globfree(&pglob); + goto err_out; + } + } + + globfree(&pglob); + } + +err_out: + closedir(dp); + return found ? 0 : -1; +} + +/* Wrapper in case we want to use a list of compat strings or extend + * this to search for other types of devices */ +int fdt_find_spi_nor_flash(unsigned int *bus, unsigned int *cs) +{ + return do_fdt_find_spi_nor_flash("spi", "jedec,spi-nor", bus, cs); +} diff --git a/file.h b/file.h index ea37084..9af84bf 100644 --- a/file.h +++ b/file.h @@ -1,5 +1,5 @@ /* - * Copyright 2012, The Chromium OS Authors + * Copyright 2015, The Chromium OS Authors * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,3 +31,4 @@
const char *scanft(const char *root, const char *filename, const char *str, int symdepth); +int fdt_find_spi_nor_flash(unsigned int *bus, unsigned int *cs);