Message ID | 20231219-b4-qcom-common-target-v2-17-b6dd9704219e@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | Qualcomm generic board support | expand |
On 19/12/2023 17:04, Caleb Connolly wrote: > With just a few basic rules, we can generate the $fdtfile environment > variable to match the format used in Linux. This uses the root > compatible property inside u-boot, with specific handling for the > Dragonboard845c which is a special case, and for the qrb robotics > boards. > > This is known to work on supported platforms, and lets us avoid having a > big lookup table. > > Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org> > --- > arch/arm/mach-snapdragon/board.c | 101 +++++++++++++++++++++++++++++++++++++++ > 1 file changed, 101 insertions(+) > > diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c > index b00f536d38b4..752166ea7563 100644 > --- a/arch/arm/mach-snapdragon/board.c > +++ b/arch/arm/mach-snapdragon/board.c > @@ -113,6 +113,106 @@ int board_init(void) > return 0; > } > > +/* Sets up the "board", and "soc" environment variables as well as constructing the devicetree > + * path, with a few quirks to handle non-standard dtb filenames. This is not meant to be a > + * comprehensive solution to automatically picking the DTB, but aims to be correct for the > + * majority case. For most devices it should be possible to make this algorithm work by > + * adjusting the root compatible property in the U-Boot DTS. Handling devices with multiple > + * variants that are all supported by a single U-Boot image will require implementing device- > + * specific detection. > + */ > +static void configure_env(void) > +{ > + const char *first_compat, *last_compat; > + char *tmp; > + char buf[32] = { 0 }; > + /* > + * Most DTB filenames follow the scheme: qcom/<soc>-[vendor]-<board>.dtb > + * The vendor is skipped when it's a Qualcomm reference board, or the > + * db845c. > + */ > + char dt_path[64] = { 0 }; > + int compat_count, ret; > + ofnode root; > + > + root = ofnode_root(); > + /* This is almost always 2, but be explicit that we want the first and last compatibles > + * not the first and second. > + */ > + compat_count = ofnode_read_string_count(root, "compatible"); > + if (compat_count < 2) { > + log_warning("%s: only one root compatible bailing!\n", __func__); > + return; > + } > + > + /* The most specific device compatible (e.g. "thundercomm,db845c") */ > + ret = ofnode_read_string_index(root, "compatible", 0, &first_compat); > + if (ret < 0) { > + log_warning("Can't read first compatible\n"); > + return; > + } > + > + /* The last compatible is always the SoC compatible */ > + ret = ofnode_read_string_index(root, "compatible", compat_count - 1, &last_compat); > + if (ret < 0) { > + log_warning("Can't read second compatible\n"); > + return; > + } > + > + /* Copy the second compat (e.g. "qcom,sdm845") into buf */ > + strlcpy(buf, last_compat, sizeof(buf) - 1); > + tmp = buf; > + > + /* strsep() is destructive, it replaces the comma with a \0 */ > + if (!strsep(&tmp, ",")) { > + log_warning("second compatible '%s' has no ','\n", buf); > + return; > + } > + > + /* tmp now points to just the "sdm845" part of the string */ > + env_set("soc", tmp); > + > + /* Now figure out the "board" part from the first compatible */ > + memset(buf, 0, sizeof(buf)); > + strlcpy(buf, first_compat, sizeof(buf) - 1); > + tmp = buf; > + > + /* The Qualcomm reference boards (RBx, HDK, etc) */ > + if (!strncmp("qcom", buf, strlen("qcom"))) { > + /* > + * They all have the first compatible as "qcom,<soc>-<board>" > + * (e.g. "qcom,qrb5165-rb5"). We extract just the part after > + * the dash. > + */ > + if (!strsep(&tmp, "-")) { > + log_warning("compatible '%s' has no '-'\n", buf); > + return; > + } > + /* tmp is now "rb5" */ > + env_set("board", tmp); > + } else { > + if (!strsep(&tmp, ",")) { > + log_warning("compatible '%s' has no ','\n", buf); > + return; > + } > + /* for thundercomm we just want the bit after the comma (e.g. "db845c"), > + * for all other boards we replace the comma with a '-' and take both > + * (e.g. "oneplus-enchilada") > + */ > + if (!strncmp("thundercomm", buf, strlen("thundercomm"))) { > + env_set("board", tmp); > + } else { > + *(tmp - 1) = '-'; > + env_set("board", buf); > + } > + } > + > + /* Now build the full path name */ > + snprintf(dt_path, sizeof(dt_path), "qcom/%s-%s.dtb", > + env_get("soc"), env_get("board")); > + env_set("fdtfile", dt_path); > +} > + > void __weak qcom_late_init(void) > { > } > @@ -142,6 +242,7 @@ int board_late_init(void) > if (status) > log_warning("%s: Failed to set run time variables\n", __func__); > > + configure_env(); > qcom_late_init(); > > return 0; > Nice, hope it will still fit for all future boards! Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index b00f536d38b4..752166ea7563 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -113,6 +113,106 @@ int board_init(void) return 0; } +/* Sets up the "board", and "soc" environment variables as well as constructing the devicetree + * path, with a few quirks to handle non-standard dtb filenames. This is not meant to be a + * comprehensive solution to automatically picking the DTB, but aims to be correct for the + * majority case. For most devices it should be possible to make this algorithm work by + * adjusting the root compatible property in the U-Boot DTS. Handling devices with multiple + * variants that are all supported by a single U-Boot image will require implementing device- + * specific detection. + */ +static void configure_env(void) +{ + const char *first_compat, *last_compat; + char *tmp; + char buf[32] = { 0 }; + /* + * Most DTB filenames follow the scheme: qcom/<soc>-[vendor]-<board>.dtb + * The vendor is skipped when it's a Qualcomm reference board, or the + * db845c. + */ + char dt_path[64] = { 0 }; + int compat_count, ret; + ofnode root; + + root = ofnode_root(); + /* This is almost always 2, but be explicit that we want the first and last compatibles + * not the first and second. + */ + compat_count = ofnode_read_string_count(root, "compatible"); + if (compat_count < 2) { + log_warning("%s: only one root compatible bailing!\n", __func__); + return; + } + + /* The most specific device compatible (e.g. "thundercomm,db845c") */ + ret = ofnode_read_string_index(root, "compatible", 0, &first_compat); + if (ret < 0) { + log_warning("Can't read first compatible\n"); + return; + } + + /* The last compatible is always the SoC compatible */ + ret = ofnode_read_string_index(root, "compatible", compat_count - 1, &last_compat); + if (ret < 0) { + log_warning("Can't read second compatible\n"); + return; + } + + /* Copy the second compat (e.g. "qcom,sdm845") into buf */ + strlcpy(buf, last_compat, sizeof(buf) - 1); + tmp = buf; + + /* strsep() is destructive, it replaces the comma with a \0 */ + if (!strsep(&tmp, ",")) { + log_warning("second compatible '%s' has no ','\n", buf); + return; + } + + /* tmp now points to just the "sdm845" part of the string */ + env_set("soc", tmp); + + /* Now figure out the "board" part from the first compatible */ + memset(buf, 0, sizeof(buf)); + strlcpy(buf, first_compat, sizeof(buf) - 1); + tmp = buf; + + /* The Qualcomm reference boards (RBx, HDK, etc) */ + if (!strncmp("qcom", buf, strlen("qcom"))) { + /* + * They all have the first compatible as "qcom,<soc>-<board>" + * (e.g. "qcom,qrb5165-rb5"). We extract just the part after + * the dash. + */ + if (!strsep(&tmp, "-")) { + log_warning("compatible '%s' has no '-'\n", buf); + return; + } + /* tmp is now "rb5" */ + env_set("board", tmp); + } else { + if (!strsep(&tmp, ",")) { + log_warning("compatible '%s' has no ','\n", buf); + return; + } + /* for thundercomm we just want the bit after the comma (e.g. "db845c"), + * for all other boards we replace the comma with a '-' and take both + * (e.g. "oneplus-enchilada") + */ + if (!strncmp("thundercomm", buf, strlen("thundercomm"))) { + env_set("board", tmp); + } else { + *(tmp - 1) = '-'; + env_set("board", buf); + } + } + + /* Now build the full path name */ + snprintf(dt_path, sizeof(dt_path), "qcom/%s-%s.dtb", + env_get("soc"), env_get("board")); + env_set("fdtfile", dt_path); +} + void __weak qcom_late_init(void) { } @@ -142,6 +242,7 @@ int board_late_init(void) if (status) log_warning("%s: Failed to set run time variables\n", __func__); + configure_env(); qcom_late_init(); return 0;
With just a few basic rules, we can generate the $fdtfile environment variable to match the format used in Linux. This uses the root compatible property inside u-boot, with specific handling for the Dragonboard845c which is a special case, and for the qrb robotics boards. This is known to work on supported platforms, and lets us avoid having a big lookup table. Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org> --- arch/arm/mach-snapdragon/board.c | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+)