cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

adm1272.c (16385B)


      1/*
      2 * Analog Devices ADM1272 High Voltage Positive Hot Swap Controller and Digital
      3 * Power Monitor with PMBus
      4 *
      5 * Copyright 2021 Google LLC
      6 *
      7 * SPDX-License-Identifier: GPL-2.0-or-later
      8 */
      9
     10#include "qemu/osdep.h"
     11#include <string.h>
     12#include "hw/i2c/pmbus_device.h"
     13#include "hw/irq.h"
     14#include "migration/vmstate.h"
     15#include "qapi/error.h"
     16#include "qapi/visitor.h"
     17#include "qemu/log.h"
     18#include "qemu/module.h"
     19
     20#define TYPE_ADM1272 "adm1272"
     21#define ADM1272(obj) OBJECT_CHECK(ADM1272State, (obj), TYPE_ADM1272)
     22
     23#define ADM1272_RESTART_TIME            0xCC
     24#define ADM1272_MFR_PEAK_IOUT           0xD0
     25#define ADM1272_MFR_PEAK_VIN            0xD1
     26#define ADM1272_MFR_PEAK_VOUT           0xD2
     27#define ADM1272_MFR_PMON_CONTROL        0xD3
     28#define ADM1272_MFR_PMON_CONFIG         0xD4
     29#define ADM1272_MFR_ALERT1_CONFIG       0xD5
     30#define ADM1272_MFR_ALERT2_CONFIG       0xD6
     31#define ADM1272_MFR_PEAK_TEMPERATURE    0xD7
     32#define ADM1272_MFR_DEVICE_CONFIG       0xD8
     33#define ADM1272_MFR_POWER_CYCLE         0xD9
     34#define ADM1272_MFR_PEAK_PIN            0xDA
     35#define ADM1272_MFR_READ_PIN_EXT        0xDB
     36#define ADM1272_MFR_READ_EIN_EXT        0xDC
     37
     38#define ADM1272_HYSTERESIS_LOW          0xF2
     39#define ADM1272_HYSTERESIS_HIGH         0xF3
     40#define ADM1272_STATUS_HYSTERESIS       0xF4
     41#define ADM1272_STATUS_GPIO             0xF5
     42#define ADM1272_STRT_UP_IOUT_LIM        0xF6
     43
     44/* Defaults */
     45#define ADM1272_OPERATION_DEFAULT       0x80
     46#define ADM1272_CAPABILITY_DEFAULT      0xB0
     47#define ADM1272_CAPABILITY_NO_PEC       0x30
     48#define ADM1272_DIRECT_MODE             0x40
     49#define ADM1272_HIGH_LIMIT_DEFAULT      0x0FFF
     50#define ADM1272_PIN_OP_DEFAULT          0x7FFF
     51#define ADM1272_PMBUS_REVISION_DEFAULT  0x22
     52#define ADM1272_MFR_ID_DEFAULT          "ADI"
     53#define ADM1272_MODEL_DEFAULT           "ADM1272-A1"
     54#define ADM1272_MFR_DEFAULT_REVISION    "25"
     55#define ADM1272_DEFAULT_DATE            "160301"
     56#define ADM1272_RESTART_TIME_DEFAULT    0x64
     57#define ADM1272_PMON_CONTROL_DEFAULT    0x1
     58#define ADM1272_PMON_CONFIG_DEFAULT     0x3F35
     59#define ADM1272_DEVICE_CONFIG_DEFAULT   0x8
     60#define ADM1272_HYSTERESIS_HIGH_DEFAULT     0xFFFF
     61#define ADM1272_STRT_UP_IOUT_LIM_DEFAULT    0x000F
     62#define ADM1272_VOLT_DEFAULT            12000
     63#define ADM1272_IOUT_DEFAULT            25000
     64#define ADM1272_PWR_DEFAULT             300  /* 12V 25A */
     65#define ADM1272_SHUNT                   300 /* micro-ohms */
     66#define ADM1272_VOLTAGE_COEFF_DEFAULT   1
     67#define ADM1272_CURRENT_COEFF_DEFAULT   3
     68#define ADM1272_PWR_COEFF_DEFAULT       7
     69#define ADM1272_IOUT_OFFSET             0x5000
     70#define ADM1272_IOUT_OFFSET             0x5000
     71
     72
     73typedef struct ADM1272State {
     74    PMBusDevice parent;
     75
     76    uint64_t ein_ext;
     77    uint32_t pin_ext;
     78    uint8_t restart_time;
     79
     80    uint16_t peak_vin;
     81    uint16_t peak_vout;
     82    uint16_t peak_iout;
     83    uint16_t peak_temperature;
     84    uint16_t peak_pin;
     85
     86    uint8_t pmon_control;
     87    uint16_t pmon_config;
     88    uint16_t alert1_config;
     89    uint16_t alert2_config;
     90    uint16_t device_config;
     91
     92    uint16_t hysteresis_low;
     93    uint16_t hysteresis_high;
     94    uint8_t status_hysteresis;
     95    uint8_t status_gpio;
     96
     97    uint16_t strt_up_iout_lim;
     98
     99} ADM1272State;
    100
    101static const PMBusCoefficients adm1272_coefficients[] = {
    102    [0] = { 6770, 0, -2 },        /* voltage, vrange 60V */
    103    [1] = { 4062, 0, -2 },        /* voltage, vrange 100V */
    104    [2] = { 1326, 20480, -1 },    /* current, vsense range 15mV */
    105    [3] = { 663, 20480, -1 },     /* current, vsense range 30mV */
    106    [4] = { 3512, 0, -2 },        /* power, vrange 60V, irange 15mV */
    107    [5] = { 21071, 0, -3 },       /* power, vrange 100V, irange 15mV */
    108    [6] = { 17561, 0, -3 },       /* power, vrange 60V, irange 30mV */
    109    [7] = { 10535, 0, -3 },       /* power, vrange 100V, irange 30mV */
    110    [8] = { 42, 31871, -1 },      /* temperature */
    111};
    112
    113static void adm1272_check_limits(ADM1272State *s)
    114{
    115    PMBusDevice *pmdev = PMBUS_DEVICE(s);
    116
    117    pmbus_check_limits(pmdev);
    118
    119    if (pmdev->pages[0].read_vout > s->peak_vout) {
    120        s->peak_vout = pmdev->pages[0].read_vout;
    121    }
    122
    123    if (pmdev->pages[0].read_vin > s->peak_vin) {
    124        s->peak_vin = pmdev->pages[0].read_vin;
    125    }
    126
    127    if (pmdev->pages[0].read_iout > s->peak_iout) {
    128        s->peak_iout = pmdev->pages[0].read_iout;
    129    }
    130
    131    if (pmdev->pages[0].read_temperature_1 > s->peak_temperature) {
    132        s->peak_temperature = pmdev->pages[0].read_temperature_1;
    133    }
    134
    135    if (pmdev->pages[0].read_pin > s->peak_pin) {
    136        s->peak_pin = pmdev->pages[0].read_pin;
    137    }
    138}
    139
    140static uint16_t adm1272_millivolts_to_direct(uint32_t value)
    141{
    142    PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
    143    c.b = c.b * 1000;
    144    c.R = c.R - 3;
    145    return pmbus_data2direct_mode(c, value);
    146}
    147
    148static uint32_t adm1272_direct_to_millivolts(uint16_t value)
    149{
    150    PMBusCoefficients c = adm1272_coefficients[ADM1272_VOLTAGE_COEFF_DEFAULT];
    151    c.b = c.b * 1000;
    152    c.R = c.R - 3;
    153    return pmbus_direct_mode2data(c, value);
    154}
    155
    156static uint16_t adm1272_milliamps_to_direct(uint32_t value)
    157{
    158    PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
    159    /* Y = (m * r_sense * x - b) * 10^R */
    160    c.m = c.m * ADM1272_SHUNT / 1000; /* micro-ohms */
    161    c.b = c.b * 1000;
    162    c.R = c.R - 3;
    163    return pmbus_data2direct_mode(c, value);
    164}
    165
    166static uint32_t adm1272_direct_to_milliamps(uint16_t value)
    167{
    168    PMBusCoefficients c = adm1272_coefficients[ADM1272_CURRENT_COEFF_DEFAULT];
    169    c.m = c.m * ADM1272_SHUNT / 1000;
    170    c.b = c.b * 1000;
    171    c.R = c.R - 3;
    172    return pmbus_direct_mode2data(c, value);
    173}
    174
    175static uint16_t adm1272_watts_to_direct(uint32_t value)
    176{
    177    PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
    178    c.m = c.m * ADM1272_SHUNT / 1000;
    179    return pmbus_data2direct_mode(c, value);
    180}
    181
    182static uint32_t adm1272_direct_to_watts(uint16_t value)
    183{
    184    PMBusCoefficients c = adm1272_coefficients[ADM1272_PWR_COEFF_DEFAULT];
    185    c.m = c.m * ADM1272_SHUNT / 1000;
    186    return pmbus_direct_mode2data(c, value);
    187}
    188
    189static void adm1272_exit_reset(Object *obj)
    190{
    191    ADM1272State *s = ADM1272(obj);
    192    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
    193
    194    pmdev->page = 0;
    195    pmdev->pages[0].operation = ADM1272_OPERATION_DEFAULT;
    196
    197
    198    pmdev->capability = ADM1272_CAPABILITY_NO_PEC;
    199    pmdev->pages[0].revision = ADM1272_PMBUS_REVISION_DEFAULT;
    200    pmdev->pages[0].vout_mode = ADM1272_DIRECT_MODE;
    201    pmdev->pages[0].vout_ov_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
    202    pmdev->pages[0].vout_uv_warn_limit = 0;
    203    pmdev->pages[0].iout_oc_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
    204    pmdev->pages[0].ot_fault_limit = ADM1272_HIGH_LIMIT_DEFAULT;
    205    pmdev->pages[0].ot_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
    206    pmdev->pages[0].vin_ov_warn_limit = ADM1272_HIGH_LIMIT_DEFAULT;
    207    pmdev->pages[0].vin_uv_warn_limit = 0;
    208    pmdev->pages[0].pin_op_warn_limit = ADM1272_PIN_OP_DEFAULT;
    209
    210    pmdev->pages[0].status_word = 0;
    211    pmdev->pages[0].status_vout = 0;
    212    pmdev->pages[0].status_iout = 0;
    213    pmdev->pages[0].status_input = 0;
    214    pmdev->pages[0].status_temperature = 0;
    215    pmdev->pages[0].status_mfr_specific = 0;
    216
    217    pmdev->pages[0].read_vin
    218        = adm1272_millivolts_to_direct(ADM1272_VOLT_DEFAULT);
    219    pmdev->pages[0].read_vout
    220        = adm1272_millivolts_to_direct(ADM1272_VOLT_DEFAULT);
    221    pmdev->pages[0].read_iout
    222        = adm1272_milliamps_to_direct(ADM1272_IOUT_DEFAULT);
    223    pmdev->pages[0].read_temperature_1 = 0;
    224    pmdev->pages[0].read_pin = adm1272_watts_to_direct(ADM1272_PWR_DEFAULT);
    225    pmdev->pages[0].revision = ADM1272_PMBUS_REVISION_DEFAULT;
    226    pmdev->pages[0].mfr_id = ADM1272_MFR_ID_DEFAULT;
    227    pmdev->pages[0].mfr_model = ADM1272_MODEL_DEFAULT;
    228    pmdev->pages[0].mfr_revision = ADM1272_MFR_DEFAULT_REVISION;
    229    pmdev->pages[0].mfr_date = ADM1272_DEFAULT_DATE;
    230
    231    s->pin_ext = 0;
    232    s->ein_ext = 0;
    233    s->restart_time = ADM1272_RESTART_TIME_DEFAULT;
    234
    235    s->peak_vin = 0;
    236    s->peak_vout = 0;
    237    s->peak_iout = 0;
    238    s->peak_temperature = 0;
    239    s->peak_pin = 0;
    240
    241    s->pmon_control = ADM1272_PMON_CONTROL_DEFAULT;
    242    s->pmon_config = ADM1272_PMON_CONFIG_DEFAULT;
    243    s->alert1_config = 0;
    244    s->alert2_config = 0;
    245    s->device_config = ADM1272_DEVICE_CONFIG_DEFAULT;
    246
    247    s->hysteresis_low = 0;
    248    s->hysteresis_high = ADM1272_HYSTERESIS_HIGH_DEFAULT;
    249    s->status_hysteresis = 0;
    250    s->status_gpio = 0;
    251
    252    s->strt_up_iout_lim = ADM1272_STRT_UP_IOUT_LIM_DEFAULT;
    253}
    254
    255static uint8_t adm1272_read_byte(PMBusDevice *pmdev)
    256{
    257    ADM1272State *s = ADM1272(pmdev);
    258
    259    switch (pmdev->code) {
    260    case ADM1272_RESTART_TIME:
    261        pmbus_send8(pmdev, s->restart_time);
    262        break;
    263
    264    case ADM1272_MFR_PEAK_IOUT:
    265        pmbus_send16(pmdev, s->peak_iout);
    266        break;
    267
    268    case ADM1272_MFR_PEAK_VIN:
    269        pmbus_send16(pmdev, s->peak_vin);
    270        break;
    271
    272    case ADM1272_MFR_PEAK_VOUT:
    273        pmbus_send16(pmdev, s->peak_vout);
    274        break;
    275
    276    case ADM1272_MFR_PMON_CONTROL:
    277        pmbus_send8(pmdev, s->pmon_control);
    278        break;
    279
    280    case ADM1272_MFR_PMON_CONFIG:
    281        pmbus_send16(pmdev, s->pmon_config);
    282        break;
    283
    284    case ADM1272_MFR_ALERT1_CONFIG:
    285        pmbus_send16(pmdev, s->alert1_config);
    286        break;
    287
    288    case ADM1272_MFR_ALERT2_CONFIG:
    289        pmbus_send16(pmdev, s->alert2_config);
    290        break;
    291
    292    case ADM1272_MFR_PEAK_TEMPERATURE:
    293        pmbus_send16(pmdev, s->peak_temperature);
    294        break;
    295
    296    case ADM1272_MFR_DEVICE_CONFIG:
    297        pmbus_send16(pmdev, s->device_config);
    298        break;
    299
    300    case ADM1272_MFR_PEAK_PIN:
    301        pmbus_send16(pmdev, s->peak_pin);
    302        break;
    303
    304    case ADM1272_MFR_READ_PIN_EXT:
    305        pmbus_send32(pmdev, s->pin_ext);
    306        break;
    307
    308    case ADM1272_MFR_READ_EIN_EXT:
    309        pmbus_send64(pmdev, s->ein_ext);
    310        break;
    311
    312    case ADM1272_HYSTERESIS_LOW:
    313        pmbus_send16(pmdev, s->hysteresis_low);
    314        break;
    315
    316    case ADM1272_HYSTERESIS_HIGH:
    317        pmbus_send16(pmdev, s->hysteresis_high);
    318        break;
    319
    320    case ADM1272_STATUS_HYSTERESIS:
    321        pmbus_send16(pmdev, s->status_hysteresis);
    322        break;
    323
    324    case ADM1272_STATUS_GPIO:
    325        pmbus_send16(pmdev, s->status_gpio);
    326        break;
    327
    328    case ADM1272_STRT_UP_IOUT_LIM:
    329        pmbus_send16(pmdev, s->strt_up_iout_lim);
    330        break;
    331
    332    default:
    333        qemu_log_mask(LOG_GUEST_ERROR,
    334                      "%s: reading from unsupported register: 0x%02x\n",
    335                      __func__, pmdev->code);
    336        return 0xFF;
    337        break;
    338    }
    339
    340    return 0;
    341}
    342
    343static int adm1272_write_data(PMBusDevice *pmdev, const uint8_t *buf,
    344                              uint8_t len)
    345{
    346    ADM1272State *s = ADM1272(pmdev);
    347
    348    if (len == 0) {
    349        qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
    350        return -1;
    351    }
    352
    353    pmdev->code = buf[0]; /* PMBus command code */
    354
    355    if (len == 1) {
    356        return 0;
    357    }
    358
    359    /* Exclude command code from buffer */
    360    buf++;
    361    len--;
    362
    363    switch (pmdev->code) {
    364
    365    case ADM1272_RESTART_TIME:
    366        s->restart_time = pmbus_receive8(pmdev);
    367        break;
    368
    369    case ADM1272_MFR_PMON_CONTROL:
    370        s->pmon_control = pmbus_receive8(pmdev);
    371        break;
    372
    373    case ADM1272_MFR_PMON_CONFIG:
    374        s->pmon_config = pmbus_receive16(pmdev);
    375        break;
    376
    377    case ADM1272_MFR_ALERT1_CONFIG:
    378        s->alert1_config = pmbus_receive16(pmdev);
    379        break;
    380
    381    case ADM1272_MFR_ALERT2_CONFIG:
    382        s->alert2_config = pmbus_receive16(pmdev);
    383        break;
    384
    385    case ADM1272_MFR_DEVICE_CONFIG:
    386        s->device_config = pmbus_receive16(pmdev);
    387        break;
    388
    389    case ADM1272_MFR_POWER_CYCLE:
    390        adm1272_exit_reset((Object *)s);
    391        break;
    392
    393    case ADM1272_HYSTERESIS_LOW:
    394        s->hysteresis_low = pmbus_receive16(pmdev);
    395        break;
    396
    397    case ADM1272_HYSTERESIS_HIGH:
    398        s->hysteresis_high = pmbus_receive16(pmdev);
    399        break;
    400
    401    case ADM1272_STRT_UP_IOUT_LIM:
    402        s->strt_up_iout_lim = pmbus_receive16(pmdev);
    403        adm1272_check_limits(s);
    404        break;
    405
    406    default:
    407        qemu_log_mask(LOG_GUEST_ERROR,
    408                      "%s: writing to unsupported register: 0x%02x\n",
    409                      __func__, pmdev->code);
    410        break;
    411    }
    412    return 0;
    413}
    414
    415static void adm1272_get(Object *obj, Visitor *v, const char *name, void *opaque,
    416                        Error **errp)
    417{
    418    uint16_t value;
    419
    420    if (strcmp(name, "vin") == 0 || strcmp(name, "vout") == 0) {
    421        value = adm1272_direct_to_millivolts(*(uint16_t *)opaque);
    422    } else if (strcmp(name, "iout") == 0) {
    423        value = adm1272_direct_to_milliamps(*(uint16_t *)opaque);
    424    } else if (strcmp(name, "pin") == 0) {
    425        value = adm1272_direct_to_watts(*(uint16_t *)opaque);
    426    } else {
    427        value = *(uint16_t *)opaque;
    428    }
    429
    430    visit_type_uint16(v, name, &value, errp);
    431}
    432
    433static void adm1272_set(Object *obj, Visitor *v, const char *name, void *opaque,
    434                        Error **errp)
    435{
    436    ADM1272State *s = ADM1272(obj);
    437    uint16_t *internal = opaque;
    438    uint16_t value;
    439
    440    if (!visit_type_uint16(v, name, &value, errp)) {
    441        return;
    442    }
    443
    444    if (strcmp(name, "vin") == 0 || strcmp(name, "vout") == 0) {
    445        *internal = adm1272_millivolts_to_direct(value);
    446    } else if (strcmp(name, "iout") == 0) {
    447        *internal = adm1272_milliamps_to_direct(value);
    448    } else if (strcmp(name, "pin") == 0) {
    449        *internal = adm1272_watts_to_direct(value);
    450    } else {
    451        *internal = value;
    452    }
    453
    454    adm1272_check_limits(s);
    455}
    456
    457static const VMStateDescription vmstate_adm1272 = {
    458    .name = "ADM1272",
    459    .version_id = 0,
    460    .minimum_version_id = 0,
    461    .fields = (VMStateField[]){
    462        VMSTATE_PMBUS_DEVICE(parent, ADM1272State),
    463        VMSTATE_UINT64(ein_ext, ADM1272State),
    464        VMSTATE_UINT32(pin_ext, ADM1272State),
    465        VMSTATE_UINT8(restart_time, ADM1272State),
    466
    467        VMSTATE_UINT16(peak_vin, ADM1272State),
    468        VMSTATE_UINT16(peak_vout, ADM1272State),
    469        VMSTATE_UINT16(peak_iout, ADM1272State),
    470        VMSTATE_UINT16(peak_temperature, ADM1272State),
    471        VMSTATE_UINT16(peak_pin, ADM1272State),
    472
    473        VMSTATE_UINT8(pmon_control, ADM1272State),
    474        VMSTATE_UINT16(pmon_config, ADM1272State),
    475        VMSTATE_UINT16(alert1_config, ADM1272State),
    476        VMSTATE_UINT16(alert2_config, ADM1272State),
    477        VMSTATE_UINT16(device_config, ADM1272State),
    478
    479        VMSTATE_UINT16(hysteresis_low, ADM1272State),
    480        VMSTATE_UINT16(hysteresis_high, ADM1272State),
    481        VMSTATE_UINT8(status_hysteresis, ADM1272State),
    482        VMSTATE_UINT8(status_gpio, ADM1272State),
    483
    484        VMSTATE_UINT16(strt_up_iout_lim, ADM1272State),
    485        VMSTATE_END_OF_LIST()
    486    }
    487};
    488
    489static void adm1272_init(Object *obj)
    490{
    491    PMBusDevice *pmdev = PMBUS_DEVICE(obj);
    492    uint64_t flags = PB_HAS_VOUT_MODE | PB_HAS_VOUT | PB_HAS_VIN | PB_HAS_IOUT |
    493                     PB_HAS_PIN | PB_HAS_TEMPERATURE | PB_HAS_MFR_INFO;
    494
    495    pmbus_page_config(pmdev, 0, flags);
    496
    497    object_property_add(obj, "vin", "uint16",
    498                        adm1272_get,
    499                        adm1272_set, NULL, &pmdev->pages[0].read_vin);
    500
    501    object_property_add(obj, "vout", "uint16",
    502                        adm1272_get,
    503                        adm1272_set, NULL, &pmdev->pages[0].read_vout);
    504
    505    object_property_add(obj, "iout", "uint16",
    506                        adm1272_get,
    507                        adm1272_set, NULL, &pmdev->pages[0].read_iout);
    508
    509    object_property_add(obj, "pin", "uint16",
    510                        adm1272_get,
    511                        adm1272_set, NULL, &pmdev->pages[0].read_pin);
    512
    513}
    514
    515static void adm1272_class_init(ObjectClass *klass, void *data)
    516{
    517    ResettableClass *rc = RESETTABLE_CLASS(klass);
    518    DeviceClass *dc = DEVICE_CLASS(klass);
    519    PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
    520
    521    dc->desc = "Analog Devices ADM1272 Hot Swap controller";
    522    dc->vmsd = &vmstate_adm1272;
    523    k->write_data = adm1272_write_data;
    524    k->receive_byte = adm1272_read_byte;
    525    k->device_num_pages = 1;
    526
    527    rc->phases.exit = adm1272_exit_reset;
    528}
    529
    530static const TypeInfo adm1272_info = {
    531    .name = TYPE_ADM1272,
    532    .parent = TYPE_PMBUS_DEVICE,
    533    .instance_size = sizeof(ADM1272State),
    534    .instance_init = adm1272_init,
    535    .class_init = adm1272_class_init,
    536};
    537
    538static void adm1272_register_types(void)
    539{
    540    type_register_static(&adm1272_info);
    541}
    542
    543type_init(adm1272_register_types)