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
)
98 qemu_log_mask(LOG_GUEST_ERROR
,
99 "%s: %s: uninitialised read from 0x%02x\n",
100 __func__
, DEVICE(pmdev
)->canonical_path
, pmdev
->code
);
104 size_t len
= strlen(data
);
106 g_assert(len
+ pmdev
->out_buf_len
< SMBUS_DATA_MAX_LEN
);
107 pmdev
->out_buf
[len
+ pmdev
->out_buf_len
] = len
;
109 for (int i
= len
- 1; i
>= 0; i
--) {
110 pmdev
->out_buf
[i
+ pmdev
->out_buf_len
] = data
[len
- 1 - i
];
112 pmdev
->out_buf_len
+= len
+ 1;
116 static uint64_t pmbus_receive_uint(PMBusDevice
*pmdev
)
120 /* Exclude command code from return value */
124 for (int i
= pmdev
->in_buf_len
- 1; i
>= 0; i
--) {
125 ret
= ret
<< 8 | pmdev
->in_buf
[i
];
130 uint8_t pmbus_receive8(PMBusDevice
*pmdev
)
132 if (pmdev
->in_buf_len
- 1 != 1) {
133 qemu_log_mask(LOG_GUEST_ERROR
,
134 "%s: length mismatch. Expected 1 byte, got %d bytes\n",
135 __func__
, pmdev
->in_buf_len
- 1);
137 return pmbus_receive_uint(pmdev
);
140 uint16_t pmbus_receive16(PMBusDevice
*pmdev
)
142 if (pmdev
->in_buf_len
- 1 != 2) {
143 qemu_log_mask(LOG_GUEST_ERROR
,
144 "%s: length mismatch. Expected 2 bytes, got %d bytes\n",
145 __func__
, pmdev
->in_buf_len
- 1);
147 return pmbus_receive_uint(pmdev
);
150 uint32_t pmbus_receive32(PMBusDevice
*pmdev
)
152 if (pmdev
->in_buf_len
- 1 != 4) {
153 qemu_log_mask(LOG_GUEST_ERROR
,
154 "%s: length mismatch. Expected 4 bytes, got %d bytes\n",
155 __func__
, pmdev
->in_buf_len
- 1);
157 return pmbus_receive_uint(pmdev
);
160 uint64_t pmbus_receive64(PMBusDevice
*pmdev
)
162 if (pmdev
->in_buf_len
- 1 != 8) {
163 qemu_log_mask(LOG_GUEST_ERROR
,
164 "%s: length mismatch. Expected 8 bytes, got %d bytes\n",
165 __func__
, pmdev
->in_buf_len
- 1);
167 return pmbus_receive_uint(pmdev
);
170 static uint8_t pmbus_out_buf_pop(PMBusDevice
*pmdev
)
172 if (pmdev
->out_buf_len
== 0) {
173 qemu_log_mask(LOG_GUEST_ERROR
,
174 "%s: tried to read from empty buffer",
176 return PMBUS_ERR_BYTE
;
178 uint8_t data
= pmdev
->out_buf
[pmdev
->out_buf_len
- 1];
179 pmdev
->out_buf_len
--;
183 static void pmbus_quick_cmd(SMBusDevice
*smd
, uint8_t read
)
185 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
186 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
188 if (pmdc
->quick_cmd
) {
189 pmdc
->quick_cmd(pmdev
, read
);
193 static void pmbus_pages_alloc(PMBusDevice
*pmdev
)
195 /* some PMBus devices don't use the PAGE command, so they get 1 page */
196 PMBusDeviceClass
*k
= PMBUS_DEVICE_GET_CLASS(pmdev
);
197 if (k
->device_num_pages
== 0) {
198 k
->device_num_pages
= 1;
200 pmdev
->num_pages
= k
->device_num_pages
;
201 pmdev
->pages
= g_new0(PMBusPage
, k
->device_num_pages
);
204 void pmbus_check_limits(PMBusDevice
*pmdev
)
206 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
207 if ((pmdev
->pages
[i
].operation
& PB_OP_ON
) == 0) {
208 continue; /* don't check powered off devices */
211 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_fault_limit
) {
212 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
213 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_FAULT
;
216 if (pmdev
->pages
[i
].read_vout
> pmdev
->pages
[i
].vout_ov_warn_limit
) {
217 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
218 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_OV_WARN
;
221 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_warn_limit
) {
222 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
223 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_WARN
;
226 if (pmdev
->pages
[i
].read_vout
< pmdev
->pages
[i
].vout_uv_fault_limit
) {
227 pmdev
->pages
[i
].status_word
|= PB_STATUS_VOUT
;
228 pmdev
->pages
[i
].status_vout
|= PB_STATUS_VOUT_UV_FAULT
;
231 if (pmdev
->pages
[i
].read_vin
> pmdev
->pages
[i
].vin_ov_warn_limit
) {
232 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
233 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_OV_WARN
;
236 if (pmdev
->pages
[i
].read_vin
< pmdev
->pages
[i
].vin_uv_warn_limit
) {
237 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
238 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_VIN_UV_WARN
;
241 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_warn_limit
) {
242 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
243 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_WARN
;
246 if (pmdev
->pages
[i
].read_iout
> pmdev
->pages
[i
].iout_oc_fault_limit
) {
247 pmdev
->pages
[i
].status_word
|= PB_STATUS_IOUT_POUT
;
248 pmdev
->pages
[i
].status_iout
|= PB_STATUS_IOUT_OC_FAULT
;
251 if (pmdev
->pages
[i
].read_pin
> pmdev
->pages
[i
].pin_op_warn_limit
) {
252 pmdev
->pages
[i
].status_word
|= PB_STATUS_INPUT
;
253 pmdev
->pages
[i
].status_input
|= PB_STATUS_INPUT_PIN_OP_WARN
;
256 if (pmdev
->pages
[i
].read_temperature_1
257 > pmdev
->pages
[i
].ot_fault_limit
) {
258 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
259 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_FAULT
;
262 if (pmdev
->pages
[i
].read_temperature_1
263 > pmdev
->pages
[i
].ot_warn_limit
) {
264 pmdev
->pages
[i
].status_word
|= PB_STATUS_TEMPERATURE
;
265 pmdev
->pages
[i
].status_temperature
|= PB_STATUS_OT_WARN
;
270 void pmbus_idle(PMBusDevice
*pmdev
)
272 pmdev
->code
= PMBUS_IDLE_STATE
;
275 /* assert the status_cml error upon receipt of malformed command */
276 static void pmbus_cml_error(PMBusDevice
*pmdev
)
278 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
279 pmdev
->pages
[i
].status_word
|= PMBUS_STATUS_CML
;
280 pmdev
->pages
[i
].status_cml
|= PB_CML_FAULT_INVALID_CMD
;
284 static uint8_t pmbus_receive_byte(SMBusDevice
*smd
)
286 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
287 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
288 uint8_t ret
= PMBUS_ERR_BYTE
;
291 if (pmdev
->out_buf_len
!= 0) {
292 ret
= pmbus_out_buf_pop(pmdev
);
297 * Reading from all pages will return the value from page 0,
298 * means that all subsequent commands are to be applied to all output.
300 if (pmdev
->page
== PB_ALL_PAGES
) {
302 } else if (pmdev
->page
> pmdev
->num_pages
- 1) {
303 qemu_log_mask(LOG_GUEST_ERROR
,
304 "%s: page %d is out of range\n",
305 __func__
, pmdev
->page
);
306 pmbus_cml_error(pmdev
);
307 return PMBUS_ERR_BYTE
;
312 switch (pmdev
->code
) {
314 pmbus_send8(pmdev
, pmdev
->page
);
317 case PMBUS_OPERATION
: /* R/W byte */
318 pmbus_send8(pmdev
, pmdev
->pages
[index
].operation
);
321 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
322 pmbus_send8(pmdev
, pmdev
->pages
[index
].on_off_config
);
325 case PMBUS_PHASE
: /* R/W byte */
326 pmbus_send8(pmdev
, pmdev
->pages
[index
].phase
);
329 case PMBUS_WRITE_PROTECT
: /* R/W byte */
330 pmbus_send8(pmdev
, pmdev
->pages
[index
].write_protect
);
333 case PMBUS_CAPABILITY
:
334 pmbus_send8(pmdev
, pmdev
->capability
);
335 if (pmdev
->capability
& BIT(7)) {
336 qemu_log_mask(LOG_UNIMP
,
337 "%s: PEC is enabled but not yet supported.\n",
342 case PMBUS_VOUT_MODE
: /* R/W byte */
343 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
344 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_mode
);
350 case PMBUS_VOUT_COMMAND
: /* R/W word */
351 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
352 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_command
);
358 case PMBUS_VOUT_TRIM
: /* R/W word */
359 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
360 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_trim
);
366 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
367 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
368 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_cal_offset
);
374 case PMBUS_VOUT_MAX
: /* R/W word */
375 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
376 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_max
);
382 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
383 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
384 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_high
);
390 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
391 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
392 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_margin_low
);
398 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
399 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
400 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_transition_rate
);
406 case PMBUS_VOUT_DROOP
: /* R/W word */
407 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
408 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_droop
);
414 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
415 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
416 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_loop
);
422 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
423 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
424 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_scale_monitor
);
430 case PMBUS_VOUT_MIN
: /* R/W word */
431 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
432 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_min
);
438 /* TODO: implement coefficients support */
440 case PMBUS_POUT_MAX
: /* R/W word */
441 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
442 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_max
);
448 case PMBUS_VIN_ON
: /* R/W word */
449 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
450 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_on
);
456 case PMBUS_VIN_OFF
: /* R/W word */
457 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
458 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_off
);
464 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
465 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
466 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_cal_gain
);
472 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
473 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
474 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_fault_limit
);
480 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
481 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
482 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_ov_fault_response
);
488 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
489 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
490 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_ov_warn_limit
);
496 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
497 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
498 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_warn_limit
);
504 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
505 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
506 pmbus_send16(pmdev
, pmdev
->pages
[index
].vout_uv_fault_limit
);
512 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
513 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
514 pmbus_send8(pmdev
, pmdev
->pages
[index
].vout_uv_fault_response
);
520 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
521 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
522 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_fault_limit
);
528 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
529 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
530 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_fault_response
);
536 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
537 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
538 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_limit
);
544 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
545 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
546 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_oc_lv_fault_response
);
552 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
553 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
554 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_oc_warn_limit
);
560 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
561 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
562 pmbus_send16(pmdev
, pmdev
->pages
[index
].iout_uc_fault_limit
);
568 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
569 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
570 pmbus_send8(pmdev
, pmdev
->pages
[index
].iout_uc_fault_response
);
576 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
577 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
578 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_fault_limit
);
584 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
585 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
586 pmbus_send8(pmdev
, pmdev
->pages
[index
].ot_fault_response
);
592 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
593 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
594 pmbus_send16(pmdev
, pmdev
->pages
[index
].ot_warn_limit
);
600 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
601 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
602 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_warn_limit
);
608 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
609 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
610 pmbus_send16(pmdev
, pmdev
->pages
[index
].ut_fault_limit
);
616 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
617 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
618 pmbus_send8(pmdev
, pmdev
->pages
[index
].ut_fault_response
);
624 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
625 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
626 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_fault_limit
);
632 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
633 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
634 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_ov_fault_response
);
640 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
641 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
642 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_ov_warn_limit
);
648 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
649 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
650 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_warn_limit
);
656 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
657 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
658 pmbus_send16(pmdev
, pmdev
->pages
[index
].vin_uv_fault_limit
);
664 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
665 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
666 pmbus_send8(pmdev
, pmdev
->pages
[index
].vin_uv_fault_response
);
672 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
673 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
674 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_fault_limit
);
680 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
681 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
682 pmbus_send8(pmdev
, pmdev
->pages
[index
].iin_oc_fault_response
);
688 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
689 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
690 pmbus_send16(pmdev
, pmdev
->pages
[index
].iin_oc_warn_limit
);
696 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
697 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
698 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_fault_limit
);
704 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
705 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
706 pmbus_send8(pmdev
, pmdev
->pages
[index
].pout_op_fault_response
);
712 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
713 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
714 pmbus_send16(pmdev
, pmdev
->pages
[index
].pout_op_warn_limit
);
720 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
721 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
722 pmbus_send16(pmdev
, pmdev
->pages
[index
].pin_op_warn_limit
);
728 case PMBUS_STATUS_BYTE
: /* R/W byte */
729 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_word
& 0xFF);
732 case PMBUS_STATUS_WORD
: /* R/W word */
733 pmbus_send16(pmdev
, pmdev
->pages
[index
].status_word
);
736 case PMBUS_STATUS_VOUT
: /* R/W byte */
737 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
738 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_vout
);
744 case PMBUS_STATUS_IOUT
: /* R/W byte */
745 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
746 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_iout
);
752 case PMBUS_STATUS_INPUT
: /* R/W byte */
753 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
||
754 pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
||
755 pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
756 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_input
);
762 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
763 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
764 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_temperature
);
770 case PMBUS_STATUS_CML
: /* R/W byte */
771 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_cml
);
774 case PMBUS_STATUS_OTHER
: /* R/W byte */
775 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_other
);
778 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
779 pmbus_send8(pmdev
, pmdev
->pages
[index
].status_mfr_specific
);
782 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
783 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EIN
) {
784 pmbus_send(pmdev
, pmdev
->pages
[index
].read_ein
, 5);
790 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
791 if (pmdev
->pages
[index
].page_flags
& PB_HAS_EOUT
) {
792 pmbus_send(pmdev
, pmdev
->pages
[index
].read_eout
, 5);
798 case PMBUS_READ_VIN
: /* Read-Only word */
799 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
800 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vin
);
806 case PMBUS_READ_IIN
: /* Read-Only word */
807 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
808 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iin
);
814 case PMBUS_READ_VOUT
: /* Read-Only word */
815 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
816 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_vout
);
822 case PMBUS_READ_IOUT
: /* Read-Only word */
823 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
824 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_iout
);
830 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
831 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
832 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_1
);
838 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
839 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP2
) {
840 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_2
);
846 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
847 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP3
) {
848 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_temperature_3
);
854 case PMBUS_READ_POUT
: /* Read-Only word */
855 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT
) {
856 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pout
);
862 case PMBUS_READ_PIN
: /* Read-Only word */
863 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
864 pmbus_send16(pmdev
, pmdev
->pages
[index
].read_pin
);
870 case PMBUS_REVISION
: /* Read-Only byte */
871 pmbus_send8(pmdev
, pmdev
->pages
[index
].revision
);
874 case PMBUS_MFR_ID
: /* R/W block */
875 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
876 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_id
);
882 case PMBUS_MFR_MODEL
: /* R/W block */
883 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
884 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_model
);
890 case PMBUS_MFR_REVISION
: /* R/W block */
891 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
892 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_revision
);
898 case PMBUS_MFR_LOCATION
: /* R/W block */
899 if (pmdev
->pages
[index
].page_flags
& PB_HAS_MFR_INFO
) {
900 pmbus_send_string(pmdev
, pmdev
->pages
[index
].mfr_location
);
906 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
907 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
908 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_min
);
914 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
915 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN_RATING
) {
916 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vin_max
);
922 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
923 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN_RATING
) {
924 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iin_max
);
930 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
931 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN_RATING
) {
932 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pin_max
);
938 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
939 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
940 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_min
);
946 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
947 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
948 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_vout_max
);
954 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
955 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_RATING
) {
956 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_iout_max
);
962 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
963 if (pmdev
->pages
[index
].page_flags
& PB_HAS_POUT_RATING
) {
964 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_pout_max
);
970 case PMBUS_MFR_MAX_TEMP_1
: /* R/W word */
971 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
972 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_1
);
978 case PMBUS_MFR_MAX_TEMP_2
: /* R/W word */
979 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
980 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_2
);
986 case PMBUS_MFR_MAX_TEMP_3
: /* R/W word */
987 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMP_RATING
) {
988 pmbus_send16(pmdev
, pmdev
->pages
[index
].mfr_max_temp_3
);
994 case PMBUS_IDLE_STATE
:
995 pmbus_send8(pmdev
, PMBUS_ERR_BYTE
);
998 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
999 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
1000 case PMBUS_STORE_DEFAULT_ALL
: /* Send Byte */
1001 case PMBUS_RESTORE_DEFAULT_ALL
: /* Send Byte */
1002 case PMBUS_STORE_DEFAULT_CODE
: /* Write-only Byte */
1003 case PMBUS_RESTORE_DEFAULT_CODE
: /* Write-only Byte */
1004 case PMBUS_STORE_USER_ALL
: /* Send Byte */
1005 case PMBUS_RESTORE_USER_ALL
: /* Send Byte */
1006 case PMBUS_STORE_USER_CODE
: /* Write-only Byte */
1007 case PMBUS_RESTORE_USER_CODE
: /* Write-only Byte */
1008 case PMBUS_QUERY
: /* Write-Only */
1009 qemu_log_mask(LOG_GUEST_ERROR
,
1010 "%s: reading from write only register 0x%02x\n",
1011 __func__
, pmdev
->code
);
1016 /* Pass through read request if not handled */
1017 if (pmdc
->receive_byte
) {
1018 ret
= pmdc
->receive_byte(pmdev
);
1023 if (pmdev
->out_buf_len
!= 0) {
1024 ret
= pmbus_out_buf_pop(pmdev
);
1032 * PMBus clear faults command applies to all status registers, existing faults
1033 * should separately get re-asserted.
1035 static void pmbus_clear_faults(PMBusDevice
*pmdev
)
1037 for (uint8_t i
= 0; i
< pmdev
->num_pages
; i
++) {
1038 pmdev
->pages
[i
].status_word
= 0;
1039 pmdev
->pages
[i
].status_vout
= 0;
1040 pmdev
->pages
[i
].status_iout
= 0;
1041 pmdev
->pages
[i
].status_input
= 0;
1042 pmdev
->pages
[i
].status_temperature
= 0;
1043 pmdev
->pages
[i
].status_cml
= 0;
1044 pmdev
->pages
[i
].status_other
= 0;
1045 pmdev
->pages
[i
].status_mfr_specific
= 0;
1046 pmdev
->pages
[i
].status_fans_1_2
= 0;
1047 pmdev
->pages
[i
].status_fans_3_4
= 0;
1053 * PMBus operation is used to turn On and Off PSUs
1054 * Therefore, default value for the Operation should be PB_OP_ON or 0x80
1056 static void pmbus_operation(PMBusDevice
*pmdev
)
1058 uint8_t index
= pmdev
->page
;
1059 if ((pmdev
->pages
[index
].operation
& PB_OP_ON
) == 0) {
1060 pmdev
->pages
[index
].read_vout
= 0;
1061 pmdev
->pages
[index
].read_iout
= 0;
1062 pmdev
->pages
[index
].read_pout
= 0;
1066 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_HIGH
)) {
1067 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_high
;
1070 if (pmdev
->pages
[index
].operation
& (PB_OP_ON
| PB_OP_MARGIN_LOW
)) {
1071 pmdev
->pages
[index
].read_vout
= pmdev
->pages
[index
].vout_margin_low
;
1073 pmbus_check_limits(pmdev
);
1076 static int pmbus_write_data(SMBusDevice
*smd
, uint8_t *buf
, uint8_t len
)
1078 PMBusDevice
*pmdev
= PMBUS_DEVICE(smd
);
1079 PMBusDeviceClass
*pmdc
= PMBUS_DEVICE_GET_CLASS(pmdev
);
1084 qemu_log_mask(LOG_GUEST_ERROR
, "%s: writing empty data\n", __func__
);
1085 return PMBUS_ERR_BYTE
;
1088 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1089 pmbus_pages_alloc(pmdev
);
1092 pmdev
->in_buf_len
= len
;
1093 pmdev
->in_buf
= buf
;
1095 pmdev
->code
= buf
[0]; /* PMBus command code */
1096 if (len
== 1) { /* Single length writes are command codes only */
1100 if (pmdev
->code
== PMBUS_PAGE
) {
1101 pmdev
->page
= pmbus_receive8(pmdev
);
1105 /* loop through all the pages when 0xFF is received */
1106 if (pmdev
->page
== PB_ALL_PAGES
) {
1107 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1109 pmbus_write_data(smd
, buf
, len
);
1111 pmdev
->page
= PB_ALL_PAGES
;
1115 if (pmdev
->page
> pmdev
->num_pages
- 1) {
1116 qemu_log_mask(LOG_GUEST_ERROR
,
1117 "%s: page %u is out of range\n",
1118 __func__
, pmdev
->page
);
1119 pmdev
->page
= 0; /* undefined behaviour - reset to page 0 */
1120 pmbus_cml_error(pmdev
);
1121 return PMBUS_ERR_BYTE
;
1124 index
= pmdev
->page
;
1126 switch (pmdev
->code
) {
1127 case PMBUS_OPERATION
: /* R/W byte */
1128 pmdev
->pages
[index
].operation
= pmbus_receive8(pmdev
);
1129 pmbus_operation(pmdev
);
1132 case PMBUS_ON_OFF_CONFIG
: /* R/W byte */
1133 pmdev
->pages
[index
].on_off_config
= pmbus_receive8(pmdev
);
1136 case PMBUS_CLEAR_FAULTS
: /* Send Byte */
1137 pmbus_clear_faults(pmdev
);
1140 case PMBUS_PHASE
: /* R/W byte */
1141 pmdev
->pages
[index
].phase
= pmbus_receive8(pmdev
);
1144 case PMBUS_PAGE_PLUS_WRITE
: /* Block Write-only */
1145 case PMBUS_WRITE_PROTECT
: /* R/W byte */
1146 pmdev
->pages
[index
].write_protect
= pmbus_receive8(pmdev
);
1149 case PMBUS_VOUT_MODE
: /* R/W byte */
1150 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MODE
) {
1151 pmdev
->pages
[index
].vout_mode
= pmbus_receive8(pmdev
);
1157 case PMBUS_VOUT_COMMAND
: /* R/W word */
1158 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1159 pmdev
->pages
[index
].vout_command
= pmbus_receive16(pmdev
);
1165 case PMBUS_VOUT_TRIM
: /* R/W word */
1166 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1167 pmdev
->pages
[index
].vout_trim
= pmbus_receive16(pmdev
);
1173 case PMBUS_VOUT_CAL_OFFSET
: /* R/W word */
1174 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1175 pmdev
->pages
[index
].vout_cal_offset
= pmbus_receive16(pmdev
);
1181 case PMBUS_VOUT_MAX
: /* R/W word */
1182 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1183 pmdev
->pages
[index
].vout_max
= pmbus_receive16(pmdev
);
1189 case PMBUS_VOUT_MARGIN_HIGH
: /* R/W word */
1190 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1191 pmdev
->pages
[index
].vout_margin_high
= pmbus_receive16(pmdev
);
1197 case PMBUS_VOUT_MARGIN_LOW
: /* R/W word */
1198 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_MARGIN
) {
1199 pmdev
->pages
[index
].vout_margin_low
= pmbus_receive16(pmdev
);
1205 case PMBUS_VOUT_TRANSITION_RATE
: /* R/W word */
1206 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1207 pmdev
->pages
[index
].vout_transition_rate
= pmbus_receive16(pmdev
);
1213 case PMBUS_VOUT_DROOP
: /* R/W word */
1214 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1215 pmdev
->pages
[index
].vout_droop
= pmbus_receive16(pmdev
);
1221 case PMBUS_VOUT_SCALE_LOOP
: /* R/W word */
1222 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1223 pmdev
->pages
[index
].vout_scale_loop
= pmbus_receive16(pmdev
);
1229 case PMBUS_VOUT_SCALE_MONITOR
: /* R/W word */
1230 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1231 pmdev
->pages
[index
].vout_scale_monitor
= pmbus_receive16(pmdev
);
1237 case PMBUS_VOUT_MIN
: /* R/W word */
1238 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT_RATING
) {
1239 pmdev
->pages
[index
].vout_min
= pmbus_receive16(pmdev
);
1245 case PMBUS_POUT_MAX
: /* R/W word */
1246 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1247 pmdev
->pages
[index
].pout_max
= pmbus_receive16(pmdev
);
1253 case PMBUS_VIN_ON
: /* R/W word */
1254 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1255 pmdev
->pages
[index
].vin_on
= pmbus_receive16(pmdev
);
1261 case PMBUS_VIN_OFF
: /* R/W word */
1262 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1263 pmdev
->pages
[index
].vin_off
= pmbus_receive16(pmdev
);
1269 case PMBUS_IOUT_CAL_GAIN
: /* R/W word */
1270 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT_GAIN
) {
1271 pmdev
->pages
[index
].iout_cal_gain
= pmbus_receive16(pmdev
);
1277 case PMBUS_VOUT_OV_FAULT_LIMIT
: /* R/W word */
1278 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1279 pmdev
->pages
[index
].vout_ov_fault_limit
= pmbus_receive16(pmdev
);
1285 case PMBUS_VOUT_OV_FAULT_RESPONSE
: /* R/W byte */
1286 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1287 pmdev
->pages
[index
].vout_ov_fault_response
= pmbus_receive8(pmdev
);
1293 case PMBUS_VOUT_OV_WARN_LIMIT
: /* R/W word */
1294 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1295 pmdev
->pages
[index
].vout_ov_warn_limit
= pmbus_receive16(pmdev
);
1301 case PMBUS_VOUT_UV_WARN_LIMIT
: /* R/W word */
1302 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1303 pmdev
->pages
[index
].vout_uv_warn_limit
= pmbus_receive16(pmdev
);
1309 case PMBUS_VOUT_UV_FAULT_LIMIT
: /* R/W word */
1310 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1311 pmdev
->pages
[index
].vout_uv_fault_limit
= pmbus_receive16(pmdev
);
1317 case PMBUS_VOUT_UV_FAULT_RESPONSE
: /* R/W byte */
1318 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1319 pmdev
->pages
[index
].vout_uv_fault_response
= pmbus_receive8(pmdev
);
1325 case PMBUS_IOUT_OC_FAULT_LIMIT
: /* R/W word */
1326 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1327 pmdev
->pages
[index
].iout_oc_fault_limit
= pmbus_receive16(pmdev
);
1333 case PMBUS_IOUT_OC_FAULT_RESPONSE
: /* R/W byte */
1334 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1335 pmdev
->pages
[index
].iout_oc_fault_response
= pmbus_receive8(pmdev
);
1341 case PMBUS_IOUT_OC_LV_FAULT_LIMIT
: /* R/W word */
1342 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1343 pmdev
->pages
[index
].iout_oc_lv_fault_limit
= pmbus_receive16(pmdev
);
1349 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE
: /* R/W byte */
1350 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1351 pmdev
->pages
[index
].iout_oc_lv_fault_response
1352 = pmbus_receive8(pmdev
);
1358 case PMBUS_IOUT_OC_WARN_LIMIT
: /* R/W word */
1359 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1360 pmdev
->pages
[index
].iout_oc_warn_limit
= pmbus_receive16(pmdev
);
1366 case PMBUS_IOUT_UC_FAULT_LIMIT
: /* R/W word */
1367 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1368 pmdev
->pages
[index
].iout_uc_fault_limit
= pmbus_receive16(pmdev
);
1374 case PMBUS_IOUT_UC_FAULT_RESPONSE
: /* R/W byte */
1375 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1376 pmdev
->pages
[index
].iout_uc_fault_response
= pmbus_receive8(pmdev
);
1382 case PMBUS_OT_FAULT_LIMIT
: /* R/W word */
1383 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1384 pmdev
->pages
[index
].ot_fault_limit
= pmbus_receive16(pmdev
);
1390 case PMBUS_OT_FAULT_RESPONSE
: /* R/W byte */
1391 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1392 pmdev
->pages
[index
].ot_fault_response
= pmbus_receive8(pmdev
);
1398 case PMBUS_OT_WARN_LIMIT
: /* R/W word */
1399 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1400 pmdev
->pages
[index
].ot_warn_limit
= pmbus_receive16(pmdev
);
1406 case PMBUS_UT_WARN_LIMIT
: /* R/W word */
1407 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1408 pmdev
->pages
[index
].ut_warn_limit
= pmbus_receive16(pmdev
);
1414 case PMBUS_UT_FAULT_LIMIT
: /* R/W word */
1415 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1416 pmdev
->pages
[index
].ut_fault_limit
= pmbus_receive16(pmdev
);
1422 case PMBUS_UT_FAULT_RESPONSE
: /* R/W byte */
1423 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1424 pmdev
->pages
[index
].ut_fault_response
= pmbus_receive8(pmdev
);
1430 case PMBUS_VIN_OV_FAULT_LIMIT
: /* R/W word */
1431 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1432 pmdev
->pages
[index
].vin_ov_fault_limit
= pmbus_receive16(pmdev
);
1438 case PMBUS_VIN_OV_FAULT_RESPONSE
: /* R/W byte */
1439 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1440 pmdev
->pages
[index
].vin_ov_fault_response
= pmbus_receive8(pmdev
);
1446 case PMBUS_VIN_OV_WARN_LIMIT
: /* R/W word */
1447 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1448 pmdev
->pages
[index
].vin_ov_warn_limit
= pmbus_receive16(pmdev
);
1454 case PMBUS_VIN_UV_WARN_LIMIT
: /* R/W word */
1455 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1456 pmdev
->pages
[index
].vin_uv_warn_limit
= pmbus_receive16(pmdev
);
1462 case PMBUS_VIN_UV_FAULT_LIMIT
: /* R/W word */
1463 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1464 pmdev
->pages
[index
].vin_uv_fault_limit
= pmbus_receive16(pmdev
);
1470 case PMBUS_VIN_UV_FAULT_RESPONSE
: /* R/W byte */
1471 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VIN
) {
1472 pmdev
->pages
[index
].vin_uv_fault_response
= pmbus_receive8(pmdev
);
1478 case PMBUS_IIN_OC_FAULT_LIMIT
: /* R/W word */
1479 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1480 pmdev
->pages
[index
].iin_oc_fault_limit
= pmbus_receive16(pmdev
);
1486 case PMBUS_IIN_OC_FAULT_RESPONSE
: /* R/W byte */
1487 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1488 pmdev
->pages
[index
].iin_oc_fault_response
= pmbus_receive8(pmdev
);
1494 case PMBUS_IIN_OC_WARN_LIMIT
: /* R/W word */
1495 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IIN
) {
1496 pmdev
->pages
[index
].iin_oc_warn_limit
= pmbus_receive16(pmdev
);
1502 case PMBUS_POUT_OP_FAULT_LIMIT
: /* R/W word */
1503 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1504 pmdev
->pages
[index
].pout_op_fault_limit
= pmbus_receive16(pmdev
);
1510 case PMBUS_POUT_OP_FAULT_RESPONSE
: /* R/W byte */
1511 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1512 pmdev
->pages
[index
].pout_op_fault_response
= pmbus_receive8(pmdev
);
1518 case PMBUS_POUT_OP_WARN_LIMIT
: /* R/W word */
1519 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1520 pmdev
->pages
[index
].pout_op_warn_limit
= pmbus_receive16(pmdev
);
1526 case PMBUS_PIN_OP_WARN_LIMIT
: /* R/W word */
1527 if (pmdev
->pages
[index
].page_flags
& PB_HAS_PIN
) {
1528 pmdev
->pages
[index
].pin_op_warn_limit
= pmbus_receive16(pmdev
);
1534 case PMBUS_STATUS_BYTE
: /* R/W byte */
1535 pmdev
->pages
[index
].status_word
= pmbus_receive8(pmdev
);
1538 case PMBUS_STATUS_WORD
: /* R/W word */
1539 pmdev
->pages
[index
].status_word
= pmbus_receive16(pmdev
);
1542 case PMBUS_STATUS_VOUT
: /* R/W byte */
1543 if (pmdev
->pages
[index
].page_flags
& PB_HAS_VOUT
) {
1544 pmdev
->pages
[index
].status_vout
= pmbus_receive8(pmdev
);
1550 case PMBUS_STATUS_IOUT
: /* R/W byte */
1551 if (pmdev
->pages
[index
].page_flags
& PB_HAS_IOUT
) {
1552 pmdev
->pages
[index
].status_iout
= pmbus_receive8(pmdev
);
1558 case PMBUS_STATUS_INPUT
: /* R/W byte */
1559 pmdev
->pages
[index
].status_input
= pmbus_receive8(pmdev
);
1562 case PMBUS_STATUS_TEMPERATURE
: /* R/W byte */
1563 if (pmdev
->pages
[index
].page_flags
& PB_HAS_TEMPERATURE
) {
1564 pmdev
->pages
[index
].status_temperature
= pmbus_receive8(pmdev
);
1570 case PMBUS_STATUS_CML
: /* R/W byte */
1571 pmdev
->pages
[index
].status_cml
= pmbus_receive8(pmdev
);
1574 case PMBUS_STATUS_OTHER
: /* R/W byte */
1575 pmdev
->pages
[index
].status_other
= pmbus_receive8(pmdev
);
1578 case PMBUS_STATUS_MFR_SPECIFIC
: /* R/W byte */
1579 pmdev
->pages
[index
].status_mfr_specific
= pmbus_receive8(pmdev
);
1582 case PMBUS_PAGE_PLUS_READ
: /* Block Read-only */
1583 case PMBUS_CAPABILITY
: /* Read-Only byte */
1584 case PMBUS_COEFFICIENTS
: /* Read-only block 5 bytes */
1585 case PMBUS_READ_EIN
: /* Read-Only block 5 bytes */
1586 case PMBUS_READ_EOUT
: /* Read-Only block 5 bytes */
1587 case PMBUS_READ_VIN
: /* Read-Only word */
1588 case PMBUS_READ_IIN
: /* Read-Only word */
1589 case PMBUS_READ_VCAP
: /* Read-Only word */
1590 case PMBUS_READ_VOUT
: /* Read-Only word */
1591 case PMBUS_READ_IOUT
: /* Read-Only word */
1592 case PMBUS_READ_TEMPERATURE_1
: /* Read-Only word */
1593 case PMBUS_READ_TEMPERATURE_2
: /* Read-Only word */
1594 case PMBUS_READ_TEMPERATURE_3
: /* Read-Only word */
1595 case PMBUS_READ_FAN_SPEED_1
: /* Read-Only word */
1596 case PMBUS_READ_FAN_SPEED_2
: /* Read-Only word */
1597 case PMBUS_READ_FAN_SPEED_3
: /* Read-Only word */
1598 case PMBUS_READ_FAN_SPEED_4
: /* Read-Only word */
1599 case PMBUS_READ_DUTY_CYCLE
: /* Read-Only word */
1600 case PMBUS_READ_FREQUENCY
: /* Read-Only word */
1601 case PMBUS_READ_POUT
: /* Read-Only word */
1602 case PMBUS_READ_PIN
: /* Read-Only word */
1603 case PMBUS_REVISION
: /* Read-Only byte */
1604 case PMBUS_APP_PROFILE_SUPPORT
: /* Read-Only block-read */
1605 case PMBUS_MFR_VIN_MIN
: /* Read-Only word */
1606 case PMBUS_MFR_VIN_MAX
: /* Read-Only word */
1607 case PMBUS_MFR_IIN_MAX
: /* Read-Only word */
1608 case PMBUS_MFR_PIN_MAX
: /* Read-Only word */
1609 case PMBUS_MFR_VOUT_MIN
: /* Read-Only word */
1610 case PMBUS_MFR_VOUT_MAX
: /* Read-Only word */
1611 case PMBUS_MFR_IOUT_MAX
: /* Read-Only word */
1612 case PMBUS_MFR_POUT_MAX
: /* Read-Only word */
1613 case PMBUS_MFR_TAMBIENT_MAX
: /* Read-Only word */
1614 case PMBUS_MFR_TAMBIENT_MIN
: /* Read-Only word */
1615 case PMBUS_MFR_EFFICIENCY_LL
: /* Read-Only block 14 bytes */
1616 case PMBUS_MFR_EFFICIENCY_HL
: /* Read-Only block 14 bytes */
1617 case PMBUS_MFR_PIN_ACCURACY
: /* Read-Only byte */
1618 case PMBUS_IC_DEVICE_ID
: /* Read-Only block-read */
1619 case PMBUS_IC_DEVICE_REV
: /* Read-Only block-read */
1620 qemu_log_mask(LOG_GUEST_ERROR
,
1621 "%s: writing to read-only register 0x%02x\n",
1622 __func__
, pmdev
->code
);
1626 /* Unimplimented registers get passed to the device */
1628 if (pmdc
->write_data
) {
1629 ret
= pmdc
->write_data(pmdev
, buf
, len
);
1633 pmbus_check_limits(pmdev
);
1634 pmdev
->in_buf_len
= 0;
1638 int pmbus_page_config(PMBusDevice
*pmdev
, uint8_t index
, uint64_t flags
)
1640 if (!pmdev
->pages
) { /* allocate memory for pages on first use */
1641 pmbus_pages_alloc(pmdev
);
1644 /* The 0xFF page is special for commands applying to all pages */
1645 if (index
== PB_ALL_PAGES
) {
1646 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
1647 pmdev
->pages
[i
].page_flags
= flags
;
1652 if (index
> pmdev
->num_pages
- 1) {
1653 qemu_log_mask(LOG_GUEST_ERROR
,
1654 "%s: index %u is out of range\n",
1659 pmdev
->pages
[index
].page_flags
= flags
;
1664 /* TODO: include pmbus page info in vmstate */
1665 const VMStateDescription vmstate_pmbus_device
= {
1666 .name
= TYPE_PMBUS_DEVICE
,
1668 .minimum_version_id
= 0,
1669 .fields
= (VMStateField
[]) {
1670 VMSTATE_SMBUS_DEVICE(smb
, PMBusDevice
),
1671 VMSTATE_UINT8(num_pages
, PMBusDevice
),
1672 VMSTATE_UINT8(code
, PMBusDevice
),
1673 VMSTATE_UINT8(page
, PMBusDevice
),
1674 VMSTATE_UINT8(capability
, PMBusDevice
),
1675 VMSTATE_END_OF_LIST()
1679 static void pmbus_device_finalize(Object
*obj
)
1681 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
1682 g_free(pmdev
->pages
);
1685 static void pmbus_device_class_init(ObjectClass
*klass
, void *data
)
1687 SMBusDeviceClass
*k
= SMBUS_DEVICE_CLASS(klass
);
1689 k
->quick_cmd
= pmbus_quick_cmd
;
1690 k
->write_data
= pmbus_write_data
;
1691 k
->receive_byte
= pmbus_receive_byte
;
1694 static const TypeInfo pmbus_device_type_info
= {
1695 .name
= TYPE_PMBUS_DEVICE
,
1696 .parent
= TYPE_SMBUS_DEVICE
,
1697 .instance_size
= sizeof(PMBusDevice
),
1698 .instance_finalize
= pmbus_device_finalize
,
1700 .class_size
= sizeof(PMBusDeviceClass
),
1701 .class_init
= pmbus_device_class_init
,
1704 static void pmbus_device_register_types(void)
1706 type_register_static(&pmbus_device_type_info
);
1709 type_init(pmbus_device_register_types
)