@@ -339,6 +339,7 @@ config SECURED_MODE_CSK_INDEX
default 0
depends on SECURED_MODE_IMAGE
+source "board/Marvell/common/Kconfig"
source "board/solidrun/clearfog/Kconfig"
source "board/kobol/helios4/Kconfig"
new file mode 100644
@@ -0,0 +1,20 @@
+menu "Marvell Armada common configuration"
+depends on TARGET_MVEBU_ARMADA_37XX || TARGET_MVEBU_ARMADA_8K
+
+config MVEBU_MAC_HW_INFO
+ bool "Marvell hw_info (mac) support"
+ depends on SPI_FLASH && ENV_IS_IN_SPI_FLASH && ARCH_MVEBU
+ default n
+ help
+ Enable loading of the Marvell hw_info parameters from the
+ SPI flash hw_info area. Parameters (usually the board serial
+ number and MAC addresses) are then imported into the
+ existing U-Boot environment.
+ Implementation of this command is compatible with the
+ original Marvell U-Boot command. Reading and writing is
+ supported.
+ EEPROM config pattern and checksum aren't supported.
+ After enabled, these parameters are managed from the common
+ U-Boot mac command.
+
+endmenu
new file mode 100644
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2021 Sartura Ltd.
+
+obj-$(CONFIG_ID_EEPROM) += mac.o
new file mode 100644
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Marvell hw_info (mac) command implementation
+ * Helper command for interfacing with the Marvell hw_info parameters
+ *
+ * Copyright (c) 2021 Sartura Ltd.
+ * Copyright (c) 2018 Marvell International Ltd.
+ *
+ * Author: Luka Kovacic <luka.kovacic@sartura.hr>
+ */
+
+#include <command.h>
+#include <common.h>
+#include <env.h>
+#include <env_internal.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#define HW_INFO_MAX_ENV_SIZE 0x1F0
+#define HW_INFO_ENV_OFFSET 0xA
+#define HW_INFO_ENV_SEP 0x20
+
+#define HW_INFO_MAX_NAME_LEN 32
+
+#define HW_INFO_MERGED_VARIABLE "read_board_hw_info"
+
+static char hw_info_allowed_parameters[][HW_INFO_MAX_NAME_LEN] = {
+ "pcb_slm",
+ "pcb_rev",
+ "eco_rev",
+ "pcb_sn",
+ "ethaddr",
+ "eth1addr",
+ "eth2addr",
+ "eth3addr",
+ "eth4addr",
+ "eth5addr",
+ "eth6addr",
+ "eth7addr",
+ "eth8addr",
+ "eth9addr",
+};
+
+static int hw_info_allowed_param_count = (sizeof(hw_info_allowed_parameters) /
+ sizeof(hw_info_allowed_parameters[0]));
+
+static int hw_info_check_parameter(char *name)
+{
+ int idx;
+
+ for (idx = 0; idx < hw_info_allowed_param_count; idx++) {
+ if (strcmp(name, hw_info_allowed_parameters[idx]) == 0)
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * read_spi_flash_offset() - Read data from the SPI flash
+ * @buf: Buffer to write in
+ * @offset: Offset from the flash start
+ *
+ * Read SPI flash data into the buffer from offset to HW_INFO_MAX_ENV_SIZE.
+ */
+static int read_spi_flash_offset(char *buf, int offset)
+{
+ struct spi_flash *flash;
+ int ret;
+
+ flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
+
+ if (!flash) {
+ printf("Error - unable to probe SPI flash.\n");
+ return -EIO;
+ }
+
+ ret = spi_flash_read(flash, offset, HW_INFO_MAX_ENV_SIZE, buf);
+ if (ret) {
+ printf("Error - unable to read hw_info environment from SPI flash.\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * write_spi_flash_offset() - Write a buffer to SPI flash
+ * @buf: Buffer to write to SPI flash
+ * @offset: Offset from the flash start
+ * @size: Size of the buffer content
+ *
+ * This function probes the SPI flash and updates the specified flash location
+ * with new data from the buffer.
+ */
+static int write_spi_flash_offset(char *buf, fdt_addr_t flash_offset, int env_offset, ssize_t size)
+{
+ ssize_t safe_size, erase_size;
+ struct spi_flash *flash;
+ int ret;
+
+ flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
+
+ if (!flash) {
+ printf("Error - unable to probe SPI flash.\n");
+ return -EIO;
+ }
+
+ safe_size = size > HW_INFO_MAX_ENV_SIZE ? HW_INFO_MAX_ENV_SIZE : size;
+ erase_size = safe_size +
+ (flash->erase_size - safe_size % flash->erase_size);
+ ret = spi_flash_erase(flash, flash_offset, erase_size);
+ if (ret) {
+ printf("Error - unable to erase the hw_info area on SPI flash.\n");
+ return ret;
+ }
+ ret = spi_flash_write(flash, flash_offset + env_offset, safe_size, buf);
+ if (ret) {
+ printf("Error - unable to write hw_info parameters to SPI flash.\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * cmd_hw_info_dump() - Dump the hw_info parameters
+ *
+ * This function prints all Marvell hw_info parameters, which are stored in
+ * the SPI flash.
+ */
+static int cmd_hw_info_dump(fdt_addr_t flash_offset)
+{
+ char buffer[HW_INFO_MAX_ENV_SIZE];
+ struct hsearch_data htab;
+ char *res = NULL;
+ ssize_t len;
+ int ret = 0;
+
+ ret = read_spi_flash_offset(buffer, flash_offset +
+ HW_INFO_ENV_OFFSET);
+ if (ret)
+ goto err;
+ memset(&htab, 0, sizeof(htab));
+ if (!hcreate_r(HW_INFO_MAX_ENV_SIZE, &htab)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (!himport_r(&htab, buffer, HW_INFO_MAX_ENV_SIZE,
+ HW_INFO_ENV_SEP, H_NOCLEAR, 0, 0, NULL)) {
+ ret = -EFAULT;
+ goto err_htab;
+ }
+
+ len = hexport_r(&htab, '\n', H_HIDE_DOT, &res, 0, 0, NULL);
+ if (len > 0) {
+ printf("Parameters (hw_info):\n");
+ puts(res);
+ free(res);
+ ret = 0;
+ goto ret_htab;
+ }
+ret_htab:
+ hdestroy_r(&htab);
+ return ret;
+err_htab:
+ hdestroy_r(&htab);
+err:
+ printf("## Error: cannot store hw_info parameters to SPI flash\n");
+ return ret;
+}
+
+/**
+ * cmd_hw_info_read() - Import the hw_info parameters into U-Boot env
+ * @print_env: Print U-Boot environment after new parameters are imported
+ *
+ * This function reads the Marvell hw_info parameters from SPI flash and
+ * imports them into the U-Boot env.
+ */
+static int cmd_hw_info_read(fdt_addr_t flash_offset, bool print_env)
+{
+ char buffer[HW_INFO_MAX_ENV_SIZE];
+ char *res = NULL;
+ ssize_t len;
+ int ret = 0;
+
+ ret = read_spi_flash_offset(buffer, flash_offset +
+ HW_INFO_ENV_OFFSET);
+ if (ret)
+ goto err;
+ if (!himport_r(&env_htab, buffer, HW_INFO_MAX_ENV_SIZE,
+ HW_INFO_ENV_SEP, H_NOCLEAR, 0, 0, NULL)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ printf("Successfully imported the Marvell hw_info parameters.\n");
+ if (!print_env)
+ return 0;
+
+ len = hexport_r(&env_htab, '\n', H_HIDE_DOT, &res, 0, 0, NULL);
+ if (len > 0) {
+ printf("Updated environment:\n");
+ puts(res);
+ free(res);
+ return 0;
+ }
+err:
+ printf("## Error: cannot import hw_info parameters\n");
+ return ret;
+}
+
+/**
+ * cmd_hw_info_save() - Save a parameter from U-Boot env to hw_info parameters
+ * @name: Name of the U-Boot env parameter to save
+ *
+ * This function finds the specified parameter by name in the U-Boot env
+ * and then updates the Marvell hw_info parameters with the new value.
+ */
+static int cmd_hw_info_save(fdt_addr_t flash_offset, char *name)
+{
+ char buffer[HW_INFO_MAX_ENV_SIZE];
+ struct env_entry e, *ep, *rv;
+ struct hsearch_data htab;
+ char *res = NULL;
+ ssize_t len;
+ int ret = 0;
+
+ ret = hw_info_check_parameter(name);
+ if (ret) {
+ printf("Invalid parameter %s, stopping.\n", name);
+ goto err;
+ }
+
+ ret = read_spi_flash_offset(buffer, flash_offset +
+ HW_INFO_ENV_OFFSET);
+ if (ret)
+ goto err;
+ memset(&htab, 0, sizeof(htab));
+ if (!hcreate_r(HW_INFO_MAX_ENV_SIZE, &htab)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (!himport_r(&htab, buffer, HW_INFO_MAX_ENV_SIZE,
+ HW_INFO_ENV_SEP, H_NOCLEAR, 0, 0, NULL)) {
+ ret = -EFAULT;
+ goto err_htab;
+ }
+
+ e.key = name;
+ e.data = NULL;
+ if (!hsearch_r(e, ENV_FIND, &ep, &env_htab, H_HIDE_DOT)) {
+ ret = -ENOENT;
+ goto err_htab;
+ }
+ if (!ep) {
+ ret = -ENOENT;
+ goto err_htab;
+ }
+
+ printf("Storing %s=%s to hw_info...\n", ep->key, ep->data);
+
+ e.key = ep->key;
+ e.data = ep->data;
+ if (!hsearch_r(e, ENV_ENTER, &rv, &htab, H_HIDE_DOT)) {
+ ret = -EINVAL;
+ goto err_htab;
+ }
+ if (!rv) {
+ ret = -EINVAL;
+ goto err_htab;
+ }
+ len = hexport_r(&htab, HW_INFO_ENV_SEP, H_MATCH_KEY | H_MATCH_IDENT,
+ &res, 0, 0, NULL);
+ if (len <= 0) {
+ free(res);
+ goto ret_htab;
+ }
+ ret = write_spi_flash_offset(res, flash_offset,
+ HW_INFO_ENV_OFFSET, len);
+ free(res);
+ if (ret)
+ goto err_htab;
+
+ printf("Successfully stored the Marvell hw_info parameters.\n");
+ return 0;
+ret_htab:
+ hdestroy_r(&htab);
+ return ret;
+err_htab:
+ hdestroy_r(&htab);
+err:
+ printf("## Error: cannot store hw_info parameters to SPI flash\n");
+ return ret;
+}
+
+/**
+ * mac_read_from_eeprom() - Read the parameters from SPI flash.
+ *
+ * This function reads the content of the Marvell hw_info parameters from the
+ * SPI flash and imports them into the U-Boot environment.
+ * This includes MAC addresses and board serial numbers.
+ *
+ * The import is performed only once.
+ *
+ * This function is a part of the U-Boot mac command and must be executed
+ * after SPI flash initialization.
+ */
+int mac_read_from_eeprom(void)
+{
+ fdt_addr_t flash_offset, size;
+ ofnode hw_info_node;
+
+ hw_info_node = ofnode_by_compatible(ofnode_null(), "marvell,hw-info");
+ if (!ofnode_valid(hw_info_node)) {
+ printf("Missing hw-info DT node!\n");
+ return -ENODEV;
+ }
+
+ flash_offset = ofnode_get_addr_size_index_notrans(hw_info_node, 0, &size);
+ if (flash_offset == FDT_ADDR_T_NONE || !size) {
+ printf("Missing hw-info offset or size!\n");
+ return -EINVAL;
+ }
+
+ if (env_get_ulong(HW_INFO_MERGED_VARIABLE, 10, 0) == 0) {
+ if (env_set_ulong(HW_INFO_MERGED_VARIABLE, 1))
+ return -ENOENT;
+ return cmd_hw_info_read(flash_offset, false);
+ }
+ return 0;
+}
+
+/**
+ * print_platform_help() - Print the platform specific help
+ *
+ * Extend the existing U-Boot mac command description by also printing
+ * platform specific help text.
+ */
+static void print_platform_help(void)
+{
+ printf("\nNote: arguments mac [id|num|errata|date|ports|port_number]\n"
+ "are unavailable on Marvell Armada A37xx platforms.\n"
+ "Use mac [read|save {parameter}] instead.\n"
+ "Available parameters:\n"
+ "pcb_slm\tPCB SLM number\n"
+ "pcb_rev\tPCB revision number\n"
+ "eco_rev\tECO revision number\n"
+ "pcb_sn\tPCB SN\n"
+ "ethaddr\tfirst MAC address\n"
+ "eth[1-9]addr\tsecond-ninth MAC address\n");
+}
+
+/**
+ * do_mac() - Standard U-Boot mac command implementation
+ * @cmdtp: U-Boot command table
+ * @flag: Execution flags
+ * @argc: Count of arguments
+ * @argv: Arguments
+ *
+ * This function implements the standard U-Boot mac command in a mostly
+ * compatible way.
+ * To conform to the general command structure as much as possible, the
+ * command description from cmd/mac.c is followed.
+ * Where not possible, convenient or sensible additional comments for the user
+ * are added.
+ */
+int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ const char *cmd = argv[1];
+ fdt_addr_t flash_offset, size;
+ ofnode hw_info_node;
+ int ret = 0;
+
+ hw_info_node = ofnode_by_compatible(ofnode_null(), "marvell,hw-info");
+ if (!ofnode_valid(hw_info_node)) {
+ printf("Missing hw-info DT node!\n");
+ return -ENODEV;
+ }
+
+ flash_offset = ofnode_get_addr_size_index_notrans(hw_info_node, 0, &size);
+ if (flash_offset == FDT_ADDR_T_NONE || !size) {
+ printf("Missing hw-info offset or size!\n");
+ return -EINVAL;
+ }
+
+ if (argc == 1) {
+ ret = cmd_hw_info_dump(flash_offset);
+ if (ret)
+ return -EINVAL;
+ return CMD_RET_SUCCESS;
+ }
+
+ if (!strcmp(cmd, "read")) {
+ if (cmd_hw_info_read(flash_offset, true))
+ return -EINVAL;
+ } else if (!strcmp(cmd, "save")) {
+ if (argc != 3) {
+ printf("Please pass an additional argument to specify, "
+ "which env parameter to save.\n");
+ return -EINVAL;
+ }
+ if (cmd_hw_info_save(flash_offset, argv[2]))
+ return -EINVAL;
+ } else {
+ ret = cmd_usage(cmdtp);
+ print_platform_help();
+ return ret;
+ }
+
+ return CMD_RET_SUCCESS;
+}
@@ -40,6 +40,13 @@
*/
#define DEFAULT_ENV_IS_RW /* required for configuring default fdtfile= */
+/*
+ * Platform identification (Marvell hw_info parameters)
+ */
+#ifdef CONFIG_MVEBU_MAC_HW_INFO
+#define CONFIG_ID_EEPROM /* U-Boot mac command */
+#endif
+
/*
* Ethernet Driver configuration
*/
@@ -29,6 +29,13 @@
/* End of 16M scrubbed by training in bootrom */
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_TEXT_BASE + 0xFF0000)
+/*
+ * Platform identification (Marvell hw_info parameters)
+ */
+#ifdef CONFIG_MVEBU_MAC_HW_INFO
+#define CONFIG_ID_EEPROM /* U-Boot mac command */
+#endif
+
/* When runtime detection fails this is the default */
#define CONFIG_SYS_MAX_NAND_DEVICE 1
@@ -794,7 +794,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])
* multi-line values.
*
* In theory, arbitrary separator characters can be used, but only
- * '\0' and '\n' have really been tested.
+ * '\0', '\n' and 0x20 have been tested.
*/
int himport_r(struct hsearch_data *htab,