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