mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
drm/nouveau/iccsense: Parse the resistors and config the right way
Previously we parsed that table a bit wrong: 1. The entry layout depends on the sensor type used. 2. We have all resitors in one entry for the INA3221. 3. The config is already included in the vbios. This commit addresses that issue and with that we should be able to read out the right power consumption for every GPU with a INA209, INA219 and INA3221. Signed-off-by: Karol Herbst <karolherbst@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
9936aeeaeb
commit
a8c119a4d0
4 changed files with 84 additions and 94 deletions
|
@ -1,10 +1,16 @@
|
|||
#ifndef __NVBIOS_ICCSENSE_H__
|
||||
#define __NVBIOS_ICCSENSE_H__
|
||||
struct pwr_rail_resistor_t {
|
||||
u8 mohm;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct pwr_rail_t {
|
||||
u8 mode;
|
||||
u8 extdev_id;
|
||||
u8 resistor_mohm;
|
||||
u8 rail;
|
||||
u8 resistor_count;
|
||||
struct pwr_rail_resistor_t resistors[3];
|
||||
u16 config;
|
||||
};
|
||||
|
||||
struct nvbios_iccsense {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/bit.h>
|
||||
#include <subdev/bios/extdev.h>
|
||||
#include <subdev/bios/iccsense.h>
|
||||
|
||||
static u16
|
||||
|
@ -77,23 +78,47 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense)
|
|||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < cnt; ++i) {
|
||||
struct nvbios_extdev_func extdev;
|
||||
struct pwr_rail_t *rail = &iccsense->rail[i];
|
||||
u8 res_start = 0;
|
||||
int r;
|
||||
|
||||
entry = table + hdr + i * len;
|
||||
|
||||
switch(ver) {
|
||||
case 0x10:
|
||||
rail->mode = nvbios_rd08(bios, entry + 0x1);
|
||||
rail->extdev_id = nvbios_rd08(bios, entry + 0x2);
|
||||
rail->resistor_mohm = nvbios_rd08(bios, entry + 0x3);
|
||||
rail->rail = nvbios_rd08(bios, entry + 0x4);
|
||||
res_start = 0x3;
|
||||
break;
|
||||
case 0x20:
|
||||
rail->mode = nvbios_rd08(bios, entry);
|
||||
rail->extdev_id = nvbios_rd08(bios, entry + 0x1);
|
||||
rail->resistor_mohm = nvbios_rd08(bios, entry + 0x5);
|
||||
rail->rail = nvbios_rd08(bios, entry + 0x6);
|
||||
res_start = 0x5;
|
||||
break;
|
||||
};
|
||||
|
||||
if (nvbios_extdev_parse(bios, rail->extdev_id, &extdev))
|
||||
continue;
|
||||
|
||||
switch (extdev.type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
rail->resistor_count = 1;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
rail->resistor_count = 3;
|
||||
break;
|
||||
default:
|
||||
rail->resistor_count = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
for (r = 0; r < rail->resistor_count; ++r) {
|
||||
rail->resistors[r].mohm = nvbios_rd08(bios, entry + res_start + r * 2);
|
||||
rail->resistors[r].enabled = !(nvbios_rd08(bios, entry + res_start + r * 2 + 1) & 0x40);
|
||||
}
|
||||
rail->config = nvbios_rd16(bios, entry + res_start + rail->resistor_count * 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -95,61 +95,13 @@ nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense,
|
|||
40 * 8);
|
||||
}
|
||||
|
||||
static void
|
||||
nvkm_iccsense_ina209_config(struct nvkm_iccsense *iccsense,
|
||||
struct nvkm_iccsense_sensor *sensor)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
/* configuration:
|
||||
* 0x0007: 0x0007 shunt and bus continous
|
||||
* 0x0078: 0x0078 128 samples shunt
|
||||
* 0x0780: 0x0780 128 samples bus
|
||||
* 0x1800: 0x0000 +-40 mV shunt range
|
||||
* 0x2000: 0x0000 16V FSR
|
||||
*/
|
||||
u16 value = 0x07ff;
|
||||
nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
|
||||
nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
|
||||
}
|
||||
|
||||
static void
|
||||
nvkm_iccsense_ina3221_config(struct nvkm_iccsense *iccsense,
|
||||
struct nvkm_iccsense_sensor *sensor)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
/* configuration:
|
||||
* 0x0007: 0x0007 shunt and bus continous
|
||||
* 0x0031: 0x0000 140 us conversion time shunt
|
||||
* 0x01c0: 0x0000 140 us conversion time bus
|
||||
* 0x0f00: 0x0f00 1024 samples
|
||||
* 0x7000: 0x?000 channels
|
||||
*/
|
||||
u16 value = 0x0e07;
|
||||
if (sensor->rail_mask & 0x1)
|
||||
value |= 0x1 << 14;
|
||||
if (sensor->rail_mask & 0x2)
|
||||
value |= 0x1 << 13;
|
||||
if (sensor->rail_mask & 0x4)
|
||||
value |= 0x1 << 12;
|
||||
nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
|
||||
nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
|
||||
}
|
||||
|
||||
static void
|
||||
nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense,
|
||||
struct nvkm_iccsense_sensor *sensor)
|
||||
{
|
||||
switch (sensor->type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
nvkm_iccsense_ina209_config(iccsense, sensor);
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
nvkm_iccsense_ina3221_config(iccsense, sensor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
nvkm_trace(subdev, "write config of extdev %i: 0x%04x\n", sensor->id, sensor->config);
|
||||
nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, sensor->config);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -196,7 +148,6 @@ nvkm_iccsense_dtor(struct nvkm_subdev *subdev)
|
|||
static struct nvkm_iccsense_sensor*
|
||||
nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
|
||||
{
|
||||
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
struct nvkm_bios *bios = subdev->device->bios;
|
||||
struct nvkm_i2c *i2c = subdev->device->i2c;
|
||||
|
@ -245,7 +196,7 @@ nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
|
|||
sensor->type = extdev.type;
|
||||
sensor->i2c = &i2c_bus->i2c;
|
||||
sensor->addr = addr;
|
||||
sensor->rail_mask = 0x0;
|
||||
sensor->config = 0x0;
|
||||
return sensor;
|
||||
}
|
||||
|
||||
|
@ -273,48 +224,56 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
|
|||
|
||||
iccsense->data_valid = true;
|
||||
for (i = 0; i < stbl.nr_entry; ++i) {
|
||||
struct pwr_rail_t *r = &stbl.rail[i];
|
||||
struct nvkm_iccsense_rail *rail;
|
||||
struct pwr_rail_t *pwr_rail = &stbl.rail[i];
|
||||
struct nvkm_iccsense_sensor *sensor;
|
||||
int (*read)(struct nvkm_iccsense *,
|
||||
struct nvkm_iccsense_rail *);
|
||||
int r;
|
||||
|
||||
if (!r->mode || r->resistor_mohm == 0)
|
||||
if (pwr_rail->mode != 1 || !pwr_rail->resistor_count)
|
||||
continue;
|
||||
|
||||
sensor = nvkm_iccsense_get_sensor(iccsense, r->extdev_id);
|
||||
sensor = nvkm_iccsense_get_sensor(iccsense, pwr_rail->extdev_id);
|
||||
if (!sensor)
|
||||
continue;
|
||||
|
||||
switch (sensor->type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
if (r->rail != 0)
|
||||
continue;
|
||||
read = nvkm_iccsense_ina209_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
if (r->rail != 0)
|
||||
continue;
|
||||
read = nvkm_iccsense_ina219_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
if (r->rail >= 3)
|
||||
continue;
|
||||
read = nvkm_iccsense_ina3221_read;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (!sensor->config)
|
||||
sensor->config = pwr_rail->config;
|
||||
else if (sensor->config != pwr_rail->config)
|
||||
nvkm_error(subdev, "config mismatch found for extdev %i\n", pwr_rail->extdev_id);
|
||||
|
||||
rail = kmalloc(sizeof(*rail), GFP_KERNEL);
|
||||
if (!rail)
|
||||
return -ENOMEM;
|
||||
sensor->rail_mask |= 1 << r->rail;
|
||||
rail->read = read;
|
||||
rail->sensor = sensor;
|
||||
rail->idx = r->rail;
|
||||
rail->mohm = r->resistor_mohm;
|
||||
list_add_tail(&rail->head, &iccsense->rails);
|
||||
for (r = 0; r < pwr_rail->resistor_count; ++r) {
|
||||
struct nvkm_iccsense_rail *rail;
|
||||
struct pwr_rail_resistor_t *res = &pwr_rail->resistors[r];
|
||||
int (*read)(struct nvkm_iccsense *,
|
||||
struct nvkm_iccsense_rail *);
|
||||
|
||||
if (!res->mohm || !res->enabled)
|
||||
continue;
|
||||
|
||||
switch (sensor->type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
read = nvkm_iccsense_ina209_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
read = nvkm_iccsense_ina219_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
read = nvkm_iccsense_ina3221_read;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
rail = kmalloc(sizeof(*rail), GFP_KERNEL);
|
||||
if (!rail)
|
||||
return -ENOMEM;
|
||||
|
||||
rail->read = read;
|
||||
rail->sensor = sensor;
|
||||
rail->idx = r;
|
||||
rail->mohm = res->mohm;
|
||||
nvkm_debug(subdev, "create rail for extdev %i: { idx: %i, mohm: %i }\n", pwr_rail->extdev_id, r, rail->mohm);
|
||||
list_add_tail(&rail->head, &iccsense->rails);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ struct nvkm_iccsense_sensor {
|
|||
enum nvbios_extdev_type type;
|
||||
struct i2c_adapter *i2c;
|
||||
u8 addr;
|
||||
u8 rail_mask;
|
||||
u16 config;
|
||||
};
|
||||
|
||||
struct nvkm_iccsense_rail {
|
||||
|
|
Loading…
Reference in a new issue