2 * PMBus wrapper over SMBus
4 * Copyright 2021 Google LLC
6 * SPDX-License-Identifier: GPL-2.0-or-later
9 #include "qemu/osdep.h"
12 #include "hw/i2c/pmbus_device.h"
13 #include "migration/vmstate.h"
14 #include "qemu/module.h"
17 uint16_t pmbus_data2direct_mode(PMBusCoefficients c
, uint32_t value
)
19 /* R is usually negative to fit large readings into 16 bits */
20 uint16_t y
= (c
.m
* value
+ c
.b
) * pow(10, c
.R
);
24 uint32_t pmbus_direct_mode2data(PMBusCoefficients c
, uint16_t value
)
26 /* X = (Y * 10^-R - b) / m */
27 uint32_t x
= (value
/ pow(10, c
.R
) - c
.b
) / c
.m
;
31 uint16_t pmbus_data2linear_mode(uint16_t value
, int exp
)
35 return value
<< (-exp
);
40 uint16_t pmbus_linear_mode2data(uint16_t value
, int exp
)
44 return value
>> (-exp
);
49 void pmbus_send(PMBusDevice
*pmdev
, const uint8_t *data
, uint16_t len
)
51 if (pmdev
->out_buf_len
+ len
> SMBUS_DATA_MAX_LEN
) {
52 qemu_log_mask(LOG_GUEST_ERROR
,
53 "PMBus device tried to send too much data");
57 for (int i
= len
- 1; i
>= 0; i
--) {
58 pmdev
->out_buf
[i
+ pmdev
->out_buf_len
] = data
[len
- i
- 1];
60 pmdev
->out_buf_len
+= len
;
63 /* Internal only, convert unsigned ints to the little endian bus */
64 static void pmbus_send_uint(PMBusDevice
*pmdev
, uint64_t data
, uint8_t size
)
69 for (int i
= 0; i
< size
; i
++) {
70 bytes
[i
] = data
& 0xFF;
73 pmbus_send(pmdev
, bytes
, size
);
76 void pmbus_send8(PMBusDevice
*pmdev
, uint8_t data
)
78 pmbus_send_uint(pmdev
, data
, 1);
81 void pmbus_send16(PMBusDevice
*pmdev
, uint16_t data
)
83 pmbus_send_uint(pmdev
, data
, 2);
86 void pmbus_send32(PMBusDevice
*pmdev
, uint32_t data
)
88 pmbus_send_uint(pmdev
, data
, 4);
91 void pmbus_send64(PMBusDevice
*pmdev
, uint64_t data
)
93 pmbus_send_uint(pmdev
, data
, 8);
96 void pmbus_send_string(PMBusDevice
*pmdev
, const char *data
)
98 size_t len
= strlen(data
);
100 g_assert(len
+ pmdev
->out_buf_len
< SMBUS_DATA_MAX_LEN
);
101 pmdev
->out_buf
[len
+ pmdev
->out_buf_len
] = len
;
103 for (int i
= len
- 1; i
>= 0; i
--) {
104 pmdev
->out_buf
[i
+ pmdev
->out_buf_len
] = data
[len
- 1 - i
];
106 pmdev
->out_buf_len
+= len
+ 1;
110 static uint64_t pmbus_receive_uint(PMBusDevice
*pmdev
)
114 /* Exclude command code from return value */
118 for (int i
= pmdev
->in_buf_len
- 1; i
>= 0; i
--) {
119 ret
= ret
<< 8 | pmdev
->in_buf
[i
];
124 uint8_t pmbus_receive8(PMBusDevice
*pmdev
)
126 if (pmdev
->in_buf_len
- 1 != 1) {
127 qemu_log_mask(LOG_GUEST_ERROR
,
128 "%s: length mismatch. Expected 1 byte, got %d bytes\n",
129 __func__
, pmdev
->in_buf_len
- 1);
131 return pmbus_receive_uint(pmdev
);
134 uint16_t pmbus_receive16(PMBusDevice
*pmdev
)
136 if (pmdev
->in_buf_len
- 1 != 2) {
137 qemu_log_mask(LOG_GUEST_ERROR
,
138 "%s: length mismatch. Expected 2 bytes, got %d bytes\n",
139 __func__
, pmdev
->in_buf_len
- 1);
141 return pmbus_receive_uint(pmdev
);
144 uint32_t pmbus_receive32(PMBusDevice
*pmdev
)
146 if (pmdev
->in_buf_len
- 1 != 4) {
147 qemu_log_mask(LOG_GUEST_ERROR
,
148 "%s: length mismatch. Expected 4 bytes, got %d bytes\n",
149 __func__
, pmdev
->in_buf_len
- 1);
151 return pmbus_receive_uint(pmdev
);
154 uint64_t pmbus_receive64(PMBusDevice
*pmdev
)
156 if (pmdev
->in_buf_len
- 1 != 8) {
157 qemu_log_mask(LOG_GUEST_ERROR
,
158 "%s: length mismatch. Expected 8 bytes, got %d bytes\n",
159 __func__
, pmdev
->in_buf_len
- 1);
161 return pmbus_receive_uint(pmdev
);
164 static uint8_t pmbus_out_buf_pop(PMBusDevice
*pmdev
)
166 if (pmdev
->out_buf_len
== 0) {
167 qemu_log_mask(LOG_GUEST_ERROR
,
168 "%s: tried to read from empty buffer",
170 return PMBUS_ERR_BYTE
;
172 uint8_t data
= pmdev
->out_buf
[pmdev
->out_buf_len
- 1];
173 pmdev
->out_buf_len
--;
177 static void pmbus_quick_cmd(SMBusDevice
*smd
, uint8_t read
)
179 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
180 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
182 if (pmdc
->quick_cmd
) {
183 pmdc
->quick_cmd(pmdev
, read
);
187 static void pmbus_pages_alloc(PMBusDevice
*pmdev
)
189 /* some PMBus devices don't use the PAGE command, so they get 1 page */
190 PMBusDeviceClass
*k
= PMBUS_DEVICE_GET_CLASS(pmdev
);
191 if (k
->device_num_pages
== 0) {
192 k
->device_num_pages
= 1;
194 pmdev
->num_pages
= k
->device_num_pages
;
195 pmdev
->pages
= g_new0(PMBusPage
, k
->device_num_pages
);
198 void pmbus_check_limits(PMBusDevice
*pmdev
)
200 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
201 if ((pmdev
->pages
[i
].operation
& PB_OP_ON
) == 0) {
202 continue; /* don't check powered off devices */
205 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_fault_limit
) {
206 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
207 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_FAULT
;
210 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_warn_limit
) {
211 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
212 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_WARN
;
215 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_warn_limit
) {
216 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
217 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_WARN
;
220 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_fault_limit
) {
221 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
222 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_FAULT
;
225 if (pmdev
->pages
[i
].read_vin
> pmdev
->pages
[i
].vin_ov_warn_limit
) {
226 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
227 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_OV_WARN
;
230 if (pmdev
->pages
[i
].read_vin
< pmdev
->pages
[i
].vin_uv_warn_limit
) {
231 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
232 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_UV_WARN
;
235 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_warn_limit
) {
236 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
237 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_WARN
;
240 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_fault_limit
) {
241 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
242 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_FAULT
;
245 if (pmdev
->pages
[i
].read_pin
> pmdev
->pages
[i
].pin_op_warn_limit
) {
246 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
247 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_PIN_OP_WARN
;
250 if (pmdev
->pages
[i
].read_temperature_1
251 > pmdev
->pages
[i
].ot_fault_limit
) {
252 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
253 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_FAULT
;
256 if (pmdev
->pages
[i
].read_temperature_1
257 > pmdev
->pages
[i
].ot_warn_limit
) {
258 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
259 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_WARN
;
264 void pmbus_idle(PMBusDevice
*pmdev
)
266 pmdev
->code
= PMBUS_IDLE_STATE
;
269 /* assert the status_cml error upon receipt of malformed command */
270 static void pmbus_cml_error(PMBusDevice
*pmdev
)
272 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
273 pmdev
->pages
[i
].status_word
|= PMBUS_STATUS_CML
;
274 pmdev
->pages
[i
].status_cml
|= PB_CML_FAULT_INVALID_CMD
;
278 static uint8_t pmbus_receive_byte(SMBusDevice
*smd
)
280 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
281 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
282 uint8_t ret
= PMBUS_ERR_BYTE
;
285 if (pmdev
->out_buf_len
!= 0) {
286 ret
= pmbus_out_buf_pop(pmdev
);
291 * Reading from all pages will return the value from page 0,
292 * means that all subsequent commands are to be applied to all output.
294 if (pmdev
->page
== PB_ALL_PAGES
) {
296 } else if (pmdev
->page
> pmdev
->num_pages
- 1) {
297 qemu_log_mask(LOG_GUEST_ERROR
,
298 "%s: page %d is out of range\n",
299 __func__
, pmdev
->page
);
300 pmbus_cml_error(pmdev
);
301 return PMBUS_ERR_BYTE
;
306 switch (pmdev
->code
) {
308 pmbus_send8(pmdev
, pmdev
->page
);
311 case PMBUS_OPERATION
: /* R/W byte */
312 pmbus_send8(pmdev
, pmdev
->pages
[index
].operation
);
315 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
316 pmbus_send8(pmdev
, pmdev
->pages
[index
].on_off_config
);
319 case PMBUS_PHASE
: /* R/W byte */
320 pmbus_send8(pmdev
, pmdev
->pages
[index
].phase
);
323 case PMBUS_WRITE_PROTECT
: /* R/W byte */
324 pmbus_send8(pmdev
, pmdev
->pages
[index
].write_protect
);
327 case PMBUS_CAPABILITY
:
328 pmbus_send8(pmdev
, pmdev
->capability
);
329 if (pmdev
->capability
& BIT(7)) {
330 qemu_log_mask(LOG_UNIMP
,
331 "%s: PEC is enabled but not yet supported.\n",
336 case PMBUS_VOUT_MODE
: /* R/W byte */
337 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
338 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_mode
);
344 case PMBUS_VOUT_COMMAND
: /* R/W word */
345 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
346 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_command
);
352 case PMBUS_VOUT_TRIM
: /* R/W word */
353 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
354 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_trim
);
360 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
361 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
362 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_cal_offset
);
368 case PMBUS_VOUT_MAX
: /* R/W word */
369 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
370 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_max
);
376 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
377 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
378 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_high
);
384 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
385 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
386 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_low
);
392 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
393 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
394 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_transition_rate
);
400 case PMBUS_VOUT_DROOP
: /* R/W word */
401 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
402 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_droop
);
408 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
409 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
410 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_loop
);
416 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
417 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
418 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_monitor
);
424 case PMBUS_VOUT_MIN
: /* R/W word */
425 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
426 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_min
);
432 /* TODO: implement coefficients support */
434 case PMBUS_POUT_MAX
: /* R/W word */
435 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
436 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_max
);
442 case PMBUS_VIN_ON
: /* R/W word */
443 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
444 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_on
);
450 case PMBUS_VIN_OFF
: /* R/W word */
451 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
452 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_off
);
458 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
459 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
460 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_cal_gain
);
466 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
467 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
468 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_fault_limit
);
474 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
475 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
476 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_ov_fault_response
);
482 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
483 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
484 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_warn_limit
);
490 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
491 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
492 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_warn_limit
);
498 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
499 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
500 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_fault_limit
);
506 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
507 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
508 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_uv_fault_response
);
514 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
515 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
516 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_fault_limit
);
522 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
523 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
524 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_fault_response
);
530 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
531 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
532 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_limit
);
538 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
539 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
540 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_response
);
546 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
547 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
548 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_warn_limit
);
554 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
555 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
556 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_uc_fault_limit
);
562 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
563 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
564 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_uc_fault_response
);
570 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
571 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
572 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_fault_limit
);
578 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
579 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
580 pmbus_send8(pmdev
, pmdev
->pages
[index
].ot_fault_response
);
586 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
587 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
588 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_warn_limit
);
594 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
595 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
596 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_warn_limit
);
602 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
603 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
604 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_fault_limit
);
610 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
611 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
612 pmbus_send8(pmdev
, pmdev
->pages
[index
].ut_fault_response
);
618 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
619 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
620 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_fault_limit
);
626 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
627 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
628 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_ov_fault_response
);
634 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
635 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
636 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_warn_limit
);
642 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
643 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
644 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_warn_limit
);
650 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
651 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
652 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_fault_limit
);
658 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
659 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
660 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_uv_fault_response
);
666 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
667 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
668 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_fault_limit
);
674 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
675 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
676 pmbus_send8(pmdev
, pmdev
->pages
[index
].iin_oc_fault_response
);
682 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
683 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
684 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_warn_limit
);
690 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
691 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
692 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_fault_limit
);
698 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
699 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
700 pmbus_send8(pmdev
, pmdev
->pages
[index
].pout_op_fault_response
);
706 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
707 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
708 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_warn_limit
);
714 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
715 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
716 pmbus_send16(pmdev
, pmdev
->pages
[index
].pin_op_warn_limit
);
722 case PMBUS_STATUS_BYTE
: /* R/W byte */
723 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_word
& 0xFF);
726 case PMBUS_STATUS_WORD
: /* R/W word */
727 pmbus_send16(pmdev
, pmdev
->pages
[index
].status_word
);
730 case PMBUS_STATUS_VOUT
: /* R/W byte */
731 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
732 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_vout
);
738 case PMBUS_STATUS_IOUT
: /* R/W byte */
739 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
740 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_iout
);
746 case PMBUS_STATUS_INPUT
: /* R/W byte */
747 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
||
748 pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
||
749 pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
750 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_input
);
756 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
757 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
758 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_temperature
);
764 case PMBUS_STATUS_CML
: /* R/W byte */
765 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_cml
);
768 case PMBUS_STATUS_OTHER
: /* R/W byte */
769 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_other
);
772 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
773 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_mfr_specific
);
776 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
777 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EIN
) {
778 pmbus_send(pmdev
, pmdev
->pages
[index
].read_ein
, 5);
784 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
785 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EOUT
) {
786 pmbus_send(pmdev
, pmdev
->pages
[index
].read_eout
, 5);
792 case PMBUS_READ_VIN
: /* Read-Only word */
793 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
794 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vin
);
800 case PMBUS_READ_IIN
: /* Read-Only word */
801 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
802 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iin
);
808 case PMBUS_READ_VOUT
: /* Read-Only word */
809 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
810 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vout
);
816 case PMBUS_READ_IOUT
: /* Read-Only word */
817 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
818 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iout
);
824 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
825 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
826 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_1
);
832 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
833 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP2
) {
834 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_2
);
840 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
841 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP3
) {
842 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_3
);
848 case PMBUS_READ_POUT
: /* Read-Only word */
849 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
850 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pout
);
856 case PMBUS_READ_PIN
: /* Read-Only word */
857 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
858 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pin
);
864 case PMBUS_REVISION
: /* Read-Only byte */
865 pmbus_send8(pmdev
, pmdev
->pages
[index
].revision
);
868 case PMBUS_MFR_ID
: /* R/W block */
869 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
870 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_id
);
876 case PMBUS_MFR_MODEL
: /* R/W block */
877 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
878 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_model
);
884 case PMBUS_MFR_REVISION
: /* R/W block */
885 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
886 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_revision
);
892 case PMBUS_MFR_LOCATION
: /* R/W block */
893 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
894 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_location
);
900 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
901 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
902 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_min
);
908 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
909 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
910 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_max
);
916 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
917 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN_RATING
) {
918 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iin_max
);
924 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
925 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN_RATING
) {
926 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pin_max
);
932 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
933 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
934 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_min
);
940 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
941 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
942 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_max
);
948 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
949 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_RATING
) {
950 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iout_max
);
956 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
957 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT_RATING
) {
958 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pout_max
);
964 case PMBUS_MFR_MAX_TEMP_1
: /* R/W word */
965 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
966 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_1
);
972 case PMBUS_MFR_MAX_TEMP_2
: /* R/W word */
973 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
974 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_2
);
980 case PMBUS_MFR_MAX_TEMP_3
: /* R/W word */
981 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
982 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_3
);
988 case PMBUS_IDLE_STATE
:
989 pmbus_send8(pmdev
, PMBUS_ERR_BYTE
);
992 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
993 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
994 case PMBUS_STORE_DEFAULT_ALL
: /* Send Byte */
995 case PMBUS_RESTORE_DEFAULT_ALL
: /* Send Byte */
996 case PMBUS_STORE_DEFAULT_CODE
: /* Write-only Byte */
997 case PMBUS_RESTORE_DEFAULT_CODE
: /* Write-only Byte */
998 case PMBUS_STORE_USER_ALL
: /* Send Byte */
999 case PMBUS_RESTORE_USER_ALL
: /* Send Byte */
1000 case PMBUS_STORE_USER_CODE
: /* Write-only Byte */
1001 case PMBUS_RESTORE_USER_CODE
: /* Write-only Byte */
1002 case PMBUS_QUERY
: /* Write-Only */
1003 qemu_log_mask(LOG_GUEST_ERROR
,
1004 "%s: reading from write only register 0x%02x\n",
1005 __func__
, pmdev
->code
);
1010 /* Pass through read request if not handled */
1011 if (pmdc
->receive_byte
) {
1012 ret
= pmdc
->receive_byte(pmdev
);
1017 if (pmdev
->out_buf_len
!= 0) {
1018 ret
= pmbus_out_buf_pop(pmdev
);
1026 * PMBus clear faults command applies to all status registers, existing faults
1027 * should separately get re-asserted.
1029 static void pmbus_clear_faults(PMBusDevice
*pmdev
)
1031 for (uint8_t i
= 0; i
< pmdev
->num_pages
; i
++) {
1032 pmdev
->pages
[i
].status_word
= 0;
1033 pmdev
->pages
[i
].status_vout
= 0;
1034 pmdev
->pages
[i
].status_iout
= 0;
1035 pmdev
->pages
[i
].status_input
= 0;
1036 pmdev
->pages
[i
].status_temperature
= 0;
1037 pmdev
->pages
[i
].status_cml
= 0;
1038 pmdev
->pages
[i
].status_other
= 0;
1039 pmdev
->pages
[i
].status_mfr_specific
= 0;
1040 pmdev
->pages
[i
].status_fans_1_2
= 0;
1041 pmdev
->pages
[i
].status_fans_3_4
= 0;
1047 * PMBus operation is used to turn On and Off PSUs
1048 * Therefore, default value for the Operation should be PB_OP_ON or 0x80
1050 static void pmbus_operation(PMBusDevice
*pmdev
)
1052 uint8_t index
= pmdev
->page
;
1053 if ((pmdev
->pages
[index
].operation
& PB_OP_ON
) == 0) {
1054 pmdev
->pages
[index
].read_vout
= 0;
1055 pmdev
->pages
[index
].read_iout
= 0;
1056 pmdev
->pages
[index
].read_pout
= 0;
1060 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_HIGH
)) {
1061 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_high
;
1064 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_LOW
)) {
1065 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_low
;
1067 pmbus_check_limits(pmdev
);
1070 static int pmbus_write_data(SMBusDevice
*smd
, uint8_t *buf
, uint8_t len
)
1072 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
1073 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
1078 qemu_log_mask(LOG_GUEST_ERROR
, "%s: writing empty data\n", __func__
);
1079 return PMBUS_ERR_BYTE
;
1082 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1083 pmbus_pages_alloc(pmdev
);
1086 pmdev
->in_buf_len
= len
;
1087 pmdev
->in_buf
= buf
;
1089 pmdev
->code
= buf
[0]; /* PMBus command code */
1090 if (len
== 1) { /* Single length writes are command codes only */
1094 if (pmdev
->code
== PMBUS_PAGE
) {
1095 pmdev
->page
= pmbus_receive8(pmdev
);
1099 /* loop through all the pages when 0xFF is received */
1100 if (pmdev
->page
== PB_ALL_PAGES
) {
1101 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1103 pmbus_write_data(smd
, buf
, len
);
1105 pmdev
->page
= PB_ALL_PAGES
;
1109 if (pmdev
->page
> pmdev
->num_pages
- 1) {
1110 qemu_log_mask(LOG_GUEST_ERROR
,
1111 "%s: page %u is out of range\n",
1112 __func__
, pmdev
->page
);
1113 pmdev
->page
= 0; /* undefined behaviour - reset to page 0 */
1114 pmbus_cml_error(pmdev
);
1115 return PMBUS_ERR_BYTE
;
1118 index
= pmdev
->page
;
1120 switch (pmdev
->code
) {
1121 case PMBUS_OPERATION
: /* R/W byte */
1122 pmdev
->pages
[index
].operation
= pmbus_receive8(pmdev
);
1123 pmbus_operation(pmdev
);
1126 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
1127 pmdev
->pages
[index
].on_off_config
= pmbus_receive8(pmdev
);
1130 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
1131 pmbus_clear_faults(pmdev
);
1134 case PMBUS_PHASE
: /* R/W byte */
1135 pmdev
->pages
[index
].phase
= pmbus_receive8(pmdev
);
1138 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
1139 case PMBUS_WRITE_PROTECT
: /* R/W byte */
1140 pmdev
->pages
[index
].write_protect
= pmbus_receive8(pmdev
);
1143 case PMBUS_VOUT_MODE
: /* R/W byte */
1144 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
1145 pmdev
->pages
[index
].vout_mode
= pmbus_receive8(pmdev
);
1151 case PMBUS_VOUT_COMMAND
: /* R/W word */
1152 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1153 pmdev
->pages
[index
].vout_command
= pmbus_receive16(pmdev
);
1159 case PMBUS_VOUT_TRIM
: /* R/W word */
1160 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1161 pmdev
->pages
[index
].vout_trim
= pmbus_receive16(pmdev
);
1167 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
1168 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1169 pmdev
->pages
[index
].vout_cal_offset
= pmbus_receive16(pmdev
);
1175 case PMBUS_VOUT_MAX
: /* R/W word */
1176 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1177 pmdev
->pages
[index
].vout_max
= pmbus_receive16(pmdev
);
1183 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
1184 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1185 pmdev
->pages
[index
].vout_margin_high
= pmbus_receive16(pmdev
);
1191 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
1192 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1193 pmdev
->pages
[index
].vout_margin_low
= pmbus_receive16(pmdev
);
1199 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
1200 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1201 pmdev
->pages
[index
].vout_transition_rate
= pmbus_receive16(pmdev
);
1207 case PMBUS_VOUT_DROOP
: /* R/W word */
1208 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1209 pmdev
->pages
[index
].vout_droop
= pmbus_receive16(pmdev
);
1215 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
1216 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1217 pmdev
->pages
[index
].vout_scale_loop
= pmbus_receive16(pmdev
);
1223 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
1224 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1225 pmdev
->pages
[index
].vout_scale_monitor
= pmbus_receive16(pmdev
);
1231 case PMBUS_VOUT_MIN
: /* R/W word */
1232 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
1233 pmdev
->pages
[index
].vout_min
= pmbus_receive16(pmdev
);
1239 case PMBUS_POUT_MAX
: /* R/W word */
1240 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1241 pmdev
->pages
[index
].pout_max
= pmbus_receive16(pmdev
);
1247 case PMBUS_VIN_ON
: /* R/W word */
1248 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1249 pmdev
->pages
[index
].vin_on
= pmbus_receive16(pmdev
);
1255 case PMBUS_VIN_OFF
: /* R/W word */
1256 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1257 pmdev
->pages
[index
].vin_off
= pmbus_receive16(pmdev
);
1263 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
1264 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
1265 pmdev
->pages
[index
].iout_cal_gain
= pmbus_receive16(pmdev
);
1271 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
1272 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1273 pmdev
->pages
[index
].vout_ov_fault_limit
= pmbus_receive16(pmdev
);
1279 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
1280 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1281 pmdev
->pages
[index
].vout_ov_fault_response
= pmbus_receive8(pmdev
);
1287 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
1288 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1289 pmdev
->pages
[index
].vout_ov_warn_limit
= pmbus_receive16(pmdev
);
1295 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
1296 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1297 pmdev
->pages
[index
].vout_uv_warn_limit
= pmbus_receive16(pmdev
);
1303 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
1304 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1305 pmdev
->pages
[index
].vout_uv_fault_limit
= pmbus_receive16(pmdev
);
1311 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
1312 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1313 pmdev
->pages
[index
].vout_uv_fault_response
= pmbus_receive8(pmdev
);
1319 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
1320 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1321 pmdev
->pages
[index
].iout_oc_fault_limit
= pmbus_receive16(pmdev
);
1327 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
1328 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1329 pmdev
->pages
[index
].iout_oc_fault_response
= pmbus_receive8(pmdev
);
1335 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
1336 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1337 pmdev
->pages
[index
].iout_oc_lv_fault_limit
= pmbus_receive16(pmdev
);
1343 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
1344 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1345 pmdev
->pages
[index
].iout_oc_lv_fault_response
1346 = pmbus_receive8(pmdev
);
1352 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
1353 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1354 pmdev
->pages
[index
].iout_oc_warn_limit
= pmbus_receive16(pmdev
);
1360 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
1361 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1362 pmdev
->pages
[index
].iout_uc_fault_limit
= pmbus_receive16(pmdev
);
1368 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
1369 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1370 pmdev
->pages
[index
].iout_uc_fault_response
= pmbus_receive8(pmdev
);
1376 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
1377 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1378 pmdev
->pages
[index
].ot_fault_limit
= pmbus_receive16(pmdev
);
1384 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
1385 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1386 pmdev
->pages
[index
].ot_fault_response
= pmbus_receive8(pmdev
);
1392 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
1393 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1394 pmdev
->pages
[index
].ot_warn_limit
= pmbus_receive16(pmdev
);
1400 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
1401 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1402 pmdev
->pages
[index
].ut_warn_limit
= pmbus_receive16(pmdev
);
1408 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
1409 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1410 pmdev
->pages
[index
].ut_fault_limit
= pmbus_receive16(pmdev
);
1416 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
1417 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1418 pmdev
->pages
[index
].ut_fault_response
= pmbus_receive8(pmdev
);
1424 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
1425 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1426 pmdev
->pages
[index
].vin_ov_fault_limit
= pmbus_receive16(pmdev
);
1432 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
1433 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1434 pmdev
->pages
[index
].vin_ov_fault_response
= pmbus_receive8(pmdev
);
1440 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
1441 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1442 pmdev
->pages
[index
].vin_ov_warn_limit
= pmbus_receive16(pmdev
);
1448 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
1449 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1450 pmdev
->pages
[index
].vin_uv_warn_limit
= pmbus_receive16(pmdev
);
1456 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
1457 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1458 pmdev
->pages
[index
].vin_uv_fault_limit
= pmbus_receive16(pmdev
);
1464 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
1465 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1466 pmdev
->pages
[index
].vin_uv_fault_response
= pmbus_receive8(pmdev
);
1472 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
1473 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1474 pmdev
->pages
[index
].iin_oc_fault_limit
= pmbus_receive16(pmdev
);
1480 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
1481 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1482 pmdev
->pages
[index
].iin_oc_fault_response
= pmbus_receive8(pmdev
);
1488 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
1489 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1490 pmdev
->pages
[index
].iin_oc_warn_limit
= pmbus_receive16(pmdev
);
1496 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
1497 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1498 pmdev
->pages
[index
].pout_op_fault_limit
= pmbus_receive16(pmdev
);
1504 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
1505 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1506 pmdev
->pages
[index
].pout_op_fault_response
= pmbus_receive8(pmdev
);
1512 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
1513 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1514 pmdev
->pages
[index
].pout_op_warn_limit
= pmbus_receive16(pmdev
);
1520 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
1521 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
1522 pmdev
->pages
[index
].pin_op_warn_limit
= pmbus_receive16(pmdev
);
1528 case PMBUS_STATUS_BYTE
: /* R/W byte */
1529 pmdev
->pages
[index
].status_word
= pmbus_receive8(pmdev
);
1532 case PMBUS_STATUS_WORD
: /* R/W word */
1533 pmdev
->pages
[index
].status_word
= pmbus_receive16(pmdev
);
1536 case PMBUS_STATUS_VOUT
: /* R/W byte */
1537 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1538 pmdev
->pages
[index
].status_vout
= pmbus_receive8(pmdev
);
1544 case PMBUS_STATUS_IOUT
: /* R/W byte */
1545 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1546 pmdev
->pages
[index
].status_iout
= pmbus_receive8(pmdev
);
1552 case PMBUS_STATUS_INPUT
: /* R/W byte */
1553 pmdev
->pages
[index
].status_input
= pmbus_receive8(pmdev
);
1556 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
1557 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1558 pmdev
->pages
[index
].status_temperature
= pmbus_receive8(pmdev
);
1564 case PMBUS_STATUS_CML
: /* R/W byte */
1565 pmdev
->pages
[index
].status_cml
= pmbus_receive8(pmdev
);
1568 case PMBUS_STATUS_OTHER
: /* R/W byte */
1569 pmdev
->pages
[index
].status_other
= pmbus_receive8(pmdev
);
1572 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
1573 pmdev
->pages
[index
].status_mfr_specific
= pmbus_receive8(pmdev
);
1576 case PMBUS_PAGE_PLUS_READ
: /* Block Read-only */
1577 case PMBUS_CAPABILITY
: /* Read-Only byte */
1578 case PMBUS_COEFFICIENTS
: /* Read-only block 5 bytes */
1579 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
1580 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
1581 case PMBUS_READ_VIN
: /* Read-Only word */
1582 case PMBUS_READ_IIN
: /* Read-Only word */
1583 case PMBUS_READ_VCAP
: /* Read-Only word */
1584 case PMBUS_READ_VOUT
: /* Read-Only word */
1585 case PMBUS_READ_IOUT
: /* Read-Only word */
1586 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
1587 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
1588 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
1589 case PMBUS_READ_FAN_SPEED_1
: /* Read-Only word */
1590 case PMBUS_READ_FAN_SPEED_2
: /* Read-Only word */
1591 case PMBUS_READ_FAN_SPEED_3
: /* Read-Only word */
1592 case PMBUS_READ_FAN_SPEED_4
: /* Read-Only word */
1593 case PMBUS_READ_DUTY_CYCLE
: /* Read-Only word */
1594 case PMBUS_READ_FREQUENCY
: /* Read-Only word */
1595 case PMBUS_READ_POUT
: /* Read-Only word */
1596 case PMBUS_READ_PIN
: /* Read-Only word */
1597 case PMBUS_REVISION
: /* Read-Only byte */
1598 case PMBUS_APP_PROFILE_SUPPORT
: /* Read-Only block-read */
1599 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
1600 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
1601 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
1602 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
1603 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
1604 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
1605 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
1606 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
1607 case PMBUS_MFR_TAMBIENT_MAX
: /* Read-Only word */
1608 case PMBUS_MFR_TAMBIENT_MIN
: /* Read-Only word */
1609 case PMBUS_MFR_EFFICIENCY_LL
: /* Read-Only block 14 bytes */
1610 case PMBUS_MFR_EFFICIENCY_HL
: /* Read-Only block 14 bytes */
1611 case PMBUS_MFR_PIN_ACCURACY
: /* Read-Only byte */
1612 case PMBUS_IC_DEVICE_ID
: /* Read-Only block-read */
1613 case PMBUS_IC_DEVICE_REV
: /* Read-Only block-read */
1614 qemu_log_mask(LOG_GUEST_ERROR
,
1615 "%s: writing to read-only register 0x%02x\n",
1616 __func__
, pmdev
->code
);
1620 /* Unimplimented registers get passed to the device */
1622 if (pmdc
->write_data
) {
1623 ret
= pmdc
->write_data(pmdev
, buf
, len
);
1627 pmbus_check_limits(pmdev
);
1628 pmdev
->in_buf_len
= 0;
1632 int pmbus_page_config(PMBusDevice
*pmdev
, uint8_t index
, uint64_t flags
)
1634 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1635 pmbus_pages_alloc(pmdev
);
1638 /* The 0xFF page is special for commands applying to all pages */
1639 if (index
== PB_ALL_PAGES
) {
1640 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1641 pmdev
->pages
[i
].page_flags
= flags
;
1646 if (index
> pmdev
->num_pages
- 1) {
1647 qemu_log_mask(LOG_GUEST_ERROR
,
1648 "%s: index %u is out of range\n",
1653 pmdev
->pages
[index
].page_flags
= flags
;
1658 /* TODO: include pmbus page info in vmstate */
1659 const VMStateDescription vmstate_pmbus_device
= {
1660 .name
= TYPE_PMBUS_DEVICE
,
1662 .minimum_version_id
= 0,
1663 .fields
= (VMStateField
[]) {
1664 VMSTATE_SMBUS_DEVICE(smb
, PMBusDevice
),
1665 VMSTATE_UINT8(num_pages
, PMBusDevice
),
1666 VMSTATE_UINT8(code
, PMBusDevice
),
1667 VMSTATE_UINT8(page
, PMBusDevice
),
1668 VMSTATE_UINT8(capability
, PMBusDevice
),
1669 VMSTATE_END_OF_LIST()
1673 static void pmbus_device_finalize(Object
*obj
)
1675 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
1676 g_free(pmdev
->pages
);
1679 static void pmbus_device_class_init(ObjectClass
*klass
, void *data
)
1681 SMBusDeviceClass
*k
= SMBUS_DEVICE_CLASS(klass
);
1683 k
->quick_cmd
= pmbus_quick_cmd
;
1684 k
->write_data
= pmbus_write_data
;
1685 k
->receive_byte
= pmbus_receive_byte
;
1688 static const TypeInfo pmbus_device_type_info
= {
1689 .name
= TYPE_PMBUS_DEVICE
,
1690 .parent
= TYPE_SMBUS_DEVICE
,
1691 .instance_size
= sizeof(PMBusDevice
),
1692 .instance_finalize
= pmbus_device_finalize
,
1694 .class_size
= sizeof(PMBusDeviceClass
),
1695 .class_init
= pmbus_device_class_init
,
1698 static void pmbus_device_register_types(void)
1700 type_register_static(&pmbus_device_type_info
);
1703 type_init(pmbus_device_register_types
)