13746d5c1STitus Rwantare /* 23746d5c1STitus Rwantare * PMBus wrapper over SMBus 33746d5c1STitus Rwantare * 43746d5c1STitus Rwantare * Copyright 2021 Google LLC 53746d5c1STitus Rwantare * 63746d5c1STitus Rwantare * SPDX-License-Identifier: GPL-2.0-or-later 73746d5c1STitus Rwantare */ 83746d5c1STitus Rwantare 93746d5c1STitus Rwantare #include "qemu/osdep.h" 103746d5c1STitus Rwantare #include <math.h> 113746d5c1STitus Rwantare #include "hw/i2c/pmbus_device.h" 123746d5c1STitus Rwantare #include "migration/vmstate.h" 133746d5c1STitus Rwantare #include "qemu/module.h" 143746d5c1STitus Rwantare #include "qemu/log.h" 153746d5c1STitus Rwantare 163746d5c1STitus Rwantare uint16_t pmbus_data2direct_mode(PMBusCoefficients c, uint32_t value) 173746d5c1STitus Rwantare { 183746d5c1STitus Rwantare /* R is usually negative to fit large readings into 16 bits */ 193746d5c1STitus Rwantare uint16_t y = (c.m * value + c.b) * pow(10, c.R); 203746d5c1STitus Rwantare return y; 213746d5c1STitus Rwantare } 223746d5c1STitus Rwantare 233746d5c1STitus Rwantare uint32_t pmbus_direct_mode2data(PMBusCoefficients c, uint16_t value) 243746d5c1STitus Rwantare { 253746d5c1STitus Rwantare /* X = (Y * 10^-R - b) / m */ 263746d5c1STitus Rwantare uint32_t x = (value / pow(10, c.R) - c.b) / c.m; 273746d5c1STitus Rwantare return x; 283746d5c1STitus Rwantare } 293746d5c1STitus Rwantare 30648a4882SShengtan Mao uint16_t pmbus_data2linear_mode(uint16_t value, int exp) 31648a4882SShengtan Mao { 32648a4882SShengtan Mao /* L = D * 2^(-e) */ 33648a4882SShengtan Mao if (exp < 0) { 34648a4882SShengtan Mao return value << (-exp); 35648a4882SShengtan Mao } 36648a4882SShengtan Mao return value >> exp; 37648a4882SShengtan Mao } 38648a4882SShengtan Mao 39648a4882SShengtan Mao uint16_t pmbus_linear_mode2data(uint16_t value, int exp) 40648a4882SShengtan Mao { 41648a4882SShengtan Mao /* D = L * 2^e */ 42648a4882SShengtan Mao if (exp < 0) { 43648a4882SShengtan Mao return value >> (-exp); 44648a4882SShengtan Mao } 45648a4882SShengtan Mao return value << exp; 46648a4882SShengtan Mao } 47648a4882SShengtan Mao 483746d5c1STitus Rwantare void pmbus_send(PMBusDevice *pmdev, const uint8_t *data, uint16_t len) 493746d5c1STitus Rwantare { 503746d5c1STitus Rwantare if (pmdev->out_buf_len + len > SMBUS_DATA_MAX_LEN) { 513746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 523746d5c1STitus Rwantare "PMBus device tried to send too much data"); 533746d5c1STitus Rwantare len = 0; 543746d5c1STitus Rwantare } 553746d5c1STitus Rwantare 563746d5c1STitus Rwantare for (int i = len - 1; i >= 0; i--) { 573746d5c1STitus Rwantare pmdev->out_buf[i + pmdev->out_buf_len] = data[len - i - 1]; 583746d5c1STitus Rwantare } 593746d5c1STitus Rwantare pmdev->out_buf_len += len; 603746d5c1STitus Rwantare } 613746d5c1STitus Rwantare 623746d5c1STitus Rwantare /* Internal only, convert unsigned ints to the little endian bus */ 633746d5c1STitus Rwantare static void pmbus_send_uint(PMBusDevice *pmdev, uint64_t data, uint8_t size) 643746d5c1STitus Rwantare { 653746d5c1STitus Rwantare uint8_t bytes[8]; 663746d5c1STitus Rwantare g_assert(size <= 8); 673746d5c1STitus Rwantare 683746d5c1STitus Rwantare for (int i = 0; i < size; i++) { 693746d5c1STitus Rwantare bytes[i] = data & 0xFF; 703746d5c1STitus Rwantare data = data >> 8; 713746d5c1STitus Rwantare } 723746d5c1STitus Rwantare pmbus_send(pmdev, bytes, size); 733746d5c1STitus Rwantare } 743746d5c1STitus Rwantare 753746d5c1STitus Rwantare void pmbus_send8(PMBusDevice *pmdev, uint8_t data) 763746d5c1STitus Rwantare { 773746d5c1STitus Rwantare pmbus_send_uint(pmdev, data, 1); 783746d5c1STitus Rwantare } 793746d5c1STitus Rwantare 803746d5c1STitus Rwantare void pmbus_send16(PMBusDevice *pmdev, uint16_t data) 813746d5c1STitus Rwantare { 823746d5c1STitus Rwantare pmbus_send_uint(pmdev, data, 2); 833746d5c1STitus Rwantare } 843746d5c1STitus Rwantare 853746d5c1STitus Rwantare void pmbus_send32(PMBusDevice *pmdev, uint32_t data) 863746d5c1STitus Rwantare { 873746d5c1STitus Rwantare pmbus_send_uint(pmdev, data, 4); 883746d5c1STitus Rwantare } 893746d5c1STitus Rwantare 903746d5c1STitus Rwantare void pmbus_send64(PMBusDevice *pmdev, uint64_t data) 913746d5c1STitus Rwantare { 923746d5c1STitus Rwantare pmbus_send_uint(pmdev, data, 8); 933746d5c1STitus Rwantare } 943746d5c1STitus Rwantare 953746d5c1STitus Rwantare void pmbus_send_string(PMBusDevice *pmdev, const char *data) 963746d5c1STitus Rwantare { 9795bf3418STitus Rwantare if (!data) { 9895bf3418STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 9995bf3418STitus Rwantare "%s: %s: uninitialised read from 0x%02x\n", 10095bf3418STitus Rwantare __func__, DEVICE(pmdev)->canonical_path, pmdev->code); 10195bf3418STitus Rwantare return; 10295bf3418STitus Rwantare } 10395bf3418STitus Rwantare 1043746d5c1STitus Rwantare size_t len = strlen(data); 1053746d5c1STitus Rwantare g_assert(len > 0); 1063746d5c1STitus Rwantare g_assert(len + pmdev->out_buf_len < SMBUS_DATA_MAX_LEN); 1073746d5c1STitus Rwantare pmdev->out_buf[len + pmdev->out_buf_len] = len; 1083746d5c1STitus Rwantare 1093746d5c1STitus Rwantare for (int i = len - 1; i >= 0; i--) { 1103746d5c1STitus Rwantare pmdev->out_buf[i + pmdev->out_buf_len] = data[len - 1 - i]; 1113746d5c1STitus Rwantare } 1123746d5c1STitus Rwantare pmdev->out_buf_len += len + 1; 1133746d5c1STitus Rwantare } 1143746d5c1STitus Rwantare 1153746d5c1STitus Rwantare 11678fdfc59STitus Rwantare static uint64_t pmbus_receive_uint(PMBusDevice *pmdev) 1173746d5c1STitus Rwantare { 1183746d5c1STitus Rwantare uint64_t ret = 0; 1193746d5c1STitus Rwantare 1203746d5c1STitus Rwantare /* Exclude command code from return value */ 12178fdfc59STitus Rwantare pmdev->in_buf++; 12278fdfc59STitus Rwantare pmdev->in_buf_len--; 1233746d5c1STitus Rwantare 12478fdfc59STitus Rwantare for (int i = pmdev->in_buf_len - 1; i >= 0; i--) { 12578fdfc59STitus Rwantare ret = ret << 8 | pmdev->in_buf[i]; 1263746d5c1STitus Rwantare } 1273746d5c1STitus Rwantare return ret; 1283746d5c1STitus Rwantare } 1293746d5c1STitus Rwantare 1303746d5c1STitus Rwantare uint8_t pmbus_receive8(PMBusDevice *pmdev) 1313746d5c1STitus Rwantare { 1323746d5c1STitus Rwantare if (pmdev->in_buf_len - 1 != 1) { 1333746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 1343746d5c1STitus Rwantare "%s: length mismatch. Expected 1 byte, got %d bytes\n", 1353746d5c1STitus Rwantare __func__, pmdev->in_buf_len - 1); 1363746d5c1STitus Rwantare } 13778fdfc59STitus Rwantare return pmbus_receive_uint(pmdev); 1383746d5c1STitus Rwantare } 1393746d5c1STitus Rwantare 1403746d5c1STitus Rwantare uint16_t pmbus_receive16(PMBusDevice *pmdev) 1413746d5c1STitus Rwantare { 1423746d5c1STitus Rwantare if (pmdev->in_buf_len - 1 != 2) { 1433746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 1443746d5c1STitus Rwantare "%s: length mismatch. Expected 2 bytes, got %d bytes\n", 1453746d5c1STitus Rwantare __func__, pmdev->in_buf_len - 1); 1463746d5c1STitus Rwantare } 14778fdfc59STitus Rwantare return pmbus_receive_uint(pmdev); 1483746d5c1STitus Rwantare } 1493746d5c1STitus Rwantare 1503746d5c1STitus Rwantare uint32_t pmbus_receive32(PMBusDevice *pmdev) 1513746d5c1STitus Rwantare { 1523746d5c1STitus Rwantare if (pmdev->in_buf_len - 1 != 4) { 1533746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 1543746d5c1STitus Rwantare "%s: length mismatch. Expected 4 bytes, got %d bytes\n", 1553746d5c1STitus Rwantare __func__, pmdev->in_buf_len - 1); 1563746d5c1STitus Rwantare } 15778fdfc59STitus Rwantare return pmbus_receive_uint(pmdev); 1583746d5c1STitus Rwantare } 1593746d5c1STitus Rwantare 1603746d5c1STitus Rwantare uint64_t pmbus_receive64(PMBusDevice *pmdev) 1613746d5c1STitus Rwantare { 1623746d5c1STitus Rwantare if (pmdev->in_buf_len - 1 != 8) { 1633746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 1643746d5c1STitus Rwantare "%s: length mismatch. Expected 8 bytes, got %d bytes\n", 1653746d5c1STitus Rwantare __func__, pmdev->in_buf_len - 1); 1663746d5c1STitus Rwantare } 16778fdfc59STitus Rwantare return pmbus_receive_uint(pmdev); 1683746d5c1STitus Rwantare } 1693746d5c1STitus Rwantare 1703746d5c1STitus Rwantare static uint8_t pmbus_out_buf_pop(PMBusDevice *pmdev) 1713746d5c1STitus Rwantare { 1723746d5c1STitus Rwantare if (pmdev->out_buf_len == 0) { 1733746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 1743746d5c1STitus Rwantare "%s: tried to read from empty buffer", 1753746d5c1STitus Rwantare __func__); 17638870253STitus Rwantare return PMBUS_ERR_BYTE; 1773746d5c1STitus Rwantare } 1783746d5c1STitus Rwantare uint8_t data = pmdev->out_buf[pmdev->out_buf_len - 1]; 1793746d5c1STitus Rwantare pmdev->out_buf_len--; 1803746d5c1STitus Rwantare return data; 1813746d5c1STitus Rwantare } 1823746d5c1STitus Rwantare 1833746d5c1STitus Rwantare static void pmbus_quick_cmd(SMBusDevice *smd, uint8_t read) 1843746d5c1STitus Rwantare { 1853746d5c1STitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(smd); 1863746d5c1STitus Rwantare PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev); 1873746d5c1STitus Rwantare 1883746d5c1STitus Rwantare if (pmdc->quick_cmd) { 1893746d5c1STitus Rwantare pmdc->quick_cmd(pmdev, read); 1903746d5c1STitus Rwantare } 1913746d5c1STitus Rwantare } 1923746d5c1STitus Rwantare 193f0e4588fSPhilippe Mathieu-Daudé static uint8_t pmbus_pages_num(PMBusDevice *pmdev) 194f0e4588fSPhilippe Mathieu-Daudé { 195f0e4588fSPhilippe Mathieu-Daudé const PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev); 196f0e4588fSPhilippe Mathieu-Daudé 197f0e4588fSPhilippe Mathieu-Daudé /* some PMBus devices don't use the PAGE command, so they get 1 page */ 198f0e4588fSPhilippe Mathieu-Daudé return k->device_num_pages ? : 1; 199f0e4588fSPhilippe Mathieu-Daudé } 200f0e4588fSPhilippe Mathieu-Daudé 2013746d5c1STitus Rwantare static void pmbus_pages_alloc(PMBusDevice *pmdev) 2023746d5c1STitus Rwantare { 203f0e4588fSPhilippe Mathieu-Daudé pmdev->num_pages = pmbus_pages_num(pmdev); 204f0e4588fSPhilippe Mathieu-Daudé pmdev->pages = g_new0(PMBusPage, pmdev->num_pages); 2053746d5c1STitus Rwantare } 2063746d5c1STitus Rwantare 2073746d5c1STitus Rwantare void pmbus_check_limits(PMBusDevice *pmdev) 2083746d5c1STitus Rwantare { 2093746d5c1STitus Rwantare for (int i = 0; i < pmdev->num_pages; i++) { 2103746d5c1STitus Rwantare if ((pmdev->pages[i].operation & PB_OP_ON) == 0) { 2113746d5c1STitus Rwantare continue; /* don't check powered off devices */ 2123746d5c1STitus Rwantare } 2133746d5c1STitus Rwantare 2143746d5c1STitus Rwantare if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_fault_limit) { 2153746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_VOUT; 2163746d5c1STitus Rwantare pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_FAULT; 2173746d5c1STitus Rwantare } 2183746d5c1STitus Rwantare 2193746d5c1STitus Rwantare if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_warn_limit) { 2203746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_VOUT; 2213746d5c1STitus Rwantare pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_WARN; 2223746d5c1STitus Rwantare } 2233746d5c1STitus Rwantare 2243746d5c1STitus Rwantare if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_warn_limit) { 2253746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_VOUT; 2263746d5c1STitus Rwantare pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_WARN; 2273746d5c1STitus Rwantare } 2283746d5c1STitus Rwantare 2293746d5c1STitus Rwantare if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_fault_limit) { 2303746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_VOUT; 2313746d5c1STitus Rwantare pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_FAULT; 2323746d5c1STitus Rwantare } 2333746d5c1STitus Rwantare 2343746d5c1STitus Rwantare if (pmdev->pages[i].read_vin > pmdev->pages[i].vin_ov_warn_limit) { 2353746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_INPUT; 2363746d5c1STitus Rwantare pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_OV_WARN; 2373746d5c1STitus Rwantare } 2383746d5c1STitus Rwantare 2393746d5c1STitus Rwantare if (pmdev->pages[i].read_vin < pmdev->pages[i].vin_uv_warn_limit) { 2403746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_INPUT; 2413746d5c1STitus Rwantare pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_UV_WARN; 2423746d5c1STitus Rwantare } 2433746d5c1STitus Rwantare 2443746d5c1STitus Rwantare if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_warn_limit) { 2453746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT; 2463746d5c1STitus Rwantare pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_WARN; 2473746d5c1STitus Rwantare } 2483746d5c1STitus Rwantare 2493746d5c1STitus Rwantare if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_fault_limit) { 2503746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT; 2513746d5c1STitus Rwantare pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_FAULT; 2523746d5c1STitus Rwantare } 2533746d5c1STitus Rwantare 2543746d5c1STitus Rwantare if (pmdev->pages[i].read_pin > pmdev->pages[i].pin_op_warn_limit) { 2553746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_INPUT; 2563746d5c1STitus Rwantare pmdev->pages[i].status_input |= PB_STATUS_INPUT_PIN_OP_WARN; 2573746d5c1STitus Rwantare } 2583746d5c1STitus Rwantare 2593746d5c1STitus Rwantare if (pmdev->pages[i].read_temperature_1 2603746d5c1STitus Rwantare > pmdev->pages[i].ot_fault_limit) { 2613746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE; 2623746d5c1STitus Rwantare pmdev->pages[i].status_temperature |= PB_STATUS_OT_FAULT; 2633746d5c1STitus Rwantare } 2643746d5c1STitus Rwantare 2653746d5c1STitus Rwantare if (pmdev->pages[i].read_temperature_1 2663746d5c1STitus Rwantare > pmdev->pages[i].ot_warn_limit) { 2673746d5c1STitus Rwantare pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE; 2683746d5c1STitus Rwantare pmdev->pages[i].status_temperature |= PB_STATUS_OT_WARN; 2693746d5c1STitus Rwantare } 2703746d5c1STitus Rwantare } 2713746d5c1STitus Rwantare } 2723746d5c1STitus Rwantare 273d272d141SPeter Delevoryas void pmbus_idle(PMBusDevice *pmdev) 274d272d141SPeter Delevoryas { 275d272d141SPeter Delevoryas pmdev->code = PMBUS_IDLE_STATE; 276d272d141SPeter Delevoryas } 277d272d141SPeter Delevoryas 27838870253STitus Rwantare /* assert the status_cml error upon receipt of malformed command */ 27938870253STitus Rwantare static void pmbus_cml_error(PMBusDevice *pmdev) 28038870253STitus Rwantare { 28138870253STitus Rwantare for (int i = 0; i < pmdev->num_pages; i++) { 28238870253STitus Rwantare pmdev->pages[i].status_word |= PMBUS_STATUS_CML; 28338870253STitus Rwantare pmdev->pages[i].status_cml |= PB_CML_FAULT_INVALID_CMD; 28438870253STitus Rwantare } 28538870253STitus Rwantare } 28638870253STitus Rwantare 2873746d5c1STitus Rwantare static uint8_t pmbus_receive_byte(SMBusDevice *smd) 2883746d5c1STitus Rwantare { 2893746d5c1STitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(smd); 2903746d5c1STitus Rwantare PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev); 29138870253STitus Rwantare uint8_t ret = PMBUS_ERR_BYTE; 29238870253STitus Rwantare uint8_t index; 2933746d5c1STitus Rwantare 2943746d5c1STitus Rwantare if (pmdev->out_buf_len != 0) { 2953746d5c1STitus Rwantare ret = pmbus_out_buf_pop(pmdev); 2963746d5c1STitus Rwantare return ret; 2973746d5c1STitus Rwantare } 2983746d5c1STitus Rwantare 29938870253STitus Rwantare /* 30038870253STitus Rwantare * Reading from all pages will return the value from page 0, 301dd0b3271SMaheswara Kurapati * means that all subsequent commands are to be applied to all output. 30238870253STitus Rwantare */ 30338870253STitus Rwantare if (pmdev->page == PB_ALL_PAGES) { 30438870253STitus Rwantare index = 0; 30538870253STitus Rwantare } else if (pmdev->page > pmdev->num_pages - 1) { 30638870253STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 30738870253STitus Rwantare "%s: page %d is out of range\n", 30838870253STitus Rwantare __func__, pmdev->page); 30938870253STitus Rwantare pmbus_cml_error(pmdev); 31038870253STitus Rwantare return PMBUS_ERR_BYTE; 31138870253STitus Rwantare } else { 31238870253STitus Rwantare index = pmdev->page; 31338870253STitus Rwantare } 31438870253STitus Rwantare 3153746d5c1STitus Rwantare switch (pmdev->code) { 3163746d5c1STitus Rwantare case PMBUS_PAGE: 3173746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->page); 3183746d5c1STitus Rwantare break; 3193746d5c1STitus Rwantare 3203746d5c1STitus Rwantare case PMBUS_OPERATION: /* R/W byte */ 3213746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].operation); 3223746d5c1STitus Rwantare break; 3233746d5c1STitus Rwantare 3243746d5c1STitus Rwantare case PMBUS_ON_OFF_CONFIG: /* R/W byte */ 3253746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].on_off_config); 3263746d5c1STitus Rwantare break; 3273746d5c1STitus Rwantare 3283746d5c1STitus Rwantare case PMBUS_PHASE: /* R/W byte */ 3293746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].phase); 3303746d5c1STitus Rwantare break; 3313746d5c1STitus Rwantare 3323746d5c1STitus Rwantare case PMBUS_WRITE_PROTECT: /* R/W byte */ 3333746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].write_protect); 3343746d5c1STitus Rwantare break; 3353746d5c1STitus Rwantare 3363746d5c1STitus Rwantare case PMBUS_CAPABILITY: 3373746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->capability); 3382192aaaeSTitus Rwantare if (pmdev->capability & BIT(7)) { 3392192aaaeSTitus Rwantare qemu_log_mask(LOG_UNIMP, 3402192aaaeSTitus Rwantare "%s: PEC is enabled but not yet supported.\n", 3412192aaaeSTitus Rwantare __func__); 3422192aaaeSTitus Rwantare } 3433746d5c1STitus Rwantare break; 3443746d5c1STitus Rwantare 3453746d5c1STitus Rwantare case PMBUS_VOUT_MODE: /* R/W byte */ 3463746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) { 3473746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].vout_mode); 3483746d5c1STitus Rwantare } else { 3493746d5c1STitus Rwantare goto passthough; 3503746d5c1STitus Rwantare } 3513746d5c1STitus Rwantare break; 3523746d5c1STitus Rwantare 3533746d5c1STitus Rwantare case PMBUS_VOUT_COMMAND: /* R/W word */ 3543746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 3553746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_command); 3563746d5c1STitus Rwantare } else { 3573746d5c1STitus Rwantare goto passthough; 3583746d5c1STitus Rwantare } 3593746d5c1STitus Rwantare break; 3603746d5c1STitus Rwantare 3613746d5c1STitus Rwantare case PMBUS_VOUT_TRIM: /* R/W word */ 3623746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 3633746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_trim); 3643746d5c1STitus Rwantare } else { 3653746d5c1STitus Rwantare goto passthough; 3663746d5c1STitus Rwantare } 3673746d5c1STitus Rwantare break; 3683746d5c1STitus Rwantare 3693746d5c1STitus Rwantare case PMBUS_VOUT_CAL_OFFSET: /* R/W word */ 3703746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 3713746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_cal_offset); 3723746d5c1STitus Rwantare } else { 3733746d5c1STitus Rwantare goto passthough; 3743746d5c1STitus Rwantare } 3753746d5c1STitus Rwantare break; 3763746d5c1STitus Rwantare 3773746d5c1STitus Rwantare case PMBUS_VOUT_MAX: /* R/W word */ 3783746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 3793746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_max); 3803746d5c1STitus Rwantare } else { 3813746d5c1STitus Rwantare goto passthough; 3823746d5c1STitus Rwantare } 3833746d5c1STitus Rwantare break; 3843746d5c1STitus Rwantare 3853746d5c1STitus Rwantare case PMBUS_VOUT_MARGIN_HIGH: /* R/W word */ 3863746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 3873746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_margin_high); 3883746d5c1STitus Rwantare } else { 3893746d5c1STitus Rwantare goto passthough; 3903746d5c1STitus Rwantare } 3913746d5c1STitus Rwantare break; 3923746d5c1STitus Rwantare 3933746d5c1STitus Rwantare case PMBUS_VOUT_MARGIN_LOW: /* R/W word */ 3943746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 3953746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_margin_low); 3963746d5c1STitus Rwantare } else { 3973746d5c1STitus Rwantare goto passthough; 3983746d5c1STitus Rwantare } 3993746d5c1STitus Rwantare break; 4003746d5c1STitus Rwantare 4013746d5c1STitus Rwantare case PMBUS_VOUT_TRANSITION_RATE: /* R/W word */ 4023746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 4033746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_transition_rate); 4043746d5c1STitus Rwantare } else { 4053746d5c1STitus Rwantare goto passthough; 4063746d5c1STitus Rwantare } 4073746d5c1STitus Rwantare break; 4083746d5c1STitus Rwantare 4093746d5c1STitus Rwantare case PMBUS_VOUT_DROOP: /* R/W word */ 4103746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 4113746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_droop); 4123746d5c1STitus Rwantare } else { 4133746d5c1STitus Rwantare goto passthough; 4143746d5c1STitus Rwantare } 4153746d5c1STitus Rwantare break; 4163746d5c1STitus Rwantare 4173746d5c1STitus Rwantare case PMBUS_VOUT_SCALE_LOOP: /* R/W word */ 4183746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 4193746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_scale_loop); 4203746d5c1STitus Rwantare } else { 4213746d5c1STitus Rwantare goto passthough; 4223746d5c1STitus Rwantare } 4233746d5c1STitus Rwantare break; 4243746d5c1STitus Rwantare 4253746d5c1STitus Rwantare case PMBUS_VOUT_SCALE_MONITOR: /* R/W word */ 4263746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 4273746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_scale_monitor); 4283746d5c1STitus Rwantare } else { 4293746d5c1STitus Rwantare goto passthough; 4303746d5c1STitus Rwantare } 4313746d5c1STitus Rwantare break; 4323746d5c1STitus Rwantare 43332480293STitus Rwantare case PMBUS_VOUT_MIN: /* R/W word */ 43432480293STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 43532480293STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_min); 43632480293STitus Rwantare } else { 43732480293STitus Rwantare goto passthough; 43832480293STitus Rwantare } 43932480293STitus Rwantare break; 44032480293STitus Rwantare 4413746d5c1STitus Rwantare /* TODO: implement coefficients support */ 4423746d5c1STitus Rwantare 4433746d5c1STitus Rwantare case PMBUS_POUT_MAX: /* R/W word */ 4443746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 4453746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].pout_max); 4463746d5c1STitus Rwantare } else { 4473746d5c1STitus Rwantare goto passthough; 4483746d5c1STitus Rwantare } 4493746d5c1STitus Rwantare break; 4503746d5c1STitus Rwantare 4513746d5c1STitus Rwantare case PMBUS_VIN_ON: /* R/W word */ 4523746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 4533746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vin_on); 4543746d5c1STitus Rwantare } else { 4553746d5c1STitus Rwantare goto passthough; 4563746d5c1STitus Rwantare } 4573746d5c1STitus Rwantare break; 4583746d5c1STitus Rwantare 4593746d5c1STitus Rwantare case PMBUS_VIN_OFF: /* R/W word */ 4603746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 4613746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vin_off); 4623746d5c1STitus Rwantare } else { 4633746d5c1STitus Rwantare goto passthough; 4643746d5c1STitus Rwantare } 4653746d5c1STitus Rwantare break; 4663746d5c1STitus Rwantare 4673746d5c1STitus Rwantare case PMBUS_IOUT_CAL_GAIN: /* R/W word */ 4683746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) { 4693746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].iout_cal_gain); 4703746d5c1STitus Rwantare } else { 4713746d5c1STitus Rwantare goto passthough; 4723746d5c1STitus Rwantare } 4733746d5c1STitus Rwantare break; 4743746d5c1STitus Rwantare 4753746d5c1STitus Rwantare case PMBUS_VOUT_OV_FAULT_LIMIT: /* R/W word */ 4763746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 4773746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_ov_fault_limit); 4783746d5c1STitus Rwantare } else { 4793746d5c1STitus Rwantare goto passthough; 4803746d5c1STitus Rwantare } 4813746d5c1STitus Rwantare break; 4823746d5c1STitus Rwantare 4833746d5c1STitus Rwantare case PMBUS_VOUT_OV_FAULT_RESPONSE: /* R/W byte */ 4843746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 4853746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].vout_ov_fault_response); 4863746d5c1STitus Rwantare } else { 4873746d5c1STitus Rwantare goto passthough; 4883746d5c1STitus Rwantare } 4893746d5c1STitus Rwantare break; 4903746d5c1STitus Rwantare 4913746d5c1STitus Rwantare case PMBUS_VOUT_OV_WARN_LIMIT: /* R/W word */ 4923746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 4933746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_ov_warn_limit); 4943746d5c1STitus Rwantare } else { 4953746d5c1STitus Rwantare goto passthough; 4963746d5c1STitus Rwantare } 4973746d5c1STitus Rwantare break; 4983746d5c1STitus Rwantare 4993746d5c1STitus Rwantare case PMBUS_VOUT_UV_WARN_LIMIT: /* R/W word */ 5003746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 5013746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_uv_warn_limit); 5023746d5c1STitus Rwantare } else { 5033746d5c1STitus Rwantare goto passthough; 5043746d5c1STitus Rwantare } 5053746d5c1STitus Rwantare break; 5063746d5c1STitus Rwantare 5073746d5c1STitus Rwantare case PMBUS_VOUT_UV_FAULT_LIMIT: /* R/W word */ 5083746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 5093746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vout_uv_fault_limit); 5103746d5c1STitus Rwantare } else { 5113746d5c1STitus Rwantare goto passthough; 5123746d5c1STitus Rwantare } 5133746d5c1STitus Rwantare break; 5143746d5c1STitus Rwantare 5153746d5c1STitus Rwantare case PMBUS_VOUT_UV_FAULT_RESPONSE: /* R/W byte */ 5163746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 5173746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].vout_uv_fault_response); 5183746d5c1STitus Rwantare } else { 5193746d5c1STitus Rwantare goto passthough; 5203746d5c1STitus Rwantare } 5213746d5c1STitus Rwantare break; 5223746d5c1STitus Rwantare 5233746d5c1STitus Rwantare case PMBUS_IOUT_OC_FAULT_LIMIT: /* R/W word */ 5243746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 5253746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].iout_oc_fault_limit); 5263746d5c1STitus Rwantare } else { 5273746d5c1STitus Rwantare goto passthough; 5283746d5c1STitus Rwantare } 5293746d5c1STitus Rwantare break; 5303746d5c1STitus Rwantare 5313746d5c1STitus Rwantare case PMBUS_IOUT_OC_FAULT_RESPONSE: /* R/W byte */ 5323746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 5333746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].iout_oc_fault_response); 5343746d5c1STitus Rwantare } else { 5353746d5c1STitus Rwantare goto passthough; 5363746d5c1STitus Rwantare } 5373746d5c1STitus Rwantare break; 5383746d5c1STitus Rwantare 5393746d5c1STitus Rwantare case PMBUS_IOUT_OC_LV_FAULT_LIMIT: /* R/W word */ 5403746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 5413746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].iout_oc_lv_fault_limit); 5423746d5c1STitus Rwantare } else { 5433746d5c1STitus Rwantare goto passthough; 5443746d5c1STitus Rwantare } 5453746d5c1STitus Rwantare break; 5463746d5c1STitus Rwantare 5473746d5c1STitus Rwantare case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */ 5483746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 5493746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].iout_oc_lv_fault_response); 5503746d5c1STitus Rwantare } else { 5513746d5c1STitus Rwantare goto passthough; 5523746d5c1STitus Rwantare } 5533746d5c1STitus Rwantare break; 5543746d5c1STitus Rwantare 5553746d5c1STitus Rwantare case PMBUS_IOUT_OC_WARN_LIMIT: /* R/W word */ 5563746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 5573746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].iout_oc_warn_limit); 5583746d5c1STitus Rwantare } else { 5593746d5c1STitus Rwantare goto passthough; 5603746d5c1STitus Rwantare } 5613746d5c1STitus Rwantare break; 5623746d5c1STitus Rwantare 5633746d5c1STitus Rwantare case PMBUS_IOUT_UC_FAULT_LIMIT: /* R/W word */ 5643746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 5653746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].iout_uc_fault_limit); 5663746d5c1STitus Rwantare } else { 5673746d5c1STitus Rwantare goto passthough; 5683746d5c1STitus Rwantare } 5693746d5c1STitus Rwantare break; 5703746d5c1STitus Rwantare 5713746d5c1STitus Rwantare case PMBUS_IOUT_UC_FAULT_RESPONSE: /* R/W byte */ 5723746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 5733746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].iout_uc_fault_response); 5743746d5c1STitus Rwantare } else { 5753746d5c1STitus Rwantare goto passthough; 5763746d5c1STitus Rwantare } 5773746d5c1STitus Rwantare break; 5783746d5c1STitus Rwantare 5793746d5c1STitus Rwantare case PMBUS_OT_FAULT_LIMIT: /* R/W word */ 5803746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 5813746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].ot_fault_limit); 5823746d5c1STitus Rwantare } else { 5833746d5c1STitus Rwantare goto passthough; 5843746d5c1STitus Rwantare } 5853746d5c1STitus Rwantare break; 5863746d5c1STitus Rwantare 5873746d5c1STitus Rwantare case PMBUS_OT_FAULT_RESPONSE: /* R/W byte */ 5883746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 5893746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].ot_fault_response); 5903746d5c1STitus Rwantare } else { 5913746d5c1STitus Rwantare goto passthough; 5923746d5c1STitus Rwantare } 5933746d5c1STitus Rwantare break; 5943746d5c1STitus Rwantare 5953746d5c1STitus Rwantare case PMBUS_OT_WARN_LIMIT: /* R/W word */ 5963746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 5973746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].ot_warn_limit); 5983746d5c1STitus Rwantare } else { 5993746d5c1STitus Rwantare goto passthough; 6003746d5c1STitus Rwantare } 6013746d5c1STitus Rwantare break; 6023746d5c1STitus Rwantare 6033746d5c1STitus Rwantare case PMBUS_UT_WARN_LIMIT: /* R/W word */ 6043746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 6053746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].ut_warn_limit); 6063746d5c1STitus Rwantare } else { 6073746d5c1STitus Rwantare goto passthough; 6083746d5c1STitus Rwantare } 6093746d5c1STitus Rwantare break; 6103746d5c1STitus Rwantare 6113746d5c1STitus Rwantare case PMBUS_UT_FAULT_LIMIT: /* R/W word */ 6123746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 6133746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].ut_fault_limit); 6143746d5c1STitus Rwantare } else { 6153746d5c1STitus Rwantare goto passthough; 6163746d5c1STitus Rwantare } 6173746d5c1STitus Rwantare break; 6183746d5c1STitus Rwantare 6193746d5c1STitus Rwantare case PMBUS_UT_FAULT_RESPONSE: /* R/W byte */ 6203746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 6213746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].ut_fault_response); 6223746d5c1STitus Rwantare } else { 6233746d5c1STitus Rwantare goto passthough; 6243746d5c1STitus Rwantare } 6253746d5c1STitus Rwantare break; 6263746d5c1STitus Rwantare 6273746d5c1STitus Rwantare case PMBUS_VIN_OV_FAULT_LIMIT: /* R/W word */ 6283746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 6293746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vin_ov_fault_limit); 6303746d5c1STitus Rwantare } else { 6313746d5c1STitus Rwantare goto passthough; 6323746d5c1STitus Rwantare } 6333746d5c1STitus Rwantare break; 6343746d5c1STitus Rwantare 6353746d5c1STitus Rwantare case PMBUS_VIN_OV_FAULT_RESPONSE: /* R/W byte */ 6363746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 6373746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].vin_ov_fault_response); 6383746d5c1STitus Rwantare } else { 6393746d5c1STitus Rwantare goto passthough; 6403746d5c1STitus Rwantare } 6413746d5c1STitus Rwantare break; 6423746d5c1STitus Rwantare 6433746d5c1STitus Rwantare case PMBUS_VIN_OV_WARN_LIMIT: /* R/W word */ 6443746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 6453746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vin_ov_warn_limit); 6463746d5c1STitus Rwantare } else { 6473746d5c1STitus Rwantare goto passthough; 6483746d5c1STitus Rwantare } 6493746d5c1STitus Rwantare break; 6503746d5c1STitus Rwantare 6513746d5c1STitus Rwantare case PMBUS_VIN_UV_WARN_LIMIT: /* R/W word */ 6523746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 6533746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vin_uv_warn_limit); 6543746d5c1STitus Rwantare } else { 6553746d5c1STitus Rwantare goto passthough; 6563746d5c1STitus Rwantare } 6573746d5c1STitus Rwantare break; 6583746d5c1STitus Rwantare 6593746d5c1STitus Rwantare case PMBUS_VIN_UV_FAULT_LIMIT: /* R/W word */ 6603746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 6613746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].vin_uv_fault_limit); 6623746d5c1STitus Rwantare } else { 6633746d5c1STitus Rwantare goto passthough; 6643746d5c1STitus Rwantare } 6653746d5c1STitus Rwantare break; 6663746d5c1STitus Rwantare 6673746d5c1STitus Rwantare case PMBUS_VIN_UV_FAULT_RESPONSE: /* R/W byte */ 6683746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 6693746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].vin_uv_fault_response); 6703746d5c1STitus Rwantare } else { 6713746d5c1STitus Rwantare goto passthough; 6723746d5c1STitus Rwantare } 6733746d5c1STitus Rwantare break; 6743746d5c1STitus Rwantare 6753746d5c1STitus Rwantare case PMBUS_IIN_OC_FAULT_LIMIT: /* R/W word */ 6763746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 6773746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].iin_oc_fault_limit); 6783746d5c1STitus Rwantare } else { 6793746d5c1STitus Rwantare goto passthough; 6803746d5c1STitus Rwantare } 6813746d5c1STitus Rwantare break; 6823746d5c1STitus Rwantare 6833746d5c1STitus Rwantare case PMBUS_IIN_OC_FAULT_RESPONSE: /* R/W byte */ 6843746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 6853746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].iin_oc_fault_response); 6863746d5c1STitus Rwantare } else { 6873746d5c1STitus Rwantare goto passthough; 6883746d5c1STitus Rwantare } 6893746d5c1STitus Rwantare break; 6903746d5c1STitus Rwantare 6913746d5c1STitus Rwantare case PMBUS_IIN_OC_WARN_LIMIT: /* R/W word */ 6923746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 6933746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].iin_oc_warn_limit); 6943746d5c1STitus Rwantare } else { 6953746d5c1STitus Rwantare goto passthough; 6963746d5c1STitus Rwantare } 6973746d5c1STitus Rwantare break; 6983746d5c1STitus Rwantare 6993746d5c1STitus Rwantare case PMBUS_POUT_OP_FAULT_LIMIT: /* R/W word */ 7003746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 7013746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].pout_op_fault_limit); 7023746d5c1STitus Rwantare } else { 7033746d5c1STitus Rwantare goto passthough; 7043746d5c1STitus Rwantare } 7053746d5c1STitus Rwantare break; 7063746d5c1STitus Rwantare 7073746d5c1STitus Rwantare case PMBUS_POUT_OP_FAULT_RESPONSE: /* R/W byte */ 7083746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 7093746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].pout_op_fault_response); 7103746d5c1STitus Rwantare } else { 7113746d5c1STitus Rwantare goto passthough; 7123746d5c1STitus Rwantare } 7133746d5c1STitus Rwantare break; 7143746d5c1STitus Rwantare 7153746d5c1STitus Rwantare case PMBUS_POUT_OP_WARN_LIMIT: /* R/W word */ 7163746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 7173746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].pout_op_warn_limit); 7183746d5c1STitus Rwantare } else { 7193746d5c1STitus Rwantare goto passthough; 7203746d5c1STitus Rwantare } 7213746d5c1STitus Rwantare break; 7223746d5c1STitus Rwantare 7233746d5c1STitus Rwantare case PMBUS_PIN_OP_WARN_LIMIT: /* R/W word */ 7243746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_PIN) { 7253746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].pin_op_warn_limit); 7263746d5c1STitus Rwantare } else { 7273746d5c1STitus Rwantare goto passthough; 7283746d5c1STitus Rwantare } 7293746d5c1STitus Rwantare break; 7303746d5c1STitus Rwantare 7313746d5c1STitus Rwantare case PMBUS_STATUS_BYTE: /* R/W byte */ 7323746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_word & 0xFF); 7333746d5c1STitus Rwantare break; 7343746d5c1STitus Rwantare 7353746d5c1STitus Rwantare case PMBUS_STATUS_WORD: /* R/W word */ 7363746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].status_word); 7373746d5c1STitus Rwantare break; 7383746d5c1STitus Rwantare 7393746d5c1STitus Rwantare case PMBUS_STATUS_VOUT: /* R/W byte */ 7403746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 7413746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_vout); 7423746d5c1STitus Rwantare } else { 7433746d5c1STitus Rwantare goto passthough; 7443746d5c1STitus Rwantare } 7453746d5c1STitus Rwantare break; 7463746d5c1STitus Rwantare 7473746d5c1STitus Rwantare case PMBUS_STATUS_IOUT: /* R/W byte */ 7483746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 7493746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_iout); 7503746d5c1STitus Rwantare } else { 7513746d5c1STitus Rwantare goto passthough; 7523746d5c1STitus Rwantare } 7533746d5c1STitus Rwantare break; 7543746d5c1STitus Rwantare 7553746d5c1STitus Rwantare case PMBUS_STATUS_INPUT: /* R/W byte */ 7563746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN || 7573746d5c1STitus Rwantare pmdev->pages[index].page_flags & PB_HAS_IIN || 7583746d5c1STitus Rwantare pmdev->pages[index].page_flags & PB_HAS_PIN) { 7593746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_input); 7603746d5c1STitus Rwantare } else { 7613746d5c1STitus Rwantare goto passthough; 7623746d5c1STitus Rwantare } 7633746d5c1STitus Rwantare break; 7643746d5c1STitus Rwantare 7653746d5c1STitus Rwantare case PMBUS_STATUS_TEMPERATURE: /* R/W byte */ 7663746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 7673746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_temperature); 7683746d5c1STitus Rwantare } else { 7693746d5c1STitus Rwantare goto passthough; 7703746d5c1STitus Rwantare } 7713746d5c1STitus Rwantare break; 7723746d5c1STitus Rwantare 7733746d5c1STitus Rwantare case PMBUS_STATUS_CML: /* R/W byte */ 7743746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_cml); 7753746d5c1STitus Rwantare break; 7763746d5c1STitus Rwantare 7773746d5c1STitus Rwantare case PMBUS_STATUS_OTHER: /* R/W byte */ 7783746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_other); 7793746d5c1STitus Rwantare break; 7803746d5c1STitus Rwantare 78132480293STitus Rwantare case PMBUS_STATUS_MFR_SPECIFIC: /* R/W byte */ 78232480293STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].status_mfr_specific); 78332480293STitus Rwantare break; 78432480293STitus Rwantare 7853746d5c1STitus Rwantare case PMBUS_READ_EIN: /* Read-Only block 5 bytes */ 7863746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_EIN) { 7873746d5c1STitus Rwantare pmbus_send(pmdev, pmdev->pages[index].read_ein, 5); 7883746d5c1STitus Rwantare } else { 7893746d5c1STitus Rwantare goto passthough; 7903746d5c1STitus Rwantare } 7913746d5c1STitus Rwantare break; 7923746d5c1STitus Rwantare 7933746d5c1STitus Rwantare case PMBUS_READ_EOUT: /* Read-Only block 5 bytes */ 7943746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_EOUT) { 7953746d5c1STitus Rwantare pmbus_send(pmdev, pmdev->pages[index].read_eout, 5); 7963746d5c1STitus Rwantare } else { 7973746d5c1STitus Rwantare goto passthough; 7983746d5c1STitus Rwantare } 7993746d5c1STitus Rwantare break; 8003746d5c1STitus Rwantare 8013746d5c1STitus Rwantare case PMBUS_READ_VIN: /* Read-Only word */ 8023746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 8033746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_vin); 8043746d5c1STitus Rwantare } else { 8053746d5c1STitus Rwantare goto passthough; 8063746d5c1STitus Rwantare } 8073746d5c1STitus Rwantare break; 8083746d5c1STitus Rwantare 8093746d5c1STitus Rwantare case PMBUS_READ_IIN: /* Read-Only word */ 8103746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 8113746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_iin); 8123746d5c1STitus Rwantare } else { 8133746d5c1STitus Rwantare goto passthough; 8143746d5c1STitus Rwantare } 8153746d5c1STitus Rwantare break; 8163746d5c1STitus Rwantare 8173746d5c1STitus Rwantare case PMBUS_READ_VOUT: /* Read-Only word */ 8183746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 8193746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_vout); 8203746d5c1STitus Rwantare } else { 8213746d5c1STitus Rwantare goto passthough; 8223746d5c1STitus Rwantare } 8233746d5c1STitus Rwantare break; 8243746d5c1STitus Rwantare 8253746d5c1STitus Rwantare case PMBUS_READ_IOUT: /* Read-Only word */ 8263746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 8273746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_iout); 8283746d5c1STitus Rwantare } else { 8293746d5c1STitus Rwantare goto passthough; 8303746d5c1STitus Rwantare } 8313746d5c1STitus Rwantare break; 8323746d5c1STitus Rwantare 8333746d5c1STitus Rwantare case PMBUS_READ_TEMPERATURE_1: /* Read-Only word */ 8343746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 8353746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_temperature_1); 8363746d5c1STitus Rwantare } else { 8373746d5c1STitus Rwantare goto passthough; 8383746d5c1STitus Rwantare } 8393746d5c1STitus Rwantare break; 8403746d5c1STitus Rwantare 8413746d5c1STitus Rwantare case PMBUS_READ_TEMPERATURE_2: /* Read-Only word */ 8423746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMP2) { 8433746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_temperature_2); 8443746d5c1STitus Rwantare } else { 8453746d5c1STitus Rwantare goto passthough; 8463746d5c1STitus Rwantare } 8473746d5c1STitus Rwantare break; 8483746d5c1STitus Rwantare 8493746d5c1STitus Rwantare case PMBUS_READ_TEMPERATURE_3: /* Read-Only word */ 8503746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMP3) { 8513746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_temperature_3); 8523746d5c1STitus Rwantare } else { 8533746d5c1STitus Rwantare goto passthough; 8543746d5c1STitus Rwantare } 8553746d5c1STitus Rwantare break; 8563746d5c1STitus Rwantare 8573746d5c1STitus Rwantare case PMBUS_READ_POUT: /* Read-Only word */ 8583746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 8593746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_pout); 8603746d5c1STitus Rwantare } else { 8613746d5c1STitus Rwantare goto passthough; 8623746d5c1STitus Rwantare } 8633746d5c1STitus Rwantare break; 8643746d5c1STitus Rwantare 8653746d5c1STitus Rwantare case PMBUS_READ_PIN: /* Read-Only word */ 8663746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_PIN) { 8673746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].read_pin); 8683746d5c1STitus Rwantare } else { 8693746d5c1STitus Rwantare goto passthough; 8703746d5c1STitus Rwantare } 8713746d5c1STitus Rwantare break; 8723746d5c1STitus Rwantare 8733746d5c1STitus Rwantare case PMBUS_REVISION: /* Read-Only byte */ 8743746d5c1STitus Rwantare pmbus_send8(pmdev, pmdev->pages[index].revision); 8753746d5c1STitus Rwantare break; 8763746d5c1STitus Rwantare 8773746d5c1STitus Rwantare case PMBUS_MFR_ID: /* R/W block */ 8783746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 8793746d5c1STitus Rwantare pmbus_send_string(pmdev, pmdev->pages[index].mfr_id); 8803746d5c1STitus Rwantare } else { 8813746d5c1STitus Rwantare goto passthough; 8823746d5c1STitus Rwantare } 8833746d5c1STitus Rwantare break; 8843746d5c1STitus Rwantare 8853746d5c1STitus Rwantare case PMBUS_MFR_MODEL: /* R/W block */ 8863746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 8873746d5c1STitus Rwantare pmbus_send_string(pmdev, pmdev->pages[index].mfr_model); 8883746d5c1STitus Rwantare } else { 8893746d5c1STitus Rwantare goto passthough; 8903746d5c1STitus Rwantare } 8913746d5c1STitus Rwantare break; 8923746d5c1STitus Rwantare 8933746d5c1STitus Rwantare case PMBUS_MFR_REVISION: /* R/W block */ 8943746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 8953746d5c1STitus Rwantare pmbus_send_string(pmdev, pmdev->pages[index].mfr_revision); 8963746d5c1STitus Rwantare } else { 8973746d5c1STitus Rwantare goto passthough; 8983746d5c1STitus Rwantare } 8993746d5c1STitus Rwantare break; 9003746d5c1STitus Rwantare 9013746d5c1STitus Rwantare case PMBUS_MFR_LOCATION: /* R/W block */ 9023746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 9033746d5c1STitus Rwantare pmbus_send_string(pmdev, pmdev->pages[index].mfr_location); 9043746d5c1STitus Rwantare } else { 9053746d5c1STitus Rwantare goto passthough; 9063746d5c1STitus Rwantare } 9073746d5c1STitus Rwantare break; 9083746d5c1STitus Rwantare 9093746d5c1STitus Rwantare case PMBUS_MFR_VIN_MIN: /* Read-Only word */ 9103746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) { 9113746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_min); 9123746d5c1STitus Rwantare } else { 9133746d5c1STitus Rwantare goto passthough; 9143746d5c1STitus Rwantare } 9153746d5c1STitus Rwantare break; 9163746d5c1STitus Rwantare 9173746d5c1STitus Rwantare case PMBUS_MFR_VIN_MAX: /* Read-Only word */ 9183746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) { 9193746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_max); 9203746d5c1STitus Rwantare } else { 9213746d5c1STitus Rwantare goto passthough; 9223746d5c1STitus Rwantare } 9233746d5c1STitus Rwantare break; 9243746d5c1STitus Rwantare 9253746d5c1STitus Rwantare case PMBUS_MFR_IIN_MAX: /* Read-Only word */ 9263746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN_RATING) { 9273746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_iin_max); 9283746d5c1STitus Rwantare } else { 9293746d5c1STitus Rwantare goto passthough; 9303746d5c1STitus Rwantare } 9313746d5c1STitus Rwantare break; 9323746d5c1STitus Rwantare 9333746d5c1STitus Rwantare case PMBUS_MFR_PIN_MAX: /* Read-Only word */ 9343746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_PIN_RATING) { 9353746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_pin_max); 9363746d5c1STitus Rwantare } else { 9373746d5c1STitus Rwantare goto passthough; 9383746d5c1STitus Rwantare } 9393746d5c1STitus Rwantare break; 9403746d5c1STitus Rwantare 9413746d5c1STitus Rwantare case PMBUS_MFR_VOUT_MIN: /* Read-Only word */ 9423746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 9433746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_min); 9443746d5c1STitus Rwantare } else { 9453746d5c1STitus Rwantare goto passthough; 9463746d5c1STitus Rwantare } 9473746d5c1STitus Rwantare break; 9483746d5c1STitus Rwantare 9493746d5c1STitus Rwantare case PMBUS_MFR_VOUT_MAX: /* Read-Only word */ 9503746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 9513746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_max); 9523746d5c1STitus Rwantare } else { 9533746d5c1STitus Rwantare goto passthough; 9543746d5c1STitus Rwantare } 9553746d5c1STitus Rwantare break; 9563746d5c1STitus Rwantare 9573746d5c1STitus Rwantare case PMBUS_MFR_IOUT_MAX: /* Read-Only word */ 9583746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT_RATING) { 9593746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_iout_max); 9603746d5c1STitus Rwantare } else { 9613746d5c1STitus Rwantare goto passthough; 9623746d5c1STitus Rwantare } 9633746d5c1STitus Rwantare break; 9643746d5c1STitus Rwantare 9653746d5c1STitus Rwantare case PMBUS_MFR_POUT_MAX: /* Read-Only word */ 9663746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_POUT_RATING) { 9673746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_pout_max); 9683746d5c1STitus Rwantare } else { 9693746d5c1STitus Rwantare goto passthough; 9703746d5c1STitus Rwantare } 9713746d5c1STitus Rwantare break; 9723746d5c1STitus Rwantare 9733746d5c1STitus Rwantare case PMBUS_MFR_MAX_TEMP_1: /* R/W word */ 9743746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) { 9753746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_1); 9763746d5c1STitus Rwantare } else { 9773746d5c1STitus Rwantare goto passthough; 9783746d5c1STitus Rwantare } 9793746d5c1STitus Rwantare break; 9803746d5c1STitus Rwantare 9813746d5c1STitus Rwantare case PMBUS_MFR_MAX_TEMP_2: /* R/W word */ 9823746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) { 9833746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_2); 9843746d5c1STitus Rwantare } else { 9853746d5c1STitus Rwantare goto passthough; 9863746d5c1STitus Rwantare } 9873746d5c1STitus Rwantare break; 9883746d5c1STitus Rwantare 9893746d5c1STitus Rwantare case PMBUS_MFR_MAX_TEMP_3: /* R/W word */ 9903746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) { 9913746d5c1STitus Rwantare pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_3); 9923746d5c1STitus Rwantare } else { 9933746d5c1STitus Rwantare goto passthough; 9943746d5c1STitus Rwantare } 9953746d5c1STitus Rwantare break; 9963746d5c1STitus Rwantare 997d272d141SPeter Delevoryas case PMBUS_IDLE_STATE: 998d272d141SPeter Delevoryas pmbus_send8(pmdev, PMBUS_ERR_BYTE); 999d272d141SPeter Delevoryas break; 1000d272d141SPeter Delevoryas 10013746d5c1STitus Rwantare case PMBUS_CLEAR_FAULTS: /* Send Byte */ 10023746d5c1STitus Rwantare case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */ 10033746d5c1STitus Rwantare case PMBUS_STORE_DEFAULT_ALL: /* Send Byte */ 10043746d5c1STitus Rwantare case PMBUS_RESTORE_DEFAULT_ALL: /* Send Byte */ 10053746d5c1STitus Rwantare case PMBUS_STORE_DEFAULT_CODE: /* Write-only Byte */ 10063746d5c1STitus Rwantare case PMBUS_RESTORE_DEFAULT_CODE: /* Write-only Byte */ 10073746d5c1STitus Rwantare case PMBUS_STORE_USER_ALL: /* Send Byte */ 10083746d5c1STitus Rwantare case PMBUS_RESTORE_USER_ALL: /* Send Byte */ 10093746d5c1STitus Rwantare case PMBUS_STORE_USER_CODE: /* Write-only Byte */ 10103746d5c1STitus Rwantare case PMBUS_RESTORE_USER_CODE: /* Write-only Byte */ 10113746d5c1STitus Rwantare case PMBUS_QUERY: /* Write-Only */ 10123746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 10133746d5c1STitus Rwantare "%s: reading from write only register 0x%02x\n", 10143746d5c1STitus Rwantare __func__, pmdev->code); 10153746d5c1STitus Rwantare break; 10163746d5c1STitus Rwantare 10173746d5c1STitus Rwantare passthough: 10183746d5c1STitus Rwantare default: 10193746d5c1STitus Rwantare /* Pass through read request if not handled */ 10203746d5c1STitus Rwantare if (pmdc->receive_byte) { 10213746d5c1STitus Rwantare ret = pmdc->receive_byte(pmdev); 10223746d5c1STitus Rwantare } 10233746d5c1STitus Rwantare break; 10243746d5c1STitus Rwantare } 10253746d5c1STitus Rwantare 10263746d5c1STitus Rwantare if (pmdev->out_buf_len != 0) { 10273746d5c1STitus Rwantare ret = pmbus_out_buf_pop(pmdev); 10283746d5c1STitus Rwantare return ret; 10293746d5c1STitus Rwantare } 10303746d5c1STitus Rwantare 10313746d5c1STitus Rwantare return ret; 10323746d5c1STitus Rwantare } 10333746d5c1STitus Rwantare 10343746d5c1STitus Rwantare /* 10353746d5c1STitus Rwantare * PMBus clear faults command applies to all status registers, existing faults 10363746d5c1STitus Rwantare * should separately get re-asserted. 10373746d5c1STitus Rwantare */ 10383746d5c1STitus Rwantare static void pmbus_clear_faults(PMBusDevice *pmdev) 10393746d5c1STitus Rwantare { 10403746d5c1STitus Rwantare for (uint8_t i = 0; i < pmdev->num_pages; i++) { 10413746d5c1STitus Rwantare pmdev->pages[i].status_word = 0; 10423746d5c1STitus Rwantare pmdev->pages[i].status_vout = 0; 10433746d5c1STitus Rwantare pmdev->pages[i].status_iout = 0; 10443746d5c1STitus Rwantare pmdev->pages[i].status_input = 0; 10453746d5c1STitus Rwantare pmdev->pages[i].status_temperature = 0; 10463746d5c1STitus Rwantare pmdev->pages[i].status_cml = 0; 10473746d5c1STitus Rwantare pmdev->pages[i].status_other = 0; 10483746d5c1STitus Rwantare pmdev->pages[i].status_mfr_specific = 0; 10493746d5c1STitus Rwantare pmdev->pages[i].status_fans_1_2 = 0; 10503746d5c1STitus Rwantare pmdev->pages[i].status_fans_3_4 = 0; 10513746d5c1STitus Rwantare } 10523746d5c1STitus Rwantare 10533746d5c1STitus Rwantare } 10543746d5c1STitus Rwantare 10553746d5c1STitus Rwantare /* 10563746d5c1STitus Rwantare * PMBus operation is used to turn On and Off PSUs 10573746d5c1STitus Rwantare * Therefore, default value for the Operation should be PB_OP_ON or 0x80 10583746d5c1STitus Rwantare */ 10593746d5c1STitus Rwantare static void pmbus_operation(PMBusDevice *pmdev) 10603746d5c1STitus Rwantare { 10613746d5c1STitus Rwantare uint8_t index = pmdev->page; 10623746d5c1STitus Rwantare if ((pmdev->pages[index].operation & PB_OP_ON) == 0) { 10633746d5c1STitus Rwantare pmdev->pages[index].read_vout = 0; 10643746d5c1STitus Rwantare pmdev->pages[index].read_iout = 0; 10653746d5c1STitus Rwantare pmdev->pages[index].read_pout = 0; 10663746d5c1STitus Rwantare return; 10673746d5c1STitus Rwantare } 10683746d5c1STitus Rwantare 10693746d5c1STitus Rwantare if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_HIGH)) { 10703746d5c1STitus Rwantare pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_high; 10713746d5c1STitus Rwantare } 10723746d5c1STitus Rwantare 10733746d5c1STitus Rwantare if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_LOW)) { 10743746d5c1STitus Rwantare pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_low; 10753746d5c1STitus Rwantare } 10763746d5c1STitus Rwantare pmbus_check_limits(pmdev); 10773746d5c1STitus Rwantare } 10783746d5c1STitus Rwantare 10793746d5c1STitus Rwantare static int pmbus_write_data(SMBusDevice *smd, uint8_t *buf, uint8_t len) 10803746d5c1STitus Rwantare { 10813746d5c1STitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(smd); 10823746d5c1STitus Rwantare PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev); 10833746d5c1STitus Rwantare int ret = 0; 10843746d5c1STitus Rwantare uint8_t index; 10853746d5c1STitus Rwantare 10863746d5c1STitus Rwantare if (len == 0) { 10873746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); 108838870253STitus Rwantare return PMBUS_ERR_BYTE; 10893746d5c1STitus Rwantare } 10903746d5c1STitus Rwantare 10913746d5c1STitus Rwantare if (!pmdev->pages) { /* allocate memory for pages on first use */ 10923746d5c1STitus Rwantare pmbus_pages_alloc(pmdev); 10933746d5c1STitus Rwantare } 10943746d5c1STitus Rwantare 10953746d5c1STitus Rwantare pmdev->in_buf_len = len; 10963746d5c1STitus Rwantare pmdev->in_buf = buf; 10973746d5c1STitus Rwantare 10983746d5c1STitus Rwantare pmdev->code = buf[0]; /* PMBus command code */ 10993746d5c1STitus Rwantare if (len == 1) { /* Single length writes are command codes only */ 11003746d5c1STitus Rwantare return 0; 11013746d5c1STitus Rwantare } 11023746d5c1STitus Rwantare 11033746d5c1STitus Rwantare if (pmdev->code == PMBUS_PAGE) { 11043746d5c1STitus Rwantare pmdev->page = pmbus_receive8(pmdev); 11053746d5c1STitus Rwantare return 0; 11063746d5c1STitus Rwantare } 110738870253STitus Rwantare 11083746d5c1STitus Rwantare /* loop through all the pages when 0xFF is received */ 11093746d5c1STitus Rwantare if (pmdev->page == PB_ALL_PAGES) { 11103746d5c1STitus Rwantare for (int i = 0; i < pmdev->num_pages; i++) { 11113746d5c1STitus Rwantare pmdev->page = i; 11123746d5c1STitus Rwantare pmbus_write_data(smd, buf, len); 11133746d5c1STitus Rwantare } 11143746d5c1STitus Rwantare pmdev->page = PB_ALL_PAGES; 11153746d5c1STitus Rwantare return 0; 11163746d5c1STitus Rwantare } 11173746d5c1STitus Rwantare 111838870253STitus Rwantare if (pmdev->page > pmdev->num_pages - 1) { 111938870253STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 112038870253STitus Rwantare "%s: page %u is out of range\n", 112138870253STitus Rwantare __func__, pmdev->page); 112238870253STitus Rwantare pmdev->page = 0; /* undefined behaviour - reset to page 0 */ 112338870253STitus Rwantare pmbus_cml_error(pmdev); 112438870253STitus Rwantare return PMBUS_ERR_BYTE; 112538870253STitus Rwantare } 112638870253STitus Rwantare 11273746d5c1STitus Rwantare index = pmdev->page; 11283746d5c1STitus Rwantare 11293746d5c1STitus Rwantare switch (pmdev->code) { 11303746d5c1STitus Rwantare case PMBUS_OPERATION: /* R/W byte */ 11313746d5c1STitus Rwantare pmdev->pages[index].operation = pmbus_receive8(pmdev); 11323746d5c1STitus Rwantare pmbus_operation(pmdev); 11333746d5c1STitus Rwantare break; 11343746d5c1STitus Rwantare 11353746d5c1STitus Rwantare case PMBUS_ON_OFF_CONFIG: /* R/W byte */ 11363746d5c1STitus Rwantare pmdev->pages[index].on_off_config = pmbus_receive8(pmdev); 11373746d5c1STitus Rwantare break; 11383746d5c1STitus Rwantare 11393746d5c1STitus Rwantare case PMBUS_CLEAR_FAULTS: /* Send Byte */ 11403746d5c1STitus Rwantare pmbus_clear_faults(pmdev); 11413746d5c1STitus Rwantare break; 11423746d5c1STitus Rwantare 11433746d5c1STitus Rwantare case PMBUS_PHASE: /* R/W byte */ 11443746d5c1STitus Rwantare pmdev->pages[index].phase = pmbus_receive8(pmdev); 11453746d5c1STitus Rwantare break; 11463746d5c1STitus Rwantare 11473746d5c1STitus Rwantare case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */ 11483746d5c1STitus Rwantare case PMBUS_WRITE_PROTECT: /* R/W byte */ 11493746d5c1STitus Rwantare pmdev->pages[index].write_protect = pmbus_receive8(pmdev); 11503746d5c1STitus Rwantare break; 11513746d5c1STitus Rwantare 11523746d5c1STitus Rwantare case PMBUS_VOUT_MODE: /* R/W byte */ 11533746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) { 11543746d5c1STitus Rwantare pmdev->pages[index].vout_mode = pmbus_receive8(pmdev); 11553746d5c1STitus Rwantare } else { 11563746d5c1STitus Rwantare goto passthrough; 11573746d5c1STitus Rwantare } 11583746d5c1STitus Rwantare break; 11593746d5c1STitus Rwantare 11603746d5c1STitus Rwantare case PMBUS_VOUT_COMMAND: /* R/W word */ 11613746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 11623746d5c1STitus Rwantare pmdev->pages[index].vout_command = pmbus_receive16(pmdev); 11633746d5c1STitus Rwantare } else { 11643746d5c1STitus Rwantare goto passthrough; 11653746d5c1STitus Rwantare } 11663746d5c1STitus Rwantare break; 11673746d5c1STitus Rwantare 11683746d5c1STitus Rwantare case PMBUS_VOUT_TRIM: /* R/W word */ 11693746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 11703746d5c1STitus Rwantare pmdev->pages[index].vout_trim = pmbus_receive16(pmdev); 11713746d5c1STitus Rwantare } else { 11723746d5c1STitus Rwantare goto passthrough; 11733746d5c1STitus Rwantare } 11743746d5c1STitus Rwantare break; 11753746d5c1STitus Rwantare 11763746d5c1STitus Rwantare case PMBUS_VOUT_CAL_OFFSET: /* R/W word */ 11773746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 11783746d5c1STitus Rwantare pmdev->pages[index].vout_cal_offset = pmbus_receive16(pmdev); 11793746d5c1STitus Rwantare } else { 11803746d5c1STitus Rwantare goto passthrough; 11813746d5c1STitus Rwantare } 11823746d5c1STitus Rwantare break; 11833746d5c1STitus Rwantare 11843746d5c1STitus Rwantare case PMBUS_VOUT_MAX: /* R/W word */ 11853746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 11863746d5c1STitus Rwantare pmdev->pages[index].vout_max = pmbus_receive16(pmdev); 11873746d5c1STitus Rwantare } else { 11883746d5c1STitus Rwantare goto passthrough; 11893746d5c1STitus Rwantare } 11903746d5c1STitus Rwantare break; 11913746d5c1STitus Rwantare 11923746d5c1STitus Rwantare case PMBUS_VOUT_MARGIN_HIGH: /* R/W word */ 11933746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 11943746d5c1STitus Rwantare pmdev->pages[index].vout_margin_high = pmbus_receive16(pmdev); 11953746d5c1STitus Rwantare } else { 11963746d5c1STitus Rwantare goto passthrough; 11973746d5c1STitus Rwantare } 11983746d5c1STitus Rwantare break; 11993746d5c1STitus Rwantare 12003746d5c1STitus Rwantare case PMBUS_VOUT_MARGIN_LOW: /* R/W word */ 12013746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 12023746d5c1STitus Rwantare pmdev->pages[index].vout_margin_low = pmbus_receive16(pmdev); 12033746d5c1STitus Rwantare } else { 12043746d5c1STitus Rwantare goto passthrough; 12053746d5c1STitus Rwantare } 12063746d5c1STitus Rwantare break; 12073746d5c1STitus Rwantare 12083746d5c1STitus Rwantare case PMBUS_VOUT_TRANSITION_RATE: /* R/W word */ 12093746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12103746d5c1STitus Rwantare pmdev->pages[index].vout_transition_rate = pmbus_receive16(pmdev); 12113746d5c1STitus Rwantare } else { 12123746d5c1STitus Rwantare goto passthrough; 12133746d5c1STitus Rwantare } 12143746d5c1STitus Rwantare break; 12153746d5c1STitus Rwantare 12163746d5c1STitus Rwantare case PMBUS_VOUT_DROOP: /* R/W word */ 12173746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12183746d5c1STitus Rwantare pmdev->pages[index].vout_droop = pmbus_receive16(pmdev); 12193746d5c1STitus Rwantare } else { 12203746d5c1STitus Rwantare goto passthrough; 12213746d5c1STitus Rwantare } 12223746d5c1STitus Rwantare break; 12233746d5c1STitus Rwantare 12243746d5c1STitus Rwantare case PMBUS_VOUT_SCALE_LOOP: /* R/W word */ 12253746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12263746d5c1STitus Rwantare pmdev->pages[index].vout_scale_loop = pmbus_receive16(pmdev); 12273746d5c1STitus Rwantare } else { 12283746d5c1STitus Rwantare goto passthrough; 12293746d5c1STitus Rwantare } 12303746d5c1STitus Rwantare break; 12313746d5c1STitus Rwantare 12323746d5c1STitus Rwantare case PMBUS_VOUT_SCALE_MONITOR: /* R/W word */ 12333746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12343746d5c1STitus Rwantare pmdev->pages[index].vout_scale_monitor = pmbus_receive16(pmdev); 12353746d5c1STitus Rwantare } else { 12363746d5c1STitus Rwantare goto passthrough; 12373746d5c1STitus Rwantare } 12383746d5c1STitus Rwantare break; 12393746d5c1STitus Rwantare 124032480293STitus Rwantare case PMBUS_VOUT_MIN: /* R/W word */ 124132480293STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 124232480293STitus Rwantare pmdev->pages[index].vout_min = pmbus_receive16(pmdev); 124332480293STitus Rwantare } else { 124432480293STitus Rwantare goto passthrough; 124532480293STitus Rwantare } 124632480293STitus Rwantare break; 124732480293STitus Rwantare 12483746d5c1STitus Rwantare case PMBUS_POUT_MAX: /* R/W word */ 12493746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12503746d5c1STitus Rwantare pmdev->pages[index].pout_max = pmbus_receive16(pmdev); 12513746d5c1STitus Rwantare } else { 12523746d5c1STitus Rwantare goto passthrough; 12533746d5c1STitus Rwantare } 12543746d5c1STitus Rwantare break; 12553746d5c1STitus Rwantare 12563746d5c1STitus Rwantare case PMBUS_VIN_ON: /* R/W word */ 12573746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 12583746d5c1STitus Rwantare pmdev->pages[index].vin_on = pmbus_receive16(pmdev); 12593746d5c1STitus Rwantare } else { 12603746d5c1STitus Rwantare goto passthrough; 12613746d5c1STitus Rwantare } 12623746d5c1STitus Rwantare break; 12633746d5c1STitus Rwantare 12643746d5c1STitus Rwantare case PMBUS_VIN_OFF: /* R/W word */ 12653746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 12663746d5c1STitus Rwantare pmdev->pages[index].vin_off = pmbus_receive16(pmdev); 12673746d5c1STitus Rwantare } else { 12683746d5c1STitus Rwantare goto passthrough; 12693746d5c1STitus Rwantare } 12703746d5c1STitus Rwantare break; 12713746d5c1STitus Rwantare 12723746d5c1STitus Rwantare case PMBUS_IOUT_CAL_GAIN: /* R/W word */ 12733746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) { 12743746d5c1STitus Rwantare pmdev->pages[index].iout_cal_gain = pmbus_receive16(pmdev); 12753746d5c1STitus Rwantare } else { 12763746d5c1STitus Rwantare goto passthrough; 12773746d5c1STitus Rwantare } 12783746d5c1STitus Rwantare break; 12793746d5c1STitus Rwantare 12803746d5c1STitus Rwantare case PMBUS_VOUT_OV_FAULT_LIMIT: /* R/W word */ 12813746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12823746d5c1STitus Rwantare pmdev->pages[index].vout_ov_fault_limit = pmbus_receive16(pmdev); 12833746d5c1STitus Rwantare } else { 12843746d5c1STitus Rwantare goto passthrough; 12853746d5c1STitus Rwantare } 12863746d5c1STitus Rwantare break; 12873746d5c1STitus Rwantare 12883746d5c1STitus Rwantare case PMBUS_VOUT_OV_FAULT_RESPONSE: /* R/W byte */ 12893746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12903746d5c1STitus Rwantare pmdev->pages[index].vout_ov_fault_response = pmbus_receive8(pmdev); 12913746d5c1STitus Rwantare } else { 12923746d5c1STitus Rwantare goto passthrough; 12933746d5c1STitus Rwantare } 12943746d5c1STitus Rwantare break; 12953746d5c1STitus Rwantare 12963746d5c1STitus Rwantare case PMBUS_VOUT_OV_WARN_LIMIT: /* R/W word */ 12973746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 12983746d5c1STitus Rwantare pmdev->pages[index].vout_ov_warn_limit = pmbus_receive16(pmdev); 12993746d5c1STitus Rwantare } else { 13003746d5c1STitus Rwantare goto passthrough; 13013746d5c1STitus Rwantare } 13023746d5c1STitus Rwantare break; 13033746d5c1STitus Rwantare 13043746d5c1STitus Rwantare case PMBUS_VOUT_UV_WARN_LIMIT: /* R/W word */ 13053746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 13063746d5c1STitus Rwantare pmdev->pages[index].vout_uv_warn_limit = pmbus_receive16(pmdev); 13073746d5c1STitus Rwantare } else { 13083746d5c1STitus Rwantare goto passthrough; 13093746d5c1STitus Rwantare } 13103746d5c1STitus Rwantare break; 13113746d5c1STitus Rwantare 13123746d5c1STitus Rwantare case PMBUS_VOUT_UV_FAULT_LIMIT: /* R/W word */ 13133746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 13143746d5c1STitus Rwantare pmdev->pages[index].vout_uv_fault_limit = pmbus_receive16(pmdev); 13153746d5c1STitus Rwantare } else { 13163746d5c1STitus Rwantare goto passthrough; 13173746d5c1STitus Rwantare } 13183746d5c1STitus Rwantare break; 13193746d5c1STitus Rwantare 13203746d5c1STitus Rwantare case PMBUS_VOUT_UV_FAULT_RESPONSE: /* R/W byte */ 13213746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 13223746d5c1STitus Rwantare pmdev->pages[index].vout_uv_fault_response = pmbus_receive8(pmdev); 13233746d5c1STitus Rwantare } else { 13243746d5c1STitus Rwantare goto passthrough; 13253746d5c1STitus Rwantare } 13263746d5c1STitus Rwantare break; 13273746d5c1STitus Rwantare 13283746d5c1STitus Rwantare case PMBUS_IOUT_OC_FAULT_LIMIT: /* R/W word */ 13293746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 13303746d5c1STitus Rwantare pmdev->pages[index].iout_oc_fault_limit = pmbus_receive16(pmdev); 13313746d5c1STitus Rwantare } else { 13323746d5c1STitus Rwantare goto passthrough; 13333746d5c1STitus Rwantare } 13343746d5c1STitus Rwantare break; 13353746d5c1STitus Rwantare 13363746d5c1STitus Rwantare case PMBUS_IOUT_OC_FAULT_RESPONSE: /* R/W byte */ 13373746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 13383746d5c1STitus Rwantare pmdev->pages[index].iout_oc_fault_response = pmbus_receive8(pmdev); 13393746d5c1STitus Rwantare } else { 13403746d5c1STitus Rwantare goto passthrough; 13413746d5c1STitus Rwantare } 13423746d5c1STitus Rwantare break; 13433746d5c1STitus Rwantare 13443746d5c1STitus Rwantare case PMBUS_IOUT_OC_LV_FAULT_LIMIT: /* R/W word */ 13453746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 13463746d5c1STitus Rwantare pmdev->pages[index].iout_oc_lv_fault_limit = pmbus_receive16(pmdev); 13473746d5c1STitus Rwantare } else { 13483746d5c1STitus Rwantare goto passthrough; 13493746d5c1STitus Rwantare } 13503746d5c1STitus Rwantare break; 13513746d5c1STitus Rwantare 13523746d5c1STitus Rwantare case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */ 13533746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 13543746d5c1STitus Rwantare pmdev->pages[index].iout_oc_lv_fault_response 13553746d5c1STitus Rwantare = pmbus_receive8(pmdev); 13563746d5c1STitus Rwantare } else { 13573746d5c1STitus Rwantare goto passthrough; 13583746d5c1STitus Rwantare } 13593746d5c1STitus Rwantare break; 13603746d5c1STitus Rwantare 13613746d5c1STitus Rwantare case PMBUS_IOUT_OC_WARN_LIMIT: /* R/W word */ 13623746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 13633746d5c1STitus Rwantare pmdev->pages[index].iout_oc_warn_limit = pmbus_receive16(pmdev); 13643746d5c1STitus Rwantare } else { 13653746d5c1STitus Rwantare goto passthrough; 13663746d5c1STitus Rwantare } 13673746d5c1STitus Rwantare break; 13683746d5c1STitus Rwantare 13693746d5c1STitus Rwantare case PMBUS_IOUT_UC_FAULT_LIMIT: /* R/W word */ 13703746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 13713746d5c1STitus Rwantare pmdev->pages[index].iout_uc_fault_limit = pmbus_receive16(pmdev); 13723746d5c1STitus Rwantare } else { 13733746d5c1STitus Rwantare goto passthrough; 13743746d5c1STitus Rwantare } 13753746d5c1STitus Rwantare break; 13763746d5c1STitus Rwantare 13773746d5c1STitus Rwantare case PMBUS_IOUT_UC_FAULT_RESPONSE: /* R/W byte */ 13783746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 13793746d5c1STitus Rwantare pmdev->pages[index].iout_uc_fault_response = pmbus_receive8(pmdev); 13803746d5c1STitus Rwantare } else { 13813746d5c1STitus Rwantare goto passthrough; 13823746d5c1STitus Rwantare } 13833746d5c1STitus Rwantare break; 13843746d5c1STitus Rwantare 13853746d5c1STitus Rwantare case PMBUS_OT_FAULT_LIMIT: /* R/W word */ 13863746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 13873746d5c1STitus Rwantare pmdev->pages[index].ot_fault_limit = pmbus_receive16(pmdev); 13883746d5c1STitus Rwantare } else { 13893746d5c1STitus Rwantare goto passthrough; 13903746d5c1STitus Rwantare } 13913746d5c1STitus Rwantare break; 13923746d5c1STitus Rwantare 13933746d5c1STitus Rwantare case PMBUS_OT_FAULT_RESPONSE: /* R/W byte */ 13943746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 13953746d5c1STitus Rwantare pmdev->pages[index].ot_fault_response = pmbus_receive8(pmdev); 13963746d5c1STitus Rwantare } else { 13973746d5c1STitus Rwantare goto passthrough; 13983746d5c1STitus Rwantare } 13993746d5c1STitus Rwantare break; 14003746d5c1STitus Rwantare 14013746d5c1STitus Rwantare case PMBUS_OT_WARN_LIMIT: /* R/W word */ 14023746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 14033746d5c1STitus Rwantare pmdev->pages[index].ot_warn_limit = pmbus_receive16(pmdev); 14043746d5c1STitus Rwantare } else { 14053746d5c1STitus Rwantare goto passthrough; 14063746d5c1STitus Rwantare } 14073746d5c1STitus Rwantare break; 14083746d5c1STitus Rwantare 14093746d5c1STitus Rwantare case PMBUS_UT_WARN_LIMIT: /* R/W word */ 14103746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 14113746d5c1STitus Rwantare pmdev->pages[index].ut_warn_limit = pmbus_receive16(pmdev); 14123746d5c1STitus Rwantare } else { 14133746d5c1STitus Rwantare goto passthrough; 14143746d5c1STitus Rwantare } 14153746d5c1STitus Rwantare break; 14163746d5c1STitus Rwantare 14173746d5c1STitus Rwantare case PMBUS_UT_FAULT_LIMIT: /* R/W word */ 14183746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 14193746d5c1STitus Rwantare pmdev->pages[index].ut_fault_limit = pmbus_receive16(pmdev); 14203746d5c1STitus Rwantare } else { 14213746d5c1STitus Rwantare goto passthrough; 14223746d5c1STitus Rwantare } 14233746d5c1STitus Rwantare break; 14243746d5c1STitus Rwantare 14253746d5c1STitus Rwantare case PMBUS_UT_FAULT_RESPONSE: /* R/W byte */ 14263746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 14273746d5c1STitus Rwantare pmdev->pages[index].ut_fault_response = pmbus_receive8(pmdev); 14283746d5c1STitus Rwantare } else { 14293746d5c1STitus Rwantare goto passthrough; 14303746d5c1STitus Rwantare } 14313746d5c1STitus Rwantare break; 14323746d5c1STitus Rwantare 14333746d5c1STitus Rwantare case PMBUS_VIN_OV_FAULT_LIMIT: /* R/W word */ 14343746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 14353746d5c1STitus Rwantare pmdev->pages[index].vin_ov_fault_limit = pmbus_receive16(pmdev); 14363746d5c1STitus Rwantare } else { 14373746d5c1STitus Rwantare goto passthrough; 14383746d5c1STitus Rwantare } 14393746d5c1STitus Rwantare break; 14403746d5c1STitus Rwantare 14413746d5c1STitus Rwantare case PMBUS_VIN_OV_FAULT_RESPONSE: /* R/W byte */ 14423746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 14433746d5c1STitus Rwantare pmdev->pages[index].vin_ov_fault_response = pmbus_receive8(pmdev); 14443746d5c1STitus Rwantare } else { 14453746d5c1STitus Rwantare goto passthrough; 14463746d5c1STitus Rwantare } 14473746d5c1STitus Rwantare break; 14483746d5c1STitus Rwantare 14493746d5c1STitus Rwantare case PMBUS_VIN_OV_WARN_LIMIT: /* R/W word */ 14503746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 14513746d5c1STitus Rwantare pmdev->pages[index].vin_ov_warn_limit = pmbus_receive16(pmdev); 14523746d5c1STitus Rwantare } else { 14533746d5c1STitus Rwantare goto passthrough; 14543746d5c1STitus Rwantare } 14553746d5c1STitus Rwantare break; 14563746d5c1STitus Rwantare 14573746d5c1STitus Rwantare case PMBUS_VIN_UV_WARN_LIMIT: /* R/W word */ 14583746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 14593746d5c1STitus Rwantare pmdev->pages[index].vin_uv_warn_limit = pmbus_receive16(pmdev); 14603746d5c1STitus Rwantare } else { 14613746d5c1STitus Rwantare goto passthrough; 14623746d5c1STitus Rwantare } 14633746d5c1STitus Rwantare break; 14643746d5c1STitus Rwantare 14653746d5c1STitus Rwantare case PMBUS_VIN_UV_FAULT_LIMIT: /* R/W word */ 14663746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 14673746d5c1STitus Rwantare pmdev->pages[index].vin_uv_fault_limit = pmbus_receive16(pmdev); 14683746d5c1STitus Rwantare } else { 14693746d5c1STitus Rwantare goto passthrough; 14703746d5c1STitus Rwantare } 14713746d5c1STitus Rwantare break; 14723746d5c1STitus Rwantare 14733746d5c1STitus Rwantare case PMBUS_VIN_UV_FAULT_RESPONSE: /* R/W byte */ 14743746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 14753746d5c1STitus Rwantare pmdev->pages[index].vin_uv_fault_response = pmbus_receive8(pmdev); 14763746d5c1STitus Rwantare } else { 14773746d5c1STitus Rwantare goto passthrough; 14783746d5c1STitus Rwantare } 14793746d5c1STitus Rwantare break; 14803746d5c1STitus Rwantare 14813746d5c1STitus Rwantare case PMBUS_IIN_OC_FAULT_LIMIT: /* R/W word */ 14823746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 14833746d5c1STitus Rwantare pmdev->pages[index].iin_oc_fault_limit = pmbus_receive16(pmdev); 14843746d5c1STitus Rwantare } else { 14853746d5c1STitus Rwantare goto passthrough; 14863746d5c1STitus Rwantare } 14873746d5c1STitus Rwantare break; 14883746d5c1STitus Rwantare 14893746d5c1STitus Rwantare case PMBUS_IIN_OC_FAULT_RESPONSE: /* R/W byte */ 14903746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 14913746d5c1STitus Rwantare pmdev->pages[index].iin_oc_fault_response = pmbus_receive8(pmdev); 14923746d5c1STitus Rwantare } else { 14933746d5c1STitus Rwantare goto passthrough; 14943746d5c1STitus Rwantare } 14953746d5c1STitus Rwantare break; 14963746d5c1STitus Rwantare 14973746d5c1STitus Rwantare case PMBUS_IIN_OC_WARN_LIMIT: /* R/W word */ 14983746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 14993746d5c1STitus Rwantare pmdev->pages[index].iin_oc_warn_limit = pmbus_receive16(pmdev); 15003746d5c1STitus Rwantare } else { 15013746d5c1STitus Rwantare goto passthrough; 15023746d5c1STitus Rwantare } 15033746d5c1STitus Rwantare break; 15043746d5c1STitus Rwantare 15053746d5c1STitus Rwantare case PMBUS_POUT_OP_FAULT_LIMIT: /* R/W word */ 15063746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 15073746d5c1STitus Rwantare pmdev->pages[index].pout_op_fault_limit = pmbus_receive16(pmdev); 15083746d5c1STitus Rwantare } else { 15093746d5c1STitus Rwantare goto passthrough; 15103746d5c1STitus Rwantare } 15113746d5c1STitus Rwantare break; 15123746d5c1STitus Rwantare 15133746d5c1STitus Rwantare case PMBUS_POUT_OP_FAULT_RESPONSE: /* R/W byte */ 15143746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 15153746d5c1STitus Rwantare pmdev->pages[index].pout_op_fault_response = pmbus_receive8(pmdev); 15163746d5c1STitus Rwantare } else { 15173746d5c1STitus Rwantare goto passthrough; 15183746d5c1STitus Rwantare } 15193746d5c1STitus Rwantare break; 15203746d5c1STitus Rwantare 15213746d5c1STitus Rwantare case PMBUS_POUT_OP_WARN_LIMIT: /* R/W word */ 15223746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 15233746d5c1STitus Rwantare pmdev->pages[index].pout_op_warn_limit = pmbus_receive16(pmdev); 15243746d5c1STitus Rwantare } else { 15253746d5c1STitus Rwantare goto passthrough; 15263746d5c1STitus Rwantare } 15273746d5c1STitus Rwantare break; 15283746d5c1STitus Rwantare 15293746d5c1STitus Rwantare case PMBUS_PIN_OP_WARN_LIMIT: /* R/W word */ 15303746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_PIN) { 15313746d5c1STitus Rwantare pmdev->pages[index].pin_op_warn_limit = pmbus_receive16(pmdev); 15323746d5c1STitus Rwantare } else { 15333746d5c1STitus Rwantare goto passthrough; 15343746d5c1STitus Rwantare } 15353746d5c1STitus Rwantare break; 15363746d5c1STitus Rwantare 15373746d5c1STitus Rwantare case PMBUS_STATUS_BYTE: /* R/W byte */ 15383746d5c1STitus Rwantare pmdev->pages[index].status_word = pmbus_receive8(pmdev); 15393746d5c1STitus Rwantare break; 15403746d5c1STitus Rwantare 15413746d5c1STitus Rwantare case PMBUS_STATUS_WORD: /* R/W word */ 15423746d5c1STitus Rwantare pmdev->pages[index].status_word = pmbus_receive16(pmdev); 15433746d5c1STitus Rwantare break; 15443746d5c1STitus Rwantare 15453746d5c1STitus Rwantare case PMBUS_STATUS_VOUT: /* R/W byte */ 15463746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 15473746d5c1STitus Rwantare pmdev->pages[index].status_vout = pmbus_receive8(pmdev); 15483746d5c1STitus Rwantare } else { 15493746d5c1STitus Rwantare goto passthrough; 15503746d5c1STitus Rwantare } 15513746d5c1STitus Rwantare break; 15523746d5c1STitus Rwantare 15533746d5c1STitus Rwantare case PMBUS_STATUS_IOUT: /* R/W byte */ 15543746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 15553746d5c1STitus Rwantare pmdev->pages[index].status_iout = pmbus_receive8(pmdev); 15563746d5c1STitus Rwantare } else { 15573746d5c1STitus Rwantare goto passthrough; 15583746d5c1STitus Rwantare } 15593746d5c1STitus Rwantare break; 15603746d5c1STitus Rwantare 15613746d5c1STitus Rwantare case PMBUS_STATUS_INPUT: /* R/W byte */ 15623746d5c1STitus Rwantare pmdev->pages[index].status_input = pmbus_receive8(pmdev); 15633746d5c1STitus Rwantare break; 15643746d5c1STitus Rwantare 15653746d5c1STitus Rwantare case PMBUS_STATUS_TEMPERATURE: /* R/W byte */ 15663746d5c1STitus Rwantare if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 15673746d5c1STitus Rwantare pmdev->pages[index].status_temperature = pmbus_receive8(pmdev); 15683746d5c1STitus Rwantare } else { 15693746d5c1STitus Rwantare goto passthrough; 15703746d5c1STitus Rwantare } 15713746d5c1STitus Rwantare break; 15723746d5c1STitus Rwantare 15733746d5c1STitus Rwantare case PMBUS_STATUS_CML: /* R/W byte */ 15743746d5c1STitus Rwantare pmdev->pages[index].status_cml = pmbus_receive8(pmdev); 15753746d5c1STitus Rwantare break; 15763746d5c1STitus Rwantare 15773746d5c1STitus Rwantare case PMBUS_STATUS_OTHER: /* R/W byte */ 15783746d5c1STitus Rwantare pmdev->pages[index].status_other = pmbus_receive8(pmdev); 15793746d5c1STitus Rwantare break; 15803746d5c1STitus Rwantare 158132480293STitus Rwantare case PMBUS_STATUS_MFR_SPECIFIC: /* R/W byte */ 158232480293STitus Rwantare pmdev->pages[index].status_mfr_specific = pmbus_receive8(pmdev); 158332480293STitus Rwantare break; 158432480293STitus Rwantare 15853746d5c1STitus Rwantare case PMBUS_PAGE_PLUS_READ: /* Block Read-only */ 15863746d5c1STitus Rwantare case PMBUS_CAPABILITY: /* Read-Only byte */ 15873746d5c1STitus Rwantare case PMBUS_COEFFICIENTS: /* Read-only block 5 bytes */ 15883746d5c1STitus Rwantare case PMBUS_READ_EIN: /* Read-Only block 5 bytes */ 15893746d5c1STitus Rwantare case PMBUS_READ_EOUT: /* Read-Only block 5 bytes */ 15903746d5c1STitus Rwantare case PMBUS_READ_VIN: /* Read-Only word */ 15913746d5c1STitus Rwantare case PMBUS_READ_IIN: /* Read-Only word */ 15923746d5c1STitus Rwantare case PMBUS_READ_VCAP: /* Read-Only word */ 15933746d5c1STitus Rwantare case PMBUS_READ_VOUT: /* Read-Only word */ 15943746d5c1STitus Rwantare case PMBUS_READ_IOUT: /* Read-Only word */ 15953746d5c1STitus Rwantare case PMBUS_READ_TEMPERATURE_1: /* Read-Only word */ 15963746d5c1STitus Rwantare case PMBUS_READ_TEMPERATURE_2: /* Read-Only word */ 15973746d5c1STitus Rwantare case PMBUS_READ_TEMPERATURE_3: /* Read-Only word */ 15983746d5c1STitus Rwantare case PMBUS_READ_FAN_SPEED_1: /* Read-Only word */ 15993746d5c1STitus Rwantare case PMBUS_READ_FAN_SPEED_2: /* Read-Only word */ 16003746d5c1STitus Rwantare case PMBUS_READ_FAN_SPEED_3: /* Read-Only word */ 16013746d5c1STitus Rwantare case PMBUS_READ_FAN_SPEED_4: /* Read-Only word */ 16023746d5c1STitus Rwantare case PMBUS_READ_DUTY_CYCLE: /* Read-Only word */ 16033746d5c1STitus Rwantare case PMBUS_READ_FREQUENCY: /* Read-Only word */ 16043746d5c1STitus Rwantare case PMBUS_READ_POUT: /* Read-Only word */ 16053746d5c1STitus Rwantare case PMBUS_READ_PIN: /* Read-Only word */ 16063746d5c1STitus Rwantare case PMBUS_REVISION: /* Read-Only byte */ 16073746d5c1STitus Rwantare case PMBUS_APP_PROFILE_SUPPORT: /* Read-Only block-read */ 16083746d5c1STitus Rwantare case PMBUS_MFR_VIN_MIN: /* Read-Only word */ 16093746d5c1STitus Rwantare case PMBUS_MFR_VIN_MAX: /* Read-Only word */ 16103746d5c1STitus Rwantare case PMBUS_MFR_IIN_MAX: /* Read-Only word */ 16113746d5c1STitus Rwantare case PMBUS_MFR_PIN_MAX: /* Read-Only word */ 16123746d5c1STitus Rwantare case PMBUS_MFR_VOUT_MIN: /* Read-Only word */ 16133746d5c1STitus Rwantare case PMBUS_MFR_VOUT_MAX: /* Read-Only word */ 16143746d5c1STitus Rwantare case PMBUS_MFR_IOUT_MAX: /* Read-Only word */ 16153746d5c1STitus Rwantare case PMBUS_MFR_POUT_MAX: /* Read-Only word */ 16163746d5c1STitus Rwantare case PMBUS_MFR_TAMBIENT_MAX: /* Read-Only word */ 16173746d5c1STitus Rwantare case PMBUS_MFR_TAMBIENT_MIN: /* Read-Only word */ 16183746d5c1STitus Rwantare case PMBUS_MFR_EFFICIENCY_LL: /* Read-Only block 14 bytes */ 16193746d5c1STitus Rwantare case PMBUS_MFR_EFFICIENCY_HL: /* Read-Only block 14 bytes */ 16203746d5c1STitus Rwantare case PMBUS_MFR_PIN_ACCURACY: /* Read-Only byte */ 16213746d5c1STitus Rwantare case PMBUS_IC_DEVICE_ID: /* Read-Only block-read */ 16223746d5c1STitus Rwantare case PMBUS_IC_DEVICE_REV: /* Read-Only block-read */ 16233746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 16243746d5c1STitus Rwantare "%s: writing to read-only register 0x%02x\n", 16253746d5c1STitus Rwantare __func__, pmdev->code); 16263746d5c1STitus Rwantare break; 16273746d5c1STitus Rwantare 16283746d5c1STitus Rwantare passthrough: 1629*8fa21b80SMichael Tokarev /* Unimplemented registers get passed to the device */ 16303746d5c1STitus Rwantare default: 16313746d5c1STitus Rwantare if (pmdc->write_data) { 16323746d5c1STitus Rwantare ret = pmdc->write_data(pmdev, buf, len); 16333746d5c1STitus Rwantare } 16343746d5c1STitus Rwantare break; 16353746d5c1STitus Rwantare } 16363746d5c1STitus Rwantare pmbus_check_limits(pmdev); 16373746d5c1STitus Rwantare pmdev->in_buf_len = 0; 16383746d5c1STitus Rwantare return ret; 16393746d5c1STitus Rwantare } 16403746d5c1STitus Rwantare 16413746d5c1STitus Rwantare int pmbus_page_config(PMBusDevice *pmdev, uint8_t index, uint64_t flags) 16423746d5c1STitus Rwantare { 16433746d5c1STitus Rwantare if (!pmdev->pages) { /* allocate memory for pages on first use */ 16443746d5c1STitus Rwantare pmbus_pages_alloc(pmdev); 16453746d5c1STitus Rwantare } 16463746d5c1STitus Rwantare 16473746d5c1STitus Rwantare /* The 0xFF page is special for commands applying to all pages */ 16483746d5c1STitus Rwantare if (index == PB_ALL_PAGES) { 16493746d5c1STitus Rwantare for (int i = 0; i < pmdev->num_pages; i++) { 16503746d5c1STitus Rwantare pmdev->pages[i].page_flags = flags; 16513746d5c1STitus Rwantare } 16523746d5c1STitus Rwantare return 0; 16533746d5c1STitus Rwantare } 16543746d5c1STitus Rwantare 16553746d5c1STitus Rwantare if (index > pmdev->num_pages - 1) { 16563746d5c1STitus Rwantare qemu_log_mask(LOG_GUEST_ERROR, 16573746d5c1STitus Rwantare "%s: index %u is out of range\n", 16583746d5c1STitus Rwantare __func__, index); 16593746d5c1STitus Rwantare return -1; 16603746d5c1STitus Rwantare } 16613746d5c1STitus Rwantare 16623746d5c1STitus Rwantare pmdev->pages[index].page_flags = flags; 16633746d5c1STitus Rwantare 16643746d5c1STitus Rwantare return 0; 16653746d5c1STitus Rwantare } 16663746d5c1STitus Rwantare 16673746d5c1STitus Rwantare /* TODO: include pmbus page info in vmstate */ 16683746d5c1STitus Rwantare const VMStateDescription vmstate_pmbus_device = { 16693746d5c1STitus Rwantare .name = TYPE_PMBUS_DEVICE, 16703746d5c1STitus Rwantare .version_id = 0, 16713746d5c1STitus Rwantare .minimum_version_id = 0, 16723746d5c1STitus Rwantare .fields = (VMStateField[]) { 16733746d5c1STitus Rwantare VMSTATE_SMBUS_DEVICE(smb, PMBusDevice), 16743746d5c1STitus Rwantare VMSTATE_UINT8(num_pages, PMBusDevice), 16753746d5c1STitus Rwantare VMSTATE_UINT8(code, PMBusDevice), 16763746d5c1STitus Rwantare VMSTATE_UINT8(page, PMBusDevice), 16773746d5c1STitus Rwantare VMSTATE_UINT8(capability, PMBusDevice), 16783746d5c1STitus Rwantare VMSTATE_END_OF_LIST() 16793746d5c1STitus Rwantare } 16803746d5c1STitus Rwantare }; 16813746d5c1STitus Rwantare 16823746d5c1STitus Rwantare static void pmbus_device_finalize(Object *obj) 16833746d5c1STitus Rwantare { 16843746d5c1STitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(obj); 16853746d5c1STitus Rwantare g_free(pmdev->pages); 16863746d5c1STitus Rwantare } 16873746d5c1STitus Rwantare 16883746d5c1STitus Rwantare static void pmbus_device_class_init(ObjectClass *klass, void *data) 16893746d5c1STitus Rwantare { 16903746d5c1STitus Rwantare SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass); 16913746d5c1STitus Rwantare 16923746d5c1STitus Rwantare k->quick_cmd = pmbus_quick_cmd; 16933746d5c1STitus Rwantare k->write_data = pmbus_write_data; 16943746d5c1STitus Rwantare k->receive_byte = pmbus_receive_byte; 16953746d5c1STitus Rwantare } 16963746d5c1STitus Rwantare 16973746d5c1STitus Rwantare static const TypeInfo pmbus_device_type_info = { 16983746d5c1STitus Rwantare .name = TYPE_PMBUS_DEVICE, 16993746d5c1STitus Rwantare .parent = TYPE_SMBUS_DEVICE, 17003746d5c1STitus Rwantare .instance_size = sizeof(PMBusDevice), 17013746d5c1STitus Rwantare .instance_finalize = pmbus_device_finalize, 17023746d5c1STitus Rwantare .abstract = true, 17033746d5c1STitus Rwantare .class_size = sizeof(PMBusDeviceClass), 17043746d5c1STitus Rwantare .class_init = pmbus_device_class_init, 17053746d5c1STitus Rwantare }; 17063746d5c1STitus Rwantare 17073746d5c1STitus Rwantare static void pmbus_device_register_types(void) 17083746d5c1STitus Rwantare { 17093746d5c1STitus Rwantare type_register_static(&pmbus_device_type_info); 17103746d5c1STitus Rwantare } 17113746d5c1STitus Rwantare 17123746d5c1STitus Rwantare type_init(pmbus_device_register_types) 1713