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 void pmbus_send(PMBusDevice
*pmdev
, const uint8_t *data
, uint16_t len
)
33 if (pmdev
->out_buf_len
+ len
> SMBUS_DATA_MAX_LEN
) {
34 qemu_log_mask(LOG_GUEST_ERROR
,
35 "PMBus device tried to send too much data");
39 for (int i
= len
- 1; i
>= 0; i
--) {
40 pmdev
->out_buf
[i
+ pmdev
->out_buf_len
] = data
[len
- i
- 1];
42 pmdev
->out_buf_len
+= len
;
45 /* Internal only, convert unsigned ints to the little endian bus */
46 static void pmbus_send_uint(PMBusDevice
*pmdev
, uint64_t data
, uint8_t size
)
51 for (int i
= 0; i
< size
; i
++) {
52 bytes
[i
] = data
& 0xFF;
55 pmbus_send(pmdev
, bytes
, size
);
58 void pmbus_send8(PMBusDevice
*pmdev
, uint8_t data
)
60 pmbus_send_uint(pmdev
, data
, 1);
63 void pmbus_send16(PMBusDevice
*pmdev
, uint16_t data
)
65 pmbus_send_uint(pmdev
, data
, 2);
68 void pmbus_send32(PMBusDevice
*pmdev
, uint32_t data
)
70 pmbus_send_uint(pmdev
, data
, 4);
73 void pmbus_send64(PMBusDevice
*pmdev
, uint64_t data
)
75 pmbus_send_uint(pmdev
, data
, 8);
78 void pmbus_send_string(PMBusDevice
*pmdev
, const char *data
)
80 size_t len
= strlen(data
);
82 g_assert(len
+ pmdev
->out_buf_len
< SMBUS_DATA_MAX_LEN
);
83 pmdev
->out_buf
[len
+ pmdev
->out_buf_len
] = len
;
85 for (int i
= len
- 1; i
>= 0; i
--) {
86 pmdev
->out_buf
[i
+ pmdev
->out_buf_len
] = data
[len
- 1 - i
];
88 pmdev
->out_buf_len
+= len
+ 1;
92 static uint64_t pmbus_receive_uint(PMBusDevice
*pmdev
)
96 /* Exclude command code from return value */
100 for (int i
= pmdev
->in_buf_len
- 1; i
>= 0; i
--) {
101 ret
= ret
<< 8 | pmdev
->in_buf
[i
];
106 uint8_t pmbus_receive8(PMBusDevice
*pmdev
)
108 if (pmdev
->in_buf_len
- 1 != 1) {
109 qemu_log_mask(LOG_GUEST_ERROR
,
110 "%s: length mismatch. Expected 1 byte, got %d bytes\n",
111 __func__
, pmdev
->in_buf_len
- 1);
113 return pmbus_receive_uint(pmdev
);
116 uint16_t pmbus_receive16(PMBusDevice
*pmdev
)
118 if (pmdev
->in_buf_len
- 1 != 2) {
119 qemu_log_mask(LOG_GUEST_ERROR
,
120 "%s: length mismatch. Expected 2 bytes, got %d bytes\n",
121 __func__
, pmdev
->in_buf_len
- 1);
123 return pmbus_receive_uint(pmdev
);
126 uint32_t pmbus_receive32(PMBusDevice
*pmdev
)
128 if (pmdev
->in_buf_len
- 1 != 4) {
129 qemu_log_mask(LOG_GUEST_ERROR
,
130 "%s: length mismatch. Expected 4 bytes, got %d bytes\n",
131 __func__
, pmdev
->in_buf_len
- 1);
133 return pmbus_receive_uint(pmdev
);
136 uint64_t pmbus_receive64(PMBusDevice
*pmdev
)
138 if (pmdev
->in_buf_len
- 1 != 8) {
139 qemu_log_mask(LOG_GUEST_ERROR
,
140 "%s: length mismatch. Expected 8 bytes, got %d bytes\n",
141 __func__
, pmdev
->in_buf_len
- 1);
143 return pmbus_receive_uint(pmdev
);
146 static uint8_t pmbus_out_buf_pop(PMBusDevice
*pmdev
)
148 if (pmdev
->out_buf_len
== 0) {
149 qemu_log_mask(LOG_GUEST_ERROR
,
150 "%s: tried to read from empty buffer",
152 return PMBUS_ERR_BYTE
;
154 uint8_t data
= pmdev
->out_buf
[pmdev
->out_buf_len
- 1];
155 pmdev
->out_buf_len
--;
159 static void pmbus_quick_cmd(SMBusDevice
*smd
, uint8_t read
)
161 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
162 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
164 if (pmdc
->quick_cmd
) {
165 pmdc
->quick_cmd(pmdev
, read
);
169 static void pmbus_pages_alloc(PMBusDevice
*pmdev
)
171 /* some PMBus devices don't use the PAGE command, so they get 1 page */
172 PMBusDeviceClass
*k
= PMBUS_DEVICE_GET_CLASS(pmdev
);
173 if (k
->device_num_pages
== 0) {
174 k
->device_num_pages
= 1;
176 pmdev
->num_pages
= k
->device_num_pages
;
177 pmdev
->pages
= g_new0(PMBusPage
, k
->device_num_pages
);
180 void pmbus_check_limits(PMBusDevice
*pmdev
)
182 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
183 if ((pmdev
->pages
[i
].operation
& PB_OP_ON
) == 0) {
184 continue; /* don't check powered off devices */
187 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_fault_limit
) {
188 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
189 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_FAULT
;
192 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_warn_limit
) {
193 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
194 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_WARN
;
197 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_warn_limit
) {
198 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
199 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_WARN
;
202 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_fault_limit
) {
203 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
204 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_FAULT
;
207 if (pmdev
->pages
[i
].read_vin
> pmdev
->pages
[i
].vin_ov_warn_limit
) {
208 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
209 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_OV_WARN
;
212 if (pmdev
->pages
[i
].read_vin
< pmdev
->pages
[i
].vin_uv_warn_limit
) {
213 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
214 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_UV_WARN
;
217 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_warn_limit
) {
218 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
219 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_WARN
;
222 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_fault_limit
) {
223 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
224 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_FAULT
;
227 if (pmdev
->pages
[i
].read_pin
> pmdev
->pages
[i
].pin_op_warn_limit
) {
228 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
229 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_PIN_OP_WARN
;
232 if (pmdev
->pages
[i
].read_temperature_1
233 > pmdev
->pages
[i
].ot_fault_limit
) {
234 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
235 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_FAULT
;
238 if (pmdev
->pages
[i
].read_temperature_1
239 > pmdev
->pages
[i
].ot_warn_limit
) {
240 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
241 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_WARN
;
246 /* assert the status_cml error upon receipt of malformed command */
247 static void pmbus_cml_error(PMBusDevice
*pmdev
)
249 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
250 pmdev
->pages
[i
].status_word
|= PMBUS_STATUS_CML
;
251 pmdev
->pages
[i
].status_cml
|= PB_CML_FAULT_INVALID_CMD
;
255 static uint8_t pmbus_receive_byte(SMBusDevice
*smd
)
257 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
258 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
259 uint8_t ret
= PMBUS_ERR_BYTE
;
262 if (pmdev
->out_buf_len
!= 0) {
263 ret
= pmbus_out_buf_pop(pmdev
);
268 * Reading from all pages will return the value from page 0,
269 * this is unspecified behaviour in general.
271 if (pmdev
->page
== PB_ALL_PAGES
) {
273 qemu_log_mask(LOG_GUEST_ERROR
,
274 "%s: tried to read from all pages\n",
276 pmbus_cml_error(pmdev
);
277 } else if (pmdev
->page
> pmdev
->num_pages
- 1) {
278 qemu_log_mask(LOG_GUEST_ERROR
,
279 "%s: page %d is out of range\n",
280 __func__
, pmdev
->page
);
281 pmbus_cml_error(pmdev
);
282 return PMBUS_ERR_BYTE
;
287 switch (pmdev
->code
) {
289 pmbus_send8(pmdev
, pmdev
->page
);
292 case PMBUS_OPERATION
: /* R/W byte */
293 pmbus_send8(pmdev
, pmdev
->pages
[index
].operation
);
296 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
297 pmbus_send8(pmdev
, pmdev
->pages
[index
].on_off_config
);
300 case PMBUS_PHASE
: /* R/W byte */
301 pmbus_send8(pmdev
, pmdev
->pages
[index
].phase
);
304 case PMBUS_WRITE_PROTECT
: /* R/W byte */
305 pmbus_send8(pmdev
, pmdev
->pages
[index
].write_protect
);
308 case PMBUS_CAPABILITY
:
309 pmbus_send8(pmdev
, pmdev
->capability
);
310 if (pmdev
->capability
& BIT(7)) {
311 qemu_log_mask(LOG_UNIMP
,
312 "%s: PEC is enabled but not yet supported.\n",
317 case PMBUS_VOUT_MODE
: /* R/W byte */
318 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
319 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_mode
);
325 case PMBUS_VOUT_COMMAND
: /* R/W word */
326 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
327 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_command
);
333 case PMBUS_VOUT_TRIM
: /* R/W word */
334 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
335 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_trim
);
341 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
342 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
343 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_cal_offset
);
349 case PMBUS_VOUT_MAX
: /* R/W word */
350 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
351 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_max
);
357 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
358 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
359 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_high
);
365 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
366 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
367 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_low
);
373 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
374 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
375 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_transition_rate
);
381 case PMBUS_VOUT_DROOP
: /* R/W word */
382 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
383 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_droop
);
389 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
390 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
391 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_loop
);
397 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
398 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
399 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_monitor
);
405 case PMBUS_VOUT_MIN
: /* R/W word */
406 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
407 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_min
);
413 /* TODO: implement coefficients support */
415 case PMBUS_POUT_MAX
: /* R/W word */
416 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
417 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_max
);
423 case PMBUS_VIN_ON
: /* R/W word */
424 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
425 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_on
);
431 case PMBUS_VIN_OFF
: /* R/W word */
432 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
433 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_off
);
439 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
440 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
441 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_cal_gain
);
447 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
448 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
449 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_fault_limit
);
455 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
456 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
457 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_ov_fault_response
);
463 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
464 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
465 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_warn_limit
);
471 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
472 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
473 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_warn_limit
);
479 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
480 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
481 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_fault_limit
);
487 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
488 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
489 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_uv_fault_response
);
495 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
496 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
497 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_fault_limit
);
503 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
504 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
505 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_fault_response
);
511 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
512 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
513 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_limit
);
519 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
520 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
521 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_response
);
527 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
528 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
529 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_warn_limit
);
535 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
536 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
537 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_uc_fault_limit
);
543 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
544 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
545 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_uc_fault_response
);
551 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
552 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
553 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_fault_limit
);
559 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
560 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
561 pmbus_send8(pmdev
, pmdev
->pages
[index
].ot_fault_response
);
567 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
568 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
569 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_warn_limit
);
575 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
576 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
577 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_warn_limit
);
583 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
584 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
585 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_fault_limit
);
591 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
592 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
593 pmbus_send8(pmdev
, pmdev
->pages
[index
].ut_fault_response
);
599 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
600 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
601 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_fault_limit
);
607 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
608 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
609 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_ov_fault_response
);
615 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
616 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
617 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_warn_limit
);
623 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
624 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
625 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_warn_limit
);
631 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
632 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
633 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_fault_limit
);
639 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
640 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
641 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_uv_fault_response
);
647 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
648 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
649 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_fault_limit
);
655 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
656 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
657 pmbus_send8(pmdev
, pmdev
->pages
[index
].iin_oc_fault_response
);
663 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
664 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
665 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_warn_limit
);
671 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
672 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
673 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_fault_limit
);
679 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
680 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
681 pmbus_send8(pmdev
, pmdev
->pages
[index
].pout_op_fault_response
);
687 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
688 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
689 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_warn_limit
);
695 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
696 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
697 pmbus_send16(pmdev
, pmdev
->pages
[index
].pin_op_warn_limit
);
703 case PMBUS_STATUS_BYTE
: /* R/W byte */
704 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_word
& 0xFF);
707 case PMBUS_STATUS_WORD
: /* R/W word */
708 pmbus_send16(pmdev
, pmdev
->pages
[index
].status_word
);
711 case PMBUS_STATUS_VOUT
: /* R/W byte */
712 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
713 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_vout
);
719 case PMBUS_STATUS_IOUT
: /* R/W byte */
720 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
721 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_iout
);
727 case PMBUS_STATUS_INPUT
: /* R/W byte */
728 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
||
729 pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
||
730 pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
731 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_input
);
737 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
738 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
739 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_temperature
);
745 case PMBUS_STATUS_CML
: /* R/W byte */
746 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_cml
);
749 case PMBUS_STATUS_OTHER
: /* R/W byte */
750 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_other
);
753 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
754 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_mfr_specific
);
757 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
758 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EIN
) {
759 pmbus_send(pmdev
, pmdev
->pages
[index
].read_ein
, 5);
765 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
766 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EOUT
) {
767 pmbus_send(pmdev
, pmdev
->pages
[index
].read_eout
, 5);
773 case PMBUS_READ_VIN
: /* Read-Only word */
774 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
775 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vin
);
781 case PMBUS_READ_IIN
: /* Read-Only word */
782 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
783 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iin
);
789 case PMBUS_READ_VOUT
: /* Read-Only word */
790 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
791 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vout
);
797 case PMBUS_READ_IOUT
: /* Read-Only word */
798 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
799 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iout
);
805 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
806 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
807 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_1
);
813 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
814 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP2
) {
815 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_2
);
821 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
822 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP3
) {
823 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_3
);
829 case PMBUS_READ_POUT
: /* Read-Only word */
830 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
831 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pout
);
837 case PMBUS_READ_PIN
: /* Read-Only word */
838 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
839 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pin
);
845 case PMBUS_REVISION
: /* Read-Only byte */
846 pmbus_send8(pmdev
, pmdev
->pages
[index
].revision
);
849 case PMBUS_MFR_ID
: /* R/W block */
850 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
851 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_id
);
857 case PMBUS_MFR_MODEL
: /* R/W block */
858 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
859 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_model
);
865 case PMBUS_MFR_REVISION
: /* R/W block */
866 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
867 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_revision
);
873 case PMBUS_MFR_LOCATION
: /* R/W block */
874 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
875 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_location
);
881 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
882 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
883 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_min
);
889 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
890 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
891 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_max
);
897 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
898 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN_RATING
) {
899 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iin_max
);
905 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
906 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN_RATING
) {
907 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pin_max
);
913 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
914 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
915 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_min
);
921 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
922 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
923 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_max
);
929 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
930 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_RATING
) {
931 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iout_max
);
937 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
938 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT_RATING
) {
939 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pout_max
);
945 case PMBUS_MFR_MAX_TEMP_1
: /* R/W word */
946 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
947 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_1
);
953 case PMBUS_MFR_MAX_TEMP_2
: /* R/W word */
954 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
955 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_2
);
961 case PMBUS_MFR_MAX_TEMP_3
: /* R/W word */
962 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
963 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_3
);
969 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
970 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
971 case PMBUS_STORE_DEFAULT_ALL
: /* Send Byte */
972 case PMBUS_RESTORE_DEFAULT_ALL
: /* Send Byte */
973 case PMBUS_STORE_DEFAULT_CODE
: /* Write-only Byte */
974 case PMBUS_RESTORE_DEFAULT_CODE
: /* Write-only Byte */
975 case PMBUS_STORE_USER_ALL
: /* Send Byte */
976 case PMBUS_RESTORE_USER_ALL
: /* Send Byte */
977 case PMBUS_STORE_USER_CODE
: /* Write-only Byte */
978 case PMBUS_RESTORE_USER_CODE
: /* Write-only Byte */
979 case PMBUS_QUERY
: /* Write-Only */
980 qemu_log_mask(LOG_GUEST_ERROR
,
981 "%s: reading from write only register 0x%02x\n",
982 __func__
, pmdev
->code
);
987 /* Pass through read request if not handled */
988 if (pmdc
->receive_byte
) {
989 ret
= pmdc
->receive_byte(pmdev
);
994 if (pmdev
->out_buf_len
!= 0) {
995 ret
= pmbus_out_buf_pop(pmdev
);
1003 * PMBus clear faults command applies to all status registers, existing faults
1004 * should separately get re-asserted.
1006 static void pmbus_clear_faults(PMBusDevice
*pmdev
)
1008 for (uint8_t i
= 0; i
< pmdev
->num_pages
; i
++) {
1009 pmdev
->pages
[i
].status_word
= 0;
1010 pmdev
->pages
[i
].status_vout
= 0;
1011 pmdev
->pages
[i
].status_iout
= 0;
1012 pmdev
->pages
[i
].status_input
= 0;
1013 pmdev
->pages
[i
].status_temperature
= 0;
1014 pmdev
->pages
[i
].status_cml
= 0;
1015 pmdev
->pages
[i
].status_other
= 0;
1016 pmdev
->pages
[i
].status_mfr_specific
= 0;
1017 pmdev
->pages
[i
].status_fans_1_2
= 0;
1018 pmdev
->pages
[i
].status_fans_3_4
= 0;
1024 * PMBus operation is used to turn On and Off PSUs
1025 * Therefore, default value for the Operation should be PB_OP_ON or 0x80
1027 static void pmbus_operation(PMBusDevice
*pmdev
)
1029 uint8_t index
= pmdev
->page
;
1030 if ((pmdev
->pages
[index
].operation
& PB_OP_ON
) == 0) {
1031 pmdev
->pages
[index
].read_vout
= 0;
1032 pmdev
->pages
[index
].read_iout
= 0;
1033 pmdev
->pages
[index
].read_pout
= 0;
1037 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_HIGH
)) {
1038 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_high
;
1041 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_LOW
)) {
1042 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_low
;
1044 pmbus_check_limits(pmdev
);
1047 static int pmbus_write_data(SMBusDevice
*smd
, uint8_t *buf
, uint8_t len
)
1049 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
1050 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
1055 qemu_log_mask(LOG_GUEST_ERROR
, "%s: writing empty data\n", __func__
);
1056 return PMBUS_ERR_BYTE
;
1059 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1060 pmbus_pages_alloc(pmdev
);
1063 pmdev
->in_buf_len
= len
;
1064 pmdev
->in_buf
= buf
;
1066 pmdev
->code
= buf
[0]; /* PMBus command code */
1067 if (len
== 1) { /* Single length writes are command codes only */
1071 if (pmdev
->code
== PMBUS_PAGE
) {
1072 pmdev
->page
= pmbus_receive8(pmdev
);
1076 /* loop through all the pages when 0xFF is received */
1077 if (pmdev
->page
== PB_ALL_PAGES
) {
1078 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1080 pmbus_write_data(smd
, buf
, len
);
1082 pmdev
->page
= PB_ALL_PAGES
;
1086 if (pmdev
->page
> pmdev
->num_pages
- 1) {
1087 qemu_log_mask(LOG_GUEST_ERROR
,
1088 "%s: page %u is out of range\n",
1089 __func__
, pmdev
->page
);
1090 pmdev
->page
= 0; /* undefined behaviour - reset to page 0 */
1091 pmbus_cml_error(pmdev
);
1092 return PMBUS_ERR_BYTE
;
1095 index
= pmdev
->page
;
1097 switch (pmdev
->code
) {
1098 case PMBUS_OPERATION
: /* R/W byte */
1099 pmdev
->pages
[index
].operation
= pmbus_receive8(pmdev
);
1100 pmbus_operation(pmdev
);
1103 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
1104 pmdev
->pages
[index
].on_off_config
= pmbus_receive8(pmdev
);
1107 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
1108 pmbus_clear_faults(pmdev
);
1111 case PMBUS_PHASE
: /* R/W byte */
1112 pmdev
->pages
[index
].phase
= pmbus_receive8(pmdev
);
1115 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
1116 case PMBUS_WRITE_PROTECT
: /* R/W byte */
1117 pmdev
->pages
[index
].write_protect
= pmbus_receive8(pmdev
);
1120 case PMBUS_VOUT_MODE
: /* R/W byte */
1121 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
1122 pmdev
->pages
[index
].vout_mode
= pmbus_receive8(pmdev
);
1128 case PMBUS_VOUT_COMMAND
: /* R/W word */
1129 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1130 pmdev
->pages
[index
].vout_command
= pmbus_receive16(pmdev
);
1136 case PMBUS_VOUT_TRIM
: /* R/W word */
1137 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1138 pmdev
->pages
[index
].vout_trim
= pmbus_receive16(pmdev
);
1144 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
1145 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1146 pmdev
->pages
[index
].vout_cal_offset
= pmbus_receive16(pmdev
);
1152 case PMBUS_VOUT_MAX
: /* R/W word */
1153 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1154 pmdev
->pages
[index
].vout_max
= pmbus_receive16(pmdev
);
1160 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
1161 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1162 pmdev
->pages
[index
].vout_margin_high
= pmbus_receive16(pmdev
);
1168 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
1169 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1170 pmdev
->pages
[index
].vout_margin_low
= pmbus_receive16(pmdev
);
1176 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
1177 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1178 pmdev
->pages
[index
].vout_transition_rate
= pmbus_receive16(pmdev
);
1184 case PMBUS_VOUT_DROOP
: /* R/W word */
1185 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1186 pmdev
->pages
[index
].vout_droop
= pmbus_receive16(pmdev
);
1192 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
1193 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1194 pmdev
->pages
[index
].vout_scale_loop
= pmbus_receive16(pmdev
);
1200 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
1201 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1202 pmdev
->pages
[index
].vout_scale_monitor
= pmbus_receive16(pmdev
);
1208 case PMBUS_VOUT_MIN
: /* R/W word */
1209 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
1210 pmdev
->pages
[index
].vout_min
= pmbus_receive16(pmdev
);
1216 case PMBUS_POUT_MAX
: /* R/W word */
1217 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1218 pmdev
->pages
[index
].pout_max
= pmbus_receive16(pmdev
);
1224 case PMBUS_VIN_ON
: /* R/W word */
1225 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1226 pmdev
->pages
[index
].vin_on
= pmbus_receive16(pmdev
);
1232 case PMBUS_VIN_OFF
: /* R/W word */
1233 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1234 pmdev
->pages
[index
].vin_off
= pmbus_receive16(pmdev
);
1240 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
1241 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
1242 pmdev
->pages
[index
].iout_cal_gain
= pmbus_receive16(pmdev
);
1248 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
1249 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1250 pmdev
->pages
[index
].vout_ov_fault_limit
= pmbus_receive16(pmdev
);
1256 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
1257 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1258 pmdev
->pages
[index
].vout_ov_fault_response
= pmbus_receive8(pmdev
);
1264 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
1265 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1266 pmdev
->pages
[index
].vout_ov_warn_limit
= pmbus_receive16(pmdev
);
1272 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
1273 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1274 pmdev
->pages
[index
].vout_uv_warn_limit
= pmbus_receive16(pmdev
);
1280 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
1281 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1282 pmdev
->pages
[index
].vout_uv_fault_limit
= pmbus_receive16(pmdev
);
1288 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
1289 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1290 pmdev
->pages
[index
].vout_uv_fault_response
= pmbus_receive8(pmdev
);
1296 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
1297 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1298 pmdev
->pages
[index
].iout_oc_fault_limit
= pmbus_receive16(pmdev
);
1304 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
1305 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1306 pmdev
->pages
[index
].iout_oc_fault_response
= pmbus_receive8(pmdev
);
1312 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
1313 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1314 pmdev
->pages
[index
].iout_oc_lv_fault_limit
= pmbus_receive16(pmdev
);
1320 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
1321 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1322 pmdev
->pages
[index
].iout_oc_lv_fault_response
1323 = pmbus_receive8(pmdev
);
1329 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
1330 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1331 pmdev
->pages
[index
].iout_oc_warn_limit
= pmbus_receive16(pmdev
);
1337 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
1338 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1339 pmdev
->pages
[index
].iout_uc_fault_limit
= pmbus_receive16(pmdev
);
1345 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
1346 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1347 pmdev
->pages
[index
].iout_uc_fault_response
= pmbus_receive8(pmdev
);
1353 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
1354 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1355 pmdev
->pages
[index
].ot_fault_limit
= pmbus_receive16(pmdev
);
1361 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
1362 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1363 pmdev
->pages
[index
].ot_fault_response
= pmbus_receive8(pmdev
);
1369 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
1370 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1371 pmdev
->pages
[index
].ot_warn_limit
= pmbus_receive16(pmdev
);
1377 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
1378 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1379 pmdev
->pages
[index
].ut_warn_limit
= pmbus_receive16(pmdev
);
1385 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
1386 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1387 pmdev
->pages
[index
].ut_fault_limit
= pmbus_receive16(pmdev
);
1393 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
1394 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1395 pmdev
->pages
[index
].ut_fault_response
= pmbus_receive8(pmdev
);
1401 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
1402 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1403 pmdev
->pages
[index
].vin_ov_fault_limit
= pmbus_receive16(pmdev
);
1409 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
1410 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1411 pmdev
->pages
[index
].vin_ov_fault_response
= pmbus_receive8(pmdev
);
1417 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
1418 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1419 pmdev
->pages
[index
].vin_ov_warn_limit
= pmbus_receive16(pmdev
);
1425 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
1426 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1427 pmdev
->pages
[index
].vin_uv_warn_limit
= pmbus_receive16(pmdev
);
1433 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
1434 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1435 pmdev
->pages
[index
].vin_uv_fault_limit
= pmbus_receive16(pmdev
);
1441 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
1442 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1443 pmdev
->pages
[index
].vin_uv_fault_response
= pmbus_receive8(pmdev
);
1449 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
1450 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1451 pmdev
->pages
[index
].iin_oc_fault_limit
= pmbus_receive16(pmdev
);
1457 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
1458 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1459 pmdev
->pages
[index
].iin_oc_fault_response
= pmbus_receive8(pmdev
);
1465 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
1466 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1467 pmdev
->pages
[index
].iin_oc_warn_limit
= pmbus_receive16(pmdev
);
1473 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
1474 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1475 pmdev
->pages
[index
].pout_op_fault_limit
= pmbus_receive16(pmdev
);
1481 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
1482 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1483 pmdev
->pages
[index
].pout_op_fault_response
= pmbus_receive8(pmdev
);
1489 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
1490 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1491 pmdev
->pages
[index
].pout_op_warn_limit
= pmbus_receive16(pmdev
);
1497 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
1498 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
1499 pmdev
->pages
[index
].pin_op_warn_limit
= pmbus_receive16(pmdev
);
1505 case PMBUS_STATUS_BYTE
: /* R/W byte */
1506 pmdev
->pages
[index
].status_word
= pmbus_receive8(pmdev
);
1509 case PMBUS_STATUS_WORD
: /* R/W word */
1510 pmdev
->pages
[index
].status_word
= pmbus_receive16(pmdev
);
1513 case PMBUS_STATUS_VOUT
: /* R/W byte */
1514 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1515 pmdev
->pages
[index
].status_vout
= pmbus_receive8(pmdev
);
1521 case PMBUS_STATUS_IOUT
: /* R/W byte */
1522 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1523 pmdev
->pages
[index
].status_iout
= pmbus_receive8(pmdev
);
1529 case PMBUS_STATUS_INPUT
: /* R/W byte */
1530 pmdev
->pages
[index
].status_input
= pmbus_receive8(pmdev
);
1533 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
1534 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1535 pmdev
->pages
[index
].status_temperature
= pmbus_receive8(pmdev
);
1541 case PMBUS_STATUS_CML
: /* R/W byte */
1542 pmdev
->pages
[index
].status_cml
= pmbus_receive8(pmdev
);
1545 case PMBUS_STATUS_OTHER
: /* R/W byte */
1546 pmdev
->pages
[index
].status_other
= pmbus_receive8(pmdev
);
1549 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
1550 pmdev
->pages
[index
].status_mfr_specific
= pmbus_receive8(pmdev
);
1553 case PMBUS_PAGE_PLUS_READ
: /* Block Read-only */
1554 case PMBUS_CAPABILITY
: /* Read-Only byte */
1555 case PMBUS_COEFFICIENTS
: /* Read-only block 5 bytes */
1556 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
1557 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
1558 case PMBUS_READ_VIN
: /* Read-Only word */
1559 case PMBUS_READ_IIN
: /* Read-Only word */
1560 case PMBUS_READ_VCAP
: /* Read-Only word */
1561 case PMBUS_READ_VOUT
: /* Read-Only word */
1562 case PMBUS_READ_IOUT
: /* Read-Only word */
1563 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
1564 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
1565 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
1566 case PMBUS_READ_FAN_SPEED_1
: /* Read-Only word */
1567 case PMBUS_READ_FAN_SPEED_2
: /* Read-Only word */
1568 case PMBUS_READ_FAN_SPEED_3
: /* Read-Only word */
1569 case PMBUS_READ_FAN_SPEED_4
: /* Read-Only word */
1570 case PMBUS_READ_DUTY_CYCLE
: /* Read-Only word */
1571 case PMBUS_READ_FREQUENCY
: /* Read-Only word */
1572 case PMBUS_READ_POUT
: /* Read-Only word */
1573 case PMBUS_READ_PIN
: /* Read-Only word */
1574 case PMBUS_REVISION
: /* Read-Only byte */
1575 case PMBUS_APP_PROFILE_SUPPORT
: /* Read-Only block-read */
1576 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
1577 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
1578 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
1579 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
1580 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
1581 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
1582 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
1583 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
1584 case PMBUS_MFR_TAMBIENT_MAX
: /* Read-Only word */
1585 case PMBUS_MFR_TAMBIENT_MIN
: /* Read-Only word */
1586 case PMBUS_MFR_EFFICIENCY_LL
: /* Read-Only block 14 bytes */
1587 case PMBUS_MFR_EFFICIENCY_HL
: /* Read-Only block 14 bytes */
1588 case PMBUS_MFR_PIN_ACCURACY
: /* Read-Only byte */
1589 case PMBUS_IC_DEVICE_ID
: /* Read-Only block-read */
1590 case PMBUS_IC_DEVICE_REV
: /* Read-Only block-read */
1591 qemu_log_mask(LOG_GUEST_ERROR
,
1592 "%s: writing to read-only register 0x%02x\n",
1593 __func__
, pmdev
->code
);
1597 /* Unimplimented registers get passed to the device */
1599 if (pmdc
->write_data
) {
1600 ret
= pmdc
->write_data(pmdev
, buf
, len
);
1604 pmbus_check_limits(pmdev
);
1605 pmdev
->in_buf_len
= 0;
1609 int pmbus_page_config(PMBusDevice
*pmdev
, uint8_t index
, uint64_t flags
)
1611 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1612 pmbus_pages_alloc(pmdev
);
1615 /* The 0xFF page is special for commands applying to all pages */
1616 if (index
== PB_ALL_PAGES
) {
1617 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1618 pmdev
->pages
[i
].page_flags
= flags
;
1623 if (index
> pmdev
->num_pages
- 1) {
1624 qemu_log_mask(LOG_GUEST_ERROR
,
1625 "%s: index %u is out of range\n",
1630 pmdev
->pages
[index
].page_flags
= flags
;
1635 /* TODO: include pmbus page info in vmstate */
1636 const VMStateDescription vmstate_pmbus_device
= {
1637 .name
= TYPE_PMBUS_DEVICE
,
1639 .minimum_version_id
= 0,
1640 .fields
= (VMStateField
[]) {
1641 VMSTATE_SMBUS_DEVICE(smb
, PMBusDevice
),
1642 VMSTATE_UINT8(num_pages
, PMBusDevice
),
1643 VMSTATE_UINT8(code
, PMBusDevice
),
1644 VMSTATE_UINT8(page
, PMBusDevice
),
1645 VMSTATE_UINT8(capability
, PMBusDevice
),
1646 VMSTATE_END_OF_LIST()
1650 static void pmbus_device_finalize(Object
*obj
)
1652 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
1653 g_free(pmdev
->pages
);
1656 static void pmbus_device_class_init(ObjectClass
*klass
, void *data
)
1658 SMBusDeviceClass
*k
= SMBUS_DEVICE_CLASS(klass
);
1660 k
->quick_cmd
= pmbus_quick_cmd
;
1661 k
->write_data
= pmbus_write_data
;
1662 k
->receive_byte
= pmbus_receive_byte
;
1665 static const TypeInfo pmbus_device_type_info
= {
1666 .name
= TYPE_PMBUS_DEVICE
,
1667 .parent
= TYPE_SMBUS_DEVICE
,
1668 .instance_size
= sizeof(PMBusDevice
),
1669 .instance_finalize
= pmbus_device_finalize
,
1671 .class_size
= sizeof(PMBusDeviceClass
),
1672 .class_init
= pmbus_device_class_init
,
1675 static void pmbus_device_register_types(void)
1677 type_register_static(&pmbus_device_type_info
);
1680 type_init(pmbus_device_register_types
)