Browse Source

board: starfive: Add StarFive Devkits board support

Add board support for StarFive Devkits.
The code is ported from tag JH7110_DVK_515_v3.9.3 of Devkits repo.

Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
Hal Feng 9 months ago
parent
commit
4d348e3fb4

+ 52 - 0
board/starfive/devkits/Kconfig

@@ -0,0 +1,52 @@
+if TARGET_STARFIVE_DEVKITS
+
+config SYS_CPU
+	default "jh7110"
+
+config SYS_BOARD
+	default "devkits"
+
+config SYS_VENDOR
+	default "starfive"
+
+config SYS_CONFIG_NAME
+	default "starfive-devkits"
+
+config ENV_SIZE
+	default 0x2000 if ENV_IS_IN_SPI_FLASH
+
+config ENV_OFFSET
+	default 0x140000 if ENV_IS_IN_SPI_FLASH
+
+config SYS_TEXT_BASE
+	default 0x40200000 if SPL
+	default 0x40000000 if !RISCV_SMODE
+	default 0x40200000 if RISCV_SMODE
+
+config SPL_TEXT_BASE
+	default 0x08000000
+
+config SPL_OPENSBI_LOAD_ADDR
+	default 0x80000000
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select STARFIVE_JH7110
+	imply CMD_DHCP
+	imply CMD_EXT2
+	imply CMD_EXT4
+	imply CMD_FAT
+	imply CMD_FS_GENERIC
+	imply CMD_GPT
+	imply PARTITION_TYPE_GUID
+	imply CMD_NET
+	imply CMD_PING
+	imply CMD_SF
+	imply DOS_PARTITION
+	imply EFI_PARTITION
+	imply IP_DYN
+	imply ISO_PARTITION
+	imply PHY_LIB
+	imply PHY_MSCC
+
+endif

+ 7 - 0
board/starfive/devkits/MAINTAINERS

@@ -0,0 +1,7 @@
+STARFIVE JH7110 DevKits BOARD
+M:	Yanhong Wang <yanhong.wang@starfivetech.com>
+S:	Maintained
+F:	arch/riscv/include/asm/arch-jh7110/
+F:	board/starfive/devkits/
+F:	include/configs/starfive-devkits.h
+F:	configs/starfive_devkits_defconfig

+ 10 - 0
board/starfive/devkits/Makefile

@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2021 Shanghai StarFive Technology Co., Ltd.
+#
+
+obj-y	:= starfive_devkits.o
+
+obj-$(CONFIG_SPL_BUILD) += spl.o
+
+obj-$(CONFIG_ID_EEPROM) += devkits-i2c-eeprom.o

+ 758 - 0
board/starfive/devkits/devkits-i2c-eeprom.c

