1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2020 SolidRun
4  */
5 
6 #include <common.h>
7 #include <compiler.h>
8 #include <tlv_eeprom.h>
9 #include "tlv_data.h"
10 
11 #define SR_TLV_CODE_RAM_SIZE	0x81
12 
store_product_name(struct tlvinfo_tlv * tlv_entry,struct tlv_data * td)13 static void store_product_name(struct tlvinfo_tlv *tlv_entry,
14 			       struct tlv_data *td)
15 {
16 	int len;
17 	char *dest;
18 
19 	if (strlen(td->tlv_product_name[0]) == 0)
20 		dest = td->tlv_product_name[0];
21 	else if (strlen(td->tlv_product_name[1]) == 0)
22 		dest = td->tlv_product_name[1];
23 	else
24 		return;
25 
26 	len = min_t(unsigned int, tlv_entry->length,
27 		    sizeof(td->tlv_product_name[0]) - 1);
28 	memcpy(dest, tlv_entry->value, len);
29 }
30 
parse_tlv_vendor_ext(struct tlvinfo_tlv * tlv_entry,struct tlv_data * td)31 static void parse_tlv_vendor_ext(struct tlvinfo_tlv *tlv_entry,
32 				 struct tlv_data *td)
33 {
34 	u8 *val = tlv_entry->value;
35 	u32 pen; /* IANA Private Enterprise Numbers */
36 
37 	if (tlv_entry->length < 5) /* 4 bytes PEN + at least 1 byte type */
38 		return;
39 
40 	/* PEN is big endian */
41 	pen = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3];
42 	/* Not a real PEN */
43 	if (pen != 0xffffffff)
44 		return;
45 
46 	if (val[4] != SR_TLV_CODE_RAM_SIZE)
47 		return;
48 	if (tlv_entry->length != 6)
49 		return;
50 	td->ram_size = val[5];
51 }
52 
parse_tlv_data(u8 * eeprom,struct tlvinfo_header * hdr,struct tlvinfo_tlv * entry,struct tlv_data * td)53 static void parse_tlv_data(u8 *eeprom, struct tlvinfo_header *hdr,
54 			   struct tlvinfo_tlv *entry, struct tlv_data *td)
55 {
56 	unsigned int tlv_offset, tlv_len;
57 
58 	tlv_offset = sizeof(struct tlvinfo_header);
59 	tlv_len = sizeof(struct tlvinfo_header) + be16_to_cpu(hdr->totallen);
60 	while (tlv_offset < tlv_len) {
61 		entry = (struct tlvinfo_tlv *)&eeprom[tlv_offset];
62 
63 		switch (entry->type) {
64 		case TLV_CODE_PRODUCT_NAME:
65 			store_product_name(entry, td);
66 			break;
67 		case TLV_CODE_VENDOR_EXT:
68 			parse_tlv_vendor_ext(entry, td);
69 			break;
70 		default:
71 			break;
72 		}
73 
74 		tlv_offset += sizeof(struct tlvinfo_tlv) + entry->length;
75 	}
76 }
77 
read_tlv_data(struct tlv_data * td)78 void read_tlv_data(struct tlv_data *td)
79 {
80 	u8 eeprom_data[TLV_TOTAL_LEN_MAX];
81 	struct tlvinfo_header *tlv_hdr;
82 	struct tlvinfo_tlv *tlv_entry;
83 	int ret, i;
84 
85 	for (i = 0; i < 2; i++) {
86 		ret = read_tlvinfo_tlv_eeprom(eeprom_data, &tlv_hdr,
87 					      &tlv_entry, i);
88 		if (ret < 0)
89 			continue;
90 		parse_tlv_data(eeprom_data, tlv_hdr, tlv_entry, td);
91 	}
92 }
93 
sr_product_is(const struct tlv_data * td,const char * product)94 bool sr_product_is(const struct tlv_data *td, const char *product)
95 {
96 	/* Allow prefix sub-string match */
97 	if (strncmp(td->tlv_product_name[0], product, strlen(product)) == 0)
98 		return true;
99 	if (strncmp(td->tlv_product_name[1], product, strlen(product)) == 0)
100 		return true;
101 
102 	return false;
103 }
104