--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2021 OpenWrt.org
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_RELEASE:=1
+PKG_VERSION:=2021.07
+
+PKG_HASH:=312b7eeae44581d1362c3a3f02c28d806647756c82ba8c72241c7cdbe68ba77e
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+ BUILD_TARGET:=hifiveu
+ BUILD_DEVICES=$(1)
+ UBOOT_IMAGE:=u-boot.itb
+ DTS_DIR:=arch/riscv/dts
+ UENV:=default
+ DEFAULT:=y
+endef
+
+define U-Boot/sifive_unleashed
+ NAME:=SiFive Unleashed
+ OPENSBI:=generic
+ DEPENDS:=+opensbi_generic
+ UBOOT_DTS:=hifive-unleashed-a00.dtb
+ BUILD_DEVICES:=sifive_unleashed
+endef
+
+define U-Boot/sifive_unmatched
+ NAME:=SiFive Unmatched
+ OPENSBI:=generic
+ DEPENDS:=+opensbi_generic
+ UBOOT_DTS:=hifive-unmatched-a00.dtb
+ BUILD_DEVICES:=sifive_unmatched
+endef
+
+UBOOT_TARGETS := \
+ sifive_unleashed \
+ sifive_unmatched
+
+UBOOT_MAKE_FLAGS += \
+ OPENSBI=$(STAGING_DIR_IMAGE)/fw_dynamic-${OPENSBI}.bin
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE)
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/spl/u-boot-spl.bin $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE)-spl
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(DTS_DIR)/$(UBOOT_DTS) $(STAGING_DIR_IMAGE)/$(UBOOT_DTS)
+
+ mkimage -C none -A arm -T script -d uEnv-$(UENV).txt \
+ $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-boot.scr
+endef
+
+$(eval $(call BuildPackage/U-Boot))
--- /dev/null
+From 351fbd6208739d1a94fc11b2aa60d8a02d2f675a Mon Sep 17 00:00:00 2001
+From: David Abdurachmanov <david.abdurachmanov@sifive.com>
+Date: Mon, 13 Sep 2021 03:09:05 -0700
+Subject: [PATCH 01/16] riscv: sifive: unleashed: support compressed images
+
+Define kernel_comp_addr_r and kernel_comp_size to allow support for compressed
+Image files for booti command. Note that we leave 128MiB for ramdisk and set
+compressed kernel size for 64MiB.
+
+Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
+---
+ include/configs/sifive-unleashed.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/configs/sifive-unleashed.h b/include/configs/sifive-unleashed.h
+index 0d69d1c..5acce36 100644
+--- a/include/configs/sifive-unleashed.h
++++ b/include/configs/sifive-unleashed.h
+@@ -71,6 +71,8 @@
+ "script_size_f=0x1000\0" \
+ "pxefile_addr_r=0x88200000\0" \
+ "ramdisk_addr_r=0x88300000\0" \
++ "kernel_comp_addr_r=0x90300000\0" \
++ "kernel_comp_size=0x4000000\0" \
+ "type_guid_gpt_loader1=" TYPE_GUID_LOADER1 "\0" \
+ "type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
+ "type_guid_gpt_system=" TYPE_GUID_SYSTEM "\0" \
+--
+2.7.4
+
--- /dev/null
+From a3a717668b8158c555490921722c04ea6c07bf1a Mon Sep 17 00:00:00 2001
+From: Green Wan <green.wan@sifive.com>
+Date: Mon, 28 Jun 2021 19:13:08 +0800
+Subject: [PATCH 02/16] drivers: clk: sifive: fu740-prci: replace 'pciaux' with
+ 'pcieaux'
+
+Replace 'pciaux' with 'pcieaux', including name string and function
+prefix. The old name string, 'pciaux', might cause an error if PCIe
+driver is changed to use clk_get_by_name() with 'pcieaux' to get
+clock.
+
+Signed-off-by: Green Wan <green.wan@sifive.com>
+Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
+---
+ drivers/clk/sifive/fu740-prci.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c
+index 9a642c1..b025050 100644
+--- a/drivers/clk/sifive/fu740-prci.c
++++ b/drivers/clk/sifive/fu740-prci.c
+@@ -20,7 +20,7 @@
+ #include "sifive-prci.h"
+ #include <asm/io.h>
+
+-int sifive_prci_fu740_pciauxclk_enable(struct __prci_clock *pc, bool enable)
++int sifive_prci_fu740_pcieauxclk_enable(struct __prci_clock *pc, bool enable)
+ {
+ struct __prci_wrpll_data *pwd = pc->pwd;
+ struct __prci_data *pd = pc->pd;
+@@ -98,7 +98,7 @@ static const struct __prci_clock_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = {
+ };
+
+ static const struct __prci_clock_ops sifive_fu740_prci_pcieaux_clk_ops = {
+- .enable_clk = sifive_prci_fu740_pciauxclk_enable,
++ .enable_clk = sifive_prci_fu740_pcieauxclk_enable,
+ };
+
+ /* List of clock controls provided by the PRCI */
+@@ -150,7 +150,7 @@ struct __prci_clock __prci_init_clocks_fu740[] = {
+ .ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops,
+ },
+ [PRCI_CLK_PCIEAUX] {
+- .name = "pciaux",
++ .name = "pcieaux",
+ .parent_name = "",
+ .ops = &sifive_fu740_prci_pcieaux_clk_ops,
+ .pwd = &__prci_pcieaux_data,
+--
+2.7.4
+
--- /dev/null
+From 3b4e1fd666cc156bf6d56da60d62dc063f75b7c4 Mon Sep 17 00:00:00 2001
+From: Zong Li <zong.li@sifive.com>
+Date: Wed, 30 Jun 2021 23:23:45 +0800
+Subject: [PATCH 03/16] board: sifive: unmatched: add initial support for a
+ platform ID EEPROM
+
+Add initial support for the PCB description EEPROM for SiFive HiFive
+Unmatched boards.
+
+This implementation is refactored based on Paul Walmsley's porting and
+adopt the suggestions from David Abdurachmanov.
+
+Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
+Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
+Signed-off-by: Zong Li <zong.li@sifive.com>
+Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
+---
+ board/sifive/unmatched/Makefile | 1 +
+ .../sifive/unmatched/hifive-platform-i2c-eeprom.c | 542 +++++++++++++++++++++
+ include/configs/sifive-unmatched.h | 6 +
+ 3 files changed, 549 insertions(+)
+ create mode 100644 board/sifive/unmatched/hifive-platform-i2c-eeprom.c
+
+diff --git a/board/sifive/unmatched/Makefile b/board/sifive/unmatched/Makefile
+index 6308c80..e00b330 100644
+--- a/board/sifive/unmatched/Makefile
++++ b/board/sifive/unmatched/Makefile
+@@ -3,6 +3,7 @@
+ # Copyright (c) 2020-2021 SiFive, Inc
+
+ obj-y += unmatched.o
++obj-$(CONFIG_ID_EEPROM) += hifive-platform-i2c-eeprom.o
+
+ ifdef CONFIG_SPL_BUILD
+ obj-y += spl.o
+diff --git a/board/sifive/unmatched/hifive-platform-i2c-eeprom.c b/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
+new file mode 100644
+index 0000000..9a62d32
+--- /dev/null
++++ b/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
+@@ -0,0 +1,542 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2020 SiFive, Inc.
++ *
++ * Based on board/freescale/common/sys_eeprom.c:
++ * Copyright 2006, 2008-2009, 2011 Freescale Semiconductor
++ * York Sun (yorksun@freescale.com)
++ * Haiying Wang (haiying.wang@freescale.com)
++ * Timur Tabi (timur@freescale.com)
++ */
++
++#include <common.h>
++#include <command.h>
++#include <env.h>
++#include <i2c.h>
++#include <init.h>
++#include <linux/ctype.h>
++#include <linux/delay.h>
++#include <u-boot/crc.h>
++
++#ifndef CONFIG_SYS_EEPROM_BUS_NUM
++#error Requires CONFIG_SYS_EEPROM_BUS_NUM to be defined
++#endif
++
++#define FORMAT_VERSION 0x1
++
++/* Options for the manuf_test_status field */
++#define SIFIVE_MANUF_TEST_STATUS_UNKNOWN 0
++#define SIFIVE_MANUF_TEST_STATUS_PASS 1
++#define SIFIVE_MANUF_TEST_STATUS_FAIL 2
++
++/*
++ * BYTES_PER_EEPROM_PAGE: the AT24C02 datasheet says that data can
++ * only be written in page mode, which means 8 bytes at a time
++ */
++#define BYTES_PER_EEPROM_PAGE 8
++
++/*
++ * EEPROM_WRITE_DELAY_MS: the AT24C02 datasheet says it takes up to
++ * 5ms to complete a given write
++ */
++#define EEPROM_WRITE_DELAY_MS 5000
++
++/*
++ * MAGIC_NUMBER_BYTES: number of bytes used by the magic number
++ */
++#define MAGIC_NUMBER_BYTES 4
++
++/*
++ * SERIAL_NUMBER_BYTES: number of bytes used by the board serial
++ * number
++ */
++#define SERIAL_NUMBER_BYTES 16
++
++/*
++ * MAC_ADDR_BYTES: number of bytes used by the Ethernet MAC address
++ */
++#define MAC_ADDR_BYTES 6
++
++/*
++ * MAC_ADDR_STRLEN: length of mac address string
++ */
++#define MAC_ADDR_STRLEN 17
++
++/*
++ * SiFive OUI. Registration Date is 2018-02-15
++ */
++#define SIFIVE_OUI_PREFIX "70:B3:D5:92:F"
++
++/**
++ * static eeprom: EEPROM layout for the SiFive platform I2C format
++ */
++static struct __attribute__ ((__packed__)) sifive_eeprom {
++ u8 magic[MAGIC_NUMBER_BYTES];
++ u8 format_ver;
++ u16 product_id;
++ u8 pcb_revision;
++ u8 bom_revision;
++ u8 bom_variant;
++ u8 serial[SERIAL_NUMBER_BYTES];
++ u8 manuf_test_status;
++ u8 mac_addr[MAC_ADDR_BYTES];
++ u32 crc;
++} e;
++
++struct sifive_product {
++ u16 id;
++ const char *name;
++};
++
++/* Set to 1 if we've read EEPROM into memory */
++static int has_been_read;
++
++/* Magic number at the first four bytes of EEPROM */
++static const unsigned char magic[MAGIC_NUMBER_BYTES] = { 0xf1, 0x5e, 0x50, 0x45 };
++
++/* Does the magic number match that of a SiFive EEPROM? */
++static inline int is_match_magic(void)
++{
++ return (memcmp(&e.magic, &magic, MAGIC_NUMBER_BYTES) == 0);
++}
++
++/* Calculate the current CRC */
++static inline u32 calculate_crc32(void)
++{
++ return crc32(0, (void *)&e, sizeof(struct sifive_eeprom) - sizeof(e.crc));
++}
++
++/* This function should be called after each update to the EEPROM structure */
++static inline void update_crc(void)
++{
++ e.crc = calculate_crc32();
++}
++
++static struct sifive_product sifive_products[] = {
++ { 0, "Unknown"},
++ { 2, "HiFive Unmatched" },
++};
++
++/**
++ * dump_raw_eeprom - display the raw contents of the EEPROM
++ */
++static void dump_raw_eeprom(void)
++{
++ unsigned int i;
++
++ printf("EEPROM dump: (0x%lx bytes)\n", sizeof(e));
++ for (i = 0; i < sizeof(e); i++) {
++ if ((i % 16) == 0)
++ printf("%02X: ", i);
++ printf("%02X ", ((u8 *)&e)[i]);
++ if (((i % 16) == 15) || (i == sizeof(e) - 1))
++ printf("\n");
++ }
++}
++
++/**
++ * show_eeprom - display the contents of the EEPROM
++ */
++static void show_eeprom(void)
++{
++ unsigned int i;
++ u32 crc;
++ const char *product_name = "Unknown";
++ char board_serial[SERIAL_NUMBER_BYTES + 1] = { 0 };
++
++ if (!is_match_magic()) {
++ printf("Not a SiFive HiFive EEPROM data format - magic bytes don't match\n");
++ dump_raw_eeprom();
++ return;
++ };
++
++ snprintf(board_serial, sizeof(board_serial), "%s", e.serial);
++
++ for (i = 0; i < ARRAY_SIZE(sifive_products); i++) {
++ if (sifive_products[i].id == e.product_id) {
++ product_name = sifive_products[i].name;
++ break;
++ }
++ };
++
++ printf("SiFive PCB EEPROM format v%u\n", e.format_ver);
++ printf("Product ID: %04hx (%s)\n", e.product_id, product_name);
++ printf("PCB revision: %x\n", e.pcb_revision);
++ printf("BOM revision: %c\n", e.bom_revision);
++ printf("BOM variant: %x\n", e.bom_variant);
++ printf("Serial number: %s\n", board_serial);
++ printf("Ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
++ e.mac_addr[0], e.mac_addr[1], e.mac_addr[2],
++ e.mac_addr[3], e.mac_addr[4], e.mac_addr[5]);
++
++ crc = calculate_crc32();
++ if (crc == e.crc) {
++ printf("CRC: %08x\n", e.crc);
++ } else {
++ printf("CRC: %08x (should be %08x)\n", e.crc, crc);
++ dump_raw_eeprom();
++ }
++}
++
++/**
++ * read_eeprom() - read the EEPROM into memory, if it hasn't been read already
++ */
++static int read_eeprom(void)
++{
++ int ret;
++ struct udevice *dev;
++
++ if (has_been_read)
++ return 0;
++
++ ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
++ CONFIG_SYS_I2C_EEPROM_ADDR,
++ 1,
++ &dev);
++ if (!ret)
++ dm_i2c_read(dev, 0, (void *)&e,
++ sizeof(struct sifive_eeprom));
++
++ show_eeprom();
++
++ has_been_read = (ret == 0) ? 1 : 0;
++
++ return ret;
++}
++
++/**
++ * prog_eeprom() - write the EEPROM from memory
++ */
++static int prog_eeprom(void)
++{
++ int ret = 0;
++ unsigned int i;
++ void *p;
++
++ if (!is_match_magic()) {
++ printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n");
++ return 0;
++ }
++
++ for (i = 0, p = &e; i < sizeof(e);
++ i += BYTES_PER_EEPROM_PAGE, p += BYTES_PER_EEPROM_PAGE) {
++ struct udevice *dev;
++
++ ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
++ CONFIG_SYS_I2C_EEPROM_ADDR,
++ CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
++ &dev);
++ if (!ret)
++ ret = dm_i2c_write(dev, i, p,
++ min((int)(sizeof(e) - i),
++ BYTES_PER_EEPROM_PAGE));
++
++ if (ret)
++ break;
++
++ udelay(EEPROM_WRITE_DELAY_MS);
++ }
++
++ if (!ret) {
++ /* Verify the write by reading back the EEPROM and comparing */
++ struct sifive_eeprom e2;
++ struct udevice *dev;
++
++ ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
++ CONFIG_SYS_I2C_EEPROM_ADDR,
++ CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
++ &dev);
++ if (!ret)
++ ret = dm_i2c_read(dev, 0, (void *)&e2, sizeof(e2));
++ if (!ret && memcmp(&e, &e2, sizeof(e)))
++ ret = -1;
++ }
++
++ if (ret) {
++ printf("Programming failed.\n");
++ has_been_read = 0;
++ return -1;
++ }
++
++ printf("Programming passed.\n");
++ return 0;
++}
++
++/**
++ * set_mac_address() - stores a MAC address into the local EEPROM copy
++ *
++ * This function takes a pointer to MAC address string
++ * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number),
++ * stores it in the MAC address field of the EEPROM local copy, and
++ * updates the local copy of the CRC.
++ */
++static void set_mac_address(char *string)
++{
++ unsigned int i;
++
++ if (strncasecmp(SIFIVE_OUI_PREFIX, string, 13)) {
++ printf("The MAC address doesn't match SiFive OUI %s\n",
++ SIFIVE_OUI_PREFIX);
++ return;
++ }
++
++ for (i = 0; *string && (i < MAC_ADDR_BYTES); i++) {
++ e.mac_addr[i] = simple_strtoul(string, &string, 16);
++ if (*string == ':')
++ string++;
++ }
++
++ update_crc();
++}
++
++/**
++ * set_manuf_test_status() - stores a test status byte into the in-memory copy
++ *
++ * Takes a pointer to a manufacturing test status string ("unknown",
++ * "pass", "fail") and stores the corresponding numeric ID to the
++ * manuf_test_status field of the EEPROM local copy, and updates the
++ * CRC of the local copy.
++ */
++static void set_manuf_test_status(char *string)
++{
++ if (!strcasecmp(string, "unknown")) {
++ e.manuf_test_status = SIFIVE_MANUF_TEST_STATUS_UNKNOWN;
++ } else if (!strcasecmp(string, "pass")) {
++ e.manuf_test_status = SIFIVE_MANUF_TEST_STATUS_PASS;
++ } else if (!strcasecmp(string, "fail")) {
++ e.manuf_test_status = SIFIVE_MANUF_TEST_STATUS_FAIL;
++ } else {
++ printf("Usage: mac manuf_test_status (unknown|pass|fail)\n");
++ return;
++ }
++
++ update_crc();
++}
++
++/**
++ * set_pcb_revision() - stores a SiFive PCB revision into the local EEPROM copy
++ *
++ * Takes a pointer to a string representing the numeric PCB revision in
++ * decimal ("0" - "255"), stores it in the pcb_revision field of the
++ * EEPROM local copy, and updates the CRC of the local copy.
++ */
++static void set_pcb_revision(char *string)
++{
++ unsigned long p;
++
++ p = simple_strtoul(string, &string, 10);
++ if (p > U8_MAX) {
++ printf("%s must not be greater than %d\n", "PCB revision",
++ U8_MAX);
++ return;
++ }
++
++ e.pcb_revision = p;
++
++ update_crc();
++}
++
++/**
++ * set_bom_revision() - stores a SiFive BOM revision into the local EEPROM copy
++ *
++ * Takes a pointer to a uppercase ASCII character representing the BOM
++ * revision ("A" - "Z"), stores it in the bom_revision field of the
++ * EEPROM local copy, and updates the CRC of the local copy.
++ */
++static void set_bom_revision(char *string)
++{
++ if (string[0] < 'A' || string[0] > 'Z') {
++ printf("BOM revision must be an uppercase letter between A and Z\n");
++ return;
++ }
++
++ e.bom_revision = string[0];
++
++ update_crc();
++}
++
++/**
++ * set_bom_variant() - stores a SiFive BOM variant into the local EEPROM copy
++ *
++ * Takes a pointer to a string representing the numeric BOM variant in
++ * decimal ("0" - "255"), stores it in the bom_variant field of the
++ * EEPROM local copy, and updates the CRC of the local copy.
++ */
++static void set_bom_variant(char *string)
++{
++ unsigned long p;
++
++ p = simple_strtoul(string, &string, 10);
++ if (p > U8_MAX) {
++ printf("%s must not be greater than %d\n", "BOM variant",
++ U8_MAX);
++ return;
++ }
++
++ e.bom_variant = p;
++
++ update_crc();
++}
++
++/**
++ * set_product_id() - stores a SiFive product ID into the local EEPROM copy
++ *
++ * Takes a pointer to a string representing the numeric product ID in
++ * decimal ("0" - "65535"), stores it in the product ID field of the
++ * EEPROM local copy, and updates the CRC of the local copy.
++ */
++static void set_product_id(char *string)
++{
++ unsigned long p;
++
++ p = simple_strtoul(string, &string, 10);
++ if (p > U16_MAX) {
++ printf("%s must not be greater than %d\n", "Product ID",
++ U16_MAX);
++ return;
++ }
++
++ e.product_id = p;
++
++ update_crc();
++}
++
++/**
++ * set_serial_number() - set the PCB serial number in the in-memory copy
++ *
++ * Set the board serial number in the in-memory EEPROM copy from the supplied
++ * string argument, and update the CRC.
++ */
++static void set_serial_number(char *string)
++{
++ if (strlen(string) > SERIAL_NUMBER_BYTES) {
++ printf("Serial number must not be greater than 16 bytes\n");
++ return;
++ }
++
++ memset(e.serial, 0, sizeof(e.serial));
++ strncpy((char *)e.serial, string, sizeof(e.serial));
++ update_crc();
++}
++
++/**
++ * init_local_copy() - initialize the in-memory EEPROM copy
++ *
++ * Initialize the in-memory EEPROM copy with the magic number. Must
++ * be done when preparing to initialize a blank EEPROM, or overwrite
++ * one with a corrupted magic number.
++ */
++static void init_local_copy(void)
++{
++ memset(&e, 0, sizeof(e));
++ memcpy(e.magic, magic, sizeof(e.magic));
++ e.format_ver = FORMAT_VERSION;
++ update_crc();
++}
++
++int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
++{
++ char *cmd;
++
++ if (argc == 1) {
++ show_eeprom();
++ return 0;
++ }
++
++ if (argc > 3)
++ return cmd_usage(cmdtp);
++
++ cmd = argv[1];
++
++ /* Commands with no argument */
++ if (!strcmp(cmd, "read_eeprom")) {
++ read_eeprom();
++ return 0;
++ } else if (!strcmp(cmd, "initialize")) {
++ init_local_copy();
++ return 0;
++ } else if (!strcmp(cmd, "write_eeprom")) {
++ prog_eeprom();
++ return 0;
++ }
++
++ if (argc != 3)
++ return cmd_usage(cmdtp);
++
++ if (!is_match_magic()) {
++ printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n");
++ return 0;
++ }
++
++ if (!strcmp(cmd, "serial_number")) {
++ set_serial_number(argv[2]);
++ return 0;
++ } else if (!strcmp(cmd, "manuf_test_status")) {
++ set_manuf_test_status(argv[2]);
++ return 0;
++ } else if (!strcmp(cmd, "mac_address")) {
++ set_mac_address(argv[2]);
++ return 0;
++ } else if (!strcmp(cmd, "pcb_revision")) {
++ set_pcb_revision(argv[2]);
++ return 0;
++ } else if (!strcmp(cmd, "bom_variant")) {
++ set_bom_variant(argv[2]);
++ return 0;
++ } else if (!strcmp(cmd, "bom_revision")) {
++ set_bom_revision(argv[2]);
++ return 0;
++ } else if (!strcmp(cmd, "product_id")) {
++ set_product_id(argv[2]);
++ return 0;
++ }
++
++ return cmd_usage(cmdtp);
++}
++
++/**
++ * mac_read_from_eeprom() - read the MAC address from EEPROM
++ *
++ * This function reads the MAC address from EEPROM and sets the
++ * appropriate environment variables for each one read.
++ *
++ * The environment variables are only set if they haven't been set already.
++ * This ensures that any user-saved variables are never overwritten.
++ *
++ * This function must be called after relocation.
++ */
++int mac_read_from_eeprom(void)
++{
++ u32 crc;
++ char board_serial[SERIAL_NUMBER_BYTES + 1] = { 0 };
++
++ puts("EEPROM: ");
++
++ if (read_eeprom()) {
++ printf("Read failed.\n");
++ return 0;
++ }
++
++ if (!is_match_magic()) {
++ printf("Invalid ID (%02x %02x %02x %02x)\n",
++ e.magic[0], e.magic[1], e.magic[2], e.magic[3]);
++ dump_raw_eeprom();
++ return 0;
++ }
++
++ crc = calculate_crc32();
++ if (crc != e.crc) {
++ printf("CRC mismatch (%08x != %08x)\n", crc, e.crc);
++ dump_raw_eeprom();
++ return 0;
++ }
++
++ eth_env_set_enetaddr("ethaddr", e.mac_addr);
++
++ if (!env_get("serial#")) {
++ snprintf(board_serial, sizeof(board_serial), "%s", e.serial);
++ env_set("serial#", board_serial);
++ }
++
++ return 0;
++}
+diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h
+index 4fad69b..9e1859c 100644
+--- a/include/configs/sifive-unmatched.h
++++ b/include/configs/sifive-unmatched.h
+@@ -80,4 +80,10 @@
+ "fdt addr ${fdtcontroladdr};"
+ #endif /* CONFIG_SPL_BUILD */
+
++#define CONFIG_SYS_EEPROM_BUS_NUM 0
++#define CONFIG_SYS_I2C_EEPROM_ADDR 0x54
++#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 0x1
++
++#define CONFIG_ID_EEPROM
++
+ #endif /* __SIFIVE_UNMATCHED_H */
+--
+2.7.4
+
--- /dev/null
+From feb5ac0bc029c8199bc29ab5b2ddf66eaa533843 Mon Sep 17 00:00:00 2001
+From: Zong Li <zong.li@sifive.com>
+Date: Wed, 30 Jun 2021 23:23:46 +0800
+Subject: [PATCH 04/16] riscv: sifive: fu740: kconfig: Enable support for
+ Opencores I2C controller
+
+Enable the Opencores I2C controller on FU740
+
+Signed-off-by: Zong Li <zong.li@sifive.com>
+Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
+---
+ arch/riscv/cpu/fu740/Kconfig | 2 ++
+ board/sifive/unmatched/Kconfig | 1 +
+ 2 files changed, 3 insertions(+)
+
+diff --git a/arch/riscv/cpu/fu740/Kconfig b/arch/riscv/cpu/fu740/Kconfig
+index 3a5f6e4..1dc052b 100644
+--- a/arch/riscv/cpu/fu740/Kconfig
++++ b/arch/riscv/cpu/fu740/Kconfig
+@@ -35,3 +35,5 @@ config SIFIVE_FU740
+ imply SIFIVE_OTP
+ imply DM_PWM
+ imply PWM_SIFIVE
++ imply DM_I2C
++ imply SYS_I2C_OCORES
+diff --git a/board/sifive/unmatched/Kconfig b/board/sifive/unmatched/Kconfig
+index 88b5883..fb2c1fb 100644
+--- a/board/sifive/unmatched/Kconfig
++++ b/board/sifive/unmatched/Kconfig
+@@ -47,5 +47,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+ imply PHY_MSCC
+ imply SYSRESET
+ imply SYSRESET_GPIO
++ imply CMD_I2C
+
+ endif
+--
+2.7.4
+
--- /dev/null
+From bda688c4b0cda4bd20ccf1d771f1f4285a9adf27 Mon Sep 17 00:00:00 2001
+From: Zong Li <zong.li@sifive.com>
+Date: Wed, 30 Jun 2021 23:23:47 +0800
+Subject: [PATCH 05/16] riscv: sifive: fu740: Support i2c in spl
+
+Enable SPL_I2C_SUPPORT for fu740, and add 'u-boot,dm-spl' property in
+i2c node.
+
+Signed-off-by: Zong Li <zong.li@sifive.com>
+Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
+---
+ arch/riscv/cpu/fu740/Kconfig | 1 +
+ arch/riscv/dts/fu740-c000-u-boot.dtsi | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/arch/riscv/cpu/fu740/Kconfig b/arch/riscv/cpu/fu740/Kconfig
+index 1dc052b..8e54310 100644
+--- a/arch/riscv/cpu/fu740/Kconfig
++++ b/arch/riscv/cpu/fu740/Kconfig
+@@ -37,3 +37,4 @@ config SIFIVE_FU740
+ imply PWM_SIFIVE
+ imply DM_I2C
+ imply SYS_I2C_OCORES
++ imply SPL_I2C_SUPPORT
+diff --git a/arch/riscv/dts/fu740-c000-u-boot.dtsi b/arch/riscv/dts/fu740-c000-u-boot.dtsi
+index a5d0688..a6f7a08 100644
+--- a/arch/riscv/dts/fu740-c000-u-boot.dtsi
++++ b/arch/riscv/dts/fu740-c000-u-boot.dtsi
+@@ -95,6 +95,10 @@
+ u-boot,dm-spl;
+ };
+
++&i2c0 {
++ u-boot,dm-spl;
++};
++
+ ð0 {
+ assigned-clocks = <&prci PRCI_CLK_GEMGXLPLL>;
+ assigned-clock-rates = <125125000>;
+--
+2.7.4
+
--- /dev/null
+From cdecb59564d7b2f2f0a53a41e6933f63badb2def Mon Sep 17 00:00:00 2001
+From: Zong Li <zong.li@sifive.com>
+Date: Wed, 30 Jun 2021 23:23:48 +0800
+Subject: [PATCH 06/16] board: sifive: Add an interface to get PCB revision
+
+There are different DDR parameter settings for different board
+revisions. Add a new interface to get the PCB revision to determine
+which DT should be selected at runtime.
+
+Signed-off-by: Zong Li <zong.li@sifive.com>
+Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
+---
+ arch/riscv/include/asm/arch-fu740/eeprom.h | 15 ++++++++++
+ .../sifive/unmatched/hifive-platform-i2c-eeprom.c | 32 ++++++++++++++++++++++
+ 2 files changed, 47 insertions(+)
+ create mode 100644 arch/riscv/include/asm/arch-fu740/eeprom.h
+
+diff --git a/arch/riscv/include/asm/arch-fu740/eeprom.h b/arch/riscv/include/asm/arch-fu740/eeprom.h
+new file mode 100644
+index 0000000..0e1220e
+--- /dev/null
++++ b/arch/riscv/include/asm/arch-fu740/eeprom.h
+@@ -0,0 +1,15 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2021 SiFive, Inc.
++ *
++ * Zong Li <zong.li@sifve.com>
++ */
++
++#ifndef _ASM_RISCV_EEPROM_H
++#define _ASM_RISCV_EEPROM_H
++
++#define PCB_REVISION_REV3 0x3
++
++u8 get_pcb_revision_from_eeprom(void);
++
++#endif /* _ASM_RISCV_EEPROM_H */
+diff --git a/board/sifive/unmatched/hifive-platform-i2c-eeprom.c b/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
+index 9a62d32..a2151f1 100644
+--- a/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
++++ b/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
+@@ -540,3 +540,35 @@ int mac_read_from_eeprom(void)
+
+ return 0;
+ }
++
++/**
++ * get_pcb_revision_from_eeprom - get the PCB revision
++ *
++ * Read the EEPROM to determine the board revision.
++ *
++ * This function is called before relocation, so we need to read a private
++ * copy of the EEPROM into a local variable on the stack.
++ */
++u8 get_pcb_revision_from_eeprom(void)
++{
++ struct __attribute__ ((__packed__)) board_eeprom {
++ u8 magic[MAGIC_NUMBER_BYTES];
++ u8 format_ver;
++ u16 product_id;
++ u8 pcb_revision;
++ } be;
++
++ int ret;
++ struct udevice *dev;
++
++ ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
++ CONFIG_SYS_I2C_EEPROM_ADDR,
++ 1,
++ &dev);
++
++ if (!ret)
++ dm_i2c_read(dev, 0, (void *)&be,
++ sizeof(struct board_eeprom));
++
++ return be.pcb_revision;
++}
+--
+2.7.4
+
--- /dev/null
+From e6b25cf93a9255a5c167ffab7a6e87c272a2b07d Mon Sep 17 00:00:00 2001
+From: Zong Li <zong.li@sifive.com>
+Date: Fri, 9 Jul 2021 16:26:35 +0800
+Subject: [PATCH 07/16] board: sifive: remove the command for setting serial
+ number
+
+We wouldn't like to allow user to change the serial number, so remove
+the command for changing serial number in EEPROM.
+
+Signed-off-by: Zong Li <zong.li@sifive.com>
+Suggested-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
+Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
+---
+ .../sifive/unmatched/hifive-platform-i2c-eeprom.c | 23 +---------------------
+ 1 file changed, 1 insertion(+), 22 deletions(-)
+
+diff --git a/board/sifive/unmatched/hifive-platform-i2c-eeprom.c b/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
+index a2151f1..ad2f315 100644
+--- a/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
++++ b/board/sifive/unmatched/hifive-platform-i2c-eeprom.c
+@@ -402,24 +402,6 @@ static void set_product_id(char *string)
+ }
+
+ /**
+- * set_serial_number() - set the PCB serial number in the in-memory copy
+- *
+- * Set the board serial number in the in-memory EEPROM copy from the supplied
+- * string argument, and update the CRC.
+- */
+-static void set_serial_number(char *string)
+-{
+- if (strlen(string) > SERIAL_NUMBER_BYTES) {
+- printf("Serial number must not be greater than 16 bytes\n");
+- return;
+- }
+-
+- memset(e.serial, 0, sizeof(e.serial));
+- strncpy((char *)e.serial, string, sizeof(e.serial));
+- update_crc();
+-}
+-
+-/**
+ * init_local_copy() - initialize the in-memory EEPROM copy
+ *
+ * Initialize the in-memory EEPROM copy with the magic number. Must
+@@ -468,10 +450,7 @@ int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+ return 0;
+ }
+
+- if (!strcmp(cmd, "serial_number")) {
+- set_serial_number(argv[2]);
+- return 0;
+- } else if (!strcmp(cmd, "manuf_test_status")) {
++ if (!strcmp(cmd, "manuf_test_status")) {
+ set_manuf_test_status(argv[2]);
+ return 0;
+ } else if (!strcmp(cmd, "mac_address")) {
+--
+2.7.4
+
--- /dev/null
+From 5f26d71202f37d77ecf74da2ce7e4c3a3f4d48d3 Mon Sep 17 00:00:00 2001
+From: Vincent Chen <vincent.chen@sifive.com>
+Date: Thu, 8 Jul 2021 09:08:20 +0800
+Subject: [PATCH 08/16] board: sifive: unmatched: refine GEMGXL initialized
+ function in SPL
+
+Create a new function spl_reset_device_by_gpio to reset the device
+whose reset pin is connected to the GPIO. Then, using this function
+to initialize GEMGXL.
+
+Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
+---
+ board/sifive/unmatched/spl.c | 58 +++++++++++++++++++++++++++++---------------
+ 1 file changed, 39 insertions(+), 19 deletions(-)
+
+diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c
+index 5e1333b..b598f9f 100644
+--- a/board/sifive/unmatched/spl.c
++++ b/board/sifive/unmatched/spl.c
+@@ -22,43 +22,63 @@
+ #define MODE_SELECT_SD 0xb
+ #define MODE_SELECT_MASK GENMASK(3, 0)
+
+-int spl_board_init_f(void)
++static inline int spl_reset_device_by_gpio(const char *label, int pin, int low_width)
+ {
+ int ret;
+
+- ret = spl_soc_init();
++ ret = gpio_request(pin, label);
+ if (ret) {
+- debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret);
++ debug("%s gpio request failed: %d\n", label, ret);
++ return ret;
++ }
++
++ ret = gpio_direction_output(pin, 1);
++ if (ret) {
++ debug("%s gpio direction set failed: %d\n", label, ret);
+ return ret;
+ }
+
++ udelay(1);
++
++ gpio_set_value(pin, 0);
++ udelay(low_width);
++ gpio_set_value(pin, 1);
++
++ return ret;
++}
++
++static inline int spl_gemgxl_init(void)
++{
++ int ret;
+ /*
+ * GEMGXL init VSC8541 PHY reset sequence;
+ * leave pull-down active for 2ms
+ */
+ udelay(2000);
+- ret = gpio_request(GEM_PHY_RESET, "gem_phy_reset");
++ ret = spl_reset_device_by_gpio("gem_phy_reset", GEM_PHY_RESET, 1);
++ mdelay(15);
++
++ return ret;
++}
++
++int spl_board_init_f(void)
++{
++ int ret;
++
++ ret = spl_soc_init();
+ if (ret) {
+- debug("gem_phy_reset gpio request failed: %d\n", ret);
+- return ret;
++ debug("HiFive Unmatched FU740 SPL init failed: %d\n", ret);
++ goto end;
+ }
+
+- /* Set GPIO 12 (PHY NRESET) */
+- ret = gpio_direction_output(GEM_PHY_RESET, 1);
++ ret = spl_gemgxl_init();
+ if (ret) {
+- debug("gem_phy_reset gpio direction set failed: %d\n", ret);
+- return ret;
++ debug("Gigabit ethernet PHY (VSC8541) init failed: %d\n", ret);
++ goto end;
+ }
+
+- udelay(1);
+-
+- /* Reset PHY again to enter unmanaged mode */
+- gpio_set_value(GEM_PHY_RESET, 0);
+- udelay(1);
+- gpio_set_value(GEM_PHY_RESET, 1);
+- mdelay(15);
+-
+- return 0;
++end:
++ return ret;
+ }
+
+ u32 spl_boot_device(void)
+--
+2.7.4
+
--- /dev/null
+From 01f3996f6f3ad9b7d26bc7620af44aa063bd01b1 Mon Sep 17 00:00:00 2001
+From: Vincent Chen <vincent.chen@sifive.com>
+Date: Thu, 8 Jul 2021 09:08:21 +0800
+Subject: [PATCH 09/16] board: sifive: unmatched: reset USB hub, PCIe-USB
+ bridge, and ULPI device in SPL
+
+Ensure USB hub, PCIe-USB bridge, and ULPI device to be reset
+even if the rebooting is without power-cycling.
+
+Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
+---
+ board/sifive/unmatched/spl.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c
+index b598f9f..d566327 100644
+--- a/board/sifive/unmatched/spl.c
++++ b/board/sifive/unmatched/spl.c
+@@ -16,6 +16,9 @@
+ #include <asm/arch/gpio.h>
+ #include <asm/arch/spl.h>
+
++#define UBRDG_RESET SIFIVE_GENERIC_GPIO_NR(0, 7)
++#define ULPI_RESET SIFIVE_GENERIC_GPIO_NR(0, 9)
++#define UHUB_RESET SIFIVE_GENERIC_GPIO_NR(0, 11)
+ #define GEM_PHY_RESET SIFIVE_GENERIC_GPIO_NR(0, 12)
+
+ #define MODE_SELECT_REG 0x1000
+@@ -61,6 +64,21 @@ static inline int spl_gemgxl_init(void)
+ return ret;
+ }
+
++static inline int spl_usb_pcie_bridge_init(void)
++{
++ return spl_reset_device_by_gpio("usb_pcie_bridge_reset", UBRDG_RESET, 3000);
++}
++
++static inline int spl_usb_hub_init(void)
++{
++ return spl_reset_device_by_gpio("usb_hub_reset", UHUB_RESET, 100);
++}
++
++static inline int spl_ulpi_init(void)
++{
++ return spl_reset_device_by_gpio("ulpi_reset", ULPI_RESET, 1);
++}
++
+ int spl_board_init_f(void)
+ {
+ int ret;
+@@ -77,6 +95,24 @@ int spl_board_init_f(void)
+ goto end;
+ }
+
++ ret = spl_usb_pcie_bridge_init();
++ if (ret) {
++ debug("USB Bridge (ASM1042A) init failed: %d\n", ret);
++ goto end;
++ }
++
++ ret = spl_usb_hub_init();
++ if (ret) {
++ debug("USB Hub (ASM1074) init failed: %d\n", ret);
++ goto end;
++ }
++
++ ret = spl_ulpi_init();
++ if (ret) {
++ debug("USB 2.0 PHY (USB3320C) init failed: %d\n", ret);
++ goto end;
++ }
++
+ end:
+ return ret;
+ }
+--
+2.7.4
+
--- /dev/null
+From ac71430a203ae7073d92c5f3026f0863e6b7e22b Mon Sep 17 00:00:00 2001
+From: Vincent Chen <vincent.chen@sifive.com>
+Date: Fri, 26 Mar 2021 13:58:59 +0800
+Subject: [PATCH 10/16] board: sifive: spl: Initialized the PWM setting in the
+ SPL stage
+
+LEDs and multiple fans can be controlled by SPL. This patch ensures
+that all fans have been enabled in the SPL stage. In addition, the
+LED's color will be set to yellow.
+---
+ board/sifive/unmatched/spl.c | 2 ++
+ board/sifive/unmatched/unmatched.c | 48 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 50 insertions(+)
+
+diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c
+index d566327..3c3b22d 100644
+--- a/board/sifive/unmatched/spl.c
++++ b/board/sifive/unmatched/spl.c
+@@ -89,6 +89,8 @@ int spl_board_init_f(void)
+ goto end;
+ }
+
++ pwm_device_init();
++
+ ret = spl_gemgxl_init();
+ if (ret) {
+ debug("Gigabit ethernet PHY (VSC8541) init failed: %d\n", ret);
+diff --git a/board/sifive/unmatched/unmatched.c b/board/sifive/unmatched/unmatched.c
+index 6d60559..9924da9 100644
+--- a/board/sifive/unmatched/unmatched.c
++++ b/board/sifive/unmatched/unmatched.c
+@@ -9,6 +9,54 @@
+ #include <common.h>
+ #include <dm.h>
+ #include <asm/arch/cache.h>
++#include <linux/io.h>
++#include <asm/arch/eeprom.h>
++
++struct pwm_sifive_regs {
++ unsigned int cfg; /* PWM configuration register */
++ unsigned int pad0; /* Reserved */
++ unsigned int cnt; /* PWM count register */
++ unsigned int pad1; /* Reserved */
++ unsigned int pwms; /* Scaled PWM count register */
++ unsigned int pad2; /* Reserved */
++ unsigned int pad3; /* Reserved */
++ unsigned int pad4; /* Reserved */
++ unsigned int cmp0; /* PWM 0 compare register */
++ unsigned int cmp1; /* PWM 1 compare register */
++ unsigned int cmp2; /* PWM 2 compare register */
++ unsigned int cmp3; /* PWM 3 compare register */
++};
++
++#define PWM0_BASE 0x10020000
++#define PWM1_BASE 0x10021000
++#define PWM_CFG_INIT 0x1000
++#define PWM_CMP_ENABLE_VAL 0x0
++#define PWM_CMP_DISABLE_VAL 0xffff
++
++void pwm_device_init(void)
++{
++ struct pwm_sifive_regs *pwm0, *pwm1;
++ pwm0 = (struct pwm_sifive_regs *)PWM0_BASE;
++ pwm1 = (struct pwm_sifive_regs *)PWM1_BASE;
++ writel(PWM_CMP_DISABLE_VAL, (void *)&pwm0->cmp0);
++ /* Set the 3-color PWM LEDs to yellow in SPL */
++ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm0->cmp1);
++ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm0->cmp2);
++ writel(PWM_CMP_DISABLE_VAL, (void *)&pwm0->cmp3);
++ writel(PWM_CFG_INIT, (void *)&pwm0->cfg);
++
++ writel(PWM_CMP_DISABLE_VAL, (void *)&pwm0->cmp3);
++ /* Turn on all the fans, (J21), (J23) and (J24), on the unmatched board */
++ /* The SoC fan(J21) on the rev3 board cannot be controled by PWM_COMP0,
++ so here sets the initial value of PWM_COMP0 as DISABLE */
++ if (get_pcb_revision_from_eeprom() == PCB_REVISION_REV3)
++ writel(PWM_CMP_DISABLE_VAL, (void *)&pwm1->cmp1);
++ else
++ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm1->cmp1);
++ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm1->cmp2);
++ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm1->cmp3);
++ writel(PWM_CFG_INIT, (void *)&pwm1->cfg);
++}
+
+ int board_init(void)
+ {
+--
+2.7.4
+
--- /dev/null
+From d2753e049b571796bb7e9290c7740c772122a3b1 Mon Sep 17 00:00:00 2001
+From: Vincent Chen <vincent.chen@sifive.com>
+Date: Fri, 26 Mar 2021 14:10:02 +0800
+Subject: [PATCH 11/16] board: sifive: Set LED's color to purple in the U-boot
+ stage
+
+Set LED's color to purple in the U-boot stage. Because there are still
+some functions to be executed before board_early_init_f(), it means
+the LED's is not changed to purple instantly when entering the U-boot
+stage.
+---
+ board/sifive/unmatched/unmatched.c | 14 ++++++++++++++
+ configs/sifive_unmatched_defconfig | 1 +
+ 2 files changed, 15 insertions(+)
+
+diff --git a/board/sifive/unmatched/unmatched.c b/board/sifive/unmatched/unmatched.c
+index 9924da9..5183f7f 100644
+--- a/board/sifive/unmatched/unmatched.c
++++ b/board/sifive/unmatched/unmatched.c
+@@ -38,6 +38,7 @@ void pwm_device_init(void)
+ struct pwm_sifive_regs *pwm0, *pwm1;
+ pwm0 = (struct pwm_sifive_regs *)PWM0_BASE;
+ pwm1 = (struct pwm_sifive_regs *)PWM1_BASE;
++#ifdef CONFIG_SPL_BUILD
+ writel(PWM_CMP_DISABLE_VAL, (void *)&pwm0->cmp0);
+ /* Set the 3-color PWM LEDs to yellow in SPL */
+ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm0->cmp1);
+@@ -56,6 +57,19 @@ void pwm_device_init(void)
+ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm1->cmp2);
+ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm1->cmp3);
+ writel(PWM_CFG_INIT, (void *)&pwm1->cfg);
++#else
++ /* Set the 3-color PWM LEDs to purple in U-boot */
++ writel(PWM_CMP_DISABLE_VAL, (void *)&pwm0->cmp1);
++ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm0->cmp2);
++ writel(PWM_CMP_ENABLE_VAL, (void *)&pwm0->cmp3);
++#endif
++
++}
++
++int board_early_init_f(void)
++{
++ pwm_device_init();
++ return 0;
+ }
+
+ int board_init(void)
+diff --git a/configs/sifive_unmatched_defconfig b/configs/sifive_unmatched_defconfig
+index 4c26504..cf08955 100644
+--- a/configs/sifive_unmatched_defconfig
++++ b/configs/sifive_unmatched_defconfig
+@@ -40,3 +40,4 @@ CONFIG_USB=y
+ CONFIG_DM_USB=y
+ CONFIG_USB_XHCI_HCD=y
+ CONFIG_USB_XHCI_PCI=y
++CONFIG_BOARD_EARLY_INIT_F=y
+--
+2.7.4
+
--- /dev/null
+From 0c0bc1969d89e9b8425641436db706cfac57cf45 Mon Sep 17 00:00:00 2001
+From: Vincent Chen <vincent.chen@sifive.com>
+Date: Fri, 26 Mar 2021 14:07:58 +0800
+Subject: [PATCH 12/16] board: sifive: Set LED's color to blue before jumping
+ to Linux
+
+The LED's color wil be changed from purple to blue before executing
+the sysboot command. Because the sysboot command includes the image loading
+from the boot partition, It means the LED's color is blue when executing
+"Retrieving file: /Image.gz".
+---
+ include/configs/sifive-unmatched.h | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h
+index 9e1859c..fd93e89 100644
+--- a/include/configs/sifive-unmatched.h
++++ b/include/configs/sifive-unmatched.h
+@@ -73,7 +73,12 @@
+ "type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
+ "type_guid_gpt_system=" TYPE_GUID_SYSTEM "\0" \
+ "partitions=" PARTS_DEFAULT "\0" \
+- BOOTENV
++ "setled_blue=mw.l 0x10020024 0x0000ffff; mw.l 0x10020028 0x0000ffff; mw.l 0x1002002c 0x0\0" \
++ BOOTENV \
++ "boot_extlinux=" \
++ "run setled_blue; " \
++ "sysboot ${devtype} ${devnum}:${distro_bootpart} any " \
++ "${scriptaddr} ${prefix}${boot_syslinux_conf};\0"
+
+ #define CONFIG_PREBOOT \
+ "setenv fdt_addr ${fdtcontroladdr};" \
+--
+2.7.4
+
--- /dev/null
+From 6265d23e2f9fdc0e33074a28d52a894b6be2b19d Mon Sep 17 00:00:00 2001
+From: Vincent Chen <vincent.chen@sifive.com>
+Date: Mon, 17 May 2021 16:21:13 +0800
+Subject: [PATCH 13/16] board: sifive: spl: Set remote thermal of TMP451 to 85
+ deg C for the unmatched board
+
+For TMP451 on the unmatched board, the default value of the remote thermal
+threshold is 108 deg C. This commit initilizes it to 85 deg C at SPL.
+
+Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
+---
+ board/sifive/unmatched/spl.c | 29 +++++++++++++++++++++++++++++
+ drivers/misc/Kconfig | 10 ++++++++++
+ include/configs/sifive-unmatched.h | 3 +++
+ scripts/config_whitelist.txt | 1 +
+ 4 files changed, 43 insertions(+)
+
+diff --git a/board/sifive/unmatched/spl.c b/board/sifive/unmatched/spl.c
+index 3c3b22d..7d59ca0 100644
+--- a/board/sifive/unmatched/spl.c
++++ b/board/sifive/unmatched/spl.c
+@@ -10,6 +10,8 @@
+ #include <spl.h>
+ #include <misc.h>
+ #include <log.h>
++#include <config.h>
++#include <i2c.h>
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <asm/gpio.h>
+@@ -25,6 +27,27 @@
+ #define MODE_SELECT_SD 0xb
+ #define MODE_SELECT_MASK GENMASK(3, 0)
+
++#define TMP451_REMOTE_THERM_LIMIT_REG_OFFSET 0x19
++#define TMP451_RETMOE_THERM_LIMIT_INIT_VALUE 0x55
++
++static inline int init_tmp451_remote_therm_limit(void)
++{
++ struct udevice *dev;
++ unsigned char r_therm_limit = TMP451_RETMOE_THERM_LIMIT_INIT_VALUE;
++ int ret;
++
++ ret = i2c_get_chip_for_busnum(CONFIG_SYS_TMP451_BUS_NUM,
++ CONFIG_SYS_I2C_TMP451_ADDR,
++ CONFIG_SYS_I2C_TMP451_ADDR_LEN,
++ &dev);
++
++ if (!ret)
++ ret = dm_i2c_write(dev, TMP451_REMOTE_THERM_LIMIT_REG_OFFSET,
++ &r_therm_limit,
++ sizeof(unsigned char));
++ return ret;
++}
++
+ static inline int spl_reset_device_by_gpio(const char *label, int pin, int low_width)
+ {
+ int ret;
+@@ -91,6 +114,12 @@ int spl_board_init_f(void)
+
+ pwm_device_init();
+
++ ret = init_tmp451_remote_therm_limit();
++ if (ret) {
++ debug("TMP451 remote THERM limit init failed: %d\n", ret);
++ goto end;
++ }
++
+ ret = spl_gemgxl_init();
+ if (ret) {
+ debug("Gigabit ethernet PHY (VSC8541) init failed: %d\n", ret);
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 997b713..2878313 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -404,6 +404,10 @@ config SYS_I2C_EEPROM_ADDR
+ hex "Chip address of the EEPROM device"
+ default 0
+
++config SYS_I2C_TMP451_ADDR
++ hex "Chip address of the TMP451 device"
++ default 0
++
+ config SYS_I2C_EEPROM_BUS
+ int "I2C bus of the EEPROM device."
+ default 0
+@@ -429,6 +433,12 @@ config SYS_I2C_EEPROM_ADDR_LEN
+ help
+ Note: This is NOT the chip address length!
+
++config SYS_I2C_TMP451_ADDR_LEN
++ int "Length in bytes of the TMP451 memory array address"
++ default 1
++ help
++ Note: This is NOT the chip address length!
++
+ config SYS_I2C_EEPROM_ADDR_OVERFLOW
+ hex "EEPROM Address Overflow"
+ default 0
+diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h
+index fd93e89..f75cf9b 100644
+--- a/include/configs/sifive-unmatched.h
++++ b/include/configs/sifive-unmatched.h
+@@ -88,6 +88,9 @@
+ #define CONFIG_SYS_EEPROM_BUS_NUM 0
+ #define CONFIG_SYS_I2C_EEPROM_ADDR 0x54
+ #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 0x1
++#define CONFIG_SYS_TMP451_BUS_NUM 0
++#define CONFIG_SYS_I2C_TMP451_ADDR 0x4c
++#define CONFIG_SYS_I2C_TMP451_ADDR_LEN 0x1
+
+ #define CONFIG_ID_EEPROM
+
+diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
+index 3dbcc04..a0005fe 100644
+--- a/scripts/config_whitelist.txt
++++ b/scripts/config_whitelist.txt
+@@ -3550,6 +3550,7 @@ CONFIG_SYS_TIMER_COUNTER
+ CONFIG_SYS_TIMER_COUNTS_DOWN
+ CONFIG_SYS_TIMER_PRESCALER
+ CONFIG_SYS_TIMER_RATE
++CONFIG_SYS_TMP451_BUS_NUM
+ CONFIG_SYS_TMPVIRT
+ CONFIG_SYS_TMRINTR_MASK
+ CONFIG_SYS_TMRINTR_NO
+--
+2.7.4
+
--- /dev/null
+From 78cd21523e6c83d42a3e3c8bf01a84b9850b2a5f Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+Date: Wed, 14 Jul 2021 09:19:48 -0700
+Subject: [PATCH 14/16] riscv: sifive: Set default fdtfile names
+
+Set default fdtfile names for unleashed and unmatched boards, as used
+in the upstream Linux kernel. This allows sysboot command to find and
+load appropriate dtb for the matching kernel from universal stock
+Ubuntu RISC-V rootfs images based on fdtdir setting in extlinux.conf.
+
+Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
+Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
+cc: Paul Walmsley <paul.walmsley@sifive.com>
+cc: Palmer Dabbelt <palmer@dabbelt.com>
+cc: Anup Patel <anup.patel@wdc.com>
+cc: Atish Patra <atish.patra@wdc.com>
+cc: Pragnesh Patel <pragnesh.patel@sifive.com>
+cc: Green Wan <green.wan@sifive.com>
+---
+ configs/sifive_unleashed_defconfig | 1 +
+ configs/sifive_unmatched_defconfig | 1 +
+ include/configs/sifive-unleashed.h | 1 +
+ include/configs/sifive-unmatched.h | 1 +
+ 4 files changed, 4 insertions(+)
+
+diff --git a/configs/sifive_unleashed_defconfig b/configs/sifive_unleashed_defconfig
+index 5bf40ce..d665c8f 100644
+--- a/configs/sifive_unleashed_defconfig
++++ b/configs/sifive_unleashed_defconfig
+@@ -14,6 +14,7 @@ CONFIG_RISCV_SMODE=y
+ CONFIG_DISTRO_DEFAULTS=y
+ CONFIG_FIT=y
+ CONFIG_SPL_LOAD_FIT_ADDRESS=0x84000000
++CONFIG_DEFAULT_FDT_FILE="sifive/hifive-unleashed-a00.dtb"
+ CONFIG_DISPLAY_CPUINFO=y
+ CONFIG_DISPLAY_BOARDINFO=y
+ CONFIG_MISC_INIT_R=y
+diff --git a/configs/sifive_unmatched_defconfig b/configs/sifive_unmatched_defconfig
+index cf08955..bdf90ec 100644
+--- a/configs/sifive_unmatched_defconfig
++++ b/configs/sifive_unmatched_defconfig
+@@ -14,6 +14,7 @@ CONFIG_RISCV_SMODE=y
+ CONFIG_DISTRO_DEFAULTS=y
+ CONFIG_FIT=y
+ CONFIG_SPL_LOAD_FIT_ADDRESS=0x84000000
++CONFIG_DEFAULT_FDT_FILE="sifive/hifive-unmatched-a00.dtb"
+ CONFIG_DISPLAY_CPUINFO=y
+ CONFIG_DISPLAY_BOARDINFO=y
+ CONFIG_DISPLAY_BOARDINFO_LATE=y
+diff --git a/include/configs/sifive-unleashed.h b/include/configs/sifive-unleashed.h
+index 5acce36..db0ebaf 100644
+--- a/include/configs/sifive-unleashed.h
++++ b/include/configs/sifive-unleashed.h
+@@ -77,6 +77,7 @@
+ "type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
+ "type_guid_gpt_system=" TYPE_GUID_SYSTEM "\0" \
+ "partitions=" PARTS_DEFAULT "\0" \
++ "fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0" \
+ BOOTENV \
+ BOOTENV_SF
+
+diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h
+index f75cf9b..7157295 100644
+--- a/include/configs/sifive-unmatched.h
++++ b/include/configs/sifive-unmatched.h
+@@ -73,6 +73,7 @@
+ "type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
+ "type_guid_gpt_system=" TYPE_GUID_SYSTEM "\0" \
+ "partitions=" PARTS_DEFAULT "\0" \
++ "fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0" \
+ "setled_blue=mw.l 0x10020024 0x0000ffff; mw.l 0x10020028 0x0000ffff; mw.l 0x1002002c 0x0\0" \
+ BOOTENV \
+ "boot_extlinux=" \
+--
+2.7.4
+
--- /dev/null
+From 5f543ecf0d976d139de1bea274f4ea7759e4d932 Mon Sep 17 00:00:00 2001
+From: David Abdurachmanov <david.abdurachmanov@sifive.com>
+Date: Mon, 13 Sep 2021 03:15:35 -0700
+Subject: [PATCH 15/16] riscv: sifive: unmatched: leave 128MiB for ramdisk
+
+The current configuration only allows 125MiB, but the max allowed size should
+be 128MiB.
+
+Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
+---
+ include/configs/sifive-unmatched.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h
+index 7157295..7254e06 100644
+--- a/include/configs/sifive-unmatched.h
++++ b/include/configs/sifive-unmatched.h
+@@ -67,7 +67,7 @@
+ "scriptaddr=0x88100000\0" \
+ "pxefile_addr_r=0x88200000\0" \
+ "ramdisk_addr_r=0x88300000\0" \
+- "kernel_comp_addr_r=0x90000000\0" \
++ "kernel_comp_addr_r=0x90300000\0" \
+ "kernel_comp_size=0x4000000\0" \
+ "type_guid_gpt_loader1=" TYPE_GUID_LOADER1 "\0" \
+ "type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
+--
+2.7.4
+
--- /dev/null
+From 1998aacd5faef21c665fa7b4771aeb9193bfd247 Mon Sep 17 00:00:00 2001
+From: David Abdurachmanov <david.abdurachmanov@sifive.com>
+Date: Mon, 13 Sep 2021 03:22:32 -0700
+Subject: [PATCH 16/16] riscv: sifive: unmatched: disable FDT and initrd
+ relocation
+
+Same as on SiFive Unleashed we need to disable fdt and initrd relocation. Tom
+Rini mentined 18 days ago that it's most likely due to RISC-V lacking
+`arch_lmb_reserve` implementation.
+
+The patch seems to be submitted now:
+[PATCH 09/12] lmb: riscv: Add arch_lmb_reserve()
+https://lists.denx.de/pipermail/u-boot/2021-September/460333.html
+
+Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
+---
+ include/configs/sifive-unmatched.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/configs/sifive-unmatched.h b/include/configs/sifive-unmatched.h
+index 7254e06..3b72304 100644
+--- a/include/configs/sifive-unmatched.h
++++ b/include/configs/sifive-unmatched.h
+@@ -62,6 +62,8 @@
+ "name=system,size=-,bootable,type=${type_guid_gpt_system};"
+
+ #define CONFIG_EXTRA_ENV_SETTINGS \
++ "fdt_high=0xffffffffffffffff\0" \
++ "initrd_high=0xffffffffffffffff\0" \
+ "kernel_addr_r=0x84000000\0" \
+ "fdt_addr_r=0x88000000\0" \
+ "scriptaddr=0x88100000\0" \
+--
+2.7.4
+
--- /dev/null
+From 637800493945ffed2f454756300437a4ec86e3b1 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Wed, 19 Jul 2017 22:23:15 +0200
+Subject: mkimage: check environment for dtc binary location
+
+Currently mkimage assumes the dtc binary is in the path and fails
+otherwise. This patch makes it check the DTC environment variable first
+for the dtc binary and then fall back to the default path. This makes
+it possible to call the u-boot build with make DTC=... and build a fit
+image with the dtc binary not being the the default path.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Cc: Simon Glass <sjg@chromium.org>
+---
+ tools/fit_image.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/tools/fit_image.c
++++ b/tools/fit_image.c
+@@ -726,9 +726,14 @@ static int fit_handle_file(struct image_
+ }
+ *cmd = '\0';
+ } else if (params->datafile) {
++ const char* dtc = getenv("DTC");
++
++ if (!dtc)
++ dtc = MKIMAGE_DTC;
++
+ /* dtc -I dts -O dtb -p 500 -o tmpfile datafile */
+ snprintf(cmd, sizeof(cmd), "%s %s -o \"%s\" \"%s\"",
+- MKIMAGE_DTC, params->dtc, tmpfile, params->datafile);
++ dtc, params->dtc, tmpfile, params->datafile);
+ debug("Trying to execute \"%s\"\n", cmd);
+ } else {
+ snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"",
--- /dev/null
+setenv loadkernel fatload mmc 0:3 \$kernel_addr_r uImage
+setenv bootargs console=ttySIF0,115200 earlycon=sbi root=/dev/mmcblk0p4 rootwait
+setenv uenvcmd run loadkernel \&\& bootm \$kernel_addr_r
+run uenvcmd