@@ -0,0 +1,758 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
+ * Written by Wei Fu (wefu@redhat.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>
+/*
+ * 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
+
+/*
+ * Atom Types
+ * 0x0000 = invalid
+ * 0x0001 = vendor info
+ * 0x0002 = GPIO map
+ * 0x0003 = Linux device tree blob
+ * 0x0004 = manufacturer custom data
+ * 0x0005-0xfffe = reserved for future use
+ * 0xffff = invalid
+ */
+
+#define HATS_ATOM_INVALID	0x0000
+#define HATS_ATOM_VENDOR	0x0001
+#define HATS_ATOM_GPIO		0x0002
+#define HATS_ATOM_DTB		0x0003
+#define HATS_ATOM_CUSTOM	0x0004
+#define HATS_ATOM_INVALID_END	0xffff
+
+struct eeprom_hats_header {
+	char signature[MAGIC_NUMBER_BYTES];	/* ASCII table signature */
+	u8 version;		/* EEPROM data format version */
+				/* (0x00 reserved, 0x01 = first version) */
+	u8 reversed;		/* 0x00, Reserved field */
+	u16 numatoms;		/* total atoms in EEPROM */
+	u32 eeplen;		/* total length in bytes of all eeprom data */
+				/* (including this header) */
+};
+
+struct eeprom_hats_atom_header {
+	u16 type;
+	u16 count;
+	u32 dlen;
+};
+
+/**
+ * static eeprom: EEPROM layout for the StarFive platform I2C format
+ */
+struct starfive_eeprom_atom1_data {
+	u8 uuid[16];
+	u16 pid;
+	u16 pver;
+	u8 vslen;
+	u8 pslen;
+	uchar vstr[STARFIVE_EEPROM_ATOM1_VSTR_SIZE];
+	uchar pstr[STARFIVE_EEPROM_ATOM1_PSTR_SIZE]; /* product SN */
+};
+
+struct starfive_eeprom_atom1 {
+	struct eeprom_hats_atom_header header;
+	struct starfive_eeprom_atom1_data data;
+	u16 crc16;
+};
+
+struct starfive_eeprom_atom4_v1_data {
+	u16 version;
+	u8 pcb_revision;		/* PCB version */
+	u8 bom_revision;		/* BOM version */
+	u8 mac0_addr[MAC_ADDR_BYTES];	/* Ethernet0 MAC */
+	u8 mac1_addr[MAC_ADDR_BYTES];	/* Ethernet1 MAC */
+	u8 reserved[2];
+};
+
+struct starfive_eeprom_atom4_v1 {
+	struct eeprom_hats_atom_header header;
+	struct starfive_eeprom_atom4_v1_data data;
+	u16 crc16;
+};
+
+/* Set to 1 if we've read EEPROM into memory
+ * Set to -1 if EEPROM data is wrong
+ */
+static int has_been_read;
+
+/**
+ * helper struct for getting info from the local EEPROM copy.
+ * most of the items are pointers to the eeprom_wp_buff.
+ * ONLY serialnum is the u32 from the last 8 Bytes of product string
+ */
+struct starfive_eeprom_info {
+	char *vstr;		/* Vendor string in ATOM1 */
+	char *pstr;		/* product string in ATOM1 */
+	u32 serialnum;		/* serial number from in product string*/
+	u16 *version;		/* custom data version in ATOM4 */
+	u8 *pcb_revision;	/* PCB version in ATOM4 */
+	u8 *bom_revision;	/* BOM version in ATOM4 */
+	u8 *mac0_addr;		/* Ethernet0 MAC in ATOM4 */
+	u8 *mac1_addr;		/* Ethernet1 MAC in ATOM4 */
+};
+static struct starfive_eeprom_info einfo;
+
+
+static uchar eeprom_wp_buff[STARFIVE_EEPROM_HATS_SIZE_MAX];
+static struct eeprom_hats_header starfive_eeprom_hats_header_default = {
+	.signature = STARFIVE_EEPROM_HATS_SIG,
+	.version = FORMAT_VERSION,
+	.numatoms = 2,
+	.eeplen = sizeof(struct eeprom_hats_header) +
+		  sizeof(struct starfive_eeprom_atom1) +
+		  sizeof(struct starfive_eeprom_atom4_v1)
+};
+static struct starfive_eeprom_atom1 starfive_eeprom_atom1_default = {
+	.header = {
+		.type = HATS_ATOM_VENDOR,
+		.count = 1,
+		.dlen = sizeof(struct starfive_eeprom_atom1_data) + sizeof(u16)
+	},
+	.data = {
+		.uuid = {0},
+		.pid = 0,
+		.pver = 0,
+		.vslen = STARFIVE_EEPROM_ATOM1_VSTR_SIZE,
+		.pslen = STARFIVE_EEPROM_ATOM1_PSTR_SIZE,
+		.vstr = STARFIVE_EEPROM_ATOM1_VSTR,
+		.pstr = STARFIVE_EEPROM_ATOM1_PSTR
+	}
+};
+static struct starfive_eeprom_atom4_v1 starfive_eeprom_atom4_v1_default = {
+	.header = {
+		.type = HATS_ATOM_CUSTOM,
+		.count = 2,
+		.dlen = sizeof(struct starfive_eeprom_atom4_v1_data) + sizeof(u16)
+	},
+	.data = {
+		.version = FORMAT_VERSION,
+		.pcb_revision = PCB_VERSION,
+		.bom_revision = BOM_VERSION,
+		.mac0_addr = STARFIVE_DEFAULT_MAC0,
+		.mac1_addr = STARFIVE_DEFAULT_MAC1,
+		.reserved = {0}
+	}
+};
+
+//static u8 starfive_default_mac[MAC_ADDR_BYTES] = STARFIVE_DEFAULT_MAC;
+
+/**
+ * is_match_magic() - Does the magic number match that of a StarFive EEPROM?
+ *
+ * @hats:		the pointer of eeprom_hats_header
+ * Return:		status code, 0: Yes, non-0: NO
+ */
+static inline int is_match_magic(char *hats)
+{
+	return strncmp(hats, STARFIVE_EEPROM_HATS_SIG, MAGIC_NUMBER_BYTES);
+}
+
+/**
+ * calculate_crc16() - Calculate the current CRC for atom
+ * Porting from  https://github.com/raspberrypi/hats, getcrc
+ * @data:		the pointer of eeprom_hats_atom_header
+ * @size:		total length in bytes of the entire atom
+ * 			(type, count, dlen, data)
+ * Return:		result: crc16 code
+ */
+#define CRC16 0x8005
+static u16 calculate_crc16(uchar* data, unsigned int size)
+{
+	int i, j = 0x0001;
+	u16 out = 0, crc = 0;
+	int bits_read = 0, bit_flag;
+
+	/* Sanity check: */
+	if((data == NULL) || size == 0)
+		return 0;
+
+	while(size > 0) {
+		bit_flag = out >> 15;
+
+		/* Get next bit: */
+		out <<= 1;
+		// item a) work from the least significant bits
+		out |= (*data >> bits_read) & 1;
+
+		/* Increment bit counter: */
+		bits_read++;
+		if(bits_read > 7) {
+			bits_read = 0;
+			data++;
+			size--;
+		}
+
+		/* Cycle check: */
+		if(bit_flag)
+			out ^= CRC16;
+	}
+
+	// item b) "push out" the last 16 bits
+	for (i = 0; i < 16; ++i) {
+		bit_flag = out >> 15;
+		out <<= 1;
+		if(bit_flag)
+			out ^= CRC16;
+	}
+
+	// item c) reverse the bits
+	for (i = 0x8000; i != 0; i >>=1, j <<= 1) {
+		if (i & out)
+			crc |= j;
+	}
+
+	return crc;
+}
+
+/* This function should be called after each update to any EEPROM ATOM */
+static inline void update_crc(struct eeprom_hats_atom_header *atom)
+{
+	uint atom_crc_offset = sizeof(struct eeprom_hats_atom_header) +
+			       atom->dlen - sizeof(u16);
+	u16 *atom_crc_p = (void *) atom + atom_crc_offset;
+	*atom_crc_p = calculate_crc16((uchar*) atom, atom_crc_offset);
+}
+
+/**
+ * dump_raw_eeprom - display the raw contents of the EEPROM
+ */
+static void dump_raw_eeprom(u8 *e, unsigned int size)
+{
+	unsigned int i;
+
+	printf("EEPROM dump: (0x%x bytes)\n", size);
+
+	for (i = 0; i < size; i++) {
+		if (!(i % 0x10))
+			printf("%02X: ", i);
+
+		printf("%02X ", e[i]);
+
+		if (((i % 16) == 15) || (i == size - 1))
+			printf("\n");
+	}
+
+	return;
+}
+
+static int hats_atom_crc_check(struct eeprom_hats_atom_header *atom)
+{
+	u16 atom_crc, data_crc;
+	uint atom_crc_offset = sizeof(struct eeprom_hats_atom_header) +
+			       atom->dlen - sizeof(atom_crc);
+	u16 *atom_crc_p = (void *) atom + atom_crc_offset;
+
+	atom_crc = *atom_crc_p;
+	data_crc = calculate_crc16((uchar *) atom, atom_crc_offset);
+	if (atom_crc == data_crc)
+		return 0;
+
+	printf("EEPROM HATs: CRC ERROR in atom %x type %x, (%x!=%x)\n",
+		atom->count, atom->type, atom_crc, data_crc);
+	return -1;
+}
+
+static void *hats_get_atom(struct eeprom_hats_header *header, u16 type)
+ {
+	struct eeprom_hats_atom_header *atom;
+	void *hats_eeprom_max = (void *)header + header->eeplen;
+	void *temp = (void *)header + sizeof(struct eeprom_hats_header);
+
+	for (int numatoms = (int)header->numatoms; numatoms > 0; numatoms--) {
+		atom = (struct eeprom_hats_atom_header *)temp;
+		if (hats_atom_crc_check(atom))
+			return NULL;
+		if (atom->type == type)
+			return (void *)atom;
+		/* go to next atom */
+		temp = (void *)atom + sizeof(struct eeprom_hats_atom_header) +
+		       atom->dlen;
+		if (temp > hats_eeprom_max) {
+			printf("EEPROM HATs: table overflow next@%p, max@%p\n",
+				temp, hats_eeprom_max);
+			break;
+		}
+	}
+
+	/* fail to get atom */
+	return NULL;
+}
+
+/**
+ * show_eeprom - display the contents of the EEPROM
+ */
+static void show_eeprom(struct starfive_eeprom_info *einfo)
+{
+	if (has_been_read != 1)
+		return;
+
+	printf("\n--------EEPROM INFO--------\n");
+	printf("Vendor : %s\n", einfo->vstr);
+	printf("Product full SN: %s\n", einfo->pstr);
+	printf("data version: 0x%x\n", *einfo->version);
+	if (1 == *einfo->version) {
+		printf("PCB revision: 0x%x\n", *einfo->pcb_revision);
+		printf("BOM revision: %c\n", *einfo->bom_revision);
+		printf("Ethernet MAC0 address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       einfo->mac0_addr[0], einfo->mac0_addr[1],
+		       einfo->mac0_addr[2], einfo->mac0_addr[3],
+		       einfo->mac0_addr[4], einfo->mac0_addr[5]);
+		printf("Ethernet MAC1 address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       einfo->mac1_addr[0], einfo->mac1_addr[1],
+		       einfo->mac1_addr[2], einfo->mac1_addr[3],
+		       einfo->mac1_addr[4], einfo->mac1_addr[5]);
+	} else {
+		printf("Custom data v%d is not Supported\n", *einfo->version);
+	}
+	printf("--------EEPROM INFO--------\n\n");
+}
+
+/**
+ * parse_eeprom_info - parse the contents of the EEPROM
+ * If everthing gose right,
+ * 1, set has_been_read to 1
+ * 2, display info
+ *
+ * If anything goes wrong,
+ * 1, set has_been_read to -1
+ * 2, dump data by hex for debug
+ *
+ * @buf:		the pointer of eeprom_hats_header in memory
+ * Return:		status code, 0: Success, non-0: Fail
+ *
+ */
+static int parse_eeprom_info(struct eeprom_hats_header *buf)
+{
+	struct eeprom_hats_atom_header *atom;
+	void *atom_data;
+	struct starfive_eeprom_atom1_data *atom1 = NULL;
+	struct starfive_eeprom_atom4_v1_data *atom4_v1 = NULL;
+
+	if (is_match_magic((char *)buf)) {
+		printf("Not a StarFive EEPROM data format - magic error\n");
+		goto error;
+	};
+
+	printf("StarFive EEPROM format v%u\n", buf->version);
+
+	// parse atom1(verdor)
+	atom = (struct eeprom_hats_atom_header *)
+		hats_get_atom(buf, HATS_ATOM_VENDOR);
+	if (atom) {
+		atom_data = (void *)atom +
+			    sizeof(struct eeprom_hats_atom_header);
+		atom1 = (struct starfive_eeprom_atom1_data *)atom_data;
+		einfo.vstr = atom1->vstr;
+		einfo.pstr = atom1->pstr;
+		einfo.serialnum = (u32)hextoul((void *)atom1->pstr +
+					STARFIVE_EEPROM_ATOM1_SN_OFFSET,
+					NULL);
+	} else  {
+		printf("fail to get vendor atom\n");
+		goto error;
+	};
+
+	// parse atom4(custom)
+	atom = (struct eeprom_hats_atom_header *)
+		hats_get_atom(buf, HATS_ATOM_CUSTOM);
+	if (atom) {
+		atom_data = (void *)atom +
+			    sizeof(struct eeprom_hats_atom_header);
+		atom4_v1 = (struct starfive_eeprom_atom4_v1_data *)atom_data;
+		einfo.version = &atom4_v1->version;
+		if (*einfo.version == 1) {
+			einfo.pcb_revision = &atom4_v1->pcb_revision;
+			einfo.bom_revision = &atom4_v1->bom_revision;
+			einfo.mac0_addr =  atom4_v1->mac0_addr;
+			einfo.mac1_addr =  atom4_v1->mac1_addr;
+		}
+	} else  {
+		printf("fail to get custom data atom\n");
+		goto error;
+	};
+
+	// everthing gose right
+	has_been_read = 1;
+	show_eeprom(&einfo);
+	return 0;
+
+error:
+	has_been_read = -1;
+	dump_raw_eeprom(eeprom_wp_buff,
+			STARFIVE_EEPROM_HATS_SIZE_MAX);
+	return -1;
+}
+
+/**
+ * read_eeprom() - read the EEPROM into memory, if it hasn't been read yet
+ * @buf:		the pointer of eeprom data buff
+ * Return:		status code, 0: Success, non-0: Fail
+ * Note: depend on	CONFIG_SYS_EEPROM_BUS_NUM
+ * 			CONFIG_SYS_I2C_EEPROM_ADDR
+ * 			STARFIVE_EEPROM_WP_OFFSET
+ * 			STARFIVE_EEPROM_HATS_SIZE_MAX
+ */
+static int read_eeprom(uint8_t *buf)
+{
+	int ret;
+	struct udevice *dev;
+
+	if (has_been_read == 1)
+		return 0;
+
+	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, STARFIVE_EEPROM_WP_OFFSET,
+				  buf, STARFIVE_EEPROM_HATS_SIZE_MAX);
+	}
+
+	if (ret) {
+		printf("fail to read EEPROM.\n");
+		return ret;
+	}
+
+	return parse_eeprom_info((struct eeprom_hats_header *)buf);
+}
+
+/**
+ * prog_eeprom() - write the EEPROM from memory
+ */
+static int prog_eeprom(uint8_t *buf, unsigned int size)
+{
+	unsigned int i;
+	void *p;
+	uchar tmp_buff[STARFIVE_EEPROM_HATS_SIZE_MAX];
+	struct udevice *dev;
+	int ret = i2c_get_chip_for_busnum(CONFIG_SYS_EEPROM_BUS_NUM,
+					  CONFIG_SYS_I2C_EEPROM_ADDR,
+					  CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
+					  &dev);
+
+	if (is_match_magic(buf)) {
+		printf("MAGIC ERROR, Please check the data@%p.\n", buf);
+		return -1;
+	}
+
+	for (i = 0, p = buf; i < size;
+	     i += BYTES_PER_EEPROM_PAGE, p += BYTES_PER_EEPROM_PAGE) {
+		if (!ret)
+			ret = dm_i2c_write(dev,
+					   i + STARFIVE_EEPROM_WP_OFFSET,
+					   p, min((int)(size - 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 */
+		ret = dm_i2c_read(dev,
+				  STARFIVE_EEPROM_WP_OFFSET,
+				  tmp_buff,
+				  STARFIVE_EEPROM_HATS_SIZE_MAX);
+		if (!ret && memcmp((void *)buf, (void *)tmp_buff,
+				   STARFIVE_EEPROM_HATS_SIZE_MAX))
+			ret = -1;
+	}
+
+	if (ret) {
+		has_been_read = -1;
+		printf("Programming failed.Temp buff:\n");
+		dump_raw_eeprom(tmp_buff,
+				STARFIVE_EEPROM_HATS_SIZE_MAX);
+		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, int index)
+{
+	unsigned int i;
+	struct eeprom_hats_atom_header *atom4;
+	atom4 = (struct eeprom_hats_atom_header *)
+		hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
+			      HATS_ATOM_CUSTOM);
+
+	if (strncasecmp(STARFIVE_OUI_PREFIX, string,
+			strlen(STARFIVE_OUI_PREFIX))) {
+		printf("The MAC address doesn't match StarFive OUI %s\n",
+		       STARFIVE_OUI_PREFIX);
+		return;
+	}
+
+	for (i = 0; *string && (i < MAC_ADDR_BYTES); i++) {
+		if (index == 0) {
+			einfo.mac0_addr[i] = hextoul(string, &string);
+		} else {
+			einfo.mac1_addr[i] = hextoul(string, &string);
+		}
+		if (*string == ':')
+			string++;
+	}
+
+	update_crc(atom4);
+}
+
+/**
+ * set_pcb_revision() - stores a StarFive 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)
+{
+	u8 p;
+	uint base = 16;
+	struct eeprom_hats_atom_header *atom4;
+	atom4 = (struct eeprom_hats_atom_header *)
+		hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
+			      HATS_ATOM_CUSTOM);
+
+	p = (u8)simple_strtoul(string, NULL, base);
+	if (p > U8_MAX) {
+		printf("%s must not be greater than %d\n", "PCB revision",
+		       U8_MAX);
+		return;
+	}
+
+	*einfo.pcb_revision = p;
+
+	update_crc(atom4);
+}
+
+/**
+ * set_bom_revision() - stores a StarFive 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)
+{
+	struct eeprom_hats_atom_header *atom4;
+	atom4 = (struct eeprom_hats_atom_header *)
+		hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
+			      HATS_ATOM_CUSTOM);
+
+	if (string[0] < 'A' || string[0] > 'Z') {
+		printf("BOM revision must be an uppercase letter between A and Z\n");
+		return;
+	}
+
+	*einfo.bom_revision = string[0];
+
+	update_crc(atom4);
+}
+
+/**
+ * set_product_id() - stores a StarFive product ID into the local EEPROM copy
+ *
+ * Takes a pointer to a string representing the numeric product ID  in
+ * string ("DK7110B1-2150-D104EC32-00000001\0"), stores it in the product string
+ * field of the EEPROM local copy, and updates the CRC of the local copy.
+ */
+static void set_product_id(char *string)
+{
+	struct eeprom_hats_atom_header *atom1;
+	atom1 = (struct eeprom_hats_atom_header *)
+		hats_get_atom((struct eeprom_hats_header *)eeprom_wp_buff,
+			      HATS_ATOM_VENDOR);
+
+	memcpy((void *)einfo.pstr, (void *)string,
+		STARFIVE_EEPROM_ATOM1_PSTR_SIZE);
+
+	update_crc(atom1);
+}
+
+/**
+ * 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(uchar *buff)
+{
+	struct eeprom_hats_header *hats = (struct eeprom_hats_header *)buff;
+	struct eeprom_hats_atom_header *atom1 = (void *)hats +
+					sizeof(struct eeprom_hats_header);
+	struct eeprom_hats_atom_header *atom4_v1 = (void *)atom1 +
+					sizeof(struct starfive_eeprom_atom1);
+
+	memcpy((void *)hats, (void *)&starfive_eeprom_hats_header_default,
+	       sizeof(struct eeprom_hats_header));
+	memcpy((void *)atom1, (void *)&starfive_eeprom_atom1_default,
+	       sizeof(struct starfive_eeprom_atom1));
+	memcpy((void *)atom4_v1, (void *)&starfive_eeprom_atom4_v1_default,
+	       sizeof(struct starfive_eeprom_atom4_v1));
+
+	update_crc(atom1);
+	update_crc(atom4_v1);
+}
+
+static int print_usage(void)
+{
+	printf("display and program the system ID and MAC addresses in EEPROM\n"
+	"[read_eeprom|initialize|write_eeprom|mac_address|pcb_revision|bom_revision|product_id]\n"
+	"mac read_eeprom\n"
+	"    - read EEPROM content into memory data structure\n"
+	"mac write_eeprom\n"
+	"    - save memory data structure to the EEPROM\n"
+	"mac initialize\n"
+	"    - initialize the in-memory EEPROM copy with default data\n"
+	"mac mac0_address <xx:xx:xx:xx:xx:xx>\n"
+	"    - stores a MAC0 address into the local EEPROM copy\n"
+	"mac mac1_address <xx:xx:xx:xx:xx:xx>\n"
+	"    - stores a MAC1 address into the local EEPROM copy\n"
+	"mac pcb_revision <?>\n"
+	"    - stores a StarFive PCB revision into the local EEPROM copy\n"
+	"mac bom_revision <A>\n"
+	"    - stores a StarFive BOM revision into the local EEPROM copy\n"
+	"mac product_id <DK7110B1-2150-D104EC32-xxxxxxxx>\n"
+	"    - stores a StarFive product ID into the local EEPROM copy\n");
+	return 0;
+}
+
+int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	char *cmd;
+
+	if (argc == 1) {
+		show_eeprom(&einfo);
+		return 0;
+	}
+
+	if (argc > 3)
+		return print_usage();
+
+	cmd = argv[1];
+
+	/* Commands with no argument */
+	if (!strcmp(cmd, "read_eeprom")) {
+		has_been_read = 0;
+		return read_eeprom(eeprom_wp_buff);
+	} else if (!strcmp(cmd, "initialize")) {
+		init_local_copy(eeprom_wp_buff);
+		return 0;
+	} else if (!strcmp(cmd, "write_eeprom")) {
+		return prog_eeprom(eeprom_wp_buff,
+				   STARFIVE_EEPROM_HATS_SIZE_MAX);
+	}
+
+	if (argc != 3)
+		return print_usage();
+
+	if (is_match_magic(eeprom_wp_buff)) {
+		printf("Please read the EEPROM ('read_eeprom') and/or initialize the EEPROM ('initialize') first.\n");
+		return 0;
+	}
+
+	if (!strcmp(cmd, "mac0_address")) {
+		set_mac_address(argv[2], 0);
+		return 0;
+	} else if (!strcmp(cmd, "mac1_address")) {
+		set_mac_address(argv[2], 1);
+		return 0;
+	} else if (!strcmp(cmd, "pcb_revision")) {
+		set_pcb_revision(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 print_usage();
+}
+
+/**
+ * mac_read_from_eeprom() - read the MAC address & the serial number in EEPROM
+ *
+ * This function reads the MAC address and the serial number 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.
+ *
+ * If CONFIG_ID_EEPROM is enabled, this function will be called in
+ * "static init_fnc_t init_sequence_r[]" of u-boot/common/board_r.c.
+ */
+int mac_read_from_eeprom(void)
+{
+	/**
+	 * try to fill the buff from EEPROM,
+	 * always return SUCCESS, even some error happens.
+	 */
+	if (read_eeprom(eeprom_wp_buff))
+		return 0;
+
+	// 1, setup ethaddr env
+	eth_env_set_enetaddr("eth0addr", einfo.mac0_addr);
+	eth_env_set_enetaddr("eth1addr", einfo.mac1_addr);
+
+	/**
+	 * 2, setup serial# env, reference to hifive-platform-i2c-eeprom.c,
+	 * serial# can be a ASCII string, but not just a hex number, so we
+	 * setup serial# in the 32Byte format:
+	 * "DK7110B1-2150-D104EC32-00000001\0;"
+	 * "<product>-<date>-<DDR&eMMC>-<serial_number>"
+	 * <date>: 4Byte, should be the output of `date +%y%W`
+	 * <DDR&eMMC>: 8Byte, "D008" means 8GB, "D01T" means 1TB;
+	 *     "E000" means no eMMC,"E032" means 32GB, "E01T" means 1TB.
+	 * <serial_number>: 8Byte, the Unique Identifier of board in hex.
+	 */
+	if (!env_get("serial#"))
+		env_set("serial#", einfo.pstr);
+
+	return 0;
+}
+

+ 166 - 0
board/starfive/devkits/spl.c

@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
+ * Author:	yanhong <yanhong.wang@starfivetech.com>
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/arch/spl.h>
+#include <asm/io.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/jh7110-regs.h>
+#include <asm/arch/clk.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+
+#define MODE_SELECT_REG		0x1702002c
+
+int spl_board_init_f(void)
+{
+	int ret;
+
+	ret = spl_soc_init();
+	if (ret) {
+		debug("JH7110 SPL init failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+u32 spl_boot_device(void)
+{
+	int boot_mode = 0;
+
+	boot_mode = readl((const volatile void *)MODE_SELECT_REG) & 0x3;
+	switch (boot_mode) {
+	case 0:
+		return BOOT_DEVICE_SPI;
+	case 1:
+		return BOOT_DEVICE_MMC2;
+	case 2:
+		return BOOT_DEVICE_MMC1;
+	case 3:
+		return BOOT_DEVICE_UART;
+	default:
+		debug("Unsupported boot device 0x%x.\n",
+		      boot_mode);
+		return BOOT_DEVICE_NONE;
+	}
+}
+
+struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+{
+	return (struct image_header *)(STARFIVE_SPL_BOOT_LOAD_ADDR);
+}
+
+void board_init_f(ulong dummy)
+{
+	int ret;
+
+	/* Adjust cpu frequency, the default is 1.0GHz */
+	starfive_jh7110_pll_set_rate(PLL0, 1000000000);
+
+	/*change pll2 to 1188MHz*/
+	starfive_jh7110_pll_set_rate(PLL2, 1188000000);
+
+	/*DDR control depend clk init*/
+	clrsetbits_le32(SYS_CRG_BASE, CLK_CPU_ROOT_SW_MASK,
+		BIT(CLK_CPU_ROOT_SW_SHIFT) & CLK_CPU_ROOT_SW_MASK);
+
+	clrsetbits_le32(SYS_CRG_BASE + CLK_BUS_ROOT_OFFSET,
+		CLK_BUS_ROOT_SW_MASK,
+		BIT(CLK_BUS_ROOT_SW_SHIFT) & CLK_BUS_ROOT_SW_MASK);
+
+	/*Set clk_perh_root clk default mux sel to pll2*/
+	clrsetbits_le32(SYS_CRG_BASE + CLK_PERH_ROOT_OFFSET,
+		CLK_PERH_ROOT_MASK,
+		BIT(CLK_PERH_ROOT_SHIFT) & CLK_PERH_ROOT_MASK);
+
+	clrsetbits_le32(SYS_CRG_BASE + CLK_NOC_BUS_STG_AXI_OFFSET,
+		CLK_NOC_BUS_STG_AXI_EN_MASK,
+		BIT(CLK_NOC_BUS_STG_AXI_EN_SHIFT)
+		& CLK_NOC_BUS_STG_AXI_EN_MASK);
+
+	clrsetbits_le32(AON_CRG_BASE + CLK_AON_APB_FUNC_OFFSET,
+		CLK_AON_APB_FUNC_SW_MASK,
+		BIT(CLK_AON_APB_FUNC_SW_SHIFT) & CLK_AON_APB_FUNC_SW_MASK);
+
+	/* switch qspi clk to pll0 */
+	clrsetbits_le32(SYS_CRG_BASE + CLK_QSPI_REF_OFFSET,
+			CLK_QSPI_REF_SW_MASK,
+			BIT(CLK_QSPI_REF_SW_SHIFT) & CLK_QSPI_REF_SW_MASK);
+
+	/*set GPIO to 3.3v*/
+	setbits_le32(SYS_SYSCON_BASE + 0xC, 0x0);
+
+	/* Improved GMAC0 TX I/O PAD capability */
+	clrsetbits_le32(AON_IOMUX_BASE + 0x78, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(AON_IOMUX_BASE + 0x7c, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(AON_IOMUX_BASE + 0x80, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(AON_IOMUX_BASE + 0x84, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(AON_IOMUX_BASE + 0x88, 0x3, BIT(0) & 0x3);
+
+	/* Improved GMAC1 TX I/O PAD capability */
+	clrsetbits_le32(SYS_IOMUX_BASE + 0x26c, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(SYS_IOMUX_BASE + 0x270, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(SYS_IOMUX_BASE + 0x274, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(SYS_IOMUX_BASE + 0x278, 0x3, BIT(0) & 0x3);
+	clrsetbits_le32(SYS_IOMUX_BASE + 0x27c, 0x3, BIT(0) & 0x3);
+
+	SYS_IOMUX_DOEN(62, LOW);
+	SYS_IOMUX_DOUT(62, 19);
+	SYS_IOMUX_SET_DS(64, 2);
+	SYS_IOMUX_SET_SLEW(64, 1);
+	SYS_IOMUX_SET_DS(65, 1);
+	SYS_IOMUX_SET_DS(66, 1);
+	SYS_IOMUX_SET_DS(67, 1);
+	SYS_IOMUX_SET_DS(68, 1);
+	SYS_IOMUX_SET_DS(69, 1);
+	SYS_IOMUX_SET_DS(70, 1);
+	SYS_IOMUX_SET_DS(71, 1);
+	SYS_IOMUX_SET_DS(72, 1);
+	SYS_IOMUX_SET_DS(73, 1);
+
+	SYS_IOMUX_DOEN(10, LOW);
+	SYS_IOMUX_DOUT(10, 55);
+	SYS_IOMUX_SET_SLEW(10, 1);
+	SYS_IOMUX_SET_DS(10, 2);
+	SYS_IOMUX_COMPLEX(9, 44, 57, 19);
+	SYS_IOMUX_SET_DS(9, 1);
+	SYS_IOMUX_COMPLEX(11, 45, 58, 20);
+	SYS_IOMUX_SET_DS(11, 1);
+	SYS_IOMUX_COMPLEX(12, 46, 59, 21);
+	SYS_IOMUX_SET_DS(12, 1);
+	SYS_IOMUX_COMPLEX(7, 47, 60, 22);
+	SYS_IOMUX_SET_DS(7, 1);
+	SYS_IOMUX_COMPLEX(8, 48, 61, 23);
+	SYS_IOMUX_SET_DS(8, 1);
+
+	ret = spl_early_init();
+	if (ret)
+		panic("spl_early_init() failed: %d\n", ret);
+
+	arch_cpu_init_dm();
+
+	preloader_console_init();
+
+	ret = spl_board_init_f();
+	if (ret) {
+		debug("spl_board_init_f init failed: %d\n", ret);
+		return;
+	}
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+	/* boot using first FIT config */
+	return 0;
+}
+#endif
+
+

+ 482 - 0
board/starfive/devkits/starfive_devkits.c

@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
+ * Author:	yanhong <yanhong.wang@starfivetech.com>
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/jh7110-regs.h>
+#include <asm/gpio.h>
+#include <cpu_func.h>
+#include <dm/uclass.h>
+#include <dm/device.h>
+#include <env.h>
+#include <i2c.h>
+#include <inttypes.h>
+#include <misc.h>
+#include <linux/bitops.h>
+#include <asm/arch/gpio.h>
+#include <bmp_logo.h>
+#include <video.h>
+#include <splash.h>
+#include <asm/gpio.h>
+#include <linux/err.h>
+
+
+#define SYS_CLOCK_ENABLE(clk) \
+	setbits_le32(SYS_CRG_BASE + clk, CLK_ENABLE_MASK)
+
+#define CPU_VOL_BINNING_OFFSET 0x7fc
+enum {
+	BOOT_FLASH =	0,
+	BOOT_SD,
+	BOOT_EMMC,
+	BOOT_UART,
+};
+enum cpu_voltage_type_t {
+	CPU_VOL_1020 = 0xef0,
+	CPU_VOL_1040 = 0xfff,
+	CPU_VOL_1060 = 0xff0,
+	CPU_VOL_1000  = 0x8f0,
+};
+#define CPU_VOL_MASK	0xfff
+
+static void sys_reset_clear(ulong assert, ulong status, u32 rst)
+{
+	u32 value;
+
+	clrbits_le32(SYS_CRG_BASE + assert, BIT(rst));
+	do {
+		value = in_le32(SYS_CRG_BASE + status);
+	} while ((value & BIT(rst)) != BIT(rst));
+}
+
+static void jh7110_timer_init(void)
+{
+	SYS_CLOCK_ENABLE(TIMER_CLK_APB_SHIFT);
+	SYS_CLOCK_ENABLE(TIMER_CLK_TIMER0_SHIFT);
+	SYS_CLOCK_ENABLE(TIMER_CLK_TIMER1_SHIFT);
+	SYS_CLOCK_ENABLE(TIMER_CLK_TIMER2_SHIFT);
+	SYS_CLOCK_ENABLE(TIMER_CLK_TIMER3_SHIFT);
+
+	sys_reset_clear(SYS_CRG_RESET_ASSERT3_SHIFT,
+			SYS_CRG_RESET_STATUS3_SHIFT, TIMER_RSTN_APB_SHIFT);
+	sys_reset_clear(SYS_CRG_RESET_ASSERT3_SHIFT,
+			SYS_CRG_RESET_STATUS3_SHIFT, TIMER_RSTN_TIMER0_SHIFT);
+	sys_reset_clear(SYS_CRG_RESET_ASSERT3_SHIFT,
+			SYS_CRG_RESET_STATUS3_SHIFT, TIMER_RSTN_TIMER1_SHIFT);
+	sys_reset_clear(SYS_CRG_RESET_ASSERT3_SHIFT,
+			SYS_CRG_RESET_STATUS3_SHIFT, TIMER_RSTN_TIMER2_SHIFT);
+	sys_reset_clear(SYS_CRG_RESET_ASSERT3_SHIFT,
+			SYS_CRG_RESET_STATUS3_SHIFT, TIMER_RSTN_TIMER3_SHIFT);
+}
+
+static void jh7110_i2c_init (int id)
+{
+	switch (id) {
+	case 5:
+		//scl
+		SYS_IOMUX_COMPLEX(19, 79, 0, 42);
+		//sda
+		SYS_IOMUX_COMPLEX(20, 80, 0, 43);
+
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void jh7110_gmac_sel_tx_to_rgmii(int id)
+{
+	switch (id) {
+	case 0:
+		clrsetbits_le32(AON_CRG_BASE + GMAC5_0_CLK_TX_SHIFT,
+		GMAC5_0_CLK_TX_MASK,
+		BIT(GMAC5_0_CLK_TX_BIT) & GMAC5_0_CLK_TX_MASK);
+		break;
+	case 1:
+		clrsetbits_le32(SYS_CRG_BASE + GMAC5_1_CLK_TX_SHIFT,
+		GMAC5_1_CLK_TX_MASK,
+		BIT(GMAC5_1_CLK_TX_BIT) & GMAC5_1_CLK_TX_MASK);
+		break;
+	default:
+		break;
+	}
+}
+
+static void jh7110_gmac_io_pad(int id)
+{
+	u32 cap = BIT(0); /* 2.5V */
+
+	switch (id) {
+	case 0:
+		/* Improved GMAC0 TX I/O PAD capability */
+		clrsetbits_le32(AON_IOMUX_BASE + 0x78, 0x3, cap & 0x3);
+		clrsetbits_le32(AON_IOMUX_BASE + 0x7c, 0x3, cap & 0x3);
+		clrsetbits_le32(AON_IOMUX_BASE + 0x80, 0x3, cap & 0x3);
+		clrsetbits_le32(AON_IOMUX_BASE + 0x84, 0x3, cap & 0x3);
+		clrsetbits_le32(AON_IOMUX_BASE + 0x88, 0x3, cap & 0x3);
+		break;
+	case 1:
+		/* Improved GMAC1 TX I/O PAD capability */
+		clrsetbits_le32(SYS_IOMUX_BASE + 0x26c, 0x3, cap & 0x3);
+		clrsetbits_le32(SYS_IOMUX_BASE + 0x270, 0x3, cap & 0x3);
+		clrsetbits_le32(SYS_IOMUX_BASE + 0x274, 0x3, cap & 0x3);
+		clrsetbits_le32(SYS_IOMUX_BASE + 0x278, 0x3, cap & 0x3);
+		clrsetbits_le32(SYS_IOMUX_BASE + 0x27c, 0x3, cap & 0x3);
+		break;
+	}
+}
+
+static void jh7110_gmac_init(int id)
+{
+	jh7110_gmac_sel_tx_to_rgmii(id);
+	jh7110_gmac_io_pad(id);
+}
+
+static void jh7110_usb_init(bool usb2_enable)
+{
+	if (usb2_enable) {
+		/*usb 2.0 utmi phy init*/
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_4,
+			USB_MODE_STRAP_MASK,
+			(2<<USB_MODE_STRAP_SHIFT) &
+			USB_MODE_STRAP_MASK);/*2:host mode, 4:device mode*/
+		clrsetbits_le32(STG_SYSCON_BASE + STG_SYSCON_4,
+			USB_OTG_SUSPENDM_BYPS_MASK,
+			BIT(USB_OTG_SUSPENDM_BYPS_SHIFT)
+			& USB_OTG_SUSPENDM_BYPS_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE + STG_SYSCON_4,
+			USB_OTG_SUSPENDM_MASK,
+			BIT(USB_OTG_SUSPENDM_SHIFT) &
+			USB_OTG_SUSPENDM_MASK);/*HOST = 1. DEVICE = 0;*/
+		clrsetbits_le32(STG_SYSCON_BASE + STG_SYSCON_4,
+			USB_PLL_EN_MASK,
+			BIT(USB_PLL_EN_SHIFT) & USB_PLL_EN_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE + STG_SYSCON_4,
+			USB_REFCLK_MODE_MASK,
+			BIT(USB_REFCLK_MODE_SHIFT) & USB_REFCLK_MODE_MASK);
+		/* usb 2.0 phy mode,REPLACE USB3.0 PHY module = 1;else = 0*/
+		clrsetbits_le32(SYS_SYSCON_BASE + SYS_SYSCON_24,
+			PDRSTN_SPLIT_MASK,
+			BIT(PDRSTN_SPLIT_SHIFT) &
+			PDRSTN_SPLIT_MASK);
+	} else {
+		/*usb 3.0 pipe phy config*/
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_196,
+			PCIE_CKREF_SRC_MASK,
+			(0<<PCIE_CKREF_SRC_SHIFT) & PCIE_CKREF_SRC_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_196,
+			PCIE_CLK_SEL_MASK,
+			(0<<PCIE_CLK_SEL_SHIFT) & PCIE_CLK_SEL_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_328,
+			PCIE_PHY_MODE_MASK,
+			BIT(PCIE_PHY_MODE_SHIFT) & PCIE_PHY_MODE_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_500,
+			PCIE_USB3_BUS_WIDTH_MASK,
+			(0 << PCIE_USB3_BUS_WIDTH_SHIFT) &
+			PCIE_USB3_BUS_WIDTH_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_500,
+			PCIE_USB3_RATE_MASK,
+			(0 << PCIE_USB3_RATE_SHIFT) & PCIE_USB3_RATE_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_500,
+			PCIE_USB3_RX_STANDBY_MASK,
+			(0 << PCIE_USB3_RX_STANDBY_SHIFT)
+			& PCIE_USB3_RX_STANDBY_MASK);
+		clrsetbits_le32(STG_SYSCON_BASE  + STG_SYSCON_500,
+			PCIE_USB3_PHY_ENABLE_MASK,
+			BIT(PCIE_USB3_PHY_ENABLE_SHIFT)
+			& PCIE_USB3_PHY_ENABLE_MASK);
+
+		/* usb 3.0 phy mode,REPLACE USB3.0 PHY module = 1;else = 0*/
+		clrsetbits_le32(SYS_SYSCON_BASE + SYS_SYSCON_24,
+			PDRSTN_SPLIT_MASK,
+			(0 << PDRSTN_SPLIT_SHIFT) & PDRSTN_SPLIT_MASK);
+	}
+}
+
+#if CONFIG_IS_ENABLED(STARFIVE_OTP)
+static void get_cpu_voltage_type(struct udevice *dev)
+{
+	int ret;
+	u32 buf = CPU_VOL_1040;
+
+	ret = misc_read(dev, CPU_VOL_BINNING_OFFSET, &buf, sizeof(buf));
+	if (ret != sizeof(buf))
+		printf("%s: error reading CPU vol from OTP\n", __func__);
+	else {
+		switch ((buf & CPU_VOL_MASK)) {
+		case CPU_VOL_1000:
+			env_set("cpu_max_vol", "1000000");
+			break;
+		case CPU_VOL_1060:
+			env_set("cpu_max_vol", "1060000");
+			break;
+		case CPU_VOL_1020:
+			env_set("cpu_max_vol", "1020000");
+			break;
+		default:
+			env_set("cpu_max_vol", "1040000");
+			break;
+		}
+	}
+}
+#endif
+
+static void get_boot_mode(void)
+{
+	u32 value;
+
+	value = in_le32(AON_IOMUX_BASE + AON_GPIO_DIN_REG);
+	switch (value & 0x03) {
+		case BOOT_FLASH:
+			env_set("bootmode", "flash");
+			env_set("devnum", "1");
+			break;
+
+		case BOOT_SD:
+			env_set("bootmode", "sd");
+			env_set("devnum", "1");
+			break;
+
+		case BOOT_EMMC:
+			env_set("bootmode", "emmc");
+			env_set("devnum", "0");
+			break;
+
+		default:
+			env_set("bootmode", "uart");
+			env_set("devnum", "1");
+			break;
+	}
+}
+
+#define CONFIG_SYS_PMIC_BUS_NUM			5
+#define CONFIG_SYS_I2C_PMIC_ADDR		0x36
+#define CONFIG_SYS_I2C_PMIC_ADDR_LEN		1
+#define AXP15060_DCDC_MODE_CTRL_2		0x1b
+#define AXP15060_DCDC5_MODE_BIT			BIT(4)
+#define AXP15060_PWR_SEQUENCE_CTRL		0X32
+#define AXP15060_RST_PMIC_BY_PWROK_BIT		BIT(4)
+
+int set_pmic(void)
+{
+	int ret;
+	struct udevice *dev;
+	u8 temp_buf;
+
+	ret = i2c_get_chip_for_busnum(CONFIG_SYS_PMIC_BUS_NUM,
+				      CONFIG_SYS_I2C_PMIC_ADDR,
+				      CONFIG_SYS_I2C_PMIC_ADDR_LEN,
+				      &dev);
+
+	if (!ret) {
+		/* Set Pmic DCDC5 Mode as PWM */
+		ret = dm_i2c_read(dev,
+				  AXP15060_DCDC_MODE_CTRL_2,
+				  &temp_buf,
+				  sizeof(temp_buf));
+		if (ret)
+			printf("%s: can't read pmic dcdc5 mode register\n",
+                                 __func__);
+
+		temp_buf = temp_buf | AXP15060_DCDC5_MODE_BIT;
+		ret = dm_i2c_write(dev,
+				AXP15060_DCDC_MODE_CTRL_2,
+				&temp_buf,
+				sizeof(temp_buf));
+		if (ret)
+			printf("%s: can't write pmic dcdc5 mode register\n",
+                                 __func__);
+
+		/* Enable PWROK in PMIC */
+		ret = dm_i2c_read(dev,
+				  AXP15060_PWR_SEQUENCE_CTRL,
+				  &temp_buf,
+				  sizeof(temp_buf));
+		if (ret)
+                        printf("%s: can't read pmic power disbale & down sequence register\n",
+                                 __func__);
+
+		temp_buf = temp_buf | AXP15060_RST_PMIC_BY_PWROK_BIT;
+		ret = dm_i2c_write(dev,
+                                AXP15060_PWR_SEQUENCE_CTRL,
+                                &temp_buf,
+                                sizeof(temp_buf));
+		if (ret)
+                        printf("%s: can't write pmic power disbale & down sequence register\n",
+                                 __func__);
+
+	}
+
+	return 0;
+}
+
+int board_init(void)
+{
+	enable_caches();
+
+	jh7110_timer_init();
+	jh7110_usb_init(true);
+	jh7110_gmac_init(0);
+	jh7110_gmac_init(1);
+	jh7110_i2c_init(5);
+
+	return 0;
+}
+
+#ifdef CONFIG_MISC_INIT_R
+
+int misc_init_r(void)
+{
+	char mac0[6] = {0x6c, 0xcf, 0x39, 0x6c, 0xde, 0xad};
+	char mac1[6] = {0x6c, 0xcf, 0x39, 0x7c, 0xae, 0x5d};
+
+#if CONFIG_IS_ENABLED(STARFIVE_OTP)
+	struct udevice *dev;
+	char buf[16];
+	int ret;
+#define MACADDR_OFFSET 0x8
+
+	ret = uclass_get_device_by_driver(UCLASS_MISC,
+				DM_DRIVER_GET(starfive_otp), &dev);
+	if (ret) {
+		debug("%s: could not find otp device\n", __func__);
+		goto err;
+	}
+
+	ret = misc_read(dev, MACADDR_OFFSET, buf, sizeof(buf));
+	if (ret != sizeof(buf))
+		printf("%s: error reading mac from OTP\n", __func__);
+	else
+		if (buf[0] != 0xff) {
+			memcpy(mac0, buf, 6);
+			memcpy(mac1, &buf[8], 6);
+		}
+err:
+#endif
+	eth_env_set_enetaddr("eth0addr", mac0);
+	eth_env_set_enetaddr("eth1addr", mac1);
+
+#if CONFIG_IS_ENABLED(STARFIVE_OTP)
+	get_cpu_voltage_type(dev);
+#endif
+	return 0;
+}
+#endif
+
+int board_late_init(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	get_boot_mode();
+
+	env_set("chip_vision", "B");
+
+	/*
+	 * save the memory info by environment variable in u-boot,
+	 * It will used to update the memory configuration in dts,
+	 * which passed to kernel lately.
+	 */
+	env_set_hex("memory_addr", gd->ram_base);
+	env_set_hex("memory_size", gd->ram_size);
+
+	ret = uclass_get_device(UCLASS_VIDEO, 0, &dev);
+	if (ret)
+		return ret;
+
+	ret = video_bmp_display(dev, (ulong)&bmp_logo_bitmap[0], BMP_ALIGN_CENTER, BMP_ALIGN_CENTER, true);
+	if (ret)
+		goto err;
+
+err:
+		return 0;
+
+}
+
+static int jh7110_get_gpio_val(u32 gpio)
+{
+	int ret;
+
+	ret = gpio_request(gpio, "ddr_gpio");
+	if (!ret) {
+		ret = gpio_direction_input(gpio);
+		if (!ret)
+			ret = gpio_get_value(gpio);
+
+		gpio_free(gpio);
+	}
+
+	return ret;
+}
+
+int board_ddr_size(void)
+{
+	int val, ret;
+
+	val = jh7110_get_gpio_val(21);
+	if (IS_ERR_VALUE(val))
+		return val;
+
+	ret = jh7110_get_gpio_val(22);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	val |= (ret << 1);
+
+	switch (val) {
+	case 0x0:
+		ret = 8; //8GB
+		break;
+	case 0x1:
+		ret = 4; //4GB
+		break;
+	case 0x2:
+		ret = 2; //2GB
+		break;
+	case 0x3:
+		ret = 1; //1GB
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+static int starfive_get_gpio_val(u32 gpio)
+{
+	int ret;
+
+	ret = gpio_request(gpio, "ddr_gpio");
+	if (!ret) {
+		ret = gpio_direction_input(gpio);
+		if (!ret)
+			ret = gpio_get_value(gpio);
+
+		gpio_free(gpio);
+	}
+
+	return ret;
+}
+
+/* get ddr type from GPIO23,GPIO24 DDR4 or LPDDR4 */
+int starfive_get_ddr_type(void)
+{
+	int val, ret;
+
+	val = starfive_get_gpio_val(23);
+	if (IS_ERR_VALUE(val))
+		return val;
+
+	ret = starfive_get_gpio_val(24);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	return val | (ret << 1);
+}

+ 405 - 0
include/configs/starfive-devkits.h

@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Shanghai StarFive Technology Co., Ltd.
+ * YanHong  Wang <yanhong.wang@starfivetech.com>
+ */
+
+#ifndef _STARFIVE_DEVKITS_H
+#define _STARFIVE_DEVKITS_H
+
+#include <version.h>
+#include <linux/sizes.h>
+
+#ifdef CONFIG_SPL
+
+#define CONFIG_SPL_MAX_SIZE		0x00040000
+#define CONFIG_SPL_BSS_START_ADDR	0x08040000
+#define CONFIG_SPL_BSS_MAX_SIZE		0x00010000
+#define CONFIG_SYS_SPL_MALLOC_START	0x42000000
+#define CONFIG_SYS_SPL_MALLOC_SIZE	0x00800000
+
+#define CONFIG_SPL_STACK		(0x08000000 + 0x00180000 - \
+					GENERATED_GBL_DATA_SIZE)
+
+#define STARFIVE_SPL_BOOT_LOAD_ADDR	0x60000000
+#endif
+
+#define CONFIG_SYS_BOOTM_LEN            SZ_64M
+
+#define CONFIG_SYS_CACHELINE_SIZE 64
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_SYS_CBSIZE	1024	/* Console I/O Buffer Size */
+
+/*
+ * Print Buffer Size
+ */
+#define CONFIG_SYS_PBSIZE					\
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * max number of command args
+ */
+#define CONFIG_SYS_MAXARGS	16
+
+/*
+ * Boot Argument Buffer Size
+ */
+#define CONFIG_SYS_BARGSIZE	CONFIG_SYS_CBSIZE
+
+/*
+ * Size of malloc() pool
+ * 512kB is suggested, (CONFIG_ENV_SIZE + 128 * 1024) was not enough
+ */
+#define CONFIG_SYS_MALLOC_LEN		SZ_8M
+
+#define CONFIG_SYS_SDRAM_BASE		0x40000000
+
+/* Init Stack Pointer */
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_8M)
+
+#define CONFIG_SYS_LOAD_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_STANDALONE_LOAD_ADDR	(CONFIG_SYS_SDRAM_BASE + SZ_16M)
+
+/*
+ * Ethernet
+ */
+#ifdef CONFIG_CMD_NET
+#define CONFIG_DW_ALTDESCRIPTOR
+#define DWC_NET_PHYADDR		0
+#define CONFIG_ARP_TIMEOUT	500
+#define PHY_ANEG_TIMEOUT	8000 /* PHY needs longer aneg time */
+#define CONFIG_NETMASK		255.255.255.0
+#define CONFIG_IPADDR		192.168.120.230
+#define CONFIG_IP_DEFRAG
+#ifndef CONFIG_NET_MAXDEFRAG
+#define CONFIG_NET_MAXDEFRAG	16384
+#endif
+#endif
+
+/* HACK these should have '#if defined (stuff) around them like zynqp*/
+#define BOOT_TARGET_DEVICES(func) func(DHCP, dhcp, na)	func(MMC, mmc, 0)
+
+#include <config_distro_bootcmd.h>
+
+
+#include <environment/distro/sf.h>
+
+#define TYPE_GUID_LOADER1	"5B193300-FC78-40CD-8002-E86C45580B47"
+#define TYPE_GUID_LOADER2	"2E54B353-1271-4842-806F-E436D6AF6985"
+#define TYPE_GUID_SYSTEM	"0FC63DAF-8483-4772-8E79-3D69D8477DE4"
+
+#define CPU_VOL_1020_SET \
+	"cpu_vol_1020_set=" 			\
+	"fdt set /opp-table-0/opp-1500000000 opp-microvolt <1020000>;\0"
+
+#define CPU_VOL_1040_SET \
+	"cpu_vol_1040_set="			\
+	"fdt set /opp-table-0/opp-1500000000 opp-microvolt <1040000>;\0"
+
+#define CPU_VOL_1060_SET \
+	"cpu_vol_1060_set="			\
+	"fdt set /opp-table-0/opp-1500000000 opp-microvolt <1060000>;\0"
+
+#define CPU_SPEED_1250_SET \
+	"cpu_speed_1250_set="			\
+	"fdt rm /opp-table-0/opp-375000000;"	\
+	"fdt rm /opp-table-0/opp-500000000;"	\
+	"fdt rm /opp-table-0/opp-750000000;"	\
+	"fdt rm /opp-table-0/opp-1500000000;\0"
+
+#define CPU_SPEED_1500_SET \
+	"cpu_speed_1500_set="			\
+	"fdt rm /opp-table-0/opp-312500000;"	\
+	"fdt rm /opp-table-0/opp-417000000;"	\
+	"fdt rm /opp-table-0/opp-625000000;"	\
+	"fdt rm /opp-table-0/opp-1250000000;\0"
+
+#define CMA_SIZE_SET \
+	"cma_start=70000000\0"					\
+	"cma_1g=b000000\0"					\
+	"cma_2g=20000000\0"					\
+	"cma_4g=40000000\0"					\
+	"cma_8g=60000000\0"					\
+	"cma_node=/reserved-memory/linux,cma\0" 		\
+	"cma_ddr1g_set="					\
+	"fdt set ${cma_node} size <0x0 0x${cma_1g}>;"		\
+	"fdt set ${cma_node} alloc-ranges <0x0 0x${cma_start} 0x0 0x${cma_1g}>;\0" \
+	"cma_ddr2g_set="					\
+	"fdt set ${cma_node} size <0x0 0x${cma_2g}>;"		\
+	"fdt set ${cma_node} alloc-ranges <0x0 0x${cma_start} 0x0 0x${cma_2g}>;\0" \
+	"cma_ddr4g_set="					\
+	"fdt set ${cma_node} size <0x0 0x${cma_4g}>;"		\
+	"fdt set ${cma_node} alloc-ranges <0x0 0x${cma_start} 0x0 0x${cma_4g}>;\0" \
+	"cma_ddr8g_set="					\
+	"fdt set ${cma_node} size <0x0 0x${cma_8g}>;"		\
+	"fdt set ${cma_node} alloc-ranges <0x0 0x${cma_start} 0x0 0x${cma_8g}>;\0" \
+	"cma_resize="						\
+	"if test ${memory_size} -eq 40000000; then "		\
+		"run cma_ddr1g_set;"				\
+	"elif test ${memory_size} -eq 80000000; then "		\
+		"run cma_ddr2g_set;"				\
+	"elif test ${memory_size} -eq 100000000; then " 	\
+		"run cma_ddr4g_set;"				\
+	"elif test ${memory_size} -ge 200000000; then " 	\
+		"run cma_ddr8g_set;"				\
+	"fi; \0 "
+
+#define CPU_FREQ_VOL_SET \
+	"cpu_vol_set="						\
+	"if test ${cpu_max_vol} = 1000000; then "		\
+		"run cpu_speed_1250_set; "			\
+	"else "							\
+		"run cpu_speed_1500_set; "			\
+		"if test ${cpu_max_vol} = 1060000; then "	\
+			"run cpu_vol_1060_set; "		\
+		"elif test ${cpu_max_vol} = 1020000; then "	\
+			"run cpu_vol_1020_set; "		\
+		"else "						\
+			"run cpu_vol_1040_set; "		\
+		"fi; "						\
+	"fi; \0"
+
+#define DEVKITS_MEM_SET	\
+	"devkits_mem_set="	\
+	"fdt memory ${memory_addr} ${memory_size};" \
+	"run cma_resize; \0"
+
+#define CHIPA_GMAC_SET \
+	"chipa_gmac_set="	\
+	"fdt set /soc/ethernet@16030000/ethernet-phy@0 tx_inverted_10 <0x1>;"	\
+	"fdt set /soc/ethernet@16030000/ethernet-phy@0 tx_inverted_100 <0x1>;"	\
+	"fdt set /soc/ethernet@16030000/ethernet-phy@0 tx_inverted_1000 <0x1>;\0"
+
+#define CHIPA_SET	\
+	"chipa_set="				\
+	"if test ${chip_vision} = B; then "	\
+		"run chipa_gmac_set;"		\
+	"fi; \0"				\
+	"chipa_set_uboot="			\
+	"fdt addr ${fdtcontroladdr};"		\
+	"run chipa_set;\0"			\
+	"chipa_set_linux="			\
+	"fdt addr ${fdt_addr_r};"		\
+	"run devkits_mem_set;"			\
+	"run chipa_set;\0"
+
+#define PARTS_DEFAULT							\
+	"name=loader1,start=17K,size=1M,type=${type_guid_gpt_loader1};" \
+	"name=loader2,size=4MB,type=${type_guid_gpt_loader2};"		\
+	"name=system,size=-,bootable,type=${type_guid_gpt_system};"
+
+#define JH7110_SDK_BOOTENV		\
+	"bootdir=/boot\0"		\
+	"bootpart=3\0"			\
+	"rootpart=4\0"			\
+	"load_sdk_uenv="		\
+		"fatload ${bootdev} ${devnum}:${bootpart} ${loadaddr} ${bootenv_sdk};"	\
+		"env import -t ${loadaddr} ${filesize}; \0"				\
+	"mmc_test_and_boot="				\
+		"if mmc dev ${devnum}; then "	\
+			"echo Try booting from MMC${devnum} ...; "	\
+			"setenv sdev_blk mmcblk${devnum}p${rootpart};"	\
+			"run load_sdk_uenv; run boot2;" \
+		"fi;\0" 						\
+	"bootenv_mmc="					\
+		"setenv bootdev mmc;"			\
+		"if test ${bootmode} = flash; then "	\
+			"for mmc_devnum in ${mmc_devnum_l}; do " \
+				"setenv devnum ${mmc_devnum}; " \
+				"run mmc_test_and_boot;"	\
+			"done;" 				\
+		"fi; "						\
+		"if test ${bootmode} = sd; then "	\
+			"setenv devnum ${sd_devnum};"	\
+			"run mmc_test_and_boot;"	\
+		"fi; "					\
+		"if test ${bootmode} = emmc; then "	\
+			"setenv devnum	${emmc_devnum};"\
+			"run mmc_test_and_boot;"	\
+		"fi; \0"				\
+	"bootenv_nvme=" 				\
+		"if test ${bootmode} = flash; then "	\
+			"for nvme_devnum in ${nvme_devnum_l}; do " \
+				"setenv devnum ${nvme_devnum};" \
+				"if pci enum; then "		\
+					"nvme scan; "		\
+				"fi; "				\
+				"if nvme dev ${devnum}; then "	\
+					"echo Try booting from NVME${devnum} ...; "	\
+					"setenv bootdev nvme;"	\
+					"setenv sdev_blk nvme${devnum}n1p${rootpart};"	\
+					"run load_sdk_uenv; run boot2;" \
+				"fi; "				\
+			"done; "				\
+		"fi; \0"					\
+	"sdk_boot_env=" 		\
+		"for bootdev_s in ${boot_devs}; do "	\
+		"run bootenv_${bootdev_s}; "		\
+		"done;\0"				\
+	"fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0"
+
+#define DEVKITS_SDK_BOOTENV		\
+	"bootenv=uEnv.txt\0"		\
+	"bootenv_sdk=devkits_uEnv.txt\0"\
+	"boot_devs=mmc nvme\0"		\
+	"emmc_devnum=0\0"		\
+	"sd_devnum=1\0" 		\
+	"mmc_devnum_l=1 0\0"		\
+	"nvme_devnum_l=0 0\0"
+
+#define JH7110_DISTRO_BOOTENV	\
+	"bootdir=/boot\0"	\
+	"bootpart=3\0"		\
+	"rootpart=4\0"		\
+	"load_distro_uenv="						\
+		"fatload ${bootdev} ${devnum}:${bootpart} ${loadaddr} /${bootenv}; " \
+		"env import ${loadaddr} ${filesize}; \0" \
+	"fdt_loaddtb="		\
+		"fatload ${bootdev} ${devnum}:${bootpart} ${fdt_addr_r} /dtbs/${fdtfile}; fdt addr ${fdt_addr_r}; \0" \
+	"fdt_sizecheck="	\
+		"fatsize ${bootdev} ${devnum}:${bootpart} /dtbs/${fdtfile}; \0" \
+	"set_fdt_distro="	\
+		"run chipa_set_linux; run cpu_vol_set;" \
+		"fatwrite ${bootdev} ${devnum}:${bootpart} ${fdt_addr_r} /dtbs/${fdtfile} ${filesize}; \0" \
+	"bootcmd_distro="	\
+		"run load_distro_uenv; " \
+		"run fdt_loaddtb; run fdt_sizecheck; run set_fdt_distro; "	\
+		"sysboot ${bootdev} ${devnum}:${bootpart} fat ${scriptaddr} /${boot_syslinux_conf}; \0" \
+	"distro_mmc_test_and_boot="					\
+		"if mmc dev ${devnum}; then "				\
+			"echo Try booting from MMC${devnum} ...; "	\
+			"run bootcmd_distro;"				\
+		"fi;\0" 						\
+	"distro_bootenv_mmc="					\
+		"setenv bootdev mmc;"			\
+		"if test ${bootmode} = flash; then "	\
+			"for mmc_devnum in ${mmc_devnum_l}; do "\
+				"setenv devnum ${mmc_devnum}; " \
+				"run distro_mmc_test_and_boot;" \
+			"done;" 				\
+		"fi; "						\
+		"if test ${bootmode} = sd; then "	\
+			"setenv devnum ${sd_devnum};"	\
+			"run distro_mmc_test_and_boot;" \
+		"fi; "					\
+		"if test ${bootmode} = emmc; then "	\
+			"setenv devnum	${emmc_devnum};"\
+			"run distro_mmc_test_and_boot;" \
+		"fi; \0"				\
+	"distro_bootenv_nvme="				\
+		"if test ${bootmode} = flash; then "	\
+			"for nvme_devnum in ${nvme_devnum_l}; do " \
+				"setenv devnum ${nvme_devnum};" \
+				"if pci enum; then "		\
+					"nvme scan; "		\
+				"fi; "				\
+				"if nvme dev ${devnum}; then "	\
+					"echo Try booting from NVME${devnum} ...; "	\
+					"setenv bootdev nvme;"	\
+					"run bootcmd_distro; "	\
+				"fi; "				\
+			"done; "				\
+		"fi; \0"					\
+	"distro_boot_env="		\
+		"echo Tring booting distro ...;"		\
+		"for bootdev_s in ${boot_devs}; do "		\
+			"run distro_bootenv_${bootdev_s}; "	\
+		"done; \0"
+
+#define CONFIG_EXTRA_ENV_SETTINGS			\
+	"fdt_high=0xffffffffffffffff\0"			\
+	"initrd_high=0xffffffffffffffff\0"		\
+	"kernel_addr_r=0x40200000\0"			\
+	"kernel_comp_addr_r=0x5a000000\0"		\
+	"kernel_comp_size=0x4000000\0"			\
+	"fdt_addr_r=0x46000000\0"			\
+	"scriptaddr=0x43900000\0"			\
+	"script_offset_f=0x1fff000\0"			\
+	"script_size_f=0x1000\0"			\
+	"pxefile_addr_r=0x45900000\0"			\
+	"ramdisk_addr_r=0x46100000\0"			\
+	"fdtoverlay_addr_r=0x4f000000\0"		\
+	"loadaddr=0x60000000\0"				\
+	CHIPA_GMAC_SET					\
+	CHIPA_SET					\
+	CPU_VOL_1020_SET				\
+	CPU_VOL_1040_SET				\
+	CPU_VOL_1060_SET				\
+	CPU_SPEED_1250_SET				\
+	CPU_SPEED_1500_SET				\
+	CPU_FREQ_VOL_SET				\
+	DEVKITS_MEM_SET					\
+	DEVKITS_SDK_BOOTENV				\
+	CMA_SIZE_SET					\
+	JH7110_SDK_BOOTENV				\
+	JH7110_DISTRO_BOOTENV				\
+	"type_guid_gpt_loader1=" TYPE_GUID_LOADER1 "\0" \
+	"type_guid_gpt_loader2=" TYPE_GUID_LOADER2 "\0" \
+	"type_guid_gpt_system=" TYPE_GUID_SYSTEM "\0"	\
+	"partitions=" PARTS_DEFAULT "\0"		\
+	BOOTENV						\
+	BOOTENV_SF
+
+#define CONFIG_SYS_BAUDRATE_TABLE {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600}
+#define CONFIG_SYS_LOADS_BAUD_CHANGE 1		/* allow baudrate change */
+
+/* 6.25MHz RTC clock, StarFive JH7110*/
+#define CONFIG_SYS_HZ_CLOCK	4000000
+
+#define __io
+
+#define memset_io(c, v, l)	memset((c), (v), (l))
+#define memcpy_fromio(a, c, l)	memcpy((a), (c), (l))
+#define memcpy_toio(c, a, l)	memcpy((c), (a), (l))
+
+#define CONFIG_ID_EEPROM
+
+#ifdef CONFIG_ID_EEPROM		/* EEPROM for SN and MAC */
+#define CONFIG_SYS_EEPROM_BUS_NUM		5
+
+#define FORMAT_VERSION				0x01
+#define PCB_VERSION				0xB0
+#define BOM_VERSION				'A'
+/*
+ * BYTES_PER_EEPROM_PAGE: the 24FC04H datasheet says that data can
+ * only be written in page mode, which means 16 bytes at a time:
+ * 16-Byte Page Write Buffer
+ */
+#define BYTES_PER_EEPROM_PAGE			16
+
+/*
+ * EEPROM_WRITE_DELAY_MS: the 24FC04H datasheet says it takes up to
+ * 5ms to complete a given write:
+ * Write Cycle Time (byte or page) ro Page Write Time 5 ms, Maximum
+ */
+#define EEPROM_WRITE_DELAY_MS			5000
+/*
+ * StarFive OUI. Registration Date is 20xx-xx-xx
+ */
+#define STARFIVE_OUI_PREFIX			"6C:CF:39:"
+#define STARFIVE_DEFAULT_MAC0			{0x6c, 0xcf, 0x39, 0x6c, 0xde, 0xad}
+#define STARFIVE_DEFAULT_MAC1			{0x6c, 0xcf, 0x39, 0x7c, 0xae, 0x5d}
+
+/* Magic number at the first four bytes of EEPROM HATs */
+#define STARFIVE_EEPROM_HATS_SIG	"SFDK" /* StarFive VisionFive */
+
+#define STARFIVE_EEPROM_HATS_SIZE_MAX	256 /* Header + Atom1&4(v1) */
+#define STARFIVE_EEPROM_WP_OFFSET	0 /* Read only field */
+#define STARFIVE_EEPROM_ATOM1_PSTR	"DK7110B1-2150-D104EC32-00000001\0"
+
+#define STARFIVE_EEPROM_ATOM1_PSTR_SIZE	32
+#define STARFIVE_EEPROM_ATOM1_SN_OFFSET	23
+#define STARFIVE_EEPROM_ATOM1_VSTR	"StarFive Technology Co., Ltd.\0\0\0"
+#define STARFIVE_EEPROM_ATOM1_VSTR_SIZE	32
+#endif
+
+#define CONFIG_VIDEO_BMP_LOGO
+#define CONFIG_VIDEO_LOGO
+#define CONFIG_BMP_16BPP
+#define CONFIG_BMP_24BPP
+#define CONFIG_BMP_32BPP
+
+#endif /* _STARFIVE_DEVKITS_H */