0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/pci.h>
0024
0025 #include "amdgpu.h"
0026 #include "amdgpu_i2c.h"
0027 #include "smu_v11_0_i2c.h"
0028 #include "atom.h"
0029 #include "amdgpu_fru_eeprom.h"
0030 #include "amdgpu_eeprom.h"
0031
0032 #define FRU_EEPROM_MADDR 0x60000
0033
0034 static bool is_fru_eeprom_supported(struct amdgpu_device *adev)
0035 {
0036
0037
0038
0039
0040 struct atom_context *atom_ctx = adev->mode_info.atom_context;
0041
0042
0043
0044
0045 if (amdgpu_sriov_vf(adev))
0046 return false;
0047
0048
0049
0050
0051
0052
0053
0054 switch (adev->asic_type) {
0055 case CHIP_VEGA20:
0056
0057 if (strnstr(atom_ctx->vbios_version, "D161",
0058 sizeof(atom_ctx->vbios_version)) ||
0059 strnstr(atom_ctx->vbios_version, "D163",
0060 sizeof(atom_ctx->vbios_version)))
0061 return true;
0062 else
0063 return false;
0064 case CHIP_ALDEBARAN:
0065
0066 return true;
0067 case CHIP_SIENNA_CICHLID:
0068 if (strnstr(atom_ctx->vbios_version, "D603",
0069 sizeof(atom_ctx->vbios_version))) {
0070 if (strnstr(atom_ctx->vbios_version, "D603GLXE",
0071 sizeof(atom_ctx->vbios_version)))
0072 return false;
0073 else
0074 return true;
0075 } else {
0076 return false;
0077 }
0078 default:
0079 return false;
0080 }
0081 }
0082
0083 static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr,
0084 unsigned char *buf, size_t buf_size)
0085 {
0086 int ret;
0087 u8 size;
0088
0089 ret = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addrptr, buf, 1);
0090 if (ret < 1) {
0091 DRM_WARN("FRU: Failed to get size field");
0092 return ret;
0093 }
0094
0095
0096
0097
0098 size = buf[0] & 0x3F;
0099 size = min_t(size_t, size, buf_size);
0100
0101 ret = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addrptr + 1,
0102 buf, size);
0103 if (ret < 1) {
0104 DRM_WARN("FRU: Failed to get data field");
0105 return ret;
0106 }
0107
0108 return size;
0109 }
0110
0111 int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
0112 {
0113 unsigned char buf[AMDGPU_PRODUCT_NAME_LEN];
0114 u32 addrptr;
0115 int size, len;
0116
0117 if (!is_fru_eeprom_supported(adev))
0118 return 0;
0119
0120
0121 if (!adev->pm.fru_eeprom_i2c_bus || !adev->pm.fru_eeprom_i2c_bus->algo) {
0122 DRM_WARN("Cannot access FRU, EEPROM accessor not initialized");
0123 return -ENODEV;
0124 }
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138 addrptr = FRU_EEPROM_MADDR + 0xb;
0139 size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
0140 if (size < 1) {
0141 DRM_ERROR("Failed to read FRU Manufacturer, ret:%d", size);
0142 return -EINVAL;
0143 }
0144
0145
0146
0147
0148 addrptr += size + 1;
0149 size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
0150 if (size < 1) {
0151 DRM_ERROR("Failed to read FRU product name, ret:%d", size);
0152 return -EINVAL;
0153 }
0154
0155 len = size;
0156 if (len >= AMDGPU_PRODUCT_NAME_LEN) {
0157 DRM_WARN("FRU Product Name is larger than %d characters. This is likely a mistake",
0158 AMDGPU_PRODUCT_NAME_LEN);
0159 len = AMDGPU_PRODUCT_NAME_LEN - 1;
0160 }
0161 memcpy(adev->product_name, buf, len);
0162 adev->product_name[len] = '\0';
0163
0164 addrptr += size + 1;
0165 size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
0166 if (size < 1) {
0167 DRM_ERROR("Failed to read FRU product number, ret:%d", size);
0168 return -EINVAL;
0169 }
0170
0171 len = size;
0172
0173
0174
0175 if (len >= sizeof(adev->product_number)) {
0176 DRM_WARN("FRU Product Number is larger than 16 characters. This is likely a mistake");
0177 len = sizeof(adev->product_number) - 1;
0178 }
0179 memcpy(adev->product_number, buf, len);
0180 adev->product_number[len] = '\0';
0181
0182 addrptr += size + 1;
0183 size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
0184
0185 if (size < 1) {
0186 DRM_ERROR("Failed to read FRU product version, ret:%d", size);
0187 return -EINVAL;
0188 }
0189
0190 addrptr += size + 1;
0191 size = amdgpu_fru_read_eeprom(adev, addrptr, buf, sizeof(buf));
0192
0193 if (size < 1) {
0194 DRM_ERROR("Failed to read FRU serial number, ret:%d", size);
0195 return -EINVAL;
0196 }
0197
0198 len = size;
0199
0200
0201
0202 if (len >= sizeof(adev->serial)) {
0203 DRM_WARN("FRU Serial Number is larger than 16 characters. This is likely a mistake");
0204 len = sizeof(adev->serial) - 1;
0205 }
0206 memcpy(adev->serial, buf, len);
0207 adev->serial[len] = '\0';
0208
0209 return 0;
0210 }