blob: cf5824886c37d873c2ff39c35a3053120b076130 [file] [log] [blame]
Baruch Siach4417ff22020-01-20 14:20:11 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2020 SolidRun
4 */
5
6#include <common.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06007#include <compiler.h>
Baruch Siach4417ff22020-01-20 14:20:11 +02008#include <tlv_eeprom.h>
9#include "tlv_data.h"
10
11#define SR_TLV_CODE_RAM_SIZE 0x81
12
13static 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
31static 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;
Josua Mayere5283662023-10-08 16:58:03 +020048 if (tlv_entry->length < 6)
Baruch Siach4417ff22020-01-20 14:20:11 +020049 return;
50 td->ram_size = val[5];
Josua Mayere5283662023-10-08 16:58:03 +020051
52 /* extension with additional data field for number of ddr channels */
53 if (tlv_entry->length >= 7) {
54 td->ram_channels = val[6];
55 }
Baruch Siach4417ff22020-01-20 14:20:11 +020056}
57
58static void parse_tlv_data(u8 *eeprom, struct tlvinfo_header *hdr,
59 struct tlvinfo_tlv *entry, struct tlv_data *td)
60{
61 unsigned int tlv_offset, tlv_len;
62
63 tlv_offset = sizeof(struct tlvinfo_header);
64 tlv_len = sizeof(struct tlvinfo_header) + be16_to_cpu(hdr->totallen);
65 while (tlv_offset < tlv_len) {
66 entry = (struct tlvinfo_tlv *)&eeprom[tlv_offset];
67
68 switch (entry->type) {
69 case TLV_CODE_PRODUCT_NAME:
70 store_product_name(entry, td);
71 break;
72 case TLV_CODE_VENDOR_EXT:
73 parse_tlv_vendor_ext(entry, td);
74 break;
75 default:
76 break;
77 }
78
79 tlv_offset += sizeof(struct tlvinfo_tlv) + entry->length;
80 }
81}
82
83void read_tlv_data(struct tlv_data *td)
84{
85 u8 eeprom_data[TLV_TOTAL_LEN_MAX];
86 struct tlvinfo_header *tlv_hdr;
87 struct tlvinfo_tlv *tlv_entry;
88 int ret, i;
89
90 for (i = 0; i < 2; i++) {
91 ret = read_tlvinfo_tlv_eeprom(eeprom_data, &tlv_hdr,
92 &tlv_entry, i);
93 if (ret < 0)
94 continue;
95 parse_tlv_data(eeprom_data, tlv_hdr, tlv_entry, td);
96 }
97}
98
99bool sr_product_is(const struct tlv_data *td, const char *product)
100{
101 /* Allow prefix sub-string match */
102 if (strncmp(td->tlv_product_name[0], product, strlen(product)) == 0)
103 return true;
104 if (strncmp(td->tlv_product_name[1], product, strlen(product)) == 0)
105 return true;
106
107 return false;
108}