diff mbox series

[U-Boot,06/10] ARM: mvebu: clearfog: read basic TLV data

Message ID b52e4baf8b4afa8289f3b35267ac8a566842f79b.1574676560.git.baruch@tkos.co.il
State Superseded
Delegated to: Stefan Roese
Headers show
Series ARM: clearfog: add run-time board detect | expand

Commit Message

Baruch Siach Nov. 25, 2019, 10:30 a.m. UTC
Read RAM die capacity from the EEPROM TLV.

Follow the ONIE standard that defines the Vendor Extension entry type
for vendor specific data. We have no Private Enterprise Number at the
moment as the standard requires. Use the dummy all 0xff value for now.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
 board/solidrun/clearfog/clearfog.c | 118 +++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)

Comments

Stefan Roese Jan. 13, 2020, 7:22 a.m. UTC | #1
On 25.11.19 11:30, Baruch Siach wrote:
> Read RAM die capacity from the EEPROM TLV.
> 
> Follow the ONIE standard that defines the Vendor Extension entry type
> for vendor specific data. We have no Private Enterprise Number at the
> moment as the standard requires. Use the dummy all 0xff value for now.
> 
> Signed-off-by: Baruch Siach <baruch@tkos.co.il>
> ---
>   board/solidrun/clearfog/clearfog.c | 118 +++++++++++++++++++++++++++++
>   1 file changed, 118 insertions(+)
> 
> diff --git a/board/solidrun/clearfog/clearfog.c b/board/solidrun/clearfog/clearfog.c
> index 8b6381194688..707afabb11a7 100644
> --- a/board/solidrun/clearfog/clearfog.c
> +++ b/board/solidrun/clearfog/clearfog.c
> @@ -7,6 +7,7 @@
>   #include <i2c.h>
>   #include <miiphy.h>
>   #include <netdev.h>
> +#include <sys_eeprom.h>
>   #include <asm/io.h>
>   #include <asm/arch/cpu.h>
>   #include <asm/arch/soc.h>
> @@ -16,6 +17,14 @@
>   
>   DECLARE_GLOBAL_DATA_PTR;
>   
> +#define SR_TLV_CODE_RAM_DIE_SIZE	0x81
> +
> +/*
> + * Some Clearfog variants have TLV on SOM and on carrier, with separate
> + * product name entries.
> + */
> +static char tlv_product_name[2][32];
> +
>   /*
>    * Those values and defines are taken from the Marvell U-Boot version
>    * "u-boot-2013.01-15t1-clearfog"
> @@ -74,8 +83,117 @@ static struct mv_ddr_topology_map board_topology_map = {
>   	0x3,				/* clock enable mask */
>   };
>   
> +static void store_product_name(tlvinfo_tlv_t *tlv_entry)
> +{
> +	int len;
> +	char *dest;
> +
> +	if (strlen(tlv_product_name[0]) == 0)
> +		dest = tlv_product_name[0];
> +	else if (strlen(tlv_product_name[1]) == 0)
> +		dest = tlv_product_name[1];
> +	else
> +		return;
> +
> +	len = min_t(unsigned, tlv_entry->length,
> +			sizeof(tlv_product_name[0])-1);

Nitpicking: Space missing around "-". Please run checkpatch.

> +	memcpy(dest, tlv_entry->value, len);
> +}
> +
> +static bool sr_product_is(const char *product)
> +{
> +	/* Allow prefix sub-string match */
> +	if (strncmp(tlv_product_name[0], product, strlen(product)) == 0)
> +		return true;
> +	if (strncmp(tlv_product_name[1], product, strlen(product)) == 0)
> +		return true;
> +
> +	return false;
> +}
> +
> +static void parse_tlv_vendor_ext(tlvinfo_tlv_t *tlv_entry)
> +{
> +	struct if_params *ifp = &board_topology_map.interface_params[0];
> +	u8 *val = tlv_entry->value;
> +	uint32_t pen; /* IANA Private Enterprise Numbers */
> +
> +	if (tlv_entry->length < 5) /* 4 bytes PEN + at least 1 byte type */
> +		return;
> +
> +	/* PEN is big endian */
> +	pen = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3];
> +	/* Not a real PEN */
> +	if (pen != 0xffffffff)
> +		return;
> +
> +	switch (val[4]) {
> +	case SR_TLV_CODE_RAM_DIE_SIZE:
> +		if (tlv_entry->length != 6)
> +			break;
> +		switch (val[5]) {
> +		case 4:
> +		default:
> +			ifp->memory_size = MV_DDR_DIE_CAP_4GBIT;
> +			break;
> +		case 8:
> +			ifp->memory_size = MV_DDR_DIE_CAP_8GBIT;
> +			break;
> +		}
> +	default:
> +		break;
> +	}
> +}
> +
> +static void parse_tlv_data(uint8_t *eeprom, tlvinfo_header_t *hdr,
> +		tlvinfo_tlv_t *entry)
> +{
> +	unsigned tlv_offset, tlv_len;
> +
> +	tlv_offset = sizeof(tlvinfo_header_t);
> +	tlv_len = sizeof(tlvinfo_header_t) + be16_to_cpu(hdr->totallen);
> +	while (tlv_offset < tlv_len) {
> +		entry = (tlvinfo_tlv_t *) &eeprom[tlv_offset];
> +
> +		switch (entry->type) {
> +		case TLV_CODE_PRODUCT_NAME:
> +			store_product_name(entry);
> +			break;
> +		case TLV_CODE_VENDOR_EXT:
> +			parse_tlv_vendor_ext(entry);
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		tlv_offset += sizeof(tlvinfo_tlv_t) + entry->length;
> +	}
> +}
> +
> +static void read_tlv_data(void)
> +{
> +	uint8_t eeprom_data[TLV_TOTAL_LEN_MAX];
> +	tlvinfo_header_t *tlv_hdr;

AFAIK, using typedefs (in the sys_eeprom header most likely) is frowned
upon nowadays. Not sure if it makes sense to remove these typedefs as
this might make the code incompatible with other potential users.

> +	tlvinfo_tlv_t *tlv_entry;
> +	static bool ran_once;
> +	int ret, i;
> +
> +	if (ran_once)
> +		return;
> +	ran_once = true;
> +
> +	for (i = 0; i < 2; i++) {
> +		ret = read_tlvinfo_sys_eeprom_dev(eeprom_data, &tlv_hdr,
> +				&tlv_entry, i);
> +		if (ret < 0)
> +			continue;
> +		parse_tlv_data(eeprom_data, tlv_hdr, tlv_entry);
> +	}
> +}
> +
>   struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
>   {
> +	read_tlv_data();
> +
>   	/* Return the board topology as defined in the board code */
>   	return &board_topology_map;
>   }
> 

Other than my comments above:

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan
diff mbox series

Patch

diff --git a/board/solidrun/clearfog/clearfog.c b/board/solidrun/clearfog/clearfog.c
index 8b6381194688..707afabb11a7 100644
--- a/board/solidrun/clearfog/clearfog.c
+++ b/board/solidrun/clearfog/clearfog.c
@@ -7,6 +7,7 @@ 
 #include <i2c.h>
 #include <miiphy.h>
 #include <netdev.h>
+#include <sys_eeprom.h>
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
@@ -16,6 +17,14 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#define SR_TLV_CODE_RAM_DIE_SIZE	0x81
+
+/*
+ * Some Clearfog variants have TLV on SOM and on carrier, with separate
+ * product name entries.
+ */
+static char tlv_product_name[2][32];
+
 /*
  * Those values and defines are taken from the Marvell U-Boot version
  * "u-boot-2013.01-15t1-clearfog"
@@ -74,8 +83,117 @@  static struct mv_ddr_topology_map board_topology_map = {
 	0x3,				/* clock enable mask */
 };
 
