1*6f351a7aSTitus Rwantare /* 2*6f351a7aSTitus Rwantare * Analog Devices ADM1266 Cascadable Super Sequencer with Margin Control and 3*6f351a7aSTitus Rwantare * Fault Recording with PMBus 4*6f351a7aSTitus Rwantare * 5*6f351a7aSTitus Rwantare * https://www.analog.com/media/en/technical-documentation/data-sheets/adm1266.pdf 6*6f351a7aSTitus Rwantare * 7*6f351a7aSTitus Rwantare * Copyright 2023 Google LLC 8*6f351a7aSTitus Rwantare * 9*6f351a7aSTitus Rwantare * SPDX-License-Identifier: GPL-2.0-or-later 10*6f351a7aSTitus Rwantare */ 11*6f351a7aSTitus Rwantare 12*6f351a7aSTitus Rwantare #include "qemu/osdep.h" 13*6f351a7aSTitus Rwantare #include "hw/i2c/pmbus_device.h" 14*6f351a7aSTitus Rwantare #include "hw/irq.h" 15*6f351a7aSTitus Rwantare #include "migration/vmstate.h" 16*6f351a7aSTitus Rwantare #include "qapi/error.h" 17*6f351a7aSTitus Rwantare #include "qapi/visitor.h" 18*6f351a7aSTitus Rwantare #include "qemu/log.h" 19*6f351a7aSTitus Rwantare #include "qemu/module.h" 20*6f351a7aSTitus Rwantare 21*6f351a7aSTitus Rwantare #define TYPE_ADM1266 "adm1266" 22*6f351a7aSTitus Rwantare OBJECT_DECLARE_SIMPLE_TYPE(ADM1266State, ADM1266) 23*6f351a7aSTitus Rwantare 24*6f351a7aSTitus Rwantare #define ADM1266_BLACKBOX_CONFIG 0xD3 25*6f351a7aSTitus Rwantare #define ADM1266_PDIO_CONFIG 0xD4 26*6f351a7aSTitus Rwantare #define ADM1266_READ_STATE 0xD9 27*6f351a7aSTitus Rwantare #define ADM1266_READ_BLACKBOX 0xDE 28*6f351a7aSTitus Rwantare #define ADM1266_SET_RTC 0xDF 29*6f351a7aSTitus Rwantare #define ADM1266_GPIO_SYNC_CONFIGURATION 0xE1 30*6f351a7aSTitus Rwantare #define ADM1266_BLACKBOX_INFORMATION 0xE6 31*6f351a7aSTitus Rwantare #define ADM1266_PDIO_STATUS 0xE9 32*6f351a7aSTitus Rwantare #define ADM1266_GPIO_STATUS 0xEA 33*6f351a7aSTitus Rwantare 34*6f351a7aSTitus Rwantare /* Defaults */ 35*6f351a7aSTitus Rwantare #define ADM1266_OPERATION_DEFAULT 0x80 36*6f351a7aSTitus Rwantare #define ADM1266_CAPABILITY_DEFAULT 0xA0 37*6f351a7aSTitus Rwantare #define ADM1266_CAPABILITY_NO_PEC 0x20 38*6f351a7aSTitus Rwantare #define ADM1266_PMBUS_REVISION_DEFAULT 0x22 39*6f351a7aSTitus Rwantare #define ADM1266_MFR_ID_DEFAULT "ADI" 40*6f351a7aSTitus Rwantare #define ADM1266_MFR_ID_DEFAULT_LEN 32 41*6f351a7aSTitus Rwantare #define ADM1266_MFR_MODEL_DEFAULT "ADM1266-A1" 42*6f351a7aSTitus Rwantare #define ADM1266_MFR_MODEL_DEFAULT_LEN 32 43*6f351a7aSTitus Rwantare #define ADM1266_MFR_REVISION_DEFAULT "25" 44*6f351a7aSTitus Rwantare #define ADM1266_MFR_REVISION_DEFAULT_LEN 8 45*6f351a7aSTitus Rwantare 46*6f351a7aSTitus Rwantare #define ADM1266_NUM_PAGES 17 47*6f351a7aSTitus Rwantare /** 48*6f351a7aSTitus Rwantare * PAGE Index 49*6f351a7aSTitus Rwantare * Page 0 VH1. 50*6f351a7aSTitus Rwantare * Page 1 VH2. 51*6f351a7aSTitus Rwantare * Page 2 VH3. 52*6f351a7aSTitus Rwantare * Page 3 VH4. 53*6f351a7aSTitus Rwantare * Page 4 VP1. 54*6f351a7aSTitus Rwantare * Page 5 VP2. 55*6f351a7aSTitus Rwantare * Page 6 VP3. 56*6f351a7aSTitus Rwantare * Page 7 VP4. 57*6f351a7aSTitus Rwantare * Page 8 VP5. 58*6f351a7aSTitus Rwantare * Page 9 VP6. 59*6f351a7aSTitus Rwantare * Page 10 VP7. 60*6f351a7aSTitus Rwantare * Page 11 VP8. 61*6f351a7aSTitus Rwantare * Page 12 VP9. 62*6f351a7aSTitus Rwantare * Page 13 VP10. 63*6f351a7aSTitus Rwantare * Page 14 VP11. 64*6f351a7aSTitus Rwantare * Page 15 VP12. 65*6f351a7aSTitus Rwantare * Page 16 VP13. 66*6f351a7aSTitus Rwantare */ 67*6f351a7aSTitus Rwantare typedef struct ADM1266State { 68*6f351a7aSTitus Rwantare PMBusDevice parent; 69*6f351a7aSTitus Rwantare 70*6f351a7aSTitus Rwantare char mfr_id[32]; 71*6f351a7aSTitus Rwantare char mfr_model[32]; 72*6f351a7aSTitus Rwantare char mfr_rev[8]; 73*6f351a7aSTitus Rwantare } ADM1266State; 74*6f351a7aSTitus Rwantare 75*6f351a7aSTitus Rwantare static const uint8_t adm1266_ic_device_id[] = {0x03, 0x41, 0x12, 0x66}; 76*6f351a7aSTitus Rwantare static const uint8_t adm1266_ic_device_rev[] = {0x08, 0x01, 0x08, 0x07, 0x0, 77*6f351a7aSTitus Rwantare 0x0, 0x07, 0x41, 0x30}; 78*6f351a7aSTitus Rwantare 79*6f351a7aSTitus Rwantare static void adm1266_exit_reset(Object *obj) 80*6f351a7aSTitus Rwantare { 81*6f351a7aSTitus Rwantare ADM1266State *s = ADM1266(obj); 82*6f351a7aSTitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(obj); 83*6f351a7aSTitus Rwantare 84*6f351a7aSTitus Rwantare pmdev->page = 0; 85*6f351a7aSTitus Rwantare pmdev->capability = ADM1266_CAPABILITY_NO_PEC; 86*6f351a7aSTitus Rwantare 87*6f351a7aSTitus Rwantare for (int i = 0; i < ADM1266_NUM_PAGES; i++) { 88*6f351a7aSTitus Rwantare pmdev->pages[i].operation = ADM1266_OPERATION_DEFAULT; 89*6f351a7aSTitus Rwantare pmdev->pages[i].revision = ADM1266_PMBUS_REVISION_DEFAULT; 90*6f351a7aSTitus Rwantare pmdev->pages[i].vout_mode = 0; 91*6f351a7aSTitus Rwantare pmdev->pages[i].read_vout = pmbus_data2linear_mode(12, 0); 92*6f351a7aSTitus Rwantare pmdev->pages[i].vout_margin_high = pmbus_data2linear_mode(15, 0); 93*6f351a7aSTitus Rwantare pmdev->pages[i].vout_margin_low = pmbus_data2linear_mode(3, 0); 94*6f351a7aSTitus Rwantare pmdev->pages[i].vout_ov_fault_limit = pmbus_data2linear_mode(16, 0); 95*6f351a7aSTitus Rwantare pmdev->pages[i].revision = ADM1266_PMBUS_REVISION_DEFAULT; 96*6f351a7aSTitus Rwantare } 97*6f351a7aSTitus Rwantare 98*6f351a7aSTitus Rwantare strncpy(s->mfr_id, ADM1266_MFR_ID_DEFAULT, 4); 99*6f351a7aSTitus Rwantare strncpy(s->mfr_model, ADM1266_MFR_MODEL_DEFAULT, 11); 100*6f351a7aSTitus Rwantare strncpy(s->mfr_rev, ADM1266_MFR_REVISION_DEFAULT, 3); 101*6f351a7aSTitus Rwantare } 102*6f351a7aSTitus Rwantare 103*6f351a7aSTitus Rwantare static uint8_t adm1266_read_byte(PMBusDevice *pmdev) 104*6f351a7aSTitus Rwantare { 105*6f351a7aSTitus Rwantare ADM1266State *s = ADM1266(pmdev); 106*6f351a7aSTitus Rwantare 107*6f351a7aSTitus Rwantare switch (pmdev->code) { 108*6f351a7aSTitus Rwantare case PMBUS_MFR_ID: /* R/W block */ 109*6f351a7aSTitus Rwantare pmbus_send_string(pmdev, s->mfr_id); 110*6f351a7aSTitus Rwantare break; 111*6f351a7aSTitus Rwantare 112*6f351a7aSTitus Rwantare case PMBUS_MFR_MODEL: /* R/W block */ 113*6f351a7aSTitus Rwantare pmbus_send_string(pmdev, s->mfr_model); 114*6f351a7aSTitus Rwantare break; 115*6f351a7aSTitus Rwantare 116*6f351a7aSTitus Rwantare case PMBUS_MFR_REVISION: /* R/W block */ 117*6f351a7aSTitus Rwantare pmbus_send_string(pmdev, s->mfr_rev); 118*6f351a7aSTitus Rwantare break; 119*6f351a7aSTitus Rwantare 120*6f351a7aSTitus Rwantare case PMBUS_IC_DEVICE_ID: 121*6f351a7aSTitus Rwantare pmbus_send(pmdev, adm1266_ic_device_id, sizeof(adm1266_ic_device_id)); 122*6f351a7aSTitus Rwantare break; 123*6f351a7aSTitus Rwantare 124*6f351a7aSTitus Rwantare case PMBUS_IC_DEVICE_REV: 125*6f351a7aSTitus Rwantare pmbus_send(pmdev, adm1266_ic_device_rev, sizeof(adm1266_ic_device_rev)); 126*6f351a7aSTitus Rwantare break; 127*6f351a7aSTitus Rwantare 128*6f351a7aSTitus Rwantare default: 129*6f351a7aSTitus Rwantare qemu_log_mask(LOG_UNIMP, 130*6f351a7aSTitus Rwantare "%s: reading from unimplemented register: 0x%02x\n", 131*6f351a7aSTitus Rwantare __func__, pmdev->code); 132*6f351a7aSTitus Rwantare return 0xFF; 133*6f351a7aSTitus Rwantare } 134*6f351a7aSTitus Rwantare 135*6f351a7aSTitus Rwantare return 0; 136*6f351a7aSTitus Rwantare } 137*6f351a7aSTitus Rwantare 138*6f351a7aSTitus Rwantare static int adm1266_write_data(PMBusDevice *pmdev, const uint8_t *buf, 139*6f351a7aSTitus Rwantare uint8_t len) 140*6f351a7aSTitus Rwantare { 141*6f351a7aSTitus Rwantare ADM1266State *s = ADM1266(pmdev); 142*6f351a7aSTitus Rwantare 143*6f351a7aSTitus Rwantare switch (pmdev->code) { 144*6f351a7aSTitus Rwantare case PMBUS_MFR_ID: /* R/W block */ 145*6f351a7aSTitus Rwantare pmbus_receive_block(pmdev, (uint8_t *)s->mfr_id, sizeof(s->mfr_id)); 146*6f351a7aSTitus Rwantare break; 147*6f351a7aSTitus Rwantare 148*6f351a7aSTitus Rwantare case PMBUS_MFR_MODEL: /* R/W block */ 149*6f351a7aSTitus Rwantare pmbus_receive_block(pmdev, (uint8_t *)s->mfr_model, 150*6f351a7aSTitus Rwantare sizeof(s->mfr_model)); 151*6f351a7aSTitus Rwantare break; 152*6f351a7aSTitus Rwantare 153*6f351a7aSTitus Rwantare case PMBUS_MFR_REVISION: /* R/W block*/ 154*6f351a7aSTitus Rwantare pmbus_receive_block(pmdev, (uint8_t *)s->mfr_rev, sizeof(s->mfr_rev)); 155*6f351a7aSTitus Rwantare break; 156*6f351a7aSTitus Rwantare 157*6f351a7aSTitus Rwantare case ADM1266_SET_RTC: /* do nothing */ 158*6f351a7aSTitus Rwantare break; 159*6f351a7aSTitus Rwantare 160*6f351a7aSTitus Rwantare default: 161*6f351a7aSTitus Rwantare qemu_log_mask(LOG_UNIMP, 162*6f351a7aSTitus Rwantare "%s: writing to unimplemented register: 0x%02x\n", 163*6f351a7aSTitus Rwantare __func__, pmdev->code); 164*6f351a7aSTitus Rwantare break; 165*6f351a7aSTitus Rwantare } 166*6f351a7aSTitus Rwantare return 0; 167*6f351a7aSTitus Rwantare } 168*6f351a7aSTitus Rwantare 169*6f351a7aSTitus Rwantare static void adm1266_get(Object *obj, Visitor *v, const char *name, void *opaque, 170*6f351a7aSTitus Rwantare Error **errp) 171*6f351a7aSTitus Rwantare { 172*6f351a7aSTitus Rwantare uint16_t value; 173*6f351a7aSTitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(obj); 174*6f351a7aSTitus Rwantare PMBusVoutMode *mode = (PMBusVoutMode *)&pmdev->pages[0].vout_mode; 175*6f351a7aSTitus Rwantare 176*6f351a7aSTitus Rwantare if (strcmp(name, "vout") == 0) { 177*6f351a7aSTitus Rwantare value = pmbus_linear_mode2data(*(uint16_t *)opaque, mode->exp); 178*6f351a7aSTitus Rwantare } else { 179*6f351a7aSTitus Rwantare value = *(uint16_t *)opaque; 180*6f351a7aSTitus Rwantare } 181*6f351a7aSTitus Rwantare 182*6f351a7aSTitus Rwantare visit_type_uint16(v, name, &value, errp); 183*6f351a7aSTitus Rwantare } 184*6f351a7aSTitus Rwantare 185*6f351a7aSTitus Rwantare static void adm1266_set(Object *obj, Visitor *v, const char *name, void *opaque, 186*6f351a7aSTitus Rwantare Error **errp) 187*6f351a7aSTitus Rwantare { 188*6f351a7aSTitus Rwantare uint16_t *internal = opaque; 189*6f351a7aSTitus Rwantare uint16_t value; 190*6f351a7aSTitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(obj); 191*6f351a7aSTitus Rwantare PMBusVoutMode *mode = (PMBusVoutMode *)&pmdev->pages[0].vout_mode; 192*6f351a7aSTitus Rwantare 193*6f351a7aSTitus Rwantare if (!visit_type_uint16(v, name, &value, errp)) { 194*6f351a7aSTitus Rwantare return; 195*6f351a7aSTitus Rwantare } 196*6f351a7aSTitus Rwantare 197*6f351a7aSTitus Rwantare *internal = pmbus_data2linear_mode(value, mode->exp); 198*6f351a7aSTitus Rwantare pmbus_check_limits(pmdev); 199*6f351a7aSTitus Rwantare } 200*6f351a7aSTitus Rwantare 201*6f351a7aSTitus Rwantare static const VMStateDescription vmstate_adm1266 = { 202*6f351a7aSTitus Rwantare .name = "ADM1266", 203*6f351a7aSTitus Rwantare .version_id = 0, 204*6f351a7aSTitus Rwantare .minimum_version_id = 0, 205*6f351a7aSTitus Rwantare .fields = (VMStateField[]){ 206*6f351a7aSTitus Rwantare VMSTATE_PMBUS_DEVICE(parent, ADM1266State), 207*6f351a7aSTitus Rwantare VMSTATE_END_OF_LIST() 208*6f351a7aSTitus Rwantare } 209*6f351a7aSTitus Rwantare }; 210*6f351a7aSTitus Rwantare 211*6f351a7aSTitus Rwantare static void adm1266_init(Object *obj) 212*6f351a7aSTitus Rwantare { 213*6f351a7aSTitus Rwantare PMBusDevice *pmdev = PMBUS_DEVICE(obj); 214*6f351a7aSTitus Rwantare uint64_t flags = PB_HAS_VOUT_MODE | PB_HAS_VOUT | PB_HAS_VOUT_MARGIN | 215*6f351a7aSTitus Rwantare PB_HAS_VOUT_RATING | PB_HAS_STATUS_MFR_SPECIFIC; 216*6f351a7aSTitus Rwantare 217*6f351a7aSTitus Rwantare for (int i = 0; i < ADM1266_NUM_PAGES; i++) { 218*6f351a7aSTitus Rwantare pmbus_page_config(pmdev, i, flags); 219*6f351a7aSTitus Rwantare 220*6f351a7aSTitus Rwantare object_property_add(obj, "vout[*]", "uint16", 221*6f351a7aSTitus Rwantare adm1266_get, 222*6f351a7aSTitus Rwantare adm1266_set, NULL, &pmdev->pages[i].read_vout); 223*6f351a7aSTitus Rwantare } 224*6f351a7aSTitus Rwantare } 225*6f351a7aSTitus Rwantare 226*6f351a7aSTitus Rwantare static void adm1266_class_init(ObjectClass *klass, void *data) 227*6f351a7aSTitus Rwantare { 228*6f351a7aSTitus Rwantare ResettableClass *rc = RESETTABLE_CLASS(klass); 229*6f351a7aSTitus Rwantare DeviceClass *dc = DEVICE_CLASS(klass); 230*6f351a7aSTitus Rwantare PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass); 231*6f351a7aSTitus Rwantare 232*6f351a7aSTitus Rwantare dc->desc = "Analog Devices ADM1266 Hot Swap controller"; 233*6f351a7aSTitus Rwantare dc->vmsd = &vmstate_adm1266; 234*6f351a7aSTitus Rwantare k->write_data = adm1266_write_data; 235*6f351a7aSTitus Rwantare k->receive_byte = adm1266_read_byte; 236*6f351a7aSTitus Rwantare k->device_num_pages = 17; 237*6f351a7aSTitus Rwantare 238*6f351a7aSTitus Rwantare rc->phases.exit = adm1266_exit_reset; 239*6f351a7aSTitus Rwantare } 240*6f351a7aSTitus Rwantare 241*6f351a7aSTitus Rwantare static const TypeInfo adm1266_info = { 242*6f351a7aSTitus Rwantare .name = TYPE_ADM1266, 243*6f351a7aSTitus Rwantare .parent = TYPE_PMBUS_DEVICE, 244*6f351a7aSTitus Rwantare .instance_size = sizeof(ADM1266State), 245*6f351a7aSTitus Rwantare .instance_init = adm1266_init, 246*6f351a7aSTitus Rwantare .class_init = adm1266_class_init, 247*6f351a7aSTitus Rwantare }; 248*6f351a7aSTitus Rwantare 249*6f351a7aSTitus Rwantare static void adm1266_register_types(void) 250*6f351a7aSTitus Rwantare { 251*6f351a7aSTitus Rwantare type_register_static(&adm1266_info); 252*6f351a7aSTitus Rwantare } 253*6f351a7aSTitus Rwantare 254*6f351a7aSTitus Rwantare type_init(adm1266_register_types) 255