0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <subdev/bios.h>
0025 #include <subdev/bios/bit.h>
0026 #include <subdev/bios/extdev.h>
0027 #include <subdev/bios/iccsense.h>
0028
0029 static u32
0030 nvbios_iccsense_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt,
0031 u8 *len)
0032 {
0033 struct bit_entry bit_P;
0034 u32 iccsense;
0035
0036 if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 ||
0037 bit_P.length < 0x2c)
0038 return 0;
0039
0040 iccsense = nvbios_rd32(bios, bit_P.offset + 0x28);
0041 if (!iccsense)
0042 return 0;
0043
0044 *ver = nvbios_rd08(bios, iccsense + 0);
0045 switch (*ver) {
0046 case 0x10:
0047 case 0x20:
0048 *hdr = nvbios_rd08(bios, iccsense + 1);
0049 *len = nvbios_rd08(bios, iccsense + 2);
0050 *cnt = nvbios_rd08(bios, iccsense + 3);
0051 return iccsense;
0052 default:
0053 break;
0054 }
0055
0056 return 0;
0057 }
0058
0059 int
0060 nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense)
0061 {
0062 struct nvkm_subdev *subdev = &bios->subdev;
0063 u8 ver, hdr, cnt, len, i;
0064 u32 table, entry;
0065
0066 table = nvbios_iccsense_table(bios, &ver, &hdr, &cnt, &len);
0067 if (!table || !cnt)
0068 return -EINVAL;
0069
0070 if (ver != 0x10 && ver != 0x20) {
0071 nvkm_error(subdev, "ICCSENSE version 0x%02x unknown\n", ver);
0072 return -EINVAL;
0073 }
0074
0075 iccsense->nr_entry = cnt;
0076 iccsense->rail = kmalloc_array(cnt, sizeof(struct pwr_rail_t),
0077 GFP_KERNEL);
0078 if (!iccsense->rail)
0079 return -ENOMEM;
0080
0081 for (i = 0; i < cnt; ++i) {
0082 struct nvbios_extdev_func extdev;
0083 struct pwr_rail_t *rail = &iccsense->rail[i];
0084 u8 res_start = 0;
0085 int r;
0086
0087 entry = table + hdr + i * len;
0088
0089 switch(ver) {
0090 case 0x10:
0091 if ((nvbios_rd08(bios, entry + 0x1) & 0xf8) == 0xf8)
0092 rail->mode = 1;
0093 else
0094 rail->mode = 0;
0095 rail->extdev_id = nvbios_rd08(bios, entry + 0x2);
0096 res_start = 0x3;
0097 break;
0098 case 0x20:
0099 rail->mode = nvbios_rd08(bios, entry);
0100 rail->extdev_id = nvbios_rd08(bios, entry + 0x1);
0101 res_start = 0x5;
0102 break;
0103 }
0104
0105 if (nvbios_extdev_parse(bios, rail->extdev_id, &extdev))
0106 continue;
0107
0108 switch (extdev.type) {
0109 case NVBIOS_EXTDEV_INA209:
0110 case NVBIOS_EXTDEV_INA219:
0111 rail->resistor_count = 1;
0112 break;
0113 case NVBIOS_EXTDEV_INA3221:
0114 rail->resistor_count = 3;
0115 break;
0116 default:
0117 rail->resistor_count = 0;
0118 break;
0119 }
0120
0121 for (r = 0; r < rail->resistor_count; ++r) {
0122 rail->resistors[r].mohm = nvbios_rd08(bios, entry + res_start + r * 2);
0123 rail->resistors[r].enabled = !(nvbios_rd08(bios, entry + res_start + r * 2 + 1) & 0x40);
0124 }
0125 rail->config = nvbios_rd16(bios, entry + res_start + rail->resistor_count * 2);
0126 }
0127
0128 return 0;
0129 }