2 * PMBus wrapper over SMBus
4 * Copyright 2021 Google LLC
6 * SPDX-License-Identifier: GPL-2.0-or-later
9 #include "qemu/osdep.h"
11 #include "hw/i2c/pmbus_device.h"
12 #include "migration/vmstate.h"
13 #include "qemu/module.h"
16 uint16_t pmbus_data2direct_mode(PMBusCoefficients c
, uint32_t value
)
18 /* R is usually negative to fit large readings into 16 bits */
19 uint16_t y
= (c
.m
* value
+ c
.b
) * pow(10, c
.R
);
23 uint32_t pmbus_direct_mode2data(PMBusCoefficients c
, uint16_t value
)
25 /* X = (Y * 10^-R - b) / m */
26 uint32_t x
= (value
/ pow(10, c
.R
) - c
.b
) / c
.m
;
30 uint16_t pmbus_data2linear_mode(uint16_t value
, int exp
)
34 return value
<< (-exp
);
39 uint16_t pmbus_linear_mode2data(uint16_t value
, int exp
)
43 return value
>> (-exp
);
48 void pmbus_send(PMBusDevice
*pmdev
, const uint8_t *data
, uint16_t len
)
50 if (pmdev
->out_buf_len
+ len
> SMBUS_DATA_MAX_LEN
) {
51 qemu_log_mask(LOG_GUEST_ERROR
,
52 "PMBus device tried to send too much data");
56 for (int i
= len
- 1; i
>= 0; i
--) {
57 pmdev
->out_buf
[i
+ pmdev
->out_buf_len
] = data
[len
- i
- 1];
59 pmdev
->out_buf_len
+= len
;
62 /* Internal only, convert unsigned ints to the little endian bus */
63 static void pmbus_send_uint(PMBusDevice
*pmdev
, uint64_t data
, uint8_t size
)
68 for (int i
= 0; i
< size
; i
++) {
69 bytes
[i
] = data
& 0xFF;
72 pmbus_send(pmdev
, bytes
, size
);
75 void pmbus_send8(PMBusDevice
*pmdev
, uint8_t data
)
77 pmbus_send_uint(pmdev
, data
, 1);
80 void pmbus_send16(PMBusDevice
*pmdev
, uint16_t data
)
82 pmbus_send_uint(pmdev
, data
, 2);
85 void pmbus_send32(PMBusDevice
*pmdev
, uint32_t data
)
87 pmbus_send_uint(pmdev
, data
, 4);
90 void pmbus_send64(PMBusDevice
*pmdev
, uint64_t data
)
92 pmbus_send_uint(pmdev
, data
, 8);
95 void pmbus_send_string(PMBusDevice
*pmdev
, const char *data
)
97 size_t len
= strlen(data
);
99 g_assert(len
+ pmdev
->out_buf_len
< SMBUS_DATA_MAX_LEN
);
100 pmdev
->out_buf
[len
+ pmdev
->out_buf_len
] = len
;
102 for (int i
= len
- 1; i
>= 0; i
--) {
103 pmdev
->out_buf
[i
+ pmdev
->out_buf_len
] = data
[len
- 1 - i
];
105 pmdev
->out_buf_len
+= len
+ 1;
109 static uint64_t pmbus_receive_uint(PMBusDevice
*pmdev
)
113 /* Exclude command code from return value */
117 for (int i
= pmdev
->in_buf_len
- 1; i
>= 0; i
--) {
118 ret
= ret
<< 8 | pmdev
->in_buf
[i
];
123 uint8_t pmbus_receive8(PMBusDevice
*pmdev
)
125 if (pmdev
->in_buf_len
- 1 != 1) {
126 qemu_log_mask(LOG_GUEST_ERROR
,
127 "%s: length mismatch. Expected 1 byte, got %d bytes\n",
128 __func__
, pmdev
->in_buf_len
- 1);
130 return pmbus_receive_uint(pmdev
);
133 uint16_t pmbus_receive16(PMBusDevice
*pmdev
)
135 if (pmdev
->in_buf_len
- 1 != 2) {
136 qemu_log_mask(LOG_GUEST_ERROR
,
137 "%s: length mismatch. Expected 2 bytes, got %d bytes\n",
138 __func__
, pmdev
->in_buf_len
- 1);
140 return pmbus_receive_uint(pmdev
);
143 uint32_t pmbus_receive32(PMBusDevice
*pmdev
)
145 if (pmdev
->in_buf_len
- 1 != 4) {
146 qemu_log_mask(LOG_GUEST_ERROR
,
147 "%s: length mismatch. Expected 4 bytes, got %d bytes\n",
148 __func__
, pmdev
->in_buf_len
- 1);
150 return pmbus_receive_uint(pmdev
);
153 uint64_t pmbus_receive64(PMBusDevice
*pmdev
)
155 if (pmdev
->in_buf_len
- 1 != 8) {
156 qemu_log_mask(LOG_GUEST_ERROR
,
157 "%s: length mismatch. Expected 8 bytes, got %d bytes\n",
158 __func__
, pmdev
->in_buf_len
- 1);
160 return pmbus_receive_uint(pmdev
);
163 static uint8_t pmbus_out_buf_pop(PMBusDevice
*pmdev
)
165 if (pmdev
->out_buf_len
== 0) {
166 qemu_log_mask(LOG_GUEST_ERROR
,
167 "%s: tried to read from empty buffer",
169 return PMBUS_ERR_BYTE
;
171 uint8_t data
= pmdev
->out_buf
[pmdev
->out_buf_len
- 1];
172 pmdev
->out_buf_len
--;
176 static void pmbus_quick_cmd(SMBusDevice
*smd
, uint8_t read
)
178 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
179 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
181 if (pmdc
->quick_cmd
) {
182 pmdc
->quick_cmd(pmdev
, read
);
186 static void pmbus_pages_alloc(PMBusDevice
*pmdev
)
188 /* some PMBus devices don't use the PAGE command, so they get 1 page */
189 PMBusDeviceClass
*k
= PMBUS_DEVICE_GET_CLASS(pmdev
);
190 if (k
->device_num_pages
== 0) {
191 k
->device_num_pages
= 1;
193 pmdev
->num_pages
= k
->device_num_pages
;
194 pmdev
->pages
= g_new0(PMBusPage
, k
->device_num_pages
);
197 void pmbus_check_limits(PMBusDevice
*pmdev
)
199 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
200 if ((pmdev
->pages
[i
].operation
& PB_OP_ON
) == 0) {
201 continue; /* don't check powered off devices */
204 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_fault_limit
) {
205 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
206 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_FAULT
;
209 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_warn_limit
) {
210 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
211 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_WARN
;
214 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_warn_limit
) {
215 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
216 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_WARN
;
219 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_fault_limit
) {
220 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
221 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_FAULT
;
224 if (pmdev
->pages
[i
].read_vin
> pmdev
->pages
[i
].vin_ov_warn_limit
) {
225 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
226 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_OV_WARN
;
229 if (pmdev
->pages
[i
].read_vin
< pmdev
->pages
[i
].vin_uv_warn_limit
) {
230 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
231 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_UV_WARN
;
234 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_warn_limit
) {
235 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
236 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_WARN
;
239 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_fault_limit
) {
240 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
241 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_FAULT
;
244 if (pmdev
->pages
[i
].read_pin
> pmdev
->pages
[i
].pin_op_warn_limit
) {
245 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
246 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_PIN_OP_WARN
;
249 if (pmdev
->pages
[i
].read_temperature_1
250 > pmdev
->pages
[i
].ot_fault_limit
) {
251 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
252 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_FAULT
;
255 if (pmdev
->pages
[i
].read_temperature_1
256 > pmdev
->pages
[i
].ot_warn_limit
) {
257 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
258 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_WARN
;
263 void pmbus_idle(PMBusDevice
*pmdev
)
265 pmdev
->code
= PMBUS_IDLE_STATE
;
268 /* assert the status_cml error upon receipt of malformed command */
269 static void pmbus_cml_error(PMBusDevice
*pmdev
)
271 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
272 pmdev
->pages
[i
].status_word
|= PMBUS_STATUS_CML
;
273 pmdev
->pages
[i
].status_cml
|= PB_CML_FAULT_INVALID_CMD
;
277 static uint8_t pmbus_receive_byte(SMBusDevice
*smd
)
279 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
280 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
281 uint8_t ret
= PMBUS_ERR_BYTE
;
284 if (pmdev
->out_buf_len
!= 0) {
285 ret
= pmbus_out_buf_pop(pmdev
);
290 * Reading from all pages will return the value from page 0,
291 * means that all subsequent commands are to be applied to all output.
293 if (pmdev
->page
== PB_ALL_PAGES
) {
295 } else if (pmdev
->page
> pmdev
->num_pages
- 1) {
296 qemu_log_mask(LOG_GUEST_ERROR
,
297 "%s: page %d is out of range\n",
298 __func__
, pmdev
->page
);
299 pmbus_cml_error(pmdev
);
300 return PMBUS_ERR_BYTE
;
305 switch (pmdev
->code
) {
307 pmbus_send8(pmdev
, pmdev
->page
);
310 case PMBUS_OPERATION
: /* R/W byte */
311 pmbus_send8(pmdev
, pmdev
->pages
[index
].operation
);
314 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
315 pmbus_send8(pmdev
, pmdev
->pages
[index
].on_off_config
);
318 case PMBUS_PHASE
: /* R/W byte */
319 pmbus_send8(pmdev
, pmdev
->pages
[index
].phase
);
322 case PMBUS_WRITE_PROTECT
: /* R/W byte */
323 pmbus_send8(pmdev
, pmdev
->pages
[index
].write_protect
);
326 case PMBUS_CAPABILITY
:
327 pmbus_send8(pmdev
, pmdev
->capability
);
328 if (pmdev
->capability
& BIT(7)) {
329 qemu_log_mask(LOG_UNIMP
,
330 "%s: PEC is enabled but not yet supported.\n",
335 case PMBUS_VOUT_MODE
: /* R/W byte */
336 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
337 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_mode
);
343 case PMBUS_VOUT_COMMAND
: /* R/W word */
344 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
345 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_command
);
351 case PMBUS_VOUT_TRIM
: /* R/W word */
352 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
353 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_trim
);
359 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
360 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
361 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_cal_offset
);
367 case PMBUS_VOUT_MAX
: /* R/W word */
368 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
369 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_max
);
375 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
376 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
377 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_high
);
383 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
384 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
385 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_low
);
391 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
392 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
393 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_transition_rate
);
399 case PMBUS_VOUT_DROOP
: /* R/W word */
400 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
401 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_droop
);
407 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
408 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
409 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_loop
);
415 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
416 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
417 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_monitor
);
423 case PMBUS_VOUT_MIN
: /* R/W word */
424 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
425 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_min
);
431 /* TODO: implement coefficients support */
433 case PMBUS_POUT_MAX
: /* R/W word */
434 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
435 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_max
);
441 case PMBUS_VIN_ON
: /* R/W word */
442 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
443 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_on
);
449 case PMBUS_VIN_OFF
: /* R/W word */
450 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
451 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_off
);
457 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
458 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
459 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_cal_gain
);
465 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
466 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
467 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_fault_limit
);
473 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
474 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
475 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_ov_fault_response
);
481 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
482 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
483 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_warn_limit
);
489 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
490 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
491 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_warn_limit
);
497 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
498 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
499 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_fault_limit
);
505 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
506 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
507 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_uv_fault_response
);
513 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
514 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
515 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_fault_limit
);
521 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
522 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
523 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_fault_response
);
529 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
530 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
531 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_limit
);
537 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
538 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
539 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_response
);
545 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
546 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
547 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_warn_limit
);
553 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
554 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
555 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_uc_fault_limit
);
561 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
562 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
563 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_uc_fault_response
);
569 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
570 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
571 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_fault_limit
);
577 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
578 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
579 pmbus_send8(pmdev
, pmdev
->pages
[index
].ot_fault_response
);
585 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
586 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
587 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_warn_limit
);
593 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
594 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
595 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_warn_limit
);
601 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
602 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
603 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_fault_limit
);
609 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
610 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
611 pmbus_send8(pmdev
, pmdev
->pages
[index
].ut_fault_response
);
617 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
618 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
619 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_fault_limit
);
625 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
626 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
627 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_ov_fault_response
);
633 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
634 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
635 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_warn_limit
);
641 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
642 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
643 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_warn_limit
);
649 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
650 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
651 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_fault_limit
);
657 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
658 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
659 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_uv_fault_response
);
665 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
666 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
667 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_fault_limit
);
673 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
674 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
675 pmbus_send8(pmdev
, pmdev
->pages
[index
].iin_oc_fault_response
);
681 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
682 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
683 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_warn_limit
);
689 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
690 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
691 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_fault_limit
);
697 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
698 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
699 pmbus_send8(pmdev
, pmdev
->pages
[index
].pout_op_fault_response
);
705 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
706 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
707 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_warn_limit
);
713 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
714 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
715 pmbus_send16(pmdev
, pmdev
->pages
[index
].pin_op_warn_limit
);
721 case PMBUS_STATUS_BYTE
: /* R/W byte */
722 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_word
& 0xFF);
725 case PMBUS_STATUS_WORD
: /* R/W word */
726 pmbus_send16(pmdev
, pmdev
->pages
[index
].status_word
);
729 case PMBUS_STATUS_VOUT
: /* R/W byte */
730 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
731 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_vout
);
737 case PMBUS_STATUS_IOUT
: /* R/W byte */
738 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
739 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_iout
);
745 case PMBUS_STATUS_INPUT
: /* R/W byte */
746 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
||
747 pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
||
748 pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
749 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_input
);
755 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
756 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
757 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_temperature
);
763 case PMBUS_STATUS_CML
: /* R/W byte */
764 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_cml
);
767 case PMBUS_STATUS_OTHER
: /* R/W byte */
768 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_other
);
771 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
772 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_mfr_specific
);
775 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
776 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EIN
) {
777 pmbus_send(pmdev
, pmdev
->pages
[index
].read_ein
, 5);
783 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
784 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EOUT
) {
785 pmbus_send(pmdev
, pmdev
->pages
[index
].read_eout
, 5);
791 case PMBUS_READ_VIN
: /* Read-Only word */
792 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
793 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vin
);
799 case PMBUS_READ_IIN
: /* Read-Only word */
800 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
801 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iin
);
807 case PMBUS_READ_VOUT
: /* Read-Only word */
808 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
809 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vout
);
815 case PMBUS_READ_IOUT
: /* Read-Only word */
816 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
817 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iout
);
823 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
824 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
825 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_1
);
831 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
832 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP2
) {
833 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_2
);
839 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
840 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP3
) {
841 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_3
);
847 case PMBUS_READ_POUT
: /* Read-Only word */
848 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
849 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pout
);
855 case PMBUS_READ_PIN
: /* Read-Only word */
856 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
857 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pin
);
863 case PMBUS_REVISION
: /* Read-Only byte */
864 pmbus_send8(pmdev
, pmdev
->pages
[index
].revision
);
867 case PMBUS_MFR_ID
: /* R/W block */
868 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
869 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_id
);
875 case PMBUS_MFR_MODEL
: /* R/W block */
876 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
877 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_model
);
883 case PMBUS_MFR_REVISION
: /* R/W block */
884 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
885 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_revision
);
891 case PMBUS_MFR_LOCATION
: /* R/W block */
892 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
893 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_location
);
899 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
900 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
901 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_min
);
907 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
908 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
909 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_max
);
915 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
916 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN_RATING
) {
917 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iin_max
);
923 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
924 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN_RATING
) {
925 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pin_max
);
931 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
932 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
933 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_min
);
939 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
940 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
941 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_max
);
947 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
948 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_RATING
) {
949 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iout_max
);
955 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
956 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT_RATING
) {
957 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pout_max
);
963 case PMBUS_MFR_MAX_TEMP_1
: /* R/W word */
964 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
965 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_1
);
971 case PMBUS_MFR_MAX_TEMP_2
: /* R/W word */
972 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
973 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_2
);
979 case PMBUS_MFR_MAX_TEMP_3
: /* R/W word */
980 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
981 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_3
);
987 case PMBUS_IDLE_STATE
:
988 pmbus_send8(pmdev
, PMBUS_ERR_BYTE
);
991 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
992 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
993 case PMBUS_STORE_DEFAULT_ALL
: /* Send Byte */
994 case PMBUS_RESTORE_DEFAULT_ALL
: /* Send Byte */
995 case PMBUS_STORE_DEFAULT_CODE
: /* Write-only Byte */
996 case PMBUS_RESTORE_DEFAULT_CODE
: /* Write-only Byte */
997 case PMBUS_STORE_USER_ALL
: /* Send Byte */
998 case PMBUS_RESTORE_USER_ALL
: /* Send Byte */
999 case PMBUS_STORE_USER_CODE
: /* Write-only Byte */
1000 case PMBUS_RESTORE_USER_CODE
: /* Write-only Byte */
1001 case PMBUS_QUERY
: /* Write-Only */
1002 qemu_log_mask(LOG_GUEST_ERROR
,
1003 "%s: reading from write only register 0x%02x\n",
1004 __func__
, pmdev
->code
);
1009 /* Pass through read request if not handled */
1010 if (pmdc
->receive_byte
) {
1011 ret
= pmdc
->receive_byte(pmdev
);
1016 if (pmdev
->out_buf_len
!= 0) {
1017 ret
= pmbus_out_buf_pop(pmdev
);
1025 * PMBus clear faults command applies to all status registers, existing faults
1026 * should separately get re-asserted.
1028 static void pmbus_clear_faults(PMBusDevice
*pmdev
)
1030 for (uint8_t i
= 0; i
< pmdev
->num_pages
; i
++) {
1031 pmdev
->pages
[i
].status_word
= 0;
1032 pmdev
->pages
[i
].status_vout
= 0;
1033 pmdev
->pages
[i
].status_iout
= 0;
1034 pmdev
->pages
[i
].status_input
= 0;
1035 pmdev
->pages
[i
].status_temperature
= 0;
1036 pmdev
->pages
[i
].status_cml
= 0;
1037 pmdev
->pages
[i
].status_other
= 0;
1038 pmdev
->pages
[i
].status_mfr_specific
= 0;
1039 pmdev
->pages
[i
].status_fans_1_2
= 0;
1040 pmdev
->pages
[i
].status_fans_3_4
= 0;
1046 * PMBus operation is used to turn On and Off PSUs
1047 * Therefore, default value for the Operation should be PB_OP_ON or 0x80
1049 static void pmbus_operation(PMBusDevice
*pmdev
)
1051 uint8_t index
= pmdev
->page
;
1052 if ((pmdev
->pages
[index
].operation
& PB_OP_ON
) == 0) {
1053 pmdev
->pages
[index
].read_vout
= 0;
1054 pmdev
->pages
[index
].read_iout
= 0;
1055 pmdev
->pages
[index
].read_pout
= 0;
1059 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_HIGH
)) {
1060 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_high
;
1063 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_LOW
)) {
1064 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_low
;
1066 pmbus_check_limits(pmdev
);
1069 static int pmbus_write_data(SMBusDevice
*smd
, uint8_t *buf
, uint8_t len
)
1071 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
1072 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
1077 qemu_log_mask(LOG_GUEST_ERROR
, "%s: writing empty data\n", __func__
);
1078 return PMBUS_ERR_BYTE
;
1081 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1082 pmbus_pages_alloc(pmdev
);
1085 pmdev
->in_buf_len
= len
;
1086 pmdev
->in_buf
= buf
;
1088 pmdev
->code
= buf
[0]; /* PMBus command code */
1089 if (len
== 1) { /* Single length writes are command codes only */
1093 if (pmdev
->code
== PMBUS_PAGE
) {
1094 pmdev
->page
= pmbus_receive8(pmdev
);
1098 /* loop through all the pages when 0xFF is received */
1099 if (pmdev
->page
== PB_ALL_PAGES
) {
1100 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1102 pmbus_write_data(smd
, buf
, len
);
1104 pmdev
->page
= PB_ALL_PAGES
;
1108 if (pmdev
->page
> pmdev
->num_pages
- 1) {
1109 qemu_log_mask(LOG_GUEST_ERROR
,
1110 "%s: page %u is out of range\n",
1111 __func__
, pmdev
->page
);
1112 pmdev
->page
= 0; /* undefined behaviour - reset to page 0 */
1113 pmbus_cml_error(pmdev
);
1114 return PMBUS_ERR_BYTE
;
1117 index
= pmdev
->page
;
1119 switch (pmdev
->code
) {
1120 case PMBUS_OPERATION
: /* R/W byte */
1121 pmdev
->pages
[index
].operation
= pmbus_receive8(pmdev
);
1122 pmbus_operation(pmdev
);
1125 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
1126 pmdev
->pages
[index
].on_off_config
= pmbus_receive8(pmdev
);
1129 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
1130 pmbus_clear_faults(pmdev
);
1133 case PMBUS_PHASE
: /* R/W byte */
1134 pmdev
->pages
[index
].phase
= pmbus_receive8(pmdev
);
1137 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
1138 case PMBUS_WRITE_PROTECT
: /* R/W byte */
1139 pmdev
->pages
[index
].write_protect
= pmbus_receive8(pmdev
);
1142 case PMBUS_VOUT_MODE
: /* R/W byte */
1143 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
1144 pmdev
->pages
[index
].vout_mode
= pmbus_receive8(pmdev
);
1150 case PMBUS_VOUT_COMMAND
: /* R/W word */
1151 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1152 pmdev
->pages
[index
].vout_command
= pmbus_receive16(pmdev
);
1158 case PMBUS_VOUT_TRIM
: /* R/W word */
1159 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1160 pmdev
->pages
[index
].vout_trim
= pmbus_receive16(pmdev
);
1166 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
1167 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1168 pmdev
->pages
[index
].vout_cal_offset
= pmbus_receive16(pmdev
);
1174 case PMBUS_VOUT_MAX
: /* R/W word */
1175 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1176 pmdev
->pages
[index
].vout_max
= pmbus_receive16(pmdev
);
1182 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
1183 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1184 pmdev
->pages
[index
].vout_margin_high
= pmbus_receive16(pmdev
);
1190 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
1191 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1192 pmdev
->pages
[index
].vout_margin_low
= pmbus_receive16(pmdev
);
1198 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
1199 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1200 pmdev
->pages
[index
].vout_transition_rate
= pmbus_receive16(pmdev
);
1206 case PMBUS_VOUT_DROOP
: /* R/W word */
1207 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1208 pmdev
->pages
[index
].vout_droop
= pmbus_receive16(pmdev
);
1214 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
1215 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1216 pmdev
->pages
[index
].vout_scale_loop
= pmbus_receive16(pmdev
);
1222 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
1223 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1224 pmdev
->pages
[index
].vout_scale_monitor
= pmbus_receive16(pmdev
);
1230 case PMBUS_VOUT_MIN
: /* R/W word */
1231 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
1232 pmdev
->pages
[index
].vout_min
= pmbus_receive16(pmdev
);
1238 case PMBUS_POUT_MAX
: /* R/W word */
1239 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1240 pmdev
->pages
[index
].pout_max
= pmbus_receive16(pmdev
);
1246 case PMBUS_VIN_ON
: /* R/W word */
1247 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1248 pmdev
->pages
[index
].vin_on
= pmbus_receive16(pmdev
);
1254 case PMBUS_VIN_OFF
: /* R/W word */
1255 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1256 pmdev
->pages
[index
].vin_off
= pmbus_receive16(pmdev
);
1262 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
1263 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
1264 pmdev
->pages
[index
].iout_cal_gain
= pmbus_receive16(pmdev
);
1270 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
1271 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1272 pmdev
->pages
[index
].vout_ov_fault_limit
= pmbus_receive16(pmdev
);
1278 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
1279 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1280 pmdev
->pages
[index
].vout_ov_fault_response
= pmbus_receive8(pmdev
);
1286 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
1287 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1288 pmdev
->pages
[index
].vout_ov_warn_limit
= pmbus_receive16(pmdev
);
1294 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
1295 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1296 pmdev
->pages
[index
].vout_uv_warn_limit
= pmbus_receive16(pmdev
);
1302 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
1303 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1304 pmdev
->pages
[index
].vout_uv_fault_limit
= pmbus_receive16(pmdev
);
1310 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
1311 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1312 pmdev
->pages
[index
].vout_uv_fault_response
= pmbus_receive8(pmdev
);
1318 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
1319 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1320 pmdev
->pages
[index
].iout_oc_fault_limit
= pmbus_receive16(pmdev
);
1326 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
1327 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1328 pmdev
->pages
[index
].iout_oc_fault_response
= pmbus_receive8(pmdev
);
1334 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
1335 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1336 pmdev
->pages
[index
].iout_oc_lv_fault_limit
= pmbus_receive16(pmdev
);
1342 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
1343 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1344 pmdev
->pages
[index
].iout_oc_lv_fault_response
1345 = pmbus_receive8(pmdev
);
1351 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
1352 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1353 pmdev
->pages
[index
].iout_oc_warn_limit
= pmbus_receive16(pmdev
);
1359 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
1360 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1361 pmdev
->pages
[index
].iout_uc_fault_limit
= pmbus_receive16(pmdev
);
1367 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
1368 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1369 pmdev
->pages
[index
].iout_uc_fault_response
= pmbus_receive8(pmdev
);
1375 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
1376 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1377 pmdev
->pages
[index
].ot_fault_limit
= pmbus_receive16(pmdev
);
1383 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
1384 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1385 pmdev
->pages
[index
].ot_fault_response
= pmbus_receive8(pmdev
);
1391 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
1392 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1393 pmdev
->pages
[index
].ot_warn_limit
= pmbus_receive16(pmdev
);
1399 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
1400 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1401 pmdev
->pages
[index
].ut_warn_limit
= pmbus_receive16(pmdev
);
1407 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
1408 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1409 pmdev
->pages
[index
].ut_fault_limit
= pmbus_receive16(pmdev
);
1415 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
1416 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1417 pmdev
->pages
[index
].ut_fault_response
= pmbus_receive8(pmdev
);
1423 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
1424 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1425 pmdev
->pages
[index
].vin_ov_fault_limit
= pmbus_receive16(pmdev
);
1431 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
1432 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1433 pmdev
->pages
[index
].vin_ov_fault_response
= pmbus_receive8(pmdev
);
1439 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
1440 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1441 pmdev
->pages
[index
].vin_ov_warn_limit
= pmbus_receive16(pmdev
);
1447 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
1448 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1449 pmdev
->pages
[index
].vin_uv_warn_limit
= pmbus_receive16(pmdev
);
1455 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
1456 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1457 pmdev
->pages
[index
].vin_uv_fault_limit
= pmbus_receive16(pmdev
);
1463 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
1464 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1465 pmdev
->pages
[index
].vin_uv_fault_response
= pmbus_receive8(pmdev
);
1471 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
1472 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1473 pmdev
->pages
[index
].iin_oc_fault_limit
= pmbus_receive16(pmdev
);
1479 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
1480 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1481 pmdev
->pages
[index
].iin_oc_fault_response
= pmbus_receive8(pmdev
);
1487 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
1488 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1489 pmdev
->pages
[index
].iin_oc_warn_limit
= pmbus_receive16(pmdev
);
1495 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
1496 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1497 pmdev
->pages
[index
].pout_op_fault_limit
= pmbus_receive16(pmdev
);
1503 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
1504 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1505 pmdev
->pages
[index
].pout_op_fault_response
= pmbus_receive8(pmdev
);
1511 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
1512 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1513 pmdev
->pages
[index
].pout_op_warn_limit
= pmbus_receive16(pmdev
);
1519 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
1520 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
1521 pmdev
->pages
[index
].pin_op_warn_limit
= pmbus_receive16(pmdev
);
1527 case PMBUS_STATUS_BYTE
: /* R/W byte */
1528 pmdev
->pages
[index
].status_word
= pmbus_receive8(pmdev
);
1531 case PMBUS_STATUS_WORD
: /* R/W word */
1532 pmdev
->pages
[index
].status_word
= pmbus_receive16(pmdev
);
1535 case PMBUS_STATUS_VOUT
: /* R/W byte */
1536 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1537 pmdev
->pages
[index
].status_vout
= pmbus_receive8(pmdev
);
1543 case PMBUS_STATUS_IOUT
: /* R/W byte */
1544 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1545 pmdev
->pages
[index
].status_iout
= pmbus_receive8(pmdev
);
1551 case PMBUS_STATUS_INPUT
: /* R/W byte */
1552 pmdev
->pages
[index
].status_input
= pmbus_receive8(pmdev
);
1555 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
1556 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1557 pmdev
->pages
[index
].status_temperature
= pmbus_receive8(pmdev
);
1563 case PMBUS_STATUS_CML
: /* R/W byte */
1564 pmdev
->pages
[index
].status_cml
= pmbus_receive8(pmdev
);
1567 case PMBUS_STATUS_OTHER
: /* R/W byte */
1568 pmdev
->pages
[index
].status_other
= pmbus_receive8(pmdev
);
1571 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
1572 pmdev
->pages
[index
].status_mfr_specific
= pmbus_receive8(pmdev
);
1575 case PMBUS_PAGE_PLUS_READ
: /* Block Read-only */
1576 case PMBUS_CAPABILITY
: /* Read-Only byte */
1577 case PMBUS_COEFFICIENTS
: /* Read-only block 5 bytes */
1578 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
1579 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
1580 case PMBUS_READ_VIN
: /* Read-Only word */
1581 case PMBUS_READ_IIN
: /* Read-Only word */
1582 case PMBUS_READ_VCAP
: /* Read-Only word */
1583 case PMBUS_READ_VOUT
: /* Read-Only word */
1584 case PMBUS_READ_IOUT
: /* Read-Only word */
1585 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
1586 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
1587 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
1588 case PMBUS_READ_FAN_SPEED_1
: /* Read-Only word */
1589 case PMBUS_READ_FAN_SPEED_2
: /* Read-Only word */
1590 case PMBUS_READ_FAN_SPEED_3
: /* Read-Only word */
1591 case PMBUS_READ_FAN_SPEED_4
: /* Read-Only word */
1592 case PMBUS_READ_DUTY_CYCLE
: /* Read-Only word */
1593 case PMBUS_READ_FREQUENCY
: /* Read-Only word */
1594 case PMBUS_READ_POUT
: /* Read-Only word */
1595 case PMBUS_READ_PIN
: /* Read-Only word */
1596 case PMBUS_REVISION
: /* Read-Only byte */
1597 case PMBUS_APP_PROFILE_SUPPORT
: /* Read-Only block-read */
1598 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
1599 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
1600 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
1601 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
1602 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
1603 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
1604 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
1605 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
1606 case PMBUS_MFR_TAMBIENT_MAX
: /* Read-Only word */
1607 case PMBUS_MFR_TAMBIENT_MIN
: /* Read-Only word */
1608 case PMBUS_MFR_EFFICIENCY_LL
: /* Read-Only block 14 bytes */
1609 case PMBUS_MFR_EFFICIENCY_HL
: /* Read-Only block 14 bytes */
1610 case PMBUS_MFR_PIN_ACCURACY
: /* Read-Only byte */
1611 case PMBUS_IC_DEVICE_ID
: /* Read-Only block-read */
1612 case PMBUS_IC_DEVICE_REV
: /* Read-Only block-read */
1613 qemu_log_mask(LOG_GUEST_ERROR
,
1614 "%s: writing to read-only register 0x%02x\n",
1615 __func__
, pmdev
->code
);
1619 /* Unimplimented registers get passed to the device */
1621 if (pmdc
->write_data
) {
1622 ret
= pmdc
->write_data(pmdev
, buf
, len
);
1626 pmbus_check_limits(pmdev
);
1627 pmdev
->in_buf_len
= 0;
1631 int pmbus_page_config(PMBusDevice
*pmdev
, uint8_t index
, uint64_t flags
)
1633 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1634 pmbus_pages_alloc(pmdev
);
1637 /* The 0xFF page is special for commands applying to all pages */
1638 if (index
== PB_ALL_PAGES
) {
1639 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1640 pmdev
->pages
[i
].page_flags
= flags
;
1645 if (index
> pmdev
->num_pages
- 1) {
1646 qemu_log_mask(LOG_GUEST_ERROR
,
1647 "%s: index %u is out of range\n",
1652 pmdev
->pages
[index
].page_flags
= flags
;
1657 /* TODO: include pmbus page info in vmstate */
1658 const VMStateDescription vmstate_pmbus_device
= {
1659 .name
= TYPE_PMBUS_DEVICE
,
1661 .minimum_version_id
= 0,
1662 .fields
= (VMStateField
[]) {
1663 VMSTATE_SMBUS_DEVICE(smb
, PMBusDevice
),
1664 VMSTATE_UINT8(num_pages
, PMBusDevice
),
1665 VMSTATE_UINT8(code
, PMBusDevice
),
1666 VMSTATE_UINT8(page
, PMBusDevice
),
1667 VMSTATE_UINT8(capability
, PMBusDevice
),
1668 VMSTATE_END_OF_LIST()
1672 static void pmbus_device_finalize(Object
*obj
)
1674 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
1675 g_free(pmdev
->pages
);
1678 static void pmbus_device_class_init(ObjectClass
*klass
, void *data
)
1680 SMBusDeviceClass
*k
= SMBUS_DEVICE_CLASS(klass
);
1682 k
->quick_cmd
= pmbus_quick_cmd
;
1683 k
->write_data
= pmbus_write_data
;
1684 k
->receive_byte
= pmbus_receive_byte
;
1687 static const TypeInfo pmbus_device_type_info
= {
1688 .name
= TYPE_PMBUS_DEVICE
,
1689 .parent
= TYPE_SMBUS_DEVICE
,
1690 .instance_size
= sizeof(PMBusDevice
),
1691 .instance_finalize
= pmbus_device_finalize
,
1693 .class_size
= sizeof(PMBusDeviceClass
),
1694 .class_init
= pmbus_device_class_init
,
1697 static void pmbus_device_register_types(void)
1699 type_register_static(&pmbus_device_type_info
);
1702 type_init(pmbus_device_register_types
)