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