+static void store_product_name(tlvinfo_tlv_t *tlv_entry)
+{
+	int len;
+	char *dest;
+
+	if (strlen(tlv_product_name[0]) == 0)
+		dest = tlv_product_name[0];
+	else if (strlen(tlv_product_name[1]) == 0)
+		dest = tlv_product_name[1];
+	else
+		return;
+
+	len = min_t(unsigned, tlv_entry->length,
+			sizeof(tlv_product_name[0])-1);
+	memcpy(dest, tlv_entry->value, len);
+}
+
+static bool sr_product_is(const char *product)
+{
+	/* Allow prefix sub-string match */
+	if (strncmp(tlv_product_name[0], product, strlen(product)) == 0)
+		return true;
+	if (strncmp(tlv_product_name[1], product, strlen(product)) == 0)
+		return true;
+
+	return false;
+}
+
+static void parse_tlv_vendor_ext(tlvinfo_tlv_t *tlv_entry)
+{
+	struct if_params *ifp = &board_topology_map.interface_params[0];
+	u8 *val = tlv_entry->value;
+	uint32_t pen; /* IANA Private Enterprise Numbers */
+
+	if (tlv_entry->length < 5) /* 4 bytes PEN + at least 1 byte type */
+		return;
+
+	/* PEN is big endian */
+	pen = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3];
+	/* Not a real PEN */
+	if (pen != 0xffffffff)
+		return;
+
+	switch (val[4]) {
+	case SR_TLV_CODE_RAM_DIE_SIZE:
+		if (tlv_entry->length != 6)
+			break;
+		switch (val[5]) {
+		case 4:
+		default:
+			ifp->memory_size = MV_DDR_DIE_CAP_4GBIT;
+			break;
+		case 8:
+			ifp->memory_size = MV_DDR_DIE_CAP_8GBIT;
+			break;
+		}
+	default:
+		break;
+	}
+}
+
+static void parse_tlv_data(uint8_t *eeprom, tlvinfo_header_t *hdr,
+		tlvinfo_tlv_t *entry)
+{
+	unsigned tlv_offset, tlv_len;
+
+	tlv_offset = sizeof(tlvinfo_header_t);
+	tlv_len = sizeof(tlvinfo_header_t) + be16_to_cpu(hdr->totallen);
+	while (tlv_offset < tlv_len) {
+		entry = (tlvinfo_tlv_t *) &eeprom[tlv_offset];
+
+		switch (entry->type) {
+		case TLV_CODE_PRODUCT_NAME:
+			store_product_name(entry);
+			break;
+		case TLV_CODE_VENDOR_EXT:
+			parse_tlv_vendor_ext(entry);
+			break;
+		default:
+			break;
+		}
+
+		tlv_offset += sizeof(tlvinfo_tlv_t) + entry->length;
+	}
+}
+
+static void read_tlv_data(void)
+{
+	uint8_t eeprom_data[TLV_TOTAL_LEN_MAX];
+	tlvinfo_header_t *tlv_hdr;
+	tlvinfo_tlv_t *tlv_entry;
+	static bool ran_once;
+	int ret, i;
+
+	if (ran_once)
+		return;
+	ran_once = true;
+
+	for (i = 0; i < 2; i++) {
+		ret = read_tlvinfo_sys_eeprom_dev(eeprom_data, &tlv_hdr,
+				&tlv_entry, i);
+		if (ret < 0)
+			continue;
+		parse_tlv_data(eeprom_data, tlv_hdr, tlv_entry);
+	}
+}
+
 struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
 {
+	read_tlv_data();
+
 	/* Return the board topology as defined in the board code */
 	return &board_topology_map;
 }